From 509e02db33faf9d6cc2a19112382e765ed5b9553 Mon Sep 17 00:00:00 2001 From: Christophe Geuzaine <cgeuzaine@ulg.ac.be> Date: Wed, 21 Sep 2005 17:29:42 +0000 Subject: [PATCH] moving all external code to contrib subdirectory --- Common/Makefile | 5 +- Fltk/Makefile | 5 +- Geo/Makefile | 7 +- Graphics/Makefile | 5 +- Makefile | 22 +- Mesh/Makefile | 11 +- Parser/Makefile | 5 +- Plugin/Makefile | 7 +- configure | 185 +- configure.in | 75 +- contrib/ANN/Copyright.txt | 47 + contrib/ANN/License.txt | 450 + contrib/ANN/Makefile | 114 + contrib/ANN/include/ANN/ANN.h | 829 + contrib/ANN/include/ANN/ANNperf.h | 226 + contrib/ANN/include/ANN/ANNx.h | 170 + contrib/ANN/src/ANN.cpp | 198 + contrib/ANN/src/bd_fix_rad_search.cpp | 61 + contrib/ANN/src/bd_pr_search.cpp | 62 + contrib/ANN/src/bd_search.cpp | 61 + contrib/ANN/src/bd_tree.cpp | 417 + contrib/ANN/src/bd_tree.h | 100 + contrib/ANN/src/brute.cpp | 109 + contrib/ANN/src/kd_dump.cpp | 444 + contrib/ANN/src/kd_fix_rad_search.cpp | 183 + contrib/ANN/src/kd_fix_rad_search.h | 44 + contrib/ANN/src/kd_pr_search.cpp | 219 + contrib/ANN/src/kd_pr_search.h | 49 + contrib/ANN/src/kd_search.cpp | 210 + contrib/ANN/src/kd_search.h | 48 + contrib/ANN/src/kd_split.cpp | 428 + contrib/ANN/src/kd_split.h | 85 + contrib/ANN/src/kd_tree.cpp | 405 + contrib/ANN/src/kd_tree.h | 197 + contrib/ANN/src/kd_util.cpp | 439 + contrib/ANN/src/kd_util.h | 124 + contrib/ANN/src/perf.cpp | 134 + contrib/ANN/src/pr_queue.h | 125 + contrib/ANN/src/pr_queue_k.h | 118 + contrib/MathEval/Makefile | 79 + contrib/MathEval/README | 25 + contrib/MathEval/common.h | 37 + contrib/MathEval/matheval.cpp | 248 + contrib/MathEval/matheval.h | 89 + contrib/MathEval/node.cpp | 653 + contrib/MathEval/node.h | 111 + contrib/MathEval/parser.tab.cpp | 1044 + contrib/MathEval/parser.tab.hpp | 11 + contrib/MathEval/parser.y | 126 + contrib/MathEval/scanner.l | 130 + contrib/MathEval/scanner.yy.cpp | 1716 ++ contrib/MathEval/symbol_table.cpp | 212 + contrib/MathEval/symbol_table.h | 79 + contrib/MathEval/xmath.cpp | 101 + contrib/MathEval/xmath.h | 35 + contrib/Metis/Makefile | 103 + contrib/Metis/balance.c | 278 + contrib/Metis/bucketsort.c | 43 + contrib/Metis/ccgraph.c | 599 + contrib/Metis/coarsen.c | 83 + contrib/Metis/compress.c | 256 + contrib/Metis/debug.c | 239 + contrib/Metis/defs.h | 161 + contrib/Metis/estmem.c | 157 + contrib/Metis/fm.c | 194 + contrib/Metis/fortran.c | 141 + contrib/Metis/frename.c | 312 + contrib/Metis/graph.c | 616 + contrib/Metis/initpart.c | 422 + contrib/Metis/kmetis.c | 129 + contrib/Metis/kvmetis.c | 130 + contrib/Metis/kwayfm.c | 672 + contrib/Metis/kwayrefine.c | 392 + contrib/Metis/kwayvolfm.c | 1778 ++ contrib/Metis/kwayvolrefine.c | 460 + contrib/Metis/macros.h | 143 + contrib/Metis/match.c | 267 + contrib/Metis/mbalance.c | 260 + contrib/Metis/mbalance2.c | 328 + contrib/Metis/mcoarsen.c | 91 + contrib/Metis/memory.c | 208 + contrib/Metis/mesh.c | 398 + contrib/Metis/meshpart.c | 204 + contrib/Metis/metis.h | 37 + contrib/Metis/mfm.c | 344 + contrib/Metis/mfm2.c | 349 + contrib/Metis/mincover.c | 259 + contrib/Metis/minitpart.c | 355 + contrib/Metis/minitpart2.c | 368 + contrib/Metis/mkmetis.c | 123 + contrib/Metis/mkwayfmh.c | 677 + contrib/Metis/mkwayrefine.c | 297 + contrib/Metis/mmatch.c | 506 + contrib/Metis/mmd.c | 593 + contrib/Metis/mpmetis.c | 402 + contrib/Metis/mrefine.c | 219 + contrib/Metis/mrefine2.c | 55 + contrib/Metis/mutil.c | 101 + contrib/Metis/myqsort.c | 547 + contrib/Metis/ometis.c | 764 + contrib/Metis/parmetis.c | 371 + contrib/Metis/pmetis.c | 341 + contrib/Metis/pqueue.c | 579 + contrib/Metis/proto.h | 505 + contrib/Metis/refine.c | 204 + contrib/Metis/rename.h | 418 + contrib/Metis/separator.c | 284 + contrib/Metis/sfm.c | 1069 + contrib/Metis/srefine.c | 169 + contrib/Metis/stat.c | 287 + contrib/Metis/struct.h | 251 + contrib/Metis/subdomains.c | 1295 + contrib/Metis/timing.c | 74 + contrib/Metis/util.c | 519 + contrib/NR/Makefile | 77 + contrib/NR/brent.cpp | 77 + contrib/NR/dpythag.cpp | 14 + contrib/NR/dsvdcmp.cpp | 183 + contrib/NR/fdjac.cpp | 29 + contrib/NR/fmin.cpp | 20 + contrib/NR/lnsrch.cpp | 65 + contrib/NR/lubksb.cpp | 23 + contrib/NR/ludcmp.cpp | 60 + contrib/NR/mnbrak.cpp | 67 + contrib/NR/newt.cpp | 92 + contrib/NR/nrutil.cpp | 620 + contrib/NR/nrutil.h | 109 + contrib/Netgen/COPYING.LIB | 504 + contrib/Netgen/Makefile | 4412 +++ contrib/Netgen/README | 72 + contrib/Netgen/VERSION | 1 + contrib/Netgen/libsrc/Makefile | 38 + contrib/Netgen/libsrc/csg/Makefile | 26 + contrib/Netgen/libsrc/csg/algprim.cpp | 1389 + contrib/Netgen/libsrc/csg/algprim.hpp | 338 + contrib/Netgen/libsrc/csg/brick.cpp | 409 + contrib/Netgen/libsrc/csg/brick.hpp | 98 + contrib/Netgen/libsrc/csg/bspline2d.cpp | 242 + contrib/Netgen/libsrc/csg/csg.hpp | 48 + contrib/Netgen/libsrc/csg/csgeom.cpp | 1020 + contrib/Netgen/libsrc/csg/csgeom.hpp | 257 + contrib/Netgen/libsrc/csg/csgparser.cpp | 1156 + .../Netgen/libsrc/csg/csgparser_dalibor.cpp | 1111 + contrib/Netgen/libsrc/csg/csgscanner.cpp | 205 + contrib/Netgen/libsrc/csg/curve2d.cpp | 78 + contrib/Netgen/libsrc/csg/curve2d.hpp | 59 + contrib/Netgen/libsrc/csg/edgeflw.cpp | 1524 ++ contrib/Netgen/libsrc/csg/edgeflw.hpp | 99 + contrib/Netgen/libsrc/csg/edgeflw2.cpp | 1404 + contrib/Netgen/libsrc/csg/edgeflw_new.cpp | 1553 ++ contrib/Netgen/libsrc/csg/edgeflw_old.cpp | 1405 + contrib/Netgen/libsrc/csg/explicitcurve2d.cpp | 160 + contrib/Netgen/libsrc/csg/explicitcurve2d.hpp | 109 + contrib/Netgen/libsrc/csg/extrusion.cpp | 175 + contrib/Netgen/libsrc/csg/extrusion.hpp | 89 + contrib/Netgen/libsrc/csg/gencyl.cpp | 209 + contrib/Netgen/libsrc/csg/gencyl.hpp | 64 + contrib/Netgen/libsrc/csg/genmesh.cpp | 684 + contrib/Netgen/libsrc/csg/geometry.cpp | 1792 ++ contrib/Netgen/libsrc/csg/geometry.h | 48 + contrib/Netgen/libsrc/csg/geometry.ll | 94 + contrib/Netgen/libsrc/csg/geometry.yy | 585 + contrib/Netgen/libsrc/csg/geoml.hpp | 16 + contrib/Netgen/libsrc/csg/identify.cpp | 1508 + contrib/Netgen/libsrc/csg/identify.hpp | 180 + contrib/Netgen/libsrc/csg/lex.yy.cpp | 1834 ++ contrib/Netgen/libsrc/csg/manifold.cpp | 14 + contrib/Netgen/libsrc/csg/manifold.hpp | 22 + contrib/Netgen/libsrc/csg/meshsurf.cpp | 178 + contrib/Netgen/libsrc/csg/meshsurf.hpp | 85 + contrib/Netgen/libsrc/csg/polyhedra.cpp | 358 + contrib/Netgen/libsrc/csg/polyhedra.hpp | 78 + contrib/Netgen/libsrc/csg/revolution.cpp | 151 + contrib/Netgen/libsrc/csg/revolution.hpp | 65 + contrib/Netgen/libsrc/csg/singularref.cpp | 117 + contrib/Netgen/libsrc/csg/singularref.hpp | 68 + contrib/Netgen/libsrc/csg/solid.cpp | 1217 + contrib/Netgen/libsrc/csg/solid.hpp | 195 + contrib/Netgen/libsrc/csg/specpoin.cpp | 1231 + contrib/Netgen/libsrc/csg/specpoin.hpp | 150 + contrib/Netgen/libsrc/csg/specpoin_new.cpp | 1367 + contrib/Netgen/libsrc/csg/specpoin_old.cpp | 1370 + contrib/Netgen/libsrc/csg/spline3d.cpp | 355 + contrib/Netgen/libsrc/csg/spline3d.hpp | 92 + contrib/Netgen/libsrc/csg/surface.cpp | 392 + contrib/Netgen/libsrc/csg/surface.hpp | 301 + contrib/Netgen/libsrc/csg/triapprox.cpp | 59 + contrib/Netgen/libsrc/csg/triapprox.hpp | 57 + contrib/Netgen/libsrc/general/Makefile | 12 + contrib/Netgen/libsrc/general/array.cpp | 75 + contrib/Netgen/libsrc/general/array.hpp | 478 + contrib/Netgen/libsrc/general/autoptr.hpp | 31 + contrib/Netgen/libsrc/general/bitarray.cpp | 132 + contrib/Netgen/libsrc/general/bitarray.hpp | 207 + contrib/Netgen/libsrc/general/dynamicmem.cpp | 117 + contrib/Netgen/libsrc/general/dynamicmem.hpp | 94 + contrib/Netgen/libsrc/general/flags.cpp | 330 + contrib/Netgen/libsrc/general/flags.hpp | 83 + contrib/Netgen/libsrc/general/hashtabl.cpp | 294 + contrib/Netgen/libsrc/general/hashtabl.hpp | 1000 + contrib/Netgen/libsrc/general/moveablemem.cpp | 249 + contrib/Netgen/libsrc/general/moveablemem.hpp | 97 + contrib/Netgen/libsrc/general/myadt.hpp | 43 + contrib/Netgen/libsrc/general/mystring.cpp | 386 + contrib/Netgen/libsrc/general/mystring.hpp | 209 + contrib/Netgen/libsrc/general/ngexception.cpp | 33 + contrib/Netgen/libsrc/general/ngexception.hpp | 30 + contrib/Netgen/libsrc/general/optmem.cpp | 63 + contrib/Netgen/libsrc/general/optmem.hpp | 52 + contrib/Netgen/libsrc/general/parthreads.cpp | 40 + contrib/Netgen/libsrc/general/parthreads.hpp | 126 + contrib/Netgen/libsrc/general/seti.cpp | 70 + contrib/Netgen/libsrc/general/seti.hpp | 45 + contrib/Netgen/libsrc/general/sort.cpp | 75 + contrib/Netgen/libsrc/general/sort.hpp | 19 + contrib/Netgen/libsrc/general/spbita2d.cpp | 172 + contrib/Netgen/libsrc/general/spbita2d.hpp | 56 + contrib/Netgen/libsrc/general/stack.hpp | 112 + contrib/Netgen/libsrc/general/stack.icc | 67 + contrib/Netgen/libsrc/general/symbolta.cpp | 52 + contrib/Netgen/libsrc/general/symbolta.hpp | 158 + contrib/Netgen/libsrc/general/table.cpp | 167 + contrib/Netgen/libsrc/general/table.hpp | 212 + contrib/Netgen/libsrc/general/template.hpp | 448 + contrib/Netgen/libsrc/geom2d/Makefile | 12 + contrib/Netgen/libsrc/geom2d/genmesh2d.cpp | 145 + contrib/Netgen/libsrc/geom2d/geom2dmesh.cpp | 55 + contrib/Netgen/libsrc/geom2d/geom2dmesh.hpp | 38 + contrib/Netgen/libsrc/geom2d/geometry2d.hpp | 20 + contrib/Netgen/libsrc/geom2d/spline2d.cpp | 395 + contrib/Netgen/libsrc/geom2d/spline2d.hpp | 204 + .../Netgen/libsrc/geom2d/splinegeometry2.cpp | 346 + .../Netgen/libsrc/geom2d/splinegeometry2.hpp | 83 + contrib/Netgen/libsrc/gprim/Makefile | 14 + contrib/Netgen/libsrc/gprim/adtree.cpp | 2245 ++ contrib/Netgen/libsrc/gprim/adtree.hpp | 477 + contrib/Netgen/libsrc/gprim/geom2d.cpp | 485 + contrib/Netgen/libsrc/gprim/geom2d.hpp | 870 + contrib/Netgen/libsrc/gprim/geom3d.cpp | 650 + contrib/Netgen/libsrc/gprim/geom3d.hpp | 732 + contrib/Netgen/libsrc/gprim/geomfuncs.cpp | 111 + contrib/Netgen/libsrc/gprim/geomfuncs.hpp | 136 + contrib/Netgen/libsrc/gprim/geomobjects.hpp | 346 + contrib/Netgen/libsrc/gprim/geomobjects2.hpp | 366 + contrib/Netgen/libsrc/gprim/geomops.hpp | 391 + contrib/Netgen/libsrc/gprim/geomops2.hpp | 428 + contrib/Netgen/libsrc/gprim/geomtest3d.cpp | 1223 + contrib/Netgen/libsrc/gprim/geomtest3d.hpp | 80 + contrib/Netgen/libsrc/gprim/gprim.hpp | 26 + contrib/Netgen/libsrc/gprim/testgeom.cpp | 20 + contrib/Netgen/libsrc/gprim/transform3d.cpp | 173 + contrib/Netgen/libsrc/gprim/transform3d.hpp | 174 + contrib/Netgen/libsrc/include/FlexLexer.h | 184 + contrib/Netgen/libsrc/include/csg.hpp | 1 + contrib/Netgen/libsrc/include/geometry2d.hpp | 1 + contrib/Netgen/libsrc/include/gprim.hpp | 1 + contrib/Netgen/libsrc/include/incvis.hpp | 33 + contrib/Netgen/libsrc/include/linalg.hpp | 1 + contrib/Netgen/libsrc/include/meshing.hpp | 1 + contrib/Netgen/libsrc/include/myadt.hpp | 1 + contrib/Netgen/libsrc/include/mydefs.hpp | 29 + contrib/Netgen/libsrc/include/mystdlib.h | 69 + contrib/Netgen/libsrc/include/occgeom.hpp | 1 + contrib/Netgen/libsrc/include/opti.hpp | 1 + contrib/Netgen/libsrc/include/stepgeom.hpp | 10 + contrib/Netgen/libsrc/include/stepreader.hpp | 1 + contrib/Netgen/libsrc/include/stlgeom.hpp | 1 + contrib/Netgen/libsrc/include/visual.hpp | 1 + contrib/Netgen/libsrc/interface/Makefile | 7 + .../libsrc/interface/importsolution.cpp | 121 + .../Netgen/libsrc/interface/nginterface.cpp | 1476 + contrib/Netgen/libsrc/interface/nginterface.h | 245 + contrib/Netgen/libsrc/interface/nglib.cpp | 573 + contrib/Netgen/libsrc/interface/nglib.h | 208 + contrib/Netgen/libsrc/interface/printdest.cpp | 11 + contrib/Netgen/libsrc/interface/readuser.cpp | 394 + .../Netgen/libsrc/interface/writeabaqus.cpp | 237 + .../Netgen/libsrc/interface/writediffpack.cpp | 296 + .../Netgen/libsrc/interface/writeelmer.cpp | 127 + contrib/Netgen/libsrc/interface/writefeap.cpp | 220 + .../Netgen/libsrc/interface/writefluent.cpp | 193 + contrib/Netgen/libsrc/interface/writegmsh.cpp | 200 + .../Netgen/libsrc/interface/writepermas.cpp | 208 + .../Netgen/libsrc/interface/writepermas2.cpp | 173 + .../Netgen/libsrc/interface/writetecplot.cpp | 127 + .../Netgen/libsrc/interface/writetochnog.cpp | 108 + contrib/Netgen/libsrc/interface/writeuser.cpp | 899 + contrib/Netgen/libsrc/interface/writeuser.hpp | 114 + .../Netgen/libsrc/interface/wuchemnitz.cpp | 309 + contrib/Netgen/libsrc/linalg/Makefile | 13 + contrib/Netgen/libsrc/linalg/basemat.cpp | 472 + contrib/Netgen/libsrc/linalg/basemat.hpp | 109 + contrib/Netgen/libsrc/linalg/densemat.cpp | 1443 + contrib/Netgen/libsrc/linalg/densemat.hpp | 260 + contrib/Netgen/libsrc/linalg/linalg.hpp | 35 + contrib/Netgen/libsrc/linalg/polynomial.cpp | 216 + contrib/Netgen/libsrc/linalg/polynomial.hpp | 45 + contrib/Netgen/libsrc/linalg/sparsmat.cpp | 1707 ++ contrib/Netgen/libsrc/linalg/sparsmat.hpp | 265 + contrib/Netgen/libsrc/linalg/vector.cpp | 787 + contrib/Netgen/libsrc/linalg/vector.hpp | 485 + contrib/Netgen/libsrc/makefile.inc | 48 + contrib/Netgen/libsrc/makefile.mach.FREEBSD | 26 + contrib/Netgen/libsrc/makefile.mach.INTEL | 34 + contrib/Netgen/libsrc/makefile.mach.LINUX | 31 + .../Netgen/libsrc/makefile.mach.LINUXGCC33 | 33 + contrib/Netgen/libsrc/makefile.mach.SGI | 19 + contrib/Netgen/libsrc/makefile.mach.SGIGCC | 53 + contrib/Netgen/libsrc/makefile.mach.SUN | 16 + contrib/Netgen/libsrc/meshing/Makefile | 16 + contrib/Netgen/libsrc/meshing/adfront2.cpp | 526 + contrib/Netgen/libsrc/meshing/adfront2.hpp | 337 + contrib/Netgen/libsrc/meshing/adfront3.cpp | 883 + contrib/Netgen/libsrc/meshing/adfront3.hpp | 276 + contrib/Netgen/libsrc/meshing/bisect.cpp | 2371 ++ contrib/Netgen/libsrc/meshing/bisect.hpp | 77 + .../Netgen/libsrc/meshing/boundarylayer.cpp | 91 + .../Netgen/libsrc/meshing/boundarylayer.hpp | 9 + contrib/Netgen/libsrc/meshing/clusters.cpp | 260 + contrib/Netgen/libsrc/meshing/clusters.hpp | 42 + contrib/Netgen/libsrc/meshing/curvedelems.cpp | 2037 ++ contrib/Netgen/libsrc/meshing/curvedelems.hpp | 837 + .../Netgen/libsrc/meshing/curvedelems2.cpp | 752 + contrib/Netgen/libsrc/meshing/delaunay.cpp | 1683 ++ contrib/Netgen/libsrc/meshing/findip.cpp | 115 + contrib/Netgen/libsrc/meshing/findip.hpp | 108 + contrib/Netgen/libsrc/meshing/geomsearch.cpp | 263 + contrib/Netgen/libsrc/meshing/geomsearch.hpp | 116 + contrib/Netgen/libsrc/meshing/global.cpp | 53 + contrib/Netgen/libsrc/meshing/global.hpp | 54 + contrib/Netgen/libsrc/meshing/hpref_prism.hpp | 300 + contrib/Netgen/libsrc/meshing/hpref_quad.hpp | 2129 ++ contrib/Netgen/libsrc/meshing/hpref_tet.hpp | 2842 ++ contrib/Netgen/libsrc/meshing/hpref_trig.hpp | 750 + .../Netgen/libsrc/meshing/hprefinement.cpp | 2605 ++ .../Netgen/libsrc/meshing/hprefinement.hpp | 227 + contrib/Netgen/libsrc/meshing/improve2.cpp | 798 + contrib/Netgen/libsrc/meshing/improve2.hpp | 91 + contrib/Netgen/libsrc/meshing/improve2gen.cpp | 441 + contrib/Netgen/libsrc/meshing/improve3.cpp | 1947 ++ contrib/Netgen/libsrc/meshing/improve3.hpp | 50 + contrib/Netgen/libsrc/meshing/localh.cpp | 682 + contrib/Netgen/libsrc/meshing/localh.hpp | 145 + contrib/Netgen/libsrc/meshing/meshclass.cpp | 4744 ++++ contrib/Netgen/libsrc/meshing/meshclass.hpp | 620 + contrib/Netgen/libsrc/meshing/meshfunc.cpp | 688 + contrib/Netgen/libsrc/meshing/meshfunc.hpp | 41 + contrib/Netgen/libsrc/meshing/meshfunc2d.cpp | 61 + contrib/Netgen/libsrc/meshing/meshing.hpp | 60 + contrib/Netgen/libsrc/meshing/meshing2.cpp | 1864 ++ contrib/Netgen/libsrc/meshing/meshing2.hpp | 149 + contrib/Netgen/libsrc/meshing/meshing3.cpp | 1260 + contrib/Netgen/libsrc/meshing/meshing3.hpp | 128 + contrib/Netgen/libsrc/meshing/meshtool.cpp | 978 + contrib/Netgen/libsrc/meshing/meshtool.hpp | 83 + contrib/Netgen/libsrc/meshing/meshtype.cpp | 2233 ++ contrib/Netgen/libsrc/meshing/meshtype.hpp | 1025 + contrib/Netgen/libsrc/meshing/msghandler.cpp | 193 + contrib/Netgen/libsrc/meshing/msghandler.hpp | 52 + contrib/Netgen/libsrc/meshing/netrule2.cpp | 226 + contrib/Netgen/libsrc/meshing/netrule3.cpp | 1138 + contrib/Netgen/libsrc/meshing/parser2.cpp | 559 + contrib/Netgen/libsrc/meshing/parser3.cpp | 987 + contrib/Netgen/libsrc/meshing/prism2rls.cpp | 457 + contrib/Netgen/libsrc/meshing/prism2rls_2.cpp | 446 + contrib/Netgen/libsrc/meshing/pyramid2rls.cpp | 309 + contrib/Netgen/libsrc/meshing/pyramidrls.cpp | 263 + contrib/Netgen/libsrc/meshing/quadrls.cpp | 765 + contrib/Netgen/libsrc/meshing/refine.cpp | 721 + contrib/Netgen/libsrc/meshing/ruler2.cpp | 646 + contrib/Netgen/libsrc/meshing/ruler2.hpp | 166 + contrib/Netgen/libsrc/meshing/ruler3.cpp | 1176 + contrib/Netgen/libsrc/meshing/ruler3.hpp | 210 + contrib/Netgen/libsrc/meshing/secondorder.cpp | 496 + contrib/Netgen/libsrc/meshing/smoothing2.cpp | 922 + contrib/Netgen/libsrc/meshing/smoothing3.cpp | 1546 ++ contrib/Netgen/libsrc/meshing/specials.cpp | 193 + contrib/Netgen/libsrc/meshing/specials.hpp | 16 + contrib/Netgen/libsrc/meshing/tetrarls.cpp | 1466 + contrib/Netgen/libsrc/meshing/topology.cpp | 1595 ++ contrib/Netgen/libsrc/meshing/topology.hpp | 113 + contrib/Netgen/libsrc/meshing/triarls.cpp | 468 + contrib/Netgen/libsrc/meshing/zrefine.cpp | 735 + contrib/Netgen/libsrc/occ/Makefile | 11 + contrib/Netgen/libsrc/occ/occgenmesh.cpp | 1245 + contrib/Netgen/libsrc/occ/occgeom.cpp | 1102 + contrib/Netgen/libsrc/occ/occgeom.hpp | 279 + contrib/Netgen/libsrc/occ/occmeshsurf.cpp | 592 + contrib/Netgen/libsrc/occ/occmeshsurf.hpp | 201 + contrib/Netgen/libsrc/opti/Makefile | 10 + contrib/Netgen/libsrc/opti/bfgs.cpp | 367 + contrib/Netgen/libsrc/opti/linopt.cpp | 73 + contrib/Netgen/libsrc/opti/linsearch.cpp | 346 + contrib/Netgen/libsrc/opti/opti.hpp | 142 + contrib/Netgen/libsrc/stlgeom/Makefile | 11 + .../Netgen/libsrc/stlgeom/meshstlsurface.cpp | 1130 + .../Netgen/libsrc/stlgeom/meshstlsurface.hpp | 121 + contrib/Netgen/libsrc/stlgeom/stlgeom.cpp | 3476 +++ contrib/Netgen/libsrc/stlgeom/stlgeom.hpp | 450 + .../Netgen/libsrc/stlgeom/stlgeomchart.cpp | 801 + contrib/Netgen/libsrc/stlgeom/stlgeommesh.cpp | 1592 ++ contrib/Netgen/libsrc/stlgeom/stlline.cpp | 780 + contrib/Netgen/libsrc/stlgeom/stlline.hpp | 188 + contrib/Netgen/libsrc/stlgeom/stltool.cpp | 1288 + contrib/Netgen/libsrc/stlgeom/stltool.hpp | 271 + contrib/Netgen/libsrc/stlgeom/stltopology.cpp | 1067 + contrib/Netgen/libsrc/stlgeom/stltopology.hpp | 362 + contrib/Netgen/libsrc/visualization/Makefile | 13 + .../Netgen/libsrc/visualization/meshdoc.cpp | 615 + .../Netgen/libsrc/visualization/meshdoc.hpp | 37 + .../Netgen/libsrc/visualization/mvdraw.cpp | 1335 + .../Netgen/libsrc/visualization/mvdraw.hpp | 370 + .../Netgen/libsrc/visualization/soldata.hpp | 45 + .../libsrc/visualization/stlmeshing.cpp | 1074 + .../Netgen/libsrc/visualization/vispar.hpp | 89 + .../Netgen/libsrc/visualization/visual.hpp | 26 + contrib/Netgen/libsrc/visualization/vscsg.cpp | 199 + .../Netgen/libsrc/visualization/vsmesh.cpp | 3114 +++ contrib/Netgen/libsrc/visualization/vsocc.cpp | 743 + .../libsrc/visualization/vssolution.cpp | 3005 ++ .../libsrc/visualization/vssolution.hpp | 220 + contrib/Netgen/nglib_addon.cpp | 105 + contrib/Netgen/nglib_addon.h | 8 + contrib/Netgen/nglib_addon.o | Bin 0 -> 291636 bytes contrib/Tetgen/LICENSE | 65 + contrib/Tetgen/Makefile | 53 + contrib/Tetgen/predicates.cxx | 4176 +++ contrib/Tetgen/tetgen.cxx | 22807 ++++++++++++++++ contrib/Tetgen/tetgen.h | 1764 ++ contrib/Triangle/Makefile | 55 + contrib/Triangle/README | 74 + contrib/Triangle/triangle.c | 16008 +++++++++++ contrib/Triangle/triangle.h | 282 + 433 files changed, 221397 insertions(+), 157 deletions(-) create mode 100644 contrib/ANN/Copyright.txt create mode 100644 contrib/ANN/License.txt create mode 100644 contrib/ANN/Makefile create mode 100644 contrib/ANN/include/ANN/ANN.h create mode 100644 contrib/ANN/include/ANN/ANNperf.h create mode 100644 contrib/ANN/include/ANN/ANNx.h create mode 100644 contrib/ANN/src/ANN.cpp create mode 100644 contrib/ANN/src/bd_fix_rad_search.cpp create mode 100644 contrib/ANN/src/bd_pr_search.cpp create mode 100644 contrib/ANN/src/bd_search.cpp create mode 100644 contrib/ANN/src/bd_tree.cpp create mode 100644 contrib/ANN/src/bd_tree.h create mode 100644 contrib/ANN/src/brute.cpp create mode 100644 contrib/ANN/src/kd_dump.cpp create mode 100644 contrib/ANN/src/kd_fix_rad_search.cpp create mode 100644 contrib/ANN/src/kd_fix_rad_search.h create mode 100644 contrib/ANN/src/kd_pr_search.cpp create mode 100644 contrib/ANN/src/kd_pr_search.h create mode 100644 contrib/ANN/src/kd_search.cpp create mode 100644 contrib/ANN/src/kd_search.h create mode 100644 contrib/ANN/src/kd_split.cpp create mode 100644 contrib/ANN/src/kd_split.h create mode 100644 contrib/ANN/src/kd_tree.cpp create mode 100644 contrib/ANN/src/kd_tree.h create mode 100644 contrib/ANN/src/kd_util.cpp create mode 100644 contrib/ANN/src/kd_util.h create mode 100644 contrib/ANN/src/perf.cpp create mode 100644 contrib/ANN/src/pr_queue.h create mode 100644 contrib/ANN/src/pr_queue_k.h create mode 100644 contrib/MathEval/Makefile create mode 100644 contrib/MathEval/README create mode 100644 contrib/MathEval/common.h create mode 100644 contrib/MathEval/matheval.cpp create mode 100644 contrib/MathEval/matheval.h create mode 100644 contrib/MathEval/node.cpp create mode 100644 contrib/MathEval/node.h create mode 100644 contrib/MathEval/parser.tab.cpp create mode 100644 contrib/MathEval/parser.tab.hpp create mode 100644 contrib/MathEval/parser.y create mode 100644 contrib/MathEval/scanner.l create mode 100644 contrib/MathEval/scanner.yy.cpp create mode 100644 contrib/MathEval/symbol_table.cpp create mode 100644 contrib/MathEval/symbol_table.h create mode 100644 contrib/MathEval/xmath.cpp create mode 100644 contrib/MathEval/xmath.h create mode 100644 contrib/Metis/Makefile create mode 100644 contrib/Metis/balance.c create mode 100644 contrib/Metis/bucketsort.c create mode 100644 contrib/Metis/ccgraph.c create mode 100644 contrib/Metis/coarsen.c create mode 100644 contrib/Metis/compress.c create mode 100644 contrib/Metis/debug.c create mode 100644 contrib/Metis/defs.h create mode 100644 contrib/Metis/estmem.c create mode 100644 contrib/Metis/fm.c create mode 100644 contrib/Metis/fortran.c create mode 100644 contrib/Metis/frename.c create mode 100644 contrib/Metis/graph.c create mode 100644 contrib/Metis/initpart.c create mode 100644 contrib/Metis/kmetis.c create mode 100644 contrib/Metis/kvmetis.c create mode 100644 contrib/Metis/kwayfm.c create mode 100644 contrib/Metis/kwayrefine.c create mode 100644 contrib/Metis/kwayvolfm.c create mode 100644 contrib/Metis/kwayvolrefine.c create mode 100644 contrib/Metis/macros.h create mode 100644 contrib/Metis/match.c create mode 100644 contrib/Metis/mbalance.c create mode 100644 contrib/Metis/mbalance2.c create mode 100644 contrib/Metis/mcoarsen.c create mode 100644 contrib/Metis/memory.c create mode 100644 contrib/Metis/mesh.c create mode 100644 contrib/Metis/meshpart.c create mode 100644 contrib/Metis/metis.h create mode 100644 contrib/Metis/mfm.c create mode 100644 contrib/Metis/mfm2.c create mode 100644 contrib/Metis/mincover.c create mode 100644 contrib/Metis/minitpart.c create mode 100644 contrib/Metis/minitpart2.c create mode 100644 contrib/Metis/mkmetis.c create mode 100644 contrib/Metis/mkwayfmh.c create mode 100644 contrib/Metis/mkwayrefine.c create mode 100644 contrib/Metis/mmatch.c create mode 100644 contrib/Metis/mmd.c create mode 100644 contrib/Metis/mpmetis.c create mode 100644 contrib/Metis/mrefine.c create mode 100644 contrib/Metis/mrefine2.c create mode 100644 contrib/Metis/mutil.c create mode 100644 contrib/Metis/myqsort.c create mode 100644 contrib/Metis/ometis.c create mode 100644 contrib/Metis/parmetis.c create mode 100644 contrib/Metis/pmetis.c create mode 100644 contrib/Metis/pqueue.c create mode 100644 contrib/Metis/proto.h create mode 100644 contrib/Metis/refine.c create mode 100644 contrib/Metis/rename.h create mode 100644 contrib/Metis/separator.c create mode 100644 contrib/Metis/sfm.c create mode 100644 contrib/Metis/srefine.c create mode 100644 contrib/Metis/stat.c create mode 100644 contrib/Metis/struct.h create mode 100644 contrib/Metis/subdomains.c create mode 100644 contrib/Metis/timing.c create mode 100644 contrib/Metis/util.c create mode 100644 contrib/NR/Makefile create mode 100644 contrib/NR/brent.cpp create mode 100644 contrib/NR/dpythag.cpp create mode 100644 contrib/NR/dsvdcmp.cpp create mode 100644 contrib/NR/fdjac.cpp create mode 100644 contrib/NR/fmin.cpp create mode 100644 contrib/NR/lnsrch.cpp create mode 100644 contrib/NR/lubksb.cpp create mode 100644 contrib/NR/ludcmp.cpp create mode 100644 contrib/NR/mnbrak.cpp create mode 100644 contrib/NR/newt.cpp create mode 100644 contrib/NR/nrutil.cpp create mode 100644 contrib/NR/nrutil.h create mode 100644 contrib/Netgen/COPYING.LIB create mode 100644 contrib/Netgen/Makefile create mode 100644 contrib/Netgen/README create mode 100644 contrib/Netgen/VERSION create mode 100644 contrib/Netgen/libsrc/Makefile create mode 100644 contrib/Netgen/libsrc/csg/Makefile create mode 100644 contrib/Netgen/libsrc/csg/algprim.cpp create mode 100644 contrib/Netgen/libsrc/csg/algprim.hpp create mode 100644 contrib/Netgen/libsrc/csg/brick.cpp create mode 100644 contrib/Netgen/libsrc/csg/brick.hpp create mode 100644 contrib/Netgen/libsrc/csg/bspline2d.cpp create mode 100644 contrib/Netgen/libsrc/csg/csg.hpp create mode 100644 contrib/Netgen/libsrc/csg/csgeom.cpp create mode 100644 contrib/Netgen/libsrc/csg/csgeom.hpp create mode 100644 contrib/Netgen/libsrc/csg/csgparser.cpp create mode 100644 contrib/Netgen/libsrc/csg/csgparser_dalibor.cpp create mode 100644 contrib/Netgen/libsrc/csg/csgscanner.cpp create mode 100644 contrib/Netgen/libsrc/csg/curve2d.cpp create mode 100644 contrib/Netgen/libsrc/csg/curve2d.hpp create mode 100644 contrib/Netgen/libsrc/csg/edgeflw.cpp create mode 100644 contrib/Netgen/libsrc/csg/edgeflw.hpp create mode 100644 contrib/Netgen/libsrc/csg/edgeflw2.cpp create mode 100644 contrib/Netgen/libsrc/csg/edgeflw_new.cpp create mode 100644 contrib/Netgen/libsrc/csg/edgeflw_old.cpp create mode 100644 contrib/Netgen/libsrc/csg/explicitcurve2d.cpp create mode 100644 contrib/Netgen/libsrc/csg/explicitcurve2d.hpp create mode 100644 contrib/Netgen/libsrc/csg/extrusion.cpp create mode 100644 contrib/Netgen/libsrc/csg/extrusion.hpp create mode 100644 contrib/Netgen/libsrc/csg/gencyl.cpp create mode 100644 contrib/Netgen/libsrc/csg/gencyl.hpp create mode 100644 contrib/Netgen/libsrc/csg/genmesh.cpp create mode 100644 contrib/Netgen/libsrc/csg/geometry.cpp create mode 100644 contrib/Netgen/libsrc/csg/geometry.h create mode 100644 contrib/Netgen/libsrc/csg/geometry.ll create mode 100644 contrib/Netgen/libsrc/csg/geometry.yy create mode 100644 contrib/Netgen/libsrc/csg/geoml.hpp create mode 100644 contrib/Netgen/libsrc/csg/identify.cpp create mode 100644 contrib/Netgen/libsrc/csg/identify.hpp create mode 100644 contrib/Netgen/libsrc/csg/lex.yy.cpp create mode 100644 contrib/Netgen/libsrc/csg/manifold.cpp create mode 100644 contrib/Netgen/libsrc/csg/manifold.hpp create mode 100644 contrib/Netgen/libsrc/csg/meshsurf.cpp create mode 100644 contrib/Netgen/libsrc/csg/meshsurf.hpp create mode 100644 contrib/Netgen/libsrc/csg/polyhedra.cpp create mode 100644 contrib/Netgen/libsrc/csg/polyhedra.hpp create mode 100644 contrib/Netgen/libsrc/csg/revolution.cpp create mode 100644 contrib/Netgen/libsrc/csg/revolution.hpp create mode 100644 contrib/Netgen/libsrc/csg/singularref.cpp create mode 100644 contrib/Netgen/libsrc/csg/singularref.hpp create mode 100644 contrib/Netgen/libsrc/csg/solid.cpp create mode 100644 contrib/Netgen/libsrc/csg/solid.hpp create mode 100644 contrib/Netgen/libsrc/csg/specpoin.cpp create mode 100644 contrib/Netgen/libsrc/csg/specpoin.hpp create mode 100644 contrib/Netgen/libsrc/csg/specpoin_new.cpp create mode 100644 contrib/Netgen/libsrc/csg/specpoin_old.cpp create mode 100644 contrib/Netgen/libsrc/csg/spline3d.cpp create mode 100644 contrib/Netgen/libsrc/csg/spline3d.hpp create mode 100644 contrib/Netgen/libsrc/csg/surface.cpp create mode 100644 contrib/Netgen/libsrc/csg/surface.hpp create mode 100644 contrib/Netgen/libsrc/csg/triapprox.cpp create mode 100644 contrib/Netgen/libsrc/csg/triapprox.hpp create mode 100644 contrib/Netgen/libsrc/general/Makefile create mode 100644 contrib/Netgen/libsrc/general/array.cpp create mode 100644 contrib/Netgen/libsrc/general/array.hpp create mode 100644 contrib/Netgen/libsrc/general/autoptr.hpp create mode 100644 contrib/Netgen/libsrc/general/bitarray.cpp create mode 100644 contrib/Netgen/libsrc/general/bitarray.hpp create mode 100644 contrib/Netgen/libsrc/general/dynamicmem.cpp create mode 100644 contrib/Netgen/libsrc/general/dynamicmem.hpp create mode 100644 contrib/Netgen/libsrc/general/flags.cpp create mode 100644 contrib/Netgen/libsrc/general/flags.hpp create mode 100644 contrib/Netgen/libsrc/general/hashtabl.cpp create mode 100644 contrib/Netgen/libsrc/general/hashtabl.hpp create mode 100644 contrib/Netgen/libsrc/general/moveablemem.cpp create mode 100644 contrib/Netgen/libsrc/general/moveablemem.hpp create mode 100644 contrib/Netgen/libsrc/general/myadt.hpp create mode 100644 contrib/Netgen/libsrc/general/mystring.cpp create mode 100644 contrib/Netgen/libsrc/general/mystring.hpp create mode 100644 contrib/Netgen/libsrc/general/ngexception.cpp create mode 100644 contrib/Netgen/libsrc/general/ngexception.hpp create mode 100644 contrib/Netgen/libsrc/general/optmem.cpp create mode 100644 contrib/Netgen/libsrc/general/optmem.hpp create mode 100644 contrib/Netgen/libsrc/general/parthreads.cpp create mode 100644 contrib/Netgen/libsrc/general/parthreads.hpp create mode 100644 contrib/Netgen/libsrc/general/seti.cpp create mode 100644 contrib/Netgen/libsrc/general/seti.hpp create mode 100644 contrib/Netgen/libsrc/general/sort.cpp create mode 100644 contrib/Netgen/libsrc/general/sort.hpp create mode 100644 contrib/Netgen/libsrc/general/spbita2d.cpp create mode 100644 contrib/Netgen/libsrc/general/spbita2d.hpp create mode 100644 contrib/Netgen/libsrc/general/stack.hpp create mode 100644 contrib/Netgen/libsrc/general/stack.icc create mode 100644 contrib/Netgen/libsrc/general/symbolta.cpp create mode 100644 contrib/Netgen/libsrc/general/symbolta.hpp create mode 100644 contrib/Netgen/libsrc/general/table.cpp create mode 100644 contrib/Netgen/libsrc/general/table.hpp create mode 100644 contrib/Netgen/libsrc/general/template.hpp create mode 100644 contrib/Netgen/libsrc/geom2d/Makefile create mode 100644 contrib/Netgen/libsrc/geom2d/genmesh2d.cpp create mode 100644 contrib/Netgen/libsrc/geom2d/geom2dmesh.cpp create mode 100644 contrib/Netgen/libsrc/geom2d/geom2dmesh.hpp create mode 100644 contrib/Netgen/libsrc/geom2d/geometry2d.hpp create mode 100644 contrib/Netgen/libsrc/geom2d/spline2d.cpp create mode 100644 contrib/Netgen/libsrc/geom2d/spline2d.hpp create mode 100644 contrib/Netgen/libsrc/geom2d/splinegeometry2.cpp create mode 100644 contrib/Netgen/libsrc/geom2d/splinegeometry2.hpp create mode 100644 contrib/Netgen/libsrc/gprim/Makefile create mode 100644 contrib/Netgen/libsrc/gprim/adtree.cpp create mode 100644 contrib/Netgen/libsrc/gprim/adtree.hpp create mode 100644 contrib/Netgen/libsrc/gprim/geom2d.cpp create mode 100644 contrib/Netgen/libsrc/gprim/geom2d.hpp create mode 100644 contrib/Netgen/libsrc/gprim/geom3d.cpp create mode 100644 contrib/Netgen/libsrc/gprim/geom3d.hpp create mode 100644 contrib/Netgen/libsrc/gprim/geomfuncs.cpp create mode 100644 contrib/Netgen/libsrc/gprim/geomfuncs.hpp create mode 100644 contrib/Netgen/libsrc/gprim/geomobjects.hpp create mode 100644 contrib/Netgen/libsrc/gprim/geomobjects2.hpp create mode 100644 contrib/Netgen/libsrc/gprim/geomops.hpp create mode 100644 contrib/Netgen/libsrc/gprim/geomops2.hpp create mode 100644 contrib/Netgen/libsrc/gprim/geomtest3d.cpp create mode 100644 contrib/Netgen/libsrc/gprim/geomtest3d.hpp create mode 100644 contrib/Netgen/libsrc/gprim/gprim.hpp create mode 100644 contrib/Netgen/libsrc/gprim/testgeom.cpp create mode 100644 contrib/Netgen/libsrc/gprim/transform3d.cpp create mode 100644 contrib/Netgen/libsrc/gprim/transform3d.hpp create mode 100644 contrib/Netgen/libsrc/include/FlexLexer.h create mode 100644 contrib/Netgen/libsrc/include/csg.hpp create mode 100644 contrib/Netgen/libsrc/include/geometry2d.hpp create mode 100644 contrib/Netgen/libsrc/include/gprim.hpp create mode 100644 contrib/Netgen/libsrc/include/incvis.hpp create mode 100644 contrib/Netgen/libsrc/include/linalg.hpp create mode 100644 contrib/Netgen/libsrc/include/meshing.hpp create mode 100644 contrib/Netgen/libsrc/include/myadt.hpp create mode 100644 contrib/Netgen/libsrc/include/mydefs.hpp create mode 100644 contrib/Netgen/libsrc/include/mystdlib.h create mode 100644 contrib/Netgen/libsrc/include/occgeom.hpp create mode 100644 contrib/Netgen/libsrc/include/opti.hpp create mode 100644 contrib/Netgen/libsrc/include/stepgeom.hpp create mode 100644 contrib/Netgen/libsrc/include/stepreader.hpp create mode 100644 contrib/Netgen/libsrc/include/stlgeom.hpp create mode 100644 contrib/Netgen/libsrc/include/visual.hpp create mode 100644 contrib/Netgen/libsrc/interface/Makefile create mode 100644 contrib/Netgen/libsrc/interface/importsolution.cpp create mode 100644 contrib/Netgen/libsrc/interface/nginterface.cpp create mode 100644 contrib/Netgen/libsrc/interface/nginterface.h create mode 100644 contrib/Netgen/libsrc/interface/nglib.cpp create mode 100644 contrib/Netgen/libsrc/interface/nglib.h create mode 100644 contrib/Netgen/libsrc/interface/printdest.cpp create mode 100644 contrib/Netgen/libsrc/interface/readuser.cpp create mode 100644 contrib/Netgen/libsrc/interface/writeabaqus.cpp create mode 100644 contrib/Netgen/libsrc/interface/writediffpack.cpp create mode 100644 contrib/Netgen/libsrc/interface/writeelmer.cpp create mode 100644 contrib/Netgen/libsrc/interface/writefeap.cpp create mode 100644 contrib/Netgen/libsrc/interface/writefluent.cpp create mode 100644 contrib/Netgen/libsrc/interface/writegmsh.cpp create mode 100644 contrib/Netgen/libsrc/interface/writepermas.cpp create mode 100644 contrib/Netgen/libsrc/interface/writepermas2.cpp create mode 100644 contrib/Netgen/libsrc/interface/writetecplot.cpp create mode 100644 contrib/Netgen/libsrc/interface/writetochnog.cpp create mode 100644 contrib/Netgen/libsrc/interface/writeuser.cpp create mode 100644 contrib/Netgen/libsrc/interface/writeuser.hpp create mode 100644 contrib/Netgen/libsrc/interface/wuchemnitz.cpp create mode 100644 contrib/Netgen/libsrc/linalg/Makefile create mode 100644 contrib/Netgen/libsrc/linalg/basemat.cpp create mode 100644 contrib/Netgen/libsrc/linalg/basemat.hpp create mode 100644 contrib/Netgen/libsrc/linalg/densemat.cpp create mode 100644 contrib/Netgen/libsrc/linalg/densemat.hpp create mode 100644 contrib/Netgen/libsrc/linalg/linalg.hpp create mode 100644 contrib/Netgen/libsrc/linalg/polynomial.cpp create mode 100644 contrib/Netgen/libsrc/linalg/polynomial.hpp create mode 100644 contrib/Netgen/libsrc/linalg/sparsmat.cpp create mode 100644 contrib/Netgen/libsrc/linalg/sparsmat.hpp create mode 100644 contrib/Netgen/libsrc/linalg/vector.cpp create mode 100644 contrib/Netgen/libsrc/linalg/vector.hpp create mode 100644 contrib/Netgen/libsrc/makefile.inc create mode 100644 contrib/Netgen/libsrc/makefile.mach.FREEBSD create mode 100644 contrib/Netgen/libsrc/makefile.mach.INTEL create mode 100644 contrib/Netgen/libsrc/makefile.mach.LINUX create mode 100644 contrib/Netgen/libsrc/makefile.mach.LINUXGCC33 create mode 100644 contrib/Netgen/libsrc/makefile.mach.SGI create mode 100644 contrib/Netgen/libsrc/makefile.mach.SGIGCC create mode 100644 contrib/Netgen/libsrc/makefile.mach.SUN create mode 100644 contrib/Netgen/libsrc/meshing/Makefile create mode 100644 contrib/Netgen/libsrc/meshing/adfront2.cpp create mode 100644 contrib/Netgen/libsrc/meshing/adfront2.hpp create mode 100644 contrib/Netgen/libsrc/meshing/adfront3.cpp create mode 100644 contrib/Netgen/libsrc/meshing/adfront3.hpp create mode 100644 contrib/Netgen/libsrc/meshing/bisect.cpp create mode 100644 contrib/Netgen/libsrc/meshing/bisect.hpp create mode 100644 contrib/Netgen/libsrc/meshing/boundarylayer.cpp create mode 100644 contrib/Netgen/libsrc/meshing/boundarylayer.hpp create mode 100644 contrib/Netgen/libsrc/meshing/clusters.cpp create mode 100644 contrib/Netgen/libsrc/meshing/clusters.hpp create mode 100644 contrib/Netgen/libsrc/meshing/curvedelems.cpp create mode 100644 contrib/Netgen/libsrc/meshing/curvedelems.hpp create mode 100644 contrib/Netgen/libsrc/meshing/curvedelems2.cpp create mode 100644 contrib/Netgen/libsrc/meshing/delaunay.cpp create mode 100644 contrib/Netgen/libsrc/meshing/findip.cpp create mode 100644 contrib/Netgen/libsrc/meshing/findip.hpp create mode 100644 contrib/Netgen/libsrc/meshing/geomsearch.cpp create mode 100644 contrib/Netgen/libsrc/meshing/geomsearch.hpp create mode 100644 contrib/Netgen/libsrc/meshing/global.cpp create mode 100644 contrib/Netgen/libsrc/meshing/global.hpp create mode 100644 contrib/Netgen/libsrc/meshing/hpref_prism.hpp create mode 100644 contrib/Netgen/libsrc/meshing/hpref_quad.hpp create mode 100644 contrib/Netgen/libsrc/meshing/hpref_tet.hpp create mode 100644 contrib/Netgen/libsrc/meshing/hpref_trig.hpp create mode 100644 contrib/Netgen/libsrc/meshing/hprefinement.cpp create mode 100644 contrib/Netgen/libsrc/meshing/hprefinement.hpp create mode 100644 contrib/Netgen/libsrc/meshing/improve2.cpp create mode 100644 contrib/Netgen/libsrc/meshing/improve2.hpp create mode 100644 contrib/Netgen/libsrc/meshing/improve2gen.cpp create mode 100644 contrib/Netgen/libsrc/meshing/improve3.cpp create mode 100644 contrib/Netgen/libsrc/meshing/improve3.hpp create mode 100644 contrib/Netgen/libsrc/meshing/localh.cpp create mode 100644 contrib/Netgen/libsrc/meshing/localh.hpp create mode 100644 contrib/Netgen/libsrc/meshing/meshclass.cpp create mode 100644 contrib/Netgen/libsrc/meshing/meshclass.hpp create mode 100644 contrib/Netgen/libsrc/meshing/meshfunc.cpp create mode 100644 contrib/Netgen/libsrc/meshing/meshfunc.hpp create mode 100644 contrib/Netgen/libsrc/meshing/meshfunc2d.cpp create mode 100644 contrib/Netgen/libsrc/meshing/meshing.hpp create mode 100644 contrib/Netgen/libsrc/meshing/meshing2.cpp create mode 100644 contrib/Netgen/libsrc/meshing/meshing2.hpp create mode 100644 contrib/Netgen/libsrc/meshing/meshing3.cpp create mode 100644 contrib/Netgen/libsrc/meshing/meshing3.hpp create mode 100644 contrib/Netgen/libsrc/meshing/meshtool.cpp create mode 100644 contrib/Netgen/libsrc/meshing/meshtool.hpp create mode 100644 contrib/Netgen/libsrc/meshing/meshtype.cpp create mode 100644 contrib/Netgen/libsrc/meshing/meshtype.hpp create mode 100644 contrib/Netgen/libsrc/meshing/msghandler.cpp create mode 100644 contrib/Netgen/libsrc/meshing/msghandler.hpp create mode 100644 contrib/Netgen/libsrc/meshing/netrule2.cpp create mode 100644 contrib/Netgen/libsrc/meshing/netrule3.cpp create mode 100644 contrib/Netgen/libsrc/meshing/parser2.cpp create mode 100644 contrib/Netgen/libsrc/meshing/parser3.cpp create mode 100644 contrib/Netgen/libsrc/meshing/prism2rls.cpp create mode 100644 contrib/Netgen/libsrc/meshing/prism2rls_2.cpp create mode 100644 contrib/Netgen/libsrc/meshing/pyramid2rls.cpp create mode 100644 contrib/Netgen/libsrc/meshing/pyramidrls.cpp create mode 100644 contrib/Netgen/libsrc/meshing/quadrls.cpp create mode 100644 contrib/Netgen/libsrc/meshing/refine.cpp create mode 100644 contrib/Netgen/libsrc/meshing/ruler2.cpp create mode 100644 contrib/Netgen/libsrc/meshing/ruler2.hpp create mode 100644 contrib/Netgen/libsrc/meshing/ruler3.cpp create mode 100644 contrib/Netgen/libsrc/meshing/ruler3.hpp create mode 100644 contrib/Netgen/libsrc/meshing/secondorder.cpp create mode 100644 contrib/Netgen/libsrc/meshing/smoothing2.cpp create mode 100644 contrib/Netgen/libsrc/meshing/smoothing3.cpp create mode 100644 contrib/Netgen/libsrc/meshing/specials.cpp create mode 100644 contrib/Netgen/libsrc/meshing/specials.hpp create mode 100644 contrib/Netgen/libsrc/meshing/tetrarls.cpp create mode 100644 contrib/Netgen/libsrc/meshing/topology.cpp create mode 100644 contrib/Netgen/libsrc/meshing/topology.hpp create mode 100644 contrib/Netgen/libsrc/meshing/triarls.cpp create mode 100644 contrib/Netgen/libsrc/meshing/zrefine.cpp create mode 100644 contrib/Netgen/libsrc/occ/Makefile create mode 100644 contrib/Netgen/libsrc/occ/occgenmesh.cpp create mode 100644 contrib/Netgen/libsrc/occ/occgeom.cpp create mode 100644 contrib/Netgen/libsrc/occ/occgeom.hpp create mode 100644 contrib/Netgen/libsrc/occ/occmeshsurf.cpp create mode 100644 contrib/Netgen/libsrc/occ/occmeshsurf.hpp create mode 100644 contrib/Netgen/libsrc/opti/Makefile create mode 100644 contrib/Netgen/libsrc/opti/bfgs.cpp create mode 100644 contrib/Netgen/libsrc/opti/linopt.cpp create mode 100644 contrib/Netgen/libsrc/opti/linsearch.cpp create mode 100644 contrib/Netgen/libsrc/opti/opti.hpp create mode 100644 contrib/Netgen/libsrc/stlgeom/Makefile create mode 100644 contrib/Netgen/libsrc/stlgeom/meshstlsurface.cpp create mode 100644 contrib/Netgen/libsrc/stlgeom/meshstlsurface.hpp create mode 100644 contrib/Netgen/libsrc/stlgeom/stlgeom.cpp create mode 100644 contrib/Netgen/libsrc/stlgeom/stlgeom.hpp create mode 100644 contrib/Netgen/libsrc/stlgeom/stlgeomchart.cpp create mode 100644 contrib/Netgen/libsrc/stlgeom/stlgeommesh.cpp create mode 100644 contrib/Netgen/libsrc/stlgeom/stlline.cpp create mode 100644 contrib/Netgen/libsrc/stlgeom/stlline.hpp create mode 100644 contrib/Netgen/libsrc/stlgeom/stltool.cpp create mode 100644 contrib/Netgen/libsrc/stlgeom/stltool.hpp create mode 100644 contrib/Netgen/libsrc/stlgeom/stltopology.cpp create mode 100644 contrib/Netgen/libsrc/stlgeom/stltopology.hpp create mode 100644 contrib/Netgen/libsrc/visualization/Makefile create mode 100644 contrib/Netgen/libsrc/visualization/meshdoc.cpp create mode 100644 contrib/Netgen/libsrc/visualization/meshdoc.hpp create mode 100644 contrib/Netgen/libsrc/visualization/mvdraw.cpp create mode 100644 contrib/Netgen/libsrc/visualization/mvdraw.hpp create mode 100644 contrib/Netgen/libsrc/visualization/soldata.hpp create mode 100644 contrib/Netgen/libsrc/visualization/stlmeshing.cpp create mode 100644 contrib/Netgen/libsrc/visualization/vispar.hpp create mode 100644 contrib/Netgen/libsrc/visualization/visual.hpp create mode 100644 contrib/Netgen/libsrc/visualization/vscsg.cpp create mode 100644 contrib/Netgen/libsrc/visualization/vsmesh.cpp create mode 100644 contrib/Netgen/libsrc/visualization/vsocc.cpp create mode 100644 contrib/Netgen/libsrc/visualization/vssolution.cpp create mode 100644 contrib/Netgen/libsrc/visualization/vssolution.hpp create mode 100644 contrib/Netgen/nglib_addon.cpp create mode 100644 contrib/Netgen/nglib_addon.h create mode 100644 contrib/Netgen/nglib_addon.o create mode 100644 contrib/Tetgen/LICENSE create mode 100644 contrib/Tetgen/Makefile create mode 100644 contrib/Tetgen/predicates.cxx create mode 100644 contrib/Tetgen/tetgen.cxx create mode 100644 contrib/Tetgen/tetgen.h create mode 100644 contrib/Triangle/Makefile create mode 100644 contrib/Triangle/README create mode 100644 contrib/Triangle/triangle.c create mode 100644 contrib/Triangle/triangle.h diff --git a/Common/Makefile b/Common/Makefile index 612c4ed3d5..7235d9ed38 100644 --- a/Common/Makefile +++ b/Common/Makefile @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.76 2005-06-03 17:32:29 geuzaine Exp $ +# $Id: Makefile,v 1.77 2005-09-21 17:29:36 geuzaine Exp $ # # Copyright (C) 1997-2005 C. Geuzaine, J.-F. Remacle # @@ -23,7 +23,8 @@ include ../variables LIB = ../lib/libGmshCommon.a INCLUDE = -I../Common -I../DataStr -I../Geo -I../Graphics -I../Mesh\ - -I../Numeric -I../Parser -I../Plugin -I../Fltk -I../MathEval + -I../Numeric -I../Parser -I../Plugin -I../Fltk\ + -I../contrib/MathEval CFLAGS = ${OPTIM} ${FLAGS} ${INCLUDE} SRC = Context.cpp\ diff --git a/Fltk/Makefile b/Fltk/Makefile index 05d406690b..99355da315 100644 --- a/Fltk/Makefile +++ b/Fltk/Makefile @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.73 2005-08-22 00:35:06 geuzaine Exp $ +# $Id: Makefile,v 1.74 2005-09-21 17:29:36 geuzaine Exp $ # # Copyright (C) 1997-2005 C. Geuzaine, J.-F. Remacle # @@ -23,7 +23,8 @@ include ../variables LIB = ../lib/libGmshFltk.a INCLUDE = -I../Common -I../DataStr -I../Graphics -I../Geo -I../Mesh\ - -I../Numeric -I../Parser -I../Fltk -I../Plugin -I../utils/solvers -I../ANN/include + -I../Numeric -I../Parser -I../Fltk -I../Plugin -I../utils/solvers\ + -I../contrib/ANN/include CFLAGS = ${OPTIM} ${FLAGS} ${INCLUDE} SRC = Main.cpp \ diff --git a/Geo/Makefile b/Geo/Makefile index 7c08013cf5..106c942560 100644 --- a/Geo/Makefile +++ b/Geo/Makefile @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.65 2005-07-15 10:31:06 geuzaine Exp $ +# $Id: Makefile,v 1.66 2005-09-21 17:29:36 geuzaine Exp $ # # Copyright (C) 1997-2005 C. Geuzaine, J.-F. Remacle # @@ -22,8 +22,9 @@ include ../variables LIB = ../lib/libGmshGeo.a -INCLUDE = -I../Common -I../DataStr -I../Geo -I../Mesh -I../Numeric -I../NR\ - -I../Parser -I../Fltk +INCLUDE = -I../Common -I../DataStr -I../Geo -I../Mesh -I../Numeric\ + -I../Parser -I../Fltk\ + -I../contrib/NR CFLAGS = ${OPTIM} ${FLAGS} ${INCLUDE} SRC = CAD.cpp \ diff --git a/Graphics/Makefile b/Graphics/Makefile index 57db350a9a..d168498c7c 100644 --- a/Graphics/Makefile +++ b/Graphics/Makefile @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.72 2005-08-19 14:07:32 remacle Exp $ +# $Id: Makefile,v 1.73 2005-09-21 17:29:37 geuzaine Exp $ # # Copyright (C) 1997-2005 C. Geuzaine, J.-F. Remacle # @@ -23,7 +23,8 @@ include ../variables LIB = ../lib/libGmshGraphics.a INCLUDE = -I../Common -I../DataStr -I../Geo -I../Graphics\ - -I../Fltk -I../Mesh -I../Numeric -I../Parser -I../Plugin -I../ANN/include + -I../Fltk -I../Mesh -I../Numeric -I../Parser -I../Plugin\ + -I../contrib/ANN/include CFLAGS = ${OPTIM} ${FLAGS} ${INCLUDE} SRC = Draw.cpp \ diff --git a/Makefile b/Makefile index 0886f105ab..c69733e595 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.395 2005-08-31 22:03:26 geuzaine Exp $ +# $Id: Makefile,v 1.396 2005-09-21 17:29:36 geuzaine Exp $ # # Copyright (C) 1997-2005 C. Geuzaine, J.-F. Remacle # @@ -90,7 +90,7 @@ clean: rm -f ${GMSH_VERSION_FILE} clean-most: - for i in doc lib ${GMSH_DIRS:Netgen=}; do (cd $$i && ${MAKE} clean); done + for i in doc lib ${GMSH_DIRS:contrib/Netgen=}; do (cd $$i && ${MAKE} clean); done rm -f ${GMSH_VERSION_FILE} depend: initialtag @@ -133,24 +133,26 @@ etags: source-common: rm -rf gmsh-${GMSH_VERSION} - tar zcvf gmsh.tgz `ls TODO README* */README* */COPYING* */VERSION*\ - configure *.in *.spec Makefile */Makefile\ - */*.[chylr] */*.[ch]pp */*/*/*.[chyli]*\ - */*.rc */*.res */*.ico */*.icns`\ + tar zcvf gmsh.tgz `ls TODO README* */README* */*/README* */COPYING* */VERSION*\ + configure *.in *.spec Makefile */Makefile */*/Makefile\ + */*.[chylr] */*/*.[chylr] */*.[ch]pp */*/*.[ch]pp\ + */*/*/*/*.[chyli]* */*.rc */*.res */*.ico */*.icns`\ doc demos tutorial utils mkdir gmsh-${GMSH_VERSION} cd gmsh-${GMSH_VERSION} && tar zxvf ../gmsh.tgz rm -f gmsh.tgz source: source-common - cd gmsh-${GMSH_VERSION} && rm -rf CVS */CVS */*/CVS */*/*/CVS */.globalrc\ - NR Triangle/triangle.* Tetgen/tetgen.* Tetgen/predicates.*\ + cd gmsh-${GMSH_VERSION} && rm -rf CVS */CVS */*/CVS */*/*/CVS */*/*/*/CVS\ + */.globalrc contrib/NR contrib/Triangle/triangle.* contrib/Tetgen/tetgen.*\ + contrib/Tetgen/predicates.*\ utils/commercial ${GMSH_VERSION_FILE} tar zcvf gmsh-${GMSH_VERSION}-source.tgz gmsh-${GMSH_VERSION} source-commercial: source-common - cd gmsh-${GMSH_VERSION} && rm -rf CVS */CVS */*/CVS */*/*/CVS */.globalrc\ - MathEval Triangle/triangle.* Tetgen/tetgen.* Tetgen/predicates.* Netgen/libsrc\ + cd gmsh-${GMSH_VERSION} && rm -rf CVS */CVS */*/CVS */*/*/CVS */*/*/*/CVS\ + */.globalrc contrib/MathEval contrib/Triangle/triangle.* contrib/Tetgen/tetgen.*\ + contrib/Tetgen/predicates.* contrib/Netgen/libsrc\ TODO *.spec doc/gmsh.html doc/FAQ doc/README.cvs\ utils/commercial ${GMSH_VERSION_FILE} cp -f utils/commercial/README gmsh-${GMSH_VERSION}/README diff --git a/Mesh/Makefile b/Mesh/Makefile index 7eb1902c4c..02f16d2a67 100644 --- a/Mesh/Makefile +++ b/Mesh/Makefile @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.95 2005-09-07 14:36:45 remacle Exp $ +# $Id: Makefile,v 1.96 2005-09-21 17:29:37 geuzaine Exp $ # # Copyright (C) 1997-2005 C. Geuzaine, J.-F. Remacle # @@ -22,9 +22,12 @@ include ../variables LIB = ../lib/libGmshMesh.a -INCLUDE = -I../Numeric -I../NR -I../Common -I../DataStr -I../Geo -I../Mesh\ - -I../Graphics -I../Parser -I../Fltk -I../Triangle -I../Tetgen\ - -I../Netgen -I../Netgen/libsrc/include -I../Netgen/libsrc/interface -I../ANN/include -I../Metis +INCLUDE = -I../Numeric -I../Common -I../DataStr -I../Geo -I../Mesh\ + -I../Graphics -I../Parser -I../Fltk\ + -I../contrib/NR -I../contrib/Triangle -I../contrib/Tetgen\ + -I../contrib/Netgen -I../contrib/Netgen/libsrc/include\ + -I../contrib/Netgen/libsrc/interface -I../contrib/ANN/include\ + -I../contrib/Metis CFLAGS = ${OPTIM} ${FLAGS} ${INCLUDE} SRC = 1D_Mesh.cpp \ diff --git a/Parser/Makefile b/Parser/Makefile index 875bef0aac..1bc5e3a8be 100644 --- a/Parser/Makefile +++ b/Parser/Makefile @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.74 2005-08-19 14:07:35 remacle Exp $ +# $Id: Makefile,v 1.75 2005-09-21 17:29:37 geuzaine Exp $ # # Copyright (C) 1997-2005 C. Geuzaine, J.-F. Remacle # @@ -23,7 +23,8 @@ include ../variables LIB = ../lib/libGmshParser.a INCLUDE = -I../Common -I../DataStr -I../Geo -I../Graphics\ - -I../Mesh -I../Numeric -I../Fltk -I../Plugin -I../Parallel -I../ANN/include + -I../Mesh -I../Numeric -I../Fltk -I../Plugin -I../Parallel\ + -I../contrib/ANN/include CFLAGS = ${OPTIM} ${FLAGS} ${INCLUDE} SRC = Gmsh.tab.cpp\ diff --git a/Plugin/Makefile b/Plugin/Makefile index 12b3bdfb92..a1102f133a 100644 --- a/Plugin/Makefile +++ b/Plugin/Makefile @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.83 2005-06-27 19:34:34 geuzaine Exp $ +# $Id: Makefile,v 1.84 2005-09-21 17:29:37 geuzaine Exp $ # # Copyright (C) 1997-2005 C. Geuzaine, J.-F. Remacle # @@ -23,8 +23,9 @@ include ../variables LIB = ../lib/libGmshPlugin.a INCLUDE = -I../Common -I../Graphics -I../DataStr -I../Geo -I../Fltk\ - -I../Mesh -I../Numeric -I../Triangle -I../MathEval -CFLAGS = -DMPICH_SKIP_MPICXX ${OPTIM} ${FLAGS} ${INCLUDE} + -I../Mesh -I../Numeric -I../Triangle\ + -I../contrib/MathEval +CFLAGS = ${OPTIM} ${FLAGS} ${INCLUDE} SRC = Plugin.cpp\ Levelset.cpp\ diff --git a/configure b/configure index 8656b52314..35500545c5 100755 --- a/configure +++ b/configure @@ -3742,24 +3742,24 @@ else fi -echo "$as_me:$LINENO: checking for ./Triangle/triangle.c" >&5 -echo $ECHO_N "checking for ./Triangle/triangle.c... $ECHO_C" >&6 -if test "${ac_cv_file___Triangle_triangle_c+set}" = set; then +echo "$as_me:$LINENO: checking for ./contrib/Triangle/triangle.c" >&5 +echo $ECHO_N "checking for ./contrib/Triangle/triangle.c... $ECHO_C" >&6 +if test "${ac_cv_file___contrib_Triangle_triangle_c+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else test "$cross_compiling" = yes && { { echo "$as_me:$LINENO: error: cannot check for file existence when cross compiling" >&5 echo "$as_me: error: cannot check for file existence when cross compiling" >&2;} { (exit 1); exit 1; }; } -if test -r "./Triangle/triangle.c"; then - ac_cv_file___Triangle_triangle_c=yes +if test -r "./contrib/Triangle/triangle.c"; then + ac_cv_file___contrib_Triangle_triangle_c=yes else - ac_cv_file___Triangle_triangle_c=no + ac_cv_file___contrib_Triangle_triangle_c=no fi fi -echo "$as_me:$LINENO: result: $ac_cv_file___Triangle_triangle_c" >&5 -echo "${ECHO_T}$ac_cv_file___Triangle_triangle_c" >&6 -if test $ac_cv_file___Triangle_triangle_c = yes; then +echo "$as_me:$LINENO: result: $ac_cv_file___contrib_Triangle_triangle_c" >&5 +echo "${ECHO_T}$ac_cv_file___contrib_Triangle_triangle_c" >&6 +if test $ac_cv_file___contrib_Triangle_triangle_c = yes; then TRIANGLE="yes" else TRIANGLE="no" @@ -3767,15 +3767,15 @@ fi if test "x${TRIANGLE}" = "xyes"; then if test "x$enable_triangle" != "xno"; then - GMSH_DIRS="${GMSH_DIRS} Triangle" + GMSH_DIRS="${GMSH_DIRS} contrib/Triangle" GMSH_LIBS="${GMSH_LIBS} -lGmshTriangle" FLAGS="-DHAVE_TRIANGLE ${FLAGS}" echo "********************************************************************" echo "You are building a version of Gmsh that contains Jonathan" echo "Shewchuk's Triangle as an alternative isotropic 2D mesh generator." echo "Please note that by doing so, you agree with Triangle's licensing" - echo "requirements stated in ./Triangle/README. (Most notably, you may" - echo "then only redistribute Gmsh for non-commercial purposes.)" + echo "requirements stated in ./contrib/Triangle/README. (Most notably, you" + echo "may then only redistribute Gmsh for non-commercial purposes.)" echo "To disable Triangle, run configure again with the --disable-triangle" echo "option." echo "********************************************************************" @@ -3787,33 +3787,33 @@ else echo "isotropic 2D mesh generator, please download Triangle from the" echo "author's web site at http://www.cs.cmu.edu/~quake/triangle.html," echo "unpack the archive and copy the two files 'triangle.c' and" - echo "'triangle.h' in the ./Triangle subdirectory. Then run ./configure" - echo "again." + echo "'triangle.h' in the ./contrib/Triangle subdirectory. Then run" + echo "./configure again." echo "Please note that by doing so, you agree with Triangle's licensing" - echo "requirements stated in ./Triangle/README. (Most notably, you may" - echo "then only redistribute Gmsh if no compensation is received.)" + echo "requirements stated in ./contrib/Triangle/README. (Most notably, you" + echo "may then only redistribute Gmsh if no compensation is received.)" echo "********************************************************************" fi fi -echo "$as_me:$LINENO: checking for ./ANN/include/ANN/ANN.h" >&5 -echo $ECHO_N "checking for ./ANN/include/ANN/ANN.h... $ECHO_C" >&6 -if test "${ac_cv_file___ANN_include_ANN_ANN_h+set}" = set; then +echo "$as_me:$LINENO: checking for ./contrib/ANN/include/ANN/ANN.h" >&5 +echo $ECHO_N "checking for ./contrib/ANN/include/ANN/ANN.h... $ECHO_C" >&6 +if test "${ac_cv_file___contrib_ANN_include_ANN_ANN_h+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else test "$cross_compiling" = yes && { { echo "$as_me:$LINENO: error: cannot check for file existence when cross compiling" >&5 echo "$as_me: error: cannot check for file existence when cross compiling" >&2;} { (exit 1); exit 1; }; } -if test -r "./ANN/include/ANN/ANN.h"; then - ac_cv_file___ANN_include_ANN_ANN_h=yes +if test -r "./contrib/ANN/include/ANN/ANN.h"; then + ac_cv_file___contrib_ANN_include_ANN_ANN_h=yes else - ac_cv_file___ANN_include_ANN_ANN_h=no + ac_cv_file___contrib_ANN_include_ANN_ANN_h=no fi fi -echo "$as_me:$LINENO: result: $ac_cv_file___ANN_include_ANN_ANN_h" >&5 -echo "${ECHO_T}$ac_cv_file___ANN_include_ANN_ANN_h" >&6 -if test $ac_cv_file___ANN_include_ANN_ANN_h = yes; then +echo "$as_me:$LINENO: result: $ac_cv_file___contrib_ANN_include_ANN_ANN_h" >&5 +echo "${ECHO_T}$ac_cv_file___contrib_ANN_include_ANN_ANN_h" >&6 +if test $ac_cv_file___contrib_ANN_include_ANN_ANN_h = yes; then ANN="yes" else ANN="no" @@ -3821,14 +3821,14 @@ fi if test "x${ANN}" = "xyes"; then if test "x$enable_ann" != "xno"; then - GMSH_DIRS="${GMSH_DIRS} ANN" + GMSH_DIRS="${GMSH_DIRS} contrib/ANN" GMSH_LIBS="${GMSH_LIBS} -lGmshANN" FLAGS="-DHAVE_ANN_ ${FLAGS}" echo "********************************************************************" echo "You are building a version of Gmsh that contains ANN, the" echo "Approximate Nearest Neighbor library." echo "Please note that by doing so, you agree with ANN's licensing" - echo "requirements stated in ./ANN/Copyright.txt." + echo "requirements stated in ./contrib/ANN/Copyright.txt." echo "To disable ANN, run configure again with the --disable-ann" echo "option." echo "********************************************************************" @@ -3840,29 +3840,29 @@ else echo "STL mesher, please download ANN from the" echo "author's web site at http://www.cs.umd.edu/~mount/ANN/," echo "unpack the archive and copy both src and include directories in the" - echo "./ANN subdirectory. Then run ./configure again." + echo "./contrib/ANN subdirectory. Then run ./configure again." echo "********************************************************************" fi fi -echo "$as_me:$LINENO: checking for ./Metis/metis.h" >&5 -echo $ECHO_N "checking for ./Metis/metis.h... $ECHO_C" >&6 -if test "${ac_cv_file___Metis_metis_h+set}" = set; then +echo "$as_me:$LINENO: checking for ./contrib/Metis/metis.h" >&5 +echo $ECHO_N "checking for ./contrib/Metis/metis.h... $ECHO_C" >&6 +if test "${ac_cv_file___contrib_Metis_metis_h+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else test "$cross_compiling" = yes && { { echo "$as_me:$LINENO: error: cannot check for file existence when cross compiling" >&5 echo "$as_me: error: cannot check for file existence when cross compiling" >&2;} { (exit 1); exit 1; }; } -if test -r "./Metis/metis.h"; then - ac_cv_file___Metis_metis_h=yes +if test -r "./contrib/Metis/metis.h"; then + ac_cv_file___contrib_Metis_metis_h=yes else - ac_cv_file___Metis_metis_h=no + ac_cv_file___contrib_Metis_metis_h=no fi fi -echo "$as_me:$LINENO: result: $ac_cv_file___Metis_metis_h" >&5 -echo "${ECHO_T}$ac_cv_file___Metis_metis_h" >&6 -if test $ac_cv_file___Metis_metis_h = yes; then +echo "$as_me:$LINENO: result: $ac_cv_file___contrib_Metis_metis_h" >&5 +echo "${ECHO_T}$ac_cv_file___contrib_Metis_metis_h" >&6 +if test $ac_cv_file___contrib_Metis_metis_h = yes; then METIS="yes" else METIS="no" @@ -3870,14 +3870,14 @@ fi if test "x${METIS}" = "xyes"; then if test "x$enable_metis" != "xno"; then - GMSH_DIRS="${GMSH_DIRS} Metis" + GMSH_DIRS="${GMSH_DIRS} contrib/Metis" GMSH_LIBS="${GMSH_LIBS} -lGmshMetis" FLAGS="-DHAVE_METIS ${FLAGS}" echo "********************************************************************" echo "You are building a version of Gmsh that contains METIS, the" echo "Serial Graph Partitioner." echo "Please note that by doing so, you agree with METIS's licensing" - echo "requirements stated in ./Metis/Doc/manual.ps." + echo "requirements stated in ./contrib/Metis/Doc/manual.ps." echo "To disable METIS, run configure again with the --disable-metis" echo "option." echo "********************************************************************" @@ -3885,32 +3885,33 @@ if test "x${METIS}" = "xyes"; then else if test "x$enable-metis" != "xno"; then echo "********************************************************************" - echo "If you want to use METIS for doing mesh partitioning, please download METIS from the" - echo "author's web site at http://www-users.cs.umn.edu/~karypis/metis/" - echo "unpack the archive and copy the Lib Directory in the" - echo "./Metis subdirectory. Then run ./configure again." + echo "If you want to use METIS for doing mesh partitioning, please" + echo "download METIS from the author's web site at" + echo "http://www-users.cs.umn.edu/~karypis/metis/, unpack the archive and" + echo "copy the Lib Directory in the ./contrib/Metis subdirectory. Then" + echo "run ./configure again." echo "********************************************************************" fi fi -echo "$as_me:$LINENO: checking for ./Netgen/libsrc/meshing/meshclass.cpp" >&5 -echo $ECHO_N "checking for ./Netgen/libsrc/meshing/meshclass.cpp... $ECHO_C" >&6 -if test "${ac_cv_file___Netgen_libsrc_meshing_meshclass_cpp+set}" = set; then +echo "$as_me:$LINENO: checking for ./contrib/Netgen/libsrc/meshing/meshclass.cpp" >&5 +echo $ECHO_N "checking for ./contrib/Netgen/libsrc/meshing/meshclass.cpp... $ECHO_C" >&6 +if test "${ac_cv_file___contrib_Netgen_libsrc_meshing_meshclass_cpp+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else test "$cross_compiling" = yes && { { echo "$as_me:$LINENO: error: cannot check for file existence when cross compiling" >&5 echo "$as_me: error: cannot check for file existence when cross compiling" >&2;} { (exit 1); exit 1; }; } -if test -r "./Netgen/libsrc/meshing/meshclass.cpp"; then - ac_cv_file___Netgen_libsrc_meshing_meshclass_cpp=yes +if test -r "./contrib/Netgen/libsrc/meshing/meshclass.cpp"; then + ac_cv_file___contrib_Netgen_libsrc_meshing_meshclass_cpp=yes else - ac_cv_file___Netgen_libsrc_meshing_meshclass_cpp=no + ac_cv_file___contrib_Netgen_libsrc_meshing_meshclass_cpp=no fi fi -echo "$as_me:$LINENO: result: $ac_cv_file___Netgen_libsrc_meshing_meshclass_cpp" >&5 -echo "${ECHO_T}$ac_cv_file___Netgen_libsrc_meshing_meshclass_cpp" >&6 -if test $ac_cv_file___Netgen_libsrc_meshing_meshclass_cpp = yes; then +echo "$as_me:$LINENO: result: $ac_cv_file___contrib_Netgen_libsrc_meshing_meshclass_cpp" >&5 +echo "${ECHO_T}$ac_cv_file___contrib_Netgen_libsrc_meshing_meshclass_cpp" >&6 +if test $ac_cv_file___contrib_Netgen_libsrc_meshing_meshclass_cpp = yes; then NETGEN="yes" else NETGEN="no" @@ -3918,13 +3919,13 @@ fi if test "x${NETGEN}" = "xyes"; then if test "x$enable_netgen" != "xno"; then - GMSH_DIRS="${GMSH_DIRS} Netgen" + GMSH_DIRS="${GMSH_DIRS} contrib/Netgen" GMSH_LIBS="${GMSH_LIBS} -lGmshNetgen" FLAGS="-DHAVE_NETGEN ${FLAGS}" echo "********************************************************************" echo "You are building a version of Gmsh that contains Joachim Schoberl's" echo "Netgen as an alternative 3D mesh generator. Netgen is distributed" - echo "under the GNU LGPL: see ./Netgen/COPYING.LIB for more info." + echo "under the GNU LGPL: see ./contrib/Netgen/COPYING.LIB for more info." echo "To disable Netgen, run configure again with the --disable-netgen" echo "option." echo "********************************************************************" @@ -3935,32 +3936,32 @@ else echo "If you want to use Joachim Schoberl's Netgen as an alternative" echo "3D mesh generator, please download Netgen from the project's" echo "web site at http://www.hpfem.jku.at/netgen/, unpack the archive" - echo "and move the libsrc subdirectory in the ./Netgen subdirectory. Then" - echo "run ./configure again." + echo "and move the libsrc subdirectory in the ./contrib/Netgen" + echo "subdirectory. Then run ./configure again." echo "Please note that by doing so, you agree with Netgen's licensing" - echo "requirements stated in ./Netgen/COPYING.LIB." + echo "requirements stated in ./contrib/Netgen/COPYING.LIB." echo "********************************************************************" fi fi -echo "$as_me:$LINENO: checking for ./Tetgen/tetgen.h" >&5 -echo $ECHO_N "checking for ./Tetgen/tetgen.h... $ECHO_C" >&6 -if test "${ac_cv_file___Tetgen_tetgen_h+set}" = set; then +echo "$as_me:$LINENO: checking for ./contrib/Tetgen/tetgen.h" >&5 +echo $ECHO_N "checking for ./contrib/Tetgen/tetgen.h... $ECHO_C" >&6 +if test "${ac_cv_file___contrib_Tetgen_tetgen_h+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else test "$cross_compiling" = yes && { { echo "$as_me:$LINENO: error: cannot check for file existence when cross compiling" >&5 echo "$as_me: error: cannot check for file existence when cross compiling" >&2;} { (exit 1); exit 1; }; } -if test -r "./Tetgen/tetgen.h"; then - ac_cv_file___Tetgen_tetgen_h=yes +if test -r "./contrib/Tetgen/tetgen.h"; then + ac_cv_file___contrib_Tetgen_tetgen_h=yes else - ac_cv_file___Tetgen_tetgen_h=no + ac_cv_file___contrib_Tetgen_tetgen_h=no fi fi -echo "$as_me:$LINENO: result: $ac_cv_file___Tetgen_tetgen_h" >&5 -echo "${ECHO_T}$ac_cv_file___Tetgen_tetgen_h" >&6 -if test $ac_cv_file___Tetgen_tetgen_h = yes; then +echo "$as_me:$LINENO: result: $ac_cv_file___contrib_Tetgen_tetgen_h" >&5 +echo "${ECHO_T}$ac_cv_file___contrib_Tetgen_tetgen_h" >&6 +if test $ac_cv_file___contrib_Tetgen_tetgen_h = yes; then TETGEN="yes" else TETGEN="no" @@ -3968,15 +3969,15 @@ fi if test "x${TETGEN}" = "xyes"; then if test "x$enable_tetgen" != "xno"; then - GMSH_DIRS="${GMSH_DIRS} Tetgen" + GMSH_DIRS="${GMSH_DIRS} contrib/Tetgen" GMSH_LIBS="${GMSH_LIBS} -lGmshTetgen" FLAGS="-DHAVE_TETGEN ${FLAGS}" echo "********************************************************************" echo "You are building a version of Gmsh that contains Hang Si's" echo "Tetgen as an alternative 3D mesh generator." echo "Please note that by doing so, you agree with Tetgen's licensing" - echo "requirements stated in ./Tetgen/LICENSE. (Most notably, you may" - echo "then only redistribute Gmsh for non-commercial purposes.)" + echo "requirements stated in ./contrib/Tetgen/LICENSE. (Most notably, you" + echo "may then only redistribute Gmsh for non-commercial purposes.)" echo "To disable Tetgen, run configure again with the --disable-tetgen" echo "option." echo "********************************************************************" @@ -3988,32 +3989,32 @@ else echo "3D mesh generator, please download Tetgen from the project's" echo "web site at http://www.tetgen.berlios.de, unpack the archive" echo "and move the files predicates.cxx, tetgen.cxx and tetgen.h in" - echo "the ./Tetgen subdirectory. Then run ./configure again." + echo "the ./contrib/Tetgen subdirectory. Then run ./configure again." echo "Please note that by doing so, you agree with Tetgen's licensing" - echo "requirements stated in ./Tetgen/LICENSE. (Most notably, you may" - echo "then only redistribute Gmsh if no compensation is received.)" + echo "requirements stated in ./contrib/Tetgen/LICENSE. (Most notably, you" + echo "may then only redistribute Gmsh if no compensation is received.)" echo "********************************************************************" fi fi -echo "$as_me:$LINENO: checking for ./MathEval/matheval.cpp" >&5 -echo $ECHO_N "checking for ./MathEval/matheval.cpp... $ECHO_C" >&6 -if test "${ac_cv_file___MathEval_matheval_cpp+set}" = set; then +echo "$as_me:$LINENO: checking for ./contrib/MathEval/matheval.cpp" >&5 +echo $ECHO_N "checking for ./contrib/MathEval/matheval.cpp... $ECHO_C" >&6 +if test "${ac_cv_file___contrib_MathEval_matheval_cpp+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else test "$cross_compiling" = yes && { { echo "$as_me:$LINENO: error: cannot check for file existence when cross compiling" >&5 echo "$as_me: error: cannot check for file existence when cross compiling" >&2;} { (exit 1); exit 1; }; } -if test -r "./MathEval/matheval.cpp"; then - ac_cv_file___MathEval_matheval_cpp=yes +if test -r "./contrib/MathEval/matheval.cpp"; then + ac_cv_file___contrib_MathEval_matheval_cpp=yes else - ac_cv_file___MathEval_matheval_cpp=no + ac_cv_file___contrib_MathEval_matheval_cpp=no fi fi -echo "$as_me:$LINENO: result: $ac_cv_file___MathEval_matheval_cpp" >&5 -echo "${ECHO_T}$ac_cv_file___MathEval_matheval_cpp" >&6 -if test $ac_cv_file___MathEval_matheval_cpp = yes; then +echo "$as_me:$LINENO: result: $ac_cv_file___contrib_MathEval_matheval_cpp" >&5 +echo "${ECHO_T}$ac_cv_file___contrib_MathEval_matheval_cpp" >&6 +if test $ac_cv_file___contrib_MathEval_matheval_cpp = yes; then MATHEVAL="yes" else MATHEVAL="no" @@ -4021,7 +4022,7 @@ fi if test "x${MATHEVAL}" = "xyes"; then if test "x$enable_matheval" != "xno"; then - GMSH_DIRS="${GMSH_DIRS} MathEval" + GMSH_DIRS="${GMSH_DIRS} contrib/MathEval" GMSH_LIBS="${GMSH_LIBS} -lGmshMathEval" FLAGS="-DHAVE_MATH_EVAL ${FLAGS}" fi @@ -4174,24 +4175,24 @@ fi fi fi if test "x${GSL}" != "xyes"; then - echo "$as_me:$LINENO: checking for ./NR/dsvdcmp.cpp" >&5 -echo $ECHO_N "checking for ./NR/dsvdcmp.cpp... $ECHO_C" >&6 -if test "${ac_cv_file___NR_dsvdcmp_cpp+set}" = set; then + echo "$as_me:$LINENO: checking for ./contrib/NR/dsvdcmp.cpp" >&5 +echo $ECHO_N "checking for ./contrib/NR/dsvdcmp.cpp... $ECHO_C" >&6 +if test "${ac_cv_file___contrib_NR_dsvdcmp_cpp+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else test "$cross_compiling" = yes && { { echo "$as_me:$LINENO: error: cannot check for file existence when cross compiling" >&5 echo "$as_me: error: cannot check for file existence when cross compiling" >&2;} { (exit 1); exit 1; }; } -if test -r "./NR/dsvdcmp.cpp"; then - ac_cv_file___NR_dsvdcmp_cpp=yes +if test -r "./contrib/NR/dsvdcmp.cpp"; then + ac_cv_file___contrib_NR_dsvdcmp_cpp=yes else - ac_cv_file___NR_dsvdcmp_cpp=no + ac_cv_file___contrib_NR_dsvdcmp_cpp=no fi fi -echo "$as_me:$LINENO: result: $ac_cv_file___NR_dsvdcmp_cpp" >&5 -echo "${ECHO_T}$ac_cv_file___NR_dsvdcmp_cpp" >&6 -if test $ac_cv_file___NR_dsvdcmp_cpp = yes; then +echo "$as_me:$LINENO: result: $ac_cv_file___contrib_NR_dsvdcmp_cpp" >&5 +echo "${ECHO_T}$ac_cv_file___contrib_NR_dsvdcmp_cpp" >&6 +if test $ac_cv_file___contrib_NR_dsvdcmp_cpp = yes; then NR="yes" else NR="no" @@ -4204,7 +4205,7 @@ fi echo "To use the GSL instead, run configure again with the --enable-gsl" echo "option." echo "********************************************************************" - GMSH_DIRS="${GMSH_DIRS} NR" + GMSH_DIRS="${GMSH_DIRS} contrib/NR" GMSH_LIBS="${GMSH_LIBS} -lGmshNR" else echo "********************************************************************" diff --git a/configure.in b/configure.in index 27f5183387..e9ca9483ea 100644 --- a/configure.in +++ b/configure.in @@ -1,4 +1,4 @@ -dnl $Id: configure.in,v 1.79 2005-09-15 16:58:09 geuzaine Exp $ +dnl $Id: configure.in,v 1.80 2005-09-21 17:29:36 geuzaine Exp $ dnl dnl Copyright (C) 1997-2005 C. Geuzaine, J.-F. Remacle dnl @@ -226,18 +226,18 @@ else fi dnl Check if Triangle is installed -AC_CHECK_FILE(./Triangle/triangle.c, TRIANGLE="yes", TRIANGLE="no") +AC_CHECK_FILE(./contrib/Triangle/triangle.c, TRIANGLE="yes", TRIANGLE="no") if test "x${TRIANGLE}" = "xyes"; then if test "x$enable_triangle" != "xno"; then - GMSH_DIRS="${GMSH_DIRS} Triangle" + GMSH_DIRS="${GMSH_DIRS} contrib/Triangle" GMSH_LIBS="${GMSH_LIBS} -lGmshTriangle" FLAGS="-DHAVE_TRIANGLE ${FLAGS}" echo "********************************************************************" echo "You are building a version of Gmsh that contains Jonathan" echo "Shewchuk's Triangle as an alternative isotropic 2D mesh generator." echo "Please note that by doing so, you agree with Triangle's licensing" - echo "requirements stated in ./Triangle/README. (Most notably, you may" - echo "then only redistribute Gmsh for non-commercial purposes.)" + echo "requirements stated in ./contrib/Triangle/README. (Most notably, you" + echo "may then only redistribute Gmsh for non-commercial purposes.)" echo "To disable Triangle, run configure again with the --disable-triangle" echo "option." echo "********************************************************************" @@ -249,27 +249,27 @@ else echo "isotropic 2D mesh generator, please download Triangle from the" echo "author's web site at http://www.cs.cmu.edu/~quake/triangle.html," echo "unpack the archive and copy the two files 'triangle.c' and" - echo "'triangle.h' in the ./Triangle subdirectory. Then run ./configure" - echo "again." + echo "'triangle.h' in the ./contrib/Triangle subdirectory. Then run" + echo "./configure again." echo "Please note that by doing so, you agree with Triangle's licensing" - echo "requirements stated in ./Triangle/README. (Most notably, you may" - echo "then only redistribute Gmsh if no compensation is received.)" + echo "requirements stated in ./contrib/Triangle/README. (Most notably, you" + echo "may then only redistribute Gmsh if no compensation is received.)" echo "********************************************************************" fi fi dnl Check if ANN is installed -AC_CHECK_FILE(./ANN/include/ANN/ANN.h, ANN="yes", ANN="no") +AC_CHECK_FILE(./contrib/ANN/include/ANN/ANN.h, ANN="yes", ANN="no") if test "x${ANN}" = "xyes"; then if test "x$enable_ann" != "xno"; then - GMSH_DIRS="${GMSH_DIRS} ANN" + GMSH_DIRS="${GMSH_DIRS} contrib/ANN" GMSH_LIBS="${GMSH_LIBS} -lGmshANN" FLAGS="-DHAVE_ANN_ ${FLAGS}" echo "********************************************************************" echo "You are building a version of Gmsh that contains ANN, the" echo "Approximate Nearest Neighbor library." echo "Please note that by doing so, you agree with ANN's licensing" - echo "requirements stated in ./ANN/Copyright.txt." + echo "requirements stated in ./contrib/ANN/Copyright.txt." echo "To disable ANN, run configure again with the --disable-ann" echo "option." echo "********************************************************************" @@ -281,23 +281,23 @@ else echo "STL mesher, please download ANN from the" echo "author's web site at http://www.cs.umd.edu/~mount/ANN/," echo "unpack the archive and copy both src and include directories in the" - echo "./ANN subdirectory. Then run ./configure again." + echo "./contrib/ANN subdirectory. Then run ./configure again." echo "********************************************************************" fi fi dnl Check if METIS is installed -AC_CHECK_FILE(./Metis/metis.h, METIS="yes", METIS="no") +AC_CHECK_FILE(./contrib/Metis/metis.h, METIS="yes", METIS="no") if test "x${METIS}" = "xyes"; then if test "x$enable_metis" != "xno"; then - GMSH_DIRS="${GMSH_DIRS} Metis" + GMSH_DIRS="${GMSH_DIRS} contrib/Metis" GMSH_LIBS="${GMSH_LIBS} -lGmshMetis" FLAGS="-DHAVE_METIS ${FLAGS}" echo "********************************************************************" echo "You are building a version of Gmsh that contains METIS, the" echo "Serial Graph Partitioner." echo "Please note that by doing so, you agree with METIS's licensing" - echo "requirements stated in ./Metis/Doc/manual.ps." + echo "requirements stated in ./contrib/Metis/Doc/manual.ps." echo "To disable METIS, run configure again with the --disable-metis" echo "option." echo "********************************************************************" @@ -305,25 +305,26 @@ if test "x${METIS}" = "xyes"; then else if test "x$enable-metis" != "xno"; then echo "********************************************************************" - echo "If you want to use METIS for doing mesh partitioning, please download METIS from the" - echo "author's web site at http://www-users.cs.umn.edu/~karypis/metis/" - echo "unpack the archive and copy the Lib Directory in the" - echo "./Metis subdirectory. Then run ./configure again." + echo "If you want to use METIS for doing mesh partitioning, please" + echo "download METIS from the author's web site at" + echo "http://www-users.cs.umn.edu/~karypis/metis/, unpack the archive and" + echo "copy the Lib Directory in the ./contrib/Metis subdirectory. Then" + echo "run ./configure again." echo "********************************************************************" fi fi dnl Check if Netgen is installed -AC_CHECK_FILE(./Netgen/libsrc/meshing/meshclass.cpp, NETGEN="yes", NETGEN="no") +AC_CHECK_FILE(./contrib/Netgen/libsrc/meshing/meshclass.cpp, NETGEN="yes", NETGEN="no") if test "x${NETGEN}" = "xyes"; then if test "x$enable_netgen" != "xno"; then - GMSH_DIRS="${GMSH_DIRS} Netgen" + GMSH_DIRS="${GMSH_DIRS} contrib/Netgen" GMSH_LIBS="${GMSH_LIBS} -lGmshNetgen" FLAGS="-DHAVE_NETGEN ${FLAGS}" echo "********************************************************************" echo "You are building a version of Gmsh that contains Joachim Schoberl's" echo "Netgen as an alternative 3D mesh generator. Netgen is distributed" - echo "under the GNU LGPL: see ./Netgen/COPYING.LIB for more info." + echo "under the GNU LGPL: see ./contrib/Netgen/COPYING.LIB for more info." echo "To disable Netgen, run configure again with the --disable-netgen" echo "option." echo "********************************************************************" @@ -334,27 +335,27 @@ else echo "If you want to use Joachim Schoberl's Netgen as an alternative" echo "3D mesh generator, please download Netgen from the project's" echo "web site at http://www.hpfem.jku.at/netgen/, unpack the archive" - echo "and move the libsrc subdirectory in the ./Netgen subdirectory. Then" - echo "run ./configure again." + echo "and move the libsrc subdirectory in the ./contrib/Netgen" + echo "subdirectory. Then run ./configure again." echo "Please note that by doing so, you agree with Netgen's licensing" - echo "requirements stated in ./Netgen/COPYING.LIB." + echo "requirements stated in ./contrib/Netgen/COPYING.LIB." echo "********************************************************************" fi fi dnl Check if Tetgen is installed -AC_CHECK_FILE(./Tetgen/tetgen.h, TETGEN="yes", TETGEN="no") +AC_CHECK_FILE(./contrib/Tetgen/tetgen.h, TETGEN="yes", TETGEN="no") if test "x${TETGEN}" = "xyes"; then if test "x$enable_tetgen" != "xno"; then - GMSH_DIRS="${GMSH_DIRS} Tetgen" + GMSH_DIRS="${GMSH_DIRS} contrib/Tetgen" GMSH_LIBS="${GMSH_LIBS} -lGmshTetgen" FLAGS="-DHAVE_TETGEN ${FLAGS}" echo "********************************************************************" echo "You are building a version of Gmsh that contains Hang Si's" echo "Tetgen as an alternative 3D mesh generator." echo "Please note that by doing so, you agree with Tetgen's licensing" - echo "requirements stated in ./Tetgen/LICENSE. (Most notably, you may" - echo "then only redistribute Gmsh for non-commercial purposes.)" + echo "requirements stated in ./contrib/Tetgen/LICENSE. (Most notably, you" + echo "may then only redistribute Gmsh for non-commercial purposes.)" echo "To disable Tetgen, run configure again with the --disable-tetgen" echo "option." echo "********************************************************************" @@ -366,19 +367,19 @@ else echo "3D mesh generator, please download Tetgen from the project's" echo "web site at http://www.tetgen.berlios.de, unpack the archive" echo "and move the files predicates.cxx, tetgen.cxx and tetgen.h in" - echo "the ./Tetgen subdirectory. Then run ./configure again." + echo "the ./contrib/Tetgen subdirectory. Then run ./configure again." echo "Please note that by doing so, you agree with Tetgen's licensing" - echo "requirements stated in ./Tetgen/LICENSE. (Most notably, you may" - echo "then only redistribute Gmsh if no compensation is received.)" + echo "requirements stated in ./contrib/Tetgen/LICENSE. (Most notably, you" + echo "may then only redistribute Gmsh if no compensation is received.)" echo "********************************************************************" fi fi dnl Check for MathEval -AC_CHECK_FILE(./MathEval/matheval.cpp, MATHEVAL="yes", MATHEVAL="no") +AC_CHECK_FILE(./contrib/MathEval/matheval.cpp, MATHEVAL="yes", MATHEVAL="no") if test "x${MATHEVAL}" = "xyes"; then if test "x$enable_matheval" != "xno"; then - GMSH_DIRS="${GMSH_DIRS} MathEval" + GMSH_DIRS="${GMSH_DIRS} contrib/MathEval" GMSH_LIBS="${GMSH_LIBS} -lGmshMathEval" FLAGS="-DHAVE_MATH_EVAL ${FLAGS}" fi @@ -403,7 +404,7 @@ if test "x$enable_gsl" != "xno"; then fi if test "x${GSL}" != "xyes"; then dnl Check if non-free numerical recipes routines are in the tree - AC_CHECK_FILE(./NR/dsvdcmp.cpp,NR="yes",NR="no") + AC_CHECK_FILE(./contrib/NR/dsvdcmp.cpp,NR="yes",NR="no") if test "x${NR}" = "xyes"; then echo "********************************************************************" echo "You are building a non-free version of Gmsh, using code copyright" @@ -411,7 +412,7 @@ if test "x${GSL}" != "xyes"; then echo "To use the GSL instead, run configure again with the --enable-gsl" echo "option." echo "********************************************************************" - GMSH_DIRS="${GMSH_DIRS} NR" + GMSH_DIRS="${GMSH_DIRS} contrib/NR" GMSH_LIBS="${GMSH_LIBS} -lGmshNR" else echo "********************************************************************" diff --git a/contrib/ANN/Copyright.txt b/contrib/ANN/Copyright.txt new file mode 100644 index 0000000000..9b752403d4 --- /dev/null +++ b/contrib/ANN/Copyright.txt @@ -0,0 +1,47 @@ +ANN: Approximate Nearest Neighbors +Version: 1.1 +Release Date: May 3, 2005 +---------------------------------------------------------------------------- +Copyright (c) 1997-2005 University of Maryland and Sunil Arya and David +Mount All Rights Reserved. + +This program is free software; you can redistribute it and/or modify it +under the terms of the GNU Lesser Public License as published by the +Free Software Foundation; either version 2.1 of the License, or (at your +option) any later version. + +This program is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser Public License for more details. + +A copy of the terms and conditions of the license can be found in +License.txt or online at + + http://www.gnu.org/copyleft/lesser.html + +To obtain a copy, write to the Free Software Foundation, Inc., +59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +Disclaimer +---------- +The University of Maryland and the authors make no representations about +the suitability or fitness of this software for any purpose. It is +provided "as is" without express or implied warranty. +--------------------------------------------------------------------- + +Authors +------- +David Mount +Dept of Computer Science +University of Maryland, +College Park, MD 20742 USA +mount@cs.umd.edu +http://www.cs.umd.edu/~mount/ + +Sunil Arya +Dept of Computer Science +Hong University of Science and Technology +Clearwater Bay, HONG KONG +arya@cs.ust.hk +http://www.cs.ust.hk/faculty/arya/ diff --git a/contrib/ANN/License.txt b/contrib/ANN/License.txt new file mode 100644 index 0000000000..456ea97817 --- /dev/null +++ b/contrib/ANN/License.txt @@ -0,0 +1,450 @@ +---------------------------------------------------------------------- +The ANN Library (all versions) is provided under the terms and +conditions of the GNU Lesser General Public Library, which is stated +below. It can also be found at: + + http://www.gnu.org/copyleft/lesser.html + +---------------------------------------------------------------------- + +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. + +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. diff --git a/contrib/ANN/Makefile b/contrib/ANN/Makefile new file mode 100644 index 0000000000..15fc66e90e --- /dev/null +++ b/contrib/ANN/Makefile @@ -0,0 +1,114 @@ +# $Id: Makefile,v 1.1 2005-09-21 17:29:37 geuzaine Exp $ +# +# Copyright (C) 1997-2005 C. Geuzaine, J.-F. Remacle +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +# USA. +# +# Please report all bugs and problems to <gmsh@geuz.org>. + +include ../../variables + +LIB = ../../lib/libGmshANN.a +INCLUDE = -I../../Common -I./include/ +CFLAGS = ${OPTIM} ${FLAGS} ${INCLUDE} + +SRC = src/ANN.cpp\ + src/bd_fix_rad_search.cpp\ + src/bd_pr_search.cpp\ + src/bd_search.cpp\ + src/bd_tree.cpp\ + src/brute.cpp\ + src/kd_dump.cpp\ + src/kd_fix_rad_search.cpp\ + src/kd_pr_search.cpp\ + src/kd_search.cpp\ + src/kd_split.cpp\ + src/kd_tree.cpp\ + src/kd_util.cpp\ + src/perf.cpp + +OBJ = ${SRC:.cpp=.o} + +.SUFFIXES: .o .cpp + +${LIB}: ${OBJ} + ${AR} ${LIB} ${OBJ} + ${RANLIB} ${LIB} + +.cpp.o: + ${CXX} ${CFLAGS} -c $< -o ${<:.cpp=.o} + +clean: + rm -f src/*.o + +depend: + (sed '/^# DO NOT DELETE THIS LINE/q' Makefile && \ + ${CXX} -MM ${CFLAGS} ${SRC} \ + ) >Makefile.new + cp Makefile Makefile.bak + cp Makefile.new Makefile + rm -f Makefile.new + +# DO NOT DELETE THIS LINE +# 1 "/Users/geuzaine/.gmsh/ANN//" +ANN.o: src/ANN.cpp include/ANN/ANNx.h include/ANN/ANN.h \ + include/ANN/ANNperf.h +# 1 "/Users/geuzaine/.gmsh/ANN//" +bd_fix_rad_search.o: src/bd_fix_rad_search.cpp src/bd_tree.h \ + include/ANN/ANNx.h include/ANN/ANN.h src/kd_tree.h \ + src/kd_fix_rad_search.h src/kd_util.h src/pr_queue_k.h \ + include/ANN/ANNperf.h +# 1 "/Users/geuzaine/.gmsh/ANN//" +bd_pr_search.o: src/bd_pr_search.cpp src/bd_tree.h include/ANN/ANNx.h \ + include/ANN/ANN.h src/kd_tree.h src/kd_pr_search.h src/kd_util.h \ + src/pr_queue.h include/ANN/ANNperf.h src/pr_queue_k.h +# 1 "/Users/geuzaine/.gmsh/ANN//" +bd_search.o: src/bd_search.cpp src/bd_tree.h include/ANN/ANNx.h \ + include/ANN/ANN.h src/kd_tree.h src/kd_search.h src/kd_util.h \ + src/pr_queue_k.h include/ANN/ANNperf.h +# 1 "/Users/geuzaine/.gmsh/ANN//" +bd_tree.o: src/bd_tree.cpp src/bd_tree.h include/ANN/ANNx.h \ + include/ANN/ANN.h src/kd_tree.h src/kd_util.h src/kd_split.h \ + include/ANN/ANNperf.h +# 1 "/Users/geuzaine/.gmsh/ANN//" +brute.o: src/brute.cpp include/ANN/ANNx.h include/ANN/ANN.h \ + src/pr_queue_k.h include/ANN/ANNperf.h +# 1 "/Users/geuzaine/.gmsh/ANN//" +kd_dump.o: src/kd_dump.cpp src/kd_tree.h include/ANN/ANNx.h \ + include/ANN/ANN.h src/bd_tree.h +# 1 "/Users/geuzaine/.gmsh/ANN//" +kd_fix_rad_search.o: src/kd_fix_rad_search.cpp src/kd_fix_rad_search.h \ + src/kd_tree.h include/ANN/ANNx.h include/ANN/ANN.h src/kd_util.h \ + src/pr_queue_k.h include/ANN/ANNperf.h +# 1 "/Users/geuzaine/.gmsh/ANN//" +kd_pr_search.o: src/kd_pr_search.cpp src/kd_pr_search.h src/kd_tree.h \ + include/ANN/ANNx.h include/ANN/ANN.h src/kd_util.h src/pr_queue.h \ + include/ANN/ANNperf.h src/pr_queue_k.h +# 1 "/Users/geuzaine/.gmsh/ANN//" +kd_search.o: src/kd_search.cpp src/kd_search.h src/kd_tree.h \ + include/ANN/ANNx.h include/ANN/ANN.h src/kd_util.h src/pr_queue_k.h \ + include/ANN/ANNperf.h +# 1 "/Users/geuzaine/.gmsh/ANN//" +kd_split.o: src/kd_split.cpp src/kd_tree.h include/ANN/ANNx.h \ + include/ANN/ANN.h src/kd_util.h src/kd_split.h +# 1 "/Users/geuzaine/.gmsh/ANN//" +kd_tree.o: src/kd_tree.cpp src/kd_tree.h include/ANN/ANNx.h \ + include/ANN/ANN.h src/kd_split.h src/kd_util.h include/ANN/ANNperf.h +# 1 "/Users/geuzaine/.gmsh/ANN//" +kd_util.o: src/kd_util.cpp src/kd_util.h src/kd_tree.h include/ANN/ANNx.h \ + include/ANN/ANN.h include/ANN/ANNperf.h +# 1 "/Users/geuzaine/.gmsh/ANN//" +perf.o: src/perf.cpp include/ANN/ANN.h include/ANN/ANNperf.h diff --git a/contrib/ANN/include/ANN/ANN.h b/contrib/ANN/include/ANN/ANN.h new file mode 100644 index 0000000000..ca8146a35a --- /dev/null +++ b/contrib/ANN/include/ANN/ANN.h @@ -0,0 +1,829 @@ +//---------------------------------------------------------------------- +// File: ANN.h +// Programmer: Sunil Arya and David Mount +// Last modified: 05/03/05 (Release 1.1) +// Description: Basic include file for approximate nearest +// neighbor searching. +//---------------------------------------------------------------------- +// Copyright (c) 1997-2005 University of Maryland and Sunil Arya and +// David Mount. All Rights Reserved. +// +// This software and related documentation is part of the +// Approximate Nearest Neighbor Library (ANN). +// +// Permission to use, copy, and distribute this software and its +// documentation is hereby granted free of charge, provided that +// (1) it is not a component of a commercial product, and +// (2) this notice appears in all copies of the software and +// related documentation. +// +// The University of Maryland (U.M.) and the authors make no representations +// about the suitability or fitness of this software for any purpose. It is +// provided "as is" without express or implied warranty. +//---------------------------------------------------------------------- +// History: +// Revision 0.1 03/04/98 +// Initial release +// Revision 1.0 04/01/05 +// Added copyright and revision information +// Added ANNcoordPrec for coordinate precision. +// Added methods theDim, nPoints, maxPoints, thePoints to ANNpointSet. +// Cleaned up C++ structure for modern compilers +// Revision 1.1 05/03/05 +// Added fixed-radius k-NN searching +//---------------------------------------------------------------------- + +//---------------------------------------------------------------------- +// ANN - approximate nearest neighbor searching +// ANN is a library for approximate nearest neighbor searching, +// based on the use of standard and priority search in kd-trees +// and balanced box-decomposition (bbd) trees. Here are some +// references to the main algorithmic techniques used here: +// +// kd-trees: +// Friedman, Bentley, and Finkel, ``An algorithm for finding +// best matches in logarithmic expected time,'' ACM +// Transactions on Mathematical Software, 3(3):209-226, 1977. +// +// Priority search in kd-trees: +// Arya and Mount, ``Algorithms for fast vector quantization,'' +// Proc. of DCC '93: Data Compression Conference, eds. J. A. +// Storer and M. Cohn, IEEE Press, 1993, 381-390. +// +// Approximate nearest neighbor search and bbd-trees: +// Arya, Mount, Netanyahu, Silverman, and Wu, ``An optimal +// algorithm for approximate nearest neighbor searching,'' +// 5th Ann. ACM-SIAM Symposium on Discrete Algorithms, +// 1994, 573-582. +//---------------------------------------------------------------------- + +#ifndef ANN_H +#define ANN_H + +#ifdef WIN33 + //---------------------------------------------------------------------- + // For Microsoft Visual C++, externally accessible symbols must be + // explicitly indicated with DLL_API, which is somewhat like "extern." + // + // The following ifdef block is the standard way of creating macros + // which make exporting from a DLL simpler. All files within this DLL + // are compiled with the DLL_EXPORTS preprocessor symbol defined on the + // command line. In contrast, projects that use (or import) the DLL + // objects do not define the DLL_EXPORTS symbol. This way any other + // project whose source files include this file see DLL_API functions as + // being imported from a DLL, wheras this DLL sees symbols defined with + // this macro as being exported. + //---------------------------------------------------------------------- + #ifdef DLL_EXPORTS + #define DLL_API __declspec(dllexport) + #else + #define DLL_API __declspec(dllimport) + #endif + //---------------------------------------------------------------------- + // DLL_API is ignored for all other systems + //---------------------------------------------------------------------- +#else + #define DLL_API +#endif + +//---------------------------------------------------------------------- +// basic includes +//---------------------------------------------------------------------- + +#include <cmath> // math includes +#include <iostream> // I/O streams + +//---------------------------------------------------------------------- +// Limits +// There are a number of places where we use the maximum double value as +// default initializers (and others may be used, depending on the +// data/distance representation). These can usually be found in limits.h +// (as LONG_MAX, INT_MAX) or in float.h (as DBL_MAX, FLT_MAX). +// +// Not all systems have these files. If you are using such a system, +// you should set the preprocessor symbol ANN_NO_LIMITS_H when +// compiling, and modify the statements below to generate the +// appropriate value. For practical purposes, this does not need to be +// the maximum double value. It is sufficient that it be at least as +// large than the maximum squared distance between between any two +// points. +//---------------------------------------------------------------------- +#ifdef ANN_NO_LIMITS_H // limits.h unavailable + #include <cvalues> // replacement for limits.h + const double ANN_DBL_MAX = MAXDOUBLE; // insert maximum double +#else + #include <climits> + #include <cfloat> + const double ANN_DBL_MAX = DBL_MAX; +#endif + +#define ANNversion "1.0" // ANN version and information +#define ANNversionCmt "" +#define ANNcopyright "David M. Mount and Sunil Arya" +#define ANNlatestRev "Mar 1, 2005" + +//---------------------------------------------------------------------- +// ANNbool +// This is a simple boolean type. Although ANSI C++ is supposed +// to support the type bool, some compilers do not have it. +//---------------------------------------------------------------------- + +enum ANNbool {ANNfalse = 0, ANNtrue = 1}; // ANN boolean type (non ANSI C++) + +//---------------------------------------------------------------------- +// ANNcoord, ANNdist +// ANNcoord and ANNdist are the types used for representing +// point coordinates and distances. They can be modified by the +// user, with some care. It is assumed that they are both numeric +// types, and that ANNdist is generally of an equal or higher type +// from ANNcoord. A variable of type ANNdist should be large +// enough to store the sum of squared components of a variable +// of type ANNcoord for the number of dimensions needed in the +// application. For example, the following combinations are +// legal: +// +// ANNcoord ANNdist +// --------- ------------------------------- +// short short, int, long, float, double +// int int, long, float, double +// long long, float, double +// float float, double +// double double +// +// It is the user's responsibility to make sure that overflow does +// not occur in distance calculation. +//---------------------------------------------------------------------- + +typedef double ANNcoord; // coordinate data type +typedef double ANNdist; // distance data type + +//---------------------------------------------------------------------- +// ANNidx +// ANNidx is a point index. When the data structure is built, the +// points are given as an array. Nearest neighbor results are +// returned as an integer index into this array. To make it +// clearer when this is happening, we define the integer type +// ANNidx. Indexing starts from 0. +// +// For fixed-radius near neighbor searching, it is possible that +// there are not k nearest neighbors within the search radius. To +// indicate this, the algorithm returns ANN_NULL_IDX as its result. +// It should be distinguishable from any valid array index. +//---------------------------------------------------------------------- + +typedef int ANNidx; // point index +const ANNidx ANN_NULL_IDX = -1; // a NULL point index + +//---------------------------------------------------------------------- +// Infinite distance: +// The code assumes that there is an "infinite distance" which it +// uses to initialize distances before performing nearest neighbor +// searches. It should be as larger or larger than any legitimate +// nearest neighbor distance. +// +// On most systems, these should be found in the standard include +// file <limits.h> or possibly <float.h>. If you do not have these +// file, some suggested values are listed below, assuming 64-bit +// long, 32-bit int and 16-bit short. +// +// ANNdist ANN_DIST_INF Values (see <limits.h> or <float.h>) +// ------- ------------ ------------------------------------ +// double DBL_MAX 1.79769313486231570e+308 +// float FLT_MAX 3.40282346638528860e+38 +// long LONG_MAX 0x7fffffffffffffff +// int INT_MAX 0x7fffffff +// short SHRT_MAX 0x7fff +//---------------------------------------------------------------------- + +const ANNdist ANN_DIST_INF = ANN_DBL_MAX; + +//---------------------------------------------------------------------- +// Significant digits for tree dumps: +// When floating point coordinates are used, the routine that dumps +// a tree needs to know roughly how many significant digits there +// are in a ANNcoord, so it can output points to full precision. +// This is defined to be ANNcoordPrec. On most systems these +// values can be found in the standard include files <limits.h> or +// <float.h>. For integer types, the value is essentially ignored. +// +// ANNcoord ANNcoordPrec Values (see <limits.h> or <float.h>) +// -------- ------------ ------------------------------------ +// double DBL_DIG 15 +// float FLT_DIG 6 +// long doesn't matter 19 +// int doesn't matter 10 +// short doesn't matter 5 +//---------------------------------------------------------------------- + +#ifdef DBL_DIG // number of sig. bits in ANNcoord + const int ANNcoordPrec = DBL_DIG; +#else + const int ANNcoordPrec = 15; // default precision +#endif + +//---------------------------------------------------------------------- +// Self match? +// In some applications, the nearest neighbor of a point is not +// allowed to be the point itself. This occurs, for example, when +// computing all nearest neighbors in a set. By setting the +// parameter ANN_ALLOW_SELF_MATCH to ANNfalse, the nearest neighbor +// is the closest point whose distance from the query point is +// strictly positive. +//---------------------------------------------------------------------- + +const ANNbool ANN_ALLOW_SELF_MATCH = ANNtrue; + +//---------------------------------------------------------------------- +// Norms and metrics: +// ANN supports any Minkowski norm for defining distance. In +// particular, for any p >= 1, the L_p Minkowski norm defines the +// length of a d-vector (v0, v1, ..., v(d-1)) to be +// +// (|v0|^p + |v1|^p + ... + |v(d-1)|^p)^(1/p), +// +// (where ^ denotes exponentiation, and |.| denotes absolute +// value). The distance between two points is defined to be the +// norm of the vector joining them. Some common distance metrics +// include +// +// Euclidean metric p = 2 +// Manhattan metric p = 1 +// Max metric p = infinity +// +// In the case of the max metric, the norm is computed by taking +// the maxima of the absolute values of the components. ANN is +// highly "coordinate-based" and does not support general distances +// functions (e.g. those obeying just the triangle inequality). It +// also does not support distance functions based on +// inner-products. +// +// For the purpose of computing nearest neighbors, it is not +// necessary to compute the final power (1/p). Thus the only +// component that is used by the program is |v(i)|^p. +// +// ANN parameterizes the distance computation through the following +// macros. (Macros are used rather than procedures for +// efficiency.) Recall that the distance between two points is +// given by the length of the vector joining them, and the length +// or norm of a vector v is given by formula: +// +// |v| = ROOT(POW(v0) # POW(v1) # ... # POW(v(d-1))) +// +// where ROOT, POW are unary functions and # is an associative and +// commutative binary operator mapping the following types: +// +// ** POW: ANNcoord --> ANNdist +// ** #: ANNdist x ANNdist --> ANNdist +// ** ROOT: ANNdist (>0) --> double +// +// For early termination in distance calculation (partial distance +// calculation) we assume that POW and # together are monotonically +// increasing on sequences of arguments, meaning that for all +// v0..vk and y: +// +// POW(v0) #...# POW(vk) <= (POW(v0) #...# POW(vk)) # POW(y). +// +// Incremental Distance Calculation: +// The program uses an optimized method of computing distances for +// kd-trees and bd-trees, called incremental distance calculation. +// It is used when distances are to be updated when only a single +// coordinate of a point has been changed. In order to use this, +// we assume that there is an incremental update function DIFF(x,y) +// for #, such that if: +// +// s = x0 # ... # xi # ... # xk +// +// then if s' is equal to s but with xi replaced by y, that is, +// +// s' = x0 # ... # y # ... # xk +// +// then the length of s' can be computed by: +// +// |s'| = |s| # DIFF(xi,y). +// +// Thus, if # is + then DIFF(xi,y) is (yi-x). For the L_infinity +// norm we make use of the fact that in the program this function +// is only invoked when y > xi, and hence DIFF(xi,y)=y. +// +// Finally, for approximate nearest neighbor queries we assume +// that POW and ROOT are related such that +// +// v*ROOT(x) = ROOT(POW(v)*x) +// +// Here are the values for the various Minkowski norms: +// +// L_p: p even: p odd: +// ------------------------- ------------------------ +// POW(v) = v^p POW(v) = |v|^p +// ROOT(x) = x^(1/p) ROOT(x) = x^(1/p) +// # = + # = + +// DIFF(x,y) = y - x DIFF(x,y) = y - x +// +// L_inf: +// POW(v) = |v| +// ROOT(x) = x +// # = max +// DIFF(x,y) = y +// +// By default the Euclidean norm is assumed. To change the norm, +// uncomment the appropriate set of macros below. +//---------------------------------------------------------------------- + +//---------------------------------------------------------------------- +// Use the following for the Euclidean norm +//---------------------------------------------------------------------- +#define ANN_POW(v) ((v)*(v)) +#define ANN_ROOT(x) sqrt(x) +#define ANN_SUM(x,y) ((x) + (y)) +#define ANN_DIFF(x,y) ((y) - (x)) + +//---------------------------------------------------------------------- +// Use the following for the L_1 (Manhattan) norm +//---------------------------------------------------------------------- +// #define ANN_POW(v) fabs(v) +// #define ANN_ROOT(x) (x) +// #define ANN_SUM(x,y) ((x) + (y)) +// #define ANN_DIFF(x,y) ((y) - (x)) + +//---------------------------------------------------------------------- +// Use the following for a general L_p norm +//---------------------------------------------------------------------- +// #define ANN_POW(v) pow(fabs(v),p) +// #define ANN_ROOT(x) pow(fabs(x),1/p) +// #define ANN_SUM(x,y) ((x) + (y)) +// #define ANN_DIFF(x,y) ((y) - (x)) + +//---------------------------------------------------------------------- +// Use the following for the L_infinity (Max) norm +//---------------------------------------------------------------------- +// #define ANN_POW(v) fabs(v) +// #define ANN_ROOT(x) (x) +// #define ANN_SUM(x,y) ((x) > (y) ? (x) : (y)) +// #define ANN_DIFF(x,y) (y) + +//---------------------------------------------------------------------- +// Array types +// The following array types are of basic interest. A point is +// just a dimensionless array of coordinates, a point array is a +// dimensionless array of points. A distance array is a +// dimensionless array of distances and an index array is a +// dimensionless array of point indices. The latter two are used +// when returning the results of k-nearest neighbor queries. +//---------------------------------------------------------------------- + +typedef ANNcoord* ANNpoint; // a point +typedef ANNpoint* ANNpointArray; // an array of points +typedef ANNdist* ANNdistArray; // an array of distances +typedef ANNidx* ANNidxArray; // an array of point indices + +//---------------------------------------------------------------------- +// Basic point and array utilities: +// The following procedures are useful supplements to ANN's nearest +// neighbor capabilities. +// +// annDist(): +// Computes the (squared) distance between a pair of points. +// Note that this routine is not used internally by ANN for +// computing distance calculations. For reasons of efficiency +// this is done using incremental distance calculation. Thus, +// this routine cannot be modified as a method of changing the +// metric. +// +// Because points (somewhat like strings in C) are stored as +// pointers. Consequently, creating and destroying copies of +// points may require storage allocation. These procedures do +// this. +// +// annAllocPt() and annDeallocPt(): +// Allocate a deallocate storage for a single point, and +// return a pointer to it. The argument to AllocPt() is +// used to initialize all components. +// +// annAllocPts() and annDeallocPts(): +// Allocate and deallocate an array of points as well a +// place to store their coordinates, and initializes the +// points to point to their respective coordinates. It +// allocates point storage in a contiguous block large +// enough to store all the points. It performs no +// initialization. +// +// annCopyPt(): +// Creates a copy of a given point, allocating space for +// the new point. It returns a pointer to the newly +// allocated copy. +//---------------------------------------------------------------------- + +DLL_API ANNdist annDist( + int dim, // dimension of space + ANNpoint p, // points + ANNpoint q); + +DLL_API ANNpoint annAllocPt( + int dim, // dimension + ANNcoord c = 0); // coordinate value (all equal) + +DLL_API ANNpointArray annAllocPts( + int n, // number of points + int dim); // dimension + +DLL_API void annDeallocPt( + ANNpoint &p); // deallocate 1 point + +DLL_API void annDeallocPts( + ANNpointArray &pa); // point array + +DLL_API ANNpoint annCopyPt( + int dim, // dimension + ANNpoint source); // point to copy + +//---------------------------------------------------------------------- +//Overall structure: ANN supports a number of different data structures +//for approximate and exact nearest neighbor searching. These are: +// +// ANNbruteForce A simple brute-force search structure. +// ANNkd_tree A kd-tree tree search structure. ANNbd_tree +// A bd-tree tree search structure (a kd-tree with shrink +// capabilities). +// +// At a minimum, each of these data structures support k-nearest +// neighbor queries. The nearest neighbor query, annkSearch, +// returns an integer identifier and the distance to the nearest +// neighbor(s) and annRangeSearch returns the nearest points that +// lie within a given query ball. +// +// Each structure is built by invoking the appropriate constructor +// and passing it (at a minimum) the array of points, the total +// number of points and the dimension of the space. Each structure +// is also assumed to support a destructor and member functions +// that return basic information about the point set. +// +// Note that the array of points is not copied by the data +// structure (for reasons of space efficiency), and it is assumed +// to be constant throughout the lifetime of the search structure. +// +// The search algorithm, annkSearch, is given the query point (q), +// and the desired number of nearest neighbors to report (k), and +// the error bound (eps) (whose default value is 0, implying exact +// nearest neighbors). It returns two arrays which are assumed to +// contain at least k elements: one (nn_idx) contains the indices +// (within the point array) of the nearest neighbors and the other +// (dd) contains the squared distances to these nearest neighbors. +// +// The search algorithm, annkFRSearch, is a fixed-radius kNN +// search. In addition to a query point, it is given a (squared) +// radius bound. (This is done for consistency, because the search +// returns distances as squared quantities.) It does two things. +// First, it computes the k nearest neighbors within the radius +// bound, and second, it returns the total number of points lying +// within the radius bound. It is permitted to set k = 0, in which +// case it effectively answers a range counting query. If the +// error bound epsilon is positive, then the search is approximate +// in the sense that it is free to ignore any point that lies +// outside a ball of radius r/(1+epsilon), where r is the given +// (unsquared) radius bound. +// +// The generic object from which all the search structures are +// dervied is given below. It is a virtual object, and is useless +// by itself. +//---------------------------------------------------------------------- + +class DLL_API ANNpointSet { +public: + virtual ~ANNpointSet() {} // virtual distructor + + virtual void annkSearch( // approx k near neighbor search + ANNpoint q, // query point + int k, // number of near neighbors to return + ANNidxArray nn_idx, // nearest neighbor array (modified) + ANNdistArray dd, // dist to near neighbors (modified) + double eps=0.0 // error bound + ) = 0; // pure virtual (defined elsewhere) + + virtual int annkFRSearch( // approx fixed-radius kNN search + ANNpoint q, // query point + ANNdist sqRad, // squared radius + int k = 0, // number of near neighbors to return + ANNidxArray nn_idx = NULL, // nearest neighbor array (modified) + ANNdistArray dd = NULL, // dist to near neighbors (modified) + double eps=0.0 // error bound + ) = 0; // pure virtual (defined elsewhere) + + virtual int theDim() = 0; // return dimension of space + virtual int nPoints() = 0; // return number of points + // return pointer to points + virtual ANNpointArray thePoints() = 0; +}; + +//---------------------------------------------------------------------- +// Brute-force nearest neighbor search: +// The brute-force search structure is very simple but inefficient. +// It has been provided primarily for the sake of comparison with +// and validation of the more complex search structures. +// +// Query processing is the same as described above, but the value +// of epsilon is ignored, since all distance calculations are +// performed exactly. +// +// WARNING: This data structure is very slow, and should not be +// used unless the number of points is very small. +// +// Internal information: +// --------------------- +// This data structure bascially consists of the array of points +// (each a pointer to an array of coordinates). The search is +// performed by a simple linear scan of all the points. +//---------------------------------------------------------------------- + +class DLL_API ANNbruteForce: public ANNpointSet { + int dim; // dimension + int n_pts; // number of points + ANNpointArray pts; // point array +public: + ANNbruteForce( // constructor from point array + ANNpointArray pa, // point array + int n, // number of points + int dd); // dimension + + ~ANNbruteForce(); // destructor + + void annkSearch( // approx k near neighbor search + ANNpoint q, // query point + int k, // number of near neighbors to return + ANNidxArray nn_idx, // nearest neighbor array (modified) + ANNdistArray dd, // dist to near neighbors (modified) + double eps=0.0); // error bound + + int annkFRSearch( // approx fixed-radius kNN search + ANNpoint q, // query point + ANNdist sqRad, // squared radius + int k = 0, // number of near neighbors to return + ANNidxArray nn_idx = NULL, // nearest neighbor array (modified) + ANNdistArray dd = NULL, // dist to near neighbors (modified) + double eps=0.0); // error bound + + int theDim() // return dimension of space + { return dim; } + + int nPoints() // return number of points + { return n_pts; } + + ANNpointArray thePoints() // return pointer to points + { return pts; } +}; + +//---------------------------------------------------------------------- +// kd- and bd-tree splitting and shrinking rules +// kd-trees supports a collection of different splitting rules. +// In addition to the standard kd-tree splitting rule proposed +// by Friedman, Bentley, and Finkel, we have introduced a +// number of other splitting rules, which seem to perform +// as well or better (for the distributions we have tested). +// +// The splitting methods given below allow the user to tailor +// the data structure to the particular data set. They are +// are described in greater details in the kd_split.cc source +// file. The method ANN_KD_SUGGEST is the method chosen (rather +// subjectively) by the implementors as the one giving the +// fastest performance, and is the default splitting method. +// +// As with splitting rules, there are a number of different +// shrinking rules. The shrinking rule ANN_BD_NONE does no +// shrinking (and hence produces a kd-tree tree). The rule +// ANN_BD_SUGGEST uses the implementors favorite rule. +//---------------------------------------------------------------------- + +enum ANNsplitRule { + ANN_KD_STD = 0, // the optimized kd-splitting rule + ANN_KD_MIDPT = 1, // midpoint split + ANN_KD_FAIR = 2, // fair split + ANN_KD_SL_MIDPT = 3, // sliding midpoint splitting method + ANN_KD_SL_FAIR = 4, // sliding fair split method + ANN_KD_SUGGEST = 5}; // the authors' suggestion for best +const int ANN_N_SPLIT_RULES = 6; // number of split rules + +enum ANNshrinkRule { + ANN_BD_NONE = 0, // no shrinking at all (just kd-tree) + ANN_BD_SIMPLE = 1, // simple splitting + ANN_BD_CENTROID = 2, // centroid splitting + ANN_BD_SUGGEST = 3}; // the authors' suggested choice +const int ANN_N_SHRINK_RULES = 4; // number of shrink rules + +//---------------------------------------------------------------------- +// kd-tree: +// The main search data structure supported by ANN is a kd-tree. +// The main constructor is given a set of points and a choice of +// splitting method to use in building the tree. +// +// Construction: +// ------------- +// The constructor is given the point array, number of points, +// dimension, bucket size (default = 1), and the splitting rule +// (default = ANN_KD_SUGGEST). The point array is not copied, and +// is assumed to be kept constant throughout the lifetime of the +// search structure. There is also a "load" constructor that +// builds a tree from a file description that was created by the +// Dump operation. +// +// Search: +// ------- +// There are two search methods: +// +// Standard search (annkSearch()): +// Searches nodes in tree-traversal order, always visiting +// the closer child first. +// Priority search (annkPriSearch()): +// Searches nodes in order of increasing distance of the +// associated cell from the query point. For many +// distributions the standard search seems to work just +// fine, but priority search is safer for worst-case +// performance. +// +// Printing: +// --------- +// There are two methods provided for printing the tree. Print() +// is used to produce a "human-readable" display of the tree, with +// indenation, which is handy for debugging. Dump() produces a +// format that is suitable reading by another program. There is a +// "load" constructor, which constructs a tree which is assumed to +// have been saved by the Dump() procedure. +// +// Performance and Structure Statistics: +// ------------------------------------- +// The procedure getStats() collects statistics information on the +// tree (its size, height, etc.) See ANNperf.h for information on +// the stats structure it returns. +// +// Internal information: +// --------------------- +// The data structure consists of three major chunks of storage. +// The first (implicit) storage are the points themselves (pts), +// which have been provided by the users as an argument to the +// constructor, or are allocated dynamically if the tree is built +// using the load constructor). These should not be changed during +// the lifetime of the search structure. It is the user's +// responsibility to delete these after the tree is destroyed. +// +// The second is the tree itself (which is dynamically allocated in +// the constructor) and is given as a pointer to its root node +// (root). These nodes are automatically deallocated when the tree +// is deleted. See the file src/kd_tree.h for further information +// on the structure of the tree nodes. +// +// Each leaf of the tree does not contain a pointer directly to a +// point, but rather contains a pointer to a "bucket", which is an +// array consisting of point indices. The third major chunk of +// storage is an array (pidx), which is a large array in which all +// these bucket subarrays reside. (The reason for storing them +// separately is the buckets are typically small, but of varying +// sizes. This was done to avoid fragmentation.) This array is +// also deallocated when the tree is deleted. +// +// In addition to this, the tree consists of a number of other +// pieces of information which are used in searching and for +// subsequent tree operations. These consist of the following: +// +// dim Dimension of space +// n_pts Number of points currently in the tree +// n_max Maximum number of points that are allowed +// in the tree +// bkt_size Maximum bucket size (no. of points per leaf) +// bnd_box_lo Bounding box low point +// bnd_box_hi Bounding box high point +// splitRule Splitting method used +// +//---------------------------------------------------------------------- + +//---------------------------------------------------------------------- +// Some types and objects used by kd-tree functions +// See src/kd_tree.h and src/kd_tree.cpp for definitions +//---------------------------------------------------------------------- +class ANNkdStats; // stats on kd-tree +class ANNkd_node; // generic node in a kd-tree +typedef ANNkd_node* ANNkd_ptr; // pointer to a kd-tree node + +class DLL_API ANNkd_tree: public ANNpointSet { +protected: + int dim; // dimension of space + int n_pts; // number of points in tree + int bkt_size; // bucket size + ANNpointArray pts; // the points + ANNidxArray pidx; // point indices (to pts array) + ANNkd_ptr root; // root of kd-tree + ANNpoint bnd_box_lo; // bounding box low point + ANNpoint bnd_box_hi; // bounding box high point + + void SkeletonTree( // construct skeleton tree + int n, // number of points + int dd, // dimension + int bs, // bucket size + ANNpointArray pa = NULL, // point array (optional) + ANNidxArray pi = NULL); // point indices (optional) + +public: + ANNkd_tree( // build skeleton tree + int n = 0, // number of points + int dd = 0, // dimension + int bs = 1); // bucket size + + ANNkd_tree( // build from point array + ANNpointArray pa, // point array + int n, // number of points + int dd, // dimension + int bs = 1, // bucket size + ANNsplitRule split = ANN_KD_SUGGEST); // splitting method + + ANNkd_tree( // build from dump file + std::istream& in); // input stream for dump file + + ~ANNkd_tree(); // tree destructor + + void annkSearch( // approx k near neighbor search + ANNpoint q, // query point + int k, // number of near neighbors to return + ANNidxArray nn_idx, // nearest neighbor array (modified) + ANNdistArray dd, // dist to near neighbors (modified) + double eps=0.0); // error bound + + void annkPriSearch( // priority k near neighbor search + ANNpoint q, // query point + int k, // number of near neighbors to return + ANNidxArray nn_idx, // nearest neighbor array (modified) + ANNdistArray dd, // dist to near neighbors (modified) + double eps=0.0); // error bound + + int annkFRSearch( // approx fixed-radius kNN search + ANNpoint q, // the query point + ANNdist sqRad, // squared radius of query ball + int k, // number of neighbors to return + ANNidxArray nn_idx = NULL, // nearest neighbor array (modified) + ANNdistArray dd = NULL, // dist to near neighbors (modified) + double eps=0.0); // error bound + + int theDim() // return dimension of space + { return dim; } + + int nPoints() // return number of points + { return n_pts; } + + ANNpointArray thePoints() // return pointer to points + { return pts; } + + virtual void Print( // print the tree (for debugging) + ANNbool with_pts, // print points as well? + std::ostream& out); // output stream + + virtual void Dump( // dump entire tree + ANNbool with_pts, // print points as well? + std::ostream& out); // output stream + + virtual void getStats( // compute tree statistics + ANNkdStats& st); // the statistics (modified) +}; + +//---------------------------------------------------------------------- +// Box decomposition tree (bd-tree) +// The bd-tree is inherited from a kd-tree. The main difference +// in the bd-tree and the kd-tree is a new type of internal node +// called a shrinking node (in the kd-tree there is only one type +// of internal node, a splitting node). The shrinking node +// makes it possible to generate balanced trees in which the +// cells have bounded aspect ratio, by allowing the decomposition +// to zoom in on regions of dense point concentration. Although +// this is a nice idea in theory, few point distributions are so +// densely clustered that this is really needed. +//---------------------------------------------------------------------- + +class DLL_API ANNbd_tree: public ANNkd_tree { +public: + ANNbd_tree( // build skeleton tree + int n, // number of points + int dd, // dimension + int bs = 1) // bucket size + : ANNkd_tree(n, dd, bs) {} // build base kd-tree + + ANNbd_tree( // build from point array + ANNpointArray pa, // point array + int n, // number of points + int dd, // dimension + int bs = 1, // bucket size + ANNsplitRule split = ANN_KD_SUGGEST, // splitting rule + ANNshrinkRule shrink = ANN_BD_SUGGEST); // shrinking rule + + ANNbd_tree( // build from dump file + std::istream& in); // input stream for dump file +}; + +//---------------------------------------------------------------------- +// Other functions +// annMaxPtsVisit Sets a limit on the maximum number of points +// to visit in the search. +// annClose Can be called when all use of ANN is finished. +// It clears up a minor memory leak. +//---------------------------------------------------------------------- + +DLL_API void annMaxPtsVisit( // max. pts to visit in search + int maxPts); // the limit + +DLL_API void annClose(); // called to end use of ANN + +#endif diff --git a/contrib/ANN/include/ANN/ANNperf.h b/contrib/ANN/include/ANN/ANNperf.h new file mode 100644 index 0000000000..b18c81658d --- /dev/null +++ b/contrib/ANN/include/ANN/ANNperf.h @@ -0,0 +1,226 @@ +//---------------------------------------------------------------------- +// File: ANNperf.h +// Programmer: Sunil Arya and David Mount +// Last modified: 03/04/98 (Release 0.1) +// Description: Include file for ANN performance stats +// +// Some of the code for statistics gathering has been adapted +// from the SmplStat.h package in the g++ library. +//---------------------------------------------------------------------- +// Copyright (c) 1997-1998 University of Maryland and Sunil Arya and David +// Mount. All Rights Reserved. +// +// This software and related documentation is part of the +// Approximate Nearest Neighbor Library (ANN). +// +// Permission to use, copy, and distribute this software and its +// documentation is hereby granted free of charge, provided that +// (1) it is not a component of a commercial product, and +// (2) this notice appears in all copies of the software and +// related documentation. +// +// The University of Maryland (U.M.) and the authors make no representations +// about the suitability or fitness of this software for any purpose. It is +// provided "as is" without express or implied warranty. +//---------------------------------------------------------------------- +// History: +// Revision 0.1 03/04/98 +// Initial release +// Revision 1.0 04/01/05 +// Added ANN_ prefix to avoid name conflicts. +//---------------------------------------------------------------------- + +#ifndef ANNperf_H +#define ANNperf_H + +//---------------------------------------------------------------------- +// basic includes +//---------------------------------------------------------------------- + +#include <ANN/ANN.h> // basic ANN includes + +//---------------------------------------------------------------------- +// kd-tree stats object +// This object is used for collecting information about a kd-tree +// or bd-tree. +//---------------------------------------------------------------------- + +class ANNkdStats { // stats on kd-tree +public: + int dim; // dimension of space + int n_pts; // no. of points + int bkt_size; // bucket size + int n_lf; // no. of leaves (including trivial) + int n_tl; // no. of trivial leaves (no points) + int n_spl; // no. of splitting nodes + int n_shr; // no. of shrinking nodes (for bd-trees) + int depth; // depth of tree + float sum_ar; // sum of leaf aspect ratios + float avg_ar; // average leaf aspect ratio + // + // reset stats + void reset(int d=0, int n=0, int bs=0) + { + dim = d; n_pts = n; bkt_size = bs; + n_lf = n_tl = n_spl = n_shr = depth = 0; + sum_ar = avg_ar = 0.0; + } + + ANNkdStats() // basic constructor + { reset(); } + + void merge(const ANNkdStats &st); // merge stats from child +}; + +//---------------------------------------------------------------------- +// ANNsampStat +// A sample stat collects numeric (double) samples and returns some +// simple statistics. Its main functions are: +// +// reset() Reset to no samples. +// += x Include sample x. +// samples() Return number of samples. +// mean() Return mean of samples. +// stdDev() Return standard deviation +// min() Return minimum of samples. +// max() Return maximum of samples. +//---------------------------------------------------------------------- +class DLL_API ANNsampStat { + int n; // number of samples + double sum; // sum + double sum2; // sum of squares + double minVal, maxVal; // min and max +public : + void reset() // reset everything + { + n = 0; + sum = sum2 = 0; + minVal = ANN_DBL_MAX; + maxVal = -ANN_DBL_MAX; + } + + ANNsampStat() { reset(); } // constructor + + void operator+=(double x) // add sample + { + n++; sum += x; sum2 += x*x; + if (x < minVal) minVal = x; + if (x > maxVal) maxVal = x; + } + + int samples() { return n; } // number of samples + + double mean() { return sum/n; } // mean + + // standard deviation + double stdDev() { return sqrt((sum2 - (sum*sum)/n)/(n-1));} + + double min() { return minVal; } // minimum + double max() { return maxVal; } // maximum +}; + +//---------------------------------------------------------------------- +// Operation count updates +//---------------------------------------------------------------------- + +#ifdef ANN_PERF + #define ANN_FLOP(n) {ann_Nfloat_ops += (n);} + #define ANN_LEAF(n) {ann_Nvisit_lfs += (n);} + #define ANN_SPL(n) {ann_Nvisit_spl += (n);} + #define ANN_SHR(n) {ann_Nvisit_shr += (n);} + #define ANN_PTS(n) {ann_Nvisit_pts += (n);} + #define ANN_COORD(n) {ann_Ncoord_hts += (n);} +#else + #define ANN_FLOP(n) + #define ANN_LEAF(n) + #define ANN_SPL(n) + #define ANN_SHR(n) + #define ANN_PTS(n) + #define ANN_COORD(n) +#endif + +//---------------------------------------------------------------------- +// Performance statistics +// The following data and routines are used for computing performance +// statistics for nearest neighbor searching. Because these routines +// can slow the code down, they can be activated and deactiviated by +// defining the ANN_PERF variable, by compiling with the option: +// -DANN_PERF +//---------------------------------------------------------------------- + +//---------------------------------------------------------------------- +// Global counters for performance measurement +// +// visit_lfs The number of leaf nodes visited in the +// tree. +// +// visit_spl The number of splitting nodes visited in the +// tree. +// +// visit_shr The number of shrinking nodes visited in the +// tree. +// +// visit_pts The number of points visited in all the +// leaf nodes visited. Equivalently, this +// is the number of points for which distance +// calculations are performed. +// +// coord_hts The number of times a coordinate of a +// data point is accessed. This is generally +// less than visit_pts*d if partial distance +// calculation is used. This count is low +// in the sense that if a coordinate is hit +// many times in the same routine we may +// count it only once. +// +// float_ops The number of floating point operations. +// This includes all operations in the heap +// as well as distance calculations to boxes. +// +// average_err The average error of each query (the +// error of the reported point to the true +// nearest neighbor). For k nearest neighbors +// the error is computed k times. +// +// rank_err The rank error of each query (the difference +// in the rank of the reported point and its +// true rank). +// +// data_pts The number of data points. This is not +// a counter, but used in stats computation. +//---------------------------------------------------------------------- + +extern int ann_Ndata_pts; // number of data points +extern int ann_Nvisit_lfs; // number of leaf nodes visited +extern int ann_Nvisit_spl; // number of splitting nodes visited +extern int ann_Nvisit_shr; // number of shrinking nodes visited +extern int ann_Nvisit_pts; // visited points for one query +extern int ann_Ncoord_hts; // coordinate hits for one query +extern int ann_Nfloat_ops; // floating ops for one query +extern ANNsampStat ann_visit_lfs; // stats on leaf nodes visits +extern ANNsampStat ann_visit_spl; // stats on splitting nodes visits +extern ANNsampStat ann_visit_shr; // stats on shrinking nodes visits +extern ANNsampStat ann_visit_nds; // stats on total nodes visits +extern ANNsampStat ann_visit_pts; // stats on points visited +extern ANNsampStat ann_coord_hts; // stats on coordinate hits +extern ANNsampStat ann_float_ops; // stats on floating ops +//---------------------------------------------------------------------- +// The following need to be part of the public interface, because +// they are accessed outside the DLL in ann_test.cpp. +//---------------------------------------------------------------------- +DLL_API extern ANNsampStat ann_average_err; // average error +DLL_API extern ANNsampStat ann_rank_err; // rank error + +//---------------------------------------------------------------------- +// Declaration of externally accessible routines for statistics +//---------------------------------------------------------------------- + +DLL_API void annResetStats(int data_size); // reset stats for a set of queries + +DLL_API void annResetCounts(); // reset counts for one queries + +DLL_API void annUpdateStats(); // update stats with current counts + +DLL_API void annPrintStats(ANNbool validate); // print statistics for a run + +#endif diff --git a/contrib/ANN/include/ANN/ANNx.h b/contrib/ANN/include/ANN/ANNx.h new file mode 100644 index 0000000000..38b07b76fa --- /dev/null +++ b/contrib/ANN/include/ANN/ANNx.h @@ -0,0 +1,170 @@ +//---------------------------------------------------------------------- +// File: ANNx.h +// Programmer: Sunil Arya and David Mount +// Last modified: 03/04/98 (Release 0.1) +// Description: Internal include file for ANN +// +// These declarations are of use in manipulating some of +// the internal data objects appearing in ANN, but are not +// needed for applications just using the nearest neighbor +// search. +// +// Typical users of ANN should not need to access this file. +//---------------------------------------------------------------------- +// Copyright (c) 1997-1998 University of Maryland and Sunil Arya and David +// Mount. All Rights Reserved. +// +// This software and related documentation is part of the +// Approximate Nearest Neighbor Library (ANN). +// +// Permission to use, copy, and distribute this software and its +// documentation is hereby granted free of charge, provided that +// (1) it is not a component of a commercial product, and +// (2) this notice appears in all copies of the software and +// related documentation. +// +// The University of Maryland (U.M.) and the authors make no representations +// about the suitability or fitness of this software for any purpose. It is +// provided "as is" without express or implied warranty. +//---------------------------------------------------------------------- +// History: +// Revision 0.1 03/04/98 +// Initial release +// Revision 1.0 04/01/05 +// Changed LO, HI, IN, OUT to ANN_LO, ANN_HI, etc. +//---------------------------------------------------------------------- + +#ifndef ANNx_H +#define ANNx_H + +#include <iomanip> // I/O manipulators +#include <ANN/ANN.h> // ANN includes + +//---------------------------------------------------------------------- +// Global constants and types +//---------------------------------------------------------------------- +enum {ANN_LO=0, ANN_HI=1}; // splitting indices +enum {ANN_IN=0, ANN_OUT=1}; // shrinking indices + // what to do in case of error +enum ANNerr {ANNwarn = 0, ANNabort = 1}; + +//---------------------------------------------------------------------- +// Maximum number of points to visit +// We have an option for terminating the search early if the +// number of points visited exceeds some threshold. If the +// threshold is 0 (its default) this means there is no limit +// and the algorithm applies its normal termination condition. +//---------------------------------------------------------------------- + +extern int ANNmaxPtsVisited; // maximum number of pts visited +extern int ANNptsVisited; // number of pts visited in search + +//---------------------------------------------------------------------- +// Global function declarations +//---------------------------------------------------------------------- + +void annError( // ANN error routine + char *msg, // error message + ANNerr level); // level of error + +void annPrintPt( // print a point + ANNpoint pt, // the point + int dim, // the dimension + std::ostream &out); // output stream + +//---------------------------------------------------------------------- +// Orthogonal (axis aligned) rectangle +// Orthogonal rectangles are represented by two points, one +// for the lower left corner (min coordinates) and the other +// for the upper right corner (max coordinates). +// +// The constructor initializes from either a pair of coordinates, +// pair of points, or another rectangle. Note that all constructors +// allocate new point storage. The destructor deallocates this +// storage. +// +// BEWARE: Orthogonal rectangles should be passed ONLY BY REFERENCE. +// (C++'s default copy constructor will not allocate new point +// storage, then on return the destructor free's storage, and then +// you get into big trouble in the calling procedure.) +//---------------------------------------------------------------------- + +class ANNorthRect { +public: + ANNpoint lo; // rectangle lower bounds + ANNpoint hi; // rectangle upper bounds +// + ANNorthRect( // basic constructor + int dd, // dimension of space + ANNcoord l=0, // default is empty + ANNcoord h=0) + { lo = annAllocPt(dd, l); hi = annAllocPt(dd, h); } + + ANNorthRect( // (almost a) copy constructor + int dd, // dimension + const ANNorthRect &r) // rectangle to copy + { lo = annCopyPt(dd, r.lo); hi = annCopyPt(dd, r.hi); } + + ANNorthRect( // construct from points + int dd, // dimension + ANNpoint l, // low point + ANNpoint h) // hight point + { lo = annCopyPt(dd, l); hi = annCopyPt(dd, h); } + + ~ANNorthRect() // destructor + { annDeallocPt(lo); annDeallocPt(hi); } + + ANNbool inside(int dim, ANNpoint p);// is point p inside rectangle? +}; + +void annAssignRect( // assign one rect to another + int dim, // dimension (both must be same) + ANNorthRect &dest, // destination (modified) + const ANNorthRect &source); // source + +//---------------------------------------------------------------------- +// Orthogonal (axis aligned) halfspace +// An orthogonal halfspace is represented by an integer cutting +// dimension cd, coordinate cutting value, cv, and side, sd, which is +// either +1 or -1. Our convention is that point q lies in the (closed) +// halfspace if (q[cd] - cv)*sd >= 0. +//---------------------------------------------------------------------- + +class ANNorthHalfSpace { +public: + int cd; // cutting dimension + ANNcoord cv; // cutting value + int sd; // which side +// + ANNorthHalfSpace() // default constructor + { cd = 0; cv = 0; sd = 0; } + + ANNorthHalfSpace( // basic constructor + int cdd, // dimension of space + ANNcoord cvv, // cutting value + int sdd) // side + { cd = cdd; cv = cvv; sd = sdd; } + + ANNbool in(ANNpoint q) const // is q inside halfspace? + { return (ANNbool) ((q[cd] - cv)*sd >= 0); } + + ANNbool out(ANNpoint q) const // is q outside halfspace? + { return (ANNbool) ((q[cd] - cv)*sd < 0); } + + ANNdist dist(ANNpoint q) const // (squared) distance from q + { return (ANNdist) ANN_POW(q[cd] - cv); } + + void setLowerBound(int d, ANNpoint p)// set to lower bound at p[i] + { cd = d; cv = p[d]; sd = +1; } + + void setUpperBound(int d, ANNpoint p)// set to upper bound at p[i] + { cd = d; cv = p[d]; sd = -1; } + + void project(ANNpoint &q) // project q (modified) onto halfspace + { if (out(q)) q[cd] = cv; } +}; + + // array of halfspaces +typedef ANNorthHalfSpace *ANNorthHSArray; + +#endif diff --git a/contrib/ANN/src/ANN.cpp b/contrib/ANN/src/ANN.cpp new file mode 100644 index 0000000000..82f90f54af --- /dev/null +++ b/contrib/ANN/src/ANN.cpp @@ -0,0 +1,198 @@ +//---------------------------------------------------------------------- +// File: ANN.cpp +// Programmer: Sunil Arya and David Mount +// Description: Methods for ANN.h and ANNx.h +// Last modified: 01/04/05 (Version 1.0) +//---------------------------------------------------------------------- +// Copyright (c) 1997-2005 University of Maryland and Sunil Arya and +// David Mount. All Rights Reserved. +// +// This software and related documentation is part of the Approximate +// Nearest Neighbor Library (ANN). This software is provided under +// the provisions of the Lesser GNU Public License (LGPL). See the +// file ../ReadMe.txt for further information. +// +// The University of Maryland (U.M.) and the authors make no +// representations about the suitability or fitness of this software for +// any purpose. It is provided "as is" without express or implied +// warranty. +//---------------------------------------------------------------------- +// History: +// Revision 0.1 03/04/98 +// Initial release +// Revision 1.0 04/01/05 +// Added performance counting to annDist() +//---------------------------------------------------------------------- + +#include <ANN/ANNx.h> // all ANN includes +#include <ANN/ANNperf.h> // ANN performance + +using namespace std; // make std:: accessible + +//---------------------------------------------------------------------- +// Point methods +//---------------------------------------------------------------------- + +//---------------------------------------------------------------------- +// Distance utility. +// (Note: In the nearest neighbor search, most distances are +// computed using partial distance calculations, not this +// procedure.) +//---------------------------------------------------------------------- + +ANNdist annDist( // interpoint squared distance + int dim, + ANNpoint p, + ANNpoint q) +{ + register int d; + register ANNcoord diff; + register ANNcoord dist; + + dist = 0; + for (d = 0; d < dim; d++) { + diff = p[d] - q[d]; + dist = ANN_SUM(dist, ANN_POW(diff)); + } + ANN_FLOP(3*dim) // performance counts + ANN_PTS(1) + ANN_COORD(dim) + return dist; +} + +//---------------------------------------------------------------------- +// annPrintPoint() prints a point to a given output stream. +//---------------------------------------------------------------------- + +void annPrintPt( // print a point + ANNpoint pt, // the point + int dim, // the dimension + std::ostream &out) // output stream +{ + for (int j = 0; j < dim; j++) { + out << pt[j]; + if (j < dim-1) out << " "; + } +} + +//---------------------------------------------------------------------- +// Point allocation/deallocation: +// +// Because points (somewhat like strings in C) are stored +// as pointers. Consequently, creating and destroying +// copies of points may require storage allocation. These +// procedures do this. +// +// annAllocPt() and annDeallocPt() allocate a deallocate +// storage for a single point, and return a pointer to it. +// +// annAllocPts() allocates an array of points as well a place +// to store their coordinates, and initializes the points to +// point to their respective coordinates. It allocates point +// storage in a contiguous block large enough to store all the +// points. It performs no initialization. +// +// annDeallocPts() should only be used on point arrays allocated +// by annAllocPts since it assumes that points are allocated in +// a block. +// +// annCopyPt() copies a point taking care to allocate storage +// for the new point. +// +// annAssignRect() assigns the coordinates of one rectangle to +// another. The two rectangles must have the same dimension +// (and it is not possible to test this here). +//---------------------------------------------------------------------- + +ANNpoint annAllocPt(int dim, ANNcoord c) // allocate 1 point +{ + ANNpoint p = new ANNcoord[dim]; + for (int i = 0; i < dim; i++) p[i] = c; + return p; +} + +ANNpointArray annAllocPts(int n, int dim) // allocate n pts in dim +{ + ANNpointArray pa = new ANNpoint[n]; // allocate points + ANNpoint p = new ANNcoord[n*dim]; // allocate space for coords + for (int i = 0; i < n; i++) { + pa[i] = &(p[i*dim]); + } + return pa; +} + +void annDeallocPt(ANNpoint &p) // deallocate 1 point +{ + delete [] p; + p = NULL; +} + +void annDeallocPts(ANNpointArray &pa) // deallocate points +{ + delete [] pa[0]; // dealloc coordinate storage + delete [] pa; // dealloc points + pa = NULL; +} + +ANNpoint annCopyPt(int dim, ANNpoint source) // copy point +{ + ANNpoint p = new ANNcoord[dim]; + for (int i = 0; i < dim; i++) p[i] = source[i]; + return p; +} + + // assign one rect to another +void annAssignRect(int dim, ANNorthRect &dest, const ANNorthRect &source) +{ + for (int i = 0; i < dim; i++) { + dest.lo[i] = source.lo[i]; + dest.hi[i] = source.hi[i]; + } +} + + // is point inside rectangle? +ANNbool ANNorthRect::inside(int dim, ANNpoint p) +{ + for (int i = 0; i < dim; i++) { + if (p[i] < lo[i] || p[i] > hi[i]) return ANNfalse; + } + return ANNtrue; +} + +//---------------------------------------------------------------------- +// Error handler +//---------------------------------------------------------------------- + +void annError(char *msg, ANNerr level) +{ + if (level == ANNabort) { + cerr << "ANN: ERROR------->" << msg << "<-------------ERROR\n"; + exit(1); + } + else { + cerr << "ANN: WARNING----->" << msg << "<-------------WARNING\n"; + } +} + +//---------------------------------------------------------------------- +// Limit on number of points visited +// We have an option for terminating the search early if the +// number of points visited exceeds some threshold. If the +// threshold is 0 (its default) this means there is no limit +// and the algorithm applies its normal termination condition. +// This is for applications where there are real time constraints +// on the running time of the algorithm. +//---------------------------------------------------------------------- + +int ANNmaxPtsVisited = 0; // maximum number of pts visited +int ANNptsVisited; // number of pts visited in search + +//---------------------------------------------------------------------- +// Global function declarations +//---------------------------------------------------------------------- + +void annMaxPtsVisit( // set limit on max. pts to visit in search + int maxPts) // the limit +{ + ANNmaxPtsVisited = maxPts; +} diff --git a/contrib/ANN/src/bd_fix_rad_search.cpp b/contrib/ANN/src/bd_fix_rad_search.cpp new file mode 100644 index 0000000000..dea3f6bdf1 --- /dev/null +++ b/contrib/ANN/src/bd_fix_rad_search.cpp @@ -0,0 +1,61 @@ +//---------------------------------------------------------------------- +// File: bd_fix_rad_search.cpp +// Programmer: David Mount +// Description: Standard bd-tree search +// Last modified: 05/03/05 (Version 1.1) +//---------------------------------------------------------------------- +// Copyright (c) 1997-2005 University of Maryland and Sunil Arya and +// David Mount. All Rights Reserved. +// +// This software and related documentation is part of the Approximate +// Nearest Neighbor Library (ANN). This software is provided under +// the provisions of the Lesser GNU Public License (LGPL). See the +// file ../ReadMe.txt for further information. +// +// The University of Maryland (U.M.) and the authors make no +// representations about the suitability or fitness of this software for +// any purpose. It is provided "as is" without express or implied +// warranty. +//---------------------------------------------------------------------- +// History: +// Revision 1.1 05/03/05 +// Initial release +//---------------------------------------------------------------------- + +#include "bd_tree.h" // bd-tree declarations +#include "kd_fix_rad_search.h" // kd-tree FR search declarations + +//---------------------------------------------------------------------- +// Approximate searching for bd-trees. +// See the file kd_FR_search.cpp for general information on the +// approximate nearest neighbor search algorithm. Here we +// include the extensions for shrinking nodes. +//---------------------------------------------------------------------- + +//---------------------------------------------------------------------- +// bd_shrink::ann_FR_search - search a shrinking node +//---------------------------------------------------------------------- + +void ANNbd_shrink::ann_FR_search(ANNdist box_dist) +{ + // check dist calc term cond. + if (ANNmaxPtsVisited != 0 && ANNptsVisited > ANNmaxPtsVisited) return; + + ANNdist inner_dist = 0; // distance to inner box + for (int i = 0; i < n_bnds; i++) { // is query point in the box? + if (bnds[i].out(ANNkdFRQ)) { // outside this bounding side? + // add to inner distance + inner_dist = (ANNdist) ANN_SUM(inner_dist, bnds[i].dist(ANNkdFRQ)); + } + } + if (inner_dist <= box_dist) { // if inner box is closer + child[ANN_IN]->ann_FR_search(inner_dist);// search inner child first + child[ANN_OUT]->ann_FR_search(box_dist);// ...then outer child + } + else { // if outer box is closer + child[ANN_OUT]->ann_FR_search(box_dist);// search outer child first + child[ANN_IN]->ann_FR_search(inner_dist);// ...then outer child + } + ANN_FLOP(3*n_bnds) // increment floating ops + ANN_SHR(1) // one more shrinking node +} diff --git a/contrib/ANN/src/bd_pr_search.cpp b/contrib/ANN/src/bd_pr_search.cpp new file mode 100644 index 0000000000..d16d632945 --- /dev/null +++ b/contrib/ANN/src/bd_pr_search.cpp @@ -0,0 +1,62 @@ +//---------------------------------------------------------------------- +// File: bd_pr_search.cpp +// Programmer: David Mount +// Description: Priority search for bd-trees +// Last modified: 01/04/05 (Version 1.0) +//---------------------------------------------------------------------- +// Copyright (c) 1997-2005 University of Maryland and Sunil Arya and +// David Mount. All Rights Reserved. +// +// This software and related documentation is part of the Approximate +// Nearest Neighbor Library (ANN). This software is provided under +// the provisions of the Lesser GNU Public License (LGPL). See the +// file ../ReadMe.txt for further information. +// +// The University of Maryland (U.M.) and the authors make no +// representations about the suitability or fitness of this software for +// any purpose. It is provided "as is" without express or implied +// warranty. +//---------------------------------------------------------------------- +//History: +// Revision 0.1 03/04/98 +// Initial release +//---------------------------------------------------------------------- + +#include "bd_tree.h" // bd-tree declarations +#include "kd_pr_search.h" // kd priority search declarations + +//---------------------------------------------------------------------- +// Approximate priority searching for bd-trees. +// See the file kd_pr_search.cc for general information on the +// approximate nearest neighbor priority search algorithm. Here +// we include the extensions for shrinking nodes. +//---------------------------------------------------------------------- + +//---------------------------------------------------------------------- +// bd_shrink::ann_search - search a shrinking node +//---------------------------------------------------------------------- + +void ANNbd_shrink::ann_pri_search(ANNdist box_dist) +{ + ANNdist inner_dist = 0; // distance to inner box + for (int i = 0; i < n_bnds; i++) { // is query point in the box? + if (bnds[i].out(ANNprQ)) { // outside this bounding side? + // add to inner distance + inner_dist = (ANNdist) ANN_SUM(inner_dist, bnds[i].dist(ANNprQ)); + } + } + if (inner_dist <= box_dist) { // if inner box is closer + if (child[ANN_OUT] != KD_TRIVIAL) // enqueue outer if not trivial + ANNprBoxPQ->insert(box_dist,child[ANN_OUT]); + // continue with inner child + child[ANN_IN]->ann_pri_search(inner_dist); + } + else { // if outer box is closer + if (child[ANN_IN] != KD_TRIVIAL) // enqueue inner if not trivial + ANNprBoxPQ->insert(inner_dist,child[ANN_IN]); + // continue with outer child + child[ANN_OUT]->ann_pri_search(box_dist); + } + ANN_FLOP(3*n_bnds) // increment floating ops + ANN_SHR(1) // one more shrinking node +} diff --git a/contrib/ANN/src/bd_search.cpp b/contrib/ANN/src/bd_search.cpp new file mode 100644 index 0000000000..f057018a28 --- /dev/null +++ b/contrib/ANN/src/bd_search.cpp @@ -0,0 +1,61 @@ +//---------------------------------------------------------------------- +// File: bd_search.cpp +// Programmer: David Mount +// Description: Standard bd-tree search +// Last modified: 01/04/05 (Version 1.0) +//---------------------------------------------------------------------- +// Copyright (c) 1997-2005 University of Maryland and Sunil Arya and +// David Mount. All Rights Reserved. +// +// This software and related documentation is part of the Approximate +// Nearest Neighbor Library (ANN). This software is provided under +// the provisions of the Lesser GNU Public License (LGPL). See the +// file ../ReadMe.txt for further information. +// +// The University of Maryland (U.M.) and the authors make no +// representations about the suitability or fitness of this software for +// any purpose. It is provided "as is" without express or implied +// warranty. +//---------------------------------------------------------------------- +// History: +// Revision 0.1 03/04/98 +// Initial release +//---------------------------------------------------------------------- + +#include "bd_tree.h" // bd-tree declarations +#include "kd_search.h" // kd-tree search declarations + +//---------------------------------------------------------------------- +// Approximate searching for bd-trees. +// See the file kd_search.cpp for general information on the +// approximate nearest neighbor search algorithm. Here we +// include the extensions for shrinking nodes. +//---------------------------------------------------------------------- + +//---------------------------------------------------------------------- +// bd_shrink::ann_search - search a shrinking node +//---------------------------------------------------------------------- + +void ANNbd_shrink::ann_search(ANNdist box_dist) +{ + // check dist calc term cond. + if (ANNmaxPtsVisited != 0 && ANNptsVisited > ANNmaxPtsVisited) return; + + ANNdist inner_dist = 0; // distance to inner box + for (int i = 0; i < n_bnds; i++) { // is query point in the box? + if (bnds[i].out(ANNkdQ)) { // outside this bounding side? + // add to inner distance + inner_dist = (ANNdist) ANN_SUM(inner_dist, bnds[i].dist(ANNkdQ)); + } + } + if (inner_dist <= box_dist) { // if inner box is closer + child[ANN_IN]->ann_search(inner_dist); // search inner child first + child[ANN_OUT]->ann_search(box_dist); // ...then outer child + } + else { // if outer box is closer + child[ANN_OUT]->ann_search(box_dist); // search outer child first + child[ANN_IN]->ann_search(inner_dist); // ...then outer child + } + ANN_FLOP(3*n_bnds) // increment floating ops + ANN_SHR(1) // one more shrinking node +} diff --git a/contrib/ANN/src/bd_tree.cpp b/contrib/ANN/src/bd_tree.cpp new file mode 100644 index 0000000000..0977dea96f --- /dev/null +++ b/contrib/ANN/src/bd_tree.cpp @@ -0,0 +1,417 @@ +//---------------------------------------------------------------------- +// File: bd_tree.cpp +// Programmer: David Mount +// Description: Basic methods for bd-trees. +// Last modified: 01/04/05 (Version 1.0) +//---------------------------------------------------------------------- +// Copyright (c) 1997-2005 University of Maryland and Sunil Arya and +// David Mount. All Rights Reserved. +// +// This software and related documentation is part of the Approximate +// Nearest Neighbor Library (ANN). This software is provided under +// the provisions of the Lesser GNU Public License (LGPL). See the +// file ../ReadMe.txt for further information. +// +// The University of Maryland (U.M.) and the authors make no +// representations about the suitability or fitness of this software for +// any purpose. It is provided "as is" without express or implied +// warranty. +//---------------------------------------------------------------------- +// History: +// Revision 0.1 03/04/98 +// Initial release +// Revision l.0 04/01/05 +// Fixed centroid shrink threshold condition to depend on the +// dimension. +// Moved dump routine to kd_dump.cpp. +//---------------------------------------------------------------------- + +#include "bd_tree.h" // bd-tree declarations +#include "kd_util.h" // kd-tree utilities +#include "kd_split.h" // kd-tree splitting rules + +#include <ANN/ANNperf.h> // performance evaluation + +//---------------------------------------------------------------------- +// Printing a bd-tree +// These routines print a bd-tree. See the analogous procedure +// in kd_tree.cpp for more information. +//---------------------------------------------------------------------- + +void ANNbd_shrink::print( // print shrinking node + int level, // depth of node in tree + ostream &out) // output stream +{ + child[ANN_OUT]->print(level+1, out); // print out-child + + out << " "; + for (int i = 0; i < level; i++) // print indentation + out << ".."; + out << "Shrink"; + for (int j = 0; j < n_bnds; j++) { // print sides, 2 per line + if (j % 2 == 0) { + out << "\n"; // newline and indentation + for (int i = 0; i < level+2; i++) out << " "; + } + out << " ([" << bnds[j].cd << "]" + << (bnds[j].sd > 0 ? ">=" : "< ") + << bnds[j].cv << ")"; + } + out << "\n"; + + child[ANN_IN]->print(level+1, out); // print in-child +} + +//---------------------------------------------------------------------- +// kd_tree statistics utility (for performance evaluation) +// This routine computes various statistics information for +// shrinking nodes. See file kd_tree.cpp for more information. +//---------------------------------------------------------------------- + +void ANNbd_shrink::getStats( // get subtree statistics + int dim, // dimension of space + ANNkdStats &st, // stats (modified) + ANNorthRect &bnd_box) // bounding box +{ + ANNkdStats ch_stats; // stats for children + ANNorthRect inner_box(dim); // inner box of shrink + + annBnds2Box(bnd_box, // enclosing box + dim, // dimension + n_bnds, // number of bounds + bnds, // bounds array + inner_box); // inner box (modified) + // get stats for inner child + ch_stats.reset(); // reset + child[ANN_IN]->getStats(dim, ch_stats, inner_box); + st.merge(ch_stats); // merge them + // get stats for outer child + ch_stats.reset(); // reset + child[ANN_OUT]->getStats(dim, ch_stats, bnd_box); + st.merge(ch_stats); // merge them + + st.depth++; // increment depth + st.n_shr++; // increment number of shrinks +} + +//---------------------------------------------------------------------- +// bd-tree constructor +// This is the main constructor for bd-trees given a set of points. +// It first builds a skeleton kd-tree as a basis, then computes the +// bounding box of the data points, and then invokes rbd_tree() to +// actually build the tree, passing it the appropriate splitting +// and shrinking information. +//---------------------------------------------------------------------- + +ANNkd_ptr rbd_tree( // recursive construction of bd-tree + ANNpointArray pa, // point array + ANNidxArray pidx, // point indices to store in subtree + int n, // number of points + int dim, // dimension of space + int bsp, // bucket space + ANNorthRect &bnd_box, // bounding box for current node + ANNkd_splitter splitter, // splitting routine + ANNshrinkRule shrink); // shrinking rule + +ANNbd_tree::ANNbd_tree( // construct from point array + ANNpointArray pa, // point array (with at least n pts) + int n, // number of points + int dd, // dimension + int bs, // bucket size + ANNsplitRule split, // splitting rule + ANNshrinkRule shrink) // shrinking rule + : ANNkd_tree(n, dd, bs) // build skeleton base tree +{ + pts = pa; // where the points are + if (n == 0) return; // no points--no sweat + + ANNorthRect bnd_box(dd); // bounding box for points + // construct bounding rectangle + annEnclRect(pa, pidx, n, dd, bnd_box); + // copy to tree structure + bnd_box_lo = annCopyPt(dd, bnd_box.lo); + bnd_box_hi = annCopyPt(dd, bnd_box.hi); + + switch (split) { // build by rule + case ANN_KD_STD: // standard kd-splitting rule + root = rbd_tree(pa, pidx, n, dd, bs, bnd_box, kd_split, shrink); + break; + case ANN_KD_MIDPT: // midpoint split + root = rbd_tree(pa, pidx, n, dd, bs, bnd_box, midpt_split, shrink); + break; + case ANN_KD_SUGGEST: // best (in our opinion) + case ANN_KD_SL_MIDPT: // sliding midpoint split + root = rbd_tree(pa, pidx, n, dd, bs, bnd_box, sl_midpt_split, shrink); + break; + case ANN_KD_FAIR: // fair split + root = rbd_tree(pa, pidx, n, dd, bs, bnd_box, fair_split, shrink); + break; + case ANN_KD_SL_FAIR: // sliding fair split + root = rbd_tree(pa, pidx, n, dd, bs, + bnd_box, sl_fair_split, shrink); + break; + default: + annError("Illegal splitting method", ANNabort); + } +} + +//---------------------------------------------------------------------- +// Shrinking rules +//---------------------------------------------------------------------- + +enum ANNdecomp {SPLIT, SHRINK}; // decomposition methods + +//---------------------------------------------------------------------- +// trySimpleShrink - Attempt a simple shrink +// +// We compute the tight bounding box of the points, and compute +// the 2*dim ``gaps'' between the sides of the tight box and the +// bounding box. If any of the gaps is large enough relative to +// the longest side of the tight bounding box, then we shrink +// all sides whose gaps are large enough. (The reason for +// comparing against the tight bounding box, is that after +// shrinking the longest box size will decrease, and if we use +// the standard bounding box, we may decide to shrink twice in +// a row. Since the tight box is fixed, we cannot shrink twice +// consecutively.) +//---------------------------------------------------------------------- +const float BD_GAP_THRESH = 0.5; // gap threshold (must be < 1) +const int BD_CT_THRESH = 2; // min number of shrink sides + +ANNdecomp trySimpleShrink( // try a simple shrink + ANNpointArray pa, // point array + ANNidxArray pidx, // point indices to store in subtree + int n, // number of points + int dim, // dimension of space + const ANNorthRect &bnd_box, // current bounding box + ANNorthRect &inner_box) // inner box if shrinking (returned) +{ + int i; + // compute tight bounding box + annEnclRect(pa, pidx, n, dim, inner_box); + + ANNcoord max_length = 0; // find longest box side + for (i = 0; i < dim; i++) { + ANNcoord length = inner_box.hi[i] - inner_box.lo[i]; + if (length > max_length) { + max_length = length; + } + } + + int shrink_ct = 0; // number of sides we shrunk + for (i = 0; i < dim; i++) { // select which sides to shrink + // gap between boxes + ANNcoord gap_hi = bnd_box.hi[i] - inner_box.hi[i]; + // big enough gap to shrink? + if (gap_hi < max_length*BD_GAP_THRESH) + inner_box.hi[i] = bnd_box.hi[i]; // no - expand + else shrink_ct++; // yes - shrink this side + + // repeat for high side + ANNcoord gap_lo = inner_box.lo[i] - bnd_box.lo[i]; + if (gap_lo < max_length*BD_GAP_THRESH) + inner_box.lo[i] = bnd_box.lo[i]; // no - expand + else shrink_ct++; // yes - shrink this side + } + + if (shrink_ct >= BD_CT_THRESH) // did we shrink enough sides? + return SHRINK; + else return SPLIT; +} + +//---------------------------------------------------------------------- +// tryCentroidShrink - Attempt a centroid shrink +// +// We repeatedly apply the splitting rule, always to the larger subset +// of points, until the number of points decreases by the constant +// fraction BD_FRACTION. If this takes more than dim*BD_MAX_SPLIT_FAC +// splits for this to happen, then we shrink to the final inner box +// Otherwise we split. +//---------------------------------------------------------------------- + +const float BD_MAX_SPLIT_FAC = 0.5; // maximum number of splits allowed +const float BD_FRACTION = 0.5; // ...to reduce points by this fraction + // ...This must be < 1. + +ANNdecomp tryCentroidShrink( // try a centroid shrink + ANNpointArray pa, // point array + ANNidxArray pidx, // point indices to store in subtree + int n, // number of points + int dim, // dimension of space + const ANNorthRect &bnd_box, // current bounding box + ANNkd_splitter splitter, // splitting procedure + ANNorthRect &inner_box) // inner box if shrinking (returned) +{ + int n_sub = n; // number of points in subset + int n_goal = (int) (n*BD_FRACTION); // number of point in goal + int n_splits = 0; // number of splits needed + // initialize inner box to bounding box + annAssignRect(dim, inner_box, bnd_box); + + while (n_sub > n_goal) { // keep splitting until goal reached + int cd; // cut dim from splitter (ignored) + ANNcoord cv; // cut value from splitter (ignored) + int n_lo; // number of points on low side + // invoke splitting procedure + (*splitter)(pa, pidx, inner_box, n_sub, dim, cd, cv, n_lo); + n_splits++; // increment split count + + if (n_lo >= n_sub/2) { // most points on low side + inner_box.hi[cd] = cv; // collapse high side + n_sub = n_lo; // recurse on lower points + } + else { // most points on high side + inner_box.lo[cd] = cv; // collapse low side + pidx += n_lo; // recurse on higher points + n_sub -= n_lo; + } + } + if (n_splits > dim*BD_MAX_SPLIT_FAC)// took too many splits + return SHRINK; // shrink to final subset + else + return SPLIT; +} + +//---------------------------------------------------------------------- +// selectDecomp - select which decomposition to use +//---------------------------------------------------------------------- + +ANNdecomp selectDecomp( // select decomposition method + ANNpointArray pa, // point array + ANNidxArray pidx, // point indices to store in subtree + int n, // number of points + int dim, // dimension of space + const ANNorthRect &bnd_box, // current bounding box + ANNkd_splitter splitter, // splitting procedure + ANNshrinkRule shrink, // shrinking rule + ANNorthRect &inner_box) // inner box if shrinking (returned) +{ + ANNdecomp decomp = SPLIT; // decomposition + + switch (shrink) { // check shrinking rule + case ANN_BD_NONE: // no shrinking allowed + decomp = SPLIT; + break; + case ANN_BD_SUGGEST: // author's suggestion + case ANN_BD_SIMPLE: // simple shrink + decomp = trySimpleShrink( + pa, pidx, // points and indices + n, dim, // number of points and dimension + bnd_box, // current bounding box + inner_box); // inner box if shrinking (returned) + break; + case ANN_BD_CENTROID: // centroid shrink + decomp = tryCentroidShrink( + pa, pidx, // points and indices + n, dim, // number of points and dimension + bnd_box, // current bounding box + splitter, // splitting procedure + inner_box); // inner box if shrinking (returned) + break; + default: + annError("Illegal shrinking rule", ANNabort); + } + return decomp; +} + +//---------------------------------------------------------------------- +// rbd_tree - recursive procedure to build a bd-tree +// +// This is analogous to rkd_tree, but for bd-trees. See the +// procedure rkd_tree() in kd_split.cpp for more information. +// +// If the number of points falls below the bucket size, then a +// leaf node is created for the points. Otherwise we invoke the +// procedure selectDecomp() which determines whether we are to +// split or shrink. If splitting is chosen, then we essentially +// do exactly as rkd_tree() would, and invoke the specified +// splitting procedure to the points. Otherwise, the selection +// procedure returns a bounding box, from which we extract the +// appropriate shrinking bounds, and create a shrinking node. +// Finally the points are subdivided, and the procedure is +// invoked recursively on the two subsets to form the children. +//---------------------------------------------------------------------- + +ANNkd_ptr rbd_tree( // recursive construction of bd-tree + ANNpointArray pa, // point array + ANNidxArray pidx, // point indices to store in subtree + int n, // number of points + int dim, // dimension of space + int bsp, // bucket space + ANNorthRect &bnd_box, // bounding box for current node + ANNkd_splitter splitter, // splitting routine + ANNshrinkRule shrink) // shrinking rule +{ + ANNdecomp decomp; // decomposition method + + ANNorthRect inner_box(dim); // inner box (if shrinking) + + if (n <= bsp) { // n small, make a leaf node + if (n == 0) // empty leaf node + return KD_TRIVIAL; // return (canonical) empty leaf + else // construct the node and return + return new ANNkd_leaf(n, pidx); + } + + decomp = selectDecomp( // select decomposition method + pa, pidx, // points and indices + n, dim, // number of points and dimension + bnd_box, // current bounding box + splitter, shrink, // splitting/shrinking methods + inner_box); // inner box if shrinking (returned) + + if (decomp == SPLIT) { // split selected + int cd; // cutting dimension + ANNcoord cv; // cutting value + int n_lo; // number on low side of cut + // invoke splitting procedure + (*splitter)(pa, pidx, bnd_box, n, dim, cd, cv, n_lo); + + ANNcoord lv = bnd_box.lo[cd]; // save bounds for cutting dimension + ANNcoord hv = bnd_box.hi[cd]; + + bnd_box.hi[cd] = cv; // modify bounds for left subtree + ANNkd_ptr lo = rbd_tree( // build left subtree + pa, pidx, n_lo, // ...from pidx[0..n_lo-1] + dim, bsp, bnd_box, splitter, shrink); + bnd_box.hi[cd] = hv; // restore bounds + + bnd_box.lo[cd] = cv; // modify bounds for right subtree + ANNkd_ptr hi = rbd_tree( // build right subtree + pa, pidx + n_lo, n-n_lo,// ...from pidx[n_lo..n-1] + dim, bsp, bnd_box, splitter, shrink); + bnd_box.lo[cd] = lv; // restore bounds + // create the splitting node + return new ANNkd_split(cd, cv, lv, hv, lo, hi); + } + else { // shrink selected + int n_in; // number of points in box + int n_bnds; // number of bounding sides + + annBoxSplit( // split points around inner box + pa, // points to split + pidx, // point indices + n, // number of points + dim, // dimension + inner_box, // inner box + n_in); // number of points inside (returned) + + ANNkd_ptr in = rbd_tree( // build inner subtree pidx[0..n_in-1] + pa, pidx, n_in, dim, bsp, inner_box, splitter, shrink); + ANNkd_ptr out = rbd_tree( // build outer subtree pidx[n_in..n] + pa, pidx+n_in, n - n_in, dim, bsp, bnd_box, splitter, shrink); + + ANNorthHSArray bnds = NULL; // bounds (alloc in Box2Bnds and + // ...freed in bd_shrink destroyer) + + annBox2Bnds( // convert inner box to bounds + inner_box, // inner box + bnd_box, // enclosing box + dim, // dimension + n_bnds, // number of bounds (returned) + bnds); // bounds array (modified) + + // return shrinking node + return new ANNbd_shrink(n_bnds, bnds, in, out); + } +} diff --git a/contrib/ANN/src/bd_tree.h b/contrib/ANN/src/bd_tree.h new file mode 100644 index 0000000000..408889a07d --- /dev/null +++ b/contrib/ANN/src/bd_tree.h @@ -0,0 +1,100 @@ +//---------------------------------------------------------------------- +// File: bd_tree.h +// Programmer: David Mount +// Description: Declarations for standard bd-tree routines +// Last modified: 01/04/05 (Version 1.0) +//---------------------------------------------------------------------- +// Copyright (c) 1997-2005 University of Maryland and Sunil Arya and +// David Mount. All Rights Reserved. +// +// This software and related documentation is part of the Approximate +// Nearest Neighbor Library (ANN). This software is provided under +// the provisions of the Lesser GNU Public License (LGPL). See the +// file ../ReadMe.txt for further information. +// +// The University of Maryland (U.M.) and the authors make no +// representations about the suitability or fitness of this software for +// any purpose. It is provided "as is" without express or implied +// warranty. +//---------------------------------------------------------------------- +// History: +// Revision 0.1 03/04/98 +// Initial release +// Revision 1.0 04/01/05 +// Changed IN, OUT to ANN_IN, ANN_OUT +//---------------------------------------------------------------------- + +#ifndef ANN_bd_tree_H +#define ANN_bd_tree_H + +#include <ANN/ANNx.h> // all ANN includes +#include "kd_tree.h" // kd-tree includes + +//---------------------------------------------------------------------- +// bd-tree shrinking node. +// The main addition in the bd-tree is the shrinking node, which +// is declared here. +// +// Shrinking nodes are defined by list of orthogonal halfspaces. +// These halfspaces define a (possibly unbounded) orthogonal +// rectangle. There are two children, in and out. Points that +// lie within this rectangle are stored in the in-child, and the +// other points are stored in the out-child. +// +// We use a list of orthogonal halfspaces rather than an +// orthogonal rectangle object because typically the number of +// sides of the shrinking box will be much smaller than the +// worst case bound of 2*dim. +// +// BEWARE: Note that constructor just copies the pointer to the +// bounding array, but the destructor deallocates it. This is +// rather poor practice, but happens to be convenient. The list +// is allocated in the bd-tree building procedure rbd_tree() just +// prior to construction, and is used for no other purposes. +// +// WARNING: In the near neighbor searching code it is assumed that +// the list of bounding halfspaces is irredundant, meaning that there +// are no two distinct halfspaces in the list with the same outward +// pointing normals. +//---------------------------------------------------------------------- + +class ANNbd_shrink : public ANNkd_node // splitting node of a kd-tree +{ + int n_bnds; // number of bounding halfspaces + ANNorthHSArray bnds; // list of bounding halfspaces + ANNkd_ptr child[2]; // in and out children +public: + ANNbd_shrink( // constructor + int nb, // number of bounding halfspaces + ANNorthHSArray bds, // list of bounding halfspaces + ANNkd_ptr ic=NULL, ANNkd_ptr oc=NULL) // children + { + n_bnds = nb; // cutting dimension + bnds = bds; // assign bounds + child[ANN_IN] = ic; // set children + child[ANN_OUT] = oc; + } + + ~ANNbd_shrink() // destructor + { + if (child[ANN_IN]!= NULL && child[ANN_IN]!= KD_TRIVIAL) + delete child[ANN_IN]; + if (child[ANN_OUT]!= NULL&& child[ANN_OUT]!= KD_TRIVIAL) + delete child[ANN_OUT]; + if (bnds != NULL) + delete [] bnds; // delete bounds + } + + virtual void getStats( // get tree statistics + int dim, // dimension of space + ANNkdStats &st, // statistics + ANNorthRect &bnd_box); // bounding box + virtual void print(int level, ostream &out);// print node + virtual void dump(ostream &out); // dump node + + virtual void ann_search(ANNdist); // standard search + virtual void ann_pri_search(ANNdist); // priority search + virtual void ann_FR_search(ANNdist); // fixed-radius search +}; + +#endif diff --git a/contrib/ANN/src/brute.cpp b/contrib/ANN/src/brute.cpp new file mode 100644 index 0000000000..d7cba2c7f6 --- /dev/null +++ b/contrib/ANN/src/brute.cpp @@ -0,0 +1,109 @@ +//---------------------------------------------------------------------- +// File: brute.cpp +// Programmer: Sunil Arya and David Mount +// Description: Brute-force nearest neighbors +// Last modified: 05/03/05 (Version 1.1) +//---------------------------------------------------------------------- +// Copyright (c) 1997-2005 University of Maryland and Sunil Arya and +// David Mount. All Rights Reserved. +// +// This software and related documentation is part of the Approximate +// Nearest Neighbor Library (ANN). This software is provided under +// the provisions of the Lesser GNU Public License (LGPL). See the +// file ../ReadMe.txt for further information. +// +// The University of Maryland (U.M.) and the authors make no +// representations about the suitability or fitness of this software for +// any purpose. It is provided "as is" without express or implied +// warranty. +//---------------------------------------------------------------------- +// History: +// Revision 0.1 03/04/98 +// Initial release +// Revision 1.1 05/03/05 +// Added fixed-radius kNN search +//---------------------------------------------------------------------- + +#include <ANN/ANNx.h> // all ANN includes +#include "pr_queue_k.h" // k element priority queue + +//---------------------------------------------------------------------- +// Brute-force search simply stores a pointer to the list of +// data points and searches linearly for the nearest neighbor. +// The k nearest neighbors are stored in a k-element priority +// queue (which is implemented in a pretty dumb way as well). +// +// If ANN_ALLOW_SELF_MATCH is ANNfalse then data points at distance +// zero are not considered. +// +// Note that the error bound eps is passed in, but it is ignored. +// These routines compute exact nearest neighbors (which is needed +// for validation purposes in ann_test.cpp). +//---------------------------------------------------------------------- + +ANNbruteForce::ANNbruteForce( // constructor from point array + ANNpointArray pa, // point array + int n, // number of points + int dd) // dimension +{ + dim = dd; n_pts = n; pts = pa; +} + +ANNbruteForce::~ANNbruteForce() { } // destructor (empty) + +void ANNbruteForce::annkSearch( // approx k near neighbor search + ANNpoint q, // query point + int k, // number of near neighbors to return + ANNidxArray nn_idx, // nearest neighbor indices (returned) + ANNdistArray dd, // dist to near neighbors (returned) + double eps) // error bound (ignored) +{ + ANNmin_k mk(k); // construct a k-limited priority queue + int i; + + if (k > n_pts) { // too many near neighbors? + annError("Requesting more near neighbors than data points", ANNabort); + } + // run every point through queue + for (i = 0; i < n_pts; i++) { + // compute distance to point + ANNdist sqDist = annDist(dim, pts[i], q); + if (ANN_ALLOW_SELF_MATCH || sqDist != 0) + mk.insert(sqDist, i); + } + for (i = 0; i < k; i++) { // extract the k closest points + dd[i] = mk.ith_smallest_key(i); + nn_idx[i] = mk.ith_smallest_info(i); + } +} + +int ANNbruteForce::annkFRSearch( // approx fixed-radius kNN search + ANNpoint q, // query point + ANNdist sqRad, // squared radius + int k, // number of near neighbors to return + ANNidxArray nn_idx, // nearest neighbor array (returned) + ANNdistArray dd, // dist to near neighbors (returned) + double eps) // error bound +{ + ANNmin_k mk(k); // construct a k-limited priority queue + int i; + int pts_in_range = 0; // number of points in query range + // run every point through queue + for (i = 0; i < n_pts; i++) { + // compute distance to point + ANNdist sqDist = annDist(dim, pts[i], q); + if (sqDist <= sqRad && // within radius bound + (ANN_ALLOW_SELF_MATCH || sqDist != 0)) { // ...and no self match + mk.insert(sqDist, i); + pts_in_range++; + } + } + for (i = 0; i < k; i++) { // extract the k closest points + if (dd != NULL) + dd[i] = mk.ith_smallest_key(i); + if (nn_idx != NULL) + nn_idx[i] = mk.ith_smallest_info(i); + } + + return pts_in_range; +} diff --git a/contrib/ANN/src/kd_dump.cpp b/contrib/ANN/src/kd_dump.cpp new file mode 100644 index 0000000000..e7015efe85 --- /dev/null +++ b/contrib/ANN/src/kd_dump.cpp @@ -0,0 +1,444 @@ +//---------------------------------------------------------------------- +// File: kd_dump.cc +// Programmer: David Mount +// Description: Dump and Load for kd- and bd-trees +// Last modified: 01/04/05 (Version 1.0) +//---------------------------------------------------------------------- +// Copyright (c) 1997-2005 University of Maryland and Sunil Arya and +// David Mount. All Rights Reserved. +// +// This software and related documentation is part of the Approximate +// Nearest Neighbor Library (ANN). This software is provided under +// the provisions of the Lesser GNU Public License (LGPL). See the +// file ../ReadMe.txt for further information. +// +// The University of Maryland (U.M.) and the authors make no +// representations about the suitability or fitness of this software for +// any purpose. It is provided "as is" without express or implied +// warranty. +//---------------------------------------------------------------------- +// History: +// Revision 0.1 03/04/98 +// Initial release +// Revision 1.0 04/01/05 +// Moved dump out of kd_tree.cc into this file. +// Added kd-tree load constructor. +//---------------------------------------------------------------------- +// This file contains routines for dumping kd-trees and bd-trees and +// reloading them. (It is an abuse of policy to include both kd- and +// bd-tree routines in the same file, sorry. There should be no problem +// in deleting the bd- versions of the routines if they are not +// desired.) +//---------------------------------------------------------------------- + +#include "kd_tree.h" // kd-tree declarations +#include "bd_tree.h" // bd-tree declarations + +using namespace std; // make std:: available + +//---------------------------------------------------------------------- +// Constants +//---------------------------------------------------------------------- + +const int STRING_LEN = 500; // maximum string length +const double EPSILON = 1E-5; // small number for float comparison + +enum ANNtreeType {KD_TREE, BD_TREE}; // tree types (used in loading) + +//---------------------------------------------------------------------- +// Procedure declarations +//---------------------------------------------------------------------- + +static ANNkd_ptr annReadDump( // read dump file + istream &in, // input stream + ANNtreeType tree_type, // type of tree expected + ANNpointArray &the_pts, // new points (if applic) + ANNidxArray &the_pidx, // point indices (returned) + int &the_dim, // dimension (returned) + int &the_n_pts, // number of points (returned) + int &the_bkt_size, // bucket size (returned) + ANNpoint &the_bnd_box_lo, // low bounding point + ANNpoint &the_bnd_box_hi); // high bounding point + +static ANNkd_ptr annReadTree( // read tree-part of dump file + istream &in, // input stream + ANNtreeType tree_type, // type of tree expected + ANNidxArray the_pidx, // point indices (modified) + int &next_idx); // next index (modified) + +//---------------------------------------------------------------------- +// ANN kd- and bd-tree Dump Format +// The dump file begins with a header containing the version of +// ANN, an optional section containing the points, followed by +// a description of the tree. The tree is printed in preorder. +// +// Format: +// #ANN <version number> <comments> [END_OF_LINE] +// points <dim> <n_pts> (point coordinates: this is optional) +// 0 <xxx> <xxx> ... <xxx> (point indices and coordinates) +// 1 <xxx> <xxx> ... <xxx> +// ... +// tree <dim> <n_pts> <bkt_size> +// <xxx> <xxx> ... <xxx> (lower end of bounding box) +// <xxx> <xxx> ... <xxx> (upper end of bounding box) +// If the tree is null, then a single line "null" is +// output. Otherwise the nodes of the tree are printed +// one per line in preorder. Leaves and splitting nodes +// have the following formats: +// Leaf node: +// leaf <n_pts> <bkt[0]> <bkt[1]> ... <bkt[n-1]> +// Splitting nodes: +// split <cut_dim> <cut_val> <lo_bound> <hi_bound> +// +// For bd-trees: +// +// Shrinking nodes: +// shrink <n_bnds> +// <cut_dim> <cut_val> <side> +// <cut_dim> <cut_val> <side> +// ... (repeated n_bnds times) +//---------------------------------------------------------------------- + +void ANNkd_tree::Dump( // dump entire tree + ANNbool with_pts, // print points as well? + ostream &out) // output stream +{ + out << "#ANN " << ANNversion << "\n"; + out.precision(ANNcoordPrec); // use full precision in dumping + if (with_pts) { // print point coordinates + out << "points " << dim << " " << n_pts << "\n"; + for (int i = 0; i < n_pts; i++) { + out << i << " "; + annPrintPt(pts[i], dim, out); + out << "\n"; + } + } + out << "tree " // print tree elements + << dim << " " + << n_pts << " " + << bkt_size << "\n"; + + annPrintPt(bnd_box_lo, dim, out); // print lower bound + out << "\n"; + annPrintPt(bnd_box_hi, dim, out); // print upper bound + out << "\n"; + + if (root == NULL) // empty tree? + out << "null\n"; + else { + root->dump(out); // invoke printing at root + } + out.precision(0); // restore default precision +} + +void ANNkd_split::dump( // dump a splitting node + ostream &out) // output stream +{ + out << "split " << cut_dim << " " << cut_val << " "; + out << cd_bnds[ANN_LO] << " " << cd_bnds[ANN_HI] << "\n"; + + child[ANN_LO]->dump(out); // print low child + child[ANN_HI]->dump(out); // print high child +} + +void ANNkd_leaf::dump( // dump a leaf node + ostream &out) // output stream +{ + if (this == KD_TRIVIAL) { // canonical trivial leaf node + out << "leaf 0\n"; // leaf no points + } + else{ + out << "leaf " << n_pts; + for (int j = 0; j < n_pts; j++) { + out << " " << bkt[j]; + } + out << "\n"; + } +} + +void ANNbd_shrink::dump( // dump a shrinking node + ostream &out) // output stream +{ + out << "shrink " << n_bnds << "\n"; + for (int j = 0; j < n_bnds; j++) { + out << bnds[j].cd << " " << bnds[j].cv << " " << bnds[j].sd << "\n"; + } + child[ANN_IN]->dump(out); // print in-child + child[ANN_OUT]->dump(out); // print out-child +} + +//---------------------------------------------------------------------- +// Load kd-tree from dump file +// This rebuilds a kd-tree which was dumped to a file. The dump +// file contains all the basic tree information according to a +// preorder traversal. We assume that the dump file also contains +// point data. (This is to guarantee the consistency of the tree.) +// If not, then an error is generated. +// +// Indirectly, this procedure allocates space for points, point +// indices, all nodes in the tree, and the bounding box for the +// tree. When the tree is destroyed, all but the points are +// deallocated. +// +// This routine calls annReadDump to do all the work. +//---------------------------------------------------------------------- + +ANNkd_tree::ANNkd_tree( // build from dump file + istream &in) // input stream for dump file +{ + int the_dim; // local dimension + int the_n_pts; // local number of points + int the_bkt_size; // local number of points + ANNpoint the_bnd_box_lo; // low bounding point + ANNpoint the_bnd_box_hi; // high bounding point + ANNpointArray the_pts; // point storage + ANNidxArray the_pidx; // point index storage + ANNkd_ptr the_root; // root of the tree + + the_root = annReadDump( // read the dump file + in, // input stream + KD_TREE, // expecting a kd-tree + the_pts, // point array (returned) + the_pidx, // point indices (returned) + the_dim, the_n_pts, the_bkt_size, // basic tree info (returned) + the_bnd_box_lo, the_bnd_box_hi); // bounding box info (returned) + + // create a skeletal tree + SkeletonTree(the_n_pts, the_dim, the_bkt_size, the_pts, the_pidx); + + bnd_box_lo = the_bnd_box_lo; + bnd_box_hi = the_bnd_box_hi; + + root = the_root; // set the root +} + +ANNbd_tree::ANNbd_tree( // build bd-tree from dump file + istream &in) : ANNkd_tree() // input stream for dump file +{ + int the_dim; // local dimension + int the_n_pts; // local number of points + int the_bkt_size; // local number of points + ANNpoint the_bnd_box_lo; // low bounding point + ANNpoint the_bnd_box_hi; // high bounding point + ANNpointArray the_pts; // point storage + ANNidxArray the_pidx; // point index storage + ANNkd_ptr the_root; // root of the tree + + the_root = annReadDump( // read the dump file + in, // input stream + BD_TREE, // expecting a bd-tree + the_pts, // point array (returned) + the_pidx, // point indices (returned) + the_dim, the_n_pts, the_bkt_size, // basic tree info (returned) + the_bnd_box_lo, the_bnd_box_hi); // bounding box info (returned) + + // create a skeletal tree + SkeletonTree(the_n_pts, the_dim, the_bkt_size, the_pts, the_pidx); + bnd_box_lo = the_bnd_box_lo; + bnd_box_hi = the_bnd_box_hi; + + root = the_root; // set the root +} + +//---------------------------------------------------------------------- +// annReadDump - read a dump file +// +// This procedure reads a dump file, constructs a kd-tree +// and returns all the essential information needed to actually +// construct the tree. Because this procedure is used for +// constructing both kd-trees and bd-trees, the second argument +// is used to indicate which type of tree we are expecting. +//---------------------------------------------------------------------- + +static ANNkd_ptr annReadDump( + istream &in, // input stream + ANNtreeType tree_type, // type of tree expected + ANNpointArray &the_pts, // new points (returned) + ANNidxArray &the_pidx, // point indices (returned) + int &the_dim, // dimension (returned) + int &the_n_pts, // number of points (returned) + int &the_bkt_size, // bucket size (returned) + ANNpoint &the_bnd_box_lo, // low bounding point (ret'd) + ANNpoint &the_bnd_box_hi) // high bounding point (ret'd) +{ + int j; + char str[STRING_LEN]; // storage for string + char version[STRING_LEN]; // ANN version number + ANNkd_ptr the_root = NULL; + + //------------------------------------------------------------------ + // Input file header + //------------------------------------------------------------------ + in >> str; // input header + if (strcmp(str, "#ANN") != 0) { // incorrect header + annError("Incorrect header for dump file", ANNabort); + } + in.getline(version, STRING_LEN); // get version (ignore) + + //------------------------------------------------------------------ + // Input the points + // An array the_pts is allocated and points are read from + // the dump file. + //------------------------------------------------------------------ + in >> str; // get major heading + if (strcmp(str, "points") == 0) { // points section + in >> the_dim; // input dimension + in >> the_n_pts; // number of points + // allocate point storage + the_pts = annAllocPts(the_n_pts, the_dim); + for (int i = 0; i < the_n_pts; i++) { // input point coordinates + ANNidx idx; // point index + in >> idx; // input point index + if (idx < 0 || idx >= the_n_pts) { + annError("Point index is out of range", ANNabort); + } + for (j = 0; j < the_dim; j++) { + in >> the_pts[idx][j]; // read point coordinates + } + } + in >> str; // get next major heading + } + else { // no points were input + annError("Points must be supplied in the dump file", ANNabort); + } + + //------------------------------------------------------------------ + // Input the tree + // After the basic header information, we invoke annReadTree + // to do all the heavy work. We create our own array of + // point indices (so we can pass them to annReadTree()) + // but we do not deallocate them. They will be deallocated + // when the tree is destroyed. + //------------------------------------------------------------------ + if (strcmp(str, "tree") == 0) { // tree section + in >> the_dim; // read dimension + in >> the_n_pts; // number of points + in >> the_bkt_size; // bucket size + the_bnd_box_lo = annAllocPt(the_dim); // allocate bounding box pts + the_bnd_box_hi = annAllocPt(the_dim); + + for (j = 0; j < the_dim; j++) { // read bounding box low + in >> the_bnd_box_lo[j]; + } + for (j = 0; j < the_dim; j++) { // read bounding box low + in >> the_bnd_box_hi[j]; + } + the_pidx = new ANNidx[the_n_pts]; // allocate point index array + int next_idx = 0; // number of indices filled + // read the tree and indices + the_root = annReadTree(in, tree_type, the_pidx, next_idx); + if (next_idx != the_n_pts) { // didn't see all the points? + annError("Didn't see as many points as expected", ANNwarn); + } + } + else { + annError("Illegal dump format. Expecting section heading", ANNabort); + } + return the_root; +} + +//---------------------------------------------------------------------- +// annReadTree - input tree and return pointer +// +// annReadTree reads in a node of the tree, makes any recursive +// calls as needed to input the children of this node (if internal). +// It returns a pointer to the node that was created. An array +// of point indices is given along with a pointer to the next +// available location in the array. As leaves are read, their +// point indices are stored here, and the point buckets point +// to the first entry in the array. +// +// Recall that these are the formats. The tree is given in +// preorder. +// +// Leaf node: +// leaf <n_pts> <bkt[0]> <bkt[1]> ... <bkt[n-1]> +// Splitting nodes: +// split <cut_dim> <cut_val> <lo_bound> <hi_bound> +// +// For bd-trees: +// +// Shrinking nodes: +// shrink <n_bnds> +// <cut_dim> <cut_val> <side> +// <cut_dim> <cut_val> <side> +// ... (repeated n_bnds times) +//---------------------------------------------------------------------- + +static ANNkd_ptr annReadTree( + istream &in, // input stream + ANNtreeType tree_type, // type of tree expected + ANNidxArray the_pidx, // point indices (modified) + int &next_idx) // next index (modified) +{ + char tag[STRING_LEN]; // tag (leaf, split, shrink) + int n_pts; // number of points in leaf + int cd; // cut dimension + ANNcoord cv; // cut value + ANNcoord lb; // low bound + ANNcoord hb; // high bound + int n_bnds; // number of bounding sides + int sd; // which side + + in >> tag; // input node tag + + if (strcmp(tag, "null") == 0) { // null tree + return NULL; + } + //------------------------------------------------------------------ + // Read a leaf + //------------------------------------------------------------------ + if (strcmp(tag, "leaf") == 0) { // leaf node + + in >> n_pts; // input number of points + int old_idx = next_idx; // save next_idx + if (n_pts == 0) { // trivial leaf + return KD_TRIVIAL; + } + else { + for (int i = 0; i < n_pts; i++) { // input point indices + in >> the_pidx[next_idx++]; // store in array of indices + } + } + return new ANNkd_leaf(n_pts, &the_pidx[old_idx]); + } + //------------------------------------------------------------------ + // Read a splitting node + //------------------------------------------------------------------ + else if (strcmp(tag, "split") == 0) { // splitting node + + in >> cd >> cv >> lb >> hb; + + // read low and high subtrees + ANNkd_ptr lc = annReadTree(in, tree_type, the_pidx, next_idx); + ANNkd_ptr hc = annReadTree(in, tree_type, the_pidx, next_idx); + // create new node and return + return new ANNkd_split(cd, cv, lb, hb, lc, hc); + } + //------------------------------------------------------------------ + // Read a shrinking node (bd-tree only) + //------------------------------------------------------------------ + else if (strcmp(tag, "shrink") == 0) { // shrinking node + if (tree_type != BD_TREE) { + annError("Shrinking node not allowed in kd-tree", ANNabort); + } + + in >> n_bnds; // number of bounding sides + // allocate bounds array + ANNorthHSArray bds = new ANNorthHalfSpace[n_bnds]; + for (int i = 0; i < n_bnds; i++) { + in >> cd >> cv >> sd; // input bounding halfspace + // copy to array + bds[i] = ANNorthHalfSpace(cd, cv, sd); + } + // read inner and outer subtrees + ANNkd_ptr ic = annReadTree(in, tree_type, the_pidx, next_idx); + ANNkd_ptr oc = annReadTree(in, tree_type, the_pidx, next_idx); + // create new node and return + return new ANNbd_shrink(n_bnds, bds, ic, oc); + } + else { + annError("Illegal node type in dump file", ANNabort); + exit(0); // to keep the compiler happy + } +} diff --git a/contrib/ANN/src/kd_fix_rad_search.cpp b/contrib/ANN/src/kd_fix_rad_search.cpp new file mode 100644 index 0000000000..87eb757d7b --- /dev/null +++ b/contrib/ANN/src/kd_fix_rad_search.cpp @@ -0,0 +1,183 @@ +//---------------------------------------------------------------------- +// File: kd_fix_rad_search.cpp +// Programmer: Sunil Arya and David Mount +// Description: Standard kd-tree fixed-radius kNN search +// Last modified: 05/03/05 (Version 1.1) +//---------------------------------------------------------------------- +// Copyright (c) 1997-2005 University of Maryland and Sunil Arya and +// David Mount. All Rights Reserved. +// +// This software and related documentation is part of the Approximate +// Nearest Neighbor Library (ANN). This software is provided under +// the provisions of the Lesser GNU Public License (LGPL). See the +// file ../ReadMe.txt for further information. +// +// The University of Maryland (U.M.) and the authors make no +// representations about the suitability or fitness of this software for +// any purpose. It is provided "as is" without express or implied +// warranty. +//---------------------------------------------------------------------- +// History: +// Revision 1.1 05/03/05 +// Initial release +//---------------------------------------------------------------------- + +#include "kd_fix_rad_search.h" // kd fixed-radius search decls + +//---------------------------------------------------------------------- +// Approximate fixed-radius k nearest neighbor search +// The squared radius is provided, and this procedure finds the +// k nearest neighbors within the radius, and returns the total +// number of points lying within the radius. +// +// The method used for searching the kd-tree is a variation of the +// nearest neighbor search used in kd_search.cpp, except that the +// radius of the search ball is known. We refer the reader to that +// file for the explanation of the recursive search procedure. +//---------------------------------------------------------------------- + +//---------------------------------------------------------------------- +// To keep argument lists short, a number of global variables +// are maintained which are common to all the recursive calls. +// These are given below. +//---------------------------------------------------------------------- + +int ANNkdFRDim; // dimension of space +ANNpoint ANNkdFRQ; // query point +ANNdist ANNkdFRSqRad; // squared radius search bound +double ANNkdFRMaxErr; // max tolerable squared error +ANNpointArray ANNkdFRPts; // the points +ANNmin_k* ANNkdFRPointMK; // set of k closest points +int ANNkdFRPtsVisited; // total points visited +int ANNkdFRPtsInRange; // number of points in the range + +//---------------------------------------------------------------------- +// annkFRSearch - fixed radius search for k nearest neighbors +//---------------------------------------------------------------------- + +int ANNkd_tree::annkFRSearch( + ANNpoint q, // the query point + ANNdist sqRad, // squared radius search bound + int k, // number of near neighbors to return + ANNidxArray nn_idx, // nearest neighbor indices (returned) + ANNdistArray dd, // the approximate nearest neighbor + double eps) // the error bound +{ + ANNkdFRDim = dim; // copy arguments to static equivs + ANNkdFRQ = q; + ANNkdFRSqRad = sqRad; + ANNkdFRPts = pts; + ANNkdFRPtsVisited = 0; // initialize count of points visited + ANNkdFRPtsInRange = 0; // ...and points in the range + + ANNkdFRMaxErr = ANN_POW(1.0 + eps); + ANN_FLOP(2) // increment floating op count + + ANNkdFRPointMK = new ANNmin_k(k); // create set for closest k points + // search starting at the root + root->ann_FR_search(annBoxDistance(q, bnd_box_lo, bnd_box_hi, dim)); + + for (int i = 0; i < k; i++) { // extract the k-th closest points + if (dd != NULL) + dd[i] = ANNkdFRPointMK->ith_smallest_key(i); + if (nn_idx != NULL) + nn_idx[i] = ANNkdFRPointMK->ith_smallest_info(i); + } + + delete ANNkdFRPointMK; // deallocate closest point set + return ANNkdFRPtsInRange; // return final point count +} + +//---------------------------------------------------------------------- +// kd_split::ann_FR_search - search a splitting node +// Note: This routine is similar in structure to the standard kNN +// search. It visits the subtree that is closer to the query point +// first. For fixed-radius search, there is no benefit in visiting +// one subtree before the other, but we maintain the same basic +// code structure for the sake of uniformity. +//---------------------------------------------------------------------- + +void ANNkd_split::ann_FR_search(ANNdist box_dist) +{ + // check dist calc term condition + if (ANNmaxPtsVisited != 0 && ANNkdFRPtsVisited > ANNmaxPtsVisited) return; + + // distance to cutting plane + ANNcoord cut_diff = ANNkdFRQ[cut_dim] - cut_val; + + if (cut_diff < 0) { // left of cutting plane + child[ANN_LO]->ann_FR_search(box_dist);// visit closer child first + + ANNcoord box_diff = cd_bnds[ANN_LO] - ANNkdFRQ[cut_dim]; + if (box_diff < 0) // within bounds - ignore + box_diff = 0; + // distance to further box + box_dist = (ANNdist) ANN_SUM(box_dist, + ANN_DIFF(ANN_POW(box_diff), ANN_POW(cut_diff))); + + // visit further child if in range + if (box_dist * ANNkdFRMaxErr <= ANNkdFRSqRad) + child[ANN_HI]->ann_FR_search(box_dist); + + } + else { // right of cutting plane + child[ANN_HI]->ann_FR_search(box_dist);// visit closer child first + + ANNcoord box_diff = ANNkdFRQ[cut_dim] - cd_bnds[ANN_HI]; + if (box_diff < 0) // within bounds - ignore + box_diff = 0; + // distance to further box + box_dist = (ANNdist) ANN_SUM(box_dist, + ANN_DIFF(ANN_POW(box_diff), ANN_POW(cut_diff))); + + // visit further child if close enough + if (box_dist * ANNkdFRMaxErr <= ANNkdFRSqRad) + child[ANN_LO]->ann_FR_search(box_dist); + + } + ANN_FLOP(13) // increment floating ops + ANN_SPL(1) // one more splitting node visited +} + +//---------------------------------------------------------------------- +// kd_leaf::ann_FR_search - search points in a leaf node +// Note: The unreadability of this code is the result of +// some fine tuning to replace indexing by pointer operations. +//---------------------------------------------------------------------- + +void ANNkd_leaf::ann_FR_search(ANNdist box_dist) +{ + register ANNdist dist; // distance to data point + register ANNcoord* pp; // data coordinate pointer + register ANNcoord* qq; // query coordinate pointer + register ANNcoord t; + register int d; + + for (int i = 0; i < n_pts; i++) { // check points in bucket + + pp = ANNkdFRPts[bkt[i]]; // first coord of next data point + qq = ANNkdFRQ; // first coord of query point + dist = 0; + + for(d = 0; d < ANNkdFRDim; d++) { + ANN_COORD(1) // one more coordinate hit + ANN_FLOP(5) // increment floating ops + + t = *(qq++) - *(pp++); // compute length and adv coordinate + // exceeds dist to k-th smallest? + if( (dist = ANN_SUM(dist, ANN_POW(t))) > ANNkdFRSqRad) { + break; + } + } + + if (d >= ANNkdFRDim && // among the k best? + (ANN_ALLOW_SELF_MATCH || dist!=0)) { // and no self-match problem + // add it to the list + ANNkdFRPointMK->insert(dist, bkt[i]); + ANNkdFRPtsInRange++; // increment point count + } + } + ANN_LEAF(1) // one more leaf node visited + ANN_PTS(n_pts) // increment points visited + ANNkdFRPtsVisited += n_pts; // increment number of points visited +} diff --git a/contrib/ANN/src/kd_fix_rad_search.h b/contrib/ANN/src/kd_fix_rad_search.h new file mode 100644 index 0000000000..7bae230db2 --- /dev/null +++ b/contrib/ANN/src/kd_fix_rad_search.h @@ -0,0 +1,44 @@ +//---------------------------------------------------------------------- +// File: kd_fix_rad_search.h +// Programmer: Sunil Arya and David Mount +// Description: Standard kd-tree fixed-radius kNN search +// Last modified: ??/??/?? (Version 1.1) +//---------------------------------------------------------------------- +// Copyright (c) 1997-2005 University of Maryland and Sunil Arya and +// David Mount. All Rights Reserved. +// +// This software and related documentation is part of the Approximate +// Nearest Neighbor Library (ANN). This software is provided under +// the provisions of the Lesser GNU Public License (LGPL). See the +// file ../ReadMe.txt for further information. +// +// The University of Maryland (U.M.) and the authors make no +// representations about the suitability or fitness of this software for +// any purpose. It is provided "as is" without express or implied +// warranty. +//---------------------------------------------------------------------- +// History: +// Revision 1.1 ??/??/?? +// Initial release +//---------------------------------------------------------------------- + +#ifndef ANN_kd_fix_rad_search_H +#define ANN_kd_fix_rad_search_H + +#include "kd_tree.h" // kd-tree declarations +#include "kd_util.h" // kd-tree utilities +#include "pr_queue_k.h" // k-element priority queue + +#include <ANN/ANNperf.h> // performance evaluation + +//---------------------------------------------------------------------- +// Global variables +// These are active for the life of each call to +// annRangeSearch(). They are set to save the number of +// variables that need to be passed among the various search +// procedures. +//---------------------------------------------------------------------- + +extern ANNpoint ANNkdFRQ; // query point (static copy) + +#endif diff --git a/contrib/ANN/src/kd_pr_search.cpp b/contrib/ANN/src/kd_pr_search.cpp new file mode 100644 index 0000000000..edb0479f29 --- /dev/null +++ b/contrib/ANN/src/kd_pr_search.cpp @@ -0,0 +1,219 @@ +//---------------------------------------------------------------------- +// File: kd_pr_search.cpp +// Programmer: Sunil Arya and David Mount +// Description: Priority search for kd-trees +// Last modified: 01/04/05 (Version 1.0) +//---------------------------------------------------------------------- +// Copyright (c) 1997-2005 University of Maryland and Sunil Arya and +// David Mount. All Rights Reserved. +// +// This software and related documentation is part of the Approximate +// Nearest Neighbor Library (ANN). This software is provided under +// the provisions of the Lesser GNU Public License (LGPL). See the +// file ../ReadMe.txt for further information. +// +// The University of Maryland (U.M.) and the authors make no +// representations about the suitability or fitness of this software for +// any purpose. It is provided "as is" without express or implied +// warranty. +//---------------------------------------------------------------------- +// History: +// Revision 0.1 03/04/98 +// Initial release +//---------------------------------------------------------------------- + +#include "kd_pr_search.h" // kd priority search declarations + +//---------------------------------------------------------------------- +// Approximate nearest neighbor searching by priority search. +// The kd-tree is searched for an approximate nearest neighbor. +// The point is returned through one of the arguments, and the +// distance returned is the SQUARED distance to this point. +// +// The method used for searching the kd-tree is called priority +// search. (It is described in Arya and Mount, ``Algorithms for +// fast vector quantization,'' Proc. of DCC '93: Data Compression +// Conference}, eds. J. A. Storer and M. Cohn, IEEE Press, 1993, +// 381--390.) +// +// The cell of the kd-tree containing the query point is located, +// and cells are visited in increasing order of distance from the +// query point. This is done by placing each subtree which has +// NOT been visited in a priority queue, according to the closest +// distance of the corresponding enclosing rectangle from the +// query point. The search stops when the distance to the nearest +// remaining rectangle exceeds the distance to the nearest point +// seen by a factor of more than 1/(1+eps). (Implying that any +// point found subsequently in the search cannot be closer by more +// than this factor.) +// +// The main entry point is annkPriSearch() which sets things up and +// then call the recursive routine ann_pri_search(). This is a +// recursive routine which performs the processing for one node in +// the kd-tree. There are two versions of this virtual procedure, +// one for splitting nodes and one for leaves. When a splitting node +// is visited, we determine which child to continue the search on +// (the closer one), and insert the other child into the priority +// queue. When a leaf is visited, we compute the distances to the +// points in the buckets, and update information on the closest +// points. +// +// Some trickery is used to incrementally update the distance from +// a kd-tree rectangle to the query point. This comes about from +// the fact that which each successive split, only one component +// (along the dimension that is split) of the squared distance to +// the child rectangle is different from the squared distance to +// the parent rectangle. +//---------------------------------------------------------------------- + +//---------------------------------------------------------------------- +// To keep argument lists short, a number of global variables +// are maintained which are common to all the recursive calls. +// These are given below. +//---------------------------------------------------------------------- + +double ANNprEps; // the error bound +int ANNprDim; // dimension of space +ANNpoint ANNprQ; // query point +double ANNprMaxErr; // max tolerable squared error +ANNpointArray ANNprPts; // the points +ANNpr_queue *ANNprBoxPQ; // priority queue for boxes +ANNmin_k *ANNprPointMK; // set of k closest points + +//---------------------------------------------------------------------- +// annkPriSearch - priority search for k nearest neighbors +//---------------------------------------------------------------------- + +void ANNkd_tree::annkPriSearch( + ANNpoint q, // query point + int k, // number of near neighbors to return + ANNidxArray nn_idx, // nearest neighbor indices (returned) + ANNdistArray dd, // dist to near neighbors (returned) + double eps) // error bound (ignored) +{ + // max tolerable squared error + ANNprMaxErr = ANN_POW(1.0 + eps); + ANN_FLOP(2) // increment floating ops + + ANNprDim = dim; // copy arguments to static equivs + ANNprQ = q; + ANNprPts = pts; + ANNptsVisited = 0; // initialize count of points visited + + ANNprPointMK = new ANNmin_k(k); // create set for closest k points + + // distance to root box + ANNdist box_dist = annBoxDistance(q, + bnd_box_lo, bnd_box_hi, dim); + + ANNprBoxPQ = new ANNpr_queue(n_pts);// create priority queue for boxes + ANNprBoxPQ->insert(box_dist, root); // insert root in priority queue + + while (ANNprBoxPQ->non_empty() && + (!(ANNmaxPtsVisited != 0 && ANNptsVisited > ANNmaxPtsVisited))) { + ANNkd_ptr np; // next box from prior queue + + // extract closest box from queue + ANNprBoxPQ->extr_min(box_dist, (void *&) np); + + ANN_FLOP(2) // increment floating ops + if (box_dist*ANNprMaxErr >= ANNprPointMK->max_key()) + break; + + np->ann_pri_search(box_dist); // search this subtree. + } + + for (int i = 0; i < k; i++) { // extract the k-th closest points + dd[i] = ANNprPointMK->ith_smallest_key(i); + nn_idx[i] = ANNprPointMK->ith_smallest_info(i); + } + + delete ANNprPointMK; // deallocate closest point set + delete ANNprBoxPQ; // deallocate priority queue +} + +//---------------------------------------------------------------------- +// kd_split::ann_pri_search - search a splitting node +//---------------------------------------------------------------------- + +void ANNkd_split::ann_pri_search(ANNdist box_dist) +{ + ANNdist new_dist; // distance to child visited later + // distance to cutting plane + ANNcoord cut_diff = ANNprQ[cut_dim] - cut_val; + + if (cut_diff < 0) { // left of cutting plane + ANNcoord box_diff = cd_bnds[ANN_LO] - ANNprQ[cut_dim]; + if (box_diff < 0) // within bounds - ignore + box_diff = 0; + // distance to further box + new_dist = (ANNdist) ANN_SUM(box_dist, + ANN_DIFF(ANN_POW(box_diff), ANN_POW(cut_diff))); + + if (child[ANN_HI] != KD_TRIVIAL)// enqueue if not trivial + ANNprBoxPQ->insert(new_dist, child[ANN_HI]); + // continue with closer child + child[ANN_LO]->ann_pri_search(box_dist); + } + else { // right of cutting plane + ANNcoord box_diff = ANNprQ[cut_dim] - cd_bnds[ANN_HI]; + if (box_diff < 0) // within bounds - ignore + box_diff = 0; + // distance to further box + new_dist = (ANNdist) ANN_SUM(box_dist, + ANN_DIFF(ANN_POW(box_diff), ANN_POW(cut_diff))); + + if (child[ANN_LO] != KD_TRIVIAL)// enqueue if not trivial + ANNprBoxPQ->insert(new_dist, child[ANN_LO]); + // continue with closer child + child[ANN_HI]->ann_pri_search(box_dist); + } + ANN_SPL(1) // one more splitting node visited + ANN_FLOP(8) // increment floating ops +} + +//---------------------------------------------------------------------- +// kd_leaf::ann_pri_search - search points in a leaf node +// +// This is virtually identical to the ann_search for standard search. +//---------------------------------------------------------------------- + +void ANNkd_leaf::ann_pri_search(ANNdist box_dist) +{ + register ANNdist dist; // distance to data point + register ANNcoord* pp; // data coordinate pointer + register ANNcoord* qq; // query coordinate pointer + register ANNdist min_dist; // distance to k-th closest point + register ANNcoord t; + register int d; + + min_dist = ANNprPointMK->max_key(); // k-th smallest distance so far + + for (int i = 0; i < n_pts; i++) { // check points in bucket + + pp = ANNprPts[bkt[i]]; // first coord of next data point + qq = ANNprQ; // first coord of query point + dist = 0; + + for(d = 0; d < ANNprDim; d++) { + ANN_COORD(1) // one more coordinate hit + ANN_FLOP(4) // increment floating ops + + t = *(qq++) - *(pp++); // compute length and adv coordinate + // exceeds dist to k-th smallest? + if( (dist = ANN_SUM(dist, ANN_POW(t))) > min_dist) { + break; + } + } + + if (d >= ANNprDim && // among the k best? + (ANN_ALLOW_SELF_MATCH || dist!=0)) { // and no self-match problem + // add it to the list + ANNprPointMK->insert(dist, bkt[i]); + min_dist = ANNprPointMK->max_key(); + } + } + ANN_LEAF(1) // one more leaf node visited + ANN_PTS(n_pts) // increment points visited + ANNptsVisited += n_pts; // increment number of points visited +} diff --git a/contrib/ANN/src/kd_pr_search.h b/contrib/ANN/src/kd_pr_search.h new file mode 100644 index 0000000000..39e048418d --- /dev/null +++ b/contrib/ANN/src/kd_pr_search.h @@ -0,0 +1,49 @@ +//---------------------------------------------------------------------- +// File: kd_pr_search.h +// Programmer: Sunil Arya and David Mount +// Description: Priority kd-tree search +// Last modified: 01/04/05 (Version 1.0) +//---------------------------------------------------------------------- +// Copyright (c) 1997-2005 University of Maryland and Sunil Arya and +// David Mount. All Rights Reserved. +// +// This software and related documentation is part of the Approximate +// Nearest Neighbor Library (ANN). This software is provided under +// the provisions of the Lesser GNU Public License (LGPL). See the +// file ../ReadMe.txt for further information. +// +// The University of Maryland (U.M.) and the authors make no +// representations about the suitability or fitness of this software for +// any purpose. It is provided "as is" without express or implied +// warranty. +//---------------------------------------------------------------------- +// History: +// Revision 0.1 03/04/98 +// Initial release +//---------------------------------------------------------------------- + +#ifndef ANN_kd_pr_search_H +#define ANN_kd_pr_search_H + +#include "kd_tree.h" // kd-tree declarations +#include "kd_util.h" // kd-tree utilities +#include "pr_queue.h" // priority queue declarations +#include "pr_queue_k.h" // k-element priority queue + +#include <ANN/ANNperf.h> // performance evaluation + +//---------------------------------------------------------------------- +// Global variables +// Active for the life of each call to Appx_Near_Neigh() or +// Appx_k_Near_Neigh(). +//---------------------------------------------------------------------- + +extern double ANNprEps; // the error bound +extern int ANNprDim; // dimension of space +extern ANNpoint ANNprQ; // query point +extern double ANNprMaxErr; // max tolerable squared error +extern ANNpointArray ANNprPts; // the points +extern ANNpr_queue *ANNprBoxPQ; // priority queue for boxes +extern ANNmin_k *ANNprPointMK; // set of k closest points + +#endif diff --git a/contrib/ANN/src/kd_search.cpp b/contrib/ANN/src/kd_search.cpp new file mode 100644 index 0000000000..5004ef798c --- /dev/null +++ b/contrib/ANN/src/kd_search.cpp @@ -0,0 +1,210 @@ +//---------------------------------------------------------------------- +// File: kd_search.cpp +// Programmer: Sunil Arya and David Mount +// Description: Standard kd-tree search +// Last modified: 01/04/05 (Version 1.0) +//---------------------------------------------------------------------- +// Copyright (c) 1997-2005 University of Maryland and Sunil Arya and +// David Mount. All Rights Reserved. +// +// This software and related documentation is part of the Approximate +// Nearest Neighbor Library (ANN). This software is provided under +// the provisions of the Lesser GNU Public License (LGPL). See the +// file ../ReadMe.txt for further information. +// +// The University of Maryland (U.M.) and the authors make no +// representations about the suitability or fitness of this software for +// any purpose. It is provided "as is" without express or implied +// warranty. +//---------------------------------------------------------------------- +// History: +// Revision 0.1 03/04/98 +// Initial release +// Revision 1.0 04/01/05 +// Changed names LO, HI to ANN_LO, ANN_HI +//---------------------------------------------------------------------- + +#include "kd_search.h" // kd-search declarations + +//---------------------------------------------------------------------- +// Approximate nearest neighbor searching by kd-tree search +// The kd-tree is searched for an approximate nearest neighbor. +// The point is returned through one of the arguments, and the +// distance returned is the squared distance to this point. +// +// The method used for searching the kd-tree is an approximate +// adaptation of the search algorithm described by Friedman, +// Bentley, and Finkel, ``An algorithm for finding best matches +// in logarithmic expected time,'' ACM Transactions on Mathematical +// Software, 3(3):209-226, 1977). +// +// The algorithm operates recursively. When first encountering a +// node of the kd-tree we first visit the child which is closest to +// the query point. On return, we decide whether we want to visit +// the other child. If the box containing the other child exceeds +// 1/(1+eps) times the current best distance, then we skip it (since +// any point found in this child cannot be closer to the query point +// by more than this factor.) Otherwise, we visit it recursively. +// The distance between a box and the query point is computed exactly +// (not approximated as is often done in kd-tree), using incremental +// distance updates, as described by Arya and Mount in ``Algorithms +// for fast vector quantization,'' Proc. of DCC '93: Data Compression +// Conference, eds. J. A. Storer and M. Cohn, IEEE Press, 1993, +// 381-390. +// +// The main entry points is annkSearch() which sets things up and +// then call the recursive routine ann_search(). This is a recursive +// routine which performs the processing for one node in the kd-tree. +// There are two versions of this virtual procedure, one for splitting +// nodes and one for leaves. When a splitting node is visited, we +// determine which child to visit first (the closer one), and visit +// the other child on return. When a leaf is visited, we compute +// the distances to the points in the buckets, and update information +// on the closest points. +// +// Some trickery is used to incrementally update the distance from +// a kd-tree rectangle to the query point. This comes about from +// the fact that which each successive split, only one component +// (along the dimension that is split) of the squared distance to +// the child rectangle is different from the squared distance to +// the parent rectangle. +//---------------------------------------------------------------------- + +//---------------------------------------------------------------------- +// To keep argument lists short, a number of global variables +// are maintained which are common to all the recursive calls. +// These are given below. +//---------------------------------------------------------------------- + +int ANNkdDim; // dimension of space +ANNpoint ANNkdQ; // query point +double ANNkdMaxErr; // max tolerable squared error +ANNpointArray ANNkdPts; // the points +ANNmin_k *ANNkdPointMK; // set of k closest points + +//---------------------------------------------------------------------- +// annkSearch - search for the k nearest neighbors +//---------------------------------------------------------------------- + +void ANNkd_tree::annkSearch( + ANNpoint q, // the query point + int k, // number of near neighbors to return + ANNidxArray nn_idx, // nearest neighbor indices (returned) + ANNdistArray dd, // the approximate nearest neighbor + double eps) // the error bound +{ + + ANNkdDim = dim; // copy arguments to static equivs + ANNkdQ = q; + ANNkdPts = pts; + ANNptsVisited = 0; // initialize count of points visited + + if (k > n_pts) { // too many near neighbors? + annError("Requesting more near neighbors than data points", ANNabort); + } + + ANNkdMaxErr = ANN_POW(1.0 + eps); + ANN_FLOP(2) // increment floating op count + + ANNkdPointMK = new ANNmin_k(k); // create set for closest k points + // search starting at the root + root->ann_search(annBoxDistance(q, bnd_box_lo, bnd_box_hi, dim)); + + for (int i = 0; i < k; i++) { // extract the k-th closest points + dd[i] = ANNkdPointMK->ith_smallest_key(i); + nn_idx[i] = ANNkdPointMK->ith_smallest_info(i); + } + delete ANNkdPointMK; // deallocate closest point set +} + +//---------------------------------------------------------------------- +// kd_split::ann_search - search a splitting node +//---------------------------------------------------------------------- + +void ANNkd_split::ann_search(ANNdist box_dist) +{ + // check dist calc term condition + if (ANNmaxPtsVisited != 0 && ANNptsVisited > ANNmaxPtsVisited) return; + + // distance to cutting plane + ANNcoord cut_diff = ANNkdQ[cut_dim] - cut_val; + + if (cut_diff < 0) { // left of cutting plane + child[ANN_LO]->ann_search(box_dist);// visit closer child first + + ANNcoord box_diff = cd_bnds[ANN_LO] - ANNkdQ[cut_dim]; + if (box_diff < 0) // within bounds - ignore + box_diff = 0; + // distance to further box + box_dist = (ANNdist) ANN_SUM(box_dist, + ANN_DIFF(ANN_POW(box_diff), ANN_POW(cut_diff))); + + // visit further child if close enough + if (box_dist * ANNkdMaxErr < ANNkdPointMK->max_key()) + child[ANN_HI]->ann_search(box_dist); + + } + else { // right of cutting plane + child[ANN_HI]->ann_search(box_dist);// visit closer child first + + ANNcoord box_diff = ANNkdQ[cut_dim] - cd_bnds[ANN_HI]; + if (box_diff < 0) // within bounds - ignore + box_diff = 0; + // distance to further box + box_dist = (ANNdist) ANN_SUM(box_dist, + ANN_DIFF(ANN_POW(box_diff), ANN_POW(cut_diff))); + + // visit further child if close enough + if (box_dist * ANNkdMaxErr < ANNkdPointMK->max_key()) + child[ANN_LO]->ann_search(box_dist); + + } + ANN_FLOP(10) // increment floating ops + ANN_SPL(1) // one more splitting node visited +} + +//---------------------------------------------------------------------- +// kd_leaf::ann_search - search points in a leaf node +// Note: The unreadability of this code is the result of +// some fine tuning to replace indexing by pointer operations. +//---------------------------------------------------------------------- + +void ANNkd_leaf::ann_search(ANNdist box_dist) +{ + register ANNdist dist; // distance to data point + register ANNcoord* pp; // data coordinate pointer + register ANNcoord* qq; // query coordinate pointer + register ANNdist min_dist; // distance to k-th closest point + register ANNcoord t; + register int d; + + min_dist = ANNkdPointMK->max_key(); // k-th smallest distance so far + + for (int i = 0; i < n_pts; i++) { // check points in bucket + + pp = ANNkdPts[bkt[i]]; // first coord of next data point + qq = ANNkdQ; // first coord of query point + dist = 0; + + for(d = 0; d < ANNkdDim; d++) { + ANN_COORD(1) // one more coordinate hit + ANN_FLOP(4) // increment floating ops + + t = *(qq++) - *(pp++); // compute length and adv coordinate + // exceeds dist to k-th smallest? + if( (dist = ANN_SUM(dist, ANN_POW(t))) > min_dist) { + break; + } + } + + if (d >= ANNkdDim && // among the k best? + (ANN_ALLOW_SELF_MATCH || dist!=0)) { // and no self-match problem + // add it to the list + ANNkdPointMK->insert(dist, bkt[i]); + min_dist = ANNkdPointMK->max_key(); + } + } + ANN_LEAF(1) // one more leaf node visited + ANN_PTS(n_pts) // increment points visited + ANNptsVisited += n_pts; // increment number of points visited +} diff --git a/contrib/ANN/src/kd_search.h b/contrib/ANN/src/kd_search.h new file mode 100644 index 0000000000..1adcdd4008 --- /dev/null +++ b/contrib/ANN/src/kd_search.h @@ -0,0 +1,48 @@ +//---------------------------------------------------------------------- +// File: kd_search.h +// Programmer: Sunil Arya and David Mount +// Description: Standard kd-tree search +// Last modified: 01/04/05 (Version 1.0) +//---------------------------------------------------------------------- +// Copyright (c) 1997-2005 University of Maryland and Sunil Arya and +// David Mount. All Rights Reserved. +// +// This software and related documentation is part of the Approximate +// Nearest Neighbor Library (ANN). This software is provided under +// the provisions of the Lesser GNU Public License (LGPL). See the +// file ../ReadMe.txt for further information. +// +// The University of Maryland (U.M.) and the authors make no +// representations about the suitability or fitness of this software for +// any purpose. It is provided "as is" without express or implied +// warranty. +//---------------------------------------------------------------------- +// History: +// Revision 0.1 03/04/98 +// Initial release +//---------------------------------------------------------------------- + +#ifndef ANN_kd_search_H +#define ANN_kd_search_H + +#include "kd_tree.h" // kd-tree declarations +#include "kd_util.h" // kd-tree utilities +#include "pr_queue_k.h" // k-element priority queue + +#include <ANN/ANNperf.h> // performance evaluation + +//---------------------------------------------------------------------- +// More global variables +// These are active for the life of each call to annkSearch(). They +// are set to save the number of variables that need to be passed +// among the various search procedures. +//---------------------------------------------------------------------- + +extern int ANNkdDim; // dimension of space (static copy) +extern ANNpoint ANNkdQ; // query point (static copy) +extern double ANNkdMaxErr; // max tolerable squared error +extern ANNpointArray ANNkdPts; // the points (static copy) +extern ANNmin_k *ANNkdPointMK; // set of k closest points +extern int ANNptsVisited; // number of points visited + +#endif diff --git a/contrib/ANN/src/kd_split.cpp b/contrib/ANN/src/kd_split.cpp new file mode 100644 index 0000000000..8d5b3d8735 --- /dev/null +++ b/contrib/ANN/src/kd_split.cpp @@ -0,0 +1,428 @@ +//---------------------------------------------------------------------- +// File: kd_split.cpp +// Programmer: Sunil Arya and David Mount +// Description: Methods for splitting kd-trees +// Last modified: 01/04/05 (Version 1.0) +//---------------------------------------------------------------------- +// Copyright (c) 1997-2005 University of Maryland and Sunil Arya and +// David Mount. All Rights Reserved. +// +// This software and related documentation is part of the Approximate +// Nearest Neighbor Library (ANN). This software is provided under +// the provisions of the Lesser GNU Public License (LGPL). See the +// file ../ReadMe.txt for further information. +// +// The University of Maryland (U.M.) and the authors make no +// representations about the suitability or fitness of this software for +// any purpose. It is provided "as is" without express or implied +// warranty. +//---------------------------------------------------------------------- +// History: +// Revision 0.1 03/04/98 +// Initial release +// Revision 1.0 04/01/05 +//---------------------------------------------------------------------- + +#include "kd_tree.h" // kd-tree definitions +#include "kd_util.h" // kd-tree utilities +#include "kd_split.h" // splitting functions + +//---------------------------------------------------------------------- +// Constants +//---------------------------------------------------------------------- + +const double ERR = 0.001; // a small value +const double FS_ASPECT_RATIO = 3.0; // maximum allowed aspect ratio + // in fair split. Must be >= 2. + +//---------------------------------------------------------------------- +// kd_split - Bentley's standard splitting routine for kd-trees +// Find the dimension of the greatest spread, and split +// just before the median point along this dimension. +//---------------------------------------------------------------------- + +void kd_split( + ANNpointArray pa, // point array (permuted on return) + ANNidxArray pidx, // point indices + const ANNorthRect &bnds, // bounding rectangle for cell + int n, // number of points + int dim, // dimension of space + int &cut_dim, // cutting dimension (returned) + ANNcoord &cut_val, // cutting value (returned) + int &n_lo) // num of points on low side (returned) +{ + // find dimension of maximum spread + cut_dim = annMaxSpread(pa, pidx, n, dim); + n_lo = n/2; // median rank + // split about median + annMedianSplit(pa, pidx, n, cut_dim, cut_val, n_lo); +} + +//---------------------------------------------------------------------- +// midpt_split - midpoint splitting rule for box-decomposition trees +// +// This is the simplest splitting rule that guarantees boxes +// of bounded aspect ratio. It simply cuts the box with the +// longest side through its midpoint. If there are ties, it +// selects the dimension with the maximum point spread. +// +// WARNING: This routine (while simple) doesn't seem to work +// well in practice in high dimensions, because it tends to +// generate a large number of trivial and/or unbalanced splits. +// Either kd_split(), sl_midpt_split(), or fair_split() are +// recommended, instead. +//---------------------------------------------------------------------- + +void midpt_split( + ANNpointArray pa, // point array + ANNidxArray pidx, // point indices (permuted on return) + const ANNorthRect &bnds, // bounding rectangle for cell + int n, // number of points + int dim, // dimension of space + int &cut_dim, // cutting dimension (returned) + ANNcoord &cut_val, // cutting value (returned) + int &n_lo) // num of points on low side (returned) +{ + int d; + + ANNcoord max_length = bnds.hi[0] - bnds.lo[0]; + for (d = 1; d < dim; d++) { // find length of longest box side + ANNcoord length = bnds.hi[d] - bnds.lo[d]; + if (length > max_length) { + max_length = length; + } + } + ANNcoord max_spread = -1; // find long side with most spread + for (d = 0; d < dim; d++) { + // is it among longest? + if (double(bnds.hi[d] - bnds.lo[d]) >= (1-ERR)*max_length) { + // compute its spread + ANNcoord spr = annSpread(pa, pidx, n, d); + if (spr > max_spread) { // is it max so far? + max_spread = spr; + cut_dim = d; + } + } + } + // split along cut_dim at midpoint + cut_val = (bnds.lo[cut_dim] + bnds.hi[cut_dim]) / 2; + // permute points accordingly + int br1, br2; + annPlaneSplit(pa, pidx, n, cut_dim, cut_val, br1, br2); + //------------------------------------------------------------------ + // On return: pa[0..br1-1] < cut_val + // pa[br1..br2-1] == cut_val + // pa[br2..n-1] > cut_val + // + // We can set n_lo to any value in the range [br1..br2]. + // We choose split so that points are most evenly divided. + //------------------------------------------------------------------ + if (br1 > n/2) n_lo = br1; + else if (br2 < n/2) n_lo = br2; + else n_lo = n/2; +} + +//---------------------------------------------------------------------- +// sl_midpt_split - sliding midpoint splitting rule +// +// This is a modification of midpt_split, which has the nonsensical +// name "sliding midpoint". The idea is that we try to use the +// midpoint rule, by bisecting the longest side. If there are +// ties, the dimension with the maximum spread is selected. If, +// however, the midpoint split produces a trivial split (no points +// on one side of the splitting plane) then we slide the splitting +// (maintaining its orientation) until it produces a nontrivial +// split. For example, if the splitting plane is along the x-axis, +// and all the data points have x-coordinate less than the x-bisector, +// then the split is taken along the maximum x-coordinate of the +// data points. +// +// Intuitively, this rule cannot generate trivial splits, and +// hence avoids midpt_split's tendency to produce trees with +// a very large number of nodes. +// +//---------------------------------------------------------------------- + +void sl_midpt_split( + ANNpointArray pa, // point array + ANNidxArray pidx, // point indices (permuted on return) + const ANNorthRect &bnds, // bounding rectangle for cell + int n, // number of points + int dim, // dimension of space + int &cut_dim, // cutting dimension (returned) + ANNcoord &cut_val, // cutting value (returned) + int &n_lo) // num of points on low side (returned) +{ + int d; + + ANNcoord max_length = bnds.hi[0] - bnds.lo[0]; + for (d = 1; d < dim; d++) { // find length of longest box side + ANNcoord length = bnds.hi[d] - bnds.lo[d]; + if (length > max_length) { + max_length = length; + } + } + ANNcoord max_spread = -1; // find long side with most spread + for (d = 0; d < dim; d++) { + // is it among longest? + if ((bnds.hi[d] - bnds.lo[d]) >= (1-ERR)*max_length) { + // compute its spread + ANNcoord spr = annSpread(pa, pidx, n, d); + if (spr > max_spread) { // is it max so far? + max_spread = spr; + cut_dim = d; + } + } + } + // ideal split at midpoint + ANNcoord ideal_cut_val = (bnds.lo[cut_dim] + bnds.hi[cut_dim])/2; + + ANNcoord min, max; + annMinMax(pa, pidx, n, cut_dim, min, max); // find min/max coordinates + + if (ideal_cut_val < min) // slide to min or max as needed + cut_val = min; + else if (ideal_cut_val > max) + cut_val = max; + else + cut_val = ideal_cut_val; + + // permute points accordingly + int br1, br2; + annPlaneSplit(pa, pidx, n, cut_dim, cut_val, br1, br2); + //------------------------------------------------------------------ + // On return: pa[0..br1-1] < cut_val + // pa[br1..br2-1] == cut_val + // pa[br2..n-1] > cut_val + // + // We can set n_lo to any value in the range [br1..br2] to satisfy + // the exit conditions of the procedure. + // + // if ideal_cut_val < min (implying br2 >= 1), + // then we select n_lo = 1 (so there is one point on left) and + // if ideal_cut_val > max (implying br1 <= n-1), + // then we select n_lo = n-1 (so there is one point on right). + // Otherwise, we select n_lo as close to n/2 as possible within + // [br1..br2]. + //------------------------------------------------------------------ + if (ideal_cut_val < min) n_lo = 1; + else if (ideal_cut_val > max) n_lo = n-1; + else if (br1 > n/2) n_lo = br1; + else if (br2 < n/2) n_lo = br2; + else n_lo = n/2; +} + +//---------------------------------------------------------------------- +// fair_split - fair-split splitting rule +// +// This is a compromise between the kd-tree splitting rule (which +// always splits data points at their median) and the midpoint +// splitting rule (which always splits a box through its center. +// The goal of this procedure is to achieve both nicely balanced +// splits, and boxes of bounded aspect ratio. +// +// A constant FS_ASPECT_RATIO is defined. Given a box, those sides +// which can be split so that the ratio of the longest to shortest +// side does not exceed ASPECT_RATIO are identified. Among these +// sides, we select the one in which the points have the largest +// spread. We then split the points in a manner which most evenly +// distributes the points on either side of the splitting plane, +// subject to maintaining the bound on the ratio of long to short +// sides. To determine that the aspect ratio will be preserved, +// we determine the longest side (other than this side), and +// determine how narrowly we can cut this side, without causing the +// aspect ratio bound to be exceeded (small_piece). +// +// This procedure is more robust than either kd_split or midpt_split, +// but is more complicated as well. When point distribution is +// extremely skewed, this degenerates to midpt_split (actually +// 1/3 point split), and when the points are most evenly distributed, +// this degenerates to kd-split. +//---------------------------------------------------------------------- + +void fair_split( + ANNpointArray pa, // point array + ANNidxArray pidx, // point indices (permuted on return) + const ANNorthRect &bnds, // bounding rectangle for cell + int n, // number of points + int dim, // dimension of space + int &cut_dim, // cutting dimension (returned) + ANNcoord &cut_val, // cutting value (returned) + int &n_lo) // num of points on low side (returned) +{ + int d; + ANNcoord max_length = bnds.hi[0] - bnds.lo[0]; + cut_dim = 0; + for (d = 1; d < dim; d++) { // find length of longest box side + ANNcoord length = bnds.hi[d] - bnds.lo[d]; + if (length > max_length) { + max_length = length; + cut_dim = d; + } + } + + ANNcoord max_spread = 0; // find legal cut with max spread + cut_dim = 0; + for (d = 0; d < dim; d++) { + ANNcoord length = bnds.hi[d] - bnds.lo[d]; + // is this side midpoint splitable + // without violating aspect ratio? + if (((double) max_length)*2.0/((double) length) <= FS_ASPECT_RATIO) { + // compute spread along this dim + ANNcoord spr = annSpread(pa, pidx, n, d); + if (spr > max_spread) { // best spread so far + max_spread = spr; + cut_dim = d; // this is dimension to cut + } + } + } + + max_length = 0; // find longest side other than cut_dim + for (d = 0; d < dim; d++) { + ANNcoord length = bnds.hi[d] - bnds.lo[d]; + if (d != cut_dim && length > max_length) + max_length = length; + } + // consider most extreme splits + ANNcoord small_piece = max_length / FS_ASPECT_RATIO; + ANNcoord lo_cut = bnds.lo[cut_dim] + small_piece;// lowest legal cut + ANNcoord hi_cut = bnds.hi[cut_dim] - small_piece;// highest legal cut + + int br1, br2; + // is median below lo_cut ? + if (annSplitBalance(pa, pidx, n, cut_dim, lo_cut) >= 0) { + cut_val = lo_cut; // cut at lo_cut + annPlaneSplit(pa, pidx, n, cut_dim, cut_val, br1, br2); + n_lo = br1; + } + // is median above hi_cut? + else if (annSplitBalance(pa, pidx, n, cut_dim, hi_cut) <= 0) { + cut_val = hi_cut; // cut at hi_cut + annPlaneSplit(pa, pidx, n, cut_dim, cut_val, br1, br2); + n_lo = br2; + } + else { // median cut preserves asp ratio + n_lo = n/2; // split about median + annMedianSplit(pa, pidx, n, cut_dim, cut_val, n_lo); + } +} + +//---------------------------------------------------------------------- +// sl_fair_split - sliding fair split splitting rule +// +// Sliding fair split is a splitting rule that combines the +// strengths of both fair split with sliding midpoint split. +// Fair split tends to produce balanced splits when the points +// are roughly uniformly distributed, but it can produce many +// trivial splits when points are highly clustered. Sliding +// midpoint never produces trivial splits, and shrinks boxes +// nicely if points are highly clustered, but it may produce +// rather unbalanced splits when points are unclustered but not +// quite uniform. +// +// Sliding fair split is based on the theory that there are two +// types of splits that are "good": balanced splits that produce +// fat boxes, and unbalanced splits provided the cell with fewer +// points is fat. +// +// This splitting rule operates by first computing the longest +// side of the current bounding box. Then it asks which sides +// could be split (at the midpoint) and still satisfy the aspect +// ratio bound with respect to this side. Among these, it selects +// the side with the largest spread (as fair split would). It +// then considers the most extreme cuts that would be allowed by +// the aspect ratio bound. This is done by dividing the longest +// side of the box by the aspect ratio bound. If the median cut +// lies between these extreme cuts, then we use the median cut. +// If not, then consider the extreme cut that is closer to the +// median. If all the points lie to one side of this cut, then +// we slide the cut until it hits the first point. This may +// violate the aspect ratio bound, but will never generate empty +// cells. However the sibling of every such skinny cell is fat, +// and hence packing arguments still apply. +// +//---------------------------------------------------------------------- + +void sl_fair_split( + ANNpointArray pa, // point array + ANNidxArray pidx, // point indices (permuted on return) + const ANNorthRect &bnds, // bounding rectangle for cell + int n, // number of points + int dim, // dimension of space + int &cut_dim, // cutting dimension (returned) + ANNcoord &cut_val, // cutting value (returned) + int &n_lo) // num of points on low side (returned) +{ + int d; + ANNcoord min, max; // min/max coordinates + int br1, br2; // split break points + + ANNcoord max_length = bnds.hi[0] - bnds.lo[0]; + cut_dim = 0; + for (d = 1; d < dim; d++) { // find length of longest box side + ANNcoord length = bnds.hi[d] - bnds.lo[d]; + if (length > max_length) { + max_length = length; + cut_dim = d; + } + } + + ANNcoord max_spread = 0; // find legal cut with max spread + cut_dim = 0; + for (d = 0; d < dim; d++) { + ANNcoord length = bnds.hi[d] - bnds.lo[d]; + // is this side midpoint splitable + // without violating aspect ratio? + if (((double) max_length)*2.0/((double) length) <= FS_ASPECT_RATIO) { + // compute spread along this dim + ANNcoord spr = annSpread(pa, pidx, n, d); + if (spr > max_spread) { // best spread so far + max_spread = spr; + cut_dim = d; // this is dimension to cut + } + } + } + + max_length = 0; // find longest side other than cut_dim + for (d = 0; d < dim; d++) { + ANNcoord length = bnds.hi[d] - bnds.lo[d]; + if (d != cut_dim && length > max_length) + max_length = length; + } + // consider most extreme splits + ANNcoord small_piece = max_length / FS_ASPECT_RATIO; + ANNcoord lo_cut = bnds.lo[cut_dim] + small_piece;// lowest legal cut + ANNcoord hi_cut = bnds.hi[cut_dim] - small_piece;// highest legal cut + // find min and max along cut_dim + annMinMax(pa, pidx, n, cut_dim, min, max); + // is median below lo_cut? + if (annSplitBalance(pa, pidx, n, cut_dim, lo_cut) >= 0) { + if (max > lo_cut) { // are any points above lo_cut? + cut_val = lo_cut; // cut at lo_cut + annPlaneSplit(pa, pidx, n, cut_dim, cut_val, br1, br2); + n_lo = br1; // balance if there are ties + } + else { // all points below lo_cut + cut_val = max; // cut at max value + annPlaneSplit(pa, pidx, n, cut_dim, cut_val, br1, br2); + n_lo = n-1; + } + } + // is median above hi_cut? + else if (annSplitBalance(pa, pidx, n, cut_dim, hi_cut) <= 0) { + if (min < hi_cut) { // are any points below hi_cut? + cut_val = hi_cut; // cut at hi_cut + annPlaneSplit(pa, pidx, n, cut_dim, cut_val, br1, br2); + n_lo = br2; // balance if there are ties + } + else { // all points above hi_cut + cut_val = min; // cut at min value + annPlaneSplit(pa, pidx, n, cut_dim, cut_val, br1, br2); + n_lo = 1; + } + } + else { // median cut is good enough + n_lo = n/2; // split about median + annMedianSplit(pa, pidx, n, cut_dim, cut_val, n_lo); + } +} diff --git a/contrib/ANN/src/kd_split.h b/contrib/ANN/src/kd_split.h new file mode 100644 index 0000000000..ef80461ead --- /dev/null +++ b/contrib/ANN/src/kd_split.h @@ -0,0 +1,85 @@ +//---------------------------------------------------------------------- +// File: kd_split.h +// Programmer: Sunil Arya and David Mount +// Description: Methods for splitting kd-trees +// Last modified: 01/04/05 (Version 1.0) +//---------------------------------------------------------------------- +// Copyright (c) 1997-2005 University of Maryland and Sunil Arya and +// David Mount. All Rights Reserved. +// +// This software and related documentation is part of the Approximate +// Nearest Neighbor Library (ANN). This software is provided under +// the provisions of the Lesser GNU Public License (LGPL). See the +// file ../ReadMe.txt for further information. +// +// The University of Maryland (U.M.) and the authors make no +// representations about the suitability or fitness of this software for +// any purpose. It is provided "as is" without express or implied +// warranty. +//---------------------------------------------------------------------- +// History: +// Revision 0.1 03/04/98 +// Initial release +//---------------------------------------------------------------------- + +#ifndef ANN_KD_SPLIT_H +#define ANN_KD_SPLIT_H + +#include "kd_tree.h" // kd-tree definitions + +//---------------------------------------------------------------------- +// External entry points +// These are all splitting procedures for kd-trees. +//---------------------------------------------------------------------- + +void kd_split( // standard (optimized) kd-splitter + ANNpointArray pa, // point array (unaltered) + ANNidxArray pidx, // point indices (permuted on return) + const ANNorthRect &bnds, // bounding rectangle for cell + int n, // number of points + int dim, // dimension of space + int &cut_dim, // cutting dimension (returned) + ANNcoord &cut_val, // cutting value (returned) + int &n_lo); // num of points on low side (returned) + +void midpt_split( // midpoint kd-splitter + ANNpointArray pa, // point array (unaltered) + ANNidxArray pidx, // point indices (permuted on return) + const ANNorthRect &bnds, // bounding rectangle for cell + int n, // number of points + int dim, // dimension of space + int &cut_dim, // cutting dimension (returned) + ANNcoord &cut_val, // cutting value (returned) + int &n_lo); // num of points on low side (returned) + +void sl_midpt_split( // sliding midpoint kd-splitter + ANNpointArray pa, // point array (unaltered) + ANNidxArray pidx, // point indices (permuted on return) + const ANNorthRect &bnds, // bounding rectangle for cell + int n, // number of points + int dim, // dimension of space + int &cut_dim, // cutting dimension (returned) + ANNcoord &cut_val, // cutting value (returned) + int &n_lo); // num of points on low side (returned) + +void fair_split( // fair-split kd-splitter + ANNpointArray pa, // point array (unaltered) + ANNidxArray pidx, // point indices (permuted on return) + const ANNorthRect &bnds, // bounding rectangle for cell + int n, // number of points + int dim, // dimension of space + int &cut_dim, // cutting dimension (returned) + ANNcoord &cut_val, // cutting value (returned) + int &n_lo); // num of points on low side (returned) + +void sl_fair_split( // sliding fair-split kd-splitter + ANNpointArray pa, // point array (unaltered) + ANNidxArray pidx, // point indices (permuted on return) + const ANNorthRect &bnds, // bounding rectangle for cell + int n, // number of points + int dim, // dimension of space + int &cut_dim, // cutting dimension (returned) + ANNcoord &cut_val, // cutting value (returned) + int &n_lo); // num of points on low side (returned) + +#endif diff --git a/contrib/ANN/src/kd_tree.cpp b/contrib/ANN/src/kd_tree.cpp new file mode 100644 index 0000000000..2828fd2cfd --- /dev/null +++ b/contrib/ANN/src/kd_tree.cpp @@ -0,0 +1,405 @@ +//---------------------------------------------------------------------- +// File: kd_tree.cpp +// Programmer: Sunil Arya and David Mount +// Description: Basic methods for kd-trees. +// Last modified: 01/04/05 (Version 1.0) +//---------------------------------------------------------------------- +// Copyright (c) 1997-2005 University of Maryland and Sunil Arya and +// David Mount. All Rights Reserved. +// +// This software and related documentation is part of the Approximate +// Nearest Neighbor Library (ANN). This software is provided under +// the provisions of the Lesser GNU Public License (LGPL). See the +// file ../ReadMe.txt for further information. +// +// The University of Maryland (U.M.) and the authors make no +// representations about the suitability or fitness of this software for +// any purpose. It is provided "as is" without express or implied +// warranty. +//---------------------------------------------------------------------- +// History: +// Revision 0.1 03/04/98 +// Initial release +// Revision 1.0 04/01/05 +// Increased aspect ratio bound (ANN_AR_TOOBIG) from 100 to 1000. +// Fixed leaf counts to count trivial leaves. +// Added optional pa, pi arguments to Skeleton kd_tree constructor +// for use in load constructor. +// Added annClose() to eliminate KD_TRIVIAL memory leak. +//---------------------------------------------------------------------- + +#include "kd_tree.h" // kd-tree declarations +#include "kd_split.h" // kd-tree splitting rules +#include "kd_util.h" // kd-tree utilities +#include <ANN/ANNperf.h> // performance evaluation + +//---------------------------------------------------------------------- +// Global data +// +// For some splitting rules, especially with small bucket sizes, +// it is possible to generate a large number of empty leaf nodes. +// To save storage we allocate a single trivial leaf node which +// contains no points. For messy coding reasons it is convenient +// to have it reference a trivial point index. +// +// KD_TRIVIAL is allocated when the first kd-tree is created. It +// must *never* deallocated (since it may be shared by more than +// one tree). +//---------------------------------------------------------------------- +static int IDX_TRIVIAL[] = {0}; // trivial point index +ANNkd_leaf *KD_TRIVIAL = NULL; // trivial leaf node + +//---------------------------------------------------------------------- +// Printing the kd-tree +// These routines print a kd-tree in reverse inorder (high then +// root then low). (This is so that if you look at the output +// from the right side it appear from left to right in standard +// inorder.) When outputting leaves we output only the point +// indices rather than the point coordinates. There is an option +// to print the point coordinates separately. +// +// The tree printing routine calls the printing routines on the +// individual nodes of the tree, passing in the level or depth +// in the tree. The level in the tree is used to print indentation +// for readability. +//---------------------------------------------------------------------- + +void ANNkd_split::print( // print splitting node + int level, // depth of node in tree + ostream &out) // output stream +{ + child[ANN_HI]->print(level+1, out); // print high child + out << " "; + for (int i = 0; i < level; i++) // print indentation + out << ".."; + out << "Split cd=" << cut_dim << " cv=" << cut_val; + out << " lbnd=" << cd_bnds[ANN_LO]; + out << " hbnd=" << cd_bnds[ANN_HI]; + out << "\n"; + child[ANN_LO]->print(level+1, out); // print low child +} + +void ANNkd_leaf::print( // print leaf node + int level, // depth of node in tree + ostream &out) // output stream +{ + + out << " "; + for (int i = 0; i < level; i++) // print indentation + out << ".."; + + if (this == KD_TRIVIAL) { // canonical trivial leaf node + out << "Leaf (trivial)\n"; + } + else{ + out << "Leaf n=" << n_pts << " <"; + for (int j = 0; j < n_pts; j++) { + out << bkt[j]; + if (j < n_pts-1) out << ","; + } + out << ">\n"; + } +} + +void ANNkd_tree::Print( // print entire tree + ANNbool with_pts, // print points as well? + ostream &out) // output stream +{ + out << "ANN Version " << ANNversion << "\n"; + if (with_pts) { // print point coordinates + out << " Points:\n"; + for (int i = 0; i < n_pts; i++) { + out << "\t" << i << ": "; + annPrintPt(pts[i], dim, out); + out << "\n"; + } + } + if (root == NULL) // empty tree? + out << " Null tree.\n"; + else { + root->print(0, out); // invoke printing at root + } +} + +//---------------------------------------------------------------------- +// kd_tree statistics (for performance evaluation) +// This routine compute various statistics information for +// a kd-tree. It is used by the implementors for performance +// evaluation of the data structure. +//---------------------------------------------------------------------- + +#define MAX(a,b) ((a) > (b) ? (a) : (b)) + +void ANNkdStats::merge(const ANNkdStats &st) // merge stats from child +{ + n_lf += st.n_lf; n_tl += st.n_tl; + n_spl += st.n_spl; n_shr += st.n_shr; + depth = MAX(depth, st.depth); + sum_ar += st.sum_ar; +} + +//---------------------------------------------------------------------- +// Update statistics for nodes +//---------------------------------------------------------------------- + +const double ANN_AR_TOOBIG = 1000; // too big an aspect ratio + +void ANNkd_leaf::getStats( // get subtree statistics + int dim, // dimension of space + ANNkdStats &st, // stats (modified) + ANNorthRect &bnd_box) // bounding box +{ + st.reset(); + st.n_lf = 1; // count this leaf + if (this == KD_TRIVIAL) st.n_tl = 1; // count trivial leaf + double ar = annAspectRatio(dim, bnd_box); // aspect ratio of leaf + // incr sum (ignore outliers) + st.sum_ar += float(ar < ANN_AR_TOOBIG ? ar : ANN_AR_TOOBIG); +} + +void ANNkd_split::getStats( // get subtree statistics + int dim, // dimension of space + ANNkdStats &st, // stats (modified) + ANNorthRect &bnd_box) // bounding box +{ + ANNkdStats ch_stats; // stats for children + // get stats for low child + ANNcoord hv = bnd_box.hi[cut_dim]; // save box bounds + bnd_box.hi[cut_dim] = cut_val; // upper bound for low child + ch_stats.reset(); // reset + child[ANN_LO]->getStats(dim, ch_stats, bnd_box); + st.merge(ch_stats); // merge them + bnd_box.hi[cut_dim] = hv; // restore bound + // get stats for high child + ANNcoord lv = bnd_box.lo[cut_dim]; // save box bounds + bnd_box.lo[cut_dim] = cut_val; // lower bound for high child + ch_stats.reset(); // reset + child[ANN_HI]->getStats(dim, ch_stats, bnd_box); + st.merge(ch_stats); // merge them + bnd_box.lo[cut_dim] = lv; // restore bound + + st.depth++; // increment depth + st.n_spl++; // increment number of splits +} + +//---------------------------------------------------------------------- +// getStats +// Collects a number of statistics related to kd_tree or +// bd_tree. +//---------------------------------------------------------------------- + +void ANNkd_tree::getStats( // get tree statistics + ANNkdStats &st) // stats (modified) +{ + st.reset(dim, n_pts, bkt_size); // reset stats + // create bounding box + ANNorthRect bnd_box(dim, bnd_box_lo, bnd_box_hi); + if (root != NULL) { // if nonempty tree + root->getStats(dim, st, bnd_box); // get statistics + st.avg_ar = st.sum_ar / st.n_lf; // average leaf asp ratio + } +} + +//---------------------------------------------------------------------- +// kd_tree destructor +// The destructor just frees the various elements that were +// allocated in the construction process. +//---------------------------------------------------------------------- + +ANNkd_tree::~ANNkd_tree() // tree destructor +{ + if (root != NULL) delete root; + if (pidx != NULL) delete [] pidx; + if (bnd_box_lo != NULL) annDeallocPt(bnd_box_lo); + if (bnd_box_hi != NULL) annDeallocPt(bnd_box_hi); +} + +//---------------------------------------------------------------------- +// This is called with all use of ANN is finished. It eliminates the +// minor memory leak caused by the allocation of KD_TRIVIAL. +//---------------------------------------------------------------------- +void annClose() // close use of ANN +{ + if (KD_TRIVIAL != NULL) { + delete KD_TRIVIAL; + KD_TRIVIAL = NULL; + } +} + +//---------------------------------------------------------------------- +// kd_tree constructors +// There is a skeleton kd-tree constructor which sets up a +// trivial empty tree. The last optional argument allows +// the routine to be passed a point index array which is +// assumed to be of the proper size (n). Otherwise, one is +// allocated and initialized to the identity. Warning: In +// either case the destructor will deallocate this array. +// +// As a kludge, we need to allocate KD_TRIVIAL if one has not +// already been allocated. (This is because I'm too dumb to +// figure out how to cause a pointer to be allocated at load +// time.) +//---------------------------------------------------------------------- + +void ANNkd_tree::SkeletonTree( // construct skeleton tree + int n, // number of points + int dd, // dimension + int bs, // bucket size + ANNpointArray pa, // point array + ANNidxArray pi) // point indices +{ + dim = dd; // initialize basic elements + n_pts = n; + bkt_size = bs; + pts = pa; // initialize points array + + root = NULL; // no associated tree yet + + if (pi == NULL) { // point indices provided? + pidx = new ANNidx[n]; // no, allocate space for point indices + for (int i = 0; i < n; i++) { + pidx[i] = i; // initially identity + } + } + else { + pidx = pi; // yes, use them + } + + bnd_box_lo = bnd_box_hi = NULL; // bounding box is nonexistent + if (KD_TRIVIAL == NULL) // no trivial leaf node yet? + KD_TRIVIAL = new ANNkd_leaf(0, IDX_TRIVIAL); // allocate it +} + +ANNkd_tree::ANNkd_tree( // basic constructor + int n, // number of points + int dd, // dimension + int bs) // bucket size +{ SkeletonTree(n, dd, bs); } // construct skeleton tree + +//---------------------------------------------------------------------- +// rkd_tree - recursive procedure to build a kd-tree +// +// Builds a kd-tree for points in pa as indexed through the +// array pidx[0..n-1] (typically a subarray of the array used in +// the top-level call). This routine permutes the array pidx, +// but does not alter pa[]. +// +// The construction is based on a standard algorithm for constructing +// the kd-tree (see Friedman, Bentley, and Finkel, ``An algorithm for +// finding best matches in logarithmic expected time,'' ACM Transactions +// on Mathematical Software, 3(3):209-226, 1977). The procedure +// operates by a simple divide-and-conquer strategy, which determines +// an appropriate orthogonal cutting plane (see below), and splits +// the points. When the number of points falls below the bucket size, +// we simply store the points in a leaf node's bucket. +// +// One of the arguments is a pointer to a splitting routine, +// whose prototype is: +// +// void split( +// ANNpointArray pa, // complete point array +// ANNidxArray pidx, // point array (permuted on return) +// ANNorthRect &bnds, // bounds of current cell +// int n, // number of points +// int dim, // dimension of space +// int &cut_dim, // cutting dimension +// ANNcoord &cut_val, // cutting value +// int &n_lo) // no. of points on low side of cut +// +// This procedure selects a cutting dimension and cutting value, +// partitions pa about these values, and returns the number of +// points on the low side of the cut. +//---------------------------------------------------------------------- + +ANNkd_ptr rkd_tree( // recursive construction of kd-tree + ANNpointArray pa, // point array + ANNidxArray pidx, // point indices to store in subtree + int n, // number of points + int dim, // dimension of space + int bsp, // bucket space + ANNorthRect &bnd_box, // bounding box for current node + ANNkd_splitter splitter) // splitting routine +{ + if (n <= bsp) { // n small, make a leaf node + if (n == 0) // empty leaf node + return KD_TRIVIAL; // return (canonical) empty leaf + else // construct the node and return + return new ANNkd_leaf(n, pidx); + } + else { // n large, make a splitting node + int cd; // cutting dimension + ANNcoord cv; // cutting value + int n_lo; // number on low side of cut + ANNkd_node *lo, *hi; // low and high children + + // invoke splitting procedure + (*splitter)(pa, pidx, bnd_box, n, dim, cd, cv, n_lo); + + ANNcoord lv = bnd_box.lo[cd]; // save bounds for cutting dimension + ANNcoord hv = bnd_box.hi[cd]; + + bnd_box.hi[cd] = cv; // modify bounds for left subtree + lo = rkd_tree( // build left subtree + pa, pidx, n_lo, // ...from pidx[0..n_lo-1] + dim, bsp, bnd_box, splitter); + bnd_box.hi[cd] = hv; // restore bounds + + bnd_box.lo[cd] = cv; // modify bounds for right subtree + hi = rkd_tree( // build right subtree + pa, pidx + n_lo, n-n_lo,// ...from pidx[n_lo..n-1] + dim, bsp, bnd_box, splitter); + bnd_box.lo[cd] = lv; // restore bounds + + // create the splitting node + ANNkd_split *ptr = new ANNkd_split(cd, cv, lv, hv, lo, hi); + + return ptr; // return pointer to this node + } +} + +//---------------------------------------------------------------------- +// kd-tree constructor +// This is the main constructor for kd-trees given a set of points. +// It first builds a skeleton tree, then computes the bounding box +// of the data points, and then invokes rkd_tree() to actually +// build the tree, passing it the appropriate splitting routine. +//---------------------------------------------------------------------- + +ANNkd_tree::ANNkd_tree( // construct from point array + ANNpointArray pa, // point array (with at least n pts) + int n, // number of points + int dd, // dimension + int bs, // bucket size + ANNsplitRule split) // splitting method +{ + SkeletonTree(n, dd, bs); // set up the basic stuff + pts = pa; // where the points are + if (n == 0) return; // no points--no sweat + + ANNorthRect bnd_box(dd); // bounding box for points + annEnclRect(pa, pidx, n, dd, bnd_box);// construct bounding rectangle + // copy to tree structure + bnd_box_lo = annCopyPt(dd, bnd_box.lo); + bnd_box_hi = annCopyPt(dd, bnd_box.hi); + + switch (split) { // build by rule + case ANN_KD_STD: // standard kd-splitting rule + root = rkd_tree(pa, pidx, n, dd, bs, bnd_box, kd_split); + break; + case ANN_KD_MIDPT: // midpoint split + root = rkd_tree(pa, pidx, n, dd, bs, bnd_box, midpt_split); + break; + case ANN_KD_FAIR: // fair split + root = rkd_tree(pa, pidx, n, dd, bs, bnd_box, fair_split); + break; + case ANN_KD_SUGGEST: // best (in our opinion) + case ANN_KD_SL_MIDPT: // sliding midpoint split + root = rkd_tree(pa, pidx, n, dd, bs, bnd_box, sl_midpt_split); + break; + case ANN_KD_SL_FAIR: // sliding fair split + root = rkd_tree(pa, pidx, n, dd, bs, bnd_box, sl_fair_split); + break; + default: + annError("Illegal splitting method", ANNabort); + } +} diff --git a/contrib/ANN/src/kd_tree.h b/contrib/ANN/src/kd_tree.h new file mode 100644 index 0000000000..81284b6fff --- /dev/null +++ b/contrib/ANN/src/kd_tree.h @@ -0,0 +1,197 @@ +//---------------------------------------------------------------------- +// File: kd_tree.h +// Programmer: Sunil Arya and David Mount +// Description: Declarations for standard kd-tree routines +// Last modified: 05/03/05 (Version 1.1) +//---------------------------------------------------------------------- +// Copyright (c) 1997-2005 University of Maryland and Sunil Arya and +// David Mount. All Rights Reserved. +// +// This software and related documentation is part of the Approximate +// Nearest Neighbor Library (ANN). This software is provided under +// the provisions of the Lesser GNU Public License (LGPL). See the +// file ../ReadMe.txt for further information. +// +// The University of Maryland (U.M.) and the authors make no +// representations about the suitability or fitness of this software for +// any purpose. It is provided "as is" without express or implied +// warranty. +//---------------------------------------------------------------------- +// History: +// Revision 0.1 03/04/98 +// Initial release +// Revision 1.1 05/03/05 +// Added fixed radius kNN search +//---------------------------------------------------------------------- + +#ifndef ANN_kd_tree_H +#define ANN_kd_tree_H + +#include <ANN/ANNx.h> // all ANN includes + +using namespace std; // make std:: available + +//---------------------------------------------------------------------- +// Generic kd-tree node +// +// Nodes in kd-trees are of two types, splitting nodes which contain +// splitting information (a splitting hyperplane orthogonal to one +// of the coordinate axes) and leaf nodes which contain point +// information (an array of points stored in a bucket). This is +// handled by making a generic class kd_node, which is essentially an +// empty shell, and then deriving the leaf and splitting nodes from +// this. +//---------------------------------------------------------------------- + +class ANNkd_node{ // generic kd-tree node (empty shell) +public: + virtual ~ANNkd_node() {} // virtual distroyer + + virtual void ann_search(ANNdist) = 0; // tree search + virtual void ann_pri_search(ANNdist) = 0; // priority search + virtual void ann_FR_search(ANNdist) = 0; // fixed-radius search + + virtual void getStats( // get tree statistics + int dim, // dimension of space + ANNkdStats &st, // statistics + ANNorthRect &bnd_box) = 0; // bounding box + // print node + virtual void print(int level, ostream &out) = 0; + virtual void dump(ostream &out) = 0; // dump node + + friend class ANNkd_tree; // allow kd-tree to access us +}; + +//---------------------------------------------------------------------- +// kd-splitting function: +// kd_splitter is a pointer to a splitting routine for preprocessing. +// Different splitting procedures result in different strategies +// for building the tree. +//---------------------------------------------------------------------- + +typedef void (*ANNkd_splitter)( // splitting routine for kd-trees + ANNpointArray pa, // point array (unaltered) + ANNidxArray pidx, // point indices (permuted on return) + const ANNorthRect &bnds, // bounding rectangle for cell + int n, // number of points + int dim, // dimension of space + int &cut_dim, // cutting dimension (returned) + ANNcoord &cut_val, // cutting value (returned) + int &n_lo); // num of points on low side (returned) + +//---------------------------------------------------------------------- +// Leaf kd-tree node +// Leaf nodes of the kd-tree store the set of points associated +// with this bucket, stored as an array of point indices. These +// are indices in the array points, which resides with the +// root of the kd-tree. We also store the number of points +// that reside in this bucket. +//---------------------------------------------------------------------- + +class ANNkd_leaf: public ANNkd_node // leaf node for kd-tree +{ + int n_pts; // no. points in bucket + ANNidxArray bkt; // bucket of points +public: + ANNkd_leaf( // constructor + int n, // number of points + ANNidxArray b) // bucket + { + n_pts = n; // number of points in bucket + bkt = b; // the bucket + } + + ~ANNkd_leaf() { } // destructor (none) + + virtual void getStats( // get tree statistics + int dim, // dimension of space + ANNkdStats &st, // statistics + ANNorthRect &bnd_box); // bounding box + virtual void print(int level, ostream &out);// print node + virtual void dump(ostream &out); // dump node + + virtual void ann_search(ANNdist); // standard search + virtual void ann_pri_search(ANNdist); // priority search + virtual void ann_FR_search(ANNdist); // fixed-radius search +}; + +//---------------------------------------------------------------------- +// KD_TRIVIAL is a special pointer to an empty leaf node. Since +// some splitting rules generate many (more than 50%) trivial +// leaves, we use this one shared node to save space. +// +// The pointer is initialized to NULL, but whenever a kd-tree is +// created, we allocate this node, if it has not already been +// allocated. This node is *never* deallocated, so it produces +// a small memory leak. +//---------------------------------------------------------------------- + +extern ANNkd_leaf *KD_TRIVIAL; // trivial (empty) leaf node + +//---------------------------------------------------------------------- +// kd-tree splitting node. +// Splitting nodes contain a cutting dimension and a cutting value. +// These indicate the axis-parellel plane which subdivide the +// box for this node. The extent of the bounding box along the +// cutting dimension is maintained (this is used to speed up point +// to box distance calculations) [we do not store the entire bounding +// box since this may be wasteful of space in high dimensions]. +// We also store pointers to the 2 children. +//---------------------------------------------------------------------- + +class ANNkd_split : public ANNkd_node // splitting node of a kd-tree +{ + int cut_dim; // dim orthogonal to cutting plane + ANNcoord cut_val; // location of cutting plane + ANNcoord cd_bnds[2]; // lower and upper bounds of + // rectangle along cut_dim + ANNkd_ptr child[2]; // left and right children +public: + ANNkd_split( // constructor + int cd, // cutting dimension + ANNcoord cv, // cutting value + ANNcoord lv, ANNcoord hv, // low and high values + ANNkd_ptr lc=NULL, ANNkd_ptr hc=NULL) // children + { + cut_dim = cd; // cutting dimension + cut_val = cv; // cutting value + cd_bnds[ANN_LO] = lv; // lower bound for rectangle + cd_bnds[ANN_HI] = hv; // upper bound for rectangle + child[ANN_LO] = lc; // left child + child[ANN_HI] = hc; // right child + } + + ~ANNkd_split() // destructor + { + if (child[ANN_LO]!= NULL && child[ANN_LO]!= KD_TRIVIAL) + delete child[ANN_LO]; + if (child[ANN_HI]!= NULL && child[ANN_HI]!= KD_TRIVIAL) + delete child[ANN_HI]; + } + + virtual void getStats( // get tree statistics + int dim, // dimension of space + ANNkdStats &st, // statistics + ANNorthRect &bnd_box); // bounding box + virtual void print(int level, ostream &out);// print node + virtual void dump(ostream &out); // dump node + + virtual void ann_search(ANNdist); // standard search + virtual void ann_pri_search(ANNdist); // priority search + virtual void ann_FR_search(ANNdist); // fixed-radius search +}; + +//---------------------------------------------------------------------- +// External entry points +//---------------------------------------------------------------------- + +ANNkd_ptr rkd_tree( // recursive construction of kd-tree + ANNpointArray pa, // point array (unaltered) + ANNidxArray pidx, // point indices to store in subtree + int n, // number of points + int dim, // dimension of space + int bsp, // bucket space + ANNorthRect &bnd_box, // bounding box for current node + ANNkd_splitter splitter); // splitting routine + +#endif diff --git a/contrib/ANN/src/kd_util.cpp b/contrib/ANN/src/kd_util.cpp new file mode 100644 index 0000000000..06d65b835d --- /dev/null +++ b/contrib/ANN/src/kd_util.cpp @@ -0,0 +1,439 @@ +//---------------------------------------------------------------------- +// File: kd_util.cpp +// Programmer: Sunil Arya and David Mount +// Description: Common utilities for kd-trees +// Last modified: 01/04/05 (Version 1.0) +//---------------------------------------------------------------------- +// Copyright (c) 1997-2005 University of Maryland and Sunil Arya and +// David Mount. All Rights Reserved. +// +// This software and related documentation is part of the Approximate +// Nearest Neighbor Library (ANN). This software is provided under +// the provisions of the Lesser GNU Public License (LGPL). See the +// file ../ReadMe.txt for further information. +// +// The University of Maryland (U.M.) and the authors make no +// representations about the suitability or fitness of this software for +// any purpose. It is provided "as is" without express or implied +// warranty. +//---------------------------------------------------------------------- +// History: +// Revision 0.1 03/04/98 +// Initial release +//---------------------------------------------------------------------- + +#include "kd_util.h" // kd-utility declarations + +#include <ANN/ANNperf.h> // performance evaluation + +//---------------------------------------------------------------------- +// The following routines are utility functions for manipulating +// points sets, used in determining splitting planes for kd-tree +// construction. +//---------------------------------------------------------------------- + +//---------------------------------------------------------------------- +// NOTE: Virtually all point indexing is done through an index (i.e. +// permutation) array pidx. Consequently, a reference to the d-th +// coordinate of the i-th point is pa[pidx[i]][d]. The macro PA(i,d) +// is a shorthand for this. +//---------------------------------------------------------------------- + // standard 2-d indirect indexing +#define PA(i,d) (pa[pidx[(i)]][(d)]) + // accessing a single point +#define PP(i) (pa[pidx[(i)]]) + +//---------------------------------------------------------------------- +// annAspectRatio +// Compute the aspect ratio (ratio of longest to shortest side) +// of a rectangle. +//---------------------------------------------------------------------- + +double annAspectRatio( + int dim, // dimension + const ANNorthRect &bnd_box) // bounding cube +{ + ANNcoord length = bnd_box.hi[0] - bnd_box.lo[0]; + ANNcoord min_length = length; // min side length + ANNcoord max_length = length; // max side length + for (int d = 0; d < dim; d++) { + length = bnd_box.hi[d] - bnd_box.lo[d]; + if (length < min_length) min_length = length; + if (length > max_length) max_length = length; + } + return max_length/min_length; +} + +//---------------------------------------------------------------------- +// annEnclRect, annEnclCube +// These utilities compute the smallest rectangle and cube enclosing +// a set of points, respectively. +//---------------------------------------------------------------------- + +void annEnclRect( + ANNpointArray pa, // point array + ANNidxArray pidx, // point indices + int n, // number of points + int dim, // dimension + ANNorthRect &bnds) // bounding cube (returned) +{ + for (int d = 0; d < dim; d++) { // find smallest enclosing rectangle + ANNcoord lo_bnd = PA(0,d); // lower bound on dimension d + ANNcoord hi_bnd = PA(0,d); // upper bound on dimension d + for (int i = 0; i < n; i++) { + if (PA(i,d) < lo_bnd) lo_bnd = PA(i,d); + else if (PA(i,d) > hi_bnd) hi_bnd = PA(i,d); + } + bnds.lo[d] = lo_bnd; + bnds.hi[d] = hi_bnd; + } +} + +void annEnclCube( // compute smallest enclosing cube + ANNpointArray pa, // point array + ANNidxArray pidx, // point indices + int n, // number of points + int dim, // dimension + ANNorthRect &bnds) // bounding cube (returned) +{ + int d; + // compute smallest enclosing rect + annEnclRect(pa, pidx, n, dim, bnds); + + ANNcoord max_len = 0; // max length of any side + for (d = 0; d < dim; d++) { // determine max side length + ANNcoord len = bnds.hi[d] - bnds.lo[d]; + if (len > max_len) { // update max_len if longest + max_len = len; + } + } + for (d = 0; d < dim; d++) { // grow sides to match max + ANNcoord len = bnds.hi[d] - bnds.lo[d]; + ANNcoord half_diff = (max_len - len) / 2; + bnds.lo[d] -= half_diff; + bnds.hi[d] += half_diff; + } +} + +//---------------------------------------------------------------------- +// annBoxDistance - utility routine which computes distance from point to +// box (Note: most distances to boxes are computed using incremental +// distance updates, not this function.) +//---------------------------------------------------------------------- + +ANNdist annBoxDistance( // compute distance from point to box + const ANNpoint q, // the point + const ANNpoint lo, // low point of box + const ANNpoint hi, // high point of box + int dim) // dimension of space +{ + register ANNdist dist = 0.0; // sum of squared distances + register ANNdist t; + + for (register int d = 0; d < dim; d++) { + if (q[d] < lo[d]) { // q is left of box + t = ANNdist(lo[d]) - ANNdist(q[d]); + dist = ANN_SUM(dist, ANN_POW(t)); + } + else if (q[d] > hi[d]) { // q is right of box + t = ANNdist(q[d]) - ANNdist(hi[d]); + dist = ANN_SUM(dist, ANN_POW(t)); + } + } + ANN_FLOP(4*dim) // increment floating op count + + return dist; +} + +//---------------------------------------------------------------------- +// annSpread - find spread along given dimension +// annMinMax - find min and max coordinates along given dimension +// annMaxSpread - find dimension of max spread +//---------------------------------------------------------------------- + +ANNcoord annSpread( // compute point spread along dimension + ANNpointArray pa, // point array + ANNidxArray pidx, // point indices + int n, // number of points + int d) // dimension to check +{ + ANNcoord min = PA(0,d); // compute max and min coords + ANNcoord max = PA(0,d); + for (int i = 1; i < n; i++) { + ANNcoord c = PA(i,d); + if (c < min) min = c; + else if (c > max) max = c; + } + return (max - min); // total spread is difference +} + +void annMinMax( // compute min and max coordinates along dim + ANNpointArray pa, // point array + ANNidxArray pidx, // point indices + int n, // number of points + int d, // dimension to check + ANNcoord &min, // minimum value (returned) + ANNcoord &max) // maximum value (returned) +{ + min = PA(0,d); // compute max and min coords + max = PA(0,d); + for (int i = 1; i < n; i++) { + ANNcoord c = PA(i,d); + if (c < min) min = c; + else if (c > max) max = c; + } +} + +int annMaxSpread( // compute dimension of max spread + ANNpointArray pa, // point array + ANNidxArray pidx, // point indices + int n, // number of points + int dim) // dimension of space +{ + int max_dim = 0; // dimension of max spread + ANNcoord max_spr = 0; // amount of max spread + + if (n == 0) return max_dim; // no points, who cares? + + for (int d = 0; d < dim; d++) { // compute spread along each dim + ANNcoord spr = annSpread(pa, pidx, n, d); + if (spr > max_spr) { // bigger than current max + max_spr = spr; + max_dim = d; + } + } + return max_dim; +} + +//---------------------------------------------------------------------- +// annMedianSplit - split point array about its median +// Splits a subarray of points pa[0..n] about an element of given +// rank (median: n_lo = n/2) with respect to dimension d. It places +// the element of rank n_lo-1 correctly (because our splitting rule +// takes the mean of these two). On exit, the array is permuted so +// that: +// +// pa[0..n_lo-2][d] <= pa[n_lo-1][d] <= pa[n_lo][d] <= pa[n_lo+1..n-1][d]. +// +// The mean of pa[n_lo-1][d] and pa[n_lo][d] is returned as the +// splitting value. +// +// All indexing is done indirectly through the index array pidx. +// +// This function uses the well known selection algorithm due to +// C.A.R. Hoare. +//---------------------------------------------------------------------- + + // swap two points in pa array +#define PASWAP(a,b) { int tmp = pidx[a]; pidx[a] = pidx[b]; pidx[b] = tmp; } + +void annMedianSplit( + ANNpointArray pa, // points to split + ANNidxArray pidx, // point indices + int n, // number of points + int d, // dimension along which to split + ANNcoord &cv, // cutting value + int n_lo) // split into n_lo and n-n_lo +{ + int l = 0; // left end of current subarray + int r = n-1; // right end of current subarray + while (l < r) { + register int i = (r+l)/2; // select middle as pivot + register int k; + + if (PA(i,d) > PA(r,d)) // make sure last > pivot + PASWAP(i,r) + PASWAP(l,i); // move pivot to first position + + ANNcoord c = PA(l,d); // pivot value + i = l; + k = r; + for(;;) { // pivot about c + while (PA(++i,d) < c) ; + while (PA(--k,d) > c) ; + if (i < k) PASWAP(i,k) else break; + } + PASWAP(l,k); // pivot winds up in location k + + if (k > n_lo) r = k-1; // recurse on proper subarray + else if (k < n_lo) l = k+1; + else break; // got the median exactly + } + if (n_lo > 0) { // search for next smaller item + ANNcoord c = PA(0,d); // candidate for max + int k = 0; // candidate's index + for (int i = 1; i < n_lo; i++) { + if (PA(i,d) > c) { + c = PA(i,d); + k = i; + } + } + PASWAP(n_lo-1, k); // max among pa[0..n_lo-1] to pa[n_lo-1] + } + // cut value is midpoint value + cv = (PA(n_lo-1,d) + PA(n_lo,d))/2.0; +} + +//---------------------------------------------------------------------- +// annPlaneSplit - split point array about a cutting plane +// Split the points in an array about a given plane along a +// given cutting dimension. On exit, br1 and br2 are set so +// that: +// +// pa[ 0 ..br1-1] < cv +// pa[br1..br2-1] == cv +// pa[br2.. n -1] > cv +// +// All indexing is done indirectly through the index array pidx. +// +//---------------------------------------------------------------------- + +void annPlaneSplit( // split points by a plane + ANNpointArray pa, // points to split + ANNidxArray pidx, // point indices + int n, // number of points + int d, // dimension along which to split + ANNcoord cv, // cutting value + int &br1, // first break (values < cv) + int &br2) // second break (values == cv) +{ + int l = 0; + int r = n-1; + for(;;) { // partition pa[0..n-1] about cv + while (l < n && PA(l,d) < cv) l++; + while (r >= 0 && PA(r,d) >= cv) r--; + if (l > r) break; + PASWAP(l,r); + l++; r--; + } + br1 = l; // now: pa[0..br1-1] < cv <= pa[br1..n-1] + r = n-1; + for(;;) { // partition pa[br1..n-1] about cv + while (l < n && PA(l,d) <= cv) l++; + while (r >= br1 && PA(r,d) > cv) r--; + if (l > r) break; + PASWAP(l,r); + l++; r--; + } + br2 = l; // now: pa[br1..br2-1] == cv < pa[br2..n-1] +} + + +//---------------------------------------------------------------------- +// annBoxSplit - split point array about a orthogonal rectangle +// Split the points in an array about a given orthogonal +// rectangle. On exit, n_in is set to the number of points +// that are inside (or on the boundary of) the rectangle. +// +// All indexing is done indirectly through the index array pidx. +// +//---------------------------------------------------------------------- + +void annBoxSplit( // split points by a box + ANNpointArray pa, // points to split + ANNidxArray pidx, // point indices + int n, // number of points + int dim, // dimension of space + ANNorthRect &box, // the box + int &n_in) // number of points inside (returned) +{ + int l = 0; + int r = n-1; + for(;;) { // partition pa[0..n-1] about box + while (l < n && box.inside(dim, PP(l))) l++; + while (r >= 0 && !box.inside(dim, PP(r))) r--; + if (l > r) break; + PASWAP(l,r); + l++; r--; + } + n_in = l; // now: pa[0..n_in-1] inside and rest outside +} + +//---------------------------------------------------------------------- +// annSplitBalance - compute balance factor for a given plane split +// Balance factor is defined as the number of points lying +// below the splitting value minus n/2 (median). Thus, a +// median split has balance 0, left of this is negative and +// right of this is positive. (The points are unchanged.) +//---------------------------------------------------------------------- + +int annSplitBalance( // determine balance factor of a split + ANNpointArray pa, // points to split + ANNidxArray pidx, // point indices + int n, // number of points + int d, // dimension along which to split + ANNcoord cv) // cutting value +{ + int n_lo = 0; + for(int i = 0; i < n; i++) { // count number less than cv + if (PA(i,d) < cv) n_lo++; + } + return n_lo - n/2; +} + +//---------------------------------------------------------------------- +// annBox2Bnds - convert bounding box to list of bounds +// Given two boxes, an inner box enclosed within a bounding +// box, this routine determines all the sides for which the +// inner box is strictly contained with the bounding box, +// and adds an appropriate entry to a list of bounds. Then +// we allocate storage for the final list of bounds, and return +// the resulting list and its size. +//---------------------------------------------------------------------- + +void annBox2Bnds( // convert inner box to bounds + const ANNorthRect &inner_box, // inner box + const ANNorthRect &bnd_box, // enclosing box + int dim, // dimension of space + int &n_bnds, // number of bounds (returned) + ANNorthHSArray &bnds) // bounds array (returned) +{ + int i; + n_bnds = 0; // count number of bounds + for (i = 0; i < dim; i++) { + if (inner_box.lo[i] > bnd_box.lo[i]) // low bound is inside + n_bnds++; + if (inner_box.hi[i] < bnd_box.hi[i]) // high bound is inside + n_bnds++; + } + + bnds = new ANNorthHalfSpace[n_bnds]; // allocate appropriate size + + int j = 0; + for (i = 0; i < dim; i++) { // fill the array + if (inner_box.lo[i] > bnd_box.lo[i]) { + bnds[j].cd = i; + bnds[j].cv = inner_box.lo[i]; + bnds[j].sd = +1; + j++; + } + if (inner_box.hi[i] < bnd_box.hi[i]) { + bnds[j].cd = i; + bnds[j].cv = inner_box.hi[i]; + bnds[j].sd = -1; + j++; + } + } +} + +//---------------------------------------------------------------------- +// annBnds2Box - convert list of bounds to bounding box +// Given an enclosing box and a list of bounds, this routine +// computes the corresponding inner box. It is assumed that +// the box points have been allocated already. +//---------------------------------------------------------------------- + +void annBnds2Box( + const ANNorthRect &bnd_box, // enclosing box + int dim, // dimension of space + int n_bnds, // number of bounds + ANNorthHSArray bnds, // bounds array + ANNorthRect &inner_box) // inner box (returned) +{ + annAssignRect(dim, inner_box, bnd_box); // copy bounding box to inner + + for (int i = 0; i < n_bnds; i++) { + bnds[i].project(inner_box.lo); // project each endpoint + bnds[i].project(inner_box.hi); + } +} diff --git a/contrib/ANN/src/kd_util.h b/contrib/ANN/src/kd_util.h new file mode 100644 index 0000000000..6b4343048c --- /dev/null +++ b/contrib/ANN/src/kd_util.h @@ -0,0 +1,124 @@ +//---------------------------------------------------------------------- +// File: kd_util.h +// Programmer: Sunil Arya and David Mount +// Description: Common utilities for kd- trees +// Last modified: 01/04/05 (Version 1.0) +//---------------------------------------------------------------------- +// Copyright (c) 1997-2005 University of Maryland and Sunil Arya and +// David Mount. All Rights Reserved. +// +// This software and related documentation is part of the Approximate +// Nearest Neighbor Library (ANN). This software is provided under +// the provisions of the Lesser GNU Public License (LGPL). See the +// file ../ReadMe.txt for further information. +// +// The University of Maryland (U.M.) and the authors make no +// representations about the suitability or fitness of this software for +// any purpose. It is provided "as is" without express or implied +// warranty. +//---------------------------------------------------------------------- +// History: +// Revision 0.1 03/04/98 +// Initial release +//---------------------------------------------------------------------- + +#ifndef ANN_kd_util_H +#define ANN_kd_util_H + +#include "kd_tree.h" // kd-tree declarations + +//---------------------------------------------------------------------- +// externally accessible functions +//---------------------------------------------------------------------- + +double annAspectRatio( // compute aspect ratio of box + int dim, // dimension + const ANNorthRect &bnd_box); // bounding cube + +void annEnclRect( // compute smallest enclosing rectangle + ANNpointArray pa, // point array + ANNidxArray pidx, // point indices + int n, // number of points + int dim, // dimension + ANNorthRect &bnds); // bounding cube (returned) + +void annEnclCube( // compute smallest enclosing cube + ANNpointArray pa, // point array + ANNidxArray pidx, // point indices + int n, // number of points + int dim, // dimension + ANNorthRect &bnds); // bounding cube (returned) + +ANNdist annBoxDistance( // compute distance from point to box + const ANNpoint q, // the point + const ANNpoint lo, // low point of box + const ANNpoint hi, // high point of box + int dim); // dimension of space + +ANNcoord annSpread( // compute point spread along dimension + ANNpointArray pa, // point array + ANNidxArray pidx, // point indices + int n, // number of points + int d); // dimension to check + +void annMinMax( // compute min and max coordinates along dim + ANNpointArray pa, // point array + ANNidxArray pidx, // point indices + int n, // number of points + int d, // dimension to check + ANNcoord& min, // minimum value (returned) + ANNcoord& max); // maximum value (returned) + +int annMaxSpread( // compute dimension of max spread + ANNpointArray pa, // point array + ANNidxArray pidx, // point indices + int n, // number of points + int dim); // dimension of space + +void annMedianSplit( // split points along median value + ANNpointArray pa, // points to split + ANNidxArray pidx, // point indices + int n, // number of points + int d, // dimension along which to split + ANNcoord &cv, // cutting value + int n_lo); // split into n_lo and n-n_lo + +void annPlaneSplit( // split points by a plane + ANNpointArray pa, // points to split + ANNidxArray pidx, // point indices + int n, // number of points + int d, // dimension along which to split + ANNcoord cv, // cutting value + int &br1, // first break (values < cv) + int &br2); // second break (values == cv) + +void annBoxSplit( // split points by a box + ANNpointArray pa, // points to split + ANNidxArray pidx, // point indices + int n, // number of points + int dim, // dimension of space + ANNorthRect &box, // the box + int &n_in); // number of points inside (returned) + +int annSplitBalance( // determine balance factor of a split + ANNpointArray pa, // points to split + ANNidxArray pidx, // point indices + int n, // number of points + int d, // dimension along which to split + ANNcoord cv); // cutting value + +void annBox2Bnds( // convert inner box to bounds + const ANNorthRect &inner_box, // inner box + const ANNorthRect &bnd_box, // enclosing box + int dim, // dimension of space + int &n_bnds, // number of bounds (returned) + ANNorthHSArray &bnds); // bounds array (returned) + +void annBnds2Box( // convert bounds to inner box + const ANNorthRect &bnd_box, // enclosing box + int dim, // dimension of space + int n_bnds, // number of bounds + ANNorthHSArray bnds, // bounds array + ANNorthRect &inner_box); // inner box (returned) + +#endif diff --git a/contrib/ANN/src/perf.cpp b/contrib/ANN/src/perf.cpp new file mode 100644 index 0000000000..91bb0444ae --- /dev/null +++ b/contrib/ANN/src/perf.cpp @@ -0,0 +1,134 @@ +//---------------------------------------------------------------------- +// File: perf.cpp +// Programmer: Sunil Arya and David Mount +// Description: Methods for performance stats +// Last modified: 01/04/05 (Version 1.0) +//---------------------------------------------------------------------- +// Copyright (c) 1997-2005 University of Maryland and Sunil Arya and +// David Mount. All Rights Reserved. +// +// This software and related documentation is part of the Approximate +// Nearest Neighbor Library (ANN). This software is provided under +// the provisions of the Lesser GNU Public License (LGPL). See the +// file ../ReadMe.txt for further information. +// +// The University of Maryland (U.M.) and the authors make no +// representations about the suitability or fitness of this software for +// any purpose. It is provided "as is" without express or implied +// warranty. +//---------------------------------------------------------------------- +// History: +// Revision 0.1 03/04/98 +// Initial release +// Revision 1.0 04/01/05 +// Changed names to avoid namespace conflicts. +// Added flush after printing performance stats to fix bug +// in Microsoft Windows version. +//---------------------------------------------------------------------- + +#include <ANN/ANN.h> // basic ANN includes +#include <ANN/ANNperf.h> // performance includes + +using namespace std; // make std:: available + +//---------------------------------------------------------------------- +// Performance statistics +// The following data and routines are used for computing +// performance statistics for nearest neighbor searching. +// Because these routines can slow the code down, they can be +// activated and deactiviated by defining the PERF variable, +// by compiling with the option: -DPERF +//---------------------------------------------------------------------- + +//---------------------------------------------------------------------- +// Global counters for performance measurement +//---------------------------------------------------------------------- + +int ann_Ndata_pts = 0; // number of data points +int ann_Nvisit_lfs = 0; // number of leaf nodes visited +int ann_Nvisit_spl = 0; // number of splitting nodes visited +int ann_Nvisit_shr = 0; // number of shrinking nodes visited +int ann_Nvisit_pts = 0; // visited points for one query +int ann_Ncoord_hts = 0; // coordinate hits for one query +int ann_Nfloat_ops = 0; // floating ops for one query +ANNsampStat ann_visit_lfs; // stats on leaf nodes visits +ANNsampStat ann_visit_spl; // stats on splitting nodes visits +ANNsampStat ann_visit_shr; // stats on shrinking nodes visits +ANNsampStat ann_visit_nds; // stats on total nodes visits +ANNsampStat ann_visit_pts; // stats on points visited +ANNsampStat ann_coord_hts; // stats on coordinate hits +ANNsampStat ann_float_ops; // stats on floating ops +// +ANNsampStat ann_average_err; // average error +ANNsampStat ann_rank_err; // rank error + +//---------------------------------------------------------------------- +// Routines for statistics. +//---------------------------------------------------------------------- + +DLL_API void annResetStats(int data_size) // reset stats for a set of queries +{ + ann_Ndata_pts = data_size; + ann_visit_lfs.reset(); + ann_visit_spl.reset(); + ann_visit_shr.reset(); + ann_visit_nds.reset(); + ann_visit_pts.reset(); + ann_coord_hts.reset(); + ann_float_ops.reset(); + ann_average_err.reset(); + ann_rank_err.reset(); +} + +DLL_API void annResetCounts() // reset counts for one query +{ + ann_Nvisit_lfs = 0; + ann_Nvisit_spl = 0; + ann_Nvisit_shr = 0; + ann_Nvisit_pts = 0; + ann_Ncoord_hts = 0; + ann_Nfloat_ops = 0; +} + +DLL_API void annUpdateStats() // update stats with current counts +{ + ann_visit_lfs += ann_Nvisit_lfs; + ann_visit_nds += ann_Nvisit_spl + ann_Nvisit_lfs; + ann_visit_spl += ann_Nvisit_spl; + ann_visit_shr += ann_Nvisit_shr; + ann_visit_pts += ann_Nvisit_pts; + ann_coord_hts += ann_Ncoord_hts; + ann_float_ops += ann_Nfloat_ops; +} + + // print a single statistic +void print_one_stat(char *title, ANNsampStat s, double div) +{ + cout << title << "= [ "; + cout.width(9); cout << s.mean()/div << " : "; + cout.width(9); cout << s.stdDev()/div << " ]<"; + cout.width(9); cout << s.min()/div << " , "; + cout.width(9); cout << s.max()/div << " >\n"; +} + +DLL_API void annPrintStats( // print statistics for a run + ANNbool validate) // true if average errors desired +{ + cout.precision(4); // set floating precision + cout << " (Performance stats: " + << " [ mean : stddev ]< min , max >\n"; + print_one_stat(" leaf_nodes ", ann_visit_lfs, 1); + print_one_stat(" splitting_nodes ", ann_visit_spl, 1); + print_one_stat(" shrinking_nodes ", ann_visit_shr, 1); + print_one_stat(" total_nodes ", ann_visit_nds, 1); + print_one_stat(" points_visited ", ann_visit_pts, 1); + print_one_stat(" coord_hits/pt ", ann_coord_hts, ann_Ndata_pts); + print_one_stat(" floating_ops_(K) ", ann_float_ops, 1000); + if (validate) { + print_one_stat(" average_error ", ann_average_err, 1); + print_one_stat(" rank_error ", ann_rank_err, 1); + } + cout.precision(0); // restore the default + cout << " )\n"; + cout.flush(); +} diff --git a/contrib/ANN/src/pr_queue.h b/contrib/ANN/src/pr_queue.h new file mode 100644 index 0000000000..3f4b75c878 --- /dev/null +++ b/contrib/ANN/src/pr_queue.h @@ -0,0 +1,125 @@ +//---------------------------------------------------------------------- +// File: pr_queue.h +// Programmer: Sunil Arya and David Mount +// Description: Include file for priority queue and related +// structures. +// Last modified: 01/04/05 (Version 1.0) +//---------------------------------------------------------------------- +// Copyright (c) 1997-2005 University of Maryland and Sunil Arya and +// David Mount. All Rights Reserved. +// +// This software and related documentation is part of the Approximate +// Nearest Neighbor Library (ANN). This software is provided under +// the provisions of the Lesser GNU Public License (LGPL). See the +// file ../ReadMe.txt for further information. +// +// The University of Maryland (U.M.) and the authors make no +// representations about the suitability or fitness of this software for +// any purpose. It is provided "as is" without express or implied +// warranty. +//---------------------------------------------------------------------- +// History: +// Revision 0.1 03/04/98 +// Initial release +//---------------------------------------------------------------------- + +#ifndef PR_QUEUE_H +#define PR_QUEUE_H + +#include <ANN/ANNx.h> // all ANN includes +#include <ANN/ANNperf.h> // performance evaluation + +//---------------------------------------------------------------------- +// Basic types. +//---------------------------------------------------------------------- +typedef void *PQinfo; // info field is generic pointer +typedef ANNdist PQkey; // key field is distance + +//---------------------------------------------------------------------- +// Priority queue +// A priority queue is a list of items, along with associated +// priorities. The basic operations are insert and extract_minimum. +// +// The priority queue is maintained using a standard binary heap. +// (Implementation note: Indexing is performed from [1..max] rather +// than the C standard of [0..max-1]. This simplifies parent/child +// computations.) User information consists of a void pointer, +// and the user is responsible for casting this quantity into whatever +// useful form is desired. +// +// Because the priority queue is so central to the efficiency of +// query processing, all the code is inline. +//---------------------------------------------------------------------- + +class ANNpr_queue { + + struct pq_node { // node in priority queue + PQkey key; // key value + PQinfo info; // info field + }; + int n; // number of items in queue + int max_size; // maximum queue size + pq_node *pq; // the priority queue (array of nodes) + +public: + ANNpr_queue(int max) // constructor (given max size) + { + n = 0; // initially empty + max_size = max; // maximum number of items + pq = new pq_node[max+1]; // queue is array [1..max] of nodes + } + + ~ANNpr_queue() // destructor + { delete [] pq; } + + ANNbool empty() // is queue empty? + { if (n==0) return ANNtrue; else return ANNfalse; } + + ANNbool non_empty() // is queue nonempty? + { if (n==0) return ANNfalse; else return ANNtrue; } + + void reset() // make existing queue empty + { n = 0; } + + inline void insert( // insert item (inlined for speed) + PQkey kv, // key value + PQinfo inf) // item info + { + if (++n > max_size) annError("Priority queue overflow.", ANNabort); + register int r = n; + while (r > 1) { // sift up new item + register int p = r/2; + ANN_FLOP(1) // increment floating ops + if (pq[p].key <= kv) // in proper order + break; + pq[r] = pq[p]; // else swap with parent + r = p; + } + pq[r].key = kv; // insert new item at final location + pq[r].info = inf; + } + + inline void extr_min( // extract minimum (inlined for speed) + PQkey &kv, // key (returned) + PQinfo &inf) // item info (returned) + { + kv = pq[1].key; // key of min item + inf = pq[1].info; // information of min item + register PQkey kn = pq[n--].key;// last item in queue + register int p = 1; // p points to item out of position + register int r = p<<1; // left child of p + while (r <= n) { // while r is still within the heap + ANN_FLOP(2) // increment floating ops + // set r to smaller child of p + if (r < n && pq[r].key > pq[r+1].key) r++; + if (kn <= pq[r].key) // in proper order + break; + pq[p] = pq[r]; // else swap with child + p = r; // advance pointers + r = p<<1; + } + pq[p] = pq[n+1]; // insert last item in proper place + } +}; + +#endif diff --git a/contrib/ANN/src/pr_queue_k.h b/contrib/ANN/src/pr_queue_k.h new file mode 100644 index 0000000000..c2f01c34a5 --- /dev/null +++ b/contrib/ANN/src/pr_queue_k.h @@ -0,0 +1,118 @@ +//---------------------------------------------------------------------- +// File: pr_queue_k.h +// Programmer: Sunil Arya and David Mount +// Description: Include file for priority queue with k items. +// Last modified: 01/04/05 (Version 1.0) +//---------------------------------------------------------------------- +// Copyright (c) 1997-2005 University of Maryland and Sunil Arya and +// David Mount. All Rights Reserved. +// +// This software and related documentation is part of the Approximate +// Nearest Neighbor Library (ANN). This software is provided under +// the provisions of the Lesser GNU Public License (LGPL). See the +// file ../ReadMe.txt for further information. +// +// The University of Maryland (U.M.) and the authors make no +// representations about the suitability or fitness of this software for +// any purpose. It is provided "as is" without express or implied +// warranty. +//---------------------------------------------------------------------- +// History: +// Revision 0.1 03/04/98 +// Initial release +//---------------------------------------------------------------------- + +#ifndef PR_QUEUE_K_H +#define PR_QUEUE_K_H + +#include <ANN/ANNx.h> // all ANN includes +#include <ANN/ANNperf.h> // performance evaluation + +//---------------------------------------------------------------------- +// Basic types +//---------------------------------------------------------------------- +typedef ANNdist PQKkey; // key field is distance +typedef int PQKinfo; // info field is int + +//---------------------------------------------------------------------- +// Constants +// The NULL key value is used to initialize the priority queue, and +// so it should be larger than any valid distance, so that it will +// be replaced as legal distance values are inserted. The NULL +// info value must be a nonvalid array index, we use ANN_NULL_IDX, +// which is guaranteed to be negative. +//---------------------------------------------------------------------- + +const PQKkey PQ_NULL_KEY = ANN_DIST_INF; // nonexistent key value +const PQKinfo PQ_NULL_INFO = ANN_NULL_IDX; // nonexistent info value + +//---------------------------------------------------------------------- +// ANNmin_k +// An ANNmin_k structure is one which maintains the smallest +// k values (of type PQKkey) and associated information (of type +// PQKinfo). The special info and key values PQ_NULL_INFO and +// PQ_NULL_KEY means that thise entry is empty. +// +// It is currently implemented using an array with k items. +// Items are stored in increasing sorted order, and insertions +// are made through standard insertion sort. (This is quite +// inefficient, but current applications call for small values +// of k and relatively few insertions.) +// +// Note that the list contains k+1 entries, but the last entry +// is used as a simple placeholder and is otherwise ignored. +//---------------------------------------------------------------------- + +class ANNmin_k { + struct mk_node { // node in min_k structure + PQKkey key; // key value + PQKinfo info; // info field (user defined) + }; + + int k; // max number of keys to store + int n; // number of keys currently active + mk_node *mk; // the list itself + +public: + ANNmin_k(int max) // constructor (given max size) + { + n = 0; // initially no items + k = max; // maximum number of items + mk = new mk_node[max+1]; // sorted array of keys + } + + ~ANNmin_k() // destructor + { delete [] mk; } + + PQKkey ANNmin_key() // return minimum key + { return (n > 0 ? mk[0].key : PQ_NULL_KEY); } + + PQKkey max_key() // return maximum key + { return (n == k ? mk[k-1].key : PQ_NULL_KEY); } + + PQKkey ith_smallest_key(int i) // ith smallest key (i in [0..n-1]) + { return (i < n ? mk[i].key : PQ_NULL_KEY); } + + PQKinfo ith_smallest_info(int i) // info for ith smallest (i in [0..n-1]) + { return (i < n ? mk[i].info : PQ_NULL_INFO); } + + inline void insert( // insert item (inlined for speed) + PQKkey kv, // key value + PQKinfo inf) // item info + { + register int i; + // slide larger values up + for (i = n; i > 0; i--) { + if (mk[i-1].key > kv) + mk[i] = mk[i-1]; + else + break; + } + mk[i].key = kv; // store element here + mk[i].info = inf; + if (n < k) n++; // increment number of items + ANN_FLOP(k-i+1) // increment floating ops + } +}; + +#endif diff --git a/contrib/MathEval/Makefile b/contrib/MathEval/Makefile new file mode 100644 index 0000000000..aaef9432a3 --- /dev/null +++ b/contrib/MathEval/Makefile @@ -0,0 +1,79 @@ +# $Id: Makefile,v 1.1 2005-09-21 17:29:37 geuzaine Exp $ +# +# Copyright (C) 1997-2005 C. Geuzaine, J.-F. Remacle +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +# USA. +# +# Please report all bugs and problems to <gmsh@geuz.org>. + +include ../../variables + +LIB = ../../lib/libGmshMathEval.a +INCLUDE = -I../../Common -I../../DataStr + +CFLAGS = ${OPTIM} ${FLAGS} ${INCLUDE} + +SRC = matheval.cpp\ + node.cpp\ + scanner.yy.cpp\ + parser.tab.cpp\ + symbol_table.cpp\ + xmath.cpp + +OBJ = ${SRC:.cpp=.o} + +.SUFFIXES: .o .cpp + +${LIB}: ${OBJ} + ${AR} ${LIB} ${OBJ} + ${RANLIB} ${LIB} + +.cpp.o: + ${CXX} ${CFLAGS} -c $< + +parser: + bison --output parser.tab.cpp -pme -d parser.y + if [ -r parser.tab.cpp.h ]; then mv parser.tab.cpp.h parser.tab.hpp ; fi + flex -oscanner.yy.cpp -Pme scanner.l + +clean: + rm -f *.o + +depend: + (sed '/^# DO NOT DELETE THIS LINE/q' Makefile && \ + ${CC} -MM ${CFLAGS} ${SRC} \ + ) >Makefile.new + cp Makefile Makefile.bak + cp Makefile.new Makefile + rm -f Makefile.new + +# DO NOT DELETE THIS LINE +# 1 "/Users/geuzaine/.gmsh/MathEval//" +matheval.o: matheval.cpp common.h ../DataStr/Malloc.h matheval.h node.h \ + symbol_table.h +# 1 "/Users/geuzaine/.gmsh/MathEval//" +node.o: node.cpp common.h ../DataStr/Malloc.h node.h symbol_table.h +# 1 "/Users/geuzaine/.gmsh/MathEval//" +scanner.yy.o: scanner.yy.cpp common.h ../DataStr/Malloc.h node.h \ + symbol_table.h parser.tab.hpp +# 1 "/Users/geuzaine/.gmsh/MathEval//" +parser.tab.o: parser.tab.cpp common.h ../DataStr/Malloc.h node.h \ + symbol_table.h +# 1 "/Users/geuzaine/.gmsh/MathEval//" +symbol_table.o: symbol_table.cpp common.h ../DataStr/Malloc.h \ + symbol_table.h xmath.h +# 1 "/Users/geuzaine/.gmsh/MathEval//" +xmath.o: xmath.cpp xmath.h diff --git a/contrib/MathEval/README b/contrib/MathEval/README new file mode 100644 index 0000000000..b66f65dc34 --- /dev/null +++ b/contrib/MathEval/README @@ -0,0 +1,25 @@ + +This directory contains a (heavily) modified version of GNU +libmatheval. + +The original libmatheval is Copyright (C) 1999, 2002, 2003 Aleksandar +B. Samardzic + +Copying and distribution of this file, with or without modification, are +permitted in any medium without royalty provided the copyright notice +and this notice are preserved. + +WHAT IS IT? + +GNU libmatheval is a library which contains several procedures that make +it possible to create an in-memory tree from the string representation +of a mathematical function over single or multiple variables. This tree +can be used later to evaluate a function for specified variable values, +to create a corresponding tree for the function derivative over a +specified variable, or to write a textual tree representation to a +specified string. + +BUGS + +Please report bugs and eventually send patches to +<bug-libmatheval@gnu.org> mailing list. diff --git a/contrib/MathEval/common.h b/contrib/MathEval/common.h new file mode 100644 index 0000000000..781b6df4ad --- /dev/null +++ b/contrib/MathEval/common.h @@ -0,0 +1,37 @@ +/* + * Copyright (C) 1999, 2002, 2003 Free Software Foundation, Inc. + * + * This file is part of GNU libmatheval + * + * GNU libmatheval 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. + * + * GNU libmatheval 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 + * program; see the file COPYING. If not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef COMMON_H +#define COMMON_H + +#include <math.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "Malloc.h" + +/* Macro definitions to simplify corresponding function calls. */ +#define XMALLOC(type, num) ((type *) Malloc ((num) * sizeof(type))) +#define XREALLOC(type, p, num) ((type *) Realloc ((p), (num) * sizeof(type))) +#define XCALLOC(type, num) ((type *) Calloc ((num), sizeof(type))) +#define XFREE(stale) Free (stale); + +#endif diff --git a/contrib/MathEval/matheval.cpp b/contrib/MathEval/matheval.cpp new file mode 100644 index 0000000000..efc5e1b1cb --- /dev/null +++ b/contrib/MathEval/matheval.cpp @@ -0,0 +1,248 @@ +/* + * Copyright (C) 1999, 2002, 2003 Free Software Foundation, Inc. + * + * This file is part of GNU libmatheval + * + * GNU libmatheval 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. + * + * GNU libmatheval 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 + * program; see the file COPYING. If not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* This file was modified for inclusion in Gmsh */ + +#include "common.h" +#include "matheval.h" +#include "node.h" +#include "symbol_table.h" + +/* Minimal length of evaluator symbol table. */ +#define MIN_TABLE_LENGTH 211 + +/* + * Function used to parse string representing function (this function is + * generated by parser generator). + */ +extern int meparse(); + +/* + * Following variables are needed for parsing (parser is able to communicate + * with program from which it is used through global variables only). + */ +char *matheval_input_string; /* String representing function. */ +Node *matheval_root; /* Root of tree representation of + * function. */ +SymbolTable *matheval_symbol_table; /* Evaluator symbol table. */ +int matheval_ok; /* Flag determining if parsing went OK. */ + +/* Data structure representing evaluator. */ +typedef struct { + Node *root; /* Root of tree representation of + * function. */ + SymbolTable *symbol_table; /* Evalutor symbol table. */ +} Evaluator; + +void * +evaluator_create(char *string) +{ + Evaluator *evaluator; /* Evaluator representing function given + * by string. */ + char *stringn; /* Copy of string terminated by newline + * character. */ + + /* + * Copy string representing function and terminate it with newline + * (this is necessary because parser expect newline character to + * terminate its input). + */ + stringn = XMALLOC(char, strlen(string) + 2); + + strcpy(stringn, string); + strcat(stringn, "\n"); + + /* + * Initialize global variables used by parser. + */ + matheval_input_string = stringn; + matheval_root = NULL; + matheval_symbol_table = symbol_table_create(MIN_TABLE_LENGTH); + matheval_ok = 1; + + /* + * Do parsing. + */ + meparse(); + + /* + * Free copy of string representing function. + */ + XFREE(stringn); + + /* + * Return null pointer as error indicator if parsing error occured. + */ + if (!matheval_ok || !matheval_root){ + node_destroy(matheval_root); + symbol_table_destroy(matheval_symbol_table); + return NULL; + } + + /* + * Simplify tree represention of function. + */ + matheval_root = node_simplify(matheval_root); + + /* + * Allocate memory for and initialize evaluator data structure. + */ + evaluator = XMALLOC(Evaluator, 1); + evaluator->root = matheval_root; + evaluator->symbol_table = matheval_symbol_table; + + return evaluator; +} + +void +evaluator_destroy(void *evaluator) +{ + /* + * Destroy tree represention of function, symbol table, as well as + * data structure representing evaluator. + */ + node_destroy(((Evaluator *) evaluator)->root); + symbol_table_destroy(((Evaluator *) evaluator)->symbol_table); + XFREE(evaluator); +} + +double +evaluator_evaluate(void *evaluator, int count, char **names, double *values) +{ + Record *record; /* Symbol table record corresponding to + * give variable name. */ + int i; /* Loop counter. */ + + /* + * Assign values to symbol table records corresponding to variable + * names. + */ + for (i = 0; i < count; i++) { + record = symbol_table_lookup(((Evaluator *) evaluator)->symbol_table, names[i]); + if (record && record->type == 'v') + record->data.value = values[i]; + } + + /* + * Evaluate function value using tree represention of function. + */ + return node_evaluate(((Evaluator *) evaluator)->root); +} + +int +evaluator_calculate_length(void *evaluator) +{ + /* + * Calculate length of evaluator textual representation. + */ + return node_calculate_length(((Evaluator *) evaluator)->root); +} + +void +evaluator_write(void *evaluator, char *string) +{ + /* + * Write evaluator textual representation to given string. + */ + node_write(((Evaluator *) evaluator)->root, string); +} + +void * +evaluator_derivative(void *evaluator, char *name) +{ + Evaluator *derivative; /* Derivative function evaluator. */ + + /* + * Allocate memory for and initalize data structure for evaluator + * representing derivative of function given by evaluator. + */ + derivative = XMALLOC(Evaluator, 1); + derivative->root = node_simplify(node_derivative(((Evaluator *) evaluator)->root, name, + ((Evaluator *) evaluator)->symbol_table)); + derivative->symbol_table = symbol_table_assign(((Evaluator *) evaluator)->symbol_table); + + return derivative; +} + +double +evaluator_evaluate_x(void *evaluator, double x) +{ + char *names[] = {"x"}; /* Array of variable names. */ + double values[] = {x}; /* Array of variable values. */ + + /* + * Evaluate function for given values of variable "x". + */ + return evaluator_evaluate(evaluator, sizeof(names) / sizeof(names[0]), names, values); +} + +double +evaluator_evaluate_x_y(void *evaluator, double x, double y) +{ + char *names[] = {"x", "y"}; /* Array of variable + * names. */ + double values[] = {x, y}; /* Array of variable values. */ + + /* + * Evaluate function for given values of variable "x" and "y". + */ + return evaluator_evaluate(evaluator, sizeof(names) / sizeof(names[0]), names, values); +} + +double +evaluator_evaluate_x_y_z(void *evaluator, double x, double y, double z) +{ + char *names[] = {"x", "y", "z"}; /* Array of variable + * names. */ + double values[] = {x, y, z}; /* Array of variable + * values. */ + + /* + * Evaluate function for given values of variable "x", "y" and "z". + */ + return evaluator_evaluate(evaluator, sizeof(names) / sizeof(names[0]), names, values); +} + +void * +evaluator_derivative_x(void *evaluator) +{ + /* + * Differentiate function using derivation variable "x". + */ + return evaluator_derivative(evaluator, "x"); +} + +void * +evaluator_derivative_y(void *evaluator) +{ + /* + * Differentiate function using derivation variable "y". + */ + return evaluator_derivative(evaluator, "y"); +} + +void * +evaluator_derivative_z(void *evaluator) +{ + /* + * Differentiate function using derivation variable "z". + */ + return evaluator_derivative(evaluator, "z"); +} diff --git a/contrib/MathEval/matheval.h b/contrib/MathEval/matheval.h new file mode 100644 index 0000000000..b155f4003c --- /dev/null +++ b/contrib/MathEval/matheval.h @@ -0,0 +1,89 @@ +/* + * Copyright (C) 1999, 2002, 2003 Free Software Foundation, Inc. + * + * This file is part of GNU libmatheval + * + * GNU libmatheval 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. + * + * GNU libmatheval 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 + * program; see the file COPYING. If not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* This file was modified for inclusion in Gmsh */ + +#ifndef EVALUATOR_H +#define EVALUATOR_H + +/* + * Create evaluator from string representing function. Function + * returns pointer that should be passed as first argument to all + * other library functions. If an error occurs, function will return + * null pointer. + */ +void *evaluator_create(char *string); + +/* + * Destroy evaluator specified. + */ +void evaluator_destroy(void *evaluator); + +/* + * Evaluate function represented by evaluator given. Variable names + * and respective values are represented by function third and fourth + * argument. Number of variables i.e. length of these two arrays is + * given by second argument. Function returns evaluated function + * value. In case that function contains variables with names not + * given through third function argument, value of this variable is + * undeterminated. + */ +double evaluator_evaluate(void *evaluator, int count, char **names, double *values); + +/* + * Calculate length of textual representation of evaluator. This + * procedure is inteded to be used along with evaluator_write() + * procedure that follows. + */ +int evaluator_calculate_length(void *evaluator); + +/* + * Write textual representation of evaluator (i.e. corresponding + * function) to given string. No string overflow is checked by this + * procedure; string of appropriate length (calculated beforehand + * using above evaluator_calculate_length() procedure) is expected to + * be allocated beforehand. + */ +void evaluator_write(void *evaluator, char *length); + +/* + * Create evaluator for first derivative of function represented by + * evaluator given as first argument using derivative variable given + * as second argument. + */ +void *evaluator_derivative(void *evaluator, char *name); + +/* + * Helper functions to simplify evaluation when variable names are + * "x", "x" and "y" or "x" and "y" and "z" respectively. + */ +double evaluator_evaluate_x(void *evaluator, double x); +double evaluator_evaluate_x_y(void *evaluator, double x, double y); +double evaluator_evaluate_x_y_z(void *evaluator, double x, double y, double z); + +/* + * Helper functions to simplify differentiation when variable names + * are "x" or "y" or "z" respectively. + */ +void *evaluator_derivative_x(void *evaluator); +void *evaluator_derivative_y(void *evaluator); +void *evaluator_derivative_z(void *evaluator); + +#endif diff --git a/contrib/MathEval/node.cpp b/contrib/MathEval/node.cpp new file mode 100644 index 0000000000..420dfb6717 --- /dev/null +++ b/contrib/MathEval/node.cpp @@ -0,0 +1,653 @@ +/* + * Copyright (C) 1999, 2002, 2003 Free Software Foundation, Inc. + * + * This file is part of GNU libmatheval + * + * GNU libmatheval 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. + * + * GNU libmatheval 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 + * program; see the file COPYING. If not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include <assert.h> +#include <stdarg.h> +#include "common.h" +#include "node.h" + +Node * +node_create(char type,...) +{ + Node *node; /* New node. */ + va_list ap; /* Variable argument list. */ + + /* + * Allocate memory for node and initialize its type. + */ + node = XMALLOC(Node, 1); + node->type = type; + + /* + * According to node type, initialize rest of the node from variable + * argument list. + */ + va_start(ap, type); + switch (node->type) { + case 'c': + /* + * Initialize constant value. + */ + node->data.constant = va_arg(ap, double); + break; + + case 'v': + /* + * Remember pointer to symbol table record describing + * variable. + */ + node->data.variable = va_arg(ap, Record *); + break; + + case 'f': + /* + * Remember pointer to symbol table record describing + * function and initialize function argument. + */ + node->data.function.record = va_arg(ap, Record *); + node->data.function.child = va_arg(ap, Node *); + break; + + case 'u': + /* + * Initialize operator type and operand. + */ + node->data.un_op.operatorr = (char) va_arg(ap, int); + node->data.un_op.child = va_arg(ap, Node *); + break; + + case 'b': + /* + * Initialize operator type and operands. + */ + node->data.un_op.operatorr = (char) va_arg(ap, int); + node->data.bin_op.left = va_arg(ap, Node *); + node->data.bin_op.right = va_arg(ap, Node *); + break; + + default: + assert(0); + } + va_end(ap); + + return node; +} + +void +node_destroy(Node * node) +{ + /* + * Skip if node already null (this may occur during simplification). + */ + if (!node) + return; + + /* + * If necessary, destroy subtree rooted at node. + */ + switch (node->type) { + case 'c': + case 'v': + break; + + case 'f': + node_destroy(node->data.function.child); + break; + + case 'u': + node_destroy(node->data.un_op.child); + break; + + case 'b': + node_destroy(node->data.bin_op.left); + node_destroy(node->data.bin_op.right); + break; + } + + /* + * Deallocate memory used by node. + */ + XFREE(node); +} + +Node * +node_copy(Node * node) +{ + /* + * According to node type, create (deep) copy of subtree rooted at + * node. + */ + switch (node->type) { + case 'c': + return node_create('c', node->data.constant); + + case 'v': + return node_create('v', node->data.variable); + + case 'f': + return node_create('f', node->data.function.record, node_copy(node->data.function.child)); + + case 'u': + return node_create('u', node->data.un_op.operatorr, node_copy(node->data.un_op.child)); + + case 'b': + return node_create('b', node->data.bin_op.operatorr, node_copy(node->data.bin_op.left), node_copy(node->data.bin_op.right)); + } + + return NULL; +} + +Node * +node_simplify(Node * node) +{ + /* + * According to node type, apply further simplifications. + */ + switch (node->type) { + case 'c': + case 'v': + return node; + + case 'f': + /* + * Simplify function argument and if constant evaluate function + * and replace function node with constant node (unless the + * function is Rand(x)). + */ + node->data.function.child = node_simplify(node->data.function.child); + if (node->data.function.child->type == 'c' && + strcmp(node->data.function.record->name, "Rand")) { + double value = node_evaluate(node); + + node_destroy(node); + return node_create('c', value); + } + else + return node; + + case 'u': + /* + * Simplify unary operator operand and if constant apply + * operator and replace operator node with constant node. + */ + node->data.un_op.child = node_simplify(node->data.un_op.child); + if (node->data.un_op.operatorr == '-' && node->data.un_op.child->type == 'c') { + double value = node_evaluate(node); + + node_destroy(node); + return node_create('c', value); + } + else + return node; + + case 'b': + /* + * Simplify binary operator operands. + */ + node->data.bin_op.left = node_simplify(node->data.bin_op.left); + node->data.bin_op.right = node_simplify(node->data.bin_op.right); + + /* + * If operands constant apply operator and replace operator + * node with constant node. + */ + if (node->data.bin_op.left->type == 'c' && node->data.bin_op.right->type == 'c') { + double value = node_evaluate(node); + + node_destroy(node); + return node_create('c', value); + } + /* + * Eliminate 0 as neutral addition operand. + */ + else if (node->data.bin_op.operatorr == '+') + if (node->data.bin_op.left->type == 'c' && node->data.bin_op.left->data.constant == 0) { + Node *right; + right = node->data.bin_op.right; + node->data.bin_op.right = NULL; + node_destroy(node); + return right; + } + else if (node->data.bin_op.right->type == 'c' && node->data.bin_op.right->data.constant == 0) { + Node *left; + left = node->data.bin_op.left; + node->data.bin_op.left = NULL; + node_destroy(node); + return left; + } + else + return node; + /* + * Eliminate 0 as neutral subtraction right operand. + */ + else if (node->data.bin_op.operatorr == '-') + if (node->data.bin_op.right->type == 'c' && node->data.bin_op.right->data.constant == 0) { + Node *left; + left = node->data.bin_op.left; + node->data.bin_op.left = NULL; + node_destroy(node); + return left; + } + else + return node; + /* + * Eliminate 1 as neutral multiplication operand. + */ + else if (node->data.bin_op.operatorr == '*') + if (node->data.bin_op.left->type == 'c' && node->data.bin_op.left->data.constant == 1) { + Node *right; + right = node->data.bin_op.right; + node->data.bin_op.right = NULL; + node_destroy(node); + return right; + } + else if (node->data.bin_op.right->type == 'c' && node->data.bin_op.right->data.constant == 1) { + Node *left; + left = node->data.bin_op.left; + node->data.bin_op.left = NULL; + node_destroy(node); + return left; + } + else + return node; + /* + * Eliminate 1 as neutral division right operand. + */ + else if (node->data.bin_op.operatorr == '/') + if (node->data.bin_op.right->type == 'c' && node->data.bin_op.right->data.constant == 1) { + Node *left; + left = node->data.bin_op.left; + node->data.bin_op.left = NULL; + node_destroy(node); + return left; + } + else + return node; + /* + * Eliminate 0 and 1 as both left and right exponentiation + * operands. + */ + else if (node->data.bin_op.operatorr == '^') + if (node->data.bin_op.left->type == 'c' && node->data.bin_op.left->data.constant == 0) { + node_destroy(node); + return node_create('c', 0.0); + } + else if (node->data.bin_op.left->type == 'c' && node->data.bin_op.left->data.constant == 1) { + node_destroy(node); + return node_create('c', 1.0); + } + else if (node->data.bin_op.right->type == 'c' && node->data.bin_op.right->data.constant == 0) { + node_destroy(node); + return node_create('c', 1.0); + } + else if (node->data.bin_op.right->type == 'c' && node->data.bin_op.right->data.constant == 1) { + Node *left; + left = node->data.bin_op.left; + node->data.bin_op.left = NULL; + node_destroy(node); + return left; + } + else + return node; + else + return node; + } + + return NULL; +} + +double +node_evaluate(Node * node) +{ + /* + * According to node type, evaluate subtree rooted at node. + */ + switch (node->type) { + case 'c': + return node->data.constant; + + case 'v': + /* + * Variable values are used from symbol table. + */ + return node->data.variable->data.value; + + case 'f': + /* + * Functions are evaluated through symbol table. + */ + return (*node->data.function.record->data.function) (node_evaluate(node->data.function.child)); + + case 'u': + /* + * Unary operator node is evaluated according to operator + * type. + */ + switch (node->data.un_op.operatorr) { + case '-': + return -node_evaluate(node->data.un_op.child); + } + + case 'b': + /* + * Binary operator node is evaluated according to operator + * type. + */ + switch (node->data.un_op.operatorr) { + case '+': + return node_evaluate(node->data.bin_op.left) + node_evaluate(node->data.bin_op.right); + + case '-': + return node_evaluate(node->data.bin_op.left) - node_evaluate(node->data.bin_op.right); + + case '*': + return node_evaluate(node->data.bin_op.left) * node_evaluate(node->data.bin_op.right); + + case '/': + return node_evaluate(node->data.bin_op.left) / node_evaluate(node->data.bin_op.right); + + case '^': + return pow(node_evaluate(node->data.bin_op.left), node_evaluate(node->data.bin_op.right)); + } + } + + return 0; +} + +Node * +node_derivative(Node * node, char *name, SymbolTable * symbol_table) +{ + /* + * According to node type, derivative tree for subtree rooted at node + * is created. + */ + switch (node->type) { + case 'c': + /* + * Derivative of constant equals 0. + */ + return node_create('c', 0.0); + + case 'v': + /* + * Derivative of variable equals 1 if variable is derivative + * variable, 0 otherwise. + */ + return node_create('c', (!strcmp(name, node->data.variable->name)) ? 1.0 : 0.0); + + case 'f': + /* + * Apply rule of exponential function derivative. + */ + if (!strcmp(node->data.function.record->name, "Exp")) + return node_create('b', '*', node_derivative(node->data.function.child, name, symbol_table), node_copy(node)); + /* + * Apply rule of logarithmic function derivative. + */ + else if (!strcmp(node->data.function.record->name, "Log")) + return node_create('b', '/', node_derivative(node->data.function.child, name, symbol_table), node_copy(node->data.function.child)); + /* + * Apply rule of square root function derivative. + */ + else if (!strcmp(node->data.function.record->name, "Sqrt")) + return node_create('b', '/', node_derivative(node->data.function.child, name, symbol_table), node_create('b', '*', node_create('c', 2.0), node_copy(node))); + /* + * Apply rule of sine function derivative. + */ + else if (!strcmp(node->data.function.record->name, "Sin")) + return node_create('b', '*', node_derivative(node->data.function.child, name, symbol_table), node_create('f', symbol_table_lookup(symbol_table, "Cos"), node_copy(node->data.function.child))); + /* + * Apply rule of cosine function derivative. + */ + else if (!strcmp(node->data.function.record->name, "Cos")) + return node_create('u', '-', node_create('b', '*', node_derivative(node->data.function.child, name, symbol_table), node_create('f', symbol_table_lookup(symbol_table, "Sin"), node_copy(node->data.function.child)))); + /* + * Apply rule of tangent function derivative. + */ + else if (!strcmp(node->data.function.record->name, "Tan")) + return node_create('b', '/', node_derivative(node->data.function.child, name, symbol_table), node_create('b', '^', node_create('f', symbol_table_lookup(symbol_table, "Cos"), node_copy(node->data.function.child)), node_create('c', 2.0))); + /* + * Apply rule of cotangent function derivative. + */ + else if (!strcmp(node->data.function.record->name, "Ctan")) + return node_create('u', '-', node_create('b', '/', node_derivative(node->data.function.child, name, symbol_table), node_create('b', '^', node_create('f', symbol_table_lookup(symbol_table, "Sin"), node_copy(node->data.function.child)), node_create('c', 2.0)))); + /* + * Apply rule of inverse sine function derivative. + */ + else if (!strcmp(node->data.function.record->name, "Asin")) + return node_create('b', '/', node_derivative(node->data.function.child, name, symbol_table), node_create('f', symbol_table_lookup(symbol_table, "Sqrt"), node_create('b', '-', node_create('c', 1.0), node_create('b', '^', node_copy(node->data.function.child), node_create('c', 2.0))))); + /* + * Apply rule of inverse cosine function derivative. + */ + else if (!strcmp(node->data.function.record->name, "Acos")) + return node_create('u', '-', node_create('b', '/', node_derivative(node->data.function.child, name, symbol_table), node_create('f', symbol_table_lookup(symbol_table, "Sqrt"), node_create('b', '-', node_create('c', 1.0), node_create('b', '^', node_copy(node->data.function.child), node_create('c', 2.0)))))); + /* + * Apply rule of inverse tangent function derivative. + */ + else if (!strcmp(node->data.function.record->name, "Atan")) + return node_create('b', '/', node_derivative(node->data.function.child, name, symbol_table), node_create('b', '+', node_create('c', 1.0), node_create('b', '^', node_copy(node->data.function.child), node_create('c', 2.0)))); + /* + * Apply rule of inverse cotanget function derivative. + */ + else if (!strcmp(node->data.function.record->name, "Actan")) + return node_create('u', '-', node_create('b', '/', node_derivative(node->data.function.child, name, symbol_table), node_create('b', '+', node_create('c', 1.0), node_create('b', '^', node_copy(node->data.function.child), node_create('c', 2.0))))); + /* + * Apply rule of hyperbolic sine function derivative. + */ + else if (!strcmp(node->data.function.record->name, "Sinh")) + return node_create('b', '*', node_derivative(node->data.function.child, name, symbol_table), node_create('f', symbol_table_lookup(symbol_table, "Cosh"), node_copy(node->data.function.child))); + /* + * Apply rule of hyperbolic cosine function derivative. + */ + else if (!strcmp(node->data.function.record->name, "Cosh")) + return node_create('b', '*', node_derivative(node->data.function.child, name, symbol_table), node_create('f', symbol_table_lookup(symbol_table, "Sinh"), node_copy(node->data.function.child))); + /* + * Apply rule of hyperbolic tangent function derivative. + */ + else if (!strcmp(node->data.function.record->name, "Tanh")) + return node_create('b', '/', node_derivative(node->data.function.child, name, symbol_table), node_create('b', '^', node_create('f', symbol_table_lookup(symbol_table, "Cosh"), node_copy(node->data.function.child)), node_create('c', 2.0))); + /* + * Apply rule of hyperbolic cotangent function derivative. + */ + else if (!strcmp(node->data.function.record->name, "Ctanh")) + return node_create('u', '-', node_create('b', '/', node_derivative(node->data.function.child, name, symbol_table), node_create('b', '^', node_create('f', symbol_table_lookup(symbol_table, "sinh"), node_copy(node->data.function.child)), node_create('c', 2.0)))); + /* + * Apply rule of inverse hyperbolic sine function derivative. + */ + else if (!strcmp(node->data.function.record->name, "Asinh")) + return node_create('b', '/', node_derivative(node->data.function.child, name, symbol_table), node_create('f', symbol_table_lookup(symbol_table, "Sqrt"), node_create('b', '-', node_create('c', 1.0), node_create('b', '^', node_copy(node->data.function.child), node_create('c', 2.0))))); + /* + * Apply rule of inverse hyperbolic cosine function + * derivative. + */ + else if (!strcmp(node->data.function.record->name, "Acosh")) + return node_create('b', '/', node_derivative(node->data.function.child, name, symbol_table), node_create('f', symbol_table_lookup(symbol_table, "Sqrt"), node_create('b', '-', node_create('b', '^', node_copy(node->data.function.child), node_create('c', 2.0)), node_create('c', 1.0)))); + /* + * Apply rule of inverse hyperbolic tangent function + * derivative. + */ + else if (!strcmp(node->data.function.record->name, "Atanh")) + return node_create('b', '/', node_derivative(node->data.function.child, name, symbol_table), node_create('b', '-', node_create('c', 1.0), node_create('b', '^', node_copy(node->data.function.child), node_create('c', 2.0)))); + /* + * Apply rule of inverse hyperbolic cotangent function + * derivative. + */ + else if (!strcmp(node->data.function.record->name, "Actanh")) + return node_create('b', '/', node_derivative(node->data.function.child, name, symbol_table), node_create('b', '-', node_create('b', '^', node_copy(node->data.function.child), node_create('c', 2.0)), node_create('c', 1.0))); + /* + * Apply rule of absolute value function derivative. + */ + else if (!strcmp(node->data.function.record->name, "Fabs")) + return node_create('b', '/', node_create('b', '*', node_derivative(node->data.function.child, name, symbol_table), node_copy(node->data.function.child)), node_create('f', symbol_table_lookup(symbol_table, "Sqrt"), node_create('b', '^', node_copy(node->data.function.child), node_create('c', 2.0)))); + + case 'u': + switch (node->data.un_op.operatorr) { + case '-': + /* + * Apply (-f)'=-f' derivative rule. + */ + return node_create('u', '-', node_derivative(node->data.un_op.child, name, symbol_table)); + } + + case 'b': + switch (node->data.bin_op.operatorr) { + case '+': + /* + * Apply (f+g)'=f'+g' derivative rule. + */ + return node_create('b', '+', node_derivative(node->data.bin_op.left, name, symbol_table), node_derivative(node->data.bin_op.right, name, symbol_table)); + + case '-': + /* + * Apply (f-g)'=f'-g' derivative rule. + */ + return node_create('b', '-', node_derivative(node->data.bin_op.left, name, symbol_table), node_derivative(node->data.bin_op.right, name, symbol_table)); + + case '*': + /* + * Apply (f*g)'=f'*g+f*g' derivative rule. + */ + return node_create('b', '+', node_create('b', '*', node_derivative(node->data.bin_op.left, name, symbol_table), node_copy(node->data.bin_op.right)), node_create('b', '*', node_copy(node->data.bin_op.left), node_derivative(node->data.bin_op.right, name, symbol_table))); + + case '/': + /* + * Apply (f/g)'=(f'*g-f*g')/g^2 derivative rule. + */ + return node_create('b', '/', node_create('b', '-', node_create('b', '*', node_derivative(node->data.bin_op.left, name, symbol_table), node_copy(node->data.bin_op.right)), node_create('b', '*', node_copy(node->data.bin_op.left), node_derivative(node->data.bin_op.right, name, symbol_table))), node_create('b', '^', node_copy(node->data.bin_op.right), node_create('c', 2.0))); + + case '^': + /* + * If right operand of exponentiation constant apply + * (f^n)'=n*f^(n-1)*f' derivative rule. + */ + if (node->data.bin_op.right->type == 'c') + return node_create('b', '*', node_create('b', '*', node_create('c', node->data.bin_op.right->data.constant), node_derivative(node->data.bin_op.left, name, symbol_table)), node_create('b', '^', node_copy(node->data.bin_op.left), node_create('c', node->data.bin_op.right->data.constant - 1.0))); + /* + * Otherwise, apply logaritmhic derivative rule: + * (log(f^g))'=(f^g)'/f^g => + * (f^g)'=f^g*(log(f^g))'=f^g*(g*log(f))' + */ + else { + Node *log_node, *derivative; + log_node = node_create('b', '*', node_copy(node->data.bin_op.right), node_create('f', symbol_table_lookup(symbol_table, "Log"), node_copy(node->data.bin_op.left))); + derivative = node_create('b', '*', node_copy(node), node_derivative(log_node, name, symbol_table)); + node_destroy(log_node); + return derivative; + } + } + } + + return NULL; +} + +int +node_calculate_length(Node * node) +{ + char string[1024]; /* String representing constant node + * value. */ + int length; /* Length of above string. */ + + /* + * According to node type, calculate length of string representing + * subtree rooted at node. + */ + switch (node->type) { + case 'c': + length = 0; + if (node->data.constant < 0) + length += 1; + sprintf(string, "%g", node->data.constant); + length += strlen(string); + if (node->data.constant < 0) + length += 1; + return length; + + case 'v': + return strlen(node->data.variable->name); + + case 'f': + return strlen(node->data.function.record->name) + 1 + node_calculate_length(node->data.function.child) + 1; + break; + + case 'u': + return 1 + 1 + node_calculate_length(node->data.un_op.child) + 1; + + case 'b': + return 1 + node_calculate_length(node->data.bin_op.left) + 1 + node_calculate_length(node->data.bin_op.right) + 1; + } + + return 0; +} + +void +node_write(Node * node, char *string) +{ + /* + * According to node type, write subtree rooted at node to node + * string variable. Always use parenthesis to resolve operator + * precedence. + */ + switch (node->type) { + case 'c': + if (node->data.constant < 0) { + sprintf(string, "%c", '('); + string += strlen(string); + } + sprintf(string, "%g", node->data.constant); + string += strlen(string); + if (node->data.constant < 0) + sprintf(string, "%c", ')'); + break; + + case 'v': + sprintf(string, "%s", node->data.variable->name); + break; + + case 'f': + sprintf(string, "%s%c", node->data.function.record->name, '('); + string += strlen(string); + node_write(node->data.function.child, string); + string += strlen(string); + sprintf(string, "%c", ')'); + break; + + case 'u': + sprintf(string, "%c", '('); + string += strlen(string); + sprintf(string, "%c", node->data.un_op.operatorr); + string += strlen(string); + node_write(node->data.un_op.child, string); + string += strlen(string); + sprintf(string, "%c", ')'); + break; + + case 'b': + sprintf(string, "%c", '('); + string += strlen(string); + node_write(node->data.bin_op.left, string); + string += strlen(string); + sprintf(string, "%c", node->data.bin_op.operatorr); + string += strlen(string); + node_write(node->data.bin_op.right, string); + string += strlen(string); + sprintf(string, "%c", ')'); + break; + } +} diff --git a/contrib/MathEval/node.h b/contrib/MathEval/node.h new file mode 100644 index 0000000000..c2744aae19 --- /dev/null +++ b/contrib/MathEval/node.h @@ -0,0 +1,111 @@ +/* + * Copyright (C) 1999, 2002, 2003 Free Software Foundation, Inc. + * + * This file is part of GNU libmatheval + * + * GNU libmatheval 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. + * + * GNU libmatheval 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 + * program; see the file COPYING. If not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* This file was modified for inclusion in Gmsh */ + +#ifndef NODE_H +#define NODE_H 1 + +#include "symbol_table.h" + +/* Data structure representing function tree node. */ +typedef struct _Node { + char type; /* Node type ('c' for constant, 'v' for + * variable, 'f' for function, 'u' for unary + * operator, 'b' for binary operator). */ + union { + double constant; /* Constant value. */ + Record *variable; /* Symbol table record for + * variable. */ + struct { + Record *record; /* Symbol table record for + * function. */ + struct _Node *child; /* Function argument node. */ + } function; /* Structure representing + * function. */ + struct { + char operatorr;/* Operator type ('-' + * for unary minus). */ + struct _Node *child; /* Operand node. */ + } un_op; /* Structure representing unary + * operator. */ + struct { + char operatorr;/* Operator type ('+' + * for adition, '-' for + * subtraction, '*' for + * multiplication, '/' + * for division and '^' + * for exponentiation). */ + struct _Node *left, *right; /* Operands nodes. */ + } bin_op; /* Structure representing binary + * operator. */ + } data; +} Node; + +/* + * Create node of given type and initialize it from optional arguments. + * Function returns pointer to node object that should be passed as first + * argument to all other node functions. + */ +Node *node_create(char type,...); + +/* Destroy subtree rooted at specified node. */ +void node_destroy(Node * node); + +/* + * Make a copy of subtree rooted at given node. Deep copy operation is + * employed. + */ +Node *node_copy(Node * node); + +/* + * Simplify subtree rooted at given node. Function returns root of + * simplified subtree (that may or may not be original node). + */ +Node *node_simplify(Node * node); + +/* + * Evaluate subtree rooted at given node. For variables, values from symbol + * table are used. + */ +double node_evaluate(Node * node); + +/* + * Create derivative tree for subtree rooted at given node. Second argument + * is derivation variable, third argument is symbol table (needed for + * functions derivatives). Function returns root of corresponding derivation + * tree. + */ +Node *node_derivative(Node * node, char *name, SymbolTable * symbol_table); + +/* + * Calculate length of the string representing subtree rooted at specified + * node. + */ +int node_calculate_length(Node * node); + +/* + * Write subtree rooted at specified node to given string variable. No + * checking of string overflow is done by this procedure; it is expected that + * string of appropriate length is passed as argument. + */ +void node_write(Node * node, char *string); + +#endif diff --git a/contrib/MathEval/parser.tab.cpp b/contrib/MathEval/parser.tab.cpp new file mode 100644 index 0000000000..87a34199c0 --- /dev/null +++ b/contrib/MathEval/parser.tab.cpp @@ -0,0 +1,1044 @@ + +/* A Bison parser, made from parser.y + by GNU Bison version 1.28 */ + +#define YYBISON 1 /* Identify Bison output. */ + +#define yyparse meparse +#define yylex melex +#define yyerror meerror +#define yylval melval +#define yychar mechar +#define yydebug medebug +#define yynerrs menerrs +#define NUMBER 257 +#define VARIABLE 258 +#define FUNCTION 259 +#define NEG 260 + +#line 1 "parser.y" + +/* + * Copyright (C) 1999, 2002, 2003 Free Software Foundation, Inc. + * + * This file is part of GNU libmatheval + * + * GNU libmatheval 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. + * + * GNU libmatheval 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 program; see the file COPYING. If not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + * USA. + */ + +/* This file was modified for inclusion in Gmsh */ + +#include "common.h" +#include "node.h" + +/* Variables used to communicate with code using parser. */ +extern Node* matheval_root; /* Root of tree representation of function. */ +extern int matheval_ok; /* Flag representing success of parsing. */ + +/* Report parsing error. */ +int yyerror (char *s); + +/* Function used to tokenize string representing function (this function + is generated by scanner generator). */ +int yylex (void); + +/* Function used to flush the internal flex buffer when we exit + prematurely (i.e., in case of a parse error) so that the next time + we call the scanner, all is nicely reset. Without this, the + behaviour of the next call after an error is unpredictable. */ +void force_buffer_flush(void); + + +#line 48 "parser.y" +typedef union { + Node *node; + Record *record; +} YYSTYPE; +#include <stdio.h> + +#ifndef __cplusplus +#ifndef __STDC__ +#define const +#endif +#endif + + + +#define YYFINAL 26 +#define YYFLAG -32768 +#define YYNTBASE 15 + +#define YYTRANSLATE(x) ((unsigned)(x) <= 260 ? yytranslate[x] : 17) + +static const char yytranslate[] = { 0, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 12, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 13, + 14, 8, 7, 2, 6, 2, 9, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 11, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 1, 3, 4, 5, 10 +}; + +#if YYDEBUG != 0 +static const short yyprhs[] = { 0, + 0, 3, 5, 7, 11, 15, 19, 23, 26, 30, + 35 +}; + +static const short yyrhs[] = { 16, + 12, 0, 3, 0, 4, 0, 16, 7, 16, 0, + 16, 6, 16, 0, 16, 8, 16, 0, 16, 9, + 16, 0, 6, 16, 0, 16, 11, 16, 0, 5, + 13, 16, 14, 0, 13, 16, 14, 0 +}; + +#endif + +#if YYDEBUG != 0 +static const short yyrline[] = { 0, + 71, 78, 81, 84, 88, 92, 96, 100, 104, 108, + 112 +}; +#endif + + +#if YYDEBUG != 0 || defined (YYERROR_VERBOSE) + +static const char * const yytname[] = { "$","error","$undefined.","NUMBER", +"VARIABLE","FUNCTION","'-'","'+'","'*'","'/'","NEG","'^'","'\\n'","'('","')'", +"input","expression", NULL +}; +#endif + +static const short yyr1[] = { 0, + 15, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16 +}; + +static const short yyr2[] = { 0, + 2, 1, 1, 3, 3, 3, 3, 2, 3, 4, + 3 +}; + +static const short yydefact[] = { 0, + 2, 3, 0, 0, 0, 0, 0, 8, 0, 0, + 0, 0, 0, 0, 1, 0, 11, 5, 4, 6, + 7, 9, 10, 0, 0, 0 +}; + +static const short yydefgoto[] = { 24, + 6 +}; + +static const short yypact[] = { 8, +-32768,-32768, -11, 8, 8, 27, 8, -7, 9, 8, + 8, 8, 8, 8,-32768, 18,-32768, 32, 32, -7, + -7,-32768,-32768, 5, 19,-32768 +}; + +static const short yypgoto[] = {-32768, + -4 +}; + + +#define YYLAST 43 + + +static const short yytable[] = { 8, + 9, 7, 16, 14, 25, 18, 19, 20, 21, 22, + 1, 2, 3, 4, 10, 11, 12, 13, 26, 14, + 5, 0, 17, 10, 11, 12, 13, 0, 14, 0, + 0, 23, 10, 11, 12, 13, 0, 14, 15, 12, + 13, 0, 14 +}; + +static const short yycheck[] = { 4, + 5, 13, 7, 11, 0, 10, 11, 12, 13, 14, + 3, 4, 5, 6, 6, 7, 8, 9, 0, 11, + 13, -1, 14, 6, 7, 8, 9, -1, 11, -1, + -1, 14, 6, 7, 8, 9, -1, 11, 12, 8, + 9, -1, 11 +}; +/* -*-C-*- Note some compilers choke on comments on `#line' lines. */ +#line 3 "/usr/share/bison.simple" +/* This file comes from bison-1.28. */ + +/* Skeleton output parser for bison, + Copyright (C) 1984, 1989, 1990 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +/* As a special exception, when this file is copied by Bison into a + Bison output file, you may use that output file without restriction. + This special exception was added by the Free Software Foundation + in version 1.24 of Bison. */ + +/* This is the parser code that is written into each bison parser + when the %semantic_parser declaration is not specified in the grammar. + It was written by Richard Stallman by simplifying the hairy parser + used when %semantic_parser is specified. */ + +#ifndef YYSTACK_USE_ALLOCA +#ifdef alloca +#define YYSTACK_USE_ALLOCA +#else /* alloca not defined */ +#ifdef __GNUC__ +#define YYSTACK_USE_ALLOCA +#define alloca __builtin_alloca +#else /* not GNU C. */ +#if (!defined (__STDC__) && defined (sparc)) || defined (__sparc__) || defined (__sparc) || defined (__sgi) || (defined (__sun) && defined (__i386)) +#define YYSTACK_USE_ALLOCA +#include <alloca.h> +#else /* not sparc */ +/* We think this test detects Watcom and Microsoft C. */ +/* This used to test MSDOS, but that is a bad idea + since that symbol is in the user namespace. */ +#if (defined (_MSDOS) || defined (_MSDOS_)) && !defined (__TURBOC__) +#if 0 /* No need for malloc.h, which pollutes the namespace; + instead, just don't use alloca. */ +#include <malloc.h> +#endif +#else /* not MSDOS, or __TURBOC__ */ +#if defined(_AIX) +/* I don't know what this was needed for, but it pollutes the namespace. + So I turned it off. rms, 2 May 1997. */ +/* #include <malloc.h> */ + #pragma alloca +#define YYSTACK_USE_ALLOCA +#else /* not MSDOS, or __TURBOC__, or _AIX */ +#if 0 +#ifdef __hpux /* haible@ilog.fr says this works for HPUX 9.05 and up, + and on HPUX 10. Eventually we can turn this on. */ +#define YYSTACK_USE_ALLOCA +#define alloca __builtin_alloca +#endif /* __hpux */ +#endif +#endif /* not _AIX */ +#endif /* not MSDOS, or __TURBOC__ */ +#endif /* not sparc */ +#endif /* not GNU C */ +#endif /* alloca not defined */ +#endif /* YYSTACK_USE_ALLOCA not defined */ + +#ifdef YYSTACK_USE_ALLOCA +#define YYSTACK_ALLOC alloca +#else +#define YYSTACK_ALLOC malloc +#endif + +/* Note: there must be only one dollar sign in this file. + It is replaced by the list of actions, each action + as one case of the switch. */ + +#define yyerrok (yyerrstatus = 0) +#define yyclearin (yychar = YYEMPTY) +#define YYEMPTY -2 +#define YYEOF 0 +#define YYACCEPT goto yyacceptlab +#define YYABORT goto yyabortlab +#define YYERROR goto yyerrlab1 +/* Like YYERROR except do call yyerror. + This remains here temporarily to ease the + transition to the new meaning of YYERROR, for GCC. + Once GCC version 2 has supplanted version 1, this can go. */ +#define YYFAIL goto yyerrlab +#define YYRECOVERING() (!!yyerrstatus) +#define YYBACKUP(token, value) \ +do \ + if (yychar == YYEMPTY && yylen == 1) \ + { yychar = (token), yylval = (value); \ + yychar1 = YYTRANSLATE (yychar); \ + YYPOPSTACK; \ + goto yybackup; \ + } \ + else \ + { yyerror ("syntax error: cannot back up"); YYERROR; } \ +while (0) + +#define YYTERROR 1 +#define YYERRCODE 256 + +#ifndef YYPURE +#define YYLEX yylex() +#endif + +#ifdef YYPURE +#ifdef YYLSP_NEEDED +#ifdef YYLEX_PARAM +#define YYLEX yylex(&yylval, &yylloc, YYLEX_PARAM) +#else +#define YYLEX yylex(&yylval, &yylloc) +#endif +#else /* not YYLSP_NEEDED */ +#ifdef YYLEX_PARAM +#define YYLEX yylex(&yylval, YYLEX_PARAM) +#else +#define YYLEX yylex(&yylval) +#endif +#endif /* not YYLSP_NEEDED */ +#endif + +/* If nonreentrant, generate the variables here */ + +#ifndef YYPURE + +int yychar; /* the lookahead symbol */ +YYSTYPE yylval; /* the semantic value of the */ + /* lookahead symbol */ + +#ifdef YYLSP_NEEDED +YYLTYPE yylloc; /* location data for the lookahead */ + /* symbol */ +#endif + +int yynerrs; /* number of parse errors so far */ +#endif /* not YYPURE */ + +#if YYDEBUG != 0 +int yydebug; /* nonzero means print parse trace */ +/* Since this is uninitialized, it does not stop multiple parsers + from coexisting. */ +#endif + +/* YYINITDEPTH indicates the initial size of the parser's stacks */ + +#ifndef YYINITDEPTH +#define YYINITDEPTH 200 +#endif + +/* YYMAXDEPTH is the maximum size the stacks can grow to + (effective only if the built-in stack extension method is used). */ + +#if YYMAXDEPTH == 0 +#undef YYMAXDEPTH +#endif + +#ifndef YYMAXDEPTH +#define YYMAXDEPTH 10000 +#endif + +/* Define __yy_memcpy. Note that the size argument + should be passed with type unsigned int, because that is what the non-GCC + definitions require. With GCC, __builtin_memcpy takes an arg + of type size_t, but it can handle unsigned int. */ + +#if __GNUC__ > 1 /* GNU C and GNU C++ define this. */ +#define __yy_memcpy(TO,FROM,COUNT) __builtin_memcpy(TO,FROM,COUNT) +#else /* not GNU C or C++ */ +#ifndef __cplusplus + +/* This is the most reliable way to avoid incompatibilities + in available built-in functions on various systems. */ +static void +__yy_memcpy (to, from, count) + char *to; + char *from; + unsigned int count; +{ + register char *f = from; + register char *t = to; + register int i = count; + + while (i-- > 0) + *t++ = *f++; +} + +#else /* __cplusplus */ + +/* This is the most reliable way to avoid incompatibilities + in available built-in functions on various systems. */ +static void +__yy_memcpy (char *to, char *from, unsigned int count) +{ + register char *t = to; + register char *f = from; + register int i = count; + + while (i-- > 0) + *t++ = *f++; +} + +#endif +#endif + +#line 217 "/usr/share/bison.simple" + +/* The user can define YYPARSE_PARAM as the name of an argument to be passed + into yyparse. The argument should have type void *. + It should actually point to an object. + Grammar actions can access the variable by casting it + to the proper pointer type. */ + +#ifdef YYPARSE_PARAM +#ifdef __cplusplus +#define YYPARSE_PARAM_ARG void *YYPARSE_PARAM +#define YYPARSE_PARAM_DECL +#else /* not __cplusplus */ +#define YYPARSE_PARAM_ARG YYPARSE_PARAM +#define YYPARSE_PARAM_DECL void *YYPARSE_PARAM; +#endif /* not __cplusplus */ +#else /* not YYPARSE_PARAM */ +#define YYPARSE_PARAM_ARG +#define YYPARSE_PARAM_DECL +#endif /* not YYPARSE_PARAM */ + +/* Prevent warning if -Wstrict-prototypes. */ +#ifdef __GNUC__ +#ifdef YYPARSE_PARAM +int yyparse (void *); +#else +int yyparse (void); +#endif +#endif + +int +yyparse(YYPARSE_PARAM_ARG) + YYPARSE_PARAM_DECL +{ + register int yystate; + register int yyn; + register short *yyssp; + register YYSTYPE *yyvsp; + int yyerrstatus; /* number of tokens to shift before error messages enabled */ + int yychar1 = 0; /* lookahead token as an internal (translated) token number */ + + short yyssa[YYINITDEPTH]; /* the state stack */ + YYSTYPE yyvsa[YYINITDEPTH]; /* the semantic value stack */ + + short *yyss = yyssa; /* refer to the stacks thru separate pointers */ + YYSTYPE *yyvs = yyvsa; /* to allow yyoverflow to reallocate them elsewhere */ + +#ifdef YYLSP_NEEDED + YYLTYPE yylsa[YYINITDEPTH]; /* the location stack */ + YYLTYPE *yyls = yylsa; + YYLTYPE *yylsp; + +#define YYPOPSTACK (yyvsp--, yyssp--, yylsp--) +#else +#define YYPOPSTACK (yyvsp--, yyssp--) +#endif + + int yystacksize = YYINITDEPTH; + int yyfree_stacks = 0; + +#ifdef YYPURE + int yychar; + YYSTYPE yylval; + int yynerrs; +#ifdef YYLSP_NEEDED + YYLTYPE yylloc; +#endif +#endif + + YYSTYPE yyval; /* the variable used to return */ + /* semantic values from the action */ + /* routines */ + + int yylen; + +#if YYDEBUG != 0 + if (yydebug) + fprintf(stderr, "Starting parse\n"); +#endif + + yystate = 0; + yyerrstatus = 0; + yynerrs = 0; + yychar = YYEMPTY; /* Cause a token to be read. */ + + /* Initialize stack pointers. + Waste one element of value and location stack + so that they stay on the same level as the state stack. + The wasted elements are never initialized. */ + + yyssp = yyss - 1; + yyvsp = yyvs; +#ifdef YYLSP_NEEDED + yylsp = yyls; +#endif + +/* Push a new state, which is found in yystate . */ +/* In all cases, when you get here, the value and location stacks + have just been pushed. so pushing a state here evens the stacks. */ +yynewstate: + + *++yyssp = yystate; + + if (yyssp >= yyss + yystacksize - 1) + { + /* Give user a chance to reallocate the stack */ + /* Use copies of these so that the &'s don't force the real ones into memory. */ + YYSTYPE *yyvs1 = yyvs; + short *yyss1 = yyss; +#ifdef YYLSP_NEEDED + YYLTYPE *yyls1 = yyls; +#endif + + /* Get the current used size of the three stacks, in elements. */ + int size = yyssp - yyss + 1; + +#ifdef yyoverflow + /* Each stack pointer address is followed by the size of + the data in use in that stack, in bytes. */ +#ifdef YYLSP_NEEDED + /* This used to be a conditional around just the two extra args, + but that might be undefined if yyoverflow is a macro. */ + yyoverflow("parser stack overflow", + &yyss1, size * sizeof (*yyssp), + &yyvs1, size * sizeof (*yyvsp), + &yyls1, size * sizeof (*yylsp), + &yystacksize); +#else + yyoverflow("parser stack overflow", + &yyss1, size * sizeof (*yyssp), + &yyvs1, size * sizeof (*yyvsp), + &yystacksize); +#endif + + yyss = yyss1; yyvs = yyvs1; +#ifdef YYLSP_NEEDED + yyls = yyls1; +#endif +#else /* no yyoverflow */ + /* Extend the stack our own way. */ + if (yystacksize >= YYMAXDEPTH) + { + yyerror("parser stack overflow"); + if (yyfree_stacks) + { + free (yyss); + free (yyvs); +#ifdef YYLSP_NEEDED + free (yyls); +#endif + } + return 2; + } + yystacksize *= 2; + if (yystacksize > YYMAXDEPTH) + yystacksize = YYMAXDEPTH; +#ifndef YYSTACK_USE_ALLOCA + yyfree_stacks = 1; +#endif + yyss = (short *) YYSTACK_ALLOC (yystacksize * sizeof (*yyssp)); + __yy_memcpy ((char *)yyss, (char *)yyss1, + size * (unsigned int) sizeof (*yyssp)); + yyvs = (YYSTYPE *) YYSTACK_ALLOC (yystacksize * sizeof (*yyvsp)); + __yy_memcpy ((char *)yyvs, (char *)yyvs1, + size * (unsigned int) sizeof (*yyvsp)); +#ifdef YYLSP_NEEDED + yyls = (YYLTYPE *) YYSTACK_ALLOC (yystacksize * sizeof (*yylsp)); + __yy_memcpy ((char *)yyls, (char *)yyls1, + size * (unsigned int) sizeof (*yylsp)); +#endif +#endif /* no yyoverflow */ + + yyssp = yyss + size - 1; + yyvsp = yyvs + size - 1; +#ifdef YYLSP_NEEDED + yylsp = yyls + size - 1; +#endif + +#if YYDEBUG != 0 + if (yydebug) + fprintf(stderr, "Stack size increased to %d\n", yystacksize); +#endif + + if (yyssp >= yyss + yystacksize - 1) + YYABORT; + } + +#if YYDEBUG != 0 + if (yydebug) + fprintf(stderr, "Entering state %d\n", yystate); +#endif + + goto yybackup; + yybackup: + +/* Do appropriate processing given the current state. */ +/* Read a lookahead token if we need one and don't already have one. */ +/* yyresume: */ + + /* First try to decide what to do without reference to lookahead token. */ + + yyn = yypact[yystate]; + if (yyn == YYFLAG) + goto yydefault; + + /* Not known => get a lookahead token if don't already have one. */ + + /* yychar is either YYEMPTY or YYEOF + or a valid token in external form. */ + + if (yychar == YYEMPTY) + { +#if YYDEBUG != 0 + if (yydebug) + fprintf(stderr, "Reading a token: "); +#endif + yychar = YYLEX; + } + + /* Convert token to internal form (in yychar1) for indexing tables with */ + + if (yychar <= 0) /* This means end of input. */ + { + yychar1 = 0; + yychar = YYEOF; /* Don't call YYLEX any more */ + +#if YYDEBUG != 0 + if (yydebug) + fprintf(stderr, "Now at end of input.\n"); +#endif + } + else + { + yychar1 = YYTRANSLATE(yychar); + +#if YYDEBUG != 0 + if (yydebug) + { + fprintf (stderr, "Next token is %d (%s", yychar, yytname[yychar1]); + /* Give the individual parser a way to print the precise meaning + of a token, for further debugging info. */ +#ifdef YYPRINT + YYPRINT (stderr, yychar, yylval); +#endif + fprintf (stderr, ")\n"); + } +#endif + } + + yyn += yychar1; + if (yyn < 0 || yyn > YYLAST || yycheck[yyn] != yychar1) + goto yydefault; + + yyn = yytable[yyn]; + + /* yyn is what to do for this token type in this state. + Negative => reduce, -yyn is rule number. + Positive => shift, yyn is new state. + New state is final state => don't bother to shift, + just return success. + 0, or most negative number => error. */ + + if (yyn < 0) + { + if (yyn == YYFLAG) + goto yyerrlab; + yyn = -yyn; + goto yyreduce; + } + else if (yyn == 0) + goto yyerrlab; + + if (yyn == YYFINAL) + YYACCEPT; + + /* Shift the lookahead token. */ + +#if YYDEBUG != 0 + if (yydebug) + fprintf(stderr, "Shifting token %d (%s), ", yychar, yytname[yychar1]); +#endif + + /* Discard the token being shifted unless it is eof. */ + if (yychar != YYEOF) + yychar = YYEMPTY; + + *++yyvsp = yylval; +#ifdef YYLSP_NEEDED + *++yylsp = yylloc; +#endif + + /* count tokens shifted since error; after three, turn off error status. */ + if (yyerrstatus) yyerrstatus--; + + yystate = yyn; + goto yynewstate; + +/* Do the default action for the current state. */ +yydefault: + + yyn = yydefact[yystate]; + if (yyn == 0) + goto yyerrlab; + +/* Do a reduction. yyn is the number of a rule to reduce with. */ +yyreduce: + yylen = yyr2[yyn]; + if (yylen > 0) + yyval = yyvsp[1-yylen]; /* implement default value of the action */ + +#if YYDEBUG != 0 + if (yydebug) + { + int i; + + fprintf (stderr, "Reducing via rule %d (line %d), ", + yyn, yyrline[yyn]); + + /* Print the symbols being reduced, and their result. */ + for (i = yyprhs[yyn]; yyrhs[i] > 0; i++) + fprintf (stderr, "%s ", yytname[yyrhs[i]]); + fprintf (stderr, " -> %s\n", yytname[yyr1[yyn]]); + } +#endif + + + switch (yyn) { + +case 1: +#line 71 "parser.y" +{ + matheval_root = yyvsp[-1].node; + return 1; +; + break;} +case 2: +#line 78 "parser.y" +{ + yyval.node = yyvsp[0].node; +; + break;} +case 3: +#line 81 "parser.y" +{ + yyval.node = yyvsp[0].node; +; + break;} +case 4: +#line 84 "parser.y" +{ + /* Create addition binary operator node. */ + yyval.node = node_create ('b', '+', yyvsp[-2].node, yyvsp[0].node); +; + break;} +case 5: +#line 88 "parser.y" +{ + /* Create subtraction binary operator node. */ + yyval.node = node_create ('b', '-', yyvsp[-2].node, yyvsp[0].node); +; + break;} +case 6: +#line 92 "parser.y" +{ + /* Create multiplication binary operator node. */ + yyval.node = node_create ('b', '*', yyvsp[-2].node, yyvsp[0].node); +; + break;} +case 7: +#line 96 "parser.y" +{ + /* Create division binary operator node. */ + yyval.node = node_create ('b', '/', yyvsp[-2].node, yyvsp[0].node); +; + break;} +case 8: +#line 100 "parser.y" +{ + /* Create minus unary operator node. */ + yyval.node = node_create ('u', '-', yyvsp[0].node); +; + break;} +case 9: +#line 104 "parser.y" +{ + /* Create exponentiation unary operator node. */ + yyval.node = node_create ('b', '^', yyvsp[-2].node, yyvsp[0].node); +; + break;} +case 10: +#line 108 "parser.y" +{ + /* Create function node. */ + yyval.node = node_create ('f', yyvsp[-3].record, yyvsp[-1].node); +; + break;} +case 11: +#line 112 "parser.y" +{ + yyval.node = yyvsp[-1].node; +; + break;} +} + /* the action file gets copied in in place of this dollarsign */ +#line 543 "/usr/share/bison.simple" + + yyvsp -= yylen; + yyssp -= yylen; +#ifdef YYLSP_NEEDED + yylsp -= yylen; +#endif + +#if YYDEBUG != 0 + if (yydebug) + { + short *ssp1 = yyss - 1; + fprintf (stderr, "state stack now"); + while (ssp1 != yyssp) + fprintf (stderr, " %d", *++ssp1); + fprintf (stderr, "\n"); + } +#endif + + *++yyvsp = yyval; + +#ifdef YYLSP_NEEDED + yylsp++; + if (yylen == 0) + { + yylsp->first_line = yylloc.first_line; + yylsp->first_column = yylloc.first_column; + yylsp->last_line = (yylsp-1)->last_line; + yylsp->last_column = (yylsp-1)->last_column; + yylsp->text = 0; + } + else + { + yylsp->last_line = (yylsp+yylen-1)->last_line; + yylsp->last_column = (yylsp+yylen-1)->last_column; + } +#endif + + /* Now "shift" the result of the reduction. + Determine what state that goes to, + based on the state we popped back to + and the rule number reduced by. */ + + yyn = yyr1[yyn]; + + yystate = yypgoto[yyn - YYNTBASE] + *yyssp; + if (yystate >= 0 && yystate <= YYLAST && yycheck[yystate] == *yyssp) + yystate = yytable[yystate]; + else + yystate = yydefgoto[yyn - YYNTBASE]; + + goto yynewstate; + +yyerrlab: /* here on detecting error */ + + if (! yyerrstatus) + /* If not already recovering from an error, report this error. */ + { + ++yynerrs; + +#ifdef YYERROR_VERBOSE + yyn = yypact[yystate]; + + if (yyn > YYFLAG && yyn < YYLAST) + { + int size = 0; + char *msg; + int x, count; + + count = 0; + /* Start X at -yyn if nec to avoid negative indexes in yycheck. */ + for (x = (yyn < 0 ? -yyn : 0); + x < (sizeof(yytname) / sizeof(char *)); x++) + if (yycheck[x + yyn] == x) + size += strlen(yytname[x]) + 15, count++; + msg = (char *) malloc(size + 15); + if (msg != 0) + { + strcpy(msg, "parse error"); + + if (count < 5) + { + count = 0; + for (x = (yyn < 0 ? -yyn : 0); + x < (sizeof(yytname) / sizeof(char *)); x++) + if (yycheck[x + yyn] == x) + { + strcat(msg, count == 0 ? ", expecting `" : " or `"); + strcat(msg, yytname[x]); + strcat(msg, "'"); + count++; + } + } + yyerror(msg); + free(msg); + } + else + yyerror ("parse error; also virtual memory exceeded"); + } + else +#endif /* YYERROR_VERBOSE */ + yyerror("parse error"); + } + + goto yyerrlab1; +yyerrlab1: /* here on error raised explicitly by an action */ + + if (yyerrstatus == 3) + { + /* if just tried and failed to reuse lookahead token after an error, discard it. */ + + /* return failure if at end of input */ + if (yychar == YYEOF) + YYABORT; + +#if YYDEBUG != 0 + if (yydebug) + fprintf(stderr, "Discarding token %d (%s).\n", yychar, yytname[yychar1]); +#endif + + yychar = YYEMPTY; + } + + /* Else will try to reuse lookahead token + after shifting the error token. */ + + yyerrstatus = 3; /* Each real token shifted decrements this */ + + goto yyerrhandle; + +yyerrdefault: /* current state does not do anything special for the error token. */ + +#if 0 + /* This is wrong; only states that explicitly want error tokens + should shift them. */ + yyn = yydefact[yystate]; /* If its default is to accept any token, ok. Otherwise pop it.*/ + if (yyn) goto yydefault; +#endif + +yyerrpop: /* pop the current state because it cannot handle the error token */ + + if (yyssp == yyss) YYABORT; + yyvsp--; + yystate = *--yyssp; +#ifdef YYLSP_NEEDED + yylsp--; +#endif + +#if YYDEBUG != 0 + if (yydebug) + { + short *ssp1 = yyss - 1; + fprintf (stderr, "Error: state stack now"); + while (ssp1 != yyssp) + fprintf (stderr, " %d", *++ssp1); + fprintf (stderr, "\n"); + } +#endif + +yyerrhandle: + + yyn = yypact[yystate]; + if (yyn == YYFLAG) + goto yyerrdefault; + + yyn += YYTERROR; + if (yyn < 0 || yyn > YYLAST || yycheck[yyn] != YYTERROR) + goto yyerrdefault; + + yyn = yytable[yyn]; + if (yyn < 0) + { + if (yyn == YYFLAG) + goto yyerrpop; + yyn = -yyn; + goto yyreduce; + } + else if (yyn == 0) + goto yyerrpop; + + if (yyn == YYFINAL) + YYACCEPT; + +#if YYDEBUG != 0 + if (yydebug) + fprintf(stderr, "Shifting error token, "); +#endif + + *++yyvsp = yylval; +#ifdef YYLSP_NEEDED + *++yylsp = yylloc; +#endif + + yystate = yyn; + goto yynewstate; + + yyacceptlab: + /* YYACCEPT comes here. */ + if (yyfree_stacks) + { + free (yyss); + free (yyvs); +#ifdef YYLSP_NEEDED + free (yyls); +#endif + } + return 0; + + yyabortlab: + /* YYABORT comes here. */ + if (yyfree_stacks) + { + free (yyss); + free (yyvs); +#ifdef YYLSP_NEEDED + free (yyls); +#endif + } + return 1; +} +#line 117 "parser.y" + + +int yyerror(char* s) +{ + /* Indicate parsing error through appropriate flag and stop + parsing. */ + matheval_ok = 0; + force_buffer_flush(); + return 0; +} diff --git a/contrib/MathEval/parser.tab.hpp b/contrib/MathEval/parser.tab.hpp new file mode 100644 index 0000000000..561b245ad9 --- /dev/null +++ b/contrib/MathEval/parser.tab.hpp @@ -0,0 +1,11 @@ +typedef union { + Node *node; + Record *record; +} YYSTYPE; +#define NUMBER 257 +#define VARIABLE 258 +#define FUNCTION 259 +#define NEG 260 + + +extern YYSTYPE melval; diff --git a/contrib/MathEval/parser.y b/contrib/MathEval/parser.y new file mode 100644 index 0000000000..9b5817bf81 --- /dev/null +++ b/contrib/MathEval/parser.y @@ -0,0 +1,126 @@ +%{ +/* + * Copyright (C) 1999, 2002, 2003 Free Software Foundation, Inc. + * + * This file is part of GNU libmatheval + * + * GNU libmatheval 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. + * + * GNU libmatheval 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 program; see the file COPYING. If not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + * USA. + */ + +/* This file was modified for inclusion in Gmsh */ + +#include "common.h" +#include "node.h" + +/* Variables used to communicate with code using parser. */ +extern Node* matheval_root; /* Root of tree representation of function. */ +extern int matheval_ok; /* Flag representing success of parsing. */ + +/* Report parsing error. */ +int yyerror (char *s); + +/* Function used to tokenize string representing function (this function + is generated by scanner generator). */ +int yylex (void); + +/* Function used to flush the internal flex buffer when we exit + prematurely (i.e., in case of a parse error) so that the next time + we call the scanner, all is nicely reset. Without this, the + behaviour of the next call after an error is unpredictable. */ +void force_buffer_flush(void); + +%} + +/* Parser semantic values type. */ +%union { + Node *node; + Record *record; +} + +/* Grammar terminal symbols. */ +%token <node> NUMBER VARIABLE +%token <record> FUNCTION + +/* Grammar non-terminal symbols. */ +%type <node> expression + +%left '-' '+' +%left '*' '/' +%left NEG +%left '^' + +/* Grammar start non-terminal. */ +%start input + +%% + +input +: expression '\n' { + matheval_root = $1; + return 1; +} +; + +expression +: NUMBER { + $$ = $1; +} +| VARIABLE { + $$ = $1; +} +| expression '+' expression { + /* Create addition binary operator node. */ + $$ = node_create ('b', '+', $1, $3); +} +| expression '-' expression { + /* Create subtraction binary operator node. */ + $$ = node_create ('b', '-', $1, $3); +} +| expression '*' expression { + /* Create multiplication binary operator node. */ + $$ = node_create ('b', '*', $1, $3); +} +| expression '/' expression { + /* Create division binary operator node. */ + $$ = node_create ('b', '/', $1, $3); +} +| '-' expression %prec NEG { + /* Create minus unary operator node. */ + $$ = node_create ('u', '-', $2); +} +| expression '^' expression { + /* Create exponentiation unary operator node. */ + $$ = node_create ('b', '^', $1, $3); +} +| FUNCTION '(' expression ')' { + /* Create function node. */ + $$ = node_create ('f', $1, $3); +} +| '(' expression ')' { + $$ = $2; +} +; + +%% + +int yyerror(char* s) +{ + /* Indicate parsing error through appropriate flag and stop + parsing. */ + matheval_ok = 0; + force_buffer_flush(); + return 0; +} diff --git a/contrib/MathEval/scanner.l b/contrib/MathEval/scanner.l new file mode 100644 index 0000000000..0b92fa78c8 --- /dev/null +++ b/contrib/MathEval/scanner.l @@ -0,0 +1,130 @@ +%{ +/* + * Copyright (C) 1999, 2002, 2003 Free Software Foundation, Inc. + * + * This file is part of GNU libmatheval + * + * GNU libmatheval 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. + * + * GNU libmatheval 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 program; see the file COPYING. If not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + * USA. + */ + +/* This file was modified for inclusion in Gmsh */ + +#include "common.h" +#include "node.h" +#include "parser.tab.hpp" +#include "symbol_table.h" + +#define YY_ALWAYS_INTERACTIVE 1 + +/* Redefine macro to redirect scanner input from string instead of + standard input. */ +#define YY_INPUT( buffer, result, max_size ) \ +{ result = input_from_string (buffer, max_size); } + +/* Variables used to communicate with code using scanner. */ +extern SymbolTable *matheval_symbol_table; /* Evaluator symbol table. */ +extern char *matheval_input_string; /* String representing function. */ + +/* Read next max_size character from string into buffer. */ +static int input_from_string (char *buffer, int max_size); +%} + +/* Token definitions. */ +whitespace [\ \t]+ +digit [0-9] +number ({digit}+|{digit}+"."{digit}*|{digit}*"."{digit}+)([Ee][-+]?{digit}+)? +function "Exp"|"Log"|"Sqrt"|"Sin"|"Cos"|"Tan"|"Ctan"|"Asin"|"Acos"|"Atan"|"Actan"|"Sinh"|"Cosh"|"Tanh"|"Ctanh"|"Asinh"|"Acosh"|"Atanh"|"Actanh"|"Fabs"|"Rand" +identifier [a-zA-Z\_][a-zA-Z0-9\_]* + +%% + +{whitespace} + +{number} { + /* Create node representing constant with appropriate value. */ + melval.node = node_create ('c', atof (metext)); + return NUMBER; +} + +{function} { + /* Find symbol table record corresponding to function name. */ + melval.record = symbol_table_lookup (matheval_symbol_table, metext); + return FUNCTION; +} + +{identifier} { + Record *record; /* Symbol table record. */ + /* Inserty variable into symbol table. */ + record = symbol_table_insert (matheval_symbol_table, metext, 'v'); + melval.node = node_create ('v', record); + return VARIABLE; +} + +"+" { + return '+'; +} + +"-" { + return '-'; +} + +"*" { + return '*'; +} + +"/" { + return '/'; +} + +"^" { + return '^'; +} + +"(" { + return '('; +} + +")" { + return ')'; +} + +"\n" { + return '\n'; +} + +%% + +#undef mewrap + +int mewrap() { return 1; } + +static int input_from_string (char *buffer, int max_size) +{ + int count; /* Count of characters to copy from input string to buffer. */ + + /* Calculate count of characters to copy. */ + count = strlen (matheval_input_string); + if (count > max_size) + count = max_size; + + /* Perform copy operation and update input string. */ + memcpy(buffer, matheval_input_string, count); + matheval_input_string += count; + + return count; +} + +void force_buffer_flush() { YY_FLUSH_BUFFER; } diff --git a/contrib/MathEval/scanner.yy.cpp b/contrib/MathEval/scanner.yy.cpp new file mode 100644 index 0000000000..f23bb52aa5 --- /dev/null +++ b/contrib/MathEval/scanner.yy.cpp @@ -0,0 +1,1716 @@ +#define yy_create_buffer me_create_buffer +#define yy_delete_buffer me_delete_buffer +#define yy_scan_buffer me_scan_buffer +#define yy_scan_string me_scan_string +#define yy_scan_bytes me_scan_bytes +#define yy_flex_debug me_flex_debug +#define yy_init_buffer me_init_buffer +#define yy_flush_buffer me_flush_buffer +#define yy_load_buffer_state me_load_buffer_state +#define yy_switch_to_buffer me_switch_to_buffer +#define yyin mein +#define yyleng meleng +#define yylex melex +#define yyout meout +#define yyrestart merestart +#define yytext metext +#define yywrap mewrap + +#line 20 "scanner.yy.cpp" +/* A lexical scanner generated by flex */ + +/* Scanner skeleton version: + * $Header: /cvsroot/gmsh/contrib/MathEval/scanner.yy.cpp,v 1.1 2005-09-21 17:29:37 geuzaine Exp $ + */ + +#define FLEX_SCANNER +#define YY_FLEX_MAJOR_VERSION 2 +#define YY_FLEX_MINOR_VERSION 5 + +#include <stdio.h> + + +/* cfront 1.2 defines "c_plusplus" instead of "__cplusplus" */ +#ifdef c_plusplus +#ifndef __cplusplus +#define __cplusplus +#endif +#endif + + +#ifdef __cplusplus + +#include <stdlib.h> +#include <unistd.h> + +/* Use prototypes in function declarations. */ +#define YY_USE_PROTOS + +/* The "const" storage-class-modifier is valid. */ +#define YY_USE_CONST + +#else /* ! __cplusplus */ + +#if __STDC__ + +#define YY_USE_PROTOS +#define YY_USE_CONST + +#endif /* __STDC__ */ +#endif /* ! __cplusplus */ + +#ifdef __TURBOC__ + #pragma warn -rch + #pragma warn -use +#include <io.h> +#include <stdlib.h> +#define YY_USE_CONST +#define YY_USE_PROTOS +#endif + +#ifdef YY_USE_CONST +#define yyconst const +#else +#define yyconst +#endif + + +#ifdef YY_USE_PROTOS +#define YY_PROTO(proto) proto +#else +#define YY_PROTO(proto) () +#endif + +/* Returned upon end-of-file. */ +#define YY_NULL 0 + +/* Promotes a possibly negative, possibly signed char to an unsigned + * integer for use as an array index. If the signed char is negative, + * we want to instead treat it as an 8-bit unsigned char, hence the + * double cast. + */ +#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c) + +/* Enter a start condition. This macro really ought to take a parameter, + * but we do it the disgusting crufty way forced on us by the ()-less + * definition of BEGIN. + */ +#define BEGIN yy_start = 1 + 2 * + +/* Translate the current start state into a value that can be later handed + * to BEGIN to return to the state. The YYSTATE alias is for lex + * compatibility. + */ +#define YY_START ((yy_start - 1) / 2) +#define YYSTATE YY_START + +/* Action number for EOF rule of a given start state. */ +#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1) + +/* Special action meaning "start processing a new file". */ +#define YY_NEW_FILE yyrestart( yyin ) + +#define YY_END_OF_BUFFER_CHAR 0 + +/* Size of default input buffer. */ +#define YY_BUF_SIZE 16384 + +typedef struct yy_buffer_state *YY_BUFFER_STATE; + +extern int yyleng; +extern FILE *yyin, *yyout; + +#define EOB_ACT_CONTINUE_SCAN 0 +#define EOB_ACT_END_OF_FILE 1 +#define EOB_ACT_LAST_MATCH 2 + +/* The funky do-while in the following #define is used to turn the definition + * int a single C statement (which needs a semi-colon terminator). This + * avoids problems with code like: + * + * if ( condition_holds ) + * yyless( 5 ); + * else + * do_something_else(); + * + * Prior to using the do-while the compiler would get upset at the + * "else" because it interpreted the "if" statement as being all + * done when it reached the ';' after the yyless() call. + */ + +/* Return all but the first 'n' matched characters back to the input stream. */ + +#define yyless(n) \ + do \ + { \ + /* Undo effects of setting up yytext. */ \ + *yy_cp = yy_hold_char; \ + YY_RESTORE_YY_MORE_OFFSET \ + yy_c_buf_p = yy_cp = yy_bp + n - YY_MORE_ADJ; \ + YY_DO_BEFORE_ACTION; /* set up yytext again */ \ + } \ + while ( 0 ) + +#define unput(c) yyunput( c, yytext_ptr ) + +/* The following is because we cannot portably get our hands on size_t + * (without autoconf's help, which isn't available because we want + * flex-generated scanners to compile on their own). + */ +typedef unsigned int yy_size_t; + + +struct yy_buffer_state + { + FILE *yy_input_file; + + char *yy_ch_buf; /* input buffer */ + char *yy_buf_pos; /* current position in input buffer */ + + /* Size of input buffer in bytes, not including room for EOB + * characters. + */ + yy_size_t yy_buf_size; + + /* Number of characters read into yy_ch_buf, not including EOB + * characters. + */ + int yy_n_chars; + + /* Whether we "own" the buffer - i.e., we know we created it, + * and can realloc() it to grow it, and should free() it to + * delete it. + */ + int yy_is_our_buffer; + + /* Whether this is an "interactive" input source; if so, and + * if we're using stdio for input, then we want to use getc() + * instead of fread(), to make sure we stop fetching input after + * each newline. + */ + int yy_is_interactive; + + /* Whether we're considered to be at the beginning of a line. + * If so, '^' rules will be active on the next match, otherwise + * not. + */ + int yy_at_bol; + + /* Whether to try to fill the input buffer when we reach the + * end of it. + */ + int yy_fill_buffer; + + int yy_buffer_status; +#define YY_BUFFER_NEW 0 +#define YY_BUFFER_NORMAL 1 + /* When an EOF's been seen but there's still some text to process + * then we mark the buffer as YY_EOF_PENDING, to indicate that we + * shouldn't try reading from the input source any more. We might + * still have a bunch of tokens to match, though, because of + * possible backing-up. + * + * When we actually see the EOF, we change the status to "new" + * (via yyrestart()), so that the user can continue scanning by + * just pointing yyin at a new input file. + */ +#define YY_BUFFER_EOF_PENDING 2 + }; + +static YY_BUFFER_STATE yy_current_buffer = 0; + +/* We provide macros for accessing buffer states in case in the + * future we want to put the buffer states in a more general + * "scanner state". + */ +#define YY_CURRENT_BUFFER yy_current_buffer + + +/* yy_hold_char holds the character lost when yytext is formed. */ +static char yy_hold_char; + +static int yy_n_chars; /* number of characters read into yy_ch_buf */ + + +int yyleng; + +/* Points to current character in buffer. */ +static char *yy_c_buf_p = (char *) 0; +static int yy_init = 1; /* whether we need to initialize */ +static int yy_start = 0; /* start state number */ + +/* Flag which is used to allow yywrap()'s to do buffer switches + * instead of setting up a fresh yyin. A bit of a hack ... + */ +static int yy_did_buffer_switch_on_eof; + +void yyrestart YY_PROTO(( FILE *input_file )); + +void yy_switch_to_buffer YY_PROTO(( YY_BUFFER_STATE new_buffer )); +void yy_load_buffer_state YY_PROTO(( void )); +YY_BUFFER_STATE yy_create_buffer YY_PROTO(( FILE *file, int size )); +void yy_delete_buffer YY_PROTO(( YY_BUFFER_STATE b )); +void yy_init_buffer YY_PROTO(( YY_BUFFER_STATE b, FILE *file )); +void yy_flush_buffer YY_PROTO(( YY_BUFFER_STATE b )); +#define YY_FLUSH_BUFFER yy_flush_buffer( yy_current_buffer ) + +YY_BUFFER_STATE yy_scan_buffer YY_PROTO(( char *base, yy_size_t size )); +YY_BUFFER_STATE yy_scan_string YY_PROTO(( yyconst char *yy_str )); +YY_BUFFER_STATE yy_scan_bytes YY_PROTO(( yyconst char *bytes, int len )); + +static void *yy_flex_alloc YY_PROTO(( yy_size_t )); +static void *yy_flex_realloc YY_PROTO(( void *, yy_size_t )); +static void yy_flex_free YY_PROTO(( void * )); + +#define yy_new_buffer yy_create_buffer + +#define yy_set_interactive(is_interactive) \ + { \ + if ( ! yy_current_buffer ) \ + yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); \ + yy_current_buffer->yy_is_interactive = is_interactive; \ + } + +#define yy_set_bol(at_bol) \ + { \ + if ( ! yy_current_buffer ) \ + yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); \ + yy_current_buffer->yy_at_bol = at_bol; \ + } + +#define YY_AT_BOL() (yy_current_buffer->yy_at_bol) + +typedef unsigned char YY_CHAR; +FILE *yyin = (FILE *) 0, *yyout = (FILE *) 0; +typedef int yy_state_type; +extern char *yytext; +#define yytext_ptr yytext + +static yy_state_type yy_get_previous_state YY_PROTO(( void )); +static yy_state_type yy_try_NUL_trans YY_PROTO(( yy_state_type current_state )); +static int yy_get_next_buffer YY_PROTO(( void )); +static void yy_fatal_error YY_PROTO(( yyconst char msg[] )); + +/* Done after the current pattern has been matched and before the + * corresponding action - sets up yytext. + */ +#define YY_DO_BEFORE_ACTION \ + yytext_ptr = yy_bp; \ + yyleng = (int) (yy_cp - yy_bp); \ + yy_hold_char = *yy_cp; \ + *yy_cp = '\0'; \ + yy_c_buf_p = yy_cp; + +#define YY_NUM_RULES 13 +#define YY_END_OF_BUFFER 14 +static yyconst short int yy_accept[65] = + { 0, + 0, 0, 14, 13, 1, 12, 10, 11, 7, 5, + 6, 13, 8, 2, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 9, 1, 2, 2, 2, 0, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 2, 0, 2, 4, 4, 4, 4, 3, + 4, 3, 4, 4, 3, 4, 3, 3, 4, 3, + 3, 3, 3, 0 + } ; + +static yyconst int yy_ec[256] = + { 0, + 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 2, 1, 1, 1, 1, 1, 1, 1, 4, + 5, 6, 7, 1, 8, 9, 10, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 1, 1, 1, + 1, 1, 1, 1, 12, 13, 14, 13, 15, 16, + 13, 13, 13, 13, 13, 17, 13, 13, 13, 13, + 13, 18, 19, 20, 13, 13, 13, 13, 13, 13, + 1, 1, 1, 21, 13, 1, 22, 23, 24, 25, + + 26, 13, 27, 28, 29, 13, 13, 13, 13, 30, + 31, 32, 33, 34, 35, 36, 13, 13, 13, 37, + 13, 13, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1 + } ; + +static yyconst int yy_meta[38] = + { 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2 + } ; + +static yyconst short int yy_base[66] = + { 0, + 0, 0, 106, 107, 103, 107, 107, 107, 107, 107, + 107, 93, 107, 29, 15, 0, 10, 66, 80, 70, + 78, 14, 77, 107, 96, 34, 37, 47, 46, 0, + 28, 68, 74, 60, 72, 61, 69, 64, 60, 59, + 54, 57, 50, 75, 74, 49, 61, 52, 51, 52, + 49, 0, 43, 52, 47, 38, 44, 43, 40, 41, + 40, 39, 38, 107, 40 + } ; + +static yyconst short int yy_def[66] = + { 0, + 64, 1, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 65, 65, 65, 65, 65, 65, + 65, 65, 65, 64, 64, 64, 64, 64, 64, 65, + 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, + 65, 65, 64, 64, 64, 65, 65, 65, 65, 65, + 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, + 65, 65, 65, 0, 64 + } ; + +static yyconst short int yy_nxt[145] = + { 0, + 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, + 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, + 24, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 27, 31, 28, + 34, 30, 40, 29, 26, 35, 41, 43, 29, 32, + 33, 29, 44, 44, 29, 27, 45, 28, 46, 29, + 43, 29, 29, 47, 29, 52, 52, 52, 52, 63, + 52, 52, 29, 52, 52, 29, 52, 52, 62, 52, + 61, 60, 59, 58, 45, 45, 57, 56, 55, 54, + 52, 53, 52, 51, 50, 49, 48, 25, 42, 39, + + 38, 37, 36, 26, 25, 64, 3, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64 + } ; + +static yyconst short int yy_chk[145] = + { 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 14, 15, 14, + 17, 65, 22, 14, 26, 17, 22, 27, 26, 15, + 15, 27, 29, 29, 14, 28, 29, 28, 31, 26, + 43, 28, 27, 31, 43, 63, 62, 61, 60, 59, + 58, 57, 28, 56, 55, 43, 54, 53, 51, 50, + 49, 48, 47, 46, 45, 44, 42, 41, 40, 39, + 38, 37, 36, 35, 34, 33, 32, 25, 23, 21, + + 20, 19, 18, 12, 5, 3, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64 + } ; + +static yy_state_type yy_last_accepting_state; +static char *yy_last_accepting_cpos; + +/* The intent behind this definition is that it'll catch + * any uses of REJECT which flex missed. + */ +#define REJECT reject_used_but_not_detected +#define yymore() yymore_used_but_not_detected +#define YY_MORE_ADJ 0 +#define YY_RESTORE_YY_MORE_OFFSET +char *yytext; +#line 1 "scanner.l" +#define INITIAL 0 +#line 2 "scanner.l" +/* + * Copyright (C) 1999, 2002, 2003 Free Software Foundation, Inc. + * + * This file is part of GNU libmatheval + * + * GNU libmatheval 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. + * + * GNU libmatheval 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 program; see the file COPYING. If not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + * USA. + */ + +/* This file was modified for inclusion in Gmsh */ + +#include "common.h" +#include "node.h" +#include "parser.tab.hpp" +#include "symbol_table.h" + +#define YY_ALWAYS_INTERACTIVE 1 + +/* Redefine macro to redirect scanner input from string instead of + standard input. */ +#define YY_INPUT( buffer, result, max_size ) \ +{ result = input_from_string (buffer, max_size); } + +/* Variables used to communicate with code using scanner. */ +extern SymbolTable *matheval_symbol_table; /* Evaluator symbol table. */ +extern char *matheval_input_string; /* String representing function. */ + +/* Read next max_size character from string into buffer. */ +static int input_from_string (char *buffer, int max_size); +/* Token definitions. */ +#line 476 "scanner.yy.cpp" + +/* Macros after this point can all be overridden by user definitions in + * section 1. + */ + +#ifndef YY_SKIP_YYWRAP +#ifdef __cplusplus +extern "C" int yywrap YY_PROTO(( void )); +#else +extern int yywrap YY_PROTO(( void )); +#endif +#endif + +#ifndef YY_NO_UNPUT +static void yyunput YY_PROTO(( int c, char *buf_ptr )); +#endif + +#ifndef yytext_ptr +static void yy_flex_strncpy YY_PROTO(( char *, yyconst char *, int )); +#endif + +#ifdef YY_NEED_STRLEN +static int yy_flex_strlen YY_PROTO(( yyconst char * )); +#endif + +#ifndef YY_NO_INPUT +#ifdef __cplusplus +static int yyinput YY_PROTO(( void )); +#else +static int input YY_PROTO(( void )); +#endif +#endif + +#if YY_STACK_USED +static int yy_start_stack_ptr = 0; +static int yy_start_stack_depth = 0; +static int *yy_start_stack = 0; +#ifndef YY_NO_PUSH_STATE +static void yy_push_state YY_PROTO(( int new_state )); +#endif +#ifndef YY_NO_POP_STATE +static void yy_pop_state YY_PROTO(( void )); +#endif +#ifndef YY_NO_TOP_STATE +static int yy_top_state YY_PROTO(( void )); +#endif + +#else +#define YY_NO_PUSH_STATE 1 +#define YY_NO_POP_STATE 1 +#define YY_NO_TOP_STATE 1 +#endif + +#ifdef YY_MALLOC_DECL +YY_MALLOC_DECL +#else +#if __STDC__ +#ifndef __cplusplus +#include <stdlib.h> +#endif +#else +/* Just try to get by without declaring the routines. This will fail + * miserably on non-ANSI systems for which sizeof(size_t) != sizeof(int) + * or sizeof(void*) != sizeof(int). + */ +#endif +#endif + +/* Amount of stuff to slurp up with each read. */ +#ifndef YY_READ_BUF_SIZE +#define YY_READ_BUF_SIZE 8192 +#endif + +/* Copy whatever the last rule matched to the standard output. */ + +#ifndef ECHO +/* This used to be an fputs(), but since the string might contain NUL's, + * we now use fwrite(). + */ +#define ECHO (void) fwrite( yytext, yyleng, 1, yyout ) +#endif + +/* Gets input and stuffs it into "buf". number of characters read, or YY_NULL, + * is returned in "result". + */ +#ifndef YY_INPUT +#define YY_INPUT(buf,result,max_size) \ + if ( yy_current_buffer->yy_is_interactive ) \ + { \ + int c = '*', n; \ + for ( n = 0; n < max_size && \ + (c = getc( yyin )) != EOF && c != '\n'; ++n ) \ + buf[n] = (char) c; \ + if ( c == '\n' ) \ + buf[n++] = (char) c; \ + if ( c == EOF && ferror( yyin ) ) \ + YY_FATAL_ERROR( "input in flex scanner failed" ); \ + result = n; \ + } \ + else if ( ((result = fread( buf, 1, max_size, yyin )) == 0) \ + && ferror( yyin ) ) \ + YY_FATAL_ERROR( "input in flex scanner failed" ); +#endif + +/* No semi-colon after return; correct usage is to write "yyterminate();" - + * we don't want an extra ';' after the "return" because that will cause + * some compilers to complain about unreachable statements. + */ +#ifndef yyterminate +#define yyterminate() return YY_NULL +#endif + +/* Number of entries by which start-condition stack grows. */ +#ifndef YY_START_STACK_INCR +#define YY_START_STACK_INCR 25 +#endif + +/* Report a fatal error. */ +#ifndef YY_FATAL_ERROR +#define YY_FATAL_ERROR(msg) yy_fatal_error( msg ) +#endif + +/* Default declaration of generated scanner - a define so the user can + * easily add parameters. + */ +#ifndef YY_DECL +#define YY_DECL int yylex YY_PROTO(( void )) +#endif + +/* Code executed at the beginning of each rule, after yytext and yyleng + * have been set up. + */ +#ifndef YY_USER_ACTION +#define YY_USER_ACTION +#endif + +/* Code executed at the end of each rule. */ +#ifndef YY_BREAK +#define YY_BREAK break; +#endif + +#define YY_RULE_SETUP \ + YY_USER_ACTION + +YY_DECL + { + register yy_state_type yy_current_state; + register char *yy_cp, *yy_bp; + register int yy_act; + +#line 52 "scanner.l" + + +#line 630 "scanner.yy.cpp" + + if ( yy_init ) + { + yy_init = 0; + +#ifdef YY_USER_INIT + YY_USER_INIT; +#endif + + if ( ! yy_start ) + yy_start = 1; /* first start state */ + + if ( ! yyin ) + yyin = stdin; + + if ( ! yyout ) + yyout = stdout; + + if ( ! yy_current_buffer ) + yy_current_buffer = + yy_create_buffer( yyin, YY_BUF_SIZE ); + + yy_load_buffer_state(); + } + + while ( 1 ) /* loops until end-of-file is reached */ + { + yy_cp = yy_c_buf_p; + + /* Support of yytext. */ + *yy_cp = yy_hold_char; + + /* yy_bp points to the position in yy_ch_buf of the start of + * the current run. + */ + yy_bp = yy_cp; + + yy_current_state = yy_start; +yy_match: + do + { + register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)]; + if ( yy_accept[yy_current_state] ) + { + yy_last_accepting_state = yy_current_state; + yy_last_accepting_cpos = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 65 ) + yy_c = yy_meta[(unsigned int) yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; + ++yy_cp; + } + while ( yy_base[yy_current_state] != 107 ); + +yy_find_action: + yy_act = yy_accept[yy_current_state]; + if ( yy_act == 0 ) + { /* have to back up */ + yy_cp = yy_last_accepting_cpos; + yy_current_state = yy_last_accepting_state; + yy_act = yy_accept[yy_current_state]; + } + + YY_DO_BEFORE_ACTION; + + +do_action: /* This label is used only to access EOF actions. */ + + + switch ( yy_act ) + { /* beginning of action switch */ + case 0: /* must back up */ + /* undo the effects of YY_DO_BEFORE_ACTION */ + *yy_cp = yy_hold_char; + yy_cp = yy_last_accepting_cpos; + yy_current_state = yy_last_accepting_state; + goto yy_find_action; + +case 1: +YY_RULE_SETUP +#line 54 "scanner.l" + + YY_BREAK +case 2: +YY_RULE_SETUP +#line 56 "scanner.l" +{ + /* Create node representing constant with appropriate value. */ + melval.node = node_create ('c', atof (metext)); + return NUMBER; +} + YY_BREAK +case 3: +YY_RULE_SETUP +#line 62 "scanner.l" +{ + /* Find symbol table record corresponding to function name. */ + melval.record = symbol_table_lookup (matheval_symbol_table, metext); + return FUNCTION; +} + YY_BREAK +case 4: +YY_RULE_SETUP +#line 68 "scanner.l" +{ + Record *record; /* Symbol table record. */ + /* Inserty variable into symbol table. */ + record = symbol_table_insert (matheval_symbol_table, metext, 'v'); + melval.node = node_create ('v', record); + return VARIABLE; +} + YY_BREAK +case 5: +YY_RULE_SETUP +#line 76 "scanner.l" +{ + return '+'; +} + YY_BREAK +case 6: +YY_RULE_SETUP +#line 80 "scanner.l" +{ + return '-'; +} + YY_BREAK +case 7: +YY_RULE_SETUP +#line 84 "scanner.l" +{ + return '*'; +} + YY_BREAK +case 8: +YY_RULE_SETUP +#line 88 "scanner.l" +{ + return '/'; +} + YY_BREAK +case 9: +YY_RULE_SETUP +#line 92 "scanner.l" +{ + return '^'; +} + YY_BREAK +case 10: +YY_RULE_SETUP +#line 96 "scanner.l" +{ + return '('; +} + YY_BREAK +case 11: +YY_RULE_SETUP +#line 100 "scanner.l" +{ + return ')'; +} + YY_BREAK +case 12: +YY_RULE_SETUP +#line 104 "scanner.l" +{ + return '\n'; +} + YY_BREAK +case 13: +YY_RULE_SETUP +#line 108 "scanner.l" +ECHO; + YY_BREAK +#line 808 "scanner.yy.cpp" +case YY_STATE_EOF(INITIAL): + yyterminate(); + + case YY_END_OF_BUFFER: + { + /* Amount of text matched not including the EOB char. */ + int yy_amount_of_matched_text = (int) (yy_cp - yytext_ptr) - 1; + + /* Undo the effects of YY_DO_BEFORE_ACTION. */ + *yy_cp = yy_hold_char; + YY_RESTORE_YY_MORE_OFFSET + + if ( yy_current_buffer->yy_buffer_status == YY_BUFFER_NEW ) + { + /* We're scanning a new file or input source. It's + * possible that this happened because the user + * just pointed yyin at a new source and called + * yylex(). If so, then we have to assure + * consistency between yy_current_buffer and our + * globals. Here is the right place to do so, because + * this is the first action (other than possibly a + * back-up) that will match for the new input source. + */ + yy_n_chars = yy_current_buffer->yy_n_chars; + yy_current_buffer->yy_input_file = yyin; + yy_current_buffer->yy_buffer_status = YY_BUFFER_NORMAL; + } + + /* Note that here we test for yy_c_buf_p "<=" to the position + * of the first EOB in the buffer, since yy_c_buf_p will + * already have been incremented past the NUL character + * (since all states make transitions on EOB to the + * end-of-buffer state). Contrast this with the test + * in input(). + */ + if ( yy_c_buf_p <= &yy_current_buffer->yy_ch_buf[yy_n_chars] ) + { /* This was really a NUL. */ + yy_state_type yy_next_state; + + yy_c_buf_p = yytext_ptr + yy_amount_of_matched_text; + + yy_current_state = yy_get_previous_state(); + + /* Okay, we're now positioned to make the NUL + * transition. We couldn't have + * yy_get_previous_state() go ahead and do it + * for us because it doesn't know how to deal + * with the possibility of jamming (and we don't + * want to build jamming into it because then it + * will run more slowly). + */ + + yy_next_state = yy_try_NUL_trans( yy_current_state ); + + yy_bp = yytext_ptr + YY_MORE_ADJ; + + if ( yy_next_state ) + { + /* Consume the NUL. */ + yy_cp = ++yy_c_buf_p; + yy_current_state = yy_next_state; + goto yy_match; + } + + else + { + yy_cp = yy_c_buf_p; + goto yy_find_action; + } + } + + else switch ( yy_get_next_buffer() ) + { + case EOB_ACT_END_OF_FILE: + { + yy_did_buffer_switch_on_eof = 0; + + if ( yywrap() ) + { + /* Note: because we've taken care in + * yy_get_next_buffer() to have set up + * yytext, we can now set up + * yy_c_buf_p so that if some total + * hoser (like flex itself) wants to + * call the scanner after we return the + * YY_NULL, it'll still work - another + * YY_NULL will get returned. + */ + yy_c_buf_p = yytext_ptr + YY_MORE_ADJ; + + yy_act = YY_STATE_EOF(YY_START); + goto do_action; + } + + else + { + if ( ! yy_did_buffer_switch_on_eof ) + YY_NEW_FILE; + } + break; + } + + case EOB_ACT_CONTINUE_SCAN: + yy_c_buf_p = + yytext_ptr + yy_amount_of_matched_text; + + yy_current_state = yy_get_previous_state(); + + yy_cp = yy_c_buf_p; + yy_bp = yytext_ptr + YY_MORE_ADJ; + goto yy_match; + + case EOB_ACT_LAST_MATCH: + yy_c_buf_p = + &yy_current_buffer->yy_ch_buf[yy_n_chars]; + + yy_current_state = yy_get_previous_state(); + + yy_cp = yy_c_buf_p; + yy_bp = yytext_ptr + YY_MORE_ADJ; + goto yy_find_action; + } + break; + } + + default: + YY_FATAL_ERROR( + "fatal flex scanner internal error--no action found" ); + } /* end of action switch */ + } /* end of scanning one token */ + } /* end of yylex */ + + +/* yy_get_next_buffer - try to read in a new buffer + * + * Returns a code representing an action: + * EOB_ACT_LAST_MATCH - + * EOB_ACT_CONTINUE_SCAN - continue scanning from current position + * EOB_ACT_END_OF_FILE - end of file + */ + +static int yy_get_next_buffer() + { + register char *dest = yy_current_buffer->yy_ch_buf; + register char *source = yytext_ptr; + register int number_to_move, i; + int ret_val; + + if ( yy_c_buf_p > &yy_current_buffer->yy_ch_buf[yy_n_chars + 1] ) + YY_FATAL_ERROR( + "fatal flex scanner internal error--end of buffer missed" ); + + if ( yy_current_buffer->yy_fill_buffer == 0 ) + { /* Don't try to fill the buffer, so this is an EOF. */ + if ( yy_c_buf_p - yytext_ptr - YY_MORE_ADJ == 1 ) + { + /* We matched a single character, the EOB, so + * treat this as a final EOF. + */ + return EOB_ACT_END_OF_FILE; + } + + else + { + /* We matched some text prior to the EOB, first + * process it. + */ + return EOB_ACT_LAST_MATCH; + } + } + + /* Try to read more data. */ + + /* First move last chars to start of buffer. */ + number_to_move = (int) (yy_c_buf_p - yytext_ptr) - 1; + + for ( i = 0; i < number_to_move; ++i ) + *(dest++) = *(source++); + + if ( yy_current_buffer->yy_buffer_status == YY_BUFFER_EOF_PENDING ) + /* don't do the read, it's not guaranteed to return an EOF, + * just force an EOF + */ + yy_current_buffer->yy_n_chars = yy_n_chars = 0; + + else + { + int num_to_read = + yy_current_buffer->yy_buf_size - number_to_move - 1; + + while ( num_to_read <= 0 ) + { /* Not enough room in the buffer - grow it. */ +#ifdef YY_USES_REJECT + YY_FATAL_ERROR( +"input buffer overflow, can't enlarge buffer because scanner uses REJECT" ); +#else + + /* just a shorter name for the current buffer */ + YY_BUFFER_STATE b = yy_current_buffer; + + int yy_c_buf_p_offset = + (int) (yy_c_buf_p - b->yy_ch_buf); + + if ( b->yy_is_our_buffer ) + { + int new_size = b->yy_buf_size * 2; + + if ( new_size <= 0 ) + b->yy_buf_size += b->yy_buf_size / 8; + else + b->yy_buf_size *= 2; + + b->yy_ch_buf = (char *) + /* Include room in for 2 EOB chars. */ + yy_flex_realloc( (void *) b->yy_ch_buf, + b->yy_buf_size + 2 ); + } + else + /* Can't grow it, we don't own it. */ + b->yy_ch_buf = 0; + + if ( ! b->yy_ch_buf ) + YY_FATAL_ERROR( + "fatal error - scanner input buffer overflow" ); + + yy_c_buf_p = &b->yy_ch_buf[yy_c_buf_p_offset]; + + num_to_read = yy_current_buffer->yy_buf_size - + number_to_move - 1; +#endif + } + + if ( num_to_read > YY_READ_BUF_SIZE ) + num_to_read = YY_READ_BUF_SIZE; + + /* Read in more data. */ + YY_INPUT( (&yy_current_buffer->yy_ch_buf[number_to_move]), + yy_n_chars, num_to_read ); + + yy_current_buffer->yy_n_chars = yy_n_chars; + } + + if ( yy_n_chars == 0 ) + { + if ( number_to_move == YY_MORE_ADJ ) + { + ret_val = EOB_ACT_END_OF_FILE; + yyrestart( yyin ); + } + + else + { + ret_val = EOB_ACT_LAST_MATCH; + yy_current_buffer->yy_buffer_status = + YY_BUFFER_EOF_PENDING; + } + } + + else + ret_val = EOB_ACT_CONTINUE_SCAN; + + yy_n_chars += number_to_move; + yy_current_buffer->yy_ch_buf[yy_n_chars] = YY_END_OF_BUFFER_CHAR; + yy_current_buffer->yy_ch_buf[yy_n_chars + 1] = YY_END_OF_BUFFER_CHAR; + + yytext_ptr = &yy_current_buffer->yy_ch_buf[0]; + + return ret_val; + } + + +/* yy_get_previous_state - get the state just before the EOB char was reached */ + +static yy_state_type yy_get_previous_state() + { + register yy_state_type yy_current_state; + register char *yy_cp; + + yy_current_state = yy_start; + + for ( yy_cp = yytext_ptr + YY_MORE_ADJ; yy_cp < yy_c_buf_p; ++yy_cp ) + { + register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1); + if ( yy_accept[yy_current_state] ) + { + yy_last_accepting_state = yy_current_state; + yy_last_accepting_cpos = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 65 ) + yy_c = yy_meta[(unsigned int) yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; + } + + return yy_current_state; + } + + +/* yy_try_NUL_trans - try to make a transition on the NUL character + * + * synopsis + * next_state = yy_try_NUL_trans( current_state ); + */ + +#ifdef YY_USE_PROTOS +static yy_state_type yy_try_NUL_trans( yy_state_type yy_current_state ) +#else +static yy_state_type yy_try_NUL_trans( yy_current_state ) +yy_state_type yy_current_state; +#endif + { + register int yy_is_jam; + register char *yy_cp = yy_c_buf_p; + + register YY_CHAR yy_c = 1; + if ( yy_accept[yy_current_state] ) + { + yy_last_accepting_state = yy_current_state; + yy_last_accepting_cpos = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 65 ) + yy_c = yy_meta[(unsigned int) yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; + yy_is_jam = (yy_current_state == 64); + + return yy_is_jam ? 0 : yy_current_state; + } + + +#ifndef YY_NO_UNPUT +#ifdef YY_USE_PROTOS +static void yyunput( int c, register char *yy_bp ) +#else +static void yyunput( c, yy_bp ) +int c; +register char *yy_bp; +#endif + { + register char *yy_cp = yy_c_buf_p; + + /* undo effects of setting up yytext */ + *yy_cp = yy_hold_char; + + if ( yy_cp < yy_current_buffer->yy_ch_buf + 2 ) + { /* need to shift things up to make room */ + /* +2 for EOB chars. */ + register int number_to_move = yy_n_chars + 2; + register char *dest = &yy_current_buffer->yy_ch_buf[ + yy_current_buffer->yy_buf_size + 2]; + register char *source = + &yy_current_buffer->yy_ch_buf[number_to_move]; + + while ( source > yy_current_buffer->yy_ch_buf ) + *--dest = *--source; + + yy_cp += (int) (dest - source); + yy_bp += (int) (dest - source); + yy_current_buffer->yy_n_chars = + yy_n_chars = yy_current_buffer->yy_buf_size; + + if ( yy_cp < yy_current_buffer->yy_ch_buf + 2 ) + YY_FATAL_ERROR( "flex scanner push-back overflow" ); + } + + *--yy_cp = (char) c; + + + yytext_ptr = yy_bp; + yy_hold_char = *yy_cp; + yy_c_buf_p = yy_cp; + } +#endif /* ifndef YY_NO_UNPUT */ + + +#ifdef __cplusplus +static int yyinput() +#else +static int input() +#endif + { + int c; + + *yy_c_buf_p = yy_hold_char; + + if ( *yy_c_buf_p == YY_END_OF_BUFFER_CHAR ) + { + /* yy_c_buf_p now points to the character we want to return. + * If this occurs *before* the EOB characters, then it's a + * valid NUL; if not, then we've hit the end of the buffer. + */ + if ( yy_c_buf_p < &yy_current_buffer->yy_ch_buf[yy_n_chars] ) + /* This was really a NUL. */ + *yy_c_buf_p = '\0'; + + else + { /* need more input */ + int offset = yy_c_buf_p - yytext_ptr; + ++yy_c_buf_p; + + switch ( yy_get_next_buffer() ) + { + case EOB_ACT_LAST_MATCH: + /* This happens because yy_g_n_b() + * sees that we've accumulated a + * token and flags that we need to + * try matching the token before + * proceeding. But for input(), + * there's no matching to consider. + * So convert the EOB_ACT_LAST_MATCH + * to EOB_ACT_END_OF_FILE. + */ + + /* Reset buffer status. */ + yyrestart( yyin ); + + /* fall through */ + + case EOB_ACT_END_OF_FILE: + { + if ( yywrap() ) + return EOF; + + if ( ! yy_did_buffer_switch_on_eof ) + YY_NEW_FILE; +#ifdef __cplusplus + return yyinput(); +#else + return input(); +#endif + } + + case EOB_ACT_CONTINUE_SCAN: + yy_c_buf_p = yytext_ptr + offset; + break; + } + } + } + + c = *(unsigned char *) yy_c_buf_p; /* cast for 8-bit char's */ + *yy_c_buf_p = '\0'; /* preserve yytext */ + yy_hold_char = *++yy_c_buf_p; + + + return c; + } + + +#ifdef YY_USE_PROTOS +void yyrestart( FILE *input_file ) +#else +void yyrestart( input_file ) +FILE *input_file; +#endif + { + if ( ! yy_current_buffer ) + yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); + + yy_init_buffer( yy_current_buffer, input_file ); + yy_load_buffer_state(); + } + + +#ifdef YY_USE_PROTOS +void yy_switch_to_buffer( YY_BUFFER_STATE new_buffer ) +#else +void yy_switch_to_buffer( new_buffer ) +YY_BUFFER_STATE new_buffer; +#endif + { + if ( yy_current_buffer == new_buffer ) + return; + + if ( yy_current_buffer ) + { + /* Flush out information for old buffer. */ + *yy_c_buf_p = yy_hold_char; + yy_current_buffer->yy_buf_pos = yy_c_buf_p; + yy_current_buffer->yy_n_chars = yy_n_chars; + } + + yy_current_buffer = new_buffer; + yy_load_buffer_state(); + + /* We don't actually know whether we did this switch during + * EOF (yywrap()) processing, but the only time this flag + * is looked at is after yywrap() is called, so it's safe + * to go ahead and always set it. + */ + yy_did_buffer_switch_on_eof = 1; + } + + +#ifdef YY_USE_PROTOS +void yy_load_buffer_state( void ) +#else +void yy_load_buffer_state() +#endif + { + yy_n_chars = yy_current_buffer->yy_n_chars; + yytext_ptr = yy_c_buf_p = yy_current_buffer->yy_buf_pos; + yyin = yy_current_buffer->yy_input_file; + yy_hold_char = *yy_c_buf_p; + } + + +#ifdef YY_USE_PROTOS +YY_BUFFER_STATE yy_create_buffer( FILE *file, int size ) +#else +YY_BUFFER_STATE yy_create_buffer( file, size ) +FILE *file; +int size; +#endif + { + YY_BUFFER_STATE b; + + b = (YY_BUFFER_STATE) yy_flex_alloc( sizeof( struct yy_buffer_state ) ); + if ( ! b ) + YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); + + b->yy_buf_size = size; + + /* yy_ch_buf has to be 2 characters longer than the size given because + * we need to put in 2 end-of-buffer characters. + */ + b->yy_ch_buf = (char *) yy_flex_alloc( b->yy_buf_size + 2 ); + if ( ! b->yy_ch_buf ) + YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); + + b->yy_is_our_buffer = 1; + + yy_init_buffer( b, file ); + + return b; + } + + +#ifdef YY_USE_PROTOS +void yy_delete_buffer( YY_BUFFER_STATE b ) +#else +void yy_delete_buffer( b ) +YY_BUFFER_STATE b; +#endif + { + if ( ! b ) + return; + + if ( b == yy_current_buffer ) + yy_current_buffer = (YY_BUFFER_STATE) 0; + + if ( b->yy_is_our_buffer ) + yy_flex_free( (void *) b->yy_ch_buf ); + + yy_flex_free( (void *) b ); + } + + +#ifndef YY_ALWAYS_INTERACTIVE +#ifndef YY_NEVER_INTERACTIVE +extern int isatty YY_PROTO(( int )); +#endif +#endif + +#ifdef YY_USE_PROTOS +void yy_init_buffer( YY_BUFFER_STATE b, FILE *file ) +#else +void yy_init_buffer( b, file ) +YY_BUFFER_STATE b; +FILE *file; +#endif + + + { + yy_flush_buffer( b ); + + b->yy_input_file = file; + b->yy_fill_buffer = 1; + +#if YY_ALWAYS_INTERACTIVE + b->yy_is_interactive = 1; +#else +#if YY_NEVER_INTERACTIVE + b->yy_is_interactive = 0; +#else + b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0; +#endif +#endif + } + + +#ifdef YY_USE_PROTOS +void yy_flush_buffer( YY_BUFFER_STATE b ) +#else +void yy_flush_buffer( b ) +YY_BUFFER_STATE b; +#endif + + { + if ( ! b ) + return; + + b->yy_n_chars = 0; + + /* We always need two end-of-buffer characters. The first causes + * a transition to the end-of-buffer state. The second causes + * a jam in that state. + */ + b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR; + b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR; + + b->yy_buf_pos = &b->yy_ch_buf[0]; + + b->yy_at_bol = 1; + b->yy_buffer_status = YY_BUFFER_NEW; + + if ( b == yy_current_buffer ) + yy_load_buffer_state(); + } + + +#ifndef YY_NO_SCAN_BUFFER +#ifdef YY_USE_PROTOS +YY_BUFFER_STATE yy_scan_buffer( char *base, yy_size_t size ) +#else +YY_BUFFER_STATE yy_scan_buffer( base, size ) +char *base; +yy_size_t size; +#endif + { + YY_BUFFER_STATE b; + + if ( size < 2 || + base[size-2] != YY_END_OF_BUFFER_CHAR || + base[size-1] != YY_END_OF_BUFFER_CHAR ) + /* They forgot to leave room for the EOB's. */ + return 0; + + b = (YY_BUFFER_STATE) yy_flex_alloc( sizeof( struct yy_buffer_state ) ); + if ( ! b ) + YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" ); + + b->yy_buf_size = size - 2; /* "- 2" to take care of EOB's */ + b->yy_buf_pos = b->yy_ch_buf = base; + b->yy_is_our_buffer = 0; + b->yy_input_file = 0; + b->yy_n_chars = b->yy_buf_size; + b->yy_is_interactive = 0; + b->yy_at_bol = 1; + b->yy_fill_buffer = 0; + b->yy_buffer_status = YY_BUFFER_NEW; + + yy_switch_to_buffer( b ); + + return b; + } +#endif + + +#ifndef YY_NO_SCAN_STRING +#ifdef YY_USE_PROTOS +YY_BUFFER_STATE yy_scan_string( yyconst char *yy_str ) +#else +YY_BUFFER_STATE yy_scan_string( yy_str ) +yyconst char *yy_str; +#endif + { + int len; + for ( len = 0; yy_str[len]; ++len ) + ; + + return yy_scan_bytes( yy_str, len ); + } +#endif + + +#ifndef YY_NO_SCAN_BYTES +#ifdef YY_USE_PROTOS +YY_BUFFER_STATE yy_scan_bytes( yyconst char *bytes, int len ) +#else +YY_BUFFER_STATE yy_scan_bytes( bytes, len ) +yyconst char *bytes; +int len; +#endif + { + YY_BUFFER_STATE b; + char *buf; + yy_size_t n; + int i; + + /* Get memory for full buffer, including space for trailing EOB's. */ + n = len + 2; + buf = (char *) yy_flex_alloc( n ); + if ( ! buf ) + YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" ); + + for ( i = 0; i < len; ++i ) + buf[i] = bytes[i]; + + buf[len] = buf[len+1] = YY_END_OF_BUFFER_CHAR; + + b = yy_scan_buffer( buf, n ); + if ( ! b ) + YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" ); + + /* It's okay to grow etc. this buffer, and we should throw it + * away when we're done. + */ + b->yy_is_our_buffer = 1; + + return b; + } +#endif + + +#ifndef YY_NO_PUSH_STATE +#ifdef YY_USE_PROTOS +static void yy_push_state( int new_state ) +#else +static void yy_push_state( new_state ) +int new_state; +#endif + { + if ( yy_start_stack_ptr >= yy_start_stack_depth ) + { + yy_size_t new_size; + + yy_start_stack_depth += YY_START_STACK_INCR; + new_size = yy_start_stack_depth * sizeof( int ); + + if ( ! yy_start_stack ) + yy_start_stack = (int *) yy_flex_alloc( new_size ); + + else + yy_start_stack = (int *) yy_flex_realloc( + (void *) yy_start_stack, new_size ); + + if ( ! yy_start_stack ) + YY_FATAL_ERROR( + "out of memory expanding start-condition stack" ); + } + + yy_start_stack[yy_start_stack_ptr++] = YY_START; + + BEGIN(new_state); + } +#endif + + +#ifndef YY_NO_POP_STATE +static void yy_pop_state() + { + if ( --yy_start_stack_ptr < 0 ) + YY_FATAL_ERROR( "start-condition stack underflow" ); + + BEGIN(yy_start_stack[yy_start_stack_ptr]); + } +#endif + + +#ifndef YY_NO_TOP_STATE +static int yy_top_state() + { + return yy_start_stack[yy_start_stack_ptr - 1]; + } +#endif + +#ifndef YY_EXIT_FAILURE +#define YY_EXIT_FAILURE 2 +#endif + +#ifdef YY_USE_PROTOS +static void yy_fatal_error( yyconst char msg[] ) +#else +static void yy_fatal_error( msg ) +char msg[]; +#endif + { + (void) fprintf( stderr, "%s\n", msg ); + exit( YY_EXIT_FAILURE ); + } + + + +/* Redefine yyless() so it works in section 3 code. */ + +#undef yyless +#define yyless(n) \ + do \ + { \ + /* Undo effects of setting up yytext. */ \ + yytext[yyleng] = yy_hold_char; \ + yy_c_buf_p = yytext + n; \ + yy_hold_char = *yy_c_buf_p; \ + *yy_c_buf_p = '\0'; \ + yyleng = n; \ + } \ + while ( 0 ) + + +/* Internal utility routines. */ + +#ifndef yytext_ptr +#ifdef YY_USE_PROTOS +static void yy_flex_strncpy( char *s1, yyconst char *s2, int n ) +#else +static void yy_flex_strncpy( s1, s2, n ) +char *s1; +yyconst char *s2; +int n; +#endif + { + register int i; + for ( i = 0; i < n; ++i ) + s1[i] = s2[i]; + } +#endif + +#ifdef YY_NEED_STRLEN +#ifdef YY_USE_PROTOS +static int yy_flex_strlen( yyconst char *s ) +#else +static int yy_flex_strlen( s ) +yyconst char *s; +#endif + { + register int n; + for ( n = 0; s[n]; ++n ) + ; + + return n; + } +#endif + + +#ifdef YY_USE_PROTOS +static void *yy_flex_alloc( yy_size_t size ) +#else +static void *yy_flex_alloc( size ) +yy_size_t size; +#endif + { + return (void *) malloc( size ); + } + +#ifdef YY_USE_PROTOS +static void *yy_flex_realloc( void *ptr, yy_size_t size ) +#else +static void *yy_flex_realloc( ptr, size ) +void *ptr; +yy_size_t size; +#endif + { + /* The cast to (char *) in the following accommodates both + * implementations that use char* generic pointers, and those + * that use void* generic pointers. It works with the latter + * because both ANSI C and C++ allow castless assignment from + * any pointer type to void*, and deal with argument conversions + * as though doing an assignment. + */ + return (void *) realloc( (char *) ptr, size ); + } + +#ifdef YY_USE_PROTOS +static void yy_flex_free( void *ptr ) +#else +static void yy_flex_free( ptr ) +void *ptr; +#endif + { + free( ptr ); + } + +#if YY_MAIN +int main() + { + yylex(); + return 0; + } +#endif +#line 108 "scanner.l" + + +#undef mewrap + +int mewrap() { return 1; } + +static int input_from_string (char *buffer, int max_size) +{ + int count; /* Count of characters to copy from input string to buffer. */ + + /* Calculate count of characters to copy. */ + count = strlen (matheval_input_string); + if (count > max_size) + count = max_size; + + /* Perform copy operation and update input string. */ + memcpy(buffer, matheval_input_string, count); + matheval_input_string += count; + + return count; +} + +void force_buffer_flush() { YY_FLUSH_BUFFER; } diff --git a/contrib/MathEval/symbol_table.cpp b/contrib/MathEval/symbol_table.cpp new file mode 100644 index 0000000000..34e01043a4 --- /dev/null +++ b/contrib/MathEval/symbol_table.cpp @@ -0,0 +1,212 @@ +/* + * Copyright (C) 1999, 2002, 2003 Free Software Foundation, Inc. + * + * This file is part of GNU libmatheval + * + * GNU libmatheval 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. + * + * GNU libmatheval 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 + * program; see the file COPYING. If not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* This file was modified for inclusion in Gmsh */ + +#include <assert.h> +#include <stdarg.h> + +#include "common.h" +#include "symbol_table.h" +#include "xmath.h" + +/* + * Type definition for function accepting single argument of double type and + * returning double value. + */ +typedef double (*function_type) (double); + +/* Calculate hash value for given name and hash table length. */ +static int hash(char *name, int length); + +SymbolTable * +symbol_table_create(int length) +{ + SymbolTable *symbol_table; /* Pointer to symbol table. */ + static char *names[] = {"Exp", "Log", "Sqrt", "Sin", "Cos", "Tan", "Ctan", + "Asin", "Acos", "Atan", "Actan", "Sinh", "Cosh", "Tanh", + "Ctanh", "Asinh", "Acosh", "Atanh", "Actanh", "Fabs", "Rand" }; + static double (*functions[]) (double) = { exp, log, sqrt, sin, cos, tan, x_ctan, + asin, acos, atan, x_actan, sinh, cosh, tanh, + x_ctanh, x_asinh, x_acosh, x_atanh, x_actanh, + fabs, x_rand}; + unsigned int i; + + /* + * Allocate memory for symbol table data structure as well as for + * corresponding hash table. + */ + symbol_table = XMALLOC(SymbolTable, 1); + symbol_table->length = length; + symbol_table->records = XCALLOC(Record, symbol_table->length); + + /* + * Insert predefined functions into symbol table. + */ + for (i = 0; i < sizeof(names) / sizeof(names[0]); i++) + symbol_table_insert(symbol_table, names[i], 'f', functions[i]); + + /* + * Initialize symbol table reference count. + */ + symbol_table->reference_count = 1; + + return symbol_table; +} + +void +symbol_table_destroy(SymbolTable * symbol_table) +{ + Record *curr, *next; /* Pointers to current and next record + * while traversing hash table bucket. */ + int i; + + if(!symbol_table) + return; + + /* + * Decrement refernce count and return if symbol table still used + * elsewhere. + */ + if (--symbol_table->reference_count > 0) + return; + + /* + * Delete hash table as well as data structure representing symbol + * table. + */ + for (i = 0; i < symbol_table->length; i++) + for (curr = symbol_table->records[i].next; curr;) { + next = curr->next; + XFREE(curr->name); + XFREE(curr); + curr = next; + } + XFREE(symbol_table->records); + XFREE(symbol_table); +} + +Record * +symbol_table_insert(SymbolTable * symbol_table, char *name, char type,...) +{ + Record *record; /* Pointer to symbol table record + * corresponding to name given. */ + va_list ap; /* Function variable argument list. */ + int i; + + /* + * Check if symbol already in table and, if affirmative and record + * type same as type given, return corresponding record immediately. + */ + if ((record = symbol_table_lookup(symbol_table, name))) { + assert(record->type == type); + return record; + } + /* + * Allocate memory for and initialize new record. + */ + record = XMALLOC(Record, 1); + record->name = XMALLOC(char, strlen(name) + 1); + strcpy(record->name, name); + record->type = type; + + /* + * Parse function variable argument list to complete record + * initialization. + */ + va_start(ap, type); + switch (record->type) { + case 'v': + record->data.value = 0; + break; + + case 'f': + record->data.function = va_arg(ap, function_type); + break; + } + va_end(ap); + + /* + * Calculate hash value and put record in corresponding hash table + * bucket. + */ + i = hash(name, symbol_table->length); + record->next = symbol_table->records[i].next; + symbol_table->records[i].next = record; + + return record; +} + +Record * +symbol_table_lookup(SymbolTable * symbol_table, char *name) +{ + int i; /* Hash value. */ + Record *curr; /* Pointer to current symbol table record. */ + + /* + * Calcuate hash value for name given. + */ + i = hash(name, symbol_table->length); + + /* + * Lookup for name in hash table bucket corresponding to above hash + * value. + */ + for (curr = symbol_table->records[i].next; curr; curr = curr->next) + if (!strcmp(curr->name, name)) + return curr; + + return NULL; +} + +SymbolTable * +symbol_table_assign(SymbolTable * symbol_table) +{ + /* + * Increase symbol table reference count and return pointer to data + * structure representing table. + */ + symbol_table->reference_count++; + return symbol_table; +} + +/* + * Function below reused from A.V. Aho, R. Sethi, J.D. Ullman, "Compilers - + * Principle, Techniques, and Tools", Addison-Wesley, 1986, pp 435-437, and + * in turn from P.J. Weineberger's C compiler. + */ +static int +hash(char *s, int n) +{ + char *p; + unsigned h, g; + + h = 0; + + for (p = s; *p; p++) { + h = (h << 4) + *p; + if ((g = h & 0xf0000000)) { + h = h ^ (g >> 24); + h = h ^ g; + } + } + + return h % n; +} diff --git a/contrib/MathEval/symbol_table.h b/contrib/MathEval/symbol_table.h new file mode 100644 index 0000000000..0862c956ef --- /dev/null +++ b/contrib/MathEval/symbol_table.h @@ -0,0 +1,79 @@ +/* + * Copyright (C) 1999, 2002, 2003 Free Software Foundation, Inc. + * + * This file is part of GNU libmatheval + * + * GNU libmatheval 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. + * + * GNU libmatheval 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 + * program; see the file COPYING. If not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* This file was modified for inclusion in Gmsh */ + +#ifndef SYMBOL_TABLE_H +#define SYMBOL_TABLE_H + +/* Data structure representing symbol table record. */ +typedef struct _Record { + struct _Record *next; /* Pointer to next record. */ + char *name; /* Symbol name. */ + char type; /* Symbol type ('v' for variable, 'f' for function). */ + union { + double value; /* Variable value. */ + double (*function) (double); /* Pointer to function to calculate + * its value. */ + } data; +} Record; + +/* + * Data structure representing symbol table (hash table is used for this + * purpose). + */ +typedef struct { + int length; /* Hash table length. */ + Record *records; /* Hash table buckets. */ + int reference_count; /* Reference count for symbol table (evaluator + * for derivative uses same symbol table as + * evaluator for corresponding function). */ +} SymbolTable; + +/* Create symbol table using specified length of hash table. */ +SymbolTable *symbol_table_create(int length); + +/* Destroy symbol table. */ +void symbol_table_destroy(SymbolTable * symbol_table); + +/* + * Insert symbol into given symbol table. Further arguments are symbol name + * and its type, as well as additional arguments according to symbol type. + * Return value is pointer to symobl table record created to represent + * symbol. If symbol already in symbol table, pointer to its record is + * returned immediately. + */ +Record *symbol_table_insert(SymbolTable * symbol_table, char *name, char type,...); + +/* + * Lookup symbol by name from given symbol table. Pointer to symbol record + * is returned if symbol found, null pointer otherwise. + */ +Record *symbol_table_lookup(SymbolTable * symbol_table, char *name); + +/* + * Return symbol table pointer to be assigned to variable. This function + * should be used instead of simple pointer assignement for proper reference + * counting. Users willing to manage reference counts by themselves are free + * to ignore this functions. + */ +SymbolTable *symbol_table_assign(SymbolTable * symbol_table); + +#endif diff --git a/contrib/MathEval/xmath.cpp b/contrib/MathEval/xmath.cpp new file mode 100644 index 0000000000..da1479b032 --- /dev/null +++ b/contrib/MathEval/xmath.cpp @@ -0,0 +1,101 @@ +/* + * Copyright (C) 1999, 2002, 2003 Free Software Foundation, Inc. + * + * This file is part of GNU libmatheval + * + * GNU libmatheval 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. + * + * GNU libmatheval 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 + * program; see the file COPYING. If not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* This file was modified for inclusion in Gmsh */ + +#include "xmath.h" +#include <math.h> +#include <stdlib.h> + +double +x_ctan(double x) +{ + /* + * Calculate cotangent value. + */ + return 1 / tan(x); +} + +double +x_actan(double x) +{ + /* + * Calculate inverse cotangent value. + */ + return atan(1 / x); +} + +double +x_ctanh(double x) +{ + /* + * Calculate hyperbolic cotangent value. + */ + return 1 / tanh(x); +} + +double +x_asinh(double x) +{ + /* + * Calculate inverse hyperbolic sine value using relation between + * hyperbolic and exponential functions. + */ + return log(x + sqrt(x * x + 1)); +} + +double +x_acosh(double x) +{ + /* + * Calculate inverse hyperbolic cosine value using relation between + * hyperbolic and exponential functions. + */ + return log(x + sqrt(x * x - 1)); +} + +double +x_atanh(double x) +{ + /* + * Calculate inverse hyperbolic tangent value using relation between + * hyperbolic and exponential functions. + */ + return 0.5 * log((1 + x) / (1 - x)); +} + +double +x_actanh(double x) +{ + /* + * Calculate inverse hyperbolic cotangent value. + */ + return atanh(1 / x); +} + +double +x_rand(double x) +{ + /* + * Calculate random value in [0, x]. + */ + + return x*(double)rand()/(double)RAND_MAX; +} diff --git a/contrib/MathEval/xmath.h b/contrib/MathEval/xmath.h new file mode 100644 index 0000000000..f086ad916a --- /dev/null +++ b/contrib/MathEval/xmath.h @@ -0,0 +1,35 @@ +/* + * Copyright (C) 1999, 2002, 2003 Free Software Foundation, Inc. + * + * This file is part of GNU libmatheval + * + * GNU libmatheval 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. + * + * GNU libmatheval 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 + * program; see the file COPYING. If not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* This file was modified for inclusion in Gmsh */ + +#ifndef XMATH_H +#define XMATH_H + +double x_ctan(double x); +double x_actan(double x); +double x_ctanh(double x); +double x_asinh(double x); +double x_acosh(double x); +double x_atanh(double x); +double x_actanh(double x); +double x_rand(double x); + +#endif diff --git a/contrib/Metis/Makefile b/contrib/Metis/Makefile new file mode 100644 index 0000000000..b239ce9cfd --- /dev/null +++ b/contrib/Metis/Makefile @@ -0,0 +1,103 @@ +# $Id: Makefile,v 1.1 2005-09-21 17:29:37 geuzaine Exp $ +# +# Copyright (C) 1997-2005 C. Geuzaine, J.-F. Remacle +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +# USA. +# +# Please report all bugs and problems to <gmsh@geuz.org>. + +include ../../variables + +LIB = ../../lib/libGmshMetis.a +INCLUDE = -I. +CFLAGS = ${OPTIM} ${FLAGS} ${INCLUDE} + +SRC = balance.c \ + fm.c \ + kwayfm.c \ + mcoarsen.c \ + minitpart2.c \ + mpmetis.c \ + pmetis.c \ + subdomains.c\ + bucketsort.c \ + fortran.c \ + kwayrefine.c\ + memory.c \ + minitpart.c \ + mrefine2.c\ + pqueue.c\ + timing.c\ + ccgraph.c \ + frename.c \ + kwayvolfm.c\ + mesh.c\ + mkmetis.c\ + mrefine.c \ + refine.c \ + util.c\ + coarsen.c \ + graph.c\ + kwayvolrefine.c \ + meshpart.c \ + mkwayfmh.c \ + mutil.c \ + separator.c\ + compress.c\ + initpart.c\ + match.c\ + mfm2.c \ + mkwayrefine.c\ + myqsort.c\ + sfm.c\ + debug.c \ + kmetis.c \ + mbalance2.c\ + mfm.c \ + mmatch.c \ + ometis.c \ + srefine.c\ + estmem.c \ + kvmetis.c\ + mbalance.c \ + mincover.c \ + mmd.c \ + parmetis.c \ + stat.c + +OBJ = ${SRC:.c=.o} + +.SUFFIXES: .o .c + +${LIB}: ${OBJ} + ${AR} ${LIB} ${OBJ} + ${RANLIB} ${LIB} + +.c.o: + ${CC} ${CFLAGS} -c $< -o ${<:.c=.o} + +clean: + rm -f *.o + +depend: + (sed '/^# DO NOT DELETE THIS LINE/q' Makefile && \ + ${CXX} -MM ${CFLAGS} ${SRC} \ + ) >Makefile.new + cp Makefile Makefile.bak + cp Makefile.new Makefile + rm -f Makefile.new + +# DO NOT DELETE THIS LINE diff --git a/contrib/Metis/balance.c b/contrib/Metis/balance.c new file mode 100644 index 0000000000..2e9bd5fbbb --- /dev/null +++ b/contrib/Metis/balance.c @@ -0,0 +1,278 @@ +/* + * Copyright 1997, Regents of the University of Minnesota + * + * balance.c + * + * This file contains code that is used to forcefully balance either + * bisections or k-sections + * + * Started 7/29/97 + * George + * + * $Id: balance.c,v 1.1 2005-09-21 17:29:37 geuzaine Exp $ + * + */ + +#include <metis.h> + +/************************************************************************* +* This function is the entry point of the bisection balancing algorithms. +**************************************************************************/ +void Balance2Way(CtrlType *ctrl, GraphType *graph, int *tpwgts, float ubfactor) +{ + int i, j, nvtxs, from, imax, gain, mindiff; + idxtype *id, *ed; + + /* Return right away if the balance is OK */ + mindiff = abs(tpwgts[0]-graph->pwgts[0]); + if (mindiff < 3*(graph->pwgts[0]+graph->pwgts[1])/graph->nvtxs) + return; + if (graph->pwgts[0] > tpwgts[0] && graph->pwgts[0] < (int)(ubfactor*tpwgts[0])) + return; + if (graph->pwgts[1] > tpwgts[1] && graph->pwgts[1] < (int)(ubfactor*tpwgts[1])) + return; + + if (graph->nbnd > 0) + Bnd2WayBalance(ctrl, graph, tpwgts); + else + General2WayBalance(ctrl, graph, tpwgts); + +} + + + +/************************************************************************* +* This function balances two partitions by moving boundary nodes +* from the domain that is overweight to the one that is underweight. +**************************************************************************/ +void Bnd2WayBalance(CtrlType *ctrl, GraphType *graph, int *tpwgts) +{ + int i, ii, j, k, kwgt, nvtxs, nbnd, nswaps, from, to, pass, me, tmp; + idxtype *xadj, *vwgt, *adjncy, *adjwgt, *where, *id, *ed, *bndptr, *bndind, *pwgts; + idxtype *moved, *perm; + PQueueType parts; + int higain, oldgain, mincut, mindiff; + + nvtxs = graph->nvtxs; + xadj = graph->xadj; + vwgt = graph->vwgt; + adjncy = graph->adjncy; + adjwgt = graph->adjwgt; + where = graph->where; + id = graph->id; + ed = graph->ed; + pwgts = graph->pwgts; + bndptr = graph->bndptr; + bndind = graph->bndind; + + moved = idxwspacemalloc(ctrl, nvtxs); + perm = idxwspacemalloc(ctrl, nvtxs); + + /* Determine from which domain you will be moving data */ + mindiff = abs(tpwgts[0]-pwgts[0]); + from = (pwgts[0] < tpwgts[0] ? 1 : 0); + to = (from+1)%2; + + IFSET(ctrl->dbglvl, DBG_REFINE, + printf("Partitions: [%6d %6d] T[%6d %6d], Nv-Nb[%6d %6d]. ICut: %6d [B]\n", + pwgts[0], pwgts[1], tpwgts[0], tpwgts[1], graph->nvtxs, graph->nbnd, graph->mincut)); + + tmp = graph->adjwgtsum[idxamax(nvtxs, graph->adjwgtsum)]; + PQueueInit(ctrl, &parts, nvtxs, tmp); + + idxset(nvtxs, -1, moved); + + ASSERT(ComputeCut(graph, where) == graph->mincut); + ASSERT(CheckBnd(graph)); + + /* Insert the boundary nodes of the proper partition whose size is OK in the priority queue */ + nbnd = graph->nbnd; + RandomPermute(nbnd, perm, 1); + for (ii=0; ii<nbnd; ii++) { + i = perm[ii]; + ASSERT(ed[bndind[i]] > 0 || id[bndind[i]] == 0); + ASSERT(bndptr[bndind[i]] != -1); + if (where[bndind[i]] == from && vwgt[bndind[i]] <= mindiff) + PQueueInsert(&parts, bndind[i], ed[bndind[i]]-id[bndind[i]]); + } + + mincut = graph->mincut; + for (nswaps=0; nswaps<nvtxs; nswaps++) { + if ((higain = PQueueGetMax(&parts)) == -1) + break; + ASSERT(bndptr[higain] != -1); + + if (pwgts[to]+vwgt[higain] > tpwgts[to]) + break; + + mincut -= (ed[higain]-id[higain]); + INC_DEC(pwgts[to], pwgts[from], vwgt[higain]); + + where[higain] = to; + moved[higain] = nswaps; + + IFSET(ctrl->dbglvl, DBG_MOVEINFO, + printf("Moved %6d from %d. [%3d %3d] %5d [%4d %4d]\n", higain, from, ed[higain]-id[higain], vwgt[higain], mincut, pwgts[0], pwgts[1])); + + /************************************************************** + * Update the id[i]/ed[i] values of the affected nodes + ***************************************************************/ + SWAP(id[higain], ed[higain], tmp); + if (ed[higain] == 0 && xadj[higain] < xadj[higain+1]) + BNDDelete(nbnd, bndind, bndptr, higain); + + for (j=xadj[higain]; j<xadj[higain+1]; j++) { + k = adjncy[j]; + oldgain = ed[k]-id[k]; + + kwgt = (to == where[k] ? adjwgt[j] : -adjwgt[j]); + INC_DEC(id[k], ed[k], kwgt); + + /* Update its boundary information and queue position */ + if (bndptr[k] != -1) { /* If k was a boundary vertex */ + if (ed[k] == 0) { /* Not a boundary vertex any more */ + BNDDelete(nbnd, bndind, bndptr, k); + if (moved[k] == -1 && where[k] == from && vwgt[k] <= mindiff) /* Remove it if in the queues */ + PQueueDelete(&parts, k, oldgain); + } + else { /* If it has not been moved, update its position in the queue */ + if (moved[k] == -1 && where[k] == from && vwgt[k] <= mindiff) + PQueueUpdate(&parts, k, oldgain, ed[k]-id[k]); + } + } + else { + if (ed[k] > 0) { /* It will now become a boundary vertex */ + BNDInsert(nbnd, bndind, bndptr, k); + if (moved[k] == -1 && where[k] == from && vwgt[k] <= mindiff) + PQueueInsert(&parts, k, ed[k]-id[k]); + } + } + } + } + + IFSET(ctrl->dbglvl, DBG_REFINE, + printf("\tMinimum cut: %6d, PWGTS: [%6d %6d], NBND: %6d\n", mincut, pwgts[0], pwgts[1], nbnd)); + + graph->mincut = mincut; + graph->nbnd = nbnd; + + PQueueFree(ctrl, &parts); + + idxwspacefree(ctrl, nvtxs); + idxwspacefree(ctrl, nvtxs); +} + + +/************************************************************************* +* This function balances two partitions by moving the highest gain +* (including negative gain) vertices to the other domain. +* It is used only when tha unbalance is due to non contigous +* subdomains. That is, the are no boundary vertices. +* It moves vertices from the domain that is overweight to the one that +* is underweight. +**************************************************************************/ +void General2WayBalance(CtrlType *ctrl, GraphType *graph, int *tpwgts) +{ + int i, ii, j, k, kwgt, nvtxs, nbnd, nswaps, from, to, pass, me, tmp; + idxtype *xadj, *vwgt, *adjncy, *adjwgt, *where, *id, *ed, *bndptr, *bndind, *pwgts; + idxtype *moved, *perm; + PQueueType parts; + int higain, oldgain, mincut, mindiff; + + nvtxs = graph->nvtxs; + xadj = graph->xadj; + vwgt = graph->vwgt; + adjncy = graph->adjncy; + adjwgt = graph->adjwgt; + where = graph->where; + id = graph->id; + ed = graph->ed; + pwgts = graph->pwgts; + bndptr = graph->bndptr; + bndind = graph->bndind; + + moved = idxwspacemalloc(ctrl, nvtxs); + perm = idxwspacemalloc(ctrl, nvtxs); + + /* Determine from which domain you will be moving data */ + mindiff = abs(tpwgts[0]-pwgts[0]); + from = (pwgts[0] < tpwgts[0] ? 1 : 0); + to = (from+1)%2; + + IFSET(ctrl->dbglvl, DBG_REFINE, + printf("Partitions: [%6d %6d] T[%6d %6d], Nv-Nb[%6d %6d]. ICut: %6d [B]\n", + pwgts[0], pwgts[1], tpwgts[0], tpwgts[1], graph->nvtxs, graph->nbnd, graph->mincut)); + + tmp = graph->adjwgtsum[idxamax(nvtxs, graph->adjwgtsum)]; + PQueueInit(ctrl, &parts, nvtxs, tmp); + + idxset(nvtxs, -1, moved); + + ASSERT(ComputeCut(graph, where) == graph->mincut); + ASSERT(CheckBnd(graph)); + + /* Insert the nodes of the proper partition whose size is OK in the priority queue */ + RandomPermute(nvtxs, perm, 1); + for (ii=0; ii<nvtxs; ii++) { + i = perm[ii]; + if (where[i] == from && vwgt[i] <= mindiff) + PQueueInsert(&parts, i, ed[i]-id[i]); + } + + mincut = graph->mincut; + nbnd = graph->nbnd; + for (nswaps=0; nswaps<nvtxs; nswaps++) { + if ((higain = PQueueGetMax(&parts)) == -1) + break; + + if (pwgts[to]+vwgt[higain] > tpwgts[to]) + break; + + mincut -= (ed[higain]-id[higain]); + INC_DEC(pwgts[to], pwgts[from], vwgt[higain]); + + where[higain] = to; + moved[higain] = nswaps; + + IFSET(ctrl->dbglvl, DBG_MOVEINFO, + printf("Moved %6d from %d. [%3d %3d] %5d [%4d %4d]\n", higain, from, ed[higain]-id[higain], vwgt[higain], mincut, pwgts[0], pwgts[1])); + + /************************************************************** + * Update the id[i]/ed[i] values of the affected nodes + ***************************************************************/ + SWAP(id[higain], ed[higain], tmp); + if (ed[higain] == 0 && bndptr[higain] != -1 && xadj[higain] < xadj[higain+1]) + BNDDelete(nbnd, bndind, bndptr, higain); + if (ed[higain] > 0 && bndptr[higain] == -1) + BNDInsert(nbnd, bndind, bndptr, higain); + + for (j=xadj[higain]; j<xadj[higain+1]; j++) { + k = adjncy[j]; + oldgain = ed[k]-id[k]; + + kwgt = (to == where[k] ? adjwgt[j] : -adjwgt[j]); + INC_DEC(id[k], ed[k], kwgt); + + /* Update the queue position */ + if (moved[k] == -1 && where[k] == from && vwgt[k] <= mindiff) + PQueueUpdate(&parts, k, oldgain, ed[k]-id[k]); + + /* Update its boundary information */ + if (ed[k] == 0 && bndptr[k] != -1) + BNDDelete(nbnd, bndind, bndptr, k); + else if (ed[k] > 0 && bndptr[k] == -1) + BNDInsert(nbnd, bndind, bndptr, k); + } + } + + IFSET(ctrl->dbglvl, DBG_REFINE, + printf("\tMinimum cut: %6d, PWGTS: [%6d %6d], NBND: %6d\n", mincut, pwgts[0], pwgts[1], nbnd)); + + graph->mincut = mincut; + graph->nbnd = nbnd; + + PQueueFree(ctrl, &parts); + + idxwspacefree(ctrl, nvtxs); + idxwspacefree(ctrl, nvtxs); +} diff --git a/contrib/Metis/bucketsort.c b/contrib/Metis/bucketsort.c new file mode 100644 index 0000000000..316d212179 --- /dev/null +++ b/contrib/Metis/bucketsort.c @@ -0,0 +1,43 @@ +/* + * Copyright 1997, Regents of the University of Minnesota + * + * bucketsort.c + * + * This file contains code that implement a variety of counting sorting + * algorithms + * + * Started 7/25/97 + * George + * + * $Id: bucketsort.c,v 1.1 2005-09-21 17:29:37 geuzaine Exp $ + * + */ + +#include <metis.h> + + + +/************************************************************************* +* This function uses simple counting sort to return a permutation array +* corresponding to the sorted order. The keys are assumed to start from +* 0 and they are positive. This sorting is used during matching. +**************************************************************************/ +void BucketSortKeysInc(int n, int max, idxtype *keys, idxtype *tperm, idxtype *perm) +{ + int i, ii; + idxtype *counts; + + counts = idxsmalloc(max+2, 0, "BucketSortKeysInc: counts"); + + for (i=0; i<n; i++) + counts[keys[i]]++; + MAKECSR(i, max+1, counts); + + for (ii=0; ii<n; ii++) { + i = tperm[ii]; + perm[counts[keys[i]]++] = i; + } + + free(counts); +} + diff --git a/contrib/Metis/ccgraph.c b/contrib/Metis/ccgraph.c new file mode 100644 index 0000000000..549b4267f6 --- /dev/null +++ b/contrib/Metis/ccgraph.c @@ -0,0 +1,599 @@ +/* + * Copyright 1997, Regents of the University of Minnesota + * + * ccgraph.c + * + * This file contains the functions that create the coarse graph + * + * Started 8/11/97 + * George + * + * $Id: ccgraph.c,v 1.1 2005-09-21 17:29:37 geuzaine Exp $ + * + */ + +#include <metis.h> + + + +/************************************************************************* +* This function creates the coarser graph +**************************************************************************/ +void CreateCoarseGraph(CtrlType *ctrl, GraphType *graph, int cnvtxs, idxtype *match, idxtype *perm) +{ + int i, j, jj, k, kk, l, m, istart, iend, nvtxs, nedges, ncon, cnedges, v, u, mask, dovsize; + idxtype *xadj, *vwgt, *vsize, *adjncy, *adjwgt, *adjwgtsum, *auxadj; + idxtype *cmap, *htable; + idxtype *cxadj, *cvwgt, *cvsize, *cadjncy, *cadjwgt, *cadjwgtsum; + float *nvwgt, *cnvwgt; + GraphType *cgraph; + + dovsize = (ctrl->optype == OP_KVMETIS ? 1 : 0); + + mask = HTLENGTH; + if (cnvtxs < 8*mask || graph->nedges/graph->nvtxs > 15) { + CreateCoarseGraphNoMask(ctrl, graph, cnvtxs, match, perm); + return; + } + + IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->ContractTmr)); + + nvtxs = graph->nvtxs; + ncon = graph->ncon; + xadj = graph->xadj; + vwgt = graph->vwgt; + vsize = graph->vsize; + nvwgt = graph->nvwgt; + adjncy = graph->adjncy; + adjwgt = graph->adjwgt; + adjwgtsum = graph->adjwgtsum; + cmap = graph->cmap; + + /* Initialize the coarser graph */ + cgraph = SetUpCoarseGraph(graph, cnvtxs, dovsize); + cxadj = cgraph->xadj; + cvwgt = cgraph->vwgt; + cvsize = cgraph->vsize; + cnvwgt = cgraph->nvwgt; + cadjwgtsum = cgraph->adjwgtsum; + cadjncy = cgraph->adjncy; + cadjwgt = cgraph->adjwgt; + + + iend = xadj[nvtxs]; + auxadj = ctrl->wspace.auxcore; + memcpy(auxadj, adjncy, iend*sizeof(idxtype)); + for (i=0; i<iend; i++) + auxadj[i] = cmap[auxadj[i]]; + + htable = idxset(mask+1, -1, idxwspacemalloc(ctrl, mask+1)); + + cxadj[0] = cnvtxs = cnedges = 0; + for (i=0; i<nvtxs; i++) { + v = perm[i]; + if (cmap[v] != cnvtxs) + continue; + + u = match[v]; + if (ncon == 1) + cvwgt[cnvtxs] = vwgt[v]; + else + scopy(ncon, nvwgt+v*ncon, cnvwgt+cnvtxs*ncon); + + if (dovsize) + cvsize[cnvtxs] = vsize[v]; + + cadjwgtsum[cnvtxs] = adjwgtsum[v]; + nedges = 0; + + istart = xadj[v]; + iend = xadj[v+1]; + for (j=istart; j<iend; j++) { + k = auxadj[j]; + kk = k&mask; + if ((m = htable[kk]) == -1) { + cadjncy[nedges] = k; + cadjwgt[nedges] = adjwgt[j]; + htable[kk] = nedges++; + } + else if (cadjncy[m] == k) { + cadjwgt[m] += adjwgt[j]; + } + else { + for (jj=0; jj<nedges; jj++) { + if (cadjncy[jj] == k) { + cadjwgt[jj] += adjwgt[j]; + break; + } + } + if (jj == nedges) { + cadjncy[nedges] = k; + cadjwgt[nedges++] = adjwgt[j]; + } + } + } + + if (v != u) { + if (ncon == 1) + cvwgt[cnvtxs] += vwgt[u]; + else + saxpy(ncon, 1.0, nvwgt+u*ncon, 1, cnvwgt+cnvtxs*ncon, 1); + + if (dovsize) + cvsize[cnvtxs] += vsize[u]; + + cadjwgtsum[cnvtxs] += adjwgtsum[u]; + + istart = xadj[u]; + iend = xadj[u+1]; + for (j=istart; j<iend; j++) { + k = auxadj[j]; + kk = k&mask; + if ((m = htable[kk]) == -1) { + cadjncy[nedges] = k; + cadjwgt[nedges] = adjwgt[j]; + htable[kk] = nedges++; + } + else if (cadjncy[m] == k) { + cadjwgt[m] += adjwgt[j]; + } + else { + for (jj=0; jj<nedges; jj++) { + if (cadjncy[jj] == k) { + cadjwgt[jj] += adjwgt[j]; + break; + } + } + if (jj == nedges) { + cadjncy[nedges] = k; + cadjwgt[nedges++] = adjwgt[j]; + } + } + } + + /* Remove the contracted adjacency weight */ + jj = htable[cnvtxs&mask]; + if (jj >= 0 && cadjncy[jj] != cnvtxs) { + for (jj=0; jj<nedges; jj++) { + if (cadjncy[jj] == cnvtxs) + break; + } + } + if (jj >= 0 && cadjncy[jj] == cnvtxs) { /* This 2nd check is needed for non-adjacent matchings */ + cadjwgtsum[cnvtxs] -= cadjwgt[jj]; + cadjncy[jj] = cadjncy[--nedges]; + cadjwgt[jj] = cadjwgt[nedges]; + } + } + + ASSERTP(cadjwgtsum[cnvtxs] == idxsum(nedges, cadjwgt), ("%d %d %d %d %d\n", cnvtxs, cadjwgtsum[cnvtxs], idxsum(nedges, cadjwgt), adjwgtsum[u], adjwgtsum[v])); + + for (j=0; j<nedges; j++) + htable[cadjncy[j]&mask] = -1; /* Zero out the htable */ + htable[cnvtxs&mask] = -1; + + cnedges += nedges; + cxadj[++cnvtxs] = cnedges; + cadjncy += nedges; + cadjwgt += nedges; + } + + cgraph->nedges = cnedges; + + ReAdjustMemory(graph, cgraph, dovsize); + + IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->ContractTmr)); + + idxwspacefree(ctrl, mask+1); + +} + + +/************************************************************************* +* This function creates the coarser graph +**************************************************************************/ +void CreateCoarseGraphNoMask(CtrlType *ctrl, GraphType *graph, int cnvtxs, idxtype *match, idxtype *perm) +{ + int i, j, k, m, istart, iend, nvtxs, nedges, ncon, cnedges, v, u, dovsize; + idxtype *xadj, *vwgt, *vsize, *adjncy, *adjwgt, *adjwgtsum, *auxadj; + idxtype *cmap, *htable; + idxtype *cxadj, *cvwgt, *cvsize, *cadjncy, *cadjwgt, *cadjwgtsum; + float *nvwgt, *cnvwgt; + GraphType *cgraph; + + dovsize = (ctrl->optype == OP_KVMETIS ? 1 : 0); + + IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->ContractTmr)); + + nvtxs = graph->nvtxs; + ncon = graph->ncon; + xadj = graph->xadj; + vwgt = graph->vwgt; + vsize = graph->vsize; + nvwgt = graph->nvwgt; + adjncy = graph->adjncy; + adjwgt = graph->adjwgt; + adjwgtsum = graph->adjwgtsum; + cmap = graph->cmap; + + + /* Initialize the coarser graph */ + cgraph = SetUpCoarseGraph(graph, cnvtxs, dovsize); + cxadj = cgraph->xadj; + cvwgt = cgraph->vwgt; + cvsize = cgraph->vsize; + cnvwgt = cgraph->nvwgt; + cadjwgtsum = cgraph->adjwgtsum; + cadjncy = cgraph->adjncy; + cadjwgt = cgraph->adjwgt; + + + htable = idxset(cnvtxs, -1, idxwspacemalloc(ctrl, cnvtxs)); + + iend = xadj[nvtxs]; + auxadj = ctrl->wspace.auxcore; + memcpy(auxadj, adjncy, iend*sizeof(idxtype)); + for (i=0; i<iend; i++) + auxadj[i] = cmap[auxadj[i]]; + + cxadj[0] = cnvtxs = cnedges = 0; + for (i=0; i<nvtxs; i++) { + v = perm[i]; + if (cmap[v] != cnvtxs) + continue; + + u = match[v]; + if (ncon == 1) + cvwgt[cnvtxs] = vwgt[v]; + else + scopy(ncon, nvwgt+v*ncon, cnvwgt+cnvtxs*ncon); + + if (dovsize) + cvsize[cnvtxs] = vsize[v]; + + cadjwgtsum[cnvtxs] = adjwgtsum[v]; + nedges = 0; + + istart = xadj[v]; + iend = xadj[v+1]; + for (j=istart; j<iend; j++) { + k = auxadj[j]; + if ((m = htable[k]) == -1) { + cadjncy[nedges] = k; + cadjwgt[nedges] = adjwgt[j]; + htable[k] = nedges++; + } + else { + cadjwgt[m] += adjwgt[j]; + } + } + + if (v != u) { + if (ncon == 1) + cvwgt[cnvtxs] += vwgt[u]; + else + saxpy(ncon, 1.0, nvwgt+u*ncon, 1, cnvwgt+cnvtxs*ncon, 1); + + if (dovsize) + cvsize[cnvtxs] += vsize[u]; + + cadjwgtsum[cnvtxs] += adjwgtsum[u]; + + istart = xadj[u]; + iend = xadj[u+1]; + for (j=istart; j<iend; j++) { + k = auxadj[j]; + if ((m = htable[k]) == -1) { + cadjncy[nedges] = k; + cadjwgt[nedges] = adjwgt[j]; + htable[k] = nedges++; + } + else { + cadjwgt[m] += adjwgt[j]; + } + } + + /* Remove the contracted adjacency weight */ + if ((j = htable[cnvtxs]) != -1) { + ASSERT(cadjncy[j] == cnvtxs); + cadjwgtsum[cnvtxs] -= cadjwgt[j]; + cadjncy[j] = cadjncy[--nedges]; + cadjwgt[j] = cadjwgt[nedges]; + htable[cnvtxs] = -1; + } + } + + ASSERTP(cadjwgtsum[cnvtxs] == idxsum(nedges, cadjwgt), ("%d %d\n", cadjwgtsum[cnvtxs], idxsum(nedges, cadjwgt))); + + for (j=0; j<nedges; j++) + htable[cadjncy[j]] = -1; /* Zero out the htable */ + + cnedges += nedges; + cxadj[++cnvtxs] = cnedges; + cadjncy += nedges; + cadjwgt += nedges; + } + + cgraph->nedges = cnedges; + + ReAdjustMemory(graph, cgraph, dovsize); + + IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->ContractTmr)); + + idxwspacefree(ctrl, cnvtxs); +} + + +/************************************************************************* +* This function creates the coarser graph +**************************************************************************/ +void CreateCoarseGraph_NVW(CtrlType *ctrl, GraphType *graph, int cnvtxs, idxtype *match, idxtype *perm) +{ + int i, j, jj, k, kk, l, m, istart, iend, nvtxs, nedges, ncon, cnedges, v, u, mask; + idxtype *xadj, *adjncy, *adjwgtsum, *auxadj; + idxtype *cmap, *htable; + idxtype *cxadj, *cvwgt, *cadjncy, *cadjwgt, *cadjwgtsum; + float *nvwgt, *cnvwgt; + GraphType *cgraph; + + + IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->ContractTmr)); + + nvtxs = graph->nvtxs; + ncon = graph->ncon; + xadj = graph->xadj; + nvwgt = graph->nvwgt; + adjncy = graph->adjncy; + adjwgtsum = graph->adjwgtsum; + cmap = graph->cmap; + + /* Initialize the coarser graph */ + cgraph = SetUpCoarseGraph(graph, cnvtxs, 0); + cxadj = cgraph->xadj; + cvwgt = cgraph->vwgt; + cnvwgt = cgraph->nvwgt; + cadjwgtsum = cgraph->adjwgtsum; + cadjncy = cgraph->adjncy; + cadjwgt = cgraph->adjwgt; + + + iend = xadj[nvtxs]; + auxadj = ctrl->wspace.auxcore; + memcpy(auxadj, adjncy, iend*sizeof(idxtype)); + for (i=0; i<iend; i++) + auxadj[i] = cmap[auxadj[i]]; + + mask = HTLENGTH; + htable = idxset(mask+1, -1, idxwspacemalloc(ctrl, mask+1)); + + cxadj[0] = cnvtxs = cnedges = 0; + for (i=0; i<nvtxs; i++) { + v = perm[i]; + if (cmap[v] != cnvtxs) + continue; + + u = match[v]; + cvwgt[cnvtxs] = 1; + cadjwgtsum[cnvtxs] = adjwgtsum[v]; + nedges = 0; + + istart = xadj[v]; + iend = xadj[v+1]; + for (j=istart; j<iend; j++) { + k = auxadj[j]; + kk = k&mask; + if ((m = htable[kk]) == -1) { + cadjncy[nedges] = k; + cadjwgt[nedges] = 1; + htable[kk] = nedges++; + } + else if (cadjncy[m] == k) { + cadjwgt[m]++; + } + else { + for (jj=0; jj<nedges; jj++) { + if (cadjncy[jj] == k) { + cadjwgt[jj]++; + break; + } + } + if (jj == nedges) { + cadjncy[nedges] = k; + cadjwgt[nedges++] = 1; + } + } + } + + if (v != u) { + cvwgt[cnvtxs]++; + cadjwgtsum[cnvtxs] += adjwgtsum[u]; + + istart = xadj[u]; + iend = xadj[u+1]; + for (j=istart; j<iend; j++) { + k = auxadj[j]; + kk = k&mask; + if ((m = htable[kk]) == -1) { + cadjncy[nedges] = k; + cadjwgt[nedges] = 1; + htable[kk] = nedges++; + } + else if (cadjncy[m] == k) { + cadjwgt[m]++; + } + else { + for (jj=0; jj<nedges; jj++) { + if (cadjncy[jj] == k) { + cadjwgt[jj]++; + break; + } + } + if (jj == nedges) { + cadjncy[nedges] = k; + cadjwgt[nedges++] = 1; + } + } + } + + /* Remove the contracted adjacency weight */ + jj = htable[cnvtxs&mask]; + if (jj >= 0 && cadjncy[jj] != cnvtxs) { + for (jj=0; jj<nedges; jj++) { + if (cadjncy[jj] == cnvtxs) + break; + } + } + if (jj >= 0 && cadjncy[jj] == cnvtxs) { /* This 2nd check is needed for non-adjacent matchings */ + cadjwgtsum[cnvtxs] -= cadjwgt[jj]; + cadjncy[jj] = cadjncy[--nedges]; + cadjwgt[jj] = cadjwgt[nedges]; + } + } + + ASSERTP(cadjwgtsum[cnvtxs] == idxsum(nedges, cadjwgt), ("%d %d %d %d %d\n", cnvtxs, cadjwgtsum[cnvtxs], idxsum(nedges, cadjwgt), adjwgtsum[u], adjwgtsum[v])); + + for (j=0; j<nedges; j++) + htable[cadjncy[j]&mask] = -1; /* Zero out the htable */ + htable[cnvtxs&mask] = -1; + + cnedges += nedges; + cxadj[++cnvtxs] = cnedges; + cadjncy += nedges; + cadjwgt += nedges; + } + + cgraph->nedges = cnedges; + + ReAdjustMemory(graph, cgraph, 0); + + IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->ContractTmr)); + + idxwspacefree(ctrl, mask+1); + +} + + +/************************************************************************* +* Setup the various arrays for the coarse graph +**************************************************************************/ +GraphType *SetUpCoarseGraph(GraphType *graph, int cnvtxs, int dovsize) +{ + GraphType *cgraph; + + cgraph = CreateGraph(); + cgraph->nvtxs = cnvtxs; + cgraph->ncon = graph->ncon; + + cgraph->finer = graph; + graph->coarser = cgraph; + + + /* Allocate memory for the coarser graph */ + if (graph->ncon == 1) { + if (dovsize) { + cgraph->gdata = idxmalloc(5*cnvtxs+1 + 2*graph->nedges, "SetUpCoarseGraph: gdata"); + cgraph->xadj = cgraph->gdata; + cgraph->vwgt = cgraph->gdata + cnvtxs+1; + cgraph->vsize = cgraph->gdata + 2*cnvtxs+1; + cgraph->adjwgtsum = cgraph->gdata + 3*cnvtxs+1; + cgraph->cmap = cgraph->gdata + 4*cnvtxs+1; + cgraph->adjncy = cgraph->gdata + 5*cnvtxs+1; + cgraph->adjwgt = cgraph->gdata + 5*cnvtxs+1 + graph->nedges; + } + else { + cgraph->gdata = idxmalloc(4*cnvtxs+1 + 2*graph->nedges, "SetUpCoarseGraph: gdata"); + cgraph->xadj = cgraph->gdata; + cgraph->vwgt = cgraph->gdata + cnvtxs+1; + cgraph->adjwgtsum = cgraph->gdata + 2*cnvtxs+1; + cgraph->cmap = cgraph->gdata + 3*cnvtxs+1; + cgraph->adjncy = cgraph->gdata + 4*cnvtxs+1; + cgraph->adjwgt = cgraph->gdata + 4*cnvtxs+1 + graph->nedges; + } + } + else { + if (dovsize) { + cgraph->gdata = idxmalloc(4*cnvtxs+1 + 2*graph->nedges, "SetUpCoarseGraph: gdata"); + cgraph->xadj = cgraph->gdata; + cgraph->vsize = cgraph->gdata + cnvtxs+1; + cgraph->adjwgtsum = cgraph->gdata + 2*cnvtxs+1; + cgraph->cmap = cgraph->gdata + 3*cnvtxs+1; + cgraph->adjncy = cgraph->gdata + 4*cnvtxs+1; + cgraph->adjwgt = cgraph->gdata + 4*cnvtxs+1 + graph->nedges; + } + else { + cgraph->gdata = idxmalloc(3*cnvtxs+1 + 2*graph->nedges, "SetUpCoarseGraph: gdata"); + cgraph->xadj = cgraph->gdata; + cgraph->adjwgtsum = cgraph->gdata + cnvtxs+1; + cgraph->cmap = cgraph->gdata + 2*cnvtxs+1; + cgraph->adjncy = cgraph->gdata + 3*cnvtxs+1; + cgraph->adjwgt = cgraph->gdata + 3*cnvtxs+1 + graph->nedges; + } + + cgraph->nvwgt = fmalloc(graph->ncon*cnvtxs, "SetUpCoarseGraph: nvwgt"); + } + + return cgraph; +} + + +/************************************************************************* +* This function re-adjusts the amount of memory that was allocated if +* it will lead to significant savings +**************************************************************************/ +void ReAdjustMemory(GraphType *graph, GraphType *cgraph, int dovsize) +{ + + if (cgraph->nedges > 100000 && graph->nedges < 0.7*graph->nedges) { + idxcopy(cgraph->nedges, cgraph->adjwgt, cgraph->adjncy+cgraph->nedges); + + if (graph->ncon == 1) { + if (dovsize) { + cgraph->gdata = realloc(cgraph->gdata, (5*cgraph->nvtxs+1 + 2*cgraph->nedges)*sizeof(idxtype)); + + /* Do this, in case everything was copied into new space */ + cgraph->xadj = cgraph->gdata; + cgraph->vwgt = cgraph->gdata + cgraph->nvtxs+1; + cgraph->vsize = cgraph->gdata + 2*cgraph->nvtxs+1; + cgraph->adjwgtsum = cgraph->gdata + 3*cgraph->nvtxs+1; + cgraph->cmap = cgraph->gdata + 4*cgraph->nvtxs+1; + cgraph->adjncy = cgraph->gdata + 5*cgraph->nvtxs+1; + cgraph->adjwgt = cgraph->gdata + 5*cgraph->nvtxs+1 + cgraph->nedges; + } + else { + cgraph->gdata = realloc(cgraph->gdata, (4*cgraph->nvtxs+1 + 2*cgraph->nedges)*sizeof(idxtype)); + + /* Do this, in case everything was copied into new space */ + cgraph->xadj = cgraph->gdata; + cgraph->vwgt = cgraph->gdata + cgraph->nvtxs+1; + cgraph->adjwgtsum = cgraph->gdata + 2*cgraph->nvtxs+1; + cgraph->cmap = cgraph->gdata + 3*cgraph->nvtxs+1; + cgraph->adjncy = cgraph->gdata + 4*cgraph->nvtxs+1; + cgraph->adjwgt = cgraph->gdata + 4*cgraph->nvtxs+1 + cgraph->nedges; + } + } + else { + if (dovsize) { + cgraph->gdata = realloc(cgraph->gdata, (4*cgraph->nvtxs+1 + 2*cgraph->nedges)*sizeof(idxtype)); + + /* Do this, in case everything was copied into new space */ + cgraph->xadj = cgraph->gdata; + cgraph->vsize = cgraph->gdata + cgraph->nvtxs+1; + cgraph->adjwgtsum = cgraph->gdata + 2*cgraph->nvtxs+1; + cgraph->cmap = cgraph->gdata + 3*cgraph->nvtxs+1; + cgraph->adjncy = cgraph->gdata + 4*cgraph->nvtxs+1; + cgraph->adjwgt = cgraph->gdata + 4*cgraph->nvtxs+1 + cgraph->nedges; + } + else { + cgraph->gdata = realloc(cgraph->gdata, (3*cgraph->nvtxs+1 + 2*cgraph->nedges)*sizeof(idxtype)); + + /* Do this, in case everything was copied into new space */ + cgraph->xadj = cgraph->gdata; + cgraph->adjwgtsum = cgraph->gdata + cgraph->nvtxs+1; + cgraph->cmap = cgraph->gdata + 2*cgraph->nvtxs+1; + cgraph->adjncy = cgraph->gdata + 3*cgraph->nvtxs+1; + cgraph->adjwgt = cgraph->gdata + 3*cgraph->nvtxs+1 + cgraph->nedges; + } + } + } + +} diff --git a/contrib/Metis/coarsen.c b/contrib/Metis/coarsen.c new file mode 100644 index 0000000000..40c25df00e --- /dev/null +++ b/contrib/Metis/coarsen.c @@ -0,0 +1,83 @@ +/* + * coarsen.c + * + * This file contains the driving routines for the coarsening process + * + * Started 7/23/97 + * George + * + * $Id: coarsen.c,v 1.1 2005-09-21 17:29:37 geuzaine Exp $ + * + */ + +#include <metis.h> + + +/************************************************************************* +* This function takes a graph and creates a sequence of coarser graphs +**************************************************************************/ +GraphType *Coarsen2Way(CtrlType *ctrl, GraphType *graph) +{ + int clevel; + GraphType *cgraph; + + IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->CoarsenTmr)); + + cgraph = graph; + + /* The following is ahack to allow the multiple bisections to go through with correct + coarsening */ + if (ctrl->CType > 20) { + clevel = 1; + ctrl->CType -= 20; + } + else + clevel = 0; + + do { + IFSET(ctrl->dbglvl, DBG_COARSEN, printf("%6d %7d [%d] [%d %d]\n", + cgraph->nvtxs, cgraph->nedges, ctrl->CoarsenTo, ctrl->maxvwgt, + (cgraph->vwgt ? idxsum(cgraph->nvtxs, cgraph->vwgt) : cgraph->nvtxs))); + + if (cgraph->adjwgt) { + switch (ctrl->CType) { + case MATCH_RM: + Match_RM(ctrl, cgraph); + break; + case MATCH_HEM: + if (clevel < 1) + Match_RM(ctrl, cgraph); + else + Match_HEM(ctrl, cgraph); + break; + case MATCH_SHEM: + if (clevel < 1) + Match_RM(ctrl, cgraph); + else + Match_SHEM(ctrl, cgraph); + break; + case MATCH_SHEMKWAY: + Match_SHEM(ctrl, cgraph); + break; + default: + errexit("Unknown CType: %d\n", ctrl->CType); + } + } + else { + Match_RM_NVW(ctrl, cgraph); + } + + cgraph = cgraph->coarser; + clevel++; + + } while (cgraph->nvtxs > ctrl->CoarsenTo && cgraph->nvtxs < COARSEN_FRACTION2*cgraph->finer->nvtxs && cgraph->nedges > cgraph->nvtxs/2); + + IFSET(ctrl->dbglvl, DBG_COARSEN, printf("%6d %7d [%d] [%d %d]\n", + cgraph->nvtxs, cgraph->nedges, ctrl->CoarsenTo, ctrl->maxvwgt, + (cgraph->vwgt ? idxsum(cgraph->nvtxs, cgraph->vwgt) : cgraph->nvtxs))); + + IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->CoarsenTmr)); + + return cgraph; +} + diff --git a/contrib/Metis/compress.c b/contrib/Metis/compress.c new file mode 100644 index 0000000000..9798919a6a --- /dev/null +++ b/contrib/Metis/compress.c @@ -0,0 +1,256 @@ +/* + * Copyright 1997, Regents of the University of Minnesota + * + * compress.c + * + * This file contains code for compressing nodes with identical adjacency + * structure and for prunning dense columns + * + * Started 9/17/97 + * George + * + * $Id: compress.c,v 1.1 2005-09-21 17:29:37 geuzaine Exp $ + */ + +#include <metis.h> + +/************************************************************************* +* This function compresses a graph by merging identical vertices +* The compression should lead to at least 10% reduction. +**************************************************************************/ +void CompressGraph(CtrlType *ctrl, GraphType *graph, int nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *cptr, idxtype *cind) +{ + int i, ii, iii, j, jj, k, l, cnvtxs, cnedges; + idxtype *cxadj, *cadjncy, *cvwgt, *mark, *map; + KeyValueType *keys; + + mark = idxsmalloc(nvtxs, -1, "CompressGraph: mark"); + map = idxsmalloc(nvtxs, -1, "CompressGraph: map"); + keys = (KeyValueType *)GKmalloc(nvtxs*sizeof(KeyValueType), "CompressGraph: keys"); + + /* Compute a key for each adjacency list */ + for (i=0; i<nvtxs; i++) { + k = 0; + for (j=xadj[i]; j<xadj[i+1]; j++) + k += adjncy[j]; + keys[i].key = k+i; /* Add the diagonal entry as well */ + keys[i].val = i; + } + + ikeysort(nvtxs, keys); + + l = cptr[0] = 0; + for (cnvtxs=i=0; i<nvtxs; i++) { + ii = keys[i].val; + if (map[ii] == -1) { + mark[ii] = i; /* Add the diagonal entry */ + for (j=xadj[ii]; j<xadj[ii+1]; j++) + mark[adjncy[j]] = i; + + cind[l++] = ii; + map[ii] = cnvtxs; + + for (j=i+1; j<nvtxs; j++) { + iii = keys[j].val; + + if (keys[i].key != keys[j].key || xadj[ii+1]-xadj[ii] != xadj[iii+1]-xadj[iii]) + break; /* Break if keys or degrees are different */ + + if (map[iii] == -1) { /* Do a comparison if iii has not been mapped */ + for (jj=xadj[iii]; jj<xadj[iii+1]; jj++) { + if (mark[adjncy[jj]] != i) + break; + } + + if (jj == xadj[iii+1]) { /* Identical adjacency structure */ + map[iii] = cnvtxs; + cind[l++] = iii; + } + } + } + + cptr[++cnvtxs] = l; + } + } + + /* printf("Original: %6d, Compressed: %6d\n", nvtxs, cnvtxs); */ + + + InitGraph(graph); + + if (cnvtxs >= COMPRESSION_FRACTION*nvtxs) { + graph->nvtxs = nvtxs; + graph->nedges = xadj[nvtxs]; + graph->ncon = 1; + graph->xadj = xadj; + graph->adjncy = adjncy; + + graph->gdata = idxmalloc(3*nvtxs+graph->nedges, "CompressGraph: gdata"); + graph->vwgt = graph->gdata; + graph->adjwgtsum = graph->gdata+nvtxs; + graph->cmap = graph->gdata+2*nvtxs; + graph->adjwgt = graph->gdata+3*nvtxs; + + idxset(nvtxs, 1, graph->vwgt); + idxset(graph->nedges, 1, graph->adjwgt); + for (i=0; i<nvtxs; i++) + graph->adjwgtsum[i] = xadj[i+1]-xadj[i]; + + graph->label = idxmalloc(nvtxs, "CompressGraph: label"); + for (i=0; i<nvtxs; i++) + graph->label[i] = i; + } + else { /* Ok, form the compressed graph */ + cnedges = 0; + for (i=0; i<cnvtxs; i++) { + ii = cind[cptr[i]]; + cnedges += xadj[ii+1]-xadj[ii]; + } + + /* Allocate memory for the compressed graph*/ + graph->gdata = idxmalloc(4*cnvtxs+1 + 2*cnedges, "CompressGraph: gdata"); + cxadj = graph->xadj = graph->gdata; + cvwgt = graph->vwgt = graph->gdata + cnvtxs+1; + graph->adjwgtsum = graph->gdata + 2*cnvtxs+1; + graph->cmap = graph->gdata + 3*cnvtxs+1; + cadjncy = graph->adjncy = graph->gdata + 4*cnvtxs+1; + graph->adjwgt = graph->gdata + 4*cnvtxs+1 + cnedges; + + /* Now go and compress the graph */ + idxset(nvtxs, -1, mark); + l = cxadj[0] = 0; + for (i=0; i<cnvtxs; i++) { + cvwgt[i] = cptr[i+1]-cptr[i]; + mark[i] = i; /* Remove any dioganal entries in the compressed graph */ + for (j=cptr[i]; j<cptr[i+1]; j++) { + ii = cind[j]; + for (jj=xadj[ii]; jj<xadj[ii+1]; jj++) { + k = map[adjncy[jj]]; + if (mark[k] != i) + cadjncy[l++] = k; + mark[k] = i; + } + } + cxadj[i+1] = l; + } + + graph->nvtxs = cnvtxs; + graph->nedges = l; + graph->ncon = 1; + + idxset(graph->nedges, 1, graph->adjwgt); + for (i=0; i<cnvtxs; i++) + graph->adjwgtsum[i] = cxadj[i+1]-cxadj[i]; + + graph->label = idxmalloc(cnvtxs, "CompressGraph: label"); + for (i=0; i<cnvtxs; i++) + graph->label[i] = i; + + } + + GKfree(&keys, &map, &mark, LTERM); +} + + + +/************************************************************************* +* This function prunes all the vertices in a graph with degree greater +* than factor*average +**************************************************************************/ +void PruneGraph(CtrlType *ctrl, GraphType *graph, int nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *iperm, float factor) +{ + int i, j, k, l, nlarge, pnvtxs, pnedges; + idxtype *pxadj, *padjncy, *padjwgt, *pvwgt; + idxtype *perm; + + perm = idxmalloc(nvtxs, "PruneGraph: perm"); + + factor = factor*xadj[nvtxs]/nvtxs; + + pnvtxs = pnedges = nlarge = 0; + for (i=0; i<nvtxs; i++) { + if (xadj[i+1]-xadj[i] < factor) { + perm[i] = pnvtxs; + iperm[pnvtxs++] = i; + pnedges += xadj[i+1]-xadj[i]; + } + else { + perm[i] = nvtxs - ++nlarge; + iperm[nvtxs-nlarge] = i; + } + } + + /* printf("Pruned %d vertices\n", nlarge); */ + + InitGraph(graph); + + if (nlarge == 0) { /* No prunning */ + graph->nvtxs = nvtxs; + graph->nedges = xadj[nvtxs]; + graph->ncon = 1; + graph->xadj = xadj; + graph->adjncy = adjncy; + + graph->gdata = idxmalloc(3*nvtxs+graph->nedges, "CompressGraph: gdata"); + graph->vwgt = graph->gdata; + graph->adjwgtsum = graph->gdata+nvtxs; + graph->cmap = graph->gdata+2*nvtxs; + graph->adjwgt = graph->gdata+3*nvtxs; + + idxset(nvtxs, 1, graph->vwgt); + idxset(graph->nedges, 1, graph->adjwgt); + for (i=0; i<nvtxs; i++) + graph->adjwgtsum[i] = xadj[i+1]-xadj[i]; + + graph->label = idxmalloc(nvtxs, "CompressGraph: label"); + for (i=0; i<nvtxs; i++) + graph->label[i] = i; + } + else { /* Prune the graph */ + /* Allocate memory for the compressed graph*/ + graph->gdata = idxmalloc(4*pnvtxs+1 + 2*pnedges, "PruneGraph: gdata"); + pxadj = graph->xadj = graph->gdata; + graph->vwgt = graph->gdata + pnvtxs+1; + graph->adjwgtsum = graph->gdata + 2*pnvtxs+1; + graph->cmap = graph->gdata + 3*pnvtxs+1; + padjncy = graph->adjncy = graph->gdata + 4*pnvtxs+1; + graph->adjwgt = graph->gdata + 4*pnvtxs+1 + pnedges; + + pxadj[0] = pnedges = l = 0; + for (i=0; i<nvtxs; i++) { + if (xadj[i+1]-xadj[i] < factor) { + for (j=xadj[i]; j<xadj[i+1]; j++) { + k = perm[adjncy[j]]; + if (k < pnvtxs) + padjncy[pnedges++] = k; + } + pxadj[++l] = pnedges; + } + } + + graph->nvtxs = pnvtxs; + graph->nedges = pnedges; + graph->ncon = 1; + + idxset(pnvtxs, 1, graph->vwgt); + idxset(pnedges, 1, graph->adjwgt); + for (i=0; i<pnvtxs; i++) + graph->adjwgtsum[i] = pxadj[i+1]-pxadj[i]; + + graph->label = idxmalloc(pnvtxs, "CompressGraph: label"); + for (i=0; i<pnvtxs; i++) + graph->label[i] = i; + } + + free(perm); + +} + + + + + + + + + diff --git a/contrib/Metis/debug.c b/contrib/Metis/debug.c new file mode 100644 index 0000000000..3a30fe9d78 --- /dev/null +++ b/contrib/Metis/debug.c @@ -0,0 +1,239 @@ +/* + * Copyright 1997, Regents of the University of Minnesota + * + * debug.c + * + * This file contains code that performs self debuging + * + * Started 7/24/97 + * George + * + * $Id: debug.c,v 1.1 2005-09-21 17:29:37 geuzaine Exp $ + * + */ + +#include <metis.h> + +/************************************************************************* +* This function computes the cut given the graph and a where vector +**************************************************************************/ +int ComputeCut(GraphType *graph, idxtype *where) +{ + int i, j, cut; + + if (graph->adjwgt == NULL) { + for (cut=0, i=0; i<graph->nvtxs; i++) { + for (j=graph->xadj[i]; j<graph->xadj[i+1]; j++) + if (where[i] != where[graph->adjncy[j]]) + cut++; + } + } + else { + for (cut=0, i=0; i<graph->nvtxs; i++) { + for (j=graph->xadj[i]; j<graph->xadj[i+1]; j++) + if (where[i] != where[graph->adjncy[j]]) + cut += graph->adjwgt[j]; + } + } + + return cut/2; +} + + +/************************************************************************* +* This function checks whether or not the boundary information is correct +**************************************************************************/ +int CheckBnd(GraphType *graph) +{ + int i, j, nvtxs, nbnd; + idxtype *xadj, *adjncy, *where, *bndptr, *bndind; + + nvtxs = graph->nvtxs; + xadj = graph->xadj; + adjncy = graph->adjncy; + where = graph->where; + bndptr = graph->bndptr; + bndind = graph->bndind; + + for (nbnd=0, i=0; i<nvtxs; i++) { + if (xadj[i+1]-xadj[i] == 0) + nbnd++; /* Islands are considered to be boundary vertices */ + + for (j=xadj[i]; j<xadj[i+1]; j++) { + if (where[i] != where[adjncy[j]]) { + nbnd++; + ASSERT(bndptr[i] != -1); + ASSERT(bndind[bndptr[i]] == i); + break; + } + } + } + + ASSERTP(nbnd == graph->nbnd, ("%d %d\n", nbnd, graph->nbnd)); + + return 1; +} + + + +/************************************************************************* +* This function checks whether or not the boundary information is correct +**************************************************************************/ +int CheckBnd2(GraphType *graph) +{ + int i, j, nvtxs, nbnd, id, ed; + idxtype *xadj, *adjncy, *where, *bndptr, *bndind; + + nvtxs = graph->nvtxs; + xadj = graph->xadj; + adjncy = graph->adjncy; + where = graph->where; + bndptr = graph->bndptr; + bndind = graph->bndind; + + for (nbnd=0, i=0; i<nvtxs; i++) { + id = ed = 0; + for (j=xadj[i]; j<xadj[i+1]; j++) { + if (where[i] != where[adjncy[j]]) + ed += graph->adjwgt[j]; + else + id += graph->adjwgt[j]; + } + if (ed - id >= 0 && xadj[i] < xadj[i+1]) { + nbnd++; + ASSERTP(bndptr[i] != -1, ("%d %d %d\n", i, id, ed)); + ASSERT(bndind[bndptr[i]] == i); + } + } + + ASSERTP(nbnd == graph->nbnd, ("%d %d\n", nbnd, graph->nbnd)); + + return 1; +} + +/************************************************************************* +* This function checks whether or not the boundary information is correct +**************************************************************************/ +int CheckNodeBnd(GraphType *graph, int onbnd) +{ + int i, j, nvtxs, nbnd; + idxtype *xadj, *adjncy, *where, *bndptr, *bndind; + + nvtxs = graph->nvtxs; + xadj = graph->xadj; + adjncy = graph->adjncy; + where = graph->where; + bndptr = graph->bndptr; + bndind = graph->bndind; + + for (nbnd=0, i=0; i<nvtxs; i++) { + if (where[i] == 2) + nbnd++; + } + + ASSERTP(nbnd == onbnd, ("%d %d\n", nbnd, onbnd)); + + for (i=0; i<nvtxs; i++) { + if (where[i] != 2) { + ASSERTP(bndptr[i] == -1, ("%d %d\n", i, bndptr[i])); + } + else { + ASSERTP(bndptr[i] != -1, ("%d %d\n", i, bndptr[i])); + } + } + + return 1; +} + + + +/************************************************************************* +* This function checks whether or not the rinfo of a vertex is consistent +**************************************************************************/ +int CheckRInfo(RInfoType *rinfo) +{ + int i, j; + + for (i=0; i<rinfo->ndegrees; i++) { + for (j=i+1; j<rinfo->ndegrees; j++) + ASSERTP(rinfo->edegrees[i].pid != rinfo->edegrees[j].pid, ("%d %d %d %d\n", i, j, rinfo->edegrees[i].pid, rinfo->edegrees[j].pid)); + } + + return 1; +} + + + +/************************************************************************* +* This function checks the correctness of the NodeFM data structures +**************************************************************************/ +int CheckNodePartitionParams(GraphType *graph) +{ + int i, j, k, l, nvtxs, me, other; + idxtype *xadj, *adjncy, *adjwgt, *vwgt, *where; + idxtype edegrees[2], pwgts[3]; + + nvtxs = graph->nvtxs; + xadj = graph->xadj; + vwgt = graph->vwgt; + adjncy = graph->adjncy; + adjwgt = graph->adjwgt; + + where = graph->where; + + /*------------------------------------------------------------ + / Compute now the separator external degrees + /------------------------------------------------------------*/ + pwgts[0] = pwgts[1] = pwgts[2] = 0; + for (i=0; i<nvtxs; i++) { + me = where[i]; + pwgts[me] += vwgt[i]; + + if (me == 2) { /* If it is on the separator do some computations */ + edegrees[0] = edegrees[1] = 0; + + for (j=xadj[i]; j<xadj[i+1]; j++) { + other = where[adjncy[j]]; + if (other != 2) + edegrees[other] += vwgt[adjncy[j]]; + } + if (edegrees[0] != graph->nrinfo[i].edegrees[0] || edegrees[1] != graph->nrinfo[i].edegrees[1]) { + printf("Something wrong with edegrees: %d %d %d %d %d\n", i, edegrees[0], edegrees[1], graph->nrinfo[i].edegrees[0], graph->nrinfo[i].edegrees[1]); + return 0; + } + } + } + + if (pwgts[0] != graph->pwgts[0] || pwgts[1] != graph->pwgts[1] || pwgts[2] != graph->pwgts[2]) + printf("Something wrong with part-weights: %d %d %d %d %d %d\n", pwgts[0], pwgts[1], pwgts[2], graph->pwgts[0], graph->pwgts[1], graph->pwgts[2]); + + return 1; +} + + +/************************************************************************* +* This function checks if the separator is indeed a separator +**************************************************************************/ +int IsSeparable(GraphType *graph) +{ + int i, j, nvtxs, other; + idxtype *xadj, *adjncy, *where; + + nvtxs = graph->nvtxs; + xadj = graph->xadj; + adjncy = graph->adjncy; + where = graph->where; + + for (i=0; i<nvtxs; i++) { + if (where[i] == 2) + continue; + other = (where[i]+1)%2; + for (j=xadj[i]; j<xadj[i+1]; j++) { + ASSERTP(where[adjncy[j]] != other, ("%d %d %d %d %d %d\n", i, where[i], adjncy[j], where[adjncy[j]], xadj[i+1]-xadj[i], xadj[adjncy[j]+1]-xadj[adjncy[j]])); + } + } + + return 1; +} + + diff --git a/contrib/Metis/defs.h b/contrib/Metis/defs.h new file mode 100644 index 0000000000..472e2db06a --- /dev/null +++ b/contrib/Metis/defs.h @@ -0,0 +1,161 @@ +/* + * Copyright 1997, Regents of the University of Minnesota + * + * defs.h + * + * This file contains constant definitions + * + * Started 8/27/94 + * George + * + * $Id: defs.h,v 1.1 2005-09-21 17:29:37 geuzaine Exp $ + * + */ + +#define METISTITLE " METIS 4.0.1 Copyright 1998, Regents of the University of Minnesota\n\n" +#define MAXLINE 1280000 + +#define LTERM (void **) 0 /* List terminator for GKfree() */ + +#define MAXNCON 16 /* The maximum number of constrains */ +#define MAXNOBJ 16 /* The maximum number of objectives */ + +#define PLUS_GAINSPAN 500 /* Parameters for FM buckets */ +#define NEG_GAINSPAN 500 + +#define HTLENGTH ((1<<11)-1) + +/* Meaning of various options[] parameters */ +#define OPTION_PTYPE 0 +#define OPTION_CTYPE 1 +#define OPTION_ITYPE 2 +#define OPTION_RTYPE 3 +#define OPTION_DBGLVL 4 +#define OPTION_OFLAGS 5 +#define OPTION_PFACTOR 6 +#define OPTION_NSEPS 7 + +#define OFLAG_COMPRESS 1 /* Try to compress the graph */ +#define OFLAG_CCMP 2 /* Find and order connected components */ + + +/* Default options for PMETIS */ +#define PMETIS_CTYPE MATCH_SHEM +#define PMETIS_ITYPE IPART_GGPKL +#define PMETIS_RTYPE RTYPE_FM +#define PMETIS_DBGLVL 0 + +/* Default options for KMETIS */ +#define KMETIS_CTYPE MATCH_SHEM +#define KMETIS_ITYPE IPART_PMETIS +#define KMETIS_RTYPE RTYPE_KWAYRANDOM_MCONN +#define KMETIS_DBGLVL 0 + +/* Default options for OEMETIS */ +#define OEMETIS_CTYPE MATCH_SHEM +#define OEMETIS_ITYPE IPART_GGPKL +#define OEMETIS_RTYPE RTYPE_FM +#define OEMETIS_DBGLVL 0 + +/* Default options for ONMETIS */ +#define ONMETIS_CTYPE MATCH_SHEM +#define ONMETIS_ITYPE IPART_GGPKL +#define ONMETIS_RTYPE RTYPE_SEP1SIDED +#define ONMETIS_DBGLVL 0 +#define ONMETIS_OFLAGS OFLAG_COMPRESS +#define ONMETIS_PFACTOR -1 +#define ONMETIS_NSEPS 1 + +/* Default options for McPMETIS */ +#define McPMETIS_CTYPE MATCH_SHEBM_ONENORM +#define McPMETIS_ITYPE IPART_RANDOM +#define McPMETIS_RTYPE RTYPE_FM +#define McPMETIS_DBGLVL 0 + +/* Default options for McKMETIS */ +#define McKMETIS_CTYPE MATCH_SHEBM_ONENORM +#define McKMETIS_ITYPE IPART_McHPMETIS +#define McKMETIS_RTYPE RTYPE_KWAYRANDOM +#define McKMETIS_DBGLVL 0 + +/* Default options for KVMETIS */ +#define KVMETIS_CTYPE MATCH_SHEM +#define KVMETIS_ITYPE IPART_PMETIS +#define KVMETIS_RTYPE RTYPE_KWAYRANDOM +#define KVMETIS_DBGLVL 0 + + +/* Operations supported by stand-alone code */ +#define OP_PMETIS 1 +#define OP_KMETIS 2 +#define OP_OEMETIS 3 +#define OP_ONMETIS 4 +#define OP_ONWMETIS 5 +#define OP_KVMETIS 6 + + +/* Matching Schemes */ +#define MATCH_RM 1 +#define MATCH_HEM 2 +#define MATCH_SHEM 3 +#define MATCH_SHEMKWAY 4 +#define MATCH_SHEBM_ONENORM 5 +#define MATCH_SHEBM_INFNORM 6 +#define MATCH_SBHEM_ONENORM 7 +#define MATCH_SBHEM_INFNORM 8 + +/* Initial partitioning schemes for PMETIS and ONMETIS */ +#define IPART_GGPKL 1 +#define IPART_GGPKLNODE 2 +#define IPART_RANDOM 2 + +/* Refinement schemes for PMETIS */ +#define RTYPE_FM 1 + +/* Initial partitioning schemes for KMETIS */ +#define IPART_PMETIS 1 + +/* Refinement schemes for KMETIS */ +#define RTYPE_KWAYRANDOM 1 +#define RTYPE_KWAYGREEDY 2 +#define RTYPE_KWAYRANDOM_MCONN 3 + +/* Refinement schemes for ONMETIS */ +#define RTYPE_SEP2SIDED 1 +#define RTYPE_SEP1SIDED 2 + +/* Initial Partitioning Schemes for McKMETIS */ +#define IPART_McPMETIS 1 /* Simple McPMETIS */ +#define IPART_McHPMETIS 2 /* horizontally relaxed McPMETIS */ + +#define UNMATCHED -1 + +#define HTABLE_EMPTY -1 + +#define NGR_PASSES 4 /* Number of greedy refinement passes */ +#define NLGR_PASSES 5 /* Number of GR refinement during IPartition */ + +#define LARGENIPARTS 8 /* Number of random initial partitions */ +#define SMALLNIPARTS 3 /* Number of random initial partitions */ + +#define COARSEN_FRACTION 0.75 /* Node reduction between succesive coarsening levels */ +#define COARSEN_FRACTION2 0.90 /* Node reduction between succesive coarsening levels */ +#define UNBALANCE_FRACTION 1.05 + +#define COMPRESSION_FRACTION 0.85 + +#define ORDER_UNBALANCE_FRACTION 1.10 + +#define MMDSWITCH 200 + +#define HORIZONTAL_IMBALANCE 1.05 + +/* Debug Levels */ +#define DBG_TIME 1 /* Perform timing analysis */ +#define DBG_OUTPUT 2 +#define DBG_COARSEN 4 /* Show the coarsening progress */ +#define DBG_REFINE 8 /* Show info on communication during folding */ +#define DBG_IPART 16 /* Show info on initial partition */ +#define DBG_MOVEINFO 32 /* Show info on communication during folding */ +#define DBG_KWAYPINFO 64 /* Show info on communication during folding */ +#define DBG_SEPINFO 128 /* Show info on communication during folding */ diff --git a/contrib/Metis/estmem.c b/contrib/Metis/estmem.c new file mode 100644 index 0000000000..852d5ac5e0 --- /dev/null +++ b/contrib/Metis/estmem.c @@ -0,0 +1,157 @@ +/* + * Copyright 1997, Regents of the University of Minnesota + * + * estmem.c + * + * This file contains code for estimating the amount of memory required by + * the various routines in METIS + * + * Started 11/4/97 + * George + * + * $Id: estmem.c,v 1.1 2005-09-21 17:29:37 geuzaine Exp $ + * + */ + +#include <metis.h> + +/************************************************************************* +* This function computes how much memory will be required by the various +* routines in METIS +**************************************************************************/ +void METIS_EstimateMemory(int *nvtxs, idxtype *xadj, idxtype *adjncy, int *numflag, int *optype, int *nbytes) +{ + int i, j, k, nedges, nlevels; + float vfraction, efraction, vmult, emult; + int coresize, gdata, rdata; + + if (*numflag == 1) + Change2CNumbering(*nvtxs, xadj, adjncy); + + nedges = xadj[*nvtxs]; + + InitRandom(-1); + EstimateCFraction(*nvtxs, xadj, adjncy, &vfraction, &efraction); + + /* Estimate the amount of memory for coresize */ + if (*optype == 2) + coresize = nedges; + else + coresize = 0; + coresize += nedges + 11*(*nvtxs) + 4*1024 + 2*(NEG_GAINSPAN+PLUS_GAINSPAN+1)*(sizeof(ListNodeType *)/sizeof(idxtype)); + coresize += 2*(*nvtxs); /* add some more fore other vectors */ + + gdata = nedges; /* Assume that the user does not pass weights */ + + nlevels = (int)(log(100.0/(*nvtxs))/log(vfraction) + .5); + vmult = 0.5 + (1.0 - pow(vfraction, nlevels))/(1.0 - vfraction); + emult = 1.0 + (1.0 - pow(efraction, nlevels+1))/(1.0 - efraction); + + gdata += vmult*4*(*nvtxs) + emult*2*nedges; + if ((vmult-1.0)*4*(*nvtxs) + (emult-1.0)*2*nedges < 5*(*nvtxs)) + rdata = 0; + else + rdata = 5*(*nvtxs); + + *nbytes = sizeof(idxtype)*(coresize+gdata+rdata+(*nvtxs)); + + if (*numflag == 1) + Change2FNumbering2(*nvtxs, xadj, adjncy); +} + + +/************************************************************************* +* This function finds a matching using the HEM heuristic +**************************************************************************/ +void EstimateCFraction(int nvtxs, idxtype *xadj, idxtype *adjncy, float *vfraction, float *efraction) +{ + int i, ii, j, cnvtxs, cnedges, maxidx; + idxtype *match, *cmap, *perm; + + cmap = idxmalloc(nvtxs, "cmap"); + match = idxsmalloc(nvtxs, UNMATCHED, "match"); + perm = idxmalloc(nvtxs, "perm"); + RandomPermute(nvtxs, perm, 1); + + cnvtxs = 0; + for (ii=0; ii<nvtxs; ii++) { + i = perm[ii]; + + if (match[i] == UNMATCHED) { /* Unmatched */ + maxidx = i; + + /* Find a random matching, subject to maxvwgt constraints */ + for (j=xadj[i]; j<xadj[i+1]; j++) { + if (match[adjncy[j]] == UNMATCHED) { + maxidx = adjncy[j]; + break; + } + } + + cmap[i] = cmap[maxidx] = cnvtxs++; + match[i] = maxidx; + match[maxidx] = i; + } + } + + cnedges = ComputeCoarseGraphSize(nvtxs, xadj, adjncy, cnvtxs, cmap, match, perm); + + *vfraction = (1.0*cnvtxs)/(1.0*nvtxs); + *efraction = (1.0*cnedges)/(1.0*xadj[nvtxs]); + + GKfree(&cmap, &match, &perm, LTERM); +} + + + + +/************************************************************************* +* This function computes the size of the coarse graph +**************************************************************************/ +int ComputeCoarseGraphSize(int nvtxs, idxtype *xadj, idxtype *adjncy, int cnvtxs, idxtype *cmap, idxtype *match, idxtype *perm) +{ + int i, j, k, istart, iend, nedges, cnedges, v, u; + idxtype *htable; + + htable = idxsmalloc(cnvtxs, -1, "htable"); + + cnvtxs = cnedges = 0; + for (i=0; i<nvtxs; i++) { + v = perm[i]; + if (cmap[v] != cnvtxs) + continue; + + htable[cnvtxs] = cnvtxs; + + u = match[v]; + + istart = xadj[v]; + iend = xadj[v+1]; + for (j=istart; j<iend; j++) { + k = cmap[adjncy[j]]; + if (htable[k] != cnvtxs) { + htable[k] = cnvtxs; + cnedges++; + } + } + + if (v != u) { + istart = xadj[u]; + iend = xadj[u+1]; + for (j=istart; j<iend; j++) { + k = cmap[adjncy[j]]; + if (htable[k] != cnvtxs) { + htable[k] = cnvtxs; + cnedges++; + } + } + } + cnvtxs++; + } + + GKfree(&htable, LTERM); + + return cnedges; +} + + diff --git a/contrib/Metis/fm.c b/contrib/Metis/fm.c new file mode 100644 index 0000000000..79cd74fa1a --- /dev/null +++ b/contrib/Metis/fm.c @@ -0,0 +1,194 @@ +/* + * Copyright 1997, Regents of the University of Minnesota + * + * fm.c + * + * This file contains code that implements the edge-based FM refinement + * + * Started 7/23/97 + * George + * + * $Id: fm.c,v 1.1 2005-09-21 17:29:37 geuzaine Exp $ + */ + +#include <metis.h> + + +/************************************************************************* +* This function performs an edge-based FM refinement +**************************************************************************/ +void FM_2WayEdgeRefine(CtrlType *ctrl, GraphType *graph, int *tpwgts, int npasses) +{ + int i, ii, j, k, kwgt, nvtxs, nbnd, nswaps, from, to, pass, me, limit, tmp; + idxtype *xadj, *vwgt, *adjncy, *adjwgt, *where, *id, *ed, *bndptr, *bndind, *pwgts; + idxtype *moved, *swaps, *perm; + PQueueType parts[2]; + int higain, oldgain, mincut, mindiff, origdiff, initcut, newcut, mincutorder, avgvwgt; + + nvtxs = graph->nvtxs; + xadj = graph->xadj; + vwgt = graph->vwgt; + adjncy = graph->adjncy; + adjwgt = graph->adjwgt; + where = graph->where; + id = graph->id; + ed = graph->ed; + pwgts = graph->pwgts; + bndptr = graph->bndptr; + bndind = graph->bndind; + + moved = idxwspacemalloc(ctrl, nvtxs); + swaps = idxwspacemalloc(ctrl, nvtxs); + perm = idxwspacemalloc(ctrl, nvtxs); + + limit = amin(amax(0.01*nvtxs, 15), 100); + avgvwgt = amin((pwgts[0]+pwgts[1])/20, 2*(pwgts[0]+pwgts[1])/nvtxs); + + tmp = graph->adjwgtsum[idxamax(nvtxs, graph->adjwgtsum)]; + PQueueInit(ctrl, &parts[0], nvtxs, tmp); + PQueueInit(ctrl, &parts[1], nvtxs, tmp); + + IFSET(ctrl->dbglvl, DBG_REFINE, + printf("Partitions: [%6d %6d] T[%6d %6d], Nv-Nb[%6d %6d]. ICut: %6d\n", + pwgts[0], pwgts[1], tpwgts[0], tpwgts[1], graph->nvtxs, graph->nbnd, graph->mincut)); + + origdiff = abs(tpwgts[0]-pwgts[0]); + idxset(nvtxs, -1, moved); + for (pass=0; pass<npasses; pass++) { /* Do a number of passes */ + PQueueReset(&parts[0]); + PQueueReset(&parts[1]); + + mincutorder = -1; + newcut = mincut = initcut = graph->mincut; + mindiff = abs(tpwgts[0]-pwgts[0]); + + ASSERT(ComputeCut(graph, where) == graph->mincut); + ASSERT(CheckBnd(graph)); + + /* Insert boundary nodes in the priority queues */ + nbnd = graph->nbnd; + RandomPermute(nbnd, perm, 1); + for (ii=0; ii<nbnd; ii++) { + i = perm[ii]; + ASSERT(ed[bndind[i]] > 0 || id[bndind[i]] == 0); + ASSERT(bndptr[bndind[i]] != -1); + PQueueInsert(&parts[where[bndind[i]]], bndind[i], ed[bndind[i]]-id[bndind[i]]); + } + + for (nswaps=0; nswaps<nvtxs; nswaps++) { + from = (tpwgts[0]-pwgts[0] < tpwgts[1]-pwgts[1] ? 0 : 1); + to = (from+1)%2; + + if ((higain = PQueueGetMax(&parts[from])) == -1) + break; + ASSERT(bndptr[higain] != -1); + + newcut -= (ed[higain]-id[higain]); + INC_DEC(pwgts[to], pwgts[from], vwgt[higain]); + + if ((newcut < mincut && abs(tpwgts[0]-pwgts[0]) <= origdiff+avgvwgt) || + (newcut == mincut && abs(tpwgts[0]-pwgts[0]) < mindiff)) { + mincut = newcut; + mindiff = abs(tpwgts[0]-pwgts[0]); + mincutorder = nswaps; + } + else if (nswaps-mincutorder > limit) { /* We hit the limit, undo last move */ + newcut += (ed[higain]-id[higain]); + INC_DEC(pwgts[from], pwgts[to], vwgt[higain]); + break; + } + + where[higain] = to; + moved[higain] = nswaps; + swaps[nswaps] = higain; + + IFSET(ctrl->dbglvl, DBG_MOVEINFO, + printf("Moved %6d from %d. [%3d %3d] %5d [%4d %4d]\n", higain, from, ed[higain]-id[higain], vwgt[higain], newcut, pwgts[0], pwgts[1])); + + /************************************************************** + * Update the id[i]/ed[i] values of the affected nodes + ***************************************************************/ + SWAP(id[higain], ed[higain], tmp); + if (ed[higain] == 0 && xadj[higain] < xadj[higain+1]) + BNDDelete(nbnd, bndind, bndptr, higain); + + for (j=xadj[higain]; j<xadj[higain+1]; j++) { + k = adjncy[j]; + oldgain = ed[k]-id[k]; + + kwgt = (to == where[k] ? adjwgt[j] : -adjwgt[j]); + INC_DEC(id[k], ed[k], kwgt); + + /* Update its boundary information and queue position */ + if (bndptr[k] != -1) { /* If k was a boundary vertex */ + if (ed[k] == 0) { /* Not a boundary vertex any more */ + BNDDelete(nbnd, bndind, bndptr, k); + if (moved[k] == -1) /* Remove it if in the queues */ + PQueueDelete(&parts[where[k]], k, oldgain); + } + else { /* If it has not been moved, update its position in the queue */ + if (moved[k] == -1) + PQueueUpdate(&parts[where[k]], k, oldgain, ed[k]-id[k]); + } + } + else { + if (ed[k] > 0) { /* It will now become a boundary vertex */ + BNDInsert(nbnd, bndind, bndptr, k); + if (moved[k] == -1) + PQueueInsert(&parts[where[k]], k, ed[k]-id[k]); + } + } + } + + } + + + /**************************************************************** + * Roll back computations + *****************************************************************/ + for (i=0; i<nswaps; i++) + moved[swaps[i]] = -1; /* reset moved array */ + for (nswaps--; nswaps>mincutorder; nswaps--) { + higain = swaps[nswaps]; + + to = where[higain] = (where[higain]+1)%2; + SWAP(id[higain], ed[higain], tmp); + if (ed[higain] == 0 && bndptr[higain] != -1 && xadj[higain] < xadj[higain+1]) + BNDDelete(nbnd, bndind, bndptr, higain); + else if (ed[higain] > 0 && bndptr[higain] == -1) + BNDInsert(nbnd, bndind, bndptr, higain); + + INC_DEC(pwgts[to], pwgts[(to+1)%2], vwgt[higain]); + for (j=xadj[higain]; j<xadj[higain+1]; j++) { + k = adjncy[j]; + + kwgt = (to == where[k] ? adjwgt[j] : -adjwgt[j]); + INC_DEC(id[k], ed[k], kwgt); + + if (bndptr[k] != -1 && ed[k] == 0) + BNDDelete(nbnd, bndind, bndptr, k); + if (bndptr[k] == -1 && ed[k] > 0) + BNDInsert(nbnd, bndind, bndptr, k); + } + } + + IFSET(ctrl->dbglvl, DBG_REFINE, + printf("\tMinimum cut: %6d at %5d, PWGTS: [%6d %6d], NBND: %6d\n", mincut, mincutorder, pwgts[0], pwgts[1], nbnd)); + + graph->mincut = mincut; + graph->nbnd = nbnd; + + if (mincutorder == -1 || mincut == initcut) + break; + } + + PQueueFree(ctrl, &parts[0]); + PQueueFree(ctrl, &parts[1]); + + idxwspacefree(ctrl, nvtxs); + idxwspacefree(ctrl, nvtxs); + idxwspacefree(ctrl, nvtxs); + +} + + diff --git a/contrib/Metis/fortran.c b/contrib/Metis/fortran.c new file mode 100644 index 0000000000..a89c65408a --- /dev/null +++ b/contrib/Metis/fortran.c @@ -0,0 +1,141 @@ +/* + * Copyright 1997, Regents of the University of Minnesota + * + * fortran.c + * + * This file contains code for the fortran to C interface + * + * Started 8/19/97 + * George + * + * $Id: fortran.c,v 1.1 2005-09-21 17:29:37 geuzaine Exp $ + * + */ + +#include <metis.h> + + +/************************************************************************* +* This function changes the numbering to start from 0 instead of 1 +**************************************************************************/ +void Change2CNumbering(int nvtxs, idxtype *xadj, idxtype *adjncy) +{ + int i, nedges; + + for (i=0; i<=nvtxs; i++) + xadj[i]--; + + nedges = xadj[nvtxs]; + for (i=0; i<nedges; i++) + adjncy[i]--; +} + +/************************************************************************* +* This function changes the numbering to start from 1 instead of 0 +**************************************************************************/ +void Change2FNumbering(int nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vector) +{ + int i, nedges; + + for (i=0; i<nvtxs; i++) + vector[i]++; + + nedges = xadj[nvtxs]; + for (i=0; i<nedges; i++) + adjncy[i]++; + + for (i=0; i<=nvtxs; i++) + xadj[i]++; +} + +/************************************************************************* +* This function changes the numbering to start from 1 instead of 0 +**************************************************************************/ +void Change2FNumbering2(int nvtxs, idxtype *xadj, idxtype *adjncy) +{ + int i, nedges; + + nedges = xadj[nvtxs]; + for (i=0; i<nedges; i++) + adjncy[i]++; + + for (i=0; i<=nvtxs; i++) + xadj[i]++; +} + + + +/************************************************************************* +* This function changes the numbering to start from 1 instead of 0 +**************************************************************************/ +void Change2FNumberingOrder(int nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *v1, idxtype *v2) +{ + int i, nedges; + + for (i=0; i<nvtxs; i++) { + v1[i]++; + v2[i]++; + } + + nedges = xadj[nvtxs]; + for (i=0; i<nedges; i++) + adjncy[i]++; + + for (i=0; i<=nvtxs; i++) + xadj[i]++; + +} + + + +/************************************************************************* +* This function changes the numbering to start from 0 instead of 1 +**************************************************************************/ +void ChangeMesh2CNumbering(int n, idxtype *mesh) +{ + int i; + + for (i=0; i<n; i++) + mesh[i]--; + +} + + +/************************************************************************* +* This function changes the numbering to start from 1 instead of 0 +**************************************************************************/ +void ChangeMesh2FNumbering(int n, idxtype *mesh, int nvtxs, idxtype *xadj, idxtype *adjncy) +{ + int i, nedges; + + for (i=0; i<n; i++) + mesh[i]++; + + nedges = xadj[nvtxs]; + for (i=0; i<nedges; i++) + adjncy[i]++; + + for (i=0; i<=nvtxs; i++) + xadj[i]++; + +} + + +/************************************************************************* +* This function changes the numbering to start from 1 instead of 0 +**************************************************************************/ +void ChangeMesh2FNumbering2(int n, idxtype *mesh, int ne, int nn, idxtype *epart, idxtype *npart) +{ + int i, nedges; + + for (i=0; i<n; i++) + mesh[i]++; + + for (i=0; i<ne; i++) + epart[i]++; + + for (i=0; i<nn; i++) + npart[i]++; + +} + diff --git a/contrib/Metis/frename.c b/contrib/Metis/frename.c new file mode 100644 index 0000000000..0ec34403a0 --- /dev/null +++ b/contrib/Metis/frename.c @@ -0,0 +1,312 @@ +/* + * Copyright 1997, Regents of the University of Minnesota + * + * frename.c + * + * This file contains some renaming routines to deal with different Fortran compilers + * + * Started 9/15/97 + * George + * + * $Id: frename.c,v 1.1 2005-09-21 17:29:37 geuzaine Exp $ + * + */ + +#include <metis.h> + + +void METIS_PARTGRAPHRECURSIVE(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts, int *options, int *edgecut, idxtype *part) +{ + METIS_PartGraphRecursive(nvtxs, xadj, adjncy, vwgt, adjwgt, wgtflag, numflag, nparts, options, edgecut, part); +} +void metis_partgraphrecursive(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts, int *options, int *edgecut, idxtype *part) +{ + METIS_PartGraphRecursive(nvtxs, xadj, adjncy, vwgt, adjwgt, wgtflag, numflag, nparts, options, edgecut, part); +} +void metis_partgraphrecursive_(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts, int *options, int *edgecut, idxtype *part) +{ + METIS_PartGraphRecursive(nvtxs, xadj, adjncy, vwgt, adjwgt, wgtflag, numflag, nparts, options, edgecut, part); +} +void metis_partgraphrecursive__(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts, int *options, int *edgecut, idxtype *part) +{ + METIS_PartGraphRecursive(nvtxs, xadj, adjncy, vwgt, adjwgt, wgtflag, numflag, nparts, options, edgecut, part); +} + + +void METIS_WPARTGRAPHRECURSIVE(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts, float *tpwgts, int *options, int *edgecut, idxtype *part) +{ + METIS_WPartGraphRecursive(nvtxs, xadj, adjncy, vwgt, adjwgt, wgtflag, numflag, nparts, tpwgts, options, edgecut, part); +} +void metis_wpartgraphrecursive(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts, float *tpwgts, int *options, int *edgecut, idxtype *part) +{ + METIS_WPartGraphRecursive(nvtxs, xadj, adjncy, vwgt, adjwgt, wgtflag, numflag, nparts, tpwgts, options, edgecut, part); +} +void metis_wpartgraphrecursive_(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts, float *tpwgts, int *options, int *edgecut, idxtype *part) +{ + METIS_WPartGraphRecursive(nvtxs, xadj, adjncy, vwgt, adjwgt, wgtflag, numflag, nparts, tpwgts, options, edgecut, part); +} +void metis_wpartgraphrecursive__(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts, float *tpwgts, int *options, int *edgecut, idxtype *part) +{ + METIS_WPartGraphRecursive(nvtxs, xadj, adjncy, vwgt, adjwgt, wgtflag, numflag, nparts, tpwgts, options, edgecut, part); +} + + + +void METIS_PARTGRAPHKWAY(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts, int *options, int *edgecut, idxtype *part) +{ + METIS_PartGraphKway(nvtxs, xadj, adjncy, vwgt, adjwgt, wgtflag, numflag, nparts, options, edgecut, part); +} +void metis_partgraphkway(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts, int *options, int *edgecut, idxtype *part) +{ + METIS_PartGraphKway(nvtxs, xadj, adjncy, vwgt, adjwgt, wgtflag, numflag, nparts, options, edgecut, part); +} +void metis_partgraphkway_(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts, int *options, int *edgecut, idxtype *part) +{ + METIS_PartGraphKway(nvtxs, xadj, adjncy, vwgt, adjwgt, wgtflag, numflag, nparts, options, edgecut, part); +} +void metis_partgraphkway__(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts, int *options, int *edgecut, idxtype *part) +{ + METIS_PartGraphKway(nvtxs, xadj, adjncy, vwgt, adjwgt, wgtflag, numflag, nparts, options, edgecut, part); +} + + + +void METIS_WPARTGRAPHKWAY(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts, float *tpwgts, int *options, int *edgecut, idxtype *part) +{ + METIS_WPartGraphKway(nvtxs, xadj, adjncy, vwgt, adjwgt, wgtflag, numflag, nparts, tpwgts, options, edgecut, part); +} +void metis_wpartgraphkway(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts, float *tpwgts, int *options, int *edgecut, idxtype *part) +{ + METIS_WPartGraphKway(nvtxs, xadj, adjncy, vwgt, adjwgt, wgtflag, numflag, nparts, tpwgts, options, edgecut, part); +} +void metis_wpartgraphkway_(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts, float *tpwgts, int *options, int *edgecut, idxtype *part) +{ + METIS_WPartGraphKway(nvtxs, xadj, adjncy, vwgt, adjwgt, wgtflag, numflag, nparts, tpwgts, options, edgecut, part); +} +void metis_wpartgraphkway__(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts, float *tpwgts, int *options, int *edgecut, idxtype *part) +{ + METIS_WPartGraphKway(nvtxs, xadj, adjncy, vwgt, adjwgt, wgtflag, numflag, nparts, tpwgts, options, edgecut, part); +} + + + +void METIS_EDGEND(int *nvtxs, idxtype *xadj, idxtype *adjncy, int *numflag, int *options, idxtype *perm, idxtype *iperm) +{ + METIS_EdgeND(nvtxs, xadj, adjncy, numflag, options, perm, iperm); +} +void metis_edgend(int *nvtxs, idxtype *xadj, idxtype *adjncy, int *numflag, int *options, idxtype *perm, idxtype *iperm) +{ + METIS_EdgeND(nvtxs, xadj, adjncy, numflag, options, perm, iperm); +} +void metis_edgend_(int *nvtxs, idxtype *xadj, idxtype *adjncy, int *numflag, int *options, idxtype *perm, idxtype *iperm) +{ + METIS_EdgeND(nvtxs, xadj, adjncy, numflag, options, perm, iperm); +} +void metis_edgend__(int *nvtxs, idxtype *xadj, idxtype *adjncy, int *numflag, int *options, idxtype *perm, idxtype *iperm) +{ + METIS_EdgeND(nvtxs, xadj, adjncy, numflag, options, perm, iperm); +} + + + +void METIS_NODEND(int *nvtxs, idxtype *xadj, idxtype *adjncy, int *numflag, int *options, idxtype *perm, idxtype *iperm) +{ + METIS_NodeND(nvtxs, xadj, adjncy, numflag, options, perm, iperm); +} +void metis_nodend(int *nvtxs, idxtype *xadj, idxtype *adjncy, int *numflag, int *options, idxtype *perm, idxtype *iperm) +{ + METIS_NodeND(nvtxs, xadj, adjncy, numflag, options, perm, iperm); +} +void metis_nodend_(int *nvtxs, idxtype *xadj, idxtype *adjncy, int *numflag, int *options, idxtype *perm, idxtype *iperm) +{ + METIS_NodeND(nvtxs, xadj, adjncy, numflag, options, perm, iperm); +} +void metis_nodend__(int *nvtxs, idxtype *xadj, idxtype *adjncy, int *numflag, int *options, idxtype *perm, idxtype *iperm) +{ + METIS_NodeND(nvtxs, xadj, adjncy, numflag, options, perm, iperm); +} + + + +void METIS_NODEWND(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, int *numflag, int *options, idxtype *perm, idxtype *iperm) +{ + METIS_NodeWND(nvtxs, xadj, adjncy, vwgt, numflag, options, perm, iperm); +} +void metis_nodewnd(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, int *numflag, int *options, idxtype *perm, idxtype *iperm) +{ + METIS_NodeWND(nvtxs, xadj, adjncy, vwgt, numflag, options, perm, iperm); +} +void metis_nodewnd_(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, int *numflag, int *options, idxtype *perm, idxtype *iperm) +{ + METIS_NodeWND(nvtxs, xadj, adjncy, vwgt, numflag, options, perm, iperm); +} +void metis_nodewnd__(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, int *numflag, int *options, idxtype *perm, idxtype *iperm) +{ + METIS_NodeWND(nvtxs, xadj, adjncy, vwgt, numflag, options, perm, iperm); +} + + + +void METIS_PARTMESHNODAL(int *ne, int *nn, idxtype *elmnts, int *etype, int *numflag, int *nparts, int *edgecut, idxtype *epart, idxtype *npart) +{ + METIS_PartMeshNodal(ne, nn, elmnts, etype, numflag, nparts, edgecut, epart, npart); +} +void metis_partmeshnodal(int *ne, int *nn, idxtype *elmnts, int *etype, int *numflag, int *nparts, int *edgecut, idxtype *epart, idxtype *npart) +{ + METIS_PartMeshNodal(ne, nn, elmnts, etype, numflag, nparts, edgecut, epart, npart); +} +void metis_partmeshnodal_(int *ne, int *nn, idxtype *elmnts, int *etype, int *numflag, int *nparts, int *edgecut, idxtype *epart, idxtype *npart) +{ + METIS_PartMeshNodal(ne, nn, elmnts, etype, numflag, nparts, edgecut, epart, npart); +} +void metis_partmeshnodal__(int *ne, int *nn, idxtype *elmnts, int *etype, int *numflag, int *nparts, int *edgecut, idxtype *epart, idxtype *npart) +{ + METIS_PartMeshNodal(ne, nn, elmnts, etype, numflag, nparts, edgecut, epart, npart); +} + + +void METIS_PARTMESHDUAL(int *ne, int *nn, idxtype *elmnts, int *etype, int *numflag, int *nparts, int *edgecut, idxtype *epart, idxtype *npart) +{ + METIS_PartMeshDual(ne, nn, elmnts, etype, numflag, nparts, edgecut, epart, npart); +} +void metis_partmeshdual(int *ne, int *nn, idxtype *elmnts, int *etype, int *numflag, int *nparts, int *edgecut, idxtype *epart, idxtype *npart) +{ + METIS_PartMeshDual(ne, nn, elmnts, etype, numflag, nparts, edgecut, epart, npart); +} +void metis_partmeshdual_(int *ne, int *nn, idxtype *elmnts, int *etype, int *numflag, int *nparts, int *edgecut, idxtype *epart, idxtype *npart) +{ + METIS_PartMeshDual(ne, nn, elmnts, etype, numflag, nparts, edgecut, epart, npart); +} +void metis_partmeshdual__(int *ne, int *nn, idxtype *elmnts, int *etype, int *numflag, int *nparts, int *edgecut, idxtype *epart, idxtype *npart) +{ + METIS_PartMeshDual(ne, nn, elmnts, etype, numflag, nparts, edgecut, epart, npart); +} + + +void METIS_MESHTONODAL(int *ne, int *nn, idxtype *elmnts, int *etype, int *numflag, idxtype *dxadj, idxtype *dadjncy) +{ + METIS_MeshToNodal(ne, nn, elmnts, etype, numflag, dxadj, dadjncy); +} +void metis_meshtonodal(int *ne, int *nn, idxtype *elmnts, int *etype, int *numflag, idxtype *dxadj, idxtype *dadjncy) +{ + METIS_MeshToNodal(ne, nn, elmnts, etype, numflag, dxadj, dadjncy); +} +void metis_meshtonodal_(int *ne, int *nn, idxtype *elmnts, int *etype, int *numflag, idxtype *dxadj, idxtype *dadjncy) +{ + METIS_MeshToNodal(ne, nn, elmnts, etype, numflag, dxadj, dadjncy); +} +void metis_meshtonodal__(int *ne, int *nn, idxtype *elmnts, int *etype, int *numflag, idxtype *dxadj, idxtype *dadjncy) +{ + METIS_MeshToNodal(ne, nn, elmnts, etype, numflag, dxadj, dadjncy); +} + + +void METIS_MESHTODUAL(int *ne, int *nn, idxtype *elmnts, int *etype, int *numflag, idxtype *dxadj, idxtype *dadjncy) +{ + METIS_MeshToDual(ne, nn, elmnts, etype, numflag, dxadj, dadjncy); +} +void metis_meshtodual(int *ne, int *nn, idxtype *elmnts, int *etype, int *numflag, idxtype *dxadj, idxtype *dadjncy) +{ + METIS_MeshToDual(ne, nn, elmnts, etype, numflag, dxadj, dadjncy); +} +void metis_meshtodual_(int *ne, int *nn, idxtype *elmnts, int *etype, int *numflag, idxtype *dxadj, idxtype *dadjncy) +{ + METIS_MeshToDual(ne, nn, elmnts, etype, numflag, dxadj, dadjncy); +} +void metis_meshtodual__(int *ne, int *nn, idxtype *elmnts, int *etype, int *numflag, idxtype *dxadj, idxtype *dadjncy) +{ + METIS_MeshToDual(ne, nn, elmnts, etype, numflag, dxadj, dadjncy); +} + + +void METIS_ESTIMATEMEMORY(int *nvtxs, idxtype *xadj, idxtype *adjncy, int *numflag, int *optype, int *nbytes) +{ + METIS_EstimateMemory(nvtxs, xadj, adjncy, numflag, optype, nbytes); +} +void metis_estimatememory(int *nvtxs, idxtype *xadj, idxtype *adjncy, int *numflag, int *optype, int *nbytes) +{ + METIS_EstimateMemory(nvtxs, xadj, adjncy, numflag, optype, nbytes); +} +void metis_estimatememory_(int *nvtxs, idxtype *xadj, idxtype *adjncy, int *numflag, int *optype, int *nbytes) +{ + METIS_EstimateMemory(nvtxs, xadj, adjncy, numflag, optype, nbytes); +} +void metis_estimatememory__(int *nvtxs, idxtype *xadj, idxtype *adjncy, int *numflag, int *optype, int *nbytes) +{ + METIS_EstimateMemory(nvtxs, xadj, adjncy, numflag, optype, nbytes); +} + + + +void METIS_MCPARTGRAPHRECURSIVE(int *nvtxs, int *ncon, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts, int *options, int *edgecut, idxtype *part) +{ + METIS_mCPartGraphRecursive(nvtxs, ncon, xadj, adjncy, vwgt, adjwgt, wgtflag, numflag, nparts, options, edgecut, part); +} +void metis_mcpartgraphrecursive(int *nvtxs, int *ncon, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts, int *options, int *edgecut, idxtype *part) +{ + METIS_mCPartGraphRecursive(nvtxs, ncon, xadj, adjncy, vwgt, adjwgt, wgtflag, numflag, nparts, options, edgecut, part); +} +void metis_mcpartgraphrecursive_(int *nvtxs, int *ncon, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts, int *options, int *edgecut, idxtype *part) +{ + METIS_mCPartGraphRecursive(nvtxs, ncon, xadj, adjncy, vwgt, adjwgt, wgtflag, numflag, nparts, options, edgecut, part); +} +void metis_mcpartgraphrecursive__(int *nvtxs, int *ncon, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts, int *options, int *edgecut, idxtype *part) +{ + METIS_mCPartGraphRecursive(nvtxs, ncon, xadj, adjncy, vwgt, adjwgt, wgtflag, numflag, nparts, options, edgecut, part); +} + + +void METIS_MCPARTGRAPHKWAY(int *nvtxs, int *ncon, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts, float *rubvec, int *options, int *edgecut, idxtype *part) +{ + METIS_mCPartGraphKway(nvtxs, ncon, xadj, adjncy, vwgt, adjwgt, wgtflag, numflag, nparts, rubvec, options, edgecut, part); +} +void metis_mcpartgraphkway(int *nvtxs, int *ncon, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts, float *rubvec, int *options, int *edgecut, idxtype *part) +{ + METIS_mCPartGraphKway(nvtxs, ncon, xadj, adjncy, vwgt, adjwgt, wgtflag, numflag, nparts, rubvec, options, edgecut, part); +} +void metis_mcpartgraphkway_(int *nvtxs, int *ncon, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts, float *rubvec, int *options, int *edgecut, idxtype *part) +{ + METIS_mCPartGraphKway(nvtxs, ncon, xadj, adjncy, vwgt, adjwgt, wgtflag, numflag, nparts, rubvec, options, edgecut, part); +} +void metis_mcpartgraphkway__(int *nvtxs, int *ncon, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts, float *rubvec, int *options, int *edgecut, idxtype *part) +{ + METIS_mCPartGraphKway(nvtxs, ncon, xadj, adjncy, vwgt, adjwgt, wgtflag, numflag, nparts, rubvec, options, edgecut, part); +} + + +void METIS_PARTGRAPHVKWAY(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *vsize, int *wgtflag, int *numflag, int *nparts, int *options, int *volume, idxtype *part) +{ + METIS_PartGraphVKway(nvtxs, xadj, adjncy, vwgt, vsize, wgtflag, numflag, nparts, options, volume, part); +} +void metis_partgraphvkway(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *vsize, int *wgtflag, int *numflag, int *nparts, int *options, int *volume, idxtype *part) +{ + METIS_PartGraphVKway(nvtxs, xadj, adjncy, vwgt, vsize, wgtflag, numflag, nparts, options, volume, part); +} +void metis_partgraphvkway_(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *vsize, int *wgtflag, int *numflag, int *nparts, int *options, int *volume, idxtype *part) +{ + METIS_PartGraphVKway(nvtxs, xadj, adjncy, vwgt, vsize, wgtflag, numflag, nparts, options, volume, part); +} +void metis_partgraphvkway__(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *vsize, int *wgtflag, int *numflag, int *nparts, int *options, int *volume, idxtype *part) +{ + METIS_PartGraphVKway(nvtxs, xadj, adjncy, vwgt, vsize, wgtflag, numflag, nparts, options, volume, part); +} + +void METIS_WPARTGRAPHVKWAY(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *vsize, int *wgtflag, int *numflag, int *nparts, float *tpwgts, int *options, int *volume, idxtype *part) +{ + METIS_WPartGraphVKway(nvtxs, xadj, adjncy, vwgt, vsize, wgtflag, numflag, nparts, tpwgts, options, volume, part); +} +void metis_wpartgraphvkway(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *vsize, int *wgtflag, int *numflag, int *nparts, float *tpwgts, int *options, int *volume, idxtype *part) +{ + METIS_WPartGraphVKway(nvtxs, xadj, adjncy, vwgt, vsize, wgtflag, numflag, nparts, tpwgts, options, volume, part); +} +void metis_wpartgraphvkway_(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *vsize, int *wgtflag, int *numflag, int *nparts, float *tpwgts, int *options, int *volume, idxtype *part) +{ + METIS_WPartGraphVKway(nvtxs, xadj, adjncy, vwgt, vsize, wgtflag, numflag, nparts, tpwgts, options, volume, part); +} +void metis_wpartgraphvkway__(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *vsize, int *wgtflag, int *numflag, int *nparts, float *tpwgts, int *options, int *volume, idxtype *part) +{ + METIS_WPartGraphVKway(nvtxs, xadj, adjncy, vwgt, vsize, wgtflag, numflag, nparts, tpwgts, options, volume, part); +} + + + diff --git a/contrib/Metis/graph.c b/contrib/Metis/graph.c new file mode 100644 index 0000000000..351ce4578c --- /dev/null +++ b/contrib/Metis/graph.c @@ -0,0 +1,616 @@ +/* + * Copyright 1997, Regents of the University of Minnesota + * + * graph.c + * + * This file contains functions that deal with setting up the graphs + * for METIS. + * + * Started 7/25/97 + * George + * + * $Id: graph.c,v 1.1 2005-09-21 17:29:37 geuzaine Exp $ + * + */ + +#include <metis.h> + +/************************************************************************* +* This function sets up the graph from the user input +**************************************************************************/ +void SetUpGraph(GraphType *graph, int OpType, int nvtxs, int ncon, + idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *adjwgt, int wgtflag) +{ + int i, j, k, sum, gsize; + float *nvwgt; + idxtype tvwgt[MAXNCON]; + + if (OpType == OP_KMETIS && ncon == 1 && (wgtflag&2) == 0 && (wgtflag&1) == 0) { + SetUpGraphKway(graph, nvtxs, xadj, adjncy); + return; + } + + InitGraph(graph); + + graph->nvtxs = nvtxs; + graph->nedges = xadj[nvtxs]; + graph->ncon = ncon; + graph->xadj = xadj; + graph->adjncy = adjncy; + + if (ncon == 1) { /* We are in the non mC mode */ + gsize = 0; + if ((wgtflag&2) == 0) + gsize += nvtxs; + if ((wgtflag&1) == 0) + gsize += graph->nedges; + + gsize += 2*nvtxs; + + graph->gdata = idxmalloc(gsize, "SetUpGraph: gdata"); + + /* Create the vertex/edge weight vectors if they are not supplied */ + gsize = 0; + if ((wgtflag&2) == 0) { + vwgt = graph->vwgt = idxset(nvtxs, 1, graph->gdata); + gsize += nvtxs; + } + else + graph->vwgt = vwgt; + + if ((wgtflag&1) == 0) { + adjwgt = graph->adjwgt = idxset(graph->nedges, 1, graph->gdata+gsize); + gsize += graph->nedges; + } + else + graph->adjwgt = adjwgt; + + + /* Compute the initial values of the adjwgtsum */ + graph->adjwgtsum = graph->gdata + gsize; + gsize += nvtxs; + + for (i=0; i<nvtxs; i++) { + sum = 0; + for (j=xadj[i]; j<xadj[i+1]; j++) + sum += adjwgt[j]; + graph->adjwgtsum[i] = sum; + } + + graph->cmap = graph->gdata + gsize; + gsize += nvtxs; + + } + else { /* Set up the graph in MOC mode */ + gsize = 0; + if ((wgtflag&1) == 0) + gsize += graph->nedges; + + gsize += 2*nvtxs; + + graph->gdata = idxmalloc(gsize, "SetUpGraph: gdata"); + gsize = 0; + + for (i=0; i<ncon; i++) + tvwgt[i] = idxsum_strd(nvtxs, vwgt+i, ncon); + + nvwgt = graph->nvwgt = fmalloc(ncon*nvtxs, "SetUpGraph: nvwgt"); + + for (i=0; i<nvtxs; i++) { + for (j=0; j<ncon; j++) + nvwgt[i*ncon+j] = (1.0*vwgt[i*ncon+j])/(1.0*tvwgt[j]); + } + + + /* Create the edge weight vectors if they are not supplied */ + if ((wgtflag&1) == 0) { + adjwgt = graph->adjwgt = idxset(graph->nedges, 1, graph->gdata+gsize); + gsize += graph->nedges; + } + else + graph->adjwgt = adjwgt; + + /* Compute the initial values of the adjwgtsum */ + graph->adjwgtsum = graph->gdata + gsize; + gsize += nvtxs; + + for (i=0; i<nvtxs; i++) { + sum = 0; + for (j=xadj[i]; j<xadj[i+1]; j++) + sum += adjwgt[j]; + graph->adjwgtsum[i] = sum; + } + + graph->cmap = graph->gdata + gsize; + gsize += nvtxs; + + } + + if (OpType != OP_KMETIS && OpType != OP_KVMETIS) { + graph->label = idxmalloc(nvtxs, "SetUpGraph: label"); + + for (i=0; i<nvtxs; i++) + graph->label[i] = i; + } + +} + + +/************************************************************************* +* This function sets up the graph from the user input +**************************************************************************/ +void SetUpGraphKway(GraphType *graph, int nvtxs, idxtype *xadj, idxtype *adjncy) +{ + int i; + + InitGraph(graph); + + graph->nvtxs = nvtxs; + graph->nedges = xadj[nvtxs]; + graph->ncon = 1; + graph->xadj = xadj; + graph->vwgt = NULL; + graph->adjncy = adjncy; + graph->adjwgt = NULL; + + graph->gdata = idxmalloc(2*nvtxs, "SetUpGraph: gdata"); + graph->adjwgtsum = graph->gdata; + graph->cmap = graph->gdata + nvtxs; + + /* Compute the initial values of the adjwgtsum */ + for (i=0; i<nvtxs; i++) + graph->adjwgtsum[i] = xadj[i+1]-xadj[i]; + +} + + + +/************************************************************************* +* This function sets up the graph from the user input +**************************************************************************/ +void SetUpGraph2(GraphType *graph, int nvtxs, int ncon, idxtype *xadj, + idxtype *adjncy, float *nvwgt, idxtype *adjwgt) +{ + int i, j, sum; + + InitGraph(graph); + + graph->nvtxs = nvtxs; + graph->nedges = xadj[nvtxs]; + graph->ncon = ncon; + graph->xadj = xadj; + graph->adjncy = adjncy; + graph->adjwgt = adjwgt; + + graph->nvwgt = fmalloc(nvtxs*ncon, "SetUpGraph2: graph->nvwgt"); + scopy(nvtxs*ncon, nvwgt, graph->nvwgt); + + graph->gdata = idxmalloc(2*nvtxs, "SetUpGraph: gdata"); + + /* Compute the initial values of the adjwgtsum */ + graph->adjwgtsum = graph->gdata; + for (i=0; i<nvtxs; i++) { + sum = 0; + for (j=xadj[i]; j<xadj[i+1]; j++) + sum += adjwgt[j]; + graph->adjwgtsum[i] = sum; + } + + graph->cmap = graph->gdata+nvtxs; + + graph->label = idxmalloc(nvtxs, "SetUpGraph: label"); + for (i=0; i<nvtxs; i++) + graph->label[i] = i; + +} + + +/************************************************************************* +* This function sets up the graph from the user input +**************************************************************************/ +void VolSetUpGraph(GraphType *graph, int OpType, int nvtxs, int ncon, idxtype *xadj, + idxtype *adjncy, idxtype *vwgt, idxtype *vsize, int wgtflag) +{ + int i, j, k, sum, gsize; + idxtype *adjwgt; + float *nvwgt; + idxtype tvwgt[MAXNCON]; + + InitGraph(graph); + + graph->nvtxs = nvtxs; + graph->nedges = xadj[nvtxs]; + graph->ncon = ncon; + graph->xadj = xadj; + graph->adjncy = adjncy; + + if (ncon == 1) { /* We are in the non mC mode */ + gsize = graph->nedges; /* This is for the edge weights */ + if ((wgtflag&2) == 0) + gsize += nvtxs; /* vwgts */ + if ((wgtflag&1) == 0) + gsize += nvtxs; /* vsize */ + + gsize += 2*nvtxs; + + graph->gdata = idxmalloc(gsize, "SetUpGraph: gdata"); + + /* Create the vertex/edge weight vectors if they are not supplied */ + gsize = 0; + if ((wgtflag&2) == 0) { + vwgt = graph->vwgt = idxset(nvtxs, 1, graph->gdata); + gsize += nvtxs; + } + else + graph->vwgt = vwgt; + + if ((wgtflag&1) == 0) { + vsize = graph->vsize = idxset(nvtxs, 1, graph->gdata); + gsize += nvtxs; + } + else + graph->vsize = vsize; + + /* Allocate memory for edge weights and initialize them to the sum of the vsize */ + adjwgt = graph->adjwgt = graph->gdata+gsize; + gsize += graph->nedges; + + for (i=0; i<nvtxs; i++) { + for (j=xadj[i]; j<xadj[i+1]; j++) + adjwgt[j] = 1+vsize[i]+vsize[adjncy[j]]; + } + + + /* Compute the initial values of the adjwgtsum */ + graph->adjwgtsum = graph->gdata + gsize; + gsize += nvtxs; + + for (i=0; i<nvtxs; i++) { + sum = 0; + for (j=xadj[i]; j<xadj[i+1]; j++) + sum += adjwgt[j]; + graph->adjwgtsum[i] = sum; + } + + graph->cmap = graph->gdata + gsize; + gsize += nvtxs; + + } + else { /* Set up the graph in MOC mode */ + gsize = graph->nedges; + if ((wgtflag&1) == 0) + gsize += nvtxs; + + gsize += 2*nvtxs; + + graph->gdata = idxmalloc(gsize, "SetUpGraph: gdata"); + gsize = 0; + + /* Create the normalized vertex weights along each constrain */ + if ((wgtflag&2) == 0) + vwgt = idxsmalloc(nvtxs, 1, "SetUpGraph: vwgt"); + + for (i=0; i<ncon; i++) + tvwgt[i] = idxsum_strd(nvtxs, vwgt+i, ncon); + + nvwgt = graph->nvwgt = fmalloc(ncon*nvtxs, "SetUpGraph: nvwgt"); + + for (i=0; i<nvtxs; i++) { + for (j=0; j<ncon; j++) + nvwgt[i*ncon+j] = (1.0*vwgt[i*ncon+j])/(1.0*tvwgt[j]); + } + if ((wgtflag&2) == 0) + free(vwgt); + + + /* Create the vsize vector if it is not supplied */ + if ((wgtflag&1) == 0) { + vsize = graph->vsize = idxset(nvtxs, 1, graph->gdata); + gsize += nvtxs; + } + else + graph->vsize = vsize; + + /* Allocate memory for edge weights and initialize them to the sum of the vsize */ + adjwgt = graph->adjwgt = graph->gdata+gsize; + gsize += graph->nedges; + + for (i=0; i<nvtxs; i++) { + for (j=xadj[i]; j<xadj[i+1]; j++) + adjwgt[j] = 1+vsize[i]+vsize[adjncy[j]]; + } + + /* Compute the initial values of the adjwgtsum */ + graph->adjwgtsum = graph->gdata + gsize; + gsize += nvtxs; + + for (i=0; i<nvtxs; i++) { + sum = 0; + for (j=xadj[i]; j<xadj[i+1]; j++) + sum += adjwgt[j]; + graph->adjwgtsum[i] = sum; + } + + graph->cmap = graph->gdata + gsize; + gsize += nvtxs; + + } + + if (OpType != OP_KVMETIS) { + graph->label = idxmalloc(nvtxs, "SetUpGraph: label"); + + for (i=0; i<nvtxs; i++) + graph->label[i] = i; + } + +} + + +/************************************************************************* +* This function randomly permutes the adjacency lists of a graph +**************************************************************************/ +void RandomizeGraph(GraphType *graph) +{ + int i, j, k, l, tmp, nvtxs; + idxtype *xadj, *adjncy, *adjwgt; + + nvtxs = graph->nvtxs; + xadj = graph->xadj; + adjncy = graph->adjncy; + adjwgt = graph->adjwgt; + + for (i=0; i<nvtxs; i++) { + l = xadj[i+1]-xadj[i]; + for (j=xadj[i]; j<xadj[i+1]; j++) { + k = xadj[i] + RandomInRange(l); + SWAP(adjncy[j], adjncy[k], tmp); + SWAP(adjwgt[j], adjwgt[k], tmp); + } + } +} + + +/************************************************************************* +* This function checks whether or not partition pid is contigous +**************************************************************************/ +int IsConnectedSubdomain(CtrlType *ctrl, GraphType *graph, int pid, int report) +{ + int i, j, k, nvtxs, first, last, nleft, ncmps, wgt; + idxtype *xadj, *adjncy, *where, *touched, *queue; + idxtype *cptr; + + nvtxs = graph->nvtxs; + xadj = graph->xadj; + adjncy = graph->adjncy; + where = graph->where; + + touched = idxsmalloc(nvtxs, 0, "IsConnected: touched"); + queue = idxmalloc(nvtxs, "IsConnected: queue"); + cptr = idxmalloc(nvtxs, "IsConnected: cptr"); + + nleft = 0; + for (i=0; i<nvtxs; i++) { + if (where[i] == pid) + nleft++; + } + + for (i=0; i<nvtxs; i++) { + if (where[i] == pid) + break; + } + + touched[i] = 1; + queue[0] = i; + first = 0; last = 1; + + cptr[0] = 0; /* This actually points to queue */ + ncmps = 0; + while (first != nleft) { + if (first == last) { /* Find another starting vertex */ + cptr[++ncmps] = first; + for (i=0; i<nvtxs; i++) { + if (where[i] == pid && !touched[i]) + break; + } + queue[last++] = i; + touched[i] = 1; + } + + i = queue[first++]; + for (j=xadj[i]; j<xadj[i+1]; j++) { + k = adjncy[j]; + if (where[k] == pid && !touched[k]) { + queue[last++] = k; + touched[k] = 1; + } + } + } + cptr[++ncmps] = first; + + if (ncmps > 1 && report) { + printf("The graph has %d connected components in partition %d:\t", ncmps, pid); + for (i=0; i<ncmps; i++) { + wgt = 0; + for (j=cptr[i]; j<cptr[i+1]; j++) + wgt += graph->vwgt[queue[j]]; + printf("[%5d %5d] ", cptr[i+1]-cptr[i], wgt); + /* + if (cptr[i+1]-cptr[i] == 1) + printf("[%d %d] ", queue[cptr[i]], xadj[queue[cptr[i]]+1]-xadj[queue[cptr[i]]]); + */ + } + printf("\n"); + } + + GKfree(&touched, &queue, &cptr, LTERM); + + return (ncmps == 1 ? 1 : 0); +} + + +/************************************************************************* +* This function checks whether a graph is contigous or not +**************************************************************************/ +int IsConnected(CtrlType *ctrl, GraphType *graph, int report) +{ + int i, j, k, nvtxs, first, last; + idxtype *xadj, *adjncy, *touched, *queue; + + nvtxs = graph->nvtxs; + xadj = graph->xadj; + adjncy = graph->adjncy; + + touched = idxsmalloc(nvtxs, 0, "IsConnected: touched"); + queue = idxmalloc(nvtxs, "IsConnected: queue"); + + touched[0] = 1; + queue[0] = 0; + first = 0; last = 1; + + while (first < last) { + i = queue[first++]; + for (j=xadj[i]; j<xadj[i+1]; j++) { + k = adjncy[j]; + if (!touched[k]) { + queue[last++] = k; + touched[k] = 1; + } + } + } + + if (first != nvtxs && report) + printf("The graph is not connected. It has %d disconnected vertices!\n", nvtxs-first); + + return (first == nvtxs ? 1 : 0); +} + + +/************************************************************************* +* This function checks whether or not partition pid is contigous +**************************************************************************/ +int IsConnected2(GraphType *graph, int report) +{ + int i, j, k, nvtxs, first, last, nleft, ncmps, wgt; + idxtype *xadj, *adjncy, *where, *touched, *queue; + idxtype *cptr; + + nvtxs = graph->nvtxs; + xadj = graph->xadj; + adjncy = graph->adjncy; + where = graph->where; + + touched = idxsmalloc(nvtxs, 0, "IsConnected: touched"); + queue = idxmalloc(nvtxs, "IsConnected: queue"); + cptr = idxmalloc(nvtxs, "IsConnected: cptr"); + + nleft = nvtxs; + touched[0] = 1; + queue[0] = 0; + first = 0; last = 1; + + cptr[0] = 0; /* This actually points to queue */ + ncmps = 0; + while (first != nleft) { + if (first == last) { /* Find another starting vertex */ + cptr[++ncmps] = first; + for (i=0; i<nvtxs; i++) { + if (!touched[i]) + break; + } + queue[last++] = i; + touched[i] = 1; + } + + i = queue[first++]; + for (j=xadj[i]; j<xadj[i+1]; j++) { + k = adjncy[j]; + if (!touched[k]) { + queue[last++] = k; + touched[k] = 1; + } + } + } + cptr[++ncmps] = first; + + if (ncmps > 1 && report) { + printf("%d connected components:\t", ncmps); + for (i=0; i<ncmps; i++) { + if (cptr[i+1]-cptr[i] > 200) + printf("[%5d] ", cptr[i+1]-cptr[i]); + } + printf("\n"); + } + + GKfree(&touched, &queue, &cptr, LTERM); + + return (ncmps == 1 ? 1 : 0); +} + + +/************************************************************************* +* This function returns the number of connected components in cptr,cind +* The separator of the graph is used to split it and then find its components. +**************************************************************************/ +int FindComponents(CtrlType *ctrl, GraphType *graph, idxtype *cptr, idxtype *cind) +{ + int i, j, k, nvtxs, first, last, nleft, ncmps, wgt; + idxtype *xadj, *adjncy, *where, *touched, *queue; + + nvtxs = graph->nvtxs; + xadj = graph->xadj; + adjncy = graph->adjncy; + where = graph->where; + + touched = idxsmalloc(nvtxs, 0, "IsConnected: queue"); + + for (i=0; i<graph->nbnd; i++) + touched[graph->bndind[i]] = 1; + + queue = cind; + + nleft = 0; + for (i=0; i<nvtxs; i++) { + if (where[i] != 2) + nleft++; + } + + for (i=0; i<nvtxs; i++) { + if (where[i] != 2) + break; + } + + touched[i] = 1; + queue[0] = i; + first = 0; last = 1; + + cptr[0] = 0; /* This actually points to queue */ + ncmps = 0; + while (first != nleft) { + if (first == last) { /* Find another starting vertex */ + cptr[++ncmps] = first; + for (i=0; i<nvtxs; i++) { + if (!touched[i]) + break; + } + queue[last++] = i; + touched[i] = 1; + } + + i = queue[first++]; + for (j=xadj[i]; j<xadj[i+1]; j++) { + k = adjncy[j]; + if (!touched[k]) { + queue[last++] = k; + touched[k] = 1; + } + } + } + cptr[++ncmps] = first; + + free(touched); + + return ncmps; +} + + + diff --git a/contrib/Metis/initpart.c b/contrib/Metis/initpart.c new file mode 100644 index 0000000000..72c5b7be07 --- /dev/null +++ b/contrib/Metis/initpart.c @@ -0,0 +1,422 @@ +/* + * Copyright 1997, Regents of the University of Minnesota + * + * initpart.c + * + * This file contains code that performs the initial partition of the + * coarsest graph + * + * Started 7/23/97 + * George + * + * $Id: initpart.c,v 1.1 2005-09-21 17:29:37 geuzaine Exp $ + * + */ + +#include <metis.h> + +/************************************************************************* +* This function computes the initial bisection of the coarsest graph +**************************************************************************/ +void Init2WayPartition(CtrlType *ctrl, GraphType *graph, int *tpwgts, float ubfactor) +{ + int dbglvl; + + dbglvl = ctrl->dbglvl; + IFSET(ctrl->dbglvl, DBG_REFINE, ctrl->dbglvl -= DBG_REFINE); + IFSET(ctrl->dbglvl, DBG_MOVEINFO, ctrl->dbglvl -= DBG_MOVEINFO); + + IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->InitPartTmr)); + + switch (ctrl->IType) { + case IPART_GGPKL: + GrowBisection(ctrl, graph, tpwgts, ubfactor); + break; + case 3: + RandomBisection(ctrl, graph, tpwgts, ubfactor); + break; + default: + errexit("Unknown initial partition type: %d\n", ctrl->IType); + } + + IFSET(ctrl->dbglvl, DBG_IPART, printf("Initial Cut: %d\n", graph->mincut)); + IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->InitPartTmr)); + ctrl->dbglvl = dbglvl; + +/* + IsConnectedSubdomain(ctrl, graph, 0); + IsConnectedSubdomain(ctrl, graph, 1); +*/ +} + +/************************************************************************* +* This function computes the initial bisection of the coarsest graph +**************************************************************************/ +void InitSeparator(CtrlType *ctrl, GraphType *graph, float ubfactor) +{ + int dbglvl; + + dbglvl = ctrl->dbglvl; + IFSET(ctrl->dbglvl, DBG_REFINE, ctrl->dbglvl -= DBG_REFINE); + IFSET(ctrl->dbglvl, DBG_MOVEINFO, ctrl->dbglvl -= DBG_MOVEINFO); + + IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->InitPartTmr)); + + GrowBisectionNode(ctrl, graph, ubfactor); + Compute2WayNodePartitionParams(ctrl, graph); + + IFSET(ctrl->dbglvl, DBG_IPART, printf("Initial Sep: %d\n", graph->mincut)); + IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->InitPartTmr)); + + ctrl->dbglvl = dbglvl; + +} + + + +/************************************************************************* +* This function takes a graph and produces a bisection by using a region +* growing algorithm. The resulting partition is returned in +* graph->where +**************************************************************************/ +void GrowBisection(CtrlType *ctrl, GraphType *graph, int *tpwgts, float ubfactor) +{ + int i, j, k, nvtxs, drain, nleft, first, last, pwgts[2], minpwgt[2], maxpwgt[2], from, bestcut, icut, mincut, me, pass, nbfs; + idxtype *xadj, *vwgt, *adjncy, *adjwgt, *where; + idxtype *queue, *touched, *gain, *bestwhere; + + + nvtxs = graph->nvtxs; + xadj = graph->xadj; + vwgt = graph->vwgt; + adjncy = graph->adjncy; + adjwgt = graph->adjwgt; + + Allocate2WayPartitionMemory(ctrl, graph); + where = graph->where; + + bestwhere = idxmalloc(nvtxs, "BisectGraph: bestwhere"); + queue = idxmalloc(nvtxs, "BisectGraph: queue"); + touched = idxmalloc(nvtxs, "BisectGraph: touched"); + + ASSERTP(tpwgts[0]+tpwgts[1] == idxsum(nvtxs, vwgt), ("%d %d\n", tpwgts[0]+tpwgts[1], idxsum(nvtxs, vwgt))); + + maxpwgt[0] = ubfactor*tpwgts[0]; + maxpwgt[1] = ubfactor*tpwgts[1]; + minpwgt[0] = (1.0/ubfactor)*tpwgts[0]; + minpwgt[1] = (1.0/ubfactor)*tpwgts[1]; + + nbfs = (nvtxs <= ctrl->CoarsenTo ? SMALLNIPARTS : LARGENIPARTS); + bestcut = idxsum(nvtxs, graph->adjwgtsum)+1; /* The +1 is for the 0 edges case */ + for (; nbfs>0; nbfs--) { + idxset(nvtxs, 0, touched); + + pwgts[1] = tpwgts[0]+tpwgts[1]; + pwgts[0] = 0; + + idxset(nvtxs, 1, where); + + queue[0] = RandomInRange(nvtxs); + touched[queue[0]] = 1; + first = 0; last = 1; + nleft = nvtxs-1; + drain = 0; + + /* Start the BFS from queue to get a partition */ + for (;;) { + if (first == last) { /* Empty. Disconnected graph! */ + if (nleft == 0 || drain) + break; + + k = RandomInRange(nleft); + for (i=0; i<nvtxs; i++) { + if (touched[i] == 0) { + if (k == 0) + break; + else + k--; + } + } + + queue[0] = i; + touched[i] = 1; + first = 0; last = 1;; + nleft--; + } + + i = queue[first++]; + if (pwgts[0] > 0 && pwgts[1]-vwgt[i] < minpwgt[1]) { + drain = 1; + continue; + } + + where[i] = 0; + INC_DEC(pwgts[0], pwgts[1], vwgt[i]); + if (pwgts[1] <= maxpwgt[1]) + break; + + drain = 0; + for (j=xadj[i]; j<xadj[i+1]; j++) { + k = adjncy[j]; + if (touched[k] == 0) { + queue[last++] = k; + touched[k] = 1; + nleft--; + } + } + } + + /* Check to see if we hit any bad limiting cases */ + if (pwgts[1] == 0) { + i = RandomInRange(nvtxs); + where[i] = 1; + INC_DEC(pwgts[1], pwgts[0], vwgt[i]); + } + + /************************************************************* + * Do some partition refinement + **************************************************************/ + Compute2WayPartitionParams(ctrl, graph); + /*printf("IPART: %3d [%5d %5d] [%5d %5d] %5d\n", graph->nvtxs, pwgts[0], pwgts[1], graph->pwgts[0], graph->pwgts[1], graph->mincut); */ + + Balance2Way(ctrl, graph, tpwgts, ubfactor); + /*printf("BPART: [%5d %5d] %5d\n", graph->pwgts[0], graph->pwgts[1], graph->mincut);*/ + + FM_2WayEdgeRefine(ctrl, graph, tpwgts, 4); + /*printf("RPART: [%5d %5d] %5d\n", graph->pwgts[0], graph->pwgts[1], graph->mincut);*/ + + if (bestcut > graph->mincut) { + bestcut = graph->mincut; + idxcopy(nvtxs, where, bestwhere); + if (bestcut == 0) + break; + } + } + + graph->mincut = bestcut; + idxcopy(nvtxs, bestwhere, where); + + GKfree(&bestwhere, &queue, &touched, LTERM); +} + + + + +/************************************************************************* +* This function takes a graph and produces a bisection by using a region +* growing algorithm. The resulting partition is returned in +* graph->where +**************************************************************************/ +void GrowBisectionNode(CtrlType *ctrl, GraphType *graph, float ubfactor) +{ + int i, j, k, nvtxs, drain, nleft, first, last, pwgts[2], tpwgts[2], minpwgt[2], maxpwgt[2], from, bestcut, icut, mincut, me, pass, nbfs; + idxtype *xadj, *vwgt, *adjncy, *adjwgt, *where, *bndind; + idxtype *queue, *touched, *gain, *bestwhere; + + nvtxs = graph->nvtxs; + xadj = graph->xadj; + vwgt = graph->vwgt; + adjncy = graph->adjncy; + adjwgt = graph->adjwgt; + + bestwhere = idxmalloc(nvtxs, "BisectGraph: bestwhere"); + queue = idxmalloc(nvtxs, "BisectGraph: queue"); + touched = idxmalloc(nvtxs, "BisectGraph: touched"); + + tpwgts[0] = idxsum(nvtxs, vwgt); + tpwgts[1] = tpwgts[0]/2; + tpwgts[0] -= tpwgts[1]; + + maxpwgt[0] = ubfactor*tpwgts[0]; + maxpwgt[1] = ubfactor*tpwgts[1]; + minpwgt[0] = (1.0/ubfactor)*tpwgts[0]; + minpwgt[1] = (1.0/ubfactor)*tpwgts[1]; + + /* Allocate memory for graph->rdata. Allocate sufficient memory for both edge and node */ + graph->rdata = idxmalloc(5*nvtxs+3, "GrowBisectionNode: graph->rdata"); + graph->pwgts = graph->rdata; + graph->where = graph->rdata + 3; + graph->bndptr = graph->rdata + nvtxs + 3; + graph->bndind = graph->rdata + 2*nvtxs + 3; + graph->nrinfo = (NRInfoType *)(graph->rdata + 3*nvtxs + 3); + graph->id = graph->rdata + 3*nvtxs + 3; + graph->ed = graph->rdata + 4*nvtxs + 3; + + where = graph->where; + bndind = graph->bndind; + + nbfs = (nvtxs <= ctrl->CoarsenTo ? SMALLNIPARTS : LARGENIPARTS); + bestcut = tpwgts[0]+tpwgts[1]; + for (nbfs++; nbfs>0; nbfs--) { + idxset(nvtxs, 0, touched); + + pwgts[1] = tpwgts[0]+tpwgts[1]; + pwgts[0] = 0; + + idxset(nvtxs, 1, where); + + queue[0] = RandomInRange(nvtxs); + touched[queue[0]] = 1; + first = 0; last = 1; + nleft = nvtxs-1; + drain = 0; + + /* Start the BFS from queue to get a partition */ + if (nbfs >= 1) { + for (;;) { + if (first == last) { /* Empty. Disconnected graph! */ + if (nleft == 0 || drain) + break; + + k = RandomInRange(nleft); + for (i=0; i<nvtxs; i++) { + if (touched[i] == 0) { + if (k == 0) + break; + else + k--; + } + } + + queue[0] = i; + touched[i] = 1; + first = 0; last = 1;; + nleft--; + } + + i = queue[first++]; + if (pwgts[1]-vwgt[i] < minpwgt[1]) { + drain = 1; + continue; + } + + where[i] = 0; + INC_DEC(pwgts[0], pwgts[1], vwgt[i]); + if (pwgts[1] <= maxpwgt[1]) + break; + + drain = 0; + for (j=xadj[i]; j<xadj[i+1]; j++) { + k = adjncy[j]; + if (touched[k] == 0) { + queue[last++] = k; + touched[k] = 1; + nleft--; + } + } + } + } + + /************************************************************* + * Do some partition refinement + **************************************************************/ + Compute2WayPartitionParams(ctrl, graph); + Balance2Way(ctrl, graph, tpwgts, ubfactor); + FM_2WayEdgeRefine(ctrl, graph, tpwgts, 4); + + /* Construct and refine the vertex separator */ + for (i=0; i<graph->nbnd; i++) + where[bndind[i]] = 2; + + Compute2WayNodePartitionParams(ctrl, graph); + FM_2WayNodeRefine(ctrl, graph, ubfactor, 6); + + /* printf("ISep: [%d %d %d] %d\n", graph->pwgts[0], graph->pwgts[1], graph->pwgts[2], bestcut); */ + + if (bestcut > graph->mincut) { + bestcut = graph->mincut; + idxcopy(nvtxs, where, bestwhere); + } + } + + graph->mincut = bestcut; + idxcopy(nvtxs, bestwhere, where); + + Compute2WayNodePartitionParams(ctrl, graph); + + GKfree(&bestwhere, &queue, &touched, LTERM); +} + + +/************************************************************************* +* This function takes a graph and produces a bisection by using a region +* growing algorithm. The resulting partition is returned in +* graph->where +**************************************************************************/ +void RandomBisection(CtrlType *ctrl, GraphType *graph, int *tpwgts, float ubfactor) +{ + int i, ii, j, k, nvtxs, pwgts[2], minpwgt[2], maxpwgt[2], from, bestcut, icut, mincut, me, pass, nbfs; + idxtype *xadj, *vwgt, *adjncy, *adjwgt, *where; + idxtype *perm, *bestwhere; + + nvtxs = graph->nvtxs; + xadj = graph->xadj; + vwgt = graph->vwgt; + adjncy = graph->adjncy; + adjwgt = graph->adjwgt; + + Allocate2WayPartitionMemory(ctrl, graph); + where = graph->where; + + bestwhere = idxmalloc(nvtxs, "BisectGraph: bestwhere"); + perm = idxmalloc(nvtxs, "BisectGraph: queue"); + + ASSERTP(tpwgts[0]+tpwgts[1] == idxsum(nvtxs, vwgt), ("%d %d\n", tpwgts[0]+tpwgts[1], idxsum(nvtxs, vwgt))); + + maxpwgt[0] = ubfactor*tpwgts[0]; + maxpwgt[1] = ubfactor*tpwgts[1]; + minpwgt[0] = (1.0/ubfactor)*tpwgts[0]; + minpwgt[1] = (1.0/ubfactor)*tpwgts[1]; + + nbfs = (nvtxs <= ctrl->CoarsenTo ? SMALLNIPARTS : LARGENIPARTS); + bestcut = idxsum(nvtxs, graph->adjwgtsum)+1; /* The +1 is for the 0 edges case */ + for (; nbfs>0; nbfs--) { + RandomPermute(nvtxs, perm, 1); + + idxset(nvtxs, 1, where); + pwgts[1] = tpwgts[0]+tpwgts[1]; + pwgts[0] = 0; + + + if (nbfs != 1) { + for (ii=0; ii<nvtxs; ii++) { + i = perm[ii]; + if (pwgts[0]+vwgt[i] < maxpwgt[0]) { + where[i] = 0; + pwgts[0] += vwgt[i]; + pwgts[1] -= vwgt[i]; + if (pwgts[0] > minpwgt[0]) + break; + } + } + } + + /************************************************************* + * Do some partition refinement + **************************************************************/ + Compute2WayPartitionParams(ctrl, graph); + /* printf("IPART: %3d [%5d %5d] [%5d %5d] %5d\n", graph->nvtxs, pwgts[0], pwgts[1], graph->pwgts[0], graph->pwgts[1], graph->mincut); */ + + Balance2Way(ctrl, graph, tpwgts, ubfactor); + /* printf("BPART: [%5d %5d] %5d\n", graph->pwgts[0], graph->pwgts[1], graph->mincut); */ + + FM_2WayEdgeRefine(ctrl, graph, tpwgts, 4); + /* printf("RPART: [%5d %5d] %5d\n", graph->pwgts[0], graph->pwgts[1], graph->mincut); */ + + if (bestcut > graph->mincut) { + bestcut = graph->mincut; + idxcopy(nvtxs, where, bestwhere); + if (bestcut == 0) + break; + } + } + + graph->mincut = bestcut; + idxcopy(nvtxs, bestwhere, where); + + GKfree(&bestwhere, &perm, LTERM); +} + + + + diff --git a/contrib/Metis/kmetis.c b/contrib/Metis/kmetis.c new file mode 100644 index 0000000000..9a075abde5 --- /dev/null +++ b/contrib/Metis/kmetis.c @@ -0,0 +1,129 @@ +/* + * Copyright 1997, Regents of the University of Minnesota + * + * kmetis.c + * + * This file contains the top level routines for the multilevel k-way partitioning + * algorithm KMETIS. + * + * Started 7/28/97 + * George + * + * $Id: kmetis.c,v 1.1 2005-09-21 17:29:37 geuzaine Exp $ + * + */ + +#include <metis.h> + + +/************************************************************************* +* This function is the entry point for KMETIS +**************************************************************************/ +void METIS_PartGraphKway(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, + idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts, + int *options, int *edgecut, idxtype *part) +{ + int i; + float *tpwgts; + + tpwgts = fmalloc(*nparts, "KMETIS: tpwgts"); + for (i=0; i<*nparts; i++) + tpwgts[i] = 1.0/(1.0*(*nparts)); + + METIS_WPartGraphKway(nvtxs, xadj, adjncy, vwgt, adjwgt, wgtflag, numflag, nparts, + tpwgts, options, edgecut, part); + + free(tpwgts); +} + + +/************************************************************************* +* This function is the entry point for KWMETIS +**************************************************************************/ +void METIS_WPartGraphKway(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, + idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts, + float *tpwgts, int *options, int *edgecut, idxtype *part) +{ + int i, j; + GraphType graph; + CtrlType ctrl; + + if (*numflag == 1) + Change2CNumbering(*nvtxs, xadj, adjncy); + + SetUpGraph(&graph, OP_KMETIS, *nvtxs, 1, xadj, adjncy, vwgt, adjwgt, *wgtflag); + + if (options[0] == 0) { /* Use the default parameters */ + ctrl.CType = KMETIS_CTYPE; + ctrl.IType = KMETIS_ITYPE; + ctrl.RType = KMETIS_RTYPE; + ctrl.dbglvl = KMETIS_DBGLVL; + } + else { + ctrl.CType = options[OPTION_CTYPE]; + ctrl.IType = options[OPTION_ITYPE]; + ctrl.RType = options[OPTION_RTYPE]; + ctrl.dbglvl = options[OPTION_DBGLVL]; + } + ctrl.optype = OP_KMETIS; + ctrl.CoarsenTo = amax((*nvtxs)/(40*log2(*nparts)), 20*(*nparts)); + ctrl.maxvwgt = 1.5*((graph.vwgt ? idxsum(*nvtxs, graph.vwgt) : (*nvtxs))/ctrl.CoarsenTo); + + InitRandom(-1); + + AllocateWorkSpace(&ctrl, &graph, *nparts); + + IFSET(ctrl.dbglvl, DBG_TIME, InitTimers(&ctrl)); + IFSET(ctrl.dbglvl, DBG_TIME, starttimer(ctrl.TotalTmr)); + + *edgecut = MlevelKWayPartitioning(&ctrl, &graph, *nparts, part, tpwgts, 1.03); + + IFSET(ctrl.dbglvl, DBG_TIME, stoptimer(ctrl.TotalTmr)); + IFSET(ctrl.dbglvl, DBG_TIME, PrintTimers(&ctrl)); + + FreeWorkSpace(&ctrl, &graph); + + if (*numflag == 1) + Change2FNumbering(*nvtxs, xadj, adjncy, part); +} + + +/************************************************************************* +* This function takes a graph and produces a bisection of it +**************************************************************************/ +int MlevelKWayPartitioning(CtrlType *ctrl, GraphType *graph, int nparts, idxtype *part, float *tpwgts, float ubfactor) +{ + int i, j, nvtxs, tvwgt, tpwgts2[2]; + GraphType *cgraph; + int wgtflag=3, numflag=0, options[10], edgecut; + + cgraph = Coarsen2Way(ctrl, graph); + + IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->InitPartTmr)); + AllocateKWayPartitionMemory(ctrl, cgraph, nparts); + + options[0] = 1; + options[OPTION_CTYPE] = MATCH_SHEMKWAY; + options[OPTION_ITYPE] = IPART_GGPKL; + options[OPTION_RTYPE] = RTYPE_FM; + options[OPTION_DBGLVL] = 0; + + METIS_WPartGraphRecursive(&cgraph->nvtxs, cgraph->xadj, cgraph->adjncy, cgraph->vwgt, + cgraph->adjwgt, &wgtflag, &numflag, &nparts, tpwgts, options, + &edgecut, cgraph->where); + + IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->InitPartTmr)); + IFSET(ctrl->dbglvl, DBG_IPART, printf("Initial %d-way partitioning cut: %d\n", nparts, edgecut)); + + IFSET(ctrl->dbglvl, DBG_KWAYPINFO, ComputePartitionInfo(cgraph, nparts, cgraph->where)); + + RefineKWay(ctrl, graph, cgraph, nparts, tpwgts, ubfactor); + + idxcopy(graph->nvtxs, graph->where, part); + + GKfree(&graph->gdata, &graph->rdata, LTERM); + + return graph->mincut; + +} + diff --git a/contrib/Metis/kvmetis.c b/contrib/Metis/kvmetis.c new file mode 100644 index 0000000000..f1d0b456e1 --- /dev/null +++ b/contrib/Metis/kvmetis.c @@ -0,0 +1,130 @@ +/* + * Copyright 1997, Regents of the University of Minnesota + * + * kvmetis.c + * + * This file contains the top level routines for the multilevel k-way partitioning + * algorithm KMETIS. + * + * Started 7/28/97 + * George + * + * $Id: kvmetis.c,v 1.1 2005-09-21 17:29:37 geuzaine Exp $ + * + */ + +#include <metis.h> + + +/************************************************************************* +* This function is the entry point for KMETIS +**************************************************************************/ +void METIS_PartGraphVKway(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, + idxtype *vsize, int *wgtflag, int *numflag, int *nparts, + int *options, int *volume, idxtype *part) +{ + int i; + float *tpwgts; + + tpwgts = fmalloc(*nparts, "KMETIS: tpwgts"); + for (i=0; i<*nparts; i++) + tpwgts[i] = 1.0/(1.0*(*nparts)); + + METIS_WPartGraphVKway(nvtxs, xadj, adjncy, vwgt, vsize, wgtflag, numflag, nparts, + tpwgts, options, volume, part); + + free(tpwgts); +} + + +/************************************************************************* +* This function is the entry point for KWMETIS +**************************************************************************/ +void METIS_WPartGraphVKway(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, + idxtype *vsize, int *wgtflag, int *numflag, int *nparts, + float *tpwgts, int *options, int *volume, idxtype *part) +{ + int i, j; + GraphType graph; + CtrlType ctrl; + + if (*numflag == 1) + Change2CNumbering(*nvtxs, xadj, adjncy); + + VolSetUpGraph(&graph, OP_KVMETIS, *nvtxs, 1, xadj, adjncy, vwgt, vsize, *wgtflag); + + if (options[0] == 0) { /* Use the default parameters */ + ctrl.CType = KVMETIS_CTYPE; + ctrl.IType = KVMETIS_ITYPE; + ctrl.RType = KVMETIS_RTYPE; + ctrl.dbglvl = KVMETIS_DBGLVL; + } + else { + ctrl.CType = options[OPTION_CTYPE]; + ctrl.IType = options[OPTION_ITYPE]; + ctrl.RType = options[OPTION_RTYPE]; + ctrl.dbglvl = options[OPTION_DBGLVL]; + } + ctrl.optype = OP_KVMETIS; + ctrl.CoarsenTo = amax((*nvtxs)/(40*log2(*nparts)), 20*(*nparts)); + ctrl.maxvwgt = 1.5*((graph.vwgt ? idxsum(*nvtxs, graph.vwgt) : (*nvtxs))/ctrl.CoarsenTo); + + InitRandom(-1); + + AllocateWorkSpace(&ctrl, &graph, *nparts); + + IFSET(ctrl.dbglvl, DBG_TIME, InitTimers(&ctrl)); + IFSET(ctrl.dbglvl, DBG_TIME, starttimer(ctrl.TotalTmr)); + + *volume = MlevelVolKWayPartitioning(&ctrl, &graph, *nparts, part, tpwgts, 1.03); + + IFSET(ctrl.dbglvl, DBG_TIME, stoptimer(ctrl.TotalTmr)); + IFSET(ctrl.dbglvl, DBG_TIME, PrintTimers(&ctrl)); + + FreeWorkSpace(&ctrl, &graph); + + if (*numflag == 1) + Change2FNumbering(*nvtxs, xadj, adjncy, part); +} + + +/************************************************************************* +* This function takes a graph and produces a bisection of it +**************************************************************************/ +int MlevelVolKWayPartitioning(CtrlType *ctrl, GraphType *graph, int nparts, idxtype *part, + float *tpwgts, float ubfactor) +{ + int i, j, nvtxs, tvwgt, tpwgts2[2]; + GraphType *cgraph; + int wgtflag=3, numflag=0, options[10], edgecut; + + cgraph = Coarsen2Way(ctrl, graph); + + IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->InitPartTmr)); + AllocateVolKWayPartitionMemory(ctrl, cgraph, nparts); + + options[0] = 1; + options[OPTION_CTYPE] = MATCH_SHEMKWAY; + options[OPTION_ITYPE] = IPART_GGPKL; + options[OPTION_RTYPE] = RTYPE_FM; + options[OPTION_DBGLVL] = 0; + + METIS_WPartGraphRecursive(&cgraph->nvtxs, cgraph->xadj, cgraph->adjncy, cgraph->vwgt, + cgraph->adjwgt, &wgtflag, &numflag, &nparts, tpwgts, options, + &edgecut, cgraph->where); + + IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->InitPartTmr)); + IFSET(ctrl->dbglvl, DBG_IPART, printf("Initial %d-way partitioning cut: %d\n", nparts, edgecut)); + + IFSET(ctrl->dbglvl, DBG_KWAYPINFO, ComputePartitionInfo(cgraph, nparts, cgraph->where)); + + RefineVolKWay(ctrl, graph, cgraph, nparts, tpwgts, ubfactor); + + idxcopy(graph->nvtxs, graph->where, part); + + GKfree(&graph->gdata, &graph->rdata, LTERM); + + return graph->minvol; + +} + diff --git a/contrib/Metis/kwayfm.c b/contrib/Metis/kwayfm.c new file mode 100644 index 0000000000..5772604948 --- /dev/null +++ b/contrib/Metis/kwayfm.c @@ -0,0 +1,672 @@ +/* + * kwayfm.c + * + * This file contains code that implements the multilevel k-way refinement + * + * Started 7/28/97 + * George + * + * $Id: kwayfm.c,v 1.1 2005-09-21 17:29:37 geuzaine Exp $ + * + */ + +#include <metis.h> + + +/************************************************************************* +* This function performs k-way refinement +**************************************************************************/ +void Random_KWayEdgeRefine(CtrlType *ctrl, GraphType *graph, int nparts, float *tpwgts, float ubfactor, int npasses, int ffactor) +{ + int i, ii, iii, j, jj, k, l, pass, nvtxs, nmoves, nbnd, tvwgt, myndegrees; + int from, me, to, oldcut, vwgt, gain; + idxtype *xadj, *adjncy, *adjwgt; + idxtype *where, *pwgts, *perm, *bndptr, *bndind, *minwgt, *maxwgt, *itpwgts; + EDegreeType *myedegrees; + RInfoType *myrinfo; + + nvtxs = graph->nvtxs; + xadj = graph->xadj; + adjncy = graph->adjncy; + adjwgt = graph->adjwgt; + + bndptr = graph->bndptr; + bndind = graph->bndind; + + where = graph->where; + pwgts = graph->pwgts; + + /* Setup the weight intervals of the various subdomains */ + minwgt = idxwspacemalloc(ctrl, nparts); + maxwgt = idxwspacemalloc(ctrl, nparts); + itpwgts = idxwspacemalloc(ctrl, nparts); + tvwgt = idxsum(nparts, pwgts); + ASSERT(tvwgt == idxsum(nvtxs, graph->vwgt)); + + for (i=0; i<nparts; i++) { + itpwgts[i] = tpwgts[i]*tvwgt; + maxwgt[i] = tpwgts[i]*tvwgt*ubfactor; + minwgt[i] = tpwgts[i]*tvwgt*(1.0/ubfactor); + } + + perm = idxwspacemalloc(ctrl, nvtxs); + + IFSET(ctrl->dbglvl, DBG_REFINE, + printf("Partitions: [%6d %6d]-[%6d %6d], Balance: %5.3f, Nv-Nb[%6d %6d]. Cut: %6d\n", + pwgts[idxamin(nparts, pwgts)], pwgts[idxamax(nparts, pwgts)], minwgt[0], maxwgt[0], + 1.0*nparts*pwgts[idxamax(nparts, pwgts)]/tvwgt, graph->nvtxs, graph->nbnd, + graph->mincut)); + + for (pass=0; pass<npasses; pass++) { + ASSERT(ComputeCut(graph, where) == graph->mincut); + + oldcut = graph->mincut; + nbnd = graph->nbnd; + + RandomPermute(nbnd, perm, 1); + for (nmoves=iii=0; iii<graph->nbnd; iii++) { + ii = perm[iii]; + if (ii >= nbnd) + continue; + i = bndind[ii]; + + myrinfo = graph->rinfo+i; + + if (myrinfo->ed >= myrinfo->id) { /* Total ED is too high */ + from = where[i]; + vwgt = graph->vwgt[i]; + + if (myrinfo->id > 0 && pwgts[from]-vwgt < minwgt[from]) + continue; /* This cannot be moved! */ + + myedegrees = myrinfo->edegrees; + myndegrees = myrinfo->ndegrees; + + j = myrinfo->id; + for (k=0; k<myndegrees; k++) { + to = myedegrees[k].pid; + gain = myedegrees[k].ed-j; /* j = myrinfo->id. Allow good nodes to move */ + if (pwgts[to]+vwgt <= maxwgt[to]+ffactor*gain && gain >= 0) + break; + } + if (k == myndegrees) + continue; /* break out if you did not find a candidate */ + + for (j=k+1; j<myndegrees; j++) { + to = myedegrees[j].pid; + if ((myedegrees[j].ed > myedegrees[k].ed && pwgts[to]+vwgt <= maxwgt[to]) || + (myedegrees[j].ed == myedegrees[k].ed && + itpwgts[myedegrees[k].pid]*pwgts[to] < itpwgts[to]*pwgts[myedegrees[k].pid])) + k = j; + } + + to = myedegrees[k].pid; + + j = 0; + if (myedegrees[k].ed-myrinfo->id > 0) + j = 1; + else if (myedegrees[k].ed-myrinfo->id == 0) { + if ((iii&7) == 0 || pwgts[from] >= maxwgt[from] || itpwgts[from]*(pwgts[to]+vwgt) < itpwgts[to]*pwgts[from]) + j = 1; + } + if (j == 0) + continue; + + /*===================================================================== + * If we got here, we can now move the vertex from 'from' to 'to' + *======================================================================*/ + graph->mincut -= myedegrees[k].ed-myrinfo->id; + + IFSET(ctrl->dbglvl, DBG_MOVEINFO, printf("\t\tMoving %6d to %3d. Gain: %4d. Cut: %6d\n", i, to, myedegrees[k].ed-myrinfo->id, graph->mincut)); + + /* Update where, weight, and ID/ED information of the vertex you moved */ + where[i] = to; + INC_DEC(pwgts[to], pwgts[from], vwgt); + myrinfo->ed += myrinfo->id-myedegrees[k].ed; + SWAP(myrinfo->id, myedegrees[k].ed, j); + if (myedegrees[k].ed == 0) + myedegrees[k] = myedegrees[--myrinfo->ndegrees]; + else + myedegrees[k].pid = from; + + if (myrinfo->ed-myrinfo->id < 0) + BNDDelete(nbnd, bndind, bndptr, i); + + /* Update the degrees of adjacent vertices */ + for (j=xadj[i]; j<xadj[i+1]; j++) { + ii = adjncy[j]; + me = where[ii]; + + myrinfo = graph->rinfo+ii; + if (myrinfo->edegrees == NULL) { + myrinfo->edegrees = ctrl->wspace.edegrees+ctrl->wspace.cdegree; + ctrl->wspace.cdegree += xadj[ii+1]-xadj[ii]; + } + myedegrees = myrinfo->edegrees; + + ASSERT(CheckRInfo(myrinfo)); + + if (me == from) { + INC_DEC(myrinfo->ed, myrinfo->id, adjwgt[j]); + + if (myrinfo->ed-myrinfo->id >= 0 && bndptr[ii] == -1) + BNDInsert(nbnd, bndind, bndptr, ii); + } + else if (me == to) { + INC_DEC(myrinfo->id, myrinfo->ed, adjwgt[j]); + + if (myrinfo->ed-myrinfo->id < 0 && bndptr[ii] != -1) + BNDDelete(nbnd, bndind, bndptr, ii); + } + + /* Remove contribution from the .ed of 'from' */ + if (me != from) { + for (k=0; k<myrinfo->ndegrees; k++) { + if (myedegrees[k].pid == from) { + if (myedegrees[k].ed == adjwgt[j]) + myedegrees[k] = myedegrees[--myrinfo->ndegrees]; + else + myedegrees[k].ed -= adjwgt[j]; + break; + } + } + } + + /* Add contribution to the .ed of 'to' */ + if (me != to) { + for (k=0; k<myrinfo->ndegrees; k++) { + if (myedegrees[k].pid == to) { + myedegrees[k].ed += adjwgt[j]; + break; + } + } + if (k == myrinfo->ndegrees) { + myedegrees[myrinfo->ndegrees].pid = to; + myedegrees[myrinfo->ndegrees++].ed = adjwgt[j]; + } + } + + ASSERT(myrinfo->ndegrees <= xadj[ii+1]-xadj[ii]); + ASSERT(CheckRInfo(myrinfo)); + + } + nmoves++; + } + } + + graph->nbnd = nbnd; + + IFSET(ctrl->dbglvl, DBG_REFINE, + printf("\t[%6d %6d], Balance: %5.3f, Nb: %6d. Nmoves: %5d, Cut: %6d, Vol: %6d\n", + pwgts[idxamin(nparts, pwgts)], pwgts[idxamax(nparts, pwgts)], + 1.0*nparts*pwgts[idxamax(nparts, pwgts)]/tvwgt, graph->nbnd, nmoves, graph->mincut, ComputeVolume(graph, where))); + + if (graph->mincut == oldcut) + break; + } + + idxwspacefree(ctrl, nparts); + idxwspacefree(ctrl, nparts); + idxwspacefree(ctrl, nparts); + idxwspacefree(ctrl, nvtxs); +} + + + + + + +/************************************************************************* +* This function performs k-way refinement +**************************************************************************/ +void Greedy_KWayEdgeRefine(CtrlType *ctrl, GraphType *graph, int nparts, float *tpwgts, float ubfactor, int npasses) +{ + int i, ii, iii, j, jj, k, l, pass, nvtxs, nbnd, tvwgt, myndegrees, oldgain, gain; + int from, me, to, oldcut, vwgt; + idxtype *xadj, *adjncy, *adjwgt; + idxtype *where, *pwgts, *perm, *bndptr, *bndind, *minwgt, *maxwgt, *moved, *itpwgts; + EDegreeType *myedegrees; + RInfoType *myrinfo; + PQueueType queue; + + nvtxs = graph->nvtxs; + xadj = graph->xadj; + adjncy = graph->adjncy; + adjwgt = graph->adjwgt; + + bndind = graph->bndind; + bndptr = graph->bndptr; + + where = graph->where; + pwgts = graph->pwgts; + + /* Setup the weight intervals of the various subdomains */ + minwgt = idxwspacemalloc(ctrl, nparts); + maxwgt = idxwspacemalloc(ctrl, nparts); + itpwgts = idxwspacemalloc(ctrl, nparts); + tvwgt = idxsum(nparts, pwgts); + ASSERT(tvwgt == idxsum(nvtxs, graph->vwgt)); + + for (i=0; i<nparts; i++) { + itpwgts[i] = tpwgts[i]*tvwgt; + maxwgt[i] = tpwgts[i]*tvwgt*ubfactor; + minwgt[i] = tpwgts[i]*tvwgt*(1.0/ubfactor); + } + + perm = idxwspacemalloc(ctrl, nvtxs); + moved = idxwspacemalloc(ctrl, nvtxs); + + PQueueInit(ctrl, &queue, nvtxs, graph->adjwgtsum[idxamax(nvtxs, graph->adjwgtsum)]); + + IFSET(ctrl->dbglvl, DBG_REFINE, + printf("Partitions: [%6d %6d]-[%6d %6d], Balance: %5.3f, Nv-Nb[%6d %6d]. Cut: %6d\n", + pwgts[idxamin(nparts, pwgts)], pwgts[idxamax(nparts, pwgts)], minwgt[0], maxwgt[0], + 1.0*nparts*pwgts[idxamax(nparts, pwgts)]/tvwgt, graph->nvtxs, graph->nbnd, + graph->mincut)); + + for (pass=0; pass<npasses; pass++) { + ASSERT(ComputeCut(graph, where) == graph->mincut); + + PQueueReset(&queue); + idxset(nvtxs, -1, moved); + + oldcut = graph->mincut; + nbnd = graph->nbnd; + + RandomPermute(nbnd, perm, 1); + for (ii=0; ii<nbnd; ii++) { + i = bndind[perm[ii]]; + PQueueInsert(&queue, i, graph->rinfo[i].ed - graph->rinfo[i].id); + moved[i] = 2; + } + + for (iii=0;;iii++) { + if ((i = PQueueGetMax(&queue)) == -1) + break; + moved[i] = 1; + + myrinfo = graph->rinfo+i; + from = where[i]; + vwgt = graph->vwgt[i]; + + if (pwgts[from]-vwgt < minwgt[from]) + continue; /* This cannot be moved! */ + + myedegrees = myrinfo->edegrees; + myndegrees = myrinfo->ndegrees; + + j = myrinfo->id; + for (k=0; k<myndegrees; k++) { + to = myedegrees[k].pid; + gain = myedegrees[k].ed-j; /* j = myrinfo->id. Allow good nodes to move */ + if (pwgts[to]+vwgt <= maxwgt[to]+gain && gain >= 0) + break; + } + if (k == myndegrees) + continue; /* break out if you did not find a candidate */ + + for (j=k+1; j<myndegrees; j++) { + to = myedegrees[j].pid; + if ((myedegrees[j].ed > myedegrees[k].ed && pwgts[to]+vwgt <= maxwgt[to]) || + (myedegrees[j].ed == myedegrees[k].ed && + itpwgts[myedegrees[k].pid]*pwgts[to] < itpwgts[to]*pwgts[myedegrees[k].pid])) + k = j; + } + + to = myedegrees[k].pid; + + j = 0; + if (myedegrees[k].ed-myrinfo->id > 0) + j = 1; + else if (myedegrees[k].ed-myrinfo->id == 0) { + if ((iii&7) == 0 || pwgts[from] >= maxwgt[from] || itpwgts[from]*(pwgts[to]+vwgt) < itpwgts[to]*pwgts[from]) + j = 1; + } + if (j == 0) + continue; + + /*===================================================================== + * If we got here, we can now move the vertex from 'from' to 'to' + *======================================================================*/ + graph->mincut -= myedegrees[k].ed-myrinfo->id; + + IFSET(ctrl->dbglvl, DBG_MOVEINFO, printf("\t\tMoving %6d to %3d. Gain: %4d. Cut: %6d\n", i, to, myedegrees[k].ed-myrinfo->id, graph->mincut)); + + /* Update where, weight, and ID/ED information of the vertex you moved */ + where[i] = to; + INC_DEC(pwgts[to], pwgts[from], vwgt); + myrinfo->ed += myrinfo->id-myedegrees[k].ed; + SWAP(myrinfo->id, myedegrees[k].ed, j); + if (myedegrees[k].ed == 0) + myedegrees[k] = myedegrees[--myrinfo->ndegrees]; + else + myedegrees[k].pid = from; + + if (myrinfo->ed < myrinfo->id) + BNDDelete(nbnd, bndind, bndptr, i); + + /* Update the degrees of adjacent vertices */ + for (j=xadj[i]; j<xadj[i+1]; j++) { + ii = adjncy[j]; + me = where[ii]; + + myrinfo = graph->rinfo+ii; + if (myrinfo->edegrees == NULL) { + myrinfo->edegrees = ctrl->wspace.edegrees+ctrl->wspace.cdegree; + ctrl->wspace.cdegree += xadj[ii+1]-xadj[ii]; + } + myedegrees = myrinfo->edegrees; + + ASSERT(CheckRInfo(myrinfo)); + + oldgain = (myrinfo->ed-myrinfo->id); + + if (me == from) { + INC_DEC(myrinfo->ed, myrinfo->id, adjwgt[j]); + + if (myrinfo->ed-myrinfo->id >= 0 && bndptr[ii] == -1) + BNDInsert(nbnd, bndind, bndptr, ii); + } + else if (me == to) { + INC_DEC(myrinfo->id, myrinfo->ed, adjwgt[j]); + + if (myrinfo->ed-myrinfo->id < 0 && bndptr[ii] != -1) + BNDDelete(nbnd, bndind, bndptr, ii); + } + + /* Remove contribution from the .ed of 'from' */ + if (me != from) { + for (k=0; k<myrinfo->ndegrees; k++) { + if (myedegrees[k].pid == from) { + if (myedegrees[k].ed == adjwgt[j]) + myedegrees[k] = myedegrees[--myrinfo->ndegrees]; + else + myedegrees[k].ed -= adjwgt[j]; + break; + } + } + } + + /* Add contribution to the .ed of 'to' */ + if (me != to) { + for (k=0; k<myrinfo->ndegrees; k++) { + if (myedegrees[k].pid == to) { + myedegrees[k].ed += adjwgt[j]; + break; + } + } + if (k == myrinfo->ndegrees) { + myedegrees[myrinfo->ndegrees].pid = to; + myedegrees[myrinfo->ndegrees++].ed = adjwgt[j]; + } + } + + /* Update the queue */ + if (me == to || me == from) { + gain = myrinfo->ed-myrinfo->id; + if (moved[ii] == 2) { + if (gain >= 0) + PQueueUpdate(&queue, ii, oldgain, gain); + else { + PQueueDelete(&queue, ii, oldgain); + moved[ii] = -1; + } + } + else if (moved[ii] == -1 && gain >= 0) { + PQueueInsert(&queue, ii, gain); + moved[ii] = 2; + } + } + + ASSERT(myrinfo->ndegrees <= xadj[ii+1]-xadj[ii]); + ASSERT(CheckRInfo(myrinfo)); + + } + } + + graph->nbnd = nbnd; + + IFSET(ctrl->dbglvl, DBG_REFINE, + printf("\t[%6d %6d], Balance: %5.3f, Nb: %6d. Cut: %6d\n", + pwgts[idxamin(nparts, pwgts)], pwgts[idxamax(nparts, pwgts)], + 1.0*nparts*pwgts[idxamax(nparts, pwgts)]/tvwgt, graph->nbnd, graph->mincut)); + + if (graph->mincut == oldcut) + break; + } + + PQueueFree(ctrl, &queue); + + idxwspacefree(ctrl, nparts); + idxwspacefree(ctrl, nparts); + idxwspacefree(ctrl, nparts); + idxwspacefree(ctrl, nvtxs); + idxwspacefree(ctrl, nvtxs); + +} + + +/************************************************************************* +* This function performs k-way refinement +**************************************************************************/ +void Greedy_KWayEdgeBalance(CtrlType *ctrl, GraphType *graph, int nparts, float *tpwgts, float ubfactor, int npasses) +{ + int i, ii, iii, j, jj, k, l, pass, nvtxs, nbnd, tvwgt, myndegrees, oldgain, gain, nmoves; + int from, me, to, oldcut, vwgt; + idxtype *xadj, *adjncy, *adjwgt; + idxtype *where, *pwgts, *perm, *bndptr, *bndind, *minwgt, *maxwgt, *moved, *itpwgts; + EDegreeType *myedegrees; + RInfoType *myrinfo; + PQueueType queue; + + nvtxs = graph->nvtxs; + xadj = graph->xadj; + adjncy = graph->adjncy; + adjwgt = graph->adjwgt; + + bndind = graph->bndind; + bndptr = graph->bndptr; + + where = graph->where; + pwgts = graph->pwgts; + + /* Setup the weight intervals of the various subdomains */ + minwgt = idxwspacemalloc(ctrl, nparts); + maxwgt = idxwspacemalloc(ctrl, nparts); + itpwgts = idxwspacemalloc(ctrl, nparts); + tvwgt = idxsum(nparts, pwgts); + ASSERT(tvwgt == idxsum(nvtxs, graph->vwgt)); + + for (i=0; i<nparts; i++) { + itpwgts[i] = tpwgts[i]*tvwgt; + maxwgt[i] = tpwgts[i]*tvwgt*ubfactor; + minwgt[i] = tpwgts[i]*tvwgt*(1.0/ubfactor); + } + + perm = idxwspacemalloc(ctrl, nvtxs); + moved = idxwspacemalloc(ctrl, nvtxs); + + PQueueInit(ctrl, &queue, nvtxs, graph->adjwgtsum[idxamax(nvtxs, graph->adjwgtsum)]); + + IFSET(ctrl->dbglvl, DBG_REFINE, + printf("Partitions: [%6d %6d]-[%6d %6d], Balance: %5.3f, Nv-Nb[%6d %6d]. Cut: %6d [B]\n", + pwgts[idxamin(nparts, pwgts)], pwgts[idxamax(nparts, pwgts)], minwgt[0], maxwgt[0], + 1.0*nparts*pwgts[idxamax(nparts, pwgts)]/tvwgt, graph->nvtxs, graph->nbnd, + graph->mincut)); + + for (pass=0; pass<npasses; pass++) { + ASSERT(ComputeCut(graph, where) == graph->mincut); + + /* Check to see if things are out of balance, given the tolerance */ + for (i=0; i<nparts; i++) { + if (pwgts[i] > maxwgt[i]) + break; + } + if (i == nparts) /* Things are balanced. Return right away */ + break; + + PQueueReset(&queue); + idxset(nvtxs, -1, moved); + + oldcut = graph->mincut; + nbnd = graph->nbnd; + + RandomPermute(nbnd, perm, 1); + for (ii=0; ii<nbnd; ii++) { + i = bndind[perm[ii]]; + PQueueInsert(&queue, i, graph->rinfo[i].ed - graph->rinfo[i].id); + moved[i] = 2; + } + + nmoves = 0; + for (;;) { + if ((i = PQueueGetMax(&queue)) == -1) + break; + moved[i] = 1; + + myrinfo = graph->rinfo+i; + from = where[i]; + vwgt = graph->vwgt[i]; + + if (pwgts[from]-vwgt < minwgt[from]) + continue; /* This cannot be moved! */ + + myedegrees = myrinfo->edegrees; + myndegrees = myrinfo->ndegrees; + + for (k=0; k<myndegrees; k++) { + to = myedegrees[k].pid; + if (pwgts[to]+vwgt <= maxwgt[to] || itpwgts[from]*(pwgts[to]+vwgt) <= itpwgts[to]*pwgts[from]) + break; + } + if (k == myndegrees) + continue; /* break out if you did not find a candidate */ + + for (j=k+1; j<myndegrees; j++) { + to = myedegrees[j].pid; + if (itpwgts[myedegrees[k].pid]*pwgts[to] < itpwgts[to]*pwgts[myedegrees[k].pid]) + k = j; + } + + to = myedegrees[k].pid; + + if (pwgts[from] < maxwgt[from] && pwgts[to] > minwgt[to] && myedegrees[k].ed-myrinfo->id < 0) + continue; + + /*===================================================================== + * If we got here, we can now move the vertex from 'from' to 'to' + *======================================================================*/ + graph->mincut -= myedegrees[k].ed-myrinfo->id; + + IFSET(ctrl->dbglvl, DBG_MOVEINFO, printf("\t\tMoving %6d to %3d. Gain: %4d. Cut: %6d\n", i, to, myedegrees[k].ed-myrinfo->id, graph->mincut)); + + /* Update where, weight, and ID/ED information of the vertex you moved */ + where[i] = to; + INC_DEC(pwgts[to], pwgts[from], vwgt); + myrinfo->ed += myrinfo->id-myedegrees[k].ed; + SWAP(myrinfo->id, myedegrees[k].ed, j); + if (myedegrees[k].ed == 0) + myedegrees[k] = myedegrees[--myrinfo->ndegrees]; + else + myedegrees[k].pid = from; + + if (myrinfo->ed == 0) + BNDDelete(nbnd, bndind, bndptr, i); + + /* Update the degrees of adjacent vertices */ + for (j=xadj[i]; j<xadj[i+1]; j++) { + ii = adjncy[j]; + me = where[ii]; + + myrinfo = graph->rinfo+ii; + if (myrinfo->edegrees == NULL) { + myrinfo->edegrees = ctrl->wspace.edegrees+ctrl->wspace.cdegree; + ctrl->wspace.cdegree += xadj[ii+1]-xadj[ii]; + } + myedegrees = myrinfo->edegrees; + + ASSERT(CheckRInfo(myrinfo)); + + oldgain = (myrinfo->ed-myrinfo->id); + + if (me == from) { + INC_DEC(myrinfo->ed, myrinfo->id, adjwgt[j]); + + if (myrinfo->ed > 0 && bndptr[ii] == -1) + BNDInsert(nbnd, bndind, bndptr, ii); + } + else if (me == to) { + INC_DEC(myrinfo->id, myrinfo->ed, adjwgt[j]); + + if (myrinfo->ed == 0 && bndptr[ii] != -1) + BNDDelete(nbnd, bndind, bndptr, ii); + } + + /* Remove contribution from the .ed of 'from' */ + if (me != from) { + for (k=0; k<myrinfo->ndegrees; k++) { + if (myedegrees[k].pid == from) { + if (myedegrees[k].ed == adjwgt[j]) + myedegrees[k] = myedegrees[--myrinfo->ndegrees]; + else + myedegrees[k].ed -= adjwgt[j]; + break; + } + } + } + + /* Add contribution to the .ed of 'to' */ + if (me != to) { + for (k=0; k<myrinfo->ndegrees; k++) { + if (myedegrees[k].pid == to) { + myedegrees[k].ed += adjwgt[j]; + break; + } + } + if (k == myrinfo->ndegrees) { + myedegrees[myrinfo->ndegrees].pid = to; + myedegrees[myrinfo->ndegrees++].ed = adjwgt[j]; + } + } + + /* Update the queue */ + if (me == to || me == from) { + gain = myrinfo->ed-myrinfo->id; + if (moved[ii] == 2) { + if (myrinfo->ed > 0) + PQueueUpdate(&queue, ii, oldgain, gain); + else { + PQueueDelete(&queue, ii, oldgain); + moved[ii] = -1; + } + } + else if (moved[ii] == -1 && myrinfo->ed > 0) { + PQueueInsert(&queue, ii, gain); + moved[ii] = 2; + } + } + + ASSERT(myrinfo->ndegrees <= xadj[ii+1]-xadj[ii]); + ASSERT(CheckRInfo(myrinfo)); + } + nmoves++; + } + + graph->nbnd = nbnd; + + IFSET(ctrl->dbglvl, DBG_REFINE, + printf("\t[%6d %6d], Balance: %5.3f, Nb: %6d. Nmoves: %5d, Cut: %6d\n", + pwgts[idxamin(nparts, pwgts)], pwgts[idxamax(nparts, pwgts)], + 1.0*nparts*pwgts[idxamax(nparts, pwgts)]/tvwgt, graph->nbnd, nmoves, graph->mincut)); + } + + PQueueFree(ctrl, &queue); + + idxwspacefree(ctrl, nparts); + idxwspacefree(ctrl, nparts); + idxwspacefree(ctrl, nparts); + idxwspacefree(ctrl, nvtxs); + idxwspacefree(ctrl, nvtxs); + +} + diff --git a/contrib/Metis/kwayrefine.c b/contrib/Metis/kwayrefine.c new file mode 100644 index 0000000000..2783e6cad4 --- /dev/null +++ b/contrib/Metis/kwayrefine.c @@ -0,0 +1,392 @@ +/* + * Copyright 1997, Regents of the University of Minnesota + * + * kwayrefine.c + * + * This file contains the driving routines for multilevel k-way refinement + * + * Started 7/28/97 + * George + * + * $Id: kwayrefine.c,v 1.1 2005-09-21 17:29:37 geuzaine Exp $ + */ + +#include <metis.h> + + +/************************************************************************* +* This function is the entry point of refinement +**************************************************************************/ +void RefineKWay(CtrlType *ctrl, GraphType *orggraph, GraphType *graph, int nparts, float *tpwgts, float ubfactor) +{ + int i, nlevels, mustfree=0; + GraphType *ptr; + + IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->UncoarsenTmr)); + + /* Compute the parameters of the coarsest graph */ + ComputeKWayPartitionParams(ctrl, graph, nparts); + + /* Take care any non-contiguity */ + IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->AuxTmr1)); + if (ctrl->RType == RTYPE_KWAYRANDOM_MCONN) { + EliminateComponents(ctrl, graph, nparts, tpwgts, 1.25); + EliminateSubDomainEdges(ctrl, graph, nparts, tpwgts); + EliminateComponents(ctrl, graph, nparts, tpwgts, 1.25); + } + IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->AuxTmr1)); + + /* Determine how many levels are there */ + for (ptr=graph, nlevels=0; ptr!=orggraph; ptr=ptr->finer, nlevels++); + + for (i=0; ;i++) { + /* PrintSubDomainGraph(graph, nparts, graph->where); */ + if (ctrl->RType == RTYPE_KWAYRANDOM_MCONN && (i == nlevels/2 || i == nlevels/2+1)) + EliminateSubDomainEdges(ctrl, graph, nparts, tpwgts); + + IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->RefTmr)); + + if (2*i >= nlevels && !IsBalanced(graph->pwgts, nparts, tpwgts, 1.04*ubfactor)) { + ComputeKWayBalanceBoundary(ctrl, graph, nparts); + if (ctrl->RType == RTYPE_KWAYRANDOM_MCONN) + Greedy_KWayEdgeBalanceMConn(ctrl, graph, nparts, tpwgts, ubfactor, 1); + else + Greedy_KWayEdgeBalance(ctrl, graph, nparts, tpwgts, ubfactor, 1); + ComputeKWayBoundary(ctrl, graph, nparts); + } + + switch (ctrl->RType) { + case RTYPE_KWAYRANDOM: + Random_KWayEdgeRefine(ctrl, graph, nparts, tpwgts, ubfactor, 10, 1); + break; + case RTYPE_KWAYGREEDY: + Greedy_KWayEdgeRefine(ctrl, graph, nparts, tpwgts, ubfactor, 10); + break; + case RTYPE_KWAYRANDOM_MCONN: + Random_KWayEdgeRefineMConn(ctrl, graph, nparts, tpwgts, ubfactor, 10, 1); + break; + } + IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->RefTmr)); + + if (graph == orggraph) + break; + + GKfree(&graph->gdata, LTERM); /* Deallocate the graph related arrays */ + + graph = graph->finer; + + IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->ProjectTmr)); + if (graph->vwgt == NULL) { + graph->vwgt = idxsmalloc(graph->nvtxs, 1, "RefineKWay: graph->vwgt"); + graph->adjwgt = idxsmalloc(graph->nedges, 1, "RefineKWay: graph->adjwgt"); + mustfree = 1; + } + ProjectKWayPartition(ctrl, graph, nparts); + IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->ProjectTmr)); + } + + if (!IsBalanced(graph->pwgts, nparts, tpwgts, ubfactor)) { + ComputeKWayBalanceBoundary(ctrl, graph, nparts); + if (ctrl->RType == RTYPE_KWAYRANDOM_MCONN) { + Greedy_KWayEdgeBalanceMConn(ctrl, graph, nparts, tpwgts, ubfactor, 8); + Random_KWayEdgeRefineMConn(ctrl, graph, nparts, tpwgts, ubfactor, 10, 0); + } + else { + Greedy_KWayEdgeBalance(ctrl, graph, nparts, tpwgts, ubfactor, 8); + Random_KWayEdgeRefine(ctrl, graph, nparts, tpwgts, ubfactor, 10, 0); + } + } + + /* Take care any trivial non-contiguity */ + IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->AuxTmr2)); + EliminateComponents(ctrl, graph, nparts, tpwgts, ubfactor); + IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->AuxTmr2)); + + if (mustfree) + GKfree(&graph->vwgt, &graph->adjwgt, LTERM); + + IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->UncoarsenTmr)); +} + + +/************************************************************************* +* This function allocates memory for k-way edge refinement +**************************************************************************/ +void AllocateKWayPartitionMemory(CtrlType *ctrl, GraphType *graph, int nparts) +{ + int nvtxs, pad64; + + nvtxs = graph->nvtxs; + + pad64 = (3*nvtxs+nparts)%2; + + graph->rdata = idxmalloc(3*nvtxs+nparts+(sizeof(RInfoType)/sizeof(idxtype))*nvtxs+pad64, "AllocateKWayPartitionMemory: rdata"); + graph->pwgts = graph->rdata; + graph->where = graph->rdata + nparts; + graph->bndptr = graph->rdata + nvtxs + nparts; + graph->bndind = graph->rdata + 2*nvtxs + nparts; + graph->rinfo = (RInfoType *)(graph->rdata + 3*nvtxs+nparts + pad64); + +/* + if (ctrl->wspace.edegrees != NULL) + free(ctrl->wspace.edegrees); + ctrl->wspace.edegrees = (EDegreeType *)GKmalloc(graph->nedges*sizeof(EDegreeType), "AllocateKWayPartitionMemory: edegrees"); +*/ +} + + +/************************************************************************* +* This function computes the initial id/ed +**************************************************************************/ +void ComputeKWayPartitionParams(CtrlType *ctrl, GraphType *graph, int nparts) +{ + int i, j, k, l, nvtxs, nbnd, mincut, me, other; + idxtype *xadj, *vwgt, *adjncy, *adjwgt, *pwgts, *where, *bndind, *bndptr; + RInfoType *rinfo, *myrinfo; + EDegreeType *myedegrees; + + nvtxs = graph->nvtxs; + xadj = graph->xadj; + vwgt = graph->vwgt; + adjncy = graph->adjncy; + adjwgt = graph->adjwgt; + + where = graph->where; + pwgts = idxset(nparts, 0, graph->pwgts); + bndind = graph->bndind; + bndptr = idxset(nvtxs, -1, graph->bndptr); + rinfo = graph->rinfo; + + + /*------------------------------------------------------------ + / Compute now the id/ed degrees + /------------------------------------------------------------*/ + ctrl->wspace.cdegree = 0; + nbnd = mincut = 0; + for (i=0; i<nvtxs; i++) { + me = where[i]; + pwgts[me] += vwgt[i]; + + myrinfo = rinfo+i; + myrinfo->id = myrinfo->ed = myrinfo->ndegrees = 0; + myrinfo->edegrees = NULL; + + for (j=xadj[i]; j<xadj[i+1]; j++) { + if (me != where[adjncy[j]]) + myrinfo->ed += adjwgt[j]; + } + myrinfo->id = graph->adjwgtsum[i] - myrinfo->ed; + + if (myrinfo->ed > 0) + mincut += myrinfo->ed; + + if (myrinfo->ed-myrinfo->id >= 0) + BNDInsert(nbnd, bndind, bndptr, i); + + /* Time to compute the particular external degrees */ + if (myrinfo->ed > 0) { + myedegrees = myrinfo->edegrees = ctrl->wspace.edegrees+ctrl->wspace.cdegree; + ctrl->wspace.cdegree += xadj[i+1]-xadj[i]; + + for (j=xadj[i]; j<xadj[i+1]; j++) { + other = where[adjncy[j]]; + if (me != other) { + for (k=0; k<myrinfo->ndegrees; k++) { + if (myedegrees[k].pid == other) { + myedegrees[k].ed += adjwgt[j]; + break; + } + } + if (k == myrinfo->ndegrees) { + myedegrees[myrinfo->ndegrees].pid = other; + myedegrees[myrinfo->ndegrees++].ed = adjwgt[j]; + } + } + } + + ASSERT(myrinfo->ndegrees <= xadj[i+1]-xadj[i]); + } + } + + graph->mincut = mincut/2; + graph->nbnd = nbnd; + +} + + + +/************************************************************************* +* This function projects a partition, and at the same time computes the +* parameters for refinement. +**************************************************************************/ +void ProjectKWayPartition(CtrlType *ctrl, GraphType *graph, int nparts) +{ + int i, j, k, nvtxs, nbnd, me, other, istart, iend, ndegrees; + idxtype *xadj, *adjncy, *adjwgt, *adjwgtsum; + idxtype *cmap, *where, *bndptr, *bndind; + idxtype *cwhere; + GraphType *cgraph; + RInfoType *crinfo, *rinfo, *myrinfo; + EDegreeType *myedegrees; + idxtype *htable; + + cgraph = graph->coarser; + cwhere = cgraph->where; + crinfo = cgraph->rinfo; + + nvtxs = graph->nvtxs; + cmap = graph->cmap; + xadj = graph->xadj; + adjncy = graph->adjncy; + adjwgt = graph->adjwgt; + adjwgtsum = graph->adjwgtsum; + + AllocateKWayPartitionMemory(ctrl, graph, nparts); + where = graph->where; + rinfo = graph->rinfo; + bndind = graph->bndind; + bndptr = idxset(nvtxs, -1, graph->bndptr); + + /* Go through and project partition and compute id/ed for the nodes */ + for (i=0; i<nvtxs; i++) { + k = cmap[i]; + where[i] = cwhere[k]; + cmap[i] = crinfo[k].ed; /* For optimization */ + } + + htable = idxset(nparts, -1, idxwspacemalloc(ctrl, nparts)); + + ctrl->wspace.cdegree = 0; + for (nbnd=0, i=0; i<nvtxs; i++) { + me = where[i]; + + myrinfo = rinfo+i; + myrinfo->id = myrinfo->ed = myrinfo->ndegrees = 0; + myrinfo->edegrees = NULL; + + myrinfo->id = adjwgtsum[i]; + + if (cmap[i] > 0) { /* If it is an interface node. Note cmap[i] = crinfo[cmap[i]].ed */ + istart = xadj[i]; + iend = xadj[i+1]; + + myedegrees = myrinfo->edegrees = ctrl->wspace.edegrees+ctrl->wspace.cdegree; + ctrl->wspace.cdegree += iend-istart; + + ndegrees = 0; + for (j=istart; j<iend; j++) { + other = where[adjncy[j]]; + if (me != other) { + myrinfo->ed += adjwgt[j]; + if ((k = htable[other]) == -1) { + htable[other] = ndegrees; + myedegrees[ndegrees].pid = other; + myedegrees[ndegrees++].ed = adjwgt[j]; + } + else { + myedegrees[k].ed += adjwgt[j]; + } + } + } + myrinfo->id -= myrinfo->ed; + + /* Remove space for edegrees if it was interior */ + if (myrinfo->ed == 0) { + myrinfo->edegrees = NULL; + ctrl->wspace.cdegree -= iend-istart; + } + else { + if (myrinfo->ed-myrinfo->id >= 0) + BNDInsert(nbnd, bndind, bndptr, i); + + myrinfo->ndegrees = ndegrees; + + for (j=0; j<ndegrees; j++) + htable[myedegrees[j].pid] = -1; + } + } + } + + idxcopy(nparts, cgraph->pwgts, graph->pwgts); + graph->mincut = cgraph->mincut; + graph->nbnd = nbnd; + + FreeGraph(graph->coarser); + graph->coarser = NULL; + + idxwspacefree(ctrl, nparts); + + ASSERT(CheckBnd2(graph)); + +} + + + +/************************************************************************* +* This function checks if the partition weights are within the balance +* contraints +**************************************************************************/ +int IsBalanced(idxtype *pwgts, int nparts, float *tpwgts, float ubfactor) +{ + int i, j, tvwgt; + + tvwgt = idxsum(nparts, pwgts); + for (i=0; i<nparts; i++) { + if (pwgts[i] > tpwgts[i]*tvwgt*(ubfactor+0.005)) + return 0; + } + + return 1; +} + + +/************************************************************************* +* This function computes the boundary definition for balancing +**************************************************************************/ +void ComputeKWayBoundary(CtrlType *ctrl, GraphType *graph, int nparts) +{ + int i, nvtxs, nbnd; + idxtype *bndind, *bndptr; + + nvtxs = graph->nvtxs; + bndind = graph->bndind; + bndptr = idxset(nvtxs, -1, graph->bndptr); + + + /*------------------------------------------------------------ + / Compute the new boundary + /------------------------------------------------------------*/ + nbnd = 0; + for (i=0; i<nvtxs; i++) { + if (graph->rinfo[i].ed-graph->rinfo[i].id >= 0) + BNDInsert(nbnd, bndind, bndptr, i); + } + + graph->nbnd = nbnd; +} + +/************************************************************************* +* This function computes the boundary definition for balancing +**************************************************************************/ +void ComputeKWayBalanceBoundary(CtrlType *ctrl, GraphType *graph, int nparts) +{ + int i, nvtxs, nbnd; + idxtype *bndind, *bndptr; + + nvtxs = graph->nvtxs; + bndind = graph->bndind; + bndptr = idxset(nvtxs, -1, graph->bndptr); + + + /*------------------------------------------------------------ + / Compute the new boundary + /------------------------------------------------------------*/ + nbnd = 0; + for (i=0; i<nvtxs; i++) { + if (graph->rinfo[i].ed > 0) + BNDInsert(nbnd, bndind, bndptr, i); + } + + graph->nbnd = nbnd; +} + diff --git a/contrib/Metis/kwayvolfm.c b/contrib/Metis/kwayvolfm.c new file mode 100644 index 0000000000..3271571ff1 --- /dev/null +++ b/contrib/Metis/kwayvolfm.c @@ -0,0 +1,1778 @@ +/* + * kwayvolfm.c + * + * This file contains code that implements the multilevel k-way refinement + * + * Started 7/8/98 + * George + * + * $Id: kwayvolfm.c,v 1.1 2005-09-21 17:29:37 geuzaine Exp $ + * + */ + +#include <metis.h> + + +/************************************************************************* +* This function performs k-way refinement +**************************************************************************/ +void Random_KWayVolRefine(CtrlType *ctrl, GraphType *graph, int nparts, float *tpwgts, + float ubfactor, int npasses, int ffactor) +{ + int i, ii, iii, j, jj, k, kk, l, u, pass, nvtxs, nmoves, tvwgt, myndegrees, xgain; + int from, me, to, oldcut, oldvol, vwgt; + idxtype *xadj, *adjncy, *adjwgt; + idxtype *where, *pwgts, *perm, *bndptr, *bndind, *minwgt, *maxwgt, *itpwgts, *updind, *marker, *phtable; + VEDegreeType *myedegrees; + VRInfoType *myrinfo; + + nvtxs = graph->nvtxs; + xadj = graph->xadj; + adjncy = graph->adjncy; + adjwgt = graph->adjwgt; + + bndptr = graph->bndptr; + bndind = graph->bndind; + + where = graph->where; + pwgts = graph->pwgts; + + /* Setup the weight intervals of the various subdomains */ + minwgt = idxwspacemalloc(ctrl, nparts); + maxwgt = idxwspacemalloc(ctrl, nparts); + itpwgts = idxwspacemalloc(ctrl, nparts); + tvwgt = idxsum(nparts, pwgts); + ASSERT(tvwgt == idxsum(nvtxs, graph->vwgt)); + + updind = idxmalloc(nvtxs, "Random_KWayVolRefine: updind"); + marker = idxsmalloc(nvtxs, 0, "Random_KWayVolRefine: marker"); + phtable = idxsmalloc(nparts, -1, "Random_KWayVolRefine: phtable"); + + for (i=0; i<nparts; i++) { + itpwgts[i] = tpwgts[i]*tvwgt; + maxwgt[i] = tpwgts[i]*tvwgt*ubfactor; + minwgt[i] = tpwgts[i]*tvwgt*(1.0/ubfactor); + } + + perm = idxwspacemalloc(ctrl, nvtxs); + + IFSET(ctrl->dbglvl, DBG_REFINE, + printf("VolPart: [%5d %5d]-[%5d %5d], Balance: %3.2f, Nv-Nb[%5d %5d]. Cut: %5d, Vol: %5d\n", + pwgts[idxamin(nparts, pwgts)], pwgts[idxamax(nparts, pwgts)], minwgt[0], maxwgt[0], + 1.0*nparts*pwgts[idxamax(nparts, pwgts)]/tvwgt, graph->nvtxs, graph->nbnd, + graph->mincut, graph->minvol)); + + for (pass=0; pass<npasses; pass++) { + ASSERT(ComputeCut(graph, where) == graph->mincut); + + oldcut = graph->mincut; + oldvol = graph->minvol; + + RandomPermute(graph->nbnd, perm, 1); + for (nmoves=iii=0; iii<graph->nbnd; iii++) { + ii = perm[iii]; + if (ii >= graph->nbnd) + continue; + i = bndind[ii]; + myrinfo = graph->vrinfo+i; + + if (myrinfo->gv >= 0) { /* Total volume gain is too high */ + from = where[i]; + vwgt = graph->vwgt[i]; + + if (myrinfo->id > 0 && pwgts[from]-vwgt < minwgt[from]) + continue; /* This cannot be moved! */ + + xgain = (myrinfo->id == 0 && myrinfo->ed > 0 ? graph->vsize[i] : 0); + + myedegrees = myrinfo->edegrees; + myndegrees = myrinfo->ndegrees; + + for (k=0; k<myndegrees; k++) { + to = myedegrees[k].pid; + if (pwgts[to]+vwgt <= maxwgt[to]+ffactor*myedegrees[k].gv && xgain+myedegrees[k].gv >= 0) + break; + } + if (k == myndegrees) + continue; /* break out if you did not find a candidate */ + + for (j=k+1; j<myndegrees; j++) { + to = myedegrees[j].pid; + if (pwgts[to]+vwgt > maxwgt[to]) + continue; + if (myedegrees[j].gv > myedegrees[k].gv || + (myedegrees[j].gv == myedegrees[k].gv && myedegrees[j].ed > myedegrees[k].ed) || + (myedegrees[j].gv == myedegrees[k].gv && myedegrees[j].ed == myedegrees[k].ed && + itpwgts[myedegrees[k].pid]*pwgts[to] < itpwgts[to]*pwgts[myedegrees[k].pid])) + k = j; + } + + to = myedegrees[k].pid; + + j = 0; + if (xgain+myedegrees[k].gv > 0 || myedegrees[k].ed-myrinfo->id > 0) + j = 1; + else if (myedegrees[k].ed-myrinfo->id == 0) { + if ((iii&5) == 0 || pwgts[from] >= maxwgt[from] || itpwgts[from]*(pwgts[to]+vwgt) < itpwgts[to]*pwgts[from]) + j = 1; + } + if (j == 0) + continue; + + /*===================================================================== + * If we got here, we can now move the vertex from 'from' to 'to' + *======================================================================*/ + INC_DEC(pwgts[to], pwgts[from], vwgt); + graph->mincut -= myedegrees[k].ed-myrinfo->id; + graph->minvol -= (xgain+myedegrees[k].gv); + where[i] = to; + + IFSET(ctrl->dbglvl, DBG_MOVEINFO, printf("\t\tMoving %6d from %3d to %3d. Gain: [%4d %4d]. Cut: %6d, Vol: %6d\n", + i, from, to, xgain+myedegrees[k].gv, myedegrees[k].ed-myrinfo->id, graph->mincut, graph->minvol)); + + KWayVolUpdate(ctrl, graph, i, from, to, marker, phtable, updind); + + nmoves++; + + /* CheckVolKWayPartitionParams(ctrl, graph, nparts); */ + } + } + + IFSET(ctrl->dbglvl, DBG_REFINE, + printf("\t[%6d %6d], Balance: %5.3f, Nb: %6d. Nmoves: %5d, Cut: %6d, Vol: %6d\n", + pwgts[idxamin(nparts, pwgts)], pwgts[idxamax(nparts, pwgts)], + 1.0*nparts*pwgts[idxamax(nparts, pwgts)]/tvwgt, graph->nbnd, nmoves, graph->mincut, + graph->minvol)); + + if (graph->minvol == oldvol && graph->mincut == oldcut) + break; + } + + GKfree(&marker, &updind, &phtable, LTERM); + + idxwspacefree(ctrl, nparts); + idxwspacefree(ctrl, nparts); + idxwspacefree(ctrl, nparts); + idxwspacefree(ctrl, nvtxs); +} + + +/************************************************************************* +* This function performs k-way refinement +**************************************************************************/ +void Random_KWayVolRefineMConn(CtrlType *ctrl, GraphType *graph, int nparts, float *tpwgts, + float ubfactor, int npasses, int ffactor) +{ + int i, ii, iii, j, jj, k, kk, l, u, pass, nvtxs, nmoves, tvwgt, myndegrees, xgain; + int from, me, to, oldcut, oldvol, vwgt, nadd, maxndoms; + idxtype *xadj, *adjncy, *adjwgt; + idxtype *where, *pwgts, *perm, *bndptr, *bndind, *minwgt, *maxwgt, *itpwgts, *updind, *marker, *phtable; + idxtype *pmat, *pmatptr, *ndoms; + VEDegreeType *myedegrees; + VRInfoType *myrinfo; + + nvtxs = graph->nvtxs; + xadj = graph->xadj; + adjncy = graph->adjncy; + adjwgt = graph->adjwgt; + + bndptr = graph->bndptr; + bndind = graph->bndind; + + where = graph->where; + pwgts = graph->pwgts; + + /* Setup the weight intervals of the various subdomains */ + minwgt = idxwspacemalloc(ctrl, nparts); + maxwgt = idxwspacemalloc(ctrl, nparts); + itpwgts = idxwspacemalloc(ctrl, nparts); + tvwgt = idxsum(nparts, pwgts); + ASSERT(tvwgt == idxsum(nvtxs, graph->vwgt)); + + updind = idxmalloc(nvtxs, "Random_KWayVolRefine: updind"); + marker = idxsmalloc(nvtxs, 0, "Random_KWayVolRefine: marker"); + phtable = idxsmalloc(nparts, -1, "Random_KWayVolRefine: phtable"); + + pmat = ctrl->wspace.pmat; + ndoms = idxwspacemalloc(ctrl, nparts); + + ComputeVolSubDomainGraph(graph, nparts, pmat, ndoms); + + for (i=0; i<nparts; i++) { + itpwgts[i] = tpwgts[i]*tvwgt; + maxwgt[i] = tpwgts[i]*tvwgt*ubfactor; + minwgt[i] = tpwgts[i]*tvwgt*(1.0/ubfactor); + } + + perm = idxwspacemalloc(ctrl, nvtxs); + + IFSET(ctrl->dbglvl, DBG_REFINE, + printf("VolPart: [%5d %5d]-[%5d %5d], Balance: %3.2f, Nv-Nb[%5d %5d]. Cut: %5d, Vol: %5d\n", + pwgts[idxamin(nparts, pwgts)], pwgts[idxamax(nparts, pwgts)], minwgt[0], maxwgt[0], + 1.0*nparts*pwgts[idxamax(nparts, pwgts)]/tvwgt, graph->nvtxs, graph->nbnd, + graph->mincut, graph->minvol)); + + for (pass=0; pass<npasses; pass++) { + ASSERT(ComputeCut(graph, where) == graph->mincut); + + maxndoms = ndoms[idxamax(nparts, ndoms)]; + + oldcut = graph->mincut; + oldvol = graph->minvol; + + RandomPermute(graph->nbnd, perm, 1); + for (nmoves=iii=0; iii<graph->nbnd; iii++) { + ii = perm[iii]; + if (ii >= graph->nbnd) + continue; + i = bndind[ii]; + myrinfo = graph->vrinfo+i; + + if (myrinfo->gv >= 0) { /* Total volume gain is too high */ + from = where[i]; + vwgt = graph->vwgt[i]; + + if (myrinfo->id > 0 && pwgts[from]-vwgt < minwgt[from]) + continue; /* This cannot be moved! */ + + xgain = (myrinfo->id == 0 && myrinfo->ed > 0 ? graph->vsize[i] : 0); + + myedegrees = myrinfo->edegrees; + myndegrees = myrinfo->ndegrees; + + /* Determine the valid domains */ + for (j=0; j<myndegrees; j++) { + to = myedegrees[j].pid; + phtable[to] = 1; + pmatptr = pmat + to*nparts; + for (nadd=0, k=0; k<myndegrees; k++) { + if (k == j) + continue; + + l = myedegrees[k].pid; + if (pmatptr[l] == 0) { + if (ndoms[l] > maxndoms-1) { + phtable[to] = 0; + nadd = maxndoms; + break; + } + nadd++; + } + } + if (ndoms[to]+nadd > maxndoms) + phtable[to] = 0; + if (nadd == 0) + phtable[to] = 2; + } + + for (k=0; k<myndegrees; k++) { + to = myedegrees[k].pid; + if (!phtable[to]) + continue; + if (pwgts[to]+vwgt <= maxwgt[to]+ffactor*myedegrees[k].gv && xgain+myedegrees[k].gv >= 0) + break; + } + if (k == myndegrees) + continue; /* break out if you did not find a candidate */ + + for (j=k+1; j<myndegrees; j++) { + to = myedegrees[j].pid; + if (!phtable[to] || pwgts[to]+vwgt > maxwgt[to]) + continue; + if (myedegrees[j].gv > myedegrees[k].gv || + (myedegrees[j].gv == myedegrees[k].gv && myedegrees[j].ed > myedegrees[k].ed) || + (myedegrees[j].gv == myedegrees[k].gv && myedegrees[j].ed == myedegrees[k].ed && + itpwgts[myedegrees[k].pid]*pwgts[to] < itpwgts[to]*pwgts[myedegrees[k].pid])) + k = j; + } + + to = myedegrees[k].pid; + + j = 0; + if (xgain+myedegrees[k].gv > 0 || myedegrees[k].ed-myrinfo->id > 0) + j = 1; + else if (myedegrees[k].ed-myrinfo->id == 0) { + if ((iii&5) == 0 || phtable[myedegrees[k].pid] == 2 || pwgts[from] >= maxwgt[from] || itpwgts[from]*(pwgts[to]+vwgt) < itpwgts[to]*pwgts[from]) + j = 1; + } + + if (j == 0) + continue; + + for (j=0; j<myndegrees; j++) + phtable[myedegrees[j].pid] = -1; + + + /*===================================================================== + * If we got here, we can now move the vertex from 'from' to 'to' + *======================================================================*/ + INC_DEC(pwgts[to], pwgts[from], vwgt); + graph->mincut -= myedegrees[k].ed-myrinfo->id; + graph->minvol -= (xgain+myedegrees[k].gv); + where[i] = to; + + IFSET(ctrl->dbglvl, DBG_MOVEINFO, printf("\t\tMoving %6d from %3d to %3d. Gain: [%4d %4d]. Cut: %6d, Vol: %6d\n", + i, from, to, xgain+myedegrees[k].gv, myedegrees[k].ed-myrinfo->id, graph->mincut, graph->minvol)); + + /* Update pmat to reflect the move of 'i' */ + pmat[from*nparts+to] += (myrinfo->id-myedegrees[k].ed); + pmat[to*nparts+from] += (myrinfo->id-myedegrees[k].ed); + if (pmat[from*nparts+to] == 0) { + ndoms[from]--; + if (ndoms[from]+1 == maxndoms) + maxndoms = ndoms[idxamax(nparts, ndoms)]; + } + if (pmat[to*nparts+from] == 0) { + ndoms[to]--; + if (ndoms[to]+1 == maxndoms) + maxndoms = ndoms[idxamax(nparts, ndoms)]; + } + + for (j=xadj[i]; j<xadj[i+1]; j++) { + ii = adjncy[j]; + me = where[ii]; + + /* Update pmat to reflect the move of 'i' for domains other than 'from' and 'to' */ + if (me != from && me != to) { + pmat[me*nparts+from] -= adjwgt[j]; + pmat[from*nparts+me] -= adjwgt[j]; + if (pmat[me*nparts+from] == 0) { + ndoms[me]--; + if (ndoms[me]+1 == maxndoms) + maxndoms = ndoms[idxamax(nparts, ndoms)]; + } + if (pmat[from*nparts+me] == 0) { + ndoms[from]--; + if (ndoms[from]+1 == maxndoms) + maxndoms = ndoms[idxamax(nparts, ndoms)]; + } + + if (pmat[me*nparts+to] == 0) { + ndoms[me]++; + if (ndoms[me] > maxndoms) { + printf("You just increased the maxndoms: %d %d\n", ndoms[me], maxndoms); + maxndoms = ndoms[me]; + } + } + if (pmat[to*nparts+me] == 0) { + ndoms[to]++; + if (ndoms[to] > maxndoms) { + printf("You just increased the maxndoms: %d %d\n", ndoms[to], maxndoms); + maxndoms = ndoms[to]; + } + } + pmat[me*nparts+to] += adjwgt[j]; + pmat[to*nparts+me] += adjwgt[j]; + } + } + + KWayVolUpdate(ctrl, graph, i, from, to, marker, phtable, updind); + + nmoves++; + + /* CheckVolKWayPartitionParams(ctrl, graph, nparts); */ + } + } + + IFSET(ctrl->dbglvl, DBG_REFINE, + printf("\t[%6d %6d], Balance: %5.3f, Nb: %6d. Nmoves: %5d, Cut: %6d, Vol: %6d\n", + pwgts[idxamin(nparts, pwgts)], pwgts[idxamax(nparts, pwgts)], + 1.0*nparts*pwgts[idxamax(nparts, pwgts)]/tvwgt, graph->nbnd, nmoves, graph->mincut, + graph->minvol)); + + if (graph->minvol == oldvol && graph->mincut == oldcut) + break; + } + + GKfree(&marker, &updind, &phtable, LTERM); + + idxwspacefree(ctrl, nparts); + idxwspacefree(ctrl, nparts); + idxwspacefree(ctrl, nparts); + idxwspacefree(ctrl, nparts); + idxwspacefree(ctrl, nvtxs); +} + + + + +/************************************************************************* +* This function performs k-way refinement +**************************************************************************/ +void Greedy_KWayVolBalance(CtrlType *ctrl, GraphType *graph, int nparts, float *tpwgts, + float ubfactor, int npasses) +{ + int i, ii, iii, j, jj, k, kk, l, u, pass, nvtxs, nmoves, tvwgt, myndegrees, xgain; + int from, me, to, vwgt, gain; + idxtype *xadj, *adjncy, *adjwgt; + idxtype *where, *pwgts, *perm, *moved, *bndptr, *bndind, *minwgt, *maxwgt, *itpwgts, *updind, *marker, *phtable; + VEDegreeType *myedegrees; + VRInfoType *myrinfo; + PQueueType queue; + + nvtxs = graph->nvtxs; + xadj = graph->xadj; + adjncy = graph->adjncy; + adjwgt = graph->adjwgt; + + bndptr = graph->bndptr; + bndind = graph->bndind; + + where = graph->where; + pwgts = graph->pwgts; + + /* Setup the weight intervals of the various subdomains */ + minwgt = idxwspacemalloc(ctrl, nparts); + maxwgt = idxwspacemalloc(ctrl, nparts); + itpwgts = idxwspacemalloc(ctrl, nparts); + tvwgt = idxsum(nparts, pwgts); + ASSERT(tvwgt == idxsum(nvtxs, graph->vwgt)); + + updind = idxmalloc(nvtxs, "Random_KWayVolRefine: updind"); + marker = idxsmalloc(nvtxs, 0, "Random_KWayVolRefine: marker"); + phtable = idxsmalloc(nparts, -1, "Random_KWayVolRefine: phtable"); + + for (i=0; i<nparts; i++) { + itpwgts[i] = tpwgts[i]*tvwgt; + maxwgt[i] = tpwgts[i]*tvwgt*ubfactor; + minwgt[i] = tpwgts[i]*tvwgt*(1.0/ubfactor); + } + + perm = idxwspacemalloc(ctrl, nvtxs); + moved = idxwspacemalloc(ctrl, nvtxs); + + PQueueInit(ctrl, &queue, nvtxs, graph->adjwgtsum[idxamax(nvtxs, graph->adjwgtsum)]); + + IFSET(ctrl->dbglvl, DBG_REFINE, + printf("VolPart: [%5d %5d]-[%5d %5d], Balance: %3.2f, Nv-Nb[%5d %5d]. Cut: %5d, Vol: %5d [B]\n", + pwgts[idxamin(nparts, pwgts)], pwgts[idxamax(nparts, pwgts)], minwgt[0], maxwgt[0], + 1.0*nparts*pwgts[idxamax(nparts, pwgts)]/tvwgt, graph->nvtxs, graph->nbnd, + graph->mincut, graph->minvol)); + + + for (pass=0; pass<npasses; pass++) { + ASSERT(ComputeCut(graph, where) == graph->mincut); + /* Check to see if things are out of balance, given the tolerance */ + for (i=0; i<nparts; i++) { + if (pwgts[i] > maxwgt[i]) + break; + } + if (i == nparts) /* Things are balanced. Return right away */ + break; + + PQueueReset(&queue); + idxset(nvtxs, -1, moved); + + RandomPermute(graph->nbnd, perm, 1); + for (ii=0; ii<graph->nbnd; ii++) { + i = bndind[perm[ii]]; + PQueueInsert(&queue, i, graph->vrinfo[i].gv); + moved[i] = 2; + } + + for (nmoves=0;;) { + if ((i = PQueueGetMax(&queue)) == -1) + break; + moved[i] = 1; + + myrinfo = graph->vrinfo+i; + from = where[i]; + vwgt = graph->vwgt[i]; + + if (pwgts[from]-vwgt < minwgt[from]) + continue; /* This cannot be moved! */ + + xgain = (myrinfo->id == 0 && myrinfo->ed > 0 ? graph->vsize[i] : 0); + + myedegrees = myrinfo->edegrees; + myndegrees = myrinfo->ndegrees; + + for (k=0; k<myndegrees; k++) { + to = myedegrees[k].pid; + if (pwgts[to]+vwgt <= maxwgt[to] || + itpwgts[from]*(pwgts[to]+vwgt) <= itpwgts[to]*pwgts[from]) + break; + } + if (k == myndegrees) + continue; /* break out if you did not find a candidate */ + + for (j=k+1; j<myndegrees; j++) { + to = myedegrees[j].pid; + if (itpwgts[myedegrees[k].pid]*pwgts[to] < itpwgts[to]*pwgts[myedegrees[k].pid]) + k = j; + } + + to = myedegrees[k].pid; + + if (pwgts[from] < maxwgt[from] && pwgts[to] > minwgt[to] && + (xgain+myedegrees[k].gv < 0 || + (xgain+myedegrees[k].gv == 0 && myedegrees[k].ed-myrinfo->id < 0)) + ) + continue; + + + /*===================================================================== + * If we got here, we can now move the vertex from 'from' to 'to' + *======================================================================*/ + INC_DEC(pwgts[to], pwgts[from], vwgt); + graph->mincut -= myedegrees[k].ed-myrinfo->id; + graph->minvol -= (xgain+myedegrees[k].gv); + where[i] = to; + + IFSET(ctrl->dbglvl, DBG_MOVEINFO, printf("\t\tMoving %6d from %3d to %3d. Gain: [%4d %4d]. Cut: %6d, Vol: %6d\n", + i, from, to, xgain+myedegrees[k].gv, myedegrees[k].ed-myrinfo->id, graph->mincut, graph->minvol)); + + KWayVolUpdate(ctrl, graph, i, from, to, marker, phtable, updind); + + nmoves++; + + /*CheckVolKWayPartitionParams(ctrl, graph, nparts); */ + } + + IFSET(ctrl->dbglvl, DBG_REFINE, + printf("\t[%6d %6d], Balance: %5.3f, Nb: %6d. Nmoves: %5d, Cut: %6d, Vol: %6d\n", + pwgts[idxamin(nparts, pwgts)], pwgts[idxamax(nparts, pwgts)], + 1.0*nparts*pwgts[idxamax(nparts, pwgts)]/tvwgt, graph->nbnd, nmoves, graph->mincut, + graph->minvol)); + + } + + GKfree(&marker, &updind, &phtable, LTERM); + + PQueueFree(ctrl, &queue); + + idxwspacefree(ctrl, nparts); + idxwspacefree(ctrl, nparts); + idxwspacefree(ctrl, nparts); + idxwspacefree(ctrl, nvtxs); + idxwspacefree(ctrl, nvtxs); +} + + + +/************************************************************************* +* This function performs k-way refinement +**************************************************************************/ +void Greedy_KWayVolBalanceMConn(CtrlType *ctrl, GraphType *graph, int nparts, float *tpwgts, + float ubfactor, int npasses) +{ + int i, ii, iii, j, jj, k, kk, l, u, pass, nvtxs, nmoves, tvwgt, myndegrees, xgain; + int from, me, to, vwgt, gain, maxndoms, nadd; + idxtype *xadj, *adjncy, *adjwgt; + idxtype *where, *pwgts, *perm, *moved, *bndptr, *bndind, *minwgt, *maxwgt, *itpwgts, *updind, *marker, *phtable; + idxtype *pmat, *pmatptr, *ndoms; + VEDegreeType *myedegrees; + VRInfoType *myrinfo; + PQueueType queue; + + nvtxs = graph->nvtxs; + xadj = graph->xadj; + adjncy = graph->adjncy; + adjwgt = graph->adjwgt; + + bndptr = graph->bndptr; + bndind = graph->bndind; + + where = graph->where; + pwgts = graph->pwgts; + + /* Setup the weight intervals of the various subdomains */ + minwgt = idxwspacemalloc(ctrl, nparts); + maxwgt = idxwspacemalloc(ctrl, nparts); + itpwgts = idxwspacemalloc(ctrl, nparts); + tvwgt = idxsum(nparts, pwgts); + ASSERT(tvwgt == idxsum(nvtxs, graph->vwgt)); + + updind = idxmalloc(nvtxs, "Random_KWayVolRefine: updind"); + marker = idxsmalloc(nvtxs, 0, "Random_KWayVolRefine: marker"); + phtable = idxsmalloc(nparts, -1, "Random_KWayVolRefine: phtable"); + + pmat = ctrl->wspace.pmat; + ndoms = idxwspacemalloc(ctrl, nparts); + + ComputeVolSubDomainGraph(graph, nparts, pmat, ndoms); + + for (i=0; i<nparts; i++) { + itpwgts[i] = tpwgts[i]*tvwgt; + maxwgt[i] = tpwgts[i]*tvwgt*ubfactor; + minwgt[i] = tpwgts[i]*tvwgt*(1.0/ubfactor); + } + + perm = idxwspacemalloc(ctrl, nvtxs); + moved = idxwspacemalloc(ctrl, nvtxs); + + PQueueInit(ctrl, &queue, nvtxs, graph->adjwgtsum[idxamax(nvtxs, graph->adjwgtsum)]); + + IFSET(ctrl->dbglvl, DBG_REFINE, + printf("VolPart: [%5d %5d]-[%5d %5d], Balance: %3.2f, Nv-Nb[%5d %5d]. Cut: %5d, Vol: %5d [B]\n", + pwgts[idxamin(nparts, pwgts)], pwgts[idxamax(nparts, pwgts)], minwgt[0], maxwgt[0], + 1.0*nparts*pwgts[idxamax(nparts, pwgts)]/tvwgt, graph->nvtxs, graph->nbnd, + graph->mincut, graph->minvol)); + + + for (pass=0; pass<npasses; pass++) { + ASSERT(ComputeCut(graph, where) == graph->mincut); + /* Check to see if things are out of balance, given the tolerance */ + for (i=0; i<nparts; i++) { + if (pwgts[i] > maxwgt[i]) + break; + } + if (i == nparts) /* Things are balanced. Return right away */ + break; + + PQueueReset(&queue); + idxset(nvtxs, -1, moved); + + RandomPermute(graph->nbnd, perm, 1); + for (ii=0; ii<graph->nbnd; ii++) { + i = bndind[perm[ii]]; + PQueueInsert(&queue, i, graph->vrinfo[i].gv); + moved[i] = 2; + } + + maxndoms = ndoms[idxamax(nparts, ndoms)]; + + for (nmoves=0;;) { + if ((i = PQueueGetMax(&queue)) == -1) + break; + moved[i] = 1; + + myrinfo = graph->vrinfo+i; + from = where[i]; + vwgt = graph->vwgt[i]; + + if (pwgts[from]-vwgt < minwgt[from]) + continue; /* This cannot be moved! */ + + xgain = (myrinfo->id == 0 && myrinfo->ed > 0 ? graph->vsize[i] : 0); + + myedegrees = myrinfo->edegrees; + myndegrees = myrinfo->ndegrees; + + /* Determine the valid domains */ + for (j=0; j<myndegrees; j++) { + to = myedegrees[j].pid; + phtable[to] = 1; + pmatptr = pmat + to*nparts; + for (nadd=0, k=0; k<myndegrees; k++) { + if (k == j) + continue; + + l = myedegrees[k].pid; + if (pmatptr[l] == 0) { + if (ndoms[l] > maxndoms-1) { + phtable[to] = 0; + nadd = maxndoms; + break; + } + nadd++; + } + } + if (ndoms[to]+nadd > maxndoms) + phtable[to] = 0; + } + + for (k=0; k<myndegrees; k++) { + to = myedegrees[k].pid; + if (!phtable[to]) + continue; + if (pwgts[to]+vwgt <= maxwgt[to] || + itpwgts[from]*(pwgts[to]+vwgt) <= itpwgts[to]*pwgts[from]) + break; + } + if (k == myndegrees) + continue; /* break out if you did not find a candidate */ + + for (j=k+1; j<myndegrees; j++) { + to = myedegrees[j].pid; + if (!phtable[to]) + continue; + if (itpwgts[myedegrees[k].pid]*pwgts[to] < itpwgts[to]*pwgts[myedegrees[k].pid]) + k = j; + } + + to = myedegrees[k].pid; + + for (j=0; j<myndegrees; j++) + phtable[myedegrees[j].pid] = -1; + + if (pwgts[from] < maxwgt[from] && pwgts[to] > minwgt[to] && + (xgain+myedegrees[k].gv < 0 || + (xgain+myedegrees[k].gv == 0 && myedegrees[k].ed-myrinfo->id < 0)) + ) + continue; + + + /*===================================================================== + * If we got here, we can now move the vertex from 'from' to 'to' + *======================================================================*/ + INC_DEC(pwgts[to], pwgts[from], vwgt); + graph->mincut -= myedegrees[k].ed-myrinfo->id; + graph->minvol -= (xgain+myedegrees[k].gv); + where[i] = to; + + IFSET(ctrl->dbglvl, DBG_MOVEINFO, printf("\t\tMoving %6d from %3d to %3d. Gain: [%4d %4d]. Cut: %6d, Vol: %6d\n", + i, from, to, xgain+myedegrees[k].gv, myedegrees[k].ed-myrinfo->id, graph->mincut, graph->minvol)); + + /* Update pmat to reflect the move of 'i' */ + pmat[from*nparts+to] += (myrinfo->id-myedegrees[k].ed); + pmat[to*nparts+from] += (myrinfo->id-myedegrees[k].ed); + if (pmat[from*nparts+to] == 0) { + ndoms[from]--; + if (ndoms[from]+1 == maxndoms) + maxndoms = ndoms[idxamax(nparts, ndoms)]; + } + if (pmat[to*nparts+from] == 0) { + ndoms[to]--; + if (ndoms[to]+1 == maxndoms) + maxndoms = ndoms[idxamax(nparts, ndoms)]; + } + + for (j=xadj[i]; j<xadj[i+1]; j++) { + ii = adjncy[j]; + me = where[ii]; + + /* Update pmat to reflect the move of 'i' for domains other than 'from' and 'to' */ + if (me != from && me != to) { + pmat[me*nparts+from] -= adjwgt[j]; + pmat[from*nparts+me] -= adjwgt[j]; + if (pmat[me*nparts+from] == 0) { + ndoms[me]--; + if (ndoms[me]+1 == maxndoms) + maxndoms = ndoms[idxamax(nparts, ndoms)]; + } + if (pmat[from*nparts+me] == 0) { + ndoms[from]--; + if (ndoms[from]+1 == maxndoms) + maxndoms = ndoms[idxamax(nparts, ndoms)]; + } + + if (pmat[me*nparts+to] == 0) { + ndoms[me]++; + if (ndoms[me] > maxndoms) { + printf("You just increased the maxndoms: %d %d\n", ndoms[me], maxndoms); + maxndoms = ndoms[me]; + } + } + if (pmat[to*nparts+me] == 0) { + ndoms[to]++; + if (ndoms[to] > maxndoms) { + printf("You just increased the maxndoms: %d %d\n", ndoms[to], maxndoms); + maxndoms = ndoms[to]; + } + } + pmat[me*nparts+to] += adjwgt[j]; + pmat[to*nparts+me] += adjwgt[j]; + } + } + + KWayVolUpdate(ctrl, graph, i, from, to, marker, phtable, updind); + + nmoves++; + + /*CheckVolKWayPartitionParams(ctrl, graph, nparts); */ + } + + IFSET(ctrl->dbglvl, DBG_REFINE, + printf("\t[%6d %6d], Balance: %5.3f, Nb: %6d. Nmoves: %5d, Cut: %6d, Vol: %6d\n", + pwgts[idxamin(nparts, pwgts)], pwgts[idxamax(nparts, pwgts)], + 1.0*nparts*pwgts[idxamax(nparts, pwgts)]/tvwgt, graph->nbnd, nmoves, graph->mincut, + graph->minvol)); + + } + + GKfree(&marker, &updind, &phtable, LTERM); + + PQueueFree(ctrl, &queue); + + idxwspacefree(ctrl, nparts); + idxwspacefree(ctrl, nparts); + idxwspacefree(ctrl, nparts); + idxwspacefree(ctrl, nparts); + idxwspacefree(ctrl, nvtxs); + idxwspacefree(ctrl, nvtxs); +} + + + + +/************************************************************************* +* This function updates the edge and volume gains as a result of moving +* v from 'from' to 'to'. +* The working arrays marker and phtable are assumed to be initialized to +* -1, and they left to -1 upon return +**************************************************************************/ +void KWayVolUpdate(CtrlType *ctrl, GraphType *graph, int v, int from, int to, + idxtype *marker, idxtype *phtable, idxtype *updind) +{ + int ii, iii, j, jj, k, kk, l, u, nupd, other, me, myidx; + idxtype *xadj, *vsize, *adjncy, *adjwgt, *where; + VEDegreeType *myedegrees, *oedegrees; + VRInfoType *myrinfo, *orinfo; + + xadj = graph->xadj; + adjncy = graph->adjncy; + adjwgt = graph->adjwgt; + vsize = graph->vsize; + where = graph->where; + + myrinfo = graph->vrinfo+v; + myedegrees = myrinfo->edegrees; + + + /*====================================================================== + * Remove the contributions on the gain made by 'v'. + *=====================================================================*/ + for (k=0; k<myrinfo->ndegrees; k++) + phtable[myedegrees[k].pid] = k; + phtable[from] = k; + + myidx = phtable[to]; /* Keep track of the index in myedegrees of the 'to' domain */ + + for (j=xadj[v]; j<xadj[v+1]; j++) { + ii = adjncy[j]; + other = where[ii]; + orinfo = graph->vrinfo+ii; + oedegrees = orinfo->edegrees; + + if (other == from) { + for (k=0; k<orinfo->ndegrees; k++) { + if (phtable[oedegrees[k].pid] == -1) + oedegrees[k].gv += vsize[v]; + } + } + else { + ASSERT(phtable[other] != -1); + + if (myedegrees[phtable[other]].ned > 1) { + for (k=0; k<orinfo->ndegrees; k++) { + if (phtable[oedegrees[k].pid] == -1) + oedegrees[k].gv += vsize[v]; + } + } + else { /* There is only one connection */ + for (k=0; k<orinfo->ndegrees; k++) { + if (phtable[oedegrees[k].pid] != -1) + oedegrees[k].gv -= vsize[v]; + } + } + } + } + + for (k=0; k<myrinfo->ndegrees; k++) + phtable[myedegrees[k].pid] = -1; + phtable[from] = -1; + + + /*====================================================================== + * Update the id/ed of vertex 'v' + *=====================================================================*/ + myrinfo->ed += myrinfo->id-myedegrees[myidx].ed; + SWAP(myrinfo->id, myedegrees[myidx].ed, j); + SWAP(myrinfo->nid, myedegrees[myidx].ned, j); + if (myedegrees[myidx].ed == 0) + myedegrees[myidx] = myedegrees[--myrinfo->ndegrees]; + else + myedegrees[myidx].pid = from; + + /*====================================================================== + * Update the degrees of adjacent vertices and their volume gains + *=====================================================================*/ + marker[v] = 1; + updind[0] = v; + nupd = 1; + for (j=xadj[v]; j<xadj[v+1]; j++) { + ii = adjncy[j]; + me = where[ii]; + + if (!marker[ii]) { /* The marking is done for boundary and max gv calculations */ + marker[ii] = 2; + updind[nupd++] = ii; + } + + myrinfo = graph->vrinfo+ii; + if (myrinfo->edegrees == NULL) { + myrinfo->edegrees = ctrl->wspace.vedegrees+ctrl->wspace.cdegree; + ctrl->wspace.cdegree += xadj[ii+1]-xadj[ii]; + } + myedegrees = myrinfo->edegrees; + + if (me == from) { + INC_DEC(myrinfo->ed, myrinfo->id, adjwgt[j]); + myrinfo->nid--; + } + else if (me == to) { + INC_DEC(myrinfo->id, myrinfo->ed, adjwgt[j]); + myrinfo->nid++; + } + + /* Remove the edgeweight from the 'pid == from' entry of the vertex */ + if (me != from) { + for (k=0; k<myrinfo->ndegrees; k++) { + if (myedegrees[k].pid == from) { + if (myedegrees[k].ned == 1) { + myedegrees[k] = myedegrees[--myrinfo->ndegrees]; + marker[ii] = 1; /* You do a complete .gv calculation */ + + /* All vertices adjacent to 'ii' need to be updated */ + for (jj=xadj[ii]; jj<xadj[ii+1]; jj++) { + u = adjncy[jj]; + other = where[u]; + orinfo = graph->vrinfo+u; + oedegrees = orinfo->edegrees; + + for (kk=0; kk<orinfo->ndegrees; kk++) { + if (oedegrees[kk].pid == from) { + oedegrees[kk].gv -= vsize[ii]; + break; + } + } + } + } + else { + myedegrees[k].ed -= adjwgt[j]; + myedegrees[k].ned--; + + /* Update the gv due to single 'ii' connection to 'from' */ + if (myedegrees[k].ned == 1) { + /* find the vertex 'u' that 'ii' was connected into 'from' */ + for (jj=xadj[ii]; jj<xadj[ii+1]; jj++) { + u = adjncy[jj]; + other = where[u]; + orinfo = graph->vrinfo+u; + oedegrees = orinfo->edegrees; + + if (other == from) { + for (kk=0; kk<orinfo->ndegrees; kk++) + oedegrees[kk].gv += vsize[ii]; + break; + } + } + } + } + + break; + } + } + } + + /* Add the edgeweight to the 'pid == to' entry of the vertex */ + if (me != to) { + for (k=0; k<myrinfo->ndegrees; k++) { + if (myedegrees[k].pid == to) { + myedegrees[k].ed += adjwgt[j]; + myedegrees[k].ned++; + + /* Update the gv due to non-single 'ii' connection to 'to' */ + if (myedegrees[k].ned == 2) { + /* find the vertex 'u' that 'ii' was connected into 'to' */ + for (jj=xadj[ii]; jj<xadj[ii+1]; jj++) { + u = adjncy[jj]; + other = where[u]; + orinfo = graph->vrinfo+u; + oedegrees = orinfo->edegrees; + + if (u != v && other == to) { + for (kk=0; kk<orinfo->ndegrees; kk++) + oedegrees[kk].gv -= vsize[ii]; + break; + } + } + } + break; + } + } + + if (k == myrinfo->ndegrees) { + myedegrees[myrinfo->ndegrees].pid = to; + myedegrees[myrinfo->ndegrees].ed = adjwgt[j]; + myedegrees[myrinfo->ndegrees++].ned = 1; + marker[ii] = 1; /* You do a complete .gv calculation */ + + /* All vertices adjacent to 'ii' need to be updated */ + for (jj=xadj[ii]; jj<xadj[ii+1]; jj++) { + u = adjncy[jj]; + other = where[u]; + orinfo = graph->vrinfo+u; + oedegrees = orinfo->edegrees; + + for (kk=0; kk<orinfo->ndegrees; kk++) { + if (oedegrees[kk].pid == to) { + oedegrees[kk].gv += vsize[ii]; + if (!marker[u]) { /* Need to update boundary etc */ + marker[u] = 2; + updind[nupd++] = u; + } + break; + } + } + } + } + } + + ASSERT(myrinfo->ndegrees <= xadj[ii+1]-xadj[ii]); + } + + /*====================================================================== + * Add the contributions on the volume gain due to 'v' + *=====================================================================*/ + myrinfo = graph->vrinfo+v; + myedegrees = myrinfo->edegrees; + for (k=0; k<myrinfo->ndegrees; k++) + phtable[myedegrees[k].pid] = k; + phtable[to] = k; + + for (j=xadj[v]; j<xadj[v+1]; j++) { + ii = adjncy[j]; + other = where[ii]; + orinfo = graph->vrinfo+ii; + oedegrees = orinfo->edegrees; + + if (other == to) { + for (k=0; k<orinfo->ndegrees; k++) { + if (phtable[oedegrees[k].pid] == -1) + oedegrees[k].gv -= vsize[v]; + } + } + else { + ASSERT(phtable[other] != -1); + + if (myedegrees[phtable[other]].ned > 1) { + for (k=0; k<orinfo->ndegrees; k++) { + if (phtable[oedegrees[k].pid] == -1) + oedegrees[k].gv -= vsize[v]; + } + } + else { /* There is only one connection */ + for (k=0; k<orinfo->ndegrees; k++) { + if (phtable[oedegrees[k].pid] != -1) + oedegrees[k].gv += vsize[v]; + } + } + } + } + for (k=0; k<myrinfo->ndegrees; k++) + phtable[myedegrees[k].pid] = -1; + phtable[to] = -1; + + + /*====================================================================== + * Recompute the volume information of the 'hard' nodes, and update the + * max volume gain for all the update vertices + *=====================================================================*/ + ComputeKWayVolume(graph, nupd, updind, marker, phtable); + + + /*====================================================================== + * Maintain a consistent boundary + *=====================================================================*/ + for (j=0; j<nupd; j++) { + k = updind[j]; + marker[k] = 0; + myrinfo = graph->vrinfo+k; + + if ((myrinfo->gv >= 0 || myrinfo->ed-myrinfo->id >= 0) && graph->bndptr[k] == -1) + BNDInsert(graph->nbnd, graph->bndind, graph->bndptr, k); + + if (myrinfo->gv < 0 && myrinfo->ed-myrinfo->id < 0 && graph->bndptr[k] != -1) + BNDDelete(graph->nbnd, graph->bndind, graph->bndptr, k); + } + +} + + + + +/************************************************************************* +* This function computes the initial id/ed +**************************************************************************/ +void ComputeKWayVolume(GraphType *graph, int nupd, idxtype *updind, idxtype *marker, idxtype *phtable) +{ + int ii, iii, i, j, k, kk, l, nvtxs, me, other, pid; + idxtype *xadj, *vsize, *adjncy, *adjwgt, *where; + VRInfoType *rinfo, *myrinfo, *orinfo; + VEDegreeType *myedegrees, *oedegrees; + + nvtxs = graph->nvtxs; + xadj = graph->xadj; + vsize = graph->vsize; + adjncy = graph->adjncy; + adjwgt = graph->adjwgt; + where = graph->where; + rinfo = graph->vrinfo; + + + /*------------------------------------------------------------ + / Compute now the iv/ev degrees + /------------------------------------------------------------*/ + for (iii=0; iii<nupd; iii++) { + i = updind[iii]; + me = where[i]; + + myrinfo = rinfo+i; + myedegrees = myrinfo->edegrees; + + if (marker[i] == 1) { /* Only complete gain updates go through */ + for (k=0; k<myrinfo->ndegrees; k++) + myedegrees[k].gv = 0; + + for (j=xadj[i]; j<xadj[i+1]; j++) { + ii = adjncy[j]; + other = where[ii]; + orinfo = rinfo+ii; + oedegrees = orinfo->edegrees; + + for (kk=0; kk<orinfo->ndegrees; kk++) + phtable[oedegrees[kk].pid] = kk; + phtable[other] = 1; + + if (me == other) { + /* Find which domains 'i' is connected and 'ii' is not and update their gain */ + for (k=0; k<myrinfo->ndegrees; k++) { + if (phtable[myedegrees[k].pid] == -1) + myedegrees[k].gv -= vsize[ii]; + } + } + else { + ASSERT(phtable[me] != -1); + + /* I'm the only connection of 'ii' in 'me' */ + if (oedegrees[phtable[me]].ned == 1) { + /* Increase the gains for all the common domains between 'i' and 'ii' */ + for (k=0; k<myrinfo->ndegrees; k++) { + if (phtable[myedegrees[k].pid] != -1) + myedegrees[k].gv += vsize[ii]; + } + } + else { + /* Find which domains 'i' is connected and 'ii' is not and update their gain */ + for (k=0; k<myrinfo->ndegrees; k++) { + if (phtable[myedegrees[k].pid] == -1) + myedegrees[k].gv -= vsize[ii]; + } + } + } + + for (kk=0; kk<orinfo->ndegrees; kk++) + phtable[oedegrees[kk].pid] = -1; + phtable[other] = -1; + + } + } + + myrinfo->gv = -MAXIDX; + for (k=0; k<myrinfo->ndegrees; k++) { + if (myedegrees[k].gv > myrinfo->gv) + myrinfo->gv = myedegrees[k].gv; + } + if (myrinfo->ed > 0 && myrinfo->id == 0) + myrinfo->gv += vsize[i]; + + } + +} + + + +/************************************************************************* +* This function computes the total volume +**************************************************************************/ +int ComputeVolume(GraphType *graph, idxtype *where) +{ + int i, j, k, me, nvtxs, nparts, totalv; + idxtype *xadj, *adjncy, *vsize, *marker; + + + nvtxs = graph->nvtxs; + xadj = graph->xadj; + adjncy = graph->adjncy; + vsize = (graph->vsize == NULL ? graph->vwgt : graph->vsize); + + nparts = where[idxamax(nvtxs, where)]+1; + marker = idxsmalloc(nparts, -1, "ComputeVolume: marker"); + + totalv = 0; + + for (i=0; i<nvtxs; i++) { + marker[where[i]] = i; + for (j=xadj[i]; j<xadj[i+1]; j++) { + k = where[adjncy[j]]; + if (marker[k] != i) { + marker[k] = i; + totalv += vsize[i]; + } + } + } + + free(marker); + + return totalv; +} + + + + + +/************************************************************************* +* This function computes the initial id/ed +**************************************************************************/ +void CheckVolKWayPartitionParams(CtrlType *ctrl, GraphType *graph, int nparts) +{ + int i, ii, j, k, kk, l, nvtxs, nbnd, mincut, minvol, me, other, pid; + idxtype *xadj, *vsize, *adjncy, *adjwgt, *pwgts, *where, *bndind, *bndptr; + VRInfoType *rinfo, *myrinfo, *orinfo, tmprinfo; + VEDegreeType *myedegrees, *oedegrees, *tmpdegrees; + + nvtxs = graph->nvtxs; + xadj = graph->xadj; + vsize = graph->vsize; + adjncy = graph->adjncy; + adjwgt = graph->adjwgt; + where = graph->where; + rinfo = graph->vrinfo; + + tmpdegrees = (VEDegreeType *)GKmalloc(nparts*sizeof(VEDegreeType), "CheckVolKWayPartitionParams: tmpdegrees"); + + /*------------------------------------------------------------ + / Compute now the iv/ev degrees + /------------------------------------------------------------*/ + for (i=0; i<nvtxs; i++) { + me = where[i]; + + myrinfo = rinfo+i; + myedegrees = myrinfo->edegrees; + + for (k=0; k<myrinfo->ndegrees; k++) + tmpdegrees[k] = myedegrees[k]; + + tmprinfo.ndegrees = myrinfo->ndegrees; + tmprinfo.id = myrinfo->id; + tmprinfo.ed = myrinfo->ed; + + myrinfo = &tmprinfo; + myedegrees = tmpdegrees; + + + for (k=0; k<myrinfo->ndegrees; k++) + myedegrees[k].gv = 0; + + for (j=xadj[i]; j<xadj[i+1]; j++) { + ii = adjncy[j]; + other = where[ii]; + orinfo = rinfo+ii; + oedegrees = orinfo->edegrees; + + if (me == other) { + /* Find which domains 'i' is connected and 'ii' is not and update their gain */ + for (k=0; k<myrinfo->ndegrees; k++) { + pid = myedegrees[k].pid; + for (kk=0; kk<orinfo->ndegrees; kk++) { + if (oedegrees[kk].pid == pid) + break; + } + if (kk == orinfo->ndegrees) + myedegrees[k].gv -= vsize[ii]; + } + } + else { + /* Find the orinfo[me].ed and see if I'm the only connection */ + for (k=0; k<orinfo->ndegrees; k++) { + if (oedegrees[k].pid == me) + break; + } + + if (oedegrees[k].ned == 1) { /* I'm the only connection of 'ii' in 'me' */ + for (k=0; k<myrinfo->ndegrees; k++) { + if (myedegrees[k].pid == other) { + myedegrees[k].gv += vsize[ii]; + break; + } + } + + /* Increase the gains for all the common domains between 'i' and 'ii' */ + for (k=0; k<myrinfo->ndegrees; k++) { + if ((pid = myedegrees[k].pid) == other) + continue; + for (kk=0; kk<orinfo->ndegrees; kk++) { + if (oedegrees[kk].pid == pid) { + myedegrees[k].gv += vsize[ii]; + break; + } + } + } + + } + else { + /* Find which domains 'i' is connected and 'ii' is not and update their gain */ + for (k=0; k<myrinfo->ndegrees; k++) { + if ((pid = myedegrees[k].pid) == other) + continue; + for (kk=0; kk<orinfo->ndegrees; kk++) { + if (oedegrees[kk].pid == pid) + break; + } + if (kk == orinfo->ndegrees) + myedegrees[k].gv -= vsize[ii]; + } + } + } + } + + myrinfo = rinfo+i; + myedegrees = myrinfo->edegrees; + + for (k=0; k<myrinfo->ndegrees; k++) { + pid = myedegrees[k].pid; + for (kk=0; kk<tmprinfo.ndegrees; kk++) { + if (tmpdegrees[kk].pid == pid) { + if (tmpdegrees[kk].gv != myedegrees[k].gv) + printf("[%d %d %d %d]\n", i, pid, myedegrees[k].gv, tmpdegrees[kk].gv); + break; + } + } + } + + } + + free(tmpdegrees); + +} + + +/************************************************************************* +* This function computes the subdomain graph +**************************************************************************/ +void ComputeVolSubDomainGraph(GraphType *graph, int nparts, idxtype *pmat, idxtype *ndoms) +{ + int i, j, k, me, nvtxs, ndegrees; + idxtype *xadj, *adjncy, *adjwgt, *where; + VRInfoType *rinfo; + VEDegreeType *edegrees; + + nvtxs = graph->nvtxs; + xadj = graph->xadj; + adjncy = graph->adjncy; + adjwgt = graph->adjwgt; + where = graph->where; + rinfo = graph->vrinfo; + + idxset(nparts*nparts, 0, pmat); + + for (i=0; i<nvtxs; i++) { + if (rinfo[i].ed > 0) { + me = where[i]; + ndegrees = rinfo[i].ndegrees; + edegrees = rinfo[i].edegrees; + + k = me*nparts; + for (j=0; j<ndegrees; j++) + pmat[k+edegrees[j].pid] += edegrees[j].ed; + } + } + + for (i=0; i<nparts; i++) { + ndoms[i] = 0; + for (j=0; j<nparts; j++) { + if (pmat[i*nparts+j] > 0) + ndoms[i]++; + } + } +} + + + +/************************************************************************* +* This function computes the subdomain graph +**************************************************************************/ +void EliminateVolSubDomainEdges(CtrlType *ctrl, GraphType *graph, int nparts, float *tpwgts) +{ + int i, ii, j, k, me, other, nvtxs, total, max, avg, totalout, nind, ncand, ncand2, target, target2, nadd; + int min, move, cpwgt, tvwgt; + idxtype *xadj, *adjncy, *vwgt, *adjwgt, *pwgts, *where, *maxpwgt, *pmat, *ndoms, *mypmat, *otherpmat, *ind; + KeyValueType *cand, *cand2; + + nvtxs = graph->nvtxs; + xadj = graph->xadj; + adjncy = graph->adjncy; + vwgt = graph->vwgt; + adjwgt = graph->adjwgt; + + where = graph->where; + pwgts = idxset(nparts, 0, graph->pwgts); + + maxpwgt = idxwspacemalloc(ctrl, nparts); + ndoms = idxwspacemalloc(ctrl, nparts); + otherpmat = idxwspacemalloc(ctrl, nparts); + ind = idxwspacemalloc(ctrl, nvtxs); + pmat = idxset(nparts*nparts, 0, ctrl->wspace.pmat); + + cand = (KeyValueType *)GKmalloc(nparts*sizeof(KeyValueType), "EliminateSubDomainEdges: cand"); + cand2 = (KeyValueType *)GKmalloc(nparts*sizeof(KeyValueType), "EliminateSubDomainEdges: cand"); + + /* Compute the pmat matrix */ + for (i=0; i<nvtxs; i++) { + me = where[i]; + pwgts[me] += vwgt[i]; + for (j=xadj[i]; j<xadj[i+1]; j++) { + k = adjncy[j]; + if (where[k] != me) + pmat[me*nparts+where[k]] += adjwgt[j]; + } + } + + /* Compute the maximum allowed weight for each domain */ + tvwgt = idxsum(nparts, pwgts); + for (i=0; i<nparts; i++) + maxpwgt[i] = 1.25*tpwgts[i]*tvwgt; + + /* Determine the domain connectivity */ + for (i=0; i<nparts; i++) { + for (k=0, j=0; j<nparts; j++) { + if (pmat[i*nparts+j] > 0) + k++; + } + ndoms[i] = k; + } + + /* Get into the loop eliminating subdomain connections */ + for (;;) { + total = idxsum(nparts, ndoms); + avg = total/nparts; + max = ndoms[idxamax(nparts, ndoms)]; + + /* printf("Adjacent Subdomain Stats: Total: %3d, Max: %3d, Avg: %3d\n", total, max, avg); */ + + if (max < 1.5*avg) + break; + + me = idxamax(nparts, ndoms); + mypmat = pmat + me*nparts; + totalout = idxsum(nparts, mypmat); + + /*printf("Me: %d, TotalOut: %d,\n", me, totalout);*/ + + /* Sort the connections according to their cut */ + for (ncand2=0, i=0; i<nparts; i++) { + if (mypmat[i] > 0) { + cand2[ncand2].key = mypmat[i]; + cand2[ncand2++].val = i; + } + } + ikeysort(ncand2, cand2); + + move = 0; + for (min=0; min<ncand2; min++) { + if (cand2[min].key > totalout/(2*ndoms[me])) + break; + + other = cand2[min].val; + + /*printf("\tMinOut: %d to %d\n", mypmat[other], other);*/ + + idxset(nparts, 0, otherpmat); + + /* Go and find the vertices in 'other' that are connected in 'me' */ + for (nind=0, i=0; i<nvtxs; i++) { + if (where[i] == other) { + for (j=xadj[i]; j<xadj[i+1]; j++) { + if (where[adjncy[j]] == me) { + ind[nind++] = i; + break; + } + } + } + } + + /* Go and construct the otherpmat to see where these nind vertices are connected to */ + for (cpwgt=0, ii=0; ii<nind; ii++) { + i = ind[ii]; + cpwgt += vwgt[i]; + + for (j=xadj[i]; j<xadj[i+1]; j++) { + k = adjncy[j]; + if (where[k] != other) + otherpmat[where[k]] += adjwgt[j]; + } + } + + for (ncand=0, i=0; i<nparts; i++) { + if (otherpmat[i] > 0) { + cand[ncand].key = -otherpmat[i]; + cand[ncand++].val = i; + } + } + ikeysort(ncand, cand); + + /* + * Go through and the select the first domain that is common with 'me', and + * does not increase the ndoms[target] higher than my ndoms, subject to the + * maxpwgt constraint. Traversal is done from the mostly connected to the least. + */ + target = target2 = -1; + for (i=0; i<ncand; i++) { + k = cand[i].val; + + if (mypmat[k] > 0) { + if (pwgts[k] + cpwgt > maxpwgt[k]) /* Check if balance will go off */ + continue; + + for (j=0; j<nparts; j++) { + if (otherpmat[j] > 0 && ndoms[j] >= ndoms[me]-1 && pmat[nparts*j+k] == 0) + break; + } + if (j == nparts) { /* No bad second level effects */ + for (nadd=0, j=0; j<nparts; j++) { + if (otherpmat[j] > 0 && pmat[nparts*k+j] == 0) + nadd++; + } + + /*printf("\t\tto=%d, nadd=%d, %d\n", k, nadd, ndoms[k]);*/ + if (target2 == -1 && ndoms[k]+nadd < ndoms[me]) { + target2 = k; + } + if (nadd == 0) { + target = k; + break; + } + } + } + } + if (target == -1 && target2 != -1) + target = target2; + + if (target == -1) { + /* printf("\t\tCould not make the move\n");*/ + continue; + } + + /*printf("\t\tMoving to %d\n", target);*/ + + /* Update the partition weights */ + INC_DEC(pwgts[target], pwgts[other], cpwgt); + + /* Set all nind vertices to belong to 'target' */ + for (ii=0; ii<nind; ii++) { + i = ind[ii]; + where[i] = target; + + /* First remove any contribution that this vertex may have made */ + for (j=xadj[i]; j<xadj[i+1]; j++) { + k = adjncy[j]; + if (where[k] != other) { + if (pmat[nparts*other + where[k]] == 0) + printf("Something wrong\n"); + pmat[nparts*other + where[k]] -= adjwgt[j]; + if (pmat[nparts*other + where[k]] == 0) + ndoms[other]--; + + if (pmat[nparts*where[k] + other] == 0) + printf("Something wrong\n"); + pmat[nparts*where[k] + other] -= adjwgt[j]; + if (pmat[nparts*where[k] + other] == 0) + ndoms[where[k]]--; + } + } + + /* Next add the new contributions as a result of the move */ + for (j=xadj[i]; j<xadj[i+1]; j++) { + k = adjncy[j]; + if (where[k] != target) { + if (pmat[nparts*target + where[k]] == 0) + ndoms[target]++; + pmat[nparts*target + where[k]] += adjwgt[j]; + + if (pmat[nparts*where[k] + target] == 0) + ndoms[where[k]]++; + pmat[nparts*where[k] + target] += adjwgt[j]; + } + } + } + + move = 1; + break; + } + + if (move == 0) + break; + } + + idxwspacefree(ctrl, nparts); + idxwspacefree(ctrl, nparts); + idxwspacefree(ctrl, nparts); + idxwspacefree(ctrl, nvtxs); + + GKfree(&cand, &cand2, LTERM); +} + + + +/************************************************************************* +* This function finds all the connected components induced by the +* partitioning vector in wgraph->where and tries to push them around to +* remove some of them +**************************************************************************/ +void EliminateVolComponents(CtrlType *ctrl, GraphType *graph, int nparts, float *tpwgts, float ubfactor) +{ + int i, ii, j, jj, k, me, nvtxs, tvwgt, first, last, nleft, ncmps, cwgt, ncand, other, target, deltawgt; + idxtype *xadj, *adjncy, *vwgt, *adjwgt, *where, *pwgts, *maxpwgt; + idxtype *cpvec, *touched, *perm, *todo, *cind, *cptr, *npcmps; + KeyValueType *cand; + int recompute=0; + + nvtxs = graph->nvtxs; + xadj = graph->xadj; + adjncy = graph->adjncy; + vwgt = graph->vwgt; + adjwgt = graph->adjwgt; + + where = graph->where; + pwgts = idxset(nparts, 0, graph->pwgts); + + touched = idxset(nvtxs, 0, idxwspacemalloc(ctrl, nvtxs)); + cptr = idxwspacemalloc(ctrl, nvtxs); + cind = idxwspacemalloc(ctrl, nvtxs); + perm = idxwspacemalloc(ctrl, nvtxs); + todo = idxwspacemalloc(ctrl, nvtxs); + maxpwgt = idxwspacemalloc(ctrl, nparts); + cpvec = idxwspacemalloc(ctrl, nparts); + npcmps = idxset(nparts, 0, idxwspacemalloc(ctrl, nparts)); + + for (i=0; i<nvtxs; i++) + perm[i] = todo[i] = i; + + /* Find the connected componends induced by the partition */ + ncmps = -1; + first = last = 0; + nleft = nvtxs; + while (nleft > 0) { + if (first == last) { /* Find another starting vertex */ + cptr[++ncmps] = first; + ASSERT(touched[todo[0]] == 0); + i = todo[0]; + cind[last++] = i; + touched[i] = 1; + me = where[i]; + npcmps[me]++; + } + + i = cind[first++]; + k = perm[i]; + j = todo[k] = todo[--nleft]; + perm[j] = k; + + for (j=xadj[i]; j<xadj[i+1]; j++) { + k = adjncy[j]; + if (where[k] == me && !touched[k]) { + cind[last++] = k; + touched[k] = 1; + } + } + } + cptr[++ncmps] = first; + + /* printf("I found %d components, for this %d-way partition\n", ncmps, nparts); */ + + if (ncmps > nparts) { /* There are more components than processors */ + cand = (KeyValueType *)GKmalloc(nparts*sizeof(KeyValueType), "EliminateSubDomainEdges: cand"); + + /* First determine the partition sizes and max allowed load imbalance */ + for (i=0; i<nvtxs; i++) + pwgts[where[i]] += vwgt[i]; + tvwgt = idxsum(nparts, pwgts); + for (i=0; i<nparts; i++) + maxpwgt[i] = ubfactor*tpwgts[i]*tvwgt; + + deltawgt = tvwgt/(100*nparts); + deltawgt = 5; + + for (i=0; i<ncmps; i++) { + me = where[cind[cptr[i]]]; /* Get the domain of this component */ + if (npcmps[me] == 1) + continue; /* Skip it because it is contigous */ + + /*printf("Trying to move %d from %d\n", i, me); */ + + /* Determine the connectivity */ + idxset(nparts, 0, cpvec); + for (cwgt=0, j=cptr[i]; j<cptr[i+1]; j++) { + ii = cind[j]; + cwgt += vwgt[ii]; + for (jj=xadj[ii]; jj<xadj[ii+1]; jj++) { + other = where[adjncy[jj]]; + if (me != other) + cpvec[other] += adjwgt[jj]; + } + } + + /*printf("\tCmp weight: %d\n", cwgt);*/ + + if (cwgt > .30*pwgts[me]) + continue; /* Skip the component if it is over 30% of the weight */ + + for (ncand=0, j=0; j<nparts; j++) { + if (cpvec[j] > 0) { + cand[ncand].key = -cpvec[j]; + cand[ncand++].val = j; + } + } + if (ncand == 0) + continue; + + ikeysort(ncand, cand); + + target = -1; + for (j=0; j<ncand; j++) { + k = cand[j].val; + if (cwgt < deltawgt || pwgts[k] + cwgt < maxpwgt[k]) { + target = k; + break; + } + } + + /*printf("\tMoving it to %d [%d]\n", target, cpvec[target]);*/ + + if (target != -1) { + /* Assign all the vertices of 'me' to 'target' and update data structures */ + pwgts[me] -= cwgt; + pwgts[target] += cwgt; + npcmps[me]--; + + for (j=cptr[i]; j<cptr[i+1]; j++) + where[cind[j]] = target; + + graph->mincut -= cpvec[target]; + recompute = 1; + } + } + + free(cand); + } + + if (recompute) { + int ttlv; + idxtype *marker; + + marker = idxset(nparts, -1, cpvec); + for (ttlv=0, i=0; i<nvtxs; i++) { + marker[where[i]] = i; + for (j=xadj[i]; j<xadj[i+1]; j++) { + if (marker[where[adjncy[j]]] != i) { + ttlv += graph->vsize[i]; + marker[where[adjncy[j]]] = i; + } + } + } + graph->minvol = ttlv; + } + + idxwspacefree(ctrl, nparts); + idxwspacefree(ctrl, nparts); + idxwspacefree(ctrl, nparts); + idxwspacefree(ctrl, nvtxs); + idxwspacefree(ctrl, nvtxs); + idxwspacefree(ctrl, nvtxs); + idxwspacefree(ctrl, nvtxs); + idxwspacefree(ctrl, nvtxs); + +} + diff --git a/contrib/Metis/kwayvolrefine.c b/contrib/Metis/kwayvolrefine.c new file mode 100644 index 0000000000..4677b6bd17 --- /dev/null +++ b/contrib/Metis/kwayvolrefine.c @@ -0,0 +1,460 @@ +/* + * Copyright 1997, Regents of the University of Minnesota + * + * kwayvolrefine.c + * + * This file contains the driving routines for multilevel k-way refinement + * + * Started 7/28/97 + * George + * + * $Id: kwayvolrefine.c,v 1.1 2005-09-21 17:29:37 geuzaine Exp $ + */ + +#include <metis.h> + + +/************************************************************************* +* This function is the entry point of refinement +**************************************************************************/ +void RefineVolKWay(CtrlType *ctrl, GraphType *orggraph, GraphType *graph, int nparts, + float *tpwgts, float ubfactor) +{ + int i, nlevels; + GraphType *ptr; + + IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->UncoarsenTmr)); + + /* Take care any non-contiguity */ + if (ctrl->RType == RTYPE_KWAYRANDOM_MCONN) { + ComputeVolKWayPartitionParams(ctrl, graph, nparts); + EliminateVolComponents(ctrl, graph, nparts, tpwgts, 1.25); + EliminateVolSubDomainEdges(ctrl, graph, nparts, tpwgts); + EliminateVolComponents(ctrl, graph, nparts, tpwgts, 1.25); + } + + + /* Determine how many levels are there */ + for (ptr=graph, nlevels=0; ptr!=orggraph; ptr=ptr->finer, nlevels++); + + /* Compute the parameters of the coarsest graph */ + ComputeVolKWayPartitionParams(ctrl, graph, nparts); + + for (i=0; ;i++) { + /*PrintSubDomainGraph(graph, nparts, graph->where);*/ + MALLOC_CHECK(NULL); + IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->RefTmr)); + + if (2*i >= nlevels && !IsBalanced(graph->pwgts, nparts, tpwgts, 1.04*ubfactor)) { + ComputeVolKWayBalanceBoundary(ctrl, graph, nparts); + switch (ctrl->RType) { + case RTYPE_KWAYRANDOM: + Greedy_KWayVolBalance(ctrl, graph, nparts, tpwgts, ubfactor, 1); + break; + case RTYPE_KWAYRANDOM_MCONN: + Greedy_KWayVolBalanceMConn(ctrl, graph, nparts, tpwgts, ubfactor, 1); + break; + } + ComputeVolKWayBoundary(ctrl, graph, nparts); + } + + switch (ctrl->RType) { + case RTYPE_KWAYRANDOM: + Random_KWayVolRefine(ctrl, graph, nparts, tpwgts, ubfactor, 10, 0); + break; + case RTYPE_KWAYRANDOM_MCONN: + Random_KWayVolRefineMConn(ctrl, graph, nparts, tpwgts, ubfactor, 10, 0); + break; + } + IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->RefTmr)); + + if (graph == orggraph) + break; + + GKfree(&graph->gdata, LTERM); /* Deallocate the graph related arrays */ + + graph = graph->finer; + + IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->ProjectTmr)); + ProjectVolKWayPartition(ctrl, graph, nparts); + IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->ProjectTmr)); + } + + if (!IsBalanced(graph->pwgts, nparts, tpwgts, ubfactor)) { + ComputeVolKWayBalanceBoundary(ctrl, graph, nparts); + switch (ctrl->RType) { + case RTYPE_KWAYRANDOM: + Greedy_KWayVolBalance(ctrl, graph, nparts, tpwgts, ubfactor, 8); + Random_KWayVolRefine(ctrl, graph, nparts, tpwgts, ubfactor, 10, 0); + break; + case RTYPE_KWAYRANDOM_MCONN: + Greedy_KWayVolBalanceMConn(ctrl, graph, nparts, tpwgts, ubfactor, 8); + Random_KWayVolRefineMConn(ctrl, graph, nparts, tpwgts, ubfactor, 10, 0); + break; + } + } + + EliminateVolComponents(ctrl, graph, nparts, tpwgts, ubfactor); + + IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->UncoarsenTmr)); +} + + + +/************************************************************************* +* This function allocates memory for k-way edge refinement +**************************************************************************/ +void AllocateVolKWayPartitionMemory(CtrlType *ctrl, GraphType *graph, int nparts) +{ + int nvtxs, pad64; + + nvtxs = graph->nvtxs; + + pad64 = (3*nvtxs+nparts)%2; + + graph->rdata = idxmalloc(3*nvtxs+nparts+(sizeof(VRInfoType)/sizeof(idxtype))*nvtxs+pad64, "AllocateVolKWayPartitionMemory: rdata"); + graph->pwgts = graph->rdata; + graph->where = graph->rdata + nparts; + graph->bndptr = graph->rdata + nvtxs + nparts; + graph->bndind = graph->rdata + 2*nvtxs + nparts; + graph->vrinfo = (VRInfoType *)(graph->rdata + 3*nvtxs+nparts + pad64); + +} + + + +/************************************************************************* +* This function computes the initial id/ed +**************************************************************************/ +void ComputeVolKWayPartitionParams(CtrlType *ctrl, GraphType *graph, int nparts) +{ + int i, ii, j, k, kk, l, nvtxs, nbnd, mincut, minvol, me, other, pid; + idxtype *xadj, *vwgt, *adjncy, *adjwgt, *pwgts, *where; + VRInfoType *rinfo, *myrinfo, *orinfo; + VEDegreeType *myedegrees, *oedegrees; + + nvtxs = graph->nvtxs; + xadj = graph->xadj; + vwgt = graph->vwgt; + adjncy = graph->adjncy; + adjwgt = graph->adjwgt; + + where = graph->where; + pwgts = idxset(nparts, 0, graph->pwgts); + rinfo = graph->vrinfo; + + + /*------------------------------------------------------------ + / Compute now the id/ed degrees + /------------------------------------------------------------*/ + ctrl->wspace.cdegree = 0; + mincut = 0; + for (i=0; i<nvtxs; i++) { + me = where[i]; + pwgts[me] += vwgt[i]; + + myrinfo = rinfo+i; + myrinfo->id = myrinfo->ed = myrinfo->nid = myrinfo->ndegrees = 0; + myrinfo->edegrees = NULL; + + for (j=xadj[i]; j<xadj[i+1]; j++) { + if (me == where[adjncy[j]]) { + myrinfo->id += adjwgt[j]; + myrinfo->nid++; + } + } + myrinfo->ed = graph->adjwgtsum[i] - myrinfo->id; + + mincut += myrinfo->ed; + + /* Time to compute the particular external degrees */ + if (myrinfo->ed > 0) { + myedegrees = myrinfo->edegrees = ctrl->wspace.vedegrees+ctrl->wspace.cdegree; + ctrl->wspace.cdegree += xadj[i+1]-xadj[i]; + + for (j=xadj[i]; j<xadj[i+1]; j++) { + other = where[adjncy[j]]; + if (me != other) { + for (k=0; k<myrinfo->ndegrees; k++) { + if (myedegrees[k].pid == other) { + myedegrees[k].ed += adjwgt[j]; + myedegrees[k].ned++; + break; + } + } + if (k == myrinfo->ndegrees) { + myedegrees[myrinfo->ndegrees].gv = 0; + myedegrees[myrinfo->ndegrees].pid = other; + myedegrees[myrinfo->ndegrees].ed = adjwgt[j]; + myedegrees[myrinfo->ndegrees++].ned = 1; + } + } + } + + ASSERT(myrinfo->ndegrees <= xadj[i+1]-xadj[i]); + } + } + graph->mincut = mincut/2; + + + ComputeKWayVolGains(ctrl, graph, nparts); + +} + + + +/************************************************************************* +* This function computes the initial id/ed +**************************************************************************/ +void ComputeKWayVolGains(CtrlType *ctrl, GraphType *graph, int nparts) +{ + int i, ii, j, k, kk, l, nvtxs, me, other, pid, myndegrees; + idxtype *xadj, *vsize, *adjncy, *adjwgt, *where, *bndind, *bndptr, *ophtable; + VRInfoType *rinfo, *myrinfo, *orinfo; + VEDegreeType *myedegrees, *oedegrees; + + nvtxs = graph->nvtxs; + xadj = graph->xadj; + vsize = graph->vsize; + adjncy = graph->adjncy; + adjwgt = graph->adjwgt; + + where = graph->where; + bndind = graph->bndind; + bndptr = idxset(nvtxs, -1, graph->bndptr); + rinfo = graph->vrinfo; + + ophtable = idxset(nparts, -1, idxwspacemalloc(ctrl, nparts)); + + /*------------------------------------------------------------ + / Compute now the iv/ev degrees + /------------------------------------------------------------*/ + graph->minvol = graph->nbnd = 0; + for (i=0; i<nvtxs; i++) { + myrinfo = rinfo+i; + myrinfo->gv = -MAXIDX; + + if (myrinfo->ndegrees > 0) { + me = where[i]; + myedegrees = myrinfo->edegrees; + myndegrees = myrinfo->ndegrees; + + graph->minvol += myndegrees*vsize[i]; + + for (j=xadj[i]; j<xadj[i+1]; j++) { + ii = adjncy[j]; + other = where[ii]; + orinfo = rinfo+ii; + oedegrees = orinfo->edegrees; + + for (k=0; k<orinfo->ndegrees; k++) + ophtable[oedegrees[k].pid] = k; + ophtable[other] = 1; /* this is to simplify coding */ + + if (me == other) { + /* Find which domains 'i' is connected and 'ii' is not and update their gain */ + for (k=0; k<myndegrees; k++) { + if (ophtable[myedegrees[k].pid] == -1) + myedegrees[k].gv -= vsize[ii]; + } + } + else { + ASSERT(ophtable[me] != -1); + + if (oedegrees[ophtable[me]].ned == 1) { /* I'm the only connection of 'ii' in 'me' */ + /* Increase the gains for all the common domains between 'i' and 'ii' */ + for (k=0; k<myndegrees; k++) { + if (ophtable[myedegrees[k].pid] != -1) + myedegrees[k].gv += vsize[ii]; + } + } + else { + /* Find which domains 'i' is connected and 'ii' is not and update their gain */ + for (k=0; k<myndegrees; k++) { + if (ophtable[myedegrees[k].pid] == -1) + myedegrees[k].gv -= vsize[ii]; + } + } + } + + for (kk=0; kk<orinfo->ndegrees; kk++) + ophtable[oedegrees[kk].pid] = -1; + ophtable[other] = -1; + } + + /* Compute the max vgain */ + for (k=0; k<myndegrees; k++) { + if (myedegrees[k].gv > myrinfo->gv) + myrinfo->gv = myedegrees[k].gv; + } + } + + if (myrinfo->ed > 0 && myrinfo->id == 0) + myrinfo->gv += vsize[i]; + + if (myrinfo->gv >= 0 || myrinfo->ed-myrinfo->id >= 0) + BNDInsert(graph->nbnd, bndind, bndptr, i); + } + + idxwspacefree(ctrl, nparts); + +} + + + +/************************************************************************* +* This function projects a partition, and at the same time computes the +* parameters for refinement. +**************************************************************************/ +void ProjectVolKWayPartition(CtrlType *ctrl, GraphType *graph, int nparts) +{ + int i, j, k, nvtxs, me, other, istart, iend, ndegrees; + idxtype *xadj, *adjncy, *adjwgt, *adjwgtsum; + idxtype *cmap, *where; + idxtype *cwhere; + GraphType *cgraph; + VRInfoType *crinfo, *rinfo, *myrinfo; + VEDegreeType *myedegrees; + idxtype *htable; + + cgraph = graph->coarser; + cwhere = cgraph->where; + crinfo = cgraph->vrinfo; + + nvtxs = graph->nvtxs; + cmap = graph->cmap; + xadj = graph->xadj; + adjncy = graph->adjncy; + adjwgt = graph->adjwgt; + adjwgtsum = graph->adjwgtsum; + + AllocateVolKWayPartitionMemory(ctrl, graph, nparts); + where = graph->where; + rinfo = graph->vrinfo; + + /* Go through and project partition and compute id/ed for the nodes */ + for (i=0; i<nvtxs; i++) { + k = cmap[i]; + where[i] = cwhere[k]; + cmap[i] = crinfo[k].ed; /* For optimization */ + } + + htable = idxset(nparts, -1, idxwspacemalloc(ctrl, nparts)); + + ctrl->wspace.cdegree = 0; + for (i=0; i<nvtxs; i++) { + me = where[i]; + + myrinfo = rinfo+i; + myrinfo->id = myrinfo->ed = myrinfo->nid = myrinfo->ndegrees = 0; + myrinfo->edegrees = NULL; + + myrinfo->id = adjwgtsum[i]; + myrinfo->nid = xadj[i+1]-xadj[i]; + + if (cmap[i] > 0) { /* If it is an interface node. Note cmap[i] = crinfo[cmap[i]].ed */ + istart = xadj[i]; + iend = xadj[i+1]; + + myedegrees = myrinfo->edegrees = ctrl->wspace.vedegrees+ctrl->wspace.cdegree; + ctrl->wspace.cdegree += iend-istart; + + ndegrees = 0; + for (j=istart; j<iend; j++) { + other = where[adjncy[j]]; + if (me != other) { + myrinfo->ed += adjwgt[j]; + myrinfo->nid--; + if ((k = htable[other]) == -1) { + htable[other] = ndegrees; + myedegrees[ndegrees].gv = 0; + myedegrees[ndegrees].pid = other; + myedegrees[ndegrees].ed = adjwgt[j]; + myedegrees[ndegrees++].ned = 1; + } + else { + myedegrees[k].ed += adjwgt[j]; + myedegrees[k].ned++; + } + } + } + myrinfo->id -= myrinfo->ed; + + /* Remove space for edegrees if it was interior */ + if (myrinfo->ed == 0) { + myrinfo->edegrees = NULL; + ctrl->wspace.cdegree -= iend-istart; + } + else { + myrinfo->ndegrees = ndegrees; + + for (j=0; j<ndegrees; j++) + htable[myedegrees[j].pid] = -1; + } + } + } + + ComputeKWayVolGains(ctrl, graph, nparts); + + idxcopy(nparts, cgraph->pwgts, graph->pwgts); + graph->mincut = cgraph->mincut; + + FreeGraph(graph->coarser); + graph->coarser = NULL; + + idxwspacefree(ctrl, nparts); + +} + + + +/************************************************************************* +* This function computes the boundary definition for balancing +**************************************************************************/ +void ComputeVolKWayBoundary(CtrlType *ctrl, GraphType *graph, int nparts) +{ + int i, nvtxs, nbnd; + idxtype *bndind, *bndptr; + + nvtxs = graph->nvtxs; + bndind = graph->bndind; + bndptr = idxset(nvtxs, -1, graph->bndptr); + + + /*------------------------------------------------------------ + / Compute the new boundary + /------------------------------------------------------------*/ + nbnd = 0; + for (i=0; i<nvtxs; i++) { + if (graph->vrinfo[i].gv >=0 || graph->vrinfo[i].ed-graph->vrinfo[i].id >= 0) + BNDInsert(nbnd, bndind, bndptr, i); + } + + graph->nbnd = nbnd; +} + +/************************************************************************* +* This function computes the boundary definition for balancing +**************************************************************************/ +void ComputeVolKWayBalanceBoundary(CtrlType *ctrl, GraphType *graph, int nparts) +{ + int i, nvtxs, nbnd; + idxtype *bndind, *bndptr; + + nvtxs = graph->nvtxs; + bndind = graph->bndind; + bndptr = idxset(nvtxs, -1, graph->bndptr); + + + /*------------------------------------------------------------ + / Compute the new boundary + /------------------------------------------------------------*/ + nbnd = 0; + for (i=0; i<nvtxs; i++) { + if (graph->vrinfo[i].ed > 0) + BNDInsert(nbnd, bndind, bndptr, i); + } + + graph->nbnd = nbnd; +} + diff --git a/contrib/Metis/macros.h b/contrib/Metis/macros.h new file mode 100644 index 0000000000..8151e10b41 --- /dev/null +++ b/contrib/Metis/macros.h @@ -0,0 +1,143 @@ +/* + * Copyright 1997, Regents of the University of Minnesota + * + * macros.h + * + * This file contains macros used in multilevel + * + * Started 9/25/94 + * George + * + * $Id: macros.h,v 1.1 2005-09-21 17:29:38 geuzaine Exp $ + * + */ + + +/************************************************************************* +* The following macro returns a random number in the specified range +**************************************************************************/ +#ifdef __VC__ +#define RandomInRange(u) ((rand()>>3)%(u)) +#define RandomInRangeFast(u) ((rand()>>3)%(u)) +#else +#define RandomInRange(u) ((int)(drand48()*((double)(u)))) +#define RandomInRangeFast(u) ((rand()>>3)%(u)) +#endif + + + +#define amax(a, b) ((a) >= (b) ? (a) : (b)) +#define amin(a, b) ((a) >= (b) ? (b) : (a)) + +#define AND(a, b) ((a) < 0 ? ((-(a))&(b)) : ((a)&(b))) +#define OR(a, b) ((a) < 0 ? -((-(a))|(b)) : ((a)|(b))) +#define XOR(a, b) ((a) < 0 ? -((-(a))^(b)) : ((a)^(b))) + +#define SWAP(a, b, tmp) \ + do {(tmp) = (a); (a) = (b); (b) = (tmp);} while(0) + +#define INC_DEC(a, b, val) \ + do {(a) += (val); (b) -= (val);} while(0) + + +#define scopy(n, a, b) (float *)memcpy((void *)(b), (void *)(a), sizeof(float)*(n)) +#define idxcopy(n, a, b) (idxtype *)memcpy((void *)(b), (void *)(a), sizeof(idxtype)*(n)) + +#define HASHFCT(key, size) ((key)%(size)) + + +/************************************************************************* +* Timer macros +**************************************************************************/ +#define cleartimer(tmr) (tmr = 0.0) +#define starttimer(tmr) (tmr -= seconds()) +#define stoptimer(tmr) (tmr += seconds()) +#define gettimer(tmr) (tmr) + + +/************************************************************************* +* This macro is used to handle dbglvl +**************************************************************************/ +#define IFSET(a, flag, cmd) if ((a)&(flag)) (cmd); + +/************************************************************************* +* These macros are used for debuging memory leaks +**************************************************************************/ +#ifdef DMALLOC +#define imalloc(n, msg) (malloc(sizeof(int)*(n))) +#define fmalloc(n, msg) (malloc(sizeof(float)*(n))) +#define idxmalloc(n, msg) (malloc(sizeof(idxtype)*(n))) +#define ismalloc(n, val, msg) (iset((n), (val), malloc(sizeof(int)*(n)))) +#define idxsmalloc(n, val, msg) (idxset((n), (val), malloc(sizeof(idxtype)*(n)))) +#define GKmalloc(a, b) (malloc((a))) +#endif + +#ifdef DMALLOC +# define MALLOC_CHECK(ptr) \ + if (malloc_verify((ptr)) == DMALLOC_VERIFY_ERROR) { \ + printf("***MALLOC_CHECK failed on line %d of file %s: " #ptr "\n", \ + __LINE__, __FILE__); \ + abort(); \ + } +#else +# define MALLOC_CHECK(ptr) ; +#endif + + + +/************************************************************************* +* This macro converts a length array in a CSR one +**************************************************************************/ +#define MAKECSR(i, n, a) \ + do { \ + for (i=1; i<n; i++) a[i] += a[i-1]; \ + for (i=n; i>0; i--) a[i] = a[i-1]; \ + a[0] = 0; \ + } while(0) + + +/************************************************************************* +* These macros insert and remove nodes from the boundary list +**************************************************************************/ +#define BNDInsert(nbnd, bndind, bndptr, vtx) \ + do { \ + ASSERT(bndptr[vtx] == -1); \ + bndind[nbnd] = vtx; \ + bndptr[vtx] = nbnd++;\ + } while(0) + +#define BNDDelete(nbnd, bndind, bndptr, vtx) \ + do { \ + ASSERT(bndptr[vtx] != -1); \ + bndind[bndptr[vtx]] = bndind[--nbnd]; \ + bndptr[bndind[nbnd]] = bndptr[vtx]; \ + bndptr[vtx] = -1; \ + } while(0) + + + +/************************************************************************* +* These are debugging macros +**************************************************************************/ +#ifdef DEBUG +# define ASSERT(expr) \ + if (!(expr)) { \ + printf("***ASSERTION failed on line %d of file %s: " #expr "\n", \ + __LINE__, __FILE__); \ + abort(); \ + } +#else +# define ASSERT(expr) ; +#endif + +#ifdef DEBUG +# define ASSERTP(expr, msg) \ + if (!(expr)) { \ + printf("***ASSERTION failed on line %d of file %s: " #expr "\n", \ + __LINE__, __FILE__); \ + printf msg ; \ + abort(); \ + } +#else +# define ASSERTP(expr, msg) ; +#endif diff --git a/contrib/Metis/match.c b/contrib/Metis/match.c new file mode 100644 index 0000000000..0896fe5cf0 --- /dev/null +++ b/contrib/Metis/match.c @@ -0,0 +1,267 @@ +/* + * Copyright 1997, Regents of the University of Minnesota + * + * match.c + * + * This file contains the code that computes matchings and creates the next + * level coarse graph. + * + * Started 7/23/97 + * George + * + * $Id: match.c,v 1.1 2005-09-21 17:29:38 geuzaine Exp $ + * + */ + +#include <metis.h> + + +/************************************************************************* +* This function finds a matching using the HEM heuristic +**************************************************************************/ +void Match_RM(CtrlType *ctrl, GraphType *graph) +{ + int i, ii, j, nvtxs, cnvtxs, maxidx; + idxtype *xadj, *vwgt, *adjncy, *adjwgt; + idxtype *match, *cmap, *perm; + + IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->MatchTmr)); + + nvtxs = graph->nvtxs; + xadj = graph->xadj; + vwgt = graph->vwgt; + adjncy = graph->adjncy; + adjwgt = graph->adjwgt; + + cmap = graph->cmap; + match = idxset(nvtxs, UNMATCHED, idxwspacemalloc(ctrl, nvtxs)); + + perm = idxwspacemalloc(ctrl, nvtxs); + RandomPermute(nvtxs, perm, 1); + + cnvtxs = 0; + for (ii=0; ii<nvtxs; ii++) { + i = perm[ii]; + + if (match[i] == UNMATCHED) { /* Unmatched */ + maxidx = i; + + /* Find a random matching, subject to maxvwgt constraints */ + for (j=xadj[i]; j<xadj[i+1]; j++) { + if (match[adjncy[j]] == UNMATCHED && vwgt[i]+vwgt[adjncy[j]] <= ctrl->maxvwgt) { + maxidx = adjncy[j]; + break; + } + } + + cmap[i] = cmap[maxidx] = cnvtxs++; + match[i] = maxidx; + match[maxidx] = i; + } + } + + IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->MatchTmr)); + + CreateCoarseGraph(ctrl, graph, cnvtxs, match, perm); + + idxwspacefree(ctrl, nvtxs); + idxwspacefree(ctrl, nvtxs); +} + + +/************************************************************************* +* This function finds a matching using the HEM heuristic +**************************************************************************/ +void Match_RM_NVW(CtrlType *ctrl, GraphType *graph) +{ + int i, ii, j, nvtxs, cnvtxs, maxidx; + idxtype *xadj, *adjncy; + idxtype *match, *cmap, *perm; + + IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->MatchTmr)); + + nvtxs = graph->nvtxs; + xadj = graph->xadj; + adjncy = graph->adjncy; + + cmap = graph->cmap; + match = idxset(nvtxs, UNMATCHED, idxwspacemalloc(ctrl, nvtxs)); + + perm = idxwspacemalloc(ctrl, nvtxs); + RandomPermute(nvtxs, perm, 1); + + cnvtxs = 0; + for (ii=0; ii<nvtxs; ii++) { + i = perm[ii]; + + if (match[i] == UNMATCHED) { /* Unmatched */ + maxidx = i; + + /* Find a random matching, subject to maxvwgt constraints */ + for (j=xadj[i]; j<xadj[i+1]; j++) { + if (match[adjncy[j]] == UNMATCHED) { + maxidx = adjncy[j]; + break; + } + } + + cmap[i] = cmap[maxidx] = cnvtxs++; + match[i] = maxidx; + match[maxidx] = i; + } + } + + IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->MatchTmr)); + + CreateCoarseGraph_NVW(ctrl, graph, cnvtxs, match, perm); + + idxwspacefree(ctrl, nvtxs); + idxwspacefree(ctrl, nvtxs); +} + + + +/************************************************************************* +* This function finds a matching using the HEM heuristic +**************************************************************************/ +void Match_HEM(CtrlType *ctrl, GraphType *graph) +{ + int i, ii, j, k, nvtxs, cnvtxs, maxidx, maxwgt; + idxtype *xadj, *vwgt, *adjncy, *adjwgt; + idxtype *match, *cmap, *perm; + + IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->MatchTmr)); + + nvtxs = graph->nvtxs; + xadj = graph->xadj; + vwgt = graph->vwgt; + adjncy = graph->adjncy; + adjwgt = graph->adjwgt; + + cmap = graph->cmap; + match = idxset(nvtxs, UNMATCHED, idxwspacemalloc(ctrl, nvtxs)); + + perm = idxwspacemalloc(ctrl, nvtxs); + RandomPermute(nvtxs, perm, 1); + + cnvtxs = 0; + for (ii=0; ii<nvtxs; ii++) { + i = perm[ii]; + + if (match[i] == UNMATCHED) { /* Unmatched */ + maxidx = i; + maxwgt = 0; + + /* Find a heavy-edge matching, subject to maxvwgt constraints */ + for (j=xadj[i]; j<xadj[i+1]; j++) { + k = adjncy[j]; + if (match[k] == UNMATCHED && maxwgt < adjwgt[j] && vwgt[i]+vwgt[k] <= ctrl->maxvwgt) { + maxwgt = adjwgt[j]; + maxidx = adjncy[j]; + } + } + + cmap[i] = cmap[maxidx] = cnvtxs++; + match[i] = maxidx; + match[maxidx] = i; + } + } + + IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->MatchTmr)); + + CreateCoarseGraph(ctrl, graph, cnvtxs, match, perm); + + idxwspacefree(ctrl, nvtxs); + idxwspacefree(ctrl, nvtxs); +} + + + +/************************************************************************* +* This function finds a matching using the HEM heuristic +**************************************************************************/ +void Match_SHEM(CtrlType *ctrl, GraphType *graph) +{ + int i, ii, j, k, nvtxs, cnvtxs, maxidx, maxwgt, avgdegree; + idxtype *xadj, *vwgt, *adjncy, *adjwgt; + idxtype *match, *cmap, *degrees, *perm, *tperm; + + IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->MatchTmr)); + + nvtxs = graph->nvtxs; + xadj = graph->xadj; + vwgt = graph->vwgt; + adjncy = graph->adjncy; + adjwgt = graph->adjwgt; + + cmap = graph->cmap; + match = idxset(nvtxs, UNMATCHED, idxwspacemalloc(ctrl, nvtxs)); + + perm = idxwspacemalloc(ctrl, nvtxs); + tperm = idxwspacemalloc(ctrl, nvtxs); + degrees = idxwspacemalloc(ctrl, nvtxs); + + RandomPermute(nvtxs, tperm, 1); + avgdegree = 0.7*(xadj[nvtxs]/nvtxs); + for (i=0; i<nvtxs; i++) + degrees[i] = (xadj[i+1]-xadj[i] > avgdegree ? avgdegree : xadj[i+1]-xadj[i]); + BucketSortKeysInc(nvtxs, avgdegree, degrees, tperm, perm); + + cnvtxs = 0; + + /* Take care any islands. Islands are matched with non-islands due to coarsening */ + for (ii=0; ii<nvtxs; ii++) { + i = perm[ii]; + + if (match[i] == UNMATCHED) { /* Unmatched */ + if (xadj[i] < xadj[i+1]) + break; + + maxidx = i; + for (j=nvtxs-1; j>ii; j--) { + k = perm[j]; + if (match[k] == UNMATCHED && xadj[k] < xadj[k+1]) { + maxidx = k; + break; + } + } + + cmap[i] = cmap[maxidx] = cnvtxs++; + match[i] = maxidx; + match[maxidx] = i; + } + } + + /* Continue with normal matching */ + for (; ii<nvtxs; ii++) { + i = perm[ii]; + + if (match[i] == UNMATCHED) { /* Unmatched */ + maxidx = i; + maxwgt = 0; + + /* Find a heavy-edge matching, subject to maxvwgt constraints */ + for (j=xadj[i]; j<xadj[i+1]; j++) { + if (match[adjncy[j]] == UNMATCHED && maxwgt < adjwgt[j] && vwgt[i]+vwgt[adjncy[j]] <= ctrl->maxvwgt) { + maxwgt = adjwgt[j]; + maxidx = adjncy[j]; + } + } + + cmap[i] = cmap[maxidx] = cnvtxs++; + match[i] = maxidx; + match[maxidx] = i; + } + } + + IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->MatchTmr)); + + idxwspacefree(ctrl, nvtxs); /* degrees */ + idxwspacefree(ctrl, nvtxs); /* tperm */ + + CreateCoarseGraph(ctrl, graph, cnvtxs, match, perm); + + idxwspacefree(ctrl, nvtxs); + idxwspacefree(ctrl, nvtxs); +} + diff --git a/contrib/Metis/mbalance.c b/contrib/Metis/mbalance.c new file mode 100644 index 0000000000..3fc5a6e2a9 --- /dev/null +++ b/contrib/Metis/mbalance.c @@ -0,0 +1,260 @@ +/* + * Copyright 1997, Regents of the University of Minnesota + * + * mbalance.c + * + * This file contains code that is used to forcefully balance either + * bisections or k-sections + * + * Started 7/29/97 + * George + * + * $Id: mbalance.c,v 1.1 2005-09-21 17:29:38 geuzaine Exp $ + * + */ + +#include <metis.h> + + +/************************************************************************* +* This function is the entry point of the bisection balancing algorithms. +**************************************************************************/ +void MocBalance2Way(CtrlType *ctrl, GraphType *graph, float *tpwgts, float lbfactor) +{ + + if (Compute2WayHLoadImbalance(graph->ncon, graph->npwgts, tpwgts) < lbfactor) + return; + + MocGeneral2WayBalance(ctrl, graph, tpwgts, lbfactor); + +} + + +/************************************************************************* +* This function performs an edge-based FM refinement +**************************************************************************/ +void MocGeneral2WayBalance(CtrlType *ctrl, GraphType *graph, float *tpwgts, float lbfactor) +{ + int i, ii, j, k, l, kwgt, nvtxs, ncon, nbnd, nswaps, from, to, pass, me, limit, tmp, cnum; + idxtype *xadj, *adjncy, *adjwgt, *where, *id, *ed, *bndptr, *bndind; + idxtype *moved, *swaps, *perm, *qnum; + float *nvwgt, *npwgts, mindiff[MAXNCON], origbal, minbal, newbal; + PQueueType parts[MAXNCON][2]; + int higain, oldgain, mincut, newcut, mincutorder; + int qsizes[MAXNCON][2]; + + nvtxs = graph->nvtxs; + ncon = graph->ncon; + xadj = graph->xadj; + nvwgt = graph->nvwgt; + adjncy = graph->adjncy; + adjwgt = graph->adjwgt; + where = graph->where; + id = graph->id; + ed = graph->ed; + npwgts = graph->npwgts; + bndptr = graph->bndptr; + bndind = graph->bndind; + + moved = idxwspacemalloc(ctrl, nvtxs); + swaps = idxwspacemalloc(ctrl, nvtxs); + perm = idxwspacemalloc(ctrl, nvtxs); + qnum = idxwspacemalloc(ctrl, nvtxs); + + limit = amin(amax(0.01*nvtxs, 15), 100); + + /* Initialize the queues */ + for (i=0; i<ncon; i++) { + PQueueInit(ctrl, &parts[i][0], nvtxs, PLUS_GAINSPAN+1); + PQueueInit(ctrl, &parts[i][1], nvtxs, PLUS_GAINSPAN+1); + qsizes[i][0] = qsizes[i][1] = 0; + } + + for (i=0; i<nvtxs; i++) { + qnum[i] = samax(ncon, nvwgt+i*ncon); + qsizes[qnum[i]][where[i]]++; + } + +/* + printf("Weight Distribution: \t"); + for (i=0; i<ncon; i++) + printf(" [%d %d]", qsizes[i][0], qsizes[i][1]); + printf("\n"); +*/ + + for (from=0; from<2; from++) { + for (j=0; j<ncon; j++) { + if (qsizes[j][from] == 0) { + for (i=0; i<nvtxs; i++) { + if (where[i] != from) + continue; + + k = samax2(ncon, nvwgt+i*ncon); + if (k == j && qsizes[qnum[i]][from] > qsizes[j][from] && nvwgt[i*ncon+qnum[i]] < 1.3*nvwgt[i*ncon+j]) { + qsizes[qnum[i]][from]--; + qsizes[j][from]++; + qnum[i] = j; + } + } + } + } + } + +/* + printf("Weight Distribution (after):\t "); + for (i=0; i<ncon; i++) + printf(" [%d %d]", qsizes[i][0], qsizes[i][1]); + printf("\n"); +*/ + + + + for (i=0; i<ncon; i++) + mindiff[i] = fabs(tpwgts[0]-npwgts[i]); + minbal = origbal = Compute2WayHLoadImbalance(ncon, npwgts, tpwgts); + newcut = mincut = graph->mincut; + mincutorder = -1; + + if (ctrl->dbglvl&DBG_REFINE) { + printf("Parts: ["); + for (l=0; l<ncon; l++) + printf("(%.3f, %.3f) ", npwgts[l], npwgts[ncon+l]); + printf("] T[%.3f %.3f], Nv-Nb[%5d, %5d]. ICut: %6d, LB: %.3f [B]\n", tpwgts[0], tpwgts[1], graph->nvtxs, graph->nbnd, graph->mincut, origbal); + } + + idxset(nvtxs, -1, moved); + + ASSERT(ComputeCut(graph, where) == graph->mincut); + ASSERT(CheckBnd(graph)); + + /* Insert all nodes in the priority queues */ + nbnd = graph->nbnd; + RandomPermute(nvtxs, perm, 1); + for (ii=0; ii<nvtxs; ii++) { + i = perm[ii]; + PQueueInsert(&parts[qnum[i]][where[i]], i, ed[i]-id[i]); + } + + for (nswaps=0; nswaps<nvtxs; nswaps++) { + if (minbal < lbfactor) + break; + + SelectQueue(ncon, npwgts, tpwgts, &from, &cnum, parts); + to = (from+1)%2; + + if (from == -1 || (higain = PQueueGetMax(&parts[cnum][from])) == -1) + break; + + saxpy(ncon, 1.0, nvwgt+higain*ncon, 1, npwgts+to*ncon, 1); + saxpy(ncon, -1.0, nvwgt+higain*ncon, 1, npwgts+from*ncon, 1); + newcut -= (ed[higain]-id[higain]); + newbal = Compute2WayHLoadImbalance(ncon, npwgts, tpwgts); + + if (newbal < minbal || (newbal == minbal && + (newcut < mincut || (newcut == mincut && BetterBalance(ncon, npwgts, tpwgts, mindiff))))) { + mincut = newcut; + minbal = newbal; + mincutorder = nswaps; + for (i=0; i<ncon; i++) + mindiff[i] = fabs(tpwgts[0]-npwgts[i]); + } + else if (nswaps-mincutorder > limit) { /* We hit the limit, undo last move */ + newcut += (ed[higain]-id[higain]); + saxpy(ncon, 1.0, nvwgt+higain*ncon, 1, npwgts+from*ncon, 1); + saxpy(ncon, -1.0, nvwgt+higain*ncon, 1, npwgts+to*ncon, 1); + break; + } + + where[higain] = to; + moved[higain] = nswaps; + swaps[nswaps] = higain; + + if (ctrl->dbglvl&DBG_MOVEINFO) { + printf("Moved %6d from %d(%d). Gain: %5d, Cut: %5d, NPwgts: ", higain, from, cnum, ed[higain]-id[higain], newcut); + for (l=0; l<ncon; l++) + printf("(%.3f, %.3f) ", npwgts[l], npwgts[ncon+l]); + printf(", %.3f LB: %.3f\n", minbal, newbal); + } + + + /************************************************************** + * Update the id[i]/ed[i] values of the affected nodes + ***************************************************************/ + SWAP(id[higain], ed[higain], tmp); + if (ed[higain] == 0 && bndptr[higain] != -1 && xadj[higain] < xadj[higain+1]) + BNDDelete(nbnd, bndind, bndptr, higain); + if (ed[higain] > 0 && bndptr[higain] == -1) + BNDInsert(nbnd, bndind, bndptr, higain); + + for (j=xadj[higain]; j<xadj[higain+1]; j++) { + k = adjncy[j]; + oldgain = ed[k]-id[k]; + + kwgt = (to == where[k] ? adjwgt[j] : -adjwgt[j]); + INC_DEC(id[k], ed[k], kwgt); + + /* Update the queue position */ + if (moved[k] == -1) + PQueueUpdate(&parts[qnum[k]][where[k]], k, oldgain, ed[k]-id[k]); + + /* Update its boundary information */ + if (ed[k] == 0 && bndptr[k] != -1) + BNDDelete(nbnd, bndind, bndptr, k); + else if (ed[k] > 0 && bndptr[k] == -1) + BNDInsert(nbnd, bndind, bndptr, k); + } + } + + + + /**************************************************************** + * Roll back computations + *****************************************************************/ + for (nswaps--; nswaps>mincutorder; nswaps--) { + higain = swaps[nswaps]; + + to = where[higain] = (where[higain]+1)%2; + SWAP(id[higain], ed[higain], tmp); + if (ed[higain] == 0 && bndptr[higain] != -1 && xadj[higain] < xadj[higain+1]) + BNDDelete(nbnd, bndind, bndptr, higain); + else if (ed[higain] > 0 && bndptr[higain] == -1) + BNDInsert(nbnd, bndind, bndptr, higain); + + saxpy(ncon, 1.0, nvwgt+higain*ncon, 1, npwgts+to*ncon, 1); + saxpy(ncon, -1.0, nvwgt+higain*ncon, 1, npwgts+((to+1)%2)*ncon, 1); + for (j=xadj[higain]; j<xadj[higain+1]; j++) { + k = adjncy[j]; + + kwgt = (to == where[k] ? adjwgt[j] : -adjwgt[j]); + INC_DEC(id[k], ed[k], kwgt); + + if (bndptr[k] != -1 && ed[k] == 0) + BNDDelete(nbnd, bndind, bndptr, k); + if (bndptr[k] == -1 && ed[k] > 0) + BNDInsert(nbnd, bndind, bndptr, k); + } + } + + if (ctrl->dbglvl&DBG_REFINE) { + printf("\tMincut: %6d at %5d, NBND: %6d, NPwgts: [", mincut, mincutorder, nbnd); + for (l=0; l<ncon; l++) + printf("(%.3f, %.3f) ", npwgts[l], npwgts[ncon+l]); + printf("], LB: %.3f\n", Compute2WayHLoadImbalance(ncon, npwgts, tpwgts)); + } + + graph->mincut = mincut; + graph->nbnd = nbnd; + + + for (i=0; i<ncon; i++) { + PQueueFree(ctrl, &parts[i][0]); + PQueueFree(ctrl, &parts[i][1]); + } + + idxwspacefree(ctrl, nvtxs); + idxwspacefree(ctrl, nvtxs); + idxwspacefree(ctrl, nvtxs); + idxwspacefree(ctrl, nvtxs); + +} + diff --git a/contrib/Metis/mbalance2.c b/contrib/Metis/mbalance2.c new file mode 100644 index 0000000000..6991dbf523 --- /dev/null +++ b/contrib/Metis/mbalance2.c @@ -0,0 +1,328 @@ +/* + * Copyright 1997, Regents of the University of Minnesota + * + * mbalance2.c + * + * This file contains code that is used to forcefully balance either + * bisections or k-sections + * + * Started 7/29/97 + * George + * + * $Id: mbalance2.c,v 1.1 2005-09-21 17:29:38 geuzaine Exp $ + * + */ + +#include <metis.h> + + +/************************************************************************* +* This function is the entry point of the bisection balancing algorithms. +**************************************************************************/ +void MocBalance2Way2(CtrlType *ctrl, GraphType *graph, float *tpwgts, float *ubvec) +{ + int i; + float tvec[MAXNCON]; + + Compute2WayHLoadImbalanceVec(graph->ncon, graph->npwgts, tpwgts, tvec); + if (!AreAllBelow(graph->ncon, tvec, ubvec)) + MocGeneral2WayBalance2(ctrl, graph, tpwgts, ubvec); +} + + + +/************************************************************************* +* This function performs an edge-based FM refinement +**************************************************************************/ +void MocGeneral2WayBalance2(CtrlType *ctrl, GraphType *graph, float *tpwgts, float *ubvec) +{ + int i, ii, j, k, l, kwgt, nvtxs, ncon, nbnd, nswaps, from, to, pass, me, limit, tmp, cnum; + idxtype *xadj, *adjncy, *adjwgt, *where, *id, *ed, *bndptr, *bndind; + idxtype *moved, *swaps, *perm, *qnum; + float *nvwgt, *npwgts, origbal[MAXNCON], minbal[MAXNCON], newbal[MAXNCON]; + PQueueType parts[MAXNCON][2]; + int higain, oldgain, mincut, newcut, mincutorder; + float *maxwgt, *minwgt, tvec[MAXNCON]; + + + nvtxs = graph->nvtxs; + ncon = graph->ncon; + xadj = graph->xadj; + nvwgt = graph->nvwgt; + adjncy = graph->adjncy; + adjwgt = graph->adjwgt; + where = graph->where; + id = graph->id; + ed = graph->ed; + npwgts = graph->npwgts; + bndptr = graph->bndptr; + bndind = graph->bndind; + + moved = idxwspacemalloc(ctrl, nvtxs); + swaps = idxwspacemalloc(ctrl, nvtxs); + perm = idxwspacemalloc(ctrl, nvtxs); + qnum = idxwspacemalloc(ctrl, nvtxs); + + limit = amin(amax(0.01*nvtxs, 15), 100); + + /* Setup the weight intervals of the two subdomains */ + minwgt = fwspacemalloc(ctrl, 2*ncon); + maxwgt = fwspacemalloc(ctrl, 2*ncon); + + for (i=0; i<2; i++) { + for (j=0; j<ncon; j++) { + maxwgt[i*ncon+j] = tpwgts[i]*ubvec[j]; + minwgt[i*ncon+j] = tpwgts[i]*(1.0/ubvec[j]); + } + } + + + /* Initialize the queues */ + for (i=0; i<ncon; i++) { + PQueueInit(ctrl, &parts[i][0], nvtxs, PLUS_GAINSPAN+1); + PQueueInit(ctrl, &parts[i][1], nvtxs, PLUS_GAINSPAN+1); + } + for (i=0; i<nvtxs; i++) + qnum[i] = samax(ncon, nvwgt+i*ncon); + + Compute2WayHLoadImbalanceVec(ncon, npwgts, tpwgts, origbal); + for (i=0; i<ncon; i++) + minbal[i] = origbal[i]; + + newcut = mincut = graph->mincut; + mincutorder = -1; + + if (ctrl->dbglvl&DBG_REFINE) { + printf("Parts: ["); + for (l=0; l<ncon; l++) + printf("(%.3f, %.3f) ", npwgts[l], npwgts[ncon+l]); + printf("] T[%.3f %.3f], Nv-Nb[%5d, %5d]. ICut: %6d, LB: ", tpwgts[0], tpwgts[1], + graph->nvtxs, graph->nbnd, graph->mincut); + for (i=0; i<ncon; i++) + printf("%.3f ", origbal[i]); + printf("[B]\n"); + } + + idxset(nvtxs, -1, moved); + + ASSERT(ComputeCut(graph, where) == graph->mincut); + ASSERT(CheckBnd(graph)); + + /* Insert all nodes in the priority queues */ + nbnd = graph->nbnd; + RandomPermute(nvtxs, perm, 1); + for (ii=0; ii<nvtxs; ii++) { + i = perm[ii]; + PQueueInsert(&parts[qnum[i]][where[i]], i, ed[i]-id[i]); + } + + + for (nswaps=0; nswaps<nvtxs; nswaps++) { + if (AreAllBelow(ncon, minbal, ubvec)) + break; + + SelectQueue3(ncon, npwgts, tpwgts, &from, &cnum, parts, maxwgt); + to = (from+1)%2; + + if (from == -1 || (higain = PQueueGetMax(&parts[cnum][from])) == -1) + break; + + saxpy(ncon, 1.0, nvwgt+higain*ncon, 1, npwgts+to*ncon, 1); + saxpy(ncon, -1.0, nvwgt+higain*ncon, 1, npwgts+from*ncon, 1); + newcut -= (ed[higain]-id[higain]); + Compute2WayHLoadImbalanceVec(ncon, npwgts, tpwgts, newbal); + + if (IsBetter2wayBalance(ncon, newbal, minbal, ubvec) || + (IsBetter2wayBalance(ncon, newbal, origbal, ubvec) && newcut < mincut)) { + mincut = newcut; + for (i=0; i<ncon; i++) + minbal[i] = newbal[i]; + mincutorder = nswaps; + } + else if (nswaps-mincutorder > limit) { /* We hit the limit, undo last move */ + newcut += (ed[higain]-id[higain]); + saxpy(ncon, 1.0, nvwgt+higain*ncon, 1, npwgts+from*ncon, 1); + saxpy(ncon, -1.0, nvwgt+higain*ncon, 1, npwgts+to*ncon, 1); + break; + } + + where[higain] = to; + moved[higain] = nswaps; + swaps[nswaps] = higain; + + if (ctrl->dbglvl&DBG_MOVEINFO) { + printf("Moved %6d from %d(%d). Gain: %5d, Cut: %5d, NPwgts: ", higain, from, cnum, ed[higain]-id[higain], newcut); + for (i=0; i<ncon; i++) + printf("(%.3f, %.3f) ", npwgts[i], npwgts[ncon+i]); + + Compute2WayHLoadImbalanceVec(ncon, npwgts, tpwgts, tvec); + printf(", LB: "); + for (i=0; i<ncon; i++) + printf("%.3f ", tvec[i]); + if (mincutorder == nswaps) + printf(" *\n"); + else + printf("\n"); + } + + + /************************************************************** + * Update the id[i]/ed[i] values of the affected nodes + ***************************************************************/ + SWAP(id[higain], ed[higain], tmp); + if (ed[higain] == 0 && bndptr[higain] != -1 && xadj[higain] < xadj[higain+1]) + BNDDelete(nbnd, bndind, bndptr, higain); + if (ed[higain] > 0 && bndptr[higain] == -1) + BNDInsert(nbnd, bndind, bndptr, higain); + + for (j=xadj[higain]; j<xadj[higain+1]; j++) { + k = adjncy[j]; + oldgain = ed[k]-id[k]; + + kwgt = (to == where[k] ? adjwgt[j] : -adjwgt[j]); + INC_DEC(id[k], ed[k], kwgt); + + /* Update the queue position */ + if (moved[k] == -1) + PQueueUpdate(&parts[qnum[k]][where[k]], k, oldgain, ed[k]-id[k]); + + /* Update its boundary information */ + if (ed[k] == 0 && bndptr[k] != -1) + BNDDelete(nbnd, bndind, bndptr, k); + else if (ed[k] > 0 && bndptr[k] == -1) + BNDInsert(nbnd, bndind, bndptr, k); + } + + } + + + + /**************************************************************** + * Roll back computations + *****************************************************************/ + for (i=0; i<nswaps; i++) + moved[swaps[i]] = -1; /* reset moved array */ + for (nswaps--; nswaps>mincutorder; nswaps--) { + higain = swaps[nswaps]; + + to = where[higain] = (where[higain]+1)%2; + SWAP(id[higain], ed[higain], tmp); + if (ed[higain] == 0 && bndptr[higain] != -1 && xadj[higain] < xadj[higain+1]) + BNDDelete(nbnd, bndind, bndptr, higain); + else if (ed[higain] > 0 && bndptr[higain] == -1) + BNDInsert(nbnd, bndind, bndptr, higain); + + saxpy(ncon, 1.0, nvwgt+higain*ncon, 1, npwgts+to*ncon, 1); + saxpy(ncon, -1.0, nvwgt+higain*ncon, 1, npwgts+((to+1)%2)*ncon, 1); + for (j=xadj[higain]; j<xadj[higain+1]; j++) { + k = adjncy[j]; + + kwgt = (to == where[k] ? adjwgt[j] : -adjwgt[j]); + INC_DEC(id[k], ed[k], kwgt); + + if (bndptr[k] != -1 && ed[k] == 0) + BNDDelete(nbnd, bndind, bndptr, k); + if (bndptr[k] == -1 && ed[k] > 0) + BNDInsert(nbnd, bndind, bndptr, k); + } + } + + if (ctrl->dbglvl&DBG_REFINE) { + printf("\tMincut: %6d at %5d, NBND: %6d, NPwgts: [", mincut, mincutorder, nbnd); + for (i=0; i<ncon; i++) + printf("(%.3f, %.3f) ", npwgts[i], npwgts[ncon+i]); + printf("], LB: "); + Compute2WayHLoadImbalanceVec(ncon, npwgts, tpwgts, tvec); + for (i=0; i<ncon; i++) + printf("%.3f ", tvec[i]); + printf("\n"); + } + + graph->mincut = mincut; + graph->nbnd = nbnd; + + + for (i=0; i<ncon; i++) { + PQueueFree(ctrl, &parts[i][0]); + PQueueFree(ctrl, &parts[i][1]); + } + + idxwspacefree(ctrl, nvtxs); + idxwspacefree(ctrl, nvtxs); + idxwspacefree(ctrl, nvtxs); + idxwspacefree(ctrl, nvtxs); + fwspacefree(ctrl, 2*ncon); + fwspacefree(ctrl, 2*ncon); + +} + + + + +/************************************************************************* +* This function selects the partition number and the queue from which +* we will move vertices out +**************************************************************************/ +void SelectQueue3(int ncon, float *npwgts, float *tpwgts, int *from, int *cnum, + PQueueType queues[MAXNCON][2], float *maxwgt) +{ + int i, j, maxgain=0; + float maxdiff=0.0, diff; + + *from = -1; + *cnum = -1; + + /* First determine the side and the queue, irrespective of the presence of nodes */ + for (j=0; j<2; j++) { + for (i=0; i<ncon; i++) { + diff = npwgts[j*ncon+i]-maxwgt[j*ncon+i]; + if (diff >= maxdiff) { + maxdiff = diff; + *from = j; + *cnum = i; + } + } + } + +/* DELETE +j = *from; +for (i=0; i<ncon; i++) + printf("[%5d %5d %.4f %.4f] ", i, PQueueGetSize(&queues[i][j]), npwgts[j*ncon+i], maxwgt[j*ncon+i]); +printf("***[%5d %5d]\n", *cnum, *from); +*/ + + /* If the desired queue is empty, select a node from that side anyway */ + if (*from != -1 && PQueueGetSize(&queues[*cnum][*from]) == 0) { + for (i=0; i<ncon; i++) { + if (PQueueGetSize(&queues[i][*from]) > 0) { + maxdiff = (npwgts[(*from)*ncon+i] - maxwgt[(*from)*ncon+i]); + *cnum = i; + break; + } + } + + for (i++; i<ncon; i++) { + diff = npwgts[(*from)*ncon+i] - maxwgt[(*from)*ncon+i]; + if (diff > maxdiff && PQueueGetSize(&queues[i][*from]) > 0) { + maxdiff = diff; + *cnum = i; + } + } + } + + /* If the constraints ar OK, select a high gain vertex */ + if (*from == -1) { + maxgain = -100000; + for (j=0; j<2; j++) { + for (i=0; i<ncon; i++) { + if (PQueueGetSize(&queues[i][j]) > 0 && PQueueGetKey(&queues[i][j]) > maxgain) { + maxgain = PQueueGetKey(&queues[i][0]); + *from = j; + *cnum = i; + } + } + } + + /* printf("(%2d %2d) %3d\n", *from, *cnum, maxgain); */ + } +} diff --git a/contrib/Metis/mcoarsen.c b/contrib/Metis/mcoarsen.c new file mode 100644 index 0000000000..4c4237641b --- /dev/null +++ b/contrib/Metis/mcoarsen.c @@ -0,0 +1,91 @@ +/* + * mcoarsen.c + * + * This file contains the driving routines for the coarsening process + * + * Started 7/23/97 + * George + * + * $Id: mcoarsen.c,v 1.1 2005-09-21 17:29:38 geuzaine Exp $ + * + */ + +#include <metis.h> + + +/************************************************************************* +* This function takes a graph and creates a sequence of coarser graphs +**************************************************************************/ +GraphType *MCCoarsen2Way(CtrlType *ctrl, GraphType *graph) +{ + int i, clevel; + GraphType *cgraph; + + IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->CoarsenTmr)); + + cgraph = graph; + + clevel = 0; + do { + if (ctrl->dbglvl&DBG_COARSEN) { + printf("%6d %7d %10d [%d] [%6.4f", cgraph->nvtxs, cgraph->nedges, + idxsum(cgraph->nvtxs, cgraph->adjwgtsum), ctrl->CoarsenTo, ctrl->nmaxvwgt); + for (i=0; i<graph->ncon; i++) + printf(" %5.3f", ssum_strd(cgraph->nvtxs, cgraph->nvwgt+i, cgraph->ncon)); + printf("]\n"); + } + + switch (ctrl->CType) { + case MATCH_RM: + MCMatch_RM(ctrl, cgraph); + break; + case MATCH_HEM: + if (clevel < 1) + MCMatch_RM(ctrl, cgraph); + else + MCMatch_HEM(ctrl, cgraph); + break; + case MATCH_SHEM: + if (clevel < 1) + MCMatch_RM(ctrl, cgraph); + else + MCMatch_SHEM(ctrl, cgraph); + break; + case MATCH_SHEMKWAY: + MCMatch_SHEM(ctrl, cgraph); + break; + case MATCH_SHEBM_ONENORM: + MCMatch_SHEBM(ctrl, cgraph, 1); + break; + case MATCH_SHEBM_INFNORM: + MCMatch_SHEBM(ctrl, cgraph, -1); + break; + case MATCH_SBHEM_ONENORM: + MCMatch_SBHEM(ctrl, cgraph, 1); + break; + case MATCH_SBHEM_INFNORM: + MCMatch_SBHEM(ctrl, cgraph, -1); + break; + default: + errexit("Unknown CType: %d\n", ctrl->CType); + } + + cgraph = cgraph->coarser; + clevel++; + + } while (cgraph->nvtxs > ctrl->CoarsenTo && cgraph->nvtxs < COARSEN_FRACTION2*cgraph->finer->nvtxs && cgraph->nedges > cgraph->nvtxs/2); + + if (ctrl->dbglvl&DBG_COARSEN) { + printf("%6d %7d %10d [%d] [%6.4f", cgraph->nvtxs, cgraph->nedges, + idxsum(cgraph->nvtxs, cgraph->adjwgtsum), ctrl->CoarsenTo, ctrl->nmaxvwgt); + for (i=0; i<graph->ncon; i++) + printf(" %5.3f", ssum_strd(cgraph->nvtxs, cgraph->nvwgt+i, cgraph->ncon)); + printf("]\n"); + } + + + IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->CoarsenTmr)); + + return cgraph; +} + diff --git a/contrib/Metis/memory.c b/contrib/Metis/memory.c new file mode 100644 index 0000000000..5461105338 --- /dev/null +++ b/contrib/Metis/memory.c @@ -0,0 +1,208 @@ +/* + * Copyright 1997, Regents of the University of Minnesota + * + * memory.c + * + * This file contains routines that deal with memory allocation + * + * Started 2/24/96 + * George + * + * $Id: memory.c,v 1.1 2005-09-21 17:29:38 geuzaine Exp $ + * + */ + +#include <metis.h> + + +/************************************************************************* +* This function allocates memory for the workspace +**************************************************************************/ +void AllocateWorkSpace(CtrlType *ctrl, GraphType *graph, int nparts) +{ + ctrl->wspace.pmat = NULL; + + if (ctrl->optype == OP_KMETIS) { + ctrl->wspace.edegrees = (EDegreeType *)GKmalloc(graph->nedges*sizeof(EDegreeType), "AllocateWorkSpace: edegrees"); + ctrl->wspace.vedegrees = NULL; + ctrl->wspace.auxcore = (idxtype *)ctrl->wspace.edegrees; + + ctrl->wspace.pmat = idxmalloc(nparts*nparts, "AllocateWorkSpace: pmat"); + + /* Memory requirements for different phases + Coarsening + Matching: 4*nvtxs vectors + Contraction: 2*nvtxs vectors (from the above 4), 1*nparts, 1*Nedges + Total = MAX(4*nvtxs, 2*nvtxs+nparts+nedges) + + Refinement + Random Refinement/Balance: 5*nparts + 1*nvtxs + 2*nedges + Greedy Refinement/Balance: 5*nparts + 2*nvtxs + 2*nedges + 1*PQueue(==Nvtxs) + Total = 5*nparts + 3*nvtxs + 2*nedges + + Total = 5*nparts + 3*nvtxs + 2*nedges + */ + ctrl->wspace.maxcore = 3*(graph->nvtxs+1) + /* Match/Refinement vectors */ + 5*(nparts+1) + /* Partition weights etc */ + graph->nvtxs*(sizeof(ListNodeType)/sizeof(idxtype)) + /* Greedy k-way balance/refine */ + 20 /* padding for 64 bit machines */ + ; + } + else if (ctrl->optype == OP_KVMETIS) { + ctrl->wspace.edegrees = NULL; + ctrl->wspace.vedegrees = (VEDegreeType *)GKmalloc(graph->nedges*sizeof(VEDegreeType), "AllocateWorkSpace: vedegrees"); + ctrl->wspace.auxcore = (idxtype *)ctrl->wspace.vedegrees; + + ctrl->wspace.pmat = idxmalloc(nparts*nparts, "AllocateWorkSpace: pmat"); + + /* Memory requirements for different phases are identical to KMETIS */ + ctrl->wspace.maxcore = 3*(graph->nvtxs+1) + /* Match/Refinement vectors */ + 3*(nparts+1) + /* Partition weights etc */ + graph->nvtxs*(sizeof(ListNodeType)/sizeof(idxtype)) + /* Greedy k-way balance/refine */ + 20 /* padding for 64 bit machines */ + ; + } + else { + ctrl->wspace.edegrees = (EDegreeType *)idxmalloc(graph->nedges, "AllocateWorkSpace: edegrees"); + ctrl->wspace.vedegrees = NULL; + ctrl->wspace.auxcore = (idxtype *)ctrl->wspace.edegrees; + + ctrl->wspace.maxcore = 5*(graph->nvtxs+1) + /* Refinement vectors */ + 4*(nparts+1) + /* Partition weights etc */ + 2*graph->ncon*graph->nvtxs*(sizeof(ListNodeType)/sizeof(idxtype)) + /* 2-way refinement */ + 2*graph->ncon*(NEG_GAINSPAN+PLUS_GAINSPAN+1)*(sizeof(ListNodeType *)/sizeof(idxtype)) + /* 2-way refinement */ + 20 /* padding for 64 bit machines */ + ; + } + + ctrl->wspace.maxcore += HTLENGTH; + ctrl->wspace.core = idxmalloc(ctrl->wspace.maxcore, "AllocateWorkSpace: maxcore"); + ctrl->wspace.ccore = 0; +} + + +/************************************************************************* +* This function allocates memory for the workspace +**************************************************************************/ +void FreeWorkSpace(CtrlType *ctrl, GraphType *graph) +{ + GKfree(&ctrl->wspace.edegrees, &ctrl->wspace.vedegrees, &ctrl->wspace.core, &ctrl->wspace.pmat, LTERM); +} + +/************************************************************************* +* This function returns how may words are left in the workspace +**************************************************************************/ +int WspaceAvail(CtrlType *ctrl) +{ + return ctrl->wspace.maxcore - ctrl->wspace.ccore; +} + + +/************************************************************************* +* This function allocate space from the core +**************************************************************************/ +idxtype *idxwspacemalloc(CtrlType *ctrl, int n) +{ + n += n%2; /* This is a fix for 64 bit machines that require 8-byte pointer allignment */ + + ctrl->wspace.ccore += n; + ASSERT(ctrl->wspace.ccore <= ctrl->wspace.maxcore); + return ctrl->wspace.core + ctrl->wspace.ccore - n; +} + +/************************************************************************* +* This function frees space from the core +**************************************************************************/ +void idxwspacefree(CtrlType *ctrl, int n) +{ + n += n%2; /* This is a fix for 64 bit machines that require 8-byte pointer allignment */ + + ctrl->wspace.ccore -= n; + ASSERT(ctrl->wspace.ccore >= 0); +} + + +/************************************************************************* +* This function allocate space from the core +**************************************************************************/ +float *fwspacemalloc(CtrlType *ctrl, int n) +{ + n += n%2; /* This is a fix for 64 bit machines that require 8-byte pointer allignment */ + + ctrl->wspace.ccore += n; + ASSERT(ctrl->wspace.ccore <= ctrl->wspace.maxcore); + return (float *) (ctrl->wspace.core + ctrl->wspace.ccore - n); +} + +/************************************************************************* +* This function frees space from the core +**************************************************************************/ +void fwspacefree(CtrlType *ctrl, int n) +{ + n += n%2; /* This is a fix for 64 bit machines that require 8-byte pointer allignment */ + + ctrl->wspace.ccore -= n; + ASSERT(ctrl->wspace.ccore >= 0); +} + + + +/************************************************************************* +* This function creates a CoarseGraphType data structure and initializes +* the various fields +**************************************************************************/ +GraphType *CreateGraph(void) +{ + GraphType *graph; + + graph = (GraphType *)GKmalloc(sizeof(GraphType), "CreateCoarseGraph: graph"); + + InitGraph(graph); + + return graph; +} + + +/************************************************************************* +* This function creates a CoarseGraphType data structure and initializes +* the various fields +**************************************************************************/ +void InitGraph(GraphType *graph) +{ + graph->gdata = graph->rdata = NULL; + + graph->nvtxs = graph->nedges = -1; + graph->mincut = graph->minvol = -1; + + graph->xadj = graph->vwgt = graph->adjncy = graph->adjwgt = NULL; + graph->adjwgtsum = NULL; + graph->label = NULL; + graph->cmap = NULL; + + graph->where = graph->pwgts = NULL; + graph->id = graph->ed = NULL; + graph->bndptr = graph->bndind = NULL; + graph->rinfo = NULL; + graph->vrinfo = NULL; + graph->nrinfo = NULL; + + graph->ncon = -1; + graph->nvwgt = NULL; + graph->npwgts = NULL; + + graph->vsize = NULL; + + graph->coarser = graph->finer = NULL; + +} + +/************************************************************************* +* This function deallocates any memory stored in a graph +**************************************************************************/ +void FreeGraph(GraphType *graph) +{ + + GKfree(&graph->gdata, &graph->nvwgt, &graph->rdata, &graph->npwgts, LTERM); + free(graph); +} + diff --git a/contrib/Metis/mesh.c b/contrib/Metis/mesh.c new file mode 100644 index 0000000000..607792a9a1 --- /dev/null +++ b/contrib/Metis/mesh.c @@ -0,0 +1,398 @@ +/* + * Copyright 1997, Regents of the University of Minnesota + * + * mesh.c + * + * This file contains routines for converting 3D and 4D finite element + * meshes into dual or nodal graphs + * + * Started 8/18/97 + * George + * + * $Id: mesh.c,v 1.1 2005-09-21 17:29:38 geuzaine Exp $ + * + */ + +#include <metis.h> + +/***************************************************************************** +* This function creates a graph corresponding to the dual of a finite element +* mesh. At this point the supported elements are triangles, tetrahedrons, and +* bricks. +******************************************************************************/ +void METIS_MeshToDual(int *ne, int *nn, idxtype *elmnts, int *etype, int *numflag, + idxtype *dxadj, idxtype *dadjncy) +{ + int esizes[] = {-1, 3, 4, 8, 4}; + + if (*numflag == 1) + ChangeMesh2CNumbering((*ne)*esizes[*etype], elmnts); + + GENDUALMETIS(*ne, *nn, *etype, elmnts, dxadj, dadjncy); + + if (*numflag == 1) + ChangeMesh2FNumbering((*ne)*esizes[*etype], elmnts, *ne, dxadj, dadjncy); +} + + +/***************************************************************************** +* This function creates a graph corresponding to the finite element mesh. +* At this point the supported elements are triangles, tetrahedrons. +******************************************************************************/ +void METIS_MeshToNodal(int *ne, int *nn, idxtype *elmnts, int *etype, int *numflag, + idxtype *dxadj, idxtype *dadjncy) +{ + int esizes[] = {-1, 3, 4, 8, 4}; + + if (*numflag == 1) + ChangeMesh2CNumbering((*ne)*esizes[*etype], elmnts); + + switch (*etype) { + case 1: + TRINODALMETIS(*ne, *nn, elmnts, dxadj, dadjncy); + break; + case 2: + TETNODALMETIS(*ne, *nn, elmnts, dxadj, dadjncy); + break; + case 3: + HEXNODALMETIS(*ne, *nn, elmnts, dxadj, dadjncy); + break; + case 4: + QUADNODALMETIS(*ne, *nn, elmnts, dxadj, dadjncy); + break; + } + + if (*numflag == 1) + ChangeMesh2FNumbering((*ne)*esizes[*etype], elmnts, *nn, dxadj, dadjncy); +} + + + +/***************************************************************************** +* This function creates the dual of a finite element mesh +******************************************************************************/ +void GENDUALMETIS(int nelmnts, int nvtxs, int etype, idxtype *elmnts, idxtype *dxadj, idxtype *dadjncy) +{ + int i, j, jj, k, kk, kkk, l, m, n, nedges, mask; + idxtype *nptr, *nind; + idxtype *mark, ind[200], wgt[200]; + int esize, esizes[] = {-1, 3, 4, 8, 4}, + mgcnum, mgcnums[] = {-1, 2, 3, 4, 2}; + + mask = (1<<11)-1; + mark = idxsmalloc(mask+1, -1, "GENDUALMETIS: mark"); + + /* Get the element size and magic number for the particular element */ + esize = esizes[etype]; + mgcnum = mgcnums[etype]; + + /* Construct the node-element list first */ + nptr = idxsmalloc(nvtxs+1, 0, "GENDUALMETIS: nptr"); + for (j=esize*nelmnts, i=0; i<j; i++) + nptr[elmnts[i]]++; + MAKECSR(i, nvtxs, nptr); + + nind = idxmalloc(nptr[nvtxs], "GENDUALMETIS: nind"); + for (k=i=0; i<nelmnts; i++) { + for (j=0; j<esize; j++, k++) + nind[nptr[elmnts[k]]++] = i; + } + for (i=nvtxs; i>0; i--) + nptr[i] = nptr[i-1]; + nptr[0] = 0; + + for (i=0; i<nelmnts; i++) + dxadj[i] = esize*i; + + for (i=0; i<nelmnts; i++) { + for (m=j=0; j<esize; j++) { + n = elmnts[esize*i+j]; + for (k=nptr[n+1]-1; k>=nptr[n]; k--) { + if ((kk = nind[k]) <= i) + break; + + kkk = kk&mask; + if ((l = mark[kkk]) == -1) { + ind[m] = kk; + wgt[m] = 1; + mark[kkk] = m++; + } + else if (ind[l] == kk) { + wgt[l]++; + } + else { + for (jj=0; jj<m; jj++) { + if (ind[jj] == kk) { + wgt[jj]++; + break; + } + } + if (jj == m) { + ind[m] = kk; + wgt[m++] = 1; + } + } + } + } + for (j=0; j<m; j++) { + if (wgt[j] == mgcnum) { + k = ind[j]; + dadjncy[dxadj[i]++] = k; + dadjncy[dxadj[k]++] = i; + } + mark[ind[j]&mask] = -1; + } + } + + /* Go and consolidate the dxadj and dadjncy */ + for (j=i=0; i<nelmnts; i++) { + for (k=esize*i; k<dxadj[i]; k++, j++) + dadjncy[j] = dadjncy[k]; + dxadj[i] = j; + } + for (i=nelmnts; i>0; i--) + dxadj[i] = dxadj[i-1]; + dxadj[0] = 0; + + free(mark); + free(nptr); + free(nind); + +} + + + + +/***************************************************************************** +* This function creates the nodal graph of a finite element mesh +******************************************************************************/ +void TRINODALMETIS(int nelmnts, int nvtxs, idxtype *elmnts, idxtype *dxadj, idxtype *dadjncy) +{ + int i, j, jj, k, kk, kkk, l, m, n, nedges; + idxtype *nptr, *nind; + idxtype *mark; + + /* Construct the node-element list first */ + nptr = idxsmalloc(nvtxs+1, 0, "TRINODALMETIS: nptr"); + for (j=3*nelmnts, i=0; i<j; i++) + nptr[elmnts[i]]++; + MAKECSR(i, nvtxs, nptr); + + nind = idxmalloc(nptr[nvtxs], "TRINODALMETIS: nind"); + for (k=i=0; i<nelmnts; i++) { + for (j=0; j<3; j++, k++) + nind[nptr[elmnts[k]]++] = i; + } + for (i=nvtxs; i>0; i--) + nptr[i] = nptr[i-1]; + nptr[0] = 0; + + + mark = idxsmalloc(nvtxs, -1, "TRINODALMETIS: mark"); + + nedges = dxadj[0] = 0; + for (i=0; i<nvtxs; i++) { + mark[i] = i; + for (j=nptr[i]; j<nptr[i+1]; j++) { + for (jj=3*nind[j], k=0; k<3; k++, jj++) { + kk = elmnts[jj]; + if (mark[kk] != i) { + mark[kk] = i; + dadjncy[nedges++] = kk; + } + } + } + dxadj[i+1] = nedges; + } + + free(mark); + free(nptr); + free(nind); + +} + + +/***************************************************************************** +* This function creates the nodal graph of a finite element mesh +******************************************************************************/ +void TETNODALMETIS(int nelmnts, int nvtxs, idxtype *elmnts, idxtype *dxadj, idxtype *dadjncy) +{ + int i, j, jj, k, kk, kkk, l, m, n, nedges; + idxtype *nptr, *nind; + idxtype *mark; + + /* Construct the node-element list first */ + nptr = idxsmalloc(nvtxs+1, 0, "TETNODALMETIS: nptr"); + for (j=4*nelmnts, i=0; i<j; i++) + nptr[elmnts[i]]++; + MAKECSR(i, nvtxs, nptr); + + nind = idxmalloc(nptr[nvtxs], "TETNODALMETIS: nind"); + for (k=i=0; i<nelmnts; i++) { + for (j=0; j<4; j++, k++) + nind[nptr[elmnts[k]]++] = i; + } + for (i=nvtxs; i>0; i--) + nptr[i] = nptr[i-1]; + nptr[0] = 0; + + + mark = idxsmalloc(nvtxs, -1, "TETNODALMETIS: mark"); + + nedges = dxadj[0] = 0; + for (i=0; i<nvtxs; i++) { + mark[i] = i; + for (j=nptr[i]; j<nptr[i+1]; j++) { + for (jj=4*nind[j], k=0; k<4; k++, jj++) { + kk = elmnts[jj]; + if (mark[kk] != i) { + mark[kk] = i; + dadjncy[nedges++] = kk; + } + } + } + dxadj[i+1] = nedges; + } + + free(mark); + free(nptr); + free(nind); + +} + + +/***************************************************************************** +* This function creates the nodal graph of a finite element mesh +******************************************************************************/ +void HEXNODALMETIS(int nelmnts, int nvtxs, idxtype *elmnts, idxtype *dxadj, idxtype *dadjncy) +{ + int i, j, jj, k, kk, kkk, l, m, n, nedges; + idxtype *nptr, *nind; + idxtype *mark; + int table[8][3] = {1, 3, 4, + 0, 2, 5, + 1, 3, 6, + 0, 2, 7, + 0, 5, 7, + 1, 4, 6, + 2, 5, 7, + 3, 4, 6}; + + /* Construct the node-element list first */ + nptr = idxsmalloc(nvtxs+1, 0, "HEXNODALMETIS: nptr"); + for (j=8*nelmnts, i=0; i<j; i++) + nptr[elmnts[i]]++; + MAKECSR(i, nvtxs, nptr); + + nind = idxmalloc(nptr[nvtxs], "HEXNODALMETIS: nind"); + for (k=i=0; i<nelmnts; i++) { + for (j=0; j<8; j++, k++) + nind[nptr[elmnts[k]]++] = i; + } + for (i=nvtxs; i>0; i--) + nptr[i] = nptr[i-1]; + nptr[0] = 0; + + + mark = idxsmalloc(nvtxs, -1, "HEXNODALMETIS: mark"); + + nedges = dxadj[0] = 0; + for (i=0; i<nvtxs; i++) { + mark[i] = i; + for (j=nptr[i]; j<nptr[i+1]; j++) { + jj=8*nind[j]; + for (k=0; k<8; k++) { + if (elmnts[jj+k] == i) + break; + } + ASSERT(k != 8); + + /* You found the index, now go and put the 3 neighbors */ + kk = elmnts[jj+table[k][0]]; + if (mark[kk] != i) { + mark[kk] = i; + dadjncy[nedges++] = kk; + } + kk = elmnts[jj+table[k][1]]; + if (mark[kk] != i) { + mark[kk] = i; + dadjncy[nedges++] = kk; + } + kk = elmnts[jj+table[k][2]]; + if (mark[kk] != i) { + mark[kk] = i; + dadjncy[nedges++] = kk; + } + } + dxadj[i+1] = nedges; + } + + free(mark); + free(nptr); + free(nind); + +} + + +/***************************************************************************** +* This function creates the nodal graph of a finite element mesh +******************************************************************************/ +void QUADNODALMETIS(int nelmnts, int nvtxs, idxtype *elmnts, idxtype *dxadj, idxtype *dadjncy) +{ + int i, j, jj, k, kk, kkk, l, m, n, nedges; + idxtype *nptr, *nind; + idxtype *mark; + int table[4][2] = {1, 3, + 0, 2, + 1, 3, + 0, 2}; + + /* Construct the node-element list first */ + nptr = idxsmalloc(nvtxs+1, 0, "QUADNODALMETIS: nptr"); + for (j=4*nelmnts, i=0; i<j; i++) + nptr[elmnts[i]]++; + MAKECSR(i, nvtxs, nptr); + + nind = idxmalloc(nptr[nvtxs], "QUADNODALMETIS: nind"); + for (k=i=0; i<nelmnts; i++) { + for (j=0; j<4; j++, k++) + nind[nptr[elmnts[k]]++] = i; + } + for (i=nvtxs; i>0; i--) + nptr[i] = nptr[i-1]; + nptr[0] = 0; + + + mark = idxsmalloc(nvtxs, -1, "QUADNODALMETIS: mark"); + + nedges = dxadj[0] = 0; + for (i=0; i<nvtxs; i++) { + mark[i] = i; + for (j=nptr[i]; j<nptr[i+1]; j++) { + jj=4*nind[j]; + for (k=0; k<4; k++) { + if (elmnts[jj+k] == i) + break; + } + ASSERT(k != 4); + + /* You found the index, now go and put the 2 neighbors */ + kk = elmnts[jj+table[k][0]]; + if (mark[kk] != i) { + mark[kk] = i; + dadjncy[nedges++] = kk; + } + kk = elmnts[jj+table[k][1]]; + if (mark[kk] != i) { + mark[kk] = i; + dadjncy[nedges++] = kk; + } + } + dxadj[i+1] = nedges; + } + + free(mark); + free(nptr); + free(nind); + +} diff --git a/contrib/Metis/meshpart.c b/contrib/Metis/meshpart.c new file mode 100644 index 0000000000..e054e46c73 --- /dev/null +++ b/contrib/Metis/meshpart.c @@ -0,0 +1,204 @@ +/* + * Copyright 1997, Regents of the University of Minnesota + * + * meshpart.c + * + * This file contains routines for partitioning finite element meshes. + * + * Started 9/29/97 + * George + * + * $Id: meshpart.c,v 1.1 2005-09-21 17:29:38 geuzaine Exp $ + * + */ + +#include <metis.h> + + +/************************************************************************* +* This function partitions a finite element mesh by partitioning its nodal +* graph using KMETIS and then assigning elements in a load balanced fashion. +**************************************************************************/ +void METIS_PartMeshNodal(int *ne, int *nn, idxtype *elmnts, int *etype, int *numflag, + int *nparts, int *edgecut, idxtype *epart, idxtype *npart) +{ + int i, j, k, me; + idxtype *xadj, *adjncy, *pwgts; + int options[10], pnumflag=0, wgtflag=0; + int nnbrs, nbrind[200], nbrwgt[200], maxpwgt; + int esize, esizes[] = {-1, 3, 4, 8, 4}; + + esize = esizes[*etype]; + + if (*numflag == 1) + ChangeMesh2CNumbering((*ne)*esize, elmnts); + + xadj = idxmalloc(*nn+1, "METIS_MESHPARTNODAL: xadj"); + adjncy = idxmalloc(20*(*nn), "METIS_MESHPARTNODAL: adjncy"); + + METIS_MeshToNodal(ne, nn, elmnts, etype, &pnumflag, xadj, adjncy); + + adjncy = realloc(adjncy, xadj[*nn]*sizeof(idxtype)); + + options[0] = 0; + METIS_PartGraphKway(nn, xadj, adjncy, NULL, NULL, &wgtflag, &pnumflag, nparts, options, edgecut, npart); + + /* OK, now compute an element partition based on the nodal partition npart */ + idxset(*ne, -1, epart); + pwgts = idxsmalloc(*nparts, 0, "METIS_MESHPARTNODAL: pwgts"); + for (i=0; i<*ne; i++) { + me = npart[elmnts[i*esize]]; + for (j=1; j<esize; j++) { + if (npart[elmnts[i*esize+j]] != me) + break; + } + if (j == esize) { + epart[i] = me; + pwgts[me]++; + } + } + + maxpwgt = 1.03*(*ne)/(*nparts); + for (i=0; i<*ne; i++) { + if (epart[i] == -1) { /* Assign the boundary element */ + nnbrs = 0; + for (j=0; j<esize; j++) { + me = npart[elmnts[i*esize+j]]; + for (k=0; k<nnbrs; k++) { + if (nbrind[k] == me) { + nbrwgt[k]++; + break; + } + } + if (k == nnbrs) { + nbrind[nnbrs] = me; + nbrwgt[nnbrs++] = 1; + } + } + /* Try to assign it first to the domain with most things in common */ + j = iamax(nnbrs, nbrwgt); + if (pwgts[nbrind[j]] < maxpwgt) { + epart[i] = nbrind[j]; + } + else { + /* If that fails, assign it to a light domain */ + for (j=0; j<nnbrs; j++) { + if (pwgts[nbrind[j]] < maxpwgt) { + epart[i] = nbrind[j]; + break; + } + } + if (j == nnbrs) + epart[i] = nbrind[iamax(nnbrs, nbrwgt)]; + } + pwgts[epart[i]]++; + } + } + + if (*numflag == 1) + ChangeMesh2FNumbering2((*ne)*esize, elmnts, *ne, *nn, epart, npart); + + GKfree(&xadj, &adjncy, &pwgts, LTERM); + +} + + +/************************************************************************* +* This function partitions a finite element mesh by partitioning its dual +* graph using KMETIS and then assigning nodes in a load balanced fashion. +**************************************************************************/ +void METIS_PartMeshDual(int *ne, int *nn, idxtype *elmnts, int *etype, int *numflag, + int *nparts, int *edgecut, idxtype *epart, idxtype *npart) +{ + int i, j, k, me; + idxtype *xadj, *adjncy, *pwgts, *nptr, *nind; + int options[10], pnumflag=0, wgtflag=0; + int nnbrs, nbrind[200], nbrwgt[200], maxpwgt; + int esize, esizes[] = {-1, 3, 4, 8, 4}; + + esize = esizes[*etype]; + + if (*numflag == 1) + ChangeMesh2CNumbering((*ne)*esize, elmnts); + + xadj = idxmalloc(*ne+1, "METIS_MESHPARTNODAL: xadj"); + adjncy = idxmalloc(esize*(*ne), "METIS_MESHPARTNODAL: adjncy"); + + METIS_MeshToDual(ne, nn, elmnts, etype, &pnumflag, xadj, adjncy); + + options[0] = 0; + METIS_PartGraphKway(ne, xadj, adjncy, NULL, NULL, &wgtflag, &pnumflag, nparts, options, edgecut, epart); + + /* Construct the node-element list */ + nptr = idxsmalloc(*nn+1, 0, "METIS_MESHPARTDUAL: nptr"); + for (j=esize*(*ne), i=0; i<j; i++) + nptr[elmnts[i]]++; + MAKECSR(i, *nn, nptr); + + nind = idxmalloc(nptr[*nn], "METIS_MESHPARTDUAL: nind"); + for (k=i=0; i<(*ne); i++) { + for (j=0; j<esize; j++, k++) + nind[nptr[elmnts[k]]++] = i; + } + for (i=(*nn); i>0; i--) + nptr[i] = nptr[i-1]; + nptr[0] = 0; + + + /* OK, now compute a nodal partition based on the element partition npart */ + idxset(*nn, -1, npart); + pwgts = idxsmalloc(*nparts, 0, "METIS_MESHPARTDUAL: pwgts"); + for (i=0; i<*nn; i++) { + me = epart[nind[nptr[i]]]; + for (j=nptr[i]+1; j<nptr[i+1]; j++) { + if (epart[nind[j]] != me) + break; + } + if (j == nptr[i+1]) { + npart[i] = me; + pwgts[me]++; + } + } + + maxpwgt = 1.03*(*nn)/(*nparts); + for (i=0; i<*nn; i++) { + if (npart[i] == -1) { /* Assign the boundary element */ + nnbrs = 0; + for (j=nptr[i]; j<nptr[i+1]; j++) { + me = epart[nind[j]]; + for (k=0; k<nnbrs; k++) { + if (nbrind[k] == me) { + nbrwgt[k]++; + break; + } + } + if (k == nnbrs) { + nbrind[nnbrs] = me; + nbrwgt[nnbrs++] = 1; + } + } + /* Try to assign it first to the domain with most things in common */ + j = iamax(nnbrs, nbrwgt); + if (pwgts[nbrind[j]] < maxpwgt) { + npart[i] = nbrind[j]; + } + else { + /* If that fails, assign it to a light domain */ + npart[i] = nbrind[0]; + for (j=0; j<nnbrs; j++) { + if (pwgts[nbrind[j]] < maxpwgt) { + npart[i] = nbrind[j]; + break; + } + } + } + pwgts[npart[i]]++; + } + } + + if (*numflag == 1) + ChangeMesh2FNumbering2((*ne)*esize, elmnts, *ne, *nn, epart, npart); + + GKfree(&xadj, &adjncy, &pwgts, &nptr, &nind, LTERM); + +} diff --git a/contrib/Metis/metis.h b/contrib/Metis/metis.h new file mode 100644 index 0000000000..ff4d5ac96b --- /dev/null +++ b/contrib/Metis/metis.h @@ -0,0 +1,37 @@ +/* + * Copyright 1997, Regents of the University of Minnesota + * + * metis.h + * + * This file includes all necessary header files + * + * Started 8/27/94 + * George + * + * $Id: metis.h,v 1.1 2005-09-21 17:29:38 geuzaine Exp $ + */ + + +#include <stdio.h> +#ifdef __STDC__ +#include <stdlib.h> +#else +#include <malloc.h> +#endif +#include <strings.h> +#include <string.h> +#include <ctype.h> +#include <math.h> +#include <stdarg.h> +#include <time.h> + +#ifdef DMALLOC +#include <dmalloc.h> +#endif + +#include <defs.h> +#include <struct.h> +#include <macros.h> +#include <rename.h> +#include <proto.h> + diff --git a/contrib/Metis/mfm.c b/contrib/Metis/mfm.c new file mode 100644 index 0000000000..baf24795d3 --- /dev/null +++ b/contrib/Metis/mfm.c @@ -0,0 +1,344 @@ +/* + * Copyright 1997, Regents of the University of Minnesota + * + * mfm.c + * + * This file contains code that implements the edge-based FM refinement + * + * Started 7/23/97 + * George + * + * $Id: mfm.c,v 1.1 2005-09-21 17:29:38 geuzaine Exp $ + */ + +#include <metis.h> + + +/************************************************************************* +* This function performs an edge-based FM refinement +**************************************************************************/ +void MocFM_2WayEdgeRefine(CtrlType *ctrl, GraphType *graph, float *tpwgts, int npasses) +{ + int i, ii, j, k, l, kwgt, nvtxs, ncon, nbnd, nswaps, from, to, pass, me, limit, tmp, cnum; + idxtype *xadj, *adjncy, *adjwgt, *where, *id, *ed, *bndptr, *bndind; + idxtype *moved, *swaps, *perm, *qnum; + float *nvwgt, *npwgts, mindiff[MAXNCON], origbal, minbal, newbal; + PQueueType parts[MAXNCON][2]; + int higain, oldgain, mincut, initcut, newcut, mincutorder; + float rtpwgts[2]; + + nvtxs = graph->nvtxs; + ncon = graph->ncon; + xadj = graph->xadj; + nvwgt = graph->nvwgt; + adjncy = graph->adjncy; + adjwgt = graph->adjwgt; + where = graph->where; + id = graph->id; + ed = graph->ed; + npwgts = graph->npwgts; + bndptr = graph->bndptr; + bndind = graph->bndind; + + moved = idxwspacemalloc(ctrl, nvtxs); + swaps = idxwspacemalloc(ctrl, nvtxs); + perm = idxwspacemalloc(ctrl, nvtxs); + qnum = idxwspacemalloc(ctrl, nvtxs); + + limit = amin(amax(0.01*nvtxs, 25), 150); + + /* Initialize the queues */ + for (i=0; i<ncon; i++) { + PQueueInit(ctrl, &parts[i][0], nvtxs, PLUS_GAINSPAN+1); + PQueueInit(ctrl, &parts[i][1], nvtxs, PLUS_GAINSPAN+1); + } + for (i=0; i<nvtxs; i++) + qnum[i] = samax(ncon, nvwgt+i*ncon); + + origbal = Compute2WayHLoadImbalance(ncon, npwgts, tpwgts); + + rtpwgts[0] = origbal*tpwgts[0]; + rtpwgts[1] = origbal*tpwgts[1]; + + + if (ctrl->dbglvl&DBG_REFINE) { + printf("Parts: ["); + for (l=0; l<ncon; l++) + printf("(%.3f, %.3f) ", npwgts[l], npwgts[ncon+l]); + printf("] T[%.3f %.3f], Nv-Nb[%5d, %5d]. ICut: %6d, LB: %.3f\n", tpwgts[0], tpwgts[1], graph->nvtxs, graph->nbnd, graph->mincut, origbal); + } + + idxset(nvtxs, -1, moved); + for (pass=0; pass<npasses; pass++) { /* Do a number of passes */ + for (i=0; i<ncon; i++) { + PQueueReset(&parts[i][0]); + PQueueReset(&parts[i][1]); + } + + mincutorder = -1; + newcut = mincut = initcut = graph->mincut; + for (i=0; i<ncon; i++) + mindiff[i] = fabs(tpwgts[0]-npwgts[i]); + minbal = Compute2WayHLoadImbalance(ncon, npwgts, tpwgts); + + ASSERT(ComputeCut(graph, where) == graph->mincut); + ASSERT(CheckBnd(graph)); + + /* Insert boundary nodes in the priority queues */ + nbnd = graph->nbnd; + RandomPermute(nbnd, perm, 1); + for (ii=0; ii<nbnd; ii++) { + i = bndind[perm[ii]]; + ASSERT(ed[i] > 0 || id[i] == 0); + ASSERT(bndptr[i] != -1); + PQueueInsert(&parts[qnum[i]][where[i]], i, ed[i]-id[i]); + } + + for (nswaps=0; nswaps<nvtxs; nswaps++) { + SelectQueue(ncon, npwgts, rtpwgts, &from, &cnum, parts); + to = (from+1)%2; + + if (from == -1 || (higain = PQueueGetMax(&parts[cnum][from])) == -1) + break; + ASSERT(bndptr[higain] != -1); + + saxpy(ncon, 1.0, nvwgt+higain*ncon, 1, npwgts+to*ncon, 1); + saxpy(ncon, -1.0, nvwgt+higain*ncon, 1, npwgts+from*ncon, 1); + + newcut -= (ed[higain]-id[higain]); + newbal = Compute2WayHLoadImbalance(ncon, npwgts, tpwgts); + + if ((newcut < mincut && newbal-origbal <= .00001) || + (newcut == mincut && (newbal < minbal || + (newbal == minbal && BetterBalance(ncon, npwgts, tpwgts, mindiff))))) { + mincut = newcut; + minbal = newbal; + mincutorder = nswaps; + for (i=0; i<ncon; i++) + mindiff[i] = fabs(tpwgts[0]-npwgts[i]); + } + else if (nswaps-mincutorder > limit) { /* We hit the limit, undo last move */ + newcut += (ed[higain]-id[higain]); + saxpy(ncon, 1.0, nvwgt+higain*ncon, 1, npwgts+from*ncon, 1); + saxpy(ncon, -1.0, nvwgt+higain*ncon, 1, npwgts+to*ncon, 1); + break; + } + + where[higain] = to; + moved[higain] = nswaps; + swaps[nswaps] = higain; + + if (ctrl->dbglvl&DBG_MOVEINFO) { + printf("Moved %6d from %d(%d). Gain: %5d, Cut: %5d, NPwgts: ", higain, from, cnum, ed[higain]-id[higain], newcut); + for (l=0; l<ncon; l++) + printf("(%.3f, %.3f) ", npwgts[l], npwgts[ncon+l]); + printf(", %.3f LB: %.3f\n", minbal, newbal); + } + + + /************************************************************** + * Update the id[i]/ed[i] values of the affected nodes + ***************************************************************/ + SWAP(id[higain], ed[higain], tmp); + if (ed[higain] == 0 && xadj[higain] < xadj[higain+1]) + BNDDelete(nbnd, bndind, bndptr, higain); + + for (j=xadj[higain]; j<xadj[higain+1]; j++) { + k = adjncy[j]; + oldgain = ed[k]-id[k]; + + kwgt = (to == where[k] ? adjwgt[j] : -adjwgt[j]); + INC_DEC(id[k], ed[k], kwgt); + + /* Update its boundary information and queue position */ + if (bndptr[k] != -1) { /* If k was a boundary vertex */ + if (ed[k] == 0) { /* Not a boundary vertex any more */ + BNDDelete(nbnd, bndind, bndptr, k); + if (moved[k] == -1) /* Remove it if in the queues */ + PQueueDelete(&parts[qnum[k]][where[k]], k, oldgain); + } + else { /* If it has not been moved, update its position in the queue */ + if (moved[k] == -1) + PQueueUpdate(&parts[qnum[k]][where[k]], k, oldgain, ed[k]-id[k]); + } + } + else { + if (ed[k] > 0) { /* It will now become a boundary vertex */ + BNDInsert(nbnd, bndind, bndptr, k); + if (moved[k] == -1) + PQueueInsert(&parts[qnum[k]][where[k]], k, ed[k]-id[k]); + } + } + } + + } + + + /**************************************************************** + * Roll back computations + *****************************************************************/ + for (i=0; i<nswaps; i++) + moved[swaps[i]] = -1; /* reset moved array */ + for (nswaps--; nswaps>mincutorder; nswaps--) { + higain = swaps[nswaps]; + + to = where[higain] = (where[higain]+1)%2; + SWAP(id[higain], ed[higain], tmp); + if (ed[higain] == 0 && bndptr[higain] != -1 && xadj[higain] < xadj[higain+1]) + BNDDelete(nbnd, bndind, bndptr, higain); + else if (ed[higain] > 0 && bndptr[higain] == -1) + BNDInsert(nbnd, bndind, bndptr, higain); + + saxpy(ncon, 1.0, nvwgt+higain*ncon, 1, npwgts+to*ncon, 1); + saxpy(ncon, -1.0, nvwgt+higain*ncon, 1, npwgts+((to+1)%2)*ncon, 1); + for (j=xadj[higain]; j<xadj[higain+1]; j++) { + k = adjncy[j]; + + kwgt = (to == where[k] ? adjwgt[j] : -adjwgt[j]); + INC_DEC(id[k], ed[k], kwgt); + + if (bndptr[k] != -1 && ed[k] == 0) + BNDDelete(nbnd, bndind, bndptr, k); + if (bndptr[k] == -1 && ed[k] > 0) + BNDInsert(nbnd, bndind, bndptr, k); + } + } + + if (ctrl->dbglvl&DBG_REFINE) { + printf("\tMincut: %6d at %5d, NBND: %6d, NPwgts: [", mincut, mincutorder, nbnd); + for (l=0; l<ncon; l++) + printf("(%.3f, %.3f) ", npwgts[l], npwgts[ncon+l]); + printf("], LB: %.3f\n", Compute2WayHLoadImbalance(ncon, npwgts, tpwgts)); + } + + graph->mincut = mincut; + graph->nbnd = nbnd; + + if (mincutorder == -1 || mincut == initcut) + break; + } + + for (i=0; i<ncon; i++) { + PQueueFree(ctrl, &parts[i][0]); + PQueueFree(ctrl, &parts[i][1]); + } + + idxwspacefree(ctrl, nvtxs); + idxwspacefree(ctrl, nvtxs); + idxwspacefree(ctrl, nvtxs); + idxwspacefree(ctrl, nvtxs); + +} + + +/************************************************************************* +* This function selects the partition number and the queue from which +* we will move vertices out +**************************************************************************/ +void SelectQueue(int ncon, float *npwgts, float *tpwgts, int *from, int *cnum, PQueueType queues[MAXNCON][2]) +{ + int i, part, maxgain=0; + float max, maxdiff=0.0; + + *from = -1; + *cnum = -1; + + /* First determine the side and the queue, irrespective of the presence of nodes */ + for (part=0; part<2; part++) { + for (i=0; i<ncon; i++) { + if (npwgts[part*ncon+i]-tpwgts[part] >= maxdiff) { + maxdiff = npwgts[part*ncon+i]-tpwgts[part]; + *from = part; + *cnum = i; + } + } + } + + /* printf("Selected1 %d(%d) -> %d [%5f]\n", *from, *cnum, PQueueGetSize(&queues[*cnum][*from]), maxdiff); */ + + if (*from != -1 && PQueueGetSize(&queues[*cnum][*from]) == 0) { + /* The desired queue is empty, select a node from that side anyway */ + for (i=0; i<ncon; i++) { + if (PQueueGetSize(&queues[i][*from]) > 0) { + max = npwgts[(*from)*ncon + i]; + *cnum = i; + break; + } + } + + for (i++; i<ncon; i++) { + if (npwgts[(*from)*ncon + i] > max && PQueueGetSize(&queues[i][*from]) > 0) { + max = npwgts[(*from)*ncon + i]; + *cnum = i; + } + } + } + + /* Check to see if you can focus on the cut */ + if (maxdiff <= 0.0 || *from == -1) { + maxgain = -100000; + + for (part=0; part<2; part++) { + for (i=0; i<ncon; i++) { + if (PQueueGetSize(&queues[i][part]) > 0 && PQueueGetKey(&queues[i][part]) > maxgain) { + maxgain = PQueueGetKey(&queues[i][part]); + *from = part; + *cnum = i; + } + } + } + } + + /* printf("Selected2 %d(%d) -> %d\n", *from, *cnum, PQueueGetSize(&queues[*cnum][*from])); */ +} + + + + + +/************************************************************************* +* This function checks if the balance achieved is better than the diff +* For now, it uses a 2-norm measure +**************************************************************************/ +int BetterBalance(int ncon, float *npwgts, float *tpwgts, float *diff) +{ + int i; + float ndiff[MAXNCON]; + + for (i=0; i<ncon; i++) + ndiff[i] = fabs(tpwgts[0]-npwgts[i]); + + return snorm2(ncon, ndiff) < snorm2(ncon, diff); +} + + + +/************************************************************************* +* This function computes the load imbalance over all the constrains +**************************************************************************/ +float Compute2WayHLoadImbalance(int ncon, float *npwgts, float *tpwgts) +{ + int i; + float max=0.0, temp; + + for (i=0; i<ncon; i++) { + /* temp = amax(npwgts[i]/tpwgts[0], npwgts[ncon+i]/tpwgts[1]); */ + temp = fabs(tpwgts[0]-npwgts[i])/tpwgts[0]; + max = (max < temp ? temp : max); + } + return 1.0+max; +} + + +/************************************************************************* +* This function computes the load imbalance over all the constrains +* For now assume that we just want balanced partitionings +**************************************************************************/ +void Compute2WayHLoadImbalanceVec(int ncon, float *npwgts, float *tpwgts, float *lbvec) +{ + int i; + + for (i=0; i<ncon; i++) + lbvec[i] = 1.0 + fabs(tpwgts[0]-npwgts[i])/tpwgts[0]; +} + diff --git a/contrib/Metis/mfm2.c b/contrib/Metis/mfm2.c new file mode 100644 index 0000000000..9b525d8bf7 --- /dev/null +++ b/contrib/Metis/mfm2.c @@ -0,0 +1,349 @@ +/* + * Copyright 1997, Regents of the University of Minnesota + * + * mfm2.c + * + * This file contains code that implements the edge-based FM refinement + * + * Started 7/23/97 + * George + * + * $Id: mfm2.c,v 1.1 2005-09-21 17:29:38 geuzaine Exp $ + */ + +#include <metis.h> + + +/************************************************************************* +* This function performs an edge-based FM refinement +**************************************************************************/ +void MocFM_2WayEdgeRefine2(CtrlType *ctrl, GraphType *graph, float *tpwgts, float *orgubvec, + int npasses) +{ + int i, ii, j, k, l, kwgt, nvtxs, ncon, nbnd, nswaps, from, to, pass, me, limit, tmp, cnum; + idxtype *xadj, *adjncy, *adjwgt, *where, *id, *ed, *bndptr, *bndind; + idxtype *moved, *swaps, *perm, *qnum; + float *nvwgt, *npwgts, origdiff[MAXNCON], origbal[MAXNCON], minbal[MAXNCON]; + PQueueType parts[MAXNCON][2]; + int higain, oldgain, mincut, initcut, newcut, mincutorder; + float *maxwgt, *minwgt, ubvec[MAXNCON], tvec[MAXNCON]; + + nvtxs = graph->nvtxs; + ncon = graph->ncon; + xadj = graph->xadj; + nvwgt = graph->nvwgt; + adjncy = graph->adjncy; + adjwgt = graph->adjwgt; + where = graph->where; + id = graph->id; + ed = graph->ed; + npwgts = graph->npwgts; + bndptr = graph->bndptr; + bndind = graph->bndind; + + moved = idxwspacemalloc(ctrl, nvtxs); + swaps = idxwspacemalloc(ctrl, nvtxs); + perm = idxwspacemalloc(ctrl, nvtxs); + qnum = idxwspacemalloc(ctrl, nvtxs); + + limit = amin(amax(0.01*nvtxs, 15), 100); + + Compute2WayHLoadImbalanceVec(ncon, npwgts, tpwgts, origbal); + for (i=0; i<ncon; i++) { + origdiff[i] = fabs(tpwgts[0]-npwgts[i]); + ubvec[i] = amax(origbal[i], orgubvec[i]); + } + + /* Setup the weight intervals of the two subdomains */ + minwgt = fwspacemalloc(ctrl, 2*ncon); + maxwgt = fwspacemalloc(ctrl, 2*ncon); + + for (i=0; i<2; i++) { + for (j=0; j<ncon; j++) { + maxwgt[i*ncon+j] = tpwgts[i]*ubvec[j]; + minwgt[i*ncon+j] = tpwgts[i]*(1.0/ubvec[j]); + } + } + + /* Initialize the queues */ + for (i=0; i<ncon; i++) { + PQueueInit(ctrl, &parts[i][0], nvtxs, PLUS_GAINSPAN+1); + PQueueInit(ctrl, &parts[i][1], nvtxs, PLUS_GAINSPAN+1); + } + for (i=0; i<nvtxs; i++) + qnum[i] = samax(ncon, nvwgt+i*ncon); + + + if (ctrl->dbglvl&DBG_REFINE) { + printf("Parts: ["); + for (l=0; l<ncon; l++) + printf("(%.3f, %.3f) ", npwgts[l], npwgts[ncon+l]); + printf("] T[%.3f %.3f], Nv-Nb[%5d, %5d]. ICut: %6d, LB: ", tpwgts[0], tpwgts[1], + graph->nvtxs, graph->nbnd, graph->mincut); + for (i=0; i<ncon; i++) + printf("%.3f ", origbal[i]); + printf("\n"); + } + + idxset(nvtxs, -1, moved); + for (pass=0; pass<npasses; pass++) { /* Do a number of passes */ + for (i=0; i<ncon; i++) { + PQueueReset(&parts[i][0]); + PQueueReset(&parts[i][1]); + } + + mincutorder = -1; + newcut = mincut = initcut = graph->mincut; + Compute2WayHLoadImbalanceVec(ncon, npwgts, tpwgts, minbal); + + ASSERT(ComputeCut(graph, where) == graph->mincut); + ASSERT(CheckBnd(graph)); + + /* Insert boundary nodes in the priority queues */ + nbnd = graph->nbnd; + RandomPermute(nbnd, perm, 1); + for (ii=0; ii<nbnd; ii++) { + i = bndind[perm[ii]]; + ASSERT(ed[i] > 0 || id[i] == 0); + ASSERT(bndptr[i] != -1); + PQueueInsert(&parts[qnum[i]][where[i]], i, ed[i]-id[i]); + } + + for (nswaps=0; nswaps<nvtxs; nswaps++) { + SelectQueue2(ncon, npwgts, tpwgts, &from, &cnum, parts, maxwgt); + to = (from+1)%2; + + if (from == -1 || (higain = PQueueGetMax(&parts[cnum][from])) == -1) + break; + ASSERT(bndptr[higain] != -1); + + newcut -= (ed[higain]-id[higain]); + saxpy(ncon, 1.0, nvwgt+higain*ncon, 1, npwgts+to*ncon, 1); + saxpy(ncon, -1.0, nvwgt+higain*ncon, 1, npwgts+from*ncon, 1); + + Compute2WayHLoadImbalanceVec(ncon, npwgts, tpwgts, tvec); + if ((newcut < mincut && AreAllBelow(ncon, tvec, ubvec)) || + (newcut == mincut && IsBetter2wayBalance(ncon, tvec, minbal, ubvec))) { + mincut = newcut; + for (i=0; i<ncon; i++) + minbal[i] = tvec[i]; + mincutorder = nswaps; + } + else if (nswaps-mincutorder > limit) { /* We hit the limit, undo last move */ + newcut += (ed[higain]-id[higain]); + saxpy(ncon, 1.0, nvwgt+higain*ncon, 1, npwgts+from*ncon, 1); + saxpy(ncon, -1.0, nvwgt+higain*ncon, 1, npwgts+to*ncon, 1); + break; + } + + where[higain] = to; + moved[higain] = nswaps; + swaps[nswaps] = higain; + + if (ctrl->dbglvl&DBG_MOVEINFO) { + printf("Moved %6d from %d(%d). Gain: %5d, Cut: %5d, NPwgts: ", higain, from, cnum, ed[higain]-id[higain], newcut); + for (l=0; l<ncon; l++) + printf("(%.3f, %.3f) ", npwgts[l], npwgts[ncon+l]); + + printf(", LB: "); + for (i=0; i<ncon; i++) + printf("%.3f ", tvec[i]); + if (mincutorder == nswaps) + printf(" *\n"); + else + printf("\n"); + } + + + /************************************************************** + * Update the id[i]/ed[i] values of the affected nodes + ***************************************************************/ + SWAP(id[higain], ed[higain], tmp); + if (ed[higain] == 0 && xadj[higain] < xadj[higain+1]) + BNDDelete(nbnd, bndind, bndptr, higain); + + for (j=xadj[higain]; j<xadj[higain+1]; j++) { + k = adjncy[j]; + oldgain = ed[k]-id[k]; + + kwgt = (to == where[k] ? adjwgt[j] : -adjwgt[j]); + INC_DEC(id[k], ed[k], kwgt); + + /* Update its boundary information and queue position */ + if (bndptr[k] != -1) { /* If k was a boundary vertex */ + if (ed[k] == 0) { /* Not a boundary vertex any more */ + BNDDelete(nbnd, bndind, bndptr, k); + if (moved[k] == -1) /* Remove it if in the queues */ + PQueueDelete(&parts[qnum[k]][where[k]], k, oldgain); + } + else { /* If it has not been moved, update its position in the queue */ + if (moved[k] == -1) + PQueueUpdate(&parts[qnum[k]][where[k]], k, oldgain, ed[k]-id[k]); + } + } + else { + if (ed[k] > 0) { /* It will now become a boundary vertex */ + BNDInsert(nbnd, bndind, bndptr, k); + if (moved[k] == -1) + PQueueInsert(&parts[qnum[k]][where[k]], k, ed[k]-id[k]); + } + } + } + + } + + + /**************************************************************** + * Roll back computations + *****************************************************************/ + for (i=0; i<nswaps; i++) + moved[swaps[i]] = -1; /* reset moved array */ + for (nswaps--; nswaps>mincutorder; nswaps--) { + higain = swaps[nswaps]; + + to = where[higain] = (where[higain]+1)%2; + SWAP(id[higain], ed[higain], tmp); + if (ed[higain] == 0 && bndptr[higain] != -1 && xadj[higain] < xadj[higain+1]) + BNDDelete(nbnd, bndind, bndptr, higain); + else if (ed[higain] > 0 && bndptr[higain] == -1) + BNDInsert(nbnd, bndind, bndptr, higain); + + saxpy(ncon, 1.0, nvwgt+higain*ncon, 1, npwgts+to*ncon, 1); + saxpy(ncon, -1.0, nvwgt+higain*ncon, 1, npwgts+((to+1)%2)*ncon, 1); + for (j=xadj[higain]; j<xadj[higain+1]; j++) { + k = adjncy[j]; + + kwgt = (to == where[k] ? adjwgt[j] : -adjwgt[j]); + INC_DEC(id[k], ed[k], kwgt); + + if (bndptr[k] != -1 && ed[k] == 0) + BNDDelete(nbnd, bndind, bndptr, k); + if (bndptr[k] == -1 && ed[k] > 0) + BNDInsert(nbnd, bndind, bndptr, k); + } + } + + if (ctrl->dbglvl&DBG_REFINE) { + printf("\tMincut: %6d at %5d, NBND: %6d, NPwgts: [", mincut, mincutorder, nbnd); + for (l=0; l<ncon; l++) + printf("(%.3f, %.3f) ", npwgts[l], npwgts[ncon+l]); + printf("], LB: "); + Compute2WayHLoadImbalanceVec(ncon, npwgts, tpwgts, tvec); + for (i=0; i<ncon; i++) + printf("%.3f ", tvec[i]); + printf("\n"); + } + + graph->mincut = mincut; + graph->nbnd = nbnd; + + if (mincutorder == -1 || mincut == initcut) + break; + } + + for (i=0; i<ncon; i++) { + PQueueFree(ctrl, &parts[i][0]); + PQueueFree(ctrl, &parts[i][1]); + } + + idxwspacefree(ctrl, nvtxs); + idxwspacefree(ctrl, nvtxs); + idxwspacefree(ctrl, nvtxs); + idxwspacefree(ctrl, nvtxs); + fwspacefree(ctrl, 2*ncon); + fwspacefree(ctrl, 2*ncon); + +} + + +/************************************************************************* +* This function selects the partition number and the queue from which +* we will move vertices out +**************************************************************************/ +void SelectQueue2(int ncon, float *npwgts, float *tpwgts, int *from, int *cnum, + PQueueType queues[MAXNCON][2], float *maxwgt) +{ + int i, j, maxgain=0; + float diff, max, maxdiff=0.0; + + *from = -1; + *cnum = -1; + + /* First determine the side and the queue, irrespective of the presence of nodes */ + for (j=0; j<2; j++) { + for (i=0; i<ncon; i++) { + diff = npwgts[j*ncon+i]-maxwgt[j*ncon+i]; + if (diff >= maxdiff) { + maxdiff = diff; + *from = j; + *cnum = i; + } + } + } + + if (*from != -1 && PQueueGetSize(&queues[*cnum][*from]) == 0) { + /* The desired queue is empty, select a node from that side anyway */ + for (i=0; i<ncon; i++) { + if (PQueueGetSize(&queues[i][*from]) > 0) { + max = (npwgts[(*from)*ncon+i] - maxwgt[(*from)*ncon+i]); + *cnum = i; + break; + } + } + + for (i++; i<ncon; i++) { + diff = npwgts[(*from)*ncon+i] - maxwgt[(*from)*ncon+i]; + if (diff > max && PQueueGetSize(&queues[i][*from]) > 0) { + max = diff; + *cnum = i; + } + } + } + + /* Check to see if you can focus on the cut */ + if (maxdiff <= 0.0 || *from == -1) { + maxgain = -100000; + + for (j=0; j<2; j++) { + for (i=0; i<ncon; i++) { + if (PQueueGetSize(&queues[i][j]) > 0 && PQueueGetKey(&queues[i][j]) > maxgain) { + maxgain = PQueueGetKey(&queues[i][j]); + *from = j; + *cnum = i; + } + } + } + + /* printf("(%2d %2d) %3d\n", *from, *cnum, maxgain); */ + } +} + + +/************************************************************************* +* This function checks if the newbal is better than oldbal given the +* ubvector ubvec +**************************************************************************/ +int IsBetter2wayBalance(int ncon, float *newbal, float *oldbal, float *ubvec) +{ + int i, j; + float max1=0.0, max2=0.0, sum1=0.0, sum2=0.0, tmp; + + for (i=0; i<ncon; i++) { + tmp = (newbal[i]-1)/(ubvec[i]-1); + max1 = (max1 < tmp ? tmp : max1); + sum1 += tmp; + + tmp = (oldbal[i]-1)/(ubvec[i]-1); + max2 = (max2 < tmp ? tmp : max2); + sum2 += tmp; + } + + if (max1 < max2) + return 1; + else if (max1 > max2) + return 0; + else + return sum1 <= sum2; +} + + diff --git a/contrib/Metis/mincover.c b/contrib/Metis/mincover.c new file mode 100644 index 0000000000..0e5a923308 --- /dev/null +++ b/contrib/Metis/mincover.c @@ -0,0 +1,259 @@ +/* + * Copyright 1997, Regents of the University of Minnesota + * + * mincover.c + * + * This file implements the minimum cover algorithm + * + * Started 8/1/97 + * George + * + * $Id: mincover.c,v 1.1 2005-09-21 17:29:38 geuzaine Exp $ + */ + +#include <metis.h> + +/************************************************************************* +* Constants used by mincover algorithm +**************************************************************************/ +#define INCOL 10 +#define INROW 20 +#define VC 1 +#define SC 2 +#define HC 3 +#define VR 4 +#define SR 5 +#define HR 6 + + +/************************************************************************* +* This function returns the min-cover of a bipartite graph. +* The algorithm used is due to Hopcroft and Karp as modified by Duff etal +* adj: the adjacency list of the bipartite graph +* asize: the number of vertices in the first part of the bipartite graph +* bsize-asize: the number of vertices in the second part +* 0..(asize-1) > A vertices +* asize..bsize > B vertices +* +* Returns: +* cover : the actual cover (array) +* csize : the size of the cover +**************************************************************************/ +void MinCover(idxtype *xadj, idxtype *adjncy, int asize, int bsize, idxtype *cover, int *csize) +{ + int i, j; + idxtype *mate, *queue, *flag, *level, *lst; + int fptr, rptr, lstptr; + int row, maxlevel, col; + + mate = idxsmalloc(bsize, -1, "MinCover: mate"); + flag = idxmalloc(bsize, "MinCover: flag"); + level = idxmalloc(bsize, "MinCover: level"); + queue = idxmalloc(bsize, "MinCover: queue"); + lst = idxmalloc(bsize, "MinCover: lst"); + + /* Get a cheap matching */ + for (i=0; i<asize; i++) { + for (j=xadj[i]; j<xadj[i+1]; j++) { + if (mate[adjncy[j]] == -1) { + mate[i] = adjncy[j]; + mate[adjncy[j]] = i; + break; + } + } + } + + /* Get into the main loop */ + while (1) { + /* Initialization */ + fptr = rptr = 0; /* Empty Queue */ + lstptr = 0; /* Empty List */ + for (i=0; i<bsize; i++) { + level[i] = -1; + flag[i] = 0; + } + maxlevel = bsize; + + /* Insert free nodes into the queue */ + for (i=0; i<asize; i++) + if (mate[i] == -1) { + queue[rptr++] = i; + level[i] = 0; + } + + /* Perform the BFS */ + while (fptr != rptr) { + row = queue[fptr++]; + if (level[row] < maxlevel) { + flag[row] = 1; + for (j=xadj[row]; j<xadj[row+1]; j++) { + col = adjncy[j]; + if (!flag[col]) { /* If this column has not been accessed yet */ + flag[col] = 1; + if (mate[col] == -1) { /* Free column node was found */ + maxlevel = level[row]; + lst[lstptr++] = col; + } + else { /* This column node is matched */ + if (flag[mate[col]]) + printf("\nSomething wrong, flag[%d] is 1",mate[col]); + queue[rptr++] = mate[col]; + level[mate[col]] = level[row] + 1; + } + } + } + } + } + + if (lstptr == 0) + break; /* No free columns can be reached */ + + /* Perform restricted DFS from the free column nodes */ + for (i=0; i<lstptr; i++) + MinCover_Augment(xadj, adjncy, lst[i], mate, flag, level, maxlevel); + } + + MinCover_Decompose(xadj, adjncy, asize, bsize, mate, cover, csize); + + GKfree(&mate, &flag, &level, &queue, &lst, LTERM); + +} + + +/************************************************************************* +* This function perfoms a restricted DFS and augments matchings +**************************************************************************/ +int MinCover_Augment(idxtype *xadj, idxtype *adjncy, int col, idxtype *mate, idxtype *flag, idxtype *level, int maxlevel) +{ + int i; + int row = -1; + int status; + + flag[col] = 2; + for (i=xadj[col]; i<xadj[col+1]; i++) { + row = adjncy[i]; + + if (flag[row] == 1) { /* First time through this row node */ + if (level[row] == maxlevel) { /* (col, row) is an edge of the G^T */ + flag[row] = 2; /* Mark this node as being visited */ + if (maxlevel != 0) + status = MinCover_Augment(xadj, adjncy, mate[row], mate, flag, level, maxlevel-1); + else + status = 1; + + if (status) { + mate[col] = row; + mate[row] = col; + return 1; + } + } + } + } + + return 0; +} + + + +/************************************************************************* +* This function performs a coarse decomposition and determines the +* min-cover. +* REF: Pothen ACMTrans. on Amth Software +**************************************************************************/ +void MinCover_Decompose(idxtype *xadj, idxtype *adjncy, int asize, int bsize, idxtype *mate, idxtype *cover, int *csize) +{ + int i, k; + idxtype *where; + int card[10]; + + where = idxmalloc(bsize, "MinCover_Decompose: where"); + for (i=0; i<10; i++) + card[i] = 0; + + for (i=0; i<asize; i++) + where[i] = SC; + for (; i<bsize; i++) + where[i] = SR; + + for (i=0; i<asize; i++) + if (mate[i] == -1) + MinCover_ColDFS(xadj, adjncy, i, mate, where, INCOL); + for (; i<bsize; i++) + if (mate[i] == -1) + MinCover_RowDFS(xadj, adjncy, i, mate, where, INROW); + + for (i=0; i<bsize; i++) + card[where[i]]++; + + k = 0; + if (abs(card[VC]+card[SC]-card[HR]) < abs(card[VC]-card[SR]-card[HR])) { /* S = VC+SC+HR */ + /* printf("%d %d ",vc+sc, hr); */ + for (i=0; i<bsize; i++) + if (where[i] == VC || where[i] == SC || where[i] == HR) + cover[k++] = i; + } + else { /* S = VC+SR+HR */ + /* printf("%d %d ",vc, hr+sr); */ + for (i=0; i<bsize; i++) + if (where[i] == VC || where[i] == SR || where[i] == HR) + cover[k++] = i; + } + + *csize = k; + free(where); + +} + + +/************************************************************************* +* This function perfoms a dfs starting from an unmatched col node +* forming alternate paths +**************************************************************************/ +void MinCover_ColDFS(idxtype *xadj, idxtype *adjncy, int root, idxtype *mate, idxtype *where, int flag) +{ + int i; + + if (flag == INCOL) { + if (where[root] == HC) + return; + where[root] = HC; + for (i=xadj[root]; i<xadj[root+1]; i++) + MinCover_ColDFS(xadj, adjncy, adjncy[i], mate, where, INROW); + } + else { + if (where[root] == HR) + return; + where[root] = HR; + if (mate[root] != -1) + MinCover_ColDFS(xadj, adjncy, mate[root], mate, where, INCOL); + } + +} + +/************************************************************************* +* This function perfoms a dfs starting from an unmatched col node +* forming alternate paths +**************************************************************************/ +void MinCover_RowDFS(idxtype *xadj, idxtype *adjncy, int root, idxtype *mate, idxtype *where, int flag) +{ + int i; + + if (flag == INROW) { + if (where[root] == VR) + return; + where[root] = VR; + for (i=xadj[root]; i<xadj[root+1]; i++) + MinCover_RowDFS(xadj, adjncy, adjncy[i], mate, where, INCOL); + } + else { + if (where[root] == VC) + return; + where[root] = VC; + if (mate[root] != -1) + MinCover_RowDFS(xadj, adjncy, mate[root], mate, where, INROW); + } + +} + + + diff --git a/contrib/Metis/minitpart.c b/contrib/Metis/minitpart.c new file mode 100644 index 0000000000..7b2091fcfd --- /dev/null +++ b/contrib/Metis/minitpart.c @@ -0,0 +1,355 @@ +/* + * Copyright 1997, Regents of the University of Minnesota + * + * minitpart.c + * + * This file contains code that performs the initial partition of the + * coarsest graph + * + * Started 7/23/97 + * George + * + * $Id: minitpart.c,v 1.1 2005-09-21 17:29:38 geuzaine Exp $ + * + */ + +#include <metis.h> + +/************************************************************************* +* This function computes the initial bisection of the coarsest graph +**************************************************************************/ +void MocInit2WayPartition(CtrlType *ctrl, GraphType *graph, float *tpwgts, float ubfactor) +{ + int i, dbglvl; + + dbglvl = ctrl->dbglvl; + IFSET(ctrl->dbglvl, DBG_REFINE, ctrl->dbglvl -= DBG_REFINE); + IFSET(ctrl->dbglvl, DBG_MOVEINFO, ctrl->dbglvl -= DBG_MOVEINFO); + + IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->InitPartTmr)); + + switch (ctrl->IType) { + case IPART_GGPKL: + MocGrowBisection(ctrl, graph, tpwgts, ubfactor); + break; + case IPART_RANDOM: + MocRandomBisection(ctrl, graph, tpwgts, ubfactor); + break; + default: + errexit("Unknown initial partition type: %d\n", ctrl->IType); + } + + IFSET(ctrl->dbglvl, DBG_IPART, printf("Initial Cut: %d [%d]\n", graph->mincut, graph->where[0])); + IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->InitPartTmr)); + ctrl->dbglvl = dbglvl; + +} + + + + + +/************************************************************************* +* This function takes a graph and produces a bisection by using a region +* growing algorithm. The resulting partition is returned in +* graph->where +**************************************************************************/ +void MocGrowBisection(CtrlType *ctrl, GraphType *graph, float *tpwgts, float ubfactor) +{ + int i, j, k, nvtxs, ncon, from, bestcut, mincut, nbfs; + idxtype *bestwhere, *where; + + nvtxs = graph->nvtxs; + + MocAllocate2WayPartitionMemory(ctrl, graph); + where = graph->where; + + bestwhere = idxmalloc(nvtxs, "BisectGraph: bestwhere"); + nbfs = 2*(nvtxs <= ctrl->CoarsenTo ? SMALLNIPARTS : LARGENIPARTS); + bestcut = idxsum(graph->nedges, graph->adjwgt); + + for (; nbfs>0; nbfs--) { + idxset(nvtxs, 1, where); + where[RandomInRange(nvtxs)] = 0; + + MocCompute2WayPartitionParams(ctrl, graph); + + MocInit2WayBalance(ctrl, graph, tpwgts); + + MocFM_2WayEdgeRefine(ctrl, graph, tpwgts, 4); + + MocBalance2Way(ctrl, graph, tpwgts, 1.02); + MocFM_2WayEdgeRefine(ctrl, graph, tpwgts, 4); + + if (bestcut >= graph->mincut) { + bestcut = graph->mincut; + idxcopy(nvtxs, where, bestwhere); + if (bestcut == 0) + break; + } + } + + graph->mincut = bestcut; + idxcopy(nvtxs, bestwhere, where); + + GKfree(&bestwhere, LTERM); +} + + + +/************************************************************************* +* This function takes a graph and produces a bisection by using a region +* growing algorithm. The resulting partition is returned in +* graph->where +**************************************************************************/ +void MocRandomBisection(CtrlType *ctrl, GraphType *graph, float *tpwgts, float ubfactor) +{ + int i, ii, j, k, nvtxs, ncon, from, bestcut, mincut, nbfs, qnum; + idxtype *bestwhere, *where, *perm; + int counts[MAXNCON]; + float *nvwgt; + + nvtxs = graph->nvtxs; + ncon = graph->ncon; + nvwgt = graph->nvwgt; + + MocAllocate2WayPartitionMemory(ctrl, graph); + where = graph->where; + + bestwhere = idxmalloc(nvtxs, "BisectGraph: bestwhere"); + nbfs = 2*(nvtxs <= ctrl->CoarsenTo ? SMALLNIPARTS : LARGENIPARTS); + bestcut = idxsum(graph->nedges, graph->adjwgt); + perm = idxmalloc(nvtxs, "BisectGraph: perm"); + + for (; nbfs>0; nbfs--) { + for (i=0; i<ncon; i++) + counts[i] = 0; + + RandomPermute(nvtxs, perm, 1); + + /* Partition by spliting the queues randomly */ + for (ii=0; ii<nvtxs; ii++) { + i = perm[ii]; + qnum = samax(ncon, nvwgt+i*ncon); + where[i] = counts[qnum]; + counts[qnum] = (counts[qnum]+1)%2; + } + + MocCompute2WayPartitionParams(ctrl, graph); + + MocFM_2WayEdgeRefine(ctrl, graph, tpwgts, 6); + MocBalance2Way(ctrl, graph, tpwgts, 1.02); + MocFM_2WayEdgeRefine(ctrl, graph, tpwgts, 6); + MocBalance2Way(ctrl, graph, tpwgts, 1.02); + MocFM_2WayEdgeRefine(ctrl, graph, tpwgts, 6); + + /* + printf("Edgecut: %6d, NPwgts: [", graph->mincut); + for (i=0; i<graph->ncon; i++) + printf("(%.3f %.3f) ", graph->npwgts[i], graph->npwgts[graph->ncon+i]); + printf("]\n"); + */ + + if (bestcut >= graph->mincut) { + bestcut = graph->mincut; + idxcopy(nvtxs, where, bestwhere); + if (bestcut == 0) + break; + } + } + + graph->mincut = bestcut; + idxcopy(nvtxs, bestwhere, where); + + GKfree(&bestwhere, &perm, LTERM); +} + + + + +/************************************************************************* +* This function balances two partitions by moving the highest gain +* (including negative gain) vertices to the other domain. +* It is used only when tha unbalance is due to non contigous +* subdomains. That is, the are no boundary vertices. +* It moves vertices from the domain that is overweight to the one that +* is underweight. +**************************************************************************/ +void MocInit2WayBalance(CtrlType *ctrl, GraphType *graph, float *tpwgts) +{ + int i, ii, j, k, l, kwgt, nvtxs, nbnd, ncon, nswaps, from, to, pass, me, cnum, tmp; + idxtype *xadj, *adjncy, *adjwgt, *where, *id, *ed, *bndptr, *bndind; + idxtype *perm, *qnum; + float *nvwgt, *npwgts; + PQueueType parts[MAXNCON][2]; + int higain, oldgain, mincut; + + nvtxs = graph->nvtxs; + ncon = graph->ncon; + xadj = graph->xadj; + adjncy = graph->adjncy; + nvwgt = graph->nvwgt; + adjwgt = graph->adjwgt; + where = graph->where; + id = graph->id; + ed = graph->ed; + npwgts = graph->npwgts; + bndptr = graph->bndptr; + bndind = graph->bndind; + + perm = idxwspacemalloc(ctrl, nvtxs); + qnum = idxwspacemalloc(ctrl, nvtxs); + + /* This is called for initial partitioning so we know from where to pick nodes */ + from = 1; + to = (from+1)%2; + + if (ctrl->dbglvl&DBG_REFINE) { + printf("Parts: ["); + for (l=0; l<ncon; l++) + printf("(%.3f, %.3f) ", npwgts[l], npwgts[ncon+l]); + printf("] T[%.3f %.3f], Nv-Nb[%5d, %5d]. ICut: %6d, LB: %.3f [B]\n", tpwgts[0], tpwgts[1], + graph->nvtxs, graph->nbnd, graph->mincut, + Compute2WayHLoadImbalance(ncon, npwgts, tpwgts)); + } + + for (i=0; i<ncon; i++) { + PQueueInit(ctrl, &parts[i][0], nvtxs, PLUS_GAINSPAN+1); + PQueueInit(ctrl, &parts[i][1], nvtxs, PLUS_GAINSPAN+1); + } + + ASSERT(ComputeCut(graph, where) == graph->mincut); + ASSERT(CheckBnd(graph)); + ASSERT(CheckGraph(graph)); + + /* Compute the queues in which each vertex will be assigned to */ + for (i=0; i<nvtxs; i++) + qnum[i] = samax(ncon, nvwgt+i*ncon); + + /* Insert the nodes of the proper partition in the appropriate priority queue */ + RandomPermute(nvtxs, perm, 1); + for (ii=0; ii<nvtxs; ii++) { + i = perm[ii]; + if (where[i] == from) { + if (ed[i] > 0) + PQueueInsert(&parts[qnum[i]][0], i, ed[i]-id[i]); + else + PQueueInsert(&parts[qnum[i]][1], i, ed[i]-id[i]); + } + } + + + mincut = graph->mincut; + nbnd = graph->nbnd; + for (nswaps=0; nswaps<nvtxs; nswaps++) { + if (AreAnyVwgtsBelow(ncon, 1.0, npwgts+from*ncon, 0.0, nvwgt, tpwgts[from])) + break; + + if ((cnum = SelectQueueOneWay(ncon, npwgts, tpwgts, from, parts)) == -1) + break; + + if ((higain = PQueueGetMax(&parts[cnum][0])) == -1) + higain = PQueueGetMax(&parts[cnum][1]); + + mincut -= (ed[higain]-id[higain]); + saxpy(ncon, 1.0, nvwgt+higain*ncon, 1, npwgts+to*ncon, 1); + saxpy(ncon, -1.0, nvwgt+higain*ncon, 1, npwgts+from*ncon, 1); + + where[higain] = to; + + if (ctrl->dbglvl&DBG_MOVEINFO) { + printf("Moved %6d from %d(%d). [%5d] %5d, NPwgts: ", higain, from, cnum, ed[higain]-id[higain], mincut); + for (l=0; l<ncon; l++) + printf("(%.3f, %.3f) ", npwgts[l], npwgts[ncon+l]); + printf(", LB: %.3f\n", Compute2WayHLoadImbalance(ncon, npwgts, tpwgts)); + if (ed[higain] == 0 && id[higain] > 0) + printf("\t Pulled from the interior!\n"); + } + + + /************************************************************** + * Update the id[i]/ed[i] values of the affected nodes + ***************************************************************/ + SWAP(id[higain], ed[higain], tmp); + if (ed[higain] == 0 && bndptr[higain] != -1 && xadj[higain] < xadj[higain+1]) + BNDDelete(nbnd, bndind, bndptr, higain); + if (ed[higain] > 0 && bndptr[higain] == -1) + BNDInsert(nbnd, bndind, bndptr, higain); + + for (j=xadj[higain]; j<xadj[higain+1]; j++) { + k = adjncy[j]; + oldgain = ed[k]-id[k]; + + kwgt = (to == where[k] ? adjwgt[j] : -adjwgt[j]); + INC_DEC(id[k], ed[k], kwgt); + + /* Update the queue position */ + if (where[k] == from) { + if (ed[k] > 0 && bndptr[k] == -1) { /* It moves in boundary */ + PQueueDelete(&parts[qnum[k]][1], k, oldgain); + PQueueInsert(&parts[qnum[k]][0], k, ed[k]-id[k]); + } + else { /* It must be in the boundary already */ + if (bndptr[k] == -1) + printf("What you thought was wrong!\n"); + PQueueUpdate(&parts[qnum[k]][0], k, oldgain, ed[k]-id[k]); + } + } + + /* Update its boundary information */ + if (ed[k] == 0 && bndptr[k] != -1) + BNDDelete(nbnd, bndind, bndptr, k); + else if (ed[k] > 0 && bndptr[k] == -1) + BNDInsert(nbnd, bndind, bndptr, k); + } + + ASSERTP(ComputeCut(graph, where) == mincut, ("%d != %d\n", ComputeCut(graph, where), mincut)); + + } + + if (ctrl->dbglvl&DBG_REFINE) { + printf("\tMincut: %6d, NBND: %6d, NPwgts: ", mincut, nbnd); + for (l=0; l<ncon; l++) + printf("(%.3f, %.3f) ", npwgts[l], npwgts[ncon+l]); + printf(", LB: %.3f\n", Compute2WayHLoadImbalance(ncon, npwgts, tpwgts)); + } + + graph->mincut = mincut; + graph->nbnd = nbnd; + + for (i=0; i<ncon; i++) { + PQueueFree(ctrl, &parts[i][0]); + PQueueFree(ctrl, &parts[i][1]); + } + + ASSERT(ComputeCut(graph, where) == graph->mincut); + ASSERT(CheckBnd(graph)); + + idxwspacefree(ctrl, nvtxs); + idxwspacefree(ctrl, nvtxs); +} + + + + +/************************************************************************* +* This function selects the partition number and the queue from which +* we will move vertices out +**************************************************************************/ +int SelectQueueOneWay(int ncon, float *npwgts, float *tpwgts, int from, PQueueType queues[MAXNCON][2]) +{ + int i, cnum=-1; + float max=0.0; + + for (i=0; i<ncon; i++) { + if (npwgts[from*ncon+i]-tpwgts[from] >= max && + PQueueGetSize(&queues[i][0]) + PQueueGetSize(&queues[i][1]) > 0) { + max = npwgts[from*ncon+i]-tpwgts[0]; + cnum = i; + } + } + + return cnum; +} + + diff --git a/contrib/Metis/minitpart2.c b/contrib/Metis/minitpart2.c new file mode 100644 index 0000000000..bade21bc52 --- /dev/null +++ b/contrib/Metis/minitpart2.c @@ -0,0 +1,368 @@ +/* + * Copyright 1997, Regents of the University of Minnesota + * + * minitpart2.c + * + * This file contains code that performs the initial partition of the + * coarsest graph + * + * Started 7/23/97 + * George + * + * $Id: minitpart2.c,v 1.1 2005-09-21 17:29:38 geuzaine Exp $ + * + */ + +#include <metis.h> + +/************************************************************************* +* This function computes the initial bisection of the coarsest graph +**************************************************************************/ +void MocInit2WayPartition2(CtrlType *ctrl, GraphType *graph, float *tpwgts, float *ubvec) +{ + int dbglvl; + + dbglvl = ctrl->dbglvl; + IFSET(ctrl->dbglvl, DBG_REFINE, ctrl->dbglvl -= DBG_REFINE); + IFSET(ctrl->dbglvl, DBG_MOVEINFO, ctrl->dbglvl -= DBG_MOVEINFO); + + IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->InitPartTmr)); + + switch (ctrl->IType) { + case IPART_GGPKL: + case IPART_RANDOM: + MocGrowBisection2(ctrl, graph, tpwgts, ubvec); + break; + case 3: + MocGrowBisectionNew2(ctrl, graph, tpwgts, ubvec); + break; + default: + errexit("Unknown initial partition type: %d\n", ctrl->IType); + } + + IFSET(ctrl->dbglvl, DBG_IPART, printf("Initial Cut: %d\n", graph->mincut)); + IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->InitPartTmr)); + ctrl->dbglvl = dbglvl; + +} + + + + +/************************************************************************* +* This function takes a graph and produces a bisection by using a region +* growing algorithm. The resulting partition is returned in +* graph->where +**************************************************************************/ +void MocGrowBisection2(CtrlType *ctrl, GraphType *graph, float *tpwgts, float *ubvec) +{ + int i, j, k, nvtxs, ncon, from, bestcut, mincut, nbfs; + idxtype *bestwhere, *where; + + nvtxs = graph->nvtxs; + + MocAllocate2WayPartitionMemory(ctrl, graph); + where = graph->where; + + bestwhere = idxmalloc(nvtxs, "BisectGraph: bestwhere"); + nbfs = 2*(nvtxs <= ctrl->CoarsenTo ? SMALLNIPARTS : LARGENIPARTS); + bestcut = idxsum(graph->nedges, graph->adjwgt); + + for (; nbfs>0; nbfs--) { + idxset(nvtxs, 1, where); + where[RandomInRange(nvtxs)] = 0; + + MocCompute2WayPartitionParams(ctrl, graph); + + MocBalance2Way2(ctrl, graph, tpwgts, ubvec); + + MocFM_2WayEdgeRefine2(ctrl, graph, tpwgts, ubvec, 4); + + MocBalance2Way2(ctrl, graph, tpwgts, ubvec); + MocFM_2WayEdgeRefine2(ctrl, graph, tpwgts, ubvec, 4); + + if (bestcut > graph->mincut) { + bestcut = graph->mincut; + idxcopy(nvtxs, where, bestwhere); + if (bestcut == 0) + break; + } + } + + graph->mincut = bestcut; + idxcopy(nvtxs, bestwhere, where); + + GKfree(&bestwhere, LTERM); +} + + + + + + +/************************************************************************* +* This function takes a graph and produces a bisection by using a region +* growing algorithm. The resulting partition is returned in +* graph->where +**************************************************************************/ +void MocGrowBisectionNew2(CtrlType *ctrl, GraphType *graph, float *tpwgts, float *ubvec) +{ + int i, j, k, nvtxs, ncon, from, bestcut, mincut, nbfs; + idxtype *bestwhere, *where; + + nvtxs = graph->nvtxs; + + MocAllocate2WayPartitionMemory(ctrl, graph); + where = graph->where; + + bestwhere = idxmalloc(nvtxs, "BisectGraph: bestwhere"); + nbfs = 2*(nvtxs <= ctrl->CoarsenTo ? SMALLNIPARTS : LARGENIPARTS); + bestcut = idxsum(graph->nedges, graph->adjwgt); + + for (; nbfs>0; nbfs--) { + idxset(nvtxs, 1, where); + where[RandomInRange(nvtxs)] = 0; + + MocCompute2WayPartitionParams(ctrl, graph); + + MocInit2WayBalance2(ctrl, graph, tpwgts, ubvec); + + MocFM_2WayEdgeRefine2(ctrl, graph, tpwgts, ubvec, 4); + + if (bestcut > graph->mincut) { + bestcut = graph->mincut; + idxcopy(nvtxs, where, bestwhere); + if (bestcut == 0) + break; + } + } + + graph->mincut = bestcut; + idxcopy(nvtxs, bestwhere, where); + + GKfree(&bestwhere, LTERM); +} + + + +/************************************************************************* +* This function balances two partitions by moving the highest gain +* (including negative gain) vertices to the other domain. +* It is used only when tha unbalance is due to non contigous +* subdomains. That is, the are no boundary vertices. +* It moves vertices from the domain that is overweight to the one that +* is underweight. +**************************************************************************/ +void MocInit2WayBalance2(CtrlType *ctrl, GraphType *graph, float *tpwgts, float *ubvec) +{ + int i, ii, j, k, l, kwgt, nvtxs, nbnd, ncon, nswaps, from, to, pass, me, cnum, tmp, imin; + idxtype *xadj, *adjncy, *adjwgt, *where, *id, *ed, *bndptr, *bndind; + idxtype *moved, *perm, *qnum; + float *nvwgt, *npwgts, minwgt; + PQueueType parts[MAXNCON][2]; + int higain, oldgain, mincut; + + nvtxs = graph->nvtxs; + ncon = graph->ncon; + xadj = graph->xadj; + adjncy = graph->adjncy; + nvwgt = graph->nvwgt; + adjwgt = graph->adjwgt; + where = graph->where; + id = graph->id; + ed = graph->ed; + npwgts = graph->npwgts; + bndptr = graph->bndptr; + bndind = graph->bndind; + + moved = idxwspacemalloc(ctrl, nvtxs); + perm = idxwspacemalloc(ctrl, nvtxs); + qnum = idxwspacemalloc(ctrl, nvtxs); + + /* This is called for initial partitioning so we know from where to pick nodes */ + from = 1; + to = (from+1)%2; + + if (ctrl->dbglvl&DBG_REFINE) { + printf("Parts: ["); + for (l=0; l<ncon; l++) + printf("(%.3f, %.3f) ", npwgts[l], npwgts[ncon+l]); + printf("] T[%.3f %.3f], Nv-Nb[%5d, %5d]. ICut: %6d, LB: %.3f [B]\n", tpwgts[0], tpwgts[1], graph->nvtxs, graph->nbnd, graph->mincut, ComputeLoadImbalance(ncon, 2, npwgts, tpwgts)); + } + + for (i=0; i<ncon; i++) { + PQueueInit(ctrl, &parts[i][0], nvtxs, PLUS_GAINSPAN+1); + PQueueInit(ctrl, &parts[i][1], nvtxs, PLUS_GAINSPAN+1); + } + + idxset(nvtxs, -1, moved); + + ASSERT(ComputeCut(graph, where) == graph->mincut); + ASSERT(CheckBnd(graph)); + ASSERT(CheckGraph(graph)); + + /* Compute the queues in which each vertex will be assigned to */ + for (i=0; i<nvtxs; i++) + qnum[i] = samax(ncon, nvwgt+i*ncon); + + /* Insert the nodes of the proper partition in the appropriate priority queue */ + RandomPermute(nvtxs, perm, 1); + for (ii=0; ii<nvtxs; ii++) { + i = perm[ii]; + if (where[i] == from) { + if (ed[i] > 0) + PQueueInsert(&parts[qnum[i]][0], i, ed[i]-id[i]); + else + PQueueInsert(&parts[qnum[i]][1], i, ed[i]-id[i]); + } + } + +/* + for (i=0; i<ncon; i++) + printf("Queue #%d has %d %d\n", i, parts[i][0].nnodes, parts[i][1].nnodes); +*/ + + /* Determine the termination criterion */ + imin = 0; + for (i=1; i<ncon; i++) + imin = (ubvec[i] < ubvec[imin] ? i : imin); + minwgt = .5/ubvec[imin]; + + mincut = graph->mincut; + nbnd = graph->nbnd; + for (nswaps=0; nswaps<nvtxs; nswaps++) { + /* Exit as soon as the minimum weight crossed over */ + if (npwgts[to*ncon+imin] > minwgt) + break; + + if ((cnum = SelectQueueOneWay2(ncon, npwgts+to*ncon, parts, ubvec)) == -1) + break; + + if ((higain = PQueueGetMax(&parts[cnum][0])) == -1) + higain = PQueueGetMax(&parts[cnum][1]); + + mincut -= (ed[higain]-id[higain]); + saxpy(ncon, 1.0, nvwgt+higain*ncon, 1, npwgts+to*ncon, 1); + saxpy(ncon, -1.0, nvwgt+higain*ncon, 1, npwgts+from*ncon, 1); + + where[higain] = to; + moved[higain] = nswaps; + + if (ctrl->dbglvl&DBG_MOVEINFO) { + printf("Moved %6d from %d(%d). [%5d] %5d, NPwgts: ", higain, from, cnum, ed[higain]-id[higain], mincut); + for (l=0; l<ncon; l++) + printf("(%.3f, %.3f) ", npwgts[l], npwgts[ncon+l]); + printf(", LB: %.3f\n", ComputeLoadImbalance(ncon, 2, npwgts, tpwgts)); + if (ed[higain] == 0 && id[higain] > 0) + printf("\t Pulled from the interior!\n"); + } + + + /************************************************************** + * Update the id[i]/ed[i] values of the affected nodes + ***************************************************************/ + SWAP(id[higain], ed[higain], tmp); + if (ed[higain] == 0 && bndptr[higain] != -1 && xadj[higain] < xadj[higain+1]) + BNDDelete(nbnd, bndind, bndptr, higain); + if (ed[higain] > 0 && bndptr[higain] == -1) + BNDInsert(nbnd, bndind, bndptr, higain); + + for (j=xadj[higain]; j<xadj[higain+1]; j++) { + k = adjncy[j]; + oldgain = ed[k]-id[k]; + + kwgt = (to == where[k] ? adjwgt[j] : -adjwgt[j]); + INC_DEC(id[k], ed[k], kwgt); + + /* Update the queue position */ + if (moved[k] == -1 && where[k] == from) { + if (ed[k] > 0 && bndptr[k] == -1) { /* It moves in boundary */ + PQueueDelete(&parts[qnum[k]][1], k, oldgain); + PQueueInsert(&parts[qnum[k]][0], k, ed[k]-id[k]); + } + else { /* It must be in the boundary already */ + if (bndptr[k] == -1) + printf("What you thought was wrong!\n"); + PQueueUpdate(&parts[qnum[k]][0], k, oldgain, ed[k]-id[k]); + } + } + + /* Update its boundary information */ + if (ed[k] == 0 && bndptr[k] != -1) + BNDDelete(nbnd, bndind, bndptr, k); + else if (ed[k] > 0 && bndptr[k] == -1) + BNDInsert(nbnd, bndind, bndptr, k); + } + + ASSERTP(ComputeCut(graph, where) == mincut, ("%d != %d\n", ComputeCut(graph, where), mincut)); + + } + + if (ctrl->dbglvl&DBG_REFINE) { + printf("\tMincut: %6d, NBND: %6d, NPwgts: ", mincut, nbnd); + for (l=0; l<ncon; l++) + printf("(%.3f, %.3f) ", npwgts[l], npwgts[ncon+l]); + printf(", LB: %.3f\n", ComputeLoadImbalance(ncon, 2, npwgts, tpwgts)); + } + + graph->mincut = mincut; + graph->nbnd = nbnd; + + for (i=0; i<ncon; i++) { + PQueueFree(ctrl, &parts[i][0]); + PQueueFree(ctrl, &parts[i][1]); + } + + ASSERT(ComputeCut(graph, where) == graph->mincut); + ASSERT(CheckBnd(graph)); + + idxwspacefree(ctrl, nvtxs); + idxwspacefree(ctrl, nvtxs); + idxwspacefree(ctrl, nvtxs); +} + + + +/************************************************************************* +* This function selects the partition number and the queue from which +* we will move vertices out +**************************************************************************/ +int SelectQueueOneWay2(int ncon, float *pto, PQueueType queues[MAXNCON][2], float *ubvec) +{ + int i, cnum=-1, imax, maxgain; + float max=0.0; + float twgt[MAXNCON]; + + for (i=0; i<ncon; i++) { + if (max < pto[i]) { + imax = i; + max = pto[i]; + } + } + for (i=0; i<ncon; i++) + twgt[i] = (max/(ubvec[imax]*ubvec[i]))/pto[i]; + twgt[imax] = 0.0; + + max = 0.0; + for (i=0; i<ncon; i++) { + if (max < twgt[i] && (PQueueGetSize(&queues[i][0]) > 0 || PQueueGetSize(&queues[i][1]) > 0)) { + max = twgt[i]; + cnum = i; + } + } + if (max > 1) + return cnum; + + /* optimize of cut */ + maxgain = -10000000; + for (i=0; i<ncon; i++) { + if (PQueueGetSize(&queues[i][0]) > 0 && PQueueGetKey(&queues[i][0]) > maxgain) { + maxgain = PQueueGetKey(&queues[i][0]); + cnum = i; + } + } + + return cnum; + +} + diff --git a/contrib/Metis/mkmetis.c b/contrib/Metis/mkmetis.c new file mode 100644 index 0000000000..3edf8575f0 --- /dev/null +++ b/contrib/Metis/mkmetis.c @@ -0,0 +1,123 @@ +/* + * Copyright 1997, Regents of the University of Minnesota + * + * mkmetis.c + * + * This file contains the top level routines for the multilevel k-way partitioning + * algorithm KMETIS. + * + * Started 7/28/97 + * George + * + * $Id: mkmetis.c,v 1.1 2005-09-21 17:29:38 geuzaine Exp $ + * + */ + +#include <metis.h> + + + +/************************************************************************* +* This function is the entry point for KWMETIS +**************************************************************************/ +void METIS_mCPartGraphKway(int *nvtxs, int *ncon, idxtype *xadj, idxtype *adjncy, + idxtype *vwgt, idxtype *adjwgt, int *wgtflag, int *numflag, + int *nparts, float *rubvec, int *options, int *edgecut, + idxtype *part) +{ + int i, j; + GraphType graph; + CtrlType ctrl; + + if (*numflag == 1) + Change2CNumbering(*nvtxs, xadj, adjncy); + + SetUpGraph(&graph, OP_KMETIS, *nvtxs, *ncon, xadj, adjncy, vwgt, adjwgt, *wgtflag); + + if (options[0] == 0) { /* Use the default parameters */ + ctrl.CType = McKMETIS_CTYPE; + ctrl.IType = McKMETIS_ITYPE; + ctrl.RType = McKMETIS_RTYPE; + ctrl.dbglvl = McKMETIS_DBGLVL; + } + else { + ctrl.CType = options[OPTION_CTYPE]; + ctrl.IType = options[OPTION_ITYPE]; + ctrl.RType = options[OPTION_RTYPE]; + ctrl.dbglvl = options[OPTION_DBGLVL]; + } + ctrl.optype = OP_KMETIS; + ctrl.CoarsenTo = amax((*nvtxs)/(20*log2(*nparts)), 30*(*nparts)); + + ctrl.nmaxvwgt = 1.5/(1.0*ctrl.CoarsenTo); + + InitRandom(-1); + + AllocateWorkSpace(&ctrl, &graph, *nparts); + + IFSET(ctrl.dbglvl, DBG_TIME, InitTimers(&ctrl)); + IFSET(ctrl.dbglvl, DBG_TIME, starttimer(ctrl.TotalTmr)); + + *edgecut = MCMlevelKWayPartitioning(&ctrl, &graph, *nparts, part, rubvec); + + IFSET(ctrl.dbglvl, DBG_TIME, stoptimer(ctrl.TotalTmr)); + IFSET(ctrl.dbglvl, DBG_TIME, PrintTimers(&ctrl)); + + FreeWorkSpace(&ctrl, &graph); + + if (*numflag == 1) + Change2FNumbering(*nvtxs, xadj, adjncy, part); +} + + +/************************************************************************* +* This function takes a graph and produces a bisection of it +**************************************************************************/ +int MCMlevelKWayPartitioning(CtrlType *ctrl, GraphType *graph, int nparts, idxtype *part, + float *rubvec) +{ + int i, j, nvtxs; + GraphType *cgraph; + int options[10], edgecut; + + cgraph = MCCoarsen2Way(ctrl, graph); + + IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->InitPartTmr)); + MocAllocateKWayPartitionMemory(ctrl, cgraph, nparts); + + options[0] = 1; + options[OPTION_CTYPE] = MATCH_SBHEM_INFNORM; + options[OPTION_ITYPE] = IPART_RANDOM; + options[OPTION_RTYPE] = RTYPE_FM; + options[OPTION_DBGLVL] = 0; + + /* Determine what you will use as the initial partitioner, based on tolerances */ + for (i=0; i<graph->ncon; i++) { + if (rubvec[i] > 1.2) + break; + } + if (i == graph->ncon) + METIS_mCPartGraphRecursiveInternal(&cgraph->nvtxs, &cgraph->ncon, + cgraph->xadj, cgraph->adjncy, cgraph->nvwgt, cgraph->adjwgt, &nparts, + options, &edgecut, cgraph->where); + else + METIS_mCHPartGraphRecursiveInternal(&cgraph->nvtxs, &cgraph->ncon, + cgraph->xadj, cgraph->adjncy, cgraph->nvwgt, cgraph->adjwgt, &nparts, + rubvec, options, &edgecut, cgraph->where); + + + IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->InitPartTmr)); + IFSET(ctrl->dbglvl, DBG_IPART, printf("Initial %d-way partitioning cut: %d\n", nparts, edgecut)); + + IFSET(ctrl->dbglvl, DBG_KWAYPINFO, ComputePartitionInfo(cgraph, nparts, cgraph->where)); + + MocRefineKWayHorizontal(ctrl, graph, cgraph, nparts, rubvec); + + idxcopy(graph->nvtxs, graph->where, part); + + GKfree(&graph->nvwgt, &graph->npwgts, &graph->gdata, &graph->rdata, LTERM); + + return graph->mincut; + +} + diff --git a/contrib/Metis/mkwayfmh.c b/contrib/Metis/mkwayfmh.c new file mode 100644 index 0000000000..fe0ee41b05 --- /dev/null +++ b/contrib/Metis/mkwayfmh.c @@ -0,0 +1,677 @@ +/* + * mkwayfmh.c + * + * This file contains code that implements the multilevel k-way refinement + * + * Started 7/28/97 + * George + * + * $Id: mkwayfmh.c,v 1.1 2005-09-21 17:29:38 geuzaine Exp $ + * + */ + +#include <metis.h> + + + +/************************************************************************* +* This function performs k-way refinement +**************************************************************************/ +void MCRandom_KWayEdgeRefineHorizontal(CtrlType *ctrl, GraphType *graph, int nparts, + float *orgubvec, int npasses) +{ + int i, ii, iii, j, jj, k, l, pass, nvtxs, ncon, nmoves, nbnd, myndegrees, same; + int from, me, to, oldcut, gain; + idxtype *xadj, *adjncy, *adjwgt; + idxtype *where, *perm, *bndptr, *bndind; + EDegreeType *myedegrees; + RInfoType *myrinfo; + float *npwgts, *nvwgt, *minwgt, *maxwgt, maxlb, minlb, ubvec[MAXNCON], tvec[MAXNCON]; + + nvtxs = graph->nvtxs; + ncon = graph->ncon; + xadj = graph->xadj; + adjncy = graph->adjncy; + adjwgt = graph->adjwgt; + + bndptr = graph->bndptr; + bndind = graph->bndind; + + where = graph->where; + npwgts = graph->npwgts; + + /* Setup the weight intervals of the various subdomains */ + minwgt = fwspacemalloc(ctrl, nparts*ncon); + maxwgt = fwspacemalloc(ctrl, nparts*ncon); + + /* See if the orgubvec consists of identical constraints */ + maxlb = minlb = orgubvec[0]; + for (i=1; i<ncon; i++) { + minlb = (orgubvec[i] < minlb ? orgubvec[i] : minlb); + maxlb = (orgubvec[i] > maxlb ? orgubvec[i] : maxlb); + } + same = (fabs(maxlb-minlb) < .01 ? 1 : 0); + + + /* Let's not get very optimistic. Let Balancing do the work */ + ComputeHKWayLoadImbalance(ncon, nparts, npwgts, ubvec); + for (i=0; i<ncon; i++) + ubvec[i] = amax(ubvec[i], orgubvec[i]); + + if (!same) { + for (i=0; i<nparts; i++) { + for (j=0; j<ncon; j++) { + maxwgt[i*ncon+j] = ubvec[j]/nparts; + minwgt[i*ncon+j] = 1.0/(ubvec[j]*nparts); + } + } + } + else { + maxlb = ubvec[0]; + for (i=1; i<ncon; i++) + maxlb = (ubvec[i] > maxlb ? ubvec[i] : maxlb); + + for (i=0; i<nparts; i++) { + for (j=0; j<ncon; j++) { + maxwgt[i*ncon+j] = maxlb/nparts; + minwgt[i*ncon+j] = 1.0/(maxlb*nparts); + } + } + } + + + perm = idxwspacemalloc(ctrl, nvtxs); + + if (ctrl->dbglvl&DBG_REFINE) { + printf("Partitions: [%5.4f %5.4f], Nv-Nb[%6d %6d]. Cut: %6d, LB: ", + npwgts[samin(ncon*nparts, npwgts)], npwgts[samax(ncon*nparts, npwgts)], + graph->nvtxs, graph->nbnd, graph->mincut); + ComputeHKWayLoadImbalance(ncon, nparts, npwgts, tvec); + for (i=0; i<ncon; i++) + printf("%.3f ", tvec[i]); + printf("\n"); + } + + for (pass=0; pass<npasses; pass++) { + ASSERT(ComputeCut(graph, where) == graph->mincut); + + oldcut = graph->mincut; + nbnd = graph->nbnd; + + RandomPermute(nbnd, perm, 1); + for (nmoves=iii=0; iii<graph->nbnd; iii++) { + ii = perm[iii]; + if (ii >= nbnd) + continue; + i = bndind[ii]; + + myrinfo = graph->rinfo+i; + + if (myrinfo->ed >= myrinfo->id) { /* Total ED is too high */ + from = where[i]; + nvwgt = graph->nvwgt+i*ncon; + + if (myrinfo->id > 0 && AreAllHVwgtsBelow(ncon, 1.0, npwgts+from*ncon, -1.0, nvwgt, minwgt+from*ncon)) + continue; /* This cannot be moved! */ + + myedegrees = myrinfo->edegrees; + myndegrees = myrinfo->ndegrees; + + for (k=0; k<myndegrees; k++) { + to = myedegrees[k].pid; + gain = myedegrees[k].ed - myrinfo->id; + if (gain >= 0 && + (AreAllHVwgtsBelow(ncon, 1.0, npwgts+to*ncon, 1.0, nvwgt, maxwgt+to*ncon) || + IsHBalanceBetterFT(ncon, nparts, npwgts+from*ncon, npwgts+to*ncon, nvwgt, ubvec))) + break; + } + if (k == myndegrees) + continue; /* break out if you did not find a candidate */ + + for (j=k+1; j<myndegrees; j++) { + to = myedegrees[j].pid; + if ((myedegrees[j].ed > myedegrees[k].ed && + (AreAllHVwgtsBelow(ncon, 1.0, npwgts+to*ncon, 1.0, nvwgt, maxwgt+to*ncon) || + IsHBalanceBetterFT(ncon, nparts, npwgts+from*ncon, npwgts+to*ncon, nvwgt, ubvec))) || + (myedegrees[j].ed == myedegrees[k].ed && + IsHBalanceBetterTT(ncon, nparts, npwgts+myedegrees[k].pid*ncon, npwgts+to*ncon, nvwgt, ubvec))) + k = j; + } + + to = myedegrees[k].pid; + + if (myedegrees[k].ed-myrinfo->id == 0 + && !IsHBalanceBetterFT(ncon, nparts, npwgts+from*ncon, npwgts+to*ncon, nvwgt, ubvec) + && AreAllHVwgtsBelow(ncon, 1.0, npwgts+from*ncon, 0.0, npwgts+from*ncon, maxwgt+from*ncon)) + continue; + + /*===================================================================== + * If we got here, we can now move the vertex from 'from' to 'to' + *======================================================================*/ + graph->mincut -= myedegrees[k].ed-myrinfo->id; + + IFSET(ctrl->dbglvl, DBG_MOVEINFO, printf("\t\tMoving %6d to %3d. Gain: %4d. Cut: %6d\n", i, to, myedegrees[k].ed-myrinfo->id, graph->mincut)); + + /* Update where, weight, and ID/ED information of the vertex you moved */ + saxpy(ncon, 1.0, nvwgt, 1, npwgts+to*ncon, 1); + saxpy(ncon, -1.0, nvwgt, 1, npwgts+from*ncon, 1); + where[i] = to; + myrinfo->ed += myrinfo->id-myedegrees[k].ed; + SWAP(myrinfo->id, myedegrees[k].ed, j); + if (myedegrees[k].ed == 0) + myedegrees[k] = myedegrees[--myrinfo->ndegrees]; + else + myedegrees[k].pid = from; + + if (myrinfo->ed-myrinfo->id < 0) + BNDDelete(nbnd, bndind, bndptr, i); + + /* Update the degrees of adjacent vertices */ + for (j=xadj[i]; j<xadj[i+1]; j++) { + ii = adjncy[j]; + me = where[ii]; + + myrinfo = graph->rinfo+ii; + if (myrinfo->edegrees == NULL) { + myrinfo->edegrees = ctrl->wspace.edegrees+ctrl->wspace.cdegree; + ctrl->wspace.cdegree += xadj[ii+1]-xadj[ii]; + } + myedegrees = myrinfo->edegrees; + + ASSERT(CheckRInfo(myrinfo)); + + if (me == from) { + INC_DEC(myrinfo->ed, myrinfo->id, adjwgt[j]); + + if (myrinfo->ed-myrinfo->id >= 0 && bndptr[ii] == -1) + BNDInsert(nbnd, bndind, bndptr, ii); + } + else if (me == to) { + INC_DEC(myrinfo->id, myrinfo->ed, adjwgt[j]); + + if (myrinfo->ed-myrinfo->id < 0 && bndptr[ii] != -1) + BNDDelete(nbnd, bndind, bndptr, ii); + } + + /* Remove contribution from the .ed of 'from' */ + if (me != from) { + for (k=0; k<myrinfo->ndegrees; k++) { + if (myedegrees[k].pid == from) { + if (myedegrees[k].ed == adjwgt[j]) + myedegrees[k] = myedegrees[--myrinfo->ndegrees]; + else + myedegrees[k].ed -= adjwgt[j]; + break; + } + } + } + + /* Add contribution to the .ed of 'to' */ + if (me != to) { + for (k=0; k<myrinfo->ndegrees; k++) { + if (myedegrees[k].pid == to) { + myedegrees[k].ed += adjwgt[j]; + break; + } + } + if (k == myrinfo->ndegrees) { + myedegrees[myrinfo->ndegrees].pid = to; + myedegrees[myrinfo->ndegrees++].ed = adjwgt[j]; + } + } + + ASSERT(myrinfo->ndegrees <= xadj[ii+1]-xadj[ii]); + ASSERT(CheckRInfo(myrinfo)); + + } + nmoves++; + } + } + + graph->nbnd = nbnd; + + if (ctrl->dbglvl&DBG_REFINE) { + printf("\t [%5.4f %5.4f], Nb: %6d, Nmoves: %5d, Cut: %6d, LB: ", + npwgts[samin(ncon*nparts, npwgts)], npwgts[samax(ncon*nparts, npwgts)], + nbnd, nmoves, graph->mincut); + ComputeHKWayLoadImbalance(ncon, nparts, npwgts, tvec); + for (i=0; i<ncon; i++) + printf("%.3f ", tvec[i]); + printf("\n"); + } + + if (graph->mincut == oldcut) + break; + } + + fwspacefree(ctrl, ncon*nparts); + fwspacefree(ctrl, ncon*nparts); + idxwspacefree(ctrl, nvtxs); +} + + + +/************************************************************************* +* This function performs k-way refinement +**************************************************************************/ +void MCGreedy_KWayEdgeBalanceHorizontal(CtrlType *ctrl, GraphType *graph, int nparts, + float *ubvec, int npasses) +{ + int i, ii, iii, j, jj, k, l, pass, nvtxs, ncon, nbnd, myndegrees, oldgain, gain, nmoves; + int from, me, to, oldcut; + idxtype *xadj, *adjncy, *adjwgt; + idxtype *where, *perm, *bndptr, *bndind, *moved; + EDegreeType *myedegrees; + RInfoType *myrinfo; + PQueueType queue; + float *npwgts, *nvwgt, *minwgt, *maxwgt, tvec[MAXNCON]; + + nvtxs = graph->nvtxs; + ncon = graph->ncon; + xadj = graph->xadj; + adjncy = graph->adjncy; + adjwgt = graph->adjwgt; + + bndind = graph->bndind; + bndptr = graph->bndptr; + + where = graph->where; + npwgts = graph->npwgts; + + /* Setup the weight intervals of the various subdomains */ + minwgt = fwspacemalloc(ctrl, ncon*nparts); + maxwgt = fwspacemalloc(ctrl, ncon*nparts); + + for (i=0; i<nparts; i++) { + for (j=0; j<ncon; j++) { + maxwgt[i*ncon+j] = ubvec[j]/nparts; + minwgt[i*ncon+j] = 1.0/(ubvec[j]*nparts); + } + } + + perm = idxwspacemalloc(ctrl, nvtxs); + moved = idxwspacemalloc(ctrl, nvtxs); + + PQueueInit(ctrl, &queue, nvtxs, graph->adjwgtsum[idxamax(nvtxs, graph->adjwgtsum)]); + + if (ctrl->dbglvl&DBG_REFINE) { + printf("Partitions: [%5.4f %5.4f], Nv-Nb[%6d %6d]. Cut: %6d, LB: ", + npwgts[samin(ncon*nparts, npwgts)], npwgts[samax(ncon*nparts, npwgts)], + graph->nvtxs, graph->nbnd, graph->mincut); + ComputeHKWayLoadImbalance(ncon, nparts, npwgts, tvec); + for (i=0; i<ncon; i++) + printf("%.3f ", tvec[i]); + printf("[B]\n"); + } + + + for (pass=0; pass<npasses; pass++) { + ASSERT(ComputeCut(graph, where) == graph->mincut); + + /* Check to see if things are out of balance, given the tolerance */ + if (MocIsHBalanced(ncon, nparts, npwgts, ubvec)) + break; + + PQueueReset(&queue); + idxset(nvtxs, -1, moved); + + oldcut = graph->mincut; + nbnd = graph->nbnd; + + RandomPermute(nbnd, perm, 1); + for (ii=0; ii<nbnd; ii++) { + i = bndind[perm[ii]]; + PQueueInsert(&queue, i, graph->rinfo[i].ed - graph->rinfo[i].id); + moved[i] = 2; + } + + nmoves = 0; + for (;;) { + if ((i = PQueueGetMax(&queue)) == -1) + break; + moved[i] = 1; + + myrinfo = graph->rinfo+i; + from = where[i]; + nvwgt = graph->nvwgt+i*ncon; + + if (AreAllHVwgtsBelow(ncon, 1.0, npwgts+from*ncon, -1.0, nvwgt, minwgt+from*ncon)) + continue; /* This cannot be moved! */ + + myedegrees = myrinfo->edegrees; + myndegrees = myrinfo->ndegrees; + + for (k=0; k<myndegrees; k++) { + to = myedegrees[k].pid; + if (IsHBalanceBetterFT(ncon, nparts, npwgts+from*ncon, npwgts+to*ncon, nvwgt, ubvec)) + break; + } + if (k == myndegrees) + continue; /* break out if you did not find a candidate */ + + for (j=k+1; j<myndegrees; j++) { + to = myedegrees[j].pid; + if (IsHBalanceBetterTT(ncon, nparts, npwgts+myedegrees[k].pid*ncon, npwgts+to*ncon, nvwgt, ubvec)) + k = j; + } + + to = myedegrees[k].pid; + + j = 0; + if (!AreAllHVwgtsBelow(ncon, 1.0, npwgts+from*ncon, 0.0, nvwgt, maxwgt+from*ncon)) + j++; + if (myedegrees[k].ed-myrinfo->id >= 0) + j++; + if (!AreAllHVwgtsAbove(ncon, 1.0, npwgts+to*ncon, 0.0, nvwgt, minwgt+to*ncon) && + AreAllHVwgtsBelow(ncon, 1.0, npwgts+to*ncon, 1.0, nvwgt, maxwgt+to*ncon)) + j++; + if (j == 0) + continue; + +/* DELETE + if (myedegrees[k].ed-myrinfo->id < 0 && + AreAllHVwgtsBelow(ncon, 1.0, npwgts+from*ncon, 0.0, nvwgt, maxwgt+from*ncon) && + AreAllHVwgtsAbove(ncon, 1.0, npwgts+to*ncon, 0.0, nvwgt, minwgt+to*ncon) && + AreAllHVwgtsBelow(ncon, 1.0, npwgts+to*ncon, 1.0, nvwgt, maxwgt+to*ncon)) + continue; +*/ + /*===================================================================== + * If we got here, we can now move the vertex from 'from' to 'to' + *======================================================================*/ + graph->mincut -= myedegrees[k].ed-myrinfo->id; + + IFSET(ctrl->dbglvl, DBG_MOVEINFO, printf("\t\tMoving %6d to %3d. Gain: %4d. Cut: %6d\n", i, to, myedegrees[k].ed-myrinfo->id, graph->mincut)); + + /* Update where, weight, and ID/ED information of the vertex you moved */ + saxpy(ncon, 1.0, nvwgt, 1, npwgts+to*ncon, 1); + saxpy(ncon, -1.0, nvwgt, 1, npwgts+from*ncon, 1); + where[i] = to; + myrinfo->ed += myrinfo->id-myedegrees[k].ed; + SWAP(myrinfo->id, myedegrees[k].ed, j); + if (myedegrees[k].ed == 0) + myedegrees[k] = myedegrees[--myrinfo->ndegrees]; + else + myedegrees[k].pid = from; + + if (myrinfo->ed == 0) + BNDDelete(nbnd, bndind, bndptr, i); + + /* Update the degrees of adjacent vertices */ + for (j=xadj[i]; j<xadj[i+1]; j++) { + ii = adjncy[j]; + me = where[ii]; + + myrinfo = graph->rinfo+ii; + if (myrinfo->edegrees == NULL) { + myrinfo->edegrees = ctrl->wspace.edegrees+ctrl->wspace.cdegree; + ctrl->wspace.cdegree += xadj[ii+1]-xadj[ii]; + } + myedegrees = myrinfo->edegrees; + + ASSERT(CheckRInfo(myrinfo)); + + oldgain = (myrinfo->ed-myrinfo->id); + + if (me == from) { + INC_DEC(myrinfo->ed, myrinfo->id, adjwgt[j]); + + if (myrinfo->ed > 0 && bndptr[ii] == -1) + BNDInsert(nbnd, bndind, bndptr, ii); + } + else if (me == to) { + INC_DEC(myrinfo->id, myrinfo->ed, adjwgt[j]); + + if (myrinfo->ed == 0 && bndptr[ii] != -1) + BNDDelete(nbnd, bndind, bndptr, ii); + } + + /* Remove contribution from the .ed of 'from' */ + if (me != from) { + for (k=0; k<myrinfo->ndegrees; k++) { + if (myedegrees[k].pid == from) { + if (myedegrees[k].ed == adjwgt[j]) + myedegrees[k] = myedegrees[--myrinfo->ndegrees]; + else + myedegrees[k].ed -= adjwgt[j]; + break; + } + } + } + + /* Add contribution to the .ed of 'to' */ + if (me != to) { + for (k=0; k<myrinfo->ndegrees; k++) { + if (myedegrees[k].pid == to) { + myedegrees[k].ed += adjwgt[j]; + break; + } + } + if (k == myrinfo->ndegrees) { + myedegrees[myrinfo->ndegrees].pid = to; + myedegrees[myrinfo->ndegrees++].ed = adjwgt[j]; + } + } + + + /* Update the queue */ + if (me == to || me == from) { + gain = myrinfo->ed-myrinfo->id; + if (moved[ii] == 2) { + if (myrinfo->ed > 0) + PQueueUpdate(&queue, ii, oldgain, gain); + else { + PQueueDelete(&queue, ii, oldgain); + moved[ii] = -1; + } + } + else if (moved[ii] == -1 && myrinfo->ed > 0) { + PQueueInsert(&queue, ii, gain); + moved[ii] = 2; + } + } + + ASSERT(myrinfo->ndegrees <= xadj[ii+1]-xadj[ii]); + ASSERT(CheckRInfo(myrinfo)); + } + nmoves++; + } + + graph->nbnd = nbnd; + + if (ctrl->dbglvl&DBG_REFINE) { + printf("\t [%5.4f %5.4f], Nb: %6d, Nmoves: %5d, Cut: %6d, LB: ", + npwgts[samin(ncon*nparts, npwgts)], npwgts[samax(ncon*nparts, npwgts)], + nbnd, nmoves, graph->mincut); + ComputeHKWayLoadImbalance(ncon, nparts, npwgts, tvec); + for (i=0; i<ncon; i++) + printf("%.3f ", tvec[i]); + printf("\n"); + } + + if (nmoves == 0) + break; + } + + PQueueFree(ctrl, &queue); + + fwspacefree(ctrl, ncon*nparts); + fwspacefree(ctrl, ncon*nparts); + idxwspacefree(ctrl, nvtxs); + idxwspacefree(ctrl, nvtxs); + +} + + + + + +/************************************************************************* +* This function checks if the vertex weights of two vertices are below +* a given set of values +**************************************************************************/ +int AreAllHVwgtsBelow(int ncon, float alpha, float *vwgt1, float beta, float *vwgt2, float *limit) +{ + int i; + + for (i=0; i<ncon; i++) + if (alpha*vwgt1[i] + beta*vwgt2[i] > limit[i]) + return 0; + + return 1; +} + + + +/************************************************************************* +* This function checks if the vertex weights of two vertices are above +* a given set of values +**************************************************************************/ +int AreAllHVwgtsAbove(int ncon, float alpha, float *vwgt1, float beta, float *vwgt2, float *limit) +{ + int i; + + for (i=0; i<ncon; i++) + if (alpha*vwgt1[i] + beta*vwgt2[i] < limit[i]) + return 0; + + return 1; +} + + +/************************************************************************* +* This function computes the load imbalance over all the constrains +* For now assume that we just want balanced partitionings +**************************************************************************/ +void ComputeHKWayLoadImbalance(int ncon, int nparts, float *npwgts, float *lbvec) +{ + int i, j; + float max; + + for (i=0; i<ncon; i++) { + max = 0.0; + for (j=0; j<nparts; j++) { + if (npwgts[j*ncon+i] > max) + max = npwgts[j*ncon+i]; + } + + lbvec[i] = max*nparts; + } +} + + +/************************************************************************* +* This function determines if a partitioning is horizontally balanced +**************************************************************************/ +int MocIsHBalanced(int ncon, int nparts, float *npwgts, float *ubvec) +{ + int i, j; + float max; + + for (i=0; i<ncon; i++) { + max = 0.0; + for (j=0; j<nparts; j++) { + if (npwgts[j*ncon+i] > max) + max = npwgts[j*ncon+i]; + } + + if (ubvec[i] < max*nparts) + return 0; + } + + return 1; +} + + + + + +/************************************************************************* +* This function checks if the pairwise balance of the between the two +* partitions will improve by moving the vertex v from pfrom to pto, +* subject to the target partition weights of tfrom, and tto respectively +**************************************************************************/ +int IsHBalanceBetterFT(int ncon, int nparts, float *pfrom, float *pto, float *vwgt, float *ubvec) +{ + int i, j, k; + float blb1=0.0, alb1=0.0, sblb=0.0, salb=0.0; + float blb2=0.0, alb2=0.0; + float temp; + + for (i=0; i<ncon; i++) { + temp = amax(pfrom[i], pto[i])*nparts/ubvec[i]; + if (blb1 < temp) { + blb2 = blb1; + blb1 = temp; + } + else if (blb2 < temp) + blb2 = temp; + sblb += temp; + + temp = amax(pfrom[i]-vwgt[i], pto[i]+vwgt[i])*nparts/ubvec[i]; + if (alb1 < temp) { + alb2 = alb1; + alb1 = temp; + } + else if (alb2 < temp) + alb2 = temp; + salb += temp; + } + + if (alb1 < blb1) + return 1; + if (blb1 < alb1) + return 0; + if (alb2 < blb2) + return 1; + if (blb2 < alb2) + return 0; + + return salb < sblb; + +} + + + + +/************************************************************************* +* This function checks if it will be better to move a vertex to pt2 than +* to pt1 subject to their target weights of tt1 and tt2, respectively +* This routine takes into account the weight of the vertex in question +**************************************************************************/ +int IsHBalanceBetterTT(int ncon, int nparts, float *pt1, float *pt2, float *vwgt, float *ubvec) +{ + int i; + float m11=0.0, m12=0.0, m21=0.0, m22=0.0, sm1=0.0, sm2=0.0, temp; + + for (i=0; i<ncon; i++) { + temp = (pt1[i]+vwgt[i])*nparts/ubvec[i]; + if (m11 < temp) { + m12 = m11; + m11 = temp; + } + else if (m12 < temp) + m12 = temp; + sm1 += temp; + + temp = (pt2[i]+vwgt[i])*nparts/ubvec[i]; + if (m21 < temp) { + m22 = m21; + m21 = temp; + } + else if (m22 < temp) + m22 = temp; + sm2 += temp; + } + + if (m21 < m11) + return 1; + if (m21 > m11) + return 0; + if (m22 < m12) + return 1; + if (m22 > m12) + return 0; + + return sm2 < sm1; +} + diff --git a/contrib/Metis/mkwayrefine.c b/contrib/Metis/mkwayrefine.c new file mode 100644 index 0000000000..24000aec1a --- /dev/null +++ b/contrib/Metis/mkwayrefine.c @@ -0,0 +1,297 @@ +/* + * Copyright 1997, Regents of the University of Minnesota + * + * mkwayrefine.c + * + * This file contains the driving routines for multilevel k-way refinement + * + * Started 7/28/97 + * George + * + * $Id: mkwayrefine.c,v 1.1 2005-09-21 17:29:38 geuzaine Exp $ + */ + +#include <metis.h> + + +/************************************************************************* +* This function is the entry point of refinement +**************************************************************************/ +void MocRefineKWayHorizontal(CtrlType *ctrl, GraphType *orggraph, GraphType *graph, int nparts, + float *ubvec) +{ + + IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->UncoarsenTmr)); + + /* Compute the parameters of the coarsest graph */ + MocComputeKWayPartitionParams(ctrl, graph, nparts); + + for (;;) { + IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->RefTmr)); + + if (!MocIsHBalanced(graph->ncon, nparts, graph->npwgts, ubvec)) { + MocComputeKWayBalanceBoundary(ctrl, graph, nparts); + MCGreedy_KWayEdgeBalanceHorizontal(ctrl, graph, nparts, ubvec, 4); + ComputeKWayBoundary(ctrl, graph, nparts); + } + + MCRandom_KWayEdgeRefineHorizontal(ctrl, graph, nparts, ubvec, 10); + + IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->RefTmr)); + + if (graph == orggraph) + break; + + graph = graph->finer; + IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->ProjectTmr)); + MocProjectKWayPartition(ctrl, graph, nparts); + IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->ProjectTmr)); + } + + if (!MocIsHBalanced(graph->ncon, nparts, graph->npwgts, ubvec)) { + MocComputeKWayBalanceBoundary(ctrl, graph, nparts); + MCGreedy_KWayEdgeBalanceHorizontal(ctrl, graph, nparts, ubvec, 4); + ComputeKWayBoundary(ctrl, graph, nparts); + MCRandom_KWayEdgeRefineHorizontal(ctrl, graph, nparts, ubvec, 10); + } + + IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->UncoarsenTmr)); +} + + + + +/************************************************************************* +* This function allocates memory for k-way edge refinement +**************************************************************************/ +void MocAllocateKWayPartitionMemory(CtrlType *ctrl, GraphType *graph, int nparts) +{ + int nvtxs, ncon, pad64; + + nvtxs = graph->nvtxs; + ncon = graph->ncon; + + pad64 = (3*nvtxs)%2; + + graph->rdata = idxmalloc(3*nvtxs+(sizeof(RInfoType)/sizeof(idxtype))*nvtxs+pad64, "AllocateKWayPartitionMemory: rdata"); + graph->where = graph->rdata; + graph->bndptr = graph->rdata + nvtxs; + graph->bndind = graph->rdata + 2*nvtxs; + graph->rinfo = (RInfoType *)(graph->rdata + 3*nvtxs + pad64); + + graph->npwgts = fmalloc(ncon*nparts, "MocAllocateKWayPartitionMemory: npwgts"); +} + + +/************************************************************************* +* This function computes the initial id/ed +**************************************************************************/ +void MocComputeKWayPartitionParams(CtrlType *ctrl, GraphType *graph, int nparts) +{ + int i, j, k, l, nvtxs, ncon, nbnd, mincut, me, other; + idxtype *xadj, *adjncy, *adjwgt, *where, *bndind, *bndptr; + RInfoType *rinfo, *myrinfo; + EDegreeType *myedegrees; + float *nvwgt, *npwgts; + + nvtxs = graph->nvtxs; + ncon = graph->ncon; + xadj = graph->xadj; + nvwgt = graph->nvwgt; + adjncy = graph->adjncy; + adjwgt = graph->adjwgt; + + where = graph->where; + npwgts = sset(ncon*nparts, 0.0, graph->npwgts); + bndind = graph->bndind; + bndptr = idxset(nvtxs, -1, graph->bndptr); + rinfo = graph->rinfo; + + + /*------------------------------------------------------------ + / Compute now the id/ed degrees + /------------------------------------------------------------*/ + ctrl->wspace.cdegree = 0; + nbnd = mincut = 0; + for (i=0; i<nvtxs; i++) { + me = where[i]; + saxpy(ncon, 1.0, nvwgt+i*ncon, 1, npwgts+me*ncon, 1); + + myrinfo = rinfo+i; + myrinfo->id = myrinfo->ed = myrinfo->ndegrees = 0; + myrinfo->edegrees = NULL; + + for (j=xadj[i]; j<xadj[i+1]; j++) { + if (me != where[adjncy[j]]) + myrinfo->ed += adjwgt[j]; + } + myrinfo->id = graph->adjwgtsum[i] - myrinfo->ed; + + if (myrinfo->ed > 0) + mincut += myrinfo->ed; + + if (myrinfo->ed-myrinfo->id >= 0) + BNDInsert(nbnd, bndind, bndptr, i); + + /* Time to compute the particular external degrees */ + if (myrinfo->ed > 0) { + myedegrees = myrinfo->edegrees = ctrl->wspace.edegrees+ctrl->wspace.cdegree; + ctrl->wspace.cdegree += xadj[i+1]-xadj[i]; + + for (j=xadj[i]; j<xadj[i+1]; j++) { + other = where[adjncy[j]]; + if (me != other) { + for (k=0; k<myrinfo->ndegrees; k++) { + if (myedegrees[k].pid == other) { + myedegrees[k].ed += adjwgt[j]; + break; + } + } + if (k == myrinfo->ndegrees) { + myedegrees[myrinfo->ndegrees].pid = other; + myedegrees[myrinfo->ndegrees++].ed = adjwgt[j]; + } + } + } + + ASSERT(myrinfo->ndegrees <= xadj[i+1]-xadj[i]); + } + } + + graph->mincut = mincut/2; + graph->nbnd = nbnd; + +} + + + +/************************************************************************* +* This function projects a partition, and at the same time computes the +* parameters for refinement. +**************************************************************************/ +void MocProjectKWayPartition(CtrlType *ctrl, GraphType *graph, int nparts) +{ + int i, j, k, nvtxs, nbnd, me, other, istart, iend, ndegrees; + idxtype *xadj, *adjncy, *adjwgt, *adjwgtsum; + idxtype *cmap, *where, *bndptr, *bndind; + idxtype *cwhere; + GraphType *cgraph; + RInfoType *crinfo, *rinfo, *myrinfo; + EDegreeType *myedegrees; + idxtype *htable; + + cgraph = graph->coarser; + cwhere = cgraph->where; + crinfo = cgraph->rinfo; + + nvtxs = graph->nvtxs; + cmap = graph->cmap; + xadj = graph->xadj; + adjncy = graph->adjncy; + adjwgt = graph->adjwgt; + adjwgtsum = graph->adjwgtsum; + + MocAllocateKWayPartitionMemory(ctrl, graph, nparts); + where = graph->where; + rinfo = graph->rinfo; + bndind = graph->bndind; + bndptr = idxset(nvtxs, -1, graph->bndptr); + + /* Go through and project partition and compute id/ed for the nodes */ + for (i=0; i<nvtxs; i++) { + k = cmap[i]; + where[i] = cwhere[k]; + cmap[i] = crinfo[k].ed; /* For optimization */ + } + + htable = idxset(nparts, -1, idxwspacemalloc(ctrl, nparts)); + + ctrl->wspace.cdegree = 0; + for (nbnd=0, i=0; i<nvtxs; i++) { + me = where[i]; + + myrinfo = rinfo+i; + myrinfo->id = myrinfo->ed = myrinfo->ndegrees = 0; + myrinfo->edegrees = NULL; + + myrinfo->id = adjwgtsum[i]; + + if (cmap[i] > 0) { /* If it is an interface node. Note cmap[i] = crinfo[cmap[i]].ed */ + istart = xadj[i]; + iend = xadj[i+1]; + + myedegrees = myrinfo->edegrees = ctrl->wspace.edegrees+ctrl->wspace.cdegree; + ctrl->wspace.cdegree += iend-istart; + + ndegrees = 0; + for (j=istart; j<iend; j++) { + other = where[adjncy[j]]; + if (me != other) { + myrinfo->ed += adjwgt[j]; + if ((k = htable[other]) == -1) { + htable[other] = ndegrees; + myedegrees[ndegrees].pid = other; + myedegrees[ndegrees++].ed = adjwgt[j]; + } + else { + myedegrees[k].ed += adjwgt[j]; + } + } + } + myrinfo->id -= myrinfo->ed; + + /* Remove space for edegrees if it was interior */ + if (myrinfo->ed == 0) { + myrinfo->edegrees = NULL; + ctrl->wspace.cdegree -= iend-istart; + } + else { + if (myrinfo->ed-myrinfo->id >= 0) + BNDInsert(nbnd, bndind, bndptr, i); + + myrinfo->ndegrees = ndegrees; + + for (j=0; j<ndegrees; j++) + htable[myedegrees[j].pid] = -1; + } + } + } + + scopy(graph->ncon*nparts, cgraph->npwgts, graph->npwgts); + graph->mincut = cgraph->mincut; + graph->nbnd = nbnd; + + FreeGraph(graph->coarser); + graph->coarser = NULL; + + idxwspacefree(ctrl, nparts); + + ASSERT(CheckBnd2(graph)); + +} + + + +/************************************************************************* +* This function computes the boundary definition for balancing +**************************************************************************/ +void MocComputeKWayBalanceBoundary(CtrlType *ctrl, GraphType *graph, int nparts) +{ + int i, nvtxs, nbnd; + idxtype *bndind, *bndptr; + + nvtxs = graph->nvtxs; + bndind = graph->bndind; + bndptr = idxset(nvtxs, -1, graph->bndptr); + + + /* Compute the new boundary */ + nbnd = 0; + for (i=0; i<nvtxs; i++) { + if (graph->rinfo[i].ed > 0) + BNDInsert(nbnd, bndind, bndptr, i); + } + + graph->nbnd = nbnd; +} + diff --git a/contrib/Metis/mmatch.c b/contrib/Metis/mmatch.c new file mode 100644 index 0000000000..ea15ed6c7f --- /dev/null +++ b/contrib/Metis/mmatch.c @@ -0,0 +1,506 @@ +/* + * Copyright 1997, Regents of the University of Minnesota + * + * mmatch.c + * + * This file contains the code that computes matchings and creates the next + * level coarse graph. + * + * Started 7/23/97 + * George + * + * $Id: mmatch.c,v 1.1 2005-09-21 17:29:38 geuzaine Exp $ + * + */ + +#include <metis.h> + + +/************************************************************************* +* This function finds a matching using the HEM heuristic +**************************************************************************/ +void MCMatch_RM(CtrlType *ctrl, GraphType *graph) +{ + int i, ii, j, k, nvtxs, ncon, cnvtxs, maxidx; + idxtype *xadj, *adjncy, *adjwgt; + idxtype *match, *cmap, *perm; + float *nvwgt; + + IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->MatchTmr)); + + nvtxs = graph->nvtxs; + ncon = graph->ncon; + xadj = graph->xadj; + nvwgt = graph->nvwgt; + adjncy = graph->adjncy; + adjwgt = graph->adjwgt; + + cmap = graph->cmap; + match = idxset(nvtxs, UNMATCHED, idxwspacemalloc(ctrl, nvtxs)); + + perm = idxwspacemalloc(ctrl, nvtxs); + RandomPermute(nvtxs, perm, 1); + + cnvtxs = 0; + for (ii=0; ii<nvtxs; ii++) { + i = perm[ii]; + + if (match[i] == UNMATCHED) { /* Unmatched */ + maxidx = i; + + /* Find a random matching, subject to maxvwgt constraints */ + for (j=xadj[i]; j<xadj[i+1]; j++) { + k = adjncy[j]; + if (match[k] == UNMATCHED && AreAllVwgtsBelowFast(ncon, nvwgt+i*ncon, nvwgt+k*ncon, ctrl->nmaxvwgt)) { + maxidx = k; + break; + } + } + + cmap[i] = cmap[maxidx] = cnvtxs++; + match[i] = maxidx; + match[maxidx] = i; + } + } + + IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->MatchTmr)); + + CreateCoarseGraph(ctrl, graph, cnvtxs, match, perm); + + idxwspacefree(ctrl, nvtxs); + idxwspacefree(ctrl, nvtxs); +} + + + +/************************************************************************* +* This function finds a matching using the HEM heuristic +**************************************************************************/ +void MCMatch_HEM(CtrlType *ctrl, GraphType *graph) +{ + int i, ii, j, k, l, nvtxs, cnvtxs, ncon, maxidx, maxwgt; + idxtype *xadj, *adjncy, *adjwgt; + idxtype *match, *cmap, *perm; + float *nvwgt; + + IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->MatchTmr)); + + nvtxs = graph->nvtxs; + ncon = graph->ncon; + xadj = graph->xadj; + nvwgt = graph->nvwgt; + adjncy = graph->adjncy; + adjwgt = graph->adjwgt; + + cmap = graph->cmap; + match = idxset(nvtxs, UNMATCHED, idxwspacemalloc(ctrl, nvtxs)); + + perm = idxwspacemalloc(ctrl, nvtxs); + RandomPermute(nvtxs, perm, 1); + + cnvtxs = 0; + for (ii=0; ii<nvtxs; ii++) { + i = perm[ii]; + + if (match[i] == UNMATCHED) { /* Unmatched */ + maxidx = i; + maxwgt = 0; + + /* Find a heavy-edge matching, subject to maxvwgt constraints */ + for (j=xadj[i]; j<xadj[i+1]; j++) { + k = adjncy[j]; + if (match[k] == UNMATCHED && maxwgt <= adjwgt[j] && + AreAllVwgtsBelowFast(ncon, nvwgt+i*ncon, nvwgt+k*ncon, ctrl->nmaxvwgt)) { + maxwgt = adjwgt[j]; + maxidx = adjncy[j]; + } + } + + cmap[i] = cmap[maxidx] = cnvtxs++; + match[i] = maxidx; + match[maxidx] = i; + } + } + + IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->MatchTmr)); + + CreateCoarseGraph(ctrl, graph, cnvtxs, match, perm); + + idxwspacefree(ctrl, nvtxs); + idxwspacefree(ctrl, nvtxs); +} + + + +/************************************************************************* +* This function finds a matching using the HEM heuristic +**************************************************************************/ +void MCMatch_SHEM(CtrlType *ctrl, GraphType *graph) +{ + int i, ii, j, k, nvtxs, cnvtxs, ncon, maxidx, maxwgt, avgdegree; + idxtype *xadj, *adjncy, *adjwgt; + idxtype *match, *cmap, *degrees, *perm, *tperm; + float *nvwgt; + + IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->MatchTmr)); + + nvtxs = graph->nvtxs; + ncon = graph->ncon; + xadj = graph->xadj; + nvwgt = graph->nvwgt; + adjncy = graph->adjncy; + adjwgt = graph->adjwgt; + + cmap = graph->cmap; + match = idxset(nvtxs, UNMATCHED, idxwspacemalloc(ctrl, nvtxs)); + + perm = idxwspacemalloc(ctrl, nvtxs); + tperm = idxwspacemalloc(ctrl, nvtxs); + degrees = idxwspacemalloc(ctrl, nvtxs); + + RandomPermute(nvtxs, tperm, 1); + avgdegree = 0.7*(xadj[nvtxs]/nvtxs); + for (i=0; i<nvtxs; i++) + degrees[i] = (xadj[i+1]-xadj[i] > avgdegree ? avgdegree : xadj[i+1]-xadj[i]); + BucketSortKeysInc(nvtxs, avgdegree, degrees, tperm, perm); + + cnvtxs = 0; + + /* Take care any islands. Islands are matched with non-islands due to coarsening */ + for (ii=0; ii<nvtxs; ii++) { + i = perm[ii]; + + if (match[i] == UNMATCHED) { /* Unmatched */ + if (xadj[i] < xadj[i+1]) + break; + + maxidx = i; + for (j=nvtxs-1; j>ii; j--) { + k = perm[j]; + if (match[k] == UNMATCHED && xadj[k] < xadj[k+1]) { + maxidx = k; + break; + } + } + + cmap[i] = cmap[maxidx] = cnvtxs++; + match[i] = maxidx; + match[maxidx] = i; + } + } + + /* Continue with normal matching */ + for (; ii<nvtxs; ii++) { + i = perm[ii]; + + if (match[i] == UNMATCHED) { /* Unmatched */ + maxidx = i; + maxwgt = 0; + + /* Find a heavy-edge matching, subject to maxvwgt constraints */ + for (j=xadj[i]; j<xadj[i+1]; j++) { + k = adjncy[j]; + if (match[k] == UNMATCHED && maxwgt <= adjwgt[j] && + AreAllVwgtsBelowFast(ncon, nvwgt+i*ncon, nvwgt+k*ncon, ctrl->nmaxvwgt)) { + maxwgt = adjwgt[j]; + maxidx = adjncy[j]; + } + } + + cmap[i] = cmap[maxidx] = cnvtxs++; + match[i] = maxidx; + match[maxidx] = i; + } + } + + IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->MatchTmr)); + + idxwspacefree(ctrl, nvtxs); /* degrees */ + idxwspacefree(ctrl, nvtxs); /* tperm */ + + CreateCoarseGraph(ctrl, graph, cnvtxs, match, perm); + + idxwspacefree(ctrl, nvtxs); + idxwspacefree(ctrl, nvtxs); +} + + + +/************************************************************************* +* This function finds a matching using the HEM heuristic +**************************************************************************/ +void MCMatch_SHEBM(CtrlType *ctrl, GraphType *graph, int norm) +{ + int i, ii, j, k, nvtxs, cnvtxs, ncon, maxidx, maxwgt, avgdegree; + idxtype *xadj, *adjncy, *adjwgt; + idxtype *match, *cmap, *degrees, *perm, *tperm; + float *nvwgt; + + IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->MatchTmr)); + + nvtxs = graph->nvtxs; + ncon = graph->ncon; + xadj = graph->xadj; + nvwgt = graph->nvwgt; + adjncy = graph->adjncy; + adjwgt = graph->adjwgt; + + cmap = graph->cmap; + match = idxset(nvtxs, UNMATCHED, idxwspacemalloc(ctrl, nvtxs)); + + perm = idxwspacemalloc(ctrl, nvtxs); + tperm = idxwspacemalloc(ctrl, nvtxs); + degrees = idxwspacemalloc(ctrl, nvtxs); + + RandomPermute(nvtxs, tperm, 1); + avgdegree = 0.7*(xadj[nvtxs]/nvtxs); + for (i=0; i<nvtxs; i++) + degrees[i] = (xadj[i+1]-xadj[i] > avgdegree ? avgdegree : xadj[i+1]-xadj[i]); + BucketSortKeysInc(nvtxs, avgdegree, degrees, tperm, perm); + + cnvtxs = 0; + + /* Take care any islands. Islands are matched with non-islands due to coarsening */ + for (ii=0; ii<nvtxs; ii++) { + i = perm[ii]; + + if (match[i] == UNMATCHED) { /* Unmatched */ + if (xadj[i] < xadj[i+1]) + break; + + maxidx = i; + for (j=nvtxs-1; j>ii; j--) { + k = perm[j]; + if (match[k] == UNMATCHED && xadj[k] < xadj[k+1]) { + maxidx = k; + break; + } + } + + cmap[i] = cmap[maxidx] = cnvtxs++; + match[i] = maxidx; + match[maxidx] = i; + } + } + + /* Continue with normal matching */ + for (; ii<nvtxs; ii++) { + i = perm[ii]; + + if (match[i] == UNMATCHED) { /* Unmatched */ + maxidx = i; + maxwgt = -1; + + /* Find a heavy-edge matching, subject to maxvwgt constraints */ + for (j=xadj[i]; j<xadj[i+1]; j++) { + k = adjncy[j]; + + if (match[k] == UNMATCHED && + AreAllVwgtsBelowFast(ncon, nvwgt+i*ncon, nvwgt+k*ncon, ctrl->nmaxvwgt) && + (maxwgt < adjwgt[j] || + (maxwgt == adjwgt[j] && + BetterVBalance(ncon, norm, nvwgt+i*ncon, nvwgt+maxidx*ncon, nvwgt+k*ncon) >= 0 + ) + ) + ) { + maxwgt = adjwgt[j]; + maxidx = k; + } + } + + cmap[i] = cmap[maxidx] = cnvtxs++; + match[i] = maxidx; + match[maxidx] = i; + } + } + + IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->MatchTmr)); + + idxwspacefree(ctrl, nvtxs); /* degrees */ + idxwspacefree(ctrl, nvtxs); /* tperm */ + + CreateCoarseGraph(ctrl, graph, cnvtxs, match, perm); + + idxwspacefree(ctrl, nvtxs); + idxwspacefree(ctrl, nvtxs); +} + + + +/************************************************************************* +* This function finds a matching using the HEM heuristic +**************************************************************************/ +void MCMatch_SBHEM(CtrlType *ctrl, GraphType *graph, int norm) +{ + int i, ii, j, k, nvtxs, cnvtxs, ncon, maxidx, maxwgt, avgdegree; + idxtype *xadj, *adjncy, *adjwgt; + idxtype *match, *cmap, *degrees, *perm, *tperm; + float *nvwgt, vbal; + + IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->MatchTmr)); + + nvtxs = graph->nvtxs; + ncon = graph->ncon; + xadj = graph->xadj; + nvwgt = graph->nvwgt; + adjncy = graph->adjncy; + adjwgt = graph->adjwgt; + + cmap = graph->cmap; + match = idxset(nvtxs, UNMATCHED, idxwspacemalloc(ctrl, nvtxs)); + + perm = idxwspacemalloc(ctrl, nvtxs); + tperm = idxwspacemalloc(ctrl, nvtxs); + degrees = idxwspacemalloc(ctrl, nvtxs); + + RandomPermute(nvtxs, tperm, 1); + avgdegree = 0.7*(xadj[nvtxs]/nvtxs); + for (i=0; i<nvtxs; i++) + degrees[i] = (xadj[i+1]-xadj[i] > avgdegree ? avgdegree : xadj[i+1]-xadj[i]); + BucketSortKeysInc(nvtxs, avgdegree, degrees, tperm, perm); + + cnvtxs = 0; + + /* Take care any islands. Islands are matched with non-islands due to coarsening */ + for (ii=0; ii<nvtxs; ii++) { + i = perm[ii]; + + if (match[i] == UNMATCHED) { /* Unmatched */ + if (xadj[i] < xadj[i+1]) + break; + + maxidx = i; + for (j=nvtxs-1; j>ii; j--) { + k = perm[j]; + if (match[k] == UNMATCHED && xadj[k] < xadj[k+1]) { + maxidx = k; + break; + } + } + + cmap[i] = cmap[maxidx] = cnvtxs++; + match[i] = maxidx; + match[maxidx] = i; + } + } + + /* Continue with normal matching */ + for (; ii<nvtxs; ii++) { + i = perm[ii]; + + if (match[i] == UNMATCHED) { /* Unmatched */ + maxidx = i; + maxwgt = -1; + vbal = 0.0; + + /* Find a heavy-edge matching, subject to maxvwgt constraints */ + for (j=xadj[i]; j<xadj[i+1]; j++) { + k = adjncy[j]; + if (match[k] == UNMATCHED && AreAllVwgtsBelowFast(ncon, nvwgt+i*ncon, nvwgt+k*ncon, ctrl->nmaxvwgt)) { + if (maxidx != i) + vbal = BetterVBalance(ncon, norm, nvwgt+i*ncon, nvwgt+maxidx*ncon, nvwgt+k*ncon); + + if (vbal > 0 || (vbal > -.01 && maxwgt < adjwgt[j])) { + maxwgt = adjwgt[j]; + maxidx = k; + } + } + } + + cmap[i] = cmap[maxidx] = cnvtxs++; + match[i] = maxidx; + match[maxidx] = i; + } + } + + IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->MatchTmr)); + + idxwspacefree(ctrl, nvtxs); /* degrees */ + idxwspacefree(ctrl, nvtxs); /* tperm */ + + CreateCoarseGraph(ctrl, graph, cnvtxs, match, perm); + + idxwspacefree(ctrl, nvtxs); + idxwspacefree(ctrl, nvtxs); +} + + + + + +/************************************************************************* +* This function checks if v+u2 provides a better balance in the weight +* vector that v+u1 +**************************************************************************/ +float BetterVBalance(int ncon, int norm, float *vwgt, float *u1wgt, float *u2wgt) +{ + int i; + float sum1, sum2, max1, max2, min1, min2, diff1, diff2; + + if (norm == -1) { + max1 = min1 = vwgt[0]+u1wgt[0]; + max2 = min2 = vwgt[0]+u2wgt[0]; + sum1 = vwgt[0]+u1wgt[0]; + sum2 = vwgt[0]+u2wgt[0]; + + for (i=1; i<ncon; i++) { + if (max1 < vwgt[i]+u1wgt[i]) + max1 = vwgt[i]+u1wgt[i]; + if (min1 > vwgt[i]+u1wgt[i]) + min1 = vwgt[i]+u1wgt[i]; + + if (max2 < vwgt[i]+u2wgt[i]) + max2 = vwgt[i]+u2wgt[i]; + if (min2 > vwgt[i]+u2wgt[i]) + min2 = vwgt[i]+u2wgt[i]; + + sum1 += vwgt[i]+u1wgt[i]; + sum2 += vwgt[i]+u2wgt[i]; + } + + if (sum1 == 0.0) + return 1; + else if (sum2 == 0.0) + return -1; + else + return ((max1-min1)/sum1) - ((max2-min2)/sum2); + } + else if (norm == 1) { + sum1 = sum2 = 0.0; + for (i=0; i<ncon; i++) { + sum1 += vwgt[i]+u1wgt[i]; + sum2 += vwgt[i]+u2wgt[i]; + } + sum1 = sum1/(1.0*ncon); + sum2 = sum2/(1.0*ncon); + + diff1 = diff2 = 0.0; + for (i=0; i<ncon; i++) { + diff1 += fabs(sum1 - (vwgt[i]+u1wgt[i])); + diff2 += fabs(sum2 - (vwgt[i]+u2wgt[i])); + } + + return diff1 - diff2; + } + else { + errexit("Unknown norm: %d\n", norm); + } + return 0.0; +} + + +/************************************************************************* +* This function checks if the vertex weights of two vertices are below +* a given set of values +**************************************************************************/ +int AreAllVwgtsBelowFast(int ncon, float *vwgt1, float *vwgt2, float limit) +{ + int i; + + for (i=0; i<ncon; i++) + if (vwgt1[i] + vwgt2[i] > limit) + return 0; + + return 1; +} + diff --git a/contrib/Metis/mmd.c b/contrib/Metis/mmd.c new file mode 100644 index 0000000000..ad986c2111 --- /dev/null +++ b/contrib/Metis/mmd.c @@ -0,0 +1,593 @@ +/* + * mmd.c + * + * ************************************************************** + * The following C function was developed from a FORTRAN subroutine + * in SPARSPAK written by Eleanor Chu, Alan George, Joseph Liu + * and Esmond Ng. + * + * The FORTRAN-to-C transformation and modifications such as dynamic + * memory allocation and deallocation were performed by Chunguang + * Sun. + * ************************************************************** + * + * Taken from SMMS, George 12/13/94 + * + * The meaning of invperm, and perm vectors is different from that + * in genqmd_ of SparsPak + * + * $Id: mmd.c,v 1.1 2005-09-21 17:29:38 geuzaine Exp $ + */ + +#include <metis.h> + + +/************************************************************************* +* genmmd -- multiple minimum external degree +* purpose -- this routine implements the minimum degree +* algorithm. it makes use of the implicit representation +* of elimination graphs by quotient graphs, and the notion +* of indistinguishable nodes. It also implements the modifications +* by multiple elimination and minimum external degree. +* Caution -- the adjacency vector adjncy will be destroyed. +* Input parameters -- +* neqns -- number of equations. +* (xadj, adjncy) -- the adjacency structure. +* delta -- tolerance value for multiple elimination. +* maxint -- maximum machine representable (short) integer +* (any smaller estimate will do) for marking nodes. +* Output parameters -- +* perm -- the minimum degree ordering. +* invp -- the inverse of perm. +* *ncsub -- an upper bound on the number of nonzero subscripts +* for the compressed storage scheme. +* Working parameters -- +* head -- vector for head of degree lists. +* invp -- used temporarily for degree forward link. +* perm -- used temporarily for degree backward link. +* qsize -- vector for size of supernodes. +* list -- vector for temporary linked lists. +* marker -- a temporary marker vector. +* Subroutines used -- mmdelm, mmdint, mmdnum, mmdupd. +**************************************************************************/ +void genmmd(int neqns, idxtype *xadj, idxtype *adjncy, idxtype *invp, idxtype *perm, + int delta, idxtype *head, idxtype *qsize, idxtype *list, idxtype *marker, + int maxint, int *ncsub) +{ + int ehead, i, mdeg, mdlmt, mdeg_node, nextmd, num, tag; + + if (neqns <= 0) + return; + + /* Adjust from C to Fortran */ + xadj--; adjncy--; invp--; perm--; head--; qsize--; list--; marker--; + + /* initialization for the minimum degree algorithm. */ + *ncsub = 0; + mmdint(neqns, xadj, adjncy, head, invp, perm, qsize, list, marker); + + /* 'num' counts the number of ordered nodes plus 1. */ + num = 1; + + /* eliminate all isolated nodes. */ + nextmd = head[1]; + while (nextmd > 0) { + mdeg_node = nextmd; + nextmd = invp[mdeg_node]; + marker[mdeg_node] = maxint; + invp[mdeg_node] = -num; + num = num + 1; + } + + /* search for node of the minimum degree. 'mdeg' is the current */ + /* minimum degree; 'tag' is used to facilitate marking nodes. */ + if (num > neqns) + goto n1000; + tag = 1; + head[1] = 0; + mdeg = 2; + + /* infinite loop here ! */ + while (1) { + while (head[mdeg] <= 0) + mdeg++; + + /* use value of 'delta' to set up 'mdlmt', which governs */ + /* when a degree update is to be performed. */ + mdlmt = mdeg + delta; + ehead = 0; + +n500: + mdeg_node = head[mdeg]; + while (mdeg_node <= 0) { + mdeg++; + + if (mdeg > mdlmt) + goto n900; + mdeg_node = head[mdeg]; + }; + + /* remove 'mdeg_node' from the degree structure. */ + nextmd = invp[mdeg_node]; + head[mdeg] = nextmd; + if (nextmd > 0) + perm[nextmd] = -mdeg; + invp[mdeg_node] = -num; + *ncsub += mdeg + qsize[mdeg_node] - 2; + if ((num+qsize[mdeg_node]) > neqns) + goto n1000; + + /* eliminate 'mdeg_node' and perform quotient graph */ + /* transformation. reset 'tag' value if necessary. */ + tag++; + if (tag >= maxint) { + tag = 1; + for (i = 1; i <= neqns; i++) + if (marker[i] < maxint) + marker[i] = 0; + }; + + mmdelm(mdeg_node, xadj, adjncy, head, invp, perm, qsize, list, marker, maxint, tag); + + num += qsize[mdeg_node]; + list[mdeg_node] = ehead; + ehead = mdeg_node; + if (delta >= 0) + goto n500; + + n900: + /* update degrees of the nodes involved in the */ + /* minimum degree nodes elimination. */ + if (num > neqns) + goto n1000; + mmdupd( ehead, neqns, xadj, adjncy, delta, &mdeg, head, invp, perm, qsize, list, marker, maxint, &tag); + }; /* end of -- while ( 1 ) -- */ + +n1000: + mmdnum( neqns, perm, invp, qsize ); + + /* Adjust from Fortran back to C*/ + xadj++; adjncy++; invp++; perm++; head++; qsize++; list++; marker++; +} + + +/************************************************************************** +* mmdelm ...... multiple minimum degree elimination +* Purpose -- This routine eliminates the node mdeg_node of minimum degree +* from the adjacency structure, which is stored in the quotient +* graph format. It also transforms the quotient graph representation +* of the elimination graph. +* Input parameters -- +* mdeg_node -- node of minimum degree. +* maxint -- estimate of maximum representable (short) integer. +* tag -- tag value. +* Updated parameters -- +* (xadj, adjncy) -- updated adjacency structure. +* (head, forward, backward) -- degree doubly linked structure. +* qsize -- size of supernode. +* marker -- marker vector. +* list -- temporary linked list of eliminated nabors. +***************************************************************************/ +void mmdelm(int mdeg_node, idxtype *xadj, idxtype *adjncy, idxtype *head, idxtype *forward, + idxtype *backward, idxtype *qsize, idxtype *list, idxtype *marker, int maxint,int tag) +{ + int element, i, istop, istart, j, + jstop, jstart, link, + nabor, node, npv, nqnbrs, nxnode, + pvnode, rlmt, rloc, rnode, xqnbr; + + /* find the reachable set of 'mdeg_node' and */ + /* place it in the data structure. */ + marker[mdeg_node] = tag; + istart = xadj[mdeg_node]; + istop = xadj[mdeg_node+1] - 1; + + /* 'element' points to the beginning of the list of */ + /* eliminated nabors of 'mdeg_node', and 'rloc' gives the */ + /* storage location for the next reachable node. */ + element = 0; + rloc = istart; + rlmt = istop; + for ( i = istart; i <= istop; i++ ) { + nabor = adjncy[i]; + if ( nabor == 0 ) break; + if ( marker[nabor] < tag ) { + marker[nabor] = tag; + if ( forward[nabor] < 0 ) { + list[nabor] = element; + element = nabor; + } else { + adjncy[rloc] = nabor; + rloc++; + }; + }; /* end of -- if -- */ + }; /* end of -- for -- */ + + /* merge with reachable nodes from generalized elements. */ + while ( element > 0 ) { + adjncy[rlmt] = -element; + link = element; + +n400: + jstart = xadj[link]; + jstop = xadj[link+1] - 1; + for ( j = jstart; j <= jstop; j++ ) { + node = adjncy[j]; + link = -node; + if ( node < 0 ) goto n400; + if ( node == 0 ) break; + if ((marker[node]<tag)&&(forward[node]>=0)) { + marker[node] = tag; + /*use storage from eliminated nodes if necessary.*/ + while ( rloc >= rlmt ) { + link = -adjncy[rlmt]; + rloc = xadj[link]; + rlmt = xadj[link+1] - 1; + }; + adjncy[rloc] = node; + rloc++; + }; + }; /* end of -- for ( j = jstart; -- */ + element = list[element]; + }; /* end of -- while ( element > 0 ) -- */ + if ( rloc <= rlmt ) adjncy[rloc] = 0; + /* for each node in the reachable set, do the following. */ + link = mdeg_node; + +n1100: + istart = xadj[link]; + istop = xadj[link+1] - 1; + for ( i = istart; i <= istop; i++ ) { + rnode = adjncy[i]; + link = -rnode; + if ( rnode < 0 ) goto n1100; + if ( rnode == 0 ) return; + + /* 'rnode' is in the degree list structure. */ + pvnode = backward[rnode]; + if (( pvnode != 0 ) && ( pvnode != (-maxint) )) { + /* then remove 'rnode' from the structure. */ + nxnode = forward[rnode]; + if ( nxnode > 0 ) backward[nxnode] = pvnode; + if ( pvnode > 0 ) forward[pvnode] = nxnode; + npv = -pvnode; + if ( pvnode < 0 ) head[npv] = nxnode; + }; + + /* purge inactive quotient nabors of 'rnode'. */ + jstart = xadj[rnode]; + jstop = xadj[rnode+1] - 1; + xqnbr = jstart; + for ( j = jstart; j <= jstop; j++ ) { + nabor = adjncy[j]; + if ( nabor == 0 ) break; + if ( marker[nabor] < tag ) { + adjncy[xqnbr] = nabor; + xqnbr++; + }; + }; + + /* no active nabor after the purging. */ + nqnbrs = xqnbr - jstart; + if ( nqnbrs <= 0 ) { + /* merge 'rnode' with 'mdeg_node'. */ + qsize[mdeg_node] += qsize[rnode]; + qsize[rnode] = 0; + marker[rnode] = maxint; + forward[rnode] = -mdeg_node; + backward[rnode] = -maxint; + } else { + /* flag 'rnode' for degree update, and */ + /* add 'mdeg_node' as a nabor of 'rnode'. */ + forward[rnode] = nqnbrs + 1; + backward[rnode] = 0; + adjncy[xqnbr] = mdeg_node; + xqnbr++; + if ( xqnbr <= jstop ) adjncy[xqnbr] = 0; + }; + }; /* end of -- for ( i = istart; -- */ + return; + } + +/*************************************************************************** +* mmdint ---- mult minimum degree initialization +* purpose -- this routine performs initialization for the +* multiple elimination version of the minimum degree algorithm. +* input parameters -- +* neqns -- number of equations. +* (xadj, adjncy) -- adjacency structure. +* output parameters -- +* (head, dfrow, backward) -- degree doubly linked structure. +* qsize -- size of supernode ( initialized to one). +* list -- linked list. +* marker -- marker vector. +****************************************************************************/ +int mmdint(int neqns, idxtype *xadj, idxtype *adjncy, idxtype *head, idxtype *forward, + idxtype *backward, idxtype *qsize, idxtype *list, idxtype *marker) +{ + int fnode, ndeg, node; + + for ( node = 1; node <= neqns; node++ ) { + head[node] = 0; + qsize[node] = 1; + marker[node] = 0; + list[node] = 0; + }; + + /* initialize the degree doubly linked lists. */ + for ( node = 1; node <= neqns; node++ ) { + ndeg = xadj[node+1] - xadj[node]/* + 1*/; /* george */ + if (ndeg == 0) + ndeg = 1; + fnode = head[ndeg]; + forward[node] = fnode; + head[ndeg] = node; + if ( fnode > 0 ) backward[fnode] = node; + backward[node] = -ndeg; + }; + return 0; +} + +/**************************************************************************** +* mmdnum --- multi minimum degree numbering +* purpose -- this routine performs the final step in producing +* the permutation and inverse permutation vectors in the +* multiple elimination version of the minimum degree +* ordering algorithm. +* input parameters -- +* neqns -- number of equations. +* qsize -- size of supernodes at elimination. +* updated parameters -- +* invp -- inverse permutation vector. on input, +* if qsize[node] = 0, then node has been merged +* into the node -invp[node]; otherwise, +* -invp[node] is its inverse labelling. +* output parameters -- +* perm -- the permutation vector. +****************************************************************************/ +void mmdnum(int neqns, idxtype *perm, idxtype *invp, idxtype *qsize) +{ + int father, nextf, node, nqsize, num, root; + + for ( node = 1; node <= neqns; node++ ) { + nqsize = qsize[node]; + if ( nqsize <= 0 ) perm[node] = invp[node]; + if ( nqsize > 0 ) perm[node] = -invp[node]; + }; + + /* for each node which has been merged, do the following. */ + for ( node = 1; node <= neqns; node++ ) { + if ( perm[node] <= 0 ) { + + /* trace the merged tree until one which has not */ + /* been merged, call it root. */ + father = node; + while ( perm[father] <= 0 ) + father = - perm[father]; + + /* number node after root. */ + root = father; + num = perm[root] + 1; + invp[node] = -num; + perm[root] = num; + + /* shorten the merged tree. */ + father = node; + nextf = - perm[father]; + while ( nextf > 0 ) { + perm[father] = -root; + father = nextf; + nextf = -perm[father]; + }; + }; /* end of -- if ( perm[node] <= 0 ) -- */ + }; /* end of -- for ( node = 1; -- */ + + /* ready to compute perm. */ + for ( node = 1; node <= neqns; node++ ) { + num = -invp[node]; + invp[node] = num; + perm[num] = node; + }; + return; +} + +/**************************************************************************** +* mmdupd ---- multiple minimum degree update +* purpose -- this routine updates the degrees of nodes after a +* multiple elimination step. +* input parameters -- +* ehead -- the beginning of the list of eliminated nodes +* (i.e., newly formed elements). +* neqns -- number of equations. +* (xadj, adjncy) -- adjacency structure. +* delta -- tolerance value for multiple elimination. +* maxint -- maximum machine representable (short) integer. +* updated parameters -- +* mdeg -- new minimum degree after degree update. +* (head, forward, backward) -- degree doubly linked structure. +* qsize -- size of supernode. +* list -- marker vector for degree update. +* *tag -- tag value. +****************************************************************************/ +void mmdupd(int ehead, int neqns, idxtype *xadj, idxtype *adjncy, int delta, int *mdeg, + idxtype *head, idxtype *forward, idxtype *backward, idxtype *qsize, idxtype *list, + idxtype *marker, int maxint,int *tag) +{ + int deg, deg0, element, enode, fnode, i, iq2, istop, + istart, j, jstop, jstart, link, mdeg0, mtag, nabor, + node, q2head, qxhead; + + mdeg0 = *mdeg + delta; + element = ehead; + +n100: + if ( element <= 0 ) return; + + /* for each of the newly formed element, do the following. */ + /* reset tag value if necessary. */ + mtag = *tag + mdeg0; + if ( mtag >= maxint ) { + *tag = 1; + for ( i = 1; i <= neqns; i++ ) + if ( marker[i] < maxint ) marker[i] = 0; + mtag = *tag + mdeg0; + }; + + /* create two linked lists from nodes associated with 'element': */ + /* one with two nabors (q2head) in the adjacency structure, and the*/ + /* other with more than two nabors (qxhead). also compute 'deg0',*/ + /* number of nodes in this element. */ + q2head = 0; + qxhead = 0; + deg0 = 0; + link =element; + +n400: + istart = xadj[link]; + istop = xadj[link+1] - 1; + for ( i = istart; i <= istop; i++ ) { + enode = adjncy[i]; + link = -enode; + if ( enode < 0 ) goto n400; + if ( enode == 0 ) break; + if ( qsize[enode] != 0 ) { + deg0 += qsize[enode]; + marker[enode] = mtag; + + /*'enode' requires a degree update*/ + if ( backward[enode] == 0 ) { + /* place either in qxhead or q2head list. */ + if ( forward[enode] != 2 ) { + list[enode] = qxhead; + qxhead = enode; + } else { + list[enode] = q2head; + q2head = enode; + }; + }; + }; /* enf of -- if ( qsize[enode] != 0 ) -- */ + }; /* end of -- for ( i = istart; -- */ + + /* for each node in q2 list, do the following. */ + enode = q2head; + iq2 = 1; + +n900: + if ( enode <= 0 ) goto n1500; + if ( backward[enode] != 0 ) goto n2200; + (*tag)++; + deg = deg0; + + /* identify the other adjacent element nabor. */ + istart = xadj[enode]; + nabor = adjncy[istart]; + if ( nabor == element ) nabor = adjncy[istart+1]; + link = nabor; + if ( forward[nabor] >= 0 ) { + /* nabor is uneliminated, increase degree count. */ + deg += qsize[nabor]; + goto n2100; + }; + + /* the nabor is eliminated. for each node in the 2nd element */ + /* do the following. */ +n1000: + istart = xadj[link]; + istop = xadj[link+1] - 1; + for ( i = istart; i <= istop; i++ ) { + node = adjncy[i]; + link = -node; + if ( node != enode ) { + if ( node < 0 ) goto n1000; + if ( node == 0 ) goto n2100; + if ( qsize[node] != 0 ) { + if ( marker[node] < *tag ) { + /* 'node' is not yet considered. */ + marker[node] = *tag; + deg += qsize[node]; + } else { + if ( backward[node] == 0 ) { + if ( forward[node] == 2 ) { + /* 'node' is indistinguishable from 'enode'.*/ + /* merge them into a new supernode. */ + qsize[enode] += qsize[node]; + qsize[node] = 0; + marker[node] = maxint; + forward[node] = -enode; + backward[node] = -maxint; + } else { + /* 'node' is outmacthed by 'enode' */ + if (backward[node]==0) backward[node] = -maxint; + }; + }; /* end of -- if ( backward[node] == 0 ) -- */ + }; /* end of -- if ( marker[node] < *tag ) -- */ + }; /* end of -- if ( qsize[node] != 0 ) -- */ + }; /* end of -- if ( node != enode ) -- */ + }; /* end of -- for ( i = istart; -- */ + goto n2100; + +n1500: + /* for each 'enode' in the 'qx' list, do the following. */ + enode = qxhead; + iq2 = 0; + +n1600: if ( enode <= 0 ) goto n2300; + if ( backward[enode] != 0 ) goto n2200; + (*tag)++; + deg = deg0; + + /*for each unmarked nabor of 'enode', do the following.*/ + istart = xadj[enode]; + istop = xadj[enode+1] - 1; + for ( i = istart; i <= istop; i++ ) { + nabor = adjncy[i]; + if ( nabor == 0 ) break; + if ( marker[nabor] < *tag ) { + marker[nabor] = *tag; + link = nabor; + if ( forward[nabor] >= 0 ) + /*if uneliminated, include it in deg count.*/ + deg += qsize[nabor]; + else { +n1700: + /* if eliminated, include unmarked nodes in this*/ + /* element into the degree count. */ + jstart = xadj[link]; + jstop = xadj[link+1] - 1; + for ( j = jstart; j <= jstop; j++ ) { + node = adjncy[j]; + link = -node; + if ( node < 0 ) goto n1700; + if ( node == 0 ) break; + if ( marker[node] < *tag ) { + marker[node] = *tag; + deg += qsize[node]; + }; + }; /* end of -- for ( j = jstart; -- */ + }; /* end of -- if ( forward[nabor] >= 0 ) -- */ + }; /* end of -- if ( marker[nabor] < *tag ) -- */ + }; /* end of -- for ( i = istart; -- */ + +n2100: + /* update external degree of 'enode' in degree structure, */ + /* and '*mdeg' if necessary. */ + deg = deg - qsize[enode] + 1; + fnode = head[deg]; + forward[enode] = fnode; + backward[enode] = -deg; + if ( fnode > 0 ) backward[fnode] = enode; + head[deg] = enode; + if ( deg < *mdeg ) *mdeg = deg; + +n2200: + /* get next enode in current element. */ + enode = list[enode]; + if ( iq2 == 1 ) goto n900; + goto n1600; + +n2300: + /* get next element in the list. */ + *tag = mtag; + element = list[element]; + goto n100; + } diff --git a/contrib/Metis/mpmetis.c b/contrib/Metis/mpmetis.c new file mode 100644 index 0000000000..4d677c11ed --- /dev/null +++ b/contrib/Metis/mpmetis.c @@ -0,0 +1,402 @@ +/* + * Copyright 1997, Regents of the University of Minnesota + * + * mpmetis.c + * + * This file contains the top level routines for the multilevel recursive + * bisection algorithm PMETIS. + * + * Started 7/24/97 + * George + * + * $Id: mpmetis.c,v 1.1 2005-09-21 17:29:38 geuzaine Exp $ + * + */ + +#include <metis.h> + + + +/************************************************************************* +* This function is the entry point for PWMETIS that accepts exact weights +* for the target partitions +**************************************************************************/ +void METIS_mCPartGraphRecursive(int *nvtxs, int *ncon, idxtype *xadj, idxtype *adjncy, + idxtype *vwgt, idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts, + int *options, int *edgecut, idxtype *part) +{ + int i, j; + GraphType graph; + CtrlType ctrl; + + if (*numflag == 1) + Change2CNumbering(*nvtxs, xadj, adjncy); + + SetUpGraph(&graph, OP_PMETIS, *nvtxs, *ncon, xadj, adjncy, vwgt, adjwgt, *wgtflag); + + if (options[0] == 0) { /* Use the default parameters */ + ctrl.CType = McPMETIS_CTYPE; + ctrl.IType = McPMETIS_ITYPE; + ctrl.RType = McPMETIS_RTYPE; + ctrl.dbglvl = McPMETIS_DBGLVL; + } + else { + ctrl.CType = options[OPTION_CTYPE]; + ctrl.IType = options[OPTION_ITYPE]; + ctrl.RType = options[OPTION_RTYPE]; + ctrl.dbglvl = options[OPTION_DBGLVL]; + } + ctrl.optype = OP_PMETIS; + ctrl.CoarsenTo = 100; + + ctrl.nmaxvwgt = 1.5/(1.0*ctrl.CoarsenTo); + + InitRandom(-1); + + AllocateWorkSpace(&ctrl, &graph, *nparts); + + IFSET(ctrl.dbglvl, DBG_TIME, InitTimers(&ctrl)); + IFSET(ctrl.dbglvl, DBG_TIME, starttimer(ctrl.TotalTmr)); + + *edgecut = MCMlevelRecursiveBisection(&ctrl, &graph, *nparts, part, 1.000, 0); + + IFSET(ctrl.dbglvl, DBG_TIME, stoptimer(ctrl.TotalTmr)); + IFSET(ctrl.dbglvl, DBG_TIME, PrintTimers(&ctrl)); + + FreeWorkSpace(&ctrl, &graph); + + if (*numflag == 1) + Change2FNumbering(*nvtxs, xadj, adjncy, part); +} + + + +/************************************************************************* +* This function is the entry point for PWMETIS that accepts exact weights +* for the target partitions +**************************************************************************/ +void METIS_mCHPartGraphRecursive(int *nvtxs, int *ncon, idxtype *xadj, idxtype *adjncy, + idxtype *vwgt, idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts, + float *ubvec, int *options, int *edgecut, idxtype *part) +{ + int i, j; + GraphType graph; + CtrlType ctrl; + float *myubvec; + + if (*numflag == 1) + Change2CNumbering(*nvtxs, xadj, adjncy); + + SetUpGraph(&graph, OP_PMETIS, *nvtxs, *ncon, xadj, adjncy, vwgt, adjwgt, *wgtflag); + + if (options[0] == 0) { /* Use the default parameters */ + ctrl.CType = PMETIS_CTYPE; + ctrl.IType = PMETIS_ITYPE; + ctrl.RType = PMETIS_RTYPE; + ctrl.dbglvl = PMETIS_DBGLVL; + } + else { + ctrl.CType = options[OPTION_CTYPE]; + ctrl.IType = options[OPTION_ITYPE]; + ctrl.RType = options[OPTION_RTYPE]; + ctrl.dbglvl = options[OPTION_DBGLVL]; + } + ctrl.optype = OP_PMETIS; + ctrl.CoarsenTo = 100; + + ctrl.nmaxvwgt = 1.5/(1.0*ctrl.CoarsenTo); + + myubvec = fmalloc(*ncon, "PWMETIS: mytpwgts"); + scopy(*ncon, ubvec, myubvec); + + InitRandom(-1); + + AllocateWorkSpace(&ctrl, &graph, *nparts); + + IFSET(ctrl.dbglvl, DBG_TIME, InitTimers(&ctrl)); + IFSET(ctrl.dbglvl, DBG_TIME, starttimer(ctrl.TotalTmr)); + + *edgecut = MCHMlevelRecursiveBisection(&ctrl, &graph, *nparts, part, myubvec, 0); + + IFSET(ctrl.dbglvl, DBG_TIME, stoptimer(ctrl.TotalTmr)); + IFSET(ctrl.dbglvl, DBG_TIME, PrintTimers(&ctrl)); + + FreeWorkSpace(&ctrl, &graph); + GKfree(&myubvec, LTERM); + + if (*numflag == 1) + Change2FNumbering(*nvtxs, xadj, adjncy, part); +} + + + +/************************************************************************* +* This function is the entry point for PWMETIS that accepts exact weights +* for the target partitions +**************************************************************************/ +void METIS_mCPartGraphRecursiveInternal(int *nvtxs, int *ncon, idxtype *xadj, idxtype *adjncy, + float *nvwgt, idxtype *adjwgt, int *nparts, int *options, int *edgecut, idxtype *part) +{ + int i, j; + GraphType graph; + CtrlType ctrl; + + SetUpGraph2(&graph, *nvtxs, *ncon, xadj, adjncy, nvwgt, adjwgt); + + if (options[0] == 0) { /* Use the default parameters */ + ctrl.CType = PMETIS_CTYPE; + ctrl.IType = PMETIS_ITYPE; + ctrl.RType = PMETIS_RTYPE; + ctrl.dbglvl = PMETIS_DBGLVL; + } + else { + ctrl.CType = options[OPTION_CTYPE]; + ctrl.IType = options[OPTION_ITYPE]; + ctrl.RType = options[OPTION_RTYPE]; + ctrl.dbglvl = options[OPTION_DBGLVL]; + } + ctrl.optype = OP_PMETIS; + ctrl.CoarsenTo = 100; + + ctrl.nmaxvwgt = 1.5/(1.0*ctrl.CoarsenTo); + + InitRandom(-1); + + AllocateWorkSpace(&ctrl, &graph, *nparts); + + IFSET(ctrl.dbglvl, DBG_TIME, InitTimers(&ctrl)); + IFSET(ctrl.dbglvl, DBG_TIME, starttimer(ctrl.TotalTmr)); + + *edgecut = MCMlevelRecursiveBisection(&ctrl, &graph, *nparts, part, 1.000, 0); + + IFSET(ctrl.dbglvl, DBG_TIME, stoptimer(ctrl.TotalTmr)); + IFSET(ctrl.dbglvl, DBG_TIME, PrintTimers(&ctrl)); + + FreeWorkSpace(&ctrl, &graph); + +} + + +/************************************************************************* +* This function is the entry point for PWMETIS that accepts exact weights +* for the target partitions +**************************************************************************/ +void METIS_mCHPartGraphRecursiveInternal(int *nvtxs, int *ncon, idxtype *xadj, idxtype *adjncy, + float *nvwgt, idxtype *adjwgt, int *nparts, float *ubvec, int *options, int *edgecut, + idxtype *part) +{ + int i, j; + GraphType graph; + CtrlType ctrl; + float *myubvec; + + SetUpGraph2(&graph, *nvtxs, *ncon, xadj, adjncy, nvwgt, adjwgt); + + if (options[0] == 0) { /* Use the default parameters */ + ctrl.CType = PMETIS_CTYPE; + ctrl.IType = PMETIS_ITYPE; + ctrl.RType = PMETIS_RTYPE; + ctrl.dbglvl = PMETIS_DBGLVL; + } + else { + ctrl.CType = options[OPTION_CTYPE]; + ctrl.IType = options[OPTION_ITYPE]; + ctrl.RType = options[OPTION_RTYPE]; + ctrl.dbglvl = options[OPTION_DBGLVL]; + } + ctrl.optype = OP_PMETIS; + ctrl.CoarsenTo = 100; + + ctrl.nmaxvwgt = 1.5/(1.0*ctrl.CoarsenTo); + + myubvec = fmalloc(*ncon, "PWMETIS: mytpwgts"); + scopy(*ncon, ubvec, myubvec); + + InitRandom(-1); + + AllocateWorkSpace(&ctrl, &graph, *nparts); + + IFSET(ctrl.dbglvl, DBG_TIME, InitTimers(&ctrl)); + IFSET(ctrl.dbglvl, DBG_TIME, starttimer(ctrl.TotalTmr)); + + *edgecut = MCHMlevelRecursiveBisection(&ctrl, &graph, *nparts, part, myubvec, 0); + + IFSET(ctrl.dbglvl, DBG_TIME, stoptimer(ctrl.TotalTmr)); + IFSET(ctrl.dbglvl, DBG_TIME, PrintTimers(&ctrl)); + + FreeWorkSpace(&ctrl, &graph); + GKfree(&myubvec, LTERM); + +} + + + + +/************************************************************************* +* This function takes a graph and produces a bisection of it +**************************************************************************/ +int MCMlevelRecursiveBisection(CtrlType *ctrl, GraphType *graph, int nparts, idxtype *part, + float ubfactor, int fpart) +{ + int i, j, nvtxs, ncon, cut; + idxtype *label, *where; + GraphType lgraph, rgraph; + float tpwgts[2]; + + nvtxs = graph->nvtxs; + if (nvtxs == 0) { + printf("\t***Cannot bisect a graph with 0 vertices!\n\t***You are trying to partition a graph into too many parts!\n"); + return 0; + } + + /* Determine the weights of the partitions */ + tpwgts[0] = 1.0*(nparts>>1)/(1.0*nparts); + tpwgts[1] = 1.0 - tpwgts[0]; + + MCMlevelEdgeBisection(ctrl, graph, tpwgts, ubfactor); + cut = graph->mincut; + + label = graph->label; + where = graph->where; + for (i=0; i<nvtxs; i++) + part[label[i]] = where[i] + fpart; + + if (nparts > 2) + SplitGraphPart(ctrl, graph, &lgraph, &rgraph); + + /* Free the memory of the top level graph */ + GKfree(&graph->gdata, &graph->nvwgt, &graph->rdata, &graph->npwgts, &graph->label, LTERM); + + + /* Do the recursive call */ + if (nparts > 3) { + cut += MCMlevelRecursiveBisection(ctrl, &lgraph, nparts/2, part, ubfactor, fpart); + cut += MCMlevelRecursiveBisection(ctrl, &rgraph, nparts-nparts/2, part, ubfactor, fpart+nparts/2); + } + else if (nparts == 3) { + cut += MCMlevelRecursiveBisection(ctrl, &rgraph, nparts-nparts/2, part, ubfactor, fpart+nparts/2); + GKfree(&lgraph.gdata, &lgraph.nvwgt, &lgraph.label, LTERM); + } + + return cut; + +} + + + +/************************************************************************* +* This function takes a graph and produces a bisection of it +**************************************************************************/ +int MCHMlevelRecursiveBisection(CtrlType *ctrl, GraphType *graph, int nparts, idxtype *part, + float *ubvec, int fpart) +{ + int i, j, nvtxs, ncon, cut; + idxtype *label, *where; + GraphType lgraph, rgraph; + float tpwgts[2], *npwgts, *lubvec, *rubvec; + + lubvec = rubvec = NULL; + + nvtxs = graph->nvtxs; + ncon = graph->ncon; + if (nvtxs == 0) { + printf("\t***Cannot bisect a graph with 0 vertices!\n\t***You are trying to partition a graph into too many parts!\n"); + return 0; + } + + /* Determine the weights of the partitions */ + tpwgts[0] = 1.0*(nparts>>1)/(1.0*nparts); + tpwgts[1] = 1.0 - tpwgts[0]; + + /* For now, relax at the coarsest level only */ + if (nparts == 2) + MCHMlevelEdgeBisection(ctrl, graph, tpwgts, ubvec); + else + MCMlevelEdgeBisection(ctrl, graph, tpwgts, 1.000); + cut = graph->mincut; + + label = graph->label; + where = graph->where; + for (i=0; i<nvtxs; i++) + part[label[i]] = where[i] + fpart; + + if (nparts > 2) { + /* Adjust the ubvecs before the split */ + npwgts = graph->npwgts; + lubvec = fmalloc(ncon, "MCHMlevelRecursiveBisection"); + rubvec = fmalloc(ncon, "MCHMlevelRecursiveBisection"); + + for (i=0; i<ncon; i++) { + lubvec[i] = ubvec[i]*tpwgts[0]/npwgts[i]; + lubvec[i] = amax(lubvec[i], 1.01); + + rubvec[i] = ubvec[i]*tpwgts[1]/npwgts[ncon+i]; + rubvec[i] = amax(rubvec[i], 1.01); + } + + SplitGraphPart(ctrl, graph, &lgraph, &rgraph); + } + + /* Free the memory of the top level graph */ + GKfree(&graph->gdata, &graph->nvwgt, &graph->rdata, &graph->npwgts, &graph->label, LTERM); + + + /* Do the recursive call */ + if (nparts > 3) { + cut += MCHMlevelRecursiveBisection(ctrl, &lgraph, nparts/2, part, lubvec, fpart); + cut += MCHMlevelRecursiveBisection(ctrl, &rgraph, nparts-nparts/2, part, rubvec, fpart+nparts/2); + } + else if (nparts == 3) { + cut += MCHMlevelRecursiveBisection(ctrl, &rgraph, nparts-nparts/2, part, rubvec, fpart+nparts/2); + GKfree(&lgraph.gdata, &lgraph.nvwgt, &lgraph.label, LTERM); + } + + GKfree(&lubvec, &rubvec, LTERM); + + return cut; + +} + + + + +/************************************************************************* +* This function performs multilevel bisection +**************************************************************************/ +void MCMlevelEdgeBisection(CtrlType *ctrl, GraphType *graph, float *tpwgts, float ubfactor) +{ + GraphType *cgraph; + + cgraph = MCCoarsen2Way(ctrl, graph); + + MocInit2WayPartition(ctrl, cgraph, tpwgts, ubfactor); + + MocRefine2Way(ctrl, graph, cgraph, tpwgts, ubfactor); + +} + + + +/************************************************************************* +* This function performs multilevel bisection +**************************************************************************/ +void MCHMlevelEdgeBisection(CtrlType *ctrl, GraphType *graph, float *tpwgts, float *ubvec) +{ + int i; + GraphType *cgraph; + +/* + for (i=0; i<graph->ncon; i++) + printf("%.4f ", ubvec[i]); + printf("\n"); +*/ + + cgraph = MCCoarsen2Way(ctrl, graph); + + MocInit2WayPartition2(ctrl, cgraph, tpwgts, ubvec); + + MocRefine2Way2(ctrl, graph, cgraph, tpwgts, ubvec); + +} + + diff --git a/contrib/Metis/mrefine.c b/contrib/Metis/mrefine.c new file mode 100644 index 0000000000..7d5b8e0b6e --- /dev/null +++ b/contrib/Metis/mrefine.c @@ -0,0 +1,219 @@ +/* + * Copyright 1997, Regents of the University of Minnesota + * + * refine.c + * + * This file contains the driving routines for multilevel refinement + * + * Started 7/24/97 + * George + * + * $Id: mrefine.c,v 1.1 2005-09-21 17:29:38 geuzaine Exp $ + */ + +#include <metis.h> + + +/************************************************************************* +* This function is the entry point of refinement +**************************************************************************/ +void MocRefine2Way(CtrlType *ctrl, GraphType *orggraph, GraphType *graph, float *tpwgts, float ubfactor) +{ + int i; + float tubvec[MAXNCON]; + + for (i=0; i<graph->ncon; i++) + tubvec[i] = 1.0; + + IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->UncoarsenTmr)); + + /* Compute the parameters of the coarsest graph */ + MocCompute2WayPartitionParams(ctrl, graph); + + for (;;) { + ASSERT(CheckBnd(graph)); + + IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->RefTmr)); + switch (ctrl->RType) { + case RTYPE_FM: + MocBalance2Way(ctrl, graph, tpwgts, 1.03); + MocFM_2WayEdgeRefine(ctrl, graph, tpwgts, 8); + break; + case 2: + MocBalance2Way(ctrl, graph, tpwgts, 1.03); + MocFM_2WayEdgeRefine2(ctrl, graph, tpwgts, tubvec, 8); + break; + default: + errexit("Unknown refinement type: %d\n", ctrl->RType); + } + IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->RefTmr)); + + if (graph == orggraph) + break; + + graph = graph->finer; + IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->ProjectTmr)); + MocProject2WayPartition(ctrl, graph); + IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->ProjectTmr)); + } + + MocBalance2Way(ctrl, graph, tpwgts, 1.01); + MocFM_2WayEdgeRefine(ctrl, graph, tpwgts, 8); + + IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->UncoarsenTmr)); +} + + +/************************************************************************* +* This function allocates memory for 2-way edge refinement +**************************************************************************/ +void MocAllocate2WayPartitionMemory(CtrlType *ctrl, GraphType *graph) +{ + int nvtxs, ncon; + + nvtxs = graph->nvtxs; + ncon = graph->ncon; + + graph->rdata = idxmalloc(5*nvtxs, "Allocate2WayPartitionMemory: rdata"); + graph->where = graph->rdata; + graph->id = graph->rdata + nvtxs; + graph->ed = graph->rdata + 2*nvtxs; + graph->bndptr = graph->rdata + 3*nvtxs; + graph->bndind = graph->rdata + 4*nvtxs; + + graph->npwgts = fmalloc(2*ncon, "npwgts"); +} + + +/************************************************************************* +* This function computes the initial id/ed +**************************************************************************/ +void MocCompute2WayPartitionParams(CtrlType *ctrl, GraphType *graph) +{ + int i, j, k, l, nvtxs, ncon, nbnd, mincut; + idxtype *xadj, *adjncy, *adjwgt; + float *nvwgt, *npwgts; + idxtype *id, *ed, *where; + idxtype *bndptr, *bndind; + int me, other; + + nvtxs = graph->nvtxs; + ncon = graph->ncon; + xadj = graph->xadj; + nvwgt = graph->nvwgt; + adjncy = graph->adjncy; + adjwgt = graph->adjwgt; + + where = graph->where; + npwgts = sset(2*ncon, 0.0, graph->npwgts); + id = idxset(nvtxs, 0, graph->id); + ed = idxset(nvtxs, 0, graph->ed); + bndptr = idxset(nvtxs, -1, graph->bndptr); + bndind = graph->bndind; + + + /*------------------------------------------------------------ + / Compute now the id/ed degrees + /------------------------------------------------------------*/ + nbnd = mincut = 0; + for (i=0; i<nvtxs; i++) { + ASSERT(where[i] >= 0 && where[i] <= 1); + me = where[i]; + saxpy(ncon, 1.0, nvwgt+i*ncon, 1, npwgts+me*ncon, 1); + + for (j=xadj[i]; j<xadj[i+1]; j++) { + if (me == where[adjncy[j]]) + id[i] += adjwgt[j]; + else + ed[i] += adjwgt[j]; + } + + if (ed[i] > 0 || xadj[i] == xadj[i+1]) { + mincut += ed[i]; + bndptr[i] = nbnd; + bndind[nbnd++] = i; + } + } + + graph->mincut = mincut/2; + graph->nbnd = nbnd; + +} + + + +/************************************************************************* +* This function projects a partition, and at the same time computes the +* parameters for refinement. +**************************************************************************/ +void MocProject2WayPartition(CtrlType *ctrl, GraphType *graph) +{ + int i, j, k, nvtxs, nbnd, me; + idxtype *xadj, *adjncy, *adjwgt, *adjwgtsum; + idxtype *cmap, *where, *id, *ed, *bndptr, *bndind; + idxtype *cwhere, *cid, *ced, *cbndptr; + GraphType *cgraph; + + cgraph = graph->coarser; + cwhere = cgraph->where; + cid = cgraph->id; + ced = cgraph->ed; + cbndptr = cgraph->bndptr; + + nvtxs = graph->nvtxs; + cmap = graph->cmap; + xadj = graph->xadj; + adjncy = graph->adjncy; + adjwgt = graph->adjwgt; + adjwgtsum = graph->adjwgtsum; + + MocAllocate2WayPartitionMemory(ctrl, graph); + + where = graph->where; + id = idxset(nvtxs, 0, graph->id); + ed = idxset(nvtxs, 0, graph->ed); + bndptr = idxset(nvtxs, -1, graph->bndptr); + bndind = graph->bndind; + + + /* Go through and project partition and compute id/ed for the nodes */ + for (i=0; i<nvtxs; i++) { + k = cmap[i]; + where[i] = cwhere[k]; + cmap[i] = cbndptr[k]; + } + + for (nbnd=0, i=0; i<nvtxs; i++) { + me = where[i]; + + id[i] = adjwgtsum[i]; + + if (xadj[i] == xadj[i+1]) { + bndptr[i] = nbnd; + bndind[nbnd++] = i; + } + else { + if (cmap[i] != -1) { /* If it is an interface node. Note that cmap[i] = cbndptr[cmap[i]] */ + for (j=xadj[i]; j<xadj[i+1]; j++) { + if (me != where[adjncy[j]]) + ed[i] += adjwgt[j]; + } + id[i] -= ed[i]; + + if (ed[i] > 0 || xadj[i] == xadj[i+1]) { + bndptr[i] = nbnd; + bndind[nbnd++] = i; + } + } + } + } + + graph->mincut = cgraph->mincut; + graph->nbnd = nbnd; + scopy(2*graph->ncon, cgraph->npwgts, graph->npwgts); + + FreeGraph(graph->coarser); + graph->coarser = NULL; + +} + diff --git a/contrib/Metis/mrefine2.c b/contrib/Metis/mrefine2.c new file mode 100644 index 0000000000..ed5ff9f140 --- /dev/null +++ b/contrib/Metis/mrefine2.c @@ -0,0 +1,55 @@ +/* + * Copyright 1997, Regents of the University of Minnesota + * + * mrefine2.c + * + * This file contains the driving routines for multilevel refinement + * + * Started 7/24/97 + * George + * + * $Id: mrefine2.c,v 1.1 2005-09-21 17:29:38 geuzaine Exp $ + */ + +#include <metis.h> + + +/************************************************************************* +* This function is the entry point of refinement +**************************************************************************/ +void MocRefine2Way2(CtrlType *ctrl, GraphType *orggraph, GraphType *graph, float *tpwgts, + float *ubvec) +{ + + IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->UncoarsenTmr)); + + /* Compute the parameters of the coarsest graph */ + MocCompute2WayPartitionParams(ctrl, graph); + + for (;;) { + ASSERT(CheckBnd(graph)); + + IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->RefTmr)); + switch (ctrl->RType) { + case RTYPE_FM: + MocBalance2Way2(ctrl, graph, tpwgts, ubvec); + MocFM_2WayEdgeRefine2(ctrl, graph, tpwgts, ubvec, 8); + break; + default: + errexit("Unknown refinement type: %d\n", ctrl->RType); + } + IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->RefTmr)); + + if (graph == orggraph) + break; + + graph = graph->finer; + IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->ProjectTmr)); + MocProject2WayPartition(ctrl, graph); + IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->ProjectTmr)); + } + + IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->UncoarsenTmr)); +} + + diff --git a/contrib/Metis/mutil.c b/contrib/Metis/mutil.c new file mode 100644 index 0000000000..7a6d5267b1 --- /dev/null +++ b/contrib/Metis/mutil.c @@ -0,0 +1,101 @@ +/* + * mutil.c + * + * This file contains various utility functions for the MOC portion of the + * code + * + * Started 2/15/98 + * George + * + * $Id: mutil.c,v 1.1 2005-09-21 17:29:38 geuzaine Exp $ + * + */ + +#include <metis.h> + + +/************************************************************************* +* This function checks if the vertex weights of two vertices are below +* a given set of values +**************************************************************************/ +int AreAllVwgtsBelow(int ncon, float alpha, float *vwgt1, float beta, float *vwgt2, float limit) +{ + int i; + + for (i=0; i<ncon; i++) + if (alpha*vwgt1[i] + beta*vwgt2[i] > limit) + return 0; + + return 1; +} + + +/************************************************************************* +* This function checks if the vertex weights of two vertices are below +* a given set of values +**************************************************************************/ +int AreAnyVwgtsBelow(int ncon, float alpha, float *vwgt1, float beta, float *vwgt2, float limit) +{ + int i; + + for (i=0; i<ncon; i++) + if (alpha*vwgt1[i] + beta*vwgt2[i] < limit) + return 1; + + return 0; +} + + + +/************************************************************************* +* This function checks if the vertex weights of two vertices are above +* a given set of values +**************************************************************************/ +int AreAllVwgtsAbove(int ncon, float alpha, float *vwgt1, float beta, float *vwgt2, float limit) +{ + int i; + + for (i=0; i<ncon; i++) + if (alpha*vwgt1[i] + beta*vwgt2[i] < limit) + return 0; + + return 1; +} + + +/************************************************************************* +* This function computes the load imbalance over all the constrains +* For now assume that we just want balanced partitionings +**************************************************************************/ +float ComputeLoadImbalance(int ncon, int nparts, float *npwgts, float *tpwgts) +{ + int i, j; + float max, lb=0.0; + + for (i=0; i<ncon; i++) { + max = 0.0; + for (j=0; j<nparts; j++) { + if (npwgts[j*ncon+i] > max) + max = npwgts[j*ncon+i]; + } + if (max*nparts > lb) + lb = max*nparts; + } + + return lb; +} + +/************************************************************************* +* This function checks if the vertex weights of two vertices are below +* a given set of values +**************************************************************************/ +int AreAllBelow(int ncon, float *v1, float *v2) +{ + int i; + + for (i=0; i<ncon; i++) + if (v1[i] > v2[i]) + return 0; + + return 1; +} diff --git a/contrib/Metis/myqsort.c b/contrib/Metis/myqsort.c new file mode 100644 index 0000000000..c5b756cfdf --- /dev/null +++ b/contrib/Metis/myqsort.c @@ -0,0 +1,547 @@ +/* + * Copyright 1997, Regents of the University of Minnesota + * + * myqsort.c + * + * This file contains a fast idxtype increasing qsort algorithm. + * Addopted from TeX + * + * Started 10/18/96 + * George + * + * $Id: myqsort.c,v 1.1 2005-09-21 17:29:38 geuzaine Exp $ + */ + +#include <metis.h> /* only for type declarations */ + +#define THRESH 1 /* threshold for insertion */ +#define MTHRESH 6 /* threshold for median */ + + + + +static void siqst(idxtype *, idxtype *); +static void iiqst(int *, int *); +static void keyiqst(KeyValueType *, KeyValueType *); +static void keyvaliqst(KeyValueType *, KeyValueType *); + + +/************************************************************************* +* Entry point of idxtype increasing sort +**************************************************************************/ +void iidxsort(int n, idxtype *base) +{ + register idxtype *i; + register idxtype *j; + register idxtype *lo; + register idxtype *hi; + register idxtype *min; + register idxtype c; + idxtype *max; + + if (n <= 1) + return; + + max = base + n; + + if (n >= THRESH) { + siqst(base, max); + hi = base + THRESH; + } + else + hi = max; + + for (j = lo = base; lo++ < hi;) { + if (*j > *lo) + j = lo; + } + if (j != base) { /* swap j into place */ + c = *base; + *base = *j; + *j = c; + } + + for (min = base; (hi = min += 1) < max;) { + while (*(--hi) > *min); + if ((hi += 1) != min) { + for (lo = min + 1; --lo >= min;) { + c = *lo; + for (i = j = lo; (j -= 1) >= hi; i = j) + *i = *j; + *i = c; + } + } + } +} + +static void siqst(idxtype *base, idxtype *max) +{ + register idxtype *i; + register idxtype *j; + register idxtype *jj; + register idxtype *mid; + register int ii; + register idxtype c; + idxtype *tmp; + int lo; + int hi; + + lo = max - base; /* number of elements as idxtype */ + do { + mid = base + ((unsigned) lo>>1); + if (lo >= MTHRESH) { + j = (*base > *mid ? base : mid); + tmp = max - 1; + if (*j > *tmp) { + j = (j == base ? mid : base); /* switch to first loser */ + if (*j < *tmp) + j = tmp; + } + + if (j != mid) { /* SWAP */ + c = *mid; + *mid = *j; + *j = c; + } + } + + /* Semi-standard quicksort partitioning/swapping */ + for (i = base, j = max - 1;;) { + while (i < mid && *i <= *mid) + i++; + while (j > mid) { + if (*mid <= *j) { + j--; + continue; + } + tmp = i + 1; /* value of i after swap */ + if (i == mid) /* j <-> mid, new mid is j */ + mid = jj = j; + else /* i <-> j */ + jj = j--; + goto swap; + } + + if (i == mid) + break; + else { /* i <-> mid, new mid is i */ + jj = mid; + tmp = mid = i; /* value of i after swap */ + j--; + } +swap: + c = *i; + *i = *jj; + *jj = c; + i = tmp; + } + + i = (j = mid) + 1; + if ((lo = j - base) <= (hi = max - i)) { + if (lo >= THRESH) + siqst(base, j); + base = i; + lo = hi; + } + else { + if (hi >= THRESH) + siqst(i, max); + max = j; + } + } while (lo >= THRESH); +} + + + + + +/************************************************************************* +* Entry point of int increasing sort +**************************************************************************/ +void iintsort(int n, int *base) +{ + register int *i; + register int *j; + register int *lo; + register int *hi; + register int *min; + register int c; + int *max; + + if (n <= 1) + return; + + max = base + n; + + if (n >= THRESH) { + iiqst(base, max); + hi = base + THRESH; + } + else + hi = max; + + for (j = lo = base; lo++ < hi;) { + if (*j > *lo) + j = lo; + } + if (j != base) { /* swap j into place */ + c = *base; + *base = *j; + *j = c; + } + + for (min = base; (hi = min += 1) < max;) { + while (*(--hi) > *min); + if ((hi += 1) != min) { + for (lo = min + 1; --lo >= min;) { + c = *lo; + for (i = j = lo; (j -= 1) >= hi; i = j) + *i = *j; + *i = c; + } + } + } +} + + +static void iiqst(int *base, int *max) +{ + register int *i; + register int *j; + register int *jj; + register int *mid; + register int ii; + register int c; + int *tmp; + int lo; + int hi; + + lo = max - base; /* number of elements as ints */ + do { + mid = base + ((unsigned) lo>>1); + if (lo >= MTHRESH) { + j = (*base > *mid ? base : mid); + tmp = max - 1; + if (*j > *tmp) { + j = (j == base ? mid : base); /* switch to first loser */ + if (*j < *tmp) + j = tmp; + } + + if (j != mid) { /* SWAP */ + c = *mid; + *mid = *j; + *j = c; + } + } + + /* Semi-standard quicksort partitioning/swapping */ + for (i = base, j = max - 1;;) { + while (i < mid && *i <= *mid) + i++; + while (j > mid) { + if (*mid <= *j) { + j--; + continue; + } + tmp = i + 1; /* value of i after swap */ + if (i == mid) /* j <-> mid, new mid is j */ + mid = jj = j; + else /* i <-> j */ + jj = j--; + goto swap; + } + + if (i == mid) + break; + else { /* i <-> mid, new mid is i */ + jj = mid; + tmp = mid = i; /* value of i after swap */ + j--; + } +swap: + c = *i; + *i = *jj; + *jj = c; + i = tmp; + } + + i = (j = mid) + 1; + if ((lo = j - base) <= (hi = max - i)) { + if (lo >= THRESH) + iiqst(base, j); + base = i; + lo = hi; + } + else { + if (hi >= THRESH) + iiqst(i, max); + max = j; + } + } while (lo >= THRESH); +} + + + + + +/************************************************************************* +* Entry point of KeyVal increasing sort, ONLY key part +**************************************************************************/ +void ikeysort(int n, KeyValueType *base) +{ + register KeyValueType *i; + register KeyValueType *j; + register KeyValueType *lo; + register KeyValueType *hi; + register KeyValueType *min; + register KeyValueType c; + KeyValueType *max; + + if (n <= 1) + return; + + max = base + n; + + if (n >= THRESH) { + keyiqst(base, max); + hi = base + THRESH; + } + else + hi = max; + + for (j = lo = base; lo++ < hi;) { + if (j->key > lo->key) + j = lo; + } + if (j != base) { /* swap j into place */ + c = *base; + *base = *j; + *j = c; + } + + for (min = base; (hi = min += 1) < max;) { + while ((--hi)->key > min->key); + if ((hi += 1) != min) { + for (lo = min + 1; --lo >= min;) { + c = *lo; + for (i = j = lo; (j -= 1) >= hi; i = j) + *i = *j; + *i = c; + } + } + } + + /* Sanity check */ + { + int i; + for (i=0; i<n-1; i++) + if (base[i].key > base[i+1].key) + printf("Something went wrong!\n"); + } +} + + +static void keyiqst(KeyValueType *base, KeyValueType *max) +{ + register KeyValueType *i; + register KeyValueType *j; + register KeyValueType *jj; + register KeyValueType *mid; + register KeyValueType c; + KeyValueType *tmp; + int lo; + int hi; + + lo = (max - base)>>1; /* number of elements as KeyValueType */ + do { + mid = base + ((unsigned) lo>>1); + if (lo >= MTHRESH) { + j = (base->key > mid->key ? base : mid); + tmp = max - 1; + if (j->key > tmp->key) { + j = (j == base ? mid : base); /* switch to first loser */ + if (j->key < tmp->key) + j = tmp; + } + + if (j != mid) { /* SWAP */ + c = *mid; + *mid = *j; + *j = c; + } + } + + /* Semi-standard quicksort partitioning/swapping */ + for (i = base, j = max - 1;;) { + while (i < mid && i->key <= mid->key) + i++; + while (j > mid) { + if (mid->key <= j->key) { + j--; + continue; + } + tmp = i + 1; /* value of i after swap */ + if (i == mid) /* j <-> mid, new mid is j */ + mid = jj = j; + else /* i <-> j */ + jj = j--; + goto swap; + } + + if (i == mid) + break; + else { /* i <-> mid, new mid is i */ + jj = mid; + tmp = mid = i; /* value of i after swap */ + j--; + } +swap: + c = *i; + *i = *jj; + *jj = c; + i = tmp; + } + + i = (j = mid) + 1; + if ((lo = (j - base)>>1) <= (hi = (max - i)>>1)) { + if (lo >= THRESH) + keyiqst(base, j); + base = i; + lo = hi; + } + else { + if (hi >= THRESH) + keyiqst(i, max); + max = j; + } + } while (lo >= THRESH); +} + + + + +/************************************************************************* +* Entry point of KeyVal increasing sort, BOTH key and val part +**************************************************************************/ +void ikeyvalsort(int n, KeyValueType *base) +{ + register KeyValueType *i; + register KeyValueType *j; + register KeyValueType *lo; + register KeyValueType *hi; + register KeyValueType *min; + register KeyValueType c; + KeyValueType *max; + + if (n <= 1) + return; + + max = base + n; + + if (n >= THRESH) { + keyvaliqst(base, max); + hi = base + THRESH; + } + else + hi = max; + + for (j = lo = base; lo++ < hi;) { + if ((j->key > lo->key) || (j->key == lo->key && j->val > lo->val)) + j = lo; + } + if (j != base) { /* swap j into place */ + c = *base; + *base = *j; + *j = c; + } + + for (min = base; (hi = min += 1) < max;) { + while ((--hi)->key > min->key || (hi->key == min->key && hi->val > min->val)); + if ((hi += 1) != min) { + for (lo = min + 1; --lo >= min;) { + c = *lo; + for (i = j = lo; (j -= 1) >= hi; i = j) + *i = *j; + *i = c; + } + } + } +} + + +static void keyvaliqst(KeyValueType *base, KeyValueType *max) +{ + register KeyValueType *i; + register KeyValueType *j; + register KeyValueType *jj; + register KeyValueType *mid; + register KeyValueType c; + KeyValueType *tmp; + int lo; + int hi; + + lo = (max - base)>>1; /* number of elements as KeyValueType */ + do { + mid = base + ((unsigned) lo>>1); + if (lo >= MTHRESH) { + j = (base->key > mid->key || (base->key == mid->key && base->val > mid->val) ? base : mid); + tmp = max - 1; + if (j->key > tmp->key || (j->key == tmp->key && j->val > tmp->val)) { + j = (j == base ? mid : base); /* switch to first loser */ + if (j->key < tmp->key || (j->key == tmp->key && j->val < tmp->val)) + j = tmp; + } + + if (j != mid) { /* SWAP */ + c = *mid; + *mid = *j; + *j = c; + } + } + + /* Semi-standard quicksort partitioning/swapping */ + for (i = base, j = max - 1;;) { + while (i < mid && (i->key < mid->key || (i->key == mid->key && i->val <= mid->val))) + i++; + while (j > mid) { + if (mid->key < j->key || (mid->key == j->key && mid->val <= j->val)) { + j--; + continue; + } + tmp = i + 1; /* value of i after swap */ + if (i == mid) /* j <-> mid, new mid is j */ + mid = jj = j; + else /* i <-> j */ + jj = j--; + goto swap; + } + + if (i == mid) + break; + else { /* i <-> mid, new mid is i */ + jj = mid; + tmp = mid = i; /* value of i after swap */ + j--; + } +swap: + c = *i; + *i = *jj; + *jj = c; + i = tmp; + } + + i = (j = mid) + 1; + if ((lo = (j - base)>>1) <= (hi = (max - i)>>1)) { + if (lo >= THRESH) + keyvaliqst(base, j); + base = i; + lo = hi; + } + else { + if (hi >= THRESH) + keyvaliqst(i, max); + max = j; + } + } while (lo >= THRESH); +} diff --git a/contrib/Metis/ometis.c b/contrib/Metis/ometis.c new file mode 100644 index 0000000000..7be8a7a01a --- /dev/null +++ b/contrib/Metis/ometis.c @@ -0,0 +1,764 @@ +/* + * Copyright 1997, Regents of the University of Minnesota + * + * ometis.c + * + * This file contains the top level routines for the multilevel recursive + * bisection algorithm PMETIS. + * + * Started 7/24/97 + * George + * + * $Id: ometis.c,v 1.1 2005-09-21 17:29:38 geuzaine Exp $ + * + */ + +#include <metis.h> + + +/************************************************************************* +* This function is the entry point for OEMETIS +**************************************************************************/ +void METIS_EdgeND(int *nvtxs, idxtype *xadj, idxtype *adjncy, int *numflag, int *options, + idxtype *perm, idxtype *iperm) +{ + int i, j; + GraphType graph; + CtrlType ctrl; + + if (*numflag == 1) + Change2CNumbering(*nvtxs, xadj, adjncy); + + SetUpGraph(&graph, OP_OEMETIS, *nvtxs, 1, xadj, adjncy, NULL, NULL, 0); + + if (options[0] == 0) { /* Use the default parameters */ + ctrl.CType = OEMETIS_CTYPE; + ctrl.IType = OEMETIS_ITYPE; + ctrl.RType = OEMETIS_RTYPE; + ctrl.dbglvl = OEMETIS_DBGLVL; + } + else { + ctrl.CType = options[OPTION_CTYPE]; + ctrl.IType = options[OPTION_ITYPE]; + ctrl.RType = options[OPTION_RTYPE]; + ctrl.dbglvl = options[OPTION_DBGLVL]; + } + ctrl.oflags = 0; + ctrl.pfactor = -1; + ctrl.nseps = 1; + + ctrl.optype = OP_OEMETIS; + ctrl.CoarsenTo = 20; + ctrl.maxvwgt = 1.5*(idxsum(*nvtxs, graph.vwgt)/ctrl.CoarsenTo); + + InitRandom(-1); + + AllocateWorkSpace(&ctrl, &graph, 2); + + IFSET(ctrl.dbglvl, DBG_TIME, InitTimers(&ctrl)); + IFSET(ctrl.dbglvl, DBG_TIME, starttimer(ctrl.TotalTmr)); + + MlevelNestedDissection(&ctrl, &graph, iperm, ORDER_UNBALANCE_FRACTION, *nvtxs); + + IFSET(ctrl.dbglvl, DBG_TIME, stoptimer(ctrl.TotalTmr)); + IFSET(ctrl.dbglvl, DBG_TIME, PrintTimers(&ctrl)); + + for (i=0; i<*nvtxs; i++) + perm[iperm[i]] = i; + + FreeWorkSpace(&ctrl, &graph); + + if (*numflag == 1) + Change2FNumberingOrder(*nvtxs, xadj, adjncy, perm, iperm); +} + + +/************************************************************************* +* This function is the entry point for ONCMETIS +**************************************************************************/ +void METIS_NodeND(int *nvtxs, idxtype *xadj, idxtype *adjncy, int *numflag, int *options, + idxtype *perm, idxtype *iperm) +{ + int i, ii, j, l, wflag, nflag; + GraphType graph; + CtrlType ctrl; + idxtype *cptr, *cind, *piperm; + + if (*numflag == 1) + Change2CNumbering(*nvtxs, xadj, adjncy); + + if (options[0] == 0) { /* Use the default parameters */ + ctrl.CType = ONMETIS_CTYPE; + ctrl.IType = ONMETIS_ITYPE; + ctrl.RType = ONMETIS_RTYPE; + ctrl.dbglvl = ONMETIS_DBGLVL; + ctrl.oflags = ONMETIS_OFLAGS; + ctrl.pfactor = ONMETIS_PFACTOR; + ctrl.nseps = ONMETIS_NSEPS; + } + else { + ctrl.CType = options[OPTION_CTYPE]; + ctrl.IType = options[OPTION_ITYPE]; + ctrl.RType = options[OPTION_RTYPE]; + ctrl.dbglvl = options[OPTION_DBGLVL]; + ctrl.oflags = options[OPTION_OFLAGS]; + ctrl.pfactor = options[OPTION_PFACTOR]; + ctrl.nseps = options[OPTION_NSEPS]; + } + if (ctrl.nseps < 1) + ctrl.nseps = 1; + + ctrl.optype = OP_ONMETIS; + ctrl.CoarsenTo = 100; + + IFSET(ctrl.dbglvl, DBG_TIME, InitTimers(&ctrl)); + IFSET(ctrl.dbglvl, DBG_TIME, starttimer(ctrl.TotalTmr)); + + InitRandom(-1); + + if (ctrl.pfactor > 0) { + /*============================================================ + * Prune the dense columns + ==============================================================*/ + piperm = idxmalloc(*nvtxs, "ONMETIS: piperm"); + + PruneGraph(&ctrl, &graph, *nvtxs, xadj, adjncy, piperm, (float)(0.1*ctrl.pfactor)); + } + else if (ctrl.oflags&OFLAG_COMPRESS) { + /*============================================================ + * Compress the graph + ==============================================================*/ + cptr = idxmalloc(*nvtxs+1, "ONMETIS: cptr"); + cind = idxmalloc(*nvtxs, "ONMETIS: cind"); + + CompressGraph(&ctrl, &graph, *nvtxs, xadj, adjncy, cptr, cind); + + if (graph.nvtxs >= COMPRESSION_FRACTION*(*nvtxs)) { + ctrl.oflags--; /* We actually performed no compression */ + GKfree(&cptr, &cind, LTERM); + } + else if (2*graph.nvtxs < *nvtxs && ctrl.nseps == 1) + ctrl.nseps = 2; + } + else { + SetUpGraph(&graph, OP_ONMETIS, *nvtxs, 1, xadj, adjncy, NULL, NULL, 0); + } + + + /*============================================================= + * Do the nested dissection ordering + --=============================================================*/ + ctrl.maxvwgt = 1.5*(idxsum(graph.nvtxs, graph.vwgt)/ctrl.CoarsenTo); + AllocateWorkSpace(&ctrl, &graph, 2); + + if (ctrl.oflags&OFLAG_CCMP) + MlevelNestedDissectionCC(&ctrl, &graph, iperm, ORDER_UNBALANCE_FRACTION, graph.nvtxs); + else + MlevelNestedDissection(&ctrl, &graph, iperm, ORDER_UNBALANCE_FRACTION, graph.nvtxs); + + FreeWorkSpace(&ctrl, &graph); + + if (ctrl.pfactor > 0) { /* Order any prunned vertices */ + if (graph.nvtxs < *nvtxs) { + idxcopy(graph.nvtxs, iperm, perm); /* Use perm as an auxiliary array */ + for (i=0; i<graph.nvtxs; i++) + iperm[piperm[i]] = perm[i]; + for (i=graph.nvtxs; i<*nvtxs; i++) + iperm[piperm[i]] = i; + } + + GKfree(&piperm, LTERM); + } + else if (ctrl.oflags&OFLAG_COMPRESS) { /* Uncompress the ordering */ + if (graph.nvtxs < COMPRESSION_FRACTION*(*nvtxs)) { + /* construct perm from iperm */ + for (i=0; i<graph.nvtxs; i++) + perm[iperm[i]] = i; + for (l=ii=0; ii<graph.nvtxs; ii++) { + i = perm[ii]; + for (j=cptr[i]; j<cptr[i+1]; j++) + iperm[cind[j]] = l++; + } + } + + GKfree(&cptr, &cind, LTERM); + } + + + for (i=0; i<*nvtxs; i++) + perm[iperm[i]] = i; + + IFSET(ctrl.dbglvl, DBG_TIME, stoptimer(ctrl.TotalTmr)); + IFSET(ctrl.dbglvl, DBG_TIME, PrintTimers(&ctrl)); + + if (*numflag == 1) + Change2FNumberingOrder(*nvtxs, xadj, adjncy, perm, iperm); + +} + + +/************************************************************************* +* This function is the entry point for ONWMETIS. It requires weights on the +* vertices. It is for the case that the matrix has been pre-compressed. +**************************************************************************/ +void METIS_NodeWND(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, int *numflag, + int *options, idxtype *perm, idxtype *iperm) +{ + int i, j, tvwgt; + GraphType graph; + CtrlType ctrl; + + if (*numflag == 1) + Change2CNumbering(*nvtxs, xadj, adjncy); + + SetUpGraph(&graph, OP_ONMETIS, *nvtxs, 1, xadj, adjncy, vwgt, NULL, 2); + + if (options[0] == 0) { /* Use the default parameters */ + ctrl.CType = ONMETIS_CTYPE; + ctrl.IType = ONMETIS_ITYPE; + ctrl.RType = ONMETIS_RTYPE; + ctrl.dbglvl = ONMETIS_DBGLVL; + } + else { + ctrl.CType = options[OPTION_CTYPE]; + ctrl.IType = options[OPTION_ITYPE]; + ctrl.RType = options[OPTION_RTYPE]; + ctrl.dbglvl = options[OPTION_DBGLVL]; + } + + ctrl.oflags = OFLAG_COMPRESS; + ctrl.pfactor = 0; + ctrl.nseps = 2; + ctrl.optype = OP_ONMETIS; + ctrl.CoarsenTo = 100; + ctrl.maxvwgt = 1.5*(idxsum(*nvtxs, graph.vwgt)/ctrl.CoarsenTo); + + InitRandom(-1); + + AllocateWorkSpace(&ctrl, &graph, 2); + + IFSET(ctrl.dbglvl, DBG_TIME, InitTimers(&ctrl)); + IFSET(ctrl.dbglvl, DBG_TIME, starttimer(ctrl.TotalTmr)); + + MlevelNestedDissection(&ctrl, &graph, iperm, ORDER_UNBALANCE_FRACTION, *nvtxs); + + IFSET(ctrl.dbglvl, DBG_TIME, stoptimer(ctrl.TotalTmr)); + IFSET(ctrl.dbglvl, DBG_TIME, PrintTimers(&ctrl)); + + for (i=0; i<*nvtxs; i++) + perm[iperm[i]] = i; + + FreeWorkSpace(&ctrl, &graph); + + if (*numflag == 1) + Change2FNumberingOrder(*nvtxs, xadj, adjncy, perm, iperm); +} + + + + +/************************************************************************* +* This function takes a graph and produces a bisection of it +**************************************************************************/ +void MlevelNestedDissection(CtrlType *ctrl, GraphType *graph, idxtype *order, float ubfactor, int lastvtx) +{ + int i, j, nvtxs, nbnd, tvwgt, tpwgts2[2]; + idxtype *label, *bndind; + GraphType lgraph, rgraph; + + nvtxs = graph->nvtxs; + + /* Determine the weights of the partitions */ + tvwgt = idxsum(nvtxs, graph->vwgt); + tpwgts2[0] = tvwgt/2; + tpwgts2[1] = tvwgt-tpwgts2[0]; + + switch (ctrl->optype) { + case OP_OEMETIS: + MlevelEdgeBisection(ctrl, graph, tpwgts2, ubfactor); + + IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->SepTmr)); + ConstructMinCoverSeparator(ctrl, graph, ubfactor); + IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->SepTmr)); + + break; + case OP_ONMETIS: + MlevelNodeBisectionMultiple(ctrl, graph, tpwgts2, ubfactor); + + IFSET(ctrl->dbglvl, DBG_SEPINFO, printf("Nvtxs: %6d, [%6d %6d %6d]\n", graph->nvtxs, graph->pwgts[0], graph->pwgts[1], graph->pwgts[2])); + + break; + } + + /* Order the nodes in the separator */ + nbnd = graph->nbnd; + bndind = graph->bndind; + label = graph->label; + for (i=0; i<nbnd; i++) + order[label[bndind[i]]] = --lastvtx; + + SplitGraphOrder(ctrl, graph, &lgraph, &rgraph); + + /* Free the memory of the top level graph */ + GKfree(&graph->gdata, &graph->rdata, &graph->label, LTERM); + + if (rgraph.nvtxs > MMDSWITCH) + MlevelNestedDissection(ctrl, &rgraph, order, ubfactor, lastvtx); + else { + MMDOrder(ctrl, &rgraph, order, lastvtx); + GKfree(&rgraph.gdata, &rgraph.rdata, &rgraph.label, LTERM); + } + if (lgraph.nvtxs > MMDSWITCH) + MlevelNestedDissection(ctrl, &lgraph, order, ubfactor, lastvtx-rgraph.nvtxs); + else { + MMDOrder(ctrl, &lgraph, order, lastvtx-rgraph.nvtxs); + GKfree(&lgraph.gdata, &lgraph.rdata, &lgraph.label, LTERM); + } +} + + +/************************************************************************* +* This function takes a graph and produces a bisection of it +**************************************************************************/ +void MlevelNestedDissectionCC(CtrlType *ctrl, GraphType *graph, idxtype *order, float ubfactor, int lastvtx) +{ + int i, j, nvtxs, nbnd, tvwgt, tpwgts2[2], nsgraphs, ncmps, rnvtxs; + idxtype *label, *bndind; + idxtype *cptr, *cind; + GraphType *sgraphs; + + nvtxs = graph->nvtxs; + + /* Determine the weights of the partitions */ + tvwgt = idxsum(nvtxs, graph->vwgt); + tpwgts2[0] = tvwgt/2; + tpwgts2[1] = tvwgt-tpwgts2[0]; + + MlevelNodeBisectionMultiple(ctrl, graph, tpwgts2, ubfactor); + IFSET(ctrl->dbglvl, DBG_SEPINFO, printf("Nvtxs: %6d, [%6d %6d %6d]\n", graph->nvtxs, graph->pwgts[0], graph->pwgts[1], graph->pwgts[2])); + + /* Order the nodes in the separator */ + nbnd = graph->nbnd; + bndind = graph->bndind; + label = graph->label; + for (i=0; i<nbnd; i++) + order[label[bndind[i]]] = --lastvtx; + + cptr = idxmalloc(nvtxs, "MlevelNestedDissectionCC: cptr"); + cind = idxmalloc(nvtxs, "MlevelNestedDissectionCC: cind"); + ncmps = FindComponents(ctrl, graph, cptr, cind); + +/* + if (ncmps > 2) + printf("[%5d] has %3d components\n", nvtxs, ncmps); +*/ + + sgraphs = (GraphType *)GKmalloc(ncmps*sizeof(GraphType), "MlevelNestedDissectionCC: sgraphs"); + + nsgraphs = SplitGraphOrderCC(ctrl, graph, sgraphs, ncmps, cptr, cind); + + GKfree(&cptr, &cind, LTERM); + + /* Free the memory of the top level graph */ + GKfree(&graph->gdata, &graph->rdata, &graph->label, LTERM); + + /* Go and process the subgraphs */ + for (rnvtxs=i=0; i<nsgraphs; i++) { + if (sgraphs[i].adjwgt == NULL) { + MMDOrder(ctrl, sgraphs+i, order, lastvtx-rnvtxs); + GKfree(&sgraphs[i].gdata, &sgraphs[i].label, LTERM); + } + else { + MlevelNestedDissectionCC(ctrl, sgraphs+i, order, ubfactor, lastvtx-rnvtxs); + } + rnvtxs += sgraphs[i].nvtxs; + } + + free(sgraphs); +} + + + +/************************************************************************* +* This function performs multilevel bisection. It performs multiple +* bisections and selects the best. +**************************************************************************/ +void MlevelNodeBisectionMultiple(CtrlType *ctrl, GraphType *graph, int *tpwgts, float ubfactor) +{ + int i, nvtxs, cnvtxs, mincut, tmp; + GraphType *cgraph; + idxtype *bestwhere; + + if (ctrl->nseps == 1 || graph->nvtxs < (ctrl->oflags&OFLAG_COMPRESS ? 1000 : 2000)) { + MlevelNodeBisection(ctrl, graph, tpwgts, ubfactor); + return; + } + + nvtxs = graph->nvtxs; + + if (ctrl->oflags&OFLAG_COMPRESS) { /* Multiple separators at the original graph */ + bestwhere = idxmalloc(nvtxs, "MlevelNodeBisection2: bestwhere"); + mincut = nvtxs; + + for (i=ctrl->nseps; i>0; i--) { + MlevelNodeBisection(ctrl, graph, tpwgts, ubfactor); + + /* printf("%5d ", cgraph->mincut); */ + + if (graph->mincut < mincut) { + mincut = graph->mincut; + idxcopy(nvtxs, graph->where, bestwhere); + } + + GKfree(&graph->rdata, LTERM); + + if (mincut == 0) + break; + } + /* printf("[%5d]\n", mincut); */ + + Allocate2WayNodePartitionMemory(ctrl, graph); + idxcopy(nvtxs, bestwhere, graph->where); + free(bestwhere); + + Compute2WayNodePartitionParams(ctrl, graph); + } + else { /* Coarsen it a bit */ + ctrl->CoarsenTo = nvtxs-1; + + cgraph = Coarsen2Way(ctrl, graph); + + cnvtxs = cgraph->nvtxs; + + bestwhere = idxmalloc(cnvtxs, "MlevelNodeBisection2: bestwhere"); + mincut = nvtxs; + + for (i=ctrl->nseps; i>0; i--) { + ctrl->CType += 20; /* This is a hack. Look at coarsen.c */ + MlevelNodeBisection(ctrl, cgraph, tpwgts, ubfactor); + + /* printf("%5d ", cgraph->mincut); */ + + if (cgraph->mincut < mincut) { + mincut = cgraph->mincut; + idxcopy(cnvtxs, cgraph->where, bestwhere); + } + + GKfree(&cgraph->rdata, LTERM); + + if (mincut == 0) + break; + } + /* printf("[%5d]\n", mincut); */ + + Allocate2WayNodePartitionMemory(ctrl, cgraph); + idxcopy(cnvtxs, bestwhere, cgraph->where); + free(bestwhere); + + Compute2WayNodePartitionParams(ctrl, cgraph); + + Refine2WayNode(ctrl, graph, cgraph, ubfactor); + } + +} + +/************************************************************************* +* This function performs multilevel bisection +**************************************************************************/ +void MlevelNodeBisection(CtrlType *ctrl, GraphType *graph, int *tpwgts, float ubfactor) +{ + GraphType *cgraph; + + ctrl->CoarsenTo = graph->nvtxs/8; + if (ctrl->CoarsenTo > 100) + ctrl->CoarsenTo = 100; + else if (ctrl->CoarsenTo < 40) + ctrl->CoarsenTo = 40; + ctrl->maxvwgt = 1.5*((tpwgts[0]+tpwgts[1])/ctrl->CoarsenTo); + + cgraph = Coarsen2Way(ctrl, graph); + + switch (ctrl->IType) { + case IPART_GGPKL: + Init2WayPartition(ctrl, cgraph, tpwgts, ubfactor); + + IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->SepTmr)); + + Compute2WayPartitionParams(ctrl, cgraph); + ConstructSeparator(ctrl, cgraph, ubfactor); + + IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->SepTmr)); + break; + case IPART_GGPKLNODE: + InitSeparator(ctrl, cgraph, ubfactor); + break; + } + + Refine2WayNode(ctrl, graph, cgraph, ubfactor); + +} + + + + +/************************************************************************* +* This function takes a graph and a bisection and splits it into two graphs. +* This function relies on the fact that adjwgt is all equal to 1. +**************************************************************************/ +void SplitGraphOrder(CtrlType *ctrl, GraphType *graph, GraphType *lgraph, GraphType *rgraph) +{ + int i, ii, j, k, l, istart, iend, mypart, nvtxs, snvtxs[3], snedges[3]; + idxtype *xadj, *vwgt, *adjncy, *adjwgt, *adjwgtsum, *label, *where, *bndptr, *bndind; + idxtype *sxadj[2], *svwgt[2], *sadjncy[2], *sadjwgt[2], *sadjwgtsum[2], *slabel[2]; + idxtype *rename; + idxtype *auxadjncy, *auxadjwgt; + + IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->SplitTmr)); + + nvtxs = graph->nvtxs; + xadj = graph->xadj; + vwgt = graph->vwgt; + adjncy = graph->adjncy; + adjwgt = graph->adjwgt; + adjwgtsum = graph->adjwgtsum; + label = graph->label; + where = graph->where; + bndptr = graph->bndptr; + bndind = graph->bndind; + ASSERT(bndptr != NULL); + + rename = idxwspacemalloc(ctrl, nvtxs); + + snvtxs[0] = snvtxs[1] = snvtxs[2] = snedges[0] = snedges[1] = snedges[2] = 0; + for (i=0; i<nvtxs; i++) { + k = where[i]; + rename[i] = snvtxs[k]++; + snedges[k] += xadj[i+1]-xadj[i]; + } + + SetUpSplitGraph(graph, lgraph, snvtxs[0], snedges[0]); + sxadj[0] = lgraph->xadj; + svwgt[0] = lgraph->vwgt; + sadjwgtsum[0] = lgraph->adjwgtsum; + sadjncy[0] = lgraph->adjncy; + sadjwgt[0] = lgraph->adjwgt; + slabel[0] = lgraph->label; + + SetUpSplitGraph(graph, rgraph, snvtxs[1], snedges[1]); + sxadj[1] = rgraph->xadj; + svwgt[1] = rgraph->vwgt; + sadjwgtsum[1] = rgraph->adjwgtsum; + sadjncy[1] = rgraph->adjncy; + sadjwgt[1] = rgraph->adjwgt; + slabel[1] = rgraph->label; + + /* Go and use bndptr to also mark the boundary nodes in the two partitions */ + for (ii=0; ii<graph->nbnd; ii++) { + i = bndind[ii]; + for (j=xadj[i]; j<xadj[i+1]; j++) + bndptr[adjncy[j]] = 1; + } + + snvtxs[0] = snvtxs[1] = snedges[0] = snedges[1] = 0; + sxadj[0][0] = sxadj[1][0] = 0; + for (i=0; i<nvtxs; i++) { + if ((mypart = where[i]) == 2) + continue; + + istart = xadj[i]; + iend = xadj[i+1]; + if (bndptr[i] == -1) { /* This is an interior vertex */ + auxadjncy = sadjncy[mypart] + snedges[mypart] - istart; + for(j=istart; j<iend; j++) + auxadjncy[j] = adjncy[j]; + snedges[mypart] += iend-istart; + } + else { + auxadjncy = sadjncy[mypart]; + l = snedges[mypart]; + for (j=istart; j<iend; j++) { + k = adjncy[j]; + if (where[k] == mypart) + auxadjncy[l++] = k; + } + snedges[mypart] = l; + } + + svwgt[mypart][snvtxs[mypart]] = vwgt[i]; + sadjwgtsum[mypart][snvtxs[mypart]] = snedges[mypart]-sxadj[mypart][snvtxs[mypart]]; + slabel[mypart][snvtxs[mypart]] = label[i]; + sxadj[mypart][++snvtxs[mypart]] = snedges[mypart]; + } + + for (mypart=0; mypart<2; mypart++) { + iend = snedges[mypart]; + idxset(iend, 1, sadjwgt[mypart]); + + auxadjncy = sadjncy[mypart]; + for (i=0; i<iend; i++) + auxadjncy[i] = rename[auxadjncy[i]]; + } + + lgraph->nvtxs = snvtxs[0]; + lgraph->nedges = snedges[0]; + rgraph->nvtxs = snvtxs[1]; + rgraph->nedges = snedges[1]; + + IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->SplitTmr)); + + idxwspacefree(ctrl, nvtxs); + +} + +/************************************************************************* +* This function uses MMD to order the graph. The vertices are numbered +* from lastvtx downwards +**************************************************************************/ +void MMDOrder(CtrlType *ctrl, GraphType *graph, idxtype *order, int lastvtx) +{ + int i, j, k, nvtxs, nofsub, firstvtx; + idxtype *xadj, *adjncy, *label; + idxtype *perm, *iperm, *head, *qsize, *list, *marker; + + nvtxs = graph->nvtxs; + xadj = graph->xadj; + adjncy = graph->adjncy; + + /* Relabel the vertices so that it starts from 1 */ + k = xadj[nvtxs]; + for (i=0; i<k; i++) + adjncy[i]++; + for (i=0; i<nvtxs+1; i++) + xadj[i]++; + + perm = idxmalloc(6*(nvtxs+5), "MMDOrder: perm"); + iperm = perm + nvtxs + 5; + head = iperm + nvtxs + 5; + qsize = head + nvtxs + 5; + list = qsize + nvtxs + 5; + marker = list + nvtxs + 5; + + genmmd(nvtxs, xadj, adjncy, iperm, perm, 1, head, qsize, list, marker, MAXIDX, &nofsub); + + label = graph->label; + firstvtx = lastvtx-nvtxs; + for (i=0; i<nvtxs; i++) + order[label[i]] = firstvtx+iperm[i]-1; + + free(perm); + + /* Relabel the vertices so that it starts from 0 */ + for (i=0; i<nvtxs+1; i++) + xadj[i]--; + k = xadj[nvtxs]; + for (i=0; i<k; i++) + adjncy[i]--; +} + + +/************************************************************************* +* This function takes a graph and a bisection and splits it into two graphs. +* It relies on the fact that adjwgt is all set to 1. +**************************************************************************/ +int SplitGraphOrderCC(CtrlType *ctrl, GraphType *graph, GraphType *sgraphs, int ncmps, idxtype *cptr, idxtype *cind) +{ + int i, ii, iii, j, k, l, istart, iend, mypart, nvtxs, snvtxs, snedges; + idxtype *xadj, *vwgt, *adjncy, *adjwgt, *adjwgtsum, *label, *where, *bndptr, *bndind; + idxtype *sxadj, *svwgt, *sadjncy, *sadjwgt, *sadjwgtsum, *slabel; + idxtype *rename; + idxtype *auxadjncy, *auxadjwgt; + + IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->SplitTmr)); + + nvtxs = graph->nvtxs; + xadj = graph->xadj; + vwgt = graph->vwgt; + adjncy = graph->adjncy; + adjwgt = graph->adjwgt; + adjwgtsum = graph->adjwgtsum; + label = graph->label; + where = graph->where; + bndptr = graph->bndptr; + bndind = graph->bndind; + ASSERT(bndptr != NULL); + + /* Go and use bndptr to also mark the boundary nodes in the two partitions */ + for (ii=0; ii<graph->nbnd; ii++) { + i = bndind[ii]; + for (j=xadj[i]; j<xadj[i+1]; j++) + bndptr[adjncy[j]] = 1; + } + + rename = idxwspacemalloc(ctrl, nvtxs); + + /* Go and split the graph a component at a time */ + for (iii=0; iii<ncmps; iii++) { + RandomPermute(cptr[iii+1]-cptr[iii], cind+cptr[iii], 0); + snvtxs = snedges = 0; + for (j=cptr[iii]; j<cptr[iii+1]; j++) { + i = cind[j]; + rename[i] = snvtxs++; + snedges += xadj[i+1]-xadj[i]; + } + + SetUpSplitGraph(graph, sgraphs+iii, snvtxs, snedges); + sxadj = sgraphs[iii].xadj; + svwgt = sgraphs[iii].vwgt; + sadjwgtsum = sgraphs[iii].adjwgtsum; + sadjncy = sgraphs[iii].adjncy; + sadjwgt = sgraphs[iii].adjwgt; + slabel = sgraphs[iii].label; + + snvtxs = snedges = sxadj[0] = 0; + for (ii=cptr[iii]; ii<cptr[iii+1]; ii++) { + i = cind[ii]; + + istart = xadj[i]; + iend = xadj[i+1]; + if (bndptr[i] == -1) { /* This is an interior vertex */ + auxadjncy = sadjncy + snedges - istart; + auxadjwgt = sadjwgt + snedges - istart; + for(j=istart; j<iend; j++) + auxadjncy[j] = adjncy[j]; + snedges += iend-istart; + } + else { + l = snedges; + for (j=istart; j<iend; j++) { + k = adjncy[j]; + if (where[k] != 2) + sadjncy[l++] = k; + } + snedges = l; + } + + svwgt[snvtxs] = vwgt[i]; + sadjwgtsum[snvtxs] = snedges-sxadj[snvtxs]; + slabel[snvtxs] = label[i]; + sxadj[++snvtxs] = snedges; + } + + idxset(snedges, 1, sadjwgt); + for (i=0; i<snedges; i++) + sadjncy[i] = rename[sadjncy[i]]; + + sgraphs[iii].nvtxs = snvtxs; + sgraphs[iii].nedges = snedges; + sgraphs[iii].ncon = 1; + + if (snvtxs < MMDSWITCH) + sgraphs[iii].adjwgt = NULL; /* A marker to call MMD on the driver */ + } + + IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->SplitTmr)); + + idxwspacefree(ctrl, nvtxs); + + return ncmps; + +} + + + + + diff --git a/contrib/Metis/parmetis.c b/contrib/Metis/parmetis.c new file mode 100644 index 0000000000..fde3796737 --- /dev/null +++ b/contrib/Metis/parmetis.c @@ -0,0 +1,371 @@ +/* + * Copyright 1997, Regents of the University of Minnesota + * + * parmetis.c + * + * This file contains top level routines that are used by ParMETIS + * + * Started 10/14/97 + * George + * + * $Id: parmetis.c,v 1.1 2005-09-21 17:29:38 geuzaine Exp $ + * + */ + +#include <metis.h> + + +/************************************************************************* +* This function is the entry point for KMETIS with seed specification +* in options[7] +**************************************************************************/ +void METIS_PartGraphKway2(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, + idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts, + int *options, int *edgecut, idxtype *part) +{ + int i; + float *tpwgts; + + tpwgts = fmalloc(*nparts, "KMETIS: tpwgts"); + for (i=0; i<*nparts; i++) + tpwgts[i] = 1.0/(1.0*(*nparts)); + + METIS_WPartGraphKway2(nvtxs, xadj, adjncy, vwgt, adjwgt, wgtflag, numflag, nparts, + tpwgts, options, edgecut, part); + + free(tpwgts); +} + + +/************************************************************************* +* This function is the entry point for KWMETIS with seed specification +* in options[7] +**************************************************************************/ +void METIS_WPartGraphKway2(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, + idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts, + float *tpwgts, int *options, int *edgecut, idxtype *part) +{ + int i, j; + GraphType graph; + CtrlType ctrl; + + if (*numflag == 1) + Change2CNumbering(*nvtxs, xadj, adjncy); + + SetUpGraph(&graph, OP_KMETIS, *nvtxs, 1, xadj, adjncy, vwgt, adjwgt, *wgtflag); + + if (options[0] == 0) { /* Use the default parameters */ + ctrl.CType = KMETIS_CTYPE; + ctrl.IType = KMETIS_ITYPE; + ctrl.RType = KMETIS_RTYPE; + ctrl.dbglvl = KMETIS_DBGLVL; + } + else { + ctrl.CType = options[OPTION_CTYPE]; + ctrl.IType = options[OPTION_ITYPE]; + ctrl.RType = options[OPTION_RTYPE]; + ctrl.dbglvl = options[OPTION_DBGLVL]; + } + ctrl.optype = OP_KMETIS; + ctrl.CoarsenTo = 20*(*nparts); + ctrl.maxvwgt = 1.5*((graph.vwgt ? idxsum(*nvtxs, graph.vwgt) : (*nvtxs))/ctrl.CoarsenTo); + + InitRandom(options[7]); + + AllocateWorkSpace(&ctrl, &graph, *nparts); + + IFSET(ctrl.dbglvl, DBG_TIME, InitTimers(&ctrl)); + IFSET(ctrl.dbglvl, DBG_TIME, starttimer(ctrl.TotalTmr)); + + *edgecut = MlevelKWayPartitioning(&ctrl, &graph, *nparts, part, tpwgts, 1.03); + + IFSET(ctrl.dbglvl, DBG_TIME, stoptimer(ctrl.TotalTmr)); + IFSET(ctrl.dbglvl, DBG_TIME, PrintTimers(&ctrl)); + + FreeWorkSpace(&ctrl, &graph); + + if (*numflag == 1) + Change2FNumbering(*nvtxs, xadj, adjncy, part); +} + + +/************************************************************************* +* This function is the entry point for the node ND code for ParMETIS +**************************************************************************/ +void METIS_NodeNDP(int nvtxs, idxtype *xadj, idxtype *adjncy, int npes, + int *options, idxtype *perm, idxtype *iperm, idxtype *sizes) +{ + int i, ii, j, l, wflag, nflag; + GraphType graph; + CtrlType ctrl; + idxtype *cptr, *cind; + + if (options[0] == 0) { /* Use the default parameters */ + ctrl.CType = ONMETIS_CTYPE; + ctrl.IType = ONMETIS_ITYPE; + ctrl.RType = ONMETIS_RTYPE; + ctrl.dbglvl = ONMETIS_DBGLVL; + ctrl.oflags = ONMETIS_OFLAGS; + ctrl.pfactor = ONMETIS_PFACTOR; + ctrl.nseps = ONMETIS_NSEPS; + } + else { + ctrl.CType = options[OPTION_CTYPE]; + ctrl.IType = options[OPTION_ITYPE]; + ctrl.RType = options[OPTION_RTYPE]; + ctrl.dbglvl = options[OPTION_DBGLVL]; + ctrl.oflags = options[OPTION_OFLAGS]; + ctrl.pfactor = options[OPTION_PFACTOR]; + ctrl.nseps = options[OPTION_NSEPS]; + } + if (ctrl.nseps < 1) + ctrl.nseps = 1; + + ctrl.optype = OP_ONMETIS; + ctrl.CoarsenTo = 100; + + IFSET(ctrl.dbglvl, DBG_TIME, InitTimers(&ctrl)); + IFSET(ctrl.dbglvl, DBG_TIME, starttimer(ctrl.TotalTmr)); + + InitRandom(-1); + + if (ctrl.oflags&OFLAG_COMPRESS) { + /*============================================================ + * Compress the graph + ==============================================================*/ + cptr = idxmalloc(nvtxs+1, "ONMETIS: cptr"); + cind = idxmalloc(nvtxs, "ONMETIS: cind"); + + CompressGraph(&ctrl, &graph, nvtxs, xadj, adjncy, cptr, cind); + + if (graph.nvtxs >= COMPRESSION_FRACTION*(nvtxs)) { + ctrl.oflags--; /* We actually performed no compression */ + GKfree(&cptr, &cind, LTERM); + } + else if (2*graph.nvtxs < nvtxs && ctrl.nseps == 1) + ctrl.nseps = 2; + } + else { + SetUpGraph(&graph, OP_ONMETIS, nvtxs, 1, xadj, adjncy, NULL, NULL, 0); + } + + + /*============================================================= + * Do the nested dissection ordering + --=============================================================*/ + ctrl.maxvwgt = 1.5*(idxsum(graph.nvtxs, graph.vwgt)/ctrl.CoarsenTo); + AllocateWorkSpace(&ctrl, &graph, 2); + + idxset(2*npes-1, 0, sizes); + MlevelNestedDissectionP(&ctrl, &graph, iperm, graph.nvtxs, npes, 0, sizes); + + FreeWorkSpace(&ctrl, &graph); + + if (ctrl.oflags&OFLAG_COMPRESS) { /* Uncompress the ordering */ + if (graph.nvtxs < COMPRESSION_FRACTION*(nvtxs)) { + /* construct perm from iperm */ + for (i=0; i<graph.nvtxs; i++) + perm[iperm[i]] = i; + for (l=ii=0; ii<graph.nvtxs; ii++) { + i = perm[ii]; + for (j=cptr[i]; j<cptr[i+1]; j++) + iperm[cind[j]] = l++; + } + } + + GKfree(&cptr, &cind, LTERM); + } + + + for (i=0; i<nvtxs; i++) + perm[iperm[i]] = i; + + IFSET(ctrl.dbglvl, DBG_TIME, stoptimer(ctrl.TotalTmr)); + IFSET(ctrl.dbglvl, DBG_TIME, PrintTimers(&ctrl)); + +} + + + +/************************************************************************* +* This function takes a graph and produces a bisection of it +**************************************************************************/ +void MlevelNestedDissectionP(CtrlType *ctrl, GraphType *graph, idxtype *order, int lastvtx, + int npes, int cpos, idxtype *sizes) +{ + int i, j, nvtxs, nbnd, tvwgt, tpwgts2[2]; + idxtype *label, *bndind; + GraphType lgraph, rgraph; + float ubfactor; + + nvtxs = graph->nvtxs; + + if (nvtxs == 0) { + GKfree(&graph->gdata, &graph->rdata, &graph->label, LTERM); + return; + } + + /* Determine the weights of the partitions */ + tvwgt = idxsum(nvtxs, graph->vwgt); + tpwgts2[0] = tvwgt/2; + tpwgts2[1] = tvwgt-tpwgts2[0]; + + if (cpos >= npes-1) + ubfactor = ORDER_UNBALANCE_FRACTION; + else + ubfactor = 1.05; + + + MlevelNodeBisectionMultiple(ctrl, graph, tpwgts2, ubfactor); + + IFSET(ctrl->dbglvl, DBG_SEPINFO, printf("Nvtxs: %6d, [%6d %6d %6d]\n", graph->nvtxs, graph->pwgts[0], graph->pwgts[1], graph->pwgts[2])); + + if (cpos < npes-1) { + sizes[2*npes-2-cpos] = graph->pwgts[2]; + sizes[2*npes-2-(2*cpos+1)] = graph->pwgts[1]; + sizes[2*npes-2-(2*cpos+2)] = graph->pwgts[0]; + } + + /* Order the nodes in the separator */ + nbnd = graph->nbnd; + bndind = graph->bndind; + label = graph->label; + for (i=0; i<nbnd; i++) + order[label[bndind[i]]] = --lastvtx; + + SplitGraphOrder(ctrl, graph, &lgraph, &rgraph); + + /* Free the memory of the top level graph */ + GKfree(&graph->gdata, &graph->rdata, &graph->label, LTERM); + + if (rgraph.nvtxs > MMDSWITCH || 2*cpos+1 < npes-1) + MlevelNestedDissectionP(ctrl, &rgraph, order, lastvtx, npes, 2*cpos+1, sizes); + else { + MMDOrder(ctrl, &rgraph, order, lastvtx); + GKfree(&rgraph.gdata, &rgraph.rdata, &rgraph.label, LTERM); + } + if (lgraph.nvtxs > MMDSWITCH || 2*cpos+2 < npes-1) + MlevelNestedDissectionP(ctrl, &lgraph, order, lastvtx-rgraph.nvtxs, npes, 2*cpos+2, sizes); + else { + MMDOrder(ctrl, &lgraph, order, lastvtx-rgraph.nvtxs); + GKfree(&lgraph.gdata, &lgraph.rdata, &lgraph.label, LTERM); + } +} + + + + +/************************************************************************* +* This function is the entry point for ONWMETIS. It requires weights on the +* vertices. It is for the case that the matrix has been pre-compressed. +**************************************************************************/ +void METIS_NodeComputeSeparator(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, + idxtype *adjwgt, int *options, int *sepsize, idxtype *part) +{ + int i, j, tvwgt, tpwgts[2]; + GraphType graph; + CtrlType ctrl; + + SetUpGraph(&graph, OP_ONMETIS, *nvtxs, 1, xadj, adjncy, vwgt, adjwgt, 3); + tvwgt = idxsum(*nvtxs, graph.vwgt); + + if (options[0] == 0) { /* Use the default parameters */ + ctrl.CType = ONMETIS_CTYPE; + ctrl.IType = ONMETIS_ITYPE; + ctrl.RType = ONMETIS_RTYPE; + ctrl.dbglvl = ONMETIS_DBGLVL; + } + else { + ctrl.CType = options[OPTION_CTYPE]; + ctrl.IType = options[OPTION_ITYPE]; + ctrl.RType = options[OPTION_RTYPE]; + ctrl.dbglvl = options[OPTION_DBGLVL]; + } + + ctrl.oflags = 0; + ctrl.pfactor = 0; + ctrl.nseps = 1; + ctrl.optype = OP_ONMETIS; + ctrl.CoarsenTo = amin(100, *nvtxs-1); + ctrl.maxvwgt = 1.5*tvwgt/ctrl.CoarsenTo; + + InitRandom(options[7]); + + AllocateWorkSpace(&ctrl, &graph, 2); + + /*============================================================ + * Perform the bisection + *============================================================*/ + tpwgts[0] = tvwgt/2; + tpwgts[1] = tvwgt-tpwgts[0]; + + MlevelNodeBisectionMultiple(&ctrl, &graph, tpwgts, 1.05); + + *sepsize = graph.pwgts[2]; + idxcopy(*nvtxs, graph.where, part); + + GKfree(&graph.gdata, &graph.rdata, &graph.label, LTERM); + + + FreeWorkSpace(&ctrl, &graph); + +} + + + +/************************************************************************* +* This function is the entry point for ONWMETIS. It requires weights on the +* vertices. It is for the case that the matrix has been pre-compressed. +**************************************************************************/ +void METIS_EdgeComputeSeparator(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, + idxtype *adjwgt, int *options, int *sepsize, idxtype *part) +{ + int i, j, tvwgt, tpwgts[2]; + GraphType graph; + CtrlType ctrl; + + SetUpGraph(&graph, OP_ONMETIS, *nvtxs, 1, xadj, adjncy, vwgt, adjwgt, 3); + tvwgt = idxsum(*nvtxs, graph.vwgt); + + if (options[0] == 0) { /* Use the default parameters */ + ctrl.CType = ONMETIS_CTYPE; + ctrl.IType = ONMETIS_ITYPE; + ctrl.RType = ONMETIS_RTYPE; + ctrl.dbglvl = ONMETIS_DBGLVL; + } + else { + ctrl.CType = options[OPTION_CTYPE]; + ctrl.IType = options[OPTION_ITYPE]; + ctrl.RType = options[OPTION_RTYPE]; + ctrl.dbglvl = options[OPTION_DBGLVL]; + } + + ctrl.oflags = 0; + ctrl.pfactor = 0; + ctrl.nseps = 1; + ctrl.optype = OP_OEMETIS; + ctrl.CoarsenTo = amin(100, *nvtxs-1); + ctrl.maxvwgt = 1.5*tvwgt/ctrl.CoarsenTo; + + InitRandom(options[7]); + + AllocateWorkSpace(&ctrl, &graph, 2); + + /*============================================================ + * Perform the bisection + *============================================================*/ + tpwgts[0] = tvwgt/2; + tpwgts[1] = tvwgt-tpwgts[0]; + + MlevelEdgeBisection(&ctrl, &graph, tpwgts, 1.05); + ConstructMinCoverSeparator(&ctrl, &graph, 1.05); + + *sepsize = graph.pwgts[2]; + idxcopy(*nvtxs, graph.where, part); + + GKfree(&graph.gdata, &graph.rdata, &graph.label, LTERM); + + + FreeWorkSpace(&ctrl, &graph); + +} diff --git a/contrib/Metis/pmetis.c b/contrib/Metis/pmetis.c new file mode 100644 index 0000000000..76184117de --- /dev/null +++ b/contrib/Metis/pmetis.c @@ -0,0 +1,341 @@ +/* + * Copyright 1997, Regents of the University of Minnesota + * + * pmetis.c + * + * This file contains the top level routines for the multilevel recursive + * bisection algorithm PMETIS. + * + * Started 7/24/97 + * George + * + * $Id: pmetis.c,v 1.1 2005-09-21 17:29:38 geuzaine Exp $ + * + */ + +#include <metis.h> + + +/************************************************************************* +* This function is the entry point for PMETIS +**************************************************************************/ +void METIS_PartGraphRecursive(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, + idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts, + int *options, int *edgecut, idxtype *part) +{ + int i; + float *tpwgts; + + tpwgts = fmalloc(*nparts, "KMETIS: tpwgts"); + for (i=0; i<*nparts; i++) + tpwgts[i] = 1.0/(1.0*(*nparts)); + + METIS_WPartGraphRecursive(nvtxs, xadj, adjncy, vwgt, adjwgt, wgtflag, numflag, nparts, + tpwgts, options, edgecut, part); + + free(tpwgts); +} + + + +/************************************************************************* +* This function is the entry point for PWMETIS that accepts exact weights +* for the target partitions +**************************************************************************/ +void METIS_WPartGraphRecursive(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, + idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts, + float *tpwgts, int *options, int *edgecut, idxtype *part) +{ + int i, j; + GraphType graph; + CtrlType ctrl; + float *mytpwgts; + + if (*numflag == 1) + Change2CNumbering(*nvtxs, xadj, adjncy); + + SetUpGraph(&graph, OP_PMETIS, *nvtxs, 1, xadj, adjncy, vwgt, adjwgt, *wgtflag); + + if (options[0] == 0) { /* Use the default parameters */ + ctrl.CType = PMETIS_CTYPE; + ctrl.IType = PMETIS_ITYPE; + ctrl.RType = PMETIS_RTYPE; + ctrl.dbglvl = PMETIS_DBGLVL; + } + else { + ctrl.CType = options[OPTION_CTYPE]; + ctrl.IType = options[OPTION_ITYPE]; + ctrl.RType = options[OPTION_RTYPE]; + ctrl.dbglvl = options[OPTION_DBGLVL]; + } + ctrl.optype = OP_PMETIS; + ctrl.CoarsenTo = 20; + ctrl.maxvwgt = 1.5*(idxsum(*nvtxs, graph.vwgt)/ctrl.CoarsenTo); + + mytpwgts = fmalloc(*nparts, "PWMETIS: mytpwgts"); + for (i=0; i<*nparts; i++) + mytpwgts[i] = tpwgts[i]; + + InitRandom(-1); + + AllocateWorkSpace(&ctrl, &graph, *nparts); + + IFSET(ctrl.dbglvl, DBG_TIME, InitTimers(&ctrl)); + IFSET(ctrl.dbglvl, DBG_TIME, starttimer(ctrl.TotalTmr)); + + *edgecut = MlevelRecursiveBisection(&ctrl, &graph, *nparts, part, mytpwgts, 1.000, 0); + + IFSET(ctrl.dbglvl, DBG_TIME, stoptimer(ctrl.TotalTmr)); + IFSET(ctrl.dbglvl, DBG_TIME, PrintTimers(&ctrl)); + + FreeWorkSpace(&ctrl, &graph); + free(mytpwgts); + + if (*numflag == 1) + Change2FNumbering(*nvtxs, xadj, adjncy, part); +} + + + +/************************************************************************* +* This function takes a graph and produces a bisection of it +**************************************************************************/ +int MlevelRecursiveBisection(CtrlType *ctrl, GraphType *graph, int nparts, idxtype *part, float *tpwgts, float ubfactor, int fpart) +{ + int i, j, nvtxs, cut, tvwgt, tpwgts2[2]; + idxtype *label, *where; + GraphType lgraph, rgraph; + float wsum; + + nvtxs = graph->nvtxs; + if (nvtxs == 0) { + printf("\t***Cannot bisect a graph with 0 vertices!\n\t***You are trying to partition a graph into too many parts!\n"); + return 0; + } + + /* Determine the weights of the partitions */ + tvwgt = idxsum(nvtxs, graph->vwgt); + tpwgts2[0] = tvwgt*ssum(nparts/2, tpwgts); + tpwgts2[1] = tvwgt-tpwgts2[0]; + + MlevelEdgeBisection(ctrl, graph, tpwgts2, ubfactor); + cut = graph->mincut; + + /* printf("%5d %5d %5d [%5d %f]\n", tpwgts2[0], tpwgts2[1], cut, tvwgt, ssum(nparts/2, tpwgts));*/ + + label = graph->label; + where = graph->where; + for (i=0; i<nvtxs; i++) + part[label[i]] = where[i] + fpart; + + if (nparts > 2) { + SplitGraphPart(ctrl, graph, &lgraph, &rgraph); + /* printf("%d %d\n", lgraph.nvtxs, rgraph.nvtxs); */ + } + + + /* Free the memory of the top level graph */ + GKfree(&graph->gdata, &graph->rdata, &graph->label, LTERM); + + /* Scale the fractions in the tpwgts according to the true weight */ + wsum = ssum(nparts/2, tpwgts); + sscale(nparts/2, 1.0/wsum, tpwgts); + sscale(nparts-nparts/2, 1.0/(1.0-wsum), tpwgts+nparts/2); + /* + for (i=0; i<nparts; i++) + printf("%5.3f ", tpwgts[i]); + printf("[%5.3f]\n", wsum); + */ + + /* Do the recursive call */ + if (nparts > 3) { + cut += MlevelRecursiveBisection(ctrl, &lgraph, nparts/2, part, tpwgts, ubfactor, fpart); + cut += MlevelRecursiveBisection(ctrl, &rgraph, nparts-nparts/2, part, tpwgts+nparts/2, ubfactor, fpart+nparts/2); + } + else if (nparts == 3) { + cut += MlevelRecursiveBisection(ctrl, &rgraph, nparts-nparts/2, part, tpwgts+nparts/2, ubfactor, fpart+nparts/2); + GKfree(&lgraph.gdata, &lgraph.label, LTERM); + } + + return cut; + +} + + +/************************************************************************* +* This function performs multilevel bisection +**************************************************************************/ +void MlevelEdgeBisection(CtrlType *ctrl, GraphType *graph, int *tpwgts, float ubfactor) +{ + GraphType *cgraph; + + cgraph = Coarsen2Way(ctrl, graph); + + Init2WayPartition(ctrl, cgraph, tpwgts, ubfactor); + + Refine2Way(ctrl, graph, cgraph, tpwgts, ubfactor); + +/* + IsConnectedSubdomain(ctrl, graph, 0); + IsConnectedSubdomain(ctrl, graph, 1); +*/ +} + + + + +/************************************************************************* +* This function takes a graph and a bisection and splits it into two graphs. +**************************************************************************/ +void SplitGraphPart(CtrlType *ctrl, GraphType *graph, GraphType *lgraph, GraphType *rgraph) +{ + int i, j, k, kk, l, istart, iend, mypart, nvtxs, ncon, snvtxs[2], snedges[2], sum; + idxtype *xadj, *vwgt, *adjncy, *adjwgt, *adjwgtsum, *label, *where, *bndptr; + idxtype *sxadj[2], *svwgt[2], *sadjncy[2], *sadjwgt[2], *sadjwgtsum[2], *slabel[2]; + idxtype *rename; + idxtype *auxadjncy, *auxadjwgt; + float *nvwgt, *snvwgt[2], *npwgts; + + + IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->SplitTmr)); + + nvtxs = graph->nvtxs; + ncon = graph->ncon; + xadj = graph->xadj; + vwgt = graph->vwgt; + nvwgt = graph->nvwgt; + adjncy = graph->adjncy; + adjwgt = graph->adjwgt; + adjwgtsum = graph->adjwgtsum; + label = graph->label; + where = graph->where; + bndptr = graph->bndptr; + npwgts = graph->npwgts; + + ASSERT(bndptr != NULL); + + rename = idxwspacemalloc(ctrl, nvtxs); + + snvtxs[0] = snvtxs[1] = snedges[0] = snedges[1] = 0; + for (i=0; i<nvtxs; i++) { + k = where[i]; + rename[i] = snvtxs[k]++; + snedges[k] += xadj[i+1]-xadj[i]; + } + + SetUpSplitGraph(graph, lgraph, snvtxs[0], snedges[0]); + sxadj[0] = lgraph->xadj; + svwgt[0] = lgraph->vwgt; + snvwgt[0] = lgraph->nvwgt; + sadjwgtsum[0] = lgraph->adjwgtsum; + sadjncy[0] = lgraph->adjncy; + sadjwgt[0] = lgraph->adjwgt; + slabel[0] = lgraph->label; + + SetUpSplitGraph(graph, rgraph, snvtxs[1], snedges[1]); + sxadj[1] = rgraph->xadj; + svwgt[1] = rgraph->vwgt; + snvwgt[1] = rgraph->nvwgt; + sadjwgtsum[1] = rgraph->adjwgtsum; + sadjncy[1] = rgraph->adjncy; + sadjwgt[1] = rgraph->adjwgt; + slabel[1] = rgraph->label; + + snvtxs[0] = snvtxs[1] = snedges[0] = snedges[1] = 0; + sxadj[0][0] = sxadj[1][0] = 0; + for (i=0; i<nvtxs; i++) { + mypart = where[i]; + sum = adjwgtsum[i]; + + istart = xadj[i]; + iend = xadj[i+1]; + if (bndptr[i] == -1) { /* This is an interior vertex */ + auxadjncy = sadjncy[mypart] + snedges[mypart] - istart; + auxadjwgt = sadjwgt[mypart] + snedges[mypart] - istart; + for(j=istart; j<iend; j++) { + auxadjncy[j] = adjncy[j]; + auxadjwgt[j] = adjwgt[j]; + } + snedges[mypart] += iend-istart; + } + else { + auxadjncy = sadjncy[mypart]; + auxadjwgt = sadjwgt[mypart]; + l = snedges[mypart]; + for (j=istart; j<iend; j++) { + k = adjncy[j]; + if (where[k] == mypart) { + auxadjncy[l] = k; + auxadjwgt[l++] = adjwgt[j]; + } + else { + sum -= adjwgt[j]; + } + } + snedges[mypart] = l; + } + + if (ncon == 1) + svwgt[mypart][snvtxs[mypart]] = vwgt[i]; + else { + for (kk=0; kk<ncon; kk++) + snvwgt[mypart][snvtxs[mypart]*ncon+kk] = nvwgt[i*ncon+kk]/npwgts[mypart*ncon+kk]; + } + + sadjwgtsum[mypart][snvtxs[mypart]] = sum; + slabel[mypart][snvtxs[mypart]] = label[i]; + sxadj[mypart][++snvtxs[mypart]] = snedges[mypart]; + } + + for (mypart=0; mypart<2; mypart++) { + iend = sxadj[mypart][snvtxs[mypart]]; + auxadjncy = sadjncy[mypart]; + for (i=0; i<iend; i++) + auxadjncy[i] = rename[auxadjncy[i]]; + } + + lgraph->nedges = snedges[0]; + rgraph->nedges = snedges[1]; + + IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->SplitTmr)); + + idxwspacefree(ctrl, nvtxs); +} + + +/************************************************************************* +* Setup the various arrays for the splitted graph +**************************************************************************/ +void SetUpSplitGraph(GraphType *graph, GraphType *sgraph, int snvtxs, int snedges) +{ + InitGraph(sgraph); + sgraph->nvtxs = snvtxs; + sgraph->nedges = snedges; + sgraph->ncon = graph->ncon; + + /* Allocate memory for the splitted graph */ + if (graph->ncon == 1) { + sgraph->gdata = idxmalloc(4*snvtxs+1 + 2*snedges, "SetUpSplitGraph: gdata"); + + sgraph->xadj = sgraph->gdata; + sgraph->vwgt = sgraph->gdata + snvtxs+1; + sgraph->adjwgtsum = sgraph->gdata + 2*snvtxs+1; + sgraph->cmap = sgraph->gdata + 3*snvtxs+1; + sgraph->adjncy = sgraph->gdata + 4*snvtxs+1; + sgraph->adjwgt = sgraph->gdata + 4*snvtxs+1 + snedges; + } + else { + sgraph->gdata = idxmalloc(3*snvtxs+1 + 2*snedges, "SetUpSplitGraph: gdata"); + + sgraph->xadj = sgraph->gdata; + sgraph->adjwgtsum = sgraph->gdata + snvtxs+1; + sgraph->cmap = sgraph->gdata + 2*snvtxs+1; + sgraph->adjncy = sgraph->gdata + 3*snvtxs+1; + sgraph->adjwgt = sgraph->gdata + 3*snvtxs+1 + snedges; + + sgraph->nvwgt = fmalloc(graph->ncon*snvtxs, "SetUpSplitGraph: nvwgt"); + } + + sgraph->label = idxmalloc(snvtxs, "SetUpSplitGraph: sgraph->label"); +} + diff --git a/contrib/Metis/pqueue.c b/contrib/Metis/pqueue.c new file mode 100644 index 0000000000..0f2b3d460c --- /dev/null +++ b/contrib/Metis/pqueue.c @@ -0,0 +1,579 @@ +/* + * Copyright 1997, Regents of the University of Minnesota + * + * pqueue.c + * + * This file contains functions for manipulating the bucket list + * representation of the gains associated with each vertex in a graph. + * These functions are used by the refinement algorithms + * + * Started 9/2/94 + * George + * + * $Id: pqueue.c,v 1.1 2005-09-21 17:29:38 geuzaine Exp $ + * + */ + +#include <metis.h> + + +/************************************************************************* +* This function initializes the data structures of the priority queue +**************************************************************************/ +void PQueueInit(CtrlType *ctrl, PQueueType *queue, int maxnodes, int maxgain) +{ + int i, j, ncore; + + queue->nnodes = 0; + queue->maxnodes = maxnodes; + + queue->buckets = NULL; + queue->nodes = NULL; + queue->heap = NULL; + queue->locator = NULL; + + if (maxgain > PLUS_GAINSPAN || maxnodes < 500) + queue->type = 2; + else + queue->type = 1; + + if (queue->type == 1) { + queue->pgainspan = amin(PLUS_GAINSPAN, maxgain); + queue->ngainspan = amin(NEG_GAINSPAN, maxgain); + + j = queue->ngainspan+queue->pgainspan+1; + + ncore = 2 + (sizeof(ListNodeType)/sizeof(idxtype))*maxnodes + (sizeof(ListNodeType *)/sizeof(idxtype))*j; + + if (WspaceAvail(ctrl) > ncore) { + queue->nodes = (ListNodeType *)idxwspacemalloc(ctrl, (sizeof(ListNodeType)/sizeof(idxtype))*maxnodes); + queue->buckets = (ListNodeType **)idxwspacemalloc(ctrl, (sizeof(ListNodeType *)/sizeof(idxtype))*j); + queue->mustfree = 0; + } + else { /* Not enough memory in the wspace, allocate it */ + queue->nodes = (ListNodeType *)idxmalloc((sizeof(ListNodeType)/sizeof(idxtype))*maxnodes, "PQueueInit: queue->nodes"); + queue->buckets = (ListNodeType **)idxmalloc((sizeof(ListNodeType *)/sizeof(idxtype))*j, "PQueueInit: queue->buckets"); + queue->mustfree = 1; + } + + for (i=0; i<maxnodes; i++) + queue->nodes[i].id = i; + + for (i=0; i<j; i++) + queue->buckets[i] = NULL; + + queue->buckets += queue->ngainspan; /* Advance buckets by the ngainspan proper indexing */ + queue->maxgain = -queue->ngainspan; + } + else { + queue->heap = (KeyValueType *)idxwspacemalloc(ctrl, (sizeof(KeyValueType)/sizeof(idxtype))*maxnodes); + queue->locator = idxwspacemalloc(ctrl, maxnodes); + idxset(maxnodes, -1, queue->locator); + } + +} + + +/************************************************************************* +* This function resets the buckets +**************************************************************************/ +void PQueueReset(PQueueType *queue) +{ + int i, j; + queue->nnodes = 0; + + if (queue->type == 1) { + queue->maxgain = -queue->ngainspan; + + j = queue->ngainspan+queue->pgainspan+1; + queue->buckets -= queue->ngainspan; + for (i=0; i<j; i++) + queue->buckets[i] = NULL; + queue->buckets += queue->ngainspan; + } + else { + idxset(queue->maxnodes, -1, queue->locator); + } + +} + + +/************************************************************************* +* This function frees the buckets +**************************************************************************/ +void PQueueFree(CtrlType *ctrl, PQueueType *queue) +{ + + if (queue->type == 1) { + if (queue->mustfree) { + queue->buckets -= queue->ngainspan; + GKfree(&queue->nodes, &queue->buckets, LTERM); + } + else { + idxwspacefree(ctrl, sizeof(ListNodeType *)*(queue->ngainspan+queue->pgainspan+1)/sizeof(idxtype)); + idxwspacefree(ctrl, sizeof(ListNodeType)*queue->maxnodes/sizeof(idxtype)); + } + } + else { + idxwspacefree(ctrl, sizeof(KeyValueType)*queue->maxnodes/sizeof(idxtype)); + idxwspacefree(ctrl, queue->maxnodes); + } + + queue->maxnodes = 0; +} + + +/************************************************************************* +* This function returns the number of nodes in the queue +**************************************************************************/ +int PQueueGetSize(PQueueType *queue) +{ + return queue->nnodes; +} + + +/************************************************************************* +* This function adds a node of certain gain into a partition +**************************************************************************/ +int PQueueInsert(PQueueType *queue, int node, int gain) +{ + int i, j, k; + idxtype *locator; + ListNodeType *newnode; + KeyValueType *heap; + + if (queue->type == 1) { + ASSERT(gain >= -queue->ngainspan && gain <= queue->pgainspan); + + /* Allocate and add the node */ + queue->nnodes++; + newnode = queue->nodes + node; + + /* Attach this node in the doubly-linked list */ + newnode->next = queue->buckets[gain]; + newnode->prev = NULL; + if (newnode->next != NULL) + newnode->next->prev = newnode; + queue->buckets[gain] = newnode; + + if (queue->maxgain < gain) + queue->maxgain = gain; + } + else { + ASSERT(CheckHeap(queue)); + + heap = queue->heap; + locator = queue->locator; + + ASSERT(locator[node] == -1); + + i = queue->nnodes++; + while (i > 0) { + j = (i-1)/2; + if (heap[j].key < gain) { + heap[i] = heap[j]; + locator[heap[i].val] = i; + i = j; + } + else + break; + } + ASSERT(i >= 0); + heap[i].key = gain; + heap[i].val = node; + locator[node] = i; + + ASSERT(CheckHeap(queue)); + } + + return 0; +} + + +/************************************************************************* +* This function deletes a node from a partition and reinserts it with +* an updated gain +**************************************************************************/ +int PQueueDelete(PQueueType *queue, int node, int gain) +{ + int i, j, newgain, oldgain; + idxtype *locator; + ListNodeType *newnode, **buckets; + KeyValueType *heap; + + if (queue->type == 1) { + ASSERT(gain >= -queue->ngainspan && gain <= queue->pgainspan); + ASSERT(queue->nnodes > 0); + + buckets = queue->buckets; + queue->nnodes--; + newnode = queue->nodes+node; + + /* Remove newnode from the doubly-linked list */ + if (newnode->prev != NULL) + newnode->prev->next = newnode->next; + else + buckets[gain] = newnode->next; + if (newnode->next != NULL) + newnode->next->prev = newnode->prev; + + if (buckets[gain] == NULL && gain == queue->maxgain) { + if (queue->nnodes == 0) + queue->maxgain = -queue->ngainspan; + else + for (; buckets[queue->maxgain]==NULL; queue->maxgain--); + } + } + else { /* Heap Priority Queue */ + heap = queue->heap; + locator = queue->locator; + + ASSERT(locator[node] != -1); + ASSERT(heap[locator[node]].val == node); + + ASSERT(CheckHeap(queue)); + + i = locator[node]; + locator[node] = -1; + + if (--queue->nnodes > 0 && heap[queue->nnodes].val != node) { + node = heap[queue->nnodes].val; + newgain = heap[queue->nnodes].key; + oldgain = heap[i].key; + + if (oldgain < newgain) { /* Filter-up */ + while (i > 0) { + j = (i-1)>>1; + if (heap[j].key < newgain) { + heap[i] = heap[j]; + locator[heap[i].val] = i; + i = j; + } + else + break; + } + } + else { /* Filter down */ + while ((j=2*i+1) < queue->nnodes) { + if (heap[j].key > newgain) { + if (j+1 < queue->nnodes && heap[j+1].key > heap[j].key) + j = j+1; + heap[i] = heap[j]; + locator[heap[i].val] = i; + i = j; + } + else if (j+1 < queue->nnodes && heap[j+1].key > newgain) { + j = j+1; + heap[i] = heap[j]; + locator[heap[i].val] = i; + i = j; + } + else + break; + } + } + + heap[i].key = newgain; + heap[i].val = node; + locator[node] = i; + } + + ASSERT(CheckHeap(queue)); + } + + return 0; +} + + + +/************************************************************************* +* This function deletes a node from a partition and reinserts it with +* an updated gain +**************************************************************************/ +int PQueueUpdate(PQueueType *queue, int node, int oldgain, int newgain) +{ + int i, j; + idxtype *locator; + ListNodeType *newnode; + KeyValueType *heap; + + if (oldgain == newgain) + return 0; + + if (queue->type == 1) { + /* First delete the node and then insert it */ + PQueueDelete(queue, node, oldgain); + return PQueueInsert(queue, node, newgain); + } + else { /* Heap Priority Queue */ + heap = queue->heap; + locator = queue->locator; + + ASSERT(locator[node] != -1); + ASSERT(heap[locator[node]].val == node); + ASSERT(heap[locator[node]].key == oldgain); + ASSERT(CheckHeap(queue)); + + i = locator[node]; + + if (oldgain < newgain) { /* Filter-up */ + while (i > 0) { + j = (i-1)>>1; + if (heap[j].key < newgain) { + heap[i] = heap[j]; + locator[heap[i].val] = i; + i = j; + } + else + break; + } + } + else { /* Filter down */ + while ((j=2*i+1) < queue->nnodes) { + if (heap[j].key > newgain) { + if (j+1 < queue->nnodes && heap[j+1].key > heap[j].key) + j = j+1; + heap[i] = heap[j]; + locator[heap[i].val] = i; + i = j; + } + else if (j+1 < queue->nnodes && heap[j+1].key > newgain) { + j = j+1; + heap[i] = heap[j]; + locator[heap[i].val] = i; + i = j; + } + else + break; + } + } + + heap[i].key = newgain; + heap[i].val = node; + locator[node] = i; + + ASSERT(CheckHeap(queue)); + } + + return 0; +} + + + +/************************************************************************* +* This function deletes a node from a partition and reinserts it with +* an updated gain +**************************************************************************/ +void PQueueUpdateUp(PQueueType *queue, int node, int oldgain, int newgain) +{ + int i, j; + idxtype *locator; + ListNodeType *newnode, **buckets; + KeyValueType *heap; + + if (oldgain == newgain) + return; + + if (queue->type == 1) { + ASSERT(oldgain >= -queue->ngainspan && oldgain <= queue->pgainspan); + ASSERT(newgain >= -queue->ngainspan && newgain <= queue->pgainspan); + ASSERT(queue->nnodes > 0); + + buckets = queue->buckets; + newnode = queue->nodes+node; + + /* First delete the node */ + if (newnode->prev != NULL) + newnode->prev->next = newnode->next; + else + buckets[oldgain] = newnode->next; + if (newnode->next != NULL) + newnode->next->prev = newnode->prev; + + /* Attach this node in the doubly-linked list */ + newnode->next = buckets[newgain]; + newnode->prev = NULL; + if (newnode->next != NULL) + newnode->next->prev = newnode; + buckets[newgain] = newnode; + + if (queue->maxgain < newgain) + queue->maxgain = newgain; + } + else { /* Heap Priority Queue */ + heap = queue->heap; + locator = queue->locator; + + ASSERT(locator[node] != -1); + ASSERT(heap[locator[node]].val == node); + ASSERT(heap[locator[node]].key == oldgain); + ASSERT(CheckHeap(queue)); + + + /* Here we are just filtering up since the newgain is greater than the oldgain */ + i = locator[node]; + while (i > 0) { + j = (i-1)>>1; + if (heap[j].key < newgain) { + heap[i] = heap[j]; + locator[heap[i].val] = i; + i = j; + } + else + break; + } + + heap[i].key = newgain; + heap[i].val = node; + locator[node] = i; + + ASSERT(CheckHeap(queue)); + } + +} + + +/************************************************************************* +* This function returns the vertex with the largest gain from a partition +* and removes the node from the bucket list +**************************************************************************/ +int PQueueGetMax(PQueueType *queue) +{ + int vtx, i, j, gain, node; + idxtype *locator; + ListNodeType *tptr; + KeyValueType *heap; + + if (queue->nnodes == 0) + return -1; + + queue->nnodes--; + + if (queue->type == 1) { + tptr = queue->buckets[queue->maxgain]; + queue->buckets[queue->maxgain] = tptr->next; + if (tptr->next != NULL) { + tptr->next->prev = NULL; + } + else { + if (queue->nnodes == 0) { + queue->maxgain = -queue->ngainspan; + } + else + for (; queue->buckets[queue->maxgain]==NULL; queue->maxgain--); + } + + return tptr->id; + } + else { + heap = queue->heap; + locator = queue->locator; + + vtx = heap[0].val; + locator[vtx] = -1; + + if ((i = queue->nnodes) > 0) { + gain = heap[i].key; + node = heap[i].val; + i = 0; + while ((j=2*i+1) < queue->nnodes) { + if (heap[j].key > gain) { + if (j+1 < queue->nnodes && heap[j+1].key > heap[j].key) + j = j+1; + heap[i] = heap[j]; + locator[heap[i].val] = i; + i = j; + } + else if (j+1 < queue->nnodes && heap[j+1].key > gain) { + j = j+1; + heap[i] = heap[j]; + locator[heap[i].val] = i; + i = j; + } + else + break; + } + + heap[i].key = gain; + heap[i].val = node; + locator[node] = i; + } + + ASSERT(CheckHeap(queue)); + return vtx; + } +} + + +/************************************************************************* +* This function returns the vertex with the largest gain from a partition +**************************************************************************/ +int PQueueSeeMax(PQueueType *queue) +{ + int vtx; + + if (queue->nnodes == 0) + return -1; + + if (queue->type == 1) + vtx = queue->buckets[queue->maxgain]->id; + else + vtx = queue->heap[0].val; + + return vtx; +} + + +/************************************************************************* +* This function returns the vertex with the largest gain from a partition +**************************************************************************/ +int PQueueGetKey(PQueueType *queue) +{ + int key; + + if (queue->nnodes == 0) + return -1; + + if (queue->type == 1) + key = queue->maxgain; + else + key = queue->heap[0].key; + + return key; +} + + + + +/************************************************************************* +* This functions checks the consistency of the heap +**************************************************************************/ +int CheckHeap(PQueueType *queue) +{ + int i, j, nnodes; + idxtype *locator; + KeyValueType *heap; + + heap = queue->heap; + locator = queue->locator; + nnodes = queue->nnodes; + + if (nnodes == 0) + return 1; + + ASSERT(locator[heap[0].val] == 0); + for (i=1; i<nnodes; i++) { + ASSERTP(locator[heap[i].val] == i, ("%d %d %d %d\n", nnodes, i, heap[i].val, locator[heap[i].val])); + ASSERTP(heap[i].key <= heap[(i-1)/2].key, ("%d %d %d %d %d\n", i, (i-1)/2, nnodes, heap[i].key, heap[(i-1)/2].key)); + } + for (i=1; i<nnodes; i++) + ASSERT(heap[i].key <= heap[0].key); + + for (j=i=0; i<queue->maxnodes; i++) { + if (locator[i] != -1) + j++; + } + ASSERTP(j == nnodes, ("%d %d\n", j, nnodes)); + + return 1; +} diff --git a/contrib/Metis/proto.h b/contrib/Metis/proto.h new file mode 100644 index 0000000000..b459916582 --- /dev/null +++ b/contrib/Metis/proto.h @@ -0,0 +1,505 @@ +/* + * Copyright 1997, Regents of the University of Minnesota + * + * proto.h + * + * This file contains header files + * + * Started 10/19/95 + * George + * + * $Id: proto.h,v 1.1 2005-09-21 17:29:38 geuzaine Exp $ + * + */ + +/* balance.c */ +void Balance2Way(CtrlType *, GraphType *, int *, float); +void Bnd2WayBalance(CtrlType *, GraphType *, int *); +void General2WayBalance(CtrlType *, GraphType *, int *); + +/* bucketsort.c */ +void BucketSortKeysInc(int, int, idxtype *, idxtype *, idxtype *); + +/* ccgraph.c */ +void CreateCoarseGraph(CtrlType *, GraphType *, int, idxtype *, idxtype *); +void CreateCoarseGraphNoMask(CtrlType *, GraphType *, int, idxtype *, idxtype *); +void CreateCoarseGraph_NVW(CtrlType *, GraphType *, int, idxtype *, idxtype *); +GraphType *SetUpCoarseGraph(GraphType *, int, int); +void ReAdjustMemory(GraphType *, GraphType *, int); + +/* coarsen.c */ +GraphType *Coarsen2Way(CtrlType *, GraphType *); + +/* compress.c */ +void CompressGraph(CtrlType *, GraphType *, int, idxtype *, idxtype *, idxtype *, idxtype *); +void PruneGraph(CtrlType *, GraphType *, int, idxtype *, idxtype *, idxtype *, float); + +/* debug.c */ +int ComputeCut(GraphType *, idxtype *); +int CheckBnd(GraphType *); +int CheckBnd2(GraphType *); +int CheckNodeBnd(GraphType *, int); +int CheckRInfo(RInfoType *); +int CheckNodePartitionParams(GraphType *); +int IsSeparable(GraphType *); + +/* estmem.c */ +void METIS_EstimateMemory(int *, idxtype *, idxtype *, int *, int *, int *); +void EstimateCFraction(int, idxtype *, idxtype *, float *, float *); +int ComputeCoarseGraphSize(int, idxtype *, idxtype *, int, idxtype *, idxtype *, idxtype *); + +/* fm.c */ +void FM_2WayEdgeRefine(CtrlType *, GraphType *, int *, int); + +/* fortran.c */ +void Change2CNumbering(int, idxtype *, idxtype *); +void Change2FNumbering(int, idxtype *, idxtype *, idxtype *); +void Change2FNumbering2(int, idxtype *, idxtype *); +void Change2FNumberingOrder(int, idxtype *, idxtype *, idxtype *, idxtype *); +void ChangeMesh2CNumbering(int, idxtype *); +void ChangeMesh2FNumbering(int, idxtype *, int, idxtype *, idxtype *); +void ChangeMesh2FNumbering2(int, idxtype *, int, int, idxtype *, idxtype *); + +/* frename.c */ +void METIS_PARTGRAPHRECURSIVE(int *, idxtype *, idxtype *, idxtype *, idxtype *, int *, int *, int *, int *, int *, idxtype *); +void metis_partgraphrecursive(int *, idxtype *, idxtype *, idxtype *, idxtype *, int *, int *, int *, int *, int *, idxtype *); +void metis_partgraphrecursive_(int *, idxtype *, idxtype *, idxtype *, idxtype *, int *, int *, int *, int *, int *, idxtype *); +void metis_partgraphrecursive__(int *, idxtype *, idxtype *, idxtype *, idxtype *, int *, int *, int *, int *, int *, idxtype *); +void METIS_WPARTGRAPHRECURSIVE(int *, idxtype *, idxtype *, idxtype *, idxtype *, int *, int *, int *, float *, int *, int *, idxtype *); +void metis_wpartgraphrecursive(int *, idxtype *, idxtype *, idxtype *, idxtype *, int *, int *, int *, float *, int *, int *, idxtype *); +void metis_wpartgraphrecursive_(int *, idxtype *, idxtype *, idxtype *, idxtype *, int *, int *, int *, float *, int *, int *, idxtype *); +void metis_wpartgraphrecursive__(int *, idxtype *, idxtype *, idxtype *, idxtype *, int *, int *, int *, float *, int *, int *, idxtype *); +void METIS_PARTGRAPHKWAY(int *, idxtype *, idxtype *, idxtype *, idxtype *, int *, int *, int *, int *, int *, idxtype *); +void metis_partgraphkway(int *, idxtype *, idxtype *, idxtype *, idxtype *, int *, int *, int *, int *, int *, idxtype *); +void metis_partgraphkway_(int *, idxtype *, idxtype *, idxtype *, idxtype *, int *, int *, int *, int *, int *, idxtype *); +void metis_partgraphkway__(int *, idxtype *, idxtype *, idxtype *, idxtype *, int *, int *, int *, int *, int *, idxtype *); +void METIS_WPARTGRAPHKWAY(int *, idxtype *, idxtype *, idxtype *, idxtype *, int *, int *, int *, float *, int *, int *, idxtype *); +void metis_wpartgraphkway(int *, idxtype *, idxtype *, idxtype *, idxtype *, int *, int *, int *, float *, int *, int *, idxtype *); +void metis_wpartgraphkway_(int *, idxtype *, idxtype *, idxtype *, idxtype *, int *, int *, int *, float *, int *, int *, idxtype *); +void metis_wpartgraphkway__(int *, idxtype *, idxtype *, idxtype *, idxtype *, int *, int *, int *, float *, int *, int *, idxtype *); +void METIS_EDGEND(int *, idxtype *, idxtype *, int *, int *, idxtype *, idxtype *); +void metis_edgend(int *, idxtype *, idxtype *, int *, int *, idxtype *, idxtype *); +void metis_edgend_(int *, idxtype *, idxtype *, int *, int *, idxtype *, idxtype *); +void metis_edgend__(int *, idxtype *, idxtype *, int *, int *, idxtype *, idxtype *); +void METIS_NODEND(int *, idxtype *, idxtype *, int *, int *, idxtype *, idxtype *); +void metis_nodend(int *, idxtype *, idxtype *, int *, int *, idxtype *, idxtype *); +void metis_nodend_(int *, idxtype *, idxtype *, int *, int *, idxtype *, idxtype *); +void metis_nodend__(int *, idxtype *, idxtype *, int *, int *, idxtype *, idxtype *); +void METIS_NODEWND(int *, idxtype *, idxtype *, idxtype *, int *, int *, idxtype *, idxtype *); +void metis_nodewnd(int *, idxtype *, idxtype *, idxtype *, int *, int *, idxtype *, idxtype *); +void metis_nodewnd_(int *, idxtype *, idxtype *, idxtype *, int *, int *, idxtype *, idxtype *); +void metis_nodewnd__(int *, idxtype *, idxtype *, idxtype *, int *, int *, idxtype *, idxtype *); +void METIS_PARTMESHNODAL(int *, int *, idxtype *, int *, int *, int *, int *, idxtype *, idxtype *); +void metis_partmeshnodal(int *, int *, idxtype *, int *, int *, int *, int *, idxtype *, idxtype *); +void metis_partmeshnodal_(int *, int *, idxtype *, int *, int *, int *, int *, idxtype *, idxtype *); +void metis_partmeshnodal__(int *, int *, idxtype *, int *, int *, int *, int *, idxtype *, idxtype *); +void METIS_PARTMESHDUAL(int *, int *, idxtype *, int *, int *, int *, int *, idxtype *, idxtype *); +void metis_partmeshdual(int *, int *, idxtype *, int *, int *, int *, int *, idxtype *, idxtype *); +void metis_partmeshdual_(int *, int *, idxtype *, int *, int *, int *, int *, idxtype *, idxtype *); +void metis_partmeshdual__(int *, int *, idxtype *, int *, int *, int *, int *, idxtype *, idxtype *); +void METIS_MESHTONODAL(int *, int *, idxtype *, int *, int *, idxtype *, idxtype *); +void metis_meshtonodal(int *, int *, idxtype *, int *, int *, idxtype *, idxtype *); +void metis_meshtonodal_(int *, int *, idxtype *, int *, int *, idxtype *, idxtype *); +void metis_meshtonodal__(int *, int *, idxtype *, int *, int *, idxtype *, idxtype *); +void METIS_MESHTODUAL(int *, int *, idxtype *, int *, int *, idxtype *, idxtype *); +void metis_meshtodual(int *, int *, idxtype *, int *, int *, idxtype *, idxtype *); +void metis_meshtodual_(int *, int *, idxtype *, int *, int *, idxtype *, idxtype *); +void metis_meshtodual__(int *, int *, idxtype *, int *, int *, idxtype *, idxtype *); +void METIS_ESTIMATEMEMORY(int *, idxtype *, idxtype *, int *, int *, int *); +void metis_estimatememory(int *, idxtype *, idxtype *, int *, int *, int *); +void metis_estimatememory_(int *, idxtype *, idxtype *, int *, int *, int *); +void metis_estimatememory__(int *, idxtype *, idxtype *, int *, int *, int *); +void METIS_MCPARTGRAPHRECURSIVE(int *, int *, idxtype *, idxtype *, idxtype *, idxtype *, int *, int *, int *, int *, int *, idxtype *); +void metis_mcpartgraphrecursive(int *, int *, idxtype *, idxtype *, idxtype *, idxtype *, int *, int *, int *, int *, int *, idxtype *); +void metis_mcpartgraphrecursive_(int *, int *, idxtype *, idxtype *, idxtype *, idxtype *, int *, int *, int *, int *, int *, idxtype *); +void metis_mcpartgraphrecursive__(int *, int *, idxtype *, idxtype *, idxtype *, idxtype *, int *, int *, int *, int *, int *, idxtype *); +void METIS_MCPARTGRAPHKWAY(int *, int *, idxtype *, idxtype *, idxtype *, idxtype *, int *, int *, int *, float *, int *, int *, idxtype *); +void metis_mcpartgraphkway(int *, int *, idxtype *, idxtype *, idxtype *, idxtype *, int *, int *, int *, float *, int *, int *, idxtype *); +void metis_mcpartgraphkway_(int *, int *, idxtype *, idxtype *, idxtype *, idxtype *, int *, int *, int *, float *, int *, int *, idxtype *); +void metis_mcpartgraphkway__(int *, int *, idxtype *, idxtype *, idxtype *, idxtype *, int *, int *, int *, float *, int *, int *, idxtype *); +void METIS_PARTGRAPHVKWAY(int *, idxtype *, idxtype *, idxtype *, idxtype *, int *, int *, int *, int *, int *, idxtype *); +void metis_partgraphvkway(int *, idxtype *, idxtype *, idxtype *, idxtype *, int *, int *, int *, int *, int *, idxtype *); +void metis_partgraphvkway_(int *, idxtype *, idxtype *, idxtype *, idxtype *, int *, int *, int *, int *, int *, idxtype *); +void metis_partgraphvkway__(int *, idxtype *, idxtype *, idxtype *, idxtype *, int *, int *, int *, int *, int *, idxtype *); +void METIS_WPARTGRAPHVKWAY(int *, idxtype *, idxtype *, idxtype *, idxtype *, int *, int *, int *, float *, int *, int *, idxtype *); +void metis_wpartgraphvkway(int *, idxtype *, idxtype *, idxtype *, idxtype *, int *, int *, int *, float *, int *, int *, idxtype *); +void metis_wpartgraphvkway_(int *, idxtype *, idxtype *, idxtype *, idxtype *, int *, int *, int *, float *, int *, int *, idxtype *); +void metis_wpartgraphvkway__(int *, idxtype *, idxtype *, idxtype *, idxtype *, int *, int *, int *, float *, int *, int *, idxtype *); + +/* graph.c */ +void SetUpGraph(GraphType *, int, int, int, idxtype *, idxtype *, idxtype *, idxtype *, int); +void SetUpGraphKway(GraphType *, int, idxtype *, idxtype *); +void SetUpGraph2(GraphType *, int, int, idxtype *, idxtype *, float *, idxtype *); +void VolSetUpGraph(GraphType *, int, int, int, idxtype *, idxtype *, idxtype *, idxtype *, int); +void RandomizeGraph(GraphType *); +int IsConnectedSubdomain(CtrlType *, GraphType *, int, int); +int IsConnected(CtrlType *, GraphType *, int); +int IsConnected2(GraphType *, int); +int FindComponents(CtrlType *, GraphType *, idxtype *, idxtype *); + +/* initpart.c */ +void Init2WayPartition(CtrlType *, GraphType *, int *, float); +void InitSeparator(CtrlType *, GraphType *, float); +void GrowBisection(CtrlType *, GraphType *, int *, float); +void GrowBisectionNode(CtrlType *, GraphType *, float); +void RandomBisection(CtrlType *, GraphType *, int *, float); + +/* kmetis.c */ +void METIS_PartGraphKway(int *, idxtype *, idxtype *, idxtype *, idxtype *, int *, int *, int *, int *, int *, idxtype *); +void METIS_WPartGraphKway(int *, idxtype *, idxtype *, idxtype *, idxtype *, int *, int *, int *, float *, int *, int *, idxtype *); +int MlevelKWayPartitioning(CtrlType *, GraphType *, int, idxtype *, float *, float); + +/* kvmetis.c */ +void METIS_PartGraphVKway(int *, idxtype *, idxtype *, idxtype *, idxtype *, int *, int *, int *, int *, int *, idxtype *); +void METIS_WPartGraphVKway(int *, idxtype *, idxtype *, idxtype *, idxtype *, int *, int *, int *, float *, int *, int *, idxtype *); +int MlevelVolKWayPartitioning(CtrlType *, GraphType *, int, idxtype *, float *, float); + +/* kwayfm.c */ +void Random_KWayEdgeRefine(CtrlType *, GraphType *, int, float *, float, int, int); +void Greedy_KWayEdgeRefine(CtrlType *, GraphType *, int, float *, float, int); +void Greedy_KWayEdgeBalance(CtrlType *, GraphType *, int, float *, float, int); + +/* kwayrefine.c */ +void RefineKWay(CtrlType *, GraphType *, GraphType *, int, float *, float); +void AllocateKWayPartitionMemory(CtrlType *, GraphType *, int); +void ComputeKWayPartitionParams(CtrlType *, GraphType *, int); +void ProjectKWayPartition(CtrlType *, GraphType *, int); +int IsBalanced(idxtype *, int, float *, float); +void ComputeKWayBoundary(CtrlType *, GraphType *, int); +void ComputeKWayBalanceBoundary(CtrlType *, GraphType *, int); + +/* kwayvolfm.c */ +void Random_KWayVolRefine(CtrlType *, GraphType *, int, float *, float, int, int); +void Random_KWayVolRefineMConn(CtrlType *, GraphType *, int, float *, float, int, int); +void Greedy_KWayVolBalance(CtrlType *, GraphType *, int, float *, float, int); +void Greedy_KWayVolBalanceMConn(CtrlType *, GraphType *, int, float *, float, int); +void KWayVolUpdate(CtrlType *, GraphType *, int, int, int, idxtype *, idxtype *, idxtype *); +void ComputeKWayVolume(GraphType *, int, idxtype *, idxtype *, idxtype *); +int ComputeVolume(GraphType *, idxtype *); +void CheckVolKWayPartitionParams(CtrlType *, GraphType *, int); +void ComputeVolSubDomainGraph(GraphType *, int, idxtype *, idxtype *); +void EliminateVolSubDomainEdges(CtrlType *, GraphType *, int, float *); +void EliminateVolComponents(CtrlType *, GraphType *, int, float *, float); + +/* kwayvolrefine.c */ +void RefineVolKWay(CtrlType *, GraphType *, GraphType *, int, float *, float); +void AllocateVolKWayPartitionMemory(CtrlType *, GraphType *, int); +void ComputeVolKWayPartitionParams(CtrlType *, GraphType *, int); +void ComputeKWayVolGains(CtrlType *, GraphType *, int); +void ProjectVolKWayPartition(CtrlType *, GraphType *, int); +void ComputeVolKWayBoundary(CtrlType *, GraphType *, int); +void ComputeVolKWayBalanceBoundary(CtrlType *, GraphType *, int); + +/* match.c */ +void Match_RM(CtrlType *, GraphType *); +void Match_RM_NVW(CtrlType *, GraphType *); +void Match_HEM(CtrlType *, GraphType *); +void Match_SHEM(CtrlType *, GraphType *); + +/* mbalance.c */ +void MocBalance2Way(CtrlType *, GraphType *, float *, float); +void MocGeneral2WayBalance(CtrlType *, GraphType *, float *, float); + +/* mbalance2.c */ +void MocBalance2Way2(CtrlType *, GraphType *, float *, float *); +void MocGeneral2WayBalance2(CtrlType *, GraphType *, float *, float *); +void SelectQueue3(int, float *, float *, int *, int *, PQueueType [MAXNCON][2], float *); + +/* mcoarsen.c */ +GraphType *MCCoarsen2Way(CtrlType *, GraphType *); + +/* memory.c */ +void AllocateWorkSpace(CtrlType *, GraphType *, int); +void FreeWorkSpace(CtrlType *, GraphType *); +int WspaceAvail(CtrlType *); +idxtype *idxwspacemalloc(CtrlType *, int); +void idxwspacefree(CtrlType *, int); +float *fwspacemalloc(CtrlType *, int); +void fwspacefree(CtrlType *, int); +GraphType *CreateGraph(void); +void InitGraph(GraphType *); +void FreeGraph(GraphType *); + +/* mesh.c */ +void METIS_MeshToDual(int *, int *, idxtype *, int *, int *, idxtype *, idxtype *); +void METIS_MeshToNodal(int *, int *, idxtype *, int *, int *, idxtype *, idxtype *); +void GENDUALMETIS(int, int, int, idxtype *, idxtype *, idxtype *adjncy); +void TRINODALMETIS(int, int, idxtype *, idxtype *, idxtype *adjncy); +void TETNODALMETIS(int, int, idxtype *, idxtype *, idxtype *adjncy); +void HEXNODALMETIS(int, int, idxtype *, idxtype *, idxtype *adjncy); +void QUADNODALMETIS(int, int, idxtype *, idxtype *, idxtype *adjncy); + +/* meshpart.c */ +void METIS_PartMeshNodal(int *, int *, idxtype *, int *, int *, int *, int *, idxtype *, idxtype *); +void METIS_PartMeshDual(int *, int *, idxtype *, int *, int *, int *, int *, idxtype *, idxtype *); + +/* mfm.c */ +void MocFM_2WayEdgeRefine(CtrlType *, GraphType *, float *, int); +void SelectQueue(int, float *, float *, int *, int *, PQueueType [MAXNCON][2]); +int BetterBalance(int, float *, float *, float *); +float Compute2WayHLoadImbalance(int, float *, float *); +void Compute2WayHLoadImbalanceVec(int, float *, float *, float *); + +/* mfm2.c */ +void MocFM_2WayEdgeRefine2(CtrlType *, GraphType *, float *, float *, int); +void SelectQueue2(int, float *, float *, int *, int *, PQueueType [MAXNCON][2], float *); +int IsBetter2wayBalance(int, float *, float *, float *); + +/* mincover.o */ +void MinCover(idxtype *, idxtype *, int, int, idxtype *, int *); +int MinCover_Augment(idxtype *, idxtype *, int, idxtype *, idxtype *, idxtype *, int); +void MinCover_Decompose(idxtype *, idxtype *, int, int, idxtype *, idxtype *, int *); +void MinCover_ColDFS(idxtype *, idxtype *, int, idxtype *, idxtype *, int); +void MinCover_RowDFS(idxtype *, idxtype *, int, idxtype *, idxtype *, int); + +/* minitpart.c */ +void MocInit2WayPartition(CtrlType *, GraphType *, float *, float); +void MocGrowBisection(CtrlType *, GraphType *, float *, float); +void MocRandomBisection(CtrlType *, GraphType *, float *, float); +void MocInit2WayBalance(CtrlType *, GraphType *, float *); +int SelectQueueoneWay(int, float *, float *, int, PQueueType [MAXNCON][2]); + +/* minitpart2.c */ +void MocInit2WayPartition2(CtrlType *, GraphType *, float *, float *); +void MocGrowBisection2(CtrlType *, GraphType *, float *, float *); +void MocGrowBisectionNew2(CtrlType *, GraphType *, float *, float *); +void MocInit2WayBalance2(CtrlType *, GraphType *, float *, float *); +int SelectQueueOneWay2(int, float *, PQueueType [MAXNCON][2], float *); + +/* mkmetis.c */ +void METIS_mCPartGraphKway(int *, int *, idxtype *, idxtype *, idxtype *, idxtype *, int *, int *, int *, float *, int *, int *, idxtype *); +int MCMlevelKWayPartitioning(CtrlType *, GraphType *, int, idxtype *, float *); + +/* mkwayfmh.c */ +void MCRandom_KWayEdgeRefineHorizontal(CtrlType *, GraphType *, int, float *, int); +void MCGreedy_KWayEdgeBalanceHorizontal(CtrlType *, GraphType *, int, float *, int); +int AreAllHVwgtsBelow(int, float, float *, float, float *, float *); +int AreAllHVwgtsAbove(int, float, float *, float, float *, float *); +void ComputeHKWayLoadImbalance(int, int, float *, float *); +int MocIsHBalanced(int, int, float *, float *); +int IsHBalanceBetterFT(int, int, float *, float *, float *, float *); +int IsHBalanceBetterTT(int, int, float *, float *, float *, float *); + +/* mkwayrefine.c */ +void MocRefineKWayHorizontal(CtrlType *, GraphType *, GraphType *, int, float *); +void MocAllocateKWayPartitionMemory(CtrlType *, GraphType *, int); +void MocComputeKWayPartitionParams(CtrlType *, GraphType *, int); +void MocProjectKWayPartition(CtrlType *, GraphType *, int); +void MocComputeKWayBalanceBoundary(CtrlType *, GraphType *, int); + +/* mmatch.c */ +void MCMatch_RM(CtrlType *, GraphType *); +void MCMatch_HEM(CtrlType *, GraphType *); +void MCMatch_SHEM(CtrlType *, GraphType *); +void MCMatch_SHEBM(CtrlType *, GraphType *, int); +void MCMatch_SBHEM(CtrlType *, GraphType *, int); +float BetterVBalance(int, int, float *, float *, float *); +int AreAllVwgtsBelowFast(int, float *, float *, float); + +/* mmd.c */ +void genmmd(int, idxtype *, idxtype *, idxtype *, idxtype *, int , idxtype *, idxtype *, idxtype *, idxtype *, int, int *); +void mmdelm(int, idxtype *xadj, idxtype *, idxtype *, idxtype *, idxtype *, idxtype *, idxtype *, idxtype *, int, int); +int mmdint(int, idxtype *xadj, idxtype *, idxtype *, idxtype *, idxtype *, idxtype *, idxtype *, idxtype *); +void mmdnum(int, idxtype *, idxtype *, idxtype *); +void mmdupd(int, int, idxtype *, idxtype *, int, int *, idxtype *, idxtype *, idxtype *, idxtype *, idxtype *, idxtype *, int, int *tag); + +/* mpmetis.c */ +void METIS_mCPartGraphRecursive(int *, int *, idxtype *, idxtype *, idxtype *, idxtype *, int *, int *, int *, int *, int *, idxtype *); +void METIS_mCHPartGraphRecursive(int *, int *, idxtype *, idxtype *, idxtype *, idxtype *, int *, int *, int *, float *, int *, int *, idxtype *); +void METIS_mCPartGraphRecursiveInternal(int *, int *, idxtype *, idxtype *, float *, idxtype *, int *, int *, int *, idxtype *); +void METIS_mCHPartGraphRecursiveInternal(int *, int *, idxtype *, idxtype *, float *, idxtype *, int *, float *, int *, int *, idxtype *); +int MCMlevelRecursiveBisection(CtrlType *, GraphType *, int, idxtype *, float, int); +int MCHMlevelRecursiveBisection(CtrlType *, GraphType *, int, idxtype *, float *, int); +void MCMlevelEdgeBisection(CtrlType *, GraphType *, float *, float); +void MCHMlevelEdgeBisection(CtrlType *, GraphType *, float *, float *); + +/* mrefine.c */ +void MocRefine2Way(CtrlType *, GraphType *, GraphType *, float *, float); +void MocAllocate2WayPartitionMemory(CtrlType *, GraphType *); +void MocCompute2WayPartitionParams(CtrlType *, GraphType *); +void MocProject2WayPartition(CtrlType *, GraphType *); + +/* mrefine2.c */ +void MocRefine2Way2(CtrlType *, GraphType *, GraphType *, float *, float *); + +/* mutil.c */ +int AreAllVwgtsBelow(int, float, float *, float, float *, float); +int AreAnyVwgtsBelow(int, float, float *, float, float *, float); +int AreAllVwgtsAbove(int, float, float *, float, float *, float); +float ComputeLoadImbalance(int, int, float *, float *); +int AreAllBelow(int, float *, float *); + +/* myqsort.c */ +void iidxsort(int, idxtype *); +void iintsort(int, int *); +void ikeysort(int, KeyValueType *); +void ikeyvalsort(int, KeyValueType *); + +/* ometis.c */ +void METIS_EdgeND(int *, idxtype *, idxtype *, int *, int *, idxtype *, idxtype *); +void METIS_NodeND(int *, idxtype *, idxtype *, int *, int *, idxtype *, idxtype *); +void METIS_NodeWND(int *, idxtype *, idxtype *, idxtype *, int *, int *, idxtype *, idxtype *); +void MlevelNestedDissection(CtrlType *, GraphType *, idxtype *, float, int); +void MlevelNestedDissectionCC(CtrlType *, GraphType *, idxtype *, float, int); +void MlevelNodeBisectionMultiple(CtrlType *, GraphType *, int *, float); +void MlevelNodeBisection(CtrlType *, GraphType *, int *, float); +void SplitGraphOrder(CtrlType *, GraphType *, GraphType *, GraphType *); +void MMDOrder(CtrlType *, GraphType *, idxtype *, int); +int SplitGraphOrderCC(CtrlType *, GraphType *, GraphType *, int, idxtype *, idxtype *); + +/* parmetis.c */ +void METIS_PartGraphKway2(int *, idxtype *, idxtype *, idxtype *, idxtype *, int *, int *, int *, int *, int *, idxtype *); +void METIS_WPartGraphKway2(int *, idxtype *, idxtype *, idxtype *, idxtype *, int *, int *, int *, float *, int *, int *, idxtype *); +void METIS_NodeNDP(int, idxtype *, idxtype *, int, int *, idxtype *, idxtype *, idxtype *); +void MlevelNestedDissectionP(CtrlType *, GraphType *, idxtype *, int, int, int, idxtype *); +void METIS_NodeComputeSeparator(int *, idxtype *, idxtype *, idxtype *, idxtype *, int *, int *, idxtype *); +void METIS_EdgeComputeSeparator(int *, idxtype *, idxtype *, idxtype *, idxtype *, int *, int *, idxtype *); + +/* pmetis.c */ +void METIS_PartGraphRecursive(int *, idxtype *, idxtype *, idxtype *, idxtype *, int *, int *, int *, int *, int *, idxtype *); +void METIS_WPartGraphRecursive(int *, idxtype *, idxtype *, idxtype *, idxtype *, int *, int *, int *, float *, int *, int *, idxtype *); +int MlevelRecursiveBisection(CtrlType *, GraphType *, int, idxtype *, float *, float, int); +void MlevelEdgeBisection(CtrlType *, GraphType *, int *, float); +void SplitGraphPart(CtrlType *, GraphType *, GraphType *, GraphType *); +void SetUpSplitGraph(GraphType *, GraphType *, int, int); + +/* pqueue.c */ +void PQueueInit(CtrlType *ctrl, PQueueType *, int, int); +void PQueueReset(PQueueType *); +void PQueueFree(CtrlType *ctrl, PQueueType *); +int PQueueGetSize(PQueueType *); +int PQueueInsert(PQueueType *, int, int); +int PQueueDelete(PQueueType *, int, int); +int PQueueUpdate(PQueueType *, int, int, int); +void PQueueUpdateUp(PQueueType *, int, int, int); +int PQueueGetMax(PQueueType *); +int PQueueSeeMax(PQueueType *); +int PQueueGetKey(PQueueType *); +int CheckHeap(PQueueType *); + +/* refine.c */ +void Refine2Way(CtrlType *, GraphType *, GraphType *, int *, float ubfactor); +void Allocate2WayPartitionMemory(CtrlType *, GraphType *); +void Compute2WayPartitionParams(CtrlType *, GraphType *); +void Project2WayPartition(CtrlType *, GraphType *); + +/* separator.c */ +void ConstructSeparator(CtrlType *, GraphType *, float); +void ConstructMinCoverSeparator0(CtrlType *, GraphType *, float); +void ConstructMinCoverSeparator(CtrlType *, GraphType *, float); + +/* sfm.c */ +void FM_2WayNodeRefine(CtrlType *, GraphType *, float, int); +void FM_2WayNodeRefineEqWgt(CtrlType *, GraphType *, int); +void FM_2WayNodeRefine_OneSided(CtrlType *, GraphType *, float, int); +void FM_2WayNodeBalance(CtrlType *, GraphType *, float); +int ComputeMaxNodeGain(int, idxtype *, idxtype *, idxtype *); + +/* srefine.c */ +void Refine2WayNode(CtrlType *, GraphType *, GraphType *, float); +void Allocate2WayNodePartitionMemory(CtrlType *, GraphType *); +void Compute2WayNodePartitionParams(CtrlType *, GraphType *); +void Project2WayNodePartition(CtrlType *, GraphType *); + +/* stat.c */ +void ComputePartitionInfo(GraphType *, int, idxtype *); +void ComputePartitionInfoBipartite(GraphType *, int, idxtype *); +void ComputePartitionBalance(GraphType *, int, idxtype *, float *); +float ComputeElementBalance(int, int, idxtype *); + +/* subdomains.c */ +void Random_KWayEdgeRefineMConn(CtrlType *, GraphType *, int, float *, float, int, int); +void Greedy_KWayEdgeBalanceMConn(CtrlType *, GraphType *, int, float *, float, int); +void PrintSubDomainGraph(GraphType *, int, idxtype *); +void ComputeSubDomainGraph(GraphType *, int, idxtype *, idxtype *); +void EliminateSubDomainEdges(CtrlType *, GraphType *, int, float *); +void MoveGroupMConn(CtrlType *, GraphType *, idxtype *, idxtype *, int, int, int, idxtype *); +void EliminateComponents(CtrlType *, GraphType *, int, float *, float); +void MoveGroup(CtrlType *, GraphType *, int, int, int, idxtype *, idxtype *); + +/* timing.c */ +void InitTimers(CtrlType *); +void PrintTimers(CtrlType *); +double seconds(void); + +/* util.c */ +void errexit(char *,...); +#ifndef DMALLOC +int *imalloc(int, char *); +idxtype *idxmalloc(int, char *); +float *fmalloc(int, char *); +int *ismalloc(int, int, char *); +idxtype *idxsmalloc(int, idxtype, char *); +void *GKmalloc(int, char *); +#endif +/*void GKfree(void **,...); */ +int *iset(int n, int val, int *x); +idxtype *idxset(int n, idxtype val, idxtype *x); +float *sset(int n, float val, float *x); +int iamax(int, int *); +int idxamax(int, idxtype *); +int idxamax_strd(int, idxtype *, int); +int samax(int, float *); +int samax2(int, float *); +int idxamin(int, idxtype *); +int samin(int, float *); +int idxsum(int, idxtype *); +int idxsum_strd(int, idxtype *, int); +void idxadd(int, idxtype *, idxtype *); +int charsum(int, char *); +int isum(int, int *); +float ssum(int, float *); +float ssum_strd(int n, float *x, int); +void sscale(int n, float, float *x); +float snorm2(int, float *); +float sdot(int n, float *, float *); +void saxpy(int, float, float *, int, float *, int); +void RandomPermute(int, idxtype *, int); +double drand48(); +void srand48(long); +int ispow2(int); +void InitRandom(int); +//int log2(int); + + + + + + + + + + +/*************************************************************** +* Programs Directory +****************************************************************/ + +/* io.c */ +void ReadGraph(GraphType *, char *, int *); +void WritePartition(char *, idxtype *, int, int); +void WriteMeshPartition(char *, int, int, idxtype *, int, idxtype *); +void WritePermutation(char *, idxtype *, int); +int CheckGraph(GraphType *); +idxtype *ReadMesh(char *, int *, int *, int *); +void WriteGraph(char *, int, idxtype *, idxtype *); + +/* smbfactor.c */ +void ComputeFillIn(GraphType *, idxtype *); +idxtype ComputeFillIn2(GraphType *, idxtype *); +int smbfct(int, idxtype *, idxtype *, idxtype *, idxtype *, idxtype *, int *, idxtype *, idxtype *, int *); + + +/*************************************************************** +* Test Directory +****************************************************************/ +void Test_PartGraph(int, idxtype *, idxtype *); +int VerifyPart(int, idxtype *, idxtype *, idxtype *, idxtype *, int, int, idxtype *); +int VerifyWPart(int, idxtype *, idxtype *, idxtype *, idxtype *, int, float *, int, idxtype *); +void Test_PartGraphV(int, idxtype *, idxtype *); +int VerifyPartV(int, idxtype *, idxtype *, idxtype *, idxtype *, int, int, idxtype *); +int VerifyWPartV(int, idxtype *, idxtype *, idxtype *, idxtype *, int, float *, int, idxtype *); +void Test_PartGraphmC(int, idxtype *, idxtype *); +int VerifyPartmC(int, int, idxtype *, idxtype *, idxtype *, idxtype *, int, float *, int, idxtype *); +void Test_ND(int, idxtype *, idxtype *); +int VerifyND(int, idxtype *, idxtype *); + diff --git a/contrib/Metis/refine.c b/contrib/Metis/refine.c new file mode 100644 index 0000000000..3d48683473 --- /dev/null +++ b/contrib/Metis/refine.c @@ -0,0 +1,204 @@ +/* + * Copyright 1997, Regents of the University of Minnesota + * + * refine.c + * + * This file contains the driving routines for multilevel refinement + * + * Started 7/24/97 + * George + * + * $Id: refine.c,v 1.1 2005-09-21 17:29:38 geuzaine Exp $ + */ + +#include <metis.h> + + +/************************************************************************* +* This function is the entry point of refinement +**************************************************************************/ +void Refine2Way(CtrlType *ctrl, GraphType *orggraph, GraphType *graph, int *tpwgts, float ubfactor) +{ + + IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->UncoarsenTmr)); + + /* Compute the parameters of the coarsest graph */ + Compute2WayPartitionParams(ctrl, graph); + + for (;;) { + ASSERT(CheckBnd(graph)); + + IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->RefTmr)); + switch (ctrl->RType) { + case 1: + Balance2Way(ctrl, graph, tpwgts, ubfactor); + FM_2WayEdgeRefine(ctrl, graph, tpwgts, 8); + break; + default: + errexit("Unknown refinement type: %d\n", ctrl->RType); + } + IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->RefTmr)); + + if (graph == orggraph) + break; + + graph = graph->finer; + IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->ProjectTmr)); + Project2WayPartition(ctrl, graph); + IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->ProjectTmr)); + } + + IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->UncoarsenTmr)); +} + + +/************************************************************************* +* This function allocates memory for 2-way edge refinement +**************************************************************************/ +void Allocate2WayPartitionMemory(CtrlType *ctrl, GraphType *graph) +{ + int nvtxs; + + nvtxs = graph->nvtxs; + + graph->rdata = idxmalloc(5*nvtxs+2, "Allocate2WayPartitionMemory: rdata"); + graph->pwgts = graph->rdata; + graph->where = graph->rdata + 2; + graph->id = graph->rdata + nvtxs + 2; + graph->ed = graph->rdata + 2*nvtxs + 2; + graph->bndptr = graph->rdata + 3*nvtxs + 2; + graph->bndind = graph->rdata + 4*nvtxs + 2; +} + + +/************************************************************************* +* This function computes the initial id/ed +**************************************************************************/ +void Compute2WayPartitionParams(CtrlType *ctrl, GraphType *graph) +{ + int i, j, k, l, nvtxs, nbnd, mincut; + idxtype *xadj, *vwgt, *adjncy, *adjwgt, *pwgts; + idxtype *id, *ed, *where; + idxtype *bndptr, *bndind; + int me, other; + + nvtxs = graph->nvtxs; + xadj = graph->xadj; + vwgt = graph->vwgt; + adjncy = graph->adjncy; + adjwgt = graph->adjwgt; + + where = graph->where; + pwgts = idxset(2, 0, graph->pwgts); + id = idxset(nvtxs, 0, graph->id); + ed = idxset(nvtxs, 0, graph->ed); + bndptr = idxset(nvtxs, -1, graph->bndptr); + bndind = graph->bndind; + + + /*------------------------------------------------------------ + / Compute now the id/ed degrees + /------------------------------------------------------------*/ + nbnd = mincut = 0; + for (i=0; i<nvtxs; i++) { + ASSERT(where[i] >= 0 && where[i] <= 1); + me = where[i]; + pwgts[me] += vwgt[i]; + + for (j=xadj[i]; j<xadj[i+1]; j++) { + if (me == where[adjncy[j]]) + id[i] += adjwgt[j]; + else + ed[i] += adjwgt[j]; + } + + if (ed[i] > 0 || xadj[i] == xadj[i+1]) { + mincut += ed[i]; + bndptr[i] = nbnd; + bndind[nbnd++] = i; + } + } + + graph->mincut = mincut/2; + graph->nbnd = nbnd; + + ASSERT(pwgts[0]+pwgts[1] == idxsum(nvtxs, vwgt)); +} + + + +/************************************************************************* +* This function projects a partition, and at the same time computes the +* parameters for refinement. +**************************************************************************/ +void Project2WayPartition(CtrlType *ctrl, GraphType *graph) +{ + int i, j, k, nvtxs, nbnd, me; + idxtype *xadj, *adjncy, *adjwgt, *adjwgtsum; + idxtype *cmap, *where, *id, *ed, *bndptr, *bndind; + idxtype *cwhere, *cid, *ced, *cbndptr; + GraphType *cgraph; + + cgraph = graph->coarser; + cwhere = cgraph->where; + cid = cgraph->id; + ced = cgraph->ed; + cbndptr = cgraph->bndptr; + + nvtxs = graph->nvtxs; + cmap = graph->cmap; + xadj = graph->xadj; + adjncy = graph->adjncy; + adjwgt = graph->adjwgt; + adjwgtsum = graph->adjwgtsum; + + Allocate2WayPartitionMemory(ctrl, graph); + + where = graph->where; + id = idxset(nvtxs, 0, graph->id); + ed = idxset(nvtxs, 0, graph->ed); + bndptr = idxset(nvtxs, -1, graph->bndptr); + bndind = graph->bndind; + + + /* Go through and project partition and compute id/ed for the nodes */ + for (i=0; i<nvtxs; i++) { + k = cmap[i]; + where[i] = cwhere[k]; + cmap[i] = cbndptr[k]; + } + + for (nbnd=0, i=0; i<nvtxs; i++) { + me = where[i]; + + id[i] = adjwgtsum[i]; + + if (xadj[i] == xadj[i+1]) { + bndptr[i] = nbnd; + bndind[nbnd++] = i; + } + else { + if (cmap[i] != -1) { /* If it is an interface node. Note that cmap[i] = cbndptr[cmap[i]] */ + for (j=xadj[i]; j<xadj[i+1]; j++) { + if (me != where[adjncy[j]]) + ed[i] += adjwgt[j]; + } + id[i] -= ed[i]; + + if (ed[i] > 0 || xadj[i] == xadj[i+1]) { + bndptr[i] = nbnd; + bndind[nbnd++] = i; + } + } + } + } + + graph->mincut = cgraph->mincut; + graph->nbnd = nbnd; + idxcopy(2, cgraph->pwgts, graph->pwgts); + + FreeGraph(graph->coarser); + graph->coarser = NULL; + +} + diff --git a/contrib/Metis/rename.h b/contrib/Metis/rename.h new file mode 100644 index 0000000000..49e01e87ac --- /dev/null +++ b/contrib/Metis/rename.h @@ -0,0 +1,418 @@ +/* + * Copyright 1997, Regents of the University of Minnesota + * + * rename.h + * + * This file contains header files + * + * Started 10/2/97 + * George + * + * $Id: rename.h,v 1.1 2005-09-21 17:29:38 geuzaine Exp $ + * + */ + +/* balance.c */ +#define Balance2Way __Balance2Way +#define Bnd2WayBalance __Bnd2WayBalance +#define General2WayBalance __General2WayBalance + + +/* bucketsort.c */ +#define BucketSortKeysInc __BucketSortKeysInc + + +/* ccgraph.c */ +#define CreateCoarseGraph __CreateCoarseGraph +#define CreateCoarseGraphNoMask __CreateCoarseGraphNoMask +#define CreateCoarseGraph_NVW __CreateCoarseGraph_NVW +#define SetUpCoarseGraph __SetUpCoarseGraph +#define ReAdjustMemory __ReAdjustMemory + + +/* coarsen.c */ +#define Coarsen2Way __Coarsen2Way + + +/* compress.c */ +#define CompressGraph __CompressGraph +#define PruneGraph __PruneGraph + + +/* debug.c */ +#define ComputeCut __ComputeCut +#define CheckBnd __CheckBnd +#define CheckBnd2 __CheckBnd2 +#define CheckNodeBnd __CheckNodeBnd +#define CheckRInfo __CheckRInfo +#define CheckNodePartitionParams __CheckNodePartitionParams +#define IsSeparable __IsSeparable + + +/* estmem.c */ +#define EstimateCFraction __EstimateCFraction +#define ComputeCoarseGraphSize __ComputeCoarseGraphSize + + +/* fm.c */ +#define FM_2WayEdgeRefine __FM_2WayEdgeRefine + + +/* fortran.c */ +#define Change2CNumbering __Change2CNumbering +#define Change2FNumbering __Change2FNumbering +#define Change2FNumbering2 __Change2FNumbering2 +#define Change2FNumberingOrder __Change2FNumberingOrder +#define ChangeMesh2CNumbering __ChangeMesh2CNumbering +#define ChangeMesh2FNumbering __ChangeMesh2FNumbering +#define ChangeMesh2FNumbering2 __ChangeMesh2FNumbering2 + + +/* graph.c */ +#define SetUpGraph __SetUpGraph +#define SetUpGraphKway __SetUpGraphKway +#define SetUpGraph2 __SetUpGraph2 +#define VolSetUpGraph __VolSetUpGraph +#define RandomizeGraph __RandomizeGraph +#define IsConnectedSubdomain __IsConnectedSubdomain +#define IsConnected __IsConnected +#define IsConnected2 __IsConnected2 +#define FindComponents __FindComponents + + +/* initpart.c */ +#define Init2WayPartition __Init2WayPartition +#define InitSeparator __InitSeparator +#define GrowBisection __GrowBisection +#define GrowBisectionNode __GrowBisectionNode +#define RandomBisection __RandomBisection + + +/* kmetis.c */ +#define MlevelKWayPartitioning __MlevelKWayPartitioning + + +/* kvmetis.c */ +#define MlevelVolKWayPartitioning __MlevelVolKWayPartitioning + + +/* kwayfm.c */ +#define Random_KWayEdgeRefine __Random_KWayEdgeRefine +#define Greedy_KWayEdgeRefine __Greedy_KWayEdgeRefine +#define Greedy_KWayEdgeBalance __Greedy_KWayEdgeBalance + + +/* kwayrefine.c */ +#define RefineKWay __RefineKWay +#define AllocateKWayPartitionMemory __AllocateKWayPartitionMemory +#define ComputeKWayPartitionParams __ComputeKWayPartitionParams +#define ProjectKWayPartition __ProjectKWayPartition +#define IsBalanced __IsBalanced +#define ComputeKWayBoundary __ComputeKWayBoundary +#define ComputeKWayBalanceBoundary __ComputeKWayBalanceBoundary + + +/* kwayvolfm.c */ +#define Random_KWayVolRefine __Random_KWayVolRefine +#define Random_KWayVolRefineMConn __Random_KWayVolRefineMConn +#define Greedy_KWayVolBalance __Greedy_KWayVolBalance +#define Greedy_KWayVolBalanceMConn __Greedy_KWayVolBalanceMConn +#define KWayVolUpdate __KWayVolUpdate +#define ComputeKWayVolume __ComputeKWayVolume +#define ComputeVolume __ComputeVolume +#define CheckVolKWayPartitionParams __CheckVolKWayPartitionParams +#define ComputeVolSubDomainGraph __ComputeVolSubDomainGraph +#define EliminateVolSubDomainEdges __EliminateVolSubDomainEdges + + +/* kwayvolrefine.c */ +#define RefineVolKWay __RefineVolKWay +#define AllocateVolKWayPartitionMemory __AllocateVolKWayPartitionMemory +#define ComputeVolKWayPartitionParams __ComputeVolKWayPartitionParams +#define ComputeKWayVolGains __ComputeKWayVolGains +#define ProjectVolKWayPartition __ProjectVolKWayPartition +#define ComputeVolKWayBoundary __ComputeVolKWayBoundary +#define ComputeVolKWayBalanceBoundary __ComputeVolKWayBalanceBoundary + + +/* match.c */ +#define Match_RM __Match_RM +#define Match_RM_NVW __Match_RM_NVW +#define Match_HEM __Match_HEM +#define Match_SHEM __Match_SHEM + + +/* mbalance.c */ +#define MocBalance2Way __MocBalance2Way +#define MocGeneral2WayBalance __MocGeneral2WayBalance + + +/* mbalance2.c */ +#define MocBalance2Way2 __MocBalance2Way2 +#define MocGeneral2WayBalance2 __MocGeneral2WayBalance2 +#define SelectQueue3 __SelectQueue3 + + +/* mcoarsen.c */ +#define MCCoarsen2Way __MCCoarsen2Way + + +/* memory.c */ +#define AllocateWorkSpace __AllocateWorkSpace +#define FreeWorkSpace __FreeWorkSpace +#define WspaceAvail __WspaceAvail +#define idxwspacemalloc __idxwspacemalloc +#define idxwspacefree __idxwspacefree +#define fwspacemalloc __fwspacemalloc +#define CreateGraph __CreateGraph +#define InitGraph __InitGraph +#define FreeGraph __FreeGraph + + +/* mesh.c */ +#define TRIDUALMETIS __TRIDUALMETIS +#define TETDUALMETIS __TETDUALMETIS +#define HEXDUALMETIS __HEXDUALMETIS +#define TRINODALMETIS __TRINODALMETIS +#define TETNODALMETIS __TETNODALMETIS +#define HEXNODALMETIS __HEXNODALMETIS + + +/* mfm.c */ +#define MocFM_2WayEdgeRefine __MocFM_2WayEdgeRefine +#define SelectQueue __SelectQueue +#define BetterBalance __BetterBalance +#define Compute2WayHLoadImbalance __Compute2WayHLoadImbalance +#define Compute2WayHLoadImbalanceVec __Compute2WayHLoadImbalanceVec + + +/* mfm2.c */ +#define MocFM_2WayEdgeRefine2 __MocFM_2WayEdgeRefine2 +#define SelectQueue2 __SelectQueue2 +#define IsBetter2wayBalance __IsBetter2wayBalance + + +/* mincover.c */ +#define MinCover __MinCover +#define MinCover_Augment __MinCover_Augment +#define MinCover_Decompose __MinCover_Decompose +#define MinCover_ColDFS __MinCover_ColDFS +#define MinCover_RowDFS __MinCover_RowDFS + + +/* minitpart.c */ +#define MocInit2WayPartition __MocInit2WayPartition +#define MocGrowBisection __MocGrowBisection +#define MocRandomBisection __MocRandomBisection +#define MocInit2WayBalance __MocInit2WayBalance +#define SelectQueueoneWay __SelectQueueoneWay + + +/* minitpart2.c */ +#define MocInit2WayPartition2 __MocInit2WayPartition2 +#define MocGrowBisection2 __MocGrowBisection2 +#define MocGrowBisectionNew2 __MocGrowBisectionNew2 +#define MocInit2WayBalance2 __MocInit2WayBalance2 +#define SelectQueueOneWay2 __SelectQueueOneWay2 + + +/* mkmetis.c */ +#define MCMlevelKWayPartitioning __MCMlevelKWayPartitioning + + +/* mkwayfmh.c */ +#define MCRandom_KWayEdgeRefineHorizontal __MCRandom_KWayEdgeRefineHorizontal +#define MCGreedy_KWayEdgeBalanceHorizontal __MCGreedy_KWayEdgeBalanceHorizontal +#define AreAllHVwgtsBelow __AreAllHVwgtsBelow +#define AreAllHVwgtsAbove __AreAllHVwgtsAbove +#define ComputeHKWayLoadImbalance __ComputeHKWayLoadImbalance +#define MocIsHBalanced __MocIsHBalanced +#define IsHBalanceBetterFT __IsHBalanceBetterFT +#define IsHBalanceBetterTT __IsHBalanceBetterTT + + +/* mkwayrefine.c */ +#define MocRefineKWayHorizontal __MocRefineKWayHorizontal +#define MocAllocateKWayPartitionMemory __MocAllocateKWayPartitionMemory +#define MocComputeKWayPartitionParams __MocComputeKWayPartitionParams +#define MocProjectKWayPartition __MocProjectKWayPartition +#define MocComputeKWayBalanceBoundary __MocComputeKWayBalanceBoundary + + +/* mmatch.c */ +#define MCMatch_RM __MCMatch_RM +#define MCMatch_HEM __MCMatch_HEM +#define MCMatch_SHEM __MCMatch_SHEM +#define MCMatch_SHEBM __MCMatch_SHEBM +#define MCMatch_SBHEM __MCMatch_SBHEM +#define BetterVBalance __BetterVBalance +#define AreAllVwgtsBelowFast __AreAllVwgtsBelowFast + + +/* mmd.c */ +#define genmmd __genmmd +#define mmdelm __mmdelm +#define mmdint __mmdint +#define mmdnum __mmdnum +#define mmdupd __mmdupd + + +/* mpmetis.c */ +#define MCMlevelRecursiveBisection __MCMlevelRecursiveBisection +#define MCHMlevelRecursiveBisection __MCHMlevelRecursiveBisection +#define MCMlevelEdgeBisection __MCMlevelEdgeBisection +#define MCHMlevelEdgeBisection __MCHMlevelEdgeBisection + + +/* mrefine.c */ +#define MocRefine2Way __MocRefine2Way +#define MocAllocate2WayPartitionMemory __MocAllocate2WayPartitionMemory +#define MocCompute2WayPartitionParams __MocCompute2WayPartitionParams +#define MocProject2WayPartition __MocProject2WayPartition + + +/* mrefine2.c */ +#define MocRefine2Way2 __MocRefine2Way2 + + +/* mutil.c */ +#define AreAllVwgtsBelow __AreAllVwgtsBelow +#define AreAnyVwgtsBelow __AreAnyVwgtsBelow +#define AreAllVwgtsAbove __AreAllVwgtsAbove +#define ComputeLoadImbalance __ComputeLoadImbalance +#define AreAllBelow __AreAllBelow + + +/* myqsort.c */ +#define iidxsort __iidxsort +#define iintsort __iintsort +#define ikeysort __ikeysort +#define ikeyvalsort __ikeyvalsort + + +/* ometis.c */ +#define MlevelNestedDissection __MlevelNestedDissection +#define MlevelNestedDissectionCC __MlevelNestedDissectionCC +#define MlevelNodeBisectionMultiple __MlevelNodeBisectionMultiple +#define MlevelNodeBisection __MlevelNodeBisection +#define SplitGraphOrder __SplitGraphOrder +#define MMDOrder __MMDOrder +#define SplitGraphOrderCC __SplitGraphOrderCC + + +/* parmetis.c */ +#define MlevelNestedDissectionP __MlevelNestedDissectionP + + +/* pmetis.c */ +#define MlevelRecursiveBisection __MlevelRecursiveBisection +#define MlevelEdgeBisection __MlevelEdgeBisection +#define SplitGraphPart __SplitGraphPart +#define SetUpSplitGraph __SetUpSplitGraph + + +/* pqueue.c */ +#define PQueueInit __PQueueInit +#define PQueueReset __PQueueReset +#define PQueueFree __PQueueFree +#define PQueueInsert __PQueueInsert +#define PQueueDelete __PQueueDelete +#define PQueueUpdate __PQueueUpdate +#define PQueueUpdateUp __PQueueUpdateUp +#define PQueueGetMax __PQueueGetMax +#define PQueueSeeMax __PQueueSeeMax +#define CheckHeap __CheckHeap + + +/* refine.c */ +#define Refine2Way __Refine2Way +#define Allocate2WayPartitionMemory __Allocate2WayPartitionMemory +#define Compute2WayPartitionParams __Compute2WayPartitionParams +#define Project2WayPartition __Project2WayPartition + + +/* separator.c */ +#define ConstructSeparator __ConstructSeparator +#define ConstructMinCoverSeparator0 __ConstructMinCoverSeparator0 +#define ConstructMinCoverSeparator __ConstructMinCoverSeparator + + +/* sfm.c */ +#define FM_2WayNodeRefine __FM_2WayNodeRefine +#define FM_2WayNodeRefineEqWgt __FM_2WayNodeRefineEqWgt +#define FM_2WayNodeRefine_OneSided __FM_2WayNodeRefine_OneSided +#define FM_2WayNodeBalance __FM_2WayNodeBalance +#define ComputeMaxNodeGain __ComputeMaxNodeGain + + +/* srefine.c */ +#define Refine2WayNode __Refine2WayNode +#define Allocate2WayNodePartitionMemory __Allocate2WayNodePartitionMemory +#define Compute2WayNodePartitionParams __Compute2WayNodePartitionParams +#define Project2WayNodePartition __Project2WayNodePartition + + +/* stat.c */ +#define ComputePartitionInfo __ComputePartitionInfo +#define ComputePartitionBalance __ComputePartitionBalance +#define ComputeElementBalance __ComputeElementBalance + + +/* subdomains.c */ +#define Random_KWayEdgeRefineMConn __Random_KWayEdgeRefineMConn +#define Greedy_KWayEdgeBalanceMConn __Greedy_KWayEdgeBalanceMConn +#define PrintSubDomainGraph __PrintSubDomainGraph +#define ComputeSubDomainGraph __ComputeSubDomainGraph +#define EliminateSubDomainEdges __EliminateSubDomainEdges +#define MoveGroupMConn __MoveGroupMConn +#define EliminateComponents __EliminateComponents +#define MoveGroup __MoveGroup + + +/* timing.c */ +#define InitTimers __InitTimers +#define PrintTimers __PrintTimers +#define seconds __seconds + + +/* util.c */ +#define errexit __errexit +#define GKfree __GKfree +#ifndef DMALLOC +#define imalloc __imalloc +#define idxmalloc __idxmalloc +#define fmalloc __fmalloc +#define ismalloc __ismalloc +#define idxsmalloc __idxsmalloc +#define GKmalloc __GKmalloc +#endif +#define iset __iset +#define idxset __idxset +#define sset __sset +#define iamax __iamax +#define idxamax __idxamax +#define idxamax_strd __idxamax_strd +#define samax __samax +#define samax2 __samax2 +#define idxamin __idxamin +#define samin __samin +#define idxsum __idxsum +#define idxsum_strd __idxsum_strd +#define idxadd __idxadd +#define charsum __charsum +#define isum __isum +#define ssum __ssum +#define ssum_strd __ssum_strd +#define sscale __sscale +#define snorm2 __snorm2 +#define sdot __sdot +#define saxpy __saxpy +#define RandomPermute __RandomPermute +#define ispow2 __ispow2 +#define InitRandom __InitRandom +#define log2 __log2 + + + + + diff --git a/contrib/Metis/separator.c b/contrib/Metis/separator.c new file mode 100644 index 0000000000..0c81725b8a --- /dev/null +++ b/contrib/Metis/separator.c @@ -0,0 +1,284 @@ +/* + * Copyright 1997, Regents of the University of Minnesota + * + * separator.c + * + * This file contains code for separator extraction + * + * Started 8/1/97 + * George + * + * $Id: separator.c,v 1.1 2005-09-21 17:29:38 geuzaine Exp $ + * + */ + +#include <metis.h> + +/************************************************************************* +* This function takes a bisection and constructs a minimum weight vertex +* separator out of it. It uses the node-based separator refinement for it. +**************************************************************************/ +void ConstructSeparator(CtrlType *ctrl, GraphType *graph, float ubfactor) +{ + int i, j, k, nvtxs, nbnd; + idxtype *xadj, *where, *bndind; + + nvtxs = graph->nvtxs; + xadj = graph->xadj; + nbnd = graph->nbnd; + bndind = graph->bndind; + + where = idxcopy(nvtxs, graph->where, idxwspacemalloc(ctrl, nvtxs)); + + /* Put the nodes in the boundary into the separator */ + for (i=0; i<nbnd; i++) { + j = bndind[i]; + if (xadj[j+1]-xadj[j] > 0) /* Ignore islands */ + where[j] = 2; + } + + GKfree(&graph->rdata, LTERM); + Allocate2WayNodePartitionMemory(ctrl, graph); + idxcopy(nvtxs, where, graph->where); + idxwspacefree(ctrl, nvtxs); + + ASSERT(IsSeparable(graph)); + + Compute2WayNodePartitionParams(ctrl, graph); + + ASSERT(CheckNodePartitionParams(graph)); + + FM_2WayNodeRefine(ctrl, graph, ubfactor, 8); + + ASSERT(IsSeparable(graph)); +} + + + +/************************************************************************* +* This function takes a bisection and constructs a minimum weight vertex +* separator out of it. It uses an unweighted minimum-cover algorithm +* followed by node-based separator refinement. +**************************************************************************/ +void ConstructMinCoverSeparator0(CtrlType *ctrl, GraphType *graph, float ubfactor) +{ + int i, ii, j, jj, k, l, nvtxs, nbnd, bnvtxs[3], bnedges[2], csize; + idxtype *xadj, *adjncy, *bxadj, *badjncy; + idxtype *where, *bndind, *bndptr, *vmap, *ivmap, *cover; + + + nvtxs = graph->nvtxs; + xadj = graph->xadj; + adjncy = graph->adjncy; + + nbnd = graph->nbnd; + bndind = graph->bndind; + bndptr = graph->bndptr; + where = graph->where; + + vmap = idxwspacemalloc(ctrl, nvtxs); + ivmap = idxwspacemalloc(ctrl, nbnd); + cover = idxwspacemalloc(ctrl, nbnd); + + if (nbnd > 0) { + /* Go through the boundary and determine the sizes of the bipartite graph */ + bnvtxs[0] = bnvtxs[1] = bnedges[0] = bnedges[1] = 0; + for (i=0; i<nbnd; i++) { + j = bndind[i]; + k = where[j]; + if (xadj[j+1]-xadj[j] > 0) { + bnvtxs[k]++; + bnedges[k] += xadj[j+1]-xadj[j]; + } + } + + bnvtxs[2] = bnvtxs[0]+bnvtxs[1]; + bnvtxs[1] = bnvtxs[0]; + bnvtxs[0] = 0; + + bxadj = idxmalloc(bnvtxs[2]+1, "ConstructMinCoverSeparator: bxadj"); + badjncy = idxmalloc(bnedges[0]+bnedges[1]+1, "ConstructMinCoverSeparator: badjncy"); + + /* Construct the ivmap and vmap */ + ASSERT(idxset(nvtxs, -1, vmap) == vmap); + for (i=0; i<nbnd; i++) { + j = bndind[i]; + k = where[j]; + if (xadj[j+1]-xadj[j] > 0) { + vmap[j] = bnvtxs[k]; + ivmap[bnvtxs[k]++] = j; + } + } + + /* OK, go through and put the vertices of each part starting from 0 */ + bnvtxs[1] = bnvtxs[0]; + bnvtxs[0] = 0; + bxadj[0] = l = 0; + for (k=0; k<2; k++) { + for (ii=0; ii<nbnd; ii++) { + i = bndind[ii]; + if (where[i] == k && xadj[i] < xadj[i+1]) { + for (j=xadj[i]; j<xadj[i+1]; j++) { + jj = adjncy[j]; + if (where[jj] != k) { + ASSERT(bndptr[jj] != -1); + ASSERTP(vmap[jj] != -1, ("%d %d %d\n", jj, vmap[jj], graph->bndptr[jj])); + badjncy[l++] = vmap[jj]; + } + } + bxadj[++bnvtxs[k]] = l; + } + } + } + + ASSERT(l <= bnedges[0]+bnedges[1]); + + MinCover(bxadj, badjncy, bnvtxs[0], bnvtxs[1], cover, &csize); + + IFSET(ctrl->dbglvl, DBG_SEPINFO, + printf("Nvtxs: %6d, [%5d %5d], Cut: %6d, SS: [%6d %6d], Cover: %6d\n", nvtxs, graph->pwgts[0], graph->pwgts[1], graph->mincut, bnvtxs[0], bnvtxs[1]-bnvtxs[0], csize)); + + for (i=0; i<csize; i++) { + j = ivmap[cover[i]]; + where[j] = 2; + } + + GKfree(&bxadj, &badjncy, LTERM); + + for (i=0; i<nbnd; i++) + bndptr[bndind[i]] = -1; + for (nbnd=i=0; i<nvtxs; i++) { + if (where[i] == 2) { + bndind[nbnd] = i; + bndptr[i] = nbnd++; + } + } + } + else { + IFSET(ctrl->dbglvl, DBG_SEPINFO, + printf("Nvtxs: %6d, [%5d %5d], Cut: %6d, SS: [%6d %6d], Cover: %6d\n", nvtxs, graph->pwgts[0], graph->pwgts[1], graph->mincut, 0, 0, 0)); + } + + idxwspacefree(ctrl, nvtxs); + idxwspacefree(ctrl, graph->nbnd); + idxwspacefree(ctrl, graph->nbnd); + graph->nbnd = nbnd; + + + ASSERT(IsSeparable(graph)); +} + + + +/************************************************************************* +* This function takes a bisection and constructs a minimum weight vertex +* separator out of it. It uses an unweighted minimum-cover algorithm +* followed by node-based separator refinement. +**************************************************************************/ +void ConstructMinCoverSeparator(CtrlType *ctrl, GraphType *graph, float ubfactor) +{ + int i, ii, j, jj, k, l, nvtxs, nbnd, bnvtxs[3], bnedges[2], csize; + idxtype *xadj, *adjncy, *bxadj, *badjncy; + idxtype *where, *bndind, *bndptr, *vmap, *ivmap, *cover; + + + nvtxs = graph->nvtxs; + xadj = graph->xadj; + adjncy = graph->adjncy; + + nbnd = graph->nbnd; + bndind = graph->bndind; + bndptr = graph->bndptr; + where = graph->where; + + vmap = idxwspacemalloc(ctrl, nvtxs); + ivmap = idxwspacemalloc(ctrl, nbnd); + cover = idxwspacemalloc(ctrl, nbnd); + + if (nbnd > 0) { + /* Go through the boundary and determine the sizes of the bipartite graph */ + bnvtxs[0] = bnvtxs[1] = bnedges[0] = bnedges[1] = 0; + for (i=0; i<nbnd; i++) { + j = bndind[i]; + k = where[j]; + if (xadj[j+1]-xadj[j] > 0) { + bnvtxs[k]++; + bnedges[k] += xadj[j+1]-xadj[j]; + } + } + + bnvtxs[2] = bnvtxs[0]+bnvtxs[1]; + bnvtxs[1] = bnvtxs[0]; + bnvtxs[0] = 0; + + bxadj = idxmalloc(bnvtxs[2]+1, "ConstructMinCoverSeparator: bxadj"); + badjncy = idxmalloc(bnedges[0]+bnedges[1]+1, "ConstructMinCoverSeparator: badjncy"); + + /* Construct the ivmap and vmap */ + ASSERT(idxset(nvtxs, -1, vmap) == vmap); + for (i=0; i<nbnd; i++) { + j = bndind[i]; + k = where[j]; + if (xadj[j+1]-xadj[j] > 0) { + vmap[j] = bnvtxs[k]; + ivmap[bnvtxs[k]++] = j; + } + } + + /* OK, go through and put the vertices of each part starting from 0 */ + bnvtxs[1] = bnvtxs[0]; + bnvtxs[0] = 0; + bxadj[0] = l = 0; + for (k=0; k<2; k++) { + for (ii=0; ii<nbnd; ii++) { + i = bndind[ii]; + if (where[i] == k && xadj[i] < xadj[i+1]) { + for (j=xadj[i]; j<xadj[i+1]; j++) { + jj = adjncy[j]; + if (where[jj] != k) { + ASSERT(bndptr[jj] != -1); + ASSERTP(vmap[jj] != -1, ("%d %d %d\n", jj, vmap[jj], graph->bndptr[jj])); + badjncy[l++] = vmap[jj]; + } + } + bxadj[++bnvtxs[k]] = l; + } + } + } + + ASSERT(l <= bnedges[0]+bnedges[1]); + + MinCover(bxadj, badjncy, bnvtxs[0], bnvtxs[1], cover, &csize); + + IFSET(ctrl->dbglvl, DBG_SEPINFO, + printf("Nvtxs: %6d, [%5d %5d], Cut: %6d, SS: [%6d %6d], Cover: %6d\n", nvtxs, graph->pwgts[0], graph->pwgts[1], graph->mincut, bnvtxs[0], bnvtxs[1]-bnvtxs[0], csize)); + + for (i=0; i<csize; i++) { + j = ivmap[cover[i]]; + where[j] = 2; + } + + GKfree(&bxadj, &badjncy, LTERM); + } + else { + IFSET(ctrl->dbglvl, DBG_SEPINFO, + printf("Nvtxs: %6d, [%5d %5d], Cut: %6d, SS: [%6d %6d], Cover: %6d\n", nvtxs, graph->pwgts[0], graph->pwgts[1], graph->mincut, 0, 0, 0)); + } + + /* Prepare to refine the vertex separator */ + idxcopy(nvtxs, graph->where, vmap); + GKfree(&graph->rdata, LTERM); + + Allocate2WayNodePartitionMemory(ctrl, graph); + idxcopy(nvtxs, vmap, graph->where); + idxwspacefree(ctrl, nvtxs+2*graph->nbnd); + + Compute2WayNodePartitionParams(ctrl, graph); + + ASSERT(CheckNodePartitionParams(graph)); + + FM_2WayNodeRefine_OneSided(ctrl, graph, ubfactor, 6); + + ASSERT(IsSeparable(graph)); +} + diff --git a/contrib/Metis/sfm.c b/contrib/Metis/sfm.c new file mode 100644 index 0000000000..40108b87b1 --- /dev/null +++ b/contrib/Metis/sfm.c @@ -0,0 +1,1069 @@ +/* + * Copyright 1997, Regents of the University of Minnesota + * + * sfm.c + * + * This file contains code that implementes an FM-based separator refinement + * + * Started 8/1/97 + * George + * + * $Id: sfm.c,v 1.1 2005-09-21 17:29:38 geuzaine Exp $ + * + */ + +#include <metis.h> + + +/************************************************************************* +* This function performs a node-based FM refinement +**************************************************************************/ +void FM_2WayNodeRefine(CtrlType *ctrl, GraphType *graph, float ubfactor, int npasses) +{ + int i, ii, j, k, jj, kk, nvtxs, nbnd, nswaps, nmind; + idxtype *xadj, *vwgt, *adjncy, *where, *pwgts, *edegrees, *bndind, *bndptr; + idxtype *mptr, *mind, *moved, *swaps, *perm; + PQueueType parts[2]; + NRInfoType *rinfo; + int higain, oldgain, mincut, initcut, mincutorder; + int pass, to, other, limit; + int badmaxpwgt, mindiff, newdiff; + int u[2], g[2]; + + nvtxs = graph->nvtxs; + xadj = graph->xadj; + adjncy = graph->adjncy; + vwgt = graph->vwgt; + + bndind = graph->bndind; + bndptr = graph->bndptr; + where = graph->where; + pwgts = graph->pwgts; + rinfo = graph->nrinfo; + + + i = ComputeMaxNodeGain(nvtxs, xadj, adjncy, vwgt); + PQueueInit(ctrl, &parts[0], nvtxs, i); + PQueueInit(ctrl, &parts[1], nvtxs, i); + + moved = idxwspacemalloc(ctrl, nvtxs); + swaps = idxwspacemalloc(ctrl, nvtxs); + mptr = idxwspacemalloc(ctrl, nvtxs+1); + mind = idxwspacemalloc(ctrl, nvtxs); + perm = idxwspacemalloc(ctrl, nvtxs); + + IFSET(ctrl->dbglvl, DBG_REFINE, + printf("Partitions: [%6d %6d] Nv-Nb[%6d %6d]. ISep: %6d\n", pwgts[0], pwgts[1], graph->nvtxs, graph->nbnd, graph->mincut)); + + badmaxpwgt = (int)(ubfactor*(pwgts[0]+pwgts[1]+pwgts[2])/2); + + for (pass=0; pass<npasses; pass++) { + idxset(nvtxs, -1, moved); + PQueueReset(&parts[0]); + PQueueReset(&parts[1]); + + mincutorder = -1; + initcut = mincut = graph->mincut; + nbnd = graph->nbnd; + + RandomPermute(nbnd, perm, 1); + for (ii=0; ii<nbnd; ii++) { + i = bndind[perm[ii]]; + ASSERT(where[i] == 2); + PQueueInsert(&parts[0], i, vwgt[i]-rinfo[i].edegrees[1]); + PQueueInsert(&parts[1], i, vwgt[i]-rinfo[i].edegrees[0]); + } + + ASSERT(CheckNodeBnd(graph, nbnd)); + ASSERT(CheckNodePartitionParams(graph)); + + limit = (ctrl->oflags&OFLAG_COMPRESS ? amin(5*nbnd, 400) : amin(2*nbnd, 300)); + + /****************************************************** + * Get into the FM loop + *******************************************************/ + mptr[0] = nmind = 0; + mindiff = abs(pwgts[0]-pwgts[1]); + to = (pwgts[0] < pwgts[1] ? 0 : 1); + for (nswaps=0; nswaps<nvtxs; nswaps++) { + u[0] = PQueueSeeMax(&parts[0]); + u[1] = PQueueSeeMax(&parts[1]); + if (u[0] != -1 && u[1] != -1) { + g[0] = vwgt[u[0]]-rinfo[u[0]].edegrees[1]; + g[1] = vwgt[u[1]]-rinfo[u[1]].edegrees[0]; + + to = (g[0] > g[1] ? 0 : (g[0] < g[1] ? 1 : pass%2)); + /* to = (g[0] > g[1] ? 0 : (g[0] < g[1] ? 1 : (pwgts[0] < pwgts[1] ? 0 : 1))); */ + + if (pwgts[to]+vwgt[u[to]] > badmaxpwgt) + to = (to+1)%2; + } + else if (u[0] == -1 && u[1] == -1) { + break; + } + else if (u[0] != -1 && pwgts[0]+vwgt[u[0]] <= badmaxpwgt) { + to = 0; + } + else if (u[1] != -1 && pwgts[1]+vwgt[u[1]] <= badmaxpwgt) { + to = 1; + } + else + break; + + other = (to+1)%2; + + higain = PQueueGetMax(&parts[to]); + if (moved[higain] == -1) /* Delete if it was in the separator originally */ + PQueueDelete(&parts[other], higain, vwgt[higain]-rinfo[higain].edegrees[to]); + + ASSERT(bndptr[higain] != -1); + + pwgts[2] -= (vwgt[higain]-rinfo[higain].edegrees[other]); + + newdiff = abs(pwgts[to]+vwgt[higain] - (pwgts[other]-rinfo[higain].edegrees[other])); + if (pwgts[2] < mincut || (pwgts[2] == mincut && newdiff < mindiff)) { + mincut = pwgts[2]; + mincutorder = nswaps; + mindiff = newdiff; + } + else { + if (nswaps - mincutorder > limit) { + pwgts[2] += (vwgt[higain]-rinfo[higain].edegrees[other]); + break; /* No further improvement, break out */ + } + } + + BNDDelete(nbnd, bndind, bndptr, higain); + pwgts[to] += vwgt[higain]; + where[higain] = to; + moved[higain] = nswaps; + swaps[nswaps] = higain; + + + /********************************************************** + * Update the degrees of the affected nodes + ***********************************************************/ + for (j=xadj[higain]; j<xadj[higain+1]; j++) { + k = adjncy[j]; + if (where[k] == 2) { /* For the in-separator vertices modify their edegree[to] */ + oldgain = vwgt[k]-rinfo[k].edegrees[to]; + rinfo[k].edegrees[to] += vwgt[higain]; + if (moved[k] == -1 || moved[k] == -(2+other)) + PQueueUpdate(&parts[other], k, oldgain, oldgain-vwgt[higain]); + } + else if (where[k] == other) { /* This vertex is pulled into the separator */ + ASSERTP(bndptr[k] == -1, ("%d %d %d\n", k, bndptr[k], where[k])); + BNDInsert(nbnd, bndind, bndptr, k); + + mind[nmind++] = k; /* Keep track for rollback */ + where[k] = 2; + pwgts[other] -= vwgt[k]; + + edegrees = rinfo[k].edegrees; + edegrees[0] = edegrees[1] = 0; + for (jj=xadj[k]; jj<xadj[k+1]; jj++) { + kk = adjncy[jj]; + if (where[kk] != 2) + edegrees[where[kk]] += vwgt[kk]; + else { + oldgain = vwgt[kk]-rinfo[kk].edegrees[other]; + rinfo[kk].edegrees[other] -= vwgt[k]; + if (moved[kk] == -1 || moved[kk] == -(2+to)) + PQueueUpdate(&parts[to], kk, oldgain, oldgain+vwgt[k]); + } + } + + /* Insert the new vertex into the priority queue. Only one side! */ + if (moved[k] == -1) { + PQueueInsert(&parts[to], k, vwgt[k]-edegrees[other]); + moved[k] = -(2+to); + } + } + } + mptr[nswaps+1] = nmind; + + IFSET(ctrl->dbglvl, DBG_MOVEINFO, + printf("Moved %6d to %3d, Gain: %5d [%5d] [%4d %4d] \t[%5d %5d %5d]\n", higain, to, g[to], g[other], vwgt[u[to]], vwgt[u[other]], pwgts[0], pwgts[1], pwgts[2])); + + } + + + /**************************************************************** + * Roll back computation + *****************************************************************/ + for (nswaps--; nswaps>mincutorder; nswaps--) { + higain = swaps[nswaps]; + + ASSERT(CheckNodePartitionParams(graph)); + + to = where[higain]; + other = (to+1)%2; + INC_DEC(pwgts[2], pwgts[to], vwgt[higain]); + where[higain] = 2; + BNDInsert(nbnd, bndind, bndptr, higain); + + edegrees = rinfo[higain].edegrees; + edegrees[0] = edegrees[1] = 0; + for (j=xadj[higain]; j<xadj[higain+1]; j++) { + k = adjncy[j]; + if (where[k] == 2) + rinfo[k].edegrees[to] -= vwgt[higain]; + else + edegrees[where[k]] += vwgt[k]; + } + + /* Push nodes out of the separator */ + for (j=mptr[nswaps]; j<mptr[nswaps+1]; j++) { + k = mind[j]; + ASSERT(where[k] == 2); + where[k] = other; + INC_DEC(pwgts[other], pwgts[2], vwgt[k]); + BNDDelete(nbnd, bndind, bndptr, k); + for (jj=xadj[k]; jj<xadj[k+1]; jj++) { + kk = adjncy[jj]; + if (where[kk] == 2) + rinfo[kk].edegrees[other] += vwgt[k]; + } + } + } + + ASSERT(mincut == pwgts[2]); + + IFSET(ctrl->dbglvl, DBG_REFINE, + printf("\tMinimum sep: %6d at %5d, PWGTS: [%6d %6d], NBND: %6d\n", mincut, mincutorder, pwgts[0], pwgts[1], nbnd)); + + graph->mincut = mincut; + graph->nbnd = nbnd; + + if (mincutorder == -1 || mincut >= initcut) + break; + } + + PQueueFree(ctrl, &parts[0]); + PQueueFree(ctrl, &parts[1]); + + idxwspacefree(ctrl, nvtxs+1); + idxwspacefree(ctrl, nvtxs); + idxwspacefree(ctrl, nvtxs); + idxwspacefree(ctrl, nvtxs); + idxwspacefree(ctrl, nvtxs); +} + + +/************************************************************************* +* This function performs a node-based FM refinement +**************************************************************************/ +void FM_2WayNodeRefine2(CtrlType *ctrl, GraphType *graph, float ubfactor, int npasses) +{ + int i, ii, j, k, jj, kk, nvtxs, nbnd, nswaps, nmind; + idxtype *xadj, *vwgt, *adjncy, *where, *pwgts, *edegrees, *bndind, *bndptr; + idxtype *mptr, *mind, *moved, *swaps, *perm; + PQueueType parts[2]; + NRInfoType *rinfo; + int higain, oldgain, mincut, initcut, mincutorder; + int pass, to, other, limit; + int badmaxpwgt, mindiff, newdiff; + int u[2], g[2]; + + nvtxs = graph->nvtxs; + xadj = graph->xadj; + adjncy = graph->adjncy; + vwgt = graph->vwgt; + + bndind = graph->bndind; + bndptr = graph->bndptr; + where = graph->where; + pwgts = graph->pwgts; + rinfo = graph->nrinfo; + + + i = ComputeMaxNodeGain(nvtxs, xadj, adjncy, vwgt); + PQueueInit(ctrl, &parts[0], nvtxs, i); + PQueueInit(ctrl, &parts[1], nvtxs, i); + + moved = idxwspacemalloc(ctrl, nvtxs); + swaps = idxwspacemalloc(ctrl, nvtxs); + mptr = idxwspacemalloc(ctrl, nvtxs+1); + mind = idxwspacemalloc(ctrl, nvtxs); + perm = idxwspacemalloc(ctrl, nvtxs); + + IFSET(ctrl->dbglvl, DBG_REFINE, + printf("Partitions: [%6d %6d] Nv-Nb[%6d %6d]. ISep: %6d\n", pwgts[0], pwgts[1], graph->nvtxs, graph->nbnd, graph->mincut)); + + badmaxpwgt = (int)(ubfactor*(pwgts[0]+pwgts[1]+pwgts[2])/2); + + for (pass=0; pass<npasses; pass++) { + idxset(nvtxs, -1, moved); + PQueueReset(&parts[0]); + PQueueReset(&parts[1]); + + mincutorder = -1; + initcut = mincut = graph->mincut; + nbnd = graph->nbnd; + + RandomPermute(nbnd, perm, 1); + for (ii=0; ii<nbnd; ii++) { + i = bndind[perm[ii]]; + ASSERT(where[i] == 2); + PQueueInsert(&parts[0], i, vwgt[i]-rinfo[i].edegrees[1]); + PQueueInsert(&parts[1], i, vwgt[i]-rinfo[i].edegrees[0]); + } + + ASSERT(CheckNodeBnd(graph, nbnd)); + ASSERT(CheckNodePartitionParams(graph)); + + limit = (ctrl->oflags&OFLAG_COMPRESS ? amin(5*nbnd, 400) : amin(2*nbnd, 300)); + + /****************************************************** + * Get into the FM loop + *******************************************************/ + mptr[0] = nmind = 0; + mindiff = abs(pwgts[0]-pwgts[1]); + to = (pwgts[0] < pwgts[1] ? 0 : 1); + for (nswaps=0; nswaps<nvtxs; nswaps++) { + badmaxpwgt = (int)(ubfactor*(pwgts[0]+pwgts[1]+pwgts[2]/2)/2); + + u[0] = PQueueSeeMax(&parts[0]); + u[1] = PQueueSeeMax(&parts[1]); + if (u[0] != -1 && u[1] != -1) { + g[0] = vwgt[u[0]]-rinfo[u[0]].edegrees[1]; + g[1] = vwgt[u[1]]-rinfo[u[1]].edegrees[0]; + + to = (g[0] > g[1] ? 0 : (g[0] < g[1] ? 1 : pass%2)); + /* to = (g[0] > g[1] ? 0 : (g[0] < g[1] ? 1 : (pwgts[0] < pwgts[1] ? 0 : 1))); */ + + if (pwgts[to]+vwgt[u[to]] > badmaxpwgt) + to = (to+1)%2; + } + else if (u[0] == -1 && u[1] == -1) { + break; + } + else if (u[0] != -1 && pwgts[0]+vwgt[u[0]] <= badmaxpwgt) { + to = 0; + } + else if (u[1] != -1 && pwgts[1]+vwgt[u[1]] <= badmaxpwgt) { + to = 1; + } + else + break; + + other = (to+1)%2; + + higain = PQueueGetMax(&parts[to]); + if (moved[higain] == -1) /* Delete if it was in the separator originally */ + PQueueDelete(&parts[other], higain, vwgt[higain]-rinfo[higain].edegrees[to]); + + ASSERT(bndptr[higain] != -1); + + pwgts[2] -= (vwgt[higain]-rinfo[higain].edegrees[other]); + + newdiff = abs(pwgts[to]+vwgt[higain] - (pwgts[other]-rinfo[higain].edegrees[other])); + if (pwgts[2] < mincut || (pwgts[2] == mincut && newdiff < mindiff)) { + mincut = pwgts[2]; + mincutorder = nswaps; + mindiff = newdiff; + } + else { + if (nswaps - mincutorder > limit) { + pwgts[2] += (vwgt[higain]-rinfo[higain].edegrees[other]); + break; /* No further improvement, break out */ + } + } + + BNDDelete(nbnd, bndind, bndptr, higain); + pwgts[to] += vwgt[higain]; + where[higain] = to; + moved[higain] = nswaps; + swaps[nswaps] = higain; + + + /********************************************************** + * Update the degrees of the affected nodes + ***********************************************************/ + for (j=xadj[higain]; j<xadj[higain+1]; j++) { + k = adjncy[j]; + if (where[k] == 2) { /* For the in-separator vertices modify their edegree[to] */ + oldgain = vwgt[k]-rinfo[k].edegrees[to]; + rinfo[k].edegrees[to] += vwgt[higain]; + if (moved[k] == -1 || moved[k] == -(2+other)) + PQueueUpdate(&parts[other], k, oldgain, oldgain-vwgt[higain]); + } + else if (where[k] == other) { /* This vertex is pulled into the separator */ + ASSERTP(bndptr[k] == -1, ("%d %d %d\n", k, bndptr[k], where[k])); + BNDInsert(nbnd, bndind, bndptr, k); + + mind[nmind++] = k; /* Keep track for rollback */ + where[k] = 2; + pwgts[other] -= vwgt[k]; + + edegrees = rinfo[k].edegrees; + edegrees[0] = edegrees[1] = 0; + for (jj=xadj[k]; jj<xadj[k+1]; jj++) { + kk = adjncy[jj]; + if (where[kk] != 2) + edegrees[where[kk]] += vwgt[kk]; + else { + oldgain = vwgt[kk]-rinfo[kk].edegrees[other]; + rinfo[kk].edegrees[other] -= vwgt[k]; + if (moved[kk] == -1 || moved[kk] == -(2+to)) + PQueueUpdate(&parts[to], kk, oldgain, oldgain+vwgt[k]); + } + } + + /* Insert the new vertex into the priority queue. Only one side! */ + if (moved[k] == -1) { + PQueueInsert(&parts[to], k, vwgt[k]-edegrees[other]); + moved[k] = -(2+to); + } + } + } + mptr[nswaps+1] = nmind; + + IFSET(ctrl->dbglvl, DBG_MOVEINFO, + printf("Moved %6d to %3d, Gain: %5d [%5d] [%4d %4d] \t[%5d %5d %5d]\n", higain, to, g[to], g[other], vwgt[u[to]], vwgt[u[other]], pwgts[0], pwgts[1], pwgts[2])); + + } + + + /**************************************************************** + * Roll back computation + *****************************************************************/ + for (nswaps--; nswaps>mincutorder; nswaps--) { + higain = swaps[nswaps]; + + ASSERT(CheckNodePartitionParams(graph)); + + to = where[higain]; + other = (to+1)%2; + INC_DEC(pwgts[2], pwgts[to], vwgt[higain]); + where[higain] = 2; + BNDInsert(nbnd, bndind, bndptr, higain); + + edegrees = rinfo[higain].edegrees; + edegrees[0] = edegrees[1] = 0; + for (j=xadj[higain]; j<xadj[higain+1]; j++) { + k = adjncy[j]; + if (where[k] == 2) + rinfo[k].edegrees[to] -= vwgt[higain]; + else + edegrees[where[k]] += vwgt[k]; + } + + /* Push nodes out of the separator */ + for (j=mptr[nswaps]; j<mptr[nswaps+1]; j++) { + k = mind[j]; + ASSERT(where[k] == 2); + where[k] = other; + INC_DEC(pwgts[other], pwgts[2], vwgt[k]); + BNDDelete(nbnd, bndind, bndptr, k); + for (jj=xadj[k]; jj<xadj[k+1]; jj++) { + kk = adjncy[jj]; + if (where[kk] == 2) + rinfo[kk].edegrees[other] += vwgt[k]; + } + } + } + + ASSERT(mincut == pwgts[2]); + + IFSET(ctrl->dbglvl, DBG_REFINE, + printf("\tMinimum sep: %6d at %5d, PWGTS: [%6d %6d], NBND: %6d\n", mincut, mincutorder, pwgts[0], pwgts[1], nbnd)); + + graph->mincut = mincut; + graph->nbnd = nbnd; + + if (mincutorder == -1 || mincut >= initcut) + break; + } + + PQueueFree(ctrl, &parts[0]); + PQueueFree(ctrl, &parts[1]); + + idxwspacefree(ctrl, nvtxs+1); + idxwspacefree(ctrl, nvtxs); + idxwspacefree(ctrl, nvtxs); + idxwspacefree(ctrl, nvtxs); + idxwspacefree(ctrl, nvtxs); +} + + +/************************************************************************* +* This function performs a node-based FM refinement +**************************************************************************/ +void FM_2WayNodeRefineEqWgt(CtrlType *ctrl, GraphType *graph, int npasses) +{ + int i, ii, j, k, jj, kk, nvtxs, nbnd, nswaps, nmind; + idxtype *xadj, *vwgt, *adjncy, *where, *pwgts, *edegrees, *bndind, *bndptr; + idxtype *mptr, *mind, *moved, *swaps, *perm; + PQueueType parts[2]; + NRInfoType *rinfo; + int higain, oldgain, mincut, initcut, mincutorder; + int pass, to, other, limit; + int mindiff, newdiff; + int u[2], g[2]; + + nvtxs = graph->nvtxs; + xadj = graph->xadj; + adjncy = graph->adjncy; + vwgt = graph->vwgt; + + bndind = graph->bndind; + bndptr = graph->bndptr; + where = graph->where; + pwgts = graph->pwgts; + rinfo = graph->nrinfo; + + + i = ComputeMaxNodeGain(nvtxs, xadj, adjncy, vwgt); + PQueueInit(ctrl, &parts[0], nvtxs, i); + PQueueInit(ctrl, &parts[1], nvtxs, i); + + moved = idxwspacemalloc(ctrl, nvtxs); + swaps = idxwspacemalloc(ctrl, nvtxs); + mptr = idxwspacemalloc(ctrl, nvtxs+1); + mind = idxwspacemalloc(ctrl, nvtxs); + perm = idxwspacemalloc(ctrl, nvtxs); + + IFSET(ctrl->dbglvl, DBG_REFINE, + printf("Partitions: [%6d %6d] Nv-Nb[%6d %6d]. ISep: %6d\n", pwgts[0], pwgts[1], graph->nvtxs, graph->nbnd, graph->mincut)); + + for (pass=0; pass<npasses; pass++) { + idxset(nvtxs, -1, moved); + PQueueReset(&parts[0]); + PQueueReset(&parts[1]); + + mincutorder = -1; + initcut = mincut = graph->mincut; + nbnd = graph->nbnd; + + RandomPermute(nbnd, perm, 1); + for (ii=0; ii<nbnd; ii++) { + i = bndind[perm[ii]]; + ASSERT(where[i] == 2); + PQueueInsert(&parts[0], i, vwgt[i]-rinfo[i].edegrees[1]); + PQueueInsert(&parts[1], i, vwgt[i]-rinfo[i].edegrees[0]); + } + + ASSERT(CheckNodeBnd(graph, nbnd)); + ASSERT(CheckNodePartitionParams(graph)); + + limit = (ctrl->oflags&OFLAG_COMPRESS ? amin(5*nbnd, 400) : amin(2*nbnd, 300)); + + /****************************************************** + * Get into the FM loop + *******************************************************/ + mptr[0] = nmind = 0; + mindiff = abs(pwgts[0]-pwgts[1]); + to = (pwgts[0] < pwgts[1] ? 0 : 1); + for (nswaps=0; nswaps<nvtxs; nswaps++) { + to = (pwgts[0] < pwgts[1] ? 0 : 1); + + if (pwgts[0] == pwgts[1]) { + u[0] = PQueueSeeMax(&parts[0]); + u[1] = PQueueSeeMax(&parts[1]); + if (u[0] != -1 && u[1] != -1) { + g[0] = vwgt[u[0]]-rinfo[u[0]].edegrees[1]; + g[1] = vwgt[u[1]]-rinfo[u[1]].edegrees[0]; + + to = (g[0] > g[1] ? 0 : (g[0] < g[1] ? 1 : pass%2)); + } + } + other = (to+1)%2; + + if ((higain = PQueueGetMax(&parts[to])) == -1) + break; + + if (moved[higain] == -1) /* Delete if it was in the separator originally */ + PQueueDelete(&parts[other], higain, vwgt[higain]-rinfo[higain].edegrees[to]); + + ASSERT(bndptr[higain] != -1); + + pwgts[2] -= (vwgt[higain]-rinfo[higain].edegrees[other]); + + newdiff = abs(pwgts[to]+vwgt[higain] - (pwgts[other]-rinfo[higain].edegrees[other])); + if (pwgts[2] < mincut || (pwgts[2] == mincut && newdiff < mindiff)) { + mincut = pwgts[2]; + mincutorder = nswaps; + mindiff = newdiff; + } + else { + if (nswaps - mincutorder > limit) { + pwgts[2] += (vwgt[higain]-rinfo[higain].edegrees[other]); + break; /* No further improvement, break out */ + } + } + + BNDDelete(nbnd, bndind, bndptr, higain); + pwgts[to] += vwgt[higain]; + where[higain] = to; + moved[higain] = nswaps; + swaps[nswaps] = higain; + + + /********************************************************** + * Update the degrees of the affected nodes + ***********************************************************/ + for (j=xadj[higain]; j<xadj[higain+1]; j++) { + k = adjncy[j]; + if (where[k] == 2) { /* For the in-separator vertices modify their edegree[to] */ + oldgain = vwgt[k]-rinfo[k].edegrees[to]; + rinfo[k].edegrees[to] += vwgt[higain]; + if (moved[k] == -1 || moved[k] == -(2+other)) + PQueueUpdate(&parts[other], k, oldgain, oldgain-vwgt[higain]); + } + else if (where[k] == other) { /* This vertex is pulled into the separator */ + ASSERTP(bndptr[k] == -1, ("%d %d %d\n", k, bndptr[k], where[k])); + BNDInsert(nbnd, bndind, bndptr, k); + + mind[nmind++] = k; /* Keep track for rollback */ + where[k] = 2; + pwgts[other] -= vwgt[k]; + + edegrees = rinfo[k].edegrees; + edegrees[0] = edegrees[1] = 0; + for (jj=xadj[k]; jj<xadj[k+1]; jj++) { + kk = adjncy[jj]; + if (where[kk] != 2) + edegrees[where[kk]] += vwgt[kk]; + else { + oldgain = vwgt[kk]-rinfo[kk].edegrees[other]; + rinfo[kk].edegrees[other] -= vwgt[k]; + if (moved[kk] == -1 || moved[kk] == -(2+to)) + PQueueUpdate(&parts[to], kk, oldgain, oldgain+vwgt[k]); + } + } + + /* Insert the new vertex into the priority queue. Only one side! */ + if (moved[k] == -1) { + PQueueInsert(&parts[to], k, vwgt[k]-edegrees[other]); + moved[k] = -(2+to); + } + } + } + mptr[nswaps+1] = nmind; + + IFSET(ctrl->dbglvl, DBG_MOVEINFO, + printf("Moved %6d to %3d, Gain: %5d [%5d] [%4d %4d] \t[%5d %5d %5d]\n", higain, to, g[to], g[other], vwgt[u[to]], vwgt[u[other]], pwgts[0], pwgts[1], pwgts[2])); + + } + + + /**************************************************************** + * Roll back computation + *****************************************************************/ + for (nswaps--; nswaps>mincutorder; nswaps--) { + higain = swaps[nswaps]; + + ASSERT(CheckNodePartitionParams(graph)); + + to = where[higain]; + other = (to+1)%2; + INC_DEC(pwgts[2], pwgts[to], vwgt[higain]); + where[higain] = 2; + BNDInsert(nbnd, bndind, bndptr, higain); + + edegrees = rinfo[higain].edegrees; + edegrees[0] = edegrees[1] = 0; + for (j=xadj[higain]; j<xadj[higain+1]; j++) { + k = adjncy[j]; + if (where[k] == 2) + rinfo[k].edegrees[to] -= vwgt[higain]; + else + edegrees[where[k]] += vwgt[k]; + } + + /* Push nodes out of the separator */ + for (j=mptr[nswaps]; j<mptr[nswaps+1]; j++) { + k = mind[j]; + ASSERT(where[k] == 2); + where[k] = other; + INC_DEC(pwgts[other], pwgts[2], vwgt[k]); + BNDDelete(nbnd, bndind, bndptr, k); + for (jj=xadj[k]; jj<xadj[k+1]; jj++) { + kk = adjncy[jj]; + if (where[kk] == 2) + rinfo[kk].edegrees[other] += vwgt[k]; + } + } + } + + ASSERT(mincut == pwgts[2]); + + IFSET(ctrl->dbglvl, DBG_REFINE, + printf("\tMinimum sep: %6d at %5d, PWGTS: [%6d %6d], NBND: %6d\n", mincut, mincutorder, pwgts[0], pwgts[1], nbnd)); + + graph->mincut = mincut; + graph->nbnd = nbnd; + + if (mincutorder == -1 || mincut >= initcut) + break; + } + + PQueueFree(ctrl, &parts[0]); + PQueueFree(ctrl, &parts[1]); + + idxwspacefree(ctrl, nvtxs+1); + idxwspacefree(ctrl, nvtxs); + idxwspacefree(ctrl, nvtxs); + idxwspacefree(ctrl, nvtxs); + idxwspacefree(ctrl, nvtxs); +} + + +/************************************************************************* +* This function performs a node-based FM refinement. This is the +* one-way version +**************************************************************************/ +void FM_2WayNodeRefine_OneSided(CtrlType *ctrl, GraphType *graph, float ubfactor, int npasses) +{ + int i, ii, j, k, jj, kk, nvtxs, nbnd, nswaps, nmind; + idxtype *xadj, *vwgt, *adjncy, *where, *pwgts, *edegrees, *bndind, *bndptr; + idxtype *mptr, *mind, *swaps, *perm; + PQueueType parts; + NRInfoType *rinfo; + int higain, oldgain, mincut, initcut, mincutorder; + int pass, to, other, limit; + int badmaxpwgt, mindiff, newdiff; + + nvtxs = graph->nvtxs; + xadj = graph->xadj; + adjncy = graph->adjncy; + vwgt = graph->vwgt; + + bndind = graph->bndind; + bndptr = graph->bndptr; + where = graph->where; + pwgts = graph->pwgts; + rinfo = graph->nrinfo; + + PQueueInit(ctrl, &parts, nvtxs, ComputeMaxNodeGain(nvtxs, xadj, adjncy, vwgt)); + + perm = idxwspacemalloc(ctrl, nvtxs); + swaps = idxwspacemalloc(ctrl, nvtxs); + mptr = idxwspacemalloc(ctrl, nvtxs); + mind = idxwspacemalloc(ctrl, nvtxs+1); + + IFSET(ctrl->dbglvl, DBG_REFINE, + printf("Partitions-N1: [%6d %6d] Nv-Nb[%6d %6d]. ISep: %6d\n", pwgts[0], pwgts[1], graph->nvtxs, graph->nbnd, graph->mincut)); + + badmaxpwgt = (int)(ubfactor*(pwgts[0]+pwgts[1]+pwgts[2])/2); + + to = (pwgts[0] < pwgts[1] ? 1 : 0); + for (pass=0; pass<npasses; pass++) { + other = to; + to = (to+1)%2; + + PQueueReset(&parts); + + mincutorder = -1; + initcut = mincut = graph->mincut; + nbnd = graph->nbnd; + + RandomPermute(nbnd, perm, 1); + for (ii=0; ii<nbnd; ii++) { + i = bndind[perm[ii]]; + ASSERT(where[i] == 2); + PQueueInsert(&parts, i, vwgt[i]-rinfo[i].edegrees[other]); + } + + ASSERT(CheckNodeBnd(graph, nbnd)); + ASSERT(CheckNodePartitionParams(graph)); + + limit = (ctrl->oflags&OFLAG_COMPRESS ? amin(5*nbnd, 400) : amin(2*nbnd, 300)); + + /****************************************************** + * Get into the FM loop + *******************************************************/ + mptr[0] = nmind = 0; + mindiff = abs(pwgts[0]-pwgts[1]); + for (nswaps=0; nswaps<nvtxs; nswaps++) { + + if ((higain = PQueueGetMax(&parts)) == -1) + break; + + ASSERT(bndptr[higain] != -1); + + if (pwgts[to]+vwgt[higain] > badmaxpwgt) + break; /* No point going any further. Balance will be bad */ + + pwgts[2] -= (vwgt[higain]-rinfo[higain].edegrees[other]); + + newdiff = abs(pwgts[to]+vwgt[higain] - (pwgts[other]-rinfo[higain].edegrees[other])); + if (pwgts[2] < mincut || (pwgts[2] == mincut && newdiff < mindiff)) { + mincut = pwgts[2]; + mincutorder = nswaps; + mindiff = newdiff; + } + else { + if (nswaps - mincutorder > limit) { + pwgts[2] += (vwgt[higain]-rinfo[higain].edegrees[other]); + break; /* No further improvement, break out */ + } + } + + BNDDelete(nbnd, bndind, bndptr, higain); + pwgts[to] += vwgt[higain]; + where[higain] = to; + swaps[nswaps] = higain; + + + /********************************************************** + * Update the degrees of the affected nodes + ***********************************************************/ + for (j=xadj[higain]; j<xadj[higain+1]; j++) { + k = adjncy[j]; + if (where[k] == 2) { /* For the in-separator vertices modify their edegree[to] */ + rinfo[k].edegrees[to] += vwgt[higain]; + } + else if (where[k] == other) { /* This vertex is pulled into the separator */ + ASSERTP(bndptr[k] == -1, ("%d %d %d\n", k, bndptr[k], where[k])); + BNDInsert(nbnd, bndind, bndptr, k); + + mind[nmind++] = k; /* Keep track for rollback */ + where[k] = 2; + pwgts[other] -= vwgt[k]; + + edegrees = rinfo[k].edegrees; + edegrees[0] = edegrees[1] = 0; + for (jj=xadj[k]; jj<xadj[k+1]; jj++) { + kk = adjncy[jj]; + if (where[kk] != 2) + edegrees[where[kk]] += vwgt[kk]; + else { + oldgain = vwgt[kk]-rinfo[kk].edegrees[other]; + rinfo[kk].edegrees[other] -= vwgt[k]; + + /* Since the moves are one-sided this vertex has not been moved yet */ + PQueueUpdateUp(&parts, kk, oldgain, oldgain+vwgt[k]); + } + } + + /* Insert the new vertex into the priority queue. Safe due to one-sided moves */ + PQueueInsert(&parts, k, vwgt[k]-edegrees[other]); + } + } + mptr[nswaps+1] = nmind; + + + IFSET(ctrl->dbglvl, DBG_MOVEINFO, + printf("Moved %6d to %3d, Gain: %5d [%5d] \t[%5d %5d %5d] [%3d %2d]\n", + higain, to, (vwgt[higain]-rinfo[higain].edegrees[other]), vwgt[higain], pwgts[0], pwgts[1], pwgts[2], nswaps, limit)); + + } + + + /**************************************************************** + * Roll back computation + *****************************************************************/ + for (nswaps--; nswaps>mincutorder; nswaps--) { + higain = swaps[nswaps]; + + ASSERT(CheckNodePartitionParams(graph)); + ASSERT(where[higain] == to); + + INC_DEC(pwgts[2], pwgts[to], vwgt[higain]); + where[higain] = 2; + BNDInsert(nbnd, bndind, bndptr, higain); + + edegrees = rinfo[higain].edegrees; + edegrees[0] = edegrees[1] = 0; + for (j=xadj[higain]; j<xadj[higain+1]; j++) { + k = adjncy[j]; + if (where[k] == 2) + rinfo[k].edegrees[to] -= vwgt[higain]; + else + edegrees[where[k]] += vwgt[k]; + } + + /* Push nodes out of the separator */ + for (j=mptr[nswaps]; j<mptr[nswaps+1]; j++) { + k = mind[j]; + ASSERT(where[k] == 2); + where[k] = other; + INC_DEC(pwgts[other], pwgts[2], vwgt[k]); + BNDDelete(nbnd, bndind, bndptr, k); + for (jj=xadj[k]; jj<xadj[k+1]; jj++) { + kk = adjncy[jj]; + if (where[kk] == 2) + rinfo[kk].edegrees[other] += vwgt[k]; + } + } + } + + ASSERT(mincut == pwgts[2]); + + IFSET(ctrl->dbglvl, DBG_REFINE, + printf("\tMinimum sep: %6d at %5d, PWGTS: [%6d %6d], NBND: %6d\n", mincut, mincutorder, pwgts[0], pwgts[1], nbnd)); + + graph->mincut = mincut; + graph->nbnd = nbnd; + + if (pass%2 == 1 && (mincutorder == -1 || mincut >= initcut)) + break; + } + + PQueueFree(ctrl, &parts); + + idxwspacefree(ctrl, nvtxs+1); + idxwspacefree(ctrl, nvtxs); + idxwspacefree(ctrl, nvtxs); + idxwspacefree(ctrl, nvtxs); +} + + + +/************************************************************************* +* This function performs a node-based FM refinement +**************************************************************************/ +void FM_2WayNodeBalance(CtrlType *ctrl, GraphType *graph, float ubfactor) +{ + int i, ii, j, k, jj, kk, nvtxs, nbnd, nswaps; + idxtype *xadj, *vwgt, *adjncy, *where, *pwgts, *edegrees, *bndind, *bndptr; + idxtype *perm, *moved; + PQueueType parts; + NRInfoType *rinfo; + int higain, oldgain; + int pass, to, other; + + nvtxs = graph->nvtxs; + xadj = graph->xadj; + adjncy = graph->adjncy; + vwgt = graph->vwgt; + + bndind = graph->bndind; + bndptr = graph->bndptr; + where = graph->where; + pwgts = graph->pwgts; + rinfo = graph->nrinfo; + + if (abs(pwgts[0]-pwgts[1]) < (int)((ubfactor-1.0)*(pwgts[0]+pwgts[1]))) + return; + if (abs(pwgts[0]-pwgts[1]) < 3*idxsum(nvtxs, vwgt)/nvtxs) + return; + + to = (pwgts[0] < pwgts[1] ? 0 : 1); + other = (to+1)%2; + + PQueueInit(ctrl, &parts, nvtxs, ComputeMaxNodeGain(nvtxs, xadj, adjncy, vwgt)); + + perm = idxwspacemalloc(ctrl, nvtxs); + moved = idxset(nvtxs, -1, idxwspacemalloc(ctrl, nvtxs)); + + IFSET(ctrl->dbglvl, DBG_REFINE, + printf("Partitions: [%6d %6d] Nv-Nb[%6d %6d]. ISep: %6d [B]\n", pwgts[0], pwgts[1], graph->nvtxs, graph->nbnd, graph->mincut)); + + nbnd = graph->nbnd; + RandomPermute(nbnd, perm, 1); + for (ii=0; ii<nbnd; ii++) { + i = bndind[perm[ii]]; + ASSERT(where[i] == 2); + PQueueInsert(&parts, i, vwgt[i]-rinfo[i].edegrees[other]); + } + + ASSERT(CheckNodeBnd(graph, nbnd)); + ASSERT(CheckNodePartitionParams(graph)); + + /****************************************************** + * Get into the FM loop + *******************************************************/ + for (nswaps=0; nswaps<nvtxs; nswaps++) { + if ((higain = PQueueGetMax(&parts)) == -1) + break; + + moved[higain] = 1; + + if (pwgts[other] - rinfo[higain].edegrees[other] < (pwgts[0]+pwgts[1])/2) + continue; +#ifdef XXX + if (pwgts[other] - rinfo[higain].edegrees[other] < pwgts[to]+vwgt[higain]) + break; +#endif + + ASSERT(bndptr[higain] != -1); + + pwgts[2] -= (vwgt[higain]-rinfo[higain].edegrees[other]); + + BNDDelete(nbnd, bndind, bndptr, higain); + pwgts[to] += vwgt[higain]; + where[higain] = to; + + IFSET(ctrl->dbglvl, DBG_MOVEINFO, + printf("Moved %6d to %3d, Gain: %3d, \t[%5d %5d %5d]\n", higain, to, vwgt[higain]-rinfo[higain].edegrees[other], pwgts[0], pwgts[1], pwgts[2])); + + + /********************************************************** + * Update the degrees of the affected nodes + ***********************************************************/ + for (j=xadj[higain]; j<xadj[higain+1]; j++) { + k = adjncy[j]; + if (where[k] == 2) { /* For the in-separator vertices modify their edegree[to] */ + rinfo[k].edegrees[to] += vwgt[higain]; + } + else if (where[k] == other) { /* This vertex is pulled into the separator */ + ASSERTP(bndptr[k] == -1, ("%d %d %d\n", k, bndptr[k], where[k])); + BNDInsert(nbnd, bndind, bndptr, k); + + where[k] = 2; + pwgts[other] -= vwgt[k]; + + edegrees = rinfo[k].edegrees; + edegrees[0] = edegrees[1] = 0; + for (jj=xadj[k]; jj<xadj[k+1]; jj++) { + kk = adjncy[jj]; + if (where[kk] != 2) + edegrees[where[kk]] += vwgt[kk]; + else { + ASSERT(bndptr[kk] != -1); + oldgain = vwgt[kk]-rinfo[kk].edegrees[other]; + rinfo[kk].edegrees[other] -= vwgt[k]; + + if (moved[kk] == -1) + PQueueUpdateUp(&parts, kk, oldgain, oldgain+vwgt[k]); + } + } + + /* Insert the new vertex into the priority queue */ + PQueueInsert(&parts, k, vwgt[k]-edegrees[other]); + } + } + + if (pwgts[to] > pwgts[other]) + break; + } + + IFSET(ctrl->dbglvl, DBG_REFINE, + printf("\tBalanced sep: %6d at %4d, PWGTS: [%6d %6d], NBND: %6d\n", pwgts[2], nswaps, pwgts[0], pwgts[1], nbnd)); + + graph->mincut = pwgts[2]; + graph->nbnd = nbnd; + + + PQueueFree(ctrl, &parts); + + idxwspacefree(ctrl, nvtxs); + idxwspacefree(ctrl, nvtxs); +} + + +/************************************************************************* +* This function computes the maximum possible gain for a vertex +**************************************************************************/ +int ComputeMaxNodeGain(int nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt) +{ + int i, j, k, max; + + max = 0; + for (j=xadj[0]; j<xadj[1]; j++) + max += vwgt[adjncy[j]]; + + for (i=1; i<nvtxs; i++) { + for (k=0, j=xadj[i]; j<xadj[i+1]; j++) + k += vwgt[adjncy[j]]; + if (max < k) + max = k; + } + + return max; +} + + diff --git a/contrib/Metis/srefine.c b/contrib/Metis/srefine.c new file mode 100644 index 0000000000..f0d4584181 --- /dev/null +++ b/contrib/Metis/srefine.c @@ -0,0 +1,169 @@ +/* + * Copyright 1997, Regents of the University of Minnesota + * + * srefine.c + * + * This file contains code for the separator refinement algortihms + * + * Started 8/1/97 + * George + * + * $Id: srefine.c,v 1.1 2005-09-21 17:29:38 geuzaine Exp $ + * + */ + +#include <metis.h> + + +/************************************************************************* +* This function is the entry point of the separator refinement +**************************************************************************/ +void Refine2WayNode(CtrlType *ctrl, GraphType *orggraph, GraphType *graph, float ubfactor) +{ + + IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->UncoarsenTmr)); + + for (;;) { + IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->RefTmr)); + if (ctrl->RType != 15) + FM_2WayNodeBalance(ctrl, graph, ubfactor); + + switch (ctrl->RType) { + case 1: + FM_2WayNodeRefine(ctrl, graph, ubfactor, 8); + break; + case 2: + FM_2WayNodeRefine_OneSided(ctrl, graph, ubfactor, 8); + break; + case 3: + FM_2WayNodeRefine(ctrl, graph, ubfactor, 8); + FM_2WayNodeRefine_OneSided(ctrl, graph, ubfactor, 8); + break; + case 4: + FM_2WayNodeRefine_OneSided(ctrl, graph, ubfactor, 8); + FM_2WayNodeRefine(ctrl, graph, ubfactor, 8); + break; + case 5: + FM_2WayNodeRefineEqWgt(ctrl, graph, 8); + break; + } + IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->RefTmr)); + + if (graph == orggraph) + break; + + graph = graph->finer; + IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->ProjectTmr)); + Project2WayNodePartition(ctrl, graph); + IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->ProjectTmr)); + } + + IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->UncoarsenTmr)); +} + + +/************************************************************************* +* This function allocates memory for 2-way edge refinement +**************************************************************************/ +void Allocate2WayNodePartitionMemory(CtrlType *ctrl, GraphType *graph) +{ + int nvtxs, pad64; + + nvtxs = graph->nvtxs; + + pad64 = (3*nvtxs+3)%2; + + graph->rdata = idxmalloc(3*nvtxs+3+(sizeof(NRInfoType)/sizeof(idxtype))*nvtxs+pad64, "Allocate2WayPartitionMemory: rdata"); + graph->pwgts = graph->rdata; + graph->where = graph->rdata + 3; + graph->bndptr = graph->rdata + nvtxs + 3; + graph->bndind = graph->rdata + 2*nvtxs + 3; + graph->nrinfo = (NRInfoType *)(graph->rdata + 3*nvtxs + 3 + pad64); +} + + + +/************************************************************************* +* This function computes the initial id/ed +**************************************************************************/ +void Compute2WayNodePartitionParams(CtrlType *ctrl, GraphType *graph) +{ + int i, j, k, l, nvtxs, nbnd; + idxtype *xadj, *adjncy, *adjwgt, *vwgt; + idxtype *where, *pwgts, *bndind, *bndptr, *edegrees; + NRInfoType *rinfo; + int me, other; + + nvtxs = graph->nvtxs; + xadj = graph->xadj; + vwgt = graph->vwgt; + adjncy = graph->adjncy; + adjwgt = graph->adjwgt; + + where = graph->where; + rinfo = graph->nrinfo; + pwgts = idxset(3, 0, graph->pwgts); + bndind = graph->bndind; + bndptr = idxset(nvtxs, -1, graph->bndptr); + + + /*------------------------------------------------------------ + / Compute now the separator external degrees + /------------------------------------------------------------*/ + nbnd = 0; + for (i=0; i<nvtxs; i++) { + me = where[i]; + pwgts[me] += vwgt[i]; + + ASSERT(me >=0 && me <= 2); + + if (me == 2) { /* If it is on the separator do some computations */ + BNDInsert(nbnd, bndind, bndptr, i); + + edegrees = rinfo[i].edegrees; + edegrees[0] = edegrees[1] = 0; + + for (j=xadj[i]; j<xadj[i+1]; j++) { + other = where[adjncy[j]]; + if (other != 2) + edegrees[other] += vwgt[adjncy[j]]; + } + } + } + + ASSERT(CheckNodeBnd(graph, nbnd)); + + graph->mincut = pwgts[2]; + graph->nbnd = nbnd; +} + + +/************************************************************************* +* This function computes the initial id/ed +**************************************************************************/ +void Project2WayNodePartition(CtrlType *ctrl, GraphType *graph) +{ + int i, j, nvtxs; + idxtype *cmap, *where, *cwhere; + GraphType *cgraph; + + cgraph = graph->coarser; + cwhere = cgraph->where; + + nvtxs = graph->nvtxs; + cmap = graph->cmap; + + Allocate2WayNodePartitionMemory(ctrl, graph); + where = graph->where; + + /* Project the partition */ + for (i=0; i<nvtxs; i++) { + where[i] = cwhere[cmap[i]]; + ASSERTP(where[i] >= 0 && where[i] <= 2, ("%d %d %d %d\n", i, cmap[i], where[i], cwhere[cmap[i]])); + } + + FreeGraph(graph->coarser); + graph->coarser = NULL; + + Compute2WayNodePartitionParams(ctrl, graph); +} diff --git a/contrib/Metis/stat.c b/contrib/Metis/stat.c new file mode 100644 index 0000000000..fdce921b4a --- /dev/null +++ b/contrib/Metis/stat.c @@ -0,0 +1,287 @@ +/* + * Copyright 1997, Regents of the University of Minnesota + * + * stat.c + * + * This file computes various statistics + * + * Started 7/25/97 + * George + * + * $Id: stat.c,v 1.1 2005-09-21 17:29:38 geuzaine Exp $ + * + */ + +#include <metis.h> + + +/************************************************************************* +* This function computes cuts and balance information +**************************************************************************/ +void ComputePartitionInfo(GraphType *graph, int nparts, idxtype *where) +{ + int i, j, k, nvtxs, ncon, mustfree=0; + idxtype *xadj, *adjncy, *vwgt, *adjwgt, *kpwgts, *tmpptr; + idxtype *padjncy, *padjwgt, *padjcut; + + nvtxs = graph->nvtxs; + ncon = graph->ncon; + xadj = graph->xadj; + adjncy = graph->adjncy; + vwgt = graph->vwgt; + adjwgt = graph->adjwgt; + + if (vwgt == NULL) { + vwgt = graph->vwgt = idxsmalloc(nvtxs, 1, "vwgt"); + mustfree = 1; + } + if (adjwgt == NULL) { + adjwgt = graph->adjwgt = idxsmalloc(xadj[nvtxs], 1, "adjwgt"); + mustfree += 2; + } + + printf("%d-way Cut: %5d, Vol: %5d, ", nparts, ComputeCut(graph, where), ComputeVolume(graph, where)); + + /* Compute balance information */ + kpwgts = idxsmalloc(ncon*nparts, 0, "ComputePartitionInfo: kpwgts"); + + for (i=0; i<nvtxs; i++) { + for (j=0; j<ncon; j++) + kpwgts[where[i]*ncon+j] += vwgt[i*ncon+j]; + } + + if (ncon == 1) { + printf("\tBalance: %5.3f out of %5.3f\n", + 1.0*nparts*kpwgts[idxamax(nparts, kpwgts)]/(1.0*idxsum(nparts, kpwgts)), + 1.0*nparts*vwgt[idxamax(nvtxs, vwgt)]/(1.0*idxsum(nparts, kpwgts))); + } + else { + printf("\tBalance:"); + for (j=0; j<ncon; j++) + printf(" (%5.3f out of %5.3f)", + 1.0*nparts*kpwgts[ncon*idxamax_strd(nparts, kpwgts+j, ncon)+j]/(1.0*idxsum_strd(nparts, kpwgts+j, ncon)), + 1.0*nparts*vwgt[ncon*idxamax_strd(nvtxs, vwgt+j, ncon)+j]/(1.0*idxsum_strd(nparts, kpwgts+j, ncon))); + printf("\n"); + } + + + /* Compute p-adjncy information */ + padjncy = idxsmalloc(nparts*nparts, 0, "ComputePartitionInfo: padjncy"); + padjwgt = idxsmalloc(nparts*nparts, 0, "ComputePartitionInfo: padjwgt"); + padjcut = idxsmalloc(nparts*nparts, 0, "ComputePartitionInfo: padjwgt"); + + idxset(nparts, 0, kpwgts); + for (i=0; i<nvtxs; i++) { + for (j=xadj[i]; j<xadj[i+1]; j++) { + if (where[i] != where[adjncy[j]]) { + padjncy[where[i]*nparts+where[adjncy[j]]] = 1; + padjcut[where[i]*nparts+where[adjncy[j]]] += adjwgt[j]; + if (kpwgts[where[adjncy[j]]] == 0) { + padjwgt[where[i]*nparts+where[adjncy[j]]]++; + kpwgts[where[adjncy[j]]] = 1; + } + } + } + for (j=xadj[i]; j<xadj[i+1]; j++) + kpwgts[where[adjncy[j]]] = 0; + } + + for (i=0; i<nparts; i++) + kpwgts[i] = idxsum(nparts, padjncy+i*nparts); + printf("Min/Max/Avg/Bal # of adjacent subdomains: %5d %5d %5.2f %7.3f\n", + kpwgts[idxamin(nparts, kpwgts)], kpwgts[idxamax(nparts, kpwgts)], + 1.0*idxsum(nparts, kpwgts)/(1.0*nparts), + 1.0*nparts*kpwgts[idxamax(nparts, kpwgts)]/(1.0*idxsum(nparts, kpwgts))); + + for (i=0; i<nparts; i++) + kpwgts[i] = idxsum(nparts, padjcut+i*nparts); + printf("Min/Max/Avg/Bal # of adjacent subdomain cuts: %5d %5d %5d %7.3f\n", + kpwgts[idxamin(nparts, kpwgts)], kpwgts[idxamax(nparts, kpwgts)], idxsum(nparts, kpwgts)/nparts, + 1.0*nparts*kpwgts[idxamax(nparts, kpwgts)]/(1.0*idxsum(nparts, kpwgts))); + + for (i=0; i<nparts; i++) + kpwgts[i] = idxsum(nparts, padjwgt+i*nparts); + printf("Min/Max/Avg/Bal/Frac # of interface nodes: %5d %5d %5d %7.3f %7.3f\n", + kpwgts[idxamin(nparts, kpwgts)], kpwgts[idxamax(nparts, kpwgts)], idxsum(nparts, kpwgts)/nparts, + 1.0*nparts*kpwgts[idxamax(nparts, kpwgts)]/(1.0*idxsum(nparts, kpwgts)), 1.0*idxsum(nparts, kpwgts)/(1.0*nvtxs)); + + tmpptr = graph->where; + graph->where = where; + for (i=0; i<nparts; i++) + IsConnectedSubdomain(NULL, graph, i, 1); + graph->where = tmpptr; + + if (mustfree == 1 || mustfree == 3) { + free(vwgt); + graph->vwgt = NULL; + } + if (mustfree == 2 || mustfree == 3) { + free(adjwgt); + graph->adjwgt = NULL; + } + + GKfree(&kpwgts, &padjncy, &padjwgt, &padjcut, LTERM); +} + + +/************************************************************************* +* This function computes cuts and balance information +**************************************************************************/ +void ComputePartitionInfoBipartite(GraphType *graph, int nparts, idxtype *where) +{ + int i, j, k, nvtxs, ncon, mustfree=0; + idxtype *xadj, *adjncy, *vwgt, *vsize, *adjwgt, *kpwgts, *tmpptr; + idxtype *padjncy, *padjwgt, *padjcut; + + nvtxs = graph->nvtxs; + ncon = graph->ncon; + xadj = graph->xadj; + adjncy = graph->adjncy; + vwgt = graph->vwgt; + vsize = graph->vsize; + adjwgt = graph->adjwgt; + + if (vwgt == NULL) { + vwgt = graph->vwgt = idxsmalloc(nvtxs, 1, "vwgt"); + mustfree = 1; + } + if (adjwgt == NULL) { + adjwgt = graph->adjwgt = idxsmalloc(xadj[nvtxs], 1, "adjwgt"); + mustfree += 2; + } + + printf("%d-way Cut: %5d, Vol: %5d, ", nparts, ComputeCut(graph, where), ComputeVolume(graph, where)); + + /* Compute balance information */ + kpwgts = idxsmalloc(ncon*nparts, 0, "ComputePartitionInfo: kpwgts"); + + for (i=0; i<nvtxs; i++) { + for (j=0; j<ncon; j++) + kpwgts[where[i]*ncon+j] += vwgt[i*ncon+j]; + } + + if (ncon == 1) { + printf("\tBalance: %5.3f out of %5.3f\n", + 1.0*nparts*kpwgts[idxamax(nparts, kpwgts)]/(1.0*idxsum(nparts, kpwgts)), + 1.0*nparts*vwgt[idxamax(nvtxs, vwgt)]/(1.0*idxsum(nparts, kpwgts))); + } + else { + printf("\tBalance:"); + for (j=0; j<ncon; j++) + printf(" (%5.3f out of %5.3f)", + 1.0*nparts*kpwgts[ncon*idxamax_strd(nparts, kpwgts+j, ncon)+j]/(1.0*idxsum_strd(nparts, kpwgts+j, ncon)), + 1.0*nparts*vwgt[ncon*idxamax_strd(nvtxs, vwgt+j, ncon)+j]/(1.0*idxsum_strd(nparts, kpwgts+j, ncon))); + printf("\n"); + } + + + /* Compute p-adjncy information */ + padjncy = idxsmalloc(nparts*nparts, 0, "ComputePartitionInfo: padjncy"); + padjwgt = idxsmalloc(nparts*nparts, 0, "ComputePartitionInfo: padjwgt"); + padjcut = idxsmalloc(nparts*nparts, 0, "ComputePartitionInfo: padjwgt"); + + idxset(nparts, 0, kpwgts); + for (i=0; i<nvtxs; i++) { + for (j=xadj[i]; j<xadj[i+1]; j++) { + if (where[i] != where[adjncy[j]]) { + padjncy[where[i]*nparts+where[adjncy[j]]] = 1; + padjcut[where[i]*nparts+where[adjncy[j]]] += adjwgt[j]; + if (kpwgts[where[adjncy[j]]] == 0) { + padjwgt[where[i]*nparts+where[adjncy[j]]] += vsize[i]; + kpwgts[where[adjncy[j]]] = 1; + } + } + } + for (j=xadj[i]; j<xadj[i+1]; j++) + kpwgts[where[adjncy[j]]] = 0; + } + + for (i=0; i<nparts; i++) + kpwgts[i] = idxsum(nparts, padjncy+i*nparts); + printf("Min/Max/Avg/Bal # of adjacent subdomains: %5d %5d %5d %7.3f\n", + kpwgts[idxamin(nparts, kpwgts)], kpwgts[idxamax(nparts, kpwgts)], idxsum(nparts, kpwgts)/nparts, + 1.0*nparts*kpwgts[idxamax(nparts, kpwgts)]/(1.0*idxsum(nparts, kpwgts))); + + for (i=0; i<nparts; i++) + kpwgts[i] = idxsum(nparts, padjcut+i*nparts); + printf("Min/Max/Avg/Bal # of adjacent subdomain cuts: %5d %5d %5d %7.3f\n", + kpwgts[idxamin(nparts, kpwgts)], kpwgts[idxamax(nparts, kpwgts)], idxsum(nparts, kpwgts)/nparts, + 1.0*nparts*kpwgts[idxamax(nparts, kpwgts)]/(1.0*idxsum(nparts, kpwgts))); + + for (i=0; i<nparts; i++) + kpwgts[i] = idxsum(nparts, padjwgt+i*nparts); + printf("Min/Max/Avg/Bal/Frac # of interface nodes: %5d %5d %5d %7.3f %7.3f\n", + kpwgts[idxamin(nparts, kpwgts)], kpwgts[idxamax(nparts, kpwgts)], idxsum(nparts, kpwgts)/nparts, + 1.0*nparts*kpwgts[idxamax(nparts, kpwgts)]/(1.0*idxsum(nparts, kpwgts)), 1.0*idxsum(nparts, kpwgts)/(1.0*nvtxs)); + + + if (mustfree == 1 || mustfree == 3) { + free(vwgt); + graph->vwgt = NULL; + } + if (mustfree == 2 || mustfree == 3) { + free(adjwgt); + graph->adjwgt = NULL; + } + + GKfree(&kpwgts, &padjncy, &padjwgt, &padjcut, LTERM); +} + + + +/************************************************************************* +* This function computes the balance of the partitioning +**************************************************************************/ +void ComputePartitionBalance(GraphType *graph, int nparts, idxtype *where, float *ubvec) +{ + int i, j, nvtxs, ncon; + idxtype *kpwgts, *vwgt; + float balance; + + nvtxs = graph->nvtxs; + ncon = graph->ncon; + vwgt = graph->vwgt; + + kpwgts = idxsmalloc(nparts, 0, "ComputePartitionInfo: kpwgts"); + + if (vwgt == NULL) { + for (i=0; i<nvtxs; i++) + kpwgts[where[i]]++; + ubvec[0] = 1.0*nparts*kpwgts[idxamax(nparts, kpwgts)]/(1.0*nvtxs); + } + else { + for (j=0; j<ncon; j++) { + idxset(nparts, 0, kpwgts); + for (i=0; i<graph->nvtxs; i++) + kpwgts[where[i]] += vwgt[i*ncon+j]; + + ubvec[j] = 1.0*nparts*kpwgts[idxamax(nparts, kpwgts)]/(1.0*idxsum(nparts, kpwgts)); + } + } + + free(kpwgts); + +} + + +/************************************************************************* +* This function computes the balance of the element partitioning +**************************************************************************/ +float ComputeElementBalance(int ne, int nparts, idxtype *where) +{ + int i; + idxtype *kpwgts; + float balance; + + kpwgts = idxsmalloc(nparts, 0, "ComputeElementBalance: kpwgts"); + + for (i=0; i<ne; i++) + kpwgts[where[i]]++; + + balance = 1.0*nparts*kpwgts[idxamax(nparts, kpwgts)]/(1.0*idxsum(nparts, kpwgts)); + + free(kpwgts); + + return balance; + +} diff --git a/contrib/Metis/struct.h b/contrib/Metis/struct.h new file mode 100644 index 0000000000..f565d31c65 --- /dev/null +++ b/contrib/Metis/struct.h @@ -0,0 +1,251 @@ +/* + * Copyright 1997, Regents of the University of Minnesota + * + * struct.h + * + * This file contains data structures for ILU routines. + * + * Started 9/26/95 + * George + * + * $Id: struct.h,v 1.1 2005-09-21 17:29:38 geuzaine Exp $ + */ + +/* Undefine the following #define in order to use short int as the idxtype */ +#define IDXTYPE_INT + +/* Indexes are as long as integers for now */ +#ifdef IDXTYPE_INT +typedef int idxtype; +#else +typedef short idxtype; +#endif + +#define MAXIDX (1<<8*sizeof(idxtype)-2) + + +/************************************************************************* +* The following data structure stores key-value pair +**************************************************************************/ +struct KeyValueType { + idxtype key; + idxtype val; +}; + +typedef struct KeyValueType KeyValueType; + + +/************************************************************************* +* The following data structure will hold a node of a doubly-linked list. +**************************************************************************/ +struct ListNodeType { + int id; /* The id value of the node */ + struct ListNodeType *prev, *next; /* It's a doubly-linked list */ +}; + +typedef struct ListNodeType ListNodeType; + + + +/************************************************************************* +* The following data structure is used to store the buckets for the +* refinment algorithms +**************************************************************************/ +struct PQueueType { + int type; /* The type of the representation used */ + int nnodes; + int maxnodes; + int mustfree; + + /* Linear array version of the data structures */ + int pgainspan, ngainspan; /* plus and negative gain span */ + int maxgain; + ListNodeType *nodes; + ListNodeType **buckets; + + /* Heap version of the data structure */ + KeyValueType *heap; + idxtype *locator; +}; + +typedef struct PQueueType PQueueType; + + +/************************************************************************* +* The following data structure stores an edge +**************************************************************************/ +struct edegreedef { + idxtype pid; + idxtype ed; +}; +typedef struct edegreedef EDegreeType; + + +/************************************************************************* +* The following data structure stores an edge for vol +**************************************************************************/ +struct vedegreedef { + idxtype pid; + idxtype ed, ned; + idxtype gv; +}; +typedef struct vedegreedef VEDegreeType; + + +/************************************************************************* +* This data structure holds various working space data +**************************************************************************/ +struct workspacedef { + idxtype *core; /* Where pairs, indices, and degrees are coming from */ + int maxcore, ccore; + + EDegreeType *edegrees; + VEDegreeType *vedegrees; + int cdegree; + + idxtype *auxcore; /* This points to the memory of the edegrees */ + + idxtype *pmat; /* An array of k^2 used for eliminating domain + connectivity in k-way refinement */ +}; + +typedef struct workspacedef WorkSpaceType; + + +/************************************************************************* +* The following data structure holds information on degrees for k-way +* partition +**************************************************************************/ +struct rinfodef { + int id, ed; /* ID/ED of nodes */ + int ndegrees; /* The number of different ext-degrees */ + EDegreeType *edegrees; /* List of edges */ +}; + +typedef struct rinfodef RInfoType; + + +/************************************************************************* +* The following data structure holds information on degrees for k-way +* vol-based partition +**************************************************************************/ +struct vrinfodef { + int id, ed, nid; /* ID/ED of nodes */ + int gv; /* IV/EV of nodes */ + int ndegrees; /* The number of different ext-degrees */ + VEDegreeType *edegrees; /* List of edges */ +}; + +typedef struct vrinfodef VRInfoType; + + +/************************************************************************* +* The following data structure holds information on degrees for k-way +* partition +**************************************************************************/ +struct nrinfodef { + idxtype edegrees[2]; +}; + +typedef struct nrinfodef NRInfoType; + + +/************************************************************************* +* This data structure holds the input graph +**************************************************************************/ +struct graphdef { + idxtype *gdata, *rdata; /* Memory pools for graph and refinement data. + This is where memory is allocated and used + the rest of the fields in this structure */ + + int nvtxs, nedges; /* The # of vertices and edges in the graph */ + idxtype *xadj; /* Pointers to the locally stored vertices */ + idxtype *vwgt; /* Vertex weights */ + idxtype *vsize; /* Vertex sizes for min-volume formulation */ + idxtype *adjncy; /* Array that stores the adjacency lists of nvtxs */ + idxtype *adjwgt; /* Array that stores the weights of the adjacency lists */ + + idxtype *adjwgtsum; /* The sum of the adjacency weight of each vertex */ + + idxtype *label; + + idxtype *cmap; + + /* Partition parameters */ + int mincut, minvol; + idxtype *where, *pwgts; + int nbnd; + idxtype *bndptr, *bndind; + + /* Bisection refinement parameters */ + idxtype *id, *ed; + + /* K-way refinement parameters */ + RInfoType *rinfo; + + /* K-way volume refinement parameters */ + VRInfoType *vrinfo; + + /* Node refinement information */ + NRInfoType *nrinfo; + + + /* Additional info needed by the MOC routines */ + int ncon; /* The # of constrains */ + float *nvwgt; /* Normalized vertex weights */ + float *npwgts; /* The normalized partition weights */ + + struct graphdef *coarser, *finer; +}; + +typedef struct graphdef GraphType; + + + +/************************************************************************* +* The following data type implements a timer +**************************************************************************/ +typedef double timer; + + +/************************************************************************* +* The following structure stores information used by Metis +**************************************************************************/ +struct controldef { + int CoarsenTo; /* The # of vertices in the coarsest graph */ + int dbglvl; /* Controls the debuging output of the program */ + int CType; /* The type of coarsening */ + int IType; /* The type of initial partitioning */ + int RType; /* The type of refinement */ + int maxvwgt; /* The maximum allowed weight for a vertex */ + float nmaxvwgt; /* The maximum allowed weight for a vertex for each constrain */ + int optype; /* Type of operation */ + int pfactor; /* .1*prunning factor */ + int nseps; /* The number of separators to be found during multiple bisections */ + int oflags; + + WorkSpaceType wspace; /* Work Space Informations */ + + /* Various Timers */ + timer TotalTmr, InitPartTmr, MatchTmr, ContractTmr, CoarsenTmr, UncoarsenTmr, + SepTmr, RefTmr, ProjectTmr, SplitTmr, AuxTmr1, AuxTmr2, AuxTmr3, AuxTmr4, AuxTmr5, AuxTmr6; + +}; + +typedef struct controldef CtrlType; + + +/************************************************************************* +* The following data structure stores max-partition weight info for +* Vertical MOC k-way refinement +**************************************************************************/ +struct vpwgtdef { + float max[2][MAXNCON]; + int imax[2][MAXNCON]; +}; + +typedef struct vpwgtdef VPInfoType; + + + + diff --git a/contrib/Metis/subdomains.c b/contrib/Metis/subdomains.c new file mode 100644 index 0000000000..ed3b4db4c3 --- /dev/null +++ b/contrib/Metis/subdomains.c @@ -0,0 +1,1295 @@ +/* + * Copyright 1997, Regents of the University of Minnesota + * + * subdomains.c + * + * This file contains functions that deal with prunning the number of + * adjacent subdomains in KMETIS + * + * Started 7/15/98 + * George + * + * $Id: subdomains.c,v 1.1 2005-09-21 17:29:38 geuzaine Exp $ + * + */ + +#include <metis.h> + + +/************************************************************************* +* This function performs k-way refinement +**************************************************************************/ +void Random_KWayEdgeRefineMConn(CtrlType *ctrl, GraphType *graph, int nparts, float *tpwgts, float ubfactor, int npasses, int ffactor) +{ + int i, ii, iii, j, jj, k, l, pass, nvtxs, nmoves, nbnd, tvwgt, myndegrees; + int from, me, to, oldcut, vwgt, gain; + int maxndoms, nadd; + idxtype *xadj, *adjncy, *adjwgt; + idxtype *where, *pwgts, *perm, *bndptr, *bndind, *minwgt, *maxwgt, *itpwgts; + idxtype *phtable, *pmat, *pmatptr, *ndoms; + EDegreeType *myedegrees; + RInfoType *myrinfo; + + nvtxs = graph->nvtxs; + xadj = graph->xadj; + adjncy = graph->adjncy; + adjwgt = graph->adjwgt; + + bndptr = graph->bndptr; + bndind = graph->bndind; + + where = graph->where; + pwgts = graph->pwgts; + + pmat = ctrl->wspace.pmat; + phtable = idxwspacemalloc(ctrl, nparts); + ndoms = idxwspacemalloc(ctrl, nparts); + + ComputeSubDomainGraph(graph, nparts, pmat, ndoms); + + /* Setup the weight intervals of the various subdomains */ + minwgt = idxwspacemalloc(ctrl, nparts); + maxwgt = idxwspacemalloc(ctrl, nparts); + itpwgts = idxwspacemalloc(ctrl, nparts); + tvwgt = idxsum(nparts, pwgts); + ASSERT(tvwgt == idxsum(nvtxs, graph->vwgt)); + + for (i=0; i<nparts; i++) { + itpwgts[i] = tpwgts[i]*tvwgt; + maxwgt[i] = tpwgts[i]*tvwgt*ubfactor; + minwgt[i] = tpwgts[i]*tvwgt*(1.0/ubfactor); + } + + perm = idxwspacemalloc(ctrl, nvtxs); + + IFSET(ctrl->dbglvl, DBG_REFINE, + printf("Partitions: [%6d %6d]-[%6d %6d], Balance: %5.3f, Nv-Nb[%6d %6d]. Cut: %6d\n", + pwgts[idxamin(nparts, pwgts)], pwgts[idxamax(nparts, pwgts)], minwgt[0], maxwgt[0], + 1.0*nparts*pwgts[idxamax(nparts, pwgts)]/tvwgt, graph->nvtxs, graph->nbnd, + graph->mincut)); + + for (pass=0; pass<npasses; pass++) { + ASSERT(ComputeCut(graph, where) == graph->mincut); + + maxndoms = ndoms[idxamax(nparts, ndoms)]; + + oldcut = graph->mincut; + nbnd = graph->nbnd; + + RandomPermute(nbnd, perm, 1); + for (nmoves=iii=0; iii<graph->nbnd; iii++) { + ii = perm[iii]; + if (ii >= nbnd) + continue; + i = bndind[ii]; + + myrinfo = graph->rinfo+i; + + if (myrinfo->ed >= myrinfo->id) { /* Total ED is too high */ + from = where[i]; + vwgt = graph->vwgt[i]; + + if (myrinfo->id > 0 && pwgts[from]-vwgt < minwgt[from]) + continue; /* This cannot be moved! */ + + myedegrees = myrinfo->edegrees; + myndegrees = myrinfo->ndegrees; + + /* Determine the valid domains */ + for (j=0; j<myndegrees; j++) { + to = myedegrees[j].pid; + phtable[to] = 1; + pmatptr = pmat + to*nparts; + for (nadd=0, k=0; k<myndegrees; k++) { + if (k == j) + continue; + + l = myedegrees[k].pid; + if (pmatptr[l] == 0) { + if (ndoms[l] > maxndoms-1) { + phtable[to] = 0; + nadd = maxndoms; + break; + } + nadd++; + } + } + if (ndoms[to]+nadd > maxndoms) + phtable[to] = 0; + if (nadd == 0) + phtable[to] = 2; + } + + /* Find the first valid move */ + j = myrinfo->id; + for (k=0; k<myndegrees; k++) { + to = myedegrees[k].pid; + if (!phtable[to]) + continue; + gain = myedegrees[k].ed-j; /* j = myrinfo->id. Allow good nodes to move */ + if (pwgts[to]+vwgt <= maxwgt[to]+ffactor*gain && gain >= 0) + break; + } + if (k == myndegrees) + continue; /* break out if you did not find a candidate */ + + for (j=k+1; j<myndegrees; j++) { + to = myedegrees[j].pid; + if (!phtable[to]) + continue; + if ((myedegrees[j].ed > myedegrees[k].ed && pwgts[to]+vwgt <= maxwgt[to]) || + (myedegrees[j].ed == myedegrees[k].ed && + itpwgts[myedegrees[k].pid]*pwgts[to] < itpwgts[to]*pwgts[myedegrees[k].pid])) + k = j; + } + + to = myedegrees[k].pid; + + j = 0; + if (myedegrees[k].ed-myrinfo->id > 0) + j = 1; + else if (myedegrees[k].ed-myrinfo->id == 0) { + if (/*(iii&7) == 0 ||*/ phtable[myedegrees[k].pid] == 2 || pwgts[from] >= maxwgt[from] || itpwgts[from]*(pwgts[to]+vwgt) < itpwgts[to]*pwgts[from]) + j = 1; + } + if (j == 0) + continue; + + /*===================================================================== + * If we got here, we can now move the vertex from 'from' to 'to' + *======================================================================*/ + graph->mincut -= myedegrees[k].ed-myrinfo->id; + + IFSET(ctrl->dbglvl, DBG_MOVEINFO, printf("\t\tMoving %6d to %3d. Gain: %4d. Cut: %6d\n", i, to, myedegrees[k].ed-myrinfo->id, graph->mincut)); + + /* Update pmat to reflect the move of 'i' */ + pmat[from*nparts+to] += (myrinfo->id-myedegrees[k].ed); + pmat[to*nparts+from] += (myrinfo->id-myedegrees[k].ed); + if (pmat[from*nparts+to] == 0) { + ndoms[from]--; + if (ndoms[from]+1 == maxndoms) + maxndoms = ndoms[idxamax(nparts, ndoms)]; + } + if (pmat[to*nparts+from] == 0) { + ndoms[to]--; + if (ndoms[to]+1 == maxndoms) + maxndoms = ndoms[idxamax(nparts, ndoms)]; + } + + /* Update where, weight, and ID/ED information of the vertex you moved */ + where[i] = to; + INC_DEC(pwgts[to], pwgts[from], vwgt); + myrinfo->ed += myrinfo->id-myedegrees[k].ed; + SWAP(myrinfo->id, myedegrees[k].ed, j); + if (myedegrees[k].ed == 0) + myedegrees[k] = myedegrees[--myrinfo->ndegrees]; + else + myedegrees[k].pid = from; + + if (myrinfo->ed-myrinfo->id < 0) + BNDDelete(nbnd, bndind, bndptr, i); + + /* Update the degrees of adjacent vertices */ + for (j=xadj[i]; j<xadj[i+1]; j++) { + ii = adjncy[j]; + me = where[ii]; + + myrinfo = graph->rinfo+ii; + if (myrinfo->edegrees == NULL) { + myrinfo->edegrees = ctrl->wspace.edegrees+ctrl->wspace.cdegree; + ctrl->wspace.cdegree += xadj[ii+1]-xadj[ii]; + } + myedegrees = myrinfo->edegrees; + + ASSERT(CheckRInfo(myrinfo)); + + if (me == from) { + INC_DEC(myrinfo->ed, myrinfo->id, adjwgt[j]); + + if (myrinfo->ed-myrinfo->id >= 0 && bndptr[ii] == -1) + BNDInsert(nbnd, bndind, bndptr, ii); + } + else if (me == to) { + INC_DEC(myrinfo->id, myrinfo->ed, adjwgt[j]); + + if (myrinfo->ed-myrinfo->id < 0 && bndptr[ii] != -1) + BNDDelete(nbnd, bndind, bndptr, ii); + } + + /* Remove contribution from the .ed of 'from' */ + if (me != from) { + for (k=0; k<myrinfo->ndegrees; k++) { + if (myedegrees[k].pid == from) { + if (myedegrees[k].ed == adjwgt[j]) + myedegrees[k] = myedegrees[--myrinfo->ndegrees]; + else + myedegrees[k].ed -= adjwgt[j]; + break; + } + } + } + + /* Add contribution to the .ed of 'to' */ + if (me != to) { + for (k=0; k<myrinfo->ndegrees; k++) { + if (myedegrees[k].pid == to) { + myedegrees[k].ed += adjwgt[j]; + break; + } + } + if (k == myrinfo->ndegrees) { + myedegrees[myrinfo->ndegrees].pid = to; + myedegrees[myrinfo->ndegrees++].ed = adjwgt[j]; + } + } + + /* Update pmat to reflect the move of 'i' for domains other than 'from' and 'to' */ + if (me != from && me != to) { + pmat[me*nparts+from] -= adjwgt[j]; + pmat[from*nparts+me] -= adjwgt[j]; + if (pmat[me*nparts+from] == 0) { + ndoms[me]--; + if (ndoms[me]+1 == maxndoms) + maxndoms = ndoms[idxamax(nparts, ndoms)]; + } + if (pmat[from*nparts+me] == 0) { + ndoms[from]--; + if (ndoms[from]+1 == maxndoms) + maxndoms = ndoms[idxamax(nparts, ndoms)]; + } + + if (pmat[me*nparts+to] == 0) { + ndoms[me]++; + if (ndoms[me] > maxndoms) { + printf("You just increased the maxndoms: %d %d\n", ndoms[me], maxndoms); + maxndoms = ndoms[me]; + } + } + if (pmat[to*nparts+me] == 0) { + ndoms[to]++; + if (ndoms[to] > maxndoms) { + printf("You just increased the maxndoms: %d %d\n", ndoms[to], maxndoms); + maxndoms = ndoms[to]; + } + } + pmat[me*nparts+to] += adjwgt[j]; + pmat[to*nparts+me] += adjwgt[j]; + } + + ASSERT(myrinfo->ndegrees <= xadj[ii+1]-xadj[ii]); + ASSERT(CheckRInfo(myrinfo)); + + } + nmoves++; + } + } + + graph->nbnd = nbnd; + + IFSET(ctrl->dbglvl, DBG_REFINE, + printf("\t[%6d %6d], Balance: %5.3f, Nb: %6d. Nmoves: %5d, Cut: %5d, Vol: %5d, %d\n", + pwgts[idxamin(nparts, pwgts)], pwgts[idxamax(nparts, pwgts)], + 1.0*nparts*pwgts[idxamax(nparts, pwgts)]/tvwgt, graph->nbnd, nmoves, + graph->mincut, ComputeVolume(graph, where), idxsum(nparts, ndoms))); + + if (graph->mincut == oldcut) + break; + } + + idxwspacefree(ctrl, nparts); + idxwspacefree(ctrl, nparts); + idxwspacefree(ctrl, nparts); + idxwspacefree(ctrl, nparts); + idxwspacefree(ctrl, nparts); + idxwspacefree(ctrl, nvtxs); +} + + + +/************************************************************************* +* This function performs k-way refinement +**************************************************************************/ +void Greedy_KWayEdgeBalanceMConn(CtrlType *ctrl, GraphType *graph, int nparts, float *tpwgts, float ubfactor, int npasses) +{ + int i, ii, iii, j, jj, k, l, pass, nvtxs, nbnd, tvwgt, myndegrees, oldgain, gain, nmoves; + int from, me, to, oldcut, vwgt, maxndoms, nadd; + idxtype *xadj, *adjncy, *adjwgt; + idxtype *where, *pwgts, *perm, *bndptr, *bndind, *minwgt, *maxwgt, *moved, *itpwgts; + idxtype *phtable, *pmat, *pmatptr, *ndoms; + EDegreeType *myedegrees; + RInfoType *myrinfo; + PQueueType queue; + + nvtxs = graph->nvtxs; + xadj = graph->xadj; + adjncy = graph->adjncy; + adjwgt = graph->adjwgt; + + bndind = graph->bndind; + bndptr = graph->bndptr; + + where = graph->where; + pwgts = graph->pwgts; + + pmat = ctrl->wspace.pmat; + phtable = idxwspacemalloc(ctrl, nparts); + ndoms = idxwspacemalloc(ctrl, nparts); + + ComputeSubDomainGraph(graph, nparts, pmat, ndoms); + + + /* Setup the weight intervals of the various subdomains */ + minwgt = idxwspacemalloc(ctrl, nparts); + maxwgt = idxwspacemalloc(ctrl, nparts); + itpwgts = idxwspacemalloc(ctrl, nparts); + tvwgt = idxsum(nparts, pwgts); + ASSERT(tvwgt == idxsum(nvtxs, graph->vwgt)); + + for (i=0; i<nparts; i++) { + itpwgts[i] = tpwgts[i]*tvwgt; + maxwgt[i] = tpwgts[i]*tvwgt*ubfactor; + minwgt[i] = tpwgts[i]*tvwgt*(1.0/ubfactor); + } + + perm = idxwspacemalloc(ctrl, nvtxs); + moved = idxwspacemalloc(ctrl, nvtxs); + + PQueueInit(ctrl, &queue, nvtxs, graph->adjwgtsum[idxamax(nvtxs, graph->adjwgtsum)]); + + IFSET(ctrl->dbglvl, DBG_REFINE, + printf("Partitions: [%6d %6d]-[%6d %6d], Balance: %5.3f, Nv-Nb[%6d %6d]. Cut: %6d [B]\n", + pwgts[idxamin(nparts, pwgts)], pwgts[idxamax(nparts, pwgts)], minwgt[0], maxwgt[0], + 1.0*nparts*pwgts[idxamax(nparts, pwgts)]/tvwgt, graph->nvtxs, graph->nbnd, + graph->mincut)); + + for (pass=0; pass<npasses; pass++) { + ASSERT(ComputeCut(graph, where) == graph->mincut); + + /* Check to see if things are out of balance, given the tolerance */ + for (i=0; i<nparts; i++) { + if (pwgts[i] > maxwgt[i]) + break; + } + if (i == nparts) /* Things are balanced. Return right away */ + break; + + PQueueReset(&queue); + idxset(nvtxs, -1, moved); + + oldcut = graph->mincut; + nbnd = graph->nbnd; + + RandomPermute(nbnd, perm, 1); + for (ii=0; ii<nbnd; ii++) { + i = bndind[perm[ii]]; + PQueueInsert(&queue, i, graph->rinfo[i].ed - graph->rinfo[i].id); + moved[i] = 2; + } + + maxndoms = ndoms[idxamax(nparts, ndoms)]; + + for (nmoves=0;;) { + if ((i = PQueueGetMax(&queue)) == -1) + break; + moved[i] = 1; + + myrinfo = graph->rinfo+i; + from = where[i]; + vwgt = graph->vwgt[i]; + + if (pwgts[from]-vwgt < minwgt[from]) + continue; /* This cannot be moved! */ + + myedegrees = myrinfo->edegrees; + myndegrees = myrinfo->ndegrees; + + /* Determine the valid domains */ + for (j=0; j<myndegrees; j++) { + to = myedegrees[j].pid; + phtable[to] = 1; + pmatptr = pmat + to*nparts; + for (nadd=0, k=0; k<myndegrees; k++) { + if (k == j) + continue; + + l = myedegrees[k].pid; + if (pmatptr[l] == 0) { + if (ndoms[l] > maxndoms-1) { + phtable[to] = 0; + nadd = maxndoms; + break; + } + nadd++; + } + } + if (ndoms[to]+nadd > maxndoms) + phtable[to] = 0; + } + + for (k=0; k<myndegrees; k++) { + to = myedegrees[k].pid; + if (!phtable[to]) + continue; + if (pwgts[to]+vwgt <= maxwgt[to] || itpwgts[from]*(pwgts[to]+vwgt) <= itpwgts[to]*pwgts[from]) + break; + } + if (k == myndegrees) + continue; /* break out if you did not find a candidate */ + + for (j=k+1; j<myndegrees; j++) { + to = myedegrees[j].pid; + if (!phtable[to]) + continue; + if (itpwgts[myedegrees[k].pid]*pwgts[to] < itpwgts[to]*pwgts[myedegrees[k].pid]) + k = j; + } + + to = myedegrees[k].pid; + + if (pwgts[from] < maxwgt[from] && pwgts[to] > minwgt[to] && myedegrees[k].ed-myrinfo->id < 0) + continue; + + /*===================================================================== + * If we got here, we can now move the vertex from 'from' to 'to' + *======================================================================*/ + graph->mincut -= myedegrees[k].ed-myrinfo->id; + + IFSET(ctrl->dbglvl, DBG_MOVEINFO, printf("\t\tMoving %6d to %3d. Gain: %4d. Cut: %6d\n", i, to, myedegrees[k].ed-myrinfo->id, graph->mincut)); + + /* Update pmat to reflect the move of 'i' */ + pmat[from*nparts+to] += (myrinfo->id-myedegrees[k].ed); + pmat[to*nparts+from] += (myrinfo->id-myedegrees[k].ed); + if (pmat[from*nparts+to] == 0) { + ndoms[from]--; + if (ndoms[from]+1 == maxndoms) + maxndoms = ndoms[idxamax(nparts, ndoms)]; + } + if (pmat[to*nparts+from] == 0) { + ndoms[to]--; + if (ndoms[to]+1 == maxndoms) + maxndoms = ndoms[idxamax(nparts, ndoms)]; + } + + + /* Update where, weight, and ID/ED information of the vertex you moved */ + where[i] = to; + INC_DEC(pwgts[to], pwgts[from], vwgt); + myrinfo->ed += myrinfo->id-myedegrees[k].ed; + SWAP(myrinfo->id, myedegrees[k].ed, j); + if (myedegrees[k].ed == 0) + myedegrees[k] = myedegrees[--myrinfo->ndegrees]; + else + myedegrees[k].pid = from; + + if (myrinfo->ed == 0) + BNDDelete(nbnd, bndind, bndptr, i); + + /* Update the degrees of adjacent vertices */ + for (j=xadj[i]; j<xadj[i+1]; j++) { + ii = adjncy[j]; + me = where[ii]; + + myrinfo = graph->rinfo+ii; + if (myrinfo->edegrees == NULL) { + myrinfo->edegrees = ctrl->wspace.edegrees+ctrl->wspace.cdegree; + ctrl->wspace.cdegree += xadj[ii+1]-xadj[ii]; + } + myedegrees = myrinfo->edegrees; + + ASSERT(CheckRInfo(myrinfo)); + + oldgain = (myrinfo->ed-myrinfo->id); + + if (me == from) { + INC_DEC(myrinfo->ed, myrinfo->id, adjwgt[j]); + + if (myrinfo->ed > 0 && bndptr[ii] == -1) + BNDInsert(nbnd, bndind, bndptr, ii); + } + else if (me == to) { + INC_DEC(myrinfo->id, myrinfo->ed, adjwgt[j]); + + if (myrinfo->ed == 0 && bndptr[ii] != -1) + BNDDelete(nbnd, bndind, bndptr, ii); + } + + /* Remove contribution from the .ed of 'from' */ + if (me != from) { + for (k=0; k<myrinfo->ndegrees; k++) { + if (myedegrees[k].pid == from) { + if (myedegrees[k].ed == adjwgt[j]) + myedegrees[k] = myedegrees[--myrinfo->ndegrees]; + else + myedegrees[k].ed -= adjwgt[j]; + break; + } + } + } + + /* Add contribution to the .ed of 'to' */ + if (me != to) { + for (k=0; k<myrinfo->ndegrees; k++) { + if (myedegrees[k].pid == to) { + myedegrees[k].ed += adjwgt[j]; + break; + } + } + if (k == myrinfo->ndegrees) { + myedegrees[myrinfo->ndegrees].pid = to; + myedegrees[myrinfo->ndegrees++].ed = adjwgt[j]; + } + } + + /* Update pmat to reflect the move of 'i' for domains other than 'from' and 'to' */ + if (me != from && me != to) { + pmat[me*nparts+from] -= adjwgt[j]; + pmat[from*nparts+me] -= adjwgt[j]; + if (pmat[me*nparts+from] == 0) { + ndoms[me]--; + if (ndoms[me]+1 == maxndoms) + maxndoms = ndoms[idxamax(nparts, ndoms)]; + } + if (pmat[from*nparts+me] == 0) { + ndoms[from]--; + if (ndoms[from]+1 == maxndoms) + maxndoms = ndoms[idxamax(nparts, ndoms)]; + } + + if (pmat[me*nparts+to] == 0) { + ndoms[me]++; + if (ndoms[me] > maxndoms) { + printf("You just increased the maxndoms: %d %d\n", ndoms[me], maxndoms); + maxndoms = ndoms[me]; + } + } + if (pmat[to*nparts+me] == 0) { + ndoms[to]++; + if (ndoms[to] > maxndoms) { + printf("You just increased the maxndoms: %d %d\n", ndoms[to], maxndoms); + maxndoms = ndoms[to]; + } + } + pmat[me*nparts+to] += adjwgt[j]; + pmat[to*nparts+me] += adjwgt[j]; + } + + /* Update the queue */ + if (me == to || me == from) { + gain = myrinfo->ed-myrinfo->id; + if (moved[ii] == 2) { + if (myrinfo->ed > 0) + PQueueUpdate(&queue, ii, oldgain, gain); + else { + PQueueDelete(&queue, ii, oldgain); + moved[ii] = -1; + } + } + else if (moved[ii] == -1 && myrinfo->ed > 0) { + PQueueInsert(&queue, ii, gain); + moved[ii] = 2; + } + } + + ASSERT(myrinfo->ndegrees <= xadj[ii+1]-xadj[ii]); + ASSERT(CheckRInfo(myrinfo)); + } + nmoves++; + } + + graph->nbnd = nbnd; + + IFSET(ctrl->dbglvl, DBG_REFINE, + printf("\t[%6d %6d], Balance: %5.3f, Nb: %6d. Nmoves: %5d, Cut: %6d, %d\n", + pwgts[idxamin(nparts, pwgts)], pwgts[idxamax(nparts, pwgts)], + 1.0*nparts*pwgts[idxamax(nparts, pwgts)]/tvwgt, graph->nbnd, nmoves, graph->mincut,idxsum(nparts, ndoms))); + } + + PQueueFree(ctrl, &queue); + + idxwspacefree(ctrl, nparts); + idxwspacefree(ctrl, nparts); + idxwspacefree(ctrl, nparts); + idxwspacefree(ctrl, nparts); + idxwspacefree(ctrl, nparts); + idxwspacefree(ctrl, nvtxs); + idxwspacefree(ctrl, nvtxs); + +} + + + + +/************************************************************************* +* This function computes the subdomain graph +**************************************************************************/ +void PrintSubDomainGraph(GraphType *graph, int nparts, idxtype *where) +{ + int i, j, k, me, nvtxs, total, max; + idxtype *xadj, *adjncy, *adjwgt, *pmat; + + nvtxs = graph->nvtxs; + xadj = graph->xadj; + adjncy = graph->adjncy; + adjwgt = graph->adjwgt; + + pmat = idxsmalloc(nparts*nparts, 0, "ComputeSubDomainGraph: pmat"); + + for (i=0; i<nvtxs; i++) { + me = where[i]; + for (j=xadj[i]; j<xadj[i+1]; j++) { + k = adjncy[j]; + if (where[k] != me) + pmat[me*nparts+where[k]] += adjwgt[j]; + } + } + + /* printf("Subdomain Info\n"); */ + total = max = 0; + for (i=0; i<nparts; i++) { + for (k=0, j=0; j<nparts; j++) { + if (pmat[i*nparts+j] > 0) + k++; + } + total += k; + + if (k > max) + max = k; +/* + printf("%2d -> %2d ", i, k); + for (j=0; j<nparts; j++) { + if (pmat[i*nparts+j] > 0) + printf("[%2d %4d] ", j, pmat[i*nparts+j]); + } + printf("\n"); +*/ + } + printf("Total adjacent subdomains: %d, Max: %d\n", total, max); + + free(pmat); +} + + + +/************************************************************************* +* This function computes the subdomain graph +**************************************************************************/ +void ComputeSubDomainGraph(GraphType *graph, int nparts, idxtype *pmat, idxtype *ndoms) +{ + int i, j, k, me, nvtxs, ndegrees; + idxtype *xadj, *adjncy, *adjwgt, *where; + RInfoType *rinfo; + EDegreeType *edegrees; + + nvtxs = graph->nvtxs; + xadj = graph->xadj; + adjncy = graph->adjncy; + adjwgt = graph->adjwgt; + where = graph->where; + rinfo = graph->rinfo; + + idxset(nparts*nparts, 0, pmat); + + for (i=0; i<nvtxs; i++) { + if (rinfo[i].ed > 0) { + me = where[i]; + ndegrees = rinfo[i].ndegrees; + edegrees = rinfo[i].edegrees; + + k = me*nparts; + for (j=0; j<ndegrees; j++) + pmat[k+edegrees[j].pid] += edegrees[j].ed; + } + } + + for (i=0; i<nparts; i++) { + ndoms[i] = 0; + for (j=0; j<nparts; j++) { + if (pmat[i*nparts+j] > 0) + ndoms[i]++; + } + } + +} + + + + + +/************************************************************************* +* This function computes the subdomain graph +**************************************************************************/ +void EliminateSubDomainEdges(CtrlType *ctrl, GraphType *graph, int nparts, float *tpwgts) +{ + int i, ii, j, k, me, other, nvtxs, total, max, avg, totalout, nind, ncand, ncand2, target, target2, nadd; + int min, move, cpwgt, tvwgt; + idxtype *xadj, *adjncy, *vwgt, *adjwgt, *pwgts, *where, *maxpwgt, *pmat, *ndoms, *mypmat, *otherpmat, *ind; + KeyValueType *cand, *cand2; + + nvtxs = graph->nvtxs; + xadj = graph->xadj; + adjncy = graph->adjncy; + vwgt = graph->vwgt; + adjwgt = graph->adjwgt; + + where = graph->where; + pwgts = graph->pwgts; /* We assume that this is properly initialized */ + + maxpwgt = idxwspacemalloc(ctrl, nparts); + ndoms = idxwspacemalloc(ctrl, nparts); + otherpmat = idxwspacemalloc(ctrl, nparts); + ind = idxwspacemalloc(ctrl, nvtxs); + pmat = ctrl->wspace.pmat; + + cand = (KeyValueType *)GKmalloc(nparts*sizeof(KeyValueType), "EliminateSubDomainEdges: cand"); + cand2 = (KeyValueType *)GKmalloc(nparts*sizeof(KeyValueType), "EliminateSubDomainEdges: cand"); + + /* Compute the pmat matrix and ndoms */ + ComputeSubDomainGraph(graph, nparts, pmat, ndoms); + + + /* Compute the maximum allowed weight for each domain */ + tvwgt = idxsum(nparts, pwgts); + for (i=0; i<nparts; i++) + maxpwgt[i] = 1.25*tpwgts[i]*tvwgt; + + + /* Get into the loop eliminating subdomain connections */ + for (;;) { + total = idxsum(nparts, ndoms); + avg = total/nparts; + max = ndoms[idxamax(nparts, ndoms)]; + + /* printf("Adjacent Subdomain Stats: Total: %3d, Max: %3d, Avg: %3d [%5d]\n", total, max, avg, idxsum(nparts*nparts, pmat)); */ + + if (max < 1.4*avg) + break; + + me = idxamax(nparts, ndoms); + mypmat = pmat + me*nparts; + totalout = idxsum(nparts, mypmat); + + /*printf("Me: %d, TotalOut: %d,\n", me, totalout);*/ + + /* Sort the connections according to their cut */ + for (ncand2=0, i=0; i<nparts; i++) { + if (mypmat[i] > 0) { + cand2[ncand2].key = mypmat[i]; + cand2[ncand2++].val = i; + } + } + ikeysort(ncand2, cand2); + + move = 0; + for (min=0; min<ncand2; min++) { + if (cand2[min].key > totalout/(2*ndoms[me])) + break; + + other = cand2[min].val; + + /*printf("\tMinOut: %d to %d\n", mypmat[other], other);*/ + + idxset(nparts, 0, otherpmat); + + /* Go and find the vertices in 'other' that are connected in 'me' */ + for (nind=0, i=0; i<nvtxs; i++) { + if (where[i] == other) { + for (j=xadj[i]; j<xadj[i+1]; j++) { + if (where[adjncy[j]] == me) { + ind[nind++] = i; + break; + } + } + } + } + + /* Go and construct the otherpmat to see where these nind vertices are connected to */ + for (cpwgt=0, ii=0; ii<nind; ii++) { + i = ind[ii]; + cpwgt += vwgt[i]; + + for (j=xadj[i]; j<xadj[i+1]; j++) + otherpmat[where[adjncy[j]]] += adjwgt[j]; + } + otherpmat[other] = 0; + + for (ncand=0, i=0; i<nparts; i++) { + if (otherpmat[i] > 0) { + cand[ncand].key = -otherpmat[i]; + cand[ncand++].val = i; + } + } + ikeysort(ncand, cand); + + /* + * Go through and the select the first domain that is common with 'me', and + * does not increase the ndoms[target] higher than my ndoms, subject to the + * maxpwgt constraint. Traversal is done from the mostly connected to the least. + */ + target = target2 = -1; + for (i=0; i<ncand; i++) { + k = cand[i].val; + + if (mypmat[k] > 0) { + if (pwgts[k] + cpwgt > maxpwgt[k]) /* Check if balance will go off */ + continue; + + for (j=0; j<nparts; j++) { + if (otherpmat[j] > 0 && ndoms[j] >= ndoms[me]-1 && pmat[nparts*j+k] == 0) + break; + } + if (j == nparts) { /* No bad second level effects */ + for (nadd=0, j=0; j<nparts; j++) { + if (otherpmat[j] > 0 && pmat[nparts*k+j] == 0) + nadd++; + } + + /*printf("\t\tto=%d, nadd=%d, %d\n", k, nadd, ndoms[k]);*/ + if (target2 == -1 && ndoms[k]+nadd < ndoms[me]) { + target2 = k; + } + if (nadd == 0) { + target = k; + break; + } + } + } + } + if (target == -1 && target2 != -1) + target = target2; + + if (target == -1) { + /* printf("\t\tCould not make the move\n");*/ + continue; + } + + /*printf("\t\tMoving to %d\n", target);*/ + + /* Update the partition weights */ + INC_DEC(pwgts[target], pwgts[other], cpwgt); + + MoveGroupMConn(ctrl, graph, ndoms, pmat, nparts, target, nind, ind); + + move = 1; + break; + } + + if (move == 0) + break; + } + + idxwspacefree(ctrl, nparts); + idxwspacefree(ctrl, nparts); + idxwspacefree(ctrl, nparts); + idxwspacefree(ctrl, nvtxs); + + GKfree(&cand, &cand2, LTERM); +} + + +/************************************************************************* +* This function moves a collection of vertices and updates their rinfo +**************************************************************************/ +void MoveGroupMConn(CtrlType *ctrl, GraphType *graph, idxtype *ndoms, idxtype *pmat, + int nparts, int to, int nind, idxtype *ind) +{ + int i, ii, iii, j, jj, k, l, nvtxs, nbnd, myndegrees; + int from, me; + idxtype *xadj, *adjncy, *adjwgt; + idxtype *where, *bndptr, *bndind; + EDegreeType *myedegrees; + RInfoType *myrinfo; + + nvtxs = graph->nvtxs; + xadj = graph->xadj; + adjncy = graph->adjncy; + adjwgt = graph->adjwgt; + + where = graph->where; + bndptr = graph->bndptr; + bndind = graph->bndind; + + nbnd = graph->nbnd; + + for (iii=0; iii<nind; iii++) { + i = ind[iii]; + from = where[i]; + + myrinfo = graph->rinfo+i; + if (myrinfo->edegrees == NULL) { + myrinfo->edegrees = ctrl->wspace.edegrees+ctrl->wspace.cdegree; + ctrl->wspace.cdegree += xadj[i+1]-xadj[i]; + myrinfo->ndegrees = 0; + } + myedegrees = myrinfo->edegrees; + + /* find the location of 'to' in myrinfo or create it if it is not there */ + for (k=0; k<myrinfo->ndegrees; k++) { + if (myedegrees[k].pid == to) + break; + } + if (k == myrinfo->ndegrees) { + myedegrees[k].pid = to; + myedegrees[k].ed = 0; + myrinfo->ndegrees++; + } + + graph->mincut -= myedegrees[k].ed-myrinfo->id; + + /* Update pmat to reflect the move of 'i' */ + pmat[from*nparts+to] += (myrinfo->id-myedegrees[k].ed); + pmat[to*nparts+from] += (myrinfo->id-myedegrees[k].ed); + if (pmat[from*nparts+to] == 0) + ndoms[from]--; + if (pmat[to*nparts+from] == 0) + ndoms[to]--; + + /* Update where, weight, and ID/ED information of the vertex you moved */ + where[i] = to; + myrinfo->ed += myrinfo->id-myedegrees[k].ed; + SWAP(myrinfo->id, myedegrees[k].ed, j); + if (myedegrees[k].ed == 0) + myedegrees[k] = myedegrees[--myrinfo->ndegrees]; + else + myedegrees[k].pid = from; + + if (myrinfo->ed-myrinfo->id < 0 && bndptr[i] != -1) + BNDDelete(nbnd, bndind, bndptr, i); + + /* Update the degrees of adjacent vertices */ + for (j=xadj[i]; j<xadj[i+1]; j++) { + ii = adjncy[j]; + me = where[ii]; + + myrinfo = graph->rinfo+ii; + if (myrinfo->edegrees == NULL) { + myrinfo->edegrees = ctrl->wspace.edegrees+ctrl->wspace.cdegree; + ctrl->wspace.cdegree += xadj[ii+1]-xadj[ii]; + } + myedegrees = myrinfo->edegrees; + + ASSERT(CheckRInfo(myrinfo)); + + if (me == from) { + INC_DEC(myrinfo->ed, myrinfo->id, adjwgt[j]); + + if (myrinfo->ed-myrinfo->id >= 0 && bndptr[ii] == -1) + BNDInsert(nbnd, bndind, bndptr, ii); + } + else if (me == to) { + INC_DEC(myrinfo->id, myrinfo->ed, adjwgt[j]); + + if (myrinfo->ed-myrinfo->id < 0 && bndptr[ii] != -1) + BNDDelete(nbnd, bndind, bndptr, ii); + } + + /* Remove contribution from the .ed of 'from' */ + if (me != from) { + for (k=0; k<myrinfo->ndegrees; k++) { + if (myedegrees[k].pid == from) { + if (myedegrees[k].ed == adjwgt[j]) + myedegrees[k] = myedegrees[--myrinfo->ndegrees]; + else + myedegrees[k].ed -= adjwgt[j]; + break; + } + } + } + + /* Add contribution to the .ed of 'to' */ + if (me != to) { + for (k=0; k<myrinfo->ndegrees; k++) { + if (myedegrees[k].pid == to) { + myedegrees[k].ed += adjwgt[j]; + break; + } + } + if (k == myrinfo->ndegrees) { + myedegrees[myrinfo->ndegrees].pid = to; + myedegrees[myrinfo->ndegrees++].ed = adjwgt[j]; + } + } + + /* Update pmat to reflect the move of 'i' for domains other than 'from' and 'to' */ + if (me != from && me != to) { + pmat[me*nparts+from] -= adjwgt[j]; + pmat[from*nparts+me] -= adjwgt[j]; + if (pmat[me*nparts+from] == 0) + ndoms[me]--; + if (pmat[from*nparts+me] == 0) + ndoms[from]--; + + if (pmat[me*nparts+to] == 0) + ndoms[me]++; + if (pmat[to*nparts+me] == 0) + ndoms[to]++; + + pmat[me*nparts+to] += adjwgt[j]; + pmat[to*nparts+me] += adjwgt[j]; + } + + ASSERT(CheckRInfo(myrinfo)); + } + + ASSERT(CheckRInfo(graph->rinfo+i)); + } + + graph->nbnd = nbnd; + +} + + + + +/************************************************************************* +* This function finds all the connected components induced by the +* partitioning vector in wgraph->where and tries to push them around to +* remove some of them +**************************************************************************/ +void EliminateComponents(CtrlType *ctrl, GraphType *graph, int nparts, float *tpwgts, float ubfactor) +{ + int i, ii, j, jj, k, me, nvtxs, tvwgt, first, last, nleft, ncmps, cwgt, other, target, deltawgt; + idxtype *xadj, *adjncy, *vwgt, *adjwgt, *where, *pwgts, *maxpwgt; + idxtype *cpvec, *touched, *perm, *todo, *cind, *cptr, *npcmps; + + nvtxs = graph->nvtxs; + xadj = graph->xadj; + adjncy = graph->adjncy; + vwgt = graph->vwgt; + adjwgt = graph->adjwgt; + + where = graph->where; + pwgts = graph->pwgts; + + touched = idxset(nvtxs, 0, idxwspacemalloc(ctrl, nvtxs)); + cptr = idxwspacemalloc(ctrl, nvtxs); + cind = idxwspacemalloc(ctrl, nvtxs); + perm = idxwspacemalloc(ctrl, nvtxs); + todo = idxwspacemalloc(ctrl, nvtxs); + maxpwgt = idxwspacemalloc(ctrl, nparts); + cpvec = idxwspacemalloc(ctrl, nparts); + npcmps = idxset(nparts, 0, idxwspacemalloc(ctrl, nparts)); + + for (i=0; i<nvtxs; i++) + perm[i] = todo[i] = i; + + /* Find the connected componends induced by the partition */ + ncmps = -1; + first = last = 0; + nleft = nvtxs; + while (nleft > 0) { + if (first == last) { /* Find another starting vertex */ + cptr[++ncmps] = first; + ASSERT(touched[todo[0]] == 0); + i = todo[0]; + cind[last++] = i; + touched[i] = 1; + me = where[i]; + npcmps[me]++; + } + + i = cind[first++]; + k = perm[i]; + j = todo[k] = todo[--nleft]; + perm[j] = k; + + for (j=xadj[i]; j<xadj[i+1]; j++) { + k = adjncy[j]; + if (where[k] == me && !touched[k]) { + cind[last++] = k; + touched[k] = 1; + } + } + } + cptr[++ncmps] = first; + + /* printf("I found %d components, for this %d-way partition\n", ncmps, nparts); */ + + if (ncmps > nparts) { /* There are more components than processors */ + /* First determine the max allowed load imbalance */ + tvwgt = idxsum(nparts, pwgts); + for (i=0; i<nparts; i++) + maxpwgt[i] = ubfactor*tpwgts[i]*tvwgt; + + deltawgt = 5; + + for (i=0; i<ncmps; i++) { + me = where[cind[cptr[i]]]; /* Get the domain of this component */ + if (npcmps[me] == 1) + continue; /* Skip it because it is contigous */ + + /*printf("Trying to move %d from %d\n", i, me); */ + + /* Determine the weight of the block to be moved and abort if too high */ + for (cwgt=0, j=cptr[i]; j<cptr[i+1]; j++) + cwgt += vwgt[cind[j]]; + + if (cwgt > .30*pwgts[me]) + continue; /* Skip the component if it is over 30% of the weight */ + + /* Determine the connectivity */ + idxset(nparts, 0, cpvec); + for (j=cptr[i]; j<cptr[i+1]; j++) { + ii = cind[j]; + for (jj=xadj[ii]; jj<xadj[ii+1]; jj++) + cpvec[where[adjncy[jj]]] += adjwgt[jj]; + } + cpvec[me] = 0; + + target = -1; + for (j=0; j<nparts; j++) { + if (cpvec[j] > 0 && (cwgt < deltawgt || pwgts[j] + cwgt < maxpwgt[j])) { + if (target == -1 || cpvec[target] < cpvec[j]) + target = j; + } + } + + /* printf("\tMoving it to %d [%d]\n", target, cpvec[target]);*/ + + if (target != -1) { + /* Assign all the vertices of 'me' to 'target' and update data structures */ + INC_DEC(pwgts[target], pwgts[me], cwgt); + npcmps[me]--; + + MoveGroup(ctrl, graph, nparts, target, i, cptr, cind); + } + } + + } + + idxwspacefree(ctrl, nparts); + idxwspacefree(ctrl, nparts); + idxwspacefree(ctrl, nparts); + idxwspacefree(ctrl, nvtxs); + idxwspacefree(ctrl, nvtxs); + idxwspacefree(ctrl, nvtxs); + idxwspacefree(ctrl, nvtxs); + idxwspacefree(ctrl, nvtxs); + +} + + +/************************************************************************* +* This function moves a collection of vertices and updates their rinfo +**************************************************************************/ +void MoveGroup(CtrlType *ctrl, GraphType *graph, int nparts, int to, int gid, idxtype *ptr, idxtype *ind) +{ + int i, ii, iii, j, jj, k, l, nvtxs, nbnd, myndegrees; + int from, me; + idxtype *xadj, *adjncy, *adjwgt; + idxtype *where, *bndptr, *bndind; + EDegreeType *myedegrees; + RInfoType *myrinfo; + + nvtxs = graph->nvtxs; + xadj = graph->xadj; + adjncy = graph->adjncy; + adjwgt = graph->adjwgt; + + where = graph->where; + bndptr = graph->bndptr; + bndind = graph->bndind; + + nbnd = graph->nbnd; + + for (iii=ptr[gid]; iii<ptr[gid+1]; iii++) { + i = ind[iii]; + from = where[i]; + + myrinfo = graph->rinfo+i; + if (myrinfo->edegrees == NULL) { + myrinfo->edegrees = ctrl->wspace.edegrees+ctrl->wspace.cdegree; + ctrl->wspace.cdegree += xadj[i+1]-xadj[i]; + myrinfo->ndegrees = 0; + } + myedegrees = myrinfo->edegrees; + + /* find the location of 'to' in myrinfo or create it if it is not there */ + for (k=0; k<myrinfo->ndegrees; k++) { + if (myedegrees[k].pid == to) + break; + } + if (k == myrinfo->ndegrees) { + myedegrees[k].pid = to; + myedegrees[k].ed = 0; + myrinfo->ndegrees++; + } + + graph->mincut -= myedegrees[k].ed-myrinfo->id; + + + /* Update where, weight, and ID/ED information of the vertex you moved */ + where[i] = to; + myrinfo->ed += myrinfo->id-myedegrees[k].ed; + SWAP(myrinfo->id, myedegrees[k].ed, j); + if (myedegrees[k].ed == 0) + myedegrees[k] = myedegrees[--myrinfo->ndegrees]; + else + myedegrees[k].pid = from; + + if (myrinfo->ed-myrinfo->id < 0 && bndptr[i] != -1) + BNDDelete(nbnd, bndind, bndptr, i); + + /* Update the degrees of adjacent vertices */ + for (j=xadj[i]; j<xadj[i+1]; j++) { + ii = adjncy[j]; + me = where[ii]; + + myrinfo = graph->rinfo+ii; + if (myrinfo->edegrees == NULL) { + myrinfo->edegrees = ctrl->wspace.edegrees+ctrl->wspace.cdegree; + ctrl->wspace.cdegree += xadj[ii+1]-xadj[ii]; + } + myedegrees = myrinfo->edegrees; + + ASSERT(CheckRInfo(myrinfo)); + + if (me == from) { + INC_DEC(myrinfo->ed, myrinfo->id, adjwgt[j]); + + if (myrinfo->ed-myrinfo->id >= 0 && bndptr[ii] == -1) + BNDInsert(nbnd, bndind, bndptr, ii); + } + else if (me == to) { + INC_DEC(myrinfo->id, myrinfo->ed, adjwgt[j]); + + if (myrinfo->ed-myrinfo->id < 0 && bndptr[ii] != -1) + BNDDelete(nbnd, bndind, bndptr, ii); + } + + /* Remove contribution from the .ed of 'from' */ + if (me != from) { + for (k=0; k<myrinfo->ndegrees; k++) { + if (myedegrees[k].pid == from) { + if (myedegrees[k].ed == adjwgt[j]) + myedegrees[k] = myedegrees[--myrinfo->ndegrees]; + else + myedegrees[k].ed -= adjwgt[j]; + break; + } + } + } + + /* Add contribution to the .ed of 'to' */ + if (me != to) { + for (k=0; k<myrinfo->ndegrees; k++) { + if (myedegrees[k].pid == to) { + myedegrees[k].ed += adjwgt[j]; + break; + } + } + if (k == myrinfo->ndegrees) { + myedegrees[myrinfo->ndegrees].pid = to; + myedegrees[myrinfo->ndegrees++].ed = adjwgt[j]; + } + } + + ASSERT(CheckRInfo(myrinfo)); + } + + ASSERT(CheckRInfo(graph->rinfo+i)); + } + + graph->nbnd = nbnd; + +} + diff --git a/contrib/Metis/timing.c b/contrib/Metis/timing.c new file mode 100644 index 0000000000..c8ded4a171 --- /dev/null +++ b/contrib/Metis/timing.c @@ -0,0 +1,74 @@ +/* + * Copyright 1997, Regents of the University of Minnesota + * + * timing.c + * + * This file contains routines that deal with timing Metis + * + * Started 7/24/97 + * George + * + * $Id: timing.c,v 1.1 2005-09-21 17:29:38 geuzaine Exp $ + * + */ + +#include <metis.h> + + +/************************************************************************* +* This function clears the timers +**************************************************************************/ +void InitTimers(CtrlType *ctrl) +{ + cleartimer(ctrl->TotalTmr); + cleartimer(ctrl->InitPartTmr); + cleartimer(ctrl->MatchTmr); + cleartimer(ctrl->ContractTmr); + cleartimer(ctrl->CoarsenTmr); + cleartimer(ctrl->UncoarsenTmr); + cleartimer(ctrl->RefTmr); + cleartimer(ctrl->ProjectTmr); + cleartimer(ctrl->SplitTmr); + cleartimer(ctrl->SepTmr); + cleartimer(ctrl->AuxTmr1); + cleartimer(ctrl->AuxTmr2); + cleartimer(ctrl->AuxTmr3); + cleartimer(ctrl->AuxTmr4); + cleartimer(ctrl->AuxTmr5); + cleartimer(ctrl->AuxTmr6); +} + + + +/************************************************************************* +* This function prints the various timers +**************************************************************************/ +void PrintTimers(CtrlType *ctrl) +{ + printf("\nTiming Information -------------------------------------------------"); + printf("\n Multilevel: \t\t %7.3f", gettimer(ctrl->TotalTmr)); + printf("\n Coarsening: \t\t %7.3f", gettimer(ctrl->CoarsenTmr)); + printf("\n Matching: \t\t\t %7.3f", gettimer(ctrl->MatchTmr)); + printf("\n Contract: \t\t\t %7.3f", gettimer(ctrl->ContractTmr)); + printf("\n Initial Partition: \t %7.3f", gettimer(ctrl->InitPartTmr)); + printf("\n Construct Separator: \t %7.3f", gettimer(ctrl->SepTmr)); + printf("\n Uncoarsening: \t\t %7.3f", gettimer(ctrl->UncoarsenTmr)); + printf("\n Refinement: \t\t\t %7.3f", gettimer(ctrl->RefTmr)); + printf("\n Projection: \t\t\t %7.3f", gettimer(ctrl->ProjectTmr)); + printf("\n Splitting: \t\t %7.3f", gettimer(ctrl->SplitTmr)); + printf("\n AUX1: \t\t %7.3f", gettimer(ctrl->AuxTmr1)); + printf("\n AUX2: \t\t %7.3f", gettimer(ctrl->AuxTmr2)); + printf("\n AUX3: \t\t %7.3f", gettimer(ctrl->AuxTmr3)); + printf("\n********************************************************************\n"); +} + + +/************************************************************************* +* This function returns the seconds +**************************************************************************/ +double seconds(void) +{ + return((double) clock()/CLOCKS_PER_SEC); +} + + diff --git a/contrib/Metis/util.c b/contrib/Metis/util.c new file mode 100644 index 0000000000..3eb87deb1e --- /dev/null +++ b/contrib/Metis/util.c @@ -0,0 +1,519 @@ +/* + * Copyright 1997, Regents of the University of Minnesota + * + * util.c + * + * This function contains various utility routines + * + * Started 9/28/95 + * George + * + * $Id: util.c,v 1.1 2005-09-21 17:29:38 geuzaine Exp $ + */ + +#include <metis.h> + + +/************************************************************************* +* This function prints an error message and exits +**************************************************************************/ +void errexit(char *f_str,...) +{ + va_list argp; + char out1[256], out2[256]; + + va_start(argp, f_str); + vsprintf(out1, f_str, argp); + va_end(argp); + + sprintf(out2, "Error! %s", out1); + + fprintf(stdout, out2); + fflush(stdout); + + abort(); +} + + + +#ifndef DMALLOC +/************************************************************************* +* The following function allocates an array of integers +**************************************************************************/ +int *imalloc(int n, char *msg) +{ + if (n == 0) + return NULL; + + return (int *)GKmalloc(sizeof(int)*n, msg); +} + + +/************************************************************************* +* The following function allocates an array of integers +**************************************************************************/ +idxtype *idxmalloc(int n, char *msg) +{ + if (n == 0) + return NULL; + + return (idxtype *)GKmalloc(sizeof(idxtype)*n, msg); +} + + +/************************************************************************* +* The following function allocates an array of float +**************************************************************************/ +float *fmalloc(int n, char *msg) +{ + if (n == 0) + return NULL; + + return (float *)GKmalloc(sizeof(float)*n, msg); +} + + +/************************************************************************* +* The follwoing function allocates an array of integers +**************************************************************************/ +int *ismalloc(int n, int ival, char *msg) +{ + if (n == 0) + return NULL; + + return iset(n, ival, (int *)GKmalloc(sizeof(int)*n, msg)); +} + + + +/************************************************************************* +* The follwoing function allocates an array of integers +**************************************************************************/ +idxtype *idxsmalloc(int n, idxtype ival, char *msg) +{ + if (n == 0) + return NULL; + + return idxset(n, ival, (idxtype *)GKmalloc(sizeof(idxtype)*n, msg)); +} + + +/************************************************************************* +* This function is my wrapper around malloc +**************************************************************************/ +void *GKmalloc(int nbytes, char *msg) +{ + void *ptr; + + if (nbytes == 0) + return NULL; + + ptr = (void *)malloc(nbytes); + if (ptr == NULL) + errexit("***Memory allocation failed for %s. Requested size: %d bytes", msg, nbytes); + + return ptr; +} +#endif + +/************************************************************************* +* This function is my wrapper around free, allows multiple pointers +**************************************************************************/ +void GKfree(void **ptr1,...) +{ + va_list plist; + void **ptr; + + if (*ptr1 != NULL) + free(*ptr1); + *ptr1 = NULL; + + va_start(plist, ptr1); + + /* while ((int)(ptr = va_arg(plist, void **)) != -1) { */ + while ((ptr = va_arg(plist, void **)) != LTERM) { + if (*ptr != NULL) + free(*ptr); + *ptr = NULL; + } + + va_end(plist); +} + + +/************************************************************************* +* These functions set the values of a vector +**************************************************************************/ +int *iset(int n, int val, int *x) +{ + int i; + + for (i=0; i<n; i++) + x[i] = val; + + return x; +} + + +/************************************************************************* +* These functions set the values of a vector +**************************************************************************/ +idxtype *idxset(int n, idxtype val, idxtype *x) +{ + int i; + + for (i=0; i<n; i++) + x[i] = val; + + return x; +} + + +/************************************************************************* +* These functions set the values of a vector +**************************************************************************/ +float *sset(int n, float val, float *x) +{ + int i; + + for (i=0; i<n; i++) + x[i] = val; + + return x; +} + + + +/************************************************************************* +* These functions return the index of the maximum element in a vector +**************************************************************************/ +int iamax(int n, int *x) +{ + int i, max=0; + + for (i=1; i<n; i++) + max = (x[i] > x[max] ? i : max); + + return max; +} + + +/************************************************************************* +* These functions return the index of the maximum element in a vector +**************************************************************************/ +int idxamax(int n, idxtype *x) +{ + int i, max=0; + + for (i=1; i<n; i++) + max = (x[i] > x[max] ? i : max); + + return max; +} + +/************************************************************************* +* These functions return the index of the maximum element in a vector +**************************************************************************/ +int idxamax_strd(int n, idxtype *x, int incx) +{ + int i, max=0; + + n *= incx; + for (i=incx; i<n; i+=incx) + max = (x[i] > x[max] ? i : max); + + return max/incx; +} + + + +/************************************************************************* +* These functions return the index of the maximum element in a vector +**************************************************************************/ +int samax(int n, float *x) +{ + int i, max=0; + + for (i=1; i<n; i++) + max = (x[i] > x[max] ? i : max); + + return max; +} + +/************************************************************************* +* These functions return the index of the almost maximum element in a vector +**************************************************************************/ +int samax2(int n, float *x) +{ + int i, max1, max2; + + if (x[0] > x[1]) { + max1 = 0; + max2 = 1; + } + else { + max1 = 1; + max2 = 0; + } + + for (i=2; i<n; i++) { + if (x[i] > x[max1]) { + max2 = max1; + max1 = i; + } + else if (x[i] > x[max2]) + max2 = i; + } + + return max2; +} + + +/************************************************************************* +* These functions return the index of the minimum element in a vector +**************************************************************************/ +int idxamin(int n, idxtype *x) +{ + int i, min=0; + + for (i=1; i<n; i++) + min = (x[i] < x[min] ? i : min); + + return min; +} + + +/************************************************************************* +* These functions return the index of the minimum element in a vector +**************************************************************************/ +int samin(int n, float *x) +{ + int i, min=0; + + for (i=1; i<n; i++) + min = (x[i] < x[min] ? i : min); + + return min; +} + + +/************************************************************************* +* This function sums the entries in an array +**************************************************************************/ +int idxsum(int n, idxtype *x) +{ + int i, sum = 0; + + for (i=0; i<n; i++) + sum += x[i]; + + return sum; +} + + +/************************************************************************* +* This function sums the entries in an array +**************************************************************************/ +int idxsum_strd(int n, idxtype *x, int incx) +{ + int i, sum = 0; + + for (i=0; i<n; i++, x+=incx) { + sum += *x; + } + + return sum; +} + + +/************************************************************************* +* This function sums the entries in an array +**************************************************************************/ +void idxadd(int n, idxtype *x, idxtype *y) +{ + for (n--; n>=0; n--) + y[n] += x[n]; +} + + +/************************************************************************* +* This function sums the entries in an array +**************************************************************************/ +int charsum(int n, char *x) +{ + int i, sum = 0; + + for (i=0; i<n; i++) + sum += x[i]; + + return sum; +} + +/************************************************************************* +* This function sums the entries in an array +**************************************************************************/ +int isum(int n, int *x) +{ + int i, sum = 0; + + for (i=0; i<n; i++) + sum += x[i]; + + return sum; +} + +/************************************************************************* +* This function sums the entries in an array +**************************************************************************/ +float ssum(int n, float *x) +{ + int i; + float sum = 0.0; + + for (i=0; i<n; i++) + sum += x[i]; + + return sum; +} + +/************************************************************************* +* This function sums the entries in an array +**************************************************************************/ +float ssum_strd(int n, float *x, int incx) +{ + int i; + float sum = 0.0; + + for (i=0; i<n; i++, x+=incx) + sum += *x; + + return sum; +} + +/************************************************************************* +* This function sums the entries in an array +**************************************************************************/ +void sscale(int n, float alpha, float *x) +{ + int i; + + for (i=0; i<n; i++) + x[i] *= alpha; +} + + +/************************************************************************* +* This function computes a 2-norm +**************************************************************************/ +float snorm2(int n, float *v) +{ + int i; + float partial = 0; + + for (i = 0; i<n; i++) + partial += v[i] * v[i]; + + return sqrt(partial); +} + + + +/************************************************************************* +* This function computes a 2-norm +**************************************************************************/ +float sdot(int n, float *x, float *y) +{ + int i; + float partial = 0; + + for (i = 0; i<n; i++) + partial += x[i] * y[i]; + + return partial; +} + + +/************************************************************************* +* This function computes a 2-norm +**************************************************************************/ +void saxpy(int n, float alpha, float *x, int incx, float *y, int incy) +{ + int i; + + for (i=0; i<n; i++, x+=incx, y+=incy) + *y += alpha*(*x); +} + + + + +/************************************************************************* +* This file randomly permutes the contents of an array. +* flag == 0, don't initialize perm +* flag == 1, set p[i] = i +**************************************************************************/ +void RandomPermute(int n, idxtype *p, int flag) +{ + int i, u, v; + idxtype tmp; + + if (flag == 1) { + for (i=0; i<n; i++) + p[i] = i; + } + + if (n <= 4) + return; + + for (i=0; i<n; i+=16) { + u = RandomInRangeFast(n-4); + v = RandomInRangeFast(n-4); + SWAP(p[v], p[u], tmp); + SWAP(p[v+1], p[u+1], tmp); + SWAP(p[v+2], p[u+2], tmp); + SWAP(p[v+3], p[u+3], tmp); + } +} + + + +/************************************************************************* +* This function returns true if the a is a power of 2 +**************************************************************************/ +int ispow2(int a) +{ + for (; a%2 != 1; a = a>>1); + return (a > 1 ? 0 : 1); +} + + +/************************************************************************* +* This function initializes the random number generator +**************************************************************************/ +void InitRandom(int seed) +{ + if (seed == -1) { +#ifndef __VC__ + srand48(7654321L); +#endif + srand(4321); + } + else { +#ifndef __VC__ + srand48(seed); +#endif + srand(seed); + } +} + +/************************************************************************* +* This function returns the log2(x) +**************************************************************************/ +int log2(int a) +{ + int i; + + for (i=1; a > 1; i++, a = a>>1); + return i-1; +} + diff --git a/contrib/NR/Makefile b/contrib/NR/Makefile new file mode 100644 index 0000000000..4944e04f46 --- /dev/null +++ b/contrib/NR/Makefile @@ -0,0 +1,77 @@ +# $Id: Makefile,v 1.1 2005-09-21 17:29:38 geuzaine Exp $ +# +# Copyright (C) 1997-2005 C. Geuzaine, J.-F. Remacle +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +# USA. +# +# Please report all bugs and problems to <gmsh@geuz.org>. + +include ../../variables + +LIB = ../../lib/libGmshNR.a +INCLUDE = -I../../Common -I../../DataStr -I../../Numeric +# don't optimize this library: there are some problems with gcc... +OPTIM = -O0 +CFLAGS = ${OPTIM} ${FLAGS} ${INCLUDE} + +SRC = brent.cpp\ + dpythag.cpp\ + dsvdcmp.cpp\ + fdjac.cpp\ + fmin.cpp\ + lnsrch.cpp\ + lubksb.cpp\ + ludcmp.cpp\ + mnbrak.cpp\ + newt.cpp\ + nrutil.cpp + +OBJ = ${SRC:.cpp=.o} + +.SUFFIXES: .o .cpp + +${LIB}: ${OBJ} + ${AR} ${LIB} ${OBJ} + ${RANLIB} ${LIB} + +.cpp.o: + ${CXX} ${CFLAGS} -c $< + +clean: + rm -f *.o + +depend: + (sed '/^# DO NOT DELETE THIS LINE/q' Makefile && \ + ${CXX} -MM ${CFLAGS} ${SRC} \ + ) >Makefile.new + cp Makefile Makefile.bak + cp Makefile.new Makefile + rm -f Makefile.new + +# DO NOT DELETE THIS LINE +brent.o: brent.cpp nrutil.h ../Numeric/Numeric.h +dpythag.o: dpythag.cpp nrutil.h ../Numeric/Numeric.h +dsvdcmp.o: dsvdcmp.cpp nrutil.h ../Numeric/Numeric.h +fdjac.o: fdjac.cpp nrutil.h ../Numeric/Numeric.h +fmin.o: fmin.cpp nrutil.h ../Numeric/Numeric.h +lnsrch.o: lnsrch.cpp nrutil.h ../Numeric/Numeric.h +lubksb.o: lubksb.cpp +ludcmp.o: ludcmp.cpp nrutil.h ../Numeric/Numeric.h +mnbrak.o: mnbrak.cpp nrutil.h ../Numeric/Numeric.h +newt.o: newt.cpp nrutil.h ../Numeric/Numeric.h +nrutil.o: nrutil.cpp ../Common/Gmsh.h ../Common/Message.h \ + ../DataStr/Malloc.h ../DataStr/List.h ../DataStr/Tree.h \ + ../DataStr/avl.h ../DataStr/Tools.h diff --git a/contrib/NR/brent.cpp b/contrib/NR/brent.cpp new file mode 100644 index 0000000000..8dc82e8813 --- /dev/null +++ b/contrib/NR/brent.cpp @@ -0,0 +1,77 @@ +#include <math.h> +#define NRANSI +#include "nrutil.h" +#define ITMAX 100 +#define CGOLD 0.3819660 +#define ZEPS 1.0e-10 +#define SHFT(a,b,c,d) (a)=(b);(b)=(c);(c)=(d); + +/* This file has been modified for inclusion in Gmsh (float->double) */ + +double brent(double ax, double bx, double cx, double (*f)(double), double tol, + double *xmin) +{ + int iter; + double a,b,d,etemp,fu,fv,fw,fx,p,q,r,tol1,tol2,u,v,w,x,xm; + double e=0.0; + + a=(ax < cx ? ax : cx); + b=(ax > cx ? ax : cx); + x=w=v=bx; + fw=fv=fx=(*f)(x); + for (iter=1;iter<=ITMAX;iter++) { + xm=0.5*(a+b); + tol2=2.0*(tol1=tol*fabs(x)+ZEPS); + if (fabs(x-xm) <= (tol2-0.5*(b-a))) { + *xmin=x; + return fx; + } + if (fabs(e) > tol1) { + r=(x-w)*(fx-fv); + q=(x-v)*(fx-fw); + p=(x-v)*q-(x-w)*r; + q=2.0*(q-r); + if (q > 0.0) p = -p; + q=fabs(q); + etemp=e; + e=d; + if (fabs(p) >= fabs(0.5*q*etemp) || p <= q*(a-x) || p >= q*(b-x)) + d=CGOLD*(e=(x >= xm ? a-x : b-x)); + else { + d=p/q; + u=x+d; + if (u-a < tol2 || b-u < tol2) + d=SIGN(tol1,xm-x); + } + } else { + d=CGOLD*(e=(x >= xm ? a-x : b-x)); + } + u=(fabs(d) >= tol1 ? x+d : x+SIGN(tol1,d)); + fu=(*f)(u); + if (fu <= fx) { + if (u >= x) a=x; else b=x; + SHFT(v,w,x,u) + SHFT(fv,fw,fx,fu) + } else { + if (u < x) a=u; else b=u; + if (fu <= fw || w == x) { + v=w; + w=u; + fv=fw; + fw=fu; + } else if (fu <= fv || v == x || v == w) { + v=u; + fv=fu; + } + } + } + nrerror("Too many iterations in brent"); + *xmin=x; + return fx; +} +#undef ITMAX +#undef CGOLD +#undef ZEPS +#undef SHFT +#undef NRANSI +/* (C) Copr. 1986-92 Numerical Recipes Software J!0. */ diff --git a/contrib/NR/dpythag.cpp b/contrib/NR/dpythag.cpp new file mode 100644 index 0000000000..4585295c43 --- /dev/null +++ b/contrib/NR/dpythag.cpp @@ -0,0 +1,14 @@ +#include <math.h> +#define NRANSI +#include "nrutil.h" + +double dpythag(double a, double b) +{ + double absa,absb; + absa=fabs(a); + absb=fabs(b); + if (absa > absb) return absa*sqrt(1.0+DSQR(absb/absa)); + else return (absb == 0.0 ? 0.0 : absb*sqrt(1.0+DSQR(absa/absb))); +} +#undef NRANSI +/* (C) Copr. 1986-92 Numerical Recipes Software J!0. */ diff --git a/contrib/NR/dsvdcmp.cpp b/contrib/NR/dsvdcmp.cpp new file mode 100644 index 0000000000..81317ec7db --- /dev/null +++ b/contrib/NR/dsvdcmp.cpp @@ -0,0 +1,183 @@ +#include <math.h> +#define NRANSI +#include "nrutil.h" + +void dsvdcmp(double **a, int m, int n, double w[], double **v) +{ + double dpythag(double a, double b); + int flag,i,its,j,jj,k,l,nm; + double anorm,c,f,g,h,s,scale,x,y,z,*rv1; + + rv1=dvector(1,n); + g=scale=anorm=0.0; + for (i=1;i<=n;i++) { + l=i+1; + rv1[i]=scale*g; + g=s=scale=0.0; + if (i <= m) { + for (k=i;k<=m;k++) scale += fabs(a[k][i]); + if (scale) { + for (k=i;k<=m;k++) { + a[k][i] /= scale; + s += a[k][i]*a[k][i]; + } + f=a[i][i]; + g = -SIGN(sqrt(s),f); + h=f*g-s; + a[i][i]=f-g; + for (j=l;j<=n;j++) { + for (s=0.0,k=i;k<=m;k++) s += a[k][i]*a[k][j]; + f=s/h; + for (k=i;k<=m;k++) a[k][j] += f*a[k][i]; + } + for (k=i;k<=m;k++) a[k][i] *= scale; + } + } + w[i]=scale *g; + g=s=scale=0.0; + if (i <= m && i != n) { + for (k=l;k<=n;k++) scale += fabs(a[i][k]); + if (scale) { + for (k=l;k<=n;k++) { + a[i][k] /= scale; + s += a[i][k]*a[i][k]; + } + f=a[i][l]; + g = -SIGN(sqrt(s),f); + h=f*g-s; + a[i][l]=f-g; + for (k=l;k<=n;k++) rv1[k]=a[i][k]/h; + for (j=l;j<=m;j++) { + for (s=0.0,k=l;k<=n;k++) s += a[j][k]*a[i][k]; + for (k=l;k<=n;k++) a[j][k] += s*rv1[k]; + } + for (k=l;k<=n;k++) a[i][k] *= scale; + } + } + anorm=DMAX(anorm,(fabs(w[i])+fabs(rv1[i]))); + } + for (i=n;i>=1;i--) { + if (i < n) { + if (g) { + for (j=l;j<=n;j++) v[j][i]=(a[i][j]/a[i][l])/g; + for (j=l;j<=n;j++) { + for (s=0.0,k=l;k<=n;k++) s += a[i][k]*v[k][j]; + for (k=l;k<=n;k++) v[k][j] += s*v[k][i]; + } + } + for (j=l;j<=n;j++) v[i][j]=v[j][i]=0.0; + } + v[i][i]=1.0; + g=rv1[i]; + l=i; + } + for (i=IMIN(m,n);i>=1;i--) { + l=i+1; + g=w[i]; + for (j=l;j<=n;j++) a[i][j]=0.0; + if (g) { + g=1.0/g; + for (j=l;j<=n;j++) { + for (s=0.0,k=l;k<=m;k++) s += a[k][i]*a[k][j]; + f=(s/a[i][i])*g; + for (k=i;k<=m;k++) a[k][j] += f*a[k][i]; + } + for (j=i;j<=m;j++) a[j][i] *= g; + } else for (j=i;j<=m;j++) a[j][i]=0.0; + ++a[i][i]; + } + for (k=n;k>=1;k--) { + for (its=1;its<=30;its++) { + flag=1; + for (l=k;l>=1;l--) { + nm=l-1; + if ((double)(fabs(rv1[l])+anorm) == anorm) { + flag=0; + break; + } + if ((double)(fabs(w[nm])+anorm) == anorm) break; + } + if (flag) { + c=0.0; + s=1.0; + for (i=l;i<=k;i++) { + f=s*rv1[i]; + rv1[i]=c*rv1[i]; + if ((double)(fabs(f)+anorm) == anorm) break; + g=w[i]; + h=dpythag(f,g); + w[i]=h; + h=1.0/h; + c=g*h; + s = -f*h; + for (j=1;j<=m;j++) { + y=a[j][nm]; + z=a[j][i]; + a[j][nm]=y*c+z*s; + a[j][i]=z*c-y*s; + } + } + } + z=w[k]; + if (l == k) { + if (z < 0.0) { + w[k] = -z; + for (j=1;j<=n;j++) v[j][k] = -v[j][k]; + } + break; + } + if (its == 30) nrerror("no convergence in 30 dsvdcmp iterations"); + x=w[l]; + nm=k-1; + y=w[nm]; + g=rv1[nm]; + h=rv1[k]; + f=((y-z)*(y+z)+(g-h)*(g+h))/(2.0*h*y); + g=dpythag(f,1.0); + f=((x-z)*(x+z)+h*((y/(f+SIGN(g,f)))-h))/x; + c=s=1.0; + for (j=l;j<=nm;j++) { + i=j+1; + g=rv1[i]; + y=w[i]; + h=s*g; + g=c*g; + z=dpythag(f,h); + rv1[j]=z; + c=f/z; + s=h/z; + f=x*c+g*s; + g = g*c-x*s; + h=y*s; + y *= c; + for (jj=1;jj<=n;jj++) { + x=v[jj][j]; + z=v[jj][i]; + v[jj][j]=x*c+z*s; + v[jj][i]=z*c-x*s; + } + z=dpythag(f,h); + w[j]=z; + if (z) { + z=1.0/z; + c=f*z; + s=h*z; + } + f=c*g+s*y; + x=c*y-s*g; + for (jj=1;jj<=m;jj++) { + y=a[jj][j]; + z=a[jj][i]; + a[jj][j]=y*c+z*s; + a[jj][i]=z*c-y*s; + } + } + rv1[l]=0.0; + rv1[k]=f; + w[k]=x; + } + } + free_dvector(rv1,1,n); +} +#undef NRANSI +/* (C) Copr. 1986-92 Numerical Recipes Software J!0. */ diff --git a/contrib/NR/fdjac.cpp b/contrib/NR/fdjac.cpp new file mode 100644 index 0000000000..7767ff1bc4 --- /dev/null +++ b/contrib/NR/fdjac.cpp @@ -0,0 +1,29 @@ +#include <math.h> +#define NRANSI +#include "nrutil.h" +#define EPS 1.0e-4 + +/* This file has been modified for inclusion in Gmsh (float->double) */ + +void fdjac(int n, double x[], double fvec[], double **df, + void (*vecfunc)(int, double [], double [])) +{ + int i,j; + double h,temp,*f; + + f=dvector(1,n); + for (j=1;j<=n;j++) { + temp=x[j]; + h=EPS*fabs(temp); + if (h == 0.0) h=EPS; + x[j]=temp+h; + h=x[j]-temp; + (*vecfunc)(n,x,f); + x[j]=temp; + for (i=1;i<=n;i++) df[i][j]=(f[i]-fvec[i])/h; + } + free_dvector(f,1,n); +} +#undef EPS +#undef NRANSI +/* (C) Copr. 1986-92 Numerical Recipes Software J!0. */ diff --git a/contrib/NR/fmin.cpp b/contrib/NR/fmin.cpp new file mode 100644 index 0000000000..f461aa7a05 --- /dev/null +++ b/contrib/NR/fmin.cpp @@ -0,0 +1,20 @@ +#define NRANSI +#include "nrutil.h" + +/* This file has been modified for inclusion in Gmsh (float->double) */ + +extern int nn; +extern double *fvec; +extern void (*nrfuncv)(int n, double v[], double f[]); + +double fmin(double x[]) +{ + int i; + double sum; + + (*nrfuncv)(nn,x,fvec); + for (sum=0.0,i=1;i<=nn;i++) sum += SQR(fvec[i]); + return 0.5*sum; +} +#undef NRANSI +/* (C) Copr. 1986-92 Numerical Recipes Software J!0. */ diff --git a/contrib/NR/lnsrch.cpp b/contrib/NR/lnsrch.cpp new file mode 100644 index 0000000000..e4a5346a5f --- /dev/null +++ b/contrib/NR/lnsrch.cpp @@ -0,0 +1,65 @@ +#include <math.h> +#define NRANSI +#include "nrutil.h" +#define ALF 1.0e-4 +#define TOLX 1.0e-7 + +/* This file has been modified for inclusion in Gmsh (float->double) */ + +void lnsrch(int n, double xold[], double fold, double g[], double p[], double x[], + double *f, double stpmax, int *check, double (*func)(double [])) +{ + int i; + double a,alam,alam2,alamin,b,disc,f2,fold2,rhs1,rhs2,slope,sum,temp, + test,tmplam; + + *check=0; + for (sum=0.0,i=1;i<=n;i++) sum += p[i]*p[i]; + sum=sqrt(sum); + if (sum > stpmax) + for (i=1;i<=n;i++) p[i] *= stpmax/sum; + for (slope=0.0,i=1;i<=n;i++) + slope += g[i]*p[i]; + test=0.0; + for (i=1;i<=n;i++) { + temp=fabs(p[i])/FMAX(fabs(xold[i]),1.0); + if (temp > test) test=temp; + } + alamin=TOLX/test; + alam=1.0; + for (;;) { + for (i=1;i<=n;i++) x[i]=xold[i]+alam*p[i]; + *f=(*func)(x); + if (alam < alamin) { + for (i=1;i<=n;i++) x[i]=xold[i]; + *check=1; + return; + } else if (*f <= fold+ALF*alam*slope) return; + else { + if (alam == 1.0) + tmplam = -slope/(2.0*(*f-fold-slope)); + else { + rhs1 = *f-fold-alam*slope; + rhs2=f2-fold2-alam2*slope; + a=(rhs1/(alam*alam)-rhs2/(alam2*alam2))/(alam-alam2); + b=(-alam2*rhs1/(alam*alam)+alam*rhs2/(alam2*alam2))/(alam-alam2); + if (a == 0.0) tmplam = -slope/(2.0*b); + else { + disc=b*b-3.0*a*slope; + if (disc<0.0) nrerror("Roundoff problem in lnsrch."); + else tmplam=(-b+sqrt(disc))/(3.0*a); + } + if (tmplam>0.5*alam) + tmplam=0.5*alam; + } + } + alam2=alam; + f2 = *f; + fold2=fold; + alam=FMAX(tmplam,0.1*alam); + } +} +#undef ALF +#undef TOLX +#undef NRANSI +/* (C) Copr. 1986-92 Numerical Recipes Software J!0. */ diff --git a/contrib/NR/lubksb.cpp b/contrib/NR/lubksb.cpp new file mode 100644 index 0000000000..202c826e2f --- /dev/null +++ b/contrib/NR/lubksb.cpp @@ -0,0 +1,23 @@ +/* This file has been modified for inclusion in Gmsh (float->double) */ + +void lubksb(double **a, int n, int *indx, double b[]) +{ + int i,ii=0,ip,j; + double sum; + + for (i=1;i<=n;i++) { + ip=indx[i]; + sum=b[ip]; + b[ip]=b[i]; + if (ii) + for (j=ii;j<=i-1;j++) sum -= a[i][j]*b[j]; + else if (sum) ii=i; + b[i]=sum; + } + for (i=n;i>=1;i--) { + sum=b[i]; + for (j=i+1;j<=n;j++) sum -= a[i][j]*b[j]; + b[i]=sum/a[i][i]; + } +} +/* (C) Copr. 1986-92 Numerical Recipes Software J!0. */ diff --git a/contrib/NR/ludcmp.cpp b/contrib/NR/ludcmp.cpp new file mode 100644 index 0000000000..8f4e0c17fc --- /dev/null +++ b/contrib/NR/ludcmp.cpp @@ -0,0 +1,60 @@ +#include <math.h> +#define NRANSI +#include "nrutil.h" +#define TINY 1.0e-20; + +/* This file has been modified for inclusion in Gmsh (float->double) */ + +void ludcmp(double **a, int n, int *indx, double *d) +{ + int i,imax,j,k; + double big,dum,sum,temp; + double *vv; + + vv=dvector(1,n); + *d=1.0; + for (i=1;i<=n;i++) { + big=0.0; + for (j=1;j<=n;j++) + if ((temp=fabs(a[i][j])) > big) big=temp; + if (big == 0.0) nrerror("Singular matrix in routine ludcmp"); + vv[i]=1.0/big; + } + for (j=1;j<=n;j++) { + for (i=1;i<j;i++) { + sum=a[i][j]; + for (k=1;k<i;k++) sum -= a[i][k]*a[k][j]; + a[i][j]=sum; + } + big=0.0; + for (i=j;i<=n;i++) { + sum=a[i][j]; + for (k=1;k<j;k++) + sum -= a[i][k]*a[k][j]; + a[i][j]=sum; + if ( (dum=vv[i]*fabs(sum)) >= big) { + big=dum; + imax=i; + } + } + if (j != imax) { + for (k=1;k<=n;k++) { + dum=a[imax][k]; + a[imax][k]=a[j][k]; + a[j][k]=dum; + } + *d = -(*d); + vv[imax]=vv[j]; + } + indx[j]=imax; + if (a[j][j] == 0.0) a[j][j]=TINY; + if (j != n) { + dum=1.0/(a[j][j]); + for (i=j+1;i<=n;i++) a[i][j] *= dum; + } + } + free_dvector(vv,1,n); +} +#undef TINY +#undef NRANSI +/* (C) Copr. 1986-92 Numerical Recipes Software J!0. */ diff --git a/contrib/NR/mnbrak.cpp b/contrib/NR/mnbrak.cpp new file mode 100644 index 0000000000..9aedccc886 --- /dev/null +++ b/contrib/NR/mnbrak.cpp @@ -0,0 +1,67 @@ +#include <math.h> +#define NRANSI +#include "nrutil.h" +#define GOLD 1.618034 +#define GLIMIT 100.0 +#define TINY 1.0e-20 +#define SHFT(a,b,c,d) (a)=(b);(b)=(c);(c)=(d); + +/* This file has been modified for inclusion in Gmsh (float->double) */ + +void mnbrak(double *ax, double *bx, double *cx, double *fa, double *fb, double *fc, + double (*func)(double)) +{ + double ulim,u,r,q,fu,dum; + + *fa=(*func)(*ax); + *fb=(*func)(*bx); + if (*fb > *fa) { + SHFT(dum,*ax,*bx,dum) + SHFT(dum,*fb,*fa,dum) + } + *cx=(*bx)+GOLD*(*bx-*ax); + *fc=(*func)(*cx); + while (*fb > *fc) { + r=(*bx-*ax)*(*fb-*fc); + q=(*bx-*cx)*(*fb-*fa); + u=(*bx)-((*bx-*cx)*q-(*bx-*ax)*r)/ + (2.0*SIGN(FMAX(fabs(q-r),TINY),q-r)); + ulim=(*bx)+GLIMIT*(*cx-*bx); + if ((*bx-u)*(u-*cx) > 0.0) { + fu=(*func)(u); + if (fu < *fc) { + *ax=(*bx); + *bx=u; + *fa=(*fb); + *fb=fu; + return; + } else if (fu > *fb) { + *cx=u; + *fc=fu; + return; + } + u=(*cx)+GOLD*(*cx-*bx); + fu=(*func)(u); + } else if ((*cx-u)*(u-ulim) > 0.0) { + fu=(*func)(u); + if (fu < *fc) { + SHFT(*bx,*cx,u,*cx+GOLD*(*cx-*bx)) + SHFT(*fb,*fc,fu,(*func)(u)) + } + } else if ((u-ulim)*(ulim-*cx) >= 0.0) { + u=ulim; + fu=(*func)(u); + } else { + u=(*cx)+GOLD*(*cx-*bx); + fu=(*func)(u); + } + SHFT(*ax,*bx,*cx,u) + SHFT(*fa,*fb,*fc,fu) + } +} +#undef GOLD +#undef GLIMIT +#undef TINY +#undef SHFT +#undef NRANSI +/* (C) Copr. 1986-92 Numerical Recipes Software J!0. */ diff --git a/contrib/NR/newt.cpp b/contrib/NR/newt.cpp new file mode 100644 index 0000000000..b09482177e --- /dev/null +++ b/contrib/NR/newt.cpp @@ -0,0 +1,92 @@ +#include <math.h> +#define NRANSI +#include "nrutil.h" +#define MAXITS 200 +#define TOLF 1.0e-4 +#define TOLMIN 1.0e-6 +#define TOLX 1.0e-7 +#define STPMX 100.0 + +/* This file has been modified for inclusion in Gmsh (float->double) */ + +int nn; +double *fvec; +void (*nrfuncv)(int n, double v[], double f[]); +#define FREERETURN {free_dvector(fvec,1,n);free_dvector(xold,1,n);\ + free_dvector(p,1,n);free_dvector(g,1,n);free_dmatrix(fjac,1,n,1,n);\ + free_ivector(indx,1,n);return;} + +void newt(double x[], int n, int *check, + void (*vecfunc)(int, double [], double [])) +{ + void fdjac(int n, double x[], double fvec[], double **df, + void (*vecfunc)(int, double [], double [])); + double fmin(double x[]); + void lnsrch(int n, double xold[], double fold, double g[], double p[], double x[], + double *f, double stpmax, int *check, double (*func)(double [])); + void lubksb(double **a, int n, int *indx, double b[]); + void ludcmp(double **a, int n, int *indx, double *d); + int i,its,j,*indx; + double d,den,f,fold,stpmax,sum,temp,test,**fjac,*g,*p,*xold; + + indx=ivector(1,n); + fjac=dmatrix(1,n,1,n); + g=dvector(1,n); + p=dvector(1,n); + xold=dvector(1,n); + fvec=dvector(1,n); + nn=n; + nrfuncv=vecfunc; + f=fmin(x); + test=0.0; + for (i=1;i<=n;i++) + if (fabs(fvec[i]) > test) test=fabs(fvec[i]); + if (test<0.01*TOLF) FREERETURN + for (sum=0.0,i=1;i<=n;i++) sum += SQR(x[i]); + stpmax=STPMX*FMAX(sqrt(sum),(double)n); + for (its=1;its<=MAXITS;its++) { + fdjac(n,x,fvec,fjac,vecfunc); + for (i=1;i<=n;i++) { + for (sum=0.0,j=1;j<=n;j++) sum += fjac[j][i]*fvec[j]; + g[i]=sum; + } + for (i=1;i<=n;i++) xold[i]=x[i]; + fold=f; + for (i=1;i<=n;i++) p[i] = -fvec[i]; + ludcmp(fjac,n,indx,&d); + lubksb(fjac,n,indx,p); + lnsrch(n,xold,fold,g,p,x,&f,stpmax,check,fmin); + test=0.0; + for (i=1;i<=n;i++) + if (fabs(fvec[i]) > test) test=fabs(fvec[i]); + if (test < TOLF) { + *check=0; + FREERETURN + } + if (*check) { + test=0.0; + den=FMAX(f,0.5*n); + for (i=1;i<=n;i++) { + temp=fabs(g[i])*FMAX(fabs(x[i]),1.0)/den; + if (temp > test) test=temp; + } + *check=(test < TOLMIN ? 1 : 0); + FREERETURN + } + test=0.0; + for (i=1;i<=n;i++) { + temp=(fabs(x[i]-xold[i]))/FMAX(fabs(x[i]),1.0); + if (temp > test) test=temp; + } + if (test < TOLX) FREERETURN + } + nrerror("MAXITS exceeded in newt"); +} +#undef MAXITS +#undef TOLF +#undef TOLMIN +#undef TOLX +#undef STPMX +#undef FREERETURN +#undef NRANSI +/* (C) Copr. 1986-92 Numerical Recipes Software J!0. */ diff --git a/contrib/NR/nrutil.cpp b/contrib/NR/nrutil.cpp new file mode 100644 index 0000000000..8aeaf3a79e --- /dev/null +++ b/contrib/NR/nrutil.cpp @@ -0,0 +1,620 @@ +#define NRANSI +#if defined(__STDC__) || defined(ANSI) || defined(NRANSI) /* ANSI */ + +#include <stdio.h> +#include <stddef.h> +#include <stdlib.h> +#define NR_END 1 +#define FREE_ARG char* + +#include "Gmsh.h" + +void nrerror(char error_text[]) +/* Numerical Recipes standard error handler */ +{ + Msg(GERROR, "%s", error_text); + /* + fprintf(stderr,"Numerical Recipes run-time error...\n"); + fprintf(stderr,"%s\n",error_text); + fprintf(stderr,"...now exiting to system...\n"); + exit(1); + */ +} + +float *vector(long nl, long nh) +/* allocate a float vector with subscript range v[nl..nh] */ +{ + float *v; + + v=(float *)malloc((size_t) ((nh-nl+1+NR_END)*sizeof(float))); + if (!v) nrerror("allocation failure in vector()"); + return v-nl+NR_END; +} + +int *ivector(long nl, long nh) +/* allocate an int vector with subscript range v[nl..nh] */ +{ + int *v; + + v=(int *)malloc((size_t) ((nh-nl+1+NR_END)*sizeof(int))); + if (!v) nrerror("allocation failure in ivector()"); + return v-nl+NR_END; +} + +unsigned char *cvector(long nl, long nh) +/* allocate an unsigned char vector with subscript range v[nl..nh] */ +{ + unsigned char *v; + + v=(unsigned char *)malloc((size_t) ((nh-nl+1+NR_END)*sizeof(unsigned char))); + if (!v) nrerror("allocation failure in cvector()"); + return v-nl+NR_END; +} + +unsigned long *lvector(long nl, long nh) +/* allocate an unsigned long vector with subscript range v[nl..nh] */ +{ + unsigned long *v; + + v=(unsigned long *)malloc((size_t) ((nh-nl+1+NR_END)*sizeof(long))); + if (!v) nrerror("allocation failure in lvector()"); + return v-nl+NR_END; +} + +double *dvector(long nl, long nh) +/* allocate a double vector with subscript range v[nl..nh] */ +{ + double *v; + + v=(double *)malloc((size_t) ((nh-nl+1+NR_END)*sizeof(double))); + if (!v) nrerror("allocation failure in dvector()"); + return v-nl+NR_END; +} + +float **matrix(long nrl, long nrh, long ncl, long nch) +/* allocate a float matrix with subscript range m[nrl..nrh][ncl..nch] */ +{ + long i, nrow=nrh-nrl+1,ncol=nch-ncl+1; + float **m; + + /* allocate pointers to rows */ + m=(float **) malloc((size_t)((nrow+NR_END)*sizeof(float*))); + if (!m) nrerror("allocation failure 1 in matrix()"); + m += NR_END; + m -= nrl; + + /* allocate rows and set pointers to them */ + m[nrl]=(float *) malloc((size_t)((nrow*ncol+NR_END)*sizeof(float))); + if (!m[nrl]) nrerror("allocation failure 2 in matrix()"); + m[nrl] += NR_END; + m[nrl] -= ncl; + + for(i=nrl+1;i<=nrh;i++) m[i]=m[i-1]+ncol; + + /* return pointer to array of pointers to rows */ + return m; +} + +double **dmatrix(long nrl, long nrh, long ncl, long nch) +/* allocate a double matrix with subscript range m[nrl..nrh][ncl..nch] */ +{ + long i, nrow=nrh-nrl+1,ncol=nch-ncl+1; + double **m; + + /* allocate pointers to rows */ + m=(double **) malloc((size_t)((nrow+NR_END)*sizeof(double*))); + if (!m) nrerror("allocation failure 1 in matrix()"); + m += NR_END; + m -= nrl; + + /* allocate rows and set pointers to them */ + m[nrl]=(double *) malloc((size_t)((nrow*ncol+NR_END)*sizeof(double))); + if (!m[nrl]) nrerror("allocation failure 2 in matrix()"); + m[nrl] += NR_END; + m[nrl] -= ncl; + + for(i=nrl+1;i<=nrh;i++) m[i]=m[i-1]+ncol; + + /* return pointer to array of pointers to rows */ + return m; +} + +int **imatrix(long nrl, long nrh, long ncl, long nch) +/* allocate a int matrix with subscript range m[nrl..nrh][ncl..nch] */ +{ + long i, nrow=nrh-nrl+1,ncol=nch-ncl+1; + int **m; + + /* allocate pointers to rows */ + m=(int **) malloc((size_t)((nrow+NR_END)*sizeof(int*))); + if (!m) nrerror("allocation failure 1 in matrix()"); + m += NR_END; + m -= nrl; + + + /* allocate rows and set pointers to them */ + m[nrl]=(int *) malloc((size_t)((nrow*ncol+NR_END)*sizeof(int))); + if (!m[nrl]) nrerror("allocation failure 2 in matrix()"); + m[nrl] += NR_END; + m[nrl] -= ncl; + + for(i=nrl+1;i<=nrh;i++) m[i]=m[i-1]+ncol; + + /* return pointer to array of pointers to rows */ + return m; +} + +float **submatrix(float **a, long oldrl, long oldrh, long oldcl, long oldch, + long newrl, long newcl) +/* point a submatrix [newrl..][newcl..] to a[oldrl..oldrh][oldcl..oldch] */ +{ + long i,j,nrow=oldrh-oldrl+1,ncol=oldcl-newcl; + float **m; + + /* allocate array of pointers to rows */ + m=(float **) malloc((size_t) ((nrow+NR_END)*sizeof(float*))); + if (!m) nrerror("allocation failure in submatrix()"); + m += NR_END; + m -= newrl; + + /* set pointers to rows */ + for(i=oldrl,j=newrl;i<=oldrh;i++,j++) m[j]=a[i]+ncol; + + /* return pointer to array of pointers to rows */ + return m; +} + +float **convert_matrix(float *a, long nrl, long nrh, long ncl, long nch) +/* allocate a float matrix m[nrl..nrh][ncl..nch] that points to the matrix +declared in the standard C manner as a[nrow][ncol], where nrow=nrh-nrl+1 +and ncol=nch-ncl+1. The routine should be called with the address +&a[0][0] as the first argument. */ +{ + long i,j,nrow=nrh-nrl+1,ncol=nch-ncl+1; + float **m; + + /* allocate pointers to rows */ + m=(float **) malloc((size_t) ((nrow+NR_END)*sizeof(float*))); + if (!m) nrerror("allocation failure in convert_matrix()"); + m += NR_END; + m -= nrl; + + /* set pointers to rows */ + m[nrl]=a-ncl; + for(i=1,j=nrl+1;i<nrow;i++,j++) m[j]=m[j-1]+ncol; + /* return pointer to array of pointers to rows */ + return m; +} + +float ***f3tensor(long nrl, long nrh, long ncl, long nch, long ndl, long ndh) +/* allocate a float 3tensor with range t[nrl..nrh][ncl..nch][ndl..ndh] */ +{ + long i,j,nrow=nrh-nrl+1,ncol=nch-ncl+1,ndep=ndh-ndl+1; + float ***t; + + /* allocate pointers to pointers to rows */ + t=(float ***) malloc((size_t)((nrow+NR_END)*sizeof(float**))); + if (!t) nrerror("allocation failure 1 in f3tensor()"); + t += NR_END; + t -= nrl; + + /* allocate pointers to rows and set pointers to them */ + t[nrl]=(float **) malloc((size_t)((nrow*ncol+NR_END)*sizeof(float*))); + if (!t[nrl]) nrerror("allocation failure 2 in f3tensor()"); + t[nrl] += NR_END; + t[nrl] -= ncl; + + /* allocate rows and set pointers to them */ + t[nrl][ncl]=(float *) malloc((size_t)((nrow*ncol*ndep+NR_END)*sizeof(float))); + if (!t[nrl][ncl]) nrerror("allocation failure 3 in f3tensor()"); + t[nrl][ncl] += NR_END; + t[nrl][ncl] -= ndl; + + for(j=ncl+1;j<=nch;j++) t[nrl][j]=t[nrl][j-1]+ndep; + for(i=nrl+1;i<=nrh;i++) { + t[i]=t[i-1]+ncol; + t[i][ncl]=t[i-1][ncl]+ncol*ndep; + for(j=ncl+1;j<=nch;j++) t[i][j]=t[i][j-1]+ndep; + } + + /* return pointer to array of pointers to rows */ + return t; +} + +void free_vector(float *v, long nl, long nh) +/* free a float vector allocated with vector() */ +{ + free((FREE_ARG) (v+nl-NR_END)); +} + +void free_ivector(int *v, long nl, long nh) +/* free an int vector allocated with ivector() */ +{ + free((FREE_ARG) (v+nl-NR_END)); +} + +void free_cvector(unsigned char *v, long nl, long nh) +/* free an unsigned char vector allocated with cvector() */ +{ + free((FREE_ARG) (v+nl-NR_END)); +} + +void free_lvector(unsigned long *v, long nl, long nh) +/* free an unsigned long vector allocated with lvector() */ +{ + free((FREE_ARG) (v+nl-NR_END)); +} + +void free_dvector(double *v, long nl, long nh) +/* free a double vector allocated with dvector() */ +{ + free((FREE_ARG) (v+nl-NR_END)); +} + +void free_matrix(float **m, long nrl, long nrh, long ncl, long nch) +/* free a float matrix allocated by matrix() */ +{ + free((FREE_ARG) (m[nrl]+ncl-NR_END)); + free((FREE_ARG) (m+nrl-NR_END)); +} + +void free_dmatrix(double **m, long nrl, long nrh, long ncl, long nch) +/* free a double matrix allocated by dmatrix() */ +{ + free((FREE_ARG) (m[nrl]+ncl-NR_END)); + free((FREE_ARG) (m+nrl-NR_END)); +} + +void free_imatrix(int **m, long nrl, long nrh, long ncl, long nch) +/* free an int matrix allocated by imatrix() */ +{ + free((FREE_ARG) (m[nrl]+ncl-NR_END)); + free((FREE_ARG) (m+nrl-NR_END)); +} + +void free_submatrix(float **b, long nrl, long nrh, long ncl, long nch) +/* free a submatrix allocated by submatrix() */ +{ + free((FREE_ARG) (b+nrl-NR_END)); +} + +void free_convert_matrix(float **b, long nrl, long nrh, long ncl, long nch) +/* free a matrix allocated by convert_matrix() */ +{ + free((FREE_ARG) (b+nrl-NR_END)); +} + +void free_f3tensor(float ***t, long nrl, long nrh, long ncl, long nch, + long ndl, long ndh) +/* free a float f3tensor allocated by f3tensor() */ +{ + free((FREE_ARG) (t[nrl][ncl]+ndl-NR_END)); + free((FREE_ARG) (t[nrl]+ncl-NR_END)); + free((FREE_ARG) (t+nrl-NR_END)); +} + +#else /* ANSI */ +/* traditional - K&R */ + +#include <stdio.h> +#define NR_END 1 +#define FREE_ARG char* + +void nrerror(error_text) +char error_text[]; +/* Numerical Recipes standard error handler */ +{ + void exit(); + + fprintf(stderr,"Numerical Recipes run-time error...\n"); + fprintf(stderr,"%s\n",error_text); + fprintf(stderr,"...now exiting to system...\n"); + exit(1); +} + +float *vector(nl,nh) +long nh,nl; +/* allocate a float vector with subscript range v[nl..nh] */ +{ + float *v; + + v=(float *)malloc((unsigned int) ((nh-nl+1+NR_END)*sizeof(float))); + if (!v) nrerror("allocation failure in vector()"); + return v-nl+NR_END; +} + +int *ivector(nl,nh) +long nh,nl; +/* allocate an int vector with subscript range v[nl..nh] */ +{ + int *v; + + v=(int *)malloc((unsigned int) ((nh-nl+1+NR_END)*sizeof(int))); + if (!v) nrerror("allocation failure in ivector()"); + return v-nl+NR_END; +} + +unsigned char *cvector(nl,nh) +long nh,nl; +/* allocate an unsigned char vector with subscript range v[nl..nh] */ +{ + unsigned char *v; + + v=(unsigned char *)malloc((unsigned int) ((nh-nl+1+NR_END)*sizeof(unsigned char))); + if (!v) nrerror("allocation failure in cvector()"); + return v-nl+NR_END; +} + +unsigned long *lvector(nl,nh) +long nh,nl; +/* allocate an unsigned long vector with subscript range v[nl..nh] */ +{ + unsigned long *v; + + v=(unsigned long *)malloc((unsigned int) ((nh-nl+1+NR_END)*sizeof(long))); + if (!v) nrerror("allocation failure in lvector()"); + return v-nl+NR_END; +} + +double *dvector(nl,nh) +long nh,nl; +/* allocate a double vector with subscript range v[nl..nh] */ +{ + double *v; + + v=(double *)malloc((unsigned int) ((nh-nl+1+NR_END)*sizeof(double))); + if (!v) nrerror("allocation failure in dvector()"); + return v-nl+NR_END; +} + +float **matrix(nrl,nrh,ncl,nch) +long nch,ncl,nrh,nrl; +/* allocate a float matrix with subscript range m[nrl..nrh][ncl..nch] */ +{ + long i, nrow=nrh-nrl+1,ncol=nch-ncl+1; + float **m; + + /* allocate pointers to rows */ + m=(float **) malloc((unsigned int)((nrow+NR_END)*sizeof(float*))); + if (!m) nrerror("allocation failure 1 in matrix()"); + m += NR_END; + m -= nrl; + + /* allocate rows and set pointers to them */ + m[nrl]=(float *) malloc((unsigned int)((nrow*ncol+NR_END)*sizeof(float))); + if (!m[nrl]) nrerror("allocation failure 2 in matrix()"); + m[nrl] += NR_END; + m[nrl] -= ncl; + + for(i=nrl+1;i<=nrh;i++) m[i]=m[i-1]+ncol; + + /* return pointer to array of pointers to rows */ + return m; +} + +double **dmatrix(nrl,nrh,ncl,nch) +long nch,ncl,nrh,nrl; +/* allocate a double matrix with subscript range m[nrl..nrh][ncl..nch] */ +{ + long i, nrow=nrh-nrl+1,ncol=nch-ncl+1; + double **m; + + /* allocate pointers to rows */ + m=(double **) malloc((unsigned int)((nrow+NR_END)*sizeof(double*))); + if (!m) nrerror("allocation failure 1 in matrix()"); + m += NR_END; + m -= nrl; + + /* allocate rows and set pointers to them */ + m[nrl]=(double *) malloc((unsigned int)((nrow*ncol+NR_END)*sizeof(double))); + if (!m[nrl]) nrerror("allocation failure 2 in matrix()"); + m[nrl] += NR_END; + m[nrl] -= ncl; + + for(i=nrl+1;i<=nrh;i++) m[i]=m[i-1]+ncol; + + /* return pointer to array of pointers to rows */ + return m; +} + +int **imatrix(nrl,nrh,ncl,nch) +long nch,ncl,nrh,nrl; +/* allocate a int matrix with subscript range m[nrl..nrh][ncl..nch] */ +{ + long i, nrow=nrh-nrl+1,ncol=nch-ncl+1; + int **m; + + /* allocate pointers to rows */ + m=(int **) malloc((unsigned int)((nrow+NR_END)*sizeof(int*))); + if (!m) nrerror("allocation failure 1 in matrix()"); + m += NR_END; + m -= nrl; + + + /* allocate rows and set pointers to them */ + m[nrl]=(int *) malloc((unsigned int)((nrow*ncol+NR_END)*sizeof(int))); + if (!m[nrl]) nrerror("allocation failure 2 in matrix()"); + m[nrl] += NR_END; + m[nrl] -= ncl; + + for(i=nrl+1;i<=nrh;i++) m[i]=m[i-1]+ncol; + + /* return pointer to array of pointers to rows */ + return m; +} + +float **submatrix(a,oldrl,oldrh,oldcl,oldch,newrl,newcl) +float **a; +long newcl,newrl,oldch,oldcl,oldrh,oldrl; +/* point a submatrix [newrl..][newcl..] to a[oldrl..oldrh][oldcl..oldch] */ +{ + long i,j,nrow=oldrh-oldrl+1,ncol=oldcl-newcl; + float **m; + + /* allocate array of pointers to rows */ + m=(float **) malloc((unsigned int) ((nrow+NR_END)*sizeof(float*))); + if (!m) nrerror("allocation failure in submatrix()"); + m += NR_END; + m -= newrl; + + /* set pointers to rows */ + for(i=oldrl,j=newrl;i<=oldrh;i++,j++) m[j]=a[i]+ncol; + + /* return pointer to array of pointers to rows */ + return m; +} + +float **convert_matrix(a,nrl,nrh,ncl,nch) +float *a; +long nch,ncl,nrh,nrl; +/* allocate a float matrix m[nrl..nrh][ncl..nch] that points to the matrix +declared in the standard C manner as a[nrow][ncol], where nrow=nrh-nrl+1 +and ncol=nch-ncl+1. The routine should be called with the address +&a[0][0] as the first argument. */ +{ + long i,j,nrow=nrh-nrl+1,ncol=nch-ncl+1; + float **m; + + /* allocate pointers to rows */ + m=(float **) malloc((unsigned int) ((nrow+NR_END)*sizeof(float*))); + if (!m) nrerror("allocation failure in convert_matrix()"); + m += NR_END; + m -= nrl; + + /* set pointers to rows */ + m[nrl]=a-ncl; + for(i=1,j=nrl+1;i<nrow;i++,j++) m[j]=m[j-1]+ncol; + /* return pointer to array of pointers to rows */ + return m; +} + +float ***f3tensor(nrl,nrh,ncl,nch,ndl,ndh) +long nch,ncl,ndh,ndl,nrh,nrl; +/* allocate a float 3tensor with range t[nrl..nrh][ncl..nch][ndl..ndh] */ +{ + long i,j,nrow=nrh-nrl+1,ncol=nch-ncl+1,ndep=ndh-ndl+1; + float ***t; + + /* allocate pointers to pointers to rows */ + t=(float ***) malloc((unsigned int)((nrow+NR_END)*sizeof(float**))); + if (!t) nrerror("allocation failure 1 in f3tensor()"); + t += NR_END; + t -= nrl; + + /* allocate pointers to rows and set pointers to them */ + t[nrl]=(float **) malloc((unsigned int)((nrow*ncol+NR_END)*sizeof(float*))); + if (!t[nrl]) nrerror("allocation failure 2 in f3tensor()"); + t[nrl] += NR_END; + t[nrl] -= ncl; + + /* allocate rows and set pointers to them */ + t[nrl][ncl]=(float *) malloc((unsigned int)((nrow*ncol*ndep+NR_END)*sizeof(float))); + if (!t[nrl][ncl]) nrerror("allocation failure 3 in f3tensor()"); + t[nrl][ncl] += NR_END; + t[nrl][ncl] -= ndl; + + for(j=ncl+1;j<=nch;j++) t[nrl][j]=t[nrl][j-1]+ndep; + for(i=nrl+1;i<=nrh;i++) { + t[i]=t[i-1]+ncol; + t[i][ncl]=t[i-1][ncl]+ncol*ndep; + for(j=ncl+1;j<=nch;j++) t[i][j]=t[i][j-1]+ndep; + } + + /* return pointer to array of pointers to rows */ + return t; +} + +void free_vector(v,nl,nh) +float *v; +long nh,nl; +/* free a float vector allocated with vector() */ +{ + free((FREE_ARG) (v+nl-NR_END)); +} + +void free_ivector(v,nl,nh) +int *v; +long nh,nl; +/* free an int vector allocated with ivector() */ +{ + free((FREE_ARG) (v+nl-NR_END)); +} + +void free_cvector(v,nl,nh) +long nh,nl; +unsigned char *v; +/* free an unsigned char vector allocated with cvector() */ +{ + free((FREE_ARG) (v+nl-NR_END)); +} + +void free_lvector(v,nl,nh) +long nh,nl; +unsigned long *v; +/* free an unsigned long vector allocated with lvector() */ +{ + free((FREE_ARG) (v+nl-NR_END)); +} + +void free_dvector(v,nl,nh) +double *v; +long nh,nl; +/* free a double vector allocated with dvector() */ +{ + free((FREE_ARG) (v+nl-NR_END)); +} + +void free_matrix(m,nrl,nrh,ncl,nch) +float **m; +long nch,ncl,nrh,nrl; +/* free a float matrix allocated by matrix() */ +{ + free((FREE_ARG) (m[nrl]+ncl-NR_END)); + free((FREE_ARG) (m+nrl-NR_END)); +} + +void free_dmatrix(m,nrl,nrh,ncl,nch) +double **m; +long nch,ncl,nrh,nrl; +/* free a double matrix allocated by dmatrix() */ +{ + free((FREE_ARG) (m[nrl]+ncl-NR_END)); + free((FREE_ARG) (m+nrl-NR_END)); +} + +void free_imatrix(m,nrl,nrh,ncl,nch) +int **m; +long nch,ncl,nrh,nrl; +/* free an int matrix allocated by imatrix() */ +{ + free((FREE_ARG) (m[nrl]+ncl-NR_END)); + free((FREE_ARG) (m+nrl-NR_END)); +} + +void free_submatrix(b,nrl,nrh,ncl,nch) +float **b; +long nch,ncl,nrh,nrl; +/* free a submatrix allocated by submatrix() */ +{ + free((FREE_ARG) (b+nrl-NR_END)); +} + +void free_convert_matrix(b,nrl,nrh,ncl,nch) +float **b; +long nch,ncl,nrh,nrl; +/* free a matrix allocated by convert_matrix() */ +{ + free((FREE_ARG) (b+nrl-NR_END)); +} + +void free_f3tensor(t,nrl,nrh,ncl,nch,ndl,ndh) +float ***t; +long nch,ncl,ndh,ndl,nrh,nrl; +/* free a float f3tensor allocated by f3tensor() */ +{ + free((FREE_ARG) (t[nrl][ncl]+ndl-NR_END)); + free((FREE_ARG) (t[nrl]+ncl-NR_END)); + free((FREE_ARG) (t+nrl-NR_END)); +} + +#endif /* ANSI */ diff --git a/contrib/NR/nrutil.h b/contrib/NR/nrutil.h new file mode 100644 index 0000000000..436193de5e --- /dev/null +++ b/contrib/NR/nrutil.h @@ -0,0 +1,109 @@ +#ifndef _NR_UTILS_H_ +#define _NR_UTILS_H_ + +/* This file has been modified for inclusion in Gmsh */ + +/* Gmsh: */ +#include "Gmsh.h" +#include "Numeric.h" + +/* Gmsh: +static float sqrarg; +#define SQR(a) ((sqrarg=(a)) == 0.0 ? 0.0 : sqrarg*sqrarg) + +static double dsqrarg; +#define DSQR(a) ((dsqrarg=(a)) == 0.0 ? 0.0 : dsqrarg*dsqrarg) + +static double dmaxarg1,dmaxarg2; +#define DMAX(a,b) (dmaxarg1=(a),dmaxarg2=(b),(dmaxarg1) > (dmaxarg2) ?\ + (dmaxarg1) : (dmaxarg2)) + +static double dminarg1,dminarg2; +#define DMIN(a,b) (dminarg1=(a),dminarg2=(b),(dminarg1) < (dminarg2) ?\ + (dminarg1) : (dminarg2)) + +static float maxarg1,maxarg2; +#define FMAX(a,b) (maxarg1=(a),maxarg2=(b),(maxarg1) > (maxarg2) ?\ + (maxarg1) : (maxarg2)) + +static float minarg1,minarg2; +#define FMIN(a,b) (minarg1=(a),minarg2=(b),(minarg1) < (minarg2) ?\ + (minarg1) : (minarg2)) + +static long lmaxarg1,lmaxarg2; +#define LMAX(a,b) (lmaxarg1=(a),lmaxarg2=(b),(lmaxarg1) > (lmaxarg2) ?\ + (lmaxarg1) : (lmaxarg2)) + +static long lminarg1,lminarg2; +#define LMIN(a,b) (lminarg1=(a),lminarg2=(b),(lminarg1) < (lminarg2) ?\ + (lminarg1) : (lminarg2)) + +static int imaxarg1,imaxarg2; +#define IMAX(a,b) (imaxarg1=(a),imaxarg2=(b),(imaxarg1) > (imaxarg2) ?\ + (imaxarg1) : (imaxarg2)) + +static int iminarg1,iminarg2; +#define IMIN(a,b) (iminarg1=(a),iminarg2=(b),(iminarg1) < (iminarg2) ?\ + (iminarg1) : (iminarg2)) + +#define SIGN(a,b) ((b) >= 0.0 ? fabs(a) : -fabs(a)) +*/ + +#if defined(__STDC__) || defined(ANSI) || defined(NRANSI) /* ANSI */ + +void nrerror(char error_text[]); +float *vector(long nl, long nh); +int *ivector(long nl, long nh); +unsigned char *cvector(long nl, long nh); +unsigned long *lvector(long nl, long nh); +double *dvector(long nl, long nh); +float **matrix(long nrl, long nrh, long ncl, long nch); +double **dmatrix(long nrl, long nrh, long ncl, long nch); +int **imatrix(long nrl, long nrh, long ncl, long nch); +float **submatrix(float **a, long oldrl, long oldrh, long oldcl, long oldch, + long newrl, long newcl); +float **convert_matrix(float *a, long nrl, long nrh, long ncl, long nch); +float ***f3tensor(long nrl, long nrh, long ncl, long nch, long ndl, long ndh); +void free_vector(float *v, long nl, long nh); +void free_ivector(int *v, long nl, long nh); +void free_cvector(unsigned char *v, long nl, long nh); +void free_lvector(unsigned long *v, long nl, long nh); +void free_dvector(double *v, long nl, long nh); +void free_matrix(float **m, long nrl, long nrh, long ncl, long nch); +void free_dmatrix(double **m, long nrl, long nrh, long ncl, long nch); +void free_imatrix(int **m, long nrl, long nrh, long ncl, long nch); +void free_submatrix(float **b, long nrl, long nrh, long ncl, long nch); +void free_convert_matrix(float **b, long nrl, long nrh, long ncl, long nch); +void free_f3tensor(float ***t, long nrl, long nrh, long ncl, long nch, + long ndl, long ndh); + +#else /* ANSI */ +/* traditional - K&R */ + +void nrerror(); +float *vector(); +float **matrix(); +float **submatrix(); +float **convert_matrix(); +float ***f3tensor(); +double *dvector(); +double **dmatrix(); +int *ivector(); +int **imatrix(); +unsigned char *cvector(); +unsigned long *lvector(); +void free_vector(); +void free_dvector(); +void free_ivector(); +void free_cvector(); +void free_lvector(); +void free_matrix(); +void free_submatrix(); +void free_convert_matrix(); +void free_dmatrix(); +void free_imatrix(); +void free_f3tensor(); + +#endif /* ANSI */ + +#endif /* _NR_UTILS_H_ */ diff --git a/contrib/Netgen/COPYING.LIB b/contrib/Netgen/COPYING.LIB new file mode 100644 index 0000000000..b1e3f5a263 --- /dev/null +++ b/contrib/Netgen/COPYING.LIB @@ -0,0 +1,504 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + <one line to give the library's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + <signature of Ty Coon>, 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! + + diff --git a/contrib/Netgen/Makefile b/contrib/Netgen/Makefile new file mode 100644 index 0000000000..c339277943 --- /dev/null +++ b/contrib/Netgen/Makefile @@ -0,0 +1,4412 @@ +# $Id: Makefile,v 1.1 2005-09-21 17:29:38 geuzaine Exp $ +# +# Copyright (C) 1997-2005 C. Geuzaine, J.-F. Remacle +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +# USA. +# +# Please report all bugs and problems to <gmsh@geuz.org>. + +include ../../variables + +LIB = ../../lib/libGmshNetgen.a +INCLUDE = -I../../Common -Ilibsrc/include -Ilibsrc/interface +CFLAGS = ${OPTIM} ${FLAGS} ${INCLUDE} -DNO_PARALLEL_THREADS -UWIN32 + +SRC = libsrc/opti/linopt.cpp \ + libsrc/opti/bfgs.cpp \ + libsrc/opti/linsearch.cpp \ + libsrc/meshing/global.cpp \ + libsrc/meshing/bisect.cpp \ + libsrc/meshing/meshtool.cpp \ + libsrc/meshing/refine.cpp \ + libsrc/meshing/ruler3.cpp \ + libsrc/meshing/improve3.cpp \ + libsrc/meshing/smoothing3.cpp \ + libsrc/meshing/adfront3.cpp \ + libsrc/meshing/tetrarls.cpp \ + libsrc/meshing/prism2rls.cpp \ + libsrc/meshing/pyramidrls.cpp \ + libsrc/meshing/pyramid2rls.cpp \ + libsrc/meshing/netrule3.cpp \ + libsrc/meshing/ruler2.cpp \ + libsrc/meshing/meshclass.cpp \ + libsrc/meshing/improve2.cpp \ + libsrc/meshing/smoothing2.cpp \ + libsrc/meshing/adfront2.cpp \ + libsrc/meshing/netrule2.cpp \ + libsrc/meshing/triarls.cpp \ + libsrc/meshing/geomsearch.cpp \ + libsrc/meshing/secondorder.cpp \ + libsrc/meshing/meshtype.cpp \ + libsrc/meshing/parser3.cpp \ + libsrc/meshing/meshing2.cpp \ + libsrc/meshing/quadrls.cpp \ + libsrc/meshing/specials.cpp \ + libsrc/meshing/parser2.cpp \ + libsrc/meshing/meshing3.cpp \ + libsrc/meshing/meshfunc.cpp \ + libsrc/meshing/localh.cpp \ + libsrc/meshing/improve2gen.cpp \ + libsrc/meshing/delaunay.cpp \ + libsrc/meshing/boundarylayer.cpp \ + libsrc/meshing/msghandler.cpp \ + libsrc/meshing/meshfunc2d.cpp \ + libsrc/meshing/topology.cpp \ + libsrc/meshing/clusters.cpp \ + libsrc/meshing/curvedelems.cpp \ + libsrc/meshing/curvedelems2.cpp \ + libsrc/meshing/hprefinement.cpp \ + libsrc/interface/nglib.cpp \ + libsrc/gprim/geomtest3d.cpp \ + libsrc/gprim/geom2d.cpp \ + libsrc/gprim/geom3d.cpp \ + libsrc/gprim/adtree.cpp \ + libsrc/gprim/transform3d.cpp \ + libsrc/gprim/geomfuncs.cpp \ + libsrc/linalg/polynomial.cpp \ + libsrc/linalg/densemat.cpp \ + libsrc/linalg/vector.cpp \ + libsrc/csg/algprim.cpp \ + libsrc/csg/brick.cpp \ + libsrc/csg/manifold.cpp \ + libsrc/csg/bspline2d.cpp \ + libsrc/csg/meshsurf.cpp \ + libsrc/csg/csgeom.cpp \ + libsrc/csg/polyhedra.cpp \ + libsrc/csg/curve2d.cpp \ + libsrc/csg/singularref.cpp \ + libsrc/csg/edgeflw.cpp \ + libsrc/csg/solid.cpp \ + libsrc/csg/explicitcurve2d.cpp \ + libsrc/csg/specpoin.cpp \ + libsrc/csg/gencyl.cpp \ + libsrc/csg/revolution.cpp \ + libsrc/csg/genmesh.cpp \ + libsrc/csg/spline3d.cpp \ + libsrc/csg/surface.cpp \ + libsrc/csg/identify.cpp \ + libsrc/csg/triapprox.cpp \ + libsrc/geom2d/geom2dmesh.cpp \ + libsrc/geom2d/spline2d.cpp \ + libsrc/geom2d/splinegeometry2.cpp \ + libsrc/geom2d/genmesh2d.cpp \ + libsrc/stlgeom/meshstlsurface.cpp \ + libsrc/stlgeom/stlline.cpp \ + libsrc/stlgeom/stltopology.cpp \ + libsrc/stlgeom/stltool.cpp \ + libsrc/stlgeom/stlgeom.cpp \ + libsrc/stlgeom/stlgeomchart.cpp \ + libsrc/stlgeom/stlgeommesh.cpp \ + libsrc/general/moveablemem.cpp \ + libsrc/general/ngexception.cpp \ + libsrc/general/table.cpp \ + libsrc/general/optmem.cpp \ + libsrc/general/spbita2d.cpp \ + libsrc/general/hashtabl.cpp \ + libsrc/general/sort.cpp \ + libsrc/general/flags.cpp \ + libsrc/general/seti.cpp \ + libsrc/general/bitarray.cpp \ + libsrc/general/array.cpp \ + libsrc/general/symbolta.cpp \ + libsrc/general/mystring.cpp \ + nglib_addon.cpp + +OBJ = ${SRC:.cpp=.o} + +.SUFFIXES: .o .cpp + +${LIB}: ${OBJ} + ${AR} ${LIB} ${OBJ} + ${RANLIB} ${LIB} + +.cpp.o: + ${CXX} ${CFLAGS} -c $< -o ${<:.cpp=.o} + +clean: + rm -f libsrc/*/*.o + +depend: + (sed '/^# DO NOT DELETE THIS LINE/q' Makefile && \ + ${CXX} -MM ${CFLAGS} ${SRC} \ + ) >Makefile.new + cp Makefile Makefile.bak + cp Makefile.new Makefile + rm -f Makefile.new + +# DO NOT DELETE THIS LINE +# 1 "/Users/geuzaine/.gmsh/Netgen//" +linopt.o: libsrc/opti/linopt.cpp libsrc/include/mystdlib.h \ + libsrc/include/myadt.hpp libsrc/include/../general/myadt.hpp \ + libsrc/include/mydefs.hpp libsrc/include/../general/ngexception.hpp \ + libsrc/include/../general/parthreads.hpp \ + libsrc/include/../general/moveablemem.hpp \ + libsrc/include/../general/dynamicmem.hpp \ + libsrc/include/../general/template.hpp \ + libsrc/include/../general/array.hpp libsrc/include/../general/table.hpp \ + libsrc/include/../general/hashtabl.hpp \ + libsrc/include/../general/symbolta.hpp \ + libsrc/include/../general/bitarray.hpp \ + libsrc/include/../general/flags.hpp \ + libsrc/include/../general/spbita2d.hpp \ + libsrc/include/../general/seti.hpp libsrc/include/../general/optmem.hpp \ + libsrc/include/../general/autoptr.hpp \ + libsrc/include/../general/sort.hpp libsrc/include/../general/stack.hpp \ + libsrc/include/../general/mystring.hpp libsrc/include/linalg.hpp \ + libsrc/include/../linalg/linalg.hpp libsrc/include/../linalg/vector.hpp \ + libsrc/include/../linalg/densemat.hpp \ + libsrc/include/../linalg/polynomial.hpp libsrc/opti/opti.hpp +# 1 "/Users/geuzaine/.gmsh/Netgen//" +bfgs.o: libsrc/opti/bfgs.cpp libsrc/include/mystdlib.h \ + libsrc/include/myadt.hpp libsrc/include/../general/myadt.hpp \ + libsrc/include/mydefs.hpp libsrc/include/../general/ngexception.hpp \ + libsrc/include/../general/parthreads.hpp \ + libsrc/include/../general/moveablemem.hpp \ + libsrc/include/../general/dynamicmem.hpp \ + libsrc/include/../general/template.hpp \ + libsrc/include/../general/array.hpp libsrc/include/../general/table.hpp \ + libsrc/include/../general/hashtabl.hpp \ + libsrc/include/../general/symbolta.hpp \ + libsrc/include/../general/bitarray.hpp \ + libsrc/include/../general/flags.hpp \ + libsrc/include/../general/spbita2d.hpp \ + libsrc/include/../general/seti.hpp libsrc/include/../general/optmem.hpp \ + libsrc/include/../general/autoptr.hpp \ + libsrc/include/../general/sort.hpp libsrc/include/../general/stack.hpp \ + libsrc/include/../general/mystring.hpp libsrc/include/linalg.hpp \ + libsrc/include/../linalg/linalg.hpp libsrc/include/../linalg/vector.hpp \ + libsrc/include/../linalg/densemat.hpp \ + libsrc/include/../linalg/polynomial.hpp libsrc/opti/opti.hpp +# 1 "/Users/geuzaine/.gmsh/Netgen//" +linsearch.o: libsrc/opti/linsearch.cpp libsrc/include/mystdlib.h \ + libsrc/include/myadt.hpp libsrc/include/../general/myadt.hpp \ + libsrc/include/mydefs.hpp libsrc/include/../general/ngexception.hpp \ + libsrc/include/../general/parthreads.hpp \ + libsrc/include/../general/moveablemem.hpp \ + libsrc/include/../general/dynamicmem.hpp \ + libsrc/include/../general/template.hpp \ + libsrc/include/../general/array.hpp libsrc/include/../general/table.hpp \ + libsrc/include/../general/hashtabl.hpp \ + libsrc/include/../general/symbolta.hpp \ + libsrc/include/../general/bitarray.hpp \ + libsrc/include/../general/flags.hpp \ + libsrc/include/../general/spbita2d.hpp \ + libsrc/include/../general/seti.hpp libsrc/include/../general/optmem.hpp \ + libsrc/include/../general/autoptr.hpp \ + libsrc/include/../general/sort.hpp libsrc/include/../general/stack.hpp \ + libsrc/include/../general/mystring.hpp libsrc/include/linalg.hpp \ + libsrc/include/../linalg/linalg.hpp libsrc/include/../linalg/vector.hpp \ + libsrc/include/../linalg/densemat.hpp \ + libsrc/include/../linalg/polynomial.hpp libsrc/opti/opti.hpp +# 1 "/Users/geuzaine/.gmsh/Netgen//" +global.o: libsrc/meshing/global.cpp libsrc/include/mystdlib.h \ + libsrc/meshing/meshing.hpp libsrc/include/myadt.hpp \ + libsrc/include/../general/myadt.hpp libsrc/include/mydefs.hpp \ + libsrc/include/../general/ngexception.hpp \ + libsrc/include/../general/parthreads.hpp \ + libsrc/include/../general/moveablemem.hpp \ + libsrc/include/../general/dynamicmem.hpp \ + libsrc/include/../general/template.hpp \ + libsrc/include/../general/array.hpp libsrc/include/../general/table.hpp \ + libsrc/include/../general/hashtabl.hpp \ + libsrc/include/../general/symbolta.hpp \ + libsrc/include/../general/bitarray.hpp \ + libsrc/include/../general/flags.hpp \ + libsrc/include/../general/spbita2d.hpp \ + libsrc/include/../general/seti.hpp libsrc/include/../general/optmem.hpp \ + libsrc/include/../general/autoptr.hpp \ + libsrc/include/../general/sort.hpp libsrc/include/../general/stack.hpp \ + libsrc/include/../general/mystring.hpp libsrc/include/gprim.hpp \ + libsrc/include/../gprim/gprim.hpp \ + libsrc/include/../gprim/geomobjects.hpp \ + libsrc/include/../gprim/geomops.hpp \ + libsrc/include/../gprim/geomfuncs.hpp \ + libsrc/include/../gprim/geom2d.hpp libsrc/include/../gprim/geom3d.hpp \ + libsrc/include/../gprim/geomtest3d.hpp \ + libsrc/include/../gprim/transform3d.hpp \ + libsrc/include/../gprim/adtree.hpp libsrc/include/linalg.hpp \ + libsrc/include/../linalg/linalg.hpp libsrc/include/../linalg/vector.hpp \ + libsrc/include/../linalg/densemat.hpp \ + libsrc/include/../linalg/polynomial.hpp libsrc/include/opti.hpp \ + libsrc/include/../opti/opti.hpp libsrc/meshing/msghandler.hpp \ + libsrc/meshing/meshtype.hpp libsrc/meshing/localh.hpp \ + libsrc/meshing/meshclass.hpp libsrc/meshing/global.hpp \ + libsrc/meshing/meshtool.hpp libsrc/meshing/ruler2.hpp \ + libsrc/meshing/adfront2.hpp libsrc/meshing/meshing2.hpp \ + libsrc/meshing/improve2.hpp libsrc/meshing/geomsearch.hpp \ + libsrc/meshing/adfront3.hpp libsrc/meshing/ruler3.hpp \ + libsrc/meshing/meshing3.hpp libsrc/meshing/improve3.hpp \ + libsrc/meshing/findip.hpp libsrc/meshing/topology.hpp \ + libsrc/meshing/curvedelems.hpp libsrc/meshing/bisect.hpp \ + libsrc/meshing/clusters.hpp libsrc/meshing/meshfunc.hpp \ + libsrc/meshing/hprefinement.hpp libsrc/meshing/boundarylayer.hpp \ + libsrc/meshing/specials.hpp +# 1 "/Users/geuzaine/.gmsh/Netgen//" +bisect.o: libsrc/meshing/bisect.cpp libsrc/include/mystdlib.h \ + libsrc/meshing/meshing.hpp libsrc/include/myadt.hpp \ + libsrc/include/../general/myadt.hpp libsrc/include/mydefs.hpp \ + libsrc/include/../general/ngexception.hpp \ + libsrc/include/../general/parthreads.hpp \ + libsrc/include/../general/moveablemem.hpp \ + libsrc/include/../general/dynamicmem.hpp \ + libsrc/include/../general/template.hpp \ + libsrc/include/../general/array.hpp libsrc/include/../general/table.hpp \ + libsrc/include/../general/hashtabl.hpp \ + libsrc/include/../general/symbolta.hpp \ + libsrc/include/../general/bitarray.hpp \ + libsrc/include/../general/flags.hpp \ + libsrc/include/../general/spbita2d.hpp \ + libsrc/include/../general/seti.hpp libsrc/include/../general/optmem.hpp \ + libsrc/include/../general/autoptr.hpp \ + libsrc/include/../general/sort.hpp libsrc/include/../general/stack.hpp \ + libsrc/include/../general/mystring.hpp libsrc/include/gprim.hpp \ + libsrc/include/../gprim/gprim.hpp \ + libsrc/include/../gprim/geomobjects.hpp \ + libsrc/include/../gprim/geomops.hpp \ + libsrc/include/../gprim/geomfuncs.hpp \ + libsrc/include/../gprim/geom2d.hpp libsrc/include/../gprim/geom3d.hpp \ + libsrc/include/../gprim/geomtest3d.hpp \ + libsrc/include/../gprim/transform3d.hpp \ + libsrc/include/../gprim/adtree.hpp libsrc/include/linalg.hpp \ + libsrc/include/../linalg/linalg.hpp libsrc/include/../linalg/vector.hpp \ + libsrc/include/../linalg/densemat.hpp \ + libsrc/include/../linalg/polynomial.hpp libsrc/include/opti.hpp \ + libsrc/include/../opti/opti.hpp libsrc/meshing/msghandler.hpp \ + libsrc/meshing/meshtype.hpp libsrc/meshing/localh.hpp \ + libsrc/meshing/meshclass.hpp libsrc/meshing/global.hpp \ + libsrc/meshing/meshtool.hpp libsrc/meshing/ruler2.hpp \ + libsrc/meshing/adfront2.hpp libsrc/meshing/meshing2.hpp \ + libsrc/meshing/improve2.hpp libsrc/meshing/geomsearch.hpp \ + libsrc/meshing/adfront3.hpp libsrc/meshing/ruler3.hpp \ + libsrc/meshing/meshing3.hpp libsrc/meshing/improve3.hpp \ + libsrc/meshing/findip.hpp libsrc/meshing/topology.hpp \ + libsrc/meshing/curvedelems.hpp libsrc/meshing/bisect.hpp \ + libsrc/meshing/clusters.hpp libsrc/meshing/meshfunc.hpp \ + libsrc/meshing/hprefinement.hpp libsrc/meshing/boundarylayer.hpp \ + libsrc/meshing/specials.hpp +# 1 "/Users/geuzaine/.gmsh/Netgen//" +meshtool.o: libsrc/meshing/meshtool.cpp libsrc/include/mystdlib.h \ + libsrc/meshing/meshing.hpp libsrc/include/myadt.hpp \ + libsrc/include/../general/myadt.hpp libsrc/include/mydefs.hpp \ + libsrc/include/../general/ngexception.hpp \ + libsrc/include/../general/parthreads.hpp \ + libsrc/include/../general/moveablemem.hpp \ + libsrc/include/../general/dynamicmem.hpp \ + libsrc/include/../general/template.hpp \ + libsrc/include/../general/array.hpp libsrc/include/../general/table.hpp \ + libsrc/include/../general/hashtabl.hpp \ + libsrc/include/../general/symbolta.hpp \ + libsrc/include/../general/bitarray.hpp \ + libsrc/include/../general/flags.hpp \ + libsrc/include/../general/spbita2d.hpp \ + libsrc/include/../general/seti.hpp libsrc/include/../general/optmem.hpp \ + libsrc/include/../general/autoptr.hpp \ + libsrc/include/../general/sort.hpp libsrc/include/../general/stack.hpp \ + libsrc/include/../general/mystring.hpp libsrc/include/gprim.hpp \ + libsrc/include/../gprim/gprim.hpp \ + libsrc/include/../gprim/geomobjects.hpp \ + libsrc/include/../gprim/geomops.hpp \ + libsrc/include/../gprim/geomfuncs.hpp \ + libsrc/include/../gprim/geom2d.hpp libsrc/include/../gprim/geom3d.hpp \ + libsrc/include/../gprim/geomtest3d.hpp \ + libsrc/include/../gprim/transform3d.hpp \ + libsrc/include/../gprim/adtree.hpp libsrc/include/linalg.hpp \ + libsrc/include/../linalg/linalg.hpp libsrc/include/../linalg/vector.hpp \ + libsrc/include/../linalg/densemat.hpp \ + libsrc/include/../linalg/polynomial.hpp libsrc/include/opti.hpp \ + libsrc/include/../opti/opti.hpp libsrc/meshing/msghandler.hpp \ + libsrc/meshing/meshtype.hpp libsrc/meshing/localh.hpp \ + libsrc/meshing/meshclass.hpp libsrc/meshing/global.hpp \ + libsrc/meshing/meshtool.hpp libsrc/meshing/ruler2.hpp \ + libsrc/meshing/adfront2.hpp libsrc/meshing/meshing2.hpp \ + libsrc/meshing/improve2.hpp libsrc/meshing/geomsearch.hpp \ + libsrc/meshing/adfront3.hpp libsrc/meshing/ruler3.hpp \ + libsrc/meshing/meshing3.hpp libsrc/meshing/improve3.hpp \ + libsrc/meshing/findip.hpp libsrc/meshing/topology.hpp \ + libsrc/meshing/curvedelems.hpp libsrc/meshing/bisect.hpp \ + libsrc/meshing/clusters.hpp libsrc/meshing/meshfunc.hpp \ + libsrc/meshing/hprefinement.hpp libsrc/meshing/boundarylayer.hpp \ + libsrc/meshing/specials.hpp libsrc/include/csg.hpp \ + libsrc/include/../csg/csg.hpp libsrc/include/../gprim/gprim.hpp \ + libsrc/include/meshing.hpp libsrc/include/../meshing/meshing.hpp \ + libsrc/include/../csg/surface.hpp libsrc/include/../csg/solid.hpp \ + libsrc/include/../csg/identify.hpp \ + libsrc/include/../csg/singularref.hpp libsrc/include/../csg/csgeom.hpp \ + libsrc/include/../csg/triapprox.hpp libsrc/include/../csg/algprim.hpp \ + libsrc/include/../csg/brick.hpp libsrc/include/../csg/spline3d.hpp \ + libsrc/include/../csg/manifold.hpp libsrc/include/../csg/curve2d.hpp \ + libsrc/include/../csg/explicitcurve2d.hpp \ + libsrc/include/../csg/gencyl.hpp libsrc/include/../csg/polyhedra.hpp \ + libsrc/include/../csg/extrusion.hpp \ + libsrc/include/../csg/revolution.hpp libsrc/include/../csg/specpoin.hpp \ + libsrc/include/../csg/edgeflw.hpp libsrc/include/../csg/meshsurf.hpp \ + libsrc/include/geometry2d.hpp libsrc/include/../geom2d/geometry2d.hpp \ + libsrc/include/../gprim/gprim.hpp libsrc/include/../geom2d/spline2d.hpp \ + libsrc/include/../geom2d/splinegeometry2.hpp \ + libsrc/include/../geom2d/geom2dmesh.hpp +# 1 "/Users/geuzaine/.gmsh/Netgen//" +refine.o: libsrc/meshing/refine.cpp libsrc/include/mystdlib.h \ + libsrc/meshing/meshing.hpp libsrc/include/myadt.hpp \ + libsrc/include/../general/myadt.hpp libsrc/include/mydefs.hpp \ + libsrc/include/../general/ngexception.hpp \ + libsrc/include/../general/parthreads.hpp \ + libsrc/include/../general/moveablemem.hpp \ + libsrc/include/../general/dynamicmem.hpp \ + libsrc/include/../general/template.hpp \ + libsrc/include/../general/array.hpp libsrc/include/../general/table.hpp \ + libsrc/include/../general/hashtabl.hpp \ + libsrc/include/../general/symbolta.hpp \ + libsrc/include/../general/bitarray.hpp \ + libsrc/include/../general/flags.hpp \ + libsrc/include/../general/spbita2d.hpp \ + libsrc/include/../general/seti.hpp libsrc/include/../general/optmem.hpp \ + libsrc/include/../general/autoptr.hpp \ + libsrc/include/../general/sort.hpp libsrc/include/../general/stack.hpp \ + libsrc/include/../general/mystring.hpp libsrc/include/gprim.hpp \ + libsrc/include/../gprim/gprim.hpp \ + libsrc/include/../gprim/geomobjects.hpp \ + libsrc/include/../gprim/geomops.hpp \ + libsrc/include/../gprim/geomfuncs.hpp \ + libsrc/include/../gprim/geom2d.hpp libsrc/include/../gprim/geom3d.hpp \ + libsrc/include/../gprim/geomtest3d.hpp \ + libsrc/include/../gprim/transform3d.hpp \ + libsrc/include/../gprim/adtree.hpp libsrc/include/linalg.hpp \ + libsrc/include/../linalg/linalg.hpp libsrc/include/../linalg/vector.hpp \ + libsrc/include/../linalg/densemat.hpp \ + libsrc/include/../linalg/polynomial.hpp libsrc/include/opti.hpp \ + libsrc/include/../opti/opti.hpp libsrc/meshing/msghandler.hpp \ + libsrc/meshing/meshtype.hpp libsrc/meshing/localh.hpp \ + libsrc/meshing/meshclass.hpp libsrc/meshing/global.hpp \ + libsrc/meshing/meshtool.hpp libsrc/meshing/ruler2.hpp \ + libsrc/meshing/adfront2.hpp libsrc/meshing/meshing2.hpp \ + libsrc/meshing/improve2.hpp libsrc/meshing/geomsearch.hpp \ + libsrc/meshing/adfront3.hpp libsrc/meshing/ruler3.hpp \ + libsrc/meshing/meshing3.hpp libsrc/meshing/improve3.hpp \ + libsrc/meshing/findip.hpp libsrc/meshing/topology.hpp \ + libsrc/meshing/curvedelems.hpp libsrc/meshing/bisect.hpp \ + libsrc/meshing/clusters.hpp libsrc/meshing/meshfunc.hpp \ + libsrc/meshing/hprefinement.hpp libsrc/meshing/boundarylayer.hpp \ + libsrc/meshing/specials.hpp +# 1 "/Users/geuzaine/.gmsh/Netgen//" +ruler3.o: libsrc/meshing/ruler3.cpp libsrc/include/mystdlib.h \ + libsrc/meshing/meshing.hpp libsrc/include/myadt.hpp \ + libsrc/include/../general/myadt.hpp libsrc/include/mydefs.hpp \ + libsrc/include/../general/ngexception.hpp \ + libsrc/include/../general/parthreads.hpp \ + libsrc/include/../general/moveablemem.hpp \ + libsrc/include/../general/dynamicmem.hpp \ + libsrc/include/../general/template.hpp \ + libsrc/include/../general/array.hpp libsrc/include/../general/table.hpp \ + libsrc/include/../general/hashtabl.hpp \ + libsrc/include/../general/symbolta.hpp \ + libsrc/include/../general/bitarray.hpp \ + libsrc/include/../general/flags.hpp \ + libsrc/include/../general/spbita2d.hpp \ + libsrc/include/../general/seti.hpp libsrc/include/../general/optmem.hpp \ + libsrc/include/../general/autoptr.hpp \ + libsrc/include/../general/sort.hpp libsrc/include/../general/stack.hpp \ + libsrc/include/../general/mystring.hpp libsrc/include/gprim.hpp \ + libsrc/include/../gprim/gprim.hpp \ + libsrc/include/../gprim/geomobjects.hpp \ + libsrc/include/../gprim/geomops.hpp \ + libsrc/include/../gprim/geomfuncs.hpp \ + libsrc/include/../gprim/geom2d.hpp libsrc/include/../gprim/geom3d.hpp \ + libsrc/include/../gprim/geomtest3d.hpp \ + libsrc/include/../gprim/transform3d.hpp \ + libsrc/include/../gprim/adtree.hpp libsrc/include/linalg.hpp \ + libsrc/include/../linalg/linalg.hpp libsrc/include/../linalg/vector.hpp \ + libsrc/include/../linalg/densemat.hpp \ + libsrc/include/../linalg/polynomial.hpp libsrc/include/opti.hpp \ + libsrc/include/../opti/opti.hpp libsrc/meshing/msghandler.hpp \ + libsrc/meshing/meshtype.hpp libsrc/meshing/localh.hpp \ + libsrc/meshing/meshclass.hpp libsrc/meshing/global.hpp \ + libsrc/meshing/meshtool.hpp libsrc/meshing/ruler2.hpp \ + libsrc/meshing/adfront2.hpp libsrc/meshing/meshing2.hpp \ + libsrc/meshing/improve2.hpp libsrc/meshing/geomsearch.hpp \ + libsrc/meshing/adfront3.hpp libsrc/meshing/ruler3.hpp \ + libsrc/meshing/meshing3.hpp libsrc/meshing/improve3.hpp \ + libsrc/meshing/findip.hpp libsrc/meshing/topology.hpp \ + libsrc/meshing/curvedelems.hpp libsrc/meshing/bisect.hpp \ + libsrc/meshing/clusters.hpp libsrc/meshing/meshfunc.hpp \ + libsrc/meshing/hprefinement.hpp libsrc/meshing/boundarylayer.hpp \ + libsrc/meshing/specials.hpp +# 1 "/Users/geuzaine/.gmsh/Netgen//" +improve3.o: libsrc/meshing/improve3.cpp libsrc/include/mystdlib.h \ + libsrc/meshing/meshing.hpp libsrc/include/myadt.hpp \ + libsrc/include/../general/myadt.hpp libsrc/include/mydefs.hpp \ + libsrc/include/../general/ngexception.hpp \ + libsrc/include/../general/parthreads.hpp \ + libsrc/include/../general/moveablemem.hpp \ + libsrc/include/../general/dynamicmem.hpp \ + libsrc/include/../general/template.hpp \ + libsrc/include/../general/array.hpp libsrc/include/../general/table.hpp \ + libsrc/include/../general/hashtabl.hpp \ + libsrc/include/../general/symbolta.hpp \ + libsrc/include/../general/bitarray.hpp \ + libsrc/include/../general/flags.hpp \ + libsrc/include/../general/spbita2d.hpp \ + libsrc/include/../general/seti.hpp libsrc/include/../general/optmem.hpp \ + libsrc/include/../general/autoptr.hpp \ + libsrc/include/../general/sort.hpp libsrc/include/../general/stack.hpp \ + libsrc/include/../general/mystring.hpp libsrc/include/gprim.hpp \ + libsrc/include/../gprim/gprim.hpp \ + libsrc/include/../gprim/geomobjects.hpp \ + libsrc/include/../gprim/geomops.hpp \ + libsrc/include/../gprim/geomfuncs.hpp \ + libsrc/include/../gprim/geom2d.hpp libsrc/include/../gprim/geom3d.hpp \ + libsrc/include/../gprim/geomtest3d.hpp \ + libsrc/include/../gprim/transform3d.hpp \ + libsrc/include/../gprim/adtree.hpp libsrc/include/linalg.hpp \ + libsrc/include/../linalg/linalg.hpp libsrc/include/../linalg/vector.hpp \ + libsrc/include/../linalg/densemat.hpp \ + libsrc/include/../linalg/polynomial.hpp libsrc/include/opti.hpp \ + libsrc/include/../opti/opti.hpp libsrc/meshing/msghandler.hpp \ + libsrc/meshing/meshtype.hpp libsrc/meshing/localh.hpp \ + libsrc/meshing/meshclass.hpp libsrc/meshing/global.hpp \ + libsrc/meshing/meshtool.hpp libsrc/meshing/ruler2.hpp \ + libsrc/meshing/adfront2.hpp libsrc/meshing/meshing2.hpp \ + libsrc/meshing/improve2.hpp libsrc/meshing/geomsearch.hpp \ + libsrc/meshing/adfront3.hpp libsrc/meshing/ruler3.hpp \ + libsrc/meshing/meshing3.hpp libsrc/meshing/improve3.hpp \ + libsrc/meshing/findip.hpp libsrc/meshing/topology.hpp \ + libsrc/meshing/curvedelems.hpp libsrc/meshing/bisect.hpp \ + libsrc/meshing/clusters.hpp libsrc/meshing/meshfunc.hpp \ + libsrc/meshing/hprefinement.hpp libsrc/meshing/boundarylayer.hpp \ + libsrc/meshing/specials.hpp libsrc/include/../opti/opti.hpp +# 1 "/Users/geuzaine/.gmsh/Netgen//" +smoothing3.o: libsrc/meshing/smoothing3.cpp libsrc/include/mystdlib.h \ + libsrc/meshing/meshing.hpp libsrc/include/myadt.hpp \ + libsrc/include/../general/myadt.hpp libsrc/include/mydefs.hpp \ + libsrc/include/../general/ngexception.hpp \ + libsrc/include/../general/parthreads.hpp \ + libsrc/include/../general/moveablemem.hpp \ + libsrc/include/../general/dynamicmem.hpp \ + libsrc/include/../general/template.hpp \ + libsrc/include/../general/array.hpp libsrc/include/../general/table.hpp \ + libsrc/include/../general/hashtabl.hpp \ + libsrc/include/../general/symbolta.hpp \ + libsrc/include/../general/bitarray.hpp \ + libsrc/include/../general/flags.hpp \ + libsrc/include/../general/spbita2d.hpp \ + libsrc/include/../general/seti.hpp libsrc/include/../general/optmem.hpp \ + libsrc/include/../general/autoptr.hpp \ + libsrc/include/../general/sort.hpp libsrc/include/../general/stack.hpp \ + libsrc/include/../general/mystring.hpp libsrc/include/gprim.hpp \ + libsrc/include/../gprim/gprim.hpp \ + libsrc/include/../gprim/geomobjects.hpp \ + libsrc/include/../gprim/geomops.hpp \ + libsrc/include/../gprim/geomfuncs.hpp \ + libsrc/include/../gprim/geom2d.hpp libsrc/include/../gprim/geom3d.hpp \ + libsrc/include/../gprim/geomtest3d.hpp \ + libsrc/include/../gprim/transform3d.hpp \ + libsrc/include/../gprim/adtree.hpp libsrc/include/linalg.hpp \ + libsrc/include/../linalg/linalg.hpp libsrc/include/../linalg/vector.hpp \ + libsrc/include/../linalg/densemat.hpp \ + libsrc/include/../linalg/polynomial.hpp libsrc/include/opti.hpp \ + libsrc/include/../opti/opti.hpp libsrc/meshing/msghandler.hpp \ + libsrc/meshing/meshtype.hpp libsrc/meshing/localh.hpp \ + libsrc/meshing/meshclass.hpp libsrc/meshing/global.hpp \ + libsrc/meshing/meshtool.hpp libsrc/meshing/ruler2.hpp \ + libsrc/meshing/adfront2.hpp libsrc/meshing/meshing2.hpp \ + libsrc/meshing/improve2.hpp libsrc/meshing/geomsearch.hpp \ + libsrc/meshing/adfront3.hpp libsrc/meshing/ruler3.hpp \ + libsrc/meshing/meshing3.hpp libsrc/meshing/improve3.hpp \ + libsrc/meshing/findip.hpp libsrc/meshing/topology.hpp \ + libsrc/meshing/curvedelems.hpp libsrc/meshing/bisect.hpp \ + libsrc/meshing/clusters.hpp libsrc/meshing/meshfunc.hpp \ + libsrc/meshing/hprefinement.hpp libsrc/meshing/boundarylayer.hpp \ + libsrc/meshing/specials.hpp libsrc/include/../opti/opti.hpp +# 1 "/Users/geuzaine/.gmsh/Netgen//" +adfront3.o: libsrc/meshing/adfront3.cpp libsrc/include/mystdlib.h \ + libsrc/meshing/meshing.hpp libsrc/include/myadt.hpp \ + libsrc/include/../general/myadt.hpp libsrc/include/mydefs.hpp \ + libsrc/include/../general/ngexception.hpp \ + libsrc/include/../general/parthreads.hpp \ + libsrc/include/../general/moveablemem.hpp \ + libsrc/include/../general/dynamicmem.hpp \ + libsrc/include/../general/template.hpp \ + libsrc/include/../general/array.hpp libsrc/include/../general/table.hpp \ + libsrc/include/../general/hashtabl.hpp \ + libsrc/include/../general/symbolta.hpp \ + libsrc/include/../general/bitarray.hpp \ + libsrc/include/../general/flags.hpp \ + libsrc/include/../general/spbita2d.hpp \ + libsrc/include/../general/seti.hpp libsrc/include/../general/optmem.hpp \ + libsrc/include/../general/autoptr.hpp \ + libsrc/include/../general/sort.hpp libsrc/include/../general/stack.hpp \ + libsrc/include/../general/mystring.hpp libsrc/include/gprim.hpp \ + libsrc/include/../gprim/gprim.hpp \ + libsrc/include/../gprim/geomobjects.hpp \ + libsrc/include/../gprim/geomops.hpp \ + libsrc/include/../gprim/geomfuncs.hpp \ + libsrc/include/../gprim/geom2d.hpp libsrc/include/../gprim/geom3d.hpp \ + libsrc/include/../gprim/geomtest3d.hpp \ + libsrc/include/../gprim/transform3d.hpp \ + libsrc/include/../gprim/adtree.hpp libsrc/include/linalg.hpp \ + libsrc/include/../linalg/linalg.hpp libsrc/include/../linalg/vector.hpp \ + libsrc/include/../linalg/densemat.hpp \ + libsrc/include/../linalg/polynomial.hpp libsrc/include/opti.hpp \ + libsrc/include/../opti/opti.hpp libsrc/meshing/msghandler.hpp \ + libsrc/meshing/meshtype.hpp libsrc/meshing/localh.hpp \ + libsrc/meshing/meshclass.hpp libsrc/meshing/global.hpp \ + libsrc/meshing/meshtool.hpp libsrc/meshing/ruler2.hpp \ + libsrc/meshing/adfront2.hpp libsrc/meshing/meshing2.hpp \ + libsrc/meshing/improve2.hpp libsrc/meshing/geomsearch.hpp \ + libsrc/meshing/adfront3.hpp libsrc/meshing/ruler3.hpp \ + libsrc/meshing/meshing3.hpp libsrc/meshing/improve3.hpp \ + libsrc/meshing/findip.hpp libsrc/meshing/topology.hpp \ + libsrc/meshing/curvedelems.hpp libsrc/meshing/bisect.hpp \ + libsrc/meshing/clusters.hpp libsrc/meshing/meshfunc.hpp \ + libsrc/meshing/hprefinement.hpp libsrc/meshing/boundarylayer.hpp \ + libsrc/meshing/specials.hpp +# 1 "/Users/geuzaine/.gmsh/Netgen//" +tetrarls.o: libsrc/meshing/tetrarls.cpp +# 1 "/Users/geuzaine/.gmsh/Netgen//" +prism2rls.o: libsrc/meshing/prism2rls.cpp +# 1 "/Users/geuzaine/.gmsh/Netgen//" +pyramidrls.o: libsrc/meshing/pyramidrls.cpp +# 1 "/Users/geuzaine/.gmsh/Netgen//" +pyramid2rls.o: libsrc/meshing/pyramid2rls.cpp +# 1 "/Users/geuzaine/.gmsh/Netgen//" +netrule3.o: libsrc/meshing/netrule3.cpp libsrc/include/mystdlib.h \ + libsrc/meshing/meshing.hpp libsrc/include/myadt.hpp \ + libsrc/include/../general/myadt.hpp libsrc/include/mydefs.hpp \ + libsrc/include/../general/ngexception.hpp \ + libsrc/include/../general/parthreads.hpp \ + libsrc/include/../general/moveablemem.hpp \ + libsrc/include/../general/dynamicmem.hpp \ + libsrc/include/../general/template.hpp \ + libsrc/include/../general/array.hpp libsrc/include/../general/table.hpp \ + libsrc/include/../general/hashtabl.hpp \ + libsrc/include/../general/symbolta.hpp \ + libsrc/include/../general/bitarray.hpp \ + libsrc/include/../general/flags.hpp \ + libsrc/include/../general/spbita2d.hpp \ + libsrc/include/../general/seti.hpp libsrc/include/../general/optmem.hpp \ + libsrc/include/../general/autoptr.hpp \ + libsrc/include/../general/sort.hpp libsrc/include/../general/stack.hpp \ + libsrc/include/../general/mystring.hpp libsrc/include/gprim.hpp \ + libsrc/include/../gprim/gprim.hpp \ + libsrc/include/../gprim/geomobjects.hpp \ + libsrc/include/../gprim/geomops.hpp \ + libsrc/include/../gprim/geomfuncs.hpp \ + libsrc/include/../gprim/geom2d.hpp libsrc/include/../gprim/geom3d.hpp \ + libsrc/include/../gprim/geomtest3d.hpp \ + libsrc/include/../gprim/transform3d.hpp \ + libsrc/include/../gprim/adtree.hpp libsrc/include/linalg.hpp \ + libsrc/include/../linalg/linalg.hpp libsrc/include/../linalg/vector.hpp \ + libsrc/include/../linalg/densemat.hpp \ + libsrc/include/../linalg/polynomial.hpp libsrc/include/opti.hpp \ + libsrc/include/../opti/opti.hpp libsrc/meshing/msghandler.hpp \ + libsrc/meshing/meshtype.hpp libsrc/meshing/localh.hpp \ + libsrc/meshing/meshclass.hpp libsrc/meshing/global.hpp \ + libsrc/meshing/meshtool.hpp libsrc/meshing/ruler2.hpp \ + libsrc/meshing/adfront2.hpp libsrc/meshing/meshing2.hpp \ + libsrc/meshing/improve2.hpp libsrc/meshing/geomsearch.hpp \ + libsrc/meshing/adfront3.hpp libsrc/meshing/ruler3.hpp \ + libsrc/meshing/meshing3.hpp libsrc/meshing/improve3.hpp \ + libsrc/meshing/findip.hpp libsrc/meshing/topology.hpp \ + libsrc/meshing/curvedelems.hpp libsrc/meshing/bisect.hpp \ + libsrc/meshing/clusters.hpp libsrc/meshing/meshfunc.hpp \ + libsrc/meshing/hprefinement.hpp libsrc/meshing/boundarylayer.hpp \ + libsrc/meshing/specials.hpp +# 1 "/Users/geuzaine/.gmsh/Netgen//" +ruler2.o: libsrc/meshing/ruler2.cpp libsrc/include/mystdlib.h \ + libsrc/meshing/meshing.hpp libsrc/include/myadt.hpp \ + libsrc/include/../general/myadt.hpp libsrc/include/mydefs.hpp \ + libsrc/include/../general/ngexception.hpp \ + libsrc/include/../general/parthreads.hpp \ + libsrc/include/../general/moveablemem.hpp \ + libsrc/include/../general/dynamicmem.hpp \ + libsrc/include/../general/template.hpp \ + libsrc/include/../general/array.hpp libsrc/include/../general/table.hpp \ + libsrc/include/../general/hashtabl.hpp \ + libsrc/include/../general/symbolta.hpp \ + libsrc/include/../general/bitarray.hpp \ + libsrc/include/../general/flags.hpp \ + libsrc/include/../general/spbita2d.hpp \ + libsrc/include/../general/seti.hpp libsrc/include/../general/optmem.hpp \ + libsrc/include/../general/autoptr.hpp \ + libsrc/include/../general/sort.hpp libsrc/include/../general/stack.hpp \ + libsrc/include/../general/mystring.hpp libsrc/include/gprim.hpp \ + libsrc/include/../gprim/gprim.hpp \ + libsrc/include/../gprim/geomobjects.hpp \ + libsrc/include/../gprim/geomops.hpp \ + libsrc/include/../gprim/geomfuncs.hpp \ + libsrc/include/../gprim/geom2d.hpp libsrc/include/../gprim/geom3d.hpp \ + libsrc/include/../gprim/geomtest3d.hpp \ + libsrc/include/../gprim/transform3d.hpp \ + libsrc/include/../gprim/adtree.hpp libsrc/include/linalg.hpp \ + libsrc/include/../linalg/linalg.hpp libsrc/include/../linalg/vector.hpp \ + libsrc/include/../linalg/densemat.hpp \ + libsrc/include/../linalg/polynomial.hpp libsrc/include/opti.hpp \ + libsrc/include/../opti/opti.hpp libsrc/meshing/msghandler.hpp \ + libsrc/meshing/meshtype.hpp libsrc/meshing/localh.hpp \ + libsrc/meshing/meshclass.hpp libsrc/meshing/global.hpp \ + libsrc/meshing/meshtool.hpp libsrc/meshing/ruler2.hpp \ + libsrc/meshing/adfront2.hpp libsrc/meshing/meshing2.hpp \ + libsrc/meshing/improve2.hpp libsrc/meshing/geomsearch.hpp \ + libsrc/meshing/adfront3.hpp libsrc/meshing/ruler3.hpp \ + libsrc/meshing/meshing3.hpp libsrc/meshing/improve3.hpp \ + libsrc/meshing/findip.hpp libsrc/meshing/topology.hpp \ + libsrc/meshing/curvedelems.hpp libsrc/meshing/bisect.hpp \ + libsrc/meshing/clusters.hpp libsrc/meshing/meshfunc.hpp \ + libsrc/meshing/hprefinement.hpp libsrc/meshing/boundarylayer.hpp \ + libsrc/meshing/specials.hpp +# 1 "/Users/geuzaine/.gmsh/Netgen//" +meshclass.o: libsrc/meshing/meshclass.cpp libsrc/include/mystdlib.h \ + libsrc/meshing/meshing.hpp libsrc/include/myadt.hpp \ + libsrc/include/../general/myadt.hpp libsrc/include/mydefs.hpp \ + libsrc/include/../general/ngexception.hpp \ + libsrc/include/../general/parthreads.hpp \ + libsrc/include/../general/moveablemem.hpp \ + libsrc/include/../general/dynamicmem.hpp \ + libsrc/include/../general/template.hpp \ + libsrc/include/../general/array.hpp libsrc/include/../general/table.hpp \ + libsrc/include/../general/hashtabl.hpp \ + libsrc/include/../general/symbolta.hpp \ + libsrc/include/../general/bitarray.hpp \ + libsrc/include/../general/flags.hpp \ + libsrc/include/../general/spbita2d.hpp \ + libsrc/include/../general/seti.hpp libsrc/include/../general/optmem.hpp \ + libsrc/include/../general/autoptr.hpp \ + libsrc/include/../general/sort.hpp libsrc/include/../general/stack.hpp \ + libsrc/include/../general/mystring.hpp libsrc/include/gprim.hpp \ + libsrc/include/../gprim/gprim.hpp \ + libsrc/include/../gprim/geomobjects.hpp \ + libsrc/include/../gprim/geomops.hpp \ + libsrc/include/../gprim/geomfuncs.hpp \ + libsrc/include/../gprim/geom2d.hpp libsrc/include/../gprim/geom3d.hpp \ + libsrc/include/../gprim/geomtest3d.hpp \ + libsrc/include/../gprim/transform3d.hpp \ + libsrc/include/../gprim/adtree.hpp libsrc/include/linalg.hpp \ + libsrc/include/../linalg/linalg.hpp libsrc/include/../linalg/vector.hpp \ + libsrc/include/../linalg/densemat.hpp \ + libsrc/include/../linalg/polynomial.hpp libsrc/include/opti.hpp \ + libsrc/include/../opti/opti.hpp libsrc/meshing/msghandler.hpp \ + libsrc/meshing/meshtype.hpp libsrc/meshing/localh.hpp \ + libsrc/meshing/meshclass.hpp libsrc/meshing/global.hpp \ + libsrc/meshing/meshtool.hpp libsrc/meshing/ruler2.hpp \ + libsrc/meshing/adfront2.hpp libsrc/meshing/meshing2.hpp \ + libsrc/meshing/improve2.hpp libsrc/meshing/geomsearch.hpp \ + libsrc/meshing/adfront3.hpp libsrc/meshing/ruler3.hpp \ + libsrc/meshing/meshing3.hpp libsrc/meshing/improve3.hpp \ + libsrc/meshing/findip.hpp libsrc/meshing/topology.hpp \ + libsrc/meshing/curvedelems.hpp libsrc/meshing/bisect.hpp \ + libsrc/meshing/clusters.hpp libsrc/meshing/meshfunc.hpp \ + libsrc/meshing/hprefinement.hpp libsrc/meshing/boundarylayer.hpp \ + libsrc/meshing/specials.hpp +# 1 "/Users/geuzaine/.gmsh/Netgen//" +improve2.o: libsrc/meshing/improve2.cpp libsrc/include/mystdlib.h \ + libsrc/meshing/meshing.hpp libsrc/include/myadt.hpp \ + libsrc/include/../general/myadt.hpp libsrc/include/mydefs.hpp \ + libsrc/include/../general/ngexception.hpp \ + libsrc/include/../general/parthreads.hpp \ + libsrc/include/../general/moveablemem.hpp \ + libsrc/include/../general/dynamicmem.hpp \ + libsrc/include/../general/template.hpp \ + libsrc/include/../general/array.hpp libsrc/include/../general/table.hpp \ + libsrc/include/../general/hashtabl.hpp \ + libsrc/include/../general/symbolta.hpp \ + libsrc/include/../general/bitarray.hpp \ + libsrc/include/../general/flags.hpp \ + libsrc/include/../general/spbita2d.hpp \ + libsrc/include/../general/seti.hpp libsrc/include/../general/optmem.hpp \ + libsrc/include/../general/autoptr.hpp \ + libsrc/include/../general/sort.hpp libsrc/include/../general/stack.hpp \ + libsrc/include/../general/mystring.hpp libsrc/include/gprim.hpp \ + libsrc/include/../gprim/gprim.hpp \ + libsrc/include/../gprim/geomobjects.hpp \ + libsrc/include/../gprim/geomops.hpp \ + libsrc/include/../gprim/geomfuncs.hpp \ + libsrc/include/../gprim/geom2d.hpp libsrc/include/../gprim/geom3d.hpp \ + libsrc/include/../gprim/geomtest3d.hpp \ + libsrc/include/../gprim/transform3d.hpp \ + libsrc/include/../gprim/adtree.hpp libsrc/include/linalg.hpp \ + libsrc/include/../linalg/linalg.hpp libsrc/include/../linalg/vector.hpp \ + libsrc/include/../linalg/densemat.hpp \ + libsrc/include/../linalg/polynomial.hpp libsrc/include/opti.hpp \ + libsrc/include/../opti/opti.hpp libsrc/meshing/msghandler.hpp \ + libsrc/meshing/meshtype.hpp libsrc/meshing/localh.hpp \ + libsrc/meshing/meshclass.hpp libsrc/meshing/global.hpp \ + libsrc/meshing/meshtool.hpp libsrc/meshing/ruler2.hpp \ + libsrc/meshing/adfront2.hpp libsrc/meshing/meshing2.hpp \ + libsrc/meshing/improve2.hpp libsrc/meshing/geomsearch.hpp \ + libsrc/meshing/adfront3.hpp libsrc/meshing/ruler3.hpp \ + libsrc/meshing/meshing3.hpp libsrc/meshing/improve3.hpp \ + libsrc/meshing/findip.hpp libsrc/meshing/topology.hpp \ + libsrc/meshing/curvedelems.hpp libsrc/meshing/bisect.hpp \ + libsrc/meshing/clusters.hpp libsrc/meshing/meshfunc.hpp \ + libsrc/meshing/hprefinement.hpp libsrc/meshing/boundarylayer.hpp \ + libsrc/meshing/specials.hpp libsrc/include/../opti/opti.hpp +# 1 "/Users/geuzaine/.gmsh/Netgen//" +smoothing2.o: libsrc/meshing/smoothing2.cpp libsrc/include/mystdlib.h \ + libsrc/meshing/meshing.hpp libsrc/include/myadt.hpp \ + libsrc/include/../general/myadt.hpp libsrc/include/mydefs.hpp \ + libsrc/include/../general/ngexception.hpp \ + libsrc/include/../general/parthreads.hpp \ + libsrc/include/../general/moveablemem.hpp \ + libsrc/include/../general/dynamicmem.hpp \ + libsrc/include/../general/template.hpp \ + libsrc/include/../general/array.hpp libsrc/include/../general/table.hpp \ + libsrc/include/../general/hashtabl.hpp \ + libsrc/include/../general/symbolta.hpp \ + libsrc/include/../general/bitarray.hpp \ + libsrc/include/../general/flags.hpp \ + libsrc/include/../general/spbita2d.hpp \ + libsrc/include/../general/seti.hpp libsrc/include/../general/optmem.hpp \ + libsrc/include/../general/autoptr.hpp \ + libsrc/include/../general/sort.hpp libsrc/include/../general/stack.hpp \ + libsrc/include/../general/mystring.hpp libsrc/include/gprim.hpp \ + libsrc/include/../gprim/gprim.hpp \ + libsrc/include/../gprim/geomobjects.hpp \ + libsrc/include/../gprim/geomops.hpp \ + libsrc/include/../gprim/geomfuncs.hpp \ + libsrc/include/../gprim/geom2d.hpp libsrc/include/../gprim/geom3d.hpp \ + libsrc/include/../gprim/geomtest3d.hpp \ + libsrc/include/../gprim/transform3d.hpp \ + libsrc/include/../gprim/adtree.hpp libsrc/include/linalg.hpp \ + libsrc/include/../linalg/linalg.hpp libsrc/include/../linalg/vector.hpp \ + libsrc/include/../linalg/densemat.hpp \ + libsrc/include/../linalg/polynomial.hpp libsrc/include/opti.hpp \ + libsrc/include/../opti/opti.hpp libsrc/meshing/msghandler.hpp \ + libsrc/meshing/meshtype.hpp libsrc/meshing/localh.hpp \ + libsrc/meshing/meshclass.hpp libsrc/meshing/global.hpp \ + libsrc/meshing/meshtool.hpp libsrc/meshing/ruler2.hpp \ + libsrc/meshing/adfront2.hpp libsrc/meshing/meshing2.hpp \ + libsrc/meshing/improve2.hpp libsrc/meshing/geomsearch.hpp \ + libsrc/meshing/adfront3.hpp libsrc/meshing/ruler3.hpp \ + libsrc/meshing/meshing3.hpp libsrc/meshing/improve3.hpp \ + libsrc/meshing/findip.hpp libsrc/meshing/topology.hpp \ + libsrc/meshing/curvedelems.hpp libsrc/meshing/bisect.hpp \ + libsrc/meshing/clusters.hpp libsrc/meshing/meshfunc.hpp \ + libsrc/meshing/hprefinement.hpp libsrc/meshing/boundarylayer.hpp \ + libsrc/meshing/specials.hpp libsrc/include/../opti/opti.hpp +# 1 "/Users/geuzaine/.gmsh/Netgen//" +adfront2.o: libsrc/meshing/adfront2.cpp libsrc/include/mystdlib.h \ + libsrc/meshing/meshing.hpp libsrc/include/myadt.hpp \ + libsrc/include/../general/myadt.hpp libsrc/include/mydefs.hpp \ + libsrc/include/../general/ngexception.hpp \ + libsrc/include/../general/parthreads.hpp \ + libsrc/include/../general/moveablemem.hpp \ + libsrc/include/../general/dynamicmem.hpp \ + libsrc/include/../general/template.hpp \ + libsrc/include/../general/array.hpp libsrc/include/../general/table.hpp \ + libsrc/include/../general/hashtabl.hpp \ + libsrc/include/../general/symbolta.hpp \ + libsrc/include/../general/bitarray.hpp \ + libsrc/include/../general/flags.hpp \ + libsrc/include/../general/spbita2d.hpp \ + libsrc/include/../general/seti.hpp libsrc/include/../general/optmem.hpp \ + libsrc/include/../general/autoptr.hpp \ + libsrc/include/../general/sort.hpp libsrc/include/../general/stack.hpp \ + libsrc/include/../general/mystring.hpp libsrc/include/gprim.hpp \ + libsrc/include/../gprim/gprim.hpp \ + libsrc/include/../gprim/geomobjects.hpp \ + libsrc/include/../gprim/geomops.hpp \ + libsrc/include/../gprim/geomfuncs.hpp \ + libsrc/include/../gprim/geom2d.hpp libsrc/include/../gprim/geom3d.hpp \ + libsrc/include/../gprim/geomtest3d.hpp \ + libsrc/include/../gprim/transform3d.hpp \ + libsrc/include/../gprim/adtree.hpp libsrc/include/linalg.hpp \ + libsrc/include/../linalg/linalg.hpp libsrc/include/../linalg/vector.hpp \ + libsrc/include/../linalg/densemat.hpp \ + libsrc/include/../linalg/polynomial.hpp libsrc/include/opti.hpp \ + libsrc/include/../opti/opti.hpp libsrc/meshing/msghandler.hpp \ + libsrc/meshing/meshtype.hpp libsrc/meshing/localh.hpp \ + libsrc/meshing/meshclass.hpp libsrc/meshing/global.hpp \ + libsrc/meshing/meshtool.hpp libsrc/meshing/ruler2.hpp \ + libsrc/meshing/adfront2.hpp libsrc/meshing/meshing2.hpp \ + libsrc/meshing/improve2.hpp libsrc/meshing/geomsearch.hpp \ + libsrc/meshing/adfront3.hpp libsrc/meshing/ruler3.hpp \ + libsrc/meshing/meshing3.hpp libsrc/meshing/improve3.hpp \ + libsrc/meshing/findip.hpp libsrc/meshing/topology.hpp \ + libsrc/meshing/curvedelems.hpp libsrc/meshing/bisect.hpp \ + libsrc/meshing/clusters.hpp libsrc/meshing/meshfunc.hpp \ + libsrc/meshing/hprefinement.hpp libsrc/meshing/boundarylayer.hpp \ + libsrc/meshing/specials.hpp +# 1 "/Users/geuzaine/.gmsh/Netgen//" +netrule2.o: libsrc/meshing/netrule2.cpp libsrc/include/mystdlib.h \ + libsrc/meshing/meshing.hpp libsrc/include/myadt.hpp \ + libsrc/include/../general/myadt.hpp libsrc/include/mydefs.hpp \ + libsrc/include/../general/ngexception.hpp \ + libsrc/include/../general/parthreads.hpp \ + libsrc/include/../general/moveablemem.hpp \ + libsrc/include/../general/dynamicmem.hpp \ + libsrc/include/../general/template.hpp \ + libsrc/include/../general/array.hpp libsrc/include/../general/table.hpp \ + libsrc/include/../general/hashtabl.hpp \ + libsrc/include/../general/symbolta.hpp \ + libsrc/include/../general/bitarray.hpp \ + libsrc/include/../general/flags.hpp \ + libsrc/include/../general/spbita2d.hpp \ + libsrc/include/../general/seti.hpp libsrc/include/../general/optmem.hpp \ + libsrc/include/../general/autoptr.hpp \ + libsrc/include/../general/sort.hpp libsrc/include/../general/stack.hpp \ + libsrc/include/../general/mystring.hpp libsrc/include/gprim.hpp \ + libsrc/include/../gprim/gprim.hpp \ + libsrc/include/../gprim/geomobjects.hpp \ + libsrc/include/../gprim/geomops.hpp \ + libsrc/include/../gprim/geomfuncs.hpp \ + libsrc/include/../gprim/geom2d.hpp libsrc/include/../gprim/geom3d.hpp \ + libsrc/include/../gprim/geomtest3d.hpp \ + libsrc/include/../gprim/transform3d.hpp \ + libsrc/include/../gprim/adtree.hpp libsrc/include/linalg.hpp \ + libsrc/include/../linalg/linalg.hpp libsrc/include/../linalg/vector.hpp \ + libsrc/include/../linalg/densemat.hpp \ + libsrc/include/../linalg/polynomial.hpp libsrc/include/opti.hpp \ + libsrc/include/../opti/opti.hpp libsrc/meshing/msghandler.hpp \ + libsrc/meshing/meshtype.hpp libsrc/meshing/localh.hpp \ + libsrc/meshing/meshclass.hpp libsrc/meshing/global.hpp \ + libsrc/meshing/meshtool.hpp libsrc/meshing/ruler2.hpp \ + libsrc/meshing/adfront2.hpp libsrc/meshing/meshing2.hpp \ + libsrc/meshing/improve2.hpp libsrc/meshing/geomsearch.hpp \ + libsrc/meshing/adfront3.hpp libsrc/meshing/ruler3.hpp \ + libsrc/meshing/meshing3.hpp libsrc/meshing/improve3.hpp \ + libsrc/meshing/findip.hpp libsrc/meshing/topology.hpp \ + libsrc/meshing/curvedelems.hpp libsrc/meshing/bisect.hpp \ + libsrc/meshing/clusters.hpp libsrc/meshing/meshfunc.hpp \ + libsrc/meshing/hprefinement.hpp libsrc/meshing/boundarylayer.hpp \ + libsrc/meshing/specials.hpp +# 1 "/Users/geuzaine/.gmsh/Netgen//" +triarls.o: libsrc/meshing/triarls.cpp +# 1 "/Users/geuzaine/.gmsh/Netgen//" +geomsearch.o: libsrc/meshing/geomsearch.cpp libsrc/include/mystdlib.h \ + libsrc/meshing/meshing.hpp libsrc/include/myadt.hpp \ + libsrc/include/../general/myadt.hpp libsrc/include/mydefs.hpp \ + libsrc/include/../general/ngexception.hpp \ + libsrc/include/../general/parthreads.hpp \ + libsrc/include/../general/moveablemem.hpp \ + libsrc/include/../general/dynamicmem.hpp \ + libsrc/include/../general/template.hpp \ + libsrc/include/../general/array.hpp libsrc/include/../general/table.hpp \ + libsrc/include/../general/hashtabl.hpp \ + libsrc/include/../general/symbolta.hpp \ + libsrc/include/../general/bitarray.hpp \ + libsrc/include/../general/flags.hpp \ + libsrc/include/../general/spbita2d.hpp \ + libsrc/include/../general/seti.hpp libsrc/include/../general/optmem.hpp \ + libsrc/include/../general/autoptr.hpp \ + libsrc/include/../general/sort.hpp libsrc/include/../general/stack.hpp \ + libsrc/include/../general/mystring.hpp libsrc/include/gprim.hpp \ + libsrc/include/../gprim/gprim.hpp \ + libsrc/include/../gprim/geomobjects.hpp \ + libsrc/include/../gprim/geomops.hpp \ + libsrc/include/../gprim/geomfuncs.hpp \ + libsrc/include/../gprim/geom2d.hpp libsrc/include/../gprim/geom3d.hpp \ + libsrc/include/../gprim/geomtest3d.hpp \ + libsrc/include/../gprim/transform3d.hpp \ + libsrc/include/../gprim/adtree.hpp libsrc/include/linalg.hpp \ + libsrc/include/../linalg/linalg.hpp libsrc/include/../linalg/vector.hpp \ + libsrc/include/../linalg/densemat.hpp \ + libsrc/include/../linalg/polynomial.hpp libsrc/include/opti.hpp \ + libsrc/include/../opti/opti.hpp libsrc/meshing/msghandler.hpp \ + libsrc/meshing/meshtype.hpp libsrc/meshing/localh.hpp \ + libsrc/meshing/meshclass.hpp libsrc/meshing/global.hpp \ + libsrc/meshing/meshtool.hpp libsrc/meshing/ruler2.hpp \ + libsrc/meshing/adfront2.hpp libsrc/meshing/meshing2.hpp \ + libsrc/meshing/improve2.hpp libsrc/meshing/geomsearch.hpp \ + libsrc/meshing/adfront3.hpp libsrc/meshing/ruler3.hpp \ + libsrc/meshing/meshing3.hpp libsrc/meshing/improve3.hpp \ + libsrc/meshing/findip.hpp libsrc/meshing/topology.hpp \ + libsrc/meshing/curvedelems.hpp libsrc/meshing/bisect.hpp \ + libsrc/meshing/clusters.hpp libsrc/meshing/meshfunc.hpp \ + libsrc/meshing/hprefinement.hpp libsrc/meshing/boundarylayer.hpp \ + libsrc/meshing/specials.hpp +# 1 "/Users/geuzaine/.gmsh/Netgen//" +secondorder.o: libsrc/meshing/secondorder.cpp libsrc/include/mystdlib.h \ + libsrc/meshing/meshing.hpp libsrc/include/myadt.hpp \ + libsrc/include/../general/myadt.hpp libsrc/include/mydefs.hpp \ + libsrc/include/../general/ngexception.hpp \ + libsrc/include/../general/parthreads.hpp \ + libsrc/include/../general/moveablemem.hpp \ + libsrc/include/../general/dynamicmem.hpp \ + libsrc/include/../general/template.hpp \ + libsrc/include/../general/array.hpp libsrc/include/../general/table.hpp \ + libsrc/include/../general/hashtabl.hpp \ + libsrc/include/../general/symbolta.hpp \ + libsrc/include/../general/bitarray.hpp \ + libsrc/include/../general/flags.hpp \ + libsrc/include/../general/spbita2d.hpp \ + libsrc/include/../general/seti.hpp libsrc/include/../general/optmem.hpp \ + libsrc/include/../general/autoptr.hpp \ + libsrc/include/../general/sort.hpp libsrc/include/../general/stack.hpp \ + libsrc/include/../general/mystring.hpp libsrc/include/gprim.hpp \ + libsrc/include/../gprim/gprim.hpp \ + libsrc/include/../gprim/geomobjects.hpp \ + libsrc/include/../gprim/geomops.hpp \ + libsrc/include/../gprim/geomfuncs.hpp \ + libsrc/include/../gprim/geom2d.hpp libsrc/include/../gprim/geom3d.hpp \ + libsrc/include/../gprim/geomtest3d.hpp \ + libsrc/include/../gprim/transform3d.hpp \ + libsrc/include/../gprim/adtree.hpp libsrc/include/linalg.hpp \ + libsrc/include/../linalg/linalg.hpp libsrc/include/../linalg/vector.hpp \ + libsrc/include/../linalg/densemat.hpp \ + libsrc/include/../linalg/polynomial.hpp libsrc/include/opti.hpp \ + libsrc/include/../opti/opti.hpp libsrc/meshing/msghandler.hpp \ + libsrc/meshing/meshtype.hpp libsrc/meshing/localh.hpp \ + libsrc/meshing/meshclass.hpp libsrc/meshing/global.hpp \ + libsrc/meshing/meshtool.hpp libsrc/meshing/ruler2.hpp \ + libsrc/meshing/adfront2.hpp libsrc/meshing/meshing2.hpp \ + libsrc/meshing/improve2.hpp libsrc/meshing/geomsearch.hpp \ + libsrc/meshing/adfront3.hpp libsrc/meshing/ruler3.hpp \ + libsrc/meshing/meshing3.hpp libsrc/meshing/improve3.hpp \ + libsrc/meshing/findip.hpp libsrc/meshing/topology.hpp \ + libsrc/meshing/curvedelems.hpp libsrc/meshing/bisect.hpp \ + libsrc/meshing/clusters.hpp libsrc/meshing/meshfunc.hpp \ + libsrc/meshing/hprefinement.hpp libsrc/meshing/boundarylayer.hpp \ + libsrc/meshing/specials.hpp +# 1 "/Users/geuzaine/.gmsh/Netgen//" +meshtype.o: libsrc/meshing/meshtype.cpp libsrc/include/mystdlib.h \ + libsrc/meshing/meshing.hpp libsrc/include/myadt.hpp \ + libsrc/include/../general/myadt.hpp libsrc/include/mydefs.hpp \ + libsrc/include/../general/ngexception.hpp \ + libsrc/include/../general/parthreads.hpp \ + libsrc/include/../general/moveablemem.hpp \ + libsrc/include/../general/dynamicmem.hpp \ + libsrc/include/../general/template.hpp \ + libsrc/include/../general/array.hpp libsrc/include/../general/table.hpp \ + libsrc/include/../general/hashtabl.hpp \ + libsrc/include/../general/symbolta.hpp \ + libsrc/include/../general/bitarray.hpp \ + libsrc/include/../general/flags.hpp \ + libsrc/include/../general/spbita2d.hpp \ + libsrc/include/../general/seti.hpp libsrc/include/../general/optmem.hpp \ + libsrc/include/../general/autoptr.hpp \ + libsrc/include/../general/sort.hpp libsrc/include/../general/stack.hpp \ + libsrc/include/../general/mystring.hpp libsrc/include/gprim.hpp \ + libsrc/include/../gprim/gprim.hpp \ + libsrc/include/../gprim/geomobjects.hpp \ + libsrc/include/../gprim/geomops.hpp \ + libsrc/include/../gprim/geomfuncs.hpp \ + libsrc/include/../gprim/geom2d.hpp libsrc/include/../gprim/geom3d.hpp \ + libsrc/include/../gprim/geomtest3d.hpp \ + libsrc/include/../gprim/transform3d.hpp \ + libsrc/include/../gprim/adtree.hpp libsrc/include/linalg.hpp \ + libsrc/include/../linalg/linalg.hpp libsrc/include/../linalg/vector.hpp \ + libsrc/include/../linalg/densemat.hpp \ + libsrc/include/../linalg/polynomial.hpp libsrc/include/opti.hpp \ + libsrc/include/../opti/opti.hpp libsrc/meshing/msghandler.hpp \ + libsrc/meshing/meshtype.hpp libsrc/meshing/localh.hpp \ + libsrc/meshing/meshclass.hpp libsrc/meshing/global.hpp \ + libsrc/meshing/meshtool.hpp libsrc/meshing/ruler2.hpp \ + libsrc/meshing/adfront2.hpp libsrc/meshing/meshing2.hpp \ + libsrc/meshing/improve2.hpp libsrc/meshing/geomsearch.hpp \ + libsrc/meshing/adfront3.hpp libsrc/meshing/ruler3.hpp \ + libsrc/meshing/meshing3.hpp libsrc/meshing/improve3.hpp \ + libsrc/meshing/findip.hpp libsrc/meshing/topology.hpp \ + libsrc/meshing/curvedelems.hpp libsrc/meshing/bisect.hpp \ + libsrc/meshing/clusters.hpp libsrc/meshing/meshfunc.hpp \ + libsrc/meshing/hprefinement.hpp libsrc/meshing/boundarylayer.hpp \ + libsrc/meshing/specials.hpp +# 1 "/Users/geuzaine/.gmsh/Netgen//" +parser3.o: libsrc/meshing/parser3.cpp libsrc/include/mystdlib.h \ + libsrc/meshing/meshing.hpp libsrc/include/myadt.hpp \ + libsrc/include/../general/myadt.hpp libsrc/include/mydefs.hpp \ + libsrc/include/../general/ngexception.hpp \ + libsrc/include/../general/parthreads.hpp \ + libsrc/include/../general/moveablemem.hpp \ + libsrc/include/../general/dynamicmem.hpp \ + libsrc/include/../general/template.hpp \ + libsrc/include/../general/array.hpp libsrc/include/../general/table.hpp \ + libsrc/include/../general/hashtabl.hpp \ + libsrc/include/../general/symbolta.hpp \ + libsrc/include/../general/bitarray.hpp \ + libsrc/include/../general/flags.hpp \ + libsrc/include/../general/spbita2d.hpp \ + libsrc/include/../general/seti.hpp libsrc/include/../general/optmem.hpp \ + libsrc/include/../general/autoptr.hpp \ + libsrc/include/../general/sort.hpp libsrc/include/../general/stack.hpp \ + libsrc/include/../general/mystring.hpp libsrc/include/gprim.hpp \ + libsrc/include/../gprim/gprim.hpp \ + libsrc/include/../gprim/geomobjects.hpp \ + libsrc/include/../gprim/geomops.hpp \ + libsrc/include/../gprim/geomfuncs.hpp \ + libsrc/include/../gprim/geom2d.hpp libsrc/include/../gprim/geom3d.hpp \ + libsrc/include/../gprim/geomtest3d.hpp \ + libsrc/include/../gprim/transform3d.hpp \ + libsrc/include/../gprim/adtree.hpp libsrc/include/linalg.hpp \ + libsrc/include/../linalg/linalg.hpp libsrc/include/../linalg/vector.hpp \ + libsrc/include/../linalg/densemat.hpp \ + libsrc/include/../linalg/polynomial.hpp libsrc/include/opti.hpp \ + libsrc/include/../opti/opti.hpp libsrc/meshing/msghandler.hpp \ + libsrc/meshing/meshtype.hpp libsrc/meshing/localh.hpp \ + libsrc/meshing/meshclass.hpp libsrc/meshing/global.hpp \ + libsrc/meshing/meshtool.hpp libsrc/meshing/ruler2.hpp \ + libsrc/meshing/adfront2.hpp libsrc/meshing/meshing2.hpp \ + libsrc/meshing/improve2.hpp libsrc/meshing/geomsearch.hpp \ + libsrc/meshing/adfront3.hpp libsrc/meshing/ruler3.hpp \ + libsrc/meshing/meshing3.hpp libsrc/meshing/improve3.hpp \ + libsrc/meshing/findip.hpp libsrc/meshing/topology.hpp \ + libsrc/meshing/curvedelems.hpp libsrc/meshing/bisect.hpp \ + libsrc/meshing/clusters.hpp libsrc/meshing/meshfunc.hpp \ + libsrc/meshing/hprefinement.hpp libsrc/meshing/boundarylayer.hpp \ + libsrc/meshing/specials.hpp +# 1 "/Users/geuzaine/.gmsh/Netgen//" +meshing2.o: libsrc/meshing/meshing2.cpp libsrc/include/mystdlib.h \ + libsrc/meshing/meshing.hpp libsrc/include/myadt.hpp \ + libsrc/include/../general/myadt.hpp libsrc/include/mydefs.hpp \ + libsrc/include/../general/ngexception.hpp \ + libsrc/include/../general/parthreads.hpp \ + libsrc/include/../general/moveablemem.hpp \ + libsrc/include/../general/dynamicmem.hpp \ + libsrc/include/../general/template.hpp \ + libsrc/include/../general/array.hpp libsrc/include/../general/table.hpp \ + libsrc/include/../general/hashtabl.hpp \ + libsrc/include/../general/symbolta.hpp \ + libsrc/include/../general/bitarray.hpp \ + libsrc/include/../general/flags.hpp \ + libsrc/include/../general/spbita2d.hpp \ + libsrc/include/../general/seti.hpp libsrc/include/../general/optmem.hpp \ + libsrc/include/../general/autoptr.hpp \ + libsrc/include/../general/sort.hpp libsrc/include/../general/stack.hpp \ + libsrc/include/../general/mystring.hpp libsrc/include/gprim.hpp \ + libsrc/include/../gprim/gprim.hpp \ + libsrc/include/../gprim/geomobjects.hpp \ + libsrc/include/../gprim/geomops.hpp \ + libsrc/include/../gprim/geomfuncs.hpp \ + libsrc/include/../gprim/geom2d.hpp libsrc/include/../gprim/geom3d.hpp \ + libsrc/include/../gprim/geomtest3d.hpp \ + libsrc/include/../gprim/transform3d.hpp \ + libsrc/include/../gprim/adtree.hpp libsrc/include/linalg.hpp \ + libsrc/include/../linalg/linalg.hpp libsrc/include/../linalg/vector.hpp \ + libsrc/include/../linalg/densemat.hpp \ + libsrc/include/../linalg/polynomial.hpp libsrc/include/opti.hpp \ + libsrc/include/../opti/opti.hpp libsrc/meshing/msghandler.hpp \ + libsrc/meshing/meshtype.hpp libsrc/meshing/localh.hpp \ + libsrc/meshing/meshclass.hpp libsrc/meshing/global.hpp \ + libsrc/meshing/meshtool.hpp libsrc/meshing/ruler2.hpp \ + libsrc/meshing/adfront2.hpp libsrc/meshing/meshing2.hpp \ + libsrc/meshing/improve2.hpp libsrc/meshing/geomsearch.hpp \ + libsrc/meshing/adfront3.hpp libsrc/meshing/ruler3.hpp \ + libsrc/meshing/meshing3.hpp libsrc/meshing/improve3.hpp \ + libsrc/meshing/findip.hpp libsrc/meshing/topology.hpp \ + libsrc/meshing/curvedelems.hpp libsrc/meshing/bisect.hpp \ + libsrc/meshing/clusters.hpp libsrc/meshing/meshfunc.hpp \ + libsrc/meshing/hprefinement.hpp libsrc/meshing/boundarylayer.hpp \ + libsrc/meshing/specials.hpp +# 1 "/Users/geuzaine/.gmsh/Netgen//" +quadrls.o: libsrc/meshing/quadrls.cpp +# 1 "/Users/geuzaine/.gmsh/Netgen//" +specials.o: libsrc/meshing/specials.cpp libsrc/include/mystdlib.h \ + libsrc/meshing/meshing.hpp libsrc/include/myadt.hpp \ + libsrc/include/../general/myadt.hpp libsrc/include/mydefs.hpp \ + libsrc/include/../general/ngexception.hpp \ + libsrc/include/../general/parthreads.hpp \ + libsrc/include/../general/moveablemem.hpp \ + libsrc/include/../general/dynamicmem.hpp \ + libsrc/include/../general/template.hpp \ + libsrc/include/../general/array.hpp libsrc/include/../general/table.hpp \ + libsrc/include/../general/hashtabl.hpp \ + libsrc/include/../general/symbolta.hpp \ + libsrc/include/../general/bitarray.hpp \ + libsrc/include/../general/flags.hpp \ + libsrc/include/../general/spbita2d.hpp \ + libsrc/include/../general/seti.hpp libsrc/include/../general/optmem.hpp \ + libsrc/include/../general/autoptr.hpp \ + libsrc/include/../general/sort.hpp libsrc/include/../general/stack.hpp \ + libsrc/include/../general/mystring.hpp libsrc/include/gprim.hpp \ + libsrc/include/../gprim/gprim.hpp \ + libsrc/include/../gprim/geomobjects.hpp \ + libsrc/include/../gprim/geomops.hpp \ + libsrc/include/../gprim/geomfuncs.hpp \ + libsrc/include/../gprim/geom2d.hpp libsrc/include/../gprim/geom3d.hpp \ + libsrc/include/../gprim/geomtest3d.hpp \ + libsrc/include/../gprim/transform3d.hpp \ + libsrc/include/../gprim/adtree.hpp libsrc/include/linalg.hpp \ + libsrc/include/../linalg/linalg.hpp libsrc/include/../linalg/vector.hpp \ + libsrc/include/../linalg/densemat.hpp \ + libsrc/include/../linalg/polynomial.hpp libsrc/include/opti.hpp \ + libsrc/include/../opti/opti.hpp libsrc/meshing/msghandler.hpp \ + libsrc/meshing/meshtype.hpp libsrc/meshing/localh.hpp \ + libsrc/meshing/meshclass.hpp libsrc/meshing/global.hpp \ + libsrc/meshing/meshtool.hpp libsrc/meshing/ruler2.hpp \ + libsrc/meshing/adfront2.hpp libsrc/meshing/meshing2.hpp \ + libsrc/meshing/improve2.hpp libsrc/meshing/geomsearch.hpp \ + libsrc/meshing/adfront3.hpp libsrc/meshing/ruler3.hpp \ + libsrc/meshing/meshing3.hpp libsrc/meshing/improve3.hpp \ + libsrc/meshing/findip.hpp libsrc/meshing/topology.hpp \ + libsrc/meshing/curvedelems.hpp libsrc/meshing/bisect.hpp \ + libsrc/meshing/clusters.hpp libsrc/meshing/meshfunc.hpp \ + libsrc/meshing/hprefinement.hpp libsrc/meshing/boundarylayer.hpp \ + libsrc/meshing/specials.hpp +# 1 "/Users/geuzaine/.gmsh/Netgen//" +parser2.o: libsrc/meshing/parser2.cpp libsrc/include/mystdlib.h \ + libsrc/meshing/meshing.hpp libsrc/include/myadt.hpp \ + libsrc/include/../general/myadt.hpp libsrc/include/mydefs.hpp \ + libsrc/include/../general/ngexception.hpp \ + libsrc/include/../general/parthreads.hpp \ + libsrc/include/../general/moveablemem.hpp \ + libsrc/include/../general/dynamicmem.hpp \ + libsrc/include/../general/template.hpp \ + libsrc/include/../general/array.hpp libsrc/include/../general/table.hpp \ + libsrc/include/../general/hashtabl.hpp \ + libsrc/include/../general/symbolta.hpp \ + libsrc/include/../general/bitarray.hpp \ + libsrc/include/../general/flags.hpp \ + libsrc/include/../general/spbita2d.hpp \ + libsrc/include/../general/seti.hpp libsrc/include/../general/optmem.hpp \ + libsrc/include/../general/autoptr.hpp \ + libsrc/include/../general/sort.hpp libsrc/include/../general/stack.hpp \ + libsrc/include/../general/mystring.hpp libsrc/include/gprim.hpp \ + libsrc/include/../gprim/gprim.hpp \ + libsrc/include/../gprim/geomobjects.hpp \ + libsrc/include/../gprim/geomops.hpp \ + libsrc/include/../gprim/geomfuncs.hpp \ + libsrc/include/../gprim/geom2d.hpp libsrc/include/../gprim/geom3d.hpp \ + libsrc/include/../gprim/geomtest3d.hpp \ + libsrc/include/../gprim/transform3d.hpp \ + libsrc/include/../gprim/adtree.hpp libsrc/include/linalg.hpp \ + libsrc/include/../linalg/linalg.hpp libsrc/include/../linalg/vector.hpp \ + libsrc/include/../linalg/densemat.hpp \ + libsrc/include/../linalg/polynomial.hpp libsrc/include/opti.hpp \ + libsrc/include/../opti/opti.hpp libsrc/meshing/msghandler.hpp \ + libsrc/meshing/meshtype.hpp libsrc/meshing/localh.hpp \ + libsrc/meshing/meshclass.hpp libsrc/meshing/global.hpp \ + libsrc/meshing/meshtool.hpp libsrc/meshing/ruler2.hpp \ + libsrc/meshing/adfront2.hpp libsrc/meshing/meshing2.hpp \ + libsrc/meshing/improve2.hpp libsrc/meshing/geomsearch.hpp \ + libsrc/meshing/adfront3.hpp libsrc/meshing/ruler3.hpp \ + libsrc/meshing/meshing3.hpp libsrc/meshing/improve3.hpp \ + libsrc/meshing/findip.hpp libsrc/meshing/topology.hpp \ + libsrc/meshing/curvedelems.hpp libsrc/meshing/bisect.hpp \ + libsrc/meshing/clusters.hpp libsrc/meshing/meshfunc.hpp \ + libsrc/meshing/hprefinement.hpp libsrc/meshing/boundarylayer.hpp \ + libsrc/meshing/specials.hpp +# 1 "/Users/geuzaine/.gmsh/Netgen//" +meshing3.o: libsrc/meshing/meshing3.cpp libsrc/include/mystdlib.h \ + libsrc/meshing/meshing.hpp libsrc/include/myadt.hpp \ + libsrc/include/../general/myadt.hpp libsrc/include/mydefs.hpp \ + libsrc/include/../general/ngexception.hpp \ + libsrc/include/../general/parthreads.hpp \ + libsrc/include/../general/moveablemem.hpp \ + libsrc/include/../general/dynamicmem.hpp \ + libsrc/include/../general/template.hpp \ + libsrc/include/../general/array.hpp libsrc/include/../general/table.hpp \ + libsrc/include/../general/hashtabl.hpp \ + libsrc/include/../general/symbolta.hpp \ + libsrc/include/../general/bitarray.hpp \ + libsrc/include/../general/flags.hpp \ + libsrc/include/../general/spbita2d.hpp \ + libsrc/include/../general/seti.hpp libsrc/include/../general/optmem.hpp \ + libsrc/include/../general/autoptr.hpp \ + libsrc/include/../general/sort.hpp libsrc/include/../general/stack.hpp \ + libsrc/include/../general/mystring.hpp libsrc/include/gprim.hpp \ + libsrc/include/../gprim/gprim.hpp \ + libsrc/include/../gprim/geomobjects.hpp \ + libsrc/include/../gprim/geomops.hpp \ + libsrc/include/../gprim/geomfuncs.hpp \ + libsrc/include/../gprim/geom2d.hpp libsrc/include/../gprim/geom3d.hpp \ + libsrc/include/../gprim/geomtest3d.hpp \ + libsrc/include/../gprim/transform3d.hpp \ + libsrc/include/../gprim/adtree.hpp libsrc/include/linalg.hpp \ + libsrc/include/../linalg/linalg.hpp libsrc/include/../linalg/vector.hpp \ + libsrc/include/../linalg/densemat.hpp \ + libsrc/include/../linalg/polynomial.hpp libsrc/include/opti.hpp \ + libsrc/include/../opti/opti.hpp libsrc/meshing/msghandler.hpp \ + libsrc/meshing/meshtype.hpp libsrc/meshing/localh.hpp \ + libsrc/meshing/meshclass.hpp libsrc/meshing/global.hpp \ + libsrc/meshing/meshtool.hpp libsrc/meshing/ruler2.hpp \ + libsrc/meshing/adfront2.hpp libsrc/meshing/meshing2.hpp \ + libsrc/meshing/improve2.hpp libsrc/meshing/geomsearch.hpp \ + libsrc/meshing/adfront3.hpp libsrc/meshing/ruler3.hpp \ + libsrc/meshing/meshing3.hpp libsrc/meshing/improve3.hpp \ + libsrc/meshing/findip.hpp libsrc/meshing/topology.hpp \ + libsrc/meshing/curvedelems.hpp libsrc/meshing/bisect.hpp \ + libsrc/meshing/clusters.hpp libsrc/meshing/meshfunc.hpp \ + libsrc/meshing/hprefinement.hpp libsrc/meshing/boundarylayer.hpp \ + libsrc/meshing/specials.hpp +# 1 "/Users/geuzaine/.gmsh/Netgen//" +meshfunc.o: libsrc/meshing/meshfunc.cpp libsrc/include/mystdlib.h \ + libsrc/meshing/meshing.hpp libsrc/include/myadt.hpp \ + libsrc/include/../general/myadt.hpp libsrc/include/mydefs.hpp \ + libsrc/include/../general/ngexception.hpp \ + libsrc/include/../general/parthreads.hpp \ + libsrc/include/../general/moveablemem.hpp \ + libsrc/include/../general/dynamicmem.hpp \ + libsrc/include/../general/template.hpp \ + libsrc/include/../general/array.hpp libsrc/include/../general/table.hpp \ + libsrc/include/../general/hashtabl.hpp \ + libsrc/include/../general/symbolta.hpp \ + libsrc/include/../general/bitarray.hpp \ + libsrc/include/../general/flags.hpp \ + libsrc/include/../general/spbita2d.hpp \ + libsrc/include/../general/seti.hpp libsrc/include/../general/optmem.hpp \ + libsrc/include/../general/autoptr.hpp \ + libsrc/include/../general/sort.hpp libsrc/include/../general/stack.hpp \ + libsrc/include/../general/mystring.hpp libsrc/include/gprim.hpp \ + libsrc/include/../gprim/gprim.hpp \ + libsrc/include/../gprim/geomobjects.hpp \ + libsrc/include/../gprim/geomops.hpp \ + libsrc/include/../gprim/geomfuncs.hpp \ + libsrc/include/../gprim/geom2d.hpp libsrc/include/../gprim/geom3d.hpp \ + libsrc/include/../gprim/geomtest3d.hpp \ + libsrc/include/../gprim/transform3d.hpp \ + libsrc/include/../gprim/adtree.hpp libsrc/include/linalg.hpp \ + libsrc/include/../linalg/linalg.hpp libsrc/include/../linalg/vector.hpp \ + libsrc/include/../linalg/densemat.hpp \ + libsrc/include/../linalg/polynomial.hpp libsrc/include/opti.hpp \ + libsrc/include/../opti/opti.hpp libsrc/meshing/msghandler.hpp \ + libsrc/meshing/meshtype.hpp libsrc/meshing/localh.hpp \ + libsrc/meshing/meshclass.hpp libsrc/meshing/global.hpp \ + libsrc/meshing/meshtool.hpp libsrc/meshing/ruler2.hpp \ + libsrc/meshing/adfront2.hpp libsrc/meshing/meshing2.hpp \ + libsrc/meshing/improve2.hpp libsrc/meshing/geomsearch.hpp \ + libsrc/meshing/adfront3.hpp libsrc/meshing/ruler3.hpp \ + libsrc/meshing/meshing3.hpp libsrc/meshing/improve3.hpp \ + libsrc/meshing/findip.hpp libsrc/meshing/topology.hpp \ + libsrc/meshing/curvedelems.hpp libsrc/meshing/bisect.hpp \ + libsrc/meshing/clusters.hpp libsrc/meshing/meshfunc.hpp \ + libsrc/meshing/hprefinement.hpp libsrc/meshing/boundarylayer.hpp \ + libsrc/meshing/specials.hpp +# 1 "/Users/geuzaine/.gmsh/Netgen//" +localh.o: libsrc/meshing/localh.cpp libsrc/include/mystdlib.h \ + libsrc/meshing/meshing.hpp libsrc/include/myadt.hpp \ + libsrc/include/../general/myadt.hpp libsrc/include/mydefs.hpp \ + libsrc/include/../general/ngexception.hpp \ + libsrc/include/../general/parthreads.hpp \ + libsrc/include/../general/moveablemem.hpp \ + libsrc/include/../general/dynamicmem.hpp \ + libsrc/include/../general/template.hpp \ + libsrc/include/../general/array.hpp libsrc/include/../general/table.hpp \ + libsrc/include/../general/hashtabl.hpp \ + libsrc/include/../general/symbolta.hpp \ + libsrc/include/../general/bitarray.hpp \ + libsrc/include/../general/flags.hpp \ + libsrc/include/../general/spbita2d.hpp \ + libsrc/include/../general/seti.hpp libsrc/include/../general/optmem.hpp \ + libsrc/include/../general/autoptr.hpp \ + libsrc/include/../general/sort.hpp libsrc/include/../general/stack.hpp \ + libsrc/include/../general/mystring.hpp libsrc/include/gprim.hpp \ + libsrc/include/../gprim/gprim.hpp \ + libsrc/include/../gprim/geomobjects.hpp \ + libsrc/include/../gprim/geomops.hpp \ + libsrc/include/../gprim/geomfuncs.hpp \ + libsrc/include/../gprim/geom2d.hpp libsrc/include/../gprim/geom3d.hpp \ + libsrc/include/../gprim/geomtest3d.hpp \ + libsrc/include/../gprim/transform3d.hpp \ + libsrc/include/../gprim/adtree.hpp libsrc/include/linalg.hpp \ + libsrc/include/../linalg/linalg.hpp libsrc/include/../linalg/vector.hpp \ + libsrc/include/../linalg/densemat.hpp \ + libsrc/include/../linalg/polynomial.hpp libsrc/include/opti.hpp \ + libsrc/include/../opti/opti.hpp libsrc/meshing/msghandler.hpp \ + libsrc/meshing/meshtype.hpp libsrc/meshing/localh.hpp \ + libsrc/meshing/meshclass.hpp libsrc/meshing/global.hpp \ + libsrc/meshing/meshtool.hpp libsrc/meshing/ruler2.hpp \ + libsrc/meshing/adfront2.hpp libsrc/meshing/meshing2.hpp \ + libsrc/meshing/improve2.hpp libsrc/meshing/geomsearch.hpp \ + libsrc/meshing/adfront3.hpp libsrc/meshing/ruler3.hpp \ + libsrc/meshing/meshing3.hpp libsrc/meshing/improve3.hpp \ + libsrc/meshing/findip.hpp libsrc/meshing/topology.hpp \ + libsrc/meshing/curvedelems.hpp libsrc/meshing/bisect.hpp \ + libsrc/meshing/clusters.hpp libsrc/meshing/meshfunc.hpp \ + libsrc/meshing/hprefinement.hpp libsrc/meshing/boundarylayer.hpp \ + libsrc/meshing/specials.hpp +# 1 "/Users/geuzaine/.gmsh/Netgen//" +improve2gen.o: libsrc/meshing/improve2gen.cpp libsrc/include/mystdlib.h \ + libsrc/meshing/meshing.hpp libsrc/include/myadt.hpp \ + libsrc/include/../general/myadt.hpp libsrc/include/mydefs.hpp \ + libsrc/include/../general/ngexception.hpp \ + libsrc/include/../general/parthreads.hpp \ + libsrc/include/../general/moveablemem.hpp \ + libsrc/include/../general/dynamicmem.hpp \ + libsrc/include/../general/template.hpp \ + libsrc/include/../general/array.hpp libsrc/include/../general/table.hpp \ + libsrc/include/../general/hashtabl.hpp \ + libsrc/include/../general/symbolta.hpp \ + libsrc/include/../general/bitarray.hpp \ + libsrc/include/../general/flags.hpp \ + libsrc/include/../general/spbita2d.hpp \ + libsrc/include/../general/seti.hpp libsrc/include/../general/optmem.hpp \ + libsrc/include/../general/autoptr.hpp \ + libsrc/include/../general/sort.hpp libsrc/include/../general/stack.hpp \ + libsrc/include/../general/mystring.hpp libsrc/include/gprim.hpp \ + libsrc/include/../gprim/gprim.hpp \ + libsrc/include/../gprim/geomobjects.hpp \ + libsrc/include/../gprim/geomops.hpp \ + libsrc/include/../gprim/geomfuncs.hpp \ + libsrc/include/../gprim/geom2d.hpp libsrc/include/../gprim/geom3d.hpp \ + libsrc/include/../gprim/geomtest3d.hpp \ + libsrc/include/../gprim/transform3d.hpp \ + libsrc/include/../gprim/adtree.hpp libsrc/include/linalg.hpp \ + libsrc/include/../linalg/linalg.hpp libsrc/include/../linalg/vector.hpp \ + libsrc/include/../linalg/densemat.hpp \ + libsrc/include/../linalg/polynomial.hpp libsrc/include/opti.hpp \ + libsrc/include/../opti/opti.hpp libsrc/meshing/msghandler.hpp \ + libsrc/meshing/meshtype.hpp libsrc/meshing/localh.hpp \ + libsrc/meshing/meshclass.hpp libsrc/meshing/global.hpp \ + libsrc/meshing/meshtool.hpp libsrc/meshing/ruler2.hpp \ + libsrc/meshing/adfront2.hpp libsrc/meshing/meshing2.hpp \ + libsrc/meshing/improve2.hpp libsrc/meshing/geomsearch.hpp \ + libsrc/meshing/adfront3.hpp libsrc/meshing/ruler3.hpp \ + libsrc/meshing/meshing3.hpp libsrc/meshing/improve3.hpp \ + libsrc/meshing/findip.hpp libsrc/meshing/topology.hpp \ + libsrc/meshing/curvedelems.hpp libsrc/meshing/bisect.hpp \ + libsrc/meshing/clusters.hpp libsrc/meshing/meshfunc.hpp \ + libsrc/meshing/hprefinement.hpp libsrc/meshing/boundarylayer.hpp \ + libsrc/meshing/specials.hpp libsrc/include/../opti/opti.hpp +# 1 "/Users/geuzaine/.gmsh/Netgen//" +delaunay.o: libsrc/meshing/delaunay.cpp libsrc/include/mystdlib.h \ + libsrc/meshing/meshing.hpp libsrc/include/myadt.hpp \ + libsrc/include/../general/myadt.hpp libsrc/include/mydefs.hpp \ + libsrc/include/../general/ngexception.hpp \ + libsrc/include/../general/parthreads.hpp \ + libsrc/include/../general/moveablemem.hpp \ + libsrc/include/../general/dynamicmem.hpp \ + libsrc/include/../general/template.hpp \ + libsrc/include/../general/array.hpp libsrc/include/../general/table.hpp \ + libsrc/include/../general/hashtabl.hpp \ + libsrc/include/../general/symbolta.hpp \ + libsrc/include/../general/bitarray.hpp \ + libsrc/include/../general/flags.hpp \ + libsrc/include/../general/spbita2d.hpp \ + libsrc/include/../general/seti.hpp libsrc/include/../general/optmem.hpp \ + libsrc/include/../general/autoptr.hpp \ + libsrc/include/../general/sort.hpp libsrc/include/../general/stack.hpp \ + libsrc/include/../general/mystring.hpp libsrc/include/gprim.hpp \ + libsrc/include/../gprim/gprim.hpp \ + libsrc/include/../gprim/geomobjects.hpp \ + libsrc/include/../gprim/geomops.hpp \ + libsrc/include/../gprim/geomfuncs.hpp \ + libsrc/include/../gprim/geom2d.hpp libsrc/include/../gprim/geom3d.hpp \ + libsrc/include/../gprim/geomtest3d.hpp \ + libsrc/include/../gprim/transform3d.hpp \ + libsrc/include/../gprim/adtree.hpp libsrc/include/linalg.hpp \ + libsrc/include/../linalg/linalg.hpp libsrc/include/../linalg/vector.hpp \ + libsrc/include/../linalg/densemat.hpp \ + libsrc/include/../linalg/polynomial.hpp libsrc/include/opti.hpp \ + libsrc/include/../opti/opti.hpp libsrc/meshing/msghandler.hpp \ + libsrc/meshing/meshtype.hpp libsrc/meshing/localh.hpp \ + libsrc/meshing/meshclass.hpp libsrc/meshing/global.hpp \ + libsrc/meshing/meshtool.hpp libsrc/meshing/ruler2.hpp \ + libsrc/meshing/adfront2.hpp libsrc/meshing/meshing2.hpp \ + libsrc/meshing/improve2.hpp libsrc/meshing/geomsearch.hpp \ + libsrc/meshing/adfront3.hpp libsrc/meshing/ruler3.hpp \ + libsrc/meshing/meshing3.hpp libsrc/meshing/improve3.hpp \ + libsrc/meshing/findip.hpp libsrc/meshing/topology.hpp \ + libsrc/meshing/curvedelems.hpp libsrc/meshing/bisect.hpp \ + libsrc/meshing/clusters.hpp libsrc/meshing/meshfunc.hpp \ + libsrc/meshing/hprefinement.hpp libsrc/meshing/boundarylayer.hpp \ + libsrc/meshing/specials.hpp +# 1 "/Users/geuzaine/.gmsh/Netgen//" +boundarylayer.o: libsrc/meshing/boundarylayer.cpp \ + libsrc/include/mystdlib.h libsrc/meshing/meshing.hpp \ + libsrc/include/myadt.hpp libsrc/include/../general/myadt.hpp \ + libsrc/include/mydefs.hpp libsrc/include/../general/ngexception.hpp \ + libsrc/include/../general/parthreads.hpp \ + libsrc/include/../general/moveablemem.hpp \ + libsrc/include/../general/dynamicmem.hpp \ + libsrc/include/../general/template.hpp \ + libsrc/include/../general/array.hpp libsrc/include/../general/table.hpp \ + libsrc/include/../general/hashtabl.hpp \ + libsrc/include/../general/symbolta.hpp \ + libsrc/include/../general/bitarray.hpp \ + libsrc/include/../general/flags.hpp \ + libsrc/include/../general/spbita2d.hpp \ + libsrc/include/../general/seti.hpp libsrc/include/../general/optmem.hpp \ + libsrc/include/../general/autoptr.hpp \ + libsrc/include/../general/sort.hpp libsrc/include/../general/stack.hpp \ + libsrc/include/../general/mystring.hpp libsrc/include/gprim.hpp \ + libsrc/include/../gprim/gprim.hpp \ + libsrc/include/../gprim/geomobjects.hpp \ + libsrc/include/../gprim/geomops.hpp \ + libsrc/include/../gprim/geomfuncs.hpp \ + libsrc/include/../gprim/geom2d.hpp libsrc/include/../gprim/geom3d.hpp \ + libsrc/include/../gprim/geomtest3d.hpp \ + libsrc/include/../gprim/transform3d.hpp \ + libsrc/include/../gprim/adtree.hpp libsrc/include/linalg.hpp \ + libsrc/include/../linalg/linalg.hpp libsrc/include/../linalg/vector.hpp \ + libsrc/include/../linalg/densemat.hpp \ + libsrc/include/../linalg/polynomial.hpp libsrc/include/opti.hpp \ + libsrc/include/../opti/opti.hpp libsrc/meshing/msghandler.hpp \ + libsrc/meshing/meshtype.hpp libsrc/meshing/localh.hpp \ + libsrc/meshing/meshclass.hpp libsrc/meshing/global.hpp \ + libsrc/meshing/meshtool.hpp libsrc/meshing/ruler2.hpp \ + libsrc/meshing/adfront2.hpp libsrc/meshing/meshing2.hpp \ + libsrc/meshing/improve2.hpp libsrc/meshing/geomsearch.hpp \ + libsrc/meshing/adfront3.hpp libsrc/meshing/ruler3.hpp \ + libsrc/meshing/meshing3.hpp libsrc/meshing/improve3.hpp \ + libsrc/meshing/findip.hpp libsrc/meshing/topology.hpp \ + libsrc/meshing/curvedelems.hpp libsrc/meshing/bisect.hpp \ + libsrc/meshing/clusters.hpp libsrc/meshing/meshfunc.hpp \ + libsrc/meshing/hprefinement.hpp libsrc/meshing/boundarylayer.hpp \ + libsrc/meshing/specials.hpp +# 1 "/Users/geuzaine/.gmsh/Netgen//" +msghandler.o: libsrc/meshing/msghandler.cpp libsrc/include/meshing.hpp \ + libsrc/include/../meshing/meshing.hpp libsrc/include/myadt.hpp \ + libsrc/include/../general/myadt.hpp libsrc/include/mystdlib.h \ + libsrc/include/mydefs.hpp libsrc/include/../general/ngexception.hpp \ + libsrc/include/../general/parthreads.hpp \ + libsrc/include/../general/moveablemem.hpp \ + libsrc/include/../general/dynamicmem.hpp \ + libsrc/include/../general/template.hpp \ + libsrc/include/../general/array.hpp libsrc/include/../general/table.hpp \ + libsrc/include/../general/hashtabl.hpp \ + libsrc/include/../general/symbolta.hpp \ + libsrc/include/../general/bitarray.hpp \ + libsrc/include/../general/flags.hpp \ + libsrc/include/../general/spbita2d.hpp \ + libsrc/include/../general/seti.hpp libsrc/include/../general/optmem.hpp \ + libsrc/include/../general/autoptr.hpp \ + libsrc/include/../general/sort.hpp libsrc/include/../general/stack.hpp \ + libsrc/include/../general/mystring.hpp libsrc/include/gprim.hpp \ + libsrc/include/../gprim/gprim.hpp \ + libsrc/include/../gprim/geomobjects.hpp \ + libsrc/include/../gprim/geomops.hpp \ + libsrc/include/../gprim/geomfuncs.hpp \ + libsrc/include/../gprim/geom2d.hpp libsrc/include/../gprim/geom3d.hpp \ + libsrc/include/../gprim/geomtest3d.hpp \ + libsrc/include/../gprim/transform3d.hpp \ + libsrc/include/../gprim/adtree.hpp libsrc/include/linalg.hpp \ + libsrc/include/../linalg/linalg.hpp libsrc/include/../linalg/vector.hpp \ + libsrc/include/../linalg/densemat.hpp \ + libsrc/include/../linalg/polynomial.hpp libsrc/include/opti.hpp \ + libsrc/include/../opti/opti.hpp \ + libsrc/include/../meshing/msghandler.hpp \ + libsrc/include/../meshing/meshtype.hpp \ + libsrc/include/../meshing/localh.hpp \ + libsrc/include/../meshing/meshclass.hpp \ + libsrc/include/../meshing/global.hpp \ + libsrc/include/../meshing/meshtool.hpp \ + libsrc/include/../meshing/ruler2.hpp \ + libsrc/include/../meshing/adfront2.hpp \ + libsrc/include/../meshing/meshing2.hpp \ + libsrc/include/../meshing/improve2.hpp \ + libsrc/include/../meshing/geomsearch.hpp \ + libsrc/include/../meshing/adfront3.hpp \ + libsrc/include/../meshing/ruler3.hpp \ + libsrc/include/../meshing/meshing3.hpp \ + libsrc/include/../meshing/improve3.hpp \ + libsrc/include/../meshing/findip.hpp \ + libsrc/include/../meshing/topology.hpp \ + libsrc/include/../meshing/curvedelems.hpp \ + libsrc/include/../meshing/bisect.hpp \ + libsrc/include/../meshing/clusters.hpp \ + libsrc/include/../meshing/meshfunc.hpp \ + libsrc/include/../meshing/hprefinement.hpp \ + libsrc/include/../meshing/boundarylayer.hpp \ + libsrc/include/../meshing/specials.hpp +# 1 "/Users/geuzaine/.gmsh/Netgen//" +meshfunc2d.o: libsrc/meshing/meshfunc2d.cpp libsrc/include/mystdlib.h \ + libsrc/meshing/meshing.hpp libsrc/include/myadt.hpp \ + libsrc/include/../general/myadt.hpp libsrc/include/mydefs.hpp \ + libsrc/include/../general/ngexception.hpp \ + libsrc/include/../general/parthreads.hpp \ + libsrc/include/../general/moveablemem.hpp \ + libsrc/include/../general/dynamicmem.hpp \ + libsrc/include/../general/template.hpp \ + libsrc/include/../general/array.hpp libsrc/include/../general/table.hpp \ + libsrc/include/../general/hashtabl.hpp \ + libsrc/include/../general/symbolta.hpp \ + libsrc/include/../general/bitarray.hpp \ + libsrc/include/../general/flags.hpp \ + libsrc/include/../general/spbita2d.hpp \ + libsrc/include/../general/seti.hpp libsrc/include/../general/optmem.hpp \ + libsrc/include/../general/autoptr.hpp \ + libsrc/include/../general/sort.hpp libsrc/include/../general/stack.hpp \ + libsrc/include/../general/mystring.hpp libsrc/include/gprim.hpp \ + libsrc/include/../gprim/gprim.hpp \ + libsrc/include/../gprim/geomobjects.hpp \ + libsrc/include/../gprim/geomops.hpp \ + libsrc/include/../gprim/geomfuncs.hpp \ + libsrc/include/../gprim/geom2d.hpp libsrc/include/../gprim/geom3d.hpp \ + libsrc/include/../gprim/geomtest3d.hpp \ + libsrc/include/../gprim/transform3d.hpp \ + libsrc/include/../gprim/adtree.hpp libsrc/include/linalg.hpp \ + libsrc/include/../linalg/linalg.hpp libsrc/include/../linalg/vector.hpp \ + libsrc/include/../linalg/densemat.hpp \ + libsrc/include/../linalg/polynomial.hpp libsrc/include/opti.hpp \ + libsrc/include/../opti/opti.hpp libsrc/meshing/msghandler.hpp \ + libsrc/meshing/meshtype.hpp libsrc/meshing/localh.hpp \ + libsrc/meshing/meshclass.hpp libsrc/meshing/global.hpp \ + libsrc/meshing/meshtool.hpp libsrc/meshing/ruler2.hpp \ + libsrc/meshing/adfront2.hpp libsrc/meshing/meshing2.hpp \ + libsrc/meshing/improve2.hpp libsrc/meshing/geomsearch.hpp \ + libsrc/meshing/adfront3.hpp libsrc/meshing/ruler3.hpp \ + libsrc/meshing/meshing3.hpp libsrc/meshing/improve3.hpp \ + libsrc/meshing/findip.hpp libsrc/meshing/topology.hpp \ + libsrc/meshing/curvedelems.hpp libsrc/meshing/bisect.hpp \ + libsrc/meshing/clusters.hpp libsrc/meshing/meshfunc.hpp \ + libsrc/meshing/hprefinement.hpp libsrc/meshing/boundarylayer.hpp \ + libsrc/meshing/specials.hpp +# 1 "/Users/geuzaine/.gmsh/Netgen//" +topology.o: libsrc/meshing/topology.cpp libsrc/include/mystdlib.h \ + libsrc/meshing/meshing.hpp libsrc/include/myadt.hpp \ + libsrc/include/../general/myadt.hpp libsrc/include/mydefs.hpp \ + libsrc/include/../general/ngexception.hpp \ + libsrc/include/../general/parthreads.hpp \ + libsrc/include/../general/moveablemem.hpp \ + libsrc/include/../general/dynamicmem.hpp \ + libsrc/include/../general/template.hpp \ + libsrc/include/../general/array.hpp libsrc/include/../general/table.hpp \ + libsrc/include/../general/hashtabl.hpp \ + libsrc/include/../general/symbolta.hpp \ + libsrc/include/../general/bitarray.hpp \ + libsrc/include/../general/flags.hpp \ + libsrc/include/../general/spbita2d.hpp \ + libsrc/include/../general/seti.hpp libsrc/include/../general/optmem.hpp \ + libsrc/include/../general/autoptr.hpp \ + libsrc/include/../general/sort.hpp libsrc/include/../general/stack.hpp \ + libsrc/include/../general/mystring.hpp libsrc/include/gprim.hpp \ + libsrc/include/../gprim/gprim.hpp \ + libsrc/include/../gprim/geomobjects.hpp \ + libsrc/include/../gprim/geomops.hpp \ + libsrc/include/../gprim/geomfuncs.hpp \ + libsrc/include/../gprim/geom2d.hpp libsrc/include/../gprim/geom3d.hpp \ + libsrc/include/../gprim/geomtest3d.hpp \ + libsrc/include/../gprim/transform3d.hpp \ + libsrc/include/../gprim/adtree.hpp libsrc/include/linalg.hpp \ + libsrc/include/../linalg/linalg.hpp libsrc/include/../linalg/vector.hpp \ + libsrc/include/../linalg/densemat.hpp \ + libsrc/include/../linalg/polynomial.hpp libsrc/include/opti.hpp \ + libsrc/include/../opti/opti.hpp libsrc/meshing/msghandler.hpp \ + libsrc/meshing/meshtype.hpp libsrc/meshing/localh.hpp \ + libsrc/meshing/meshclass.hpp libsrc/meshing/global.hpp \ + libsrc/meshing/meshtool.hpp libsrc/meshing/ruler2.hpp \ + libsrc/meshing/adfront2.hpp libsrc/meshing/meshing2.hpp \ + libsrc/meshing/improve2.hpp libsrc/meshing/geomsearch.hpp \ + libsrc/meshing/adfront3.hpp libsrc/meshing/ruler3.hpp \ + libsrc/meshing/meshing3.hpp libsrc/meshing/improve3.hpp \ + libsrc/meshing/findip.hpp libsrc/meshing/topology.hpp \ + libsrc/meshing/curvedelems.hpp libsrc/meshing/bisect.hpp \ + libsrc/meshing/clusters.hpp libsrc/meshing/meshfunc.hpp \ + libsrc/meshing/hprefinement.hpp libsrc/meshing/boundarylayer.hpp \ + libsrc/meshing/specials.hpp +# 1 "/Users/geuzaine/.gmsh/Netgen//" +clusters.o: libsrc/meshing/clusters.cpp libsrc/include/mystdlib.h \ + libsrc/meshing/meshing.hpp libsrc/include/myadt.hpp \ + libsrc/include/../general/myadt.hpp libsrc/include/mydefs.hpp \ + libsrc/include/../general/ngexception.hpp \ + libsrc/include/../general/parthreads.hpp \ + libsrc/include/../general/moveablemem.hpp \ + libsrc/include/../general/dynamicmem.hpp \ + libsrc/include/../general/template.hpp \ + libsrc/include/../general/array.hpp libsrc/include/../general/table.hpp \ + libsrc/include/../general/hashtabl.hpp \ + libsrc/include/../general/symbolta.hpp \ + libsrc/include/../general/bitarray.hpp \ + libsrc/include/../general/flags.hpp \ + libsrc/include/../general/spbita2d.hpp \ + libsrc/include/../general/seti.hpp libsrc/include/../general/optmem.hpp \ + libsrc/include/../general/autoptr.hpp \ + libsrc/include/../general/sort.hpp libsrc/include/../general/stack.hpp \ + libsrc/include/../general/mystring.hpp libsrc/include/gprim.hpp \ + libsrc/include/../gprim/gprim.hpp \ + libsrc/include/../gprim/geomobjects.hpp \ + libsrc/include/../gprim/geomops.hpp \ + libsrc/include/../gprim/geomfuncs.hpp \ + libsrc/include/../gprim/geom2d.hpp libsrc/include/../gprim/geom3d.hpp \ + libsrc/include/../gprim/geomtest3d.hpp \ + libsrc/include/../gprim/transform3d.hpp \ + libsrc/include/../gprim/adtree.hpp libsrc/include/linalg.hpp \ + libsrc/include/../linalg/linalg.hpp libsrc/include/../linalg/vector.hpp \ + libsrc/include/../linalg/densemat.hpp \ + libsrc/include/../linalg/polynomial.hpp libsrc/include/opti.hpp \ + libsrc/include/../opti/opti.hpp libsrc/meshing/msghandler.hpp \ + libsrc/meshing/meshtype.hpp libsrc/meshing/localh.hpp \ + libsrc/meshing/meshclass.hpp libsrc/meshing/global.hpp \ + libsrc/meshing/meshtool.hpp libsrc/meshing/ruler2.hpp \ + libsrc/meshing/adfront2.hpp libsrc/meshing/meshing2.hpp \ + libsrc/meshing/improve2.hpp libsrc/meshing/geomsearch.hpp \ + libsrc/meshing/adfront3.hpp libsrc/meshing/ruler3.hpp \ + libsrc/meshing/meshing3.hpp libsrc/meshing/improve3.hpp \ + libsrc/meshing/findip.hpp libsrc/meshing/topology.hpp \ + libsrc/meshing/curvedelems.hpp libsrc/meshing/bisect.hpp \ + libsrc/meshing/clusters.hpp libsrc/meshing/meshfunc.hpp \ + libsrc/meshing/hprefinement.hpp libsrc/meshing/boundarylayer.hpp \ + libsrc/meshing/specials.hpp +# 1 "/Users/geuzaine/.gmsh/Netgen//" +curvedelems.o: libsrc/meshing/curvedelems.cpp libsrc/include/mystdlib.h \ + libsrc/meshing/meshing.hpp libsrc/include/myadt.hpp \ + libsrc/include/../general/myadt.hpp libsrc/include/mydefs.hpp \ + libsrc/include/../general/ngexception.hpp \ + libsrc/include/../general/parthreads.hpp \ + libsrc/include/../general/moveablemem.hpp \ + libsrc/include/../general/dynamicmem.hpp \ + libsrc/include/../general/template.hpp \ + libsrc/include/../general/array.hpp libsrc/include/../general/table.hpp \ + libsrc/include/../general/hashtabl.hpp \ + libsrc/include/../general/symbolta.hpp \ + libsrc/include/../general/bitarray.hpp \ + libsrc/include/../general/flags.hpp \ + libsrc/include/../general/spbita2d.hpp \ + libsrc/include/../general/seti.hpp libsrc/include/../general/optmem.hpp \ + libsrc/include/../general/autoptr.hpp \ + libsrc/include/../general/sort.hpp libsrc/include/../general/stack.hpp \ + libsrc/include/../general/mystring.hpp libsrc/include/gprim.hpp \ + libsrc/include/../gprim/gprim.hpp \ + libsrc/include/../gprim/geomobjects.hpp \ + libsrc/include/../gprim/geomops.hpp \ + libsrc/include/../gprim/geomfuncs.hpp \ + libsrc/include/../gprim/geom2d.hpp libsrc/include/../gprim/geom3d.hpp \ + libsrc/include/../gprim/geomtest3d.hpp \ + libsrc/include/../gprim/transform3d.hpp \ + libsrc/include/../gprim/adtree.hpp libsrc/include/linalg.hpp \ + libsrc/include/../linalg/linalg.hpp libsrc/include/../linalg/vector.hpp \ + libsrc/include/../linalg/densemat.hpp \ + libsrc/include/../linalg/polynomial.hpp libsrc/include/opti.hpp \ + libsrc/include/../opti/opti.hpp libsrc/meshing/msghandler.hpp \ + libsrc/meshing/meshtype.hpp libsrc/meshing/localh.hpp \ + libsrc/meshing/meshclass.hpp libsrc/meshing/global.hpp \ + libsrc/meshing/meshtool.hpp libsrc/meshing/ruler2.hpp \ + libsrc/meshing/adfront2.hpp libsrc/meshing/meshing2.hpp \ + libsrc/meshing/improve2.hpp libsrc/meshing/geomsearch.hpp \ + libsrc/meshing/adfront3.hpp libsrc/meshing/ruler3.hpp \ + libsrc/meshing/meshing3.hpp libsrc/meshing/improve3.hpp \ + libsrc/meshing/findip.hpp libsrc/meshing/topology.hpp \ + libsrc/meshing/curvedelems.hpp libsrc/meshing/bisect.hpp \ + libsrc/meshing/clusters.hpp libsrc/meshing/meshfunc.hpp \ + libsrc/meshing/hprefinement.hpp libsrc/meshing/boundarylayer.hpp \ + libsrc/meshing/specials.hpp +# 1 "/Users/geuzaine/.gmsh/Netgen//" +curvedelems2.o: libsrc/meshing/curvedelems2.cpp libsrc/include/mystdlib.h \ + libsrc/meshing/meshing.hpp libsrc/include/myadt.hpp \ + libsrc/include/../general/myadt.hpp libsrc/include/mydefs.hpp \ + libsrc/include/../general/ngexception.hpp \ + libsrc/include/../general/parthreads.hpp \ + libsrc/include/../general/moveablemem.hpp \ + libsrc/include/../general/dynamicmem.hpp \ + libsrc/include/../general/template.hpp \ + libsrc/include/../general/array.hpp libsrc/include/../general/table.hpp \ + libsrc/include/../general/hashtabl.hpp \ + libsrc/include/../general/symbolta.hpp \ + libsrc/include/../general/bitarray.hpp \ + libsrc/include/../general/flags.hpp \ + libsrc/include/../general/spbita2d.hpp \ + libsrc/include/../general/seti.hpp libsrc/include/../general/optmem.hpp \ + libsrc/include/../general/autoptr.hpp \ + libsrc/include/../general/sort.hpp libsrc/include/../general/stack.hpp \ + libsrc/include/../general/mystring.hpp libsrc/include/gprim.hpp \ + libsrc/include/../gprim/gprim.hpp \ + libsrc/include/../gprim/geomobjects.hpp \ + libsrc/include/../gprim/geomops.hpp \ + libsrc/include/../gprim/geomfuncs.hpp \ + libsrc/include/../gprim/geom2d.hpp libsrc/include/../gprim/geom3d.hpp \ + libsrc/include/../gprim/geomtest3d.hpp \ + libsrc/include/../gprim/transform3d.hpp \ + libsrc/include/../gprim/adtree.hpp libsrc/include/linalg.hpp \ + libsrc/include/../linalg/linalg.hpp libsrc/include/../linalg/vector.hpp \ + libsrc/include/../linalg/densemat.hpp \ + libsrc/include/../linalg/polynomial.hpp libsrc/include/opti.hpp \ + libsrc/include/../opti/opti.hpp libsrc/meshing/msghandler.hpp \ + libsrc/meshing/meshtype.hpp libsrc/meshing/localh.hpp \ + libsrc/meshing/meshclass.hpp libsrc/meshing/global.hpp \ + libsrc/meshing/meshtool.hpp libsrc/meshing/ruler2.hpp \ + libsrc/meshing/adfront2.hpp libsrc/meshing/meshing2.hpp \ + libsrc/meshing/improve2.hpp libsrc/meshing/geomsearch.hpp \ + libsrc/meshing/adfront3.hpp libsrc/meshing/ruler3.hpp \ + libsrc/meshing/meshing3.hpp libsrc/meshing/improve3.hpp \ + libsrc/meshing/findip.hpp libsrc/meshing/topology.hpp \ + libsrc/meshing/curvedelems.hpp libsrc/meshing/bisect.hpp \ + libsrc/meshing/clusters.hpp libsrc/meshing/meshfunc.hpp \ + libsrc/meshing/hprefinement.hpp libsrc/meshing/boundarylayer.hpp \ + libsrc/meshing/specials.hpp +# 1 "/Users/geuzaine/.gmsh/Netgen//" +hprefinement.o: libsrc/meshing/hprefinement.cpp libsrc/include/mystdlib.h \ + libsrc/meshing/meshing.hpp libsrc/include/myadt.hpp \ + libsrc/include/../general/myadt.hpp libsrc/include/mydefs.hpp \ + libsrc/include/../general/ngexception.hpp \ + libsrc/include/../general/parthreads.hpp \ + libsrc/include/../general/moveablemem.hpp \ + libsrc/include/../general/dynamicmem.hpp \ + libsrc/include/../general/template.hpp \ + libsrc/include/../general/array.hpp libsrc/include/../general/table.hpp \ + libsrc/include/../general/hashtabl.hpp \ + libsrc/include/../general/symbolta.hpp \ + libsrc/include/../general/bitarray.hpp \ + libsrc/include/../general/flags.hpp \ + libsrc/include/../general/spbita2d.hpp \ + libsrc/include/../general/seti.hpp libsrc/include/../general/optmem.hpp \ + libsrc/include/../general/autoptr.hpp \ + libsrc/include/../general/sort.hpp libsrc/include/../general/stack.hpp \ + libsrc/include/../general/mystring.hpp libsrc/include/gprim.hpp \ + libsrc/include/../gprim/gprim.hpp \ + libsrc/include/../gprim/geomobjects.hpp \ + libsrc/include/../gprim/geomops.hpp \ + libsrc/include/../gprim/geomfuncs.hpp \ + libsrc/include/../gprim/geom2d.hpp libsrc/include/../gprim/geom3d.hpp \ + libsrc/include/../gprim/geomtest3d.hpp \ + libsrc/include/../gprim/transform3d.hpp \ + libsrc/include/../gprim/adtree.hpp libsrc/include/linalg.hpp \ + libsrc/include/../linalg/linalg.hpp libsrc/include/../linalg/vector.hpp \ + libsrc/include/../linalg/densemat.hpp \ + libsrc/include/../linalg/polynomial.hpp libsrc/include/opti.hpp \ + libsrc/include/../opti/opti.hpp libsrc/meshing/msghandler.hpp \ + libsrc/meshing/meshtype.hpp libsrc/meshing/localh.hpp \ + libsrc/meshing/meshclass.hpp libsrc/meshing/global.hpp \ + libsrc/meshing/meshtool.hpp libsrc/meshing/ruler2.hpp \ + libsrc/meshing/adfront2.hpp libsrc/meshing/meshing2.hpp \ + libsrc/meshing/improve2.hpp libsrc/meshing/geomsearch.hpp \ + libsrc/meshing/adfront3.hpp libsrc/meshing/ruler3.hpp \ + libsrc/meshing/meshing3.hpp libsrc/meshing/improve3.hpp \ + libsrc/meshing/findip.hpp libsrc/meshing/topology.hpp \ + libsrc/meshing/curvedelems.hpp libsrc/meshing/bisect.hpp \ + libsrc/meshing/clusters.hpp libsrc/meshing/meshfunc.hpp \ + libsrc/meshing/hprefinement.hpp libsrc/meshing/boundarylayer.hpp \ + libsrc/meshing/specials.hpp libsrc/meshing/hpref_trig.hpp \ + libsrc/meshing/hpref_quad.hpp libsrc/meshing/hpref_tet.hpp \ + libsrc/meshing/hpref_prism.hpp +# 1 "/Users/geuzaine/.gmsh/Netgen//" +nglib.o: libsrc/interface/nglib.cpp libsrc/include/mystdlib.h \ + libsrc/include/myadt.hpp libsrc/include/../general/myadt.hpp \ + libsrc/include/mydefs.hpp libsrc/include/../general/ngexception.hpp \ + libsrc/include/../general/parthreads.hpp \ + libsrc/include/../general/moveablemem.hpp \ + libsrc/include/../general/dynamicmem.hpp \ + libsrc/include/../general/template.hpp \ + libsrc/include/../general/array.hpp libsrc/include/../general/table.hpp \ + libsrc/include/../general/hashtabl.hpp \ + libsrc/include/../general/symbolta.hpp \ + libsrc/include/../general/bitarray.hpp \ + libsrc/include/../general/flags.hpp \ + libsrc/include/../general/spbita2d.hpp \ + libsrc/include/../general/seti.hpp libsrc/include/../general/optmem.hpp \ + libsrc/include/../general/autoptr.hpp \ + libsrc/include/../general/sort.hpp libsrc/include/../general/stack.hpp \ + libsrc/include/../general/mystring.hpp libsrc/include/linalg.hpp \ + libsrc/include/../linalg/linalg.hpp libsrc/include/../linalg/vector.hpp \ + libsrc/include/../linalg/densemat.hpp \ + libsrc/include/../linalg/polynomial.hpp libsrc/include/csg.hpp \ + libsrc/include/../csg/csg.hpp libsrc/include/gprim.hpp \ + libsrc/include/../gprim/gprim.hpp \ + libsrc/include/../gprim/geomobjects.hpp \ + libsrc/include/../gprim/geomops.hpp \ + libsrc/include/../gprim/geomfuncs.hpp \ + libsrc/include/../gprim/geom2d.hpp libsrc/include/../gprim/geom3d.hpp \ + libsrc/include/../gprim/geomtest3d.hpp \ + libsrc/include/../gprim/transform3d.hpp \ + libsrc/include/../gprim/adtree.hpp libsrc/include/meshing.hpp \ + libsrc/include/../meshing/meshing.hpp libsrc/include/../gprim/gprim.hpp \ + libsrc/include/../linalg/linalg.hpp libsrc/include/opti.hpp \ + libsrc/include/../opti/opti.hpp \ + libsrc/include/../meshing/msghandler.hpp \ + libsrc/include/../meshing/meshtype.hpp \ + libsrc/include/../meshing/localh.hpp \ + libsrc/include/../meshing/meshclass.hpp \ + libsrc/include/../meshing/global.hpp \ + libsrc/include/../meshing/meshtool.hpp \ + libsrc/include/../meshing/ruler2.hpp \ + libsrc/include/../meshing/adfront2.hpp \ + libsrc/include/../meshing/meshing2.hpp \ + libsrc/include/../meshing/improve2.hpp \ + libsrc/include/../meshing/geomsearch.hpp \ + libsrc/include/../meshing/adfront3.hpp \ + libsrc/include/../meshing/ruler3.hpp \ + libsrc/include/../meshing/meshing3.hpp \ + libsrc/include/../meshing/improve3.hpp \ + libsrc/include/../meshing/findip.hpp \ + libsrc/include/../meshing/topology.hpp \ + libsrc/include/../meshing/curvedelems.hpp \ + libsrc/include/../meshing/bisect.hpp \ + libsrc/include/../meshing/clusters.hpp \ + libsrc/include/../meshing/meshfunc.hpp \ + libsrc/include/../meshing/hprefinement.hpp \ + libsrc/include/../meshing/boundarylayer.hpp \ + libsrc/include/../meshing/specials.hpp \ + libsrc/include/../csg/surface.hpp libsrc/include/../csg/solid.hpp \ + libsrc/include/../csg/identify.hpp \ + libsrc/include/../csg/singularref.hpp libsrc/include/../csg/csgeom.hpp \ + libsrc/include/../csg/triapprox.hpp libsrc/include/../csg/algprim.hpp \ + libsrc/include/../csg/brick.hpp libsrc/include/../csg/spline3d.hpp \ + libsrc/include/../csg/manifold.hpp libsrc/include/../csg/curve2d.hpp \ + libsrc/include/../csg/explicitcurve2d.hpp \ + libsrc/include/../csg/gencyl.hpp libsrc/include/../csg/polyhedra.hpp \ + libsrc/include/../csg/extrusion.hpp \ + libsrc/include/../csg/revolution.hpp libsrc/include/../csg/specpoin.hpp \ + libsrc/include/../csg/edgeflw.hpp libsrc/include/../csg/meshsurf.hpp \ + libsrc/include/stlgeom.hpp libsrc/include/../stlgeom/stlgeom.hpp \ + libsrc/include/../gprim/gprim.hpp \ + libsrc/include/../stlgeom/stltopology.hpp \ + libsrc/include/../stlgeom/stltool.hpp \ + libsrc/include/../stlgeom/stlline.hpp \ + libsrc/include/../stlgeom/meshstlsurface.hpp \ + libsrc/include/geometry2d.hpp libsrc/include/../geom2d/geometry2d.hpp \ + libsrc/include/../gprim/gprim.hpp libsrc/include/../geom2d/spline2d.hpp \ + libsrc/include/../geom2d/splinegeometry2.hpp \ + libsrc/include/../geom2d/geom2dmesh.hpp libsrc/interface/nglib.h +# 1 "/Users/geuzaine/.gmsh/Netgen//" +geomtest3d.o: libsrc/gprim/geomtest3d.cpp libsrc/include/mystdlib.h \ + libsrc/include/myadt.hpp libsrc/include/../general/myadt.hpp \ + libsrc/include/mydefs.hpp libsrc/include/../general/ngexception.hpp \ + libsrc/include/../general/parthreads.hpp \ + libsrc/include/../general/moveablemem.hpp \ + libsrc/include/../general/dynamicmem.hpp \ + libsrc/include/../general/template.hpp \ + libsrc/include/../general/array.hpp libsrc/include/../general/table.hpp \ + libsrc/include/../general/hashtabl.hpp \ + libsrc/include/../general/symbolta.hpp \ + libsrc/include/../general/bitarray.hpp \ + libsrc/include/../general/flags.hpp \ + libsrc/include/../general/spbita2d.hpp \ + libsrc/include/../general/seti.hpp libsrc/include/../general/optmem.hpp \ + libsrc/include/../general/autoptr.hpp \ + libsrc/include/../general/sort.hpp libsrc/include/../general/stack.hpp \ + libsrc/include/../general/mystring.hpp libsrc/include/linalg.hpp \ + libsrc/include/../linalg/linalg.hpp libsrc/include/../linalg/vector.hpp \ + libsrc/include/../linalg/densemat.hpp \ + libsrc/include/../linalg/polynomial.hpp libsrc/include/gprim.hpp \ + libsrc/include/../gprim/gprim.hpp \ + libsrc/include/../gprim/geomobjects.hpp \ + libsrc/include/../gprim/geomops.hpp \ + libsrc/include/../gprim/geomfuncs.hpp \ + libsrc/include/../gprim/geom2d.hpp libsrc/include/../gprim/geom3d.hpp \ + libsrc/include/../gprim/geomtest3d.hpp \ + libsrc/include/../gprim/transform3d.hpp \ + libsrc/include/../gprim/adtree.hpp +# 1 "/Users/geuzaine/.gmsh/Netgen//" +geom2d.o: libsrc/gprim/geom2d.cpp libsrc/include/mystdlib.h \ + libsrc/include/myadt.hpp libsrc/include/../general/myadt.hpp \ + libsrc/include/mydefs.hpp libsrc/include/../general/ngexception.hpp \ + libsrc/include/../general/parthreads.hpp \ + libsrc/include/../general/moveablemem.hpp \ + libsrc/include/../general/dynamicmem.hpp \ + libsrc/include/../general/template.hpp \ + libsrc/include/../general/array.hpp libsrc/include/../general/table.hpp \ + libsrc/include/../general/hashtabl.hpp \ + libsrc/include/../general/symbolta.hpp \ + libsrc/include/../general/bitarray.hpp \ + libsrc/include/../general/flags.hpp \ + libsrc/include/../general/spbita2d.hpp \ + libsrc/include/../general/seti.hpp libsrc/include/../general/optmem.hpp \ + libsrc/include/../general/autoptr.hpp \ + libsrc/include/../general/sort.hpp libsrc/include/../general/stack.hpp \ + libsrc/include/../general/mystring.hpp libsrc/include/gprim.hpp \ + libsrc/include/../gprim/gprim.hpp \ + libsrc/include/../gprim/geomobjects.hpp \ + libsrc/include/../gprim/geomops.hpp \ + libsrc/include/../gprim/geomfuncs.hpp \ + libsrc/include/../gprim/geom2d.hpp libsrc/include/../gprim/geom3d.hpp \ + libsrc/include/../gprim/geomtest3d.hpp \ + libsrc/include/../gprim/transform3d.hpp \ + libsrc/include/../gprim/adtree.hpp +# 1 "/Users/geuzaine/.gmsh/Netgen//" +geom3d.o: libsrc/gprim/geom3d.cpp libsrc/include/mystdlib.h \ + libsrc/include/myadt.hpp libsrc/include/../general/myadt.hpp \ + libsrc/include/mydefs.hpp libsrc/include/../general/ngexception.hpp \ + libsrc/include/../general/parthreads.hpp \ + libsrc/include/../general/moveablemem.hpp \ + libsrc/include/../general/dynamicmem.hpp \ + libsrc/include/../general/template.hpp \ + libsrc/include/../general/array.hpp libsrc/include/../general/table.hpp \ + libsrc/include/../general/hashtabl.hpp \ + libsrc/include/../general/symbolta.hpp \ + libsrc/include/../general/bitarray.hpp \ + libsrc/include/../general/flags.hpp \ + libsrc/include/../general/spbita2d.hpp \ + libsrc/include/../general/seti.hpp libsrc/include/../general/optmem.hpp \ + libsrc/include/../general/autoptr.hpp \ + libsrc/include/../general/sort.hpp libsrc/include/../general/stack.hpp \ + libsrc/include/../general/mystring.hpp libsrc/include/gprim.hpp \ + libsrc/include/../gprim/gprim.hpp \ + libsrc/include/../gprim/geomobjects.hpp \ + libsrc/include/../gprim/geomops.hpp \ + libsrc/include/../gprim/geomfuncs.hpp \ + libsrc/include/../gprim/geom2d.hpp libsrc/include/../gprim/geom3d.hpp \ + libsrc/include/../gprim/geomtest3d.hpp \ + libsrc/include/../gprim/transform3d.hpp \ + libsrc/include/../gprim/adtree.hpp +# 1 "/Users/geuzaine/.gmsh/Netgen//" +adtree.o: libsrc/gprim/adtree.cpp libsrc/include/mystdlib.h \ + libsrc/include/myadt.hpp libsrc/include/../general/myadt.hpp \ + libsrc/include/mydefs.hpp libsrc/include/../general/ngexception.hpp \ + libsrc/include/../general/parthreads.hpp \ + libsrc/include/../general/moveablemem.hpp \ + libsrc/include/../general/dynamicmem.hpp \ + libsrc/include/../general/template.hpp \ + libsrc/include/../general/array.hpp libsrc/include/../general/table.hpp \ + libsrc/include/../general/hashtabl.hpp \ + libsrc/include/../general/symbolta.hpp \ + libsrc/include/../general/bitarray.hpp \ + libsrc/include/../general/flags.hpp \ + libsrc/include/../general/spbita2d.hpp \ + libsrc/include/../general/seti.hpp libsrc/include/../general/optmem.hpp \ + libsrc/include/../general/autoptr.hpp \ + libsrc/include/../general/sort.hpp libsrc/include/../general/stack.hpp \ + libsrc/include/../general/mystring.hpp libsrc/include/gprim.hpp \ + libsrc/include/../gprim/gprim.hpp \ + libsrc/include/../gprim/geomobjects.hpp \ + libsrc/include/../gprim/geomops.hpp \ + libsrc/include/../gprim/geomfuncs.hpp \ + libsrc/include/../gprim/geom2d.hpp libsrc/include/../gprim/geom3d.hpp \ + libsrc/include/../gprim/geomtest3d.hpp \ + libsrc/include/../gprim/transform3d.hpp \ + libsrc/include/../gprim/adtree.hpp +# 1 "/Users/geuzaine/.gmsh/Netgen//" +transform3d.o: libsrc/gprim/transform3d.cpp libsrc/include/mystdlib.h \ + libsrc/include/myadt.hpp libsrc/include/../general/myadt.hpp \ + libsrc/include/mydefs.hpp libsrc/include/../general/ngexception.hpp \ + libsrc/include/../general/parthreads.hpp \ + libsrc/include/../general/moveablemem.hpp \ + libsrc/include/../general/dynamicmem.hpp \ + libsrc/include/../general/template.hpp \ + libsrc/include/../general/array.hpp libsrc/include/../general/table.hpp \ + libsrc/include/../general/hashtabl.hpp \ + libsrc/include/../general/symbolta.hpp \ + libsrc/include/../general/bitarray.hpp \ + libsrc/include/../general/flags.hpp \ + libsrc/include/../general/spbita2d.hpp \ + libsrc/include/../general/seti.hpp libsrc/include/../general/optmem.hpp \ + libsrc/include/../general/autoptr.hpp \ + libsrc/include/../general/sort.hpp libsrc/include/../general/stack.hpp \ + libsrc/include/../general/mystring.hpp libsrc/include/gprim.hpp \ + libsrc/include/../gprim/gprim.hpp \ + libsrc/include/../gprim/geomobjects.hpp \ + libsrc/include/../gprim/geomops.hpp \ + libsrc/include/../gprim/geomfuncs.hpp \ + libsrc/include/../gprim/geom2d.hpp libsrc/include/../gprim/geom3d.hpp \ + libsrc/include/../gprim/geomtest3d.hpp \ + libsrc/include/../gprim/transform3d.hpp \ + libsrc/include/../gprim/adtree.hpp libsrc/include/linalg.hpp \ + libsrc/include/../linalg/linalg.hpp libsrc/include/../linalg/vector.hpp \ + libsrc/include/../linalg/densemat.hpp \ + libsrc/include/../linalg/polynomial.hpp +# 1 "/Users/geuzaine/.gmsh/Netgen//" +geomfuncs.o: libsrc/gprim/geomfuncs.cpp libsrc/include/mystdlib.h \ + libsrc/include/myadt.hpp libsrc/include/../general/myadt.hpp \ + libsrc/include/mydefs.hpp libsrc/include/../general/ngexception.hpp \ + libsrc/include/../general/parthreads.hpp \ + libsrc/include/../general/moveablemem.hpp \ + libsrc/include/../general/dynamicmem.hpp \ + libsrc/include/../general/template.hpp \ + libsrc/include/../general/array.hpp libsrc/include/../general/table.hpp \ + libsrc/include/../general/hashtabl.hpp \ + libsrc/include/../general/symbolta.hpp \ + libsrc/include/../general/bitarray.hpp \ + libsrc/include/../general/flags.hpp \ + libsrc/include/../general/spbita2d.hpp \ + libsrc/include/../general/seti.hpp libsrc/include/../general/optmem.hpp \ + libsrc/include/../general/autoptr.hpp \ + libsrc/include/../general/sort.hpp libsrc/include/../general/stack.hpp \ + libsrc/include/../general/mystring.hpp libsrc/include/gprim.hpp \ + libsrc/include/../gprim/gprim.hpp \ + libsrc/include/../gprim/geomobjects.hpp \ + libsrc/include/../gprim/geomops.hpp \ + libsrc/include/../gprim/geomfuncs.hpp \ + libsrc/include/../gprim/geom2d.hpp libsrc/include/../gprim/geom3d.hpp \ + libsrc/include/../gprim/geomtest3d.hpp \ + libsrc/include/../gprim/transform3d.hpp \ + libsrc/include/../gprim/adtree.hpp +# 1 "/Users/geuzaine/.gmsh/Netgen//" +polynomial.o: libsrc/linalg/polynomial.cpp libsrc/include/mystdlib.h \ + libsrc/include/linalg.hpp libsrc/include/../linalg/linalg.hpp \ + libsrc/include/myadt.hpp libsrc/include/../general/myadt.hpp \ + libsrc/include/mydefs.hpp libsrc/include/../general/ngexception.hpp \ + libsrc/include/../general/parthreads.hpp \ + libsrc/include/../general/moveablemem.hpp \ + libsrc/include/../general/dynamicmem.hpp \ + libsrc/include/../general/template.hpp \ + libsrc/include/../general/array.hpp libsrc/include/../general/table.hpp \ + libsrc/include/../general/hashtabl.hpp \ + libsrc/include/../general/symbolta.hpp \ + libsrc/include/../general/bitarray.hpp \ + libsrc/include/../general/flags.hpp \ + libsrc/include/../general/spbita2d.hpp \ + libsrc/include/../general/seti.hpp libsrc/include/../general/optmem.hpp \ + libsrc/include/../general/autoptr.hpp \ + libsrc/include/../general/sort.hpp libsrc/include/../general/stack.hpp \ + libsrc/include/../general/mystring.hpp \ + libsrc/include/../linalg/vector.hpp \ + libsrc/include/../linalg/densemat.hpp \ + libsrc/include/../linalg/polynomial.hpp +# 1 "/Users/geuzaine/.gmsh/Netgen//" +densemat.o: libsrc/linalg/densemat.cpp libsrc/include/mystdlib.h \ + libsrc/include/linalg.hpp libsrc/include/../linalg/linalg.hpp \ + libsrc/include/myadt.hpp libsrc/include/../general/myadt.hpp \ + libsrc/include/mydefs.hpp libsrc/include/../general/ngexception.hpp \ + libsrc/include/../general/parthreads.hpp \ + libsrc/include/../general/moveablemem.hpp \ + libsrc/include/../general/dynamicmem.hpp \ + libsrc/include/../general/template.hpp \ + libsrc/include/../general/array.hpp libsrc/include/../general/table.hpp \ + libsrc/include/../general/hashtabl.hpp \ + libsrc/include/../general/symbolta.hpp \ + libsrc/include/../general/bitarray.hpp \ + libsrc/include/../general/flags.hpp \ + libsrc/include/../general/spbita2d.hpp \ + libsrc/include/../general/seti.hpp libsrc/include/../general/optmem.hpp \ + libsrc/include/../general/autoptr.hpp \ + libsrc/include/../general/sort.hpp libsrc/include/../general/stack.hpp \ + libsrc/include/../general/mystring.hpp \ + libsrc/include/../linalg/vector.hpp \ + libsrc/include/../linalg/densemat.hpp \ + libsrc/include/../linalg/polynomial.hpp +# 1 "/Users/geuzaine/.gmsh/Netgen//" +vector.o: libsrc/linalg/vector.cpp +# 1 "/Users/geuzaine/.gmsh/Netgen//" +algprim.o: libsrc/csg/algprim.cpp libsrc/include/mystdlib.h \ + libsrc/include/linalg.hpp libsrc/include/../linalg/linalg.hpp \ + libsrc/include/myadt.hpp libsrc/include/../general/myadt.hpp \ + libsrc/include/mydefs.hpp libsrc/include/../general/ngexception.hpp \ + libsrc/include/../general/parthreads.hpp \ + libsrc/include/../general/moveablemem.hpp \ + libsrc/include/../general/dynamicmem.hpp \ + libsrc/include/../general/template.hpp \ + libsrc/include/../general/array.hpp libsrc/include/../general/table.hpp \ + libsrc/include/../general/hashtabl.hpp \ + libsrc/include/../general/symbolta.hpp \ + libsrc/include/../general/bitarray.hpp \ + libsrc/include/../general/flags.hpp \ + libsrc/include/../general/spbita2d.hpp \ + libsrc/include/../general/seti.hpp libsrc/include/../general/optmem.hpp \ + libsrc/include/../general/autoptr.hpp \ + libsrc/include/../general/sort.hpp libsrc/include/../general/stack.hpp \ + libsrc/include/../general/mystring.hpp \ + libsrc/include/../linalg/vector.hpp \ + libsrc/include/../linalg/densemat.hpp \ + libsrc/include/../linalg/polynomial.hpp libsrc/include/csg.hpp \ + libsrc/include/../csg/csg.hpp libsrc/include/gprim.hpp \ + libsrc/include/../gprim/gprim.hpp \ + libsrc/include/../gprim/geomobjects.hpp \ + libsrc/include/../gprim/geomops.hpp \ + libsrc/include/../gprim/geomfuncs.hpp \ + libsrc/include/../gprim/geom2d.hpp libsrc/include/../gprim/geom3d.hpp \ + libsrc/include/../gprim/geomtest3d.hpp \ + libsrc/include/../gprim/transform3d.hpp \ + libsrc/include/../gprim/adtree.hpp libsrc/include/meshing.hpp \ + libsrc/include/../meshing/meshing.hpp libsrc/include/../gprim/gprim.hpp \ + libsrc/include/../linalg/linalg.hpp libsrc/include/opti.hpp \ + libsrc/include/../opti/opti.hpp \ + libsrc/include/../meshing/msghandler.hpp \ + libsrc/include/../meshing/meshtype.hpp \ + libsrc/include/../meshing/localh.hpp \ + libsrc/include/../meshing/meshclass.hpp \ + libsrc/include/../meshing/global.hpp \ + libsrc/include/../meshing/meshtool.hpp \ + libsrc/include/../meshing/ruler2.hpp \ + libsrc/include/../meshing/adfront2.hpp \ + libsrc/include/../meshing/meshing2.hpp \ + libsrc/include/../meshing/improve2.hpp \ + libsrc/include/../meshing/geomsearch.hpp \ + libsrc/include/../meshing/adfront3.hpp \ + libsrc/include/../meshing/ruler3.hpp \ + libsrc/include/../meshing/meshing3.hpp \ + libsrc/include/../meshing/improve3.hpp \ + libsrc/include/../meshing/findip.hpp \ + libsrc/include/../meshing/topology.hpp \ + libsrc/include/../meshing/curvedelems.hpp \ + libsrc/include/../meshing/bisect.hpp \ + libsrc/include/../meshing/clusters.hpp \ + libsrc/include/../meshing/meshfunc.hpp \ + libsrc/include/../meshing/hprefinement.hpp \ + libsrc/include/../meshing/boundarylayer.hpp \ + libsrc/include/../meshing/specials.hpp \ + libsrc/include/../csg/surface.hpp libsrc/include/../csg/solid.hpp \ + libsrc/include/../csg/identify.hpp \ + libsrc/include/../csg/singularref.hpp libsrc/include/../csg/csgeom.hpp \ + libsrc/include/../csg/triapprox.hpp libsrc/include/../csg/algprim.hpp \ + libsrc/include/../csg/brick.hpp libsrc/include/../csg/spline3d.hpp \ + libsrc/include/../csg/manifold.hpp libsrc/include/../csg/curve2d.hpp \ + libsrc/include/../csg/explicitcurve2d.hpp \ + libsrc/include/../csg/gencyl.hpp libsrc/include/../csg/polyhedra.hpp \ + libsrc/include/../csg/extrusion.hpp \ + libsrc/include/../csg/revolution.hpp libsrc/include/../csg/specpoin.hpp \ + libsrc/include/../csg/edgeflw.hpp libsrc/include/../csg/meshsurf.hpp +# 1 "/Users/geuzaine/.gmsh/Netgen//" +brick.o: libsrc/csg/brick.cpp libsrc/include/mystdlib.h \ + libsrc/include/linalg.hpp libsrc/include/../linalg/linalg.hpp \ + libsrc/include/myadt.hpp libsrc/include/../general/myadt.hpp \ + libsrc/include/mydefs.hpp libsrc/include/../general/ngexception.hpp \ + libsrc/include/../general/parthreads.hpp \ + libsrc/include/../general/moveablemem.hpp \ + libsrc/include/../general/dynamicmem.hpp \ + libsrc/include/../general/template.hpp \ + libsrc/include/../general/array.hpp libsrc/include/../general/table.hpp \ + libsrc/include/../general/hashtabl.hpp \ + libsrc/include/../general/symbolta.hpp \ + libsrc/include/../general/bitarray.hpp \ + libsrc/include/../general/flags.hpp \ + libsrc/include/../general/spbita2d.hpp \ + libsrc/include/../general/seti.hpp libsrc/include/../general/optmem.hpp \ + libsrc/include/../general/autoptr.hpp \ + libsrc/include/../general/sort.hpp libsrc/include/../general/stack.hpp \ + libsrc/include/../general/mystring.hpp \ + libsrc/include/../linalg/vector.hpp \ + libsrc/include/../linalg/densemat.hpp \ + libsrc/include/../linalg/polynomial.hpp libsrc/include/csg.hpp \ + libsrc/include/../csg/csg.hpp libsrc/include/gprim.hpp \ + libsrc/include/../gprim/gprim.hpp \ + libsrc/include/../gprim/geomobjects.hpp \ + libsrc/include/../gprim/geomops.hpp \ + libsrc/include/../gprim/geomfuncs.hpp \ + libsrc/include/../gprim/geom2d.hpp libsrc/include/../gprim/geom3d.hpp \ + libsrc/include/../gprim/geomtest3d.hpp \ + libsrc/include/../gprim/transform3d.hpp \ + libsrc/include/../gprim/adtree.hpp libsrc/include/meshing.hpp \ + libsrc/include/../meshing/meshing.hpp libsrc/include/../gprim/gprim.hpp \ + libsrc/include/../linalg/linalg.hpp libsrc/include/opti.hpp \ + libsrc/include/../opti/opti.hpp \ + libsrc/include/../meshing/msghandler.hpp \ + libsrc/include/../meshing/meshtype.hpp \ + libsrc/include/../meshing/localh.hpp \ + libsrc/include/../meshing/meshclass.hpp \ + libsrc/include/../meshing/global.hpp \ + libsrc/include/../meshing/meshtool.hpp \ + libsrc/include/../meshing/ruler2.hpp \ + libsrc/include/../meshing/adfront2.hpp \ + libsrc/include/../meshing/meshing2.hpp \ + libsrc/include/../meshing/improve2.hpp \ + libsrc/include/../meshing/geomsearch.hpp \ + libsrc/include/../meshing/adfront3.hpp \ + libsrc/include/../meshing/ruler3.hpp \ + libsrc/include/../meshing/meshing3.hpp \ + libsrc/include/../meshing/improve3.hpp \ + libsrc/include/../meshing/findip.hpp \ + libsrc/include/../meshing/topology.hpp \ + libsrc/include/../meshing/curvedelems.hpp \ + libsrc/include/../meshing/bisect.hpp \ + libsrc/include/../meshing/clusters.hpp \ + libsrc/include/../meshing/meshfunc.hpp \ + libsrc/include/../meshing/hprefinement.hpp \ + libsrc/include/../meshing/boundarylayer.hpp \ + libsrc/include/../meshing/specials.hpp \ + libsrc/include/../csg/surface.hpp libsrc/include/../csg/solid.hpp \ + libsrc/include/../csg/identify.hpp \ + libsrc/include/../csg/singularref.hpp libsrc/include/../csg/csgeom.hpp \ + libsrc/include/../csg/triapprox.hpp libsrc/include/../csg/algprim.hpp \ + libsrc/include/../csg/brick.hpp libsrc/include/../csg/spline3d.hpp \ + libsrc/include/../csg/manifold.hpp libsrc/include/../csg/curve2d.hpp \ + libsrc/include/../csg/explicitcurve2d.hpp \ + libsrc/include/../csg/gencyl.hpp libsrc/include/../csg/polyhedra.hpp \ + libsrc/include/../csg/extrusion.hpp \ + libsrc/include/../csg/revolution.hpp libsrc/include/../csg/specpoin.hpp \ + libsrc/include/../csg/edgeflw.hpp libsrc/include/../csg/meshsurf.hpp +# 1 "/Users/geuzaine/.gmsh/Netgen//" +manifold.o: libsrc/csg/manifold.cpp libsrc/include/csg.hpp \ + libsrc/include/../csg/csg.hpp libsrc/include/myadt.hpp \ + libsrc/include/../general/myadt.hpp libsrc/include/mystdlib.h \ + libsrc/include/mydefs.hpp libsrc/include/../general/ngexception.hpp \ + libsrc/include/../general/parthreads.hpp \ + libsrc/include/../general/moveablemem.hpp \ + libsrc/include/../general/dynamicmem.hpp \ + libsrc/include/../general/template.hpp \ + libsrc/include/../general/array.hpp libsrc/include/../general/table.hpp \ + libsrc/include/../general/hashtabl.hpp \ + libsrc/include/../general/symbolta.hpp \ + libsrc/include/../general/bitarray.hpp \ + libsrc/include/../general/flags.hpp \ + libsrc/include/../general/spbita2d.hpp \ + libsrc/include/../general/seti.hpp libsrc/include/../general/optmem.hpp \ + libsrc/include/../general/autoptr.hpp \ + libsrc/include/../general/sort.hpp libsrc/include/../general/stack.hpp \ + libsrc/include/../general/mystring.hpp libsrc/include/gprim.hpp \ + libsrc/include/../gprim/gprim.hpp \ + libsrc/include/../gprim/geomobjects.hpp \ + libsrc/include/../gprim/geomops.hpp \ + libsrc/include/../gprim/geomfuncs.hpp \ + libsrc/include/../gprim/geom2d.hpp libsrc/include/../gprim/geom3d.hpp \ + libsrc/include/../gprim/geomtest3d.hpp \ + libsrc/include/../gprim/transform3d.hpp \ + libsrc/include/../gprim/adtree.hpp libsrc/include/meshing.hpp \ + libsrc/include/../meshing/meshing.hpp libsrc/include/../gprim/gprim.hpp \ + libsrc/include/linalg.hpp libsrc/include/../linalg/linalg.hpp \ + libsrc/include/../linalg/vector.hpp \ + libsrc/include/../linalg/densemat.hpp \ + libsrc/include/../linalg/polynomial.hpp libsrc/include/opti.hpp \ + libsrc/include/../opti/opti.hpp \ + libsrc/include/../meshing/msghandler.hpp \ + libsrc/include/../meshing/meshtype.hpp \ + libsrc/include/../meshing/localh.hpp \ + libsrc/include/../meshing/meshclass.hpp \ + libsrc/include/../meshing/global.hpp \ + libsrc/include/../meshing/meshtool.hpp \ + libsrc/include/../meshing/ruler2.hpp \ + libsrc/include/../meshing/adfront2.hpp \ + libsrc/include/../meshing/meshing2.hpp \ + libsrc/include/../meshing/improve2.hpp \ + libsrc/include/../meshing/geomsearch.hpp \ + libsrc/include/../meshing/adfront3.hpp \ + libsrc/include/../meshing/ruler3.hpp \ + libsrc/include/../meshing/meshing3.hpp \ + libsrc/include/../meshing/improve3.hpp \ + libsrc/include/../meshing/findip.hpp \ + libsrc/include/../meshing/topology.hpp \ + libsrc/include/../meshing/curvedelems.hpp \ + libsrc/include/../meshing/bisect.hpp \ + libsrc/include/../meshing/clusters.hpp \ + libsrc/include/../meshing/meshfunc.hpp \ + libsrc/include/../meshing/hprefinement.hpp \ + libsrc/include/../meshing/boundarylayer.hpp \ + libsrc/include/../meshing/specials.hpp \ + libsrc/include/../csg/surface.hpp libsrc/include/../csg/solid.hpp \ + libsrc/include/../csg/identify.hpp \ + libsrc/include/../csg/singularref.hpp libsrc/include/../csg/csgeom.hpp \ + libsrc/include/../csg/triapprox.hpp libsrc/include/../csg/algprim.hpp \ + libsrc/include/../csg/brick.hpp libsrc/include/../csg/spline3d.hpp \ + libsrc/include/../csg/manifold.hpp libsrc/include/../csg/curve2d.hpp \ + libsrc/include/../csg/explicitcurve2d.hpp \ + libsrc/include/../csg/gencyl.hpp libsrc/include/../csg/polyhedra.hpp \ + libsrc/include/../csg/extrusion.hpp \ + libsrc/include/../csg/revolution.hpp libsrc/include/../csg/specpoin.hpp \ + libsrc/include/../csg/edgeflw.hpp libsrc/include/../csg/meshsurf.hpp +# 1 "/Users/geuzaine/.gmsh/Netgen//" +bspline2d.o: libsrc/csg/bspline2d.cpp libsrc/include/mystdlib.h \ + libsrc/include/csg.hpp libsrc/include/../csg/csg.hpp \ + libsrc/include/myadt.hpp libsrc/include/../general/myadt.hpp \ + libsrc/include/mydefs.hpp libsrc/include/../general/ngexception.hpp \ + libsrc/include/../general/parthreads.hpp \ + libsrc/include/../general/moveablemem.hpp \ + libsrc/include/../general/dynamicmem.hpp \ + libsrc/include/../general/template.hpp \ + libsrc/include/../general/array.hpp libsrc/include/../general/table.hpp \ + libsrc/include/../general/hashtabl.hpp \ + libsrc/include/../general/symbolta.hpp \ + libsrc/include/../general/bitarray.hpp \ + libsrc/include/../general/flags.hpp \ + libsrc/include/../general/spbita2d.hpp \ + libsrc/include/../general/seti.hpp libsrc/include/../general/optmem.hpp \ + libsrc/include/../general/autoptr.hpp \ + libsrc/include/../general/sort.hpp libsrc/include/../general/stack.hpp \ + libsrc/include/../general/mystring.hpp libsrc/include/gprim.hpp \ + libsrc/include/../gprim/gprim.hpp \ + libsrc/include/../gprim/geomobjects.hpp \ + libsrc/include/../gprim/geomops.hpp \ + libsrc/include/../gprim/geomfuncs.hpp \ + libsrc/include/../gprim/geom2d.hpp libsrc/include/../gprim/geom3d.hpp \ + libsrc/include/../gprim/geomtest3d.hpp \ + libsrc/include/../gprim/transform3d.hpp \ + libsrc/include/../gprim/adtree.hpp libsrc/include/meshing.hpp \ + libsrc/include/../meshing/meshing.hpp libsrc/include/../gprim/gprim.hpp \ + libsrc/include/linalg.hpp libsrc/include/../linalg/linalg.hpp \ + libsrc/include/../linalg/vector.hpp \ + libsrc/include/../linalg/densemat.hpp \ + libsrc/include/../linalg/polynomial.hpp libsrc/include/opti.hpp \ + libsrc/include/../opti/opti.hpp \ + libsrc/include/../meshing/msghandler.hpp \ + libsrc/include/../meshing/meshtype.hpp \ + libsrc/include/../meshing/localh.hpp \ + libsrc/include/../meshing/meshclass.hpp \ + libsrc/include/../meshing/global.hpp \ + libsrc/include/../meshing/meshtool.hpp \ + libsrc/include/../meshing/ruler2.hpp \ + libsrc/include/../meshing/adfront2.hpp \ + libsrc/include/../meshing/meshing2.hpp \ + libsrc/include/../meshing/improve2.hpp \ + libsrc/include/../meshing/geomsearch.hpp \ + libsrc/include/../meshing/adfront3.hpp \ + libsrc/include/../meshing/ruler3.hpp \ + libsrc/include/../meshing/meshing3.hpp \ + libsrc/include/../meshing/improve3.hpp \ + libsrc/include/../meshing/findip.hpp \ + libsrc/include/../meshing/topology.hpp \ + libsrc/include/../meshing/curvedelems.hpp \ + libsrc/include/../meshing/bisect.hpp \ + libsrc/include/../meshing/clusters.hpp \ + libsrc/include/../meshing/meshfunc.hpp \ + libsrc/include/../meshing/hprefinement.hpp \ + libsrc/include/../meshing/boundarylayer.hpp \ + libsrc/include/../meshing/specials.hpp \ + libsrc/include/../csg/surface.hpp libsrc/include/../csg/solid.hpp \ + libsrc/include/../csg/identify.hpp \ + libsrc/include/../csg/singularref.hpp libsrc/include/../csg/csgeom.hpp \ + libsrc/include/../csg/triapprox.hpp libsrc/include/../csg/algprim.hpp \ + libsrc/include/../csg/brick.hpp libsrc/include/../csg/spline3d.hpp \ + libsrc/include/../csg/manifold.hpp libsrc/include/../csg/curve2d.hpp \ + libsrc/include/../csg/explicitcurve2d.hpp \ + libsrc/include/../csg/gencyl.hpp libsrc/include/../csg/polyhedra.hpp \ + libsrc/include/../csg/extrusion.hpp \ + libsrc/include/../csg/revolution.hpp libsrc/include/../csg/specpoin.hpp \ + libsrc/include/../csg/edgeflw.hpp libsrc/include/../csg/meshsurf.hpp +# 1 "/Users/geuzaine/.gmsh/Netgen//" +meshsurf.o: libsrc/csg/meshsurf.cpp libsrc/include/mystdlib.h \ + libsrc/include/csg.hpp libsrc/include/../csg/csg.hpp \ + libsrc/include/myadt.hpp libsrc/include/../general/myadt.hpp \ + libsrc/include/mydefs.hpp libsrc/include/../general/ngexception.hpp \ + libsrc/include/../general/parthreads.hpp \ + libsrc/include/../general/moveablemem.hpp \ + libsrc/include/../general/dynamicmem.hpp \ + libsrc/include/../general/template.hpp \ + libsrc/include/../general/array.hpp libsrc/include/../general/table.hpp \ + libsrc/include/../general/hashtabl.hpp \ + libsrc/include/../general/symbolta.hpp \ + libsrc/include/../general/bitarray.hpp \ + libsrc/include/../general/flags.hpp \ + libsrc/include/../general/spbita2d.hpp \ + libsrc/include/../general/seti.hpp libsrc/include/../general/optmem.hpp \ + libsrc/include/../general/autoptr.hpp \ + libsrc/include/../general/sort.hpp libsrc/include/../general/stack.hpp \ + libsrc/include/../general/mystring.hpp libsrc/include/gprim.hpp \ + libsrc/include/../gprim/gprim.hpp \ + libsrc/include/../gprim/geomobjects.hpp \ + libsrc/include/../gprim/geomops.hpp \ + libsrc/include/../gprim/geomfuncs.hpp \ + libsrc/include/../gprim/geom2d.hpp libsrc/include/../gprim/geom3d.hpp \ + libsrc/include/../gprim/geomtest3d.hpp \ + libsrc/include/../gprim/transform3d.hpp \ + libsrc/include/../gprim/adtree.hpp libsrc/include/meshing.hpp \ + libsrc/include/../meshing/meshing.hpp libsrc/include/../gprim/gprim.hpp \ + libsrc/include/linalg.hpp libsrc/include/../linalg/linalg.hpp \ + libsrc/include/../linalg/vector.hpp \ + libsrc/include/../linalg/densemat.hpp \ + libsrc/include/../linalg/polynomial.hpp libsrc/include/opti.hpp \ + libsrc/include/../opti/opti.hpp \ + libsrc/include/../meshing/msghandler.hpp \ + libsrc/include/../meshing/meshtype.hpp \ + libsrc/include/../meshing/localh.hpp \ + libsrc/include/../meshing/meshclass.hpp \ + libsrc/include/../meshing/global.hpp \ + libsrc/include/../meshing/meshtool.hpp \ + libsrc/include/../meshing/ruler2.hpp \ + libsrc/include/../meshing/adfront2.hpp \ + libsrc/include/../meshing/meshing2.hpp \ + libsrc/include/../meshing/improve2.hpp \ + libsrc/include/../meshing/geomsearch.hpp \ + libsrc/include/../meshing/adfront3.hpp \ + libsrc/include/../meshing/ruler3.hpp \ + libsrc/include/../meshing/meshing3.hpp \ + libsrc/include/../meshing/improve3.hpp \ + libsrc/include/../meshing/findip.hpp \ + libsrc/include/../meshing/topology.hpp \ + libsrc/include/../meshing/curvedelems.hpp \ + libsrc/include/../meshing/bisect.hpp \ + libsrc/include/../meshing/clusters.hpp \ + libsrc/include/../meshing/meshfunc.hpp \ + libsrc/include/../meshing/hprefinement.hpp \ + libsrc/include/../meshing/boundarylayer.hpp \ + libsrc/include/../meshing/specials.hpp \ + libsrc/include/../csg/surface.hpp libsrc/include/../csg/solid.hpp \ + libsrc/include/../csg/identify.hpp \ + libsrc/include/../csg/singularref.hpp libsrc/include/../csg/csgeom.hpp \ + libsrc/include/../csg/triapprox.hpp libsrc/include/../csg/algprim.hpp \ + libsrc/include/../csg/brick.hpp libsrc/include/../csg/spline3d.hpp \ + libsrc/include/../csg/manifold.hpp libsrc/include/../csg/curve2d.hpp \ + libsrc/include/../csg/explicitcurve2d.hpp \ + libsrc/include/../csg/gencyl.hpp libsrc/include/../csg/polyhedra.hpp \ + libsrc/include/../csg/extrusion.hpp \ + libsrc/include/../csg/revolution.hpp libsrc/include/../csg/specpoin.hpp \ + libsrc/include/../csg/edgeflw.hpp libsrc/include/../csg/meshsurf.hpp +# 1 "/Users/geuzaine/.gmsh/Netgen//" +csgeom.o: libsrc/csg/csgeom.cpp libsrc/include/mystdlib.h \ + libsrc/include/myadt.hpp libsrc/include/../general/myadt.hpp \ + libsrc/include/mydefs.hpp libsrc/include/../general/ngexception.hpp \ + libsrc/include/../general/parthreads.hpp \ + libsrc/include/../general/moveablemem.hpp \ + libsrc/include/../general/dynamicmem.hpp \ + libsrc/include/../general/template.hpp \ + libsrc/include/../general/array.hpp libsrc/include/../general/table.hpp \ + libsrc/include/../general/hashtabl.hpp \ + libsrc/include/../general/symbolta.hpp \ + libsrc/include/../general/bitarray.hpp \ + libsrc/include/../general/flags.hpp \ + libsrc/include/../general/spbita2d.hpp \ + libsrc/include/../general/seti.hpp libsrc/include/../general/optmem.hpp \ + libsrc/include/../general/autoptr.hpp \ + libsrc/include/../general/sort.hpp libsrc/include/../general/stack.hpp \ + libsrc/include/../general/mystring.hpp libsrc/include/linalg.hpp \ + libsrc/include/../linalg/linalg.hpp libsrc/include/../linalg/vector.hpp \ + libsrc/include/../linalg/densemat.hpp \ + libsrc/include/../linalg/polynomial.hpp libsrc/include/csg.hpp \ + libsrc/include/../csg/csg.hpp libsrc/include/gprim.hpp \ + libsrc/include/../gprim/gprim.hpp \ + libsrc/include/../gprim/geomobjects.hpp \ + libsrc/include/../gprim/geomops.hpp \ + libsrc/include/../gprim/geomfuncs.hpp \ + libsrc/include/../gprim/geom2d.hpp libsrc/include/../gprim/geom3d.hpp \ + libsrc/include/../gprim/geomtest3d.hpp \ + libsrc/include/../gprim/transform3d.hpp \ + libsrc/include/../gprim/adtree.hpp libsrc/include/meshing.hpp \ + libsrc/include/../meshing/meshing.hpp libsrc/include/../gprim/gprim.hpp \ + libsrc/include/../linalg/linalg.hpp libsrc/include/opti.hpp \ + libsrc/include/../opti/opti.hpp \ + libsrc/include/../meshing/msghandler.hpp \ + libsrc/include/../meshing/meshtype.hpp \ + libsrc/include/../meshing/localh.hpp \ + libsrc/include/../meshing/meshclass.hpp \ + libsrc/include/../meshing/global.hpp \ + libsrc/include/../meshing/meshtool.hpp \ + libsrc/include/../meshing/ruler2.hpp \ + libsrc/include/../meshing/adfront2.hpp \ + libsrc/include/../meshing/meshing2.hpp \ + libsrc/include/../meshing/improve2.hpp \ + libsrc/include/../meshing/geomsearch.hpp \ + libsrc/include/../meshing/adfront3.hpp \ + libsrc/include/../meshing/ruler3.hpp \ + libsrc/include/../meshing/meshing3.hpp \ + libsrc/include/../meshing/improve3.hpp \ + libsrc/include/../meshing/findip.hpp \ + libsrc/include/../meshing/topology.hpp \ + libsrc/include/../meshing/curvedelems.hpp \ + libsrc/include/../meshing/bisect.hpp \ + libsrc/include/../meshing/clusters.hpp \ + libsrc/include/../meshing/meshfunc.hpp \ + libsrc/include/../meshing/hprefinement.hpp \ + libsrc/include/../meshing/boundarylayer.hpp \ + libsrc/include/../meshing/specials.hpp \ + libsrc/include/../csg/surface.hpp libsrc/include/../csg/solid.hpp \ + libsrc/include/../csg/identify.hpp \ + libsrc/include/../csg/singularref.hpp libsrc/include/../csg/csgeom.hpp \ + libsrc/include/../csg/triapprox.hpp libsrc/include/../csg/algprim.hpp \ + libsrc/include/../csg/brick.hpp libsrc/include/../csg/spline3d.hpp \ + libsrc/include/../csg/manifold.hpp libsrc/include/../csg/curve2d.hpp \ + libsrc/include/../csg/explicitcurve2d.hpp \ + libsrc/include/../csg/gencyl.hpp libsrc/include/../csg/polyhedra.hpp \ + libsrc/include/../csg/extrusion.hpp \ + libsrc/include/../csg/revolution.hpp libsrc/include/../csg/specpoin.hpp \ + libsrc/include/../csg/edgeflw.hpp libsrc/include/../csg/meshsurf.hpp +# 1 "/Users/geuzaine/.gmsh/Netgen//" +polyhedra.o: libsrc/csg/polyhedra.cpp libsrc/include/mystdlib.h \ + libsrc/include/linalg.hpp libsrc/include/../linalg/linalg.hpp \ + libsrc/include/myadt.hpp libsrc/include/../general/myadt.hpp \ + libsrc/include/mydefs.hpp libsrc/include/../general/ngexception.hpp \ + libsrc/include/../general/parthreads.hpp \ + libsrc/include/../general/moveablemem.hpp \ + libsrc/include/../general/dynamicmem.hpp \ + libsrc/include/../general/template.hpp \ + libsrc/include/../general/array.hpp libsrc/include/../general/table.hpp \ + libsrc/include/../general/hashtabl.hpp \ + libsrc/include/../general/symbolta.hpp \ + libsrc/include/../general/bitarray.hpp \ + libsrc/include/../general/flags.hpp \ + libsrc/include/../general/spbita2d.hpp \ + libsrc/include/../general/seti.hpp libsrc/include/../general/optmem.hpp \ + libsrc/include/../general/autoptr.hpp \ + libsrc/include/../general/sort.hpp libsrc/include/../general/stack.hpp \ + libsrc/include/../general/mystring.hpp \ + libsrc/include/../linalg/vector.hpp \ + libsrc/include/../linalg/densemat.hpp \ + libsrc/include/../linalg/polynomial.hpp libsrc/include/csg.hpp \ + libsrc/include/../csg/csg.hpp libsrc/include/gprim.hpp \ + libsrc/include/../gprim/gprim.hpp \ + libsrc/include/../gprim/geomobjects.hpp \ + libsrc/include/../gprim/geomops.hpp \ + libsrc/include/../gprim/geomfuncs.hpp \ + libsrc/include/../gprim/geom2d.hpp libsrc/include/../gprim/geom3d.hpp \ + libsrc/include/../gprim/geomtest3d.hpp \ + libsrc/include/../gprim/transform3d.hpp \ + libsrc/include/../gprim/adtree.hpp libsrc/include/meshing.hpp \ + libsrc/include/../meshing/meshing.hpp libsrc/include/../gprim/gprim.hpp \ + libsrc/include/../linalg/linalg.hpp libsrc/include/opti.hpp \ + libsrc/include/../opti/opti.hpp \ + libsrc/include/../meshing/msghandler.hpp \ + libsrc/include/../meshing/meshtype.hpp \ + libsrc/include/../meshing/localh.hpp \ + libsrc/include/../meshing/meshclass.hpp \ + libsrc/include/../meshing/global.hpp \ + libsrc/include/../meshing/meshtool.hpp \ + libsrc/include/../meshing/ruler2.hpp \ + libsrc/include/../meshing/adfront2.hpp \ + libsrc/include/../meshing/meshing2.hpp \ + libsrc/include/../meshing/improve2.hpp \ + libsrc/include/../meshing/geomsearch.hpp \ + libsrc/include/../meshing/adfront3.hpp \ + libsrc/include/../meshing/ruler3.hpp \ + libsrc/include/../meshing/meshing3.hpp \ + libsrc/include/../meshing/improve3.hpp \ + libsrc/include/../meshing/findip.hpp \ + libsrc/include/../meshing/topology.hpp \ + libsrc/include/../meshing/curvedelems.hpp \ + libsrc/include/../meshing/bisect.hpp \ + libsrc/include/../meshing/clusters.hpp \ + libsrc/include/../meshing/meshfunc.hpp \ + libsrc/include/../meshing/hprefinement.hpp \ + libsrc/include/../meshing/boundarylayer.hpp \ + libsrc/include/../meshing/specials.hpp \ + libsrc/include/../csg/surface.hpp libsrc/include/../csg/solid.hpp \ + libsrc/include/../csg/identify.hpp \ + libsrc/include/../csg/singularref.hpp libsrc/include/../csg/csgeom.hpp \ + libsrc/include/../csg/triapprox.hpp libsrc/include/../csg/algprim.hpp \ + libsrc/include/../csg/brick.hpp libsrc/include/../csg/spline3d.hpp \ + libsrc/include/../csg/manifold.hpp libsrc/include/../csg/curve2d.hpp \ + libsrc/include/../csg/explicitcurve2d.hpp \ + libsrc/include/../csg/gencyl.hpp libsrc/include/../csg/polyhedra.hpp \ + libsrc/include/../csg/extrusion.hpp \ + libsrc/include/../csg/revolution.hpp libsrc/include/../csg/specpoin.hpp \ + libsrc/include/../csg/edgeflw.hpp libsrc/include/../csg/meshsurf.hpp +# 1 "/Users/geuzaine/.gmsh/Netgen//" +curve2d.o: libsrc/csg/curve2d.cpp libsrc/include/mystdlib.h \ + libsrc/include/myadt.hpp libsrc/include/../general/myadt.hpp \ + libsrc/include/mydefs.hpp libsrc/include/../general/ngexception.hpp \ + libsrc/include/../general/parthreads.hpp \ + libsrc/include/../general/moveablemem.hpp \ + libsrc/include/../general/dynamicmem.hpp \ + libsrc/include/../general/template.hpp \ + libsrc/include/../general/array.hpp libsrc/include/../general/table.hpp \ + libsrc/include/../general/hashtabl.hpp \ + libsrc/include/../general/symbolta.hpp \ + libsrc/include/../general/bitarray.hpp \ + libsrc/include/../general/flags.hpp \ + libsrc/include/../general/spbita2d.hpp \ + libsrc/include/../general/seti.hpp libsrc/include/../general/optmem.hpp \ + libsrc/include/../general/autoptr.hpp \ + libsrc/include/../general/sort.hpp libsrc/include/../general/stack.hpp \ + libsrc/include/../general/mystring.hpp libsrc/include/csg.hpp \ + libsrc/include/../csg/csg.hpp libsrc/include/gprim.hpp \ + libsrc/include/../gprim/gprim.hpp \ + libsrc/include/../gprim/geomobjects.hpp \ + libsrc/include/../gprim/geomops.hpp \ + libsrc/include/../gprim/geomfuncs.hpp \ + libsrc/include/../gprim/geom2d.hpp libsrc/include/../gprim/geom3d.hpp \ + libsrc/include/../gprim/geomtest3d.hpp \ + libsrc/include/../gprim/transform3d.hpp \ + libsrc/include/../gprim/adtree.hpp libsrc/include/meshing.hpp \ + libsrc/include/../meshing/meshing.hpp libsrc/include/../gprim/gprim.hpp \ + libsrc/include/linalg.hpp libsrc/include/../linalg/linalg.hpp \ + libsrc/include/../linalg/vector.hpp \ + libsrc/include/../linalg/densemat.hpp \ + libsrc/include/../linalg/polynomial.hpp libsrc/include/opti.hpp \ + libsrc/include/../opti/opti.hpp \ + libsrc/include/../meshing/msghandler.hpp \ + libsrc/include/../meshing/meshtype.hpp \ + libsrc/include/../meshing/localh.hpp \ + libsrc/include/../meshing/meshclass.hpp \ + libsrc/include/../meshing/global.hpp \ + libsrc/include/../meshing/meshtool.hpp \ + libsrc/include/../meshing/ruler2.hpp \ + libsrc/include/../meshing/adfront2.hpp \ + libsrc/include/../meshing/meshing2.hpp \ + libsrc/include/../meshing/improve2.hpp \ + libsrc/include/../meshing/geomsearch.hpp \ + libsrc/include/../meshing/adfront3.hpp \ + libsrc/include/../meshing/ruler3.hpp \ + libsrc/include/../meshing/meshing3.hpp \ + libsrc/include/../meshing/improve3.hpp \ + libsrc/include/../meshing/findip.hpp \ + libsrc/include/../meshing/topology.hpp \ + libsrc/include/../meshing/curvedelems.hpp \ + libsrc/include/../meshing/bisect.hpp \ + libsrc/include/../meshing/clusters.hpp \ + libsrc/include/../meshing/meshfunc.hpp \ + libsrc/include/../meshing/hprefinement.hpp \ + libsrc/include/../meshing/boundarylayer.hpp \ + libsrc/include/../meshing/specials.hpp \ + libsrc/include/../csg/surface.hpp libsrc/include/../csg/solid.hpp \ + libsrc/include/../csg/identify.hpp \ + libsrc/include/../csg/singularref.hpp libsrc/include/../csg/csgeom.hpp \ + libsrc/include/../csg/triapprox.hpp libsrc/include/../csg/algprim.hpp \ + libsrc/include/../csg/brick.hpp libsrc/include/../csg/spline3d.hpp \ + libsrc/include/../csg/manifold.hpp libsrc/include/../csg/curve2d.hpp \ + libsrc/include/../csg/explicitcurve2d.hpp \ + libsrc/include/../csg/gencyl.hpp libsrc/include/../csg/polyhedra.hpp \ + libsrc/include/../csg/extrusion.hpp \ + libsrc/include/../csg/revolution.hpp libsrc/include/../csg/specpoin.hpp \ + libsrc/include/../csg/edgeflw.hpp libsrc/include/../csg/meshsurf.hpp +# 1 "/Users/geuzaine/.gmsh/Netgen//" +singularref.o: libsrc/csg/singularref.cpp libsrc/include/mystdlib.h \ + libsrc/include/myadt.hpp libsrc/include/../general/myadt.hpp \ + libsrc/include/mydefs.hpp libsrc/include/../general/ngexception.hpp \ + libsrc/include/../general/parthreads.hpp \ + libsrc/include/../general/moveablemem.hpp \ + libsrc/include/../general/dynamicmem.hpp \ + libsrc/include/../general/template.hpp \ + libsrc/include/../general/array.hpp libsrc/include/../general/table.hpp \ + libsrc/include/../general/hashtabl.hpp \ + libsrc/include/../general/symbolta.hpp \ + libsrc/include/../general/bitarray.hpp \ + libsrc/include/../general/flags.hpp \ + libsrc/include/../general/spbita2d.hpp \ + libsrc/include/../general/seti.hpp libsrc/include/../general/optmem.hpp \ + libsrc/include/../general/autoptr.hpp \ + libsrc/include/../general/sort.hpp libsrc/include/../general/stack.hpp \ + libsrc/include/../general/mystring.hpp libsrc/include/linalg.hpp \ + libsrc/include/../linalg/linalg.hpp libsrc/include/../linalg/vector.hpp \ + libsrc/include/../linalg/densemat.hpp \ + libsrc/include/../linalg/polynomial.hpp libsrc/include/csg.hpp \ + libsrc/include/../csg/csg.hpp libsrc/include/gprim.hpp \ + libsrc/include/../gprim/gprim.hpp \ + libsrc/include/../gprim/geomobjects.hpp \ + libsrc/include/../gprim/geomops.hpp \ + libsrc/include/../gprim/geomfuncs.hpp \ + libsrc/include/../gprim/geom2d.hpp libsrc/include/../gprim/geom3d.hpp \ + libsrc/include/../gprim/geomtest3d.hpp \ + libsrc/include/../gprim/transform3d.hpp \ + libsrc/include/../gprim/adtree.hpp libsrc/include/meshing.hpp \ + libsrc/include/../meshing/meshing.hpp libsrc/include/../gprim/gprim.hpp \ + libsrc/include/../linalg/linalg.hpp libsrc/include/opti.hpp \ + libsrc/include/../opti/opti.hpp \ + libsrc/include/../meshing/msghandler.hpp \ + libsrc/include/../meshing/meshtype.hpp \ + libsrc/include/../meshing/localh.hpp \ + libsrc/include/../meshing/meshclass.hpp \ + libsrc/include/../meshing/global.hpp \ + libsrc/include/../meshing/meshtool.hpp \ + libsrc/include/../meshing/ruler2.hpp \ + libsrc/include/../meshing/adfront2.hpp \ + libsrc/include/../meshing/meshing2.hpp \ + libsrc/include/../meshing/improve2.hpp \ + libsrc/include/../meshing/geomsearch.hpp \ + libsrc/include/../meshing/adfront3.hpp \ + libsrc/include/../meshing/ruler3.hpp \ + libsrc/include/../meshing/meshing3.hpp \ + libsrc/include/../meshing/improve3.hpp \ + libsrc/include/../meshing/findip.hpp \ + libsrc/include/../meshing/topology.hpp \ + libsrc/include/../meshing/curvedelems.hpp \ + libsrc/include/../meshing/bisect.hpp \ + libsrc/include/../meshing/clusters.hpp \ + libsrc/include/../meshing/meshfunc.hpp \ + libsrc/include/../meshing/hprefinement.hpp \ + libsrc/include/../meshing/boundarylayer.hpp \ + libsrc/include/../meshing/specials.hpp \ + libsrc/include/../csg/surface.hpp libsrc/include/../csg/solid.hpp \ + libsrc/include/../csg/identify.hpp \ + libsrc/include/../csg/singularref.hpp libsrc/include/../csg/csgeom.hpp \ + libsrc/include/../csg/triapprox.hpp libsrc/include/../csg/algprim.hpp \ + libsrc/include/../csg/brick.hpp libsrc/include/../csg/spline3d.hpp \ + libsrc/include/../csg/manifold.hpp libsrc/include/../csg/curve2d.hpp \ + libsrc/include/../csg/explicitcurve2d.hpp \ + libsrc/include/../csg/gencyl.hpp libsrc/include/../csg/polyhedra.hpp \ + libsrc/include/../csg/extrusion.hpp \ + libsrc/include/../csg/revolution.hpp libsrc/include/../csg/specpoin.hpp \ + libsrc/include/../csg/edgeflw.hpp libsrc/include/../csg/meshsurf.hpp +# 1 "/Users/geuzaine/.gmsh/Netgen//" +edgeflw.o: libsrc/csg/edgeflw.cpp libsrc/include/mystdlib.h \ + libsrc/include/meshing.hpp libsrc/include/../meshing/meshing.hpp \ + libsrc/include/myadt.hpp libsrc/include/../general/myadt.hpp \ + libsrc/include/mydefs.hpp libsrc/include/../general/ngexception.hpp \ + libsrc/include/../general/parthreads.hpp \ + libsrc/include/../general/moveablemem.hpp \ + libsrc/include/../general/dynamicmem.hpp \ + libsrc/include/../general/template.hpp \ + libsrc/include/../general/array.hpp libsrc/include/../general/table.hpp \ + libsrc/include/../general/hashtabl.hpp \ + libsrc/include/../general/symbolta.hpp \ + libsrc/include/../general/bitarray.hpp \ + libsrc/include/../general/flags.hpp \ + libsrc/include/../general/spbita2d.hpp \ + libsrc/include/../general/seti.hpp libsrc/include/../general/optmem.hpp \ + libsrc/include/../general/autoptr.hpp \ + libsrc/include/../general/sort.hpp libsrc/include/../general/stack.hpp \ + libsrc/include/../general/mystring.hpp libsrc/include/gprim.hpp \ + libsrc/include/../gprim/gprim.hpp \ + libsrc/include/../gprim/geomobjects.hpp \ + libsrc/include/../gprim/geomops.hpp \ + libsrc/include/../gprim/geomfuncs.hpp \ + libsrc/include/../gprim/geom2d.hpp libsrc/include/../gprim/geom3d.hpp \ + libsrc/include/../gprim/geomtest3d.hpp \ + libsrc/include/../gprim/transform3d.hpp \ + libsrc/include/../gprim/adtree.hpp libsrc/include/linalg.hpp \ + libsrc/include/../linalg/linalg.hpp libsrc/include/../linalg/vector.hpp \ + libsrc/include/../linalg/densemat.hpp \ + libsrc/include/../linalg/polynomial.hpp libsrc/include/opti.hpp \ + libsrc/include/../opti/opti.hpp \ + libsrc/include/../meshing/msghandler.hpp \ + libsrc/include/../meshing/meshtype.hpp \ + libsrc/include/../meshing/localh.hpp \ + libsrc/include/../meshing/meshclass.hpp \ + libsrc/include/../meshing/global.hpp \ + libsrc/include/../meshing/meshtool.hpp \ + libsrc/include/../meshing/ruler2.hpp \ + libsrc/include/../meshing/adfront2.hpp \ + libsrc/include/../meshing/meshing2.hpp \ + libsrc/include/../meshing/improve2.hpp \ + libsrc/include/../meshing/geomsearch.hpp \ + libsrc/include/../meshing/adfront3.hpp \ + libsrc/include/../meshing/ruler3.hpp \ + libsrc/include/../meshing/meshing3.hpp \ + libsrc/include/../meshing/improve3.hpp \ + libsrc/include/../meshing/findip.hpp \ + libsrc/include/../meshing/topology.hpp \ + libsrc/include/../meshing/curvedelems.hpp \ + libsrc/include/../meshing/bisect.hpp \ + libsrc/include/../meshing/clusters.hpp \ + libsrc/include/../meshing/meshfunc.hpp \ + libsrc/include/../meshing/hprefinement.hpp \ + libsrc/include/../meshing/boundarylayer.hpp \ + libsrc/include/../meshing/specials.hpp libsrc/include/csg.hpp \ + libsrc/include/../csg/csg.hpp libsrc/include/../gprim/gprim.hpp \ + libsrc/include/../csg/surface.hpp libsrc/include/../csg/solid.hpp \ + libsrc/include/../csg/identify.hpp \ + libsrc/include/../csg/singularref.hpp libsrc/include/../csg/csgeom.hpp \ + libsrc/include/../csg/triapprox.hpp libsrc/include/../csg/algprim.hpp \ + libsrc/include/../csg/brick.hpp libsrc/include/../csg/spline3d.hpp \ + libsrc/include/../csg/manifold.hpp libsrc/include/../csg/curve2d.hpp \ + libsrc/include/../csg/explicitcurve2d.hpp \ + libsrc/include/../csg/gencyl.hpp libsrc/include/../csg/polyhedra.hpp \ + libsrc/include/../csg/extrusion.hpp \ + libsrc/include/../csg/revolution.hpp libsrc/include/../csg/specpoin.hpp \ + libsrc/include/../csg/edgeflw.hpp libsrc/include/../csg/meshsurf.hpp +# 1 "/Users/geuzaine/.gmsh/Netgen//" +solid.o: libsrc/csg/solid.cpp libsrc/include/mystdlib.h \ + libsrc/include/linalg.hpp libsrc/include/../linalg/linalg.hpp \ + libsrc/include/myadt.hpp libsrc/include/../general/myadt.hpp \ + libsrc/include/mydefs.hpp libsrc/include/../general/ngexception.hpp \ + libsrc/include/../general/parthreads.hpp \ + libsrc/include/../general/moveablemem.hpp \ + libsrc/include/../general/dynamicmem.hpp \ + libsrc/include/../general/template.hpp \ + libsrc/include/../general/array.hpp libsrc/include/../general/table.hpp \ + libsrc/include/../general/hashtabl.hpp \ + libsrc/include/../general/symbolta.hpp \ + libsrc/include/../general/bitarray.hpp \ + libsrc/include/../general/flags.hpp \ + libsrc/include/../general/spbita2d.hpp \ + libsrc/include/../general/seti.hpp libsrc/include/../general/optmem.hpp \ + libsrc/include/../general/autoptr.hpp \ + libsrc/include/../general/sort.hpp libsrc/include/../general/stack.hpp \ + libsrc/include/../general/mystring.hpp \ + libsrc/include/../linalg/vector.hpp \ + libsrc/include/../linalg/densemat.hpp \ + libsrc/include/../linalg/polynomial.hpp libsrc/include/csg.hpp \ + libsrc/include/../csg/csg.hpp libsrc/include/gprim.hpp \ + libsrc/include/../gprim/gprim.hpp \ + libsrc/include/../gprim/geomobjects.hpp \ + libsrc/include/../gprim/geomops.hpp \ + libsrc/include/../gprim/geomfuncs.hpp \ + libsrc/include/../gprim/geom2d.hpp libsrc/include/../gprim/geom3d.hpp \ + libsrc/include/../gprim/geomtest3d.hpp \ + libsrc/include/../gprim/transform3d.hpp \ + libsrc/include/../gprim/adtree.hpp libsrc/include/meshing.hpp \ + libsrc/include/../meshing/meshing.hpp libsrc/include/../gprim/gprim.hpp \ + libsrc/include/../linalg/linalg.hpp libsrc/include/opti.hpp \ + libsrc/include/../opti/opti.hpp \ + libsrc/include/../meshing/msghandler.hpp \ + libsrc/include/../meshing/meshtype.hpp \ + libsrc/include/../meshing/localh.hpp \ + libsrc/include/../meshing/meshclass.hpp \ + libsrc/include/../meshing/global.hpp \ + libsrc/include/../meshing/meshtool.hpp \ + libsrc/include/../meshing/ruler2.hpp \ + libsrc/include/../meshing/adfront2.hpp \ + libsrc/include/../meshing/meshing2.hpp \ + libsrc/include/../meshing/improve2.hpp \ + libsrc/include/../meshing/geomsearch.hpp \ + libsrc/include/../meshing/adfront3.hpp \ + libsrc/include/../meshing/ruler3.hpp \ + libsrc/include/../meshing/meshing3.hpp \ + libsrc/include/../meshing/improve3.hpp \ + libsrc/include/../meshing/findip.hpp \ + libsrc/include/../meshing/topology.hpp \ + libsrc/include/../meshing/curvedelems.hpp \ + libsrc/include/../meshing/bisect.hpp \ + libsrc/include/../meshing/clusters.hpp \ + libsrc/include/../meshing/meshfunc.hpp \ + libsrc/include/../meshing/hprefinement.hpp \ + libsrc/include/../meshing/boundarylayer.hpp \ + libsrc/include/../meshing/specials.hpp \ + libsrc/include/../csg/surface.hpp libsrc/include/../csg/solid.hpp \ + libsrc/include/../csg/identify.hpp \ + libsrc/include/../csg/singularref.hpp libsrc/include/../csg/csgeom.hpp \ + libsrc/include/../csg/triapprox.hpp libsrc/include/../csg/algprim.hpp \ + libsrc/include/../csg/brick.hpp libsrc/include/../csg/spline3d.hpp \ + libsrc/include/../csg/manifold.hpp libsrc/include/../csg/curve2d.hpp \ + libsrc/include/../csg/explicitcurve2d.hpp \ + libsrc/include/../csg/gencyl.hpp libsrc/include/../csg/polyhedra.hpp \ + libsrc/include/../csg/extrusion.hpp \ + libsrc/include/../csg/revolution.hpp libsrc/include/../csg/specpoin.hpp \ + libsrc/include/../csg/edgeflw.hpp libsrc/include/../csg/meshsurf.hpp +# 1 "/Users/geuzaine/.gmsh/Netgen//" +explicitcurve2d.o: libsrc/csg/explicitcurve2d.cpp \ + libsrc/include/mystdlib.h libsrc/include/csg.hpp \ + libsrc/include/../csg/csg.hpp libsrc/include/myadt.hpp \ + libsrc/include/../general/myadt.hpp libsrc/include/mydefs.hpp \ + libsrc/include/../general/ngexception.hpp \ + libsrc/include/../general/parthreads.hpp \ + libsrc/include/../general/moveablemem.hpp \ + libsrc/include/../general/dynamicmem.hpp \ + libsrc/include/../general/template.hpp \ + libsrc/include/../general/array.hpp libsrc/include/../general/table.hpp \ + libsrc/include/../general/hashtabl.hpp \ + libsrc/include/../general/symbolta.hpp \ + libsrc/include/../general/bitarray.hpp \ + libsrc/include/../general/flags.hpp \ + libsrc/include/../general/spbita2d.hpp \ + libsrc/include/../general/seti.hpp libsrc/include/../general/optmem.hpp \ + libsrc/include/../general/autoptr.hpp \ + libsrc/include/../general/sort.hpp libsrc/include/../general/stack.hpp \ + libsrc/include/../general/mystring.hpp libsrc/include/gprim.hpp \ + libsrc/include/../gprim/gprim.hpp \ + libsrc/include/../gprim/geomobjects.hpp \ + libsrc/include/../gprim/geomops.hpp \ + libsrc/include/../gprim/geomfuncs.hpp \ + libsrc/include/../gprim/geom2d.hpp libsrc/include/../gprim/geom3d.hpp \ + libsrc/include/../gprim/geomtest3d.hpp \ + libsrc/include/../gprim/transform3d.hpp \ + libsrc/include/../gprim/adtree.hpp libsrc/include/meshing.hpp \ + libsrc/include/../meshing/meshing.hpp libsrc/include/../gprim/gprim.hpp \ + libsrc/include/linalg.hpp libsrc/include/../linalg/linalg.hpp \ + libsrc/include/../linalg/vector.hpp \ + libsrc/include/../linalg/densemat.hpp \ + libsrc/include/../linalg/polynomial.hpp libsrc/include/opti.hpp \ + libsrc/include/../opti/opti.hpp \ + libsrc/include/../meshing/msghandler.hpp \ + libsrc/include/../meshing/meshtype.hpp \ + libsrc/include/../meshing/localh.hpp \ + libsrc/include/../meshing/meshclass.hpp \ + libsrc/include/../meshing/global.hpp \ + libsrc/include/../meshing/meshtool.hpp \ + libsrc/include/../meshing/ruler2.hpp \ + libsrc/include/../meshing/adfront2.hpp \ + libsrc/include/../meshing/meshing2.hpp \ + libsrc/include/../meshing/improve2.hpp \ + libsrc/include/../meshing/geomsearch.hpp \ + libsrc/include/../meshing/adfront3.hpp \ + libsrc/include/../meshing/ruler3.hpp \ + libsrc/include/../meshing/meshing3.hpp \ + libsrc/include/../meshing/improve3.hpp \ + libsrc/include/../meshing/findip.hpp \ + libsrc/include/../meshing/topology.hpp \ + libsrc/include/../meshing/curvedelems.hpp \ + libsrc/include/../meshing/bisect.hpp \ + libsrc/include/../meshing/clusters.hpp \ + libsrc/include/../meshing/meshfunc.hpp \ + libsrc/include/../meshing/hprefinement.hpp \ + libsrc/include/../meshing/boundarylayer.hpp \ + libsrc/include/../meshing/specials.hpp \ + libsrc/include/../csg/surface.hpp libsrc/include/../csg/solid.hpp \ + libsrc/include/../csg/identify.hpp \ + libsrc/include/../csg/singularref.hpp libsrc/include/../csg/csgeom.hpp \ + libsrc/include/../csg/triapprox.hpp libsrc/include/../csg/algprim.hpp \ + libsrc/include/../csg/brick.hpp libsrc/include/../csg/spline3d.hpp \ + libsrc/include/../csg/manifold.hpp libsrc/include/../csg/curve2d.hpp \ + libsrc/include/../csg/explicitcurve2d.hpp \ + libsrc/include/../csg/gencyl.hpp libsrc/include/../csg/polyhedra.hpp \ + libsrc/include/../csg/extrusion.hpp \ + libsrc/include/../csg/revolution.hpp libsrc/include/../csg/specpoin.hpp \ + libsrc/include/../csg/edgeflw.hpp libsrc/include/../csg/meshsurf.hpp +# 1 "/Users/geuzaine/.gmsh/Netgen//" +specpoin.o: libsrc/csg/specpoin.cpp libsrc/include/mystdlib.h \ + libsrc/include/meshing.hpp libsrc/include/../meshing/meshing.hpp \ + libsrc/include/myadt.hpp libsrc/include/../general/myadt.hpp \ + libsrc/include/mydefs.hpp libsrc/include/../general/ngexception.hpp \ + libsrc/include/../general/parthreads.hpp \ + libsrc/include/../general/moveablemem.hpp \ + libsrc/include/../general/dynamicmem.hpp \ + libsrc/include/../general/template.hpp \ + libsrc/include/../general/array.hpp libsrc/include/../general/table.hpp \ + libsrc/include/../general/hashtabl.hpp \ + libsrc/include/../general/symbolta.hpp \ + libsrc/include/../general/bitarray.hpp \ + libsrc/include/../general/flags.hpp \ + libsrc/include/../general/spbita2d.hpp \ + libsrc/include/../general/seti.hpp libsrc/include/../general/optmem.hpp \ + libsrc/include/../general/autoptr.hpp \ + libsrc/include/../general/sort.hpp libsrc/include/../general/stack.hpp \ + libsrc/include/../general/mystring.hpp libsrc/include/gprim.hpp \ + libsrc/include/../gprim/gprim.hpp \ + libsrc/include/../gprim/geomobjects.hpp \ + libsrc/include/../gprim/geomops.hpp \ + libsrc/include/../gprim/geomfuncs.hpp \ + libsrc/include/../gprim/geom2d.hpp libsrc/include/../gprim/geom3d.hpp \ + libsrc/include/../gprim/geomtest3d.hpp \ + libsrc/include/../gprim/transform3d.hpp \ + libsrc/include/../gprim/adtree.hpp libsrc/include/linalg.hpp \ + libsrc/include/../linalg/linalg.hpp libsrc/include/../linalg/vector.hpp \ + libsrc/include/../linalg/densemat.hpp \ + libsrc/include/../linalg/polynomial.hpp libsrc/include/opti.hpp \ + libsrc/include/../opti/opti.hpp \ + libsrc/include/../meshing/msghandler.hpp \ + libsrc/include/../meshing/meshtype.hpp \ + libsrc/include/../meshing/localh.hpp \ + libsrc/include/../meshing/meshclass.hpp \ + libsrc/include/../meshing/global.hpp \ + libsrc/include/../meshing/meshtool.hpp \ + libsrc/include/../meshing/ruler2.hpp \ + libsrc/include/../meshing/adfront2.hpp \ + libsrc/include/../meshing/meshing2.hpp \ + libsrc/include/../meshing/improve2.hpp \ + libsrc/include/../meshing/geomsearch.hpp \ + libsrc/include/../meshing/adfront3.hpp \ + libsrc/include/../meshing/ruler3.hpp \ + libsrc/include/../meshing/meshing3.hpp \ + libsrc/include/../meshing/improve3.hpp \ + libsrc/include/../meshing/findip.hpp \ + libsrc/include/../meshing/topology.hpp \ + libsrc/include/../meshing/curvedelems.hpp \ + libsrc/include/../meshing/bisect.hpp \ + libsrc/include/../meshing/clusters.hpp \ + libsrc/include/../meshing/meshfunc.hpp \ + libsrc/include/../meshing/hprefinement.hpp \ + libsrc/include/../meshing/boundarylayer.hpp \ + libsrc/include/../meshing/specials.hpp libsrc/include/csg.hpp \ + libsrc/include/../csg/csg.hpp libsrc/include/../gprim/gprim.hpp \ + libsrc/include/../csg/surface.hpp libsrc/include/../csg/solid.hpp \ + libsrc/include/../csg/identify.hpp \ + libsrc/include/../csg/singularref.hpp libsrc/include/../csg/csgeom.hpp \ + libsrc/include/../csg/triapprox.hpp libsrc/include/../csg/algprim.hpp \ + libsrc/include/../csg/brick.hpp libsrc/include/../csg/spline3d.hpp \ + libsrc/include/../csg/manifold.hpp libsrc/include/../csg/curve2d.hpp \ + libsrc/include/../csg/explicitcurve2d.hpp \ + libsrc/include/../csg/gencyl.hpp libsrc/include/../csg/polyhedra.hpp \ + libsrc/include/../csg/extrusion.hpp \ + libsrc/include/../csg/revolution.hpp libsrc/include/../csg/specpoin.hpp \ + libsrc/include/../csg/edgeflw.hpp libsrc/include/../csg/meshsurf.hpp +# 1 "/Users/geuzaine/.gmsh/Netgen//" +gencyl.o: libsrc/csg/gencyl.cpp libsrc/include/linalg.hpp \ + libsrc/include/../linalg/linalg.hpp libsrc/include/myadt.hpp \ + libsrc/include/../general/myadt.hpp libsrc/include/mystdlib.h \ + libsrc/include/mydefs.hpp libsrc/include/../general/ngexception.hpp \ + libsrc/include/../general/parthreads.hpp \ + libsrc/include/../general/moveablemem.hpp \ + libsrc/include/../general/dynamicmem.hpp \ + libsrc/include/../general/template.hpp \ + libsrc/include/../general/array.hpp libsrc/include/../general/table.hpp \ + libsrc/include/../general/hashtabl.hpp \ + libsrc/include/../general/symbolta.hpp \ + libsrc/include/../general/bitarray.hpp \ + libsrc/include/../general/flags.hpp \ + libsrc/include/../general/spbita2d.hpp \ + libsrc/include/../general/seti.hpp libsrc/include/../general/optmem.hpp \ + libsrc/include/../general/autoptr.hpp \ + libsrc/include/../general/sort.hpp libsrc/include/../general/stack.hpp \ + libsrc/include/../general/mystring.hpp \ + libsrc/include/../linalg/vector.hpp \ + libsrc/include/../linalg/densemat.hpp \ + libsrc/include/../linalg/polynomial.hpp libsrc/include/csg.hpp \ + libsrc/include/../csg/csg.hpp libsrc/include/gprim.hpp \ + libsrc/include/../gprim/gprim.hpp \ + libsrc/include/../gprim/geomobjects.hpp \ + libsrc/include/../gprim/geomops.hpp \ + libsrc/include/../gprim/geomfuncs.hpp \ + libsrc/include/../gprim/geom2d.hpp libsrc/include/../gprim/geom3d.hpp \ + libsrc/include/../gprim/geomtest3d.hpp \ + libsrc/include/../gprim/transform3d.hpp \ + libsrc/include/../gprim/adtree.hpp libsrc/include/meshing.hpp \ + libsrc/include/../meshing/meshing.hpp libsrc/include/../gprim/gprim.hpp \ + libsrc/include/../linalg/linalg.hpp libsrc/include/opti.hpp \ + libsrc/include/../opti/opti.hpp \ + libsrc/include/../meshing/msghandler.hpp \ + libsrc/include/../meshing/meshtype.hpp \ + libsrc/include/../meshing/localh.hpp \ + libsrc/include/../meshing/meshclass.hpp \ + libsrc/include/../meshing/global.hpp \ + libsrc/include/../meshing/meshtool.hpp \ + libsrc/include/../meshing/ruler2.hpp \ + libsrc/include/../meshing/adfront2.hpp \ + libsrc/include/../meshing/meshing2.hpp \ + libsrc/include/../meshing/improve2.hpp \ + libsrc/include/../meshing/geomsearch.hpp \ + libsrc/include/../meshing/adfront3.hpp \ + libsrc/include/../meshing/ruler3.hpp \ + libsrc/include/../meshing/meshing3.hpp \ + libsrc/include/../meshing/improve3.hpp \ + libsrc/include/../meshing/findip.hpp \ + libsrc/include/../meshing/topology.hpp \ + libsrc/include/../meshing/curvedelems.hpp \ + libsrc/include/../meshing/bisect.hpp \ + libsrc/include/../meshing/clusters.hpp \ + libsrc/include/../meshing/meshfunc.hpp \ + libsrc/include/../meshing/hprefinement.hpp \ + libsrc/include/../meshing/boundarylayer.hpp \ + libsrc/include/../meshing/specials.hpp \ + libsrc/include/../csg/surface.hpp libsrc/include/../csg/solid.hpp \ + libsrc/include/../csg/identify.hpp \ + libsrc/include/../csg/singularref.hpp libsrc/include/../csg/csgeom.hpp \ + libsrc/include/../csg/triapprox.hpp libsrc/include/../csg/algprim.hpp \ + libsrc/include/../csg/brick.hpp libsrc/include/../csg/spline3d.hpp \ + libsrc/include/../csg/manifold.hpp libsrc/include/../csg/curve2d.hpp \ + libsrc/include/../csg/explicitcurve2d.hpp \ + libsrc/include/../csg/gencyl.hpp libsrc/include/../csg/polyhedra.hpp \ + libsrc/include/../csg/extrusion.hpp \ + libsrc/include/../csg/revolution.hpp libsrc/include/../csg/specpoin.hpp \ + libsrc/include/../csg/edgeflw.hpp libsrc/include/../csg/meshsurf.hpp +# 1 "/Users/geuzaine/.gmsh/Netgen//" +revolution.o: libsrc/csg/revolution.cpp libsrc/include/mystdlib.h \ + libsrc/include/linalg.hpp libsrc/include/../linalg/linalg.hpp \ + libsrc/include/myadt.hpp libsrc/include/../general/myadt.hpp \ + libsrc/include/mydefs.hpp libsrc/include/../general/ngexception.hpp \ + libsrc/include/../general/parthreads.hpp \ + libsrc/include/../general/moveablemem.hpp \ + libsrc/include/../general/dynamicmem.hpp \ + libsrc/include/../general/template.hpp \ + libsrc/include/../general/array.hpp libsrc/include/../general/table.hpp \ + libsrc/include/../general/hashtabl.hpp \ + libsrc/include/../general/symbolta.hpp \ + libsrc/include/../general/bitarray.hpp \ + libsrc/include/../general/flags.hpp \ + libsrc/include/../general/spbita2d.hpp \ + libsrc/include/../general/seti.hpp libsrc/include/../general/optmem.hpp \ + libsrc/include/../general/autoptr.hpp \ + libsrc/include/../general/sort.hpp libsrc/include/../general/stack.hpp \ + libsrc/include/../general/mystring.hpp \ + libsrc/include/../linalg/vector.hpp \ + libsrc/include/../linalg/densemat.hpp \ + libsrc/include/../linalg/polynomial.hpp libsrc/include/csg.hpp \ + libsrc/include/../csg/csg.hpp libsrc/include/gprim.hpp \ + libsrc/include/../gprim/gprim.hpp \ + libsrc/include/../gprim/geomobjects.hpp \ + libsrc/include/../gprim/geomops.hpp \ + libsrc/include/../gprim/geomfuncs.hpp \ + libsrc/include/../gprim/geom2d.hpp libsrc/include/../gprim/geom3d.hpp \ + libsrc/include/../gprim/geomtest3d.hpp \ + libsrc/include/../gprim/transform3d.hpp \ + libsrc/include/../gprim/adtree.hpp libsrc/include/meshing.hpp \ + libsrc/include/../meshing/meshing.hpp libsrc/include/../gprim/gprim.hpp \ + libsrc/include/../linalg/linalg.hpp libsrc/include/opti.hpp \ + libsrc/include/../opti/opti.hpp \ + libsrc/include/../meshing/msghandler.hpp \ + libsrc/include/../meshing/meshtype.hpp \ + libsrc/include/../meshing/localh.hpp \ + libsrc/include/../meshing/meshclass.hpp \ + libsrc/include/../meshing/global.hpp \ + libsrc/include/../meshing/meshtool.hpp \ + libsrc/include/../meshing/ruler2.hpp \ + libsrc/include/../meshing/adfront2.hpp \ + libsrc/include/../meshing/meshing2.hpp \ + libsrc/include/../meshing/improve2.hpp \ + libsrc/include/../meshing/geomsearch.hpp \ + libsrc/include/../meshing/adfront3.hpp \ + libsrc/include/../meshing/ruler3.hpp \ + libsrc/include/../meshing/meshing3.hpp \ + libsrc/include/../meshing/improve3.hpp \ + libsrc/include/../meshing/findip.hpp \ + libsrc/include/../meshing/topology.hpp \ + libsrc/include/../meshing/curvedelems.hpp \ + libsrc/include/../meshing/bisect.hpp \ + libsrc/include/../meshing/clusters.hpp \ + libsrc/include/../meshing/meshfunc.hpp \ + libsrc/include/../meshing/hprefinement.hpp \ + libsrc/include/../meshing/boundarylayer.hpp \ + libsrc/include/../meshing/specials.hpp \ + libsrc/include/../csg/surface.hpp libsrc/include/../csg/solid.hpp \ + libsrc/include/../csg/identify.hpp \ + libsrc/include/../csg/singularref.hpp libsrc/include/../csg/csgeom.hpp \ + libsrc/include/../csg/triapprox.hpp libsrc/include/../csg/algprim.hpp \ + libsrc/include/../csg/brick.hpp libsrc/include/../csg/spline3d.hpp \ + libsrc/include/../csg/manifold.hpp libsrc/include/../csg/curve2d.hpp \ + libsrc/include/../csg/explicitcurve2d.hpp \ + libsrc/include/../csg/gencyl.hpp libsrc/include/../csg/polyhedra.hpp \ + libsrc/include/../csg/extrusion.hpp \ + libsrc/include/../csg/revolution.hpp libsrc/include/../csg/specpoin.hpp \ + libsrc/include/../csg/edgeflw.hpp libsrc/include/../csg/meshsurf.hpp +# 1 "/Users/geuzaine/.gmsh/Netgen//" +genmesh.o: libsrc/csg/genmesh.cpp libsrc/include/mystdlib.h \ + libsrc/include/myadt.hpp libsrc/include/../general/myadt.hpp \ + libsrc/include/mydefs.hpp libsrc/include/../general/ngexception.hpp \ + libsrc/include/../general/parthreads.hpp \ + libsrc/include/../general/moveablemem.hpp \ + libsrc/include/../general/dynamicmem.hpp \ + libsrc/include/../general/template.hpp \ + libsrc/include/../general/array.hpp libsrc/include/../general/table.hpp \ + libsrc/include/../general/hashtabl.hpp \ + libsrc/include/../general/symbolta.hpp \ + libsrc/include/../general/bitarray.hpp \ + libsrc/include/../general/flags.hpp \ + libsrc/include/../general/spbita2d.hpp \ + libsrc/include/../general/seti.hpp libsrc/include/../general/optmem.hpp \ + libsrc/include/../general/autoptr.hpp \ + libsrc/include/../general/sort.hpp libsrc/include/../general/stack.hpp \ + libsrc/include/../general/mystring.hpp libsrc/include/linalg.hpp \ + libsrc/include/../linalg/linalg.hpp libsrc/include/../linalg/vector.hpp \ + libsrc/include/../linalg/densemat.hpp \ + libsrc/include/../linalg/polynomial.hpp libsrc/include/csg.hpp \ + libsrc/include/../csg/csg.hpp libsrc/include/gprim.hpp \ + libsrc/include/../gprim/gprim.hpp \ + libsrc/include/../gprim/geomobjects.hpp \ + libsrc/include/../gprim/geomops.hpp \ + libsrc/include/../gprim/geomfuncs.hpp \ + libsrc/include/../gprim/geom2d.hpp libsrc/include/../gprim/geom3d.hpp \ + libsrc/include/../gprim/geomtest3d.hpp \ + libsrc/include/../gprim/transform3d.hpp \ + libsrc/include/../gprim/adtree.hpp libsrc/include/meshing.hpp \ + libsrc/include/../meshing/meshing.hpp libsrc/include/../gprim/gprim.hpp \ + libsrc/include/../linalg/linalg.hpp libsrc/include/opti.hpp \ + libsrc/include/../opti/opti.hpp \ + libsrc/include/../meshing/msghandler.hpp \ + libsrc/include/../meshing/meshtype.hpp \ + libsrc/include/../meshing/localh.hpp \ + libsrc/include/../meshing/meshclass.hpp \ + libsrc/include/../meshing/global.hpp \ + libsrc/include/../meshing/meshtool.hpp \ + libsrc/include/../meshing/ruler2.hpp \ + libsrc/include/../meshing/adfront2.hpp \ + libsrc/include/../meshing/meshing2.hpp \ + libsrc/include/../meshing/improve2.hpp \ + libsrc/include/../meshing/geomsearch.hpp \ + libsrc/include/../meshing/adfront3.hpp \ + libsrc/include/../meshing/ruler3.hpp \ + libsrc/include/../meshing/meshing3.hpp \ + libsrc/include/../meshing/improve3.hpp \ + libsrc/include/../meshing/findip.hpp \ + libsrc/include/../meshing/topology.hpp \ + libsrc/include/../meshing/curvedelems.hpp \ + libsrc/include/../meshing/bisect.hpp \ + libsrc/include/../meshing/clusters.hpp \ + libsrc/include/../meshing/meshfunc.hpp \ + libsrc/include/../meshing/hprefinement.hpp \ + libsrc/include/../meshing/boundarylayer.hpp \ + libsrc/include/../meshing/specials.hpp \ + libsrc/include/../csg/surface.hpp libsrc/include/../csg/solid.hpp \ + libsrc/include/../csg/identify.hpp \ + libsrc/include/../csg/singularref.hpp libsrc/include/../csg/csgeom.hpp \ + libsrc/include/../csg/triapprox.hpp libsrc/include/../csg/algprim.hpp \ + libsrc/include/../csg/brick.hpp libsrc/include/../csg/spline3d.hpp \ + libsrc/include/../csg/manifold.hpp libsrc/include/../csg/curve2d.hpp \ + libsrc/include/../csg/explicitcurve2d.hpp \ + libsrc/include/../csg/gencyl.hpp libsrc/include/../csg/polyhedra.hpp \ + libsrc/include/../csg/extrusion.hpp \ + libsrc/include/../csg/revolution.hpp libsrc/include/../csg/specpoin.hpp \ + libsrc/include/../csg/edgeflw.hpp libsrc/include/../csg/meshsurf.hpp +# 1 "/Users/geuzaine/.gmsh/Netgen//" +spline3d.o: libsrc/csg/spline3d.cpp libsrc/include/mystdlib.h \ + libsrc/include/myadt.hpp libsrc/include/../general/myadt.hpp \ + libsrc/include/mydefs.hpp libsrc/include/../general/ngexception.hpp \ + libsrc/include/../general/parthreads.hpp \ + libsrc/include/../general/moveablemem.hpp \ + libsrc/include/../general/dynamicmem.hpp \ + libsrc/include/../general/template.hpp \ + libsrc/include/../general/array.hpp libsrc/include/../general/table.hpp \ + libsrc/include/../general/hashtabl.hpp \ + libsrc/include/../general/symbolta.hpp \ + libsrc/include/../general/bitarray.hpp \ + libsrc/include/../general/flags.hpp \ + libsrc/include/../general/spbita2d.hpp \ + libsrc/include/../general/seti.hpp libsrc/include/../general/optmem.hpp \ + libsrc/include/../general/autoptr.hpp \ + libsrc/include/../general/sort.hpp libsrc/include/../general/stack.hpp \ + libsrc/include/../general/mystring.hpp libsrc/include/linalg.hpp \ + libsrc/include/../linalg/linalg.hpp libsrc/include/../linalg/vector.hpp \ + libsrc/include/../linalg/densemat.hpp \ + libsrc/include/../linalg/polynomial.hpp libsrc/include/csg.hpp \ + libsrc/include/../csg/csg.hpp libsrc/include/gprim.hpp \ + libsrc/include/../gprim/gprim.hpp \ + libsrc/include/../gprim/geomobjects.hpp \ + libsrc/include/../gprim/geomops.hpp \ + libsrc/include/../gprim/geomfuncs.hpp \ + libsrc/include/../gprim/geom2d.hpp libsrc/include/../gprim/geom3d.hpp \ + libsrc/include/../gprim/geomtest3d.hpp \ + libsrc/include/../gprim/transform3d.hpp \ + libsrc/include/../gprim/adtree.hpp libsrc/include/meshing.hpp \ + libsrc/include/../meshing/meshing.hpp libsrc/include/../gprim/gprim.hpp \ + libsrc/include/../linalg/linalg.hpp libsrc/include/opti.hpp \ + libsrc/include/../opti/opti.hpp \ + libsrc/include/../meshing/msghandler.hpp \ + libsrc/include/../meshing/meshtype.hpp \ + libsrc/include/../meshing/localh.hpp \ + libsrc/include/../meshing/meshclass.hpp \ + libsrc/include/../meshing/global.hpp \ + libsrc/include/../meshing/meshtool.hpp \ + libsrc/include/../meshing/ruler2.hpp \ + libsrc/include/../meshing/adfront2.hpp \ + libsrc/include/../meshing/meshing2.hpp \ + libsrc/include/../meshing/improve2.hpp \ + libsrc/include/../meshing/geomsearch.hpp \ + libsrc/include/../meshing/adfront3.hpp \ + libsrc/include/../meshing/ruler3.hpp \ + libsrc/include/../meshing/meshing3.hpp \ + libsrc/include/../meshing/improve3.hpp \ + libsrc/include/../meshing/findip.hpp \ + libsrc/include/../meshing/topology.hpp \ + libsrc/include/../meshing/curvedelems.hpp \ + libsrc/include/../meshing/bisect.hpp \ + libsrc/include/../meshing/clusters.hpp \ + libsrc/include/../meshing/meshfunc.hpp \ + libsrc/include/../meshing/hprefinement.hpp \ + libsrc/include/../meshing/boundarylayer.hpp \ + libsrc/include/../meshing/specials.hpp \ + libsrc/include/../csg/surface.hpp libsrc/include/../csg/solid.hpp \ + libsrc/include/../csg/identify.hpp \ + libsrc/include/../csg/singularref.hpp libsrc/include/../csg/csgeom.hpp \ + libsrc/include/../csg/triapprox.hpp libsrc/include/../csg/algprim.hpp \ + libsrc/include/../csg/brick.hpp libsrc/include/../csg/spline3d.hpp \ + libsrc/include/../csg/manifold.hpp libsrc/include/../csg/curve2d.hpp \ + libsrc/include/../csg/explicitcurve2d.hpp \ + libsrc/include/../csg/gencyl.hpp libsrc/include/../csg/polyhedra.hpp \ + libsrc/include/../csg/extrusion.hpp \ + libsrc/include/../csg/revolution.hpp libsrc/include/../csg/specpoin.hpp \ + libsrc/include/../csg/edgeflw.hpp libsrc/include/../csg/meshsurf.hpp +# 1 "/Users/geuzaine/.gmsh/Netgen//" +surface.o: libsrc/csg/surface.cpp libsrc/include/mystdlib.h \ + libsrc/include/myadt.hpp libsrc/include/../general/myadt.hpp \ + libsrc/include/mydefs.hpp libsrc/include/../general/ngexception.hpp \ + libsrc/include/../general/parthreads.hpp \ + libsrc/include/../general/moveablemem.hpp \ + libsrc/include/../general/dynamicmem.hpp \ + libsrc/include/../general/template.hpp \ + libsrc/include/../general/array.hpp libsrc/include/../general/table.hpp \ + libsrc/include/../general/hashtabl.hpp \ + libsrc/include/../general/symbolta.hpp \ + libsrc/include/../general/bitarray.hpp \ + libsrc/include/../general/flags.hpp \ + libsrc/include/../general/spbita2d.hpp \ + libsrc/include/../general/seti.hpp libsrc/include/../general/optmem.hpp \ + libsrc/include/../general/autoptr.hpp \ + libsrc/include/../general/sort.hpp libsrc/include/../general/stack.hpp \ + libsrc/include/../general/mystring.hpp libsrc/include/csg.hpp \ + libsrc/include/../csg/csg.hpp libsrc/include/gprim.hpp \ + libsrc/include/../gprim/gprim.hpp \ + libsrc/include/../gprim/geomobjects.hpp \ + libsrc/include/../gprim/geomops.hpp \ + libsrc/include/../gprim/geomfuncs.hpp \ + libsrc/include/../gprim/geom2d.hpp libsrc/include/../gprim/geom3d.hpp \ + libsrc/include/../gprim/geomtest3d.hpp \ + libsrc/include/../gprim/transform3d.hpp \ + libsrc/include/../gprim/adtree.hpp libsrc/include/meshing.hpp \ + libsrc/include/../meshing/meshing.hpp libsrc/include/../gprim/gprim.hpp \ + libsrc/include/linalg.hpp libsrc/include/../linalg/linalg.hpp \ + libsrc/include/../linalg/vector.hpp \ + libsrc/include/../linalg/densemat.hpp \ + libsrc/include/../linalg/polynomial.hpp libsrc/include/opti.hpp \ + libsrc/include/../opti/opti.hpp \ + libsrc/include/../meshing/msghandler.hpp \ + libsrc/include/../meshing/meshtype.hpp \ + libsrc/include/../meshing/localh.hpp \ + libsrc/include/../meshing/meshclass.hpp \ + libsrc/include/../meshing/global.hpp \ + libsrc/include/../meshing/meshtool.hpp \ + libsrc/include/../meshing/ruler2.hpp \ + libsrc/include/../meshing/adfront2.hpp \ + libsrc/include/../meshing/meshing2.hpp \ + libsrc/include/../meshing/improve2.hpp \ + libsrc/include/../meshing/geomsearch.hpp \ + libsrc/include/../meshing/adfront3.hpp \ + libsrc/include/../meshing/ruler3.hpp \ + libsrc/include/../meshing/meshing3.hpp \ + libsrc/include/../meshing/improve3.hpp \ + libsrc/include/../meshing/findip.hpp \ + libsrc/include/../meshing/topology.hpp \ + libsrc/include/../meshing/curvedelems.hpp \ + libsrc/include/../meshing/bisect.hpp \ + libsrc/include/../meshing/clusters.hpp \ + libsrc/include/../meshing/meshfunc.hpp \ + libsrc/include/../meshing/hprefinement.hpp \ + libsrc/include/../meshing/boundarylayer.hpp \ + libsrc/include/../meshing/specials.hpp \ + libsrc/include/../csg/surface.hpp libsrc/include/../csg/solid.hpp \ + libsrc/include/../csg/identify.hpp \ + libsrc/include/../csg/singularref.hpp libsrc/include/../csg/csgeom.hpp \ + libsrc/include/../csg/triapprox.hpp libsrc/include/../csg/algprim.hpp \ + libsrc/include/../csg/brick.hpp libsrc/include/../csg/spline3d.hpp \ + libsrc/include/../csg/manifold.hpp libsrc/include/../csg/curve2d.hpp \ + libsrc/include/../csg/explicitcurve2d.hpp \ + libsrc/include/../csg/gencyl.hpp libsrc/include/../csg/polyhedra.hpp \ + libsrc/include/../csg/extrusion.hpp \ + libsrc/include/../csg/revolution.hpp libsrc/include/../csg/specpoin.hpp \ + libsrc/include/../csg/edgeflw.hpp libsrc/include/../csg/meshsurf.hpp \ + libsrc/include/../linalg/linalg.hpp +# 1 "/Users/geuzaine/.gmsh/Netgen//" +identify.o: libsrc/csg/identify.cpp libsrc/include/mystdlib.h \ + libsrc/include/myadt.hpp libsrc/include/../general/myadt.hpp \ + libsrc/include/mydefs.hpp libsrc/include/../general/ngexception.hpp \ + libsrc/include/../general/parthreads.hpp \ + libsrc/include/../general/moveablemem.hpp \ + libsrc/include/../general/dynamicmem.hpp \ + libsrc/include/../general/template.hpp \ + libsrc/include/../general/array.hpp libsrc/include/../general/table.hpp \ + libsrc/include/../general/hashtabl.hpp \ + libsrc/include/../general/symbolta.hpp \ + libsrc/include/../general/bitarray.hpp \ + libsrc/include/../general/flags.hpp \ + libsrc/include/../general/spbita2d.hpp \ + libsrc/include/../general/seti.hpp libsrc/include/../general/optmem.hpp \ + libsrc/include/../general/autoptr.hpp \ + libsrc/include/../general/sort.hpp libsrc/include/../general/stack.hpp \ + libsrc/include/../general/mystring.hpp libsrc/include/linalg.hpp \ + libsrc/include/../linalg/linalg.hpp libsrc/include/../linalg/vector.hpp \ + libsrc/include/../linalg/densemat.hpp \ + libsrc/include/../linalg/polynomial.hpp libsrc/include/csg.hpp \ + libsrc/include/../csg/csg.hpp libsrc/include/gprim.hpp \ + libsrc/include/../gprim/gprim.hpp \ + libsrc/include/../gprim/geomobjects.hpp \ + libsrc/include/../gprim/geomops.hpp \ + libsrc/include/../gprim/geomfuncs.hpp \ + libsrc/include/../gprim/geom2d.hpp libsrc/include/../gprim/geom3d.hpp \ + libsrc/include/../gprim/geomtest3d.hpp \ + libsrc/include/../gprim/transform3d.hpp \ + libsrc/include/../gprim/adtree.hpp libsrc/include/meshing.hpp \ + libsrc/include/../meshing/meshing.hpp libsrc/include/../gprim/gprim.hpp \ + libsrc/include/../linalg/linalg.hpp libsrc/include/opti.hpp \ + libsrc/include/../opti/opti.hpp \ + libsrc/include/../meshing/msghandler.hpp \ + libsrc/include/../meshing/meshtype.hpp \ + libsrc/include/../meshing/localh.hpp \ + libsrc/include/../meshing/meshclass.hpp \ + libsrc/include/../meshing/global.hpp \ + libsrc/include/../meshing/meshtool.hpp \ + libsrc/include/../meshing/ruler2.hpp \ + libsrc/include/../meshing/adfront2.hpp \ + libsrc/include/../meshing/meshing2.hpp \ + libsrc/include/../meshing/improve2.hpp \ + libsrc/include/../meshing/geomsearch.hpp \ + libsrc/include/../meshing/adfront3.hpp \ + libsrc/include/../meshing/ruler3.hpp \ + libsrc/include/../meshing/meshing3.hpp \ + libsrc/include/../meshing/improve3.hpp \ + libsrc/include/../meshing/findip.hpp \ + libsrc/include/../meshing/topology.hpp \ + libsrc/include/../meshing/curvedelems.hpp \ + libsrc/include/../meshing/bisect.hpp \ + libsrc/include/../meshing/clusters.hpp \ + libsrc/include/../meshing/meshfunc.hpp \ + libsrc/include/../meshing/hprefinement.hpp \ + libsrc/include/../meshing/boundarylayer.hpp \ + libsrc/include/../meshing/specials.hpp \ + libsrc/include/../csg/surface.hpp libsrc/include/../csg/solid.hpp \ + libsrc/include/../csg/identify.hpp \ + libsrc/include/../csg/singularref.hpp libsrc/include/../csg/csgeom.hpp \ + libsrc/include/../csg/triapprox.hpp libsrc/include/../csg/algprim.hpp \ + libsrc/include/../csg/brick.hpp libsrc/include/../csg/spline3d.hpp \ + libsrc/include/../csg/manifold.hpp libsrc/include/../csg/curve2d.hpp \ + libsrc/include/../csg/explicitcurve2d.hpp \ + libsrc/include/../csg/gencyl.hpp libsrc/include/../csg/polyhedra.hpp \ + libsrc/include/../csg/extrusion.hpp \ + libsrc/include/../csg/revolution.hpp libsrc/include/../csg/specpoin.hpp \ + libsrc/include/../csg/edgeflw.hpp libsrc/include/../csg/meshsurf.hpp +# 1 "/Users/geuzaine/.gmsh/Netgen//" +triapprox.o: libsrc/csg/triapprox.cpp libsrc/include/mystdlib.h \ + libsrc/include/myadt.hpp libsrc/include/../general/myadt.hpp \ + libsrc/include/mydefs.hpp libsrc/include/../general/ngexception.hpp \ + libsrc/include/../general/parthreads.hpp \ + libsrc/include/../general/moveablemem.hpp \ + libsrc/include/../general/dynamicmem.hpp \ + libsrc/include/../general/template.hpp \ + libsrc/include/../general/array.hpp libsrc/include/../general/table.hpp \ + libsrc/include/../general/hashtabl.hpp \ + libsrc/include/../general/symbolta.hpp \ + libsrc/include/../general/bitarray.hpp \ + libsrc/include/../general/flags.hpp \ + libsrc/include/../general/spbita2d.hpp \ + libsrc/include/../general/seti.hpp libsrc/include/../general/optmem.hpp \ + libsrc/include/../general/autoptr.hpp \ + libsrc/include/../general/sort.hpp libsrc/include/../general/stack.hpp \ + libsrc/include/../general/mystring.hpp libsrc/include/linalg.hpp \ + libsrc/include/../linalg/linalg.hpp libsrc/include/../linalg/vector.hpp \ + libsrc/include/../linalg/densemat.hpp \ + libsrc/include/../linalg/polynomial.hpp libsrc/include/csg.hpp \ + libsrc/include/../csg/csg.hpp libsrc/include/gprim.hpp \ + libsrc/include/../gprim/gprim.hpp \ + libsrc/include/../gprim/geomobjects.hpp \ + libsrc/include/../gprim/geomops.hpp \ + libsrc/include/../gprim/geomfuncs.hpp \ + libsrc/include/../gprim/geom2d.hpp libsrc/include/../gprim/geom3d.hpp \ + libsrc/include/../gprim/geomtest3d.hpp \ + libsrc/include/../gprim/transform3d.hpp \ + libsrc/include/../gprim/adtree.hpp libsrc/include/meshing.hpp \ + libsrc/include/../meshing/meshing.hpp libsrc/include/../gprim/gprim.hpp \ + libsrc/include/../linalg/linalg.hpp libsrc/include/opti.hpp \ + libsrc/include/../opti/opti.hpp \ + libsrc/include/../meshing/msghandler.hpp \ + libsrc/include/../meshing/meshtype.hpp \ + libsrc/include/../meshing/localh.hpp \ + libsrc/include/../meshing/meshclass.hpp \ + libsrc/include/../meshing/global.hpp \ + libsrc/include/../meshing/meshtool.hpp \ + libsrc/include/../meshing/ruler2.hpp \ + libsrc/include/../meshing/adfront2.hpp \ + libsrc/include/../meshing/meshing2.hpp \ + libsrc/include/../meshing/improve2.hpp \ + libsrc/include/../meshing/geomsearch.hpp \ + libsrc/include/../meshing/adfront3.hpp \ + libsrc/include/../meshing/ruler3.hpp \ + libsrc/include/../meshing/meshing3.hpp \ + libsrc/include/../meshing/improve3.hpp \ + libsrc/include/../meshing/findip.hpp \ + libsrc/include/../meshing/topology.hpp \ + libsrc/include/../meshing/curvedelems.hpp \ + libsrc/include/../meshing/bisect.hpp \ + libsrc/include/../meshing/clusters.hpp \ + libsrc/include/../meshing/meshfunc.hpp \ + libsrc/include/../meshing/hprefinement.hpp \ + libsrc/include/../meshing/boundarylayer.hpp \ + libsrc/include/../meshing/specials.hpp \ + libsrc/include/../csg/surface.hpp libsrc/include/../csg/solid.hpp \ + libsrc/include/../csg/identify.hpp \ + libsrc/include/../csg/singularref.hpp libsrc/include/../csg/csgeom.hpp \ + libsrc/include/../csg/triapprox.hpp libsrc/include/../csg/algprim.hpp \ + libsrc/include/../csg/brick.hpp libsrc/include/../csg/spline3d.hpp \ + libsrc/include/../csg/manifold.hpp libsrc/include/../csg/curve2d.hpp \ + libsrc/include/../csg/explicitcurve2d.hpp \ + libsrc/include/../csg/gencyl.hpp libsrc/include/../csg/polyhedra.hpp \ + libsrc/include/../csg/extrusion.hpp \ + libsrc/include/../csg/revolution.hpp libsrc/include/../csg/specpoin.hpp \ + libsrc/include/../csg/edgeflw.hpp libsrc/include/../csg/meshsurf.hpp +# 1 "/Users/geuzaine/.gmsh/Netgen//" +geom2dmesh.o: libsrc/geom2d/geom2dmesh.cpp libsrc/include/mystdlib.h \ + libsrc/include/csg.hpp libsrc/include/../csg/csg.hpp \ + libsrc/include/myadt.hpp libsrc/include/../general/myadt.hpp \ + libsrc/include/mydefs.hpp libsrc/include/../general/ngexception.hpp \ + libsrc/include/../general/parthreads.hpp \ + libsrc/include/../general/moveablemem.hpp \ + libsrc/include/../general/dynamicmem.hpp \ + libsrc/include/../general/template.hpp \ + libsrc/include/../general/array.hpp libsrc/include/../general/table.hpp \ + libsrc/include/../general/hashtabl.hpp \ + libsrc/include/../general/symbolta.hpp \ + libsrc/include/../general/bitarray.hpp \ + libsrc/include/../general/flags.hpp \ + libsrc/include/../general/spbita2d.hpp \ + libsrc/include/../general/seti.hpp libsrc/include/../general/optmem.hpp \ + libsrc/include/../general/autoptr.hpp \ + libsrc/include/../general/sort.hpp libsrc/include/../general/stack.hpp \ + libsrc/include/../general/mystring.hpp libsrc/include/gprim.hpp \ + libsrc/include/../gprim/gprim.hpp \ + libsrc/include/../gprim/geomobjects.hpp \ + libsrc/include/../gprim/geomops.hpp \ + libsrc/include/../gprim/geomfuncs.hpp \ + libsrc/include/../gprim/geom2d.hpp libsrc/include/../gprim/geom3d.hpp \ + libsrc/include/../gprim/geomtest3d.hpp \ + libsrc/include/../gprim/transform3d.hpp \ + libsrc/include/../gprim/adtree.hpp libsrc/include/meshing.hpp \ + libsrc/include/../meshing/meshing.hpp libsrc/include/../gprim/gprim.hpp \ + libsrc/include/linalg.hpp libsrc/include/../linalg/linalg.hpp \ + libsrc/include/../linalg/vector.hpp \ + libsrc/include/../linalg/densemat.hpp \ + libsrc/include/../linalg/polynomial.hpp libsrc/include/opti.hpp \ + libsrc/include/../opti/opti.hpp \ + libsrc/include/../meshing/msghandler.hpp \ + libsrc/include/../meshing/meshtype.hpp \ + libsrc/include/../meshing/localh.hpp \ + libsrc/include/../meshing/meshclass.hpp \ + libsrc/include/../meshing/global.hpp \ + libsrc/include/../meshing/meshtool.hpp \ + libsrc/include/../meshing/ruler2.hpp \ + libsrc/include/../meshing/adfront2.hpp \ + libsrc/include/../meshing/meshing2.hpp \ + libsrc/include/../meshing/improve2.hpp \ + libsrc/include/../meshing/geomsearch.hpp \ + libsrc/include/../meshing/adfront3.hpp \ + libsrc/include/../meshing/ruler3.hpp \ + libsrc/include/../meshing/meshing3.hpp \ + libsrc/include/../meshing/improve3.hpp \ + libsrc/include/../meshing/findip.hpp \ + libsrc/include/../meshing/topology.hpp \ + libsrc/include/../meshing/curvedelems.hpp \ + libsrc/include/../meshing/bisect.hpp \ + libsrc/include/../meshing/clusters.hpp \ + libsrc/include/../meshing/meshfunc.hpp \ + libsrc/include/../meshing/hprefinement.hpp \ + libsrc/include/../meshing/boundarylayer.hpp \ + libsrc/include/../meshing/specials.hpp \ + libsrc/include/../csg/surface.hpp libsrc/include/../csg/solid.hpp \ + libsrc/include/../csg/identify.hpp \ + libsrc/include/../csg/singularref.hpp libsrc/include/../csg/csgeom.hpp \ + libsrc/include/../csg/triapprox.hpp libsrc/include/../csg/algprim.hpp \ + libsrc/include/../csg/brick.hpp libsrc/include/../csg/spline3d.hpp \ + libsrc/include/../csg/manifold.hpp libsrc/include/../csg/curve2d.hpp \ + libsrc/include/../csg/explicitcurve2d.hpp \ + libsrc/include/../csg/gencyl.hpp libsrc/include/../csg/polyhedra.hpp \ + libsrc/include/../csg/extrusion.hpp \ + libsrc/include/../csg/revolution.hpp libsrc/include/../csg/specpoin.hpp \ + libsrc/include/../csg/edgeflw.hpp libsrc/include/../csg/meshsurf.hpp \ + libsrc/include/geometry2d.hpp libsrc/include/../geom2d/geometry2d.hpp \ + libsrc/include/../gprim/gprim.hpp libsrc/include/../geom2d/spline2d.hpp \ + libsrc/include/../geom2d/splinegeometry2.hpp \ + libsrc/include/../geom2d/geom2dmesh.hpp +# 1 "/Users/geuzaine/.gmsh/Netgen//" +spline2d.o: libsrc/geom2d/spline2d.cpp libsrc/include/mystdlib.h \ + libsrc/include/csg.hpp libsrc/include/../csg/csg.hpp \ + libsrc/include/myadt.hpp libsrc/include/../general/myadt.hpp \ + libsrc/include/mydefs.hpp libsrc/include/../general/ngexception.hpp \ + libsrc/include/../general/parthreads.hpp \ + libsrc/include/../general/moveablemem.hpp \ + libsrc/include/../general/dynamicmem.hpp \ + libsrc/include/../general/template.hpp \ + libsrc/include/../general/array.hpp libsrc/include/../general/table.hpp \ + libsrc/include/../general/hashtabl.hpp \ + libsrc/include/../general/symbolta.hpp \ + libsrc/include/../general/bitarray.hpp \ + libsrc/include/../general/flags.hpp \ + libsrc/include/../general/spbita2d.hpp \ + libsrc/include/../general/seti.hpp libsrc/include/../general/optmem.hpp \ + libsrc/include/../general/autoptr.hpp \ + libsrc/include/../general/sort.hpp libsrc/include/../general/stack.hpp \ + libsrc/include/../general/mystring.hpp libsrc/include/gprim.hpp \ + libsrc/include/../gprim/gprim.hpp \ + libsrc/include/../gprim/geomobjects.hpp \ + libsrc/include/../gprim/geomops.hpp \ + libsrc/include/../gprim/geomfuncs.hpp \ + libsrc/include/../gprim/geom2d.hpp libsrc/include/../gprim/geom3d.hpp \ + libsrc/include/../gprim/geomtest3d.hpp \ + libsrc/include/../gprim/transform3d.hpp \ + libsrc/include/../gprim/adtree.hpp libsrc/include/meshing.hpp \ + libsrc/include/../meshing/meshing.hpp libsrc/include/../gprim/gprim.hpp \ + libsrc/include/linalg.hpp libsrc/include/../linalg/linalg.hpp \ + libsrc/include/../linalg/vector.hpp \ + libsrc/include/../linalg/densemat.hpp \ + libsrc/include/../linalg/polynomial.hpp libsrc/include/opti.hpp \ + libsrc/include/../opti/opti.hpp \ + libsrc/include/../meshing/msghandler.hpp \ + libsrc/include/../meshing/meshtype.hpp \ + libsrc/include/../meshing/localh.hpp \ + libsrc/include/../meshing/meshclass.hpp \ + libsrc/include/../meshing/global.hpp \ + libsrc/include/../meshing/meshtool.hpp \ + libsrc/include/../meshing/ruler2.hpp \ + libsrc/include/../meshing/adfront2.hpp \ + libsrc/include/../meshing/meshing2.hpp \ + libsrc/include/../meshing/improve2.hpp \ + libsrc/include/../meshing/geomsearch.hpp \ + libsrc/include/../meshing/adfront3.hpp \ + libsrc/include/../meshing/ruler3.hpp \ + libsrc/include/../meshing/meshing3.hpp \ + libsrc/include/../meshing/improve3.hpp \ + libsrc/include/../meshing/findip.hpp \ + libsrc/include/../meshing/topology.hpp \ + libsrc/include/../meshing/curvedelems.hpp \ + libsrc/include/../meshing/bisect.hpp \ + libsrc/include/../meshing/clusters.hpp \ + libsrc/include/../meshing/meshfunc.hpp \ + libsrc/include/../meshing/hprefinement.hpp \ + libsrc/include/../meshing/boundarylayer.hpp \ + libsrc/include/../meshing/specials.hpp \ + libsrc/include/../csg/surface.hpp libsrc/include/../csg/solid.hpp \ + libsrc/include/../csg/identify.hpp \ + libsrc/include/../csg/singularref.hpp libsrc/include/../csg/csgeom.hpp \ + libsrc/include/../csg/triapprox.hpp libsrc/include/../csg/algprim.hpp \ + libsrc/include/../csg/brick.hpp libsrc/include/../csg/spline3d.hpp \ + libsrc/include/../csg/manifold.hpp libsrc/include/../csg/curve2d.hpp \ + libsrc/include/../csg/explicitcurve2d.hpp \ + libsrc/include/../csg/gencyl.hpp libsrc/include/../csg/polyhedra.hpp \ + libsrc/include/../csg/extrusion.hpp \ + libsrc/include/../csg/revolution.hpp libsrc/include/../csg/specpoin.hpp \ + libsrc/include/../csg/edgeflw.hpp libsrc/include/../csg/meshsurf.hpp \ + libsrc/include/../linalg/linalg.hpp libsrc/geom2d/spline2d.hpp +# 1 "/Users/geuzaine/.gmsh/Netgen//" +splinegeometry2.o: libsrc/geom2d/splinegeometry2.cpp \ + libsrc/include/mystdlib.h libsrc/include/csg.hpp \ + libsrc/include/../csg/csg.hpp libsrc/include/myadt.hpp \ + libsrc/include/../general/myadt.hpp libsrc/include/mydefs.hpp \ + libsrc/include/../general/ngexception.hpp \ + libsrc/include/../general/parthreads.hpp \ + libsrc/include/../general/moveablemem.hpp \ + libsrc/include/../general/dynamicmem.hpp \ + libsrc/include/../general/template.hpp \ + libsrc/include/../general/array.hpp libsrc/include/../general/table.hpp \ + libsrc/include/../general/hashtabl.hpp \ + libsrc/include/../general/symbolta.hpp \ + libsrc/include/../general/bitarray.hpp \ + libsrc/include/../general/flags.hpp \ + libsrc/include/../general/spbita2d.hpp \ + libsrc/include/../general/seti.hpp libsrc/include/../general/optmem.hpp \ + libsrc/include/../general/autoptr.hpp \ + libsrc/include/../general/sort.hpp libsrc/include/../general/stack.hpp \ + libsrc/include/../general/mystring.hpp libsrc/include/gprim.hpp \ + libsrc/include/../gprim/gprim.hpp \ + libsrc/include/../gprim/geomobjects.hpp \ + libsrc/include/../gprim/geomops.hpp \ + libsrc/include/../gprim/geomfuncs.hpp \ + libsrc/include/../gprim/geom2d.hpp libsrc/include/../gprim/geom3d.hpp \ + libsrc/include/../gprim/geomtest3d.hpp \ + libsrc/include/../gprim/transform3d.hpp \ + libsrc/include/../gprim/adtree.hpp libsrc/include/meshing.hpp \ + libsrc/include/../meshing/meshing.hpp libsrc/include/../gprim/gprim.hpp \ + libsrc/include/linalg.hpp libsrc/include/../linalg/linalg.hpp \ + libsrc/include/../linalg/vector.hpp \ + libsrc/include/../linalg/densemat.hpp \ + libsrc/include/../linalg/polynomial.hpp libsrc/include/opti.hpp \ + libsrc/include/../opti/opti.hpp \ + libsrc/include/../meshing/msghandler.hpp \ + libsrc/include/../meshing/meshtype.hpp \ + libsrc/include/../meshing/localh.hpp \ + libsrc/include/../meshing/meshclass.hpp \ + libsrc/include/../meshing/global.hpp \ + libsrc/include/../meshing/meshtool.hpp \ + libsrc/include/../meshing/ruler2.hpp \ + libsrc/include/../meshing/adfront2.hpp \ + libsrc/include/../meshing/meshing2.hpp \ + libsrc/include/../meshing/improve2.hpp \ + libsrc/include/../meshing/geomsearch.hpp \ + libsrc/include/../meshing/adfront3.hpp \ + libsrc/include/../meshing/ruler3.hpp \ + libsrc/include/../meshing/meshing3.hpp \ + libsrc/include/../meshing/improve3.hpp \ + libsrc/include/../meshing/findip.hpp \ + libsrc/include/../meshing/topology.hpp \ + libsrc/include/../meshing/curvedelems.hpp \ + libsrc/include/../meshing/bisect.hpp \ + libsrc/include/../meshing/clusters.hpp \ + libsrc/include/../meshing/meshfunc.hpp \ + libsrc/include/../meshing/hprefinement.hpp \ + libsrc/include/../meshing/boundarylayer.hpp \ + libsrc/include/../meshing/specials.hpp \ + libsrc/include/../csg/surface.hpp libsrc/include/../csg/solid.hpp \ + libsrc/include/../csg/identify.hpp \ + libsrc/include/../csg/singularref.hpp libsrc/include/../csg/csgeom.hpp \ + libsrc/include/../csg/triapprox.hpp libsrc/include/../csg/algprim.hpp \ + libsrc/include/../csg/brick.hpp libsrc/include/../csg/spline3d.hpp \ + libsrc/include/../csg/manifold.hpp libsrc/include/../csg/curve2d.hpp \ + libsrc/include/../csg/explicitcurve2d.hpp \ + libsrc/include/../csg/gencyl.hpp libsrc/include/../csg/polyhedra.hpp \ + libsrc/include/../csg/extrusion.hpp \ + libsrc/include/../csg/revolution.hpp libsrc/include/../csg/specpoin.hpp \ + libsrc/include/../csg/edgeflw.hpp libsrc/include/../csg/meshsurf.hpp \ + libsrc/include/../linalg/linalg.hpp libsrc/geom2d/spline2d.hpp \ + libsrc/geom2d/splinegeometry2.hpp +# 1 "/Users/geuzaine/.gmsh/Netgen//" +genmesh2d.o: libsrc/geom2d/genmesh2d.cpp libsrc/include/mystdlib.h \ + libsrc/include/csg.hpp libsrc/include/../csg/csg.hpp \ + libsrc/include/myadt.hpp libsrc/include/../general/myadt.hpp \ + libsrc/include/mydefs.hpp libsrc/include/../general/ngexception.hpp \ + libsrc/include/../general/parthreads.hpp \ + libsrc/include/../general/moveablemem.hpp \ + libsrc/include/../general/dynamicmem.hpp \ + libsrc/include/../general/template.hpp \ + libsrc/include/../general/array.hpp libsrc/include/../general/table.hpp \ + libsrc/include/../general/hashtabl.hpp \ + libsrc/include/../general/symbolta.hpp \ + libsrc/include/../general/bitarray.hpp \ + libsrc/include/../general/flags.hpp \ + libsrc/include/../general/spbita2d.hpp \ + libsrc/include/../general/seti.hpp libsrc/include/../general/optmem.hpp \ + libsrc/include/../general/autoptr.hpp \ + libsrc/include/../general/sort.hpp libsrc/include/../general/stack.hpp \ + libsrc/include/../general/mystring.hpp libsrc/include/gprim.hpp \ + libsrc/include/../gprim/gprim.hpp \ + libsrc/include/../gprim/geomobjects.hpp \ + libsrc/include/../gprim/geomops.hpp \ + libsrc/include/../gprim/geomfuncs.hpp \ + libsrc/include/../gprim/geom2d.hpp libsrc/include/../gprim/geom3d.hpp \ + libsrc/include/../gprim/geomtest3d.hpp \ + libsrc/include/../gprim/transform3d.hpp \ + libsrc/include/../gprim/adtree.hpp libsrc/include/meshing.hpp \ + libsrc/include/../meshing/meshing.hpp libsrc/include/../gprim/gprim.hpp \ + libsrc/include/linalg.hpp libsrc/include/../linalg/linalg.hpp \ + libsrc/include/../linalg/vector.hpp \ + libsrc/include/../linalg/densemat.hpp \ + libsrc/include/../linalg/polynomial.hpp libsrc/include/opti.hpp \ + libsrc/include/../opti/opti.hpp \ + libsrc/include/../meshing/msghandler.hpp \ + libsrc/include/../meshing/meshtype.hpp \ + libsrc/include/../meshing/localh.hpp \ + libsrc/include/../meshing/meshclass.hpp \ + libsrc/include/../meshing/global.hpp \ + libsrc/include/../meshing/meshtool.hpp \ + libsrc/include/../meshing/ruler2.hpp \ + libsrc/include/../meshing/adfront2.hpp \ + libsrc/include/../meshing/meshing2.hpp \ + libsrc/include/../meshing/improve2.hpp \ + libsrc/include/../meshing/geomsearch.hpp \ + libsrc/include/../meshing/adfront3.hpp \ + libsrc/include/../meshing/ruler3.hpp \ + libsrc/include/../meshing/meshing3.hpp \ + libsrc/include/../meshing/improve3.hpp \ + libsrc/include/../meshing/findip.hpp \ + libsrc/include/../meshing/topology.hpp \ + libsrc/include/../meshing/curvedelems.hpp \ + libsrc/include/../meshing/bisect.hpp \ + libsrc/include/../meshing/clusters.hpp \ + libsrc/include/../meshing/meshfunc.hpp \ + libsrc/include/../meshing/hprefinement.hpp \ + libsrc/include/../meshing/boundarylayer.hpp \ + libsrc/include/../meshing/specials.hpp \ + libsrc/include/../csg/surface.hpp libsrc/include/../csg/solid.hpp \ + libsrc/include/../csg/identify.hpp \ + libsrc/include/../csg/singularref.hpp libsrc/include/../csg/csgeom.hpp \ + libsrc/include/../csg/triapprox.hpp libsrc/include/../csg/algprim.hpp \ + libsrc/include/../csg/brick.hpp libsrc/include/../csg/spline3d.hpp \ + libsrc/include/../csg/manifold.hpp libsrc/include/../csg/curve2d.hpp \ + libsrc/include/../csg/explicitcurve2d.hpp \ + libsrc/include/../csg/gencyl.hpp libsrc/include/../csg/polyhedra.hpp \ + libsrc/include/../csg/extrusion.hpp \ + libsrc/include/../csg/revolution.hpp libsrc/include/../csg/specpoin.hpp \ + libsrc/include/../csg/edgeflw.hpp libsrc/include/../csg/meshsurf.hpp \ + libsrc/include/geometry2d.hpp libsrc/include/../geom2d/geometry2d.hpp \ + libsrc/include/../gprim/gprim.hpp libsrc/include/../geom2d/spline2d.hpp \ + libsrc/include/../geom2d/splinegeometry2.hpp \ + libsrc/include/../geom2d/geom2dmesh.hpp +# 1 "/Users/geuzaine/.gmsh/Netgen//" +meshstlsurface.o: libsrc/stlgeom/meshstlsurface.cpp \ + libsrc/include/mystdlib.h libsrc/include/myadt.hpp \ + libsrc/include/../general/myadt.hpp libsrc/include/mydefs.hpp \ + libsrc/include/../general/ngexception.hpp \ + libsrc/include/../general/parthreads.hpp \ + libsrc/include/../general/moveablemem.hpp \ + libsrc/include/../general/dynamicmem.hpp \ + libsrc/include/../general/template.hpp \ + libsrc/include/../general/array.hpp libsrc/include/../general/table.hpp \ + libsrc/include/../general/hashtabl.hpp \ + libsrc/include/../general/symbolta.hpp \ + libsrc/include/../general/bitarray.hpp \ + libsrc/include/../general/flags.hpp \ + libsrc/include/../general/spbita2d.hpp \ + libsrc/include/../general/seti.hpp libsrc/include/../general/optmem.hpp \ + libsrc/include/../general/autoptr.hpp \ + libsrc/include/../general/sort.hpp libsrc/include/../general/stack.hpp \ + libsrc/include/../general/mystring.hpp libsrc/include/linalg.hpp \ + libsrc/include/../linalg/linalg.hpp libsrc/include/../linalg/vector.hpp \ + libsrc/include/../linalg/densemat.hpp \ + libsrc/include/../linalg/polynomial.hpp libsrc/include/gprim.hpp \ + libsrc/include/../gprim/gprim.hpp \ + libsrc/include/../gprim/geomobjects.hpp \ + libsrc/include/../gprim/geomops.hpp \ + libsrc/include/../gprim/geomfuncs.hpp \ + libsrc/include/../gprim/geom2d.hpp libsrc/include/../gprim/geom3d.hpp \ + libsrc/include/../gprim/geomtest3d.hpp \ + libsrc/include/../gprim/transform3d.hpp \ + libsrc/include/../gprim/adtree.hpp libsrc/include/meshing.hpp \ + libsrc/include/../meshing/meshing.hpp libsrc/include/../gprim/gprim.hpp \ + libsrc/include/../linalg/linalg.hpp libsrc/include/opti.hpp \ + libsrc/include/../opti/opti.hpp \ + libsrc/include/../meshing/msghandler.hpp \ + libsrc/include/../meshing/meshtype.hpp \ + libsrc/include/../meshing/localh.hpp \ + libsrc/include/../meshing/meshclass.hpp \ + libsrc/include/../meshing/global.hpp \ + libsrc/include/../meshing/meshtool.hpp \ + libsrc/include/../meshing/ruler2.hpp \ + libsrc/include/../meshing/adfront2.hpp \ + libsrc/include/../meshing/meshing2.hpp \ + libsrc/include/../meshing/improve2.hpp \ + libsrc/include/../meshing/geomsearch.hpp \ + libsrc/include/../meshing/adfront3.hpp \ + libsrc/include/../meshing/ruler3.hpp \ + libsrc/include/../meshing/meshing3.hpp \ + libsrc/include/../meshing/improve3.hpp \ + libsrc/include/../meshing/findip.hpp \ + libsrc/include/../meshing/topology.hpp \ + libsrc/include/../meshing/curvedelems.hpp \ + libsrc/include/../meshing/bisect.hpp \ + libsrc/include/../meshing/clusters.hpp \ + libsrc/include/../meshing/meshfunc.hpp \ + libsrc/include/../meshing/hprefinement.hpp \ + libsrc/include/../meshing/boundarylayer.hpp \ + libsrc/include/../meshing/specials.hpp libsrc/stlgeom/stlgeom.hpp \ + libsrc/include/../gprim/gprim.hpp libsrc/stlgeom/stltopology.hpp \ + libsrc/stlgeom/stltool.hpp libsrc/stlgeom/stlline.hpp \ + libsrc/stlgeom/meshstlsurface.hpp +# 1 "/Users/geuzaine/.gmsh/Netgen//" +stlline.o: libsrc/stlgeom/stlline.cpp libsrc/include/mystdlib.h \ + libsrc/include/myadt.hpp libsrc/include/../general/myadt.hpp \ + libsrc/include/mydefs.hpp libsrc/include/../general/ngexception.hpp \ + libsrc/include/../general/parthreads.hpp \ + libsrc/include/../general/moveablemem.hpp \ + libsrc/include/../general/dynamicmem.hpp \ + libsrc/include/../general/template.hpp \ + libsrc/include/../general/array.hpp libsrc/include/../general/table.hpp \ + libsrc/include/../general/hashtabl.hpp \ + libsrc/include/../general/symbolta.hpp \ + libsrc/include/../general/bitarray.hpp \ + libsrc/include/../general/flags.hpp \ + libsrc/include/../general/spbita2d.hpp \ + libsrc/include/../general/seti.hpp libsrc/include/../general/optmem.hpp \ + libsrc/include/../general/autoptr.hpp \ + libsrc/include/../general/sort.hpp libsrc/include/../general/stack.hpp \ + libsrc/include/../general/mystring.hpp libsrc/include/linalg.hpp \ + libsrc/include/../linalg/linalg.hpp libsrc/include/../linalg/vector.hpp \ + libsrc/include/../linalg/densemat.hpp \ + libsrc/include/../linalg/polynomial.hpp libsrc/include/gprim.hpp \ + libsrc/include/../gprim/gprim.hpp \ + libsrc/include/../gprim/geomobjects.hpp \ + libsrc/include/../gprim/geomops.hpp \ + libsrc/include/../gprim/geomfuncs.hpp \ + libsrc/include/../gprim/geom2d.hpp libsrc/include/../gprim/geom3d.hpp \ + libsrc/include/../gprim/geomtest3d.hpp \ + libsrc/include/../gprim/transform3d.hpp \ + libsrc/include/../gprim/adtree.hpp libsrc/include/meshing.hpp \ + libsrc/include/../meshing/meshing.hpp libsrc/include/../gprim/gprim.hpp \ + libsrc/include/../linalg/linalg.hpp libsrc/include/opti.hpp \ + libsrc/include/../opti/opti.hpp \ + libsrc/include/../meshing/msghandler.hpp \ + libsrc/include/../meshing/meshtype.hpp \ + libsrc/include/../meshing/localh.hpp \ + libsrc/include/../meshing/meshclass.hpp \ + libsrc/include/../meshing/global.hpp \ + libsrc/include/../meshing/meshtool.hpp \ + libsrc/include/../meshing/ruler2.hpp \ + libsrc/include/../meshing/adfront2.hpp \ + libsrc/include/../meshing/meshing2.hpp \ + libsrc/include/../meshing/improve2.hpp \ + libsrc/include/../meshing/geomsearch.hpp \ + libsrc/include/../meshing/adfront3.hpp \ + libsrc/include/../meshing/ruler3.hpp \ + libsrc/include/../meshing/meshing3.hpp \ + libsrc/include/../meshing/improve3.hpp \ + libsrc/include/../meshing/findip.hpp \ + libsrc/include/../meshing/topology.hpp \ + libsrc/include/../meshing/curvedelems.hpp \ + libsrc/include/../meshing/bisect.hpp \ + libsrc/include/../meshing/clusters.hpp \ + libsrc/include/../meshing/meshfunc.hpp \ + libsrc/include/../meshing/hprefinement.hpp \ + libsrc/include/../meshing/boundarylayer.hpp \ + libsrc/include/../meshing/specials.hpp libsrc/stlgeom/stlgeom.hpp \ + libsrc/include/../gprim/gprim.hpp libsrc/stlgeom/stltopology.hpp \ + libsrc/stlgeom/stltool.hpp libsrc/stlgeom/stlline.hpp \ + libsrc/stlgeom/meshstlsurface.hpp +# 1 "/Users/geuzaine/.gmsh/Netgen//" +stltopology.o: libsrc/stlgeom/stltopology.cpp libsrc/include/mystdlib.h \ + libsrc/include/myadt.hpp libsrc/include/../general/myadt.hpp \ + libsrc/include/mydefs.hpp libsrc/include/../general/ngexception.hpp \ + libsrc/include/../general/parthreads.hpp \ + libsrc/include/../general/moveablemem.hpp \ + libsrc/include/../general/dynamicmem.hpp \ + libsrc/include/../general/template.hpp \ + libsrc/include/../general/array.hpp libsrc/include/../general/table.hpp \ + libsrc/include/../general/hashtabl.hpp \ + libsrc/include/../general/symbolta.hpp \ + libsrc/include/../general/bitarray.hpp \ + libsrc/include/../general/flags.hpp \ + libsrc/include/../general/spbita2d.hpp \ + libsrc/include/../general/seti.hpp libsrc/include/../general/optmem.hpp \ + libsrc/include/../general/autoptr.hpp \ + libsrc/include/../general/sort.hpp libsrc/include/../general/stack.hpp \ + libsrc/include/../general/mystring.hpp libsrc/include/linalg.hpp \ + libsrc/include/../linalg/linalg.hpp libsrc/include/../linalg/vector.hpp \ + libsrc/include/../linalg/densemat.hpp \ + libsrc/include/../linalg/polynomial.hpp libsrc/include/gprim.hpp \ + libsrc/include/../gprim/gprim.hpp \ + libsrc/include/../gprim/geomobjects.hpp \ + libsrc/include/../gprim/geomops.hpp \ + libsrc/include/../gprim/geomfuncs.hpp \ + libsrc/include/../gprim/geom2d.hpp libsrc/include/../gprim/geom3d.hpp \ + libsrc/include/../gprim/geomtest3d.hpp \ + libsrc/include/../gprim/transform3d.hpp \ + libsrc/include/../gprim/adtree.hpp libsrc/include/meshing.hpp \ + libsrc/include/../meshing/meshing.hpp libsrc/include/../gprim/gprim.hpp \ + libsrc/include/../linalg/linalg.hpp libsrc/include/opti.hpp \ + libsrc/include/../opti/opti.hpp \ + libsrc/include/../meshing/msghandler.hpp \ + libsrc/include/../meshing/meshtype.hpp \ + libsrc/include/../meshing/localh.hpp \ + libsrc/include/../meshing/meshclass.hpp \ + libsrc/include/../meshing/global.hpp \ + libsrc/include/../meshing/meshtool.hpp \ + libsrc/include/../meshing/ruler2.hpp \ + libsrc/include/../meshing/adfront2.hpp \ + libsrc/include/../meshing/meshing2.hpp \ + libsrc/include/../meshing/improve2.hpp \ + libsrc/include/../meshing/geomsearch.hpp \ + libsrc/include/../meshing/adfront3.hpp \ + libsrc/include/../meshing/ruler3.hpp \ + libsrc/include/../meshing/meshing3.hpp \ + libsrc/include/../meshing/improve3.hpp \ + libsrc/include/../meshing/findip.hpp \ + libsrc/include/../meshing/topology.hpp \ + libsrc/include/../meshing/curvedelems.hpp \ + libsrc/include/../meshing/bisect.hpp \ + libsrc/include/../meshing/clusters.hpp \ + libsrc/include/../meshing/meshfunc.hpp \ + libsrc/include/../meshing/hprefinement.hpp \ + libsrc/include/../meshing/boundarylayer.hpp \ + libsrc/include/../meshing/specials.hpp libsrc/stlgeom/stlgeom.hpp \ + libsrc/include/../gprim/gprim.hpp libsrc/stlgeom/stltopology.hpp \ + libsrc/stlgeom/stltool.hpp libsrc/stlgeom/stlline.hpp \ + libsrc/stlgeom/meshstlsurface.hpp +# 1 "/Users/geuzaine/.gmsh/Netgen//" +stltool.o: libsrc/stlgeom/stltool.cpp libsrc/include/mystdlib.h \ + libsrc/include/myadt.hpp libsrc/include/../general/myadt.hpp \ + libsrc/include/mydefs.hpp libsrc/include/../general/ngexception.hpp \ + libsrc/include/../general/parthreads.hpp \ + libsrc/include/../general/moveablemem.hpp \ + libsrc/include/../general/dynamicmem.hpp \ + libsrc/include/../general/template.hpp \ + libsrc/include/../general/array.hpp libsrc/include/../general/table.hpp \ + libsrc/include/../general/hashtabl.hpp \ + libsrc/include/../general/symbolta.hpp \ + libsrc/include/../general/bitarray.hpp \ + libsrc/include/../general/flags.hpp \ + libsrc/include/../general/spbita2d.hpp \ + libsrc/include/../general/seti.hpp libsrc/include/../general/optmem.hpp \ + libsrc/include/../general/autoptr.hpp \ + libsrc/include/../general/sort.hpp libsrc/include/../general/stack.hpp \ + libsrc/include/../general/mystring.hpp libsrc/include/linalg.hpp \ + libsrc/include/../linalg/linalg.hpp libsrc/include/../linalg/vector.hpp \ + libsrc/include/../linalg/densemat.hpp \ + libsrc/include/../linalg/polynomial.hpp libsrc/include/gprim.hpp \ + libsrc/include/../gprim/gprim.hpp \ + libsrc/include/../gprim/geomobjects.hpp \ + libsrc/include/../gprim/geomops.hpp \ + libsrc/include/../gprim/geomfuncs.hpp \ + libsrc/include/../gprim/geom2d.hpp libsrc/include/../gprim/geom3d.hpp \ + libsrc/include/../gprim/geomtest3d.hpp \ + libsrc/include/../gprim/transform3d.hpp \ + libsrc/include/../gprim/adtree.hpp libsrc/include/meshing.hpp \ + libsrc/include/../meshing/meshing.hpp libsrc/include/../gprim/gprim.hpp \ + libsrc/include/../linalg/linalg.hpp libsrc/include/opti.hpp \ + libsrc/include/../opti/opti.hpp \ + libsrc/include/../meshing/msghandler.hpp \ + libsrc/include/../meshing/meshtype.hpp \ + libsrc/include/../meshing/localh.hpp \ + libsrc/include/../meshing/meshclass.hpp \ + libsrc/include/../meshing/global.hpp \ + libsrc/include/../meshing/meshtool.hpp \ + libsrc/include/../meshing/ruler2.hpp \ + libsrc/include/../meshing/adfront2.hpp \ + libsrc/include/../meshing/meshing2.hpp \ + libsrc/include/../meshing/improve2.hpp \ + libsrc/include/../meshing/geomsearch.hpp \ + libsrc/include/../meshing/adfront3.hpp \ + libsrc/include/../meshing/ruler3.hpp \ + libsrc/include/../meshing/meshing3.hpp \ + libsrc/include/../meshing/improve3.hpp \ + libsrc/include/../meshing/findip.hpp \ + libsrc/include/../meshing/topology.hpp \ + libsrc/include/../meshing/curvedelems.hpp \ + libsrc/include/../meshing/bisect.hpp \ + libsrc/include/../meshing/clusters.hpp \ + libsrc/include/../meshing/meshfunc.hpp \ + libsrc/include/../meshing/hprefinement.hpp \ + libsrc/include/../meshing/boundarylayer.hpp \ + libsrc/include/../meshing/specials.hpp libsrc/stlgeom/stlgeom.hpp \ + libsrc/include/../gprim/gprim.hpp libsrc/stlgeom/stltopology.hpp \ + libsrc/stlgeom/stltool.hpp libsrc/stlgeom/stlline.hpp \ + libsrc/stlgeom/meshstlsurface.hpp +# 1 "/Users/geuzaine/.gmsh/Netgen//" +stlgeom.o: libsrc/stlgeom/stlgeom.cpp libsrc/include/mystdlib.h \ + libsrc/include/myadt.hpp libsrc/include/../general/myadt.hpp \ + libsrc/include/mydefs.hpp libsrc/include/../general/ngexception.hpp \ + libsrc/include/../general/parthreads.hpp \ + libsrc/include/../general/moveablemem.hpp \ + libsrc/include/../general/dynamicmem.hpp \ + libsrc/include/../general/template.hpp \ + libsrc/include/../general/array.hpp libsrc/include/../general/table.hpp \ + libsrc/include/../general/hashtabl.hpp \ + libsrc/include/../general/symbolta.hpp \ + libsrc/include/../general/bitarray.hpp \ + libsrc/include/../general/flags.hpp \ + libsrc/include/../general/spbita2d.hpp \ + libsrc/include/../general/seti.hpp libsrc/include/../general/optmem.hpp \ + libsrc/include/../general/autoptr.hpp \ + libsrc/include/../general/sort.hpp libsrc/include/../general/stack.hpp \ + libsrc/include/../general/mystring.hpp libsrc/include/linalg.hpp \ + libsrc/include/../linalg/linalg.hpp libsrc/include/../linalg/vector.hpp \ + libsrc/include/../linalg/densemat.hpp \ + libsrc/include/../linalg/polynomial.hpp libsrc/include/gprim.hpp \ + libsrc/include/../gprim/gprim.hpp \ + libsrc/include/../gprim/geomobjects.hpp \ + libsrc/include/../gprim/geomops.hpp \ + libsrc/include/../gprim/geomfuncs.hpp \ + libsrc/include/../gprim/geom2d.hpp libsrc/include/../gprim/geom3d.hpp \ + libsrc/include/../gprim/geomtest3d.hpp \ + libsrc/include/../gprim/transform3d.hpp \ + libsrc/include/../gprim/adtree.hpp libsrc/include/meshing.hpp \ + libsrc/include/../meshing/meshing.hpp libsrc/include/../gprim/gprim.hpp \ + libsrc/include/../linalg/linalg.hpp libsrc/include/opti.hpp \ + libsrc/include/../opti/opti.hpp \ + libsrc/include/../meshing/msghandler.hpp \ + libsrc/include/../meshing/meshtype.hpp \ + libsrc/include/../meshing/localh.hpp \ + libsrc/include/../meshing/meshclass.hpp \ + libsrc/include/../meshing/global.hpp \ + libsrc/include/../meshing/meshtool.hpp \ + libsrc/include/../meshing/ruler2.hpp \ + libsrc/include/../meshing/adfront2.hpp \ + libsrc/include/../meshing/meshing2.hpp \ + libsrc/include/../meshing/improve2.hpp \ + libsrc/include/../meshing/geomsearch.hpp \ + libsrc/include/../meshing/adfront3.hpp \ + libsrc/include/../meshing/ruler3.hpp \ + libsrc/include/../meshing/meshing3.hpp \ + libsrc/include/../meshing/improve3.hpp \ + libsrc/include/../meshing/findip.hpp \ + libsrc/include/../meshing/topology.hpp \ + libsrc/include/../meshing/curvedelems.hpp \ + libsrc/include/../meshing/bisect.hpp \ + libsrc/include/../meshing/clusters.hpp \ + libsrc/include/../meshing/meshfunc.hpp \ + libsrc/include/../meshing/hprefinement.hpp \ + libsrc/include/../meshing/boundarylayer.hpp \ + libsrc/include/../meshing/specials.hpp libsrc/stlgeom/stlgeom.hpp \ + libsrc/include/../gprim/gprim.hpp libsrc/stlgeom/stltopology.hpp \ + libsrc/stlgeom/stltool.hpp libsrc/stlgeom/stlline.hpp \ + libsrc/stlgeom/meshstlsurface.hpp +# 1 "/Users/geuzaine/.gmsh/Netgen//" +stlgeomchart.o: libsrc/stlgeom/stlgeomchart.cpp libsrc/include/mystdlib.h \ + libsrc/include/myadt.hpp libsrc/include/../general/myadt.hpp \ + libsrc/include/mydefs.hpp libsrc/include/../general/ngexception.hpp \ + libsrc/include/../general/parthreads.hpp \ + libsrc/include/../general/moveablemem.hpp \ + libsrc/include/../general/dynamicmem.hpp \ + libsrc/include/../general/template.hpp \ + libsrc/include/../general/array.hpp libsrc/include/../general/table.hpp \ + libsrc/include/../general/hashtabl.hpp \ + libsrc/include/../general/symbolta.hpp \ + libsrc/include/../general/bitarray.hpp \ + libsrc/include/../general/flags.hpp \ + libsrc/include/../general/spbita2d.hpp \ + libsrc/include/../general/seti.hpp libsrc/include/../general/optmem.hpp \ + libsrc/include/../general/autoptr.hpp \ + libsrc/include/../general/sort.hpp libsrc/include/../general/stack.hpp \ + libsrc/include/../general/mystring.hpp libsrc/include/linalg.hpp \ + libsrc/include/../linalg/linalg.hpp libsrc/include/../linalg/vector.hpp \ + libsrc/include/../linalg/densemat.hpp \ + libsrc/include/../linalg/polynomial.hpp libsrc/include/gprim.hpp \ + libsrc/include/../gprim/gprim.hpp \ + libsrc/include/../gprim/geomobjects.hpp \ + libsrc/include/../gprim/geomops.hpp \ + libsrc/include/../gprim/geomfuncs.hpp \ + libsrc/include/../gprim/geom2d.hpp libsrc/include/../gprim/geom3d.hpp \ + libsrc/include/../gprim/geomtest3d.hpp \ + libsrc/include/../gprim/transform3d.hpp \ + libsrc/include/../gprim/adtree.hpp libsrc/include/meshing.hpp \ + libsrc/include/../meshing/meshing.hpp libsrc/include/../gprim/gprim.hpp \ + libsrc/include/../linalg/linalg.hpp libsrc/include/opti.hpp \ + libsrc/include/../opti/opti.hpp \ + libsrc/include/../meshing/msghandler.hpp \ + libsrc/include/../meshing/meshtype.hpp \ + libsrc/include/../meshing/localh.hpp \ + libsrc/include/../meshing/meshclass.hpp \ + libsrc/include/../meshing/global.hpp \ + libsrc/include/../meshing/meshtool.hpp \ + libsrc/include/../meshing/ruler2.hpp \ + libsrc/include/../meshing/adfront2.hpp \ + libsrc/include/../meshing/meshing2.hpp \ + libsrc/include/../meshing/improve2.hpp \ + libsrc/include/../meshing/geomsearch.hpp \ + libsrc/include/../meshing/adfront3.hpp \ + libsrc/include/../meshing/ruler3.hpp \ + libsrc/include/../meshing/meshing3.hpp \ + libsrc/include/../meshing/improve3.hpp \ + libsrc/include/../meshing/findip.hpp \ + libsrc/include/../meshing/topology.hpp \ + libsrc/include/../meshing/curvedelems.hpp \ + libsrc/include/../meshing/bisect.hpp \ + libsrc/include/../meshing/clusters.hpp \ + libsrc/include/../meshing/meshfunc.hpp \ + libsrc/include/../meshing/hprefinement.hpp \ + libsrc/include/../meshing/boundarylayer.hpp \ + libsrc/include/../meshing/specials.hpp libsrc/stlgeom/stlgeom.hpp \ + libsrc/include/../gprim/gprim.hpp libsrc/stlgeom/stltopology.hpp \ + libsrc/stlgeom/stltool.hpp libsrc/stlgeom/stlline.hpp \ + libsrc/stlgeom/meshstlsurface.hpp +# 1 "/Users/geuzaine/.gmsh/Netgen//" +stlgeommesh.o: libsrc/stlgeom/stlgeommesh.cpp libsrc/include/mystdlib.h \ + libsrc/include/myadt.hpp libsrc/include/../general/myadt.hpp \ + libsrc/include/mydefs.hpp libsrc/include/../general/ngexception.hpp \ + libsrc/include/../general/parthreads.hpp \ + libsrc/include/../general/moveablemem.hpp \ + libsrc/include/../general/dynamicmem.hpp \ + libsrc/include/../general/template.hpp \ + libsrc/include/../general/array.hpp libsrc/include/../general/table.hpp \ + libsrc/include/../general/hashtabl.hpp \ + libsrc/include/../general/symbolta.hpp \ + libsrc/include/../general/bitarray.hpp \ + libsrc/include/../general/flags.hpp \ + libsrc/include/../general/spbita2d.hpp \ + libsrc/include/../general/seti.hpp libsrc/include/../general/optmem.hpp \ + libsrc/include/../general/autoptr.hpp \ + libsrc/include/../general/sort.hpp libsrc/include/../general/stack.hpp \ + libsrc/include/../general/mystring.hpp libsrc/include/linalg.hpp \ + libsrc/include/../linalg/linalg.hpp libsrc/include/../linalg/vector.hpp \ + libsrc/include/../linalg/densemat.hpp \ + libsrc/include/../linalg/polynomial.hpp libsrc/include/gprim.hpp \ + libsrc/include/../gprim/gprim.hpp \ + libsrc/include/../gprim/geomobjects.hpp \ + libsrc/include/../gprim/geomops.hpp \ + libsrc/include/../gprim/geomfuncs.hpp \ + libsrc/include/../gprim/geom2d.hpp libsrc/include/../gprim/geom3d.hpp \ + libsrc/include/../gprim/geomtest3d.hpp \ + libsrc/include/../gprim/transform3d.hpp \ + libsrc/include/../gprim/adtree.hpp libsrc/include/meshing.hpp \ + libsrc/include/../meshing/meshing.hpp libsrc/include/../gprim/gprim.hpp \ + libsrc/include/../linalg/linalg.hpp libsrc/include/opti.hpp \ + libsrc/include/../opti/opti.hpp \ + libsrc/include/../meshing/msghandler.hpp \ + libsrc/include/../meshing/meshtype.hpp \ + libsrc/include/../meshing/localh.hpp \ + libsrc/include/../meshing/meshclass.hpp \ + libsrc/include/../meshing/global.hpp \ + libsrc/include/../meshing/meshtool.hpp \ + libsrc/include/../meshing/ruler2.hpp \ + libsrc/include/../meshing/adfront2.hpp \ + libsrc/include/../meshing/meshing2.hpp \ + libsrc/include/../meshing/improve2.hpp \ + libsrc/include/../meshing/geomsearch.hpp \ + libsrc/include/../meshing/adfront3.hpp \ + libsrc/include/../meshing/ruler3.hpp \ + libsrc/include/../meshing/meshing3.hpp \ + libsrc/include/../meshing/improve3.hpp \ + libsrc/include/../meshing/findip.hpp \ + libsrc/include/../meshing/topology.hpp \ + libsrc/include/../meshing/curvedelems.hpp \ + libsrc/include/../meshing/bisect.hpp \ + libsrc/include/../meshing/clusters.hpp \ + libsrc/include/../meshing/meshfunc.hpp \ + libsrc/include/../meshing/hprefinement.hpp \ + libsrc/include/../meshing/boundarylayer.hpp \ + libsrc/include/../meshing/specials.hpp libsrc/stlgeom/stlgeom.hpp \ + libsrc/include/../gprim/gprim.hpp libsrc/stlgeom/stltopology.hpp \ + libsrc/stlgeom/stltool.hpp libsrc/stlgeom/stlline.hpp \ + libsrc/stlgeom/meshstlsurface.hpp +# 1 "/Users/geuzaine/.gmsh/Netgen//" +moveablemem.o: libsrc/general/moveablemem.cpp libsrc/include/myadt.hpp \ + libsrc/include/../general/myadt.hpp libsrc/include/mystdlib.h \ + libsrc/include/mydefs.hpp libsrc/include/../general/ngexception.hpp \ + libsrc/include/../general/parthreads.hpp \ + libsrc/include/../general/moveablemem.hpp \ + libsrc/include/../general/dynamicmem.hpp \ + libsrc/include/../general/template.hpp \ + libsrc/include/../general/array.hpp libsrc/include/../general/table.hpp \ + libsrc/include/../general/hashtabl.hpp \ + libsrc/include/../general/symbolta.hpp \ + libsrc/include/../general/bitarray.hpp \ + libsrc/include/../general/flags.hpp \ + libsrc/include/../general/spbita2d.hpp \ + libsrc/include/../general/seti.hpp libsrc/include/../general/optmem.hpp \ + libsrc/include/../general/autoptr.hpp \ + libsrc/include/../general/sort.hpp libsrc/include/../general/stack.hpp \ + libsrc/include/../general/mystring.hpp +# 1 "/Users/geuzaine/.gmsh/Netgen//" +ngexception.o: libsrc/general/ngexception.cpp libsrc/include/myadt.hpp \ + libsrc/include/../general/myadt.hpp libsrc/include/mystdlib.h \ + libsrc/include/mydefs.hpp libsrc/include/../general/ngexception.hpp \ + libsrc/include/../general/parthreads.hpp \ + libsrc/include/../general/moveablemem.hpp \ + libsrc/include/../general/dynamicmem.hpp \ + libsrc/include/../general/template.hpp \ + libsrc/include/../general/array.hpp libsrc/include/../general/table.hpp \ + libsrc/include/../general/hashtabl.hpp \ + libsrc/include/../general/symbolta.hpp \ + libsrc/include/../general/bitarray.hpp \ + libsrc/include/../general/flags.hpp \ + libsrc/include/../general/spbita2d.hpp \ + libsrc/include/../general/seti.hpp libsrc/include/../general/optmem.hpp \ + libsrc/include/../general/autoptr.hpp \ + libsrc/include/../general/sort.hpp libsrc/include/../general/stack.hpp \ + libsrc/include/../general/mystring.hpp +# 1 "/Users/geuzaine/.gmsh/Netgen//" +table.o: libsrc/general/table.cpp libsrc/include/mystdlib.h \ + libsrc/include/myadt.hpp libsrc/include/../general/myadt.hpp \ + libsrc/include/mydefs.hpp libsrc/include/../general/ngexception.hpp \ + libsrc/include/../general/parthreads.hpp \ + libsrc/include/../general/moveablemem.hpp \ + libsrc/include/../general/dynamicmem.hpp \ + libsrc/include/../general/template.hpp \ + libsrc/include/../general/array.hpp libsrc/include/../general/table.hpp \ + libsrc/include/../general/hashtabl.hpp \ + libsrc/include/../general/symbolta.hpp \ + libsrc/include/../general/bitarray.hpp \ + libsrc/include/../general/flags.hpp \ + libsrc/include/../general/spbita2d.hpp \ + libsrc/include/../general/seti.hpp libsrc/include/../general/optmem.hpp \ + libsrc/include/../general/autoptr.hpp \ + libsrc/include/../general/sort.hpp libsrc/include/../general/stack.hpp \ + libsrc/include/../general/mystring.hpp +# 1 "/Users/geuzaine/.gmsh/Netgen//" +optmem.o: libsrc/general/optmem.cpp libsrc/include/mystdlib.h \ + libsrc/include/myadt.hpp libsrc/include/../general/myadt.hpp \ + libsrc/include/mydefs.hpp libsrc/include/../general/ngexception.hpp \ + libsrc/include/../general/parthreads.hpp \ + libsrc/include/../general/moveablemem.hpp \ + libsrc/include/../general/dynamicmem.hpp \ + libsrc/include/../general/template.hpp \ + libsrc/include/../general/array.hpp libsrc/include/../general/table.hpp \ + libsrc/include/../general/hashtabl.hpp \ + libsrc/include/../general/symbolta.hpp \ + libsrc/include/../general/bitarray.hpp \ + libsrc/include/../general/flags.hpp \ + libsrc/include/../general/spbita2d.hpp \ + libsrc/include/../general/seti.hpp libsrc/include/../general/optmem.hpp \ + libsrc/include/../general/autoptr.hpp \ + libsrc/include/../general/sort.hpp libsrc/include/../general/stack.hpp \ + libsrc/include/../general/mystring.hpp +# 1 "/Users/geuzaine/.gmsh/Netgen//" +spbita2d.o: libsrc/general/spbita2d.cpp libsrc/include/mystdlib.h \ + libsrc/include/myadt.hpp libsrc/include/../general/myadt.hpp \ + libsrc/include/mydefs.hpp libsrc/include/../general/ngexception.hpp \ + libsrc/include/../general/parthreads.hpp \ + libsrc/include/../general/moveablemem.hpp \ + libsrc/include/../general/dynamicmem.hpp \ + libsrc/include/../general/template.hpp \ + libsrc/include/../general/array.hpp libsrc/include/../general/table.hpp \ + libsrc/include/../general/hashtabl.hpp \ + libsrc/include/../general/symbolta.hpp \ + libsrc/include/../general/bitarray.hpp \ + libsrc/include/../general/flags.hpp \ + libsrc/include/../general/spbita2d.hpp \ + libsrc/include/../general/seti.hpp libsrc/include/../general/optmem.hpp \ + libsrc/include/../general/autoptr.hpp \ + libsrc/include/../general/sort.hpp libsrc/include/../general/stack.hpp \ + libsrc/include/../general/mystring.hpp +# 1 "/Users/geuzaine/.gmsh/Netgen//" +hashtabl.o: libsrc/general/hashtabl.cpp libsrc/include/mystdlib.h \ + libsrc/include/myadt.hpp libsrc/include/../general/myadt.hpp \ + libsrc/include/mydefs.hpp libsrc/include/../general/ngexception.hpp \ + libsrc/include/../general/parthreads.hpp \ + libsrc/include/../general/moveablemem.hpp \ + libsrc/include/../general/dynamicmem.hpp \ + libsrc/include/../general/template.hpp \ + libsrc/include/../general/array.hpp libsrc/include/../general/table.hpp \ + libsrc/include/../general/hashtabl.hpp \ + libsrc/include/../general/symbolta.hpp \ + libsrc/include/../general/bitarray.hpp \ + libsrc/include/../general/flags.hpp \ + libsrc/include/../general/spbita2d.hpp \ + libsrc/include/../general/seti.hpp libsrc/include/../general/optmem.hpp \ + libsrc/include/../general/autoptr.hpp \ + libsrc/include/../general/sort.hpp libsrc/include/../general/stack.hpp \ + libsrc/include/../general/mystring.hpp +# 1 "/Users/geuzaine/.gmsh/Netgen//" +sort.o: libsrc/general/sort.cpp libsrc/include/mystdlib.h \ + libsrc/include/myadt.hpp libsrc/include/../general/myadt.hpp \ + libsrc/include/mydefs.hpp libsrc/include/../general/ngexception.hpp \ + libsrc/include/../general/parthreads.hpp \ + libsrc/include/../general/moveablemem.hpp \ + libsrc/include/../general/dynamicmem.hpp \ + libsrc/include/../general/template.hpp \ + libsrc/include/../general/array.hpp libsrc/include/../general/table.hpp \ + libsrc/include/../general/hashtabl.hpp \ + libsrc/include/../general/symbolta.hpp \ + libsrc/include/../general/bitarray.hpp \ + libsrc/include/../general/flags.hpp \ + libsrc/include/../general/spbita2d.hpp \ + libsrc/include/../general/seti.hpp libsrc/include/../general/optmem.hpp \ + libsrc/include/../general/autoptr.hpp \ + libsrc/include/../general/sort.hpp libsrc/include/../general/stack.hpp \ + libsrc/include/../general/mystring.hpp +# 1 "/Users/geuzaine/.gmsh/Netgen//" +flags.o: libsrc/general/flags.cpp libsrc/include/mystdlib.h \ + libsrc/include/myadt.hpp libsrc/include/../general/myadt.hpp \ + libsrc/include/mydefs.hpp libsrc/include/../general/ngexception.hpp \ + libsrc/include/../general/parthreads.hpp \ + libsrc/include/../general/moveablemem.hpp \ + libsrc/include/../general/dynamicmem.hpp \ + libsrc/include/../general/template.hpp \ + libsrc/include/../general/array.hpp libsrc/include/../general/table.hpp \ + libsrc/include/../general/hashtabl.hpp \ + libsrc/include/../general/symbolta.hpp \ + libsrc/include/../general/bitarray.hpp \ + libsrc/include/../general/flags.hpp \ + libsrc/include/../general/spbita2d.hpp \ + libsrc/include/../general/seti.hpp libsrc/include/../general/optmem.hpp \ + libsrc/include/../general/autoptr.hpp \ + libsrc/include/../general/sort.hpp libsrc/include/../general/stack.hpp \ + libsrc/include/../general/mystring.hpp +# 1 "/Users/geuzaine/.gmsh/Netgen//" +seti.o: libsrc/general/seti.cpp libsrc/include/mystdlib.h \ + libsrc/include/myadt.hpp libsrc/include/../general/myadt.hpp \ + libsrc/include/mydefs.hpp libsrc/include/../general/ngexception.hpp \ + libsrc/include/../general/parthreads.hpp \ + libsrc/include/../general/moveablemem.hpp \ + libsrc/include/../general/dynamicmem.hpp \ + libsrc/include/../general/template.hpp \ + libsrc/include/../general/array.hpp libsrc/include/../general/table.hpp \ + libsrc/include/../general/hashtabl.hpp \ + libsrc/include/../general/symbolta.hpp \ + libsrc/include/../general/bitarray.hpp \ + libsrc/include/../general/flags.hpp \ + libsrc/include/../general/spbita2d.hpp \ + libsrc/include/../general/seti.hpp libsrc/include/../general/optmem.hpp \ + libsrc/include/../general/autoptr.hpp \ + libsrc/include/../general/sort.hpp libsrc/include/../general/stack.hpp \ + libsrc/include/../general/mystring.hpp +# 1 "/Users/geuzaine/.gmsh/Netgen//" +bitarray.o: libsrc/general/bitarray.cpp libsrc/include/mystdlib.h \ + libsrc/include/myadt.hpp libsrc/include/../general/myadt.hpp \ + libsrc/include/mydefs.hpp libsrc/include/../general/ngexception.hpp \ + libsrc/include/../general/parthreads.hpp \ + libsrc/include/../general/moveablemem.hpp \ + libsrc/include/../general/dynamicmem.hpp \ + libsrc/include/../general/template.hpp \ + libsrc/include/../general/array.hpp libsrc/include/../general/table.hpp \ + libsrc/include/../general/hashtabl.hpp \ + libsrc/include/../general/symbolta.hpp \ + libsrc/include/../general/bitarray.hpp \ + libsrc/include/../general/flags.hpp \ + libsrc/include/../general/spbita2d.hpp \ + libsrc/include/../general/seti.hpp libsrc/include/../general/optmem.hpp \ + libsrc/include/../general/autoptr.hpp \ + libsrc/include/../general/sort.hpp libsrc/include/../general/stack.hpp \ + libsrc/include/../general/mystring.hpp +# 1 "/Users/geuzaine/.gmsh/Netgen//" +array.o: libsrc/general/array.cpp libsrc/include/mystdlib.h \ + libsrc/include/myadt.hpp libsrc/include/../general/myadt.hpp \ + libsrc/include/mydefs.hpp libsrc/include/../general/ngexception.hpp \ + libsrc/include/../general/parthreads.hpp \ + libsrc/include/../general/moveablemem.hpp \ + libsrc/include/../general/dynamicmem.hpp \ + libsrc/include/../general/template.hpp \ + libsrc/include/../general/array.hpp libsrc/include/../general/table.hpp \ + libsrc/include/../general/hashtabl.hpp \ + libsrc/include/../general/symbolta.hpp \ + libsrc/include/../general/bitarray.hpp \ + libsrc/include/../general/flags.hpp \ + libsrc/include/../general/spbita2d.hpp \ + libsrc/include/../general/seti.hpp libsrc/include/../general/optmem.hpp \ + libsrc/include/../general/autoptr.hpp \ + libsrc/include/../general/sort.hpp libsrc/include/../general/stack.hpp \ + libsrc/include/../general/mystring.hpp +# 1 "/Users/geuzaine/.gmsh/Netgen//" +symbolta.o: libsrc/general/symbolta.cpp libsrc/include/mystdlib.h \ + libsrc/include/myadt.hpp libsrc/include/../general/myadt.hpp \ + libsrc/include/mydefs.hpp libsrc/include/../general/ngexception.hpp \ + libsrc/include/../general/parthreads.hpp \ + libsrc/include/../general/moveablemem.hpp \ + libsrc/include/../general/dynamicmem.hpp \ + libsrc/include/../general/template.hpp \ + libsrc/include/../general/array.hpp libsrc/include/../general/table.hpp \ + libsrc/include/../general/hashtabl.hpp \ + libsrc/include/../general/symbolta.hpp \ + libsrc/include/../general/bitarray.hpp \ + libsrc/include/../general/flags.hpp \ + libsrc/include/../general/spbita2d.hpp \ + libsrc/include/../general/seti.hpp libsrc/include/../general/optmem.hpp \ + libsrc/include/../general/autoptr.hpp \ + libsrc/include/../general/sort.hpp libsrc/include/../general/stack.hpp \ + libsrc/include/../general/mystring.hpp +# 1 "/Users/geuzaine/.gmsh/Netgen//" +mystring.o: libsrc/general/mystring.cpp libsrc/include/mystdlib.h \ + libsrc/include/myadt.hpp libsrc/include/../general/myadt.hpp \ + libsrc/include/mydefs.hpp libsrc/include/../general/ngexception.hpp \ + libsrc/include/../general/parthreads.hpp \ + libsrc/include/../general/moveablemem.hpp \ + libsrc/include/../general/dynamicmem.hpp \ + libsrc/include/../general/template.hpp \ + libsrc/include/../general/array.hpp libsrc/include/../general/table.hpp \ + libsrc/include/../general/hashtabl.hpp \ + libsrc/include/../general/symbolta.hpp \ + libsrc/include/../general/bitarray.hpp \ + libsrc/include/../general/flags.hpp \ + libsrc/include/../general/spbita2d.hpp \ + libsrc/include/../general/seti.hpp libsrc/include/../general/optmem.hpp \ + libsrc/include/../general/autoptr.hpp \ + libsrc/include/../general/sort.hpp libsrc/include/../general/stack.hpp \ + libsrc/include/../general/mystring.hpp libsrc/include/linalg.hpp \ + libsrc/include/../linalg/linalg.hpp libsrc/include/../linalg/vector.hpp \ + libsrc/include/../linalg/densemat.hpp \ + libsrc/include/../linalg/polynomial.hpp libsrc/include/gprim.hpp \ + libsrc/include/../gprim/gprim.hpp \ + libsrc/include/../gprim/geomobjects.hpp \ + libsrc/include/../gprim/geomops.hpp \ + libsrc/include/../gprim/geomfuncs.hpp \ + libsrc/include/../gprim/geom2d.hpp libsrc/include/../gprim/geom3d.hpp \ + libsrc/include/../gprim/geomtest3d.hpp \ + libsrc/include/../gprim/transform3d.hpp \ + libsrc/include/../gprim/adtree.hpp +# 1 "/Users/geuzaine/.gmsh/Netgen//" +nglib_addon.o: nglib_addon.cpp libsrc/include/meshing.hpp \ + libsrc/include/../meshing/meshing.hpp libsrc/include/myadt.hpp \ + libsrc/include/../general/myadt.hpp libsrc/include/mystdlib.h \ + libsrc/include/mydefs.hpp libsrc/include/../general/ngexception.hpp \ + libsrc/include/../general/parthreads.hpp \ + libsrc/include/../general/moveablemem.hpp \ + libsrc/include/../general/dynamicmem.hpp \ + libsrc/include/../general/template.hpp \ + libsrc/include/../general/array.hpp libsrc/include/../general/table.hpp \ + libsrc/include/../general/hashtabl.hpp \ + libsrc/include/../general/symbolta.hpp \ + libsrc/include/../general/bitarray.hpp \ + libsrc/include/../general/flags.hpp \ + libsrc/include/../general/spbita2d.hpp \ + libsrc/include/../general/seti.hpp libsrc/include/../general/optmem.hpp \ + libsrc/include/../general/autoptr.hpp \ + libsrc/include/../general/sort.hpp libsrc/include/../general/stack.hpp \ + libsrc/include/../general/mystring.hpp libsrc/include/gprim.hpp \ + libsrc/include/../gprim/gprim.hpp \ + libsrc/include/../gprim/geomobjects.hpp \ + libsrc/include/../gprim/geomops.hpp \ + libsrc/include/../gprim/geomfuncs.hpp \ + libsrc/include/../gprim/geom2d.hpp libsrc/include/../gprim/geom3d.hpp \ + libsrc/include/../gprim/geomtest3d.hpp \ + libsrc/include/../gprim/transform3d.hpp \ + libsrc/include/../gprim/adtree.hpp libsrc/include/linalg.hpp \ + libsrc/include/../linalg/linalg.hpp libsrc/include/../linalg/vector.hpp \ + libsrc/include/../linalg/densemat.hpp \ + libsrc/include/../linalg/polynomial.hpp libsrc/include/opti.hpp \ + libsrc/include/../opti/opti.hpp \ + libsrc/include/../meshing/msghandler.hpp \ + libsrc/include/../meshing/meshtype.hpp \ + libsrc/include/../meshing/localh.hpp \ + libsrc/include/../meshing/meshclass.hpp \ + libsrc/include/../meshing/global.hpp \ + libsrc/include/../meshing/meshtool.hpp \ + libsrc/include/../meshing/ruler2.hpp \ + libsrc/include/../meshing/adfront2.hpp \ + libsrc/include/../meshing/meshing2.hpp \ + libsrc/include/../meshing/improve2.hpp \ + libsrc/include/../meshing/geomsearch.hpp \ + libsrc/include/../meshing/adfront3.hpp \ + libsrc/include/../meshing/ruler3.hpp \ + libsrc/include/../meshing/meshing3.hpp \ + libsrc/include/../meshing/improve3.hpp \ + libsrc/include/../meshing/findip.hpp \ + libsrc/include/../meshing/topology.hpp \ + libsrc/include/../meshing/curvedelems.hpp \ + libsrc/include/../meshing/bisect.hpp \ + libsrc/include/../meshing/clusters.hpp \ + libsrc/include/../meshing/meshfunc.hpp \ + libsrc/include/../meshing/hprefinement.hpp \ + libsrc/include/../meshing/boundarylayer.hpp \ + libsrc/include/../meshing/specials.hpp libsrc/interface/nglib.h \ + ../Common/Message.h diff --git a/contrib/Netgen/README b/contrib/Netgen/README new file mode 100644 index 0000000000..08e5573ac2 --- /dev/null +++ b/contrib/Netgen/README @@ -0,0 +1,72 @@ + +This directory may contain a slightly modified version of Joachim +Sch\"oberl's NETGEN mesh generator: + +- only the libsrc directory was kept from the original distribution + +- the file meshing/improve2.cpp was slightly modified to fix build + problems on machines without TCL/TK + +- the file meshing/meshtype.hpp was slightly modified so that it + compiles with ISO-C++ complient compilers + +**IMPORTANT NOTICE** + +NETGEN requires the boundary mesh to be oriented with exterior +pointing normals. You HAVE TO define your geometry so that this +criterion is fulfilled (i.e., correctly orient the geometry surfaces +and the surface loops). + +************************************************************** + +From NETGEN's documentation: + +What is NETGEN +============== + +NETGEN is an automatic mesh generation tool for two and three +dimensions. Netgen is open source under the conditions of the LGPL. +It comes as stand alone programme with graphical user interface, or as +C++ library to be linked into an other application. Netgen is +available for Unix/Linux and Windows 98/NT. Netgen generates +triangular or quadrilateral meshes in 2D, and tetrahedral meshes in +3D. The input for 2D is described by spline curves, and the input for +3D problems is either defined by constructive solid geometries (CSG) +or by the standard STL file format. NETGEN contains modules for mesh +optimization and hierarchical mesh refinement. Curved elements are +supported of arbitrary order. + +The history of NETGEN +===================== + +The NETGEN project was started 1994 in the master's programme of +Joachim Sch\"oberl, under supervision of Prof. Ulrich Langer, at the +Department of Computational Mathematics and Optimization, University +Linz, Austria. Its further development was supported by the Austrian +science Fund ``Fonds zur F\"orderung der wissenschaftlichen +Forschung'' (http://www.fwf.ac.at) under projects P 10643-TEC and SFB +1306. The current home of Netgen is the Start project ``hp-FEM'' +(http://www.hpfem.jku.at) granted by the FWF. + +Special thanks go to +- Robert Gaisbauer: High order curved elements +- Hannes Gerstmayr: Meshing of STL geometry + +How to receive NETGEN +===================== + +NETGEN is available from the WEB at http://www.hpfem.jku.at/netgen +You find there source code releases for Linux/Unix/Windows, as well +as compiled versions for Windows. You can use CVS access to receive +the most up to date version. + +************************************************************** + +From NETGEN's README.install file: + +Latest information is available from: +http://www.sfb013.uni-linz.ac.at/~joachim/netgen + +People might have asked similar questions on +https://www.sfb013.uni-linz.ac.at/mailman/listinfo/netgen +(please note the s in https) diff --git a/contrib/Netgen/VERSION b/contrib/Netgen/VERSION new file mode 100644 index 0000000000..f56504b6db --- /dev/null +++ b/contrib/Netgen/VERSION @@ -0,0 +1 @@ +NG Version 4.4 \ No newline at end of file diff --git a/contrib/Netgen/libsrc/Makefile b/contrib/Netgen/libsrc/Makefile new file mode 100644 index 0000000000..4bf820bc2a --- /dev/null +++ b/contrib/Netgen/libsrc/Makefile @@ -0,0 +1,38 @@ +# +# +appl = NETGEN +.default all: +# +# +all: + @ (cd linalg; $(MAKE) -f Makefile) + @ (cd general; $(MAKE) -f Makefile) + @ (cd gprim; $(MAKE) -f Makefile) + @ (cd csg; $(MAKE) -f Makefile) + @ (cd geom2d; $(MAKE) -f Makefile) + @ (cd stlgeom; $(MAKE) -f Makefile) + @ (cd occ; $(MAKE) -f Makefile) + @ (cd meshing; $(MAKE) -f Makefile) + @ (cd opti; $(MAKE) -f Makefile) + @ (cd visualization; $(MAKE) -f Makefile) + @ (cd interface; $(MAKE) -f Makefile) +# +# @ (cd step; $(MAKE) -f Makefile) +# @ (cd stepgeom; $(MAKE) -f Makefile) +# @ (cd graphics; $(MAKE) -f Makefile) + +tar: + tar cvf ../../libsrc.tar Makefile + tar rf ../../libsrc.tar linalg/Makefile linalg/*.hh linalg/*.cc + tar rf ../../libsrc.tar general/Makefile general/*.hh general/*.cc + tar rf ../../libsrc.tar gprim/Makefile gprim/*.hh gprim/*.cc + tar rf ../../libsrc.tar csg/Makefile csg/*.hh csg/*.cc + tar rf ../../libsrc.tar stlgeom/Makefile stlgeom/*.hh stlgeom/*.cc + tar rf ../../libsrc.tar occ/Makefile occ/*.h* occ/*.c* + tar rf ../../libsrc.tar meshing/Makefile meshing/*.hh meshing/*.cc meshing/*.h + tar rf ../../libsrc.tar opti/Makefile opti/*.hh opti/*.cc + tar rf ../../libsrc.tar step/Makefile step/*.h step/*.cc + tar rf ../../libsrc.tar stepgeom/Makefile stepgeom/*.hh stepgeom/*.cc + tar tf ../../libsrc.tar include/*.h include/*.hh + gzip -9 ../../libsrc.tar + diff --git a/contrib/Netgen/libsrc/csg/Makefile b/contrib/Netgen/libsrc/csg/Makefile new file mode 100644 index 0000000000..e8c51dc218 --- /dev/null +++ b/contrib/Netgen/libsrc/csg/Makefile @@ -0,0 +1,26 @@ +# +# Makefile for geometric library +# +src = csgparser.cpp algprim.cpp curve2d.cpp brick.cpp \ + solid.cpp spline3d.cpp surface.cpp bspline2d.cpp \ + explicitcurve2d.cpp gencyl.cpp csgeom.cpp polyhedra.cpp extrusion.cpp revolution.cpp \ + manifold.cpp curve2d.cpp triapprox.cpp identify.cpp \ + singularref.cpp \ + edgeflw.cpp specpoin.cpp meshsurf.cpp genmesh.cpp +# +# lex.yy.cpp geometry.cpp +# +lib = csg +libpath = libsrc/csg +# +# +include ../makefile.inc +# +# geometry.cpp : geometry.yy +# bison -d -o geometry.c geometry.yy +# mv -f geometry.c geometry.cpp +# +# lex.yy.cpp : geometry.yy geometry.ll +# flex -+ -d -I geometry.ll +# mv lex.yy.cc lex.yy.cpp + diff --git a/contrib/Netgen/libsrc/csg/algprim.cpp b/contrib/Netgen/libsrc/csg/algprim.cpp new file mode 100644 index 0000000000..1123706b1e --- /dev/null +++ b/contrib/Netgen/libsrc/csg/algprim.cpp @@ -0,0 +1,1389 @@ +#include <mystdlib.h> + + +#include <linalg.hpp> +#include <csg.hpp> + + +namespace netgen +{ + +double +QuadraticSurface :: CalcFunctionValue (const Point<3> & p) const +{ + return p(0) * (cxx * p(0) + cxy * p(1) + cxz * p(2) + cx) + + p(1) * (cyy * p(1) + cyz * p(2) + cy) + + p(2) * (czz * p(2) + cz) + c1; +} + +void +QuadraticSurface :: CalcGradient (const Point<3> & p, Vec<3> & grad) const +{ + grad(0) = 2 * cxx * p(0) + cxy * p(1) + cxz * p(2) + cx; + grad(1) = 2 * cyy * p(1) + cxy * p(0) + cyz * p(2) + cy; + grad(2) = 2 * czz * p(2) + cxz * p(0) + cyz * p(1) + cz; +} + +void +QuadraticSurface :: CalcHesse (const Point<3> & /* p */, Mat<3> & hesse) const +{ + hesse(0,0) = 2 * cxx; + hesse(1,1) = 2 * cyy; + hesse(2,2) = 2 * czz; + hesse(0,1) = hesse(1,0) = cxy; + hesse(0,2) = hesse(2,0) = cxz; + hesse(1,2) = hesse(2,1) = cyz; +} + + +void QuadraticSurface :: Read (istream & ist) +{ + ist >> cxx >> cyy >> czz >> cxy >> cxz >> cyz >> cx >> cy >> cz >> c1; +} + +void QuadraticSurface :: Print (ostream & ost) const +{ + ost << cxx << " " << cyy << " " << czz << " " + << cxy << " " << cxz << " " << cyz << " " + << cx << " " << cy << " " << cz << " " + << c1 << endl; +} + + +void QuadraticSurface :: PrintCoeff (ostream & ost) const +{ + ost << " cxx = " << cxx + << " cyy = " << cyy + << " czz = " << czz + << " cxy = " << cxy + << " cxz = " << cxz + << " cyz = " << cyz + << " cx = " << cx + << " cy = " << cy + << " cz = " << cz + << " c1 = " << c1 << endl; +} + + + +Point<3> QuadraticSurface :: GetSurfacePoint () const +{ + MyError ("GetSurfacePoint called for QuadraticSurface"); + return Point<3> (0, 0, 0); +} + + +Plane :: Plane (const Point<3> & ap, Vec<3> an) +{ + p = ap; + n = an; + n.Normalize(); + + cxx = cyy = czz = cxy = cxz = cyz = 0; + cx = n(0); cy = n(1); cz = n(2); + c1 = - (cx * p(0) + cy * p(1) + cz * p(2)); +} + +Primitive * Plane :: Copy () const +{ + return new Plane (p, n); +} + +void Plane :: Transform (Transformation<3> & trans) +{ + Point<3> hp; + Vec<3> hn; + trans.Transform (p, hp); + trans.Transform (n, hn); + p = hp; + n = hn; + + cxx = cyy = czz = cxy = cxz = cyz = 0; + cx = n(0); cy = n(1); cz = n(2); + c1 = - (cx * p(0) + cy * p(1) + cz * p(2)); +} + + + +void Plane :: GetPrimitiveData (char *& classname, + ARRAY<double> & coeffs) const +{ + classname = "plane"; + coeffs.SetSize (6); + coeffs.Elem(1) = p(0); + coeffs.Elem(2) = p(1); + coeffs.Elem(3) = p(2); + coeffs.Elem(4) = n(0); + coeffs.Elem(5) = n(1); + coeffs.Elem(6) = n(2); +} + +void Plane :: SetPrimitiveData (ARRAY<double> & coeffs) +{ + p(0) = coeffs.Elem(1); + p(1) = coeffs.Elem(2); + p(2) = coeffs.Elem(3); + n(0) = coeffs.Elem(4); + n(1) = coeffs.Elem(5); + n(2) = coeffs.Elem(6); + + n.Normalize(); + + cxx = cyy = czz = cxy = cxz = cyz = 0; + cx = n(0); cy = n(1); cz = n(2); + c1 = - (cx * p(0) + cy * p(1) + cz * p(2)); +} + +Primitive * Plane :: CreateDefault () +{ + return new Plane (Point<3> (0,0,0), Vec<3> (0,0,1)); +} + + +int Plane :: IsIdentic (const Surface & s2, int & inv, double eps) const +{ + if (fabs (s2.CalcFunctionValue(p)) > eps) return 0; + Vec<3> hv1, hv2; + hv1 = n.GetNormal (); + hv2 = Cross (n, hv1); + + Point<3> hp = p + hv1; + if (fabs (s2.CalcFunctionValue(hp)) > eps) return 0; + hp = p + hv2; + if (fabs (s2.CalcFunctionValue(hp)) > eps) return 0; + + Vec<3> n1, n2; + 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 +{ + /* + Vec<3> p1p; + Point<2> pplane2 = pplane; + + pplane2 *= h; + p1p = pplane2(0) * ex + pplane2(1) * ey; + p3d = p1 + p1p; + */ + p3d = p1 + (h * pplane(0)) * ex + (h * pplane(1)) * ey; +} + + +void Plane :: Project (Point<3> & p3d) const +{ + double val = Plane::CalcFunctionValue (p3d); + p3d -= val * n; +} + +INSOLID_TYPE Plane :: BoxInSolid (const BoxSphere<3> & box) const +{ + int i; + double val; + Point<3> p; + + 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++) + { + p = box.GetPointNr (i); + val = Plane::CalcFunctionValue (p); + if (val < 0) + return DOES_INTERSECT; + } + return IS_OUTSIDE; + } + else + { + /* + double modify = + ((box.MaxX()-box.MinX()) * fabs (cx) + + (box.MaxY()-box.MinY()) * fabs (cy) + + (box.MaxZ()-box.MinZ()) * fabs (cz)) / 2; + */ + Vec<3> vdiag = box.PMax() - box.PMin(); + double modify = (vdiag(0) * fabs (cx) + + vdiag(1) * fabs (cy) + + vdiag(2) * fabs (cz) ) / 2; + if (val + modify > 0) + return DOES_INTERSECT; + return IS_INSIDE; + + + // only inside or intersect possible + for (i = 0; i < 8; i++) + { + p = box.GetPointNr (i); + val = Plane::CalcFunctionValue (p); + if (val > 0) + return DOES_INTERSECT; + } + return IS_INSIDE; + } + + + + /* + for (i = 1; i <= 8; i++) + { + box.GetPointNr (i, p); + val = CalcFunctionValue (p); + if (val > 0) inside = 0; + if (val < 0) outside = 0; + } + + if (inside) return IS_INSIDE; + if (outside) return IS_OUTSIDE; + return DOES_INTERSECT; + */ +} + + + +// double Plane :: CalcFunctionValue (const Point<3> & p3d) const +// { +// return cx * p3d(0) + cy * p3d(1) + cz * p3d(2) + c1; +// } + +void Plane :: CalcGradient (const Point<3> & /* p */, Vec<3> & grad) const +{ + grad(0) = cx; + grad(1) = cy; + grad(2) = cz; +} + +void Plane :: CalcHesse (const Point<3> & /* p */, Mat<3> & hesse) const +{ + hesse = 0; +} + +double Plane :: HesseNorm () const +{ + return 0; +} + + +Point<3> Plane :: GetSurfacePoint () const +{ + return p; +} + + +void Plane :: GetTriangleApproximation +(TriangleApproximation & tas, + const Box<3> & boundingbox, double facets) const +{ + // find triangle, such that + // boundingbox /cap plane is contained in it + + Point<3> c = boundingbox.Center(); + double r = boundingbox.Diam(); + + Project (c); + Vec<3> t1 = n.GetNormal(); + Vec<3> t2 = Cross (n, t1); + + t1.Normalize(); + t2.Normalize(); + + tas.AddPoint (c + (-0.5 * r) * t2 + (sqrt(0.75) * r) * t1); + tas.AddPoint (c + (-0.5 * r) * t2 + (-sqrt(0.75) * r) * t1); + tas.AddPoint (c + r * t2); + + tas.AddTriangle (TATriangle (0, 0, 1, 2)); +} + + + + +Sphere :: Sphere (const Point<3> & ac, double ar) +{ + c = ac; + r = ar; + + cxx = cyy = czz = 0.5 / r; + cxy = cxz = cyz = 0; + cx = - c(0) / r; + cy = - c(1) / r; + cz = - c(2) / r; + c1 = (c(0) * c(0) + c(1) * c(1) + c(2) * c(2)) / (2 * r) - r / 2; +} + +void Sphere :: GetPrimitiveData (char *& classname, ARRAY<double> & coeffs) const +{ + classname = "sphere"; + coeffs.SetSize (4); + coeffs.Elem(1) = c(0); + coeffs.Elem(2) = c(1); + coeffs.Elem(3) = c(2); + coeffs.Elem(4) = r; +} + +void Sphere :: SetPrimitiveData (ARRAY<double> & coeffs) +{ + c(0) = coeffs.Elem(1); + c(1) = coeffs.Elem(2); + c(2) = coeffs.Elem(3); + r = coeffs.Elem(4); + + cxx = cyy = czz = 0.5 / r; + cxy = cxz = cyz = 0; + cx = - c(0) / r; + cy = - c(1) / r; + cz = - c(2) / r; + c1 = (c(0) * c(0) + c(1) * c(1) + c(2) * c(2)) / (2 * r) - r / 2; +} + +Primitive * Sphere :: CreateDefault () +{ + return new Sphere (Point<3> (0,0,0), 1); +} + + + +Primitive * Sphere :: Copy () const +{ + return new Sphere (c, r); +} + +void Sphere :: Transform (Transformation<3> & trans) +{ + Point<3> hp; + trans.Transform (c, hp); + c = hp; + + cxx = cyy = czz = 0.5 / r; + cxy = cxz = cyz = 0; + cx = - c(0) / r; + cy = - c(1) / r; + cz = - c(2) / r; + c1 = (c(0) * c(0) + c(1) * c(1) + c(2) * c(2)) / (2 * r) - r / 2; +} + + + + +int Sphere :: IsIdentic (const Surface & s2, int & inv, double eps) const +{ + const Sphere * sp2 = dynamic_cast<const Sphere*> (&s2); + + if (!sp2) return 0; + + if (Dist (sp2->c, c) > eps) return 0; + if (fabs (sp2->r - r) > eps) return 0; + + inv = 0; + + return 1; +} + + +void Sphere :: DefineTangentialPlane (const Point<3> & ap1, const Point<3> & ap2) +{ + Surface::DefineTangentialPlane (ap1, ap2); + + ez = p1 - c; + ez /= ez.Length(); + + ex = p2 - p1; + ex -= (ex * ez) * ez; + ex /= ex.Length(); + + ey = Cross (ez, ex); +} + + +void Sphere :: ToPlane (const Point<3> & p, Point<2> & pplane, double h, int & zone) const +{ + Vec<3> p1p; + + p1p = p - p1; + + /* + if (p1p * ez < -r) + { + zone = -1; + pplane = Point<2> (1E8, 1E8); + } + else + { + zone = 0; + p1p /= h; + pplane(0) = p1p * ex; + pplane(1) = p1p * ey; + } + */ + + Point<3> p1top = c + (c - p1); + + Vec<3> p1topp = p - p1top; + Vec<3> p1topp1 = p1 - p1top; + Vec<3> lam; + // SolveLinearSystem (ex, ey, p1topp, p1topp1, lam); + + Mat<3> m; + for (int i = 0; i < 3; i++) + { + m(i, 0) = ex(i); + m(i, 1) = ey(i); + m(i, 2) = p1topp(i); + } + m.Solve (p1topp1, lam); + + pplane(0) = -lam(0) / h; + pplane(1) = -lam(1) / h; + + if (lam(2) > 2) + zone = -1; + else + zone = 0; +} + +void Sphere :: FromPlane (const Point<2> & pplane, Point<3> & p, double h) const +{ + /* + // Vec<3> p1p; + double z; + Point<2> pplane2 (pplane); + + pplane2(0) *= h; + pplane2(1) *= h; + z = -r + sqrt (sqr (r) - sqr (pplane2(0)) - sqr (pplane2(1))); + // p = p1; + p(0) = p1(0) + pplane2(0) * ex(0) + pplane2(1) * ey(0) + z * ez(0); + p(1) = p1(1) + pplane2(0) * ex(1) + pplane2(1) * ey(1) + z * ez(1); + p(2) = p1(2) + pplane2(0) * ex(2) + pplane2(1) * ey(2) + z * ez(2); + */ + + Point<2> pplane2 (pplane); + + pplane2(0) *= h; + pplane2(1) *= h; + + p(0) = p1(0) + pplane2(0) * ex(0) + pplane2(1) * ey(0); + p(1) = p1(1) + pplane2(0) * ex(1) + pplane2(1) * ey(1); + p(2) = p1(2) + pplane2(0) * ex(2) + pplane2(1) * ey(2); + Project (p); +} + + +void Sphere :: Project (Point<3> & p) const +{ + Vec<3> v; + v = p - c; + v *= (r / v.Length()); + p = c + v; +} + + +INSOLID_TYPE Sphere :: BoxInSolid (const BoxSphere<3> & box) const +{ + double dist; + dist = Dist (box.Center(), c); + + if (dist - box.Diam()/2 > r) return IS_OUTSIDE; + if (dist + box.Diam()/2 < r) return IS_INSIDE; + return DOES_INTERSECT; +} + +double Sphere :: HesseNorm () const +{ + return 2 / r; +} + + +Point<3> Sphere :: GetSurfacePoint () const +{ + return c + Vec<3> (r, 0, 0); +} + + +void Sphere :: GetTriangleApproximation +(TriangleApproximation & tas, + const Box<3> & boundingbox, double facets) const +{ + int i, j; + double lg, bg; + int n = int(facets) + 1; + + for (j = 0; j <= n; j++) + for (i = 0; i <= n; i++) + { + lg = 2 * M_PI * double (i) / n; + bg = M_PI * (double(j) / n - 0.5); + + Point<3> p(c(0) + r * cos(bg) * sin (lg), + c(1) + r * cos(bg) * cos (lg), + c(2) + r * sin(bg)); + tas.AddPoint (p); + } + + for (j = 0; j < n; j++) + for (i = 0; i < n; i++) + { + int pi = i + (n+1) * j; + tas.AddTriangle (TATriangle (0, pi, pi+1, pi+n+2)); + tas.AddTriangle (TATriangle (0, pi, pi+n+2, pi+n+1)); + } +} + + + + + +Ellipsoid :: +Ellipsoid (const Point<3> & aa, + const Vec<3> & av1, const Vec<3> & av2, const Vec<3> & av3) +{ + a = aa; + v1 = av1; + v2 = av2; + v3 = av3; + + CalcData(); +} + + +void Ellipsoid :: CalcData () +{ + // f = (x-a, vl)^2 / |vl|^2 + (x-a, vs)^2 / |vs|^2 -1 + // f = sum_{i=1}^3 (x-a,v_i)^2 / |vi|^4 - 1 = sum (x-a,hv_i)^2 + + Vec<3> hv1, hv2, hv3; + double lv1 = v1.Length2 (); + if (lv1 < 1e-32) lv1 = 1; + double lv2 = v2.Length2 (); + if (lv2 < 1e-32) lv2 = 1; + double lv3 = v3.Length2 (); + if (lv3 < 1e-32) lv3 = 1; + + rmin = sqrt (min3 (lv1, lv2, lv3)); + + hv1 = (1.0 / lv1) * v1; + hv2 = (1.0 / lv2) * v2; + hv3 = (1.0 / lv3) * v3; + + cxx = hv1(0) * hv1(0) + hv2(0) * hv2(0) + hv3(0) * hv3(0); + cyy = hv1(1) * hv1(1) + hv2(1) * hv2(1) + hv3(1) * hv3(1); + czz = hv1(2) * hv1(2) + hv2(2) * hv2(2) + hv3(2) * hv3(2); + + cxy = 2 * (hv1(0) * hv1(1) + hv2(0) * hv2(1) + hv3(0) * hv3(1)); + cxz = 2 * (hv1(0) * hv1(2) + hv2(0) * hv2(2) + hv3(0) * hv3(2)); + cyz = 2 * (hv1(1) * hv1(2) + hv2(1) * hv2(2) + hv3(1) * hv3(2)); + + Vec<3> va (a); + c1 = sqr(va * hv1) + sqr(va * hv2) + sqr(va * hv3) - 1; + + Vec<3> v = -2 * (va * hv1) * hv1 - 2 * (va * hv2) * hv2 - 2 * (va * hv3) * hv3; + cx = v(0); + cy = v(1); + cz = v(2); +} + + +INSOLID_TYPE Ellipsoid :: BoxInSolid (const BoxSphere<3> & box) const +{ + // double grad = 2.0 / rmin; + // double grad = 3*(box.Center()-a).Length() / (rmin*rmin*rmin); + + double ggrad = 1.0 / (rmin*rmin); + Vec<3> g; + double val = CalcFunctionValue (box.Center()); + CalcGradient (box.Center(), g); + double grad = g.Length(); + + double r = box.Diam() / 2; + double maxval = grad * r + ggrad * r * r; + + // (*testout) << "box = " << box << ", val = " << val << ", maxval = " << maxval << endl; + + if (val > maxval) return IS_OUTSIDE; + if (val < -maxval) return IS_INSIDE; + return DOES_INTERSECT; +} + + +double Ellipsoid :: HesseNorm () const +{ + return 1.0/ (rmin * rmin); +} + +Point<3> Ellipsoid :: GetSurfacePoint () const +{ + return a + v1; +} + + + +void Ellipsoid :: GetTriangleApproximation +(TriangleApproximation & tas, + const Box<3> & boundingbox, double facets) const +{ + int i, j; + double lg, bg; + int n = int(facets) + 1; + + for (j = 0; j <= n; j++) + for (i = 0; i <= n; i++) + { + lg = 2 * M_PI * double (i) / n; + bg = M_PI * (double(j) / n - 0.5); + + + Point<3> p(a + + sin (bg) * v1 + + cos (bg) * sin (lg) * v2 + + cos (bg) * cos (lg) * v3); + + tas.AddPoint (p); + } + + for (j = 0; j < n; j++) + for (i = 0; i < n; i++) + { + int pi = i + (n+1) * j; + tas.AddTriangle (TATriangle (0, pi, pi+1, pi+n+2)); + tas.AddTriangle (TATriangle (0, pi, pi+n+2, pi+n+1)); + } +} + + + + + + + + + + + + + + + + + + + + +Cylinder :: Cylinder (const Point<3> & aa, const Point<3> & ab, double ar) +{ + a = aa; + b = ab; + vab = (b - a); + vab /= vab.Length(); + r = ar; + + // ( <x,x> - 2 <x,a> + <a,a> + // - <x,vab>^2 + 2 <x,vab> <a, vab> - <a, vab>^2 + // - r^2) / (2r) = 0 + + double hv; + cxx = cyy = czz = 0.5 / r; + cxy = cxz = cyz = 0; + cx = - a(0) / r; + cy = - a(1) / r; + cz = - a(2) / r; + c1 = (a(0) * a(0) + a(1) * a(1) + a(2) * a(2)) / (2 * r); + hv = a(0) * vab(0) + a(1) * vab(1) + a(2) * vab(2); + cxx -= vab(0) * vab(0) / (2 * r); + cyy -= vab(1) * vab(1) / (2 * r); + czz -= vab(2) * vab(2) / (2 * r); + cxy -= vab(0) * vab(1) / r; + cxz -= vab(0) * vab(2) / r; + cyz -= vab(1) * vab(2) / r; + cx += vab(0) * hv / r; + cy += vab(1) * hv / r; + cz += vab(2) * hv / r; + c1 -= hv * hv / (2 * r); + c1 -= r / 2; + // PrintCoeff (); +} + + + +void Cylinder :: GetPrimitiveData (char *& classname, ARRAY<double> & coeffs) const +{ + classname = "cylinder"; + coeffs.SetSize (7); + coeffs.Elem(1) = a(0); + coeffs.Elem(2) = a(1); + coeffs.Elem(3) = a(2); + coeffs.Elem(4) = b(0); + coeffs.Elem(5) = b(1); + coeffs.Elem(6) = b(2); + coeffs.Elem(7) = r; +} + +void Cylinder :: SetPrimitiveData (ARRAY<double> & coeffs) +{ + a(0) = coeffs.Elem(1); + a(1) = coeffs.Elem(2); + a(2) = coeffs.Elem(3); + b(0) = coeffs.Elem(4); + b(1) = coeffs.Elem(5); + b(2) = coeffs.Elem(6); + r = coeffs.Elem(7); + + + vab = (b - a); + vab /= vab.Length(); + + + double hv; + cxx = cyy = czz = 0.5 / r; + cxy = cxz = cyz = 0; + cx = - a(0) / r; + cy = - a(1) / r; + cz = - a(2) / r; + c1 = (a(0) * a(0) + a(1) * a(1) + a(2) * a(2)) / (2 * r); + hv = a(0) * vab(0) + a(1) * vab(1) + a(2) * vab(2); + cxx -= vab(0) * vab(0) / (2 * r); + cyy -= vab(1) * vab(1) / (2 * r); + czz -= vab(2) * vab(2) / (2 * r); + cxy -= vab(0) * vab(1) / r; + cxz -= vab(0) * vab(2) / r; + cyz -= vab(1) * vab(2) / r; + cx += vab(0) * hv / r; + cy += vab(1) * hv / r; + cz += vab(2) * hv / r; + c1 -= hv * hv / (2 * r); + c1 -= r / 2; +} + +Primitive * Cylinder :: CreateDefault () +{ + return new Cylinder (Point<3> (0,0,0), Point<3> (1,0,0), 1); +} + + + + +Primitive * Cylinder :: Copy () const +{ + return new Cylinder (a, b, r); +} + + +int Cylinder :: IsIdentic (const Surface & s2, int & inv, double eps) const +{ + const Cylinder * cyl2 = dynamic_cast<const Cylinder*> (&s2); + + if (!cyl2) return 0; + + if (fabs (cyl2->r - r) > eps) return 0; + + Vec<3> v1 = b - a; + Vec<3> v2 = cyl2->a - a; + + if ( fabs (v1 * v2) < (1-eps) * v1.Length() * v2.Length()) return 0; + v2 = cyl2->b - a; + if ( fabs (v1 * v2) < (1-eps) * v1.Length() * v2.Length()) return 0; + + inv = 0; + return 1; +} + + + +void Cylinder :: Transform (Transformation<3> & trans) +{ + Point<3> hp; + trans.Transform (a, hp); + a = hp; + trans.Transform (b, hp); + b = hp; + + vab = (b - a); + vab /= vab.Length(); + + // ( <x,x> - 2 <x,a> + <a,a> + // - <x,vab>^2 + 2 <x,vab> <a, vab> - <a, vab>^2 + // - r^2) / (2r) = 0 + + double hv; + cxx = cyy = czz = 0.5 / r; + cxy = cxz = cyz = 0; + cx = - a(0) / r; + cy = - a(1) / r; + cz = - a(2) / r; + c1 = (a(0) * a(0) + a(1) * a(1) + a(2) * a(2)) / (2 * r); + hv = a(0) * vab(0) + a(1) * vab(1) + a(2) * vab(2); + cxx -= vab(0) * vab(0) / (2 * r); + cyy -= vab(1) * vab(1) / (2 * r); + czz -= vab(2) * vab(2) / (2 * r); + cxy -= vab(0) * vab(1) / r; + cxz -= vab(0) * vab(2) / r; + cyz -= vab(1) * vab(2) / r; + cx += vab(0) * hv / r; + cy += vab(1) * hv / r; + cz += vab(2) * hv / r; + c1 -= hv * hv / (2 * r); + c1 -= r / 2; + // PrintCoeff (); +} + + + + + + + + + +void Cylinder :: DefineTangentialPlane (const Point<3> & ap1, const Point<3> & ap2) +{ + Surface::DefineTangentialPlane (ap1, ap2); + + ez = Center (p1, p2) - a; + ez -= (ez * vab) * vab; + ez /= ez.Length(); + + ex = p2 - p1; + ex -= (ex * ez) * ez; + ex /= ex.Length(); + + ey = Cross (ez, ex); +} + + +void Cylinder :: ToPlane (const Point<3> & p, + Point<2> & pplane, + double h, int & zone) const +{ + Point<3> cp1p2 = Center (p1, p2); + Project (cp1p2); + + Point<3> ccp1p2 = a + ( (cp1p2 - a) * vab ) * vab; + + Vec<3> er = cp1p2 - ccp1p2; + er.Normalize(); + Vec<3> ephi = Cross (vab, er); + + double co, si; + Point<2> p1p, p2p, pp; + + co = er * (p1 - ccp1p2); + si = ephi * (p1 - ccp1p2); + p1p(0) = r * atan2 (si, co); + p1p(1) = vab * (p1 - ccp1p2); + + co = er * (p2 - ccp1p2); + si = ephi * (p2 - ccp1p2); + p2p(0) = r * atan2 (si, co); + p2p(1) = vab * (p2 - ccp1p2); + + co = er * (p - ccp1p2); + si = ephi * (p - ccp1p2); + + double phi = atan2 (si, co); + pp(0) = r * phi; + pp(1) = vab * (p - ccp1p2); + + zone = 0; + if (phi > 1.57) zone = 1; + if (phi < -1.57) zone = 2; + + + + Vec<2> e2x = p2p - p1p; + e2x /= e2x.Length(); + + Vec<2> e2y (-e2x(1), e2x(0)); + + Vec<2> p1pp = pp - p1p; + + + pplane(0) = (p1pp * e2x) / h; + pplane(1) = (p1pp * e2y) / h; + + /* + (*testout) << "p1 = " << p1 << ", p2 = " << p2 << endl; + (*testout) << "p = " << p << ", pp = " << pp << ", pplane = " << pplane << endl; + */ + + /* + Vec<3> p1p; + + p1p = p - p1; + + if (p1p * ez < -1 * r) + { + zone = -1; + pplane(0) = 1e8; + pplane(1) = 1e8; + } + else + { + zone = 0; + p1p /= h; + pplane(0) = p1p * ex; + pplane(1) = p1p * ey; + } + */ +} + +void Cylinder :: FromPlane (const Point<2> & pplane, Point<3> & p, double h) const +{ + Point<2> pplane2 (pplane); + + pplane2(0) *= h; + pplane2(1) *= h; + + p(0) = p1(0) + pplane2(0) * ex(0) + pplane2(1) * ey(0); + p(1) = p1(1) + pplane2(0) * ex(1) + pplane2(1) * ey(1); + p(2) = p1(2) + pplane2(0) * ex(2) + pplane2(1) * ey(2); + Project (p); +} + + +void Cylinder :: Project (Point<3> & p) const +{ + Vec<3> v; + Point<3> c; + + c = a + ((p - a) * vab) * vab; + v = p - c; + v *= (r / v.Length()); + p = c + v; +} +/* +int Cylinder :: RootInBox (const BoxSphere<3> & box) const + { + double dist; + dist = sqrt (2 * CalcFunctionValue(box.Center()) * r + r * r); + if (fabs (dist - r) > box.Diam()/2) return 0; + return 2; + } +*/ + +INSOLID_TYPE Cylinder :: BoxInSolid (const BoxSphere<3> & box) const +{ + double dist; + // dist = sqrt (2 * CalcFunctionValue(box.Center()) * r + r * r); + + dist = (2 * CalcFunctionValue(box.Center()) * r + r * r); + if (dist <= 0) dist = 0; + else dist = sqrt (dist + 1e-16); + + if (dist - box.Diam()/2 > r) return IS_OUTSIDE; + if (dist + box.Diam()/2 < r) return IS_INSIDE; + return DOES_INTERSECT; +} + + +double Cylinder :: HesseNorm () const +{ + return 2 / r; +} + +Point<3> Cylinder :: GetSurfacePoint () const +{ + Vec<3> vr; + if (fabs (vab(0)) > fabs(vab(2))) + vr = Vec<3> (vab(1), -vab(0), 0); + else + vr = Vec<3> (0, -vab(2), vab(1)); + + vr *= (r / vr.Length()); + return a + vr; +} + +void Cylinder :: GetTriangleApproximation +(TriangleApproximation & tas, + const Box<3> & boundingbox, double facets) const +{ + int i, j; + double lg, bg; + int n = int(facets) + 1; + + Vec<3> lvab = b - a; + Vec<3> n1 = lvab.GetNormal(); + Vec<3> n2 = Cross (lvab, n1); + + n1.Normalize(); + n2.Normalize(); + + + for (j = 0; j <= n; j++) + for (i = 0; i <= n; i++) + { + lg = 2 * M_PI * double (i) / n; + bg = double(j) / n; + + Point<3> p = a + (bg * lvab) + + ((r * cos(lg)) * n1) + + ((r * sin(lg)) * n2); + + tas.AddPoint (p); + } + + for (j = 0; j < n; j++) + for (i = 0; i < n; i++) + { + int pi = i + (n+1) * j; + tas.AddTriangle (TATriangle (0, pi, pi+1, pi+n+2)); + tas.AddTriangle (TATriangle (0, pi, pi+n+2, pi+n+1)); + } +} + + + + + + + + + +EllipticCylinder :: +EllipticCylinder (const Point<3> & aa, + const Vec<3> & avl, const Vec<3> & avs) +{ + a = aa; + vl = avl; + vs = avs; + + CalcData(); + Print (cout); +} + + +void EllipticCylinder :: CalcData () +{ + // f = (x-a, vl)^2 / |vl|^2 + (x-a, vs)^2 / |vs|^2 -1 + + Vec<3> hvl, hvs; + double lvl = vl.Length2 (); + if (lvl < 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 = va * hvl + va * hvs - 1; + + Vec<3> v = -2 * (va * hvl) * hvl - 2 * (va * hvs) * hvs; + cx = v(0); + cy = v(1); + cz = v(2); +} + + +INSOLID_TYPE EllipticCylinder :: BoxInSolid (const BoxSphere<3> & box) const +{ + double grad = 2.0 / vs.Length (); + double ggrad = 1.0 / vs.Length2 (); + + double val = CalcFunctionValue (box.Center()); + double r = box.Diam() / 2; + double maxval = grad * r + ggrad * r * r; + + // (*testout) << "box = " << box << ", val = " << val << ", maxval = " << maxval << endl; + + if (val > maxval) return IS_OUTSIDE; + if (val < -maxval) return IS_INSIDE; + return DOES_INTERSECT; +} + + +double EllipticCylinder :: HesseNorm () const +{ + return 1.0/vs.Length2 (); +} + +Point<3> EllipticCylinder :: GetSurfacePoint () const +{ + return a + vl; +} + + + +void EllipticCylinder :: GetTriangleApproximation +(TriangleApproximation & tas, + const Box<3> & boundingbox, double facets) const +{ + int i, j; + double lg, bg; + int n = int(facets) + 1; + + Vec<3> axis = Cross (vl, vs); + + for (j = 0; j <= n; j++) + for (i = 0; i <= n; i++) + { + lg = 2 * M_PI * double (i) / n; + bg = double(j) / n; + + Point<3> p = a + (bg * axis) + + cos(lg) * vl + sin(lg) * vs; + + tas.AddPoint (p); + } + + for (j = 0; j < n; j++) + for (i = 0; i < n; i++) + { + int pi = i + (n+1) * j; + tas.AddTriangle (TATriangle (0, pi, pi+1, pi+n+2)); + tas.AddTriangle (TATriangle (0, pi, pi+n+2, pi+n+1)); + } +} + + + + + + + + + + +Cone :: Cone (const Point<3> & aa, const Point<3> & ab, + double ara, double arb) +{ + a = aa; + b = ab; + ra = ara; + rb = arb; + + CalcData(); + Print (cout); +} + + +Primitive * Cone :: CreateDefault () +{ + return new Cone (Point<3> (0,0,0), Point<3> (1,0,0), 0.5, 0.2); +} + + + + +void Cone :: GetPrimitiveData (char *& classname, ARRAY<double> & coeffs) const +{ + classname = "cone"; + coeffs.SetSize (8); + coeffs.Elem(1) = a(0); + coeffs.Elem(2) = a(1); + coeffs.Elem(3) = a(2); + coeffs.Elem(4) = b(0); + coeffs.Elem(5) = b(1); + coeffs.Elem(6) = b(2); + coeffs.Elem(7) = ra; + coeffs.Elem(8) = rb; +} + +void Cone :: SetPrimitiveData (ARRAY<double> & coeffs) +{ + a(0) = coeffs.Elem(1); + a(1) = coeffs.Elem(2); + a(2) = coeffs.Elem(3); + b(0) = coeffs.Elem(4); + b(1) = coeffs.Elem(5); + b(2) = coeffs.Elem(6); + ra = coeffs.Elem(7); + rb = coeffs.Elem(8); + + CalcData(); +} + +void Cone :: CalcData () +{ + + minr = (ra < rb) ? ra : rb; + + vab = b - a; + vabl = vab.Length(); + + Vec<3> va (a); + + // + // f = r(P)^2 - R(z(P))^2 + // + // z(P) = t0vec * P + t0 = (P-a, b-a)/(b-a,b-a) + // R(z(P)) = t1vec * P + t1 = rb * z + ra * (1-z) + // r(P)^2 =||P-a||^2 - ||a-b||^2 z^2k + + + t0vec = vab; + t0vec /= (vabl * vabl); + t0 = -(va * vab) / (vabl * vabl); + + t1vec = t0vec; + t1vec *= (rb - ra); + t1 = ra + (rb - ra) * t0; + + cxx = cyy = czz = 1; + cxy = cxz = cyz = 0; + + cxx = 1 - (vab*vab) * t0vec(0) * t0vec(0) - t1vec(0) * t1vec(0); + cyy = 1 - (vab*vab) * t0vec(1) * t0vec(1) - t1vec(1) * t1vec(1); + czz = 1 - (vab*vab) * t0vec(2) * t0vec(2) - t1vec(2) * t1vec(2); + + cxy = -2 * (vab * vab) * t0vec(0) * t0vec(1) - 2 * t1vec(0) * t1vec(1); + cxz = -2 * (vab * vab) * t0vec(0) * t0vec(2) - 2 * t1vec(0) * t1vec(2); + cyz = -2 * (vab * vab) * t0vec(1) * t0vec(2) - 2 * t1vec(1) * t1vec(2); + + cx = -2 * a(0) - 2 * (vab * vab) * t0 * t0vec(0) - 2 * t1 * t1vec(0); + cy = -2 * a(1) - 2 * (vab * vab) * t0 * t0vec(1) - 2 * t1 * t1vec(1); + cz = -2 * a(2) - 2 * (vab * vab) * t0 * t0vec(2) - 2 * t1 * t1vec(2); + + c1 = va.Length2() - (vab * vab) * t0 * t0 - t1 * t1; + + // (*testout) << "t0vec = " << t0vec << " t0 = " << t0 << endl; + // (*testout) << "t1vec = " << t1vec << " t1 = " << t1 << endl; + // PrintCoeff (*testout); +} + + +INSOLID_TYPE Cone :: BoxInSolid (const BoxSphere<3> & box) const +{ + double rp, dist; + + Vec<3> cv(box.Center()); + + rp = cv * t1vec + t1; + dist = sqrt (CalcFunctionValue(box.Center()) + rp * rp) - rp; + + if (dist - box.Diam() > 0) return IS_OUTSIDE; + if (dist + box.Diam() < 0) return IS_INSIDE; + return DOES_INTERSECT; +} + + +double Cone :: HesseNorm () const +{ + return 2 / minr; +} + + +double Cone :: LocH (const Point<3> & p, double x, + double c, double hmax) const +{ + double bloch = Surface::LocH (p, x, c, hmax); + Vec<3> g; + CalcGradient (p, g); + + double lam = Abs(g); + double meancurv = + -( 2 * g(0)*g(1)*cxy - 2 * czz * (g(0)*g(0)+g(1)*g(1)) + +2 * g(1)*g(2)*cyz - 2 * cxx * (g(1)*g(1)+g(2)*g(2)) + +2 * g(0)*g(2)*cxz - 2 * cyy * (g(0)*g(0)+g(2)*g(2))) / (3*lam*lam*lam); + + // cout << "type = " << typeid(*this).name() << ", baseh = " << bloch << ", meancurv = " << meancurv << endl; + // return bloch; + + meancurv = fabs (meancurv); + if (meancurv < 1e-20) meancurv = 1e-20; + + // cout << "c = " << c << ", safety = " << mparam.curvaturesafety << endl; + double hcurv = 1.0/(3*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)); + } +} +} diff --git a/contrib/Netgen/libsrc/csg/algprim.hpp b/contrib/Netgen/libsrc/csg/algprim.hpp new file mode 100644 index 0000000000..aeb829f9c1 --- /dev/null +++ b/contrib/Netgen/libsrc/csg/algprim.hpp @@ -0,0 +1,338 @@ +#ifndef FILE_ALGPRIM +#define FILE_ALGPRIM + + +/**************************************************************************/ +/* File: algprim.hh */ +/* Author: Joachim Schoeberl */ +/* Date: 1. Dez. 95 */ +/**************************************************************************/ + +/* + +Quadric Surfaces (Plane, Sphere, Cylinder) + +*/ + + +/** + A quadric surface. + surface defined by + cxx x^2 + cyy y^2 + czz z^2 + cxy x y + cxz x z + cyz y z + + cx x + cy y + cz z + c1 = 0. + **/ +class QuadraticSurface : public OneSurfacePrimitive +{ +protected: + double cxx, cyy, czz, cxy, cxz, cyz, cx, cy, cz, c1; + +public: + + virtual double CalcFunctionValue (const Point<3> & point) const; + virtual void CalcGradient (const Point<3> & point, Vec<3> & grad) const; + virtual void CalcHesse (const Point<3> & point, Mat<3> & hesse) const; + /* + virtual int RootInBox (const Box<3> & box) + const { return 0; } + virtual INSOLID_TYPE BoxInSolid (const BoxSphere<3> & box) + const { return DOES_INTERSECT; } +*/ + virtual double HesseNorm () const { return cxx + cyy + czz; } + + virtual Point<3> GetSurfacePoint () const; + + + virtual void Print (ostream & ist) const; + virtual void Read (istream & ist); + void PrintCoeff (ostream & ost) const; +}; + + +/// A Plane (i.e., the plane and everything behind it). +class Plane : public QuadraticSurface +{ + /// a point in the plane + Point<3> p; + /// outward normal vector + Vec<3> n; +public: + /// + Plane (const Point<3> & ap, Vec<3> an); + + virtual void GetPrimitiveData (char *& classname, + ARRAY<double> & coeffs) const; + virtual void SetPrimitiveData (ARRAY<double> & coeffs); + static Primitive * CreateDefault (); + + virtual Primitive * Copy () const; + virtual void Transform (Transformation<3> & trans); + + + virtual int IsIdentic (const Surface & s2, int & inv, double eps) const; + + /// + virtual void DefineTangentialPlane (const Point<3> & ap1, + const Point<3> & ap2); + /// + virtual void ToPlane (const Point<3> & p3d, + Point<2> & pplane, double h, + int & zone) const; + /// + virtual void FromPlane (const Point<2> & pplane, + Point<3> & p3d, + double h) const; + /// + virtual void Project (Point<3> & p) const; + + /// + virtual INSOLID_TYPE BoxInSolid (const BoxSphere<3> & box) const; + + /// + 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; + +}; + +// typedef Plane Plane; + + +/// +class Sphere : public QuadraticSurface +{ + /// + Point<3> c; + /// + double r; +public: + /// + Sphere (const Point<3> & ac, double ar); + + virtual void GetPrimitiveData (char *& classname, + ARRAY<double> & coeffs) const; + virtual void SetPrimitiveData (ARRAY<double> & coeffs); + static Primitive * CreateDefault (); + + virtual Primitive * Copy () const; + virtual void Transform (Transformation<3> & trans); + + + virtual int IsIdentic (const Surface & s2, int & inv, double eps) const; + + /// + virtual void DefineTangentialPlane (const Point<3> & ap1, + const Point<3> & ap2); + /// + virtual void ToPlane (const Point<3> & p3d, + Point<2> & pplane, double h, + int & zone) const; + /// + virtual void FromPlane (const Point<2> & pplane, + Point<3> & p, double h) const; + /// + virtual void Project (Point<3> & p) const; + + /// + virtual INSOLID_TYPE BoxInSolid (const BoxSphere<3> & box) const; + /// + virtual double HesseNorm () const; + /// + virtual Point<3> GetSurfacePoint () const; + /// + const Point<3> & Center () const { return c; } + /// + double Radius () const { return r; } + + /// + virtual void GetTriangleApproximation (TriangleApproximation & tas, + const Box<3> & bbox, + double facets) const; +}; + + +/// +class Cylinder : public QuadraticSurface +{ + /// + Point<3> a, b; + /// + double r; + /// + Vec<3> vab; + +public: + Cylinder (const Point<3> & aa, const Point<3> & ab, double ar); + + virtual void GetPrimitiveData (char *& classname, ARRAY<double> & coeffs) const; + virtual void SetPrimitiveData (ARRAY<double> & coeffs); + static Primitive * CreateDefault (); + + virtual Primitive * Copy () const; + virtual void Transform (Transformation<3> & trans); + + /// + virtual int IsIdentic (const Surface & s2, int & inv, double eps) const; + /// + virtual void DefineTangentialPlane (const Point<3> & ap1, + const Point<3> & ap2); + /// + virtual void ToPlane (const Point<3> & p, + Point<2> & pplane, + double h, + int & zone) const; + /// + virtual void FromPlane (const Point<2> & pplane, + Point<3> & p, + double h) const; + /// + virtual void Project (Point<3> & p) const; + + /// + virtual INSOLID_TYPE BoxInSolid (const BoxSphere<3> & box) const; + /// + virtual double HesseNorm () const; + /// + virtual Point<3> GetSurfacePoint () const; + /// + virtual void GetTriangleApproximation (TriangleApproximation & tas, + const Box<3> & bbox, + double facets) const; +}; + + + + + +/// +class EllipticCylinder : public QuadraticSurface +{ +private: + /// + Point<3> a; + /// + Vec<3> vl, vs; + /// + Vec<3> vab, t0vec, t1vec; + /// + double vabl, t0, t1; +public: + /// + EllipticCylinder (const Point<3> & aa, + const Vec<3> & avl, const Vec<3> & avs); + + /* + static Primitive * CreateDefault (); + virtual void GetPrimitiveData (char *& classname, ARRAY<double> & coeffs) const; + virtual void SetPrimitiveData (ARRAY<double> & coeffs); + */ + /// + virtual INSOLID_TYPE BoxInSolid (const BoxSphere<3> & box) const; + /// + virtual double HesseNorm () const; + /// + virtual Point<3> GetSurfacePoint () const; + + virtual void GetTriangleApproximation (TriangleApproximation & tas, + const Box<3> & bbox, + double facets) const; + +private: + void CalcData(); +}; + + + + + + +/// +class Ellipsoid : public QuadraticSurface +{ +private: + /// + Point<3> a; + /// + Vec<3> v1, v2, v3; + /// + double rmin; +public: + /// + Ellipsoid (const Point<3> & aa, + const Vec<3> & av1, + const Vec<3> & av2, + const Vec<3> & av3); + /// + virtual INSOLID_TYPE BoxInSolid (const BoxSphere<3> & box) const; + /// + virtual double HesseNorm () const; + /// + virtual Point<3> GetSurfacePoint () const; + + virtual void GetTriangleApproximation (TriangleApproximation & tas, + const Box<3> & bbox, + double facets) const; + +private: + void CalcData(); +}; + + + + + + + + +/// +class Cone : public QuadraticSurface +{ + /// + Point<3> a, b; + /// + double ra, rb, minr; + /// + Vec<3> vab, t0vec, t1vec; + /// + double vabl, t0, t1; +public: + /// + Cone (const Point<3> & aa, const Point<3> & ab, double ara, double arb); + /// + static Primitive * CreateDefault (); + virtual void GetPrimitiveData (char *& classname, ARRAY<double> & coeffs) const; + virtual void SetPrimitiveData (ARRAY<double> & coeffs); + + /// + virtual INSOLID_TYPE BoxInSolid (const BoxSphere<3> & box) const; + /// + virtual double HesseNorm () const; + + virtual double LocH (const Point<3> & p, double x, + double c, double hmax) const; + + /// + virtual Point<3> GetSurfacePoint () const; + + virtual void GetTriangleApproximation (TriangleApproximation & tas, + const Box<3> & bbox, + double facets) const; + +private: + void CalcData(); +}; + + +#endif diff --git a/contrib/Netgen/libsrc/csg/brick.cpp b/contrib/Netgen/libsrc/csg/brick.cpp new file mode 100644 index 0000000000..f408e922f4 --- /dev/null +++ b/contrib/Netgen/libsrc/csg/brick.cpp @@ -0,0 +1,409 @@ +#include <mystdlib.h> + +#include <linalg.hpp> +#include <csg.hpp> + +namespace netgen +{ + +Parallelogram3d :: Parallelogram3d (Point<3> ap1, Point<3> ap2, Point<3> ap3) +{ + p1 = ap1; + p2 = ap2; + p3 = ap3; + + CalcData(); +} + +Parallelogram3d ::~Parallelogram3d () +{ + ; +} + +void Parallelogram3d :: SetPoints (Point<3> ap1, + Point<3> ap2, + Point<3> ap3) +{ + p1 = ap1; + p2 = ap2; + p3 = ap3; + + CalcData(); +} + +void Parallelogram3d :: CalcData() +{ + v12 = p2 - p1; + v13 = p3 - p1; + p4 = p2 + v13; + + n = Cross (v12, v13); + n.Normalize(); +} + +int Parallelogram3d :: +IsIdentic (const Surface & s2, int & inv, double eps) const +{ + int id = + (fabs (s2.CalcFunctionValue (p1)) <= eps) && + (fabs (s2.CalcFunctionValue (p2)) <= eps) && + (fabs (s2.CalcFunctionValue (p3)) <= eps); + + if (id) + { + Vec<3> n2; + 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)); +} + + +INSOLID_TYPE Brick :: BoxInSolid (const BoxSphere<3> & box) const +{ + /* + int i; + double maxval; + for (i = 1; i <= 6; i++) + { + double val = faces.Get(i)->CalcFunctionValue (box.Center()); + if (i == 1 || val > maxval) + maxval = val; + } + + if (maxval > box.Diam()) return IS_OUTSIDE; + if (maxval < -box.Diam()) return IS_INSIDE; + return DOES_INTERSECT; + */ + + bool inside = 1; + bool outside = 0; + + for (int i = 0; i < 6; i++) + { + bool outsidei = 1; + for (int j = 0; j < 8; j++) + { + Point<3> p = box.GetPointNr (j); + double val = faces[i]->CalcFunctionValue (p); + + if (val > 0) inside = 0; + if (val < 0) outsidei = 0; + } + if (outsidei) outside = 1; + } + + if (outside) return IS_OUTSIDE; + if (inside) return IS_INSIDE; + return DOES_INTERSECT; +} + +INSOLID_TYPE Brick :: PointInSolid (const Point<3> & p, + double eps) const +{ + double maxval = faces[0] -> CalcFunctionValue (p); + for (int i = 1; i < 6; i++) + { + double val = faces[i] -> CalcFunctionValue (p); + if (val > maxval) maxval = val; + } + + if (maxval > eps) return IS_OUTSIDE; + if (maxval < -eps) return IS_INSIDE; + return DOES_INTERSECT; +} + +INSOLID_TYPE Brick :: VecInSolid (const Point<3> & p, + const Vec<3> & v, + double eps) const +{ + INSOLID_TYPE is = IS_INSIDE; + Vec<3> grad; + double scal; + + for (int i = 0; i < faces.Size(); i++) + { + if (faces[i] -> PointOnSurface (p, eps)) + { + GetSurface(i).CalcGradient (p, grad); + scal = v * grad; + + if (scal >= eps) + is = IS_OUTSIDE; + if (scal >= -eps && is == IS_INSIDE) + is = DOES_INTERSECT; + } + } + return is; + /* + Point<3> p2 = p + 1e-2 * v; + return PointInSolid (p2, eps); + */ +} + + +void Brick :: +GetPrimitiveData (char *& classname, ARRAY<double> & coeffs) const +{ + classname = "brick"; + coeffs.SetSize(12); + coeffs.Elem(1) = p1(0); + coeffs.Elem(2) = p1(1); + coeffs.Elem(3) = p1(2); + + coeffs.Elem(4) = p2(0); + coeffs.Elem(5) = p2(1); + coeffs.Elem(6) = p2(2); + + coeffs.Elem(7) = p3(0); + coeffs.Elem(8) = p3(1); + coeffs.Elem(9) = p3(2); + + coeffs.Elem(10) = p4(0); + coeffs.Elem(11) = p4(1); + coeffs.Elem(12) = p4(2); +} + +void Brick :: SetPrimitiveData (ARRAY<double> & coeffs) +{ + p1(0) = coeffs.Elem(1); + p1(1) = coeffs.Elem(2); + p1(2) = coeffs.Elem(3); + + p2(0) = coeffs.Elem(4); + p2(1) = coeffs.Elem(5); + p2(2) = coeffs.Elem(6); + + p3(0) = coeffs.Elem(7); + p3(1) = coeffs.Elem(8); + p3(2) = coeffs.Elem(9); + + p4(0) = coeffs.Elem(10); + p4(1) = coeffs.Elem(11); + p4(2) = coeffs.Elem(12); + + CalcData(); +} + + + +void Brick :: CalcData() +{ + v12 = p2 - p1; + v13 = p3 - p1; + v14 = p4 - p1; + + Point<3> pi[8]; + int i1, i2, i3; + int i, j; + + i = 0; + for (i3 = 0; i3 <= 1; i3++) + for (i2 = 0; i2 <= 1; i2++) + for (i1 = 0; i1 <= 1; i1++) + { + pi[i] = p1 + i1 * v12 + i2 * v13 + i3 * v14; + i++; + } + + static int lface[6][4] = + { { 1, 3, 2, 4 }, + { 5, 6, 7, 8 }, + { 1, 2, 5, 6 }, + { 3, 7, 4, 8 }, + { 1, 5, 3, 7 }, + { 2, 4, 6, 8 } }; + + ARRAY<double> data(6); + for (i = 0; i < 6; i++) + { + const Point<3> p1 = pi[lface[i][0]-1]; + const Point<3> p2 = pi[lface[i][1]-1]; + const Point<3> p3 = pi[lface[i][2]-1]; + + Vec<3> n = Cross ((p2-p1), (p3-p1)); + n.Normalize(); + + for (j = 0; j < 3; j++) + { + data[j] = p1(j); + data[j+3] = n(j); + } + faces[i] -> SetPrimitiveData (data); + /* + { + faces.Elem(i+1) -> SetPoints + (pi[lface[i][0]-1], + pi[lface[i][1]-1], + pi[lface[i][2]-1]); + } + */ + } +} + + +void Brick :: Reduce (const BoxSphere<3> & box) +{ + double val; + Point<3> p; + for (int i = 0; i < 6; i++) + { + bool hasout = 0; + bool hasin = 0; + for (int j = 0; j < 8; j++) + { + p = box.GetPointNr (j); + val = faces[i]->CalcFunctionValue (p); + if (val > 0) hasout = 1; + else if (val < 0) hasin = 1; + } + surfaceactive[i] = hasout && hasin; + } +} + +void Brick :: UnReduce () +{ + for (int i = 0; i < 6; i++) + surfaceactive[i] = 1; +} + + + +OrthoBrick :: OrthoBrick (const Point<3> & ap1, const Point<3> & ap2) + : Brick (ap1, + Point<3> (ap2(0), ap1(1), ap1(2)), + Point<3> (ap1(0), ap2(1), ap1(2)), + Point<3> (ap1(0), ap1(1), ap2(2))) +{ + pmin = ap1; + pmax = ap2; +} + +INSOLID_TYPE OrthoBrick :: BoxInSolid (const BoxSphere<3> & box) const +{ + if (pmin(0) > box.PMax()(0) || + pmin(1) > box.PMax()(1) || + pmin(2) > box.PMax()(2) || + pmax(0) < box.PMin()(0) || + pmax(1) < box.PMin()(1) || + pmax(2) < box.PMin()(2)) + return IS_OUTSIDE; + + if (pmin(0) < box.PMin()(0) && + pmin(1) < box.PMin()(1) && + pmin(2) < box.PMin()(2) && + pmax(0) > box.PMax()(0) && + pmax(1) > box.PMax()(1) && + pmax(2) > box.PMax()(2)) + return IS_INSIDE; + + return DOES_INTERSECT; +} + + +void OrthoBrick :: Reduce (const BoxSphere<3> & box) +{ + surfaceactive.Elem(1) = + (box.PMin()(2) < pmin(2)) && (pmin(2) < box.PMax()(2)); + surfaceactive.Elem(2) = + (box.PMin()(2) < pmax(2)) && (pmax(2) < box.PMax()(2)); + + surfaceactive.Elem(3) = + (box.PMin()(1) < pmin(1)) && (pmin(1) < box.PMax()(1)); + surfaceactive.Elem(4) = + (box.PMin()(1) < pmax(1)) && (pmax(1) < box.PMax()(1)); + + surfaceactive.Elem(5) = + (box.PMin()(0) < pmin(0)) && (pmin(0) < box.PMax()(0)); + surfaceactive.Elem(6) = + (box.PMin()(0) < pmax(0)) && (pmax(0) < box.PMax()(0)); +} +} diff --git a/contrib/Netgen/libsrc/csg/brick.hpp b/contrib/Netgen/libsrc/csg/brick.hpp new file mode 100644 index 0000000000..11106b66d3 --- /dev/null +++ b/contrib/Netgen/libsrc/csg/brick.hpp @@ -0,0 +1,98 @@ +#ifndef FILE_BRICK +#define FILE_BRICK + + +/**************************************************************************/ +/* File: brick.hh */ +/* Author: Joachim Schoeberl */ +/* Date: 11. Mar. 98 */ +/**************************************************************************/ + +/* + + brick geometry, has several surfaces + +*/ + + + +class Parallelogram3d : public Surface +{ + Point<3> p1, p2, p3, p4; + Vec<3> v12, v13; + Vec<3> n; + +public: + Parallelogram3d (Point<3> ap1, Point<3> ap2, Point<3> ap3); + virtual ~Parallelogram3d (); + void SetPoints (Point<3> ap1, Point<3> ap2, Point<3> ap3); + + virtual int IsIdentic (const Surface & s2, int & inv, double eps) const; + + virtual double CalcFunctionValue (const Point<3> & point) const; + virtual void CalcGradient (const Point<3> & point, Vec<3> & grad) const; + virtual void CalcHesse (const Point<3> & point, Mat<3> & hesse) const; + virtual double HesseNorm () const; + + virtual Point<3> GetSurfacePoint () const; + virtual void Print (ostream & str) const; + + virtual void GetTriangleApproximation (TriangleApproximation & tas, + const Box<3> & boundingbox, + double facets) const; + +protected: + void CalcData(); +}; + + +class Brick : public Primitive +{ + Point<3> p1, p2, p3, p4; + Vec<3> v12, v13, v14; + ARRAY<OneSurfacePrimitive*> faces; + +public: + Brick (Point<3> ap1, Point<3> ap2, Point<3> ap3, Point<3> ap4); + virtual ~Brick (); + static Primitive * CreateDefault (); + + + virtual INSOLID_TYPE BoxInSolid (const BoxSphere<3> & box) const; + virtual INSOLID_TYPE PointInSolid (const Point<3> & p, + double eps) const; + virtual INSOLID_TYPE VecInSolid (const Point<3> & p, + const Vec<3> & v, + double eps) const; + + virtual int GetNSurfaces() const + { return 6; } + virtual Surface & GetSurface (int i) + { return *faces[i]; } + virtual const Surface & GetSurface (int i) const + { return *faces[i]; } + + + virtual void GetPrimitiveData (char *& classname, ARRAY<double> & coeffs) const; + virtual void SetPrimitiveData (ARRAY<double> & coeffs); + + virtual void Reduce (const BoxSphere<3> & box); + virtual void UnReduce (); + +protected: + void CalcData(); +}; + + +class OrthoBrick : public Brick +{ +protected: + Point<3> pmin, pmax; +public: + OrthoBrick (const Point<3> & ap1, const Point<3> & ap2); + + virtual INSOLID_TYPE BoxInSolid (const BoxSphere<3> & box) const; + virtual void Reduce (const BoxSphere<3> & box); +}; + +#endif diff --git a/contrib/Netgen/libsrc/csg/bspline2d.cpp b/contrib/Netgen/libsrc/csg/bspline2d.cpp new file mode 100644 index 0000000000..93b5e89621 --- /dev/null +++ b/contrib/Netgen/libsrc/csg/bspline2d.cpp @@ -0,0 +1,242 @@ +#include <mystdlib.h> + +#include <csg.hpp> + +namespace netgen +{ + +BSplineCurve2d :: BSplineCurve2d () +{ + redlevel = 0; +} + + +void BSplineCurve2d :: AddPoint (const Point<2> & apoint) +{ + points.Append (apoint); + intervallused.Append (0); +} + +bool BSplineCurve2d :: Inside (const Point<2> & p, double & dist) const +{ + Point<2> hp = p; + double t = ProjectParam (p); + hp = Eval(t); + Vec<2> v = EvalPrime (t); + + Vec<2> n (v(0), -v(1)); + + cout << "p = " << p << ", hp = " << hp << endl; + dist = Dist (p, hp); + double scal = (hp-p) * n; + cout << "scal = " << scal << endl; + + return scal >= 0; +} + +double BSplineCurve2d :: ProjectParam (const Point<2> & p) const +{ + double t, dt, mindist, mint = 0.0; + int n1; + + mindist = 1e10; + dt = 0.2; + for (n1 = 1; n1 <= points.Size(); n1++) + if (intervallused.Get(n1) == 0) + for (t = n1; t <= n1+1; t += dt) + if (Dist (Eval(t), p) < mindist) + { + mint = t; + mindist = Dist (Eval(t), p); + } + + if (mindist > 1e9) + { + for (t = 0; t <= points.Size(); t += dt) + if (Dist (Eval(t), p) < mindist) + { + mint = t; + mindist = Dist (Eval(t), p); + } + } + + while (Dist (Eval (mint-dt), p) < mindist) + { + mindist = Dist (Eval (mint-dt), p); + mint -= dt; + } + while (Dist (Eval (mint+dt), p) < mindist) + { + mindist = Dist (Eval (mint+dt), p); + mint += dt; + } + + + return NumericalProjectParam (p, mint-dt, mint+dt); +} + + +// t \in (n1, n2) + +Point<2> BSplineCurve2d :: Eval (double t) const +{ + int n, n1, n2, n3, n4; + double loct, b1, b2, b3, b4; + Point<2> hp; + + static int cnt = 0; + cnt++; + if (cnt % 100000 == 0) (*mycout) << "cnt = " << cnt << endl; + + n = int(t); + loct = t - n; + + b1 = 0.25 * (1 - loct) * (1 - loct); + b4 = 0.25 * loct * loct; + b2 = 0.5 - b4; + b3 = 0.5 - b1; + + n1 = (n + 10 * points.Size() -1) % points.Size() + 1; + n2 = n1+1; + if (n2 > points.Size()) n2 = 1; + n3 = n2+1; + if (n3 > points.Size()) n3 = 1; + n4 = n3+1; + if (n4 > points.Size()) n4 = 1; + + // (*mycout) << "t = " << t << " n = " << n << " loct = " << loct + // << " n1 = " << n1 << endl; + + + hp(0) = b1 * points.Get(n1)(0) + b2 * points.Get(n2)(0) + + b3 * points.Get(n3)(0) + b4 * points.Get(n4)(0); + hp(1) = b1 * points.Get(n1)(1) + b2 * points.Get(n2)(1) + + b3 * points.Get(n3)(1) + b4 * points.Get(n4)(1); + return hp; +} + +Vec<2> BSplineCurve2d :: EvalPrime (double t) const +{ + int n, n1, n2, n3, n4; + double loct, db1, db2, db3, db4; + Vec<2> hv; + + n = int(t); + loct = t - n; + + db1 = 0.5 * (loct - 1); + db4 = 0.5 * loct; + db2 = -db4; + db3 = -db1; + + n1 = (n + 10 * points.Size() -1) % points.Size() + 1; + n2 = n1+1; + if (n2 > points.Size()) n2 = 1; + n3 = n2+1; + if (n3 > points.Size()) n3 = 1; + n4 = n3+1; + if (n4 > points.Size()) n4 = 1; + + hv(0) = db1 * points.Get(n1)(0) + db2 * points.Get(n2)(0) + + db3 * points.Get(n3)(0) + db4 * points.Get(n4)(0); + hv(1) = db1 * points.Get(n1)(1) + db2 * points.Get(n2)(1) + + db3 * points.Get(n3)(1) + db4 * points.Get(n4)(1); + return hv; +} + +Vec<2> BSplineCurve2d :: EvalPrimePrime (double t) const +{ + int n, n1, n2, n3, n4; + double ddb1, ddb2, ddb3, ddb4; + Vec<2> hv; + + n = int(t); + // double loct = t - n; + + ddb1 = 0.5; + ddb4 = 0.5; + ddb2 = -0.5; + ddb3 = -0.5; + + n1 = (n + 10 * points.Size() -1) % points.Size() + 1; + n2 = n1+1; + if (n2 > points.Size()) n2 = 1; + n3 = n2+1; + if (n3 > points.Size()) n3 = 1; + n4 = n3+1; + if (n4 > points.Size()) n4 = 1; + + hv(0) = ddb1 * points.Get(n1)(0) + ddb2 * points.Get(n2)(0) + + ddb3 * points.Get(n3)(0) + ddb4 * points.Get(n4)(0); + hv(1) = ddb1 * points.Get(n1)(1) + ddb2 * points.Get(n2)(1) + + ddb3 * points.Get(n3)(1) + ddb4 * points.Get(n4)(1); + return hv; +} + + +int BSplineCurve2d :: SectionUsed (double t) const +{ + int n1 = int(t); + n1 = (n1 + 10 * points.Size() - 1) % points.Size() + 1; + return (intervallused.Get(n1) == 0); +} + +void BSplineCurve2d :: Reduce (const Point<2> & p, double rad) +{ + int n1, n; + int j; + double minx, miny, maxx, maxy; + + // (*testout) << "Reduce: " << p << "," << rad << endl; + + redlevel++; + + for (n1 = 1; n1 <= points.Size(); n1++) + { + if (intervallused.Get(n1) != 0) continue; + + minx = maxx = points.Get(n1)(0); + miny = maxy = points.Get(n1)(1); + + n = n1; + for (j = 1; j <= 3; j++) + { + n++; + if (n > points.Size()) n = 1; + if (points.Get(n)(0) < minx) minx = points.Get(n)(0); + if (points.Get(n)(1) < miny) miny = points.Get(n)(1); + if (points.Get(n)(0) > maxx) maxx = points.Get(n)(0); + if (points.Get(n)(1) > maxy) maxy = points.Get(n)(1); + } + + if (minx > p(0) + rad || maxx < p(0) - rad || + miny > p(1) + rad || maxy < p(1) - rad) + { + intervallused.Elem(n1) = redlevel; + // (*testout) << 0; + } + else + { + // (*testout) << 1; + intervallused.Elem(n1) = 0; + } + } + // (*testout) << endl; +} + +void BSplineCurve2d :: UnReduce () +{ + int i; + for (i = 1; i <= intervallused.Size(); i++) + if (intervallused.Get(i) == redlevel) + intervallused.Set (i, 0); + redlevel--; +} + +void BSplineCurve2d :: Print (ostream & ost) const +{ + ost << "SplineCurve: " << points.Size() << " points." << endl; + for (int i = 1; i <= points.Size(); i++) + ost << "P" << i << " = " << points.Get(i) << endl; +} +} diff --git a/contrib/Netgen/libsrc/csg/csg.hpp b/contrib/Netgen/libsrc/csg/csg.hpp new file mode 100644 index 0000000000..e150860232 --- /dev/null +++ b/contrib/Netgen/libsrc/csg/csg.hpp @@ -0,0 +1,48 @@ +#ifndef FILE_CSG +#define FILE_CSG + +/* *************************************************************************/ +/* File: geoml.hpp */ +/* Author: Joachim Schoeberl */ +/* Date: 21. Jun. 98 */ +/* *************************************************************************/ + +#include <myadt.hpp> +#include <gprim.hpp> +#include <meshing.hpp> + +namespace netgen +{ +#include "surface.hpp" +#include "solid.hpp" +#include "identify.hpp" +#include "singularref.hpp" +#include "csgeom.hpp" + +#ifndef SMALLLIB +#define _INCLUDE_MORE +#endif +#ifdef LINUX +#define _INCLUDE_MORE +#endif + +#ifdef _INCLUDE_MORE +#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 +} + +#endif diff --git a/contrib/Netgen/libsrc/csg/csgeom.cpp b/contrib/Netgen/libsrc/csg/csgeom.cpp new file mode 100644 index 0000000000..f7c25ee9c6 --- /dev/null +++ b/contrib/Netgen/libsrc/csg/csgeom.cpp @@ -0,0 +1,1020 @@ +#include <mystdlib.h> +#include <myadt.hpp> + +#include <linalg.hpp> +#include <csg.hpp> + + +namespace netgen +{ + + int CSGeometry :: changeval = 0; + + + + TopLevelObject :: + TopLevelObject (Solid * asolid, + Surface * asurface) + { + solid = asolid; + surface = asurface; + + SetRGB (0, 0, 1); + SetTransparent (0); + SetVisible (1); + SetLayer (1); + + if (!surface) + maxh = solid->GetMaxH(); + else + maxh = surface->GetMaxH(); + + SetBCProp (-1); + } + + void TopLevelObject :: GetData (ostream & ost) + { + ost << red << " " << green << " " << blue << " " + << transp << " " << visible << " "; + } + + void TopLevelObject :: SetData (istream & ist) + { + ist >> red >> green >> blue >> transp >> visible; + } + + + + Box<3> CSGeometry::default_boundingbox (Point<3> (-1000, -1000, -1000), + Point<3> ( 1000, 1000, 1000)); + + + CSGeometry :: CSGeometry () + : boundingbox (default_boundingbox), + identicsurfaces (100), filename("") + { + ; + } + + CSGeometry :: CSGeometry (const string & afilename) + : boundingbox (default_boundingbox), + identicsurfaces (100), filename(afilename) + { + changeval++; + } + + CSGeometry :: ~CSGeometry () + { + Clean(); + } + + + void CSGeometry :: Clean () + { + for (int i = 0; i < solids.Size(); i++) + delete solids[i]->S1(); + for (int i = 0; i < solids.Size(); i++) + delete solids[i]; + solids.DeleteAll (); + + /* + for (int i = 0; i < surfaces.Size(); i++) + delete surfaces[i]; + surfaces.DeleteAll (); + */ + + for (int i = 0; i < toplevelobjects.Size(); i++) + delete toplevelobjects[i]; + toplevelobjects.DeleteAll (); + for (int i = 0; i < triapprox.Size(); i++) + delete triapprox[i]; + triapprox.DeleteAll(); + + changeval++; + } + + + + + + 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) + { + char * classname; + ARRAY<double> coeffs; + + prim -> GetPrimitiveData (classname, coeffs); + + if (sol->Name()) + ost << "primitive " + << sol->Name() << " " + << classname << " " << coeffs.Size(); + for (int i = 0; i < coeffs.Size(); i++) + ost << " " << coeffs[i]; + ost << endl; + } + } + + + void CSGeometry :: Save (ostream & ost) + { + ost << "boundingbox " + << boundingbox.PMin()(0) << " " + << boundingbox.PMin()(1) << " " + << boundingbox.PMin()(2) << " " + << boundingbox.PMax()(0) << " " + << boundingbox.PMax()(1) << " " + << boundingbox.PMax()(2) << endl; + + + WritePrimitivesIt wpi(ost); + IterateAllSolids (wpi, 1); + + for (int i = 0; i < solids.Size(); i++) + { + if (!solids[i]->GetPrimitive()) + { + ost << "solid " << solids.GetName(i) << " "; + solids[i] -> GetSolidData (ost); + ost << endl; + } + } + + for (int i = 0; i < GetNTopLevelObjects(); i++) + { + TopLevelObject * tlo = GetTopLevelObject (i); + ost << "toplevel "; + if (tlo -> GetSurface()) + ost << "surface " << tlo->GetSolid()->Name() << " " + << tlo->GetSurface()->Name() << " "; + else + ost << "solid " << tlo->GetSolid()->Name() << " "; + tlo->GetData(ost); + ost << endl; + } + + for (int i = 0; i < identifications.Size(); i++) + { + ost << "identify "; + identifications[i] -> GetData (ost); + ost << endl; + } + + ost << "end" << endl; + } + + + void CSGeometry :: Load (istream & ist) + { + // CSGeometry * geo = new CSGeometry; + + char key[100], name[100], classname[100], sname[100]; + int ncoeff, i, j; + ARRAY<double> coeff; + + while (ist.good()) + { + ist >> key; + if (strcmp (key, "boundingbox") == 0) + { + Point<3> pmin, pmax; + ist >> pmin(0) >> pmin(1) >> pmin(2); + ist >> pmax(0) >> pmax(1) >> pmax(2); + SetBoundingBox (Box<3> (pmin, pmax)); + } + if (strcmp (key, "primitive") == 0) + { + ist >> name >> classname >> ncoeff; + coeff.SetSize (ncoeff); + for (i = 0; i < ncoeff; i++) + ist >> coeff[i]; + + Primitive * nprim = Primitive::CreatePrimitive (classname); + nprim -> SetPrimitiveData (coeff); + Solid * nsol = new Solid (nprim); + + for (j = 0; j < nprim->GetNSurfaces(); j++) + { + sprintf (sname, "%s,%d", name, j); + AddSurface (sname, &nprim->GetSurface(j)); + nprim -> SetSurfaceId (j, GetNSurf()); + } + SetSolid (name, nsol); + } + else if (strcmp (key, "solid") == 0) + { + ist >> name; + Solid * nsol = Solid::CreateSolid (ist, solids); + + cout << " I have found solid " << name << " = "; + nsol -> GetSolidData (cout); + cout << endl; + + SetSolid (name, nsol); + } + else if (strcmp (key, "toplevel") == 0) + { + char type[20], solname[50], surfname[50]; + const Solid * sol = NULL; + const Surface * surf = NULL; + int nr; + + ist >> type; + if (strcmp (type, "solid") == 0) + { + ist >> solname; + sol = GetSolid (solname); + } + if (strcmp (type, "surface") == 0) + { + ist >> solname >> surfname; + sol = GetSolid (solname); + surf = GetSurface (surfname); + } + nr = SetTopLevelObject ((Solid*)sol, (Surface*)surf); + GetTopLevelObject (nr) -> SetData (ist); + } + else if (strcmp (key, "identify") == 0) + { + char type[10], surfname1[50], surfname2[50]; + const Surface * surf1; + const Surface * surf2; + + + ist >> type >> surfname1 >> surfname2; + surf1 = GetSurface(surfname1); + surf2 = GetSurface(surfname2); + + AddIdentification (new PeriodicIdentification + (GetNIdentifications(), + *this, surf1, surf2)); + } + else if (strcmp (key, "end") == 0) + break; + } + + changeval++; + } + + + + + + void CSGeometry :: AddSurface (Surface * surf) + { + static int cntsurfs = 0; + cntsurfs++; + char name[15]; + sprintf (name, "nnsurf%d", cntsurfs); + AddSurface (name, surf); + } + + void CSGeometry :: AddSurface (char * name, Surface * surf) + { + surfaces.Set (name, surf); + surf->SetName (name); + changeval++; + } + + void CSGeometry :: AddSurfaces (Primitive * prim) + { + for (int i = 0; i < prim->GetNSurfaces(); i++) + { + AddSurface (&prim->GetSurface(i)); + prim->SetSurfaceId (i, GetNSurf()-1); + } + } + + const Surface * CSGeometry :: GetSurface (const char * name) const + { + if (surfaces.Used(name)) + return surfaces.Get(name); + else + return NULL; + } + + /* + const Surface * CSGeometry :: GetSurface (int i) const + { + if (i >= 0 && i < surfaces.Size()) + return surfaces[i]; + else + throw NgException ("CSGeometry::GetSurface out of range"); + } + */ + + + + + void CSGeometry :: SetSolid (const char * name, Solid * sol) + { + Solid * oldsol = NULL; + + if (solids.Used (name)) + oldsol = solids.Get(name); + + solids.Set (name, sol); + sol->SetName (name); + + if (oldsol) + { + if (oldsol->op != Solid::ROOT || + sol->op != Solid::ROOT) + { + cerr << "Setsolid: old or new no root" << endl; + } + oldsol -> s1 = sol -> s1; + } + changeval++; + } + + const Solid * CSGeometry :: GetSolid (const char * name) const + { + if (solids.Used(name)) + return solids.Get(name); + else + return NULL; + } + + + + const Solid * CSGeometry :: GetSolid (const string & name) const + { + if (solids.Used(name.c_str())) + return solids.Get(name.c_str()); + else + return NULL; + } + + + + + + + + + class RemoveDummyIterator : public SolidIterator + { + public: + + RemoveDummyIterator() { ; } + virtual ~RemoveDummyIterator() { ; } + virtual void Do(Solid * sol); + }; + + void RemoveDummyIterator :: Do(Solid * sol) + { + if ( (sol->op == Solid::SUB || sol->op == Solid::SECTION || + sol->op == Solid::UNION) + && sol->s1->op == Solid::DUMMY) + sol->s1 = sol->s1->s1; + if ( (sol->op == Solid::SECTION || sol->op == Solid::UNION) + && sol->s2->op == Solid::DUMMY) + sol->s2 = sol->s2->s1; + } + + + + + + + int CSGeometry :: SetTopLevelObject (Solid * sol, Surface * surf) + { + return toplevelobjects.Append (new TopLevelObject (sol, surf)) - 1; + } + + TopLevelObject * CSGeometry :: + GetTopLevelObject (const Solid * sol, const Surface * surf) + { + for (int i = 0; i < toplevelobjects.Size(); i++) + { + if (toplevelobjects[i]->GetSolid() == sol && + toplevelobjects[i]->GetSurface() == surf) + return (toplevelobjects[i]); + } + return NULL; + } + + void CSGeometry :: RemoveTopLevelObject (Solid * sol, Surface * surf) + { + for (int i = 0; i < toplevelobjects.Size(); i++) + { + if (toplevelobjects[i]->GetSolid() == sol && + toplevelobjects[i]->GetSurface() == surf) + { + delete toplevelobjects[i]; + toplevelobjects.DeleteElement (i+1); + changeval++; + break; + } + } + } + + void CSGeometry :: AddIdentification (Identification * ident) + { + identifications.Append (ident); + } + + void CSGeometry :: SetFlags (const char * solidname, const Flags & flags) + { + Solid * solid = solids.Elem(solidname); + ARRAY<int> surfind; + + int i; + double maxh = flags.GetNumFlag ("maxh", -1); + if (maxh > 0 && solid) + { + solid->GetSurfaceIndices (surfind); + + for (i = 0; i < surfind.Size(); i++) + { + if (surfaces[surfind[i]]->GetMaxH() > maxh) + surfaces[surfind[i]] -> SetMaxH (maxh); + } + + solid->SetMaxH (maxh); + } + + if (flags.NumFlagDefined ("bc")) + { + solid->GetSurfaceIndices (surfind); + int bc = int (flags.GetNumFlag("bc", -1)); + for (i = 0; i < surfind.Size(); i++) + { + if (surfaces[surfind[i]]->GetBCProperty() == -1) + surfaces[surfind[i]]->SetBCProperty(bc); + } + } + } + + void CSGeometry :: FindIdenticSurfaces (double eps) + { + int inv; + int nsurf = GetNSurf(); + + 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) << "surfaces " << i2 << " are identic" << endl; + } + + /* + (*testout) << "identicmap:" << endl; + for (int i = 0; i < isidenticto.Size(); i++) + (*testout) << i << " -> " << isidenticto[i] << endl; + + for (int i = 0; i < nsurf; i++) + GetSurface(i)->Print (*testout); + */ + } + + + void CSGeometry :: + GetIndependentSurfaceIndices (const Solid * sol, + const BoxSphere<3> & box, + ARRAY<int> & locsurf) const + { + ReducePrimitiveIterator rpi(box); + UnReducePrimitiveIterator urpi; + + ((Solid*)sol) -> IterateSolid (rpi); + sol -> GetSurfaceIndices (locsurf); + ((Solid*)sol) -> IterateSolid (urpi); + + for (int i = 0; i < locsurf.Size(); i++) + locsurf[i] = isidenticto[locsurf[i]]; + + for (int i = locsurf.Size()-1; i >= 0; i--) + { + bool indep = 1; + for (int j = 0; j < i; j++) + if (locsurf[i] == locsurf[j]) + { + indep = 0; + break; + } + + if (!indep) locsurf.Delete(i); + } + + + /* + // delete identified + for (int i = locsurf.Size()-1; i >= 0; i--) + { + bool indep = 1; + for (int j = 0; j < i; j++) + { + if (identicsurfaces.Used (INDEX_2::Sort (locsurf[i], locsurf[j])) != + (isidenticto[locsurf[i]] == isidenticto[locsurf[j]])) + { + cerr << "different result" << endl; + exit(1); + } + + if (isidenticto[locsurf[i]] == isidenticto[locsurf[j]]) + { + indep = 0; + break; + } + } + if (!indep) + locsurf.Delete(i); + } + + for (int i = 0; i < locsurf.Size(); i++) + locsurf[i] = isidenticto[locsurf[i]]; + */ + } + + + void CSGeometry :: + GetIndependentSurfaceIndices (const Solid * sol, + const Point<3> & p, Vec<3> & v, + ARRAY<int> & locsurf) const + { + Point<3> p2 = p + 1e-2 * v; + BoxSphere<3> box (p2, p2); + box.Increase (1e-3); + box.CalcDiamCenter(); + GetIndependentSurfaceIndices (sol, box, locsurf); + } + + + void CSGeometry :: + CalcTriangleApproximation(const Box<3> & boundingbox, + double detail, double facets) + { + PrintMessage (1, "Calc Triangle Approximation"); + + // FindIdenticSurfaces (1e-6); + + int ntlo = GetNTopLevelObjects(); + + for (int i = 0; i < triapprox.Size(); i++) + delete triapprox[i]; + triapprox.SetSize (ntlo); + + ARRAY<int> surfind; + + 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); + + RefineTriangleApprox (locsol, j, box, detail, + tria, *tams); + delete locsol; + } + } + } + + tams->RemoveUnusedPoints (); + PrintMessage (2, "Object ", i, " has ", tams->GetNT(), " triangles"); + } + + Change(); + } + + + + void CSGeometry :: + RefineTriangleApprox (Solid * locsol, + int surfind, + const BoxSphere<3> & box, + double detail, + const TATriangle & tria, + TriangleApproximation & tams) + { + int pinds[6]; + ArrayMem<int,500> surfused(GetNSurf()); + + ReducePrimitiveIterator rpi(box); + UnReducePrimitiveIterator urpi; + + + locsol -> IterateSolid (rpi); + // locsol -> GetSurfaceIndices (lsurfi); + + + IndexSet iset(GetNSurf()); + locsol -> GetSurfaceIndices (iset); + const ARRAY<int> & lsurfi = iset.Array(); + + 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); + 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); + } + + 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; + if ( fabs (f1-f2) > 1e-20 ) + { + double l2 = -f1/(f2-f1); + double l1 = f2/(f2-f1); + pn = Point<3>(l1 * p1(0) + l2 * p2(0), + l1 * p1(1) + l2 * p2(1), + l1 * p1(2) + l2 * p2(2)); + } + else + pn = p1; + + pnums[lpin] = tams.AddPoint (pn); + + GetSurface (surfind)->Project (pn); + + Vec<3> n; + 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]); + tams.AddTriangle (ntria); + } + + /* saturn changes: + + int pvis[3]; + for (j = 0; j < 3; j++) + pvis[j] = !locsol->IsStrictIn (tams.GetPoint (j+1), 1e-6) && + locsol->IsIn (tams.GetPoint (j+1), 1e-6); + + int newpi[3]; + for (j = 0; j < 3; j++) + { + int pi1 = j; + int pi2 = (j+1) % 3; + int pic = j; + + if (pvis[pi1] != pvis[pi2]) + { + Point<3> hp = Center (tams.GetPoint (tria.PNum (pi1+1)), + tams.GetPoint (tria.PNum (pi2+1))); + + newpi[j] = tams.AddPoint (hp); + Vec<3> n = tams.GetNormal (pi1); + tams.AddNormal (n); + } + else + newpi[j] = 0; + } + + int nvis = 0; + for (j = 0; j <= nvis; j++) + if (pvis[j]) nvis++; + + int si = tria.SurfaceIndex(); + switch (nvis) + { + case 0: + break; + case 1: + { + int visj; + for (j = 0; j < 3; j++) + if (pvis[j]) visj = j; + int pivis = tria.PNum (visj+1); + int pic1 = newpi[(visj+1)%3]; + int pic2 = newpi[(visj+2)%3]; + + cout << pivis << "," << pic1 << "," << pic2 << endl; + + tams.AddTriangle (TATriangle (si, pivis, pic1,pic2)); + break; + } + case 2: + { + int nvisj; + for (j = 0; j < 3; j++) + if (!pvis[j]) nvisj = j; + + int pivis1 = tria.PNum ((nvisj+1)%3+1); + int pivis2 = tria.PNum ((nvisj+2)%3+1); + int pic1 = newpi[nvisj]; + int pic2 = newpi[(nvisj+2)%3]; + + tams.AddTriangle (TATriangle (si, pivis1, pic1,pic2)); + tams.AddTriangle (TATriangle (si, pivis1, pic1,pivis2)); + break; + } + case 3: + { + tams.AddTriangle (tria); + break; + } + } + + */ + return; + } + } + + // bisection + if (box.Diam() < detail) + return; + + for (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-6); + nbox.CalcDiamCenter(); + + Solid * nsol = locsol -> GetReducedSolid (nbox); + + if (nsol) + { + RefineTriangleApprox (nsol, surfind, nbox, + detail, ntri, tams); + + delete nsol; + } + } + } + + + + + class ClearVisitedIt : public SolidIterator + { + public: + ClearVisitedIt () { ; } + virtual ~ClearVisitedIt () { ; } + + virtual void Do (Solid * sol) + { + sol -> visited = 0; + } + }; + + + void CSGeometry :: + IterateAllSolids (SolidIterator & it, int only_once) + { + if (only_once) + { + ClearVisitedIt clit; + for (int i = 0; i < solids.Size(); i++) + solids[i] -> IterateSolid (clit, 0); + } + + for (int i = 0; i < solids.Size(); i++) + solids[i] -> IterateSolid (it, only_once); + } + + + double CSGeometry :: MaxSize () const + { + double maxs, mins; + maxs = max3 (boundingbox.PMax()(0), + boundingbox.PMax()(1), + boundingbox.PMax()(2)); + mins = min3 (boundingbox.PMin()(0), + boundingbox.PMin()(1), + boundingbox.PMin()(2)); + return max2 (maxs, -mins) * 1.1; + } +} diff --git a/contrib/Netgen/libsrc/csg/csgeom.hpp b/contrib/Netgen/libsrc/csg/csgeom.hpp new file mode 100644 index 0000000000..6e29a8163b --- /dev/null +++ b/contrib/Netgen/libsrc/csg/csgeom.hpp @@ -0,0 +1,257 @@ +#ifndef FILE_CSGEOM +#define FILE_CSGEOM + +/**************************************************************************/ +/* File: csgeom.hh */ +/* Author: Joachim Schoeberl */ +/* Date: 27. Nov. 97 */ +/**************************************************************************/ + +/** + Constructive Solid Geometry +*/ + + +class TriangleApproximation; +class TATriangle; + + +/** + A top level object is an entity to be meshed. + I can be either a solid, or one surface patch of a solid. + */ +class TopLevelObject +{ + Solid * solid; + Surface * surface; + + double red, blue, green; + bool visible, transp; + double maxh; + string material; + int layer; + int bc; // for surface patches, only +public: + TopLevelObject (Solid * asolid, + Surface * asurface = NULL); + + const Solid * GetSolid() const { return solid; } + Solid * GetSolid() { return solid; } + + const Surface * GetSurface () const { return surface; } + Surface * GetSurface () { return surface; } + + void GetData (ostream & ost); + void SetData (istream & ist); + + void SetMaxH (double amaxh) { maxh = amaxh; } + double GetMaxH () const { return maxh; } + + void SetRGB (double ared, double agreen, double ablue) + { + red = ared; + green = agreen; + blue = ablue; + } + + double GetRed () const { return red; } + double GetGreen () const { return green; } + double GetBlue () const { return blue; } + + void SetTransparent (bool atransp) + { transp = atransp; } + bool GetTransparent () const { return transp; } + + void SetVisible (bool avisible) + { visible = avisible; } + bool GetVisible () const { return visible; } + + const string GetMaterial () const { return material; } + void SetMaterial (const string & mat) { material = mat; } + + int GetLayer () const { return layer; } + void SetLayer (int alayer) { layer = alayer; } + + void SetBCProp (int abc) { bc = abc; } + int GetBCProp () const { return bc; } +}; + + +/** + CSGeometry has the whole geometric information + */ +class CSGeometry +{ +private: + /// all surfaces + SYMBOLTABLE<Surface*> surfaces; + + /// all named solids + SYMBOLTABLE<Solid*> solids; + + /// all top level objects: solids and surfaces + ARRAY<TopLevelObject*> toplevelobjects; + + /// additional points specified by user + ARRAY<Point<3> > userpoints; + + /// triangular approximation of top level objects + ARRAY<TriangleApproximation*> triapprox; + + /// increment, if geometry is changed + static int changeval; + + /// bounding box of geometry + Box<3> boundingbox; + + /// bounding box, if not set by input file + static Box<3> default_boundingbox; + + /// identic surfaces are stored by pair of indizes, val = inverse + INDEX_2_HASHTABLE<int> identicsurfaces; + ARRAY<int> isidenticto; + + /// identification of boundaries (periodic, thin domains, ...) + + + + /// filename of inputfile + string filename; + +public: + CSGeometry (); + CSGeometry (const string & afilename); + ~CSGeometry (); + + void Clean (); + + void Save (ostream & ost); + void Load (istream & ist); + + int GetChangeVal() { return changeval; } + void Change() { changeval++; } + + void AddSurface (Surface * surf); + void AddSurface (char * name, Surface * surf); + 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) { return solids[i]; } + const SYMBOLTABLE<Solid*> & GetSolids () const { return solids; } + + + 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) + { return toplevelobjects[nr]; } + const TopLevelObject * GetTopLevelObject (int nr) const + { return toplevelobjects[nr]; } + void RemoveTopLevelObject (Solid * sol, Surface * surf = NULL); + + + void AddUserPoint (const Point<3> & p) + { userpoints.Append (p); } + int GetNUserPoints () const + { return userpoints.Size(); } + const Point<3> & GetUserPoint (int nr) const + { return userpoints[nr]; } + + + // quick implementations: + ARRAY<SingularFace*> singfaces; + ARRAY<SingularEdge*> singedges; + ARRAY<SingularPoint*> singpoints; + ARRAY<Identification*> identifications; + + int GetNIdentifications () { return identifications.Size(); } + void AddIdentification (Identification * ident); + + + /// + void CalcTriangleApproximation(const Box<3> & boundingbox, + double detail, double facets); + + /// + void FindIdenticSurfaces (double eps); + /// + void GetIndependentSurfaceIndices (const Solid * sol, + const BoxSphere<3> & box, + ARRAY<int> & locsurf) const; + /// + void GetIndependentSurfaceIndices (const Solid * sol, + const Point<3> & p, Vec<3> & v, + ARRAY<int> & locsurf) const; + /// + int GetSurfaceClassRepresentant (int si) const + { return isidenticto[si]; } + + /// + const TriangleApproximation * GetTriApprox (int msnr) + { + if (msnr < triapprox.Size()) + return triapprox[msnr]; + return 0; + } + + + void IterateAllSolids (SolidIterator & it, int only_once = 0); + + void RefineTriangleApprox (Solid * locsol, + int surfind, + const BoxSphere<3> & box, + double detail, + const TATriangle & tria, + TriangleApproximation & tams); + + const Box<3> & BoundingBox () const { return boundingbox; } + + void SetBoundingBox (const Box<3> & abox) + { + boundingbox = abox; + } + + + static void SetDefaultBoundingBox (const Box<3> & abox) + { + default_boundingbox = abox; + } + + double MaxSize () const; + + + + class BCModification { + public: + int si; + int tlonr; + int bcnr; + }; + ARRAY<BCModification> bcmodifications; + +}; +#endif + diff --git a/contrib/Netgen/libsrc/csg/csgparser.cpp b/contrib/Netgen/libsrc/csg/csgparser.cpp new file mode 100644 index 0000000000..b6d4878399 --- /dev/null +++ b/contrib/Netgen/libsrc/csg/csgparser.cpp @@ -0,0 +1,1156 @@ +#include <mystdlib.h> +#include <myadt.hpp> + +#include <linalg.hpp> +#include <csg.hpp> + + +namespace netgen +{ + using namespace netgen; + + + enum TOKEN_TYPE + { + TOK_MINUS = '-', TOK_LP = '(', OK_RP = ')', TOK_LSP = '[', TOK_RSP = ']', + TOK_EQU = '=', TOK_COMMA = ',', TOK_SEMICOLON = ';', + TOK_NUM = 100, TOK_STRING, TOK_NAMED_SOLID, TOK_PRIMITIVE, + TOK_OR, TOK_AND, TOK_NOT, + TOK_SINGULAR, TOK_EDGE, TOK_POINT, TOK_FACE, TOK_IDENTIFY, TOK_CLOSESURFACES, + TOK_CLOSEEDGES, TOK_PERIODIC, + TOK_SOLID, TOK_RECO, TOK_TLO, TOK_BOUNDINGBOX, TOK_BOUNDARYCONDITION, + TOK_END }; + + struct kwstruct + { + TOKEN_TYPE kw; + char * name; + }; + + static kwstruct defkw[] = + { + { TOK_RECO, "algebraic3d" }, + { TOK_SOLID, "solid" }, + { TOK_TLO, "tlo" }, + { TOK_BOUNDINGBOX, "boundingbox" }, + { TOK_OR, "or" }, + { TOK_AND, "and" }, + { TOK_NOT, "not" }, + { TOK_SINGULAR, "singular" }, + { TOK_EDGE, "edge" }, + { TOK_FACE, "face" }, + { TOK_POINT, "point" }, + { TOK_IDENTIFY, "identify" }, + { TOK_CLOSESURFACES, "closesurfaces" }, + { TOK_CLOSEEDGES, "closeedges" }, + { TOK_PERIODIC, "periodic" }, + { TOK_BOUNDARYCONDITION, "boundarycondition" }, + { TOKEN_TYPE(0) } + }; + + enum PRIMITIVE_TYPE + { + TOK_SPHERE = 1, TOK_CYLINDER, TOK_PLANE, TOK_ELLIPTICCYLINDER, + TOK_ELLIPSOID, TOK_CONE, + TOK_ORTHOBRICK, TOK_POLYHEDRON, + + TOK_TUBE, TOK_GENCYL, TOK_EXTRUSION, TOK_REVOLUTION, // currently, out of order + + TOK_TRANSLATE, TOK_MULTITRANSLATE, TOK_ROTATE, TOK_MULTIROTATE + }; + + struct primstruct + { + PRIMITIVE_TYPE kw; + char * name; + }; + + static primstruct defprim[] = + { + { TOK_PLANE, "plane" }, + { TOK_SPHERE, "sphere" }, + { TOK_CYLINDER, "cylinder" }, + { TOK_CONE, "cone" }, + { TOK_ELLIPTICCYLINDER, "ellipticcylinder" }, + { TOK_ELLIPSOID, "ellipsoid" }, + { TOK_ORTHOBRICK, "orthobrick" }, + { TOK_POLYHEDRON, "polyhedron" }, + + { 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) } + }; + + static CSGeometry * geom; + + + + 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 :: 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; + } + + // skip comment line + if (ch == '#') + { + while (ch != '\n') + { + scanin->get(ch); + if (scanin->eof()) + { + token = TOK_END; + return; + } + } + linenum++; + } + } + while (isspace(ch)); + + switch (ch) + { + case '(': case ')': + case '[': case ']': + case '-': + case '=': case ',': case ';': + { + token = TOKEN_TYPE (ch); + break; + } + + default: + { + if (isdigit (ch) || ch == '.') + { + scanin->putback (ch); + (*scanin) >> num_value; + token = TOK_NUM; + return; + } + + if (isalpha (ch)) + { + string_value = string (1, ch); + scanin->get(ch); + while (isalnum(ch) || ch == '_') + { + string_value += ch; + scanin->get(ch); + } + scanin->putback (ch); + } + + int nr = 0; + while (defkw[nr].kw) + { + if (string_value == defkw[nr].name) + { + token = defkw[nr].kw; + return; + } + nr++; + } + + nr = 0; + while (defprim[nr].kw) + { + if (string_value == defprim[nr].name) + { + token = TOK_PRIMITIVE; + prim_token = defprim[nr].kw; + return; + } + nr++; + } + + token = TOK_STRING; + } + } + } + + void CSGScanner :: Error (const string & err) + { + stringstream errstr; + errstr << "Parsing error in line " << linenum << ": " << endl << err << endl; + throw string(errstr.str()); + } + + + /* + Solid = Term { OR Term } + Term = Primary { AND Primary } + Primary = PRIM | IDENT | ( Solid ) | NOT Primary + */ + + void ParseChar (CSGScanner & scan, char ch) + { + if (scan.GetToken() != TOKEN_TYPE(ch)) + scan.Error (string ("token '") + string(1, ch) + string("' expected")); + scan.ReadNext(); + } + + double ParseNumber(CSGScanner & scan) + { + if (scan.GetToken() == '-') + { + scan.ReadNext(); + return -ParseNumber (scan); + } + if (scan.GetToken() != TOK_NUM) scan.Error ("number expected"); + double val = scan.GetNumValue(); + scan.ReadNext(); + return val; + } + + Vec<3> ParseVector (CSGScanner & scan) + { + Vec<3> v; + v(0) = ParseNumber (scan); + ParseChar (scan, ','); + v(1) = ParseNumber (scan); + ParseChar (scan, ','); + v(2) = ParseNumber (scan); + return v; + } + + + CSGScanner & operator>> (CSGScanner & scan, char ch) + { + if (scan.GetToken() != TOKEN_TYPE(ch)) + scan.Error (string ("token '") + string(1, ch) + string("' expected")); + scan.ReadNext(); + return scan; + } + + CSGScanner & operator>> (CSGScanner & scan, double & d) + { + d = ParseNumber (scan); + return scan; + } + + CSGScanner & operator>> (CSGScanner & scan, int & i) + { + i = int (ParseNumber (scan)); + return scan; + } + + CSGScanner & operator>> (CSGScanner & scan, Point<3> & p) + { + scan >> p(0) >> ',' >> p(1) >> ',' >> p(2); + return scan; + } + + CSGScanner & operator>> (CSGScanner & scan, Vec<3> & v) + { + scan >> v(0) >> ',' >> v(1) >> ',' >> v(2); + return scan; + } + + + Solid * ParseSolid (CSGScanner & scan); + Solid * ParseTerm (CSGScanner & scan); + Solid * ParsePrimary (CSGScanner & scan); + + + Solid * ParsePrimary (CSGScanner & scan) + { + if (scan.GetToken() == TOK_PRIMITIVE) + { + switch (scan.GetPrimitiveToken()) + { + case TOK_PLANE: + { + Point<3> p; + Vec<3> v; + + scan.ReadNext(); + scan >> '(' >> p >> ';' >> v >> ')'; + + OneSurfacePrimitive * surf = new Plane ( p, v ); + geom->AddSurfaces (surf); + return new Solid (surf); + } + + case TOK_CYLINDER: + { + Point<3> pa, pb; + double r; + + scan.ReadNext(); + scan >> '(' >> pa >> ';' >> pb >> ';' >> r >> ')'; + + OneSurfacePrimitive * surf = new Cylinder ( pa, pb, r ); + geom->AddSurfaces (surf); + return new Solid (surf); + } + + case TOK_ELLIPTICCYLINDER: + { + Point<3> pa; + Vec<3> vl, vs; + + scan.ReadNext(); + scan >> '(' >> pa >> ';' >> vl >> ';' >> vs >> ')'; + + OneSurfacePrimitive * surf = new EllipticCylinder ( pa, vl, vs); + geom->AddSurfaces (surf); + return new Solid (surf); + } + + + case TOK_ELLIPSOID: + { + Point<3> pa; + Vec<3> v1, v2, v3; + + scan.ReadNext(); + scan >> '(' >> pa >> ';' >> v1 >> ';' >> v2 >> ';' >> v3 >> ')'; + + OneSurfacePrimitive * surf = new Ellipsoid ( pa, v1, v2, v3); + geom->AddSurfaces (surf); + return new Solid (surf); + } + + + case TOK_CONE: + { + Point<3> pa, pb; + double ra, rb; + + scan.ReadNext(); + scan >> '(' >> pa >> ';' >> ra >> ';' >> pb >> ';' >> rb >> ')'; + + OneSurfacePrimitive * surf = new Cone ( pa, pb, ra, rb ); + geom->AddSurfaces (surf); + return new Solid (surf); + } + + + + case TOK_SPHERE: + { + Point<3> p; + double r; + + scan.ReadNext(); + scan >> '(' >> p >> ';' >> r >> ')'; + + OneSurfacePrimitive * surf = new Sphere ( p, r ); + geom->AddSurfaces (surf); + return new Solid (surf); + } + + case TOK_ORTHOBRICK: + { + Point<3> pa, pb; + + scan.ReadNext(); + scan >> '(' >> pa >> ';' >> pb >> ')'; + + Primitive * nprim = new OrthoBrick (pa, pb); + geom->AddSurfaces (nprim); + return new Solid (nprim); + } + + case TOK_POLYHEDRON: + { + // Added by Dalibor Lukas, October 15, 2003 + + Point<3> p; + int pi1, pi2, pi3, pi4; + + scan.ReadNext(); + ParseChar (scan, '('); + + Polyhedra * polyhedron = new Polyhedra; + + // scanning the points + while (1) + { + p = Point<3> (ParseVector (scan)); + ParseChar (scan, ';'); + + polyhedron->AddPoint(p); + + if (scan.GetToken() == ';') + { + scan.ReadNext(); + break; + } + } + + // scanning the faces + while (1) + { + pi1 = (int) (ParseNumber (scan)); + ParseChar (scan, ','); + pi2 = (int) (ParseNumber (scan)); + ParseChar (scan, ','); + pi3 = (int) (ParseNumber (scan)); + + polyhedron->AddFace(pi1-1,pi2-1,pi3-1); + + if (scan.GetToken() == TOK_COMMA) + { + ParseChar (scan, ','); + pi4 = (int) (ParseNumber (scan)); + polyhedron->AddFace(pi1-1,pi3-1,pi4-1); + } + + if (scan.GetToken() == ')') + { + scan.ReadNext(); + break; + } + scan.ReadNext(); + } + + geom->AddSurfaces (polyhedron); + return new Solid (polyhedron); + } + + + case TOK_EXTRUSION: // not functional + { + Point<3> p0; + Vec<3> ex, ey; + ARRAY<Point<2> > points; + + scan.ReadNext(); + + ParseChar (scan, '('); + p0(0) = ParseNumber (scan); + ParseChar (scan, ','); + p0(1) = ParseNumber (scan); + ParseChar (scan, ','); + p0(2) = ParseNumber (scan); + ParseChar (scan, ';'); + + ex(0) = ParseNumber (scan); + ParseChar (scan, ','); + ex(1) = ParseNumber (scan); + ParseChar (scan, ','); + ex(2) = ParseNumber (scan); + ParseChar (scan, ';'); + + ey(0) = ParseNumber (scan); + ParseChar (scan, ','); + ey(1) = ParseNumber (scan); + ParseChar (scan, ','); + ey(2) = ParseNumber (scan); + ParseChar (scan, ';'); + + cout << "p0 = " << p0 << endl; + + // int npseg = 0; + // int nseg = 0; + while (1) + { + Point<2> p1, p2, p3; + + p1(0) = ParseNumber(scan); + ParseChar (scan, ','); + p1(1) = ParseNumber(scan); + points.Append (p1); + if (scan.GetToken() == ')') + { + scan.ReadNext(); + break; + } + scan.ReadNext(); + } + + + /* + while (1) + { + Point<2> p1, p2, p3; + + p3 = p2; + p2 = p1; + p1(0) = ParseNumber(scan); + ParseChar (scan, ','); + p1(1) = ParseNumber(scan); + npseg++; + + cout << "p1 = " << p1 << endl; + + if (scan.GetToken() == ';' || scan.GetToken() == ')') + { + if (npseg == 2) + { + p3 = p2; + p2 = Center (p1, p3); + } + if (nseg == 0) + points.Append (p3); + points.Append (p2); + points.Append (p1); + npseg = 1; + nseg++; + + cout << "p1, = " << p1 << ", p2 = " << p2 << ", p3 = " << p3 << endl; + } + + if (scan.GetToken() == ')') + { + scan.ReadNext(); + break; + } + if (scan.GetToken() == ';' || scan.GetToken() == ',') + { + scan.ReadNext(); + } + } + */ + cout << "p0 = " << p0 << endl; + cout << ", ex = " << ex << ", ey = " << ey << endl; + cout << "points = " << points << endl; + + Extrusion * extrusion = new Extrusion (p0, ex, ey, points); + + geom->AddSurfaces (extrusion); + return new Solid (extrusion); + + /* + // cout << "define cylinder, pa = " << pa << "; pb = " << pb + // << ", rad = " << r << endl; + OneSurfacePrimitive * surf = new Cylinder ( pa, pb, r ); + + geom->AddSurface (surf); + surf->SetSurfaceId (0, geom->GetNSurf()-1); + + return new Solid (surf); + */ + } + + + + + + case TOK_TRANSLATE: + { + Vec<3> v; + scan.ReadNext(); + + ParseChar (scan, '('); + v = 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_MULTITRANSLATE: + { + Vec<3> v; + int n; + + scan.ReadNext(); + + scan >> '(' >> v >> ';' >> n >> ';'; + + Solid * sol1 = ParseSolid (scan); + + scan >> ')'; + + Solid * hsol = sol1; + for (int i = 1; i <= n; i++) + { + Solid * nsol = sol1 -> Copy(*geom); + Transformation<3> trans(double(i) * v); + + nsol -> Transform (trans); + hsol = new Solid (Solid::UNION, hsol, nsol); + } + return hsol; + } + + + case TOK_MULTIROTATE: + { + Point<3> c; + Vec<3> v; + int n; + + scan.ReadNext(); + + scan >> '(' >> c >> ';' >> v >> ';' >> n >> ';'; + Solid * sol1 = ParseSolid (scan); + scan >> ')'; + + Transformation<3> trans(c, v(0), v(1), v(2)); + Transformation<3> multi(Vec<3>(0,0,0)); + Transformation<3> ht; + + Solid * hsol = sol1; + for (int i = 1; i <= n; i++) + { + Solid * nsol = sol1 -> Copy(*geom); + + nsol -> Transform (multi); + hsol = new Solid (Solid::UNION, hsol, nsol); + + ht=multi; + multi.Combine (trans, ht); + } + return hsol; + } + + + default: + { + scan.Error (string ("unknown primary ") + scan.GetStringValue()); + } + + } + } + + else if (scan.GetToken() == TOK_STRING && + geom->GetSolid(scan.GetStringValue())) + + { + Solid * sol = const_cast<Solid*> (geom->GetSolid(scan.GetStringValue())); + scan.ReadNext(); + return sol; + } + + else if (scan.GetToken() == TOK_NOT) + + { + scan.ReadNext(); + Solid * sol1 = ParsePrimary (scan); + return new Solid (Solid::SUB, sol1); + } + + else if (scan.GetToken() == '(') + + { + scan.ReadNext(); + Solid * sol1 = ParseSolid (scan); + scan.ReadNext(); + return sol1; + } + + scan.Error (string ("not a primary, name = ")+ + scan.GetStringValue()); + return 0; + } + + + + Solid * ParseTerm (CSGScanner & scan) + { + Solid * sol = ParsePrimary(scan); + while (scan.GetToken() == TOK_AND) + { + scan.ReadNext(); + Solid * sol2 = ParsePrimary(scan); + sol = new Solid (Solid::SECTION, sol, sol2); + } + return sol; + } + + + Solid * ParseSolid (CSGScanner & scan) + { + Solid * sol = ParseTerm(scan); + while (scan.GetToken() == TOK_OR) + { + scan.ReadNext(); + Solid * sol2 = ParseTerm(scan); + sol = new Solid (Solid::UNION, sol, sol2); + } + return sol; + } + + + + void ParseFlags (CSGScanner & scan, Flags & flags) + { + while (scan.GetToken() == '-') + { + scan.ReadNext(); + string name = scan.GetStringValue(); + scan.ReadNext(); + if (scan.GetToken() == '=') + { + scan.ReadNext(); + if (scan.GetToken() == TOK_STRING) + { + flags.SetFlag (name.c_str(), scan.GetStringValue().c_str()); + scan.ReadNext(); + } + else if (scan.GetToken() == '[') + { + scan.ReadNext(); + ARRAY<double> vals; + vals.Append (ParseNumber(scan)); + while (scan.GetToken() == ',') + { + scan.ReadNext(); + vals.Append (ParseNumber(scan)); + } + ParseChar (scan, ']'); + flags.SetFlag (name.c_str(), vals); + } + else if (scan.GetToken() == TOK_NUM) + { + flags.SetFlag (name.c_str(), scan.GetNumValue()); + scan.ReadNext(); + } + } + else + { + flags.SetFlag (name.c_str()); + } + } + } + + + /* + Main parsing function for CSG geometry + */ + CSGeometry * ParseCSG (istream & istr) + { + CSGScanner scan(istr); + + geom = new CSGeometry; + + scan.ReadNext(); + if (scan.GetToken() != TOK_RECO) // keyword 'algebraic3d' + return 0; + + scan.ReadNext(); + + try + { + while (1) + { + if (scan.GetToken() == TOK_END) break; + + if (scan.GetToken() == TOK_SOLID) + { + scan.ReadNext(); + if (scan.GetToken() != TOK_STRING) + scan.Error ("name identifier expected"); + string solidname = scan.GetStringValue(); + + scan.ReadNext(); + + ParseChar (scan, '='); + Solid * solid = ParseSolid (scan); + + Flags flags; + ParseFlags (scan, flags); + + geom->SetSolid (solidname.c_str(), new Solid (Solid::ROOT, solid)); + geom->SetFlags (solidname.c_str(), flags); + + ParseChar (scan, ';'); + + PrintMessage (4, "define solid ", solidname); + } + + else if (scan.GetToken() == TOK_TLO) + + { // a TopLevelObject definition + + scan.ReadNext(); + + string name = scan.GetStringValue(); + scan.ReadNext(); + + if (scan.GetToken() != TOK_STRING) + + { // a solid TLO + + Flags flags; + ParseFlags (scan, flags); + + ParseChar (scan, ';'); + if (!geom->GetSolid (name)) + scan.Error ("Top-Level-Object "+name+" not defined"); + + int tlonr = + geom->SetTopLevelObject ((Solid*)geom->GetSolid(name)); + TopLevelObject * tlo = geom->GetTopLevelObject (tlonr); + + if (flags.NumListFlagDefined ("col")) + { + const ARRAY<double> & col = + flags.GetNumListFlag ("col"); + tlo->SetRGB (col[0], col[1], col[2]); + } + + if (flags.GetDefineFlag ("transparent")) + tlo->SetTransparent (1); + + tlo->SetMaterial (flags.GetStringFlag ("material", "")); + tlo->SetLayer (int(flags.GetNumFlag ("layer", 1))); + if (flags.NumFlagDefined ("maxh")) + tlo->SetMaxH (flags.GetNumFlag("maxh", 1e10)); + } + + else + + { // a surface TLO + + string surfname = scan.GetStringValue(); + scan.ReadNext(); + + Flags flags; + ParseFlags (scan, flags); + + ParseChar (scan, ';'); + + ARRAY<int> si; + geom->GetSolid(surfname)->GetSurfaceIndices(si); + int tlonr = + geom->SetTopLevelObject ((Solid*)geom->GetSolid(name), + (Surface*)geom->GetSurface(si.Get(1))); + TopLevelObject * tlo = geom->GetTopLevelObject (tlonr); + if (flags.NumListFlagDefined ("col")) + { + const ARRAY<double> & col = flags.GetNumListFlag ("col"); + tlo->SetRGB (col.Get(1), col.Get(2), col.Get(3)); + } + if (flags.GetDefineFlag ("transparent")) + tlo->SetTransparent (1); + + if (flags.NumFlagDefined ("maxh")) + tlo->SetMaxH (flags.GetNumFlag("maxh", 1e10)); + tlo->SetLayer (int(flags.GetNumFlag ("layer", 1))); + tlo->SetBCProp (int(flags.GetNumFlag ("bc", -1))); + } + } + + else if (scan.GetToken() == TOK_IDENTIFY) + + { + + scan.ReadNext(); + switch (scan.GetToken()) + { + case TOK_CLOSESURFACES: + { + scan.ReadNext(); + + string name1 = scan.GetStringValue(); + scan.ReadNext(); + + string name2 = scan.GetStringValue(); + scan.ReadNext(); + + Flags flags; + ParseFlags (scan, flags); + + ParseChar (scan, ';'); + + + ARRAY<int> si1, si2; + geom->GetSolid(name1)->GetSurfaceIndices(si1); + geom->GetSolid(name2)->GetSurfaceIndices(si2); + + const TopLevelObject * domain = + geom->GetTopLevelObject (geom->GetSolid(flags.GetStringFlag ("tlo",""))); + + geom->AddIdentification + (new CloseSurfaceIdentification + (geom->GetNIdentifications()+1, *geom, + geom->GetSurface (si1[0]), geom->GetSurface (si2[0]), + domain, + flags)); + + break; + } + + case TOK_PERIODIC: + { + scan.ReadNext(); + + string name1 = scan.GetStringValue(); + scan.ReadNext(); + + string name2 = scan.GetStringValue(); + scan.ReadNext(); + + ParseChar (scan, ';'); + + + ARRAY<int> si1, si2; + geom->GetSolid(name1)->GetSurfaceIndices(si1); + geom->GetSolid(name2)->GetSurfaceIndices(si2); + + geom->AddIdentification + (new PeriodicIdentification + (geom->GetNIdentifications()+1, + *geom, + geom->GetSurface (si1.Get(1)), + geom->GetSurface (si2.Get(1)))); + break; + } + + default: + scan.Error ("keyword 'closesurfaces' or 'periodic' expected"); + } + + } + + else if (scan.GetToken() == TOK_SINGULAR) + + { + + scan.ReadNext(); + switch (scan.GetToken()) + { + case TOK_FACE: + { + scan.ReadNext(); + + string name1 = scan.GetStringValue(); // tlo + scan.ReadNext(); + + string name2 = scan.GetStringValue(); + scan.ReadNext(); + + Flags flags; + ParseFlags (scan, flags); + + ParseChar (scan, ';'); + + const Solid * sol = geom->GetSolid(name2); + + for (int i = 0; i < geom->GetNTopLevelObjects(); i++) + if (name1 == geom->GetTopLevelObject (i)->GetSolid()->Name()) + geom->singfaces.Append (new SingularFace (i+1, sol)); + + break; + } + + case TOK_EDGE: + { + scan.ReadNext(); + + string name1 = scan.GetStringValue(); + scan.ReadNext(); + + string name2 = scan.GetStringValue(); + scan.ReadNext(); + + Flags flags; + ParseFlags (scan, flags); + + ParseChar (scan, ';'); + + const Solid * s1 = geom->GetSolid(name1); + const Solid * s2 = geom->GetSolid(name2); + geom->singedges.Append (new SingularEdge (1, s1, s2)); + 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); + + ParseChar (scan, ';'); + + const Solid * s1 = geom->GetSolid(name1); + const Solid * s2 = geom->GetSolid(name2); + const Solid * s3 = geom->GetSolid(name3); + geom->singpoints.Append (new SingularPoint (1, s1, s2, s3)); + 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, ')'); + ParseChar (scan, ';'); + + geom->AddUserPoint (p); + } + + 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_BOUNDARYCONDITION) + { + scan.ReadNext(); + + string name1 = scan.GetStringValue(); + scan.ReadNext(); + + string name2 = scan.GetStringValue(); + scan.ReadNext(); + + int num = int (ParseNumber (scan)); + ParseChar (scan, ';'); + + + CSGeometry::BCModification bcm; + ARRAY<int> si; + + geom->GetSolid(name1)->GetSurfaceIndices(si); + + bcm.tlonr = -1; + int i; + for (i = 0; i < geom->GetNTopLevelObjects(); i++) + if (string (geom->GetTopLevelObject(i)->GetSolid()->Name()) + == name2) + { + bcm.tlonr = i; + break; + } + + bcm.bcnr = num; + for (i = 0; i < si.Size(); i++) + { + bcm.si = si[i]; + geom->bcmodifications.Append (bcm); + } + } + + else + { + cout << "read unidentified token " << scan.GetToken() + << " string = " << scan.GetStringValue() << endl; + scan.ReadNext(); + } + } + } + catch (string errstr) + { + cout << "caught error " << errstr << endl; + throw NgException (errstr); + } + + + return geom; + /* + do + { + scan.ReadNext(); + if (scan.GetToken() == TOK_STRING) + cout << "found string " << scan.GetStringValue() << endl; + else + cout << "token = " << int(scan.GetToken()) << endl; + } + while (scan.GetToken() != TOK_END); + */ + } + + +}; + diff --git a/contrib/Netgen/libsrc/csg/csgparser_dalibor.cpp b/contrib/Netgen/libsrc/csg/csgparser_dalibor.cpp new file mode 100644 index 0000000000..7f640864a3 --- /dev/null +++ b/contrib/Netgen/libsrc/csg/csgparser_dalibor.cpp @@ -0,0 +1,1111 @@ +#include <mystdlib.h> +#include <myadt.hpp> + +#include <linalg.hpp> +#include <csg.hpp> + + +namespace netgen +{ + using namespace netgen; + + + enum TOKEN_TYPE + { + TOK_MINUS = '-', TOK_LP = '(', OK_RP = ')', TOK_LSP = '[', TOK_RSP = ']', + TOK_EQU = '=', TOK_COMMA = ',', TOK_SEMICOLON = ';', + TOK_NUM = 100, TOK_STRING, TOK_NAMED_SOLID, TOK_PRIMITIVE, + TOK_OR, TOK_AND, TOK_NOT, + TOK_TRANSLATE, TOK_MULTITRANSLATE, TOK_ROTATE, TOK_MULTIROTATE, + TOK_SINGULAR, TOK_EDGE, TOK_POINT, TOK_IDENTIFY, TOK_CLOSESURFACES, + TOK_CLOSEEDGES, TOK_PERIODIC, + TOK_SOLID, TOK_RECO, TOK_TLO, TOK_BOUNDINGBOX, TOK_BOUNDARYCONDITION, + TOK_END }; + + struct kwstruct + { + TOKEN_TYPE kw; + char * name; + }; + + static kwstruct defkw[] = + { + { TOK_RECO, "algebraic3d" }, + { TOK_SOLID, "solid" }, + { TOK_TLO, "tlo" }, + { TOK_BOUNDINGBOX, "boundingbox" }, + { TOK_OR, "or" }, + { TOK_AND, "and" }, + { TOK_NOT, "not" }, + { TOK_TRANSLATE, "translate" }, + { TOK_MULTITRANSLATE, "multitranslate" }, + { TOK_ROTATE, "rotate" }, + { TOK_MULTIROTATE, "multirotate" }, + { TOK_SINGULAR, "singular" }, + { TOK_EDGE, "edge" }, + { TOK_POINT, "point" }, + { TOK_IDENTIFY, "identify" }, + { TOK_CLOSESURFACES, "closesurfaces" }, + { TOK_CLOSEEDGES, "closeedges" }, + { TOK_PERIODIC, "periodic" }, + { TOK_BOUNDARYCONDITION, "boundarycondition" }, + { TOKEN_TYPE(0) } + }; + + enum PRIMITIVE_TYPE + { TOK_SPHERE = 1, TOK_CYLINDER, TOK_PLANE, TOK_ELLIPTICCYLINDER, + TOK_ELLIPSOID, + TOK_CONE, TOK_TUBE, + TOK_GENCYL, TOK_ORTHOBRICK, TOK_POLYHEDRON, TOK_EXTRUSION, TOK_REVOLUTION }; + + struct primstruct + { + PRIMITIVE_TYPE kw; + char * name; + }; + + static primstruct defprim[] = + { + { TOK_PLANE, "plane" }, + { TOK_SPHERE, "sphere" }, + { TOK_CYLINDER, "cylinder" }, + { TOK_CONE, "cone" }, + { TOK_ELLIPTICCYLINDER, "ellipticcylinder" }, + { TOK_ELLIPSOID, "ellipsoid" }, + { TOK_TUBE, "tube" }, + { TOK_GENCYL, "gencyl" }, + { TOK_ORTHOBRICK, "orthobrick" }, + { TOK_POLYHEDRON, "polyhedron" }, + { TOK_EXTRUSION, "extrusion" }, + { TOK_REVOLUTION, "revolution" }, + { PRIMITIVE_TYPE(0) } + }; + + + + static CSGeometry * geom; + + /* +%token <solidtype> TOK_SPHERE TOK_CYLINDER TOK_CONE TOK_PLAIN TOK_TUBE TOK_GENCYL TOK_ORTHOBRICK TOK_POLYHEDRON TOK_REVOLUTION +%left <solidtype> TOK_OR TOK_AND TOK_NOT +%token <solidtype> TOK_TRANSLATE TOK_MULTITRANSLATE TOK_ROTATE TOK_MULTIROTATE +%type <solidtype> solid solidprimitive +%type <void> splinesegmentlist splinesegment readbspline bsplinepointlist +%type <chptr> anyident +%token TOK_SINGULAR TOK_EDGE TOK_POINT +%token TOK_IDENTIFY TOK_CLOSESURFACES TOK_CLOSEEDGES TOK_PERIODIC +%token TOK_BOUNDARYCONDITION +%type <void> polyhedronpoints polyhedronfaces polyhedronpoint polyhedronface +%type <void> revolutionpoints revolutionpoint + */ + + + + class CSGScanner + { + TOKEN_TYPE token; + PRIMITIVE_TYPE prim_token; + double num_value; + string string_value; + + int linenum; + istream * scanin; + + public: + + CSGScanner (istream & ascanin); + + TOKEN_TYPE GetToken() const + { return token; } + + double GetNumValue() const + { return num_value; } + + const string & GetStringValue() const + { return string_value; } + + PRIMITIVE_TYPE GetPrimitiveToken() const + { return prim_token; } + + void ReadNext(); + void Error (const string & err); + }; + + + CSGScanner :: CSGScanner (istream & ascanin) + { + int i; + + scanin = &ascanin; + token = TOK_END; + num_value = 0; + linenum = 1; + } + + + void CSGScanner :: ReadNext () + { + char ch; + + + // whitespaces ueberspringen + do + { + scanin->get(ch); + + if (ch == '\n') + linenum++; + + // end of file reached + if (scanin->eof()) + { + token = TOK_END; + return; + } + + // skip comment line + if (ch == '#') + { + while (ch != '\n') + { + scanin->get(ch); + if (scanin->eof()) + { + token = TOK_END; + return; + } + } + linenum++; + } + } + while (isspace(ch)); + + switch (ch) + { + case '(': case ')': + case '[': case ']': + case '-': + case '=': case ',': case ';': + { + token = TOKEN_TYPE (ch); + break; + } + + default: + { + if (isdigit (ch) || ch == '.') + { + scanin->putback (ch); + (*scanin) >> num_value; + token = TOK_NUM; + return; + } + + if (isalpha (ch)) + { + string_value = string (1, ch); + scanin->get(ch); + while (isalnum(ch)) + { + string_value += ch; + scanin->get(ch); + } + scanin->putback (ch); + } + /* + (*scanin).putback (ch); + (*scanin) >> string_value; + */ + int nr = 0; + while (defkw[nr].kw) + { + if (string_value == defkw[nr].name) + { + token = defkw[nr].kw; + return; + } + nr++; + } + + nr = 0; + while (defprim[nr].kw) + { + if (string_value == defprim[nr].name) + { + token = TOK_PRIMITIVE; + prim_token = defprim[nr].kw; + return; + } + nr++; + } + + token = TOK_STRING; + } + } + } + + void CSGScanner :: Error (const string & err) + { + stringstream errstr; + errstr << "Parsing error in line " << linenum << ": " << endl << err << endl; + throw string(errstr.str()); + } + + + /* + Solid = Term { OR Term } + Term = Primary { AND Primary } + Primary = PRIM | IDENT | ( Solid ) | NOT Primary + */ + + void ParseChar (CSGScanner & scan, char ch) + { + char str[2]; + str[0] = ch; + str[1] = 0; + if (scan.GetToken() != TOKEN_TYPE(ch)) + scan.Error (string ("token '") + string(str) + string("' expected")); + scan.ReadNext(); + } + + double ParseNumber(CSGScanner & scan) + { + if (scan.GetToken() == '-') + { + scan.ReadNext(); + return -ParseNumber (scan); + } + if (scan.GetToken() != TOK_NUM) scan.Error ("number expected"); + double val = scan.GetNumValue(); + scan.ReadNext(); + return val; + } + + + Solid * ParseSolid (CSGScanner & scan); + Solid * ParseTerm (CSGScanner & scan); + Solid * ParsePrimary (CSGScanner & scan); + + + Solid * ParsePrimary (CSGScanner & scan) + { + if (scan.GetToken() == TOK_PRIMITIVE) + { + // cout << "prim token = " << int (scan.GetPrimitiveToken()) << endl; + switch (scan.GetPrimitiveToken()) + { + case TOK_PLANE: + { + Point<3> p; + Vec<3> v; + + scan.ReadNext(); + + ParseChar (scan, '('); + p(0) = ParseNumber (scan); + ParseChar (scan, ','); + p(1) = ParseNumber (scan); + ParseChar (scan, ','); + p(2) = ParseNumber (scan); + ParseChar (scan, ';'); + v(0) = ParseNumber (scan); + ParseChar (scan, ','); + v(1) = ParseNumber (scan); + ParseChar (scan, ','); + v(2) = ParseNumber (scan); + ParseChar (scan, ')'); + + // cout << "define plane, p = " << p << "; v = " << v << endl; + OneSurfacePrimitive * surf = new Plane ( p, v ); + + geom->AddSurface (surf); + surf->SetSurfaceId (0, geom->GetNSurf()-1); + + return new Solid (surf); + } + case TOK_CYLINDER: + { + Point<3> pa, pb; + double r; + + scan.ReadNext(); + + ParseChar (scan, '('); + pa(0) = ParseNumber (scan); + ParseChar (scan, ','); + pa(1) = ParseNumber (scan); + ParseChar (scan, ','); + pa(2) = ParseNumber (scan); + ParseChar (scan, ';'); + pb(0) = ParseNumber (scan); + ParseChar (scan, ','); + pb(1) = ParseNumber (scan); + ParseChar (scan, ','); + pb(2) = ParseNumber (scan); + ParseChar (scan, ';'); + r = ParseNumber (scan); + ParseChar (scan, ')'); + + OneSurfacePrimitive * surf = new Cylinder ( pa, pb, r ); + + geom->AddSurface (surf); + surf->SetSurfaceId (0, geom->GetNSurf()-1); + + return new Solid (surf); + } + + case TOK_ELLIPTICCYLINDER: + { + Point<3> pa; + Vec<3> vl, vs; + + scan.ReadNext(); + + ParseChar (scan, '('); + pa(0) = ParseNumber (scan); + ParseChar (scan, ','); + pa(1) = ParseNumber (scan); + ParseChar (scan, ','); + pa(2) = ParseNumber (scan); + ParseChar (scan, ';'); + + vl(0) = ParseNumber (scan); + ParseChar (scan, ','); + vl(1) = ParseNumber (scan); + ParseChar (scan, ','); + vl(2) = ParseNumber (scan); + ParseChar (scan, ';'); + + vs(0) = ParseNumber (scan); + ParseChar (scan, ','); + vs(1) = ParseNumber (scan); + ParseChar (scan, ','); + vs(2) = ParseNumber (scan); + ParseChar (scan, ')'); + + OneSurfacePrimitive * surf = new EllipticCylinder ( pa, vl, vs); + + geom->AddSurface (surf); + surf->SetSurfaceId (0, geom->GetNSurf()-1); + + return new Solid (surf); + } + + + case TOK_ELLIPSOID: + { + Point<3> pa; + Vec<3> v1, v2, v3; + + scan.ReadNext(); + + ParseChar (scan, '('); + pa(0) = ParseNumber (scan); + ParseChar (scan, ','); + pa(1) = ParseNumber (scan); + ParseChar (scan, ','); + pa(2) = ParseNumber (scan); + ParseChar (scan, ';'); + + v1(0) = ParseNumber (scan); + ParseChar (scan, ','); + v1(1) = ParseNumber (scan); + ParseChar (scan, ','); + v1(2) = ParseNumber (scan); + ParseChar (scan, ';'); + + v2(0) = ParseNumber (scan); + ParseChar (scan, ','); + v2(1) = ParseNumber (scan); + ParseChar (scan, ','); + v2(2) = ParseNumber (scan); + ParseChar (scan, ';'); + + v3(0) = ParseNumber (scan); + ParseChar (scan, ','); + v3(1) = ParseNumber (scan); + ParseChar (scan, ','); + v3(2) = ParseNumber (scan); + ParseChar (scan, ')'); + + OneSurfacePrimitive * surf = new Ellipsoid ( pa, v1, v2, v3); + + geom->AddSurface (surf); + surf->SetSurfaceId (0, geom->GetNSurf()-1); + + return new Solid (surf); + } + + + case TOK_CONE: + { + Point<3> pa, pb; + double ra, rb; + + scan.ReadNext(); + + ParseChar (scan, '('); + pa(0) = ParseNumber (scan); + ParseChar (scan, ','); + pa(1) = ParseNumber (scan); + ParseChar (scan, ','); + pa(2) = ParseNumber (scan); + ParseChar (scan, ';'); + ra = ParseNumber (scan); + ParseChar (scan, ';'); + pb(0) = ParseNumber (scan); + ParseChar (scan, ','); + pb(1) = ParseNumber (scan); + ParseChar (scan, ','); + pb(2) = ParseNumber (scan); + ParseChar (scan, ';'); + rb = ParseNumber (scan); + ParseChar (scan, ')'); + + OneSurfacePrimitive * surf = new Cone ( pa, pb, ra, rb); + + geom->AddSurface (surf); + surf->SetSurfaceId (0, geom->GetNSurf()-1); + + return new Solid (surf); + } + + + + + case TOK_SPHERE: + { + Point<3> p; + double r; + + scan.ReadNext(); + + ParseChar (scan, '('); + p(0) = ParseNumber (scan); + ParseChar (scan, ','); + p(1) = ParseNumber (scan); + ParseChar (scan, ','); + p(2) = ParseNumber (scan); + ParseChar (scan, ';'); + r = ParseNumber (scan); + ParseChar (scan, ')'); + + // cout << "define sphere, c = " << p << ", rad = " << r << endl; + OneSurfacePrimitive * surf = new Sphere ( p, r ); + + geom->AddSurface (surf); + surf->SetSurfaceId (0, geom->GetNSurf()-1); + + return new Solid (surf); + } + + case TOK_ORTHOBRICK: + { + Point<3> pa, pb; + + scan.ReadNext(); + + ParseChar (scan, '('); + pa(0) = ParseNumber (scan); + ParseChar (scan, ','); + pa(1) = ParseNumber (scan); + ParseChar (scan, ','); + pa(2) = ParseNumber (scan); + ParseChar (scan, ';'); + pb(0) = ParseNumber (scan); + ParseChar (scan, ','); + pb(1) = ParseNumber (scan); + ParseChar (scan, ','); + pb(2) = ParseNumber (scan); + ParseChar (scan, ')'); + + // cout << "define orthobrick, p1 = " << pa << "; p2 = " << pb << endl; + + Primitive * nprim = new OrthoBrick (pa, pb); + + for (int j = 0; j < nprim->GetNSurfaces(); j++) + { + geom->AddSurface (&nprim->GetSurface(j)); + nprim->SetSurfaceId (j, geom->GetNSurf()-1); + } + return new Solid (nprim); + } + + + case TOK_EXTRUSION: + { + Point<3> p0; + Vec<3> ex, ey; + ARRAY<Point<2> > points; + + scan.ReadNext(); + + ParseChar (scan, '('); + p0(0) = ParseNumber (scan); + ParseChar (scan, ','); + p0(1) = ParseNumber (scan); + ParseChar (scan, ','); + p0(2) = ParseNumber (scan); + ParseChar (scan, ';'); + + ex(0) = ParseNumber (scan); + ParseChar (scan, ','); + ex(1) = ParseNumber (scan); + ParseChar (scan, ','); + ex(2) = ParseNumber (scan); + ParseChar (scan, ';'); + + ey(0) = ParseNumber (scan); + ParseChar (scan, ','); + ey(1) = ParseNumber (scan); + ParseChar (scan, ','); + ey(2) = ParseNumber (scan); + ParseChar (scan, ';'); + + cout << "p0 = " << p0 << endl; + + int npseg = 0; + int nseg = 0; + while (1) + { + Point<2> p1, p2, p3; + + p1(0) = ParseNumber(scan); + ParseChar (scan, ','); + p1(1) = ParseNumber(scan); + points.Append (p1); + if (scan.GetToken() == ')') + { + scan.ReadNext(); + break; + } + scan.ReadNext(); + } + + + /* + while (1) + { + Point<2> p1, p2, p3; + + p3 = p2; + p2 = p1; + p1(0) = ParseNumber(scan); + ParseChar (scan, ','); + p1(1) = ParseNumber(scan); + npseg++; + + cout << "p1 = " << p1 << endl; + + if (scan.GetToken() == ';' || scan.GetToken() == ')') + { + if (npseg == 2) + { + p3 = p2; + p2 = Center (p1, p3); + } + if (nseg == 0) + points.Append (p3); + points.Append (p2); + points.Append (p1); + npseg = 1; + nseg++; + + cout << "p1, = " << p1 << ", p2 = " << p2 << ", p3 = " << p3 << endl; + } + + if (scan.GetToken() == ')') + { + scan.ReadNext(); + break; + } + if (scan.GetToken() == ';' || scan.GetToken() == ',') + { + scan.ReadNext(); + } + } + */ + cout << "p0 = " << p0 << endl; + cout << ", ex = " << ex << ", ey = " << ey << endl; + cout << "points = " << points << endl; + + Extrusion * extrusion = new Extrusion (p0, ex, ey, points); + + for (int i = 0; i < extrusion->GetNSurfaces(); i++) + { + geom->AddSurface (&extrusion->GetSurface(i)); + extrusion->SetSurfaceId(i, geom->GetNSurf()-1); + } + return new Solid (extrusion); + + /* + // cout << "define cylinder, pa = " << pa << "; pb = " << pb + // << ", rad = " << r << endl; + OneSurfacePrimitive * surf = new Cylinder ( pa, pb, r ); + + geom->AddSurface (surf); + surf->SetSurfaceId (0, geom->GetNSurf()-1); + + return new Solid (surf); + */ + } + + +// Added by Dalibor Lukas, October 15, 2003 + case TOK_POLYHEDRON: + { + Point<3> p; + int pi1, pi2, pi3, pi4; + + scan.ReadNext(); + ParseChar (scan, '('); + + Polyhedra * polyhedron = new Polyhedra; + + // scanning the points + while (1) + { + p(0) = ParseNumber (scan); + ParseChar (scan, ','); + p(1) = ParseNumber (scan); + ParseChar (scan, ','); + p(2) = ParseNumber (scan); + ParseChar (scan, ';'); + + cout << "point = " << p << endl; + + polyhedron->AddPoint(p); + + if (scan.GetToken() == ';') + { + scan.ReadNext(); + break; + } + } + + // scanning the faces + while (1) + { + pi1 = (int) (ParseNumber (scan)); + ParseChar (scan, ','); + pi2 = (int) (ParseNumber (scan)); + ParseChar (scan, ','); + pi3 = (int) (ParseNumber (scan)); + ParseChar (scan, ','); + pi4 = (int) (ParseNumber (scan)); + + cout << "face = (" << pi1 << ", " << pi2 << ", " << pi3 + << ", " << pi4 << ")" << endl; + + polyhedron->AddFace(pi1-1,pi2-1,pi3-1); + polyhedron->AddFace(pi1-1,pi3-1,pi4-1); + + if (scan.GetToken() == ')') + { + scan.ReadNext(); + break; + } + scan.ReadNext(); + } + + int j; + for (j = 0; j < polyhedron->GetNSurfaces(); j++) + { + geom->AddSurface (&polyhedron->GetSurface(j)); + polyhedron->SetSurfaceId (j, geom->GetNSurf()-1); + } + + return new Solid (polyhedron); + } +// DL + + + } + cout << "unknown primary " << scan.GetStringValue() << endl; + } + + else if (scan.GetToken() == TOK_STRING && + geom->GetSolid(scan.GetStringValue())) + + { + Solid * sol = const_cast<Solid*> (geom->GetSolid(scan.GetStringValue())); + scan.ReadNext(); + return sol; + } + + else if (scan.GetToken() == TOK_NOT) + + { + scan.ReadNext(); + Solid * sol1 = ParsePrimary (scan); + return new Solid (Solid::SUB, sol1); + } + + else if (scan.GetToken() == '(') + + { + scan.ReadNext(); + Solid * sol1 = ParseSolid (scan); + scan.ReadNext(); + return sol1; + } + + scan.Error (string ("not a primary, name = ")+ + scan.GetStringValue()); + return 0; + } + + + Solid * ParseTerm (CSGScanner & scan) + { + Solid * sol = ParsePrimary(scan); + while (scan.GetToken() == TOK_AND) + { + scan.ReadNext(); + Solid * sol2 = ParsePrimary(scan); + sol = new Solid (Solid::SECTION, sol, sol2); + } + return sol; + } + + Solid * ParseSolid (CSGScanner & scan) + { + Solid * sol = ParseTerm(scan); + while (scan.GetToken() == TOK_OR) + { + scan.ReadNext(); + Solid * sol2 = ParseTerm(scan); + sol = new Solid (Solid::UNION, sol, sol2); + } + return sol; + } + + + + void ParseFlags (CSGScanner & scan, Flags & flags) + { + while (scan.GetToken() == '-') + { + scan.ReadNext(); + string name = scan.GetStringValue(); + scan.ReadNext(); + if (scan.GetToken() == '=') + { + scan.ReadNext(); + if (scan.GetToken() == TOK_STRING) + { + flags.SetFlag (name.c_str(), scan.GetStringValue().c_str()); + scan.ReadNext(); + } + else if (scan.GetToken() == '[') + { + scan.ReadNext(); + ARRAY<double> vals; + vals.Append (ParseNumber(scan)); + while (scan.GetToken() == ',') + { + scan.ReadNext(); + vals.Append (ParseNumber(scan)); + } + ParseChar (scan, ']'); + flags.SetFlag (name.c_str(), vals); + } + else if (scan.GetToken() == TOK_NUM) + { + flags.SetFlag (name.c_str(), scan.GetNumValue()); + scan.ReadNext(); + } + } + else + { + flags.SetFlag (name.c_str()); + } + } + } + + + /* + Main parsing function for CSG geometry + */ + CSGeometry * ParseCSG (istream & istr) + { + CSGScanner scan(istr); + + geom = new CSGeometry; + + scan.ReadNext(); + if (scan.GetToken() != TOK_RECO) // keyword 'algebraic3d' + return 0; + scan.ReadNext(); + + try + { + while (1) + { + if (scan.GetToken() == TOK_END) break; + + if (scan.GetToken() == TOK_SOLID) + { + scan.ReadNext(); + if (scan.GetToken() != TOK_STRING) + scan.Error ("name identifier expected"); + string solidname = scan.GetStringValue(); + + scan.ReadNext(); + + ParseChar (scan, '='); + Solid * solid = ParseSolid (scan); + + Flags flags; + ParseFlags (scan, flags); + + geom->SetSolid (solidname.c_str(), new Solid (Solid::ROOT, solid)); + geom->SetFlags (solidname.c_str(), flags); + + ParseChar (scan, ';'); + + PrintMessage (4, "define solid ", solidname); + } + + else if (scan.GetToken() == TOK_TLO) + + { // a TopLevelObject definition + + scan.ReadNext(); + + string name = scan.GetStringValue(); + scan.ReadNext(); + + if (scan.GetToken() != TOK_STRING) + + { // a solid TLO + + Flags flags; + ParseFlags (scan, flags); + + ParseChar (scan, ';'); + + int tlonr = + geom->SetTopLevelObject ((Solid*)geom->GetSolid(name)); + TopLevelObject * tlo = geom->GetTopLevelObject (tlonr); + if (flags.NumListFlagDefined ("col")) + { + const ARRAY<double> & col = + flags.GetNumListFlag ("col"); + tlo->SetRGB (col[0], col[1], col[2]); + } + + if (flags.GetDefineFlag ("transparent")) + tlo->SetTransparent (1); + + tlo->SetMaterial (flags.GetStringFlag ("material", "")); + tlo->SetLayer (int(flags.GetNumFlag ("layer", 1))); + if (flags.NumFlagDefined ("maxh")) + tlo->SetMaxH (flags.GetNumFlag("maxh", 1e10)); + } + + else + + { // a surface TLO + + string surfname = scan.GetStringValue(); + scan.ReadNext(); + + Flags flags; + ParseFlags (scan, flags); + + ParseChar (scan, ';'); + + ARRAY<int> si; + geom->GetSolid(surfname)->GetSurfaceIndices(si); + int tlonr = + geom->SetTopLevelObject ((Solid*)geom->GetSolid(name), + (Surface*)geom->GetSurface(si.Get(1))); + TopLevelObject * tlo = geom->GetTopLevelObject (tlonr); + if (flags.NumListFlagDefined ("col")) + { + const ARRAY<double> & col = flags.GetNumListFlag ("col"); + tlo->SetRGB (col.Get(1), col.Get(2), col.Get(3)); + } + if (flags.GetDefineFlag ("transparent")) + tlo->SetTransparent (1); + + if (flags.NumFlagDefined ("maxh")) + tlo->SetMaxH (flags.GetNumFlag("maxh", 1e10)); + tlo->SetLayer (int(flags.GetNumFlag ("layer", 1))); + tlo->SetBCProp (int(flags.GetNumFlag ("bc", -1))); + } + } + + else if (scan.GetToken() == TOK_IDENTIFY) + + { + + scan.ReadNext(); + switch (scan.GetToken()) + { + case TOK_CLOSESURFACES: + { + scan.ReadNext(); + + string name1 = scan.GetStringValue(); + scan.ReadNext(); + + string name2 = scan.GetStringValue(); + scan.ReadNext(); + + Flags flags; + ParseFlags (scan, flags); + + ParseChar (scan, ';'); + + + ARRAY<int> si1, si2; + geom->GetSolid(name1)->GetSurfaceIndices(si1); + geom->GetSolid(name2)->GetSurfaceIndices(si2); + + geom->AddIdentification + (new CloseSurfaceIdentification + (geom->GetNIdentifications()+1, *geom, + geom->GetSurface (si1[0]), geom->GetSurface (si2[0]), + flags)); + break; + } + + case TOK_PERIODIC: + { + scan.ReadNext(); + + string name1 = scan.GetStringValue(); + scan.ReadNext(); + + string name2 = scan.GetStringValue(); + scan.ReadNext(); + + ParseChar (scan, ';'); + + + ARRAY<int> si1, si2; + geom->GetSolid(name1)->GetSurfaceIndices(si1); + geom->GetSolid(name2)->GetSurfaceIndices(si2); + + geom->AddIdentification + (new PeriodicIdentification + (geom->GetNIdentifications()+1, + *geom, + geom->GetSurface (si1.Get(1)), + geom->GetSurface (si2.Get(1)))); + break; + } + } + + } + + else if (scan.GetToken() == TOK_POINT) + { + Point<3> p; + + scan.ReadNext(); + ParseChar (scan, '('); + p(0) = ParseNumber (scan); + ParseChar (scan, ','); + p(1) = ParseNumber (scan); + ParseChar (scan, ','); + p(2) = ParseNumber (scan); + ParseChar (scan, ')'); + ParseChar (scan, ';'); + + geom->AddUserPoint (p); + } + + else if (scan.GetToken() == TOK_BOUNDINGBOX) + { + Point<3> p1, p2; + + scan.ReadNext(); + ParseChar (scan, '('); + p1(0) = ParseNumber (scan); + ParseChar (scan, ','); + p1(1) = ParseNumber (scan); + ParseChar (scan, ','); + p1(2) = ParseNumber (scan); + ParseChar (scan, ';'); + p2(0) = ParseNumber (scan); + ParseChar (scan, ','); + p2(1) = ParseNumber (scan); + ParseChar (scan, ','); + p2(2) = ParseNumber (scan); + ParseChar (scan, ')'); + ParseChar (scan, ';'); + + geom->SetBoundingBox (Box<3> (p1, p2)); + } + + else if (scan.GetToken() == TOK_BOUNDARYCONDITION) + { + scan.ReadNext(); + + string name1 = scan.GetStringValue(); + scan.ReadNext(); + + string name2 = scan.GetStringValue(); + scan.ReadNext(); + + int num = int (ParseNumber (scan)); + ParseChar (scan, ';'); + + + CSGeometry::BCModification bcm; + ARRAY<int> si; + + geom->GetSolid(name1)->GetSurfaceIndices(si); + + bcm.tlonr = -1; + int i; + for (i = 0; i < geom->GetNTopLevelObjects(); i++) + if (string (geom->GetTopLevelObject(i)->GetSolid()->Name()) + == name2) + { + bcm.tlonr = i; + break; + } + + bcm.bcnr = num; + for (i = 0; i < si.Size(); i++) + { + bcm.si = si[i]; + geom->bcmodifications.Append (bcm); + } + } + + else + { + cout << "read unidentified token " << scan.GetToken() + << " string = " << scan.GetStringValue() << endl; + scan.ReadNext(); + } + } + } + catch (string errstr) + { + cout << "caught error " << errstr << endl; + } + + + return geom; + /* + do + { + scan.ReadNext(); + if (scan.GetToken() == TOK_STRING) + cout << "found string " << scan.GetStringValue() << endl; + else + cout << "token = " << int(scan.GetToken()) << endl; + } + while (scan.GetToken() != TOK_END); + */ + } + + +}; + diff --git a/contrib/Netgen/libsrc/csg/csgscanner.cpp b/contrib/Netgen/libsrc/csg/csgscanner.cpp new file mode 100644 index 0000000000..50e2213ea6 --- /dev/null +++ b/contrib/Netgen/libsrc/csg/csgscanner.cpp @@ -0,0 +1,205 @@ +#include <mystdlib.h> +#include <myadt.hpp> + +#include <linalg.hpp> +#include <csg.hpp> + + +namespace netgen +{ + using namespace netgen; + + + enum TOKEN_TYPE + { + LP = '(', RP = ')', EQU = '=', COMMA = ',', SEMICOLON = ';', + TOK_NUM, TOK_STRING, TOK_NAMED_SOLID, TOK_PRIMITIVE, + TOK_OR, TOK_AND, TOK_NOT, + TOK_SOLID, TOK_RECO, TOK_TLO, TOK_BOUNDINGBOX, + TOK_END }; + + struct kwstruct + { + TOKEN_TYPE kw; + string name; + }; + + static kwstruct defkw[] = + { + { TOK_OR, "or" }, + { TOK_AND, "and" }, + { TOKEN_TYPE(0) } + }; + + enum PRIMITIVE_TYPE { TOK_SPHERE, TOK_CYLINDER, TOK_PLANE }; + + /* +%token <solidtype> TOK_SPHERE TOK_CYLINDER TOK_CONE TOK_PLAIN TOK_TUBE TOK_GENCYL TOK_ORTHOBRICK TOK_POLYHEDRON TOK_REVOLUTION +%left <solidtype> TOK_OR TOK_AND TOK_NOT +%token <solidtype> TOK_TRANSLATE TOK_MULTITRANSLATE TOK_ROTATE TOK_MULTIROTATE +%type <solidtype> solid solidprimitive +%type <void> splinesegmentlist splinesegment readbspline bsplinepointlist +%type <chptr> anyident +%token TOK_SINGULAR TOK_EDGE TOK_POINT +%token TOK_IDENTIFY TOK_CLOSESURFACES TOK_CLOSEEDGES TOK_PERIODIC +%token TOK_BOUNDARYCONDITION +%type <void> polyhedronpoints polyhedronfaces polyhedronpoint polyhedronface +%type <void> revolutionpoints revolutionpoint + */ + + + + class CSGScanner + { + TOKEN_TYPE token; + double num_value; + string string_value; + + int linenum; + istream * scanin; + + public: + + CSGScanner (istream & ascanin); + + TOKEN_TYPE GetToken() const + { return token; } + + double GetNumValue() const + { return num_value; } + + const string & GetStringValue() const + { return string_value; } + + void ReadNext(); + + void Error (const string & err); + }; + + + CSGScanner :: CSGScanner (istream & ascanin) + { + int i; + + scanin = &ascanin; + token = TOK_END; + num_value = 0; + linenum = 1; + } + + + void CSGScanner :: ReadNext () + { + char ch; + + + // whitespaces ueberspringen + do + { + scanin->get(ch); + + if (ch == '\n') + linenum++; + + // end of file reached + if (scanin->eof()) + { + token = TOK_END; + return; + } + + // skip comment line + if (ch == '#') + { + while (ch != '\n') + { + scanin->get(ch); + if (scanin->eof()) + { + token = TOK_END; + return; + } + } + linenum++; + } + } + while (isspace(ch)); + + switch (ch) + { + case '(': case ')': + case '=': case ',': case ';': + { + token = TOKEN_TYPE (ch); + break; + } + + default: + { + if (isdigit (ch) || ch == '.' || ch == '-') + { + scanin->putback (ch); + (*scanin) >> num_value; + token = TOK_NUM; + return; + } + + (*scanin).putback (ch); + (*scanin) >> string_value; + + int nr = 0; + while (defkw[nr].kw) + { + if (string_value == defkw[nr].name) + { + token = defkw[nr].kw; + return; + } + } + + token = TOK_STRING; + } + } + } + + void CSGScanner :: Error (const string & err) + { + stringstream errstr; + errstr << "Parsing error in line " << linenum << ": " << endl << err << endl; + /* + errstr << "input continues with <<<"; + for (int i = 0; i < 50; i++) + { + char ch; + scanin->get(ch); + errstr << ch; + if (scanin->eof()) + { + errstr << "(end of file)"; + break; + } + } + errstr << endl << ">>> stop parsing" << endl; + throw Exception (errstr.str()); + */ + } + + + + + + void ParseCSG (istream & istr) + { + CSGScanner scan(istr); + + do + { + scan.ReadNext(); + cout << "token = " << int(scan.GetToken()) << endl; + } + while (scan.GetToken() != TOK_END); + } + + +}; + diff --git a/contrib/Netgen/libsrc/csg/curve2d.cpp b/contrib/Netgen/libsrc/csg/curve2d.cpp new file mode 100644 index 0000000000..7091e87af9 --- /dev/null +++ b/contrib/Netgen/libsrc/csg/curve2d.cpp @@ -0,0 +1,78 @@ +#include <mystdlib.h> + +#include <myadt.hpp> +#include <csg.hpp> + +namespace netgen +{ +CircleCurve2d :: CircleCurve2d (const Point<2> & acenter, double arad) + { + center = acenter; + rad = arad; + } + +void CircleCurve2d :: Project (Point<2> & p) const + { + Vec<2> v = p - center; + v *= rad/v.Length(); + p = center + v; + } + +void CircleCurve2d :: NormalVector (const Point<2> & p, Vec<2> & n) const + { + n = p - center; + n /= n.Length(); + } + + + + + + +QuadraticCurve2d :: QuadraticCurve2d () +{ + cxx = cyy = cxy = cx = cy = c = 0; +} + +void QuadraticCurve2d :: Read (istream & ist) +{ + ist >> cxx >> cyy >> cxy >> cx >> cy >> c; +} + + +void QuadraticCurve2d :: Project (Point<2> & p) const +{ + double f, x, y, gradx, grady, grad2; + int its = 0; + + x = p(0); + y = p(1); + + do + { + f = cxx * x * x + cyy * y * y + cxy * x * y + cx * x + cy * y + c; + gradx = 2 * cxx * x + cxy * y + cx; + grady = 2 * cyy * y + cxy * x + cy; + grad2 = gradx * gradx + grady * grady; + + x -= f * gradx / grad2; + y -= f * grady / grad2; + + // (*mycout) << "x = " << x << " y = " << y << " f = " << f << endl; + its++; + } + while (fabs (f) > 1e-8 && its < 20); + if (its >= 20) + cerr << "QuadraticCurve2d::Project: many iterations, f = " << f << endl; + p(0) = x; + p(1) = y; +} + + +void QuadraticCurve2d :: NormalVector (const Point<2> & p, Vec<2> & n) const +{ + n(0) = 2 * cxx * p(0) + cxy * p(1) + cx; + n(1) = 2 * cyy * p(1) + cxy * p(0) + cy; + n.Normalize(); +} +} diff --git a/contrib/Netgen/libsrc/csg/curve2d.hpp b/contrib/Netgen/libsrc/csg/curve2d.hpp new file mode 100644 index 0000000000..917bd53205 --- /dev/null +++ b/contrib/Netgen/libsrc/csg/curve2d.hpp @@ -0,0 +1,59 @@ +#ifndef FILE_CURVE2D +#define FILE_CURVE2D + +/**************************************************************************/ +/* File: curve2d.hh */ +/* Author: Joachim Schoeberl */ +/* Date: 24. Jul. 96 */ +/**************************************************************************/ + +/* + + 2D Curve repesentation + +*/ + + + +/// +class Curve2d : public Manifold + { + public: + /// + virtual void Project (Point<2> & p) const = 0; + /// + virtual void NormalVector (const Point<2> & p, Vec<2> & n) const = 0; + }; + +/// +class CircleCurve2d : public Curve2d + { + /// + Point<2> center; + /// + double rad; + public: + /// + CircleCurve2d (const Point<2> & acenter, double arad); + /// + virtual void Project (Point<2> & p) const; + /// + virtual void NormalVector (const Point<2> & p, Vec<2> & n) const; + }; + +/// +class QuadraticCurve2d : public Curve2d +{ + /// + double cxx, cyy, cxy, cx, cy, c; +public: + /// + QuadraticCurve2d (); + /// + void Read (istream & ist); + /// + virtual void Project (Point<2> & p) const; + /// + virtual void NormalVector (const Point<2> & p, Vec<2> & n) const; +}; +#endif diff --git a/contrib/Netgen/libsrc/csg/edgeflw.cpp b/contrib/Netgen/libsrc/csg/edgeflw.cpp new file mode 100644 index 0000000000..50b425f84f --- /dev/null +++ b/contrib/Netgen/libsrc/csg/edgeflw.cpp @@ -0,0 +1,1524 @@ +#include <mystdlib.h> +#include <meshing.hpp> +#include <csg.hpp> + +#undef DEVELOP + +namespace netgen +{ + + EdgeCalculation :: + EdgeCalculation (const CSGeometry & ageometry, + ARRAY<SpecialPoint> & aspecpoints) + : geometry(ageometry), specpoints(aspecpoints) + { + Box<3> bbox; + if (specpoints.Size() >= 1) + bbox.Set (specpoints[0].p); + else + { bbox.Set (Point<3> (0,0,0)); bbox.Add (Point<3> (1,1,1)); } + for (int i = 1; i < specpoints.Size(); i++) + bbox.Add (specpoints[i].p); + + 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); + } + + EdgeCalculation :: ~EdgeCalculation() + { + delete searchtree; + delete meshpoint_tree; + } + + + void EdgeCalculation :: Calc(double h, Mesh & mesh) + { + PrintMessage (1, "Find edges"); + PushStatus ("Find edges"); + + CalcEdges1 (h, mesh); + SplitEqualOneSegEdges (mesh); + FindClosedSurfaces (h, mesh); + PrintMessage (3, cntedge, " edges found"); + + PopStatus (); + } + + + + + + void EdgeCalculation :: CalcEdges1 (double h, Mesh & mesh) + { + ARRAY<int> hsp(specpoints.Size()); + ARRAY<int> glob2hsp(specpoints.Size()); + ARRAY<int> startpoints, endpoints; + + int pos, ep; + int layer; + + Point<3> p, np; + int pi1, s1, s2; + + ARRAY<Point<3> > edgepoints; + ARRAY<double> curvelength; + int copyedge, copyfromedge = -1, copyedgeidentification = -1; + + ARRAY<int> locsurfind, locind; + + // double len, corr, lam; + // double steplen, cursteplen, loch, + double hd; + + 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; + } + + + cntedge = 0; + INDEX_2_HASHTABLE<int> identification_used(100); // identification i already used for startpoint j + + + while (hsp.Size()) + { + SetThreadPercent(100 - 100 * double (hsp.Size()) / specpoints.Size()); + + edgepoints.SetSize (0); + curvelength.SetSize (0); + + + pi1 = 0; + copyedge = 0; + // identifyable point available ? + + // (*testout) << endl; + + for (int i = 0; i < geometry.identifications.Size() && !pi1; i++) + for (int j = checkedcopy; j < startpoints.Size() && !pi1; j++) + + if (geometry.identifications[i]->IdentifyableCandidate (specpoints[startpoints[j]])) + + { + int pi1cand = 0; + double mindist = 1e10; + + for (int k = 0; k < hsp.Size() && !pi1; k++) + { + if (identification_used.Used (INDEX_2(i, startpoints[j])) || + identification_used.Used (INDEX_2(i, hsp[k]))) continue; + + if (geometry.identifications[i] + ->Identifyable(specpoints[startpoints[j]], specpoints[hsp[k]]) || + geometry.identifications[i] + ->Identifyable(specpoints[hsp[k]], specpoints[startpoints[j]])) + { + if (Dist (specpoints[startpoints[j]].p, specpoints[hsp[k]].p) < mindist) + { + mindist = Dist (specpoints[startpoints[j]].p, specpoints[hsp[k]].p); + pi1cand = k+1; + } + } + } + + + if (pi1cand) + { + pi1 = pi1cand; + copyedge = 1; + copyfromedge = j+1; + copyedgeidentification = i+1; + + identification_used.Set (INDEX_2(i, startpoints[j]), 1); + identification_used.Set (INDEX_2(i, hsp.Get(pi1)), 1); + } + } + + + // cannot copy from other ege ? + if (!pi1) + checkedcopy = startpoints.Size(); + + // unconditional special point available ? + if (!pi1) + for (int i = 1; i <= hsp.Size(); i++) + if (specpoints[hsp.Get(i)].unconditional == 1) + { + pi1 = i; + break; + } + + + if (!pi1) + { + // only unconditional points available, choose first + 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 && + (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) << "edge nr " << cntedge << endl; + (*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; + + + // 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)); + hd = Dist (p, np); + + + Box<3> boxp (np - (1.2 * hd) * Vec<3> (1, 1, 1), + np + (1.2 * hd) * Vec<3> (1, 1, 1)); + searchtree -> GetIntersecting (boxp.PMin(), boxp.PMax(), locind); + + for (int i = 0; i < locind.Size(); i++) + { + if ( specpoints[locind[i]].HasSurfaces (s1, s2) && + specpoints[locind[i]].unconditional == 0) + { + searchtree -> DeleteElement (locind[i]); + + int li = glob2hsp[locind[i]]; + glob2hsp[locind[i]] = -1; + glob2hsp[hsp.Last()] = li; + hsp.Delete (li); + } + } + + + /* + for (int i = 1; i <= hsp.Size(); i++) + if ( specpoints[hsp.Get(i)].HasSurfaces (s1, s2) && + specpoints[hsp.Get(i)].unconditional == 0 && + Dist2 (np, specpoints[hsp.Get(i)].p) < 1.2 * hd) + { + searchtree -> DeleteElement (hsp.Get(i)+1); + hsp.DeleteElement (i); + i--; + } + */ + } + + + ARRAY<Segment> refedges; + ARRAY<bool> refedgesinv; + + + AnalyzeEdge (s1, s2, pos, layer, + edgepoints, + refedges, refedgesinv); + + for (int i = 0; i < refedges.Size(); i++) + refedges[i].edgenr = cntedge; + + + + +#ifdef DEVELOP + (*testout) << "edge " << cntedge << endl + << "startp: " << specpoints[startpoints.Last()].p + << ", v = " << specpoints[startpoints.Last()].v << endl + // << "copy = " << copyedge << endl + << refedges.Size() << " refedges: "; + for (int i = 1; i <= refedges.Size(); i++) + (*testout) << " " << refedges.Get(i).si; + (*testout) << endl; + (*testout) << "inv[1] = " << refedgesinv.Get(1) << endl; +#endif + + if (!copyedge) + { + // int oldnseg = mesh.GetNSeg(); + + if (!shortedge) + StoreEdge (refedges, refedgesinv, + edgepoints, curvelength, layer, mesh); + else + StoreShortEdge (refedges, refedgesinv, + edgepoints, curvelength, layer, mesh); + + + /* + for (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); + } + + } + } + + + + + + /* + If two or more edges share the same initial and end-points, + then they need at least two segments + */ + void EdgeCalculation :: + SplitEqualOneSegEdges (Mesh & mesh) + { + // int i, j; + SegmentIndex si; + PointIndex pi; + + ARRAY<int> osedges(cntedge); + INDEX_2_HASHTABLE<int> osedgesht (cntedge+1); + + osedges = 2; + + // count segments on edges + for (si = 0; si < mesh.GetNSeg(); si++) + { + const Segment & seg = mesh[si]; + if (seg.seginfo && seg.edgenr >= 1 && seg.edgenr <= cntedge) + osedges.Elem(seg.edgenr)--; + } + + // (*testout) << "osedges = " << osedges << endl; + + // flag one segment edges + for (int i = 0; i < cntedge; i++) + osedges[i] = (osedges[i] > 0) ? 1 : 0; + + // (*testout) << "osedges, now = " << osedges << endl; + + for (si = 0; si < mesh.GetNSeg(); si++) + { + const Segment & seg = mesh[si]; + if (seg.seginfo && seg.edgenr >= 1 && seg.edgenr <= cntedge) + { + if (osedges.Get(seg.edgenr)) + { + INDEX_2 i2(seg.p1, seg.p2); + i2.Sort (); + if (osedgesht.Used (i2)) + osedgesht.Set (i2, 2); + else + osedgesht.Set (i2, 1); + } + } + } + + + // one edge 1 segment, other 2 segments + // yes, it happens ! + point_on_edge_problem = 0; + for (int i = 1; i <= osedgesht.GetNBags(); i++) + for (int j = 1; j <= osedgesht.GetBagSize(i); j++) + { + INDEX_2 i2; + int val; + osedgesht.GetData (i, j, i2, val); + + const Point<3> & p1 = mesh[PointIndex(i2.I1())]; + const Point<3> & p2 = mesh[PointIndex(i2.I2())]; + Vec<3> v = p2 - p1; + double vlen = v.Length(); + v /= vlen; + for (pi = PointIndex::BASE; + pi < mesh.GetNP()+PointIndex::BASE; pi++) + + if (pi != i2.I1() && pi != i2.I2()) + { + const Point<3> & p = mesh[pi]; + Vec<3> v2 = p - p1; + double lam = (v2 * v); + if (lam > 0 && lam < vlen) + { + Point<3> hp = p1 + lam * v; + if (Dist (p, hp) < 1e-4 * vlen) + { + PrintWarning ("Point on edge !!!"); + cout << "seg: " << i2 << ", p = " << pi << endl; + osedgesht.Set (i2, 2); + point_on_edge_problem = 1; + } + } + } + } + + + // insert new points + osedges = -1; + + int nseg = mesh.GetNSeg(); + for (si = 0; si < nseg; si++) + { + const Segment & seg = mesh[si]; + if (seg.seginfo && seg.edgenr >= 1 && seg.edgenr <= cntedge) + { + INDEX_2 i2(seg.p1, seg.p2); + i2.Sort (); + if (osedgesht.Used (i2) && + osedgesht.Get (i2) == 2 && + osedges.Elem(seg.edgenr) == -1) + { + Point<3> newp = Center (mesh[PointIndex(seg.p1)], + mesh[PointIndex(seg.p2)]); + + ProjectToEdge (geometry.GetSurface(seg.surfnr1), + geometry.GetSurface(seg.surfnr2), + newp); + + osedges.Elem(seg.edgenr) = + mesh.AddPoint (newp, mesh[PointIndex(seg.p1)].GetLayer()); + meshpoint_tree -> Insert (newp, osedges.Elem(seg.edgenr)); + } + } + } + + + for (int i = 1; i <= nseg; i++) + { + Segment & seg = mesh.LineSegment (i); + if (seg.edgenr >= 1 && seg.edgenr <= cntedge) + { + if (osedges.Get(seg.edgenr) != -1) + { + Segment newseg = seg; + newseg.p1 = osedges.Get(seg.edgenr); + seg.p2 = osedges.Get(seg.edgenr); + mesh.AddSegment (newseg); + } + } + } + + } + + + + void EdgeCalculation :: + FollowEdge (int pi1, int & ep, int & pos, + const ARRAY<int> & hsp, + double h, const Mesh & mesh, + ARRAY<Point<3> > & edgepoints, + ARRAY<double> & curvelength) + { + int s1, s2; + double len, steplen, cursteplen, loch; + Point<3> p, np, pnp; + Vec<3> a1, a2, t; + + ARRAY<int> locind; + + double size = geometry.MaxSize(); + double epspointdist2 = size * 1e-6; + epspointdist2 = sqr (epspointdist2); + int uselocalh = mparam.uselocalh; + + + s1 = specpoints[hsp.Get(pi1)].s1; + s2 = specpoints[hsp.Get(pi1)].s2; + + p = specpoints[hsp.Get(pi1)].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; + + loch = min2 (geometry.GetSurface(s1) -> LocH (p, 3, 1, h), + geometry.GetSurface(s2) -> LocH (p, 3, 1, h)); + + + + if (uselocalh) + { + double lh = mesh.GetH(p); + if (lh < loch) + loch = lh; + } + + steplen = 0.1 * loch; + + do + { + if (multithread.terminate) + return; + + if (fabs (p(0)) + fabs (p(1)) + fabs (p(2)) > 100000) + { + 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) -> LocH (np, 3, 1, h), + geometry.GetSurface(s2) -> LocH (np, 3, 1, h)); + + if (uselocalh) + { + double lh = mesh.GetH(np); + if (lh < loch) + loch = lh; + } + + + len += Dist (p, np) / loch; + edgepoints.Append (np); + curvelength.Append (len); + + p = np; + + geometry.GetSurface(s1) -> CalcGradient (p, a1); + geometry.GetSurface(s2) -> CalcGradient (p, a2); + t = Cross (a1, a2); + t.Normalize(); + if (!pos) t *= -1; + } + while (! ep); + } + + + + + + + + void EdgeCalculation :: + AnalyzeEdge (int s1, int s2, int pos, int layer, + const ARRAY<Point<3> > & edgepoints, + ARRAY<Segment> & refedges, + ARRAY<bool> & refedgesinv) + { + int i, j, k, l; + int hi; + Point<3> hp; + Vec<3> t, a1, a2, m, n; + Segment seg; + Solid * locsol; + ARRAY<int> locsurfind; + + /* + int pi1 = 0, pi2 = 0; + extern Mesh * mesh; + for (i = 1; i <= mesh->GetNP(); i++) + { + if (Dist2 (edgepoints.Get(1), mesh->Point(i)) < 1e-12) + pi1 = i; + if (Dist2 (edgepoints.Last(), mesh->Point(i)) < 1e-12) + pi2 = i; + } + (*testout) << "Analyze edge: " << pi1 << " - " << pi2 << ", pts = " << edgepoints.Size() << endl; + (*testout) << "p1 = " << edgepoints.Get(1) << " pl = " << edgepoints.Last() << endl; + */ + bool debug = 0; + /* + Dist2 (Point<3> (1.824, -0.104, -0.95), edgepoints.Get(1)) < 1e-6 || + Dist2 (Point<3> (1.824, -0.104, -0.95), edgepoints.Last()) < 1e-6 || + Dist2 (Point<3> (1.72149, -0.26069, -0.95), edgepoints.Get(1)) < 1e-6 || + Dist2 (Point<3> (1.72149, -0.26069, -0.95), edgepoints.Last()) < 1e-6; + */ + + if (debug) + { + (*testout) << "tubious edge !!!" << endl; + (*testout) << "edgepoints = " << edgepoints << endl; + (*testout) << "s1, s2 = " << s1 << " - " << s2 << endl; + } + + refedges.SetSize(0); + refedgesinv.SetSize(0); + hp = Center (edgepoints[0], edgepoints[1]); + ProjectToEdge (geometry.GetSurface(s1), geometry.GetSurface(s2), hp); + + geometry.GetSurface(s1) -> CalcGradient (hp, a1); + geometry.GetSurface(s2) -> CalcGradient (hp, a2); + t = Cross (a1, a2); + t.Normalize(); + if (!pos) t *= -1; + + for (i = 0; i < geometry.GetNTopLevelObjects(); i++) + { + if (geometry.GetTopLevelObject(i)->GetLayer() != layer) + continue; + + const Solid * sol = geometry.GetTopLevelObject(i)->GetSolid(); + const Surface * surf = geometry.GetTopLevelObject(i)->GetSurface(); + + sol -> TangentialSolid (hp, locsol); + + if (!locsol) continue; + + BoxSphere<3> boxp (hp, hp); + boxp.Increase (1e-5); + boxp.CalcDiamCenter(); + + ReducePrimitiveIterator rpi(boxp); + UnReducePrimitiveIterator urpi; + + ((Solid*)locsol) -> IterateSolid (rpi); + + locsol -> CalcSurfaceInverse (); + + if (!surf) + { + locsol -> GetSurfaceIndices (locsurfind); + } + else + { + /* + if (fabs (surf->CalcFunctionValue (hp)) < 1e-6) + continue; + */ + locsurfind.SetSize(1); + locsurfind[0] = -1; + for (j = 0; j < geometry.GetNSurf(); j++) + if (geometry.GetSurface(j) == surf) + { + locsurfind[0] = j; + // geometry.GetSurfaceClassRepresentant(j); + break; + } + } + + ((Solid*)locsol) -> IterateSolid (urpi); + + + if (debug) + (*testout) << "edge of tlo " << i << ", has " << locsurfind.Size() << " faces." << endl; + + + for (j = locsurfind.Size()-1; j >= 0; j--) + if (fabs (geometry.GetSurface(locsurfind[j]) + ->CalcFunctionValue (hp) ) > 1e-6) + locsurfind.Delete(j); + + if (debug) + (*testout) << locsurfind.Size() << " faces on hp" << endl; + + for (j = 0; j < locsurfind.Size(); j++) + { + int lsi = locsurfind[j]; + int rlsi = geometry.GetSurfaceClassRepresentant(lsi); + + Vec<3> rn; + + // n is outer normal to solid + n = geometry.GetSurface(lsi) -> GetNormalVector (hp); + if (geometry.GetSurface (lsi)->Inverse()) + n *= -1; + + if (fabs (t * n) > 1e-4) continue; + if (debug) + { + (*testout) << "face " << locsurfind.Get(j) << ", rep = " << rlsi + << " has (t*n) = " << (t*n) << endl; + (*testout) << "n = " << n << endl; + } + + // rn is normal to class representant + rn = geometry.GetSurface(rlsi) -> GetNormalVector (hp); + + int sameasref = ((n * rn) > 0); + + m = Cross (t, rn); + m.Normalize(); + + if (debug) + (*testout) << "m = " << m << endl; + + for (k = 1; k <= 2; k ++) + { + bool edgeinv = (k == 2); + + if (debug) + { + (*testout) << "onface(" << hp << ", " << m << ")= " << flush; + (*testout) << locsol->OnFace (hp, m) << flush; + (*testout) << " vec2in = " + << locsol -> VectorIn2 (hp, m, n) << " and " + << locsol -> VectorIn2 (hp, m, -1 * n) << endl; + } + + // if (locsol -> OnFace (hp, m)) + if (locsol -> VectorIn2 (hp, m, n) == 0 && + locsol -> VectorIn2 (hp, m, -1 * n) == 1) + { + if (debug) + (*testout) << "is true" << endl; + hi = 0; + for (l = 1; l <= refedges.Size(); l++) + { + if (refedges.Get(l).si == rlsi && + refedgesinv.Get(l) == edgeinv) + hi = l; + } + + if (!hi) + { + seg.si = rlsi; + seg.domin = -1; + seg.domout = -1; + seg.tlosurf = -1; + seg.surfnr1 = s1; + seg.surfnr2 = s2; + hi = refedges.Append (seg); + refedgesinv.Append (edgeinv); + } + + if (!surf) + { + if (sameasref) + refedges.Elem(hi).domin = i; + else + refedges.Elem(hi).domout = i; + } + else + refedges.Elem(hi).tlosurf = i; + + if (debug) + (*testout) << "add ref seg:" + << "si = " << refedges.Get(hi).si + << ", domin = " << refedges.Get(hi).domin + << ", domout = " << refedges.Get(hi).domout + << ", surfnr1/2 = " << refedges.Get(hi).surfnr1 + << ", " << refedges.Get(hi).surfnr2 + << ", inv = " << refedgesinv.Get(hi) + << ", refedgenr = " << hi + << endl; + } + else + { + if (debug) + (*testout) << "is false" << endl; + } + m *= -1; + } + } + delete locsol; + } + } + + + + void EdgeCalculation :: + StoreEdge (const ARRAY<Segment> & refedges, + const ARRAY<bool> & refedgesinv, + const ARRAY<Point<3> > & edgepoints, + const ARRAY<double> & curvelength, + int layer, + Mesh & mesh) + { + + // Calculate optimal element-length + int i, j, k; + PointIndex pi; + int ne; + + double len, corr, lam; + PointIndex thispi, lastpi; + Point<3> p, np; + Segment seg; + + + const Surface * surf1 = geometry.GetSurface (refedges.Get(1).surfnr1); + const Surface * surf2 = geometry.GetSurface (refedges.Get(1).surfnr2); + + len = curvelength.Last(); + ne = int (len + 0.5); + if (ne == 0) ne = 1; + if (Dist2 (edgepoints.Get(1), edgepoints.Last()) < 1e-8 && + ne <= 6) + ne = 6; + corr = len / ne; + + // generate initial point + p = edgepoints.Get(1); + lastpi = -1; + + /* + for (pi = PointIndex::BASE; + pi < mesh.GetNP()+PointIndex::BASE; pi++) + if (Dist (mesh[pi], p) < 1e-6) + { + lastpi = pi; + break; + } + */ + ARRAY<int> locsearch; + meshpoint_tree -> GetIntersecting (p-Vec<3> (1e-6, 1e-6, 1e-6), + p+Vec<3> (1e-6, 1e-6, 1e-6), locsearch); + if (locsearch.Size()) + lastpi = locsearch[0]; + + + + if (lastpi == -1) + { + lastpi = mesh.AddPoint (p, layer); + meshpoint_tree -> Insert (p, lastpi); + } + + j = 1; + for (i = 1; i <= ne; i++) + { + while (curvelength.Get(j) < i * corr && j < curvelength.Size()) j++; + + lam = (i * corr - curvelength.Get(j-1)) / + (curvelength.Get(j) - curvelength.Get(j-1)); + + np(0) = (1-lam) * edgepoints.Get(j-1)(0) + lam * edgepoints.Get(j)(0); + np(1) = (1-lam) * edgepoints.Get(j-1)(1) + lam * edgepoints.Get(j)(1); + np(2) = (1-lam) * edgepoints.Get(j-1)(2) + lam * edgepoints.Get(j)(2); + + + thispi = -1; + if (i == ne) + { + /* + for (pi = PointIndex::BASE; + pi < mesh.GetNP()+PointIndex::BASE; pi++) + if (Dist(mesh[pi], np) < 1e-6) + thispi = pi; + */ + + meshpoint_tree -> GetIntersecting (np-Vec<3> (1e-6, 1e-6, 1e-6), + np+Vec<3> (1e-6, 1e-6, 1e-6), locsearch); + if (locsearch.Size()) + thispi = locsearch[0]; + } + + if (thispi == -1) + { + ProjectToEdge (surf1, surf2, np); + thispi = mesh.AddPoint (np, layer); + meshpoint_tree -> Insert (np, thispi); + } + + for (k = 1; k <= refedges.Size(); k++) + { + if (refedgesinv.Get(k)) + { + seg.p1 = lastpi; + seg.p2 = thispi; + } + else + { + seg.p1 = thispi; + seg.p2 = lastpi; + } + seg.si = refedges.Get(k).si; + seg.domin = refedges.Get(k).domin; + seg.domout = refedges.Get(k).domout; + seg.tlosurf = refedges.Get(k).tlosurf; + seg.edgenr = refedges.Get(k).edgenr; + seg.surfnr1 = refedges.Get(k).surfnr1; + seg.surfnr2 = refedges.Get(k).surfnr2; + seg.seginfo = 0; + if (k == 1) seg.seginfo = (refedgesinv.Get(k)) ? 2 : 1; + mesh.AddSegment (seg); + // (*testout) << "add seg " << seg.p1 << "-" << seg.p2 << endl; + + double maxh = min2 (geometry.GetSurface(seg.surfnr1)->GetMaxH(), + geometry.GetSurface(seg.surfnr2)->GetMaxH()); + + if (seg.domin != -1) + { + const Solid * s1 = + geometry.GetTopLevelObject(seg.domin) -> GetSolid(); + maxh = min2 (maxh, s1->GetMaxH()); + maxh = min2 (maxh, geometry.GetTopLevelObject(seg.domin)->GetMaxH()); + mesh.RestrictLocalH (p, maxh); + mesh.RestrictLocalH (np, maxh); + } + if (seg.domout != -1) + { + const Solid * s1 = + geometry.GetTopLevelObject(seg.domout) -> GetSolid(); + maxh = min2 (maxh, s1->GetMaxH()); + maxh = min2 (maxh, geometry.GetTopLevelObject(seg.domout)->GetMaxH()); + mesh.RestrictLocalH (p, maxh); + mesh.RestrictLocalH (np, maxh); + } + if (seg.tlosurf != -1) + { + double hi = geometry.GetTopLevelObject(seg.tlosurf) -> GetMaxH(); + maxh = min2 (maxh, hi); + mesh.RestrictLocalH (p, maxh); + mesh.RestrictLocalH (np, maxh); + } + } + + p = np; + lastpi = thispi; + } + +#ifdef DEVELOP + (*testout) << " eplast = " << lastpi << " = " << p << endl; +#endif + } + + + + + + + void EdgeCalculation :: + StoreShortEdge (const ARRAY<Segment> & refedges, + const ARRAY<bool> & refedgesinv, + const ARRAY<Point<3> > & edgepoints, + const ARRAY<double> & curvelength, + int layer, + Mesh & mesh) + { + + // Calculate optimal element-length + PointIndex pi; + // int ne; + Segment seg; + + /* + double len, corr, lam; + int thispi, lastpi; + Point<3> p, np; + + + const Surface * surf1 = geometry.GetSurface (refedges.Get(1).surfnr1); + const Surface * surf2 = geometry.GetSurface (refedges.Get(1).surfnr2); + + len = curvelength.Last(); + ne = int (len + 0.5); + if (ne == 0) ne = 1; + if (Dist2 (edgepoints[1], edgepoints.Last()) < 1e-8 && + ne <= 6) + ne = 6; + corr = len / ne; + */ + + // generate initial point + Point<3> p = edgepoints[0]; + PointIndex pi1 = -1; + for (pi = PointIndex::BASE; + pi < mesh.GetNP()+PointIndex::BASE; pi++) + + if (Dist (mesh[pi], p) < 1e-6) + { + pi1 = pi; + break; + } + + if (pi1 == -1) + { + pi1 = mesh.AddPoint (p, layer); + meshpoint_tree -> Insert (p, pi1); + } + + p = edgepoints.Last(); + PointIndex pi2 = -1; + for (pi = PointIndex::BASE; + pi < mesh.GetNP()+PointIndex::BASE; pi++) + + if (Dist (mesh[pi], p) < 1e-6) + { + pi2 = pi; + break; + } + if (pi2==-1) + { + pi2 = mesh.AddPoint (p, layer); + meshpoint_tree -> Insert (p, pi2); + } + + /* + + j = 1; + for (i = 1; i <= ne; i++) + { + while (curvelength[j] < i * corr && j < curvelength.Size()) j++; + + lam = (i * corr - curvelength[j-1]) / + (curvelength[j] - curvelength[j-1]); + + np(0) = (1-lam) * edgepoints[j-1](0) + lam * edgepoints[j](0); + np(1) = (1-lam) * edgepoints[j-1](1) + lam * edgepoints[j](1); + np(2) = (1-lam) * edgepoints[j-1](2) + lam * edgepoints[j](2); + + + thispi = 0; + if (i == ne) + for (j = 1; j <= mesh.GetNP(); j++) + if (Dist(mesh.Point(j), np) < 1e-6) + thispi = j; + + if (!thispi) + { + ProjectToEdge (surf1, surf2, np); + thispi = mesh.AddPoint (np); + } + */ + + for (int k = 1; k <= refedges.Size(); k++) + { + if (refedgesinv.Get(k)) + { + seg.p1 = pi1; + seg.p2 = pi2; + } + else + { + seg.p1 = pi2; + seg.p2 = pi1; + } + + seg.si = refedges.Get(k).si; + seg.domin = refedges.Get(k).domin; + seg.domout = refedges.Get(k).domout; + seg.tlosurf = refedges.Get(k).tlosurf; + seg.edgenr = refedges.Get(k).edgenr; + seg.surfnr1 = refedges.Get(k).surfnr1; + seg.surfnr2 = refedges.Get(k).surfnr2; + seg.seginfo = 0; + if (k == 1) seg.seginfo = (refedgesinv.Get(k)) ? 2 : 1; + mesh.AddSegment (seg); + // (*testout) << "add seg " << seg.p1 << "-" << seg.p2 << endl; + } + } + + + + + + + + void EdgeCalculation :: + CopyEdge (const ARRAY<Segment> & refedges, + const ARRAY<bool> & refedgesinv, + int copyfromedge, + const Point<3> & fromstart, const Point<3> & fromend, + const Point<3> & tostart, const Point<3> & toend, + int copyedgeidentification, + int layer, + Mesh & mesh) + { + int k; + PointIndex pi; + + // copy start and end points + for (int i = 1; i <= 2; i++) + { + Point<3> fromp = + (i == 1) ? fromstart : fromend; + Point<3> top = + (i == 1) ? tostart : toend; + + PointIndex frompi = -1; + PointIndex topi = -1; + for (pi = PointIndex::BASE; + pi < mesh.GetNP()+PointIndex::BASE; pi++) + { + if (Dist2 (mesh[pi], fromp) <= 1e-16) + frompi = pi; + if (Dist2 (mesh[pi], top) <= 1e-16) + topi = pi; + } + + if (topi == -1) + { + topi = mesh.AddPoint (top, layer); + meshpoint_tree -> Insert (top, topi); + } + + const Identification & csi = + (*geometry.identifications.Get(copyedgeidentification)); + + if (csi.Identifyable (mesh[frompi], mesh[topi])) + mesh.GetIdentifications().Add(frompi, topi, copyedgeidentification); + else if (csi.Identifyable (mesh[topi], mesh[frompi])) + mesh.GetIdentifications().Add(topi, frompi, copyedgeidentification); + else + { + cerr << "edgeflw.cpp: should identify, but cannot"; + exit(1); + } + /* + (*testout) << "Add Identification from CopyEdge, p1 = " + << mesh[PointIndex(frompi)] << ", p2 = " + << mesh[PointIndex(topi)] << endl; + + mesh.GetIdentifications().Add(frompi, topi, copyedgeidentification); + */ + } + + int oldns = mesh.GetNSeg(); + for (int i = 1; i <= oldns; i++) + { + // real copy, since array might be reallocated !! + const Segment oldseg = mesh.LineSegment(i); + if (oldseg.edgenr != copyfromedge) + continue; + if (oldseg.seginfo == 0) + continue; + + int pi1 = oldseg.p1; + int pi2 = oldseg.p2; + + int npi1 = geometry.identifications.Get(copyedgeidentification) + -> GetIdentifiedPoint (mesh, pi1); + int npi2 = geometry.identifications.Get(copyedgeidentification) + -> GetIdentifiedPoint (mesh, pi2); + + Segment seg; + + for (k = 1; k <= refedges.Size(); k++) + { + bool inv = refedgesinv.Get(k); + + // other edge is inverse + if (oldseg.seginfo == 1) + inv = !inv; + + // (*testout) << "inv, now = " << inv << endl; + + if (inv) + { + seg.p1 = npi1; + seg.p2 = npi2; + } + else + { + seg.p1 = npi2; + seg.p2 = npi1; + } + seg.si = refedges.Get(k).si; + seg.domin = refedges.Get(k).domin; + seg.domout = refedges.Get(k).domout; + seg.tlosurf = refedges.Get(k).tlosurf; + seg.edgenr = refedges.Get(k).edgenr; + seg.surfnr1 = refedges.Get(k).surfnr1; + seg.surfnr2 = refedges.Get(k).surfnr2; + seg.seginfo = 0; + if (k == 1) seg.seginfo = refedgesinv.Get(k) ? 2 : 1; + mesh.AddSegment (seg); + // (*testout) << "copy seg " << seg.p1 << "-" << seg.p2 << endl; +#ifdef DEVELOP + + (*testout) << "copy seg, face = " << seg.si << ": " + << " inv = " << inv << ", refinv = " << refedgesinv.Get(k) + << mesh.Point(seg.p1) << ", " << mesh.Point(seg.p2) << endl; +#endif + + } + + } + } + + + + + + + + void EdgeCalculation :: + FindClosedSurfaces (double h, Mesh & mesh) + { + // if there is no special point at a sphere, one has to add a segment pair + + int i, j; + int nsol; + int nsurf = geometry.GetNSurf(); + int layer; + + BitArray pointatsurface (nsurf); + Point<3> p1, p2; + Vec<3> nv, tv; + Solid * tansol; + ARRAY<int> tansurfind; + // const Solid * sol; + + nsol = geometry.GetNTopLevelObjects(); + + + pointatsurface.Clear(); + + /* + for (i = 1; i <= specpoints.Size(); i++) + { + int classrep; + + classrep = geometry.GetSurfaceClassRepresentant (specpoints[i].s1); + pointatsurface.Set (classrep); + classrep = geometry.GetSurfaceClassRepresentant (specpoints[i].s2); + pointatsurface.Set (classrep); + // pointatsurface.Set (specpoints[i].s1); + // pointatsurface.Set (specpoints[i].s2); + } + */ + for (i = 1; i <= mesh.GetNSeg(); i++) + { + const Segment & seg = mesh.LineSegment(i); + int classrep; + +#ifdef DEVELOP + (*testout) << seg.surfnr1 << ", " << seg.surfnr2 << ", si = " << seg.si << endl; +#endif + classrep = geometry.GetSurfaceClassRepresentant (seg.si); + + pointatsurface.Set (classrep); + } + + + for (i = 0; i < nsurf; i++) + { + int classrep = geometry.GetSurfaceClassRepresentant (i); + + if (!pointatsurface.Test(classrep)) + { + const Surface * s = geometry.GetSurface(i); + p1 = s -> GetSurfacePoint(); + nv = s -> GetNormalVector (p1); + + double hloc = + min2 (s->LocH (p1, 3, 1, h), mesh.GetH(p1)); + + tv = nv.GetNormal (); + tv *= (hloc / tv.Length()); + p2 = p1 + tv; + s->Project (p2); + + + Segment seg1; + seg1.si = i; + seg1.domin = -1; + seg1.domout = -1; + + Segment seg2; + seg2.si = i; + seg2.domin = -1; + seg2.domout = -1; + + seg1.surfnr1 = i; + seg2.surfnr1 = i; + seg1.surfnr2 = i; + seg2.surfnr2 = i; + + for (j = 0; j < nsol; j++) + { + if (geometry.GetTopLevelObject(j)->GetSurface()) + continue; + + const Solid * sol = geometry.GetTopLevelObject(j)->GetSolid(); + sol -> TangentialSolid (p1, tansol); + layer = geometry.GetTopLevelObject(j)->GetLayer(); + + if (tansol) + { + tansol -> GetSurfaceIndices (tansurfind); + + if (tansurfind.Size() == 1 && tansurfind.Get(1) == i) + { + if (!tansol->VectorIn(p1, nv)) + { + seg1.domin = j; + seg2.domin = j; + seg1.tlosurf = j; + seg2.tlosurf = j; + } + else + { + seg1.domout = j; + seg2.domout = j; + seg1.tlosurf = j; + seg2.tlosurf = j; + } + // seg.s2 = i; + // seg.invs1 = surfaces[i] -> Inverse(); + // seg.invs2 = ! (surfaces[i] -> Inverse()); + } + delete tansol; + } + } + + + if (seg1.domin != -1 || seg1.domout != -1) + { + mesh.AddPoint (p1, layer); + mesh.AddPoint (p2, layer); + seg1.p1 = mesh.GetNP()-1; + seg1.p2 = mesh.GetNP(); + seg2.p2 = mesh.GetNP()-1; + seg2.p1 = mesh.GetNP(); + seg1.geominfo[0].trignum = 1; + seg1.geominfo[1].trignum = 1; + seg2.geominfo[0].trignum = 1; + seg2.geominfo[1].trignum = 1; + mesh.AddSegment (seg1); + mesh.AddSegment (seg2); + + PrintMessage (5, "Add line segment to smooth surface"); + +#ifdef DEVELOP + (*testout) << "Add segment at smooth surface " << i; + if (i != classrep) (*testout) << ", classrep = " << classrep; + (*testout) << ": " + << mesh.Point (mesh.GetNP()-1) << " - " + << mesh.Point (mesh.GetNP()) << endl; +#endif + } + } + } + } + +} diff --git a/contrib/Netgen/libsrc/csg/edgeflw.hpp b/contrib/Netgen/libsrc/csg/edgeflw.hpp new file mode 100644 index 0000000000..beb1f690a9 --- /dev/null +++ b/contrib/Netgen/libsrc/csg/edgeflw.hpp @@ -0,0 +1,99 @@ +#ifndef FILE_EDGEFLW +#define FILE_EDGEFLW + +/**************************************************************************/ +/* File: edgeflw.hh */ +/* Author: Joachim Schoeberl */ +/* Date: 01. Okt. 95 */ +/**************************************************************************/ + +/* + + Edge - following function and + Projection to edge of implicitly given edge + +*/ + + +/** + Calculates edges. + The edges of a solid geometry are computed. Special + points have to be given. + */ +extern void CalcEdges (const CSGeometry & geometry, + const ARRAY<SpecialPoint> & specpoints, + double h, Mesh & mesh); + + + + + +class EdgeCalculation +{ + const CSGeometry & geometry; + ARRAY<SpecialPoint> & specpoints; + Point3dTree * searchtree; + Point3dTree * meshpoint_tree; + int cntedge; +public: + EdgeCalculation (const CSGeometry & ageometry, + ARRAY<SpecialPoint> & aspecpoints); + + ~EdgeCalculation(); + + void Calc(double h, Mesh & mesh); + + +private: + void CalcEdges1 (double h, Mesh & mesh); + + + void FollowEdge (int pi1, int & ep, int & pos, + // const ARRAY<SpecialPoint> & hsp, + const ARRAY<int> & hsp, + double h, const Mesh & mesh, + ARRAY<Point<3> > & edgepoints, + ARRAY<double> & curvelength); + + + void AnalyzeEdge (int s1, int s2, int pos, int layer, + const ARRAY<Point<3> > & edgepoints, + ARRAY<Segment> & refedges, + ARRAY<bool> & refedgesinv); + + void StoreEdge (const ARRAY<Segment> & refedges, + const ARRAY<bool> & refedgesinv, + const ARRAY<Point<3> > & edgepoints, + const ARRAY<double> & curvelength, + int layer, + Mesh & mesh); + + void StoreShortEdge (const ARRAY<Segment> & refedges, + const ARRAY<bool> & refedgesinv, + const ARRAY<Point<3> > & edgepoints, + const ARRAY<double> & curvelength, + int layer, + Mesh & mesh); + + void CopyEdge (const ARRAY<Segment> & refedges, + const ARRAY<bool> & refedgesinv, + int copyfromedge, + const Point<3> & fromstart, const Point<3> & fromend, + const Point<3> & tostart, const Point<3> & toend, + int copyedgeidentification, + int layer, + Mesh & mesh); + + + void SplitEqualOneSegEdges (Mesh & mesh); + void FindClosedSurfaces (double h, Mesh & mesh); + + +public: + bool point_on_edge_problem; + +}; + + + +#endif diff --git a/contrib/Netgen/libsrc/csg/edgeflw2.cpp b/contrib/Netgen/libsrc/csg/edgeflw2.cpp new file mode 100644 index 0000000000..87239c05bb --- /dev/null +++ b/contrib/Netgen/libsrc/csg/edgeflw2.cpp @@ -0,0 +1,1404 @@ +#include <mystdlib.h> +#include <meshing.hpp> +#include <csg.hpp> + +#undef DEVELOP + +namespace netgen +{ + + EdgeCalculation :: + EdgeCalculation (const CSGeometry & ageometry, + const ARRAY<SpecialPoint> & aspecpoints) + : geometry(ageometry), specpoints(aspecpoints) + { + ; + } + + + + void EdgeCalculation :: Calc(double h, Mesh & mesh) + { + PrintMessage (1, "Find edges"); + PushStatus ("Find edges"); + + CalcEdges1 (h, mesh); + SplitEqualOneSegEdges (mesh); + FindClosedSurfaces (h, mesh); + PrintMessage (3, cntedge, " edges found"); + + PopStatus (); + } + + + + + void EdgeCalculation :: CalcEdges1 (double h, Mesh & mesh) + { + ARRAY<SpecialPoint> hsp(specpoints.Size()); + ARRAY<SpecialPoint> startpoints, endpoints; + + int i, j, k, l, hi, pos, ep, ne; + int layer; + + Vec<3> a1, a2, t, n, m; + Point<3> p, np, pnp, hp; + + Segment seg; + int pi1, s1, s2; + int lastpi, thispi; + + ARRAY<Point<3> > edgepoints; + ARRAY<double> curvelength; + int copyedge, copyfromedge, copyedgeidentification; + + ARRAY<int> locsurfind; + + double len, corr, lam; + double steplen, cursteplen, loch, hd; + + int checkedcopy = 0; + + double size = geometry.MaxSize(); // globflags.GetNumFlag ("maxsize", 500); + double epspointdist2 = size * 1e-6; // globflags.GetNumFlag ("epspointdist", size * 1e-6); + epspointdist2 = sqr (epspointdist2); + + + Solid * locsol; + + + // copy special points to work with + for (i = 0; i < specpoints.Size(); i++) + hsp[i] = specpoints[i]; + + + cntedge = 0; + + while (hsp.Size()) + { + SetThreadPercent(100 - 100 * double (hsp.Size()) / specpoints.Size()); + + edgepoints.SetSize (0); + curvelength.SetSize (0); + + + pi1 = 0; + copyedge = 0; + // identifyable point available ? + + // (*testout) << endl; + + for (i = 1; i <= geometry.identifications.Size() && !pi1; i++) + { + for (j = checkedcopy+1; j <= startpoints.Size() && !pi1; j++) + { + + if (geometry.identifications.Get(i)->IdentifyableCandidate (startpoints.Get(j))) + + { + int pi1cand = 0; + double mindist = 1e10; + + for (k = 1; k <= hsp.Size() && !pi1; k++) + { +#ifdef DEVELOP + (*testout) << "check kand = " << hsp.Get(k).p + << ", v = " << hsp.Get(k).v + << endl; +#endif + if (geometry.identifications.Get(i) + ->Identifyable(startpoints.Get(j), hsp.Get(k)) || + geometry.identifications.Get(i) + ->Identifyable(hsp.Get(k), startpoints.Get(j))) + { + +#ifdef DEVELOP + (*testout) << "identifiable, dist = " + << Dist (startpoints.Get(j).p, hsp.Get(k).p) << endl; +#endif + + if (Dist (startpoints.Get(j).p, hsp.Get(k).p) < mindist) + { + mindist = Dist (startpoints.Get(j).p, hsp.Get(k).p); + pi1cand = k; + } + /* + pi1 = k; + copyedge = 1; + copyfromedge = j; + copyedgeidentification = i; + + (*testout) << "copy edge startpoint from " + << startpoints.Get(j).p << " - " + << startpoints.Get(j).v + << " to " + << hsp.Get(k).p << " - " << hsp.Get(k).v << endl; + */ + } + } + + if (pi1cand) + { + pi1 = pi1cand; + copyedge = 1; + copyfromedge = j; + copyedgeidentification = i; +#ifdef DEVELOP + (*testout) << "copy edge startpoint from " + << startpoints.Get(j).p << " - " + << startpoints.Get(j).v + << " to " + << hsp.Get(pi1).p << " - " << hsp.Get(pi1).v << endl; +#endif + } + } + } + } + + + // cannot copy from other ege ? + if (!pi1) + checkedcopy = startpoints.Size(); + + // unconditional special point available ? + if (!pi1) + for (i = 1; i <= hsp.Size() && pi1 == 0; i++) + if (hsp.Get(i).unconditional == 1) + pi1 = i; + + + if (!pi1) + { + // only unconditional points available, choose first + pi1 = 1; + } + + layer = hsp.Get(pi1).GetLayer(); + + + if (!hsp.Get(pi1).unconditional) + { + hsp.Elem(pi1).unconditional = 1; + for (i = 1; i <= hsp.Size(); i++) + if (i != pi1 && Dist (hsp.Get(pi1).p, hsp.Get(i).p) < 1e-8 && + (hsp.Get(pi1).v + hsp.Get(i).v).Length() < 1e-4) + { + // opposite direction + hsp.Elem(i).unconditional = 1; + } + } + + cntedge++; + startpoints.Append (hsp.Get(pi1)); + +#ifdef DEVELOP + (*testout) << "edge nr " << cntedge << endl; + (*testout) << "start followedge: p1 = " << hsp.Get(pi1).p << ", v = " << hsp.Get(pi1).v << endl; +#endif + + FollowEdge (pi1, ep, pos, hsp, h, mesh, + edgepoints, curvelength); + + + if (multithread.terminate) + return; + + if (!ep) + { + // ignore starting point + hsp.DeleteElement (pi1); + continue; + } + + + + endpoints.Append (hsp.Get(ep)); + + + double elen = 0; + for (i = 1; i <= edgepoints.Size()-1; i++) + elen += Dist (edgepoints.Get(i), edgepoints.Get(i+1)); + + + int shortedge = 0; + for (i = 1; i <= geometry.identifications.Size(); i++) + if (geometry.identifications.Get(i)->ShortEdge(hsp.Get(pi1), hsp.Get(ep))) + shortedge = 1; + (*testout) << "shortedge = " << shortedge << endl; + + + if (!shortedge) + { + mesh.RestrictLocalHLine (Point3d (hsp.Get(pi1).p), + Point3d (hsp.Get(ep).p), + elen / mparam.segmentsperedge); + } + + s1 = hsp.Get(pi1).s1; + s2 = hsp.Get(pi1).s2; + + + // delete initial, terminal and conditional points + +#ifdef DEVELOP + (*testout) << "terminal point: p = " << hsp.Get(ep).p << ", v = " << hsp.Get(ep).v << endl; +#endif + if (ep > pi1) + { + hsp.DeleteElement (ep); + hsp.DeleteElement (pi1); + } + else + { + hsp.DeleteElement (pi1); + hsp.DeleteElement (ep); + } + + + for (j = 1; j <= edgepoints.Size()-1; j++) + { + p = edgepoints.Get(j); + np = Center (p, edgepoints.Get(j+1)); + hd = Dist2 (p, np); + + for (i = 1; i <= hsp.Size(); i++) + if ( hsp.Get(i).HasSurfaces (s1, s2) && + hsp.Get(i).unconditional == 0 && + Dist2 (np, hsp.Get(i).p) < 1.2 * hd) + { + hsp.DeleteElement (i); + i--; + } + } + + + ARRAY<Segment> refedges; + ARRAY<int> refedgesinv; + + + AnalyzeEdge (s1, s2, pos, layer, + edgepoints, + refedges, refedgesinv); + + for (i = 1; i <= refedges.Size(); i++) + refedges.Elem(i).edgenr = cntedge; + + +#ifdef DEVELOP + (*testout) << "edge " << cntedge << endl + << "startp: " << startpoints.Last().p + << ", v = " << startpoints.Last().v << endl + << "copy = " << copyedge << endl + << refedges.Size() << " refedges: "; + for (i = 1; i <= refedges.Size(); i++) + (*testout) << " " << refedges.Get(i).si; + (*testout) << endl; + (*testout) << "inv[1] = " << refedgesinv.Get(1) << endl; +#endif + + if (!copyedge) + { + int oldnseg = mesh.GetNSeg(); + + if (!shortedge) + StoreEdge (refedges, refedgesinv, + edgepoints, curvelength, layer, mesh); + else + StoreShortEdge (refedges, refedgesinv, + edgepoints, curvelength, layer, mesh); + + + /* + for (i = oldnseg+1; i <= mesh.GetNSeg(); i++) + for (j = 1; j <= oldnseg; j++) + { + const Point<3> & l1p1 = mesh.Point (mesh.LineSegment(i).p1); + const Point<3> & l1p2 = mesh.Point (mesh.LineSegment(i).p2); + const Point<3> & l2p1 = mesh.Point (mesh.LineSegment(j).p1); + const Point<3> & l2p2 = mesh.Point (mesh.LineSegment(j).p2); + Vec<3> vl1(l1p1, l1p2); + for (double lamk = 0; lamk <= 1; lamk += 0.1) + { + Point<3> l2p = l1p1 + lamk * vl1; + double dist = sqrt (MinDistLP2 (l2p1, l2p2, l2p)); + if (dist > 1e-12) + mesh.RestrictLocalH (l2p, 3*dist); + } + } + */ + } + else + { + CopyEdge (refedges, refedgesinv, + copyfromedge, + startpoints.Get(copyfromedge).p, + endpoints.Get(copyfromedge).p, + edgepoints.Get(1), edgepoints.Last(), + copyedgeidentification, + layer, + mesh); + } + + } + } + + + + /* + If two or more edges share the same initial and end-points, + then they need at least two segments + */ + void EdgeCalculation :: + SplitEqualOneSegEdges (Mesh & mesh) + { + int i, j; + SegmentIndex si; + PointIndex pi; + + ARRAY<int> osedges(cntedge); + INDEX_2_HASHTABLE<int> osedgesht (cntedge+1); + + osedges = 2; + + // count segments on edges + for (si = 0; si < mesh.GetNSeg(); si++) + { + const Segment & seg = mesh[si]; + if (seg.seginfo && seg.edgenr >= 1 && seg.edgenr <= cntedge) + osedges.Elem(seg.edgenr)--; + } + + (*testout) << "osedges = " << osedges << endl; + + // flag one segment edges + for (i = 0; i < cntedge; i++) + osedges[i] = (osedges[i] > 0) ? 1 : 0; + + (*testout) << "osedges, now = " << osedges << endl; + + for (si = 0; si < mesh.GetNSeg(); si++) + { + const Segment & seg = mesh[si]; + if (seg.seginfo && seg.edgenr >= 1 && seg.edgenr <= cntedge) + { + if (osedges.Get(seg.edgenr)) + { + INDEX_2 i2(seg.p1, seg.p2); + i2.Sort (); + if (osedgesht.Used (i2)) + osedgesht.Set (i2, 2); + else + osedgesht.Set (i2, 1); + } + } + } + + + // one edge 1 segment, other 2 segments + // yes, it happens ! + + for (i = 1; i <= osedgesht.GetNBags(); i++) + for (j = 1; j <= osedgesht.GetBagSize(i); j++) + { + INDEX_2 i2; + int val; + osedgesht.GetData (i, j, i2, val); + + const Point<3> & p1 = mesh[PointIndex(i2.I1())]; + const Point<3> & p2 = mesh[PointIndex(i2.I2())]; + Vec<3> v = p2 - p1; + double vlen = v.Length(); + v /= vlen; + for (pi = PointIndex::BASE; + pi < mesh.GetNP()+PointIndex::BASE; pi++) + + if (pi != i2.I1() && pi != i2.I2()) + { + const Point<3> & p = mesh[pi]; + Vec<3> v2 = p - p1; + double lam = (v2 * v); + if (lam > 0 && lam < vlen) + { + Point<3> hp = p1 + lam * v; + if (Dist (p, hp) < 1e-4 * vlen) + { + PrintSysError ("Point on edge !!!"); + cout << "seg: " << i2 << ", p = " << pi << endl; + osedgesht.Set (i2, 2); + } + } + } + } + + + // insert new points + osedges = -1; + + int nseg = mesh.GetNSeg(); + for (si = 0; si < nseg; si++) + { + const Segment & seg = mesh[si]; + if (seg.seginfo && seg.edgenr >= 1 && seg.edgenr <= cntedge) + { + INDEX_2 i2(seg.p1, seg.p2); + i2.Sort (); + if (osedgesht.Used (i2) && + osedgesht.Get (i2) == 2 && + osedges.Elem(seg.edgenr) == -1) + { + Point<3> newp = Center (mesh[PointIndex(seg.p1)], + mesh[PointIndex(seg.p2)]); + + ProjectToEdge (geometry.GetSurface(seg.surfnr1), + geometry.GetSurface(seg.surfnr2), + newp); + + osedges.Elem(seg.edgenr) = + mesh.AddPoint (newp, mesh[PointIndex(seg.p1)].GetLayer()); + } + } + } + + + for (i = 1; i <= nseg; i++) + { + Segment & seg = mesh.LineSegment (i); + if (seg.edgenr >= 1 && seg.edgenr <= cntedge) + { + if (osedges.Get(seg.edgenr) != -1) + { + Segment newseg = seg; + newseg.p1 = osedges.Get(seg.edgenr); + seg.p2 = osedges.Get(seg.edgenr); + mesh.AddSegment (newseg); + } + } + } + + } + + + + void EdgeCalculation :: + FollowEdge (int pi1, int & ep, int & pos, + const ARRAY<SpecialPoint> & hsp, + double h, const Mesh & mesh, + ARRAY<Point<3> > & edgepoints, + ARRAY<double> & curvelength) + { + int i, j, s1, s2; + double len, steplen, cursteplen, loch; + Point<3> p, np, pnp; + Vec<3> a1, a2, t; + + + double size = geometry.MaxSize(); + double epspointdist2 = size * 1e-6; + epspointdist2 = sqr (epspointdist2); + int uselocalh = mparam.uselocalh; + + + s1 = hsp.Get(pi1).s1; + s2 = hsp.Get(pi1).s2; + + p = hsp.Get(pi1).p; + geometry.GetSurface(s1) -> CalcGradient (p, a1); + geometry.GetSurface(s2) -> CalcGradient (p, a2); + + t = Cross (a1, a2); + t.Normalize(); + + pos = (hsp.Get(pi1).v * t) > 0; + if (!pos) t *= -1; + + + edgepoints.Append (p); + curvelength.Append (0); + len = 0; + + loch = min2 (geometry.GetSurface(s1) -> LocH (p, 3, 1, h), + geometry.GetSurface(s2) -> LocH (p, 3, 1, h)); + + + + if (uselocalh) + { + double lh = mesh.GetH(p); + if (lh < loch) + loch = lh; + } + + steplen = 0.1 * loch; + + do + { + if (multithread.terminate) + return; + + if (fabs (p(0)) + fabs (p(1)) + fabs (p(2)) > 10000) + { + ep = 0; + PrintWarning ("Give up line"); + break; + } + + if (steplen > 0.1 * loch) steplen = 0.1 * loch; + + steplen *= 2; + do + { + steplen *= 0.5; + np = p + steplen * t; + pnp = np; + ProjectToEdge (geometry.GetSurface(s1), + geometry.GetSurface(s2), pnp); + } + while (Dist (np, pnp) > 0.1 * steplen); + + cursteplen = steplen; + if (Dist (np, pnp) < 0.01 * steplen) steplen *= 2; + + + np = pnp; + +#ifdef MYGRAPH + if (silentflag <= 2) + { + MyLine3D (p, np, rot); + MyDraw (); + } +#endif + + ep = 0; + + double hvtmin = 1.5 * cursteplen; + + Box<3> boxp (p - (2 * cursteplen) * Vec<3> (1, 1, 1), + p + (2 * cursteplen) * Vec<3> (1, 1, 1)); + + for (i = 1; i <= hsp.Size(); i++) + // if ( i != pi1 && hsp.Get(i).HasSurfaces (s1, s2) ) + { + if (!boxp.IsIn (hsp.Get(i).p)) + continue; + + Vec<3> hv = hsp.Get(i).p - p; + if (hv.Length2() > 9 * cursteplen * cursteplen) + continue; + + /* + if (!hsp.Get(i).HasSurfaces (s1, s2)) + continue; // test for dalibor-problem + */ + + double hvt = hv * t; + hv -= hvt * t; + + if (hv.Length() < 0.2 * cursteplen && + hvt > 0 && + // hvt < 1.5 * cursteplen && + hvt < hvtmin && + hsp.Get(i).unconditional == 1 && + (hsp.Get(i).v + t).Length() < 0.4 ) + { + Point<3> hep = hsp.Get(i).p; + ProjectToEdge (geometry.GetSurface(s1), + geometry.GetSurface(s2), hep); + + + if (Dist2 (hep, hsp.Get(i).p) < epspointdist2 ) + { + geometry.GetSurface(s1) -> CalcGradient (hep, a1); + geometry.GetSurface(s2) -> CalcGradient (hep, a2); + Vec<3> ept = Cross (a1, a2); + ept /= ept.Length(); + if (!pos) ept *= -1; + + if ( (hsp.Get(i).v + ept).Length() < 1e-4 ) + { + np = hsp.Get(i).p; + ep = i; + hvtmin = hvt; + // break; + } + } + } + } + + loch = min2 (geometry.GetSurface(s1) -> LocH (np, 3, 1, h), + geometry.GetSurface(s2) -> LocH (np, 3, 1, h)); + + if (uselocalh) + { + double lh = mesh.GetH(np); + if (lh < loch) + loch = lh; + } + + + len += Dist (p, np) / loch; + edgepoints.Append (np); + curvelength.Append (len); + + p = np; + + geometry.GetSurface(s1) -> CalcGradient (p, a1); + geometry.GetSurface(s2) -> CalcGradient (p, a2); + t = Cross (a1, a2); + t.Normalize(); + if (!pos) t *= -1; + } + while (! ep); + } + + + + + + + + void EdgeCalculation :: + AnalyzeEdge (int s1, int s2, int pos, int layer, + const ARRAY<Point<3> > & edgepoints, + ARRAY<Segment> & refedges, + ARRAY<int> & refedgesinv) + { + int i, j, k, l; + int hi; + Point<3> hp; + Vec<3> t, a1, a2, m, n; + Segment seg; + Solid * locsol; + ARRAY<int> locsurfind; + + /* + int pi1 = 0, pi2 = 0; + extern Mesh * mesh; + for (i = 1; i <= mesh->GetNP(); i++) + { + if (Dist2 (edgepoints.Get(1), mesh->Point(i)) < 1e-12) + pi1 = i; + if (Dist2 (edgepoints.Last(), mesh->Point(i)) < 1e-12) + pi2 = i; + } + (*testout) << "Analyze edge: " << pi1 << " - " << pi2 << ", pts = " << edgepoints.Size() << endl; + (*testout) << "p1 = " << edgepoints.Get(1) << " pl = " << edgepoints.Last() << endl; + */ + int debug = 0; + /* + Dist2 (Point<3> (2.69642, 1.1866, 2.03), edgepoints.Get(1)) < 1e-6 || + Dist2 (Point<3> (2.69642, 1.1866, 2.03), edgepoints.Last()) < 1e-6; + */ + + if (debug) + { + // (*testout) << "tubious edge !!!" << endl; + (*testout) << "s1, s2 = " << s1 << " - " << s2 << endl; + } + + refedges.SetSize(0); + refedgesinv.SetSize(0); + hp = Center (edgepoints.Get(1), edgepoints.Get(2)); + ProjectToEdge (geometry.GetSurface(s1), geometry.GetSurface(s2), hp); + + geometry.GetSurface(s1) -> CalcGradient (hp, a1); + geometry.GetSurface(s2) -> CalcGradient (hp, a2); + t = Cross (a1, a2); + t.Normalize(); + if (!pos) t *= -1; + + (*testout) << "t = " << t << endl; + + for (i = 0; i < geometry.GetNTopLevelObjects(); i++) + { + (*testout) << "layer = " << layer + << ", tlo-layer = " << geometry.GetTopLevelObject(i)->GetLayer() << endl; + if (geometry.GetTopLevelObject(i)->GetLayer() != layer) + continue; + + const Solid * sol = geometry.GetTopLevelObject(i)->GetSolid(); + const Surface * surf = geometry.GetTopLevelObject(i)->GetSurface(); + + sol -> TangentialSolid (hp, locsol); + if (!locsol) continue; + + BoxSphere<3> boxp (hp, hp); + boxp.Increase (1e-5); + boxp.CalcDiamCenter(); + + ReducePrimitiveIterator rpi(boxp); + UnReducePrimitiveIterator urpi; + + ((Solid*)locsol) -> IterateSolid (rpi); + + locsol -> CalcSurfaceInverse (); + + + if (!surf) + { + locsol -> GetSurfaceIndices (locsurfind); + } + else + { + /* + if (fabs (surf->CalcFunctionValue (hp)) < 1e-6) + continue; + */ + locsurfind.SetSize(1); + locsurfind[0] = -1; + for (j = 0; j < geometry.GetNSurf(); j++) + if (geometry.GetSurface(j) == surf) + { + locsurfind[0] = j; + // geometry.GetSurfaceClassRepresentant(j); + break; + } + } + + ((Solid*)locsol) -> IterateSolid (urpi); + + + if (debug) + (*testout) << "edge of tlo " << i << ", has " << locsurfind.Size() << " faces." << endl; + + + for (j = locsurfind.Size()-1; j >= 0; j--) + if (fabs (geometry.GetSurface(locsurfind[j]) + ->CalcFunctionValue (hp) ) > 1e-6) + locsurfind.DeleteElement(j+1); + + if (debug) + (*testout) << locsurfind.Size() << " faces on hp" << endl; + + for (j = 0; j < locsurfind.Size(); j++) + { + int lsi = locsurfind[j]; + int rlsi = geometry.GetSurfaceClassRepresentant(lsi); + + Vec<3> rn; + + // n is outer normal to solid + geometry.GetSurface(lsi) -> GetNormalVector (hp, n); + if (geometry.GetSurface (lsi)->Inverse()) + n *= -1; + + if (fabs (t * n) > 1e-4) continue; + if (debug) + { + (*testout) << "face " << locsurfind.Get(j) << ", rep = " << rlsi + << " has (t*n) = " << (t*n) << endl; + (*testout) << "n = " << n << endl; + } + + // rn is normal to class representant + geometry.GetSurface(rlsi) -> GetNormalVector (hp, rn); + + int sameasref = ((n * rn) > 0); + + m = Cross (t, rn); + m.Normalize(); + + + for (k = 1; k <= 2; k ++) + { + bool edgeinv = (k == 2); + + if (debug) + { + (*testout) << "onface(" << hp << ", " << m << ")= " + << locsol->OnFace (hp, m); + (*testout) << " vec2in = " + << locsol -> VectorIn2 (hp, m, n) << " and " + << locsol -> VectorIn2 (hp, m, -1 * n) << endl; + } + + // if (locsol -> OnFace (hp, m)) + if (locsol -> VectorIn2 (hp, m, n) == 0 && + locsol -> VectorIn2 (hp, m, -1 * n) == 1) + { + hi = 0; + for (l = 1; l <= refedges.Size(); l++) + { + if (refedges.Get(l).si == rlsi && + refedgesinv.Get(l) == edgeinv) + hi = l; + } + + if (!hi) + { + seg.si = rlsi; + seg.domin = -1; + seg.domout = -1; + seg.tlosurf = -1; + seg.surfnr1 = s1; + seg.surfnr2 = s2; + hi = refedges.Append (seg); + refedgesinv.Append (edgeinv); + } + + if (!surf) + { + if (sameasref) + refedges.Elem(hi).domin = i; + else + refedges.Elem(hi).domout = i; + } + else + refedges.Elem(hi).tlosurf = i; + + if (debug) + (*testout) << "add ref seg:" + << "si = " << refedges.Get(hi).si + << ", domin = " << refedges.Get(hi).domin + << ", domout = " << refedges.Get(hi).domout + << ", surfnr1/2 = " << refedges.Get(hi).surfnr1 + << ", " << refedges.Get(hi).surfnr2 + << ", inv = " << refedgesinv.Get(hi) + << ", refedgenr = " << hi + << endl; + } + m *= -1; + } + } + delete locsol; + } + } + + + + void EdgeCalculation :: + StoreEdge (const ARRAY<Segment> & refedges, + const ARRAY<int> & refedgesinv, + const ARRAY<Point<3> > & edgepoints, + const ARRAY<double> & curvelength, + int layer, + Mesh & mesh) + { + + // Calculate optimal element-length + int i, j, k; + PointIndex pi; + int ne; + + double len, corr, lam; + PointIndex thispi, lastpi; + Point<3> p, np; + Segment seg; + + + const Surface * surf1 = geometry.GetSurface (refedges.Get(1).surfnr1); + const Surface * surf2 = geometry.GetSurface (refedges.Get(1).surfnr2); + + len = curvelength.Last(); + ne = int (len + 0.5); + if (ne == 0) ne = 1; + if (Dist2 (edgepoints.Get(1), edgepoints.Last()) < 1e-8 && + ne <= 6) + ne = 6; + corr = len / ne; + + // generate initial point + p = edgepoints.Get(1); + lastpi = -1; + for (pi = PointIndex::BASE; + pi < mesh.GetNP()+PointIndex::BASE; pi++) + if (Dist (mesh[pi], p) < 1e-6) + { + lastpi = pi; + break; + } + + if (lastpi == -1) + lastpi = mesh.AddPoint (p, layer); + + + j = 1; + for (i = 1; i <= ne; i++) + { + while (curvelength.Get(j) < i * corr && j < curvelength.Size()) j++; + + lam = (i * corr - curvelength.Get(j-1)) / + (curvelength.Get(j) - curvelength.Get(j-1)); + + np(0) = (1-lam) * edgepoints.Get(j-1)(0) + lam * edgepoints.Get(j)(0); + np(1) = (1-lam) * edgepoints.Get(j-1)(1) + lam * edgepoints.Get(j)(1); + np(2) = (1-lam) * edgepoints.Get(j-1)(2) + lam * edgepoints.Get(j)(2); + + + thispi = -1; + if (i == ne) + for (pi = PointIndex::BASE; + pi < mesh.GetNP()+PointIndex::BASE; pi++) + if (Dist(mesh[pi], np) < 1e-6) + thispi = pi; + + if (thispi == -1) + { + ProjectToEdge (surf1, surf2, np); + thispi = mesh.AddPoint (np, layer); + } + + for (k = 1; k <= refedges.Size(); k++) + { + if (refedgesinv.Get(k)) + { + seg.p1 = lastpi; + seg.p2 = thispi; + } + else + { + seg.p1 = thispi; + seg.p2 = lastpi; + } + seg.si = refedges.Get(k).si; + seg.domin = refedges.Get(k).domin; + seg.domout = refedges.Get(k).domout; + seg.tlosurf = refedges.Get(k).tlosurf; + seg.edgenr = refedges.Get(k).edgenr; + seg.surfnr1 = refedges.Get(k).surfnr1; + seg.surfnr2 = refedges.Get(k).surfnr2; + seg.seginfo = 0; + if (k == 1) seg.seginfo = (refedgesinv.Get(k)) ? 2 : 1; + mesh.AddSegment (seg); + // (*testout) << "add seg " << seg.p1 << "-" << seg.p2 << endl; + + double maxh = min2 (geometry.GetSurface(seg.surfnr1)->GetMaxH(), + geometry.GetSurface(seg.surfnr2)->GetMaxH()); + + if (seg.domin != -1) + { + const Solid * s1 = + geometry.GetTopLevelObject(seg.domin) -> GetSolid(); + maxh = min2 (maxh, s1->GetMaxH()); + maxh = min2 (maxh, geometry.GetTopLevelObject(seg.domin)->GetMaxH()); + mesh.RestrictLocalH (p, maxh); + mesh.RestrictLocalH (np, maxh); + } + if (seg.domout != -1) + { + const Solid * s1 = + geometry.GetTopLevelObject(seg.domout) -> GetSolid(); + maxh = min2 (maxh, s1->GetMaxH()); + maxh = min2 (maxh, geometry.GetTopLevelObject(seg.domout)->GetMaxH()); + mesh.RestrictLocalH (p, maxh); + mesh.RestrictLocalH (np, maxh); + } + if (seg.tlosurf != -1) + { + double hi = geometry.GetTopLevelObject(seg.tlosurf) -> GetMaxH(); + maxh = min2 (maxh, hi); + mesh.RestrictLocalH (p, maxh); + mesh.RestrictLocalH (np, maxh); + } + } + + p = np; + lastpi = thispi; + } + +#ifdef DEVELOP + (*testout) << " eplast = " << lastpi << " = " << p << endl; +#endif + } + + + + + + + void EdgeCalculation :: + StoreShortEdge (const ARRAY<Segment> & refedges, + const ARRAY<int> & refedgesinv, + const ARRAY<Point<3> > & edgepoints, + const ARRAY<double> & curvelength, + int layer, + Mesh & mesh) + { + + // Calculate optimal element-length + int i, j, k; + PointIndex pi; + int ne; + Segment seg; + + /* + double len, corr, lam; + int thispi, lastpi; + Point<3> p, np; + + + const Surface * surf1 = geometry.GetSurface (refedges.Get(1).surfnr1); + const Surface * surf2 = geometry.GetSurface (refedges.Get(1).surfnr2); + + len = curvelength.Last(); + ne = int (len + 0.5); + if (ne == 0) ne = 1; + if (Dist2 (edgepoints[1], edgepoints.Last()) < 1e-8 && + ne <= 6) + ne = 6; + corr = len / ne; + */ + + // generate initial point + Point<3> p = edgepoints[0]; + PointIndex pi1 = -1; + for (pi = PointIndex::BASE; + pi < mesh.GetNP()+PointIndex::BASE; pi++) + + if (Dist (mesh[pi], p) < 1e-6) + { + pi1 = pi; + break; + } + + if (pi1 == -1) pi1 = mesh.AddPoint (p, layer); + + p = edgepoints.Last(); + PointIndex pi2 = -1; + for (pi = PointIndex::BASE; + pi < mesh.GetNP()+PointIndex::BASE; pi++) + + if (Dist (mesh[pi], p) < 1e-6) + { + pi2 = pi; + break; + } + if (pi2==-1) pi2 = mesh.AddPoint (p, layer); + + /* + + j = 1; + for (i = 1; i <= ne; i++) + { + while (curvelength[j] < i * corr && j < curvelength.Size()) j++; + + lam = (i * corr - curvelength[j-1]) / + (curvelength[j] - curvelength[j-1]); + + np(0) = (1-lam) * edgepoints[j-1](0) + lam * edgepoints[j](0); + np(1) = (1-lam) * edgepoints[j-1](1) + lam * edgepoints[j](1); + np(2) = (1-lam) * edgepoints[j-1](2) + lam * edgepoints[j](2); + + + thispi = 0; + if (i == ne) + for (j = 1; j <= mesh.GetNP(); j++) + if (Dist(mesh.Point(j), np) < 1e-6) + thispi = j; + + if (!thispi) + { + ProjectToEdge (surf1, surf2, np); + thispi = mesh.AddPoint (np); + } + */ + + for (k = 1; k <= refedges.Size(); k++) + { + if (refedgesinv.Get(k)) + { + seg.p1 = pi1; + seg.p2 = pi2; + } + else + { + seg.p1 = pi2; + seg.p2 = pi1; + } + + seg.si = refedges.Get(k).si; + seg.domin = refedges.Get(k).domin; + seg.domout = refedges.Get(k).domout; + seg.tlosurf = refedges.Get(k).tlosurf; + seg.edgenr = refedges.Get(k).edgenr; + seg.surfnr1 = refedges.Get(k).surfnr1; + seg.surfnr2 = refedges.Get(k).surfnr2; + seg.seginfo = 0; + if (k == 1) seg.seginfo = (refedgesinv.Get(k)) ? 2 : 1; + mesh.AddSegment (seg); + // (*testout) << "add seg " << seg.p1 << "-" << seg.p2 << endl; + } + } + + + + + + + + void EdgeCalculation :: + CopyEdge (const ARRAY<Segment> & refedges, + const ARRAY<int> & refedgesinv, + int copyfromedge, + const Point<3> & fromstart, const Point<3> & fromend, + const Point<3> & tostart, const Point<3> & toend, + int copyedgeidentification, + int layer, + Mesh & mesh) + { + int i, j, k; + PointIndex pi; + + // copy start and end points + for (i = 1; i <= 2; i++) + { + Point<3> fromp = + (i == 1) ? fromstart : fromend; + Point<3> top = + (i == 1) ? tostart : toend; + + PointIndex frompi = -1; + PointIndex topi = -1; + for (pi = PointIndex::BASE; + pi < mesh.GetNP()+PointIndex::BASE; pi++) + { + if (Dist2 (mesh[pi], fromp) <= 1e-16) + frompi = pi; + if (Dist2 (mesh[pi], top) <= 1e-16) + topi = pi; + } + + if (topi == -1) + topi = mesh.AddPoint (top, layer); + + const Identification & csi = + (*geometry.identifications.Get(copyedgeidentification)); + + if (csi.Identifyable (mesh[frompi], mesh[topi])) + mesh.GetIdentifications().Add(frompi, topi, copyedgeidentification); + else if (csi.Identifyable (mesh[topi], mesh[frompi])) + mesh.GetIdentifications().Add(topi, frompi, copyedgeidentification); + else + { + cerr << "edgeflw.cpp: should identify, but cannot"; + exit(1); + } + /* + (*testout) << "Add Identification from CopyEdge, p1 = " + << mesh[PointIndex(frompi)] << ", p2 = " + << mesh[PointIndex(topi)] << endl; + + mesh.GetIdentifications().Add(frompi, topi, copyedgeidentification); + */ + } + + int oldns = mesh.GetNSeg(); + for (i = 1; i <= oldns; i++) + { + // real copy, since array might be reallocated !! + const Segment oldseg = mesh.LineSegment(i); + if (oldseg.edgenr != copyfromedge) + continue; + if (oldseg.seginfo == 0) + continue; + + int pi1 = oldseg.p1; + int pi2 = oldseg.p2; + + int npi1 = geometry.identifications.Get(copyedgeidentification) + -> GetIdentifiedPoint (mesh, pi1); + int npi2 = geometry.identifications.Get(copyedgeidentification) + -> GetIdentifiedPoint (mesh, pi2); + + Segment seg; + + for (k = 1; k <= refedges.Size(); k++) + { + int inv = refedgesinv.Get(k); + + // other edge is inverse + if (oldseg.seginfo == 1) + inv = !inv; + + // (*testout) << "inv, now = " << inv << endl; + + if (inv) + { + seg.p1 = npi1; + seg.p2 = npi2; + } + else + { + seg.p1 = npi2; + seg.p2 = npi1; + } + seg.si = refedges.Get(k).si; + seg.domin = refedges.Get(k).domin; + seg.domout = refedges.Get(k).domout; + seg.tlosurf = refedges.Get(k).tlosurf; + seg.edgenr = refedges.Get(k).edgenr; + seg.surfnr1 = refedges.Get(k).surfnr1; + seg.surfnr2 = refedges.Get(k).surfnr2; + seg.seginfo = 0; + if (k == 1) seg.seginfo = refedgesinv.Get(k) ? 2 : 1; + mesh.AddSegment (seg); + // (*testout) << "copy seg " << seg.p1 << "-" << seg.p2 << endl; +#ifdef DEVELOP + + (*testout) << "copy seg, face = " << seg.si << ": " + << " inv = " << inv << ", refinv = " << refedgesinv.Get(k) + << mesh.Point(seg.p1) << ", " << mesh.Point(seg.p2) << endl; +#endif + + } + + } + } + + + + + + + + void EdgeCalculation :: + FindClosedSurfaces (double h, Mesh & mesh) + { + // if there is no special point at a sphere, one has to add a segment pair + + int i, j; + int nsol; + int nsurf = geometry.GetNSurf(); + int layer; + + BitArray pointatsurface (nsurf); + Point<3> p1, p2; + Vec<3> nv, tv; + Solid * tansol; + ARRAY<int> tansurfind; + // const Solid * sol; + + nsol = geometry.GetNTopLevelObjects(); + + + pointatsurface.Clear(); + + /* + for (i = 1; i <= specpoints.Size(); i++) + { + int classrep; + + classrep = geometry.GetSurfaceClassRepresentant (specpoints[i].s1); + pointatsurface.Set (classrep); + classrep = geometry.GetSurfaceClassRepresentant (specpoints[i].s2); + pointatsurface.Set (classrep); + // pointatsurface.Set (specpoints[i].s1); + // pointatsurface.Set (specpoints[i].s2); + } + */ + for (i = 1; i <= mesh.GetNSeg(); i++) + { + const Segment & seg = mesh.LineSegment(i); + int classrep; + +#ifdef DEVELOP + (*testout) << seg.surfnr1 << ", " << seg.surfnr2 << ", si = " << seg.si << endl; +#endif + classrep = geometry.GetSurfaceClassRepresentant (seg.si); + + pointatsurface.Set (classrep); + } + + + for (i = 0; i < nsurf; i++) + { + int classrep = geometry.GetSurfaceClassRepresentant (i); + + if (!pointatsurface.Test(classrep)) + { + const Surface * s = geometry.GetSurface(i); + p1 = s -> GetSurfacePoint(); + s -> GetNormalVector (p1, nv); + + double hloc = + min2 (s->LocH (p1, 3, 1, h), mesh.GetH(p1)); + + tv = nv.GetNormal (); + tv *= (hloc / tv.Length()); + p2 = p1 + tv; + s->Project (p2); + + + Segment seg1; + seg1.si = i; + seg1.domin = -1; + seg1.domout = -1; + + Segment seg2; + seg2.si = i; + seg2.domin = -1; + seg2.domout = -1; + + seg1.surfnr1 = i; + seg2.surfnr1 = i; + seg1.surfnr2 = i; + seg2.surfnr2 = i; + + for (j = 0; j < nsol; j++) + { + if (geometry.GetTopLevelObject(j)->GetSurface()) + continue; + + const Solid * sol = geometry.GetTopLevelObject(j)->GetSolid(); + sol -> TangentialSolid (p1, tansol); + layer = geometry.GetTopLevelObject(j)->GetLayer(); + + if (tansol) + { + tansol -> GetSurfaceIndices (tansurfind); + + if (tansurfind.Size() == 1 && tansurfind.Get(1) == i) + { + if (!tansol->VectorIn(p1, nv)) + { + seg1.domin = j; + seg2.domin = j; + seg1.tlosurf = j; + seg2.tlosurf = j; + } + else + { + seg1.domout = j; + seg2.domout = j; + seg1.tlosurf = j; + seg2.tlosurf = j; + } + // seg.s2 = i; + // seg.invs1 = surfaces[i] -> Inverse(); + // seg.invs2 = ! (surfaces[i] -> Inverse()); + } + delete tansol; + } + } + + + if (seg1.domin != -1 || seg1.domout != -1) + { + mesh.AddPoint (p1, layer); + mesh.AddPoint (p2, layer); + seg1.p1 = mesh.GetNP()-1; + seg1.p2 = mesh.GetNP(); + seg2.p2 = mesh.GetNP()-1; + seg2.p1 = mesh.GetNP(); + seg1.geominfo[0].trignum = 1; + seg1.geominfo[1].trignum = 1; + seg2.geominfo[0].trignum = 1; + seg2.geominfo[1].trignum = 1; + mesh.AddSegment (seg1); + mesh.AddSegment (seg2); + + PrintMessage (5, "Add line segment to smooth surface"); + +#ifdef DEVELOP + (*testout) << "Add segment at smooth surface " << i; + if (i != classrep) (*testout) << ", classrep = " << classrep; + (*testout) << ": " + << mesh.Point (mesh.GetNP()-1) << " - " + << mesh.Point (mesh.GetNP()) << endl; +#endif + } + } + } + } + +} diff --git a/contrib/Netgen/libsrc/csg/edgeflw_new.cpp b/contrib/Netgen/libsrc/csg/edgeflw_new.cpp new file mode 100644 index 0000000000..8aa9f0263b --- /dev/null +++ b/contrib/Netgen/libsrc/csg/edgeflw_new.cpp @@ -0,0 +1,1553 @@ +#include <mystdlib.h> +#include <meshing.hpp> +#include <csg.hpp> + +#undef DEVELOP + +namespace netgen +{ + + EdgeCalculation :: + EdgeCalculation (const CSGeometry & ageometry, + ARRAY<SpecialPoint> & aspecpoints) + : geometry(ageometry), specpoints(aspecpoints) + { + Box<3> bbox; + if (specpoints.Size() >= 1) + bbox.Set (specpoints[0].p); + for (int i = 1; i < specpoints.Size(); i++) + bbox.Add (specpoints[i].p); + + 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); + } + + EdgeCalculation :: ~EdgeCalculation() + { + delete searchtree; + delete meshpoint_tree; + } + + + void EdgeCalculation :: Calc(double h, Mesh & mesh) + { + (*testout) << "Find edges" << endl; + PrintMessage (1, "Find edges"); + PushStatus ("Find edges"); + + CalcEdges1 (h, mesh); + SplitEqualOneSegEdges (mesh); + FindClosedSurfaces (h, mesh); + PrintMessage (3, cntedge, " edges found"); + + for (SegmentIndex si = 0; si < mesh.GetNSeg(); si++) + (*testout) << "seg " << si << " = " << mesh[si] << endl; + PopStatus (); + } + + + + + + void EdgeCalculation :: CalcEdges1 (double h, Mesh & mesh) + { + ARRAY<int> hsp(specpoints.Size()); + ARRAY<int> glob2hsp(specpoints.Size()); + ARRAY<int> startpoints, endpoints; + + int i, j, k, l, hi, pos, ep, ne; + int layer; + + Vec<3> a1, a2, t, n, m; + Point<3> p, np, pnp, hp; + + Segment seg; + int pi1, s1, s2; + int lastpi, thispi; + + ARRAY<Point<3> > edgepoints; + ARRAY<double> curvelength; + int copyedge, copyfromedge, copyedgeidentification; + + ARRAY<int> locsurfind, locind; + + double len, corr, lam; + double steplen, cursteplen, loch, hd; + + int checkedcopy = 0; + + double size = geometry.MaxSize(); // globflags.GetNumFlag ("maxsize", 500); + double epspointdist2 = size * 1e-6; // globflags.GetNumFlag ("epspointdist", size * 1e-6); + epspointdist2 = sqr (epspointdist2); + + + + Solid * locsol; + + + // copy special points to work with + for (i = 0; i < specpoints.Size(); i++) + { + hsp[i] = i; + glob2hsp[i] = i; + } + + + cntedge = 0; + + while (hsp.Size()) + { + SetThreadPercent(100 - 100 * double (hsp.Size()) / specpoints.Size()); + + edgepoints.SetSize (0); + curvelength.SetSize (0); + + + pi1 = 0; + copyedge = 0; + // identifyable point available ? + + // (*testout) << endl; + + for (i = 1; i <= geometry.identifications.Size() && !pi1; i++) + { + for (j = checkedcopy+1; j <= startpoints.Size() && !pi1; j++) + { + + if (geometry.identifications.Get(i)->IdentifyableCandidate (specpoints[startpoints.Get(j)])) + + { + int pi1cand = 0; + double mindist = 1e10; + + for (k = 1; k <= hsp.Size() && !pi1; k++) + { +#ifdef DEVELOP + (*testout) << "check kand = " << hsp.Get(k).p + << ", v = " << hsp.Get(k).v + << endl; +#endif + if (geometry.identifications.Get(i) + ->Identifyable(specpoints[startpoints.Get(j)], specpoints[hsp.Get(k)]) || + geometry.identifications.Get(i) + ->Identifyable(specpoints[hsp.Get(k)], specpoints[startpoints.Get(j)])) + { + +#ifdef DEVELOP + (*testout) << "identifiable, dist = " + << Dist (startpoints.Get(j).p, hsp.Get(k).p) << endl; +#endif + + if (Dist (specpoints[startpoints.Get(j)].p, specpoints[hsp.Get(k)].p) < mindist) + { + mindist = Dist (specpoints[startpoints.Get(j)].p, specpoints[hsp.Get(k)].p); + pi1cand = k; + } + /* + pi1 = k; + copyedge = 1; + copyfromedge = j; + copyedgeidentification = i; + + (*testout) << "copy edge startpoint from " + << startpoints.Get(j).p << " - " + << startpoints.Get(j).v + << " to " + << hsp.Get(k).p << " - " << hsp.Get(k).v << endl; + */ + } + } + + if (pi1cand) + { + pi1 = pi1cand; + copyedge = 1; + copyfromedge = j; + copyedgeidentification = i; +#ifdef DEVELOP + (*testout) << "copy edge startpoint from " + << startpoints.Get(j).p << " - " + << startpoints.Get(j).v + << " to " + << specpoints[hsp.Get(pi1)].p << " - " << hsp.Get(pi1).v << endl; +#endif + } + } + } + } + + + // cannot copy from other ege ? + if (!pi1) + checkedcopy = startpoints.Size(); + + // unconditional special point available ? + if (!pi1) + for (i = 1; i <= hsp.Size(); i++) + if (specpoints[hsp.Get(i)].unconditional == 1) + { + pi1 = i; + break; + } + + + if (!pi1) + { + // only unconditional points available, choose first + pi1 = 1; + } + + layer = specpoints[hsp.Get(pi1)].GetLayer(); + + + if (!specpoints[hsp.Get(pi1)].unconditional) + { + specpoints[hsp.Elem(pi1)].unconditional = 1; + for (i = 1; i <= hsp.Size(); i++) + if (i != pi1 && + Dist (specpoints[hsp.Get(pi1)].p, specpoints[hsp.Get(i)].p) < 1e-8 && + (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) << "edge nr " << cntedge << endl; + (*testout) << "start followedge: p1 = " << hsp.Get(pi1).p << ", v = " << hsp.Get(pi1).v << endl; +#endif + + FollowEdge (pi1, ep, pos, hsp, h, mesh, + edgepoints, curvelength); + + + if (multithread.terminate) + return; + + if (!ep) + { + // ignore starting point + hsp.DeleteElement (pi1); + cout << "yes, this happens" << endl; + continue; + } + + + + endpoints.Append (hsp.Get(ep)); + + + double elen = 0; + for (i = 1; i <= edgepoints.Size()-1; i++) + elen += Dist (edgepoints.Get(i), edgepoints.Get(i+1)); + + + int shortedge = 0; + for (i = 1; i <= geometry.identifications.Size(); i++) + if (geometry.identifications.Get(i)->ShortEdge(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; + + + // delete initial, terminal and conditional points + +#ifdef DEVELOP + (*testout) << "terminal point: p = " << hsp.Get(ep).p << ", v = " << 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 (j = 1; j <= edgepoints.Size()-1; j++) + { + p = edgepoints.Get(j); + np = Center (p, edgepoints.Get(j+1)); + 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 (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 (i = 1; i <= hsp.Size(); i++) + if ( specpoints[hsp.Get(i)].HasSurfaces (s1, s2) && + specpoints[hsp.Get(i)].unconditional == 0 && + Dist2 (np, specpoints[hsp.Get(i)].p) < 1.2 * hd) + { + searchtree -> DeleteElement (hsp.Get(i)+1); + hsp.DeleteElement (i); + i--; + } + */ + } + + + ARRAY<Segment> refedges; + ARRAY<int> refedgesinv; + + + AnalyzeEdge (s1, s2, pos, layer, + edgepoints, + refedges, refedgesinv); + + for (i = 1; i <= refedges.Size(); i++) + refedges.Elem(i).edgenr = cntedge; + + +#ifdef DEVELOP + (*testout) << "edge " << cntedge << endl + << "startp: " << startpoints.Last().p + << ", v = " << startpoints.Last().v << endl + << "copy = " << copyedge << endl + << refedges.Size() << " refedges: "; + for (i = 1; i <= refedges.Size(); i++) + (*testout) << " " << refedges.Get(i).si; + (*testout) << endl; + (*testout) << "inv[1] = " << refedgesinv.Get(1) << endl; +#endif + + if (!copyedge) + { + int oldnseg = mesh.GetNSeg(); + + if (!shortedge) + StoreEdge (refedges, refedgesinv, + edgepoints, curvelength, layer, mesh); + else + StoreShortEdge (refedges, refedgesinv, + edgepoints, curvelength, layer, mesh); + + + /* + for (i = oldnseg+1; i <= mesh.GetNSeg(); i++) + for (j = 1; j <= oldnseg; j++) + { + const Point<3> & l1p1 = mesh.Point (mesh.LineSegment(i).p1); + const Point<3> & l1p2 = mesh.Point (mesh.LineSegment(i).p2); + const Point<3> & l2p1 = mesh.Point (mesh.LineSegment(j).p1); + const Point<3> & l2p2 = mesh.Point (mesh.LineSegment(j).p2); + Vec<3> vl1(l1p1, l1p2); + for (double lamk = 0; lamk <= 1; lamk += 0.1) + { + Point<3> l2p = l1p1 + lamk * vl1; + double dist = sqrt (MinDistLP2 (l2p1, l2p2, l2p)); + if (dist > 1e-12) + mesh.RestrictLocalH (l2p, 3*dist); + } + } + */ + } + else + { + CopyEdge (refedges, refedgesinv, + copyfromedge, + specpoints[startpoints.Get(copyfromedge)].p, + specpoints[endpoints.Get(copyfromedge)].p, + edgepoints.Get(1), edgepoints.Last(), + copyedgeidentification, + layer, + mesh); + } + + } + } + + + + /* + If two or more edges share the same initial and end-points, + then they need at least two segments + */ + void EdgeCalculation :: + SplitEqualOneSegEdges (Mesh & mesh) + { + int i, j; + SegmentIndex si; + PointIndex pi; + + ARRAY<int> osedges(cntedge); + INDEX_2_HASHTABLE<int> osedgesht (cntedge+1); + + osedges = 2; + + // count segments on edges + for (si = 0; si < mesh.GetNSeg(); si++) + { + const Segment & seg = mesh[si]; + if (seg.seginfo && seg.edgenr >= 1 && seg.edgenr <= cntedge) + osedges.Elem(seg.edgenr)--; + } + + (*testout) << "osedges = " << osedges << endl; + + // flag one segment edges + for (i = 0; i < cntedge; i++) + osedges[i] = (osedges[i] > 0) ? 1 : 0; + + (*testout) << "osedges, now = " << osedges << endl; + + for (si = 0; si < mesh.GetNSeg(); si++) + { + const Segment & seg = mesh[si]; + if (seg.seginfo && seg.edgenr >= 1 && seg.edgenr <= cntedge) + { + if (osedges.Get(seg.edgenr)) + { + INDEX_2 i2(seg.p1, seg.p2); + i2.Sort (); + if (osedgesht.Used (i2)) + osedgesht.Set (i2, 2); + else + osedgesht.Set (i2, 1); + } + } + } + + + // one edge 1 segment, other 2 segments + // yes, it happens ! + + for (i = 1; i <= osedgesht.GetNBags(); i++) + for (j = 1; j <= osedgesht.GetBagSize(i); j++) + { + INDEX_2 i2; + int val; + osedgesht.GetData (i, j, i2, val); + + const Point<3> & p1 = mesh[PointIndex(i2.I1())]; + const Point<3> & p2 = mesh[PointIndex(i2.I2())]; + Vec<3> v = p2 - p1; + double vlen = v.Length(); + v /= vlen; + for (pi = PointIndex::BASE; + pi < mesh.GetNP()+PointIndex::BASE; pi++) + + if (pi != i2.I1() && pi != i2.I2()) + { + const Point<3> & p = mesh[pi]; + Vec<3> v2 = p - p1; + double lam = (v2 * v); + if (lam > 0 && lam < vlen) + { + Point<3> hp = p1 + lam * v; + if (Dist (p, hp) < 1e-4 * vlen) + { + PrintSysError ("Point on edge !!!"); + cout << "seg: " << i2 << ", p = " << pi << endl; + osedgesht.Set (i2, 2); + } + } + } + } + + + // insert new points + osedges = -1; + + int nseg = mesh.GetNSeg(); + for (si = 0; si < nseg; si++) + { + const Segment & seg = mesh[si]; + if (seg.seginfo && seg.edgenr >= 1 && seg.edgenr <= cntedge) + { + INDEX_2 i2(seg.p1, seg.p2); + i2.Sort (); + if (osedgesht.Used (i2) && + osedgesht.Get (i2) == 2 && + osedges.Elem(seg.edgenr) == -1) + { + Point<3> newp = Center (mesh[PointIndex(seg.p1)], + mesh[PointIndex(seg.p2)]); + + ProjectToEdge (geometry.GetSurface(seg.surfnr1), + geometry.GetSurface(seg.surfnr2), + newp); + + osedges.Elem(seg.edgenr) = + mesh.AddPoint (newp, mesh[PointIndex(seg.p1)].GetLayer()); + meshpoint_tree -> Insert (newp, osedges.Elem(seg.edgenr)); + } + } + } + + + for (i = 1; i <= nseg; i++) + { + Segment & seg = mesh.LineSegment (i); + if (seg.edgenr >= 1 && seg.edgenr <= cntedge) + { + if (osedges.Get(seg.edgenr) != -1) + { + Segment newseg = seg; + newseg.p1 = osedges.Get(seg.edgenr); + seg.p2 = osedges.Get(seg.edgenr); + mesh.AddSegment (newseg); + } + } + } + + } + + + + void EdgeCalculation :: + FollowEdge (int pi1, int & ep, int & pos, + const ARRAY<int> & hsp, + double h, const Mesh & mesh, + ARRAY<Point<3> > & edgepoints, + ARRAY<double> & curvelength) + { + int i, j, s1, s2; + double len, steplen, cursteplen, loch; + Point<3> p, np, pnp; + Vec<3> a1, a2, t; + + ARRAY<int> locind; + + double size = geometry.MaxSize(); + double epspointdist2 = size * 1e-6; + epspointdist2 = sqr (epspointdist2); + int uselocalh = mparam.uselocalh; + + + s1 = specpoints[hsp.Get(pi1)].s1; + s2 = specpoints[hsp.Get(pi1)].s2; + + p = specpoints[hsp.Get(pi1)].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; + + loch = min2 (geometry.GetSurface(s1) -> LocH (p, 3, 1, h), + geometry.GetSurface(s2) -> LocH (p, 3, 1, h)); + + + + if (uselocalh) + { + double lh = mesh.GetH(p); + if (lh < loch) + loch = lh; + } + + steplen = 0.1 * loch; + + do + { + if (multithread.terminate) + return; + + if (fabs (p(0)) + fabs (p(1)) + fabs (p(2)) > 10000) + { + ep = 0; + PrintWarning ("Give up line"); + break; + } + + if (steplen > 0.1 * loch) steplen = 0.1 * loch; + + steplen *= 2; + do + { + steplen *= 0.5; + np = p + steplen * t; + pnp = np; + ProjectToEdge (geometry.GetSurface(s1), + geometry.GetSurface(s2), pnp); + } + while (Dist (np, pnp) > 0.1 * steplen); + + cursteplen = steplen; + if (Dist (np, pnp) < 0.01 * steplen) steplen *= 2; + + + np = pnp; + +#ifdef MYGRAPH + if (silentflag <= 2) + { + MyLine3D (p, np, rot); + MyDraw (); + } +#endif + + ep = 0; + + double hvtmin = 1.5 * cursteplen; + + Box<3> boxp (p - (2 * cursteplen) * Vec<3> (1, 1, 1), + p + (2 * cursteplen) * Vec<3> (1, 1, 1)); + + searchtree -> GetIntersecting (boxp.PMin(), boxp.PMax(), locind); + + for (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 (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) -> LocH (np, 3, 1, h), + geometry.GetSurface(s2) -> LocH (np, 3, 1, h)); + + if (uselocalh) + { + double lh = mesh.GetH(np); + if (lh < loch) + loch = lh; + } + + + len += Dist (p, np) / loch; + edgepoints.Append (np); + curvelength.Append (len); + + p = np; + + geometry.GetSurface(s1) -> CalcGradient (p, a1); + geometry.GetSurface(s2) -> CalcGradient (p, a2); + t = Cross (a1, a2); + t.Normalize(); + if (!pos) t *= -1; + } + while (! ep); + } + + + + + + + + void EdgeCalculation :: + AnalyzeEdge (int s1, int s2, int pos, int layer, + const ARRAY<Point<3> > & edgepoints, + ARRAY<Segment> & refedges, + ARRAY<int> & refedgesinv) + { + int i, j, k, l; + int hi; + Point<3> hp; + Vec<3> t, a1, a2, m, n; + Segment seg; + Solid * locsol; + ARRAY<int> locsurfind; + + /* + int pi1 = 0, pi2 = 0; + extern Mesh * mesh; + for (i = 1; i <= mesh->GetNP(); i++) + { + if (Dist2 (edgepoints.Get(1), mesh->Point(i)) < 1e-12) + pi1 = i; + if (Dist2 (edgepoints.Last(), mesh->Point(i)) < 1e-12) + pi2 = i; + } + (*testout) << "Analyze edge: " << pi1 << " - " << pi2 << ", pts = " << edgepoints.Size() << endl; + (*testout) << "p1 = " << edgepoints.Get(1) << " pl = " << edgepoints.Last() << endl; + */ + int debug = 0; + /* + Dist2 (Point<3> (2.69642, 1.1866, 2.03), edgepoints.Get(1)) < 1e-6 || + Dist2 (Point<3> (2.69642, 1.1866, 2.03), edgepoints.Last()) < 1e-6; + */ + + if (debug) + { + // (*testout) << "tubious edge !!!" << endl; + (*testout) << "s1, s2 = " << s1 << " - " << s2 << endl; + } + + refedges.SetSize(0); + refedgesinv.SetSize(0); + hp = Center (edgepoints.Get(1), edgepoints.Get(2)); + ProjectToEdge (geometry.GetSurface(s1), geometry.GetSurface(s2), hp); + + geometry.GetSurface(s1) -> CalcGradient (hp, a1); + geometry.GetSurface(s2) -> CalcGradient (hp, a2); + t = Cross (a1, a2); + t.Normalize(); + if (!pos) t *= -1; + + (*testout) << "t = " << t << endl; + + for (i = 0; i < geometry.GetNTopLevelObjects(); i++) + { + (*testout) << "layer = " << layer + << ", tlo-layer = " << geometry.GetTopLevelObject(i)->GetLayer() << endl; + if (geometry.GetTopLevelObject(i)->GetLayer() != layer) + continue; + + const Solid * sol = geometry.GetTopLevelObject(i)->GetSolid(); + const Surface * surf = geometry.GetTopLevelObject(i)->GetSurface(); + + sol -> TangentialSolid (hp, locsol); + if (!locsol) continue; + + BoxSphere<3> boxp (hp, hp); + boxp.Increase (1e-5); + boxp.CalcDiamCenter(); + + ReducePrimitiveIterator rpi(boxp); + UnReducePrimitiveIterator urpi; + + ((Solid*)locsol) -> IterateSolid (rpi); + + locsol -> CalcSurfaceInverse (); + + + if (!surf) + { + locsol -> GetSurfaceIndices (locsurfind); + } + else + { + /* + if (fabs (surf->CalcFunctionValue (hp)) < 1e-6) + continue; + */ + locsurfind.SetSize(1); + locsurfind[0] = -1; + for (j = 0; j < geometry.GetNSurf(); j++) + if (geometry.GetSurface(j) == surf) + { + locsurfind[0] = j; + // geometry.GetSurfaceClassRepresentant(j); + break; + } + } + + ((Solid*)locsol) -> IterateSolid (urpi); + + + if (debug) + (*testout) << "edge of tlo " << i << ", has " << locsurfind.Size() << " faces." << endl; + + + for (j = locsurfind.Size()-1; j >= 0; j--) + if (fabs (geometry.GetSurface(locsurfind[j]) + ->CalcFunctionValue (hp) ) > 1e-6) + locsurfind.DeleteElement(j+1); + + if (debug) + (*testout) << locsurfind.Size() << " faces on hp" << endl; + + for (j = 0; j < locsurfind.Size(); j++) + { + int lsi = locsurfind[j]; + int rlsi = geometry.GetSurfaceClassRepresentant(lsi); + + Vec<3> rn; + + // n is outer normal to solid + geometry.GetSurface(lsi) -> GetNormalVector (hp, n); + if (geometry.GetSurface (lsi)->Inverse()) + n *= -1; + + if (fabs (t * n) > 1e-4) continue; + if (debug) + { + (*testout) << "face " << locsurfind.Get(j) << ", rep = " << rlsi + << " has (t*n) = " << (t*n) << endl; + (*testout) << "n = " << n << endl; + } + + // rn is normal to class representant + geometry.GetSurface(rlsi) -> GetNormalVector (hp, rn); + + int sameasref = ((n * rn) > 0); + + m = Cross (t, rn); + m.Normalize(); + + + for (k = 1; k <= 2; k ++) + { + bool edgeinv = (k == 2); + + if (debug) + { + (*testout) << "onface(" << hp << ", " << m << ")= " + << locsol->OnFace (hp, m); + (*testout) << " vec2in = " + << locsol -> VectorIn2 (hp, m, n) << " and " + << locsol -> VectorIn2 (hp, m, -1 * n) << endl; + } + + // if (locsol -> OnFace (hp, m)) + if (locsol -> VectorIn2 (hp, m, n) == 0 && + locsol -> VectorIn2 (hp, m, -1 * n) == 1) + { + hi = 0; + for (l = 1; l <= refedges.Size(); l++) + { + if (refedges.Get(l).si == rlsi && + refedgesinv.Get(l) == edgeinv) + hi = l; + } + + if (!hi) + { + seg.si = rlsi; + seg.domin = -1; + seg.domout = -1; + seg.tlosurf = -1; + seg.surfnr1 = s1; + seg.surfnr2 = s2; + hi = refedges.Append (seg); + refedgesinv.Append (edgeinv); + } + + if (!surf) + { + if (sameasref) + refedges.Elem(hi).domin = i; + else + refedges.Elem(hi).domout = i; + } + else + refedges.Elem(hi).tlosurf = i; + + if (debug) + (*testout) << "add ref seg:" + << "si = " << refedges.Get(hi).si + << ", domin = " << refedges.Get(hi).domin + << ", domout = " << refedges.Get(hi).domout + << ", surfnr1/2 = " << refedges.Get(hi).surfnr1 + << ", " << refedges.Get(hi).surfnr2 + << ", inv = " << refedgesinv.Get(hi) + << ", refedgenr = " << hi + << endl; + } + m *= -1; + } + } + delete locsol; + } + } + + + + void EdgeCalculation :: + StoreEdge (const ARRAY<Segment> & refedges, + const ARRAY<int> & refedgesinv, + const ARRAY<Point<3> > & edgepoints, + const ARRAY<double> & curvelength, + int layer, + Mesh & mesh) + { + + // Calculate optimal element-length + int i, j, k; + PointIndex pi; + int ne; + + double len, corr, lam; + PointIndex thispi, lastpi; + Point<3> p, np; + Segment seg; + + + const Surface * surf1 = geometry.GetSurface (refedges.Get(1).surfnr1); + const Surface * surf2 = geometry.GetSurface (refedges.Get(1).surfnr2); + + len = curvelength.Last(); + ne = int (len + 0.5); + if (ne == 0) ne = 1; + if (Dist2 (edgepoints.Get(1), edgepoints.Last()) < 1e-8 && + ne <= 6) + ne = 6; + corr = len / ne; + + // generate initial point + p = edgepoints.Get(1); + lastpi = -1; + + /* + for (pi = PointIndex::BASE; + pi < mesh.GetNP()+PointIndex::BASE; pi++) + if (Dist (mesh[pi], p) < 1e-6) + { + lastpi = pi; + break; + } + */ + ARRAY<int> locsearch; + meshpoint_tree -> GetIntersecting (p-Vec<3> (1e-6, 1e-6, 1e-6), + p+Vec<3> (1e-6, 1e-6, 1e-6), locsearch); + if (locsearch.Size()) + lastpi = locsearch[0]; + + + + if (lastpi == -1) + { + lastpi = mesh.AddPoint (p, layer); + meshpoint_tree -> Insert (p, lastpi); + } + + j = 1; + for (i = 1; i <= ne; i++) + { + while (curvelength.Get(j) < i * corr && j < curvelength.Size()) j++; + + lam = (i * corr - curvelength.Get(j-1)) / + (curvelength.Get(j) - curvelength.Get(j-1)); + + np(0) = (1-lam) * edgepoints.Get(j-1)(0) + lam * edgepoints.Get(j)(0); + np(1) = (1-lam) * edgepoints.Get(j-1)(1) + lam * edgepoints.Get(j)(1); + np(2) = (1-lam) * edgepoints.Get(j-1)(2) + lam * edgepoints.Get(j)(2); + + + thispi = -1; + if (i == ne) + { + /* + for (pi = PointIndex::BASE; + pi < mesh.GetNP()+PointIndex::BASE; pi++) + if (Dist(mesh[pi], np) < 1e-6) + thispi = pi; + */ + + meshpoint_tree -> GetIntersecting (np-Vec<3> (1e-6, 1e-6, 1e-6), + np+Vec<3> (1e-6, 1e-6, 1e-6), locsearch); + if (locsearch.Size()) + thispi = locsearch[0]; + } + + if (thispi == -1) + { + ProjectToEdge (surf1, surf2, np); + thispi = mesh.AddPoint (np, layer); + meshpoint_tree -> Insert (np, thispi); + } + + for (k = 1; k <= refedges.Size(); k++) + { + if (refedgesinv.Get(k)) + { + seg.p1 = lastpi; + seg.p2 = thispi; + } + else + { + seg.p1 = thispi; + seg.p2 = lastpi; + } + seg.si = refedges.Get(k).si; + seg.domin = refedges.Get(k).domin; + seg.domout = refedges.Get(k).domout; + seg.tlosurf = refedges.Get(k).tlosurf; + seg.edgenr = refedges.Get(k).edgenr; + seg.surfnr1 = refedges.Get(k).surfnr1; + seg.surfnr2 = refedges.Get(k).surfnr2; + seg.seginfo = 0; + if (k == 1) seg.seginfo = (refedgesinv.Get(k)) ? 2 : 1; + mesh.AddSegment (seg); + // (*testout) << "add seg " << seg.p1 << "-" << seg.p2 << endl; + + double maxh = min2 (geometry.GetSurface(seg.surfnr1)->GetMaxH(), + geometry.GetSurface(seg.surfnr2)->GetMaxH()); + + if (seg.domin != -1) + { + const Solid * s1 = + geometry.GetTopLevelObject(seg.domin) -> GetSolid(); + maxh = min2 (maxh, s1->GetMaxH()); + maxh = min2 (maxh, geometry.GetTopLevelObject(seg.domin)->GetMaxH()); + mesh.RestrictLocalH (p, maxh); + mesh.RestrictLocalH (np, maxh); + } + if (seg.domout != -1) + { + const Solid * s1 = + geometry.GetTopLevelObject(seg.domout) -> GetSolid(); + maxh = min2 (maxh, s1->GetMaxH()); + maxh = min2 (maxh, geometry.GetTopLevelObject(seg.domout)->GetMaxH()); + mesh.RestrictLocalH (p, maxh); + mesh.RestrictLocalH (np, maxh); + } + if (seg.tlosurf != -1) + { + double hi = geometry.GetTopLevelObject(seg.tlosurf) -> GetMaxH(); + maxh = min2 (maxh, hi); + mesh.RestrictLocalH (p, maxh); + mesh.RestrictLocalH (np, maxh); + } + } + + p = np; + lastpi = thispi; + } + +#ifdef DEVELOP + (*testout) << " eplast = " << lastpi << " = " << p << endl; +#endif + } + + + + + + + void EdgeCalculation :: + StoreShortEdge (const ARRAY<Segment> & refedges, + const ARRAY<int> & refedgesinv, + const ARRAY<Point<3> > & edgepoints, + const ARRAY<double> & curvelength, + int layer, + Mesh & mesh) + { + + // Calculate optimal element-length + int i, j, k; + PointIndex pi; + int ne; + Segment seg; + + /* + double len, corr, lam; + int thispi, lastpi; + Point<3> p, np; + + + const Surface * surf1 = geometry.GetSurface (refedges.Get(1).surfnr1); + const Surface * surf2 = geometry.GetSurface (refedges.Get(1).surfnr2); + + len = curvelength.Last(); + ne = int (len + 0.5); + if (ne == 0) ne = 1; + if (Dist2 (edgepoints[1], edgepoints.Last()) < 1e-8 && + ne <= 6) + ne = 6; + corr = len / ne; + */ + + // generate initial point + Point<3> p = edgepoints[0]; + PointIndex pi1 = -1; + for (pi = PointIndex::BASE; + pi < mesh.GetNP()+PointIndex::BASE; pi++) + + if (Dist (mesh[pi], p) < 1e-6) + { + pi1 = pi; + break; + } + + if (pi1 == -1) + { + pi1 = mesh.AddPoint (p, layer); + meshpoint_tree -> Insert (p, pi1); + } + + p = edgepoints.Last(); + PointIndex pi2 = -1; + for (pi = PointIndex::BASE; + pi < mesh.GetNP()+PointIndex::BASE; pi++) + + if (Dist (mesh[pi], p) < 1e-6) + { + pi2 = pi; + break; + } + if (pi2==-1) + { + pi2 = mesh.AddPoint (p, layer); + meshpoint_tree -> Insert (p, pi2); + } + + /* + + j = 1; + for (i = 1; i <= ne; i++) + { + while (curvelength[j] < i * corr && j < curvelength.Size()) j++; + + lam = (i * corr - curvelength[j-1]) / + (curvelength[j] - curvelength[j-1]); + + np(0) = (1-lam) * edgepoints[j-1](0) + lam * edgepoints[j](0); + np(1) = (1-lam) * edgepoints[j-1](1) + lam * edgepoints[j](1); + np(2) = (1-lam) * edgepoints[j-1](2) + lam * edgepoints[j](2); + + + thispi = 0; + if (i == ne) + for (j = 1; j <= mesh.GetNP(); j++) + if (Dist(mesh.Point(j), np) < 1e-6) + thispi = j; + + if (!thispi) + { + ProjectToEdge (surf1, surf2, np); + thispi = mesh.AddPoint (np); + } + */ + + for (k = 1; k <= refedges.Size(); k++) + { + if (refedgesinv.Get(k)) + { + seg.p1 = pi1; + seg.p2 = pi2; + } + else + { + seg.p1 = pi2; + seg.p2 = pi1; + } + + seg.si = refedges.Get(k).si; + seg.domin = refedges.Get(k).domin; + seg.domout = refedges.Get(k).domout; + seg.tlosurf = refedges.Get(k).tlosurf; + seg.edgenr = refedges.Get(k).edgenr; + seg.surfnr1 = refedges.Get(k).surfnr1; + seg.surfnr2 = refedges.Get(k).surfnr2; + seg.seginfo = 0; + if (k == 1) seg.seginfo = (refedgesinv.Get(k)) ? 2 : 1; + mesh.AddSegment (seg); + // (*testout) << "add seg " << seg.p1 << "-" << seg.p2 << endl; + } + } + + + + + + + + void EdgeCalculation :: + CopyEdge (const ARRAY<Segment> & refedges, + const ARRAY<int> & refedgesinv, + int copyfromedge, + const Point<3> & fromstart, const Point<3> & fromend, + const Point<3> & tostart, const Point<3> & toend, + int copyedgeidentification, + int layer, + Mesh & mesh) + { + int i, j, k; + PointIndex pi; + + // copy start and end points + for (i = 1; i <= 2; i++) + { + Point<3> fromp = + (i == 1) ? fromstart : fromend; + Point<3> top = + (i == 1) ? tostart : toend; + + PointIndex frompi = -1; + PointIndex topi = -1; + for (pi = PointIndex::BASE; + pi < mesh.GetNP()+PointIndex::BASE; pi++) + { + if (Dist2 (mesh[pi], fromp) <= 1e-16) + frompi = pi; + if (Dist2 (mesh[pi], top) <= 1e-16) + topi = pi; + } + + if (topi == -1) + { + topi = mesh.AddPoint (top, layer); + meshpoint_tree -> Insert (top, topi); + } + + const Identification & csi = + (*geometry.identifications.Get(copyedgeidentification)); + + if (csi.Identifyable (mesh[frompi], mesh[topi])) + mesh.GetIdentifications().Add(frompi, topi, copyedgeidentification); + else if (csi.Identifyable (mesh[topi], mesh[frompi])) + mesh.GetIdentifications().Add(topi, frompi, copyedgeidentification); + else + { + cerr << "edgeflw.cpp: should identify, but cannot"; + exit(1); + } + /* + (*testout) << "Add Identification from CopyEdge, p1 = " + << mesh[PointIndex(frompi)] << ", p2 = " + << mesh[PointIndex(topi)] << endl; + + mesh.GetIdentifications().Add(frompi, topi, copyedgeidentification); + */ + } + + int oldns = mesh.GetNSeg(); + for (i = 1; i <= oldns; i++) + { + // real copy, since array might be reallocated !! + const Segment oldseg = mesh.LineSegment(i); + if (oldseg.edgenr != copyfromedge) + continue; + if (oldseg.seginfo == 0) + continue; + + int pi1 = oldseg.p1; + int pi2 = oldseg.p2; + + int npi1 = geometry.identifications.Get(copyedgeidentification) + -> GetIdentifiedPoint (mesh, pi1); + int npi2 = geometry.identifications.Get(copyedgeidentification) + -> GetIdentifiedPoint (mesh, pi2); + + Segment seg; + + for (k = 1; k <= refedges.Size(); k++) + { + int inv = refedgesinv.Get(k); + + // other edge is inverse + if (oldseg.seginfo == 1) + inv = !inv; + + // (*testout) << "inv, now = " << inv << endl; + + if (inv) + { + seg.p1 = npi1; + seg.p2 = npi2; + } + else + { + seg.p1 = npi2; + seg.p2 = npi1; + } + seg.si = refedges.Get(k).si; + seg.domin = refedges.Get(k).domin; + seg.domout = refedges.Get(k).domout; + seg.tlosurf = refedges.Get(k).tlosurf; + seg.edgenr = refedges.Get(k).edgenr; + seg.surfnr1 = refedges.Get(k).surfnr1; + seg.surfnr2 = refedges.Get(k).surfnr2; + seg.seginfo = 0; + if (k == 1) seg.seginfo = refedgesinv.Get(k) ? 2 : 1; + mesh.AddSegment (seg); + // (*testout) << "copy seg " << seg.p1 << "-" << seg.p2 << endl; +#ifdef DEVELOP + + (*testout) << "copy seg, face = " << seg.si << ": " + << " inv = " << inv << ", refinv = " << refedgesinv.Get(k) + << mesh.Point(seg.p1) << ", " << mesh.Point(seg.p2) << endl; +#endif + + } + + } + } + + + + + + + + void EdgeCalculation :: + FindClosedSurfaces (double h, Mesh & mesh) + { + // if there is no special point at a sphere, one has to add a segment pair + + int i, j; + int nsol; + int nsurf = geometry.GetNSurf(); + int layer; + + BitArray pointatsurface (nsurf); + Point<3> p1, p2; + Vec<3> nv, tv; + Solid * tansol; + ARRAY<int> tansurfind; + // const Solid * sol; + + nsol = geometry.GetNTopLevelObjects(); + + + pointatsurface.Clear(); + + /* + for (i = 1; i <= specpoints.Size(); i++) + { + int classrep; + + classrep = geometry.GetSurfaceClassRepresentant (specpoints[i].s1); + pointatsurface.Set (classrep); + classrep = geometry.GetSurfaceClassRepresentant (specpoints[i].s2); + pointatsurface.Set (classrep); + // pointatsurface.Set (specpoints[i].s1); + // pointatsurface.Set (specpoints[i].s2); + } + */ + for (i = 1; i <= mesh.GetNSeg(); i++) + { + const Segment & seg = mesh.LineSegment(i); + int classrep; + +#ifdef DEVELOP + (*testout) << seg.surfnr1 << ", " << seg.surfnr2 << ", si = " << seg.si << endl; +#endif + classrep = geometry.GetSurfaceClassRepresentant (seg.si); + + pointatsurface.Set (classrep); + } + + + for (i = 0; i < nsurf; i++) + { + int classrep = geometry.GetSurfaceClassRepresentant (i); + + if (!pointatsurface.Test(classrep)) + { + const Surface * s = geometry.GetSurface(i); + p1 = s -> GetSurfacePoint(); + s -> GetNormalVector (p1, nv); + + double hloc = + min2 (s->LocH (p1, 3, 1, h), mesh.GetH(p1)); + + tv = nv.GetNormal (); + tv *= (hloc / tv.Length()); + p2 = p1 + tv; + s->Project (p2); + + + Segment seg1; + seg1.si = i; + seg1.domin = -1; + seg1.domout = -1; + + Segment seg2; + seg2.si = i; + seg2.domin = -1; + seg2.domout = -1; + + seg1.surfnr1 = i; + seg2.surfnr1 = i; + seg1.surfnr2 = i; + seg2.surfnr2 = i; + + for (j = 0; j < nsol; j++) + { + if (geometry.GetTopLevelObject(j)->GetSurface()) + continue; + + const Solid * sol = geometry.GetTopLevelObject(j)->GetSolid(); + sol -> TangentialSolid (p1, tansol); + layer = geometry.GetTopLevelObject(j)->GetLayer(); + + if (tansol) + { + tansol -> GetSurfaceIndices (tansurfind); + + if (tansurfind.Size() == 1 && tansurfind.Get(1) == i) + { + if (!tansol->VectorIn(p1, nv)) + { + seg1.domin = j; + seg2.domin = j; + seg1.tlosurf = j; + seg2.tlosurf = j; + } + else + { + seg1.domout = j; + seg2.domout = j; + seg1.tlosurf = j; + seg2.tlosurf = j; + } + // seg.s2 = i; + // seg.invs1 = surfaces[i] -> Inverse(); + // seg.invs2 = ! (surfaces[i] -> Inverse()); + } + delete tansol; + } + } + + + if (seg1.domin != -1 || seg1.domout != -1) + { + mesh.AddPoint (p1, layer); + mesh.AddPoint (p2, layer); + seg1.p1 = mesh.GetNP()-1; + seg1.p2 = mesh.GetNP(); + seg2.p2 = mesh.GetNP()-1; + seg2.p1 = mesh.GetNP(); + seg1.geominfo[0].trignum = 1; + seg1.geominfo[1].trignum = 1; + seg2.geominfo[0].trignum = 1; + seg2.geominfo[1].trignum = 1; + mesh.AddSegment (seg1); + mesh.AddSegment (seg2); + + PrintMessage (5, "Add line segment to smooth surface"); + +#ifdef DEVELOP + (*testout) << "Add segment at smooth surface " << i; + if (i != classrep) (*testout) << ", classrep = " << classrep; + (*testout) << ": " + << mesh.Point (mesh.GetNP()-1) << " - " + << mesh.Point (mesh.GetNP()) << endl; +#endif + } + } + } + } + +} diff --git a/contrib/Netgen/libsrc/csg/edgeflw_old.cpp b/contrib/Netgen/libsrc/csg/edgeflw_old.cpp new file mode 100644 index 0000000000..5321dfd17d --- /dev/null +++ b/contrib/Netgen/libsrc/csg/edgeflw_old.cpp @@ -0,0 +1,1405 @@ +#include <mystdlib.h> +#include <meshing.hpp> +#include <csg.hpp> + +#undef DEVELOP + +namespace netgen +{ + + EdgeCalculation :: + EdgeCalculation (const CSGeometry & ageometry, + ARRAY<SpecialPoint> & aspecpoints) + : geometry(ageometry), specpoints(aspecpoints) + { + ; + } + + EdgeCalculation :: ~EdgeCalculation () + { ; } + + void EdgeCalculation :: Calc(double h, Mesh & mesh) + { + PrintMessage (1, "Find edges"); + PushStatus ("Find edges"); + + CalcEdges1 (h, mesh); + SplitEqualOneSegEdges (mesh); + FindClosedSurfaces (h, mesh); + PrintMessage (3, cntedge, " edges found"); + + PopStatus (); + } + + + + + void EdgeCalculation :: CalcEdges1 (double h, Mesh & mesh) + { + ARRAY<SpecialPoint> hsp(specpoints.Size()); + ARRAY<SpecialPoint> startpoints, endpoints; + + int i, j, k, l, hi, pos, ep, ne; + int layer; + + Vec<3> a1, a2, t, n, m; + Point<3> p, np, pnp, hp; + + Segment seg; + int pi1, s1, s2; + int lastpi, thispi; + + ARRAY<Point<3> > edgepoints; + ARRAY<double> curvelength; + int copyedge, copyfromedge, copyedgeidentification; + + ARRAY<int> locsurfind; + + double len, corr, lam; + double steplen, cursteplen, loch, hd; + + int checkedcopy = 0; + + double size = geometry.MaxSize(); // globflags.GetNumFlag ("maxsize", 500); + double epspointdist2 = size * 1e-6; // globflags.GetNumFlag ("epspointdist", size * 1e-6); + epspointdist2 = sqr (epspointdist2); + + + Solid * locsol; + + + // copy special points to work with + for (i = 0; i < specpoints.Size(); i++) + hsp[i] = specpoints[i]; + + + cntedge = 0; + + while (hsp.Size()) + { + SetThreadPercent(100 - 100 * double (hsp.Size()) / specpoints.Size()); + + edgepoints.SetSize (0); + curvelength.SetSize (0); + + + pi1 = 0; + copyedge = 0; + // identifyable point available ? + + // (*testout) << endl; + + for (i = 1; i <= geometry.identifications.Size() && !pi1; i++) + { + for (j = checkedcopy+1; j <= startpoints.Size() && !pi1; j++) + { + + if (geometry.identifications.Get(i)->IdentifyableCandidate (startpoints.Get(j))) + + { + int pi1cand = 0; + double mindist = 1e10; + + for (k = 1; k <= hsp.Size() && !pi1; k++) + { +#ifdef DEVELOP + (*testout) << "check kand = " << hsp.Get(k).p + << ", v = " << hsp.Get(k).v + << endl; +#endif + if (geometry.identifications.Get(i) + ->Identifyable(startpoints.Get(j), hsp.Get(k)) || + geometry.identifications.Get(i) + ->Identifyable(hsp.Get(k), startpoints.Get(j))) + { + +#ifdef DEVELOP + (*testout) << "identifiable, dist = " + << Dist (startpoints.Get(j).p, hsp.Get(k).p) << endl; +#endif + + if (Dist (startpoints.Get(j).p, hsp.Get(k).p) < mindist) + { + mindist = Dist (startpoints.Get(j).p, hsp.Get(k).p); + pi1cand = k; + } + /* + pi1 = k; + copyedge = 1; + copyfromedge = j; + copyedgeidentification = i; + + (*testout) << "copy edge startpoint from " + << startpoints.Get(j).p << " - " + << startpoints.Get(j).v + << " to " + << hsp.Get(k).p << " - " << hsp.Get(k).v << endl; + */ + } + } + + if (pi1cand) + { + pi1 = pi1cand; + copyedge = 1; + copyfromedge = j; + copyedgeidentification = i; +#ifdef DEVELOP + (*testout) << "copy edge startpoint from " + << startpoints.Get(j).p << " - " + << startpoints.Get(j).v + << " to " + << hsp.Get(pi1).p << " - " << hsp.Get(pi1).v << endl; +#endif + } + } + } + } + + + // cannot copy from other ege ? + if (!pi1) + checkedcopy = startpoints.Size(); + + // unconditional special point available ? + if (!pi1) + for (i = 1; i <= hsp.Size() && pi1 == 0; i++) + if (hsp.Get(i).unconditional == 1) + pi1 = i; + + + if (!pi1) + { + // only unconditional points available, choose first + pi1 = 1; + } + + layer = hsp.Get(pi1).GetLayer(); + + + if (!hsp.Get(pi1).unconditional) + { + hsp.Elem(pi1).unconditional = 1; + for (i = 1; i <= hsp.Size(); i++) + if (i != pi1 && Dist (hsp.Get(pi1).p, hsp.Get(i).p) < 1e-8 && + (hsp.Get(pi1).v + hsp.Get(i).v).Length() < 1e-4) + { + // opposite direction + hsp.Elem(i).unconditional = 1; + } + } + + cntedge++; + startpoints.Append (hsp.Get(pi1)); + +#ifdef DEVELOP + (*testout) << "edge nr " << cntedge << endl; + (*testout) << "start followedge: p1 = " << hsp.Get(pi1).p << ", v = " << hsp.Get(pi1).v << endl; +#endif + + FollowEdge (pi1, ep, pos, hsp, h, mesh, + edgepoints, curvelength); + + + if (multithread.terminate) + return; + + if (!ep) + { + // ignore starting point + hsp.DeleteElement (pi1); + continue; + } + + + + endpoints.Append (hsp.Get(ep)); + + + double elen = 0; + for (i = 1; i <= edgepoints.Size()-1; i++) + elen += Dist (edgepoints.Get(i), edgepoints.Get(i+1)); + + + int shortedge = 0; + for (i = 1; i <= geometry.identifications.Size(); i++) + if (geometry.identifications.Get(i)->ShortEdge(hsp.Get(pi1), hsp.Get(ep))) + shortedge = 1; + (*testout) << "shortedge = " << shortedge << endl; + + + if (!shortedge) + { + mesh.RestrictLocalHLine (Point3d (hsp.Get(pi1).p), + Point3d (hsp.Get(ep).p), + elen / mparam.segmentsperedge); + } + + s1 = hsp.Get(pi1).s1; + s2 = hsp.Get(pi1).s2; + + + // delete initial, terminal and conditional points + +#ifdef DEVELOP + (*testout) << "terminal point: p = " << hsp.Get(ep).p << ", v = " << hsp.Get(ep).v << endl; +#endif + if (ep > pi1) + { + hsp.DeleteElement (ep); + hsp.DeleteElement (pi1); + } + else + { + hsp.DeleteElement (pi1); + hsp.DeleteElement (ep); + } + + + for (j = 1; j <= edgepoints.Size()-1; j++) + { + p = edgepoints.Get(j); + np = Center (p, edgepoints.Get(j+1)); + hd = Dist2 (p, np); + + for (i = 1; i <= hsp.Size(); i++) + if ( hsp.Get(i).HasSurfaces (s1, s2) && + hsp.Get(i).unconditional == 0 && + Dist2 (np, hsp.Get(i).p) < 1.2 * hd) + { + hsp.DeleteElement (i); + i--; + } + } + + + ARRAY<Segment> refedges; + ARRAY<int> refedgesinv; + + + AnalyzeEdge (s1, s2, pos, layer, + edgepoints, + refedges, refedgesinv); + + for (i = 1; i <= refedges.Size(); i++) + refedges.Elem(i).edgenr = cntedge; + + +#ifdef DEVELOP + (*testout) << "edge " << cntedge << endl + << "startp: " << startpoints.Last().p + << ", v = " << startpoints.Last().v << endl + << "copy = " << copyedge << endl + << refedges.Size() << " refedges: "; + for (i = 1; i <= refedges.Size(); i++) + (*testout) << " " << refedges.Get(i).si; + (*testout) << endl; + (*testout) << "inv[1] = " << refedgesinv.Get(1) << endl; +#endif + + if (!copyedge) + { + int oldnseg = mesh.GetNSeg(); + + if (!shortedge) + StoreEdge (refedges, refedgesinv, + edgepoints, curvelength, layer, mesh); + else + StoreShortEdge (refedges, refedgesinv, + edgepoints, curvelength, layer, mesh); + + + /* + for (i = oldnseg+1; i <= mesh.GetNSeg(); i++) + for (j = 1; j <= oldnseg; j++) + { + const Point<3> & l1p1 = mesh.Point (mesh.LineSegment(i).p1); + const Point<3> & l1p2 = mesh.Point (mesh.LineSegment(i).p2); + const Point<3> & l2p1 = mesh.Point (mesh.LineSegment(j).p1); + const Point<3> & l2p2 = mesh.Point (mesh.LineSegment(j).p2); + Vec<3> vl1(l1p1, l1p2); + for (double lamk = 0; lamk <= 1; lamk += 0.1) + { + Point<3> l2p = l1p1 + lamk * vl1; + double dist = sqrt (MinDistLP2 (l2p1, l2p2, l2p)); + if (dist > 1e-12) + mesh.RestrictLocalH (l2p, 3*dist); + } + } + */ + } + else + { + CopyEdge (refedges, refedgesinv, + copyfromedge, + startpoints.Get(copyfromedge).p, + endpoints.Get(copyfromedge).p, + edgepoints.Get(1), edgepoints.Last(), + copyedgeidentification, + layer, + mesh); + } + + } + } + + + + /* + If two or more edges share the same initial and end-points, + then they need at least two segments + */ + void EdgeCalculation :: + SplitEqualOneSegEdges (Mesh & mesh) + { + int i, j; + SegmentIndex si; + PointIndex pi; + + ARRAY<int> osedges(cntedge); + INDEX_2_HASHTABLE<int> osedgesht (cntedge+1); + + osedges = 2; + + // count segments on edges + for (si = 0; si < mesh.GetNSeg(); si++) + { + const Segment & seg = mesh[si]; + if (seg.seginfo && seg.edgenr >= 1 && seg.edgenr <= cntedge) + osedges.Elem(seg.edgenr)--; + } + + (*testout) << "osedges = " << osedges << endl; + + // flag one segment edges + for (i = 0; i < cntedge; i++) + osedges[i] = (osedges[i] > 0) ? 1 : 0; + + (*testout) << "osedges, now = " << osedges << endl; + + for (si = 0; si < mesh.GetNSeg(); si++) + { + const Segment & seg = mesh[si]; + if (seg.seginfo && seg.edgenr >= 1 && seg.edgenr <= cntedge) + { + if (osedges.Get(seg.edgenr)) + { + INDEX_2 i2(seg.p1, seg.p2); + i2.Sort (); + if (osedgesht.Used (i2)) + osedgesht.Set (i2, 2); + else + osedgesht.Set (i2, 1); + } + } + } + + + // one edge 1 segment, other 2 segments + // yes, it happens ! + + for (i = 1; i <= osedgesht.GetNBags(); i++) + for (j = 1; j <= osedgesht.GetBagSize(i); j++) + { + INDEX_2 i2; + int val; + osedgesht.GetData (i, j, i2, val); + + const Point<3> & p1 = mesh[PointIndex(i2.I1())]; + const Point<3> & p2 = mesh[PointIndex(i2.I2())]; + Vec<3> v = p2 - p1; + double vlen = v.Length(); + v /= vlen; + for (pi = PointIndex::BASE; + pi < mesh.GetNP()+PointIndex::BASE; pi++) + + if (pi != i2.I1() && pi != i2.I2()) + { + const Point<3> & p = mesh[pi]; + Vec<3> v2 = p - p1; + double lam = (v2 * v); + if (lam > 0 && lam < vlen) + { + Point<3> hp = p1 + lam * v; + if (Dist (p, hp) < 1e-4 * vlen) + { + PrintSysError ("Point on edge !!!"); + cout << "seg: " << i2 << ", p = " << pi << endl; + osedgesht.Set (i2, 2); + } + } + } + } + + + // insert new points + osedges = -1; + + int nseg = mesh.GetNSeg(); + for (si = 0; si < nseg; si++) + { + const Segment & seg = mesh[si]; + if (seg.seginfo && seg.edgenr >= 1 && seg.edgenr <= cntedge) + { + INDEX_2 i2(seg.p1, seg.p2); + i2.Sort (); + if (osedgesht.Used (i2) && + osedgesht.Get (i2) == 2 && + osedges.Elem(seg.edgenr) == -1) + { + Point<3> newp = Center (mesh[PointIndex(seg.p1)], + mesh[PointIndex(seg.p2)]); + + ProjectToEdge (geometry.GetSurface(seg.surfnr1), + geometry.GetSurface(seg.surfnr2), + newp); + + osedges.Elem(seg.edgenr) = + mesh.AddPoint (newp, mesh[PointIndex(seg.p1)].GetLayer()); + } + } + } + + + for (i = 1; i <= nseg; i++) + { + Segment & seg = mesh.LineSegment (i); + if (seg.edgenr >= 1 && seg.edgenr <= cntedge) + { + if (osedges.Get(seg.edgenr) != -1) + { + Segment newseg = seg; + newseg.p1 = osedges.Get(seg.edgenr); + seg.p2 = osedges.Get(seg.edgenr); + mesh.AddSegment (newseg); + } + } + } + + } + + + + void EdgeCalculation :: + FollowEdge (int pi1, int & ep, int & pos, + const ARRAY<SpecialPoint> & hsp, + double h, const Mesh & mesh, + ARRAY<Point<3> > & edgepoints, + ARRAY<double> & curvelength) + { + int i, j, s1, s2; + double len, steplen, cursteplen, loch; + Point<3> p, np, pnp; + Vec<3> a1, a2, t; + + + double size = geometry.MaxSize(); + double epspointdist2 = size * 1e-6; + epspointdist2 = sqr (epspointdist2); + int uselocalh = mparam.uselocalh; + + + s1 = hsp.Get(pi1).s1; + s2 = hsp.Get(pi1).s2; + + p = hsp.Get(pi1).p; + geometry.GetSurface(s1) -> CalcGradient (p, a1); + geometry.GetSurface(s2) -> CalcGradient (p, a2); + + t = Cross (a1, a2); + t.Normalize(); + + pos = (hsp.Get(pi1).v * t) > 0; + if (!pos) t *= -1; + + + edgepoints.Append (p); + curvelength.Append (0); + len = 0; + + loch = min2 (geometry.GetSurface(s1) -> LocH (p, 3, 1, h), + geometry.GetSurface(s2) -> LocH (p, 3, 1, h)); + + + + if (uselocalh) + { + double lh = mesh.GetH(p); + if (lh < loch) + loch = lh; + } + + steplen = 0.1 * loch; + + do + { + if (multithread.terminate) + return; + + if (fabs (p(0)) + fabs (p(1)) + fabs (p(2)) > 10000) + { + ep = 0; + PrintWarning ("Give up line"); + break; + } + + if (steplen > 0.1 * loch) steplen = 0.1 * loch; + + steplen *= 2; + do + { + steplen *= 0.5; + np = p + steplen * t; + pnp = np; + ProjectToEdge (geometry.GetSurface(s1), + geometry.GetSurface(s2), pnp); + } + while (Dist (np, pnp) > 0.1 * steplen); + + cursteplen = steplen; + if (Dist (np, pnp) < 0.01 * steplen) steplen *= 2; + + + np = pnp; + +#ifdef MYGRAPH + if (silentflag <= 2) + { + MyLine3D (p, np, rot); + MyDraw (); + } +#endif + + ep = 0; + + double hvtmin = 1.5 * cursteplen; + + Box<3> boxp (p - (2 * cursteplen) * Vec<3> (1, 1, 1), + p + (2 * cursteplen) * Vec<3> (1, 1, 1)); + + for (i = 1; i <= hsp.Size(); i++) + // if ( i != pi1 && hsp.Get(i).HasSurfaces (s1, s2) ) + { + if (!boxp.IsIn (hsp.Get(i).p)) + continue; + + Vec<3> hv = hsp.Get(i).p - p; + if (hv.Length2() > 9 * cursteplen * cursteplen) + continue; + + /* + if (!hsp.Get(i).HasSurfaces (s1, s2)) + continue; // test for dalibor-problem + */ + + double hvt = hv * t; + hv -= hvt * t; + + if (hv.Length() < 0.2 * cursteplen && + hvt > 0 && + // hvt < 1.5 * cursteplen && + hvt < hvtmin && + hsp.Get(i).unconditional == 1 && + (hsp.Get(i).v + t).Length() < 0.4 ) + { + Point<3> hep = hsp.Get(i).p; + ProjectToEdge (geometry.GetSurface(s1), + geometry.GetSurface(s2), hep); + + + if (Dist2 (hep, hsp.Get(i).p) < epspointdist2 ) + { + geometry.GetSurface(s1) -> CalcGradient (hep, a1); + geometry.GetSurface(s2) -> CalcGradient (hep, a2); + Vec<3> ept = Cross (a1, a2); + ept /= ept.Length(); + if (!pos) ept *= -1; + + if ( (hsp.Get(i).v + ept).Length() < 1e-4 ) + { + np = hsp.Get(i).p; + ep = i; + hvtmin = hvt; + // break; + } + } + } + } + + loch = min2 (geometry.GetSurface(s1) -> LocH (np, 3, 1, h), + geometry.GetSurface(s2) -> LocH (np, 3, 1, h)); + + if (uselocalh) + { + double lh = mesh.GetH(np); + if (lh < loch) + loch = lh; + } + + + len += Dist (p, np) / loch; + edgepoints.Append (np); + curvelength.Append (len); + + p = np; + + geometry.GetSurface(s1) -> CalcGradient (p, a1); + geometry.GetSurface(s2) -> CalcGradient (p, a2); + t = Cross (a1, a2); + t.Normalize(); + if (!pos) t *= -1; + } + while (! ep); + } + + + + + + + + void EdgeCalculation :: + AnalyzeEdge (int s1, int s2, int pos, int layer, + const ARRAY<Point<3> > & edgepoints, + ARRAY<Segment> & refedges, + ARRAY<int> & refedgesinv) + { + int i, j, k, l; + int hi; + Point<3> hp; + Vec<3> t, a1, a2, m, n; + Segment seg; + Solid * locsol; + ARRAY<int> locsurfind; + + /* + int pi1 = 0, pi2 = 0; + extern Mesh * mesh; + for (i = 1; i <= mesh->GetNP(); i++) + { + if (Dist2 (edgepoints.Get(1), mesh->Point(i)) < 1e-12) + pi1 = i; + if (Dist2 (edgepoints.Last(), mesh->Point(i)) < 1e-12) + pi2 = i; + } + (*testout) << "Analyze edge: " << pi1 << " - " << pi2 << ", pts = " << edgepoints.Size() << endl; + (*testout) << "p1 = " << edgepoints.Get(1) << " pl = " << edgepoints.Last() << endl; + */ + int debug = 0; + /* + Dist2 (Point<3> (2.69642, 1.1866, 2.03), edgepoints.Get(1)) < 1e-6 || + Dist2 (Point<3> (2.69642, 1.1866, 2.03), edgepoints.Last()) < 1e-6; + */ + + if (debug) + { + // (*testout) << "tubious edge !!!" << endl; + (*testout) << "s1, s2 = " << s1 << " - " << s2 << endl; + } + + refedges.SetSize(0); + refedgesinv.SetSize(0); + hp = Center (edgepoints.Get(1), edgepoints.Get(2)); + ProjectToEdge (geometry.GetSurface(s1), geometry.GetSurface(s2), hp); + + geometry.GetSurface(s1) -> CalcGradient (hp, a1); + geometry.GetSurface(s2) -> CalcGradient (hp, a2); + t = Cross (a1, a2); + t.Normalize(); + if (!pos) t *= -1; + + (*testout) << "t = " << t << endl; + + for (i = 0; i < geometry.GetNTopLevelObjects(); i++) + { + (*testout) << "layer = " << layer + << ", tlo-layer = " << geometry.GetTopLevelObject(i)->GetLayer() << endl; + if (geometry.GetTopLevelObject(i)->GetLayer() != layer) + continue; + + const Solid * sol = geometry.GetTopLevelObject(i)->GetSolid(); + const Surface * surf = geometry.GetTopLevelObject(i)->GetSurface(); + + sol -> TangentialSolid (hp, locsol); + if (!locsol) continue; + + BoxSphere<3> boxp (hp, hp); + boxp.Increase (1e-5); + boxp.CalcDiamCenter(); + + ReducePrimitiveIterator rpi(boxp); + UnReducePrimitiveIterator urpi; + + ((Solid*)locsol) -> IterateSolid (rpi); + + locsol -> CalcSurfaceInverse (); + + + if (!surf) + { + locsol -> GetSurfaceIndices (locsurfind); + } + else + { + /* + if (fabs (surf->CalcFunctionValue (hp)) < 1e-6) + continue; + */ + locsurfind.SetSize(1); + locsurfind[0] = -1; + for (j = 0; j < geometry.GetNSurf(); j++) + if (geometry.GetSurface(j) == surf) + { + locsurfind[0] = j; + // geometry.GetSurfaceClassRepresentant(j); + break; + } + } + + ((Solid*)locsol) -> IterateSolid (urpi); + + + if (debug) + (*testout) << "edge of tlo " << i << ", has " << locsurfind.Size() << " faces." << endl; + + + for (j = locsurfind.Size()-1; j >= 0; j--) + if (fabs (geometry.GetSurface(locsurfind[j]) + ->CalcFunctionValue (hp) ) > 1e-6) + locsurfind.DeleteElement(j+1); + + if (debug) + (*testout) << locsurfind.Size() << " faces on hp" << endl; + + for (j = 0; j < locsurfind.Size(); j++) + { + int lsi = locsurfind[j]; + int rlsi = geometry.GetSurfaceClassRepresentant(lsi); + + Vec<3> rn; + + // n is outer normal to solid + geometry.GetSurface(lsi) -> GetNormalVector (hp, n); + if (geometry.GetSurface (lsi)->Inverse()) + n *= -1; + + if (fabs (t * n) > 1e-4) continue; + if (debug) + { + (*testout) << "face " << locsurfind.Get(j) << ", rep = " << rlsi + << " has (t*n) = " << (t*n) << endl; + (*testout) << "n = " << n << endl; + } + + // rn is normal to class representant + geometry.GetSurface(rlsi) -> GetNormalVector (hp, rn); + + int sameasref = ((n * rn) > 0); + + m = Cross (t, rn); + m.Normalize(); + + + for (k = 1; k <= 2; k ++) + { + bool edgeinv = (k == 2); + + if (debug) + { + (*testout) << "onface(" << hp << ", " << m << ")= " + << locsol->OnFace (hp, m); + (*testout) << " vec2in = " + << locsol -> VectorIn2 (hp, m, n) << " and " + << locsol -> VectorIn2 (hp, m, -1 * n) << endl; + } + + // if (locsol -> OnFace (hp, m)) + if (locsol -> VectorIn2 (hp, m, n) == 0 && + locsol -> VectorIn2 (hp, m, -1 * n) == 1) + { + hi = 0; + for (l = 1; l <= refedges.Size(); l++) + { + if (refedges.Get(l).si == rlsi && + refedgesinv.Get(l) == edgeinv) + hi = l; + } + + if (!hi) + { + seg.si = rlsi; + seg.domin = -1; + seg.domout = -1; + seg.tlosurf = -1; + seg.surfnr1 = s1; + seg.surfnr2 = s2; + hi = refedges.Append (seg); + refedgesinv.Append (edgeinv); + } + + if (!surf) + { + if (sameasref) + refedges.Elem(hi).domin = i; + else + refedges.Elem(hi).domout = i; + } + else + refedges.Elem(hi).tlosurf = i; + + if (debug) + (*testout) << "add ref seg:" + << "si = " << refedges.Get(hi).si + << ", domin = " << refedges.Get(hi).domin + << ", domout = " << refedges.Get(hi).domout + << ", surfnr1/2 = " << refedges.Get(hi).surfnr1 + << ", " << refedges.Get(hi).surfnr2 + << ", inv = " << refedgesinv.Get(hi) + << ", refedgenr = " << hi + << endl; + } + m *= -1; + } + } + delete locsol; + } + } + + + + void EdgeCalculation :: + StoreEdge (const ARRAY<Segment> & refedges, + const ARRAY<int> & refedgesinv, + const ARRAY<Point<3> > & edgepoints, + const ARRAY<double> & curvelength, + int layer, + Mesh & mesh) + { + + // Calculate optimal element-length + int i, j, k; + PointIndex pi; + int ne; + + double len, corr, lam; + PointIndex thispi, lastpi; + Point<3> p, np; + Segment seg; + + + const Surface * surf1 = geometry.GetSurface (refedges.Get(1).surfnr1); + const Surface * surf2 = geometry.GetSurface (refedges.Get(1).surfnr2); + + len = curvelength.Last(); + ne = int (len + 0.5); + if (ne == 0) ne = 1; + if (Dist2 (edgepoints.Get(1), edgepoints.Last()) < 1e-8 && + ne <= 6) + ne = 6; + corr = len / ne; + + // generate initial point + p = edgepoints.Get(1); + lastpi = -1; + for (pi = PointIndex::BASE; + pi < mesh.GetNP()+PointIndex::BASE; pi++) + if (Dist (mesh[pi], p) < 1e-6) + { + lastpi = pi; + break; + } + + if (lastpi == -1) + lastpi = mesh.AddPoint (p, layer); + + + j = 1; + for (i = 1; i <= ne; i++) + { + while (curvelength.Get(j) < i * corr && j < curvelength.Size()) j++; + + lam = (i * corr - curvelength.Get(j-1)) / + (curvelength.Get(j) - curvelength.Get(j-1)); + + np(0) = (1-lam) * edgepoints.Get(j-1)(0) + lam * edgepoints.Get(j)(0); + np(1) = (1-lam) * edgepoints.Get(j-1)(1) + lam * edgepoints.Get(j)(1); + np(2) = (1-lam) * edgepoints.Get(j-1)(2) + lam * edgepoints.Get(j)(2); + + + thispi = -1; + if (i == ne) + for (pi = PointIndex::BASE; + pi < mesh.GetNP()+PointIndex::BASE; pi++) + if (Dist(mesh[pi], np) < 1e-6) + thispi = pi; + + if (thispi == -1) + { + ProjectToEdge (surf1, surf2, np); + thispi = mesh.AddPoint (np, layer); + } + + for (k = 1; k <= refedges.Size(); k++) + { + if (refedgesinv.Get(k)) + { + seg.p1 = lastpi; + seg.p2 = thispi; + } + else + { + seg.p1 = thispi; + seg.p2 = lastpi; + } + seg.si = refedges.Get(k).si; + seg.domin = refedges.Get(k).domin; + seg.domout = refedges.Get(k).domout; + seg.tlosurf = refedges.Get(k).tlosurf; + seg.edgenr = refedges.Get(k).edgenr; + seg.surfnr1 = refedges.Get(k).surfnr1; + seg.surfnr2 = refedges.Get(k).surfnr2; + seg.seginfo = 0; + if (k == 1) seg.seginfo = (refedgesinv.Get(k)) ? 2 : 1; + mesh.AddSegment (seg); + // (*testout) << "add seg " << seg.p1 << "-" << seg.p2 << endl; + + double maxh = min2 (geometry.GetSurface(seg.surfnr1)->GetMaxH(), + geometry.GetSurface(seg.surfnr2)->GetMaxH()); + + if (seg.domin != -1) + { + const Solid * s1 = + geometry.GetTopLevelObject(seg.domin) -> GetSolid(); + maxh = min2 (maxh, s1->GetMaxH()); + maxh = min2 (maxh, geometry.GetTopLevelObject(seg.domin)->GetMaxH()); + mesh.RestrictLocalH (p, maxh); + mesh.RestrictLocalH (np, maxh); + } + if (seg.domout != -1) + { + const Solid * s1 = + geometry.GetTopLevelObject(seg.domout) -> GetSolid(); + maxh = min2 (maxh, s1->GetMaxH()); + maxh = min2 (maxh, geometry.GetTopLevelObject(seg.domout)->GetMaxH()); + mesh.RestrictLocalH (p, maxh); + mesh.RestrictLocalH (np, maxh); + } + if (seg.tlosurf != -1) + { + double hi = geometry.GetTopLevelObject(seg.tlosurf) -> GetMaxH(); + maxh = min2 (maxh, hi); + mesh.RestrictLocalH (p, maxh); + mesh.RestrictLocalH (np, maxh); + } + } + + p = np; + lastpi = thispi; + } + +#ifdef DEVELOP + (*testout) << " eplast = " << lastpi << " = " << p << endl; +#endif + } + + + + + + + void EdgeCalculation :: + StoreShortEdge (const ARRAY<Segment> & refedges, + const ARRAY<int> & refedgesinv, + const ARRAY<Point<3> > & edgepoints, + const ARRAY<double> & curvelength, + int layer, + Mesh & mesh) + { + + // Calculate optimal element-length + int i, j, k; + PointIndex pi; + int ne; + Segment seg; + + /* + double len, corr, lam; + int thispi, lastpi; + Point<3> p, np; + + + const Surface * surf1 = geometry.GetSurface (refedges.Get(1).surfnr1); + const Surface * surf2 = geometry.GetSurface (refedges.Get(1).surfnr2); + + len = curvelength.Last(); + ne = int (len + 0.5); + if (ne == 0) ne = 1; + if (Dist2 (edgepoints[1], edgepoints.Last()) < 1e-8 && + ne <= 6) + ne = 6; + corr = len / ne; + */ + + // generate initial point + Point<3> p = edgepoints[0]; + PointIndex pi1 = -1; + for (pi = PointIndex::BASE; + pi < mesh.GetNP()+PointIndex::BASE; pi++) + + if (Dist (mesh[pi], p) < 1e-6) + { + pi1 = pi; + break; + } + + if (pi1 == -1) pi1 = mesh.AddPoint (p, layer); + + p = edgepoints.Last(); + PointIndex pi2 = -1; + for (pi = PointIndex::BASE; + pi < mesh.GetNP()+PointIndex::BASE; pi++) + + if (Dist (mesh[pi], p) < 1e-6) + { + pi2 = pi; + break; + } + if (pi2==-1) pi2 = mesh.AddPoint (p, layer); + + /* + + j = 1; + for (i = 1; i <= ne; i++) + { + while (curvelength[j] < i * corr && j < curvelength.Size()) j++; + + lam = (i * corr - curvelength[j-1]) / + (curvelength[j] - curvelength[j-1]); + + np(0) = (1-lam) * edgepoints[j-1](0) + lam * edgepoints[j](0); + np(1) = (1-lam) * edgepoints[j-1](1) + lam * edgepoints[j](1); + np(2) = (1-lam) * edgepoints[j-1](2) + lam * edgepoints[j](2); + + + thispi = 0; + if (i == ne) + for (j = 1; j <= mesh.GetNP(); j++) + if (Dist(mesh.Point(j), np) < 1e-6) + thispi = j; + + if (!thispi) + { + ProjectToEdge (surf1, surf2, np); + thispi = mesh.AddPoint (np); + } + */ + + for (k = 1; k <= refedges.Size(); k++) + { + if (refedgesinv.Get(k)) + { + seg.p1 = pi1; + seg.p2 = pi2; + } + else + { + seg.p1 = pi2; + seg.p2 = pi1; + } + + seg.si = refedges.Get(k).si; + seg.domin = refedges.Get(k).domin; + seg.domout = refedges.Get(k).domout; + seg.tlosurf = refedges.Get(k).tlosurf; + seg.edgenr = refedges.Get(k).edgenr; + seg.surfnr1 = refedges.Get(k).surfnr1; + seg.surfnr2 = refedges.Get(k).surfnr2; + seg.seginfo = 0; + if (k == 1) seg.seginfo = (refedgesinv.Get(k)) ? 2 : 1; + mesh.AddSegment (seg); + // (*testout) << "add seg " << seg.p1 << "-" << seg.p2 << endl; + } + } + + + + + + + + void EdgeCalculation :: + CopyEdge (const ARRAY<Segment> & refedges, + const ARRAY<int> & refedgesinv, + int copyfromedge, + const Point<3> & fromstart, const Point<3> & fromend, + const Point<3> & tostart, const Point<3> & toend, + int copyedgeidentification, + int layer, + Mesh & mesh) + { + int i, j, k; + PointIndex pi; + + // copy start and end points + for (i = 1; i <= 2; i++) + { + Point<3> fromp = + (i == 1) ? fromstart : fromend; + Point<3> top = + (i == 1) ? tostart : toend; + + PointIndex frompi = -1; + PointIndex topi = -1; + for (pi = PointIndex::BASE; + pi < mesh.GetNP()+PointIndex::BASE; pi++) + { + if (Dist2 (mesh[pi], fromp) <= 1e-16) + frompi = pi; + if (Dist2 (mesh[pi], top) <= 1e-16) + topi = pi; + } + + if (topi == -1) + topi = mesh.AddPoint (top, layer); + + const Identification & csi = + (*geometry.identifications.Get(copyedgeidentification)); + + if (csi.Identifyable (mesh[frompi], mesh[topi])) + mesh.GetIdentifications().Add(frompi, topi, copyedgeidentification); + else if (csi.Identifyable (mesh[topi], mesh[frompi])) + mesh.GetIdentifications().Add(topi, frompi, copyedgeidentification); + else + { + cerr << "edgeflw.cpp: should identify, but cannot"; + exit(1); + } + /* + (*testout) << "Add Identification from CopyEdge, p1 = " + << mesh[PointIndex(frompi)] << ", p2 = " + << mesh[PointIndex(topi)] << endl; + + mesh.GetIdentifications().Add(frompi, topi, copyedgeidentification); + */ + } + + int oldns = mesh.GetNSeg(); + for (i = 1; i <= oldns; i++) + { + // real copy, since array might be reallocated !! + const Segment oldseg = mesh.LineSegment(i); + if (oldseg.edgenr != copyfromedge) + continue; + if (oldseg.seginfo == 0) + continue; + + int pi1 = oldseg.p1; + int pi2 = oldseg.p2; + + int npi1 = geometry.identifications.Get(copyedgeidentification) + -> GetIdentifiedPoint (mesh, pi1); + int npi2 = geometry.identifications.Get(copyedgeidentification) + -> GetIdentifiedPoint (mesh, pi2); + + Segment seg; + + for (k = 1; k <= refedges.Size(); k++) + { + int inv = refedgesinv.Get(k); + + // other edge is inverse + if (oldseg.seginfo == 1) + inv = !inv; + + // (*testout) << "inv, now = " << inv << endl; + + if (inv) + { + seg.p1 = npi1; + seg.p2 = npi2; + } + else + { + seg.p1 = npi2; + seg.p2 = npi1; + } + seg.si = refedges.Get(k).si; + seg.domin = refedges.Get(k).domin; + seg.domout = refedges.Get(k).domout; + seg.tlosurf = refedges.Get(k).tlosurf; + seg.edgenr = refedges.Get(k).edgenr; + seg.surfnr1 = refedges.Get(k).surfnr1; + seg.surfnr2 = refedges.Get(k).surfnr2; + seg.seginfo = 0; + if (k == 1) seg.seginfo = refedgesinv.Get(k) ? 2 : 1; + mesh.AddSegment (seg); + // (*testout) << "copy seg " << seg.p1 << "-" << seg.p2 << endl; +#ifdef DEVELOP + + (*testout) << "copy seg, face = " << seg.si << ": " + << " inv = " << inv << ", refinv = " << refedgesinv.Get(k) + << mesh.Point(seg.p1) << ", " << mesh.Point(seg.p2) << endl; +#endif + + } + + } + } + + + + + + + + void EdgeCalculation :: + FindClosedSurfaces (double h, Mesh & mesh) + { + // if there is no special point at a sphere, one has to add a segment pair + + int i, j; + int nsol; + int nsurf = geometry.GetNSurf(); + int layer; + + BitArray pointatsurface (nsurf); + Point<3> p1, p2; + Vec<3> nv, tv; + Solid * tansol; + ARRAY<int> tansurfind; + // const Solid * sol; + + nsol = geometry.GetNTopLevelObjects(); + + + pointatsurface.Clear(); + + /* + for (i = 1; i <= specpoints.Size(); i++) + { + int classrep; + + classrep = geometry.GetSurfaceClassRepresentant (specpoints[i].s1); + pointatsurface.Set (classrep); + classrep = geometry.GetSurfaceClassRepresentant (specpoints[i].s2); + pointatsurface.Set (classrep); + // pointatsurface.Set (specpoints[i].s1); + // pointatsurface.Set (specpoints[i].s2); + } + */ + for (i = 1; i <= mesh.GetNSeg(); i++) + { + const Segment & seg = mesh.LineSegment(i); + int classrep; + +#ifdef DEVELOP + (*testout) << seg.surfnr1 << ", " << seg.surfnr2 << ", si = " << seg.si << endl; +#endif + classrep = geometry.GetSurfaceClassRepresentant (seg.si); + + pointatsurface.Set (classrep); + } + + + for (i = 0; i < nsurf; i++) + { + int classrep = geometry.GetSurfaceClassRepresentant (i); + + if (!pointatsurface.Test(classrep)) + { + const Surface * s = geometry.GetSurface(i); + p1 = s -> GetSurfacePoint(); + s -> GetNormalVector (p1, nv); + + double hloc = + min2 (s->LocH (p1, 3, 1, h), mesh.GetH(p1)); + + tv = nv.GetNormal (); + tv *= (hloc / tv.Length()); + p2 = p1 + tv; + s->Project (p2); + + + Segment seg1; + seg1.si = i; + seg1.domin = -1; + seg1.domout = -1; + + Segment seg2; + seg2.si = i; + seg2.domin = -1; + seg2.domout = -1; + + seg1.surfnr1 = i; + seg2.surfnr1 = i; + seg1.surfnr2 = i; + seg2.surfnr2 = i; + + for (j = 0; j < nsol; j++) + { + if (geometry.GetTopLevelObject(j)->GetSurface()) + continue; + + const Solid * sol = geometry.GetTopLevelObject(j)->GetSolid(); + sol -> TangentialSolid (p1, tansol); + layer = geometry.GetTopLevelObject(j)->GetLayer(); + + if (tansol) + { + tansol -> GetSurfaceIndices (tansurfind); + + if (tansurfind.Size() == 1 && tansurfind.Get(1) == i) + { + if (!tansol->VectorIn(p1, nv)) + { + seg1.domin = j; + seg2.domin = j; + seg1.tlosurf = j; + seg2.tlosurf = j; + } + else + { + seg1.domout = j; + seg2.domout = j; + seg1.tlosurf = j; + seg2.tlosurf = j; + } + // seg.s2 = i; + // seg.invs1 = surfaces[i] -> Inverse(); + // seg.invs2 = ! (surfaces[i] -> Inverse()); + } + delete tansol; + } + } + + + if (seg1.domin != -1 || seg1.domout != -1) + { + mesh.AddPoint (p1, layer); + mesh.AddPoint (p2, layer); + seg1.p1 = mesh.GetNP()-1; + seg1.p2 = mesh.GetNP(); + seg2.p2 = mesh.GetNP()-1; + seg2.p1 = mesh.GetNP(); + seg1.geominfo[0].trignum = 1; + seg1.geominfo[1].trignum = 1; + seg2.geominfo[0].trignum = 1; + seg2.geominfo[1].trignum = 1; + mesh.AddSegment (seg1); + mesh.AddSegment (seg2); + + PrintMessage (5, "Add line segment to smooth surface"); + +#ifdef DEVELOP + (*testout) << "Add segment at smooth surface " << i; + if (i != classrep) (*testout) << ", classrep = " << classrep; + (*testout) << ": " + << mesh.Point (mesh.GetNP()-1) << " - " + << mesh.Point (mesh.GetNP()) << endl; +#endif + } + } + } + } + +} diff --git a/contrib/Netgen/libsrc/csg/explicitcurve2d.cpp b/contrib/Netgen/libsrc/csg/explicitcurve2d.cpp new file mode 100644 index 0000000000..b1eef537c8 --- /dev/null +++ b/contrib/Netgen/libsrc/csg/explicitcurve2d.cpp @@ -0,0 +1,160 @@ +#include <mystdlib.h> +#include <csg.hpp> + +namespace netgen +{ +ExplicitCurve2d :: ExplicitCurve2d () + { + ; + } + + +void ExplicitCurve2d :: Project (Point<2> & p) const + { + double t; + t = ProjectParam (p); + p = Eval (t); + } + +double ExplicitCurve2d :: NumericalProjectParam (const Point<2> & p, double lb, double ub) const + { + double t; + Vec<2> tan; + Vec<2> curv; + Point<2> cp; + double f, fl, fu; + int cnt; + + tan = EvalPrime (lb); + cp = Eval (lb); + fl = tan * (cp - p); + if (fl > 0) // changed by wmf, originally fl >= 0 + { + // cerr << "tan = " << tan << " cp - p = " << (cp - p) << endl; + // cerr << "ExplicitCurve2d::NumericalProject: lb wrong" << endl; + return 0; + } + + tan = EvalPrime (ub); + cp = Eval (ub); + fu = tan * (cp - p); + if (fu < 0) // changed by wmf, originally fu <= 0 + { + // cerr << "tan = " << tan << " cp - p = " << (cp - p) << endl; + // cerr << "ExplicitCurve2d::NumericalProject: ub wrong" << endl; + return 0; + } + + cnt = 0; + while (ub - lb > 1e-12 && fu - fl > 1e-12) + { + cnt++; + if (cnt > 50) + { + (*testout) << "Num Proj, cnt = " << cnt << endl; + } + + t = (lb * fu - ub * fl) / (fu - fl); + if (t > 0.9 * ub + 0.1 * lb) t = 0.9 * ub + 0.1 * lb; + if (t < 0.1 * ub + 0.9 * lb) t = 0.1 * ub + 0.9 * lb; + + tan = EvalPrime (t); + cp = Eval (t); + f = tan * (cp - p); + + if (f >= 0) + { + ub = t; + fu = f; + } + else + { + lb = t; + fl = f; + } + } + + return t; + } + + +Vec<2> ExplicitCurve2d :: Normal (double t) const +{ + Vec<2> tan = EvalPrime (t); + tan.Normalize(); + return Vec<2> (tan(1), -tan(0)); +} + + +void ExplicitCurve2d :: NormalVector (const Point<2> & p, Vec<2> & n) const + { + double t = ProjectParam (p); + n = Normal (t); + } + + +Point<2> ExplicitCurve2d :: CurvCircle (double t) const + { + Point<2> cp; + Vec<2> tan, n, curv; + double den; + + cp = Eval (t); + tan = EvalPrime (t); + n = Normal (t); + curv = EvalPrimePrime (t); + + den = n * curv; + if (fabs (den) < 1e-12) + return cp + 1e12 * n; + + return cp + (tan.Length2() / den) * n; + } + + +double ExplicitCurve2d :: MaxCurvature () const + { + double t, tmin, tmax, dt; + double curv; + Vec<2> tan; + double maxcurv; + + maxcurv = 0; + + tmin = MinParam (); + tmax = MaxParam (); + dt = (tmax - tmin) / 1000; + for (t = tmin; t <= tmax+dt; t += dt) + if (SectionUsed (t)) + { + tan = EvalPrime (t); + curv = fabs ( (Normal(t) * EvalPrimePrime(t)) / tan.Length2()); + if (curv > maxcurv) maxcurv = curv; + } + return maxcurv; + } + +double ExplicitCurve2d :: MaxCurvatureLoc (const Point<2> & p, double rad) const + { + double t, tmin, tmax, dt; + double curv; + Vec<2> tan; + double maxcurv; + + maxcurv = 0; + + tmin = MinParam (); + tmax = MaxParam (); + dt = (tmax - tmin) / 1000; + for (t = tmin; t <= tmax+dt; t += dt) + if (Dist (Eval(t), p) < rad) + { + tan = EvalPrime (t); + curv = fabs ( (Normal(t) * EvalPrimePrime(t)) / tan.Length2()); + if (curv > maxcurv) maxcurv = curv; + } + + return maxcurv; + } + +} diff --git a/contrib/Netgen/libsrc/csg/explicitcurve2d.hpp b/contrib/Netgen/libsrc/csg/explicitcurve2d.hpp new file mode 100644 index 0000000000..af405aed3c --- /dev/null +++ b/contrib/Netgen/libsrc/csg/explicitcurve2d.hpp @@ -0,0 +1,109 @@ +#ifndef FILE_EXPLICITCURVE2D +#define FILE_EXPLICITCURVE2D + +/**************************************************************************/ +/* File: explicitcurve2d.hh */ +/* Author: Joachim Schoeberl */ +/* Date: 14. Oct. 96 */ +/**************************************************************************/ + +/* + + Explicit 2D Curve repesentation + +*/ + + + +/// +class ExplicitCurve2d : public Curve2d +{ +public: + /// + ExplicitCurve2d (); + + /// + virtual void Project (Point<2> & p) const; + /// + virtual double ProjectParam (const Point<2> & p) const = 0; + /// + virtual double NumericalProjectParam (const Point<2> & p, double lb, double ub) const; + /// + virtual double MinParam () const = 0; + /// + virtual double MaxParam () const = 0; + /// + virtual Point<2> Eval (double t) const = 0; + /// + virtual Vec<2> EvalPrime (double t) const = 0; + /// + virtual Vec<2> Normal (double t) const; + /// + virtual void NormalVector (const Point<2> & p, Vec<2> & n) const; + /// + virtual Vec<2> EvalPrimePrime (double t) const = 0; + + /// + virtual double MaxCurvature () const; + /// + virtual double MaxCurvatureLoc (const Point<2> & p, double rad) const; + + /// + virtual Point<2> CurvCircle (double t) const; + /// + virtual void Print (ostream & /* str */) const { }; + + /// + virtual int SectionUsed (double /* t */) const { return 1; } + /// + virtual void Reduce (const Point<2> & /* p */, double /* rad */) { }; + /// + virtual void UnReduce () { }; +}; + + +/// +class BSplineCurve2d : public ExplicitCurve2d +{ + /// + ARRAY<Point<2> > points; + /// + ARRAY<int> intervallused; + /// + int redlevel; + +public: + /// + BSplineCurve2d (); + /// + void AddPoint (const Point<2> & apoint); + + bool Inside (const Point<2> & p, double & dist) const; + + /// + virtual double ProjectParam (const Point<2> & p) const; + /// + virtual double MinParam () const { return 0; } + /// + virtual double MaxParam () const { return points.Size(); } + /// + virtual Point<2> Eval (double t) const; + /// + virtual Vec<2> EvalPrime (double t) const; + /// + virtual Vec<2> EvalPrimePrime (double t) const; + /// + virtual void Print (ostream & str) const; + + /// + virtual int SectionUsed (double t) const; + /// + virtual void Reduce (const Point<2> & p, double rad); + /// + virtual void UnReduce (); +}; + + + + +#endif diff --git a/contrib/Netgen/libsrc/csg/extrusion.cpp b/contrib/Netgen/libsrc/csg/extrusion.cpp new file mode 100644 index 0000000000..acf9b863bc --- /dev/null +++ b/contrib/Netgen/libsrc/csg/extrusion.cpp @@ -0,0 +1,175 @@ +#include <mystdlib.h> + +#include <linalg.hpp> +#include <csg.hpp> + +namespace netgen +{ + + + + ExtrusionSurface :: ExtrusionSurface (const Point<3> & ap0, + const Vec<3> & aex, + const Vec<3> & aey, + BSplineCurve2d * acurve, + int asegnr) + : p0(ap0), ex(aex), ey(aey), curve(acurve), segnr(asegnr) + { + ; + } + + ExtrusionSurface :: ~ExtrusionSurface () + { + ; + } + + void ExtrusionSurface :: DefineTangentialPlane (const Point<3> & ap1, + const Point<3> & ap2) + { + ; + } + + void ExtrusionSurface :: ToPlane (const Point<3> & p3d, Point<2> & pplane, + double h, int & zone) const + { + ; + } + + void ExtrusionSurface :: FromPlane (const Point<2> & pplane, + Point<3> & p3d, double h) const + { + ; + } + + + void ExtrusionSurface :: Project (Point<3> & p) const + { + ; + } + + + double ExtrusionSurface :: CalcFunctionValue (const Point<3> & point) const + { + return 0; + } + + void ExtrusionSurface :: CalcGradient (const Point<3> & point, Vec<3> & grad) const + { + ; + } + + Point<3> ExtrusionSurface :: GetSurfacePoint () const + { + return Point<3> (0,0,0); + } + + double ExtrusionSurface :: HesseNorm () const + { + return 1; + } + + void ExtrusionSurface :: Print (ostream & str) const + { + ; + } + + void ExtrusionSurface :: GetTriangleApproximation (TriangleApproximation & tas, + const Box<3> & boundingbox, + double facets) const + { + Point<2> p2d; + Point<3> p; + int n = int(facets)+1; + Vec<3> ez = Cross (ex, ey); + cout << "ex = " << ex << endl; + cout << "ey = " << ey << endl; + for (double t = 0; t < 1.0001; t += 1.0 / n) + { + cout << "t = " << t << endl; + p2d = curve -> Eval (segnr+t); + p = p0 + p2d(0) * ex + p2d(1) * ey; + cout << "p2d = " << p2d << endl; + cout << "add point " << p << endl; + tas.AddPoint (p); + tas.AddPoint (p + ez); + } + + for (int i = 0; i < n; i++) + { + cout << "add trig " << endl; + tas.AddTriangle (TATriangle (0, 2*i, 2*i+2, 2*i+1)); + tas.AddTriangle (TATriangle (0, 2*i+2, 2*i+3, 2*i+1)); + } + } + + + + +Extrusion :: Extrusion (const Point<3> & ap0, + const Vec<3> & aex, + const Vec<3> & aey, + const ARRAY< Point<2> > & points) + : p0(ap0), ex(aex), ey(aey) +{ + int i; + + ex.Normalize(); + ey -= (ex*ey) * ex; + ey.Normalize(); + + for (i = 0; i < points.Size(); i++) + curve.AddPoint (points[i]); + + surfs.SetSize (points.Size()/2); + for (i = 0; i < surfs.Size(); i++) + surfs = new ExtrusionSurface (p0, ex, ey, &curve, i); +} + +Extrusion :: ~Extrusion () +{ + int i; + for (i = 0; i < surfs.Size(); i++) + delete surfs[i]; +} + + +INSOLID_TYPE Extrusion :: BoxInSolid (const BoxSphere<3> & box) const +{ + Vec<3> p0c = box.Center() - p0; + Point<2> p2d (ex*p0c, ey*p0c); + double r = box.Diam() / 2; + double dist; + bool inside = + curve.Inside (p2d, dist); + + if (inside && dist > r) return IS_INSIDE; + if (!inside && dist > r) return IS_OUTSIDE; + return DOES_INTERSECT; +} + + +INSOLID_TYPE Extrusion :: PointInSolid (const Point<3> & p, + double eps) const +{ + Vec<3> p0c = p - p0; + Point<2> p2d (ex*p0c, ey*p0c); + double dist; + bool inside = + curve.Inside (p2d, dist); + + if (dist < eps) return DOES_INTERSECT; + if (inside) return IS_INSIDE; + return IS_OUTSIDE; +} + + +INSOLID_TYPE Extrusion :: VecInSolid (const Point<3> & p, + const Vec<3> & v, + double eps) const +{ + Point<3> p2 = p + (1e-3/(v.Length()+1e-16)) * v; + return PointInSolid (p2, eps); +} + + +} diff --git a/contrib/Netgen/libsrc/csg/extrusion.hpp b/contrib/Netgen/libsrc/csg/extrusion.hpp new file mode 100644 index 0000000000..ff5a47b4e1 --- /dev/null +++ b/contrib/Netgen/libsrc/csg/extrusion.hpp @@ -0,0 +1,89 @@ +#ifndef FILE_EXTRUSION +#define FILE_EXTRUSION + +/**************************************************************************/ +/* File: extrusion.hpp */ +/* Author: Joachim Schoeberl */ +/* Date: 17. Mar. 2003 */ +/**************************************************************************/ + +/* + +extrusion of 2D curve + +*/ + + +class ExtrusionSurface : public Surface +{ +protected: + BSplineCurve2d * curve; + int segnr; + Point<3> p0; + Vec<3> ex, ey; +public: + ExtrusionSurface (const Point<3> & ap0, + const Vec<3> & aex, + const Vec<3> & aey, + BSplineCurve2d * acurve, + int asegnr); + virtual ~ExtrusionSurface (); + + virtual void DefineTangentialPlane (const Point<3> & ap1, + const Point<3> & ap2); + + virtual void ToPlane (const Point<3> & p3d, Point<2> & pplane, + double h, int & zone) const; + + virtual void FromPlane (const Point<2> & pplane, + Point<3> & p3d, double h) const; + + + virtual void Project (Point<3> & p) const; + + + virtual double CalcFunctionValue (const Point<3> & point) const; + + virtual void CalcGradient (const Point<3> & point, Vec<3> & grad) const; + + virtual Point<3> GetSurfacePoint () const; + + virtual double HesseNorm () const; + + virtual void Print (ostream & str) const; + virtual void GetTriangleApproximation (TriangleApproximation & tas, + const Box<3> & boundingbox, + double facets) const; +}; + + +class Extrusion : public Primitive +{ +protected: + Point<3> p0; + Vec<3> ex, ey; + BSplineCurve2d curve; + ARRAY<ExtrusionSurface*> surfs; + +public: + Extrusion (const Point<3> & ap0, + const Vec<3> & aex, + const Vec<3> & aey, + const ARRAY< Point<2> > & points); + virtual ~Extrusion (); + + + + virtual INSOLID_TYPE BoxInSolid (const BoxSphere<3> & box) const; + virtual INSOLID_TYPE PointInSolid (const Point<3> & p, + double eps) const; + virtual INSOLID_TYPE VecInSolid (const Point<3> & p, + const Vec<3> & v, + double eps) const; + + virtual int GetNSurfaces() const { return surfs.Size(); } + virtual Surface & GetSurface (int i) { return *surfs[i]; } + virtual const Surface & GetSurface (int i) const { return *surfs[i]; } +}; + +#endif diff --git a/contrib/Netgen/libsrc/csg/gencyl.cpp b/contrib/Netgen/libsrc/csg/gencyl.cpp new file mode 100644 index 0000000000..01c893d4a3 --- /dev/null +++ b/contrib/Netgen/libsrc/csg/gencyl.cpp @@ -0,0 +1,209 @@ +#include <linalg.hpp> +#include <csg.hpp> + + +namespace netgen +{ + +GeneralizedCylinder :: GeneralizedCylinder (ExplicitCurve2d & acrosssection, + Point<3> ap, Vec<3> ae1, Vec<3> ae2) + : crosssection(acrosssection) +{ + planep = ap; + planee1 = ae1; + planee2 = ae2; + planee3 = Cross (planee1, planee2); + (*testout) << "Vecs = " << planee1 << " " << planee2 << " " << planee3 << endl; +} + + +void GeneralizedCylinder :: Project (Point<3> & p) const +{ + Point<2> p2d; + double z; + + p2d = Point<2> (planee1 * (p - planep), planee2 * (p - planep)); + z = planee3 * (p - planep); + + crosssection.Project (p2d); + + p = planep + p2d(0) * planee1 + p2d(1) * planee2 + z * planee3; +} + +int GeneralizedCylinder ::BoxInSolid (const BoxSphere<3> & box) const +{ + Point<3> p3d; + Point<2> p2d, projp; + double t; + Vec<2> tan, n; + + p3d = box.Center(); + + p2d = Point<2> (planee1 * (p3d - planep), planee2 * (p3d - planep)); + t = crosssection.ProjectParam (p2d); + + projp = crosssection.Eval (t); + tan = crosssection.EvalPrime (t); + n(0) = tan(1); + n(1) = -tan(0); + + if (Dist (p2d, projp) < box.Diam()/2) + return 2; + + if (n * (p2d - projp) > 0) + { + return 0; + } + + return 1; +} + +double GeneralizedCylinder :: CalcFunctionValue (const Point<3> & point) const +{ + Point<2> p2d, projp; + double t; + Vec<2> tan, n; + + + p2d = Point<2> (planee1 * (point - planep), planee2 * (point - planep)); + t = crosssection.ProjectParam (p2d); + + projp = crosssection.Eval (t); + tan = crosssection.EvalPrime (t); + n(0) = tan(1); + n(1) = -tan(0); + + n /= n.Length(); + return n * (p2d - projp); +} + +void GeneralizedCylinder :: CalcGradient (const Point<3> & point, Vec<3> & grad) const +{ + Point<2> p2d, projp; + double t; + Vec<2> tan, n; + + + p2d = Point<2> (planee1 * (point - planep), planee2 * (point - planep)); + t = crosssection.ProjectParam (p2d); + + projp = crosssection.Eval (t); + tan = crosssection.EvalPrime (t); + n(0) = tan(1); + n(1) = -tan(0); + + n /= n.Length(); + grad = n(0) * planee1 + n(1) * planee2; +} + + +void GeneralizedCylinder :: CalcHesse (const Point<3> & point, Mat<3> & hesse) const +{ + Point<2> p2d, projp; + double t, dist, val; + Point<2> curvp; + Vec<2> curvpp; + Mat<2> h2d; + Mat<3,2> vmat; + int i, j, k, l; + + p2d = Point<2> (planee1 * (point - planep), planee2 * (point - planep)); + t = crosssection.ProjectParam (p2d); + + curvp = crosssection.CurvCircle (t); + curvpp = p2d-curvp; + dist = curvpp.Length(); + curvpp /= dist; + + h2d(1, 1) = (1 - curvpp(0) * curvpp(0) ) / dist; + h2d(1, 2) = h2d(2, 1) = (- curvpp(0) * curvpp(1) ) / dist; + h2d(2, 2) = (1 - curvpp(1) * curvpp(1) ) / dist; + + vmat(0,0) = planee1(0); + vmat(1,0) = planee1(1); + vmat(2,0) = planee1(2); + vmat(0,1) = planee2(0); + vmat(1,1) = planee2(1); + vmat(2,1) = planee2(2); + + for (i = 0; i < 3; i++) + for (j = 0; j < 3; j++) + { + val = 0; + for (k = 0; k < 2; k++) + for (l = 0; l < 2; l++) + val += vmat(i,k) * h2d(k,l) * vmat(j,l); + hesse(i,j) = val; + } +} + + +double GeneralizedCylinder :: HesseNorm () const +{ + return crosssection.MaxCurvature(); +} + +double GeneralizedCylinder :: MaxCurvatureLoc (const Point<3> & c, double rad) const +{ + Point<2> c2d = Point<2> (planee1 * (c - planep), planee2 * (c - planep)); + return crosssection.MaxCurvatureLoc(c2d, rad); +} + + + +Point<3> GeneralizedCylinder :: GetSurfacePoint () const +{ + Point<2> p2d; + p2d = crosssection.Eval(0); + return planep + p2d(0) * planee1 + p2d(1) * planee2; +} + +void GeneralizedCylinder :: Reduce (const BoxSphere<3> & box) +{ + Point<2> c2d = Point<2> (planee1 * (box.Center() - planep), + planee2 * (box.Center() - planep)); + crosssection.Reduce (c2d, box.Diam()/2); +} + +void GeneralizedCylinder :: UnReduce () +{ + crosssection.UnReduce (); +} + +void GeneralizedCylinder :: Print (ostream & str) const +{ + str << "Generalized Cylinder" << endl; + crosssection.Print (str); +} + +#ifdef MYGRAPH +void GeneralizedCylinder :: Plot (const class ROT3D & rot) const +{ + Point<2> p2d; + Point<3> p, oldp; + double t, tmin, tmax, dt; + + tmin = crosssection.MinParam(); + tmax = crosssection.MaxParam(); + dt = (tmax - tmin)/ 500; + + p2d = crosssection.Eval(tmin); + p = planep + p2d(0) * planee1 + p2d(1) * planee2; + + for (t = tmin; t <= tmax+dt; t += dt) + { + if (crosssection.SectionUsed (t)) + MySetColor (RED); + else + MySetColor (BLUE); + + oldp = p; + p2d = crosssection.Eval(t); + p = planep + p2d(0) * planee1 + p2d(1) * planee2; + MyLine3D (p, oldp, rot); + } + +} + +#endif +} diff --git a/contrib/Netgen/libsrc/csg/gencyl.hpp b/contrib/Netgen/libsrc/csg/gencyl.hpp new file mode 100644 index 0000000000..424c867a92 --- /dev/null +++ b/contrib/Netgen/libsrc/csg/gencyl.hpp @@ -0,0 +1,64 @@ +#ifndef FILE_GENCYL +#define FILE_GENCYL + +/**************************************************************************/ +/* File: gencyl.hh */ +/* Author: Joachim Schoeberl */ +/* Date: 14. Oct. 96 */ +/**************************************************************************/ + +/* + + Generalized Cylinder + +*/ + + +/// +class GeneralizedCylinder : public Surface +{ + /// + ExplicitCurve2d & crosssection; + /// + Point<3> planep; + /// + Vec<3> planee1, planee2, planee3; + + /// Vec<3> ex, ey, ez; + Vec2d e2x, e2y; + /// + Point<3> cp; + +public: + /// + GeneralizedCylinder (ExplicitCurve2d & acrosssection, + Point<3> ap, Vec<3> ae1, Vec<3> ae2); + + /// + virtual void Project (Point<3> & p) const; + + /// + virtual int BoxInSolid (const BoxSphere<3> & box) const; + /// 0 .. no, 1 .. yes, 2 .. maybe + + virtual double CalcFunctionValue (const Point<3> & point) const; + /// + virtual void CalcGradient (const Point<3> & point, Vec<3> & grad) const; + /// + virtual void CalcHesse (const Point<3> & point, Mat<3> & hesse) const; + /// + virtual double HesseNorm () const; + /// + virtual double MaxCurvatureLoc (const Point<3> & c, double rad) const; + /// + virtual Point<3> GetSurfacePoint () const; + /// + virtual void Print (ostream & str) const; + + /// + virtual void Reduce (const BoxSphere<3> & box); + /// + virtual void UnReduce (); +}; + +#endif diff --git a/contrib/Netgen/libsrc/csg/genmesh.cpp b/contrib/Netgen/libsrc/csg/genmesh.cpp new file mode 100644 index 0000000000..c052624a42 --- /dev/null +++ b/contrib/Netgen/libsrc/csg/genmesh.cpp @@ -0,0 +1,684 @@ +#include <mystdlib.h> + + +#include <myadt.hpp> + +#include <linalg.hpp> +#include <csg.hpp> +#include <meshing.hpp> + + +namespace netgen +{ + ARRAY<SpecialPoint> specpoints; + static ARRAY<MeshPoint> spoints; + +#define TCL_OK 0 +#define TCL_ERROR 1 + + + + static void FindPoints (CSGeometry & geom, Mesh & mesh) + { + PrintMessage (1, "Start Findpoints"); + + char * savetask = multithread.task; + multithread.task = "Find points"; + + for (int i = 0; i < geom.GetNUserPoints(); i++) + { + mesh.AddPoint (geom.GetUserPoint (i)); + mesh.AddLockedPoint (PointIndex (i+1)); + } + + SpecialPointCalculation spc; + + if (spoints.Size() == 0) + spc.CalcSpecialPoints (geom, spoints); + + PrintMessage (2, "Analyze spec points"); + spc.AnalyzeSpecialPoints (geom, spoints, specpoints); + + PrintMessage (5, "done"); + + (*testout) << specpoints.Size() << " special points:" << endl; + for (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) + { + EdgeCalculation ec (geom, specpoints); + ec.Calc (mparam.maxh, mesh); + + for (int i = 0; i < geom.singedges.Size(); i++) + geom.singedges[i]->FindPointsOnEdge (mesh); + for (int i = 0; i < geom.singpoints.Size(); i++) + geom.singpoints[i]->FindPoints (mesh); + + for (int i = 1; i <= mesh.GetNSeg(); i++) + { + int ok = 0; + for (int k = 1; k <= mesh.GetNFD(); k++) + if (mesh.GetFaceDescriptor(k).SegmentFits (mesh.LineSegment(i))) + ok = k; + + if (!ok) + ok = mesh.AddFaceDescriptor (FaceDescriptor (mesh.LineSegment(i))); + + mesh.LineSegment(i).si = ok; + } + + for (int i = 0; i < geom.identifications.Size(); i++) + geom.identifications[i]->IdentifyPoints (mesh); + for (int i = 0; i < geom.identifications.Size(); i++) + geom.identifications[i]->IdentifyFaces (mesh); + + + + // find intersecting segments + PrintMessage (3, "Check intersecting edges"); + + if (!ec.point_on_edge_problem) + for (SegmentIndex si = 0; si < mesh.GetNSeg(); si++) + for (SegmentIndex sj = 0; sj < si; sj++) + { + if (!mesh[si].seginfo || !mesh[sj].seginfo) continue; + if (mesh[mesh[si].p1].GetLayer() != mesh[mesh[sj].p2].GetLayer()) continue; + + Point<3> pi1 = mesh[mesh[si].p1]; + Point<3> pi2 = mesh[mesh[si].p2]; + Point<3> pj1 = mesh[mesh[sj].p1]; + Point<3> pj2 = mesh[mesh[sj].p2]; + 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 j = 0; j < 3; j++) + { + mat(j,0) = vi(j); + mat(j,1) = -vj(j); + rhs(j) = pj1(j)-pi1(j); + } + + mat.Solve (rhs, sol); + + 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; + cout << "Intersection at " << ip << endl; + + geom.AddUserPoint (ip); + spoints.Append (MeshPoint (ip, mesh[mesh[si].p1].GetLayer())); + mesh.AddPoint (ip); + } + } + } + + + + + + + static void MeshSurface (CSGeometry & geom, Mesh & mesh) + { + char * savetask = multithread.task; + multithread.task = "Surface meshing"; + + ARRAY<Segment> segments; + int noldp = mesh.GetNP(); + + double starttime = GetTime(); + + // find master faces from identified + ARRAY<int> masterface(mesh.GetNFD()); + for (int i = 1; i <= mesh.GetNFD(); i++) + masterface.Elem(i) = i; + + ARRAY<INDEX_2> fpairs; + bool changed; + do + { + changed = 0; + for (int i = 0; i < geom.identifications.Size(); i++) + { + geom.identifications[i]->GetIdentifiedFaces (fpairs); + + for (int j = 0; j < fpairs.Size(); j++) + { + if (masterface.Get(fpairs[j].I1()) < + masterface.Get(fpairs[j].I2())) + { + changed = 1; + masterface.Elem(fpairs[j].I2()) = + masterface.Elem(fpairs[j].I1()); + } + if (masterface.Get(fpairs[j].I2()) < + masterface.Get(fpairs[j].I1())) + { + changed = 1; + masterface.Elem(fpairs[j].I1()) = + masterface.Elem(fpairs[j].I2()); + } + } + } + } + while (changed); + + + int bccnt=0; + for (int k = 0; k < geom.GetNSurf(); k++) + bccnt = max2 (bccnt, geom.GetSurface(k)->GetBCProperty()); + + for (int k = 1; k <= mesh.GetNFD(); k++) + { + FaceDescriptor & fd = mesh.GetFaceDescriptor(k); + const Surface * surf = geom.GetSurface(fd.SurfNr()); + + if (fd.TLOSurface() && + geom.GetTopLevelObject(fd.TLOSurface()-1) -> GetBCProp() > 0) + fd.SetBCProperty (geom.GetTopLevelObject(fd.TLOSurface()-1) -> GetBCProp()); + else if (surf -> GetBCProperty() != -1) + fd.SetBCProperty (surf->GetBCProperty()); + else + { + bccnt++; + fd.SetBCProperty (bccnt); + } + + for (int l = 0; l < geom.bcmodifications.Size(); l++) + { + if (geom.GetSurfaceClassRepresentant (fd.SurfNr()) == + geom.GetSurfaceClassRepresentant (geom.bcmodifications[l].si) && + (fd.DomainIn() == geom.bcmodifications[l].tlonr+1 || + fd.DomainOut() == geom.bcmodifications[l].tlonr+1)) + { + fd.SetBCProperty (geom.bcmodifications[l].bcnr); + } + } + } + + + for (int j = 0; j < geom.singfaces.Size(); j++) + { + ARRAY<int> surfs; + geom.GetIndependentSurfaceIndices (geom.singfaces[j]->GetSolid(), + geom.BoundingBox(), surfs); + for (int k = 1; k <= mesh.GetNFD(); k++) + { + FaceDescriptor & fd = mesh.GetFaceDescriptor(k); + for (int l = 0; l < surfs.Size(); l++) + if (surfs[l] == fd.SurfNr()) + { + if (geom.singfaces[j]->GetDomainNr() == fd.DomainIn()) + fd.domin_singular = 1; + if (geom.singfaces[j]->GetDomainNr() == fd.DomainOut()) + fd.domout_singular = 1; + } + } + } + + + // assemble edge hash-table + mesh.CalcSurfacesOfNode(); + + for (int k = 1; k <= mesh.GetNFD(); k++) + { + multithread.percent = 100.0 * k / (mesh.GetNFD()+1e-10); + + if (masterface.Get(k) != k) + continue; + + FaceDescriptor & fd = mesh.GetFaceDescriptor(k); + + (*testout) << "Surface " << k << endl; + (*testout) << "Face Descriptor: " << fd << endl; + PrintMessage (1, "Surface ", k, " / ", mesh.GetNFD()); + + int oldnf = mesh.GetNSE(); + + const Surface * surf = + geom.GetSurface((mesh.GetFaceDescriptor(k).SurfNr())); + + + Meshing2Surfaces meshing(*surf, geom.BoundingBox()); + meshing.SetStartTime (starttime); + + for (PointIndex pi = PointIndex::BASE; pi < noldp+PointIndex::BASE; pi++) + meshing.AddPoint (mesh[pi], pi); + + segments.SetSize (0); + + for (SegmentIndex si = 0; si < mesh.GetNSeg(); si++) + if (mesh[si].si == k) + segments.Append (mesh[si]); + + for (int i = 1; i <= geom.identifications.Size(); i++) + geom.identifications.Get(i)-> + BuildSurfaceElements(segments, mesh, surf); + + for (int si = 0; si < segments.Size(); si++) + { + PointGeomInfo gi; + gi.trignum = k; + meshing.AddBoundaryElement (segments[si].p1 + 1 - PointIndex::BASE, + segments[si].p2 + 1 - PointIndex::BASE, + gi, gi); + } + + double maxh = mparam.maxh; + if (fd.DomainIn() != 0) + { + const Solid * s1 = + geom.GetTopLevelObject(fd.DomainIn()-1) -> GetSolid(); + if (s1->GetMaxH() < maxh) + maxh = s1->GetMaxH(); + maxh = min2(maxh, geom.GetTopLevelObject(fd.DomainIn()-1)->GetMaxH()); + } + if (fd.DomainOut() != 0) + { + const Solid * s1 = + geom.GetTopLevelObject(fd.DomainOut()-1) -> GetSolid(); + if (s1->GetMaxH() < maxh) + maxh = s1->GetMaxH(); + maxh = min2(maxh, geom.GetTopLevelObject(fd.DomainOut()-1)->GetMaxH()); + } + if (fd.TLOSurface() != 0) + { + double hi = geom.GetTopLevelObject(fd.TLOSurface()-1) -> GetMaxH(); + if (hi < maxh) maxh = hi; + } + + (*testout) << "domin = " << fd.DomainIn() << ", domout = " << fd.DomainOut() + << ", tlo-surf = " << fd.TLOSurface() + << " mpram.maxh = " << mparam.maxh << ", maxh = " << maxh << endl; + + mparam.checkoverlap = 0; + + MESHING2_RESULT res = + meshing.GenerateMesh (mesh, maxh, k); + + if (res != MESHING2_OK) + { + PrintError ("Problem in Surface mesh generation"); + throw NgException ("Problem in Surface mesh generation"); + } + + if (multithread.terminate) return; + + for (int i = oldnf+1; i <= mesh.GetNSE(); i++) + mesh.SurfaceElement(i).SetIndex (k); + + + // mesh.CalcSurfacesOfNode(); + if (segments.Size()) + { + // surface was meshed, not copied + PrintMessage (2, "Optimize Surface"); + for (int i = 1; i <= mparam.optsteps2d; i++) + { + if (multithread.terminate) return; + + { + MeshOptimize2dSurfaces meshopt(geom); + meshopt.SetFaceIndex (k); + meshopt.SetImproveEdges (0); + meshopt.SetMetricWeight (0.2); + meshopt.SetWriteStatus (0); + + meshopt.EdgeSwapping (mesh, (i > mparam.optsteps2d/2)); + } + + if (multithread.terminate) return; + { + // mesh.CalcSurfacesOfNode(); + + MeshOptimize2dSurfaces meshopt(geom); + meshopt.SetFaceIndex (k); + meshopt.SetImproveEdges (0); + meshopt.SetMetricWeight (0.2); + meshopt.SetWriteStatus (0); + + meshopt.ImproveMesh (mesh); + } + + { + MeshOptimize2dSurfaces meshopt(geom); + meshopt.SetFaceIndex (k); + meshopt.SetImproveEdges (0); + meshopt.SetMetricWeight (0.2); + meshopt.SetWriteStatus (0); + + meshopt.CombineImprove (mesh); + // mesh.CalcSurfacesOfNode(); + } + + if (multithread.terminate) return; + { + MeshOptimize2dSurfaces meshopt(geom); + meshopt.SetFaceIndex (k); + meshopt.SetImproveEdges (0); + meshopt.SetMetricWeight (0.2); + meshopt.SetWriteStatus (0); + + meshopt.ImproveMesh (mesh); + } + } + } + + + PrintMessage (3, (mesh.GetNSE() - oldnf), " elements, ", mesh.GetNP(), " points"); + +#ifdef OPENGL + extern void Render(); + Render(); +#endif + } + + mesh.Compress(); + + do + { + changed = 0; + for (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 (int i = oldnf+1; i <= mesh.GetNSE(); i++) + mesh.SurfaceElement(i).SetIndex (k); + + + if (!segments.Size()) + { + masterface.Elem(k) = k; + changed = 1; + } + + PrintMessage (3, (mesh.GetNSE() - oldnf), " elements, ", mesh.GetNP(), " points"); + } + +#ifdef OPENGL + extern void Render(); + Render(); +#endif + } + while (changed); + + mesh.SplitSeparatedFaces(); + mesh.CalcSurfacesOfNode(); + + multithread.task = savetask; + } + + + + + + + + int GenerateMesh (CSGeometry & geom, + Mesh *& mesh, + int perfstepsstart, int perfstepsend, + const char * optstr) + { + + if (mesh && mesh->GetNSE() && + !geom.GetNSolids()) + { + if (perfstepsstart < MESHCONST_MESHVOLUME) + perfstepsstart = MESHCONST_MESHVOLUME; + } + + + + if (perfstepsstart <= MESHCONST_ANALYSE) + { + delete mesh; + mesh = new Mesh(); + + mesh->SetGlobalH (mparam.maxh); + + ARRAY<double> maxhdom(geom.GetNTopLevelObjects()); + for (int i = 0; i < maxhdom.Size(); i++) + maxhdom[i] = geom.GetTopLevelObject(i)->GetMaxH(); + + mesh->SetMaxHDomain (maxhdom); + + if (mparam.uselocalh) + { + double maxsize = geom.MaxSize(); + mesh->SetLocalH (Point<3>(-maxsize, -maxsize, -maxsize), + Point<3>(maxsize, maxsize, maxsize), + mparam.grading); + + mesh -> LoadLocalMeshSize (mparam.meshsizefilename); + } + + spoints.SetSize(0); + FindPoints (geom, *mesh); + + PrintMessage (5, "find points done"); + +#ifdef LOG_STREAM + (*logout) << "Special points found" << endl + << "time = " << GetTime() << " sec" << endl + << "points: " << mesh->GetNP() << endl << endl; +#endif + } + + + if (multithread.terminate || perfstepsend <= MESHCONST_ANALYSE) + return TCL_OK; + + + if (perfstepsstart <= MESHCONST_MESHEDGES) + { + FindEdges (geom, *mesh); + if (multithread.terminate) return TCL_OK; +#ifdef LOG_STREAM + (*logout) << "Edges meshed" << endl + << "time = " << GetTime() << " sec" << endl + << "points: " << mesh->GetNP() << endl; +#endif + + + if (multithread.terminate) + return TCL_OK; + + if (mparam.uselocalh) + { + mesh->CalcLocalH(); + mesh->DeleteMesh(); + + FindPoints (geom, *mesh); + if (multithread.terminate) return TCL_OK; + FindEdges (geom, *mesh); + if (multithread.terminate) return TCL_OK; + + mesh->DeleteMesh(); + + FindPoints (geom, *mesh); + if (multithread.terminate) return TCL_OK; + FindEdges (geom, *mesh); + if (multithread.terminate) return TCL_OK; + } + } + + if (multithread.terminate || perfstepsend <= MESHCONST_MESHEDGES) + return TCL_OK; + + + if (perfstepsstart <= MESHCONST_MESHSURFACE) + { + MeshSurface (geom, *mesh); + if (multithread.terminate) return TCL_OK; + +#ifdef LOG_STREAM + (*logout) << "Surfaces meshed" << endl + << "time = " << GetTime() << " sec" << endl + << "points: " << mesh->GetNP() << endl; +#endif + + if (mparam.uselocalh && 0) + { + mesh->CalcLocalH(); + mesh->DeleteMesh(); + + FindPoints (geom, *mesh); + if (multithread.terminate) return TCL_OK; + FindEdges (geom, *mesh); + if (multithread.terminate) return TCL_OK; + + MeshSurface (geom, *mesh); + if (multithread.terminate) return TCL_OK; + } + +#ifdef LOG_STREAM + (*logout) << "Surfaces remeshed" << endl + << "time = " << GetTime() << " sec" << endl + << "points: " << mesh->GetNP() << endl; +#endif + +#ifdef STAT_STREAM + (*statout) << mesh->GetNSeg() << " & " + << mesh->GetNSE() << " & - &" + << GetTime() << " & " << endl; +#endif + + MeshQuality2d (*mesh); + mesh->CalcSurfacesOfNode(); + } + + if (multithread.terminate || perfstepsend <= MESHCONST_OPTSURFACE) + return TCL_OK; + + + if (perfstepsstart <= MESHCONST_MESHVOLUME) + { + multithread.task = "Volume meshing"; + + MESHING3_RESULT res = + MeshVolume (mparam, *mesh); + + if (res != MESHING3_OK) return TCL_ERROR; + + if (multithread.terminate) return TCL_OK; + + RemoveIllegalElements (*mesh); + if (multithread.terminate) return TCL_OK; + + MeshQuality3d (*mesh); + + for (int i = 0; i < geom.GetNTopLevelObjects(); i++) + mesh->SetMaterial (i+1, geom.GetTopLevelObject(i)->GetMaterial().c_str()); + + +#ifdef STAT_STREAM + (*statout) << GetTime() << " & "; +#endif + +#ifdef LOG_STREAM + (*logout) << "Volume meshed" << endl + << "time = " << GetTime() << " sec" << endl + << "points: " << mesh->GetNP() << endl; +#endif + } + + if (multithread.terminate || perfstepsend <= MESHCONST_MESHVOLUME) + return TCL_OK; + + + if (perfstepsstart <= MESHCONST_OPTVOLUME) + { + multithread.task = "Volume optimization"; + + OptimizeVolume (mparam, *mesh); + if (multithread.terminate) return TCL_OK; + +#ifdef STAT_STREAM + (*statout) << GetTime() << " & " + << mesh->GetNE() << " & " + << mesh->GetNP() << " " << '\\' << '\\' << " \\" << "hline" << endl; +#endif + +#ifdef LOG_STREAM + (*logout) << "Volume optimized" << endl + << "time = " << GetTime() << " sec" << endl + << "points: " << mesh->GetNP() << endl; +#endif + } + + return TCL_OK; + } +} diff --git a/contrib/Netgen/libsrc/csg/geometry.cpp b/contrib/Netgen/libsrc/csg/geometry.cpp new file mode 100644 index 0000000000..14806ee9cb --- /dev/null +++ b/contrib/Netgen/libsrc/csg/geometry.cpp @@ -0,0 +1,1792 @@ +/* A Bison parser, made from geometry.yy + by GNU bison 1.35. */ + +#define YYBISON 1 /* Identify Bison output. */ + +# define NUM 257 +# define TOK_SOLID 258 +# define TOK_RECO 259 +# define TOK_TLO 260 +# define TOK_BOUNDINGBOX 261 +# define IDENT 262 +# define IDENTSOLID 263 +# define TOK_SPHERE 264 +# define TOK_CYLINDER 265 +# define TOK_CONE 266 +# define TOK_PLAIN 267 +# define TOK_TUBE 268 +# define TOK_GENCYL 269 +# define TOK_ORTHOBRICK 270 +# define TOK_POLYHEDRON 271 +# define TOK_REVOLUTION 272 +# define TOK_OR 273 +# define TOK_AND 274 +# define TOK_NOT 275 +# define TOK_TRANSLATE 276 +# define TOK_MULTITRANSLATE 277 +# define TOK_ROTATE 278 +# define TOK_MULTIROTATE 279 +# define TOK_SINGULAR 280 +# define TOK_EDGE 281 +# define TOK_POINT 282 +# define TOK_IDENTIFY 283 +# define TOK_CLOSESURFACES 284 +# define TOK_CLOSEEDGES 285 +# define TOK_PERIODIC 286 +# define TOK_BOUNDARYCONDITION 287 + +#line 1 "geometry.yy" + +//define YYDEBUG 1 + +extern int yylex (); + +#include <mystdlib.h> + +#include <myadt.hpp> + +#include <linalg.hpp> +#include <csg.hpp> + +namespace netgen +{ +netgen::CSGeometry * parsegeom; +} + +using namespace netgen; + +// extern ARRAY<Surface*> surfaces; +// extern SYMBOLTABLE<Solid*> solids; + + +int yyerror (char * s); +splinetube * tube; +spline3d * middlecurve; +Point<3> splinep1; +BSplineCurve2d *bspline; +Flags parseflags; +extern int linenum; +ARRAY<double> doublearray; +ARRAY<char*> stringarray; + +Polyhedra * polyhedron; +// Revolution * revolution; + +#line 38 "geometry.yy" +#ifndef YYSTYPE +typedef union { +double val; +char * chptr; +Solid * solidtype; +} yystype; +# define YYSTYPE yystype +# define YYSTYPE_IS_TRIVIAL 1 +#endif +#ifndef YYDEBUG +# define YYDEBUG 0 +#endif + + + +#define YYFINAL 260 +#define YYFLAG -32768 +#define YYNTBASE 42 + +/* YYTRANSLATE(YYLEX) -- Bison token number corresponding to YYLEX. */ +#define YYTRANSLATE(x) ((unsigned)(x) <= 287 ? yytranslate[x] : 67) + +/* YYTRANSLATE[YYLEX] -- Bison token number corresponding to YYLEX. */ +static const char yytranslate[] = +{ + 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 36, 37, 2, 2, 38, 39, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 34, + 2, 35, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 40, 2, 41, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 1, 3, 4, 5, + 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, + 26, 27, 28, 29, 30, 31, 32, 33 +}; + +#if YYDEBUG +static const short yyprhs[] = +{ + 0, 0, 1, 6, 7, 11, 12, 19, 21, 23, + 27, 31, 34, 38, 49, 66, 85, 100, 115, 116, + 125, 136, 149, 166, 185, 189, 191, 195, 197, 203, + 209, 217, 221, 223, 227, 229, 233, 245, 246, 252, + 253, 254, 261, 262, 266, 272, 279, 285, 291, 296, + 300, 305, 320, 329, 334, 335, 338, 339, 342, 345, + 350, 355, 360, 365, 366, 371, 373, 377, 378, 383, + 385, 389, 391 +}; +static const short yyrhs[] = +{ + -1, 43, 5, 44, 54, 0, 0, 44, 45, 34, + 0, 0, 4, 8, 35, 47, 46, 56, 0, 48, + 0, 9, 0, 47, 19, 47, 0, 47, 20, 47, + 0, 21, 47, 0, 36, 47, 37, 0, 10, 36, + 3, 38, 3, 38, 3, 34, 3, 37, 0, 11, + 36, 3, 38, 3, 38, 3, 34, 3, 38, 3, + 38, 3, 34, 3, 37, 0, 12, 36, 3, 38, + 3, 38, 3, 34, 3, 34, 3, 38, 3, 38, + 3, 34, 3, 37, 0, 13, 36, 3, 38, 3, + 38, 3, 34, 3, 38, 3, 38, 3, 37, 0, + 16, 36, 3, 38, 3, 38, 3, 34, 3, 38, + 3, 38, 3, 37, 0, 0, 17, 36, 49, 50, + 34, 34, 51, 37, 0, 22, 36, 3, 38, 3, + 38, 3, 34, 47, 37, 0, 23, 36, 3, 38, + 3, 38, 3, 34, 3, 34, 47, 37, 0, 24, + 36, 3, 38, 3, 38, 3, 34, 3, 38, 3, + 38, 3, 34, 47, 37, 0, 25, 36, 3, 38, + 3, 38, 3, 34, 3, 38, 3, 38, 3, 34, + 3, 34, 47, 37, 0, 50, 34, 52, 0, 52, + 0, 51, 34, 53, 0, 53, 0, 3, 38, 3, + 38, 3, 0, 3, 38, 3, 38, 3, 0, 3, + 38, 3, 38, 3, 38, 3, 0, 67, 34, 68, + 0, 68, 0, 3, 38, 3, 0, 70, 0, 70, + 38, 69, 0, 3, 38, 3, 38, 3, 38, 3, + 38, 3, 38, 3, 0, 0, 3, 38, 3, 72, + 73, 0, 0, 0, 38, 3, 38, 3, 74, 73, + 0, 0, 54, 55, 34, 0, 26, 27, 3, 9, + 9, 0, 26, 28, 3, 9, 9, 9, 0, 29, + 30, 9, 9, 56, 0, 29, 31, 9, 9, 9, + 0, 29, 32, 9, 9, 0, 6, 9, 56, 0, + 6, 9, 9, 56, 0, 7, 36, 3, 38, 3, + 38, 3, 34, 3, 38, 3, 38, 3, 37, 0, + 28, 36, 3, 38, 3, 38, 3, 37, 0, 33, + 9, 9, 3, 0, 0, 57, 58, 0, 0, 59, + 58, 0, 39, 66, 0, 39, 66, 35, 66, 0, + 39, 66, 35, 3, 0, 39, 66, 35, 60, 0, + 39, 66, 35, 63, 0, 0, 40, 61, 62, 41, + 0, 3, 0, 62, 38, 3, 0, 0, 40, 64, + 65, 41, 0, 66, 0, 65, 38, 66, 0, 8, + 0, 9, 0 +}; + +#endif + +#if YYDEBUG +/* YYRLINE[YYN] -- source line where rule number YYN was defined. */ +static const short yyrline[] = +{ + 0, 61, 61, 79, 81, 84, 84, 94, 96, 97, + 98, 99, 100, 103, 112, 123, 135, 144, 158, 158, + 197, 206, 222, 231, 285, 287, 289, 291, 293, 300, + 306, 315, 317, 319, 331, 333, 335, 345, 345, 354, + 356, 356, 372, 374, 377, 385, 394, 409, 425, 439, + 453, 470, 477, 482, 511, 511, 516, 518, 521, 524, + 526, 528, 530, 535, 535, 540, 542, 545, 545, 556, + 563, 574, 576 +}; +#endif + + +#if (YYDEBUG) || defined YYERROR_VERBOSE + +/* YYTNAME[TOKEN_NUM] -- String name of the token TOKEN_NUM. */ +static const char *const yytname[] = +{ + "$", "error", "$undefined.", "NUM", "TOK_SOLID", "TOK_RECO", "TOK_TLO", + "TOK_BOUNDINGBOX", "IDENT", "IDENTSOLID", "TOK_SPHERE", "TOK_CYLINDER", + "TOK_CONE", "TOK_PLAIN", "TOK_TUBE", "TOK_GENCYL", "TOK_ORTHOBRICK", + "TOK_POLYHEDRON", "TOK_REVOLUTION", "TOK_OR", "TOK_AND", "TOK_NOT", + "TOK_TRANSLATE", "TOK_MULTITRANSLATE", "TOK_ROTATE", "TOK_MULTIROTATE", + "TOK_SINGULAR", "TOK_EDGE", "TOK_POINT", "TOK_IDENTIFY", + "TOK_CLOSESURFACES", "TOK_CLOSEEDGES", "TOK_PERIODIC", + "TOK_BOUNDARYCONDITION", "';'", "'='", "'('", "')'", "','", "'-'", + "'['", "']'", "input", "@1", "recsoliddef", "soliddef", "@2", "solid", + "solidprimitive", "@3", "polyhedronpoints", "polyhedronfaces", + "polyhedronpoint", "polyhedronface", "recadddef", "adddef", "flaglist", + "@6", "recflaglist", "flag", "numlistbrack", "@7", "numlist", + "stringlistbrack", "@8", "stringlist", "anyident", 0 +}; +#endif + +/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ +static const short yyr1[] = +{ + 0, 43, 42, 44, 44, 46, 45, 47, 47, 47, + 47, 47, 47, 48, 48, 48, 48, 48, 49, 48, + 48, 48, 48, 48, 50, 50, 51, 51, 52, 53, + 53, 67, 67, 68, 69, 69, 70, 72, 71, 73, + 74, 73, 54, 54, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 57, 56, 58, 58, 59, 59, + 59, 59, 59, 61, 60, 62, 62, 64, 63, 65, + 65, 66, 66 +}; + +/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */ +static const short yyr2[] = +{ + 0, 0, 4, 0, 3, 0, 6, 1, 1, 3, + 3, 2, 3, 10, 16, 18, 14, 14, 0, 8, + 10, 12, 16, 18, 3, 1, 3, 1, 5, 5, + 7, 3, 1, 3, 1, 3, 11, 0, 5, 0, + 0, 6, 0, 3, 5, 6, 5, 5, 4, 3, + 4, 14, 8, 4, 0, 2, 0, 2, 2, 4, + 4, 4, 4, 0, 4, 1, 3, 0, 4, 1, + 3, 1, 1 +}; + +/* YYDEFACT[S] -- default rule to reduce with in state S when YYTABLE + doesn't specify something else to do. Zero means the default is an + error. */ +static const short yydefact[] = +{ + 1, 0, 3, 42, 0, 0, 2, 0, 4, 0, + 0, 0, 0, 0, 0, 0, 0, 54, 0, 0, + 0, 0, 0, 0, 0, 0, 43, 8, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 5, 7, 54, 49, 56, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 18, 11, + 0, 0, 0, 0, 0, 0, 0, 54, 50, 0, + 55, 56, 0, 0, 0, 0, 54, 0, 48, 53, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 12, 9, 10, 6, 71, 72, 58, 57, 0, 44, + 0, 0, 46, 47, 0, 0, 0, 0, 0, 0, + 0, 25, 0, 0, 0, 0, 0, 0, 45, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 60, 67, 61, 62, 59, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 24, 0, 0, 0, 0, + 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, + 0, 0, 27, 0, 0, 0, 0, 65, 0, 0, + 69, 0, 0, 0, 0, 0, 0, 28, 0, 0, + 19, 0, 0, 0, 0, 0, 64, 0, 68, 0, + 0, 0, 0, 0, 0, 0, 26, 0, 0, 0, + 0, 66, 70, 0, 13, 0, 0, 0, 0, 0, + 20, 0, 0, 0, 0, 0, 0, 0, 0, 29, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, + 0, 0, 51, 0, 0, 0, 0, 30, 0, 0, + 0, 0, 16, 17, 0, 0, 0, 0, 0, 0, + 14, 0, 22, 0, 0, 0, 15, 23, 0, 0, + 0 +}; + +static const short yydefgoto[] = +{ + 258, 1, 3, 5, 67, 40, 41, 85, 110, 161, + 111, 162, 6, 15, 43, 44, 70, 71, 133, 150, + 168, 134, 151, 169, 96 +}; + +static const short yypact[] = +{ + -32768, 5,-32768, 18, 21, 7, 14, 11,-32768, 52, + 35, 36, 39, 28, 56, 42, 2, 58, 66, 74, + 75, 76, 71, 72, 73, 77,-32768,-32768, 48, 49, + 51, 53, 55, 57, 2, 59, 60, 61, 62, 2, + 54,-32768,-32768,-32768, 44, 50, 81, 83, 63, 85, + 90, 91, 99, 100, 101, 102, 103, 104,-32768,-32768, + 105, 106, 107, 108, -3, 2, 2,-32768,-32768, 47, + -32768, 44, 109, 110, 111, 112,-32768, 113,-32768,-32768, + 78, 79, 80, 86, 87, 118, 88, 89, 92, 93, + -32768,-32768,-32768,-32768,-32768,-32768, 94,-32768, 95,-32768, + 114, 96,-32768,-32768, 125, 129, 132, 133, 134, 115, + 116,-32768, 135, 136, 137, 138, -1, 139,-32768, 140, + 117, 119, 120, 121, 122, 141, 1, 123, 124, 126, + 127,-32768, 142,-32768,-32768,-32768, 144, 130, 143, 145, + 146, 148, 149, 128, 151,-32768, 153, 160, 165, 166, + 167, 47, 168,-32768, 147, 150, 152, 154, 155, 169, + 156, -28,-32768, 157, 158, 159, 161,-32768, -8, 16, + -32768, 162, 170, 171, 172, 173, 176,-32768, 177, 151, + -32768, 2, 179, 180, 182, 184,-32768, 47,-32768, 187, + 164, 174, 163, 175, 178, 183,-32768, 25, 181, 185, + 186,-32768,-32768, 188,-32768, 193, 195, 196, 199, 200, + -32768, 2, 201, 202, 203, 189, 190, 191, 192, 194, + 29, 197, 198, 204, 205, 206, 208, 211, 214,-32768, + 215, 217,-32768, 209, 207, 210, 212,-32768, 216, 218, + 219, 222,-32768,-32768, 2, 228, 220, 221, 31, 224, + -32768, 230,-32768, 2, 223, 33,-32768,-32768, 234, 237, + -32768 +}; + +static const short yypgoto[] = +{ + -32768,-32768,-32768,-32768,-32768, -34,-32768,-32768,-32768,-32768, + -13, -65,-32768,-32768, -39,-32768, 213,-32768,-32768,-32768, + -32768,-32768,-32768,-32768, -115 +}; + + +#define YYLAST 284 + + +static const short yytable[] = +{ + 59, 135, 131, 68, 109, 64, 179, 94, 95, 180, + 2, 27, 28, 29, 30, 31, 65, 66, 32, 33, + 9, 10, 4, 34, 35, 36, 37, 38, 93, 7, + 185, 91, 92, 186, 90, 144, 170, 102, 39, 132, + 11, 8, 12, 13, 65, 66, 16, 14, 65, 66, + 65, 66, 65, 66, 187, 94, 95, 188, 22, 23, + 24, 17, 210, 19, 20, 25, 229, 42, 252, 45, + 257, 18, 202, 65, 66, 21, 26, 46, 47, 48, + 49, 50, 51, 69, 53, 54, 52, 55, 72, 56, + 73, 57, 74, 58, 76, 60, 61, 62, 63, 77, + 78, 75, 79, 80, 81, 82, 83, 84, 86, 87, + 88, 89, 98, 145, 196, 101, 104, 105, 106, 99, + 100, 109, 103, 118, 107, 108, 112, 113, 120, 116, + 114, 115, 121, 117, 119, 122, 123, 124, 127, 128, + 129, 130, 136, 137, 143, -63, 154, 197, 155, 156, + 126, 157, 158, 125, 160, 138, 163, 139, 140, 141, + 142, 146, 147, 164, 148, 149, 159, 153, 165, 166, + 167, 171, 177, 190, 191, 192, 193, 220, 152, 194, + 195, 172, 198, 199, 173, 200, 174, 201, 175, 176, + 203, 181, 182, 183, 178, 184, 215, 206, 216, 217, + 189, 204, 218, 219, 221, 222, 223, 0, 233, 234, + 248, 235, 205, 207, 236, 211, 208, 237, 238, 255, + 239, 209, 246, 212, 213, 247, 214, 224, 225, 226, + 227, 249, 228, 254, 259, 230, 231, 260, 0, 0, + 0, 232, 0, 240, 0, 241, 0, 242, 0, 243, + 244, 0, 245, 0, 0, 251, 0, 250, 253, 0, + 256, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 97 +}; + +static const short yycheck[] = +{ + 34, 116, 3, 42, 3, 39, 34, 8, 9, 37, + 5, 9, 10, 11, 12, 13, 19, 20, 16, 17, + 6, 7, 4, 21, 22, 23, 24, 25, 67, 8, + 38, 65, 66, 41, 37, 34, 151, 76, 36, 40, + 26, 34, 28, 29, 19, 20, 35, 33, 19, 20, + 19, 20, 19, 20, 38, 8, 9, 41, 30, 31, + 32, 9, 37, 27, 28, 9, 37, 9, 37, 3, + 37, 36, 187, 19, 20, 36, 34, 3, 3, 3, + 9, 9, 9, 39, 36, 36, 9, 36, 38, 36, + 9, 36, 9, 36, 9, 36, 36, 36, 36, 9, + 9, 38, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 126, 179, 3, 38, 38, 38, 9, + 9, 3, 9, 9, 38, 38, 38, 38, 3, 35, + 38, 38, 3, 38, 38, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 181, 3, 3, + 34, 3, 3, 38, 3, 38, 3, 38, 38, 38, + 38, 38, 38, 3, 38, 38, 38, 37, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 211, 34, 3, + 3, 34, 3, 3, 34, 3, 34, 3, 34, 34, + 3, 34, 34, 34, 38, 34, 3, 34, 3, 3, + 38, 37, 3, 3, 3, 3, 3, -1, 3, 3, + 244, 3, 38, 38, 3, 34, 38, 3, 3, 253, + 3, 38, 3, 38, 38, 3, 38, 38, 38, 38, + 38, 3, 38, 3, 0, 38, 38, 0, -1, -1, + -1, 37, -1, 34, -1, 38, -1, 37, -1, 37, + 34, -1, 34, -1, -1, 34, -1, 37, 34, -1, + 37, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 71 +}; +/* -*-C-*- Note some compilers choke on comments on `#line' lines. */ +#line 3 "/usr/share/bison/bison.simple" + +/* Skeleton output parser for bison, + + Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002 Free Software + Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +/* As a special exception, when this file is copied by Bison into a + Bison output file, you may use that output file without restriction. + This special exception was added by the Free Software Foundation + in version 1.24 of Bison. */ + +/* This is the parser code that is written into each bison parser when + the %semantic_parser declaration is not specified in the grammar. + It was written by Richard Stallman by simplifying the hairy parser + used when %semantic_parser is specified. */ + +/* All symbols defined below should begin with yy or YY, to avoid + infringing on user name space. This should be done even for local + variables, as they might otherwise be expanded by user macros. + There are some unavoidable exceptions within include files to + define necessary library symbols; they are noted "INFRINGES ON + USER NAME SPACE" below. */ + +#ifndef YYPARSE_RETURN_TYPE +#define YYPARSE_RETURN_TYPE int +#endif + +#if ! defined (yyoverflow) || defined (YYERROR_VERBOSE) + +/* The parser invokes alloca or malloc; define the necessary symbols. */ + +# if YYSTACK_USE_ALLOCA +# define YYSTACK_ALLOC alloca +# else +# ifndef YYSTACK_USE_ALLOCA +# if defined (alloca) || defined (_ALLOCA_H) +# define YYSTACK_ALLOC alloca +# else +# ifdef __GNUC__ +# define YYSTACK_ALLOC __builtin_alloca +# endif +# endif +# endif +# endif + +# ifdef YYSTACK_ALLOC + /* Pacify GCC's `empty if-body' warning. */ +# define YYSTACK_FREE(Ptr) do { /* empty */; } while (0) +# else +# if defined (__STDC__) || defined (__cplusplus) +# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */ +# define YYSIZE_T size_t +# endif +# define YYSTACK_ALLOC malloc +# define YYSTACK_FREE free +# endif +#endif /* ! defined (yyoverflow) || defined (YYERROR_VERBOSE) */ + + +#if (! defined (yyoverflow) \ + && (! defined (__cplusplus) \ + || ((YYLTYPE_IS_TRIVIAL || ! YYLSP_NEEDED) && YYSTYPE_IS_TRIVIAL))) + +/* A type that is properly aligned for any stack member. */ +union yyalloc +{ + short yyss; + YYSTYPE yyvs; +# if YYLSP_NEEDED + YYLTYPE yyls; +# endif +}; + +/* The size of the maximum gap between one aligned stack and the next. */ +# define YYSTACK_GAP_MAX (sizeof (union yyalloc) - 1) + +/* The size of an array large to enough to hold all stacks, each with + N elements. */ +# if YYLSP_NEEDED +# define YYSTACK_BYTES(N) \ + ((N) * (sizeof (short) + sizeof (YYSTYPE) + sizeof (YYLTYPE)) \ + + 2 * YYSTACK_GAP_MAX) +# else +# define YYSTACK_BYTES(N) \ + ((N) * (sizeof (short) + sizeof (YYSTYPE)) \ + + YYSTACK_GAP_MAX) +# endif + +/* Copy COUNT objects from FROM to TO. The source and destination do + not overlap. */ +# ifndef YYCOPY +# if 1 < __GNUC__ +# define YYCOPY(To, From, Count) \ + __builtin_memcpy (To, From, (Count) * sizeof (*(From))) +# else +# define YYCOPY(To, From, Count) \ + do \ + { \ + register YYSIZE_T yyi; \ + for (yyi = 0; yyi < (Count); yyi++) \ + (To)[yyi] = (From)[yyi]; \ + } \ + while (0) +# endif +# endif + +/* Relocate STACK from its old location to the new one. The + local variables YYSIZE and YYSTACKSIZE give the old and new number of + elements in the stack, and YYPTR gives the new location of the + stack. Advance YYPTR to a properly aligned location for the next + stack. */ +# define YYSTACK_RELOCATE(Stack) \ + do \ + { \ + YYSIZE_T yynewbytes; \ + YYCOPY (&yyptr->Stack, Stack, yysize); \ + Stack = &yyptr->Stack; \ + yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAX; \ + yyptr += yynewbytes / sizeof (*yyptr); \ + } \ + while (0) + +#endif + + +#if ! defined (YYSIZE_T) && defined (__SIZE_TYPE__) +# define YYSIZE_T __SIZE_TYPE__ +#endif +#if ! defined (YYSIZE_T) && defined (size_t) +# define YYSIZE_T size_t +#endif +#if ! defined (YYSIZE_T) +# if defined (__STDC__) || defined (__cplusplus) +# include <stddef.h> /* INFRINGES ON USER NAME SPACE */ +# define YYSIZE_T size_t +# endif +#endif +#if ! defined (YYSIZE_T) +# define YYSIZE_T unsigned int +#endif + +#define yyerrok (yyerrstatus = 0) +#define yyclearin (yychar = YYEMPTY) +#define YYEMPTY -2 +#define YYEOF 0 +#define YYACCEPT goto yyacceptlab +#define YYABORT goto yyabortlab +#define YYERROR goto yyerrlab1 +/* Like YYERROR except do call yyerror. This remains here temporarily + to ease the transition to the new meaning of YYERROR, for GCC. + Once GCC version 2 has supplanted version 1, this can go. */ +#define YYFAIL goto yyerrlab +#define YYRECOVERING() (!!yyerrstatus) +#define YYBACKUP(Token, Value) \ +do \ + if (yychar == YYEMPTY && yylen == 1) \ + { \ + yychar = (Token); \ + yylval = (Value); \ + yychar1 = YYTRANSLATE (yychar); \ + YYPOPSTACK; \ + goto yybackup; \ + } \ + else \ + { \ + yyerror ("syntax error: cannot back up"); \ + YYERROR; \ + } \ +while (0) + +#define YYTERROR 1 +#define YYERRCODE 256 + + +/* YYLLOC_DEFAULT -- Compute the default location (before the actions + are run). + + When YYLLOC_DEFAULT is run, CURRENT is set the location of the + first token. By default, to implement support for ranges, extend + its range to the last symbol. */ + +#ifndef YYLLOC_DEFAULT +# define YYLLOC_DEFAULT(Current, Rhs, N) \ + Current.last_line = Rhs[N].last_line; \ + Current.last_column = Rhs[N].last_column; +#endif + + +/* YYLEX -- calling `yylex' with the right arguments. */ + +#if YYPURE +# if YYLSP_NEEDED +# ifdef YYLEX_PARAM +# define YYLEX yylex (&yylval, &yylloc, YYLEX_PARAM) +# else +# define YYLEX yylex (&yylval, &yylloc) +# endif +# else /* !YYLSP_NEEDED */ +# ifdef YYLEX_PARAM +# define YYLEX yylex (&yylval, YYLEX_PARAM) +# else +# define YYLEX yylex (&yylval) +# endif +# endif /* !YYLSP_NEEDED */ +#else /* !YYPURE */ +# define YYLEX yylex () +#endif /* !YYPURE */ + + +/* Enable debugging if requested. */ +#if YYDEBUG + +# ifndef YYFPRINTF +# include <stdio.h> /* INFRINGES ON USER NAME SPACE */ +# define YYFPRINTF fprintf +# endif + +# define YYDPRINTF(Args) \ +do { \ + if (yydebug) \ + YYFPRINTF Args; \ +} while (0) +/* Nonzero means print parse trace. It is left uninitialized so that + multiple parsers can coexist. */ +int yydebug; +#else /* !YYDEBUG */ +# define YYDPRINTF(Args) +#endif /* !YYDEBUG */ + +/* YYINITDEPTH -- initial size of the parser's stacks. */ +#ifndef YYINITDEPTH +# define YYINITDEPTH 200 +#endif + +/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only + if the built-in stack extension method is used). + + Do not make this value too large; the results are undefined if + SIZE_MAX < YYSTACK_BYTES (YYMAXDEPTH) + evaluated with infinite-precision integer arithmetic. */ + +#if YYMAXDEPTH == 0 +# undef YYMAXDEPTH +#endif + +#ifndef YYMAXDEPTH +# define YYMAXDEPTH 10000 +#endif + +#ifdef YYERROR_VERBOSE + +# ifndef yystrlen +# if defined (__GLIBC__) && defined (_STRING_H) +# define yystrlen strlen +# else +/* Return the length of YYSTR. */ +static YYSIZE_T +# if defined (__STDC__) || defined (__cplusplus) +yystrlen (const char *yystr) +# else +yystrlen (yystr) + const char *yystr; +# endif +{ + register const char *yys = yystr; + + while (*yys++ != '\0') + continue; + + return yys - yystr - 1; +} +# endif +# endif + +# ifndef yystpcpy +# if defined (__GLIBC__) && defined (_STRING_H) && defined (_GNU_SOURCE) +# define yystpcpy stpcpy +# else +/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in + YYDEST. */ +static char * +# if defined (__STDC__) || defined (__cplusplus) +yystpcpy (char *yydest, const char *yysrc) +# else +yystpcpy (yydest, yysrc) + char *yydest; + const char *yysrc; +# endif +{ + register char *yyd = yydest; + register const char *yys = yysrc; + + while ((*yyd++ = *yys++) != '\0') + continue; + + return yyd - 1; +} +# endif +# endif +#endif + +#line 319 "/usr/share/bison/bison.simple" + + +/* The user can define YYPARSE_PARAM as the name of an argument to be passed + into yyparse. The argument should have type void *. + It should actually point to an object. + Grammar actions can access the variable by casting it + to the proper pointer type. */ + +#ifdef YYPARSE_PARAM +# if defined (__STDC__) || defined (__cplusplus) +# define YYPARSE_PARAM_ARG void *YYPARSE_PARAM +# define YYPARSE_PARAM_DECL +# else +# define YYPARSE_PARAM_ARG YYPARSE_PARAM +# define YYPARSE_PARAM_DECL void *YYPARSE_PARAM; +# endif +#else /* !YYPARSE_PARAM */ +# define YYPARSE_PARAM_ARG +# define YYPARSE_PARAM_DECL +#endif /* !YYPARSE_PARAM */ + +/* Prevent warning if -Wstrict-prototypes. */ +#ifdef __GNUC__ +# ifdef YYPARSE_PARAM +YYPARSE_RETURN_TYPE yyparse (void *); +# else +YYPARSE_RETURN_TYPE yyparse (void); +# endif +#endif + +/* YY_DECL_VARIABLES -- depending whether we use a pure parser, + variables are global, or local to YYPARSE. */ + +#define YY_DECL_NON_LSP_VARIABLES \ +/* The lookahead symbol. */ \ +int yychar; \ + \ +/* The semantic value of the lookahead symbol. */ \ +YYSTYPE yylval; \ + \ +/* Number of parse errors so far. */ \ +int yynerrs; + +#if YYLSP_NEEDED +# define YY_DECL_VARIABLES \ +YY_DECL_NON_LSP_VARIABLES \ + \ +/* Location data for the lookahead symbol. */ \ +YYLTYPE yylloc; +#else +# define YY_DECL_VARIABLES \ +YY_DECL_NON_LSP_VARIABLES +#endif + + +/* If nonreentrant, generate the variables here. */ + +#if !YYPURE +YY_DECL_VARIABLES +#endif /* !YYPURE */ + +YYPARSE_RETURN_TYPE +yyparse (YYPARSE_PARAM_ARG) + YYPARSE_PARAM_DECL +{ + /* If reentrant, generate the variables here. */ +#if YYPURE + YY_DECL_VARIABLES +#endif /* !YYPURE */ + + register int yystate; + register int yyn; + int yyresult; + /* Number of tokens to shift before error messages enabled. */ + int yyerrstatus; + /* Lookahead token as an internal (translated) token number. */ + int yychar1 = 0; + + /* Three stacks and their tools: + `yyss': related to states, + `yyvs': related to semantic values, + `yyls': related to locations. + + Refer to the stacks thru separate pointers, to allow yyoverflow + to reallocate them elsewhere. */ + + /* The state stack. */ + short yyssa[YYINITDEPTH]; + short *yyss = yyssa; + register short *yyssp; + + /* The semantic value stack. */ + YYSTYPE yyvsa[YYINITDEPTH]; + YYSTYPE *yyvs = yyvsa; + register YYSTYPE *yyvsp; + +#if YYLSP_NEEDED + /* The location stack. */ + YYLTYPE yylsa[YYINITDEPTH]; + YYLTYPE *yyls = yylsa; + YYLTYPE *yylsp; +#endif + +#if YYLSP_NEEDED +# define YYPOPSTACK (yyvsp--, yyssp--, yylsp--) +#else +# define YYPOPSTACK (yyvsp--, yyssp--) +#endif + + YYSIZE_T yystacksize = YYINITDEPTH; + + + /* The variables used to return semantic value and location from the + action routines. */ + YYSTYPE yyval; +#if YYLSP_NEEDED + YYLTYPE yyloc; +#endif + + /* When reducing, the number of symbols on the RHS of the reduced + rule. */ + int yylen; + + YYDPRINTF ((stderr, "Starting parse\n")); + + yystate = 0; + yyerrstatus = 0; + yynerrs = 0; + yychar = YYEMPTY; /* Cause a token to be read. */ + + /* Initialize stack pointers. + Waste one element of value and location stack + so that they stay on the same level as the state stack. + The wasted elements are never initialized. */ + + yyssp = yyss; + yyvsp = yyvs; +#if YYLSP_NEEDED + yylsp = yyls; +#endif + goto yysetstate; + +/*------------------------------------------------------------. +| yynewstate -- Push a new state, which is found in yystate. | +`------------------------------------------------------------*/ + yynewstate: + /* In all cases, when you get here, the value and location stacks + have just been pushed. so pushing a state here evens the stacks. + */ + yyssp++; + + yysetstate: + *yyssp = yystate; + + if (yyssp >= yyss + yystacksize - 1) + { + /* Get the current used size of the three stacks, in elements. */ + YYSIZE_T yysize = yyssp - yyss + 1; + +#ifdef yyoverflow + { + /* Give user a chance to reallocate the stack. Use copies of + these so that the &'s don't force the real ones into + memory. */ + YYSTYPE *yyvs1 = yyvs; + short *yyss1 = yyss; + + /* Each stack pointer address is followed by the size of the + data in use in that stack, in bytes. */ +# if YYLSP_NEEDED + YYLTYPE *yyls1 = yyls; + /* This used to be a conditional around just the two extra args, + but that might be undefined if yyoverflow is a macro. */ + yyoverflow ("parser stack overflow", + &yyss1, yysize * sizeof (*yyssp), + &yyvs1, yysize * sizeof (*yyvsp), + &yyls1, yysize * sizeof (*yylsp), + &yystacksize); + yyls = yyls1; +# else + yyoverflow ("parser stack overflow", + &yyss1, yysize * sizeof (*yyssp), + &yyvs1, yysize * sizeof (*yyvsp), + &yystacksize); +# endif + yyss = yyss1; + yyvs = yyvs1; + } +#else /* no yyoverflow */ +# ifndef YYSTACK_RELOCATE + goto yyoverflowlab; +# else + /* Extend the stack our own way. */ + if (yystacksize >= YYMAXDEPTH) + goto yyoverflowlab; + yystacksize *= 2; + if (yystacksize > YYMAXDEPTH) + yystacksize = YYMAXDEPTH; + + { + short *yyss1 = yyss; + union yyalloc *yyptr = + (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize)); + if (! yyptr) + goto yyoverflowlab; + YYSTACK_RELOCATE (yyss); + YYSTACK_RELOCATE (yyvs); +# if YYLSP_NEEDED + YYSTACK_RELOCATE (yyls); +# endif +# undef YYSTACK_RELOCATE + if (yyss1 != yyssa) + YYSTACK_FREE (yyss1); + } +# endif +#endif /* no yyoverflow */ + + yyssp = yyss + yysize - 1; + yyvsp = yyvs + yysize - 1; +#if YYLSP_NEEDED + yylsp = yyls + yysize - 1; +#endif + + YYDPRINTF ((stderr, "Stack size increased to %lu\n", + (unsigned long int) yystacksize)); + + if (yyssp >= yyss + yystacksize - 1) + YYABORT; + } + + YYDPRINTF ((stderr, "Entering state %d\n", yystate)); + + goto yybackup; + + +/*-----------. +| yybackup. | +`-----------*/ +yybackup: + +/* Do appropriate processing given the current state. */ +/* Read a lookahead token if we need one and don't already have one. */ +/* yyresume: */ + + /* First try to decide what to do without reference to lookahead token. */ + + yyn = yypact[yystate]; + if (yyn == YYFLAG) + goto yydefault; + + /* Not known => get a lookahead token if don't already have one. */ + + /* yychar is either YYEMPTY or YYEOF + or a valid token in external form. */ + + if (yychar == YYEMPTY) + { + YYDPRINTF ((stderr, "Reading a token: ")); + yychar = YYLEX; + } + + /* Convert token to internal form (in yychar1) for indexing tables with */ + + if (yychar <= 0) /* This means end of input. */ + { + yychar1 = 0; + yychar = YYEOF; /* Don't call YYLEX any more */ + + YYDPRINTF ((stderr, "Now at end of input.\n")); + } + else + { + yychar1 = YYTRANSLATE (yychar); + +#if YYDEBUG + /* We have to keep this `#if YYDEBUG', since we use variables + which are defined only if `YYDEBUG' is set. */ + if (yydebug) + { + YYFPRINTF (stderr, "Next token is %d (%s", + yychar, yytname[yychar1]); + /* Give the individual parser a way to print the precise + meaning of a token, for further debugging info. */ +# ifdef YYPRINT + YYPRINT (stderr, yychar, yylval); +# endif + YYFPRINTF (stderr, ")\n"); + } +#endif + } + + yyn += yychar1; + if (yyn < 0 || yyn > YYLAST || yycheck[yyn] != yychar1) + goto yydefault; + + yyn = yytable[yyn]; + + /* yyn is what to do for this token type in this state. + Negative => reduce, -yyn is rule number. + Positive => shift, yyn is new state. + New state is final state => don't bother to shift, + just return success. + 0, or most negative number => error. */ + + if (yyn < 0) + { + if (yyn == YYFLAG) + goto yyerrlab; + yyn = -yyn; + goto yyreduce; + } + else if (yyn == 0) + goto yyerrlab; + + if (yyn == YYFINAL) + YYACCEPT; + + /* Shift the lookahead token. */ + YYDPRINTF ((stderr, "Shifting token %d (%s), ", + yychar, yytname[yychar1])); + + /* Discard the token being shifted unless it is eof. */ + if (yychar != YYEOF) + yychar = YYEMPTY; + + *++yyvsp = yylval; +#if YYLSP_NEEDED + *++yylsp = yylloc; +#endif + + /* Count tokens shifted since error; after three, turn off error + status. */ + if (yyerrstatus) + yyerrstatus--; + + yystate = yyn; + goto yynewstate; + + +/*-----------------------------------------------------------. +| yydefault -- do the default action for the current state. | +`-----------------------------------------------------------*/ +yydefault: + yyn = yydefact[yystate]; + if (yyn == 0) + goto yyerrlab; + goto yyreduce; + + +/*-----------------------------. +| yyreduce -- Do a reduction. | +`-----------------------------*/ +yyreduce: + /* yyn is the number of a rule to reduce with. */ + yylen = yyr2[yyn]; + + /* If YYLEN is nonzero, implement the default value of the action: + `$$ = $1'. + + Otherwise, the following line sets YYVAL to the semantic value of + the lookahead token. This behavior is undocumented and Bison + users should not rely upon it. Assigning to YYVAL + unconditionally makes the parser a bit smaller, and it avoids a + GCC warning that YYVAL may be used uninitialized. */ + yyval = yyvsp[1-yylen]; + +#if YYLSP_NEEDED + /* Similarly for the default location. Let the user run additional + commands if for instance locations are ranges. */ + yyloc = yylsp[1-yylen]; + YYLLOC_DEFAULT (yyloc, (yylsp - yylen), yylen); +#endif + +#if YYDEBUG + /* We have to keep this `#if YYDEBUG', since we use variables which + are defined only if `YYDEBUG' is set. */ + if (yydebug) + { + int yyi; + + YYFPRINTF (stderr, "Reducing via rule %d (line %d), ", + yyn, yyrline[yyn]); + + /* Print the symbols being reduced, and their result. */ + for (yyi = yyprhs[yyn]; yyrhs[yyi] > 0; yyi++) + YYFPRINTF (stderr, "%s ", yytname[yyrhs[yyi]]); + YYFPRINTF (stderr, " -> %s\n", yytname[yyr1[yyn]]); + } +#endif + + switch (yyn) { + +case 1: +#line 62 "geometry.yy" +{ + linenum = 1; + ; + break;} +case 2: +#line 69 "geometry.yy" +{ + int i; + extern ARRAY<char*> parsestrings; + for (i = 0; i < parsestrings.Size(); i++) + delete [] parsestrings[i]; + parsestrings.SetSize(0); + ; + break;} +case 5: +#line 86 "geometry.yy" +{ parsegeom->SetSolid(yyvsp[-2].chptr, new Solid (Solid::ROOT, yyvsp[0].solidtype)); + ; + break;} +case 6: +#line 89 "geometry.yy" +{ + parsegeom->SetFlags(yyvsp[-4].chptr, parseflags); + ; + break;} +case 8: +#line 96 "geometry.yy" +{ yyval.solidtype = (Solid*)parsegeom->GetSolid(yyvsp[0].chptr); ; + break;} +case 9: +#line 97 "geometry.yy" +{ yyval.solidtype = new Solid (Solid::UNION, yyvsp[-2].solidtype, yyvsp[0].solidtype); ; + break;} +case 10: +#line 98 "geometry.yy" +{ yyval.solidtype = new Solid (Solid::SECTION, yyvsp[-2].solidtype, yyvsp[0].solidtype); ; + break;} +case 11: +#line 99 "geometry.yy" +{ yyval.solidtype = new Solid (Solid::SUB, yyvsp[0].solidtype); ; + break;} +case 12: +#line 100 "geometry.yy" +{ yyval.solidtype = yyvsp[-1].solidtype; ; + break;} +case 13: +#line 106 "geometry.yy" +{ + OneSurfacePrimitive * surf = new Sphere (Point<3> (yyvsp[-7].val, yyvsp[-5].val, yyvsp[-3].val), yyvsp[-1].val); + parsegeom -> AddSurface (surf); + surf->SetSurfaceId (0, parsegeom->GetNSurf()-1); + yyval.solidtype = new Solid (surf); + ; + break;} +case 14: +#line 116 "geometry.yy" +{ + OneSurfacePrimitive * surf = new Cylinder (Point<3> (yyvsp[-13].val, yyvsp[-11].val, yyvsp[-9].val), + Point<3> (yyvsp[-7].val, yyvsp[-5].val, yyvsp[-3].val), yyvsp[-1].val); + parsegeom->AddSurface (surf); + surf->SetSurfaceId (0, parsegeom->GetNSurf()-1); + yyval.solidtype = new Solid (surf); + ; + break;} +case 15: +#line 128 "geometry.yy" +{ + OneSurfacePrimitive * surf = new Cone (Point<3> (yyvsp[-15].val, yyvsp[-13].val, yyvsp[-11].val), + Point<3> (yyvsp[-7].val, yyvsp[-5].val, yyvsp[-3].val), yyvsp[-9].val, yyvsp[-1].val); + parsegeom->AddSurface (surf); + surf->SetSurfaceId (0, parsegeom->GetNSurf()-1); + yyval.solidtype = new Solid (surf); + ; + break;} +case 16: +#line 137 "geometry.yy" +{ + OneSurfacePrimitive * surf = new Plane ( Point<3> (yyvsp[-11].val, yyvsp[-9].val, yyvsp[-7].val), + Vec<3> (yyvsp[-5].val, yyvsp[-3].val, yyvsp[-1].val) ); + parsegeom->AddSurface (surf); + surf->SetSurfaceId (0, parsegeom->GetNSurf()-1); + yyval.solidtype = new Solid (surf); + ; + break;} +case 17: +#line 146 "geometry.yy" +{ + Primitive * nprim = new OrthoBrick (Point<3> (yyvsp[-11].val, yyvsp[-9].val, yyvsp[-7].val), + Point<3> (yyvsp[-5].val, yyvsp[-3].val, yyvsp[-1].val)); + for (int j = 0; j < nprim->GetNSurfaces(); j++) + { + parsegeom->AddSurface (&nprim->GetSurface(j)); + nprim->SetSurfaceId (j, parsegeom->GetNSurf()-1); + yyval.solidtype = new Solid (nprim); + } + ; + break;} +case 18: +#line 159 "geometry.yy" +{ + polyhedron = new Polyhedra (); + ; + break;} +case 19: +#line 164 "geometry.yy" +{ + int j; + for (j = 0; j < polyhedron->GetNSurfaces(); j++) + { + parsegeom->AddSurface (&polyhedron->GetSurface(j)); + polyhedron->SetSurfaceId (j, parsegeom->GetNSurf()-1); + yyval.solidtype = new Solid (polyhedron); + } + ; + break;} +case 20: +#line 198 "geometry.yy" +{ + Solid * nsol = yyvsp[-1].solidtype -> Copy(*parsegeom); + Vec<3> v(yyvsp[-7].val, yyvsp[-5].val, yyvsp[-3].val); + Transformation<3> trans(v); + nsol -> Transform (trans); + yyval.solidtype = nsol; + ; + break;} +case 21: +#line 207 "geometry.yy" +{ + int i; + Solid * hsol = yyvsp[-1].solidtype; + for (i = 1; i <= yyvsp[-3].val; i++) + { + Solid * nsol = yyvsp[-1].solidtype -> Copy(*parsegeom); + Vec<3> v(yyvsp[-9].val, yyvsp[-7].val, yyvsp[-5].val); + v *= i; + Transformation<3> trans(v); + nsol -> Transform (trans); + hsol = new Solid (Solid::UNION, hsol, nsol); + } + yyval.solidtype = hsol; + ; + break;} +case 22: +#line 223 "geometry.yy" +{ + Solid * nsol = yyvsp[-1].solidtype -> Copy(*parsegeom); + Point<3> c(yyvsp[-13].val, yyvsp[-11].val, yyvsp[-9].val); + Transformation<3> rot(c, yyvsp[-7].val, yyvsp[-5].val, yyvsp[-3].val); + nsol -> Transform (rot); + yyval.solidtype = nsol; + ; + break;} +case 23: +#line 234 "geometry.yy" +{ + int i; + Solid * hsol = yyvsp[-1].solidtype; + + Point<3> c(yyvsp[-15].val, yyvsp[-13].val, yyvsp[-11].val); + Transformation<3> trans(c, yyvsp[-9].val, yyvsp[-7].val, yyvsp[-5].val); + Transformation<3> multi(Vec<3>(0,0,0)); + Transformation<3> ht; + + for (i = 1; i <= yyvsp[-3].val; i++) + { + Solid * nsol = yyvsp[-1].solidtype -> Copy(*parsegeom); + nsol -> Transform (multi); + hsol = new Solid (Solid::UNION, hsol, nsol); + + ht=multi; + multi.Combine (trans, ht); + } + yyval.solidtype = hsol; + ; + break;} +case 28: +#line 295 "geometry.yy" +{ + polyhedron->AddPoint (Point<3> (yyvsp[-4].val, yyvsp[-2].val, yyvsp[0].val)); + cout << " " << yyvsp[-4].val << " " << yyvsp[-2].val << " " << yyvsp[0].val << endl; + ; + break;} +case 29: +#line 302 "geometry.yy" +{ + polyhedron->AddFace (int(yyvsp[-4].val)-1, int(yyvsp[-2].val)-1, int(yyvsp[0].val)-1); + cout << yyvsp[-4].val << " " << yyvsp[-2].val << " " << yyvsp[0].val << endl; + ; + break;} +case 30: +#line 307 "geometry.yy" +{ + cout << "face, 1 = " << yyvsp[-6].val << " " << yyvsp[-4].val << " " << yyvsp[-2].val << " " << yyvsp[0].val << endl; + polyhedron->AddFace (int(yyvsp[-6].val)-1, int(yyvsp[-4].val)-1, int(yyvsp[-2].val)-1); + polyhedron->AddFace (int(yyvsp[-6].val)-1, int(yyvsp[-2].val)-1, int(yyvsp[0].val)-1); + cout << yyvsp[-6].val << yyvsp[-4].val << yyvsp[-2].val << yyvsp[0].val << endl; + ; + break;} +case 33: +#line 321 "geometry.yy" +{ +// revolution->AddPoint (Point<2> ($1, $3)); + cout << " " << yyvsp[-2].val << " " << yyvsp[0].val << endl; + ; + break;} +case 36: +#line 338 "geometry.yy" +{ + middlecurve->AddSegment (splinep1, Point<3> (yyvsp[-10].val, yyvsp[-8].val, yyvsp[-6].val), Point<3> (yyvsp[-4].val, yyvsp[-2].val, yyvsp[0].val)); + splinep1(0) = yyvsp[-4].val; splinep1(1) = yyvsp[-2].val; splinep1(2) = yyvsp[0].val; + ; + break;} +case 37: +#line 347 "geometry.yy" +{ + bspline = new BSplineCurve2d; + bspline -> AddPoint (Point<2> (yyvsp[-2].val, yyvsp[0].val)); + cout << "first point" << endl; + ; + break;} +case 39: +#line 355 "geometry.yy" +{ ; + break;} +case 40: +#line 357 "geometry.yy" +{ + bspline -> AddPoint (Point<2> (yyvsp[-2].val, yyvsp[0].val)); + cout << "Add Point: " << yyvsp[-2].val << "-" << yyvsp[0].val << endl; + ; + break;} +case 44: +#line 379 "geometry.yy" +{ cout << "singular edge:" << yyvsp[-2].val << " between " + << yyvsp[-1].chptr << " and " << yyvsp[0].chptr << endl; + parsegeom->singedges.Append + (new SingularEdge (yyvsp[-2].val, parsegeom->GetSolid(yyvsp[-1].chptr), + parsegeom->GetSolid(yyvsp[0].chptr))); + ; + break;} +case 45: +#line 387 "geometry.yy" +{ cout << "singular point:" << yyvsp[-3].val << " between " + << yyvsp[-2].chptr << ", " << yyvsp[-1].chptr << " and " << yyvsp[0].chptr << endl; + parsegeom->singpoints.Append + (new SingularPoint (yyvsp[-3].val, parsegeom->GetSolid(yyvsp[-2].chptr), + parsegeom->GetSolid(yyvsp[-1].chptr), + parsegeom->GetSolid(yyvsp[0].chptr))); + ; + break;} +case 46: +#line 396 "geometry.yy" +{ + ARRAY<int> si1, si2; + parsegeom->GetSolid(yyvsp[-2].chptr)->GetSurfaceIndices(si1); + parsegeom->GetSolid(yyvsp[-1].chptr)->GetSurfaceIndices(si2); + + parsegeom->AddIdentification ( + new CloseSurfaceIdentification ( + parsegeom->GetNIdentifications()+1, + *parsegeom, + parsegeom->GetSurface (si1[0]), + parsegeom->GetSurface (si2[0]), + parseflags)); + ; + break;} +case 47: +#line 411 "geometry.yy" +{ + ARRAY<int> si1, si2, si3; + parsegeom->GetSolid(yyvsp[-2].chptr)->GetSurfaceIndices(si1); + parsegeom->GetSolid(yyvsp[-1].chptr)->GetSurfaceIndices(si2); + parsegeom->GetSolid(yyvsp[0].chptr)->GetSurfaceIndices(si3); + + parsegeom->AddIdentification ( + new CloseEdgesIdentification ( + parsegeom->GetNIdentifications()+1, + *parsegeom, + parsegeom->GetSurface (si1.Get(1)), + parsegeom->GetSurface (si2.Get(1)), + parsegeom->GetSurface (si3.Get(1)))); + ; + break;} +case 48: +#line 427 "geometry.yy" +{ + ARRAY<int> si1, si2; + parsegeom->GetSolid(yyvsp[-1].chptr)->GetSurfaceIndices(si1); + parsegeom->GetSolid(yyvsp[0].chptr)->GetSurfaceIndices(si2); + + parsegeom->AddIdentification ( + new PeriodicIdentification ( + parsegeom->GetNIdentifications()+1, + *parsegeom, + parsegeom->GetSurface (si1.Get(1)), + parsegeom->GetSurface (si2.Get(1)))); + ; + break;} +case 49: +#line 441 "geometry.yy" +{ + int tlonr = + parsegeom->SetTopLevelObject ((Solid*)parsegeom->GetSolid(yyvsp[-1].chptr)); + TopLevelObject * tlo = parsegeom->GetTopLevelObject (tlonr); + if (parseflags.NumListFlagDefined ("col")) + { + const ARRAY<double> & col = parseflags.GetNumListFlag ("col"); + tlo->SetRGB (col[0], col[1], col[2]); + } + if (parseflags.GetDefineFlag ("transparent")) + tlo->SetTransparent (1); + ; + break;} +case 50: +#line 455 "geometry.yy" +{ + ARRAY<int> si; + parsegeom->GetSolid(yyvsp[-1].chptr)->GetSurfaceIndices(si); + int tlonr = + parsegeom->SetTopLevelObject ((Solid*)parsegeom->GetSolid(yyvsp[-2].chptr), + (Surface*)parsegeom->GetSurface(si.Get(1))); + TopLevelObject * tlo = parsegeom->GetTopLevelObject (tlonr); + if (parseflags.NumListFlagDefined ("col")) + { + const ARRAY<double> & col = parseflags.GetNumListFlag ("col"); + tlo->SetRGB (col.Get(1), col.Get(2), col.Get(3)); + } + if (parseflags.GetDefineFlag ("transparent")) + tlo->SetTransparent (1); + ; + break;} +case 51: +#line 473 "geometry.yy" +{ + parsegeom->SetBoundingBox (Box<3> (Point<3> (yyvsp[-11].val, yyvsp[-9].val, yyvsp[-7].val), + Point<3> (yyvsp[-5].val, yyvsp[-3].val, yyvsp[-1].val))); + ; + break;} +case 52: +#line 479 "geometry.yy" +{ + parsegeom->AddUserPoint (Point<3> (yyvsp[-5].val, yyvsp[-3].val, yyvsp[-1].val)); + ; + break;} +case 53: +#line 484 "geometry.yy" +{ + CSGeometry::BCModification bcm; + ARRAY<int> si; + + parsegeom->GetSolid(yyvsp[-2].chptr)->GetSurfaceIndices(si); + + bcm.tlonr = -1; + int i; + for (i = 0; i < parsegeom->GetNTopLevelObjects(); i++) + if (strcmp (parsegeom->GetTopLevelObject(i)->GetSolid()->Name(), yyvsp[-1].chptr) == 0) + { + bcm.tlonr = i; + break; + } + + bcm.bcnr = int(yyvsp[0].val); + for (i = 0; i < si.Size(); i++) + { + bcm.si = si[i]; + parsegeom->bcmodifications.Append (bcm); + } + ; + break;} +case 54: +#line 512 "geometry.yy" +{ parseflags.DeleteFlags (); ; + break;} +case 58: +#line 523 "geometry.yy" +{ parseflags.SetFlag (yyvsp[0].chptr); ; + break;} +case 59: +#line 525 "geometry.yy" +{ parseflags.SetFlag (yyvsp[-2].chptr, yyvsp[0].chptr); ; + break;} +case 60: +#line 527 "geometry.yy" +{ parseflags.SetFlag (yyvsp[-2].chptr, yyvsp[0].val); ; + break;} +case 61: +#line 529 "geometry.yy" +{ parseflags.SetFlag (yyvsp[-2].chptr, doublearray); ; + break;} +case 62: +#line 531 "geometry.yy" +{ parseflags.SetFlag (yyvsp[-2].chptr, stringarray); ; + break;} +case 63: +#line 536 "geometry.yy" +{ doublearray.SetSize (0); ; + break;} +case 65: +#line 541 "geometry.yy" +{ doublearray.Append (yyvsp[0].val); ; + break;} +case 66: +#line 542 "geometry.yy" +{ doublearray.Append (yyvsp[0].val); ; + break;} +case 67: +#line 547 "geometry.yy" +{ + int i; + for (i = 0; i < stringarray.Size(); i++) + delete stringarray[i]; + stringarray.SetSize (0); + ; + break;} +case 69: +#line 558 "geometry.yy" +{ + stringarray.Append (new char[strlen(yyvsp[0].chptr)+1]); + strcpy (stringarray.Last(), yyvsp[0].chptr); + ; + break;} +case 70: +#line 564 "geometry.yy" +{ + stringarray.Append (new char[strlen(yyvsp[0].chptr)+1]); + strcpy (stringarray.Last(), yyvsp[0].chptr); + ; + break;} +case 71: +#line 575 "geometry.yy" +{ yyval.chptr = yyvsp[0].chptr; ; + break;} +case 72: +#line 576 "geometry.yy" +{ yyval.chptr = yyvsp[0].chptr; ; + break;} +} + +#line 709 "/usr/share/bison/bison.simple" + + + yyvsp -= yylen; + yyssp -= yylen; +#if YYLSP_NEEDED + yylsp -= yylen; +#endif + +#if YYDEBUG + if (yydebug) + { + short *yyssp1 = yyss - 1; + YYFPRINTF (stderr, "state stack now"); + while (yyssp1 != yyssp) + YYFPRINTF (stderr, " %d", *++yyssp1); + YYFPRINTF (stderr, "\n"); + } +#endif + + *++yyvsp = yyval; +#if YYLSP_NEEDED + *++yylsp = yyloc; +#endif + + /* Now `shift' the result of the reduction. Determine what state + that goes to, based on the state we popped back to and the rule + number reduced by. */ + + yyn = yyr1[yyn]; + + yystate = yypgoto[yyn - YYNTBASE] + *yyssp; + if (yystate >= 0 && yystate <= YYLAST && yycheck[yystate] == *yyssp) + yystate = yytable[yystate]; + else + yystate = yydefgoto[yyn - YYNTBASE]; + + goto yynewstate; + + +/*------------------------------------. +| yyerrlab -- here on detecting error | +`------------------------------------*/ +yyerrlab: + /* If not already recovering from an error, report this error. */ + if (!yyerrstatus) + { + ++yynerrs; + +#ifdef YYERROR_VERBOSE + yyn = yypact[yystate]; + + if (yyn > YYFLAG && yyn < YYLAST) + { + YYSIZE_T yysize = 0; + char *yymsg; + int yyx, yycount; + + yycount = 0; + /* Start YYX at -YYN if negative to avoid negative indexes in + YYCHECK. */ + for (yyx = yyn < 0 ? -yyn : 0; + yyx < (int) (sizeof (yytname) / sizeof (char *)); yyx++) + if (yycheck[yyx + yyn] == yyx) + yysize += yystrlen (yytname[yyx]) + 15, yycount++; + yysize += yystrlen ("parse error, unexpected ") + 1; + yysize += yystrlen (yytname[YYTRANSLATE (yychar)]); + yymsg = (char *) YYSTACK_ALLOC (yysize); + if (yymsg != 0) + { + char *yyp = yystpcpy (yymsg, "parse error, unexpected "); + yyp = yystpcpy (yyp, yytname[YYTRANSLATE (yychar)]); + + if (yycount < 5) + { + yycount = 0; + for (yyx = yyn < 0 ? -yyn : 0; + yyx < (int) (sizeof (yytname) / sizeof (char *)); + yyx++) + if (yycheck[yyx + yyn] == yyx) + { + const char *yyq = ! yycount ? ", expecting " : " or "; + yyp = yystpcpy (yyp, yyq); + yyp = yystpcpy (yyp, yytname[yyx]); + yycount++; + } + } + yyerror (yymsg); + YYSTACK_FREE (yymsg); + } + else + yyerror ("parse error; also virtual memory exhausted"); + } + else +#endif /* defined (YYERROR_VERBOSE) */ + yyerror ("parse error"); + } + goto yyerrlab1; + + +/*--------------------------------------------------. +| yyerrlab1 -- error raised explicitly by an action | +`--------------------------------------------------*/ +yyerrlab1: + if (yyerrstatus == 3) + { + /* If just tried and failed to reuse lookahead token after an + error, discard it. */ + + /* return failure if at end of input */ + if (yychar == YYEOF) + YYABORT; + YYDPRINTF ((stderr, "Discarding token %d (%s).\n", + yychar, yytname[yychar1])); + yychar = YYEMPTY; + } + + /* Else will try to reuse lookahead token after shifting the error + token. */ + + yyerrstatus = 3; /* Each real token shifted decrements this */ + + goto yyerrhandle; + + +/*-------------------------------------------------------------------. +| yyerrdefault -- current state does not do anything special for the | +| error token. | +`-------------------------------------------------------------------*/ +yyerrdefault: +#if 0 + /* This is wrong; only states that explicitly want error tokens + should shift them. */ + + /* If its default is to accept any token, ok. Otherwise pop it. */ + yyn = yydefact[yystate]; + if (yyn) + goto yydefault; +#endif + + +/*---------------------------------------------------------------. +| yyerrpop -- pop the current state because it cannot handle the | +| error token | +`---------------------------------------------------------------*/ +yyerrpop: + if (yyssp == yyss) + YYABORT; + yyvsp--; + yystate = *--yyssp; +#if YYLSP_NEEDED + yylsp--; +#endif + +#if YYDEBUG + if (yydebug) + { + short *yyssp1 = yyss - 1; + YYFPRINTF (stderr, "Error: state stack now"); + while (yyssp1 != yyssp) + YYFPRINTF (stderr, " %d", *++yyssp1); + YYFPRINTF (stderr, "\n"); + } +#endif + +/*--------------. +| yyerrhandle. | +`--------------*/ +yyerrhandle: + yyn = yypact[yystate]; + if (yyn == YYFLAG) + goto yyerrdefault; + + yyn += YYTERROR; + if (yyn < 0 || yyn > YYLAST || yycheck[yyn] != YYTERROR) + goto yyerrdefault; + + yyn = yytable[yyn]; + if (yyn < 0) + { + if (yyn == YYFLAG) + goto yyerrpop; + yyn = -yyn; + goto yyreduce; + } + else if (yyn == 0) + goto yyerrpop; + + if (yyn == YYFINAL) + YYACCEPT; + + YYDPRINTF ((stderr, "Shifting error token, ")); + + *++yyvsp = yylval; +#if YYLSP_NEEDED + *++yylsp = yylloc; +#endif + + yystate = yyn; + goto yynewstate; + + +/*-------------------------------------. +| yyacceptlab -- YYACCEPT comes here. | +`-------------------------------------*/ +yyacceptlab: + yyresult = 0; + goto yyreturn; + +/*-----------------------------------. +| yyabortlab -- YYABORT comes here. | +`-----------------------------------*/ +yyabortlab: + yyresult = 1; + goto yyreturn; + +/*---------------------------------------------. +| yyoverflowab -- parser overflow comes here. | +`---------------------------------------------*/ +yyoverflowlab: + yyerror ("parser stack overflow"); + yyresult = 2; + /* Fall through. */ + +yyreturn: +#ifndef yyoverflow + if (yyss != yyssa) + YYSTACK_FREE (yyss); +#endif + return yyresult; +} +#line 577 "geometry.yy" + + + +int yyerror (char * s) +{ + cerr << s << " in line " << linenum << endl; + return 0; +} + diff --git a/contrib/Netgen/libsrc/csg/geometry.h b/contrib/Netgen/libsrc/csg/geometry.h new file mode 100644 index 0000000000..d84e8db183 --- /dev/null +++ b/contrib/Netgen/libsrc/csg/geometry.h @@ -0,0 +1,48 @@ +#ifndef BISON_GEOMETRY_H +# define BISON_GEOMETRY_H + +#ifndef YYSTYPE +typedef union { +double val; +char * chptr; +Solid * solidtype; +} yystype; +# define YYSTYPE yystype +# define YYSTYPE_IS_TRIVIAL 1 +#endif +# define NUM 257 +# define TOK_SOLID 258 +# define TOK_RECO 259 +# define TOK_TLO 260 +# define TOK_BOUNDINGBOX 261 +# define IDENT 262 +# define IDENTSOLID 263 +# define TOK_SPHERE 264 +# define TOK_CYLINDER 265 +# define TOK_CONE 266 +# define TOK_PLAIN 267 +# define TOK_TUBE 268 +# define TOK_GENCYL 269 +# define TOK_ORTHOBRICK 270 +# define TOK_POLYHEDRON 271 +# define TOK_REVOLUTION 272 +# define TOK_OR 273 +# define TOK_AND 274 +# define TOK_NOT 275 +# define TOK_TRANSLATE 276 +# define TOK_MULTITRANSLATE 277 +# define TOK_ROTATE 278 +# define TOK_MULTIROTATE 279 +# define TOK_SINGULAR 280 +# define TOK_EDGE 281 +# define TOK_POINT 282 +# define TOK_IDENTIFY 283 +# define TOK_CLOSESURFACES 284 +# define TOK_CLOSEEDGES 285 +# define TOK_PERIODIC 286 +# define TOK_BOUNDARYCONDITION 287 + + +extern YYSTYPE yylval; + +#endif /* not BISON_GEOMETRY_H */ diff --git a/contrib/Netgen/libsrc/csg/geometry.ll b/contrib/Netgen/libsrc/csg/geometry.ll new file mode 100644 index 0000000000..bb2edbc9f5 --- /dev/null +++ b/contrib/Netgen/libsrc/csg/geometry.ll @@ -0,0 +1,94 @@ +%{ +#include <mystdlib.h> +#include <myadt.hpp> + +#include <linalg.hpp> +#include <csg.hpp> + + + + +// extern SYMBOLTABLE<Solid*> solids; +namespace netgen { +extern CSGeometry * parsegeom; +} +using namespace netgen; + +#include "geometry.h" + + +ARRAY<char*> parsestrings; +int linenum; +%} + +dig [0-9] +id [a-zA-Z][a-zA-Z0-9]* +num1 [-+]?{dig}+\.?([eE][-+]?{dig}+)? +num2 [-+]?{dig}*\.{dig}+([eE][-+]?{dig}+)? +number {num1}|{num2} +%x incl +%x comment + +%% +algebraic3d { return TOK_RECO; } +solid { return TOK_SOLID; } +tlo { return TOK_TLO; } +and { return TOK_AND; } +or { return TOK_OR; } +not { return TOK_NOT; } +translate { return TOK_TRANSLATE; } +multitranslate { return TOK_MULTITRANSLATE; } +rotate { return TOK_ROTATE; } +multirotate { return TOK_MULTIROTATE; } +sphere { return TOK_SPHERE; } +cylinder { return TOK_CYLINDER; } +cone { return TOK_CONE; } +plain { return TOK_PLAIN; } +plane { return TOK_PLAIN; } +tube { return TOK_TUBE; } +gencyl { return TOK_GENCYL; } +orthobrick { return TOK_ORTHOBRICK; } +polyhedron { return TOK_POLYHEDRON; } +revolution { return TOK_REVOLUTION; } + +singular { return TOK_SINGULAR; } +edge { return TOK_EDGE; } +point { return TOK_POINT; } + +identify { return TOK_IDENTIFY; } +closesurfaces { return TOK_CLOSESURFACES; } +closeedges { return TOK_CLOSEEDGES; } +periodic { return TOK_PERIODIC; } +boundarycondition { return TOK_BOUNDARYCONDITION; } +boundingbox { return TOK_BOUNDINGBOX; } + +{number} { yylval.val = atof (YYText()); return NUM; } +{id}+ { + yylval.chptr = new char [YYLeng()+1]; + parsestrings.Append (yylval.chptr); + strcpy (yylval.chptr, YYText()); + if (parsegeom->GetSolid (yylval.chptr)) + return IDENTSOLID; + else + return IDENT; + } +[ \t] /* eat up ws */ +. { return int(*YYText()); } +\n { linenum++; } +"##".*\n { linenum++; cout << (YYText()+2) ; } /* line comment */ +"#".*\n { linenum++; } /* line comment */ + + +%% + +extern FlexLexer * lexer; + +int yylex () + { + return lexer -> yylex(); + } + +extern "C" int yywrap () + { + return 1; + } diff --git a/contrib/Netgen/libsrc/csg/geometry.yy b/contrib/Netgen/libsrc/csg/geometry.yy new file mode 100644 index 0000000000..49dd63a53a --- /dev/null +++ b/contrib/Netgen/libsrc/csg/geometry.yy @@ -0,0 +1,585 @@ +%{ +//define YYDEBUG 1 + +extern int yylex (); + +#include <mystdlib.h> + +#include <myadt.hpp> + +#include <linalg.hpp> +#include <csg.hpp> + +namespace netgen +{ +netgen::CSGeometry * parsegeom; +} + +using namespace netgen; + +// extern ARRAY<Surface*> surfaces; +// extern SYMBOLTABLE<Solid*> solids; + + +int yyerror (char * s); +splinetube * tube; +spline3d * middlecurve; +Point<3> splinep1; +BSplineCurve2d *bspline; +Flags parseflags; +extern int linenum; +ARRAY<double> doublearray; +ARRAY<char*> stringarray; + +Polyhedra * polyhedron; +// Revolution * revolution; +%} + +%union { +double val; +char * chptr; +Solid * solidtype; +} + +%token <val> NUM +%token TOK_SOLID, TOK_RECO, TOK_TLO, TOK_BOUNDINGBOX +%token <chptr> IDENT IDENTSOLID +%token <solidtype> TOK_SPHERE TOK_CYLINDER TOK_CONE TOK_PLAIN TOK_TUBE TOK_GENCYL TOK_ORTHOBRICK TOK_POLYHEDRON TOK_REVOLUTION +%left <solidtype> TOK_OR TOK_AND TOK_NOT +%token <solidtype> TOK_TRANSLATE TOK_MULTITRANSLATE TOK_ROTATE TOK_MULTIROTATE +%type <solidtype> solid solidprimitive +%type <void> splinesegmentlist splinesegment readbspline bsplinepointlist +%type <chptr> anyident +%token TOK_SINGULAR TOK_EDGE TOK_POINT +%token TOK_IDENTIFY TOK_CLOSESURFACES TOK_CLOSEEDGES TOK_PERIODIC +%token TOK_BOUNDARYCONDITION +%type <void> polyhedronpoints polyhedronfaces polyhedronpoint polyhedronface +%type <void> revolutionpoints revolutionpoint + + +%% +input: + { + linenum = 1; + } + TOK_RECO + recsoliddef + recadddef + + { + int i; + extern ARRAY<char*> parsestrings; + for (i = 0; i < parsestrings.Size(); i++) + delete [] parsestrings[i]; + parsestrings.SetSize(0); + } + ; + + +recsoliddef: + /* empty */ + | recsoliddef soliddef ';' + ; + +soliddef: + TOK_SOLID IDENT '=' solid + { parsegeom->SetSolid($2, new Solid (Solid::ROOT, $4)); + } + flaglist + { + parsegeom->SetFlags($2, parseflags); + } + ; + +solid: + solidprimitive + | IDENTSOLID { $$ = (Solid*)parsegeom->GetSolid($1); } + | solid TOK_OR solid { $$ = new Solid (Solid::UNION, $1, $3); } + | solid TOK_AND solid { $$ = new Solid (Solid::SECTION, $1, $3); } + | TOK_NOT solid { $$ = new Solid (Solid::SUB, $2); } + | '(' solid ')' { $$ = $2; } + ; + +solidprimitive: + TOK_SPHERE '(' NUM ',' NUM ',' NUM ';' + NUM ')' + { + OneSurfacePrimitive * surf = new Sphere (Point<3> ($3, $5, $7), $9); + parsegeom -> AddSurface (surf); + surf->SetSurfaceId (0, parsegeom->GetNSurf()-1); + $$ = new Solid (surf); + } + | TOK_CYLINDER '(' NUM ',' NUM ',' NUM ';' + NUM ',' NUM ',' NUM ';' + NUM ')' + + { + OneSurfacePrimitive * surf = new Cylinder (Point<3> ($3, $5, $7), + Point<3> ($9, $11, $13), $15); + parsegeom->AddSurface (surf); + surf->SetSurfaceId (0, parsegeom->GetNSurf()-1); + $$ = new Solid (surf); + } + | TOK_CONE '(' NUM ',' NUM ',' NUM ';' + NUM ';' + NUM ',' NUM ',' NUM ';' + NUM ')' + + { + OneSurfacePrimitive * surf = new Cone (Point<3> ($3, $5, $7), + Point<3> ($11, $13, $15), $9, $17); + parsegeom->AddSurface (surf); + surf->SetSurfaceId (0, parsegeom->GetNSurf()-1); + $$ = new Solid (surf); + } + | TOK_PLAIN '(' NUM ',' NUM ',' NUM ';' + NUM ',' NUM ',' NUM ')' + { + OneSurfacePrimitive * surf = new Plane ( Point<3> ($3, $5, $7), + Vec<3> ($9, $11, $13) ); + parsegeom->AddSurface (surf); + surf->SetSurfaceId (0, parsegeom->GetNSurf()-1); + $$ = new Solid (surf); + } + | TOK_ORTHOBRICK '(' NUM ',' NUM ',' NUM ';' + NUM ',' NUM ',' NUM ')' + { + Primitive * nprim = new OrthoBrick (Point<3> ($3, $5, $7), + Point<3> ($9, $11, $13)); + for (int j = 0; j < nprim->GetNSurfaces(); j++) + { + parsegeom->AddSurface (&nprim->GetSurface(j)); + nprim->SetSurfaceId (j, parsegeom->GetNSurf()-1); + $$ = new Solid (nprim); + } + } + + + | TOK_POLYHEDRON '(' + { + polyhedron = new Polyhedra (); + } + polyhedronpoints ';' ';' + polyhedronfaces ')' + { + int j; + for (j = 0; j < polyhedron->GetNSurfaces(); j++) + { + parsegeom->AddSurface (&polyhedron->GetSurface(j)); + polyhedron->SetSurfaceId (j, parsegeom->GetNSurf()-1); + $$ = new Solid (polyhedron); + } + } + + +/* + | TOK_REVOLUTION '(' NUM ',' NUM ',' NUM ';' + NUM ',' NUM ',' NUM ';' + { + revolution = new Revolution (Point<3> ($3, $5, $7), + Point<3> ($9, $11, $13)); + } + revolutionpoints + ')' + { + revolution -> Finish (); + int j; + for (j = 0; j < revolution->GetNSurfaces(); j++) + { + parsegeom->AddSurface (&revolution->GetSurface(j)); + revolution->SetSurfaceId (j, parsegeom->GetNSurf()-1); + $$ = new Solid (revolution); + } + } +*/ + + + | TOK_TRANSLATE '(' NUM ',' NUM ',' NUM ';' solid ')' + { + Solid * nsol = $9 -> Copy(*parsegeom); + Vec<3> v($3, $5, $7); + Transformation<3> trans(v); + nsol -> Transform (trans); + $$ = nsol; + } + + | TOK_MULTITRANSLATE '(' NUM ',' NUM ',' NUM ';' NUM ';' solid ')' + { + int i; + Solid * hsol = $11; + for (i = 1; i <= $9; i++) + { + Solid * nsol = $11 -> Copy(*parsegeom); + Vec<3> v($3, $5, $7); + v *= i; + Transformation<3> trans(v); + nsol -> Transform (trans); + hsol = new Solid (Solid::UNION, hsol, nsol); + } + $$ = hsol; + } + + | TOK_ROTATE '(' NUM ',' NUM ',' NUM ';' NUM ',' NUM ',' NUM ';' solid ')' + { + Solid * nsol = $15 -> Copy(*parsegeom); + Point<3> c($3, $5, $7); + Transformation<3> rot(c, $9, $11, $13); + nsol -> Transform (rot); + $$ = nsol; + } + + | TOK_MULTIROTATE '(' NUM ',' NUM ',' NUM ';' + NUM ',' NUM ',' NUM ';' + NUM ';' solid ')' + { + int i; + Solid * hsol = $17; + + Point<3> c($3, $5, $7); + Transformation<3> trans(c, $9, $11, $13); + Transformation<3> multi(Vec<3>(0,0,0)); + Transformation<3> ht; + + for (i = 1; i <= $15; i++) + { + Solid * nsol = $17 -> Copy(*parsegeom); + nsol -> Transform (multi); + hsol = new Solid (Solid::UNION, hsol, nsol); + + ht=multi; + multi.Combine (trans, ht); + } + $$ = hsol; + } + + +/* + | TOK_TUBE '(' NUM ',' NUM ',' NUM ',' + { + middlecurve = new spline3d; + splinep1.X() = $3; splinep1.Y() = $5; splinep1.Z() = $7; + } + splinesegmentlist ';' NUM ')' + { + Surface * surf = new splinetube (*middlecurve, $12); + parsegeom->AddSurface (surf); + $$ = new Solid (surf, parsegeom->GetNSurf()); + } + + | TOK_GENCYL '(' NUM ',' NUM ',' NUM ';' + NUM ',' NUM ',' NUM ';' + NUM ',' NUM ',' NUM ';' + readbspline + ')' + { + Surface * surf = new GeneralizedCylinder + (*bspline, Point<3> ($3, $5, $7), Vec<3> ($9, $11, $13), + Vec<3> ($15, $17, $19) ); + parsegeom->AddSurface (surf); + $$ = new Solid (surf, parsegeom->GetNSurf()); + } +*/ + ; + + +polyhedronpoints: + polyhedronpoints ';' polyhedronpoint + | polyhedronpoint + ; +polyhedronfaces: + polyhedronfaces ';' polyhedronface + | polyhedronface + ; +polyhedronpoint: + NUM ',' NUM ',' NUM + { + polyhedron->AddPoint (Point<3> ($1, $3, $5)); + cout << " " << $1 << " " << $3 << " " << $5 << endl; + } + ; +polyhedronface: + NUM ',' NUM ',' NUM + { + polyhedron->AddFace (int($1)-1, int($3)-1, int($5)-1); + cout << $1 << " " << $3 << " " << $5 << endl; + } + | NUM ',' NUM ',' NUM ',' NUM + { + cout << "face, 1 = " << $1 << " " << $3 << " " << $5 << " " << $7 << endl; + polyhedron->AddFace (int($1)-1, int($3)-1, int($5)-1); + polyhedron->AddFace (int($1)-1, int($5)-1, int($7)-1); + cout << $1 << $3 << $5 << $7 << endl; + } + ; + +revolutionpoints: + revolutionpoints ';' revolutionpoint + | revolutionpoint + ; +revolutionpoint: + NUM ',' NUM + { +// revolution->AddPoint (Point<2> ($1, $3)); + cout << " " << $1 << " " << $3 << endl; + } + ; + + + + + +splinesegmentlist: + splinesegment + | splinesegment ',' splinesegmentlist + ; +splinesegment: + NUM ',' NUM ',' NUM ',' + NUM ',' NUM ',' NUM + { + middlecurve->AddSegment (splinep1, Point<3> ($1, $3, $5), Point<3> ($7, $9, $11)); + splinep1(0) = $7; splinep1(1) = $9; splinep1(2) = $11; + } + ; + + +readbspline: + NUM ',' NUM + { + bspline = new BSplineCurve2d; + bspline -> AddPoint (Point<2> ($1, $3)); + cout << "first point" << endl; + } + bsplinepointlist + ; +bsplinepointlist: + /* empty */ { } + | ',' NUM ',' NUM + { + bspline -> AddPoint (Point<2> ($2, $4)); + cout << "Add Point: " << $2 << "-" << $4 << endl; + } + bsplinepointlist + ; + + + + + + + + + +recadddef: + /* empty */ + | recadddef adddef ';' + ; + +adddef: + TOK_SINGULAR TOK_EDGE NUM IDENTSOLID IDENTSOLID + { cout << "singular edge:" << $3 << " between " + << $4 << " and " << $5 << endl; + parsegeom->singedges.Append + (new SingularEdge ($3, parsegeom->GetSolid($4), + parsegeom->GetSolid($5))); + } + | + TOK_SINGULAR TOK_POINT NUM IDENTSOLID IDENTSOLID IDENTSOLID + { cout << "singular point:" << $3 << " between " + << $4 << ", " << $5 << " and " << $6 << endl; + parsegeom->singpoints.Append + (new SingularPoint ($3, parsegeom->GetSolid($4), + parsegeom->GetSolid($5), + parsegeom->GetSolid($6))); + } + | + TOK_IDENTIFY TOK_CLOSESURFACES IDENTSOLID IDENTSOLID flaglist + { + ARRAY<int> si1, si2; + parsegeom->GetSolid($3)->GetSurfaceIndices(si1); + parsegeom->GetSolid($4)->GetSurfaceIndices(si2); + + parsegeom->AddIdentification ( + new CloseSurfaceIdentification ( + parsegeom->GetNIdentifications()+1, + *parsegeom, + parsegeom->GetSurface (si1[0]), + parsegeom->GetSurface (si2[0]), + parseflags)); + } + | + TOK_IDENTIFY TOK_CLOSEEDGES IDENTSOLID IDENTSOLID IDENTSOLID + { + ARRAY<int> si1, si2, si3; + parsegeom->GetSolid($3)->GetSurfaceIndices(si1); + parsegeom->GetSolid($4)->GetSurfaceIndices(si2); + parsegeom->GetSolid($5)->GetSurfaceIndices(si3); + + parsegeom->AddIdentification ( + new CloseEdgesIdentification ( + parsegeom->GetNIdentifications()+1, + *parsegeom, + parsegeom->GetSurface (si1.Get(1)), + parsegeom->GetSurface (si2.Get(1)), + parsegeom->GetSurface (si3.Get(1)))); + } + | + TOK_IDENTIFY TOK_PERIODIC IDENTSOLID IDENTSOLID + { + ARRAY<int> si1, si2; + parsegeom->GetSolid($3)->GetSurfaceIndices(si1); + parsegeom->GetSolid($4)->GetSurfaceIndices(si2); + + parsegeom->AddIdentification ( + new PeriodicIdentification ( + parsegeom->GetNIdentifications()+1, + *parsegeom, + parsegeom->GetSurface (si1.Get(1)), + parsegeom->GetSurface (si2.Get(1)))); + } + | + TOK_TLO IDENTSOLID flaglist + { + int tlonr = + parsegeom->SetTopLevelObject ((Solid*)parsegeom->GetSolid($2)); + TopLevelObject * tlo = parsegeom->GetTopLevelObject (tlonr); + if (parseflags.NumListFlagDefined ("col")) + { + const ARRAY<double> & col = parseflags.GetNumListFlag ("col"); + tlo->SetRGB (col[0], col[1], col[2]); + } + if (parseflags.GetDefineFlag ("transparent")) + tlo->SetTransparent (1); + } + | + TOK_TLO IDENTSOLID IDENTSOLID flaglist + { + ARRAY<int> si; + parsegeom->GetSolid($3)->GetSurfaceIndices(si); + int tlonr = + parsegeom->SetTopLevelObject ((Solid*)parsegeom->GetSolid($2), + (Surface*)parsegeom->GetSurface(si.Get(1))); + TopLevelObject * tlo = parsegeom->GetTopLevelObject (tlonr); + if (parseflags.NumListFlagDefined ("col")) + { + const ARRAY<double> & col = parseflags.GetNumListFlag ("col"); + tlo->SetRGB (col.Get(1), col.Get(2), col.Get(3)); + } + if (parseflags.GetDefineFlag ("transparent")) + tlo->SetTransparent (1); + } + | + TOK_BOUNDINGBOX '(' NUM ',' NUM ',' NUM ';' + NUM ',' NUM ',' NUM ')' + { + parsegeom->SetBoundingBox (Box<3> (Point<3> ($3, $5, $7), + Point<3> ($9, $11, $13))); + } + | + TOK_POINT '(' NUM ',' NUM ',' NUM ')' + { + parsegeom->AddUserPoint (Point<3> ($3, $5, $7)); + } + | + TOK_BOUNDARYCONDITION IDENTSOLID IDENTSOLID NUM + { + CSGeometry::BCModification bcm; + ARRAY<int> si; + + parsegeom->GetSolid($2)->GetSurfaceIndices(si); + + bcm.tlonr = -1; + int i; + for (i = 0; i < parsegeom->GetNTopLevelObjects(); i++) + if (strcmp (parsegeom->GetTopLevelObject(i)->GetSolid()->Name(), $3) == 0) + { + bcm.tlonr = i; + break; + } + + bcm.bcnr = int($4); + for (i = 0; i < si.Size(); i++) + { + bcm.si = si[i]; + parsegeom->bcmodifications.Append (bcm); + } + } + ; + + + + +flaglist: + { parseflags.DeleteFlags (); } + recflaglist + ; + +recflaglist: + /* empty */ + | flag recflaglist + ; + +flag: + '-' anyident + { parseflags.SetFlag ($2); } + | '-' anyident '=' anyident + { parseflags.SetFlag ($2, $4); } + | '-' anyident '=' NUM + { parseflags.SetFlag ($2, $4); } + | '-' anyident '=' numlistbrack + { parseflags.SetFlag ($2, doublearray); } + | '-' anyident '=' stringlistbrack + { parseflags.SetFlag ($2, stringarray); } + ; + + +numlistbrack: + '[' { doublearray.SetSize (0); } + numlist ']' + ; + +numlist: + NUM { doublearray.Append ($1); } + | numlist ',' NUM { doublearray.Append ($3); } + ; + +stringlistbrack: + '[' + { + int i; + for (i = 0; i < stringarray.Size(); i++) + delete stringarray[i]; + stringarray.SetSize (0); + } + stringlist ']' + ; + +stringlist: + anyident + { + stringarray.Append (new char[strlen($1)+1]); + strcpy (stringarray.Last(), $1); + } + + | stringlist ',' anyident + { + stringarray.Append (new char[strlen($3)+1]); + strcpy (stringarray.Last(), $3); + } + ; + + + + + +anyident: + IDENT { $$ = $1; } + | IDENTSOLID { $$ = $1; } +%% + + +int yyerror (char * s) +{ + cerr << s << " in line " << linenum << endl; + return 0; +} + diff --git a/contrib/Netgen/libsrc/csg/geoml.hpp b/contrib/Netgen/libsrc/csg/geoml.hpp new file mode 100644 index 0000000000..e7974ad206 --- /dev/null +++ b/contrib/Netgen/libsrc/csg/geoml.hpp @@ -0,0 +1,16 @@ +#ifndef FILE_GEOML +#define FILE_GEOML + +/* *************************************************************************/ +/* File: geoml.hh */ +/* Author: Joachim Schoeberl */ +/* Date: 21. Jun. 98 */ +/* *************************************************************************/ + +#include <geom/geom.hh> + +#include <geom/solid.hh> +#include <geom/algprim.hh> +#include <geom/adtree.hh> +#include <geom/csgeom.hh> +#endif diff --git a/contrib/Netgen/libsrc/csg/identify.cpp b/contrib/Netgen/libsrc/csg/identify.cpp new file mode 100644 index 0000000000..4622ee42bb --- /dev/null +++ b/contrib/Netgen/libsrc/csg/identify.cpp @@ -0,0 +1,1508 @@ +#include <mystdlib.h> +#include <myadt.hpp> + +#include <linalg.hpp> +#include <csg.hpp> +#include <meshing.hpp> + + +namespace netgen +{ +Identification :: Identification (int anr, const CSGeometry & ageom) + : geom(ageom), identfaces(10) +{ + nr = anr; +} + +Identification :: ~Identification () +{ + ; +} + + +ostream & operator<< (ostream & ost, Identification & ident) +{ + ident.Print (ost); + return ost; +} + + +/* +void Identification :: IdentifySpecialPoints (ARRAY<class SpecialPoint> & points) +{ + ; +} +*/ + + +int Identification :: +Identifyable (const SpecialPoint & sp1, const SpecialPoint & sp2) const +{ + cout << "Identification::Identifyable called for base-class" << endl; + return 0; +} + +int Identification :: +Identifyable (const Point<3> & p1, const Point<3> & sp2) const +{ + cout << "Identification::Identifyable called for base-class" << endl; + return 0; +} + + +int Identification :: +IdentifyableCandidate (const SpecialPoint & sp1) const +{ + return 1; +} + + +int Identification :: +ShortEdge (const SpecialPoint & sp1, const SpecialPoint & sp2) const +{ + return 0; +} + +int Identification :: GetIdentifiedPoint (class Mesh & mesh, int pi) +{ + cout << "Identification::GetIdentifiedPoint called for base-class" << endl; + return -1; +} + +void Identification :: IdentifyPoints (Mesh & mesh) +{ + cout << "Identification::IdentifyPoints called for base-class" << endl; + ; +} + +void Identification :: IdentifyFaces (class Mesh & mesh) +{ + cout << "Identification::IdentifyFaces called for base-class" << endl; + ; +} + +void Identification :: +BuildSurfaceElements (ARRAY<Segment> & segs, + Mesh & mesh, const Surface * surf) +{ + cout << "Identification::BuildSurfaceElements called for base-class" << endl; + ; +} + + +void Identification :: +BuildVolumeElements (ARRAY<class Element2d> & surfels, + class Mesh & mesh) +{ + ; +} + +void Identification :: +GetIdentifiedFaces (ARRAY<INDEX_2> & idfaces) const +{ + idfaces.SetSize(0); + for (int i = 1; i <= identfaces.GetNBags(); i++) + for (int j = 1; j <= identfaces.GetBagSize(i); j++) + { + INDEX_2 i2; + int val; + identfaces.GetData (i, j, i2, val); + idfaces.Append (i2); + } +} + + + + +PeriodicIdentification :: +PeriodicIdentification (int anr, + const CSGeometry & ageom, + const Surface * as1, + const Surface * as2) + : Identification(anr, ageom) +{ + s1 = as1; + s2 = as2; +} + +PeriodicIdentification :: ~PeriodicIdentification () +{ + ; +} + +/* +void PeriodicIdentification :: IdentifySpecialPoints +(ARRAY<class SpecialPoint> & points) +{ + int i, j; + int bestj; + double bestval, val; + + for (i = 1; i <= points.Size(); i++) + { + Point<3> p1 = points.Get(i).p; + Point<3> hp1 = p1; + s1->Project (hp1); + if (Dist (p1, hp1) > 1e-6) continue; + + Vec<3> n1; + s1->GetNormalVector (p1, n1); + n1 /= n1.Length(); + if ( fabs(n1 * points.Get(i).v) > 1e-3) + continue; + + bestval = 1e8; + bestj = 1; + for (j = 1; j <= points.Size(); j++) + { + Point<3> p2= points.Get(j).p; + Point<3> hp2 = p2; + s2->Project (hp2); + if (Dist (p2, hp2) > 1e-6) continue; + + Vec<3> n2; + s2->GetNormalVector (p2, n2); + n2 /= n2.Length(); + if ( fabs(n2 * points.Get(j).v) > 1e-3) + continue; + + + Vec<3> v(p1, p2); + double vl = v.Length(); + double cl = fabs (v*n1); + + val = 1 - cl*cl/(vl*vl); + + val += (points.Get(i).v - points.Get(j).v).Length(); + + if (val < bestval) + { + bestj = j; + bestval = val; + } + } + + (*testout) << "Identify Periodic special points: pi = " + << points.Get(i).p << ", vi = " << points.Get(i).v + << " pj = " << points.Get(bestj).p + << ", vj = " << points.Get(bestj).v + << " bestval = " << bestval << endl; + } +} +*/ + +int PeriodicIdentification :: +Identifyable (const SpecialPoint & sp1, const SpecialPoint & sp2) const +{ + int i; + double val; + + SpecialPoint hsp1 = sp1; + SpecialPoint hsp2 = sp2; + + for (i = 1; i <= 1; i++) + { + // Swap (hsp1, hsp2); + + if (!s1->PointOnSurface (hsp1.p)) + continue; + + Vec<3> n1; + 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; +} + +int PeriodicIdentification :: +Identifyable (const Point<3> & p1, const Point<3> & p2) const +{ + return (s1->PointOnSurface (p1) && + s2->PointOnSurface (p2)); +} + + + + +int PeriodicIdentification :: +GetIdentifiedPoint (class Mesh & mesh, int pi) +{ + const Surface * sold, *snew; + const Point<3> & p = mesh.Point (pi); + + if (s1->PointOnSurface (p)) + { + snew = s2; + } + else + { + if (s2->PointOnSurface (p)) + { + snew = s1; + } + else + { + cerr << "GetIdenfifiedPoint: Not possible" << endl; + exit (1); + } + } + + // project to other surface + Point<3> hp = p; + snew->Project (hp); + + int i; + int newpi = 0; + for (i = 1; i <= mesh.GetNP(); i++) + if (Dist2 (mesh.Point(i), hp) < 1e-12) + { + newpi = i; + break; + } + if (!newpi) + newpi = mesh.AddPoint (hp); + + if (snew == s2) + mesh.GetIdentifications().Add (pi, newpi, nr); + else + mesh.GetIdentifications().Add (newpi, pi, nr); + + /* + (*testout) << "Identify points(periodic), nr = " << nr << ": " << mesh.Point(pi) + << " and " << mesh.Point(newpi) + << ((snew == s2) ? "" : " inverse") + << endl; + */ + return newpi; +} + + +void PeriodicIdentification :: IdentifyPoints (class Mesh & mesh) +{ + int i, j; + for (i = 1; i <= mesh.GetNP(); i++) + { + Point<3> p = mesh.Point(i); + if (s1->PointOnSurface (p)) + { + Point<3> pp = p; + s2->Project (pp); + for (j = 1; j <= mesh.GetNP(); j++) + if (Dist2(mesh.Point(j), pp) < 1e-6) + { + mesh.GetIdentifications().Add (i, j, nr); + /* + (*testout) << "Identify points(periodic:), nr = " << nr << ": " + << mesh.Point(i) << " - " << mesh.Point(j) << endl; + */ + } + } + } +} + + +void PeriodicIdentification :: IdentifyFaces (class Mesh & mesh) +{ + int i, j, k, l; + int fi1, fi2, side; + for (i = 1; i <= mesh.GetNFD(); i++) + for (j = 1; j <= mesh.GetNFD(); j++) + { + int surfi = mesh.GetFaceDescriptor(i).SurfNr(); + int surfj = mesh.GetFaceDescriptor(j).SurfNr(); + if (surfi == surfj) + continue; + + if (geom.GetSurface (surfi) != s1 || + geom.GetSurface (surfj) != s2) + continue; + + int idok = 1; + + + // (*testout) << "check faces " << i << " and " << j << endl; + for (side = 1; side <= 2 && idok; side++) + { + if (side == 1) + { + fi1 = i; + fi2 = j; + } + else + { + fi1 = j; + fi2 = i; + } + + for (k = 1; k <= mesh.GetNSeg(); k++) + { + const Segment & seg1 = mesh.LineSegment(k); + if (seg1.si != fi1) + continue; + + int foundother = 0; + for (l = 1; l <= mesh.GetNSeg(); l++) + { + const Segment & seg2 = mesh.LineSegment(l); + if (seg2.si != fi2) + continue; + + // (*testout) << "seg1 = " << seg1.p1 << "-" << seg1.p2 << ", seg2 = " << seg2.p1 << "-" << seg2.p2; + + if (side == 1) + { + if (mesh.GetIdentifications().Get (seg1.p1, seg2.p1) && + mesh.GetIdentifications().Get (seg1.p2, seg2.p2)) + { + foundother = 1; + break; + } + + if (mesh.GetIdentifications().Get (seg1.p1, seg2.p2) && + mesh.GetIdentifications().Get (seg1.p2, seg2.p1)) + { + foundother = 1; + break; + } + } + else + { + if (mesh.GetIdentifications().Get (seg2.p1, seg1.p1) && + mesh.GetIdentifications().Get (seg2.p2, seg1.p2)) + { + foundother = 1; + break; + } + + if (mesh.GetIdentifications().Get (seg2.p1, seg1.p2) && + mesh.GetIdentifications().Get (seg2.p2, seg1.p1)) + { + foundother = 1; + break; + } + } + } + + if (!foundother) + { + idok = 0; + break; + } + } + } + + + if (idok) + { + // (*testout) << "Identify faces " << i << " and " << j << endl; + INDEX_2 fpair(i,j); + fpair.Sort(); + identfaces.Set (fpair, 1); + } + } +} + + + +void PeriodicIdentification :: +BuildSurfaceElements (ARRAY<Segment> & segs, + Mesh & mesh, const Surface * surf) +{ + int i1, i2; + int found = 0; + int i, j, k; + int fother; + + + int facei = segs.Get(1).si; + int surfnr = mesh.GetFaceDescriptor(facei).SurfNr(); + + + if (geom.GetSurface(surfnr) == s1 || + geom.GetSurface(surfnr) == s2) + { + // (*testout) << "surfs found !" << endl; + + for (i = 1; i <= mesh.GetNSE(); i++) + { + const Element2d & sel = mesh.SurfaceElement(i); + INDEX_2 fpair (facei, sel.GetIndex()); + fpair.Sort(); + if (identfaces.Used (fpair)) + { + found = 1; + fother = sel.GetIndex(); + + // copy element + Element2d newel(3); + newel.SetIndex (facei); + for (k = 1; k <= 3; k++) + { + newel.PNum(k) = + GetIdentifiedPoint (mesh, sel.PNum(k)); + } + + Vec<3> nt = Cross (Point<3> (mesh.Point (newel.PNum(2)))- + Point<3> (mesh.Point (newel.PNum(1))), + Point<3> (mesh.Point (newel.PNum(3)))- + Point<3> (mesh.Point (newel.PNum(1)))); + + Vec<3> nsurf; + 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; + 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"); + // eps_n = 1e-3; + eps_n = 1e-6; + + dom_surf_valid = 0; +} + +CloseSurfaceIdentification :: ~CloseSurfaceIdentification () +{ + ; +} + +void CloseSurfaceIdentification :: Print (ostream & ost) const +{ + ost << "CloseSurface Identifiaction, surfaces: " + << s1->Name() << " - " << s2->Name() << endl; + s1->Print (ost); + s2->Print (ost); + ost << endl; +} + + +void CloseSurfaceIdentification :: GetData (ostream & ost) const +{ + ost << "close surface " << s1->Name() << " " << s2->Name(); +} + + +/* +void CloseSurfaceIdentification :: IdentifySpecialPoints +(ARRAY<class SpecialPoint> & points) +{ + int i, j; + int bestj; + double bestval, val; + + for (i = 1; i <= points.Size(); i++) + { + Point<3> p1 = points.Get(i).p; + Vec<3> n1; + + if (!s1->PointOnSurface (p1)) + continue; + + s1->GetNormalVector (p1, n1); + n1 /= n1.Length(); + if ( fabs(n1 * points.Get(i).v) > 1e-3) + continue; + + bestval = 1e8; + bestj = 1; + for (j = 1; j <= points.Size(); j++) + { + Point<3> p2= points.Get(j).p; + if (!s2->PointOnSurface (p2)) + continue; + + Vec<3> n2; + s2->GetNormalVector (p2, n2); + n2 /= n2.Length(); + if ( fabs(n2 * points.Get(j).v) > 1e-3) + continue; + + + Vec<3> v(p1, p2); + double vl = v.Length(); + double cl = fabs (v*n1); + + val = 1 - cl*cl/(vl*vl); + + val += (points.Get(i).v - points.Get(j).v).Length(); + + if (val < bestval) + { + bestj = j; + bestval = val; + } + } + + (*testout) << "Identify close surfaces special points: pi = " + << points.Get(i).p << ", vi = " << points.Get(i).v + << " pj = " << points.Get(bestj).p + << ", vj = " << points.Get(bestj).v + << " bestval = " << bestval << endl; + } +} +*/ + +int CloseSurfaceIdentification :: +Identifyable (const SpecialPoint & sp1, const SpecialPoint & sp2) const +{ + + if (!dom_surf_valid) + { + const_cast<bool&> (dom_surf_valid) = 1; + ARRAY<int> & hsurf = const_cast<ARRAY<int>&> (domain_surfaces); + + if (domain) + { + BoxSphere<3> hbox (geom.BoundingBox()); + geom.GetIndependentSurfaceIndices (domain->GetSolid(), hbox, + hsurf); + } + else + { + hsurf.SetSize (geom.GetNSurf()); + for (int j = 0; j < hsurf.Size(); j++) + hsurf[j] = j; + } + } + + + + if (!s1->PointOnSurface (sp1.p)) + return 0; + + Vec<3> n1 = s1->GetNormalVector (sp1.p); + n1.Normalize(); + if ( fabs(n1 * sp1.v) > eps_n) + return 0; + + if (!s2->PointOnSurface(sp2.p)) + return 0; + + Vec<3> n2 = s2->GetNormalVector (sp2.p); + n2.Normalize(); + if ( fabs(n2 * sp2.v) > eps_n) + return 0; + + // must have joint surface + bool joint = 0; + // for (int j = 0; j < geom.GetNSurf(); j++) + for (int jj = 0; jj < domain_surfaces.Size(); jj++) + { + int j = domain_surfaces[jj]; + if (geom.GetSurface(j) -> PointOnSurface(sp1.p) && + geom.GetSurface(j) -> PointOnSurface(sp2.p) ) + { + Vec<3> hn1 = geom.GetSurface(j)->GetNormalVector (sp1.p); + Vec<3> hn2 = geom.GetSurface(j)->GetNormalVector (sp2.p); + + if (hn1 * hn2 > 0) + { + joint = 1; + break; + } + } + } + if (!joint) return 0; + + Vec<3> v = sp2.p - sp1.p; + double vl = v.Length(); + double cl = fabs (v*n1); + + if (cl > (1-eps_n*eps_n) * vl && (sp1.v - sp2.v).Length() < 0.1) + return 1; + + return 0; +} + +int CloseSurfaceIdentification :: +Identifyable (const Point<3> & p1, const Point<3> & p2) const +{ + return (s1->PointOnSurface (p1) && s2->PointOnSurface (p2)); +} + + + + +int CloseSurfaceIdentification :: +IdentifyableCandidate (const SpecialPoint & sp1) const +{ + if (s1->PointOnSurface (sp1.p)) + { + Vec<3> n1; + n1 = s1->GetNormalVector (sp1.p); + n1.Normalize(); + if ( fabs(n1 * sp1.v) > eps_n) + return 0; + return 1; + } + + if (s2->PointOnSurface (sp1.p)) + { + Vec<3> n1; + n1 = s2->GetNormalVector (sp1.p); + n1.Normalize(); + if ( fabs(n1 * sp1.v) > eps_n) + return 0; + return 1; + } + return 0; +} + + + +int CloseSurfaceIdentification :: +ShortEdge (const SpecialPoint & sp1, const SpecialPoint & sp2) const +{ + if ( (s1->PointOnSurface (sp1.p) && s2->PointOnSurface (sp2.p)) || + (s1->PointOnSurface (sp2.p) && s2->PointOnSurface (sp1.p)) ) + { + return 1; + } + return 0; +} + + + +int CloseSurfaceIdentification :: +GetIdentifiedPoint (class Mesh & mesh, int pi) +{ + const Surface * sold, *snew; + const Point<3> & p = mesh.Point (pi); + + ARRAY<int,PointIndex::BASE> identmap(mesh.GetNP()); + mesh.GetIdentifications().GetMap (nr, identmap); + if (identmap.Get(pi)) + return identmap.Get(pi); + + if (s1->PointOnSurface (p)) + { + snew = s2; + } + else + { + if (s2->PointOnSurface (p)) + { + snew = s1; + } + else + { + (*testout) << "GetIdenfifiedPoint: Not possible" << endl; + (*testout) << "p = " << p << endl; + (*testout) << "surf1: "; + s1->Print (*testout); + (*testout) << endl; + (*testout) << "surf2: "; + s2->Print (*testout); + (*testout) << endl; + + cerr << "GetIdenfifiedPoint: Not possible" << endl; + exit (1); + } + } + + // project to other surface + Point<3> hp = p; + snew->Project (hp); + + int i; + int newpi = 0; + for (i = 1; i <= mesh.GetNP(); i++) + if (Dist2 (mesh.Point(i), hp) < 1e-12) + // if (Dist2 (mesh.Point(i), hp) < 1 * Dist2 (hp, p)) + { + newpi = i; + break; + } + if (!newpi) + newpi = mesh.AddPoint (hp); + + if (snew == s2) + mesh.GetIdentifications().Add (pi, newpi, nr); + else + mesh.GetIdentifications().Add (newpi, pi, nr); + + /* + (*testout) << "Identify points(closesurface), nr = " << nr << ": " << mesh.Point(pi) + << " and " << mesh.Point(newpi) + << ((snew == s2) ? "" : " inverse") + << endl; + */ + return newpi; +} + + + + + +void CloseSurfaceIdentification :: IdentifyPoints (Mesh & mesh) +{ + int i, j; + int i1, i2; + + int np = mesh.GetNP(); + BitArray ons2(np); + ons2.Clear(); + for (i2 = 1; i2 <= np; i2++) + if (s2->PointOnSurface (mesh.Point(i2))) + ons2.Set (i2); + + for (i1 = 1; i1 <= np; i1++) + { + const Point<3> p1 = mesh.Point(i1); + if (s1->PointOnSurface (p1)) + { + int candi2 = 0; + double mindist = 1e10; + + Vec<3> n1; + n1 = s1->GetNormalVector (p1); + n1.Normalize(); + + for (i2 = 1; i2 <= np; i2++) + { + if (i2 == i1) + continue; + + const Point<3> p2 = mesh.Point(i2); + + if (!ons2.Test(i2)) + continue; + /* + if (!s2->PointOnSurface (p2)) + continue; + */ + Vec<3> n = p2 - p1; + n.Normalize(); + + + bool joint = 0; + for (int jj = 0; jj < domain_surfaces.Size(); jj++) + { + int j = domain_surfaces[jj]; + if (geom.GetSurface(j) -> PointOnSurface(p1) && + 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 (fabs (n * n1) > 0.9 && + Dist (p1, p2) < mindist) + { + candi2 = i2; + mindist = Dist (p1, p2); + } + } + + if (candi2) + { + // (*testout) << "identify points " << p1 << " - " << mesh.Point(candi2) << endl; + (*testout) << "Add Identification from CSI2, p1 = " + << mesh[PointIndex(i1)] << ", p2 = " + << mesh[PointIndex(candi2)] << endl; + + mesh.GetIdentifications().Add (i1, candi2, nr); + } + } + } +} + + + +void CloseSurfaceIdentification :: IdentifyFaces (class Mesh & mesh) +{ + int i, j, k, l; + int fi1, fi2, side; + + int s1rep, s2rep; + for (i = 0; i < geom.GetNSurf(); i++) + { + if (geom.GetSurface (i) == s1) + s1rep = geom.GetSurfaceClassRepresentant(i); + if (geom.GetSurface (i) == s2) + s2rep = geom.GetSurfaceClassRepresentant(i); + } + + for (i = 1; i <= mesh.GetNFD(); i++) + for (j = 1; j <= mesh.GetNFD(); j++) + { + int surfi = mesh.GetFaceDescriptor(i).SurfNr(); + int surfj = mesh.GetFaceDescriptor(j).SurfNr(); + if (surfi == surfj) + continue; + + if (s1rep != surfi || s2rep != surfj) + continue; + + /* + if (geom.GetSurface (surfi) != s1 || + geom.GetSurface (surfj) != s2) + continue; + */ + + int idok = 1; + + + // (*testout) << "check faces " << i << " and " << j << endl; + for (side = 1; side <= 2 && idok; side++) + { + if (side == 1) + { + fi1 = i; + fi2 = j; + } + else + { + fi1 = j; + fi2 = i; + } + + for (k = 1; k <= mesh.GetNSeg(); k++) + { + const Segment & seg1 = mesh.LineSegment(k); + if (seg1.si != fi1) + continue; + + int foundother = 0; + for (l = 1; l <= mesh.GetNSeg(); l++) + { + const Segment & seg2 = mesh.LineSegment(l); + if (seg2.si != fi2) + continue; + + // (*testout) << "seg1 = " << seg1.p1 << "-" << seg1.p2 << ", seg2 = " << seg2.p1 << "-" << seg2.p2; + + if (side == 1) + { + if (mesh.GetIdentifications().Get (seg1.p1, seg2.p1) && + mesh.GetIdentifications().Get (seg1.p2, seg2.p2)) + { + foundother = 1; + break; + } + + if (mesh.GetIdentifications().Get (seg1.p1, seg2.p2) && + mesh.GetIdentifications().Get (seg1.p2, seg2.p1)) + { + foundother = 1; + break; + } + } + else + { + if (mesh.GetIdentifications().Get (seg2.p1, seg1.p1) && + mesh.GetIdentifications().Get (seg2.p2, seg1.p2)) + { + foundother = 1; + break; + } + + if (mesh.GetIdentifications().Get (seg2.p1, seg1.p2) && + mesh.GetIdentifications().Get (seg2.p2, seg1.p1)) + { + foundother = 1; + break; + } + } + } + + if (!foundother) + { + idok = 0; + break; + } + } + } + + + if (idok) + { + // (*testout) << "Identify faces " << i << " and " << j << endl; + INDEX_2 fpair(i,j); + fpair.Sort(); + identfaces.Set (fpair, 1); + } + } +} + + + +void CloseSurfaceIdentification :: +BuildSurfaceElements (ARRAY<Segment> & segs, + Mesh & mesh, const Surface * surf) +{ + int i1, i2; + int found = 0, cntquads = 0; + int i, j, k; + + // insert quad layer: + for (i1 = 1; i1 <= segs.Size(); i1++) + for (i2 = 1; i2 < i1; i2++) + { + const Segment & s1 = segs.Get(i1); + const Segment & s2 = segs.Get(i2); + if ( (mesh.GetIdentifications().Get (s1.p1, s2.p2) == nr && + mesh.GetIdentifications().Get (s1.p2, s2.p1) == nr) || + (mesh.GetIdentifications().Get (s2.p1, s1.p2) == nr && + mesh.GetIdentifications().Get (s2.p2, s1.p1) == nr) + ) + { + Element2d el(4); + el.PNum(1) = s1.p1; + el.PNum(2) = s1.p2; + el.PNum(3) = s2.p1; + el.PNum(4) = s2.p2; + + Vec<3> n = Cross (Point<3> (mesh.Point(el.PNum(2)))- + Point<3> (mesh.Point(el.PNum(1))), + Point<3> (mesh.Point(el.PNum(4)))- + Point<3> (mesh.Point(el.PNum(1)))); + + Vec<3> ns; + 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)); + } + + mesh.AddSurfaceElement (el); + (*testout) << "add rect element: " + << mesh.Point (el.PNum(1)) << " - " + << mesh.Point (el.PNum(2)) << " - " + << mesh.Point (el.PNum(3)) << " - " + << mesh.Point (el.PNum(4)) << endl; + found = 1; + cntquads++; + } + } + + if (found) + { + (*mycout) << " insert quad layer of " << cntquads + << " elements at face " << segs.Get(1).si << endl; + segs.SetSize(0); + } + else + { + BuildSurfaceElements2 (segs, mesh, surf); + } + + /* + int fother; + int facei = segs.Get(1).si; + int surfnr = mesh.GetFaceDescriptor(facei).SurfNr(); + + int foundid = 0; + for (i = 1; i <= identfaces.GetNBags(); i++) + for (j = 1; j <= identfaces.GetBagSize(i); j++) + { + INDEX_2 i2; + int data; + identfaces.GetData (i, j, i2, data); + if (i2.I1() == facei || i2.I2() == facei) + foundid = 1; + } + + // (*testout) << "facei = " << facei << ", surfnr = " << surfnr << endl; + + if (foundid) + { + // (*testout) << "surfaces found" << endl; + // copy surface + for (i = 1; i <= mesh.GetNSE(); i++) + { + const Element2d & sel = mesh.SurfaceElement(i); + INDEX_2 fpair (facei, sel.GetIndex()); + fpair.Sort(); + if (identfaces.Used (fpair)) + { + found = 1; + fother = sel.GetIndex(); + + // copy element + Element2d newel(3); + newel.SetIndex (facei); + for (k = 1; k <= 3; k++) + { + newel.PNum(k) = + GetIdentifiedPoint (mesh, sel.PNum(k)); + // cout << "id-point = " << sel.PNum(k) << ", np = " << newel.PNum(k) << endl; + } + + Vec<3> nt = Cross (Vec<3> (mesh.Point (newel.PNum(1)), mesh.Point (newel.PNum(2))), + Vec<3> (mesh.Point (newel.PNum(1)), mesh.Point (newel.PNum(3)))); + Vec<3> nsurf; + 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; + } + + if (found) + segs.SetSize(0); + */ +} + + + + + + +void CloseSurfaceIdentification :: +BuildSurfaceElements2 (ARRAY<Segment> & segs, + Mesh & mesh, const Surface * surf) +{ + int i1, i2; + int found = 0, cntquads = 0; + int i, j, k; + + int fother; + int facei = segs.Get(1).si; + int surfnr = mesh.GetFaceDescriptor(facei).SurfNr(); + + int foundid = 0; + for (i = 1; i <= identfaces.GetNBags(); i++) + for (j = 1; j <= identfaces.GetBagSize(i); j++) + { + INDEX_2 i2; + int data; + identfaces.GetData (i, j, i2, data); + if (i2.I1() == facei || i2.I2() == facei) + foundid = 1; + } + + // (*testout) << "facei = " << facei << ", surfnr = " << surfnr << endl; + + /* + if (geom.GetSurface(surfnr) == s1 || + geom.GetSurface(surfnr) == s2) + */ + if (foundid) + { + // (*testout) << "surfaces found" << endl; + // copy surface + for (i = 1; i <= mesh.GetNSE(); i++) + { + const Element2d & sel = mesh.SurfaceElement(i); + INDEX_2 fpair (facei, sel.GetIndex()); + fpair.Sort(); + if (identfaces.Used (fpair)) + { + found = 1; + fother = sel.GetIndex(); + + // copy element + Element2d newel(3); + newel.SetIndex (facei); + for (k = 1; k <= 3; k++) + { + newel.PNum(k) = + GetIdentifiedPoint (mesh, sel.PNum(k)); + // cout << "id-point = " << sel.PNum(k) << ", np = " << newel.PNum(k) << endl; + } + + Vec<3> nt = Cross (Point<3> (mesh.Point (newel.PNum(2)))- + Point<3> (mesh.Point (newel.PNum(1))), + Point<3> (mesh.Point (newel.PNum(3)))- + Point<3> (mesh.Point (newel.PNum(1)))); + Vec<3> nsurf; + 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; + segs.SetSize(0); + } +} + + + + + + + + + + + + + + +void CloseSurfaceIdentification :: +BuildVolumeElements (ARRAY<class Element2d> & surfels, + class Mesh & mesh) +{ + ; +} + + + + + + + + + + + + + +/* ***************** Close Edges Identification ********** */ + + + +CloseEdgesIdentification :: +CloseEdgesIdentification (int anr, + const CSGeometry & ageom, + const Surface * afacet, + const Surface * as1, + const Surface * as2) + : Identification(anr, ageom) +{ + facet = afacet; + s1 = as1; + s2 = as2; +} + +CloseEdgesIdentification :: ~CloseEdgesIdentification () +{ + ; +} + +void CloseEdgesIdentification :: Print (ostream & ost) const +{ + ost << "CloseEdges Identifiaction, facet = " + << facet->Name() << ", surfaces: " + << s1->Name() << " - " << s2->Name() << endl; + facet->Print (ost); + s1->Print (ost); + s2->Print (ost); + ost << endl; +} + + +void CloseEdgesIdentification :: GetData (ostream & ost) const +{ + ost << "closeedges " << facet->Name() << " " + << s1->Name() << " " << s2->Name(); +} + + +/* +void CloseEdgesIdentification :: IdentifySpecialPoints +(ARRAY<class SpecialPoint> & points) +{ + int i, j; + int bestj; + double bestval, val; + + for (i = 1; i <= points.Size(); i++) + { + Point<3> p1 = points.Get(i).p; + Vec<3> n1; + + if (!s1->PointOnSurface (p1)) + continue; + + s1->GetNormalVector (p1, n1); + n1 /= n1.Length(); + if ( fabs(n1 * points.Get(i).v) > 1e-3) + continue; + + bestval = 1e8; + bestj = 1; + for (j = 1; j <= points.Size(); j++) + { + Point<3> p2= points.Get(j).p; + if (!s2->PointOnSurface (p2)) + continue; + + Vec<3> n2; + s2->GetNormalVector (p2, n2); + n2 /= n2.Length(); + if ( fabs(n2 * points.Get(j).v) > 1e-3) + continue; + + + Vec<3> v(p1, p2); + double vl = v.Length(); + double cl = fabs (v*n1); + + val = 1 - cl*cl/(vl*vl); + + val += (points.Get(i).v - points.Get(j).v).Length(); + + if (val < bestval) + { + bestj = j; + bestval = val; + } + } + + (*testout) << "Identify close surfaces special points: pi = " + << points.Get(i).p << ", vi = " << points.Get(i).v + << " pj = " << points.Get(bestj).p + << ", vj = " << points.Get(bestj).v + << " bestval = " << bestval << endl; + } +} +*/ + +int CloseEdgesIdentification :: +Identifyable (const SpecialPoint & sp1, const SpecialPoint & sp2) const +{ + int i; + double val; + + SpecialPoint hsp1 = sp1; + SpecialPoint hsp2 = sp2; + + for (i = 1; i <= 1; i++) + { + if (!s1->PointOnSurface (hsp1.p)) + continue; + + Vec<3> n1; + 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 i, j; + int i1, i2; + + int np = mesh.GetNP(); + for (i1 = 1; i1 <= np; i1++) + for (i2 = 1; i2 <= np; i2++) + { + if (i2 == i1) + continue; + + const Point<3> p1 = mesh.Point(i1); + const Point<3> p2 = mesh.Point(i2); + Point<3> pp1 = p1; + Point<3> pp2 = p2; + + s1->Project (pp1); + facet->Project (pp1); + s2->Project (pp2); + facet->Project (pp2); + + if (Dist (p1, pp1) > 1e-6 || Dist (p2, pp2) > 1e-6) + continue; + + Vec<3> n1, nf, t; + Vec<3> n = p2 - p1; + n.Normalize(); + + 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); + } + } +} + +void CloseEdgesIdentification :: +BuildSurfaceElements (ARRAY<Segment> & segs, + Mesh & mesh, const Surface * surf) +{ + int i1, i2; + int found = 0; + int i, j, k; + + if (surf != facet) + return; + + for (i1 = 1; i1 <= segs.Size(); i1++) + for (i2 = 1; i2 < i1; i2++) + { + const Segment & s1 = segs.Get(i1); + const Segment & s2 = segs.Get(i2); + if (mesh.GetIdentifications().Get (s1.p1, s2.p2) && + mesh.GetIdentifications().Get (s1.p2, s2.p1)) + { + Element2d el(4); + el.PNum(1) = s1.p1; + el.PNum(2) = s1.p2; + el.PNum(3) = s2.p2; + el.PNum(4) = s2.p1; + + Vec<3> n = Cross (Point<3> (mesh.Point(el.PNum(2)))- + Point<3> (mesh.Point(el.PNum(1))), + Point<3> (mesh.Point(el.PNum(3)))- + Point<3> (mesh.Point(el.PNum(1)))); + Vec<3> ns; + ns = surf->GetNormalVector (mesh.Point(el.PNum(1))); + (*testout) << "n = " << n << " ns = " << ns << endl; + if (n * ns < 0) + { + (*testout) << "Swap the quad" << endl; + Swap (el.PNum(1), el.PNum(2)); + Swap (el.PNum(3), el.PNum(4)); + } + + + Swap (el.PNum(3), el.PNum(4)); + mesh.AddSurfaceElement (el); + (*testout) << "add rect element: " + << mesh.Point (el.PNum(1)) << " - " + << mesh.Point (el.PNum(2)) << " - " + << mesh.Point (el.PNum(3)) << " - " + << mesh.Point (el.PNum(4)) << endl; + found = 1; + } + } + + if (found) + segs.SetSize(0); +} + +} diff --git a/contrib/Netgen/libsrc/csg/identify.hpp b/contrib/Netgen/libsrc/csg/identify.hpp new file mode 100644 index 0000000000..16e371b200 --- /dev/null +++ b/contrib/Netgen/libsrc/csg/identify.hpp @@ -0,0 +1,180 @@ + +#ifndef FILE_IDENTIFY +#define FILE_IDENTIFY + +/**************************************************************************/ +/* File: identify.hh */ +/* Author: Joachim Schoeberl */ +/* Date: 1. Aug. 99 */ +/**************************************************************************/ + +/** + Identify surfaces for periodic b.c. or + thin domains +*/ + + +class SpecialPoint; +class Identification +{ +protected: + const CSGeometry & geom; + // identified faces, index sorted + INDEX_2_HASHTABLE<int> identfaces; + int nr; + +public: + Identification (int anr, const CSGeometry & ageom); + virtual ~Identification (); + virtual void Print (ostream & ost) const = 0; + virtual void GetData (ostream & ost) const = 0; + + /// obsolete + // virtual void IdentifySpecialPoints (ARRAY<class SpecialPoint> & points); + + /// can identify both special points (fixed direction) + /// (identified points, same tangent) + virtual int Identifyable (const SpecialPoint & sp1, const SpecialPoint & sp2) const; + /// + virtual int Identifyable (const Point<3> & p1, const Point<3> & sp2) const; + /// is it possible to identify sp1 with some other ? + virtual int IdentifyableCandidate (const SpecialPoint & sp1) const; + + /// are points (if connected) by a short edge (direction anyhow) ? + virtual int ShortEdge (const SpecialPoint & sp1, const SpecialPoint & sp2) const; + + /// add entries in mesh identification tables + virtual void IdentifyPoints (class Mesh & mesh); + + /// add entries to identified faces (based on segment infos) + virtual void IdentifyFaces (class Mesh & mesh); + + /// get point on other surface, add entry in mesh identifications + virtual int GetIdentifiedPoint (class Mesh & mesh, int pi1); + + /// copy surfaces, or fill rectangles + virtual void BuildSurfaceElements (ARRAY<class Segment> & segs, + class Mesh & mesh, + const Surface * surf); + + /// insert volume elements in thin layers + virtual void BuildVolumeElements (ARRAY<class Element2d> & surfels, + class Mesh & mesh); + + /// get list of identified faces + virtual void GetIdentifiedFaces (ARRAY<INDEX_2> & idfaces) const; + + friend ostream & operator<< (ostream & ost, Identification & ident); +}; + + +class PeriodicIdentification : public Identification +{ + const Surface * s1; + const Surface * s2; +public: + PeriodicIdentification (int anr, + const CSGeometry & ageom, + const Surface * as1, + const Surface * as2); + virtual ~PeriodicIdentification (); + virtual void Print (ostream & ost) const; + virtual void GetData (ostream & ost) const; + + + // virtual void IdentifySpecialPoints (ARRAY<class SpecialPoint> & points); + virtual int Identifyable (const SpecialPoint & sp1, const SpecialPoint & sp2) const; + virtual int Identifyable (const Point<3> & p1, const Point<3> & sp2) const; + virtual int GetIdentifiedPoint (class Mesh & mesh, int pi1); + virtual void IdentifyPoints (class Mesh & mesh); + virtual void IdentifyFaces (class Mesh & mesh); + virtual void BuildSurfaceElements (ARRAY<class Segment> & segs, + class Mesh & mesh, + const Surface * surf); +}; + + +/// +class TopLevelObject; +class CloseSurfaceIdentification : public Identification +{ + const Surface * s1; + const Surface * s2; + const TopLevelObject * domain; + /// number of refinement levels (in Z-refinement) + int ref_levels; + /// number of refinement levels for layer next to s1 (in Z-refinement) + int ref_levels_s1; + /// number of refinement levels for layer next to s2 (in Z-refinement) + int ref_levels_s2; + /// + double eps_n; + ARRAY<double> slices; + /// used only for domain-local identification: + ARRAY<int> domain_surfaces; + /// + bool dom_surf_valid; +public: + CloseSurfaceIdentification (int anr, + const CSGeometry & ageom, + const Surface * as1, + const Surface * as2, + const TopLevelObject * adomain, + const Flags & flags); + virtual ~CloseSurfaceIdentification (); + + virtual void Print (ostream & ost) const; + virtual void GetData (ostream & ost) const; + + + // virtual void IdentifySpecialPoints (ARRAY<class SpecialPoint> & points); + virtual int Identifyable (const SpecialPoint & sp1, const SpecialPoint & sp2) const; + virtual int Identifyable (const Point<3> & p1, const Point<3> & sp2) const; + virtual int IdentifyableCandidate (const SpecialPoint & sp1) const; + virtual int ShortEdge (const SpecialPoint & sp1, const SpecialPoint & sp2) const; + virtual int GetIdentifiedPoint (class Mesh & mesh, int pi1); + const ARRAY<double> & GetSlices () const { return slices; } + virtual void IdentifyPoints (class Mesh & mesh); + virtual void IdentifyFaces (class Mesh & mesh); + virtual void BuildSurfaceElements (ARRAY<class Segment> & segs, + class Mesh & mesh, + const Surface * surf); + void BuildSurfaceElements2 (ARRAY<class Segment> & segs, + class Mesh & mesh, + const Surface * surf); + + virtual void BuildVolumeElements (ARRAY<class Element2d> & surfels, + class Mesh & mesh); + + int RefLevels () const { return ref_levels; } + int RefLevels1 () const { return ref_levels_s1; } + int RefLevels2 () const { return ref_levels_s2; } +}; + + +class CloseEdgesIdentification : public Identification +{ + const Surface * facet; + const Surface * s1; + const Surface * s2; +public: + CloseEdgesIdentification (int anr, + const CSGeometry & ageom, + const Surface * afacet, + const Surface * as1, + const Surface * as2); + virtual ~CloseEdgesIdentification (); + virtual void Print (ostream & ost) const; + virtual void GetData (ostream & ost) const; + + // virtual void IdentifySpecialPoints (ARRAY<class SpecialPoint> & points); + virtual int Identifyable (const SpecialPoint & sp1, const SpecialPoint & sp2) const; + + + virtual void IdentifyPoints (class Mesh & mesh); + virtual void BuildSurfaceElements (ARRAY<class Segment> & segs, + class Mesh & mesh, + const Surface * surf); +}; + +#endif diff --git a/contrib/Netgen/libsrc/csg/lex.yy.cpp b/contrib/Netgen/libsrc/csg/lex.yy.cpp new file mode 100644 index 0000000000..e5c4e6f614 --- /dev/null +++ b/contrib/Netgen/libsrc/csg/lex.yy.cpp @@ -0,0 +1,1834 @@ +/* A lexical scanner generated by flex */ + +/* Scanner skeleton version: + * $Header: /cvsroot/gmsh/contrib/Netgen/libsrc/csg/lex.yy.cpp,v 1.1 2005-09-21 17:29:38 geuzaine Exp $ + */ + +#define FLEX_SCANNER +#define YY_FLEX_MAJOR_VERSION 2 +#define YY_FLEX_MINOR_VERSION 5 + + + +/* cfront 1.2 defines "c_plusplus" instead of "__cplusplus" */ +#ifdef c_plusplus +#ifndef __cplusplus +#define __cplusplus +#endif +#endif + + +#ifdef __cplusplus + +#include <stdlib.h> +#include <iostream.h> +#include <unistd.h> + +/* Use prototypes in function declarations. */ +#define YY_USE_PROTOS + +/* The "const" storage-class-modifier is valid. */ +#define YY_USE_CONST + +#else /* ! __cplusplus */ + +#if __STDC__ + +#define YY_USE_PROTOS +#define YY_USE_CONST + +#endif /* __STDC__ */ +#endif /* ! __cplusplus */ + +#ifdef __TURBOC__ + #pragma warn -rch + #pragma warn -use +#include <io.h> +#include <stdlib.h> +#define YY_USE_CONST +#define YY_USE_PROTOS +#endif + +#ifdef YY_USE_CONST +#define yyconst const +#else +#define yyconst +#endif + + +#ifdef YY_USE_PROTOS +#define YY_PROTO(proto) proto +#else +#define YY_PROTO(proto) () +#endif + +/* Returned upon end-of-file. */ +#define YY_NULL 0 + +/* Promotes a possibly negative, possibly signed char to an unsigned + * integer for use as an array index. If the signed char is negative, + * we want to instead treat it as an 8-bit unsigned char, hence the + * double cast. + */ +#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c) + +/* Enter a start condition. This macro really ought to take a parameter, + * but we do it the disgusting crufty way forced on us by the ()-less + * definition of BEGIN. + */ +#define BEGIN yy_start = 1 + 2 * + +/* Translate the current start state into a value that can be later handed + * to BEGIN to return to the state. The YYSTATE alias is for lex + * compatibility. + */ +#define YY_START ((yy_start - 1) / 2) +#define YYSTATE YY_START + +/* Action number for EOF rule of a given start state. */ +#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1) + +/* Special action meaning "start processing a new file". */ +#define YY_NEW_FILE yyrestart( yyin ) + +#define YY_END_OF_BUFFER_CHAR 0 + +/* Size of default input buffer. */ +#define YY_BUF_SIZE 16384 + +typedef struct yy_buffer_state *YY_BUFFER_STATE; + +extern int yyleng; + +#define EOB_ACT_CONTINUE_SCAN 0 +#define EOB_ACT_END_OF_FILE 1 +#define EOB_ACT_LAST_MATCH 2 + +/* The funky do-while in the following #define is used to turn the definition + * int a single C statement (which needs a semi-colon terminator). This + * avoids problems with code like: + * + * if ( condition_holds ) + * yyless( 5 ); + * else + * do_something_else(); + * + * Prior to using the do-while the compiler would get upset at the + * "else" because it interpreted the "if" statement as being all + * done when it reached the ';' after the yyless() call. + */ + +/* Return all but the first 'n' matched characters back to the input stream. */ + +#define yyless(n) \ + do \ + { \ + /* Undo effects of setting up yytext. */ \ + *yy_cp = yy_hold_char; \ + YY_RESTORE_YY_MORE_OFFSET \ + yy_c_buf_p = yy_cp = yy_bp + n - YY_MORE_ADJ; \ + YY_DO_BEFORE_ACTION; /* set up yytext again */ \ + } \ + while ( 0 ) + +#define unput(c) yyunput( c, yytext_ptr ) + +/* The following is because we cannot portably get our hands on size_t + * (without autoconf's help, which isn't available because we want + * flex-generated scanners to compile on their own). + */ +typedef unsigned int yy_size_t; + + +struct yy_buffer_state + { + istream* yy_input_file; + + char *yy_ch_buf; /* input buffer */ + char *yy_buf_pos; /* current position in input buffer */ + + /* Size of input buffer in bytes, not including room for EOB + * characters. + */ + yy_size_t yy_buf_size; + + /* Number of characters read into yy_ch_buf, not including EOB + * characters. + */ + int yy_n_chars; + + /* Whether we "own" the buffer - i.e., we know we created it, + * and can realloc() it to grow it, and should free() it to + * delete it. + */ + int yy_is_our_buffer; + + /* Whether this is an "interactive" input source; if so, and + * if we're using stdio for input, then we want to use getc() + * instead of fread(), to make sure we stop fetching input after + * each newline. + */ + int yy_is_interactive; + + /* Whether we're considered to be at the beginning of a line. + * If so, '^' rules will be active on the next match, otherwise + * not. + */ + int yy_at_bol; + + /* Whether to try to fill the input buffer when we reach the + * end of it. + */ + int yy_fill_buffer; + + int yy_buffer_status; +#define YY_BUFFER_NEW 0 +#define YY_BUFFER_NORMAL 1 + /* When an EOF's been seen but there's still some text to process + * then we mark the buffer as YY_EOF_PENDING, to indicate that we + * shouldn't try reading from the input source any more. We might + * still have a bunch of tokens to match, though, because of + * possible backing-up. + * + * When we actually see the EOF, we change the status to "new" + * (via yyrestart()), so that the user can continue scanning by + * just pointing yyin at a new input file. + */ +#define YY_BUFFER_EOF_PENDING 2 + }; + + +/* We provide macros for accessing buffer states in case in the + * future we want to put the buffer states in a more general + * "scanner state". + */ +#define YY_CURRENT_BUFFER yy_current_buffer + + + +static void *yy_flex_alloc YY_PROTO(( yy_size_t )); +static void *yy_flex_realloc YY_PROTO(( void *, yy_size_t )); +static void yy_flex_free YY_PROTO(( void * )); + +#define yy_new_buffer yy_create_buffer + +#define yy_set_interactive(is_interactive) \ + { \ + if ( ! yy_current_buffer ) \ + yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); \ + yy_current_buffer->yy_is_interactive = is_interactive; \ + } + +#define yy_set_bol(at_bol) \ + { \ + if ( ! yy_current_buffer ) \ + yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); \ + yy_current_buffer->yy_at_bol = at_bol; \ + } + +#define YY_AT_BOL() (yy_current_buffer->yy_at_bol) + + +#define FLEX_DEBUG +typedef unsigned char YY_CHAR; +#define yytext_ptr yytext +#define YY_INTERACTIVE + +#define FLEX_DEBUG + +#include <FlexLexer.h> + + +/* Done after the current pattern has been matched and before the + * corresponding action - sets up yytext. + */ +#define YY_DO_BEFORE_ACTION \ + yytext_ptr = yy_bp; \ + yyleng = (int) (yy_cp - yy_bp); \ + yy_hold_char = *yy_cp; \ + *yy_cp = '\0'; \ + yy_c_buf_p = yy_cp; + +#define YY_NUM_RULES 37 +#define YY_END_OF_BUFFER 38 +static yyconst short int yy_accept[222] = + { 0, + 0, 0, 0, 0, 0, 0, 38, 33, 32, 34, + 33, 33, 33, 30, 31, 31, 31, 31, 31, 31, + 31, 31, 31, 31, 31, 31, 31, 31, 37, 0, + 36, 0, 0, 30, 30, 30, 0, 31, 31, 31, + 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, + 5, 31, 31, 31, 31, 31, 31, 31, 31, 31, + 31, 31, 0, 35, 0, 0, 30, 31, 4, 31, + 31, 31, 31, 31, 31, 31, 31, 6, 31, 31, + 31, 31, 31, 31, 31, 31, 31, 31, 3, 31, + 31, 0, 30, 31, 31, 31, 13, 31, 22, 31, + + 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, + 31, 31, 31, 31, 16, 31, 31, 31, 31, 31, + 31, 31, 31, 31, 14, 15, 23, 31, 31, 31, + 31, 2, 31, 31, 31, 31, 31, 31, 31, 31, + 17, 31, 31, 31, 31, 31, 31, 31, 9, 31, + 11, 31, 31, 31, 31, 31, 31, 31, 31, 31, + 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, + 31, 31, 12, 24, 31, 31, 31, 27, 31, 31, + 21, 31, 31, 31, 31, 31, 31, 31, 31, 31, + 31, 31, 7, 31, 31, 31, 26, 31, 31, 31, + + 18, 19, 20, 1, 31, 29, 31, 10, 31, 31, + 31, 31, 31, 25, 31, 31, 8, 31, 31, 28, + 0 + } ; + +static yyconst int yy_ec[256] = + { 0, + 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 2, 1, 1, 4, 1, 1, 1, 1, 1, + 1, 1, 5, 1, 5, 6, 1, 7, 7, 7, + 8, 7, 7, 7, 7, 7, 7, 1, 1, 1, + 1, 1, 1, 1, 9, 9, 9, 9, 10, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 1, 1, 1, 1, 1, 1, 11, 12, 13, 14, + + 15, 16, 17, 18, 19, 9, 20, 21, 22, 23, + 24, 25, 9, 26, 27, 28, 29, 30, 9, 31, + 32, 9, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1 + } ; + +static yyconst int yy_meta[33] = + { 0, + 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2 + } ; + +static yyconst short int yy_base[226] = + { 0, + 0, 0, 0, 0, 0, 0, 77, 706, 706, 706, + 30, 29, 31, 34, 38, 40, 43, 61, 45, 47, + 50, 58, 64, 66, 87, 76, 105, 124, 706, 67, + 706, 57, 68, 0, 71, 89, 98, 82, 102, 108, + 112, 110, 114, 120, 126, 129, 133, 144, 141, 147, + 150, 153, 156, 161, 158, 163, 166, 169, 176, 178, + 185, 191, 53, 706, 199, 193, 201, 203, 205, 207, + 209, 212, 214, 216, 221, 218, 230, 232, 235, 237, + 240, 242, 244, 247, 253, 260, 262, 265, 267, 271, + 275, 277, 279, 281, 284, 288, 292, 294, 297, 299, + + 301, 303, 306, 308, 311, 313, 316, 318, 330, 332, + 334, 338, 340, 342, 346, 348, 351, 357, 368, 360, + 370, 372, 378, 380, 384, 388, 394, 396, 398, 400, + 402, 405, 409, 411, 414, 421, 423, 426, 428, 430, + 434, 436, 441, 443, 446, 448, 452, 454, 456, 463, + 468, 470, 472, 476, 478, 480, 485, 491, 482, 493, + 495, 497, 502, 505, 511, 515, 517, 519, 521, 528, + 531, 535, 540, 542, 545, 547, 550, 552, 554, 557, + 559, 561, 564, 566, 572, 575, 577, 579, 584, 586, + 590, 592, 596, 602, 610, 612, 614, 616, 619, 623, + + 628, 630, 632, 634, 638, 640, 642, 646, 648, 653, + 655, 657, 659, 661, 663, 667, 669, 672, 676, 681, + 706, 699, 701, 41, 703 + } ; + +static yyconst short int yy_def[226] = + { 0, + 221, 1, 222, 222, 222, 222, 221, 221, 221, 221, + 223, 221, 221, 221, 224, 224, 224, 224, 224, 224, + 224, 224, 224, 224, 224, 224, 224, 224, 221, 223, + 221, 225, 221, 14, 221, 221, 221, 224, 224, 224, + 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, + 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, + 224, 224, 225, 221, 221, 221, 221, 224, 224, 224, + 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, + 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, + 224, 221, 221, 224, 224, 224, 224, 224, 224, 224, + + 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, + 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, + 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, + 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, + 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, + 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, + 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, + 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, + 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, + 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, + + 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, + 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, + 0, 221, 221, 221, 221 + } ; + +static yyconst short int yy_nxt[739] = + { 0, + 8, 9, 10, 11, 12, 13, 14, 14, 15, 15, + 16, 17, 18, 15, 19, 15, 20, 15, 21, 15, + 15, 22, 23, 24, 25, 26, 27, 28, 15, 15, + 15, 15, 31, 32, 33, 34, 34, 35, 35, 36, + 34, 34, 39, 37, 38, 38, 38, 38, 37, 38, + 38, 38, 38, 38, 38, 64, 38, 38, 46, 64, + 40, 47, 41, 48, 38, 38, 42, 38, 38, 31, + 38, 38, 38, 38, 35, 35, 221, 35, 35, 221, + 65, 43, 38, 38, 44, 65, 49, 50, 38, 38, + 55, 51, 45, 38, 38, 35, 35, 221, 37, 56, + + 221, 52, 66, 37, 67, 67, 221, 53, 38, 38, + 54, 38, 38, 221, 38, 38, 38, 38, 38, 38, + 38, 38, 221, 57, 68, 69, 38, 38, 58, 59, + 38, 38, 38, 38, 221, 38, 38, 71, 70, 38, + 38, 221, 72, 221, 60, 74, 73, 38, 38, 61, + 38, 38, 62, 38, 38, 75, 38, 38, 76, 38, + 38, 77, 38, 38, 38, 38, 81, 38, 38, 38, + 38, 221, 38, 38, 78, 38, 38, 79, 80, 82, + 221, 83, 38, 38, 38, 38, 221, 84, 86, 87, + 85, 38, 38, 88, 221, 90, 221, 38, 38, 67, + + 67, 89, 91, 92, 221, 93, 93, 67, 67, 38, + 38, 38, 38, 38, 38, 38, 38, 94, 38, 38, + 38, 38, 38, 38, 38, 38, 97, 38, 38, 95, + 99, 221, 98, 100, 221, 96, 38, 38, 38, 38, + 101, 38, 38, 38, 38, 221, 38, 38, 38, 38, + 38, 38, 103, 38, 38, 104, 221, 102, 105, 38, + 38, 221, 106, 110, 107, 221, 38, 38, 38, 38, + 109, 38, 38, 38, 38, 108, 111, 38, 38, 113, + 112, 38, 38, 93, 93, 93, 93, 38, 38, 115, + 38, 38, 116, 114, 38, 38, 221, 117, 38, 38, + + 38, 38, 118, 38, 38, 38, 38, 38, 38, 38, + 38, 221, 38, 38, 38, 38, 119, 38, 38, 38, + 38, 122, 38, 38, 38, 38, 221, 126, 121, 123, + 120, 124, 221, 125, 221, 128, 38, 38, 38, 38, + 38, 38, 221, 127, 38, 38, 38, 38, 38, 38, + 129, 132, 38, 38, 38, 38, 221, 38, 38, 130, + 221, 136, 131, 38, 38, 133, 38, 38, 134, 137, + 221, 138, 221, 135, 38, 38, 38, 38, 38, 38, + 141, 140, 221, 139, 38, 38, 38, 38, 142, 145, + 38, 38, 221, 146, 38, 38, 221, 143, 221, 144, + + 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, + 147, 38, 38, 221, 149, 38, 38, 38, 38, 221, + 38, 38, 150, 151, 153, 221, 148, 38, 38, 38, + 38, 152, 38, 38, 38, 38, 38, 38, 221, 156, + 38, 38, 38, 38, 158, 155, 154, 38, 38, 38, + 38, 159, 38, 38, 38, 38, 157, 221, 38, 38, + 38, 38, 38, 38, 160, 164, 163, 221, 161, 38, + 38, 162, 221, 166, 38, 38, 38, 38, 38, 38, + 167, 165, 38, 38, 38, 38, 38, 38, 38, 38, + 168, 38, 38, 221, 170, 221, 171, 38, 38, 38, + + 38, 38, 38, 38, 38, 176, 221, 169, 38, 38, + 172, 38, 38, 174, 178, 177, 173, 38, 38, 221, + 175, 38, 38, 38, 38, 38, 38, 38, 38, 180, + 179, 183, 221, 184, 38, 38, 221, 38, 38, 185, + 181, 38, 38, 221, 182, 186, 38, 38, 38, 38, + 187, 38, 38, 38, 38, 188, 38, 38, 38, 38, + 38, 38, 190, 38, 38, 38, 38, 38, 38, 189, + 38, 194, 38, 38, 221, 193, 221, 191, 38, 38, + 192, 38, 38, 38, 38, 38, 38, 198, 221, 195, + 38, 38, 38, 38, 221, 196, 38, 38, 38, 38, + + 221, 197, 38, 38, 221, 201, 199, 221, 38, 38, + 200, 221, 202, 221, 203, 204, 38, 38, 38, 38, + 38, 38, 38, 38, 221, 38, 38, 221, 207, 38, + 38, 221, 205, 208, 38, 38, 38, 38, 38, 38, + 38, 38, 206, 209, 38, 38, 38, 38, 38, 38, + 221, 210, 38, 38, 38, 38, 211, 221, 212, 38, + 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, + 38, 213, 221, 38, 38, 38, 38, 217, 38, 38, + 221, 214, 38, 38, 215, 218, 216, 38, 38, 221, + 221, 221, 221, 221, 221, 219, 221, 221, 220, 29, + + 29, 30, 30, 63, 63, 7, 221, 221, 221, 221, + 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, + 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, + 221, 221, 221, 221, 221, 221, 221, 221 + } ; + +static yyconst short int yy_chk[739] = + { 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 11, 11, 12, 12, 12, 13, 13, 14, + 14, 14, 224, 14, 15, 15, 16, 16, 14, 17, + 17, 19, 19, 20, 20, 63, 21, 21, 19, 32, + 16, 20, 16, 21, 22, 22, 17, 18, 18, 30, + 23, 23, 24, 24, 33, 33, 7, 35, 35, 0, + 35, 18, 26, 26, 18, 35, 22, 23, 38, 38, + 26, 24, 18, 25, 25, 36, 36, 0, 36, 26, + + 0, 25, 37, 36, 37, 37, 0, 25, 39, 39, + 25, 27, 27, 0, 40, 40, 42, 42, 41, 41, + 43, 43, 0, 27, 40, 41, 44, 44, 27, 27, + 28, 28, 45, 45, 0, 46, 46, 43, 42, 47, + 47, 0, 44, 0, 28, 46, 45, 49, 49, 28, + 48, 48, 28, 50, 50, 47, 51, 51, 48, 52, + 52, 49, 53, 53, 55, 55, 53, 54, 54, 56, + 56, 0, 57, 57, 50, 58, 58, 51, 52, 54, + 0, 54, 59, 59, 60, 60, 0, 55, 57, 58, + 56, 61, 61, 59, 0, 61, 0, 62, 62, 66, + + 66, 60, 62, 65, 0, 65, 65, 67, 67, 68, + 68, 69, 69, 70, 70, 71, 71, 68, 72, 72, + 73, 73, 74, 74, 76, 76, 72, 75, 75, 70, + 74, 0, 73, 75, 0, 71, 77, 77, 78, 78, + 76, 79, 79, 80, 80, 0, 81, 81, 82, 82, + 83, 83, 79, 84, 84, 80, 0, 77, 81, 85, + 85, 0, 81, 85, 82, 0, 86, 86, 87, 87, + 84, 88, 88, 89, 89, 83, 86, 90, 90, 88, + 87, 91, 91, 92, 92, 93, 93, 94, 94, 91, + 95, 95, 94, 90, 96, 96, 0, 95, 97, 97, + + 98, 98, 96, 99, 99, 100, 100, 101, 101, 102, + 102, 0, 103, 103, 104, 104, 98, 105, 105, 106, + 106, 102, 107, 107, 108, 108, 0, 106, 101, 103, + 100, 104, 0, 105, 0, 108, 109, 109, 110, 110, + 111, 111, 0, 107, 112, 112, 113, 113, 114, 114, + 109, 112, 115, 115, 116, 116, 0, 117, 117, 110, + 0, 117, 111, 118, 118, 113, 120, 120, 114, 117, + 0, 118, 0, 116, 119, 119, 121, 121, 122, 122, + 120, 119, 0, 118, 123, 123, 124, 124, 121, 123, + 125, 125, 0, 124, 126, 126, 0, 122, 0, 122, + + 127, 127, 128, 128, 129, 129, 130, 130, 131, 131, + 128, 132, 132, 0, 130, 133, 133, 134, 134, 0, + 135, 135, 131, 133, 135, 0, 129, 136, 136, 137, + 137, 134, 138, 138, 139, 139, 140, 140, 0, 138, + 141, 141, 142, 142, 140, 137, 136, 143, 143, 144, + 144, 142, 145, 145, 146, 146, 139, 0, 147, 147, + 148, 148, 149, 149, 143, 147, 146, 0, 144, 150, + 150, 145, 0, 150, 151, 151, 152, 152, 153, 153, + 152, 148, 154, 154, 155, 155, 156, 156, 159, 159, + 153, 157, 157, 0, 155, 0, 156, 158, 158, 160, + + 160, 161, 161, 162, 162, 161, 0, 154, 163, 163, + 157, 164, 164, 159, 163, 162, 158, 165, 165, 0, + 160, 166, 166, 167, 167, 168, 168, 169, 169, 165, + 164, 168, 0, 169, 170, 170, 0, 171, 171, 170, + 166, 172, 172, 0, 167, 171, 173, 173, 174, 174, + 172, 175, 175, 176, 176, 175, 177, 177, 178, 178, + 179, 179, 177, 180, 180, 181, 181, 182, 182, 176, + 183, 183, 184, 184, 0, 182, 0, 179, 185, 185, + 180, 186, 186, 187, 187, 188, 188, 187, 0, 184, + 189, 189, 190, 190, 0, 185, 191, 191, 192, 192, + + 0, 186, 193, 193, 0, 190, 188, 0, 194, 194, + 189, 0, 191, 0, 192, 194, 195, 195, 196, 196, + 197, 197, 198, 198, 0, 199, 199, 0, 198, 200, + 200, 0, 195, 199, 201, 201, 202, 202, 203, 203, + 204, 204, 196, 200, 205, 205, 206, 206, 207, 207, + 0, 205, 208, 208, 209, 209, 207, 0, 209, 210, + 210, 211, 211, 212, 212, 213, 213, 214, 214, 215, + 215, 210, 0, 216, 216, 217, 217, 215, 218, 218, + 0, 211, 219, 219, 212, 216, 213, 220, 220, 0, + 0, 0, 0, 0, 0, 218, 0, 0, 219, 222, + + 222, 223, 223, 225, 225, 221, 221, 221, 221, 221, + 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, + 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, + 221, 221, 221, 221, 221, 221, 221, 221 + } ; + +static yyconst short int yy_rule_linenum[37] = + { 0, + 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, + 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, + 54, 55, 56, 58, 59, 60, 61, 62, 63, 65, + 66, 75, 76, 77, 78, 79 + } ; + +/* The intent behind this definition is that it'll catch + * any uses of REJECT which flex missed. + */ +#define REJECT reject_used_but_not_detected +#define yymore() yymore_used_but_not_detected +#define YY_MORE_ADJ 0 +#define YY_RESTORE_YY_MORE_OFFSET +#line 1 "geometry.ll" +#define INITIAL 0 +#line 2 "geometry.ll" +#include <mystdlib.h> +#include <myadt.hpp> + +#include <linalg.hpp> +#include <csg.hpp> + + + + +// extern SYMBOLTABLE<Solid*> solids; +namespace netgen { +extern CSGeometry * parsegeom; +} +using namespace netgen; + +#include "geometry.h" + + +ARRAY<char*> parsestrings; +int linenum; +#define incl 1 + +#define comment 2 + +#line 594 "lex.yy.cc" + +/* Macros after this point can all be overridden by user definitions in + * section 1. + */ + +#ifndef YY_SKIP_YYWRAP +#ifdef __cplusplus +extern "C" int yywrap YY_PROTO(( void )); +#else +extern int yywrap YY_PROTO(( void )); +#endif +#endif + + +#ifndef yytext_ptr +static void yy_flex_strncpy YY_PROTO(( char *, yyconst char *, int )); +#endif + +#ifdef YY_NEED_STRLEN +static int yy_flex_strlen YY_PROTO(( yyconst char * )); +#endif + +#ifndef YY_NO_INPUT +#endif + +#if YY_STACK_USED +static int yy_start_stack_ptr = 0; +static int yy_start_stack_depth = 0; +static int *yy_start_stack = 0; +#ifndef YY_NO_PUSH_STATE +static void yy_push_state YY_PROTO(( int new_state )); +#endif +#ifndef YY_NO_POP_STATE +static void yy_pop_state YY_PROTO(( void )); +#endif +#ifndef YY_NO_TOP_STATE +static int yy_top_state YY_PROTO(( void )); +#endif + +#else +#define YY_NO_PUSH_STATE 1 +#define YY_NO_POP_STATE 1 +#define YY_NO_TOP_STATE 1 +#endif + +#ifdef YY_MALLOC_DECL +YY_MALLOC_DECL +#else +#if __STDC__ +#ifndef __cplusplus +#include <stdlib.h> +#endif +#else +/* Just try to get by without declaring the routines. This will fail + * miserably on non-ANSI systems for which sizeof(size_t) != sizeof(int) + * or sizeof(void*) != sizeof(int). + */ +#endif +#endif + +/* Amount of stuff to slurp up with each read. */ +#ifndef YY_READ_BUF_SIZE +#define YY_READ_BUF_SIZE 8192 +#endif + +/* Copy whatever the last rule matched to the standard output. */ + +#ifndef ECHO +#define ECHO LexerOutput( yytext, yyleng ) +#endif + +/* Gets input and stuffs it into "buf". number of characters read, or YY_NULL, + * is returned in "result". + */ +#ifndef YY_INPUT +#define YY_INPUT(buf,result,max_size) \ + if ( (result = LexerInput( (char *) buf, max_size )) < 0 ) \ + YY_FATAL_ERROR( "input in flex scanner failed" ); +#endif + +/* No semi-colon after return; correct usage is to write "yyterminate();" - + * we don't want an extra ';' after the "return" because that will cause + * some compilers to complain about unreachable statements. + */ +#ifndef yyterminate +#define yyterminate() return YY_NULL +#endif + +/* Number of entries by which start-condition stack grows. */ +#ifndef YY_START_STACK_INCR +#define YY_START_STACK_INCR 25 +#endif + +/* Report a fatal error. */ +#ifndef YY_FATAL_ERROR +#define YY_FATAL_ERROR(msg) LexerError( msg ) +#endif + +/* Default declaration of generated scanner - a define so the user can + * easily add parameters. + */ +#ifndef YY_DECL +#define YY_DECL int yyFlexLexer::yylex() +#endif + +/* Code executed at the beginning of each rule, after yytext and yyleng + * have been set up. + */ +#ifndef YY_USER_ACTION +#define YY_USER_ACTION +#endif + +/* Code executed at the end of each rule. */ +#ifndef YY_BREAK +#define YY_BREAK break; +#endif + +#define YY_RULE_SETUP \ + YY_USER_ACTION + +YY_DECL + { + register yy_state_type yy_current_state; + register char *yy_cp, *yy_bp; + register int yy_act; + +#line 32 "geometry.ll" + +#line 723 "lex.yy.cc" + + if ( yy_init ) + { + yy_init = 0; + +#ifdef YY_USER_INIT + YY_USER_INIT; +#endif + + if ( ! yy_start ) + yy_start = 1; /* first start state */ + + if ( ! yyin ) + yyin = &cin; + + if ( ! yyout ) + yyout = &cout; + + if ( ! yy_current_buffer ) + yy_current_buffer = + yy_create_buffer( yyin, YY_BUF_SIZE ); + + yy_load_buffer_state(); + } + + while ( 1 ) /* loops until end-of-file is reached */ + { + yy_cp = yy_c_buf_p; + + /* Support of yytext. */ + *yy_cp = yy_hold_char; + + /* yy_bp points to the position in yy_ch_buf of the start of + * the current run. + */ + yy_bp = yy_cp; + + yy_current_state = yy_start; +yy_match: + do + { + register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)]; + if ( yy_accept[yy_current_state] ) + { + yy_last_accepting_state = yy_current_state; + yy_last_accepting_cpos = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 222 ) + yy_c = yy_meta[(unsigned int) yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; + ++yy_cp; + } + while ( yy_base[yy_current_state] != 706 ); + +yy_find_action: + yy_act = yy_accept[yy_current_state]; + if ( yy_act == 0 ) + { /* have to back up */ + yy_cp = yy_last_accepting_cpos; + yy_current_state = yy_last_accepting_state; + yy_act = yy_accept[yy_current_state]; + } + + YY_DO_BEFORE_ACTION; + + +do_action: /* This label is used only to access EOF actions. */ + + if ( yy_flex_debug ) + { + if ( yy_act == 0 ) + cerr << "--scanner backing up\n"; + else if ( yy_act < 37 ) + cerr << "--accepting rule at line " << yy_rule_linenum[yy_act] << + "(\"" << yytext << "\")\n"; + else if ( yy_act == 37 ) + cerr << "--accepting default rule (\"" << yytext << "\")\n"; + else if ( yy_act == 38 ) + cerr << "--(end of buffer or a NUL)\n"; + else + cerr << "--EOF (start condition " << YY_START << ")\n"; + } + + switch ( yy_act ) + { /* beginning of action switch */ + case 0: /* must back up */ + /* undo the effects of YY_DO_BEFORE_ACTION */ + *yy_cp = yy_hold_char; + yy_cp = yy_last_accepting_cpos; + yy_current_state = yy_last_accepting_state; + goto yy_find_action; + +case 1: +YY_RULE_SETUP +#line 33 "geometry.ll" +{ return TOK_RECO; } + YY_BREAK +case 2: +YY_RULE_SETUP +#line 34 "geometry.ll" +{ return TOK_SOLID; } + YY_BREAK +case 3: +YY_RULE_SETUP +#line 35 "geometry.ll" +{ return TOK_TLO; } + YY_BREAK +case 4: +YY_RULE_SETUP +#line 36 "geometry.ll" +{ return TOK_AND; } + YY_BREAK +case 5: +YY_RULE_SETUP +#line 37 "geometry.ll" +{ return TOK_OR; } + YY_BREAK +case 6: +YY_RULE_SETUP +#line 38 "geometry.ll" +{ return TOK_NOT; } + YY_BREAK +case 7: +YY_RULE_SETUP +#line 39 "geometry.ll" +{ return TOK_TRANSLATE; } + YY_BREAK +case 8: +YY_RULE_SETUP +#line 40 "geometry.ll" +{ return TOK_MULTITRANSLATE; } + YY_BREAK +case 9: +YY_RULE_SETUP +#line 41 "geometry.ll" +{ return TOK_ROTATE; } + YY_BREAK +case 10: +YY_RULE_SETUP +#line 42 "geometry.ll" +{ return TOK_MULTIROTATE; } + YY_BREAK +case 11: +YY_RULE_SETUP +#line 43 "geometry.ll" +{ return TOK_SPHERE; } + YY_BREAK +case 12: +YY_RULE_SETUP +#line 44 "geometry.ll" +{ return TOK_CYLINDER; } + YY_BREAK +case 13: +YY_RULE_SETUP +#line 45 "geometry.ll" +{ return TOK_CONE; } + YY_BREAK +case 14: +YY_RULE_SETUP +#line 46 "geometry.ll" +{ return TOK_PLAIN; } + YY_BREAK +case 15: +YY_RULE_SETUP +#line 47 "geometry.ll" +{ return TOK_PLAIN; } + YY_BREAK +case 16: +YY_RULE_SETUP +#line 48 "geometry.ll" +{ return TOK_TUBE; } + YY_BREAK +case 17: +YY_RULE_SETUP +#line 49 "geometry.ll" +{ return TOK_GENCYL; } + YY_BREAK +case 18: +YY_RULE_SETUP +#line 50 "geometry.ll" +{ return TOK_ORTHOBRICK; } + YY_BREAK +case 19: +YY_RULE_SETUP +#line 51 "geometry.ll" +{ return TOK_POLYHEDRON; } + YY_BREAK +case 20: +YY_RULE_SETUP +#line 52 "geometry.ll" +{ return TOK_REVOLUTION; } + YY_BREAK +case 21: +YY_RULE_SETUP +#line 54 "geometry.ll" +{ return TOK_SINGULAR; } + YY_BREAK +case 22: +YY_RULE_SETUP +#line 55 "geometry.ll" +{ return TOK_EDGE; } + YY_BREAK +case 23: +YY_RULE_SETUP +#line 56 "geometry.ll" +{ return TOK_POINT; } + YY_BREAK +case 24: +YY_RULE_SETUP +#line 58 "geometry.ll" +{ return TOK_IDENTIFY; } + YY_BREAK +case 25: +YY_RULE_SETUP +#line 59 "geometry.ll" +{ return TOK_CLOSESURFACES; } + YY_BREAK +case 26: +YY_RULE_SETUP +#line 60 "geometry.ll" +{ return TOK_CLOSEEDGES; } + YY_BREAK +case 27: +YY_RULE_SETUP +#line 61 "geometry.ll" +{ return TOK_PERIODIC; } + YY_BREAK +case 28: +YY_RULE_SETUP +#line 62 "geometry.ll" +{ return TOK_BOUNDARYCONDITION; } + YY_BREAK +case 29: +YY_RULE_SETUP +#line 63 "geometry.ll" +{ return TOK_BOUNDINGBOX; } + YY_BREAK +case 30: +YY_RULE_SETUP +#line 65 "geometry.ll" +{ yylval.val = atof (YYText()); return NUM; } + YY_BREAK +case 31: +YY_RULE_SETUP +#line 66 "geometry.ll" +{ + yylval.chptr = new char [YYLeng()+1]; + parsestrings.Append (yylval.chptr); + strcpy (yylval.chptr, YYText()); + if (parsegeom->GetSolid (yylval.chptr)) + return IDENTSOLID; + else + return IDENT; + } + YY_BREAK +case 32: +YY_RULE_SETUP +#line 75 "geometry.ll" +/* eat up ws */ + YY_BREAK +case 33: +YY_RULE_SETUP +#line 76 "geometry.ll" +{ return int(*YYText()); } + YY_BREAK +case 34: +YY_RULE_SETUP +#line 77 "geometry.ll" +{ linenum++; } + YY_BREAK +case 35: +YY_RULE_SETUP +#line 78 "geometry.ll" +{ linenum++; cout << (YYText()+2) ; } /* line comment */ + YY_BREAK +case 36: +YY_RULE_SETUP +#line 79 "geometry.ll" +{ linenum++; } /* line comment */ + YY_BREAK +case 37: +YY_RULE_SETUP +#line 82 "geometry.ll" +ECHO; + YY_BREAK +#line 1013 "lex.yy.cc" +case YY_STATE_EOF(INITIAL): +case YY_STATE_EOF(incl): +case YY_STATE_EOF(comment): + yyterminate(); + + case YY_END_OF_BUFFER: + { + /* Amount of text matched not including the EOB char. */ + int yy_amount_of_matched_text = (int) (yy_cp - yytext_ptr) - 1; + + /* Undo the effects of YY_DO_BEFORE_ACTION. */ + *yy_cp = yy_hold_char; + YY_RESTORE_YY_MORE_OFFSET + + if ( yy_current_buffer->yy_buffer_status == YY_BUFFER_NEW ) + { + /* We're scanning a new file or input source. It's + * possible that this happened because the user + * just pointed yyin at a new source and called + * yylex(). If so, then we have to assure + * consistency between yy_current_buffer and our + * globals. Here is the right place to do so, because + * this is the first action (other than possibly a + * back-up) that will match for the new input source. + */ + yy_n_chars = yy_current_buffer->yy_n_chars; + yy_current_buffer->yy_input_file = yyin; + yy_current_buffer->yy_buffer_status = YY_BUFFER_NORMAL; + } + + /* Note that here we test for yy_c_buf_p "<=" to the position + * of the first EOB in the buffer, since yy_c_buf_p will + * already have been incremented past the NUL character + * (since all states make transitions on EOB to the + * end-of-buffer state). Contrast this with the test + * in input(). + */ + if ( yy_c_buf_p <= &yy_current_buffer->yy_ch_buf[yy_n_chars] ) + { /* This was really a NUL. */ + yy_state_type yy_next_state; + + yy_c_buf_p = yytext_ptr + yy_amount_of_matched_text; + + yy_current_state = yy_get_previous_state(); + + /* Okay, we're now positioned to make the NUL + * transition. We couldn't have + * yy_get_previous_state() go ahead and do it + * for us because it doesn't know how to deal + * with the possibility of jamming (and we don't + * want to build jamming into it because then it + * will run more slowly). + */ + + yy_next_state = yy_try_NUL_trans( yy_current_state ); + + yy_bp = yytext_ptr + YY_MORE_ADJ; + + if ( yy_next_state ) + { + /* Consume the NUL. */ + yy_cp = ++yy_c_buf_p; + yy_current_state = yy_next_state; + goto yy_match; + } + + else + { + yy_cp = yy_c_buf_p; + goto yy_find_action; + } + } + + else switch ( yy_get_next_buffer() ) + { + case EOB_ACT_END_OF_FILE: + { + yy_did_buffer_switch_on_eof = 0; + + if ( yywrap() ) + { + /* Note: because we've taken care in + * yy_get_next_buffer() to have set up + * yytext, we can now set up + * yy_c_buf_p so that if some total + * hoser (like flex itself) wants to + * call the scanner after we return the + * YY_NULL, it'll still work - another + * YY_NULL will get returned. + */ + yy_c_buf_p = yytext_ptr + YY_MORE_ADJ; + + yy_act = YY_STATE_EOF(YY_START); + goto do_action; + } + + else + { + if ( ! yy_did_buffer_switch_on_eof ) + YY_NEW_FILE; + } + break; + } + + case EOB_ACT_CONTINUE_SCAN: + yy_c_buf_p = + yytext_ptr + yy_amount_of_matched_text; + + yy_current_state = yy_get_previous_state(); + + yy_cp = yy_c_buf_p; + yy_bp = yytext_ptr + YY_MORE_ADJ; + goto yy_match; + + case EOB_ACT_LAST_MATCH: + yy_c_buf_p = + &yy_current_buffer->yy_ch_buf[yy_n_chars]; + + yy_current_state = yy_get_previous_state(); + + yy_cp = yy_c_buf_p; + yy_bp = yytext_ptr + YY_MORE_ADJ; + goto yy_find_action; + } + break; + } + + default: + YY_FATAL_ERROR( + "fatal flex scanner internal error--no action found" ); + } /* end of action switch */ + } /* end of scanning one token */ + } /* end of yylex */ + +yyFlexLexer::yyFlexLexer( istream* arg_yyin, ostream* arg_yyout ) + { + yyin = arg_yyin; + yyout = arg_yyout; + yy_c_buf_p = 0; + yy_init = 1; + yy_start = 0; + yy_flex_debug = 0; + yylineno = 1; // this will only get updated if %option yylineno + + yy_did_buffer_switch_on_eof = 0; + + yy_looking_for_trail_begin = 0; + yy_more_flag = 0; + yy_more_len = 0; + yy_more_offset = yy_prev_more_offset = 0; + + yy_start_stack_ptr = yy_start_stack_depth = 0; + yy_start_stack = 0; + + yy_current_buffer = 0; + +#ifdef YY_USES_REJECT + yy_state_buf = new yy_state_type[YY_BUF_SIZE + 2]; +#else + yy_state_buf = 0; +#endif + } + +yyFlexLexer::~yyFlexLexer() + { + delete yy_state_buf; + yy_delete_buffer( yy_current_buffer ); + } + +void yyFlexLexer::switch_streams( istream* new_in, ostream* new_out ) + { + if ( new_in ) + { + yy_delete_buffer( yy_current_buffer ); + yy_switch_to_buffer( yy_create_buffer( new_in, YY_BUF_SIZE ) ); + } + + if ( new_out ) + yyout = new_out; + } + +#ifdef YY_INTERACTIVE +int yyFlexLexer::LexerInput( char* buf, int /* max_size */ ) +#else +int yyFlexLexer::LexerInput( char* buf, int max_size ) +#endif + { + if ( yyin->eof() || yyin->fail() ) + return 0; + +#ifdef YY_INTERACTIVE + yyin->get( buf[0] ); + + if ( yyin->eof() ) + return 0; + + if ( yyin->bad() ) + return -1; + + return 1; + +#else + (void) yyin->read( buf, max_size ); + + if ( yyin->bad() ) + return -1; + else + return yyin->gcount(); +#endif + } + +void yyFlexLexer::LexerOutput( const char* buf, int size ) + { + (void) yyout->write( buf, size ); + } + +/* yy_get_next_buffer - try to read in a new buffer + * + * Returns a code representing an action: + * EOB_ACT_LAST_MATCH - + * EOB_ACT_CONTINUE_SCAN - continue scanning from current position + * EOB_ACT_END_OF_FILE - end of file + */ + +int yyFlexLexer::yy_get_next_buffer() + { + register char *dest = yy_current_buffer->yy_ch_buf; + register char *source = yytext_ptr; + register int number_to_move, i; + int ret_val; + + if ( yy_c_buf_p > &yy_current_buffer->yy_ch_buf[yy_n_chars + 1] ) + YY_FATAL_ERROR( + "fatal flex scanner internal error--end of buffer missed" ); + + if ( yy_current_buffer->yy_fill_buffer == 0 ) + { /* Don't try to fill the buffer, so this is an EOF. */ + if ( yy_c_buf_p - yytext_ptr - YY_MORE_ADJ == 1 ) + { + /* We matched a single character, the EOB, so + * treat this as a final EOF. + */ + return EOB_ACT_END_OF_FILE; + } + + else + { + /* We matched some text prior to the EOB, first + * process it. + */ + return EOB_ACT_LAST_MATCH; + } + } + + /* Try to read more data. */ + + /* First move last chars to start of buffer. */ + number_to_move = (int) (yy_c_buf_p - yytext_ptr) - 1; + + for ( i = 0; i < number_to_move; ++i ) + *(dest++) = *(source++); + + if ( yy_current_buffer->yy_buffer_status == YY_BUFFER_EOF_PENDING ) + /* don't do the read, it's not guaranteed to return an EOF, + * just force an EOF + */ + yy_current_buffer->yy_n_chars = yy_n_chars = 0; + + else + { + int num_to_read = + yy_current_buffer->yy_buf_size - number_to_move - 1; + + while ( num_to_read <= 0 ) + { /* Not enough room in the buffer - grow it. */ +#ifdef YY_USES_REJECT + YY_FATAL_ERROR( +"input buffer overflow, can't enlarge buffer because scanner uses REJECT" ); +#else + + /* just a shorter name for the current buffer */ + YY_BUFFER_STATE b = yy_current_buffer; + + int yy_c_buf_p_offset = + (int) (yy_c_buf_p - b->yy_ch_buf); + + if ( b->yy_is_our_buffer ) + { + int new_size = b->yy_buf_size * 2; + + if ( new_size <= 0 ) + b->yy_buf_size += b->yy_buf_size / 8; + else + b->yy_buf_size *= 2; + + b->yy_ch_buf = (char *) + /* Include room in for 2 EOB chars. */ + yy_flex_realloc( (void *) b->yy_ch_buf, + b->yy_buf_size + 2 ); + } + else + /* Can't grow it, we don't own it. */ + b->yy_ch_buf = 0; + + if ( ! b->yy_ch_buf ) + YY_FATAL_ERROR( + "fatal error - scanner input buffer overflow" ); + + yy_c_buf_p = &b->yy_ch_buf[yy_c_buf_p_offset]; + + num_to_read = yy_current_buffer->yy_buf_size - + number_to_move - 1; +#endif + } + + if ( num_to_read > YY_READ_BUF_SIZE ) + num_to_read = YY_READ_BUF_SIZE; + + /* Read in more data. */ + YY_INPUT( (&yy_current_buffer->yy_ch_buf[number_to_move]), + yy_n_chars, num_to_read ); + + yy_current_buffer->yy_n_chars = yy_n_chars; + } + + if ( yy_n_chars == 0 ) + { + if ( number_to_move == YY_MORE_ADJ ) + { + ret_val = EOB_ACT_END_OF_FILE; + yyrestart( yyin ); + } + + else + { + ret_val = EOB_ACT_LAST_MATCH; + yy_current_buffer->yy_buffer_status = + YY_BUFFER_EOF_PENDING; + } + } + + else + ret_val = EOB_ACT_CONTINUE_SCAN; + + yy_n_chars += number_to_move; + yy_current_buffer->yy_ch_buf[yy_n_chars] = YY_END_OF_BUFFER_CHAR; + yy_current_buffer->yy_ch_buf[yy_n_chars + 1] = YY_END_OF_BUFFER_CHAR; + + yytext_ptr = &yy_current_buffer->yy_ch_buf[0]; + + return ret_val; + } + + +/* yy_get_previous_state - get the state just before the EOB char was reached */ + +yy_state_type yyFlexLexer::yy_get_previous_state() + { + register yy_state_type yy_current_state; + register char *yy_cp; + + yy_current_state = yy_start; + + for ( yy_cp = yytext_ptr + YY_MORE_ADJ; yy_cp < yy_c_buf_p; ++yy_cp ) + { + register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1); + if ( yy_accept[yy_current_state] ) + { + yy_last_accepting_state = yy_current_state; + yy_last_accepting_cpos = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 222 ) + yy_c = yy_meta[(unsigned int) yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; + } + + return yy_current_state; + } + + +/* yy_try_NUL_trans - try to make a transition on the NUL character + * + * synopsis + * next_state = yy_try_NUL_trans( current_state ); + */ + +yy_state_type yyFlexLexer::yy_try_NUL_trans( yy_state_type yy_current_state ) + { + register int yy_is_jam; + register char *yy_cp = yy_c_buf_p; + + register YY_CHAR yy_c = 1; + if ( yy_accept[yy_current_state] ) + { + yy_last_accepting_state = yy_current_state; + yy_last_accepting_cpos = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 222 ) + yy_c = yy_meta[(unsigned int) yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; + yy_is_jam = (yy_current_state == 221); + + return yy_is_jam ? 0 : yy_current_state; + } + + +void yyFlexLexer::yyunput( int c, register char* yy_bp ) + { + register char *yy_cp = yy_c_buf_p; + + /* undo effects of setting up yytext */ + *yy_cp = yy_hold_char; + + if ( yy_cp < yy_current_buffer->yy_ch_buf + 2 ) + { /* need to shift things up to make room */ + /* +2 for EOB chars. */ + register int number_to_move = yy_n_chars + 2; + register char *dest = &yy_current_buffer->yy_ch_buf[ + yy_current_buffer->yy_buf_size + 2]; + register char *source = + &yy_current_buffer->yy_ch_buf[number_to_move]; + + while ( source > yy_current_buffer->yy_ch_buf ) + *--dest = *--source; + + yy_cp += (int) (dest - source); + yy_bp += (int) (dest - source); + yy_current_buffer->yy_n_chars = + yy_n_chars = yy_current_buffer->yy_buf_size; + + if ( yy_cp < yy_current_buffer->yy_ch_buf + 2 ) + YY_FATAL_ERROR( "flex scanner push-back overflow" ); + } + + *--yy_cp = (char) c; + + + yytext_ptr = yy_bp; + yy_hold_char = *yy_cp; + yy_c_buf_p = yy_cp; + } + + +int yyFlexLexer::yyinput() + { + int c; + + *yy_c_buf_p = yy_hold_char; + + if ( *yy_c_buf_p == YY_END_OF_BUFFER_CHAR ) + { + /* yy_c_buf_p now points to the character we want to return. + * If this occurs *before* the EOB characters, then it's a + * valid NUL; if not, then we've hit the end of the buffer. + */ + if ( yy_c_buf_p < &yy_current_buffer->yy_ch_buf[yy_n_chars] ) + /* This was really a NUL. */ + *yy_c_buf_p = '\0'; + + else + { /* need more input */ + int offset = yy_c_buf_p - yytext_ptr; + ++yy_c_buf_p; + + switch ( yy_get_next_buffer() ) + { + case EOB_ACT_LAST_MATCH: + /* This happens because yy_g_n_b() + * sees that we've accumulated a + * token and flags that we need to + * try matching the token before + * proceeding. But for input(), + * there's no matching to consider. + * So convert the EOB_ACT_LAST_MATCH + * to EOB_ACT_END_OF_FILE. + */ + + /* Reset buffer status. */ + yyrestart( yyin ); + + /* fall through */ + + case EOB_ACT_END_OF_FILE: + { + if ( yywrap() ) + return EOF; + + if ( ! yy_did_buffer_switch_on_eof ) + YY_NEW_FILE; +#ifdef __cplusplus + return yyinput(); +#else + return input(); +#endif + } + + case EOB_ACT_CONTINUE_SCAN: + yy_c_buf_p = yytext_ptr + offset; + break; + } + } + } + + c = *(unsigned char *) yy_c_buf_p; /* cast for 8-bit char's */ + *yy_c_buf_p = '\0'; /* preserve yytext */ + yy_hold_char = *++yy_c_buf_p; + + + return c; + } + + +void yyFlexLexer::yyrestart( istream* input_file ) + { + if ( ! yy_current_buffer ) + yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); + + yy_init_buffer( yy_current_buffer, input_file ); + yy_load_buffer_state(); + } + + +void yyFlexLexer::yy_switch_to_buffer( YY_BUFFER_STATE new_buffer ) + { + if ( yy_current_buffer == new_buffer ) + return; + + if ( yy_current_buffer ) + { + /* Flush out information for old buffer. */ + *yy_c_buf_p = yy_hold_char; + yy_current_buffer->yy_buf_pos = yy_c_buf_p; + yy_current_buffer->yy_n_chars = yy_n_chars; + } + + yy_current_buffer = new_buffer; + yy_load_buffer_state(); + + /* We don't actually know whether we did this switch during + * EOF (yywrap()) processing, but the only time this flag + * is looked at is after yywrap() is called, so it's safe + * to go ahead and always set it. + */ + yy_did_buffer_switch_on_eof = 1; + } + + +void yyFlexLexer::yy_load_buffer_state() + { + yy_n_chars = yy_current_buffer->yy_n_chars; + yytext_ptr = yy_c_buf_p = yy_current_buffer->yy_buf_pos; + yyin = yy_current_buffer->yy_input_file; + yy_hold_char = *yy_c_buf_p; + } + + +YY_BUFFER_STATE yyFlexLexer::yy_create_buffer( istream* file, int size ) + { + YY_BUFFER_STATE b; + + b = (YY_BUFFER_STATE) yy_flex_alloc( sizeof( struct yy_buffer_state ) ); + if ( ! b ) + YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); + + b->yy_buf_size = size; + + /* yy_ch_buf has to be 2 characters longer than the size given because + * we need to put in 2 end-of-buffer characters. + */ + b->yy_ch_buf = (char *) yy_flex_alloc( b->yy_buf_size + 2 ); + if ( ! b->yy_ch_buf ) + YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); + + b->yy_is_our_buffer = 1; + + yy_init_buffer( b, file ); + + return b; + } + + +void yyFlexLexer::yy_delete_buffer( YY_BUFFER_STATE b ) + { + if ( ! b ) + return; + + if ( b == yy_current_buffer ) + yy_current_buffer = (YY_BUFFER_STATE) 0; + + if ( b->yy_is_our_buffer ) + yy_flex_free( (void *) b->yy_ch_buf ); + + yy_flex_free( (void *) b ); + } + + +#include<unistd.h> +void yyFlexLexer::yy_init_buffer( YY_BUFFER_STATE b, istream* file ) + + { + yy_flush_buffer( b ); + + b->yy_input_file = file; + b->yy_fill_buffer = 1; + + b->yy_is_interactive = 0; + } + + +void yyFlexLexer::yy_flush_buffer( YY_BUFFER_STATE b ) + { + if ( ! b ) + return; + + b->yy_n_chars = 0; + + /* We always need two end-of-buffer characters. The first causes + * a transition to the end-of-buffer state. The second causes + * a jam in that state. + */ + b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR; + b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR; + + b->yy_buf_pos = &b->yy_ch_buf[0]; + + b->yy_at_bol = 1; + b->yy_buffer_status = YY_BUFFER_NEW; + + if ( b == yy_current_buffer ) + yy_load_buffer_state(); + } + + +#ifndef YY_NO_SCAN_BUFFER +#endif + + +#ifndef YY_NO_SCAN_STRING +#endif + + +#ifndef YY_NO_SCAN_BYTES +#endif + + +#ifndef YY_NO_PUSH_STATE +void yyFlexLexer::yy_push_state( int new_state ) + { + if ( yy_start_stack_ptr >= yy_start_stack_depth ) + { + yy_size_t new_size; + + yy_start_stack_depth += YY_START_STACK_INCR; + new_size = yy_start_stack_depth * sizeof( int ); + + if ( ! yy_start_stack ) + yy_start_stack = (int *) yy_flex_alloc( new_size ); + + else + yy_start_stack = (int *) yy_flex_realloc( + (void *) yy_start_stack, new_size ); + + if ( ! yy_start_stack ) + YY_FATAL_ERROR( + "out of memory expanding start-condition stack" ); + } + + yy_start_stack[yy_start_stack_ptr++] = YY_START; + + BEGIN(new_state); + } +#endif + + +#ifndef YY_NO_POP_STATE +void yyFlexLexer::yy_pop_state() + { + if ( --yy_start_stack_ptr < 0 ) + YY_FATAL_ERROR( "start-condition stack underflow" ); + + BEGIN(yy_start_stack[yy_start_stack_ptr]); + } +#endif + + +#ifndef YY_NO_TOP_STATE +int yyFlexLexer::yy_top_state() + { + return yy_start_stack[yy_start_stack_ptr - 1]; + } +#endif + +#ifndef YY_EXIT_FAILURE +#define YY_EXIT_FAILURE 2 +#endif + + +void yyFlexLexer::LexerError( yyconst char msg[] ) + { + cerr << msg << '\n'; + exit( YY_EXIT_FAILURE ); + } + + +/* Redefine yyless() so it works in section 3 code. */ + +#undef yyless +#define yyless(n) \ + do \ + { \ + /* Undo effects of setting up yytext. */ \ + yytext[yyleng] = yy_hold_char; \ + yy_c_buf_p = yytext + n; \ + yy_hold_char = *yy_c_buf_p; \ + *yy_c_buf_p = '\0'; \ + yyleng = n; \ + } \ + while ( 0 ) + + +/* Internal utility routines. */ + +#ifndef yytext_ptr +#ifdef YY_USE_PROTOS +static void yy_flex_strncpy( char *s1, yyconst char *s2, int n ) +#else +static void yy_flex_strncpy( s1, s2, n ) +char *s1; +yyconst char *s2; +int n; +#endif + { + register int i; + for ( i = 0; i < n; ++i ) + s1[i] = s2[i]; + } +#endif + +#ifdef YY_NEED_STRLEN +#ifdef YY_USE_PROTOS +static int yy_flex_strlen( yyconst char *s ) +#else +static int yy_flex_strlen( s ) +yyconst char *s; +#endif + { + register int n; + for ( n = 0; s[n]; ++n ) + ; + + return n; + } +#endif + + +#ifdef YY_USE_PROTOS +static void *yy_flex_alloc( yy_size_t size ) +#else +static void *yy_flex_alloc( size ) +yy_size_t size; +#endif + { + return (void *) malloc( size ); + } + +#ifdef YY_USE_PROTOS +static void *yy_flex_realloc( void *ptr, yy_size_t size ) +#else +static void *yy_flex_realloc( ptr, size ) +void *ptr; +yy_size_t size; +#endif + { + /* The cast to (char *) in the following accommodates both + * implementations that use char* generic pointers, and those + * that use void* generic pointers. It works with the latter + * because both ANSI C and C++ allow castless assignment from + * any pointer type to void*, and deal with argument conversions + * as though doing an assignment. + */ + return (void *) realloc( (char *) ptr, size ); + } + +#ifdef YY_USE_PROTOS +static void yy_flex_free( void *ptr ) +#else +static void yy_flex_free( ptr ) +void *ptr; +#endif + { + free( ptr ); + } + +#if YY_MAIN +int main() + { + yylex(); + return 0; + } +#endif +#line 82 "geometry.ll" + + +extern FlexLexer * lexer; + +int yylex () + { + return lexer -> yylex(); + } + +extern "C" int yywrap () + { + return 1; + } diff --git a/contrib/Netgen/libsrc/csg/manifold.cpp b/contrib/Netgen/libsrc/csg/manifold.cpp new file mode 100644 index 0000000000..9733389d67 --- /dev/null +++ b/contrib/Netgen/libsrc/csg/manifold.cpp @@ -0,0 +1,14 @@ +#include <csg.hpp> + +namespace netgen +{ +Manifold :: Manifold () +{ + ; +} + +Manifold :: ~Manifold () +{ + ; +} +} diff --git a/contrib/Netgen/libsrc/csg/manifold.hpp b/contrib/Netgen/libsrc/csg/manifold.hpp new file mode 100644 index 0000000000..5deb7236a7 --- /dev/null +++ b/contrib/Netgen/libsrc/csg/manifold.hpp @@ -0,0 +1,22 @@ +#ifndef FILE_MANIFOLD +#define FILE_MANIFOLD + +/**************************************************************************/ +/* File: manifold.hh */ +/* Author: Joachim Schoeberl */ +/* Date: 7. Aug. 96 */ +/**************************************************************************/ + +/** + Basis class for manifolds in 2d and 3d +*/ +class Manifold +{ +public: + /// + Manifold (); + /// + virtual ~Manifold (); +}; + +#endif diff --git a/contrib/Netgen/libsrc/csg/meshsurf.cpp b/contrib/Netgen/libsrc/csg/meshsurf.cpp new file mode 100644 index 0000000000..0a7d7c74a0 --- /dev/null +++ b/contrib/Netgen/libsrc/csg/meshsurf.cpp @@ -0,0 +1,178 @@ +#include <mystdlib.h> + +#include <csg.hpp> +#include <meshing.hpp> + + + +namespace netgen +{ + /* +Meshing2Surfaces :: Meshing2Surfaces (const Surface & asurface) + : surface(asurface) +{ + ; +} + */ +Meshing2Surfaces :: Meshing2Surfaces (const Surface & asurf, + const Box<3> & abb) + : Meshing2(Box3d(abb.PMin(), abb.PMax())), surface(asurf) +{ + ; +} + + +void Meshing2Surfaces :: DefineTransformation (Point3d & p1, Point3d & p2, + const PointGeomInfo * geominfo1, + const PointGeomInfo * geominfo2) +{ + ((Surface&)surface).DefineTangentialPlane (p1, p2); +} + +void Meshing2Surfaces :: TransformToPlain (const Point3d & locpoint, + const MultiPointGeomInfo & geominfo, + Point2d & planepoint, + double h, int & zone) +{ + Point<2> hp; + surface.ToPlane (locpoint, hp, h, zone); + planepoint.X() = hp(0); + planepoint.Y() = hp(1); +} + +int Meshing2Surfaces :: TransformFromPlain (Point2d & planepoint, + Point3d & locpoint, + PointGeomInfo & gi, + double h) +{ + Point<3> hp; + Point<2> hp2 (planepoint.X(), planepoint.Y()); + surface.FromPlane (hp2, hp, h); + locpoint = hp; + gi.trignum = 1; + return 0; +} + + + +double Meshing2Surfaces :: CalcLocalH (const Point3d & p, double gh) const +{ + return surface.LocH (p, 3, 1, gh); + /* + double loch = mesh.lochfunc->GetH(p); + if (gh < loch) loch = gh; + return loch; + */ +} + + + + + + +MeshOptimize2dSurfaces :: MeshOptimize2dSurfaces (const CSGeometry & ageometry) + : MeshOptimize2d(), geometry(ageometry) +{ + ; +} + + +void MeshOptimize2dSurfaces :: ProjectPoint (INDEX surfind, Point3d & p) const +{ + Point<3> hp = p; + geometry.GetSurface(surfind)->Project (hp); + p = hp; +} + +void MeshOptimize2dSurfaces :: ProjectPoint2 (INDEX surfind, INDEX surfind2, + Point3d & p) const +{ + Point<3> hp = p; + ProjectToEdge ( geometry.GetSurface(surfind), + geometry.GetSurface(surfind2), hp); + p = hp; +} + + +void MeshOptimize2dSurfaces :: +GetNormalVector(INDEX surfind, const Point3d & p, Vec3d & n) const +{ + Vec<3> hn = n; + geometry.GetSurface(surfind)->CalcGradient (p, hn); + hn.Normalize(); + n = hn; + + /* + if (geometry.GetSurface(surfind)->Inverse()) + n *= -1; + */ +} + + + + + + + +RefinementSurfaces :: RefinementSurfaces (const CSGeometry & ageometry) + : Refinement(), geometry(ageometry) +{ + ; +} + +RefinementSurfaces :: ~RefinementSurfaces () +{ + ; +} + +void RefinementSurfaces :: +PointBetween (const Point3d & p1, const Point3d & p2, double secpoint, + int surfi, + const PointGeomInfo & gi1, + const PointGeomInfo & gi2, + Point3d & newp, PointGeomInfo & newgi) +{ + Point<3> hnewp; + hnewp = p1+secpoint*(p2-p1); + + if (surfi != -1) + { + geometry.GetSurface (surfi) -> Project (hnewp); + newgi.trignum = 1; + } + + newp = hnewp; +} + +void RefinementSurfaces :: +PointBetween (const Point3d & p1, const Point3d & p2, double secpoint, + int surfi1, int surfi2, + const EdgePointGeomInfo & ap1, + const EdgePointGeomInfo & ap2, + Point3d & newp, EdgePointGeomInfo & newgi) +{ + Point<3> hnewp = p1+secpoint*(p2-p1); + if (surfi1 != -1 && surfi2 != -1 && surfi1 != surfi2) + { + ProjectToEdge (geometry.GetSurface(surfi1), + geometry.GetSurface(surfi2), + hnewp); + // (*testout) << "Pointbetween, newp = " << hnewp << endl + // << ", err = " << sqrt (sqr (hnewp(0))+ sqr(hnewp(1)) + sqr (hnewp(2))) - 1 << endl; + newgi.edgenr = 1; + } + else if (surfi1 != -1) + { + geometry.GetSurface (surfi1) -> Project (hnewp); + } + + newp = hnewp; +} + + +void RefinementSurfaces :: ProjectToSurface (Point<3> & p, int surfi) +{ + if (surfi != -1) + geometry.GetSurface (surfi) -> Project (p); +} +} diff --git a/contrib/Netgen/libsrc/csg/meshsurf.hpp b/contrib/Netgen/libsrc/csg/meshsurf.hpp new file mode 100644 index 0000000000..023c2eef70 --- /dev/null +++ b/contrib/Netgen/libsrc/csg/meshsurf.hpp @@ -0,0 +1,85 @@ +#ifndef FILE_MESHSURF +#define FILE_MESHSURF + +/// +class Meshing2Surfaces : public Meshing2 +{ + /// + const Surface & surface; + +public: + /// + // Meshing2Surfaces (const Surface & asurf); + /// + Meshing2Surfaces (const Surface & asurf, const Box<3> & aboundingbox); + +protected: + /// + virtual void DefineTransformation (Point3d & p1, Point3d & p2, + const PointGeomInfo * geominfo1, + const PointGeomInfo * geominfo2); + /// + virtual void TransformToPlain (const Point3d & locpoint, + const MultiPointGeomInfo & geominfo, + Point2d & plainpoint, + double h, int & zone); + /// + virtual int TransformFromPlain (Point2d & plainpoint, + Point3d & locpoint, + PointGeomInfo & gi, + double h); + /// + virtual double CalcLocalH (const Point3d & p, double gh) const; +}; + + + +/// +class MeshOptimize2dSurfaces : public MeshOptimize2d + { + /// + const CSGeometry & geometry; + +public: + /// + MeshOptimize2dSurfaces (const CSGeometry & ageometry); + + /// + virtual void ProjectPoint (INDEX surfind, Point3d & p) const; + /// + virtual void ProjectPoint2 (INDEX surfind, INDEX surfind2, Point3d & p) const; + /// + virtual void GetNormalVector(INDEX surfind, const Point3d & p, Vec3d & n) const; +}; + + + + + +class RefinementSurfaces : public Refinement +{ + const CSGeometry & geometry; + +public: + RefinementSurfaces (const CSGeometry & ageometry); + virtual ~RefinementSurfaces (); + + virtual void PointBetween (const Point3d & p1, const Point3d & p2, double secpoint, + int surfi, + const PointGeomInfo & gi1, + const PointGeomInfo & gi2, + Point3d & newp, PointGeomInfo & newgi); + + virtual void PointBetween (const Point3d & p1, const Point3d & p2, double secpoint, + int surfi1, int surfi2, + const EdgePointGeomInfo & ap1, + const EdgePointGeomInfo & ap2, + Point3d & newp, EdgePointGeomInfo & newgi); + + virtual void ProjectToSurface (Point<3> & p, int surfi); +}; + + + +#endif + diff --git a/contrib/Netgen/libsrc/csg/polyhedra.cpp b/contrib/Netgen/libsrc/csg/polyhedra.cpp new file mode 100644 index 0000000000..f0ce2f63f5 --- /dev/null +++ b/contrib/Netgen/libsrc/csg/polyhedra.cpp @@ -0,0 +1,358 @@ +#include <mystdlib.h> + +#include <linalg.hpp> +#include <csg.hpp> + +namespace netgen +{ + +Polyhedra::Face::Face (int pi1, int pi2, int pi3, const ARRAY<Point<3> > & points) +{ + pnums[0] = pi1; + pnums[1] = pi2; + pnums[2] = pi3; + + bbox.Set (points[pi1]); + bbox.Add (points[pi2]); + bbox.Add (points[pi3]); + + v1 = points[pi2] - points[pi1]; + v2 = points[pi3] - points[pi1]; + + n = Cross (v1, v2); + nn = n; + nn.Normalize(); + // PseudoInverse (v1, v2, w1, w2); + + Mat<2,3> mat; + Mat<3,2> inv; + 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); +} + +Polyhedra :: ~Polyhedra () +{ + ; +} + +Primitive * Polyhedra :: CreateDefault () +{ + return new Polyhedra(); +} + +INSOLID_TYPE Polyhedra :: BoxInSolid (const BoxSphere<3> & box) const +{ + /* + for (i = 1; i <= faces.Size(); i++) + if (FaceBoxIntersection (i, box)) + return DOES_INTERSECT; + */ + for (int i = 0; i < faces.Size(); i++) + { + if (!faces[i].bbox.Intersect (box)) + continue; + + const Point<3> & p1 = points[faces[i].pnums[0]]; + const Point<3> & p2 = points[faces[i].pnums[1]]; + const Point<3> & p3 = points[faces[i].pnums[2]]; + + if (fabs (faces[i].nn * (p1 - box.Center())) > box.Diam()/2) + continue; + + double dist2 = MinDistTP2 (p1, p2, p3, box.Center()); + if (dist2 < sqr (box.Diam()/2)) + return DOES_INTERSECT; + }; + + return PointInSolid (box.Center(), 1e-3 * box.Diam()); +} + + +INSOLID_TYPE Polyhedra :: PointInSolid (const Point<3> & p, + double eps) const +{ + Vec<3> n, v1, v2; + + // random (?) numbers: + n(0) = 0.123871; + n(1) = 0.15432; + n(2) = 0.43989; + + int cnt = 0; + Point<3> pmeps (p(0) - eps, p(1) - eps, p(2) - eps); + + for (int i = 0; i < faces.Size(); i++) + { + const Point<3> & fpmax = faces[i].bbox.PMax(); + if (fpmax(0) < pmeps(0) || + fpmax(1) < pmeps(1) || + fpmax(2) < pmeps(2)) continue; + + const Point<3> & p1 = points[faces[i].pnums[0]]; + + Vec<3> v0 = p - p1; + double lam3 = -(faces[i].n * v0) / (faces[i].n * n); + + if (lam3 < -eps) continue; + Vec<3> rs = v0 + lam3 * n; + + double lam1 = (faces[i].w1 * rs); + double lam2 = (faces[i].w2 * rs); + + if (lam3 < eps) + { + if (lam1 >= -eps && lam2 >= -eps && lam1+lam2 <= 1+eps) + return DOES_INTERSECT; + } + else if (lam1 >= 0 && lam2 >= 0 && lam1+lam2 <= 1) + { // lam3 > 0 + cnt++; + } + + } + + // (*testout) << " inside = " << (cnt % 2) << endl; + return (cnt % 2) ? IS_INSIDE : IS_OUTSIDE; +} + + + +INSOLID_TYPE Polyhedra :: VecInSolid (const Point<3> & p, + const Vec<3> & v, + double eps) const +{ + int point_on_n_faces = 0; + INSOLID_TYPE res; + + 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].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) + { + point_on_n_faces++; + + double scal = vn * faces[i].n; + + res = DOES_INTERSECT; + if (scal > eps) res = IS_OUTSIDE; + if (scal < -eps) res = IS_INSIDE; + } + } + + if (point_on_n_faces == 1) + return res; + + + Point<3> p2 = p + (1e-3/(v.Length()+1e-16)) * v; + res = PointInSolid (p2, eps); + // (*testout) << "p = " << p << " v = " << v << " p2 = " << p2 << endl; + // (*testout) << "polyeder::vecinsolid = " << int(res) << endl; + return res; +} + + +INSOLID_TYPE Polyhedra :: VecInSolid2 (const Point<3> & p, + const Vec<3> & v1, + const Vec<3> & v2, + double eps) const +{ + int point_on_n_faces = 0; + INSOLID_TYPE res; + + 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; + + + + + return Primitive :: VecInSolid2 (p, v1, v2, eps); +} + + + + +void Polyhedra :: GetPrimitiveData (char *& classname, + ARRAY<double> & coeffs) const +{ + classname = "Polyhedra"; + coeffs.SetSize(0); + coeffs.Append (points.Size()); + coeffs.Append (faces.Size()); + coeffs.Append (planes.Size()); + + /* + int i, j; + for (i = 1; i <= planes.Size(); i++) + { + planes.Elem(i)->Print (*testout); + } + for (i = 1; i <= faces.Size(); i++) + { + (*testout) << "face " << i << " has plane " << faces.Get(i).planenr << endl; + for (j = 1; j <= 3; j++) + (*testout) << points.Get(faces.Get(i).pnums[j-1]); + (*testout) << endl; + } + */ +} + +void Polyhedra :: SetPrimitiveData (ARRAY<double> & coeffs) +{ + ; +} + +void Polyhedra :: Reduce (const BoxSphere<3> & box) +{ + 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) +{ + return points.Append (p); +} + +int Polyhedra :: AddFace (int pi1, int pi2, int pi3) +{ + faces.Append (Face (pi1, pi2, pi3, points)); + + Point<3> p1 = points[pi1]; + Point<3> p2 = points[pi2]; + Point<3> p3 = points[pi3]; + + Vec<3> v1 = p2 - p1; + Vec<3> v2 = p3 - p1; + + Vec<3> n = Cross (v1, v2); + n.Normalize(); + + Plane pl (p1, n); + int inverse; + int identicto = -1; + for (int i = 0; i < planes.Size(); i++) + if (pl.IsIdentic (*planes[i], inverse, 1e-6)) + { + if (!inverse) + identicto = i; + } + // cout << "is identic = " << identicto << endl; + + if (identicto != -1) + faces.Last().planenr = identicto; + else + { + planes.Append (new Plane (p1, n)); + surfaceactive.Append (1); + surfaceids.Append (0); + faces.Last().planenr = planes.Size()-1; + } + + return faces.Size(); +} + + + +int Polyhedra :: FaceBoxIntersection (int fnr, const BoxSphere<3> & box) const +{ + /* + (*testout) << "check face box intersection, fnr = " << fnr << endl; + (*testout) << "box = " << box << endl; + (*testout) << "face-box = " << faces[fnr].bbox << endl; + */ + + if (!faces[fnr].bbox.Intersect (box)) + return 0; + + const Point<3> & p1 = points[faces[fnr].pnums[0]]; + const Point<3> & p2 = points[faces[fnr].pnums[1]]; + const Point<3> & p3 = points[faces[fnr].pnums[2]]; + + double dist2 = MinDistTP2 (p1, p2, p3, box.Center()); + /* + (*testout) << "p1 = " << p1 << endl; + (*testout) << "p2 = " << p2 << endl; + (*testout) << "p3 = " << p3 << endl; + + (*testout) << "box.Center() = " << box.Center() << endl; + (*testout) << "center = " << box.Center() << endl; + (*testout) << "dist2 = " << dist2 << endl; + (*testout) << "diam = " << box.Diam() << endl; + */ + if (dist2 < sqr (box.Diam()/2)) + { + // (*testout) << "intersect" << endl; + return 1; + } + return 0; +} +} diff --git a/contrib/Netgen/libsrc/csg/polyhedra.hpp b/contrib/Netgen/libsrc/csg/polyhedra.hpp new file mode 100644 index 0000000000..529cfff40d --- /dev/null +++ b/contrib/Netgen/libsrc/csg/polyhedra.hpp @@ -0,0 +1,78 @@ +#ifndef FILE_POLYHEDRA +#define FILE_POLYHEDRA + + +/**************************************************************************/ +/* File: polyhedra.hh */ +/* Author: Joachim Schoeberl */ +/* Date: 19. Mar. 2000 */ +/**************************************************************************/ + +/* + + Polyhedral primitive + +*/ + +class Polyhedra : public Primitive +{ + class Face { + public: + int pnums[3]; + int planenr; + + Box<3> bbox; + // Point<3> center; + Vec<3> v1, v2; // edges + Vec<3> w1, w2; // pseudo-inverse + Vec<3> n; // normal to face + Vec<3> nn; // normed normal + + Face () { ; } + Face (int pi1, int pi2, int pi3, const ARRAY<Point<3> > & points); + }; + + ARRAY<Point<3> > points; + ARRAY<Face> faces; + ARRAY<Plane*> planes; + +public: + Polyhedra (); + virtual ~Polyhedra (); + static Primitive * CreateDefault (); + + virtual INSOLID_TYPE BoxInSolid (const BoxSphere<3> & box) const; + virtual INSOLID_TYPE PointInSolid (const Point<3> & p, + double eps) const; + virtual INSOLID_TYPE VecInSolid (const Point<3> & p, + const Vec<3> & v, + double eps) const; + + // checks if lim s->0 lim t->0 p + t(v1 + s v2) in solid + virtual INSOLID_TYPE VecInSolid2 (const Point<3> & p, + const Vec<3> & v1, + const Vec<3> & v2, + double eps) const; + + virtual int GetNSurfaces() const + { return planes.Size(); } + virtual Surface & GetSurface (int i) + { return *planes[i]; } + virtual const Surface & GetSurface (int i) const + { return *planes[i]; } + + virtual void GetPrimitiveData (char *& classname, ARRAY<double> & coeffs) const; + virtual void SetPrimitiveData (ARRAY<double> & coeffs); + + virtual void Reduce (const BoxSphere<3> & box); + virtual void UnReduce (); + + int AddPoint (const Point<3> & p); + int AddFace (int pi1, int pi2, int pi3); + +protected: + int FaceBoxIntersection (int fnr, const BoxSphere<3> & box) const; + // void CalcData(); +}; + +#endif diff --git a/contrib/Netgen/libsrc/csg/revolution.cpp b/contrib/Netgen/libsrc/csg/revolution.cpp new file mode 100644 index 0000000000..e235012e43 --- /dev/null +++ b/contrib/Netgen/libsrc/csg/revolution.cpp @@ -0,0 +1,151 @@ +#include <mystdlib.h> + +#include <linalg.hpp> +#include <csg.hpp> + +namespace netgen +{ + +#ifdef NONE + +Revolution :: Revolution (const Point<3> & ap1, const Point<3> & ap2) +{ + p1 = ap1; + p2 = ap2; + v12 = p2 - p1; + v12.Normalize(); +} + +Revolution :: ~Revolution () +{ + ; +} + +Primitive * Revolution :: CreateDefault () +{ + return new Revolution( Point<3> (0, 0, 0), + Point<3> (1, 0, 0)); +} + +INSOLID_TYPE Revolution :: BoxInSolid (const BoxSphere<3> & box) const +{ + int i; + + Vec<3> v = box.Center() - p1; + double x = v * v12; + double y = sqrt (v.Length2() - x*x); + + Point<2> lp1, lp2; + for (i = 1; i <= polygon.GetNP(); i++) + { + polygon.GetLine (i, lp1, lp2); + + double dist2 = MinDistLP2 (lp1, lp2, Point<2>(x,y)); + if (dist2 < sqr (box.Diam())) + return DOES_INTERSECT; + }; + + return PointInSolid (box.Center(), 1e-3 * box.Diam()); +} + + +INSOLID_TYPE Revolution :: PointInSolid (const Point<3> & p, + double eps) const +{ + int i, cnt; + + Vec<3> v(p1, p); + double x = v * v12; + double y = sqrt (v.Length2() - x*x); + + if (polygon.IsOn (Point<2> (x, y))) + return DOES_INTERSECT; + if (polygon.IsIn (Point<2> (x, y))) + return IS_INSIDE; + else + return IS_OUTSIDE; +} + + + +INSOLID_TYPE Revolution :: VecInSolid (const Point<3> & p, + const Vec<3> & v, + double eps) const +{ + Point<3> p2 = p + (1e-3/(v.Length()+1e-16)) * v; + return PointInSolid (p2, eps); +} + + +void Revolution :: GetPrimitiveData (char *& classname, + ARRAY<double> & coeffs) const +{ + classname = "Revolution"; + coeffs.SetSize(0); + coeffs.Append (polygon.GetNP()); +} + +void Revolution :: SetPrimitiveData (ARRAY<double> & coeffs) +{ + ; +} + +void Revolution :: Reduce (const BoxSphere<3> & box) +{ + int i; + + for (i = 1; i <= polygon.GetNP(); i++) + surfaceactive.Elem (i) = 0; + + + Vec<3> v = box.Center() - p1; + double x = v * v12; + double y = sqrt (v.Length2() - x*x); + + Point<2> lp1, lp2; + for (i = 1; i <= polygon.GetNP(); i++) + { + polygon.GetLine (i, lp1, lp2); + + double dist2 = MinDistLP2 (lp1, lp2, Point<2>(x,y)); + if (dist2 < sqr (box.Diam()/2)) + surfaceactive.Elem(i) = 1; + }; +} + +void Revolution :: UnReduce () +{ + for (int i = 0; i < polygon.GetNP(); i++) + surfaceactive[i] = 1; +} + + +int Revolution :: AddPoint (const Point<2> & p) +{ + polygon.AddPoint (p); + return polygon.GetNP(); +} + +void Revolution :: Finish () +{ + int i; + Point<2> lp1, lp2; + Point<3> cp1, cp2; + + for (i = 1; i <= polygon.GetNP(); i++) + { + polygon.GetLine (i, lp1, lp2); + cp1 = p1 + lp1.X() * v12; + cp2 = p1 + lp2.X() * v12; + + faces.Append (new Cone (cp1, cp2, + fabs (lp1.Y()), + fabs (lp2.Y()))); + + invsurf.Append (lp1.X() < lp2.X()); + } +} + + +#endif +} diff --git a/contrib/Netgen/libsrc/csg/revolution.hpp b/contrib/Netgen/libsrc/csg/revolution.hpp new file mode 100644 index 0000000000..d57102d306 --- /dev/null +++ b/contrib/Netgen/libsrc/csg/revolution.hpp @@ -0,0 +1,65 @@ +#ifndef FILE_REVOLUTION +#define FILE_REVOLUTION + + +/**************************************************************************/ +/* File: revolution.hh */ +/* Author: Joachim Schoeberl */ +/* Date: 12. Oct. 2000 */ +/**************************************************************************/ + +/* + + Primitive of revolution + +*/ + + +#ifdef NONE + +class Revolution : public Primitive +{ + Point<3> p1, p2; + Vec<3> v12; + Polygon2d polygon; + ARRAY<Cone*> faces; + ARRAY<int> invsurf; +public: + Revolution (const Point<3> & ap1, const Point<3> & ap2); + ~Revolution (); + static Primitive * CreateDefault (); + + virtual INSOLID_TYPE BoxInSolid (const BoxSphere<3> & box) const; + virtual INSOLID_TYPE PointInSolid (const Point<3> & p, + double eps) const; + virtual INSOLID_TYPE VecInSolid (const Point<3> & p, + const Vec<3> & v, + double eps) const; + + virtual int GetNSurfaces() const + { return faces.Size(); } + virtual Surface & GetSurface (int i) + { return *faces.Elem(i); } + virtual const Surface & GetSurface (int i = 1) const + { return *faces.Get(i); } + + virtual int SurfaceInverted (int i = 1) const + { return invsurf.Get(i); } + + virtual void GetPrimitiveData (char *& classname, ARRAY<double> & coeffs) const; + virtual void SetPrimitiveData (ARRAY<double> & coeffs); + + virtual void Reduce (const BoxSphere<3> & box); + virtual void UnReduce (); + + int AddPoint (const Point<2> & p); + void Finish (); +protected: + // int FaceBoxIntersection (int fnr, const BoxSphere<3> & box) const; + // void CalcData(); +}; + + +#endif + +#endif diff --git a/contrib/Netgen/libsrc/csg/singularref.cpp b/contrib/Netgen/libsrc/csg/singularref.cpp new file mode 100644 index 0000000000..add7bfdf65 --- /dev/null +++ b/contrib/Netgen/libsrc/csg/singularref.cpp @@ -0,0 +1,117 @@ +#include <mystdlib.h> +#include <myadt.hpp> + +#include <linalg.hpp> +#include <csg.hpp> +#include <meshing.hpp> + +namespace netgen +{ + +SingularEdge :: SingularEdge (double abeta, + const Solid * asol1, + const Solid * asol2) +{ + beta = abeta; + + if (beta > 1) + { + beta = 1; + cout << "Warning: beta set to 1" << endl; + } + if (beta <= 1e-3) + { + beta = 1e-3; + cout << "Warning: beta set to minimal value 0.001" << endl; + } + + sol1 = asol1; + sol2 = asol2; +} + +void SingularEdge :: FindPointsOnEdge (class Mesh & mesh) +{ + (*testout) << "find points on edge" << endl; + int j; + points.SetSize(0); + segms.SetSize(0); + for (SegmentIndex si = 0; si < mesh.GetNSeg(); si++) + { + INDEX_2 i2 (mesh[si].p1, mesh[si].p2); + + 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 (onedge) + { + segms.Append (i2); + PrintMessage (5, "sing segment ", i2.I1(), " - ", i2.I2()); + points.Append (mesh[ PointIndex (i2.I1())]); + points.Append (mesh[ PointIndex (i2.I2())]); + mesh[si].singedge_left = 1; + mesh[si].singedge_right = 1; + } + } + + /* + (*testout) << "Singular 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); + 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) +{ + beta = abeta; + sol1 = asol1; + sol2 = asol2; + sol3 = asol3; +} + + +void SingularPoint :: FindPoints (class Mesh & mesh) +{ + points.SetSize(0); + for (PointIndex pi = PointIndex::BASE; + pi < mesh.GetNP()+PointIndex::BASE; pi++) + { + const Point<3> p = mesh[pi]; + if (sol1->IsIn (p) && sol2->IsIn(p) && sol3->IsIn(p) && + !sol1->IsStrictIn (p) && !sol2->IsStrictIn(p) && !sol3->IsStrictIn(p)) + { + points.Append (p); + PrintMessage (5, "Point (", p(0), ", ", p(1), ", ", p(2), ") is singular"); + mesh[pi].SetSingular(); + } + } +} + + +void SingularPoint :: SetMeshSize (class Mesh & mesh, double globalh) +{ + double hloc = pow (globalh, 1/beta); + for (int i = 1; i <= points.Size(); i++) + mesh.RestrictLocalH (points.Get(i), hloc); +} +} diff --git a/contrib/Netgen/libsrc/csg/singularref.hpp b/contrib/Netgen/libsrc/csg/singularref.hpp new file mode 100644 index 0000000000..d52dcf8f8c --- /dev/null +++ b/contrib/Netgen/libsrc/csg/singularref.hpp @@ -0,0 +1,68 @@ +#ifndef FILE_SINGULARREF +#define FILE_SINGULARREF + +/**************************************************************************/ +/* File: singularref.hh */ +/* Author: Joachim Schoeberl */ +/* Date: 25. Sep. 99 */ +/**************************************************************************/ + +/** + Control for local refinement +*/ + + + +/** + Singular Face. + Causes a bounday layer mesh refinement. + All elements in subdomain domnr will get a boundary layer + on faces sharing the solid sol + */ +class SingularFace +{ +public: + int domnr; + const Solid *sol; + // ARRAY<Point<3> > points; + // ARRAY<INDEX_2> segms; +public: + SingularFace (int adomnr, const Solid * asol) + : domnr(adomnr), sol(asol) { ; } + const Solid * GetSolid() const { return sol; } + int GetDomainNr () const { return domnr; } +}; + + +/// +class SingularEdge +{ +public: + double beta; + const Solid *sol1, *sol2; + ARRAY<Point<3> > points; + ARRAY<INDEX_2> segms; +public: + SingularEdge (double abeta, const Solid * asol1, const Solid * asol2); + void FindPointsOnEdge (class Mesh & mesh); + void SetMeshSize (class Mesh & mesh, double globalh); +}; + + +/// +class SingularPoint +{ +public: + double beta; + const Solid *sol1, *sol2, *sol3; + ARRAY<Point<3> > points; + +public: + SingularPoint (double abeta, const Solid * asol1, const Solid * asol2, + const Solid * asol3); + void FindPoints (class Mesh & mesh); + void SetMeshSize (class Mesh & mesh, double globalh); +}; + + +#endif diff --git a/contrib/Netgen/libsrc/csg/solid.cpp b/contrib/Netgen/libsrc/csg/solid.cpp new file mode 100644 index 0000000000..08d20f78a4 --- /dev/null +++ b/contrib/Netgen/libsrc/csg/solid.cpp @@ -0,0 +1,1217 @@ +#include <mystdlib.h> + +#include <linalg.hpp> +#include <csg.hpp> + + +namespace netgen +{ + using namespace netgen; + + + /* + SolidIterator :: SolidIterator () + { + ; + } + + SolidIterator :: ~SolidIterator () + { + ; + } + */ + + + + // int Solid :: cntnames = 0; + + Solid :: Solid (Primitive * aprim) + { + op = TERM; + prim = aprim; + s1 = s2 = NULL; + maxh = 1e10; + name = NULL; + } + + Solid :: Solid (optyp aop, Solid * as1, Solid * as2) + { + op = aop; + s1 = as1; + s2 = as2; + prim = NULL; + name = NULL; + maxh = 1e10; + } + + Solid :: ~Solid () + { + // cout << "delete solid, op = " << int(op) << endl; + delete [] name; + + switch (op) + { + case UNION: + case SECTION: + { + if (s1->op != ROOT) delete s1; + if (s2->op != ROOT) delete s2; + break; + } + case SUB: + // case ROOT: + { + if (s1->op != ROOT) delete s1; + break; + } + case TERM: + { + // cout << "has term" << endl; + delete prim; + break; + } + default: + break; + } + } + + void Solid :: SetName (const char * aname) + { + delete [] name; + name = new char[strlen (aname)+1]; + strcpy (name, aname); + } + + + Solid * Solid :: Copy (CSGeometry & geom) const + { + Solid * nsol; + 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; + } + } + } + + + + + bool Solid :: IsIn (const Point<3> & p, double eps) const + { + switch (op) + { + case TERM: case TERM_REF: + { + INSOLID_TYPE ist = prim->PointInSolid (p, eps); + return ( (ist == IS_INSIDE) || (ist == DOES_INTERSECT) ) ? 1 : 0; + } + case SECTION: + return s1->IsIn (p, eps) && s2->IsIn (p, eps); + case UNION: + return s1->IsIn (p, eps) || s2->IsIn (p, eps); + case SUB: + return !s1->IsStrictIn (p, eps); + case ROOT: + return s1->IsIn (p, eps); + } + return 0; + } + + bool Solid :: IsStrictIn (const Point<3> & p, double eps) const + { + switch (op) + { + case TERM: case TERM_REF: + { + INSOLID_TYPE ist = prim->PointInSolid (p, eps); + return (ist == IS_INSIDE) ? 1 : 0; + } + case SECTION: + return s1->IsStrictIn(p, eps) && s2->IsStrictIn(p, eps); + case UNION: + return s1->IsStrictIn(p, eps) || s2->IsStrictIn(p, eps); + case SUB: + return !s1->IsIn (p, eps); + case ROOT: + return s1->IsStrictIn (p, eps); + } + return 0; + } + + bool Solid :: VectorIn (const Point<3> & p, const Vec<3> & v, + double eps) const + { + Vec<3> hv; + switch (op) + { + case TERM: case TERM_REF: + { + INSOLID_TYPE ist = prim->VecInSolid (p, v, eps); + return (ist == IS_INSIDE || ist == DOES_INTERSECT) ? 1 : 0; + } + case SECTION: + return s1 -> VectorIn (p, v, eps) && s2 -> VectorIn (p, v, eps); + case UNION: + return s1 -> VectorIn (p, v, eps) || s2 -> VectorIn (p, v, eps); + case SUB: + return !s1->VectorStrictIn(p, v, eps); + case ROOT: + return s1->VectorIn(p, v, eps); + } + return 0; + } + + bool Solid :: VectorStrictIn (const Point<3> & p, const Vec<3> & v, + double eps) const + { + Vec<3> hv; + switch (op) + { + case TERM: case TERM_REF: + { + INSOLID_TYPE ist = prim->VecInSolid (p, v, eps); + return (ist == IS_INSIDE) ? 1 : 0; + } + case SECTION: + return s1 -> VectorStrictIn (p, v, eps) && + s2 -> VectorStrictIn (p, v, eps); + case UNION: + return s1 -> VectorStrictIn (p, v, eps) || + s2 -> VectorStrictIn (p, v, eps); + case SUB: + return !s1->VectorIn(p, v, eps); + case ROOT: + return s1->VectorStrictIn(p, v, eps); + } + return 0; + } + + + 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); + case SECTION: + return s1->VectorIn2Rec (p, v1, v2, eps) && + s2->VectorIn2Rec (p, v1, v2, eps); + case UNION: + return s1->VectorIn2Rec (p, v1, v2, eps) || + s2->VectorIn2Rec (p, v1, v2, eps); + case SUB: + return !s1->VectorIn2Rec (p, v1, v2, eps); + case ROOT: + return s1->VectorIn2Rec (p, v1, v2, eps); + } + return 0; + } + + + + + + + void Solid :: Print (ostream & str) const + { + switch (op) + { + case TERM: case TERM_REF: + { + str << prim->GetSurfaceId(0); + for (int i = 1; i < prim->GetNSurfaces(); i++) + str << "," << prim->GetSurfaceId(i); + break; + } + case SECTION: + { + str << "("; + s1 -> Print (str); + str << " AND "; + s2 -> Print (str); + str << ")"; + break; + } + case UNION: + { + str << "("; + s1 -> Print (str); + str << " OR "; + s2 -> Print (str); + str << ")"; + break; + } + case SUB: + { + str << " NOT "; + s1 -> Print (str); + break; + } + case ROOT: + { + str << " [" << name << "="; + s1 -> Print (str); + str << "] "; + break; + } + } + } + + + + void Solid :: GetSolidData (ostream & ost, int first) const + { + switch (op) + { + case SECTION: + { + ost << "("; + s1 -> GetSolidData (ost, 0); + ost << " AND "; + s2 -> GetSolidData (ost, 0); + ost << ")"; + break; + } + case UNION: + { + ost << "("; + s1 -> GetSolidData (ost, 0); + ost << " OR "; + s2 -> GetSolidData (ost, 0); + ost << ")"; + break; + } + case SUB: + { + ost << "NOT "; + s1 -> GetSolidData (ost, 0); + break; + } + case TERM: case TERM_REF: + { + if (name) + ost << name; + else + ost << "(noname)"; + break; + } + case ROOT: + { + if (first) + s1 -> GetSolidData (ost, 0); + else + ost << name; + break; + } + } + } + + + + static Solid * CreateSolidExpr (istream & ist, const SYMBOLTABLE<Solid*> & solids); + static Solid * CreateSolidTerm (istream & ist, const SYMBOLTABLE<Solid*> & solids); + static Solid * CreateSolidPrim (istream & ist, const SYMBOLTABLE<Solid*> & solids); + + static void ReadString (istream & ist, char * str) + { + char * hstr = str; + char ch; + + while (1) + { + ist.get(ch); + if (!ist.good()) break; + + if (!isspace (ch)) + { + ist.putback (ch); + break; + } + } + + while (1) + { + ist.get(ch); + if (!ist.good()) break; + if (isalpha(ch) || isdigit(ch)) + { + *str = ch; + str++; + } + else + { + ist.putback (ch); + break; + } + } + *str = 0; + // cout << "Read string (" << hstr << ")" + // << "put back: " << ch << endl; + } + + + Solid * CreateSolidExpr (istream & ist, const SYMBOLTABLE<Solid*> & solids) + { + // cout << "create expr" << endl; + + Solid *s1, *s2; + char str[100]; + + s1 = CreateSolidTerm (ist, solids); + ReadString (ist, str); + if (strcmp (str, "OR") == 0) + { + // cout << " OR "; + s2 = CreateSolidExpr (ist, solids); + return new Solid (Solid::UNION, s1, s2); + } + + // cout << "no OR found, put back string: " << str << endl; + int i; + for (i = strlen(str)-1; i >= 0; i--) + ist.putback (str[i]); + + return s1; + } + + Solid * CreateSolidTerm (istream & ist, const SYMBOLTABLE<Solid*> & solids) + { + // cout << "create term" << endl; + + Solid *s1, *s2; + char str[100]; + + s1 = CreateSolidPrim (ist, solids); + ReadString (ist, str); + if (strcmp (str, "AND") == 0) + { + // cout << " AND "; + s2 = CreateSolidTerm (ist, solids); + return new Solid (Solid::SECTION, s1, s2); + } + + + // cout << "no AND found, put back string: " << str << endl; + int i; + for (i = strlen(str)-1; i >= 0; i--) + ist.putback (str[i]); + + return s1; + } + + Solid * CreateSolidPrim (istream & ist, const SYMBOLTABLE<Solid*> & solids) + { + Solid * s1; + char ch; + char str[100]; + + ist >> ch; + if (ch == '(') + { + s1 = CreateSolidExpr (ist, solids); + ist >> ch; // ')' + // cout << "close back " << ch << endl; + return s1; + } + ist.putback (ch); + + ReadString (ist, str); + if (strcmp (str, "NOT") == 0) + { + // cout << " NOT "; + s1 = CreateSolidPrim (ist, solids); + return new Solid (Solid::SUB, s1); + } + + (*testout) << "get terminal " << str << endl; + s1 = solids.Get(str); + if (s1) + { + // cout << "primitive: " << str << endl; + return s1; + } + cerr << "syntax error" << endl; + + return NULL; + } + + + Solid * Solid :: CreateSolid (istream & ist, const SYMBOLTABLE<Solid*> & solids) + { + Solid * nsol = CreateSolidExpr (ist, solids); + nsol = new Solid (ROOT, nsol); + (*testout) << "Print new sol: "; + nsol -> Print (*testout); + (*testout) << endl; + return nsol; + } + + + + void Solid :: Boundaries (const Point<3> & p, ARRAY<int> & bounds) const + { + int in, strin; + bounds.SetSize (0); + RecBoundaries (p, bounds, in, strin); + } + + void Solid :: RecBoundaries (const Point<3> & p, ARRAY<int> & bounds, + int & in, int & strin) const + { + switch (op) + { + case TERM: case TERM_REF: + { + /* + double val; + val = surf->CalcFunctionValue (p); + in = (val < 1e-6); + strin = (val < -1e-6); + if (in && !strin) bounds.Append (id); + */ + if (prim->PointInSolid (p, 1e-6) == DOES_INTERSECT) + bounds.Append (prim->GetSurfaceId (1)); + break; + } + case SECTION: + { + int i, in1, in2, strin1, strin2; + ARRAY<int> bounds1, bounds2; + + s1 -> RecBoundaries (p, bounds1, in1, strin1); + s2 -> RecBoundaries (p, bounds2, in2, strin2); + + if (in1 && in2) + { + for (i = 1; i <= bounds1.Size(); i++) + bounds.Append (bounds1.Get(i)); + for (i = 1; i <= bounds2.Size(); i++) + bounds.Append (bounds2.Get(i)); + } + in = (in1 && in2); + strin = (strin1 && strin2); + break; + } + case UNION: + { + int i, in1, in2, strin1, strin2; + ARRAY<int> bounds1, bounds2; + + s1 -> RecBoundaries (p, bounds1, in1, strin1); + s2 -> RecBoundaries (p, bounds2, in2, strin2); + + if (!strin1 && !strin2) + { + for (i = 1; i <= bounds1.Size(); i++) + bounds.Append (bounds1.Get(i)); + for (i = 1; i <= bounds2.Size(); i++) + bounds.Append (bounds2.Get(i)); + } + in = (in1 || in2); + strin = (strin1 || strin2); + break; + } + case SUB: + { + int hin, hstrin; + s1 -> RecBoundaries (p, bounds, hin, hstrin); + in = !hstrin; + strin = !hin; + break; + } + + case ROOT: + { + s1 -> RecBoundaries (p, bounds, in, strin); + break; + } + } + } + + + + void Solid :: TangentialSolid (const Point<3> & p, Solid *& tansol) const + { + int in, strin; + RecTangentialSolid (p, tansol, in, strin); + } + + void Solid :: RecTangentialSolid (const Point<3> & p, Solid *& tansol, + int & in, int & strin) const + { + tansol = NULL; + + switch (op) + { + case TERM: 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, 1e-6); + + in = (ist == IS_INSIDE || ist == DOES_INTERSECT); + strin = (ist == IS_INSIDE); + + if (ist == DOES_INTERSECT) + { + tansol = new Solid (prim); + tansol -> op = TERM_REF; + } + break; + } + case SECTION: + { + int in1, in2, strin1, strin2; + Solid * tansol1, * tansol2; + + s1 -> RecTangentialSolid (p, tansol1, in1, strin1); + s2 -> RecTangentialSolid (p, tansol2, in2, strin2); + + if (in1 && in2) + { + if (tansol1 && tansol2) + tansol = new Solid (SECTION, tansol1, tansol2); + else if (tansol1) + tansol = tansol1; + else if (tansol2) + tansol = tansol2; + } + in = (in1 && in2); + strin = (strin1 && strin2); + break; + } + case UNION: + { + int in1, in2, strin1, strin2; + Solid * tansol1, * tansol2; + + s1 -> RecTangentialSolid (p, tansol1, in1, strin1); + s2 -> RecTangentialSolid (p, tansol2, in2, strin2); + + if (!strin1 && !strin2) + { + if (tansol1 && tansol2) + tansol = new Solid (UNION, tansol1, tansol2); + else if (tansol1) + tansol = tansol1; + else if (tansol2) + tansol = tansol2; + } + in = (in1 || in2); + strin = (strin1 || strin2); + break; + } + case SUB: + { + int hin, hstrin; + Solid * tansol1; + + s1 -> RecTangentialSolid (p, tansol1, hin, hstrin); + + if (tansol1) + tansol = new Solid (SUB, tansol1); + in = !hstrin; + strin = !hin; + break; + } + case ROOT: + { + s1 -> RecTangentialSolid (p, tansol, in, strin); + break; + } + } + } + + + + + void Solid :: TangentialSolid2 (const Point<3> & p, + const Vec<3> & t, + Solid *& tansol) const + { + int in, strin; + RecTangentialSolid2 (p, t, tansol, in, strin); + } + + void Solid :: RecTangentialSolid2 (const Point<3> & p, const Vec<3> & t, + Solid *& tansol, + int & in, int & strin) const + { + tansol = NULL; + + switch (op) + { + case TERM: 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, 1e-6); + if (ist == DOES_INTERSECT) + ist = prim->VecInSolid (p, t, 1e-6); + + in = (ist == IS_INSIDE || ist == DOES_INTERSECT); + strin = (ist == IS_INSIDE); + + if (ist == DOES_INTERSECT) + { + tansol = new Solid (prim); + tansol -> op = TERM_REF; + } + break; + } + case SECTION: + { + int in1, in2, strin1, strin2; + Solid * tansol1, * tansol2; + + s1 -> RecTangentialSolid2 (p, t, tansol1, in1, strin1); + s2 -> RecTangentialSolid2 (p, t, tansol2, in2, strin2); + + if (in1 && in2) + { + if (tansol1 && tansol2) + tansol = new Solid (SECTION, tansol1, tansol2); + else if (tansol1) + tansol = tansol1; + else if (tansol2) + tansol = tansol2; + } + in = (in1 && in2); + strin = (strin1 && strin2); + break; + } + case UNION: + { + int in1, in2, strin1, strin2; + Solid * tansol1, * tansol2; + + s1 -> RecTangentialSolid2 (p, t, tansol1, in1, strin1); + s2 -> RecTangentialSolid2 (p, t, tansol2, in2, strin2); + + if (!strin1 && !strin2) + { + if (tansol1 && tansol2) + tansol = new Solid (UNION, tansol1, tansol2); + else if (tansol1) + tansol = tansol1; + else if (tansol2) + tansol = tansol2; + } + in = (in1 || in2); + strin = (strin1 || strin2); + break; + } + case SUB: + { + int hin, hstrin; + Solid * tansol1; + + s1 -> RecTangentialSolid2 (p, t, tansol1, hin, hstrin); + + if (tansol1) + tansol = new Solid (SUB, tansol1); + in = !hstrin; + strin = !hin; + break; + } + case ROOT: + { + s1 -> RecTangentialSolid2 (p, t, tansol, in, strin); + break; + } + } + } + + + + + int Solid :: Edge (const Point<3> & p, const Vec<3> & v) const + { + int in, strin, faces; + RecEdge (p, v, in, strin, faces); + return faces >= 2; + } + + int Solid :: OnFace (const Point<3> & p, const Vec<3> & v) const + { + int in, strin, faces; + RecEdge (p, v, in, strin, faces); + return faces >= 1; + } + + + void Solid :: RecEdge (const Point<3> & p, const Vec<3> & v, + int & in, int & strin, int & faces) const + { + switch (op) + { + case TERM: case TERM_REF: + { + INSOLID_TYPE ist = prim->VecInSolid (p, v, 1e-6); + in = (ist == IS_INSIDE || ist == DOES_INTERSECT); + strin = (ist == IS_INSIDE); + /* + in = VectorIn (p, v); + strin = VectorStrictIn (p, v); + */ + faces = 0; + + if (in && ! strin) + { + // faces = 1; + int i; + Vec<3> grad; + for (i = 0; i < prim->GetNSurfaces(); i++) + { + double val = prim->GetSurface(i).CalcFunctionValue(p); + prim->GetSurface(i).CalcGradient (p, grad); + if (fabs (val) < 1e-6 && fabs (v * grad) < 1e-6) + faces++; + } + } + // else + // faces = 0; + break; + } + case SECTION: + { + int in1, in2, strin1, strin2, faces1, faces2; + + s1 -> RecEdge (p, v, in1, strin1, faces1); + s2 -> RecEdge (p, v, in2, strin2, faces2); + + faces = 0; + if (in1 && in2) + faces = faces1 + faces2; + in = in1 && in2; + strin = strin1 && strin2; + break; + } + case UNION: + { + int in1, in2, strin1, strin2, faces1, faces2; + + s1 -> RecEdge (p, v, in1, strin1, faces1); + s2 -> RecEdge (p, v, in2, strin2, faces2); + + faces = 0; + if (!strin1 && !strin2) + faces = faces1 + faces2; + in = in1 || in2; + strin = strin1 || strin2; + break; + } + case SUB: + { + int in1, strin1; + s1 -> RecEdge (p, v, in1, strin1, faces); + in = !strin1; + strin = !in1; + break; + } + case ROOT: + { + s1 -> RecEdge (p, v, in, strin, faces); + break; + } + } + } + + + void Solid :: CalcSurfaceInverse () + { + CalcSurfaceInverseRec (0); + } + + void Solid :: CalcSurfaceInverseRec (int inv) + { + switch (op) + { + case TERM: case TERM_REF: + { + int priminv; + for (int i = 0; i < prim->GetNSurfaces(); i++) + { + priminv = prim->SurfaceInverted(i); + if (inv) priminv = 1 - priminv; + prim->GetSurface(i).SetInverse (priminv); + } + break; + } + case UNION: + case SECTION: + { + s1 -> CalcSurfaceInverseRec (inv); + s2 -> CalcSurfaceInverseRec (inv); + break; + } + case SUB: + { + s1 -> CalcSurfaceInverseRec (1 - inv); + break; + } + case ROOT: + { + s1 -> CalcSurfaceInverseRec (inv); + break; + } + } + } + + + Solid * Solid :: GetReducedSolid (const BoxSphere<3> & box) const + { + INSOLID_TYPE in; + return RecGetReducedSolid (box, in); + } + + Solid * Solid :: RecGetReducedSolid (const BoxSphere<3> & box, INSOLID_TYPE & in) const + { + Solid * redsol = NULL; + + switch (op) + { + case TERM: + case TERM_REF: + { + in = prim -> BoxInSolid (box); + if (in == DOES_INTERSECT) + { + redsol = new Solid (prim); + redsol -> op = TERM_REF; + } + break; + } + case SECTION: + { + INSOLID_TYPE in1, in2; + Solid * redsol1, * redsol2; + + redsol1 = s1 -> RecGetReducedSolid (box, in1); + redsol2 = s2 -> RecGetReducedSolid (box, in2); + + if (in1 == IS_OUTSIDE || in2 == IS_OUTSIDE) + { + if (in1 == DOES_INTERSECT) delete redsol1; + if (in2 == DOES_INTERSECT) delete redsol2; + in = IS_OUTSIDE; + } + else + { + if (in1 == DOES_INTERSECT || in2 == DOES_INTERSECT) + in = DOES_INTERSECT; + else + in = IS_INSIDE; + + if (in1 == DOES_INTERSECT && in2 == DOES_INTERSECT) + redsol = new Solid (SECTION, redsol1, redsol2); + else if (in1 == DOES_INTERSECT) + redsol = redsol1; + else if (in2 == DOES_INTERSECT) + redsol = redsol2; + } + break; + } + + case UNION: + { + INSOLID_TYPE in1, in2; + Solid * redsol1, * redsol2; + + redsol1 = s1 -> RecGetReducedSolid (box, in1); + redsol2 = s2 -> RecGetReducedSolid (box, in2); + + if (in1 == IS_INSIDE || in2 == IS_INSIDE) + { + if (in1 == DOES_INTERSECT) delete redsol1; + if (in2 == DOES_INTERSECT) delete redsol2; + in = IS_INSIDE; + } + else + { + if (in1 == DOES_INTERSECT || in2 == DOES_INTERSECT) in = DOES_INTERSECT; + else in = IS_OUTSIDE; + + if (in1 == DOES_INTERSECT && in2 == DOES_INTERSECT) + redsol = new Solid (UNION, redsol1, redsol2); + else if (in1 == DOES_INTERSECT) + redsol = redsol1; + else if (in2 == DOES_INTERSECT) + redsol = redsol2; + } + break; + } + + case SUB: + { + INSOLID_TYPE in1; + Solid * redsol1 = s1 -> RecGetReducedSolid (box, in1); + + switch (in1) + { + case IS_OUTSIDE: in = IS_INSIDE; break; + case IS_INSIDE: in = IS_OUTSIDE; break; + case DOES_INTERSECT: in = DOES_INTERSECT; break; + } + + if (redsol1) + redsol = new Solid (SUB, redsol1); + break; + } + + case ROOT: + { + INSOLID_TYPE in1; + redsol = s1 -> RecGetReducedSolid (box, in1); + in = in1; + break; + } + } + return redsol; + } + + + int Solid :: NumPrimitives () const + { + switch (op) + { + case TERM: case TERM_REF: + { + return 1; + } + case UNION: + case SECTION: + { + return s1->NumPrimitives () + s2 -> NumPrimitives(); + } + case SUB: + case ROOT: + { + return s1->NumPrimitives (); + } + } + return 0; + } + + void Solid :: GetSurfaceIndices (ARRAY<int> & surfind) const + { + surfind.SetSize (0); + RecGetSurfaceIndices (surfind); + } + + void Solid :: RecGetSurfaceIndices (ARRAY<int> & surfind) const + { + switch (op) + { + case TERM: case TERM_REF: + { + /* + int i; + for (i = 1; i <= surfind.Size(); i++) + if (surfind.Get(i) == prim->GetSurfaceId()) + return; + surfind.Append (prim->GetSurfaceId()); + break; + */ + for (int j = 0; j < prim->GetNSurfaces(); j++) + if (prim->SurfaceActive (j)) + { + bool found = 0; + int siprim = prim->GetSurfaceId(j); + + for (int i = 0; i < surfind.Size(); i++) + if (surfind[i] == siprim) + { + found = 1; + break; + } + if (!found) surfind.Append (siprim); + } + break; + } + case UNION: + case SECTION: + { + s1 -> RecGetSurfaceIndices (surfind); + s2 -> RecGetSurfaceIndices (surfind); + break; + } + case SUB: + case ROOT: + { + s1 -> RecGetSurfaceIndices (surfind); + break; + } + } + } + + + + void Solid :: 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; + } + } + } + + + + + + BlockAllocator Solid :: ball(sizeof (Solid)); +} diff --git a/contrib/Netgen/libsrc/csg/solid.hpp b/contrib/Netgen/libsrc/csg/solid.hpp new file mode 100644 index 0000000000..796729125a --- /dev/null +++ b/contrib/Netgen/libsrc/csg/solid.hpp @@ -0,0 +1,195 @@ +#ifndef FILE_SOLID +#define FILE_SOLID + +/**************************************************************************/ +/* File: solid.hh */ +/* Author: Joachim Schoeberl */ +/* Date: 1. Dez. 95 */ +/**************************************************************************/ + +/* + + Constructive Solid Model (csg) + +*/ + + + + +class Solid; + +class SolidIterator +{ +public: + SolidIterator () { ; } + virtual ~SolidIterator () { ; } + virtual void Do (Solid * sol) = 0; +}; + + + +class Solid +{ +public: + + typedef enum optyp1 { TERM, TERM_REF, SECTION, UNION, SUB, ROOT, DUMMY } optyp; + +private: + char * name; + Primitive * prim; + Solid * s1, * s2; + + optyp op; + bool visited; + double maxh; + + // static int cntnames; + +public: + Solid (Primitive * aprim); + Solid (optyp aop, Solid * as1, Solid * as2 = NULL); + ~Solid (); + + const char * Name () const { return name; } + void SetName (const char * aname); + + Solid * Copy (class CSGeometry & geom) const; + void Transform (Transformation<3> & trans); + + + void IterateSolid (SolidIterator & it, bool only_once = 0); + + + void Boundaries (const Point<3> & p, ARRAY<int> & bounds) const; + int NumPrimitives () const; + void GetSurfaceIndices (ARRAY<int> & surfind) const; + void GetSurfaceIndices (IndexSet & iset) const; + + Primitive * GetPrimitive () + { return (op == TERM || op == TERM_REF) ? prim : NULL; } + const Primitive * GetPrimitive () const + { return (op == TERM || op == TERM_REF) ? prim : NULL; } + + Solid * S1() { return s1; } + Solid * S2() { return s2; } + + // geometric tests + + bool IsIn (const Point<3> & p, double eps = 1e-6) const; + bool IsStrictIn (const Point<3> & p, double eps = 1e-6) const; + bool VectorIn (const Point<3> & p, const Vec<3> & v, double eps = 1e-6) const; + bool VectorStrictIn (const Point<3> & p, const Vec<3> & v, double eps = 1e-6) const; + + bool VectorIn2 (const Point<3> & p, const Vec<3> & v1, const Vec<3> & v2, + double eps = 1e-6) const; + bool VectorIn2Rec (const Point<3> & p, const Vec<3> & v1, const Vec<3> & v2, + double eps = 1e-6) const; + + + /// + void TangentialSolid (const Point<3> & p, Solid *& tansol) const; + /// + void TangentialSolid2 (const Point<3> & p, const Vec<3> & t, + Solid *& tansol) const; + /// + int Edge (const Point<3> & p, const Vec<3> & v) const; + /// + int OnFace (const Point<3> & p, const Vec<3> & v) const; + /// + void Print (ostream & str) const; + /// + void CalcSurfaceInverse (); + /// + Solid * GetReducedSolid (const BoxSphere<3> & box) const; + + + void SetMaxH (double amaxh) + { maxh = amaxh; } + double GetMaxH () const + { return maxh; } + + void GetSolidData (ostream & ost, int first = 1) const; + static Solid * CreateSolid (istream & ist, const SYMBOLTABLE<Solid*> & solids); + + + static BlockAllocator ball; + void * operator new(size_t /* s */) + { + return ball.Alloc(); + } + + void operator delete (void * p) + { + ball.Free (p); + } + + +protected: + /// + + void RecBoundaries (const Point<3> & p, ARRAY<int> & bounds, + int & in, int & strin) const; + /// + void RecTangentialSolid (const Point<3> & p, Solid *& tansol, + int & in, int & strin) const; + /// + void RecTangentialSolid2 (const Point<3> & p, const Vec<3> & vec, + Solid *& tansol, int & in, int & strin) const; + /// + void RecEdge (const Point<3> & p, const Vec<3> & v, + int & in, int & strin, int & faces) const; + /// + void CalcSurfaceInverseRec (int inv); + /// + Solid * RecGetReducedSolid (const BoxSphere<3> & box, INSOLID_TYPE & in) const; + /// + void RecGetSurfaceIndices (ARRAY<int> & surfind) const; + void RecGetSurfaceIndices (IndexSet & iset) const; + + friend class SolidIterator; + friend class ClearVisitedIt; + friend class RemoveDummyIterator; + friend class CSGeometry; +}; + + +inline ostream & operator<< (ostream & ost, const Solid & sol) +{ + sol.Print (ost); + return ost; +} + + + + + + +class ReducePrimitiveIterator : public SolidIterator +{ + const BoxSphere<3> & box; +public: + ReducePrimitiveIterator (const BoxSphere<3> & abox) + : SolidIterator(), box(abox) { ; } + virtual ~ReducePrimitiveIterator () { ; } + virtual void Do (Solid * sol) + { + if (sol -> GetPrimitive()) + sol -> GetPrimitive() -> Reduce (box); + } +}; + + +class UnReducePrimitiveIterator : public SolidIterator +{ +public: + UnReducePrimitiveIterator () { ; } + virtual ~UnReducePrimitiveIterator () { ; } + virtual void Do (Solid * sol) + { + if (sol -> GetPrimitive()) + sol -> GetPrimitive() -> UnReduce (); + } +}; + + +#endif diff --git a/contrib/Netgen/libsrc/csg/specpoin.cpp b/contrib/Netgen/libsrc/csg/specpoin.cpp new file mode 100644 index 0000000000..c9b2477bb0 --- /dev/null +++ b/contrib/Netgen/libsrc/csg/specpoin.cpp @@ -0,0 +1,1231 @@ +#include <mystdlib.h> +#include <meshing.hpp> +#include <csg.hpp> + + +/* + Special Point calculation uses the global Flags: + + relydegtest when to rely on degeneration ? + calccp calculate points of intersection ? + cpeps1 eps for degenerated poi + calcep calculate points of extreme coordinates ? + epeps1 eps for degenerated edge + epeps2 eps for axis parallel pec + epspointdist eps for distance of special points +*/ + + +namespace netgen +{ + void ProjectToEdge (const Surface * f1, const Surface * f2, Point<3> & hp); + + + + SpecialPoint :: SpecialPoint (const SpecialPoint & sp) + { + p = sp.p; + v = sp.v; + s1 = sp.s1; + s2 = sp.s2; + layer = sp.layer; + unconditional = sp.unconditional; + } + + SpecialPoint & SpecialPoint :: operator= (const SpecialPoint & sp) + { + p = sp.p; + v = sp.v; + s1 = sp.s1; + s2 = sp.s2; + layer = sp.layer; + unconditional = sp.unconditional; + return *this; + } + + + void SpecialPoint :: Print (ostream & str) + { + str << "p = " << p << " v = " << v + << " s1/s2 = " << s1 << "/" << s2 + << " layer = " << layer + << endl; + } + + + static ARRAY<int> numprim_hist; + + SpecialPointCalculation :: SpecialPointCalculation () + { + ; + } + + void SpecialPointCalculation :: + CalcSpecialPoints (const CSGeometry & ageometry, + ARRAY<MeshPoint> & apoints) + { + 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; + + CalcSpecialPointsRec (tlo->GetSolid(), tlo->GetLayer(), + box, 1, 1, 1); + } + + // 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) + { + if (multithread.terminate) + throw NgException ("Meshing stopped"); + + + if (!sol) return; + + if (level >= 100) + { + MyStr err = + MyStr("Problems in CalcSpecialPoints\nPoint: ") + MyStr (box.Center()); + throw NgException (err.c_str()); + } + + + bool decision; + bool possiblecrossp, possibleexp; // possible cross or extremalpoint + bool surecrossp, sureexp; // sure ... + + static ARRAY<int> locsurf; // attention: array is static + + static int cntbox = 0; + cntbox++; + + if (level <= boxesinlevel.Size()) + boxesinlevel.Elem(level)++; + else + boxesinlevel.Append (1); + + /* + numprim = sol -> NumPrimitives(); + sol -> GetSurfaceIndices (locsurf); + */ + + geometry -> GetIndependentSurfaceIndices (sol, box, locsurf); + int numprim = locsurf.Size(); + + numprim_hist[numprim]++; + + Point<3> p = box.Center(); + + + possiblecrossp = (numprim >= 3) && calccp; + surecrossp = 0; + + if (possiblecrossp && (locsurf.Size() <= 5 || 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)), p ); + + deg = CrossPointDegenerated + (geometry->GetSurface(locsurf.Get(k1)), + geometry->GetSurface(locsurf.Get(k2)), + geometry->GetSurface(locsurf.Get(k3)), box ); + + if (!nc && !deg) decision = 0; + if (nc) surecrossp = 1; + } + + if (decision && surecrossp) + { + for (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)), p ) ) + { + Point<3> pp = p; + CrossPointNewton + (geometry->GetSurface(locsurf.Get(k1)), + geometry->GetSurface(locsurf.Get(k2)), + geometry->GetSurface(locsurf.Get(k3)), pp); + + BoxSphere<3> hbox (pp, pp); + hbox.Increase (1e-8); + + if (pp(0) > box.PMin()(0) - 1e-5 && + pp(0) < box.PMax()(0) + 1e-5 && + pp(1) > box.PMin()(1) - 1e-5 && + pp(1) < box.PMax()(1) + 1e-5 && + pp(2) > box.PMin()(2) - 1e-5 && + pp(2) < box.PMax()(2) + 1e-5 && + sol -> IsIn (pp) && !sol->IsStrictIn (pp) && + !CrossPointDegenerated + (geometry->GetSurface(locsurf.Get(k1)), + geometry->GetSurface(locsurf.Get(k2)), + geometry->GetSurface(locsurf.Get(k3)), hbox )) + + { + // AddCrossPoint (locsurf, sol, p); + BoxSphere<3> boxp (pp, pp); + boxp.Increase (1e-3); + boxp.CalcDiamCenter(); + ARRAY<int> locsurf2; + + geometry -> GetIndependentSurfaceIndices (sol, boxp, locsurf2); + + bool found1 = 0, found2 = 0, found3 = 0; + for (int i = 0; i < locsurf2.Size(); i++) + { + if (locsurf2[i] == locsurf.Get(k1)) found1 = 1; + if (locsurf2[i] == locsurf.Get(k2)) found2 = 1; + if (locsurf2[i] == locsurf.Get(k3)) found3 = 1; + } + + 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; + + + if (numprim == 2) + { + const Surface * surf1 = geometry->GetSurface(locsurf[0]); + const Surface * surf2 = geometry->GetSurface(locsurf[1]); + + const Plane * plane1 = dynamic_cast<const Plane*> (surf1); + const Plane * plane2 = dynamic_cast<const Plane*> (surf2); + const QuadraticSurface * quadric1 = dynamic_cast<const QuadraticSurface*> (surf1); + const QuadraticSurface * quadric2 = dynamic_cast<const QuadraticSurface*> (surf2); + + if (plane1 && plane2) + possibleexp = 0; + else + { + ARRAY<Point<3> > pts; + if (plane1 && quadric2) + { + ComputeExtremalPoints (plane1, quadric2, pts); + possibleexp = 0; + } + else if (plane2 && quadric1) + { + ComputeExtremalPoints (plane2, quadric1, pts); + possibleexp = 0; + } + + for (int j = 0; j < pts.Size(); j++) + if (Dist (pts[j], box.Center()) < box.Diam()/2 && + sol -> IsIn (pts[j]) && !sol->IsStrictIn (pts[j]) ) + { + if (AddPoint (pts[j], layer)) + (*testout) << "Extremal point found: " << pts[j] << endl; + } + } + } + + + if (possibleexp && (locsurf.Size() <= 5 || 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; + } + } + + if (decision && sureexp) + { + for (int k1 = 0; k1 < locsurf.Size() - 1; k1++) + for (int k2 = k1+1; k2 < locsurf.Size(); k2++) + { + const Surface * surf1 = geometry->GetSurface(locsurf[k1]); + const Surface * surf2 = geometry->GetSurface(locsurf[k2]); + + if (EdgeNewtonConvergence (surf1, surf2, p)) + { + EdgeNewton (surf1, surf2, p); + + Point<3> pp; + if (IsEdgeExtremalPoint (surf1, surf2, p, pp, box.Diam()/2)) + { + (*testout) << "extremalpoint (nearly) found:" << pp << endl; + + if (Dist (pp, box.Center()) < box.Diam()/2 && + sol -> IsIn (pp) && !sol->IsStrictIn (pp) ) + { + if (AddPoint (pp, layer)) + (*testout) << "Extremal point found: " << pp << endl; + } + } + } + } + } + if (decision) + possibleexp = 0; + } + + + + if (possiblecrossp || possibleexp) + { + BoxSphere<3> sbox; + for (int i = 0; i < 8; i++) + { + box.GetSubBox (i, sbox); + sbox.Increase (1e-4 * sbox.Diam()); + + 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 Point<3> & p) + { + Vec<3> grad, rs, x; + Mat<3> jacobi, inv; + + 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); + + return (beta * gamma * eta < 0.1); + } + 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; + + p -= sol; + } + } + + + + + /******* Tests for Point on edges **********************/ + + + + + bool SpecialPointCalculation :: + EdgeNewtonConvergence (const Surface * f1, const Surface * f2, + const Point<3> & p) + { + Vec<3> g1, g2, sol; + Vec<2> vrs; + Mat<2,3> mat; + Mat<3,2> inv; + + f1->CalcGradient (p, g1); + f2->CalcGradient (p, g2); + + if ( sqr(g1 * g2) < (1 - 1e-8) * Abs2 (g1) * Abs2 (g2)) + { + double gamma = f1 -> HesseNorm() + f2 -> HesseNorm(); + if (gamma < 1e-32) return 1; + gamma = sqr (gamma); + + for (int i = 0; i < 3; i++) + { + mat(0,i) = g1(i); + mat(1,i) = g2(i); + } + + CalcInverse (mat, inv); + + vrs(0) = f1->CalcFunctionValue (p); + vrs(1) = f2->CalcFunctionValue (p); + sol = inv * vrs; + + double beta = 0; + for (int i = 0; i < 3; i++) + for (int j = 0; j < 2; j++) + beta += inv(i,j) * inv(i,j); + // beta = sqrt (beta); + + double eta = Abs2 (sol); + + // alpha = beta * gamma * eta; + return (beta * gamma * eta < 0.01); + } + return 0; + } + + + + + bool SpecialPointCalculation :: + EdgeDegenerated (const Surface * f1, + const Surface * f2, + const BoxSphere<3> & box) const + { + // perform newton steps. normals parallel ? + // if not decideable: return 0 + + Point<3> p = box.Center(); + Vec<3> g1, g2, sol; + Vec<2> vrs; + Mat<2,3> mat; + + int i = 20; + while (i > 0) + { + if (Dist2 (p, box.Center()) > sqr(box.Diam())) + return 0; + + i--; + vrs(0) = f1->CalcFunctionValue (p); + vrs(1) = f2->CalcFunctionValue (p); + + f1->CalcGradient (p, g1); + f2->CalcGradient (p, g2); + + if ( sqr (g1 * g2) > (1 - 1e-10) * Abs2 (g1) * Abs2 (g2)) + return 1; + + for (int j = 0; j < 3; j++) + { + mat(0,j) = g1(j); + mat(1,j) = g2(j); + } + mat.Solve (vrs, sol); + + if (Abs2 (sol) < 1e-24 && i > 1) i = 1; + p -= sol; + } + + return 0; + } + + + + + + + void SpecialPointCalculation :: EdgeNewton (const Surface * f1, + const Surface * f2, Point<3> & p) + { + Vec<3> g1, g2, sol; + Vec<2> vrs; + Mat<2,3> mat; + + int i = 10; + while (i > 0) + { + i--; + vrs(0) = f1->CalcFunctionValue (p); + vrs(1) = f2->CalcFunctionValue (p); + + f1->CalcGradient (p, g1); + f2->CalcGradient (p, g2); + + 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); + + jacobi.Solve (rs, x); + + if (Abs2 (x) < 1e-24 && i > 1) + { + i = 1; + } + + 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 :: + ComputeExtremalPoints (const Plane * plane, + const QuadraticSurface * quadric, + ARRAY<Point<3> > & pts) + { + // 3 equations: + // surf1 = 0 <===> plane_a + plane_b x = 0; + // surf2 = 0 <===> quad_a + quad_b x + x^T quad_c x = 0 + // (grad 1 x grad 2)(i) = 0 <====> (grad 1 x e_i) . grad_2 = 0 + + pts.SetSize (0); + + Point<3> p0(0,0,0); + double plane_a, quad_a; + Vec<3> plane_b, quad_b, ei; + Mat<3> quad_c; + + plane_a = plane -> CalcFunctionValue(p0); + plane -> CalcGradient (p0, plane_b); + + quad_a = quadric -> CalcFunctionValue(p0); + quadric -> CalcGradient (p0, quad_b); + quadric -> CalcHesse (p0, quad_c); + for (int i = 0; i < 3; i++) + for (int j = 0; j < 3; j++) + quad_c(i,j) *= 0.5; + + for (int dir = 0; dir <= 2; dir++) + { + ei = 0.0; ei(dir) = 1; + Vec<3> v1 = Cross (plane_b, ei); + + // grad_2 . v1 ... linear: + double g2v1_c = v1 * quad_b; + Vec<3> g2v1_l = 2.0 * (quad_c * v1); + + // find line of two linear equations: + + Vec<2> rhs; + Vec<3> sol; + Mat<2,3> mat; + + for (int j = 0; j < 3; j++) + { + mat(0,j) = plane_b(j); + mat(1,j) = g2v1_l(j); + } + rhs(0) = -plane_a; + rhs(1) = -g2v1_c; + + Vec<3> t = Cross (plane_b, g2v1_l); + if (Abs2(t) > 0) + { + mat.Solve (rhs, sol); + + // solve quadratic equation along line sol + alpha t .... + double a = quad_a + quad_b * sol + sol * (quad_c * sol); + double b = quad_b * t + 2 * (sol * (quad_c * t)); + double c = t * (quad_c * t); + + // solve a + b alpha + c alpha^2: + + if (fabs (c) > 1e-32) + { + double disc = sqr (0.5*b/c) - a/c; + if (disc > 0) + { + disc = sqrt (disc); + double alpha1 = -0.5*b/c + disc; + double alpha2 = -0.5*b/c - disc; + + pts.Append (Point<3> (sol+alpha1*t)); + pts.Append (Point<3> (sol+alpha2*t)); + /* + cout << "sol1 = " << sol + alpha1 * t + << ", sol2 = " << sol + alpha2 * t << endl; + */ + } + } + } + } + } + + + + + + + /* + 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 0; + + points->Append (MeshPoint(p, layer)); + PrintMessageCR (3, "Found points ", points->Size()); + return 1; + } + + + + + + + + void SpecialPointCalculation :: + AnalyzeSpecialPoints (const CSGeometry & ageometry, + ARRAY<MeshPoint> & apoints, + ARRAY<SpecialPoint> & specpoints) + { + ARRAY<int> surfind; + ARRAY<int> surfind2; + + ARRAY<Vec<3> > normalvecs; + Vec<3> t, nsurf; + Point<3> p; + + ARRAY<int> specpoint2point; + specpoints.SetSize (0); + + geometry = &ageometry; + + (*testout) << "AnalyzeSpecialPoints\n"; + + + Box<3> bbox; + if (apoints.Size()) + bbox.Set (apoints[0]); + else + { bbox.Set (Point<3> (0,0,0)); bbox.Add (Point<3> (1,1,1)); } + for (int i = 1; i < apoints.Size(); i++) + bbox.Add (apoints[i]); + bbox.Increase (0.1 * Dist (bbox.PMin(), bbox.PMax())); + + Point3dTree searchtree (bbox.PMin(), bbox.PMax()); + ARRAY<int> locsearch; + + for (int si = 0; si < ageometry.GetNTopLevelObjects(); si++) + { + // (*testout) << "main solid " << si << "\n"; + + const Solid * sol = ageometry.GetTopLevelObject(si)->GetSolid(); + const Surface * surf = ageometry.GetTopLevelObject(si)->GetSurface(); + + for (int i = 0; i < apoints.Size(); i++) + { + p = apoints[i]; + if (ageometry.GetTopLevelObject(si)->GetLayer() != + apoints[i].GetLayer()) + continue; + + // (*testout) << "Point " << apoints[i] << "\n"; + + Solid * locsol; + sol -> TangentialSolid (p, locsol); + if (!locsol) continue; + + // get all surface indices, + if (surf) + { + locsol -> GetSurfaceIndices (surfind); + bool hassurf = 0; + for (int m = 0; m < surfind.Size(); m++) + if (ageometry.GetSurface(surfind[m]) == surf) + hassurf = 1; + + if (!hassurf) + continue; + + nsurf = surf->GetNormalVector (p); + } + + // get independent surfaces of tangential solid + + BoxSphere<3> box(p,p); + box.Increase (1e-6); + box.CalcDiamCenter(); + ageometry.GetIndependentSurfaceIndices (locsol, box, 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 = j+1; k < normalvecs.Size(); k++) + for (int l = 1; l <= 2; l++) + { + t = Cross (normalvecs[j], normalvecs[k]); + if (Abs2 (t) < 1e-8) + { + cerr << "AnalyzePoint: Surfaces degenerated" << "\n"; + break; + } + t.Normalize(); + if (l == 2) t *= -1; + + // try tangential direction t + + // (*testout) << "check tangential " << t << "\n"; + + if (surf && fabs (nsurf * t) > 1e-6) + continue; + + if (!surf) + { + ageometry.GetIndependentSurfaceIndices + (locsol, p, t, surfind2); + + bool found1 = 0, found2 = 0; + for (int ii = 0; ii < surfind2.Size(); ii++) + { + if (surfind2[ii] == surfind[j]) + found1 = 1; + if (surfind2[ii] == surfind[k]) + found2 = 1; + } + if (!found1 || !found2) + continue; + } + + + bool isedge; + + // isedge = locsol -> Edge (apoints.Get(i), t); + + // edge must be on tangential surface + isedge = + locsol->VectorIn (p, t) && + !locsol->VectorStrictIn (p, t); + + // (*testout) << "isedge,1 = " << isedge << "\n"; + + // there must exist at least two different faces on edge + if (isedge) + { + int cnts = 0; + for (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; + + /* + (*testout) << "nv = " << normalvecs[m] << ", s = " << s << "\n"; + (*testout) << "t2a = " << t2a << ", t2b = " << t2b << "\n"; + (*testout) << "via = " + << locsol->VectorIn (p, t2a) << "/" + << locsol->VectorStrictIn (p, t2a); + (*testout) << "vib = " + << locsol->VectorIn (p, t2b) << "/" + << locsol->VectorStrictIn (p, t2b) << "\n"; + */ + + bool isface = + (locsol->VectorIn (p, t2a) && + !locsol->VectorStrictIn (p, t2a)) + || + (locsol->VectorIn (p, t2b) && + !locsol->VectorStrictIn (p, t2b)); + + if (isface) + { + cnts++; + } + } + if (cnts < 2) isedge = 0; + } + + if (isedge) + { + int spi = -1; + + searchtree.GetIntersecting (apoints[i]-Vec3d(1e-4,1e-4,1e-4), + apoints[i]+Vec3d(1e-4,1e-4,1e-4), + locsearch); + + for (int m = 0; m < locsearch.Size(); m++) + if (Dist2 (specpoints[locsearch[m]].p, apoints[i]) < 1e-8 + && Abs2(specpoints[locsearch[m]].v - t) < 1e-8) + { + spi = locsearch[m]; + break; + } + + + if (spi == -1) + { + spi = specpoints.Append (SpecialPoint()) - 1; + specpoint2point.Append (i); + specpoints.Last().unconditional = 0; + searchtree.Insert (apoints[i], spi); + } + + specpoints[spi].p = apoints[i]; + specpoints[spi].v = t; + if (surfind.Size() >= 3) + specpoints[spi].unconditional = 1; + specpoints[spi].s1 = surfind[j]; + specpoints[spi].s2 = surfind[k]; + specpoints[spi].layer = apoints[i].GetLayer(); + for (int up = 0; up < geometry->GetNUserPoints(); up++) + if (Dist (geometry->GetUserPoint(up), apoints[i]) < 1e-10) + specpoints[spi].unconditional = 1; + } + + } + delete locsol; + } + } + + // if special point is unconditional on some solid, + // it must be unconditional everywhere: + + BitArray uncond (apoints.Size()); + uncond.Clear(); + + for (int i = 0; i < specpoints.Size(); i++) + if (specpoints[i].unconditional) + uncond.Set (specpoint2point[i]); + + for (int i = 0; i < specpoints.Size(); i++) + specpoints[i].unconditional = + uncond.Test (specpoint2point[i]) ? 1 : 0; + } +} diff --git a/contrib/Netgen/libsrc/csg/specpoin.hpp b/contrib/Netgen/libsrc/csg/specpoin.hpp new file mode 100644 index 0000000000..8fd26f3207 --- /dev/null +++ b/contrib/Netgen/libsrc/csg/specpoin.hpp @@ -0,0 +1,150 @@ +#ifndef FILE_SPECPOIN +#define FILE_SPECPOIN + + +/**************************************************************************/ +/* File: specpoin.hpp */ +/* Author: Joachim Schoeberl */ +/* Date: 01. Okt. 95 */ +/**************************************************************************/ + +/* + +Special Point Calculation + +*/ + +class Surface; +class Solid; + +/// Special point. +class SpecialPoint +{ +public: + /// coordinates + Point<3> p; + /// tangential to edge + Vec<3> v; + /// + int layer; + /// point must be used in mesh + bool unconditional; + + /// surfaces defining edge + int s1, s2; + + /// + SpecialPoint () : p(0,0,0), v(0,0,0), layer(0), unconditional(0), s1(0), s2(0) + { ; } + + /// + SpecialPoint (const SpecialPoint & sp2); + + /// + SpecialPoint & operator= (const SpecialPoint & sp2); + + /// + void Print (ostream & str); + + + int GetLayer() const { return layer; } + + /// + bool HasSurfaces (int as1, int as2) const + { + return (s1 == as1 && s2 == as2 || s1 == as2 && s2 == as1); + } +}; + + + +/// +class SpecialPointCalculation +{ +private: + /// + const CSGeometry * geometry; + /// + ARRAY<MeshPoint> * points; + /// + ARRAY<long int> boxesinlevel; + + /// + double size; + /// + double relydegtest; // maximal dimension of bisection intervall for + /// test of degeneration parameters + double cpeps1, epeps1, epeps2, epspointdist2; + +public: + + /// + SpecialPointCalculation (); + + /// + void CalcSpecialPoints (const CSGeometry & ageometry, + ARRAY<MeshPoint> & points); + /// + void AnalyzeSpecialPoints (const CSGeometry & geometry, + ARRAY<MeshPoint> & points, + ARRAY<SpecialPoint> & specpoints); + +protected: + /// + void CalcSpecialPointsRec (const Solid * sol, int layer, + const BoxSphere<3> & box, + int level, + bool calccp, bool calcep); + + + /// + bool CrossPointNewtonConvergence (const Surface * f1, const Surface * f2, + const Surface * f3, const Point<3> & p); + /// + bool CrossPointDegenerated (const Surface * f1, const Surface * f2, + const Surface * f3, const BoxSphere<3> & box) const; + /// + void CrossPointNewton (const Surface * f1, const Surface * f2, + const Surface * f3, Point<3> & p); + + bool EdgeNewtonConvergence (const Surface * f1, const Surface * f2, + const Point<3> & p); + /// + bool EdgeDegenerated (const Surface * f1, const Surface * f2, + const BoxSphere<3> & box) const; + /// + void EdgeNewton (const Surface * f1, const Surface * f2, + Point<3> & p); + /// + bool IsEdgeExtremalPoint (const Surface * f1, const Surface * f2, + const Point<3> & p, Point<3> & pp, double rad); + + + + /* + /// + bool ExtremalPointPossible (const Surface * f1, const Surface * f2, + int dir, const BoxSphere<3> & box); + /// + bool ExtremalPointDegenerated (const Surface * f1, const Surface * f2, + int dir, const BoxSphere<3> & box); + /// + bool ExtremalPointNewtonConvergence (const Surface * f1, const Surface * f2, + int dir, const BoxSphere<3> & box); + */ + /// + void ExtremalPointNewton (const Surface * f1, const Surface * f2, + int dir, Point<3> & p); + + + /// + bool AddPoint (const Point<3> & p, int layer); + + void ComputeExtremalPoints (const Plane * plane, + const QuadraticSurface * quadric, + ARRAY<Point<3> > & pts); +}; + +#endif + + diff --git a/contrib/Netgen/libsrc/csg/specpoin_new.cpp b/contrib/Netgen/libsrc/csg/specpoin_new.cpp new file mode 100644 index 0000000000..4ac2c130fa --- /dev/null +++ b/contrib/Netgen/libsrc/csg/specpoin_new.cpp @@ -0,0 +1,1367 @@ +#include <mystdlib.h> +#include <meshing.hpp> +#include <csg.hpp> + + +/* + Special Point calculation uses the global Flags: + + size .. 500 cube = [-size, size]^3 + relydegtest when to rely on degeneration ? + calccp calculate points of intersection ? + cpeps1 eps for degenerated poi + calcep calculate points of extreme coordinates ? + epeps1 eps for degenerated edge + epeps2 eps for axis parallel pec + epspointdist eps for distance of special points +*/ + + +namespace netgen +{ +void ProjectToEdge (const Surface * f1, const Surface * f2, Point<3> & hp); + + + +SpecialPoint :: SpecialPoint (const SpecialPoint & sp) +{ + p = sp.p; + v = sp.v; + s1 = sp.s1; + s2 = sp.s2; + layer = sp.layer; + unconditional = sp.unconditional; +} + +SpecialPoint & SpecialPoint :: operator= (const SpecialPoint & sp) +{ + p = sp.p; + v = sp.v; + s1 = sp.s1; + s2 = sp.s2; + layer = sp.layer; + unconditional = sp.unconditional; + return *this; +} + + +void SpecialPoint :: Print (ostream & str) +{ + str << "p = " << p << " v = " << v + << " s1/s2 = " << s1 << "/" << s2 + << " layer = " << layer + << endl; +} + + + + +SpecialPointCalculation :: SpecialPointCalculation () +{ + ; +} + +void SpecialPointCalculation :: +CalcSpecialPoints (const CSGeometry & ageometry, + ARRAY<MeshPoint> & apoints) +{ + int i; + + geometry = &ageometry; + points = &apoints; + + size = geometry->MaxSize(); + (*testout) << "Find Special Points" << endl; + (*testout) << "maxsize = " << size << endl; + + cpeps1 = 1e-6; + epeps1 = 1e-3; + epeps2 = 1e-6; + + epspointdist2 = sqr (size * 1e-8); + relydegtest = size * 1e-4; + + + BoxSphere<3> box (Point<3> (-size, -size, -size), + Point<3> ( size, size, size)); + + box.CalcDiamCenter(); + PrintMessage (3, "main-solids: ", geometry->GetNTopLevelObjects()); + + for (i = 0; i < geometry->GetNTopLevelObjects(); i++) + { + (*testout) << "tlo " << i << ":" << endl; + const TopLevelObject * tlo = geometry->GetTopLevelObject(i); + tlo->GetSolid()->Print (*testout); + (*testout) << endl; + CalcSpecialPointsRec (tlo->GetSolid(), tlo->GetLayer(), + box, 1, 1, 1); + } + + PrintDot ('\n'); + + + // add user point: + for (i = 0; i < geometry->GetNUserPoints(); i++) + AddPoint (geometry->GetUserPoint(i), 1); + + PrintMessage (3, apoints.Size(), " special points"); + + for (i = 0; i < boxesinlevel.Size(); i++) + (*testout) << "level " << i << " has " + << boxesinlevel[i] << " boxes" << endl; +} + + + +// int debug; +void SpecialPointCalculation :: +CalcSpecialPointsRec (const Solid * sol, int layer, + const BoxSphere<3> & box, + int level, bool calccp, bool calcep) +{ + if (multithread.terminate) + return; + + int i; + BoxSphere<3> sbox; + Solid * redsol; + + int numprim; + + bool decision; + bool possiblecrossp, possibleexp; // possible cross or extremalpoint + bool surecrossp, sureexp; // sure ... + + static ARRAY<int> locsurf; // attention: array is static + + + Point<3> p; + int k1, k2, k3; + int extremdir; + double hd; + + if (!sol) return; + + if (level >= 100) + { + cerr << "Problems in CalcSpecialPoints" << endl; + cerr << "Point: " << box.Center() << endl; + exit (1); + } + + static int cntbox = 0; + cntbox++; + if (cntbox % 10000 == 0) + PrintDot (); + + if (level <= boxesinlevel.Size()) + boxesinlevel.Elem(level)++; + else + boxesinlevel.Append (1); + + /* + numprim = sol -> NumPrimitives(); + sol -> GetSurfaceIndices (locsurf); + */ + + // debug = 0; + // box.IsIn (Point<3> (4.9, 1.279, 2.8)); + + + geometry -> GetIndependentSurfaceIndices (sol, box, locsurf); + numprim = locsurf.Size(); + + /* + if (debug) + { + (*testout) << "box = " << box.PMin() << "-" << box.PMax() + << " np = " << numprim << " : "; + for (i = 1; i <= locsurf.Size(); i++) + (*testout) << " " << locsurf.Get(i); + (*testout) << " diam = " << box.Diam(); + (*testout) << " numprim = " << numprim; + (*testout) << endl; + } + */ + + + p = box.Center(); + + /* + (*testout) << "box = " << box.PMin() << " - " << box.PMax() + << ", lev = " << level + << ", nprim = " << sol->NumPrimitives() + << ", lsurf = " << locsurf.Size() << endl; + + for (i = 1; i <= locsurf.Size(); i++) + geometry->GetSurface (locsurf.Get(i)) -> Print (*testout); + sol -> Print (*testout); + */ + + /* + for (i = 1; i <= locsurf.Size(); i++) + (*testout) << locsurf.Get(i) << " "; + (*testout) << "C = " << box.Center() << " diam = " << box.Diam() << endl; + */ + + possiblecrossp = (numprim >= 3) && calccp; + surecrossp = 0; + + if (possiblecrossp && (locsurf.Size() <= 10)) + { + decision = 1; + surecrossp = 0; + + for (k1 = 1; k1 <= locsurf.Size() - 2; k1++) + for (k2 = k1 + 1; k2 <= locsurf.Size() - 1; k2++) + for (k3 = k2 + 1; k3 <= locsurf.Size(); k3++) + { + int nc, deg; + nc = CrossPointNewtonConvergence + (geometry->GetSurface(locsurf.Get(k1)), + geometry->GetSurface(locsurf.Get(k2)), + geometry->GetSurface(locsurf.Get(k3)), p ); + + deg = CrossPointDegenerated + (geometry->GetSurface(locsurf.Get(k1)), + geometry->GetSurface(locsurf.Get(k2)), + geometry->GetSurface(locsurf.Get(k3)), box ); + + if (!nc && !deg) decision = 0; + if (nc) surecrossp = 1; + } + + if (decision && surecrossp) + { + for (k1 = 1; k1 <= locsurf.Size() - 2; k1++) + for (k2 = k1 + 1; k2 <= locsurf.Size() - 1; k2++) + for (k3 = k2 + 1; k3 <= locsurf.Size(); k3++) + { + if (CrossPointNewtonConvergence + (geometry->GetSurface(locsurf.Get(k1)), + geometry->GetSurface(locsurf.Get(k2)), + geometry->GetSurface(locsurf.Get(k3)), p ) ) + { + Point<3> pp = p; + CrossPointNewton + (geometry->GetSurface(locsurf.Get(k1)), + geometry->GetSurface(locsurf.Get(k2)), + geometry->GetSurface(locsurf.Get(k3)), pp); + + BoxSphere<3> hbox (pp, pp); + hbox.Increase (1e-8); + + if (pp(0) > box.PMin()(0) - 1e-5 && + pp(0) < box.PMax()(0) + 1e-5 && + pp(1) > box.PMin()(1) - 1e-5 && + pp(1) < box.PMax()(1) + 1e-5 && + pp(2) > box.PMin()(2) - 1e-5 && + pp(2) < box.PMax()(2) + 1e-5 && + sol -> IsIn (pp) && !sol->IsStrictIn (pp) && + !CrossPointDegenerated + (geometry->GetSurface(locsurf.Get(k1)), + geometry->GetSurface(locsurf.Get(k2)), + geometry->GetSurface(locsurf.Get(k3)), hbox )) + + { + // AddCrossPoint (locsurf, sol, p); + BoxSphere<3> boxp (pp, pp); + boxp.Increase (1e-3); + boxp.CalcDiamCenter(); + ARRAY<int> locsurf2; + + geometry -> GetIndependentSurfaceIndices (sol, boxp, locsurf2); + + /* + ReducePrimitiveIterator rpi(boxp); + UnReducePrimitiveIterator urpi; + + ((Solid*)sol) -> IterateSolid (rpi); + sol -> GetIndependentSurfaceIndices (locsurf2); + ((Solid*)sol) -> IterateSolid (urpi); + */ + bool found1 = 0, found2 = 0, found3 = 0; + for (i = 1; i <= locsurf2.Size(); i++) + { + if (locsurf2.Get(i) == locsurf.Get(k1)) + found1 = 1; + if (locsurf2.Get(i) == locsurf.Get(k2)) + found2 = 1; + if (locsurf2.Get(i) == locsurf.Get(k3)) + found3 = 1; + } + + if (found1 && found2 && found3) + if (AddPoint (pp, layer)) + { + (*testout) << "Crosspoint found: " << pp + << " diam = " << box.Diam() << endl; + (*testout) << "surfs: " + << locsurf.Get(k1) << "," + << locsurf.Get(k2) << "," + << locsurf.Get(k3) << endl; + } + } + } + } + } + + if (decision) + possiblecrossp = 0; + } + + + + + possibleexp = (numprim >= 2) && calcep; + + if (possibleexp && (locsurf.Size() <= 10)) + { + decision = 1; + sureexp = 0; + + for (k1 = 1; k1 <= locsurf.Size() - 1; k1++) + for (k2 = k1+1; k2 <= locsurf.Size(); k2++) + { + bool nc, deg; + + nc = EdgeNewtonConvergence + (geometry->GetSurface(locsurf.Get(k1)), + geometry->GetSurface(locsurf.Get(k2)), + p); + + deg = EdgeDegenerated + (geometry->GetSurface(locsurf.Get(k1)), + geometry->GetSurface(locsurf.Get(k2)), + box); + + if (!nc && !deg) decision = 0; + if (nc) sureexp = 1; + + /* + if (debug) + { + (*testout) << "p = " << p << " s1,2 = " << locsurf.Get(k1) << ", " << locsurf.Get(k2) + << " nc = " << nc << " deg = " << deg << endl; + } + */ + } + + if (decision && sureexp) + { + for (k1 = 1; k1 <= locsurf.Size() - 1; k1++) + for (k2 = k1+1; k2 <= locsurf.Size(); k2++) + { + if ( + EdgeNewtonConvergence + (geometry->GetSurface(locsurf.Get(k1)), + geometry->GetSurface(locsurf.Get(k2)), + p) ) + { + EdgeNewton + (geometry->GetSurface(locsurf.Get(k1)), + geometry->GetSurface(locsurf.Get(k2)), + p); + + Point<3> pp; + if (IsEdgeExtremalPoint + (geometry->GetSurface(locsurf.Get(k1)), + geometry->GetSurface(locsurf.Get(k2)), + p, pp, box.Diam()/2)) + { + (*testout) << "extremalpoint (nearly) found:" + << pp + << endl; + if (Dist (pp, box.Center()) < box.Diam()/2 && + sol -> IsIn (pp) && !sol->IsStrictIn (pp) ) + { + // AddExtremalPoint (locsurf.Get(k1), locsurf.Get(k2), p); + if (AddPoint (pp, layer)) + (*testout) << "Extremal point found: " << pp << endl; + } + } + } + } + } + if (decision) + possibleexp = 0; + } + + + + if (possiblecrossp || possibleexp) + { + for (i = 0; i < 8; i++) + { + box.GetSubBox (i, sbox); + sbox.Increase (1e-4 * sbox.Diam()); + + redsol = sol -> GetReducedSolid (sbox); + + if (redsol) + { + CalcSpecialPointsRec (redsol, layer, sbox, level+1, calccp, calcep); + delete redsol; + } + } + } +} + + + + + +/******* Tests for Point of intersection **********************/ + + + +bool SpecialPointCalculation :: +CrossPointNewtonConvergence (const Surface * f1, + const Surface * f2, + const Surface * f3, + const Point<3> & p) +{ + int i; + Vec<3> grad; + Vec<3> rs, x; + Mat<3> jacobi, inv; + double alpha, beta, gamma, eta; + double sum; + int j; + + + rs(0) = f1->CalcFunctionValue (p); + rs(1) = f2->CalcFunctionValue (p); + rs(2) = f3->CalcFunctionValue (p); + + f1->CalcGradient (p, grad); + jacobi(0,0) = grad(0); + jacobi(0,1) = grad(1); + jacobi(0,2) = grad(2); + + f2->CalcGradient (p, grad); + jacobi(1,0) = grad(0); + jacobi(1,1) = grad(1); + jacobi(1,2) = grad(2); + + f3->CalcGradient (p, grad); + jacobi(2,0) = grad(0); + jacobi(2,1) = grad(1); + jacobi(2,2) = grad(2); + + alpha = 1; + if (fabs (Det (jacobi)) > 1e-8) + { + CalcInverse (jacobi, inv); + x = inv * rs; + + gamma = f1 -> HesseNorm() + f2 -> HesseNorm() + f3 -> HesseNorm(); + beta = 0; + for (i = 0; i < 3; i++) + { + sum = 0; + for (j = 0; j < 3; j++) + sum += fabs (inv(i,j)); + beta = max2 (beta, sum); + } + eta = Abs (x); + + alpha = beta * gamma * eta; + } + + return (alpha < 0.1); +} + + + + +bool SpecialPointCalculation :: +CrossPointDegenerated (const Surface * f1, + const Surface * f2, + const Surface * f3, + const BoxSphere<3> & box) const +{ + Mat<3> mat; + Vec<3> grad, g1, g2, g3; + double normprod; + + if (box.Diam() > relydegtest) return 0; + + f1->CalcGradient (box.Center(), g1); + normprod = Abs (g1); + + f2->CalcGradient (box.Center(), g2); + normprod *= Abs (g2); + + f3->CalcGradient (box.Center(), g3); + normprod *= Abs (g3); + + for (int i = 0; i < 3; i++) + { + mat(i,0) = g1(i); + mat(i,1) = g2(i); + mat(i,2) = g3(i); + } + + if (fabs (Det (mat)) < cpeps1 * normprod) + return 1; + else + return 0; +} + + + + + +void SpecialPointCalculation :: CrossPointNewton (const Surface * f1, + const Surface * f2, + const Surface * f3, Point<3> & p) +{ + int i; + Vec<3> g1, g2, g3; + Vec<3> rs, sol; + Mat<3> mat; + + i = 10; + while (i > 0) + { + i--; + rs(0) = f1->CalcFunctionValue (p); + rs(1) = f2->CalcFunctionValue (p); + rs(2) = f3->CalcFunctionValue (p); + + f1->CalcGradient (p, g1); + f2->CalcGradient (p, g2); + f3->CalcGradient (p, g3); + + for (int j = 0; j < 3; j++) + { + mat(0, j) = g1(j); + mat(1, j) = g2(j); + mat(2, j) = g3(j); + } + mat.Solve (rs, sol); + /* + Transpose (g1, g2, g3); + SolveLinearSystem (g1, g2, g3, rs, sol); + */ + if (sol.Length() < 1e-12 && i > 1) i = 1; + + p -= sol; + } +} + + + + +/******* Tests for Point on edges **********************/ + + + + +bool SpecialPointCalculation :: +EdgeNewtonConvergence (const Surface * f1, const Surface * f2, + const Point<3> & p) +{ + int i; + Vec<3> g1, g2, sol; + Vec<2> vrs; + double alpha, beta, gamma, eta; + double sum; + Mat<2,3> mat; + Mat<3,2> inv; + int j; + + vrs(0) = f1->CalcFunctionValue (p); + vrs(1) = f2->CalcFunctionValue (p); + + f1->CalcGradient (p, g1); + f2->CalcGradient (p, g2); + + for (i = 0; i < 3; i++) + { + mat(0,i) = g1(i); + mat(1,i) = g2(i); + } + + alpha = 1; + + if ( fabs(g1 * g2) < (1 - 1e-8) * Abs (g1) * Abs (g2)) + { + CalcInverse (mat, inv); + sol = inv * vrs; + + // SolveLinearSystemLS (g1, g2, vrs, sol); + + gamma = f1 -> HesseNorm() + f2 -> HesseNorm(); + + /* + Vec<3> inv1, inv2; + PseudoInverse (g1, g2, inv1, inv2); + */ + + beta = 0; + for (i = 0; i < 3; i++) + for (j = 0; j < 2; j++) + beta += inv(i,j) * inv(i,j); + beta = sqrt (beta); + + // beta = inv1.Length() + inv2.Length(); + eta = Abs (sol); + alpha = beta * gamma * eta; + } + return (alpha < 0.1); +} + + + + +bool SpecialPointCalculation :: +EdgeDegenerated (const Surface * f1, + const Surface * f2, + const BoxSphere<3> & box) const +{ + // perform newton steps. normals parallel ? + // if not decideable: return 0 + + + Point<3> p = box.Center(); + int i; + Vec<3> grad, g1, g2, sol; + Vec<2> vrs; + Mat<2,3> mat; + + i = 20; + while (i > 0) + { + if (Dist (p, box.Center()) > box.Diam()) + return 0; + + i--; + vrs(0) = f1->CalcFunctionValue (p); + vrs(1) = f2->CalcFunctionValue (p); + + f1->CalcGradient (p, g1); + f2->CalcGradient (p, g2); + + if ( fabs (g1 * g2) > (1 - 1e-10) * Abs (g1) * Abs (g2)) + return 1; + + for (int j = 0; j < 3; j++) + { + mat(0,j) = g1(j); + mat(1,j) = g2(j); + } + mat.Solve (vrs, sol); + // SolveLinearSystemLS (g1, g2, vrs, sol); + + if (Abs (sol) < 1e-12 && i > 1) i = 1; + p -= sol; + } + + return 0; +} + + + + + + +void SpecialPointCalculation :: EdgeNewton (const Surface * f1, + const Surface * f2, Point<3> & p) +{ + int i; + Vec<3> grad, g1, g2, sol; + Vec<2> vrs; + Mat<2,3> mat; + + i = 10; + while (i > 0) + { + i--; + vrs(0) = f1->CalcFunctionValue (p); + vrs(1) = f2->CalcFunctionValue (p); + + f1->CalcGradient (p, g1); + f2->CalcGradient (p, g2); + + for (int j = 0; j < 3; j++) + { + mat(0,j) = g1(j); + mat(1,j) = g2(j); + } + mat.Solve (vrs, sol); + // SolveLinearSystemLS (g1, g2, vrs, sol); + + if (Abs (sol) < 1e-12 && i > 1) i = 1; + p -= sol; + } +} + + + +bool SpecialPointCalculation :: +IsEdgeExtremalPoint (const Surface * f1, const Surface * f2, + const Point<3> & p, Point<3> & pp, double rad) +{ + Vec<3> g1, g2, t, t1, t2; + int j; + + f1->CalcGradient (p, g1); + f2->CalcGradient (p, g2); + + t = Cross (g1, g2); + t.Normalize(); + + Point<3> p1 = p + rad * t; + Point<3> p2 = p - rad * t; + + EdgeNewton (f1, f2, p1); + EdgeNewton (f1, f2, p2); + + + f1->CalcGradient (p1, g1); + f2->CalcGradient (p1, g2); + t1 = Cross (g1, g2); + t1.Normalize(); + + f1->CalcGradient (p2, g1); + f2->CalcGradient (p2, g2); + t2 = Cross (g1, g2); + t2.Normalize(); + + double val = 1e-8 * rad * rad; + for (j = 0; j < 3; j++) + if ( (t1(j) * t2(j) < -val) ) + { + pp = p; + ExtremalPointNewton (f1, f2, j+1, pp); + return 1; + } + + return 0; +} + + + + + + + + + +/********** Tests of Points of extremal coordinates ****************/ + + +void SpecialPointCalculation :: ExtremalPointNewton (const Surface * f1, + const Surface * f2, + int dir, Point<3> & p) +{ + int i; + + Vec<3> g1, g2, v, curv; + Vec<3> rs, x, y1, y2, y; + Mat<3> h1, h2; + Mat<3> jacobi; + + + if (dir < 1 || dir > 3) + { + cerr << "Error: Illegal extremdir" << endl; + return; + } + + i = 50; + while (i > 0) + { + i--; + rs(0) = f1->CalcFunctionValue (p); + rs(1) = f2->CalcFunctionValue (p); + + f1 -> CalcGradient (p, g1); + f2 -> CalcGradient (p, g2); + + f1 -> CalcHesse (p, h1); + f2 -> CalcHesse (p, h2); + + + v = Cross (g1, g2); + + rs(2) = v(dir-1); + + jacobi(0,0) = g1(0); + jacobi(0,1) = g1(1); + jacobi(0,2) = g1(2); + + jacobi(1,0) = g2(0); + jacobi(1,1) = g2(1); + jacobi(1,2) = g2(2); + + + switch (dir) + { + case 1: + { + y1(0) = 0; + y1(1) = g2(2); + y1(2) = -g2(1); + y2(0) = 0; + y2(1) = -g1(2); + y2(2) = g1(1); + break; + } + case 2: + { + y1(0) = -g2(2); + y1(1) = 0; + y1(2) = g2(0); + y2(0) = g1(2); + y2(1) = 0; + y2(2) = -g1(0); + break; + } + case 3: + { + y1(0) = g2(1); + y1(1) = -g2(0); + y1(2) = 0; + y2(0) = -g1(1); + y2(1) = g1(0); + y2(2) = 0; + break; + } + } + + y = h1 * y1 + h2 * y2; + + jacobi(2,0) = y(0); + jacobi(2,1) = y(1); + jacobi(2,2) = y(2); + + jacobi.Solve (rs, x); + /* + CalcInverse (jacobi, inv); + inv.Mult (rs, x); + */ + // (*testout) << "err = " << x.L2Norm() << endl; + + if (Abs (x) < 1e-12 && i > 1) + { + // (*testout) << "convergent in " << (10 - i) << " steps " << endl; + + i = 1; + } + + p -= x; + } + + if (Abs (x) > 1e-10) + { + (*testout) << "Error: extremum Newton not convergent" << endl; + (*testout) << "dir = " << dir << endl; + (*testout) << "p = " << p << endl; + (*testout) << "x = " << x << endl; + } +} + + + + +bool SpecialPointCalculation :: ExtremalPointPossible (const Surface * f1, + const Surface * f2, + int dir, + const BoxSphere<3> & box) +{ + double hn1, hn2, gn1, gn2; + Point<3> p; + Vec<3> g1, g2, v; + double f3; + double r = box.Diam()/2; + + p = box.Center(); + + f1 -> CalcGradient (p, g1); + f2 -> CalcGradient (p, g2); + + gn1 = g1.Length(); + gn2 = g2.Length(); + + hn1 = f1 -> HesseNorm (); + hn2 = f2 -> HesseNorm (); + + v = Cross (g1, g2); + f3 = fabs (v(dir-1)); + + // (*testout) << "f3 = " << f3 << " r = " << r + // << "normbound = " + // << (hn1 * (gn2 + r * hn2) + hn2 * (gn1 + r * hn1)) << endl; + + return (f3 <= 3 * r * (hn1 * (gn2 + r * hn2) + hn2 * (gn1 + r * hn1))); +} + + + +bool SpecialPointCalculation :: +ExtremalPointNewtonConvergence (const Surface * f1, const Surface * f2, + int dir, + const BoxSphere<3> & box) +{ + return box.Diam() < 1e-8; +} + + +bool SpecialPointCalculation :: +ExtremalPointDegenerated (const Surface * f1, const Surface * f2, + int dir, const BoxSphere<3> & box) +{ + double gn1, gn2; + Point<3> p; + Vec<3> g1, g2, v; + double maxderiv; + double minv; + Vec<3> curv, t; + Vec<2> rs, x; + Mat<3> h1, h2; + Mat<2> a, inv; + double leftside; + + if (box.Diam() > relydegtest) return 0; + + p = box.Center(); + + f1 -> CalcGradient (p, g1); + f2 -> CalcGradient (p, g2); + gn1 = g1.Length(); + gn2 = g2.Length(); + + v = Cross (g1, g2); + if (Abs (v) < epeps1 * gn1 * gn2) return 1; // irregular edge + + f1 -> CalcHesse (p, h1); + f2 -> CalcHesse (p, h2); + + // hn1 = f1 -> HesseNorm (); + // hn2 = f2 -> HesseNorm (); + + t = v; + a(0, 0) = g1 * g1; + a(0, 1) = + a(1, 0) = g1 * g2; + a(1, 1) = g2 * g2; + + rs(0) = g1(dir-1); + rs(1) = g2(dir-1); + + a.Solve (rs, x); + + /* + CalcInverse (a, inv); + inv.Mult (rs, x); // x .. Lagrangeparameter + */ + // (*testout) << "g1 = " << g1 << " g2 = " << g2 << endl; + // (*testout) << "lam = " << x << endl; + // (*testout) << "h2 = " << h2 << endl; + + leftside = fabs (x(0) * ( t * (h1 * t)) + + x(1) * ( t * (h2 * t))); + + // (*testout) << "leftside = " << leftside << endl; + + if (leftside < epeps2 * Abs2 (v)) return 1; + + return 0; +} + + + +bool SpecialPointCalculation :: AddPoint (const Point<3> & p, int layer) +{ + for (int i = 0; i < points->Size(); i++) + if (Dist2 ( (*points)[i], p) < epspointdist2 && + (*points)[i].GetLayer() == layer) + return 0; + + points->Append (MeshPoint(p, layer)); + return 1; +} + + + + + + + +/* +void SpecialPointCalculation :: +AnalyzeSpecialPoints (const CSGeometry & ageometry, + ARRAY<Point<3> > & apoints, + ARRAY<SpecialPoint> & specpoints) +{ + int si, i, j, k, l, m, spi; + Solid * locsol; + ARRAY<int> surfind; + ARRAY<Vec<3>> normalvecs; + const Solid * sol; + Vec<3> t; + Point<3> p; + + ARRAY<int> specpoint2point; + specpoints.SetSize (0); + + (*testout) << "AnalyzeSpecialPoints" << endl; + + for (si = 1; si <= ageometry.GetNTopLevelObjects(); si++) + { + (*testout) << "main solid " << si << endl; + + sol = ageometry.GetTopLevelObject(si)->GetSolid(); + for (i = 1; i <= apoints.Size(); i++) + { + p = apoints.Get(i); + + sol -> TangentialSolid (p, locsol); + if (!locsol) continue; + + (*testout) << "Point " << apoints.Get(i) << endl; + + locsol -> GetSurfaceIndices (surfind); + for (j = surfind.Size(); j >= 1; j--) + if (fabs (ageometry.GetSurface(surfind.Get(j))-> + CalcFunctionValue (p)) > 1e-6) + surfind.DeleteElement (j); + + + + (*testout) << "Surfaces: "; + for (j = 1; j <= surfind.Size(); j++) + (*testout) << surfind.Get(j) << " "; + (*testout) << endl; + + normalvecs.SetSize(surfind.Size()); + for (j = 1; j <= surfind.Size(); j++) + ageometry.GetSurface(surfind.Get(j)) -> + GetNormalVector(apoints.Get(i), normalvecs.Elem(j)); + + for (j = 1; j <= normalvecs.Size() - 1; j ++) + for (k = j+1; k <= normalvecs.Size(); k++) + for (l = 1; l <= 2; l++) + { + t = Cross (normalvecs.Get(j), normalvecs.Get(k)); + if (t.Length2() < 1e-8) + { + cerr << "AnalyzePoint: Surfaces degenerated" << endl; + break; + } + t /= t.Length(); + if (l == 2) t *= -1; + + if (locsol -> Edge (apoints.Get(i), t)) + { + spi = 0; + for (m = 1; m <= specpoints.Size(); m++) + if (Dist2 (specpoints.Get(m).p, apoints.Get(i)) < 1e-8 + && (specpoints.Get(m).v - t).Length2() < 1e-8) + { + spi = m; + break; + } + if (!spi) + { + spi = specpoints.Append (SpecialPoint()); + specpoint2point.Append (i); + specpoints.Last().unconditional = 0; + } + specpoints.Elem(spi).p = apoints.Get(i); + specpoints.Elem(spi).v = t; + if (surfind.Size() >= 3) + specpoints.Elem(spi).unconditional = 1; + specpoints.Elem(spi).s1 = surfind.Get(j); + specpoints.Elem(spi).s2 = surfind.Get(k); + (*testout) << "spi = " << spi + << " uncond = " << specpoints.Get(spi).unconditional + << " t = " << t << endl; + } + + } + delete locsol; + } + } + + // if special point is unconditional on some solid, + // it must be unconditional everywhere: + + BitArray uncond (apoints.Size()); + uncond.Clear(); + + for (i = 1; i <= specpoints.Size(); i++) + if (specpoints.Get(i).unconditional) + uncond.Set (specpoint2point.Get(i)); + + for (i = 1; i <= specpoints.Size(); i++) + specpoints.Elem(i).unconditional = + uncond.Test (specpoint2point.Get(i)) ? 1 : 0; +} +*/ + + + +void SpecialPointCalculation :: +AnalyzeSpecialPoints (const CSGeometry & ageometry, + ARRAY<MeshPoint> & apoints, + ARRAY<SpecialPoint> & specpoints) +{ + int si, i, j, k, l, m, spi; + + Solid * locsol; + ARRAY<int> surfind; + ARRAY<int> surfind2; + + ARRAY<Vec<3> > normalvecs; + const Solid * sol; + const Surface * surf; + + Vec<3> t, nsurf; + Point<3> p; + + ARRAY<int> specpoint2point; + specpoints.SetSize (0); + + geometry = &ageometry; + + (*testout) << "AnalyzeSpecialPoints\n"; + + + Box<3> bbox; + if (apoints.Size()) + bbox.Set (apoints[0]); + for (int i = 1; i < apoints.Size(); i++) + bbox.Add (apoints[i]); + bbox.Increase (0.1 * Dist (bbox.PMin(), bbox.PMax())); + + Point3dTree searchtree (bbox.PMin(), bbox.PMax()); + ARRAY<int> locsearch; + + for (si = 0; si < ageometry.GetNTopLevelObjects(); si++) + { + (*testout) << "main solid " << si << "\n"; + + sol = ageometry.GetTopLevelObject(si)->GetSolid(); + surf = ageometry.GetTopLevelObject(si)->GetSurface(); + + for (i = 0; i < apoints.Size(); i++) + { + p = apoints[i]; + if (ageometry.GetTopLevelObject(si)->GetLayer() != + apoints[i].GetLayer()) + continue; + + (*testout) << "Point " << apoints[i] << "\n"; + + sol -> TangentialSolid (p, locsol); + if (!locsol) continue; + + // get all surface indices, + if (surf) + { + locsol -> GetSurfaceIndices (surfind); + bool hassurf = 0; + for (m = 0; m < surfind.Size(); m++) + if (ageometry.GetSurface(surfind[m]) == surf) + hassurf = 1; + + if (!hassurf) + continue; + + surf->GetNormalVector (p, nsurf); + } + + // get independent surfaces of tangential solid + + BoxSphere<3> box(p,p); + box.Increase (1e-6); + box.CalcDiamCenter(); + ageometry.GetIndependentSurfaceIndices (locsol, box, surfind); + + + (*testout) << "surfind.size = " << surfind.Size() << endl; + + /* + locsol -> GetSurfaceIndices (surfind); + for (j = surfind.Size(); j >= 1; j--) + if (fabs (ageometry.GetSurface(surfind.Get(j))-> + CalcFunctionValue (p)) > 1e-6) + surfind.DeleteElement (j); + */ + + /* + (*testout) << "Surfaces: "; + for (j = 0; j < surfind.Size(); j++) + (*testout) << surfind[j] << " "; + (*testout) << "\n"; + */ + + + normalvecs.SetSize(surfind.Size()); + for (j = 0; j < surfind.Size(); j++) + ageometry.GetSurface(surfind[j]) -> + GetNormalVector(apoints[i], normalvecs[j]); + + for (j = 0; j < normalvecs.Size(); j++) + for (k = j+1; k < normalvecs.Size(); k++) + for (l = 1; l <= 2; l++) + { + t = Cross (normalvecs[j], normalvecs[k]); + if (Abs2 (t) < 1e-8) + { + cerr << "AnalyzePoint: Surfaces degenerated" << "\n"; + break; + } + t.Normalize(); + if (l == 2) t *= -1; + + // try tangential direction t + + // (*testout) << "check tangential " << t << "\n"; + + if (surf && fabs (nsurf * t) > 1e-6) + continue; + + if (!surf) + { + ageometry.GetIndependentSurfaceIndices + (locsol, p, t, surfind2); + + bool found1 = 0, found2 = 0; + for (int ii = 0; ii < surfind2.Size(); ii++) + { + if (surfind2[ii] == surfind[j]) + found1 = 1; + if (surfind2[ii] == surfind[k]) + found2 = 1; + } + if (!found1 || !found2) + continue; + } + + + bool isedge; + + // isedge = locsol -> Edge (apoints.Get(i), t); + + // edge must be on tangential surface + isedge = + locsol->VectorIn (p, t) && + !locsol->VectorStrictIn (p, t); + + // (*testout) << "isedge,1 = " << isedge << "\n"; + + // there must exist at least two different faces on edge + if (isedge) + { + int cnts = 0; + for (m = 0; m < surfind.Size(); m++) + { + if (fabs (normalvecs[m] * t) > 1e-6) + continue; + + Vec<3> s = Cross (normalvecs[m], t); + Vec<3> t2a = t + 0.01 *s; + Vec<3> t2b = t - 0.01 *s; + + /* + (*testout) << "nv = " << normalvecs[m] << ", s = " << s << "\n"; + (*testout) << "t2a = " << t2a << ", t2b = " << t2b << "\n"; + (*testout) << "via = " + << locsol->VectorIn (p, t2a) << "/" + << locsol->VectorStrictIn (p, t2a); + (*testout) << "vib = " + << locsol->VectorIn (p, t2b) << "/" + << locsol->VectorStrictIn (p, t2b) << "\n"; + */ + + bool isface = + (locsol->VectorIn (p, t2a) && + !locsol->VectorStrictIn (p, t2a)) + || + (locsol->VectorIn (p, t2b) && + !locsol->VectorStrictIn (p, t2b)); + + if (isface) + { + cnts++; + } + } + if (cnts < 2) isedge = 0; + } + + if (isedge) + { + spi = -1; + + searchtree.GetIntersecting (apoints[i]-Vec3d(1e-4,1e-4,1e-4), + apoints[i]+Vec3d(1e-4,1e-4,1e-4), + locsearch); + + for (m = 0; m < locsearch.Size(); m++) + if (Dist2 (specpoints[locsearch[m]].p, apoints[i]) < 1e-8 + && Abs2(specpoints[locsearch[m]].v - t) < 1e-8) + { + spi = locsearch[m]; + break; + } + + /* + for (m = 0; m < specpoints.Size(); m++) + if (Dist2 (specpoints[m].p, apoints[i]) < 1e-8 + && Abs2(specpoints[m].v - t) < 1e-8) + { + spi = m; + break; + } + */ + if (spi == -1) + { + spi = specpoints.Append (SpecialPoint()) - 1; + specpoint2point.Append (i); + specpoints.Last().unconditional = 0; + searchtree.Insert (apoints[i], spi); + } + specpoints[spi].p = apoints[i]; + specpoints[spi].v = t; + if (surfind.Size() >= 3) + specpoints[spi].unconditional = 1; + specpoints[spi].s1 = surfind[j]; + specpoints[spi].s2 = surfind[k]; + specpoints[spi].layer = apoints[i].GetLayer(); + for (int up = 0; up < geometry->GetNUserPoints(); up++) + if (Dist (geometry->GetUserPoint(up), apoints[i]) < 1e-10) + specpoints[spi].unconditional = 1; + + /* + (*testout) << "spi = " << spi + << " uncond = " << specpoints[spi].unconditional + << " t = " << t << "\n"; + */ + } + + } + delete locsol; + } + } + + // if special point is unconditional on some solid, + // it must be unconditional everywhere: + + BitArray uncond (apoints.Size()); + uncond.Clear(); + + for (i = 0; i < specpoints.Size(); i++) + if (specpoints[i].unconditional) + uncond.Set (specpoint2point[i]); + + for (i = 0; i < specpoints.Size(); i++) + specpoints[i].unconditional = + uncond.Test (specpoint2point[i]) ? 1 : 0; +} +} diff --git a/contrib/Netgen/libsrc/csg/specpoin_old.cpp b/contrib/Netgen/libsrc/csg/specpoin_old.cpp new file mode 100644 index 0000000000..0f30ef7298 --- /dev/null +++ b/contrib/Netgen/libsrc/csg/specpoin_old.cpp @@ -0,0 +1,1370 @@ +#include <mystdlib.h> +#include <meshing.hpp> +#include <csg.hpp> + + +/* + + Special Point calculation uses the global Flags: + + + size .. 500 cube = [-size, size]^3 + relydegtest when to rely on degeneration ? + calccp calculate points of intersection ? + cpeps1 eps for degenerated poi + calcep calculate points of extreme coordinates ? + epeps1 eps for degenerated edge + epeps2 eps for axis parallel pec + epspointdist eps for distance of special points +*/ + + +namespace netgen +{ +void ProjectToEdge (const Surface * f1, const Surface * f2, Point<3> & hp); + + + + /* +SpecialPoint :: SpecialPoint () + : p(), v(), layer(0) +{ + ; +} + */ + + +SpecialPoint :: SpecialPoint (const SpecialPoint & sp) +{ + p = sp.p; + v = sp.v; + s1 = sp.s1; + s2 = sp.s2; + layer = sp.layer; + unconditional = sp.unconditional; +} + +SpecialPoint & SpecialPoint :: operator= (const SpecialPoint & sp) +{ + p = sp.p; + v = sp.v; + s1 = sp.s1; + s2 = sp.s2; + layer = sp.layer; + unconditional = sp.unconditional; + return *this; +} + +/* +bool SpecialPoint :: HasSurfaces (int as1, int as2) const +{ + return (s1 == as1 && s2 == as2 || s1 == as2 && s2 == as1); +} +*/ +void SpecialPoint :: Print (ostream & str) +{ + str << "p = " << p << " v = " << v + << " s1/s2 = " << s1 << "/" << s2 + << " layer = " << layer + << endl; +} + + + + +SpecialPointCalculation :: SpecialPointCalculation () +{ + ; +} + +void SpecialPointCalculation :: +CalcSpecialPoints (const CSGeometry & ageometry, + ARRAY<MeshPoint> & apoints) +{ + int i; + + geometry = &ageometry; + points = &apoints; + + size = geometry->MaxSize(); // globflags.GetNumFlag ("maxsize", 500); + (*testout) << "Find Special Points" << endl; + (*testout) << "maxsize = " << size << endl; + + cpeps1 = 1e-6; + epeps1 = 1e-3; + epeps2 = 1e-6; + + epspointdist2 = sqr (size * 1e-8); + relydegtest = size * 1e-4; + + + BoxSphere<3> box (Point<3> (-size, -size, -size), + Point<3> ( size, size, size)); + box.CalcDiamCenter(); + PrintMessage (3, "main-solids: ", geometry->GetNTopLevelObjects()); + + for (i = 0; i < geometry->GetNTopLevelObjects(); i++) + { + (*testout) << "tlo " << i << ":" << endl; + const TopLevelObject * tlo = geometry->GetTopLevelObject(i); + tlo->GetSolid()->Print (*testout); + (*testout) << endl; + CalcSpecialPointsRec (tlo->GetSolid(), tlo->GetLayer(), + box, 1, 1, 1); + } + + PrintDot ('\n'); + + + // add user point: + int found = 0; + for (i = 0; i < geometry->GetNUserPoints(); i++) + AddPoint (geometry->GetUserPoint(i), 1); + + PrintMessage (3, apoints.Size(), " special points"); + + for (i = 0; i < boxesinlevel.Size(); i++) + (*testout) << "level " << i << " has " + << boxesinlevel[i] << " boxes" << endl; +} + + + +int debug; +void SpecialPointCalculation :: +CalcSpecialPointsRec (const Solid * sol, int layer, + const BoxSphere<3> & box, + int level, bool calccp, bool calcep) +{ + if (multithread.terminate) + return; + + int i; + BoxSphere<3> sbox; + Solid * redsol; + + int numprim; + + bool decision; + bool possiblecrossp, possibleexp; // possible cross or extremalpoint + bool surecrossp, sureexp; // sure ... + + static ARRAY<int> locsurf; // attention: array is static + + + Point<3> p; + int k1, k2, k3; + int extremdir; + double hd; + + if (!sol) return; + + + if (level >= 100) + { + cerr << "Problems in CalcSpecialPoints" << endl; + cerr << "Point: " << box.Center() << endl; + exit (1); + } + + static int cntbox = 0; + cntbox++; + if (cntbox % 10000 == 0) + PrintDot (); + + if (level <= boxesinlevel.Size()) + boxesinlevel.Elem(level)++; + else + boxesinlevel.Append (1); + + /* + numprim = sol -> NumPrimitives(); + sol -> GetSurfaceIndices (locsurf); + */ + + debug = 0; + // box.IsIn (Point<3> (4.9, 1.279, 2.8)); + + + geometry -> GetIndependentSurfaceIndices (sol, box, locsurf); + numprim = locsurf.Size(); + + if (debug) + { + (*testout) << "box = " << box.PMin() << "-" << box.PMax() + << " np = " << numprim << " : "; + for (i = 1; i <= locsurf.Size(); i++) + (*testout) << " " << locsurf.Get(i); + (*testout) << " diam = " << box.Diam(); + (*testout) << " numprim = " << numprim; + (*testout) << endl; + } + + p = box.Center(); + + /* + (*testout) << "box = " << box.PMin() << " - " << box.PMax() + << ", lev = " << level + << ", nprim = " << sol->NumPrimitives() + << ", lsurf = " << locsurf.Size() << endl; + + for (i = 1; i <= locsurf.Size(); i++) + geometry->GetSurface (locsurf.Get(i)) -> Print (*testout); + sol -> Print (*testout); + */ + + /* + for (i = 1; i <= locsurf.Size(); i++) + (*testout) << locsurf.Get(i) << " "; + (*testout) << "C = " << box.Center() << " diam = " << box.Diam() << endl; + */ + + possiblecrossp = (numprim >= 3) && calccp; + surecrossp = 0; + + if (possiblecrossp && (locsurf.Size() <= 10)) + { + decision = 1; + surecrossp = 0; + + for (k1 = 1; k1 <= locsurf.Size() - 2; k1++) + for (k2 = k1 + 1; k2 <= locsurf.Size() - 1; k2++) + for (k3 = k2 + 1; k3 <= locsurf.Size(); k3++) + { + int nc, deg; + nc = CrossPointNewtonConvergence + (geometry->GetSurface(locsurf.Get(k1)), + geometry->GetSurface(locsurf.Get(k2)), + geometry->GetSurface(locsurf.Get(k3)), p ); + + deg = CrossPointDegenerated + (geometry->GetSurface(locsurf.Get(k1)), + geometry->GetSurface(locsurf.Get(k2)), + geometry->GetSurface(locsurf.Get(k3)), box ); + + if (!nc && !deg) decision = 0; + if (nc) surecrossp = 1; + } + + if (decision && surecrossp) + { + for (k1 = 1; k1 <= locsurf.Size() - 2; k1++) + for (k2 = k1 + 1; k2 <= locsurf.Size() - 1; k2++) + for (k3 = k2 + 1; k3 <= locsurf.Size(); k3++) + { + if (CrossPointNewtonConvergence + (geometry->GetSurface(locsurf.Get(k1)), + geometry->GetSurface(locsurf.Get(k2)), + geometry->GetSurface(locsurf.Get(k3)), p ) ) + { + Point<3> pp = p; + CrossPointNewton + (geometry->GetSurface(locsurf.Get(k1)), + geometry->GetSurface(locsurf.Get(k2)), + geometry->GetSurface(locsurf.Get(k3)), pp); + + BoxSphere<3> hbox (pp, pp); + hbox.Increase (1e-8); + + if (pp(0) > box.PMin()(0) - 1e-5 && + pp(0) < box.PMax()(0) + 1e-5 && + pp(1) > box.PMin()(1) - 1e-5 && + pp(1) < box.PMax()(1) + 1e-5 && + pp(2) > box.PMin()(2) - 1e-5 && + pp(2) < box.PMax()(2) + 1e-5 && + sol -> IsIn (pp) && !sol->IsStrictIn (pp) && + !CrossPointDegenerated + (geometry->GetSurface(locsurf.Get(k1)), + geometry->GetSurface(locsurf.Get(k2)), + geometry->GetSurface(locsurf.Get(k3)), hbox )) + + { + // AddCrossPoint (locsurf, sol, p); + BoxSphere<3> boxp (pp, pp); + boxp.Increase (1e-3); + boxp.CalcDiamCenter(); + ARRAY<int> locsurf2; + + geometry -> GetIndependentSurfaceIndices (sol, boxp, locsurf2); + + /* + ReducePrimitiveIterator rpi(boxp); + UnReducePrimitiveIterator urpi; + + ((Solid*)sol) -> IterateSolid (rpi); + sol -> GetIndependentSurfaceIndices (locsurf2); + ((Solid*)sol) -> IterateSolid (urpi); + */ + bool found1 = 0, found2 = 0, found3 = 0; + for (i = 1; i <= locsurf2.Size(); i++) + { + if (locsurf2.Get(i) == locsurf.Get(k1)) + found1 = 1; + if (locsurf2.Get(i) == locsurf.Get(k2)) + found2 = 1; + if (locsurf2.Get(i) == locsurf.Get(k3)) + found3 = 1; + } + + if (found1 && found2 && found3) + if (AddPoint (pp, layer)) + { + (*testout) << "Crosspoint found: " << pp + << " diam = " << box.Diam() << endl; + (*testout) << "surfs: " + << locsurf.Get(k1) << "," + << locsurf.Get(k2) << "," + << locsurf.Get(k3) << endl; + } + } + } + } + } + + if (decision) + possiblecrossp = 0; + } + + + + + possibleexp = (numprim >= 2) && calcep; + + if (possibleexp && (locsurf.Size() <= 10)) + { + decision = 1; + sureexp = 0; + + for (k1 = 1; k1 <= locsurf.Size() - 1; k1++) + for (k2 = k1+1; k2 <= locsurf.Size(); k2++) + { + bool nc, deg; + + nc = EdgeNewtonConvergence + (geometry->GetSurface(locsurf.Get(k1)), + geometry->GetSurface(locsurf.Get(k2)), + p); + + deg = EdgeDegenerated + (geometry->GetSurface(locsurf.Get(k1)), + geometry->GetSurface(locsurf.Get(k2)), + box); + + if (!nc && !deg) decision = 0; + if (nc) sureexp = 1; + + if (debug) + { + (*testout) << "p = " << p << " s1,2 = " << locsurf.Get(k1) << ", " << locsurf.Get(k2) + << " nc = " << nc << " deg = " << deg << endl; + } + } + + if (decision && sureexp) + { + for (k1 = 1; k1 <= locsurf.Size() - 1; k1++) + for (k2 = k1+1; k2 <= locsurf.Size(); k2++) + { + if ( + EdgeNewtonConvergence + (geometry->GetSurface(locsurf.Get(k1)), + geometry->GetSurface(locsurf.Get(k2)), + p) ) + { + EdgeNewton + (geometry->GetSurface(locsurf.Get(k1)), + geometry->GetSurface(locsurf.Get(k2)), + p); + + Point<3> pp; + if (IsEdgeExtremalPoint + (geometry->GetSurface(locsurf.Get(k1)), + geometry->GetSurface(locsurf.Get(k2)), + p, pp, box.Diam()/2)) + { + (*testout) << "extremalpoint (nearly) found:" + << pp + << endl; + if (Dist (pp, box.Center()) < box.Diam()/2 && + sol -> IsIn (pp) && !sol->IsStrictIn (pp) ) + { + // AddExtremalPoint (locsurf.Get(k1), locsurf.Get(k2), p); + if (AddPoint (pp, layer)) + (*testout) << "Extremal point found: " << pp << endl; + } + } + } + } + } + if (decision) + possibleexp = 0; + } + + + + if (possiblecrossp || possibleexp) + { + for (i = 0; i < 8; i++) + { + box.GetSubBox (i, sbox); + sbox.Increase (1e-4 * sbox.Diam()); + + redsol = sol -> GetReducedSolid (sbox); + + if (redsol) + { + CalcSpecialPointsRec (redsol, layer, sbox, level+1, calccp, calcep); + delete redsol; + } + } + } +} + + + + + +/******* Tests for Point of intersection **********************/ + + + +bool SpecialPointCalculation :: +CrossPointNewtonConvergence (const Surface * f1, + const Surface * f2, + const Surface * f3, + const Point<3> & p) +{ + int i; + Vec<3> grad; + Vec<3> rs, x; + Mat<3> jacobi, inv; + double alpha, beta, gamma, eta; + double sum; + int j; + + + rs(0) = f1->CalcFunctionValue (p); + rs(1) = f2->CalcFunctionValue (p); + rs(2) = f3->CalcFunctionValue (p); + + f1->CalcGradient (p, grad); + jacobi(0,0) = grad(0); + jacobi(0,1) = grad(1); + jacobi(0,2) = grad(2); + + f2->CalcGradient (p, grad); + jacobi(1,0) = grad(0); + jacobi(1,1) = grad(1); + jacobi(1,2) = grad(2); + + f3->CalcGradient (p, grad); + jacobi(2,0) = grad(0); + jacobi(2,1) = grad(1); + jacobi(2,2) = grad(2); + + alpha = 1; + if (fabs (Det (jacobi)) > 1e-8) + { + CalcInverse (jacobi, inv); + x = inv * rs; + + gamma = f1 -> HesseNorm() + f2 -> HesseNorm() + f3 -> HesseNorm(); + beta = 0; + for (i = 0; i < 3; i++) + { + sum = 0; + for (j = 0; j < 3; j++) + sum += fabs (inv(i,j)); + beta = max2 (beta, sum); + } + eta = Abs (x); + + alpha = beta * gamma * eta; + } + + return (alpha < 0.1); +} + + + + +bool SpecialPointCalculation :: +CrossPointDegenerated (const Surface * f1, + const Surface * f2, + const Surface * f3, + const BoxSphere<3> & box) const +{ + Mat<3> mat; + Vec<3> grad, g1, g2, g3; + double normprod; + + if (box.Diam() > relydegtest) return 0; + + f1->CalcGradient (box.Center(), g1); + normprod = Abs (g1); + + f2->CalcGradient (box.Center(), g2); + normprod *= Abs (g2); + + f3->CalcGradient (box.Center(), g3); + normprod *= Abs (g3); + + for (int i = 0; i < 3; i++) + { + mat(i,0) = g1(i); + mat(i,1) = g2(i); + mat(i,2) = g3(i); + } + + if (fabs (Det (mat)) < cpeps1 * normprod) + return 1; + else + return 0; +} + + + + + +void SpecialPointCalculation :: CrossPointNewton (const Surface * f1, + const Surface * f2, + const Surface * f3, Point<3> & p) +{ + int i; + Vec<3> g1, g2, g3; + Vec<3> rs, sol; + Mat<3> mat; + + i = 10; + while (i > 0) + { + i--; + rs(0) = f1->CalcFunctionValue (p); + rs(1) = f2->CalcFunctionValue (p); + rs(2) = f3->CalcFunctionValue (p); + + f1->CalcGradient (p, g1); + f2->CalcGradient (p, g2); + f3->CalcGradient (p, g3); + + for (int j = 0; j < 3; j++) + { + mat(0, j) = g1(j); + mat(1, j) = g2(j); + mat(2, j) = g3(j); + } + mat.Solve (rs, sol); + /* + Transpose (g1, g2, g3); + SolveLinearSystem (g1, g2, g3, rs, sol); + */ + if (sol.Length() < 1e-12 && i > 1) i = 1; + + p -= sol; + } +} + + + + +/******* Tests for Point on edges **********************/ + + + + +bool SpecialPointCalculation :: +EdgeNewtonConvergence (const Surface * f1, const Surface * f2, + const Point<3> & p) +{ + int i; + Vec<3> g1, g2, sol; + Vec<2> vrs; + double alpha, beta, gamma, eta; + double sum; + Mat<2,3> mat; + Mat<3,2> inv; + int j; + + vrs(0) = f1->CalcFunctionValue (p); + vrs(1) = f2->CalcFunctionValue (p); + + f1->CalcGradient (p, g1); + f2->CalcGradient (p, g2); + + for (i = 0; i < 3; i++) + { + mat(0,i) = g1(i); + mat(1,i) = g2(i); + } + + alpha = 1; + + if ( fabs(g1 * g2) < (1 - 1e-8) * Abs (g1) * Abs (g2)) + { + CalcInverse (mat, inv); + sol = inv * vrs; + + // SolveLinearSystemLS (g1, g2, vrs, sol); + + gamma = f1 -> HesseNorm() + f2 -> HesseNorm(); + + /* + Vec<3> inv1, inv2; + PseudoInverse (g1, g2, inv1, inv2); + */ + + beta = 0; + for (i = 0; i < 3; i++) + for (j = 0; j < 2; j++) + beta += inv(i,j) * inv(i,j); + beta = sqrt (beta); + + // beta = inv1.Length() + inv2.Length(); + eta = Abs (sol); + alpha = beta * gamma * eta; + } + return (alpha < 0.1); +} + + + + +bool SpecialPointCalculation :: +EdgeDegenerated (const Surface * f1, + const Surface * f2, + const BoxSphere<3> & box) const +{ + // perform newton steps. normals parallel ? + // if not decideable: return 0 + + + Point<3> p = box.Center(); + int i; + Vec<3> grad, g1, g2, sol; + Vec<2> vrs; + Mat<2,3> mat; + + i = 20; + while (i > 0) + { + if (Dist (p, box.Center()) > box.Diam()) + return 0; + + i--; + vrs(0) = f1->CalcFunctionValue (p); + vrs(1) = f2->CalcFunctionValue (p); + + f1->CalcGradient (p, g1); + f2->CalcGradient (p, g2); + + if ( fabs (g1 * g2) > (1 - 1e-10) * Abs (g1) * Abs (g2)) + return 1; + + for (int j = 0; j < 3; j++) + { + mat(0,j) = g1(j); + mat(1,j) = g2(j); + } + mat.Solve (vrs, sol); + // SolveLinearSystemLS (g1, g2, vrs, sol); + + if (Abs (sol) < 1e-12 && i > 1) i = 1; + p -= sol; + } + + return 0; + /* + return 0; + + static DenseMatrix jacobi(3); + Vec<3> grad, g1, g2, g3; + double normprod; + + if (box.Diam() > relydegtest) return 0; + + f1->CalcGradient (box.Center(), g1); + normprod = g1.Length(); + + f2->CalcGradient (box.Center(), g2); + normprod *= g2.Length(); + + if (fabs (g1 * g2) < 1e-8 * normprod) + return 1; + else + return 0; + */ +} + + + + + + +void SpecialPointCalculation :: EdgeNewton (const Surface * f1, + const Surface * f2, Point<3> & p) +{ + int i; + Vec<3> grad, g1, g2, sol; + Vec<2> vrs; + Mat<2,3> mat; + + i = 10; + while (i > 0) + { + i--; + vrs(0) = f1->CalcFunctionValue (p); + vrs(1) = f2->CalcFunctionValue (p); + + f1->CalcGradient (p, g1); + f2->CalcGradient (p, g2); + + for (int j = 0; j < 3; j++) + { + mat(0,j) = g1(j); + mat(1,j) = g2(j); + } + mat.Solve (vrs, sol); + // SolveLinearSystemLS (g1, g2, vrs, sol); + + if (Abs (sol) < 1e-12 && i > 1) i = 1; + p -= sol; + } +} + + + +bool SpecialPointCalculation :: +IsEdgeExtremalPoint (const Surface * f1, const Surface * f2, + const Point<3> & p, Point<3> & pp, double rad) +{ + Vec<3> g1, g2, t, t1, t2; + int j; + + f1->CalcGradient (p, g1); + f2->CalcGradient (p, g2); + + t = Cross (g1, g2); + t.Normalize(); + + Point<3> p1 = p + rad * t; + Point<3> p2 = p - rad * t; + + EdgeNewton (f1, f2, p1); + EdgeNewton (f1, f2, p2); + + + f1->CalcGradient (p1, g1); + f2->CalcGradient (p1, g2); + t1 = Cross (g1, g2); + t1.Normalize(); + + f1->CalcGradient (p2, g1); + f2->CalcGradient (p2, g2); + t2 = Cross (g1, g2); + t2.Normalize(); + + double val = 1e-8 * rad * rad; + for (j = 0; j < 3; j++) + if ( (t1(j) * t2(j) < -val) ) + { + pp = p; + ExtremalPointNewton (f1, f2, j+1, pp); + return 1; + } + + return 0; +} + + + + + + + + + +/********** Tests of Points of extremal coordinates ****************/ + + +void SpecialPointCalculation :: ExtremalPointNewton (const Surface * f1, + const Surface * f2, + int dir, Point<3> & p) +{ + int i; + + Vec<3> g1, g2, v, curv; + Vec<3> rs, x, y1, y2, y; + Mat<3> h1, h2; + Mat<3> jacobi; + + + if (dir < 1 || dir > 3) + { + cerr << "Error: Illegal extremdir" << endl; + return; + } + + i = 50; + while (i > 0) + { + i--; + rs(0) = f1->CalcFunctionValue (p); + rs(1) = f2->CalcFunctionValue (p); + + f1 -> CalcGradient (p, g1); + f2 -> CalcGradient (p, g2); + + f1 -> CalcHesse (p, h1); + f2 -> CalcHesse (p, h2); + + + v = Cross (g1, g2); + + rs(2) = v(dir-1); + + jacobi(0,0) = g1(0); + jacobi(0,1) = g1(1); + jacobi(0,2) = g1(2); + + jacobi(1,0) = g2(0); + jacobi(1,1) = g2(1); + jacobi(1,2) = g2(2); + + + switch (dir) + { + case 1: + { + y1(0) = 0; + y1(1) = g2(2); + y1(2) = -g2(1); + y2(0) = 0; + y2(1) = -g1(2); + y2(2) = g1(1); + break; + } + case 2: + { + y1(0) = -g2(2); + y1(1) = 0; + y1(2) = g2(0); + y2(0) = g1(2); + y2(1) = 0; + y2(2) = -g1(0); + break; + } + case 3: + { + y1(0) = g2(1); + y1(1) = -g2(0); + y1(2) = 0; + y2(0) = -g1(1); + y2(1) = g1(0); + y2(2) = 0; + break; + } + } + + y = h1 * y1 + h2 * y2; + + jacobi(2,0) = y(0); + jacobi(2,1) = y(1); + jacobi(2,2) = y(2); + + jacobi.Solve (rs, x); + /* + CalcInverse (jacobi, inv); + inv.Mult (rs, x); + */ + // (*testout) << "err = " << x.L2Norm() << endl; + + if (Abs (x) < 1e-12 && i > 1) + { + // (*testout) << "convergent in " << (10 - i) << " steps " << endl; + + i = 1; + } + + p -= x; + } + + if (Abs (x) > 1e-10) + { + (*testout) << "Error: extremum Newton not convergent" << endl; + (*testout) << "dir = " << dir << endl; + (*testout) << "p = " << p << endl; + (*testout) << "x = " << x << endl; + } +} + + + + +bool SpecialPointCalculation :: ExtremalPointPossible (const Surface * f1, + const Surface * f2, + int dir, + const BoxSphere<3> & box) +{ + double hn1, hn2, gn1, gn2; + Point<3> p; + Vec<3> g1, g2, v; + double f3; + double r = box.Diam()/2; + + p = box.Center(); + + f1 -> CalcGradient (p, g1); + f2 -> CalcGradient (p, g2); + + gn1 = g1.Length(); + gn2 = g2.Length(); + + hn1 = f1 -> HesseNorm (); + hn2 = f2 -> HesseNorm (); + + v = Cross (g1, g2); + f3 = fabs (v(dir-1)); + + // (*testout) << "f3 = " << f3 << " r = " << r + // << "normbound = " + // << (hn1 * (gn2 + r * hn2) + hn2 * (gn1 + r * hn1)) << endl; + + return (f3 <= 3 * r * (hn1 * (gn2 + r * hn2) + hn2 * (gn1 + r * hn1))); +} + + + +bool SpecialPointCalculation :: +ExtremalPointNewtonConvergence (const Surface * f1, const Surface * f2, + int dir, + const BoxSphere<3> & box) +{ + return box.Diam() < 1e-8; +} + + +bool SpecialPointCalculation :: +ExtremalPointDegenerated (const Surface * f1, const Surface * f2, + int dir, const BoxSphere<3> & box) +{ + double gn1, gn2; + Point<3> p; + Vec<3> g1, g2, v; + double maxderiv; + double minv; + Vec<3> curv, t; + Vec<2> rs, x; + Mat<3> h1, h2; + Mat<2> a, inv; + double leftside; + + if (box.Diam() > relydegtest) return 0; + + p = box.Center(); + + f1 -> CalcGradient (p, g1); + f2 -> CalcGradient (p, g2); + gn1 = g1.Length(); + gn2 = g2.Length(); + + v = Cross (g1, g2); + if (Abs (v) < epeps1 * gn1 * gn2) return 1; // irregular edge + + f1 -> CalcHesse (p, h1); + f2 -> CalcHesse (p, h2); + + // hn1 = f1 -> HesseNorm (); + // hn2 = f2 -> HesseNorm (); + + t = v; + a(0, 0) = g1 * g1; + a(0, 1) = + a(1, 0) = g1 * g2; + a(1, 1) = g2 * g2; + + rs(0) = g1(dir-1); + rs(1) = g2(dir-1); + + a.Solve (rs, x); + + /* + CalcInverse (a, inv); + inv.Mult (rs, x); // x .. Lagrangeparameter + */ + // (*testout) << "g1 = " << g1 << " g2 = " << g2 << endl; + // (*testout) << "lam = " << x << endl; + // (*testout) << "h2 = " << h2 << endl; + + leftside = fabs (x(0) * ( t * (h1 * t)) + + x(1) * ( t * (h2 * t))); + + // (*testout) << "leftside = " << leftside << endl; + + if (leftside < epeps2 * Abs2 (v)) return 1; + + return 0; +} + + + +bool SpecialPointCalculation :: AddPoint (const Point<3> & p, int layer) +{ + for (int i = 0; i < points->Size(); i++) + if (Dist2 ( (*points)[i], p) < epspointdist2 && + (*points)[i].GetLayer() == layer) + return 0; + + points->Append (MeshPoint(p, layer)); + return 1; +} + + + + + + + +/* +void SpecialPointCalculation :: +AnalyzeSpecialPoints (const CSGeometry & ageometry, + ARRAY<Point<3> > & apoints, + ARRAY<SpecialPoint> & specpoints) +{ + int si, i, j, k, l, m, spi; + Solid * locsol; + ARRAY<int> surfind; + ARRAY<Vec<3>> normalvecs; + const Solid * sol; + Vec<3> t; + Point<3> p; + + ARRAY<int> specpoint2point; + specpoints.SetSize (0); + + (*testout) << "AnalyzeSpecialPoints" << endl; + + for (si = 1; si <= ageometry.GetNTopLevelObjects(); si++) + { + (*testout) << "main solid " << si << endl; + + sol = ageometry.GetTopLevelObject(si)->GetSolid(); + for (i = 1; i <= apoints.Size(); i++) + { + p = apoints.Get(i); + + sol -> TangentialSolid (p, locsol); + if (!locsol) continue; + + (*testout) << "Point " << apoints.Get(i) << endl; + + locsol -> GetSurfaceIndices (surfind); + for (j = surfind.Size(); j >= 1; j--) + if (fabs (ageometry.GetSurface(surfind.Get(j))-> + CalcFunctionValue (p)) > 1e-6) + surfind.DeleteElement (j); + + + + (*testout) << "Surfaces: "; + for (j = 1; j <= surfind.Size(); j++) + (*testout) << surfind.Get(j) << " "; + (*testout) << endl; + + normalvecs.SetSize(surfind.Size()); + for (j = 1; j <= surfind.Size(); j++) + ageometry.GetSurface(surfind.Get(j)) -> + GetNormalVector(apoints.Get(i), normalvecs.Elem(j)); + + for (j = 1; j <= normalvecs.Size() - 1; j ++) + for (k = j+1; k <= normalvecs.Size(); k++) + for (l = 1; l <= 2; l++) + { + t = Cross (normalvecs.Get(j), normalvecs.Get(k)); + if (t.Length2() < 1e-8) + { + cerr << "AnalyzePoint: Surfaces degenerated" << endl; + break; + } + t /= t.Length(); + if (l == 2) t *= -1; + + if (locsol -> Edge (apoints.Get(i), t)) + { + spi = 0; + for (m = 1; m <= specpoints.Size(); m++) + if (Dist2 (specpoints.Get(m).p, apoints.Get(i)) < 1e-8 + && (specpoints.Get(m).v - t).Length2() < 1e-8) + { + spi = m; + break; + } + if (!spi) + { + spi = specpoints.Append (SpecialPoint()); + specpoint2point.Append (i); + specpoints.Last().unconditional = 0; + } + specpoints.Elem(spi).p = apoints.Get(i); + specpoints.Elem(spi).v = t; + if (surfind.Size() >= 3) + specpoints.Elem(spi).unconditional = 1; + specpoints.Elem(spi).s1 = surfind.Get(j); + specpoints.Elem(spi).s2 = surfind.Get(k); + (*testout) << "spi = " << spi + << " uncond = " << specpoints.Get(spi).unconditional + << " t = " << t << endl; + } + + } + delete locsol; + } + } + + // if special point is unconditional on some solid, + // it must be unconditional everywhere: + + BitArray uncond (apoints.Size()); + uncond.Clear(); + + for (i = 1; i <= specpoints.Size(); i++) + if (specpoints.Get(i).unconditional) + uncond.Set (specpoint2point.Get(i)); + + for (i = 1; i <= specpoints.Size(); i++) + specpoints.Elem(i).unconditional = + uncond.Test (specpoint2point.Get(i)) ? 1 : 0; +} +*/ + + + +void SpecialPointCalculation :: +AnalyzeSpecialPoints (const CSGeometry & ageometry, + ARRAY<MeshPoint> & apoints, + ARRAY<SpecialPoint> & specpoints) +{ + int si, i, j, k, l, m, spi; + + Solid * locsol; + ARRAY<int> surfind; + ARRAY<int> surfind2; + + ARRAY<Vec<3> > normalvecs; + const Solid * sol; + const Surface * surf; + + Vec<3> t, nsurf; + Point<3> p; + + ARRAY<int> specpoint2point; + specpoints.SetSize (0); + + geometry = &ageometry; + + (*testout) << "AnalyzeSpecialPoints\n"; + + for (si = 0; si < ageometry.GetNTopLevelObjects(); si++) + { + (*testout) << "main solid " << si << "\n"; + + sol = ageometry.GetTopLevelObject(si)->GetSolid(); + surf = ageometry.GetTopLevelObject(si)->GetSurface(); + + for (i = 0; i < apoints.Size(); i++) + { + p = apoints[i]; + if (ageometry.GetTopLevelObject(si)->GetLayer() != + apoints[i].GetLayer()) + continue; + + // (*testout) << "Point " << apoints[i] << "\n"; + + sol -> TangentialSolid (p, locsol); + if (!locsol) continue; + + // get all surface indices, + if (surf) + { + locsol -> GetSurfaceIndices (surfind); + bool hassurf = 0; + for (m = 0; m < surfind.Size(); m++) + if (ageometry.GetSurface(surfind[m]) == surf) + hassurf = 1; + + if (!hassurf) + continue; + + surf->GetNormalVector (p, nsurf); + } + + // get independent surfaces of tangential solid + + BoxSphere<3> box(p,p); + box.Increase (1e-6); + box.CalcDiamCenter(); + ageometry.GetIndependentSurfaceIndices (locsol, box, surfind); + + + /* + locsol -> GetSurfaceIndices (surfind); + for (j = surfind.Size(); j >= 1; j--) + if (fabs (ageometry.GetSurface(surfind.Get(j))-> + CalcFunctionValue (p)) > 1e-6) + surfind.DeleteElement (j); + */ + + /* + (*testout) << "Surfaces: "; + for (j = 0; j < surfind.Size(); j++) + (*testout) << surfind[j] << " "; + (*testout) << "\n"; + */ + + + normalvecs.SetSize(surfind.Size()); + for (j = 0; j < surfind.Size(); j++) + ageometry.GetSurface(surfind[j]) -> + GetNormalVector(apoints[i], normalvecs[j]); + + for (j = 0; j < normalvecs.Size(); j++) + for (k = j+1; k < normalvecs.Size(); k++) + for (l = 1; l <= 2; l++) + { + t = Cross (normalvecs[j], normalvecs[k]); + if (Abs2 (t) < 1e-8) + { + cerr << "AnalyzePoint: Surfaces degenerated" << "\n"; + break; + } + t.Normalize(); + if (l == 2) t *= -1; + + // try tangential direction t + + // (*testout) << "check tangential " << t << "\n"; + + if (surf && fabs (nsurf * t) > 1e-6) + continue; + + if (!surf) + { + ageometry.GetIndependentSurfaceIndices + (locsol, p, t, surfind2); + + bool found1 = 0, found2 = 0; + for (int ii = 0; ii < surfind2.Size(); ii++) + { + if (surfind2[ii] == surfind[j]) + found1 = 1; + if (surfind2[ii] == surfind[k]) + found2 = 1; + } + if (!found1 || !found2) + continue; + } + + + bool isedge; + + // isedge = locsol -> Edge (apoints.Get(i), t); + + // edge must be on tangential surface + isedge = + locsol->VectorIn (p, t) && + !locsol->VectorStrictIn (p, t); + + // (*testout) << "isedge,1 = " << isedge << "\n"; + + // there must exist at least two different faces on edge + if (isedge) + { + int cnts = 0; + for (m = 0; m < surfind.Size(); m++) + { + if (fabs (normalvecs[m] * t) > 1e-6) + continue; + + Vec<3> s = Cross (normalvecs[m], t); + Vec<3> t2a = t + 0.01 *s; + Vec<3> t2b = t - 0.01 *s; + + /* + (*testout) << "nv = " << normalvecs[m] << ", s = " << s << "\n"; + (*testout) << "t2a = " << t2a << ", t2b = " << t2b << "\n"; + (*testout) << "via = " + << locsol->VectorIn (p, t2a) << "/" + << locsol->VectorStrictIn (p, t2a); + (*testout) << "vib = " + << locsol->VectorIn (p, t2b) << "/" + << locsol->VectorStrictIn (p, t2b) << "\n"; + */ + + bool isface = + (locsol->VectorIn (p, t2a) && + !locsol->VectorStrictIn (p, t2a)) + || + (locsol->VectorIn (p, t2b) && + !locsol->VectorStrictIn (p, t2b)); + + if (isface) + { + cnts++; + } + } + if (cnts < 2) isedge = 0; + } + + if (isedge) + { + spi = -1; + for (m = 0; m < specpoints.Size(); m++) + if (Dist2 (specpoints[m].p, apoints[i]) < 1e-8 + && Abs2(specpoints[m].v - t) < 1e-8) + { + spi = m; + break; + } + if (spi == -1) + { + spi = specpoints.Append (SpecialPoint()) - 1; + specpoint2point.Append (i); + specpoints.Last().unconditional = 0; + } + specpoints[spi].p = apoints[i]; + specpoints[spi].v = t; + if (surfind.Size() >= 3) + specpoints[spi].unconditional = 1; + specpoints[spi].s1 = surfind[j]; + specpoints[spi].s2 = surfind[k]; + specpoints[spi].layer = apoints[i].GetLayer(); + for (int up = 0; up < geometry->GetNUserPoints(); up++) + if (Dist (geometry->GetUserPoint(up), apoints[i]) < 1e-10) + specpoints[spi].unconditional = 1; + + /* + (*testout) << "spi = " << spi + << " uncond = " << specpoints[spi].unconditional + << " t = " << t << "\n"; + */ + } + + } + delete locsol; + } + } + + // if special point is unconditional on some solid, + // it must be unconditional everywhere: + + BitArray uncond (apoints.Size()); + uncond.Clear(); + + for (i = 0; i < specpoints.Size(); i++) + if (specpoints[i].unconditional) + uncond.Set (specpoint2point[i]); + + for (i = 0; i < specpoints.Size(); i++) + specpoints[i].unconditional = + uncond.Test (specpoint2point[i]) ? 1 : 0; +} +} diff --git a/contrib/Netgen/libsrc/csg/spline3d.cpp b/contrib/Netgen/libsrc/csg/spline3d.cpp new file mode 100644 index 0000000000..455493ad6f --- /dev/null +++ b/contrib/Netgen/libsrc/csg/spline3d.cpp @@ -0,0 +1,355 @@ +#include <mystdlib.h> + +#include <myadt.hpp> + +#include <linalg.hpp> +#include <csg.hpp> + + +namespace netgen +{ +splinesegment3d :: splinesegment3d (const Point<3> & ap1, const Point<3> & ap2, + const Point<3> & ap3) +{ + p1 = ap1; + p2 = ap2; + p3 = ap3; +} + + +/* + todo + Tip von Joerg Stiller: + setzt Du in + void splinesegment3d :: Evaluate + Zeilen 54 und 56 + b2 = 2 * t * (1-t); + b2 /= sqrt(2); + Das heisst, Du wichtest das zweite Bersteinpolynom mit + w2 = 1 / sqrt(2); + Das ist aber nur fuer 45-Grad-Segmente korrekt. Fuer den + allgemeinen Fall funktioniert + w2 = ( e(p3 - p1), e(p2 - p1) ); // also cos(winkel(p3-p1, p2-p1)) + bzw. schoen symmetrisch + w2 = ( e(p3 - p1), e(p2 - p1) )/2 + ( e(p1 - p3), e(p2 - p3) )/2; + Das ist natuerlich kein C++ Code sondern symbolisch, wobei + e(p3 - p1) ist der von p1 zu p3 zeigende Einheitsvektor und + (a, b) steht fuer das Skalarprodukt zweier Vektoren etc. + + Eine vergleichbare Information steht auch irgendwo im Hoscheck & Lasser. + Ich habe das Buch aber eben nicht zur Hand. +*/ + +void splinesegment3d :: Evaluate (double t, Point<3> & p) const +{ + double x, y, z, w; + double b1, b2, b3; + + b1 = (1-t)*(1-t); + b2 = 2 * t * (1-t); + b3 = t * t; + + b2 /= sqrt(double(2)); + + x = p1(0) * b1 + p2(0) * b2 + p3(0) * b3; + y = p1(1) * b1 + p2(1) * b2 + p3(1) * b3; + z = p1(2) * b1 + p2(2) * b2 + p3(2) * b3; + w = b1 + b2 + b3; + + p(0) = x / w; + p(1) = y / w; + p(2) = z / w; +} + +void splinesegment3d :: EvaluateTangent (double t, Vec<3> & tang) const +{ + double x, y, z, w, xprime, yprime, zprime, wprime; + double b1, b2, b3, b1prime, b2prime, b3prime; + + b1 = (1-t)*(1-t); + b2 = 2 * t * (1-t); + b3 = t * t; + b2 /= sqrt(double(2)); + + b1prime = 2 * t - 2; + b2prime = - 4 * t + 2; + b3prime = 2 * t; + b2prime /= sqrt(double(2)); + + + x = p1(0) * b1 + p2(0) * b2 + p3(0) * b3; + y = p1(1) * b1 + p2(1) * b2 + p3(1) * b3; + z = p1(2) * b1 + p2(2) * b2 + p3(2) * b3; + w = b1 + b2 + b3; + + xprime = p1(0) * b1prime + p2(0) * b2prime + p3(0) * b3prime; + yprime = p1(1) * b1prime + p2(1) * b2prime + p3(1) * b3prime; + zprime = p1(2) * b1prime + p2(2) * b2prime + p3(2) * b3prime; + wprime = b1prime + b2prime + b3prime; + + tang(0) = (w * xprime - x * wprime) / (w * w); + tang(1) = (w * yprime - y * wprime) / (w * w); + tang(2) = (w * zprime - z * wprime) / (w * w); +} + + +void spline3d :: AddSegment (const Point<3> & ap1, const Point<3> & ap2, + const Point<3> & ap3) +{ + segments.Append (new splinesegment3d (ap1, ap2, ap3)); +} + +void spline3d :: Evaluate (double t, Point<3> & p) const +{ + int nr; + double loct; + static int cnt = 0; + + cnt++; + if (cnt % 10000 == 0) (*mycout) << "Evaluate calls: " << cnt << endl; + + while (t < 0) t += GetNumSegments(); + while (t >= GetNumSegments()) t -= GetNumSegments(); + nr = 1 + int (t); + loct = t - nr + 1; + segments.Get(nr)->Evaluate (loct, p); +} + +void spline3d :: EvaluateTangent (double t, Vec<3> & tang) const +{ + int nr; + double loct; + + while (t < 0) t += GetNumSegments(); + while (t >= GetNumSegments()) t -= GetNumSegments(); + nr = 1 + int (t); + loct = t - nr + 1; + segments.Get(nr)->EvaluateTangent (loct, tang); +} + + +double spline3d :: ProjectToSpline (Point<3> & p) const +{ + double t, tl, tu, dt, dist, mindist, optt; + Point<3> hp; + Vec<3> tanx, px; + + dt = 0.01; + mindist = 0; + for (t = 0; t <= GetNumSegments() + dt/2; t += dt) + { + Evaluate (t, hp); + dist = Dist (hp, p); + if (t == 0 || dist < mindist) + { + optt = t; + mindist = dist; + } + } + + + tu = optt + dt; + tl = optt - dt; + while (tu - tl > 1e-2) + { + optt = 0.5 * (tu + tl); + Evaluate (optt, hp); + EvaluateTangent (optt, tanx); + if (tanx * (hp - p) > 0) + tu = optt; + else + tl = optt; + } + + optt = 0.5 * (tu + tl); + + optt = ProjectToSpline (p, optt); + return optt; +} + + +double spline3d :: ProjectToSpline (Point<3> & p, double optt) const +{ + double tl, tu, dt, val, dval, valu, vall; + Point<3> hp; + Vec<3> tanx, px; + int its = 0; + int cnt = 1000; + do + { + dt = 1e-8; + tl = optt - dt; + tu = optt + dt; + + EvaluateTangent (optt, tanx); + Evaluate (optt, hp); + px = hp - p; + val = px * tanx; + + EvaluateTangent (tl, tanx); + Evaluate (tl, hp); + px = hp - p; + vall = px * tanx; + + EvaluateTangent (tu, tanx); + Evaluate (tu, hp); + px = hp - p; + valu = px * tanx; + + dval = (valu - vall) / (2 * dt); + + if (its % 100 == 99) + (*testout) << "optt = " << optt + << " val = " << val + << " dval = " << dval << endl; + optt -= val / dval; + its++; + if (fabs(val) < 1e-8 && cnt > 5) cnt = 5; + cnt--; + } + while (cnt > 0); + + Evaluate (optt, p); + return optt; +} + + +splinetube :: splinetube (const spline3d & amiddlecurve, double ar) + : Surface(), middlecurve (amiddlecurve), r(ar) +{ + (*mycout) << "Splinetube Allocated, r = " << r << endl; + +} + +void splinetube :: DefineTangentialPlane (const Point<3> & ap1, + const Point<3> & ap2) +{ + double t; + double phi, z; + + p1 = ap1; + p2 = ap2; + cp = p1; + t = middlecurve.ProjectToSpline (cp); + ex = p1 - cp; + middlecurve.EvaluateTangent (t, ez); + ex.Normalize(); + ez.Normalize(); + ey = Cross (ez, ex); + + phi = r * atan2 (ey * (p2-cp), ex * (p2-cp)); + z = ez * (p2 - cp); + e2x(0) = phi; + e2x(1) = z; + e2x.Normalize(); + e2y(1) = e2x(0); + e2y(0) = -e2x(1); + + // (*testout) << "Defineplane: " << endl + // << "p1 = " << p1 << " p2 = " << p2 << endl + // << "pc = " << cp << endl + // << "ex = " << ex << " ey = " << ey << " ez = " << ez << endl + // << "phi = " << phi << " z = " << z << endl + // << "e2x = " << e2x << " e2y = " << e2y << endl; +} + +void splinetube :: ToPlane (const Point<3> & p3d, Point<2> & pplain, double h, + int & zone) const +{ + Vec<2> v; + v(0) = r * atan2 (ey * (p3d-cp), ex * (p3d-cp)); + v(1) = ez * (p3d - cp); + zone = 0; + if (v(0) > r * 2) zone = 1; + if (v(0) < r * 2) zone = 2; + + pplain(0) = (v * e2x) / h; + pplain(1) = (v * e2y) / h; +} + +void splinetube :: FromPlane (const Point<2> & pplain, Point<3> & p3d, double h) const +{ + Vec<2> v; + + v(0) = pplain(0) * h * e2x(0) + pplain(1) * h * e2y(0); + v(1) = pplain(0) * h * e2x(1) + pplain(1) * h * e2y(1); + + p3d = p1 + v(0) * ey + v(1) * ez; + + Project (p3d); +} + +void splinetube :: Project (Point<3> & p3d) const +{ + Point<3> hp; + + hp = p3d; + middlecurve.ProjectToSpline (hp); + + p3d = hp + (r / Dist(p3d, hp)) * (p3d - hp); +} + + + +double splinetube :: CalcFunctionValue (const Point<3> & point) const +{ + Point<3> hcp; + double rad; + + hcp = point; + middlecurve.ProjectToSpline (hcp); + rad = Dist (hcp, point); + return 0.5 * (rad * rad / r - r); +} + +void splinetube :: CalcGradient (const Point<3> & point, Vec<3> & grad) const +{ + Point<3> hcp; + + hcp = point; + middlecurve.ProjectToSpline (hcp); + + grad = point - hcp; + grad /= r; +} + + + + +Point<3> splinetube :: GetSurfacePoint () const +{ + Point<3> p; + Vec<3> t, n; + + middlecurve.Evaluate (0, p); + middlecurve.EvaluateTangent (0, t); + n = t.GetNormal (); + n *= r; + (*mycout) << "p = " << p << " t = " << t << " n = " << n << endl; + return p + n; +} + +void splinetube :: Print (ostream & str) const +{ + int i; + str << "SplineTube, " + << middlecurve.GetNumSegments () << " segments, r = " << r << endl; + for (i = 1; i <= middlecurve.GetNumSegments(); i++) + str << middlecurve.P1(i) << " - " + << middlecurve.P2(i) << " - " + << middlecurve.P3(i) << endl; +} + + +int splinetube :: BoxInSolid (const BoxSphere<3> & box) const + // 0 .. no, 1 .. yes, 2 .. maybe +{ + Point<3> pc = box.Center(); + middlecurve.ProjectToSpline (pc); + double d = Dist (pc, box.Center()); + + if (d < r - box.Diam()/2) return 1; + if (d > r + box.Diam()/2) return 0; + return 2; +} +} diff --git a/contrib/Netgen/libsrc/csg/spline3d.hpp b/contrib/Netgen/libsrc/csg/spline3d.hpp new file mode 100644 index 0000000000..753788459f --- /dev/null +++ b/contrib/Netgen/libsrc/csg/spline3d.hpp @@ -0,0 +1,92 @@ +/// +class splinesegment3d + { + /// + Point<3> p1, p2, p3; + + public: + /// + splinesegment3d (const Point<3> & ap1, const Point<3> & ap2, + const Point<3> & ap3); + /// + void Evaluate (double t, Point<3> & p) const; + /// + void EvaluateTangent (double t, Vec<3> & tang) const; + /// + const Point<3> & P1() const { return p1; } + /// + const Point<3> & P2() const { return p2; } + /// + const Point<3> & P3() const { return p3; } + }; + +/// +class spline3d + { + /// + ARRAY<splinesegment3d *> segments; + + public: + /// + spline3d () { }; + /// + void AddSegment (const Point<3> & ap1, const Point<3> & ap2, const Point<3> & ap3); + /// + int GetNumSegments () const { return segments.Size(); } + /// + double ProjectToSpline (Point<3> & p) const; + /// + double ProjectToSpline (Point<3> & p, double t) const; + /// + void Evaluate (double t, Point<3> & p) const; + /// + void EvaluateTangent (double t, Vec<3> & tang) const; + /// + const Point<3> & P1(int i) const { return segments.Get(i)->P1(); } + /// + const Point<3> & P2(int i) const { return segments.Get(i)->P2(); } + /// + const Point<3> & P3(int i) const { return segments.Get(i)->P3(); } + }; + +/// +class splinetube : public Surface + { + /// + const spline3d & middlecurve; + /// + double r; +/// Vec<3> ex, ey, ez; + Vec<2> e2x, e2y; + /// + Point<3> cp; + + public: + /// + splinetube (const spline3d & amiddlecurve, double ar); + + /// + virtual void DefineTangentialPlane (const Point<3> & ap1, const Point<3> & ap2); + /// + virtual void ToPlane (const Point<3> & p, Point<2> & pplain, double h, int & zone) const; + /// + virtual void FromPlane (const Point<2> & pplain, Point<3> & p, double h) const; + /// + virtual void Project (Point<3> & p) const; + +// virtual int RootInBox (const box3d & box) const { return 0; } + /// 0 .. no, 1 .. yes, 2 .. maybe + + virtual int BoxInSolid (const BoxSphere<3> & box) const; + /// 0 .. no, 1 .. yes, 2 .. maybe + + virtual double CalcFunctionValue (const Point<3> & point) const; + /// + virtual void CalcGradient (const Point<3> & point, Vec<3> & grad) const; + /// + virtual double HesseNorm () const { return 0.5 / r; } + /// + virtual Point<3> GetSurfacePoint () const; + /// + virtual void Print (ostream & str) const; + }; diff --git a/contrib/Netgen/libsrc/csg/surface.cpp b/contrib/Netgen/libsrc/csg/surface.cpp new file mode 100644 index 0000000000..8b8d58127a --- /dev/null +++ b/contrib/Netgen/libsrc/csg/surface.cpp @@ -0,0 +1,392 @@ +#include <mystdlib.h> + +#include <myadt.hpp> +#include <csg.hpp> + +#include <linalg.hpp> +#include <meshing.hpp> + + +namespace netgen +{ +Surface :: Surface () +{ + maxh = 1e10; + name = new char[7]; + strcpy (name, "noname"); + bcprop = -1; +} + +Surface :: ~Surface() +{ + delete [] name; +} + + +void Surface :: SetName (const char * aname) +{ + delete [] name; + name = new char[strlen (aname)+1]; + strcpy (name, aname); +} + + +int Surface :: PointOnSurface (const Point<3> & p, + double eps) const +{ + double val = CalcFunctionValue (p); + return fabs (val) < eps; +} + + +void Surface :: CalcHesse (const Point<3> & point, Mat<3> & hesse) const +{ + double dx = 1e-5; + Point<3> hp1, hp2; + Vec<3> g1, g2; + + for (int i = 0; i < 3; i++) + { + hp1 = point; + hp2 = point; + + hp1(i) += dx; + hp2(i) -= dx; + + CalcGradient (hp1, g1); + CalcGradient (hp2, g2); + + for (int j = 0; j < 3; j++) + hesse(i, j) = (g1(j) - g2(j)) / (2 * dx); + } +} + +/* +void Surface :: GetNormalVector (const Point<3> & p, Vec<3> & n) const +{ + CalcGradient (p, n); + n.Normalize(); +} +*/ +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; + } +} + +double Surface :: MaxCurvature () const +{ + return 0.5 * HesseNorm (); +} + +double Surface :: +MaxCurvatureLoc (const Point<3> & /* c */ , double /* rad */) const +{ + return MaxCurvature (); +} + + + +double Surface :: LocH (const Point<3> & p, double x, + double c, double hmax) const + // finds h <= hmax, s.t. h * \kappa_x*h < c +{ + /* + double h, hmin, kappa; + hmin = 0; + + while (hmin < 0.9 * hmax) + { + h = 0.5 * (hmin + hmax); + kappa = 2 * MaxCurvatureLoc (p, x * h); + + if (kappa * h >= c) + hmax = h; + else + hmin = h; + } + return h; + */ + + double hret; + double kappa = MaxCurvatureLoc (p, x*hmax); + + kappa *= c * mparam.curvaturesafety; + + if (hmax * kappa < 1) + hret = hmax; + else + hret = 1 / kappa; + + if (maxh < hret) + hret = maxh; + + return hret; +} + + + + +Primitive :: Primitive () +{ + surfaceids.SetSize (1); + surfaceactive.SetSize (1); + surfaceactive[0] = 1; +} + +Primitive :: ~Primitive() +{ + ; +} + +int Primitive :: GetSurfaceId (int i) const +{ + return surfaceids[i]; +} + +void Primitive :: SetSurfaceId (int i, int id) +{ + surfaceids[i] = id; +} + + + + +void Primitive :: GetPrimitiveData (char *& classname, + ARRAY<double> & coeffs) const +{ + classname = "undef"; + coeffs.SetSize (0); +} + +void Primitive :: SetPrimitiveData (ARRAY<double> & coeffs) +{ + ; +} + +Primitive * Primitive :: CreatePrimitive (const char * classname) +{ + if (strcmp (classname, "sphere") == 0) + return Sphere::CreateDefault(); + if (strcmp (classname, "plane") == 0) + return Plane::CreateDefault(); + if (strcmp (classname, "cylinder") == 0) + return Cylinder::CreateDefault(); + if (strcmp (classname, "cone") == 0) + return Cone::CreateDefault(); + if (strcmp (classname, "brick") == 0) + return Brick::CreateDefault(); + + cout << "cannot create primitive " << classname << endl; + return NULL; +} + + +Primitive * Primitive :: Copy () const +{ + cout << "Primitive called for baseclass" << endl; + return NULL; +} + + +void Primitive :: Transform (Transformation<3> & trans) +{ + cout << "transform called for baseclass" << endl; +} + + +INSOLID_TYPE Primitive :: +VecInSolid2 (const Point<3> & p, + const Vec<3> & v1, + const Vec<3> & v2, + double eps) const +{ + Point<3> hp = p + 1e-3 * v1 + 1e-5 * v2; + + INSOLID_TYPE res = PointInSolid (hp, eps); + // (*testout) << "vectorin2, type = " << typeid(*this).name() << ", res = " << res << endl; + + return res; +} + + + + + + +OneSurfacePrimitive :: OneSurfacePrimitive() +{ + ; +} + +OneSurfacePrimitive :: ~OneSurfacePrimitive() +{ + ; +} + + +INSOLID_TYPE OneSurfacePrimitive :: +PointInSolid (const Point<3> & p, + double eps) const +{ + double hv1 = (GetSurface(0).CalcFunctionValue(p)); + if (hv1 <= -eps) + return IS_INSIDE; + if (hv1 >= eps) + return IS_OUTSIDE; + return DOES_INTERSECT; +} + +INSOLID_TYPE OneSurfacePrimitive :: +VecInSolid (const Point<3> & p, const Vec<3> & v, + double eps) const +{ + Vec<3> hv; + double hv1; + GetSurface(0).CalcGradient (p, hv); + + hv1 = v * hv; + + if (hv1 <= -eps) + return IS_INSIDE; + if (hv1 >= eps) + return IS_OUTSIDE; + + return DOES_INTERSECT; +} + + +INSOLID_TYPE OneSurfacePrimitive :: +VecInSolid2 (const Point<3> & p, + const Vec<3> & v1, + const Vec<3> & v2, + double eps) const +{ + Vec<3> hv; + double hv1, hv2; + + GetSurface(0).CalcGradient (p, hv); + + hv1 = v1 * hv; + if (hv1 <= -eps) + return IS_INSIDE; + if (hv1 >= eps) + return IS_OUTSIDE; + + hv2 = v2 * hv; + if (hv2 <= 0) + return IS_INSIDE; + else + return IS_OUTSIDE; +} + + + + +int OneSurfacePrimitive :: GetNSurfaces() const +{ + return 1; +} + +Surface & OneSurfacePrimitive :: GetSurface (int i) +{ + return *this; +} + +const Surface & OneSurfacePrimitive :: GetSurface (int i) const +{ + return *this; +} + + + + + + +void ProjectToEdge (const Surface * f1, const Surface * f2, Point<3> & hp) +{ + Vec<2> rs, lam; + Vec<3> a1, a2; + Mat<2> a; + + int i = 10; + while (i > 0) + { + i--; + rs(0) = f1 -> CalcFunctionValue (hp); + rs(1) = f2 -> CalcFunctionValue (hp); + f1->CalcGradient (hp, a1); + f2->CalcGradient (hp, a2); + + a(0,0) = a1 * a1; + a(0,1) = a(1,0) = a1 * a2; + a(1,1) = a2 * a2; + + a.Solve (rs, lam); + + hp -= lam(0) * a1 + lam(1) * a2; + + if (Abs2 (rs) < 1e-24 && i > 1) i = 1; + } +} +} diff --git a/contrib/Netgen/libsrc/csg/surface.hpp b/contrib/Netgen/libsrc/csg/surface.hpp new file mode 100644 index 0000000000..db0b4a74d2 --- /dev/null +++ b/contrib/Netgen/libsrc/csg/surface.hpp @@ -0,0 +1,301 @@ +#ifndef FILE_SURFACE +#define FILE_SURFACE + +/**************************************************************************/ +/* File: surface.hh */ +/* Author: Joachim Schoeberl */ +/* Date: 1. Dez. 95 */ +/**************************************************************************/ + + + + +// class DenseMatrix; +// class Box3dSphere; +class TriangleApproximation; + +/** + Basis class for implicit surface geometry. + This class is used for generation of surface meshes + in NETGEN as well as for mesh refinement in FEPP. + */ + + + + +class Surface +{ +protected: + /// invert normal vector + bool inverse; + /// maximal h in surface + double maxh; + /// name of surface + char * name; + /// boundary condition nr + int bcprop; + /// + +public: + Surface (); + /** @name Tangential plane. + The tangential plane is used for surface mesh generation. + */ + + virtual ~Surface(); + +protected: + /** @name Points in the surface defining tangential plane. + Tangential plane is taken in p1, the local x-axis + is directed to p2. + */ + //@{ + /// + Point<3> p1; + /// + Point<3> p2; + //@} + /** @name Base-vectos for local coordinate system. */ + //@{ + /// in plane, directed p1->p2 + Vec<3> ex; + /// in plane + Vec<3> ey; + /// outer normal direction + Vec<3> ez; + //@} +public: + + void SetName (const char * aname); + const char * Name () const { return name; } + + //@{ + /** + Defines tangential plane in ap1. + The local x-coordinate axis point to the direction of ap2 */ + virtual void DefineTangentialPlane (const Point<3> & ap1, + const Point<3> & ap2); + + /// Transforms 3d point p3d to local coordinates pplane + virtual void ToPlane (const Point<3> & p3d, Point<2> & pplane, + double h, int & zone) const; + + /// Transforms point pplane in local coordinates to 3d point + virtual void FromPlane (const Point<2> & pplane, + Point<3> & p3d, double h) const; + //@} + + + /// Move Point p to closes point in surface + virtual void Project (Point<3> & p) const; + + + virtual int IsIdentic (const Surface & /* s2 */, int & /* inv */, + double /* eps */) const + { return 0; } + + /// + virtual int PointOnSurface (const Point<3> & p, + double eps = 1e-6) const; + + + /** @name Implicit function. + Calculate function value and derivatives. + */ + //@{ + /// Calculate implicit function value in point point + virtual double CalcFunctionValue (const Point<3> & point) const = 0; + + /** + Calc gradient of implicit function. + gradient should be O(1) at surface + */ + virtual void CalcGradient (const Point<3> & point, Vec<3> & grad) const = 0; + + /** + Calculate second derivatives of implicit function. + */ + virtual void CalcHesse (const Point<3> & point, Mat<3> & hesse) const; + + /** + Returns outer normal vector. + */ + // virtual void GetNormalVector (const Point<3> & p, Vec<3> & n) const; + virtual Vec<3> GetNormalVector (const Point<3> & p) const; + + /** + Upper bound for spectral norm of Hesse-matrix + */ + virtual double HesseNorm () const = 0; + + /** + Upper bound for spectral norm of Hesse-matrix in the + rad - environment of point c. + */ + virtual double HesseNormLoc (const Point<3> & /* c */, + double /* rad */) const + { return HesseNorm (); } + //@} + + + /// + virtual double MaxCurvature () const; + /// + virtual double MaxCurvatureLoc (const Point<3> & /* c */ , + double /* rad */) const; + + /** Returns any point in the surface. + Needed to start surface mesh generation e.g. on sphere */ + virtual Point<3> GetSurfacePoint () const = 0; + + /// + bool Inverse () const { return inverse; } + /// + void SetInverse (bool ainverse) { inverse = ainverse; } + /// + virtual void Print (ostream & str) const = 0; + + /// + virtual void Reduce (const BoxSphere<3> & /* box */) { }; + /// + virtual void UnReduce () { }; + + /// set max h in surface + void SetMaxH (double amaxh) { maxh = amaxh; } + /// + double GetMaxH () const { return maxh; } + /// + int GetBCProperty () const { return bcprop; } + /// + void SetBCProperty (int abc) { bcprop = abc; } + + /** Determine local mesh-size. + Find + \[ h \leq hmax, \] + such that + \[ h \times \kappa (x) \leq c \qquad \mbox{in} B(x, h), \] + where kappa(x) is the curvature in x. */ + virtual double LocH (const Point<3> & p, double x, + double c, double hmax) const; + + /** + Gets Approximation by triangles, + where qual is about the number of triangles per radius + */ + virtual void GetTriangleApproximation (TriangleApproximation & /* tas */, + const Box<3> & /* boundingbox */, + double /* facets */ ) const { }; + +#ifdef MYGRAPH + /// + virtual void Plot (const class ROT3D & /* rot */) const { }; +#endif + }; + + +typedef enum { IS_OUTSIDE = 0, IS_INSIDE = 1, DOES_INTERSECT = 2} +INSOLID_TYPE; + + + + +class Primitive +{ + +public: + + Primitive (); + + virtual ~Primitive(); + + + /* + Check, whether box intersects solid defined by surface. + + return values: + 0 .. box outside solid \\ + 1 .. box in solid \\ + 2 .. can't decide (allowed, iff box is close to solid) + */ + virtual INSOLID_TYPE BoxInSolid (const BoxSphere<3> & box) const = 0; + virtual INSOLID_TYPE PointInSolid (const Point<3> & p, + double eps) const = 0; + virtual INSOLID_TYPE VecInSolid (const Point<3> & p, + const Vec<3> & v, + double eps) const = 0; + + // checks if lim s->0 lim t->0 p + t(v1 + s v2) in solid + virtual INSOLID_TYPE VecInSolid2 (const Point<3> & p, + const Vec<3> & v1, + const Vec<3> & v2, + double eps) const; + + + virtual int GetNSurfaces() const = 0; + virtual Surface & GetSurface (int i = 0) = 0; + virtual const Surface & GetSurface (int i = 0) const = 0; + + ARRAY<int> surfaceids; + ARRAY<int> surfaceactive; + + int GetSurfaceId (int i = 0) const; + void SetSurfaceId (int i, int id); + int SurfaceActive (int i) const { return surfaceactive[i]; } + virtual int SurfaceInverted (int i = 0) const { return 0; } + + virtual void GetPrimitiveData (char *& classname, + ARRAY<double> & coeffs) const; + virtual void SetPrimitiveData (ARRAY<double> & coeffs); + static Primitive * CreatePrimitive (const char * classname); + + + virtual void Reduce (const BoxSphere<3> & /* box */) { }; + virtual void UnReduce () { }; + + virtual Primitive * Copy () const; + virtual void Transform (Transformation<3> & trans); +}; + + + + +class OneSurfacePrimitive : public Surface, public Primitive +{ +public: + OneSurfacePrimitive(); + ~OneSurfacePrimitive(); + + virtual INSOLID_TYPE PointInSolid (const Point<3> & p, + double eps) const; + virtual INSOLID_TYPE VecInSolid (const Point<3> & p, + const Vec<3> & v, + double eps) const; + virtual INSOLID_TYPE VecInSolid2 (const Point<3> & p, + const Vec<3> & v1, + const Vec<3> & v2, + double eps) const; + + + virtual int GetNSurfaces() const; + virtual Surface & GetSurface (int i = 0); + virtual const Surface & GetSurface (int i = 0) const; +}; + + + + + + +/** + Projects point to edge. + The point hp is projected to the edge descibed by f1 and f2. + It is assumed that the edge is non-degenerated, and the + (generalized) Newton method converges. + */ +extern void ProjectToEdge (const Surface * f1, + const Surface * f2, + Point<3> & hp); + + + +#endif diff --git a/contrib/Netgen/libsrc/csg/triapprox.cpp b/contrib/Netgen/libsrc/csg/triapprox.cpp new file mode 100644 index 0000000000..403716155b --- /dev/null +++ b/contrib/Netgen/libsrc/csg/triapprox.cpp @@ -0,0 +1,59 @@ +#include <mystdlib.h> +#include <myadt.hpp> + +#include <linalg.hpp> +#include <csg.hpp> + + +namespace netgen +{ + + TriangleApproximation :: TriangleApproximation () + { + ; + } + + int TriangleApproximation :: + AddTriangle (const TATriangle & tri, bool invert) + { + trigs.Append (tri); + if (invert) + { + trigs.Last()[1] = tri[2]; + trigs.Last()[2] = tri[1]; + } + return trigs.Size()-1; + } + + + void TriangleApproximation :: RemoveUnusedPoints () + { + BitArray used(GetNP()); + ARRAY<int> map (GetNP()); + int i, j; + int cnt = 0; + + used.Clear(); + for (i = 0; i < GetNT(); i++) + for (j = 0; j < 3; j++) + used.Set (GetTriangle (i)[j]); + + for (i = 0; i < GetNP(); i++) + if (used.Test(i)) + map[i] = cnt++; + + for (i = 0; i < GetNT(); i++) + for (j = 0; j < 3; j++) + trigs[i][j] = map[trigs[i][j]]; + + for (i = 0; i < GetNP(); i++) + if (used.Test(i)) + { + points[map[i]] = points[i]; + normals[map[i]] = normals[i]; + } + + points.SetSize (cnt); + normals.SetSize (cnt); + } +} diff --git a/contrib/Netgen/libsrc/csg/triapprox.hpp b/contrib/Netgen/libsrc/csg/triapprox.hpp new file mode 100644 index 0000000000..7b2db16b09 --- /dev/null +++ b/contrib/Netgen/libsrc/csg/triapprox.hpp @@ -0,0 +1,57 @@ +#ifndef FILE_TRIAPPROX +#define FILE_TRIAPPROX + +/**************************************************************************/ +/* File: triapprox.hh */ +/* Author: Joachim Schoeberl */ +/* Date: 2. Mar. 98 */ +/**************************************************************************/ + +/** + Triangulated approxiamtion to true surface +*/ + + +class TATriangle +{ + int pi[3]; + int surfind; +public: + TATriangle () { ; } + + TATriangle (int si, int pi1, int pi2, int pi3) + { surfind = si; pi[0] = pi1; pi[1] = pi2; pi[2] = pi3; } + + int SurfaceIndex() const { return surfind; } + int & SurfaceIndex() { return surfind; } + + int & operator[] (int i) { return pi[i]; } + const int & operator[] (int i) const { return pi[i]; } +}; + + +class TriangleApproximation +{ + ARRAY<Point<3> > points; + ARRAY<Vec<3> > normals; + ARRAY<TATriangle> trigs; + +public: + TriangleApproximation(); + int GetNP () const { return points.Size(); } + int GetNT () const { return trigs.Size(); } + + int AddPoint (const Point<3> & p) { points.Append (p); return points.Size()-1; } + int AddNormal (const Vec<3> & n) { normals.Append (n); return normals.Size()-1; } + int AddTriangle (const TATriangle & tri, bool invert = 0); + + const Point<3> & GetPoint (int i) const { return points[i]; } + const TATriangle & GetTriangle (int i) const { return trigs[i]; } + const Vec<3> & GetNormal (int i) const { return normals[i]; } + + void RemoveUnusedPoints (); + + friend class CSGeometry; +}; + +#endif diff --git a/contrib/Netgen/libsrc/general/Makefile b/contrib/Netgen/libsrc/general/Makefile new file mode 100644 index 0000000000..65a387a844 --- /dev/null +++ b/contrib/Netgen/libsrc/general/Makefile @@ -0,0 +1,12 @@ +# +# Makefile for general purpose data types +# +src = array.cpp bitarray.cpp hashtabl.cpp symbolta.cpp table.cpp flags.cpp \ + spbita2d.cpp seti.cpp optmem.cpp sort.cpp mystring.cpp parthreads.cpp \ + moveablemem.cpp dynamicmem.cpp ngexception.cpp +# +lib = gen +libpath = libsrc/general +# +include ../makefile.inc + diff --git a/contrib/Netgen/libsrc/general/array.cpp b/contrib/Netgen/libsrc/general/array.cpp new file mode 100644 index 0000000000..e3bc3e6fdf --- /dev/null +++ b/contrib/Netgen/libsrc/general/array.cpp @@ -0,0 +1,75 @@ +#ifndef FILE_NGSTD_ARRAYCPP +#define FILE_NGSTD_ARRAYCPP +// necessary for SGI ???? + +/**************************************************************************/ +/* File: array.cpp */ +/* Author: Joachim Schoeberl */ +/* Date: 01. Jun. 95 */ +/**************************************************************************/ + +/* + Abstract data type ARRAY +*/ + +#include <mystdlib.h> +#include <myadt.hpp> +#include <assert.h> + + +namespace netgen +{ + using namespace netgen; + +#ifdef NONE + void BASE_ARRAY :: ReSize (int minsize, int elementsize) + { + cout << "resize, minsize = " << minsize << endl; + + if (inc == -1) + throw Exception ("Try to resize fixed size array"); + + + void * p; + int nsize = (inc) ? allocsize + inc : 2 * allocsize; + if (nsize < minsize) nsize = minsize; + + if (data) + { + p = new char [nsize * elementsize]; + + int mins = (nsize < actsize) ? nsize : actsize; + memcpy (p, data, mins * elementsize); + + delete [] static_cast<char*> (data); + data = p; + } + else + { + data = new char[nsize * elementsize]; + } + + allocsize = nsize; + cout << "resize done" << endl; + } + + + + void BASE_ARRAY :: RangeCheck (int i) const + { + if (i < 0 || i >= actsize) + throw ArrayRangeException (); + } + + void BASE_ARRAY :: CheckNonEmpty () const + { + if (!actsize) + { + throw Exception ("Array should not be empty"); + // cerr << "Array souldn't be empty"; + } + } +#endif +} +#endif + diff --git a/contrib/Netgen/libsrc/general/array.hpp b/contrib/Netgen/libsrc/general/array.hpp new file mode 100644 index 0000000000..c953cedeff --- /dev/null +++ b/contrib/Netgen/libsrc/general/array.hpp @@ -0,0 +1,478 @@ +#ifndef FILE_ARRAY +#define FILE_ARRAY + +/**************************************************************************/ +/* File: array.hpp */ +/* Author: Joachim Schoeberl */ +/* Date: 01. Jun. 95 */ +/**************************************************************************/ + + +/** + A simple array container. + Array represented by size and data-pointer. + No memory allocation and deallocation, must be provided by user. + Helper functions for printing. + Optional range check by macro RANGE_CHECK + */ + +template <class T, int BASE = 0> +class FlatArray +{ +protected: + /// the size + int size; + /// the data + T * data; +public: + + /// provide size and memory + inline FlatArray (int asize, T * adata) + : size(asize), data(adata) { ; } + + /// the size + inline int Size() const { return size; } + + + /// access array. + inline T & operator[] (int i) + { +#ifdef DEBUG + if (i-BASE < 0 || i-BASE >= size) + cout << "array<" << typeid(T).name() << "> out of range, i = " << i << ", s = " << size << endl; +#endif + + return data[i-BASE]; + } + + + /// Access array. + inline const T & operator[] (int i) const + { +#ifdef DEBUG + if (i-BASE < 0 || i-BASE >= size) + cout << "array<" << typeid(T).name() << "> out of range, i = " << i << ", s = " << size << endl; +#endif + + return data[i-BASE]; + } + + /// + T & Elem (int i) + { +#ifdef DEBUG + if (i < 1 || i > size) + cout << "ARRAY<" << typeid(T).name() + << ">::Elem out of range, i = " << i + << ", s = " << size << endl; +#endif + + return ((T*)data)[i-1]; + } + + /// + const T & Get (int i) const + { +#ifdef DEBUG + if (i < 1 || i > size) + cout << "ARRAY<" << typeid(T).name() << ">::Get out of range, i = " << i + << ", s = " << size << endl; +#endif + + return ((const T*)data)[i-1]; + } + + /// + void Set (int i, const T & el) + { +#ifdef DEBUG + if (i < 1 || i > size) + cout << "ARRAY<" << typeid(T).name() << ">::Set out of range, i = " << i + << ", s = " << size << endl; +#endif + + ((T*)data)[i-1] = el; + } + + + /// access last element. check by macro CHECK_RANGE + T & Last () + { + return data[size-1]; + } + + /// access last element. check by macro CHECK_RANGE + const T & Last () const + { + return data[size-1]; + } + + /// Fill array with value val + FlatArray & operator= (const T & val) + { + for (int i = 0; i < size; i++) + data[i] = val; + return *this; + } +}; + + + + +// print array +template <class T, int BASE> +inline ostream & operator<< (ostream & s, const FlatArray<T,BASE> & a) +{ + for (int i = BASE; i < a.Size()+BASE; i++) + s << i << ": " << a[i] << endl; + return s; +} + + + + +/** + Dynamic array container. + + ARRAY<T> is an automatically increasing array container. + The allocated memory doubles on overflow. + Either the container takes care of memory allocation and deallocation, + or the user provides one block of data. +*/ +template <class T, int BASE = 0> +class ARRAY : public FlatArray<T, BASE> +{ +protected: + /// physical size of array + int allocsize; + /// memory is responsibility of container + bool ownmem; + +public: + + /// Generate array of logical and physical size asize + explicit ARRAY(int asize = 0) + : FlatArray<T, BASE> (asize, asize ? new T[asize] : 0) + { + allocsize = asize; + ownmem = 1; + } + + /// Generate array in user data + ARRAY(int asize, T* adata) + : FlatArray<T, BASE> (asize, adata) + { + allocsize = asize; + ownmem = 0; + } + + /// array copy + explicit ARRAY (const ARRAY<T> & a2) + : FlatArray<T, BASE> (a2.Size(), a2.Size() ? new T[a2.Size()] : 0) + { + allocsize = this->size; + ownmem = 1; + for (int i = BASE; i < this->size+BASE; i++) + (*this)[i] = a2[i]; + } + + + + /// if responsible, deletes memory + ~ARRAY() + { + if (ownmem) + delete [] this->data; + } + + /// Change logical size. If necessary, do reallocation. Keeps contents. + void SetSize(int nsize) + { + if (nsize > allocsize) + ReSize (nsize); + this->size = nsize; + } + + /// Change physical size. Keeps logical size. Keeps contents. + void SetAllocSize (int nallocsize) + { + if (nallocsize > allocsize) + ReSize (nallocsize); + } + + + /// Add element at end of array. reallocation if necessary. + int Append (const T & el) + { + if (this->size == allocsize) + ReSize (this->size+1); + this->data[this->size] = el; + this->size++; + return this->size; + } + + + /// Delete element i (0-based). Move last element to position i. + void Delete (int i) + { +#ifdef CHECK_ARRAY_RANGE + RangeCheck (i+1); +#endif + + this->data[i] = this->data[this->size-1]; + this->size--; + // DeleteElement (i+1); + } + + + /// Delete element i (1-based). Move last element to position i. + void DeleteElement (int i) + { +#ifdef CHECK_ARRAY_RANGE + RangeCheck (i); +#endif + + this->data[i-1] = this->data[this->size-1]; + this->size--; + } + + /// Delete last element. + void DeleteLast () + { + this->size--; + } + + /// Deallocate memory + void DeleteAll () + { + if (ownmem) + delete [] this->data; + this->data = 0; + this->size = allocsize = 0; + } + + /// Fill array with val + ARRAY & operator= (const T & val) + { + FlatArray<T, BASE>::operator= (val); + return *this; + } + + /// array copy + ARRAY & operator= (const ARRAY & a2) + { + SetSize (a2.Size()); + for (int i = BASE; i < this->size+BASE; i++) + (*this)[i] = a2[i]; + return *this; + } + +private: + + /// resize array, at least to size minsize. copy contents + void ReSize (int minsize) + { + int nsize = 2 * allocsize; + if (nsize < minsize) nsize = minsize; + + if (this->data) + { + T * p = new T[nsize]; + + int mins = (nsize < this->size) ? nsize : this->size; + memcpy (p, this->data, mins * sizeof(T)); + + if (ownmem) + delete [] this->data; + ownmem = 1; + this->data = p; + } + else + { + this->data = new T[nsize]; + ownmem = 1; + } + + allocsize = nsize; + } +}; + + + +template <class T, int S> +class ArrayMem : public ARRAY<T> +{ + // T mem[S]; + // char mem[S*sizeof(T)]; + double mem[(S*sizeof(T)+7) / 8]; +public: + /// Generate array of logical and physical size asize + explicit ArrayMem(int asize = 0) + : ARRAY<T> (S, static_cast<T*> (static_cast<void*>(&mem[0]))) + { + this->SetSize (asize); + } + + ArrayMem & operator= (const T & val) + { + ARRAY<T>::operator= (val); + return *this; + } +}; + + + + + + + + + + + +/// +template <class T> class MoveableArray +{ + int size; + int allocsize; + MoveableMem<T> data; + +public: + + MoveableArray() + { + size = allocsize = 0; + data.SetName ("MoveableArray"); + } + + MoveableArray(int asize) + : size(asize), allocsize(asize), data(asize) + { ; } + + ~MoveableArray () { ; } + + int Size() const { return size; } + + void SetSize(int nsize) + { + if (nsize > allocsize) + { + data.ReAlloc (nsize); + allocsize = nsize; + } + size = nsize; + } + + void SetAllocSize (int nallocsize) + { + data.ReAlloc (nallocsize); + allocsize = nallocsize; + } + + /// + T & operator[] (int i) + { return ((T*)data)[i]; } + + /// + const T & operator[] (int i) const + { return ((const T*)data)[i]; } + + /// + T & Elem (int i) + { return ((T*)data)[i-1]; } + + /// + const T & Get (int i) const + { return ((const T*)data)[i-1]; } + + /// + void Set (int i, const T & el) + { ((T*)data)[i-1] = el; } + + /// + T & Last () + { return ((T*)data)[size-1]; } + + /// + const T & Last () const + { return ((const T*)data)[size-1]; } + + /// + int Append (const T & el) + { + if (size == allocsize) + { + SetAllocSize (2*allocsize+1); + } + ((T*)data)[size] = el; + size++; + return size; + } + + /// + void Delete (int i) + { + DeleteElement (i+1); + } + + /// + void DeleteElement (int i) + { + ((T*)data)[i-1] = ((T*)data)[size-1]; + size--; + } + + /// + void DeleteLast () + { size--; } + + /// + void DeleteAll () + { + size = allocsize = 0; + data.Free(); + } + + /// + void PrintMemInfo (ostream & ost) const + { + ost << Size() << " elements of size " << sizeof(T) << " = " + << Size() * sizeof(T) << endl; + } + + MoveableArray & operator= (const T & el) + { + for (int i = 0; i < size; i++) + ((T*)data)[i] = el; + return *this; + } + + void SetName (char * aname) + { + data.SetName(aname); + } +private: + /// + MoveableArray & operator= (MoveableArray &); + /// + MoveableArray (const MoveableArray &); +}; + + +template <class T> +inline ostream & operator<< (ostream & ost, MoveableArray<T> & a) +{ + for (int i = 0; i < a.Size(); i++) + ost << i << ": " << a[i] << endl; + return ost; +} + + + + + + + + +#endif + diff --git a/contrib/Netgen/libsrc/general/autoptr.hpp b/contrib/Netgen/libsrc/general/autoptr.hpp new file mode 100644 index 0000000000..b90841408b --- /dev/null +++ b/contrib/Netgen/libsrc/general/autoptr.hpp @@ -0,0 +1,31 @@ +#ifndef FILE_AUTOPTR +#define FILE_AUTOPTR + +/**************************************************************************/ +/* File: autoptr.hpp */ +/* Author: STL, Joachim Schoeberl */ +/* Date: 29. Dec. 02 */ +/**************************************************************************/ + +template <typename T> +class AutoPtr +{ +private: + T * ptr; +public: + typedef T* pT; + explicit AutoPtr (T * p = 0) { ptr = p; } + ~AutoPtr () { delete ptr; } + + T & operator*() const { return *ptr; } + T* operator->() const { return ptr; } + T *& Ptr() { return ptr; } + T * Ptr() const { return ptr; } + void Reset(T * p = 0) { if (p != ptr) { delete ptr; ptr = p; } } + operator bool () { return ptr != 0; } +private: + AutoPtr (AutoPtr &) { ; } + AutoPtr & operator= (AutoPtr &) { ; } +}; + +#endif diff --git a/contrib/Netgen/libsrc/general/bitarray.cpp b/contrib/Netgen/libsrc/general/bitarray.cpp new file mode 100644 index 0000000000..0d03fd5c45 --- /dev/null +++ b/contrib/Netgen/libsrc/general/bitarray.cpp @@ -0,0 +1,132 @@ +/**************************************************************************/ +/* File: bitarray.cc */ +/* Autho: Joachim Schoeberl */ +/* Date: 01. Jun. 95 */ +/**************************************************************************/ + +/* + data type BitArray +*/ + +#include <mystdlib.h> +#include <myadt.hpp> + + +namespace netgen +{ + using namespace netgen; + + BitArray :: BitArray () + { + size = 0; + data = NULL; + } + + BitArray :: BitArray (int asize) + { + size = 0; + data = NULL; + SetSize (asize); + } + + BitArray :: ~BitArray () + { + delete [] data; + } + + void BitArray :: SetSize (int asize) + { + if (size == asize) return; + delete [] data; + + size = asize; + data = new unsigned char [Addr (size)+1]; + } + + void BitArray :: Set () + { + if (!size) return; + for (int i = 0; i <= Addr (size); i++) + data[i] = UCHAR_MAX; + } + + void BitArray :: Clear () + { + if (!size) return; + for (int i = 0; i <= Addr (size); i++) + data[i] = 0; + } + + + + void BitArray :: Invert () + { + if (!size) return; + for (int i = 0; i <= Addr (size); i++) + data[i] ^= 255; + } + + void BitArray :: And (const BitArray & ba2) + { + if (!size) return; + for (int i = 0; i <= Addr (size); i++) + data[i] &= ba2.data[i]; + } + + + void BitArray :: Or (const BitArray & ba2) + { + if (!size) return; + for (int i = 0; i <= Addr (size); i++) + data[i] |= ba2.data[i]; + } + + + + + + + + + + + + template <int BASE> + void BitArrayChar<BASE> :: Set () + { + data = 1; + } + + template <int BASE> + void BitArrayChar<BASE> :: Clear () + { + data = 0; + } + + + template <int BASE> + void BitArrayChar<BASE> :: Invert () + { + for (int i = BASE; i < data.Size()+BASE; i++) + data[i] = 1 - data[i]; + } + + template <int BASE> + void BitArrayChar<BASE> :: And (const BitArrayChar & ba2) + { + for (int i = BASE; i < data.Size()+BASE; i++) + data[i] &= ba2.data[i]; + } + + + template <int BASE> + void BitArrayChar<BASE> :: Or (const BitArrayChar & ba2) + { + for (int i = BASE; i < data.Size()+BASE; i++) + data[i] |= ba2.data[i]; + } + + + template class BitArrayChar<0>; + template class BitArrayChar<1>; +} diff --git a/contrib/Netgen/libsrc/general/bitarray.hpp b/contrib/Netgen/libsrc/general/bitarray.hpp new file mode 100644 index 0000000000..1b7042fa5a --- /dev/null +++ b/contrib/Netgen/libsrc/general/bitarray.hpp @@ -0,0 +1,207 @@ +#ifndef FILE_BitArray +#define FILE_BitArray + +/**************************************************************************/ +/* File: bitarray.hpp */ +/* Author: Joachim Schoeberl */ +/* Date: 01. Jun. 95 */ +/**************************************************************************/ + +#include <limits.h> + +/** + data type BitArray + + BitArray is a compressed array of Boolean information. By Set and Clear + the whole array or one bit can be set or reset, respectively. + Test returns the state of the accoring bit. + No range checking is done. + + index ranges from 0 to size-1 +*/ +class BitArray +{ + /// + INDEX size; + /// + unsigned char * data; + +public: + /// + BitArray (); + /// + BitArray (INDEX asize); + /// + ~BitArray (); + + /// + void SetSize (INDEX asize); + /// + inline INDEX Size () const; + + /// + void Set (); + /// + inline void Set (INDEX i); + /// + void Clear (); + /// + inline void Clear (INDEX i); + /// + inline int Test (INDEX i) const; + /// + void Invert (); + /// + void And (const BitArray & ba2); + /// + void Or (const BitArray & ba2); +private: + /// + inline unsigned char Mask (INDEX i) const; + /// + inline INDEX Addr (INDEX i) const; + + /// + BitArray & operator= (BitArray &); + /// + BitArray (const BitArray &); +}; + + + + + +// print bitarray +inline ostream & operator<< (ostream & s, const BitArray & a) +{ + for (int i = 1; i <= a.Size(); i++) + { + s << a.Test(i); + if (i % 40 == 0) s << "\n"; + } + if (a.Size() % 40 != 0) s << "\n"; + return s; +} + + + +inline +INDEX BitArray :: Size () const + { + return size; + } + +inline +unsigned char BitArray :: Mask (INDEX i) const + { + return char(1) << (i % CHAR_BIT); + } + +inline +INDEX BitArray :: Addr (INDEX i) const + { + return (i / CHAR_BIT); + } + +inline +void BitArray :: Set (INDEX i) + { + data[Addr(i)] |= Mask(i); + } + +inline +void BitArray :: Clear (INDEX i) + { + data[Addr(i)] &= ~Mask(i); + } + +inline +int BitArray :: Test (INDEX i) const + { + return (data[i / CHAR_BIT] & (char(1) << (i % CHAR_BIT) ) ) ? 1 : 0; + } + + + + + + + + +/** + data type BitArrayChar + + BitArray is an array of Boolean information. By Set and Clear + the whole array or one bit can be set or reset, respectively. + Test returns the state of the accoring bit. + No range checking is done. +*/ +template <int BASE = 1> +class BitArrayChar +{ + /// + ARRAY<char,BASE> data; + +public: + /// + BitArrayChar () + { ; } + /// + BitArrayChar (int asize) + : data(asize) + { ; } + /// + ~BitArrayChar () + { ; } + + /// + void SetSize (int asize) + { data.SetSize(asize); } + + /// + inline int Size () const + { return data.Size(); } + + /// + void Set (); + /// + inline void Set (int i) + { data[i] = 1; } + /// + void Clear (); + /// + inline void Clear (int i) + { data[i] = 0; } + /// + inline int Test (int i) const + { return data[i]; } + /// + void Invert (); + /// + void And (const BitArrayChar & ba2); + /// + void Or (const BitArrayChar & ba2); +private: + /// copy bitarray is not supported + BitArrayChar & operator= (BitArrayChar &) { return *this; } + /// copy bitarray is not supported + BitArrayChar (const BitArrayChar &) { ; } +}; + + + + +template <int BASE> +inline ostream & operator<< (ostream & s, const BitArrayChar<BASE> & a) +{ + for (int i = BASE; i < a.Size()+BASE; i++) + { + s << a.Test(i); + if ( (i-BASE) % 40 == 39) s << "\n"; + } + if (a.Size() % 40 != 0) s << "\n"; + return s; +} + + +#endif diff --git a/contrib/Netgen/libsrc/general/dynamicmem.cpp b/contrib/Netgen/libsrc/general/dynamicmem.cpp new file mode 100644 index 0000000000..66b22cb4a7 --- /dev/null +++ b/contrib/Netgen/libsrc/general/dynamicmem.cpp @@ -0,0 +1,117 @@ +#include <iostream> +#include <iomanip> + +#include <myadt.hpp> +using namespace std; + +namespace netgen +{ + +BaseDynamicMem * BaseDynamicMem::first = 0; +BaseDynamicMem * BaseDynamicMem::last = 0; + + +BaseDynamicMem :: BaseDynamicMem () +{ + prev = last; + next = 0; + + if (last) last->next = this; + last = this; + if (!first) first = this; + + size = 0; + ptr = 0; + name = 0; +} + +BaseDynamicMem :: ~BaseDynamicMem () +{ + Free(); + + if (next) next->prev = prev; + else last = prev; + if (prev) prev->next = next; + else first = next; + + delete [] name; +} + +void BaseDynamicMem :: SetName (const char * aname) +{ + delete [] name; + if (aname) + { + name = new char[strlen(aname)+1]; + strcpy (name, aname); + } +} + + +void BaseDynamicMem :: Alloc (size_t s) +{ + size = s; + // ptr = new char[s]; + ptr = (char*)malloc (s); +} + +void BaseDynamicMem :: ReAlloc (size_t s) +{ + if (size == s) return; + + char * old = ptr; + // ptr = new char[s]; + ptr = (char*)malloc(s); + memmove (ptr, old, (s < size) ? s : size); + // delete old; + free (old); + size = s; +} + +void BaseDynamicMem :: Free () +{ + // delete ptr; + free (ptr); + ptr = 0; +} + +void BaseDynamicMem :: Swap (BaseDynamicMem & m2) +{ + int hi; + char * cp; + hi = size; size = m2.size; m2.size = hi; + cp = ptr; ptr = m2.ptr; m2.ptr = cp; + cp = name; name = m2.name; m2.name = cp; +} + + +void BaseDynamicMem :: Print () +{ + cout << "****************** Dynamic Mem Report ****************" << endl; + BaseDynamicMem * p = first; + int mem = 0; + int cnt = 0; + while (p) + { + mem += p->size; + cnt++; + + cout << setw(10) << p->size << " Bytes"; + if (p->name) + cout << " in block " << p->name; + cout << endl; + + p = p->next; + } + + if (mem > 100000000) + cout << "memory in dynamic memory: " << mem/1048576 << " MB" << endl; + else if (mem > 100000) + cout << "memory in dynamic memory: " << mem/1024 << " kB" << endl; + else + cout << "memory in dynamic memory: " << mem << " Bytes" << endl; + cout << "number of blocks: " << cnt << endl; + // cout << "******************************************************" << endl; +} + +} diff --git a/contrib/Netgen/libsrc/general/dynamicmem.hpp b/contrib/Netgen/libsrc/general/dynamicmem.hpp new file mode 100644 index 0000000000..501020988e --- /dev/null +++ b/contrib/Netgen/libsrc/general/dynamicmem.hpp @@ -0,0 +1,94 @@ +#ifndef FILE_DYNAMICMEM +#define FILE_DYNAMICMEM + +/**************************************************************************/ +/* File: dynamicmem.hpp */ +/* Author: Joachim Schoeberl */ +/* Date: 12. Feb. 2003 */ +/**************************************************************************/ + + + + +class BaseDynamicMem +{ +private: + static BaseDynamicMem *first, *last; + + BaseDynamicMem *prev, *next; + size_t size; + char * ptr; + char * name; + +protected: + BaseDynamicMem (); + ~BaseDynamicMem (); + void Alloc (size_t s); + void ReAlloc (size_t s); + void Free (); + char * Ptr() { return ptr; } + const char * Ptr() const { return ptr; } + void Swap (BaseDynamicMem & m2); +public: + void SetName (const char * aname); + static void Print (); +}; + + +template <typename T> +class DynamicMem : public BaseDynamicMem +{ +public: + DynamicMem () + : BaseDynamicMem () + { + ; + } + DynamicMem (size_t s) + : BaseDynamicMem () + { + Alloc (s); + } + void Alloc (size_t s) + { + BaseDynamicMem::Alloc (sizeof(T) * s); + } + void ReAlloc (size_t s) + { + BaseDynamicMem::ReAlloc (sizeof(T) * s); + } + void Free () + { + BaseDynamicMem::Free (); + } + + const T * Ptr() const + { + return reinterpret_cast<const T*> (BaseDynamicMem::Ptr()); + } + + T * Ptr() + { + return reinterpret_cast<T*> (BaseDynamicMem::Ptr()); + } + + operator const T* () const + { + return reinterpret_cast<const T*> (BaseDynamicMem::Ptr()); + } + + operator T* () + { + return reinterpret_cast<T*> (BaseDynamicMem::Ptr()); + } + + void Swap (DynamicMem<T> & m2) + { + BaseDynamicMem::Swap (m2); + } +protected: + DynamicMem (const DynamicMem & m); + DynamicMem & operator= (const DynamicMem & m); +}; + +#endif diff --git a/contrib/Netgen/libsrc/general/flags.cpp b/contrib/Netgen/libsrc/general/flags.cpp new file mode 100644 index 0000000000..9cce0cef2f --- /dev/null +++ b/contrib/Netgen/libsrc/general/flags.cpp @@ -0,0 +1,330 @@ +/**************************************************************************/ +/* File: flags.cc */ +/* Author: Joachim Schoeberl */ +/* Date: 10. Oct. 96 */ +/**************************************************************************/ + +/* + Datatype Flags +*/ + +#include <mystdlib.h> +#include <myadt.hpp> + +namespace netgen +{ + using namespace netgen; + + Flags :: Flags () + { + ; + } + + Flags :: ~Flags () + { + DeleteFlags (); + } + + void Flags :: DeleteFlags () + { + for (int i = 0; i < strflags.Size(); i++) + delete [] strflags[i]; + for (int i = 0; i < numlistflags.Size(); i++) + delete numlistflags[i]; + strflags.DeleteAll(); + numflags.DeleteAll(); + defflags.DeleteAll(); + strlistflags.DeleteAll(); + numlistflags.DeleteAll(); + } + + void Flags :: SetFlag (const char * name, const char * val) + { + char * hval = new char[strlen (val) + 1]; + strcpy (hval, val); + strflags.Set (name, hval); + } + + void Flags :: SetFlag (const char * name, double val) + { + numflags.Set (name, val); + } + + void Flags :: SetFlag (const char * name) + { + defflags.Set (name, 1); + } + + + void Flags :: SetFlag (const char * name, const ARRAY<char*> & val) + { + ARRAY<char*> * strarray = new ARRAY<char*>; + for (int i = 1; i <= val.Size(); i++) + { + strarray->Append (new char[strlen(val.Get(i))+1]); + strcpy (strarray->Last(), val.Get(i)); + } + strlistflags.Set (name, strarray); + } + + void Flags :: SetFlag (const char * name, const ARRAY<double> & val) + { + ARRAY<double> * numarray = new ARRAY<double>; + for (int i = 1; i <= val.Size(); i++) + numarray->Append (val.Get(i)); + numlistflags.Set (name, numarray); + } + + + + + + const char * + Flags :: GetStringFlag (const char * name, const char * def) const + { + if (strflags.Used (name)) + return strflags.Get(name); + else + return def; + } + + double Flags :: GetNumFlag (const char * name, double def) const + { + if (numflags.Used (name)) + return numflags.Get(name); + else + return def; + } + + const double * Flags :: GetNumFlagPtr (const char * name) const + { + if (numflags.Used (name)) + return & ((SYMBOLTABLE<double>&)numflags).Elem(name); + else + return NULL; + } + + double * Flags :: GetNumFlagPtr (const char * name) + { + if (numflags.Used (name)) + return & ((SYMBOLTABLE<double>&)numflags).Elem(name); + else + return NULL; + } + + int Flags :: GetDefineFlag (const char * name) const + { + return defflags.Used (name); + } + + + const ARRAY<char*> & + Flags :: GetStringListFlag (const char * name) const + { + if (strlistflags.Used (name)) + return *strlistflags.Get(name); + else + { + static ARRAY<char*> hstra(0); + return hstra; + } + } + + const ARRAY<double> & + Flags ::GetNumListFlag (const char * name) const + { + if (numlistflags.Used (name)) + return *numlistflags.Get(name); + else + { + static ARRAY<double> hnuma(0); + return hnuma; + } + } + + + int Flags :: StringFlagDefined (const char * name) const + { + return strflags.Used (name); + } + + int Flags :: NumFlagDefined (const char * name) const + { + return numflags.Used (name); + } + + int Flags :: StringListFlagDefined (const char * name) const + { + return strlistflags.Used (name); + } + + int Flags :: NumListFlagDefined (const char * name) const + { + return numlistflags.Used (name); + } + + + void Flags :: SaveFlags (const char * filename) const + { + int i; + ofstream outfile (filename); + + for (i = 1; i <= strflags.Size(); i++) + outfile << strflags.GetName(i) << " = " << strflags.Get(i) << endl; + for (i = 1; i <= numflags.Size(); i++) + outfile << numflags.GetName(i) << " = " << numflags.Get(i) << endl; + for (i = 1; i <= defflags.Size(); i++) + outfile << defflags.GetName(i) << endl; + } + + + + void Flags :: PrintFlags (ostream & ost) const + { + int i; + + for (i = 1; i <= strflags.Size(); i++) + ost << strflags.GetName(i) << " = " << strflags.Get(i) << endl; + for (i = 1; i <= numflags.Size(); i++) + ost << numflags.GetName(i) << " = " << numflags.Get(i) << endl; + for (i = 1; i <= defflags.Size(); i++) + ost << defflags.GetName(i) << endl; + } + + + void Flags :: LoadFlags (const char * filename) + { + char name[100], str[100]; + char ch; + double val; + ifstream infile(filename); + + // (*logout) << "Load flags from " << filename << endl << endl; + while (infile.good()) + { + infile >> name; + if (strlen (name) == 0) break; + + if (name[0] == '/' && name[1] == '/') + { + // (*logout) << "comment: "; + ch = 0; + while (ch != '\n' && infile.good()) + { + ch = infile.get(); + // (*logout) << ch; + } + continue; + } + + // (*logout) << name; + ch = 0; + infile >> ch; + if (ch != '=') + { + // (*logout) << endl; + infile.putback (ch); + SetFlag (name); + } + else + { + infile >> val; + if (!infile.good()) + { + infile.clear(); + infile >> str; + SetFlag (name, str); + // (*logout) << " = " << str << endl; + } + else + { + SetFlag (name, val); + // (*logout) << " = " << val << endl; + } + } + } + // (*logout) << endl; + } + + + void Flags :: SetCommandLineFlag (const char * st) + { + // cout << "clflag = " << st << endl; + istringstream inst( (char *)st); + // istrstream defined with char * (not const char * ?????) + + char name[100]; + double val; + + + if (st[0] != '-') + { + cerr << "flag must start with '-'" << endl; + return; + } + + const char * pos = strchr (st, '='); + + if (!pos) + { + // (cout) << "Add def flag: " << st+1 << endl; + SetFlag (st+1); + } + else + { + // cout << "pos = " << pos << endl; + + strncpy (name, st+1, (pos-st)-1); + name[pos-st-1] = 0; + + // cout << "name = " << name << endl; + + pos++; + char * endptr = NULL; + + val = strtod (pos, &endptr); + + // cout << "val = " << val << endl; + + if (endptr == pos) + { + // (cout) << "Add String Flag: " << name << " = " << pos << endl; + SetFlag (name, pos); + } + else + { + // (cout) << "Add Num Flag: " << name << " = " << val << endl; + SetFlag (name, val); + } + } + + + /* + inst >> name; + (*mycout) << "name = " << name << endl; + + ch = 0; + inst >> ch; + if (ch != '=') + { + SetFlag (name); + } + else + { + inst >> val; + if (!inst.good()) + { + inst.clear(); + inst >> str; + SetFlag (name, str); + (*mycout) << "str = " << str << endl; + } + else + { + SetFlag (name, val); + (*mycout) << "val = " << val << endl; + } + } + */ + } +} diff --git a/contrib/Netgen/libsrc/general/flags.hpp b/contrib/Netgen/libsrc/general/flags.hpp new file mode 100644 index 0000000000..7c62f7815b --- /dev/null +++ b/contrib/Netgen/libsrc/general/flags.hpp @@ -0,0 +1,83 @@ +#ifndef FILE_FLAGS +#define FILE_FLAGS + + +/**************************************************************************/ +/* File: flags.hh */ +/* Author: Joachim Schoeberl */ +/* Date: 10. Oct. 96 */ +/**************************************************************************/ + +/** + Flag - Table. + A flag table maintains string variables, numerical + variables and boolean flags. +*/ +class Flags +{ + /// + SYMBOLTABLE<char *> strflags; + /// + SYMBOLTABLE<double> numflags; + /// + SYMBOLTABLE<int> defflags; + /// + SYMBOLTABLE<ARRAY<char*>*> strlistflags; + /// + SYMBOLTABLE<ARRAY<double>*> numlistflags; +public: + /// + Flags (); + /// + ~Flags (); + + /// Deletes all flags + void DeleteFlags (); + /// Sets string flag, overwrite if exists + void SetFlag (const char * name, const char * val); + /// Sets numerical flag, overwrite if exists + void SetFlag (const char * name, double val); + /// Sets boolean flag + void SetFlag (const char * name); + /// Sets string arary falg + void SetFlag (const char * name, const ARRAY<char*> & val); + /// Sets double array flag + void SetFlag (const char * name, const ARRAY<double> & val); + + /// Save flags to file + void SaveFlags (const char * filename) const; + /// write flags to stream + void PrintFlags (ostream & ost) const; + /// Load flags from file + void LoadFlags (const char * filename); + /// set flag of form -name=hello -val=0.5 -defined + void SetCommandLineFlag (const char * st); + + /// Returns string flag, default value if not exists + const char * GetStringFlag (const char * name, const char * def) const; + /// Returns numerical flag, default value if not exists + double GetNumFlag (const char * name, double def) const; + /// Returns address of numerical flag, null if not exists + const double * GetNumFlagPtr (const char * name) const; + /// Returns address of numerical flag, null if not exists + double * GetNumFlagPtr (const char * name); + /// Returns boolean flag + int GetDefineFlag (const char * name) const; + /// Returns string list flag, empty array if not exist + const ARRAY<char*> & GetStringListFlag (const char * name) const; + /// Returns num list flag, empty array if not exist + const ARRAY<double> & GetNumListFlag (const char * name) const; + + + /// Test, if string flag is defined + int StringFlagDefined (const char * name) const; + /// Test, if num flag is defined + int NumFlagDefined (const char * name) const; + /// Test, if string list flag is defined + int StringListFlagDefined (const char * name) const; + /// Test, if num list flag is defined + int NumListFlagDefined (const char * name) const; +}; + +#endif + diff --git a/contrib/Netgen/libsrc/general/hashtabl.cpp b/contrib/Netgen/libsrc/general/hashtabl.cpp new file mode 100644 index 0000000000..0485ab6045 --- /dev/null +++ b/contrib/Netgen/libsrc/general/hashtabl.cpp @@ -0,0 +1,294 @@ +/**************************************************************************/ +/* File: hashtabl.cpp */ +/* Author: Joachim Schoeberl */ +/* Date: 01. Jun. 95 */ +/**************************************************************************/ + +/* + Abstract data type HASHTABLE +*/ + +#include <algorithm> +#include <mystdlib.h> +#include <myadt.hpp> + +namespace netgen +{ + using namespace netgen; + + void INDEX_4 :: Sort () + { + if (i[0] > i[1]) Swap (i[0], i[1]); + if (i[2] > i[3]) Swap (i[2], i[3]); + if (i[0] > i[2]) Swap (i[0], i[2]); + if (i[1] > i[3]) Swap (i[1], i[3]); + if (i[1] > i[2]) Swap (i[1], i[2]); + } + + + + void INDEX_4Q :: Sort () + { + if (min2 (i[1], i[2]) < min2 (i[0], i[3])) + { Swap (i[0], i[1]); Swap (i[2], i[3]);} + if (i[3] < i[0]) + { Swap (i[0], i[3]); Swap (i[1], i[2]);} + if (i[3] < i[1]) + { Swap (i[1], i[3]); } + } + + + ostream & operator<<(ostream & s, const INDEX_2 & i2) + { + return s << i2.I1() << ", " << i2.I2(); + } + + ostream & operator<<(ostream & s, const INDEX_3 & i3) + { + return s << i3.I1() << ", " << i3.I2() << ", " << i3.I3(); + } + + ostream & operator<<(ostream & s, const INDEX_4 & i4) + { + return s << i4.I1() << ", " << i4.I2() << ", " << i4.I3() << ", " << i4.I4(); + } + + ostream & operator<<(ostream & s, const INDEX_4Q & i4) + { + return s << i4.I1() << ", " << i4.I2() << ", " << i4.I3() << ", " << i4.I4(); + } + + + int BASE_INDEX_HASHTABLE :: Position (int bnr, const INDEX & ind) const + { + int i; + for (i = 1; i <= hash.EntrySize (bnr); i++) + if (hash.Get(bnr, i) == ind) + return i; + return 0; + } + + + + /* + int BASE_INDEX_2_HASHTABLE :: Position (int bnr, const INDEX_2 & ind) const + { + int i; + for (i = 1; i <= hash.EntrySize (bnr); i++) + if (hash.Get(bnr, i) == ind) + return i; + return 0; + } + */ + + void BASE_INDEX_2_HASHTABLE :: PrintStat (ostream & ost) const + { + int n = hash.Size(); + int i; + int sumn = 0, sumnn = 0; + + for (i = 1; i <= n; i++) + { + sumn += hash.EntrySize(i); + sumnn += sqr (hash.EntrySize(i)); + } + + ost << "Hashtable: " << endl + << "size : " << n << endl + << "elements per row : " << (double(sumn) / double(n)) << endl + << "av. acces time : " + << (sumn ? (double (sumnn) / double(sumn)) : 0) << endl; + } + + + /* + int BASE_INDEX_3_HASHTABLE :: Position (int bnr, const INDEX_3 & ind) const + { + int i; + const INDEX_3 * pi = &hash.Get(bnr, 1); + int n = hash.EntrySize(bnr); + for (i = 1; i <= n; ++i, ++pi) + { + if (*pi == ind) + return i; + } + + return 0; + } + */ + + + + + + + + + + + + + + + + + + BASE_INDEX_2_CLOSED_HASHTABLE :: + BASE_INDEX_2_CLOSED_HASHTABLE (int size) + : hash(size) + { + hash.SetName ("i2-hashtable, hash"); + + invalid = -1; + int i; + for (i = 1; i <= size; i++) + hash.Elem(i).I1() = invalid; + } + + void BASE_INDEX_2_CLOSED_HASHTABLE :: + BaseSetSize (int size) + { + int i; + hash.SetSize(size); + for (i = 1; i <= size; i++) + hash.Elem(i).I1() = invalid; + } + + + int BASE_INDEX_2_CLOSED_HASHTABLE :: + Position2 (const INDEX_2 & ind) const + { + int i; + + i = HashValue(ind); + while (1) + { + i++; + if (i > hash.Size()) i = 1; + if (hash.Get(i) == ind) return i; + if (hash.Get(i).I1() == invalid) return 0; + } + } + + + + int BASE_INDEX_2_CLOSED_HASHTABLE :: + PositionCreate2 (const INDEX_2 & ind, int & apos) + { + int i; + + i = HashValue(ind); + while (1) + { + i++; + if (i > hash.Size()) i = 1; + if (hash.Get(i) == ind) + { + apos = i; + return 0; + } + if (hash.Get(i).I1() == invalid) + { + hash.Elem(i) = ind; + apos = i; + return 1; + } + } + } + + int BASE_INDEX_2_CLOSED_HASHTABLE :: UsedElements () const + { + int i, n = hash.Size(); + int cnt = 0; + for (i = 1; i <= n; i++) + if (hash.Get(i).I1() != invalid) + cnt++; + return cnt; + } + + + + + + + + + + + + BASE_INDEX_3_CLOSED_HASHTABLE :: + BASE_INDEX_3_CLOSED_HASHTABLE (int size) + : hash(size) + { + hash.SetName ("i3-hashtable, hash"); + + invalid = -1; + int i; + for (i = 1; i <= size; i++) + hash.Elem(i).I1() = invalid; + } + + void BASE_INDEX_3_CLOSED_HASHTABLE :: + BaseSetSize (int size) + { + int i; + hash.SetSize(size); + for (i = 1; i <= size; i++) + hash.Elem(i).I1() = invalid; + } + + + int BASE_INDEX_3_CLOSED_HASHTABLE :: + Position2 (const INDEX_3 & ind) const + { + int i; + + i = HashValue(ind); + while (1) + { + i++; + if (i > hash.Size()) i = 1; + if (hash.Get(i) == ind) return i; + if (hash.Get(i).I1() == invalid) return 0; + } + } + + + + int BASE_INDEX_3_CLOSED_HASHTABLE :: + PositionCreate2 (const INDEX_3 & ind, int & apos) + { + int i; + + i = HashValue(ind); + while (1) + { + i++; + if (i > hash.Size()) i = 1; + if (hash.Get(i) == ind) + { + apos = i; + return 0; + } + if (hash.Get(i).I1() == invalid) + { + hash.Elem(i) = ind; + apos = i; + return 1; + } + } + } + + int BASE_INDEX_3_CLOSED_HASHTABLE :: UsedElements () const + { + int i, n = hash.Size(); + int cnt = 0; + for (i = 1; i <= n; i++) + if (hash.Get(i).I1() != invalid) + cnt++; + return cnt; + } + + +} + diff --git a/contrib/Netgen/libsrc/general/hashtabl.hpp b/contrib/Netgen/libsrc/general/hashtabl.hpp new file mode 100644 index 0000000000..b3e0e93f7e --- /dev/null +++ b/contrib/Netgen/libsrc/general/hashtabl.hpp @@ -0,0 +1,1000 @@ +#ifndef FILE_HASHTABL +#define FILE_HASHTABL + +/**************************************************************************/ +/* File: hashtabl.hh */ +/* Author: Joachim Schoeberl */ +/* Date: 01. Jun. 95 */ +/**************************************************************************/ + +/** + Abstract data type HASHTABLE. + Hash is done by one INDEX +*/ +class BASE_INDEX_HASHTABLE +{ +protected: + /// keys are stored in this table + TABLE<INDEX> hash; + +public: + /// + BASE_INDEX_HASHTABLE (int size) + : hash (size) { }; + +protected: + /// + int HashValue (const INDEX & ind) const + { + return ind % hash.Size() + 1; + } + + /// + int Position (int bnr, const INDEX & ind) const; +}; + +/// +template <class T> +class INDEX_HASHTABLE : private BASE_INDEX_HASHTABLE +{ + /// + TABLE<T> cont; + +public: + /// + inline INDEX_HASHTABLE (int size); + /// + inline void Set (const INDEX & hash, const T & acont); + /// + inline const T & Get (const INDEX & ahash) const; + /// + inline bool Used (const INDEX & ahash) const; + /// + inline int GetNBags () const; + /// + inline int GetBagSize (int bnr) const; + /// + inline void GetData (int bnr, int colnr, INDEX & ahash, T & acont) const; + + /// + inline void PrintMemInfo (ostream & ost) const; +}; + + + + + + + + + + + +/// +class BASE_INDEX_2_HASHTABLE +{ +protected: + /// + TABLE<INDEX_2> hash; + +public: + /// + BASE_INDEX_2_HASHTABLE (int size) + : hash (size) { }; + + /// + void PrintStat (ostream & ost) const; + void BaseSetSize(int s) {hash.SetSize(s);} +protected: + /// + int HashValue (const INDEX_2 & ind) const + { + return (ind.I1() + ind.I2()) % hash.Size() + 1; + } + /// + int Position (int bnr, const INDEX_2 & ind) const + { + int i; + for (i = 1; i <= hash.EntrySize (bnr); i++) + if (hash.Get(bnr, i) == ind) + return i; + return 0; + } +}; + + +/// +template <class T> +class INDEX_2_HASHTABLE : public BASE_INDEX_2_HASHTABLE +{ + /// + TABLE<T> cont; + +public: + /// + INDEX_2_HASHTABLE (int size) + : BASE_INDEX_2_HASHTABLE (size), cont(size) + { ; } + + /// + void SetSize(int s) + { + cont.SetSize(s); + BaseSetSize(s); + } + + /// + void Set (const INDEX_2 & ahash, const T & acont) + { + int bnr = HashValue (ahash); + int pos = Position (bnr, ahash); + if (pos) + cont.Set (bnr, pos, acont); + else + { + hash.Add1 (bnr, ahash); + cont.Add1 (bnr, acont); + } + } + + /// + const T & Get (const INDEX_2 & ahash) const + { + int bnr = HashValue (ahash); + int pos = Position (bnr, ahash); + return cont.Get (bnr, pos); + } + + /// + bool Used (const INDEX_2 & ahash) const + { + return (Position (HashValue (ahash), ahash)) ? 1 : 0; + } + + /// + int GetNBags () const + { + return cont.Size(); + } + + /// + int GetBagSize (int bnr) const + { + return cont.EntrySize (bnr); + } + + /// + void GetData (int bnr, int colnr, + INDEX_2 & ahash, T & acont) const + { + ahash = hash.Get(bnr, colnr); + acont = cont.Get(bnr, colnr); + } + + /// + void SetData (int bnr, int colnr, + const INDEX_2 & ahash, const T & acont) + { + hash.Set(bnr, colnr, ahash); + cont.Set(bnr, colnr, acont); + } + + /// + void PrintMemInfo (ostream & ost) const + { + ost << "Hash: " << endl; + hash.PrintMemInfo (ost); + ost << "Cont: " << endl; + cont.PrintMemInfo (ost); + } + + + + class Iterator + { + const INDEX_2_HASHTABLE & ht; + int bagnr, pos; + public: + Iterator (const INDEX_2_HASHTABLE & aht, + int abagnr, int apos) + : ht(aht), bagnr(abagnr), pos(apos) + { ; } + + int BagNr() const { return bagnr; } + int Pos() const { return pos; } + + void operator++ (int) + { + // cout << "begin Operator ++: bagnr = " << bagnr << " - pos = " << pos << endl; + pos++; + while (bagnr < ht.GetNBags() && + pos == ht.GetBagSize(bagnr+1)) + { + pos = 0; + bagnr++; + } + // cout << "end Operator ++: bagnr = " << bagnr << " - pos = " << pos << endl; + } + + bool operator != (int i) const + { + return bagnr != i; + } + + }; + + Iterator Begin () const + { + Iterator it(*this, 0, -1); + it++; + return it; + } + + int End() const + { + return GetNBags(); + } + + void GetData (const Iterator & it, + INDEX_2 & ahash, T & acont) const + { + ahash = hash[it.BagNr()][it.Pos()]; + acont = cont[it.BagNr()][it.Pos()]; + } + + const INDEX_2 & GetHash (const Iterator & it) const + { return hash[it.BagNr()][it.Pos()]; } + + const T & GetData (const Iterator & it) const + { return cont[it.BagNr()][it.Pos()]; } +}; + + + +template <typename T> +inline ostream & operator<< (ostream & ost, const INDEX_2_HASHTABLE<T> & ht) +{ + for (typename INDEX_2_HASHTABLE<T>::Iterator it = ht.Begin(); + it != ht.End(); it++) + { + ost << ht.GetHash(it) << ": " << ht.GetData(it) << endl; + } + + return ost; +} + + + + + + + +/// +class BASE_INDEX_3_HASHTABLE +{ +protected: + /// + TABLE<INDEX_3> hash; + +public: + /// + BASE_INDEX_3_HASHTABLE (int size) + : hash (size) { }; + +protected: + /// + int HashValue (const INDEX_3 & ind) const + { + return (ind.I1() + ind.I2() + ind.I3()) % hash.Size() + 1; + } + + /// + int Position (int bnr, const INDEX_3 & ind) const + { + const INDEX_3 * pi = &hash.Get(bnr, 1); + int n = hash.EntrySize(bnr); + for (int i = 1; i <= n; ++i, ++pi) + { + if (*pi == ind) + return i; + } + + return 0; + } + + +}; + + +/// +template <class T> +class INDEX_3_HASHTABLE : private BASE_INDEX_3_HASHTABLE +{ + /// + TABLE<T> cont; + +public: + /// + inline INDEX_3_HASHTABLE (int size); + /// + inline void Set (const INDEX_3 & ahash, const T & acont); + /// + inline const T & Get (const INDEX_3 & ahash) const; + /// + inline bool Used (const INDEX_3 & ahash) const; + /// + inline int GetNBags () const; + /// + inline int GetBagSize (int bnr) const; + /// + inline void SetData (int bnr, int colnr, const INDEX_3 & ahash, const T & acont); + /// + inline void GetData (int bnr, int colnr, INDEX_3 & ahash, T & acont) const; + /// returns position, if not existing, will create (create == return 1) + inline int PositionCreate (const INDEX_3 & ahash, int & bnr, int & colnr); + /// + inline void SetSize (int size); + + /// + inline void PrepareSet (const INDEX_3 & ahash); + /// + inline void AllocateElements (); + + /// + inline void PrintMemInfo (ostream & ost) const; + /// + inline void DeleteData (); +}; + + + + + + + + +/// Closed Hashing HT + +class BASE_INDEX_2_CLOSED_HASHTABLE +{ +protected: + /// + MoveableArray<INDEX_2> hash; + /// + int invalid; +public: + /// + BASE_INDEX_2_CLOSED_HASHTABLE (int size); + + int Size() const { return hash.Size(); } + int UsedPos (int pos) const { return ! (hash.Get(pos).I1() == invalid); } + int UsedElements () const; + + /// + int HashValue (const INDEX_2 & ind) const + { + return (ind.I1() + 71 * ind.I2()) % hash.Size() + 1; + } + + + int Position (const INDEX_2 & ind) const + { + int i = HashValue(ind); + while (1) + { + if (hash.Get(i) == ind) return i; + if (hash.Get(i).I1() == invalid) return 0; + i++; + if (i > hash.Size()) i = 1; + } + /* + int pos = HashValue (ind); + if (hash.Get(pos) == ind) return pos; + return Position2 (ind); + */ + } + + // returns 1, if new postion is created + int PositionCreate (const INDEX_2 & ind, int & apos) + { + int i = HashValue (ind); + if (hash.Get(i) == ind) + { + apos = i; + return 0; + } + if (hash.Get(i).I1() == invalid) + { + hash.Elem(i) = ind; + apos = i; + return 1; + } + return PositionCreate2 (ind, apos); + } + +protected: + /// + + int Position2 (const INDEX_2 & ind) const; + int PositionCreate2 (const INDEX_2 & ind, int & apos); + void BaseSetSize (int asize); +}; + + +template <class T> +class INDEX_2_CLOSED_HASHTABLE : public BASE_INDEX_2_CLOSED_HASHTABLE +{ + /// + MoveableArray<T> cont; + +public: + /// + inline INDEX_2_CLOSED_HASHTABLE (int size); + /// + inline void Set (const INDEX_2 & ahash, const T & acont); + /// + inline const T & Get (const INDEX_2 & ahash) const; + /// + inline bool Used (const INDEX_2 & ahash) const; + /// + inline void SetData (int pos, const INDEX_2 & ahash, const T & acont); + /// + inline void GetData (int pos, INDEX_2 & ahash, T & acont) const; + /// + inline void SetData (int pos, const T & acont); + /// + inline void GetData (int pos, T & acont) const; + /// + const T & GetData (int pos) { return cont.Get(pos); } + /// + inline void SetSize (int size); + /// + inline void PrintMemInfo (ostream & ost) const; + /// + inline void DeleteData () + { SetSize (cont.Size()); } + + void SetName (const char * aname) + { + cont.SetName(aname); + hash.SetName(aname); + } +}; + + + + + + + + + + + + + +class BASE_INDEX_3_CLOSED_HASHTABLE +{ +protected: + /// + MoveableArray<INDEX_3> hash; + /// + int invalid; +public: + /// + BASE_INDEX_3_CLOSED_HASHTABLE (int size); + + int Size() const { return hash.Size(); } + bool UsedPos (int pos) const { return ! (hash.Get(pos).I1() == invalid); } + int UsedElements () const; + + /// + int HashValue (const INDEX_3 & ind) const + { + return (ind.I1() + 15 * ind.I2() + 41 * ind.I3()) % hash.Size() + 1; + } + + int Position (const INDEX_3 & ind) const + { + int i = HashValue(ind); + while (1) + { + if (hash.Get(i) == ind) return i; + if (hash.Get(i).I1() == invalid) return 0; + i++; + if (i > hash.Size()) i = 1; + } + /* + int pos = HashValue (ind); + if (hash.Get(pos) == ind) return pos; + return Position2 (ind); + */ + } + + // returns 1, if new postion is created + int PositionCreate (const INDEX_3 & ind, int & apos) + { + int i = HashValue (ind); + if (hash.Get(i) == ind) + { + apos = i; + return 0; + } + if (hash.Get(i).I1() == invalid) + { + hash.Elem(i) = ind; + apos = i; + return 1; + } + return PositionCreate2 (ind, apos); + } + + +protected: + /// + + int Position2 (const INDEX_3 & ind) const; + int PositionCreate2 (const INDEX_3 & ind, int & apos); + void BaseSetSize (int asize); +}; + + +template <class T> +class INDEX_3_CLOSED_HASHTABLE : public BASE_INDEX_3_CLOSED_HASHTABLE +{ + /// + MoveableArray<T> cont; + +public: + /// + inline INDEX_3_CLOSED_HASHTABLE (int size); + /// + inline void Set (const INDEX_3 & ahash, const T & acont); + /// + inline const T & Get (const INDEX_3 & ahash) const; + /// + inline bool Used (const INDEX_3 & ahash) const; + /// + inline void SetData (int pos, const INDEX_3 & ahash, const T & acont); + /// + inline void GetData (int pos, INDEX_3 & ahash, T & acont) const; + /// + inline void SetData (int pos, const T & acont); + /// + inline void GetData (int pos, T & acont) const; + /// + inline const T & GetData (int pos) const; + /// + inline void SetSize (int size); + /// + inline void PrintMemInfo (ostream & ost) const; + /// + inline void DeleteData () + { SetSize (cont.Size()); } + + void SetName (const char * aname) + { + cont.SetName(aname); + hash.SetName(aname); + } +}; + + + + + + + + + + + + + + + + +template<class T> +inline INDEX_3_HASHTABLE<T> :: INDEX_3_HASHTABLE (int size) + : BASE_INDEX_3_HASHTABLE (size), cont(size) +{ + ; +} + +template<class T> +inline int INDEX_3_HASHTABLE<T> :: PositionCreate (const INDEX_3 & ahash, int & bnr, int & colnr) +{ + bnr = HashValue (ahash); + colnr = Position (bnr, ahash); + if (!colnr) + { + hash.Add (bnr, ahash); + cont.AddEmpty (bnr); + colnr = cont.EntrySize (bnr); + return 1; + } + return 0; +} + + +template<class T> +inline void INDEX_3_HASHTABLE<T> :: Set (const INDEX_3 & ahash, const T & acont) +{ + int bnr = HashValue (ahash); + int pos = Position (bnr, ahash); + if (pos) + cont.Set (bnr, pos, acont); + else + { + hash.Add1 (bnr, ahash); + cont.Add1 (bnr, acont); + } +} + +template<class T> +inline const T & INDEX_3_HASHTABLE<T> :: Get (const INDEX_3 & ahash) const +{ + int bnr = HashValue (ahash); + int pos = Position (bnr, ahash); + return cont.Get (bnr, pos); +} + +template<class T> +inline bool INDEX_3_HASHTABLE<T> :: Used (const INDEX_3 & ahash) const +{ + return (Position (HashValue (ahash), ahash)) ? 1 : 0; +} + +template<class T> +inline int INDEX_3_HASHTABLE<T> :: GetNBags () const +{ + return cont.Size(); +} + +template<class T> +inline int INDEX_3_HASHTABLE<T> :: GetBagSize (int bnr) const +{ + return cont.EntrySize (bnr); +} + +template<class T> +inline void INDEX_3_HASHTABLE<T> :: GetData (int bnr, int colnr, INDEX_3 & ahash, T & acont) const +{ + ahash = hash.Get(bnr, colnr); + acont = cont.Get(bnr, colnr); +} + +template<class T> +inline void INDEX_3_HASHTABLE<T> :: SetData (int bnr, int colnr, const INDEX_3 & ahash, const T & acont) +{ + hash.Set(bnr, colnr, ahash); + cont.Set(bnr, colnr, acont); +} + +template<class T> +inline void INDEX_3_HASHTABLE<T> :: SetSize (int size) +{ + hash.SetSize (size); + cont.SetSize (size); +} + +template<class T> +inline void INDEX_3_HASHTABLE<T> :: DeleteData () +{ + int n = hash.Size(); + hash.SetSize (n); + cont.SetSize (n); +} + +template<class T> +inline void INDEX_3_HASHTABLE<T> :: PrepareSet (const INDEX_3 & ahash) +{ + int bnr = HashValue (ahash); + hash.IncSizePrepare (bnr-1); + cont.IncSizePrepare (bnr-1); +} + + +template<class T> +inline void INDEX_3_HASHTABLE<T> :: AllocateElements () +{ + hash.AllocateElementsOneBlock(); + cont.AllocateElementsOneBlock(); +} + + + +template<class T> +inline void INDEX_3_HASHTABLE<T> :: PrintMemInfo (ostream & ost) const + { + ost << "Hash: " << endl; + hash.PrintMemInfo (ost); + ost << "Cont: " << endl; + cont.PrintMemInfo (ost); + } + + + + + +template<class T> +inline INDEX_HASHTABLE<T> :: INDEX_HASHTABLE (int size) + : BASE_INDEX_HASHTABLE (size), cont(size) + { + ; + } + +template<class T> +inline void INDEX_HASHTABLE<T> :: Set (const INDEX & ahash, const T & acont) + { + int bnr = HashValue (ahash); + int pos = Position (bnr, ahash); + if (pos) + cont.Set (bnr, pos, acont); + else + { + hash.Add (bnr, ahash); + cont.Add (bnr, acont); + } + } + +template<class T> +inline const T & INDEX_HASHTABLE<T> :: Get (const INDEX & ahash) const + { + int bnr = HashValue (ahash); + int pos = Position (bnr, ahash); + return cont.Get (bnr, pos); + } + +template<class T> +inline bool INDEX_HASHTABLE<T> :: Used (const INDEX & ahash) const + { + return (Position (HashValue (ahash), ahash)) ? 1 : 0; + } + +template<class T> +inline int INDEX_HASHTABLE<T> :: GetNBags () const + { + return hash.Size(); + } + +template<class T> +inline int INDEX_HASHTABLE<T> :: GetBagSize (int bnr) const + { + return hash.EntrySize(bnr); + } + +template<class T> +inline void INDEX_HASHTABLE<T> :: GetData (int bnr, int colnr, INDEX & ahash, T & acont) const + { + ahash = hash.Get(bnr, colnr); + acont = cont.Get(bnr, colnr); + } + +template<class T> +inline void INDEX_HASHTABLE<T> :: PrintMemInfo (ostream & ost) const + { + ost << "Hash: " << endl; + hash.PrintMemInfo (ost); + ost << "Cont: " << endl; + cont.PrintMemInfo (ost); + } + + + + + + + + + + + + + + + +/* *********** Closed Hashing ************************* */ + + + + +template<class T> +inline INDEX_2_CLOSED_HASHTABLE<T> :: +INDEX_2_CLOSED_HASHTABLE (int size) + : BASE_INDEX_2_CLOSED_HASHTABLE(size), cont(size) +{ + cont.SetName ("i2-hashtable, contents"); +} + +template<class T> +inline void INDEX_2_CLOSED_HASHTABLE<T> :: +Set (const INDEX_2 & ahash, const T & acont) +{ + int pos; + PositionCreate (ahash, pos); + hash.Elem(pos) = ahash; + cont.Elem(pos) = acont; +} + +template<class T> +inline const T & INDEX_2_CLOSED_HASHTABLE<T> :: +Get (const INDEX_2 & ahash) const +{ + int pos = Position (ahash); + return cont.Get(pos); +} + +template<class T> +inline bool INDEX_2_CLOSED_HASHTABLE<T> :: +Used (const INDEX_2 & ahash) const +{ + int pos = Position (ahash); + return (pos != 0); +} + +template<class T> +inline void INDEX_2_CLOSED_HASHTABLE<T> :: +SetData (int pos, const INDEX_2 & ahash, const T & acont) +{ + hash.Elem(pos) = ahash; + cont.Elem(pos) = acont; +} + +template<class T> +inline void INDEX_2_CLOSED_HASHTABLE<T> :: +GetData (int pos, INDEX_2 & ahash, T & acont) const +{ + ahash = hash.Get(pos); + acont = cont.Get(pos); +} + +template<class T> +inline void INDEX_2_CLOSED_HASHTABLE<T> :: +SetData (int pos, const T & acont) +{ + cont.Elem(pos) = acont; +} + +template<class T> +inline void INDEX_2_CLOSED_HASHTABLE<T> :: +GetData (int pos, T & acont) const +{ + acont = cont.Get(pos); +} + + +template<class T> +inline void INDEX_2_CLOSED_HASHTABLE<T> :: +SetSize (int size) +{ + BaseSetSize(size); + cont.SetSize(size); +} + + + +template<class T> +inline void INDEX_2_CLOSED_HASHTABLE<T> :: +PrintMemInfo (ostream & ost) const +{ + cout << "Hashtable: " << Size() + << " entries of size " << sizeof(INDEX_2) << " + " << sizeof(T) + << " = " << Size() * (sizeof(INDEX_2) + sizeof(T)) << " bytes." + << " Used els: " << UsedElements() + << endl; +} + + + + + + + + + + + + + + + + + +template<class T> +inline INDEX_3_CLOSED_HASHTABLE<T> :: +INDEX_3_CLOSED_HASHTABLE (int size) + : BASE_INDEX_3_CLOSED_HASHTABLE(size), cont(size) +{ + cont.SetName ("i3-hashtable, contents"); +} + +template<class T> +inline void INDEX_3_CLOSED_HASHTABLE<T> :: +Set (const INDEX_3 & ahash, const T & acont) +{ + int pos; + PositionCreate (ahash, pos); + hash.Elem(pos) = ahash; + cont.Elem(pos) = acont; +} + +template<class T> +inline const T & INDEX_3_CLOSED_HASHTABLE<T> :: +Get (const INDEX_3 & ahash) const +{ + int pos = Position (ahash); + return cont.Get(pos); +} + +template<class T> +inline bool INDEX_3_CLOSED_HASHTABLE<T> :: +Used (const INDEX_3 & ahash) const +{ + int pos = Position (ahash); + return (pos != 0); +} + +template<class T> +inline void INDEX_3_CLOSED_HASHTABLE<T> :: +SetData (int pos, const INDEX_3 & ahash, const T & acont) +{ + hash.Elem(pos) = ahash; + cont.Elem(pos) = acont; +} + +template<class T> +inline void INDEX_3_CLOSED_HASHTABLE<T> :: +GetData (int pos, INDEX_3 & ahash, T & acont) const +{ + ahash = hash.Get(pos); + acont = cont.Get(pos); +} + +template<class T> +inline void INDEX_3_CLOSED_HASHTABLE<T> :: +SetData (int pos, const T & acont) +{ + cont.Elem(pos) = acont; +} + +template<class T> +inline void INDEX_3_CLOSED_HASHTABLE<T> :: +GetData (int pos, T & acont) const +{ + acont = cont.Get(pos); +} + +template<class T> +inline const T & INDEX_3_CLOSED_HASHTABLE<T> :: +GetData (int pos) const +{ + return cont.Get(pos); +} + + +template<class T> +inline void INDEX_3_CLOSED_HASHTABLE<T> :: +SetSize (int size) +{ + BaseSetSize(size); + cont.SetSize(size); +} + + + +template<class T> +inline void INDEX_3_CLOSED_HASHTABLE<T> :: +PrintMemInfo (ostream & ost) const +{ + cout << "Hashtable: " << Size() + << " entries of size " << sizeof(INDEX_3) << " + " << sizeof(T) + << " = " << Size() * (sizeof(INDEX_3) + sizeof(T)) << " bytes" << endl; +} + + + + + + +#endif diff --git a/contrib/Netgen/libsrc/general/moveablemem.cpp b/contrib/Netgen/libsrc/general/moveablemem.cpp new file mode 100644 index 0000000000..cdfac0e7b8 --- /dev/null +++ b/contrib/Netgen/libsrc/general/moveablemem.cpp @@ -0,0 +1,249 @@ +#include <iostream> +#include <iomanip> + +#include <myadt.hpp> +using namespace std; +namespace netgen +{ + + NgMutex mem_mutex; + + size_t BaseMoveableMem::totalsize = 0; // 500000000; + size_t BaseMoveableMem::used = 0; + char * BaseMoveableMem::largeblock = 0; + + BaseMoveableMem * BaseMoveableMem::first = 0; + BaseMoveableMem * BaseMoveableMem::last = 0; + + + BaseMoveableMem :: BaseMoveableMem (size_t s) + { + // cout << "Construct object begin" << endl; + // Print (); + + prev = last; + next = 0; + + if (last) last->next = this; + last = this; + if (!first) first = this; + + size = 0; + + if (prev) + pos = prev->pos + prev->size; + else + pos = 0; + + ptr = 0; + name = NULL; + + if (s) Alloc(s); +} + +BaseMoveableMem :: ~BaseMoveableMem () throw() +{ + Free(); + + if (next) next->prev = prev; + else last = prev; + if (prev) prev->next = next; + else first = next; + + if(name != NULL) + { + delete [] name; + name = NULL; + } +} + +void BaseMoveableMem :: SetName (const char * aname) +{ + if(name != NULL) + { + delete [] name; + name = NULL; + } + if (aname) + { + name = new char[strlen(aname)+1]; + strcpy (name, aname); + } +} + + +void BaseMoveableMem :: Alloc (size_t s) +{ + if (totalsize == 0) + { + size = s; + ptr = (char*) malloc(s); + return; + } + + + used += s - size; + + int r = s % 8; + if (r) s += 8-r; + if (prev) + pos = prev->pos + prev->size; + else + pos = 0; + size = s; + + if (next) + { + NgLock lock(mem_mutex); + lock.Lock(); + try + { + next->MoveTo (pos+size); + } + catch (NgException e) + { + lock.UnLock(); + throw NgException ("MoveableMem overflow"); + } + lock.UnLock(); + } + + if (size) + { + if (!largeblock) + { + cout << "moveable memory: allocate large block of " + << totalsize / 1048576 << " MB" << endl; + // largeblock = new char[totalsize]; + largeblock = (char*)malloc (totalsize); + } + ptr = largeblock+pos; + + if (pos + size > totalsize) + throw NgException ("MoveableMem overflow"); + } + else + ptr = 0; +} + +void BaseMoveableMem :: ReAlloc (size_t s) +{ + if (totalsize == 0) + { + if (size == s) return; + + char * old = ptr; + ptr = (char*)malloc(s); + memmove (ptr, old, (s < size) ? s : size); + free (old); + size = s; + return; + } + + Alloc (s); +} + +void BaseMoveableMem :: MoveTo (size_t newpos) +{ + // cout << "move block, oldpos = " << pos << "; newpos = " << newpos + // << ", size = " << size << endl; + static int move = 0; + + if (newpos + size > totalsize) + throw NgException ("MoveableMem overflow"); + if (newpos > pos) + { + if (next) next->MoveTo (newpos+size); + memmove (largeblock+newpos, largeblock+pos, size); + move += size; + } + else if (newpos < pos) + { + // cout << "move down: " << size << endl; + memmove (largeblock+newpos, largeblock+pos, size); + if (next) next->MoveTo (newpos+size); + move += size; + } + pos = newpos; + ptr = largeblock+pos; + // cout << "total move: " << move << endl; +} + +void BaseMoveableMem :: Free () throw() +{ + if (totalsize == 0) + { + free (ptr); + ptr = 0; + return; + } + + /* + cout << "free block, pos = " << pos << "size = " << size << endl; + cout << "before: " << endl; + Print(); + */ + used -= size; + if (next) + { + NgLock lock(mem_mutex); + lock.Lock(); + next->MoveTo (pos); + lock.UnLock(); + } + + size = 0; + ptr = 0; + // pos = 0; +} + +void BaseMoveableMem :: Swap (BaseMoveableMem & m2) throw() +{ + int hi; + // BaseMoveableMem * hp; + char * cp; + hi = size; size = m2.size; m2.size = hi; + hi = pos; pos = m2.pos; m2.pos = hi; + /* + hp = prev; prev = m2.prev; m2.prev = hp; + hp = next; next = m2.next; m2.next = hp; + */ + cp = ptr; ptr = m2.ptr; m2.ptr = cp; + cp = name; name = m2.name; m2.name = cp; +} + + +void BaseMoveableMem :: Print () +{ + cout << "****************** Moveable Mem Report ****************" << endl; + BaseMoveableMem * p = first; + int mem = 0; + int cnt = 0; + while (p) + { + mem += p->size; + cnt++; + + cout << setw(10) << p->size << " Bytes"; + cout << ", pos = " << p->pos; + // cout << ", addr = " << p->ptr; + if (p->name) + cout << " in block " << p->name; + cout << endl; + + p = p->next; + } + + if (mem > 100000000) + cout << "memory in moveable arena: " << mem/1048576 << " MB" << endl; + else if (mem > 100000) + cout << "memory in moveable arena: " << mem/1024 << " kB" << endl; + else + cout << "memory in moveable arena: " << mem << " Bytes" << endl; + cout << "number of blocks: " << cnt << endl; + + cout << " used = " << used << endl; + // cout << "******************************************************" << endl; +} + +} diff --git a/contrib/Netgen/libsrc/general/moveablemem.hpp b/contrib/Netgen/libsrc/general/moveablemem.hpp new file mode 100644 index 0000000000..92a67ad6da --- /dev/null +++ b/contrib/Netgen/libsrc/general/moveablemem.hpp @@ -0,0 +1,97 @@ +#ifndef FILE_MOVEABLEMEM +#define FILE_MOVEABLEMEM + +/**************************************************************************/ +/* File: moveablemem.hpp */ +/* Author: Joachim Schoeberl */ +/* Date: 12. Feb. 2003 */ +/**************************************************************************/ + + +extern NgMutex mem_mutex; + +class BaseMoveableMem +{ +public: + static size_t totalsize; + static size_t used; + +private: + static char * largeblock; + static BaseMoveableMem *first, *last; + + BaseMoveableMem *prev, *next; + size_t size, pos; + char * ptr; + char * name; + +protected: + BaseMoveableMem (size_t s = 0); + ~BaseMoveableMem () throw(); + void Alloc (size_t s); + void ReAlloc (size_t s); + void MoveTo (size_t newpos); + void Free () throw(); + char * Ptr() { return ptr; } + const char * Ptr() const { return ptr; } + void Swap (BaseMoveableMem & m2) throw(); +public: + void SetName (const char * aname); + static void Print (); +}; + + + + +template <typename T> +class MoveableMem : public BaseMoveableMem +{ +public: + MoveableMem (size_t s = 0) + : BaseMoveableMem (sizeof(T) * s) + { + ; + } + void Alloc (size_t s) + { + BaseMoveableMem::Alloc (sizeof(T) * s); + } + void ReAlloc (size_t s) + { + BaseMoveableMem::ReAlloc (sizeof(T) * s); + } + void Free () + { + BaseMoveableMem::Free (); + } + + const T * Ptr() const + { + return reinterpret_cast<const T*> (BaseMoveableMem::Ptr()); + } + + T * Ptr() + { + return reinterpret_cast<T*> (BaseMoveableMem::Ptr()); + } + + operator const T* () const + { + return reinterpret_cast<const T*> (BaseMoveableMem::Ptr()); + } + + operator T* () + { + return reinterpret_cast<T*> (BaseMoveableMem::Ptr()); + } + + void Swap (MoveableMem<T> & m2) + { + BaseMoveableMem::Swap (m2); + } +protected: + MoveableMem (const MoveableMem & m) { ; } + MoveableMem & operator= (const MoveableMem & m) { ; } +}; + +#endif diff --git a/contrib/Netgen/libsrc/general/myadt.hpp b/contrib/Netgen/libsrc/general/myadt.hpp new file mode 100644 index 0000000000..f74976d51f --- /dev/null +++ b/contrib/Netgen/libsrc/general/myadt.hpp @@ -0,0 +1,43 @@ +#ifndef FILE_MYADT +#define FILE_MYADT + +/**************************************************************************/ +/* File: myadt.hpp */ +/* Author: Joachim Schoeberl */ +/* Date: 01. Jun. 95 */ +/**************************************************************************/ + +/* + include for all abstract data types +*/ + + + +#include <mystdlib.h> +#include <mydefs.hpp> + + +namespace netgen +{ +#include "ngexception.hpp" +#include "parthreads.hpp" +#include "moveablemem.hpp" +#include "dynamicmem.hpp" + +#include "template.hpp" +#include "array.hpp" +#include "table.hpp" +#include "hashtabl.hpp" +#include "symbolta.hpp" +#include "bitarray.hpp" +#include "flags.hpp" +#include "spbita2d.hpp" +#include "seti.hpp" +#include "optmem.hpp" +#include "autoptr.hpp" +#include "sort.hpp" +#include "stack.hpp" +#include "mystring.hpp" +} + +#endif diff --git a/contrib/Netgen/libsrc/general/mystring.cpp b/contrib/Netgen/libsrc/general/mystring.cpp new file mode 100644 index 0000000000..6b0f0cee74 --- /dev/null +++ b/contrib/Netgen/libsrc/general/mystring.cpp @@ -0,0 +1,386 @@ + +//************************************************************** +// +// filename: mystring.cpp +// +// project: doctoral thesis +// +// autor: Dipl.-Ing. Gerstmayr Johannes +// +// generated: 20.12.98 +// last change: 20.12.98 +// description: implementation for strings +// remarks: +// +//************************************************************** + +// string class +#include <mystdlib.h> +#include <myadt.hpp> + +#include <linalg.hpp> +#include <gprim.hpp> + +/* +#include <iostream.h> +#include <string.h> +#include <stdlib.h> +#include <stdio.h> +#include <math.h> +#include <fstream.h> +#include "mystring.hh" + + */ + +namespace netgen +{ + +void DefaultStringErrHandler() +{ + cerr << "Fehler : Bereichs�berschreitung bei Stringoperation\n" << flush; +} + +void (*MyStr::ErrHandler)() = DefaultStringErrHandler; + + /* +MyStr::MyStr() +{ + length = 0; + str = shortstr; + str[0] = 0; +} + */ + +MyStr::MyStr(const char *s) +{ + length = strlen(s); + + if (length > SHORTLEN) + str = new char[length + 1]; + else + str = shortstr; + strcpy(str, s); +} + +/* +MyStr::MyStr(char s) +{ + length = 1; + str = shortstr; + str[0] = s; + str[1] = (char)0; +} +*/ + +MyStr::MyStr(const MyStr& s) +{ + length = s.length; + if (length > SHORTLEN) + str = new char[length + 1]; + else + str = shortstr; + strcpy(str, s.str); +} + +MyStr::MyStr(int i) +{ + char buffer[32]; + sprintf(buffer, "%d", i); + length = strlen(buffer); + if (length > SHORTLEN) + str = new char[length + 1]; + else + str = shortstr; + strcpy(str, buffer); +} + +MyStr::MyStr(long l) +{ + char buffer[32]; + sprintf(buffer, "%ld", l); + length = strlen(buffer); + if (length > SHORTLEN) + str = new char[length + 1]; + else + str = shortstr; + strcpy(str, buffer); +} + +MyStr::MyStr(double d) +{ + char buffer[32]; + //if (fabs(d) < 1E-100) {d = 0;} + sprintf(buffer, "%g", d); + length = strlen(buffer); + if (length > SHORTLEN) + str = new char[length + 1]; + else + str = shortstr; + strcpy(str, buffer); +} + +MyStr::MyStr(const Point3d& p) +{ + char buffer[80]; + //if (fabs(d) < 1E-100) {d = 0;} + sprintf(buffer, "[%g, %g, %g]", p.X(), p.Y(), p.Z()); + length = strlen(buffer); + if (length > SHORTLEN) + str = new char[length + 1]; + else + str = shortstr; + strcpy(str, buffer); +} + +MyStr::MyStr(const Vec3d& p) +{ + char buffer[80]; + //if (fabs(d) < 1E-100) {d = 0;} + sprintf(buffer, "[%g, %g, %g]", p.X(), p.Y(), p.Z()); + length = strlen(buffer); + if (length > SHORTLEN) + str = new char[length + 1]; + else + str = shortstr; + strcpy(str, buffer); +} + +MyStr::MyStr(unsigned n, int) +{ + length = n; + if (length > SHORTLEN) + str = new char[length + 1]; + else + str = shortstr; + str[n] = 0; +} + +MyStr::MyStr(const std::string & st) +{ + length = st.length(); + if (length > SHORTLEN) + str = new char[length + 1]; + else + str = shortstr; + strcpy (str, st.c_str()); +} + + + +MyStr MyStr::Left(unsigned r) +{ + if(r > length) + { + MyStr::ErrHandler(); + MyStr s; + return s; + } + else + { + MyStr tmp(r, 0); + strncpy(tmp.str, str, r); + return tmp; + } +} + +MyStr MyStr::Right(unsigned l) +{ + if(l > length) + { + MyStr::ErrHandler(); + MyStr s; + return s; + } + else + { + MyStr tmp(l, 0); + strncpy(tmp.str, str + length - l, l); + return tmp; + } +} + +MyStr& MyStr::InsertAt(unsigned pos, const MyStr& s) +{ + if(pos > length) + { + MyStr::ErrHandler(); + return *this; + } + int newLength = length + s.length; + char *tmp = new char[newLength + 1]; + strncpy(tmp, str, pos); + strcpy(tmp + pos, s.str); + strcpy(tmp + pos + s.length, str + pos); + + if (length > SHORTLEN) delete str; + length = newLength; + if (length > SHORTLEN) + str = tmp; + else + { + strcpy (shortstr, tmp); + delete tmp; + str = shortstr; + } + return *this; +} + +MyStr &MyStr::WriteAt(unsigned pos, const MyStr& s) +{ + if(pos > length) + { + MyStr::ErrHandler(); + return *this; + } + int n = length - pos; + if(s.length < n) + n = s.length; + strncpy(str + pos, s.str, n); + return *this; +} + +void MyStr::ConvertTextToExcel() +{ + /* + for (int i = 0; i < Length(); i++) + { + if ((*this)[i]==',') {(*this)[i] = ';';} + else if ((*this)[i]=='.') {(*this)[i] = ',';} + } + */ +} + +void MyStr::ConvertExcelToText() +{ + /* + for (int i = 0; i < Length(); i++) + { + if ((*this)[i]==',') {(*this)[i] = '.';} + else if ((*this)[i]==';') {(*this)[i] = ',';} + } + */ +} + +MyStr& MyStr::operator = (const MyStr& s) +{ + if (length > SHORTLEN) delete str; + length = s.length; + if (length > SHORTLEN) + str = new char[length + 1]; + else + str = shortstr; + strcpy(str, s.str); + return *this; +} + +MyStr operator + (const MyStr& s1, const MyStr& s2) +{ + MyStr tmp(s1.length + s2.length, 0); + if (s1.length != 0) strcpy(tmp.str, s1.str); + if (s2.length != 0) strcpy(tmp.str + s1.length, s2.str); + return tmp; +} + +void MyStr::operator += (const MyStr& s) +{ + if (length+s.length <= SHORTLEN) + { + if (s.length != 0) strcpy(shortstr + length, s.str); + } + else + { + char *tmp = new char[length + s.length + 1]; + if (length != 0) strcpy(tmp, str); + if (s.length != 0) strcpy(tmp + length, s.str); + if (length > SHORTLEN) delete str; + length += s.length; + str = tmp; + } +} + +char& MyStr::operator [] (unsigned n) +{ + static char dummy; + if(n < length) + return str[n]; + else + { + MyStr::ErrHandler(); + return dummy; + } +} + +char MyStr::operator [] (unsigned n) const +{ + static char dummy; + if(n < length) + return str[n]; + else + { + MyStr::ErrHandler(); + return dummy; + } +} + +MyStr MyStr::operator () (unsigned l, unsigned r) +{ + if((l > r) || (r > length)) + { + MyStr::ErrHandler(); + MyStr s; + return s; + } + else + { + int n = r - l + 1; + MyStr tmp(n, 0); + strncpy(tmp.str, str + 1, n); + return tmp; + } +} + +istream& operator >> (istream& is, MyStr& s) +{ + const int buflen = 1000; + char buffer[buflen+1]; + + int end = 0; + s = ""; + MyStr str; + + while (!end) + { + is.get(buffer, buflen); + str = MyStr(buffer); + s += str; + if (is.peek() == EOF) {end = 1;} + } + + return is; +} + +/* +#ifdef __borland +::ifstream& operator >> (::ifstream& is, MyStr& s) // wb +{ // wb + const int buflen = 1000; // wb + char buffer[buflen+1]; // wb + // wb + int end = 0; // wb + s = ""; // wb + MyStr str; // wb + // wb + while (!end) // wb + { // wb + is.get(buffer, buflen); // wb + str = MyStr(buffer); // wb + s += str; // wb + if (is.peek() == EOF) {end = 1;} // wb + } // wb + // wb + return is; // wb +} + +#endif +*/ +} diff --git a/contrib/Netgen/libsrc/general/mystring.hpp b/contrib/Netgen/libsrc/general/mystring.hpp new file mode 100644 index 0000000000..cd6639552c --- /dev/null +++ b/contrib/Netgen/libsrc/general/mystring.hpp @@ -0,0 +1,209 @@ + +//************************************************************** +// +// filename: mystring.h +// +// project: doctoral thesis, program smart +// +// autor: Dipl.-Ing. Gerstmayr Johannes +// +// generated: 20.12.98 +// last change: 20.12.98 +// description: base class for strings +// remarks: string with n characters has +// 0..n-1 characters and at pos n a 0 +// +//************************************************************** + + +#ifndef MYSTRING__H +#define MYSTRING__H + +class Point3d; +class Vec3d; + +class MyStr; + +MyStr operator + (const MyStr &, const MyStr &); +int operator == (const MyStr &, const MyStr &); +int operator < (const MyStr &, const MyStr &); +int operator <= (const MyStr &, const MyStr &); +int operator > (const MyStr &, const MyStr &); +int operator >= (const MyStr &, const MyStr &); +int operator != (const MyStr &, const MyStr &); +ostream& operator << (ostream &, const MyStr &); +istream& operator >> (istream &, MyStr &); + +class MyStr +{ +public: + MyStr(); + MyStr(const char *); + MyStr(char); + MyStr(const MyStr &); + MyStr(int); + MyStr(long); + MyStr(double); + MyStr(const Point3d& p); + MyStr(const Vec3d& p); + MyStr(const std::string & st); + + ~MyStr(); + MyStr Left(unsigned); + MyStr Right(unsigned); + MyStr& InsertAt(unsigned, const MyStr &); + MyStr& WriteAt(unsigned, const MyStr &); + unsigned Length() const; + int Find(const char); + int Find(const char *); + int Find(const MyStr &); + MyStr& operator = (const MyStr &); + friend MyStr operator + (const MyStr &, const MyStr &); + void operator += (const MyStr &); + char* c_str(); + + //change every ',' -> ';', '.' -> ',' + void ConvertTextToExcel(); + //change every ','->'.', ';'->',' + void ConvertExcelToText(); + + MyStr operator () (unsigned, unsigned); + operator int(); + operator double(); + operator long(); + operator char *(); + char& operator [] (unsigned int); + char operator [] (unsigned int) const; + + friend int operator == (const MyStr &, const MyStr &); + friend int operator < (const MyStr &, const MyStr &); + friend int operator <= (const MyStr &, const MyStr &); + friend int operator > (const MyStr &, const MyStr &); + friend int operator >= (const MyStr &, const MyStr &); + friend int operator != (const MyStr &, const MyStr &); + friend ostream& operator << (ostream &, const MyStr &); + friend istream& operator >> (istream &, MyStr &); + static void SetToErrHandler(void (*)()); +private: + MyStr(unsigned, int); + char *str; + unsigned length; + enum { SHORTLEN = 24 }; + char shortstr[SHORTLEN+1]; + static void(*ErrHandler)(); +}; + + +inline MyStr::MyStr() +{ + length = 0; + str = shortstr; + str[0] = 0; +} + +inline MyStr::MyStr(char s) +{ + length = 1; + str = shortstr; + str[0] = s; + str[1] = (char)0; +} + +inline MyStr::~MyStr() +{ + if (length > SHORTLEN) + delete [] str; +} + +inline unsigned MyStr::Length() const +{ + return length; +} + +inline int MyStr::Find(const char c) +{ + char *pos = strchr(str, int(c)); + return pos ? int(pos - str) : -1; +} + +inline int MyStr::Find(const MyStr &s) +{ + char *pos = strstr(str, s.str); + return pos ? int(pos - str) : -1; +} + +inline int MyStr::Find(const char *s) +{ + char *pos = strstr(str, s); + return pos ? int(pos - str) : -1; +} + +inline MyStr::operator int() +{ + return atoi(str); +} + +inline MyStr::operator double() +{ + return atof(str); +} + +inline MyStr::operator long() +{ + return atol(str); +} + +inline MyStr::operator char *() +{ + return str; +} + +inline char* MyStr::c_str() +{ + return str; +} + + +inline int operator == (const MyStr &s1, const MyStr& s2) +{ + return strcmp(s1.str, s2.str) == 0; +} + +inline int operator < (const MyStr &s1, const MyStr& s2) +{ + return strcmp(s1.str, s2.str) < 0; +} + +inline int operator <= (const MyStr &s1, const MyStr& s2) +{ + return strcmp(s1.str, s2.str) <= 0; +} + +inline int operator > (const MyStr &s1, const MyStr& s2) +{ + return strcmp(s1.str, s2.str) > 0; +} + +inline int operator >= (const MyStr &s1, const MyStr& s2) +{ + return strcmp(s1.str, s2.str) >= 0; +} + +inline int operator != (const MyStr &s1, const MyStr& s2) +{ + return !(s1 == s2); +} + +inline ostream& operator << (ostream& os, const MyStr& s) +{ + return os << s.str; +} + +inline void MyStr::SetToErrHandler(void (*Handler)()) +{ + ErrHandler = Handler; +} + +#endif + + diff --git a/contrib/Netgen/libsrc/general/ngexception.cpp b/contrib/Netgen/libsrc/general/ngexception.cpp new file mode 100644 index 0000000000..6746dd2521 --- /dev/null +++ b/contrib/Netgen/libsrc/general/ngexception.cpp @@ -0,0 +1,33 @@ +/**************************************************************************/ +/* File: ngexception.cpp */ +/* Author: Joachim Schoeberl */ +/* Date: 16. Jan. 02 */ +/**************************************************************************/ + +#include <myadt.hpp> + +namespace netgen +{ + using namespace netgen; + + + + NgException :: NgException (const string & s) + : what(s) + { + ; + } + + + NgException :: ~NgException () + { + ; + } + + /// append string to description + void NgException :: Append (const string & s) + { + what += s; + } + +} diff --git a/contrib/Netgen/libsrc/general/ngexception.hpp b/contrib/Netgen/libsrc/general/ngexception.hpp new file mode 100644 index 0000000000..56c561aa8c --- /dev/null +++ b/contrib/Netgen/libsrc/general/ngexception.hpp @@ -0,0 +1,30 @@ +#ifndef FILE_NGEXCEPTION +#define FILE_NGEXCEPTION + +/**************************************************************************/ +/* File: ngexception.hpp */ +/* Author: Joachim Schoeberl */ +/* Date: 16. Jan. 2002 */ +/**************************************************************************/ + + +/// Base class for all ng exceptions +class NgException +{ + /// verbal description of exception + string what; +public: + /// + NgException (const string & s); + /// + virtual ~NgException (); + + /// append string to description + void Append (const string & s); + // void Append (const char * s); + + /// verbal description of exception + const string & What() const { return what; } +}; + +#endif diff --git a/contrib/Netgen/libsrc/general/optmem.cpp b/contrib/Netgen/libsrc/general/optmem.cpp new file mode 100644 index 0000000000..c8f961b12a --- /dev/null +++ b/contrib/Netgen/libsrc/general/optmem.cpp @@ -0,0 +1,63 @@ +/**************************************************************************/ +/* File: optmem.cc */ +/* Author: Joachim Schoeberl */ +/* Date: 04. Apr. 97 */ +/**************************************************************************/ + +/* + Abstract data type ARRAY +*/ + + +#include <mystdlib.h> +#include <myadt.hpp> + +namespace netgen +{ + using namespace netgen; + + BlockAllocator :: BlockAllocator (unsigned asize, unsigned ablocks) + : bablocks (0) + { + if (asize < sizeof(void*)) + asize = sizeof(void*); + size = asize; + blocks = ablocks; + freelist = NULL; + } + + BlockAllocator :: ~BlockAllocator () + { + for (unsigned i = 0; i < bablocks.Size(); i++) + delete [] bablocks[i]; + } + + void BlockAllocator :: Alloc2 () + { + // return new char[size]; + // if (!freelist) + { + // cout << "BlockAlloc: " << size*blocks << endl; + char * hcp = new char [size * blocks]; + bablocks.Append (hcp); + bablocks.Last() = hcp; + for (unsigned i = 0; i < blocks-1; i++) + *(void**)&(hcp[i * size]) = &(hcp[ (i+1) * size]); + *(void**)&(hcp[(blocks-1)*size]) = NULL; + freelist = hcp; + } + /* + void * p = freelist; + freelist = *(void**)freelist; + return p; + */ + } + + /* + void BlockAllocator :: Free (void * p) + { + *(void**)p = freelist; + freelist = p; + } + */ +} diff --git a/contrib/Netgen/libsrc/general/optmem.hpp b/contrib/Netgen/libsrc/general/optmem.hpp new file mode 100644 index 0000000000..d9e5e2137e --- /dev/null +++ b/contrib/Netgen/libsrc/general/optmem.hpp @@ -0,0 +1,52 @@ +#ifndef FILE_OPTMEM +#define FILE_OPTMEM + +/**************************************************************************/ +/* File: optmem.hh */ +/* Author: Joachim Schoeberl */ +/* Date: 04. Apr. 97 */ +/**************************************************************************/ + +/** + Optimized Memory allocation classes +*/ + +class BlockAllocator +{ +private: + /// + unsigned size, blocks; + /// + void * freelist; + /// + ARRAY<char*> bablocks; +public: + /// + BlockAllocator (unsigned asize, unsigned ablocks = 100); + /// + ~BlockAllocator (); + /// + void * Alloc () + { + if (!freelist) + Alloc2(); + + void * p = freelist; + freelist = *(void**)freelist; + return p; + } + /// + void Free (void * p) + { + *(void**)p = freelist; + freelist = p; + } + + +private: + void Alloc2 (); +}; + + + +#endif diff --git a/contrib/Netgen/libsrc/general/parthreads.cpp b/contrib/Netgen/libsrc/general/parthreads.cpp new file mode 100644 index 0000000000..81e9d0b6cc --- /dev/null +++ b/contrib/Netgen/libsrc/general/parthreads.cpp @@ -0,0 +1,40 @@ +/**************************************************************************/ +/* File: parthreads.cpp */ +/* Author: Joachim Schoeberl */ +/* Date: 01. Jun. 95 */ +/**************************************************************************/ + + +#include <mystdlib.h> +#include <myadt.hpp> + +/* + +namespace netgen +{ + using namespace netgen; + +#ifdef WIN32 + + NgLock :: NgLock (NgMutex & mut) + : sl(&mut.cs) + { + ; + } + + void NgLock :: Lock () + { + sl.Lock(); + } + void NgLock :: UnLock () + { + sl.Unlock(); + } + + +#else + +#endif +} + +*/ diff --git a/contrib/Netgen/libsrc/general/parthreads.hpp b/contrib/Netgen/libsrc/general/parthreads.hpp new file mode 100644 index 0000000000..99dd017633 --- /dev/null +++ b/contrib/Netgen/libsrc/general/parthreads.hpp @@ -0,0 +1,126 @@ +#ifndef FILE_PARTHREADS +#define FILE_PARTHREADS + +/**************************************************************************/ +/* File: parthreads.hh */ +/* Author: Joachim Schoeberl */ +/* Date: 22. Nov. 2000 */ +/**************************************************************************/ + +/* + Parallel thread, Mutex, +*/ + +#ifdef NO_PARALLEL_THREADS + +class NgMutex { }; + +class NgLock +{ +public: + NgLock (NgMutex & mut, bool lock = 0) { ; } + void Lock () { ; } + void UnLock () { ; } +}; + + +#else + +#ifdef WIN32 + +class NgMutex +{ + CCriticalSection cs; + +public: + NgMutex () + { ; } + friend class NgLock; +}; + +class NgLock +{ + CSingleLock sl; + bool locked; +public: + NgLock (NgMutex & mut, bool lock = 0) + : sl(&mut.cs) + { + if (lock) sl.Lock(); + locked = lock; + } + + ~NgLock () + { + if (locked) sl.Unlock(); + } + + void Lock () + { + sl.Lock(); + locked = 1; + } + + void UnLock () + { + sl.Unlock(); + locked = 0; + } +}; + +#else + + +#include <pthread.h> + +class NgMutex +{ + pthread_mutex_t mut; +public: + NgMutex () + { + pthread_mutex_init (&mut, NULL); + } + friend class NgLock; +}; + +class NgLock +{ + pthread_mutex_t & mut; + bool locked; +public: + NgLock (NgMutex & ngmut, bool lock = 0) + : mut (ngmut.mut) + { + if (lock) pthread_mutex_lock (&mut); + locked = lock; + }; + + ~NgLock() + { + if (locked) pthread_mutex_unlock (&mut); + } + + void Lock () + { + pthread_mutex_lock (&mut); + locked = 1; + } + void UnLock () + { + pthread_mutex_unlock (&mut); + locked = 0; + } + /* + int TryLock () + { + return pthread_mutex_trylock (&mut); + } + */ +}; + +#endif + +#endif + +#endif diff --git a/contrib/Netgen/libsrc/general/seti.cpp b/contrib/Netgen/libsrc/general/seti.cpp new file mode 100644 index 0000000000..702337f076 --- /dev/null +++ b/contrib/Netgen/libsrc/general/seti.cpp @@ -0,0 +1,70 @@ +#include <mystdlib.h> +#include <myadt.hpp> + + +namespace netgen +{ + using namespace netgen; + + IndexSet :: IndexSet (int maxind) + { + SetMaxIndex (maxind); + } + + IndexSet :: ~IndexSet () + { + Clear(); + } + + + void IndexSet :: SetMaxIndex (int maxind) + { + if (maxind > flags.Size()) + { + flags.SetSize (2 * maxind); + flags.Clear(); + } + } + + /* + int IndexSet :: IsIn (int ind) const + { + return flags.Test (ind); + } + */ + + /* + void IndexSet :: Add (int ind) + { + if (ind > flags.Size()) + { + cerr << "out of range" << endl; + exit (1); + } + + if (!flags.Test(ind)) + { + set.Append (ind); + flags.Set (ind); + } + } + */ + + void IndexSet :: Del (int ind) + { + for (int i = 1; i <= set.Size(); i++) + if (set.Get(i) == ind) + { + set.DeleteElement (ind); + break; + } + flags.Clear (ind); + } + + void IndexSet :: Clear () + { + for (int i = 1; i <= set.Size(); i++) + flags.Clear (set.Get(i)); + set.SetSize (0); + } +} diff --git a/contrib/Netgen/libsrc/general/seti.hpp b/contrib/Netgen/libsrc/general/seti.hpp new file mode 100644 index 0000000000..4ca0b8eb4e --- /dev/null +++ b/contrib/Netgen/libsrc/general/seti.hpp @@ -0,0 +1,45 @@ +#ifndef FILE_SETI +#define FILE_SETI + + +/**************************************************************************/ +/* File: seti.hh */ +/* Author: Joachim Schoeberl */ +/* Date: 20. Mar. 98 */ +/**************************************************************************/ + +/** + Set of Integers + */ +class IndexSet +{ + ARRAY<int> set; + BitArray flags; +public: + IndexSet (int maxind); + + ~IndexSet (); + /// increase range to maxind + void SetMaxIndex (int maxind); + int IsIn (int ind) const + { + return flags.Test (ind); + } + + void Add (int ind) + { + if (!flags.Test(ind)) + { + set.Append (ind); + flags.Set (ind); + } + } + + void Del (int ind); + void Clear (); + + const ARRAY<int> & Array() { return set; } +}; + +#endif + diff --git a/contrib/Netgen/libsrc/general/sort.cpp b/contrib/Netgen/libsrc/general/sort.cpp new file mode 100644 index 0000000000..264a132a74 --- /dev/null +++ b/contrib/Netgen/libsrc/general/sort.cpp @@ -0,0 +1,75 @@ +/**************************************************************************/ +/* File: sort.cc */ +/* Author: Joachim Schoeberl */ +/* Date: 07. Jan. 00 */ +/**************************************************************************/ + +/* + Sorting +*/ + + +#include <algorithm> +#include <mystdlib.h> +#include <myadt.hpp> + +namespace netgen +{ + +void Sort (const ARRAY<double> & values, + ARRAY<int> & order) +{ + int n = values.Size(); + int i, j; + + order.SetSize (n); + + for (i = 1; i <= n; i++) + order.Elem(i) = i; + for (i = 1; i <= n-1; i++) + for (j = 1; j <= n-1; j++) + if (values.Get(order.Elem(j)) > values.Get(order.Elem(j+1))) + { + Swap (order.Elem(j), order.Elem(j+1)); + } +} + + +void QickSortRec (const ARRAY<double> & values, + ARRAY<int> & order, + int left, int right) +{ + int i, j; + double midval; + + i = left; + j = right; + midval = values.Get(order.Get((i+j)/2)); + + do + { + while (values.Get(order.Get(i)) < midval) i++; + while (midval < values.Get(order.Get(j))) j--; + + if (i <= j) + { + Swap (order.Elem(i), order.Elem(j)); + i++; j--; + } + } + while (i <= j); + if (left < j) QickSortRec (values, order, left, j); + if (i < right) QickSortRec (values, order, i, right); +} + +void QickSort (const ARRAY<double> & values, + ARRAY<int> & order) +{ + int i, n = values.Size(); + order.SetSize (n); + for (i = 1; i <= n; i++) + order.Elem(i) = i; + + QickSortRec (values, order, 1, order.Size()); +} +} diff --git a/contrib/Netgen/libsrc/general/sort.hpp b/contrib/Netgen/libsrc/general/sort.hpp new file mode 100644 index 0000000000..99c3291000 --- /dev/null +++ b/contrib/Netgen/libsrc/general/sort.hpp @@ -0,0 +1,19 @@ +#ifndef FILE_SORT +#define FILE_SORT + +/**************************************************************************/ +/* File: sort.hh */ +/* Author: Joachim Schoeberl */ +/* Date: 07. Jan. 00 */ +/**************************************************************************/ + + +// order(i) is sorted index of element i +extern void Sort (const ARRAY<double> & values, + ARRAY<int> & order); + +extern void QickSort (const ARRAY<double> & values, + ARRAY<int> & order); + + +#endif diff --git a/contrib/Netgen/libsrc/general/spbita2d.cpp b/contrib/Netgen/libsrc/general/spbita2d.cpp new file mode 100644 index 0000000000..e1e80e2cad --- /dev/null +++ b/contrib/Netgen/libsrc/general/spbita2d.cpp @@ -0,0 +1,172 @@ +/**************************************************************************/ +/* File: spbita2d.cpp */ +/* Author: Joachim Schoeberl */ +/* Date: 01. Jun. 95 */ +/**************************************************************************/ + +/* + Implementation of sparse 2 dimensional bitarray +*/ + + +#include <mystdlib.h> +#include <myadt.hpp> + +namespace netgen +{ + using namespace netgen; + + SPARSE_BIT_ARRAY_2D :: SPARSE_BIT_ARRAY_2D (int ah, int aw) + { + lines = NULL; + SetSize (ah, aw); + } + + SPARSE_BIT_ARRAY_2D :: ~SPARSE_BIT_ARRAY_2D () + { + DeleteElements (); + delete lines; + } + + + void SPARSE_BIT_ARRAY_2D :: SetSize (int ah, int aw) + { + DeleteElements(); + if (lines) + { + delete lines; + lines = NULL; + } + + if (!aw) aw = ah; + + height = ah; + width = aw; + + if (!ah) return; + lines = new linestruct[ah]; + + if (lines) + { + for (int i = 0; i < ah; i++) + { + lines[i].size = 0; + lines[i].maxsize = 0; + lines[i].col = NULL; + } + } + else + { + height = width = 0; + MyError ("SPARSE_ARRAY::SetSize: Out of memory"); + } + } + + + + void SPARSE_BIT_ARRAY_2D :: DeleteElements () + { + if (lines) + { + for (int i = 0; i < height; i++) + { + if (lines[i].col) + { + delete [] lines[i].col; + lines[i].col = NULL; + lines[i].size = 0; + lines[i].maxsize = 0; + } + } + } + } + + + int SPARSE_BIT_ARRAY_2D :: Test (int i, int j) const + { + int k, max, *col; + + if (!lines) return 0; + if (i < 1 || i > height) return 0; + + col = lines[i-1].col; + max = lines[i-1].size; + + for (k = 0; k < max; k++, col++) + if (*col == j) return 1; + + return 0; + } + + + + void SPARSE_BIT_ARRAY_2D :: Set(int i, int j) + { + int k, max, *col; + + i--; + col = lines[i].col; + max = lines[i].size; + + for (k = 0; k < max; k++, col++) + if (*col == j) + return; + + if (lines[i].size) + { + if (lines[i].size == lines[i].maxsize) + { + col = new int[lines[i].maxsize+2]; + if (col) + { + lines[i].maxsize += 2; + memcpy (col, lines[i].col, sizeof (int) * lines[i].size); + delete [] lines[i].col; + lines[i].col = col; + } + else + { + MyError ("SPARSE_BIT_ARRAY::Set: Out of mem 1"); + return; + } + } + else + col = lines[i].col; + + if (col) + { + k = lines[i].size-1; + while (k >= 0 && col[k] > j) + { + col[k+1] = col[k]; + k--; + } + + k++; + lines[i].size++; + col[k] = j; + return; + } + else + { + MyError ("SPARSE_ARRAY::Set: Out of memory 2"); + } + } + else + { + lines[i].col = new int[4]; + if (lines[i].col) + { + lines[i].maxsize = 4; + lines[i].size = 1; + lines[i].col[0] = j; + return; + } + else + { + MyError ("SparseMatrix::Elem: Out of memory 3"); + } + } + } + +} diff --git a/contrib/Netgen/libsrc/general/spbita2d.hpp b/contrib/Netgen/libsrc/general/spbita2d.hpp new file mode 100644 index 0000000000..db656653b1 --- /dev/null +++ b/contrib/Netgen/libsrc/general/spbita2d.hpp @@ -0,0 +1,56 @@ +#ifndef FILE_SPBITA2D +#define FILE_SPBITA2D + +/**************************************************************************/ +/* File: spbita2d.hh */ +/* Author: Joachim Schoeberl */ +/* Date: 01. Jun. 95 */ +/**************************************************************************/ + +/** + Implementation of sparse 2 dimensional bitarray +*/ + + +class SPARSE_BIT_ARRAY_2D + { + class linestruct { public: INDEX size; INDEX maxsize; INDEX * col; }; + + /// + linestruct * lines; + /// + INDEX height, width; + + public: + + /// + SPARSE_BIT_ARRAY_2D (INDEX ah = 0, INDEX aw = 0); + /// + ~SPARSE_BIT_ARRAY_2D (); + + /// + void SetSize (INDEX ah, INDEX aw = 0); + /// + void DeleteElements (); + + /// + int Get (INDEX i, INDEX j) const; + + /// + INDEX Height () const { return height; } + /// + INDEX Width () const { return width; } + + /// + void Set (INDEX i, INDEX j); + /// + int Test (INDEX i, INDEX j) const; + + /// + INDEX BitsInLine (INDEX i) const { return lines[i-1].size; } + /// + INDEX GetIndex (INDEX i, INDEX nr) const { return lines[i-1].col[nr-1]; } + }; + + +#endif diff --git a/contrib/Netgen/libsrc/general/stack.hpp b/contrib/Netgen/libsrc/general/stack.hpp new file mode 100644 index 0000000000..db8dfad266 --- /dev/null +++ b/contrib/Netgen/libsrc/general/stack.hpp @@ -0,0 +1,112 @@ +#ifndef FILE_STACK +#define FILE_STACK + +/*****************************************************************************/ +/* File: stack.hh */ +/* Author: Wolfram Muehlhuber */ +/* Date: September 98 */ +/*****************************************************************************/ + +/* + + Stack class, based on a resizable array + + */ + + +#include "array.hpp" + + +/// +template <class T> class STACK +{ +public: + /// + inline STACK (INDEX asize = 0, INDEX ainc = 0); + /// + inline ~STACK (); + + /// + inline void Push (const T & el); + /// + inline T & Pop (); + /// + const inline T & Top () const; + /// + inline int IsEmpty () const; + /// + inline void MakeEmpty (); + +private: + /// + ARRAY<T> elems; + /// + INDEX size; +}; + + + + +/* + + Stack class, based on a resizable array + + */ + +template <class T> +inline STACK<T> :: STACK (INDEX asize, INDEX ainc) + : elems(asize, ainc) +{ + size = 0; +} + + +template <class T> +inline STACK<T> :: ~STACK () +{ + ; +} + + +template <class T> +inline void STACK<T> :: Push (const T & el) +{ + if (size < elems.Size()) + elems.Elem(++size) = el; + else + { + elems.Append(el); + size++; + } +} + + +template <class T> +inline T & STACK<T> :: Pop () +{ + return elems.Elem(size--); +} + + +template <class T> +const inline T & STACK<T> :: Top () const +{ + return elems.Get(size); +} + +template <class T> +inline int STACK<T> :: IsEmpty () const +{ + return (size == 0); +} + + +template <class T> +inline void STACK<T> :: MakeEmpty () +{ + size = 0; +} + + + +#endif diff --git a/contrib/Netgen/libsrc/general/stack.icc b/contrib/Netgen/libsrc/general/stack.icc new file mode 100644 index 0000000000..c0182a564b --- /dev/null +++ b/contrib/Netgen/libsrc/general/stack.icc @@ -0,0 +1,67 @@ +/*****************************************************************************/ +/* File: stack.hh */ +/* Author: Wolfram Muehlhuber */ +/* Date: September 98 */ +/*****************************************************************************/ + +/* + + Stack class, based on a resizable array + + */ + +template <class T> +inline STACK<T> :: STACK (INDEX asize, INDEX ainc) + : elems(asize, ainc) +{ + size = 0; +} + + +template <class T> +inline STACK<T> :: ~STACK () +{ + ; +} + + +template <class T> +inline void STACK<T> :: Push (const T & el) +{ + if (size < elems.Size()) + elems.Elem(++size) = el; + else + { + elems.Append(el); + size++; + } +} + + +template <class T> +inline T & STACK<T> :: Pop () +{ + return elems.Elem(size--); +} + + +template <class T> +const inline T & STACK<T> :: Top () const +{ + return elems.Get(size); +} + +template <class T> +inline int STACK<T> :: IsEmpty () const +{ + return (size == 0); +} + + +template <class T> +inline void STACK<T> :: MakeEmpty () +{ + size = 0; +} + + diff --git a/contrib/Netgen/libsrc/general/symbolta.cpp b/contrib/Netgen/libsrc/general/symbolta.cpp new file mode 100644 index 0000000000..b02daa65dc --- /dev/null +++ b/contrib/Netgen/libsrc/general/symbolta.cpp @@ -0,0 +1,52 @@ +/**************************************************************************/ +/* File: symbolta.cc */ +/* Author: Joachim Schoeberl */ +/* Date: 01. Jun. 95 */ +/**************************************************************************/ + +/* + Abstract data type Symbol Table +*/ + +#include <mystdlib.h> +#include <myadt.hpp> + + +#ifndef FILE_SYMBOLTABLECC +#define FILE_SYMBOLTABLECC +// necessary for SGI ???? + + +namespace netgen +{ + using namespace netgen; + + BASE_SYMBOLTABLE :: BASE_SYMBOLTABLE () + { + ; + } + + + BASE_SYMBOLTABLE :: ~BASE_SYMBOLTABLE() + { + DelNames(); + } + + + void BASE_SYMBOLTABLE :: DelNames() + { + for (int i = 0; i < names.Size(); i++) + delete [] names[i]; + names.SetSize (0); + } + + int BASE_SYMBOLTABLE :: Index (const char * name) const + { + if (!name) return 0; + for (int i = 0; i < names.Size(); i++) + if (strcmp (names[i], name) == 0) return i+1; + return 0; + } +} + +#endif diff --git a/contrib/Netgen/libsrc/general/symbolta.hpp b/contrib/Netgen/libsrc/general/symbolta.hpp new file mode 100644 index 0000000000..6b8916e8ea --- /dev/null +++ b/contrib/Netgen/libsrc/general/symbolta.hpp @@ -0,0 +1,158 @@ +#ifndef FILE_SYMBOLTA +#define FILE_SYMBOLTA + + +/**************************************************************************/ +/* File: symbolta.hh */ +/* Author: Joachim Schoeberl */ +/* Date: 01. Jun. 95 */ +/**************************************************************************/ + +/** + Base class for the generic SYMBOLTABLE. + An array of identifiers is maintained. +*/ +class BASE_SYMBOLTABLE +{ +protected: + /// identifiers + ARRAY <char*> names; + +public: + /// Constructor + BASE_SYMBOLTABLE (); + /// + ~BASE_SYMBOLTABLE (); + /// + void DelNames (); + /// Index of symbol name, returns 0 if not used. + int Index (const char * name) const; +}; + + +/** + Abstract data type Symbol Table. + + To a string an value of the generic type T is associated. + The string is not copied into the symbol table class! +*/ +template <class T> +class SYMBOLTABLE : public BASE_SYMBOLTABLE +{ +private: + /// Associated data + ARRAY <T> data; + +public: + /// Creates a symboltable + inline SYMBOLTABLE (); + /// Returns size of symboltable + inline INDEX Size() const; + /// Returns reference to element, error if not used + inline T & Elem (const char * name); + /// Returns reference to i-th element + inline T & Elem (int i) + { return data.Elem(i); } + /// Returns element, error if not used + inline const T & Get (const char * name) const; + /// Returns i-th element + inline const T & Get (int i) const; + /// Returns name of i-th element + inline const char* GetName (int i) const; + /// Associates el to the string name, overrides if name is used + inline void Set (const char * name, const T & el); + /// Checks whether name is used + inline int Used (const char * name) const; + /// Deletes symboltable + inline void DeleteAll (); + + inline T & operator[] (int i) + { return data[i]; } + inline const T & operator[] (int i) const + { return data[i]; } + +private: + /// Prevents from copying symboltable by pointer assignment + SYMBOLTABLE<T> & operator= (SYMBOLTABLE<T> &); +}; + + + + +template <class T> +inline SYMBOLTABLE<T> :: SYMBOLTABLE () +{ + ; +} + + +template <class T> +inline INDEX SYMBOLTABLE<T> :: Size() const +{ + return data.Size(); +} + +template <class T> +inline T & SYMBOLTABLE<T> :: Elem (const char * name) +{ + int i = Index (name); + if (i) + return data.Elem (i); + else + return data.Elem(1); +} + +template <class T> +inline const T & SYMBOLTABLE<T> :: Get (const char * name) const +{ + int i; + i = Index (name); + if (i) + return data.Get(i); + else + return data.Get(1); +} + +template <class T> +inline const T & SYMBOLTABLE<T> :: Get (int i) const +{ + return data.Get(i); +} + +template <class T> +inline const char* SYMBOLTABLE<T> :: GetName (int i) const +{ + return names.Get(i); +} + +template <class T> +inline void SYMBOLTABLE<T> :: Set (const char * name, const T & el) +{ + int i; + i = Index (name); + if (i) + data.Set(i, el); + else + { + data.Append (el); + char * hname = new char [strlen (name) + 1]; + strcpy (hname, name); + names.Append (hname); + } +} + +template <class T> +inline int SYMBOLTABLE<T> :: Used (const char * name) const +{ + return (Index(name)) ? 1 : 0; +} + +template <class T> +inline void SYMBOLTABLE<T> :: DeleteAll () +{ + DelNames(); + data.DeleteAll(); +} + + +#endif diff --git a/contrib/Netgen/libsrc/general/table.cpp b/contrib/Netgen/libsrc/general/table.cpp new file mode 100644 index 0000000000..ed84789bf9 --- /dev/null +++ b/contrib/Netgen/libsrc/general/table.cpp @@ -0,0 +1,167 @@ +/**************************************************************************/ +/* File: table.cpp */ +/* Author: Joachim Schoeberl */ +/* Date: 01. Jun. 95 */ +/**************************************************************************/ + +/* + Abstract data type TABLE +*/ + +#include <mystdlib.h> +#include <myadt.hpp> + +namespace netgen +{ + using namespace netgen; + + BASE_TABLE :: BASE_TABLE (int size) + : data(size) + { + for (int i = 0; i < size; i++) + { + data[i].maxsize = 0; + data[i].size = 0; + data[i].col = NULL; + } + oneblock = NULL; + } + + BASE_TABLE :: BASE_TABLE (const FlatArray<int> & entrysizes, int elemsize) + : data(entrysizes.Size()) + { + int i, cnt = 0; + int n = entrysizes.Size(); + + for (i = 0; i < n; i++) + cnt += entrysizes[i]; + oneblock = new char[elemsize * cnt]; + // mem_total_alloc_table += elemsize * cnt; + + cnt = 0; + for (i = 0; i < n; i++) + { + data[i].maxsize = entrysizes[i]; + data[i].size = 0; + + data[i].col = &oneblock[elemsize * cnt]; + cnt += entrysizes[i]; + } + } + + BASE_TABLE :: ~BASE_TABLE () + { + if (oneblock) + delete [] oneblock; + else + { + for (int i = 0; i < data.Size(); i++) + delete [] (char*)data[i].col; + } + } + + void BASE_TABLE :: SetSize (int size) + { + for (int i = 0; i < data.Size(); i++) + delete [] (char*)data[i].col; + + data.SetSize(size); + for (int i = 0; i < size; i++) + { + data[i].maxsize = 0; + data[i].size = 0; + data[i].col = NULL; + } + } + + void BASE_TABLE :: IncSize2 (int i, int elsize) + { +#ifdef DEBUG + if (i < 0 || i >= data.Size()) + { + MyError ("BASE_TABLE::Inc: Out of range"); + return; + } +#endif + + linestruct & line = data[i]; + if (line.size == line.maxsize) + { + void * p = new char [(line.maxsize+5) * elsize]; + + memcpy (p, line.col, line.maxsize * elsize); + delete [] (char*)line.col; + + line.col = p; + line.maxsize += 5; + } + + line.size++; + } + + + + /* + void BASE_TABLE :: DecSize (int i) + { +#ifdef DEBUG + if (i < 0 || i >= data.Size()) + { + MyError ("BASE_TABLE::Dec: Out of range"); + return; + } +#endif + + linestruct & line = data[i]; + +#ifdef DEBUG + if (line.size == 0) + { + MyError ("BASE_TABLE::Dec: EntrySize < 0"); + return; + } +#endif + + line.size--; + } + */ + + + + void BASE_TABLE :: AllocateElementsOneBlock (int elemsize) + { + int cnt = 0; + int n = data.Size(); + + for (int i = 0; i < n; i++) + cnt += data[i].maxsize; + oneblock = new char[elemsize * cnt]; + + cnt = 0; + for (int i = 0; i < n; i++) + { + data[i].size = 0; + data[i].col = &oneblock[elemsize * cnt]; + cnt += data[i].maxsize; + } + } + + + + int BASE_TABLE :: AllocatedElements () const + { + int els = 0; + for (int i = 0; i < data.Size(); i++) + els += data[i].maxsize; + return els; + } + + int BASE_TABLE :: UsedElements () const + { + int els = 0; + for (int i = 0; i < data.Size(); i++) + els += data[i].size; + return els; + } + +} diff --git a/contrib/Netgen/libsrc/general/table.hpp b/contrib/Netgen/libsrc/general/table.hpp new file mode 100644 index 0000000000..b986049b00 --- /dev/null +++ b/contrib/Netgen/libsrc/general/table.hpp @@ -0,0 +1,212 @@ +#ifndef FILE_TABLE +#define FILE_TABLE + +/**************************************************************************/ +/* File: table.hpp */ +/* Author: Joachim Schoeberl */ +/* Date: 01. Jun. 95 */ +/**************************************************************************/ + +/// Base class to generic class TABLE. +class BASE_TABLE +{ +protected: + + /// + class linestruct + { + public: + /// + int size; + /// + int maxsize; + /// + void * col; + }; + + /// + ARRAY<linestruct> data; + char * oneblock; + +public: + /// + BASE_TABLE (int size); + /// + BASE_TABLE (const FlatArray<int> & entrysizes, int elemsize); + /// + ~BASE_TABLE (); + /// + void SetSize (int size); + + /// 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 IncSize2 (int i, int elsize); + + // void DecSize (int i); + + /// + void AllocateElementsOneBlock (int elemsize); + + int AllocatedElements () const; + int UsedElements () const; +}; + + + + + + + +/** + Abstract data type TABLE. + + To an integer i in the range from 1 to size a set of elements of the + generic type T is associated. +*/ +template <class T, int BASE = 0> +class TABLE : public BASE_TABLE +{ +public: + /// Creates table. + inline TABLE () : BASE_TABLE(0) { ; } + + /// Creates table of size size + inline TABLE (int size) : BASE_TABLE (size) { ; } + + /// Creates fixed element size table + inline TABLE (const FlatArray<int,BASE> & entrysizes) + : BASE_TABLE (FlatArray<int> (entrysizes.Size(), const_cast<int*>(&entrysizes[BASE])), + sizeof(T)) + { ; } + + /// Changes Size of table to size, deletes data + inline void SetSize (int size) + { + BASE_TABLE::SetSize (size); + } + + + /// Inserts element acont into row i, 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 mem + inline void AddSave (int i, const T & acont) + { + ((T*)data[i-BASE].col)[data[i-BASE].size] = acont; + data[i-BASE].size++; + } + + /// Inserts element acont into row i. 1-based. Does not test if already used, assumes to have mem + inline void AddSave1 (int i, const T & acont) + { + ((T*)data.Elem(i).col)[data.Elem(i).size] = acont; + data.Elem(i).size++; + } + + /// Inserts element acont into row i. Does not test if already used. + inline void AddEmpty (int i) + { + IncSize (i-BASE, sizeof (T)); + } + + /** Set the nr-th element in the i-th row to acont. + Does not check for overflow. */ + inline void Set (int i, int nr, const T & acont) + { ((T*)data.Get(i).col)[nr-1] = acont; } + /** Returns the nr-th element in the i-th row. + Does not check for overflow. */ + inline const T & Get (int i, int nr) const + { return ((T*)data.Get(i).col)[nr-1]; } + + + /** Returns pointer to the first element in row i. */ + inline const T * GetLine (int i) const + { + return ((const T*)data.Get(i).col); + } + + + /// Returns size of the table. + inline int Size () const + { + return data.Size(); + } + + /// Returns size of the i-th row. + inline int EntrySize (int i) const + { return data.Get(i).size; } + + /* + inline void DecEntrySize (int i) + { DecSize(i); } + */ + void AllocateElementsOneBlock () + { BASE_TABLE::AllocateElementsOneBlock (sizeof(T)); } + + + inline void PrintMemInfo (ostream & ost) const + { + int els = AllocatedElements(); + ost << "table: allocaed " << els + << " a " << sizeof(T) << " Byts = " + << els * sizeof(T) + << " bytes in " << Size() << " bags." + << " used: " << UsedElements() + << endl; + } + + /// Access entry. + FlatArray<T> operator[] (int i) const + { +#ifdef DEBUG + if (i-BASE < 0 || i-BASE >= data.Size()) + cout << "table out of range, i = " << i << ", s = " << data.Size() << endl; +#endif + + return FlatArray<T> (data[i-BASE].size, (T*)data[i-BASE].col); + } +}; + + +template <class T, int BASE> +inline ostream & operator<< (ostream & ost, TABLE<T,BASE> & table) +{ + for (int i = BASE; i < table.Size()+BASE; i++) + { + ost << i << ": "; + FlatArray<T> row = table[i]; + for (int j = 0; j < row.Size(); j++) + ost << row[j] << " "; + ost << endl; + } + return ost; +} + +#endif + diff --git a/contrib/Netgen/libsrc/general/template.hpp b/contrib/Netgen/libsrc/general/template.hpp new file mode 100644 index 0000000000..4bf983c06b --- /dev/null +++ b/contrib/Netgen/libsrc/general/template.hpp @@ -0,0 +1,448 @@ +#ifndef FILE_TEMPLATE +#define FILE_TEMPLATE + +/**************************************************************************/ +/* File: template.hh */ +/* Author: Joachim Schoeberl */ +/* Date: 01. Jun. 95 */ +/**************************************************************************/ + +/* + templates, global types, defines and variables +*/ + +/// The following value may be adapted to the hardware ! +#ifndef CLOCKS_PER_SEC +#define CLOCKS_PER_SEC 1000000 +#endif + + +// #include <iostream> +/** output stream for testing. + testout is opened by main */ +extern ostream * testout; + +/** use instead of cout */ +extern ostream * mycout; + +/** error output stream */ +extern ostream * myerr; + +/** Error messages display. + Error messages are displayed by this function */ +extern void MyError (const char * ch); + + +/** Rings the bell. + Produces nr beeps. */ +extern void MyBeep (int nr = 1); + + +template <class T> +inline void Swap (T & a, T & b) +{ + T temp = a; + a = b; + b = temp; +} + +/* +template <class T> +inline void swap (T & a, T & b) +{ + T temp = a; + a = b; + b = temp; +} +*/ + + + +/** + INDEX is a typedef for (at least) 4-byte integer + */ +typedef int INDEX; + +/** + BOOL is a typedef for boolean variables + */ +// typedef int BOOL; + +typedef int ELIND; +typedef int PIND; + + +class twoint +{ +public: /// + int i1, i2; /// + twoint() {}; + /// + twoint(int ii1, int ii2) {i1 = ii1; i2 = ii2;} + friend int operator== (const twoint& t1, const twoint& t2); + /// + void Swap() {int x = i1; i1 = i2; i2 = x;} + void Sort() {if (i1 > i2) {Swap();}} +}; + +inline int operator== (const twoint& t1, const twoint& t2) +{ + return t1.i1 == t2.i1 && t1.i2 == t2.i2; +} + +class threeint +{ +public: /// + int i1, i2, i3; /// + threeint() {}; + /// + threeint(int ii1, int ii2, int ii3) {i1 = ii1; i2 = ii2; i3 = ii3;} +}; + +/// +class twodouble +{ +public: + /// + double d1, d2; + /// + twodouble() {d1 = 0; d2 = 0;}; + /// + twodouble(double id1, double id2) {d1 = id1; d2 = id2;} + /// + void Swap() {double x = d1; d1 = d2; d2 = x;} +}; + +class fourint { public: int i1, i2, i3, i4; fourint() {}; }; + + +/// +class INDEX_2; +ostream & operator<<(ostream & s, const INDEX_2 & i2); + + +class INDEX_2 +{ + /// + INDEX i[2]; + +public: + /// + INDEX_2 () { } + /// + INDEX_2 (INDEX ai1, INDEX ai2) + { i[0] = ai1; i[1] = ai2; } + + /// + INDEX_2 (const INDEX_2 & in2) + { i[0] = in2.i[0]; i[1] = in2.i[1]; } + + /// + int operator== (const INDEX_2 & in2) const + { return i[0] == in2.i[0] && i[1] == in2.i[1]; } + + /// + + + INDEX_2 Sort () + { + if (i[0] > i[1]) + { + INDEX hi = i[0]; + i[0] = i[1]; + i[1] = hi; + } + return *this; + } + + static INDEX_2 Sort (int i1, int i2) + { + if (i1 > i2) + return INDEX_2 (i2,i1); + else + return INDEX_2 (i1,i2); + } + + + /// + INDEX & I1 () { return i[0]; } + /// + INDEX & I2 () { return i[1]; } + /// + INDEX & I (int j) { return i[j-1]; } + /// + const INDEX & I1 () const { return i[0]; } + /// + const INDEX & I2 () const { return i[1]; } + /// + const INDEX & I (int j) const { return i[j-1]; } + /// + int & operator[] (int j) { return i[j]; } + /// + const int & operator[] (int j) const { return i[j]; } + /// + friend ostream & operator<<(ostream & s, const INDEX_2 & i2); +}; + + +/// +class INDEX_3 +{ + /// + INDEX i[3]; + +public: + /// + INDEX_3 () { } + /// + INDEX_3 (INDEX ai1, INDEX ai2, INDEX ai3) + { i[0] = ai1; i[1] = ai2; i[2] = ai3; } + + /// + INDEX_3 (const INDEX_3 & in2) + { i[0] = in2.i[0]; i[1] = in2.i[1]; i[2] = in2.i[2]; } + + + static INDEX_3 Sort (INDEX_3 i3) + { + return i3.Sort(); + } + + static INDEX_3 Sort (int i1, int i2, int i3) + { + INDEX_3 i(i1, i2, i3); + return i.Sort(); + } + + /// + 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); +}; + + + + + + + + + + + + +/// +template <class T> +inline T min2 (T a, T b) +{ + /// + return (a < b) ? a : b; +} +/// +template <class T> +inline T max2 (T a, T b) +{ + /// + return (a > b) ? a : b; +} +/// +template <class T> +inline T min3 (T a, T b, T c) +{ + /// + return (a < b) ? (a < c) ? a : c + : (b < c) ? b : c; +} +/// +template <class T> +inline T max3 (T a, T b, T c) +{ + /// + return (a > b) ? ((a > c) ? a : c) + : ((b > c) ? b : c); +} + +/// + +/// +template <class T> +inline int sgn (T a) +{ + return (a > 0) ? 1 : ( ( a < 0) ? -1 : 0 ); +} + +/// +template <class T> +inline T sqr (const T a) +{ + return a * a; +} + +/// +template <class T> +inline T pow3 (const T a) +{ + return a * a * a; +} + + + +/* +template <class T> +void BubbleSort (int size, T * data); + +template <class T> +void MergeSort (int size, T * data, T * help); +*/ + + + + + +#endif diff --git a/contrib/Netgen/libsrc/geom2d/Makefile b/contrib/Netgen/libsrc/geom2d/Makefile new file mode 100644 index 0000000000..8371fa19e7 --- /dev/null +++ b/contrib/Netgen/libsrc/geom2d/Makefile @@ -0,0 +1,12 @@ +# +# Makefile for geometric library +# +src = spline2d.cpp geom2dmesh.cpp splinegeometry2.cpp genmesh2d.cpp +# +lib = geom2d +libpath = libsrc/geom2d +# +# +include ../makefile.inc +# + diff --git a/contrib/Netgen/libsrc/geom2d/genmesh2d.cpp b/contrib/Netgen/libsrc/geom2d/genmesh2d.cpp new file mode 100644 index 0000000000..34f93b66ee --- /dev/null +++ b/contrib/Netgen/libsrc/geom2d/genmesh2d.cpp @@ -0,0 +1,145 @@ +#include <mystdlib.h> +#include <csg.hpp> +#include <geometry2d.hpp> +#include "meshing.hpp" + +namespace netgen +{ + + // static ARRAY<Point<2> > points2; + // static ARRAY<int> lp1, lp2; + + + extern void Optimize2d (Mesh & mesh, MeshingParameters & mp); + + + + + void MeshFromSpline2D (SplineGeometry2d & geometry, + Mesh *& mesh, + MeshingParameters & mp) + { + int i, j, domnr; + double elto0, minx, miny, maxx, maxy; + + // mp.Print(*testout); + + PointIndex pi; + SegmentIndex si; + SurfaceElementIndex sei; + + double h = mp.maxh; + + Box<2> bbox; + geometry.GetBoundingBox (bbox); + + if (bbox.Diam() < h) + { + h = bbox.Diam(); + mp.maxh = h; + } + + mesh = new Mesh; + mesh->SetDimension (2); + PrintMessage (1, "Generate Mesh from spline geometry"); + + geometry.PartitionBoundary (h, *mesh); + + for (i = 0; i < geometry.GetNP(); i++) + if (geometry.GetPoint(i).hpref) + { + double mindist = 1e99; + PointIndex mpi; + Point<2> gp = geometry.GetPoint(i); + Point<3> gp3(gp(0), gp(1), 0); + for (PointIndex pi = PointIndex::BASE; + pi < mesh->GetNP()+PointIndex::BASE; pi++) + if (Dist2(gp3, (*mesh)[pi]) < mindist) + { + mpi = pi; + mindist = Dist2(gp3, (*mesh)[pi]); + } + (*mesh)[mpi].SetSingular(); + } + + + int maxdomnr = 0; + for (si = 0; si < mesh->GetNSeg(); si++) + { + if ( (*mesh)[si].domin > maxdomnr) maxdomnr = (*mesh)[si].domin; + if ( (*mesh)[si].domout > maxdomnr) maxdomnr = (*mesh)[si].domout; + } + + mesh->ClearFaceDescriptors(); + for (i = 1; i <= maxdomnr; i++) + mesh->AddFaceDescriptor (FaceDescriptor (i, 0, 0, i)); + + Point3d pmin(bbox.PMin()(0), bbox.PMin()(1), -bbox.Diam()); + Point3d pmax(bbox.PMax()(0), bbox.PMax()(1), bbox.Diam()); + + mesh->SetLocalH (pmin, pmax, mparam.grading); + mesh->SetGlobalH (h); + + mesh->CalcLocalH(); + + int bnp = mesh->GetNP(); // boundary points + + for (domnr = 1; domnr <= maxdomnr; domnr++) + { + PrintMessage (3, "Meshing domain ", domnr, " / ", maxdomnr); + + int oldnf = mesh->GetNSE(); + + Meshing2 meshing (Box3d (pmin, pmax)); + + for (pi = PointIndex::BASE; + pi < bnp+PointIndex::BASE; pi++) + meshing.AddPoint ( (*mesh)[pi], pi); + + + PointGeomInfo gi; + gi.trignum = 1; + for (si = 0; si < mesh->GetNSeg(); si++) + { + if ( (*mesh)[si].domin == domnr) + meshing.AddBoundaryElement ( (*mesh)[si].p1 + 1 - PointIndex::BASE, + (*mesh)[si].p2 + 1 - PointIndex::BASE, gi, gi); + if ( (*mesh)[si].domout == domnr) + meshing.AddBoundaryElement ( (*mesh)[si].p2 + 1 - PointIndex::BASE, + (*mesh)[si].p1 + 1 - PointIndex::BASE, gi, gi); + } + + + mparam.checkoverlap = 0; + meshing.GenerateMesh (*mesh, h, domnr); + + for (sei = oldnf; sei < mesh->GetNSE(); sei++) + (*mesh)[sei].SetIndex (domnr); + } + + + int hsteps = mp.optsteps2d; + + mp.optimize2d = "smcm"; + mp.optsteps2d = hsteps/2; + Optimize2d (*mesh, mp); + + mp.optimize2d = "Smcm"; + mp.optsteps2d = (hsteps+1)/2; + Optimize2d (*mesh, mp); + + mp.optsteps2d = hsteps; + + mesh->Compress(); + mesh -> SetNextMajorTimeStamp(); + + +#ifdef OPENGL + extern void Render(); + Render(); +#endif + + } + + +} diff --git a/contrib/Netgen/libsrc/geom2d/geom2dmesh.cpp b/contrib/Netgen/libsrc/geom2d/geom2dmesh.cpp new file mode 100644 index 0000000000..1b679bd3c0 --- /dev/null +++ b/contrib/Netgen/libsrc/geom2d/geom2dmesh.cpp @@ -0,0 +1,55 @@ +#include <mystdlib.h> + +#include <csg.hpp> +#include <geometry2d.hpp> +#include <meshing.hpp> + +namespace netgen +{ + + Refinement2d :: Refinement2d (const SplineGeometry2d & ageometry) + : Refinement(), geometry(ageometry) + { + ; + } + + Refinement2d :: ~Refinement2d () + { + ; + } + + + void Refinement2d :: + PointBetween (const Point3d & p1, const Point3d & p2, double secpoint, + int surfi, + const PointGeomInfo & gi1, + const PointGeomInfo & gi2, + Point3d & newp, PointGeomInfo & newgi) + { + newp = p1+secpoint*(p2-p1); + newgi.trignum = 1; + } + + + + void Refinement2d :: + PointBetween (const Point3d & p1, const Point3d & p2, double secpoint, + int surfi1, int surfi2, + const EdgePointGeomInfo & ap1, + const EdgePointGeomInfo & ap2, + Point3d & newp, EdgePointGeomInfo & newgi) + { + Point<2> p2d; + + p2d = geometry.GetSplines().Get(ap1.edgenr) -> + GetPoint (((1-secpoint)*ap1.dist+secpoint*ap2.dist)); + + // (*testout) << "refine 2d line, ap1.dist, ap2.dist = " << ap1.dist << ", " << ap2.dist << endl; + // (*testout) << "p1, p2 = " << p1 << p2 << ", newp = " << p2d << endl; + + newp = Point3d (p2d(0), p2d(1), 0); + newgi.edgenr = ap1.edgenr; + newgi.dist = ((1-secpoint)*ap1.dist+secpoint*ap2.dist); + } + +} diff --git a/contrib/Netgen/libsrc/geom2d/geom2dmesh.hpp b/contrib/Netgen/libsrc/geom2d/geom2dmesh.hpp new file mode 100644 index 0000000000..6912cd7752 --- /dev/null +++ b/contrib/Netgen/libsrc/geom2d/geom2dmesh.hpp @@ -0,0 +1,38 @@ +#ifndef FILE_GEOM2DMESH +#define FILE_GEOM2DMESH + +/**************************************************************************/ +/* File: geom2dmesh.hh */ +/* Author: Joachim Schoeberl */ +/* Date: 22. Jan. 01 */ +/**************************************************************************/ + + +class Refinement2d : public Refinement +{ + const SplineGeometry2d & geometry; + +public: + Refinement2d (const SplineGeometry2d & ageometry); + virtual ~Refinement2d (); + + virtual void PointBetween (const Point3d & p1, const Point3d & p2, double secpoint, + int surfi, + const PointGeomInfo & gi1, + const PointGeomInfo & gi2, + Point3d & newp, PointGeomInfo & newgi); + + virtual void PointBetween (const Point3d & p1, const Point3d & p2, double secpoint, + int surfi1, int surfi2, + const EdgePointGeomInfo & ap1, + const EdgePointGeomInfo & ap2, + Point3d & newp, EdgePointGeomInfo & newgi); + +}; + + + + + + +#endif diff --git a/contrib/Netgen/libsrc/geom2d/geometry2d.hpp b/contrib/Netgen/libsrc/geom2d/geometry2d.hpp new file mode 100644 index 0000000000..80d276e340 --- /dev/null +++ b/contrib/Netgen/libsrc/geom2d/geometry2d.hpp @@ -0,0 +1,20 @@ +#ifndef FILE_GEOMETRY2D +#define FILE_GEOMETRY2D + +/* *************************************************************************/ +/* File: geometry2d.hpp */ +/* Author: Joachim Schoeberl */ +/* Date: 20. Jul. 02 */ +/* *************************************************************************/ + +#include <myadt.hpp> +#include <gprim.hpp> + +namespace netgen +{ +#include "spline2d.hpp" +#include "splinegeometry2.hpp" +#include "geom2dmesh.hpp" +} + +#endif diff --git a/contrib/Netgen/libsrc/geom2d/spline2d.cpp b/contrib/Netgen/libsrc/geom2d/spline2d.cpp new file mode 100644 index 0000000000..8609e064d1 --- /dev/null +++ b/contrib/Netgen/libsrc/geom2d/spline2d.cpp @@ -0,0 +1,395 @@ +/* + +2d Spline curve for Mesh generator + +*/ + +#include <mystdlib.h> +#include <csg.hpp> +#include <linalg.hpp> +#include <meshing.hpp> + +namespace netgen +{ +#include "spline2d.hpp" + + + void CalcPartition (double l, double h, double r1, double r2, + double ra, double elto0, ARRAY<double> & points); + + + + // calculates length of spline-curve + double SplineSegment :: Length () const + { + Point<2> p, pold; + + int i, n = 100; + double dt = 1.0 / n; + + pold = GetPoint (0); + + double l = 0; + for (i = 1; i <= n; i++) + { + p = GetPoint (i * dt); + l += Dist (p, pold); + pold = p; + } + return l; + } + + + + // partitionizes spline curve + void SplineSegment :: Partition (double h, double elto0, + Mesh & mesh, Point3dTree & searchtree, int segnr) const + { + int i, j; + double l, r1, r2, ra; + double lold, dt, frac; + int n = 100; + Point<2> p, pold, mark, oldmark; + ARRAY<double> curvepoints; + double edgelength, edgelengthold; + l = Length(); + + r1 = StartPI().refatpoint; + r2 = EndPI().refatpoint; + ra = reffak; + + // cout << "Partition, l = " << l << ", h = " << h << endl; + CalcPartition (l, h, r1, r2, ra, elto0, curvepoints); + // cout << "curvepoints = " << curvepoints << endl; + + dt = 1.0 / n; + + l = 0; + j = 1; + + pold = GetPoint (0); + lold = 0; + oldmark = pold; + edgelengthold = 0; + ARRAY<int> locsearch; + + for (i = 1; i <= n; i++) + { + p = GetPoint (i*dt); + l = lold + Dist (p, pold); + while (j < curvepoints.Size() && (l >= curvepoints[j] || i == n)) + { + frac = (curvepoints[j]-lold) / (l-lold); + mark = pold + frac * (p-pold); + edgelength = i*dt + (frac-1)*dt; + { + PointIndex pi1 = -1, pi2 = -1; + + Point3d mark3(mark(0), mark(1), 0); + Point3d oldmark3(oldmark(0), oldmark(1), 0); + + Vec<3> v (1e-4*h, 1e-4*h, 1e-4*h); + searchtree.GetIntersecting (oldmark3 - v, oldmark3 + v, locsearch); + if (locsearch.Size()) pi1 = locsearch[0]; + + searchtree.GetIntersecting (mark3 - v, mark3 + v, locsearch); + if (locsearch.Size()) pi2 = locsearch[0]; + /* + for (PointIndex pk = PointIndex::BASE; + pk < mesh.GetNP()+PointIndex::BASE; pk++) + { + if (Dist (mesh[pk], oldmark3) < 1e-4 * h) pi1 = pk; + if (Dist (mesh[pk], mark3) < 1e-4 * h) pi2 = pk; + } + */ + + + // cout << "pi1 = " << pi1 << endl; + // cout << "pi2 = " << pi2 << endl; + + if (pi1 == -1) + { + pi1 = mesh.AddPoint(oldmark3); + searchtree.Insert (oldmark3, pi1); + } + if (pi2 == -1) + { + pi2 = mesh.AddPoint(mark3); + searchtree.Insert (mark3, pi2); + } + + // cout << "pi1 = " << pi1 << endl; + // cout << "pi2 = " << pi2 << endl; + + Segment seg; + seg.edgenr = segnr; + seg.si = bc; // segnr; + seg.p1 = pi1; + seg.p2 = pi2; + seg.domin = leftdom; + seg.domout = rightdom; + seg.epgeominfo[0].edgenr = segnr; + seg.epgeominfo[0].dist = edgelengthold; + seg.epgeominfo[1].edgenr = segnr; + seg.epgeominfo[1].dist = edgelength; + seg.singedge_left = hpref_left; + seg.singedge_right = hpref_right; + mesh.AddSegment (seg); + } + + oldmark = mark; + edgelengthold = edgelength; + j++; + } + + pold = p; + lold = l; + } + } + + + void SplineSegment :: GetPoints (int n, ARRAY<Point<2> > & points) + { + points.SetSize (n); + if (n >= 2) + for (int i = 0; i < n; i++) + points[i] = GetPoint(double(i) / (n-1)); + } + + + + /* + Implementation of line-segment from p1 to p2 + */ + + + LineSegment :: LineSegment (const GeomPoint2d & ap1, + const GeomPoint2d & ap2) + : p1(ap1), p2(ap2) + { + ; + } + + + Point<2> LineSegment :: GetPoint (double t) const + { + return p1 + t * (p2 - p1); + } + + double LineSegment :: Length () const + { + return Dist (p1, p2); + } + + + void LineSegment :: PrintCoeff (ostream & ost) const + { + double dx = p2(0) - p1(0); + double dy = p2(1) - p1(1); + ost << "0 0 0 " << dy << " " << -dx << " " + << dx * p1(1) - dy * p1(0) << endl; + } + + + + + + SplineSegment3 :: SplineSegment3 (const GeomPoint2d & ap1, + const GeomPoint2d & ap2, + const GeomPoint2d & ap3) + : p1(ap1), p2(ap2), p3(ap3) + { + ; + } + + Point<2> SplineSegment3 :: GetPoint (double t) const + { + double x, y, w; + double b1, b2, b3; + + b1 = (1-t)*(1-t); + b2 = sqrt(2.0) * t * (1-t); + b3 = t * t; + + x = p1(0) * b1 + p2(0) * b2 + p3(0) * b3; + y = p1(1) * b1 + p2(1) * b2 + p3(1) * b3; + w = b1 + b2 + b3; + + return Point<2> (x/w, y/w); + } + + + void SplineSegment3 :: PrintCoeff (ostream & ost) const + { + double t; + int i; + Point<2> p; + DenseMatrix a(6, 6); + DenseMatrix ata(6, 6); + Vector u(6), f(6); + + // ata.SetSymmetric(1); + + t = 0; + for (i = 1; i <= 5; i++, t += 0.25) + { + p = GetPoint (t); + a.Elem(i, 1) = p(0) * p(0); + a.Elem(i, 2) = p(1) * p(1); + a.Elem(i, 3) = p(0) * p(1); + a.Elem(i, 4) = p(0); + a.Elem(i, 5) = p(1); + a.Elem(i, 6) = 1; + } + a.Elem(6, 1) = 1; + + CalcAtA (a, ata); + + u = 0; + u.Elem(6) = 1; + a.MultTrans (u, f); + ata.Solve (f, u); + + for (i = 1; i <= 6; i++) + ost << u.Get(i) << " "; + ost << endl; + } + + + + + //######################################################################## + // circlesegment + + CircleSegment :: CircleSegment (const GeomPoint2d & ap1, + const GeomPoint2d & ap2, + const GeomPoint2d & ap3) + : p1(ap1), p2(ap2), p3(ap3) + { + Vec<2> v1,v2; + + v1 = p1 - p2; + v2 = p3 - p2; + + Point<2> p1t(p1(0)+v1[1], p1(1)-v1[0]); + Point<2> p2t(p3(0)+v2[1], p3(1)-v2[0]); + Line2d g1t(p1, p1t), g2t(p3, p2t); + + pm = CrossPoint (g1t,g2t); + radius = Dist(pm,StartPI()); + w1 = Angle(Vec2d (p1 - pm)); + w3 = Angle(Vec2d (p3 - pm)); + if ( fabs(w3-w1) > M_PI ) + { + if ( w3>M_PI ) w3 -= 2*M_PI; + if ( w1>M_PI ) w1 -= 2*M_PI; + } + } + + Point<2> CircleSegment :: GetPoint (double t) const + { + if (t >= 1.0) { return p3; } + + double phi = StartAngle() + t*(EndAngle()-StartAngle()); + Vec2d tmp(cos(phi),sin(phi)); + + return pm + Radius()*tmp; + } + + void CircleSegment :: PrintCoeff (ostream & ost) const + { + double a,b,c,d,e,f; + + a = b = 1.0; + c = 0.0; + d = -2.0 * pm[0]; + e = -2.0 * pm[1]; + f = sqr(pm[0]) + sqr(pm[1]) - sqr(Radius()); + + ost << a << " " << b << " " << c << " " << d << " " << e << " " << f ; + ost << endl; + } + + + + DiscretePointsSegment :: DiscretePointsSegment (const ARRAY<Point<2> > & apts) + : pts (apts), + p1 (apts[0](0), apts[0](1), 1), + p2 (apts.Last()(0), apts.Last()(1), 1) + + { ; } + + + DiscretePointsSegment :: ~DiscretePointsSegment () + { ; } + + Point<2> DiscretePointsSegment :: 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 Point<2> ((1-rest)*pts[segnr](0) + rest*pts[segnr+1](0), + (1-rest)*pts[segnr](1) + rest*pts[segnr+1](1)); + } + + + + + + + //######################################################################## + + + + + void CalcPartition (double l, double h, double r1, double r2, + double ra, double elto0, ARRAY<double> & points) + { + int i, j, n, nel; + double sum, t, dt, fun, fperel, oldf, f; + + n = 1000; + + points.SetSize (0); + + sum = 0; + dt = l / n; + t = 0.5 * dt; + for (i = 1; i <= n; i++) + { + fun = min3 (h/ra, t/elto0 + h/r1, (l-t)/elto0 + h/r2); + sum += dt / fun; + t += dt; + } + + nel = int (sum+1); + fperel = sum / nel; + + points.Append (0); + + i = 1; + oldf = 0; + t = 0.5 * dt; + for (j = 1; j <= n && i < nel; j++) + { + fun = min3 (h/ra, t/elto0 + h/r1, (l-t)/elto0 + h/r2); + + f = oldf + dt / fun; + + while (f > i * fperel && i < nel) + { + points.Append ( (l/n) * (j-1 + (i * fperel - oldf) / (f - oldf)) ); + i++; + } + oldf = f; + t += dt; + } + points.Append (l); + } + + +} diff --git a/contrib/Netgen/libsrc/geom2d/spline2d.hpp b/contrib/Netgen/libsrc/geom2d/spline2d.hpp new file mode 100644 index 0000000000..f107a137f1 --- /dev/null +++ b/contrib/Netgen/libsrc/geom2d/spline2d.hpp @@ -0,0 +1,204 @@ +#ifndef FILE_SPLINE2D +#define FILE_SPLINE2D + +/**************************************************************************/ +/* File: spline2d.hh */ +/* Author: Joachim Schoeberl */ +/* Date: 24. Jul. 96 */ +/**************************************************************************/ + + +/* + Spline curves for 2D mesh generation + */ + + +/// Geometry point +class GeomPoint2d : public Point<2> +{ +public: + /// refinement to point + double refatpoint; + bool hpref; + + GeomPoint2d () + { ; } + + /// + GeomPoint2d (double ax, double ay, double aref = 1) + : Point<2> (ax, ay), refatpoint(aref) { ; } +}; + + + +/// base class for 2d - segment +class SplineSegment +{ +public: + /// left domain + int leftdom; + /// right domain + int rightdom; + /// refinement at line + double reffak; + /// boundary condition number + int bc; + /// copy spline mesh from other spline (-1.. do not copy) + int copyfrom; + /// perfrom anisotropic refinement (hp-refinement) to edge + bool hpref_left; + bool hpref_right; + /// calculates length of curve + virtual double Length () const; + /// returns point at curve, 0 <= t <= 1 + virtual Point<2> GetPoint (double t) const = 0; + /// partitionizes curve + void Partition (double h, double elto0, + Mesh & mesh, Point3dTree & searchtree, int segnr) const; + /// returns initial point on curve + virtual const GeomPoint2d & StartPI () const = 0; + /// returns terminal point on curve + virtual const GeomPoint2d & EndPI () const = 0; + /** writes curve description for fepp: + for implicitly given quadratic curves, the 6 coefficients of + the polynomial + $$ a x^2 + b y^2 + c x y + d x + e y + f = 0 $$ + are written to ost */ + virtual void PrintCoeff (ostream & ost) const = 0; + + virtual void GetPoints (int n, ARRAY<Point<2> > & points); + + 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 string GetType(void) const {return "line";} +}; + + +/// 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 string GetType(void) const {return "spline3";} +}; + + +// Gundolf Haase 8/26/97 +/// A circle +class CircleSegment : public SplineSegment +{ + /// +private: + const GeomPoint2d &p1, &p2, &p3; + Point<2> pm; + double radius, w1,w3; +public: + /// + CircleSegment (const GeomPoint2d & ap1, + const GeomPoint2d & ap2, + const GeomPoint2d & ap3); + /// + virtual Point<2> GetPoint (double t) const; + /// + virtual const GeomPoint2d & StartPI () const { return p1; }; + /// + virtual const GeomPoint2d & EndPI () const { return p3; } + /// + virtual void PrintCoeff (ostream & ost) const; + /// + double Radius() const { return radius; } + /// + double StartAngle() const { return w1; } + /// + double EndAngle() const { return w3; } + + virtual string GetType(void) const {return "circle";} +}; + + +// Gundolf Haase 8/26/97 +/// elliptic curve with one axe parallel to line {P1,P2} +/* +class ellipsegment3 : public SplineSegment +{ + /// + GeomPoint2d *p1, *p2, *p3; +public: + /// + SplineSegment3 (GeomPoint2d * ap1, GeomPoint2d * ap2, GeomPoint2d * ap3); + /// + virtual Point<2> GetPoint (double t) const; + /// + virtual GeomPoint2d * StartPI () const { return p1; }; + /// + virtual GeomPoint2d * EndPI () const { return p3; } + /// + virtual void PrintCoeff (ostream & ost) const; +}; +*/ + + + + + + +/// +class DiscretePointsSegment : public SplineSegment +{ + ARRAY<Point<2> > pts; + GeomPoint2d p1, p2; +public: + /// + DiscretePointsSegment (const ARRAY<Point<2> > & apts); + /// + virtual ~DiscretePointsSegment (); + /// + virtual Point<2> GetPoint (double t) const; + /// + virtual const GeomPoint2d & StartPI () const { return p1; }; + /// + virtual const GeomPoint2d & EndPI () const { return p2; } + /// + virtual void PrintCoeff (ostream & /* ost */) const { ; } +}; + + + + + +#endif diff --git a/contrib/Netgen/libsrc/geom2d/splinegeometry2.cpp b/contrib/Netgen/libsrc/geom2d/splinegeometry2.cpp new file mode 100644 index 0000000000..a034d53989 --- /dev/null +++ b/contrib/Netgen/libsrc/geom2d/splinegeometry2.cpp @@ -0,0 +1,346 @@ +/* + +2d Spline curve for Mesh generator + +*/ + +#include <mystdlib.h> +#include <csg.hpp> +#include <linalg.hpp> +#include <meshing.hpp> + + +namespace netgen + +{ + +#include "spline2d.hpp" +#include "splinegeometry2.hpp" + + + +SplineGeometry2d :: ~SplineGeometry2d() +{ + for(int i=0; i<splines.Size(); i++) + { + delete splines[i]; + } + splines.DeleteAll(); + geompoints.DeleteAll(); +} + +void SplineGeometry2d :: Load (const char * filename) +{ + ifstream infile; + int nump, numseg, leftdom, rightdom; + double x, y; + int hi1, hi2, hi3; + double hd; + char buf[50], ch; + + infile.open (filename); + + if (! infile.good() ) + throw NgException(string ("2D Input file '") + + string (filename) + + string ("' not available!")); + + infile >> buf; // file recognition + infile >> elto0; + + infile >> nump; + for (int i = 0; i < nump; i++) + { + infile >> x >> y >> 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 (GeomPoint2d(x, y, hd)); + geompoints.Last().hpref = flags.GetDefineFlag ("hpref"); + } + + infile >> numseg; + SplineSegment * spline = 0; + for (int i = 0; i < numseg; i++) + { + infile >> leftdom >> rightdom; + + // cout << "add spline " << i << ", left = " << leftdom << endl; + + infile >> buf; + // type of spline segement + if (strcmp (buf, "2") == 0) + { // a line + infile >> hi1 >> hi2; + spline = new LineSegment(geompoints[hi1-1], + geompoints[hi2-1]); + } + else if (strcmp (buf, "3") == 0) + { // a rational spline + infile >> hi1 >> hi2 >> hi3; + spline = new SplineSegment3 (geompoints[hi1-1], + geompoints[hi2-1], + geompoints[hi3-1]); + } + else if (strcmp (buf, "4") == 0) + { // an arc + infile >> hi1 >> hi2 >> hi3; + spline = new CircleSegment (geompoints[hi1-1], + geompoints[hi2-1], + geompoints[hi3-1]); + break; + } + else if (strcmp (buf, "discretepoints") == 0) + { + int npts; + infile >> npts; + ARRAY<Point<2> > pts(npts); + for (int j = 0; j < npts; j++) + infile >> pts[j](0) >> pts[j](1); + + spline = new DiscretePointsSegment (pts); + cout << "pts = " << pts << endl; + } + + infile >> spline->reffak; + spline -> leftdom = leftdom; + spline -> rightdom = rightdom; + splines.Append (spline); + + + Flags flags; + ch = 'a'; + infile >> ch; + while (ch == '-') + { + char flag[100]; + flag[0]='-'; + infile >> (flag+1); + flags.SetCommandLineFlag (flag); + ch = 'a'; + infile >> ch; + } + + if (infile.good()) + infile.putback (ch); + + splines.Last()->bc = int (flags.GetNumFlag ("bc", i+1)); + splines.Last()->hpref_left = int (flags.GetDefineFlag ("hpref")) || + int (flags.GetDefineFlag ("hprefleft")); + splines.Last()->hpref_right = int (flags.GetDefineFlag ("hpref")) || + int (flags.GetDefineFlag ("hprefright")); + splines.Last()->copyfrom = int (flags.GetNumFlag ("copy", -1)); + } + + + infile.close(); +} + + + +void SplineGeometry2d :: +PartitionBoundary (double h, Mesh & mesh2d) +{ + Box<2> bbox; + GetBoundingBox (bbox); + double dist = Dist (bbox.PMin(), bbox.PMax()); + Point<3> pmin(bbox.PMin()(0), bbox.PMin()(1), -dist); + Point<3> pmax(bbox.PMax()(0), bbox.PMax()(1), dist); + + cout << "searchtree from " << pmin << " to " << pmax << endl; + Point3dTree searchtree (pmin, pmax); + + for (int i = 0; i < splines.Size(); i++) + if (splines[i]->copyfrom == -1) + splines[i]->Partition(h, elto0, mesh2d, searchtree, i+1); + else + CopyEdgeMesh (splines[i]->copyfrom, i+1, mesh2d, searchtree); +} + + +void SplineGeometry2d :: CopyEdgeMesh (int from, int to, Mesh & mesh, Point3dTree & searchtree) +{ + int i, j, k; + + ARRAY<int, PointIndex::BASE> mappoints (mesh.GetNP()); + ARRAY<double, PointIndex::BASE> param (mesh.GetNP()); + mappoints = -1; + param = 0; + + Point3d pmin, pmax; + mesh.GetBox (pmin, pmax); + double diam2 = Dist2(pmin, pmax); + + cout << "copy edge, from = " << from << " to " << to << endl; + + for (i = 1; i <= mesh.GetNSeg(); i++) + { + const Segment & seg = mesh.LineSegment(i); + if (seg.edgenr == from) + { + mappoints.Elem(seg.p1) = 1; + param.Elem(seg.p1) = seg.epgeominfo[0].dist; + + mappoints.Elem(seg.p2) = 1; + param.Elem(seg.p2) = seg.epgeominfo[1].dist; + } + } + + for (i = 1; i <= mappoints.Size(); i++) + { + if (mappoints.Get(i) != -1) + { + Point<2> newp = splines.Get(to)->GetPoint (param.Get(i)); + Point<3> newp3 (newp(0), newp(1), 0); + + int npi = -1; + + for (PointIndex pi = PointIndex::BASE; + pi < mesh.GetNP()+PointIndex::BASE; pi++) + if (Dist2 (mesh.Point(pi), newp3) < 1e-12 * diam2) + npi = pi; + + if (npi == -1) + { + npi = mesh.AddPoint (newp3); + searchtree.Insert (newp3, npi); + } + + mappoints.Elem(i) = npi; + + mesh.GetIdentifications().Add (i, npi, to); + } + } + + // copy segments + int oldnseg = mesh.GetNSeg(); + for (i = 1; i <= oldnseg; i++) + { + const Segment & seg = mesh.LineSegment(i); + if (seg.edgenr == from) + { + Segment nseg; + nseg.edgenr = to; + nseg.si = splines.Get(to)->bc; + nseg.p1 = mappoints.Get(seg.p1); + nseg.p2 = mappoints.Get(seg.p2); + nseg.domin = splines.Get(to)->leftdom; + nseg.domout = splines.Get(to)->rightdom; + + nseg.epgeominfo[0].edgenr = to; + nseg.epgeominfo[0].dist = param.Get(seg.p1); + nseg.epgeominfo[1].edgenr = to; + nseg.epgeominfo[1].dist = param.Get(seg.p2); + mesh.AddSegment (nseg); + } + } +} + + +void SplineGeometry2d :: +GetBoundingBox (Box<2> & box) const +{ + if (!splines.Size()) + { + box.Set (Point<2> (0,0)); + return; + } + + ARRAY<Point<2> > points; + for (int i = 0; i < splines.Size(); i++) + { + splines[i]->GetPoints (20, points); + + if (i == 0) box.Set(points[0]); + for (int j = 0; j < points.Size(); j++) + box.Add (points[j]); + } +} + +void SplineGeometry2d :: +SetGrading (const double grading) +{ elto0 = grading;} + +void SplineGeometry2d :: +AppendPoint (const double x, const double y, const double reffac, const bool hpref) +{ + geompoints.Append (GeomPoint2d(x, y, reffac)); + geompoints.Last().hpref = hpref; +} + + +void SplineGeometry2d :: +AppendSegment(SplineSegment * spline, const int leftdomain, const int rightdomain, + const int bc, + const double reffac, const bool hprefleft, const bool hprefright, + const int copyfrom) +{ + spline -> leftdom = leftdomain; + spline -> rightdom = rightdomain; + spline -> bc = (bc >= 0) ? bc : (splines.Size()+1); + spline -> reffak = reffac; + spline -> hpref_left = hprefleft; + spline -> hpref_right = hprefright; + spline -> copyfrom = copyfrom; + + splines.Append(spline); +} + +void SplineGeometry2d :: +AppendLineSegment (const int n1, const int n2, const int leftdomain, const int rightdomain, + const int bc, + const double reffac, const bool hprefleft, const bool hprefright, + const int copyfrom) +{ + SplineSegment * spline = new LineSegment(geompoints[n1],geompoints[n2]); + AppendSegment(spline,leftdomain,rightdomain,bc,reffac,hprefleft,hprefright,copyfrom); +} +void SplineGeometry2d :: +AppendSplineSegment (const int n1, const int n2, const int n3, const int leftdomain, const int rightdomain, + const int bc, + const double reffac, const bool hprefleft, const bool hprefright, + const int copyfrom) +{ + SplineSegment * spline = new SplineSegment3(geompoints[n1],geompoints[n2],geompoints[n3]); + AppendSegment(spline,leftdomain,rightdomain,bc,reffac,hprefleft,hprefright,copyfrom); +} +void SplineGeometry2d :: +AppendCircleSegment (const int n1, const int n2, const int n3, const int leftdomain, const int rightdomain, + const int bc, + const double reffac, const bool hprefleft, const bool hprefright, + const int copyfrom) +{ + SplineSegment * spline = new CircleSegment(geompoints[n1],geompoints[n2],geompoints[n3]); + AppendSegment(spline,leftdomain,rightdomain,bc,reffac,hprefleft,hprefright,copyfrom); +} +void SplineGeometry2d :: +AppendDiscretePointsSegment (const ARRAY< Point<2> > & points, const int leftdomain, const int rightdomain, + const int bc, + const double reffac, const bool hprefleft, const bool hprefright, + const int copyfrom) +{ + SplineSegment * spline = new DiscretePointsSegment(points); + AppendSegment(spline,leftdomain,rightdomain,bc,reffac,hprefleft,hprefright,copyfrom); +} + +} diff --git a/contrib/Netgen/libsrc/geom2d/splinegeometry2.hpp b/contrib/Netgen/libsrc/geom2d/splinegeometry2.hpp new file mode 100644 index 0000000000..66c2a4d79f --- /dev/null +++ b/contrib/Netgen/libsrc/geom2d/splinegeometry2.hpp @@ -0,0 +1,83 @@ +#ifndef FILE_SPLINEGEOMETRY2 +#define FILE_SPLINEGEOMETRY2 + +/**************************************************************************/ +/* File: splinegeometry2.hpp */ +/* Author: Joachim Schoeberl */ +/* Date: 24. Jul. 96 */ +/**************************************************************************/ + + + +/// +extern void LoadBoundarySplines (const char * filename, + ARRAY<GeomPoint2d> & geompoints, + ARRAY<SplineSegment*> & splines, + double & elto0); +/// +extern void PartitionBoundary (const ARRAY<SplineSegment*> & splines, + double h, double elto0, + Mesh & mesh2d); + +class SplineGeometry2d +{ + ARRAY<GeomPoint2d> geompoints; + ARRAY<SplineSegment*> splines; + double elto0; + + +private: + void AppendSegment(SplineSegment * spline, const int leftdomain, const int rightdomain, + const int bc, + const double reffac, const bool hprefleft, const bool hprefright, + const int copyfrom); + +public: + ~SplineGeometry2d(); + + void Load (const char * filename); + void PartitionBoundary (double h, Mesh & mesh2d); + + void CopyEdgeMesh (int from, int to, Mesh & mesh2d, Point3dTree & searchtree); + + const ARRAY<SplineSegment*> & GetSplines () const + { return splines; } + + void GetBoundingBox (Box<2> & box) const; + + int GetNP () const { return geompoints.Size(); } + const GeomPoint2d & GetPoint(int i) const { return geompoints[i]; } + + void SetGrading (const double grading); + void AppendPoint (const double x, const double y, const double reffac = 1., const bool hpref = false); + + void AppendLineSegment (const int n1, const int n2, + const int leftdomain, const int rightdomain, const int bc = -1, + const double reffac = 1., + const bool hprefleft = false, const bool hprefright = false, + const int copyfrom = -1); + void AppendSplineSegment (const int n1, const int n2, const int n3, + const int leftdomain, const int rightdomain, const int bc = -1, + const double reffac = 1., + const bool hprefleft = false, const bool hprefright = false, + const int copyfrom = -1); + void AppendCircleSegment (const int n1, const int n2, const int n3, + const int leftdomain, const int rightdomain, const int bc = -1, + const double reffac = 1., + const bool hprefleft = false, const bool hprefright = false, + const int copyfrom = -1); + void AppendDiscretePointsSegment (const ARRAY< Point<2> > & points, + const int leftdomain, const int rightdomain, const int bc = -1, + const double reffac = 1., + const bool hprefleft = false, const bool hprefright = false, + const int copyfrom = -1); + +}; + + +void MeshFromSpline2D (SplineGeometry2d & geometry, + Mesh *& mesh, + MeshingParameters & mp); + + +#endif diff --git a/contrib/Netgen/libsrc/gprim/Makefile b/contrib/Netgen/libsrc/gprim/Makefile new file mode 100644 index 0000000000..608e522844 --- /dev/null +++ b/contrib/Netgen/libsrc/gprim/Makefile @@ -0,0 +1,14 @@ +# +# Makefile for geometric library +# +src = geom2d.cpp geom3d.cpp \ + geomtest3d.cpp adtree.cpp transform3d.cpp geomfuncs.cpp + +# reftrans.cpp rot3d.cpp +# +lib = gprim +libpath = libsrc/gprim +# +# +include ../makefile.inc +# diff --git a/contrib/Netgen/libsrc/gprim/adtree.cpp b/contrib/Netgen/libsrc/gprim/adtree.cpp new file mode 100644 index 0000000000..25f46183e2 --- /dev/null +++ b/contrib/Netgen/libsrc/gprim/adtree.cpp @@ -0,0 +1,2245 @@ +#include <mystdlib.h> + + +#include <myadt.hpp> +// class DenseMatrix; +#include <gprim.hpp> + +namespace netgen +{ + + + /* ******************************* ADTree ******************************* */ + + + ADTreeNode :: ADTreeNode(int adim) + { + pi = -1; + + left = NULL; + right = NULL; + father = NULL; + nchilds = 0; + dim = adim; + data = new float [dim]; + boxmin = NULL; + boxmax = NULL; + } + + + + + ADTreeNode :: ~ADTreeNode() + { + delete data; + } + + + ADTree :: ADTree (int adim, const float * acmin, + const float * acmax) + : ela(0), stack(1000), stackdir(1000) + { + dim = adim; + cmin = new float [dim]; + cmax = new float [dim]; + memcpy (cmin, acmin, dim * sizeof(float)); + memcpy (cmax, acmax, dim * sizeof(float)); + + root = new ADTreeNode (dim); + root->sep = (cmin[0] + cmax[0]) / 2; + root->boxmin = new float [dim]; + root->boxmax = new float [dim]; + memcpy (root->boxmin, cmin, dim * sizeof(float)); + memcpy (root->boxmax, cmax, dim * sizeof(float)); + } + + ADTree :: ~ADTree () + { + ; + } + + void ADTree :: Insert (const float * p, int pi) + { + ADTreeNode *node; + ADTreeNode *next; + int dir; + int lr; + + float * bmin = new float [dim]; + float * bmax = new float [dim]; + + memcpy (bmin, cmin, dim * sizeof(float)); + memcpy (bmax, cmax, dim * sizeof(float)); + + + next = root; + dir = 0; + while (next) + { + node = next; + + if (node->pi == -1) + { + memcpy (node->data, p, dim * sizeof(float)); + node->pi = pi; + + if (ela.Size() < pi+1) + ela.SetSize (pi+1); + ela[pi] = node; + + return; + } + + if (node->sep > p[dir]) + { + next = node->left; + bmax[dir] = node->sep; + lr = 0; + } + else + { + next = node->right; + bmin[dir] = node->sep; + lr = 1; + } + + dir++; + if (dir == dim) + dir = 0; + } + + + next = new ADTreeNode(dim); + memcpy (next->data, p, dim * sizeof(float)); + next->pi = pi; + next->sep = (bmin[dir] + bmax[dir]) / 2; + next->boxmin = bmin; + next->boxmax = bmax; + + if (ela.Size() < pi+1) + ela.SetSize (pi+1); + ela[pi] = next; + + + if (lr) + node->right = next; + else + node->left = next; + next -> father = node; + + while (node) + { + node->nchilds++; + node = node->father; + } + } + + void ADTree :: DeleteElement (int pi) + { + ADTreeNode * node = ela[pi]; + + node->pi = -1; + + node = node->father; + while (node) + { + node->nchilds--; + node = node->father; + } + } + + + void ADTree :: SetCriterion (ADTreeCriterion & acriterion) + { + criterion = & acriterion; + } + + + void ADTree :: Reset () + { + stack.Elem(1) = root; + stackdir.Elem(1) = 0; + stackindex = 1; + } + + + int ADTree:: Next () + { + ADTreeNode *node; + int dir; + + if (stackindex == 0) + return -1; + + do + { + node = stack.Get(stackindex); + dir = stackdir.Get(stackindex); + stackindex --; + + if (criterion -> Eval(node)) + { + int ndir = dir + 1; + if (ndir == dim) + ndir = 0; + + if (node -> left && criterion -> Eval (node->left)) + { + stackindex ++; + stack.Elem(stackindex) = node -> left; + stackdir.Elem(stackindex) = ndir; + } + if (node->right && criterion -> Eval (node -> right)) + { + stackindex++; + stack.Elem(stackindex) = node->right; + stackdir.Elem(stackindex) = ndir; + } + + if (node -> pi != -1) + return node->pi; + } + } + while (stackindex > 0); + + return -1; + } + + + void ADTree :: GetMatch (ARRAY <int> & matches) + { + int nodenr; + + Reset(); + + while ( (nodenr = Next()) != -1) + matches.Append (nodenr); + } + + + void ADTree :: PrintRec (ostream & ost, const ADTreeNode * node) const + { + + if (node->data) + { + ost << node->pi << ": "; + ost << node->nchilds << " childs, "; + for (int i = 0; i < dim; i++) + ost << node->data[i] << " "; + ost << endl; + } + if (node->left) + { + ost << "l "; + PrintRec (ost, node->left); + } + if (node->right) + { + ost << "r "; + PrintRec (ost, node->right); + } + } + + + /* ******************************* ADTree3 ******************************* */ + + + ADTreeNode3 :: ADTreeNode3() + { + pi = -1; + + left = NULL; + right = NULL; + father = NULL; + nchilds = 0; + } + + void ADTreeNode3 :: DeleteChilds () + { + if (left) + { + left->DeleteChilds(); + delete left; + left = NULL; + } + if (right) + { + right->DeleteChilds(); + delete right; + right = NULL; + } + } + + + BlockAllocator ADTreeNode3 :: ball(sizeof (ADTreeNode3)); + + + void * ADTreeNode3 :: operator new(size_t s) + { + return ball.Alloc(); + } + + void ADTreeNode3 :: operator delete (void * p) + { + ball.Free (p); + } + + + + + + + + ADTree3 :: ADTree3 (const float * acmin, + const float * acmax) + : ela(0) + { + memcpy (cmin, acmin, 3 * sizeof(float)); + memcpy (cmax, acmax, 3 * sizeof(float)); + + root = new ADTreeNode3; + root->sep = (cmin[0] + cmax[0]) / 2; + } + + ADTree3 :: ~ADTree3 () + { + root->DeleteChilds(); + delete root; + } + + + void ADTree3 :: Insert (const float * p, int pi) + { + ADTreeNode3 *node; + ADTreeNode3 *next; + int dir; + int lr; + + float bmin[3]; + float bmax[3]; + + memcpy (bmin, cmin, 3 * sizeof(float)); + memcpy (bmax, cmax, 3 * sizeof(float)); + + next = root; + dir = 0; + while (next) + { + node = next; + + if (node->pi == -1) + { + memcpy (node->data, p, 3 * sizeof(float)); + node->pi = pi; + + if (ela.Size() < pi+1) + ela.SetSize (pi+1); + ela[pi] = node; + + return; + } + + if (node->sep > p[dir]) + { + next = node->left; + bmax[dir] = node->sep; + lr = 0; + } + else + { + next = node->right; + bmin[dir] = node->sep; + lr = 1; + } + + dir++; + if (dir == 3) + dir = 0; + } + + + next = new ADTreeNode3; + memcpy (next->data, p, 3 * sizeof(float)); + next->pi = pi; + next->sep = (bmin[dir] + bmax[dir]) / 2; + + + if (ela.Size() < pi+1) + ela.SetSize (pi+1); + ela[pi] = next; + + + if (lr) + node->right = next; + else + node->left = next; + next -> father = node; + + while (node) + { + node->nchilds++; + node = node->father; + } + } + + void ADTree3 :: DeleteElement (int pi) + { + ADTreeNode3 * node = ela[pi]; + + node->pi = -1; + + node = node->father; + while (node) + { + node->nchilds--; + node = node->father; + } + } + + void ADTree3 :: GetIntersecting (const float * bmin, + const float * bmax, + ARRAY<int> & pis) const + { + static ARRAY<ADTreeNode3*> stack(1000); + static ARRAY<int> stackdir(1000); + ADTreeNode3 * node; + int dir, stacks; + + stack.SetSize (1000); + stackdir.SetSize(1000); + pis.SetSize(0); + + stack.Elem(1) = root; + stackdir.Elem(1) = 0; + stacks = 1; + + while (stacks) + { + node = stack.Get(stacks); + dir = stackdir.Get(stacks); + stacks--; + + if (node->pi != -1) + { + if (node->data[0] >= bmin[0] && node->data[0] <= bmax[0] && + node->data[1] >= bmin[1] && node->data[1] <= bmax[1] && + node->data[2] >= bmin[2] && node->data[2] <= bmax[2]) + + pis.Append (node->pi); + } + + + int ndir = dir+1; + if (ndir == 3) + ndir = 0; + + if (node->left && bmin[dir] <= node->sep) + { + stacks++; + stack.Elem(stacks) = node->left; + stackdir.Elem(stacks) = ndir; + } + if (node->right && bmax[dir] >= node->sep) + { + stacks++; + stack.Elem(stacks) = node->right; + stackdir.Elem(stacks) = ndir; + } + } + } + + void ADTree3 :: PrintRec (ostream & ost, const ADTreeNode3 * node) const + { + + if (node->data) + { + ost << node->pi << ": "; + ost << node->nchilds << " childs, "; + for (int i = 0; i < 3; i++) + ost << node->data[i] << " "; + ost << endl; + } + if (node->left) + PrintRec (ost, node->left); + if (node->right) + PrintRec (ost, node->right); + } + + + + + + + + +#ifdef ABC + + /* ******************************* ADTree3Div ******************************* */ + + + ADTreeNode3Div :: ADTreeNode3Div() + { + pi = 0; + + int i; + for (i = 0; i < ADTN_DIV; i++) + childs[i] = NULL; + + father = NULL; + nchilds = 0; + minx = 0; + dist = 1; + } + + void ADTreeNode3Div :: DeleteChilds () + { + int i; + for (i = 0; i < ADTN_DIV; i++) + if (childs[i]) + { + childs[i]->DeleteChilds(); + delete childs[i]; + childs[i] = NULL; + } + } + + + BlockAllocator ADTreeNode3Div :: ball(sizeof (ADTreeNode3Div)); + + void * ADTreeNode3Div :: operator new(size_t) + { + return ball.Alloc(); + } + + void ADTreeNode3Div :: operator delete (void * p) + { + ball.Free (p); + } + + + + + + + + ADTree3Div :: ADTree3Div (const float * acmin, + const float * acmax) + : ela(0) + { + memcpy (cmin, acmin, 3 * sizeof(float)); + memcpy (cmax, acmax, 3 * sizeof(float)); + + root = new ADTreeNode3Div; + + root->minx = cmin[0]; + root->dist = (cmax[0] - cmin[0]) / ADTN_DIV; + + // root->sep = (cmin[0] + cmax[0]) / 2; + } + + ADTree3Div :: ~ADTree3Div () + { + root->DeleteChilds(); + delete root; + } + + + void ADTree3Div :: Insert (const float * p, int pi) + { + ADTreeNode3Div *node; + ADTreeNode3Div *next; + int dir; + int bag; + + float bmin[3]; + float bmax[3]; + + memcpy (bmin, cmin, 3 * sizeof(float)); + memcpy (bmax, cmax, 3 * sizeof(float)); + + + next = root; + dir = 0; + while (next) + { + node = next; + + if (!node->pi) + { + memcpy (node->data, p, 3 * sizeof(float)); + node->pi = pi; + + if (ela.Size() < pi) + ela.SetSize (pi); + ela.Elem(pi) = node; + + return; + } + + double dx = (bmax[dir] - bmin[dir]) / ADTN_DIV; + bag = int ((p[dir]-bmin[dir]) / dx); + + // (*testout) << "insert, bag = " << bag << endl; + + if (bag < 0) bag = 0; + if (bag >= ADTN_DIV) bag = ADTN_DIV-1; + + double nbmin = bmin[dir] + bag * dx; + double nbmax = bmin[dir] + (bag+1) * dx; + + /* + (*testout) << "bmin, max = " << bmin[dir] << "-" << bmax[dir] + << " p = " << p[dir]; + */ + next = node->childs[bag]; + bmin[dir] = nbmin; + bmax[dir] = nbmax; + + // (*testout) << "new bmin, max = " << bmin[dir] << "-" << bmax[dir] << endl; + + + /* + if (node->sep > p[dir]) + { + next = node->left; + bmax[dir] = node->sep; + lr = 0; + } + else + { + next = node->right; + bmin[dir] = node->sep; + lr = 1; + } + */ + + dir++; + if (dir == 3) + dir = 0; + } + + + next = new ADTreeNode3Div; + memcpy (next->data, p, 3 * sizeof(float)); + next->pi = pi; + + next->minx = bmin[dir]; + next->dist = (bmax[dir] - bmin[dir]) / ADTN_DIV; + // next->sep = (bmin[dir] + bmax[dir]) / 2; + + + if (ela.Size() < pi) + ela.SetSize (pi); + ela.Elem(pi) = next; + + node->childs[bag] = next; + next -> father = node; + + while (node) + { + node->nchilds++; + node = node->father; + } + } + + void ADTree3Div :: DeleteElement (int pi) + { + ADTreeNode3Div * node = ela.Get(pi); + + node->pi = 0; + + node = node->father; + while (node) + { + node->nchilds--; + node = node->father; + } + } + + void ADTree3Div :: GetIntersecting (const float * bmin, + const float * bmax, + ARRAY<int> & pis) const + { + static ARRAY<ADTreeNode3Div*> stack(1000); + static ARRAY<int> stackdir(1000); + ADTreeNode3Div * node; + int dir, i, stacks; + + stack.SetSize (1000); + stackdir.SetSize(1000); + pis.SetSize(0); + + stack.Elem(1) = root; + stackdir.Elem(1) = 0; + stacks = 1; + + while (stacks) + { + node = stack.Get(stacks); + dir = stackdir.Get(stacks); + stacks--; + + if (node->pi) + { + if (node->data[0] >= bmin[0] && node->data[0] <= bmax[0] && + node->data[1] >= bmin[1] && node->data[1] <= bmax[1] && + node->data[2] >= bmin[2] && node->data[2] <= bmax[2]) + + pis.Append (node->pi); + } + + + int ndir = dir+1; + if (ndir == 3) + ndir = 0; + + int mini = int ( (bmin[dir] - node->minx) / node->dist ); + int maxi = int ( (bmax[dir] - node->minx) / node->dist ); + + // (*testout) << "get int, mini, maxi = " << mini << ", " << maxi << endl; + if (mini < 0) mini = 0; + if (maxi >= ADTN_DIV) maxi = ADTN_DIV-1; + + for (i = mini; i <= maxi; i++) + if (node->childs[i]) + { + stacks++; + stack.Elem(stacks) = node->childs[i]; + stackdir.Elem(stacks) = ndir; + } + + + /* + if (node->left && bmin[dir] <= node->sep) + { + stacks++; + stack.Elem(stacks) = node->left; + stackdir.Elem(stacks) = ndir; + } + if (node->right && bmax[dir] >= node->sep) + { + stacks++; + stack.Elem(stacks) = node->right; + stackdir.Elem(stacks) = ndir; + } + */ + } + } + + void ADTree3Div :: PrintRec (ostream & ost, const ADTreeNode3Div * node) const + { + + if (node->data) + { + ost << node->pi << ": "; + ost << node->nchilds << " childs, "; + ost << " from " << node->minx << " - " << node->minx + node->dist*ADTN_DIV << " "; + for (int i = 0; i < 3; i++) + ost << node->data[i] << " "; + ost << endl; + } + int i; + for (i = 0; i < ADTN_DIV; i++) + if (node->childs[i]) + PrintRec (ost, node->childs[i]); + } + + + + + + + + + + + + + /* ******************************* ADTree3M ******************************* */ + + + ADTreeNode3M :: ADTreeNode3M() + { + int i; + for (i = 0; i < ADTN_SIZE; i++) + pi[i] = 0; + + left = NULL; + right = NULL; + father = NULL; + nchilds = 0; + } + + void ADTreeNode3M :: DeleteChilds () + { + if (left) + { + left->DeleteChilds(); + delete left; + left = NULL; + } + if (right) + { + right->DeleteChilds(); + delete right; + right = NULL; + } + } + + + BlockAllocator ADTreeNode3M :: ball(sizeof (ADTreeNode3M)); + + void * ADTreeNode3M :: operator new(size_t) + { + return ball.Alloc(); + } + + void ADTreeNode3M :: operator delete (void * p) + { + ball.Free (p); + } + + + + + + + + ADTree3M :: ADTree3M (const float * acmin, + const float * acmax) + : ela(0) + { + memcpy (cmin, acmin, 3 * sizeof(float)); + memcpy (cmax, acmax, 3 * sizeof(float)); + + root = new ADTreeNode3M; + root->sep = (cmin[0] + cmax[0]) / 2; + } + + ADTree3M :: ~ADTree3M () + { + root->DeleteChilds(); + delete root; + } + + + void ADTree3M :: Insert (const float * p, int pi) + { + ADTreeNode3M *node; + ADTreeNode3M *next; + int dir; + int lr; + int i; + float bmin[3]; + float bmax[3]; + + memcpy (bmin, cmin, 3 * sizeof(float)); + memcpy (bmax, cmax, 3 * sizeof(float)); + + next = root; + dir = 0; + while (next) + { + node = next; + + for (i = 0; i < ADTN_SIZE; i++) + if (!node->pi[i]) + { + memcpy (node->data[i], p, 3 * sizeof(float)); + node->pi[i] = pi; + + if (ela.Size() < pi) + ela.SetSize (pi); + ela.Elem(pi) = node; + + return; + } + + if (node->sep > p[dir]) + { + next = node->left; + bmax[dir] = node->sep; + lr = 0; + } + else + { + next = node->right; + bmin[dir] = node->sep; + lr = 1; + } + + dir++; + if (dir == 3) + dir = 0; + } + + + next = new ADTreeNode3M; + memcpy (next->data[0], p, 3 * sizeof(float)); + next->pi[0] = pi; + next->sep = (bmin[dir] + bmax[dir]) / 2; + + + if (ela.Size() < pi) + ela.SetSize (pi); + ela.Elem(pi) = next; + + + if (lr) + node->right = next; + else + node->left = next; + next -> father = node; + + while (node) + { + node->nchilds++; + node = node->father; + } + } + + void ADTree3M :: DeleteElement (int pi) + { + ADTreeNode3M * node = ela.Get(pi); + + int i; + for (i = 0; i < ADTN_SIZE; i++) + if (node->pi[i] == pi) + node->pi[i] = 0; + + node = node->father; + while (node) + { + node->nchilds--; + node = node->father; + } + } + + void ADTree3M :: GetIntersecting (const float * bmin, + const float * bmax, + ARRAY<int> & pis) const + { + static ARRAY<ADTreeNode3M*> stack(1000); + static ARRAY<int> stackdir(1000); + ADTreeNode3M * node; + int dir, i, stacks; + + stack.SetSize (1000); + stackdir.SetSize(1000); + pis.SetSize(0); + + stack.Elem(1) = root; + stackdir.Elem(1) = 0; + stacks = 1; + + while (stacks) + { + node = stack.Get(stacks); + dir = stackdir.Get(stacks); + stacks--; + + int * hpi = node->pi; + for (i = 0; i < ADTN_SIZE; i++) + if (hpi[i]) + { + float * datai = &node->data[i][0]; + if (datai[0] >= bmin[0] && datai[0] <= bmax[0] && + datai[1] >= bmin[1] && datai[1] <= bmax[1] && + datai[2] >= bmin[2] && datai[2] <= bmax[2]) + + pis.Append (node->pi[i]); + } + + + int ndir = dir+1; + if (ndir == 3) + ndir = 0; + + if (node->left && bmin[dir] <= node->sep) + { + stacks++; + stack.Elem(stacks) = node->left; + stackdir.Elem(stacks) = ndir; + } + if (node->right && bmax[dir] >= node->sep) + { + stacks++; + stack.Elem(stacks) = node->right; + stackdir.Elem(stacks) = ndir; + } + } + } + + void ADTree3M :: PrintRec (ostream & ost, const ADTreeNode3M * node) const + { + + if (node->data) + { + // ost << node->pi << ": "; + ost << node->nchilds << " childs, "; + for (int i = 0; i < 3; i++) + ost << node->data[i] << " "; + ost << endl; + } + if (node->left) + PrintRec (ost, node->left); + if (node->right) + PrintRec (ost, node->right); + } + + + + + + + + + + + + + /* ******************************* ADTree3F ******************************* */ + + + ADTreeNode3F :: ADTreeNode3F() + { + pi = 0; + father = NULL; + nchilds = 0; + int i; + for (i = 0; i < 8; i++) + childs[i] = NULL; + } + + void ADTreeNode3F :: DeleteChilds () + { + int i; + + for (i = 0; i < 8; i++) + { + if (childs[i]) + childs[i]->DeleteChilds(); + delete childs[i]; + childs[i] = NULL; + } + } + + + BlockAllocator ADTreeNode3F :: ball(sizeof (ADTreeNode3F)); + + void * ADTreeNode3F :: operator new(size_t) + { + return ball.Alloc(); + } + + void ADTreeNode3F :: operator delete (void * p) + { + ball.Free (p); + } + + + + + + + + ADTree3F :: ADTree3F (const float * acmin, + const float * acmax) + : ela(0) + { + memcpy (cmin, acmin, 3 * sizeof(float)); + memcpy (cmax, acmax, 3 * sizeof(float)); + + root = new ADTreeNode3F; + for (int i = 0; i < 3; i++) + root->sep[i] = (cmin[i] + cmax[i]) / 2; + } + + ADTree3F :: ~ADTree3F () + { + root->DeleteChilds(); + delete root; + } + + + void ADTree3F :: Insert (const float * p, int pi) + { + ADTreeNode3F *node; + ADTreeNode3F *next; + int lr; + + float bmin[3]; + float bmax[3]; + int i, dir; + + memcpy (bmin, cmin, 3 * sizeof(float)); + memcpy (bmax, cmax, 3 * sizeof(float)); + + + next = root; + while (next) + { + node = next; + + if (!node->pi) + { + memcpy (node->data, p, 3 * sizeof(float)); + node->pi = pi; + + if (ela.Size() < pi) + ela.SetSize (pi); + ela.Elem(pi) = node; + + return; + } + + dir = 0; + for (i = 0; i < 3; i++) + { + if (node->sep[i] > p[i]) + { + bmax[i] = node->sep[i]; + } + else + { + bmin[i] = node->sep[i]; + dir += (1 << i); + } + } + next = node->childs[dir]; + + /* + if (node->sep > p[dir]) + { + next = node->left; + bmax[dir] = node->sep; + lr = 0; + } + else + { + next = node->right; + bmin[dir] = node->sep; + lr = 1; + } + */ + } + + + next = new ADTreeNode3F; + memcpy (next->data, p, 3 * sizeof(float)); + next->pi = pi; + + for (i = 0; i < 3; i++) + next->sep[i] = (bmin[i] + bmax[i]) / 2; + + + if (ela.Size() < pi) + ela.SetSize (pi); + ela.Elem(pi) = next; + + node->childs[dir] = next; + next->father = node; + + while (node) + { + node->nchilds++; + node = node->father; + } + } + + void ADTree3F :: DeleteElement (int pi) + { + ADTreeNode3F * node = ela.Get(pi); + + node->pi = 0; + + node = node->father; + while (node) + { + node->nchilds--; + node = node->father; + } + } + + void ADTree3F :: GetIntersecting (const float * bmin, + const float * bmax, + ARRAY<int> & pis) const + { + static ARRAY<ADTreeNode3F*> stack(1000); + ADTreeNode3F * node; + int dir, i, stacks; + + stack.SetSize (1000); + pis.SetSize(0); + + stack.Elem(1) = root; + stacks = 1; + + while (stacks) + { + node = stack.Get(stacks); + stacks--; + + if (node->pi) + { + if (node->data[0] >= bmin[0] && node->data[0] <= bmax[0] && + node->data[1] >= bmin[1] && node->data[1] <= bmax[1] && + node->data[2] >= bmin[2] && node->data[2] <= bmax[2]) + + pis.Append (node->pi); + } + + + int i1min = (bmin[0] <= node->sep[0]) ? 0 : 1; + int i1max = (bmax[0] < node->sep[0]) ? 0 : 1; + int i2min = (bmin[1] <= node->sep[1]) ? 0 : 1; + int i2max = (bmax[1] < node->sep[1]) ? 0 : 1; + int i3min = (bmin[2] <= node->sep[2]) ? 0 : 1; + int i3max = (bmax[2] < node->sep[2]) ? 0 : 1; + + int i1, i2, i3; + for (i1 = i1min; i1 <= i1max; i1++) + for (i2 = i2min; i2 <= i2max; i2++) + for (i3 = i3min; i3 <= i3max; i3++) + { + i = i1+2*i2+4*i3; + if (node->childs[i]) + { + stacks++; + stack.Elem(stacks) = node->childs[i]; + } + } + + /* + if (node->left && bmin[dir] <= node->sep) + { + stacks++; + stack.Elem(stacks) = node->left; + stackdir.Elem(stacks) = ndir; + } + if (node->right && bmax[dir] >= node->sep) + { + stacks++; + stack.Elem(stacks) = node->right; + stackdir.Elem(stacks) = ndir; + } + */ + } + } + + void ADTree3F :: PrintRec (ostream & ost, const ADTreeNode3F * node) const + { + int i; + if (node->data) + { + ost << node->pi << ": "; + ost << node->nchilds << " childs, "; + for (i = 0; i < 3; i++) + ost << node->data[i] << " "; + ost << endl; + } + + for (i = 0; i < 8; i++) + if (node->childs[i]) + PrintRec (ost, node->childs[i]); + } + + + + + + + + + + + + + + /* ******************************* ADTree3FM ******************************* */ + + + ADTreeNode3FM :: ADTreeNode3FM() + { + father = NULL; + nchilds = 0; + int i; + + for (i = 0; i < ADTN_SIZE; i++) + pi[i] = 0; + + for (i = 0; i < 8; i++) + childs[i] = NULL; + } + + void ADTreeNode3FM :: DeleteChilds () + { + int i; + + for (i = 0; i < 8; i++) + { + if (childs[i]) + childs[i]->DeleteChilds(); + delete childs[i]; + childs[i] = NULL; + } + } + + + BlockAllocator ADTreeNode3FM :: ball(sizeof (ADTreeNode3FM)); + + void * ADTreeNode3FM :: operator new(size_t) + { + return ball.Alloc(); + } + + void ADTreeNode3FM :: operator delete (void * p) + { + ball.Free (p); + } + + + + + + + + ADTree3FM :: ADTree3FM (const float * acmin, + const float * acmax) + : ela(0) + { + memcpy (cmin, acmin, 3 * sizeof(float)); + memcpy (cmax, acmax, 3 * sizeof(float)); + + root = new ADTreeNode3FM; + for (int i = 0; i < 3; i++) + root->sep[i] = (cmin[i] + cmax[i]) / 2; + } + + ADTree3FM :: ~ADTree3FM () + { + root->DeleteChilds(); + delete root; + } + + + void ADTree3FM :: Insert (const float * p, int pi) + { + ADTreeNode3FM *node; + ADTreeNode3FM *next; + int lr; + + float bmin[3]; + float bmax[3]; + int i, dir; + + memcpy (bmin, cmin, 3 * sizeof(float)); + memcpy (bmax, cmax, 3 * sizeof(float)); + + next = root; + while (next) + { + node = next; + + for (i = 0; i < ADTN_SIZE; i++) + if (!node->pi[i]) + { + memcpy (node->data[i], p, 3 * sizeof(float)); + node->pi[i] = pi; + + if (ela.Size() < pi) + ela.SetSize (pi); + ela.Elem(pi) = node; + + return; + } + + dir = 0; + for (i = 0; i < 3; i++) + { + if (node->sep[i] > p[i]) + { + bmax[i] = node->sep[i]; + } + else + { + bmin[i] = node->sep[i]; + dir += (1 << i); + } + } + next = node->childs[dir]; + + /* + if (node->sep > p[dir]) + { + next = node->left; + bmax[dir] = node->sep; + lr = 0; + } + else + { + next = node->right; + bmin[dir] = node->sep; + lr = 1; + } + */ + } + + + next = new ADTreeNode3FM; + memcpy (next->data[0], p, 3 * sizeof(float)); + next->pi[0] = pi; + + for (i = 0; i < 3; i++) + next->sep[i] = (bmin[i] + bmax[i]) / 2; + + + if (ela.Size() < pi) + ela.SetSize (pi); + ela.Elem(pi) = next; + + node->childs[dir] = next; + next->father = node; + + while (node) + { + node->nchilds++; + node = node->father; + } + } + + void ADTree3FM :: DeleteElement (int pi) + { + ADTreeNode3FM * node = ela.Get(pi); + + int i; + for (i = 0; i < ADTN_SIZE; i++) + if (node->pi[i] == pi) + node->pi[i] = 0; + + node = node->father; + while (node) + { + node->nchilds--; + node = node->father; + } + } + + void ADTree3FM :: GetIntersecting (const float * bmin, + const float * bmax, + ARRAY<int> & pis) const + { + static ARRAY<ADTreeNode3FM*> stack(1000); + ADTreeNode3FM * node; + int dir, i, stacks; + + stack.SetSize (1000); + pis.SetSize(0); + + stack.Elem(1) = root; + stacks = 1; + + while (stacks) + { + node = stack.Get(stacks); + stacks--; + + int * hpi = node->pi; + for (i = 0; i < ADTN_SIZE; i++) + if (hpi[i]) + { + float * datai = &node->data[i][0]; + if (datai[0] >= bmin[0] && datai[0] <= bmax[0] && + datai[1] >= bmin[1] && datai[1] <= bmax[1] && + datai[2] >= bmin[2] && datai[2] <= bmax[2]) + + pis.Append (node->pi[i]); + } + + /* + if (node->pi) + { + if (node->data[0] >= bmin[0] && node->data[0] <= bmax[0] && + node->data[1] >= bmin[1] && node->data[1] <= bmax[1] && + node->data[2] >= bmin[2] && node->data[2] <= bmax[2]) + + pis.Append (node->pi); + } + */ + + int i1min = (bmin[0] <= node->sep[0]) ? 0 : 1; + int i1max = (bmax[0] < node->sep[0]) ? 0 : 1; + int i2min = (bmin[1] <= node->sep[1]) ? 0 : 1; + int i2max = (bmax[1] < node->sep[1]) ? 0 : 1; + int i3min = (bmin[2] <= node->sep[2]) ? 0 : 1; + int i3max = (bmax[2] < node->sep[2]) ? 0 : 1; + + int i1, i2, i3; + for (i1 = i1min; i1 <= i1max; i1++) + for (i2 = i2min; i2 <= i2max; i2++) + for (i3 = i3min; i3 <= i3max; i3++) + { + i = i1+2*i2+4*i3; + if (node->childs[i]) + { + stacks++; + stack.Elem(stacks) = node->childs[i]; + } + } + + /* + if (node->left && bmin[dir] <= node->sep) + { + stacks++; + stack.Elem(stacks) = node->left; + stackdir.Elem(stacks) = ndir; + } + if (node->right && bmax[dir] >= node->sep) + { + stacks++; + stack.Elem(stacks) = node->right; + stackdir.Elem(stacks) = ndir; + } + */ + } + } + + void ADTree3FM :: PrintRec (ostream & ost, const ADTreeNode3FM * node) const + { + int i; + if (node->data) + { + ost << node->pi << ": "; + ost << node->nchilds << " childs, "; + for (i = 0; i < 3; i++) + ost << node->data[i] << " "; + ost << endl; + } + + for (i = 0; i < 8; i++) + if (node->childs[i]) + PrintRec (ost, node->childs[i]); + } + + + + +#endif + + + + + + + /* ******************************* ADTree6 ******************************* */ + + + ADTreeNode6 :: ADTreeNode6() + { + pi = -1; + + left = NULL; + right = NULL; + father = NULL; + nchilds = 0; + } + + void ADTreeNode6 :: DeleteChilds () + { + if (left) + { + left->DeleteChilds(); + delete left; + left = NULL; + } + if (right) + { + right->DeleteChilds(); + delete right; + right = NULL; + } + } + + + BlockAllocator ADTreeNode6 :: ball (sizeof (ADTreeNode6)); + void * ADTreeNode6 :: operator new(size_t) + { + return ball.Alloc(); + } + + void ADTreeNode6 :: operator delete (void * p) + { + ball.Free (p); + } + + + + + + ADTree6 :: ADTree6 (const float * acmin, + const float * acmax) + : ela(0) + { + memcpy (cmin, acmin, 6 * sizeof(float)); + memcpy (cmax, acmax, 6 * sizeof(float)); + + root = new ADTreeNode6; + root->sep = (cmin[0] + cmax[0]) / 2; + } + + ADTree6 :: ~ADTree6 () + { + root->DeleteChilds(); + delete root; + } + + void ADTree6 :: Insert (const float * p, int pi) + { + ADTreeNode6 *node; + ADTreeNode6 *next; + int dir; + int lr; + + float bmin[6]; + float bmax[6]; + + + memcpy (bmin, cmin, 6 * sizeof(float)); + memcpy (bmax, cmax, 6 * sizeof(float)); + + next = root; + dir = 0; + while (next) + { + node = next; + + if (node->pi == -1) + { + memcpy (node->data, p, 6 * sizeof(float)); + node->pi = pi; + + if (ela.Size() < pi+1) + ela.SetSize (pi+1); + ela[pi] = node; + + return; + } + + if (node->sep > p[dir]) + { + next = node->left; + bmax[dir] = node->sep; + lr = 0; + } + else + { + next = node->right; + bmin[dir] = node->sep; + lr = 1; + } + + dir++; + if (dir == 6) + dir = 0; + } + + + next = new ADTreeNode6; + memcpy (next->data, p, 6 * sizeof(float)); + next->pi = pi; + next->sep = (bmin[dir] + bmax[dir]) / 2; + + + if (ela.Size() < pi+1) + ela.SetSize (pi+1); + ela[pi] = next; + + + if (lr) + node->right = next; + else + node->left = next; + next -> father = node; + + while (node) + { + node->nchilds++; + node = node->father; + } + } + + void ADTree6 :: DeleteElement (int pi) + { + ADTreeNode6 * node = ela[pi]; + + node->pi = -1; + + node = node->father; + while (node) + { + node->nchilds--; + node = node->father; + } + } + + void ADTree6 :: PrintMemInfo (ostream & ost) const + { + ost << Elements() << " elements a " << sizeof(ADTreeNode6) + << " Bytes = " + << Elements() * sizeof(ADTreeNode6) << endl; + ost << "maxind = " << ela.Size() << " = " << sizeof(ADTreeNode6*) * ela.Size() << " Bytes" << endl; + } + + + + class inttn6 { + public: + int dir; + ADTreeNode6 * node; + }; + + + + + void ADTree6 :: GetIntersecting (const float * bmin, + const float * bmax, + ARRAY<int> & pis) const + { + static ARRAY<inttn6> stack(10000); + ADTreeNode6 * node; + int dir, stacks; + + stack.SetSize (10000); + pis.SetSize(0); + + stack.Elem(1).node = root; + stack.Elem(1).dir = 0; + stacks = 1; + + while (stacks) + { + node = stack.Get(stacks).node; + dir = stack.Get(stacks).dir; + stacks--; + + if (node->pi != -1) + { + + // int in = 1; + // for (i = 0; i < 3; i++) + // if (/* node->data[i] < bmin[i] || */ node->data[i] > bmax[i] || + // node->data[i+3] < bmin[i+3] /* || node->data[i+3] > bmax[i+3] */ ) + // { + // in = 0; + // break; + // } + + // if (in) + // pis.Append (node->pi); + + if (node->data[0] > bmax[0] || + node->data[1] > bmax[1] || + node->data[2] > bmax[2] || + node->data[3] < bmin[3] || + node->data[4] < bmin[4] || + node->data[5] < bmin[5]) + ; + else + pis.Append (node->pi); + } + + + int ndir = dir+1; + if (ndir == 6) + ndir = 0; + + if (node->left && bmin[dir] <= node->sep) + { + stacks++; + stack.Elem(stacks).node = node->left; + stack.Elem(stacks).dir = ndir; + } + if (node->right && bmax[dir] >= node->sep) + { + stacks++; + stack.Elem(stacks).node = node->right; + stack.Elem(stacks).dir = ndir; + } + } + } + + /* + void ADTree6 :: GetIntersecting (const float * bmin, + const float * bmax, + ARRAY<int> & pis) const + { + static ARRAY<ADTreeNode6*> stack(10000); + static ARRAY<int> stackdir(10000); + ADTreeNode6 * node; + int dir, stacks; + + stack.SetSize (10000); + stackdir.SetSize(10000); + pis.SetSize(0); + + stack.Elem(1) = root; + stackdir.Elem(1) = 0; + stacks = 1; + + while (stacks) + { + node = stack.Get(stacks); + dir = stackdir.Get(stacks); + stacks--; + + if (node->pi) + { + + if (node->data[0] > bmax[0] || + node->data[1] > bmax[1] || + node->data[2] > bmax[2] || + node->data[3] < bmin[3] || + node->data[4] < bmin[4] || + node->data[5] < bmin[5]) + ; + else + pis.Append (node->pi); + } + + + int ndir = dir+1; + if (ndir == 6) + ndir = 0; + + if (node->left && bmin[dir] <= node->sep) + { + stacks++; + stack.Elem(stacks) = node->left; + stackdir.Elem(stacks) = ndir; + } + if (node->right && bmax[dir] >= node->sep) + { + stacks++; + stack.Elem(stacks) = node->right; + stackdir.Elem(stacks) = ndir; + } + } + } + */ + + + void ADTree6 :: PrintRec (ostream & ost, const ADTreeNode6 * node) const + { + + if (node->data) + { + ost << node->pi << ": "; + ost << node->nchilds << " childs, "; + for (int i = 0; i < 6; i++) + ost << node->data[i] << " "; + ost << endl; + } + if (node->left) + PrintRec (ost, node->left); + if (node->right) + PrintRec (ost, node->right); + } + + + int ADTree6 :: DepthRec (const ADTreeNode6 * node) const + { + int ldepth = 0; + int rdepth = 0; + + if (node->left) + ldepth = DepthRec(node->left); + if (node->right) + rdepth = DepthRec(node->right); + return 1 + max2 (ldepth, rdepth); + } + + int ADTree6 :: ElementsRec (const ADTreeNode6 * node) const + { + int els = 1; + if (node->left) + els += ElementsRec(node->left); + if (node->right) + els += ElementsRec(node->right); + return els; + } + + + + + + +#ifdef ABC + + /* ******************************* ADTree6F ******************************* */ + + + ADTreeNode6F :: ADTreeNode6F() + { + pi = 0; + father = NULL; + nchilds = 0; + int i; + for (i = 0; i < 64; i++) + childs[i] = NULL; + } + + void ADTreeNode6F :: DeleteChilds () + { + int i; + + for (i = 0; i < 64; i++) + { + if (childs[i]) + childs[i]->DeleteChilds(); + delete childs[i]; + childs[i] = NULL; + } + } + + + BlockAllocator ADTreeNode6F :: ball(sizeof (ADTreeNode6F)); + + void * ADTreeNode6F :: operator new(size_t) + { + return ball.Alloc(); + } + + void ADTreeNode6F :: operator delete (void * p) + { + ball.Free (p); + } + + + + + + + + ADTree6F :: ADTree6F (const float * acmin, + const float * acmax) + : ela(0) + { + memcpy (cmin, acmin, 6 * sizeof(float)); + memcpy (cmax, acmax, 6 * sizeof(float)); + + root = new ADTreeNode6F; + for (int i = 0; i < 6; i++) + root->sep[i] = (cmin[i] + cmax[i]) / 2; + } + + ADTree6F :: ~ADTree6F () + { + root->DeleteChilds(); + delete root; + } + + + void ADTree6F :: Insert (const float * p, int pi) + { + ADTreeNode6F *node; + ADTreeNode6F *next; + int lr; + + float bmin[6]; + float bmax[6]; + int i, dir; + + memcpy (bmin, cmin, 6 * sizeof(float)); + memcpy (bmax, cmax, 6 * sizeof(float)); + + next = root; + while (next) + { + node = next; + + if (!node->pi) + { + memcpy (node->data, p, 6 * sizeof(float)); + node->pi = pi; + + if (ela.Size() < pi) + ela.SetSize (pi); + ela.Elem(pi) = node; + + return; + } + + dir = 0; + for (i = 0; i < 6; i++) + { + if (node->sep[i] > p[i]) + { + bmax[i] = node->sep[i]; + } + else + { + bmin[i] = node->sep[i]; + dir += (1 << i); + } + } + next = node->childs[dir]; + + /* + if (node->sep > p[dir]) + { + next = node->left; + bmax[dir] = node->sep; + lr = 0; + } + else + { + next = node->right; + bmin[dir] = node->sep; + lr = 1; + } + */ + } + + + next = new ADTreeNode6F; + memcpy (next->data, p, 6 * sizeof(float)); + next->pi = pi; + + for (i = 0; i < 6; i++) + next->sep[i] = (bmin[i] + bmax[i]) / 2; + + + if (ela.Size() < pi) + ela.SetSize (pi); + ela.Elem(pi) = next; + + node->childs[dir] = next; + next->father = node; + + while (node) + { + node->nchilds++; + node = node->father; + } + } + + void ADTree6F :: DeleteElement (int pi) + { + ADTreeNode6F * node = ela.Get(pi); + + node->pi = 0; + + node = node->father; + while (node) + { + node->nchilds--; + node = node->father; + } + } + + void ADTree6F :: GetIntersecting (const float * bmin, + const float * bmax, + ARRAY<int> & pis) const + { + static ARRAY<ADTreeNode6F*> stack(1000); + ADTreeNode6F * node; + int dir, i, stacks; + + stack.SetSize (1000); + pis.SetSize(0); + + stack.Elem(1) = root; + stacks = 1; + + while (stacks) + { + node = stack.Get(stacks); + stacks--; + + if (node->pi) + { + if ( + node->data[0] >= bmin[0] && node->data[0] <= bmax[0] && + node->data[1] >= bmin[1] && node->data[1] <= bmax[1] && + node->data[2] >= bmin[2] && node->data[2] <= bmax[2] && + node->data[3] >= bmin[3] && node->data[3] <= bmax[3] && + node->data[4] >= bmin[4] && node->data[4] <= bmax[4] && + node->data[5] >= bmin[5] && node->data[5] <= bmax[5] + ) + + pis.Append (node->pi); + } + + + int i1min = (bmin[0] <= node->sep[0]) ? 0 : 1; + int i1max = (bmax[0] < node->sep[0]) ? 0 : 1; + int i2min = (bmin[1] <= node->sep[1]) ? 0 : 1; + int i2max = (bmax[1] < node->sep[1]) ? 0 : 1; + int i3min = (bmin[2] <= node->sep[2]) ? 0 : 1; + int i3max = (bmax[2] < node->sep[2]) ? 0 : 1; + + int i4min = (bmin[3] <= node->sep[3]) ? 0 : 1; + int i4max = (bmax[3] < node->sep[3]) ? 0 : 1; + int i5min = (bmin[4] <= node->sep[4]) ? 0 : 1; + int i5max = (bmax[4] < node->sep[4]) ? 0 : 1; + int i6min = (bmin[5] <= node->sep[5]) ? 0 : 1; + int i6max = (bmax[5] < node->sep[5]) ? 0 : 1; + + int i1, i2, i3, i4, i5, i6; + for (i1 = i1min; i1 <= i1max; i1++) + for (i2 = i2min; i2 <= i2max; i2++) + for (i3 = i3min; i3 <= i3max; i3++) + for (i4 = i4min; i4 <= i4max; i4++) + for (i5 = i5min; i5 <= i5max; i5++) + for (i6 = i6min; i6 <= i6max; i6++) + { + i = i1 + 2*i2 + 4*i3 + 8*i4 + 16*i5 +32*i6; + if (node->childs[i]) + { + stacks++; + stack.Elem(stacks) = node->childs[i]; + } + } + + /* + if (node->left && bmin[dir] <= node->sep) + { + stacks++; + stack.Elem(stacks) = node->left; + stackdir.Elem(stacks) = ndir; + } + if (node->right && bmax[dir] >= node->sep) + { + stacks++; + stack.Elem(stacks) = node->right; + stackdir.Elem(stacks) = ndir; + } + */ + } + } + + void ADTree6F :: PrintRec (ostream & ost, const ADTreeNode6F * node) const + { + int i; + if (node->data) + { + ost << node->pi << ": "; + ost << node->nchilds << " childs, "; + for (i = 0; i < 6; i++) + ost << node->data[i] << " "; + ost << endl; + } + + for (i = 0; i < 64; i++) + if (node->childs[i]) + PrintRec (ost, node->childs[i]); + } + + + +#endif + + + + /* ************************************* Point3dTree ********************** */ + + + + Point3dTree :: Point3dTree (const Point3d & pmin, const Point3d & pmax) + { + float pmi[3], pma[3]; + for (int i = 0; i < 3; i++) + { + pmi[i] = pmin.X(i+1); + pma[i] = pmax.X(i+1); + } + tree = new ADTree3 (pmi, pma); + } + + Point3dTree :: ~Point3dTree () + { + delete tree; + } + + + + void Point3dTree :: Insert (const Point3d & p, int pi) + { + static float pd[3]; + pd[0] = p.X(); + pd[1] = p.Y(); + pd[2] = p.Z(); + tree->Insert (pd, pi); + } + + void Point3dTree :: GetIntersecting (const Point3d & pmin, const Point3d & pmax, + ARRAY<int> & pis) const + { + float pmi[3], pma[3]; + for (int i = 0; i < 3; i++) + { + pmi[i] = pmin.X(i+1); + pma[i] = pmax.X(i+1); + } + tree->GetIntersecting (pmi, pma, pis); + } + + + + + + + + + + + Box3dTree :: Box3dTree (const Point3d & apmin, const Point3d & apmax) + { + boxpmin = apmin; + boxpmax = apmax; + float tpmin[6], tpmax[6]; + for (int i = 0; i < 3; i++) + { + tpmin[i] = tpmin[i+3] = boxpmin.X(i+1); + tpmax[i] = tpmax[i+3] = boxpmax.X(i+1); + } + tree = new ADTree6 (tpmin, tpmax); + } + + Box3dTree :: ~Box3dTree () + { + delete tree; + } + + void Box3dTree :: Insert (const Point3d & bmin, const Point3d & bmax, int pi) + { + static float tp[6]; + + for (int i = 0; i < 3; i++) + { + tp[i] = bmin.X(i+1); + tp[i+3] = bmax.X(i+1); + } + + tree->Insert (tp, pi); + } + + void Box3dTree ::GetIntersecting (const Point3d & pmin, const Point3d & pmax, + ARRAY<int> & pis) const + { + float tpmin[6]; + float tpmax[6]; + + for (int i = 0; i < 3; i++) + { + tpmin[i] = boxpmin.X(i+1); + tpmax[i] = pmax.X(i+1); + + tpmin[i+3] = pmin.X(i+1); + tpmax[i+3] = boxpmax.X(i+1); + } + + tree->GetIntersecting (tpmin, tpmax, pis); + } + +} diff --git a/contrib/Netgen/libsrc/gprim/adtree.hpp b/contrib/Netgen/libsrc/gprim/adtree.hpp new file mode 100644 index 0000000000..64f3509e1a --- /dev/null +++ b/contrib/Netgen/libsrc/gprim/adtree.hpp @@ -0,0 +1,477 @@ +#ifndef FILE_ADTREE +#define FILE_ADTREE + +/* *************************************************************************/ +/* File: adtree.hh */ +/* Author: Joachim Schoeberl */ +/* Date: 16. Feb. 98 */ +/* Redesigned by Wolfram Muehlhuber, May 1998 */ +/* *************************************************************************/ + + + +/** + Alternating Digital Tree + */ + +#include <mystdlib.h> +#include <myadt.hpp> + +class ADTreeNode +{ +public: + ADTreeNode *left, *right, *father; + int dim; + float sep; + float *data; + float *boxmin; + float *boxmax; + int pi; + int nchilds; + + ADTreeNode (int adim); + ~ADTreeNode (); + + friend class ADTree; +}; + + +class ADTreeCriterion +{ +public: + ADTreeCriterion() { } + virtual int Eval (const ADTreeNode * node) const = 0; +}; + + +class ADTree +{ + int dim; + ADTreeNode * root; + float *cmin, *cmax; + ARRAY<ADTreeNode*> ela; + const ADTreeCriterion * criterion; + + ARRAY<ADTreeNode*> stack; + ARRAY<int> stackdir; + int stackindex; + +public: + ADTree (int adim, const float * acmin, + const float * acmax); + ~ADTree (); + + void Insert (const float * p, int pi); + // void GetIntersecting (const float * bmin, const float * bmax, + // ARRAY<int> & pis) const; + void SetCriterion (ADTreeCriterion & acriterion); + void Reset (); + int Next (); + void GetMatch (ARRAY<int> & matches); + + void DeleteElement (int pi); + + + void Print (ostream & ost) const + { PrintRec (ost, root); } + + void PrintRec (ostream & ost, const ADTreeNode * node) const; +}; + + + +class ADTreeNode3 +{ +public: + ADTreeNode3 *left, *right, *father; + float sep; + float data[3]; + int pi; + int nchilds; + + ADTreeNode3 (); + void DeleteChilds (); + friend class ADTree3; + + static BlockAllocator ball; + void * operator new(size_t); + void operator delete (void *); +}; + + +class ADTree3 +{ + ADTreeNode3 * root; + float cmin[3], cmax[3]; + ARRAY<ADTreeNode3*> ela; + +public: + ADTree3 (const float * acmin, + const float * acmax); + ~ADTree3 (); + + void Insert (const float * p, int pi); + void GetIntersecting (const float * bmin, const float * bmax, + ARRAY<int> & pis) const; + + void DeleteElement (int pi); + + + void Print (ostream & ost) const + { PrintRec (ost, root); } + + void PrintRec (ostream & ost, const ADTreeNode3 * node) const; +}; + + +/* + +// divide each direction +#define ADTN_DIV 10 +class ADTreeNode3Div +{ +public: + ADTreeNode3Div *father; + ADTreeNode3Div *childs[ADTN_DIV]; + + float minx, dist; + float data[3]; + int pi; + int nchilds; + + ADTreeNode3Div (); + void DeleteChilds (); + friend class ADTree3Div; + + static BlockAllocator ball; + void * operator new(size_t); + void operator delete (void *); +}; + + +class ADTree3Div +{ + ADTreeNode3Div * root; + float cmin[3], cmax[3]; + ARRAY<ADTreeNode3Div*> ela; + +public: + ADTree3Div (const float * acmin, + const float * acmax); + ~ADTree3Div (); + + void Insert (const float * p, int pi); + void GetIntersecting (const float * bmin, const float * bmax, + ARRAY<int> & pis) const; + + void DeleteElement (int pi); + + + void Print (ostream & ost) const + { PrintRec (ost, root); } + + void PrintRec (ostream & ost, const ADTreeNode3Div * node) const; +}; + + + + +#define ADTN_SIZE 10 + +// multiple entries +class ADTreeNode3M +{ +public: + ADTreeNode3M *left, *right, *father; + float sep; + float data[ADTN_SIZE][3]; + int pi[ADTN_SIZE]; + int nchilds; + + ADTreeNode3M (); + void DeleteChilds (); + friend class ADTree3M; + + static BlockAllocator ball; + void * operator new(size_t); + void operator delete (void *); +}; + + +class ADTree3M +{ + ADTreeNode3M * root; + float cmin[3], cmax[3]; + ARRAY<ADTreeNode3M*> ela; + +public: + ADTree3M (const float * acmin, + const float * acmax); + ~ADTree3M (); + + void Insert (const float * p, int pi); + void GetIntersecting (const float * bmin, const float * bmax, + ARRAY<int> & pis) const; + + void DeleteElement (int pi); + + + void Print (ostream & ost) const + { PrintRec (ost, root); } + + void PrintRec (ostream & ost, const ADTreeNode3M * node) const; +}; + + + + + + +class ADTreeNode3F +{ +public: + ADTreeNode3F *father; + ADTreeNode3F *childs[8]; + float sep[3]; + float data[3]; + int pi; + int nchilds; + + ADTreeNode3F (); + void DeleteChilds (); + friend class ADTree3F; + + static BlockAllocator ball; + void * operator new(size_t); + void operator delete (void *); +}; + +// fat tree +class ADTree3F +{ + ADTreeNode3F * root; + float cmin[3], cmax[3]; + ARRAY<ADTreeNode3F*> ela; + +public: + ADTree3F (const float * acmin, + const float * acmax); + ~ADTree3F (); + + void Insert (const float * p, int pi); + void GetIntersecting (const float * bmin, const float * bmax, + ARRAY<int> & pis) const; + + void DeleteElement (int pi); + + + void Print (ostream & ost) const + { PrintRec (ost, root); } + + void PrintRec (ostream & ost, const ADTreeNode3F * node) const; +}; + + + + +class ADTreeNode3FM +{ +public: + ADTreeNode3FM *father; + ADTreeNode3FM *childs[8]; + float sep[3]; + float data[ADTN_SIZE][3]; + int pi[ADTN_SIZE]; + int nchilds; + + ADTreeNode3FM (); + void DeleteChilds (); + friend class ADTree3FM; + + static BlockAllocator ball; + void * operator new(size_t); + void operator delete (void *); +}; + +// fat tree +class ADTree3FM +{ + ADTreeNode3FM * root; + float cmin[3], cmax[3]; + ARRAY<ADTreeNode3FM*> ela; + +public: + ADTree3FM (const float * acmin, + const float * acmax); + ~ADTree3FM (); + + void Insert (const float * p, int pi); + void GetIntersecting (const float * bmin, const float * bmax, + ARRAY<int> & pis) const; + + void DeleteElement (int pi); + + + void Print (ostream & ost) const + { PrintRec (ost, root); } + + void PrintRec (ostream & ost, const ADTreeNode3FM * node) const; +}; + + + +*/ + + + + + +class ADTreeNode6 +{ +public: + ADTreeNode6 *left, *right, *father; + float sep; + float data[6]; + int pi; + int nchilds; + + ADTreeNode6 (); + void DeleteChilds (); + friend class ADTree6; + + static BlockAllocator ball; + void * operator new(size_t); + void operator delete (void *); +}; + + +class ADTree6 +{ + ADTreeNode6 * root; + float cmin[6], cmax[6]; + ARRAY<ADTreeNode6*> ela; + +public: + ADTree6 (const float * acmin, + const float * acmax); + ~ADTree6 (); + + void Insert (const float * p, int pi); + void GetIntersecting (const float * bmin, const float * bmax, + ARRAY<int> & pis) const; + + void DeleteElement (int pi); + + + void Print (ostream & ost) const + { PrintRec (ost, root); } + int Depth () const + { return DepthRec (root); } + int Elements () const + { return ElementsRec (root); } + + void PrintRec (ostream & ost, const ADTreeNode6 * node) const; + int DepthRec (const ADTreeNode6 * node) const; + int ElementsRec (const ADTreeNode6 * node) const; + + void PrintMemInfo (ostream & ost) const; +}; + + + + +/* + +class ADTreeNode6F +{ +public: + ADTreeNode6F * father; + ADTreeNode6F * childs[64]; + + float sep[6]; + float data[6]; + int pi; + int nchilds; + + ADTreeNode6F (); + void DeleteChilds (); + friend class ADTree6F; + + static BlockAllocator ball; + void * operator new(size_t); + void operator delete (void *); +}; + + +class ADTree6F +{ + ADTreeNode6F * root; + float cmin[6], cmax[6]; + ARRAY<ADTreeNode6F*> ela; + +public: + ADTree6F (const float * acmin, + const float * acmax); + ~ADTree6F (); + + void Insert (const float * p, int pi); + void GetIntersecting (const float * bmin, const float * bmax, + ARRAY<int> & pis) const; + + void DeleteElement (int pi); + + + void Print (ostream & ost) const + { PrintRec (ost, root); } + int Depth () const + { return DepthRec (root); } + + void PrintRec (ostream & ost, const ADTreeNode6F * node) const; + int DepthRec (const ADTreeNode6F * node) const; +}; + + + + + + + +*/ + + + + + +class Point3dTree +{ + ADTree3 * tree; + +public: + Point3dTree (const Point3d & pmin, const Point3d & pmax); + ~Point3dTree (); + void Insert (const Point3d & p, int pi); + void DeleteElement (int pi) + { tree->DeleteElement(pi); } + void GetIntersecting (const Point3d & pmin, const Point3d & pmax, + ARRAY<int> & pis) const; + const ADTree3 & Tree() const { return *tree; }; +}; + + + +class Box3dTree +{ + ADTree6 * tree; + Point3d boxpmin, boxpmax; +public: + Box3dTree (const Point3d & apmin, const Point3d & apmax); + ~Box3dTree (); + void Insert (const Point3d & bmin, const Point3d & bmax, int pi); + void DeleteElement (int pi) + { tree->DeleteElement(pi); } + void GetIntersecting (const Point3d & pmin, const Point3d & pmax, + ARRAY<int> & pis) const; + + const ADTree6 & Tree() const { return *tree; }; +}; +#endif diff --git a/contrib/Netgen/libsrc/gprim/geom2d.cpp b/contrib/Netgen/libsrc/gprim/geom2d.cpp new file mode 100644 index 0000000000..01463d0255 --- /dev/null +++ b/contrib/Netgen/libsrc/gprim/geom2d.cpp @@ -0,0 +1,485 @@ +#include <mystdlib.h> + +#include <myadt.hpp> +#include <gprim.hpp> + +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif + +namespace netgen +{ + +ostream & operator<<(ostream & s, const Point2d & p) +{ + return s << "(" << p.px << ", " << p.py << ")"; +} + +ostream & operator<<(ostream & s, const Vec2d & v) +{ + return s << "(" << v.vx << ", " << v.vy << ")"; +} + +#ifdef none +ostream & operator<<(ostream & s, const Line2d & l) + { + return s << l.p1 << "-" << l.p2; +} + +ostream & operator<<(ostream & s, const TRIANGLE2D & t) +{ + return s << t.p1 << "-" << t.p2 << "-" << t.p3; +} +#endif + + +double Fastatan2 (double x, double y) +{ + if (y > 0) + { + if (x > 0) + return y / (x+y); + else + return 1 - x / (y-x); + } + else if (y < 0) + { + if (x < 0) + return 2 + y / (x+y); + else + return 3 - x / (y-x); + } + else + { + if (x >= 0) + return 0; + else + return 2; + } +} + + +double Angle (const Vec2d & v) +{ + if (v.X() == 0 && v.Y() == 0) return 0; + double ang = atan2 (v.Y(), v.X()); + if (ang < 0) ang+= 2 * M_PI; + return ang; +} + +double FastAngle (const Vec2d & v) +{ + return Fastatan2 (v.X(), v.Y()); +} + +double Angle (const Vec2d & v1, const Vec2d & v2) +{ + double ang = Angle(v2) - Angle(v1); + if (ang < 0) ang += 2 * M_PI; + return ang; +} + +double FastAngle (const Vec2d & v1, const Vec2d & v2) +{ + double ang = FastAngle(v2) - FastAngle(v1); + if (ang < 0) ang += 4; + return ang; +} + +/* +int CW (const Point2d & p1,const Point2d & p2,const Point2d & p3) +{ + return Cross (p2 - p1, p3 - p2) < 0; +} + +int CCW (const Point2d & p1,const Point2d & p2,const Point2d & p3) +{ + return Cross (p2 - p1, p3 - p2) > 0; +} +*/ + +double Dist2(const Line2d & g, const Line2d & h ) + { + double dd = 0.0, d1,d2,d3,d4; + Point2d cp = CrossPoint(g,h); + + if ( Parallel(g,h) || !IsOnLine(g,cp) || !IsOnLine(h,cp) ) + { + d1 = Dist2(g.P1(),h.P1()); + d2 = Dist2(g.P1(),h.P2()); + d3 = Dist2(g.P2(),h.P1()); + d4 = Dist2(g.P2(),h.P2()); + if (d1<d2) d2 = d1; + if (d3<d4) d4 = d3; + dd = ( d2 < d4 ) ? d2 : d4; + } + return dd; +} + + +Point2d CrossPoint (const Line2d & l1, const Line2d & l2) + { + double den = Cross (l1.Delta(), l2.Delta()); + double num = Cross ( (l2.P1() - l1.P1()), l2.Delta()); + + if (den == 0) return l1.P1(); + else + return l1.P1() + (num/den) * l1.Delta(); +} + + +int CrossPointBarycentric (const Line2d & l1, const Line2d & l2, + double & lam1, double & lam2) +{ + // p = l1.1 + lam1 (l1.2-l1.1) = l2.1 + lam2 (l2.2-l2.1) + double a11 = l1.p2.X() - l1.p1.X(); + double a21 = l1.p2.Y() - l1.p1.Y(); + double a12 = -(l2.p2.X() - l2.p1.X()); + double a22 = -(l2.p2.Y() - l2.p1.Y()); + + double b1 = l2.p1.X() - l1.p1.X(); + double b2 = l2.p1.Y() - l1.p1.Y(); + + double det = a11*a22 - a12 * a21; + if (det == 0) return 1; + + lam1 = (a22 * b1 - a12 * b2) / det; + lam2 = (a11 * b2 - a21 * b1) / det; + return 0; +} + + + + +int Parallel (const Line2d & l1, const Line2d & l2, double peps) + { + double p = fabs (Cross (l1.Delta(), l2.Delta())); + // (*mycout) << endl << p << " " << l1.Length() << " " << l2.Length() << endl; + return p <= peps * l1.Length() * l2.Length(); +} + +int IsOnLine (const Line2d & l, const Point2d & p, double heps) + { + double c1 = (p - l.P1()) * l.Delta(); + double c2 = (p - l.P2()) * l.Delta(); + double d = fabs (Cross ( (p - l.P1()), l.Delta())); + double len2 = l.Length2(); + + return c1 >= -heps * len2 && c2 <= heps * len2 && d <= heps * len2; +} + +#ifdef none +int IsOnLine (const PLine2d & l, const Point2d & p, double heps) + { + double c1 = (p - l.P1()) * l.Delta(); + double c2 = (p - l.P2()) * l.Delta(); + double d = fabs (Cross ( (p - l.P1()), l.Delta())); + double len2 = l.Length2(); + + return c1 >= -heps * len2 && c2 <= heps * len2 && d <= heps * len2; +} + +int IsOnLongLine (const Line2d & l, const Point2d & p) + { + double d = fabs (Cross ( (p - l.P1()), l.Delta())); + return d <= EPSGEOM * l.Length(); +} + +int Hit (const Line2d & l1, const Line2d & l2, double heps) + { + double den = Cross ( (l1.P2() - l1.P1()), (l2.P1() - l2.P2())); + double num1 = Cross ( (l2.P1() - l1.P1()), (l2.P1() - l2.P2())); + double num2 = Cross ( (l1.P2() - l1.P1()), (l2.P1() - l1.P1())); + num1 *= sgn (den); + num2 *= sgn (den); + den = fabs (den); + + int ch = (-den * heps <= num1 && num1 <= den * (1 + heps) && + -den * heps <= num2 && num2 <= den * (1 + heps)); + return ch; +} + + +void Line2d :: GetNormal (Line2d & n) const +{ + double ax = P2().X()-P1().X(), + ay = P2().Y()-P1().Y(); + Point2d mid(P1().X()+.5*ax, P1().Y()+.5*ay); + + n=Line2d(mid,Point2d(mid.X()+ay,mid.Y()-ax)) ; +} + +Vec2d Line2d :: NormalDelta () const +{ + Line2d tmp; + GetNormal(tmp); + return tmp.Delta(); +} + +int TRIANGLE2D :: IsOn (const Point2d & p) const + { + return IsOnLine (Line2d (p1, p2), p) || + IsOnLine (Line2d (p1, p3), p) || + IsOnLine (Line2d (p2, p3), p); + } + + +int TRIANGLE2D :: IsIn (const Point2d & p) const +{ + return ::CW(p, p1, p2) == ::CW(p, p2, p3) && + ::CW(p, p1, p2) == ::CW(p, p3, p1); +} + + + +int PTRIANGLE2D :: IsOn (const Point2d & p) const +{ + return IsOnLine (Line2d (*p1, *p2), p) || + IsOnLine (Line2d (*p1, *p3), p) || + IsOnLine (Line2d (*p2, *p3), p); +} + + +int PTRIANGLE2D :: IsIn (const Point2d & p) const +{ + return ::CW(p, *p1, *p2) == ::CW(p, *p2, *p3) && + ::CW(p, *p1, *p2) == ::CW(p, *p3, *p1); +} + +#endif + + + + + + +Polygon2d :: Polygon2d () +{ + ; +} + +Polygon2d :: ~Polygon2d () +{ + ; +} + +void Polygon2d :: AddPoint (const Point2d & p) +{ + points.Append(p); +} + + +double Polygon2d :: HArea () const +{ + int i; + double ar = 0; + for (i = 1; i <= points.Size(); i++) + { + const Point2d & p1 = points.Get(i); + const Point2d & p2 = points.Get(i%points.Size()+1); + ar += + (p2.X()-p1.X()) * p1.Y() - + (p2.Y()-p1.Y()) * p1.X(); + } + return ar/2; + /* + CURSOR c; + double ar = 0; + Point2d * p1, * p2, p0 = Point2d(0, 0); + Vec2d v1, v2 = Vec2d(1, 0); + + p2 = points[points.Last()]; + for (c = points.First(); c != points.Head(); c++) + { + p1 = p2; + p2 = points[c]; + ar += Cross ( (*p2-*p1), (*p1 - p0)); + } + return ar / 2; + */ +} + + +int Polygon2d :: IsOn (const Point2d & p) const +{ + int i; + for (i = 1; i <= points.Size(); i++) + { + const Point2d & p1 = points.Get(i); + const Point2d & p2 = points.Get(i%points.Size()+1); + if (IsOnLine (Line2d(p1, p2), p)) return 1; + } + return 0; + /* + CURSOR c; + Point2d * p1, * p2; + + p2 = points[points.Last()]; + for (c = points.First(); c != points.Head(); c++) + { + p1 = p2; + p2 = points[c]; + if (IsOnLine (Line2d(*p1, *p2), p)) return 1; + } + return 0; + */ +} + + +int Polygon2d :: IsIn (const Point2d & p) const +{ + int i; + double sum = 0, ang; + for (i = 1; i <= points.Size(); i++) + { + const Point2d & p1 = points.Get(i); + const Point2d & p2 = points.Get(i%points.Size()+1); + ang = Angle ( (p1 - p), (p2 - p) ); + if (ang > M_PI) ang -= 2 * M_PI; + sum += ang; + } + return fabs(sum) > M_PI; + /* + CURSOR c; + Point2d * p1, * p2; + double sum = 0, ang; + + p2 = points[points.Last()]; + for (c = points.First(); c != points.Head(); c++) + { + p1 = p2; + p2 = points[c]; + ang = Angle ( (*p1 - p), (*p2 - p) ); + if (ang > M_PI) ang -= 2 * M_PI; + sum += ang; + } + + return fabs(sum) > M_PI; + */ +} + +int Polygon2d :: IsConvex () const + { + /* + Point2d *p, *pold, *pnew; + char cw; + CURSOR c; + + if (points.Length() < 3) return 0; + + c = points.Last(); + p = points[c]; + c--; + pold = points[c]; + pnew = points[points.First()]; + cw = ::CW (*pold, *p, *pnew); + + for (c = points.First(); c != points.Head(); c++) + { + pnew = points[c]; + if (cw != ::CW (*pold, *p, *pnew)) + return 0; + pold = p; + p = pnew; + } + */ + return 0; + } + + +int Polygon2d :: IsStarPoint (const Point2d & p) const + { + /* + Point2d *pnew, *pold; + char cw; + CURSOR c; + + if (points.Length() < 3) return 0; + + pold = points[points.Last()]; + pnew = points[points.First()]; + + cw = ::CW (p, *pold, *pnew); + + for (c = points.First(); c != points.Head(); c++) + { + pnew = points[c]; + if (cw != ::CW (p, *pold, *pnew)) + return 0; + pold = pnew; + } + return 1; + */ + return 0; + } + + +Point2d Polygon2d :: Center () const + { + /* + double ai, a = 0, x = 0, y = 0; + Point2d * p, *p2; + Point2d p0 = Point2d(0, 0); + CURSOR c; + + p2 = points[points.Last()]; + + for (c = points.First(); c != points.Head(); c++) + { + p = points[c]; + ai = Cross (*p2 - p0, *p - p0); + x += ai / 3 * (p2->X() + p->X()); + y += ai / 3 * (p2->Y() + p->Y()); + a+= ai; + p2 = p; + } + if (a != 0) + return Point2d (x / a, y / a); + else + return Point2d (0, 0); + */ + return Point2d (0, 0); + } + + + +Point2d Polygon2d :: EqualAreaPoint () const + { + /* + double a11 = 0, a12 = 0, a21= 0, a22 = 0; + double b1 = 0, b2 = 0, dx, dy; + double det; + Point2d * p, *p2; + CURSOR c; + + p = points[points.Last()]; + + for (c = points.First(); c != points.Head(); c++) + { + p2 = p; + p = points[c]; + + dx = p->X() - p2->X(); + dy = p->Y() - p2->Y(); + + a11 += sqr (dy); + a12 -= dx * dy; + a21 -= dx * dy; + a22 += sqr (dx); + b1 -= dy * (p->X() * p2->Y() - p2->X() * p->Y()); + b2 -= dx * (p->Y() * p2->X() - p2->Y() * p->X()); + } + + det = a11 * a22 - a21 * a12; + + if (det != 0) + return Point2d ( (b1 * a22 - b2 * a12) / det, + (a11 * b2 - a21 * b1) / det); + else + return Point2d (0, 0); +*/ + return Point2d (0, 0); + } + + +} diff --git a/contrib/Netgen/libsrc/gprim/geom2d.hpp b/contrib/Netgen/libsrc/gprim/geom2d.hpp new file mode 100644 index 0000000000..48b5eda71d --- /dev/null +++ b/contrib/Netgen/libsrc/gprim/geom2d.hpp @@ -0,0 +1,870 @@ +#ifndef FILE_GEOM2D +#define FILE_GEOM2D + +/* *************************************************************************/ +/* File: geom2d.hh */ +/* Author: Joachim Schoeberl */ +/* Date: 5. Aug. 95 */ +/* *************************************************************************/ + + + +/* Geometric Algorithms */ + +#define EPSGEOM 1E-5 + + +// extern void MyError (const char * ch); + +class Point2d; +class Vec2d; + +class LINE2D; +class Line2d; +class PLine2d; +class TRIANGLE2D; +class PTRIANGLE2D; + + +inline Vec2d operator- (const Point2d & p1, const Point2d & p2); +inline Point2d operator- (const Point2d & p1, const Vec2d & v); +inline Point2d operator+ (const Point2d & p1, const Vec2d & v); +inline Point2d Center (const Point2d & p1, const Point2d & p2); + +inline void PpSmV (const Point2d & p1, double s, const Vec2d & v, Point2d & p2); +inline void PmP (const Point2d & p1, const Point2d & p2, Vec2d & v); +ostream & operator<<(ostream & s, const Point2d & p); +inline Vec2d operator- (const Point2d & p1, const Point2d & p2); +inline Point2d operator- (const Point2d & p1, const Vec2d & v); +inline Point2d operator+ (const Point2d & p1, const Vec2d & v); +inline Vec2d operator- (const Vec2d & p1, const Vec2d & v); +inline Vec2d operator+ (const Vec2d & p1, const Vec2d & v); +inline Vec2d operator* (double scal, const Vec2d & v); +double Angle (const Vec2d & v); +double FastAngle (const Vec2d & v); +double Angle (const Vec2d & v1, const Vec2d & v2); +double FastAngle (const Vec2d & v1, const Vec2d & v2); +ostream & operator<<(ostream & s, const Vec2d & v); +double Dist2(const Line2d & g, const Line2d & h ); // GH +int Near (const Point2d & p1, const Point2d & p2, const double eps); + +int Parallel (const Line2d & l1, const Line2d & l2, double peps = EPSGEOM); +int IsOnLine (const Line2d & l, const Point2d & p, double heps = EPSGEOM); +int IsOnLongLine (const Line2d & l, const Point2d & p); +int Hit (const Line2d & l1, const Line2d & l2, double heps = EPSGEOM); +ostream & operator<<(ostream & s, const Line2d & l); +Point2d CrossPoint (const PLine2d & l1, const PLine2d & l2); +int Parallel (const PLine2d & l1, const PLine2d & l2, double peps = EPSGEOM); +int IsOnLine (const PLine2d & l, const Point2d & p, double heps = EPSGEOM); +int IsOnLongLine (const PLine2d & l, const Point2d & p); +int Hit (const PLine2d & l1, const Line2d & l2, double heps = EPSGEOM); +ostream & operator<<(ostream & s, const Line2d & l); +ostream & operator<<(ostream & s, const TRIANGLE2D & t); +ostream & operator<<(ostream & s, const PTRIANGLE2D & t); + +/// +class Point2d +{ + /// + friend class Vec2d; + +protected: + /// + double px, py; + +public: + /// + Point2d() { /* px = py = 0; */ } + /// + Point2d(double ax, double ay) { px = ax; py = ay; } + /// + Point2d(const Point2d & p2) { px = p2.px; py = p2.py; } + + Point2d (const Point<2> & p2) + { + px = p2(0); + py = p2(1); + } + /// + Point2d & operator= (const Point2d & p2) + { px = p2.px; py = p2.py; return *this; } + + /// + int operator== (const Point2d & p2) const // GH + { return (px == p2.px && py == p2.py) ; } + + /// + double & X() { return px; } + /// + double & Y() { return py; } + /// + double X() const { return px; } + /// + double Y() const { return py; } + + operator Point<2> () const + { + return Point<2> (px, py); + } + + + /// + friend inline Vec2d operator- (const Point2d & p1, const Point2d & p2); + /// + friend inline Point2d operator- (const Point2d & p1, const Vec2d & v); + /// + friend inline Point2d operator+ (const Point2d & p1, const Vec2d & v); + + /// + friend inline Point2d Center (const Point2d & p1, const Point2d & p2); + + const Point2d & SetToMin (const Point2d & p2) + { + if (p2.px < px) px = p2.px; + if (p2.py < py) py = p2.py; + return *this; + } + + + /// + const Point2d & SetToMax (const Point2d & p2) + { + if (p2.px > px) px = p2.px; + if (p2.py > py) py = p2.py; + return *this; + } + + /// + friend double Dist (const Point2d & p1, const Point2d & p2) + { return sqrt ( (p1.px - p2.px) * (p1.px - p2.px) + + (p1.py - p2.py) * (p1.py - p2.py) ); } + // { return sqrt ( sqr (p1.X()-p2.X()) + sqr (p1.Y()-p2.Y()) ); } + + /// + friend double Dist2 (const Point2d & p1, const Point2d & p2) + { return ( (p1.px - p2.px) * (p1.px - p2.px) + + (p1.py - p2.py) * (p1.py - p2.py) ); } + // { return sqr (p1.X()-p2.X()) + sqr (p1.Y()-p2.Y()) ; } + + + /** + Points clock-wise ? + Are the points (p1, p2, p3) clock-wise ? + */ + friend inline int CW (const Point2d & p1, const Point2d & p2, const Point2d & p3) + { + // return Cross (p2 - p1, p3 - p2) < 0; + return + (p2.px - p1.px) * (p3.py - p2.py) - + (p2.py - p1.py) * (p3.px - p2.px) < 0; + } + /** + Points counter-clock-wise ? + Are the points (p1, p2, p3) counter-clock-wise ? + */ + friend inline int CCW (const Point2d & p1, const Point2d & p2, const Point2d & p3) + { + // return Cross (p2 - p1, p3 - p2) > 0; + return + (p2.px - p1.px) * (p3.py - p2.py) - + (p2.py - p1.py) * (p3.px - p2.px) > 0; + } + + /// + friend inline void PpSmV (const Point2d & p1, double s, const Vec2d & v, Point2d & p2); + /// + friend inline void PmP (const Point2d & p1, const Point2d & p2, Vec2d & v); + + /// + friend ostream & operator<<(ostream & s, const Point2d & p); +}; + + +inline int Near (const Point2d & p1, const Point2d & p2, + const double eps = 1e-4 ) +{ + return Dist2(p1,p2) <= eps*eps; +} + + + + + + +/// +class Vec2d + { +protected: + /// + double vx, vy; + +public: + /// + Vec2d() { /* vx = vy = 0; */ } + /// + Vec2d(double ax, double ay) + { vx = ax; vy = ay; } + /// + Vec2d(const Vec2d & v2) { vx = v2.vx; vy = v2.vy; } + + /// + explicit Vec2d(const Vec<2> & v2) { vx = v2(0); vy = v2(1); } + + /// + Vec2d(const Point2d & p1, const Point2d & p2) + { vx = p2.px - p1.px; vy = p2.py - p1.py; } + + /// + Vec2d & operator= (const Vec2d & p2) + { vx = p2.vx; vy = p2.vy; return *this; } + + /// + double & X() { return vx; } + /// + double & Y() { return vy; } + /// + double X() const { return vx; } + /// + double Y() const { return vy; } + + /// + double Length() const { return sqrt (vx * vx + vy * vy); } + /// + double Length2() const { return vx * vx + vy * vy; } + + void GetNormal (Vec2d & n) const { n.vx=-vy; n.vy=vx; } // GH + + /// + inline Vec2d & operator+= (const Vec2d & v2); + /// + inline Vec2d & operator-= (const Vec2d & v2); + /// + inline Vec2d & operator*= (double s); + /// + inline Vec2d & operator/= (double s); + + /// + friend inline Vec2d operator- (const Point2d & p1, const Point2d & p2); + /// + friend inline Point2d operator- (const Point2d & p1, const Vec2d & v); + /// + friend inline Point2d operator+ (const Point2d & p1, const Vec2d & v); + /// + friend inline Vec2d operator- (const Vec2d & p1, const Vec2d & v); + /// + friend inline Vec2d operator+ (const Vec2d & p1, const Vec2d & v); + /// + friend inline Vec2d operator* (double scal, const Vec2d & v); + + /// + friend double operator* (const Vec2d & v1, const Vec2d & v2) + { return v1.X() * v2.X() + v1.Y() * v2.Y(); } + + + /// + friend double Cross (const Vec2d & v1, const Vec2d & v2) + { return double(v1.X()) * double(v2.Y()) - + double(v1.Y()) * double(v2.X()); } + + /// + friend inline void PpSmV (const Point2d & p1, double s, const Vec2d & v, Point2d & p2); + /// + friend inline void PmP (const Point2d & p1, const Point2d & p2, Vec2d & v); + +/// Angle in [0,2*PI) + + /// + friend double Angle (const Vec2d & v); + /// + friend double FastAngle (const Vec2d & v); + /// + friend double Angle (const Vec2d & v1, const Vec2d & v2); + /// + friend double FastAngle (const Vec2d & v1, const Vec2d & v2); + + /// + friend ostream & operator<<(ostream & s, const Vec2d & v); + }; + + + +/// +class Line2d + { +protected: + /// + Point2d p1, p2; + +public: + /// + Line2d() : p1(), p2() { }; + /// + Line2d(const Point2d & ap1, const Point2d & ap2) + { p1 = ap1; p2 = ap2; } + + /// + Line2d & operator= (const Line2d & l2) + { p1 = l2.p1; p2 = l2.p2; return *this;} + + /// + Point2d & P1() { return p1; } + /// + Point2d & P2() { return p2; } + /// + const Point2d & P1() const { return p1; } + /// + const Point2d & P2() const { return p2; } + + /// + double XMax() const { return max2 (p1.X(), p2.X()); } + /// + double YMax() const { return max2 (p1.Y(), p2.Y()); } + /// + double XMin() const { return min2 (p1.X(), p2.X()); } + /// + double YMin() const { return min2 (p1.Y(), p2.Y()); } + + /// + Vec2d Delta () const { return Vec2d (p2.X()-p1.X(), p2.Y()-p1.Y()); } + /// + double Length () const { return Delta().Length(); } + /// + double Length2 () const + { return sqr (p1.X() - p2.X()) + + sqr (p1.Y() - p2.Y()); } + + void GetNormal (Line2d & n) const; // GH + Vec2d NormalDelta () const; // GH + + /// square of the distance between two 2d-lines. + friend double Dist2(const Line2d & g, const Line2d & h ); // GH + + /// + friend Point2d CrossPoint (const Line2d & l1, const Line2d & l2); + /// returns 1 iff parallel + friend int CrossPointBarycentric (const Line2d & l1, const Line2d & l2, + double & lam1, double & lam2); + + /// + friend int Parallel (const Line2d & l1, const Line2d & l2, double peps); + /// + friend int IsOnLine (const Line2d & l, const Point2d & p, double heps); + /// + friend int IsOnLongLine (const Line2d & l, const Point2d & p); + /// + friend int Hit (const Line2d & l1, const Line2d & l2, double heps); + + /// + friend ostream & operator<<(ostream & s, const Line2d & l); + }; + + +#ifdef NONE +/// +class PLine2d + { +protected: + /// + Point2d const * p1, *p2; + +public: + /// + PLine2d() { }; + /// + PLine2d(Point2d const * ap1, Point2d const * ap2) + { p1 = ap1; p2 = ap2; } + + /// + PLine2d & operator= (const PLine2d & l2) + { p1 = l2.p1; p2 = l2.p2; return *this;} + + /// + const Point2d *& P1() { return p1; } + /// + const Point2d *& P2() { return p2; } + /// + const Point2d & P1() const { return *p1; } + /// + const Point2d & P2() const { return *p2; } + + /// + double XMax() const { return max2 (p1->X(), p2->X()); } + /// + double YMax() const { return max2 (p1->Y(), p2->Y()); } + /// + double XMin() const { return min2 (p1->X(), p2->X()); } + /// + double YMin() const { return min2 (p1->Y(), p2->Y()); } + + + /// + Vec2d Delta () const { return Vec2d (p2->X()-p1->X(), p2->Y()-p1->Y()); } + /// + double Length () const { return Delta().Length(); } + /// + double Length2 () const + { return sqr (p1->X() - p2->X()) + + sqr (p1->Y() - p2->Y()); } + + + + /// + friend Point2d CrossPoint (const PLine2d & l1, const PLine2d & l2); + /// + friend int Parallel (const PLine2d & l1, const PLine2d & l2, double peps); + /// + friend int IsOnLine (const PLine2d & l, const Point2d & p, double heps); + /// + friend int IsOnLongLine (const PLine2d & l, const Point2d & p); + /// + friend int Hit (const PLine2d & l1, const Line2d & l2, double heps); + + /// + friend ostream & operator<<(ostream & s, const Line2d & l); + }; + + + +/// +class ILINE + { + /// + INDEX i[2]; + + public: + /// + ILINE() {}; + /// + ILINE(INDEX i1, INDEX i2) { i[0] = i1; i[1] = i2; } + /// + ILINE(const ILINE & l) { i[0] = l.i[0]; i[1] = l.i[1]; } + + /// + ILINE & operator= (const ILINE & l) + { i[0] = l.i[0]; i[1] = l.i[1]; return *this; } + + /// + const INDEX & I(int ai) const { return i[ai-1]; } + /// + const INDEX & X() const { return i[0]; } + /// + const INDEX & Y() const { return i[1]; } + /// + const INDEX & I1() const { return i[0]; } + /// + const INDEX & I2() const { return i[1]; } + + /// + INDEX & I(int ai) { return i[ai-1]; } + /// + INDEX & X() { return i[0]; } + /// + INDEX & Y() { return i[1]; } + /// + INDEX & I1() { return i[0]; } + /// + INDEX & I2() { return i[1]; } + }; + + + + +/// +class TRIANGLE2D + { +private: + /// + Point2d p1, p2, p3; + +public: + /// + TRIANGLE2D() { }; + /// + TRIANGLE2D (const Point2d & ap1, const Point2d & ap2, + const Point2d & ap3) + { p1 = ap1; p2 = ap2; p3 = ap3;} + + /// + TRIANGLE2D & operator= (const TRIANGLE2D & t2) + { p1 = t2.p1; p2 = t2.p2; p3 = t2.p3; return *this; } + + /// + Point2d & P1() { return p1; } + /// + Point2d & P2() { return p2; } + /// + Point2d & P3() { return p3; } + /// + const Point2d & P1() const { return p1; } + /// + const Point2d & P2() const { return p2; } + /// + const Point2d & P3() const { return p3; } + + /// + double XMax() const { return max3 (p1.X(), p2.X(), p3.X()); } + /// + double YMax() const { return max3 (p1.Y(), p2.Y(), p3.Y()); } + /// + double XMin() const { return min3 (p1.X(), p2.X(), p3.X()); } + /// + double YMin() const { return min3 (p1.Y(), p2.Y(), p3.Y()); } + + /// + inline Point2d Center () const + { return Point2d( (p1.X()+p2.X()+p3.X())/3, (p1.Y()+p2.Y()+p3.Y())/3); } + + /// + int Regular() const; + /// + int CW () const; + /// + int CCW () const; + + /// + int IsOn (const Point2d & p) const; + /// + int IsIn (const Point2d & p) const; + /// + friend ostream & operator<<(ostream & s, const TRIANGLE2D & t); + }; + + +/// +class PTRIANGLE2D + { +private: + /// + Point2d const *p1, *p2, *p3; + +public: + /// + PTRIANGLE2D() { }; + /// + PTRIANGLE2D (const Point2d * ap1, const Point2d * ap2, + const Point2d * ap3) + { p1 = ap1; p2 = ap2; p3 = ap3;} + + /// + PTRIANGLE2D & operator= (const PTRIANGLE2D & t2) + { p1 = t2.p1; p2 = t2.p2; p3 = t2.p3; return *this; } + + /// + const Point2d *& P1() { return p1; } + /// + const Point2d *& P2() { return p2; } + /// + const Point2d *& P3() { return p3; } + /// + const Point2d * P1() const { return p1; } + /// + const Point2d * P2() const { return p2; } + /// + const Point2d * P3() const { return p3; } + + /// + double XMax() const { return max3 (p1->X(), p2->X(), p3->X()); } + /// + double YMax() const { return max3 (p1->Y(), p2->Y(), p3->Y()); } + /// + double XMin() const { return min3 (p1->X(), p2->X(), p3->X()); } + /// + double YMin() const { return min3 (p1->Y(), p2->Y(), p3->Y()); } + + /// + Point2d Center () const + { return Point2d( (p1->X()+p2->X()+p3->X())/3, (p1->Y()+p2->Y()+p3->Y())/3); } + + + /// + int Regular() const; + /// + int CW () const; + /// + int CCW () const; + + /// + int IsOn (const Point2d & p) const; + /// + int IsIn (const Point2d & p) const; + /// + friend ostream & operator<<(ostream & s, const PTRIANGLE2D & t); + }; +#endif + + + +class Polygon2d +{ +protected: + ARRAY<Point2d> points; + +public: + Polygon2d (); + ~Polygon2d (); + + void AddPoint (const Point2d & p); + int GetNP() const { return points.Size(); } + void GetPoint (int i, Point2d & p) const + { p = points.Get(i); } + void GetLine (int i, Point2d & p1, Point2d & p2) const + { p1 = points.Get(i); p2 = points.Get(i%points.Size()+1); } + + double Area () const { return fabs (HArea()); } + int CW () const { return HArea() > 0; } + int CCW () const { return HArea() < 0; } + + int IsOn (const Point2d & p) const; + int IsIn (const Point2d & p) const; + + int IsConvex () const; + + int IsStarPoint (const Point2d & p) const; + Point2d Center() const; + Point2d EqualAreaPoint () const; +private: + double HArea () const; +}; + + +/** Cheap approximation to atan2. + A monotone function of atan2(x,y) is computed. + */ +extern double Fastatan2 (double x, double y); + + +inline Vec2d & Vec2d :: operator+= (const Vec2d & v2) + { + vx += v2.vx; + vy += v2.vy; + return *this; + } + +inline Vec2d & Vec2d :: operator-= (const Vec2d & v2) + { + vx -= v2.vx; + vy -= v2.vy; + return *this; + } + +inline Vec2d & Vec2d :: operator*= (double s) + { + vx *= s; + vy *= s; + return *this; + } + + +inline Vec2d & Vec2d :: operator/= (double s) +{ + if (s != 0) + { + vx /= s; + vy /= s; + } + else + { + MyError ("Vec2d::operator /=: Division by zero"); + } + return *this; +} + + + +inline Vec2d operator- (const Point2d & p1, const Point2d & p2) + { + return Vec2d (p1.X() - p2.X(), p1.Y() - p2.Y()); + } + + +inline Point2d operator- (const Point2d & p1, const Vec2d & v) + { + return Point2d (p1.X() - v.X(), p1.Y() - v.Y()); + } + + +inline Point2d operator+ (const Point2d & p1, const Vec2d & v) + { + return Point2d (p1.X() + v.X(), p1.Y() + v.Y()); + } + + +inline Point2d Center (const Point2d & p1, const Point2d & p2) + { + return Point2d ((p1.X() + p2.X()) / 2, (p1.Y() + p2.Y()) / 2); + } + + +inline Vec2d operator- (const Vec2d & v1, const Vec2d & v2) + { + return Vec2d (v1.X() - v2.X(), v1.Y() - v2.Y()); + } + + +inline Vec2d operator+ (const Vec2d & v1, const Vec2d & v2) + { + return Vec2d (v1.X() + v2.X(), v1.Y() + v2.Y()); + } + + +inline Vec2d operator* (double scal, const Vec2d & v) + { + return Vec2d (scal * v.X(), scal * v.Y()); + } + + +inline void PpSmV (const Point2d & p1, double s, + const Vec2d & v, Point2d & p2) + { + p2.X() = p1.X() + s * v.X(); + p2.Y() = p1.Y() + s * v.Y(); + } + + +inline void PmP (const Point2d & p1, const Point2d & p2, Vec2d & v) + { + v.X() = p1.X() - p2.X(); + v.Y() = p1.Y() - p2.Y(); + } + + + + + +#ifdef none +inline int TRIANGLE2D :: Regular() const + { + return fabs(Cross ( p2 - p1, p3 - p2)) > EPSGEOM; + } + + +inline int TRIANGLE2D :: CW () const + { + return Cross ( p2 - p1, p3 - p2) < 0; + } + + +inline int TRIANGLE2D :: CCW () const + { + return Cross ( p2 - p1, p3 - p2) > 0; + } + + + + +inline int PTRIANGLE2D :: Regular() const + { + return fabs(Cross ( *p2 - *p1, *p3 - *p2)) > EPSGEOM; + } + + +inline int PTRIANGLE2D :: CW () const + { + return Cross ( *p2 - *p1, *p3 - *p2) < 0; + } + + +inline int PTRIANGLE2D :: CCW () const + { + return Cross ( *p2 - *p1, *p3 - *p2) > 0; + } + + +#endif + + +/// +class Mat2d +{ +protected: + /// + double coeff[4]; + +public: + /// + Mat2d() { coeff[0] = coeff[1] = coeff[2] = coeff[3] = 0; } + /// + Mat2d(double a11, double a12, double a21, double a22) + { coeff[0] = a11; coeff[1] = a12; coeff[2] = a21; coeff[3] = a22; } + /// + Mat2d(const Mat2d & m2) + { for (int i = 0; i < 4; i++) coeff[i] = m2.Get(i); } + + /// + double & Elem (INDEX i, INDEX j) { return coeff[2*(i-1)+j-1]; } + /// + double & Elem (INDEX i) {return coeff[i]; } + /// + double Get (INDEX i, INDEX j) const { return coeff[2*(i-1)+j-1]; } + /// + double Get (INDEX i) const {return coeff[i]; } + + /// + double Det () const { return coeff[0] * coeff[3] - coeff[1] * coeff[2]; } + + /// + void Mult (const Vec2d & v, Vec2d & prod) const; + /// + void MultTrans (const Vec2d & v , Vec2d & prod) const; + /// + void Solve (const Vec2d & rhs, Vec2d & x) const; + /// Solves mat * x = rhs, but using a positive definite matrix instead of mat + void SolvePositiveDefinite (const Vec2d & rhs, Vec2d & x) const; + /// add a term \alpha * v * v^T + void AddDiadicProduct (double alpha, Vec2d & v); +}; + + + +inline void Mat2d :: Mult (const Vec2d & v, Vec2d & prod) const +{ + prod.X() = coeff[0] * v.X() + coeff[1] * v.Y(); + prod.Y() = coeff[2] * v.X() + coeff[3] * v.Y(); +} + + +inline void Mat2d :: MultTrans (const Vec2d & v, Vec2d & prod) const +{ + prod.X() = coeff[0] * v.X() + coeff[2] * v.Y(); + prod.Y() = coeff[1] * v.X() + coeff[3] * v.Y(); +} + + + +inline void Mat2d :: Solve (const Vec2d & rhs, Vec2d & x) const +{ + double det = Det(); + + if (det == 0) + MyError ("Mat2d::Solve: zero determinant"); + else + { + x.X() = (coeff[3] * rhs.X() - coeff[1] * rhs.Y()) / det; + x.Y() = (-coeff[2] * rhs.X() + coeff[0] * rhs.Y()) / det; + } +} + + +inline void Mat2d :: SolvePositiveDefinite (const Vec2d & rhs, Vec2d & x) const +{ + double a = max2(coeff[0], 1e-8); + double b = coeff[1] / a; + double c = coeff[2] / a; + double d = max2(coeff[3] - a *b * c, 1e-8); + + x.X() = (rhs.X() - b * rhs.Y()) / a; + x.Y() = rhs.Y() / d - c * x.X(); +} + + +inline void Mat2d :: AddDiadicProduct (double alpha, Vec2d & v) +{ + coeff[0] += alpha * v.X() * v.X(); + coeff[1] += alpha * v.X() * v.Y(); + coeff[2] += alpha * v.Y() * v.X(); + coeff[3] += alpha * v.Y() * v.Y(); +} + + + +#endif diff --git a/contrib/Netgen/libsrc/gprim/geom3d.cpp b/contrib/Netgen/libsrc/gprim/geom3d.cpp new file mode 100644 index 0000000000..eaee776778 --- /dev/null +++ b/contrib/Netgen/libsrc/gprim/geom3d.cpp @@ -0,0 +1,650 @@ +#include <algorithm> +#include <mystdlib.h> + +#include <myadt.hpp> +#include <gprim.hpp> + +namespace netgen +{ +ostream & operator<<(ostream & s, const Point3d & p) + { + return s << "(" << p.x[0] << ", " << p.x[1] << ", " << p.x[2] << ")"; + } + +ostream & operator<<(ostream & s, const Vec3d & v) + { + return s << "(" << v.x[0] << ", " << v.x[1] << ", " << v.x[2] << ")"; + } + +double Angle (const Vec3d & v1, const Vec3d & v2) +{ + double co = (v1 * v2) / (v1.Length() * v2.Length()); + if (co > 1) co = 1; + if (co < -1) co = -1; + return acos ( co ); +} + + +void Vec3d :: GetNormal (Vec3d & n) const + { + if (fabs (X()) > fabs (Z())) + { + n.X() = -Y(); + n.Y() = X(); + n.Z() = 0; + } + else + { + n.X() = 0; + n.Y() = Z(); + n.Z() = -Y(); + } + double len = n.Length(); + if (len == 0) + { + n.X() = 1; + n.Y() = n.Z() = 0; + } + else + n /= len; + } + +/* +ostream & operator<<(ostream & s, const ROTDenseMatrix3D & r) + { + return s << "{ (" << r.txx << ", " << r.txy << ", " << r.txz << ") , (" + << r.tyx << ", " << r.tyy << ", " << r.tyz << ") , (" + << r.tzx << ", " << r.tzy << ", " << r.tzz << ") }"; + } +*/ + +/* +Vec3d operator- (const Point3d & p1, const Point3d & p2) + { + return Vec3d (p1.X() - p2.X(), p1.Y() - p2.Y(),p1.Z() - p2.Z()); + } + +Point3d operator- (const Point3d & p1, const Vec3d & v) + { + return Point3d (p1.X() - v.X(), p1.Y() - v.Y(),p1.Z() - v.Z()); + } + +Point3d operator+ (const Point3d & p1, const Vec3d & v) + { + return Point3d (p1.X() + v.X(), p1.Y() + v.Y(),p1.Z() + v.Z()); + } + +Vec3d operator- (const Vec3d & v1, const Vec3d & v2) + { + return Vec3d (v1.X() - v2.X(), v1.Y() - v2.Y(),v1.Z() - v2.Z()); + } + +Vec3d operator+ (const Vec3d & v1, const Vec3d & v2) + { + return Vec3d (v1.X() + v2.X(), v1.Y() + v2.Y(),v1.Z() + v2.Z()); + } + +Vec3d operator* (double scal, const Vec3d & v) + { + return Vec3d (scal * v.X(), scal * v.Y(), scal * v.Z()); + } +*/ +/* +double operator* (const Vec3d & v1, const Vec3d & v2) + { + return v1.X() * v2.X() + v1.Y() * v2.Y() + v1.Z() * v2.Z(); + } + +double Cross (const Vec3d & v1, const Vec3d & v2) + { + return v1.X() * v2.Y() - v1.Y() * v2.X(); + } +*/ + +/* +void ROTDenseMatrix3D :: CalcRotMat(double ag, double bg, double lg, double size2, Vec3d r) + { + size = size2; + txx=size * ( cos(bg) * cos(lg) ); + txy=size * ( cos(bg) * sin(lg) ); + txz=size * (-sin(bg) ); + + tyx=size * ( sin(ag) * sin(bg) * cos(lg) - cos(ag) * sin(lg) ); + tyy=size * ( sin(ag) * sin(bg) * sin(lg) + cos(ag) * cos(lg) ); + tyz=size * ( sin(ag) * cos(bg) ); + + tzx=size * ( cos(ag) * sin(bg) * cos(lg) + sin(ag) * sin(lg) ); + tzy=size * ( cos(ag) * sin(bg) * sin(lg) - sin(ag) * cos(lg) ); + tzz=size * ( cos(ag) * cos(bg) ); + + deltaR=r; + } +ROTDenseMatrix3D :: ROTDenseMatrix3D(double ag, double bg, double lg, double size2, Vec3d r) + {CalcRotMat(ag, bg, lg, size2, r); } + +ROTDenseMatrix3D :: ROTDenseMatrix3D(Vec3d rot2) + { + Vec3d r2(0,0,0); + CalcRotMat(rot2.X(), rot2.Y(), rot2.Z(), 1, r2); + } + +ROTDenseMatrix3D ROTDenseMatrix3D :: INV() + { + ROTDenseMatrix3D rinv(txx/sqr(size),tyx/sqr(size),tzx/sqr(size), + txy/sqr(size),tyy/sqr(size),tzy/sqr(size), + txz/sqr(size),tyz/sqr(size),tzz/sqr(size), + 1/size,deltaR); + return rinv; + } + +Vec3d operator* (const ROTDenseMatrix3D & r, const Vec3d & v) + { + return Vec3d (r.XX() * v.X() + r.XY() * v.Y() + r.XZ() * v.Z(), + r.YX() * v.X() + r.YY() * v.Y() + r.YZ() * v.Z(), + r.ZX() * v.X() + r.ZY() * v.Y() + r.ZZ() * v.Z() ); + } + +Point3d operator* (const ROTDenseMatrix3D & r, const Point3d & p) + { + return Point3d (r.XX() * p.X() + r.XY() * p.Y() + r.XZ() * p.Z(), + r.YX() * p.X() + r.YY() * p.Y() + r.YZ() * p.Z(), + r.ZX() * p.X() + r.ZY() * p.Y() + r.ZZ() * p.Z() ); + } +*/ + + + + + + + +Box3d :: Box3d ( double aminx, double amaxx, + double aminy, double amaxy, + double aminz, double amaxz ) +{ + minx[0] = aminx; maxx[0] = amaxx; + minx[1] = aminy; maxx[1] = amaxy; + minx[2] = aminz; maxx[2] = amaxz; +} + +Box3d :: Box3d ( const Box3d & b2 ) +{ + for (int i = 0; i < 3; i++) + { + minx[i] = b2.minx[i]; + maxx[i] = b2.maxx[i]; + } +} + +Box3d :: Box3d ( const Box<3> & b2 ) +{ + for (int i = 0; i < 3; i++) + { + minx[i] = b2.PMin()(i); + maxx[i] = b2.PMax()(i); + } +} + + +/* +int Box3d :: Intersect (const Box3d & box2) const +{ + int i; + for (i = 0; i <= 2; i++) + if (minx[i] > box2.maxx[i] || maxx[i] < box2.minx[i]) + return 0; + return 1; +} +*/ + +/* +void Box3d :: SetPoint (const Point3d & p) +{ + minx[0] = maxx[0] = p.X(); + minx[1] = maxx[1] = p.Y(); + minx[2] = maxx[2] = p.Z(); +} + +void Box3d :: AddPoint (const Point3d & p) +{ + if (p.X() < minx[0]) minx[0] = p.X(); + if (p.X() > maxx[0]) maxx[0] = p.X(); + if (p.Y() < minx[1]) minx[1] = p.Y(); + if (p.Y() > maxx[1]) maxx[1] = p.Y(); + if (p.Z() < minx[2]) minx[2] = p.Z(); + if (p.Z() > maxx[2]) maxx[2] = p.Z(); +} +*/ + +void Box3d :: GetPointNr (int i, Point3d & point) const +{ + i--; + point.X() = (i & 1) ? maxx[0] : minx[0]; + point.Y() = (i & 2) ? maxx[1] : minx[1]; + point.Z() = (i & 4) ? maxx[2] : minx[2]; +} + + +void Box3d :: Increase (double d) +{ + for (int i = 0; i <= 2; i++) + { + minx[i] -= d; + maxx[i] += d; + } +} + +void Box3d :: IncreaseRel (double /* rel */) +{ + for (int i = 0; i <= 2; i++) + { + double d = 0.5 * (maxx[i] - minx[i]); + minx[i] -= d; + maxx[i] += d; + } +} + + +Box3d :: Box3d (const Point3d& p1, const Point3d& p2) +{ + minx[0] = min2 (p1.X(), p2.X()); + minx[1] = min2 (p1.Y(), p2.Y()); + minx[2] = min2 (p1.Z(), p2.Z()); + maxx[0] = max2 (p1.X(), p2.X()); + maxx[1] = max2 (p1.Y(), p2.Y()); + maxx[2] = max2 (p1.Z(), p2.Z()); +} + +const Box3d& Box3d :: operator+=(const Box3d& b) +{ + minx[0] = min2 (minx[0], b.minx[0]); + minx[1] = min2 (minx[1], b.minx[1]); + minx[2] = min2 (minx[2], b.minx[2]); + maxx[0] = max2 (maxx[0], b.maxx[0]); + maxx[1] = max2 (maxx[1], b.maxx[1]); + maxx[2] = max2 (maxx[2], b.maxx[2]); + + return *this; +} + +Point3d Box3d :: MaxCoords() const +{ + return Point3d(maxx[0], maxx[1], maxx[2]); +} + +Point3d Box3d :: MinCoords() const +{ + return Point3d(minx[0], minx[1], minx[2]); +} + +/* +void Box3d :: CreateNegMinMaxBox() +{ + minx[0] = MAXDOUBLE; + minx[1] = MAXDOUBLE; + minx[2] = MAXDOUBLE; + maxx[0] = MINDOUBLE; + maxx[1] = MINDOUBLE; + maxx[2] = MINDOUBLE; + +} +*/ + +void Box3d :: WriteData(ofstream& fout) const +{ + for(int i = 0; i < 3; i++) + { + fout << minx[i] << " " << maxx[i] << " "; + } + fout << "\n"; +} + +void Box3d :: ReadData(ifstream& fin) +{ + for(int i = 0; i < 3; i++) + { + fin >> minx[i]; + fin >> maxx[i]; + } +} + + + + +Box3dSphere :: Box3dSphere ( double aminx, double amaxx, + double aminy, double amaxy, + double aminz, double amaxz ) + : Box3d (aminx, amaxx, aminy, amaxy, aminz, amaxz) +{ + CalcDiamCenter (); +} + + +void Box3dSphere :: CalcDiamCenter () +{ + diam = sqrt( sqr (maxx[0] - minx[0]) + + sqr (maxx[1] - minx[1]) + + sqr (maxx[2] - minx[2])); + + c.X() = 0.5 * (minx[0] + maxx[0]); + c.Y() = 0.5 * (minx[1] + maxx[1]); + c.Z() = 0.5 * (minx[2] + maxx[2]); + + inner = min2 ( min2 (maxx[0] - minx[0], maxx[1] - minx[1]), maxx[2] - minx[2]) / 2; +} + + +void Box3dSphere :: GetSubBox (int i, Box3dSphere & sbox) const +{ + i--; + if (i & 1) + { + sbox.minx[0] = c.X(); + sbox.maxx[0] = maxx[0]; + } + else + { + sbox.minx[0] = minx[0]; + sbox.maxx[0] = c.X(); + } + if (i & 2) + { + sbox.minx[1] = c.Y(); + sbox.maxx[1] = maxx[1]; + } + else + { + sbox.minx[1] = minx[1]; + sbox.maxx[1] = c.Y(); + } + if (i & 4) + { + sbox.minx[2] = c.Z(); + sbox.maxx[2] = maxx[2]; + } + else + { + sbox.minx[2] = minx[2]; + sbox.maxx[2] = c.Z(); + } + + // sbox.CalcDiamCenter (); + + sbox.c.X() = 0.5 * (sbox.minx[0] + sbox.maxx[0]); + sbox.c.Y() = 0.5 * (sbox.minx[1] + sbox.maxx[1]); + sbox.c.Z() = 0.5 * (sbox.minx[2] + sbox.maxx[2]); + sbox.diam = 0.5 * diam; + sbox.inner = 0.5 * inner; +} + + + + +/* +double Determinant (const Vec3d & col1, + const Vec3d & col2, + const Vec3d & col3) +{ + return + col1.x[0] * ( col2.x[1] * col3.x[2] - col2.x[2] * col3.x[1]) + + col1.x[1] * ( col2.x[2] * col3.x[0] - col2.x[0] * col3.x[2]) + + col1.x[2] * ( col2.x[0] * col3.x[1] - col2.x[1] * col3.x[0]); +} +*/ + +void Transpose (Vec3d & v1, Vec3d & v2, Vec3d & v3) +{ + Swap (v1.Y(), v2.X()); + Swap (v1.Z(), v3.X()); + Swap (v2.Z(), v3.Y()); +} + + +int SolveLinearSystem (const Vec3d & col1, const Vec3d & col2, + const Vec3d & col3, const Vec3d & rhs, + Vec3d & sol) +{ + Vec3d cr; + Cross (col1, col2, cr); + double det = cr * col3; + + if (fabs (det) < 1e-40) + return 1; + + if (fabs(cr.Z()) > 1e-12) + { + // solve for 3. component + sol.Z() = (cr * rhs) / det; + + // 2x2 system for 1. and 2. component + double res1 = rhs.X() - sol.Z() * col3.X(); + double res2 = rhs.Y() - sol.Z() * col3.Y(); + + sol.X() = (col2.Y() * res1 - col2.X() * res2) / cr.Z(); + sol.Y() = (col1.X() * res2 - col1.Y() * res1) / cr.Z(); + + } + else + { + det = Determinant (col1, col2, col3); + if (fabs (det) < 1e-40) + return 1; + + sol.X() = Determinant (rhs, col2, col3) / det; + sol.Y() = Determinant (col1, rhs, col3) / det; + sol.Z() = Determinant (col1, col2, rhs) / det; + } + + return 0; +} + + +int SolveLinearSystemLS (const Vec3d & col1, + const Vec3d & col2, + const Vec2d & rhs, + Vec3d & sol) +{ + double a11 = col1 * col1; + double a12 = col1 * col2; + double a22 = col2 * col2; + + double det = a11 * a22 - a12 * a12; + + if (det*det <= 1e-24 * a11 * a22) + { + sol = Vec3d (0, 0, 0); + return 1; + } + + Vec2d invrhs; + invrhs.X() = ( a22 * rhs.X() - a12 * rhs.Y()) / det; + invrhs.Y() = (-a12 * rhs.X() + a11 * rhs.Y()) / det; + + sol.X() = invrhs.X() * col1.X() + invrhs.Y() * col2.X(); + sol.Y() = invrhs.X() * col1.Y() + invrhs.Y() * col2.Y(); + sol.Z() = invrhs.X() * col1.Z() + invrhs.Y() * col2.Z(); + + return 0; + + /* + Vec3d inv1, inv2; + int err = + PseudoInverse (col1, col2, inv1, inv2); + + sol = rhs.X() * inv1 + rhs.Y() * inv2; + return err; + */ +} + +int SolveLinearSystemLS2 (const Vec3d & col1, + const Vec3d & col2, + const Vec2d & rhs, + Vec3d & sol, double & x, double & y) +{ + double a11 = col1 * col1; + double a12 = col1 * col2; + double a22 = col2 * col2; + + double det = a11 * a22 - a12 * a12; + + if (fabs (det) <= 1e-12 * col1.Length() * col2.Length() || + col1.Length2() == 0 || col2.Length2() == 0) + { + sol = Vec3d (0, 0, 0); + x = 0; y = 0; + return 1; + } + + Vec2d invrhs; + invrhs.X() = ( a22 * rhs.X() - a12 * rhs.Y()) / det; + invrhs.Y() = (-a12 * rhs.X() + a11 * rhs.Y()) / det; + + sol.X() = invrhs.X() * col1.X() + invrhs.Y() * col2.X(); + sol.Y() = invrhs.X() * col1.Y() + invrhs.Y() * col2.Y(); + sol.Z() = invrhs.X() * col1.Z() + invrhs.Y() * col2.Z(); + + x = invrhs.X(); + y = invrhs.Y(); + + return 0; + + /* + Vec3d inv1, inv2; + int err = + PseudoInverse (col1, col2, inv1, inv2); + + sol = rhs.X() * inv1 + rhs.Y() * inv2; + return err; + */ +} + +int PseudoInverse (const Vec3d & col1, + const Vec3d & col2, + Vec3d & inv1, + Vec3d & inv2) +{ + double a11 = col1 * col1; + double a12 = col1 * col2; + double a22 = col2 * col2; + + double det = a11 * a22 - a12 * a12; + + if (fabs (det) < 1e-12 * col1.Length() * col2.Length()) + { + inv1 = Vec3d (0, 0, 0); + inv2 = Vec3d (0, 0, 0); + return 1; + } + + double ia11 = a22 / det; + double ia12 = -a12 / det; + double ia22 = a11 / det; + + inv1 = ia11 * col1 + ia12 * col2; + inv2 = ia12 * col1 + ia22 * col2; + + return 0; +} + + + + +QuadraticFunction3d :: +QuadraticFunction3d (const Point3d & p, const Vec3d & v) +{ + Vec3d hv(v); + hv /= (hv.Length() + 1e-12); + Vec3d t1, t2; + hv.GetNormal (t1); + Cross (hv, t1, t2); + + double t1p = t1.X() * p.X() + t1.Y() * p.Y() + t1.Z() * p.Z(); + double t2p = t2.X() * p.X() + t2.Y() * p.Y() + t2.Z() * p.Z(); + c0 = sqr (t1p) + sqr (t2p); + cx = -2 * (t1p * t1.X() + t2p * t2.X()); + cy = -2 * (t1p * t1.Y() + t2p * t2.Y()); + cz = -2 * (t1p * t1.Z() + t2p * t2.Z()); + + cxx = t1.X() * t1.X() + t2.X() * t2.X(); + cyy = t1.Y() * t1.Y() + t2.Y() * t2.Y(); + czz = t1.Z() * t1.Z() + t2.Z() * t2.Z(); + + cxy = 2 * t1.X() * t1.Y() + 2 * t2.X() * t2.Y(); + cxz = 2 * t1.X() * t1.Z() + 2 * t2.X() * t2.Z(); + cyz = 2 * t1.Y() * t1.Z() + 2 * t2.Y() * t2.Z(); + + /* + (*testout) << "c0 = " << c0 + << " clin = " << cx << " " << cy << " " << cz + << " cq = " << cxx << " " << cyy << " " << czz + << cxy << " " << cyz << " " << cyz << endl; + */ +} + +// QuadraticFunction3d gqf (Point3d (0,0,0), Vec3d (1, 0, 0)); + + + + + +void referencetransform :: Set (const Point3d & p1, const Point3d & p2, + const Point3d & p3, double ah) +{ + ex = p2 - p1; + ex /= ex.Length(); + ey = p3 - p1; + ey -= (ex * ey) * ex; + ey /= ey.Length(); + ez = Cross (ex, ey); + rp = p1; + h = ah; + + exh = ah * ex; + eyh = ah * ey; + ezh = ah * ez; + ah = 1 / ah; + ex_h = ah * ex; + ey_h = ah * ey; + ez_h = ah * ez; +} + +void referencetransform :: ToPlain (const Point3d & p, Point3d & pp) const +{ + Vec3d v; + v = p - rp; + pp.X() = (ex_h * v); + pp.Y() = (ey_h * v); + pp.Z() = (ez_h * v); +} + +void referencetransform :: ToPlain (const ARRAY<Point3d> & p, + ARRAY<Point3d> & pp) const +{ + Vec3d v; + int i; + + pp.SetSize (p.Size()); + for (i = 1; i <= p.Size(); i++) + { + v = p.Get(i) - rp; + pp.Elem(i).X() = (ex_h * v); + pp.Elem(i).Y() = (ey_h * v); + pp.Elem(i).Z() = (ez_h * v); + } +} + +void referencetransform :: FromPlain (const Point3d & pp, Point3d & p) const +{ + Vec3d v; + // v = (h * pp.X()) * ex + (h * pp.Y()) * ey + (h * pp.Z()) * ez; + // p = rp + v; + v.X() = pp.X() * exh.X() + pp.Y() * eyh.X() + pp.Z() * ezh.X(); + v.Y() = pp.X() * exh.Y() + pp.Y() * eyh.Y() + pp.Z() * ezh.Y(); + v.Z() = pp.X() * exh.Z() + pp.Y() * eyh.Z() + pp.Z() * ezh.Z(); + p.X() = rp.X() + v.X(); + p.Y() = rp.Y() + v.Y(); + p.Z() = rp.Z() + v.Z(); +} + + +} diff --git a/contrib/Netgen/libsrc/gprim/geom3d.hpp b/contrib/Netgen/libsrc/gprim/geom3d.hpp new file mode 100644 index 0000000000..56bff4ad6b --- /dev/null +++ b/contrib/Netgen/libsrc/gprim/geom3d.hpp @@ -0,0 +1,732 @@ +#ifndef FILE_GEOM3D +#define FILE_GEOM3D + +/* *************************************************************************/ +/* File: geom3d.hh */ +/* Author: Joachim Schoeberl */ +/* Date: 5. Aug. 95 */ +/* *************************************************************************/ + + + + +extern void MyError (const char * ch); + +class Point3d; +class Vec3d; + +inline Vec3d operator- (const Point3d & p1, const Point3d & p2); +inline Point3d operator- (const Point3d & p1, const Vec3d & v); +inline Point3d operator+ (const Point3d & p1, const Vec3d & v); +Point3d & Add (double d, const Vec3d & v); +Point3d & Add2 (double d, const Vec3d & v, + double d2, const Vec3d & v2); +inline Point3d Center (const Point3d & p1, const Point3d & p2); +inline Point3d Center (const Point3d & p1, const Point3d & p2, const Point3d & p3); +inline Point3d Center (const Point3d & p1, const Point3d & p2, + const Point3d & p3, const Point3d & p4); +ostream & operator<<(ostream & s, const Point3d & p); +inline Vec3d operator- (const Vec3d & p1, const Vec3d & v); +inline Vec3d operator+ (const Vec3d & p1, const Vec3d & v); +inline Vec3d operator* (double scal, const Vec3d & v); +inline double operator* (const Vec3d & v1, const Vec3d & v2); +inline Vec3d Cross (const Vec3d & v1, const Vec3d & v2); +inline void Cross (const Vec3d & v1, const Vec3d & v2, Vec3d & prod); +double Angle (const Vec3d & v); +double FastAngle (const Vec3d & v); +double Angle (const Vec3d & v1, const Vec3d & v2); +double FastAngle (const Vec3d & v1, const Vec3d & v2); +ostream & operator<<(ostream & s, const Vec3d & v); +void Transpose (Vec3d & v1, Vec3d & v2, Vec3d & v3); +int SolveLinearSystem (const Vec3d & col1, + const Vec3d & col2, + const Vec3d & col3, + const Vec3d & rhs, + Vec3d & sol); +int SolveLinearSystemLS (const Vec3d & col1, + const Vec3d & col2, + const Vec2d & rhs, + Vec3d & sol); +int SolveLinearSystemLS2 (const Vec3d & col1, + const Vec3d & col2, + const Vec2d & rhs, + Vec3d & sol, + double & x, double & y); +int PseudoInverse (const Vec3d & col1, + const Vec3d & col2, + Vec3d & inv1, + Vec3d & inv2); +double Determinant (const Vec3d & col1, + const Vec3d & col2, + const Vec3d & col3); + +/// Point in R3 +class Point3d +{ +protected: + /// + double x[3]; + +public: + /// + Point3d () { x[0] = x[1] = x[2] = 0; } + /// + Point3d(double ax, double ay, double az) + { x[0] = ax; x[1] = ay; x[2] = az; } + /// + Point3d(double ax[3]) + { x[0] = ax[0]; x[1] = ax[1]; x[2] = ax[2]; } + + /// + Point3d(const Point3d & p2) + { x[0] = p2.x[0]; x[1] = p2.x[1]; x[2] = p2.x[2]; } + + Point3d (const Point<3> & p2) + { + for (int i = 0; i < 3; i++) + x[i] = p2(i); + } + + /// + Point3d & operator= (const Point3d & p2) + { x[0] = p2.x[0]; x[1] = p2.x[1]; x[2] = p2.x[2]; return *this; } + + /// + int operator== (const Point3d& p) const + { return (x[0] == p.x[0] && x[1] == p.x[1] && x[2] == p.x[2]); } + + /// + double & X() { return x[0]; } + /// + double & Y() { return x[1]; } + /// + double & Z() { return x[2]; } + /// + double X() const { return x[0]; } + /// + double Y() const { return x[1]; } + /// + double Z() const { return x[2]; } + /// + double & X(int i) { return x[i-1]; } + /// + double X(int i) const { return x[i-1]; } + /// + const Point3d & SetToMin (const Point3d & p2) + { + if (p2.x[0] < x[0]) x[0] = p2.x[0]; + if (p2.x[1] < x[1]) x[1] = p2.x[1]; + if (p2.x[2] < x[2]) x[2] = p2.x[2]; + return *this; + } + + /// + const Point3d & SetToMax (const Point3d & p2) + { + if (p2.x[0] > x[0]) x[0] = p2.x[0]; + if (p2.x[1] > x[1]) x[1] = p2.x[1]; + if (p2.x[2] > x[2]) x[2] = p2.x[2]; + return *this; + } + + /// + friend inline Vec3d operator- (const Point3d & p1, const Point3d & p2); + /// + friend inline Point3d operator- (const Point3d & p1, const Vec3d & v); + /// + friend inline Point3d operator+ (const Point3d & p1, const Vec3d & v); + /// + inline Point3d & operator+= (const Vec3d & v); + inline Point3d & operator-= (const Vec3d & v); + /// + inline Point3d & Add (double d, const Vec3d & v); + /// + inline Point3d & Add2 (double d, const Vec3d & v, + double d2, const Vec3d & v2); + /// + friend inline double Dist (const Point3d & p1, const Point3d & p2) + { return sqrt ( (p1.x[0]-p2.x[0]) * (p1.x[0]-p2.x[0]) + + (p1.x[1]-p2.x[1]) * (p1.x[1]-p2.x[1]) + + (p1.x[2]-p2.x[2]) * (p1.x[2]-p2.x[2])); } + /// + inline friend double Dist2 (const Point3d & p1, const Point3d & p2) + { return ( (p1.x[0]-p2.x[0]) * (p1.x[0]-p2.x[0]) + + (p1.x[1]-p2.x[1]) * (p1.x[1]-p2.x[1]) + + (p1.x[2]-p2.x[2]) * (p1.x[2]-p2.x[2])); } + + /// + friend inline Point3d Center (const Point3d & p1, const Point3d & p2); + /// + friend inline Point3d Center (const Point3d & p1, const Point3d & p2, const Point3d & p3); + /// + friend inline Point3d Center (const Point3d & p1, const Point3d & p2, + const Point3d & p3, const Point3d & p4); + /// + friend ostream & operator<<(ostream & s, const Point3d & p); + + /// + friend class Vec3d; + /// + friend class Box3d; + + + operator Point<3> () const + { + return Point<3> (x[0], x[1], x[2]); + } +}; + + +/// +class Vec3d +{ +protected: + /// + double x[3]; + +public: + /// + inline Vec3d() { x[0] = x[1] = x[2] = 0; } + /// + inline Vec3d(double ax, double ay, double az) + { x[0] = ax; x[1] = ay; x[2] = az; } + /// + Vec3d(double ax[3]) + { x[0] = ax[0]; x[1] = ax[1]; x[2] = ax[2]; } + /// + inline Vec3d(const Vec3d & v2) + { x[0] = v2.x[0]; x[1] = v2.x[1]; x[2] = v2.x[2]; } + /// + inline Vec3d(const Point3d & p1, const Point3d & p2) + { + x[0] = p2.x[0] - p1.x[0]; + x[1] = p2.x[1] - p1.x[1]; + x[2] = p2.x[2] - p1.x[2]; + } + /// + inline Vec3d(const Point3d & p1) + { + x[0] = p1.x[0]; + x[1] = p1.x[1]; + x[2] = p1.x[2]; + } + + Vec3d (const Vec<3> & v2) + { + for (int i = 0; i < 3; i++) + x[i] = v2(i); + } + + operator Vec<3> () const + { + return Vec<3> (x[0], x[1], x[2]); + } + + + Vec3d & operator= (const Vec3d & v2) + { x[0] = v2.x[0]; x[1] = v2.x[1]; x[2] = v2.x[2]; return *this; } + /// + Vec3d & operator= (double val) + { x[0] = x[1] = x[2] = val; return *this; } + /// + double & X() { return x[0]; } + /// + double & Y() { return x[1]; } + /// + double & Z() { return x[2]; } + /// + double & X(int i) { return x[i-1]; } + + /// + double X() const { return x[0]; } + /// + double Y() const { return x[1]; } + /// + double Z() const { return x[2]; } + /// + double X(int i) const { return x[i-1]; } + + /// + double Length() const + { return sqrt (x[0] * x[0] + x[1] * x[1] + x[2] * x[2]); } + /// + double Length2() const + { return x[0] * x[0] + x[1] * x[1] + x[2] * x[2]; } + + /// + Vec3d & operator+= (const Vec3d & v2); + /// + Vec3d & operator-= (const Vec3d & v2); + /// + Vec3d & operator*= (double s); + /// + Vec3d & operator/= (double s); + /// + inline Vec3d & Add (double d, const Vec3d & v); + /// + inline Vec3d & Add2 (double d, const Vec3d & v, + double d2, const Vec3d & v2); + + /// + friend inline Vec3d operator- (const Point3d & p1, const Point3d & p2); + /// + friend inline Point3d operator- (const Point3d & p1, const Vec3d & v); + /// + friend inline Point3d operator+ (const Point3d & p1, const Vec3d & v); + /// + friend inline Vec3d operator- (const Vec3d & p1, const Vec3d & v); + /// + friend inline Vec3d operator+ (const Vec3d & p1, const Vec3d & v); + /// + friend inline Vec3d operator* (double scal, const Vec3d & v); + + /// + friend inline double operator* (const Vec3d & v1, const Vec3d & v2); + /// + friend inline Vec3d Cross (const Vec3d & v1, const Vec3d & v2); + /// + friend inline void Cross (const Vec3d & v1, const Vec3d & v2, Vec3d & prod); + + /// Returns one normal-vector to n + void GetNormal (Vec3d & n) const; + /// + friend double Angle (const Vec3d & v); + /// + friend double FastAngle (const Vec3d & v); + /// + friend double Angle (const Vec3d & v1, const Vec3d & v2); + /// + friend double FastAngle (const Vec3d & v1, const Vec3d & v2); + + void Normalize() + { + double len = (x[0] * x[0] + x[1] * x[1] + x[2] * x[2]); + if (len == 0) return; + len = sqrt (len); + x[0] /= len; x[1] /= len; x[2] /= len; + } + + /// + friend ostream & operator<<(ostream & s, const Vec3d & v); + + /// + friend class Point3d; + friend void Transpose (Vec3d & v1, Vec3d & v2, Vec3d & v3); + friend int SolveLinearSystem (const Vec3d & col1, + const Vec3d & col2, + const Vec3d & col3, + const Vec3d & rhs, + Vec3d & sol); + friend int SolveLinearSystemLS (const Vec3d & col1, + const Vec3d & col2, + const Vec2d & rhs, + Vec3d & sol); + friend int SolveLinearSystemLS2 (const Vec3d & col1, + const Vec3d & col2, + const Vec2d & rhs, + Vec3d & sol, + double & x, double & y); + friend int PseudoInverse (const Vec3d & col1, + const Vec3d & col2, + Vec3d & inv1, + Vec3d & inv2); + friend double Determinant (const Vec3d & col1, + const Vec3d & col2, + const Vec3d & col3); +}; + + + + +class QuadraticFunction3d +{ + double c0, cx, cy, cz; + double cxx, cyy, czz, cxy, cxz, cyz; + +public: + QuadraticFunction3d (const Point3d & p, const Vec3d & v); + double Eval (const Point3d & p) + { + return + c0 + + p.X() * (cx + cxx * p.X() + cxy * p.Y() + cxz * p.Z()) + + p.Y() * (cy + cyy * p.Y() + cyz * p.Z()) + + p.Z() * (cz + czz * p.Z()); + } +}; + + + +inline Point3d Center (const Point3d & p1, const Point3d & p2) +{ + return Point3d (0.5 * (p1.x[0] + p2.x[0]), + 0.5 * (p1.x[1] + p2.x[1]), + 0.5 * (p1.x[2] + p2.x[2])); +} + + +inline Point3d Center (const Point3d & p1, const Point3d & p2, + const Point3d & p3) +{ + return Point3d (1.0/3.0 * (p1.x[0] + p2.x[0] + p3.x[0]), + 1.0/3.0 * (p1.x[1] + p2.x[1] + p3.x[1]), + 1.0/3.0 * (p1.x[2] + p2.x[2] + p3.x[2])); +} + +inline Point3d Center (const Point3d & p1, const Point3d & p2, + const Point3d & p3, const Point3d & p4) +{ + return Point3d (0.25 * (p1.x[0] + p2.x[0] + p3.x[0] + p4.x[0]), + 0.25 * (p1.x[1] + p2.x[1] + p3.x[1] + p4.x[1]), + 0.25 * (p1.x[2] + p2.x[2] + p3.x[2] + p4.x[2])); +} + + + +inline Vec3d & Vec3d :: operator+= (const Vec3d & v2) +{ + x[0] += v2.x[0]; + x[1] += v2.x[1]; + x[2] += v2.x[2]; + return *this; +} + +inline Vec3d & Vec3d :: operator-= (const Vec3d & v2) +{ + x[0] -= v2.x[0]; + x[1] -= v2.x[1]; + x[2] -= v2.x[2]; + return *this; +} + + +inline Vec3d & Vec3d :: operator*= (double s) +{ + x[0] *= s; + x[1] *= s; + x[2] *= s; + return *this; +} + + +inline Vec3d & Vec3d :: operator/= (double s) +{ + if (s != 0) + { + x[0] /= s; + x[1] /= s; + x[2] /= s; + } +#ifdef DEBUG + else + { + cerr << "Vec div by 0, v = " << (*this) << endl; + // MyError ("Vec3d::operator /=: Divisioin by zero"); + } +#endif + return *this; +} + +inline Vec3d & Vec3d::Add (double d, const Vec3d & v) +{ + x[0] += d * v.x[0]; + x[1] += d * v.x[1]; + x[2] += d * v.x[2]; + return *this; +} + +inline Vec3d & Vec3d::Add2 (double d, const Vec3d & v, + double d2, const Vec3d & v2) +{ + x[0] += d * v.x[0] + d2 * v2.x[0]; + x[1] += d * v.x[1] + d2 * v2.x[1]; + x[2] += d * v.x[2] + d2 * v2.x[2]; + return *this; +} + + + + + + + + +inline Vec3d operator- (const Point3d & p1, const Point3d & p2) +{ + return Vec3d (p1.x[0] - p2.x[0], p1.x[1] - p2.x[1],p1.x[2] - p2.x[2]); +} + + +inline Point3d operator- (const Point3d & p1, const Vec3d & v) +{ + return Point3d (p1.x[0] - v.x[0], p1.x[1] - v.x[1],p1.x[2] - v.x[2]); +} + + +inline Point3d operator+ (const Point3d & p1, const Vec3d & v) +{ + return Point3d (p1.x[0] + v.x[0], p1.x[1] + v.x[1],p1.x[2] + v.x[2]); +} + +inline Point3d & Point3d::operator+= (const Vec3d & v) +{ + x[0] += v.x[0]; + x[1] += v.x[1]; + x[2] += v.x[2]; + return *this; +} + +inline Point3d & Point3d::operator-= (const Vec3d & v) +{ + x[0] -= v.x[0]; + x[1] -= v.x[1]; + x[2] -= v.x[2]; + return *this; +} + +inline Point3d & Point3d::Add (double d, const Vec3d & v) +{ + x[0] += d * v.x[0]; + x[1] += d * v.x[1]; + x[2] += d * v.x[2]; + return *this; +} + +inline Point3d & Point3d::Add2 (double d, const Vec3d & v, + double d2, const Vec3d & v2) +{ + x[0] += d * v.x[0] + d2 * v2.x[0]; + x[1] += d * v.x[1] + d2 * v2.x[1]; + x[2] += d * v.x[2] + d2 * v2.x[2]; + return *this; +} + + +inline Vec3d operator- (const Vec3d & v1, const Vec3d & v2) +{ + return Vec3d (v1.x[0] - v2.x[0], v1.x[1] - v2.x[1],v1.x[2] - v2.x[2]); +} + + +inline Vec3d operator+ (const Vec3d & v1, const Vec3d & v2) +{ + return Vec3d (v1.x[0] + v2.x[0], v1.x[1] + v2.x[1],v1.x[2] + v2.x[2]); +} + + +inline Vec3d operator* (double scal, const Vec3d & v) +{ + return Vec3d (scal * v.x[0], scal * v.x[1], scal * v.x[2]); +} + + + +inline double operator* (const Vec3d & v1, const Vec3d & v2) +{ + return v1.x[0] * v2.x[0] + v1.x[1] * v2.x[1] + v1.x[2] * v2.x[2]; +} + + + +inline Vec3d Cross (const Vec3d & v1, const Vec3d & v2) +{ + return Vec3d + ( v1.x[1] * v2.x[2] - v1.x[2] * v2.x[1], + v1.x[2] * v2.x[0] - v1.x[0] * v2.x[2], + v1.x[0] * v2.x[1] - v1.x[1] * v2.x[0]); +} + +inline void Cross (const Vec3d & v1, const Vec3d & v2, Vec3d & prod) +{ + prod.x[0] = v1.x[1] * v2.x[2] - v1.x[2] * v2.x[1]; + prod.x[1] = v1.x[2] * v2.x[0] - v1.x[0] * v2.x[2]; + prod.x[2] = v1.x[0] * v2.x[1] - v1.x[1] * v2.x[0]; +} + +inline double Determinant (const Vec3d & col1, + const Vec3d & col2, + const Vec3d & col3) +{ + return + col1.x[0] * ( col2.x[1] * col3.x[2] - col2.x[2] * col3.x[1]) + + col1.x[1] * ( col2.x[2] * col3.x[0] - col2.x[0] * col3.x[2]) + + col1.x[2] * ( col2.x[0] * col3.x[1] - col2.x[1] * col3.x[0]); +} + + +/// +class Box3d +{ +protected: + /// + double minx[3], maxx[3]; + +public: + /// + Box3d () { }; + /// + Box3d ( double aminx, double amaxx, + double aminy, double amaxy, + double aminz, double amaxz ); + /// + Box3d ( const Box3d & b2 ); + /// + Box3d (const Point3d& p1, const Point3d& p2); + /// + Box3d (const Box<3> & b2); + /// + double MinX () const { return minx[0]; } + /// + double MaxX () const { return maxx[0]; } + /// + double MinY () const { return minx[1]; } + /// + double MaxY () const { return maxx[1]; } + /// + double MinZ () const { return minx[2]; } + /// + double MaxZ () const { return maxx[2]; } + + /// + double Mini (int i) const { return minx[i-1]; } + /// + double Maxi (int i) const { return maxx[i-1]; } + + /// + Point3d PMin () const { return Point3d(minx[0], minx[1], minx[2]); } + /// + Point3d PMax () const { return Point3d(maxx[0], maxx[1], maxx[2]); } + + /// + void GetPointNr (int i, Point3d & point) const; + /// increase Box at each side with dist + void Increase (double dist); + /// increase Box by factor rel + void IncreaseRel (double rel); + /// return 1 if closures are intersecting + int Intersect (const Box3d & box2) const + { + if (minx[0] > box2.maxx[0] || maxx[0] < box2.minx[0] || + minx[1] > box2.maxx[1] || maxx[1] < box2.minx[1] || + minx[2] > box2.maxx[2] || maxx[2] < box2.minx[2]) + return 0; + return 1; + } + /// return 1 if point p in closure + int IsIn (const Point3d & p) const + { + if (minx[0] <= p.x[0] && maxx[0] >= p.x[0] && + minx[1] <= p.x[1] && maxx[1] >= p.x[1] && + minx[2] <= p.x[2] && maxx[2] >= p.x[2]) + return 1; + return 0; + } + /// + inline void SetPoint (const Point3d & p) + { + minx[0] = maxx[0] = p.X(); + minx[1] = maxx[1] = p.Y(); + minx[2] = maxx[2] = p.Z(); + } + + /// + inline void AddPoint (const Point3d & p) + { + if (p.x[0] < minx[0]) minx[0] = p.x[0]; + if (p.x[0] > maxx[0]) maxx[0] = p.x[0]; + if (p.x[1] < minx[1]) minx[1] = p.x[1]; + if (p.x[1] > maxx[1]) maxx[1] = p.x[1]; + if (p.x[2] < minx[2]) minx[2] = p.x[2]; + if (p.x[2] > maxx[2]) maxx[2] = p.x[2]; + } + + /// + const Box3d& operator+=(const Box3d& b); + + /// + Point3d MaxCoords() const; + /// + Point3d MinCoords() const; + + /// Make a negative sized box; + // void CreateNegMinMaxBox(); + + /// + Point3d CalcCenter () const { return Point3d(0.5*(minx[0] + maxx[0]), + 0.5*(minx[1] + maxx[1]), + 0.5*(minx[2] + maxx[2])); } + /// + double CalcDiam () const { return sqrt(sqr(maxx[0]-minx[0])+ + sqr(maxx[1]-minx[1])+ + sqr(maxx[2]-minx[2])); } + + /// + void WriteData(ofstream& fout) const; + /// + void ReadData(ifstream& fin); +}; + + +class Box3dSphere : public Box3d +{ +protected: + /// + double diam, inner; + /// + Point3d c; +public: + /// + Box3dSphere () { }; + /// + Box3dSphere ( double aminx, double amaxx, + double aminy, double amaxy, + double aminz, double amaxz); + /// + const Point3d & Center () const { return c; } + + /// + double Diam () const { return diam; } + /// + double Inner () const { return inner; } + /// + void GetSubBox (int i, Box3dSphere & sbox) const; + + // private: + /// + void CalcDiamCenter (); +}; + + + + +/// +class referencetransform +{ + /// + Vec3d ex, ey, ez; + /// + Vec3d exh, eyh, ezh; + /// + Vec3d ex_h, ey_h, ez_h; + /// + Point3d rp; + /// + double h; + +public: + + /// + void Set (const Point3d & p1, const Point3d & p2, + const Point3d & p3, double ah); + + /// + void ToPlain (const Point3d & p, Point3d & pp) const; + /// + void ToPlain (const ARRAY<Point3d> & p, ARRAY<Point3d> & pp) const; + /// + void FromPlain (const Point3d & pp, Point3d & p) const; +}; + + + +#endif diff --git a/contrib/Netgen/libsrc/gprim/geomfuncs.cpp b/contrib/Netgen/libsrc/gprim/geomfuncs.cpp new file mode 100644 index 0000000000..b2ac83824a --- /dev/null +++ b/contrib/Netgen/libsrc/gprim/geomfuncs.cpp @@ -0,0 +1,111 @@ +#include <mystdlib.h> + +#include <myadt.hpp> +#include <gprim.hpp> + +namespace netgen +{ + + /* + // template <> +inline void CalcInverse (const Mat<2,2> & m, Mat<2,2> & inv) +{ + double det = m(0,0) * m(1,1) - m(0,1) * m(1,0); + if (det == 0) + { + inv = 0; + return; + } + + double idet = 1.0 / det; + inv(0,0) = idet * m(1,1); + inv(0,1) = -idet * m(0,1); + inv(1,0) = -idet * m(1,0); + inv(1,1) = idet * m(0,0); +} + */ + + + + // template <> +void CalcInverse (const Mat<3,3> & m, Mat<3,3> & inv) +{ + double det = Det (m); + if (det == 0) + { + inv = 0; + return; + } + + double idet = 1.0 / det; + inv(0,0) = idet * (m(1,1) * m(2,2) - m(1,2) * m(2,1)); + inv(1,0) = -idet * (m(1,0) * m(2,2) - m(1,2) * m(2,0)); + inv(2,0) = idet * (m(1,0) * m(2,1) - m(1,1) * m(2,0)); + + inv(0,1) = -idet * (m(0,1) * m(2,2) - m(0,2) * m(2,1)); + inv(1,1) = idet * (m(0,0) * m(2,2) - m(0,2) * m(2,0)); + inv(2,1) = -idet * (m(0,0) * m(2,1) - m(0,1) * m(2,0)); + + inv(0,2) = idet * (m(0,1) * m(1,2) - m(0,2) * m(1,1)); + inv(1,2) = -idet * (m(0,0) * m(1,2) - m(0,2) * m(1,0)); + inv(2,2) = idet * (m(0,0) * m(1,1) - m(0,1) * m(1,0)); +} + +/* +// template <> +void CalcInverse (const Mat<2,3> & m, Mat<3,2> & inv) +{ + Mat<2,2> a = m * Trans (m); + Mat<2,2> ainv; + CalcInverse (a, ainv); + inv = Trans (m) * ainv; +} +*/ + + + +double Det (const Mat<2,2> & m) +{ + return m(0,0) * m(1,1) - m(0,1) * m(1,0); +} + +double Det (const Mat<3,3> & m) +{ + return + m(0,0) * m(1,1) * m(2,2) + + m(1,0) * m(2,1) * m(0,2) + + m(2,0) * m(0,1) * m(1,2) + - m(0,0) * m(2,1) * m(1,2) + - m(1,0) * m(0,1) * m(2,2) + - m(2,0) * m(1,1) * m(0,2); +} + + +void EigenValues (const Mat<3,3> & m, Vec<3> & ev) +{ + const double pi = 3.141592; + double a, b, c, d; + double p, q; + double arg; + + a = -1.; + b = m(0,0) + m(1,1) + m(2,2); + c = -( m(0,0)*m(2,2) + m(1,1)*m(2,2) + m(0,0)*m(1,1) - sqr(m(0,1)) - sqr(m(0,2)) - sqr(m(1,2)) ); + d = Det (m); + p = 3.*a*c - sqr(b); + q = 27.*sqr(a)*d - 9.*a*b*c + 2.*sqr(b)*b; + + + arg = acos((-q/2)/sqrt(-(p*p*p))); + + + ev(0) = (2. * sqrt(-p) * cos(arg/3.) - b) / 3.*a; + ev(1) = (-2. * sqrt(-p) * cos(arg/3.+pi/3) - b) / 3.*a; + ev(2) = (-2. * sqrt(-p) * cos(arg/3.-pi/3)- b) / 3.*a; + + + +} + + +} diff --git a/contrib/Netgen/libsrc/gprim/geomfuncs.hpp b/contrib/Netgen/libsrc/gprim/geomfuncs.hpp new file mode 100644 index 0000000000..b9228c8583 --- /dev/null +++ b/contrib/Netgen/libsrc/gprim/geomfuncs.hpp @@ -0,0 +1,136 @@ +#ifndef FILE_GEOMFUNCS +#define FILE_GEOMFUNCS + +/* *************************************************************************/ +/* File: geomfuncs.hpp */ +/* Author: Joachim Schoeberl */ +/* Date: 20. Jul. 02 */ +/* *************************************************************************/ + + +template <int D> +inline double Abs (const Vec<D> & v) +{ + double sum = 0; + for (int i = 0; i < D; i++) + sum += v(i) * v(i); + return sqrt (sum); +} + + +template <int D> +inline double Abs2 (const Vec<D> & v) +{ + double sum = 0; + for (int i = 0; i < D; i++) + sum += v(i) * v(i); + return sum; +} + + + +template <int D> +inline double Dist (const Point<D> & a, const Point<D> & b) +{ + return Abs (a-b); +} + +template <int D> +inline double Dist2 (const Point<D> & a, const Point<D> & b) +{ + return Abs2 (a-b); +} + + +template <int D> +inline Point<D> Center (const Point<D> & a, const Point<D> & b) +{ + Point<D> res; + for (int i = 0; i < D; i++) + res(i) = 0.5 * (a(i) + b(i)); + return res; +} + +template <int D> +inline Point<D> Center (const Point<D> & a, const Point<D> & b, const Point<D> & c) +{ + Point<D> res; + for (int i = 0; i < D; i++) + res(i) = (1.0/3.0) * (a(i) + b(i) + c(i)); + return res; +} + + + +inline Vec<3> Cross (const Vec<3> & v1, const Vec<3> & v2) +{ + return Vec<3> + ( v1(1) * v2(2) - v1(2) * v2(1), + v1(2) * v2(0) - v1(0) * v2(2), + v1(0) * v2(1) - v1(1) * v2(0) ); +} + + +template <> +inline Vec<2> Vec<2> :: GetNormal () const +{ + return Vec<2> (-x[1], x[0]); +} + +template <> +inline Vec<3> Vec<3> :: GetNormal () const +{ + if (fabs (x[0]) > fabs (x[2])) + return Vec<3> (-x[1], x[0], 0); + else + return Vec<3> (0, x[2], -x[1]); +} + + + +// template <int H, int W> +inline void CalcInverse (const Mat<2,2> & m, Mat<2,2> & inv) +{ + double det = m(0,0) * m(1,1) - m(0,1) * m(1,0); + if (det == 0) + { + inv = 0; + return; + } + + double idet = 1.0 / det; + inv(0,0) = idet * m(1,1); + inv(0,1) = -idet * m(0,1); + inv(1,0) = -idet * m(1,0); + inv(1,1) = idet * m(0,0); +} + +void CalcInverse (const Mat<3,3> & m, Mat<3,3> & inv); + +inline void CalcInverse (const Mat<2,3> & m, Mat<3,2> & inv) +{ + Mat<2,2> a = m * Trans (m); + Mat<2,2> ainv; + CalcInverse (a, ainv); + inv = Trans (m) * ainv; +} + +void CalcInverse (const Mat<3,2> & m, Mat<2,3> & inv); + +inline void CalcInverse (const Mat<3,2> & m, Mat<2,3> & inv) +{ + Mat<2,2> a = Trans (m) * m; + Mat<2,2> ainv; + CalcInverse (a, ainv); + inv = ainv * Trans (m); +} + + +double Det (const Mat<2,2> & m); +double Det (const Mat<3,3> & m); + +// eigenvalues of a symmetric matrix +void EigenValues (const Mat<3,3> & m, Vec<3> & ev); +void EigenValues (const Mat<2,2> & m, Vec<3> & ev); + +#endif diff --git a/contrib/Netgen/libsrc/gprim/geomobjects.hpp b/contrib/Netgen/libsrc/gprim/geomobjects.hpp new file mode 100644 index 0000000000..2db82cf9e9 --- /dev/null +++ b/contrib/Netgen/libsrc/gprim/geomobjects.hpp @@ -0,0 +1,346 @@ +#ifndef FILE_OBJECTS +#define FILE_OBJECTS + +/* *************************************************************************/ +/* File: geomobjects.hpp */ +/* Author: Joachim Schoeberl */ +/* Date: 20. Jul. 02 */ +/* *************************************************************************/ + + + +template <int D> class Vec; +template <int D> class Point; + + +template <int D> +class Point +{ + +protected: + double x[D]; + +public: + Point () { ; } + Point (double ax) { x[0] = ax; } + Point (double ax, double ay) { x[0] = ax; x[1] = ay; } + Point (double ax, double ay, double az) + { x[0] = ax; x[1] = ay; x[2] = az; } + Point (double ax, double ay, double az, double au) + { x[0] = ax; x[1] = ay; x[2] = az; x[3] = au;} + + Point (const Point<D> & p2) + { for (int i = 0; i < D; i++) x[i] = p2.x[i]; } + + explicit Point (const Vec<D> & v) + { for (int i = 0; i < D; i++) x[i] = v(i); } + + + Point & operator= (const Point<D> & p2) + { + for (int i = 0; i < D; i++) x[i] = p2.x[i]; + return *this; + } + + double & operator() (int i) { return x[i]; } + const double & operator() (int i) const { return x[i]; } + + operator const double* () const { return x; } +}; + + + + + +template <int D> +class Vec +{ + +protected: + double x[D]; + +public: + Vec () { ; } + Vec (double ax) { for (int i = 0; i < D; i++) x[i] = ax; } + Vec (double ax, double ay) { x[0] = ax; x[1] = ay; } + Vec (double ax, double ay, double az) + { x[0] = ax; x[1] = ay; x[2] = az; } + Vec (double ax, double ay, double az, double au) + { x[0] = ax; x[1] = ay; x[2] = az; x[3] = au; } + + Vec (const Vec<D> & p2) + { for (int i = 0; i < D; i++) x[i] = p2.x[i]; } + + explicit Vec (const Point<D> & p) + { for (int i = 0; i < D; i++) x[i] = p(i); } + + Vec (const Vec<D> & p1, const Vec<D> & p2) + { for(int i=0; i<D; i++) x[i] = p2(i)-p1(1); } + + + + Vec & operator= (const Vec<D> & p2) + { + for (int i = 0; i < D; i++) x[i] = p2.x[i]; + return *this; + } + + Vec & operator= (double s) + { + for (int i = 0; i < D; i++) x[i] = s; + return *this; + } + + double & operator() (int i) { return x[i]; } + const double & operator() (int i) const { return x[i]; } + + operator const double* () const { return x; } + + double Length () const + { + double l = 0; + for (int i = 0; i < D; i++) + l += x[i] * x[i]; + return sqrt (l); + } + + double Length2 () const + { + double l = 0; + for (int i = 0; i < D; i++) + l += x[i] * x[i]; + return l; + } + + const Vec<D> & Normalize () + { + double l = Length(); + if (l != 0) + for (int i = 0; i < D; i++) + x[i] /= l; + return *this; + } + + Vec<D> GetNormal () const; +}; + + + + + +template <int H, int W=H> +class Mat +{ + +protected: + double x[H*W]; + +public: + Mat () { ; } + Mat (const Mat & b) + { for (int i = 0; i < H*W; i++) x[i] = b.x[i]; } + + Mat & operator= (double s) + { + for (int i = 0; i < H*W; i++) x[i] = s; + return *this; + } + + Mat & operator= (const Mat & b) + { + for (int i = 0; i < H*W; i++) x[i] = b.x[i]; + return *this; + } + + double & operator() (int i, int j) { return x[i*W+j]; } + const double & operator() (int i, int j) const { return x[i*W+j]; } + double & operator() (int i) { return x[i]; } + const double & operator() (int i) const { return x[i]; } + + Vec<H> Col (int i) const + { + Vec<H> hv; + for (int j = 0; j < H; j++) + hv(j) = x[j*W+i]; + return hv; + } + + Vec<W> Row (int i) const + { + Vec<W> hv; + for (int j = 0; j < W; j++) + hv(j) = x[i*W+j]; + return hv; + } + + void Solve (const Vec<H> & rhs, Vec<W> & sol) const + { + Mat<W,H> inv; + CalcInverse (*this, inv); + sol = inv * rhs; + } +}; + + + + +template <int D> +class Box +{ +protected: + Point<D> pmin, pmax; +public: + Box () { ; } + Box ( const Point<D> & p1, const Point<D> & p2) + { + for (int i = 0; i < D; i++) + { + pmin(i) = min2(p1(i), p2(i)); + pmax(i) = max2(p1(i), p2(i)); + } + } + + const Point<D> & PMin () const { return pmin; } + const Point<D> & PMax () const { return pmax; } + + void Set (const Point<D> & p) + { pmin = pmax = p; } + + void Add (const Point<D> & p) + { + for (int i = 0; i < D; i++) + { + if (p(i) < pmin(i)) pmin(i) = p(i); + else if (p(i) > pmax(i)) pmax(i) = p(i); + } + } + + Point<D> Center () const + { + Point<D> c; + for (int i = 0; i < D; i++) + c(i) = 0.5 * (pmin(i)+pmax(i)); + return c; + } + double Diam () const { return Abs (pmax-pmin); } + + Point<D> GetPointNr (int nr) const + { + Point<D> p; + for (int i = 0; i < D; i++) + { + p(i) = (nr & 1) ? pmax(i) : pmin(i); + nr >>= 1; + } + return p; + } + + + bool Intersect (const Box<D> & box2) const + { + for (int i = 0; i < D; i++) + if (pmin(i) > box2.pmax(i) || + pmax(i) < box2.pmin(i)) return 0; + return 1; + } + + + bool IsIn (const Point<D> & p) const + { + for (int i = 0; i < D; i++) + if (p(i) < pmin(i) || p(i) > pmax(i)) return 0; + return 1; + } + + + void Increase (double dist) + { + for (int i = 0; i < D; i++) + { + pmin(i) -= dist; + pmax(i) += dist; + } + } +}; + + + + +template <int D> +class BoxSphere : public Box<D> +{ +protected: + /// + Point<D> c; + /// + double diam; + /// + double inner; +public: + /// + BoxSphere () { }; + /// + BoxSphere (const Box<D> & box) + : Box<D> (box) + { + CalcDiamCenter(); + }; + + /// + BoxSphere ( Point<D> pmin, Point<D> pmax ) + : Box<D> (pmin, pmax) + { + CalcDiamCenter(); + } + + /// + const Point<D> & Center () const { return c; } + /// + double Diam () const { return diam; } + /// + double Inner () const { return inner; } + + + /// + void GetSubBox (int nr, BoxSphere & sbox) const + { + for (int i = 0; i < D; i++) + { + if (nr & 1) + { + sbox.pmin(i) = c(i); + sbox.pmax(i) = this->pmax(i); + } + else + { + sbox.pmin(i) = this->pmin(i); + sbox.pmax(i) = c(i); + } + sbox.c(i) = 0.5 * (sbox.pmin(i) + sbox.pmax(i)); + nr >>= 1; + } + sbox.diam = 0.5 * diam; + sbox.inner = 0.5 * inner; + } + + + /// + void CalcDiamCenter () + { + c = Box<D>::Center (); + diam = Dist (this->pmin, this->pmax); + + inner = this->pmax(0) - this->pmin(0); + for (int i = 1; i < D; i++) + if (this->pmax(i) - this->pmin(i) < inner) + inner = this->pmax(i) - this->pmin(i); + } + +}; + + + + + + +#endif diff --git a/contrib/Netgen/libsrc/gprim/geomobjects2.hpp b/contrib/Netgen/libsrc/gprim/geomobjects2.hpp new file mode 100644 index 0000000000..014a38525a --- /dev/null +++ b/contrib/Netgen/libsrc/gprim/geomobjects2.hpp @@ -0,0 +1,366 @@ +#ifndef FILE_OBJECTS +#define FILE_OBJECTS + +/* *************************************************************************/ +/* File: geomobjects.hpp */ +/* Author: Joachim Schoeberl */ +/* Date: 20. Jul. 02 */ +/* *************************************************************************/ + +template <typename T> +class VecExpr +{ +public: + VecExpr () { ; } + double operator() (int i) const { return static_cast<const T&> (*this) (i); } +}; + + +template <int D> class Vec; +template <int D> class Point; + + +template <int D> +class Point : public VecExpr<Point<D> > +{ + +protected: + double x[D]; + +public: + Point () { ; } + Point (double ax) { x[0] = ax; } + Point (double ax, double ay) { x[0] = ax; x[1] = ay; } + Point (double ax, double ay, double az) + { x[0] = ax; x[1] = ay; x[2] = az; } + Point (double ax, double ay, double az, double au) + { x[0] = ax; x[1] = ay; x[2] = az; x[3] = au;} + + Point (const Point<D> & p2) + { for (int i = 0; i < D; i++) x[i] = p2.x[i]; } + + explicit Point (const Vec<D> & v) + { for (int i = 0; i < D; i++) x[i] = v(i); } + + + template <typename T> + explicit Point (const VecExpr<T> & expr) + { + for (int i = 0; i < D; i++) x[i] = expr(i); + } + + Point & operator= (const Point<D> & p2) + { + for (int i = 0; i < D; i++) x[i] = p2.x[i]; + return *this; + } + + template <typename T> + Point & operator= (const VecExpr<T> & expr) + { + for (int i = 0; i < D; i++) x[i] = expr(i); + return *this; + } + + double & operator() (int i) { return x[i]; } + const double & operator() (int i) const { return x[i]; } + + operator const double* () const { return x; } +}; + + + + + +template <int D> +class Vec : public VecExpr<Vec<D> > +{ + +protected: + double x[D]; + +public: + Vec () { ; } + Vec (double ax) { for (int i = 0; i < D; i++) x[i] = ax; } + Vec (double ax, double ay) { x[0] = ax; x[1] = ay; } + Vec (double ax, double ay, double az) + { x[0] = ax; x[1] = ay; x[2] = az; } + Vec (double ax, double ay, double az, double au) + { x[0] = ax; x[1] = ay; x[2] = az; x[3] = au; } + + Vec (const Vec<D> & p2) + { for (int i = 0; i < D; i++) x[i] = p2.x[i]; } + + explicit Vec (const Point<D> & p) + { for (int i = 0; i < D; i++) x[i] = p(i); } + + template <typename T> + explicit Vec (const VecExpr<T> & expr) + { + for (int i = 0; i < D; i++) x[i] = expr(i); + } + + + Vec & operator= (const Vec<D> & p2) + { + for (int i = 0; i < D; i++) x[i] = p2.x[i]; + return *this; + } + + template <typename T> + Vec & operator= (const VecExpr<T> & expr) + { + for (int i = 0; i < D; i++) x[i] = expr(i); + return *this; + } + + Vec & operator= (double s) + { + for (int i = 0; i < D; i++) x[i] = s; + return *this; + } + + double & operator() (int i) { return x[i]; } + const double & operator() (int i) const { return x[i]; } + + operator const double* () const { return x; } + + double Length () const + { + double l = 0; + for (int i = 0; i < D; i++) + l += x[i] * x[i]; + return sqrt (l); + } + + double Length2 () const + { + double l = 0; + for (int i = 0; i < D; i++) + l += x[i] * x[i]; + return l; + } + + const Vec<D> & Normalize () + { + double l = Length(); + if (l != 0) + for (int i = 0; i < D; i++) + x[i] /= l; + return *this; + } + + Vec<D> GetNormal () const; +}; + + + + + +template <int H, int W=H> +class Mat +{ + +protected: + double x[H*W]; + +public: + Mat () { ; } + Mat (const Mat & b) + { for (int i = 0; i < H*W; i++) x[i] = b.x[i]; } + + Mat & operator= (double s) + { + for (int i = 0; i < H*W; i++) x[i] = s; + return *this; + } + + Mat & operator= (const Mat & b) + { + for (int i = 0; i < H*W; i++) x[i] = b.x[i]; + return *this; + } + + double & operator() (int i, int j) { return x[i*W+j]; } + const double & operator() (int i, int j) const { return x[i*W+j]; } + + Vec<H> Col (int i) const + { + Vec<H> hv; + for (int j = 0; j < H; j++) + hv(j) = x[j*W+i]; + return hv; + } + + Vec<W> Row (int i) const + { + Vec<W> hv; + for (int j = 0; j < W; j++) + hv(j) = x[i*W+j]; + return hv; + } + + void Solve (const Vec<H> & rhs, Vec<W> & sol) const + { + Mat<W,H> inv; + CalcInverse (*this, inv); + sol = inv * rhs; + } +}; + + + + +template <int D> +class Box +{ +protected: + Point<D> pmin, pmax; +public: + Box () { ; } + Box ( const Point<D> & p1, const Point<D> & p2) + { + for (int i = 0; i < D; i++) + { + pmin(i) = min2(p1(i), p2(i)); + pmax(i) = max2(p1(i), p2(i)); + } + } + + const Point<D> & PMin () const { return pmin; } + const Point<D> & PMax () const { return pmax; } + + void Set (const Point<D> & p) + { pmin = pmax = p; } + + void Add (const Point<D> & p) + { + for (int i = 0; i < D; i++) + { + if (p(i) < pmin(i)) pmin(i) = p(i); + else if (p(i) > pmax(i)) pmax(i) = p(i); + } + } + + Point<D> Center () const + { + Point<D> c; + for (int i = 0; i < D; i++) + c(i) = 0.5 * (pmin(i)+pmax(i)); + return c; + } + double Diam () const { return Abs (pmax-pmin); } + + Point<D> GetPointNr (int nr) const + { + Point<D> p; + for (int i = 0; i < D; i++) + { + p(i) = (nr & 1) ? pmax(i) : pmin(i); + nr >>= 1; + } + return p; + } + + + bool Intersect (const Box<D> & box2) const + { + for (int i = 0; i < D; i++) + if (pmin(i) > box2.pmax(i) || + pmax(i) < box2.pmin(i)) return 0; + return 1; + } + + + bool IsIn (const Point<D> & p) const + { + for (int i = 0; i < D; i++) + if (p(i) < pmin(i) || p(i) > pmax(i)) return 0; + return 1; + } + + + void Increase (double dist) + { + for (int i = 0; i < D; i++) + { + pmin(i) -= dist; + pmax(i) += dist; + } + } +}; + + + + +template <int D> +class BoxSphere : public Box<D> +{ +protected: + /// + Point<D> c; + /// + double diam; + /// + double inner; +public: + /// + BoxSphere () { }; + /// + BoxSphere ( Point<D> pmin, Point<D> pmax ) + : Box<D> (pmin, pmax) + { + CalcDiamCenter(); + } + + /// + const Point<D> & Center () const { return c; } + /// + double Diam () const { return diam; } + /// + double Inner () const { return inner; } + + + /// + void GetSubBox (int nr, BoxSphere & sbox) const + { + for (int i = 0; i < D; i++) + { + if (nr & 1) + { + sbox.pmin(i) = c(i); + sbox.pmax(i) = this->pmax(i); + } + else + { + sbox.pmin(i) = this->pmin(i); + sbox.pmax(i) = c(i); + } + sbox.c(i) = 0.5 * (sbox.pmin(i) + sbox.pmax(i)); + nr >>= 1; + } + sbox.diam = 0.5 * diam; + sbox.inner = 0.5 * inner; + } + + + /// + void CalcDiamCenter () + { + c = Box<D>::Center (); + diam = Dist (this->pmin, this->pmax); + + inner = this->pmax(0) - this->pmin(0); + for (int i = 1; i < D; i++) + if (this->pmax(i) - this->pmin(i) < inner) + inner = this->pmax(i) - this->pmin(i); + } + +}; + + + + + + +#endif diff --git a/contrib/Netgen/libsrc/gprim/geomops.hpp b/contrib/Netgen/libsrc/gprim/geomops.hpp new file mode 100644 index 0000000000..755f35a878 --- /dev/null +++ b/contrib/Netgen/libsrc/gprim/geomops.hpp @@ -0,0 +1,391 @@ +#ifndef FILE_GEOMOPS +#define FILE_GEOMOPS + +/* *************************************************************************/ +/* File: geomops.hpp */ +/* Author: Joachim Schoeberl */ +/* Date: 20. Jul. 02 */ +/* *************************************************************************/ + + +/* + +Point - Vector operations + + */ + + +template <int D> +inline Vec<D> operator+ (const Vec<D> & a, const Vec<D> & b) +{ + Vec<D> res; + for (int i = 0; i < D; i++) + res(i) = a(i) + b(i); + return res; +} + + + +template <int D> +inline Point<D> operator+ (const Point<D> & a, const Vec<D> & b) +{ + Point<D> res; + for (int i = 0; i < D; i++) + res(i) = a(i) + b(i); + return res; +} + + + +template <int D> +inline Vec<D> operator- (const Point<D> & a, const Point<D> & b) +{ + Vec<D> res; + for (int i = 0; i < D; i++) + res(i) = a(i) - b(i); + return res; +} + +template <int D> +inline Point<D> operator- (const Point<D> & a, const Vec<D> & b) +{ + Point<D> res; + for (int i = 0; i < D; i++) + res(i) = a(i) - b(i); + return res; +} + +template <int D> +inline Vec<D> operator- (const Vec<D> & a, const Vec<D> & b) +{ + Vec<D> res; + for (int i = 0; i < D; i++) + res(i) = a(i) - b(i); + return res; +} + + + +template <int D> +inline Vec<D> operator* (double s, const Vec<D> & b) +{ + Vec<D> res; + for (int i = 0; i < D; i++) + res(i) = s * b(i); + return res; +} + + +template <int D> +inline double operator* (const Vec<D> & a, const Vec<D> & b) +{ + double sum = 0; + for (int i = 0; i < D; i++) + sum += a(i) * b(i); + return sum; +} + + + +template <int D> +inline Vec<D> operator- (const Vec<D> & b) +{ + Vec<D> res; + for (int i = 0; i < D; i++) + res(i) = -b(i); + return res; +} + + +template <int D> +inline Point<D> & operator+= (Point<D> & a, const Vec<D> & b) +{ + for (int i = 0; i < D; i++) + a(i) += b(i); + return a; +} + +template <int D> +inline Vec<D> & operator+= (Vec<D> & a, const Vec<D> & b) +{ + for (int i = 0; i < D; i++) + a(i) += b(i); + return a; +} + + +template <int D> +inline Point<D> & operator-= (Point<D> & a, const Vec<D> & b) +{ + for (int i = 0; i < D; i++) + a(i) -= b(i); + return a; +} + +template <int D> +inline Vec<D> & operator-= (Vec<D> & a, const Vec<D> & b) +{ + for (int i = 0; i < D; i++) + a(i) -= b(i); + return a; +} + + + +template <int D> +inline Vec<D> & operator*= (Vec<D> & a, double s) +{ + for (int i = 0; i < D; i++) + a(i) *= s; + return a; +} + + +template <int D> +inline Vec<D> & operator/= (Vec<D> & a, double s) +{ + for (int i = 0; i < D; i++) + a(i) /= s; + return a; +} + + + + +// Matrix - Vector operations + +/* +template <int H, int W> +inline Vec<H> operator* (const Mat<H,W> & m, const Vec<W> & v) +{ + Vec<H> res; + for (int i = 0; i < H; i++) + { + res(i) = 0; + for (int j = 0; j < W; j++) + res(i) += m(i,j) * v(j); + } + return res; +} +*/ + +// thanks to VC60 partial template specialization features !!! + +inline Vec<2> operator* (const Mat<2,2> & m, const Vec<2> & v) +{ + Vec<2> res; + for (int i = 0; i < 2; i++) + { + res(i) = 0; + for (int j = 0; j < 2; j++) + res(i) += m(i,j) * v(j); + } + return res; +} + +inline Vec<2> operator* (const Mat<2,3> & m, const Vec<3> & v) +{ + Vec<2> res; + for (int i = 0; i < 2; i++) + { + res(i) = 0; + for (int j = 0; j < 3; j++) + res(i) += m(i,j) * v(j); + } + return res; +} + + +inline Vec<3> operator* (const Mat<3,2> & m, const Vec<2> & v) +{ + Vec<3> res; + for (int i = 0; i < 3; i++) + { + res(i) = 0; + for (int j = 0; j < 2; j++) + res(i) += m(i,j) * v(j); + } + return res; +} + + +inline Vec<3> operator* (const Mat<3,3> & m, const Vec<3> & v) +{ + Vec<3> res; + for (int i = 0; i < 3; i++) + { + res(i) = 0; + for (int j = 0; j < 3; j++) + res(i) += m(i,j) * v(j); + } + return res; +} + + + + + + + +/* +template <int H1, int W1, int H2, int W2> +inline Mat<H1,W2> operator* (const Mat<H1,W1> & a, const Mat<H2,W2> & b) +{ + Mat<H1,W2> m; + for (int i = 0; i < H1; i++) + for (int j = 0; j < W2; j++) + { + double sum = 0; + for (int k = 0; k < W1; k++) + sum += a(i,k) * b(k, j); + m(i,j) = sum; + } + return m; +} +*/ + +inline Mat<2,2> operator* (const Mat<2,2> & a, const Mat<2,2> & b) +{ + Mat<2,2> m; + for (int i = 0; i < 2; i++) + for (int j = 0; j < 2; j++) + { + double sum = 0; + for (int k = 0; k < 2; k++) + sum += a(i,k) * b(k, j); + m(i,j) = sum; + } + return m; +} + +inline Mat<2,2> operator* (const Mat<2,3> & a, const Mat<3,2> & b) +{ + Mat<2,2> m; + for (int i = 0; i < 2; i++) + for (int j = 0; j < 2; j++) + { + double sum = 0; + for (int k = 0; k < 3; k++) + sum += a(i,k) * b(k, j); + m(i,j) = sum; + } + return m; +} + + +inline Mat<3,2> operator* (const Mat<3,2> & a, const Mat<2,2> & b) +{ + Mat<3,2> m; + for (int i = 0; i < 3; i++) + for (int j = 0; j < 2; j++) + { + double sum = 0; + for (int k = 0; k < 2; k++) + sum += a(i,k) * b(k, j); + m(i,j) = sum; + } + return m; +} + + + +inline Mat<2,3> operator* (const Mat<2,2> & a, const Mat<2,3> & b) +{ + Mat<2,3> m; + for (int i = 0; i < 2; i++) + for (int j = 0; j < 3; j++) + { + double sum = 0; + for (int k = 0; k < 2; k++) + sum += a(i,k) * b(k, j); + m(i,j) = sum; + } + return m; +} + + +inline Mat<3,3> operator* (const Mat<3,3> & a, const Mat<3,3> & b) +{ + Mat<3,3> m; + for (int i = 0; i < 3; i++) + for (int j = 0; j < 3; j++) + { + double sum = 0; + for (int k = 0; k < 3; k++) + sum += a(i,k) * b(k, j); + m(i,j) = sum; + } + return m; +} + + + + + + + + +template <int H, int W> +inline Mat<W,H> Trans (const Mat<H,W> & m) +{ + Mat<W,H> res; + for (int i = 0; i < H; i++) + for (int j = 0; j < W; j++) + res(j,i) = m(i,j); + return res; +} + + + + + + + + + + + +template <int D> +inline ostream & operator<< (ostream & ost, const Vec<D> & a) +{ + ost << "("; + for (int i = 0; i < D-1; i++) + ost << a(i) << ", "; + ost << a(D-1) << ")"; + return ost; +} + +template <int D> +inline ostream & operator<< (ostream & ost, const Point<D> & a) +{ + ost << "("; + for (int i = 0; i < D-1; i++) + ost << a(i) << ", "; + ost << a(D-1) << ")"; + return ost; +} + +template <int D> +inline ostream & operator<< (ostream & ost, const Box<D> & b) +{ + ost << b.PMin() << " - " << b.PMax(); + return ost; +} + +template <int H, int W> +inline ostream & operator<< (ostream & ost, const Mat<H,W> & m) +{ + ost << "("; + for (int i = 0; i < H; i++) + { + for (int j = 0; j < W; j++) + ost << m(i,j) << " "; + ost << endl; + } + return ost; +} + + + + +#endif diff --git a/contrib/Netgen/libsrc/gprim/geomops2.hpp b/contrib/Netgen/libsrc/gprim/geomops2.hpp new file mode 100644 index 0000000000..c615da14ec --- /dev/null +++ b/contrib/Netgen/libsrc/gprim/geomops2.hpp @@ -0,0 +1,428 @@ +#ifndef FILE_GEOMOPS +#define FILE_GEOMOPS + +/* *************************************************************************/ +/* File: geomops.hpp */ +/* Author: Joachim Schoeberl */ +/* Date: 20. Jul. 02 */ +/* *************************************************************************/ + + +/* + +Point - Vector operations + + */ + + + + +template <class TA, class TB> +class SumExpr : public VecExpr<SumExpr<TA, TB> > +{ + const TA a; + const TB b; +public: + SumExpr (const TA aa, const TB ab) : a(aa), b(ab) { ; } + double operator() (int i) const { return a(i) + b(i); } +}; + +template <typename TA, typename TB> +inline SumExpr<TA,TB> +operator+ (const VecExpr<TA> & a, const VecExpr<TB> & b) +{ + return SumExpr<TA,TB> (static_cast <const TA&> (a), static_cast <const TB&> (b)); +} + +/* +template <int D1, int D2> +inline SumExpr<const Vec<D1>&, const Vec<D2>&> +operator+ (const Vec<D1> & a, const Vec<D2> & b) +{ + return SumExpr<const Vec<D1>&, const Vec<D2>&> (a, b); +} +*/ + + + + + +/* +template <int D> +inline Vec<D> operator+ (const Vec<D> & a, const Vec<D> & b) +{ + Vec<D> res; + for (int i = 0; i < D; i++) + res(i) = a(i) + b(i); + return res; +} +*/ + +template <int D> +inline Point<D> operator+ (const Point<D> & a, const Vec<D> & b) +{ + Point<D> res; + for (int i = 0; i < D; i++) + res(i) = a(i) + b(i); + return res; +} + + +template <int D> +inline Vec<D> operator- (const Point<D> & a, const Point<D> & b) +{ + Vec<D> res; + for (int i = 0; i < D; i++) + res(i) = a(i) - b(i); + return res; +} + +template <int D> +inline Point<D> operator- (const Point<D> & a, const Vec<D> & b) +{ + Point<D> res; + for (int i = 0; i < D; i++) + res(i) = a(i) - b(i); + return res; +} + +template <int D> +inline Vec<D> operator- (const Vec<D> & a, const Vec<D> & b) +{ + Vec<D> res; + for (int i = 0; i < D; i++) + res(i) = a(i) - b(i); + return res; +} + + +template <int D> +inline Vec<D> operator* (double s, const Vec<D> & b) +{ + Vec<D> res; + for (int i = 0; i < D; i++) + res(i) = s * b(i); + return res; +} + + +template <int D> +inline double operator* (const Vec<D> & a, const Vec<D> & b) +{ + double sum = 0; + for (int i = 0; i < D; i++) + sum += a(i) * b(i); + return sum; +} + + + +template <int D> +inline Vec<D> operator- (const Vec<D> & b) +{ + Vec<D> res; + for (int i = 0; i < D; i++) + res(i) = -b(i); + return res; +} + + +template <int D> +inline Point<D> & operator+= (Point<D> & a, const Vec<D> & b) +{ + for (int i = 0; i < D; i++) + a(i) += b(i); + return a; +} + + +template <int D, typename T> +inline Point<D> & operator+= (Point<D> & a, const VecExpr<T> & b) +{ + for (int i = 0; i < D; i++) + a(i) += b(i); + return a; +} + +template <int D> +inline Vec<D> & operator+= (Vec<D> & a, const Vec<D> & b) +{ + for (int i = 0; i < D; i++) + a(i) += b(i); + return a; +} + + + + + +template <int D> +inline Point<D> & operator-= (Point<D> & a, const Vec<D> & b) +{ + for (int i = 0; i < D; i++) + a(i) -= b(i); + return a; +} + +template <int D, typename T> +inline Point<D> & operator-= (Point<D> & a, const VecExpr<T> & b) +{ + for (int i = 0; i < D; i++) + a(i) -= b(i); + return a; +} + + + + + +template <int D> +inline Vec<D> & operator-= (Vec<D> & a, const Vec<D> & b) +{ + for (int i = 0; i < D; i++) + a(i) -= b(i); + return a; +} + + + +template <int D> +inline Vec<D> & operator*= (Vec<D> & a, double s) +{ + for (int i = 0; i < D; i++) + a(i) *= s; + return a; +} + + +template <int D> +inline Vec<D> & operator/= (Vec<D> & a, double s) +{ + for (int i = 0; i < D; i++) + a(i) /= s; + return a; +} + + + + +// Matrix - Vector operations + +/* +template <int H, int W> +inline Vec<H> operator* (const Mat<H,W> & m, const Vec<W> & v) +{ + Vec<H> res; + for (int i = 0; i < H; i++) + { + res(i) = 0; + for (int j = 0; j < W; j++) + res(i) += m(i,j) * v(j); + } + return res; +} +*/ + +// thanks to VC60 partial template specialization features !!! + +inline Vec<2> operator* (const Mat<2,2> & m, const Vec<2> & v) +{ + Vec<2> res; + for (int i = 0; i < 2; i++) + { + res(i) = 0; + for (int j = 0; j < 2; j++) + res(i) += m(i,j) * v(j); + } + return res; +} + +inline Vec<2> operator* (const Mat<2,3> & m, const Vec<3> & v) +{ + Vec<2> res; + for (int i = 0; i < 2; i++) + { + res(i) = 0; + for (int j = 0; j < 3; j++) + res(i) += m(i,j) * v(j); + } + return res; +} + + +inline Vec<3> operator* (const Mat<3,2> & m, const Vec<2> & v) +{ + Vec<3> res; + for (int i = 0; i < 3; i++) + { + res(i) = 0; + for (int j = 0; j < 2; j++) + res(i) += m(i,j) * v(j); + } + return res; +} + + +inline Vec<3> operator* (const Mat<3,3> & m, const Vec<3> & v) +{ + Vec<3> res; + for (int i = 0; i < 3; i++) + { + res(i) = 0; + for (int j = 0; j < 3; j++) + res(i) += m(i,j) * v(j); + } + return res; +} + + + + + + + +/* +template <int H1, int W1, int H2, int W2> +inline Mat<H1,W2> operator* (const Mat<H1,W1> & a, const Mat<H2,W2> & b) +{ + Mat<H1,W2> m; + for (int i = 0; i < H1; i++) + for (int j = 0; j < W2; j++) + { + double sum = 0; + for (int k = 0; k < W1; k++) + sum += a(i,k) * b(k, j); + m(i,j) = sum; + } + return m; +} +*/ + +inline Mat<2,2> operator* (const Mat<2,2> & a, const Mat<2,2> & b) +{ + Mat<2,2> m; + for (int i = 0; i < 2; i++) + for (int j = 0; j < 2; j++) + { + double sum = 0; + for (int k = 0; k < 2; k++) + sum += a(i,k) * b(k, j); + m(i,j) = sum; + } + return m; +} + +inline Mat<2,2> operator* (const Mat<2,3> & a, const Mat<3,2> & b) +{ + Mat<2,2> m; + for (int i = 0; i < 2; i++) + for (int j = 0; j < 2; j++) + { + double sum = 0; + for (int k = 0; k < 3; k++) + sum += a(i,k) * b(k, j); + m(i,j) = sum; + } + return m; +} + + +inline Mat<3,2> operator* (const Mat<3,2> & a, const Mat<2,2> & b) +{ + Mat<3,2> m; + for (int i = 0; i < 3; i++) + for (int j = 0; j < 2; j++) + { + double sum = 0; + for (int k = 0; k < 2; k++) + sum += a(i,k) * b(k, j); + m(i,j) = sum; + } + return m; +} + +inline Mat<3,3> operator* (const Mat<3,3> & a, const Mat<3,3> & b) +{ + Mat<3,3> m; + for (int i = 0; i < 3; i++) + for (int j = 0; j < 3; j++) + { + double sum = 0; + for (int k = 0; k < 3; k++) + sum += a(i,k) * b(k, j); + m(i,j) = sum; + } + return m; +} + + + + + + + + +template <int H, int W> +inline Mat<W,H> Trans (const Mat<H,W> & m) +{ + Mat<W,H> res; + for (int i = 0; i < H; i++) + for (int j = 0; j < W; j++) + res(j,i) = m(i,j); + return res; +} + + + + + + + + + + + +template <int D> +inline ostream & operator<< (ostream & ost, const Vec<D> & a) +{ + ost << "("; + for (int i = 0; i < D-1; i++) + ost << a(i) << ", "; + ost << a(D-1) << ")"; + return ost; +} + +template <int D> +inline ostream & operator<< (ostream & ost, const Point<D> & a) +{ + ost << "("; + for (int i = 0; i < D-1; i++) + ost << a(i) << ", "; + ost << a(D-1) << ")"; + return ost; +} + +template <int D> +inline ostream & operator<< (ostream & ost, const Box<D> & b) +{ + ost << b.PMin() << " - " << b.PMax(); + return ost; +} + +template <int H, int W> +inline ostream & operator<< (ostream & ost, const Mat<H,W> & m) +{ + ost << "("; + for (int i = 0; i < H; i++) + { + for (int j = 0; j < W; j++) + ost << m(i,j) << " "; + ost << endl; + } + return ost; +} + + + + +#endif diff --git a/contrib/Netgen/libsrc/gprim/geomtest3d.cpp b/contrib/Netgen/libsrc/gprim/geomtest3d.cpp new file mode 100644 index 0000000000..14d1d58bd1 --- /dev/null +++ b/contrib/Netgen/libsrc/gprim/geomtest3d.cpp @@ -0,0 +1,1223 @@ +#include <mystdlib.h> +#include <myadt.hpp> + +#include <linalg.hpp> +#include <gprim.hpp> + +namespace netgen +{ +int +IntersectTriangleLine (const Point3d ** tri, const Point3d ** line) +{ + Vec3d vl(*line[0], *line[1]); + Vec3d vt1(*tri[0], *tri[1]); + Vec3d vt2(*tri[0], *tri[2]); + Vec3d vrs(*tri[0], *line[0]); + + static DenseMatrix a(3), ainv(3); + static Vector rs(3), lami(3); + int i; + + /* + (*testout) << "Tri-Line inters: " << endl + << "tri = " << *tri[0] << ", " << *tri[1] << ", " << *tri[2] << endl + << "line = " << *line[0] << ", " << *line[1] << endl; + */ + for (i = 1; i <= 3; i++) + { + a.Elem(i, 1) = -vl.X(i); + a.Elem(i, 2) = vt1.X(i); + a.Elem(i, 3) = vt2.X(i); + rs.Elem(i) = vrs.X(i); + } + + double det = a.Det(); + + double arel = vl.Length() * vt1.Length() * vt2.Length(); + /* + double amax = 0; + for (i = 1; i <= 9; i++) + if (fabs (a.Get(i)) > amax) + amax = fabs(a.Get(i)); + */ + // new !!!! + if (fabs (det) <= 1e-10 * arel) + { +#ifdef DEVELOP + // line parallel to triangle ! + // cout << "ERROR: IntersectTriangleLine degenerated" << endl; + // (*testout) << "WARNING: IntersectTriangleLine degenerated\n"; + /* + (*testout) << "lin-tri intersection: " << endl + << "line = " << *line[0] << " - " << *line[1] << endl + << "tri = " << *tri[0] << " - " << *tri[1] << " - " << *tri[2] << endl + << "lami = " << lami << endl + << "pc = " << ( *line[0] + lami.Get(1) * vl ) << endl + << " = " << ( *tri[0] + lami.Get(2) * vt1 + lami.Get(3) * vt2) << endl + << " a = " << a << endl + << " ainv = " << ainv << endl + << " det(a) = " << det << endl + << " rs = " << rs << endl; + */ +#endif + return 0; + } + + CalcInverse (a, ainv); + ainv.Mult (rs, lami); + + // (*testout) << "lami = " << lami << endl; + + double eps = 1e-6; + if ( + (lami.Get(1) >= -eps && lami.Get(1) <= 1+eps && + lami.Get(2) >= -eps && lami.Get(3) >= -eps && + lami.Get(2) + lami.Get(3) <= 1+eps) && ! + (lami.Get(1) >= eps && lami.Get(1) <= 1-eps && + lami.Get(2) >= eps && lami.Get(3) >= eps && + lami.Get(2) + lami.Get(3) <= 1-eps) ) + + + { +#ifdef DEVELOP + // cout << "WARNING: IntersectTriangleLine degenerated" << endl; + (*testout) << "WARNING: IntersectTriangleLine numerical inexact" << endl; + + (*testout) << "lin-tri intersection: " << endl + << "line = " << *line[0] << " - " << *line[1] << endl + << "tri = " << *tri[0] << " - " << *tri[1] << " - " << *tri[2] << endl + << "lami = " << lami << endl + << "pc = " << ( *line[0] + lami.Get(1) * vl ) << endl + << " = " << ( *tri[0] + lami.Get(2) * vt1 + lami.Get(3) * vt2) << endl + << " a = " << a << endl + << " ainv = " << ainv << endl + << " det(a) = " << det << endl + << " rs = " << rs << endl; +#endif + } + + + if (lami.Get(1) >= 0 && lami.Get(1) <= 1 && + lami.Get(2) >= 0 && lami.Get(3) >= 0 && lami.Get(2) + lami.Get(3) <= 1) + { + + return 1; + } + + return 0; +} + + + + + +int IntersectTetTriangle (const Point3d ** tet, const Point3d ** tri, + const int * tetpi, const int * tripi) +{ + int i, j; + double diam = Dist (*tri[0], *tri[1]); + double epsrel = 1e-8; + double eps = diam * epsrel; + +#ifdef MARK + MARK (inttettri1); +#endif + + double eps2 = eps * eps; + int loctripi[3], cnt = 0; + int loctetpi[4]; + + int tetp1 = -1, tetp2 = -1; + int trip1 = -1, trip2 = -1; + int tetp3, tetp4, trip3; + + /* + for (i = 0; i < 4; i++) + loctetpi[i] = -1; + */ + + + if (!tetpi) + { + for (i = 0; i <= 2; i++) + { + // loctripi[i] = -1; + for (j = 0; j <= 3; j++) + { + if (Dist2 (*tet[j], *tri[i]) < eps2) + { + // loctripi[i] = j; + // loctetpi[j] = i; + cnt++; + tetp2 = tetp1; + tetp1 = j; + trip2 = trip1; + trip1 = i; + break; + } + } + } + } + else + { + for (i = 0; i <= 2; i++) + { + // loctripi[i] = -1; + for (j = 0; j <= 3; j++) + { + if (tetpi[j] == tripi[i]) + { + // loctripi[i] = j; + // loctetpi[j] = i; + cnt++; + tetp2 = tetp1; + tetp1 = j; + trip2 = trip1; + trip1 = i; + break; + } + } + } + } + + // (*testout) << "cnt = " << cnt << endl; + +#ifdef MARK + MARK (inttettri2); +#endif + + + // (*testout) << "tet-trig inters, cnt = " << cnt << endl; + + // cnt .. number of common points + switch (cnt) + { + case 0: + { +#ifdef MARK + MARK (inttettric0); +#endif + + Vec3d no, n; + int inpi[3]; + + // check, if some trigpoint is in tet: + + for (j = 0; j < 3; j++) + inpi[j] = 1; + + for (i = 1; i <= 4; i++) + { + int pi1 = i % 4; + int pi2 = (i+1) % 4; + int pi3 = (i+2) % 4; + int pi4 = (i+3) % 4; + + Vec3d v1 (*tet[pi1], *tet[pi2]); + Vec3d v2 (*tet[pi1], *tet[pi3]); + Vec3d v3 (*tet[pi1], *tet[pi4]); + Cross (v1, v2, n); + + // n /= n.Length(); + double nl = n.Length(); + + if (v3 * n > 0) + n *= -1; + + int outeri = 1; + for (j = 0; j < 3; j++) + { + Vec3d v(*tet[pi1], *tri[j]); + if ( v * n < eps * nl) + outeri = 0; + else + inpi[j] = 0; + } + + if (outeri) + return 0; + } + + if (inpi[0] || inpi[1] || inpi[2]) + { + return 1; + } + + + // check, if some tet edge intersects triangle: + const Point3d * line[2], *tetf[3]; + for (i = 0; i <= 2; i++) + for (j = i+1; j <= 3; j++) + { + line[0] = tet[i]; + line[1] = tet[j]; + + if (IntersectTriangleLine (tri, &line[0])) + return 1; + } + + // check, if triangle line intersects tet face: + for (i = 0; i <= 3; i++) + { + for (j = 0; j <= 2; j++) + tetf[j] = tet[(i+j) % 4]; + + for (j = 0; j <= 2; j++) + { + line[0] = tri[j]; + line[1] = tri[(j+1) % 3]; + + if (IntersectTriangleLine (&tetf[0], &line[0])) + return 1; + } + } + + + return 0; +//GH break; + } + case 1: + { +#ifdef MARK + MARK (inttettric1); +#endif + + trip2 = 0; + while (trip2 == trip1) + trip2++; + trip3 = 3 - trip1 - trip2; + + tetp2 = 0; + while (tetp2 == tetp1) + tetp2++; + tetp3 = 0; + while (tetp3 == tetp1 || tetp3 == tetp2) + tetp3++; + tetp4 = 6 - tetp1 - tetp2 - tetp3; + + Vec3d vtri1 = *tri[trip2] - *tri[trip1]; + Vec3d vtri2 = *tri[trip3] - *tri[trip1]; + Vec3d ntri; + Cross (vtri1, vtri2, ntri); + + // tri durch tet ? + // fehlt noch + + + // test 3 tet-faces: + for (i = 1; i <= 3; i++) + { + Vec3d vtet1, vtet2; + switch (i) + { + case 1: + { + vtet1 = *tet[tetp2] - *tet[tetp1]; + vtet2 = *tet[tetp3] - *tet[tetp1]; + break; + } + case 2: + { + vtet1 = *tet[tetp3] - *tet[tetp1]; + vtet2 = *tet[tetp4] - *tet[tetp1]; + break; + } + case 3: + { + vtet1 = *tet[tetp4] - *tet[tetp1]; + vtet2 = *tet[tetp2] - *tet[tetp1]; + break; + } + } + + Vec3d ntet; + Cross (vtet1, vtet2, ntet); + + Vec3d crline = Cross (ntri, ntet); + + double lcrline = crline.Length(); + + if (lcrline < eps * eps * eps * eps) // new change ! + continue; + + if (vtri1 * crline + vtri2 * crline < 0) + crline *= -1; + + crline /= lcrline; + + double lam1, lam2, lam3, lam4; + LocalCoordinates (vtri1, vtri2, crline, lam1, lam2); + LocalCoordinates (vtet1, vtet2, crline, lam3, lam4); + + if (lam1 > -epsrel && lam2 > -epsrel && + lam3 > -epsrel && lam4 > -epsrel) + { + + /* + (*testout) << "lcrline = " << lcrline + << " eps = " << eps << " diam = " << diam << endl; + + (*testout) << "hit, cnt == 1 " + << "lam1,2,3,4 = " << lam1 << ", " + << lam2 << ", " << lam3 << ", " << lam4 + << "\n"; + */ + return 1; + } + } + return 0; +//GH break; + } + case 2: + { +#ifdef MARK + MARK (inttettric2); +#endif + + // common edge + tetp3 = 0; + while (tetp3 == tetp1 || tetp3 == tetp2) + tetp3++; + tetp4 = 6 - tetp1 - tetp2 - tetp3; + trip3 = 3 - trip1 - trip2; + + // (*testout) << "trip1,2,3 = " << trip1 << ", " << trip2 << ", " << trip3 << endl; + // (*testout) << "tetp1,2,3,4 = " << tetp1 << ", " << tetp2 + // << ", " << tetp3 << ", " << tetp4 << endl; + + Vec3d vtri = *tri[trip3] - *tri[trip1]; + Vec3d vtet1 = *tet[tetp3] - *tri[trip1]; + Vec3d vtet2 = *tet[tetp4] - *tri[trip1]; + + Vec3d n = *tri[trip2] - *tri[trip1]; + n /= n.Length(); + + vtet1 -= (n * vtet1) * n; + vtet2 -= (n * vtet2) * n; + + + double lam1, lam2; + LocalCoordinates (vtet1, vtet2, vtri, lam1, lam2); + + if (lam1 < -epsrel || lam2 < -epsrel) + return 0; + else + { + /* + + (*testout) << "vtet1 = " << vtet1 << endl; + (*testout) << "vtet2 = " << vtet2 << endl; + (*testout) << "vtri = " << vtri << endl; + (*testout) << "lam1 = " << lam1 << " lam2 = " << lam2 << endl; + (*testout) << (lam1 * (vtet1 * vtet1) + lam2 * (vtet1 * vtet2)) + << " = " << (vtet1 * vtri) << endl; + (*testout) << (lam1 * (vtet1 * vtet2) + lam2 * (vtet2 * vtet2)) + << " = " << (vtet2 * vtri) << endl; + + (*testout) << "tet = "; + for (j = 0; j < 4; j++) + (*testout) << (*tet[j]) << " "; + (*testout) << endl; + (*testout) << "tri = "; + for (j = 0; j < 3; j++) + (*testout) << (*tri[j]) << " "; + (*testout) << endl; + + (*testout) << "hit, cnt == 2" << endl; + */ + + return 1; + } + + break; + } + case 3: + { +#ifdef MARK + MARK (inttettric3); +#endif + + // common face + return 0; + } + } + + (*testout) << "hit, cnt = " << cnt << endl; + return 1; +} + + + + + +int IntersectTetTriangleRef (const Point3d ** tri, const int * tripi) +{ + int i, j; + double eps = 1e-8; + double eps2 = eps * eps; + + static Point3d rtetp1(0, 0, 0); + static Point3d rtetp2(1, 0, 0); + static Point3d rtetp3(0, 1, 0); + static Point3d rtetp4(0, 0, 1); + + static const Point3d * tet[] = { &rtetp1, &rtetp2, &rtetp3, &rtetp4 }; + static int tetpi[] = { 1, 2, 3, 4 }; + + + // return IntersectTetTriangle (tet, tri, tetpi, tripi); + + + int cnt = 0; + + int tetp1 = -1, tetp2 = -1; + int trip1 = -1, trip2 = -1; + int tetp3, tetp4, trip3; + + + if (!tetpi) + { + for (i = 0; i <= 2; i++) + { + for (j = 0; j <= 3; j++) + { + if (Dist2 (*tet[j], *tri[i]) < eps2) + { + cnt++; + tetp2 = tetp1; + tetp1 = j; + trip2 = trip1; + trip1 = i; + break; + } + } + } + } + else + { + for (i = 0; i <= 2; i++) + { + for (j = 0; j <= 3; j++) + { + if (tetpi[j] == tripi[i]) + { + cnt++; + tetp2 = tetp1; + tetp1 = j; + trip2 = trip1; + trip1 = i; + break; + } + } + } + } + + // (*testout) << "cnt = " << cnt << endl; + +#ifdef MARK + MARK (inttettriref2); +#endif + + + switch (cnt) + { + case 0: + { +#ifdef MARK + MARK (inttettric0ref); +#endif + + Vec3d no, n; + // int inpi[3]; + int pside[3][4]; + + for (j = 0; j < 3; j++) + { + pside[j][0] = (*tri[j]).X() > -eps; + pside[j][1] = (*tri[j]).Y() > -eps; + pside[j][2] = (*tri[j]).Z() > -eps; + pside[j][3] = (*tri[j]).X() + (*tri[j]).Y() + (*tri[j]).Z() < 1+eps; + } + + + for (j = 0; j < 4; j++) + { + if (!pside[0][j] && !pside[1][j] && !pside[2][j]) + return 0; + } + + for (j = 0; j < 3; j++) + { + if (pside[j][0] && pside[j][1] && pside[j][2] && pside[j][3]) + return 1; + } + + + const Point3d * line[2], *tetf[3]; + for (i = 0; i <= 2; i++) + for (j = i+1; j <= 3; j++) + { + line[0] = tet[i]; + line[1] = tet[j]; + + if (IntersectTriangleLine (tri, &line[0])) + return 1; + } + + for (i = 0; i <= 3; i++) + { + for (j = 0; j <= 2; j++) + tetf[j] = tet[(i+j) % 4]; + + for (j = 0; j <= 2; j++) + { + line[0] = tri[j]; + line[1] = tri[(j+1) % 3]; + + if (IntersectTriangleLine (&tetf[0], &line[0])) + return 1; + } + } + + + return 0; + break; + } + case 1: + { +#ifdef MARK + MARK (inttettric1ref); +#endif + + trip2 = 0; + if (trip2 == trip1) + trip2++; + trip3 = 3 - trip1 - trip2; + + tetp2 = 0; + while (tetp2 == tetp1) + tetp2++; + tetp3 = 0; + while (tetp3 == tetp1 || tetp3 == tetp2) + tetp3++; + tetp4 = 6 - tetp1 - tetp2 - tetp3; + + Vec3d vtri1 = *tri[trip2] - *tri[trip1]; + Vec3d vtri2 = *tri[trip3] - *tri[trip1]; + Vec3d ntri; + Cross (vtri1, vtri2, ntri); + + // tri durch tet ? + + /* + Vec3d vtet1(*tet[tetp1], *tet[tetp2]); + Vec3d vtet2(*tet[tetp1], *tet[tetp3]); + Vec3d vtet3(*tet[tetp1], *tet[tetp4]); + Vec3d sol; + + SolveLinearSystem (vtet1, vtet2, vtet3, vtri1, sol); + if (sol.X() > 0 && sol.Y() > 0 && sol.Z() > 0) + return 1; + + SolveLinearSystem (vtet1, vtet2, vtet3, vtri2, sol); + if (sol.X() > 0 && sol.Y() > 0 && sol.Z() > 0) + return 1; + */ + + // test 3 tet-faces: + for (i = 1; i <= 3; i++) + { + Vec3d vtet1, vtet2; + switch (i) + { + case 1: + { + vtet1 = *tet[tetp2] - *tet[tetp1]; + vtet2 = *tet[tetp3] - *tet[tetp1]; + break; + } + case 2: + { + vtet1 = *tet[tetp3] - *tet[tetp1]; + vtet2 = *tet[tetp4] - *tet[tetp1]; + break; + } + case 3: + { + vtet1 = *tet[tetp4] - *tet[tetp1]; + vtet2 = *tet[tetp2] - *tet[tetp1]; + break; + } + } + + Vec3d ntet; + Cross (vtet1, vtet2, ntet); + + Vec3d crline = Cross (ntri, ntet); + + double lcrline = crline.Length(); + if (lcrline < eps * eps) + continue; + + + if (vtri1 * crline + vtri2 * crline < 0) + crline *= -1; + + double lam1, lam2, lam3, lam4; + LocalCoordinates (vtri1, vtri2, crline, lam1, lam2); + LocalCoordinates (vtet1, vtet2, crline, lam3, lam4); + + if (lam1 > -eps && lam2 > -eps && + lam3 > -eps && lam4 > -eps) + { + // (*testout) << "hit, cnt == 1" << "\n"; + return 1; + } + } + + return 0; + break; + } + case 2: + { +#ifdef MARK + MARK (inttettric2ref); +#endif + + // common edge + tetp3 = 0; + while (tetp3 == tetp1 || tetp3 == tetp2) + tetp3++; + tetp4 = 6 - tetp1 - tetp2 - tetp3; + trip3 = 3 - trip1 - trip2; + + // (*testout) << "trip1,2,3 = " << trip1 << ", " << trip2 << ", " << trip3 << endl; + // (*testout) << "tetp1,2,3,4 = " << tetp1 << ", " << tetp2 + // << ", " << tetp3 << ", " << tetp4 << endl; + + Vec3d vtri = *tri[trip3] - *tri[trip1]; + Vec3d vtet1 = *tet[tetp3] - *tri[trip1]; + Vec3d vtet2 = *tet[tetp4] - *tri[trip1]; + + Vec3d n = *tri[trip2] - *tri[trip1]; + n /= n.Length(); + + vtet1 -= (n * vtet1) * n; + vtet2 -= (n * vtet2) * n; + + + double lam1, lam2; + LocalCoordinates (vtet1, vtet2, vtri, lam1, lam2); + + if (lam1 < -eps || lam2 < -eps) + return 0; + else + { + +// (*testout) << "vtet1 = " << vtet1 << endl; +// (*testout) << "vtet2 = " << vtet2 << endl; +// (*testout) << "vtri = " << vtri << endl; +// (*testout) << "lam1 = " << lam1 << " lam2 = " << lam2 << endl; + +// (*testout) << (lam1 * (vtet1 * vtet1) + lam2 * (vtet1 * vtet2)) +// << " = " << (vtet1 * vtri) << endl; +// (*testout) << (lam1 * (vtet1 * vtet2) + lam2 * (vtet2 * vtet2)) +// << " = " << (vtet2 * vtri) << endl; + +// (*testout) << "tet = "; +// for (j = 0; j < 4; j++) +// (*testout) << (*tet[j]) << " "; +// (*testout) << endl; +// (*testout) << "tri = "; +// for (j = 0; j < 3; j++) +// (*testout) << (*tri[j]) << " "; +// (*testout) << endl; + +// (*testout) << "hit, cnt == 2" << endl; + + return 1; + } + + break; + } + case 3: + { +#ifdef MARK + MARK (inttettric3ref); +#endif + + // common face + return 0; + } + } + + (*testout) << "hit, cnt = " << cnt << endl; + return 1; +} + + + + + + + + + + + +int IntersectTriangleTriangle (const Point3d ** tri1, const Point3d ** tri2) +{ + int i, j; + double diam = Dist (*tri1[0], *tri1[1]); + double epsrel = 1e-8; + double eps = diam * epsrel; + double eps2 = eps * eps; + + + + int cnt = 0; + /* + int tri1pi[3]; + int tri2pi[3]; + */ + + // int tri1p1 = -1; + /// int tri1p2 = -1; + // int tri2p1 = -1; + // int tri2p2 = -1; + // int tri1p3, tri2p3; + + /* + for (i = 0; i < 3; i++) + tri1pi[i] = -1; + */ + for (i = 0; i <= 2; i++) + { + // tri2pi[i] = -1; + for (j = 0; j <= 2; j++) + { + if (Dist2 (*tri1[j], *tri2[i]) < eps2) + { + // tri2pi[i] = j; + // tri1pi[j] = i; + cnt++; + // tri1p2 = tri1p1; + // tri1p1 = j; + // tri2p2 = tri2p1; + // tri2p1 = i; + break; + } + } + } + + switch (cnt) + { + case 0: + { + const Point3d * line[2]; + + for (i = 0; i <= 2; i++) + { + line[0] = tri2[i]; + line[1] = tri2[(i+1)%3]; + + if (IntersectTriangleLine (tri1, &line[0])) + { + (*testout) << "int1, line = " << *line[0] << " - " << *line[1] << endl; + return 1; + } + } + + for (i = 0; i <= 2; i++) + { + line[0] = tri1[i]; + line[1] = tri1[(i+1)%3]; + + if (IntersectTriangleLine (tri2, &line[0])) + { + (*testout) << "int2, line = " << *line[0] << " - " << *line[1] << endl; + return 1; + } + } + break; + } + default: + return 0; + } + + return 0; +} + + + +void +LocalCoordinates (const Vec3d & e1, const Vec3d & e2, + const Vec3d & v, double & lam1, double & lam2) +{ + double m11 = e1 * e1; + double m12 = e1 * e2; + double m22 = e2 * e2; + double rs1 = v * e1; + double rs2 = v * e2; + + double det = m11 * m22 - m12 * m12; + lam1 = (rs1 * m22 - rs2 * m12)/det; + lam2 = (m11 * rs2 - m12 * rs1)/det; +} + + + + + +int CalcSphereCenter (const Point3d ** pts, Point3d & c) +{ + /* + static DenseMatrix a(3), inva(3); + static Vector rs(3), sol(3); + int i; + double h = Dist(*pts[0], *pts[1]); + + for (i = 1; i <= 3; i++) + { + const Point3d & p1 = *pts[0]; + const Point3d & p2 = *pts[i]; + Vec3d v(p1, p2); + a.Elem(i,1) = v.X(); + a.Elem(i,2) = v.Y(); + a.Elem(i,3) = v.Z(); + + rs.Elem(i) = 0.5 * (v * v); + } + + if (fabs (a.Det()) <= 1e-12 * h * h * h) + { + (*testout) << "CalcSphereCenter: degenerated" << endl; + return 1; + } + + CalcInverse (a, inva); + inva.Mult (rs, sol); + + for (i = 1; i <= 3; i++) + c.X(i) = pts[0]->X(i) + sol.Elem(i); + */ + + Vec3d row1 (*pts[0], *pts[1]); + Vec3d row2 (*pts[0], *pts[2]); + Vec3d row3 (*pts[0], *pts[3]); + + Vec3d rhs(0.5 * (row1*row1), + 0.5 * (row2*row2), + 0.5 * (row3*row3)); + Transpose (row1, row2, row3); + + Vec3d sol; + if (SolveLinearSystem (row1, row2, row3, rhs, sol)) + { + (*testout) << "CalcSphereCenter: degenerated" << endl; + return 1; + } + + c = *pts[0] + sol; + return 0; +} + + + + + +int CalcTriangleCenter (const Point3d ** pts, Point3d & c) +{ + static DenseMatrix a(2), inva(2); + static Vector rs(2), sol(2); + double h = Dist(*pts[0], *pts[1]); + + Vec3d v1(*pts[0], *pts[1]); + Vec3d v2(*pts[0], *pts[2]); + + rs.Elem(1) = v1 * v1; + rs.Elem(2) = v2 * v2; + + a.Elem(1,1) = 2 * rs.Get(1); + a.Elem(1,2) = a.Elem(2,1) = 2 * (v1 * v2); + a.Elem(2,2) = 2 * rs.Get(2); + + if (fabs (a.Det()) <= 1e-12 * h * h) + { + (*testout) << "CalcTriangleCenter: degenerated" << endl; + return 1; + } + + CalcInverse (a, inva); + inva.Mult (rs, sol); + + c = *pts[0]; + v1 *= sol.Get(1); + v2 *= sol.Get(2); + + c += v1; + c += v2; + + return 0; +} + + + +double ComputeCylinderRadius (const Point3d & p1, + const Point3d & p2, + const Point3d & p3, + const Point3d & p4) +{ + Vec3d v12(p1, p2); + Vec3d v13(p1, p3); + Vec3d v14(p1, p4); + + Vec3d n1 = Cross (v12, v13); + Vec3d n2 = Cross (v14, v12); + + double n1l = n1.Length(); + double n2l = n2.Length(); + n1 /= n1l; + n2 /= n2l; + + double v12len = v12.Length(); + double h1 = n1l / v12len; + double h2 = n2l / v12len; + + /* + (*testout) << "n1 = " << n1 << " n2 = " << n2 + << "h1 = " << h1 << " h2 = " << h2 << endl; + */ + return ComputeCylinderRadius (n1, n2, h1, h2); +} + + + + +/* + Two triangles T1 and T2 have normals n1 and n2. + The height over the common edge is h1, and h2. + */ +double ComputeCylinderRadius (const Vec3d & n1, const Vec3d & n2, + double h1, double h2) +{ + Vec3d t1, t2; + double n11 = n1 * n1; + double n12 = n1 * n2; + double n22 = n2 * n2; + double det = n11 * n22 - n12 * n12; + + if (fabs (det) < 1e-14 * n11 * n22) + return 1e20; + + // a biorthogonal bases (ti * nj) = delta_ij: + t1 = (n22/det) * n1 + (-n12/det) * n2; + t2 = (-n12/det) * n1 + (n11/det) * n2; + + // normalize: + t1 /= t1.Length(); + t2 /= t2.Length(); + + /* + vector to center point has form + v = lam1 n1 + lam2 n2 + and fulfills + t2 v = h1/2 + t1 v = h2/2 + */ + + double lam1 = 0.5 * h2 / (n1 * t1); + double lam2 = 0.5 * h1 / (n2 * t2); + + double rad = (lam1 * n1 + lam2 * n2).Length(); + /* + (*testout) << "n1 = " << n1 + << " n2 = " << n2 + << " t1 = " << t1 + << " t2 = " << t2 + << " rad = " << rad << endl; + */ + return rad; +} + + + + + + +double MinDistLP2 (const Point2d & lp1, const Point2d & lp2, const Point2d & p) +{ + Vec2d v(lp1, lp2); + Vec2d vlp(lp1, p); + + // dist(lam) = \| vlp \|^2 - 2 lam (v1p, v) + lam^2 \| v \|^2 + + // lam = (v * vlp) / (v * v); + // if (lam < 0) lam = 0; + // if (lam > 1) lam = 1; + + double num = v*vlp; + double den = v*v; + + if (num <= 0) + return Dist2 (lp1, p); + + if (num >= den) + return Dist2 (lp2, p); + + if (den > 0) + { + return vlp.Length2() - num * num /den; + } + else + return vlp.Length2(); +} + + + + +double MinDistLP2 (const Point3d & lp1, const Point3d & lp2, const Point3d & p) +{ + Vec3d v(lp1, lp2); + Vec3d vlp(lp1, p); + + // dist(lam) = \| vlp \|^2 - 2 lam (v1p, v) + lam^2 \| v \|^2 + + // lam = (v * vlp) / (v * v); + // if (lam < 0) lam = 0; + // if (lam > 1) lam = 1; + + double num = v*vlp; + double den = v*v; + + if (num <= 0) + return Dist2 (lp1, p); + + if (num >= den) + return Dist2 (lp2, p); + + if (den > 0) + { + return vlp.Length2() - num * num /den; + } + else + return vlp.Length2(); +} + + + +double MinDistTP2 (const Point3d & tp1, const Point3d & tp2, + const Point3d & tp3, const Point3d & p) +{ + double lam1, lam2; + double res; + + LocalCoordinates (Vec3d (tp1, tp2), Vec3d (tp1, tp3), + Vec3d (tp1, p), lam1, lam2); + int in1 = lam1 >= 0; + int in2 = lam2 >= 0; + int in3 = lam1+lam2 <= 1; + + if (in1 && in2 && in3) + { + Point3d pp = tp1 + lam1 * Vec3d(tp1, tp2) + lam2 * Vec3d (tp1, tp3); + res = Dist2 (p, pp); + } + else + { + res = Dist2 (tp1, p); + if (!in1) + { + double hv = MinDistLP2 (tp1, tp3, p); + if (hv < res) res = hv; + } + if (!in2) + { + double hv = MinDistLP2 (tp1, tp2, p); + if (hv < res) res = hv; + } + if (!in3) + { + double hv = MinDistLP2 (tp2, tp3, p); + if (hv < res) res = hv; + } + /* + double d1 = MinDistLP2 (tp1, tp2, p); + double d2 = MinDistLP2 (tp1, tp3, p); + double d3 = MinDistLP2 (tp2, tp3, p); + res = min3 (d1, d2, d3); + */ + } + + return res; + + Vec3d pp1(tp1, p); + Vec3d v1(tp1, tp2), v2(tp1, tp3); + + double c = pp1.Length2(); + double cx = -2 * (pp1 * v1); + double cy = -2 * (pp1 * v2); + double cxx = v1.Length2(); + double cxy = 2 * (v1 * v2); + double cyy = v2.Length2(); + + QuadraticPolynomial2V pol (-c, -cx, -cy, -cxx, -cxy, -cyy); + double res2 = - pol.MaxUnitTriangle (); + + if (fabs (res - res2) > 1e-8) + cout << "res and res2 differ: " << res << " != " << res2 << endl; + return res2; +} + + +// 0 checks !!! +double MinDistLL2 (const Point3d & l1p1, const Point3d & l1p2, + const Point3d & l2p1, const Point3d & l2p2) +{ + // dist(lam1,lam2) = \| l2p1+lam2v2 - (l1p1+lam1 v1) \| + // min ! + + Vec3d l1l2 (l1p1, l2p1); + Vec3d v1 (l1p1, l1p2); + Vec3d v2 (l2p1, l2p2); + + double a11, a12, a22, rs1, rs2; + double lam1, lam2, det; + + a11 = v1*v1; + a12 = -(v1*v2); + a22 = v2*v2; + rs1 = l1l2 * v1; + rs2 = - (l1l2 * v2); + + det = a11 * a22 - a12 * a12; + if (det < 1e-14 * a11 * a22) + det = 1e-14 * a11 * a22; // regularization should be stable + + if (det < 1e-20) + det = 1e-20; + + + lam1 = (a22 * rs1 - a12 * rs2) / det; + lam2 = (-a12 * rs1 + a11 * rs2) / det; + + if (lam1 >= 0 && lam2 >= 0 && lam1 <= 1 && lam2 <= 1) + { + Vec3d v = l1l2 + (-lam1) * v1 + lam2 * v2; + return v.Length2(); + } + + double minv, hv; + minv = MinDistLP2 (l1p1, l1p2, l2p1); + hv = MinDistLP2 (l1p1, l1p2, l2p2); + if (hv < minv) minv = hv; + + hv = MinDistLP2 (l2p1, l2p2, l1p1); + if (hv < minv) minv = hv; + hv = MinDistLP2 (l2p1, l2p2, l1p2); + if (hv < minv) minv = hv; + + return minv; +} + +} diff --git a/contrib/Netgen/libsrc/gprim/geomtest3d.hpp b/contrib/Netgen/libsrc/gprim/geomtest3d.hpp new file mode 100644 index 0000000000..f801b8cdef --- /dev/null +++ b/contrib/Netgen/libsrc/gprim/geomtest3d.hpp @@ -0,0 +1,80 @@ +#ifndef FILE_GEOMTEST3D +#define FILE_GEOMTEST3D + +/* *************************************************************************/ +/* File: geomtest3d.hh */ +/* Author: Joachim Schoeberl */ +/* Date: 13. Feb. 98 */ +/* *************************************************************************/ + + + +extern int +IntersectTriangleLine (const Point3d ** tri, const Point3d ** line); + + + +/** + Returns 0, iff + closure (tet) cup closure (tri) is empty, one corner point of tet, + one edge of tet or one face of tet + */ +extern int +IntersectTetTriangle (const Point3d ** tet, const Point3d ** tri, + const int * tetpi = NULL, const int * tripi = NULL); + +/** + Same test as above, but tet int reference position (0, ex, ey, ez), + tetpi = 1, 2, 4, 5 + */ +extern int +IntersectTetTriangleRef (const Point3d ** tri, const int * tripi = NULL); + + +// 1, iff not regular triangulation +extern int +IntersectTriangleTriangle (const Point3d ** tri1, const Point3d ** tri2); + + +extern void +LocalCoordinates (const Vec3d & e1, const Vec3d & e2, + const Vec3d & v, double & lam1, double & lam2); + +/// return 1 = degenerated sphere +extern int +CalcSphereCenter (const Point3d ** pts, Point3d & c); + +/// return 1 = degenerated triangle +extern int +CalcTriangleCenter (const Point3d ** pts, Point3d & c); + + + +/* + Compute radius of cylinder fitting 4 points. + cylinder axis is in the direction of p1-p2 +*/ +extern double ComputeCylinderRadius (const Point3d & p1, const Point3d & p2, + const Point3d & p3, const Point3d & p4); + +/* + Two triangles T1 and T2 have normals n1 and n2. + The height over the common edge is h1, and h2. + Radius of cylinder fitting both triangles +*/ +extern double ComputeCylinderRadius (const Vec3d & n1, const Vec3d & n2, + double h1, double h2); + + +extern double MinDistLP2 (const Point2d & lp1, const Point2d & lp2, const Point2d & p); + +extern double MinDistLP2 (const Point3d & lp1, const Point3d & lp2, const Point3d & p); + +extern double MinDistTP2 (const Point3d & tp1, const Point3d & tp2, + const Point3d & tp3, const Point3d & p); + +extern double MinDistLL2 (const Point3d & l1p1, const Point3d & l1p2, + const Point3d & l2p1, const Point3d & l2p2); + + +#endif diff --git a/contrib/Netgen/libsrc/gprim/gprim.hpp b/contrib/Netgen/libsrc/gprim/gprim.hpp new file mode 100644 index 0000000000..0f57ebac86 --- /dev/null +++ b/contrib/Netgen/libsrc/gprim/gprim.hpp @@ -0,0 +1,26 @@ +#ifndef FILE_GPRIM +#define FILE_GPRIM + +/* *************************************************************************/ +/* File: gprim.hpp */ +/* Author: Joachim Schoeberl */ +/* Date: 14. Aug. 97 */ +/* *************************************************************************/ + + +namespace netgen +{ +#include "geomobjects.hpp" +#include "geomops.hpp" +#include "geomfuncs.hpp" + +#include "geom2d.hpp" +#include "geom3d.hpp" +#include "geomtest3d.hpp" +// #include "rot3d.hpp" +#include "transform3d.hpp" +// #include "reftrans.hpp" +#include "adtree.hpp" +} + +#endif diff --git a/contrib/Netgen/libsrc/gprim/testgeom.cpp b/contrib/Netgen/libsrc/gprim/testgeom.cpp new file mode 100644 index 0000000000..8413f0f2b5 --- /dev/null +++ b/contrib/Netgen/libsrc/gprim/testgeom.cpp @@ -0,0 +1,20 @@ +#include <mystdlib.h> + +#include <myadt.hpp> +#include <gprim.hpp> + + +Vec<2> func1 (const Point<2> & a, const Point<2> & b) +{ + return a-b; +} + +void func2 (Point<3> & a, Vec<3> & v) +{ + a += 3.4 * v; +} + +void func3 (const Mat<2,2> & m, const Vec<2> & vc, Vec<2> & res) +{ + res += Trans (m) * vc; +} diff --git a/contrib/Netgen/libsrc/gprim/transform3d.cpp b/contrib/Netgen/libsrc/gprim/transform3d.cpp new file mode 100644 index 0000000000..ea62fffe5a --- /dev/null +++ b/contrib/Netgen/libsrc/gprim/transform3d.cpp @@ -0,0 +1,173 @@ +#include <mystdlib.h> + +#include <myadt.hpp> +#include <gprim.hpp> +#include <linalg.hpp> + +namespace netgen +{ + +Transformation3d :: Transformation3d () +{ + int i, j; + for (i = 0; i < 3; i++) + { + offset[i] = 0; + for (j = 0; j < 3; j++) + lin[i][j] = 0; + } +} + +Transformation3d :: Transformation3d (const Vec3d & translate) +{ + int i, j; + for (i = 0; i < 3; i++) + for (j = 0; j < 3; j++) + lin[i][j] = 0; + for (i = 0; i < 3; i++) + { + offset[i] = translate.X(i+1); + lin[i][i] = 1; + } +} + + +Transformation3d :: +Transformation3d (const Point3d & c, double alpha, + double beta, double gamma) +{ + // total = T_c x Rot_0 x T_c^{-1} + // Use Euler angles, see many books from tech mech, e.g. + // Shabana "multibody systems" + + Transformation3d tc(c); + Transformation3d tcinv; + tc.CalcInverse (tcinv); + + Transformation3d r1, r2, r3, ht, ht2; + r1.SetAxisRotation (3, alpha); + r2.SetAxisRotation (1, beta); + r3.SetAxisRotation (3, gamma); + + ht.Combine (tc, r3); + ht2.Combine (ht, r2); + ht.Combine (ht2, r1); + Combine (ht, tcinv); + + cout << "Rotation - Transformation:" << (*this) << endl; + // (*testout) << "Rotation - Transformation:" << (*this) << endl; +} + + + + +Transformation3d :: Transformation3d (const Point3d ** pp) +{ + int i, j; + for (i = 1; i <= 3; i++) + { + offset[i-1] = (*pp[0]).X(i); + for (j = 1; j <= 3; j++) + lin[i-1][j-1] = (*pp[j]).X(i) - (*pp[0]).X(i); + } +} + +Transformation3d :: Transformation3d (const Point3d pp[]) +{ + int i, j; + for (i = 1; i <= 3; i++) + { + offset[i-1] = pp[0].X(i); + for (j = 1; j <= 3; j++) + lin[i-1][j-1] = pp[j].X(i) - pp[0].X(i); + } +} + + +void Transformation3d :: CalcInverse (Transformation3d & inv) const +{ + static DenseMatrix a(3), inva(3); + static Vector b(3), sol(3); + int i, j; + + for (i = 1; i <= 3; i++) + { + b.Elem(i) = offset[i-1]; + for (j = 1; j <= 3; j++) + a.Elem(i, j) = lin[i-1][j-1]; + } + + ::netgen::CalcInverse (a, inva); + inva.Mult (b, sol); + + for (i = 1; i <= 3; i++) + { + inv.offset[i-1] = -sol.Get(i); + for (j = 1; j <= 3; j++) + inv.lin[i-1][j-1] = inva.Elem(i, j); + } +} + + +void Transformation3d:: +Combine (const Transformation3d & ta, const Transformation3d & tb) +{ + int i, j, k; + + // o = o_a+ m_a o_b + // m = m_a m_b + + for (i = 0; i <= 2; i++) + { + offset[i] = ta.offset[i]; + for (j = 0; j <= 2; j++) + offset[i] += ta.lin[i][j] * tb.offset[j]; + } + + for (i = 0; i <= 2; i++) + for (j = 0; j <= 2; j++) + { + lin[i][j] = 0; + for (k = 0; k <= 2; k++) + lin[i][j] += ta.lin[i][k] * tb.lin[k][j]; + } +} +void Transformation3d :: SetAxisRotation (int dir, double alpha) +{ + double co = cos(alpha); + double si = sin(alpha); + dir--; + int pos1 = (dir+1) % 3; + int pos2 = (dir+2) % 3; + + int i, j; + for (i = 0; i <= 2; i++) + { + offset[i] = 0; + for (j = 0; j <= 2; j++) + lin[i][j] = 0; + } + + lin[dir][dir] = 1; + lin[pos1][pos1] = co; + lin[pos2][pos2] = co; + lin[pos1][pos2] = si; + lin[pos2][pos1] = -si; +} + +ostream & operator<< (ostream & ost, Transformation3d & trans) +{ + int i, j; + ost << "offset = "; + for (i = 0; i <= 2; i++) + ost << trans.offset[i] << " "; + ost << endl << "linear = " << endl; + for (i = 0; i <= 2; i++) + { + for (j = 0; j <= 2; j++) + ost << trans.lin[i][j] << " "; + ost << endl; + } + return ost; +} +} diff --git a/contrib/Netgen/libsrc/gprim/transform3d.hpp b/contrib/Netgen/libsrc/gprim/transform3d.hpp new file mode 100644 index 0000000000..7472257297 --- /dev/null +++ b/contrib/Netgen/libsrc/gprim/transform3d.hpp @@ -0,0 +1,174 @@ +#ifndef FILE_TRANSFORM3D +#define FILE_TRANSFORM3D + +/* *************************************************************************/ +/* File: transform3d.hh */ +/* Author: Joachim Schoeberl */ +/* Date: 22. Mar. 98 */ +/* *************************************************************************/ + +/* + Affine - Linear mapping in 3D space + */ + +class Transformation3d; +ostream & operator<< (ostream & ost, Transformation3d & trans); + +class Transformation3d +{ + double lin[3][3]; + double offset[3]; +public: + /// + Transformation3d (); + /// Unit tet is mapped to tet descibed by pp + Transformation3d (const Point3d ** pp); + /// Unit tet is mapped to tet descibed by pp + Transformation3d (const Point3d pp[]); + /// translation + Transformation3d (const Vec3d & translate); + /// rotation with ... + Transformation3d (const Point3d & c, double alpha, double beta, double gamma); + /// + void CalcInverse (Transformation3d & inv) const; + /// this = ta x tb + void Combine (const Transformation3d & ta, const Transformation3d & tb); + /// dir = 1..3 (== x..z) + void SetAxisRotation (int dir, double alpha); + /// + void Transform (const Point3d & from, Point3d & to) const + { + for (int i = 1; i <= 3; i++) + { + to.X(i) = offset[i-1] + lin[i-1][0] * from.X(1) + + lin[i-1][1] * from.X(2) + lin[i-1][2] * from.X(3); + } + } + /// transform vector, apply only linear part, not offset + void Transform (const Vec3d & from, Vec3d & to) const + { + for (int i = 1; i <= 3; i++) + { + to.X(i) = lin[i-1][0] * from.X(1) + + lin[i-1][1] * from.X(2) + lin[i-1][2] * from.X(3); + } + } + friend ostream & operator<< (ostream & ost, Transformation3d & trans); +}; + + + + + + + + + + + + + + +template <int D> +class Transformation +{ + Mat<D> m; + Vec<D> v; +public: + /// + Transformation () { m = 0; v = 0; } + + /// Unit tet is mapped to tet descibed by pp + Transformation (const Point<D> * pp); + + /// translation + Transformation (const Vec<D> & translate) + { + v = translate; + m = 0; + for (int i = 0; i < D; i++) + m(i,i) = 1; + } + + // rotation with ... + Transformation (const Point<D> & c, double alpha, double beta, double gamma) + { + // total = T_c x Rot_0 x T_c^{-1} + // Use Euler angles, see many books from tech mech, e.g. + // Shabana "multibody systems" + + Vec<D> vc(c); + Transformation<D> tc(vc); + Transformation<D> tcinv(-vc); + // tc.CalcInverse (tcinv); + + Transformation<D> r1, r2, r3, ht, ht2; + r1.SetAxisRotation (3, alpha); + r2.SetAxisRotation (1, beta); + r3.SetAxisRotation (3, gamma); + + ht.Combine (tc, r3); + ht2.Combine (ht, r2); + ht.Combine (ht2, r1); + Combine (ht, tcinv); + + // cout << "Rotation - Transformation:" << (*this) << endl; + // (*testout) << "Rotation - Transformation:" << (*this) << endl; + } + + /// + void CalcInverse (Transformation & inv) const; + + /// this = ta x tb + void Combine (const Transformation & ta, const Transformation & tb) + { + v = ta.v + ta.m * tb.v; + m = ta.m * tb.m; + } + + + + /// dir = 1..3 (== x..z) + void SetAxisRotation (int dir, double alpha) + { + double co = cos(alpha); + double si = sin(alpha); + dir--; + int pos1 = (dir+1) % 3; + int pos2 = (dir+2) % 3; + + int i, j; + for (i = 0; i <= 2; i++) + { + v(i) = 0; + for (j = 0; j <= 2; j++) + m(i,j) = 0; + } + + m(dir,dir) = 1; + m(pos1, pos1) = co; + m(pos2, pos2) = co; + m(pos1, pos2) = si; + m(pos2, pos1) = -si; + } + + /// + void Transform (const Point<D> & from, Point<D> & to) const + { + to = Point<D> (v + m * Vec<D>(from)); + } + + /// transform vector, apply only linear part, not offset + void Transform (const Vec<D> & from, Vec<D> & to) const + { + to = m * from; + } +}; + +template <int D> +ostream & operator<< (ostream & ost, Transformation<D> & trans); + + + + +#endif diff --git a/contrib/Netgen/libsrc/include/FlexLexer.h b/contrib/Netgen/libsrc/include/FlexLexer.h new file mode 100644 index 0000000000..e242c836f8 --- /dev/null +++ b/contrib/Netgen/libsrc/include/FlexLexer.h @@ -0,0 +1,184 @@ +// $Header: /cvsroot/gmsh/contrib/Netgen/libsrc/include/FlexLexer.h,v 1.1 2005-09-21 17:29:38 geuzaine Exp $ + +// FlexLexer.h -- define interfaces for lexical analyzer classes generated +// by flex + +// Copyright (c) 1993 The Regents of the University of California. +// All rights reserved. +// +// This code is derived from software contributed to Berkeley by +// Kent Williams and Tom Epperly. +// +// Redistribution and use in source and binary forms are permitted provided +// that: (1) source distributions retain this entire copyright notice and +// comment, and (2) distributions including binaries display the following +// acknowledgement: ``This product includes software developed by the +// University of California, Berkeley and its contributors'' in the +// documentation or other materials provided with the distribution and in +// all advertising materials mentioning features or use of this software. +// Neither the name of the University nor the names of its contributors may +// be used to endorse or promote products derived from this software without +// specific prior written permission. +// THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED +// WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + +// This file defines FlexLexer, an abstract class which specifies the +// external interface provided to flex C++ lexer objects, and yyFlexLexer, +// which defines a particular lexer class. +// +// If you want to create multiple lexer classes, you use the -P flag +// to rename each yyFlexLexer to some other xxFlexLexer. You then +// include <FlexLexer.h> in your other sources once per lexer class: +// +// #undef yyFlexLexer +// #define yyFlexLexer xxFlexLexer +// #include <FlexLexer.h> +// +// #undef yyFlexLexer +// #define yyFlexLexer zzFlexLexer +// #include <FlexLexer.h> +// ... + +#ifndef __FLEX_LEXER_H +// Never included before - need to define base class. +#define __FLEX_LEXER_H + + +extern "C++" { +struct yy_buffer_state; +typedef int yy_state_type; + +class FlexLexer { +public: + virtual ~FlexLexer() { } + + const char* YYText() { return yytext; } + int YYLeng() { return yyleng; } + + virtual void + yy_switch_to_buffer( struct yy_buffer_state* new_buffer ) = 0; + virtual struct yy_buffer_state* + yy_create_buffer( istream* s, int size ) = 0; + virtual void yy_delete_buffer( struct yy_buffer_state* b ) = 0; + virtual void yyrestart( istream* s ) = 0; + + virtual int yylex() = 0; + + // Call yylex with new input/output sources. + int yylex( istream* new_in, ostream* new_out = 0 ) + { + switch_streams( new_in, new_out ); + return yylex(); + } + + // Switch to new input/output streams. A nil stream pointer + // indicates "keep the current one". + virtual void switch_streams( istream* new_in = 0, + ostream* new_out = 0 ) = 0; + + int lineno() const { return yylineno; } + + int debug() const { return yy_flex_debug; } + void set_debug( int flag ) { yy_flex_debug = flag; } + +protected: + char* yytext; + int yyleng; + int yylineno; // only maintained if you use %option yylineno + int yy_flex_debug; // only has effect with -d or "%option debug" +}; + +} +#endif + +#if defined(yyFlexLexer) || ! defined(yyFlexLexerOnce) +// Either this is the first time through (yyFlexLexerOnce not defined), +// or this is a repeated include to define a different flavor of +// yyFlexLexer, as discussed in the flex man page. +#define yyFlexLexerOnce + +class yyFlexLexer : public FlexLexer { +public: + // arg_yyin and arg_yyout default to the cin and cout, but we + // only make that assignment when initializing in yylex(). + yyFlexLexer( istream* arg_yyin = 0, ostream* arg_yyout = 0 ); + + virtual ~yyFlexLexer(); + + void yy_switch_to_buffer( struct yy_buffer_state* new_buffer ); + struct yy_buffer_state* yy_create_buffer( istream* s, int size ); + void yy_delete_buffer( struct yy_buffer_state* b ); + void yyrestart( istream* s ); + + virtual int yylex(); + virtual void switch_streams( istream* new_in, ostream* new_out ); + +protected: + virtual int LexerInput( char* buf, int max_size ); + virtual void LexerOutput( const char* buf, int size ); + virtual void LexerError( const char* msg ); + + void yyunput( int c, char* buf_ptr ); + int yyinput(); + + void yy_load_buffer_state(); + void yy_init_buffer( struct yy_buffer_state* b, istream* s ); + void yy_flush_buffer( struct yy_buffer_state* b ); + + int yy_start_stack_ptr; + int yy_start_stack_depth; + int* yy_start_stack; + + void yy_push_state( int new_state ); + void yy_pop_state(); + int yy_top_state(); + + yy_state_type yy_get_previous_state(); + yy_state_type yy_try_NUL_trans( yy_state_type current_state ); + int yy_get_next_buffer(); + + istream* yyin; // input source for default LexerInput + ostream* yyout; // output sink for default LexerOutput + + struct yy_buffer_state* yy_current_buffer; + + // yy_hold_char holds the character lost when yytext is formed. + char yy_hold_char; + + // Number of characters read into yy_ch_buf. + int yy_n_chars; + + // Points to current character in buffer. + char* yy_c_buf_p; + + int yy_init; // whether we need to initialize + int yy_start; // start state number + + // Flag which is used to allow yywrap()'s to do buffer switches + // instead of setting up a fresh yyin. A bit of a hack ... + int yy_did_buffer_switch_on_eof; + + // The following are not always needed, but may be depending + // on use of certain flex features (like REJECT or yymore()). + + yy_state_type yy_last_accepting_state; + char* yy_last_accepting_cpos; + + yy_state_type* yy_state_buf; + yy_state_type* yy_state_ptr; + + char* yy_full_match; + int* yy_full_state; + int yy_full_lp; + + int yy_lp; + int yy_looking_for_trail_begin; + + int yy_more_flag; + int yy_more_len; + int yy_more_offset; + int yy_prev_more_offset; +}; + +#endif diff --git a/contrib/Netgen/libsrc/include/csg.hpp b/contrib/Netgen/libsrc/include/csg.hpp new file mode 100644 index 0000000000..ffd45ef0bf --- /dev/null +++ b/contrib/Netgen/libsrc/include/csg.hpp @@ -0,0 +1 @@ +#include "../csg/csg.hpp" diff --git a/contrib/Netgen/libsrc/include/geometry2d.hpp b/contrib/Netgen/libsrc/include/geometry2d.hpp new file mode 100644 index 0000000000..bf0965c228 --- /dev/null +++ b/contrib/Netgen/libsrc/include/geometry2d.hpp @@ -0,0 +1 @@ +#include "../geom2d/geometry2d.hpp" diff --git a/contrib/Netgen/libsrc/include/gprim.hpp b/contrib/Netgen/libsrc/include/gprim.hpp new file mode 100644 index 0000000000..1e827aaf8c --- /dev/null +++ b/contrib/Netgen/libsrc/include/gprim.hpp @@ -0,0 +1 @@ +#include "../gprim/gprim.hpp" diff --git a/contrib/Netgen/libsrc/include/incvis.hpp b/contrib/Netgen/libsrc/include/incvis.hpp new file mode 100644 index 0000000000..a38e918698 --- /dev/null +++ b/contrib/Netgen/libsrc/include/incvis.hpp @@ -0,0 +1,33 @@ +// libraries for User interface: + +/* +#include <tcl8.3.h> +#include <tk8.3.h> + +#include <GL/gl.h> +#include <GL/glu.h> +#include "../togl/togl.h" + +#include <tix8.1.h> +*/ + + +#include <tcl.h> +#include <tk.h> + + +#if TK_MAJOR_VERSION==8 && TK_MINOR_VERSION==4 +#define tcl_const const +#else +#define tcl_const +#endif + + +#include <GL/gl.h> +#include <GL/glu.h> +#include "../../togl/togl.h" + + + +// Just the init-call +// #include <tix.h> diff --git a/contrib/Netgen/libsrc/include/linalg.hpp b/contrib/Netgen/libsrc/include/linalg.hpp new file mode 100644 index 0000000000..e96bd036c3 --- /dev/null +++ b/contrib/Netgen/libsrc/include/linalg.hpp @@ -0,0 +1 @@ +#include "../linalg/linalg.hpp" diff --git a/contrib/Netgen/libsrc/include/meshing.hpp b/contrib/Netgen/libsrc/include/meshing.hpp new file mode 100644 index 0000000000..e41a88f9f2 --- /dev/null +++ b/contrib/Netgen/libsrc/include/meshing.hpp @@ -0,0 +1 @@ +#include <../meshing/meshing.hpp> diff --git a/contrib/Netgen/libsrc/include/myadt.hpp b/contrib/Netgen/libsrc/include/myadt.hpp new file mode 100644 index 0000000000..d36bef05c1 --- /dev/null +++ b/contrib/Netgen/libsrc/include/myadt.hpp @@ -0,0 +1 @@ +#include <../general/myadt.hpp> diff --git a/contrib/Netgen/libsrc/include/mydefs.hpp b/contrib/Netgen/libsrc/include/mydefs.hpp new file mode 100644 index 0000000000..c34ce56a8e --- /dev/null +++ b/contrib/Netgen/libsrc/include/mydefs.hpp @@ -0,0 +1,29 @@ +#ifndef FILE_MYDEFS +#define FILE_MYDEFS + +/**************************************************************************/ +/* File: mydefs.hh */ +/* Author: Joachim Schoeberl */ +/* Date: 10. Mar. 98 */ +/**************************************************************************/ + +/* + defines for graphics, testmodes, ... +*/ + + +// #define DEBUG + + +#define noDEMOVERSION +#define noDEVELOP +#define noSTEP +#define noSOLIDGEOM + +#define noDEMOAPP +#define noMODELLER + +#define noSTAT_STREAM +#define noLOG_STREAM + +#endif diff --git a/contrib/Netgen/libsrc/include/mystdlib.h b/contrib/Netgen/libsrc/include/mystdlib.h new file mode 100644 index 0000000000..2249aea3a2 --- /dev/null +++ b/contrib/Netgen/libsrc/include/mystdlib.h @@ -0,0 +1,69 @@ +#ifndef FILE_MYSTDLIB +#define FILE_MYSTDLIB + + +#include <iostream> +#include <iomanip> +#include <fstream> +#include <sstream> + +#ifdef OLDCINCLUDE + +// e.g., CC compiler on SGI +#include <stdlib.h> +#include <stdio.h> +#include <math.h> +#include <malloc.h> +#include <ctype.h> +#include <time.h> + +#else + +// new standard +#include <cstdlib> +#include <cstdio> +#include <cmath> +#include <cctype> +#include <ctime> +#endif + + + +#include <new> +#include <string> +#include <typeinfo> + +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif + + +/*** Windows headers ***/ +#ifdef WIN32 +#define WIN32_LEAN_AND_MEAN +#include <afxwin.h> +#include <afxmt.h> +#include <windows.h> +#undef WIN32_LEAN_AND_MEAN +#include <winnt.h> +#endif /* WIN32 */ + + +/* +extern void* operator new(std::size_t) throw (std::bad_alloc); +extern void* operator new[](std::size_t) throw (std::bad_alloc); +extern void operator delete(void*) throw(); +extern void operator delete[](void*) throw(); +*/ + + +extern int mem_alloc; +extern int mem_total_alloc; +extern int mem_max_alloc; +extern int mem_total_alloc_array; +extern int mem_total_alloc_table; + + +using namespace std; + +#endif diff --git a/contrib/Netgen/libsrc/include/occgeom.hpp b/contrib/Netgen/libsrc/include/occgeom.hpp new file mode 100644 index 0000000000..af258e0df0 --- /dev/null +++ b/contrib/Netgen/libsrc/include/occgeom.hpp @@ -0,0 +1 @@ +#include "../occ/occgeom.hpp" diff --git a/contrib/Netgen/libsrc/include/opti.hpp b/contrib/Netgen/libsrc/include/opti.hpp new file mode 100644 index 0000000000..6b8a0b61c8 --- /dev/null +++ b/contrib/Netgen/libsrc/include/opti.hpp @@ -0,0 +1 @@ +#include "../opti/opti.hpp" diff --git a/contrib/Netgen/libsrc/include/stepgeom.hpp b/contrib/Netgen/libsrc/include/stepgeom.hpp new file mode 100644 index 0000000000..d2c5c5e41e --- /dev/null +++ b/contrib/Netgen/libsrc/include/stepgeom.hpp @@ -0,0 +1,10 @@ +#include "../stepgeom/geomanif.hh" +#include "../stepgeom/geopac2d.hh" +#include "../stepgeom/geopac3d.hh" +#include "../stepgeom/geosplinesurf.hh" +#include "../stepgeom/algprim.hh" +#include "../stepgeom/scenery.hh" +#include "../stepgeom/brep.hh" +#include "../stepgeom/adtcrit.hh" +#include "../stepgeom/STEPgeom.hh" +#include "../stepgeom/visapprox.hh" diff --git a/contrib/Netgen/libsrc/include/stepreader.hpp b/contrib/Netgen/libsrc/include/stepreader.hpp new file mode 100644 index 0000000000..0214d58d9d --- /dev/null +++ b/contrib/Netgen/libsrc/include/stepreader.hpp @@ -0,0 +1 @@ +#include "../stepgeom/STEPread.hh" diff --git a/contrib/Netgen/libsrc/include/stlgeom.hpp b/contrib/Netgen/libsrc/include/stlgeom.hpp new file mode 100644 index 0000000000..f1eea264e1 --- /dev/null +++ b/contrib/Netgen/libsrc/include/stlgeom.hpp @@ -0,0 +1 @@ +#include <../stlgeom/stlgeom.hpp> diff --git a/contrib/Netgen/libsrc/include/visual.hpp b/contrib/Netgen/libsrc/include/visual.hpp new file mode 100644 index 0000000000..f026f5a458 --- /dev/null +++ b/contrib/Netgen/libsrc/include/visual.hpp @@ -0,0 +1 @@ +#include "../visualization/visual.hpp" diff --git a/contrib/Netgen/libsrc/interface/Makefile b/contrib/Netgen/libsrc/interface/Makefile new file mode 100644 index 0000000000..c47dbe2c5a --- /dev/null +++ b/contrib/Netgen/libsrc/interface/Makefile @@ -0,0 +1,7 @@ +src = nginterface.cpp writeuser.cpp writediffpack.cpp writeabaqus.cpp writefluent.cpp writepermas.cpp writetochnog.cpp writetecplot.cpp wuchemnitz.cpp writetochnog.cpp writefeap.cpp writeelmer.cpp writegmsh.cpp readuser.cpp importsolution.cpp +# +lib = nginterface +libpath = libsrc/interface +# +include ../makefile.inc +# diff --git a/contrib/Netgen/libsrc/interface/importsolution.cpp b/contrib/Netgen/libsrc/interface/importsolution.cpp new file mode 100644 index 0000000000..3973d3927e --- /dev/null +++ b/contrib/Netgen/libsrc/interface/importsolution.cpp @@ -0,0 +1,121 @@ +// +// Read solution file +// + + +#include <mystdlib.h> + + +#include <myadt.hpp> +#include <linalg.hpp> +#include <csg.hpp> +#include <meshing.hpp> + +#include "nginterface.h" + +namespace netgen +{ +#include "writeuser.hpp" + + +void ImportSolution (const char * filename) +{ + ifstream inf (filename); + char buf[100], name[1000]; + int i, j, size, comps, order; + bool iscomplex; + const char * type; + Flags flags; + + while (1) + { + buf[0] = 0; + inf >> buf; + if (strcmp (buf, "solution") == 0) + { + inf >> name; + + inf >> buf[0]; + flags.DeleteFlags (); + while (buf[0] == '-') + { + inf >> buf[1]; + inf.putback (buf[1]); + if (!isalpha (buf[1])) + { + break; + } + inf >> (buf+1); + flags.SetCommandLineFlag (buf); + buf[0] = 0; + inf >> buf[0]; + } + inf.putback (buf[0]); + + (*testout) << "Flags: " << endl; + flags.PrintFlags (*testout); + (*testout) << "done" << endl; + + size = int(flags.GetNumFlag ("size", Ng_GetNP())); + comps = int(flags.GetNumFlag ("components", 1)); + type = flags.GetStringFlag ("type", "nodal"); + order = int(flags.GetNumFlag ("order", 1)); + iscomplex = flags.GetDefineFlag ("complex"); + + double * sol = new double[size*comps]; + + (*testout) << "import solution " << name << " size = " << size << " comps = " << comps << " order = " << order << endl; + + for (i = 0; i < size*comps; i++) + { + inf >> sol[i]; + // (*testout) << "sol: " << sol[i] << endl; + } + + Ng_SolutionData soldata; + Ng_InitSolutionData (&soldata); + soldata.name = name; + soldata.data = sol; + soldata.dist = comps; + soldata.components = comps; + soldata.order = order; + soldata.iscomplex = iscomplex; + soldata.soltype = NG_SOLUTION_NODAL; + if (strcmp (type, "element") == 0) + soldata.soltype = NG_SOLUTION_ELEMENT; + if (strcmp (type, "surfaceelement") == 0) + soldata.soltype = NG_SOLUTION_SURFACE_ELEMENT; + if (strcmp (type, "noncontinuous") == 0) + soldata.soltype = NG_SOLUTION_NONCONTINUOUS; + if (strcmp (type, "surfacenoncontinuous") == 0) + soldata.soltype = NG_SOLUTION_SURFACE_NONCONTINUOUS; + + Ng_SetSolutionData (&soldata); + } + else + { + // cout << "kw = (" << buf << ")" << endl; + (*testout) << "kw = (" << buf << ")" << endl; + break; + } + } + /* + struct Ng_SolutionData + { + char * name; // name of gridfunction + double * data; // solution values + int components; // used components in solution vector + int dist; // num of doubles per entry (alignment!) + Ng_SolutionType soltype; // type of solution function + }; + + // initialize solution data with default arguments + void Ng_InitSolutionData (Ng_SolutionData * soldata); + // set solution data + void Ng_SetSolutionData (Ng_SolutionData * soldata); + */ +} + + + +} diff --git a/contrib/Netgen/libsrc/interface/nginterface.cpp b/contrib/Netgen/libsrc/interface/nginterface.cpp new file mode 100644 index 0000000000..784be18dc5 --- /dev/null +++ b/contrib/Netgen/libsrc/interface/nginterface.cpp @@ -0,0 +1,1476 @@ +#include <mystdlib.h> + + +#include <meshing.hpp> +#include <csg.hpp> +#include <geometry2d.hpp> +#include <stlgeom.hpp> + +#ifdef OCCGEOMETRY +#include <occgeom.hpp> +#endif + + +#include <visual.hpp> + +#include "nginterface.h" +// #include <FlexLexer.h> + + +// #include <mystdlib.h> + + +namespace netgen +{ + extern AutoPtr<Mesh> mesh; + extern VisualSceneMesh vsmesh; + extern Tcl_Interp * tcl_interp; + + extern AutoPtr<SplineGeometry2d> geometry2d; + extern AutoPtr<CSGeometry> geometry; + extern STLGeometry * stlgeometry; +#ifdef OCCGEOMETRY + extern OCCGeometry * occgeometry; +#endif + +#ifdef OPENGL + extern VisualSceneSolution vssolution; +#endif + extern CSGeometry * ParseCSG (istream & istr); +} + + +using namespace netgen; + +/* + extern void * operator new (size_t s); + extern void * operator new [] (size_t s); + extern void operator delete (void * p); + extern void operator delete [] (void * p); +*/ + +// extern FlexLexer * lexer; + + + +void Ng_LoadGeometry (char * filename) +{ + ifstream infile (filename); + + geometry.Reset (); + geometry2d.Reset (); + +#ifdef OCCGEOMETRY + delete occgeometry; + occgeometry = 0; +#endif + + if ((strcmp (&filename[strlen(filename)-3], "geo") == 0) || + (strcmp (&filename[strlen(filename)-3], "GEO") == 0) || + (strcmp (&filename[strlen(filename)-3], "Geo") == 0)) + { + geometry.Reset (netgen::ParseCSG (infile)); + + if (!geometry) + { + geometry.Reset (new CSGeometry ()); + throw NgException ("input file not found"); + } + + geometry -> FindIdenticSurfaces(1e-6); + + double detail = atof (Tcl_GetVar (tcl_interp, "geooptions.detail", 0)); + double facets = atof (Tcl_GetVar (tcl_interp, "geooptions.facets", 0)); + Box<3> box (geometry->BoundingBox()); + + if (atoi (Tcl_GetVar (tcl_interp, "geooptions.drawcsg", 0))) + geometry->CalcTriangleApproximation(box, detail, facets); + + // geometry->CalcTriangleApproximation (box, 0.01, 10); + } + + else if (strcmp (&filename[strlen(filename)-4], "in2d") == 0) + { + geometry2d.Reset (new SplineGeometry2d()); + geometry2d -> Load (filename); + } + + else if ((strcmp (&filename[strlen(filename)-3], "stl") == 0) || + (strcmp (&filename[strlen(filename)-3], "STL") == 0) || + (strcmp (&filename[strlen(filename)-3], "Stl") == 0)) + { + ifstream infile(filename); + stlgeometry = STLGeometry :: Load (infile); + stlgeometry->edgesfound = 0; + Mesh meshdummy; + stlgeometry->Clear(); + stlgeometry->BuildEdges(); + stlgeometry->MakeAtlas(meshdummy); + stlgeometry->CalcFaceNums(); + stlgeometry->AddFaceEdges(); + stlgeometry->LinkEdges(); + } + +#ifdef OCCGEOMETRY + else if ((strcmp (&filename[strlen(filename)-4], "iges") == 0) || + (strcmp (&filename[strlen(filename)-3], "igs") == 0) || + (strcmp (&filename[strlen(filename)-3], "IGS") == 0) || + (strcmp (&filename[strlen(filename)-4], "IGES") == 0)) + { + PrintMessage (1, "Load IGES geometry file ", filename); + occgeometry = LoadOCC_IGES (filename); + } + else if ((strcmp (&filename[strlen(filename)-4], "step") == 0) || + (strcmp (&filename[strlen(filename)-3], "stp") == 0) || + (strcmp (&filename[strlen(filename)-3], "STP") == 0) || + (strcmp (&filename[strlen(filename)-4], "STEP") == 0)) + { + PrintMessage (1, "Load STEP geometry file ", filename); + occgeometry = LoadOCC_STEP (filename); + } +#endif + else + { + cerr << "Unknown geometry extension!!" << endl; + } +} + + +void Ng_LoadMesh (char * filename) +{ + mesh.Reset (new Mesh()); + mesh->Load (filename); +} + + + +int Ng_GetDimension () +{ + return mesh->GetDimension(); +} + +int Ng_GetNP () +{ + return mesh->GetNP(); +} + +int Ng_GetNV () +{ + return mesh->GetNV(); +} + +int Ng_GetNE () +{ + if (mesh->GetDimension() == 3) + return mesh->GetNE(); + else + return mesh->GetNSE(); +} + +int Ng_GetNSE () +{ + if (mesh->GetDimension() == 3) + return mesh->GetNSE(); + else + return mesh->GetNSeg(); +} + +void Ng_GetPoint (int pi, double * p) +{ + const Point3d & hp = mesh->Point (pi); + p[0] = hp.X(); + p[1] = hp.Y(); + if (mesh->GetDimension() == 3) + p[2] = hp.Z(); +} + + +NG_ELEMENT_TYPE Ng_GetElement (int ei, int * epi, int * np) +{ + if (mesh->GetDimension() == 3) + { + int i; + const Element & el = mesh->VolumeElement (ei); + for (i = 0; i < el.GetNP(); i++) + epi[i] = el.PNum(i+1); + + if (np) + *np = el.GetNP(); + + if (el.GetType() == PRISM) + { + // degenerated prism, (should be obsolete) + const int map1[] = { 3, 2, 5, 6, 1 }; + const int map2[] = { 1, 3, 6, 4, 2 }; + const int map3[] = { 2, 1, 4, 5, 3 }; + + const int * map = NULL; + int deg1 = 0, deg2 = 0, deg3 = 0; + int deg = 0; + if (el.PNum(1) == el.PNum(4)) { map = map1; deg1 = 1; } + if (el.PNum(2) == el.PNum(5)) { map = map2; deg2 = 1; } + if (el.PNum(3) == el.PNum(6)) { map = map3; deg3 = 1; } + + switch (deg1+deg2+deg3) + { + { + case 1: + cout << "degenerated prism found, deg = 1" << endl; + for (i = 0; i < 5; i++) + epi[i] = el.PNum (map[i]); + + if (np) *np = 5; + return NG_PYRAMID; + break; + } + case 2: + { + cout << "degenerated prism found, deg = 2" << endl; + if (!deg1) epi[3] = el.PNum(4); + if (!deg2) epi[3] = el.PNum(5); + if (!deg3) epi[3] = el.PNum(6); + + if (np) *np = 4; + return NG_TET; + break; + } + default: + ; + } + + } + + return NG_ELEMENT_TYPE (el.GetType()); + } + else + { + int i; + const Element2d & el = mesh->SurfaceElement (ei); + for (i = 0; i < el.GetNP(); i++) + epi[i] = el.PNum(i+1); + + if (np) *np = el.GetNP(); + return NG_ELEMENT_TYPE (el.GetType()); + /* + switch (el.GetNP()) + { + case 3: return NG_TRIG; + case 4: return NG_QUAD; + case 6: return NG_TRIG6; + } + */ + } + + // should not occur + return NG_TET; +} + + +NG_ELEMENT_TYPE Ng_GetElementType (int ei) +{ + if (mesh->GetDimension() == 3) + { + return NG_ELEMENT_TYPE (mesh->VolumeElement (ei).GetType()); + } + else + { + int i; + const Element2d & el = mesh->SurfaceElement (ei); + switch (el.GetNP()) + { + case 3: return NG_TRIG; + case 4: return NG_QUAD; + case 6: return NG_TRIG6; + } + } + + // should not occur + return NG_TET; +} + + + +int Ng_GetElementIndex (int ei) +{ + if (mesh->GetDimension() == 3) + return mesh->VolumeElement(ei).GetIndex(); + else + { + int ind = mesh->SurfaceElement(ei).GetIndex(); + ind = mesh->GetFaceDescriptor(ind).BCProperty(); + return ind; + } +} + +char * Ng_GetElementMaterial (int ei) +{ + static char empty[] = ""; + if (mesh->GetDimension() == 3) + { + int ind = mesh->VolumeElement(ei).GetIndex(); + // cout << "ind = " << ind << endl; + const char * mat = mesh->GetMaterial (ind); + if (mat) + return const_cast<char*> (mat); + else + return empty; + } + return 0; +} + +NG_ELEMENT_TYPE Ng_GetSurfaceElement (int ei, int * epi, int * np) +{ + if (mesh->GetDimension() == 3) + { + const Element2d & el = mesh->SurfaceElement (ei); + for (int i = 0; i < el.GetNP(); i++) + epi[i] = el[i]; + + if (np) *np = el.GetNP(); + + return NG_ELEMENT_TYPE (el.GetType()); + } + else + { + const Segment & seg = mesh->LineSegment (ei); + + if (seg.pmid < 0) + { + epi[0] = seg.p1; + epi[1] = seg.p2; + + if (np) *np = 2; + return NG_SEGM; + } + else + { + epi[0] = seg.p1; + epi[1] = seg.p2; + epi[2] = seg.pmid; + + if (np) *np = 3; + return NG_SEGM3; + } + } + + return NG_TRIG; +} + +int Ng_GetSurfaceElementIndex (int ei) +{ + if (mesh->GetDimension() == 3) + return mesh->GetFaceDescriptor(mesh->SurfaceElement(ei).GetIndex()).BCProperty(); + else + return mesh->LineSegment(ei).si; +} + + +void Ng_GetNormalVector (int sei, int locpi, double * nv) +{ + nv[0] = 0; + nv[1] = 0; + nv[2] = 1; + + (*testout) << "Ng_GetNormalVector (sei = " << sei << ", locpi = " << locpi << ")" << endl; + + 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 OCCGEOMETRY + 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); + } + else +#endif + if (geometry) + { + (*testout) << "geometry defined" << endl; + n = geometry->GetSurface (surfi) -> GetNormalVector(p); + (*testout) << "aus is" << endl; + nv[0] = n(0); + nv[1] = n(1); + nv[2] = n(2); + } + } +} + + +int Ng_FindElementOfPoint (double * p, double * lami, int build_searchtree, int index) +{ + if (mesh->GetDimension() == 3) + { + Point3d p3d(p[0], p[1], p[2]); + int ind = + mesh->GetElementOfPoint(p3d, lami, build_searchtree != 0, index); + return ind; + } + else + { + double lam3[3]; + Point3d p2d(p[0], p[1], 0); + int ind = + mesh->GetElementOfPoint(p2d, lam3, build_searchtree != 0, index); + lami[0] = lam3[0]; + lami[1] = lam3[1]; + return ind; + } +} + + + +void Ng_GetElementTransformation (int ei, const double * xi, + double * x, double * dxdxi) +{ + if (mesh->GetDimension() == 2) + { + Point<2> xl(xi[0], xi[1]); + Point<3> xg; + Mat<3,2> dx; + + mesh->GetCurvedElements().CalcSurfaceTransformation (xl, ei-1, xg, dx); + + if (x) + { + for (int i = 0; i < 2; i++) + x[i] = xg(i); + } + + if (dxdxi) + { + for (int i=0; i<2; i++) + { + dxdxi[2*i] = dx(i,0); + dxdxi[2*i+1] = dx(i,1); + } + } + } + else + { + Point<3> xl(xi[0], xi[1], xi[2]); + // (*testout) << "elnr = " << ei << ", eltrans, xl = " << xl << endl; + Point<3> xg; + Mat<3,3> dx; + + mesh->GetCurvedElements().CalcElementTransformation (xl, ei-1, xg, dx); + + // still 1-based arrays + if (x) + { + for (int i = 0; i < 3; i++) + x[i] = xg(i); + } + + if (dxdxi) + { + for (int i=0; i<3; i++) + { + dxdxi[3*i] = dx(i,0); + dxdxi[3*i+1] = dx(i,1); + dxdxi[3*i+2] = dx(i,2); + } + } + } +} + + +void Ng_GetSurfaceElementTransformation (int sei, const double * xi, + double * x, double * dxdxi) +{ + if (mesh->GetDimension() == 2) + { + Point<3> xg; + Vec<3> dx; + + // still 1-based arrays + mesh->GetCurvedElements().CalcSegmentTransformation (xi[0], sei-1, xg, dx); + + if (x) + for (int i = 0; i < 2; i++) + x[i] = xg(i); + + if (dxdxi) + for (int i=0; i<2; i++) + dxdxi[i] = dx(i); + + } + else + { + Point<2> xl(xi[0], xi[1]); + Point<3> xg; + Mat<3,2> dx; + + // still 1-based arrays + mesh->GetCurvedElements().CalcSurfaceTransformation (xl, sei-1, xg, dx); + + for (int i=0; i<3; i++) + { + if (x) + x[i] = xg(i); + if (dxdxi) + { + dxdxi[2*i] = dx(i,0); + dxdxi[2*i+1] = dx(i,1); + } + } + } +} + + + +void Ng_GetSurfaceElementNeighbouringDomains(const int selnr, int & in, int & out) +{ + in = mesh->GetFaceDescriptor((*mesh)[static_cast<SurfaceElementIndex>(selnr)].GetIndex()).DomainIn(); + out = mesh->GetFaceDescriptor((*mesh)[static_cast<SurfaceElementIndex>(selnr)].GetIndex()).DomainOut(); +} + + +void Ng_SetRefinementFlag (int ei, int flag) +{ + if (mesh->GetDimension() == 3) + mesh->VolumeElement(ei).SetRefinementFlag (flag != 0); + else + mesh->SurfaceElement(ei).SetRefinementFlag (flag != 0); +} + +void Ng_SetSurfaceRefinementFlag (int ei, int flag) +{ + if (mesh->GetDimension() == 3) + mesh->SurfaceElement(ei).SetRefinementFlag (flag != 0); +} + + +void Ng_Refine (NG_REFINEMENT_TYPE reftype) +{ + BisectionOptions biopt; + biopt.usemarkedelements = 1; + biopt.refine_p = 0; + biopt.refine_hp = 0; + if (reftype == NG_REFINE_P) + biopt.refine_p = 1; + if (reftype == NG_REFINE_HP) + biopt.refine_hp = 1; + Refinement * ref; + + if (geometry2d) + ref = new Refinement2d(*geometry2d); + else if (stlgeometry) + ref = new RefinementSTLGeometry(*stlgeometry); +#ifdef OCCGEOMETRY + else if (occgeometry) + ref = new OCCRefinementSurfaces (*occgeometry); +#endif + else if (geometry && mesh->GetDimension() == 3) + ref = new RefinementSurfaces(*geometry); + else + { + ref = new Refinement(); + } + + ref -> Bisect (*mesh, biopt); + + mesh -> UpdateTopology(); + // mesh -> GetCurvedElements().BuildCurvedElements (ref, mparam.elementorder); + delete ref; +} + +void Ng_SecondOrder () +{ + if (stlgeometry) + { + RefinementSTLGeometry ref (*stlgeometry); + ref.MakeSecondOrder (*mesh); + } + + else if (geometry2d) + { + Refinement2d ref (*geometry2d); + ref.MakeSecondOrder (*mesh); + } + + else if (geometry && mesh->GetDimension() == 3) + + { + RefinementSurfaces ref (*geometry); + ref.MakeSecondOrder (*mesh); + } + else + { + cout << "no geom" << endl; + Refinement ref; + ref.MakeSecondOrder (*mesh); + } + + mesh -> UpdateTopology(); +} + +void Ng_HPRefinement (int levels) +{ + 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_HighOrder (int order) +{ + Refinement * ref; + + if (stlgeometry) + ref = new RefinementSTLGeometry (*stlgeometry); +#ifdef OCCGEOMETRY + else if (occgeometry) + ref = new OCCRefinementSurfaces (*occgeometry); +#endif + else if (geometry2d) + ref = new Refinement2d (*geometry2d); + else + ref = new RefinementSurfaces (*geometry); + + // cout << "parameter 1: " << argv[1] << " (conversion to int = " << atoi(argv[1]) << ")" << endl; + + mesh -> GetCurvedElements().BuildCurvedElements (ref, order); + + delete ref; +} + + + + + + + + + + + + +int Ng_ME_GetNVertices (NG_ELEMENT_TYPE et) +{ + switch (et) + { + case NG_SEGM: + case NG_SEGM3: + return 2; + + case NG_TRIG: + case NG_TRIG6: + return 3; + + case NG_QUAD: + return 4; + + case NG_TET: + case NG_TET10: + return 4; + + case NG_PYRAMID: + return 5; + + case NG_PRISM: + case NG_PRISM12: + return 6; + + case NG_HEX: + return 8; + + default: + cerr << "Ng_ME_GetNVertices, illegal element type " << et << endl; + } + return 0; +} + +int Ng_ME_GetNEdges (NG_ELEMENT_TYPE et) +{ + switch (et) + { + case NG_SEGM: + case NG_SEGM3: + return 1; + + case NG_TRIG: + case NG_TRIG6: + return 3; + + case NG_QUAD: + return 4; + + case NG_TET: + case NG_TET10: + return 6; + + case NG_PYRAMID: + return 8; + + case NG_PRISM: + case NG_PRISM12: + return 9; + + case NG_HEX: + return 12; + + default: + cerr << "Ng_ME_GetNEdges, illegal element type " << et << endl; + } + return 0; +} + + +int Ng_ME_GetNFaces (NG_ELEMENT_TYPE et) +{ + switch (et) + { + case NG_SEGM: + case NG_SEGM3: + return 0; + + case NG_TRIG: + case NG_TRIG6: + return 1; + + case NG_QUAD: + case NG_QUAD6: + return 1; + + case NG_TET: + case NG_TET10: + return 4; + + case NG_PYRAMID: + return 5; + + case NG_PRISM: + case NG_PRISM12: + return 5; + + case NG_HEX: + return 6; + + default: + cerr << "Ng_ME_GetNVertices, illegal element type " << et << endl; + } + return 0; +} + + +const NG_POINT * Ng_ME_GetVertices (NG_ELEMENT_TYPE et) +{ + static double segm_points [][3] = + { { 1, 0, 0 }, + { 0, 0, 0 } }; + + static double trig_points [][3] = + { { 1, 0, 0 }, + { 0, 1, 0 }, + { 0, 0, 0 } }; + + static double quad_points [][3] = + { { 0, 0, 0 }, + { 1, 0, 0 }, + { 1, 1, 0 }, + { 0, 1, 0 } }; + + static double tet_points [][3] = + { { 1, 0, 0 }, + { 0, 1, 0 }, + { 0, 0, 1 }, + { 0, 0, 0 } }; + + static double pyramid_points [][3] = + { + { 0, 0, 0 }, + { 1, 0, 0 }, + { 1, 1, 0 }, + { 0, 1, 0 }, + { 0, 0, 1-1e-7 }, + }; + + static double prism_points[][3] = + { + { 1, 0, 0 }, + { 0, 1, 0 }, + { 0, 0, 0 }, + { 1, 0, 1 }, + { 0, 1, 1 }, + { 0, 0, 1 } + }; + + switch (et) + { + case NG_SEGM: + case NG_SEGM3: + return segm_points; + + case NG_TRIG: + case NG_TRIG6: + return trig_points; + + case NG_QUAD: + case NG_QUAD6: + return quad_points; + + case NG_TET: + case NG_TET10: + return tet_points; + + case NG_PYRAMID: + return pyramid_points; + + case NG_PRISM: + case NG_PRISM12: + return prism_points; + + case NG_HEX: + default: + cerr << "Ng_ME_GetVertices, illegal element type " << et << endl; + } + return 0; +} + + + +const NG_EDGE * Ng_ME_GetEdges (NG_ELEMENT_TYPE et) +{ + static int segm_edges[1][2] = + { { 1, 2 }}; + + static int trig_edges[3][2] = + { { 3, 1 }, + { 3, 2 }, + { 1, 2 }}; + + static int quad_edges[4][2] = + { { 1, 2 }, + { 4, 3 }, + { 1, 4 }, + { 2, 3 }}; + + + static int tet_edges[6][2] = + { { 4, 1 }, + { 4, 2 }, + { 4, 3 }, + { 1, 2 }, + { 1, 3 }, + { 2, 3 }}; + + static int prism_edges[9][2] = + { { 3, 1 }, + { 1, 2 }, + { 3, 2 }, + { 6, 4 }, + { 4, 5 }, + { 6, 5 }, + { 3, 6 }, + { 1, 4 }, + { 2, 5 }}; + + static int pyramid_edges[8][2] = + { { 1, 2 }, + { 2, 3 }, + { 1, 4 }, + { 4, 3 }, + { 1, 5 }, + { 2, 5 }, + { 3, 5 }, + { 4, 5 }}; + + + + switch (et) + { + case NG_SEGM: + case NG_SEGM3: + return segm_edges; + + case NG_TRIG: + case NG_TRIG6: + return trig_edges; + + case NG_QUAD: + case NG_QUAD6: + return quad_edges; + + case NG_TET: + case NG_TET10: + return tet_edges; + + case NG_PYRAMID: + return pyramid_edges; + + case NG_PRISM: + case NG_PRISM12: + return prism_edges; + + case NG_HEX: + default: + cerr << "Ng_ME_GetEdges, illegal element type " << et << endl; + } + return 0; +} + + +const NG_FACE * Ng_ME_GetFaces (NG_ELEMENT_TYPE et) +{ + static int tet_faces[4][4] = + { { 4, 2, 3, 0 }, + { 4, 1, 3, 0 }, + { 4, 1, 2, 0 }, + { 1, 2, 3, 0 } }; + + static int prism_faces[5][4] = + { + { 1, 2, 3, 0 }, + { 4, 5, 6, 0 }, + { 3, 1, 4, 6 }, + { 1, 2, 5, 4 }, + { 2, 3, 6, 5 } + }; + + static int pyramid_faces[5][4] = + { + { 1, 2, 5, 0 }, + { 2, 3, 5, 0 }, + { 3, 4, 5, 0 }, + { 4, 1, 5, 0 }, + { 1, 2, 3, 4 } + }; + + static int trig_faces[1][4] = + { + { 1, 2, 3, 0 }, + }; + + switch (et) + { + case NG_TET: + case NG_TET10: + return tet_faces; + + case NG_PRISM: + case NG_PRISM12: + return prism_faces; + + case NG_PYRAMID: + return pyramid_faces; + + + case NG_SEGM: + case NG_SEGM3: + + case NG_TRIG: + case NG_TRIG6: + return trig_faces; + case NG_QUAD: + + + case NG_HEX: + + default: + cerr << "Ng_ME_GetFaces, illegal element type " << et << endl; + } + return 0; +} + + +int Ng_GetNEdges() +{ + return mesh->GetTopology().GetNEdges(); +} +int Ng_GetNFaces() +{ + return mesh->GetTopology().GetNFaces(); +} + + + +int Ng_GetElement_Edges (int elnr, int * edges, int * orient) +{ + const MeshTopology & topology = mesh->GetTopology(); + if (mesh->GetDimension() == 3) + return topology.GetElementEdges (elnr, edges, orient); + else + return topology.GetSurfaceElementEdges (elnr, edges, orient); +} + +int Ng_GetElement_Faces (int elnr, int * faces, int * orient) +{ + const MeshTopology & topology = mesh->GetTopology(); + if (mesh->GetDimension() == 3) + return topology.GetElementFaces (elnr, faces, orient); + else + { + faces[0] = elnr; + if (orient) orient[0] = 0; + return 1; + } +} + +int Ng_GetSurfaceElement_Edges (int elnr, int * edges, int * orient) +{ + const MeshTopology & topology = mesh->GetTopology(); + if (mesh->GetDimension() == 3) + return topology.GetSurfaceElementEdges (elnr, edges, orient); + else + { + if (orient) + topology.GetSegmentEdge(elnr, edges[0], orient[0]); + else + edges[0] = topology.GetSegmentEdge(elnr); + } + return 1; + /* + int i, ned; + const MeshTopology & topology = mesh->GetTopology(); + ARRAY<int> ia; + topology.GetSurfaceElementEdges (elnr, ia); + ned = ia.Size(); + for (i = 1; i <= ned; i++) + edges[i-1] = ia.Get(i); + + if (orient) + { + topology.GetSurfaceElementEdgeOrientations (elnr, ia); + for (i = 1; i <= ned; i++) + orient[i-1] = ia.Get(i); + } + return ned; + */ +} + +int Ng_GetSurfaceElement_Face (int selnr, int * orient) +{ + if (mesh->GetDimension() == 3) + { + const MeshTopology & topology = mesh->GetTopology(); + if (orient) + *orient = topology.GetSurfaceElementFaceOrientation (selnr); + return topology.GetSurfaceElementFace (selnr); + } + return -1; +} + +int Ng_GetFace_Vertices (int fnr, int * vert) +{ + const MeshTopology & topology = mesh->GetTopology(); + ArrayMem<int,4> ia; + topology.GetFaceVertices (fnr, ia); + for (int i = 0; i < ia.Size(); i++) + vert[i] = ia[i]; + // cout << "face verts = " << ia << endl; + return ia.Size(); +} + + +int Ng_GetFace_Edges (int fnr, int * edge) +{ + const MeshTopology & topology = mesh->GetTopology(); + ArrayMem<int,4> ia; + topology.GetFaceEdges (fnr, ia); + for (int i = 0; i < ia.Size(); i++) + edge[i] = ia[i]; + return ia.Size(); +} + +void Ng_GetEdge_Vertices (int ednr, int * vert) +{ + const MeshTopology & topology = mesh->GetTopology(); + topology.GetEdgeVertices (ednr, vert[0], vert[1]); +} + + +int Ng_GetNVertexElements (int vnr) +{ + if (mesh->GetDimension() == 3) + return mesh->GetTopology().GetVertexElements(vnr).Size(); + else + return mesh->GetTopology().GetVertexSurfaceElements(vnr).Size(); +} + +void Ng_GetVertexElements (int vnr, int * els) +{ + FlatArray<int> ia(0,0); + if (mesh->GetDimension() == 3) + ia = mesh->GetTopology().GetVertexElements(vnr); + else + ia = mesh->GetTopology().GetVertexSurfaceElements(vnr); + for (int i = 0; i < ia.Size(); i++) + els[i] = ia[i]; +} + + +int Ng_GetElementOrder (int enr) +{ + if (mesh->GetDimension() == 3) + return mesh->VolumeElement(enr).GetOrder(); + else + return mesh->SurfaceElement(enr).GetOrder(); +} + + + +int Ng_GetNLevels () +{ + return mesh->mglevels; +} + + +void Ng_GetParentNodes (int ni, int * parents) +{ + if (ni <= mesh->mlbetweennodes.Size()) + { + parents[0] = mesh->mlbetweennodes.Get(ni).I1(); + parents[1] = mesh->mlbetweennodes.Get(ni).I2(); + } + else + parents[0] = parents[1] = 0; +} + + +int Ng_GetParentElement (int ei) +{ + if (mesh->GetDimension() == 3) + { + if (ei <= mesh->mlparentelement.Size()) + return mesh->mlparentelement.Get(ei); + } + else + { + if (ei <= mesh->mlparentsurfaceelement.Size()) + return mesh->mlparentsurfaceelement.Get(ei); + } + return 0; +} + + +int Ng_GetParentSElement (int ei) +{ + if (mesh->GetDimension() == 3) + { + if (ei <= mesh->mlparentsurfaceelement.Size()) + return mesh->mlparentsurfaceelement.Get(ei); + } + else + { + return 0; + } + return 0; +} + + + + + +int Ng_GetClusterRepVertex (int pi) +{ + return mesh->GetClusters().GetVertexRepresentant(pi); +} + +int Ng_GetClusterRepEdge (int pi) +{ + return mesh->GetClusters().GetEdgeRepresentant(pi); +} + +int Ng_GetClusterRepFace (int pi) +{ + return mesh->GetClusters().GetFaceRepresentant(pi); +} + +int Ng_GetClusterRepElement (int pi) +{ + return mesh->GetClusters().GetElementRepresentant(pi); +} + + + + + + +void Ng_InitSolutionData (Ng_SolutionData * soldata) +{ + soldata -> name = NULL; + soldata -> data = NULL; + soldata -> components = 1; + soldata -> dist = 1; + soldata -> order = 1; + soldata -> iscomplex = 0; + soldata -> draw_surface = 1; + soldata -> draw_volume = 1; + soldata -> soltype = NG_SOLUTION_NODAL; + soldata -> solclass = 0; +} + +void Ng_SetSolutionData (Ng_SolutionData * soldata) +{ +#ifdef OPENGL + // vssolution.ClearSolutionData (); + VisualSceneSolution::SolData * vss = new VisualSceneSolution::SolData; + + // cout << "Add solution " << soldata->name << ", type = " << soldata->soltype << endl; + + vss->name = new char[strlen (soldata->name)+1]; + strcpy (vss->name, soldata->name); + + vss->data = soldata->data; + vss->components = soldata->components; + vss->dist = soldata->dist; + vss->order = soldata->order; + vss->iscomplex = bool(soldata->iscomplex); + vss->draw_surface = soldata->draw_surface; + vss->draw_volume = soldata->draw_volume; + vss->soltype = VisualSceneSolution::SolType (soldata->soltype); + vss->solclass = soldata->solclass; + vssolution.AddSolutionData (vss); +#endif +} + +void Ng_ClearSolutionData () +{ + vssolution.ClearSolutionData(); +} + + + +void Ng_Redraw () +{ +#ifdef OPENGL + vssolution.UpdateSolutionTimeStamp(); + Render(); +#endif +} + + +void Ng_SetVisualizationParameter (const char * name, const char * value) +{ +#ifdef OPENGL + char buf[100]; + sprintf (buf, "visoptions.%s", name); + cout << "name = " << name << ", value = " << value << endl; + cout << "set tcl-variable " << buf << " to " << value << endl; + Tcl_SetVar (tcl_interp, buf, const_cast<char*> (value), 0); + Tcl_Eval (tcl_interp, "Ng_Vis_Set parameters;"); +#endif +} + + + + +int firsttime = 1; +int animcnt = 0; +void PlayAnimFile(const char* name, int speed, int maxcnt) +{ + //extern Mesh * mesh; + + /* + if (mesh.Ptr()) mesh->DeleteMesh(); + if (!mesh.Ptr()) mesh = new Mesh(); + */ + mesh.Reset (new Mesh()); + + int ne, np, i, ti; + + char str[80]; + char str2[80]; + + //int tend = 5000; + // for (ti = 1; ti <= tend; ti++) + //{ + int rti = (animcnt%(maxcnt-1)) + 1; + animcnt+=speed; + + sprintf(str2,"%05i.sol",rti); + strcpy(str,"mbssol/"); + strcat(str,name); + strcat(str,str2); + + cout << "read file '" << str << "'" << endl; + + ifstream infile(str); + infile >> ne; + for (i = 1; i <= ne; i++) + { + int j; + Element2d tri(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)=p; + } + + //firsttime = 0; + Ng_Redraw(); + } +} + + +int Ng_GetNPeriodicVertices () +{ + ARRAY<INDEX_2> apairs; + mesh->GetIdentifications().GetPairs (0, apairs); + return apairs.Size(); +} + + +// pairs should be an integer array of 2*npairs +void Ng_GetPeriodicVertices (int * pairs) +{ + ARRAY<INDEX_2> apairs; + mesh->GetIdentifications().GetPairs (0, apairs); + for (int i = 0; i < apairs.Size(); i++) + { + pairs[2*i] = apairs[i].I1(); + pairs[2*i+1] = apairs[i].I2(); + } + +} + + + +int Ng_GetNPeriodicEdges () +{ + ARRAY<INDEX,PointIndex::BASE> map; + const MeshTopology & top = mesh->GetTopology(); + int nse = mesh->GetNSeg(); + + int cnt = 0; + // for (int id = 1; id <= mesh->GetIdentifications().GetMaxNr(); id++) + { + mesh->GetIdentifications().GetMap(0, map); + //(*testout) << "ident-map " << id << ":" << endl << map << endl; + + for (SegmentIndex si = 0; si < nse; si++) + { + PointIndex other1 = map[(*mesh)[si].p1]; + PointIndex other2 = map[(*mesh)[si].p2]; + // (*testout) << "seg = " << (*mesh)[si] << "; other = " + // << other1 << "-" << other2 << endl; + if (other1 && other2 && mesh->IsSegment (other1, other2)) + { + cnt++; + } + } + } + return cnt; +} + +void Ng_GetPeriodicEdges (int * pairs) +{ + ARRAY<INDEX,PointIndex::BASE> map; + const MeshTopology & top = mesh->GetTopology(); + int nse = mesh->GetNSeg(); + + int cnt = 0; + // for (int id = 1; id <= mesh->GetIdentifications().GetMaxNr(); id++) + { + mesh->GetIdentifications().GetMap(0, map); + + //(*testout) << "map = " << map << endl; + + for (SegmentIndex si = 0; si < nse; si++) + { + PointIndex other1 = map[(*mesh)[si].p1]; + PointIndex other2 = map[(*mesh)[si].p2]; + if (other1 && other2 && mesh->IsSegment (other1, other2)) + { + SegmentIndex otherseg = mesh->SegmentNr (other1, other2); + pairs[cnt++] = top.GetSegmentEdge (si+1); + pairs[cnt++] = top.GetSegmentEdge (otherseg+1); + } + } + } +} + + + +void Ng_PushStatus (const char * str) +{ + PushStatus (MyStr (str)); +} + +void Ng_PopStatus () +{ + PopStatus (); +} + +void Ng_SetThreadPercentage (double percent) +{ + SetThreadPercent (percent); +} + + +///// Added by Roman Stainko .... +int Ng_GetVertex_Elements( int vnr, int* elems ) +{ + const MeshTopology& topology = mesh->GetTopology(); + ArrayMem<int,4> indexArray; + topology.GetVertexElements( vnr, indexArray ); + + for( int i=0; i<indexArray.Size(); i++ ) + elems[i] = indexArray[i]; + + return indexArray.Size(); +} + +///// Added by Roman Stainko .... +int Ng_GetVertex_SurfaceElements( int vnr, int* elems ) +{ + const MeshTopology& topology = mesh->GetTopology(); + ArrayMem<int,4> indexArray; + topology.GetVertexSurfaceElements( vnr, indexArray ); + + for( int i=0; i<indexArray.Size(); i++ ) + elems[i] = indexArray[i]; + + return indexArray.Size(); +} + +///// Added by Roman Stainko .... +int Ng_GetVertex_NElements( int vnr ) +{ + const MeshTopology& topology = mesh->GetTopology(); + ArrayMem<int,4> indexArray; + topology.GetVertexElements( vnr, indexArray ); + + return indexArray.Size(); +} + +///// Added by Roman Stainko .... +int Ng_GetVertex_NSurfaceElements( int vnr ) +{ + const MeshTopology& topology = mesh->GetTopology(); + ArrayMem<int,4> indexArray; + topology.GetVertexSurfaceElements( vnr, indexArray ); + + return indexArray.Size(); +} + + + diff --git a/contrib/Netgen/libsrc/interface/nginterface.h b/contrib/Netgen/libsrc/interface/nginterface.h new file mode 100644 index 0000000000..dcb8ddd332 --- /dev/null +++ b/contrib/Netgen/libsrc/interface/nginterface.h @@ -0,0 +1,245 @@ +#ifndef NGINTERFACE +#define NGINTERFACE + +/**************************************************************************/ +/* File: nginterface.hh */ +/* Author: Joachim Schoeberl */ +/* Date: 20. Nov. 99 */ +/**************************************************************************/ + +/* + + Application program interface to Netgen + + + */ + + +// max number of nodes per element +#define NG_ELEMENT_MAXPOINTS 12 + +// max number of nodes per surface element +#define NG_SURFACE_ELEMENT_MAXPOINTS 8 + + + +// implemented element types: +enum NG_ELEMENT_TYPE { + NG_SEGM = 1, NG_SEGM3 = 2, + NG_TRIG = 10, NG_QUAD=11, NG_TRIG6 = 12, NG_QUAD6 = 13, + NG_TET = 20, NG_TET10 = 21, + NG_PYRAMID = 22, NG_PRISM = 23, NG_PRISM12 = 24, + NG_HEX = 25 +}; + +typedef double NG_POINT[3]; // coordinates +typedef int NG_EDGE[2]; // initial point, end point +typedef int NG_FACE[4]; // points, last one is 0 for trig + + +#ifdef __cplusplus +extern "C" { +#endif + + // load geomtry from file + void Ng_LoadGeometry (char * filename); + + // load netgen mesh + void Ng_LoadMesh (char * filename); + + + // space dimension (2 or 3) + int Ng_GetDimension (); + + // number of mesh points + int Ng_GetNP (); + + // number of mesh vertices (differs from GetNP for 2nd order elements) + int Ng_GetNV (); + + // number of mesh elements + int Ng_GetNE (); + + // number of surface triangles + int Ng_GetNSE (); + + // Get Point coordintes, index from 1 .. np + void Ng_GetPoint (int pi, double * p); + + // Get Element Points + NG_ELEMENT_TYPE Ng_GetElement (int ei, int * epi, int * np = 0); + + // Get Element Type + NG_ELEMENT_TYPE Ng_GetElementType (int ei); + + // Get sub-domain of element ei + int Ng_GetElementIndex (int ei); + + // Get Material of element ei + char * Ng_GetElementMaterial (int ei); + + // Get Surface Element Points + NG_ELEMENT_TYPE Ng_GetSurfaceElement (int ei, int * epi, int * np = 0); + + // Get Surface Element Index + int Ng_GetSurfaceElementIndex (int ei); + + // Get normal vector of surface element node + void Ng_GetNormalVector (int sei, int locpi, double * nv); + + + // Find element of point, returns local coordinates + int Ng_FindElementOfPoint (double * p, double * lami, + int build_searchtrees = 0, int index = -1); + + + /// Curved Elemens: + /// xi..local coordinates + /// x ..global coordinates + /// dxdxi...D x D Jacobian matrix (row major storage) + void Ng_GetElementTransformation (int ei, const double * xi, + double * x, double * dxdxi); + + /// Curved Elemens: + /// xi..local coordinates + /// x ..global coordinates + /// dxdxi...D x D-1 Jacobian matrix (row major storage) + void Ng_GetSurfaceElementTransformation (int sei, const double * xi, double * x, double * dxdxi); + + + // Mark element for refinement + void Ng_SetRefinementFlag (int ei, int flag); + 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 }; + void Ng_Refine (NG_REFINEMENT_TYPE reftype); + + // Use second order elements + void Ng_SecondOrder (); + void Ng_HighOrder (int order); + void Ng_HPRefinement (int levels); + + + // Topology and coordinate information of master element: + + int Ng_ME_GetNVertices (NG_ELEMENT_TYPE et); + int Ng_ME_GetNEdges (NG_ELEMENT_TYPE et); + int Ng_ME_GetNFaces (NG_ELEMENT_TYPE et); + + const NG_POINT * Ng_ME_GetVertices (NG_ELEMENT_TYPE et); + const NG_EDGE * Ng_ME_GetEdges (NG_ELEMENT_TYPE et); + const NG_FACE * Ng_ME_GetFaces (NG_ELEMENT_TYPE et); + + int Ng_GetNEdges(); + int Ng_GetNFaces(); + + + int Ng_GetElement_Edges (int elnr, int * edges, int * orient = 0); + int Ng_GetElement_Faces (int elnr, int * faces, int * orient = 0); + + int Ng_GetSurfaceElement_Edges (int selnr, int * edges, int * orient = 0); + int Ng_GetSurfaceElement_Face (int selnr, int * orient = 0); + + void Ng_GetSurfaceElementNeighbouringDomains(const int selnr, int & in, int & out); + + int Ng_GetFace_Vertices (int fnr, int * vert); + void Ng_GetEdge_Vertices (int ednr, int * vert); + int Ng_GetFace_Edges (int fnr, int * edge); + + int Ng_GetNVertexElements (int vnr); + void Ng_GetVertexElements (int vnr, int * els); + + int Ng_GetElementOrder (int enr); + + // Multilevel functions: + + // number of levels: + int Ng_GetNLevels (); + // get two parent nodes of node ni + void Ng_GetParentNodes (int ni, int * parents); + + // get parent element (first child has always same number) + int Ng_GetParentElement (int ei); + + // get parent surface element (first child has always same number) + int Ng_GetParentSElement (int ei); + + // representant of anisotropic cluster + int Ng_GetClusterRepVertex (int vi); + int Ng_GetClusterRepEdge (int edi); + int Ng_GetClusterRepFace (int fai); + int Ng_GetClusterRepElement (int eli); + + + void Ng_SurfaceElementTransformation (int eli, double x, double y, + double * p3d, double * jacobian); + +namespace netgen { +#include "../visualization/soldata.hpp" +} + + 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 + { + char * name; // name of gridfunction + double * data; // solution values + int components; // relevant (double) components in solution vector + int dist; // # doubles per entry alignment! + int iscomplex; // complex vector ? + bool draw_surface; + bool draw_volume; + int order; // order of elements, only partially supported + Ng_SolutionType soltype; // type of solution function + netgen::SolutionData * solclass; + }; + + // initialize solution data with default arguments + void Ng_InitSolutionData (Ng_SolutionData * soldata); + // set solution data + void Ng_SetSolutionData (Ng_SolutionData * soldata); + /// delete gridfunctions + void Ng_ClearSolutionData(); + // redraw + void Ng_Redraw(); + // + void Ng_SetVisualizationParameter (const char * name, + const char * value); + + + // number of periodic vertices + int Ng_GetNPeriodicVertices (); + // pairs should be an integer array of 2*npairs + void Ng_GetPeriodicVertices (int * pairs); + + // number of periodic edges + int Ng_GetNPeriodicEdges (); + // pairs should be an integer array of 2*npairs + void Ng_GetPeriodicEdges (int * pairs); + + + void Ng_PushStatus (const char * str); + void Ng_PopStatus (); + void Ng_SetThreadPercentage (double percent); + + //// added by Roman Stainko .... + int Ng_GetVertex_Elements( int vnr, int* elems); + int Ng_GetVertex_SurfaceElements( int vnr, int* elems ); + int Ng_GetVertex_NElements( int vnr ); + int Ng_GetVertex_NSurfaceElements( int vnr ); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/contrib/Netgen/libsrc/interface/nglib.cpp b/contrib/Netgen/libsrc/interface/nglib.cpp new file mode 100644 index 0000000000..d2e59f931e --- /dev/null +++ b/contrib/Netgen/libsrc/interface/nglib.cpp @@ -0,0 +1,573 @@ +/**************************************************************************/ +/* File: nglib.cc */ +/* Author: Joachim Schoeberl */ +/* Date: 7. May. 2000 */ +/**************************************************************************/ + +/* + + Interface to the netgen meshing kernel + +*/ + + +#include <mystdlib.h> +#include <myadt.hpp> + +#include <linalg.hpp> +#include <csg.hpp> +#include <stlgeom.hpp> +#include <geometry2d.hpp> +#include <meshing.hpp> + + + +// #include <FlexLexer.h> + +namespace netgen { + extern void MeshFromSpline2D (SplineGeometry2d & geometry, + Mesh *& mesh, + MeshingParameters & mp); +} + + + + + + + +namespace nglib { +#include "nglib.h" +} + +using namespace netgen; + +// constants and types: + +namespace nglib +{ +// initialize, deconstruct Netgen library: +void Ng_Init () +{ + mycout = &cout; + myerr = &cerr; + testout = new ofstream ("test.out"); +} + +void Ng_Exit () +{ + ; +} + + + +Ng_Mesh * Ng_NewMesh () +{ + Mesh * mesh = new Mesh; + mesh->AddFaceDescriptor (FaceDescriptor (1, 1, 0, 1)); + return (Ng_Mesh*)(void*)mesh; +} + +void Ng_DeleteMesh (Ng_Mesh * mesh) +{ + delete (Mesh*)mesh; +} + + +// feeds points, surface elements and volume elements to the mesh +void Ng_AddPoint (Ng_Mesh * mesh, double * x) +{ + Mesh * m = (Mesh*)mesh; + m->AddPoint (Point3d (x[0], x[1], x[2])); +} + +void Ng_AddSurfaceElement (Ng_Mesh * mesh, Ng_Surface_Element_Type et, + int * pi) +{ + Mesh * m = (Mesh*)mesh; + Element2d el (3); + el.SetIndex (1); + el.PNum(1) = pi[0]; + el.PNum(2) = pi[1]; + el.PNum(3) = pi[2]; + m->AddSurfaceElement (el); +} + +void Ng_AddVolumeElement (Ng_Mesh * mesh, Ng_Volume_Element_Type et, + int * pi) +{ + Mesh * m = (Mesh*)mesh; + Element el (4); + el.SetIndex (1); + el.PNum(1) = pi[0]; + el.PNum(2) = pi[1]; + el.PNum(3) = pi[2]; + el.PNum(4) = pi[3]; + m->AddVolumeElement (el); +} + +// ask for number of points, surface and volume elements +int Ng_GetNP (Ng_Mesh * mesh) +{ + return ((Mesh*)mesh) -> GetNP(); +} + +int Ng_GetNSE (Ng_Mesh * mesh) +{ + return ((Mesh*)mesh) -> GetNSE(); +} + +int Ng_GetNE (Ng_Mesh * mesh) +{ + return ((Mesh*)mesh) -> GetNE(); +} + + +// return point coordinates +void Ng_GetPoint (Ng_Mesh * mesh, int num, double * x) +{ + const Point3d & p = ((Mesh*)mesh)->Point(num); + x[0] = p.X(); + x[1] = p.Y(); + x[2] = p.Z(); +} + +// return surface and volume element in pi +Ng_Surface_Element_Type +Ng_GetSurfaceElement (Ng_Mesh * mesh, int num, int * pi) +{ + const Element2d & el = ((Mesh*)mesh)->SurfaceElement(num); + for (int i = 1; i <= el.GetNP(); i++) + pi[i-1] = el.PNum(i); + Ng_Surface_Element_Type et; + switch (el.GetNP()) + { + case 3: et = NG_TRIG; break; + case 4: et = NG_QUAD; break; + case 6: et = NG_TRIG6; break; + } + return et; +} + +Ng_Volume_Element_Type +Ng_GetVolumeElement (Ng_Mesh * mesh, int num, int * pi) +{ + const Element & el = ((Mesh*)mesh)->VolumeElement(num); + for (int i = 1; i <= el.GetNP(); i++) + pi[i-1] = el.PNum(i); + Ng_Volume_Element_Type et; + switch (el.GetNP()) + { + case 4: et = NG_TET; break; + case 5: et = NG_PYRAMID; break; + case 6: et = NG_PRISM; break; + case 10: et = NG_TET10; break; + } + return et; +} + + + +// generates volume mesh from surface mesh +Ng_Result Ng_GenerateVolumeMesh (Ng_Mesh * mesh, Ng_Meshing_Parameters * mp) +{ + Mesh * m = (Mesh*)mesh; + + + MeshingParameters mparam; + mparam.maxh = mp->maxh; + mparam.meshsizefilename = mp->meshsize_filename; + + m->CalcLocalH(); + + MeshVolume (mparam, *m); + RemoveIllegalElements (*m); + OptimizeVolume (mparam, *m); + + return NG_OK; +} + + + +// 2D Meshing Functions: + + + +void Ng_AddPoint_2D (Ng_Mesh * mesh, double * x) +{ + Mesh * m = (Mesh*)mesh; + + m->AddPoint (Point3d (x[0], x[1], 0)); +} + +void Ng_AddBoundarySeg_2D (Ng_Mesh * mesh, int pi1, int pi2) +{ + Mesh * m = (Mesh*)mesh; + + Segment seg; + seg.p1 = pi1; + seg.p2 = pi2; + m->AddSegment (seg); +} + + +int Ng_GetNP_2D (Ng_Mesh * mesh) +{ + Mesh * m = (Mesh*)mesh; + return m->GetNP(); +} + +int Ng_GetNE_2D (Ng_Mesh * mesh) +{ + Mesh * m = (Mesh*)mesh; + return m->GetNSE(); +} + +int Ng_GetNSeg_2D (Ng_Mesh * mesh) +{ + Mesh * m = (Mesh*)mesh; + return m->GetNSeg(); +} + +void Ng_GetPoint_2D (Ng_Mesh * mesh, int num, double * x) +{ + Mesh * m = (Mesh*)mesh; + + Point3d & p = m->Point(num); + x[0] = p.X(); + x[1] = p.Y(); +} + +void Ng_GetElement_2D (Ng_Mesh * mesh, int num, int * pi, int * matnum) +{ + const Element2d & el = ((Mesh*)mesh)->SurfaceElement(num); + for (int i = 1; i <= 3; i++) + pi[i-1] = el.PNum(i); + if (matnum) + *matnum = el.GetIndex(); +} + + +void Ng_GetSegment_2D (Ng_Mesh * mesh, int num, int * pi, int * matnum) +{ + const Segment & seg = ((Mesh*)mesh)->LineSegment(num); + pi[0] = seg.p1; + pi[1] = seg.p2; + + if (matnum) + *matnum = seg.edgenr; +} + + + + +Ng_Geometry_2D * Ng_LoadGeometry_2D (const char * filename) +{ + SplineGeometry2d * geom = new SplineGeometry2d(); + geom -> Load (filename); + return (Ng_Geometry_2D *)geom; +} + +Ng_Result Ng_GenerateMesh_2D (Ng_Geometry_2D * geom, + Ng_Mesh ** mesh, + Ng_Meshing_Parameters * mp) +{ + // use global variable mparam + // MeshingParameters mparam; + mparam.maxh = mp->maxh; + mparam.meshsizefilename = mp->meshsize_filename; + mparam.quad = mp->quad_dominated; + + Mesh * m; + MeshFromSpline2D (*(SplineGeometry2d*)geom, m, mparam); + + cout << m->GetNSE() << " elements, " << m->GetNP() << " points" << endl; + + *mesh = (Ng_Mesh*)m; + return NG_OK; +} + + + +void Ng_HP_Refinement (Ng_Geometry_2D * geom, + Ng_Mesh * mesh, + int levels) +{ + Refinement2d ref(*(SplineGeometry2d*)geom); + HPRefinement (*(Mesh*)mesh, &ref, levels); +} + + + + + + + + + + + + + +ARRAY<STLReadTriangle> readtrias; //only before initstlgeometry +ARRAY<Point<3> > readedges; //only before init stlgeometry + +void Ng_SaveMesh(Ng_Mesh * mesh, const char* filename) +{ + ((Mesh*)mesh)->Save(filename); +} + +Ng_Mesh * Ng_LoadMesh(const char* filename) +{ + Mesh * mesh = new Mesh; + mesh->Load(filename); + return ( (Ng_Mesh*)mesh ); +} + +// loads geometry from STL file +Ng_STL_Geometry * Ng_STL_LoadGeometry (const char * filename, int binary) +{ + int i; + STLGeometry geom; + STLGeometry* geo; + ifstream ist(filename); + + if (binary) + { + geo = geom.LoadBinary(ist); + } + else + { + geo = geom.Load(ist); + } + + readtrias.SetSize(0); + readedges.SetSize(0); + + Point3d p; + Vec3d normal; + double p1[3]; + double p2[3]; + double p3[3]; + double n[3]; + + Ng_STL_Geometry * geo2 = Ng_STL_NewGeometry(); + + for (i = 1; i <= geo->GetNT(); i++) + { + const STLTriangle& t = geo->GetTriangle(i); + p = geo->GetPoint(t.PNum(1)); + p1[0] = p.X(); p1[1] = p.Y(); p1[2] = p.Z(); + p = geo->GetPoint(t.PNum(2)); + p2[0] = p.X(); p2[1] = p.Y(); p2[2] = p.Z(); + p = geo->GetPoint(t.PNum(3)); + p3[0] = p.X(); p3[1] = p.Y(); p3[2] = p.Z(); + normal = t.Normal(); + n[0] = normal.X(); n[1] = normal.Y(); n[2] = normal.Z(); + + Ng_STL_AddTriangle(geo2, p1, p2, p3, n); + } + + return geo2; +} + +// generate new STL Geometry +Ng_STL_Geometry * Ng_STL_NewGeometry () +{ + return (Ng_STL_Geometry*)(void*)new STLGeometry; +} + +// after adding triangles (and edges) initialize +Ng_Result Ng_STL_InitSTLGeometry (Ng_STL_Geometry * geom) +{ + STLGeometry* geo = (STLGeometry*)geom; + geo->InitSTLGeometry(readtrias); + readtrias.SetSize(0); + + if (readedges.Size() != 0) + { + int i; + /* + for (i = 1; i <= readedges.Size(); i+=2) + { + cout << "e(" << readedges.Get(i) << "," << readedges.Get(i+1) << ")" << endl; + } + */ + geo->AddEdges(readedges); + } + + if (geo->GetStatus() == STLTopology::STL_GOOD || geo->GetStatus() == STLTopology::STL_WARNING) return NG_OK; + return NG_SURFACE_INPUT_ERROR; +} + + // automatically generates edges: +Ng_Result Ng_STL_MakeEdges (Ng_STL_Geometry * geom, + Ng_Mesh* mesh, + Ng_Meshing_Parameters * mp) +{ + STLGeometry* stlgeometry = (STLGeometry*)geom; + Mesh* me = (Mesh*)mesh; + + MeshingParameters mparam; + + mparam.maxh = mp->maxh; + mparam.meshsizefilename = mp->meshsize_filename; + + me -> SetGlobalH (mparam.maxh); + me -> SetLocalH (stlgeometry->GetBoundingBox().PMin() - Vec3d(10, 10, 10), + stlgeometry->GetBoundingBox().PMax() + Vec3d(10, 10, 10), + 0.3); + + me -> LoadLocalMeshSize (mp->meshsize_filename); + /* + if (mp->meshsize_filename) + { + ifstream infile (mp->meshsize_filename); + if (!infile.good()) return NG_FILE_NOT_FOUND; + me -> LoadLocalMeshSize (infile); + } + */ + + STLMeshing (*stlgeometry, *me); + + stlgeometry->edgesfound = 1; + stlgeometry->surfacemeshed = 0; + stlgeometry->surfaceoptimized = 0; + stlgeometry->volumemeshed = 0; + + return NG_OK; +} + + +// generates mesh, empty mesh be already created. +Ng_Result Ng_STL_GenerateSurfaceMesh (Ng_STL_Geometry * geom, + Ng_Mesh* mesh, + Ng_Meshing_Parameters * mp) +{ + STLGeometry* stlgeometry = (STLGeometry*)geom; + Mesh* me = (Mesh*)mesh; + + MeshingParameters mparam; + + mparam.maxh = mp->maxh; + mparam.meshsizefilename = mp->meshsize_filename; + + /* + me -> SetGlobalH (mparam.maxh); + me -> SetLocalH (stlgeometry->GetBoundingBox().PMin() - Vec3d(10, 10, 10), + stlgeometry->GetBoundingBox().PMax() + Vec3d(10, 10, 10), + 0.3); + */ + /* + STLMeshing (*stlgeometry, *me); + + stlgeometry->edgesfound = 1; + stlgeometry->surfacemeshed = 0; + stlgeometry->surfaceoptimized = 0; + stlgeometry->volumemeshed = 0; + */ + int retval = STLSurfaceMeshing (*stlgeometry, *me); + if (retval == MESHING3_OK) + { + (*mycout) << "Success !!!!" << endl; + stlgeometry->surfacemeshed = 1; + stlgeometry->surfaceoptimized = 0; + stlgeometry->volumemeshed = 0; + } + else if (retval == MESHING3_OUTERSTEPSEXCEEDED) + { + (*mycout) << "ERROR: Give up because of too many trials. Meshing aborted!" << endl; + } + else if (retval == MESHING3_TERMINATE) + { + (*mycout) << "Meshing Stopped!" << endl; + } + else + { + (*mycout) << "ERROR: Surface meshing not successful. Meshing aborted!" << endl; + } + + + STLSurfaceOptimization (*stlgeometry, *me, mparam); + + return NG_OK; +} + + + // fills STL Geometry + // positive orientation + // normal vector may be null-pointer +void Ng_STL_AddTriangle (Ng_STL_Geometry * geom, + double * p1, double * p2, double * p3, double * nv) +{ + Point<3> apts[3]; + apts[0] = Point<3>(p1[0],p1[1],p1[2]); + apts[1] = Point<3>(p2[0],p2[1],p2[2]); + apts[2] = Point<3>(p3[0],p3[1],p3[2]); + + Vec<3> n; + if (!nv) + n = Cross (apts[0]-apts[1], apts[0]-apts[2]); + else + n = Vec<3>(nv[0],nv[1],nv[2]); + + readtrias.Append(STLReadTriangle(apts,n)); +} + + // add (optional) edges: +void Ng_STL_AddEdge (Ng_STL_Geometry * geom, + double * p1, double * p2) +{ + readedges.Append(Point3d(p1[0],p1[1],p1[2])); + readedges.Append(Point3d(p2[0],p2[1],p2[2])); +} + + + +Ng_Meshing_Parameters :: Ng_Meshing_Parameters() +{ + maxh = 1000; + fineness = 0.5; + secondorder = 0; + meshsize_filename = 0; + quad_dominated = 0; +} + + +} + + +// compatibility functions: + +namespace netgen +{ + + char geomfilename[255]; + +void MyError (const char * ch) +{ + cerr << ch; +} + +//Destination for messages, errors, ... +void Ng_PrintDest(const char * s) +{ + (*mycout) << s << flush; +} + +double GetTime () +{ + return 0; +} + +void ResetTime () +{ + ; +} + +void MyBeep (int i) +{ + ; +} + +} diff --git a/contrib/Netgen/libsrc/interface/nglib.h b/contrib/Netgen/libsrc/interface/nglib.h new file mode 100644 index 0000000000..20d745d470 --- /dev/null +++ b/contrib/Netgen/libsrc/interface/nglib.h @@ -0,0 +1,208 @@ +#ifndef NGLIB +#define NGLIB + +/**************************************************************************/ +/* File: nglib.hh */ +/* Author: Joachim Schoeberl */ +/* Date: 7. May. 2000 */ +/**************************************************************************/ + +/* + + Interface to the netgen meshing kernel + +*/ + +/// Data type for NETGEN mesh +typedef void * Ng_Mesh; + +/// Data type for NETGEN CSG geomty +typedef void * Ng_CSG_Geometry; + +/// Data type for NETGEN 2D geomty +typedef void * Ng_Geometry_2D; + +/// 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 }; + + + +class Ng_Meshing_Parameters +{ + public: + + double maxh; + double fineness; // 0 .. coarse, 1 .. fine + int secondorder; + char * meshsize_filename; + int quad_dominated; + + Ng_Meshing_Parameters(); +}; + + +enum Ng_Result { NG_OK = 0, + NG_SURFACE_INPUT_ERROR = 1, + NG_VOLUME_FAILURE = 2, + NG_STL_INPUT_ERROR = 3, + NG_SURFACE_FAILURE = 4, + NG_FILE_NOT_FOUND = 5 }; + + + + + +// #ifdef __cplusplus +// extern "C" +// { +// #endif + + // initialize, deconstruct Netgen library: + void Ng_Init (); + void Ng_Exit (); + + + // 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); + + + // 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); + + void Ng_SaveMesh(Ng_Mesh * mesh, const char* filename); + Ng_Mesh * Ng_LoadMesh(const char* filename); + + + + + + // ********************************************************** + // ** 2D Meshing ** + // ********************************************************** + + + // feeds points and boundary to mesh + + void Ng_AddPoint_2D (Ng_Mesh * mesh, double * x); + void Ng_AddBoundarySeg_2D (Ng_Mesh * mesh, int pi1, int pi2); + + // ask for number of points, elements and boundary segments + int Ng_GetNP_2D (Ng_Mesh * mesh); + int Ng_GetNE_2D (Ng_Mesh * mesh); + int Ng_GetNSeg_2D (Ng_Mesh * mesh); + + // return point coordinates + void Ng_GetPoint_2D (Ng_Mesh * mesh, int num, double * x); + + // return 2d triangles + void Ng_GetElement_2D (Ng_Mesh * mesh, int num, int * pi, int * matnum = NULL); + + // return 2d boundary segment + void Ng_GetSegment_2D (Ng_Mesh * mesh, int num, int * pi, int * matnum = NULL); + + + // load 2d netgen spline geometry + Ng_Geometry_2D * Ng_LoadGeometry_2D (const char * filename); + + // generate 2d mesh, mesh is allocated by function + Ng_Result Ng_GenerateMesh_2D (Ng_Geometry_2D * geom, + Ng_Mesh ** mesh, + Ng_Meshing_Parameters * mp); + + void Ng_HP_Refinement (Ng_Geometry_2D * geom, + Ng_Mesh * mesh, + int levels); + + + + + + // ********************************************************** + // ** STL Meshing ** + // ********************************************************** + + + // loads geometry from STL file + Ng_STL_Geometry * Ng_STL_LoadGeometry (const 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 = NULL); + + // 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: + Ng_Result Ng_STL_MakeEdges (Ng_STL_Geometry * geom, + Ng_Mesh* mesh, + Ng_Meshing_Parameters * mp); + + + // generates mesh, empty mesh must be already created. + Ng_Result Ng_STL_GenerateSurfaceMesh (Ng_STL_Geometry * geom, + Ng_Mesh * mesh, + Ng_Meshing_Parameters * mp); + +// #ifdef __cplusplus +// } +// #endif + + +#endif diff --git a/contrib/Netgen/libsrc/interface/printdest.cpp b/contrib/Netgen/libsrc/interface/printdest.cpp new file mode 100644 index 0000000000..0db654d94f --- /dev/null +++ b/contrib/Netgen/libsrc/interface/printdest.cpp @@ -0,0 +1,11 @@ +#include <mystdlib.h> +#include <myadt.hpp> + +namespace netgen +{ + //Destination for messages, errors, ... + void Ng_PrintDest(const char * s) + { + (*mycout) << s << flush; + } +} diff --git a/contrib/Netgen/libsrc/interface/readuser.cpp b/contrib/Netgen/libsrc/interface/readuser.cpp new file mode 100644 index 0000000000..f7d4d1eae8 --- /dev/null +++ b/contrib/Netgen/libsrc/interface/readuser.cpp @@ -0,0 +1,394 @@ +// +// Read user dependent output file +// + + +#include <mystdlib.h> + + +#include <myadt.hpp> +#include <linalg.hpp> +#include <csg.hpp> +#include <meshing.hpp> + +namespace netgen +{ +#include "writeuser.hpp" + +void ReadFile (Mesh & mesh, + const string & hfilename) +{ + cout << "Read User File" << endl; + + const char * filename = hfilename.c_str(); + + int i, j; + + char reco[100]; + int np, nbe; + + + + // ".surf" - mesh + + if ( (strlen (filename) > 5) && + strcmp (&filename[strlen (filename)-5], ".surf") == 0 ) + + { + cout << "Surface file" << endl; + + ifstream in (filename); + + in >> reco; + in >> np; + for (i = 1; i <= np; i++) + { + Point3d p; + in >> p.X() >> p.Y() >> p.Z(); + mesh.AddPoint (p); + } + + + in >> nbe; + // int invert = globflags.GetDefineFlag ("invertsurfacemesh"); + for (i = 1; i <= nbe; i++) + { + Element2d el; + int hi; + + el.SetIndex(1); + + for (j = 1; j <= 3; j++) + { + in >> el.PNum(j); + if (el.PNum(j) < PointIndex(1) || + el.PNum(j) > PointIndex(np)) + { + cerr << "Point Number " << el.PNum(j) << " out of range 1..." + << np << endl; + return; + } + } + + /* + if (invert) + swap (el.PNum(2), el.PNum(3)); + */ + + mesh.AddSurfaceElement (el); + } + + mesh.ClearFaceDescriptors(); + mesh.AddFaceDescriptor (FaceDescriptor(0,1,0,0)); + + cout << "points: " << np << " faces: " << nbe << endl; + } + + + + + + // Universal mesh (AVL) + if ( (strlen (filename) > 4) && + strcmp (&filename[strlen (filename)-4], ".unv") == 0 ) + { + int i, j, k; + + double h; + char reco[100]; + int np, nbe; + int invert; + + + ifstream in(filename); + + invert = 0; // globflags.GetDefineFlag ("invertsurfacemesh"); + double scale = 1; // globflags.GetNumFlag ("scale", 1); + + + while (in.good()) + { + in >> reco; + if (strcmp (reco, "NODES") == 0) + { + cout << "nodes found" << endl; + for (j = 1; j <= 4; j++) + in >> reco; // read dummy + + while (1) + { + int pi, hi; + double x, y, z; + Point3d p; + + in >> pi; + if (pi == -1) + break; + + in >> hi >> hi >> hi; + in >> p.X() >> p.Y() >> p.Z(); + + p.X() *= scale; + p.Y() *= scale; + p.Z() *= scale; + + + mesh.AddPoint (p); + } + } + + if (strcmp (reco, "ELEMENTS") == 0) + { + cout << "elements found" << endl; + for (j = 1; j <= 4; j++) + in >> reco; // read dummy + + while (1) + { + int hi; + in >> hi; + if (hi == -1) break; + for (j = 1; j <= 7; j++) + in >> hi; + + Element2d el; + el.SetIndex(1); + in >> el.PNum(1) >> el.PNum(2) >> el.PNum(3); + + if (invert) + swap (el.PNum(2), el.PNum(3)); + mesh.AddSurfaceElement (el); + + for (j = 1; j <= 5; j++) + in >> hi; + } + } + } + + mesh.ClearFaceDescriptors(); + mesh.AddFaceDescriptor (FaceDescriptor(0,1,0,0)); + + Point3d pmin, pmax; + mesh.GetBox (pmin, pmax); + cout << "bounding-box = " << pmin << "-" << pmax << endl; + } + + + + // fepp format2d: + + if ( (strlen (filename) > 7) && + strcmp (&filename[strlen (filename)-7], ".mesh2d") == 0 ) + { + cout << "Reading FEPP2D Mesh" << endl; + + char buf[100]; + int np, ne, nseg, i, j; + + ifstream in (filename); + + in >> buf; + + in >> nseg; + for (i = 1; i <= nseg; i++) + { + int bound, p1, p2; + in >> bound >> p1 >> p2; + // forget them + } + + in >> ne; + for (i = 1; i <= ne; i++) + { + int mat, nelp; + in >> mat >> nelp; + Element2d el (nelp == 3 ? TRIG : QUAD); + el.SetIndex (mat); + for (j = 1; j <= nelp; j++) + in >> el.PNum(j); + mesh.AddSurfaceElement (el); + } + + in >> np; + for (i = 1; i <= np; i++) + { + Point3d p(0,0,0); + in >> p.X() >> p.Y(); + mesh.AddPoint (p); + } + } + + + else if ( (strlen (filename) > 5) && + strcmp (&filename[strlen (filename)-5], ".mesh") == 0 ) + { + cout << "Reading Neutral Format" << endl; + + int np, ne, nse, i, j; + + ifstream in (filename); + + in >> np; + + if (in.good()) + { + // file starts with an integer + + for (i = 1; i <= np; i++) + { + Point3d p(0,0,0); + in >> p.X() >> p.Y() >> p.Z(); + mesh.AddPoint (p); + } + + in >> ne; + for (i = 1; i <= ne; i++) + { + int mat; + in >> mat; + Element el (4); + el.SetIndex (mat); + for (j = 1; j <= 4; j++) + in >> el.PNum(j); + mesh.AddVolumeElement (el); + } + + in >> nse; + for (i = 1; i <= nse; i++) + { + int mat, nelp; + in >> mat; + Element2d el (TRIG); + el.SetIndex (mat); + for (j = 1; j <= 3; j++) + in >> el.PNum(j); + mesh.AddSurfaceElement (el); + } + } + else + { + char buf[100]; + in.clear(); + do + { + in >> buf; + cout << "buf = " << buf << endl; + if (strcmp (buf, "points") == 0) + { + in >> np; + cout << "np = " << np << endl; + } + } + while (in.good()); + } + } + + + if ( (strlen (filename) > 4) && + strcmp (&filename[strlen (filename)-4], ".emt") == 0 ) + { + ifstream inemt (filename); + + string pktfile = filename; + int len = strlen (filename); + pktfile[len-3] = 'p'; + pktfile[len-2] = 'k'; + pktfile[len-1] = 't'; + cout << "pktfile = " << pktfile << endl; + + int np, nse, i; + int num, bcprop; + ifstream inpkt (pktfile.c_str()); + inpkt >> np; + ARRAY<double> values(np); + for (i = 1; i <= np; i++) + { + Point3d p(0,0,0); + inpkt >> p.X() >> p.Y() >> p.Z() + >> bcprop >> values.Elem(i); + mesh.AddPoint (p); + } + + mesh.ClearFaceDescriptors(); + mesh.AddFaceDescriptor (FaceDescriptor(0,1,0,0)); + mesh.GetFaceDescriptor(1).SetBCProperty (1); + mesh.AddFaceDescriptor (FaceDescriptor(0,1,0,0)); + mesh.GetFaceDescriptor(2).SetBCProperty (2); + mesh.AddFaceDescriptor (FaceDescriptor(0,1,0,0)); + mesh.GetFaceDescriptor(3).SetBCProperty (3); + mesh.AddFaceDescriptor (FaceDescriptor(0,1,0,0)); + mesh.GetFaceDescriptor(4).SetBCProperty (4); + mesh.AddFaceDescriptor (FaceDescriptor(0,1,0,0)); + mesh.GetFaceDescriptor(5).SetBCProperty (5); + + int p1, p2, p3; + double value; + inemt >> nse; + for (i = 1; i <= nse; i++) + { + inemt >> p1 >> p2 >> p3 >> bcprop >> value; + + if (bcprop < 1 || bcprop > 4) + cerr << "bcprop out of range, bcprop = " << bcprop << endl; + p1++; + p2++; + p3++; + if (p1 < 1 || p1 > np || p2 < 1 || p2 > np || p3 < 1 || p3 > np) + { + cout << "p1 = " << p1 << " p2 = " << p2 << " p3 = " << p3 << endl; + } + + if (i > 110354) Swap (p2, p3); + if (mesh.Point(p1).X() < 0.25) + Swap (p2,p3); + + Element2d el(TRIG); + + if (bcprop == 1) + { + if (values.Get(p1) < -69999) + el.SetIndex(1); + else + el.SetIndex(2); + } + else + el.SetIndex(3); + + + el.PNum(1) = p1; + el.PNum(2) = p2; + el.PNum(3) = p3; + mesh.AddSurfaceElement (el); + } + + + ifstream incyl ("ngusers/guenter/cylinder.surf"); + int npcyl, nsecyl; + incyl >> npcyl; + cout << "npcyl = " << npcyl << endl; + for (i = 1; i <= npcyl; i++) + { + Point3d p(0,0,0); + incyl >> p.X() >> p.Y() >> p.Z(); + mesh.AddPoint (p); + } + incyl >> nsecyl; + cout << "nsecyl = " << nsecyl << endl; + for (i = 1; i <= nsecyl; i++) + { + incyl >> p1 >> p2 >> p3; + p1 += np; + p2 += np; + p3 += np; + Element2d el(TRIG); + el.SetIndex(5); + el.PNum(1) = p1; + el.PNum(2) = p2; + el.PNum(3) = p3; + mesh.AddSurfaceElement (el); + } + } + +} + +} diff --git a/contrib/Netgen/libsrc/interface/writeabaqus.cpp b/contrib/Netgen/libsrc/interface/writeabaqus.cpp new file mode 100644 index 0000000000..e9308b1472 --- /dev/null +++ b/contrib/Netgen/libsrc/interface/writeabaqus.cpp @@ -0,0 +1,237 @@ +// +// Write Abaqus file +// +// + +#include <mystdlib.h> + +#include <myadt.hpp> +#include <linalg.hpp> +#include <csg.hpp> +#include <meshing.hpp> + +namespace netgen +{ +#include "writeuser.hpp" + + + + +void WriteAbaqusFormat (const Mesh & mesh, + const string & filename) + +{ + + cout << "\nWrite Abaqus Volume Mesh" << endl; + + ofstream outfile (filename.c_str()); + + outfile << "*Heading" << endl; + outfile << " " << filename << endl; + + outfile.precision(8); + + outfile << "*Node" << endl; + + int np = mesh.GetNP(); + int ne = mesh.GetNE(); + int i, j, k; + + for (i = 1; i <= np; i++) + { + outfile << i << ", "; + outfile << mesh.Point(i).X() << ", "; + outfile << mesh.Point(i).Y() << ", "; + outfile << mesh.Point(i).Z() << "\n"; + } + + int elemcnt = 0; //element counter + int finished = 0; + int indcnt = 1; //index counter + + while (!finished) + { + int actcnt = 0; + const Element & el1 = mesh.VolumeElement(1); + int non = el1.GetNP(); + if (non == 4) + { + outfile << "*Element, type=C3D4, ELSET=PART" << indcnt << endl; + } + else if (non == 10) + { + outfile << "*Element, type=C3D10, ELSET=PART" << indcnt << endl; + } + else + { + cout << "unsupported Element type!!!" << endl; + } + + for (i = 1; i <= ne; i++) + { + const Element & el = mesh.VolumeElement(i); + + if (el.GetIndex() == indcnt) + { + actcnt++; + if (el.GetNP() != non) + { + cout << "different element-types in a subdomain are not possible!!!" << endl; + continue; + } + + elemcnt++; + outfile << elemcnt << ", "; + if (non == 4) + { + outfile << el.PNum(1) << ", "; + outfile << el.PNum(2) << ", "; + outfile << el.PNum(4) << ", "; + outfile << el.PNum(3) << "\n"; + } + else if (non == 10) + { + outfile << el.PNum(1) << ", "; + outfile << el.PNum(2) << ", "; + outfile << el.PNum(4) << ", "; + outfile << el.PNum(3) << ", "; + outfile << el.PNum(5) << ", "; + outfile << el.PNum(9) << ", "; + outfile << el.PNum(7) << ", " << "\n"; + outfile << el.PNum(6) << ", "; + outfile << el.PNum(8) << ", "; + outfile << el.PNum(10) << "\n"; + } + else + { + cout << "unsupported Element type!!!" << endl; + for (j = 1; j <= el.GetNP(); j++) + { + outfile << el.PNum(j); + if (j != el.GetNP()) outfile << ", "; + } + outfile << "\n"; + } + } + } + indcnt++; + if (elemcnt == ne) {finished = 1; cout << "all elements found by Index!" << endl;} + if (actcnt == 0) {finished = 1;} + } + + if (mesh.GetIdentifications().GetMaxNr()) + { + // periodic identification, implementation for + // Helmut J. Boehm, TU Vienna + + char cfilename[255]; + strcpy (cfilename, filename.c_str()); + + char mpcfilename[255]; + strcpy (mpcfilename, cfilename); + int len = strlen (cfilename); + if (len >= 4 && (strcmp (mpcfilename+len-4, ".inp") == 0)) + strcpy (mpcfilename+len-4, ".mpc"); + else + strcat (mpcfilename, ".mpc"); + + ofstream mpc (mpcfilename); + + int masternode; + + ARRAY<INDEX_2> pairs; + BitArray master(np), help(np); + master.Set(); + for (i = 1; i <= 3; i++) + { + mesh.GetIdentifications().GetPairs (i, pairs); + help.Clear(); + for (j = 1; j <= pairs.Size(); j++) + { + help.Set (pairs.Get(j).I1()); + } + master.And (help); + } + for (i = 1; i <= np; i++) + if (master.Test(i)) + masternode = i; + + cout << "masternode = " << masternode << " = " + << mesh.Point(masternode) << endl; + ARRAY<int> slaves(3); + for (i = 1; i <= 3; i++) + { + mesh.GetIdentifications().GetPairs (i, pairs); + for (j = 1; j <= pairs.Size(); j++) + { + if (pairs.Get(j).I1() == masternode) + slaves.Elem(i) = pairs.Get(j).I2(); + } + cout << "slave(" << i << ") = " << slaves.Get(i) + << " = " << mesh.Point(slaves.Get(i)) << endl; + } + + + outfile << "**\n" + << "*NSET,NSET=CTENODS\n" + << slaves.Get(1) << ", " + << slaves.Get(2) << ", " + << slaves.Get(3) << endl; + + + outfile << "**\n" + << "**POINT_fixed\n" + << "**\n" + << "*BOUNDARY, OP=NEW\n"; + for (j = 1; j <= 3; j++) + outfile << masternode << ", " << j << ",, 0.\n"; + + outfile << "**\n" + << "*BOUNDARY, OP=NEW\n"; + for (j = 1; j <= 3; j++) + { + Vec3d v(mesh.Point(masternode), mesh.Point(slaves.Get(j))); + double vlen = v.Length(); + int dir = 0; + if (fabs (v.X()) > 0.9 * vlen) dir = 2; + if (fabs (v.Y()) > 0.9 * vlen) dir = 3; + if (fabs (v.Z()) > 0.9 * vlen) dir = 1; + if (!dir) + cout << "ERROR: Problem with rigid body constraints" << endl; + outfile << slaves.Get(j) << ", " << dir << ",, 0.\n"; + } + + outfile << "**\n" + << "*EQUATION, INPUT=" << mpcfilename << endl; + + + BitArray eliminated(np); + eliminated.Clear(); + for (i = 1; i <= mesh.GetIdentifications().GetMaxNr(); i++) + { + mesh.GetIdentifications().GetPairs (i, pairs); + if (!pairs.Size()) + continue; + + for (j = 1; j <= pairs.Size(); j++) + if (pairs.Get(j).I1() != masternode && + !eliminated.Test(pairs.Get(j).I2())) + { + eliminated.Set (pairs.Get(j).I2()); + for (k = 1; k <= 3; k++) + { + mpc << "4" << "\n"; + mpc << pairs.Get(j).I2() << "," << k << ", -1.0, "; + mpc << pairs.Get(j).I1() << "," << k << ", 1.0, "; + mpc << slaves.Get(i) << "," << k << ", 1.0, "; + mpc << masternode << "," << k << ", -1.0 \n"; + } + } + } + } + + + cout << "done" << endl; +} + +} diff --git a/contrib/Netgen/libsrc/interface/writediffpack.cpp b/contrib/Netgen/libsrc/interface/writediffpack.cpp new file mode 100644 index 0000000000..25f9b2986f --- /dev/null +++ b/contrib/Netgen/libsrc/interface/writediffpack.cpp @@ -0,0 +1,296 @@ +// +// Write diffpack file +// +// by +// Bartosz Sawicki <sawickib@ee.pw.edu.pl> +// extended by +// Jacques Lechelle <jacques.lechelle@wanadoo.fr> +// +#include <mystdlib.h> + +#include <myadt.hpp> +#include <linalg.hpp> +#include <csg.hpp> +#include <meshing.hpp> + + +namespace netgen +{ +#include "writeuser.hpp" + + +void WriteDiffPackFormat (const Mesh & mesh, + const CSGeometry & geom, + const string & filename) +{ + // double scale = globflags.GetNumFlag ("scale", 1); + double scale = 1; + + ofstream outfile(filename.c_str()); + + if (mesh.GetDimension() == 3) + + { + // Output compatible to Diffpack grid format + // Bartosz Sawicki <sawickib@ee.pw.edu.pl> + + int np = mesh.GetNP(); + int ne = mesh.GetNE(); + int nse = mesh.GetNSE(); + ARRAY <int> BIname; + ARRAY <int> BCsinpoint; + int i, j, k, l; + + + outfile.precision(6); + outfile.setf (ios::fixed, ios::floatfield); + outfile.setf (ios::showpoint); + + const Element & eldummy = mesh.VolumeElement((int)1); + outfile << "\n\n" + "Finite element mesh (GridFE):\n\n" + " Number of space dim. = 3\n" + " Number of elements = " << ne << "\n" + " Number of nodes = " << np << "\n\n" + " All elements are of the same type : dpTRUE\n" + " Max number of nodes in an element: "<< eldummy.GetNP() << "\n" + " Only one subdomain : dpFALSE\n" + " Lattice data ? 0\n\n\n\n"; + + for (i = 1; i <= nse; i++) + { + int BI=mesh.GetFaceDescriptor(mesh.SurfaceElement(i).GetIndex()).BCProperty(); + int nbi=BIname.Size(); + int found=0; + for (j = 1; j <= nbi; j++) + if(BI == BIname.Get(j)) found = 1; + if( ! found ) BIname.Append(BI); + } + + outfile << " " << BIname.Size() << " Boundary indicators: "; + for (i =1 ; i <= BIname.Size(); i++) + outfile << BIname.Get(i) << " "; + outfile << "\n\n\n"; + + outfile << " Nodal coordinates and nodal boundary indicators,\n" + " the columns contain:\n" + " - node number\n" + " - coordinates\n" + " - no of boundary indicators that are set (ON)\n" + " - the boundary indicators that are set (ON) if any.\n" + "#\n"; + + for (i = 1; i <= np; i++) + { + const Point3d & p = mesh.Point(i); + + outfile.width(4); + outfile << i << " ("; + outfile.width(10); + outfile << p.X()/scale << ", "; + outfile.width(9); + outfile << p.Y()/scale << ", "; + outfile.width(9); + outfile << p.Z()/scale << ") "; + + if(mesh.PointType(i) != INNERPOINT) + { + BCsinpoint.DeleteAll(); + for (j = 1; j <= nse; j++) + { + for (k = 1; k <= mesh.SurfaceElement(j).GetNP(); k++) + { + if(mesh.SurfaceElement(j).PNum(k)==i) + { + int BC=mesh.GetFaceDescriptor(mesh.SurfaceElement(j).GetIndex()).BCProperty(); + int nbcsp=BCsinpoint.Size(); + int found = 0; + for (l = 1; l <= nbcsp; l++) + if(BC == BCsinpoint.Get(l)) found = 1; + if( ! found ) BCsinpoint.Append(BC); + } + } + } + int nbcsp = BCsinpoint.Size(); + outfile << "[" << nbcsp << "] "; + for (j = 1; j <= nbcsp; j++) + outfile << BCsinpoint.Get(j) << " "; + outfile << "\n"; + } + else outfile << "[0]\n"; + + } + + outfile << "\n" + " Element types and connectivity\n" + " the columns contain:\n" + " - element number\n" + " - element type\n" + " - subdomain number\n" + " - the global node numbers of the nodes in the element.\n" + "#\n"; + + for (i = 1; i <= ne; i++) + { + const Element & el = mesh.VolumeElement(i); + outfile.width(5); + if(el.GetNP()==4) + outfile << i << " ElmT4n3D "; + else + outfile << i << " ElmT10n3D "; + outfile.width(4); + outfile << el.GetIndex() << " "; + if(el.GetNP()==10) + { + outfile.width(8); + outfile << el.PNum(1); + outfile.width(8); + outfile << el.PNum(3); + outfile.width(8); + outfile << el.PNum(2); + outfile.width(8); + outfile << el.PNum(4); + outfile.width(8); + outfile << el.PNum(6); + outfile.width(8); + outfile << el.PNum(8); + outfile.width(8); + outfile << el.PNum(5); + outfile.width(8); + outfile << el.PNum(7); + outfile.width(8); + outfile << el.PNum(10); + outfile.width(8); + outfile << el.PNum(9); + } + else + { + outfile.width(8); + outfile << el.PNum(1); + outfile.width(8); + outfile << el.PNum(3); + outfile.width(8); + outfile << el.PNum(2); + outfile.width(8); + outfile << el.PNum(4); + } + outfile << "\n"; + } + } /* Diffpack */ + + else + + { + // Output compatible to Diffpack grid format 2D + + int np = mesh.GetNP(); + int ne = mesh.GetNE(); + int nse = mesh.GetNSE(); + ARRAY <int> BIname; + ARRAY <int> BCsinpoint; + int i, j, k, l; + + + outfile.precision(6); + outfile.setf (ios::fixed, ios::floatfield); + outfile.setf (ios::showpoint); + + outfile << "\n\n" + "Finite element mesh (GridFE):\n\n" + " Number of space dim. = 2\n" + " Number of elements = " << nse << "\n" + " Number of nodes = " << np << "\n\n" + " All elements are of the same type : dpTRUE\n" + " Max number of nodes in an element: 3\n" + " Only one subdomain : dpFALSE\n" + " Lattice data ? 0\n\n\n\n"; + + for (i = 1; i <= nse; i++) + { + int BI=mesh.GetFaceDescriptor(mesh.SurfaceElement(i).GetIndex()).BCProperty(); + int nbi=BIname.Size(); + int found=0; + for (j = 1; j <= nbi; j++) + if(BI == BIname.Get(j)) found = 1; + if( ! found ) BIname.Append(BI); + } + + outfile << " " << BIname.Size() << " Boundary indicators: "; + for (i =1 ; i <= BIname.Size(); i++) + outfile << BIname.Get(i) << " "; + outfile << "\n\n\n"; + + outfile << " Nodal coordinates and nodal boundary indicators,\n" + " the columns contain:\n" + " - node number\n" + " - coordinates\n" + " - no of boundary indicators that are set (ON)\n" + " - the boundary indicators that are set (ON) if any.\n" + "#\n"; + + for (i = 1; i <= np; i++) + { + const Point3d & p = mesh.Point(i); + + outfile.width(4); + outfile << i << " ("; + outfile.width(10); + outfile << p.X()/scale << ", "; + outfile.width(9); + outfile << p.Y()/scale << ", "; + + if(mesh.PointType(i) != INNERPOINT) + { + BCsinpoint.DeleteAll(); + for (j = 1; j <= nse; j++) + { + for (k = 1; k <= 2; k++) + { + if(mesh.SurfaceElement(j).PNum(k)==i) + { + int BC=mesh.GetFaceDescriptor(mesh.SurfaceElement(j).GetIndex()).BCProperty(); + int nbcsp=BCsinpoint.Size(); + int found = 0; + for (l = 1; l <= nbcsp; l++) + if(BC == BCsinpoint.Get(l)) found = 1; + if( ! found ) BCsinpoint.Append(BC); + } + } + } + int nbcsp = BCsinpoint.Size(); + outfile << "[" << nbcsp << "] "; + for (j = 1; j <= nbcsp; j++) + outfile << BCsinpoint.Get(j) << " "; + outfile << "\n"; + } + else outfile << "[0]\n"; + + } + + outfile << "\n" + " Element types and connectivity\n" + " the columns contain:\n" + " - element number\n" + " - element type\n" + " - subdomain number\n" + " - the global node numbers of the nodes in the element.\n" + "#\n"; + + for (i = 1; i <= nse; i++) + { + const Element2d & el = mesh.SurfaceElement(i); + outfile.width(5); + outfile << i << " ElmT3n2D "; + outfile.width(4); + outfile << el.GetIndex() << " "; + outfile.width(8); + outfile << el.PNum(1); + outfile.width(8); + outfile << el.PNum(3); + outfile.width(8); + outfile << el.PNum(2); + outfile << "\n"; + } + } +} +} diff --git a/contrib/Netgen/libsrc/interface/writeelmer.cpp b/contrib/Netgen/libsrc/interface/writeelmer.cpp new file mode 100644 index 0000000000..caf02e2c68 --- /dev/null +++ b/contrib/Netgen/libsrc/interface/writeelmer.cpp @@ -0,0 +1,127 @@ + +// +// Write Elmer file +// +// + +#include <mystdlib.h> + +#include <myadt.hpp> +#include <linalg.hpp> +#include <csg.hpp> +#include <meshing.hpp> + +namespace netgen +{ +#include "writeuser.hpp" + +#include <sys/stat.h> + + +void WriteElmerFormat (const Mesh &mesh, + const string &filename) +{ + cout << "write elmer mesh files" << endl; + int np = mesh.GetNP(); + int ne = mesh.GetNE(); + int nse = mesh.GetNSE(); + int i, j, rc; + char str[200]; + + int inverttets = mparam.inverttets; + int invertsurf = mparam.inverttrigs; + +#ifdef WIN32 + cerr << "not yet implemented for Windows platforms." << endl; + return; +#else + rc = mkdir(filename.c_str(), S_IRWXU|S_IRWXG); +#endif + sprintf( str, "%s/mesh.header", filename.c_str() ); + ofstream outfile_h(str); + sprintf( str, "%s/mesh.nodes", filename.c_str() ); + ofstream outfile_n(str); + sprintf( str, "%s/mesh.elements", filename.c_str() ); + ofstream outfile_e(str); + sprintf( str, "%s/mesh.boundary", filename.c_str() ); + ofstream outfile_b(str); + + // fill hashtable + + INDEX_3_HASHTABLE<int> face2volelement(ne); + + for (i = 1; i <= ne; i++) + { + const Element & el = mesh.VolumeElement(i); + INDEX_3 i3; + int k, l; + for (j = 1; j <= 4; j++) // loop over faces of tet + { + l = 0; + for (k = 1; k <= 4; k++) + if (k != j) + { + l++; + i3.I(l) = el.PNum(k); + } + i3.Sort(); + face2volelement.Set (i3, i); + } + } + +// outfile.precision(6); +// outfile.setf (ios::fixed, ios::floatfield); +// outfile.setf (ios::showpoint); + + outfile_h << np << " " << ne << " " << nse << "\n"; + outfile_h << "1" << "\n"; + outfile_h << "504 1" << "\n"; + + for (i = 1; i <= np; i++) + { + const Point3d & p = mesh.Point(i); + + outfile_n << i << " -1 "; + outfile_n << p.X() << " "; + outfile_n << p.Y() << " "; + outfile_n << p.Z() << "\n"; + } + + for (i = 1; i <= ne; i++) + { + Element el = mesh.VolumeElement(i); + if (inverttets) el.Invert(); + sprintf( str, "5%02d", (int)el.GetNP() ); + outfile_e << i << " " << el.GetIndex() << " " << str << " "; + for (j = 1; j <= el.GetNP(); j++) + { + outfile_e << " "; + outfile_e << el.PNum(j); + } + outfile_e << "\n"; + } + + for (i = 1; i <= nse; i++) + { + Element2d el = mesh.SurfaceElement(i); + if (invertsurf) el.Invert(); + sprintf( str, "3%02d", (int)el.GetNP() ); + { + INDEX_3 i3; + for (j = 1; j <= 3; j++) i3.I(j) = el.PNum(j); + i3.Sort(); + + int elind = face2volelement.Get(i3); + outfile_b << i << " " << mesh.GetFaceDescriptor(el.GetIndex()).BCProperty() << + " " << elind << " 0 " << str << " "; + } + for (j = 1; j <= el.GetNP(); j++) + { + outfile_b << " "; + outfile_b << el.PNum(j); + } + outfile_b << "\n"; + } +} + +} diff --git a/contrib/Netgen/libsrc/interface/writefeap.cpp b/contrib/Netgen/libsrc/interface/writefeap.cpp new file mode 100644 index 0000000000..817ee7c538 --- /dev/null +++ b/contrib/Netgen/libsrc/interface/writefeap.cpp @@ -0,0 +1,220 @@ +// +// Write FEAP file +// FEAP by Bob Taylor, Berkely +// +// contact Peter Wriggers or Albrecht Rieger, Hannover +// rieger@ibnm.uni-hannover.de +// + +#include <mystdlib.h> + +#include <myadt.hpp> +#include <linalg.hpp> +#include <csg.hpp> +#include <meshing.hpp> + +namespace netgen +{ + +#include "writeuser.hpp" + + +void WriteFEAPFormat (const Mesh & mesh, + const string & filename) + +{ + // Feap format by A. Rieger + // rieger@ibnm.uni-hannover.de + + int inverttets = mparam.inverttets; + int invertsurf = mparam.inverttrigs; + + int i, j, zz, n; + + double scale = 1; // globflags.GetNumFlag ("scale", 1); + + ofstream outfile(filename.c_str()); + + outfile << "feap" << "\n"; + outfile << mesh.GetNP(); + outfile << ","; + outfile << mesh.GetNE(); + outfile << ","; + outfile << "1,3,3,4" << "\n" << "\n"; + outfile << "!numnp,numel,nummat,ndm,ndf,nen"; + outfile << "\n"; + + outfile << "\n" << "\n"; + outfile << "!node,, X Y Z" << "\n"; + outfile << "COOR" << "\n"; + outfile.precision(4); + outfile.setf (ios::fixed, ios::floatfield); + outfile.setf (ios::showpoint); + + for (i = 1; i <= mesh.GetNP(); i++) + { + outfile.width(5); + outfile << i; + outfile << ",,"; + outfile.width(10); + outfile << mesh.Point(i).X()/scale << " "; + outfile.width(10); + outfile << mesh.Point(i).Y()/scale << " "; + outfile.width(10); + outfile << mesh.Point(i).Z()/scale << "\n"; + } + + outfile << "\n" << "\n"; + outfile << "!elm,,mat, n1 n2 n3 n4" << "\n"; + outfile << "ELEM" << "\n"; + + for (i = 1; i <= mesh.GetNE(); i++) + { + Element el = mesh.VolumeElement(i); + if (inverttets) + el.Invert(); + + + outfile.width(5); + outfile << i; + outfile << ",,"; + outfile << el.GetIndex(); + outfile << ","; + + + for (j = 1; j <= el.NP(); j++) + { + outfile.width(8); + outfile << el.PNum(j); + } + outfile << "\n"; + } + + outfile << "\n" << "\n"; + + + /* + + //outfile << "SLOA" << "\n"; + //outfile << "2,3,3" << "\n"; + //outfile << GetNSE() << "\n"; + outfile << "selm" << "\n" << GetNSE() << "\n"; + for (i = 1; i <= GetNSE(); i++) + { + if (SurfaceElement(i).GetIndex()) + { + outfile.width(8); + outfile << facedecoding.Get(SurfaceElement(i).GetIndex ()).surfnr; + //outfile.width(8); + //outfile << facedecoding.Get(SurfaceElement(i).GetIndex ()).domin; + //outfile.width(8); + //outfile << facedecoding.Get(SurfaceElement(i).GetIndex ()).domout; + } + else + outfile << " 0 0 0"; + + + Element2d sel = SurfaceElement(i); + if (invertsurf) + sel.Invert(); + //outfile.width(8); + //outfile << sel.GetNP(); + //if (facedecoding.Get(SurfaceElement(i).GetIndex ()).surfnr == 4) + //{ + for (j = 1; j <= sel.GetNP(); j++) + { + outfile.width(8); + outfile << sel.PNum(j); + } + //outfile.width(8); + //outfile << "0.0"; + //outfile.width(8); + //outfile << "0.0"; + //outfile.width(8); + //outfile << "1.0" << "\n"; + //} + outfile << "\n"; + //outfile << endl; + } + */ + + + + // BEGIN CONTACT OUTPUT + /* + int masterindex, slaveindex; + cout << "Master Surface index = "; + cin >> masterindex; + cout << "Slave Surface index = "; + cin >> slaveindex; + + + // CONTACT SURFACE 1 + outfile << "\n"; + outfile << "\n"; + outfile << "surface,1" << "\n";; + outfile.width(6); + outfile << "tria" << "\n";; + outfile.width(13); + outfile << "facet" << "\n";; + zz = 0; + for (i = 1; i <= mesh.GetNSE(); i++) + { + Element2d sel = mesh.SurfaceElement(i); + if (invertsurf) + sel.Invert(); + if (mesh.GetFaceDescriptor(sel.GetIndex ()).BCProperty() == masterindex) + { + zz++; + outfile.width(14); + outfile << zz; + outfile << ",,"; + for (j = 1; j <= sel.GetNP(); j++) + { + outfile << sel.PNum(j); + outfile << ","; + } + outfile << "\n"; + } + } + + + // CONTACT SURFACE 2 + outfile << "\n"; + outfile << "\n"; + outfile << "surface,2" << "\n";; + outfile.width(6); + outfile << "tria" << "\n";; + outfile.width(13); + outfile << "facet" << "\n";; + zz = 0; + for (i = 1; i <= mesh.GetNSE(); i++) + { + + Element2d sel = mesh.SurfaceElement(i); + if (invertsurf) + sel.Invert(); + if (mesh.GetFaceDescriptor(sel.GetIndex ()).BCProperty() == slaveindex) + { + zz++; + outfile.width(14); + outfile << zz; + outfile << ",,"; + for (j = 1; j <= sel.GetNP(); j++) + { + outfile << sel.PNum(j); + outfile << ","; + } + outfile << "\n"; + } + } + + outfile << "\n"; + outfile << "\n"; + */ + + // END CONTACT OUTPUT + + cout << "done" << endl; +} +} diff --git a/contrib/Netgen/libsrc/interface/writefluent.cpp b/contrib/Netgen/libsrc/interface/writefluent.cpp new file mode 100644 index 0000000000..5c08d59857 --- /dev/null +++ b/contrib/Netgen/libsrc/interface/writefluent.cpp @@ -0,0 +1,193 @@ +// +// Write Fluent file +// Johannes Gerstmayr, University Linz +// + +#include <mystdlib.h> + +#include <myadt.hpp> +#include <linalg.hpp> +#include <csg.hpp> +#include <meshing.hpp> + +namespace netgen +{ + +#include "writeuser.hpp" + + + +void WriteFluentFormat (const Mesh & mesh, + const string & filename) + +{ + cout << "start writing fluent export" << endl; + + int np = mesh.GetNP(); + int ne = mesh.GetNE(); + int nse = mesh.GetNSE(); + int i, j; + + ofstream outfile (filename.c_str()); + char str[100]; + + outfile.precision(6); + //outfile.setf (ios::fixed, ios::floatfield); + //outfile.setf (ios::showpoint); + + outfile << "(0 \"Exported file from NETGEN \")" << endl; + outfile << "(0 \"Dimension:\")" << endl; + outfile << "(2 3)" << endl << endl; + + outfile << "(0 \"Nodes:\")" << endl; + + //number of nodes: + sprintf(str,"(10 (0 1 %x 1))",np); //hexadecimal!!! + outfile << str << endl; + + //nodes of zone 1: + sprintf(str,"(10 (7 1 %x 1)(",np); //hexadecimal!!! + outfile << str << endl; + for (i = 1; i <= np; i++) + { + const Point3d & p = mesh.Point(i); + + //outfile.width(10); + outfile << p.X() << " "; + outfile << p.Y() << " "; + outfile << p.Z() << "\n"; + } + outfile << "))" << endl << endl; + + //write faces with elements + + outfile << "(0 \"Faces:\")" << endl; + + Element2d face, face2; + int i2, j2; + ARRAY<INDEX_3> surfaceelp; + ARRAY<int> surfaceeli; + ARRAY<int> locels; + + //no cells=no tets + //no faces=2*tets + + int noverbface = 2*ne-nse/2; + + sprintf(str,"(13 (0 1 %x 0))",(noverbface+nse)); //hexadecimal!!! + outfile << str << endl; + + sprintf(str,"(13 (4 1 %x 2 3)(",noverbface); //hexadecimal!!! + outfile << str << endl; + + const_cast<Mesh&> (mesh).BuildElementSearchTree(); + + for (i = 1; i <= ne; i++) + { + if (ne > 2000) + { + if (i%2000 == 0) + { + cout << (double)i/(double)ne*100. << "%" << endl; + } + } + + Element el = mesh.VolumeElement(i); + //if (inverttets) + // el.Invert(); + + //outfile << el.GetIndex() << " "; + if (el.GetNP() != 4) {cout << "only tet-meshes supported in write fluent!" << endl;} + + //faces: + + Box3d box; + el.GetBox(mesh.Points(), box); + box.IncreaseRel(1e-6); + + mesh.GetIntersectingVolEls(box.PMin(),box.PMax(),locels); + int nel = locels.Size(); + int locind; + + //cout << "nel=" << nel << endl; + + for (j = 1; j <= el.GetNFaces(); j++) + { + el.GetFace(j, face); + face.Invert(); + int eli2 = 0; + int stopsig = 0; + + for (i2 = 1; i2 <= nel; i2++) + { + locind = locels.Get(i2); + //cout << " locind=" << locind << endl; + + Element el2 = mesh.VolumeElement(locind); + //if (inverttets) + // el2.Invert(); + + for (j2 = 1; j2 <= el2.GetNFaces(); j2++) + { + el2.GetFace(j2, face2); + + if (face2.HasFace(face)) {eli2 = locind; stopsig = 1; break;} + } + if (stopsig) break; + } + + if (eli2==i) cout << "error in WRITE_FLUENT!!!" << endl; + + if (eli2 > i) //dont write faces two times! + { + //i: left cell, eli: right cell + outfile << hex << face.PNum(2) << " " + << hex << face.PNum(1) << " " + << hex << face.PNum(3) << " " + << hex << i << " " + << hex << eli2 << "\n"; + } + if (eli2 == 0) + { + surfaceelp.Append(INDEX_3(face.PNum(2),face.PNum(1),face.PNum(3))); + surfaceeli.Append(i); + } + } + } + outfile << "))" << endl; + + sprintf(str,"(13 (2 %x %x 3 3)(",(noverbface+1),noverbface+nse); //hexadecimal!!! + outfile << str << endl; + + for (i = 1; i <= surfaceelp.Size(); i++) + { + outfile << hex << surfaceelp.Get(i).I1() << " " + << hex << surfaceelp.Get(i).I2() << " " + << hex << surfaceelp.Get(i).I3() << " " + << hex << surfaceeli.Get(i) << " " << 0 << "\n"; + } + + outfile << "))" << endl << endl; + + outfile << "(0 \"Cells:\")" << endl; + + sprintf(str,"(12 (0 1 %x 0))",ne); //hexadecimal!!! + outfile << str << endl; + + sprintf(str,"(12 (1 1 %x 1 2))",ne); //hexadecimal!!! + outfile << str << endl << endl; + + + + + outfile << "(0 \"Zones:\")\n" + << "(45 (1 fluid fluid)())\n" + // << "(45 (2 velocity-inlet velocity_inlet.1)())\n" + // << "(45 (3 pressure-outlet pressure_outlet.2)())\n" + << "(45 (2 wall wall)())\n" + << "(45 (4 interior default-interior)())\n" << endl; + + cout << "done" << endl; +} + +} diff --git a/contrib/Netgen/libsrc/interface/writegmsh.cpp b/contrib/Netgen/libsrc/interface/writegmsh.cpp new file mode 100644 index 0000000000..93def67783 --- /dev/null +++ b/contrib/Netgen/libsrc/interface/writegmsh.cpp @@ -0,0 +1,200 @@ +/************************************* + * Write Gmsh file + * First issue the 04/26/2004 by Paul CARRICO (paul.carrico@free.fr) + * At the moment, the GMSH format is available for + * linear tetrahedron elements i.e. in 3D + * (based on Neutral Format) + * + * Second issue the 05/05/2004 by Paul CARRICO + * Thanks to Joachim Schoeberl for the correction of a minor bug + * the 2 initial Gmsh Format (i.e. volume format and surface format) are group together) + * in only one file + **************************************/ + +#include <mystdlib.h> + +#include <myadt.hpp> +#include <linalg.hpp> +#include <csg.hpp> +#include <meshing.hpp> + +namespace netgen +{ +#include "writeuser.hpp" + + + +/* + * GMSH mesh format + * points, elements, surface elements and physical entities + */ + +void WriteGmshFormat (const Mesh & mesh, + const CSGeometry & geom, + const string & filename) +{ + ofstream outfile (filename.c_str()); + outfile.precision(6); + outfile.setf (ios::fixed, ios::floatfield); + outfile.setf (ios::showpoint); + + int np = mesh.GetNP(); /// number of point + int ne = mesh.GetNE(); /// number of element + int nse = mesh.GetNSE(); /// number of surface element (BC) + int i, j, k, l; + + + /* + * 3D section : Linear volume elements (only tetrahedra) + */ + + if (ne > 0 && mesh.VolumeElement(1).GetNP() == 4) + { + cout << "Write GMSH Format \n"; + cout << "The GMSH format is available for linear tetrahedron elements only in 3D\n" << endl; + + int inverttets = mparam.inverttets; + int invertsurf = mparam.inverttrigs; + + + /// Write nodes + outfile << "$NOD\n"; + outfile << np << "\n"; + + for (i = 1; i <= np; i++) + { + const Point3d & p = mesh.Point(i); + outfile << i << " "; /// node number + outfile << p.X() << " "; + outfile << p.Y() << " "; + outfile << p.Z() << "\n"; + } + outfile << "$ENDNOD\n"; + + /// write elements + outfile << "$ELM\n"; + outfile << ne + nse << "\n"; //// number of elements + number of surfaces BC + + for (i = 1; i <= nse; i++) + { + Element2d el = mesh.SurfaceElement(i); + if (invertsurf) el.Invert(); + outfile << i; + outfile << " "; + outfile << "2"; + outfile << " "; + outfile << mesh.GetFaceDescriptor (el.GetIndex()).BCProperty() << " "; + /// that means that physical entity = elementary entity (arbitrary approach) + outfile << mesh.GetFaceDescriptor (el.GetIndex()).BCProperty() << " "; + outfile << "3"; + outfile << " "; + for (j = 1; j <= el.GetNP(); j++) + { + outfile << " "; + outfile << el.PNum(j); + } + outfile << "\n"; + } + + + for (i = 1; i <= ne; i++) + { + Element el = mesh.VolumeElement(i); + if (inverttets) el.Invert(); + outfile << nse + i; /// element number + outfile << " "; + outfile << "4"; /// element type i.e. Tetraedron == 4 + outfile << " "; + outfile << 100000 + el.GetIndex(); + /// that means that physical entity = elementary entity (arbitrary approach) + outfile << " "; + outfile << 100000 + el.GetIndex(); /// volume number + outfile << " "; + outfile << "4"; /// number of nodes i.e. 4 for a tetrahedron + + for (j = 1; j <= el.GetNP(); j++) + { + outfile << " "; + outfile << el.PNum(j); + } + outfile << "\n"; + } + + + outfile << "$ENDELM\n"; + } + + /* + * End of 3D section + */ + + + + + + /* + * 2D section : available for triangles and quadrangles + */ + else if (ne == 0) /// means that there's no 3D element + { + cout << "\n Write Gmsh Surface Mesh (triangle and/or quadrangles)" << endl; + + /// Write nodes + outfile << "$NOD\n"; + outfile << np << "\n"; + + for (i = 1; i <= np; i++) + { + const Point3d & p = mesh.Point(i); + outfile << i << " "; /// node number + outfile << p.X() << " "; + outfile << p.Y() << " "; + outfile << p.Z() << "\n"; + } + outfile << "$ENDNOD\n"; + + + /// write triangles & quadrangles + outfile << "$ELM\n"; + outfile << nse << "\n"; + + for (k = 1; k <= nse; k++) + { + const Element2d & el = mesh.SurfaceElement(k); + + + outfile << k; + outfile << " "; + outfile << (el.GetNP()-1); // 2 for a triangle and 3 for a quadrangle + outfile << " "; + outfile << mesh.GetFaceDescriptor (el.GetIndex()).BCProperty() << " "; + /// that means that physical entity = elementary entity (arbitrary approach) + outfile << mesh.GetFaceDescriptor (el.GetIndex()).BCProperty() << " "; + outfile << (el.GetNP()); // number of node per surfacic element + outfile << " "; + + for (l = 1; l <= el.GetNP(); l++) + { + outfile << " "; + outfile << el.PNum(l); + } + outfile << "\n"; + + } + outfile << "$ENDELM$ \n"; + } + + /* + * End of 2D section + */ + + else + { + cout << " Invalide element type for Gmsh volume Format !\n"; + } + + +} +} + + diff --git a/contrib/Netgen/libsrc/interface/writepermas.cpp b/contrib/Netgen/libsrc/interface/writepermas.cpp new file mode 100644 index 0000000000..9dc7662458 --- /dev/null +++ b/contrib/Netgen/libsrc/interface/writepermas.cpp @@ -0,0 +1,208 @@ +// +// Write Permas file +// for Intes GmbH, Stuttgart +// + +#include <mystdlib.h> + +#include <myadt.hpp> +#include <linalg.hpp> +#include <csg.hpp> +#include <meshing.hpp> + +#include <string> + +using namespace std; + +namespace netgen +{ +#include "writeuser.hpp" + // Forward declarations (don't know, where to define them, sorry) + int addComponent(string &strComp, string &strSitu, ofstream &out); + + + // This should be the new function to export a PERMAS file + void WritePermasFormat (const Mesh &mesh, const string &filename, + string &strComp, string &strSitu) + { + ofstream outfile (filename.c_str()); + addComponent(strComp, strSitu, outfile); + WritePermasFormat ( mesh, filename); + } + + void WritePermasFormat (const Mesh &mesh, const string &filename) + { + string strComp, strSitu; + ofstream outfile (filename.c_str()); + + outfile.precision(8); + + strSitu = strComp = ""; + if (addComponent(strComp, strSitu, outfile) == 1) { + printf("Error while exporting PERMAS dat!\n"); + return; + } + + int np = mesh.GetNP(); + int ne = mesh.GetNE(); + int nse = mesh.GetNSE(); + int i, j, k; + + if (ne == 0) + { + // pure surface mesh + cout << "\nWrite Permas Surface Mesh" << endl; + + int elnr = 0; + for (j = 1; j <= 2; j++) + { + int nelp; + switch (j) + { + case 1: + nelp = 3; + outfile << "$ELEMENT TYPE = TRIA3 ESET = ALLQUAD" << endl; + break; + case 2: + nelp = 4; + outfile << "$ELEMENT TYPE = QUAD4 ESET = ALLQUAD" << endl; + break; + } + + for (i = 1; i <= nse; i++) + { + const Element2d & el = mesh.SurfaceElement(i); + if (el.GetNP() != nelp) + continue; + + elnr++; + outfile << elnr << " "; + for (k = 1; k <= nelp; k++) + outfile << " " << el.PNum(k); + outfile << endl; + + } + } + } + else + { + cout << "\nWrite Permas Volume Mesh" << endl; + + int secondorder = (mesh.VolumeElement(1).GetNP() == 10); + + if (!secondorder) + { + outfile << "$ELEMENT TYPE = TET4 ESET = ALLTET" << endl; + for (i = 1; i <= ne; i++) + { + const Element & el = mesh.VolumeElement(i); + outfile << i + << " " << el.PNum(1) + << " " << el.PNum(2) + << " " << el.PNum(3) + << " " << el.PNum(4) << endl; + } + } + else + { + outfile << "$ELEMENT TYPE = TET10 ESET = ALLTET" << endl; + for (i = 1; i <= ne; i++) + { + const Element & el = mesh.VolumeElement(i); + outfile << i + << " " << el.PNum(1) + << " " << el.PNum(5) + << " " << el.PNum(2) + << " " << el.PNum(8) + << " " << el.PNum(3) + << " " << el.PNum(6) << endl << "& " + << " " << el.PNum(7) + << " " << el.PNum(9) + << " " << el.PNum(10) + << " " << el.PNum(4) << endl; + } + } + + outfile << endl << endl; + + + outfile << "$SURFACE GEO SURFID = 1 SFSET = ALLSUR" << endl; + for (i = 1; i <= nse; i++) + { + const Element2d & el = mesh.SurfaceElement(i); + if (el.GetNP() == 3) + outfile << "STRIA3" + << " " << el.PNum(1) + << " " << el.PNum(2) + << " " << el.PNum(3) << endl; + } + + for (i = 1; i <= nse; i++) + { + const Element2d & el = mesh.SurfaceElement(i); + if (el.GetNP() == 4) + outfile << "SQUAD4" + << " " << el.PNum(1) + << " " << el.PNum(2) + << " " << el.PNum(3) + << " " << el.PNum(4) << endl; + } + + for (i = 1; i <= nse; i++) + { + const Element2d & el = mesh.SurfaceElement(i); + if (el.GetNP() == 6) + outfile << "STRIA6" + << " " << el.PNum(1) + << " " << el.PNum(4) + << " " << el.PNum(2) + << " " << el.PNum(5) + << " " << el.PNum(3) + << " " << el.PNum(6) << endl; + } + } + + + outfile << endl << endl; + + outfile << "$COOR NSET = ALLNODES" << endl; + + outfile.precision(6); + outfile.setf (ios::fixed, ios::floatfield); + outfile.setf (ios::showpoint); + + for (i = 1; i <= np; i++) + { + outfile << i << " "; + outfile << mesh.Point(i).X() << " "; + outfile << mesh.Point(i).Y() << " "; + outfile << mesh.Point(i).Z() << "\n"; + } + } + ////////////////////////////////////////////////////////////////////////////////// + // \brief Writes PERMAS configuration header into export file + // Returns >0 in case of errors + // \par string &strComp : Reference to component description + // \par string &strComp : Reference to situation description + ////////////////////////////////////////////////////////////////////////////////// + int addComponent(string &strComp, string &strSitu, ofstream &out) + { + if (strComp.size() > 12 || strSitu > 12) + return 1; + + if (0 == strComp.size()) + strComp = "KOMPO1"; + + if (0 == strSitu.size()) + strSitu = "SIT1"; + + // Writing description header of configuration + out << "$ENTER COMPONENT NAME = " << strComp << " DOFTYPE = DISP MATH" << endl << endl; + out << " $SITUATION NAME = " << strSitu << endl; + out << " $END SITUATION" << endl << endl; + out << " $STRUCTURE" << endl; + + return 0; + } + +} diff --git a/contrib/Netgen/libsrc/interface/writepermas2.cpp b/contrib/Netgen/libsrc/interface/writepermas2.cpp new file mode 100644 index 0000000000..f78714c5a4 --- /dev/null +++ b/contrib/Netgen/libsrc/interface/writepermas2.cpp @@ -0,0 +1,173 @@ +// +// Write Permas file +// for Intes GmbH, Stuttgart +// + +#include <mystdlib.h> + +#include <myadt.hpp> +#include <linalg.hpp> +#include <csg.hpp> +#include <meshing.hpp> + +namespace netgen +{ +#include "writeuser.hpp" + + + +void WritePermasFormat (const Mesh & mesh, + const string & filename) + +{ + + ofstream outfile (filename.c_str()); + + outfile.precision(8); + + int np = mesh.GetNP(); + int ne = mesh.GetNE(); + int nse = mesh.GetNSE(); + int i, j, k; + + + if (ne == 0) + { + // pure surface mesh + + cout << "\nWrite Permas Surface Mesh" << endl; + + int elnr = 0; + for (j = 1; j <= 2; j++) + { + int nelp; + switch (j) + { + case 1: + nelp = 3; + outfile << "$ELEMENT TYPE = TRIA3 ESET = ALLQUAD" << endl; + break; + case 2: + nelp = 4; + outfile << "$ELEMENT TYPE = QUAD4 ESET = ALLQUAD" << endl; + break; + } + + for (i = 1; i <= nse; i++) + { + const Element2d & el = mesh.SurfaceElement(i); + if (el.GetNP() != nelp) + continue; + + elnr++; + outfile << elnr << " "; + for (k = 1; k <= nelp; k++) + outfile << " " << el.PNum(k); + outfile << endl; + + } + } + } + + else + + { + cout << "\nWrite Permas Volume Mesh" << endl; + + + int secondorder = (mesh.VolumeElement(1).GetNP() == 10); + + if (!secondorder) + { + outfile << "$ELEMENT TYPE = TET4 ESET = ALLTET" << endl; + for (i = 1; i <= ne; i++) + { + const Element & el = mesh.VolumeElement(i); + outfile << i + << " " << el.PNum(1) + << " " << el.PNum(2) + << " " << el.PNum(3) + << " " << el.PNum(4) << endl; + } + } + else + { + outfile << "$ELEMENT TYPE = TET10 ESET = ALLTET" << endl; + for (i = 1; i <= ne; i++) + { + const Element & el = mesh.VolumeElement(i); + outfile << i + << " " << el.PNum(1) + << " " << el.PNum(5) + << " " << el.PNum(2) + << " " << el.PNum(8) + << " " << el.PNum(3) + << " " << el.PNum(6) << endl << "& " + << " " << el.PNum(7) + << " " << el.PNum(9) + << " " << el.PNum(10) + << " " << el.PNum(4) << endl; + } + } + + outfile << endl << endl; + + + outfile << "$SURFACE GEO SURFID = 1 SFSET = ALLSUR" << endl; + for (i = 1; i <= nse; i++) + { + const Element2d & el = mesh.SurfaceElement(i); + if (el.GetNP() == 3) + outfile << "STRIA3" + << " " << el.PNum(1) + << " " << el.PNum(2) + << " " << el.PNum(3) << endl; + } + + for (i = 1; i <= nse; i++) + { + const Element2d & el = mesh.SurfaceElement(i); + if (el.GetNP() == 4) + outfile << "SQUAD4" + << " " << el.PNum(1) + << " " << el.PNum(2) + << " " << el.PNum(3) + << " " << el.PNum(4) << endl; + } + + for (i = 1; i <= nse; i++) + { + const Element2d & el = mesh.SurfaceElement(i); + if (el.GetNP() == 6) + outfile << "STRIA6" + << " " << el.PNum(1) + << " " << el.PNum(4) + << " " << el.PNum(2) + << " " << el.PNum(5) + << " " << el.PNum(3) + << " " << el.PNum(6) << endl; + } + } + + + outfile << endl << endl; + + + + outfile << "$COOR NSET = ALLNODES" << endl; + + 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).X() << " "; + outfile << mesh.Point(i).Y() << " "; + outfile << mesh.Point(i).Z() << "\n"; + } +} + + +} diff --git a/contrib/Netgen/libsrc/interface/writetecplot.cpp b/contrib/Netgen/libsrc/interface/writetecplot.cpp new file mode 100644 index 0000000000..a3ddda3f9a --- /dev/null +++ b/contrib/Netgen/libsrc/interface/writetecplot.cpp @@ -0,0 +1,127 @@ +// +// +// TECPLOT file by Jawor Georgiew +// +#include <mystdlib.h> + +#include <myadt.hpp> +#include <linalg.hpp> +#include <csg.hpp> +#include <meshing.hpp> + + + +namespace netgen +{ +#include "writeuser.hpp" + +void WriteTecPlotFormat (const Mesh & mesh, + const CSGeometry & geom, + const string & filename) +{ + INDEX i; + int j, k, e, z; + Vec<3> n; + + INDEX np = mesh.GetNP(); + INDEX ne = mesh.GetNE(); + INDEX nse = mesh.GetNSE(); + + ARRAY<int> sn(np); + ofstream outfile(filename.c_str()); + + outfile << "TITLE=\" " << filename << "\"" << endl; + + // fill hashtable + + INDEX_3_HASHTABLE<int> face2volelement(ne); + + for (i = 1; i <= ne; i++) + { + const Element & el = mesh.VolumeElement(i); + INDEX_3 i3; + int k, l; + for (j = 1; j <= 4; j++) // loop over faces of tet + { + l = 0; + for (k = 1; k <= 4; k++) + if (k != j) + { + l++; + i3.I(l) = el.PNum(k); + } + i3.Sort(); + face2volelement.Set (i3, i); + } + } + + + for (j = 1; j <= geom.GetNSurf(); j++) /* Flaeche Nummer j */ + { + for (i = 1; i <= np; i++) + sn.Elem(i) = 0; + + e = 0; + + for (i = 1; i <= nse; i++) + { + const Element2d & el = mesh.SurfaceElement(i); + if (j == mesh.GetFaceDescriptor (el.GetIndex ()).SurfNr()) + { + for (k = 1; k <= 3; k++) + sn.Elem(el.PNum(k)) = 1; + e++; /* e= Anzahl der neuen Elemente */ + } + } + + z = 0; + for (i = 1; i <= np; i++) + if (sn.Elem(i) == 1) + sn.Elem(i) = ++z; + + outfile << "ZONE T=\" Surface " << j << " \", N=" << z + << ", E=" << e << ", ET=TRIANGLE, F=FEPOINT" << endl; + + for (i = 1; i <= np; i++) + if (sn.Elem(i) != 0) + { + n = geom.GetSurface(j) -> GetNormalVector ( mesh.Point(i) ); + + outfile << mesh.Point(i).X() << " " /* Knoten Koordinaten */ + << mesh.Point(i).Y() << " " + << mesh.Point(i).Z() << " " + << n(0) << " " + << n(1) << " " + << n(2) << " " + << i << endl; + } + + + for (i = 1; i <= nse; i++) + { + const Element2d & el = mesh.SurfaceElement(i); + if (j == mesh.GetFaceDescriptor(el.GetIndex ()).SurfNr()) + /* FlaechenKnoten (3) */ + outfile << sn.Get(el.PNum(1)) << " " + << sn.Get(el.PNum(2)) << " " + << sn.Get(el.PNum(3)) << endl; + + /// Hier soll noch die Ausgabe der Nummer des angrenzenden + /// Vol.elements erfolgen ! + + for (i = 1; i <= nse; i++) + { + const Element2d & el = mesh.SurfaceElement(i); + INDEX_3 i3; + for (j = 1; j <= 3; j++) + i3.I(j) = el.PNum(j); + i3.Sort(); + + int elind = face2volelement.Get(i3); + } + } + } +} + + +} diff --git a/contrib/Netgen/libsrc/interface/writetochnog.cpp b/contrib/Netgen/libsrc/interface/writetochnog.cpp new file mode 100644 index 0000000000..50546dc2d1 --- /dev/null +++ b/contrib/Netgen/libsrc/interface/writetochnog.cpp @@ -0,0 +1,108 @@ +// +// Write Tochnog file +// +// by +// +// Andreas Seltmann +// email: A.Seltmann@lsw.uni-heidelberg.de +// +#include <mystdlib.h> + +#include <myadt.hpp> +#include <linalg.hpp> +#include <csg.hpp> +#include <meshing.hpp> + + +namespace netgen +{ +#include "writeuser.hpp" + + +void WriteTochnogFormat (const Mesh & mesh, + const string & filename) +{ + cout << "\nWrite Tochnog Volume Mesh" << endl; + + ofstream outfile (filename.c_str()); + + outfile << "(Nodes and Elements generated with NETGEN" << endl; + outfile << " " << filename << ")" << endl; + + outfile.precision(8); + + outfile << "(Nodes)" << endl; + + int np = mesh.GetNP(); + int ne = mesh.GetNE(); + int i, j, k; + + for (i = 1; i <= np; i++) + { + outfile << "node " << " " << i << " "; + outfile << mesh.Point(i).X() << " "; + outfile << mesh.Point(i).Y() << " "; + outfile << mesh.Point(i).Z() << "\n"; + } + + int elemcnt = 0; //element counter + int finished = 0; + int indcnt = 1; //index counter + + while (!finished) + { + int actcnt = 0; + const Element & el1 = mesh.VolumeElement(1); + int non = el1.GetNP(); + if (non == 4) + { + outfile << "(Elements, type=-tet4)" << endl; + } + else + { + cout << "unsupported Element type!!!" << endl; + } + + for (i = 1; i <= ne; i++) + { + const Element & el = mesh.VolumeElement(i); + + if (el.GetIndex() == indcnt) + { + actcnt++; + if (el.GetNP() != non) + { + cout << "different element-types in a subdomain are not possible!!!" << endl; + continue; + } + + elemcnt++; + outfile << "element " << elemcnt << " -tet4 "; + if (non == 4) + { + outfile << el.PNum(1) << " "; + outfile << el.PNum(2) << " "; + outfile << el.PNum(4) << " "; + outfile << el.PNum(3) << "\n"; + } + else + { + cout << "unsupported Element type!!!" << endl; + for (j = 1; j <= el.GetNP(); j++) + { + outfile << el.PNum(j); + if (j != el.GetNP()) outfile << ", "; + } + outfile << "\n"; + } + } + } + indcnt++; + if (elemcnt == ne) {finished = 1; cout << "all elements found by Index!" << endl;} + if (actcnt == 0) {finished = 1;} + } + + cout << "done" << endl; +} + +} diff --git a/contrib/Netgen/libsrc/interface/writeuser.cpp b/contrib/Netgen/libsrc/interface/writeuser.cpp new file mode 100644 index 0000000000..83b9a050ce --- /dev/null +++ b/contrib/Netgen/libsrc/interface/writeuser.cpp @@ -0,0 +1,899 @@ +// +// Write user dependent output file +// + +#include <mystdlib.h> + +#include <myadt.hpp> +#include <linalg.hpp> +#include <csg.hpp> +#include <geometry2d.hpp> +#include <meshing.hpp> + +namespace netgen +{ +#include "writeuser.hpp" + + +void RegisterUserFormats (ARRAY<const char*> & names) +{ + char *types[] = + { + "Neutral Format", + "Surface Mesh Format" , + "DIFFPACK Format", + "TecPlot Format", + "Tochnog Format", + "Abaqus Format", + "Fluent Format", + "Permas Format", + "FEAP Format", + "Elmer Format", + "STL Format", + "VRML Format", + "Gmsh Format", + // { "Chemnitz Format" }, + 0 + }; + + for (int i = 0; types[i]; i++) + names.Append (types[i]); +} + + + +bool WriteUserFormat (const string & format, + const Mesh & mesh, + const CSGeometry & geom, + const string & filename) +{ + PrintMessage (1, "Export mesh to file ", filename, + ", format is ", format); + + if (format == "Neutral Format") + WriteNeutralFormat (mesh, geom, filename); + + else if (format == "Surface Mesh Format") + WriteSurfaceFormat (mesh, filename); + + else if (format == "DIFFPACK Format") + WriteDiffPackFormat (mesh, geom, filename); + + else if (format == "Tochnog Format") + WriteTochnogFormat (mesh, filename); + + else if (format == "TecPlot Format") + cerr << "ERROR: TecPlot format currently out of order" << endl; + // WriteTecPlotFormat (mesh, geom, filename); + + else if (format == "Abaqus Format") + WriteAbaqusFormat (mesh, filename); + + else if (format == "Fluent Format") + WriteFluentFormat (mesh, filename); + + else if (format == "Permas Format") + WritePermasFormat (mesh, filename); + + else if (format == "FEAP Format") + WriteFEAPFormat (mesh, filename); + + else if (format == "Elmer Format") + WriteElmerFormat (mesh, filename); + + else if (format == "STL Format") + WriteSTLFormat (mesh, filename); + + else if (format == "VRML Format") + WriteVRMLFormat (mesh, 1, filename); + + else if (format == "Fepp Format") + WriteFEPPFormat (mesh, geom, filename); + + else if (format == "EdgeElement Format") + WriteEdgeElementFormat (mesh, geom, filename); + + else if (format == "Chemnitz Format") + WriteUserChemnitz (mesh, filename); + + else if (format == "Gmsh Format") + WriteGmshFormat (mesh, geom, filename); + + else + { + return 1; + } + + return 0; +} + + + + +/* + * Neutral mesh format + * points, elements, surface elements + */ + +void WriteNeutralFormat (const Mesh & mesh, + const CSGeometry & geom, + const string & filename) +{ + cout << "write neutral, new" << endl; + int np = mesh.GetNP(); + int ne = mesh.GetNE(); + int nse = mesh.GetNSE(); + int nseg = mesh.GetNSeg(); + int i, j; + + int inverttets = mparam.inverttets; + int invertsurf = mparam.inverttrigs; + + ofstream outfile (filename.c_str()); + + outfile.precision(6); + outfile.setf (ios::fixed, ios::floatfield); + outfile.setf (ios::showpoint); + + outfile << np << "\n"; + + for (i = 1; i <= np; i++) + { + const Point3d & p = mesh.Point(i); + + outfile.width(10); + outfile << p.X() << " "; + outfile.width(9); + outfile << p.Y() << " "; + if (mesh.GetDimension() == 3) + { + outfile.width(9); + outfile << p.Z(); + } + outfile << "\n"; + } + + if (mesh.GetDimension() == 3) + { + outfile << ne << "\n"; + for (i = 1; i <= ne; i++) + { + Element el = mesh.VolumeElement(i); + if (inverttets) + el.Invert(); + outfile.width(4); + outfile << el.GetIndex() << " "; + for (j = 1; j <= el.GetNP(); j++) + { + outfile << " "; + outfile.width(8); + outfile << el.PNum(j); + } + outfile << "\n"; + } + } + + outfile << nse << "\n"; + for (i = 1; i <= nse; i++) + { + Element2d el = mesh.SurfaceElement(i); + if (invertsurf) + el.Invert(); + outfile.width(4); + outfile << mesh.GetFaceDescriptor (el.GetIndex()).BCProperty() << " "; + for (j = 1; j <= el.GetNP(); j++) + { + outfile << " "; + outfile.width(8); + outfile << el.PNum(j); + } + outfile << "\n"; + } + + + if (mesh.GetDimension() == 2) + { + outfile << nseg << "\n"; + for (i = 1; i <= nseg; i++) + { + const Segment & seg = mesh.LineSegment(i); + outfile.width(4); + outfile << seg.si << " "; + + outfile << " "; + outfile.width(8); + outfile << seg.p1; + outfile << " "; + outfile.width(8); + outfile << seg.p2; + + outfile << "\n"; + } + } +} + + + + + + + + + +void WriteSurfaceFormat (const Mesh & mesh, + const string & filename) +{ + // surface mesh + int i, j; + + cout << "Write Surface Mesh" << endl; + + ofstream outfile (filename.c_str()); + + outfile << "surfacemesh" << endl; + + outfile << mesh.GetNP() << endl; + for (i = 1; i <= mesh.GetNP(); i++) + { + for (j = 1; j <= 3; j++) + { + outfile.width(10); + outfile << mesh.Point(i).X(j) << " "; + } + outfile << endl; + } + outfile << mesh.GetNSE() << endl; + for (i = 1; i <= mesh.GetNSE(); i++) + { + for (j = 1; j <= 3; j++) + { + outfile.width(8); + outfile << mesh.SurfaceElement(i).PNum(j); + } + outfile << endl; + } +} + + + + + +/* + * save surface mesh as STL file + */ + +void WriteSTLFormat (const Mesh & mesh, + const string & filename) +{ + cout << "\nWrite STL Surface Mesh" << endl; + + ofstream outfile (filename.c_str()); + + int i, j, k; + + outfile.precision(10); + + outfile << "solid" << endl; + + for (i = 1; i <= mesh.GetNSE(); i++) + { + outfile << "facet normal "; + const Point3d& p1 = mesh.Point(mesh.SurfaceElement(i).PNum(1)); + const Point3d& p2 = mesh.Point(mesh.SurfaceElement(i).PNum(2)); + const Point3d& p3 = mesh.Point(mesh.SurfaceElement(i).PNum(3)); + + Vec3d normal = Cross(p2-p1,p3-p1); + if (normal.Length() != 0) + { + normal /= (normal.Length()); + } + + outfile << normal.X() << " " << normal.Y() << " " << normal.Z() << "\n"; + outfile << "outer loop\n"; + + outfile << "vertex " << p1.X() << " " << p1.Y() << " " << p1.Z() << "\n"; + outfile << "vertex " << p2.X() << " " << p2.Y() << " " << p2.Z() << "\n"; + outfile << "vertex " << p3.X() << " " << p3.Y() << " " << p3.Z() << "\n"; + + outfile << "endloop\n"; + outfile << "endfacet\n"; + } + outfile << "endsolid" << endl; +} + + + + + +/* + * + * write surface mesh as VRML file + * + */ + +void WriteVRMLFormat (const Mesh & mesh, + bool faces, + const string & filename) +{ + + if (faces) + + { + // Output in VRML, IndexedFaceSet is used + // Bartosz Sawicki <sawickib@ee.pw.edu.pl> + + int np = mesh.GetNP(); + int nse = mesh.GetNSE(); + int i, j, k, l; + + ofstream outfile (filename.c_str()); + + outfile.precision(6); + outfile.setf (ios::fixed, ios::floatfield); + outfile.setf (ios::showpoint); + + outfile << "#VRML V2.0 utf8 \n" + "Background {\n" + " skyColor [1 1 1]\n" + " groundColor [1 1 1]\n" + "}\n" + "Group{ children [\n" + "Shape{ \n" + "appearance Appearance { material Material { }} \n" + "geometry IndexedFaceSet { \n" + "coord Coordinate { point [ \n"; + + + for (i = 1; i <= np; i++) + { + const Point3d & p = mesh.Point(i); + outfile.width(10); + outfile << p.X() << " "; + outfile << p.Y() << " "; + outfile << p.Z() << " \n"; + } + + outfile << " ] } \n" + "coordIndex [ \n"; + + for (i = 1; i <= nse; i++) + { + const Element2d & el = mesh.SurfaceElement(i); + + for (j = 1; j <= 3; j++) + { + outfile.width(8); + outfile << el.PNum(j)-1; + } + outfile << " -1 \n"; + } + + outfile << " ] \n"; + + //define number and RGB definitions of colors + outfile << "color Color { color [1 0 0, 0 1 0, 0 0 1, 1 1 0]} \n" + "colorIndex [\n"; + + for (i = 1; i <= nse; i++) + { + outfile << mesh.GetFaceDescriptor(mesh.SurfaceElement(i).GetIndex ()).BCProperty(); + outfile << endl; + } + + outfile << " ] \n" + "colorPerVertex FALSE \n" + "creaseAngle 0 \n" + "solid FALSE \n" + "ccw FALSE \n" + "convex TRUE \n" + "} } # end of Shape\n" + "] }\n"; + + } /* end of VRMLFACES */ + + + else + + { + // Output in VRML, IndexedLineSet is used + // Bartosz Sawicki <sawickib@ee.pw.edu.pl> + + int np = mesh.GetNP(); + int nse = mesh.GetNSE(); + int i, j, k, l; + + ofstream outfile (filename.c_str()); + + outfile.precision(6); + outfile.setf (ios::fixed, ios::floatfield); + outfile.setf (ios::showpoint); + + outfile << "#VRML V2.0 utf8 \n" + "Background {\n" + " skyColor [1 1 1]\n" + " groundColor [1 1 1]\n" + "}\n" + "Group{ children [\n" + "Shape{ \n" + "appearance Appearance { material Material { }} \n" + "geometry IndexedLineSet { \n" + "coord Coordinate { point [ \n"; + + + for (i = 1; i <= np; i++) + { + const Point3d & p = mesh.Point(i); + outfile.width(10); + outfile << p.X() << " "; + outfile << p.Y() << " "; + outfile << p.Z() << " \n"; + } + + outfile << " ] } \n" + "coordIndex [ \n"; + + for (i = 1; i <= nse; i++) + { + const Element2d & el = mesh.SurfaceElement(i); + + for (j = 1; j <= 3; j++) + { + outfile.width(8); + outfile << el.PNum(j)-1; + } + outfile.width(8); + outfile << el.PNum(1)-1; + outfile << " -1 \n"; + } + + outfile << " ] \n"; + +/* Uncomment if you want color mesh + outfile << "color Color { color [1 1 1, 0 1 0, 0 0 1, 1 1 0]} \n" + "colorIndex [\n"; + + for (i = 1; i <= nse; i++) + { + outfile << mesh.GetFaceDescriptor(mesh.SurfaceElement(i).GetIndex ()).BCProperty(); + outfile << endl; + } + + outfile << " ] \n" +*/ + outfile << "colorPerVertex FALSE \n" + "} } #end of Shape\n" + "] } \n"; + + } + +} + + + + + + +/* + * FEPP .. a finite element package developed at University Linz, Austria + */ +void WriteFEPPFormat (const Mesh & mesh, + const CSGeometry & geom, + const string & filename) +{ + + ofstream outfile (filename.c_str()); + + if (mesh.GetDimension() == 3) + + { + + // output for FEPP + + int np = mesh.GetNP(); + int ne = mesh.GetNE(); + int nse = mesh.GetNSE(); + int ns = mesh.GetNFD(); + int i, j; + + outfile.precision(5); + outfile.setf (ios::fixed, ios::floatfield); + outfile.setf (ios::showpoint); + + outfile << "volumemesh4" << endl; + outfile << nse << endl; + for (i = 1; i <= nse; i++) + { + const Element2d & el = mesh.SurfaceElement(i); + + // int facenr = mesh.facedecoding.Get(el.GetIndex()).surfnr; + outfile.width(4); + outfile << el.GetIndex() << " "; + outfile.width(4); + // outfile << mesh.GetFaceDescriptor(el.GetIndex()).BCProperty() << " "; + outfile << mesh.GetFaceDescriptor(el.GetIndex()).BCProperty() << " "; + outfile.width(4); + outfile << el.GetNP() << " "; + for (j = 1; j <= el.GetNP(); j++) + { + outfile.width(8); + outfile << el.PNum(j); + } + outfile << "\n"; + } + + + outfile << ne << "\n"; + for (i = 1; i <= ne; i++) + { + const Element & el = mesh.VolumeElement(i); + outfile.width(4); + outfile << el.GetIndex() << " "; + outfile.width(4); + outfile << el.GetNP() << " "; + for (j = 1; j <= el.GetNP(); j++) + { + outfile.width(8); + outfile << el.PNum(j); + } + outfile << "\n"; + } + + outfile << np << "\n"; + for (i = 1; i <= np; i++) + { + const Point3d & p = mesh.Point(i); + + outfile.width(10); + outfile << p.X() << " "; + outfile.width(9); + outfile << p.Y() << " "; + outfile.width(9); + outfile << p.Z() << "\n"; + } + + /* + if (typ == WRITE_FEPPML) + { + int nbn = mesh.mlbetweennodes.Size(); + outfile << nbn << "\n"; + for (i = 1; i <= nbn; i++) + outfile << mesh.mlbetweennodes.Get(i).I1() << " " + << mesh.mlbetweennodes.Get(i).I2() << "\n"; + + + // int ncon = mesh.connectedtonode.Size(); + // outfile << ncon << "\n"; + // for (i = 1; i <= ncon; i++) + // outfile << i << " " << mesh.connectedtonode.Get(i) << endl; + } + */ + + + // write CSG surfaces + if (&geom && geom.GetNSurf() >= ns) + { + outfile << ns << endl; + for (i = 1; i <= ns; i++) + geom.GetSurface(mesh.GetFaceDescriptor(i).SurfNr())->Print(outfile); + } + else + outfile << "0" << endl; + } + + + else + + { // 2D fepp format + + ; + /* + extern SplineGeometry2d * geometry2d; + if (geometry2d) + Save2DMesh (mesh, &geometry2d->GetSplines(), outfile); + else + Save2DMesh (mesh, 0, outfile); + */ + } +} + + + + + + +/* + * Edge element mesh format + * points, elements, edges + */ + +void WriteEdgeElementFormat (const Mesh & mesh, + const CSGeometry & geom, + const string & filename) +{ + cout << "write edge element format" << endl; + + const MeshTopology * top = &mesh.GetTopology(); + int npoints = mesh.GetNP(); + int nelements = mesh.GetNE(); + int nsurfelem = mesh.GetNSE(); + int nedges = top->GetNEdges(); + int i, j; + + int inverttets = mparam.inverttets; + int invertsurf = mparam.inverttrigs; + ARRAY<int> edges; + + ofstream outfile (filename.c_str()); + + outfile.precision(6); + outfile.setf (ios::fixed, ios::floatfield); + outfile.setf (ios::showpoint); + + + // vertices with coordinates + outfile << npoints << "\n"; + for (i = 1; i <= npoints; i++) + { + const Point3d & p = mesh.Point(i); + + outfile.width(10); + outfile << p.X() << " "; + outfile.width(9); + outfile << p.Y() << " "; + outfile.width(9); + outfile << p.Z() << "\n"; + } + + // element - edge - list + outfile << nelements << " " << nedges << "\n"; + for (i = 1; i <= nelements; i++) + { + Element el = mesh.VolumeElement(i); + if (inverttets) + el.Invert(); + outfile.width(4); + outfile << el.GetIndex() << " "; + outfile.width(8); + outfile << el.GetNP(); + for (j = 1; j <= el.GetNP(); j++) + { + outfile << " "; + outfile.width(8); + outfile << el.PNum(j); + } + + top->GetElementEdges(i,edges); + outfile << endl << " "; + outfile.width(8); + outfile << edges.Size(); + for (j=1; j <= edges.Size(); j++) + { + outfile << " "; + outfile.width(8); + outfile << edges[j-1]; + } + outfile << "\n"; + + // orientation: + top->GetElementEdgeOrientations(i,edges); + outfile << " "; + for (j=1; j <= edges.Size(); j++) + { + outfile << " "; + outfile.width(8); + outfile << edges[j-1]; + } + outfile << "\n"; + } + + // surface element - edge - list (with boundary conditions) + outfile << nsurfelem << "\n"; + for (i = 1; i <= nsurfelem; i++) + { + Element2d el = mesh.SurfaceElement(i); + if (invertsurf) + el.Invert(); + outfile.width(4); + outfile << mesh.GetFaceDescriptor (el.GetIndex()).BCProperty() << " "; + outfile.width(8); + outfile << el.GetNP(); + for (j = 1; j <= el.GetNP(); j++) + { + outfile << " "; + outfile.width(8); + outfile << el.PNum(j); + } + + top->GetSurfaceElementEdges(i,edges); + outfile << endl << " "; + outfile.width(8); + outfile << edges.Size(); + for (j=1; j <= edges.Size(); j++) + { + outfile << " "; + outfile.width(8); + outfile << edges[j-1]; + } + outfile << "\n"; + } + + + int v1, v2; + // edge - vertex - list + outfile << nedges << "\n"; + for (i=1; i <= nedges; i++) + { + top->GetEdgeVertices(i,v1,v2); + outfile.width(4); + outfile << v1; + outfile << " "; + outfile.width(8); + outfile << v2 << endl; + } +} + + + + + + + + + +#ifdef OLDSTYLE_WRITE + + +void WriteFile (int typ, + const Mesh & mesh, + const CSGeometry & geom, + const char * filename, + const char * geomfile, + double h) +{ + + + int inverttets = mparam.inverttets; + int invertsurf = mparam.inverttrigs; + + + + + + + + + if (typ == WRITE_EDGEELEMENT) + { + // write edge element file + // Peter Harscher, ETHZ + + cout << "Write Edge-Element Format" << endl; + + ofstream outfile (filename); + + int i, j; + int ned; + + // hash table representing edges; + INDEX_2_HASHTABLE<int> edgeht(mesh.GetNP()); + + // list of edges + ARRAY<INDEX_2> edgelist; + + // edge (point) on boundary ? + BitArray bedge, bpoint(mesh.GetNP()); + + static int eledges[6][2] = { { 1, 2 } , { 1, 3 } , { 1, 4 }, + { 2, 3 } , { 2, 4 } , { 3, 4 } }; + + // fill hashtable (point1, point2) ----> edgenr + for (i = 1; i <= mesh.GetNE(); i++) + { + const Element & el = mesh.VolumeElement (i); + INDEX_2 edge; + for (j = 1; j <= 6; j++) + { + edge.I1() = el.PNum (eledges[j-1][0]); + edge.I2() = el.PNum (eledges[j-1][1]); + edge.Sort(); + + if (!edgeht.Used (edge)) + { + edgelist.Append (edge); + edgeht.Set (edge, edgelist.Size()); + } + } + } + + + // set bedges, bpoints + bedge.SetSize (edgelist.Size()); + bedge.Clear(); + bpoint.Clear(); + + for (i = 1; i <= mesh.GetNSE(); i++) + { + const Element2d & sel = mesh.SurfaceElement(i); + for (j = 1; j <= 3; j++) + { + bpoint.Set (sel.PNum(j)); + + INDEX_2 edge; + edge.I1() = sel.PNum(j); + edge.I2() = sel.PNum(j%3+1); + edge.Sort(); + + bedge.Set (edgeht.Get (edge)); + } + } + + + + outfile << mesh.GetNE() << endl; + // write element ---> point + for (i = 1; i <= mesh.GetNE(); i++) + { + const Element & el = mesh.VolumeElement(i); + + outfile.width(8); + outfile << i; + for (j = 1; j <= 4; j++) + { + outfile.width(8); + outfile << el.PNum(j); + } + outfile << endl; + } + + // write element ---> edge + for (i = 1; i <= mesh.GetNE(); i++) + { + const Element & el = mesh.VolumeElement (i); + INDEX_2 edge; + for (j = 1; j <= 6; j++) + { + edge.I1() = el.PNum (eledges[j-1][0]); + edge.I2() = el.PNum (eledges[j-1][1]); + edge.Sort(); + + outfile.width(8); + outfile << edgeht.Get (edge); + } + outfile << endl; + } + + // write points + outfile << mesh.GetNP() << endl; + outfile.precision (6); + for (i = 1; i <= mesh.GetNP(); i++) + { + const Point3d & p = mesh.Point(i); + + for (j = 1; j <= 3; j++) + { + outfile.width(8); + outfile << p.X(j); + } + outfile << " " + << (bpoint.Test(i) ? "1" : 0) << endl; + } + + // write edges + outfile << edgelist.Size() << endl; + for (i = 1; i <= edgelist.Size(); i++) + { + outfile.width(8); + outfile << edgelist.Get(i).I1(); + outfile.width(8); + outfile << edgelist.Get(i).I2(); + outfile << " " + << (bedge.Test(i) ? "1" : "0") << endl; + } + } + + + + +} +#endif +} diff --git a/contrib/Netgen/libsrc/interface/writeuser.hpp b/contrib/Netgen/libsrc/interface/writeuser.hpp new file mode 100644 index 0000000000..afb2a6d5e3 --- /dev/null +++ b/contrib/Netgen/libsrc/interface/writeuser.hpp @@ -0,0 +1,114 @@ +#ifndef WRITEUSER +#define WRITEUSER + +/**************************************************************************/ +/* File: writeuser.hh */ +/* Authors: many */ +/* Date: 10. Dec. 97 */ +/**************************************************************************/ + + +extern +void WriteFile (int typ, + const Mesh & mesh, + const CSGeometry & geom, + const char * filename, + const char * geomfile = NULL, + double h = 0); + + + +extern +void ReadFile (Mesh & mesh, + const string & filename); + +extern +void ImportSolution (const char * filename); + + + + + + + +extern +void WriteNeutralFormat (const Mesh & mesh, + const CSGeometry & geom, + const string & filename); + +extern +void WriteSurfaceFormat (const Mesh & mesh, + const string & filename); + +extern +void WriteSTLFormat (const Mesh & mesh, + const string & filename); + +extern +void WriteVRMLFormat (const Mesh & mesh, + bool faces, + const string & filename); + +extern +void WriteFEPPFormat (const Mesh & mesh, + const CSGeometry & geom, + const string & filename); + +extern +void WriteGmshFormat (const Mesh & mesh, + const CSGeometry & geom, + const string & filename); + +extern +void WriteUserChemnitz (const Mesh & mesh, + const string & filename); + + +extern +void WriteDiffPackFormat (const Mesh & mesh, + const CSGeometry & geom, + const string & filename); + +extern +void WriteTochnogFormat (const Mesh & mesh, + const string & filename); + +extern +void WriteTecPlotFormat (const Mesh & mesh, + const CSGeometry & geom, + const string & filename); + +extern +void WriteAbaqusFormat (const Mesh & mesh, + const string & filename); + +extern +void WriteFluentFormat (const Mesh & mesh, + const string & filename); + +extern +void WritePermasFormat (const Mesh & mesh, + const string & filename); + +extern +void WriteFEAPFormat (const Mesh & mesh, + const string & filename); + +extern +void WriteElmerFormat (const Mesh & mesh, + const string & filename); + + +extern +void WriteEdgeElementFormat (const Mesh & mesh, + const CSGeometry & geom, + const string & filename); + + + +extern void RegisterUserFormats (ARRAY<const char*> & names); +extern bool WriteUserFormat (const string & format, + const Mesh & mesh, + const CSGeometry & geom, + const string & filename); +#endif diff --git a/contrib/Netgen/libsrc/interface/wuchemnitz.cpp b/contrib/Netgen/libsrc/interface/wuchemnitz.cpp new file mode 100644 index 0000000000..82a513d1ca --- /dev/null +++ b/contrib/Netgen/libsrc/interface/wuchemnitz.cpp @@ -0,0 +1,309 @@ +// Write Chemnitz file format + + +#include <mystdlib.h> + +#include <myadt.hpp> + +#include <linalg.hpp> +#include <csg.hpp> +#include <meshing.hpp> + +namespace netgen +{ + +class POINT3D + { + public: + POINT3D () { }; + double x, y, z; + }; + +class VOLELEMENT + { + public: + VOLELEMENT () {}; + int domnr, p1, p2, p3, p4; + int faces[4]; + }; + +class SURFELEMENT + { + public: + SURFELEMENT () { }; + int snr, p1, p2, p3; + }; + + +class FACE + { + public: + FACE () { }; + int p1, p2, p3; + int edges[3]; + }; + +class EDGE + { + public: + EDGE () { }; + int p1, p2; + }; + +static ARRAY<POINT3D> points; +static ARRAY<VOLELEMENT> volelements; +static ARRAY<SURFELEMENT> surfelements; + +static ARRAY<FACE> faces; +static ARRAY<EDGE> edges; + + +void ReadFile (char * filename) + { + int i, n; + ifstream infile(filename); + char reco[100]; + + + infile >> reco; // file format recognition + + infile >> n; // number of surface elements + cout << n << " Surface elements" << endl; + + for (i = 1; i <= n; i++) + { + SURFELEMENT sel; + infile >> sel.snr >> sel.p1 >> sel.p2 >> sel.p3; + surfelements.Append (sel); + } + + infile >> n; // number of volume elements + cout << n << " Volume elements" << endl; + + for (i = 1; i <= n; i++) + { + VOLELEMENT el; + infile >> el.p1 >> el.p2 >> el.p3 >> el.p4; + volelements.Append (el); + } + + infile >> n; // number of points + cout << n << " Points" << endl; + + for (i = 1; i <= n; i++) + { + POINT3D p; + infile >> p.x >> p.y >> p.z; + points.Append (p); + } + } + + + +void ReadFileMesh (const Mesh & mesh) +{ + int i, n; + + n = mesh.GetNSE(); // number of surface elements + cout << n << " Surface elements" << endl; + + for (i = 1; i <= n; i++) + { + SURFELEMENT sel; + const Element2d & el = mesh.SurfaceElement(i); + sel.snr = el.GetIndex(); + sel.p1 = el.PNum(1); + sel.p2 = el.PNum(2); + sel.p3 = el.PNum(3); + surfelements.Append (sel); + } + + n = mesh.GetNE(); // number of volume elements + cout << n << " Volume elements" << endl; + + for (i = 1; i <= n; i++) + { + VOLELEMENT el; + const Element & nel = mesh.VolumeElement(i); + el.p1 = nel.PNum(1); + el.p2 = nel.PNum(2); + el.p3 = nel.PNum(3); + el.p4 = nel.PNum(4); + // infile >> el.p1 >> el.p2 >> el.p3 >> el.p4; + volelements.Append (el); + } + + n = mesh.GetNP(); // number of points + cout << n << " Points" << endl; + + for (i = 1; i <= n; i++) + { + POINT3D p; + Point3d mp = mesh.Point(i); + p.x = mp.X(); + p.y = mp.Y(); + p.z = mp.Z(); + // infile >> p.x >> p.y >> p.z; + points.Append (p); + } + } + + + + +void Convert () + { + int i, j, facei, edgei; + INDEX_3 i3; + INDEX_2 i2; + + INDEX_3_HASHTABLE<int> faceindex(volelements.Size()/5 + 1); + INDEX_2_HASHTABLE<int> edgeindex(volelements.Size()/5 + 1); + + for (i = 1; i <= volelements.Size(); i++) + { + for (j = 1; j <= 4; j++) + { + switch (j) + { + case 1: + i3.I1() = volelements.Get(i).p2; + i3.I2() = volelements.Get(i).p3; + i3.I3() = volelements.Get(i).p4; + break; + case 2: + i3.I1() = volelements.Get(i).p1; + i3.I2() = volelements.Get(i).p3; + i3.I3() = volelements.Get(i).p4; + break; + case 3: + i3.I1() = volelements.Get(i).p1; + i3.I2() = volelements.Get(i).p2; + i3.I3() = volelements.Get(i).p4; + break; + case 4: + i3.I1() = volelements.Get(i).p1; + i3.I2() = volelements.Get(i).p2; + i3.I3() = volelements.Get(i).p3; + break; + } + i3.Sort(); + if (faceindex.Used (i3)) + facei = faceindex.Get(i3); + else + { + FACE fa; + fa.p1 = i3.I1(); + fa.p2 = i3.I2(); + fa.p3 = i3.I3(); + facei = faces.Append (fa); + faceindex.Set (i3, facei); + } + + volelements.Elem(i).faces[j-1] = facei; + } + + } + + + for (i = 1; i <= faces.Size(); i++) + { + for (j = 1; j <= 3; j++) + { + switch (j) + { + case 1: + i2.I1() = faces.Get(i).p2; + i2.I2() = faces.Get(i).p3; + break; + case 2: + i2.I1() = faces.Get(i).p1; + i2.I2() = faces.Get(i).p3; + break; + case 3: + i2.I1() = faces.Get(i).p1; + i2.I2() = faces.Get(i).p2; + break; + } + if (i2.I1() > i2.I2()) swap (i2.I1(), i2.I2()); + if (edgeindex.Used (i2)) + edgei = edgeindex.Get(i2); + else + { + EDGE ed; + ed.p1 = i2.I1(); + ed.p2 = i2.I2(); + edgei = edges.Append (ed); + edgeindex.Set (i2, edgei); + } + + faces.Elem(i).edges[j-1] = edgei; + } + + } + + } + + +void WriteFile (ostream & outfile) + { + int i; + + outfile + << "#VERSION: 1.0" << endl + << "#PROGRAM: NETGEN" << endl + << "#EQN_TYPE: POISSON" << endl + << "#DIMENSION: 3D" << endl + << "#DEG_OF_FREE: 1" << endl + << "#DESCRIPTION: I don't know" << endl + << "##RENUM: not done" << endl + << "#USER: Kleinzen" << endl + << "DATE: 10.06.1996" << endl; + + outfile << "#HEADER: 8" << endl + << points.Size() << " " << edges.Size() << " " + << faces.Size() << " " << volelements.Size() << " 0 0 0 0" << endl; + + outfile << "#VERTEX: " << points.Size() << endl; + for (i = 1; i <= points.Size(); i++) + outfile << " " << i << " " << points.Get(i).x << " " << points.Get(i).y + << " " << points.Get(i).z << endl; + + outfile << "#EDGE: " << edges.Size() << endl; + for (i = 1; i <= edges.Size(); i++) + outfile << " " << i << " 1 " + << edges.Get(i).p1 << " " + << edges.Get(i).p2 + << " 0" << endl; + + outfile << "#FACE: " << faces.Size() << endl; + for (i = 1; i <= faces.Size(); i++) + outfile << " " << i << " 1 3 " + << faces.Get(i).edges[0] << " " + << faces.Get(i).edges[1] << " " + << faces.Get(i).edges[2] << endl; + + outfile << "#SOLID: " << volelements.Size() << endl; + for (i = 1; i <= volelements.Size(); i++) + outfile << " " << i << " 1 4 " + << volelements.Get(i).faces[0] << " " + << volelements.Get(i).faces[1] << " " + << volelements.Get(i).faces[2] << " " + << volelements.Get(i).faces[3] << endl; + + outfile << "#END_OF_DATA" << endl; + } + + +void WriteUserChemnitz (const Mesh & mesh, + const string & filename) +{ + ofstream outfile (filename.c_str()); + + ReadFileMesh (mesh); + Convert (); + + WriteFile (outfile); + cout << "Wrote Chemnitz standard file" << endl; +} +} diff --git a/contrib/Netgen/libsrc/linalg/Makefile b/contrib/Netgen/libsrc/linalg/Makefile new file mode 100644 index 0000000000..0cb19b0932 --- /dev/null +++ b/contrib/Netgen/libsrc/linalg/Makefile @@ -0,0 +1,13 @@ +# +# Makefile for linear algebra library +# +src = basemat.cpp densemat.cpp vector.cpp sparsmat.cpp polynomial.cpp +# +lib = la +libpath = libsrc/linalg +# +# +include ../makefile.inc +# + + diff --git a/contrib/Netgen/libsrc/linalg/basemat.cpp b/contrib/Netgen/libsrc/linalg/basemat.cpp new file mode 100644 index 0000000000..889d79d668 --- /dev/null +++ b/contrib/Netgen/libsrc/linalg/basemat.cpp @@ -0,0 +1,472 @@ +#ifdef ABC + +#include <mystdlib.h> +#include <linalg.hpp> + + +// ofstream (*myerr) ("error.out"); +// ofstream (*myerr) ("NUL"); + + +namespace netgen +{ + +double BaseMatrix :: shit = 0; + + +BaseMatrix :: BaseMatrix () + { + height = width = 0; + symmetric = 0; + } + +BaseMatrix :: BaseMatrix (INDEX h, INDEX w) + { + if (!w) w = h; + height = h; + width = w; + symmetric = 0; + } + +void BaseMatrix :: SetSize (INDEX h, INDEX w) + { + if (!w) w = h; + height = h; + width = w; + } + +void BaseMatrix :: SetSymmetric (int sym) + { + symmetric = sym; + } + +double & BaseMatrix :: operator() (INDEX, INDEX) + { + (*myerr) << "BaseMatrix: operator() called" << endl; + return shit; + } + +double BaseMatrix :: operator() (INDEX, INDEX) const + { + (*myerr) << "BaseMatrix: operator() called" << endl; + return 0; + } + + + +ostream & operator<<(ostream & s, const BaseMatrix & m) + { + return m.Print (s); + } + +ostream & BaseMatrix :: Print (ostream & s) const + { + if (Symmetric()) s << "Symmetric" << endl; + for (INDEX i = 1; i <= Height(); i++) + { + for (INDEX j = 1; j < Width(); j++) + s << (*this)(i, j) << " "; + s << (*this)(i, Width()) << endl; + } + + return s; + } + + + /* +TempVector BaseMatrix :: operator* (const Vector & v) const + { + Vector * prod = new Vector(Height()); + + if (Width() != v.Length()) + { + (*myerr) << "\nMatrix and Vector don't fit 1" << endl; + } + else if (Height() != prod->Length()) + { + (*myerr) << "Base_Matrix::operator*(Vector): prod vector not ok" << endl; + } + else + { + Mult (v, *prod); + } + + return *prod; + } + */ + + +DenseMatrix operator* (const BaseMatrix & m1, const BaseMatrix & m2) + { + DenseMatrix temp (m1.Height(), m2.Width()); + double sum; + + if (m1.Width() != m2.Height()) + { + (*myerr) << "BaseMatrix :: operator*: Matrix Size does not fit" << endl; + } + else if (temp.Height() != m1.Height()) + { + (*myerr) << "BaseMatrix :: operator*: temp not allocated" << endl; + } + else + { + for (INDEX i = 1; i <= m1.Height(); i++) + for (INDEX j = 1; j <= m2.Width(); j++) + { + sum = 0; + for (INDEX k = 1; k <= m1.Width(); k++) + sum += m1(i, k) * m2(k, j); + temp(i, j) = sum; + } + } + return temp; + } + + +DenseMatrix operator+ (const BaseMatrix & m1, const BaseMatrix & m2) + { + DenseMatrix temp (m1.Height(), m1.Width()); + INDEX i, j; + + if (m1.Width() != m2.Width() || m1.Height() != m2.Height()) + { + (*myerr) << "BaseMatrix :: operator+: Matrix Size does not fit" << endl; + } + else if (temp.Height() != m1.Height()) + { + (*myerr) << "BaseMatrix :: operator+: temp not allocated" << endl; + } + else + { + for (i = 1; i <= m1.Height(); i++) + for (j = 1; j <= m1.Width(); j++) + { + temp(i, j) = m1(i, j) + m2(i, j); + } + } + return temp; + } + + +void BaseMatrix :: Mult (const FlatVector & /* v */, + FlatVector & /* prod */) const + { + (*myerr) << "BaseMatrix :: Mult called" << endl; + double * x = 0; + *x = 1; + assert (1); + } + +void BaseMatrix :: MultTrans (const Vector & v, + Vector & prod) const + { + if (Symmetric()) + Mult (v, prod); + else + (*myerr) << "BaseMatrix :: MultTrans called for non symmetric matrix" << endl; + } + +void BaseMatrix :: Residuum (const Vector & x, + const Vector & b, Vector & res) const + { + Mult (x, res); + res *= -1; + res.Add (1, b); + } + +void BaseMatrix :: ResiduumTrans (const Vector & x, + const Vector & b, Vector & res) const + { + MultTrans (x, res); + res *= -1; + res.Add (1, b); + } + +BaseMatrix * BaseMatrix :: Copy () const + { + (*myerr) << "BaseMatrix :: Copy called" << endl; + return NULL; + } + + +Vector * BaseMatrix :: CreateVector () const + { + return new Vector (Height()); + } + + + +/* +void BaseMatrix :: Mult (const Vector & v, Vector & prod) const + { + double sum; + + prod.SetLength (Height()); + + if (Width() != v.Length()) + { + (*myerr) << "\nMatrix and Vector don't fit 2" << endl; + } + else if (Height() != prod.Length()) + { + (*myerr) << "Base_Matrix::operator*(Vector): prod vector not ok" << endl; + } + else + { + for (INDEX i = 1; i <= Height(); i++) + { + sum = 0; + + for (INDEX j = 1; j <= Width(); j++) + sum += (*this)(i,j) * v.Get(j); + + prod.Set (i, sum); + } + } + } + + +void BaseMatrix :: MultTrans (const Vector & v, Vector & prod) const + { + double sum; + + prod.SetLength (Width()); + + if (Height() != v.Length()) + { + (*myerr) << "\nMatrix and Vector don't fit 3" << endl; + } + else if (Width() != prod.Length()) + { + (*myerr) << "Base_Matrix::operator*(Vector): prod vector not ok" << endl; + } + else + { + for (INDEX i = 1; i <= Width(); i++) + { + sum = 0; + + for (INDEX j = 1; j <= Height(); j++) + sum += (*this)(j, i) * v.Get(j); + + prod.Set (i, sum); + } + } + } + + +void BaseMatrix :: Residuum (const Vector & x, const Vector & b, Vector & res) const + { + double sum; + + res.SetLength (Height()); + + if (Width() != x.Length() || Height() != b.Length()) + { + (*myerr) << "\nMatrix and Vector don't fit 4" << endl; + } + else if (Height() != res.Length()) + { + (*myerr) << "Base_Matrix::operator*(Vector): prod vector not ok" << endl; + } + else + { + for (INDEX i = 1; i <= Height(); i++) + { + sum = b.Get(i); + + for (INDEX j = 1; j <= Width(); j++) + sum -= (*this)(i,j) * x.Get(j); + + res.Set (i, sum); + } + } + } +*/ + + + + + + + +void BaseMatrix :: SolveDestroy (const Vector & v, Vector & sol) + { + INDEX i, j, k; + double q; + + if (Width() != Height()) + { + (*myerr) << "SolveDestroy: Matrix not square"; + return; + } + if (Width() != v.Size()) + { + (*myerr) << "SolveDestroy: Matrix and Vector don't fit"; + return; + } + + sol = v; + if (Height() != sol.Size()) + { + (*myerr) << "SolveDestroy: Solution Vector not ok"; + return; + } + + for (i = 1; i <= Height(); i++) + { + for (j = i+1; j <= Height(); j++) + { + q=(*this)(j,i) / (*this)(i,i); + for (k = i+1; k <= Height(); k++) + { + (*this)(j, k) -= q * (*this)(i,k); + } + sol.Elem(j) -= q * sol.Get(i); + } + } + + for (i = Height(); i >= 1; i--) + { + q = sol.Elem(i); + for (j = i+1; j <= Height(); j++) + { + q -= (*this)(i,j) * sol.Get(j); + } + sol.Elem(i) = q / (*this)(i,i); + } + } + +void BaseMatrix :: Solve (const Vector & v, Vector & sol) const + { + BaseMatrix * temp = Copy(); + + if (temp->Height() != Height()) + { + (*myerr) << "Solve: Matrix temp not allocated" << endl; + return; + } + + temp->SolveDestroy (v, sol); + + delete temp; + } + + + /* +Vector BaseMatrix :: SolveDestroyFunc (const Vector & b) const +{ + return Vector(0); +} +*/ + + +Vector BaseMatrix :: Solve (const Vector & v) const + { + Vector sol (v.Size()); + + if (Width() != Height()) + { + (*myerr) << "Solve: Matrix not square"; + return v; + } + if (Width() != v.Size()) + { + (*myerr) << "Solve: Matrix and Vector don't fit"; + return v; + } + if (Width() != sol.Size()) + { + (*myerr) << "Solve: Vector sol not allocated" << endl; + } + + Solve (v, sol); + + return sol; + } + + + + + + + +void BaseMatrix :: LU_Decomposition (DenseMatrix & l, DenseMatrix & u) const + { + INDEX i, j ,k; + double sum; + l.SetSize (Width()); + u.SetSize (Width()); + + for (i = 1; i <= Width(); i++) + for (j = 1; j <= Width(); j++) + l(i, j) = u(i, j) = 0; + + for (i = 1; i <= Width(); i++) + { + for (k = 1; k < i; k++) + { + sum = (*this)(i, k); + for (j = 1; j < k; j++) + sum -= l(i, j) * u(j, k); + l(i, k) = sum / u(k, k); + } + l(i, i) = 1; + + for (k = i; k <= Width(); k++) + { + sum = (*this)(i, k); + for (j = 1; j < i; j++) + sum -= l(i, j) * u(j, k); + u(i, k) = sum; + } + } + } + + + +void Transpose (const BaseMatrix & m1, DenseMatrix & m2) + { + m2.SetSize (m1.Width(), m1.Height()); + INDEX i, j; + + for (i = 1; i <= m1.Height(); i++) + for (j = 1; j <= m1.Width(); j++) + m2(j, i) = m1(i, j); + } + + + +DenseMatrix * BaseMatrix :: MakeDenseMatrix () const +{ + DenseMatrix * dmat = new DenseMatrix (Height(), Width()); + dmat -> SetSymmetric(Symmetric()); + + Vector x(Width()), y(Height()); + INDEX i, j; + + for (i = 1; i <= Width(); i++) + { + x = 0; + x.Elem(i) = 1; + Mult (x, y); + + for (j = 1; j <= Height(); j++) + dmat->Elem(j, i) = y.Get(j); + } + + return dmat; +} + + +BaseMatrix * BaseMatrix :: InverseMatrix (const BitArray * /* inner */) const +{ + (*mycout) << "called basematrix::inversemarix" << endl; + return NULL; +} + + + +} +#endif diff --git a/contrib/Netgen/libsrc/linalg/basemat.hpp b/contrib/Netgen/libsrc/linalg/basemat.hpp new file mode 100644 index 0000000000..d47abe790d --- /dev/null +++ b/contrib/Netgen/libsrc/linalg/basemat.hpp @@ -0,0 +1,109 @@ +#ifdef NONE + +#ifndef FILE_BASEMAT +#define FILE_BASEMAT + +/**************************************************************************/ +/* File: basemat.hh */ +/* Author: Joachim Schoeberl */ +/* Date: 01. Oct. 94 */ +/**************************************************************************/ + +/* + Base type for linear operator +*/ + +class DenseMatrix; + +/// +class BaseMatrix +{ +protected: + /// + INDEX height, width; + /// + int symmetric; + /// + static double shit; + +public: + /// + BaseMatrix (); + /// + BaseMatrix (INDEX h, INDEX w = 0); + /// + virtual ~BaseMatrix () { }; + + /// + INDEX Width () const { return width; } + /// + INDEX Height () const { return height; } + /// + int Symmetric () const { return symmetric; } + + /// + virtual void SetSize (INDEX h, INDEX w = 0); + /// + virtual void SetSymmetric (int sym = 1); + + /// + virtual double & operator() (INDEX i, INDEX j); + /// + virtual double operator() (INDEX i, INDEX j) const; + + /// + friend ostream & operator<<(ostream & s, const BaseMatrix & m); + /// + virtual ostream & Print (ostream & s) const; + + /// + // TempVector operator* (const Vector & v) const; + + + /// + virtual void Mult (const FlatVector & v, FlatVector & prod) const; + /// + virtual void MultTrans (const Vector & v, Vector & prod) const; + /// + virtual void Residuum (const Vector & x, const Vector & b, Vector & res) const; + /// + virtual void ResiduumTrans (const Vector & x, const Vector & b, Vector & res) const; + // virtual double EvaluateBilinearform (const Vector & x); + + virtual BaseMatrix * Copy () const; + /// + virtual Vector * CreateVector () const; + + /// + virtual void AddElementMatrix (const ARRAY<INDEX> & /* pnum */, + const BaseMatrix & /* elemmat */) { }; + /// + virtual void MultElementMatrix (const ARRAY<INDEX> & /* pnum */, + const Vector & /* x */, Vector & /* y */) { }; + /// + virtual void MultTransElementMatrix (const ARRAY<INDEX> & /* pnum */, + const Vector & /* x */, Vector & /* y */) { }; + + + /// + virtual DenseMatrix * MakeDenseMatrix () const; + /// + virtual BaseMatrix * InverseMatrix (const class BitArray * inner = NULL) + const; + + /// + virtual void SolveDestroy (const Vector & b, Vector & x); + /// + void Solve (const Vector & b, Vector & x) const; + /// + // virtual Vector SolveDestroyFunc (const Vector & b) const; + /// + Vector Solve (const Vector & b) const; + /// + virtual void LU_Decomposition (DenseMatrix & l, DenseMatrix & u) const; +}; + + +#endif + +#endif diff --git a/contrib/Netgen/libsrc/linalg/densemat.cpp b/contrib/Netgen/libsrc/linalg/densemat.cpp new file mode 100644 index 0000000000..d15c123e0d --- /dev/null +++ b/contrib/Netgen/libsrc/linalg/densemat.cpp @@ -0,0 +1,1443 @@ +#include <mystdlib.h> + +#include <linalg.hpp> + + +namespace netgen +{ + DenseMatrix :: DenseMatrix () + { + data = NULL; + height = 0; + width = 0; + } + + DenseMatrix :: DenseMatrix (int h, int w) + { + if (!w) w = h; + width = w; + height = h; + if (h*w) + data = new double[h*w]; + else + data = 0; + + for (int i = 0 ; i < (h * w); i++) + data[i] = 0; + } + + /* + DenseMatrix :: DenseMatrix (int h, int w, const double * d) + : BaseMatrix (h, w) + { + int size = h * w; + int i; + + if (size) + { + data = new double[size]; + for (i = 0; i < size; i++) + data[i] = d[i]; + } + else + data = NULL; + } + */ + + DenseMatrix :: DenseMatrix (const DenseMatrix & m2) + { + data = NULL; + SetSize (m2.Height(), m2.Width()); + memcpy (data, m2.data, sizeof(double) * Height() * Width()); + } + + DenseMatrix :: ~DenseMatrix () + { + delete [] data; + } + + + void DenseMatrix :: SetSize (int h, int w) + { + if (!w) w = h; + if (height == h && width == w) return; + + height = h; + width = w; + + delete[] data; + + if (h*w) + data = new double[h*w]; + else + data = NULL; + } + + + /* +DenseMatrix & DenseMatrix :: operator= (const BaseMatrix & m2) + { + int i, j; + + SetSize (m2.Height(), m2.Width()); + + if (data) + for (i = 1; i <= Height(); i++) + for (j = 1; j <= Width(); j++) + Set (i, j, m2(i, j)); + else + (*myerr) << "DenseMatrix::Operator=: Matrix not allocated" << endl; + + return *this; + } + */ + + + DenseMatrix & DenseMatrix :: operator= (const DenseMatrix & m2) + { + SetSize (m2.Height(), m2.Width()); + + if (data) memcpy (data, m2.data, sizeof(double) * m2.Height() * m2.Width()); + return *this; + } + + + DenseMatrix & DenseMatrix :: operator+= (const DenseMatrix & m2) + { + int i; + double * p, * q; + + if (Height() != m2.Height() || Width() != m2.Width()) + { + (*myerr) << "DenseMatrix::Operator+=: Sizes don't fit" << endl; + return *this; + } + + if (data) + { + p = data; + q = m2.data; + for (i = Width() * Height(); i > 0; i--) + { + *p += *q; + p++; + q++; + } + } + else + (*myerr) << "DenseMatrix::Operator+=: Matrix not allocated" << endl; + + return *this; + } + + +DenseMatrix & DenseMatrix :: operator-= (const DenseMatrix & m2) + { + int i; + double * p, * q; + + if (Height() != m2.Height() || Width() != m2.Width()) + { + (*myerr) << "DenseMatrix::Operator-=: Sizes don't fit" << endl; + return *this; + } + + if (data) + { + p = data; + q = m2.data; + for (i = Width() * Height(); i > 0; i--) + { + *p -= *q; + p++; + q++; + } + } + else + (*myerr) << "DenseMatrix::Operator-=: Matrix not allocated" << endl; + + return *this; + } + + + + + /* +double & DenseMatrix :: operator() (int i, int j) +{ + if (i >= 1 && j >= 1 && i <= height && j <= width) + return Elem(i,j); + else (*myerr) << "DenseMatrix: index (" << i << "," << j << ") out of range (1.." + << height << ",1.." << width << ")\n"; + static double dummy = 0; + return dummy; +} + + double DenseMatrix :: operator() (int i, int j) const + { + if (i >= 1 && j >= 1 && i <= height && j <= width) + return Get(i,j); + else (*myerr) << "DenseMatrix: index (" << i << "," << j << ") out of range (1.." + << height << ",1.." << width << ")\n"; + + static double dummy = 0; + return dummy; + } + */ + +DenseMatrix & DenseMatrix :: operator= (double v) + { + int i; + double * p = data; + + if (data) + for (i = width*height; i > 0; i--, p++) + *p = v; + + return *this; + } + + + +DenseMatrix & DenseMatrix :: operator*= (double v) + { + int i; + double * p = data; + + if (data) + for (i = width*height; i > 0; i--, p++) + *p *= v; + + return *this; + } + + +double DenseMatrix :: Det () const + { + if (width != height) + { + (*myerr) << "DenseMatrix :: Det: width != height" << endl; + return 0; + } + + switch (width) + { + case 1: return Get(1, 1); + case 2: return Get(1) * Get(4) - Get(2) * Get(3); + + case 3: return Get(1) * Get(5) * Get(9) + + Get(2) * Get(6) * Get(7) + + Get(3) * Get(4) * Get(8) + - Get(1) * Get(6) * Get(8) + - Get(2) * Get(4) * Get(9) + - Get(3) * Get(5) * Get(7); + default: + { + (*myerr) << "Matrix :: Det: general size not implemented (size=" << width << ")" << endl; + return 0; + } + } + } + + +void CalcInverse (const DenseMatrix & m1, DenseMatrix & m2) + { + // int i, j, k, n; + double det; + // DenseMatrix m1 = hm1; + + if (m1.width != m1.height) + { + (*myerr) << "CalcInverse: matrix not symmetric" << endl; + return; + } + if (m1.width != m2.width || m1.height != m2.height) + { + (*myerr) << "CalcInverse: dim(m2) != dim(m1)" << endl; + return; + } + + + if (m1.Width() <= 3) + { + det = m1.Det(); + if (det == 0) + { + (*myerr) << "CalcInverse: Matrix singular" << endl; + return; + } + + det = 1e0 / det; + switch (m1.width) + { + case 1: + { + m2.Set(1, 1, det); + return; + } + case 2: + { + m2.Set(1, 1, det * m1.Get(4)); + m2.Set(2, 2, det * m1.Get(1)); + m2.Set(1, 2, - det * m1.Get(2)); + m2.Set(2, 1, - det * m1.Get(3)); + return; + } + case 3: + { + m2.Set(1, 1, det * (m1.Get(5) * m1.Get(9) - m1.Get(6) * m1.Get(8))); + m2.Set(2, 1, -det * (m1.Get(4) * m1.Get(9) - m1.Get(6) * m1.Get(7))); + m2.Set(3, 1, det * (m1.Get(4) * m1.Get(8) - m1.Get(5) * m1.Get(7))); + + m2.Set(1, 2, -det * (m1.Get(2) * m1.Get(9) - m1.Get(3) * m1.Get(8))); + m2.Set(2, 2, det * (m1.Get(1) * m1.Get(9) - m1.Get(3) * m1.Get(7))); + m2.Set(3, 2, -det * (m1.Get(1) * m1.Get(8) - m1.Get(2) * m1.Get(7))); + + m2.Set(1, 3, det * (m1.Get(2) * m1.Get(6) - m1.Get(3) * m1.Get(5))); + m2.Set(2, 3, -det * (m1.Get(1) * m1.Get(6) - m1.Get(3) * m1.Get(4))); + m2.Set(3, 3, det * (m1.Get(1) * m1.Get(5) - m1.Get(2) * m1.Get(4))); + return; + } + } + } + + else + { + int i, j, k, n; + n = m1.Height(); + + +#ifdef CHOL + int dots = (n > 200); + + // Cholesky + + double x; + Vector p(n); + + m2 = m1; + /* + m2.SetSymmetric(); + if (!m2.Symmetric()) + cerr << "m should be symmetric for Cholesky" << endl; + */ + + for (i = 1; i <= n; i++) + for (j = 1; j < i; j++) + m2.Elem(j, i) = m2.Get(i, j); + + for (i = 1; i <= n; i++) + { + if (dots && i % 10 == 0) + (*mycout) << "." << flush; + + for (j = i; j <= n; j++) + { + x = m2.Get(i, j); + + const double * pik = &m2.Get(i, 1); + const double * pjk = &m2.Get(j, 1); + + for (k = i-2; k >= 0; --k, ++pik, ++pjk) + x -= (*pik) * (*pjk); + + // for (k = i-1; k >= 1; --k) + // x -= m2.Get(j, k) * m2.Get(i, k); + + if (i == j) + { + if (x <= 0) + { + cerr << "Matrix indefinite 1" << endl; + return; + } + + p.Elem(i) = 1 / sqrt(x); + } + else + { + m2.Elem(j, i) = x * p.Get(i); + } + } + } + + for (i = 1; i <= n; i++) + m2.Elem(i, i) = 1 / p.Get(i); + + // check: A = L L^t + +// for (i = 1; i <= n; i++) +// for (j = 1; j <= n; j++) +// { +// x = 0; +// for (k = 1; k <= i && k <= j; k++) +// x += m2.Get(i, k) * m2.Get(j, k); +// (*testout) << "err " << i << "," << j << " = " << (m1.Get(i, j) - x) << endl; +// } + + + + // calc L^{-1}, store upper triangle + + // DenseMatrix hm(n); + // hm = m2; + + for (i = 1; i <= n; i++) + { + if (dots && i % 10 == 0) + (*mycout) << "+" << flush; + + for (j = i; j <= n; j++) + { + x = 0; + if (j == i) x = 1; + + const double * pjk = &m2.Get(j, i); + const double * pik = &m2.Get(i, i); + for (k = i; k < j; k++, ++pjk, ++pik) + x -= *pik * *pjk; + + // for (k = i; k < j; k++) + // x -= m2.Get(j, k) * m2.Get(i, k); + + m2.Elem(i, j) = x / m2.Get(j, j); + } + } + +// (*testout) << "check L^-1" << endl; +// for (i = 1; i <= n; i++) +// for (j = 1; j <= n; j++) +// { +// x = 0; +// for (k = j; k <= i; k++) +// x += hm.Get(i, k) * m2.Get(j, k); +// (*testout) << "i, j = " << i << "," << j << " x = " << x << endl; +// } + + + // calc A^-1 = L^-T * L^-1 + + for (i = 1; i <= n; i++) + { + if (dots && i % 10 == 0) + (*mycout) << "-" << flush; + + for (j = 1; j <= i; j++) + { + x = 0; + k = i; + if (j > i) k = j; + + const double * pik = &m2.Get(i, k); + const double * pjk = &m2.Get(j, k); + + for ( ; k <= n; ++k, ++pik, ++pjk) + x += *pik * *pjk; + // for ( ; k <= n; k++) + // x += m2.Get(i, k) * m2.Get(j, k); + + m2.Elem(i, j) = x; + } + } + + for (i = 1; i <= n; i++) + for (j = 1; j < i; j++) + m2.Elem(j, i) = m2.Get(i, j); + + if (dots) (*mycout) << endl; +#endif + + + + // Gauss - Jordan - algorithm + + int r, hi; + double max, hr; + + + ARRAY<int> p(n); // pivot-permutation + Vector hv(n); + + + m2 = m1; + + /* + if (m2.Symmetric()) + for (i = 1; i <= n; i++) + for (j = 1; j < i; j++) + m2.Elem(j, i) = m2.Get(i, j); + */ + + // Algorithm of Stoer, Einf. i. d. Num. Math, S 145 + + for (j = 1; j <= n; j++) + p.Set(j, j); + + for (j = 1; j <= n; j++) + { + // pivot search + + max = fabs(m2.Get(j, j)); + r = j; + + for (i = j+1; i <= n ;i++) + if (fabs (m2.Get(i, j)) > max) + { + r = i; + max = fabs (m2.Get(i, j)); + } + + if (max < 1e-20) + { + cerr << "Inverse matrix: matrix singular" << endl; + return; + } + + r = j; + + // exchange rows + if (r > j) + { + for (k = 1; k <= n; k++) + { + hr = m2.Get(j, k); + m2.Elem(j, k) = m2.Get(r, k); + m2.Elem(r, k) = hr; + } + hi = p.Get(j); + p.Elem(j) = p.Get(r); + p.Elem(r) = hi; + } + + + // transformation + + hr = 1 / m2.Get(j, j); + for (i = 1; i <= n; i++) + m2.Elem(i, j) *= hr; + m2.Elem(j, j) = hr; + + for (k = 1; k <= n; k++) + if (k != j) + { + for (i = 1; i <= n; i++) + if (i != j) + m2.Elem(i, k) -= m2.Elem(i, j) * m2.Elem(j, k); + m2.Elem(j, k) *= -hr; + } + } + + // col exchange + + for (i = 1; i <= n; i++) + { + for (k = 1; k <= n; k++) + hv.Elem(p.Get(k)) = m2.Get(i, k); + for (k = 1; k <= n; k++) + m2.Elem(i, k) = hv.Get(k); + } + + + + /* + if (m1.Symmetric()) + for (i = 1; i <= n; i++) + for (j = 1; j < i; j++) + m1.Elem(j, i) = m1.Get(i, j); + + m2 = 0; + + for (i = 1; i <= n; i++) + m2.Elem(i, i) = 1; + + for (i = 1; i <= n; i++) + { + // (*mycout) << '.' << flush; + q = m1.Get(i, i); + for (k = 1; k <= n; k++) + { + m1.Elem(i, k) /= q; + m2.Elem(i, k) /= q; + } + + for (j = i+1; j <= n; j++) + { + q = m1.Elem(j, i); + + double * m1pi = &m1.Elem(i, i); + double * m1pj = &m1.Elem(j, i); + + for (k = n; k >= i; --k, ++m1pi, ++m1pj) + *m1pj -= q * (*m1pi); + + double * m2pi = &m2.Elem(i, 1); + double * m2pj = &m2.Elem(j, 1); + + for (k = i; k > 0; --k, ++m2pi, ++m2pj) + *m2pj -= q * (*m2pi); + + // for (k = 1; k <= n; k++) + // { + // m1.Elem(j, k) -= q * m1.Elem(i, k); + // m2.Elem(j, k) -= q * m2.Elem(i, k); + // } + + } + } + + for (i = n; i >= 1; i--) + { + // (*mycout) << "+" << flush; + for (j = 1; j < i; j++) + { + q = m1.Elem(j, i); + + double * m2pi = &m2.Elem(i, 1); + double * m2pj = &m2.Elem(j, 1); + + for (k = n; k > 0; --k, ++m2pi, ++m2pj) + *m2pj -= q * (*m2pi); + + + // for (k = 1; k <= n; k++) + // { + // m1.Elem(j, k) -= q * m1.Elem(i, k); + // m2.Elem(j, k) -= q * m2.Elem(i, k); + // } + } + } + + if (m2.Symmetric()) + { + for (i = 1; i <= n; i++) + for (j = 1; j < i; j++) + m2.Elem(i, j) = m2.Elem(j, i); + } +*/ + } + } + + +void CalcAAt (const DenseMatrix & a, DenseMatrix & m2) + { + int n1 = a.Height(); + int n2 = a.Width(); + int i, j, k; + double sum; + const double *p, *q, *p0; + + if (m2.Height() != n1 || m2.Width() != n1) + { + (*myerr) << "CalcAAt: sizes don't fit" << endl; + return; + } + + for (i = 1; i <= n1; i++) + { + sum = 0; + p = &a.ConstElem(i, 1); + for (k = 1; k <= n2; k++) + { + sum += *p * *p; + p++; + } + m2.Set(i, i, sum); + + p0 = &a.ConstElem(i, 1); + q = a.data; + for (j = 1; j < i; j++) + { + sum = 0; + p = p0; + + for (k = 1; k <= n2; k++) + { + sum += *p * *q; + p++; + q++; + } + m2.Set(i, j, sum); + m2.Set(j, i, sum); + } + } + } + + + +#ifdef ABC +BaseMatrix * DenseMatrix :: InverseMatrix (const BitArray * /* inner */) const +{ + if (Height() != Width()) + { + (*myerr) << "BaseMatrix::InverseMatrix(): Matrix not symmetric" << endl; + return new DenseMatrix(1); + } + else + { + if (Symmetric()) + { + (*mycout) << "Invmat not available" << endl; + BaseMatrix * invmat = NULL; + return invmat; + } + + DenseMatrix * invmat = new DenseMatrix (Height()); + + CalcInverse (*this, *invmat); + return invmat; + } +} +#endif + + + +void CalcAtA (const DenseMatrix & a, DenseMatrix & m2) + { + int n1 = a.Height(); + int n2 = a.Width(); + int i, j, k; + double sum; + + if (m2.Height() != n2 || m2.Width() != n2) + { + (*myerr) << "CalcAtA: sizes don't fit" << endl; + return; + } + + for (i = 1; i <= n2; i++) + for (j = 1; j <= n2; j++) + { + sum = 0; + for (k = 1; k <= n1; k++) + sum += a.Get(k, i) * a.Get(k, j); + m2.Elem(i, j) = sum; + } + } + + + + + + +void CalcABt (const DenseMatrix & a, const DenseMatrix & b, DenseMatrix & m2) + { + int n1 = a.Height(); + int n2 = a.Width(); + int n3 = b.Height(); + int i, j, k; + double sum; + + if (m2.Height() != n1 || m2.Width() != n3 || b.Width() != n2) + { + (*myerr) << "CalcABt: sizes don't fit" << endl; + return; + } + + double * pm2 = &m2.Elem(1, 1); + const double * pa1 = &a.Get(1, 1); + + for (i = 1; i <= n1; i++) + { + const double * pb = &b.Get(1, 1); + for (j = 1; j <= n3; j++) + { + sum = 0; + const double * pa = pa1; + + for (k = 1; k <= n2; k++) + { + sum += *pa * *pb; + pa++; pb++; + } + + *pm2 = sum; + pm2++; + } + pa1 += n2; + } + } + + +void CalcAtB (const DenseMatrix & a, const DenseMatrix & b, DenseMatrix & m2) + { + int n1 = a.Height(); + int n2 = a.Width(); + int n3 = b.Width(); + int i, j, k; + + if (m2.Height() != n2 || m2.Width() != n3 || b.Height() != n1) + { + (*myerr) << "CalcAtB: sizes don't fit" << endl; + return; + } + + for (i = 1; i <= n2 * n3; i++) + m2.data[i-1] = 0; + + for (i = 1; i <= n1; i++) + for (j = 1; j <= n2; j++) + { + const double va = a.Get(i, j); + double * pm2 = &m2.Elem(j, 1); + const double * pb = &b.Get(i, 1); + + for (k = 1; k <= n3; ++k, ++pm2, ++pb) + *pm2 += va * *pb; + // for (k = 1; k <= n3; k++) + // m2.Elem(j, k) += va * b.Get(i, k); + } + /* + for (i = 1; i <= n2; i++) + for (j = 1; j <= n3; j++) + { + sum = 0; + for (k = 1; k <= n1; k++) + sum += a.Get(k, i) * b.Get(k, j); + m2.Elem(i, j) = sum; + } + */ + } + + + + + + + +DenseMatrix operator* (const DenseMatrix & m1, const DenseMatrix & m2) + { + DenseMatrix temp (m1.Height(), m2.Width()); + + if (m1.Width() != m2.Height()) + { + (*myerr) << "DenseMatrix :: operator*: Matrix Size does not fit" << endl; + } + else if (temp.Height() != m1.Height()) + { + (*myerr) << "DenseMatrix :: operator*: temp not allocated" << endl; + } + else + { + Mult (m1, m2, temp); + } + return temp; + } + + +void Mult (const DenseMatrix & m1, const DenseMatrix & m2, DenseMatrix & m3) + { + double sum; + double *p1, *p1s, *p1sn, *p1snn, *p2, *p2s, *p2sn, *p3; + + if (m1.Width() != m2.Height() || m1.Height() != m3.Height() || + m2.Width() != m3.Width() ) + { + (*myerr) << "DenseMatrix :: Mult: Matrix Size does not fit" << endl; + (*myerr) << "m1: " << m1.Height() << " x " << m1.Width() << endl; + (*myerr) << "m2: " << m2.Height() << " x " << m2.Width() << endl; + (*myerr) << "m3: " << m3.Height() << " x " << m3.Width() << endl; + return; + } + /* + else if (m1.Symmetric() || m2.Symmetric() || m3.Symmetric()) + { + (*myerr) << "DenseMatrix :: Mult: not implemented for symmetric matrices" << endl; + return; + } + */ + else + { + // int i, j, k; + int n1 = m1.Height(); + int n2 = m2.Width(); + int n3 = m1.Width(); + + /* + for (i = n1 * n2-1; i >= 0; --i) + m3.data[i] = 0; + + const double * pm1 = &m1.Get(1, 1); + for (i = 1; i <= n1; i++) + { + const double * pm2 = &m2.Get(1, 1); + double * pm3i = &m3.Elem(i, 1); + + for (j = 1; j <= n3; j++) + { + const double vm1 = *pm1; + ++pm1; + // const double vm1 = m1.Get(i, j); + double * pm3 = pm3i; + // const double * pm2 = &m2.Get(j, 1); + + for (k = 0; k < n2; k++) + { + *pm3 += vm1 * *pm2; + ++pm2; + ++pm3; + } + + // for (k = 1; k <= n2; k++) + // m3.Elem(i, k) += m1.Get(i, j) * m2.Get(j, k); + } + } + */ + + /* + for (i = 1; i <= n1; i++) + for (j = 1; j <= n2; j++) + { + sum = 0; + for (k = 1; k <= n3; k++) + sum += m1.Get(i, k) * m2.Get(k, j); + m3.Set(i, j, sum); + } + */ + + + /* + for (i = 1; i <= n1; i++) + { + const double pm1i = &m1.Get(i, 1); + const double pm2j = &m2.Get(1, 1); + + for (j = 1; j <= n2; j++) + { + double sum = 0; + const double * pm1 = pm1i; + const double * pm2 = pm2j; + pm2j++; + + for (k = 1; k <= n3; k++) + { + sum += *pm1 * *pm2; + ++pm1; + pm2 += n2; + } + + m3.Set (i, j, sum); + } + } + */ + + + p3 = m3.data; + p1s = m1.data; + p2sn = m2.data + n2; + p1snn = p1s + n1 * n3; + + while (p1s != p1snn) + { + p1sn = p1s + n3; + p2s = m2.data; + + while (p2s != p2sn) + { + sum = 0; + p1 = p1s; + p2 = p2s; + p2s++; + + while (p1 != p1sn) + { + sum += *p1 * *p2; + p1++; + p2 += n2; + } + *p3++ = sum; + } + p1s = p1sn; + } + } + } + + + +DenseMatrix operator+ (const DenseMatrix & m1, const DenseMatrix & m2) + { + DenseMatrix temp (m1.Height(), m1.Width()); + int i, j; + + if (m1.Width() != m2.Width() || m1.Height() != m2.Height()) + { + (*myerr) << "BaseMatrix :: operator+: Matrix Size does not fit" << endl; + } + else if (temp.Height() != m1.Height()) + { + (*myerr) << "BaseMatrix :: operator+: temp not allocated" << endl; + } + else + { + for (i = 1; i <= m1.Height(); i++) + for (j = 1; j <= m1.Width(); j++) + { + temp.Set(i, j, m1.Get(i, j) + m2.Get(i, j)); + } + } + return temp; + } + + + + +void Transpose (const DenseMatrix & m1, DenseMatrix & m2) +{ + int w = m1.Width(); + int h = m1.Height(); + int i, j; + + m2.SetSize (w, h); + + double * pm2 = &m2.Elem(1, 1); + for (j = 1; j <= w; j++) + { + const double * pm1 = &m1.Get(1, j); + for (i = 1; i <= h; i++) + { + *pm2 = *pm1; + pm2 ++; + pm1 += w; + } + } +} + + +/* +void DenseMatrix :: Mult (const Vector & v, Vector & prod) const + { + double sum, val; + const double * mp, * sp; + double * dp; + // const Vector & v = bv.CastToVector(); + // Vector & prod = bprod.CastToVector(); + + + int n = Height(); + int m = Width(); + + if (prod.Size() != n) + prod.SetSize (n); + +#ifdef DEVELOP + if (!n) + { + cout << "DenseMatrix::Mult mheight = 0" << endl; + } + if (!m) + { + cout << "DenseMatrix::Mult mwidth = 0" << endl; + } + + if (m != v.Size()) + { + (*myerr) << "\nMatrix and Vector don't fit" << endl; + } + else if (Height() != prod.Size()) + { + (*myerr) << "Base_Matrix::operator*(Vector): prod vector not ok" << endl; + } + else +#endif + { + if (Symmetric()) + { + int i, j; + + + for (i = 1; i <= n; i++) + { + sp = &v.Get(1); + dp = &prod.Elem(1); + mp = &Get(i, 1); + + val = v.Get(i); + sum = Get(i, i) * val; + + for (j = 1; j < i; ++j, ++mp, ++sp, ++dp) + { + sum += *mp * *sp; + *dp += val * *mp; + } + + prod.Elem(i) = sum; + } + } + else + { + mp = data; + dp = &prod.Elem(1); + for (int i = 1; i <= n; i++) + { + sum = 0; + sp = &v.Get(1); + + for (int j = 1; j <= m; j++) + { + // sum += Get(i,j) * v.Get(j); + sum += *mp * *sp; + mp++; + sp++; + } + + // prod.Set (i, sum); + *dp = sum; + dp++; + } + } + } + } +*/ + +void DenseMatrix :: MultTrans (const Vector & v, Vector & prod) const +{ + // const Vector & v = (const Vector&)bv; // .CastToVector(); + // Vector & prod = (Vector & )bprod; // .CastToVector(); + + /* + if (Height() != v.Size()) + { + (*myerr) << "\nMatrix and Vector don't fit" << endl; + } + else if (Width() != prod.Size()) + { + (*myerr) << "Base_Matrix::operator*(Vector): prod vector not ok" << endl; + } + else + */ + { + int i, j; + int w = Width(), h = Height(); + if (prod.Size() != w) + prod.SetSize (w); + + const double * pmat = &Get(1, 1); + const double * pv = &v.Get(1); + + prod = 0; + + for (i = 1; i <= h; i++) + { + double val = *pv; + ++pv; + + double * pprod = &prod.Elem(1); + + for (j = w-1; j >= 0; --j, ++pmat, ++pprod) + { + *pprod += val * *pmat; + } + } + + /* + double sum; + + for (i = 1; i <= Width(); i++) + { + sum = 0; + + for (int j = 1; j <= Height(); j++) + sum += Get(j, i) * v.Get(j); + + prod.Set (i, sum); + } + */ + } + } + + +void DenseMatrix :: Residuum (const Vector & x, const Vector & b, + Vector & res) const + { + double sum; + // const Vector & x = bx.CastToVector(); + // const Vector & b = bb.CastToVector(); + // Vector & res = bres.CastToVector(); + + res.SetSize (Height()); + + if (Width() != x.Size() || Height() != b.Size()) + { + (*myerr) << "\nMatrix and Vector don't fit" << endl; + } + else if (Height() != res.Size()) + { + (*myerr) << "Base_Matrix::operator*(Vector): prod vector not ok" << endl; + } + else + { + int i, j; + int h = Height(); + int w = Width(); + const double * mp = &Get(1, 1); + + for (i = 1; i <= h; i++) + { + sum = b.Get(i); + const double * xp = &x.Get(1); + + for (j = 1; j <= w; ++j, ++mp, ++xp) + sum -= *mp * *xp; + + res.Elem(i) = sum; + } + } + } + +#ifdef ABC +double DenseMatrix :: EvaluateBilinearform (const Vector & hx) const + { + double sum = 0, hsum; + // const Vector & hx = x.CastToVector(); + int i, j; + + if (Width() != hx.Size() || Height() != hx.Size()) + { + (*myerr) << "Matrix::EvaluateBilinearForm: sizes don't fit" << endl; + } + else + { + for (i = 1; i <= Height(); i++) + { + hsum = 0; + for (j = 1; j <= Height(); j++) + { + hsum += Get(i, j) * hx.Get(j); + } + sum += hsum * hx.Get(i); + } + } + +// testout << "sum = " << sum << endl; + return sum; + } + + +void DenseMatrix :: MultElementMatrix (const ARRAY<int> & pnum, + const Vector & hx, Vector & hy) + { + int i, j; + // const Vector & hx = x.CastToVector(); + // Vector & hy = y.CastToVector(); + + if (Symmetric()) + { + for (i = 1; i <= Height(); i++) + { + for (j = 1; j < i; j++) + { + hy.Elem(pnum.Get(i)) += Get(i, j) * hx.Get(pnum.Get(j)); + hy.Elem(pnum.Get(j)) += Get(i, j) * hx.Get(pnum.Get(i)); + } + hy.Elem(pnum.Get(j)) += Get(i, i) * hx.Get(pnum.Get(i)); + } + } + else + for (i = 1; i <= Height(); i++) + for (j = 1; j <= Width(); j++) + hy.Elem(pnum.Get(i)) += Get(i, j) * hx.Get(pnum.Get(j)); + + } + +void DenseMatrix :: MultTransElementMatrix (const ARRAY<int> & pnum, + const Vector & hx, Vector & hy) + { + int i, j; + // const Vector & hx = x.CastToVector(); + // Vector & hy = y.CastToVector(); + + if (Symmetric()) + MultElementMatrix (pnum, hx, hy); + else + for (i = 1; i <= Height(); i++) + for (j = 1; j <= Width(); j++) + hy.Elem(pnum.Get(i)) += Get(j, i) * hx.Get(pnum.Get(j)); + } +#endif + + +void DenseMatrix :: Solve (const Vector & v, Vector & sol) const +{ + DenseMatrix temp (*this); + temp.SolveDestroy (v, sol); +} + + +void DenseMatrix :: SolveDestroy (const Vector & v, Vector & sol) + { + double q; + + if (Width() != Height()) + { + (*myerr) << "SolveDestroy: Matrix not square"; + return; + } + if (Width() != v.Size()) + { + (*myerr) << "SolveDestroy: Matrix and Vector don't fit"; + return; + } + + sol = v; + if (Height() != sol.Size()) + { + (*myerr) << "SolveDestroy: Solution Vector not ok"; + return; + } + + + if (0 /* Symmetric() */) + { + + // Cholesky factorization + + int i, j, k, n; + n = Height(); + + // Cholesky + + double x; + Vector p(n); + + for (i = 1; i <= n; i++) + for (j = 1; j < i; j++) + Elem(j, i) = Get(i, j); + + for (i = 1; i <= n; i++) + { + // (*mycout) << "." << flush; + for (j = i; j <= n; j++) + { + x = Get(i, j); + + const double * pik = &Get(i, 1); + const double * pjk = &Get(j, 1); + + for (k = i-2; k >= 0; --k, ++pik, ++pjk) + x -= (*pik) * (*pjk); + + // for (k = i-1; k >= 1; --k) + // x -= Get(j, k) * Get(i, k); + + if (i == j) + { + if (x <= 0) + { + cerr << "Matrix indefinite" << endl; + return; + } + + p.Elem(i) = 1 / sqrt(x); + } + else + { + Elem(j, i) = x * p.Get(i); + } + } + } + + for (i = 1; i <= n; i++) + Elem(i, i) = 1 / p.Get(i); + + // A = L L^t + // L stored in left-lower triangle + + + sol = v; + + // Solve L sol = sol + + for (i = 1; i <= n; i++) + { + double val = sol.Get(i); + + const double * pij = &Get(i, 1); + const double * solj = &sol.Get(1); + + for (j = 1; j < i; j++, ++pij, ++solj) + val -= *pij * *solj; + // for (j = 1; j < i; j++) + // val -= Get(i, j) * sol.Get(j); + + sol.Elem(i) = val / Get(i, i); + } + + // Solve L^t sol = sol + + for (i = n; i >= 1; i--) + { + double val = sol.Get(i) / Get(i, i); + sol.Elem(i) = val; + + double * solj = &sol.Elem(1); + const double * pij = &Get(i, 1); + + for (j = 1; j < i; ++j, ++pij, ++solj) + *solj -= val * *pij; + // for (j = 1; j < i; j++) + // sol.Elem(j) -= Get(i, j) * val; + } + + + } + else + { + // (*mycout) << "gauss" << endl; + int i, j, k, n = Height(); + for (i = 1; i <= n; i++) + { + for (j = i+1; j <= n; j++) + { + q = Get(j,i) / Get(i,i); + if (q) + { + const double * pik = &Get(i, i+1); + double * pjk = &Elem(j, i+1); + + for (k = i+1; k <= n; ++k, ++pik, ++pjk) + *pjk -= q * *pik; + + // for (k = i+1; k <= Height(); k++) + // Elem(j, k) -= q * Get(i,k); + + + sol.Elem(j) -= q * sol.Get(i); + } + } + } + + for (i = n; i >= 1; i--) + { + q = sol.Get(i); + for (j = i+1; j <= n; j++) + q -= Get(i,j) * sol.Get(j); + + sol.Elem(i) = q / Get(i,i); + } + } + } + + +/* +BaseMatrix * DenseMatrix :: Copy () const + { + return new DenseMatrix (*this); + } +*/ + + + + +ostream & operator<< (ostream & ost, const DenseMatrix & m) +{ + for (int i = 0; i < m.Height(); i++) + { + for (int j = 0; j < m.Width(); j++) + ost << m.Get(i+1,j+1) << " "; + ost << endl; + } + return ost; +} + + + +} diff --git a/contrib/Netgen/libsrc/linalg/densemat.hpp b/contrib/Netgen/libsrc/linalg/densemat.hpp new file mode 100644 index 0000000000..fadb128d6a --- /dev/null +++ b/contrib/Netgen/libsrc/linalg/densemat.hpp @@ -0,0 +1,260 @@ +#ifndef FILE_DENSEMAT +#define FILE_DENSEMAT + +/**************************************************************************/ +/* File: densemat.hh */ +/* Author: Joachim Schoeberl */ +/* Date: 01. Oct. 94 */ +/**************************************************************************/ + +/** + Data type dense matrix +*/ + + +#include <assert.h> + +class DenseMatrix +{ +protected: + int height; + int width; + double * data; + +public: + /// + DenseMatrix (); + /// + DenseMatrix (int h, int w = 0); + /// + DenseMatrix (const DenseMatrix & m2); + /// + ~DenseMatrix (); + + /// + void SetSize (int h, int w = 0); + + int Height() const { return height; } + int Width() const { return width; } + + double & operator() (int i, int j) { return data[i*width+j]; } + double operator() (int i, int j) const { return data[i*width+j]; } + double & operator() (int i) { return data[i]; } + double operator() (int i) const { return data[i]; } + + /// + DenseMatrix & operator= (const DenseMatrix & m2); + /// + DenseMatrix & operator+= (const DenseMatrix & m2); + /// + DenseMatrix & operator-= (const DenseMatrix & m2); + + /// + DenseMatrix & operator= (double v); + /// + DenseMatrix & operator*= (double v); + + /// + void Mult (const FlatVector & v, FlatVector & prod) const + { + double sum; + const double * mp, * sp; + double * dp; + +#ifdef DEBUG + if (prod.Size() != height) + { + cerr << "Mult: wrong vector size " << endl; + assert (1); + // prod.SetSize (height); + } + + + if (!height) + { + cout << "DenseMatrix::Mult height = 0" << endl; + } + if (!width) + { + cout << "DenseMatrix::Mult width = 0" << endl; + } + + if (width != v.Size()) + { + (*myerr) << "\nMatrix and Vector don't fit" << endl; + } + else if (Height() != prod.Size()) + { + (*myerr) << "Base_Matrix::operator*(Vector): prod vector not ok" << endl; + } + else +#endif + { + mp = data; + dp = &prod.Elem(1); + for (int i = 1; i <= height; i++) + { + sum = 0; + sp = &v.Get(1); + + for (INDEX j = 1; j <= width; j++) + { + // sum += Get(i,j) * v.Get(j); + sum += *mp * *sp; + mp++; + sp++; + } + + *dp = sum; + dp++; + } + } + } + + /// + void MultTrans (const Vector & v, Vector & prod) const; + /// + void Residuum (const Vector & x, const Vector & b, Vector & res) const; + /// + double Det () const; + + /// + friend DenseMatrix operator* (const DenseMatrix & m1, const DenseMatrix & m2); + /// + friend DenseMatrix operator+ (const DenseMatrix & m1, const DenseMatrix & m2); + + /// + friend void Transpose (const DenseMatrix & m1, DenseMatrix & m2); + /// + friend void Mult (const DenseMatrix & m1, const DenseMatrix & m2, DenseMatrix & m3); + /// + friend void CalcInverse (const DenseMatrix & m1, DenseMatrix & m2); + /// + friend void CalcAAt (const DenseMatrix & a, DenseMatrix & m2); + /// + friend void CalcAtA (const DenseMatrix & a, DenseMatrix & m2); + /// + friend void CalcABt (const DenseMatrix & a, const DenseMatrix & b, DenseMatrix & m2); + /// + friend void CalcAtB (const DenseMatrix & a, const DenseMatrix & b, DenseMatrix & m2); + /// + void Solve (const Vector & b, Vector & x) const; + /// + void SolveDestroy (const Vector & b, Vector & x); + /// + const double & Get(INDEX i, INDEX j) const { return data[(i-1)*width+j-1]; } + /// + const double & Get(INDEX i) const { return data[i-1]; } + /// + void Set(INDEX i, INDEX j, double v) { data[(i-1)*width+j-1] = v; } + /// + double & Elem(INDEX i, INDEX j) { return data[(i-1)*width+j-1]; } + /// + const double & ConstElem(INDEX i, INDEX j) const { return data[(i-1)*width+j-1]; } +}; + + +extern ostream & operator<< (ostream & ost, const DenseMatrix & m); + + + +template <int WIDTH> +class MatrixFixWidth +{ +protected: + int height; + double * data; + +public: + /// + MatrixFixWidth () + { height = 0; data = 0; } + /// + MatrixFixWidth (int h) + { height = h; data = new double[WIDTH*height]; } + /// + ~MatrixFixWidth () + { delete [] data; } + + void SetSize (int h) + { + if (h != height) + { + delete data; + height = h; + data = new double[WIDTH*height]; + } + } + + /// + int Height() const { return height; } + + /// + int Width() const { return WIDTH; } + + /// + 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]; } + + + + const double & Get(int i, int j) const { return data[(i-1)*WIDTH+j-1]; } + /// + const double & Get(int i) const { return data[i-1]; } + /// + void Set(int i, int j, double v) { data[(i-1)*WIDTH+j-1] = v; } + /// + double & Elem(int i, int j) { return data[(i-1)*WIDTH+j-1]; } + /// + const double & ConstElem(int i, int j) const { return data[(i-1)*WIDTH+j-1]; } +}; + + + + + +#endif diff --git a/contrib/Netgen/libsrc/linalg/linalg.hpp b/contrib/Netgen/libsrc/linalg/linalg.hpp new file mode 100644 index 0000000000..4599fad48d --- /dev/null +++ b/contrib/Netgen/libsrc/linalg/linalg.hpp @@ -0,0 +1,35 @@ +#ifndef FILE_LINALG +#define FILE_LINALG + +/* *************************************************************************/ +/* File: linalg.hpp */ +/* Author: Joachim Schoeberl */ +/* Date: 01. Oct. 94 */ +/* *************************************************************************/ + +/* + + Data types for basic linear algebra + more data types are found in linalgl.hpp + + The basic concepts include the data types + + Vector + SparseMatrix + DenseMatrix + +*/ + + +#include <myadt.hpp> +namespace netgen +{ +#include "vector.hpp" + // #include "basemat.hpp" +#include "densemat.hpp" + // #include "sparsmat.hpp" +#include "polynomial.hpp" +} +#endif + + diff --git a/contrib/Netgen/libsrc/linalg/polynomial.cpp b/contrib/Netgen/libsrc/linalg/polynomial.cpp new file mode 100644 index 0000000000..964dab9674 --- /dev/null +++ b/contrib/Netgen/libsrc/linalg/polynomial.cpp @@ -0,0 +1,216 @@ +#include <mystdlib.h> +#include <linalg.hpp> + +namespace netgen +{ + +QuadraticPolynomial1V :: +QuadraticPolynomial1V (double ac, double acx, double acxx) +{ + c = ac; + cx = acx; + cxx = acxx; +} + +double QuadraticPolynomial1V :: +Value (double x) +{ + return c + cx * x + cxx * x * x; +} + +double QuadraticPolynomial1V :: MaxUnitInterval () +{ + // inner max + if (cxx < 0 && cx > 0 && cx < -2 * cxx) + { + return c - 0.25 * cx * cx / cxx; + } + + + if (cx + cxx > 0) // right edge + return c + cx + cxx; + + // left end + return c; +} + + + + +LinearPolynomial2V :: +LinearPolynomial2V (double ac, double acx, double acy) +{ + c = ac; + cx = acx; + cy = acy; +} + + +QuadraticPolynomial2V :: +QuadraticPolynomial2V () +{ + ; +} + + +QuadraticPolynomial2V :: +QuadraticPolynomial2V (double ac, double acx, double acy, + double acxx, double acxy, double acyy) +{ + c = ac; + cx = acx; + cy = acy; + cxx = acxx; + cxy = acxy; + cyy = acyy; +} + +void QuadraticPolynomial2V :: +Square (const LinearPolynomial2V & lp) +{ + c = lp.c * lp.c; + cx = 2 * lp.c * lp.cx; + cy = 2 * lp.c * lp.cy; + + cxx = lp.cx * lp.cx; + cxy = 2 * lp.cx * lp.cy; + cyy = lp.cy * lp.cy; +} + +void QuadraticPolynomial2V :: +Add (double lam, const QuadraticPolynomial2V & qp2) +{ + c += lam * qp2.c; + cx += lam * qp2.cx; + cy += lam * qp2.cy; + cxx += lam * qp2.cxx; + cxy += lam * qp2.cxy; + cyy += lam * qp2.cyy; +} + +double QuadraticPolynomial2V :: +Value (double x, double y) +{ + return c + cx * x + cy * y + cxx * x * x + cxy * x * y + cyy * y * y; +} + +/* +double QuadraticPolynomial2V :: +MinUnitSquare () +{ + double x, y; + double minv = 1e8; + double val; + for (x = 0; x <= 1; x += 0.1) + for (y = 0; y <= 1; y += 0.1) + { + val = Value (x, y); + if (val < minv) + minv = val; + } + return minv; +}; +*/ + +double QuadraticPolynomial2V :: +MaxUnitSquare () +{ + // find critical point + + double maxv = c; + double hv; + + double det, x0, y0; + det = 4 * cxx * cyy - cxy * cxy; + + if (det > 0) + { + // definite surface + + x0 = (-2 * cyy * cx + cxy * cy) / det; + y0 = (cxy * cx -2 * cxx * cy) / det; + + if (x0 >= 0 && x0 <= 1 && y0 >= 0 && y0 <= 1) + { + hv = Value (x0, y0); + if (hv > maxv) maxv = hv; + } + } + + QuadraticPolynomial1V e1(c, cx, cxx); + QuadraticPolynomial1V e2(c, cy, cyy); + QuadraticPolynomial1V e3(c+cy+cyy, cx+cxy, cxx); + QuadraticPolynomial1V e4(c+cx+cxx, cy+cxy, cyy); + + hv = e1.MaxUnitInterval(); + if (hv > maxv) maxv = hv; + hv = e2.MaxUnitInterval(); + if (hv > maxv) maxv = hv; + hv = e3.MaxUnitInterval(); + if (hv > maxv) maxv = hv; + hv = e4.MaxUnitInterval(); + if (hv > maxv) maxv = hv; + + return maxv; + + // (*testout) << "maxv = " << maxv << " =~= "; + + /* + double x, y; + maxv = -1e8; + double val; + for (x = 0; x <= 1.01; x += 0.1) + for (y = 0; y <= 1.01; y += 0.1) + { + val = Value (x, y); + if (val > maxv) + maxv = val; + } + + // (*testout) << maxv << endl; + return maxv; + */ +} + + + + +double QuadraticPolynomial2V :: +MaxUnitTriangle () +{ + // find critical point + + double maxv = c; + double hv; + + double det, x0, y0; + det = 4 * cxx * cyy - cxy * cxy; + + if (cxx < 0 && det > 0) + { + // definite surface + + x0 = (-2 * cyy * cx + cxy * cy) / det; + y0 = (cxy * cx -2 * cxx * cy) / det; + + if (x0 >= 0 && y0 >= 0 && x0+y0 <= 1) + { + return Value (x0, y0); + } + } + + + QuadraticPolynomial1V e1(c, cx, cxx); + QuadraticPolynomial1V e2(c, cy, cyy); + QuadraticPolynomial1V e3(c+cy+cyy, cx-cy+cxy-2*cyy, cxx-cxy+cyy); + + hv = e1.MaxUnitInterval(); + if (hv > maxv) maxv = hv; + hv = e2.MaxUnitInterval(); + if (hv > maxv) maxv = hv; + hv = e3.MaxUnitInterval(); + if (hv > maxv) maxv = hv; + + return maxv; +} +} diff --git a/contrib/Netgen/libsrc/linalg/polynomial.hpp b/contrib/Netgen/libsrc/linalg/polynomial.hpp new file mode 100644 index 0000000000..3108d4dd72 --- /dev/null +++ b/contrib/Netgen/libsrc/linalg/polynomial.hpp @@ -0,0 +1,45 @@ +#ifndef FILE_POLYNOMIAL +#define FILE_POLYNOMIAL + +/* *************************************************************************/ +/* File: polynomial.hh */ +/* Author: Joachim Schoeberl */ +/* Date: 25. Nov. 99 */ +/* *************************************************************************/ + + +class QuadraticPolynomial1V +{ + double c, cx, cxx; +public: + QuadraticPolynomial1V (double ac, double acx, double acxx); + double Value (double x); + double MaxUnitInterval (); +}; + +class LinearPolynomial2V +{ + double c, cx, cy; +public: + LinearPolynomial2V (double ac, double acx, double acy); + friend class QuadraticPolynomial2V; +}; + + +class QuadraticPolynomial2V +{ + double c, cx, cy, cxx, cxy, cyy; +public: + QuadraticPolynomial2V (); + QuadraticPolynomial2V (double ac, double acx, double acy, + double acxx, double acxy, double acyy); + void Square (const LinearPolynomial2V & lp); + void Add (double lam, const QuadraticPolynomial2V & qp); + + double Value (double x, double y); + // double MinUnitSquare (); + double MaxUnitSquare (); + double MaxUnitTriangle (); +}; + +#endif diff --git a/contrib/Netgen/libsrc/linalg/sparsmat.cpp b/contrib/Netgen/libsrc/linalg/sparsmat.cpp new file mode 100644 index 0000000000..f3249f82e6 --- /dev/null +++ b/contrib/Netgen/libsrc/linalg/sparsmat.cpp @@ -0,0 +1,1707 @@ +//#include <algorithm> +#ifdef ABC + +#include <mystdlib.h> + +#include <linalg.hpp> + + +namespace netgen +{ +MatrixGraph :: MatrixGraph (int size, int aincrement) +{ + int i; + increment = aincrement; + + lines.SetSize (size); + for (i = 1;i <= size; i++) + { + lines.Elem(i).allocsize = increment; + lines.Elem(i).size = 1; + lines.Elem(i).diag = 1; + lines.Elem(i).col = new INDEX[increment]; + lines.Elem(i).col[0] = i; + } +} + +MatrixGraph :: MatrixGraph (const ARRAY<int> & linesize) +{ + INDEX i; + INDEX n = linesize.Size(); + INDEX sum = 0; + INDEX * cola; + + lines.SetSize (n); + increment = 0; + + for (i = 1; i <= n; i++) + sum += linesize.Get(i); + + cola = new INDEX[sum]; + + sum = 0; + for (i = 1; i <= n; i++) + { + lines.Elem(i).allocsize=linesize.Get(i); + lines.Elem(i).size = 1; + lines.Elem(i).diag = 1; + lines.Elem(i).col = &cola[sum]; + cola[sum] = i; + sum += linesize.Get(i); + } +} + +int MatrixGraph :: GetPosition (INDEX i, INDEX j) const +{ + int k; + + INDEX * ip = lines.Get(i).col; + INDEX n = lines.Get(i).size; + for (k = 1; k <= n; k++, ip++) + { + if (j == *ip) return k; + } + + return 0; + + /* + // quick search: + + const INDEX * ip = lines.Get(i).col; + int max = lines.Get(i).size; + + int l = 0, k = 1, newind; + + while (k < max) + k <<= 1; + + while (k > 0) + { + k >>= 1; + newind = k+l; + if (newind >= max) continue; + if (ip[newind] <= j) + l += k; + } + + if (l < max && ip[l] == j) + return l+1; + + return 0; + */ +} + + + +int MatrixGraph :: CreatePosition (INDEX i, INDEX j) + { + int k; + MatrixGraph::linestruct * lin = &lines.Elem(i); + + + + for (k = 1; k <= lin->size; k++) + { + if (lin->col[k-1] == j) + return 0; + if (lin->col[k-1] > j) + break; + } + + // k ... position to enter new element + + if (lin->size == lin->allocsize) + { + INDEX * tmpcol = new INDEX[lin->size + increment]; + memcpy (tmpcol, lin->col, sizeof(INDEX) * lin->size); + delete lin->col; + lin->col = tmpcol; + lin->allocsize+=increment; + } + + if (k <= lin->size) + memmove (&lin->col[k], &lin->col[k-1], + sizeof(INDEX) * (lin->size + 1 - k)); + + lin->col[k-1] = j; + lin->size++; + if (j < i) lin->diag++; + + return 1; + } + + + +double & SparseMatrix :: operator() (INDEX i, INDEX j) +{ + if (i >= 1 && i <= height && j >= 1 && j <= width) + return Elem(i, j); + else + { + (*myerr) << "SparseMatirx::operator(): out of range" << endl; + return shit; + } +} + +double SparseMatrix :: operator() (INDEX i, INDEX j) const +{ + if (i >= 1 && i <= height && j >= 1 && j <= width) + return Get(i, j); + else + { + (*myerr) << "SparseMatirx::operator(): out of range" << endl; + return shit; + } +} + + + + + + +SparseMatrix :: SparseMatrix (INDEX h, INDEX w) + : BaseMatrix (h, w) +{ + ; +} + + + + +void SparseMatrix :: Mult (const Vector & v, Vector & prod) const + { + double sum, vi; + INDEX i, j, n; + + const INDEX * col; + const double * valp; + + // const Vector & v = bv.CastToVector(); + // Vector & prod = bprod.CastToVector(); + + prod.SetSize (Height()); + + /* + if (prod.Size() != Height() || v.Size() != Width()) + { + (*myerr) << "SparseMatrix::Mult: Dimensions don't fit" << endl; + return; + } + */ + + if (!Symmetric()) + { + n = Height(); + INDEX w = Width(); + + /* + const MatrixGraph::linestruct * linep = &graph->lines.Get(1); + + for (i = 1; i <= n; i++) + { + sum = 0; + col = linep->col; + valp = data.Get(i); + + for (j = 0; j < linep->size; j++, valp++, col++) + sum += *valp * v.Get(*col); + + linep++; + prod.Set (i, sum); + } + */ + + const MatrixGraph::linestruct * linep = &graph->lines.Get(1); + const double * vp = &v.Get(1); + vp--; + + for (i = 1; i <= n; i++) + { + sum = 0; + col = linep->col; + valp = data.Get(i); + const int ls = linep->size; + + if (i <= w) + for (j = 0; j < ls; j++) + sum += valp[j] * vp[col[j]]; + else + // decrement one, because of diagonal element outside + for (j = 0; j < ls-1; j++) + sum += valp[j] * vp[col[j]]; + + + linep++; + prod.Elem(i) = sum; + } + + } + else + { + prod = 0; + n = Height(); + + const MatrixGraph::linestruct * linep = &graph->lines.Get(1); + + for (i = 1; i <= n; i++) + { + sum = 0; + // col = graph->lines.Get(i).col; + col = linep->col; + valp = data.Get(i); + vi = v.Get(i); + + for (j = linep->diag-1; j > 0; j--, col++, valp++) + { + sum += (*valp) * v.Get(*col); + prod.Elem(*col) += (*valp) * vi; + } + + linep++; + sum += (*valp) * v.Get(*col); + prod.Elem(i) += sum; + } + } + } + +void SparseMatrix :: MultTrans (const Vector & v, Vector & prod) const + { + INDEX i, j, n, coln; + // const Vector & v = bv.CastToVector(); + // Vector & prod = bprod.CastToVector(); + const INDEX * col; + const double * valp; + double val; + + prod.SetSize (Width()); + + if (prod.Size() != Width() || v.Size() != Height()) + { + (*myerr) << "SparseMatrix::Mult: Dimensions don't fit" << endl; + return; + } + + if (!Symmetric()) + { + n = Height(); + prod = 0; + + for (i = 1; i <= n; i++) + { + col = graph->lines.Get(i).col; + valp = data.Get(i); + coln = graph->lines.Get(i).size; + val = v.Get(i); + + // lin = &lins.Get(i); + // col = lin->col; + // val = v.Get(i); + + for (j = 1; j <= coln; j++, col++, valp++) + prod.Elem(*col) += (*valp) * val; + } + } + else + { + Mult (v, prod); + } + } + + + + +void SparseMatrix :: Residuum (const Vector & bx, const Vector & bb, + Vector & bres) const + { + BaseMatrix :: Residuum (bx, bb, bres); + /* + double sum, xi; + INDEX i, j, n; + colstruct * col; + const linestruct * lin; + const Vector & x = bx.CastToVector(); + const Vector & b = bb.CastToVector(); + Vector & res = bres.CastToVector(); + + res.SetSize (b.Size()); + + if (res.Size() != b.Size() || b.Size() != Height() || + x.Size() != Width()) + { + (*myerr) << "SparseMatrix::Residuum: Dimensions don't fit" << endl; + return; + } + + n = Height(); + if (!Symmetric()) + { + for (i = 1; i <= Height(); i++) + { + lin = &lins.Get(i); + sum = b.Get(i); + col = lin->col; + + for (j = lin->size; j > 0; j--, col++) + sum -= col->data * x.Get(col->colnr); + + res.Set (i, sum); + } + } + else + { + res = b; + for (i = 1; i <= n; i++) + { + lin = &lins.Get(i); + sum = 0; + col = lin->col; + xi = x.Get(i); + + for (j = lin->size; j > 0; j--, col++) + { + sum -= col->data * x.Get(col->colnr); + if (col->colnr != i) + res.Elem(col->colnr) -= col->data * xi; + } + + res.Elem(i) += sum; + } + } + */ + } + + +void SparseMatrix :: ResiduumTrans (const Vector & /* bx */, + const Vector & /* bb */, + Vector & /* bres */) const + { + cerr << "SparseMastrix :: Residuumtrans called, but not implemented" << endl; + + /* + INDEX i, j, n; + colstruct * col; + const linestruct * lin; + const Vector & x = bx.CastToVector(); + const Vector & b = bb.CastToVector(); + Vector & res = bres.CastToVector(); + + + res.SetSize (Width()); + + if (res.Size() != b.Size() || b.Size() != Width() || + x.Size() != Height()) + { + (*myerr) << "SparseMatrix::ResiduumTrans: Dimensions don't fit" << endl; + return; + } + + if (!Symmetric()) + { + n = Height(); + + res = b; + + for (i = 1; i <= n; i++) + { + lin = &lins.Get(i); + col = lin->col; + + for (j = lin->size; j > 0; j--, col++) + res.Elem(col->colnr) -= col->data * x.Get(i); + } + } + else + { + Residuum (bx, bb, bres); + } + */ + } + + + +ostream & SparseMatrix :: Print (ostream & s) const + { + INDEX i, j; + + if (Symmetric()) s << "Lower half of matrix:" << endl; + + for (i = 1; i <= Height(); i++) + { + s << "Line " << i << " "; + + if (Symmetric()) + { + for (j = 1 ; j <= GetDiagPos (i); j++) + s << "(" << GetColIndex (i, j) << ": " << GetData (i, j) << ") "; + } + else + { + for (j = 1 ; j <= ElementsInLine (i); j++) + s << "(" << GetColIndex (i, j) << ": " << GetData (i, j) << ") "; + } + + s << endl; + } + return s; + } + + + + + + +void SparseMatrix :: AddElementMatrix (const ARRAY<INDEX> & pnum, + const BaseMatrix & elemmat) +{ + int i, j, i1, i2, n; + + n = pnum.Size(); + static ARRAY<int> spnum, map; + spnum.SetSize (n); + map.SetSize (n); + + for (i = 1; i <= n; i++) + spnum.Elem(i) = pnum.Get(i); + + for (i = 1; i <= n; i++) + for (j = 1; j <= n-1; j++) + if (spnum.Elem(j) > spnum.Elem(j+1)) + swap (spnum.Elem(j), spnum.Elem(j+1)); + + for (i = 1; i <= n; i++) + for (j = 1; j <= n; j++) + if (pnum.Get(i) == spnum.Get(j)) + map.Elem(j) = i; + + + const DenseMatrix & delemmat = (const DenseMatrix&)elemmat; + if (Symmetric()) + { + for (i1 = 1; i1 <= n; i1++) + { + INDEX ii1 = spnum.Get(i1); + const INDEX * coli = graph->lines.Get(ii1).col; + double * val = data.Get(ii1); + int ncol = graph->lines.Get(ii1).size; + + int hi = 0; + for (i2 = 1; i2 <= i1; i2++) + { + while (coli[hi] < spnum.Get(i2)) + hi++; + val[hi] += delemmat.Get(map.Get(i1), map.Get(i2)); + } + } + + /* + for (i1 = 1; i1 <= pnum.Size(); i1++) + for (i2 = 1; i2 <= i1; i2++) + Elem(pnum.Get(i1), pnum.Get(i2)) += delemmat.Get(i1, i2); + */ + } + else + { + for (i1 = 1; i1 <= n; i1++) + { + INDEX ii1 = spnum.Get(i1); + const INDEX * coli = graph->lines.Get(ii1).col; + double * val = data.Get(ii1); + int ncol = graph->lines.Get(ii1).size; + + int hi = 0; + for (i2 = 1; i2 <= n; i2++) + { + while (coli[hi] < spnum.Get(i2)) + hi++; + val[hi] += delemmat.Get(map.Get(i1), map.Get(i2)); + } + } + + /* + for (i1 = 1; i1 <= pnum.Size(); i1++) + for (i2 = 1; i2 <= pnum.Size(); i2++) + Elem(pnum.Get(i1), pnum.Get(i2)) += delemmat.Get(i1, i2); + */ + } +} + + + + +double SparseMatrix :: RowTimesVector (INDEX i, const Vector & v) const + { + const double * valp; + const INDEX * col; + int coln; + double sum; + int j; + + /* + if (Width() > v.Size()) + { + cerr << "SparseMatrix::RowTimesVector: Size doesn't fit" << endl; + return 0; + } + */ + + col = graph->lines.Get(i).col; + valp = data.Get(i); + sum = 0; + coln = Symmetric() ? graph->lines.Get(i).diag : graph->lines.Get(i).size; + + for (j = 1; j <= coln; ++j, ++col, ++valp) + sum += (*valp) * v.Get(*col); + + return sum; + + /* + col = graph->lines.Get(i).col; + valp = data.Get(i); + coln = graph->lines.Get(i).size; + val = v.Get(i); + + // lin = &lins.Get(i); + // col = lin->col; + // val = v.Get(i); + + for (j = 1; j <= coln; j++, col++, valp++) + prod.Elem(*col) += (*valp) * val; + */ + + + } + + + +void SparseMatrix :: AddRowToVector (INDEX i, double s, Vector & v) const +{ + const double * valp; + const INDEX * col; + double * vp; + int coln, j; + +#ifdef debug + if (Width() > v.Size()) + { + cerr << "SparseMatrix::AddRowToVector: Size doesn't fit" + << "w = " << Width() << " len = " << v.Size() << endl; + return; + } +#endif + + vp = &v.Elem(1) - 1; + valp = data.Get(i); + col = graph->lines.Get(i).col; + coln = Symmetric() ? graph->lines.Get(i).diag : graph->lines.Get(i).size; + + // for (j = 0; j < coln; j++) + // vp[col[j]] += s * valp[j]; + + for (j = coln-1; j >= 0; --j, ++valp, ++col) + vp[*col] += s * (*valp); +} + + + + + + +char SparseMatrix :: Used (INDEX i, INDEX j) const + { + return (graph->GetPosition(i, j) != 0); + } + + + +double SparseMatrix :: Get(INDEX i, INDEX j) const + { + if (Symmetric() && (j > i)) swap (i, j); + + int pos = graph->GetPosition(i, j); + if (pos) + return data.Get(i)[pos-1]; + else + return 0; + } + + +/* + quick search: + + const colstruct * col = lins.Get(i).col; + INDEX max = lins.Get(i).size; + + int l = 0, k = 1, newind; + + while (k < max) + k <<= 1; + + + while (k > 0) + { + k >>= 1; + newind = k+l; + if (newind >= max) continue; + if (col[newind].colnr <= j) + l += k; + } + + if (l < max && col[l].colnr == j) return col[l].data; + + return 0; + */ + + + +void SparseMatrix :: Set(INDEX i, INDEX j, double v) + { + Elem (i, j) = v; + } + + + +double & SparseMatrix :: Elem(INDEX i, INDEX j) + { + if (Symmetric() && j > i) swap (i, j); + + int pos = graph->GetPosition (i, j); + if (!pos) + { + CreatePosition (i, j); + pos = graph->GetPosition (i, j); + } + + return data.Elem(i)[pos-1]; + } + + + + + + + + +SparseMatrixFlex :: SparseMatrixFlex (INDEX h, INDEX w) + : SparseMatrix (h, w) +{ + INDEX i; + graph = + mygraph = new MatrixGraph (h); + + data.SetSize (h); + for (i = 1; i <= graph->Size(); i++) + { + data.Elem(i) = new double[graph->lines.Get(i).allocsize]; + data.Elem(i)[0] = 0; + } +} + +SparseMatrixFlex :: ~SparseMatrixFlex () +{ + ; +} + + +void SparseMatrixFlex :: SetSize (INDEX /* h */, INDEX /* w */) +{ + cerr << "SparseMatrixFlex :: SetSize() not implemented" << endl; +} + +void SparseMatrixFlex :: SetSymmetric (int sym) +{ + BaseMatrix::SetSymmetric (sym); +} + +void SparseMatrixFlex :: ChangeSize (INDEX /* h */, INDEX /* w */) +{ + cerr << "SparseMatrixFlex :: ChangeSize() not implemented" << endl; +} + + +void SparseMatrixFlex :: DeleteElements () +{ + ; +} + +BaseMatrix * SparseMatrixFlex :: Copy () const +{ + return (SparseMatrixFlex*)this; +} + + +int SparseMatrixFlex :: CreatePosition (INDEX i, INDEX j) +{ + int oldlinesize = graph->lines.Get(i).allocsize; + if (mygraph->CreatePosition(i, j)) + { + int newlinesize = graph->lines.Get(i).allocsize; + if (oldlinesize != newlinesize) + { + double * hdp = new double[newlinesize]; + memcpy (hdp, data.Elem(i), sizeof(double) * oldlinesize); + delete data.Elem(i); + data.Elem(i) = hdp; + } + + int pos = graph->GetPosition (i, j); + int size = graph->lines.Get(i).size; + + memmove (&data.Elem(i)[pos], &data.Elem(i)[pos-1], + sizeof(double) * (size-pos)); + data.Elem(i)[pos-1] = 0; + } + + return 0; +} + + + + +SparseMatrixFix :: SparseMatrixFix (const MatrixGraph & agraph, + int asymmetric) + : SparseMatrix (agraph.Size()) +{ + graph = &agraph; + SetSymmetric (asymmetric); + + data.SetSize (graph->Size()); + + int i, nne; + double * block; + + nne = 0; + for (i = 1; i <= graph->Size(); i++) + { + if (Symmetric()) + nne += graph->lines.Get(i).diag; + else + nne += graph->lines.Get(i).size; + } + + block = new double[nne]; + + for (i = 0; i < nne; i++) + block[i] = 0; + + nne = 0; + for (i = 1; i <= graph->Size(); i++) + { + data.Elem(i) = &block[nne]; + if (Symmetric()) + nne += graph->lines.Get(i).diag; + else + nne += graph->lines.Get(i).size; + } + +} + + +SparseMatrixFix :: ~SparseMatrixFix () +{ + ; +} + +int SparseMatrixFix :: CreatePosition (INDEX i, INDEX j) +{ + (*myerr) << "SparseMatrixFix cannot change graph, requested: " + << i << "-" << j << endl; + return 0; +} + +#ifdef nothing + + +SparseMatrix :: SparseMatrix () : BaseMatrix (), lins() + { + }; + +SparseMatrix :: SparseMatrix (INDEX h, INDEX w) : BaseMatrix (h, w), lins (h) + { + if (!w) w = h; + + for (INDEX i = 1; i <= h; i++) + { + lins[i].size = 0; + lins[i].maxsize = 0; + lins[i].col = NULL; + } + } + +SparseMatrix :: SparseMatrix (const SparseMatrix & m2) : BaseMatrix(), lins() + { + (*this) = m2; + } + + +SparseMatrix :: ~SparseMatrix () + { + DeleteElements (); + } + + + +void SparseMatrix :: SetSize (INDEX h, INDEX w) + { + if (!w) w = h; + DeleteElements (); + + if (height == h && width == w) return; + + height = h; + width = w; + lins.SetSize (height); + + if (lins.Size () == height) + { + for (INDEX i = 1; i <= h; i++) + { + lins[i].size = 0; + lins[i].maxsize = 0; + lins[i].col = NULL; + } + } + else + { + height = width = 0; + (*myerr) << "SparseMatrix::SetSize: Out of memory" << endl; + } + } + + +void SparseMatrix :: ChangeSize (INDEX h, INDEX w) + { + INDEX i; + + if (!w) w = h; + if (height == h && width == w) return; + + lins.SetSize (h); + + if (lins.Size () == h) + { + for (i = height+1; i <= h; i++) + { + lins[i].size = 0; + lins[i].maxsize = 0; + lins[i].col = NULL; + } + for (i = h+1; i <= height; i++) + { + if (lins[i].col) + { + DeleteColStruct (lins[i].col, lins[i].maxsize); + + lins[i].col = NULL; + lins[i].size = 0; + lins[i].maxsize = 0; + } + } + + height = h; + width = w; + } + else + { + height = width = 0; + (*myerr) << "SparseMatrix::SetSize: Out of memory" << endl; + } + } + + +void SparseMatrix :: SetSymmetric (int sym) + { + INDEX i, j; + int nr; + + if (sym != Symmetric()) + { + BaseMatrix :: SetSymmetric (sym); + + if (!sym) + { + for (i = 1; i <= Height(); i++) + for (nr = 1; nr <= ElementsInLine (i); nr++) + { + j = GetIndex (i, nr); + if (j < i) + Elem (j, i) = GetData (i, nr); + } + } + else + { + DeleteElements(); + } + } + } + + +void SparseMatrix :: DeleteElements () + { + for (INDEX i = 1; i <= lins.Size(); i++) + { + if (lins[i].col) + { + DeleteColStruct (lins[i].col, lins[i].maxsize); + + lins[i].col = NULL; + lins[i].size = 0; + lins[i].maxsize = 0; + } + } + } + + + +double & SparseMatrix::operator() (INDEX i, INDEX j) +{ + if (i >= 1 && j >= 1 && i <= height && j <= width) + { + return Elem(i, j); + } + else (*myerr) << "\nindex (" << i << "," << j << ") out of range (1.." + << height << ",1.." << width << ")\n"; + return shit; +} + +double SparseMatrix::operator() (INDEX i, INDEX j) const +{ + if (i >= 1 && j >= 1 && i <= height && j <= width) + { + return Get(i, j); + } + else (*myerr) << "\nindex (" << i << "," << j << ") out of range (1.." + << height << ",1.." << width << ")\n"; + return 0; +} + +SparseMatrix & SparseMatrix :: operator= (const SparseMatrix & m2) + { + INDEX i, j; + + SetSize (m2.Height(), m2.Width()); + SetSymmetric (m2.Symmetric()); + + for (i = 1; i <= m2.Height(); i++) + for (j = 1; j <= m2.ElementsInLine(i); j++) + (*this).Elem(i, m2.GetIndex(i, j)) = m2.GetData(i, j); + return *this; + } + + +SparseMatrix & SparseMatrix :: operator*= (double v) + { + INDEX i, j; + + for (i = 1; i <= Height(); i++) + for (j = 1; j <= ElementsInLine(i); j++) + GetDataRef(i, j) *= v; + return *this; + } + + + +char SparseMatrix :: Used (INDEX i, INDEX j) const + { + if (Symmetric() && j > i) swap (i, j); + + if (i < 1 || i > height) return 0; + + const colstruct * col = lins.Get(i).col; + INDEX max = lins.Get(i).size; + + for (int k = 0; k < max; k++, col++) + if (col->colnr == j) return 1; + + return 0; + } + + + +double SparseMatrix :: Get(INDEX i, INDEX j) const + { + if (Symmetric() && j > i) swap (i, j); + + const colstruct * col = lins.Get(i).col; + INDEX max = lins.Get(i).size; + + int l = 0, k = 1, newind; + + while (k < max) + k <<= 1; + + + while (k > 0) + { + k >>= 1; + newind = k+l; + if (newind >= max) continue; + if (col[newind].colnr <= j) + l += k; + } + + if (l < max && col[l].colnr == j) return col[l].data; + + return 0; + + /* + for (INDEX k = 0; k < max; k++, col++) + if (col->colnr == j) + { + if (l != k) cerr << "Set: ind not ok" << endl; + else cerr << "is ok" << endl; + return col->data; + } + + return 0; + */ + } + + +void SparseMatrix :: Set(INDEX i, INDEX j, double v) + { + Elem (i, j) = v; + } + + + +double & SparseMatrix :: Elem(INDEX i, INDEX j) + { + if (Symmetric() && j > i) swap (i, j); + + linestruct * lin = &lins.Elem(i); + colstruct * col, *ncol; + + int size = lin->size; + int pos; + + if (size) + { + + // bereits Elemente in der Liste + + if (j > lin->col[size-1].colnr) + { + + // neues Element an letzter Position einfuegen + + if (lin->maxsize > size) + { + lin->size++; + lin->col[size].colnr = j; + return lin->col[size].data = 0; + } + + if ( (ncol = NewColStruct(lin->maxsize+4)/* new colstruct[lin->maxsize+4] */) != NULL) + { + memcpy (ncol, lin->col, sizeof(colstruct) * size); + + DeleteColStruct (lin->col, lin->maxsize); + + lin->maxsize += 4; + lin->col = ncol; + lin->size++; + ncol[size].colnr = j; + return ncol[size].data = 0; + } + else + { + (*myerr) << "SparseMatrix::Elem: Out of memory 1" << endl; + return shit; + } + + } + else + { + + for (col = lin->col; col->colnr < j; col++); + // Zeilenliste durchsuchen + + if (col->colnr == j) return col->data; + // Element exisitiert bereits + + if (lin->maxsize > size) + { + memmove (col+1, col, size_t((char*)&lin->col[size] - (char*)col)); + + lin->size++; + col->colnr = j; + return col->data = 0; + } + + pos = size_t (col - lin->col); + + if ( (ncol = NewColStruct(lin->maxsize+4) ) != NULL) + { + + if (pos) memcpy (ncol, lin->col, sizeof(colstruct) * pos); + memcpy (ncol+(pos+1), col, sizeof(colstruct) * (size-pos)); + + DeleteColStruct (lin->col, lin->maxsize); +// delete lin->col; + + lin->maxsize += 4; + lin->col = ncol; + lin->size++; + ncol[pos].colnr = j; + return ncol[pos].data = 0; + } + else + { + (*myerr) << "SparseMatrix::Elem: Out of memory 2" << endl; + return shit; + } + } + } + else + { + // kein Element in der Liste + + if (lin->maxsize) + { + // Liste bereits angelegt + + lin->size = 1; + lin->col->colnr = j; + return lin->col->data = 0; + } + else + { + if ( (lin->col = NewColStruct(6) ) != NULL ) + { + lin->maxsize = 6; + lin->size = 1; + lin->col->colnr = j; + return lin->col->data = 0; + } + else + { + (*myerr) << "SparseMatrix::Elem: Out of memory 3" << endl; + return shit; + } + } + } + } + + + +void SparseMatrix :: Delete (INDEX i, int nr) + { + colstruct * col = lins[i].col; + + nr--; + while (nr < lins[i].size-1) + { + col[nr].data = col[nr+1].data; + col[nr].colnr = col[nr+1].colnr; + nr++; + } + lins[i].size--; + } + +void SparseMatrix :: DeleteElem (INDEX i, INDEX j) + { + int nr; + int dec = 0; + + if (Symmetric() && j > i) swap (i, j); + + colstruct * col = lins[i].col; + + for (nr = 0; nr < lins[i].size; nr++) + { + if (dec) + { + col[nr-1].data = col[nr].data; + col[nr-1].colnr = col[nr].colnr; + } + if (col[nr].colnr == j) dec = 1; + } + if (dec) + lins[i].size--; + } + + +void SparseMatrix :: SetLineAllocSize (INDEX i, int j) + { + colstruct * ncol; + + + if (lins[i].maxsize < j) + { + if ( (ncol = NewColStruct(j)) != NULL) + { + memcpy (ncol, lins[i].col, sizeof(colstruct) * lins[i].size); + + if (lins[i].maxsize) + DeleteColStruct (lins[i].col, lins[i].maxsize); + + lins[i].maxsize = j; + lins[i].col = ncol; + } + else + (*myerr) << "SPARSE_MATIRX :: SetLineAllocSize: Out of Memory" << endl; + } + } + + + + + + + + + + + + + + +SparseMatrix operator* (const SparseMatrix & m1, + const SparseMatrix & m2) + { + SparseMatrix m(m1.Height(), m2.Width()); + INDEX i, j, k, nr; + + if (!m1.Symmetric() && !m2.Symmetric()) + { + for (i = 1; i <= m1.Height(); i++) + { + for (j = 1; j <= m1.ElementsInLine(i); j++) + { + nr = m1.GetIndex (i, j); + for (k = 1; k <= m2.ElementsInLine(nr); k++) + { + m(i, m2.GetIndex(nr, k)) += m1.GetData(i, j) * m2.GetData(nr, k); + } + } + } + } + else + { + (*myerr) << "SparseMatrix :: operator* not implemented for symmetric case" << endl; + } + return m; + } + + +SparseMatrix & SparseMatrix :: operator+= (const SparseMatrix & m2) + { + INDEX i, k; + int j; + + if (Symmetric() == m2.Symmetric()) + { + for (i = 1; i <= Height(); i++) + for (j = 1; j <= m2.ElementsInLine (i); j++) + { + k = m2.GetIndex (i, j); + Elem(i, k) += m2.GetData (i, j); + } + } + else + { + (*myerr) << "SparseMatrix :: operator+= not implemented for different cases" << endl; + } + return *this; + } + + + +SparseMatrix & SparseMatrix :: operator*= (const SparseMatrix & m2) + { + INDEX i, k; + int j, l; + colstruct * cs; + int ms, s; + + if (!Symmetric() && !m2.Symmetric()) + { + for (i = 1; i <= Height(); i++) + { + cs = lins[i].col; + s = lins[i].size; + ms = lins[i].maxsize; + + lins[i].col = NULL; + lins[i].size = 0; + lins[i].maxsize = 0; + + + for (j = 0; j < s; j++) + { + k = cs[j].colnr; + + for (l = 1; l <= m2.ElementsInLine (k); l++) + Elem(i, m2.GetIndex(k, l)) += cs[j].data * m2.GetData(k, l); + } + + DeleteColStruct (cs, ms); + } + } + else + { + (*myerr) << "SparseMatrix :: operator*= not implemented for Symmetric matrices" << endl; + } + + return *this; + } + + +void SparseMatrix :: Solve (const Vector & v, Vector & sol) const + { + SparseMatrix temp = *this; + INDEX i, j, nr, k; + double q; + + sol = v; + + + if (!Symmetric()) + { + for (i = 1; i <= Height(); i++) + { + if (temp.ElementsInLine(i) < 1 || temp.GetIndex(i, 1) != i) + { + (*myerr) << "i = " << i << endl; + (*myerr) << "Solve: Matrix singular" << endl; + char ch; + cin >> ch; + } + for (j = 2; j <= temp.ElementsInLine(i); j++) + { + nr = temp.GetIndex(i, j); + if (temp.GetIndex(nr, 1) != i) + { + (*myerr) << temp << endl; + (*myerr) << "i = " << i << "j = " << j << "nr = " << nr << endl; + (*myerr) << "Solve: Graph not symmetrix" << endl; + char ch; + cin >> ch; + } + + q = temp.GetData (nr, 1) / temp.GetData(i, 1); + temp.Delete (nr, 1); + + for (k = 2; k <= temp.ElementsInLine (i); k++) + temp.Elem(nr, temp.GetIndex(i, k)) -= q * temp.GetData(i, k); + + sol(nr) -= q * sol(i); + } + } + + for (i = temp.Height(); i >= 1; i--) + { + for (j = 2; j <= temp.ElementsInLine(i); j++) + { + sol(i) -= temp.GetData(i, j) * sol(temp.GetIndex(i, j)); + } + sol(i) /= temp.GetData(i, 1); + } + } + else + (*myerr) << "SparseMatrix :: Solve not implemented for symmetic case" << endl; + } + + + + + +void Transpose (const SparseMatrix & m1, SparseMatrix & m2) + { + INDEX i, j; + + m2.SetSize(m1.Width(), m1.Height()); + m2.SetSymmetric(m1.Symmetric()); + + if (!m1.Symmetric()) + { + for (i = 1; i <= m1.Height(); i++) + for (j = 1; j <= m1.ElementsInLine(i); j++) + m2(m1.GetIndex(i, j), i) = m1.GetData(i, j); + } + else + m2 = m1; + } + + + +BaseMatrix * SparseMatrix :: Copy () const + { + return new SparseMatrix (*this); + } + + + + + + + +void SparseMatrix :: AddRowMatrix (INDEX row, const SparseMatrix & m2) + { + int i1, i2, i; + colstruct * cs1, * cs2, * ncs; + int s1, s2, s; + + s1 = lins[row].size; + s2 = m2.lins[1].size; + cs1 = lins[row].col; + cs2 = m2.lins[1].col; + + i1 = 0; + i2 = 0; + i = 0; + + + if (Symmetric()) + { + while (s2 && cs2[s2-1].colnr > row) s2--; + } + + + while (i1 < s1 && i2 < s2) + { + if (cs1[i1].colnr < cs2[i2].colnr) i1++; + else if (cs1[i1].colnr > cs2[i2].colnr) i2++; + else { i1++; i2++; } + i++; + } + + i += (s1 - i1); + i += (s2 - i2); + + s = i; + + if (s > s1) + { + ncs = NewColStruct (s); + + i1 = 0; + i2 = 0; + i = 0; + + while (i1 < s1 && i2 < s2) + { + if (cs1[i1].colnr < cs2[i2].colnr) + { + ncs[i].colnr = cs1[i1].colnr; + ncs[i].data = cs1[i1].data; + i1++; + } + else if (cs1[i1].colnr > cs2[i2].colnr) + { + ncs[i].colnr = cs2[i2].colnr; + ncs[i].data = cs2[i2].data; + i2++; + } + else + { + ncs[i].colnr = cs1[i1].colnr; + ncs[i].data = cs1[i1].data + cs2[i2].data; + i1++; + i2++; + } + i++; + } + + while (i1 < s1) + { + ncs[i].colnr = cs1[i1].colnr; + ncs[i].data = cs1[i1].data; + i1++; + i++; + } + + while (i2 < s2) + { + ncs[i].colnr = cs2[i2].colnr; + ncs[i].data = cs2[i2].data; + i2++; + i++; + } + + if (lins[row].maxsize) + DeleteColStruct (cs1, lins[row].maxsize); + + lins[row].col = ncs; + lins[row].size = s; + lins[row].maxsize = s; + } + + + else + { + i1 = 0; + i2 = 0; + + while (i2 < s2) + { + if (cs1[i1].colnr == cs2[i2].colnr) + { + cs1[i1].data += cs2[i2].data; + i2++; + } + i1++; + } + } + } + + +double SparseMatrix :: RowTimesVector (INDEX i, const Vector & v) const + { + const linestruct * lin; + const colstruct * col; + double sum; + int j; + + if (Width() > v.Size()) + { + cerr << "SparseMatrix::RowTimesVector: Size doesn't fit" << endl; + return 0; + } + + lin = &lins.Get(i); + sum = 0; + col = lin->col; + + for (j = lin->size; j > 0; j--, col++) + sum += col->data * v.Get(col->colnr); + + return sum; + } + +void SparseMatrix :: AddRowToVector (INDEX i, double s, Vector & v) const + { + const linestruct * lin; + const colstruct * col; + int j; + + if (Width() > v.Size()) + { + cerr << "SparseMatrix::AddRowToVector: Size doesn't fit" + << "w = " << Width() << " len = " << v.Size() << endl; + return; + } + + lin = &lins.Get(i); + col = lin->col; + + for (j = lin->size; j > 0; j--, col++) + v.Elem(col->colnr) += s * col->data; + } + + +static ARRAY<void*> poolarray; +static ARRAY<int> poolsizes; + + +SparseMatrix::colstruct * SparseMatrix :: NewColStruct (int s) + { +// return new colstruct[s]; + + + int i, j; + void * p; + colstruct * cs; + + if (s > 20) return new colstruct[s]; + + for (i = 1; i <= poolsizes.Size(); i++) + if (poolsizes.Get(i) == s) break; + + if (i > poolsizes.Size()) + { + poolsizes.Append(s); + poolarray.Append((void*)NULL); + i = poolsizes.Size(); + } + + p = poolarray.Get(i); + if (!p) + { + poolarray.Elem(i) = p = cs = new colstruct[10 * s]; + for (j = 0; j < 9; j++) + *(void**)(void*)(&cs[s * j]) = &cs[s * (j+1)]; + *(void**)(void*)(&cs[s * 9]) = NULL; + } + + poolarray.Elem(i) = *(void**)p; + return (colstruct*)p; + } + +void SparseMatrix :: DeleteColStruct (colstruct * cs, int s) + { +// delete cs; +// return; + + int i; + + if (s > 20) + { + delete cs; + return; + } + + for (i = 1; i <= poolsizes.Size(); i++) + if (poolsizes.Get(i) == s) break; + + + if (i > poolsizes.Size()) + { + (*myerr) << "SparseMatrix :: DeleteColStruct: Size not found" << endl; + return; + } + + + *(void**)(void*)cs = poolarray.Get(i); + poolarray.Elem(i) = cs; + } + +void SparseMatrix :: SetGraph (const class TABLE<INDEX> & graph) + { + int i, j, es, ad, nne; + colstruct * block; + + nne = 0; + for (i = 1; i <= graph.Size(); i++) + { + if (Symmetric()) + { + es = 0; + for (j = 1; j <= graph.EntrySize(i); j++) + if (graph.Get(i, j) <= i) + es++; + } + else + es = graph.EntrySize(i); + nne += es; + } + + oneblock = 1; + block = new colstruct[nne]; + + ad = 0; + for (i = 1; i <= graph.Size(); i++) + { + if (Symmetric()) + { + es = 0; + for (j = 1; j <= graph.EntrySize(i); j++) + if (graph.Get(i, j) <= i) + es++; + } + else + es = graph.EntrySize(i); + + lins.Elem(i).size = 0; + lins.Elem(i).maxsize = es; + lins.Elem(i).col = &block[ad]; + ad += es; + } + } + + + + +#endif +} +#endif diff --git a/contrib/Netgen/libsrc/linalg/sparsmat.hpp b/contrib/Netgen/libsrc/linalg/sparsmat.hpp new file mode 100644 index 0000000000..74aaa3134e --- /dev/null +++ b/contrib/Netgen/libsrc/linalg/sparsmat.hpp @@ -0,0 +1,265 @@ +#ifdef NONE + +#ifndef FILE_SPARSMAT +#define FILE_SPARSMAT + +/* *************************************************************************/ +/* File: sparsmat.hh */ +/* Author: Joachim Schoeberl */ +/* Date: 01. Oct. 94 */ +/* *************************************************************************/ + + +class SparseMatrix; + +/** + The graph of a sparse matrix. + The graph is stored for a non-symmetric matrix +*/ +class MatrixGraph +{ + /// data structure for one row of matrix + struct linestruct + { + /// allocated size + int allocsize; + /// used size + int size; + /// diag element (always allocated) + int diag; + /// colume numbers + INDEX* col; + }; + + /// graph of matrix + ARRAY<linestruct> lines; + /// increment of allocated line-memory on overflow + int increment; + +public: + //@{ @name Constructors, Destructor + + /// Height of matrix, increment value for line-overflow + MatrixGraph (int size, int aincrement = 5); + /// Allocates graph with elements per row given in ARRAY linesize + MatrixGraph (const ARRAY<int> & linesize); + //@} + + + /// returns position of Element (i, j), 0 for unused + int GetPosition (INDEX i, INDEX j) const; + + /// returns position of new element + int CreatePosition (INDEX i, INDEX j); + + /// Returns height of matrix + int Size() const { return lines.Size(); } + + + friend class SparseMatrix; + friend class SparseMatrixFlex; + friend class SparseMatrixFix; + friend class PointJacobiPrecond; +}; + + + + + + +/** + Base class for sparse matrix. + Matrix to work with in most applications + */ +class SparseMatrix : public BaseMatrix +{ +protected: + /// graph of matrix + const MatrixGraph * graph; + /// pointer to matrix values in each row + ARRAY<double*> data; + +public: + + /// returns reference, fail save but slow + virtual double & operator() (INDEX i, INDEX j); + /// returns value, fail save but slow + virtual double operator() (INDEX i, INDEX j) const; + + + /// prod = matrix x v + virtual void Mult (const Vector & v, Vector & prod) const; + /// prod = matrix^T x v + virtual void MultTrans (const Vector & v, Vector & prod) const; + /// res = b - mat x x + virtual void Residuum (const Vector & x, const Vector & b, + Vector & res) const; + /// res = b - mat^T x x + virtual void ResiduumTrans (const Vector & x, const Vector & b, + Vector & res) const; + + + /** + Add element matrix to sparse matrix. + The graph of the element-matrix must be symmetric. + Global point numbers are given in pnum. + */ + virtual void AddElementMatrix (const ARRAY<INDEX> & pnum, const BaseMatrix & elemmat); + + /// for multigrid-extension, should be removed from here + void GSStepToInner (const Vector & b, Vector & x, double dump, + const BitArray & inner) const; + + /// for multigrid-extension, should be removed from here + void GSStepBackToInner (const Vector & b, Vector & x, double dump, + const BitArray & inner) const; + + /// + virtual ostream & Print (ostream & s) const; + + /** Scalar product of i-th row times vector. + For symmetric matrices only lower left block + (including diagonal) is used. + */ + double RowTimesVector (INDEX i, const Vector & v) const; + /** Adds s times the i-th row of matrix to vector v. + For symmetric matrices only lower left block + (including diagonal) is used. + */ + void AddRowToVector (INDEX i, double s, Vector & v) const; + + /** Number of elements in line. + For symmetric matrices GetDiagPos must be used for + most purposes. + */ + int ElementsInLine (INDEX i) const + { return graph->lines.Get(i).size; } + + /** Columne index of nr-th non-zero element in row i */ + INDEX GetColIndex (INDEX i, int nr) const + { return graph->lines.Get(i).col[nr-1]; } + + /** Referece to columne index of nr-th non-zero + element in row i */ + const INDEX & GetColIndexRef (INDEX i, int nr) const + { return graph->lines.Get(i).col[nr-1]; } + + /** Value of nr-th non-zero element in row i */ + double GetData (INDEX i, int nr) const + { return data.Get(i)[nr-1]; } + + /** Reference to value of nr-th non-zero element in row i */ + const double & GetDataRef (INDEX i, int nr) const + { return data.Get(i)[nr-1]; } + + /** Returns value of diagonal element in row i */ + double GetDiag (INDEX i) const + { return data.Get(i)[graph->lines.Get(i).diag-1]; } + + /** Which position has diagonal element in row i ? */ + int GetDiagPos (INDEX i) const + { return graph->lines.Get(i).diag; } + + /** Returns matrix value of row i, col j. + For symmetric matrices the indices will be sorted in + this function */ + double Get(INDEX i, INDEX j) const; + + /** Set value of element (i, j) to v. + For symmetric matrices element (j, i) is set. */ + void Set(INDEX i, INDEX j, double v); + + /** Returns reference to element (i, j). + For symmetric matrices a reference to (j, i) is returned */ + double & Elem(INDEX i, INDEX j); + + /** Is element (i, j) used ? */ + char Used (INDEX i, INDEX j) const; + +protected: + /// A sparse matrix must not be constructed + SparseMatrix (INDEX h, INDEX w = 0); + /// Allocates matrix position + virtual int CreatePosition (INDEX i, INDEX j) = 0; + +private: + /// + friend class ScalarBlockJacobiPrecond; + friend class PointJacobiPrecond; +}; + + + + +/** Sparse matrix with flexible graph. + On demand, a matrix position is allocated */ +class SparseMatrixFlex : public SparseMatrix +{ + /// non-const pointer to graph. + MatrixGraph * mygraph; + +public: + /// + SparseMatrixFlex (); + /// + SparseMatrixFlex (INDEX h, INDEX w = 0); + /// + SparseMatrixFlex (const SparseMatrix & m2); + /// + virtual ~SparseMatrixFlex (); + + /// + virtual void SetSize (INDEX h, INDEX w = 0); + /// + virtual void SetSymmetric (int sym = 1); + /// + virtual void ChangeSize (INDEX h, INDEX w = 0); + /// + void DeleteElements (); + + + /// + SparseMatrix & operator= (const SparseMatrix & m2); + /// + SparseMatrix & operator*= (double v); + + + /// + virtual BaseMatrix * Copy () const; + /// + void Delete (INDEX i, int nr); + /// + void DeleteElem (INDEX i, INDEX j); + + /// + void SetLineAllocSize (INDEX i, int j); + +protected: + /// + virtual int CreatePosition (INDEX i, INDEX j); + +}; + + + + +/** Sparse matrix with fixed graph. + After construction of the matrix, the graph + must not be changed. */ +class SparseMatrixFix : public SparseMatrix +{ +public: + /// + SparseMatrixFix (const MatrixGraph & agraph, int asymmetric = 0); + /// + virtual ~SparseMatrixFix (); + +protected: + /// CreatePosition is not allowed for SparseMatrixFix -> error + virtual int CreatePosition (INDEX i, INDEX j); +}; + + +#endif + +#endif diff --git a/contrib/Netgen/libsrc/linalg/vector.cpp b/contrib/Netgen/libsrc/linalg/vector.cpp new file mode 100644 index 0000000000..05b5a0a71e --- /dev/null +++ b/contrib/Netgen/libsrc/linalg/vector.cpp @@ -0,0 +1,787 @@ +#ifdef abc +#include <mystdlib.h> +#include <linalg.hpp> +#include <algorithm> + +namespace netgen +{ + +double BaseVector :: shit = 0; + +// %FD Constructs a vector of length zero +BaseVector :: BaseVector () + { + length = 0; + } + +// %FD Constructs a vector of given length +BaseVector :: BaseVector ( + INDEX alength // length of the vector + ) + { + length = alength; + } + +// %FD Sets length of the vector, old vector will be destroyed +void +BaseVector :: SetLength ( + INDEX alength // new length of the vector + ) + { + length = alength; + } + +// %FD Changes length of the vector, old values stay valid +void +BaseVector :: ChangeLength ( + INDEX alength // new length of the vector + ) + { + length = alength; + } + + + +// %FD { Write a vector with the help of the '<<' operator onto a stream } +ostream & // stream for further use +operator<< ( + ostream & s, // stream to write vector onto + const BaseVector & v // vector to write + ) + { + return v.Print (s); + } + + +// %FD{ Divides every component of the vector by the scalar c. +// The function checks for division by zero } +BaseVector & // result vector +BaseVector :: operator/= ( + double c // scalar to divide by + ) + { + if (c) + return (*this) *= (1/c); + else + { + (*myerr) << "operator/=: division by zero" << endl; + return *this; + } + } + + +// %FD Creates a copy of the object +BaseVector * // pointer to the new vector +BaseVector :: Copy () const + { + cerr << "Base_vector::Copy called" << endl << flush; + return NULL; + } + + + + +void BaseVector :: GetElementVector (const ARRAY<INDEX> & pnum, + BaseVector & elvec) const +{ + int i; + for (i = 1; i <= pnum.Size(); i++) + elvec(i) = (*this)(pnum.Get(i)); +} + +void BaseVector :: SetElementVector (const ARRAY<INDEX> & pnum, + const BaseVector & elvec) +{ + int i; + for (i = 1; i <= pnum.Size(); i++) + (*this)(pnum.Get(i)) = elvec(i); +} + + +void BaseVector :: AddElementVector (const ARRAY<INDEX> & pnum, + const BaseVector & elvec) +{ + int i; + for (i = 1; i <= pnum.Size(); i++) + (*this)(pnum.Get(i)) += elvec(i); +} + + + + + + + + + + + +TempVector :: ~TempVector () + { + delete vec; + } + +TempVector BaseVector :: operator+ (const BaseVector & v2) const + { + return (*Copy()) += v2; + } + +TempVector BaseVector :: operator- (const BaseVector & v2) const + { + return (*Copy()) -= v2; + } + +TempVector BaseVector :: operator- () const + { + return (*Copy()) *= -1; + } + + +TempVector operator* (const BaseVector & v1, double scal) + { + return (*v1.Copy()) *= scal; + } + +TempVector operator/ (const BaseVector & v1, double scal) + { + return (*v1.Copy()) /= scal; + } + + +TempVector operator* (double scal, const BaseVector & v1) + { + return v1 * scal; + } + + + + + +BaseVector * TempVector :: Copy () const + { + return vec->Copy(); + } + + + + + + + + + + +double Vector :: shit = 0; + +class clVecpool +{ +public: + ARRAY<double *> vecs; + ARRAY<INDEX> veclens; + + ~clVecpool(); +}; + +clVecpool :: ~clVecpool() +{ + int i; + for (i = 1; i <= vecs.Size(); i++) + delete vecs.Elem(i); +} + +static clVecpool vecpool; + + + +static double * NewDouble (INDEX len) +{ + if (len < 10) + return new double[len]; + else + { + int i; + for (i = 1; i <= vecpool.veclens.Size(); i++) + if (vecpool.veclens.Get(i) == len) + { + double * hvec = vecpool.vecs.Get(i); + vecpool.vecs.DeleteElement(i); + vecpool.veclens.DeleteElement(i); + return hvec; + } + + return new double[len]; + } +} + +static void DeleteDouble (INDEX len, double * dp) +{ + if (len < 10) + delete [] dp; + else + { + vecpool.vecs.Append (dp); + vecpool.veclens.Append (len); + } +} + + + +Vector :: Vector () : BaseVector() + { + data = NULL; + } + +Vector :: Vector (INDEX alength) : BaseVector (alength) + { + if (length) + { + // data = new double[length]; + data = NewDouble (length); + + if (!data) + { + length = 0; + (*myerr) << "Vector not allocated" << endl; + } + } + else + data = NULL; + } + + +Vector :: Vector (const Vector & v2) + { + length = v2.length; + + if (length) + { + // data = new double[length]; + data = NewDouble (length); + + if (data) + { + memcpy (data, v2.data, length * sizeof (double)); + } + else + { + length = 0; + (*myerr) << "Vector::Vector : Vector not allocated" << endl; + } + } + else + data = NULL; + } + + +Vector :: ~Vector () +{ + // veclenfile << "~Vector delete: " << length << endl; + if (data) + { + DeleteDouble (length, data); + // delete [] data; + } + +} + +void Vector :: SetLength (INDEX alength) + { + if (length == alength) return; + + if (data) + { + DeleteDouble (length, data); + // delete [] data; + } + data = NULL; + length = alength; + + if (length == 0) return; + // data = new double[length]; + data = NewDouble (length); + + if (!data) + { + length = 0; + (*myerr) << "Vector::SetLength: Vector not allocated" << endl; + } + } + +void Vector :: ChangeLength (INDEX alength) +{ + (*mycout) << "Vector::ChangeLength called" << endl; + if (length == alength) return; + + if (alength == 0) + { + // delete [] data; + DeleteDouble (length, data); + length = 0; + return; + } + + double * olddata = data; + + data = NewDouble (alength); + // data = new double[alength]; + if (!data) + { + length = 0; + (*myerr) << "Vector::SetLength: Vector not allocated" << endl; + delete [] olddata; + } + + memcpy (data, olddata, min2(alength, length)); + + delete [] olddata; + length = alength; + } + +/// NEW RM +void Vector::SetBlockLength (INDEX /* blength */) +{ + MyError("BaseVector::SetBlockLength was called for a Vector"); +} + + +double & Vector :: operator() (INDEX i) + { + if (i >= 1 && i <= length) return Elem(i); + else (*myerr) << "\nindex " << i << " out of range (" + << 1 << "," << Length() << ")\n"; + return shit; + } + +double Vector :: operator() (INDEX i) const + { + if (i >= 1 && i <= length) return Get(i); + else (*myerr) << "\nindex " << i << " out of range (" + << 1 << "," << Length() << ")\n" << flush; + return shit; + } + + + +double Vector :: SupNorm () const + { + double sup = 0; + + for (INDEX i = 1; i <= Length(); i++) + if (fabs (Get(i)) > sup) + sup = fabs(Get(i)); + + return sup; + } + +double Vector :: L2Norm () const + { + double sum = 0; + + for (INDEX i = 1; i <= Length(); i++) + sum += Get(i) * Get(i); + + return sqrt (sum); + } + +double Vector :: L1Norm () const + { + double sum = 0; + + for (INDEX i = 1; i <= Length(); i++) + sum += fabs (Get(i)); + + return sum; + } + +double Vector :: Max () const + { + if (!Length()) return 0; + double m = Get(1); + for (INDEX i = 2; i <= Length(); i++) + if (Get(i) > m) m = Get(i); + return m; + } + +double Vector :: Min () const + { + if (!Length()) return 0; + double m = Get(1); + for (INDEX i = 2; i <= Length(); i++) + if (Get(i) < m) m = Get(i); + return m; + } + + +/* +ostream & operator<<(ostream & s, const Vector & v) + { + int w = s.width(); + if (v.Length()) + { + s.width(0); + s << '('; + for (INDEX i = 1; i < v.Length(); i++) + { + s.width(w); + s << v.Get(i) << ","; + if (i % 8 == 0) s << endl << ' '; + } + s.width(w); + s << v.Get(v.Length()) << ')'; + } + else + s << "(Vector not allocated)"; + + return s; + } +*/ + +ostream & Vector :: Print (ostream & s) const + { + int w = s.width(); + if (Length()) + { + s.width(0); + s << '('; + for (INDEX i = 1; i < Length(); i++) + { + s.width(w); + s << Get(i) << ","; + if (i % 8 == 0) s << endl << ' '; + } + s.width(w); + s << Get(Length()) << ')'; + } + else + s << "(Vector not allocated)"; + + return s; + } + + + +BaseVector & Vector :: operator+= (const BaseVector & v2) + { + const Vector & hv2 = v2.CastToVector(); + + if (Length() == hv2.Length()) + for (INDEX i = 1; i <= Length(); i++) + Elem (i) += hv2.Get(i); + else + (*myerr) << "operator+= illegal dimension" << endl; + return *this; + } + +BaseVector & Vector :: operator-= (const BaseVector & v2) + { + const Vector & hv2 = v2.CastToVector(); + + if (Length() == hv2.Length()) + for (INDEX i = 1; i <= Length(); i++) + Elem (i) -= hv2.Get(i); + else + (*myerr) << "operator-= illegal dimension" << endl; + return *this; + } + +BaseVector & Vector :: operator*= (double c) + { + for (INDEX i = 1; i <= Length(); i++) + Elem(i) *= c; + return *this; + } + + + +BaseVector & Vector :: Add (double scal, const BaseVector & v2) + { + const Vector & hv2 = v2.CastToVector(); + + if (Length() == hv2.Length()) + { + double * p1 = data; + double * p2 = hv2.data; + + for (INDEX i = Length(); i > 0; i--) + { + (*p1) += scal * (*p2); + p1++; p2++; + } + } + else + (*myerr) << "Vector::Add: illegal dimension" << endl; + return *this; + } + +BaseVector & Vector :: Add2 (double scal, const BaseVector & v2, + double scal3, const BaseVector & v3) + { + const Vector & hv2 = v2.CastToVector(); + const Vector & hv3 = v3.CastToVector(); + + if (Length() == hv2.Length()) + { + double * p1 = data; + double * p2 = hv2.data; + double * p3 = hv3.data; + + for (INDEX i = Length(); i > 0; i--) + { + (*p1) += (scal * (*p2) + scal3 * (*p3)); + p1++; p2++; p3++; + } + } + else + (*myerr) << "Vector::Add: illegal dimension" << endl; + return *this; + } + +BaseVector & Vector :: Set (double scal, const BaseVector & v2) + { + const Vector & hv2 = v2.CastToVector(); + + if (Length() == hv2.Length()) + { + double * p1 = data; + double * p2 = hv2.data; + + for (INDEX i = Length(); i > 0; i--) + { + (*p1) = scal * (*p2); + p1++; p2++; + } + } + else + (*myerr) << "Vector::Set: illegal dimension" << endl; + return *this; + } + + +BaseVector & Vector :: Set2 (double scal , const BaseVector & v2, + double scal3, const BaseVector & v3) + { + const Vector & hv2 = v2.CastToVector(); + const Vector & hv3 = v3.CastToVector(); + + + if (Length() == hv2.Length()) + { + double * p1 = data; + double * p2 = hv2.data; + double * p3 = hv3.data; + + for (INDEX i = Length(); i > 0; i--) + { + (*p1) = scal * (*p2) + scal3 * (*p3); + p1++; p2++; p3++; + } + } + else + (*myerr) << "Vector::Set: illegal dimension" << endl; + return *this; + } + + +void Vector :: GetPart (int startpos, BaseVector & v2) const +{ + Vector & hv2 = v2.CastToVector(); + + if (Length() >= startpos + v2.Length() - 1) + { + const double * p1 = &Get(startpos); + double * p2 = &hv2.Elem(1); + + memcpy (p2, p1, hv2.Length() * sizeof(double)); + } + else + MyError ("Vector::GetPart: Vector to short"); +} + + +// NEW RM +void Vector :: SetPart (int startpos, const BaseVector & v2) +{ + const Vector & hv2 = v2.CastToVector(); + INDEX i; + INDEX n = v2.Length(); + + if (Length() >= startpos + n - 1) + { + double * p1 = &Elem(startpos); + const double * p2 = &hv2.Get(1); + + for (i = 1; i <= n; i++) + { + (*p1) = (*p2); + p1++; + p2++; + } + } + else + MyError ("Vector::SetPart: Vector to short"); +} + +void Vector :: AddPart (int startpos, double val, const BaseVector & v2) +{ + const Vector & hv2 = v2.CastToVector(); + INDEX i; + INDEX n = v2.Length(); + + if (Length() >= startpos + n - 1) + { + double * p1 = &Elem(startpos); + const double * p2 = &hv2.Get(1); + + for (i = 1; i <= n; i++) + { + (*p1) += val * (*p2); + p1++; + p2++; + } + } + else + MyError ("Vector::AddPart: Vector to short"); +} + + + + +double Vector :: operator* (const BaseVector & v2) const + { + const Vector & hv2 = v2.CastToVector(); + + double sum = 0; + double * p1 = data; + double * p2 = hv2.data; + + if (Length() == hv2.Length()) + { + for (INDEX i = Length(); i > 0; i--) + { + sum += (*p1) * (*p2); + p1++; p2++; + } + } + else + (*myerr) << "Scalarproduct illegal dimension" << endl; + return sum; + } + +void Vector :: SetRandom () + { + INDEX i; + for (i = 1; i <= Length(); i++) + Elem(i) = rand (); + + double l2 = L2Norm(); + if (l2 > 0) + (*this) /= l2; + // Elem(i) = 1.0 / double(i); + // Elem(i) = drand48(); + } + + +/* +TempVector Vector :: operator- () const + { + Vector & sum = *(Vector*)Copy(); + + if (sum.Length () == Length()) + { + for (INDEX i = 1; i <= Length(); i++) + sum.Set (i, Get(i)); + } + else + (*myerr) << "operator+ (Vector, Vector): sum.Length() not ok" << endl; + return sum; + } +*/ + +BaseVector & Vector::operator= (const Vector & v2) + { + SetLength (v2.Length()); + + if (data == v2.data) return *this; + + if (v2.Length() == Length()) + memcpy (data, v2.data, sizeof (double) * Length()); + else + (*myerr) << "Vector::operator=: not allocated" << endl; + + return *this; + } + +BaseVector & Vector::operator= (const BaseVector & v2) + { + const Vector & hv2 = v2.CastToVector(); + + SetLength (hv2.Length()); + + if (data == hv2.data) return *this; + + if (hv2.Length() == Length()) + memcpy (data, hv2.data, sizeof (double) * Length()); + else + (*myerr) << "Vector::operator=: not allocated" << endl; + + return *this; + } + + +BaseVector & Vector::operator= (double scal) + { + if (!Length()) (*myerr) << "Vector::operator= (double) : data not allocated" + << endl; + + for (INDEX i = 1; i <= Length(); i++) + Set (i, scal); + + return *this; + } + + +BaseVector * Vector :: Copy () const + { + return new Vector (*this); + } + + +void Vector :: Swap (BaseVector & v2) + { + Vector & hv2 = v2.CastToVector(); + swap (length, hv2.length); + swap (data, hv2.data); + } + + + + +void Vector :: GetElementVector (const ARRAY<INDEX> & pnum, + BaseVector & elvec) const +{ + int i; + Vector & helvec = elvec.CastToVector(); + for (i = 1; i <= pnum.Size(); i++) + helvec.Elem(i) = Get(pnum.Get(i)); +} + +void Vector :: SetElementVector (const ARRAY<INDEX> & pnum, + const BaseVector & elvec) +{ + int i; + const Vector & helvec = elvec.CastToVector(); + for (i = 1; i <= pnum.Size(); i++) + Elem(pnum.Get(i)) = helvec.Get(i); +} + + +void Vector :: AddElementVector (const ARRAY<INDEX> & pnum, + const BaseVector & elvec) +{ + int i; + const Vector & helvec = elvec.CastToVector(); + for (i = 1; i <= pnum.Size(); i++) + Elem(pnum.Get(i)) += helvec.Get(i); +} +} +#endif diff --git a/contrib/Netgen/libsrc/linalg/vector.hpp b/contrib/Netgen/libsrc/linalg/vector.hpp new file mode 100644 index 0000000000..acba491792 --- /dev/null +++ b/contrib/Netgen/libsrc/linalg/vector.hpp @@ -0,0 +1,485 @@ +#ifndef FILE_VECTOR +#define FILE_VECTOR + +/* *************************************************************************/ +/* File: vector.hh */ +/* Author: Joachim Schoeberl */ +/* Date: 01. Oct. 94 */ +/* *************************************************************************/ + + +class FlatVector +{ +protected: + int s; + double *data; +public: + FlatVector () { ; } + FlatVector (int as, double * adata) + { s = as; data = adata; } + + int Size () const + { return s; } + + FlatVector & operator= (const FlatVector & v) + { memcpy (data, v.data, s*sizeof(double)); return *this; } + + FlatVector & operator= (double scal) + { + for (int i = 0; i < s; i++) data[i] = scal; + return *this; + } + + double & operator[] (int i) { return data[i]; } + const double & operator[] (int i) const { return data[i]; } + double & operator() (int i) { return data[i]; } + const double & operator() (int i) const { return data[i]; } + + double & Elem (int i) { return data[i-1]; } + const double & Get (int i) const { return data[i-1]; } + void Set (int i, double val) { data[i-1] = val; } + + FlatVector & operator*= (double scal) + { + for (int i = 0; i < s; i++) data[i] *= scal; + return *this; + } + + FlatVector & Add (double scal, const FlatVector & v2) + { + for (int i = 0; i < s; i++) + data[i] += scal * v2.data[i]; + return *this; + } + + FlatVector & Set (double scal, const FlatVector & v2) + { + for (int i = 0; i < s; i++) + data[i] = scal * v2.data[i]; + return *this; + } + + FlatVector & Set2 (double scal1, const FlatVector & v1, + double scal2, const FlatVector & v2) + { + for (int i = 0; i < s; i++) + data[i] = scal1 * v1.data[i] + scal2 * v2.data[i]; + return *this; + } + + double L2Norm() const + { + double sum = 0; + for (int i = 0; i < s; i++) + sum += data[i] * data[i]; + return sqrt (sum); + } + + friend double operator* (const FlatVector & v1, const FlatVector & v2); +}; + + + +class Vector : public FlatVector +{ + +public: + Vector () + { s = 0; data = 0; } + Vector (int as) + { s = as; data = new double[s]; } + ~Vector () + { delete [] data; } + + Vector & operator= (const FlatVector & v) + { memcpy (data, &v.Get(1), s*sizeof(double)); return *this; } + + Vector & operator= (double scal) + { + for (int i = 0; i < s; i++) data[i] = scal; + return *this; + } + + void SetSize (int as) + { + if (s != as) + { + s = as; + delete [] data; + data = new double [s]; + } + } + +}; + + +inline double operator* (const FlatVector & v1, const FlatVector & v2) +{ + double sum = 0; + for (int i = 0; i < v1.s; i++) + sum += v1.data[i] * v2.data[i]; + return sum; +} + + + + +inline ostream & operator<< (ostream & ost, const FlatVector & v) +{ + for (int i = 0; i < v.Size(); i++) + ost << " " << setw(7) << v[i]; + return ost; +} + + + + + + + + + + +#ifdef OLDVEC + +class TempVector; +class Vector; +class BlockVector; + +/** Data types for vectors. + + Every Vector data structure is derived from a BaseVector class. + A BaseVector provides virtual functions for the scalar-vector + and vector-vector operations. + If the return value of a function is a vector, then there should + be used a TempVector class. This avoids one additional constructor/ + destructor call. + Finally, a Vector - class contains the data of a Vector in dense + form. + + Vector - Operations: + + Vector ( x ) Constructor empty, with given length or + given vector to copy + + SetLength () + ChangeLength() Change vector-length with/without destroing the vector + Length() return vector-length + + Copy() Construct a vector of same type and contents + + operator() Save vector access + Set, Get, Elem: Fast vector access for setting, receiving and reference + + +, -, *, =, +=, -=, *=, /= + virtual vector operations + + SupNorm, L2Norm, L1Norm, Min, Max + Vector operations + + Set (s, v), Add (s, v) + Fast scalar-vector operations + + Print () stream output of a vector + +*/ + +class BaseVector +{ +protected: + /// + INDEX length; + /// + static double shit; + +public: + /// + BaseVector (); + /// + BaseVector (INDEX alength); + /// + virtual ~BaseVector () { }; + /// + virtual void SetSize (INDEX asize) { SetLength(asize); } + /// + virtual void SetLength (INDEX alength); + /// + virtual void ChangeLength (INDEX alength); + /// Size should be prefered !!! + INDEX Length () const { return length; } + /// + INDEX Size() const { return length; } + + // NEW RM ---> in BlockVector + // rtual void SetBlockLength (INDEX blength) = 0; + + /// + virtual BaseVector & operator= (const BaseVector & /* v2 */) { return *this; } + /// + virtual BaseVector & operator= (double /* scal */) { return *this; } + + /// + virtual double & operator() (INDEX /* i */) { return shit; } + /// + virtual double operator() (INDEX /* i */) const { return 0; } + + /// + virtual double SupNorm () const = 0; + /// + virtual double L2Norm () const = 0; + /// + virtual double L1Norm () const = 0; + /// + virtual double Min () const = 0; + /// + virtual double Max () const = 0; + + /// + virtual BaseVector & operator+= (const BaseVector & v2) = 0; + /// + virtual BaseVector & operator-= (const BaseVector & v2) = 0; + /// + virtual BaseVector & operator*= (double scal) = 0; + /// + virtual BaseVector & operator/= (double scal); + + /// + virtual TempVector operator+ (const BaseVector & v2) const; + /// + virtual TempVector operator- (const BaseVector & v2) const; + /// + virtual TempVector operator- () const; + /// + virtual double operator* (const BaseVector & v2) const = 0; + /// + friend TempVector operator* (const BaseVector & v1, double scal); + /// + friend TempVector operator/ (const BaseVector & v1, double scal); + /// + friend TempVector operator* (double scal, const BaseVector & v1); + + /// + virtual BaseVector & Add (double /* scal */, const BaseVector & /* v2 */) { return *this; } + /// + virtual BaseVector & Add2 (double /* scal */, const BaseVector & /* v2 */, + double /* scal3 */, const BaseVector & /* v3 */) { return *this; } + /// + virtual BaseVector & Set (double /* scal */, const BaseVector & /* v2 */) { return *this; } + /// + virtual BaseVector & Set2 (double /* scal */, const BaseVector & /* v2 */, + double /* scal3 */, const BaseVector & /* v3 */) { return *this; } + + /// + virtual void SetRandom () { }; + + + /// + virtual void GetPart (int /* startpos */, + BaseVector & /* v2*/ ) const { }; + /// + virtual void SetPart (int /* startpos */, + const BaseVector & /* v2 */) { }; + /// + virtual void AddPart (int /* startpos */, double /* val */, + const BaseVector & /* v2 */) { }; + + /// + virtual void GetElementVector (const ARRAY<INDEX> & pnum, + BaseVector & elvec) const; + /// + virtual void SetElementVector (const ARRAY<INDEX> & pnum, + const BaseVector & elvec); + /// + virtual void AddElementVector (const ARRAY<INDEX> & pnum, + const BaseVector & elvec); + + /// + friend ostream & operator<<(ostream & s, const BaseVector & v); + /// + virtual ostream & Print (ostream & s) const { return s; } + + /// + virtual BaseVector * Copy () const; + /// + virtual int IsVector () const { return 0; } + /// + virtual int IsBlockVector () const { return 0; } + /// + virtual Vector & CastToVector () { return *(Vector*)this; } + /// + virtual const Vector & CastToVector () const { return *(Vector*)this; } + /// + virtual BlockVector & CastToBlockVector () { return *(BlockVector*)this; } + /// + virtual const BlockVector & CastToBlockVector () const { return *(BlockVector*)this; } + }; + + +/// +class TempVector : public BaseVector +{ + /// + BaseVector * vec; + + public: + /// + TempVector (BaseVector & v1) { vec = & v1; } + /// + ~TempVector (); + /// + virtual Vector & CastToVector () + { return vec->CastToVector(); } + /// + virtual const Vector & CastToVector () const + { return vec->CastToVector(); } + /// + virtual BlockVector & CastToBlockVector () + { return vec->CastToBlockVector(); } + /// + virtual const BlockVector & CastToBlockVector () const + { return vec->CastToBlockVector(); } + + + /// + virtual BaseVector & operator+= (const BaseVector & /* v2 */) { return *this; } + /// + virtual BaseVector & operator-= (const BaseVector & /* v2 */) { return *this; } + /// + virtual BaseVector & operator*= (double /* scal */) { return *this; } + /// + virtual double operator* (const BaseVector & /* v2 */) const { return 0; } + + /// + virtual double SupNorm () const { return vec->SupNorm(); } + /// + virtual double L2Norm () const { return vec->L2Norm(); } + /// + virtual double L1Norm () const { return vec->L1Norm(); } + /// + virtual double Min () const { return vec->Min(); } + /// + virtual double Max () const { return vec->Max(); } + + /// + virtual void Swap (BaseVector &) { }; + /// + virtual BaseVector * Copy () const; + + + }; + + +/// +class Vector : public BaseVector +{ + /// + double * data; + /// + static double shit; + +public: + /// + Vector (); + /// + Vector (INDEX alength); + /// + Vector (const Vector & v2); + /// + virtual ~Vector (); + + /// + virtual void SetLength (INDEX alength); + /// + virtual void ChangeLength (INDEX alength); + /// NEW RM + virtual void SetBlockLength (INDEX blength); + + /// + virtual BaseVector & operator= (const BaseVector & v2); + /// + virtual BaseVector & operator= (const Vector & v2); + /// + virtual BaseVector & operator= (double scal); + + /// + double & operator() (INDEX i); + /// + double operator() (INDEX i) const; + + /// + virtual double SupNorm () const; + /// + virtual double L2Norm () const; + /// + virtual double L1Norm () const; + /// + virtual double Min () const; + /// + virtual double Max () const; + + /// + virtual BaseVector & operator+= (const BaseVector & v2); + /// + virtual BaseVector & operator-= (const BaseVector & v2); + /// + virtual BaseVector & operator*= (double scal); + + /// + virtual double operator* (const BaseVector & v2) const; + + + /// + virtual BaseVector & Add (double scal, const BaseVector & v2); + /// + virtual BaseVector & Add2 (double scal, const BaseVector & v2, + double scal3, const BaseVector & v3); + /// + virtual BaseVector & Set (double scal, const BaseVector & v2); + /// + virtual BaseVector & Set2 (double scal , const BaseVector & v2, + double scal3, const BaseVector & v3); + + /// + virtual void GetPart (int startpos, BaseVector & v2) const; + /// + virtual void SetPart (int startpos, const BaseVector & v2); + /// + virtual void AddPart (int startpos, double val, const BaseVector & v2); + + /// + virtual void SetRandom (); + + /// + virtual ostream & Print (ostream & s) const; + /// + virtual BaseVector * Copy () const; + /// + virtual void Swap (BaseVector &); + + /// + const double & Get (INDEX i) const { return data[i-1]; } + /// + void Set (INDEX i, double v) { data[i-1] = v; } + /// + double & Elem (INDEX i) { return data[i-1]; } + + /// + virtual int IsVector () const { return 1; } + + + /// + virtual void GetElementVector (const ARRAY<INDEX> & pnum, + BaseVector & elvec) const; + /// + virtual void SetElementVector (const ARRAY<INDEX> & pnum, + const BaseVector & elvec); + /// + virtual void AddElementVector (const ARRAY<INDEX> & pnum, + const BaseVector & elvec); + }; + +#endif + +#endif + + diff --git a/contrib/Netgen/libsrc/makefile.inc b/contrib/Netgen/libsrc/makefile.inc new file mode 100644 index 0000000000..76369d5fb6 --- /dev/null +++ b/contrib/Netgen/libsrc/makefile.inc @@ -0,0 +1,48 @@ +# +# +# Make-Include-File for library +# Joachim Schoeberl, 17.04.96 +# +# +CPP_DIR=../.. +LIBSRC_DIR=$(CPP_DIR)/libsrc +LIB_DIR=$(CPP_DIR)/lib/$(MACHINE) + +OCC_DIR=../../occ +OCCINC_DIR=$(OCC_DIR)/inc +OCCLIB_DIR=$(OCC_DIR)/lib +# +include $(LIBSRC_DIR)/makefile.mach.$(MACHINE) +# +CPLUSPLUSFLAGS1 = -c -I$(LIBSRC_DIR)/include -I$(OCCINC_DIR) +# +ARFLAGS = r +# +LIBB=$(LIB_DIR)/lib$(lib).a +# +.PRECIOUS: .cpp .c +.SUFFIXES: .cpp .c .o +# +.cpp.o: + $(CPLUSPLUS) $(CPLUSPLUSFLAGS1) $(CPLUSPLUSFLAGS2) $(CPLUSPLUSFLAGSLIBRARY) $< +.c.o: + $(CPLUSPLUS) $(CPLUSPLUSFLAGS1) $(CPLUSPLUSFLAGS2) $(CPLUSPLUSFLAGSLIBRARY) $< +# +# +$(LIBB):: $(LIB_DIR) +# +# make lib from sources: +# +$(LIBB):: $(src) + $(CPLUSPLUS) $(CPLUSPLUSFLAGS1) $(CPLUSPLUSFLAGS2) $(CPLUSPLUSFLAGSLIBRARY) $? + @$(AR) $(ARFLAGS) $@ *.o + -@$(RM) *.o + -@$(RANLIB) $@ +# +# +# +$(LIB_DIR) : + -@mkdir $(CPP_DIR)/lib + @mkdir $(LIB_DIR) +# +# diff --git a/contrib/Netgen/libsrc/makefile.mach.FREEBSD b/contrib/Netgen/libsrc/makefile.mach.FREEBSD new file mode 100644 index 0000000000..6f903d4e60 --- /dev/null +++ b/contrib/Netgen/libsrc/makefile.mach.FREEBSD @@ -0,0 +1,26 @@ +# +# Machine dependent make include file for gcc +# +# +#CC=gcc +CPLUSPLUS=$(CC) +AR=ar +LINK=$(CC) +#MAKE=make +RM=rm +RANLIB=ranlib +# +# Machine dependent flags: +# +include $(LOCALBASE)/lib/tixConfig.sh +include $(LOCALBASE)/lib/tcl$(TCL_VER)/tclConfig.sh +include $(LOCALBASE)/lib/tk$(TK_VER)/tkConfig.sh +tcltklib = `echo $(TIX_BUILD_LIB_SPEC)` `echo $(TK_LIB_SPEC)` `echo $(TCL_LIB_FLAG)` + +CFLAGS2 = +CPLUSPLUSFLAGS2 = $(CXXFLAGS) -I$(X11BASE)/include -DLINUX -DOPENGL +CPLUSPLUSFLAGS3 = -I$(LIBSRC_DIR)/step `echo $(TCL_INCLUDE_SPEC)` `echo -I$(TK_PREFIX)`/include/tk`echo $(TK_VERSION)` +# +LINKFLAGS2 = -L$(LOCALBASE)/lib -L$(X11BASE)/lib + +SYSLIB2 = -lstdc++ diff --git a/contrib/Netgen/libsrc/makefile.mach.INTEL b/contrib/Netgen/libsrc/makefile.mach.INTEL new file mode 100644 index 0000000000..deef5b091c --- /dev/null +++ b/contrib/Netgen/libsrc/makefile.mach.INTEL @@ -0,0 +1,34 @@ +# +# Machine dependent make include file +# +CC=icc +CPLUSPLUS=$(CC) +AR=ar +LINK=$(CC) +MAKE=make +RM=rm +RANLIB=ranlib +# +# Machine dependent flags: +# +CFLAGS2 = +CPLUSPLUSFLAGS2 = -O2 -wd1572 -Ob2 -DLINUX -DOPENGL -DNGSOLVE \ + -Qoption,c,-ip_ninl_max_stats=1000 \ + -Qoption,c,-ip_ninl_min_stats=50 \ + -Qoption,c,-ip_ninl_max_total_stats=1000 \ + -gcc-name=/usr/bin/g++ +# +LINKFLAGS2 = -L/usr/openwin/lib -L/usr/X11R6/lib -L/usr/lib/GL3.5 \ + -gcc-name=/usr/bin/g++ +# +# SYSLIB2 = /opt/experimental/lib/libstdc++.a +# SYSLIB2 = -lstdc++ +# -lgcc_s +# SYSLIB2 = -L/usr/lib/lapack -lblas -lstdc++ + +# goalngs = goalngs + + +goalngs=goalngs + +appngs = lib/$(MACHINE)/*.o -lngsolvebasic \ No newline at end of file diff --git a/contrib/Netgen/libsrc/makefile.mach.LINUX b/contrib/Netgen/libsrc/makefile.mach.LINUX new file mode 100644 index 0000000000..f5df356167 --- /dev/null +++ b/contrib/Netgen/libsrc/makefile.mach.LINUX @@ -0,0 +1,31 @@ +# +# Machine dependent make include file +# +# +# CC=/opt/gcc-dev/bin/gcc +# CC=/usr/local/bin/gcc +CC=gcc +CPLUSPLUS=$(CC) +AR=ar +LINK=$(CC) +MAKE=make +RM=rm +RANLIB=ranlib +# +# Machine dependent flags: +# +CFLAGS2 = + +CPLUSPLUSFLAGS2 = -O2 -I/usr/include/GL3.5 -DLINUX -DOPENGL \ + -ftemplate-depth-99 -finline-limit=20000 \ + -funroll-loops -DNGSOLVE + +LINKFLAGS2 = -L/usr/openwin/lib -L/usr/X11R6/lib -L/usr/lib/GL3.5 -lstdc++ + + +goalngs=goalngs + +# lapack = -llapack -lblas -lgmp -lg2c + + +appngs = lib/$(MACHINE)/*.o -lngsolvebasic \ No newline at end of file diff --git a/contrib/Netgen/libsrc/makefile.mach.LINUXGCC33 b/contrib/Netgen/libsrc/makefile.mach.LINUXGCC33 new file mode 100644 index 0000000000..0a6ee84afb --- /dev/null +++ b/contrib/Netgen/libsrc/makefile.mach.LINUXGCC33 @@ -0,0 +1,33 @@ +# +# Machine dependent make include file +# +# +# CC=/opt/gcc33/bin/gcc +# CC=/usr/local/bin/gcc +CC=gcc +CPLUSPLUS=$(CC) +AR=ar +LINK=$(CC) +MAKE=make +RM=rm +RANLIB=ranlib +# +# +CFLAGS2 = +CPLUSPLUSFLAGS2 = -O2 -DLINUX -DOPENGL \ + -ftemplate-depth-99 -finline-limit=20000 \ + -mcpu=pentium4 -fforce-addr -funroll-loops \ + -DnoTRAFO -DNGSOLVE -DnoADDON -DnoPML -DnoLAPACK \ + -DnoOCCGEOMETRY -I/usr/include/g++/backward -I./occ/inc -DnoDEBUG +# +# +# +LINKFLAGS2 = -L/usr/openwin/lib -L/usr/X11R6/lib -L/usr/lib/GL3.5 + +SYSLIB2 = -lstdc++ + +goalngs = goalngs + +appngs = lib/$(MACHINE)/*.o -lngsolvebasic + +# occlib = -L$(OCCLIB_DIR) -lTKIGES -lTKBRep -lTKSTEP -lTKSTL \ No newline at end of file diff --git a/contrib/Netgen/libsrc/makefile.mach.SGI b/contrib/Netgen/libsrc/makefile.mach.SGI new file mode 100644 index 0000000000..b75920ce26 --- /dev/null +++ b/contrib/Netgen/libsrc/makefile.mach.SGI @@ -0,0 +1,19 @@ +# +# Machine dependent make include file +# +CC=CC +CPLUSPLUS=$(CC) +AR=ar +LINK=$(CC) +MAKE=make -k +RM=rm +RANLIB=echo +# +CFLAGS2 = +# +CPLUSPLUSFLAGS2 = -O2 -LANG:std -OPT:Olimit=0 -I/usr/X11R6/include -I/usr/local/include -I/nfs/home/joachim/tcltk/include -DOPENGL -woff 1174 -woff 1682 -woff 1681 -woff 1552 -DOLDCINCLUDE +# -woff 3262,3203,1174,1110 +# +# -I/usr/freeware/include +LINKFLAGS2 = -LANG:std -L/usr/openwin/lib -L/usr/freeware/lib32 -L/usr/X11R6/lib -L/usr/local/lib -w -L/nfs/home/joachim/tcltk/lib + diff --git a/contrib/Netgen/libsrc/makefile.mach.SGIGCC b/contrib/Netgen/libsrc/makefile.mach.SGIGCC new file mode 100644 index 0000000000..c43363c5e7 --- /dev/null +++ b/contrib/Netgen/libsrc/makefile.mach.SGIGCC @@ -0,0 +1,53 @@ +# +# Machine dependent make include file +# +# +# CC=/opt/experimental/bin/gcc +CC=/usr/freeware/bin/gcc +CPLUSPLUS=$(CC) +AR=ar +LINK=$(CC) +MAKE=make +RM=rm +RANLIB=ranlib +# +# Machine dependent flags: +# +CFLAGS2 = +# I/opt/experimental/include/g++-v3 +CPLUSPLUSFLAGS2 = -O2 -save-temps -fverbose-asm -I/usr/local/include -I/usr/freeware/include -I/usr/freeware/include/tcl -I/usr/freeware/include/tk -I/usr/include/GL3.5 -DLINUX -DOPENGL -I../lapack/\ + -ftemplate-depth-99 +# -finline-limit=10000 +# -mcpu=pentiumpro -fforce-addr -Wdisabled-optimization -funroll-loops +# -funroll-all-loops +# -dr -dt -df +# -fforce-addr \ +# -fssa -fdce -fschedule-insns2 -fstrict-aliasing -frename-registers \ +# -freg-struct-return +# -fargument-noalias-global -fargument-noalias \ +# --param max-gcse-memory=100000000 \ +# --param max-delay-slot-live-search=100000 \ +# --param max-pending-list-length=10000 \ +# -fssa \ +# -fomit-frame-pointer -fno-enforce-eh-specs -fno-defer-pop \ +# -fforce-mem -fstrict-aliasing \ +# -fno-implement-inlines \ +# -foptimize-sibling-calls \ +# -frerun-cse-after-loop -fcse-follow-jumps -fexpensive-optimizations \ +# -fstrength-reduce -frerun-loop-opt -fcse-skip-blocks -fgcse \ +# -pedantic \ +# -fno-implicit-templates +# +# -I/usr/local/intel/mkl/INCLUDE +# -fsyntax-only +# -fomit-frame-pointer +# -funroll-loops +# +LINKFLAGS2 = -L/usr/local/lib -L/usr/openwin/lib -L/usr/X11R6/lib -L/usr/lib/GL3.5 -L/usr/freeware/lib32 -L/usr/X11R6/lib -L/usr/local/lib + +# SYSLIB2 = libstdc++. +# SYSLIB2 = -lstdc++ +# -lgcc_s +# SYSLIB2 = -L/usr/lib/lapack -lblas -lstdc++ + + diff --git a/contrib/Netgen/libsrc/makefile.mach.SUN b/contrib/Netgen/libsrc/makefile.mach.SUN new file mode 100644 index 0000000000..f927ae06f1 --- /dev/null +++ b/contrib/Netgen/libsrc/makefile.mach.SUN @@ -0,0 +1,16 @@ +# +# Machine dependent make include file +# +CC=CC +CPLUSPLUS=$(CC) +AR=ar +LINK=$(CC) +MAKE=make -k +RM=rm +RANLIB=ranlib +# +CFLAGS2 = +# +CPLUSPLUSFLAGS2 = -fast -O2 -I/usr/openwin/share/include +LINKFLAGS2 = -L/usr/openwin/lib + diff --git a/contrib/Netgen/libsrc/meshing/Makefile b/contrib/Netgen/libsrc/meshing/Makefile new file mode 100644 index 0000000000..c0f17db986 --- /dev/null +++ b/contrib/Netgen/libsrc/meshing/Makefile @@ -0,0 +1,16 @@ +src = adfront2.cpp adfront3.cpp geomsearch.cpp global.cpp \ + meshtool.cpp \ + netrule2.cpp netrule3.cpp parser2.cpp parser3.cpp ruler2.cpp ruler3.cpp \ + meshtype.cpp meshclass.cpp improve2.cpp smoothing2.cpp improve3.cpp smoothing3.cpp \ + improve2gen.cpp meshing2.cpp meshing3.cpp \ + localh.cpp delaunay.cpp topology.cpp clusters.cpp \ + tetrarls.cpp triarls.cpp quadrls.cpp meshfunc.cpp meshfunc2d.cpp \ + refine.cpp bisect.cpp zrefine.cpp secondorder.cpp hprefinement.cpp \ + boundarylayer.cpp specials.cpp msghandler.cpp \ + pyramidrls.cpp pyramid2rls.cpp prism2rls.cpp curvedelems.cpp curvedelems2.cpp +# +lib = mesh +libpath = libsrc/meshing +# +include ../makefile.inc +# diff --git a/contrib/Netgen/libsrc/meshing/adfront2.cpp b/contrib/Netgen/libsrc/meshing/adfront2.cpp new file mode 100644 index 0000000000..01b591f477 --- /dev/null +++ b/contrib/Netgen/libsrc/meshing/adfront2.cpp @@ -0,0 +1,526 @@ +/* + Advancing front class for surfaces +*/ + +#include <mystdlib.h> +#include "meshing.hpp" + + +namespace netgen +{ + + /* +AdFront2::FrontPoint2 :: FrontPoint2 () +{ + globalindex = 0; + nlinetopoint = 0; + frontnr = INT_MAX-10; // attention: overflow on calculating INT_MAX + 1 + mgi = NULL; +} + */ + +AdFront2::FrontPoint2 :: FrontPoint2 (const Point3d & ap, PointIndex agi, + MultiPointGeomInfo * amgi) +{ + p = ap; + globalindex = agi; + nlinetopoint = 0; + frontnr = INT_MAX-10; + + if (amgi) + { + mgi = new MultiPointGeomInfo (*amgi); + for (int i = 1; i <= mgi->GetNPGI(); i++) + if (mgi->GetPGI(i).trignum <= 0) + cout << "Add FrontPoint2, illegal geominfo = " << mgi->GetPGI(i).trignum << endl; + } + else + mgi = NULL; +} + +/* +AdFront2::FrontPoint2 :: ~FrontPoint2 () +{ +// if (mgi) delete mgi; +} +*/ + + +AdFront2::FrontLine :: FrontLine () +{ + lineclass = 1; +} + +AdFront2::FrontLine :: FrontLine (const INDEX_2 & al) +{ + l = al; + lineclass = 1; +} + + + + + + +AdFront2 :: AdFront2 (const Box3d & aboundingbox) + : boundingbox(aboundingbox), + linesearchtree(boundingbox.PMin(), boundingbox.PMax()), + cpointsearchtree(boundingbox.PMin(), boundingbox.PMax()) +{ + nfl = 0; + // allflines = new INDEX_2_HASHTABLE<int> (100000); + allflines = 0; + + minval = 0; + starti = 1; +} + +AdFront2 :: ~AdFront2 () +{ + delete allflines; +} + + +void AdFront2 :: PrintOpenSegments (ostream & ost) const +{ + if (nfl > 0) + { + int i; + ost << nfl << " open front segments left:" << endl; + for (i = 1; i <= lines.Size(); i++) + if (lines.Get(i).Valid()) + ost << GetGlobalIndex (lines.Get(i).L().I1()) << "-" + << GetGlobalIndex (lines.Get(i).L().I2()) << endl; + + } +} + + +void AdFront2 :: GetPoints (ARRAY<Point3d> & apoints) const +{ + for (int i = 0; i < points.Size(); i++) + apoints.Append (points[i].P()); +} + + + + + +INDEX AdFront2 :: AddPoint (const Point3d & p, PointIndex globind, + MultiPointGeomInfo * mgi) +{ + // inserts at empty position or resizes array + int pi; + + if (delpointl.Size() != 0) + { + pi = delpointl.Last(); + delpointl.DeleteLast (); + + points.Elem(pi) = FrontPoint2 (p, globind, mgi); + } + else + { + pi = points.Append (FrontPoint2 (p, globind, mgi)); + } + + if (mgi) + { + cpointsearchtree.Insert (p, pi); + } + + return pi; +} + + +INDEX AdFront2 :: AddLine (INDEX pi1, INDEX pi2, + const PointGeomInfo & gi1, const PointGeomInfo & gi2) +{ + int minfn; + INDEX li; + + FrontPoint2 & p1 = points.Elem(pi1); + FrontPoint2 & p2 = points.Elem(pi2); + + + + nfl++; + + p1.AddLine(); + p2.AddLine(); + + minfn = min2 (p1.FrontNr(), p2.FrontNr()); + p1.DecFrontNr (minfn+1); + p2.DecFrontNr (minfn+1); + + if (dellinel.Size() != 0) + { + li = dellinel.Last(); + dellinel.DeleteLast (); + + lines.Elem(li) = FrontLine (INDEX_2(pi1, pi2)); + } + else + { + li = lines.Append(FrontLine (INDEX_2(pi1, pi2))); + } + + + if (!gi1.trignum || !gi2.trignum) + { + cout << "ERROR: in AdFront::AddLine, illegal geominfo" << endl; + } + + lines.Elem(li).SetGeomInfo (gi1, gi2); + + Box3d lbox; + lbox.SetPoint(p1.P()); + lbox.AddPoint(p2.P()); + + linesearchtree.Insert (lbox.PMin(), lbox.PMax(), li); + + /* + (*testout) << "add front line: " << p1.P() << " - " << p2.P() + << " Dist = " << Dist (p1.P(), p2.P()) << endl; + */ + + if (allflines) + { + if (allflines->Used (INDEX_2 (GetGlobalIndex (pi1), + GetGlobalIndex (pi2)))) + { + cerr << "ERROR Adfront2::AddLine: line exists" << endl; + (*testout) << "ERROR Adfront2::AddLine: line exists" << endl; + } + + allflines->Set (INDEX_2 (GetGlobalIndex (pi1), + GetGlobalIndex (pi2)), 1); + } + + return li; +} + + +void AdFront2 :: DeleteLine (INDEX li) +{ + int i; + INDEX pi; + + nfl--; + + for (i = 1; i <= 2; i++) + { + pi = lines.Get(li).L().I(i); + points.Elem(pi).RemoveLine(); + + if (!points.Get(pi).Valid()) + { + delpointl.Append (pi); + if (points.Elem(pi).mgi) + { + cpointsearchtree.DeleteElement (pi); + delete points.Elem(pi).mgi; + points.Elem(pi).mgi = NULL; + } + } + } + + if (allflines) + { + allflines->Set (INDEX_2 (GetGlobalIndex (lines.Get(li).L().I1()), + GetGlobalIndex (lines.Get(li).L().I2())), 2); + } + + lines.Elem(li).Invalidate(); + linesearchtree.DeleteElement (li); + + + + dellinel.Append (li); +} + + +int AdFront2 :: ExistsLine (int pi1, int pi2) +{ + if (!allflines) + return 0; + if (allflines->Used (INDEX_2(pi1, pi2))) + return allflines->Get (INDEX_2 (pi1, pi2)); + else + return 0; +} + + + +void AdFront2 :: IncrementClass (INDEX li) +{ + lines.Elem(li).IncrementClass(); +} + + +void AdFront2 :: ResetClass (INDEX li) +{ + lines.Elem(li).ResetClass(); +} + + + +int AdFront2 :: SelectBaseLine (Point3d & p1, Point3d & p2, + const PointGeomInfo *& geominfo1, + const PointGeomInfo *& geominfo2, + int & qualclass) +{ + int i, hi; + + /* + int minval; + int baselineindex; + minval = INT_MAX; + for (i = 1; i <= lines.Size(); i++) + if (lines.Get(i).Valid()) + { + hi = lines.Get(i).LineClass() + + points.Get(lines.Get(i).L().I1()).FrontNr() + + points.Get(lines.Get(i).L().I2()).FrontNr(); + + if (hi < minval) + { + minval = hi; + baselineindex = i; + } + } + */ + + /* + static int minval = 0; + static int starti = 1; + */ + int baselineindex = 0; + + for (i = starti; i <= lines.Size(); i++) + { + if (lines.Get(i).Valid()) + // const ILINE * lp = &lines.Get(i).l; + // if (lp->I1() >= 0) + { + hi = lines.Get(i).LineClass() + + points.Get(lines.Get(i).L().I1()).FrontNr() + + points.Get(lines.Get(i).L().I2()).FrontNr(); + + if (hi <= minval) + { + minval = hi; + baselineindex = i; + break; + } + } + } + + if (!baselineindex) + { + // (*testotu) << "nfl = " << nfl << " tot l = " << lines.Size() << endl; + minval = INT_MAX; + for (i = 1; i <= lines.Size(); i++) + if (lines.Get(i).Valid()) + { + hi = lines.Get(i).LineClass() + + points.Get(lines.Get(i).L().I1()).FrontNr() + + points.Get(lines.Get(i).L().I2()).FrontNr(); + + if (hi < minval) + { + minval = hi; + baselineindex = i; + } + } + } + starti = baselineindex+1; + + + + p1 = points.Get(lines.Get(baselineindex).L().I1()).P(); + p2 = points.Get(lines.Get(baselineindex).L().I2()).P(); + geominfo1 = &lines.Get(baselineindex).GetGeomInfo(1); + geominfo2 = &lines.Get(baselineindex).GetGeomInfo(2); + + qualclass = lines.Get(baselineindex).LineClass(); + + return baselineindex; +} + + + + +int AdFront2 :: GetLocals (int baselineindex, + ARRAY<Point3d> & locpoints, + ARRAY<MultiPointGeomInfo> & pgeominfo, + ARRAY<INDEX_2> & loclines, // local index + ARRAY<INDEX> & pindex, + ARRAY<INDEX> & lindex, + double xh) +{ + int i, j, ii; + int pstind; + int pi; + Point3d midp, p0; + + pstind = lines.Get(baselineindex).L().I1(); + p0 = points.Get(pstind).P(); + + loclines.Append(lines.Get(baselineindex).L()); + lindex.Append(baselineindex); + + static ARRAY<int> nearlines; + + nearlines.SetSize(0); + + linesearchtree.GetIntersecting (p0 - Vec3d(xh, xh, xh), + p0 + Vec3d(xh, xh, xh), + nearlines); + + for (ii = 1; ii <= nearlines.Size(); ii++) + { + i = nearlines.Get(ii); + + if (lines.Get(i).Valid() && i != baselineindex) + { + // const Point3d & p1 = points.Get(lines.Get(i).L().I1()).P(); + // const Point3d & p2 = points.Get(lines.Get(i).L().I2()).P(); + + // midp = Center (p1, p2); + // if (Dist (midp, p0) <= xh + 0.5 * Dist (p1, p2)) + { + loclines.Append(lines.Get(i).L()); + lindex.Append(i); + } + } + } + + static ARRAY<int> invpindex; + + invpindex.SetSize (points.Size()); + for (i = 1; i <= loclines.Size(); i++) + { + invpindex.Elem(loclines.Get(i).I1()) = 0; + invpindex.Elem(loclines.Get(i).I2()) = 0; + } + + for (i = 1; i <= loclines.Size(); i++) + { + for (j = 1; j <= 2; j++) + { + pi = loclines.Get(i).I(j); + if (invpindex.Get(pi) == 0) + { + pindex.Append (pi); + invpindex.Elem(pi) = pindex.Size(); + loclines.Elem(i).I(j) = locpoints.Append (points.Get(pi).P()); + } + else + loclines.Elem(i).I(j) = invpindex.Get(pi); + } + } + + pgeominfo.SetSize (locpoints.Size()); + for (i = 1; i <= pgeominfo.Size(); i++) + pgeominfo.Elem(i).Init(); + + + for (i = 1; i <= loclines.Size(); i++) + for (j = 1; j <= 2; j++) + { + int lpi = loclines.Get(i).I(j); + + const PointGeomInfo & gi = + lines.Get(lindex.Get(i)).GetGeomInfo (j); + pgeominfo.Elem(lpi).AddPointGeomInfo (gi); + + /* + if (pgeominfo.Elem(lpi).cnt == MULTIPOINTGEOMINFO_MAX) + break; + + const PointGeomInfo & gi = + lines.Get(lindex.Get(i)).GetGeomInfo (j); + + PointGeomInfo * pgi = pgeominfo.Elem(lpi).mgi; + + int found = 0; + for (k = 0; k < pgeominfo.Elem(lpi).cnt; k++) + if (pgi[k].trignum == gi.trignum) + found = 1; + + if (!found) + { + pgi[pgeominfo.Elem(lpi).cnt] = gi; + pgeominfo.Elem(lpi).cnt++; + } + */ + } + + for (i = 1; i <= locpoints.Size(); i++) + { + int pi = pindex.Get(i); + + if (points.Get(pi).mgi) + for (j = 1; j <= points.Get(pi).mgi->GetNPGI(); j++) + pgeominfo.Elem(i).AddPointGeomInfo (points.Get(pi).mgi->GetPGI(j)); + } + + + + /* + for (i = 1; i <= points.Size(); i++) + if (points.Get(i).Valid() && + Dist (points.Get(i).P(), p0) <= xh && + invpindex.Get(i) == 0) + { + invpindex.Elem(i) = + locpoints.Append (points.Get(pi).P()); + } + */ + + if (loclines.Size() == 1) + { + cout << "loclines.Size = 1" << endl; + (*testout) << "loclines.size = 1" << endl + << " h = " << xh << endl + << " nearline.size = " << nearlines.Size() << endl + << " p0 = " << p0 << endl; + } + + return lines.Get(baselineindex).LineClass(); +} + + + +void AdFront2 :: SetStartFront () +{ + INDEX i; + int j; + + for (i = 1; i <= lines.Size(); i++) + if (lines.Get(i).Valid()) + for (j = 1; j <= 2; j++) + points.Elem(lines.Get(i).L().I(j)).DecFrontNr(0); +} + + + + +void AdFront2 :: Print (ostream & ost) const +{ + INDEX i; + + ost << points.Size() << " Points: " << endl; + for (i = 1; i <= points.Size(); i++) + if (points.Get(i).Valid()) + ost << i << " " << points.Get(i).P() << endl; + + ost << nfl << " Lines: " << endl; + for (i = 1; i <= lines.Size(); i++) + if (lines.Get(i).Valid()) + ost << lines.Get(i).L().I1() << " - " << lines.Get(i).L().I2() << endl; + + ost << flush; +} +} diff --git a/contrib/Netgen/libsrc/meshing/adfront2.hpp b/contrib/Netgen/libsrc/meshing/adfront2.hpp new file mode 100644 index 0000000000..4e72c087fb --- /dev/null +++ b/contrib/Netgen/libsrc/meshing/adfront2.hpp @@ -0,0 +1,337 @@ +#ifndef FILE_ADFRONT2 +#define FILE_ADFRONT2 + +/**************************************************************************/ +/* File: adfront2.hh */ +/* Author: Joachim Schoeberl */ +/* Date: 01. Okt. 95 */ +/**************************************************************************/ + +/* + Advancing front class for surfaces +*/ + + +/* +#define FRONTLINE_GEOMINFO_SIZE 8 +#define FRONTPOINT_GEOMINFO_SIZE 4 +*/ + +/// +class AdFront2 +{ + + /// + class FrontPoint2 + { + /// coordinates + Point3d p; + /// global node index + PointIndex globalindex; + /// number of front lines connected to point + int nlinetopoint; + /// distance to original boundary + int frontnr; + // char geominfo[FRONTLINE_GEOMINFO_SIZE]; + public: + /// + MultiPointGeomInfo * mgi; + + /// + FrontPoint2 () + { + globalindex = -1; + nlinetopoint = 0; + frontnr = INT_MAX-10; // attention: overflow on calculating INT_MAX + 1 + mgi = NULL; + } + + /// + FrontPoint2 (const Point3d & ap, PointIndex agi, + MultiPointGeomInfo * amgi); + /// + ~FrontPoint2 () { ; } + + /// + const Point3d & P () const { return p; } + /// + PointIndex GlobalIndex () const { return globalindex; } + + /// + void AddLine () { nlinetopoint++; } + /// + void RemoveLine () + { + nlinetopoint--; + if (nlinetopoint == 0) + nlinetopoint = -1; + } + + /// + bool Valid () const + { return nlinetopoint >= 0; } + + /// + void DecFrontNr (int afrontnr) + { + if (frontnr > afrontnr) frontnr = afrontnr; + } + + /// + int FrontNr () const { return frontnr; } + }; + + + /// + class FrontLine + { + private: + /// Point Indizes + INDEX_2 l; + /// quality class + int lineclass; + /// geometry specific data + // char geominfo[FRONTLINE_GEOMINFO_SIZE]; + PointGeomInfo geominfo[2]; + public: + + FrontLine (); + /// + FrontLine (const INDEX_2 & al); + + /// + const INDEX_2 & L () const + { + return l; + } + + /// + int LineClass() const + { + return lineclass; + } + + /// + void IncrementClass () + { + lineclass++; + } + /// + void ResetClass () + { + lineclass = 1; + } + + /// + bool Valid () const + { + return l.I1() != -1; + } + /// + void Invalidate () + { + l.I1() = -1; + l.I2() = -1; + lineclass = 1000; + } + + void SetGeomInfo (const PointGeomInfo & gi1, const PointGeomInfo & gi2) + { + geominfo[0] = gi1; + geominfo[1] = gi2; + } + + const PointGeomInfo * GetGeomInfo () const + { return geominfo; } + + const PointGeomInfo & GetGeomInfo (int endp) const + { return geominfo[endp-1]; } + + friend class AdFront2; + }; + + + + /// + ARRAY<FrontPoint2> points; /// front points + ARRAY<FrontLine> lines; /// front lines + + Box3d boundingbox; + Box3dTree linesearchtree; /// search tree for lines + Point3dTree cpointsearchtree; /// search tree for cone points + + ARRAY<INDEX> delpointl; /// list of deleted front points + ARRAY<INDEX> dellinel; /// list of deleted front lines + + INDEX nfl; /// number of front lines; + INDEX_2_HASHTABLE<int> * allflines; /// all front lines ever have been + + + int minval; + int starti; + +public: + /// + // AdFront2 (); + AdFront2 (const Box3d & aboundingbox); + /// + ~AdFront2 (); + + /// + void GetPoints (ARRAY<Point3d> & apoints) const; + /// + void Print (ostream & ost) const; + + /// + bool Empty () const + { + return nfl == 0; + } + /// + int GetNFL () const { return nfl; } + /// + int SelectBaseLine (Point3d & p1, Point3d & p2, + const PointGeomInfo *& geominfo1, + const PointGeomInfo *& geominfo2, + int & qualclass); + + /// + int GetLocals (int baseline, + ARRAY<Point3d> & locpoints, + ARRAY<MultiPointGeomInfo> & pgeominfo, + ARRAY<INDEX_2> & loclines, // local index + ARRAY<INDEX> & pindex, + ARRAY<INDEX> & lindex, + double xh); + + /// + void DeleteLine (INDEX li); + /// + INDEX AddPoint (const Point3d & p, PointIndex globind, + MultiPointGeomInfo * mgi = NULL); + /// + INDEX AddLine (INDEX pi1, INDEX pi2, + const PointGeomInfo & gi1, const PointGeomInfo & gi2); + /// + int ExistsLine (int gpi1, int gpi2); + /// + void IncrementClass (INDEX li); + /// + void ResetClass (INDEX li); + + /// + const PointGeomInfo & GetLineGeomInfo (int li, int lend) const + { return lines.Get(li).GetGeomInfo (lend); } + /// + + PointIndex GetGlobalIndex (int pi) const + { + return points.Get(pi).GlobalIndex(); + } + /// + void SetStartFront (); + /// + void PrintOpenSegments (ostream & ost) const; +}; + + + + + + +/* +inline int AdFront2::FrontPoint2 :: Valid () const +{ + return nlinetopoint >= 0; +} +*/ +/* +inline const Point3d & AdFront2::FrontPoint2 :: P () const +{ + return p; +} + +inline PointIndex AdFront2::FrontPoint2 :: GlobalIndex () const +{ + return globalindex; +} + +inline void AdFront2::FrontPoint2 :: AddLine () +{ + nlinetopoint++; +} + +inline void AdFront2::FrontPoint2 :: RemoveLine () +{ + nlinetopoint--; + if (nlinetopoint == 0) + nlinetopoint = -1; +} + +inline int AdFront2::FrontPoint2 :: FrontNr () const +{ + return frontnr; +} + +inline void AdFront2::FrontPoint2 :: DecFrontNr (int afrontnr) +{ + if (frontnr > afrontnr) frontnr = afrontnr; +} +*/ + + + + + + + + +/* +inline int AdFront2::FrontLine :: Valid () const +{ + return l.I1() != 0; +} + +inline void AdFront2::FrontLine :: Invalidate () +{ + l.I1() = 0; + l.I2() = 0; + lineclass = 1000; +} + +inline const INDEX_2 & AdFront2::FrontLine :: L () const +{ + return l; +} + +inline int AdFront2::FrontLine :: LineClass () const +{ + return lineclass; +} + + +inline void AdFront2::FrontLine :: IncrementClass () +{ + lineclass++; +} + +inline void AdFront2::FrontLine :: ResetClass () +{ + lineclass = 1; +} + + +inline int AdFront2 :: Empty () const +{ + return nfl == 0; +} + +inline INDEX AdFront2 :: GetGlobalIndex (INDEX pi) const +{ + return points.Get(pi).GlobalIndex(); +} +*/ +#endif + + + diff --git a/contrib/Netgen/libsrc/meshing/adfront3.cpp b/contrib/Netgen/libsrc/meshing/adfront3.cpp new file mode 100644 index 0000000000..1bf686e103 --- /dev/null +++ b/contrib/Netgen/libsrc/meshing/adfront3.cpp @@ -0,0 +1,883 @@ +#include <mystdlib.h> +#include "meshing.hpp" + + +/* ********************** FrontPoint ********************** */ + +namespace netgen +{ + +FrontPoint3 :: FrontPoint3 () +{ + globalindex = -1; + nfacetopoint = 0; + frontnr = 1000; + cluster = 0; +} + + +FrontPoint3 :: FrontPoint3 (const Point3d & ap, PointIndex agi) +{ + p = ap; + globalindex = agi; + nfacetopoint = 0; + frontnr = 1000; + cluster = 0; +} + + + +/* ********************** FrontFace ********************** */ + +FrontFace :: FrontFace () +{ + qualclass = 1; + oldfront = 0; + hashvalue = 0; + cluster = 0; +} + +FrontFace :: FrontFace (const Element2d & af) +{ + f = af; + oldfront = 0; + qualclass = 1; + hashvalue = 0; +} + +void FrontFace :: Invalidate () +{ + f.Delete(); + oldfront = 0; + qualclass = 1000; +} + + + + +/* ********************** AddFront ********************** */ + + +AdFront3 :: AdFront3 () +{ + nff = 0; + nff4 = 0; + vol = 0; + + hashon = 1; + hashcreated = 0; + if (hashon) + hashtable.Init(&points, &faces); + + facetree = NULL; + connectedpairs = NULL; + + rebuildcounter = -1; + lasti = 0; + minval = -1; +} + + +AdFront3 :: ~AdFront3 () +{ + delete facetree; + delete connectedpairs; +} + +void AdFront3 :: GetPoints (ARRAY<Point3d> & apoints) const +{ + for (PointIndex pi = PointIndex::BASE; + pi < points.Size()+PointIndex::BASE; pi++) + + apoints.Append (points[pi].P()); +} + + +PointIndex AdFront3 :: AddPoint (const Point3d & p, PointIndex globind) +{ + if (delpointl.Size()) + { + PointIndex pi = delpointl.Last(); + delpointl.DeleteLast (); + + points[pi] = FrontPoint3 (p, globind); + return pi; + } + else + { + points.Append (FrontPoint3 (p, globind)); + return points.Size()-1+PointIndex::BASE; + } +} + + +INDEX AdFront3 :: AddFace (const Element2d & aface) +{ + int i, minfn; + + nff++; + + for (i = 0; i < aface.GetNP(); i++) + points[aface[i]].AddFace(); + + const Point3d & p1 = points[aface[0]].P(); + const Point3d & p2 = points[aface[1]].P(); + const Point3d & p3 = points[aface[2]].P(); + + vol += 1.0/6.0 * (p1.X() + p2.X() + p3.X()) * + ( (p2.Y() - p1.Y()) * (p3.Z() - p1.Z()) - + (p2.Z() - p1.Z()) * (p3.Y() - p1.Y()) ); + + if (aface.GetNP() == 4) + { + nff4++; + const Point3d & p4 = points[aface[3]].P(); + vol += 1.0/6.0 * (p1.X() + p3.X() + p4.X()) * + ( (p3.Y() - p1.Y()) * (p4.Z() - p1.Z()) - + (p3.Z() - p1.Z()) * (p4.Y() - p1.Y()) ); + } + + + minfn = 1000; + for (i = 0; i < aface.GetNP(); i++) + { + int fpn = points[aface[i]].FrontNr(); + if (i == 0 || fpn < minfn) + minfn = fpn; + } + + + int cluster = 0; + for (i = 1; i <= aface.GetNP(); i++) + { + if (points[aface.PNum(i)].cluster) + cluster = points[aface.PNum(i)].cluster; + } + for (i = 1; i <= aface.GetNP(); i++) + points[aface.PNum(i)].cluster = cluster; + + + for (i = 1; i <= aface.GetNP(); i++) + points[aface.PNum(i)].DecFrontNr (minfn+1); + + int nfn = faces.Append(FrontFace (aface)); + faces.Elem(nfn).cluster = cluster; + + if (hashon && hashcreated) + hashtable.AddElem(aface, nfn); + + return nfn; +} + + + +void AdFront3 :: DeleteFace (INDEX fi) +{ + nff--; + + for (int i = 1; i <= faces.Get(fi).Face().GetNP(); i++) + { + PointIndex pi = faces.Get(fi).Face().PNum(i); + points[pi].RemoveFace(); + if (!points[pi].Valid()) + delpointl.Append (pi); + } + + const Element2d & face = faces.Get(fi).Face(); + const Point3d & p1 = points[face.PNum(1)].P(); + const Point3d & p2 = points[face.PNum(2)].P(); + const Point3d & p3 = points[face.PNum(3)].P(); + + vol -= 1.0/6.0 * (p1.X() + p2.X() + p3.X()) * + ( (p2.Y() - p1.Y()) * (p3.Z() - p1.Z()) - + (p2.Z() - p1.Z()) * (p3.Y() - p1.Y()) ); + + if (face.GetNP() == 4) + { + const Point3d & p4 = points[face.PNum(4)].P(); + vol -= 1.0/6.0 * (p1.X() + p3.X() + p4.X()) * + ( (p3.Y() - p1.Y()) * (p4.Z() - p1.Z()) - + (p3.Z() - p1.Z()) * (p4.Y() - p1.Y()) ); + + nff4--; + } + + faces.Elem(fi).Invalidate(); +} + + +INDEX AdFront3 :: AddConnectedPair (const INDEX_2 & apair) +{ + if (!connectedpairs) + connectedpairs = new TABLE<int, PointIndex::BASE> (GetNP()); + + connectedpairs->Add (apair.I1(), apair.I2()); + connectedpairs->Add (apair.I2(), apair.I1()); + + return 0; +} + + + +void AdFront3 :: IncrementClass (INDEX fi) +{ + faces.Elem(fi).IncrementQualClass(); +} + + +void AdFront3 :: ResetClass (INDEX fi) +{ + faces.Elem(fi).ResetQualClass(); +} + + + +void AdFront3 :: CreateTrees () +{ + int i, j; + PointIndex pi; + Point3d pmin, pmax; + + for (pi = PointIndex::BASE; + pi < GetNP()+PointIndex::BASE; pi++) + { + const Point3d & p = GetPoint(pi); + if (pi == PointIndex::BASE) + { + pmin = p; + pmax = p; + } + else + { + pmin.SetToMin (p); + pmax.SetToMax (p); + } + } + + pmax = pmax + 0.5 * (pmax - pmin); + pmin = pmin + 0.5 * (pmin - pmax); + + delete facetree; + facetree = new Box3dTree (pmin, pmax); + + for (i = 1; i <= GetNF(); i++) + { + const Element2d & el = GetFace(i); + pmin = GetPoint (el[0]); + pmax = pmin; + for (j = 1; j < 3; j++) + { + const Point3d & p = GetPoint (el[j]); + pmin.SetToMin (p); + pmax.SetToMax (p); + } + pmax = pmax + 0.01 * (pmax - pmin); + pmin = pmin + 0.01 * (pmin - pmax); + // (*testout) << "insert " << i << ": " << pmin << " - " << pmax << "\n"; + facetree -> Insert (pmin, pmax, i); + } +} + + +void AdFront3 :: GetIntersectingFaces (const Point3d & pmin, const Point3d & pmax, + ARRAY<int> & ifaces) const +{ + facetree -> GetIntersecting (pmin, pmax, ifaces); +} + +void AdFront3 :: GetFaceBoundingBox (int i, Box3d & box) const +{ + const FrontFace & face = faces.Get(i); + box.SetPoint (points[face.f[0]].p); + box.AddPoint (points[face.f[1]].p); + box.AddPoint (points[face.f[2]].p); +} + +void AdFront3 :: RebuildInternalTables () +{ + int i, j, hi; + + hi = 0; + for (i = 1; i <= faces.Size(); i++) + if (faces.Get(i).Valid()) + { + hi++; + if (hi < i) + faces.Elem(hi) = faces.Get(i); + } + + faces.SetSize (nff); + + int np = points.Size(); + + for (i = PointIndex::BASE; + i < np+PointIndex::BASE; i++) + points[i].cluster = i; + + int change; + do + { + change = 0; + for (i = 1; i <= faces.Size(); i++) + { + const Element2d & el = faces.Get(i).Face(); + + int mini = points[el.PNum(1)].cluster; + int maxi = mini; + + for (j = 2; j <= 3; j++) + { + int ci = points[el.PNum(j)].cluster; + if (ci < mini) mini = ci; + if (ci > maxi) maxi = ci; + } + + if (mini < maxi) + { + change = 1; + for (j = 1; j <= 3; j++) + points[el.PNum(j)].cluster = mini; + } + } + } + while (change); + + BitArrayChar<PointIndex::BASE> usecl(np); + usecl.Clear(); + for (i = 1; i <= faces.Size(); i++) + { + usecl.Set (points[faces.Get(i).Face().PNum(1)].cluster); + faces.Elem(i).cluster = + points[faces.Get(i).Face().PNum(1)].cluster; + } + int cntcl = 0; + for (i = PointIndex::BASE; + i < np+PointIndex::BASE; i++) + if (usecl.Test(i)) + cntcl++; + + ARRAY<double, PointIndex::BASE> clvol (np); + clvol = 0.0; + + for (i = 1; i <= faces.Size(); i++) + { + const Element2d & 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; + } + + + int negvol = 0; + for (i = PointIndex::BASE; + i < clvol.Size()+PointIndex::BASE; i++) + { + if (clvol[i] < 0) + negvol = 1; + } + + if (negvol) + { + for (i = 1; i <= faces.Size(); i++) + faces.Elem(i).cluster = 1; + for (i = PointIndex::BASE; + i < points.Size()+PointIndex::BASE; i++) + points[i].cluster = 1; + } + + if (hashon) + hashtable.Create(); +} + + + +int AdFront3 :: SelectBaseElement () +{ + int i, hi, fstind; + + /* + static int minval = -1; + static int lasti = 0; + static int counter = 0; + */ + if (rebuildcounter <= 0) + { + RebuildInternalTables(); + rebuildcounter = nff / 10 + 1; + + lasti = 0; + } + rebuildcounter--; + + /* + if (faces.Size() > 2 * nff) + { + // compress facelist + + RebuildInternalTables (); + lasti = 0; + } + */ + + fstind = 0; + + for (i = lasti+1; i <= faces.Size() && !fstind; i++) + if (faces.Elem(i).Valid()) + { + hi = faces.Get(i).QualClass() + + points[faces.Get(i).Face().PNum(1)].FrontNr() + + points[faces.Get(i).Face().PNum(2)].FrontNr() + + points[faces.Get(i).Face().PNum(3)].FrontNr(); + + if (hi <= minval) + { + minval = hi; + fstind = i; + lasti = fstind; + } + } + + if (!fstind) + { + minval = INT_MAX; + for (i = 1; i <= faces.Size(); i++) + if (faces.Elem(i).Valid()) + { + hi = faces.Get(i).QualClass() + + points[faces.Get(i).Face().PNum(1)].FrontNr() + + points[faces.Get(i).Face().PNum(2)].FrontNr() + + points[faces.Get(i).Face().PNum(3)].FrontNr(); + + if (hi <= minval) + { + minval = hi; + fstind = i; + lasti = 0; + } + } + } + + + return fstind; +} + + + +int AdFront3 :: GetLocals (int fstind, + ARRAY<Point3d> & locpoints, + ARRAY<Element2d> & locfaces, // local index + ARRAY<PointIndex> & pindex, + ARRAY<INDEX> & findex, + INDEX_2_HASHTABLE<int> & getconnectedpairs, + float xh, + float relh, + INDEX& facesplit) +{ + if (hashon && faces.Size() < 500) { hashon=0; } + if (hashon && !hashcreated) + { + hashtable.Create(); + hashcreated=1; + } + + INDEX i, j; + PointIndex pstind; + INDEX pi; + Point3d midp, p0; + + static ARRAY<int, PointIndex::BASE> invpindex; + + static ARRAY<Element2d> locfaces2; //all local faces in radius xh + static ARRAY<int> locfaces3; // all faces in outer radius relh + static ARRAY<INDEX> findex2; + + locfaces2.SetSize(0); + locfaces3.SetSize(0); + findex2.SetSize(0); + + int cluster = faces.Get(fstind).cluster; + + pstind = faces.Get(fstind).Face().PNum(1); + p0 = points[pstind].P(); + + locfaces2.Append(faces.Get(fstind).Face()); + findex2.Append(fstind); + + + Box3d b1 (p0 - Vec3d(xh, xh, xh), p0 + Vec3d (xh, xh, xh)); + + if (hashon) + { + hashtable.GetLocals(locfaces2, findex2, fstind, p0, xh); + } + else + { + for (i = 1; i <= faces.Size(); i++) + { + const Element2d & face = faces.Get(i).Face(); + if (faces.Get(i).cluster == cluster && faces.Get(i).Valid() && i != fstind) + { + const Point3d & p1 = points[face.PNum(1)].P(); + const Point3d & p2 = points[face.PNum(2)].P(); + const Point3d & p3 = points[face.PNum(3)].P(); + + Box3d b2; + b2.SetPoint (p1); + b2.AddPoint (p2); + b2.AddPoint (p3); + + /* + midp = Center (p1, p2, p3); + + if (Dist2 (midp, p0) <= xh*xh) + { + locfaces2.Append(faces.Get(i).Face()); + findex2.Append(i); + } + */ + if (b1.Intersect (b2)) + { + locfaces2.Append(faces.Get(i).Face()); + findex2.Append(i); + } + } + } + } + + //local faces for inner radius: + for (i = 1; i <= locfaces2.Size(); i++) + { + const Element2d & face = locfaces2.Get(i); + const Point3d & p1 = points[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) <= relh * relh || i == 1) + { + locfaces.Append(locfaces2.Get(i)); + findex.Append(findex2.Get(i)); + } + else + locfaces3.Append (i); + } + + facesplit=locfaces.Size(); + + + //local faces for outer radius: + for (i = 1; i <= locfaces3.Size(); i++) + { + locfaces.Append (locfaces2.Get(locfaces3.Get(i))); + findex.Append (findex2.Get(locfaces3.Get(i))); + } + + + invpindex.SetSize (points.Size()); + for (i = 1; i <= locfaces.Size(); i++) + for (j = 1; j <= locfaces.Get(i).GetNP(); j++) + { + pi = locfaces.Get(i).PNum(j); + invpindex[pi] = -1; + } + + for (i = 1; i <= locfaces.Size(); i++) + { + for (j = 1; j <= locfaces.Get(i).GetNP(); j++) + { + pi = locfaces.Get(i).PNum(j); + if (invpindex[pi] == -1) + { + pindex.Append (pi); + invpindex[pi] = pindex.Size(); // -1+PointIndex::BASE; + locfaces.Elem(i).PNum(j) = locpoints.Append (points[pi].P()); + } + else + locfaces.Elem(i).PNum(j) = invpindex[pi]; + + } + } + + + + if (connectedpairs) + { + for (i = 1; i <= locpoints.Size(); i++) + { + int pi = pindex.Get(i); + if (pi >= 1 && pi <= connectedpairs->Size ()) + { + for (j = 1; j <= connectedpairs->EntrySize(pi); j++) + { + int oi = connectedpairs->Get(pi, j); + int other = invpindex.Get(oi); + if (other >= 1 && other <= pindex.Size() && + pindex.Get(other) == oi) + { + INDEX_2 coned(i, other); + coned.Sort(); + // (*testout) << "connected: " << locpoints.Get(i) << "-" << locpoints.Get(other) << endl; + getconnectedpairs.Set (coned, 1); + } + } + } + } + } + + + + + /* + for (i = 1; i <= points.Size(); i++) + if (points.Elem(i).Valid() && Dist (points.Elem(i).P(), p0) <= xh) + { + if (!invpindex.Get(i)) + { + locpoints.Append (points.Get(i).P()); + pindex.Append (i); + invpindex.Elem(i) = pindex.Size(); + } + } + */ + return faces.Get(fstind).QualClass(); +} + + +// returns all points connected with fi +void AdFront3 :: GetGroup (int fi, + ARRAY<MeshPoint> & grouppoints, + ARRAY<Element2d> & groupelements, + ARRAY<PointIndex> & pindex, + ARRAY<INDEX> & findex + ) const +{ + static ARRAY<char> pingroup; + INDEX i; + int j, changed, fused; + + pingroup.SetSize(points.Size()); + + for (i = 1; i <= pingroup.Size(); i++) + pingroup.Elem(i) = 0; + for (j = 1; j <= 3; j++) + pingroup.Elem (faces.Get(fi).Face().PNum(j)) = 1; + + do + { + changed = 0; + + for (i = 1; i <= faces.Size(); i++) + if (faces.Get(i).Valid()) + { + const Element2d & face = faces.Get(i).Face(); + + + fused = 0; + for (j = 1; j <= 3; j++) + if (pingroup.Elem(face.PNum(j))) + fused++; + + if (fused >= 2) + for (j = 1; j <= 3; j++) + if (!pingroup.Elem(face.PNum(j))) + { + pingroup.Elem(face.PNum(j)) = 1; + changed = 1; + } + } + + } + while (changed); + + + static ARRAY<int> invpindex; + invpindex.SetSize (points.Size()); + + + for (i = 1; i <= points.Size(); i++) + if (points.Get(i).Valid()) + { + grouppoints.Append (points.Get(i).P()); + pindex.Append (i); + invpindex.Elem(i) = pindex.Size(); + } + + for (i = 1; i <= faces.Size(); i++) + if (faces.Get(i).Valid()) + { + fused = 0; + for (j = 1; j <= 3; j++) + if (pingroup.Get(faces.Get(i).Face().PNum(j))) + fused++; + + if (fused >= 2) + { + groupelements.Append (faces.Get(i).Face()); + findex.Append (i); + } + } + + for (i = 1; i <= groupelements.Size(); i++) + for (j = 1; j <= 3; j++) + { + groupelements.Elem(i).PNum(j) = + invpindex.Get(groupelements.Elem(i).PNum(j)); + } + + /* + for (i = 1; i <= groupelements.Size(); i++) + for (j = 1; j <= 3; j++) + for (k = 1; k <= grouppoints.Size(); k++) + if (pindex.Get(k) == groupelements.Get(i).PNum(j)) + { + groupelements.Elem(i).PNum(j) = k; + break; + } + */ +} + + +void AdFront3 :: SetStartFront (int /* baseelnp */) +{ + INDEX i; + int j; + + for (i = 1; i <= faces.Size(); i++) + if (faces.Get(i).Valid()) + { + const Element2d & face = faces.Get(i).Face(); + for (j = 1; j <= 3; j++) + points[face.PNum(j)].DecFrontNr(0); + } + + /* + if (baseelnp) + { + for (i = 1; i <= faces.Size(); i++) + if (faces.Get(i).Valid() && faces.Get(i).Face().GetNP() != baseelnp) + faces.Elem(i).qualclass = 1000; + } + */ +} + + +int AdFront3 :: Inside (const Point3d & p) const +{ + int i, cnt; + Vec3d n, v1, v2; + DenseMatrix a(3), ainv(3); + Vector b(3), u(3); + + // random numbers: + n.X() = 0.123871; + n.Y() = 0.15432; + n.Z() = -0.43989; + + cnt = 0; + for (i = 1; i <= faces.Size(); i++) + if (faces.Get(i).Valid()) + { + const Point3d & p1 = points[faces.Get(i).Face().PNum(1)].P(); + const Point3d & p2 = points[faces.Get(i).Face().PNum(2)].P(); + const Point3d & p3 = points[faces.Get(i).Face().PNum(3)].P(); + + v1 = p2 - p1; + v2 = p3 - p1; + + a.Elem(1, 1) = v1.X(); + a.Elem(2, 1) = v1.Y(); + a.Elem(3, 1) = v1.Z(); + a.Elem(1, 2) = v2.X(); + a.Elem(2, 2) = v2.Y(); + a.Elem(3, 2) = v2.Z(); + a.Elem(1, 3) = -n.X(); + a.Elem(2, 3) = -n.Y(); + a.Elem(3, 3) = -n.Z(); + + b.Elem(1) = p.X() - p1.X(); + b.Elem(2) = p.Y() - p1.Y(); + b.Elem(3) = p.Z() - p1.Z(); + + CalcInverse (a, ainv); + ainv.Mult (b, u); + + if (u.Elem(1) >= 0 && u.Elem(2) >= 0 && u.Elem(1)+u.Elem(2) <= 1 && + u.Elem(3) > 0) + { + cnt++; + } + } + + return (cnt % 2); +} + + + + + +int AdFront3 :: SameSide (const Point3d & lp1, const Point3d & lp2, + const ARRAY<int> * testfaces) const +{ + int i, ii, cnt; + + const Point3d *line[2]; + line[0] = &lp1; + line[1] = &lp2; + + + cnt = 0; + + Point3d pmin(lp1); + Point3d pmax(lp1); + pmin.SetToMin (lp2); + pmax.SetToMax (lp2); + + static ARRAY<int> aprif; + aprif.SetSize(0); + + if (!testfaces) + facetree->GetIntersecting (pmin, pmax, aprif); + else + { + for (i = 1; i <= testfaces->Size(); i++) + aprif.Append (testfaces->Get(i)); + } + + // (*testout) << "test ss, p1,p2 = " << lp1 << lp2 << ", inters = " << aprif.Size() << endl; + // for (i = 1; i <= faces.Size(); i++) + for (ii = 1; ii <= aprif.Size(); ii++) + { + i = aprif.Get(ii); + + if (faces.Get(i).Valid()) + { + const Point3d *tri[3]; + tri[0] = &points[faces.Get(i).Face().PNum(1)].P(); + tri[1] = &points[faces.Get(i).Face().PNum(2)].P(); + tri[2] = &points[faces.Get(i).Face().PNum(3)].P(); + + if (IntersectTriangleLine (&tri[0], &line[0])) + cnt++; + + } + } + + return ((cnt+1) % 2); +} +} diff --git a/contrib/Netgen/libsrc/meshing/adfront3.hpp b/contrib/Netgen/libsrc/meshing/adfront3.hpp new file mode 100644 index 0000000000..2c43f9334b --- /dev/null +++ b/contrib/Netgen/libsrc/meshing/adfront3.hpp @@ -0,0 +1,276 @@ +#ifndef FILE_ADFRONT3 +#define FILE_ADFRONT3 + +/**************************************************************************/ +/* File: adfront3.hh */ +/* Author: Joachim Schoeberl */ +/* Date: 01. Okt. 95 */ +/**************************************************************************/ + +/* + Advancing front class for volume meshing +*/ + + + +/// Point in advancing front +class FrontPoint3 +{ + /// coordinates + Point3d p; + /// global node index + PointIndex globalindex; + /// number of faces connected to point + int nfacetopoint; + /// distance to original boundary + int frontnr; + /// + int cluster; +public: + /// + FrontPoint3 (); + /// + FrontPoint3 (const Point3d & ap, PointIndex agi); + + /// + const Point3d & P () const + { return p; } + /// + PointIndex GlobalIndex () const + { return globalindex; } + + /// + void AddFace () + { nfacetopoint++; } + + /// + void RemoveFace() + { + nfacetopoint--; + if (nfacetopoint == 0) nfacetopoint = -1; + } + + /// + int Valid () const + { return nfacetopoint >= 0; } + + /// + void DecFrontNr (int afrontnr) + { + if (frontnr > afrontnr) frontnr = afrontnr; + } + + /// + int FrontNr () const + { return frontnr; } + + /// + friend class AdFront3; +}; + +/// Face in advancing front +class FrontFace +{ + /// + Element2d f; + /// + int qualclass; + /// + char oldfront; + /// + int hashvalue; + /// + int cluster; + +public: + /// + FrontFace (); + /// + FrontFace (const Element2d & af); + /// + const Element2d & Face () const + { return f; } + + /// + int QualClass () const + { return qualclass; } + + /// + void IncrementQualClass () + { qualclass++; } + + /// + void ResetQualClass () + { + if (qualclass > 1) + { + qualclass = 1; + oldfront = 0; + } + } + + /// + bool Valid () const + { return !f.IsDeleted(); } + + /// + void Invalidate (); + + /// + int HashValue() const + { return hashvalue; } + + /// + void SetHashValue(int hv) + { hashvalue = hv; } + + /// + friend class AdFront3; + + int Cluster () const { return cluster; } +}; + + + + +/// Advancing front, 3D. +class AdFront3 +{ + /// + ARRAY<FrontPoint3, PointIndex::BASE> points; + /// + ARRAY<FrontFace> faces; + /// + ARRAY<PointIndex> delpointl; + + /// which points are connected to pi ? + TABLE<int, PointIndex::BASE> * connectedpairs; + + /// number of total front faces; + int nff; + /// number of quads in front + int nff4; + + /// + double vol; + + /// + GeomSearch3d hashtable; + + /// + int hashon; + + /// + int hashcreated; + + /// counter for rebuilding internal tables + int rebuildcounter; + /// last base element + int lasti; + /// minimal selection-value of baseelements + int minval; + + /// + class Box3dTree * facetree; +public: + + /// + AdFront3 (); + /// + ~AdFront3 (); + /// + void GetPoints (ARRAY<Point3d> & apoints) const; + /// + int GetNP() const + { return points.Size(); } + /// + const Point3d & GetPoint (PointIndex pi) const + { return points[pi].P(); } + /// + int GetNF() const + { return nff; } + /// + const Element2d & GetFace (int i) const + { return faces.Get(i).Face(); } + /// + void Print () const; + /// + 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 Point3d & pmin, const Point3d & pmax, + ARRAY<int> & ifaces) const; + + /// + void GetFaceBoundingBox (int i, Box3d & box) const; + + /// + int GetLocals (int baseelement, + ARRAY<Point3d> & locpoints, + ARRAY<Element2d> & locfaces, // local index + ARRAY<PointIndex> & pindex, + ARRAY<INDEX> & findex, + INDEX_2_HASHTABLE<int> & connectedpairs, + float xh, + float relh, + INDEX& facesplit); + + /// + void GetGroup (int fi, + ARRAY<MeshPoint> & grouppoints, + ARRAY<Element2d> & groupelements, + ARRAY<PointIndex> & pindex, + ARRAY<INDEX> & findex + ) const; + + /// + void DeleteFace (INDEX fi); + /// + PointIndex AddPoint (const Point3d & p, PointIndex globind); + /// + INDEX AddFace (const Element2d & e); + /// + INDEX AddConnectedPair (const INDEX_2 & pair); + /// + void IncrementClass (INDEX fi); + /// + void ResetClass (INDEX fi); + /// + void SetStartFront (int baseelnp = 0); + + /// is Point p inside Surface ? + int Inside (const Point3d & p) const; + /// both points on same side ? + int SameSide (const Point3d & lp1, const Point3d & lp2, + const ARRAY<int> * testfaces = NULL) const; + + + /// + PointIndex GetGlobalIndex (PointIndex pi) const + { return points[pi].GlobalIndex(); } + /// + double Volume () const + { return vol; } + + +private: + void RebuildInternalTables(); +}; + + + + +#endif diff --git a/contrib/Netgen/libsrc/meshing/bisect.cpp b/contrib/Netgen/libsrc/meshing/bisect.cpp new file mode 100644 index 0000000000..c95a2f1421 --- /dev/null +++ b/contrib/Netgen/libsrc/meshing/bisect.cpp @@ -0,0 +1,2371 @@ +#include <mystdlib.h> +#include "meshing.hpp" + + +namespace netgen +{ +//#include "../interface/writeuser.hpp" + + class MarkedTet; + class MarkedPrism; + class MarkedTri; + class MarkedQuad; + + typedef MoveableArray<MarkedTet> T_MTETS; + typedef MoveableArray<MarkedPrism> T_MPRISMS; + typedef MoveableArray<MarkedTri> T_MTRIS; + typedef MoveableArray<MarkedQuad> T_MQUADS; + +class MarkedTet +{ +public: + /// pnums of tet + PointIndex pnums[4]; + /// material number + int matindex; + /// element marked for refinement + /// marked = 1: marked by element marker, marked = 2 due to closure + unsigned int marked:2; + /// flag of Arnold-Mukherjee algorithm + unsigned int flagged:1; + /// tetedge (local coordinates 0..3) + unsigned int tetedge1:3; + unsigned int tetedge2:3; + /// marked edge of faces + /// face_j : face without node j, + /// mark_k : edge without node k + unsigned char faceedges[4]; + + bool incorder; + unsigned int order:6; + + friend ostream & operator<< (ostream & ost, const MarkedTet & mt); +}; + +class MarkedPrism +{ +public: + /// 6 point numbers + PointIndex pnums[6]; + /// material number + int matindex; + /// marked for refinement + int marked; + /// edge without node k (0,1,2) + int markededge; + + bool incorder; + unsigned int order:6; +}; + +class MarkedTri +{ +public: + /// three point numbers + PointIndex pnums[3]; + /// three geominfos + PointGeomInfo pgeominfo[3]; + /// marked for refinement + int marked; + /// edge without node k + int markededge; + /// surface id + int surfid; + + bool incorder; + unsigned int order:6; +}; + +class MarkedQuad +{ +public: + /// point numbers + PointIndex pnums[4]; + /// + PointGeomInfo pgeominfo[4]; + /// marked for refinement + int marked; + /// surface id + int surfid; + + bool incorder; + unsigned int order:6; +}; + + + + + +ostream & operator<< (ostream & ost, const MarkedTet & mt) +{ + int k; + ost << "MT: " << mt.pnums[0] << " - " << mt.pnums[1] << " - " + << mt.pnums[2] << " - " << mt.pnums[3] << endl + << "marked edge: " << mt.tetedge1 << " - " << mt.tetedge2 + << ", order = " << mt.order << endl; + for (k = 0; k < 4; k++) + ost << mt.faceedges[k] << " "; + ost << endl; + return ost; +} + + + + +void BTSortEdges (const Mesh & mesh, + INDEX_2_CLOSED_HASHTABLE<int> & edgenumber) +{ + cout << "sorting ... " << flush; + + // if (mesh.PureTetMesh()) + if (1) + { + // new, fast version + + ARRAY<INDEX_2> edges; + ARRAY<int> eclasses; + + int i, j, k; + int cntedges = 0; + int goon; + int ned; + + // enumerate edges: + for (i = 1; i <= mesh.GetNE(); i++) + { + const Element & el = mesh.VolumeElement (i); + static int tetedges[6][2] = + { { 1, 2 }, + { 1, 3 }, + { 1, 4 }, + { 2, 3 }, + { 2, 4 }, + { 3, 4 } } ; + static int prismedges[9][2] = + { { 1, 2 }, + { 1, 3 }, + { 2, 3 }, + { 4, 5 }, + { 4, 6 }, + { 5, 6 }, + { 1, 4 }, + { 2, 5 }, + { 3, 6 } }; + int pyramidedges[6][2] = + { { 1, 2 }, + { 3, 4 }, + { 1, 5 }, + { 2, 5 }, + { 3, 5 }, + { 4, 5 } }; + + int (*tip)[2]; + + switch (el.GetType()) + { + case TET: + case TET10: + { + tip = tetedges; + ned = 6; + break; + } + case PRISM: + case PRISM12: + { + tip = prismedges; + ned = 6; + break; + } + case PYRAMID: + { + tip = pyramidedges; + ned = 6; + break; + } + } + + for (j = 0; j < ned; j++) + { + INDEX_2 i2(el.PNum(tip[j][0]), el.PNum(tip[j][1])); + i2.Sort(); + if (!edgenumber.Used(i2)) + { + cntedges++; + edges.Append (i2); + edgenumber.Set(i2, cntedges); + } + } + } + + // additional surface edges: + for (i = 1; i <= mesh.GetNSE(); i++) + { + const Element2d & el = mesh.SurfaceElement (i); + static int trigedges[3][2] = + { { 1, 2 }, + { 2, 3 }, + { 3, 1 } }; + + static int quadedges[4][2] = + { { 1, 2 }, + { 2, 3 }, + { 3, 4 }, + { 4, 1 } }; + + + int (*tip)[2]; + + switch (el.GetType()) + { + case TRIG: + case TRIG6: + { + tip = trigedges; + ned = 3; + break; + } + case QUAD: + case QUAD6: + { + tip = quadedges; + ned = 4; + break; + } + default: + { + cerr << "Error: Sort for Bisect, SE has " << el.GetNP() << " points" << endl; + ned = 0; + } + } + + for (j = 0; j < ned; j++) + { + INDEX_2 i2(el.PNum(tip[j][0]), el.PNum(tip[j][1])); + i2.Sort(); + if (!edgenumber.Used(i2)) + { + cntedges++; + edges.Append (i2); + edgenumber.Set(i2, cntedges); + } + } + } + + + + + + eclasses.SetSize (cntedges); + for (i = 1; i <= cntedges; i++) + eclasses.Elem(i) = i; + + + // identify edges in element stack + do + { + goon = 0; + for (i = 1; i <= mesh.GetNE(); i++) + { + const Element & el = mesh.VolumeElement (i); + + if (el.GetType() != PRISM && + el.GetType() != PRISM12 && + el.GetType() != PYRAMID) + continue; + + int prismpairs[3][4] = + { { 1, 2, 4, 5 }, + { 2, 3, 5, 6 }, + { 1, 3, 4, 6 } }; + + int pyramidpairs[3][4] = + { { 1, 2, 4, 3 }, + { 1, 5, 4, 5 }, + { 2, 5, 3, 5 } }; + + int (*pairs)[4]; + switch (el.GetType()) + { + case PRISM: + case PRISM12: + { + pairs = prismpairs; + break; + } + case PYRAMID: + { + pairs = pyramidpairs; + break; + } + } + + for (j = 0; j < 3; j++) + { + INDEX_2 e1 (el.PNum(pairs[j][0]), + el.PNum(pairs[j][1])); + INDEX_2 e2 (el.PNum(pairs[j][2]), + el.PNum(pairs[j][3])); + e1.Sort(); + e2.Sort(); + + int eclass1 = edgenumber.Get (e1); + int eclass2 = edgenumber.Get (e2); + + // (*testout) << "identify edges " << eclass1 << "-" << eclass2 << endl; + + if (eclasses.Get(eclass1) > + eclasses.Get(eclass2)) + { + eclasses.Elem(eclass1) = + eclasses.Get(eclass2); + goon = 1; + } + if (eclasses.Get(eclass2) > + eclasses.Get(eclass1)) + { + eclasses.Elem(eclass2) = + eclasses.Get(eclass1); + goon = 1; + } + } + } + } + while (goon); + + /* + for (i = 1; i <= cntedges; i++) + { + (*testout) << "edge " << i << ": " + << edges.Get(i).I1() << "-" << edges.Get(i).I2() + << ", class = " << eclasses.Get(i) << endl; + } + */ + // compute classlength: + ARRAY<double> edgelength(cntedges); + for (i = 1; i <= cntedges; i++) + edgelength.Elem(i) = 1e20; + + for (i = 1; i <= cntedges; i++) + { + INDEX_2 edge = edges.Get(i); + double elen = Dist (mesh.Point(edge.I1()), + mesh.Point(edge.I2())); + edgelength.Elem (i) = elen; + } + + /* + for (i = 1; i <= mesh.GetNE(); i++) + { + const Element & el = mesh.VolumeElement (i); + + if (el.GetType() == TET) + { + for (j = 1; j <= 3; j++) + for (k = j+1; k <= 4; k++) + { + INDEX_2 i2(el.PNum(j), el.PNum(k)); + i2.Sort(); + + int enr = edgenumber.Get(i2); + double elen = Dist (mesh.Point (i2.I1()), mesh.Point (i2.I2())); + if (elen < edgelength.Get(enr)) + edgelength.Set (enr, elen); + } + } + else if (el.GetType() == PRISM) + { + for (j = 1; j <= 3; j++) + { + k = (j % 3) + 1; + + INDEX_2 i2(el.PNum(j), el.PNum(k)); + i2.Sort(); + + int enr = edgenumber.Get(i2); + double elen = Dist (mesh.Point (i2.I1()), mesh.Point (i2.I2())); + if (elen < edgelength.Get(enr)) + edgelength.Set (enr, elen); + + i2 = INDEX_2(el.PNum(j+3), el.PNum(k+3)); + i2.Sort(); + + enr = edgenumber.Get(i2); + elen = Dist (mesh.Point (i2.I1()), mesh.Point (i2.I2())); + if (elen < edgelength.Get(enr)) + edgelength.Set (enr, elen); + + if (!edgenumber.Used(i2)) + { + cntedges++; + edgenumber.Set(i2, cntedges); + } + i2 = INDEX_2(el.PNum(j), el.PNum(j+3)); + i2.Sort(); + + enr = edgenumber.Get(i2); + elen = Dist (mesh.Point (i2.I1()), mesh.Point (i2.I2())); + if (elen < edgelength.Get(enr)) + edgelength.Set (enr, elen); + } + } + } + */ + + + for (i = 1; i <= cntedges; i++) + { + if (eclasses.Get(i) != i) + { + if (edgelength.Get(i) < edgelength.Get(eclasses.Get(i))) + edgelength.Elem(eclasses.Get(i)) = edgelength.Get(i); + edgelength.Elem(i) = 1e20; + } + } + + + TABLE<int> eclasstab(cntedges); + for (i = 1; i <= cntedges; i++) + eclasstab.Add1 (eclasses.Get(i), i); + + + // sort edges: + ARRAY<int> sorted(cntedges); + + QickSort (edgelength, sorted); + + int cnt = 0; + for (i = 1; i <= cntedges; i++) + { + int ii = sorted.Get(i); + for (j = 1; j <= eclasstab.EntrySize(ii); j++) + { + cnt++; + edgenumber.Set (edges.Get(eclasstab.Get(ii, j)), cnt); + } + } + } + + else + + { + // old version + + int i, j, k; + int cnt = 0; + int found; + double len2, maxlen2; + INDEX_2 ep; + + // sort edges by length, parallel edges (on prisms) + // are added in blocks + + do + { + found = 0; + maxlen2 = 1e30; + + for (i = 1; i <= mesh.GetNE(); i++) + { + const Element & el = mesh.VolumeElement (i); + int ned; + int tetedges[6][2] = + { { 1, 2 }, + { 1, 3 }, + { 1, 4 }, + { 2, 3 }, + { 2, 4 }, + { 3, 4 } }; + int prismedges[6][2] = + { { 1, 2 }, + { 1, 3 }, + { 2, 4 }, + { 4, 5 }, + { 4, 6 }, + { 5, 6 } }; + int pyramidedges[6][2] = + { { 1, 2 }, + { 3, 4 }, + { 1, 5 }, + { 2, 5 }, + { 3, 5 }, + { 4, 5 } }; + + int (*tip)[2]; + + switch (el.GetType()) + { + case TET: + { + tip = tetedges; + ned = 6; + break; + } + case PRISM: + { + tip = prismedges; + ned = 6; + break; + } + case PYRAMID: + { + tip = pyramidedges; + ned = 6; + break; + } + } + + for (j = 0; j < ned; j++) + { + INDEX_2 i2(el.PNum(tip[j][0]), el.PNum(tip[j][1])); + i2.Sort(); + if (!edgenumber.Used(i2)) + { + len2 = Dist (mesh.Point (i2.I1()), + mesh.Point (i2.I2())); + if (len2 < maxlen2) + { + maxlen2 = len2; + ep = i2; + found = 1; + } + } + } + } + if (found) + { + cnt++; + edgenumber.Set (ep, cnt); + + + // find connected edges: + int goon = 0; + do + { + goon = 0; + for (i = 1; i <= mesh.GetNE(); i++) + { + const Element & el = mesh.VolumeElement (i); + if (el.GetNP() != 6) continue; + + int prismpairs[3][4] = + { { 1, 2, 4, 5 }, + { 2, 3, 5, 6 }, + { 1, 3, 4, 6 } }; + + int pyramidpairs[3][4] = + { { 1, 2, 4, 3 }, + { 1, 5, 4, 5 }, + { 2, 5, 3, 5 } }; + + int (*pairs)[4]; + switch (el.GetType()) + { + case PRISM: + { + pairs = prismpairs; + break; + } + case PYRAMID: + { + pairs = pyramidpairs; + break; + } + } + + for (j = 0; j < 3; j++) + { + INDEX_2 e1 (el.PNum(pairs[j][0]), + el.PNum(pairs[j][1])); + INDEX_2 e2 (el.PNum(pairs[j][2]), + el.PNum(pairs[j][3])); + e1.Sort(); + e2.Sort(); + + int used1 = edgenumber.Used (e1); + int used2 = edgenumber.Used (e2); + + if (used1 && !used2) + { + cnt++; + edgenumber.Set (e2, cnt); + goon = 1; + } + if (used2 && !used1) + { + cnt++; + edgenumber.Set (e1, cnt); + goon = 1; + } + } + } + } + while (goon); + } + } + while (found); + } +} + + + + +void BTDefineMarkedTet (const Element & el, + INDEX_2_CLOSED_HASHTABLE<int> & edgenumber, + MarkedTet & mt) +{ + int i, j, k; + for (i = 0; i < 4; i++) + mt.pnums[i] = el[i]; + + mt.marked = 0; + mt.flagged = 0; + + mt.incorder = 0; + mt.order = 1; + + int val = 0; + // find marked edge of tet: + for (i = 0; i < 3; i++) + for (j = i+1; j < 4; j++) + { + INDEX_2 i2(mt.pnums[i], mt.pnums[j]); + i2.Sort(); + int hval = edgenumber.Get(i2); + if (hval > val) + { + val = hval; + mt.tetedge1 = i; + mt.tetedge2 = j; + } + } + + + // find marked edges of faces: + for (k = 0; k < 4; k++) + { + val = 0; + for (i = 0; i < 3; i++) + for (j = i+1; j < 4; j++) + if (i != k && j != k) + { + INDEX_2 i2(mt.pnums[i], mt.pnums[j]); + i2.Sort(); + int hval = edgenumber.Get(i2); + if (hval > val) + { + val = hval; + mt.faceedges[k] = 6 - k - i - j; + } + } + } +} + + + + +void BTDefineMarkedPrism (const Element & el, + INDEX_2_CLOSED_HASHTABLE<int> & edgenumber, + MarkedPrism & mp) +{ + int i, j, k; + + if (el.GetType() == PRISM || + el.GetType() == PRISM12) + { + for (i = 0; i < 6; i++) + mp.pnums[i] = el[i]; + } + else if (el.GetType() == PYRAMID) + { + static int map[6] = + { 1, 2, 5, 4, 3, 5 }; + for (i = 0; i < 6; i++) + mp.pnums[i] = el.PNum(map[i]); + } + else if (el.GetType() == TET || + el.GetType() == TET10) + { + static int map[6] = + { 1, 4, 3, 2, 4, 3 }; + for (i = 0; i < 6; i++) + mp.pnums[i] = el.PNum(map[i]); + + } + else + { + PrintSysError ("Define marked prism called for non-prism and non-pyramid"); + } + + + + mp.marked = 0; + + mp.incorder = 0; + mp.order = 1; + + int val = 0; + for (i = 0; i < 2; i++) + for (j = i+1; j < 3; j++) + { + INDEX_2 i2(mp.pnums[i], mp.pnums[j]); + i2.Sort(); + int hval = edgenumber.Get(i2); + if (hval > val) + { + val = hval; + mp.markededge = 3 - i - j; + } + } +} + + + + + + +void BTDefineMarkedTri (const Element2d & el, + INDEX_2_CLOSED_HASHTABLE<int> & edgenumber, + MarkedTri & mt) +{ + int i, j, k; + for (i = 0; i < 3; i++) + { + mt.pnums[i] = el[i]; + mt.pgeominfo[i] = el.GeomInfoPi (i+1); + } + + mt.marked = 0; + mt.surfid = el.GetIndex(); + + mt.incorder = 0; + mt.order = 1; + + int val = 0; + for (i = 0; i < 2; i++) + for (j = i+1; j < 3; j++) + { + INDEX_2 i2(mt.pnums[i], mt.pnums[j]); + i2.Sort(); + int hval = edgenumber.Get(i2); + if (hval > val) + { + val = hval; + mt.markededge = 3 - i - j; + } + } +} + + + + + +void BTDefineMarkedQuad (const Element2d & el, + INDEX_2_CLOSED_HASHTABLE<int> & edgenumber, + MarkedQuad & mq) +{ + int i, j, k; + for (i = 0; i < 4; i++) + mq.pnums[i] = el[i]; + Swap (mq.pnums[2], mq.pnums[3]); + + mq.marked = 0; + mq.surfid = el.GetIndex(); +} + + + + +// mark elements due to local h +int BTMarkTets (T_MTETS & mtets, + T_MPRISMS & mprisms, + const Mesh & mesh) +{ + int i, j, k; + int step; + + int marked = 0; + + int np = mesh.GetNP(); + Vector hv(np); + for (i = 1; i <= np; i++) + hv.Elem(i) = mesh.GetH (mesh.Point(i)); + + double hfac = 1; + + for (step = 1; step <= 2; step++) + { + for (i = 1; i <= mtets.Size(); i++) + { + double h = 0; + + for (j = 0; j < 3; j++) + for (k = j+1; k < 4; k++) + { + const Point3d & p1 = mesh.Point (mtets.Get(i).pnums[j]); + const Point3d & p2 = mesh.Point (mtets.Get(i).pnums[k]); + double hh = Dist2 (p1, p2); + if (hh > h) h = hh; + } + h = sqrt (h); + + double hshould = 1e10; + for (j = 0; j < 4; j++) + { + double hi = hv.Get (mtets.Get(i).pnums[j]); + if (hi < hshould) + hshould = hi; + } + + + if (step == 1) + { + if (h / hshould > hfac) + hfac = h / hshould; + } + else + { + if (h > hshould * hfac) + { + mtets.Elem(i).marked = 1; + marked = 1; + } + else + mtets.Elem(i).marked = 0; + } + + } + for (i = 1; i <= mprisms.Size(); i++) + { + double h = 0; + + for (j = 0; j < 2; j++) + for (k = j+1; k < 3; k++) + { + const Point3d & p1 = mesh.Point (mprisms.Get(i).pnums[j]); + const Point3d & p2 = mesh.Point (mprisms.Get(i).pnums[k]); + double hh = Dist2 (p1, p2); + if (hh > h) h = hh; + } + h = sqrt (h); + + double hshould = 1e10; + for (j = 0; j < 6; j++) + { + double hi = hv.Get (mprisms.Get(i).pnums[j]); + if (hi < hshould) + hshould = hi; + } + + + if (step == 1) + { + if (h / hshould > hfac) + hfac = h / hshould; + } + else + { + if (h > hshould * hfac) + { + mprisms.Elem(i).marked = 1; + marked = 1; + } + else + mprisms.Elem(i).marked = 0; + } + + } + + + + if (step == 1) + { + if (hfac > 2) + hfac /= 2; + else + hfac = 1; + } + + } + return marked; +} + + + + + + + + + + + + + + +void BTBisectTet (const MarkedTet & oldtet, int newp, + MarkedTet & newtet1, MarkedTet & newtet2) +{ + int i, j, k; + + + // points vis a vis from tet-edge + int vis1, vis2; + vis1 = 0; + while (vis1 == oldtet.tetedge1 || vis1 == oldtet.tetedge2) + vis1++; + vis2 = 6 - vis1 - oldtet.tetedge1 - oldtet.tetedge2; + + + // is tet of type P ? + int istypep = 0; + for (i = 0; i < 4; i++) + { + int cnt = 0; + for (j = 0; j < 4; j++) + if (oldtet.faceedges[j] == i) + cnt++; + if (cnt == 3) + istypep = 1; + } + + + + for (i = 0; i < 4; i++) + { + newtet1.pnums[i] = oldtet.pnums[i]; + newtet2.pnums[i] = oldtet.pnums[i]; + } + newtet1.flagged = istypep && !oldtet.flagged; + newtet2.flagged = istypep && !oldtet.flagged; + + int nm = oldtet.marked - 1; + if (nm < 0) nm = 0; + newtet1.marked = nm; + newtet2.marked = nm; + + + for (i = 0; i < 4; i++) + { + if (i == oldtet.tetedge1) + { + newtet2.pnums[i] = newp; + newtet2.faceedges[i] = oldtet.faceedges[i]; // inherited face + newtet2.faceedges[vis1] = i; // cut faces + newtet2.faceedges[vis2] = i; + + j = 0; + while (j == i || j == oldtet.faceedges[i]) + j++; + k = 6 - i - oldtet.faceedges[i] - j; + newtet2.tetedge1 = j; // tet-edge + newtet2.tetedge2 = k; + + // new face: + if (istypep && oldtet.flagged) + newtet2.faceedges[oldtet.tetedge2] = + 6 - oldtet.tetedge1 - j - k; + else + newtet2.faceedges[oldtet.tetedge2] = oldtet.tetedge1; + } + + if (i == oldtet.tetedge2) + { + newtet1.pnums[i] = newp; + newtet1.faceedges[i] = oldtet.faceedges[i]; // inherited face + newtet1.faceedges[vis1] = i; + newtet1.faceedges[vis2] = i; + j = 0; + while (j == i || j == oldtet.faceedges[i]) + j++; + k = 6 - i - oldtet.faceedges[i] - j; + newtet1.tetedge1 = j; + newtet1.tetedge2 = k; + + // new face: + if (istypep && oldtet.flagged) + newtet1.faceedges[oldtet.tetedge1] = + 6 - oldtet.tetedge2 - j - k; + else + newtet1.faceedges[oldtet.tetedge1] = oldtet.tetedge2; + } + } + + newtet1.matindex = oldtet.matindex; + newtet2.matindex = oldtet.matindex; + newtet1.incorder = 0; + newtet1.order = oldtet.order; + newtet2.incorder = 0; + newtet2.order = oldtet.order; +} + + + + +void BTBisectPrism (const MarkedPrism & oldprism, int newp1, int newp2, + MarkedPrism & newprism1, MarkedPrism & newprism2) +{ + int i, j, k; + + for (i = 0; i < 6; i++) + { + newprism1.pnums[i] = oldprism.pnums[i]; + newprism2.pnums[i] = oldprism.pnums[i]; + } + + int pe1, pe2; + pe1 = 0; + if (pe1 == oldprism.markededge) + pe1++; + pe2 = 3 - oldprism.markededge - pe1; + + newprism1.pnums[pe2] = newp1; + newprism1.pnums[pe2+3] = newp2; + newprism1.markededge = pe2; + newprism2.pnums[pe1] = newp1; + newprism2.pnums[pe1+3] = newp2; + newprism2.markededge = pe1; + + newprism1.matindex = oldprism.matindex; + newprism2.matindex = oldprism.matindex; + + int nm = oldprism.marked - 1; + if (nm < 0) nm = 0; + newprism1.marked = nm; + newprism2.marked = nm; + + newprism1.incorder = 0; + newprism1.order = oldprism.order; + newprism2.incorder = 0; + newprism2.order = oldprism.order; +} + + + +void BTBisectTri (const MarkedTri & oldtri, int newp, const PointGeomInfo & newpgi, + MarkedTri & newtri1, MarkedTri & newtri2) +{ + int i, j, k; + + for (i = 0; i < 3; i++) + { + newtri1.pnums[i] = oldtri.pnums[i]; + newtri1.pgeominfo[i] = oldtri.pgeominfo[i]; + newtri2.pnums[i] = oldtri.pnums[i]; + newtri2.pgeominfo[i] = oldtri.pgeominfo[i]; + } + + int pe1, pe2; + pe1 = 0; + if (pe1 == oldtri.markededge) + pe1++; + pe2 = 3 - oldtri.markededge - pe1; + + newtri1.pnums[pe2] = newp; + newtri1.pgeominfo[pe2] = newpgi; + newtri1.markededge = pe2; + + newtri2.pnums[pe1] = newp; + newtri2.pgeominfo[pe1] = newpgi; + newtri2.markededge = pe1; + + newtri1.surfid = oldtri.surfid; + newtri2.surfid = oldtri.surfid; + + int nm = oldtri.marked - 1; + if (nm < 0) nm = 0; + newtri1.marked = nm; + newtri2.marked = nm; + + newtri1.incorder = 0; + newtri1.order = oldtri.order; + newtri2.incorder = 0; + newtri2.order = oldtri.order; +} + + +void BTBisectQuad (const MarkedQuad & oldquad, + int newp1, const PointGeomInfo & npgi1, + int newp2, const PointGeomInfo & npgi2, + MarkedQuad & newquad1, MarkedQuad & newquad2) +{ + int i, j, k; + + for (i = 0; i < 4; i++) + { + newquad1.pnums[i] = oldquad.pnums[i]; + newquad1.pgeominfo[i] = oldquad.pgeominfo[i]; + newquad2.pnums[i] = oldquad.pnums[i]; + newquad2.pgeominfo[i] = oldquad.pgeominfo[i]; + } + + newquad1.pnums[1] = newp1; + newquad1.pgeominfo[1] = npgi1; + newquad1.pnums[3] = newp2; + newquad1.pgeominfo[3] = npgi2; + + newquad2.pnums[0] = newp1; + newquad2.pgeominfo[0] = npgi1; + newquad2.pnums[2] = newp2; + newquad2.pgeominfo[2] = npgi2; + + newquad1.surfid = oldquad.surfid; + newquad2.surfid = oldquad.surfid; + + + int nm = oldquad.marked - 1; + if (nm < 0) nm = 0; + + newquad1.marked = nm; + newquad2.marked = nm; +} + + + + +int MarkHangingTets (T_MTETS & mtets, + const INDEX_2_CLOSED_HASHTABLE<int> & cutedges) +{ + int i, j, k; + + int hanging = 0; + for (i = 1; i <= mtets.Size(); i++) + { + MarkedTet & teti = mtets.Elem(i); + + if (teti.marked) + { + hanging = 1; + continue; + } + + for (j = 0; j < 3; j++) + for (k = j+1; k < 4; k++) + { + INDEX_2 edge(teti.pnums[j], + teti.pnums[k]); + edge.Sort(); + if (cutedges.Used (edge)) + { + teti.marked = 1; + hanging = 1; + } + } + } + return hanging; +} + + + +int MarkHangingPrisms (T_MPRISMS & mprisms, + const INDEX_2_CLOSED_HASHTABLE<int> & cutedges) +{ + int i, j, k; + + int hanging = 0; + for (i = 1; i <= mprisms.Size(); i++) + { + if (mprisms.Elem(i).marked) + { + hanging = 1; + continue; + } + + for (j = 0; j < 2; j++) + for (k = j+1; k < 3; k++) + { + INDEX_2 edge1(mprisms.Get(i).pnums[j], + mprisms.Get(i).pnums[k]); + INDEX_2 edge2(mprisms.Get(i).pnums[j+3], + mprisms.Get(i).pnums[k+3]); + edge1.Sort(); + edge2.Sort(); + if (cutedges.Used (edge1) || + cutedges.Used (edge2)) + { + mprisms.Elem(i).marked = 1; + hanging = 1; + } + } + } + return hanging; +} + + + +int MarkHangingTris (T_MTRIS & mtris, + const INDEX_2_CLOSED_HASHTABLE<int> & cutedges) +{ + int i, j, k; + + int hanging = 0; + for (i = 1; i <= mtris.Size(); i++) + { + if (mtris.Get(i).marked) + { + hanging = 1; + continue; + } + for (j = 0; j < 2; j++) + for (k = j+1; k < 3; k++) + { + INDEX_2 edge(mtris.Get(i).pnums[j], + mtris.Get(i).pnums[k]); + edge.Sort(); + if (cutedges.Used (edge)) + { + mtris.Elem(i).marked = 1; + hanging = 1; + } + } + } + return hanging; +} + + + +int MarkHangingQuads (T_MQUADS & mquads, + const INDEX_2_CLOSED_HASHTABLE<int> & cutedges) +{ + int i; + + int hanging = 0; + for (i = 1; i <= mquads.Size(); i++) + { + if (mquads.Elem(i).marked) + { + hanging = 1; + continue; + } + + INDEX_2 edge1(mquads.Get(i).pnums[0], + mquads.Get(i).pnums[1]); + INDEX_2 edge2(mquads.Get(i).pnums[2], + mquads.Get(i).pnums[3]); + edge1.Sort(); + edge2.Sort(); + if (cutedges.Used (edge1) || + cutedges.Used (edge2)) + { + mquads.Elem(i).marked = 1; + hanging = 1; + } + + } + return hanging; +} + + + +void ConnectToNodeRec (int node, int tonode, + const TABLE<int> & conto, ARRAY<int> & connecttonode) +{ + int i, n2; + // (*testout) << "connect " << node << " to " << tonode << endl; + for (i = 1; i <= conto.EntrySize(node); i++) + { + n2 = conto.Get(node, i); + if (!connecttonode.Get(n2)) + { + connecttonode.Elem(n2) = tonode; + ConnectToNodeRec (n2, tonode, conto, connecttonode); + } + } +} + + + + +T_MTETS mtets; +T_MPRISMS mprisms; +T_MTRIS mtris; +T_MQUADS mquads; + + + +void BisectTetsCopyMesh (Mesh & mesh, const class CSGeometry *, + BisectionOptions & opt) +{ + mtets.SetName ("bisection, tets"); + mprisms.SetName ("bisection, prisms"); + mtris.SetName ("bisection, trigs"); + mquads.SetName ("bisection, quads"); + + int np = mesh.GetNP(); + int ne = mesh.GetNE(); + int nse = mesh.GetNSE(); + int i, j, k, l, m; + + /* + if (mtets.Size() + mprisms.Size() == mesh.GetNE()) + return; + */ + + mtets.SetSize(0); + mprisms.SetSize(0); + mtris.SetSize(0); + mquads.SetSize(0); + + + INDEX_2_HASHTABLE<int> shortedges(100); + for (i = 1; i <= ne; i++) + { + const Element & el = mesh.VolumeElement(i); + if (el.GetType() == PRISM || + el.GetType() == PRISM12) + { + for (j = 1; j <= 3; j++) + { + INDEX_2 se(el.PNum(j), el.PNum(j+3)); + se.Sort(); + shortedges.Set (se, 1); + } + } + } + + + + // INDEX_2_HASHTABLE<int> edgenumber(np); + INDEX_2_CLOSED_HASHTABLE<int> edgenumber(9*ne+4*nse); + + BTSortEdges (mesh, edgenumber); + for (i = 1; i <= ne; i++) + { + const Element & el = mesh.VolumeElement(i); + + switch (el.GetType()) + { + case TET: + case TET10: + { + // if tet has short edge, it is handled as degenerated prism + + int foundse = 0; + for (j = 1; j <= 3; j++) + for (k = j+1; k <= 4; k++) + { + INDEX_2 se(el.PNum(j), el.PNum(k)); + se.Sort(); + if (shortedges.Used (se)) + { + // cout << "tet converted to prism" << endl; + + foundse = 1; + int p3 = 1; + while (p3 == j || p3 == k) + p3++; + int p4 = 10 - j - k - p3; + + // even permutation ? + int pi[4]; + pi[0] = j; + pi[1] = k; + pi[2] = p3; + pi[3] = p4; + int cnt = 0; + for (l = 1; l <= 4; l++) + for (m = 0; m < 3; m++) + if (pi[m] > pi[m+1]) + { + Swap (pi[m], pi[m+1]); + cnt++; + } + if (cnt % 2) + Swap (p3, p4); + + Element hel = el; + hel.PNum(1) = el.PNum(j); + hel.PNum(2) = el.PNum(k); + hel.PNum(3) = el.PNum(p3); + hel.PNum(4) = el.PNum(p4); + + MarkedPrism mp; + BTDefineMarkedPrism (hel, edgenumber, mp); + mp.matindex = el.GetIndex(); + mprisms.Append (mp); + } + } + if (!foundse) + { + MarkedTet mt; + BTDefineMarkedTet (el, edgenumber, mt); + mt.matindex = el.GetIndex(); + mtets.Append (mt); + } + break; + } + case PYRAMID: + { + // eventually rotate + MarkedPrism mp; + + INDEX_2 se(el.PNum(1), el.PNum(2)); + se.Sort(); + if (shortedges.Used (se)) + { + Element hel = el; + hel.PNum(1) = el.PNum(2); + hel.PNum(2) = el.PNum(3); + hel.PNum(3) = el.PNum(4); + hel.PNum(4) = el.PNum(1); + BTDefineMarkedPrism (hel, edgenumber, mp); + } + else + { + BTDefineMarkedPrism (el, edgenumber, mp); + } + + mp.matindex = el.GetIndex(); + mprisms.Append (mp); + break; + } + case PRISM: + case PRISM12: + { + MarkedPrism mp; + BTDefineMarkedPrism (el, edgenumber, mp); + mp.matindex = el.GetIndex(); + mprisms.Append (mp); + break; + } + } + } + + for (i = 1; i <= nse; i++) + { + const Element2d & el = mesh.SurfaceElement(i); + if (el.GetType() == TRIG || + el.GetType() == TRIG6) + { + MarkedTri mt; + BTDefineMarkedTri (el, edgenumber, mt); + mtris.Append (mt); + } + else + { + MarkedQuad mq; + BTDefineMarkedQuad (el, edgenumber, mq); + mquads.Append (mq); + } + } + + + + mesh.mlparentelement.SetSize(ne); + for (i = 1; i <= ne; i++) + mesh.mlparentelement.Elem(i) = 0; + mesh.mlparentsurfaceelement.SetSize(nse); + for (i = 1; i <= nse; i++) + mesh.mlparentsurfaceelement.Elem(i) = 0; + + + cout << "copied " << mtets.Size() << " tets, " << mtris.Size() << " trigs" << endl; +} + + +void Refinement :: Bisect (Mesh & mesh, + BisectionOptions & opt) +{ + cout << "Mesh bisection" << endl; + + if (mesh.mglevels == 1) + BisectTetsCopyMesh(mesh, NULL, opt); + + mesh.ComputeNVertices(); + + int np = mesh.GetNV(); + mesh.SetNP(np); + + // int ne = mesh.GetNE(); + // int nse = mesh.GetNSE(); + int i, j, l; + + // int initnp = np; + // int maxsteps = 3; + + mesh.mglevels++; + + /* + if (opt.refinementfilename || opt.usemarkedelements) + maxsteps = 3; + */ + + + + if (opt.refine_p) + { + int ne = mesh.GetNE(); + int nse = mesh.GetNSE(); + int ii = 0; + for (ElementIndex ei = 0; ei < ne; ei++) + if (mesh[ei].TestRefinementFlag()) + mesh[ei].SetOrder (mesh[ei].GetOrder()+1); + + for (SurfaceElementIndex sei = 0; sei < nse; sei++) + if (mesh[sei].TestRefinementFlag()) + mesh[sei].SetOrder (mesh[sei].GetOrder()+1); + + + ARRAY<int,PointIndex::BASE> v_order (mesh.GetNP()); + v_order = 0; + + for (ElementIndex ei = 0; ei < ne; ei++) + for (j = 0; j < mesh[ei].GetNP(); j++) + if (mesh[ei].GetOrder() > v_order[mesh[ei][j]]) + v_order[mesh[ei][j]] = mesh[ei].GetOrder(); + + for (SurfaceElementIndex sei = 0; sei < nse; sei++) + for (j = 0; j < mesh[sei].GetNP(); j++) + if (mesh[sei].GetOrder() > v_order[mesh[sei][j]]) + v_order[mesh[sei][j]] = mesh[sei].GetOrder(); + + for (ElementIndex ei = 0; ei < ne; ei++) + for (j = 0; j < mesh[ei].GetNP(); j++) + if (mesh[ei].GetOrder() < v_order[mesh[ei][j]]-1) + mesh[ei].SetOrder(v_order[mesh[ei][j]]-1); + + for (SurfaceElementIndex sei = 0; sei < nse; sei++) + for (j = 0; j < mesh[sei].GetNP(); j++) + if (mesh[sei].GetOrder() < v_order[mesh[sei][j]]-1) + mesh[sei].SetOrder(v_order[mesh[sei][j]]-1); + + return; + } + + + + // INDEX_2_HASHTABLE<int> cutedges(10 + 5 * (mtets.Size()+mprisms.Size()+mtris.Size()+mquads.Size())); + INDEX_2_CLOSED_HASHTABLE<int> cutedges(10 + 9 * (mtets.Size()+mprisms.Size()+mtris.Size()+mquads.Size())); + + + for (l = 1; l <= 1; l++) + { + int marked = 0; + if (opt.refinementfilename) + { + ifstream inf(opt.refinementfilename); + cout << "load refinementinfo from file " << opt.refinementfilename << endl; + char ch; + for (i = 1; i <= mtets.Size(); i++) + { + inf >> ch; + mtets.Elem(i).marked = (ch == '1'); + } + marked = 1; + } + + else if (opt.usemarkedelements) + { + int cntm = 0; + + // all in one ! + if (mprisms.Size()) + { + int cnttet = 0; + int cntprism = 0; + for (i = 1; i <= mesh.GetNE(); i++) + { + if (mesh.VolumeElement(i).GetType() == TET || + mesh.VolumeElement(i).GetType() == TET10) + { + cnttet++; + mtets.Elem(cnttet).marked = + 3 * mesh.VolumeElement(i).TestRefinementFlag(); + if (mtets.Elem(cnttet).marked) + cntm++; + } + else + { + cntprism++; + mprisms.Elem(cntprism).marked = + 2 * mesh.VolumeElement(i).TestRefinementFlag(); + if (mprisms.Elem(cntprism).marked) + cntm++; + } + + } + } + else + for (i = 1; i <= mtets.Size(); i++) + { + mtets.Elem(i).marked = + 3 * mesh.VolumeElement(i).TestRefinementFlag(); + if (mtets.Elem(i).marked) + cntm++; + } + + // (*testout) << "mtets = " << mtets << endl; + + /* + for (i = 1; i <= mtris.Size(); i++) + mtris.Elem(i).marked = 0; + for (i = 1; i <= mquads.Size(); i++) + mquads.Elem(i).marked = 0; + */ + + cout << "marked elements: " << cntm << endl; + + int cnttrig = 0; + int cntquad = 0; + for (i = 1; i <= mesh.GetNSE(); i++) + { + if (mesh.SurfaceElement(i).GetType() == TRIG || + mesh.SurfaceElement(i).GetType() == TRIG6) + { + cnttrig++; + mtris.Elem(cnttrig).marked = + mesh.SurfaceElement(i).TestRefinementFlag() ? 2 : 0; + // mtris.Elem(cnttrig).marked = 0; + if (mtris.Elem(cnttrig).marked) + cntm++; + } + else + { + cntquad++; + mquads.Elem(cntquad).marked = + mesh.SurfaceElement(i).TestRefinementFlag(); + // mquads.Elem(cntquad).marked = 0; + if (mquads.Elem(cntquad).marked) + cntm++; + } + } + + cout << "with surface-elements: " << cntm << endl; + + if (mesh.GetDimension() == 2) + { + cntm = 0; + for (i = 1; i <= mtris.Size(); i++) + { + mtris.Elem(i).marked = + 2 * mesh.SurfaceElement(i).TestRefinementFlag(); + // mtris.Elem(i).marked = 2; + if (mtris.Elem(i).marked) + cntm++; + } + + if (!cntm) + { + for (i = 1; i <= mtris.Size(); i++) + { + mtris.Elem(i).marked = 2; + cntm++; + } + } + cout << "trigs: " << mtris.Size() << " "; + cout << "marked: " << cntm << endl; + } + + marked = (cntm > 0); + } + else + { + marked = BTMarkTets (mtets, mprisms, mesh); + } + + if (!marked) break; + + + if (opt.refine_p) + { + cout << "refine p" << endl; + + for (i = 1; i <= mtets.Size(); i++) + mtets.Elem(i).incorder = mtets.Elem(i).marked ? 1 : 0; + + for (i = 1; i <= mtets.Size(); i++) + if (mtets.Elem(i).incorder) + mtets.Elem(i).marked = 0; + + + for (i = 1; i <= mprisms.Size(); i++) + mprisms.Elem(i).incorder = mprisms.Elem(i).marked ? 1 : 0; + + for (i = 1; i <= mprisms.Size(); i++) + if (mprisms.Elem(i).incorder) + mprisms.Elem(i).marked = 0; + + + for (i = 1; i <= mtris.Size(); i++) + mtris.Elem(i).incorder = mtris.Elem(i).marked ? 1 : 0; + + for (i = 1; i <= mtris.Size(); i++) + { + if (mtris.Elem(i).incorder) + mtris.Elem(i).marked = 0; + } + } + + if (opt.refine_hp) + { + cout << "refine hp" << endl; + BitArray singv(np); + singv.Clear(); + + if (mesh.GetDimension() == 3) + for (i = 1; i <= mesh.GetNSeg(); i++) + { + const Segment & seg = mesh.LineSegment(i); + singv.Set (seg.p1); + singv.Set (seg.p2); + } + else + { + // vertices with 2 different bnds + ARRAY<int> bndind(np); + bndind = 0; + for (i = 1; i <= mesh.GetNSeg(); i++) + { + const Segment & seg = mesh.LineSegment(i); + for (int j = 0; j < 2; j++) + { + int pi = (j == 0) ? seg.p1 : seg.p2; + if (bndind.Elem(pi) == 0) + bndind.Elem(pi) = seg.edgenr; + else if (bndind.Elem(pi) != seg.edgenr) + singv.Set (pi); + } + } + } + + + + for (i = 1; i <= mtets.Size(); i++) + mtets.Elem(i).incorder = 1; + for (i = 1; i <= mtets.Size(); i++) + { + if (!mtets.Elem(i).marked) + mtets.Elem(i).incorder = 0; + for (j = 0; j < 4; j++) + if (singv.Test (mtets.Elem(i).pnums[j])) + mtets.Elem(i).incorder = 0; + } + for (i = 1; i <= mtets.Size(); i++) + if (mtets.Elem(i).incorder) + mtets.Elem(i).marked = 0; + + + for (i = 1; i <= mprisms.Size(); i++) + mprisms.Elem(i).incorder = 1; + for (i = 1; i <= mprisms.Size(); i++) + { + if (!mprisms.Elem(i).marked) + mprisms.Elem(i).incorder = 0; + for (j = 0; j < 6; j++) + if (singv.Test (mprisms.Elem(i).pnums[j])) + mprisms.Elem(i).incorder = 0; + } + for (i = 1; i <= mprisms.Size(); i++) + if (mprisms.Elem(i).incorder) + mprisms.Elem(i).marked = 0; + + + for (i = 1; i <= mtris.Size(); i++) + mtris.Elem(i).incorder = 1; + for (i = 1; i <= mtris.Size(); i++) + { + if (!mtris.Elem(i).marked) + mtris.Elem(i).incorder = 0; + for (j = 0; j < 3; j++) + if (singv.Test (mtris.Elem(i).pnums[j])) + mtris.Elem(i).incorder = 0; + } + for (i = 1; i <= mtris.Size(); i++) + { + if (mtris.Elem(i).incorder) + mtris.Elem(i).marked = 0; + } + } + + + + + + int hangingvol, hangingsurf, hangingedge; + + do + { + // refine volume elements + + int nel = mtets.Size(); + for (i = 1; i <= nel; i++) + if (mtets.Elem(i).marked) + { + MarkedTet oldtet; + MarkedTet newtet1, newtet2; + int newp; + + + oldtet = mtets.Get(i); + INDEX_2 edge(oldtet.pnums[oldtet.tetedge1], + oldtet.pnums[oldtet.tetedge2]); + edge.Sort(); + if (cutedges.Used (edge)) + { + newp = cutedges.Get(edge); + } + else + { + Point3d np = Center (mesh.Point (edge.I1()), + mesh.Point (edge.I2())); + newp = mesh.AddPoint (np); + cutedges.Set (edge, newp); + } + + BTBisectTet (oldtet, newp, newtet1, newtet2); + mtets.Elem(i) = newtet1; + mtets.Append (newtet2); + } + + int npr = mprisms.Size(); + for (i = 1; i <= npr; i++) + if (mprisms.Elem(i).marked) + { + MarkedPrism oldprism; + MarkedPrism newprism1, newprism2; + int newp1, newp2; + + oldprism = mprisms.Get(i); + int pi1 = 0; + if (pi1 == oldprism.markededge) + pi1++; + int pi2 = 3-pi1-oldprism.markededge; + + INDEX_2 edge1(oldprism.pnums[pi1], + oldprism.pnums[pi2]); + INDEX_2 edge2(oldprism.pnums[pi1+3], + oldprism.pnums[pi2+3]); + edge1.Sort(); + edge2.Sort(); + + if (cutedges.Used (edge1)) + newp1 = cutedges.Get(edge1); + else + { + Point3d np = Center (mesh.Point (edge1.I1()), + mesh.Point (edge1.I2())); + newp1 = mesh.AddPoint (np); + cutedges.Set (edge1, newp1); + } + if (cutedges.Used (edge2)) + newp2 = cutedges.Get(edge2); + else + { + Point3d np = Center (mesh.Point (edge2.I1()), + mesh.Point (edge2.I2())); + newp2 = mesh.AddPoint (np); + cutedges.Set (edge2, newp2); + } + + + BTBisectPrism (oldprism, newp1, newp2, newprism1, newprism2); + mprisms.Elem(i) = newprism1; + mprisms.Append (newprism2); + } + + + hangingvol = + MarkHangingTets (mtets, cutedges) + + MarkHangingPrisms (mprisms, cutedges); + + + int nsel = mtris.Size(); + + for (i = 1; i <= nsel; i++) + if (mtris.Elem(i).marked) + { + MarkedTri oldtri; + MarkedTri newtri1, newtri2; + int newp; + + oldtri = mtris.Get(i); + int oldpi1 = oldtri.pnums[(oldtri.markededge+1)%3]; + int oldpi2 = oldtri.pnums[(oldtri.markededge+2)%3]; + INDEX_2 edge(oldpi1, oldpi2); + edge.Sort(); + + // cerr << "edge = " << edge.I1() << "-" << edge.I2() << endl; + + if (cutedges.Used (edge)) + { + newp = cutedges.Get(edge); + } + else + { + Point3d np = Center (mesh.Point (edge.I1()), + mesh.Point (edge.I2())); + newp = mesh.AddPoint (np); + cutedges.Set (edge, newp); + } + // newp = cutedges.Get(edge); + + int si = mesh.GetFaceDescriptor (oldtri.surfid).SurfNr(); + // geom->GetSurface(si)->Project (mesh.Point(newp)); + PointGeomInfo npgi; + + if (mesh.PointType(newp) != EDGEPOINT) + PointBetween (mesh.Point (oldpi1), mesh.Point (oldpi2), + 0.5, si, + oldtri.pgeominfo[(oldtri.markededge+1)%3], + oldtri.pgeominfo[(oldtri.markededge+2)%3], + mesh.Point (newp), npgi); + + BTBisectTri (oldtri, newp, npgi, newtri1, newtri2); + + + mtris.Elem(i) = newtri1; + mtris.Append (newtri2); + mesh.mlparentsurfaceelement.Append (i); + } + + int nquad = mquads.Size(); + for (i = 1; i <= nquad; i++) + if (mquads.Elem(i).marked) + { + MarkedQuad oldquad; + MarkedQuad newquad1, newquad2; + int newp1, newp2; + + oldquad = mquads.Get(i); + INDEX_2 edge1(oldquad.pnums[0], + oldquad.pnums[1]); + INDEX_2 edge2(oldquad.pnums[2], + oldquad.pnums[3]); + edge1.Sort(); + edge2.Sort(); + + if (cutedges.Used (edge1)) + { + newp1 = cutedges.Get(edge1); + } + else + { + Point3d np = Center (mesh.Point (edge1.I1()), + mesh.Point (edge1.I2())); + newp1 = mesh.AddPoint (np); + cutedges.Set (edge1, newp1); + } + + if (cutedges.Used (edge2)) + { + newp2 = cutedges.Get(edge2); + } + else + { + Point3d np = Center (mesh.Point (edge2.I1()), + mesh.Point (edge2.I2())); + newp2 = mesh.AddPoint (np); + cutedges.Set (edge2, newp2); + } + + PointGeomInfo npgi1, npgi2; + + int si = mesh.GetFaceDescriptor (oldquad.surfid).SurfNr(); + // geom->GetSurface(si)->Project (mesh.Point(newp1)); + // geom->GetSurface(si)->Project (mesh.Point(newp2)); + + (*testout) << "project point " << newp1 << " old: " << mesh.Point(newp1); + PointBetween (mesh.Point (edge1.I1()), mesh.Point (edge1.I2()), + 0.5, si, + oldquad.pgeominfo[0], + oldquad.pgeominfo[1], + mesh.Point (newp1), npgi1); + (*testout) << " new: " << mesh.Point(newp1) << endl; + + + PointBetween (mesh.Point (edge2.I1()), mesh.Point (edge2.I2()), + 0.5, si, + oldquad.pgeominfo[2], + oldquad.pgeominfo[3], + mesh.Point (newp2), npgi2); + + + BTBisectQuad (oldquad, newp1, npgi1, newp2, npgi2, + newquad1, newquad2); + mquads.Elem(i) = newquad1; + mquads.Append (newquad2); + } + + + hangingsurf = + MarkHangingTris (mtris, cutedges) + + MarkHangingQuads (mquads, cutedges); + + hangingedge = 0; + + int nseg = mesh.GetNSeg (); + for (i = 1; i <= nseg; i++) + { + Segment & seg = mesh.LineSegment (i); + INDEX_2 edge(seg.p1, seg.p2); + edge.Sort(); + if (cutedges.Used (edge)) + { + hangingedge = 1; + Segment nseg1 = seg; + Segment nseg2 = seg; + + int newpi = cutedges.Get(edge); + + nseg1.p2 = newpi; + nseg2.p1 = newpi; + + EdgePointGeomInfo newepgi; + + // (*testout) << "move edgepoint " << newpi << " from " << mesh.Point(newpi); + PointBetween (mesh.Point (seg.p1), mesh.Point (seg.p2), + 0.5, seg.surfnr1, seg.surfnr2, + seg.epgeominfo[0], seg.epgeominfo[1], + mesh.Point (newpi), newepgi); + // (*testout) << " to " << mesh.Point (newpi) << endl; + nseg1.epgeominfo[1] = newepgi; + nseg2.epgeominfo[0] = newepgi; + + mesh.LineSegment (i) = nseg1; + mesh.AddSegment (nseg2); + } + } + + } + while (hangingvol || hangingsurf || hangingedge); + + + cout << mtets.Size() << " tets" << endl; + cout << mtris.Size() << " trigs" << endl; + if (mprisms.Size()) + { + cout << mprisms.Size() << " prisms" << endl; + cout << mquads.Size() << " quads" << endl; + } + cout << mesh.GetNP() << " points" << endl; + } + + /* + cout << "mem in mtets: " << endl; + mtets.PrintMemInfo(cout); + cout << "cutedges" << endl; + cutedges.PrintMemInfo(cout); + */ + + // (*testout) << "mtets = " << mtets << endl; + + if (opt.refine_hp) + { + // + ARRAY<int> v_order (mesh.GetNP()); + v_order = 0; + if (mesh.GetDimension() == 3) + { + for (i = 1; i <= mtets.Size(); i++) + if (mtets.Elem(i).incorder) + mtets.Elem(i).order++; + + for (i = 0; i < mtets.Size(); i++) + for (j = 0; j < 4; j++) + if (mtets[i].order > v_order.Elem(mtets[i].pnums[j])) + v_order.Elem(mtets[i].pnums[j]) = mtets[i].order; + for (i = 0; i < mtets.Size(); i++) + for (j = 0; j < 4; j++) + if (mtets[i].order < v_order.Elem(mtets[i].pnums[j])-1) + mtets[i].order = v_order.Elem(mtets[i].pnums[j])-1; + } + else + { + for (i = 1; i <= mtris.Size(); i++) + if (mtris.Elem(i).incorder) + { + mtris.Elem(i).order++; + } + + for (i = 0; i < mtris.Size(); i++) + for (j = 0; j < 3; j++) + if (mtris[i].order > v_order.Elem(mtris[i].pnums[j])) + v_order.Elem(mtris[i].pnums[j]) = mtris[i].order; + for (i = 0; i < mtris.Size(); i++) + { + for (j = 0; j < 3; j++) + if (mtris[i].order < v_order.Elem(mtris[i].pnums[j])-1) + mtris[i].order = v_order.Elem(mtris[i].pnums[j])-1; + } + } + } + + mtets.SetAllocSize (mtets.Size()); + mprisms.SetAllocSize (mprisms.Size()); + mtris.SetAllocSize (mtris.Size()); + mquads.SetAllocSize (mquads.Size()); + + + mesh.ClearVolumeElements(); + mesh.VolumeElements().SetAllocSize (mtets.Size()+mprisms.Size()); + for (i = 1; i <= mtets.Size(); i++) + { + Element el(TET); + el.SetIndex (mtets.Get(i).matindex); + for (j = 1; j <= 4; j++) + el.PNum(j) = mtets.Get(i).pnums[j-1]; + el.SetOrder (mtets.Get(i).order); + mesh.AddVolumeElement (el); + } + for (i = 1; i <= mprisms.Size(); i++) + { + Element el(PRISM); + el.SetIndex (mprisms.Get(i).matindex); + for (j = 1; j <= 6; j++) + el.PNum(j) = mprisms.Get(i).pnums[j-1]; + el.SetOrder (mprisms.Get(i).order); + + // degenerated prism ? + static const int map1[] = { 3, 2, 5, 6, 1 }; + static const int map2[] = { 1, 3, 6, 4, 2 }; + static const int map3[] = { 2, 1, 4, 5, 3 }; + + + const int * map = NULL; + int deg1 = 0, deg2 = 0, deg3 = 0; + // int deg = 0; + if (el.PNum(1) == el.PNum(4)) { map = map1; deg1 = 1; } + if (el.PNum(2) == el.PNum(5)) { map = map2; deg2 = 1; } + if (el.PNum(3) == el.PNum(6)) { map = map3; deg3 = 1; } + + switch (deg1+deg2+deg3) + { + case 1: + { + for (j = 1; j <= 5; j++) + el.PNum(j) = mprisms.Get(i).pnums[map[j-1]-1]; + + el.SetType (PYRAMID); + break; + } + case 2: + { + static const int tetmap1[] = { 1, 2, 3, 4 }; + static const int tetmap2[] = { 2, 3, 1, 5 }; + static const int tetmap3[] = { 3, 1, 2, 6 }; + if (!deg1) map = tetmap1; + if (!deg2) map = tetmap2; + if (!deg3) map = tetmap3; + for (j = 1; j <= 4; j++) + el.PNum(j) = mprisms.Get(i).pnums[map[j-1]-1]; + /* + if (!deg1) el.PNum(4) = el.PNum(4); + if (!deg2) el.PNum(4) = el.PNum(5); + if (!deg3) el.PNum(4) = el.PNum(6); + */ + el.SetType(TET); + break; + } + default: + ; + } + mesh.AddVolumeElement (el); + } + + mesh.ClearSurfaceElements(); + for (i = 1; i <= mtris.Size(); i++) + { + Element2d el(TRIG); + el.SetIndex (mtris.Get(i).surfid); + el.SetOrder (mtris.Get(i).order); + for (j = 1; j <= 3; j++) + { + el.PNum(j) = mtris.Get(i).pnums[j-1]; + el.GeomInfoPi(j) = mtris.Get(i).pgeominfo[j-1]; + } + mesh.AddSurfaceElement (el); + } + for (i = 1; i <= mquads.Size(); i++) + { + Element2d el(QUAD); + el.SetIndex (mquads.Get(i).surfid); + for (j = 1; j <= 4; j++) + el.PNum(j) = mquads.Get(i).pnums[j-1]; + Swap (el.PNum(3), el.PNum(4)); + mesh.AddSurfaceElement (el); + } + + + + // write multilevel hierarchy to mesh: + np = mesh.GetNP(); + mesh.mlbetweennodes.SetSize(np); + if (mesh.mglevels <= 2) + for (i = 1; i <= np; i++) + { + mesh.mlbetweennodes.Elem(i).I1() = 0; + mesh.mlbetweennodes.Elem(i).I2() = 0; + } + + /* + for (i = 1; i <= cutedges.GetNBags(); i++) + for (j = 1; j <= cutedges.GetBagSize(i); j++) + { + INDEX_2 edge; + int newpi; + cutedges.GetData (i, j, edge, newpi); + mesh.mlbetweennodes.Elem(newpi) = edge; + } + */ + for (i = 1; i <= cutedges.Size(); i++) + if (cutedges.UsedPos(i)) + { + INDEX_2 edge; + int newpi; + cutedges.GetData (i, edge, newpi); + mesh.mlbetweennodes.Elem(newpi) = edge; + } + + + /* + mesh.PrintMemInfo (cout); + cout << "tets "; + mtets.PrintMemInfo (cout); + cout << "prims "; + mprisms.PrintMemInfo (cout); + cout << "tris "; + mtris.PrintMemInfo (cout); + cout << "quads "; + mquads.PrintMemInfo (cout); + cout << "cutedges "; + cutedges.PrintMemInfo (cout); + */ + + + /* + + // find connected nodes (close nodes) + TABLE<int> conto(np); + for (i = 1; i <= mprisms.Size(); i++) + for (j = 1; j <= 6; j++) + { + int n1 = mprisms.Get(i).pnums[j-1]; + int n2 = mprisms.Get(i).pnums[(j+2)%6]; + // if (n1 != n2) + { + int found = 0; + for (k = 1; k <= conto.EntrySize(n1); k++) + if (conto.Get(n1, k) == n2) + { + found = 1; + break; + } + if (!found) + conto.Add (n1, n2); + } + } + mesh.connectedtonode.SetSize(np); + for (i = 1; i <= np; i++) + mesh.connectedtonode.Elem(i) = 0; + + +// (*testout) << "connection table: " << endl; +// for (i = 1; i <= np; i++) +// { +// (*testout) << "node " << i << ": "; +// for (j = 1; j <= conto.EntrySize(i); j++) +// (*testout) << conto.Get(i, j) << " "; +// (*testout) << endl; +// } + + + for (i = 1; i <= np; i++) + if (mesh.connectedtonode.Elem(i) == 0) + { + mesh.connectedtonode.Elem(i) = i; + ConnectToNodeRec (i, i, conto, mesh.connectedtonode); + } +*/ + + // mesh.BuildConnectedNodes(); + + mesh.ComputeNVertices(); + mesh.UpdateTopology(); + + // update identification tables + for (i = 1; i <= mesh.GetIdentifications().GetMaxNr(); i++) + { + ARRAY<int,PointIndex::BASE> identmap; + mesh.GetIdentifications().GetMap (i, identmap); + + + /* + for (j = 1; j <= cutedges.GetNBags(); j++) + for (k = 1; k <= cutedges.GetBagSize(j); k++) + { + INDEX_2 i2; + int newpi; + cutedges.GetData (j, k, i2, newpi); + INDEX_2 oi2(identmap.Get(i2.I1()), + identmap.Get(i2.I2())); + oi2.Sort(); + if (cutedges.Used (oi2)) + { + int onewpi = cutedges.Get(oi2); + mesh.GetIdentifications().Add (newpi, onewpi, i); + } + } + */ + + for (j = 1; j <= cutedges.Size(); j++) + if (cutedges.UsedPos(j)) + { + INDEX_2 i2; + int newpi; + cutedges.GetData (j, i2, newpi); + INDEX_2 oi2(identmap.Get(i2.I1()), + identmap.Get(i2.I2())); + oi2.Sort(); + if (cutedges.Used (oi2)) + { + int onewpi = cutedges.Get(oi2); + mesh.GetIdentifications().Add (newpi, onewpi, i); + } + } + + } + PrintMessage (5, "Bisection done"); +} + + + + +BisectionOptions :: BisectionOptions () +{ + outfilename = NULL; + mlfilename = NULL; + refinementfilename = NULL; + femcode = NULL; + maxlevel = 50; + usemarkedelements = 0; + refine_hp = 0; + refine_p = 0; +} + + + +void Refinement :: PointBetween (const Point3d & p1, const Point3d & p2, double secpoint, + int surfi, + const PointGeomInfo & gi1, + const PointGeomInfo & gi2, + Point3d & newp, PointGeomInfo & newgi) +{ + newp = p1+secpoint*(p2-p1); +} + +void Refinement :: PointBetween (const Point3d & p1, const Point3d & p2, double secpoint, + int surfi1, int surfi2, + const EdgePointGeomInfo & ap1, + const EdgePointGeomInfo & ap2, + Point3d & newp, EdgePointGeomInfo & newgi) +{ + newp = p1+secpoint*(p2-p1); +} + +void Refinement :: ProjectToSurface (Point<3> & p, int surfi) +{ + cout << "Refinement :: ProjectToSurface ERROR: no geometry set" << endl; +} + + +} diff --git a/contrib/Netgen/libsrc/meshing/bisect.hpp b/contrib/Netgen/libsrc/meshing/bisect.hpp new file mode 100644 index 0000000000..8a1e836116 --- /dev/null +++ b/contrib/Netgen/libsrc/meshing/bisect.hpp @@ -0,0 +1,77 @@ +#ifndef BISECT +#define BISECT + +class BisectionOptions +{ +public: + const char * outfilename; + const char * mlfilename; + const char * refinementfilename; + const char * femcode; + int maxlevel; + int usemarkedelements; + bool refine_hp; + bool refine_p; + BisectionOptions (); +}; + +class ZRefinementOptions +{ +public: + int minref; + ZRefinementOptions(); +}; + + +/* +extern void BisectTets (Mesh &, const CSGeometry *, + BisectionOptions & opt); +*/ + +extern void BisectTetsCopyMesh (Mesh &, const class CSGeometry *, + BisectionOptions & opt); + +extern void ZRefinement (Mesh &, const CSGeometry *, + ZRefinementOptions & opt); + + + + + +class Refinement +{ +public: + Refinement (); + virtual ~Refinement (); + + void Refine (Mesh & mesh); + void Bisect (Mesh & mesh, class BisectionOptions & opt); + void MakeSecondOrder (Mesh & mesh); + + virtual void PointBetween (const Point3d & p1, const Point3d & p2, double secpoint, + int surfi, + const PointGeomInfo & gi1, + const PointGeomInfo & gi2, + Point3d & newp, PointGeomInfo & newgi); + + virtual void PointBetween (const Point3d & p1, const Point3d & p2, double secpoint, + int surfi1, int surfi2, + const EdgePointGeomInfo & ap1, + const EdgePointGeomInfo & ap2, + Point3d & newp, EdgePointGeomInfo & newgi); + + virtual void ProjectToSurface (Point<3> & p, int surfi); + + virtual void ProjectToSurface (Point<3> & p, int surfi, PointGeomInfo & /* gi */) + { + ProjectToSurface (p, surfi); + } + + + void ValidateSecondOrder (Mesh & mesh); + void ValidateRefinedMesh (Mesh & mesh, + ARRAY<INDEX_2> & parents); + +}; + +#endif diff --git a/contrib/Netgen/libsrc/meshing/boundarylayer.cpp b/contrib/Netgen/libsrc/meshing/boundarylayer.cpp new file mode 100644 index 0000000000..6f564586b6 --- /dev/null +++ b/contrib/Netgen/libsrc/meshing/boundarylayer.cpp @@ -0,0 +1,91 @@ +#include <mystdlib.h> +#include "meshing.hpp" + +namespace netgen +{ + +void InsertVirtualBoundaryLayer (Mesh & mesh) +{ + cout << "Insert virt. b.l." << endl; + + int surfid; + + cout << "Boundary Nr:"; + cin >> surfid; + + int i, j; + int np = mesh.GetNP(); + + cout << "Old NP: " << mesh.GetNP() << endl; + cout << "Trigs: " << mesh.GetNSE() << endl; + + BitArray bndnodes(np); + ARRAY<int> mapto(np); + + bndnodes.Clear(); + for (i = 1; i <= mesh.GetNSeg(); i++) + { + int snr = mesh.LineSegment(i).edgenr; + cout << "snr = " << snr << endl; + if (snr == surfid) + { + bndnodes.Set (mesh.LineSegment(i).p1); + bndnodes.Set (mesh.LineSegment(i).p2); + } + } + for (i = 1; i <= mesh.GetNSeg(); i++) + { + int snr = mesh.LineSegment(i).edgenr; + if (snr != surfid) + { + bndnodes.Clear (mesh.LineSegment(i).p1); + bndnodes.Clear (mesh.LineSegment(i).p2); + } + } + + for (i = 1; i <= np; i++) + { + if (bndnodes.Test(i)) + mapto.Elem(i) = mesh.AddPoint (mesh.Point (i)); + else + mapto.Elem(i) = 0; + } + + for (i = 1; i <= mesh.GetNSE(); i++) + { + Element2d & el = mesh.SurfaceElement(i); + for (j = 1; j <= el.GetNP(); j++) + if (mapto.Get(el.PNum(j))) + el.PNum(j) = mapto.Get(el.PNum(j)); + } + + + int nq = 0; + for (i = 1; i <= mesh.GetNSeg(); i++) + { + int snr = mesh.LineSegment(i).edgenr; + if (snr == surfid) + { + int p1 = mesh.LineSegment(i).p1; + int p2 = mesh.LineSegment(i).p2; + int p3 = mapto.Get (p1); + if (!p3) p3 = p1; + int p4 = mapto.Get (p2); + if (!p4) p4 = p2; + + Element2d el(4); + el.PNum(1) = p1; + el.PNum(2) = p2; + el.PNum(3) = p3; + el.PNum(4) = p4; + el.SetIndex (2); + mesh.AddSurfaceElement (el); + nq++; + } + } + + cout << "New NP: " << mesh.GetNP() << endl; + cout << "Quads: " << nq << endl; +} + +} diff --git a/contrib/Netgen/libsrc/meshing/boundarylayer.hpp b/contrib/Netgen/libsrc/meshing/boundarylayer.hpp new file mode 100644 index 0000000000..e5a047b6bb --- /dev/null +++ b/contrib/Netgen/libsrc/meshing/boundarylayer.hpp @@ -0,0 +1,9 @@ +#ifndef FILE_BOUNDARYLAYER +#define FILE_BOUNDARYLAYER + + +/// +extern void InsertVirtualBoundaryLayer (Mesh & mesh); + + +#endif diff --git a/contrib/Netgen/libsrc/meshing/clusters.cpp b/contrib/Netgen/libsrc/meshing/clusters.cpp new file mode 100644 index 0000000000..5eef2078e7 --- /dev/null +++ b/contrib/Netgen/libsrc/meshing/clusters.cpp @@ -0,0 +1,260 @@ +#include <mystdlib.h> + +#include "meshing.hpp" + +namespace netgen +{ + +AnisotropicClusters :: AnisotropicClusters (const Mesh & amesh) + : mesh(amesh) +{ + ; +} + +AnisotropicClusters :: ~AnisotropicClusters () +{ + ; +} + +void AnisotropicClusters :: Update() +{ + int i, j, k; + + const MeshTopology & top = mesh.GetTopology(); + if (!top.HasEdges()) + return; + + PrintMessage (3, "Update Clusters"); + + nv = mesh.GetNV(); + ned = top.GetNEdges(); + nfa = top.GetNFaces(); + ne = mesh.GetNE(); + int nse = mesh.GetNSE(); + + cluster_reps.SetSize (nv+ned+nfa+ne); + + ARRAY<int> nnums, ednums, fanums; + int changed; + + for (i = 1; i <= cluster_reps.Size(); i++) + cluster_reps.Elem(i) = i; + + for (i = 1; i <= cluster_reps.Size(); i++) + cluster_reps.Elem(i) = -1; + + for (i = 1; i <= ne; i++) + { + const Element & el = mesh.VolumeElement(i); + ELEMENT_TYPE typ = el.GetType(); + + top.GetElementEdges (i, ednums); + top.GetElementFaces (i, fanums); + + int elnv = top.GetNVertices (typ); + int elned = ednums.Size(); + int elnfa = fanums.Size(); + + nnums.SetSize(elnv+elned+elnfa+1); + for (j = 1; j <= elnv; j++) + nnums.Elem(j) = el.PNum(j); + for (j = 1; j <= elned; j++) + nnums.Elem(elnv+j) = nv+ednums.Elem(j); + for (j = 1; j <= elnfa; j++) + nnums.Elem(elnv+elned+j) = nv+ned+fanums.Elem(j); + nnums.Elem(elnv+elned+elnfa+1) = nv+ned+nfa+i; + + for (j = 0; j < nnums.Size(); j++) + cluster_reps.Elem(nnums[j]) = nnums[j]; + } + + + for (i = 1; i <= nse; i++) + { + const Element2d & el = mesh.SurfaceElement(i); + ELEMENT_TYPE typ = el.GetType(); + + top.GetSurfaceElementEdges (i, ednums); + int fanum = top.GetSurfaceElementFace (i); + + int elnv = top.GetNVertices (typ); + int elned = ednums.Size(); + + nnums.SetSize(elnv+elned+1); + for (j = 1; j <= elnv; j++) + nnums.Elem(j) = el.PNum(j); + for (j = 1; j <= elned; j++) + nnums.Elem(elnv+j) = nv+ednums.Elem(j); + nnums.Elem(elnv+elned+1) = fanum; + + for (j = 0; j < nnums.Size(); j++) + cluster_reps.Elem(nnums[j]) = nnums[j]; + } + + static const int hex_cluster[] = + { + 1, 2, 3, 4, 1, 2, 3, 4, + 5, 6, 7, 8, 5, 6, 7, 8, 1, 2, 3, 4, + 9, 9, 5, 8, 6, 7, + 9 + }; + + static const int prism_cluster[] = + { + 1, 2, 3, 1, 2, 3, + 4, 5, 6, 4, 5, 6, 3, 1, 2, + 7, 7, 4, 5, 6, + 7 + }; + static const int pyramid_cluster[] = + { + 1, 2, 2, 1, 3, + 4, 2, 1, 4, 6, 5, 5, 6, + 7, 5, 7, 6, 4, + 7 + }; + static const int tet_cluster14[] = + { 1, 2, 3, 1, 1, 4, 5, 4, 5, 6, 7, 5, 4, 7, 7 }; + + static const int tet_cluster12[] = + { 1, 1, 2, 3, 4, 4, 5, 1, 6, 6, 7, 7, 4, 6, 7 }; + + static const int tet_cluster13[] = + { 1, 2, 1, 3, 4, 6, 4, 5, 1, 5, 7, 4, 7, 5, 7 }; + + static const int tet_cluster23[] = + { 2, 1, 1, 3, 6, 5, 5, 4, 4, 1, 5, 7, 7, 4, 7 }; + + static const int tet_cluster24[] = + { 2, 1, 3, 1, 4, 1, 5, 4, 6, 5, 5, 7, 4, 7, 7 }; + + static const int tet_cluster34[] = + { 2, 3, 1, 1, 4, 5, 1, 6, 4, 5, 5, 4, 7, 7, 7 }; + + int cnt = 0; + do + { + cnt++; + changed = 0; + + for (i = 1; i <= ne; i++) + { + const Element & el = mesh.VolumeElement(i); + ELEMENT_TYPE typ = el.GetType(); + + top.GetElementEdges (i, ednums); + top.GetElementFaces (i, fanums); + + int elnv = top.GetNVertices (typ); + int elned = ednums.Size(); + int elnfa = fanums.Size(); + + nnums.SetSize(elnv+elned+elnfa+1); + for (j = 1; j <= elnv; j++) + nnums.Elem(j) = el.PNum(j); + for (j = 1; j <= elned; j++) + nnums.Elem(elnv+j) = nv+ednums.Elem(j); + for (j = 1; j <= elnfa; j++) + nnums.Elem(elnv+elned+j) = nv+ned+fanums.Elem(j); + nnums.Elem(elnv+elned+elnfa+1) = nv+ned+nfa+i; + + + const int * clustertab = NULL; + switch (typ) + { + case PRISM: + case PRISM12: + clustertab = prism_cluster; + break; + case HEX: + clustertab = hex_cluster; + break; + case PYRAMID: + clustertab = pyramid_cluster; + break; + case TET: + case TET10: + if (cluster_reps.Get(el.PNum(1)) == + cluster_reps.Get(el.PNum(2))) + clustertab = tet_cluster12; + else if (cluster_reps.Get(el.PNum(1)) == + cluster_reps.Get(el.PNum(3))) + clustertab = tet_cluster13; + else if (cluster_reps.Get(el.PNum(1)) == + cluster_reps.Get(el.PNum(4))) + clustertab = tet_cluster14; + else if (cluster_reps.Get(el.PNum(2)) == + cluster_reps.Get(el.PNum(3))) + clustertab = tet_cluster23; + else if (cluster_reps.Get(el.PNum(2)) == + cluster_reps.Get(el.PNum(4))) + clustertab = tet_cluster24; + else if (cluster_reps.Get(el.PNum(3)) == + cluster_reps.Get(el.PNum(4))) + clustertab = tet_cluster34; + else + clustertab = NULL; + break; + default: + clustertab = NULL; + } + + if (clustertab) + for (j = 0; j < nnums.Size(); j++) + for (k = 0; k < j; k++) + if (clustertab[j] == clustertab[k]) + { + int jj = nnums[j]; + int kk = nnums[k]; + if (cluster_reps.Get(jj) < cluster_reps.Get(kk)) + { + cluster_reps.Elem(kk) = cluster_reps.Get(jj); + changed = 1; + } + else if (cluster_reps.Get(kk) < cluster_reps.Get(jj)) + { + cluster_reps.Elem(jj) = cluster_reps.Get(kk); + changed = 1; + } + } + + /* + if (clustertab) + { + if (typ == PYRAMID) + (*testout) << "pyramid"; + else if (typ == PRISM || typ == PRISM12) + (*testout) << "prism"; + else if (typ == TET || typ == TET10) + (*testout) << "tet"; + else + (*testout) << "unknown type" << endl; + + (*testout) << ", nnums = "; + for (j = 0; j < nnums.Size(); j++) + (*testout) << "node " << j << " = " << nnums[j] << ", rep = " + << cluster_reps.Get(nnums[j]) << endl; + } + */ + } + } + while (changed); + + /* + (*testout) << "cluster reps:" << endl; + for (i = 1; i <= cluster_reps.Size(); i++) + { + (*testout) << i << ": "; + if (i <= nv) + (*testout) << "v" << i << " "; + else if (i <= nv+ned) + (*testout) << "e" << i-nv << " "; + else if (i <= nv+ned+nfa) + (*testout) << "f" << i-nv-ned << " "; + else + (*testout) << "c" << i-nv-ned-nfa << " "; + (*testout) << cluster_reps.Get(i) << endl; + } + */ +} +} diff --git a/contrib/Netgen/libsrc/meshing/clusters.hpp b/contrib/Netgen/libsrc/meshing/clusters.hpp new file mode 100644 index 0000000000..b0eea1b5e0 --- /dev/null +++ b/contrib/Netgen/libsrc/meshing/clusters.hpp @@ -0,0 +1,42 @@ +#ifndef CLUSTERS +#define CLUSTERS + +/**************************************************************************/ +/* File: clusers.hh */ +/* Author: Joachim Schoeberl */ +/* Date: 28. Apr. 01 */ +/**************************************************************************/ + +/* + Anisotropic clusters + + nodes, edges, faces, elements +*/ + + +class AnisotropicClusters +{ + const Mesh & mesh; + + int nv, ned, nfa, ne; + + // connected nodes, nodes = vertices, edges, faces, elements + ARRAY<int> cluster_reps; + +public: + AnisotropicClusters (const Mesh & amesh); + ~AnisotropicClusters(); + + void Update(); + + int GetVertexRepresentant (int vnr) const + { return cluster_reps.Get(vnr); } + int GetEdgeRepresentant (int ednr) const + { return cluster_reps.Get(nv+ednr); } + int GetFaceRepresentant (int fnr) const + { return cluster_reps.Get(nv+ned+fnr); } + int GetElementRepresentant (int enr) const + { return cluster_reps.Get(nv+ned+nfa+enr); } +}; + +#endif diff --git a/contrib/Netgen/libsrc/meshing/curvedelems.cpp b/contrib/Netgen/libsrc/meshing/curvedelems.cpp new file mode 100644 index 0000000000..50fea32f55 --- /dev/null +++ b/contrib/Netgen/libsrc/meshing/curvedelems.cpp @@ -0,0 +1,2037 @@ +#include <mystdlib.h> + +#include "meshing.hpp" + +namespace netgen +{ + + + // computes Gaussean integration formula on (0,1) with n points + // in: Numerical algs in C (or, was it the Fortran book ?) + void ComputeGaussRule (int n, ARRAY<double> & xi, ARRAY<double> & wi) + { + xi.SetSize (n); + wi.SetSize (n); + + int m = (n+1)/2; + double p1, p2, p3; + double pp, z, z1; + for (int i = 1; i <= m; i++) + { + z = cos ( M_PI * (i - 0.25) / (n + 0.5)); + while(1) + { + p1 = 1; p2 = 0; + for (int j = 1; j <= n; j++) + { + p3 = p2; p2 = p1; + p1 = ((2 * j - 1) * z * p2 - (j - 1) * p3) / j; + } + // p1 is legendre polynomial + + pp = n * (z*p1-p2) / (z*z - 1); + z1 = z; + z = z1-p1/pp; + + if (fabs (z - z1) < 1e-14) break; + } + + xi[i-1] = 0.5 * (1 - z); + xi[n-i] = 0.5 * (1 + z); + wi[i-1] = wi[n-i] = 1.0 / ( (1 - z * z) * pp * pp); + } + } + + + +// ---------------------------------------------------------------------------- +// PolynomialBasis +// ---------------------------------------------------------------------------- + + + void PolynomialBasis :: CalcLegendrePolynomials (double x) + { + double p1 = 1.0, p2 = 0.0, p3; + + lp[0] = 1.0; + + for (int j=1; j<=order; j++) + { + p3=p2; p2=p1; + p1=((2.0*j-1.0)*(2*x-1)*p2-(j-1.0)*p3)/j; + lp[j] = p1; + } + } + + + void PolynomialBasis :: CalcDLegendrePolynomials (double x) + { + double p1 = 0., p2 = 0., p3; + + dlp[0] = 0.; + + for (int j = 1; j <= order-1; j++) + { + p3=p2; p2=p1; + p1=((2.*j-1.)*(2*lp[j-1]+(2*x-1)*p2)-(j-1.)*p3)/j; + dlp[j] = p1; + } + } + + + void PolynomialBasis :: CalcF (double x) + { + CalcLegendrePolynomials (x); + + for (int j = 0; j<=order-2; j++) + f[j] = (lp[j+2]-lp[j])/(2.0*(j+1)+1)/2.0; + } + + + void PolynomialBasis :: CalcDf (double x) + { + CalcLegendrePolynomials (x); + + for (int j = 0; j <= order-2; j++) + df[j] = lp[j+1]; + } + + + void PolynomialBasis :: CalcFDf (double x) + { + CalcLegendrePolynomials (x); + + for (int j = 0; j<=order-2; j++) + { + f[j] = (lp[j+2]-lp[j])/(2.0*(j+1)+1)/2.0; + df[j] = lp[j+1]; + } + } + + + void PolynomialBasis :: CalcDDf (double x) + { + CalcLegendrePolynomials (x); + CalcDLegendrePolynomials (x); + + for (int j = 0; j <= order-2; j++) ddf[j] = dlp[j+1]; + } + + + +// ---------------------------------------------------------------------------- +// BaseFiniteElement1D +// ---------------------------------------------------------------------------- + + + void BaseFiniteElement1D :: CalcVertexShapes () + { + vshape[0] = xi(0); + vshape[1] = 1-xi(0); + + vdshape[0] = 1; + vdshape[1] = -1; + + /* + if (edgeorient == -1) + { + Swap (vshape[0], vshape[1]); + Swap (vdshape[0], vdshape[1]); + } + */ + + } + + + void BaseFiniteElement1D :: CalcEdgeShapes () + { + b.SetOrder (edgeorder); + if (edgeorient == 1) + b.CalcFDf( 1-xi(0) ); + else + b.CalcFDf( xi(0) ); + + for (int k = 2; k <= edgeorder; k++) + { + eshape[k-2] = b.GetF(k); + edshape[k-2] = -b.GetDf(k); + } + } + + + void BaseFiniteElement1D :: CalcEdgeLaplaceShapes () + { + b.SetOrder (edgeorder); + if (edgeorient == 1) + b.CalcDDf( 1-xi(0) ); + else + b.CalcDDf( xi(0) ); + + for (int k = 2; k <= edgeorder; k++) + eddshape[k-2] = b.GetDDf(k); + } + + + + +// ---------------------------------------------------------------------------- +// BaseFiniteElement2D +// ---------------------------------------------------------------------------- + + + void BaseFiniteElement2D :: SetElementNumber (int aelnr) + { + int locmaxedgeorder = -1; + + BaseFiniteElement<2> :: SetElementNumber (aelnr); + const Element2d & elem = mesh[(SurfaceElementIndex) (elnr-1)]; + top.GetSurfaceElementEdges (elnr, &(edgenr[0]), &(edgeorient[0])); + facenr = top.GetSurfaceElementFace (elnr); + faceorient = top.GetSurfaceElementFaceOrientation (elnr); + + for (int v = 0; v < nvertices; v++) + vertexnr[v] = elem[v]; + + for (int e = 0; e < nedges; e++) + { + edgeorder[e] = curv.GetEdgeOrder (edgenr[e]-1); // 1-based + locmaxedgeorder = max2 (edgeorder[e], locmaxedgeorder); + } + + faceorder = curv.GetFaceOrder (facenr-1); // 1-based + CalcNFaceShapes (); + + if (locmaxedgeorder > maxedgeorder) + { + maxedgeorder = locmaxedgeorder; + eshape.SetSize(nedges * (maxedgeorder-1)); + edshape.SetSize(nedges * (maxedgeorder-1)); + } + + if (faceorder > maxfaceorder) + { + maxfaceorder = faceorder; + fshape.SetSize( nfaceshapes ); // number of face shape functions + fdshape.SetSize( nfaceshapes ); + fddshape.SetSize ( nfaceshapes ); + } + } + + + + +// ---------------------------------------------------------------------------- +// BaseFiniteElement3D +// ---------------------------------------------------------------------------- + + + void BaseFiniteElement3D :: SetElementNumber (int aelnr) + { + int locmaxedgeorder = -1; + int locmaxfaceorder = -1; + int v, f, e; + + BaseFiniteElement<3> :: SetElementNumber (aelnr); + Element elem = mesh[(ElementIndex) (elnr-1)]; + top.GetElementEdges (elnr, &(edgenr[0]), &(edgeorient[0])); + top.GetElementFaces (elnr, &(facenr[0]), &(faceorient[0])); + + for (v = 0; v < nvertices; v++) + vertexnr[v] = elem[v]; + + for (f = 0; f < nfaces; f++) + { + surfacenr[f] = top.GetFace2SurfaceElement (facenr[f]); + // surfaceorient[f] = top.GetSurfaceElementFaceOrientation (surfacenr[f]); + } + + for (e = 0; e < nedges; e++) + { + edgeorder[e] = curv.GetEdgeOrder (edgenr[e]-1); // 1-based + locmaxedgeorder = max (edgeorder[e], locmaxedgeorder); + } + + for (f = 0; f < nfaces; f++) + { + faceorder[f] = curv.GetFaceOrder (facenr[f]-1); // 1-based + locmaxfaceorder = max (faceorder[f], locmaxfaceorder); + } + + CalcNFaceShapes (); + + if (locmaxedgeorder > maxedgeorder) + { + maxedgeorder = locmaxedgeorder; + eshape.SetSize(nedges * (maxedgeorder-1)); + edshape.SetSize(nedges * (maxedgeorder-1)); + } + + if (locmaxfaceorder > maxfaceorder) + { + maxfaceorder = locmaxfaceorder; + fshape.SetSize( nfaces * (maxfaceorder-1) * (maxfaceorder-1)); // number of face shape functions + fdshape.SetSize( nfaces * (maxfaceorder-1) * (maxfaceorder-1)); + } + } + + + + +// ---------------------------------------------------------------------------- +// FETrig +// ---------------------------------------------------------------------------- + + + void FETrig :: SetReferencePoint (Point<2> axi) + { + BaseFiniteElement2D :: SetReferencePoint (axi); + lambda(0) = xi(0); + lambda(1) = xi(1); + lambda(2) = 1-xi(0)-xi(1); + + dlambda(0,0) = 1; dlambda(0,1) = 0; + dlambda(1,0) = 0; dlambda(1,1) = 1; + dlambda(2,0) = -1; dlambda(2,1) = -1; + } + + + void FETrig :: SetVertexSingularity (int v, int exponent) + { + int i; + if (1-lambda(v) < EPSILON) return; + + Point<3> lamold = lambda; + + Vec<2> dfac; + + double fac = pow(1-lambda(v),exponent-1); + + for (i = 0; i < 2; i++) + { + dfac(i) = -(exponent-1)*pow(1-lambda(v),exponent-2)*dlambda(v,i); + dlambda(v,i) *= exponent * pow(1-lambda(v),exponent-1); + } + + lambda(v) = 1-pow(1-lambda(v),exponent); + + for (i = 0; i < nvertices; i++) + { + if (i == v) continue; + for (int j = 0; j < 2; j++) + dlambda(i,j) = dlambda(i,j) * fac + lamold(i) * dfac(j); + + lambda(i) *= fac; + } + } + + + + void FETrig :: CalcVertexShapes () + { + for (int v = 0; v < nvertices; v++) + { + vshape[v] = lambda(v); + vdshape[v](0) = dlambda(v,0); + vdshape[v](1) = dlambda(v,1); + } + } + + + void FETrig :: CalcEdgeShapes () + { + int index = 0; + for (int e = 0; e < nedges; e++) + { + if (edgeorder[e] <= 1) continue; + + int i0 = eledge[e][0]-1; + int i1 = eledge[e][1]-1; + + double arg = lambda(i0) + lambda(i1); // = 1-lambda[i2]; + + if (fabs(arg) < EPSILON) // division by 0 + { + for (int k = 2; k <= edgeorder[e]; k++) + { + eshape[index] = 0; + edshape[index] = Vec<2>(0,0); + index++; + } + continue; + } + + if (edgeorient[e] == -1) Swap (i0, i1); // reverse orientation + + double xi = lambda(i1)/arg; + + b1.SetOrder (edgeorder[e]); + b1.CalcFDf (xi); + + double decay = arg; + double ddecay; + + double l0 = lambda(i0); + double l0x = dlambda(i0,0); + double l0y = dlambda(i0,1); + + double l1 = lambda(i1); + double l1x = dlambda(i1,0); + double l1y = dlambda(i1,1); + + for (int k = 2; k <= edgeorder[e]; k++) + { + ddecay = k*decay; + decay *= arg; + + eshape[index] = b1.GetF (k) * decay; + edshape[index] = Vec<2> + (b1.GetDf(k) * (l1x*arg - l1*(l0x+l1x)) * + decay / (arg * arg) + b1.GetF(k) * ddecay * (l0x+l1x), + b1.GetDf(k) * (l1y*arg - l1*(l0y+l1y)) * + decay / (arg * arg) + b1.GetF(k) * ddecay * (l0y+l1y)); + index++; + } + } + // (*testout) << "eshape = " << eshape << ", edshape = " << edshape << endl; + + + /* + index = 0; + for (int e = 0; e < nedges; e++) + { + int i0 = eledge[e][0]-1; + int i1 = eledge[e][1]-1; + + if (edgeorient[e] == -1) Swap (i0, i1); // reverse orientation + + double x = lambda(i1)-lambda(i0); + double y = 1-lambda(i0)-lambda(i1); + double fy = (1-y)*(1-y); + + // double p3 = 0, p3x = 0, p3y = 0; + // double p2 = -1, p2x = 0, p2y = 0; + // double p1 = x, p1x = 1, p1y = 0; + + double p3 = 0, p3x = 0, p3y = 0; + double p2 = -0.5, p2x = 0, p2y = 0; + double p1 = 0.5*x, p1x = 0.5, p1y = 0; + + for (int j=2; j<= edgeorder[e]; j++) + { + p3=p2; p3x = p2x; p3y = p2y; + p2=p1; p2x = p1x; p2y = p1y; + double c1 = (2.0*j-3) / j; + double c2 = (j-3.0) / j; + + p1 = c1 * x * p2 - c2 * fy * p3; + p1x = c1 * p2 + c1 * x * p2x - c2 * fy * p3x; + p1y = c1 * x * p2y - (c2 * 2 * (y-1) * p3 + c2 * fy * p3y); + eshape[index] = p1; + // edshape[index] = Vec<2> (p1x, p1y); + edshape[index](0) = -2*p1x; + edshape[index](1) = p1y-p1x; + index++; + } + + } + // (*testout) << "eshape = " << eshape << ", edshape = " << edshape << endl; + */ + } + + + void FETrig :: CalcFaceShapes () + { + int index = 0; + + int i0 = elface[0][0]-1; + int i1 = elface[0][1]-1; + int i2 = elface[0][2]-1; + + // sort lambda_i's by the corresponing vertex numbers + + if (vertexnr[i1] < vertexnr[i0]) Swap (i0, i1); + if (vertexnr[i2] < vertexnr[i0]) Swap (i0, i2); + if (vertexnr[i2] < vertexnr[i1]) Swap (i1, i2); + + double arg = lambda(i1) + lambda(i2); + + if (fabs(arg) < EPSILON) // division by 0 + { + for (int k = 0; k < nfaceshapes; k++) + { + fshape[index] = 0; + fdshape[index] = Vec<2>(0,0); + index++; + } + return; + } + + b1.SetOrder (faceorder); + b2.SetOrder (faceorder); + + b1.CalcFDf (lambda(i0)); + b2.CalcFDf (lambda(i2)/arg); + + double decay = 1; + double ddecay; + + double l0 = lambda(i0); + double l1 = lambda(i1); + double l2 = lambda(i2); + double dl0x = dlambda(i0,0); + double dl0y = dlambda(i0,1); + double dl1x = dlambda(i1,0); + double dl1y = dlambda(i1,1); + double dl2x = dlambda(i2,0); + double dl2y = dlambda(i2,1); + + double dargx = dl1x + dl2x; + double dargy = dl1y + dl2y; + + for (int n1 = 2; n1 < faceorder; n1++) + { + ddecay = (n1-1)*decay; + decay *= arg; + + for (int n0 = 2; n0 < faceorder-n1+2; n0++) + { + fshape[index] = b1.GetF(n0) * b2.GetF(n1) * decay; + fdshape[index] = Vec<2> + (b1.GetDf(n0) * dl0x * b2.GetF(n1) * decay + + b1.GetF(n0) * b2.GetDf(n1) * (dl2x * arg - l2 * dargx)/(arg*arg) * decay + + b1.GetF(n0) * b2.GetF(n1) * ddecay * dargx, + b1.GetDf(n0) * dl0y * b2.GetF(n1) * decay + + b1.GetF(n0) * b2.GetDf(n1) * (dl2y * arg - l2 * dargy)/(arg*arg) * decay + + b1.GetF(n0) * b2.GetF(n1) * ddecay * dargy); + index++; + } + } + } + + + + void FETrig :: CalcFaceLaplaceShapes () + { + int index = 0; + + int i0 = elface[0][0]-1; + int i1 = elface[0][1]-1; + int i2 = elface[0][2]-1; + + if (vertexnr[i1] < vertexnr[i0]) Swap (i0, i1); + if (vertexnr[i2] < vertexnr[i0]) Swap (i0, i2); + if (vertexnr[i2] < vertexnr[i1]) Swap (i1, i2); + + double arg = lambda(i1) + lambda(i2); + + if (fabs(arg) < EPSILON) // division by 0 + { + for (int k = 0; k < nfaceshapes; k++) + fddshape[k] = 0; + return; + } + + b1.SetOrder (faceorder); + b2.SetOrder (faceorder); + + b1.CalcFDf (lambda(i0)); + b1.CalcDDf (lambda(i0)); + b2.CalcFDf (lambda(i2)/arg); + b2.CalcDDf (lambda(i2)/arg); + + double decay = 1; + double ddecay = 0; + double dddecay; + + double l0 = lambda(i0); + double l1 = lambda(i1); + double l2 = lambda(i2); + double dl0x = dlambda(i0,0); + double dl0y = dlambda(i0,1); + double dl1x = dlambda(i1,0); + double dl1y = dlambda(i1,1); + double dl2x = dlambda(i2,0); + double dl2y = dlambda(i2,1); + + double dargx = dl1x + dl2x; + double dargy = dl1y + dl2y; + + for (int n1 = 2; n1 < faceorder; n1++) + { + dddecay = (n1-1)*ddecay; + ddecay = (n1-1)*decay; + decay *= arg; + + for (int n0 = 2; n0 < faceorder-n1+2; n0++) + { + fddshape[index] = + + // b1.GetDf(n0) * dl0x * b2.GetF(n1) * decay .... derived + + b1.GetDDf(n0) * dl0x * dl0x * b2.GetF(n1) * decay + + b1.GetDf(n0) * dl0x * b2.GetDf(n1) * (dl2x * arg - l2 * dargx)/(arg*arg) * decay + + b1.GetDf(n0) * dl0x * b2.GetF(n1) * ddecay * dargx + + + + // b1.GetF(n0) * b2.GetDf(n1) * (dl2x * arg - l2 * dargx)/(arg*arg) * decay ... derived + + b1.GetDf(n0) * dl0x * b2.GetDf(n1) * (dl2x * arg - l2 * dargx)/(arg*arg) * decay + + b1.GetF(n0) * b2.GetDDf(n1) * pow((dl2x * arg - l2 * dargx)/(arg*arg),2) * decay + + b1.GetF(n0) * b2.GetDf(n1) * (-2*dargx/arg) * (dl2x * arg - l2 * dargx)/(arg*arg) * decay + + b1.GetF(n0) * b2.GetDf(n1) * (dl2x * arg - l2 * dargx)/(arg*arg) * ddecay * dargx + + + + // b1.GetF(n0) * b2.GetF(n1) * ddecay * dargx ... derived + + b1.GetDf(n0) * dl0x * b2.GetF(n1) * ddecay * dargx + + b1.GetF(n0) * b2.GetDf(n1) * (dl2x * arg - l2 * dargx)/(arg*arg) * ddecay * dargx + + b1.GetF(n0) * b2.GetF(n1) * dddecay * dargx * dargx + + + + // b1.GetDf(n0) * dl0y * b2.GetF(n1) * decay ... derived + + b1.GetDDf(n0) * dl0y * dl0y * b2.GetF(n1) * decay + + b1.GetDf(n0) * dl0y * b2.GetDf(n1) * (dl2y * arg - l2 * dargy)/(arg*arg) * decay + + b1.GetDf(n0) * dl0y * b2.GetF(n1) * ddecay * dargy + + + + // b1.GetF(n0) * b2.GetDf(n1) * (dl2y * arg - l2 * dargy)/(arg*arg) * decay ... derived + + b1.GetDf(n0) * dl0y * b2.GetDf(n1) * (dl2y * arg - l2 * dargy)/(arg*arg) * decay + + b1.GetF(n0) * b2.GetDDf(n1) * pow((dl2y * arg - l2 * dargy)/(arg*arg),2) * decay + + b1.GetF(n0) * b2.GetDf(n1) * (-2*dargy/arg) * (dl2y * arg - l2 * dargy)/(arg*arg) * decay + + b1.GetF(n0) * b2.GetDf(n1) * (dl2y * arg - l2 * dargy)/(arg*arg) * ddecay * dargy + + + + // b1.GetF(n0) * b2.GetF(n1) * ddecay * dargy ... derived + + b1.GetDf(n0) * dl0y * b2.GetF(n1) * ddecay * dargy + + b1.GetF(n0) * b2.GetDf(n1) * (dl2y * arg - l2 * dargy)/(arg*arg) * ddecay * dargy + + b1.GetF(n0) * b2.GetF(n1) * dddecay * dargy * dargy; + + index++; + } + } + } + + + +// ---------------------------------------------------------------------------- +// FEQuad +// ---------------------------------------------------------------------------- + + + void FEQuad :: CalcVertexShapes () + { + vshape[0] = (1-xi(0)) * (1-xi(1)); + vshape[1] = ( xi(0)) * (1-xi(1)); + vshape[2] = ( xi(0)) * ( xi(1)); + vshape[3] = (1-xi(0)) * ( xi(1)); + + vdshape[0] = Vec<2> ( -(1-xi(1)), -(1-xi(0)) ); + vdshape[1] = Vec<2> ( (1-xi(1)), -( xi(0)) ); + vdshape[2] = Vec<2> ( ( xi(1)), ( xi(0)) ); + vdshape[3] = Vec<2> ( -( xi(1)), (1-xi(0)) ); + } + + + void FEQuad :: CalcEdgeShapes () + { + int index = 0; + + double arg0[4] = { xi(0), 1-xi(0), 1-xi(1), xi(1) }; + double arg1[4] = { 1-xi(1), xi(1), 1-xi(0), xi(0) }; + double darg0[4] = { 1, -1, -1, 1 }; + double darg1[4] = { -1, 1, -1, 1 }; + + for (int e = 0; e < nedges; e++) + { + b1.SetOrder (edgeorder[e]); + b1.CalcFDf (edgeorient[e] == 1 ? arg0[e] : 1-arg0[e]); + + double decay = arg1[e]; + double ddecay; + + for (int k = 2; k <= edgeorder[e]; k++, index++) + { + ddecay = k*decay; + decay *= arg1[e]; +// linear decay + eshape[index] = b1.GetF(k) * arg1[e]; + + if (e < 2) + edshape[index] = Vec<2> + (darg0[e] * edgeorient[e] * b1.GetDf(k) * arg1[e], + b1.GetF(k) * darg1[e]); + else + edshape[index] = Vec<2> + (b1.GetF(k) * darg1[e], + darg0[e] * edgeorient[e] * b1.GetDf(k) * arg1[e]); + +// exponential decay +/* eshape[index] = b1.GetF(k) * decay; + + if (e < 2) + edshape[index] = Vec<2> + (darg0[e] * edgeorient[e] * b1.GetDf(k) * decay, + b1.GetF(k) * ddecay * darg1[e]); + else + edshape[index] = Vec<2> + (b1.GetF(k) * ddecay * darg1[e], + darg0[e] * edgeorient[e] * b1.GetDf(k) * decay); +*/ + } + } + } + + + void FEQuad :: CalcFaceShapes () + { + int index = 0; + + // find index of point with smallest number + + int i0 = 0; + for (int i = 1; i < 4; i++) + if (vertexnr[elface[0][i]-1] < vertexnr[elface[0][i0]-1]) i0 = i; + + double x; + double y; + double dxx; + double dxy; + double dyx; + double dyy; + + switch (i0) + { + case 0: + x = xi(0); y = xi(1); + dxx = 1; dxy = 0; + dyx = 0; dyy = 1; + break; + case 1: + x = xi(1); y = 1-xi(0); + dxx = 0; dxy = 1; + dyx = -1; dyy = 0; + break; + case 2: + x = 1-xi(0); y = 1-xi(1); + dxx = -1; dxy = 0; + dyx = 0; dyy = -1; + break; + case 3: + x = 1-xi(1); y = xi(0); + dxx = 0; dxy =-1; + dyx = 1; dyy = 0; + break; + } + + if (vertexnr[elface[0][(i0+1) % 4]-1] > vertexnr[elface[0][(i0+3) % 4]-1]) + { + Swap (x,y); + Swap (dxx, dyx); + Swap (dxy, dyy); + } + + b1.SetOrder (faceorder); + b2.SetOrder (faceorder); + + b1.CalcFDf (x); + b2.CalcFDf (y); + + for (int n0 = 2; n0 <= faceorder; n0++) + for (int n1 = 2; n1 <= faceorder; n1++) + { + fshape[index] = b1.GetF(n0) * b2.GetF(n1); + fdshape[index] = Vec<2> (b1.GetDf(n0) * dxx * b2.GetF(n1) + b1.GetF(n0) * b2.GetDf(n1) * dyx, + b1.GetDf(n0) * dxy * b2.GetF(n1) + b1.GetF(n0) * b2.GetDf(n1) * dyy); + index++; + } + } + + + void FEQuad :: CalcFaceLaplaceShapes () + { + int index = 0; + + // find index of point with smallest number + + int i0 = 0; + for (int i = 1; i < 4; i++) + if (vertexnr[elface[0][i]-1] < vertexnr[elface[0][i0]-1]) i0 = i; + + double x; + double y; + double dxx; + double dxy; + double dyx; + double dyy; + + switch (i0) + { + case 0: + x = xi(0); y = xi(1); + dxx = 1; dxy = 0; + dyx = 0; dyy = 1; + break; + case 1: + x = xi(1); y = 1-xi(0); + dxx = 0; dxy = 1; + dyx = -1; dyy = 0; + break; + case 2: + x = 1-xi(0); y = 1-xi(1); + dxx = -1; dxy = 0; + dyx = 0; dyy = -1; + break; + case 3: + x = 1-xi(1); y = xi(0); + dxx = 0; dxy =-1; + dyx = 1; dyy = 0; + break; + } + + if (vertexnr[elface[0][(i0+1) % 4]-1] > vertexnr[elface[0][(i0+3) % 4]-1]) + { + Swap (x,y); + Swap (dxx, dyx); + Swap (dxy, dyy); + } + + b1.SetOrder (faceorder); + b2.SetOrder (faceorder); + + b1.CalcFDf (x); + b1.CalcDDf (x); + b2.CalcFDf (y); + b2.CalcDDf (y); + + for (int n0 = 2; n0 <= faceorder; n0++) + for (int n1 = 2; n1 <= faceorder; n1++) + { + fddshape[index] = + b1.GetDDf(n0) * dxx * dxx * b2.GetF(n1) + + 2* b1.GetDf(n0) * dxx * b2.GetDf(n1) * dyx + + b1.GetF(n0) * b2.GetDDf(n1) * dyx * dyx + + + b1.GetDDf(n0) * dxy * dxy * b2.GetF(n1) + + 2* b1.GetDf(n0) * dxy * b2.GetDf(n1) * dyy + + b1.GetF(n0) * b2.GetDDf(n1) * dyy * dyy; + + index++; + } + } + + + +// ---------------------------------------------------------------------------- +// FETet +// ---------------------------------------------------------------------------- + + + void FETet :: SetReferencePoint (Point<3> axi) + { + BaseFiniteElement3D :: SetReferencePoint (axi); + + lambda(0) = xi(0); + lambda(1) = xi(1); + lambda(2) = xi(2); + lambda(3) = 1-xi(0)-xi(1)-xi(2); + + dlambda(0,0) = 1; dlambda(0,1) = 0; dlambda(0,2) = 0; + dlambda(1,0) = 0; dlambda(1,1) = 1; dlambda(1,2) = 0; + dlambda(2,0) = 0; dlambda(2,1) = 0; dlambda(2,2) = 1; + dlambda(3,0) = -1; dlambda(3,1) = -1; dlambda(3,2) = -1; + } + + + void FETet :: CalcVertexShapes () + { + for (int v = 0; v < nvertices; v++) + { + vshape[v] = lambda(v); + vdshape[v](0) = dlambda(v,0); + vdshape[v](1) = dlambda(v,1); + vdshape[v](2) = dlambda(v,2); + } + } + + + void FETet :: CalcEdgeShapes () + { + int index = 0; + + for (int e = 0; e < nedges; e++) + { + int i0 = eledge[e][0]-1; + int i1 = eledge[e][1]-1; + + double arg = lambda(i0)+lambda(i1); + + if (fabs(arg) < EPSILON) // division by 0 + { + for (int k = 2; k <= edgeorder[e]; k++) + { + eshape[index] = 0; + edshape[index] = Vec<3>(0,0,0); + index++; + } + continue; + } + + if (edgeorient[e] == -1) Swap (i0, i1); + + double xi = lambda[i1]/arg; + + b1.SetOrder (edgeorder[e]); + b1.CalcFDf (xi); + + double decay = arg; + double ddecay; + + double l0 = lambda(i0); + double dl0x = dlambda(i0,0); + double dl0y = dlambda(i0,1); + double dl0z = dlambda(i0,2); + + double l1 = lambda(i1); + double dl1x = dlambda(i1,0); + double dl1y = dlambda(i1,1); + double dl1z = dlambda(i1,2); + + double dargx = dl0x + dl1x; + double dargy = dl0y + dl1y; + double dargz = dl0z + dl1z; + + for (int k = 2; k <= edgeorder[e]; k++) + { + ddecay = k*decay; + decay *= arg; + + eshape[index] = b1.GetF (k) * decay; + edshape[index] = Vec<3> + (b1.GetDf(k) * (dl1x*arg - l1*dargx) * + decay / (arg * arg) + b1.GetF(k) * ddecay * dargx, + b1.GetDf(k) * (dl1y*arg - l1*dargy) * + decay / (arg * arg) + b1.GetF(k) * ddecay * dargy, + b1.GetDf(k) * (dl1z*arg - l1*dargz) * + decay / (arg * arg) + b1.GetF(k) * ddecay * dargz); + + index++; + } + } + } + + + void FETet :: CalcFaceShapes () + { + int index = 0; + + for (int f = 0; f < nfaces; f++) + { + if (faceorder[f] <= 2) continue; + + int i0 = elface[f][0]-1; + int i1 = elface[f][1]-1; + int i2 = elface[f][2]-1; + + if (vertexnr[i1] < vertexnr[i0]) Swap (i0, i1); + if (vertexnr[i2] < vertexnr[i0]) Swap (i0, i2); + if (vertexnr[i2] < vertexnr[i1]) Swap (i1, i2); + + double arg = lambda(i1) + lambda(i2); + double arg2 = lambda(i0) + lambda(i1) + lambda(i2); + + if (fabs(arg) < EPSILON || fabs(arg2) < EPSILON) // division by 0 + { + for (int k = 0; k < nfaceshapes[f]; k++) + { + fshape[index] = 0; + fdshape[index] = Vec<3>(0,0,0); + index++; + } + continue; + } + + b1.SetOrder (faceorder[f]); + b2.SetOrder (faceorder[f]); + + b1.CalcFDf (lambda(i0)/arg2); + b2.CalcFDf (lambda(i2)/arg); + + double decay = 1; + double ddecay; + + double l0 = lambda(i0); + double l1 = lambda(i1); + double l2 = lambda(i2); + double dl0x = dlambda(i0,0); + double dl0y = dlambda(i0,1); + double dl0z = dlambda(i0,2); + double dl1x = dlambda(i1,0); + double dl1y = dlambda(i1,1); + double dl1z = dlambda(i1,2); + double dl2x = dlambda(i2,0); + double dl2y = dlambda(i2,1); + double dl2z = dlambda(i2,2); + + double dargx = dl1x + dl2x; + double dargy = dl1y + dl2y; + double dargz = dl1z + dl2z; + double darg2x = dl0x + dl1x + dl2x; + double darg2y = dl0y + dl1y + dl2y; + double darg2z = dl0z + dl1z + dl2z; + + for (int n1 = 2; n1 < faceorder[f]; n1++) + { + ddecay = (n1-1)*decay; + decay *= arg; + + double decay2 = arg2; + double ddecay2; + + for (int n0 = 2; n0 < faceorder[f]-n1+2; n0++) + { + ddecay2 = n0*decay2; + decay2 *= arg2; + + fshape[index] = b1.GetF(n0) * b2.GetF(n1) * decay * decay2; + fdshape[index] = Vec<3> + (b1.GetDf(n0) * (dl0x * arg2 - l0 * darg2x)/(arg2*arg2) * b2.GetF(n1) * decay * decay2 + + b1.GetF(n0) * b2.GetDf(n1) * (dl2x * arg - l2 * dargx)/(arg*arg) * decay * decay2 + + b1.GetF(n0) * b2.GetF(n1) * ddecay * dargx * decay2 + + b1.GetF(n0) * b2.GetF(n1) * decay * ddecay2 * darg2x, + + b1.GetDf(n0) * (dl0y * arg2 - l0 * darg2y)/(arg2*arg2) * b2.GetF(n1) * decay * decay2 + + b1.GetF(n0) * b2.GetDf(n1) * (dl2y * arg - l2 * dargy)/(arg*arg) * decay * decay2 + + b1.GetF(n0) * b2.GetF(n1) * ddecay * dargy * decay2 + + b1.GetF(n0) * b2.GetF(n1) * decay * ddecay2 * darg2y, + + b1.GetDf(n0) * (dl0z * arg2 - l0 * darg2z)/(arg2*arg2) * b2.GetF(n1) * decay * decay2 + + b1.GetF(n0) * b2.GetDf(n1) * (dl2z * arg - l2 * dargz)/(arg*arg) * decay * decay2 + + b1.GetF(n0) * b2.GetF(n1) * ddecay * dargz * decay2 + + b1.GetF(n0) * b2.GetF(n1) * decay * ddecay2 * darg2z); + + index++; + } + } + } + } + + + + +// ---------------------------------------------------------------------------- +// FEPrism +// ---------------------------------------------------------------------------- + + + void FEPrism :: SetReferencePoint (Point<3> axi) + { + BaseFiniteElement3D :: SetReferencePoint (axi); + + lambda(0) = xi(0); + lambda(1) = xi(1); + lambda(2) = 1-xi(0)-xi(1); + lambda(3) = xi(2); + + dlambda(0,0) = 1; dlambda(0,1) = 0; dlambda(0,2) = 0; + dlambda(1,0) = 0; dlambda(1,1) = 1; dlambda(1,2) = 0; + dlambda(2,0) = -1; dlambda(2,1) = -1; dlambda(2,2) = 0; + dlambda(3,0) = 0; dlambda(3,1) = 0; dlambda(3,2) = 1; + } + + + void FEPrism :: CalcVertexShapes () + { + double zcomp = 1-lambda(3); + + for (int v = 0; v < nvertices; v++) + { + if (v == 3) zcomp = 1-zcomp; + + vshape[v] = lambda(v % 3) * zcomp; + vdshape[v](0) = dlambda(v % 3,0) * zcomp; + vdshape[v](1) = dlambda(v % 3,1) * zcomp; + vdshape[v](2) = lambda(v % 3) * (-dlambda(3,2)); + + if (v >= 3) vdshape[v](2) *= -1; + } + } + + + void FEPrism :: CalcEdgeShapes () + { + int index = 0; + int e; + // triangle edge shapes + + for (e = 0; e < 6; e++) + { + int i0 = (eledge[e][0]-1) % 3; + int i1 = (eledge[e][1]-1) % 3; + + double arg = lambda[i0]+lambda[i1]; + + if (fabs(arg) < EPSILON) // division by 0 + { + for (int k = 2; k <= edgeorder[e]; k++) + { + eshape[index] = 0; + edshape[index] = Vec<3>(0,0,0); + index++; + } + continue; + } + + if (edgeorient[e] == -1) Swap (i0, i1); + + double xi = lambda[i1]/arg; + + b1.SetOrder (edgeorder[e]); + b1.CalcFDf (xi); + + double decay = arg; + double ddecay; + + double zarg = e < 3 ? (1-lambda(3)) : lambda(3); + double zcomp = zarg; + double dzcomp; + + double l0 = lambda(i0); + double dl0x = dlambda(i0,0); + double dl0y = dlambda(i0,1); + + double l1 = lambda(i1); + double dl1x = dlambda(i1,0); + double dl1y = dlambda(i1,1); + + double dargx = dl0x + dl1x; + double dargy = dl0y + dl1y; + + for (int k = 2; k <= edgeorder[e]; k++) + { + ddecay = k*decay; + decay *= arg; + + dzcomp = k*zcomp; + zcomp *= zarg; + + eshape[index] = b1.GetF (k) * decay * zcomp; + edshape[index] = Vec<3> + ((b1.GetDf(k) * (dl1x*arg - l1*dargx) * + decay / (arg * arg) + b1.GetF(k) * ddecay * dargx) * zcomp, + (b1.GetDf(k) * (dl1y*arg - l1*dargy) * + decay / (arg * arg) + b1.GetF(k) * ddecay * dargy) * zcomp, + b1.GetF(k) * decay * dzcomp * (e < 3 ? -1 : 1)); + index++; + } + } + + // rectangle edge shapes + + for (e = 6; e < nedges; e++) + { + int i0 = eledge[e][0]-1; + + double arg = lambda[i0]; + + if (fabs(arg) < EPSILON) // division by 0 + { + for (int k = 2; k <= edgeorder[e]; k++) + { + eshape[index] = 0.; + edshape[index] = Vec<3>(0.,0.,0.); + index++; + } + continue; + } + + double xi = lambda[3]; + + if (edgeorient[e] == -1) xi = 1-xi; + + b1.SetOrder (edgeorder[e]); + b1.CalcFDf (xi); + + double decay = arg; + double ddecay; + + double l0 = lambda(i0); + double l0x = dlambda(i0,0); + double l0y = dlambda(i0,1); + + for (int k = 2; k <= edgeorder[e]; k++) + { + ddecay = k*decay; + decay *= arg; + + eshape[index] = b1.GetF (k) * decay; + edshape[index] = Vec<3> + (b1.GetF(k) * ddecay * l0x, + b1.GetF(k) * ddecay * l0y, + b1.GetDf(k) * edgeorient[e] * decay); + index++; + } + } + } + + + void FEPrism :: CalcFaceShapes () + { + int index = 0; + int f; + + // triangle face parts + + for (f = 0; f < 2; f++) + { + int i0 = elface[f][0]-1; + int i1 = elface[f][1]-1; + int i2 = elface[f][2]-1; + + if (vertexnr[i1] < vertexnr[i0]) Swap (i0, i1); + if (vertexnr[i2] < vertexnr[i0]) Swap (i0, i2); + if (vertexnr[i2] < vertexnr[i1]) Swap (i1, i2); + + i0 = i0 % 3; + i1 = i1 % 3; + i2 = i2 % 3; + + double arg = lambda(i1) + lambda(i2); + + if (fabs(arg) < EPSILON) // division by 0 + { + for (int k = 0; k < nfaceshapes[f]; k++) + { + fshape[index] = 0; + fdshape[index] = Vec<3>(0,0,0); + index++; + } + continue; + } + + b1.SetOrder (faceorder[f]); + b2.SetOrder (faceorder[f]); + + b1.CalcFDf (lambda(i0)); + b2.CalcFDf (lambda(i2)/arg); + + double decay = 1; + double ddecay; + + double l0 = lambda(i0); + double l1 = lambda(i1); + double l2 = lambda(i2); + double dl0x = dlambda(i0,0); + double dl0y = dlambda(i0,1); + double dl0z = dlambda(i0,2); + double dl1x = dlambda(i1,0); + double dl1y = dlambda(i1,1); + double dl1z = dlambda(i1,2); + double dl2x = dlambda(i2,0); + double dl2y = dlambda(i2,1); + double dl2z = dlambda(i2,2); + + double dargx = dl1x + dl2x; + double dargy = dl1y + dl2y; + double dargz = dl1z + dl2z; + + double arg2 = f == 0 ? 1-xi(2) : xi(2); + double darg2z = f == 0 ? -1 : 1; + + for (int n1 = 2; n1 < faceorder[f]; n1++) + { + ddecay = (n1-1)*decay; + decay *= arg; + + double decay2 = arg2; + double ddecay2; + + for (int n0 = 2; n0 < faceorder[f]-n1+2; n0++) + { + ddecay2 = n0*decay2; + decay2 *= arg2; + + fshape[index] = b1.GetF(n0) * b2.GetF(n1) * decay * decay2; + fdshape[index] = Vec<3> + (b1.GetDf(n0) * dl0x * b2.GetF(n1) * decay * decay2 + + b1.GetF(n0) * b2.GetDf(n1) * (dl2x * arg - l2 * dargx)/(arg*arg) * decay * decay2 + + b1.GetF(n0) * b2.GetF(n1) * ddecay * dargx * decay2, + + b1.GetDf(n0) * dl0y * b2.GetF(n1) * decay * decay2 + + b1.GetF(n0) * b2.GetDf(n1) * (dl2y * arg - l2 * dargy)/(arg*arg) * decay * decay2 + + b1.GetF(n0) * b2.GetF(n1) * ddecay * dargy * decay2, + + b1.GetDf(n0) * dl0z * b2.GetF(n1) * decay * decay2 + + b1.GetF(n0) * b2.GetDf(n1) * (dl2z * arg - l2 * dargz)/(arg*arg) * decay * decay2 + + b1.GetF(n0) * b2.GetF(n1) * ddecay * dargz * decay2 + + b1.GetF(n0) * b2.GetF(n1) * decay * ddecay2 * darg2z); + + index++; + } + } + } + + + // quad parts + + for (f = 2; f < nfaces; f++) + { + // find index of point with smallest number + + int i, i0 = 0; + for (i = 1; i < 4; i++) + if (vertexnr[elface[f][i]-1] < vertexnr[elface[f][i0]-1]) i0 = i; + + double arg = 0; + double dargx = 0; + double dargy = 0; + double dargz = 0; + for (i = 0; i < 4; i++) + { + arg += lambda((elface[f][i]-1) % 3)/2.0; + dargx += dlambda((elface[f][i]-1) % 3,0)/2.0; + dargy += dlambda((elface[f][i]-1) % 3,1)/2.0; + dargz += dlambda((elface[f][i]-1) % 3,2)/2.0; + } + + if (fabs(arg) < EPSILON) // division by 0 + { + for (int k = 0; k < nfaceshapes[f]; k++) + { + fshape[index] = 0; + fdshape[index] = Vec<3>(0,0,0); + index++; + } + continue; + } + + int i1 = (i0+3) % 4; + int j = (elface[f][i0]-1) % 3; + + double lam = lambda(j)/arg; + double dlamx = (dlambda(j,0)*arg-lambda(j)*dargx)/(arg*arg); + double dlamy = (dlambda(j,1)*arg-lambda(j)*dargy)/(arg*arg); + double dlamz = (dlambda(j,2)*arg-lambda(j)*dargz)/(arg*arg); + + double x; + double z; + double dxx; + double dxy; + double dxz; + double dzx; + double dzy; + double dzz; + + int ratvar; + /* + switch (i0) + { + case 0: + x = xi(2); z = lam; + + dxx = 0; dxy = 0; dxz = 1; + dzx = dlamx; dzy = dlamy; dzz = dlamz; + ratvar = 1; + break; + case 1: + x = 1-lam; z = xi(2); + dxx = -dlamx; dxy = -dlamy; dxz = -dlamz; + dzx = 0; dzy = 0; dzz = 1; + ratvar = 0; + break; + case 2: + x = 1-xi(2); z = 1-lam; + dxx = 0; dxy = 0; dxz = -1; + dzx = -dlamx; dzy = -dlamy; dzz = -dlamz; + ratvar = 1; + break; + case 3: + x = lam; z = 1-xi(2); + dxx = dlamx; dxy = dlamy; dxz = dlamz; + dzx = 0; dzy = 0; dzz = -1; + ratvar = 0; + break; + } + */ + + ratvar = 0; + x = 1-lam; + dxx = -dlamx; dxy = -dlamy; dxz = -dlamz; + if (i0 == 0 || i0 == 1) + { + z = xi(2); + dzx = 0; dzy = 0; dzz = 1; + } + else + { + z = 1-xi(2); + dzx = 0; dzy = 0; dzz = -1; + } + + int ix = i0 ^ 1; + int iz = 3-i0; + + if (vertexnr[elface[f][ix]-1] > vertexnr[elface[f][iz]-1]) + { + Swap (x,z); + Swap (dxx, dzx); + Swap (dxy, dzy); + Swap (dxz, dzz); + ratvar = 1-ratvar; + } + + b1.SetOrder (faceorder[f]); + b2.SetOrder (faceorder[f]); + + b1.CalcFDf (x); + b2.CalcFDf (z); + + double decay = arg; + double ddecay; + + for (int n0 = 2; n0 <= faceorder[f]; n0++) + { + ddecay = n0*decay; + decay *= arg; + + if (ratvar == 1) decay = arg; + + for (int n1 = 2; n1 <= faceorder[f]; n1++) + { + if (ratvar == 1) + { + ddecay = n1*decay; + decay *= arg; + } + + fshape[index] = b1.GetF(n0) * b2.GetF(n1) * decay; + fdshape[index] = Vec<3> + (b1.GetDf(n0) * dxx * b2.GetF(n1) * decay + + b1.GetF(n0) * b2.GetDf(n1) * dzx * decay + + b1.GetF(n0) * b2.GetF(n1) * ddecay * dargx, + + b1.GetDf(n0) * dxy * b2.GetF(n1) * decay + + b1.GetF(n0) * b2.GetDf(n1) * dzy * decay + + b1.GetF(n0) * b2.GetF(n1) * ddecay * dargy, + + b1.GetDf(n0) * dxz * b2.GetF(n1) * decay + + b1.GetF(n0) * b2.GetDf(n1) * dzz * decay + + b1.GetF(n0) * b2.GetF(n1) * ddecay * dargz); + + index++; + } + } + } + } + + + +// ---------------------------------------------------------------------------- +// FEPyramid +// ---------------------------------------------------------------------------- + + + void FEPyramid :: SetReferencePoint (Point<3> axi) + { + BaseFiniteElement3D :: SetReferencePoint (axi); + } + + + void FEPyramid :: CalcVertexShapes () + { + double x = xi(0); + double y = xi(1); + double z = xi(2); + + if (z == 1.) z = 1-1e-10; + vshape[0] = (1-z-x)*(1-z-y) / (1-z); + vshape[1] = x*(1-z-y) / (1-z); + vshape[2] = x*y / (1-z); + vshape[3] = (1-z-x)*y / (1-z); + vshape[4] = z; + + double z1 = 1-z; + double z2 = z1*z1; + + vdshape[0] = Vec<3>( -(z1-y)/z1, -(z1-x)/z1, ((x+y+2*z-2)*z1+(z1-y)*(z1-x))/z2 ); + vdshape[1] = Vec<3>( (z1-y)/z1, -x/z1, (-x*z1+x*(z1-y))/z2 ); + vdshape[2] = Vec<3>( y/z1, x/z1, x*y/z2 ); + vdshape[3] = Vec<3>( -y/z1, (z1-x)/z1, (-y*z1+y*(z1-x))/z2 ); + vdshape[4] = Vec<3>( 0, 0, 1 ); + } + + + void FEPyramid :: CalcEdgeShapes () + { + int index = 0; + + for (int e = 0; e < GetNEdges(); e++) + { + for (int k = 2; k <= edgeorder[e]; k++) + { + eshape[index] = 0; + edshape[index] = Vec<3>(0,0,0); + index++; + } + } + } + + + void FEPyramid :: CalcFaceShapes () + { + int index = 0; + + for (int f = 0; f < GetNFaces(); f++) + { + for (int k = 0; k < nfaceshapes[f]; k++) + { + fshape[index] = 0; + fdshape[index] = Vec<3>(0,0,0); + index++; + } + } + } + + + + + +// ---------------------------------------------------------------------------- +// FEHex +// ---------------------------------------------------------------------------- + + + void FEHex :: SetReferencePoint (Point<3> axi) + { + BaseFiniteElement3D :: SetReferencePoint (axi); + } + + + void FEHex :: CalcVertexShapes () + { + double x = xi(0); + double y = xi(1); + double z = xi(2); + + vshape[0] = (1-x)*(1-y)*(1-z); + vshape[1] = x *(1-y)*(1-z); + vshape[2] = x * y *(1-z); + vshape[3] = (1-x)* y *(1-z); + vshape[4] = (1-x)*(1-y)* z; + vshape[5] = x *(1-y)* z; + vshape[6] = x * y * z; + vshape[7] = (1-x)* y * z; + + vdshape[0] = Vec<3>(-(1-y)*(1-z), -(1-x)*(1-z), -(1-x)*(1-y)); + vdshape[1] = Vec<3>( (1-y)*(1-z), -x *(1-z), -x *(1-y)); + vdshape[2] = Vec<3>( y *(1-z), x *(1-z), -x * y); + vdshape[3] = Vec<3>( -y *(1-z), (1-x)*(1-z), -(1-x)*y); + vdshape[4] = Vec<3>(-(1-y)* z, -(1-x)* z, (1-x)*(1-y)); + vdshape[5] = Vec<3>( (1-y)* z, -x * z, x *(1-y)); + vdshape[6] = Vec<3>( y * z, x * z, x * y); + vdshape[7] = Vec<3>( -y * z, (1-x)* z, (1-x)*y); + + } + + + void FEHex :: CalcEdgeShapes () + { + int index = 0; + + for (int e = 0; e < GetNEdges(); e++) + { + for (int k = 2; k <= edgeorder[e]; k++) + { + eshape[index] = 0; + edshape[index] = Vec<3>(0,0,0); + index++; + } + } + } + + + void FEHex :: CalcFaceShapes () + { + int index = 0; + + for (int f = 0; f < GetNFaces(); f++) + { + for (int k = 0; k < nfaceshapes[f]; k++) + { + fshape[index] = 0; + fdshape[index] = Vec<3>(0,0,0); + index++; + } + } + } + + + + + + + + + + int CurvedElements :: IsSurfaceElementCurved (int elnr) const + { + if (mesh.coarsemesh) + { + const HPRefElement & hpref_el = + (*mesh.hpelements) [ mesh[(SurfaceElementIndex) elnr].hp_elnr]; + + return mesh.coarsemesh->GetCurvedElements().IsSurfaceElementCurved (hpref_el.coarse_elnr); + } + + + + + Element2d elem = mesh[(SurfaceElementIndex) elnr]; + + switch (elem.GetType()) + { + case TRIG: + { + FETrig fe2d(*this); + fe2d.SetElementNumber (elnr+1); + return (fe2d.IsCurved()); + break; + } + + case QUAD: + { + FEQuad fe2d(*this); + fe2d.SetElementNumber (elnr+1); + return (fe2d.IsCurved()); + break; + } + + } + return 0; + } + + + + int CurvedElements :: IsElementCurved (int elnr) const + { + if (mesh.coarsemesh) + { + const HPRefElement & hpref_el = + (*mesh.hpelements) [ mesh[(ElementIndex) elnr].hp_elnr]; + + return mesh.coarsemesh->GetCurvedElements().IsElementCurved (hpref_el.coarse_elnr); + } + + + + Element elem = mesh[(ElementIndex) elnr]; + + switch (elem.GetType()) + { + case TET: + { + FETet fe3d(*this); + fe3d.SetElementNumber (elnr+1); + return (fe3d.IsCurved()); + break; + } + + case PRISM: + { + FEPrism fe3d(*this); + fe3d.SetElementNumber (elnr+1); + return (fe3d.IsCurved()); + break; + } + + case PYRAMID: + { + FEPyramid fe3d(*this); + fe3d.SetElementNumber (elnr+1); + return (fe3d.IsCurved()); + break; + } + + case HEX: + { + FEHex fe3d(*this); + fe3d.SetElementNumber (elnr+1); + return (fe3d.IsCurved()); + break; + } + + } + + return 0; + } + + + void CurvedElements :: CalcSegmentTransformation (double xi, int segnr, + Point<3> * x, Vec<3> * dxdxi) + { + FESegm segm (*this); + segm.SetElementNumber (segnr+1); + segm.SetReferencePoint (Point<1>(xi)); + +// segm.CalcVertexShapes (x != NULL, dxdxi != NULL); + segm.CalcVertexShapes (); + + if (x) + { + (*x) = Point<3>(0,0,0); + for (int v = 0; v < 2; v++) + (*x) = (*x) + segm.GetVertexShape(v) * mesh.Point(segm.GetVertexNr(v)); + } + + if (dxdxi) + { + (*dxdxi) = Vec<3>(0,0,0); + for (int v = 0; v < 2; v++) + (*dxdxi) = (*dxdxi) + segm.GetVertexDShape(v) * mesh.Point(segm.GetVertexNr(v)); + } + + if (segm.GetEdgeOrder() > 1) + { +// segm.CalcEdgeShapes (x != NULL, dxdxi != NULL); + segm.CalcEdgeShapes (); + + if (x) + { + int gindex = edgecoeffsindex[segm.GetEdgeNr()-1]; + for (int k = 2; k <= segm.GetEdgeOrder(); k++, gindex++) + (*x) = (*x) + segm.GetEdgeShape(k-2) * edgecoeffs[gindex]; + } + + if (dxdxi) + { + int gindex = edgecoeffsindex[segm.GetEdgeNr()-1]; + for (int k = 2; k <= segm.GetEdgeOrder(); k++, gindex++) + (*dxdxi) = (*dxdxi) + segm.GetEdgeDShape(k-2) * edgecoeffs[gindex]; + } + } + } + + + + void CurvedElements :: CalcSurfaceTransformation (Point<2> xi, int elnr, + Point<3> * x, Mat<3,2> * dxdxi) + { + + if (mesh.coarsemesh) + { + const HPRefElement & hpref_el = + (*mesh.hpelements) [ mesh[(SurfaceElementIndex) elnr].hp_elnr]; + + // xi umrechnen + double lami[4]; + switch (mesh[(SurfaceElementIndex) elnr].GetType()) + { + case TRIG: + { + lami[0] = xi(0); + lami[1] = xi(1); + lami[2] = 1-xi(0)-xi(1); + lami[3] = 0; + break; + } + case QUAD: + { + lami[0] = (1-xi(0))*(1-xi(1)); + lami[1] = xi(0) * (1-xi(1)); + lami[2] = xi(0) * xi(1); + lami[3] = (1-xi(0))*xi(1); + break; + } + } + Point<2> coarse_xi(0,0); + for (int i = 0; i < 4; i++) + { + coarse_xi(0) += hpref_el.param[i][0] * lami[i]; + coarse_xi(1) += hpref_el.param[i][1] * lami[i]; + } + mesh.coarsemesh->GetCurvedElements().CalcSurfaceTransformation (coarse_xi, hpref_el.coarse_elnr, x, dxdxi); + + return; + } + + + + + const Element2d & elem = mesh[(SurfaceElementIndex) elnr]; + + BaseFiniteElement2D * fe2d; + + // char locmem[max2(sizeof(FEQuad), sizeof(FETrig))]; + char locmemtrig[sizeof(FETrig)]; + char locmemquad[sizeof(FEQuad)]; + switch (elem.GetType()) + { + case TRIG: fe2d = new (locmemtrig) FETrig (*this); break; + case QUAD: fe2d = new (locmemquad) FEQuad (*this); break; + } + + fe2d->SetElementNumber (elnr+1); + fe2d->SetReferencePoint (xi); + + /* + for (int v = 0; v < fe2d->GetNVertices(); v++) + { + // if (fe2d->GetVertexNr(v) == 1) + fe2d->SetVertexSingularity (v, 2); + } + */ + /* + int imin = 0, imax = 0; + if (fe2d->GetVertexNr(1) < fe2d->GetVertexNr(0)) imin = 1; + if (fe2d->GetVertexNr(2) < fe2d->GetVertexNr(imin)) imin = 2; + if (fe2d->GetVertexNr(1) > fe2d->GetVertexNr(0)) imax = 1; + if (fe2d->GetVertexNr(2) > fe2d->GetVertexNr(imax)) imax = 2; + + fe2d->SetVertexSingularity (imin, 3); + fe2d->SetVertexSingularity (3-imin-imax, 3); + fe2d->SetVertexSingularity (imax, 3); + */ + fe2d->CalcVertexShapes (); + + if (x) + { + (*x) = Point<3>(0,0,0); + for (int v = 0; v < fe2d->GetNVertices(); v++) + (*x) = (*x) + fe2d->GetVertexShape(v) * mesh.Point(fe2d->GetVertexNr(v)); + } + + if (dxdxi) + { + for (int i = 0; i < 3; i++) + for (int j = 0; j < 2; j++) + (*dxdxi)(i,j) = 0; + + for (int v = 0; v < elem.GetNV(); v++) + for (int i = 0; i < 3; i++) + for (int j = 0; j < 2; j++) + (*dxdxi)(i,j) += fe2d->GetVertexDShape(v)(j) * mesh.Point(fe2d->GetVertexNr(v)).X(i+1); + } + + if (IsHighOrder()) + { +// fe2d->CalcEdgeShapes (x != NULL, dxdxi != NULL); + fe2d->CalcEdgeShapes (); + if (x) + { + int index = 0; + for (int e = 0; e < fe2d->GetNEdges(); e++) + { + int gindex = edgecoeffsindex[fe2d->GetEdgeNr(e)-1]; + + for (int k = 2; k <= fe2d->GetEdgeOrder(e); k++, index++, gindex++) + (*x) = (*x) + fe2d->GetEdgeShape(index) * edgecoeffs[gindex]; + } + } + + if (dxdxi) + { + int index = 0; + for (int e = 0; e < fe2d->GetNEdges(); e++) + { + int gindex = edgecoeffsindex[fe2d->GetEdgeNr(e)-1]; + for (int k = 2; k <= fe2d->GetEdgeOrder(e); k++, index++, gindex++) + for (int i = 0; i < 3; i++) + for (int j = 0; j < 2; j++) + (*dxdxi)(i,j) += fe2d->GetEdgeDShape(index)(j) * edgecoeffs[gindex](i); + } + } + + if (mesh.GetDimension() == 3) + { +// fe2d->CalcFaceShapes (x != NULL, dxdxi != NULL); + fe2d->CalcFaceShapes (); + + if (x) + { + int gindex = facecoeffsindex[fe2d->GetFaceNr()-1]; + for (int index = 0; index < fe2d->GetNFaceShapes(); index++, gindex++) + { + (*x) = (*x) + fe2d->GetFaceShape(index) * facecoeffs[gindex]; + } + } + + if (dxdxi) + { + int gindex = facecoeffsindex[fe2d->GetFaceNr()-1]; + for (int index = 0; index < fe2d->GetNFaceShapes(); index++, gindex++) + for (int i = 0; i < 3; i++) + for (int j = 0; j < 2; j++) + (*dxdxi)(i,j) += fe2d->GetFaceDShape(index)(j) * facecoeffs[gindex](i); + } + } + } + + fe2d -> ~BaseFiniteElement2D(); + } + + + + + void CurvedElements :: CalcElementTransformation (Point<3> xi, int elnr, + Point<3> * x, Mat<3,3> * dxdxi) + { + + if (mesh.coarsemesh) + { + const HPRefElement & hpref_el = + (*mesh.hpelements) [ mesh[(ElementIndex) elnr].hp_elnr]; + + + double lami[8]; + FlatVector vlami(8, lami); + vlami = 0; + mesh[(ElementIndex) elnr] . GetShapeNew (xi, vlami); + + Point<3> coarse_xi(0,0,0); + for (int i = 0; i < 8; i++) + for (int l = 0; l < 3; l++) + coarse_xi(l) += hpref_el.param[i][l] * lami[i]; + + Mat<3,3> trans, dxdxic; + if (dxdxi) + { + MatrixFixWidth<3> dlami(8); + dlami = 0; + mesh[(ElementIndex) elnr] . GetDShapeNew (xi, dlami); + + trans = 0; + for (int k = 0; k < 3; k++) + for (int l = 0; l < 3; l++) + { + double sum = 0; + for (int i = 0; i < 8; i++) + sum += hpref_el.param[i][l] * dlami(i, k); + trans(l,k) = sum; + } + } + + mesh.coarsemesh->GetCurvedElements().CalcElementTransformation (coarse_xi, hpref_el.coarse_elnr, x, &dxdxic); + + if (dxdxi) + *dxdxi = dxdxic * trans; + return; + } + + + + + + + + + + Element elem = mesh[(ElementIndex) elnr]; + BaseFiniteElement3D * fe3d; + + // char locmem[max2(sizeof(FETet), sizeof(FEPrism))]; + char locmemtet[sizeof(FETet)]; + char locmemprism[sizeof(FEPrism)]; + char locmempyramid[sizeof(FEPyramid)]; + char locmemhex[sizeof(FEHex)]; + switch (elem.GetType()) + { + case TET: fe3d = new (locmemtet) FETet (*this); break; + case PRISM: fe3d = new (locmemprism) FEPrism (*this); break; + case PYRAMID: fe3d = new (locmempyramid) FEPyramid (*this); break; + case HEX: fe3d = new (locmemhex) FEHex (*this); break; + } + + fe3d->SetElementNumber (elnr+1); + fe3d->SetReferencePoint (xi); + + fe3d->CalcVertexShapes (); +// fe3d->CalcVertexShapes (x != NULL, dxdxi != NULL); + + if (x) + { + (*x) = Point<3>(0,0,0); + for (int v = 0; v < fe3d->GetNVertices(); v++) + (*x) += fe3d->GetVertexShape(v) * Vec<3> (mesh.Point(fe3d->GetVertexNr(v))); + } + + if (dxdxi) + { + for (int i = 0; i < 3; i++) + for (int j = 0; j < 3; j++) + (*dxdxi)(i,j) = 0; + + for (int v = 0; v < fe3d->GetNVertices(); v++) + for (int i = 0; i < 3; i++) + for (int j = 0; j < 3; j++) + (*dxdxi)(i,j) += fe3d->GetVertexDShape(v)(j) * mesh.Point(fe3d->GetVertexNr(v)).X(i+1); + } + + if (IsHighOrder()) + { +// fe3d->CalcEdgeShapes (x != NULL, dxdxi != NULL); + fe3d->CalcEdgeShapes (); + + if (x) + { + int index = 0; + for (int e = 0; e < fe3d->GetNEdges(); e++) + { + int gindex = edgecoeffsindex[fe3d->GetEdgeNr(e)-1]; + for (int k = 2; k <= fe3d->GetEdgeOrder(e); k++, index++, gindex++) + (*x) += fe3d->GetEdgeShape(index) * edgecoeffs[gindex]; + } + } + + if (dxdxi) + { + int index = 0; + for (int e = 0; e < fe3d->GetNEdges(); e++) + { + int gindex = edgecoeffsindex[fe3d->GetEdgeNr(e)-1]; + for (int k = 2; k <= fe3d->GetEdgeOrder(e); k++, index++, gindex++) + for (int i = 0; i < 3; i++) + for (int j = 0; j < 3; j++) + (*dxdxi)(i,j) += fe3d->GetEdgeDShape(index)(j) * edgecoeffs[gindex](i); + } + } + + if (mesh.GetDimension() == 3) + { + fe3d->CalcFaceShapes (); +// fe3d->CalcFaceShapes (x != NULL, dxdxi != NULL); + + if (x) + { + int index = 0; + for (int f = 0; f < fe3d->GetNFaces(); f++) + { + int gindex = facecoeffsindex[fe3d->GetFaceNr(f)-1]; + for (int k = 0; k < fe3d->GetNFaceShapes(f); k++, index++, gindex++) + (*x) += fe3d->GetFaceShape(index) * facecoeffs[gindex]; + } + } + + if (dxdxi) + { + int index = 0; + for (int f = 0; f < fe3d->GetNFaces(); f++) + { + int gindex = facecoeffsindex[fe3d->GetFaceNr(f)-1]; + for (int k = 0; k < fe3d->GetNFaceShapes(f); k++, index++, gindex++) + for (int i = 0; i < 3; i++) + for (int j = 0; j < 3; j++) + (*dxdxi)(i,j) += fe3d->GetFaceDShape(index)(j) * facecoeffs[gindex](i); + } + } + } + } + + fe3d -> ~BaseFiniteElement3D(); + } + + +} // namespace netgen + + diff --git a/contrib/Netgen/libsrc/meshing/curvedelems.hpp b/contrib/Netgen/libsrc/meshing/curvedelems.hpp new file mode 100644 index 0000000000..dd11eef051 --- /dev/null +++ b/contrib/Netgen/libsrc/meshing/curvedelems.hpp @@ -0,0 +1,837 @@ +#ifndef CURVEDELEMS +#define CURVEDELEMS + +/**************************************************************************/ +/* File: curvedelems.hpp */ +/* Author: Robert Gaisbauer */ +/* Date: 27. Sep. 02 (second version: 30. Jan. 03) */ +/**************************************************************************/ + +#include "bisect.hpp" +#include <iostream> + +#define EPSILON 1e-20 + + + +void ComputeGaussRule (int n, ARRAY<double> & xi, ARRAY<double> & wi); + + + + + +// ---------------------------------------------------------------------------- +// CurvedElements +// ---------------------------------------------------------------------------- + +class CurvedElements +{ + const Mesh & mesh; + const MeshTopology & top; + + bool isHighOrder; + int nvisualsubsecs; + int nIntegrationPoints; + + ARRAY<int> edgeorder; + ARRAY<int> faceorder; + + /* + + ARRAY< Vec<3> > edgecoeffs; + ARRAY< Vec<3> > facecoeffs; + + ARRAY<int> edgecoeffsindex; + ARRAY<int> facecoeffsindex; + + */ + + inline Vec<3> GetEdgeCoeff (int edgenr, int k); + inline Vec<3> GetFaceCoeff (int facenr, int k); + + + void CalcSegmentTransformation (double xi, int segnr, + Point<3> * x = NULL, Vec<3> * dxdxi = NULL); + + void CalcSurfaceTransformation (Point<2> xi, int elnr, + Point<3> * x = NULL, Mat<3,2> * dxdxi = NULL); + + void CalcElementTransformation (Point<3> xi, int elnr, + Point<3> * x = NULL, Mat<3,3> * dxdxi = NULL); + +public: + + Refinement * refinement; + + ARRAY< Vec<3> > edgecoeffs; + ARRAY< Vec<3> > facecoeffs; + + ARRAY<int> edgecoeffsindex; + ARRAY<int> facecoeffsindex; + + + + + + CurvedElements (const Mesh & amesh); + ~CurvedElements(); + + bool IsHighOrder() const + { return isHighOrder; }; + void SetHighOrder () { isHighOrder = 1; } + + + int GetNVisualSubsecs() const + { return nvisualsubsecs; }; + + const class Mesh & GetMesh() const + { return mesh; }; + + void BuildCurvedElements(Refinement * ref, int polydeg); + + int GetEdgeOrder (int edgenr) const + { return edgeorder[edgenr]; }; + + int GetFaceOrder (int facenr) const + { return faceorder[facenr]; }; + + int IsEdgeCurved (int edgenr) const; + + int IsFaceCurved (int facenr) const; + + int IsSurfaceElementCurved (int elnr) const; + + int IsElementCurved (int elnr) const; + + + void CalcSegmentTransformation (double xi, int segnr, + Point<3> & x) + { CalcSegmentTransformation (xi, segnr, &x, NULL); }; + + void CalcSegmentTransformation (double xi, int segnr, + Vec<3> & dxdxi) + { CalcSegmentTransformation (xi, segnr, NULL, &dxdxi); }; + + void CalcSegmentTransformation (double xi, int segnr, + Point<3> & x, Vec<3> & dxdxi) + { CalcSegmentTransformation (xi, segnr, &x, &dxdxi); }; + + + void CalcSurfaceTransformation (Point<2> & xi, int elnr, + Point<3> & x) + { CalcSurfaceTransformation (xi, elnr, &x, NULL); }; + + void CalcSurfaceTransformation (Point<2> & xi, int elnr, + Mat<3,2> & dxdxi) + { CalcSurfaceTransformation (xi, elnr, NULL, &dxdxi); }; + + void CalcSurfaceTransformation (Point<2> & xi, int elnr, + Point<3> & x, Mat<3,2> & dxdxi) + { CalcSurfaceTransformation (xi, elnr, &x, &dxdxi); }; + + + void CalcElementTransformation (Point<3> xi, int elnr, + Point<3> & x) + { CalcElementTransformation (xi, elnr, &x, NULL); }; + + void CalcElementTransformation (Point<3> xi, int elnr, + Mat<3,3> & dxdxi) + { CalcElementTransformation (xi, elnr, NULL, &dxdxi); }; + + void CalcElementTransformation (Point<3> xi, int elnr, + Point<3> & x, Mat<3,3> & dxdxi) + { CalcElementTransformation (xi, elnr, &x, &dxdxi); }; + +}; + + + +// ---------------------------------------------------------------------------- +// PolynomialBasis +// ---------------------------------------------------------------------------- + +class PolynomialBasis +{ + int order; + int maxorder; + ArrayMem<double,20> f; + ArrayMem<double,20> df; + ArrayMem<double,20> ddf; + + ArrayMem<double,20> lp; + ArrayMem<double,20> dlp; + + inline void CalcLegendrePolynomials (double x); + inline void CalcDLegendrePolynomials (double x); + +public: + + PolynomialBasis () + { maxorder = -1; }; + + ~PolynomialBasis () + {}; + + void SetOrder (int aorder) + { + order = aorder; + if (order > maxorder) + { + maxorder = order; + f.SetSize(order-1); + df.SetSize(order-1); + ddf.SetSize(order-1); + lp.SetSize(order+1); + dlp.SetSize(order); + }; + }; + + inline void CalcF (double x); + inline void CalcDf (double x); + inline void CalcDDf (double x); + + inline void CalcFDf (double x); + + double GetF (int p) { return f[p-2]; }; + double GetDf (int p) { return df[p-2]; }; + double GetDDf (int p) { return ddf[p-2]; }; +}; + + + +// ---------------------------------------------------------------------------- +// BaseFiniteElement +// ---------------------------------------------------------------------------- + +template <int DIM> +class BaseFiniteElement +{ +protected: + + Point<DIM> xi; + int elnr; + const CurvedElements & curv; + const Mesh & mesh; + const MeshTopology & top; + +public: + + BaseFiniteElement(const CurvedElements & acurv) + : curv(acurv), mesh(curv.GetMesh()), top(mesh.GetTopology()) + {}; + + virtual ~BaseFiniteElement() + {}; + + void SetElementNumber (int aelnr) + { elnr = aelnr; }; // 1-based arrays in netgen + + virtual void SetReferencePoint (Point<DIM> axi) + { xi = axi; }; +}; + + + +// ---------------------------------------------------------------------------- +// BaseFiniteElement1D +// ---------------------------------------------------------------------------- + +class BaseFiniteElement1D : public BaseFiniteElement<1> +{ +protected: + PolynomialBasis b; + + int vertexnr[2]; + int edgenr; + int edgeorient; + int edgeorder; + + int maxedgeorder; + + double vshape[2]; + double vdshape[2]; + ArrayMem<double,20> eshape; + ArrayMem<double,20> edshape; + ArrayMem<double,20> eddshape; + +public: + + BaseFiniteElement1D (const CurvedElements & acurv) : BaseFiniteElement<1>(acurv) + { maxedgeorder = 1; }; + + virtual ~BaseFiniteElement1D() + {}; + + int GetVertexNr (int v) + { return vertexnr[v]; }; + + int GetEdgeNr () + { return edgenr; }; + + int GetEdgeOrder () + { return edgeorder; }; + + int GetEdgeOrientation () + { return edgeorient; }; + + void CalcVertexShapes(); + void CalcEdgeShapes(); + void CalcEdgeLaplaceShapes(); + + double GetVertexShape (int v) + { return vshape[v]; }; + + double GetEdgeShape (int index) + { return eshape[index]; }; + + double GetVertexDShape (int v) + { return vdshape[v]; }; + + double GetEdgeDShape (int index) + { return edshape[index]; }; + + double GetEdgeLaplaceShape (int index) + { return eddshape[index]; }; + +}; + + + + +// ---------------------------------------------------------------------------- +// FESegm +// ---------------------------------------------------------------------------- + +class FESegm : public BaseFiniteElement1D +{ + +public: + + FESegm(const CurvedElements & acurv) : BaseFiniteElement1D(acurv) + {}; + + virtual ~FESegm() + {}; + + void SetElementNumber (int aelnr) + { + BaseFiniteElement<1> :: SetElementNumber (aelnr); + Segment s = mesh.LineSegment(elnr); + vertexnr[0] = s.p1; + vertexnr[1] = s.p2; + edgenr = top.GetSegmentEdge(elnr); + edgeorient = top.GetSegmentEdgeOrientation(elnr); + edgeorder = curv.GetEdgeOrder(edgenr-1); // 1-based arrays in netgen + + if (edgeorder > maxedgeorder) + { + maxedgeorder = edgeorder; + eshape.SetSize(maxedgeorder-1); + edshape.SetSize(maxedgeorder-1); + eddshape.SetSize(maxedgeorder-1); + } + }; + +}; + + + +// ---------------------------------------------------------------------------- +// FEEdge +// ---------------------------------------------------------------------------- + +class FEEdge : public BaseFiniteElement1D +{ + +public: + + FEEdge(const CurvedElements & acurv) : BaseFiniteElement1D(acurv) + {}; + + virtual ~FEEdge() + {}; + + void SetElementNumber (int aelnr) + { + BaseFiniteElement<1> :: SetElementNumber (aelnr); + top.GetEdgeVertices (elnr, vertexnr[0], vertexnr[1]); + edgenr = elnr; + edgeorient = 1; + edgeorder = curv.GetEdgeOrder(edgenr-1); // 1-based arrays in netgen + + if (edgeorder > maxedgeorder) + { + maxedgeorder = edgeorder; + eshape.SetSize(maxedgeorder-1); + edshape.SetSize(maxedgeorder-1); + eddshape.SetSize(maxedgeorder-1); + } + }; + +}; + + + +// ---------------------------------------------------------------------------- +// BaseFiniteElement2D +// ---------------------------------------------------------------------------- + +class BaseFiniteElement2D : public BaseFiniteElement<2> +{ +protected: + + int nvertices; + int nedges; + + int vertexnr[4]; + int edgenr[4]; + int edgeorient[4]; + int edgeorder[4]; + int facenr; + int faceorient; + int faceorder; + + int nfaceshapes; + + int maxedgeorder; + int maxfaceorder; + + PolynomialBasis b1, b2; + + double vshape[4]; + Vec<2> vdshape[4]; + ArrayMem<double,80> eshape; + ArrayMem< Vec<2>,80> edshape; + ArrayMem<double,400> fshape; + ArrayMem<Vec<2>,400> fdshape; + ArrayMem<double,400> fddshape; + + virtual void CalcNFaceShapes () = 0; + +public: + + BaseFiniteElement2D (const CurvedElements & acurv) : BaseFiniteElement<2>(acurv) + { maxedgeorder = maxfaceorder = -1; }; + + virtual ~BaseFiniteElement2D() + {}; + + void SetElementNumber (int aelnr); + + virtual void SetVertexSingularity (int v, int exponent) = 0; + + int GetVertexNr (int v) + { return vertexnr[v]; }; + + int GetEdgeNr (int e) + { return edgenr[e]; }; + + int GetFaceNr () + { return facenr; }; + + int GetEdgeOrder (int e) + { return edgeorder[e]; }; + + int GetFaceOrder () + { return faceorder; } + + int GetNVertices () + { return nvertices; }; + + int GetNEdges () + { return nedges; }; + + int GetNFaceShapes () + { return nfaceshapes; }; + + int IsCurved () + { + bool iscurved = 0; + int e; + + for (e = 0; e < GetNEdges(); e++) + iscurved = iscurved || (GetEdgeOrder(e) > 1); + + return iscurved || (GetFaceOrder() > 1); + } + + virtual void CalcVertexShapes() = 0; + virtual void CalcEdgeShapes() = 0; + virtual void CalcFaceShapes() = 0; + + virtual void CalcFaceLaplaceShapes() = 0; + + double GetVertexShape (int v) + { return vshape[v]; }; + + double GetEdgeShape (int index) + { return eshape[index]; }; + + double GetFaceShape (int index) + { return fshape[index]; }; + + Vec<2> GetVertexDShape (int v) + { return vdshape[v]; }; + + Vec<2> GetEdgeDShape (int index) + { return edshape[index]; }; + + Vec<2> GetFaceDShape (int index) + { return fdshape[index]; }; + + double GetFaceLaplaceShape (int index) + { return fddshape[index]; }; +}; + + + +// ---------------------------------------------------------------------------- +// FETrig +// ---------------------------------------------------------------------------- + +class FETrig : public BaseFiniteElement2D +{ + Point<3> lambda; + Mat<3,2> dlambda; + + const ELEMENT_EDGE * eledge; + const ELEMENT_FACE * elface; + + virtual void CalcNFaceShapes () + { nfaceshapes = ((faceorder-1)*(faceorder-2))/2; }; + +public: + + FETrig (const CurvedElements & acurv) : BaseFiniteElement2D(acurv) + { + nvertices = 3; + nedges = 3; + eledge = MeshTopology :: GetEdges (TRIG); + elface = MeshTopology :: GetFaces (TRIG); + }; + + virtual ~FETrig() + {}; + + virtual void SetReferencePoint (Point<2> axi); + + virtual void SetVertexSingularity (int v, int exponent); + + virtual void CalcVertexShapes(); + virtual void CalcEdgeShapes(); + virtual void CalcFaceShapes(); + + virtual void CalcFaceLaplaceShapes(); +}; + + + +// ---------------------------------------------------------------------------- +// FEQuad +// ---------------------------------------------------------------------------- + +class FEQuad : public BaseFiniteElement2D +{ + const ELEMENT_FACE * elface; + + virtual void CalcNFaceShapes () + { nfaceshapes = (faceorder-1)*(faceorder-1); }; + +public: + + FEQuad (const CurvedElements & acurv) : BaseFiniteElement2D(acurv) + { + nvertices = 4; + nedges = 4; + elface = MeshTopology :: GetFaces (QUAD); + }; + + virtual ~FEQuad() + {}; + + virtual void SetVertexSingularity (int /* v */, int /* exponent */) + {}; + + virtual void CalcVertexShapes(); + virtual void CalcEdgeShapes(); + virtual void CalcFaceShapes(); + + virtual void CalcFaceLaplaceShapes(); +}; + + + + +// ---------------------------------------------------------------------------- +// BaseFiniteElement3D +// ---------------------------------------------------------------------------- + +class BaseFiniteElement3D : public BaseFiniteElement<3> +{ +protected: + + int nvertices; + int nedges; + int nfaces; + + int vertexnr[8]; + int edgenr[12]; + int edgeorient[12]; + int edgeorder[12]; + int facenr[6]; + int faceorient[6]; + int faceorder[6]; + int surfacenr[6]; + // int surfaceorient[6]; + + int nfaceshapes[6]; + + int maxedgeorder; + int maxfaceorder; + + PolynomialBasis b1, b2; + + double vshape[8]; + Vec<3> vdshape[8]; + ArrayMem<double,120> eshape; + ArrayMem<Vec<3>,120> edshape; + ArrayMem<double,2000> fshape; + ArrayMem<Vec<3>,2000> fdshape; + + virtual void CalcNFaceShapes () = 0; + +public: + + int locmaxedgeorder; + int locmaxfaceorder; + + BaseFiniteElement3D (const CurvedElements & acurv) : BaseFiniteElement<3>(acurv) + { maxedgeorder = maxfaceorder = -1; }; + + void SetElementNumber (int aelnr); + + int GetVertexNr (int v) + { return vertexnr[v]; }; + + int GetEdgeNr (int e) + { return edgenr[e]; }; + + int GetFaceNr (int f) + { return facenr[f]; }; + + int GetNFaceShapes (int f) + { return nfaceshapes[f]; }; + + int GetEdgeOrder (int e) + { return edgeorder[e]; }; + + int GetFaceOrder (int f) + { return faceorder[f]; }; + + int GetNVertices () + { return nvertices; }; + + int GetNEdges () + { return nedges; }; + + int GetNFaces () + { return nfaces; }; + + int IsCurved () + { + bool iscurved = 0; + int e, f; + + for (e = 0; e < GetNEdges(); e++) + iscurved = iscurved || (GetEdgeOrder(e) > 1); + + for (f = 0; f < GetNFaces(); f++) + iscurved = iscurved || (GetFaceOrder(f) > 1); + + return iscurved; + } + + virtual void CalcVertexShapes() = 0; + virtual void CalcEdgeShapes() = 0; + virtual void CalcFaceShapes() = 0; + + double GetVertexShape (int v) + { return vshape[v]; }; + + double GetEdgeShape (int index) + { return eshape[index]; }; + + double GetFaceShape (int index) + { return fshape[index]; }; + + Vec<3> GetVertexDShape (int v) + { return vdshape[v]; }; + + Vec<3> GetEdgeDShape (int index) + { return edshape[index]; }; + + Vec<3> GetFaceDShape (int index) + { return fdshape[index]; }; +}; + + + +// ---------------------------------------------------------------------------- +// FETet +// ---------------------------------------------------------------------------- + +class FETet : public BaseFiniteElement3D +{ + Point<4> lambda; + Mat<4,3> dlambda; + + const ELEMENT_EDGE * eledge; + const ELEMENT_FACE * elface; + + virtual void CalcNFaceShapes () + { + for (int f = 0; f < nfaces; f++) + nfaceshapes[f] = ((faceorder[f]-1)*(faceorder[f]-2))/2; + }; + +public: + + FETet (const CurvedElements & acurv) : BaseFiniteElement3D(acurv) + { + nvertices = 4; + nedges = 6; + nfaces = 4; + eledge = MeshTopology :: GetEdges (TET); + elface = MeshTopology :: GetFaces (TET); + }; + + void SetReferencePoint (Point<3> axi); + + virtual void CalcVertexShapes(); + virtual void CalcEdgeShapes(); + virtual void CalcFaceShapes(); +}; + + + +// ---------------------------------------------------------------------------- +// FEPrism +// ---------------------------------------------------------------------------- + +class FEPrism : public BaseFiniteElement3D +{ + Point<4> lambda; // mixed barycentric coordinates + Mat<4,3> dlambda; + + const ELEMENT_EDGE * eledge; + const ELEMENT_FACE * elface; + + virtual void CalcNFaceShapes () + { + int f; + for (f = 0; f < 2; f++) + nfaceshapes[f] = ((faceorder[f]-1)*(faceorder[f]-2))/2; + for (f = 2; f < nfaces; f++) + nfaceshapes[f] = (faceorder[f]-1)*(faceorder[f]-1); + }; + +public: + + FEPrism (const CurvedElements & acurv) : BaseFiniteElement3D(acurv) + { + nvertices = 6; + nedges = 9; + nfaces = 5; + eledge = MeshTopology :: GetEdges (PRISM); + elface = MeshTopology :: GetFaces (PRISM); + }; + + void SetReferencePoint (Point<3> axi); + + virtual void CalcVertexShapes(); + virtual void CalcEdgeShapes(); + virtual void CalcFaceShapes(); +}; + + + + +// ---------------------------------------------------------------------------- +// FEPyramid +// ---------------------------------------------------------------------------- + +class FEPyramid : public BaseFiniteElement3D +{ + + const ELEMENT_EDGE * eledge; + const ELEMENT_FACE * elface; + + virtual void CalcNFaceShapes () + { + int f; + for (f = 0; f < 4; f++) + nfaceshapes[f] = ((faceorder[f]-1)*(faceorder[f]-2))/2; + for (f = 4; f < nfaces; f++) + nfaceshapes[f] = (faceorder[f]-1)*(faceorder[f]-1); + }; + +public: + + FEPyramid (const CurvedElements & acurv) : BaseFiniteElement3D(acurv) + { + nvertices = 5; + nedges = 8; + nfaces = 5; + eledge = MeshTopology :: GetEdges (PYRAMID); + elface = MeshTopology :: GetFaces (PYRAMID); + }; + + void SetReferencePoint (Point<3> axi); + + virtual void CalcVertexShapes(); + virtual void CalcEdgeShapes(); + virtual void CalcFaceShapes(); +}; + + + + +// ---------------------------------------------------------------------------- +// FEHex +// ---------------------------------------------------------------------------- + +class FEHex : public BaseFiniteElement3D +{ + + const ELEMENT_EDGE * eledge; + const ELEMENT_FACE * elface; + + virtual void CalcNFaceShapes () + { + int f; + for (f = 0; f < 6; f++) + nfaceshapes[f] = (faceorder[f]-1)*(faceorder[f]-1); + }; + +public: + + FEHex (const CurvedElements & acurv) : BaseFiniteElement3D(acurv) + { + nvertices = 8; + nedges = 12; + nfaces = 6; + eledge = MeshTopology :: GetEdges (HEX); + elface = MeshTopology :: GetFaces (HEX); + }; + + void SetReferencePoint (Point<3> axi); + + virtual void CalcVertexShapes(); + virtual void CalcEdgeShapes(); + virtual void CalcFaceShapes(); +}; + + + + +#endif diff --git a/contrib/Netgen/libsrc/meshing/curvedelems2.cpp b/contrib/Netgen/libsrc/meshing/curvedelems2.cpp new file mode 100644 index 0000000000..6b79ee5fe9 --- /dev/null +++ b/contrib/Netgen/libsrc/meshing/curvedelems2.cpp @@ -0,0 +1,752 @@ +#include <mystdlib.h> + +#include "meshing.hpp" + +namespace netgen +{ + + +// ---------------------------------------------------------------------------- +// CurvedElements +// ---------------------------------------------------------------------------- + + CurvedElements :: CurvedElements (const Mesh & amesh) + : mesh(amesh), top(mesh.GetTopology()) + { + isHighOrder = 0; + nvisualsubsecs = 2; + nIntegrationPoints = 10; + } + + + CurvedElements :: ~CurvedElements () + { + ; + } + + + void CurvedElements :: BuildCurvedElements(Refinement * ref, int polydeg) + { + if (mesh.coarsemesh) + { + mesh.coarsemesh->GetCurvedElements().BuildCurvedElements (ref, polydeg); + SetHighOrder(); + return; + } + + PrintMessage (2, "Build curved elements, order = ", polydeg); + + NgLock lock(const_cast<Mesh&>(mesh).Mutex(), 1); + isHighOrder = 0; + lock.UnLock(); + + const_cast<Mesh &>(mesh).UpdateTopology(); + + // set order of edges and faces + + BaseFiniteElement2D * fe2d; + + FEEdge edge (*this); + FESegm segm (*this); + FETrig trig (*this); + FEQuad quad (*this); + + int i, k, e, f; + + ARRAY<bool> edgedone; + + edgedone.SetSize (top.GetNEdges()); + + edgeorder.SetSize (top.GetNEdges()); + faceorder.SetSize (top.GetNFaces()); + + int nedgestocurve = mesh.GetNSeg(); + + edgedone = 0; + edgeorder = 1; + faceorder = 1; + + /* + for (e = 0; e < top.GetNEdges(); e++) + { + edgedone = 0; + edgeorder[e] = 1; + } + + for (f = 0; f < top.GetNFaces(); f++) + faceorder[f] = 1; + */ + + for (i = 1; i <= mesh.GetNSeg(); i++) + edgeorder[top.GetSegmentEdge(i)-1] = polydeg; + + + if (mesh.GetDimension() == 3) + { + for (i = 1; i <= mesh.GetNSE(); i++) + { + faceorder[top.GetSurfaceElementFace(i)-1] = polydeg; + + Element2d elem = mesh[(SurfaceElementIndex) (i-1)]; + + ARRAY<int> edgenrs; + top.GetSurfaceElementEdges(i, edgenrs); + + nedgestocurve += top.GetNEdges(elem.GetType()); + + for (int e = 0; e < top.GetNEdges(elem.GetType()); e++) + edgeorder[edgenrs[e]-1] = polydeg; + } + } + + if (polydeg == 1) + { + isHighOrder = 0; + return; + } + + PrintMessage (1, "Building curved elements, order = ", polydeg); + PushStatusF ("curving edges"); + + + + // set edgecoeffs and facecoeffs arrays index and size + + edgecoeffsindex.SetSize (top.GetNEdges()+1); + facecoeffsindex.SetSize (top.GetNFaces()+1); + + edgecoeffsindex[0] = 0; + for (e = 2; e <= top.GetNEdges()+1; e++) + edgecoeffsindex[e-1] = edgecoeffsindex[e-2] + edgeorder[e-2]-1; + + facecoeffsindex[0] = 0; + for (f = 2; f <= top.GetNFaces()+1; f++) + { + switch (top.GetFaceType (f-1)) + { + case TRIG: + facecoeffsindex[f-1] = facecoeffsindex[f-2] + + (faceorder[f-2]-1)*(faceorder[f-2]-2)/2; + break; + case QUAD: + facecoeffsindex[f-1] = facecoeffsindex[f-2] + + (faceorder[f-2]-1)*(faceorder[f-2]-1); + break; + } + } + + edgecoeffs.SetSize(edgecoeffsindex[top.GetNEdges()]); + facecoeffs.SetSize(facecoeffsindex[top.GetNFaces()]); + + + + // evaluate edge points + + PointGeomInfo newgi; // dummy variable, only needed for function call + EdgePointGeomInfo newepgi; // dummy variable, only needed for function call + Point3d xexact; // new point to be stored in ARRAY edgepts + + ARRAY<double> xi, wi; + ComputeGaussRule(nIntegrationPoints, xi, wi); + + for (i=0; i<edgecoeffsindex[top.GetNEdges()]; i++) + edgecoeffs[i] = Vec<3>(0.,0.,0.); + + + + + // all edges belonging to segments + + for (i=0; i<mesh.GetNSeg(); i++) + { + if (multithread.terminate) return; + + SetThreadPercent( double(100*i/nedgestocurve) ); + + int edgenr = top.GetSegmentEdge(i+1); + + if (edgedone[edgenr-1]) continue; + + edgedone[edgenr-1] = 1; + + Segment s = mesh.LineSegment(i+1); + + segm.SetElementNumber (i+1); + + for (k = 2; k <= segm.GetEdgeOrder(); k++) + edgecoeffs[edgecoeffsindex[edgenr-1]+k-2] = Vec<3>(0.,0.,0.); + + for (int l = 0; l < nIntegrationPoints; l++) + { + segm.SetReferencePoint (Point<1>(xi[l])); + segm.CalcVertexShapes (); + segm.CalcEdgeLaplaceShapes (); + + Point<3> xv(0,0,0); + + for (int v = 0; v < 2; v++) + xv = xv + segm.GetVertexShape(v) * mesh.Point(segm.GetVertexNr(v)); + + double secpoint = xi[l]; + + ref->PointBetween (mesh.Point(segm.GetVertexNr(1)), + mesh.Point(segm.GetVertexNr(0)), secpoint, + s.surfnr2, s.surfnr1, + s.epgeominfo[1], s.epgeominfo[0], + xexact, newepgi); + + for (int k = 2; k <= segm.GetEdgeOrder(); k++) + edgecoeffs[edgecoeffsindex[edgenr-1]+k-2] -= + wi[l] * segm.GetEdgeLaplaceShape(k-2) * Vec<3>(xexact - xv); + + } + + for (k = 2; k <= segm.GetEdgeOrder(); k++) + edgecoeffs[edgecoeffsindex[edgenr-1]+k-2] = + (2.0*(k-1.0)+1.0)*edgecoeffs[edgecoeffsindex[edgenr-1]+k-2]; + + } + + + + + + // all edges belonging to surface elements + + if (mesh.GetDimension() == 3) + { + int nedgescurved = mesh.GetNSeg(); + for (int i=0; i<mesh.GetNSE(); i++) + { + if (multithread.terminate) return; + + // SetThreadPercent( double(100*(mesh.GetNSeg()+i)/nedgestocurve) ); + Element2d elem = mesh[(SurfaceElementIndex) i]; + const ELEMENT_EDGE * eledges = MeshTopology::GetEdges(elem.GetType()); + + ARRAY<int> edgenrs; + ARRAY<int> orient; + top.GetSurfaceElementEdges(i+1, edgenrs); + top.GetSurfaceElementEdgeOrientations(i+1, orient); + + for (int e = 0; e < top.GetNEdges(elem.GetType()); e++) + { +// cout << "e = " << e << "/" << top.GetNEdges(elem.GetType()) << endl; + + nedgescurved++; + + if (edgedone[edgenrs[e]-1]) continue; + + edgedone[edgenrs[e]-1] = 1; + + SetThreadPercent( double(100*(nedgescurved)/nedgestocurve) ); + + edge.SetElementNumber (edgenrs[e]); + + for (k = 2; k <= edge.GetEdgeOrder(); k++) + edgecoeffs[edgecoeffsindex[edgenrs[e]-1]+k-2] = Vec<3>(0.,0.,0.); + + for (int l = 0; l < nIntegrationPoints; l++) + { +// cout << "." << flush; + edge.SetReferencePoint (Point<1>(xi[l])); + edge.CalcVertexShapes (); + edge.CalcEdgeLaplaceShapes (); + + Point<3> xv(0,0,0); + for (int v = 0; v < 2; v++) + xv = xv + edge.GetVertexShape(v) * mesh.Point(edge.GetVertexNr(v)); + + double secpoint = xi[l]; + + if (orient[e] == 1) + ref->PointBetween (mesh.Point(edge.GetVertexNr(1)), + mesh.Point(edge.GetVertexNr(0)), secpoint, + mesh.GetFaceDescriptor(elem.GetIndex()).SurfNr(), + elem.GeomInfoPi(eledges[e][1]), + elem.GeomInfoPi(eledges[e][0]), + xexact, newgi); + else + ref->PointBetween (mesh.Point(edge.GetVertexNr(1)), + mesh.Point(edge.GetVertexNr(0)), secpoint, + mesh.GetFaceDescriptor(elem.GetIndex()).SurfNr(), + elem.GeomInfoPi(eledges[e][0]), + elem.GeomInfoPi(eledges[e][1]), + xexact, newgi); + + for (k = 2; k <= edge.GetEdgeOrder(); k++) + edgecoeffs[edgecoeffsindex[edgenrs[e]-1]+k-2] -= + wi[l] * edge.GetEdgeLaplaceShape(k-2) * Vec<3>(xexact - xv); + } +// cout << endl; + for (k = 2; k <= edge.GetEdgeOrder(); k++) + edgecoeffs[edgecoeffsindex[edgenrs[e]-1]+k-2] = + (2.0*(k-1.0)+1.0)*edgecoeffs[edgecoeffsindex[edgenrs[e]-1]+k-2]; + + } + } + } + + + + +/* + + // L2-Projection for edges + + + cout << "WARNING: L2-Projection for edges" << endl; + + if (mesh.GetDimension() == 3) + { + for (int i=0; i<mesh.GetNSE(); i++) + { + Element2d elem = mesh[(SurfaceElementIndex) i]; + const ELEMENT_EDGE * eledges = MeshTopology::GetEdges(elem.GetType()); + + ARRAY<int> edgenrs; + ARRAY<int> orient; + top.GetSurfaceElementEdges(i+1, edgenrs); + top.GetSurfaceElementEdgeOrientations(i+1, orient); + + for (int e = 0; e < top.GetNEdges(elem.GetType()); e++) + { + edge.SetElementNumber (edgenrs[e]); + + int npoints = edge.GetEdgeOrder()-1; + + if (npoints == 0) continue; + + DenseMatrix mat(npoints); + DenseMatrix inv(npoints); + Vector vec[3]; + + for (int k = 0; k < 3; k++) + { + vec[k].SetSize(npoints); + for (int n = 1; n <= npoints; n++) vec[k].Set(n, 0.); + } + + for (int l = 0; l < nIntegrationPoints; l++) + { + double w = wi[l]; + + edge.SetReferencePoint (Point<1>(xi[l])); + edge.CalcVertexShapes (); + edge.CalcEdgeShapes (); + + for (int n = 0; n < npoints; n++) + for (int m = 0; m < npoints; m++) + mat.Set(n+1, m+1, mat.Get(n+1,m+1) + + edge.GetEdgeShape(n) * edge.GetEdgeShape(m) * w); + + Point<3> xv(0,0,0); + for (int v = 0; v < 2; v++) + xv = xv + edge.GetVertexShape(v) * mesh.Point(edge.GetVertexNr(v)); + + double secpoint = xi[l]; + + ref->PointBetween (mesh.Point(edge.GetVertexNr(1)), + mesh.Point(edge.GetVertexNr(0)), secpoint, + mesh.GetFaceDescriptor(elem.GetIndex()).SurfNr(), + elem.GeomInfoPi(eledges[e][1]), + elem.GeomInfoPi(eledges[e][0]), + xexact, newgi); + + for (int k = 2; k <= edge.GetEdgeOrder(); k++) + { + vec[0].Set(k-1, vec[0].Get(k-1) + Vec<3>(xexact - xv)(0)*edge.GetEdgeShape(k-2)*w ); + vec[1].Set(k-1, vec[1].Get(k-1) + Vec<3>(xexact - xv)(1)*edge.GetEdgeShape(k-2)*w ); + vec[2].Set(k-1, vec[2].Get(k-1) + Vec<3>(xexact - xv)(2)*edge.GetEdgeShape(k-2)*w ); + } + + } + + + CalcInverse(mat,inv); + + Vector a0, a1, a2; + + a0 = inv*vec[0]; + a1 = inv*vec[1]; + a2 = inv*vec[2]; + + int index = edgecoeffsindex[edge.GetEdgeNr()-1]; + + for (int n = 0; n < npoints; n++, index++) + edgecoeffs[index] = Vec<3>(a0(n+1), a1(n+1), a2(n+1)); + } + } + } + + + for (int i=0; i<mesh.GetNSeg(); i++) + { + int edgenr = top.GetSegmentEdge(i+1); + + Segment s = mesh.LineSegment(i+1); + + segm.SetElementNumber (i+1); + + int npoints = segm.GetEdgeOrder()-1; + + if (npoints == 0) continue; + + DenseMatrix mat(npoints); + DenseMatrix inv(npoints); + Vector vec[3]; + + for (int k = 0; k < 3; k++) + { + vec[k].SetSize(npoints); + for (int n = 1; n <= npoints; n++) vec[k].Set(n, 0.); + } + + for (int l = 0; l < nIntegrationPoints; l++) + { + double w = wi[l]; + + segm.SetReferencePoint (Point<1>(xi[l])); + segm.CalcVertexShapes (); + segm.CalcEdgeShapes (); + + for (int n = 0; n < npoints; n++) + for (int m = 0; m < npoints; m++) + mat.Set(n+1, m+1, mat.Get(n+1,m+1) + + segm.GetEdgeShape(n) * segm.GetEdgeShape(m) * w); + + Point<3> xv(0,0,0); + for (int v = 0; v < 2; v++) + xv = xv + segm.GetVertexShape(v) * mesh.Point(segm.GetVertexNr(v)); + + double secpoint = xi[l]; + + if (segm.GetEdgeOrientation() == -1) secpoint = 1. - secpoint; // reverse orientation + + ref->PointBetween (mesh.Point(segm.GetVertexNr(1)), + mesh.Point(segm.GetVertexNr(0)), secpoint, + s.surfnr2, s.surfnr1, + s.epgeominfo[1], s.epgeominfo[0], + xexact, newepgi); + + for (int k = 2; k <= segm.GetEdgeOrder(); k++) + { + vec[0].Set(k-1, vec[0].Get(k-1) + Vec<3>(xexact - xv)(0)*segm.GetEdgeShape(k-2)*w ); + vec[1].Set(k-1, vec[1].Get(k-1) + Vec<3>(xexact - xv)(1)*segm.GetEdgeShape(k-2)*w ); + vec[2].Set(k-1, vec[2].Get(k-1) + Vec<3>(xexact - xv)(2)*segm.GetEdgeShape(k-2)*w ); + } + + } + + + CalcInverse(mat,inv); + + Vector a0, a1, a2; + + a0 = inv*vec[0]; + a1 = inv*vec[1]; + a2 = inv*vec[2]; + + int index = edgecoeffsindex[segm.GetEdgeNr()-1]; + + for (int n = 0; n < npoints; n++, index++) + edgecoeffs[index] = Vec<3>(a0(n+1), a1(n+1), a2(n+1)); + + + + } + +*/ + + + + + + // evaluate face points + + if (mesh.GetDimension() == 3) + { + PopStatus (); + PushStatusF ("curving faces"); + + for (int j=0; j<facecoeffsindex[top.GetNFaces()]; j++) + facecoeffs[j] = Vec<3>(0.,0.,0.); + + for (SurfaceElementIndex i = 0; i < mesh.GetNSE(); i++) // for all surface elements + { + if (multithread.terminate) return; + + SetThreadPercent( double(100*i/mesh.GetNSE()) ); + + Element2d elem = mesh[i]; + + if (elem.GetType() == TRIG) + fe2d = &trig; + else + fe2d = &quad; + + fe2d->SetElementNumber (i+1); + + int npoints = fe2d->GetNFaceShapes(); + + if (npoints == 0) continue; + + DenseMatrix mat(npoints); + DenseMatrix inv(npoints); + Vector vec[3]; + + for (int k = 0; k < 3; k++) + { + vec[k].SetSize(npoints); + for (int n = 1; n <= npoints; n++) vec[k].Set(n, 0.); + } + + for (int j = 0; j < nIntegrationPoints; j++) + { + for (int k = 0; k < nIntegrationPoints; k++) + { + double w; + Point<2> xr; + + if (elem.GetType() == TRIG) + { + w = wi[j]*wi[k]*(1-xi[j]); + xr = Point<2> (xi[j], xi[k]*(1-xi[j])); + } + else + { + w = wi[j]*wi[k]; + xr = Point<2> (xi[j], xi[k]); + } + + fe2d->SetReferencePoint (xr); + fe2d->CalcFaceShapes (); + fe2d->CalcVertexShapes (); + fe2d->CalcEdgeShapes (); + fe2d->CalcFaceLaplaceShapes (); + + // integration over the product of the gradients of the face shapes + + for (int n = 0; n < npoints; n++) + for (int m = 0; m < npoints; m++) + mat.Set(n+1, m+1, + mat.Get(n+1,m+1) + + fe2d->GetFaceDShape(n)*fe2d->GetFaceDShape(m)*w); + + // integration over the difference between the exact geometry and the one + // defined by vertex and edge shape functions times face shape + + // double giu = 0, giv = 0; + PointGeomInfo gi; + gi.trignum = elem.GeomInfoPi(1).trignum; + gi.u = 0.0; + gi.v = 0.0; + Point<3> xve(0.,0.,0.); + + // vertex shape functions + for (int v = 0; v < fe2d->GetNVertices(); v++) + { + xve = xve + fe2d->GetVertexShape(v) * mesh.Point(fe2d->GetVertexNr(v)); + gi.u += fe2d->GetVertexShape(v) * elem.GeomInfoPi(v+1).u; + gi.v += fe2d->GetVertexShape(v) * elem.GeomInfoPi(v+1).v; + } + + // edge shape functions + int index = 0; + for (int e = 0; e < fe2d->GetNEdges(); e++) + { + int gindex = edgecoeffsindex[fe2d->GetEdgeNr(e)-1]; + for (int k = 2; k <= fe2d->GetEdgeOrder(e); k++, index++, gindex++) + xve = xve + fe2d->GetEdgeShape(index) * edgecoeffs[gindex]; + } + + // exact point + + Point<3> xexact = xve; + ref->ProjectToSurface (xexact, mesh.GetFaceDescriptor(elem.GetIndex()).SurfNr(), gi); + + Vec<3> v2 = w*(Vec<3>(xexact)-Vec<3>(xve)); + + for (int k = 0; k < 3; k++) + for (int n = 0; n < npoints; n++) + vec[k].Set(n+1, vec[k].Get(n+1) - fe2d->GetFaceLaplaceShape(n)*v2(k)); + } + } + + CalcInverse(mat,inv); + + Vector a0(npoints), a1(npoints), a2(npoints); + + /* + a0 = inv*vec[0]; + a1 = inv*vec[1]; + a2 = inv*vec[2]; + */ + inv.Mult (vec[0], a0); + inv.Mult (vec[1], a1); + inv.Mult (vec[2], a2); + + int index = facecoeffsindex[fe2d->GetFaceNr()-1]; + + for (int n = 0; n < npoints; n++, index++) + facecoeffs[index] = Vec<3>(a0.Elem(n+1), a1.Elem(n+1), a2.Elem(n+1)); + } + } + + + + +/* + cout << "WARNING: L2-Projection for faces" << endl; + + // evaluate face points + + if (mesh.GetDimension() == 3) + { + for (int i=0; i<facecoeffsindex[top.GetNFaces()]; i++) + facecoeffs[i] = Vec<3>(0.,0.,0.); + + for (SurfaceElementIndex i = 0; i < mesh.GetNSE(); i++) // for all surface elements + { + Element2d elem = mesh[i]; + + if (elem.GetType() == TRIG) + fe2d = &trig; + else + fe2d = &quad; + + fe2d->SetElementNumber (i+1); + + int npoints = fe2d->GetNFaceShapes(); + + if (npoints == 0) continue; + + DenseMatrix mat(npoints); + DenseMatrix inv(npoints); + Vector vec[3]; + + for (int k = 0; k < 3; k++) + { + vec[k].SetSize(npoints); + for (int n = 1; n <= npoints; n++) vec[k].Set(n, 0.); + } + + for (int j = 0; j < nIntegrationPoints; j++) + { + for (int k = 0; k < nIntegrationPoints; k++) + { + double w; + Point<2> xr; + + if (elem.GetType() == TRIG) + { + w = wi[j]*wi[k]*(1-xi[j]); + xr = Point<2> (xi[j], xi[k]*(1-xi[j])); + } + else + { + w = wi[j]*wi[k]; + xr = Point<2> (xi[j], xi[k]); + } + + fe2d->SetReferencePoint (xr); +// fe2d->CalcFaceDShape (false, true); + fe2d->CalcFaceShapes (); + + // integration over the product of the gradients of the face shapes + + for (int n = 0; n < npoints; n++) + for (int m = 0; m < npoints; m++) + mat.Set(n+1, m+1, mat.Get(n+1,m+1) + + fe2d->GetFaceShape(n)*fe2d->GetFaceShape(m)*w); + + // integration over the difference between the exact geometry and the one + // defined by vertex and edge shape functions times face shape + + Point<3> xve(0.,0.,0.); + + // vertex shape functions + fe2d->CalcVertexShapes (); +// fe2d->CalcVertexShape (true, false); + for (int v = 0; v < fe2d->GetNVertices(); v++) + xve = xve + fe2d->GetVertexShape(v) * mesh.Point(fe2d->GetVertexNr(v)); + + // edge shape functions +// fe2d->CalcEdgeShape (true, false); + fe2d->CalcEdgeShapes (); + + int index = 0; + for (int e = 0; e < fe2d->GetNEdges(); e++) + { + int gindex = edgecoeffsindex[fe2d->GetEdgeNr(e)-1]; + + for (int k = 2; k <= fe2d->GetEdgeOrder(e); k++, index++, gindex++) + xve = xve + fe2d->GetEdgeShape(index) * edgecoeffs[gindex]; + } + + // exact point + + Point<3> xexact = xve; + ref->ProjectToSurface (xexact, mesh.GetFaceDescriptor(elem.GetIndex()).SurfNr()); + + Vec<3> v = w*(Vec<3>(xexact)-Vec<3>(xve)); + + fe2d->CalcFaceLaplaceShapes (); + + for (int k = 0; k < 3; k++) + for (int n = 0; n < npoints; n++) + vec[k].Set(n+1, vec[k].Get(n+1) + fe2d->GetFaceShape(n)*v(k)); + } + } + + CalcInverse(mat,inv); + + Vector a0, a1, a2; + + a0 = inv*vec[0]; + a1 = inv*vec[1]; + a2 = inv*vec[2]; + + int index = facecoeffsindex[fe2d->GetFaceNr()-1]; + + for (int n = 0; n < npoints; n++, index++) + facecoeffs[index] = Vec<3>(a0(n+1), a1(n+1), a2(n+1)); + } + } +*/ + + + PrintMessage (5, "reducing order"); + + for (e = 0; e < top.GetNEdges(); e++) + if (edgeorder[e] > 1) + { + int i; + double maxcoeff = 0.; + + for (i = edgecoeffsindex[e]; i < edgecoeffsindex[e+1]; i++) + maxcoeff = max2 (maxcoeff, edgecoeffs[i].Length()); + + if (maxcoeff < 1e-12) edgeorder[e] = 1; + } + + for (f = 0; f < top.GetNFaces(); f++) + if (faceorder[f] > 1) + { + int i; + double maxcoeff = 0.; + + for (i = facecoeffsindex[f]; i < facecoeffsindex[f+1]; i++) + maxcoeff = max (maxcoeff, facecoeffs[i].Length()); + + if (maxcoeff < 1e-12) faceorder[f] = 1; + } + + isHighOrder = 1; // true + + PrintMessage(1, "done"); + PopStatus(); + // cout << "finished" << endl; + } + +} // namespace netgen diff --git a/contrib/Netgen/libsrc/meshing/delaunay.cpp b/contrib/Netgen/libsrc/meshing/delaunay.cpp new file mode 100644 index 0000000000..505a8c193f --- /dev/null +++ b/contrib/Netgen/libsrc/meshing/delaunay.cpp @@ -0,0 +1,1683 @@ +#include <mystdlib.h> +#include "meshing.hpp" + + + +namespace netgen +{ + + + static const int deltetfaces[][3] = + { { 1, 2, 3 }, + { 2, 0, 3 }, + { 0, 1, 3 }, + { 1, 0, 2 } }; + + + class DelaunayTet + { + PointIndex pnums[4]; + int nb[4]; + + public: + DelaunayTet () { ; } + + DelaunayTet (const DelaunayTet & el) + { + for (int i = 0; i < 4; i++) + pnums[i] = el[i]; + } + + DelaunayTet (const Element & el) + { + for (int i = 0; i < 4; i++) + pnums[i] = el[i]; + } + + PointIndex & operator[] (int i) { return pnums[i]; } + PointIndex operator[] (int i) const { return pnums[i]; } + + int & NB1(int i) { return nb[i-1]; } + int NB1(int i) const { return nb[i-1]; } + + int & NB(int i) { return nb[i]; } + int NB(int i) const { return nb[i]; } + + + int FaceNr (INDEX_3 & face) const // which face nr is it ? + { + for (int i = 0; i < 3; i++) + if (pnums[i] != face.I1() && + pnums[i] != face.I2() && + pnums[i] != face.I3()) + return i; + return 3; + } + + void GetFace1 (int i, INDEX_3 & face) const + { + face.I(1) = pnums[deltetfaces[i-1][0]]; + face.I(2) = pnums[deltetfaces[i-1][1]]; + face.I(3) = pnums[deltetfaces[i-1][2]]; + } + + void GetFace (int i, INDEX_3 & face) const + { + face.I(1) = pnums[deltetfaces[i][0]]; + face.I(2) = pnums[deltetfaces[i][1]]; + face.I(3) = pnums[deltetfaces[i][2]]; + } + + INDEX_3 GetFace1 (int i) const + { + return INDEX_3 (pnums[deltetfaces[i-1][0]], + pnums[deltetfaces[i-1][1]], + pnums[deltetfaces[i-1][2]]); + } + + INDEX_3 GetFace (int i) const + { + return INDEX_3 (pnums[deltetfaces[i][0]], + pnums[deltetfaces[i][1]], + pnums[deltetfaces[i][2]]); + } + + void GetFace1 (int i, Element2d & face) const + { + // face.SetType(TRIG); + face[0] = pnums[deltetfaces[i-1][0]]; + face[1] = pnums[deltetfaces[i-1][1]]; + face[2] = pnums[deltetfaces[i-1][2]]; + } + }; + + + + + + + + + + /* + Table to maintain neighbour elements + */ + class MeshNB + { + // face nodes -> one element + INDEX_3_CLOSED_HASHTABLE<int> faces; + + // + ARRAY<DelaunayTet> & tets; + + public: + + // estimated number of points + MeshNB (ARRAY<DelaunayTet> & atets, int np) + : faces(200), tets(atets) + { ; } + + // add element with 4 nodes + void Add (int elnr); + + // delete element with 4 nodes + void Delete (int elnr) + { + DelaunayTet & el = tets.Elem(elnr); + for (int i = 0; i < 4; i++) + faces.Set (el.GetFace(i).Sort(), el.NB(i)); + } + + // get neighbour of element elnr in direction fnr + int GetNB (int elnr, int fnr) + { + return tets.Get(elnr).NB1(fnr); + } + + // + void ResetFaceHT (int size) + { + faces.SetSize (size); + } + }; + + + + void MeshNB :: Add (int elnr) + { + DelaunayTet & el = tets.Elem(elnr); + + for (int i = 0; i < 4; i++) + { + INDEX_3 i3 = INDEX_3::Sort (el.GetFace(i)); + + int posnr; + + if (!faces.PositionCreate (i3, posnr)) + { + // face already in use + int othertet = faces.GetData (posnr); + + el.NB(i) = othertet; + if (othertet) + { + int fnr = tets.Get(othertet).FaceNr (i3); + tets.Elem(othertet).NB(fnr) = elnr; + } + } + else + { + faces.SetData (posnr, elnr); + el.NB(i) = 0; + } + } + } + + + + + + + /* + connected lists of cosphereical elements + */ + class SphereList + { + ARRAY<int> links; + public: + SphereList () + { ; } + + void AddElement (int elnr) + { + if (elnr > links.Size()) + links.Append (1); + links.Elem(elnr) = elnr; + } + + void DeleteElement (int elnr) + { + links.Elem(elnr) = 0; + } + + void ConnectElement (int eli, int toi) + { + links.Elem (eli) = links.Get (toi); + links.Elem (toi) = eli; + } + + void GetList (int eli, ARRAY<int> & linked) const; + }; + + + void SphereList :: GetList (int eli, ARRAY<int> & linked) const + { + linked.SetSize (0); + int pi = eli; + + do + { + if (pi <= 0 || pi > links.Size()) + { + cerr << "link, error " << endl; + cerr << "pi = " << pi << " linked.s = " << linked.Size() << endl; + exit(1); + } + if (linked.Size() > links.Size()) + { + cerr << "links have loop" << endl; + exit(1); + } + + linked.Append (pi); + pi = links.Get(pi); + } + while (pi != eli); + } + + + + + + void AddDelaunayPoint (PointIndex newpi, const Point3d & newp, + ARRAY<DelaunayTet> & tempels, + Mesh & mesh, + Box3dTree & tettree, + MeshNB & meshnb, + ARRAY<Point3d> & centers, ARRAY<double> & radi2, + ARRAY<int> & connected, ARRAY<int> & treesearch, + ARRAY<int> & freelist, SphereList & list, + IndexSet & insphere, IndexSet & closesphere) + { + int i, j, k, l; + + /* + find any sphere, such that newp is contained in + */ + + DelaunayTet el; + int cfelind = -1; + + const Point3d * pp[4]; + Point3d pc; + double r2; + Point3d tpmin, tpmax; + + tettree.GetIntersecting (newp, newp, treesearch); + for (j = 0; j < treesearch.Size(); j++) + { + int jjj = treesearch[j]; + if (Dist2 (centers.Get(jjj), newp) < radi2.Get(jjj)) + { + el = tempels.Get(jjj); + cfelind = jjj; + break; + } + } + + /* + if (!felind) + { + cerr << "not in any sphere, 1" << endl; + // old, non tree search + + double mindist = 1e10; + for (j = 1; j <= tempels.Size(); j++) + { + if (tempels.Get(j).PNum(1)) + { + double toofar = + Dist2 (centers.Get(j), newp) - radi2.Get(j); + if (toofar < mindist || toofar < 1e-7) + { + mindist = toofar; + cout << " dist2 = " << Dist2 (centers.Get(j), newp) + << " radi2 = " << radi2.Get(j) << endl; + } + if (toofar < 0) + { + el = tempels.Get(j); + felind = j; + cout << "sphere found !" << endl; + break; + } + } + } + cout << "point is too far from sheres: " << mindist << endl; + } + */ + + if (cfelind == -1) + { + PrintWarning ("Delaunay, point not in any sphere"); + return; + } + + + /* + insphere: point is in sphere -> delete element + closesphere: point is close to sphere -> considered for same center + */ + + // save overestimate + insphere.SetMaxIndex (2 * tempels.Size() + 5 * mesh.GetNP()); + closesphere.SetMaxIndex (2 * tempels.Size() + 5 * mesh.GetNP()); + + insphere.Clear(); + closesphere.Clear(); + + + insphere.Add (cfelind); + + int changed = 1; + int nstarti = 1, starti; + while (changed) + { + changed = 0; + starti = nstarti; + nstarti = insphere.Array().Size()+1; + + // if point in sphere, then it is also closesphere + for (j = starti; j < nstarti; j++) + { + int helind = insphere.Array().Get(j); + if (!closesphere.IsIn (helind)) + closesphere.Add (helind); + } + + // add connected spheres to insphere - list + for (j = starti; j < nstarti; j++) + { + list.GetList (insphere.Array().Get(j), connected); + for (k = 1; k <= connected.Size(); k++) + { + int celind = connected.Get(k); + + if (tempels.Get(celind)[0] != -1 && + !insphere.IsIn (celind)) + { + changed = 1; + insphere.Add (celind); + } + } + } + + // check neighbour-tets + for (j = starti; j < nstarti; j++) + for (k = 1; k <= 4; k++) + { + int helind = insphere.Array().Get(j); + int nbind = meshnb.GetNB (helind, k); + + if (nbind && !insphere.IsIn (nbind) ) + { + if (Dist2 (centers.Get(nbind), newp) + < radi2.Get(nbind) * (1+1e-8) ) + { + closesphere.Add (nbind); + } + + if (Dist2 (centers.Get(nbind), newp) + < radi2.Get(nbind) * (1 + 1e-12)) + { + // point is in sphere -> remove tet + insphere.Add (nbind); + changed = 1; + } + else + { + /* + Element2d face; + tempels.Get(helind).GetFace (k, face); + + const Point3d & p1 = mesh.Point (face.PNum(1)); + const Point3d & p2 = mesh.Point (face[1]); + const Point3d & p3 = mesh.Point (face[2]); + */ + + INDEX_3 i3 = tempels.Get(helind).GetFace (k-1); + + const Point3d & p1 = mesh.Point ( PointIndex (i3.I1())); + const Point3d & p2 = mesh.Point ( PointIndex (i3.I2())); + const Point3d & p3 = mesh.Point ( PointIndex (i3.I3())); + + + Vec3d v1(p1, p2); + Vec3d v2(p1, p3); + Vec3d n = Cross (v1, v2); + n /= n.Length(); + + if (n * Vec3d (p1, mesh.Point (tempels.Get(helind)[k-1])) > 0) + n *= -1; + + double dist = n * Vec3d (p1, newp); + + + if (dist > -1e-10) // 1e-10 + { + insphere.Add (nbind); + changed = 1; + } + + + } + } + } + } // while (changed) + + // (*testout) << "newels: " << endl; + ARRAY<Element> newels; + + Element2d face(TRIG); + for (j = 1; j <= insphere.Array().Size(); j++) + for (k = 1; k <= 4; k++) + { + // int elind = insphere.Array().Get(j); + int celind = insphere.Array().Get(j); + int nbind = meshnb.GetNB (celind, k); + + if (!nbind || !insphere.IsIn (nbind)) + { + tempels.Get (celind).GetFace1 (k, face); + + Element newel(TET); + for (l = 1; l <= 3; l++) + newel.PNum(l) = face.PNum(l); + newel[3] = newpi; + + newels.Append (newel); + + Vec3d v1(mesh.Point (face[0]), mesh.Point (face[1])); + Vec3d v2(mesh.Point (face[0]), mesh.Point (face[2])); + Vec3d n = Cross (v1, v2); + n /= n.Length(); + if (n * Vec3d(mesh.Point (face[0]), + mesh.Point (tempels.Get(insphere.Array().Get(j))[k-1])) + > 0) + n *= -1; + + double hval = n * Vec3d (mesh.Point (face[0]), newp); + + if (hval > -1e-12) + { + cerr << "vec to outer" << endl; + (*testout) << "vec to outer, hval = " << hval << endl; + (*testout) << "v1 x v2 = " << Cross (v1, v2) << endl; + (*testout) << "facep: " + << mesh.Point (face[0]) << " " + << mesh.Point (face[1]) << " " + << mesh.Point (face[2]) << endl; + } + } + } + + meshnb.ResetFaceHT (10*insphere.Array().Size()+1); + + for (j = 1; j <= insphere.Array().Size(); j++) + { + // int elind = + int celind = insphere.Array().Get(j); + + meshnb.Delete (celind); + list.DeleteElement (celind); + + for (k = 0; k < 4; k++) + tempels.Elem(celind)[k] = -1; + + ((ADTree6&)tettree.Tree()).DeleteElement (celind); + freelist.Append (celind); + } + + + int hasclose = 0; + for (j = 1; j <= closesphere.Array().Size(); j++) + { + int ind = closesphere.Array().Get(j); + if (!insphere.IsIn(ind) && + fabs (Dist2 (centers.Get (ind), newp) - radi2.Get(ind)) < 1e-8 ) + hasclose = 1; + } + + for (j = 1; j <= newels.Size(); j++) + { + int nelind; + + if (!freelist.Size()) + { + tempels.Append (newels.Get(j)); + nelind = tempels.Size(); + } + else + { + nelind = freelist.Last(); + freelist.DeleteLast(); + + tempels.Elem(nelind) = newels.Get(j); + } + + meshnb.Add (nelind); + list.AddElement (nelind); + + for (k = 1; k <= 4; k++) + pp[k-1] = &mesh.Point (newels.Get(j).PNum(k)); + + if (CalcSphereCenter (&pp[0], pc) ) + { + PrintSysError ("Delaunay: New tet is flat"); + + (*testout) << "new tet is flat" << endl; + for (k = 1; k <= 4; k++) + (*testout) << newels.Get(j).PNum(k) << " "; + (*testout) << endl; + for (k = 1; k <= 4; k++) + (*testout) << *pp[k-1] << " "; + (*testout) << endl; + } + + r2 = Dist2 (*pp[0], pc); + if (hasclose) + for (k = 1; k <= closesphere.Array().Size(); k++) + { + int csameind = closesphere.Array().Get(k); + if (!insphere.IsIn(csameind) && + fabs (r2 - radi2.Get(csameind)) < 1e-10 && + Dist (pc, centers.Get(csameind)) < 1e-10) + { + pc = centers.Get(csameind); + r2 = radi2.Get(csameind); + list.ConnectElement (nelind, csameind); + break; + } + } + + if (centers.Size() < nelind) + { + centers.Append (pc); + radi2.Append (r2); + } + else + { + centers.Elem(nelind) = pc; + radi2.Elem(nelind) = r2; + } + + closesphere.Add (nelind); + + tpmax = tpmin = *pp[0]; + for (k = 1; k <= 3; k++) + { + tpmin.SetToMin (*pp[k]); + tpmax.SetToMax (*pp[k]); + } + tpmax = tpmax + 0.01 * (tpmax - tpmin); + tettree.Insert (tpmin, tpmax, nelind); + } + } + + + + + + + void Delaunay1 (Mesh & mesh, const MeshingParameters & mp, AdFront3 * adfront, + ARRAY<DelaunayTet> & tempels, + int oldnp, DelaunayTet & startel, Point3d & pmin, Point3d & pmax) + { + int i, j, k, l; + const Point3d * pp[4]; + + ARRAY<Point3d> centers; + ARRAY<double> radi2; + + Point3d tpmin, tpmax; + + + // new: local box + mesh.GetBox (pmax, pmin); // lower bound for pmax, upper for pmin + for (i = 1; i <= adfront->GetNF(); i++) + { + const Element2d & face = adfront->GetFace(i); + for (j = 0; j < face.GetNP(); j++) + { + pmin.SetToMin (mesh.Point (face[j])); + pmax.SetToMax (mesh.Point (face[j])); + } + } + + for (i = 0; i < mesh.LockedPoints().Size(); i++) + { + pmin.SetToMin (mesh.Point (mesh.LockedPoints()[i])); + pmax.SetToMax (mesh.Point (mesh.LockedPoints()[i])); + } + + + + Vec3d vdiag(pmin, pmax); + // double r1 = vdiag.Length(); + double r1 = sqrt (3.0) * max3(vdiag.X(), vdiag.Y(), vdiag.Z()); + vdiag = Vec3d (r1, r1, r1); + double r2; + + Point3d pmin2 = pmin - 8 * vdiag; + Point3d pmax2 = pmax + 8 * vdiag; + + Point3d cp1(pmin2), cp2(pmax2), cp3(pmax2), cp4(pmax2); + cp2.X() = pmin2.X(); + cp3.Y() = pmin2.Y(); + cp4.Z() = pmin2.Z(); + + + + + int np = mesh.GetNP(); + + startel[0] = mesh.AddPoint (cp1); + startel[1] = mesh.AddPoint (cp2); + startel[2] = mesh.AddPoint (cp3); + startel[3] = mesh.AddPoint (cp4); + + // flag points to use for Delaunay: + BitArrayChar<PointIndex::BASE> usep(np); + usep.Clear(); + for (i = 1; i <= adfront->GetNF(); i++) + { + const Element2d & face = adfront->GetFace(i); + for (j = 0; j < face.GetNP(); j++) + usep.Set (face[j]); + } + + for (i = oldnp + PointIndex::BASE; + i < np + PointIndex::BASE; i++) + usep.Set (i); + + for (i = 0; i < mesh.LockedPoints().Size(); i++) + usep.Set (mesh.LockedPoints()[i]); + + + ARRAY<int> freelist; + + + int cntp = 0; + + MeshNB meshnb (tempels, mesh.GetNP() + 5); + SphereList list; + + pmin2 = pmin2 + 0.1 * (pmin2 - pmax2); + pmax2 = pmax2 + 0.1 * (pmax2 - pmin2); + + Box3dTree tettree(pmin2, pmax2); + + + tempels.Append (startel); + meshnb.Add (1); + list.AddElement (1); + ARRAY<int> connected, treesearch; + + + tpmin = tpmax = mesh.Point(startel[0]); + for (k = 1; k < 4; k++) + { + tpmin.SetToMin (mesh.Point (startel[k])); + tpmax.SetToMax (mesh.Point (startel[k])); + } + tpmax = tpmax + 0.01 * (tpmax - tpmin); + tettree.Insert (tpmin, tpmax, 1); + + + Point3d pc; + + for (k = 0; k < 4; k++) + pp[k] = &mesh.Point (startel[k]); + + CalcSphereCenter (&pp[0], pc); + + centers.Append (pc); + radi2.Append (Dist2 (*pp[0], pc)); + + + IndexSet insphere(mesh.GetNP()); + IndexSet closesphere(mesh.GetNP()); + + + +#ifdef MARK + MARK (delaunay1); +#endif + + + // "random" reordering of points (speeds a factor 3 - 5 !!!) + + ARRAY<int> mixed(np); + int prims[] = { 11, 13, 17, 19, 23, 29, 31, 37 }; + int prim; + + i = 0; + while (np % prims[i] == 0) i++; + prim = prims[i]; + + for (i = 1; i <= np; i++) + mixed.Elem(i) = (prim * i) % np + PointIndex::BASE; + + for (i = 1; i <= np; i++) + { + if (i % 100 == 0) + PrintDot ('+'); + + multithread.percent = 100.0 * i / np; + if (multithread.terminate) + break; + + PointIndex newpi = mixed.Get(i); + + if (!usep.Test(newpi)) + continue; + + cntp++; + + const Point3d & newp = mesh.Point(newpi); + + AddDelaunayPoint (newpi, newp, tempels, mesh, + tettree, meshnb, centers, radi2, + connected, treesearch, freelist, list, insphere, closesphere); + } + +#ifdef MARK + MARK (delaunay3); +#endif + + + + for (i = tempels.Size(); i >= 1; i--) + if (tempels.Get(i)[0] <= 0) + tempels.DeleteElement (i); + + PrintDot ('\n'); + + PrintMessage (3, "Points: ", cntp); + PrintMessage (3, "Elements: ", tempels.Size()); + // (*mycout) << cntp << " / " << tempels.Size() << " points/elements" << endl; + + /* + cout << "tempels: "; + tempels.PrintMemInfo(cout); + cout << "Searchtree: "; + tettree.Tree().PrintMemInfo(cout); + cout << "MeshNB: "; + meshnb.PrintMemInfo(cout); + */ + } + + + + + + + void Meshing3 :: Delaunay (Mesh & mesh, const MeshingParameters & mp) + { + PointIndex pi; + int i, j, k, l; + int ii; + int np, ne; + + PrintMessage (1, "Delaunay meshing"); + PrintMessage (3, "number of points: ", mesh.GetNP()); + PushStatus ("Delaunay meshing"); + + + + ARRAY<DelaunayTet> tempels; + + Point3d pmin, pmax; + Point3d tpmin, tpmax; + const Point3d * pp[4]; + + + DelaunayTet startel; + + int oldnp = mesh.GetNP(); + if (mp.blockfill) + { + BlockFillLocalH (mesh, mp); + PrintMessage (3, "number of points: ", mesh.GetNP()); + } + + np = mesh.GetNP(); + + Delaunay1 (mesh, mp, adfront, tempels, oldnp, startel, pmin, pmax); + + + { + // improve delaunay - mesh by swapping !!!! + + Mesh tempmesh; + for (pi = PointIndex::BASE; pi < mesh.GetNP()+PointIndex::BASE; pi++) + tempmesh.AddPoint (mesh[pi]); + + for (i = 1; i <= tempels.Size(); i++) + { + Element el(4); + for (j = 0; j < 4; j++) + el[j] = tempels.Elem(i)[j]; + + el.SetIndex (1); + + const Point3d & lp1 = mesh.Point (el[0]); + const Point3d & lp2 = mesh.Point (el[1]); + const Point3d & lp3 = mesh.Point (el[2]); + const Point3d & lp4 = mesh.Point (el[3]); + Vec3d v1(lp1, lp2); + Vec3d v2(lp1, lp3); + Vec3d v3(lp1, lp4); + Vec3d n = Cross (v1, v2); + double vol = n * v3; + + if (vol > 0) + swap (el[2], el[3]); + + tempmesh.AddVolumeElement (el); + } + + + MeshQuality3d (tempmesh); + + for (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 (i = 1; i <= 4; i++) + { + Element2d self(TRIG); + self.SetIndex (1); + startel.GetFace1 (i, self); + tempmesh.AddSurfaceElement (self); + } + + + tempmesh.AddFaceDescriptor (FaceDescriptor (1, 1, 0, 0)); + tempmesh.AddFaceDescriptor (FaceDescriptor (2, 1, 0, 0)); + + + // for (i = mesh.GetNP() - 3; i <= mesh.GetNP(); i++) + // tempmesh.AddLockedPoint (i); + for (pi = PointIndex::BASE; + pi < tempmesh.GetNP() + PointIndex::BASE; pi++) + tempmesh.AddLockedPoint (pi); + + // tempmesh.PrintMemInfo(cout); + // tempmesh.Save ("tempmesh.vol"); + + for (i = 1; i <= 2; i++) + { + tempmesh.FindOpenElements (); + + PrintMessage (5, "Num open: ", tempmesh.GetNOpenElements()); + tempmesh.CalcSurfacesOfNode (); + + tempmesh.FreeOpenElementsEnvironment (1); + + MeshOptimize3d meshopt; + meshopt.SwapImprove(tempmesh, OPT_CONFORM); + } + + +#ifdef STAT_STREAM + tempmesh.FindOpenElements (); + PrintMessage (5, "Num open: ", tempmesh.GetNOpenElements()); + (*statout) << tempmesh.GetNOpenElements() << " & " << endl; +#endif + + MeshQuality3d (tempmesh); + + tempels.SetSize(0); + for (i = 1; i <= tempmesh.GetNE(); i++) + tempels.Append (tempmesh.VolumeElement(i)); + } + + + + // remove degenerated + + BitArray badnode(mesh.GetNP()); + badnode.Clear(); + int ndeg = 0; + for (i = 1; i <= tempels.Size(); i++) + { + Element el(4); + for (j = 0; j < 4; j++) + el[j] = tempels.Elem(i)[j]; + // Element & el = tempels.Elem(i); + const Point3d & lp1 = mesh.Point (el[0]); + const Point3d & lp2 = mesh.Point (el[1]); + const Point3d & lp3 = mesh.Point (el[2]); + const Point3d & lp4 = mesh.Point (el[3]); + Vec3d v1(lp1, lp2); + Vec3d v2(lp1, lp3); + Vec3d v3(lp1, lp4); + Vec3d n = Cross (v1, v2); + double vol = n * v3; + + double h = v1.Length() + v2.Length() + v3.Length(); + if (fabs (vol) < 1e-8 * (h * h * h) && + (el[0] <= np && el[1] <= np && + el[2] <= np && el[3] <= np) ) // old: 1e-12 + { + badnode.Set(el[0]); + badnode.Set(el[1]); + badnode.Set(el[2]); + badnode.Set(el[3]); + ndeg++; + (*testout) << "vol = " << vol << " h = " << h << endl; + } + + if (vol > 0) + Swap (el[2], el[3]); + } + + ne = tempels.Size(); + for (i = ne; i >= 1; i--) + { + const DelaunayTet & el = tempels.Get(i); + if (badnode.Test(el[0]) || + badnode.Test(el[1]) || + badnode.Test(el[2]) || + badnode.Test(el[3]) ) + tempels.DeleteElement(i); + } + + + PrintMessage (3, ndeg, " degenerated elements removed"); + + // find surface triangles which are no face of any tet + + INDEX_3_HASHTABLE<int> openeltab(mesh.GetNOpenElements()+3); + ARRAY<int> openels; + for (i = 1; i <= mesh.GetNOpenElements(); i++) + { + const Element2d & tri = mesh.OpenElement(i); + INDEX_3 i3(tri[0], tri[1], tri[2]); + i3.Sort(); + openeltab.Set (i3, i); + } + + for (i = 1; i <= tempels.Size(); i++) + { + for (j = 0; j < 4; j++) + { + INDEX_3 i3 = tempels.Get(i).GetFace (j); + i3.Sort(); + if (openeltab.Used(i3)) + openeltab.Set (i3, 0); + } + } + + // and store them in openels + for (i = 1; i <= openeltab.GetNBags(); i++) + for (j = 1; j <= openeltab.GetBagSize(i); j++) + { + INDEX_3 i3; + int fnr; + openeltab.GetData (i, j, i3, fnr); + if (fnr) + openels.Append (fnr); + } + + + + + + // find open triangle with close edge (from halfening of surface squares) + + INDEX_2_HASHTABLE<INDEX_2> twotrias(mesh.GetNOpenElements()+5); + // for (i = 1; i <= mesh.GetNOpenElements(); i++) + for (ii = 1; ii <= openels.Size(); ii++) + { + i = openels.Get(ii); + const Element2d & el = mesh.OpenElement(i); + for (j = 1; j <= 3; j++) + { + INDEX_2 hi2 (el.PNumMod (j), el.PNumMod(j+1)); + hi2.Sort(); + if (twotrias.Used(hi2)) + { + INDEX_2 hi3; + hi3 = twotrias.Get (hi2); + hi3.I2() = el.PNumMod (j+2); + twotrias.Set (hi2, hi3); + } + else + { + INDEX_2 hi3(el.PNumMod (j+2), 0); + twotrias.Set (hi2, hi3); + } + } + } + + INDEX_2_HASHTABLE<int> tetedges(tempels.Size() + 5); + for (i = 1; i <= tempels.Size(); i++) + { + const DelaunayTet & el = tempels.Get(i); + INDEX_2 i2; + for (j = 1; j <= 6; j++) + { + switch (j) + { + case 1: i2 = INDEX_2(el[0], el[1]); break; + case 2: i2 = INDEX_2(el[0], el[2]); break; + case 3: i2 = INDEX_2(el[0], el[3]); break; + case 4: i2 = INDEX_2(el[1], el[2]); break; + case 5: i2 = INDEX_2(el[1], el[3]); break; + case 6: i2 = INDEX_2(el[2], el[3]); break; + } + i2.Sort(); + tetedges.Set (i2, 1); + } + } + // cout << "tetedges:"; + // tetedges.PrintMemInfo (cout); + + + for (INDEX_2_HASHTABLE<INDEX_2>::Iterator it = twotrias.Begin(); + it != twotrias.End(); it++) + { + INDEX_2 hi2, hi3; + twotrias.GetData (it, hi2, hi3); + hi3.Sort(); + if (tetedges.Used (hi3)) + { + const Point3d & p1 = mesh.Point ( PointIndex (hi2.I1())); + const Point3d & p2 = mesh.Point ( PointIndex (hi2.I2())); + const Point3d & p3 = mesh.Point ( PointIndex (hi3.I1())); + const Point3d & p4 = mesh.Point ( PointIndex (hi3.I2())); + Vec3d v1(p1, p2); + Vec3d v2(p1, p3); + Vec3d v3(p1, p4); + Vec3d n = Cross (v1, v2); + double vol = n * v3; + + double h = v1.Length() + v2.Length() + v3.Length(); + if (fabs (vol) < 1e-4 * (h * h * h)) // old: 1e-12 + { + badnode.Set(hi3.I1()); + badnode.Set(hi3.I2()); + } + } + } + + /* + for (i = 1; i <= twotrias.GetNBags(); i++) + for (j = 1; j <= twotrias.GetBagSize (i); j++) + { + INDEX_2 hi2, hi3; + twotrias.GetData (i, j, hi2, hi3); + hi3.Sort(); + if (tetedges.Used (hi3)) + { + const Point3d & p1 = mesh.Point (hi2.I1()); + const Point3d & p2 = mesh.Point (hi2.I2()); + const Point3d & p3 = mesh.Point (hi3.I1()); + const Point3d & p4 = mesh.Point (hi3.I2()); + Vec3d v1(p1, p2); + Vec3d v2(p1, p3); + Vec3d v3(p1, p4); + Vec3d n = Cross (v1, v2); + double vol = n * v3; + + double h = v1.Length() + v2.Length() + v3.Length(); + if (fabs (vol) < 1e-4 * (h * h * h)) // old: 1e-12 + { + badnode.Set(hi3.I1()); + badnode.Set(hi3.I2()); + } + } + } + */ + + ne = tempels.Size(); + for (i = ne; i >= 1; i--) + { + const DelaunayTet & el = tempels.Get(i); + if (badnode.Test(el[0]) || + badnode.Test(el[1]) || + badnode.Test(el[2]) || + badnode.Test(el[3]) ) + tempels.DeleteElement(i); + } + + + + + // find intersecting: + PrintMessage (3, "Remove intersecting"); + if (openels.Size()) + { + Box3dTree setree(pmin, pmax); + + /* + cout << "open elements in search tree: " << openels.Size() << endl; + cout << "pmin, pmax = " << pmin << " - " << pmax << endl; + */ + + for (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 (tpmin); + + for (k = 2; k <= 3; k++) + { + ltpmin.SetToMin (mesh.Point (tri.PNum(k))); + ltpmax.SetToMax (mesh.Point (tri.PNum(k))); + } + setree.Insert (ltpmin, ltpmax, fnr); + } + } + + ARRAY<int> neartrias; + for (i = 1; i <= tempels.Size(); i++) + { + // const Point3d *pp[4]; + int tetpi[4]; + DelaunayTet & el = tempels.Elem(i); + + int intersect = 0; + + for (j = 0; j < 4; j++) + { + pp[j] = &mesh.Point(el[j]); + tetpi[j] = el[j]; + } + + Point3d tetpmin(*pp[0]); + Point3d tetpmax(tetpmin); + for (j = 1; j < 4; j++) + { + tetpmin.SetToMin (*pp[j]); + tetpmax.SetToMax (*pp[j]); + } + tetpmin = tetpmin + 0.01 * (tetpmin - tetpmax); + tetpmax = tetpmax + 0.01 * (tetpmax - tetpmin); + + setree.GetIntersecting (tetpmin, tetpmax, neartrias); + + + // for (j = 1; j <= mesh.GetNSE(); j++) + // { + for (int jj = 1; jj <= neartrias.Size(); jj++) + { + j = neartrias.Get(jj); + + const Element2d & tri = mesh.OpenElement(j); + const Point3d *tripp[3]; + int tripi[3]; + + for (k = 1; k <= 3; k++) + { + tripp[k-1] = &mesh.Point (tri.PNum(k)); + tripi[k-1] = tri.PNum(k); + } + + if (IntersectTetTriangle (&pp[0], &tripp[0], tetpi, tripi)) + { + /* + int il1, il2; + (*testout) << "intersect !" << endl; + (*testout) << "triind: "; + for (il1 = 0; il1 < 3; il1++) + (*testout) << " " << tripi[il1]; + (*testout) << endl; + (*testout) << "tetind: "; + for (il2 = 0; il2 < 4; il2++) + (*testout) << " " << tetpi[il2]; + (*testout) << endl; + + (*testout) << "trip: "; + for (il1 = 0; il1 < 3; il1++) + (*testout) << " " << *tripp[il1]; + (*testout) << endl; + (*testout) << "tetp: "; + for (il2 = 0; il2 < 4; il2++) + (*testout) << " " << *pp[il2]; + (*testout) << endl; + */ + + + intersect = 1; + break; + } + } + + + if (intersect) + { + tempels.DeleteElement(i); + i--; + } + } + } + + +#ifdef MARK + MARK (delaunay4); +#endif + + + + + + + + + PrintMessage (3, "Remove outer"); + + // find connected tets (with no face between, and no hole due + // to removed intersecting tets. + // INDEX_3_HASHTABLE<INDEX_2> innerfaces(np); + + + INDEX_3_HASHTABLE<int> boundaryfaces(mesh.GetNOpenElements()/3+1); + for (i = 1; i <= mesh.GetNOpenElements(); i++) + { + const Element2d & tri = mesh.OpenElement(i); + INDEX_3 i3 (tri[0], tri[1], tri[2]); + i3.Sort(); + boundaryfaces.PrepareSet (i3); + } + boundaryfaces.AllocateElements(); + for (i = 1; i <= mesh.GetNOpenElements(); i++) + { + const Element2d & tri = mesh.OpenElement(i); + INDEX_3 i3 (tri[0], tri[1], tri[2]); + i3.Sort(); + boundaryfaces.Set (i3, 1); + } + + for (i = 0; i < tempels.Size(); i++) + for (j = 0; j < 4; j++) + tempels[i].NB(j) = 0; + + TABLE<int,PointIndex::BASE> elsonpoint(mesh.GetNP()); + for (i = 0; i < tempels.Size(); i++) + { + const DelaunayTet & el = tempels[i]; + INDEX_4 i4(el[0], el[1], el[2], el[3]); + i4.Sort(); + elsonpoint.IncSizePrepare (i4.I1()); + elsonpoint.IncSizePrepare (i4.I2()); + } + + elsonpoint.AllocateElementsOneBlock(); + + for (i = 0; i < tempels.Size(); i++) + { + const DelaunayTet & el = tempels[i]; + INDEX_4 i4(el[0], el[1], el[2], el[3]); + i4.Sort(); + elsonpoint.Add (i4.I1(), i+1); + elsonpoint.Add (i4.I2(), i+1); + } + + // cout << "elsonpoint mem: "; + // elsonpoint.PrintMemInfo(cout); + + INDEX_3_CLOSED_HASHTABLE<INDEX_2> faceht(100); + + Element2d hel(TRIG); + for (pi = PointIndex::BASE; + pi < mesh.GetNP()+PointIndex::BASE; pi++) + { + faceht.SetSize (4 * elsonpoint[pi].Size()); + for (ii = 0; ii < elsonpoint[pi].Size(); ii++) + { + i = elsonpoint[pi][ii]; + const DelaunayTet & el = tempels.Get(i); + + for (j = 1; j <= 4; j++) + { + el.GetFace1 (j, hel); + hel.Invert(); + hel.NormalizeNumbering(); + + if (hel[0] == pi) + { + INDEX_3 i3(hel[0], hel[1], hel[2]); + + if (!boundaryfaces.Used (i3)) + { + if (faceht.Used (i3)) + { + INDEX_2 i2 = faceht.Get(i3); + + tempels.Elem(i).NB1(j) = i2.I1(); + tempels.Elem(i2.I1()).NB1(i2.I2()) = i; + } + else + { + hel.Invert(); + hel.NormalizeNumbering(); + INDEX_3 i3(hel[0], hel[1], hel[2]); + INDEX_2 i2(i, j); + faceht.Set (i3, i2); + } + } + } + } + } + } + + /* + for (i = 1; i <= tempels.Size(); i++) + { + const DelaunayTet & el = tempels.Get(i); + for (j = 1; j <= 4; j++) + { + INDEX_3 i3; + Element2d face; + el.GetFace1 (j, face); + for (int kk = 1; kk <= 3; kk++) + i3.I(kk) = face.PNum(kk); + + i3.Sort(); + if (!boundaryfaces.Used (i3)) + { + if (innerfaces.Used(i3)) + { + INDEX_2 i2; + i2 = innerfaces.Get(i3); + i2.I2() = i; + innerfaces.Set (i3, i2); + } + else + { + INDEX_2 i2; + i2.I1() = i; + i2.I2() = 0; + innerfaces.Set (i3, i2); + } + } + } + } + */ + + /* + (*testout) << "nb elements:" << endl; + for (i = 1; i <= tempels.Size(); i++) + { + (*testout) << i << " "; + for (j = 1; j <= 4; j++) + (*testout) << tempels.Get(i).NB1(j) << " "; + (*testout) << endl; + } + + (*testout) << "pairs:" << endl; + for (i = 1; i <= innerfaces.GetNBags(); i++) + for (j = 1; j <= innerfaces.GetBagSize(i); j++) + { + INDEX_3 i3; + INDEX_2 i2; + innerfaces.GetData (i, j, i3, i2); + (*testout) << i2 << endl; + } + */ + + + + + + + + /* + cout << "innerfaces: "; + innerfaces.PrintMemInfo (cout); + */ + + // cout << "boundaryfaces: "; + // boundaryfaces.PrintMemInfo (cout); + + + PrintMessage (5, "tables filled"); + + + ne = tempels.Size(); + BitArray inner(ne), outer(ne); + inner.Clear(); + outer.Clear(); + ARRAY<int> elstack; + + /* + int starti = 0; + for (i = 1; i <= ne; i++) + { + const Element & el = tempels.Get(i); + for (j = 1; j <= 4; j++) + for (k = 1; k <= 4; k++) + if (el.PNum(j) == startel.PNum(k)) + { + outer.Set(i); + starti = i; + } + } + */ + + while (1) + { + int inside; + bool done = 1; + + for (i = 1; i <= ne; i++) + if (!inner.Test(i) && !outer.Test(i)) + { + done = 0; + break; + } + + if (done) break; + + const DelaunayTet & el = tempels.Get(i); + const Point3d & p1 = mesh.Point (el[0]); + const Point3d & p2 = mesh.Point (el[1]); + const Point3d & p3 = mesh.Point (el[2]); + const Point3d & p4 = mesh.Point (el[3]); + + Point3d ci = Center (p1, p2, p3, p4); + + inside = adfront->Inside (ci); + + /* + cout << "startel: " << i << endl; + cout << "inside = " << inside << endl; + cout << "ins2 = " << adfront->Inside (Center (ci, p1)) << endl; + cout << "ins3 = " << adfront->Inside (Center (ci, p2)) << endl; + */ + + elstack.SetSize(0); + elstack.Append (i); + + while (elstack.Size()) + { + int ei = elstack.Last(); + elstack.DeleteLast(); + + if (!inner.Test(ei) && !outer.Test(ei)) + { + if (inside) + inner.Set(ei); + else + outer.Set(ei); + + + for (j = 1; j <= 4; j++) + { + INDEX_3 i3 = tempels.Get(ei).GetFace1(j); + /* + Element2d face; + tempels.Get(ei).GetFace(j, face); + for (int kk = 1; kk <= 3; kk++) + i3.I(kk) = face.PNum(kk); + */ + i3.Sort(); + + + if (tempels.Get(ei).NB1(j)) + elstack.Append (tempels.Get(ei).NB1(j)); + + /* + if (innerfaces.Used(i3)) + { + INDEX_2 i2 = innerfaces.Get(i3); + int other = i2.I1() + i2.I2() - ei; + + if (other != tempels.Get(ei).NB1(j)) + cerr << "different1 !!" << endl; + + if (other) + { + elstack.Append (other); + } + } + else + if (tempels.Get(ei).NB1(j)) + cerr << "different2 !!" << endl; + */ + + } + } + } + } + + + + // check outer elements + if (debugparam.slowchecks) + { + for (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 (j = 1; j <= 4; j++) + { + Point3d hp; + switch (j) + { + case 1: hp = Center (ci, p1); break; + case 2: hp = Center (ci, p2); break; + case 3: hp = Center (ci, p3); break; + case 4: hp = Center (ci, p4); break; + } + // cout << "inside(" << hp << ") = " << adfront->Inside(hp) << endl; + } + + } + + if (adfront->Inside(ci)) + outer.Clear(i); + else + outer.Set(i); + } + } + + + /* + + // find bug in innerfaces + + tempmesh.DeleteVolumeElements(); + + for (i = 1; i <= innerfaces.GetNBags(); i++) + for (j = 1; j <= innerfaces.GetBagSize(i); j++) + { + INDEX_3 i3; + INDEX_2 i2; + innerfaces.GetData (i, j, i3, i2); + if (i2.I2()) + { + if (outer.Test(i2.I1()) != outer.Test(i2.I2())) + { + tempmesh.AddVolumeElement (tempels.Get(i2.I1())); + tempmesh.AddVolumeElement (tempels.Get(i2.I2())); + cerr << "outer flag different for connected els" << endl; + } + } + } + + + cout << "Check intersectiong once more" << endl; + + for (i = 1; i <= openels.Size(); i++) + { + tempmesh.SurfaceElement(2*openels.Get(i)).SetIndex(2); + tempmesh.SurfaceElement(2*openels.Get(i)-1).SetIndex(2); + } + + // for (i = 1; i <= tempmesh.GetNE(); i++) + // for (j = 1; j <= tempmesh.GetNSE(); j++) + i = 6; j = 403; + if (i <= tempmesh.GetNE() && j <= tempmesh.GetNSE()) + if (tempmesh.SurfaceElement(j).GetIndex()==2) + { + const Element & el = tempmesh.VolumeElement(i); + const Element2d & sel = tempmesh.SurfaceElement(j); + + const Point3d *tripp[3]; + const Point3d *pp[4]; + int tetpi[4], tripi[3]; + + for (k = 1; k <= 4; k++) + { + pp[k-1] = &tempmesh.Point(el.PNum(k)); + tetpi[k-1] = el.PNum(k); + } + + for (k = 1; k <= 3; k++) + { + tripp[k-1] = &tempmesh.Point (sel.PNum(k)); + tripi[k-1] = sel.PNum(k); + } + + (*testout) << "Check Triangle " << j << ":"; + for (k = 1; k <= 3; k++) + (*testout) << " " << sel.PNum(k); + for (k = 1; k <= 3; k++) + (*testout) << " " << tempmesh.Point(sel.PNum(k)); + (*testout) << endl; + + (*testout) << "Check Tet " << i << ":"; + for (k = 1; k <= 4; k++) + (*testout) << " " << el.PNum(k); + for (k = 1; k <= 4; k++) + (*testout) << " " << tempmesh.Point(el.PNum(k)); + (*testout) << endl; + + if (IntersectTetTriangle (&pp[0], &tripp[0], tetpi, tripi)) + { + cout << "Intesection detected !!" << endl; + } + } + + tempmesh.Save ("temp.vol"); + + // end bug search + */ + + + for (i = ne; i >= 1; i--) + { + if (outer.Test(i)) + tempels.DeleteElement(i); + } + + + // (*mycout) << "done" << endl; + + + // mesh.points.SetSize(mesh.points.Size()-4); + + for (i = 1; i <= tempels.Size(); i++) + { + Element el(4); + for (j = 0; j < 4; j++) + el[j] = tempels.Elem(i)[j]; + mesh.AddVolumeElement (el); + } + + PrintMessage (5, "outer removed"); + + mesh.FindOpenElements(); + + mesh.Compress(); + + PopStatus (); + } +} diff --git a/contrib/Netgen/libsrc/meshing/findip.cpp b/contrib/Netgen/libsrc/meshing/findip.cpp new file mode 100644 index 0000000000..7be0ee913d --- /dev/null +++ b/contrib/Netgen/libsrc/meshing/findip.cpp @@ -0,0 +1,115 @@ +// find inner point + +#include <mystdlib.h> +#include "meshing.hpp" + +namespace netgen +{ + + +template <typename POINTARRAY, typename FACEARRAY> +int FindInnerPoint (POINTARRAY & points, + FACEARRAY & faces, + Point3d & p) +{ + int i, j; + ARRAY<Vec3d> a; + ARRAY<double> c; + Point3d p1, pmin; + int i1, i2, i3, i4; + int nf; + DenseMatrix m(3), inv(3); + Vector rs(3), x(3); + double f, fmin, hd, hmax; + + nf = faces.Size(); + + // testout << "#faces = " << faces.Size() << endl; + // testout << "#points = " << points.Size() << endl; + + a.SetSize (nf); + c.SetSize (nf); + + for (i = 1; i <= nf; i++) + { + p1 = points.Get(faces.Get(i).PNum(1)); + a.Elem(i) = Cross (points.Get(faces.Get(i).PNum(2)) - points.Get(faces.Get(i).PNum(1)), + points.Get(faces.Get(i).PNum(3)) - points.Get(faces.Get(i).PNum(1))); + a.Elem(i) /= a.Get(i).Length(); + c.Elem(i) = - (a.Get(i).X() * p1.X() + a.Get(i).Y() * p1.Y() + a.Get(i).Z() * p1.Z()); + } + + + hmax = 0; + for (i = 1; i <= nf; i++) + { + const Element2d & el = faces.Get(i); + for (j = 1; j <= 3; j++) + { + double hi = Dist (points.Get(el.PNumMod(j)), + points.Get(el.PNumMod(j+1))); + if (hi > hmax) hmax = hi; + } + } + + + fmin = 100; + pmin = Point3d (0, 0, 0); + + for (i1 = 1; i1 <= nf; i1++) + for (i2 = i1+1; i2 <= nf; i2++) + for (i3 = i2+1; i3 <= nf; i3++) + for (i4 = i3+1; i4 <= nf; i4++) + { + m.Elem(1, 1) = a.Get(i1).X() - a.Get(i2).X(); + m.Elem(1, 2) = a.Get(i1).Y() - a.Get(i2).Y(); + m.Elem(1, 3) = a.Get(i1).Z() - a.Get(i2).Z(); + rs.Elem(1) = c.Get(i2) - c.Get(i1); + + m.Elem(2, 1) = a.Get(i1).X() - a.Get(i3).X(); + m.Elem(2, 2) = a.Get(i1).Y() - a.Get(i3).Y(); + m.Elem(2, 3) = a.Get(i1).Z() - a.Get(i3).Z(); + rs.Elem(2) = c.Get(i3) - c.Get(i1); + + m.Elem(3, 1) = a.Get(i1).X() - a.Get(i4).X(); + m.Elem(3, 2) = a.Get(i1).Y() - a.Get(i4).Y(); + m.Elem(3, 3) = a.Get(i1).Z() - a.Get(i4).Z(); + rs.Elem(3) = c.Get(i4) - c.Get(i1); + + + if (fabs (m.Det()) > 1e-10) + { + CalcInverse (m, inv); + inv.Mult (rs, x); + + // testout << "x = " << x << endl; + + + f = -1e10; + for (i = 1; i <= nf; i++) + { + hd = x.Elem(1) * a.Get(i).X() + + x.Elem(2) * a.Get(i).Y() + + x.Elem(3) * a.Get(i).Z() + + c.Get(i); + if (hd > f) f = hd; + } + + if (f < fmin) + { + fmin = f; + pmin.X() = x.Elem(1); + pmin.Y() = x.Elem(2); + pmin.Z() = x.Elem(3); + } + } + } + + // testout << "fmin = " << fmin << endl; + // testout << "pmin = " << pmin << endl; + + p = pmin; + return (fmin < -1e-3 * hmax) ? 1 : 0; + // return (fmin < 0) ? 1 : 0; +} +} diff --git a/contrib/Netgen/libsrc/meshing/findip.hpp b/contrib/Netgen/libsrc/meshing/findip.hpp new file mode 100644 index 0000000000..a0aed91b6c --- /dev/null +++ b/contrib/Netgen/libsrc/meshing/findip.hpp @@ -0,0 +1,108 @@ +// find inner point + +template <typename POINTARRAY, typename FACEARRAY> +inline int FindInnerPoint (POINTARRAY & points, + FACEARRAY & faces, + Point3d & p) +{ + int i, j; + ARRAY<Vec3d> a; + ARRAY<double> c; + Point3d p1, pmin; + int i1, i2, i3, i4; + int nf; + DenseMatrix m(3), inv(3); + Vector rs(3), x(3); + double f, fmin, hd, hmax; + + nf = faces.Size(); + + // testout << "#faces = " << faces.Size() << endl; + // testout << "#points = " << points.Size() << endl; + + a.SetSize (nf); + c.SetSize (nf); + + for (i = 1; i <= nf; i++) + { + p1 = points.Get(faces.Get(i).PNum(1)); + a.Elem(i) = Cross (points.Get(faces.Get(i).PNum(2)) - points.Get(faces.Get(i).PNum(1)), + points.Get(faces.Get(i).PNum(3)) - points.Get(faces.Get(i).PNum(1))); + a.Elem(i) /= a.Get(i).Length(); + c.Elem(i) = - (a.Get(i).X() * p1.X() + a.Get(i).Y() * p1.Y() + a.Get(i).Z() * p1.Z()); + } + + + hmax = 0; + for (i = 1; i <= nf; i++) + { + const Element2d & el = faces.Get(i); + for (j = 1; j <= 3; j++) + { + double hi = Dist (points.Get(el.PNumMod(j)), + points.Get(el.PNumMod(j+1))); + if (hi > hmax) hmax = hi; + } + } + + + fmin = 100; + pmin = Point3d (0, 0, 0); + + for (i1 = 1; i1 <= nf; i1++) + for (i2 = i1+1; i2 <= nf; i2++) + for (i3 = i2+1; i3 <= nf; i3++) + for (i4 = i3+1; i4 <= nf; i4++) + { + m.Elem(1, 1) = a.Get(i1).X() - a.Get(i2).X(); + m.Elem(1, 2) = a.Get(i1).Y() - a.Get(i2).Y(); + m.Elem(1, 3) = a.Get(i1).Z() - a.Get(i2).Z(); + rs.Elem(1) = c.Get(i2) - c.Get(i1); + + m.Elem(2, 1) = a.Get(i1).X() - a.Get(i3).X(); + m.Elem(2, 2) = a.Get(i1).Y() - a.Get(i3).Y(); + m.Elem(2, 3) = a.Get(i1).Z() - a.Get(i3).Z(); + rs.Elem(2) = c.Get(i3) - c.Get(i1); + + m.Elem(3, 1) = a.Get(i1).X() - a.Get(i4).X(); + m.Elem(3, 2) = a.Get(i1).Y() - a.Get(i4).Y(); + m.Elem(3, 3) = a.Get(i1).Z() - a.Get(i4).Z(); + rs.Elem(3) = c.Get(i4) - c.Get(i1); + + + if (fabs (m.Det()) > 1e-10) + { + CalcInverse (m, inv); + inv.Mult (rs, x); + + // testout << "x = " << x << endl; + + + f = -1e10; + for (i = 1; i <= nf; i++) + { + hd = x.Elem(1) * a.Get(i).X() + + x.Elem(2) * a.Get(i).Y() + + x.Elem(3) * a.Get(i).Z() + + c.Get(i); + if (hd > f) f = hd; + } + + if (f < fmin) + { + fmin = f; + pmin.X() = x.Elem(1); + pmin.Y() = x.Elem(2); + pmin.Z() = x.Elem(3); + } + } + } + + // testout << "fmin = " << fmin << endl; + // testout << "pmin = " << pmin << endl; + + p = pmin; + return (fmin < -1e-3 * hmax) ? 1 : 0; + // return (fmin < 0) ? 1 : 0; +} + diff --git a/contrib/Netgen/libsrc/meshing/geomsearch.cpp b/contrib/Netgen/libsrc/meshing/geomsearch.cpp new file mode 100644 index 0000000000..1c37637816 --- /dev/null +++ b/contrib/Netgen/libsrc/meshing/geomsearch.cpp @@ -0,0 +1,263 @@ +#include <mystdlib.h> +#include "meshing.hpp" + + +namespace netgen +{ + GeomSearch3d :: GeomSearch3d() + { + size.i1 = 0; size.i2 = 0; size.i3 = 0; + } + + GeomSearch3d :: ~GeomSearch3d() + { + //delete old Hashtable: + if (size.i1 != 0) + { + for (int i = 0; i < size.i1*size.i2*size.i3; i++) + delete hashtable[i]; + } + } + + void GeomSearch3d :: Init (ARRAY <FrontPoint3,PointIndex::BASE> *pointsi, ARRAY <FrontFace> *facesi) + { + points = pointsi; + faces = facesi; + size.i1 = 0; size.i2 = 0; size.i3 = 0; + reset = 1; + hashcount = 1; + } + + void GeomSearch3d :: ElemMaxExt(Point3d& minp, Point3d& maxp, const Element2d& elem) + { + maxp.X()=(*points)[elem.PNum(1)].P().X(); + maxp.Y()=(*points)[elem.PNum(1)].P().Y(); + maxp.Z()=(*points)[elem.PNum(1)].P().Z(); + minp.X()=(*points)[elem.PNum(1)].P().X(); + minp.Y()=(*points)[elem.PNum(1)].P().Y(); + minp.Z()=(*points)[elem.PNum(1)].P().Z(); + + for (int i=2; i <= 3; i++) + { + maxp.X()=max2((*points)[elem.PNum(i)].P().X(),maxp.X()); + maxp.Y()=max2((*points)[elem.PNum(i)].P().Y(),maxp.Y()); + maxp.Z()=max2((*points)[elem.PNum(i)].P().Z(),maxp.Z()); + minp.X()=min2((*points)[elem.PNum(i)].P().X(),minp.X()); + minp.Y()=min2((*points)[elem.PNum(i)].P().Y(),minp.Y()); + minp.Z()=min2((*points)[elem.PNum(i)].P().Z(),minp.Z()); + } + } + + void GeomSearch3d :: MinCoords(const Point3d& p1, Point3d& p2) + { + p2.X()=min2(p1.X(),p2.X()); + p2.Y()=min2(p1.Y(),p2.Y()); + p2.Z()=min2(p1.Z(),p2.Z()); + } + + void GeomSearch3d :: MaxCoords(const Point3d& p1, Point3d& p2) + { + p2.X()=max2(p1.X(),p2.X()); + p2.Y()=max2(p1.Y(),p2.Y()); + p2.Z()=max2(p1.Z(),p2.Z()); + } + + void GeomSearch3d :: Create() + { + INDEX i,j,k; + if (reset) + { + const double hashelemsizefactor = 4; + reset = 0; + /* + minext=Point3d(MAXDOUBLE, MAXDOUBLE, MAXDOUBLE); + maxext=Point3d(MINDOUBLE, MINDOUBLE, MINDOUBLE); + */ + ElemMaxExt(minext, maxext, faces->Get(1).Face()); + Point3d maxp, minp; + Vec3d midext(0,0,0); + + //get max Extension of Frontfaces + for (i = 1; i <= faces->Size(); i++) + { + ElemMaxExt(minp, maxp, faces->Get(i).Face()); + MinCoords(minp, minext); + MaxCoords(maxp, maxext); + midext+=maxp-minp; + } + + + maxextreal = maxext; + maxext = maxext + 1e-4 * (maxext - minext); + + midext*=1./faces->Size(); + Vec3d boxext = maxext - minext; + + //delete old Hashtable: + if (size.i1 != 0) + { + for (i = 1; i <= size.i1*size.i2*size.i3; i++) + { + delete hashtable.Get(i); + } + } + + size.i1 = int (boxext.X()/midext.X()/hashelemsizefactor+1); + size.i2 = int (boxext.Y()/midext.Y()/hashelemsizefactor+1); + size.i3 = int (boxext.Z()/midext.Z()/hashelemsizefactor+1); + PrintMessage (5, "hashsizes = ", size.i1, ", ", size.i2, ", ", size.i3); + + elemsize.X()=boxext.X()/size.i1; + elemsize.Y()=boxext.Y()/size.i2; + elemsize.Z()=boxext.Z()/size.i3; + + //create Hasharrays: + hashtable.SetSize(size.i1*size.i2*size.i3); + for (i = 1; i <= size.i1; i++) + { + for (j = 1; j <= size.i2; j++) + { + for (k = 1; k <= size.i3; k++) + { + INDEX ind=i+(j-1)*size.i1+(k-1)*size.i2*size.i1; + hashtable.Elem(ind) = new ARRAY <int> (); + } + } + } + } + else + { + //Clear all Hash-Arrays + for (i = 1; i <= size.i1; i++) + { + for (j = 1; j <= size.i2; j++) + { + for (k = 1; k <= size.i3; k++) + { + INDEX ind=i+(j-1)*size.i1+(k-1)*size.i2*size.i1; + hashtable.Elem(ind)->SetSize(0); + } + } + } + } + + //Faces in Hashtable einfuegen: + for (i = 1; i <= faces->Size(); i++) + { + AddElem(faces->Get(i).Face(),i); + } + + } + + void GeomSearch3d :: AddElem(const Element2d& elem, INDEX elemnum) + { + Point3d minp, maxp; + ElemMaxExt(minp, maxp, elem); + int sx = int ((minp.X()-minext.X())/elemsize.X()+1.); + int ex = int ((maxp.X()-minext.X())/elemsize.X()+1.); + int sy = int ((minp.Y()-minext.Y())/elemsize.Y()+1.); + int ey = int ((maxp.Y()-minext.Y())/elemsize.Y()+1.); + int sz = int ((minp.Z()-minext.Z())/elemsize.Z()+1.); + int ez = int ((maxp.Z()-minext.Z())/elemsize.Z()+1.); + int ix,iy,iz; + + for (ix = sx; ix <= ex; ix++) + { + for (iy = sy; iy <= ey; iy++) + { + for (iz = sz; iz <= ez; iz++) + { + INDEX ind=ix+(iy-1)*size.i1+(iz-1)*size.i2*size.i1; + if (ind < 1 || ind > size.i1 * size.i2 * size.i3) + { + cerr << "Illegal hash-position"; + cerr << "Position: " << ix << "," << iy << "," << iz << endl; + } + hashtable.Elem(ind)->Append(elemnum); + } + } + } + } + + void GeomSearch3d :: GetLocals(ARRAY<Element2d> & locfaces, ARRAY<INDEX> & findex, + INDEX fstind, const Point3d& p0, double xh) + { + hashcount++; + + Point3d minp, maxp, midp; + + minp=p0-Vec3d(xh,xh,xh); //lay cube over sphere + maxp=p0+Vec3d(xh,xh,xh); + + MaxCoords(minext,minp); //cube may not be out of hash-region + MinCoords(maxextreal,maxp); + + + int cluster = faces->Get(fstind).Cluster(); + + int sx = int((minp.X()-minext.X())/elemsize.X()+1.); + int ex = int((maxp.X()-minext.X())/elemsize.X()+1.); + int sy = int((minp.Y()-minext.Y())/elemsize.Y()+1.); + int ey = int((maxp.Y()-minext.Y())/elemsize.Y()+1.); + int sz = int((minp.Z()-minext.Z())/elemsize.Z()+1.); + int ez = int((maxp.Z()-minext.Z())/elemsize.Z()+1.); + int ix,iy,iz,i,k; + + int cnt1 = 0; // test, how efficient hashtable is + int cnt2 = 0; + int cnt3 = 0; + + for (ix = sx; ix <= ex; ix++) + { + for (iy = sy; iy <= ey; iy++) + { + for (iz = sz; iz <= ez; iz++) + { + INDEX ind=ix+(iy-1)*size.i1+(iz-1)*size.i2*size.i1; + + //go through all elements in one hash area + const ARRAY <int> & area = *hashtable.Elem(ind); + for (k = 1; k <= area.Size(); k++) + { + cnt2++; + i = area.Get(k); + if (faces->Get(i).Cluster() == cluster && + faces->Get(i).Valid() && + faces->Get(i).HashValue() != hashcount && + i != fstind) + { + cnt1++; + const Element2d & face = faces->Get(i).Face(); + + const Point3d & p1 = (*points)[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) + { + cnt3++; + locfaces.Append(faces->Get(i).Face()); + findex.Append(i); + faces->Elem(i).SetHashValue(hashcount); + } + } + } + } + } + } + /* + if (faces->Size() != 0 && hashcount % 200 == 0) + { + (*mycout) << "n.o.f= " << faces->Size(); + (*mycout) << ", n.o.lf= " << locfaces.Size(); + (*mycout) << ", hashf= " << (double)cnt2/(double)faces->Size(); + (*mycout) << " (" << (double)cnt1/(double)faces->Size(); + (*mycout) << ", " << (double)cnt3/(double)faces->Size() << ")" << endl; + } + */ + + } + +} diff --git a/contrib/Netgen/libsrc/meshing/geomsearch.hpp b/contrib/Netgen/libsrc/meshing/geomsearch.hpp new file mode 100644 index 0000000000..5364c24f8d --- /dev/null +++ b/contrib/Netgen/libsrc/meshing/geomsearch.hpp @@ -0,0 +1,116 @@ +#ifndef FILE_GEOMSEARCH +#define FILE_GEOMSEARCH + +/**************************************************************************/ +/* File: geomsearch.hh */ +/* Author: Johannes Gerstmayr */ +/* Date: 19. Nov. 97 */ +/**************************************************************************/ + +class FrontPoint3; +class FrontFace; + + /// class for quick access of 3D-elements; class cannot delete elements, but only append +class GeomSearch3d +{ + +public: + /// + GeomSearch3d(); + /// + virtual ~GeomSearch3d(); + + /// + void Init (ARRAY <FrontPoint3,PointIndex::BASE> *pointsi, ARRAY <FrontFace> *facesi); + + ///get elements max extension + void ElemMaxExt(Point3d& minp, Point3d& maxp, const Element2d& elem); + + ///get minimum coordinates of two points ->p2 + void MinCoords(const Point3d& p1, Point3d& p2); + + ///get minimum coordinates of two points ->p2 + void MaxCoords(const Point3d& p1, Point3d& p2); + + ///create a hashtable from an existing array of triangles + ///sizei = number of pieces in one direction + void Create(); + + ///add new element to Hashtable + void AddElem(const Element2d& elem, INDEX elemnum); + + ///GetLocal faces in sphere with radius xh and middlepoint p + void GetLocals(ARRAY<Element2d> & locfaces, ARRAY<INDEX> & findex, + INDEX fstind, const Point3d& p0, double xh); + +private: + + ARRAY <FrontFace> *faces; // Pointers to Arrays in Adfront + ARRAY <FrontPoint3,PointIndex::BASE> *points; + + ARRAY <ARRAY <int>*> hashtable; + + Point3d minext; //extension of Hashdomain + Point3d maxext; + Point3d maxextreal; + Vec3d elemsize; //size of one Hash-Element + + threeint size; // size of Hashtable in each direction + int reset; + int hashcount; +}; + +#endif + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/contrib/Netgen/libsrc/meshing/global.cpp b/contrib/Netgen/libsrc/meshing/global.cpp new file mode 100644 index 0000000000..60a1fbe51d --- /dev/null +++ b/contrib/Netgen/libsrc/meshing/global.cpp @@ -0,0 +1,53 @@ +#include <mystdlib.h> +#include "meshing.hpp" + +namespace netgen +{ + ostream * testout = &cout; + + ostream * mycout = &cout; + ostream * myerr = &cerr; + + + // Flags globflags; // not used anymoure + Flags parameters; + + + int silentflag = 0; + int testmode = 0; + + MeshingParameters mparam; + volatile multithreadt multithread; + + string ngdir = "."; + + ARRAY<int> tets_in_qualclass; + + + multithreadt :: multithreadt() + { + pause =0; + testmode = 0; + redraw = 0; + drawing = 0; + terminate = 0; + running = 0; + percent = 0; + task = ""; + } + + DebugParameters debugparam; + bool verbose = 0; + + int timestamp = 0; + int GetTimeStamp() + { + return timestamp; + } + + int NextTimeStamp() + { + timestamp++; + return timestamp; + } +} diff --git a/contrib/Netgen/libsrc/meshing/global.hpp b/contrib/Netgen/libsrc/meshing/global.hpp new file mode 100644 index 0000000000..843231d0c5 --- /dev/null +++ b/contrib/Netgen/libsrc/meshing/global.hpp @@ -0,0 +1,54 @@ +#ifndef FILE_GLOBAL +#define FILE_GLOBAL + + +/**************************************************************************/ +/* File: global.hh */ +/* Author: Joachim Schoeberl */ +/* Date: 01. Okt. 95 */ +/**************************************************************************/ + +/* + global functions and variables +*/ + +/// +extern double GetTime (); +extern void ResetTime (); + +/// +extern int testmode; + +// extern ostream * testout; +// extern AutoPtr<ostream> testout; + +/// calling parameters +extern Flags parameters; + +extern MeshingParameters mparam; + +extern ARRAY<int> tets_in_qualclass; + + +class multithreadt +{ +public: + int pause; + int testmode; + int redraw; + int drawing; + int terminate; + int running; + double percent; + char * task; + bool demorunning; + multithreadt(); +}; + +extern volatile multithreadt multithread; + +extern string ngdir; +extern DebugParameters debugparam; +extern bool verbose; + +#endif diff --git a/contrib/Netgen/libsrc/meshing/hpref_prism.hpp b/contrib/Netgen/libsrc/meshing/hpref_prism.hpp new file mode 100644 index 0000000000..ffbf2d2873 --- /dev/null +++ b/contrib/Netgen/libsrc/meshing/hpref_prism.hpp @@ -0,0 +1,300 @@ + + + + + + // 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, + HP_PRISM, + 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, 7 }, + { 2, 5, 8 }, + { 3, 6, 9 }, + { 0, 0, 0 } + }; + HPREF_ELEMENT_TYPE refprism_1fa_0e_0v_newelstypes[] = + { + HP_PRISM_1FA_0E_0V, + HP_PRISM, + HP_NONE, + }; + int refprism_1fa_0e_0v_newels[][8] = + { + { 1, 2, 3, 7, 8, 9 }, + { 7, 8, 9, 4, 5, 6 } + }; + 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_1FB_0E_0V ... quad face 1-2-4-5 + int refprism_1fb_0e_0v_splitedges[][3] = + { + { 1, 3, 7 }, + { 2, 3, 8 }, + { 4, 6, 9 }, + { 5, 6, 10 }, + { 0, 0, 0 } + }; + HPREF_ELEMENT_TYPE refprism_1fb_0e_0v_newelstypes[] = + { + HP_HEX_1F_0E_0V, + HP_PRISM, + HP_NONE, + }; + int refprism_1fb_0e_0v_newels[][8] = + { + { 1, 4, 5, 2, 7, 9, 10, 8 }, + { 7, 8, 3, 9, 10, 6 } + }; + HPRef_Struct refprism_1fb_0e_0v = + { + HP_PRISM, + refprism_1fb_0e_0v_splitedges, + 0, 0, + refprism_1fb_0e_0v_newelstypes, + refprism_1fb_0e_0v_newels + }; + + + + + + +// HP_PRISM_1FB_1EA_0V ... quad face 1-2-4-5 + int refprism_1fb_1ea_0v_splitedges[][3] = + { + { 1, 3, 7 }, + { 2, 3, 8 }, + { 4, 6, 9 }, + { 5, 6, 10 }, + { 1, 2, 11 }, + { 4, 5, 12 }, + { 0, 0, 0 } + }; + HPREF_ELEMENT_TYPE refprism_1fb_1ea_0v_newelstypes[] = + { + HP_HEX_1F_0E_0V, + HP_PRISM_1FB_1EA_0V, + HP_PRISM, + HP_NONE, + }; + int refprism_1fb_1ea_0v_newels[][8] = + { + { 11, 12, 5, 2, 7, 9, 10, 8 }, + { 1, 11, 7, 4, 12, 9 }, + { 7, 8, 3, 9, 10, 6 } + }; + HPRef_Struct refprism_1fb_1ea_0v = + { + HP_PRISM, + refprism_1fb_1ea_0v_splitedges, + 0, 0, + refprism_1fb_1ea_0v_newelstypes, + refprism_1fb_1ea_0v_newels + }; + + + + + diff --git a/contrib/Netgen/libsrc/meshing/hpref_quad.hpp b/contrib/Netgen/libsrc/meshing/hpref_quad.hpp new file mode 100644 index 0000000000..8802d4539e --- /dev/null +++ b/contrib/Netgen/libsrc/meshing/hpref_quad.hpp @@ -0,0 +1,2129 @@ + + + + +// 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 }, +}; +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 }, +}; +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, + 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 }, + { 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_TRIG_SINGEDGECORNER1, + HP_QUAD_SINGEDGE, + HP_QUAD_SINGEDGE, + HP_QUAD, + HP_NONE, +}; +int refquad_2e_1vc_newels[][8] = +{ + { 1, 5, 10 }, + { 6, 1, 10 }, + { 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 +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_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 }, + { 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_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 }, + { 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 +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_SINGEDGE, + HP_QUAD_SINGEDGE, + HP_TRIG, + HP_QUAD, + HP_TRIG_SINGCORNER, + HP_TRIG_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 +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_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 }, + { 5, 12, 7, 9 }, + { 13, 6, 9, 8 }, + { 7, 8, 9 }, + { 8, 7, 10, 11 }, + { 3, 11, 10 }, + { 12, 2, 7 }, + { 4, 13, 8 } +}; +HPRef_Struct refquad_2e_3v = +{ + HP_QUAD, + refquad_2e_3v_splitedges, + refquad_2e_3v_splitfaces, + 0, + refquad_2e_3v_newelstypes, + refquad_2e_3v_newels +}; + + + + + + + + + + +// HP_QUAD_2EB_0V +int refquad_2eb_0v_splitedges[][3] = +{ + { 1, 4, 5 }, + { 2, 3, 6 }, + { 3, 2, 7 }, + { 4, 1, 8 }, + { 0, 0, 0 } +}; +int refquad_2eb_0v_splitfaces[][4] = +{ + { 0, 0, 0, 0 }, +}; +HPREF_ELEMENT_TYPE refquad_2eb_0v_newelstypes[] = +{ + HP_QUAD_SINGEDGE, + HP_QUAD_SINGEDGE, + HP_QUAD, + HP_NONE, +}; +int refquad_2eb_0v_newels[][8] = +{ + { 1, 2, 6, 5 }, + { 3, 4, 8, 7 }, + { 5, 6, 7, 8 } +}; +HPRef_Struct refquad_2eb_0v = +{ + HP_QUAD, + refquad_2eb_0v_splitedges, + refquad_2eb_0v_splitfaces, + 0, + refquad_2eb_0v_newelstypes, + refquad_2eb_0v_newels +}; + + + + + + + + +// HP_QUAD_2EB_1VA +int refquad_2eb_1va_splitedges[][3] = +{ + { 1, 4, 5 }, + { 2, 3, 6 }, + { 3, 2, 7 }, + { 4, 1, 8 }, + { 1, 2, 9 }, + { 0, 0, 0 } +}; +int refquad_2eb_1va_splitfaces[][4] = +{ + { 0, 0, 0, 0 }, +}; +HPREF_ELEMENT_TYPE refquad_2eb_1va_newelstypes[] = +{ + HP_QUAD_SINGEDGE, + HP_QUAD_SINGEDGE, + HP_TRIG_SINGEDGECORNER1, + HP_QUAD, + HP_NONE, +}; +int refquad_2eb_1va_newels[][8] = +{ + { 9, 2, 6, 5 }, + { 3, 4, 8, 7 }, + { 1, 9, 5 }, + { 5, 6, 7, 8 } +}; +HPRef_Struct refquad_2eb_1va = +{ + HP_QUAD, + refquad_2eb_1va_splitedges, + refquad_2eb_1va_splitfaces, + 0, + refquad_2eb_1va_newelstypes, + refquad_2eb_1va_newels +}; + + + + +// HP_QUAD_2EB_1VB +int refquad_2eb_1vb_splitedges[][3] = +{ + { 1, 4, 5 }, + { 2, 3, 6 }, + { 3, 2, 7 }, + { 4, 1, 8 }, + { 2, 1, 9 }, + { 0, 0, 0 } +}; +int refquad_2eb_1vb_splitfaces[][4] = +{ + { 0, 0, 0, 0 }, +}; +HPREF_ELEMENT_TYPE refquad_2eb_1vb_newelstypes[] = +{ + HP_QUAD_SINGEDGE, + HP_QUAD_SINGEDGE, + HP_TRIG_SINGEDGECORNER2, + HP_QUAD, + HP_NONE, +}; +int refquad_2eb_1vb_newels[][8] = +{ + { 1, 9, 6, 5 }, + { 3, 4, 8, 7 }, + { 9, 2, 6 }, + { 5, 6, 7, 8 } +}; +HPRef_Struct refquad_2eb_1vb = +{ + HP_QUAD, + refquad_2eb_1vb_splitedges, + refquad_2eb_1vb_splitfaces, + 0, + refquad_2eb_1vb_newelstypes, + refquad_2eb_1vb_newels +}; + + + + + + +// HP_QUAD_2EB_2VA +int refquad_2eb_2va_splitedges[][3] = +{ + { 1, 4, 5 }, + { 2, 3, 6 }, + { 3, 2, 7 }, + { 4, 1, 8 }, + { 1, 2, 9 }, + { 2, 1, 10 }, + { 0, 0, 0 } +}; +HPREF_ELEMENT_TYPE refquad_2eb_2va_newelstypes[] = +{ + HP_QUAD_SINGEDGE, + HP_QUAD_SINGEDGE, + HP_TRIG_SINGEDGECORNER1, + HP_TRIG_SINGEDGECORNER2, + HP_QUAD, + HP_NONE, +}; +int refquad_2eb_2va_newels[][8] = +{ + { 9, 10, 6, 5 }, + { 3, 4, 8, 7 }, + { 1, 9, 5 }, + { 10, 2, 6 }, + { 5, 6, 7, 8 } +}; +HPRef_Struct refquad_2eb_2va = +{ + HP_QUAD, + refquad_2eb_2va_splitedges, + 0, 0, + refquad_2eb_2va_newelstypes, + refquad_2eb_2va_newels +}; + + + +// HP_QUAD_2EB_2VB +int refquad_2eb_2vb_splitedges[][3] = +{ + { 1, 4, 5 }, + { 2, 3, 6 }, + { 3, 2, 7 }, + { 4, 1, 8 }, + { 1, 2, 9 }, + { 3, 4, 10 }, + { 0, 0, 0 } +}; +HPREF_ELEMENT_TYPE refquad_2eb_2vb_newelstypes[] = +{ + HP_QUAD_SINGEDGE, + HP_QUAD_SINGEDGE, + HP_TRIG_SINGEDGECORNER1, + HP_TRIG_SINGEDGECORNER1, + HP_QUAD, + HP_NONE, +}; +int refquad_2eb_2vb_newels[][8] = +{ + { 9, 2, 6, 5 }, + { 10, 4, 8, 7 }, + { 1, 9, 5 }, + { 3, 10, 7 }, + { 5, 6, 7, 8 } +}; +HPRef_Struct refquad_2eb_2vb = +{ + HP_QUAD, + refquad_2eb_2vb_splitedges, + 0, 0, + refquad_2eb_2vb_newelstypes, + refquad_2eb_2vb_newels +}; + + + +// HP_QUAD_2EB_2VC +int refquad_2eb_2vc_splitedges[][3] = +{ + { 1, 4, 5 }, + { 2, 3, 6 }, + { 3, 2, 7 }, + { 4, 1, 8 }, + { 1, 2, 9 }, + { 4, 3, 10 }, + { 0, 0, 0 } +}; +int refquad_2eb_2vc_splitfaces[][4] = +{ + { 0, 0, 0, 0 }, +}; +HPREF_ELEMENT_TYPE refquad_2eb_2vc_newelstypes[] = +{ + HP_QUAD_SINGEDGE, + HP_QUAD_SINGEDGE, + HP_TRIG_SINGEDGECORNER1, + HP_TRIG_SINGEDGECORNER2, + HP_QUAD, + HP_NONE, +}; +int refquad_2eb_2vc_newels[][8] = +{ + { 9, 2, 6, 5 }, + { 3, 10, 8, 7 }, + { 1, 9, 5 }, + { 10, 4, 8 }, + { 5, 6, 7, 8 } +}; +HPRef_Struct refquad_2eb_2vc = +{ + HP_QUAD, + refquad_2eb_2vc_splitedges, + refquad_2eb_2vc_splitfaces, + 0, + refquad_2eb_2vc_newelstypes, + refquad_2eb_2vc_newels +}; + + + + +// HP_QUAD_2EB_2VD +int refquad_2eb_2vd_splitedges[][3] = +{ + { 1, 4, 5 }, + { 2, 3, 6 }, + { 3, 2, 7 }, + { 4, 1, 8 }, + { 2, 1, 9 }, + { 4, 3, 10 }, + { 0, 0, 0 } +}; +HPREF_ELEMENT_TYPE refquad_2eb_2vd_newelstypes[] = +{ + HP_QUAD_SINGEDGE, + HP_QUAD_SINGEDGE, + HP_TRIG_SINGEDGECORNER2, + HP_TRIG_SINGEDGECORNER2, + HP_QUAD, + HP_NONE, +}; +int refquad_2eb_2vd_newels[][8] = +{ + { 1, 9, 6, 5 }, + { 3, 10, 8, 7 }, + { 9, 2, 6 }, + { 10, 4, 8 }, + { 5, 6, 7, 8 } +}; +HPRef_Struct refquad_2eb_2vd = +{ + HP_QUAD, + refquad_2eb_2vd_splitedges, + 0, 0, + refquad_2eb_2vd_newelstypes, + refquad_2eb_2vd_newels +}; + + + + + + + +// HP_QUAD_2EB_3VA +int refquad_2eb_3va_splitedges[][3] = +{ + { 1, 4, 5 }, + { 2, 3, 6 }, + { 1, 2, 7 }, + { 2, 1, 8 }, + { 3, 2, 9 }, + { 4, 1, 10 }, + { 3, 4, 11 }, + { 0, 0, 0 } +}; +HPREF_ELEMENT_TYPE refquad_2eb_3va_newelstypes[] = +{ + HP_TRIG_SINGEDGECORNER1, + HP_TRIG_SINGEDGECORNER2, + HP_TRIG_SINGEDGECORNER1, + HP_QUAD_SINGEDGE, + HP_QUAD_SINGEDGE, + HP_QUAD, + HP_NONE, +}; +int refquad_2eb_3va_newels[][8] = +{ + { 1, 7, 5 }, + { 8, 2, 6 }, + { 3, 11, 9}, + { 7, 8, 6, 5 }, + { 11, 4, 10, 9 }, + { 5, 6, 9, 10 } +}; +HPRef_Struct refquad_2eb_3va = +{ + HP_QUAD, + refquad_2eb_3va_splitedges, + 0, 0, + refquad_2eb_3va_newelstypes, + refquad_2eb_3va_newels +}; + + + + + +// HP_QUAD_2EB_3VB +int refquad_2eb_3vb_splitedges[][3] = +{ + { 1, 4, 5 }, + { 2, 3, 6 }, + { 1, 2, 7 }, + { 2, 1, 8 }, + { 3, 2, 9 }, + { 4, 1, 10 }, + { 4, 3, 11 }, + { 0, 0, 0 } +}; +HPREF_ELEMENT_TYPE refquad_2eb_3vb_newelstypes[] = +{ + HP_TRIG_SINGEDGECORNER1, + HP_TRIG_SINGEDGECORNER2, + HP_TRIG_SINGEDGECORNER2, + HP_QUAD_SINGEDGE, + HP_QUAD_SINGEDGE, + HP_QUAD, + HP_NONE, +}; +int refquad_2eb_3vb_newels[][8] = +{ + { 1, 7, 5 }, + { 8, 2, 6 }, + { 11, 4, 10 }, + { 7, 8, 6, 5 }, + { 3, 11, 10, 9 }, + { 5, 6, 9, 10 } +}; +HPRef_Struct refquad_2eb_3vb = +{ + HP_QUAD, + refquad_2eb_3vb_splitedges, + 0, 0, + refquad_2eb_3vb_newelstypes, + refquad_2eb_3vb_newels +}; + + + + + + +// HP_QUAD_2EB_4V +int refquad_2eb_4v_splitedges[][3] = +{ + { 1, 4, 5 }, + { 2, 3, 6 }, + { 3, 2, 7 }, + { 4, 1, 8 }, + { 1, 2, 9 }, + { 2, 1, 10 }, + { 3, 4, 11 }, + { 4, 3, 12 }, + { 0, 0, 0 } +}; +int refquad_2eb_4v_splitfaces[][4] = +{ + { 0, 0, 0, 0 }, +}; +HPREF_ELEMENT_TYPE refquad_2eb_4v_newelstypes[] = +{ + HP_QUAD_SINGEDGE, + HP_QUAD_SINGEDGE, + HP_QUAD, + HP_TRIG_SINGEDGECORNER1, + HP_TRIG_SINGEDGECORNER2, + HP_TRIG_SINGEDGECORNER1, + HP_TRIG_SINGEDGECORNER2, + HP_NONE, +}; +int refquad_2eb_4v_newels[][8] = +{ + { 9, 10, 6, 5 }, + { 11, 12, 8, 7 }, + { 5, 6, 7, 8 }, + { 1, 9, 5 }, + { 10, 2, 6 }, + { 3, 11, 7 }, + { 12, 4, 8 }, +}; +HPRef_Struct refquad_2eb_4v = +{ + HP_QUAD, + refquad_2eb_4v_splitedges, + refquad_2eb_4v_splitfaces, + 0, + refquad_2eb_4v_newelstypes, + refquad_2eb_4v_newels +}; + + + + + + + +// HP_QUAD_3E +int refquad_3e_splitedges[][3] = +{ + { 1, 2, 5 }, + { 1, 4, 6 }, + { 2, 1, 7 }, + { 2, 3, 8 }, + { 3, 4, 10 }, + { 4, 3, 12 }, + { 0, 0, 0 } +}; + +int refquad_3e_splitfaces[][4] = +{ + { 1, 2, 4, 13 }, + { 2, 3, 1, 14 }, + { 0, 0, 0, 0 }, +}; + +HPREF_ELEMENT_TYPE refquad_3e_newelstypes[] = +{ + HP_QUAD_2E, + HP_QUAD_2E, +// HP_TRIG_SINGEDGECORNER1, +// HP_TRIG_SINGEDGECORNER2, +// HP_TRIG_SINGEDGECORNER2, +// HP_TRIG_SINGEDGECORNER1, + + HP_QUAD_SINGEDGE, + HP_QUAD_SINGEDGE, + HP_QUAD_SINGEDGE, + + HP_QUAD, + HP_NONE, +}; +int refquad_3e_newels[][8] = +{ +// { 1, 5, 13 }, +// { 6, 1, 13 }, +// { 7, 2, 14 }, +// { 2, 8, 14 }, + { 1, 5, 13, 6 }, + { 2, 8, 14, 7 }, + { 5, 7, 14, 13 }, + { 8, 3, 10, 14 }, + { 4, 6, 13, 12 }, + { 13, 14, 10, 12 } +}; +HPRef_Struct refquad_3e = +{ + HP_QUAD, + refquad_3e_splitedges, + refquad_3e_splitfaces, + 0, + refquad_3e_newelstypes, + refquad_3e_newels +}; + + + + + + + +// HP_QUAD_3E_3VA +int refquad_3e_3va_splitedges[][3] = +{ + { 1, 2, 5 }, + { 1, 4, 6 }, + { 2, 1, 7 }, + { 2, 3, 8 }, + { 3, 4, 10 }, + { 3, 2, 11 }, + { 4, 3, 12 }, + { 0, 0, 0 } +}; + +int refquad_3e_3va_splitfaces[][4] = +{ + { 1, 2, 4, 13 }, + { 2, 3, 1, 14 }, + { 0, 0, 0, 0 }, +}; + +HPREF_ELEMENT_TYPE refquad_3e_3va_newelstypes[] = +{ + HP_QUAD_2E, + HP_QUAD_2E, + +// HP_TRIG_SINGEDGECORNER1, +// HP_TRIG_SINGEDGECORNER2, +// HP_TRIG_SINGEDGECORNER2, +// HP_TRIG_SINGEDGECORNER1, + HP_TRIG_SINGEDGECORNER2, + + HP_QUAD_SINGEDGE, + HP_QUAD_SINGEDGE, + HP_QUAD_SINGEDGE, + + HP_QUAD, + HP_NONE, +}; +int refquad_3e_3va_newels[][8] = +{ +// { 1, 5, 13 }, +// { 6, 1, 13 }, +// { 7, 2, 14 }, +// { 2, 8, 14 }, + { 1, 5, 13, 6 }, + { 2, 8, 14, 7 }, + { 11, 3, 10 }, + { 5, 7, 14, 13 }, + { 8, 11, 10, 14 }, + { 4, 6, 13, 12 }, + { 13, 14, 10, 12 } +}; +HPRef_Struct refquad_3e_3va = +{ + HP_QUAD, + refquad_3e_3va_splitedges, + refquad_3e_3va_splitfaces, + 0, + refquad_3e_3va_newelstypes, + refquad_3e_3va_newels +}; + + + + + + + + + + +// HP_QUAD_3E_3VB +int refquad_3e_3vb_splitedges[][3] = +{ + { 1, 2, 5 }, + { 1, 4, 6 }, + { 2, 1, 7 }, + { 2, 3, 8 }, + { 3, 4, 10 }, + { 4, 1, 11 }, + { 4, 3, 12 }, + { 0, 0, 0 } +}; + +int refquad_3e_3vb_splitfaces[][4] = +{ + { 1, 2, 4, 13 }, + { 2, 3, 1, 14 }, + { 0, 0, 0, 0 }, +}; + +HPREF_ELEMENT_TYPE refquad_3e_3vb_newelstypes[] = +{ + HP_QUAD_2E, + HP_QUAD_2E, + +// HP_TRIG_SINGEDGECORNER1, +// HP_TRIG_SINGEDGECORNER2, +// HP_TRIG_SINGEDGECORNER2, +// HP_TRIG_SINGEDGECORNER1, + HP_TRIG_SINGEDGECORNER1, + + HP_QUAD_SINGEDGE, + HP_QUAD_SINGEDGE, + HP_QUAD_SINGEDGE, + + HP_QUAD, + HP_NONE, +}; +int refquad_3e_3vb_newels[][8] = +{ +// { 1, 5, 13 }, +// { 6, 1, 13 }, +// { 7, 2, 14 }, +// { 2, 8, 14 }, + { 1, 5, 13, 6 }, + { 2, 8, 14, 7 }, + { 4, 11, 12 }, + { 5, 7, 14, 13 }, + { 8, 3, 10, 14 }, + { 11, 6, 13, 12 }, + { 13, 14, 10, 12 } +}; +HPRef_Struct refquad_3e_3vb = +{ + HP_QUAD, + refquad_3e_3vb_splitedges, + refquad_3e_3vb_splitfaces, + 0, + refquad_3e_3vb_newelstypes, + refquad_3e_3vb_newels +}; + + + + + + + + + +// HP_QUAD_3E_4V +int refquad_3e_4v_splitedges[][3] = +{ + { 1, 2, 5 }, + { 1, 4, 6 }, + { 2, 1, 7 }, + { 2, 3, 8 }, + { 3, 4, 10 }, + { 3, 2, 11 }, + { 4, 3, 12 }, + { 4, 1, 15 }, + { 0, 0, 0 } +}; + +int refquad_3e_4v_splitfaces[][4] = +{ + { 1, 2, 4, 13 }, + { 2, 3, 1, 14 }, + { 0, 0, 0, 0 }, +}; + +HPREF_ELEMENT_TYPE refquad_3e_4v_newelstypes[] = +{ + HP_QUAD_2E, + HP_QUAD_2E, + +// HP_TRIG_SINGEDGECORNER1, +// HP_TRIG_SINGEDGECORNER2, +// HP_TRIG_SINGEDGECORNER2, +// HP_TRIG_SINGEDGECORNER1, + HP_TRIG_SINGEDGECORNER2, + HP_TRIG_SINGEDGECORNER1, + + HP_QUAD_SINGEDGE, + HP_QUAD_SINGEDGE, + HP_QUAD_SINGEDGE, + + HP_QUAD, + HP_NONE, +}; +int refquad_3e_4v_newels[][8] = +{ +// { 1, 5, 13 }, +// { 6, 1, 13 }, +// { 7, 2, 14 }, +// { 2, 8, 14 }, + { 1, 5, 13, 6 }, + { 2, 8, 14, 7 }, + { 11, 3, 10 }, + { 4, 15, 12 }, + { 5, 7, 14, 13 }, + { 8, 11, 10, 14 }, + { 15, 6, 13, 12 }, + { 13, 14, 10, 12 } +}; +HPRef_Struct refquad_3e_4v = +{ + HP_QUAD, + refquad_3e_4v_splitedges, + refquad_3e_4v_splitfaces, + 0, + refquad_3e_4v_newelstypes, + refquad_3e_4v_newels +}; + + + + + + + + + +// HP_QUAD_4E +int refquad_4e_splitedges[][3] = +{ + { 1, 2, 5 }, + { 1, 4, 6 }, + { 2, 1, 7 }, + { 2, 3, 8 }, + { 3, 2, 9 }, + { 3, 4, 10 }, + { 4, 1, 11 }, + { 4, 3, 12 }, + { 0, 0, 0 } +}; + +int refquad_4e_splitfaces[][4] = +{ + { 1, 2, 4, 13 }, + { 2, 3, 1, 14 }, + { 3, 4, 2, 15 }, + { 4, 1, 3, 16 }, + { 0, 0, 0, 0 }, +}; + +HPREF_ELEMENT_TYPE refquad_4e_newelstypes[] = +{ + HP_QUAD_2E, + HP_QUAD_2E, + HP_QUAD_2E, + HP_QUAD_2E, + + HP_QUAD_SINGEDGE, + HP_QUAD_SINGEDGE, + HP_QUAD_SINGEDGE, + HP_QUAD_SINGEDGE, + + HP_QUAD, + HP_NONE, +}; +int refquad_4e_newels[][8] = +{ + { 1, 5, 13, 6 }, + { 2, 8, 14, 7 }, + { 3, 10, 15, 9 }, + { 4, 11, 16, 12 }, + { 5, 7, 14, 13 }, + { 8, 9, 15, 14 }, + { 10, 12, 16, 15 }, + { 11, 6, 13, 16 }, + { 13, 14, 15, 16 } +}; +HPRef_Struct refquad_4e = +{ + HP_QUAD, + refquad_4e_splitedges, + refquad_4e_splitfaces, + 0, + refquad_4e_newelstypes, + refquad_4e_newels +}; + + diff --git a/contrib/Netgen/libsrc/meshing/hpref_tet.hpp b/contrib/Netgen/libsrc/meshing/hpref_tet.hpp new file mode 100644 index 0000000000..b071269ec8 --- /dev/null +++ b/contrib/Netgen/libsrc/meshing/hpref_tet.hpp @@ -0,0 +1,2842 @@ + + +// HP_TET +int reftet_splitedges[][3] = +{ + { 0, 0, 0 } +}; +HPREF_ELEMENT_TYPE reftet_newelstypes[] = +{ + HP_TET, + HP_NONE, +}; +int reftet_newels[][8] = +{ + { 1, 2, 3, 4 }, +}; +HPRef_Struct reftet = +{ + HP_TET, + reftet_splitedges, + 0, 0, + reftet_newelstypes, + reftet_newels +}; + + + +/* *********** Tet - Refinement - 0 edges *************** */ + +// HP_TET_0E_1V +int reftet_0e_1v_splitedges[][3] = +{ + { 1, 2, 5 }, + { 1, 3, 6 }, + { 1, 4, 7 }, + { 0, 0, 0 } +}; +HPREF_ELEMENT_TYPE reftet_0e_1v_newelstypes[] = +{ + HP_TET_0E_1V, + HP_PRISM, + HP_NONE, +}; +int reftet_0e_1v_newels[][8] = +{ + { 1, 5, 6, 7 }, + { 5, 6, 7, 2, 3, 4 } +}; +HPRef_Struct reftet_0e_1v = +{ + HP_TET, + reftet_0e_1v_splitedges, + 0, 0, + reftet_0e_1v_newelstypes, + reftet_0e_1v_newels +}; + + + +// HP_TET_0E_2V +int reftet_0e_2v_splitedges[][3] = +{ + { 1, 2, 5 }, + { 1, 3, 6 }, + { 1, 4, 7 }, + { 2, 1, 8 }, + { 2, 3, 9 }, + { 2, 4, 10 }, + { 0, 0, 0 } +}; +HPREF_ELEMENT_TYPE reftet_0e_2v_newelstypes[] = +{ + HP_TET_0E_1V, + HP_TET_0E_1V, + HP_PRISM, + HP_PRISM, + HP_NONE, +}; +int reftet_0e_2v_newels[][8] = +{ + { 1, 5, 6, 7 }, + { 2, 10, 9, 8 }, + { 5, 6, 7, 8, 9, 10 }, + { 4, 10, 7, 3, 9, 6 }, +}; +HPRef_Struct reftet_0e_2v = +{ + HP_TET, + reftet_0e_2v_splitedges, + 0, 0, + reftet_0e_2v_newelstypes, + reftet_0e_2v_newels +}; + + + + + +// HP_TET_0E_3V +int reftet_0e_3v_splitedges[][3] = +{ + { 1, 2, 5 }, + { 1, 3, 6 }, + { 1, 4, 7 }, + { 2, 1, 8 }, + { 2, 3, 9 }, + { 2, 4, 10 }, + { 3, 1, 11 }, + { 3, 2, 12 }, + { 3, 4, 13 }, + { 0, 0, 0 } +}; +int reftet_0e_3v_splitfaces[][4] = + { + { 1, 2, 3, 14 }, + { 2, 3, 1, 15 }, + { 3, 1, 2, 16 }, + { 0, 0, 0, 0 }, + }; +HPREF_ELEMENT_TYPE reftet_0e_3v_newelstypes[] = +{ + HP_PYRAMID_0E_1V, + HP_PYRAMID_0E_1V, + HP_PYRAMID_0E_1V, + HP_PRISM, + HP_PRISM, + HP_PRISM, + HP_PRISM, + HP_TET, + HP_NONE, +}; +int reftet_0e_3v_newels[][8] = +{ + { 1, 5, 14, 6, 7 }, + { 2, 9, 15, 8, 10 }, + { 3, 11, 16, 12, 13 }, + { 5, 14, 7, 8, 15, 10 }, + { 9, 15, 10, 12, 16, 13 }, + { 6, 7, 14, 11, 13, 16 }, + { 14, 15, 16, 7, 10, 13 }, + { 7, 10, 13, 4 } +}; +HPRef_Struct reftet_0e_3v = +{ + HP_TET, + reftet_0e_3v_splitedges, + reftet_0e_3v_splitfaces, + 0, + reftet_0e_3v_newelstypes, + reftet_0e_3v_newels +}; + + + + + +// HP_TET_0E_4V +int reftet_0e_4v_splitedges[][3] = +{ + { 1, 2, 5 }, + { 1, 3, 6 }, + { 1, 4, 7 }, + { 2, 1, 8 }, + { 2, 3, 9 }, + { 2, 4, 10 }, + { 3, 1, 11 }, + { 3, 2, 12 }, + { 3, 4, 13 }, + { 4, 1, 14 }, + { 4, 2, 15 }, + { 4, 3, 16 }, + { 0, 0, 0 } +}; +int reftet_0e_4v_splitfaces[][4] = + { + { 1, 2, 3, 17 }, + { 1, 2, 4, 18 }, + { 1, 3, 4, 19 }, + + { 2, 1, 3, 20 }, + { 2, 1, 4, 21 }, + { 2, 3, 4, 22 }, + + { 3, 1, 2, 23 }, + { 3, 1, 4, 24 }, + { 3, 2, 4, 25 }, + + { 4, 1, 2, 26 }, + { 4, 1, 3, 27 }, + { 4, 2, 3, 28 }, + { 0, 0, 0, 0 }, + }; +int reftet_0e_4v_splitelements[][5] = + { + { 1, 2, 3, 4, 29 }, + { 2, 3, 4, 1, 30 }, + { 3, 4, 1, 2, 31 }, + { 4, 1, 2, 3, 32 }, + { 0 }, + }; +HPREF_ELEMENT_TYPE reftet_0e_4v_newelstypes[] = +{ + HP_HEX_0E_1V, + HP_HEX_0E_1V, + HP_HEX_0E_1V, + HP_HEX_0E_1V, + HP_PRISM, HP_PRISM, + HP_PRISM, HP_PRISM, + HP_PRISM, HP_PRISM, + HP_PRISM, HP_PRISM, + HP_PRISM, HP_PRISM, + HP_PRISM, HP_PRISM, + /* + HP_HEX, + HP_HEX, + HP_HEX, + HP_HEX, + HP_HEX, + HP_HEX, + */ + HP_PRISM, + HP_PRISM, + HP_PRISM, + HP_PRISM, + HP_TET, + HP_NONE, +}; +int reftet_0e_4v_newels[][8] = +{ + { 1, 5, 17, 6, 7, 18, 29, 19 }, + { 2, 9, 20, 8, 10, 22, 30, 21 }, + { 3, 11, 23, 12, 13, 24, 31, 25 }, + { 4, 15, 26, 14, 16, 28, 32, 27 }, + { 5, 17, 18, 8, 20, 21 }, + { 18, 17, 29, 21, 20, 30 }, + { 6, 19, 17, 11, 24, 23 }, + { 17, 19, 29, 23, 24, 31 }, + { 7, 18, 19, 14, 26, 27 }, + { 19, 18, 29, 27, 26, 32 }, + { 9, 20, 22, 12, 23, 25 }, + { 22, 20, 30, 25, 23, 31 }, + { 10, 22, 21, 15, 28, 26 }, + { 21, 22, 30, 26, 28, 32 }, + { 13, 24, 25, 16, 27, 28 }, + { 25, 24, 31, 28, 27, 32 }, + /* + { 5, 17, 29, 18, 8, 20, 30, 21 }, + { 6, 19, 29, 17, 11, 24, 31, 23 }, + { 7, 18, 29, 19, 14, 26, 32, 27 }, + { 9, 20, 30, 22, 12, 23, 31, 25 }, + { 10, 22, 30, 21, 15, 28, 32, 26 }, + { 13, 24, 31, 25, 16, 27, 32, 28 }, + */ + { 17, 20, 23, 29, 30, 31 }, + { 18, 26, 21, 29, 32, 30 }, + { 19, 24, 27, 29, 31, 32 }, + { 22, 28, 25, 30, 32, 31 }, + + { 29, 30, 31, 32 }, +}; +HPRef_Struct reftet_0e_4v = +{ + HP_TET, + reftet_0e_4v_splitedges, + reftet_0e_4v_splitfaces, + reftet_0e_4v_splitelements, + reftet_0e_4v_newelstypes, + reftet_0e_4v_newels +}; + + + + + + + + + + + + + + + + + +/* *********** Tet - Refinement - 1 edge *************** */ + + + +// HP_TET_1E_0V +int reftet_1e_0v_splitedges[][3] = +{ + { 1, 3, 5 }, + { 1, 4, 6 }, + { 2, 3, 7 }, + { 2, 4, 8 }, + { 0, 0, 0 } +}; +HPREF_ELEMENT_TYPE reftet_1e_0v_newelstypes[] = +{ + HP_PRISM_SINGEDGE, + HP_PRISM, + HP_NONE, +}; +int reftet_1e_0v_newels[][8] = +{ + { 1, 5, 6, 2, 7, 8 }, + { 7, 3, 5, 8, 4, 6 } +}; +HPRef_Struct reftet_1e_0v = +{ + HP_TET, + reftet_1e_0v_splitedges, + 0, 0, + reftet_1e_0v_newelstypes, + reftet_1e_0v_newels +}; + + + + + +// HP_TET_1E_1VA +int reftet_1e_1va_splitedges[][3] = +{ + { 1, 3, 5 }, + { 1, 4, 6 }, + { 2, 3, 7 }, + { 2, 4, 8 }, + { 1, 2, 9 }, + { 0, 0, 0 } +}; +HPREF_ELEMENT_TYPE reftet_1e_1va_newelstypes[] = +{ + HP_TET_1E_1VA, + HP_PRISM_SINGEDGE, + HP_PRISM, + HP_NONE, +}; +int reftet_1e_1va_newels[][8] = +{ + { 1, 9, 5, 6 }, + { 9, 5, 6, 2, 7, 8 }, + { 7, 3, 5, 8, 4, 6 } +}; +HPRef_Struct reftet_1e_1va = +{ + HP_TET, + reftet_1e_1va_splitedges, + 0, 0, + reftet_1e_1va_newelstypes, + reftet_1e_1va_newels +}; + + + + + + +// HP_TET_1E_1VB +int reftet_1e_1vb_splitedges[][3] = +{ + { 1, 3, 5 }, + { 1, 4, 6 }, + { 2, 3, 7 }, + { 2, 4, 8 }, + { 4, 1, 9 }, + { 4, 2, 10 }, + { 4, 3, 11 }, + { 0, 0, 0 } +}; +int reftet_1e_1vb_splitelements[][5] = +{ + { 4, 1, 2, 3, 12 }, + { 0 } +}; + +HPREF_ELEMENT_TYPE reftet_1e_1vb_newelstypes[] = +{ + HP_PRISM_SINGEDGE, + HP_TET_0E_1V, + HP_PYRAMID, + HP_TET, + HP_PYRAMID, + HP_TET, + HP_PYRAMID, + HP_TET, + HP_PYRAMID, + HP_TET, + HP_NONE, +}; +int reftet_1e_1vb_newels[][8] = +{ + { 1, 5, 6, 2, 7, 8 }, + { 4, 11, 10, 9 }, + { 7, 8, 10, 11, 12 }, + { 3, 7, 11, 12 }, + { 5, 11, 9, 6, 12 }, + { 5, 3, 11, 12 }, + { 6, 9, 10, 8, 12 }, + { 5, 7, 3, 12 }, + { 5, 6, 8, 7, 12 }, + { 9, 11, 10, 12 } +}; +HPRef_Struct reftet_1e_1vb = +{ + HP_TET, + reftet_1e_1vb_splitedges, + 0, + reftet_1e_1vb_splitelements, + reftet_1e_1vb_newelstypes, + reftet_1e_1vb_newels +}; + + + + + + + + +// HP_TET_1E_2VA +int reftet_1e_2va_splitedges[][3] = +{ + { 1, 2, 5 }, + { 1, 3, 6 }, + { 1, 4, 7 }, + { 2, 1, 8 }, + { 2, 3, 9 }, + { 2, 4, 10 }, + { 0, 0, 0 } +}; +HPREF_ELEMENT_TYPE reftet_1e_2va_newelstypes[] = +{ + HP_TET_1E_1VA, + HP_TET_1E_1VA, + HP_PRISM_SINGEDGE, + HP_PRISM, + HP_NONE, +}; +int reftet_1e_2va_newels[][8] = +{ + { 1, 5, 6, 7 }, + { 2, 8, 10, 9 }, + { 5, 6, 7, 8, 9, 10 }, + { 4, 10, 7, 3, 9, 6 }, +}; +HPRef_Struct reftet_1e_2va = +{ + HP_TET, + reftet_1e_2va_splitedges, + 0, 0, + reftet_1e_2va_newelstypes, + reftet_1e_2va_newels +}; + + + + + + + +// HP_TET_1E_2VB +int reftet_1e_2vb_splitedges[][3] = +{ + { 1, 2, 5 }, + { 1, 3, 6 }, + { 1, 4, 7 }, + { 2, 3, 8 }, + { 2, 4, 9 }, + { 3, 1, 10 }, + { 3, 2, 11 }, + { 3, 4, 12 }, + { 0, 0, 0 } +}; +int reftet_1e_2vb_splitelements[][5] = +{ + { 3, 4, 1, 2, 13 }, + { 0 } +}; + +HPREF_ELEMENT_TYPE reftet_1e_2vb_newelstypes[] = +{ + HP_TET_1E_1VA, + HP_PRISM_SINGEDGE, + HP_TET_0E_1V, + HP_PYRAMID, + HP_TET, + HP_PYRAMID, + HP_TET, + HP_PYRAMID, + HP_TET, + HP_PYRAMID, + HP_TET, + HP_NONE, +}; +int reftet_1e_2vb_newels[][8] = +{ + { 1, 5, 6, 7 }, + { 5, 6, 7, 2, 8, 9 }, + { 3, 10, 11, 12 }, + + { 8, 9, 12, 11, 13 }, + { 4, 12, 9, 13 }, + { 6, 10, 12, 7, 13 }, + { 4, 7, 12, 13 }, + { 6, 8, 11, 10, 13 }, + { 4, 9, 7, 13 }, + { 6, 7, 9, 8, 13 }, + { 10, 11, 12, 13 }, +}; +HPRef_Struct reftet_1e_2vb = +{ + HP_TET, + reftet_1e_2vb_splitedges, + 0, + reftet_1e_2vb_splitelements, + reftet_1e_2vb_newelstypes, + reftet_1e_2vb_newels +}; + + + + + + +// HP_TET_1E_2VC +int reftet_1e_2vc_splitedges[][3] = +{ + { 1, 2, 5 }, + { 1, 3, 6 }, + { 1, 4, 7 }, + { 2, 3, 8 }, + { 2, 4, 9 }, + { 4, 1, 10 }, + { 4, 2, 11 }, + { 4, 3, 12 }, + { 0, 0, 0 } +}; +int reftet_1e_2vc_splitelements[][5] = +{ + { 4, 1, 2, 3, 13 }, + { 0 } +}; + +HPREF_ELEMENT_TYPE reftet_1e_2vc_newelstypes[] = +{ + HP_TET_1E_1VA, + HP_PRISM_SINGEDGE, + HP_TET_0E_1V, + HP_PYRAMID, + HP_TET, + HP_PYRAMID, + HP_TET, + HP_PYRAMID, + HP_TET, + HP_PYRAMID, + HP_TET, + HP_NONE, +}; +int reftet_1e_2vc_newels[][8] = +{ + { 1, 5, 6, 7 }, + { 5, 6, 7, 2, 8, 9 }, + { 4, 11, 10, 12 }, + { 8, 9, 11, 12, 13 }, + { 3, 8, 12, 13 }, + { 7, 6, 12, 10, 13 }, + { 3, 12, 6, 13 }, + { 9, 7, 10, 11, 13 }, + { 3, 6, 8, 13 }, + { 6, 7, 9, 8, 13 }, + { 10, 12, 11, 13 } +}; +HPRef_Struct reftet_1e_2vc = +{ + HP_TET, + reftet_1e_2vc_splitedges, + 0, + reftet_1e_2vc_splitelements, + reftet_1e_2vc_newelstypes, + reftet_1e_2vc_newels +}; + + + + + + + + +/* + +// HP_TET_1E_2VD +int reftet_1e_2vd_splitedges[][3] = +{ + { 1, 3, 5 }, + { 1, 4, 6 }, + { 2, 3, 7 }, + { 2, 4, 8 }, + { 3, 1, 9 }, + { 3, 2, 10 }, + { 3, 4, 11 }, + { 4, 1, 12 }, + { 4, 2, 13 }, + { 4, 3, 14 }, + { 0, 0, 0 } +}; +HPREF_ELEMENT_TYPE reftet_1e_2vd_newelstypes[] = +{ + HP_PRISM_SINGEDGE, + HP_TET_0E_1V, + HP_TET_0E_1V, + HP_PRISM, + HP_HEX, + HP_NONE, +}; +int reftet_1e_2vd_newels[][8] = +{ + { 1, 5, 6, 2, 7, 8 }, + { 4, 13, 12, 14 }, + { 3, 10, 11, 9 }, + { 14, 13, 12, 11, 10, 9 }, + { 6, 12, 13, 8, 5, 9, 10, 7 }, +}; +HPRef_Struct reftet_1e_2vd = +{ + HP_TET, + reftet_1e_2vd_splitedges, + 0, 0, + reftet_1e_2vd_newelstypes, + reftet_1e_2vd_newels +}; + +*/ + + + + +// HP_TET_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 }, + /* + { 5, 17, 29, 18, 8, 20, 30, 21 }, + { 6, 19, 29, 17, 11, 24, 31, 23 }, + { 7, 18, 29, 19, 14, 26, 32, 27 }, + { 9, 20, 30, 22, 12, 23, 31, 25 }, + { 10, 22, 30, 21, 15, 28, 32, 26 }, + { 13, 24, 31, 25, 16, 27, 32, 28 }, + */ + { 17, 20, 23, 29, 30, 31 }, + { 18, 26, 21, 29, 32, 30 }, + { 19, 24, 27, 29, 31, 32 }, + { 22, 28, 25, 30, 32, 31 }, + + { 29, 30, 31, 32 }, +}; +HPRef_Struct reftet_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_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_2VA, // 2 opposite edges +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, 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_2va = +{ + HP_TET, + reftet_2eb_2va_splitedges, + 0, 0, + reftet_2eb_2va_newelstypes, + reftet_2eb_2va_newels +}; + + + + + + +// HP_TET_2EB_4V, // 2 opposite edges +int reftet_2eb_4v_splitedges[][3] = +{ + { 1, 2, 5 }, + { 1, 3, 6 }, + { 1, 4, 7 }, + { 2, 1, 8 }, + { 2, 3, 9 }, + { 2, 4, 10 }, + { 3, 1, 11 }, + { 3, 2, 12 }, + { 3, 4, 13 }, + { 4, 1, 14 }, + { 4, 2, 15 }, + { 4, 3, 16 }, + { 0, 0, 0 } +}; + +HPREF_ELEMENT_TYPE reftet_2eb_4v_newelstypes[] = + { + HP_PRISM_SINGEDGE, + HP_PRISM_SINGEDGE, + HP_TET_1E_1VA, + HP_TET_1E_1VA, + HP_TET_1E_1VA, + HP_TET_1E_1VA, + HP_HEX, + HP_NONE, + }; +int reftet_2eb_4v_newels[][8] = +{ + { 5, 6, 7, 8, 9, 10 }, + { 16, 15, 14, 13, 12, 11 }, + { 1, 5, 6, 7 }, + { 2, 8, 10, 9 }, + { 3, 13, 11, 12 }, + { 4, 16, 15, 14 }, + { 7, 14, 15, 10, 6, 11, 12, 9 } +}; +HPRef_Struct reftet_2eb_4v = +{ + HP_TET, + reftet_2eb_4v_splitedges, + 0, 0, + reftet_2eb_4v_newelstypes, + reftet_2eb_4v_newels +}; + + + + + + + + + + + + + + + + + +// HP_TET_3EA_0V, +int reftet_3ea_0v_splitedges[][3] = +{ + { 1, 2, 5 }, + { 1, 3, 6 }, + { 1, 4, 7 }, + { 2, 3, 8 }, + { 2, 4, 9 }, + { 3, 2, 10 }, + { 3, 4, 11 }, + { 4, 2, 12 }, + { 4, 3, 13 }, + { 0, 0, 0 } +}; +int reftet_3ea_0v_splitfaces[][4] = + { + { 1, 2, 3, 14 }, + { 1, 2, 4, 15 }, + { 1, 3, 4, 16 }, + { 2, 3, 4, 17 }, + { 3, 4, 2, 18 }, + { 4, 2, 3, 19 }, + { 0, 0, 0, 0 } + }; +int reftet_3ea_0v_splitelements[][5] = + { + { 1, 2, 3, 4, 20 }, + { 0 }, + }; + +HPREF_ELEMENT_TYPE reftet_3ea_0v_newelstypes[] = + { + HP_HEX_3E_0V, + HP_HEX_1E_0V, + HP_HEX_1E_0V, + HP_HEX_1E_0V, + HP_PRISM, + HP_PRISM, + HP_PRISM, + HP_TET, + HP_NONE, + }; +int reftet_3ea_0v_newels[][8] = +{ + { 1, 5, 14, 6, 7, 15, 20, 16 }, + { 5, 2, 8, 14, 15, 9, 17, 20 }, + { 3, 6, 14, 10, 11, 16, 20, 18 }, + { 7, 4, 12, 15, 16, 13, 19, 20 }, + { 11, 13, 16, 18, 19, 20 }, + { 15, 12, 9, 20, 19, 17 }, + { 8, 10, 14, 17, 18, 20 }, + { 20, 17, 18, 19 }, +}; +HPRef_Struct reftet_3ea_0v = +{ + HP_TET, + reftet_3ea_0v_splitedges, + reftet_3ea_0v_splitfaces, + reftet_3ea_0v_splitelements, + reftet_3ea_0v_newelstypes, + reftet_3ea_0v_newels +}; + + + + + + + + + + +// HP_TET_3EA_1V, +int reftet_3ea_1v_splitedges[][3] = +{ + { 1, 2, 5 }, + { 1, 3, 6 }, + { 1, 4, 7 }, + { 2, 3, 8 }, + { 2, 4, 9 }, + { 3, 2, 10 }, + { 3, 4, 11 }, + { 4, 2, 12 }, + { 4, 3, 13 }, + { 2, 1, 21 }, + { 3, 1, 22 }, + { 4, 1, 23 }, + { 0, 0, 0 } +}; +int reftet_3ea_1v_splitfaces[][4] = + { + { 1, 2, 3, 14 }, + { 1, 2, 4, 15 }, + { 1, 3, 4, 16 }, + { 2, 3, 4, 17 }, + { 3, 4, 2, 18 }, + { 4, 2, 3, 19 }, + { 0, 0, 0, 0 } + }; +int reftet_3ea_1v_splitelements[][5] = + { + { 1, 2, 3, 4, 20 }, + { 0 }, + }; + +HPREF_ELEMENT_TYPE reftet_3ea_1v_newelstypes[] = + { + HP_HEX_3E_0V, + HP_TET_1E_1VA, + HP_PRISM_SINGEDGE, + HP_PRISM, + // HP_TET_1E_1VA, + HP_PRISM_SINGEDGE, + HP_PRISM, + // HP_TET_1E_1VA, + HP_PRISM_SINGEDGE, + HP_PRISM, + + HP_PRISM, + HP_PRISM, + HP_PRISM, + HP_TET, + HP_NONE, + }; +int reftet_3ea_1v_newels[][8] = +{ + { 1, 5, 14, 6, 7, 15, 20, 16 }, + + { 2, 21, 9, 8 }, + { 5, 14, 15, 21, 8, 9 }, + { 15, 14, 20, 9, 8, 17 }, + // { 3, 22, 10, 11 }, + // { 6, 16, 14, 22, 11, 10 }, + { 6, 16, 14, 3, 11, 10 }, + { 14, 16, 20, 10, 11, 18 }, + // { 4, 23, 13, 12 }, + // { 7, 15, 16, 23, 12, 13 }, + { 7, 15, 16, 4, 12, 13 }, + { 16, 15, 20, 13, 12, 19 }, + + { 11, 13, 16, 18, 19, 20 }, + { 15, 12, 9, 20, 19, 17 }, + { 8, 10, 14, 17, 18, 20 }, + { 20, 17, 18, 19 }, +}; +HPRef_Struct reftet_3ea_1v = +{ + HP_TET, + reftet_3ea_1v_splitedges, + reftet_3ea_1v_splitfaces, + reftet_3ea_1v_splitelements, + reftet_3ea_1v_newelstypes, + reftet_3ea_1v_newels +}; + + + + + + + + + + +// HP_TET_3EA_2V, +int reftet_3ea_2v_splitedges[][3] = +{ + { 1, 2, 5 }, + { 1, 3, 6 }, + { 1, 4, 7 }, + { 2, 3, 8 }, + { 2, 4, 9 }, + { 3, 2, 10 }, + { 3, 4, 11 }, + { 4, 2, 12 }, + { 4, 3, 13 }, + { 2, 1, 21 }, + { 3, 1, 22 }, + { 4, 1, 23 }, + { 0, 0, 0 } +}; +int reftet_3ea_2v_splitfaces[][4] = + { + { 1, 2, 3, 14 }, + { 1, 2, 4, 15 }, + { 1, 3, 4, 16 }, + { 2, 3, 4, 17 }, + { 3, 4, 2, 18 }, + { 4, 2, 3, 19 }, + { 0, 0, 0, 0 } + }; +int reftet_3ea_2v_splitelements[][5] = + { + { 1, 2, 3, 4, 20 }, + { 0 }, + }; + +HPREF_ELEMENT_TYPE reftet_3ea_2v_newelstypes[] = + { + HP_HEX_3E_0V, + HP_TET_1E_1VA, + HP_PRISM_SINGEDGE, + HP_PRISM, + HP_TET_1E_1VA, + HP_PRISM_SINGEDGE, + HP_PRISM, + // HP_TET_1E_1VA, + HP_PRISM_SINGEDGE, + HP_PRISM, + + HP_PRISM, + HP_PRISM, + HP_PRISM, + HP_TET, + HP_NONE, + }; +int reftet_3ea_2v_newels[][8] = +{ + { 1, 5, 14, 6, 7, 15, 20, 16 }, + + { 2, 21, 9, 8 }, + { 5, 14, 15, 21, 8, 9 }, + { 15, 14, 20, 9, 8, 17 }, + { 3, 22, 10, 11 }, + { 6, 16, 14, 22, 11, 10 }, + { 14, 16, 20, 10, 11, 18 }, + // { 4, 23, 13, 12 }, + { 7, 15, 16, 4, 12, 13 }, + { 16, 15, 20, 13, 12, 19 }, + + { 11, 13, 16, 18, 19, 20 }, + { 15, 12, 9, 20, 19, 17 }, + { 8, 10, 14, 17, 18, 20 }, + { 20, 17, 18, 19 }, +}; +HPRef_Struct reftet_3ea_2v = +{ + HP_TET, + reftet_3ea_2v_splitedges, + reftet_3ea_2v_splitfaces, + reftet_3ea_2v_splitelements, + reftet_3ea_2v_newelstypes, + reftet_3ea_2v_newels +}; + + + + + + + + +// HP_TET_3EA_3V, +int reftet_3ea_3v_splitedges[][3] = +{ + { 1, 2, 5 }, + { 1, 3, 6 }, + { 1, 4, 7 }, + { 2, 3, 8 }, + { 2, 4, 9 }, + { 3, 2, 10 }, + { 3, 4, 11 }, + { 4, 2, 12 }, + { 4, 3, 13 }, + { 2, 1, 21 }, + { 3, 1, 22 }, + { 4, 1, 23 }, + { 0, 0, 0 } +}; +int reftet_3ea_3v_splitfaces[][4] = + { + { 1, 2, 3, 14 }, + { 1, 2, 4, 15 }, + { 1, 3, 4, 16 }, + { 2, 3, 4, 17 }, + { 3, 4, 2, 18 }, + { 4, 2, 3, 19 }, + { 0, 0, 0, 0 } + }; +int reftet_3ea_3v_splitelements[][5] = + { + { 1, 2, 3, 4, 20 }, + { 0 }, + }; + +HPREF_ELEMENT_TYPE reftet_3ea_3v_newelstypes[] = + { + HP_HEX_3E_0V, + HP_TET_1E_1VA, + HP_PRISM_SINGEDGE, + HP_PRISM, + HP_TET_1E_1VA, + HP_PRISM_SINGEDGE, + HP_PRISM, + HP_TET_1E_1VA, + HP_PRISM_SINGEDGE, + HP_PRISM, + + HP_PRISM, + HP_PRISM, + HP_PRISM, + HP_TET, + HP_NONE, + }; +int reftet_3ea_3v_newels[][8] = +{ + { 1, 5, 14, 6, 7, 15, 20, 16 }, + + { 2, 21, 9, 8 }, + { 5, 14, 15, 21, 8, 9 }, + { 15, 14, 20, 9, 8, 17 }, + { 3, 22, 10, 11 }, + { 6, 16, 14, 22, 11, 10 }, + { 14, 16, 20, 10, 11, 18 }, + { 4, 23, 13, 12 }, + { 7, 15, 16, 23, 12, 13 }, + { 16, 15, 20, 13, 12, 19 }, + + { 11, 13, 16, 18, 19, 20 }, + { 15, 12, 9, 20, 19, 17 }, + { 8, 10, 14, 17, 18, 20 }, + { 20, 17, 18, 19 }, +}; +HPRef_Struct reftet_3ea_3v = +{ + HP_TET, + reftet_3ea_3v_splitedges, + reftet_3ea_3v_splitfaces, + reftet_3ea_3v_splitelements, + reftet_3ea_3v_newelstypes, + reftet_3ea_3v_newels +}; + + + + + + + +// HP_TET_3EV_0V, +int reftet_3eb_0v_splitedges[][3] = +{ + { 1, 2, 5 }, + { 1, 3, 6 }, + { 1, 4, 7 }, + { 2, 1, 8 }, + { 2, 3, 9 }, + { 2, 4, 10 }, + { 3, 1, 11 }, + // { 3, 2, 12 }, + { 3, 4, 13 }, + // { 4, 1, 14 }, + { 4, 2, 15 }, + { 4, 3, 16 }, + { 0, 0, 0 } +}; +int reftet_3eb_0v_splitfaces[][4] = + { + { 1, 2, 4, 17 }, + { 2, 1, 3, 18 }, + { 0, 0, 0, 0 } + }; +int reftet_3eb_0v_splitelements[][5] = + { + { 1, 2, 3, 4, 20 }, + { 0 }, + }; + +HPREF_ELEMENT_TYPE reftet_3eb_0v_newelstypes[] = + { + HP_PYRAMID_EDGES, + HP_PYRAMID_EDGES, + // HP_TET_1E_1VA, + // HP_TET_1E_1VA, + HP_PRISM_SINGEDGE, + HP_PRISM_SINGEDGE, + HP_PRISM_SINGEDGE, + + HP_PYRAMID, + HP_PYRAMID, + HP_TET, + HP_TET, + HP_PYRAMID, + HP_PYRAMID, + HP_PYRAMID, + HP_NONE, + }; +int reftet_3eb_0v_newels[][8] = +{ + { 1, 7, 17, 5, 6 }, + { 2, 9, 18, 8, 10 }, + // { 3, 12, 13, 11 }, + // { 4, 14, 16, 15 }, + { 5, 6, 17, 8, 18, 10 }, + { 7, 17, 6, 4, 15, 16 }, + { 9, 18, 10, 3, 11, 13 }, + + { 10, 15, 16, 13, 20 }, + { 6, 11, 13, 16, 20 }, + { 10, 17, 15, 20 }, + { 6, 18, 11, 20 }, + { 6, 17, 10, 18, 20 }, + { 6, 16, 15, 17, 20 }, + { 18, 10, 13, 11, 20 }, +}; +HPRef_Struct reftet_3eb_0v = +{ + HP_TET, + reftet_3eb_0v_splitedges, + reftet_3eb_0v_splitfaces, + reftet_3eb_0v_splitelements, + reftet_3eb_0v_newelstypes, + reftet_3eb_0v_newels +}; + + + + + + + + + +// HP_TET_3EV_1V, +int reftet_3eb_1v_splitedges[][3] = +{ + { 1, 2, 5 }, + { 1, 3, 6 }, + { 1, 4, 7 }, + { 2, 1, 8 }, + { 2, 3, 9 }, + { 2, 4, 10 }, + { 3, 1, 11 }, + { 3, 2, 12 }, + { 3, 4, 13 }, + // { 4, 1, 14 }, + { 4, 2, 15 }, + { 4, 3, 16 }, + { 0, 0, 0 } +}; +int reftet_3eb_1v_splitfaces[][4] = + { + { 1, 2, 4, 17 }, + { 2, 1, 3, 18 }, + { 0, 0, 0, 0 } + }; +int reftet_3eb_1v_splitelements[][5] = + { + { 1, 2, 3, 4, 20 }, + { 0 }, + }; + +HPREF_ELEMENT_TYPE reftet_3eb_1v_newelstypes[] = + { + HP_PYRAMID_EDGES, + HP_PYRAMID_EDGES, + HP_TET_1E_1VA, + // HP_TET_1E_1VA, + HP_PRISM_SINGEDGE, + HP_PRISM_SINGEDGE, + HP_PRISM_SINGEDGE, + + HP_PYRAMID, + HP_PYRAMID, + HP_TET, + HP_TET, + HP_PYRAMID, + HP_PYRAMID, + HP_PYRAMID, + HP_NONE, + }; +int reftet_3eb_1v_newels[][8] = +{ + { 1, 7, 17, 5, 6 }, + { 2, 9, 18, 8, 10 }, + { 3, 12, 13, 11 }, + // { 4, 14, 16, 15 }, + { 5, 6, 17, 8, 18, 10 }, + { 7, 17, 6, 4, 15, 16 }, + { 9, 18, 10, 12, 11, 13 }, + + { 10, 15, 16, 13, 20 }, + { 6, 11, 13, 16, 20 }, + { 10, 17, 15, 20 }, + { 6, 18, 11, 20 }, + { 6, 17, 10, 18, 20 }, + { 6, 16, 15, 17, 20 }, + { 18, 10, 13, 11, 20 }, +}; +HPRef_Struct reftet_3eb_1v = +{ + HP_TET, + reftet_3eb_1v_splitedges, + reftet_3eb_1v_splitfaces, + reftet_3eb_1v_splitelements, + reftet_3eb_1v_newelstypes, + reftet_3eb_1v_newels +}; + + + + + + + + +// HP_TET_3EV_2V, +int reftet_3eb_2v_splitedges[][3] = +{ + { 1, 2, 5 }, + { 1, 3, 6 }, + { 1, 4, 7 }, + { 2, 1, 8 }, + { 2, 3, 9 }, + { 2, 4, 10 }, + { 3, 1, 11 }, + { 3, 2, 12 }, + { 3, 4, 13 }, + { 4, 1, 14 }, + { 4, 2, 15 }, + { 4, 3, 16 }, + { 0, 0, 0 } +}; +int reftet_3eb_2v_splitfaces[][4] = + { + { 1, 2, 4, 17 }, + { 2, 1, 3, 18 }, + { 0, 0, 0, 0 } + }; +int reftet_3eb_2v_splitelements[][5] = + { + { 1, 2, 3, 4, 20 }, + { 0 }, + }; + +HPREF_ELEMENT_TYPE reftet_3eb_2v_newelstypes[] = + { + HP_PYRAMID_EDGES, + HP_PYRAMID_EDGES, + HP_TET_1E_1VA, + HP_TET_1E_1VA, + HP_PRISM_SINGEDGE, + HP_PRISM_SINGEDGE, + HP_PRISM_SINGEDGE, + + HP_PYRAMID, + HP_PYRAMID, + HP_TET, + HP_TET, + HP_PYRAMID, + HP_PYRAMID, + HP_PYRAMID, + HP_NONE, + }; +int reftet_3eb_2v_newels[][8] = +{ + { 1, 7, 17, 5, 6 }, + { 2, 9, 18, 8, 10 }, + { 3, 12, 13, 11 }, + { 4, 14, 16, 15 }, + { 5, 6, 17, 8, 18, 10 }, + { 7, 17, 6, 14, 15, 16 }, + { 9, 18, 10, 12, 11, 13 }, + + { 10, 15, 16, 13, 20 }, + { 6, 11, 13, 16, 20 }, + { 10, 17, 15, 20 }, + { 6, 18, 11, 20 }, + { 6, 17, 10, 18, 20 }, + { 6, 16, 15, 17, 20 }, + { 18, 10, 13, 11, 20 }, +}; +HPRef_Struct reftet_3eb_2v = +{ + HP_TET, + reftet_3eb_2v_splitedges, + reftet_3eb_2v_splitfaces, + reftet_3eb_2v_splitelements, + reftet_3eb_2v_newelstypes, + reftet_3eb_2v_newels +}; + + + + + + + + + + + + + +// HP_TET_3EC_0V, +int reftet_3ec_0v_splitedges[][3] = +{ + { 1, 2, 5 }, + { 1, 3, 6 }, + { 1, 4, 7 }, + { 2, 1, 8 }, + { 2, 3, 9 }, + { 2, 4, 10 }, + // { 3, 1, 11 }, + { 3, 2, 12 }, + { 3, 4, 13 }, + { 4, 1, 14 }, + // { 4, 2, 15 }, + { 4, 3, 16 }, + { 0, 0, 0 } +}; +int reftet_3ec_0v_splitfaces[][4] = + { + { 1, 2, 3, 17 }, + { 2, 1, 4, 18 }, + { 0, 0, 0, 0 } + }; +int reftet_3ec_0v_splitelements[][5] = + { + { 1, 2, 3, 4, 20 }, + { 0 }, + }; + +HPREF_ELEMENT_TYPE reftet_3ec_0v_newelstypes[] = + { + HP_PYRAMID_EDGES, + HP_PYRAMID_EDGES, + // HP_TET_1E_1VA, + // HP_TET_1E_1VA, + HP_PRISM_SINGEDGE, + HP_PRISM_SINGEDGE, + HP_PRISM_SINGEDGE, + + HP_PYRAMID, + HP_PYRAMID, + HP_TET, + HP_TET, + HP_PYRAMID, + HP_PYRAMID, + HP_PYRAMID, + HP_NONE, + }; +int reftet_3ec_0v_newels[][8] = +{ + { 1, 5, 17, 6, 7 }, + { 2, 8, 18, 10, 9 }, + // { 3, 11, 12, 13 }, + // { 4, 15, 14, 16 }, + { 5, 17, 7, 8, 9, 18 }, + { 6, 7, 17, 3, 13, 12 }, + { 10, 9, 18, 4, 16, 14 }, + + { 9, 16, 13, 12, 20 }, + { 7, 13, 16, 14, 20 }, + { 7, 14, 18, 20 }, + { 9, 12, 17, 20 }, + { 17, 7, 18, 9, 20 }, + { 7, 17, 12, 13, 20 }, + { 9, 18, 14, 16, 20 }, +}; +HPRef_Struct reftet_3ec_0v = +{ + HP_TET, + reftet_3ec_0v_splitedges, + reftet_3ec_0v_splitfaces, + reftet_3ec_0v_splitelements, + reftet_3ec_0v_newelstypes, + reftet_3ec_0v_newels +}; + + + + + + + + + +// HP_TET_3EC_1V, +int reftet_3ec_1v_splitedges[][3] = +{ + { 1, 2, 5 }, + { 1, 3, 6 }, + { 1, 4, 7 }, + { 2, 1, 8 }, + { 2, 3, 9 }, + { 2, 4, 10 }, + { 3, 1, 11 }, + { 3, 2, 12 }, + { 3, 4, 13 }, + { 4, 1, 14 }, + // { 4, 2, 15 }, + { 4, 3, 16 }, + { 0, 0, 0 } +}; +int reftet_3ec_1v_splitfaces[][4] = + { + { 1, 2, 3, 17 }, + { 2, 1, 4, 18 }, + { 0, 0, 0, 0 } + }; +int reftet_3ec_1v_splitelements[][5] = + { + { 1, 2, 3, 4, 20 }, + { 0 }, + }; + +HPREF_ELEMENT_TYPE reftet_3ec_1v_newelstypes[] = + { + HP_PYRAMID_EDGES, + HP_PYRAMID_EDGES, + HP_TET_1E_1VA, + // HP_TET_1E_1VA, + HP_PRISM_SINGEDGE, + HP_PRISM_SINGEDGE, + HP_PRISM_SINGEDGE, + + HP_PYRAMID, + HP_PYRAMID, + HP_TET, + HP_TET, + HP_PYRAMID, + HP_PYRAMID, + HP_PYRAMID, + HP_NONE, + }; +int reftet_3ec_1v_newels[][8] = +{ + { 1, 5, 17, 6, 7 }, + { 2, 8, 18, 10, 9 }, + { 3, 11, 12, 13 }, + // { 4, 15, 14, 16 }, + { 5, 17, 7, 8, 9, 18 }, + { 6, 7, 17, 11, 13, 12 }, + { 10, 9, 18, 4, 16, 14 }, + + { 9, 16, 13, 12, 20 }, + { 7, 13, 16, 14, 20 }, + { 7, 14, 18, 20 }, + { 9, 12, 17, 20 }, + { 17, 7, 18, 9, 20 }, + { 7, 17, 12, 13, 20 }, + { 9, 18, 14, 16, 20 }, +}; +HPRef_Struct reftet_3ec_1v = +{ + HP_TET, + reftet_3ec_1v_splitedges, + reftet_3ec_1v_splitfaces, + reftet_3ec_1v_splitelements, + reftet_3ec_1v_newelstypes, + reftet_3ec_1v_newels +}; + + + + + + + + +// HP_TET_3EC_2V, +int reftet_3ec_2v_splitedges[][3] = +{ + { 1, 2, 5 }, + { 1, 3, 6 }, + { 1, 4, 7 }, + { 2, 1, 8 }, + { 2, 3, 9 }, + { 2, 4, 10 }, + { 3, 1, 11 }, + { 3, 2, 12 }, + { 3, 4, 13 }, + { 4, 1, 14 }, + { 4, 2, 15 }, + { 4, 3, 16 }, + { 0, 0, 0 } +}; +int reftet_3ec_2v_splitfaces[][4] = + { + { 1, 2, 3, 17 }, + { 2, 1, 4, 18 }, + { 0, 0, 0, 0 } + }; +int reftet_3ec_2v_splitelements[][5] = + { + { 1, 2, 3, 4, 20 }, + { 0 }, + }; + +HPREF_ELEMENT_TYPE reftet_3ec_2v_newelstypes[] = + { + HP_PYRAMID_EDGES, + HP_PYRAMID_EDGES, + HP_TET_1E_1VA, + HP_TET_1E_1VA, + HP_PRISM_SINGEDGE, + HP_PRISM_SINGEDGE, + HP_PRISM_SINGEDGE, + + HP_PYRAMID, + HP_PYRAMID, + HP_TET, + HP_TET, + HP_PYRAMID, + HP_PYRAMID, + HP_PYRAMID, + HP_NONE, + }; +int reftet_3ec_2v_newels[][8] = +{ + { 1, 5, 17, 6, 7 }, + { 2, 8, 18, 10, 9 }, + { 3, 11, 12, 13 }, + { 4, 15, 14, 16 }, + { 5, 17, 7, 8, 9, 18 }, + { 6, 7, 17, 11, 13, 12 }, + { 10, 9, 18, 15, 16, 14 }, + + { 9, 16, 13, 12, 20 }, + { 7, 13, 16, 14, 20 }, + { 7, 14, 18, 20 }, + { 9, 12, 17, 20 }, + { 17, 7, 18, 9, 20 }, + { 7, 17, 12, 13, 20 }, + { 9, 18, 14, 16, 20 }, +}; +HPRef_Struct reftet_3ec_2v = +{ + HP_TET, + reftet_3ec_2v_splitedges, + reftet_3ec_2v_splitfaces, + reftet_3ec_2v_splitelements, + reftet_3ec_2v_newelstypes, + reftet_3ec_2v_newels +}; + + + + + + + + + + +/* ************************ 1 singular face ******************** */ + + +// HP_TET_1F_0E_0V +int reftet_1f_0e_0v_splitedges[][3] = +{ + { 2, 1, 5 }, + { 3, 1, 6 }, + { 4, 1, 7 }, + { 0, 0, 0 } +}; +HPREF_ELEMENT_TYPE reftet_1f_0e_0v_newelstypes[] = +{ + HP_PRISM_1FA_0E_0V, + HP_TET, + HP_NONE, +}; +int reftet_1f_0e_0v_newels[][8] = +{ + { 3, 2, 4, 6, 5, 7 }, + { 5, 7, 6, 1 } +}; +HPRef_Struct reftet_1f_0e_0v = +{ + HP_TET, + reftet_1f_0e_0v_splitedges, + 0, 0, + reftet_1f_0e_0v_newelstypes, + reftet_1f_0e_0v_newels +}; + + + + + +// HP_TET_1F_0E_1VA ... singular vertex in face +int reftet_1f_0e_1va_splitedges[][3] = +{ + { 2, 1, 5 }, + { 2, 3, 6 }, + { 2, 4, 7 }, + { 3, 1, 8 }, + { 4, 1, 9 }, + { 0, 0, 0 } +}; +HPREF_ELEMENT_TYPE reftet_1f_0e_1va_newelstypes[] = +{ + HP_HEX_1F_0E_0V, + HP_TET_1F_0E_1VA, + HP_TET, + HP_NONE, +}; +int reftet_1f_0e_1va_newels[][8] = +{ + { 3, 6, 7, 4, 8, 5, 5, 9 }, + { 5, 2, 6, 7 }, + { 5, 9, 8, 1 }, +}; +HPRef_Struct reftet_1f_0e_1va = +{ + HP_TET, + reftet_1f_0e_1va_splitedges, + 0, 0, + reftet_1f_0e_1va_newelstypes, + reftet_1f_0e_1va_newels +}; + + + + + +// HP_TET_1F_0E_1VB ... singular vertex not in face +int reftet_1f_0e_1vb_splitedges[][3] = +{ + { 1, 2, 5 }, + { 1, 3, 6 }, + { 1, 4, 7 }, + { 2, 1, 8 }, + { 3, 1, 9 }, + { 4, 1, 10 }, + { 0, 0, 0 } +}; +HPREF_ELEMENT_TYPE reftet_1f_0e_1vb_newelstypes[] = +{ + HP_PRISM_1FA_0E_0V, + HP_PRISM, + HP_TET_0E_1V, + HP_NONE, +}; +int reftet_1f_0e_1vb_newels[][8] = +{ + { 2, 4, 3, 8, 10, 9 }, + { 8, 10, 9, 5, 7, 6 }, + { 1, 5, 6, 7 }, +}; +HPRef_Struct reftet_1f_0e_1vb = +{ + HP_TET, + reftet_1f_0e_1vb_splitedges, + 0, 0, + reftet_1f_0e_1vb_newelstypes, + reftet_1f_0e_1vb_newels +}; + + + + + + + + +// HP_TET_1F_1EA_0V ... sing edge is 1..2 +int reftet_1f_1ea_0v_splitedges[][3] = +{ + { 1, 3, 5 }, + { 1, 4, 6 }, + { 2, 1, 7 }, + { 2, 3, 8 }, + { 2, 4, 9 }, + { 3, 1, 10 }, + { 4, 1, 11 }, + { 0, 0, 0 } +}; + +int reftet_1f_1ea_0v_splitfaces[][4] = + { + { 2, 1, 3, 12 }, + { 2, 1, 4, 13 }, + { 0, 0, 0, 0 } + }; + + +HPREF_ELEMENT_TYPE reftet_1f_1ea_0v_newelstypes[] = +{ + HP_HEX_1F_0E_0V, + // HP_PRISM, + HP_PYRAMID_1FB_0E_1VA, + HP_TET_1E_1VA, + HP_PRISM_SINGEDGE, + HP_PRISM, + HP_NONE, +}; +int reftet_1f_1ea_0v_newels[][8] = +{ + { 3, 8, 9, 4, 10, 12, 13, 11 }, + // { 2, 9, 8, 7, 13, 12 }, + { 8, 9, 13, 12, 2 }, + { 2, 7, 13, 12 }, + { 7, 13, 12, 1, 6, 5 }, + { 6, 11, 13, 5, 10, 12 } +}; +HPRef_Struct reftet_1f_1ea_0v = +{ + HP_TET, + reftet_1f_1ea_0v_splitedges, + reftet_1f_1ea_0v_splitfaces, + 0, + reftet_1f_1ea_0v_newelstypes, + reftet_1f_1ea_0v_newels +}; + + + + + + + + +// HP_TET_1F_1EB_0V singular edge in face, edge is 2-3 +int reftet_1f_1eb_0v_splitedges[][3] = +{ + { 2, 1, 5 }, + { 2, 4, 6 }, + { 3, 1, 7 }, + { 3, 4, 8 }, + { 4, 1, 9 }, + { 0, 0, 0 } +}; + + +HPREF_ELEMENT_TYPE reftet_1f_1eb_0v_newelstypes[] = +{ + HP_PRISM_1FB_1EA_0V, + HP_PRISM_1FA_0E_0V, + HP_TET, + HP_NONE, +}; +int reftet_1f_1eb_0v_newels[][8] = +{ + // { 2, 5, 6, 3, 7, 8 }, + { 3, 8, 7, 2, 6, 5 }, + { 6, 4, 8, 5, 9, 7 }, + { 5, 9, 7, 1} +}; +HPRef_Struct reftet_1f_1eb_0v = +{ + HP_TET, + reftet_1f_1eb_0v_splitedges, + 0, 0, + reftet_1f_1eb_0v_newelstypes, + reftet_1f_1eb_0v_newels +}; + + + + + + + + + + +/* ************************ 2 singular faces ******************** */ + + +// HP_TET_2F_0E_0V +int reftet_2f_0e_0v_splitedges[][3] = +{ + { 1, 2, 5 }, + { 2, 1, 6 }, + { 3, 1, 7 }, + { 3, 2, 8 }, + { 4, 1, 9 }, + { 4, 2, 10 }, + { 0, 0, 0 } +}; + +int reftet_2f_0e_0v_splitfaces[][4] = + { + { 3, 1, 2, 11 }, + { 4, 1, 2, 12 }, + { 0, 0, 0, 0 } + }; + + +HPREF_ELEMENT_TYPE reftet_2f_0e_0v_newelstypes[] = +{ + HP_PRISM_1FA_0E_0V, + HP_PRISM_1FA_0E_0V, + HP_PRISM_1FB_1EA_0V, + HP_PRISM_1FB_1EA_0V, + HP_TET, + HP_NONE, +}; +int reftet_2f_0e_0v_newels[][8] = +{ + { 2, 10, 8, 6, 12, 11 }, + { 1, 7, 9, 5, 11, 12 }, + // { 3, 11, 8, 4, 12, 10 }, + { 4, 10, 12, 3, 8, 11 }, + { 3, 7, 11, 4, 9, 12 }, + { 5, 6, 11, 12 } +}; +HPRef_Struct reftet_2f_0e_0v = +{ + HP_TET, + reftet_2f_0e_0v_splitedges, + reftet_2f_0e_0v_splitfaces, + 0, + reftet_2f_0e_0v_newelstypes, + reftet_2f_0e_0v_newels +}; + + diff --git a/contrib/Netgen/libsrc/meshing/hpref_trig.hpp b/contrib/Netgen/libsrc/meshing/hpref_trig.hpp new file mode 100644 index 0000000000..6e2ede0eb0 --- /dev/null +++ b/contrib/Netgen/libsrc/meshing/hpref_trig.hpp @@ -0,0 +1,750 @@ + + + + + +// 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 +}; + + diff --git a/contrib/Netgen/libsrc/meshing/hprefinement.cpp b/contrib/Netgen/libsrc/meshing/hprefinement.cpp new file mode 100644 index 0000000000..6a63e87675 --- /dev/null +++ b/contrib/Netgen/libsrc/meshing/hprefinement.cpp @@ -0,0 +1,2605 @@ +#include <mystdlib.h> +#include "meshing.hpp" + + + + +namespace netgen +{ + + + // 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 + }; + + + + + + +#include "hpref_trig.hpp" +#include "hpref_quad.hpp" +#include "hpref_tet.hpp" +#include "hpref_prism.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, 6 } + }; + HPRef_Struct refpyramid = + { + HP_PYRAMID, + refpyramid_splitedges, + 0, 0, + refpyramid_newelstypes, + refpyramid_newels + }; + + + + // HP_PYRAMID_0E_1V + int refpyramid_0e_1v_splitedges[][3] = + { + { 0, 0, 0 } + }; + HPREF_ELEMENT_TYPE refpyramid_0e_1v_newelstypes[] = + { + HP_TET_0E_1V, + HP_TET, + HP_NONE, + }; + int refpyramid_0e_1v_newels[][8] = + { + { 1, 2, 4, 5 }, + { 2, 3, 4, 5 }, + }; + HPRef_Struct refpyramid_0e_1v = + { + HP_PYRAMID, + refpyramid_0e_1v_splitedges, + 0, 0, + refpyramid_0e_1v_newelstypes, + refpyramid_0e_1v_newels + }; + + + + // HP_PYRAMID_EDGES + int refpyramid_edges_splitedges[][3] = + { + { 0, 0, 0 } + }; + HPREF_ELEMENT_TYPE refpyramid_edges_newelstypes[] = + { + HP_TET_1E_1VA, + HP_TET_1E_1VA, + HP_NONE, + }; + int refpyramid_edges_newels[][8] = + { + { 1, 2, 3, 5 }, + { 1, 4, 5, 3 }, + }; + HPRef_Struct refpyramid_edges = + { + HP_PYRAMID, + refpyramid_edges_splitedges, + 0, 0, + refpyramid_edges_newelstypes, + refpyramid_edges_newels + }; + + + + + // HP_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 + }; + + + + + + + + // HP_HEX + int refhex_splitedges[][3] = + { + { 0, 0, 0 } + }; + HPREF_ELEMENT_TYPE refhex_newelstypes[] = + { + HP_HEX, + HP_NONE, + }; + int refhex_newels[][8] = + { + { 1, 2, 3, 4, 5, 6, 7, 8 } + }; + HPRef_Struct refhex = + { + HP_HEX, + refhex_splitedges, + 0, 0, + refhex_newelstypes, + refhex_newels + }; + + + + + // HP_HEX_0E_1V + int refhex_0e_1v_splitedges[][3] = + { + { 0, 0, 0 } + }; + HPREF_ELEMENT_TYPE refhex_0e_1v_newelstypes[] = + { + HP_TET_0E_1V, + HP_TET, + HP_TET, + HP_TET, + HP_TET, + HP_TET, + HP_NONE, + }; + int refhex_0e_1v_newels[][8] = + { + { 1, 5, 2, 4 }, + { 7, 3, 6, 8 }, + { 2, 8, 5, 6 }, + { 2, 8, 6, 3 }, + { 2, 8, 3, 4 }, + { 2, 8, 4, 5 }, + }; + HPRef_Struct refhex_0e_1v = + { + HP_HEX, + refhex_0e_1v_splitedges, + 0, 0, + refhex_0e_1v_newelstypes, + refhex_0e_1v_newels + }; + + + + + // HP_HEX_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 + }; + + + + // HP_HEX_3E_0V + int refhex_3e_0v_splitedges[][3] = + { + { 0, 0, 0 } + }; + HPREF_ELEMENT_TYPE refhex_3e_0v_newelstypes[] = + { + HP_TET_1E_1VA, + HP_TET_1E_1VA, + HP_TET_1E_1VA, + HP_TET_0E_1V, + HP_TET, + HP_NONE, + }; + int refhex_3e_0v_newels[][8] = + { + { 1, 2, 3, 6 }, + { 1, 4, 8, 3 }, + { 1, 5, 6, 8 }, + { 1, 6, 3, 8 }, + { 3, 8, 6, 7 }, + }; + HPRef_Struct refhex_3e_0v = + { + HP_HEX, + refhex_3e_0v_splitedges, + 0, 0, + refhex_3e_0v_newelstypes, + refhex_3e_0v_newels + }; + + + + + // HP_HEX_1E_0V + int refhex_1e_0v_splitedges[][3] = + { + { 0, 0, 0 } + }; + + HPREF_ELEMENT_TYPE refhex_1e_0v_newelstypes[] = + { + HP_PRISM_SINGEDGE, + HP_PRISM, + HP_NONE, + }; + int refhex_1e_0v_newels[][8] = + { + { 1, 4, 5, 2, 3, 6 }, + { 5, 4, 8, 6, 3, 7 }, + }; + HPRef_Struct refhex_1e_0v = + { + HP_HEX, + refhex_1e_0v_splitedges, + 0, 0, + refhex_1e_0v_newelstypes, + refhex_1e_0v_newels + }; + + + + + + // HP_HEX_1F_0E_0V + 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_1F_0E_0V, + HP_HEX, + HP_NONE, + }; + int refhex_1f_0e_0v_newels[][8] = + { + { 1, 2, 3, 4, 9, 10, 11, 12 }, + { 9, 10, 11, 12, 5, 6, 7, 8 } + }; + 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 + }; + + + + + + + + HPRef_Struct * Get_HPRef_Struct (HPREF_ELEMENT_TYPE type) + { + HPRef_Struct * hps = NULL; + + switch (type) + { + case HP_SEGM: + hps = &refsegm; break; + case HP_SEGM_SINGCORNERL: + hps = &refsegm_scl; break; + case HP_SEGM_SINGCORNERR: + hps = &refsegm_scr; break; + case HP_SEGM_SINGCORNERS: + hps = &refsegm_sc2; break; + + case HP_TRIG: + hps = &reftrig; break; + case HP_TRIG_SINGCORNER: + hps = &reftrig_singcorner; break; + case HP_TRIG_SINGCORNER12: + hps = &reftrig_singcorner12; break; + case HP_TRIG_SINGCORNER123: + hps = &reftrig_singcorner123; break; + case HP_TRIG_SINGCORNER123_2D: + hps = &reftrig_singcorner123_2D; break; + case HP_TRIG_SINGEDGE: + hps = &reftrig_singedge; break; + case HP_TRIG_SINGEDGECORNER1: + hps = &reftrig_singedgecorner1; break; + case HP_TRIG_SINGEDGECORNER2: + hps = &reftrig_singedgecorner2; break; + case HP_TRIG_SINGEDGECORNER12: + hps = &reftrig_singedgecorner12; break; + case HP_TRIG_SINGEDGECORNER3: + hps = &reftrig_singedgecorner3; break; + case HP_TRIG_SINGEDGECORNER13: + hps = &reftrig_singedgecorner13; break; + case HP_TRIG_SINGEDGECORNER23: + hps = &reftrig_singedgecorner23; break; + case HP_TRIG_SINGEDGECORNER123: + hps = &reftrig_singedgecorner123; break; + case HP_TRIG_SINGEDGES: + hps = &reftrig_singedges; break; + case HP_TRIG_SINGEDGES2: + hps = &reftrig_singedges2; break; + case HP_TRIG_SINGEDGES3: + hps = &reftrig_singedges3; break; + case HP_TRIG_SINGEDGES23: + hps = &reftrig_singedges23; break; + case HP_QUAD: + hps = &refquad; break; + case HP_DUMMY_QUAD_SINGCORNER: + hps = &refdummyquad_singcorner; break; + case HP_QUAD_SINGCORNER: + hps = &refquad_singcorner; break; + case HP_QUAD_SINGEDGE: + hps = &refquad_singedge; break; + + case HP_QUAD_0E_2VA: + hps = &refquad_0e_2va; break; + case HP_QUAD_0E_2VB: + hps = &refquad_0e_2vb; break; + + case HP_QUAD_0E_3V: + hps = &refquad_0e_3v; break; + case HP_QUAD_0E_4V: + hps = &refquad_0e_4v; break; + + case HP_QUAD_1E_1VA: + hps = &refquad_1e_1va; break; + case HP_QUAD_1E_1VB: + hps = &refquad_1e_1vb; break; + case HP_QUAD_1E_1VC: + hps = &refquad_1e_1vc; break; + case HP_QUAD_1E_1VD: + hps = &refquad_1e_1vd; break; + + case HP_QUAD_1E_2VA: + hps = &refquad_1e_2va; break; + case HP_QUAD_1E_2VB: + hps = &refquad_1e_2vb; break; + case HP_QUAD_1E_2VC: + hps = &refquad_1e_2vc; break; + case HP_QUAD_1E_2VD: + hps = &refquad_1e_2vd; break; + case HP_QUAD_1E_2VE: + hps = &refquad_1e_2ve; break; + case HP_QUAD_1E_2VF: + hps = &refquad_1e_2vf; break; + + case HP_QUAD_1E_3VA: + hps = &refquad_1e_3va; break; + case HP_QUAD_1E_3VB: + hps = &refquad_1e_3vb; break; + case HP_QUAD_1E_3VC: + hps = &refquad_1e_3vc; break; + case HP_QUAD_1E_3VD: + hps = &refquad_1e_3vd; break; + case HP_QUAD_1E_4V: + hps = &refquad_1e_4v; break; + + + case HP_QUAD_2E: + hps = &refquad_2e; break; + case HP_QUAD_2E_1VA: + hps = &refquad_2e_1va; break; + case HP_QUAD_2E_1VB: + hps = &refquad_2e_1vb; break; + case HP_QUAD_2E_1VC: + hps = &refquad_2e_1vc; break; + case HP_QUAD_2E_2VA: + hps = &refquad_2e_2va; break; + case HP_QUAD_2E_2VB: + hps = &refquad_2e_2vb; break; + case HP_QUAD_2E_2VC: + hps = &refquad_2e_2vc; break; + case HP_QUAD_2E_3V: + hps = &refquad_2e_3v; break; + + case HP_QUAD_2EB_0V: + hps = &refquad_2eb_0v; break; + + case HP_QUAD_2EB_1VA: + hps = &refquad_2eb_1va; break; + case HP_QUAD_2EB_1VB: + hps = &refquad_2eb_1vb; break; + + + case HP_QUAD_2EB_2VA: + hps = &refquad_2eb_2va; break; + case HP_QUAD_2EB_2VB: + hps = &refquad_2eb_2vb; break; + case HP_QUAD_2EB_2VC: + hps = &refquad_2eb_2vc; break; + case HP_QUAD_2EB_2VD: + hps = &refquad_2eb_2vd; break; + + case HP_QUAD_2EB_3VA: + hps = &refquad_2eb_3va; break; + case HP_QUAD_2EB_3VB: + hps = &refquad_2eb_3vb; break; + + case HP_QUAD_2EB_4V: + hps = &refquad_2eb_4v; break; + + case HP_QUAD_3E: + hps = &refquad_3e; break; + case HP_QUAD_3E_3VA: + hps = &refquad_3e_3va; break; + case HP_QUAD_3E_3VB: + hps = &refquad_3e_3vb; break; + case HP_QUAD_3E_4V: + hps = &refquad_3e_4v; break; + + + case HP_QUAD_4E: + hps = &refquad_4e; break; + + + case HP_TET: + hps = &reftet; break; + case HP_TET_0E_1V: + hps = &reftet_0e_1v; break; + case HP_TET_0E_2V: + hps = &reftet_0e_2v; break; + case HP_TET_0E_3V: + hps = &reftet_0e_3v; break; + case HP_TET_0E_4V: + hps = &reftet_0e_4v; break; + + case HP_TET_1E_0V: + hps = &reftet_1e_0v; break; + case HP_TET_1E_1VA: + hps = &reftet_1e_1va; break; + case HP_TET_1E_1VB: + hps = &reftet_1e_1vb; break; + + case HP_TET_1E_2VA: + hps = &reftet_1e_2va; break; + case HP_TET_1E_2VB: + hps = &reftet_1e_2vb; break; + case HP_TET_1E_2VC: + hps = &reftet_1e_2vc; break; + case HP_TET_1E_2VD: + hps = &reftet_1e_2vd; break; + + case HP_TET_1E_3VA: + hps = &reftet_1e_3va; break; + case HP_TET_1E_3VB: + hps = &reftet_1e_3vb; break; + case HP_TET_1E_4V: + hps = &reftet_1e_4v; break; + + case HP_TET_2EA_0V: + hps = &reftet_2ea_0v; break; + case HP_TET_2EA_1VB: + hps = &reftet_2ea_1vb; break; + case HP_TET_2EA_1VC: + hps = &reftet_2ea_1vc; break; + case HP_TET_2EA_1VA: + hps = &reftet_2ea_1va; break; + case HP_TET_2EA_2VA: + hps = &reftet_2ea_2va; break; + case HP_TET_2EA_2VB: + hps = &reftet_2ea_2vb; break; + case HP_TET_2EA_2VC: + hps = &reftet_2ea_2vc; break; + case HP_TET_2EA_3V: + hps = &reftet_2ea_3v; break; + + case HP_TET_2EB_0V: + hps = &reftet_2eb_0v; break; + case HP_TET_2EB_2VA: + hps = &reftet_2eb_2va; break; + case HP_TET_2EB_4V: + hps = &reftet_2eb_4v; break; + + + case HP_TET_3EA_0V: + hps = &reftet_3ea_0v; break; + case HP_TET_3EA_1V: + hps = &reftet_3ea_1v; break; + case HP_TET_3EA_2V: + hps = &reftet_3ea_2v; break; + case HP_TET_3EA_3V: + hps = &reftet_3ea_3v; break; + + case HP_TET_3EB_0V: + hps = &reftet_3eb_0v; break; + case HP_TET_3EB_1V: + hps = &reftet_3eb_1v; break; + case HP_TET_3EB_2V: + hps = &reftet_3eb_2v; break; + case HP_TET_3EC_0V: + hps = &reftet_3ec_0v; break; + case HP_TET_3EC_1V: + hps = &reftet_3ec_1v; break; + case HP_TET_3EC_2V: + hps = &reftet_3ec_2v; break; + + + case HP_TET_1F_0E_0V: + hps = &reftet_1f_0e_0v; break; + case HP_TET_1F_0E_1VA: + hps = &reftet_1f_0e_1va; break; + case HP_TET_1F_0E_1VB: + hps = &reftet_1f_0e_1vb; break; + case HP_TET_1F_1EA_0V: + hps = &reftet_1f_1ea_0v; break; + case HP_TET_1F_1EB_0V: + hps = &reftet_1f_1eb_0v; break; + case HP_TET_2F_0E_0V: + hps = &reftet_2f_0e_0v; break; + + + case HP_PRISM: + hps = &refprism; break; + case HP_PRISM_SINGEDGE: + hps = &refprism_singedge; break; + case HP_PRISM_SINGEDGE_H1: + hps = &refprism_singedge_h1; break; + case HP_PRISM_SINGEDGE_H12: + hps = &refprism_singedge_h12; break; + case HP_PRISM_SINGEDGE_V12: + hps = &refprism_singedge_v12; break; + + case HP_PRISM_1FA_0E_0V: + hps = &refprism_1fa_0e_0v; break; + case HP_PRISM_1FB_0E_0V: + hps = &refprism_1fb_0e_0v; break; + case HP_PRISM_1FB_1EA_0V: + hps = &refprism_1fb_1ea_0v; break; + + case HP_PYRAMID: + hps = &refpyramid; break; + case HP_PYRAMID_0E_1V: + hps = &refpyramid_0e_1v; break; + case HP_PYRAMID_EDGES: + hps = &refpyramid_edges; break; + case HP_PYRAMID_1FB_0E_1VA: + hps = &refpyramid_1fb_0e_1va; break; + case HP_HEX: + hps = &refhex; break; + case HP_HEX_0E_1V: + hps = &refhex_0e_1v; break; + case HP_HEX_1E_1V: + hps = &refhex_1e_1v; break; + case HP_HEX_1E_0V: + hps = &refhex_1e_0v; break; + case HP_HEX_3E_0V: + hps = &refhex_3e_0v; break; + + case HP_HEX_1F_0E_0V: + hps = &refhex_1f_0e_0v; break; + } + + if (!hps) + { + PrintSysError ("hp-refinement not implemented for case ", type); + } + + return hps; + } + + + /* *********************** PrepareElements ****************************** */ + + // Elements (volume, surface, edges) are classified by singular vertices, edges, faces + + + void PrepareElements (Mesh & mesh, ARRAY<HPRefElement> & elements) + { + INDEX_2_HASHTABLE<int> edges(mesh.GetNSeg()+1); + BitArray edgepoint(mesh.GetNP()); + INDEX_2_HASHTABLE<int> edgepoint_dom(mesh.GetNSeg()+1); + + edgepoint.Clear(); + BitArray cornerpoint(mesh.GetNP()); + cornerpoint.Clear(); + + + // value = nr > 0 ... refine elements in domain nr + // value = -1 ..... refine elements in any domain + INDEX_3_HASHTABLE<int> faces(mesh.GetNSE()+1); + INDEX_2_HASHTABLE<int> face_edges(mesh.GetNSE()+1); + ARRAY<int, PointIndex::BASE> facepoint(mesh.GetNP()); + + if (mesh.GetDimension() == 3) + { + /* + // check, if point has as least 3 different surfs: + + ARRAY<INDEX_3, PointIndex::BASE> surfonpoint(mesh.GetNP()); + surfonpoint = INDEX_3(0,0,0); + + for (SurfaceElementIndex sei = 0; sei < mesh.GetNSE(); sei++) + { + const Element2d & el = mesh[sei]; + int ind = el.GetIndex(); + for (int j = 0; j < el.GetNP(); j++) + { + INDEX_3 & i3 = surfonpoint[el[j]]; + if (ind != i3.I1() && ind != i3.I2() && ind != i3.I3()) + { + i3.I1() = i3.I2(); + i3.I2() = i3.I3(); + i3.I3() = ind; + } + } + } + for (int i = 1; i <= mesh.GetNP(); i++) + if (surfonpoint.Get(i).I1()) + cornerpoint.Set(i); + */ + cornerpoint.Clear(); + + for (int i = 1; i <= mesh.GetNP(); i++) + { + if (mesh.Point(i).IsSingular()) + cornerpoint.Set(i); + } + + + for (int i = 1; i <= mesh.GetNSeg(); i++) + if (mesh.LineSegment(i).singedge_left) + { + INDEX_2 i2 (mesh.LineSegment(i).p1, + mesh.LineSegment(i).p2); + i2.Sort(); + + edges.Set (i2, 1); + INDEX_2 i2s(i2.I2(), i2.I1()); + edges.Set (i2s, 1); + + edgepoint.Set (i2.I1()); + edgepoint.Set (i2.I2()); + } + + + // if 2 adjacent edges of an element are singular, the + // commen point must be a singular point + for (int i = 1; i <= mesh.GetNE(); i++) + { + const Element & el = mesh.VolumeElement(i); + const ELEMENT_EDGE * eledges = MeshTopology::GetEdges (el.GetType()); + int nedges = MeshTopology::GetNEdges (el.GetType()); + for (int j = 0; j < nedges; j++) + for (int k = 0; k < nedges; k++) + if (j != k) + { + INDEX_2 ej(el.PNum(eledges[j][0]), el.PNum(eledges[j][1])); + ej.Sort(); + INDEX_2 ek(el.PNum(eledges[k][0]), el.PNum(eledges[k][1])); + ek.Sort(); + if (edges.Used(ej) && edges.Used(ek)) + { + if (ej.I1() == ek.I1()) cornerpoint.Set (ek.I1()); + if (ej.I1() == ek.I2()) cornerpoint.Set (ek.I2()); + if (ej.I2() == ek.I1()) cornerpoint.Set (ek.I1()); + if (ej.I2() == ek.I2()) cornerpoint.Set (ek.I2()); + } + } + } + + + edgepoint.Or (cornerpoint); + + (*testout) << "cornerpoint = " << endl << cornerpoint << endl; + (*testout) << "edgepoint = " << endl << edgepoint << endl; + + facepoint = 0; + for (SurfaceElementIndex sei = 0; sei < mesh.GetNSE(); sei++) + { + const Element2d & el = mesh[sei]; + const FaceDescriptor & fd = mesh.GetFaceDescriptor (el.GetIndex()); + + if (!fd.domin_singular && !fd.domout_singular) continue; + int domnr; + if (fd.domin_singular) domnr = fd.DomainIn(); + if (fd.domout_singular) domnr = fd.DomainOut(); + if (fd.domin_singular && fd.domout_singular) domnr = -1; + + + faces.Set (INDEX_3::Sort (el[0], el[1], el[2]), domnr); + face_edges.Set (INDEX_2::Sort (el[0], el[1]), domnr); + face_edges.Set (INDEX_2::Sort (el[0], el[2]), domnr); + face_edges.Set (INDEX_2::Sort (el[2], el[1]), domnr); + facepoint[el[0]] = domnr; + facepoint[el[1]] = domnr; + facepoint[el[2]] = domnr; + } + + } + else + { + // 2D case + + // check, if point has as least 3 different surfs: + ARRAY<INDEX_3, PointIndex::BASE> surfonpoint(mesh.GetNP()); + + for (int i = 1; i <= mesh.GetNP(); i++) + surfonpoint.Elem(i) = INDEX_3(0,0,0); + + for (int i = 1; i <= mesh.GetNSeg(); i++) + { + const Segment & seg = mesh.LineSegment(i); + int ind = seg.edgenr; + + if (seg.singedge_left) + { + INDEX_2 i2 (mesh.LineSegment(i).p1, + mesh.LineSegment(i).p2); + edges.Set (i2, 1); + edgepoint.Set(i2.I1()); + edgepoint.Set(i2.I2()); + + edgepoint_dom.Set (INDEX_2(mesh.LineSegment(i).domin, i2.I1()), 1); + edgepoint_dom.Set (INDEX_2(mesh.LineSegment(i).domin, i2.I2()), 1); + } + if (seg.singedge_right) + { + INDEX_2 i2 (mesh.LineSegment(i).p2, + mesh.LineSegment(i).p1); + edges.Set (i2, 1); + edgepoint.Set(i2.I1()); + edgepoint.Set(i2.I2()); + + edgepoint_dom.Set (INDEX_2(mesh.LineSegment(i).domout, i2.I1()), 1); + edgepoint_dom.Set (INDEX_2(mesh.LineSegment(i).domout, i2.I2()), 1); + } + // (*testout) << "seg = " << ind << ", " << seg.p1 << "-" << seg.p2 << endl; + + + if (seg.singedge_left || seg.singedge_right) + { + for (int j = 0; j < 2; j++) + { + int pi = (j == 0) ? seg.p1 : seg.p2; + 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); + edgepoint.Set(i); + } + + // mark points for refinement that are explicity specified in input file + if (mesh.Point(i).IsSingular()) + { + cornerpoint.Set(i); + edgepoint.Set(i); + } + } + + edgepoint.Or (cornerpoint); + + (*testout) << "cornerpoints: " << endl << cornerpoint << endl + << "edgepoints: " << endl << edgepoint << endl; + } + + + + + int cnt_undef = 0, cnt_nonimplement = 0; + ARRAY<int> misses(10000); + misses = 0; + + for (ElementIndex i = 0; i < mesh.GetNE(); i++) + { + Element & el = mesh[i]; + + HPREF_ELEMENT_TYPE type = HP_NONE; + int pnums[8] = { 0 }; + + + switch (el.GetType()) + { + case TET: + { + int ep1, ep2, ep3, ep4, cp1, cp2, cp3, cp4, fp1, fp2, fp3, fp4; + int isedge1, isedge2, isedge3, isedge4, isedge5, isedge6; + int isfedge1, isfedge2, isfedge3, isfedge4, isfedge5, isfedge6; + int isface1, isface2, isface3, isface4; + + 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[j]); + ep2 = edgepoint.Test (el[k]); + ep3 = edgepoint.Test (el[pi3]); + ep4 = edgepoint.Test (el[pi4]); + + cp1 = cornerpoint.Test (el[j]); + cp2 = cornerpoint.Test (el[k]); + cp3 = cornerpoint.Test (el[pi3]); + cp4 = cornerpoint.Test (el[pi4]); + + isedge1 = edges.Used (INDEX_2::Sort (el[j], el[k])); + isedge2 = edges.Used (INDEX_2::Sort (el[j], el[pi3])); + isedge3 = edges.Used (INDEX_2::Sort (el[j], el[pi4])); + isedge4 = edges.Used (INDEX_2::Sort (el[k], el[pi3])); + isedge5 = edges.Used (INDEX_2::Sort (el[k], el[pi4])); + isedge6 = edges.Used (INDEX_2::Sort (el[pi3], el[pi4])); + + isface1 = isface2 = isface3 = isface4 = 0; + for (int l = 0; l < 4; l++) + { + INDEX_3 i3; + switch (l) + { + case 0: i3 = INDEX_3 (el[k], el[pi3], el[pi4]); break; + case 1: i3 = INDEX_3 (el[j], el[pi3], el[pi4]); break; + case 2: i3 = INDEX_3 (el[j], el[k], el[pi4]); break; + case 3: i3 = INDEX_3 (el[j], el[k], el[pi3]); break; + } + i3.Sort(); + if (faces.Used (i3)) + { + int domnr = faces.Get(i3); + if (domnr == -1 || domnr == el.GetIndex()) + { + switch (l) + { + case 0: isface1 = 1; break; + case 1: isface2 = 1; break; + case 2: isface3 = 1; break; + case 3: isface4 = 1; break; + } + } + } + } + /* + isface1 = faces.Used (INDEX_3::Sort (el[k], el[pi3], el[pi4])); + isface2 = faces.Used (INDEX_3::Sort (el[j], el[pi3], el[pi4])); + isface3 = faces.Used (INDEX_3::Sort (el[j], el[k], el[pi4])); + isface4 = faces.Used (INDEX_3::Sort (el[j], el[k], el[pi3])); + */ + + isfedge1 = isfedge2 = isfedge3 = isfedge4 = isfedge5 = isfedge6 = 0; + for (int l = 0; l < 6; l++) + { + INDEX_2 i2; + switch (l) + { + case 0: i2 = INDEX_2 (el[j], el[k]); break; + case 1: i2 = INDEX_2 (el[j], el[pi3]); break; + case 2: i2 = INDEX_2 (el[j], el[pi4]); break; + case 3: i2 = INDEX_2 (el[k], el[pi3]); break; + case 4: i2 = INDEX_2 (el[k], el[pi4]); break; + case 5: i2 = INDEX_2 (el[pi3], el[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[j], el[k])); + isfedge2 = face_edges.Used (INDEX_2::Sort (el[j], el[pi3])); + isfedge3 = face_edges.Used (INDEX_2::Sort (el[j], el[pi4])); + isfedge4 = face_edges.Used (INDEX_2::Sort (el[k], el[pi3])); + isfedge5 = face_edges.Used (INDEX_2::Sort (el[k], el[pi4])); + isfedge6 = face_edges.Used (INDEX_2::Sort (el[pi3], el[pi4])); + */ + + fp1 = fp2 = fp3 = fp4 = 0; + for (int l = 0; l < 4; l++) + { + int pi; + switch (l) + { + case 0: pi = el[j]; break; + case 1: pi = el[k]; break; + case 2: pi = el[pi3]; break; + case 3: pi = el[pi4]; break; + } + int domnr = facepoint[pi]; + if (domnr == -1 || domnr == el.GetIndex()) + { + switch (l) + { + case 0: fp1 = 1; break; + case 1: fp2 = 1; break; + case 2: fp3 = 1; break; + case 3: fp4 = 1; break; + } + } + } + + /* + fp1 = facepoint[el[j]] != 0; + fp2 = facepoint[el[k]] != 0; + fp3 = facepoint[el[pi3]] != 0; + fp4 = facepoint[el[pi4]] != 0; + */ + + + switch (isface1+isface2+isface3+isface4) + { + case 0: + { + isedge1 |= isfedge1; + isedge2 |= isfedge2; + isedge3 |= isfedge3; + isedge4 |= isfedge4; + isedge5 |= isfedge5; + isedge6 |= isfedge6; + + ep1 |= fp1; + ep2 |= fp2; + ep3 |= fp3; + ep4 |= fp4; + + switch (isedge1+isedge2+isedge3+isedge4+isedge5+isedge6) + { + case 0: + { + if (!ep1 && !ep2 && !ep3 && !ep4) + type = HP_TET; + + if (ep1 && !ep2 && !ep3 && !ep4) + type = HP_TET_0E_1V; + + if (ep1 && ep2 && !ep3 && !ep4) + type = HP_TET_0E_2V; + + if (ep1 && ep2 && ep3 && !ep4) + type = HP_TET_0E_3V; + + if (ep1 && ep2 && ep3 && ep4) + type = HP_TET_0E_4V; + + break; + } + + case 1: + { + if (!isedge1) break; + + if (!cp1 && !cp2 && !ep3 && !ep4) + type = HP_TET_1E_0V; + + if (cp1 && !cp2 && !ep3 && !ep4) + type = HP_TET_1E_1VA; + + if (!cp1 && !cp2 && !ep3 && ep4) + type = HP_TET_1E_1VB; + + if (cp1 && cp2 && !ep3 && !ep4) + type = HP_TET_1E_2VA; + + if (cp1 && !cp2 && ep3 && !ep4) + type = HP_TET_1E_2VB; + + if (cp1 && !cp2 && !ep3 && ep4) + type = HP_TET_1E_2VC; + + if (!cp1 && !cp2 && ep3 && ep4) + type = HP_TET_1E_2VD; + + if (cp1 && cp2 && ep3 && !ep4) + type = HP_TET_1E_3VA; + + if (cp1 && !cp2 && ep3 && ep4) + type = HP_TET_1E_3VB; + + if (cp1 && cp2 && ep3 && ep4) + type = HP_TET_1E_4V; + + break; + } + case 2: + { + if (isedge1 && isedge2) + { + if (!cp2 && !cp3 && !ep4) + type = HP_TET_2EA_0V; + + if (cp2 && !cp3 && !ep4) + type = HP_TET_2EA_1VA; + if (!cp2 && cp3 && !ep4) + type = HP_TET_2EA_1VB; + + if (!cp2 && !cp3 && ep4) + type = HP_TET_2EA_1VC; + + if (cp2 && cp3 && !ep4) + type = HP_TET_2EA_2VA; + if (cp2 && !cp3 && ep4) + type = HP_TET_2EA_2VB; + if (!cp2 && cp3 && ep4) + type = HP_TET_2EA_2VC; + + if (cp2 && cp3 && ep4) + type = HP_TET_2EA_3V; + } + if (isedge1 && isedge6) + { + if (!cp1 && !cp2 && !cp3 && !cp4) + type = HP_TET_2EB_0V; + if (cp1 && !cp2 && !cp3 && !cp4) + type = HP_TET_2EB_1V; + if (cp1 && cp2 && !cp3 && !cp4) + type = HP_TET_2EB_2VA; + if (cp1 && !cp2 && cp3 && !cp4) + type = HP_TET_2EB_2VB; + if (cp1 && !cp2 && !cp3 && cp4) + type = HP_TET_2EB_2VC; + if (cp1 && cp2 && cp3 && !cp4) + type = HP_TET_2EB_3V; + if (cp1 && cp2 && cp3 && cp4) + type = HP_TET_2EB_4V; + } + } + case 3: + { + if (isedge1 && isedge2 && isedge3) + { + if (!cp2 && !cp3 && !cp4) + type = HP_TET_3EA_0V; + if (cp2 && !cp3 && !cp4) + type = HP_TET_3EA_1V; + if (cp2 && cp3 && !cp4) + type = HP_TET_3EA_2V; + if (cp2 && cp3 && cp4) + type = HP_TET_3EA_3V; + } + if (isedge1 && isedge3 && isedge4) + { + if (!cp3 && !cp4) + type = HP_TET_3EB_0V; + if (cp3 && !cp4) + type = HP_TET_3EB_1V; + if (cp3 && cp4) + type = HP_TET_3EB_2V; + } + if (isedge1 && isedge2 && isedge5) + { + if (!cp3 && !cp4) + type = HP_TET_3EC_0V; + if (cp3 && !cp4) + type = HP_TET_3EC_1V; + if (cp3 && cp4) + type = HP_TET_3EC_2V; + } + break; + } + } + break; + } + + + + case 1: // one singular face + { + if (!isface1) break; + + switch (isfedge1+isfedge2+isfedge3+isedge4+isedge5+isedge6) + { + case 0: + { + if (!fp1 && !ep2 && !ep3 && !ep4) + type = HP_TET_1F_0E_0V; + if (fp1 && !ep2 && !ep3 && !ep4) + type = HP_TET_1F_0E_1VB; + if (!fp1 && ep2 && !ep3 & !ep4) + type = HP_TET_1F_0E_1VA; + break; + } + case 1: + { + if (isfedge1) + { + if (!ep1 && !ep3 && !ep4) + type = HP_TET_1F_1EA_0V; + } + if (isedge4) // V1-V3 + { + if (!ep1 && !cp2 && !cp3 && !ep4) + type = HP_TET_1F_1EB_0V; + } + break; + } + } + break; + } + + + case 2: // one singular face + { + if (!isface1 || !isface2) break; + + switch (isfedge1+isedge2+isedge3+isedge4+isedge5) + { + case 0: + { + if (!ep1 && !ep2 && !cp3 && !cp4) + type = HP_TET_2F_0E_0V; + break; + } + } + break; + } + + + } + + if (type != HP_NONE) + { + pnums[0] = el[j]; + pnums[1] = el[k]; + pnums[2] = el[pi3]; + pnums[3] = el[pi4]; + break; + } + } + + /* + if (type != HP_TET_2EB_2VA) + type = HP_NONE; + */ + + if (type == HP_NONE) + { + cnt_undef++; + (*testout) << "undefined element" << endl + << "cp = " << cp1 << cp2 << cp3 << cp4 << endl + << "ep = " << ep1 << ep2 << ep3 << ep4 << endl + << "isedge = " << isedge1 << isedge2 << isedge3 + << isedge4 << isedge5 << isedge6 << endl; + cout << "undefined element !!! " << endl; + } + + break; + } + + case PRISM: + { + int pi1, pi2, pi3, pi4, pi5, pi6; + int ep1, ep2, ep3, ep4, ep5, ep6, cp1, cp2, cp3, cp4, cp5, cp6; + + int ishedge1, ishedge2, ishedge3, ishedge4, ishedge5, ishedge6; + int isvedge1, isvedge2, isvedge3; + + for (int j = 1; j <= 3; j++) + { + if (type) break; + + pi1 = j; + pi2 = pi1%3 + 1; + pi3 = pi2%3 + 1; + pi4 = pi1+3; + pi5 = pi2+3; + pi6 = pi3+3; + + ep1 = edgepoint.Test (el.PNum (pi1)); + ep2 = edgepoint.Test (el.PNum (pi2)); + ep3 = edgepoint.Test (el.PNum (pi3)); + ep4 = edgepoint.Test (el.PNum (pi4)); + ep5 = edgepoint.Test (el.PNum (pi5)); + ep6 = edgepoint.Test (el.PNum (pi6)); + + cp1 = cornerpoint.Test (el.PNum (pi1)); + cp2 = cornerpoint.Test (el.PNum (pi2)); + cp3 = cornerpoint.Test (el.PNum (pi3)); + cp4 = cornerpoint.Test (el.PNum (pi4)); + cp5 = cornerpoint.Test (el.PNum (pi5)); + cp6 = cornerpoint.Test (el.PNum (pi6)); + + INDEX_2 i2 = INDEX_2::Sort(el.PNum (pi1), el.PNum (pi4)); + isvedge1 = edges.Used (i2) || ep1 || ep4; + + i2 = INDEX_2::Sort(el.PNum (pi2), el.PNum (pi5)); + isvedge2 = edges.Used (i2) || ep2 || ep5; + + i2 = INDEX_2::Sort(el.PNum (pi3), el.PNum (pi6)); + isvedge3 = edges.Used (i2) || ep3 || ep6; + + + ishedge1 = edges.Used (INDEX_2::Sort(el.PNum (pi1), el.PNum (pi2))); + ishedge2 = edges.Used (INDEX_2::Sort(el.PNum (pi2), el.PNum (pi3))); + ishedge3 = edges.Used (INDEX_2::Sort(el.PNum (pi3), el.PNum (pi1))); + + + + switch (ishedge1 + ishedge2 + ishedge3) + { + case 0: + { + if (!isvedge1 && !isvedge2 && !isvedge3) + type = HP_PRISM; + else if (isvedge1 && !isvedge2 && !isvedge3) + type = HP_PRISM_SINGEDGE; + else if (isvedge1 && isvedge2 && !isvedge3) + type = HP_PRISM_SINGEDGE_V12; + break; + } + case 1: + { + if (ishedge1) + type = HP_PRISM_SINGEDGE_H1; + break; + } + case 2: + { + if (ishedge1 && ishedge2) + type = HP_PRISM_SINGEDGE_H12; + break; + } + } + + if (type != HP_NONE) + { + cout << "classified element, type = " << type << ", el = " << el << endl; + pnums[0] = el.PNum (pi1); + pnums[1] = el.PNum (pi2); + pnums[2] = el.PNum (pi3); + pnums[3] = el.PNum (pi4); + pnums[4] = el.PNum (pi5); + pnums[5] = el.PNum (pi6); + break; + } + } + break; + } + default: + { + cerr << "hp-refinement not defined for element" << endl; + } + } + + + if (type == HP_NONE) + { + cout << "element is HP_NONE: " << el << endl; + } + + if (!Get_HPRef_Struct (type)) + { + (*testout) << "case " << type << " not implemented " << endl; + cnt_nonimplement++; + misses[type]++; + } + + HPRefElement hpel; + hpel.type = type; + for (int j = 0; j < 8; j++) + hpel.pnums[j] = pnums[j]; + hpel.index = el.GetIndex(); + hpel.level = 1; + hpel.coarse_elnr = i; + + static const double points[4][3] = + { { 1, 0, 0 }, { 0, 1, 0 }, { 0, 0, 1 }, { 0, 0, 0 } }; + for (int j = 0; j < 4; j++) + for (int k = 0; k < 4; k++) + if (pnums[j] == el[k]) + { + hpel.param[j][0] = points[k][0]; + hpel.param[j][1] = points[k][1]; + hpel.param[j][2] = points[k][2]; + } + + elements.Append (hpel); + } + + cout << "undefined elements: " << cnt_undef << endl; + cout << "non-implemented: " << cnt_nonimplement << endl; + + for (int i = 0; i < misses.Size(); i++) + if (misses[i]) + cout << "missing case " << i << " occured " << misses[i] << " times" << endl; + + for (int i = 1; i <= mesh.GetNSE(); i++) + { + int j, k, pi3, pi4; + Element2d & el = mesh.SurfaceElement(i); + + HPREF_ELEMENT_TYPE type = HP_NONE; + int pnums[8] = { 0 }; + + switch (el.GetType()) + { + case TRIG: + { + for (j = 1; j <= 3; j++) + { + int ep1 = edgepoint.Test (el.PNumMod (j)); + int ep2 = edgepoint.Test (el.PNumMod (j+1)); + int ep3 = edgepoint.Test (el.PNumMod (j+2)); + + if (mesh.GetDimension() == 2) + { + ep1 = edgepoint_dom.Used (INDEX_2 (mesh.SurfaceElement(i).GetIndex(), el.PNumMod(j))); + ep2 = edgepoint_dom.Used (INDEX_2 (mesh.SurfaceElement(i).GetIndex(), el.PNumMod(j+1))); + 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; + + INDEX_2 i2; + i2 = INDEX_2(el.PNumMod (j), el.PNumMod (j+1)); + // i2.Sort(); + int isedge1 = edges.Used (i2); + i2 = INDEX_2(el.PNumMod (j+1), el.PNumMod (j+2)); + // i2.Sort(); + int isedge2 = edges.Used (i2); + i2 = INDEX_2(el.PNumMod (j+2), el.PNumMod (j+3)); + // i2.Sort(); + int isedge3 = edges.Used (i2); + + if (isedge1 + isedge2 + isedge3 == 0) + { + if (!ep1 && !ep2 && !ep3) + type = HP_TRIG; + + if (ep1 && !ep2 && !ep3) + type = HP_TRIG_SINGCORNER; + + if (ep1 && ep2 && !ep3) + type = HP_TRIG_SINGCORNER12; + + if (ep1 && ep2 && ep3) + { + if (mesh.GetDimension() == 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; + } + } + break; + } + case QUAD: + { + int ep1, ep2, ep3, ep4, cp1, cp2, cp3, cp4; + int isedge1, isedge2, isedge3, isedge4; + + for (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 (mesh.GetDimension() == 2) + { + ep1 = edgepoint_dom.Used (INDEX_2 (mesh.SurfaceElement(i).GetIndex(), el.PNumMod(j))); + ep2 = edgepoint_dom.Used (INDEX_2 (mesh.SurfaceElement(i).GetIndex(), el.PNumMod(j+1))); + ep3 = edgepoint_dom.Used (INDEX_2 (mesh.SurfaceElement(i).GetIndex(), el.PNumMod(j+2))); + ep4 = edgepoint_dom.Used (INDEX_2 (mesh.SurfaceElement(i).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; + + + INDEX_2 i2; + i2 = INDEX_2(el.PNumMod (j), el.PNumMod (j+1)); + // i2.Sort(); + isedge1 = edges.Used (i2); + i2 = INDEX_2(el.PNumMod (j+1), el.PNumMod (j+2)); + // i2.Sort(); + isedge2 = edges.Used (i2); + i2 = INDEX_2(el.PNumMod (j+2), el.PNumMod (j+3)); + // i2.Sort(); + isedge3 = edges.Used (i2); + i2 = INDEX_2(el.PNumMod (j+3), el.PNumMod (j+4)); + // i2.Sort(); + isedge4 = edges.Used (i2); + + int sumcp = cp1 + cp2 + cp3 + cp4; + int sumep = ep1 + ep2 + ep3 + ep4; + int sumedge = isedge1 + isedge2 + isedge3 + isedge4; + + 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) + { + pnums[0] = el.PNumMod (j); + pnums[1] = el.PNumMod (j+1); + pnums[2] = el.PNumMod (j+2); + pnums[3] = el.PNumMod (j+3); + 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; + } + break; + } + } + + if (type == HP_NONE) + { + cerr << "undefined QUAD type" << endl; + for (j = 0; j < 4; j++) + pnums[j] = el[j]; + } + + HPRefElement hpel; + hpel.type = type; + for (j = 0; j < 8; j++) + hpel.pnums[j] = pnums[j]; + hpel.index = el.GetIndex(); + hpel.level = 1; + hpel.coarse_elnr = i-1; + + + static const double points[3][2] = + { { 1, 0 }, { 0, 1 }, { 0, 0 } }; + for (j = 0; j < 3; j++) + for (k = 0; k < 3; k++) + if (pnums[j] == el[k]) + { + hpel.param[j][0] = points[k][0]; + hpel.param[j][1] = points[k][1]; + } + elements.Append (hpel); + } + + + + + + + for (int i = 1; i <= mesh.GetNSeg(); i++) + { + Segment & seg = mesh.LineSegment(i); + + HPREF_ELEMENT_TYPE type = HP_NONE; + + int cp1 = cornerpoint.Test (seg.p1); + int cp2 = cornerpoint.Test (seg.p2); + + INDEX_2 i2; + i2 = INDEX_2(seg.p1, seg.p2); + i2.Sort(); + if (!edges.Used (i2)) + { + cp1 = edgepoint.Test (seg.p1); + cp2 = edgepoint.Test (seg.p2); + } + + HPRefElement hpel; + hpel.index = seg.edgenr + 10000 * seg.si; + hpel.level = 1; + + hpel.pnums[0] = seg.p1; + hpel.pnums[1] = seg.p2; + hpel.param[0][0] = seg.epgeominfo[0].dist; + hpel.param[1][0] = seg.epgeominfo[1].dist; + + 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; + + (*testout) << "refine segment " << seg << ", hptype= " << hpel.type << endl; + + elements.Append (hpel); + + (*testout) << "add seg: " << endl << seg << endl; + (*testout) << "param = " << elements.Last().param[0][0] << ", " << elements.Last().param[1][0] << endl; + } + } + + + + /* ******************************* DoRefinement *************************************** */ + + // parameter "fine": false ... divide elements by a factor of 3/4 to 1/4 + // true ... divide by 7/8 to 1/8 + + void DoRefinement (Mesh & mesh, ARRAY<HPRefElement> & elements, + Refinement * ref, bool fine) + { + INDEX_2_HASHTABLE<int> newpts(elements.Size()+1); + INDEX_3_HASHTABLE<int> newfacepts(elements.Size()+1); + + // prepare new points + + int oldelsize = elements.Size(); + for (int i = 0; i < oldelsize; i++) + { + HPRefElement & el = elements[i]; + HPRef_Struct * hprs = Get_HPRef_Struct (el.type); + + if (!hprs) + { + cout << "Refinementstruct not defined for element " << el.type << endl; + continue; + } + + int j = 0; + while (hprs->splitedges[j][0]) + { + INDEX_2 i2(el.pnums[hprs->splitedges[j][0]-1], + el.pnums[hprs->splitedges[j][1]-1]); + if (!newpts.Used (i2)) + { + Point3d np = Center (mesh.Point (i2.I1()), + mesh.Point (i2.I2())); + np = Center (mesh.Point (i2.I1()),np); + if ( fine ) np = Center (mesh.Point (i2.I1()),np); + + int npi = mesh.AddPoint (np); + newpts.Set (i2, npi); + } + j++; + } + + + j = 0; + if (hprs->splitfaces) + while (hprs->splitfaces[j][0]) + { + INDEX_3 i3(el.pnums[hprs->splitfaces[j][0]-1], + el.pnums[hprs->splitfaces[j][1]-1], + el.pnums[hprs->splitfaces[j][2]-1]); + + if (i3.I2() > i3.I3()) Swap (i3.I2(), i3.I3()); + + if (!newfacepts.Used (i3)) + { + Point3d np = Center (mesh.Point (i3.I2()), + mesh.Point (i3.I3())); + np = Center (mesh.Point (i3.I1()),np); + if ( fine ) np = Center (mesh.Point (i3.I1()),np); + 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.level + 1; + + 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) + newlevel = el.level; + + if (!hprs) continue; + + int newpnums[64]; + double newparam[64][3]; + + int j; + for (j = 0; j < 8; j++) + { + newpnums[j] = el.pnums[j]; + for (int l = 0; l < 3; l++) + newparam[j][l] = el.param[j][l]; + } + + + // split edges, incl. transferring curvature + j = 0; + while (hprs->splitedges[j][0]) + { + INDEX_2 i2(el.pnums[hprs->splitedges[j][0]-1], + el.pnums[hprs->splitedges[j][1]-1]); + + int npi = newpts.Get(i2); + newpnums[hprs->splitedges[j][2]-1] = npi; + + double fac1, fac2; + if ( fine ) { fac1 = 0.875; fac2 = 0.125; } + else { fac1 = 0.75; fac2 = 0.25; } + + for (int l = 0; l < 3; l++) + newparam[hprs->splitedges[j][2]-1][l] = + fac1 * el.param[hprs->splitedges[j][0]-1][l] + + fac2 * 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; + + double fac1, fac2; + if ( fine ) { fac1 = 0.75; fac2 = 0.125; } + else { fac1 = 0.5; fac2 = 0.25; } + + for (int l = 0; l < 3; l++) + newparam[hprs->splitfaces[j][3]-1][l] = + fac1 * 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]; + Point3d np = + Center (Center (mesh.Point (pi1), + mesh.Point (el.pnums[hprs->splitelements[j][1]-1])), + Center (mesh.Point (el.pnums[hprs->splitelements[j][2]-1]), + mesh.Point (el.pnums[hprs->splitelements[j][3]-1]))); + // divide once more, if fine subdivision is wanted + if ( fine ) np = Center (mesh.Point (pi1),np); + int npi = mesh.AddPoint (np); + newpnums[hprs->splitelements[j][4]-1] = npi; + + double fac1, fac2; + if ( fine ) { fac1 = 0.625; fac2 = 0.125; } + else { fac1 = 0.25; fac2 = 0.25; } + + for (int l = 0; l < 3; l++) + newparam[hprs->splitelements[j][4]-1][l] = + fac1 * el.param[hprs->splitelements[j][0]-1][l] + + fac2 * el.param[hprs->splitelements[j][1]-1][l] + + fac2 * el.param[hprs->splitelements[j][2]-1][l] + + fac2 * el.param[hprs->splitelements[j][3]-1][l]; + + j++; + } + + j = 0; + while (hprs->neweltypes[j]) + { + HPRefElement newel; + newel.type = hprs->neweltypes[j]; + for (int k = 0; k < 8; k++) + newel.pnums[k] = newpnums[hprs->newels[j][k]-1]; + + newel.index = elements[i].index; + newel.coarse_elnr = elements[i].coarse_elnr; + newel.level = 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++; + } + } + } + + + + + + + /* ************************** DoRefineDummies ******************************** */ + + void DoRefineDummies (Mesh & mesh, ARRAY<HPRefElement> & elements, + Refinement * ref) + { + int oldelsize = elements.Size(); + + for (int i = 0; i < oldelsize; i++) + { + HPRefElement & el = elements[i]; + HPRef_Struct * hprs = Get_HPRef_Struct (el.type); + if (!hprs) continue; + + if (el.type != HP_DUMMY_QUAD_SINGCORNER && + el.type != HP_PYRAMID_EDGES && + el.type != HP_PYRAMID_0E_1V && + el.type != HP_HEX_0E_1V && + el.type != HP_HEX_1E_1V && + el.type != HP_HEX_1E_0V && + el.type != HP_HEX_3E_0V + ) continue; + + int newlevel = el.level; + + 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]) + { + HPRefElement newel; + newel.type = hprs->neweltypes[j]; + for (int k = 0; k < 8; k++) + newel.pnums[k] = newpnums[hprs->newels[j][k]-1]; + newel.index = el.index; + newel.coarse_elnr = el.coarse_elnr; + newel.level = newlevel; + + for (int k = 0; k < 8; k++) + for (int l = 0; l < 3; l++) + newel.param[k][l] = newparam[hprs->newels[j][k]-1][l]; + + if (j == 0) + elements[i] = newel; + else + elements.Append (newel); + j++; + } + } + } + + + + + + + + void SubdivideDegeneratedHexes (Mesh & mesh, ARRAY<HPRefElement> & elements) + { + 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) + { + HPRefElement el = elements[i]; + + 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]]); + 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::GetFaces (HEX); + + for (int j = 0; j < 6; j++) + { + ARRAY<int> pts; + for (int k = 0; k < 4; k++) + { + bool same = 0; + for (int l = 0; l < pts.Size(); l++) + if (el.pnums[pts[l]] == el.pnums[faces[j][k]-1]) + same = 1; + if (!same) + pts.Append (faces[j][k]-1); + + } + + HPRefElement newel = el; + if (pts.Size() == 3) + { + 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; + } + 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; + } + + if (j == 0) + elements[i] = newel; + else + elements.Append (newel); + } + } + } + } + + + void CalcStatistics (ARRAY<HPRefElement> & elements) + { + return; + + int i, p; + int nsegm = 0, ntrig = 0, nquad = 0; + int nhex = 0, nprism = 0, npyramid = 0, ntet = 0; + int maxlevel = 0; + + for (i = 1; i <= elements.Size(); i++) + { + const HPRefElement & el = elements.Get(i); + maxlevel = max2 (el.level, maxlevel); + switch (Get_HPRef_Struct (el.type)->geom) + { + case HP_SEGM: + + { + nsegm++; + break; + } + case HP_TRIG: + { + ntrig ++; + break; + } + case HP_QUAD: + { + nquad++; + break; + } + case HP_TET: + { + ntet++; + break; + } + + case HP_PRISM: + { + nprism++; + break; + } + + case HP_PYRAMID: + { + npyramid++; + break; + } + + case HP_HEX: + { + nhex++; + break; + } + + default: + { + cerr << "statistics error, unknown element type" << endl; + } + } + } + + cout << "level = " << maxlevel << endl; + cout << "nsegm = " << nsegm << endl; + cout << "ntrig = " << ntrig << ", nquad = " << nquad << endl; + cout << "ntet = " << ntet << ", npyr = " << npyramid + << ", nprism = " << nprism << ", nhex = " << nhex << endl; + + return; + + double memcost = 0, cpucost = 0; + for (p = 1; p <= 20; p++) + { + memcost = (ntet + nprism + nhex) * pow (static_cast<double>(p), 6.0); + cpucost = (ntet + nprism + nhex) * pow (static_cast<double>(p), 9.0); + cout << "costs for p = " << p << ": mem = " << memcost << ", cpu = " << cpucost << endl; + } + + double memcosttet = 0; + double memcostprism = 0; + double memcosthex = 0; + double memcostsctet = 0; + double memcostscprism = 0; + double memcostschex = 0; + double cpucosttet = 0; + double cpucostprism = 0; + double cpucosthex = 0; + + for (i = 1; i <= elements.Size(); i++) + { + const HPRefElement & el = elements.Get(i); + switch (el.type) + { + case HP_TET: + case HP_TET_0E_1V: + case HP_TET_1E_0V: + case HP_TET_1E_1VA: + { + int p1 = maxlevel - el.level + 1; + (*testout) << "p1 = " << p1 << ", P1^6 = " << pow (static_cast<double>(p1), 6.0) + << " (p1-3)^6 = " << pow ( static_cast<double>(max2(p1-3, 0)), 6.0) + << " p1^3 = " << pow ( static_cast<double>(p1), 3.0) + << " (p1-3)^3 = " << pow ( static_cast<double>(p1-3), 3.0) + << " [p1^3-(p1-3)^3]^2 = " << sqr (pow (static_cast<double>(p1),3.0) - pow ( static_cast<double>(p1-3), 3.0)) + << endl; + + p1 /= 2 +1; + memcosttet += pow (static_cast<double>(p1), 6.0); + memcostsctet += pow (static_cast<double>(p1), 6.0) - pow ( static_cast<double>(max2(p1-3, 1)), 6.0); + cpucosttet += pow (static_cast<double>(p1), 9.0); + break; + } + case HP_PRISM: + case HP_PRISM_SINGEDGE: + { + int p1 = maxlevel - el.level + 1; + p1 /= 2 +1; + memcostprism += pow (static_cast<double>(p1), 6.0); + memcostscprism += pow (static_cast<double>(p1), 6.0) - pow ( static_cast<double>(max2(p1-3, 1)), 6.0); + cpucostprism += pow (static_cast<double>(p1), 9.0); + break; + } + case HP_HEX: + { + int p1 = maxlevel - el.level + 1; + int p2 = maxlevel; + p1 /= 2 +1; + p2 /= 2 +1; + memcosthex += pow (static_cast<double>(p1), 4.0) * pow (static_cast<double>(p2), 2.0); + memcostschex += pow (static_cast<double>(p1), 6.0) - pow ( static_cast<double>(max2(p1-2, 0)), 6.0); + cpucosthex += pow (static_cast<double>(p1), 6.0) * pow (static_cast<double>(p2), 3.0); + break; + } + default: + ; + } + } + cout << "TET: hp-memcost = " << memcosttet + << ", scmemcost = " << memcostsctet + << ", cpucost = " << cpucosttet + << endl; + cout << "PRI: hp-memcost = " << memcostprism + << ", scmemcost = " << memcostscprism + << ", cpucost = " << cpucostprism << endl; + cout << "HEX: hp-memcost = " << memcosthex + << ", scmemcost = " << memcostschex + << ", cpucost = " << cpucosthex << endl; + } + + + + + + + + /* ***************************** HPRefinement ********************************** */ + + void HPRefinement (Mesh & mesh, Refinement * ref, int levels) + { + PrintMessage (1, "HP Refinement called, levels = ", levels); + + // ARRAY<HPRefElement> hpelements; + + delete mesh.hpelements; + mesh.hpelements = new ARRAY<HPRefElement>; + + mesh.coarsemesh = new Mesh; + *mesh.coarsemesh = mesh; + + ARRAY<HPRefElement> & hpelements = *mesh.hpelements; + + + + PrepareElements (mesh, hpelements); + + for (int j = 1; j <= levels; j++) + { + cout << "hp-refine level " << j << flush; + // last parameter: true for fine subdivision (7/8 : 1/8), false for 3/4 : 1/4 + // Please check into CVS only with this parameter set to "true"! + DoRefinement (mesh, hpelements, ref, true); // FB + DoRefineDummies (mesh, hpelements, ref); + CalcStatistics (hpelements); + cout << " done" << endl; + } + + SubdivideDegeneratedHexes (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.p1 = hpel.pnums[0]; + seg.p2 = hpel.pnums[1]; + // NOTE: only for less than 10000 elements (HACK) !!! + seg.edgenr = hpel.index % 10000; + seg.si = hpel.index / 10000; + seg.epgeominfo[0].dist = hpel.param[0][0]; + seg.epgeominfo[1].dist = hpel.param[1][0]; + seg.epgeominfo[0].edgenr = seg.edgenr; + seg.epgeominfo[1].edgenr = seg.edgenr; + seg.hp_elnr = i; + mesh.AddSegment (seg); + break; + } + + + case HP_TRIG: + { + Element2d el(3); + el.PNum(1) = hpel.pnums[0]; + el.PNum(2) = hpel.pnums[1]; + el.PNum(3) = hpel.pnums[2]; + el.SetIndex (hpel.index); + el.hp_elnr = i; + mesh.AddSurfaceElement (el); + break; + } + case HP_QUAD: + { + Element2d el(4); + el.PNum(1) = hpel.pnums[0]; + el.PNum(2) = hpel.pnums[1]; + el.PNum(3) = hpel.pnums[2]; + el.PNum(4) = hpel.pnums[3]; + el.SetIndex (hpel.index); + el.hp_elnr = i; + mesh.AddSurfaceElement (el); + break; + } + case HP_TET: + { + Element el(4); + el.PNum(1) = hpel.pnums[0]; + el.PNum(2) = hpel.pnums[1]; + el.PNum(3) = hpel.pnums[2]; + el.PNum(4) = hpel.pnums[3]; + el.SetIndex (hpel.index); + el.hp_elnr = i; + mesh.AddVolumeElement (el); + break; + } + case HP_PRISM: + { + Element el(6); + el.PNum(1) = hpel.pnums[0]; + el.PNum(2) = hpel.pnums[1]; + el.PNum(3) = hpel.pnums[2]; + el.PNum(4) = hpel.pnums[3]; + el.PNum(5) = hpel.pnums[4]; + el.PNum(6) = hpel.pnums[5]; + el.SetIndex (hpel.index); + el.hp_elnr = i; + mesh.AddVolumeElement (el); + break; + } + + case HP_PYRAMID: + { + Element el(5); + el.PNum(1) = hpel.pnums[0]; + el.PNum(2) = hpel.pnums[1]; + el.PNum(3) = hpel.pnums[2]; + el.PNum(4) = hpel.pnums[3]; + el.PNum(5) = hpel.pnums[4]; + el.SetIndex (hpel.index); + el.hp_elnr = i; + mesh.AddVolumeElement (el); + break; + } + case HP_HEX: + { + Element el(8); + el.PNum(1) = hpel.pnums[0]; + el.PNum(2) = hpel.pnums[1]; + el.PNum(3) = hpel.pnums[2]; + el.PNum(4) = hpel.pnums[3]; + el.PNum(5) = hpel.pnums[4]; + el.PNum(6) = hpel.pnums[5]; + el.PNum(7) = hpel.pnums[6]; + el.PNum(8) = hpel.pnums[7]; + el.SetIndex (hpel.index); + el.hp_elnr = i; + mesh.AddVolumeElement (el); + break; + } + + default: + PrintSysError ("hpref, backconversion failed for element ", + int(Get_HPRef_Struct (hpel.type) -> geom)); + } + } + + mesh.UpdateTopology(); + } + + +} diff --git a/contrib/Netgen/libsrc/meshing/hprefinement.hpp b/contrib/Netgen/libsrc/meshing/hprefinement.hpp new file mode 100644 index 0000000000..df1cc01e8e --- /dev/null +++ b/contrib/Netgen/libsrc/meshing/hprefinement.hpp @@ -0,0 +1,227 @@ +#ifndef FILE_HPREFINEMENT +#define FILE_HPREFINEMENT + +/**************************************************************************/ +/* File: hprefinement.hh */ +/* Author: Joachim Schoeberl */ +/* Date: 27. Oct. 2000 */ +/**************************************************************************/ + +/* + HP Refinement +*/ + + + + +enum HPREF_ELEMENT_TYPE { + HP_NONE=0, + + HP_SEGM = 1, + HP_SEGM_SINGCORNERL, + HP_SEGM_SINGCORNERR, + HP_SEGM_SINGCORNERS, + + HP_TRIG = 10, + HP_TRIG_SINGCORNER, + HP_TRIG_SINGCORNER12, + HP_TRIG_SINGCORNER123, + HP_TRIG_SINGCORNER123_2D, // not rotational symmetric + HP_TRIG_SINGEDGE = 20, + HP_TRIG_SINGEDGECORNER1, // E = 100, V = 100 + HP_TRIG_SINGEDGECORNER2, // E = 100, V = 010 + HP_TRIG_SINGEDGECORNER12, // E = 100, V = 110 + HP_TRIG_SINGEDGECORNER3, + HP_TRIG_SINGEDGECORNER13, + HP_TRIG_SINGEDGECORNER23, + HP_TRIG_SINGEDGECORNER123, + HP_TRIG_SINGEDGES = 30, + HP_TRIG_SINGEDGES2, + HP_TRIG_SINGEDGES3, + HP_TRIG_SINGEDGES23, + HP_TRIG_3SINGEDGES = 40, + + HP_QUAD = 50, + HP_QUAD_SINGCORNER, + HP_DUMMY_QUAD_SINGCORNER, + HP_QUAD_SINGEDGE, + HP_QUAD_0E_2VA, // V = 1100 + HP_QUAD_0E_2VB, // V = 1010 + HP_QUAD_0E_3V, + HP_QUAD_0E_4V, + + // one edge: marked edge is always edge from vertex 1 to vertex 2 (E = 1000) + HP_QUAD_1E_1VA, // vertex on beginning of edge: V = 1000 + HP_QUAD_1E_1VB, // vertex on end of edge: V = 0100 + HP_QUAD_1E_1VC, // V = 0010 + HP_QUAD_1E_1VD, // V = 0001 + + HP_QUAD_1E_2VA, // V = 1100 + HP_QUAD_1E_2VB, // V = 1010 + HP_QUAD_1E_2VC, // V = 1001 + HP_QUAD_1E_2VD, // V = 0110 + HP_QUAD_1E_2VE, // V = 0101 + HP_QUAD_1E_2VF, // V = 0011 + + HP_QUAD_1E_3VA, // V = 1110 + HP_QUAD_1E_3VB, // V = 1101 + HP_QUAD_1E_3VC, // V = 1011 + HP_QUAD_1E_3VD, // V = 0111 + + HP_QUAD_1E_4V, // V = 1111 + + + HP_QUAD_2E, // E = 1001, V = 1000 + HP_QUAD_2E_1VA, // E = 1001, V = 1100 + HP_QUAD_2E_1VB, // E = 1001, V = 1010 + HP_QUAD_2E_1VC, // E = 1001, V = 1001 + HP_QUAD_2E_2VA, // E = 1001, V = 1110 + HP_QUAD_2E_2VB, // E = 1001, V = 1101 + HP_QUAD_2E_2VC, // E = 1001, V = 1011 + HP_QUAD_2E_3V, // E = 1001, V = 1111 + + HP_QUAD_2EB_0V, // E = 1010, V = 0000 + HP_QUAD_2EB_1VA, // E = 1010, V = 1000 + HP_QUAD_2EB_1VB, // E = 1010, V = 0100 + HP_QUAD_2EB_2VA, // E = 1010, V = 1100 + HP_QUAD_2EB_2VB, // E = 1010, V = 1010 + HP_QUAD_2EB_2VC, // E = 1010, V = 1001 + HP_QUAD_2EB_2VD, // E = 1010, V = 0101 + HP_QUAD_2EB_3VA, // E = 1010, V = 1110 + HP_QUAD_2EB_3VB, // E = 1010, V = 1101 + + HP_QUAD_2EB_4V, + + + HP_QUAD_3E, // E = 1101, V = 1100 + HP_QUAD_3E_3VA, // E = 1101, V = 1110 + HP_QUAD_3E_3VB, // E = 1101, V = 1101 + HP_QUAD_3E_4V, // E = 1101, V = 1111 + + HP_QUAD_4E, + + + HP_TET = 100, // no singular vertex/edge + HP_TET_0E_1V, // V1 + HP_TET_0E_2V, // V1,2 + HP_TET_0E_3V, // V1,2,3 + HP_TET_0E_4V, // V1,2,3,4 + HP_TET_1E_0V = 200, // E1-2 + HP_TET_1E_1VA, // V1 + HP_TET_1E_1VB, // V3 + HP_TET_1E_2VA, // V1,2 + HP_TET_1E_2VB, // V1,3 + HP_TET_1E_2VC, // V1,4 + HP_TET_1E_2VD, // V3,4 + HP_TET_1E_3VA, // V1,2,3 + HP_TET_1E_3VB, // V1,3,4 + HP_TET_1E_4V, // V1,2,3,4 + + + // 2 connected edges, additonally marked Vs + HP_TET_2EA_0V = 220, // E1-2, E1-3 + HP_TET_2EA_1VA, // V2 + HP_TET_2EA_1VB, // V3 + HP_TET_2EA_1VC, // V4 + HP_TET_2EA_2VA, // V2,3 + HP_TET_2EA_2VB, // V2,4 + HP_TET_2EA_2VC, // V3,4 + HP_TET_2EA_3V, // V2,3,4 + + // 2 opposite edges + HP_TET_2EB_0V = 230, // E1-2, E3-4 + HP_TET_2EB_1V, // V1 + HP_TET_2EB_2VA, // V1,2 + HP_TET_2EB_2VB, // V1,3 + HP_TET_2EB_2VC, // V1,4 + HP_TET_2EB_3V, // V1,2,3 + HP_TET_2EB_4V, // V1,2,3,4 + + HP_TET_3EA_0V = 400, // E1-2, E1-3, E1-4, 3 edges connected + HP_TET_3EA_1V, // V2 + HP_TET_3EA_2V, // V2,3 + HP_TET_3EA_3V, // V2,3,4 + + HP_TET_3EB_0V = 420, // E1-2, E1-4, E2-3 3 edges chain + HP_TET_3EB_1V, // + HP_TET_3EB_2V, // + HP_TET_3EC_0V = 430, // 3 edges chain, alter + HP_TET_3EC_1V, // 3 edges chain, alter + HP_TET_3EC_2V, // 3 edges chain, alter + + + HP_TET_1F_0E_0V = 500, // 1 singular face + HP_TET_1F_0E_1VA, // 1 sing vertex in face (V2) + HP_TET_1F_0E_1VB, // 1 sing vertex not in face (V1) + HP_TET_1F_1EA_0V, // 1 sing edge not in face + HP_TET_1F_1EB_0V, // 1 sing edge in face + HP_TET_2F_0E_0V = 600, // 2 singular faces + + HP_PRISM = 1000, + HP_PRISM_SINGEDGE, + HP_PRISM_SINGEDGE_V12, + HP_PRISM_SINGEDGE_H1, + HP_PRISM_SINGEDGE_H12, + + HP_PRISM_1FA_0E_0V, // 1 singular trig face + HP_PRISM_1FB_0E_0V, // 1 singular quad face 1-2-4-5 + HP_PRISM_1FB_1EA_0V, // 1 singular quad face, edge is 1-2 + + HP_PYRAMID = 2000, + HP_PYRAMID_0E_1V, + HP_PYRAMID_EDGES, + HP_PYRAMID_1FB_0E_1VA, // 1 trig face, top vertex + + HP_HEX = 3000, + HP_HEX_0E_1V, + HP_HEX_1E_1V, + HP_HEX_1E_0V, + HP_HEX_3E_0V, + + HP_HEX_1F_0E_0V +}; + + + +struct HPRef_Struct { + HPREF_ELEMENT_TYPE geom; + int (*splitedges)[3]; + int (*splitfaces)[4]; + int (*splitelements)[5]; + HPREF_ELEMENT_TYPE * neweltypes; + int (*newels)[8]; +}; + + + + +class HPRefElement +{ +public: + HPRefElement () + { + for (int i = 0; i < 8; i++) + { + pnums[i] = -1; + param[i][0] = param[i][1] = param[i][2] = 0; + } + } + HPREF_ELEMENT_TYPE type; + PointIndex pnums[8]; + double param[8][3]; + int index; + int level; + int coarse_elnr; + // EdgePointGeomInfo epgeominfo[2]; +}; + + + +extern void HPRefinement (Mesh & mesh, Refinement * ref, int levels); + + +#endif + + + + diff --git a/contrib/Netgen/libsrc/meshing/improve2.cpp b/contrib/Netgen/libsrc/meshing/improve2.cpp new file mode 100644 index 0000000000..af0ea0ca45 --- /dev/null +++ b/contrib/Netgen/libsrc/meshing/improve2.cpp @@ -0,0 +1,798 @@ +#include <mystdlib.h> + +#include "meshing.hpp" +#include <opti.hpp> + +#ifndef SMALLLIB +//#include <visual.hpp> +#endif + +namespace netgen +{ + +class Neighbour +{ + int nr[3]; + int orient[3]; + +public: + Neighbour () { nr[0] = nr[1] = nr[2] = -1; orient[0] = orient[1] = orient[2] = 0; } + + void SetNr (int side, int anr) { nr[side-1] = anr; } + int GetNr (int side) { return nr[side-1]; } + + void SetOrientation (int side, int aorient) { orient[side-1] = aorient; } + int GetOrientation (int side) { return orient[side-1]; } +}; + + + + +class trionedge +{ +public: + int tnr; + int sidenr; + + trionedge () { tnr = 0; sidenr = 0; } + trionedge (int atnr, int asidenr) + { tnr = atnr; sidenr = asidenr; } +}; + + + + +void MeshOptimize2d :: EdgeSwapping (Mesh & mesh, int usemetric) +{ + // return; + + if (!faceindex) + { + if (usemetric) + PrintMessage (3, "Edgeswapping, metric"); + else + PrintMessage (3, "Edgeswapping, topological"); + + for (faceindex = 1; faceindex <= mesh.GetNFD(); faceindex++) + { + EdgeSwapping (mesh, usemetric); + + if (multithread.terminate) + throw NgException ("Meshing stopped"); + } + + faceindex = 0; + mesh.CalcSurfacesOfNode(); + return; + } + + + int i, i2, j, k, j2; + bool should; + PointIndex pi; + + ARRAY<SurfaceElementIndex> seia; + mesh.GetSurfaceElementsOfFace (faceindex, seia); + + for (i = 0; i < seia.Size(); i++) + if (mesh[seia[i]].GetNP() != 3) + { + GenericImprove (mesh); + return; + } + + int surfnr = mesh.GetFaceDescriptor (faceindex).SurfNr(); + + ARRAY<Neighbour> neighbors(mesh.GetNSE()); + INDEX_2_HASHTABLE<trionedge> other(seia.Size() + 2); + + + ARRAY<char> swapped(mesh.GetNSE()); + ARRAY<int,PointIndex::BASE> pdef(mesh.GetNP()); + ARRAY<double,PointIndex::BASE> pangle(mesh.GetNP()); + + SurfaceElementIndex t1, t2; + int o1, o2; + + PointIndex pi1, pi2, pi3, pi4; + PointGeomInfo gi1, gi2, gi3, gi4; + + + int nswaps = 0; + int e, done; + double d; + Vec3d nv1, nv2; + double horder; + double loch; + static const double minangle[] = { 0, 1.481, 2.565, 3.627, 4.683, 5.736, 7, 9 }; + + pangle = 0; + + for (i = 0; i < seia.Size(); i++) + { + const Element2d & sel = mesh[seia[i]]; + for (j = 0; j < 3; j++) + { + POINTTYPE typ = mesh.PointType (sel[j]); + if (typ == FIXEDPOINT || typ == EDGEPOINT) + { + pangle[sel[j]] += + Angle (mesh[sel[(j+1)%3]] - mesh[sel[j]], + mesh[sel[(j+2)%3]] - mesh[sel[j]]); + } + } + } + + for (pi = PointIndex::BASE; + pi < mesh.GetNP()+PointIndex::BASE; pi++) + { + if (mesh.PointType(pi) == INNERPOINT || mesh.PointType(pi) == SURFACEPOINT) + pdef[pi] = -6; + else + for (j = 0; j < 8; j++) + if (pangle[pi] >= minangle[j]) + pdef[pi] = -1-j; + } + + for (i = 0; i < seia.Size(); i++) + { + const Element2d & sel = mesh[seia[i]]; + for (j = 0; j < 3; j++) + pdef[sel[j]]++; + } + + for (i = 0; i < seia.Size(); i++) + { + const Element2d & sel = mesh[seia[i]]; + for (j = 0; j < 3; j++) + { + neighbors[seia[i]].SetNr (j+1, -1); + neighbors[seia[i]].SetOrientation (j+1, 0); + } + } + + /* + ARRAY<Vec3d> normals(mesh.GetNP()); + for (i = 1; i <= mesh.GetNSE(); i++) + { + Element2d & hel = mesh.SurfaceElement(i); + if (hel.GetIndex() == faceindex) + for (k = 1; k <= 3; k++) + { + int pi = hel.PNum(k); + SelectSurfaceOfPoint (mesh.Point(pi), hel.GeomInfoPi(k)); + int surfi = mesh.GetFaceDescriptor(faceindex).SurfNr(); + GetNormalVector (surfi, mesh.Point(pi), normals.Elem(pi)); + normals.Elem(pi) /= normals.Elem(pi).Length(); + } + } + */ + + + for (i = 0; i < seia.Size(); i++) + { + const Element2d & sel = mesh[seia[i]]; + + for (j = 1; j <= 3; j++) + { + pi1 = sel.PNumMod(j+1); + pi2 = sel.PNumMod(j+2); + + loch = mesh.GetH(mesh[pi1]); + + INDEX_2 edge(pi1, pi2); + edge.Sort(); + + if (mesh.IsSegment (pi1, pi2)) + continue; + + /* + if (segments.Used (edge)) + continue; + */ + INDEX_2 ii2 (pi1, pi2); + if (other.Used (ii2)) + { + // INDEX_2 i2s(ii2); + // i2s.Sort(); + + i2 = other.Get(ii2).tnr; + j2 = other.Get(ii2).sidenr; + + neighbors[seia[i]].SetNr (j, i2); + neighbors[seia[i]].SetOrientation (j, j2); + neighbors[i2].SetNr (j2, seia[i]); + neighbors[i2].SetOrientation (j2, j); + } + else + { + other.Set (INDEX_2 (pi2, pi1), trionedge (seia[i], j)); + } + } + } + + for (i = 0; i < seia.Size(); i++) + swapped[seia[i]] = 0; + + + int t = 4; + done = 0; + while (!done && t >= 2) + { + for (i = 0; i < seia.Size(); i++) + { + t1 = seia[i]; + + if (mesh[t1].IsDeleted()) + continue; + + if (mesh[t1].GetIndex() != faceindex) + continue; + + if (multithread.terminate) + throw NgException ("Meshing stopped"); + + for (o1 = 1; o1 <= 3; o1++) + { + t2 = neighbors[t1].GetNr (o1); + o2 = neighbors[t1].GetOrientation (o1); + + if (t2 == -1) continue; + if (swapped[t1] || swapped[t2]) continue; + + + pi1 = mesh[t1].PNumMod(o1+1); + pi2 = mesh[t1].PNumMod(o1+2); + pi3 = mesh[t1].PNumMod(o1); + pi4 = mesh[t2].PNumMod(o2); + + gi1 = mesh[t1].GeomInfoPiMod(o1+1); + gi2 = mesh[t1].GeomInfoPiMod(o1+2); + gi3 = mesh[t1].GeomInfoPiMod(o1); + gi4 = mesh[t2].GeomInfoPiMod(o2); + + // normal of old (new ?????) + nv1 = Cross (mesh.Point(pi3)-mesh.Point(pi4), + mesh.Point(pi1)-mesh.Point(pi4)); + nv2 = Cross (mesh.Point(pi4)-mesh.Point(pi3), + mesh.Point(pi2)-mesh.Point(pi3)); + + + // normals of swapped original (???JS) + Vec3d nv3, nv4; + nv3 = Cross (mesh.Point(pi1)-mesh.Point(pi4), + mesh.Point(pi2)-mesh.Point(pi4)); + nv4 = Cross (mesh.Point(pi2)-mesh.Point(pi3), + mesh.Point(pi1)-mesh.Point(pi3)); + + nv3 *= -1; + nv4 *= -1; + nv3.Normalize(); + nv4.Normalize(); + + nv1.Normalize(); + nv2.Normalize(); + + Vec3d nvp3, nvp4; + SelectSurfaceOfPoint (mesh.Point(pi3), gi3); + GetNormalVector (surfnr, mesh.Point(pi3), gi3, nvp3); + + nvp3.Normalize(); + + SelectSurfaceOfPoint (mesh.Point(pi4), gi4); + GetNormalVector (surfnr, mesh.Point(pi4), gi4, nvp4); + + nvp4.Normalize(); + + + + double critval = cos (M_PI / 6); // 30 degree + bool allowswap = + (nv1 * nvp3 > critval) && + (nv1 * nvp4 > critval) && + (nv2 * nvp3 > critval) && + (nv2 * nvp4 > critval) && + (nvp3 * nv3 > critval) && + (nvp4 * nv4 > critval); + + + horder = Dist (mesh.Point(pi1), mesh.Point(pi2)); + + if ( // nv1 * nv2 >= 0 && + nv1.Length() > 1e-3 * horder * horder && + nv2.Length() > 1e-3 * horder * horder && + allowswap ) + { + if (!usemetric) + { + e = pdef[pi1] + pdef[pi2] - pdef[pi3] - pdef[pi4]; + d = + Dist2 (mesh.Point(pi1), mesh.Point(pi2)) - + Dist2 (mesh.Point(pi3), mesh.Point(pi4)); + + should = e >= t && (e > 2 || d > 0); + } + else + { + should = + CalcTriangleBadness (mesh.Point(pi4), mesh.Point(pi3), mesh.Point(pi1), + metricweight, loch) + + CalcTriangleBadness (mesh.Point(pi3), mesh.Point(pi4), mesh.Point(pi2), + metricweight, loch) < + CalcTriangleBadness (mesh.Point(pi1), mesh.Point(pi2), mesh.Point(pi3), + metricweight, loch) + + CalcTriangleBadness (mesh.Point(pi2), mesh.Point(pi1), mesh.Point(pi4), + metricweight, loch); + + } + + + if (allowswap) + { + Element2d sw1 (pi4, pi3, pi1); + Element2d sw2 (pi3, pi4, pi2); + + int legal1 = + mesh.LegalTrig (mesh.SurfaceElement (t1)) + + mesh.LegalTrig (mesh.SurfaceElement (t2)); + int legal2 = + mesh.LegalTrig (sw1) + mesh.LegalTrig (sw2); + + if (legal1 < legal2) should = 1; + if (legal2 < legal1) should = 0; + } + + if (should) + { + // do swapping ! + + // cout << "swap " << endl; + + nswaps ++; + + // testout << "nv1 = " << nv1 << " nv2 = " << nv2 << endl; + + done = 1; + + mesh[t1].PNum(1) = pi1; + mesh[t1].PNum(2) = pi4; + mesh[t1].PNum(3) = pi3; + + mesh[t2].PNum(1) = pi2; + mesh[t2].PNum(2) = pi3; + mesh[t2].PNum(3) = pi4; + + mesh[t1].GeomInfoPi(1) = gi1; + mesh[t1].GeomInfoPi(2) = gi4; + mesh[t1].GeomInfoPi(3) = gi3; + + mesh[t2].GeomInfoPi(1) = gi2; + mesh[t2].GeomInfoPi(2) = gi3; + mesh[t2].GeomInfoPi(3) = gi4; + + pdef[pi1]--; + pdef[pi2]--; + pdef[pi3]++; + pdef[pi4]++; + + swapped[t1] = 1; + swapped[t2] = 1; + } + } + } + } + t--; + } + + mesh.SetNextTimeStamp(); +} + + + + + + + + +void MeshOptimize2d :: CombineImprove (Mesh & mesh) +{ + if (!faceindex) + { + PrintMessage (3, "Combine improve"); + + for (faceindex = 1; faceindex <= mesh.GetNFD(); faceindex++) + { + CombineImprove (mesh); + + if (multithread.terminate) + throw NgException ("Meshing stopped"); + } + faceindex = 0; + return; + } + + + int i, j, k, l, i2, j2; + PointIndex pi; + SurfaceElementIndex sei; + + + ARRAY<SurfaceElementIndex> seia; + mesh.GetSurfaceElementsOfFace (faceindex, seia); + + + for (i = 0; i < seia.Size(); i++) + if (mesh[seia[i]].GetNP() != 3) + return; + + + + int surfnr = 0; + if (faceindex) + surfnr = mesh.GetFaceDescriptor (faceindex).SurfNr(); + + + int should; + PointIndex pi1, pi2; + MeshPoint p1, p2, pnew; + double bad1, bad2; + Vec3d nv; + + int np = mesh.GetNP(); + int nse = mesh.GetNSE(); + + TABLE<SurfaceElementIndex,PointIndex::BASE> elementsonnode(np); + ARRAY<SurfaceElementIndex> hasonepi, hasbothpi; + + for (i = 0; i < seia.Size(); i++) + { + Element2d & el = mesh[seia[i]]; + for (j = 0; j < el.GetNP(); j++) + { + elementsonnode.Add (el[j], seia[i]); + } + } + + + ARRAY<int,PointIndex::BASE> fixed(np); + fixed = 0; + + SegmentIndex si; + for (si = 0; si < mesh.GetNSeg(); si++) + { + INDEX_2 i2(mesh[si].p1, mesh[si].p2); + fixed[i2.I1()] = 1; + fixed[i2.I2()] = 1; + } + + + ARRAY<Vec3d,PointIndex::BASE> normals(np); + + for (pi = PointIndex::BASE; + pi < np + PointIndex::BASE; pi++) + { + if (elementsonnode[pi].Size()) + { + Element2d & hel = mesh[elementsonnode[pi][0]]; + for (k = 0; k < 3; k++) + if (hel[k] == pi) + { + SelectSurfaceOfPoint (mesh[pi], hel.GeomInfoPi(k+1)); + GetNormalVector (surfnr, mesh[pi], hel.GeomInfoPi(k+1), normals[pi]); + break; + } + if (k == 3) + { + cerr << "Neuer Fehler von Joachim, code 17121" << endl; + } + } + } + + + for (i = 0; i < seia.Size(); i++) + { + + sei = seia[i]; + Element2d & elem = mesh[sei]; + if (elem.IsDeleted()) continue; + + for (j = 0; j < 3; j++) + { + pi1 = elem[j]; + pi2 = elem[(j+1) % 3]; + + if (pi1 < PointIndex::BASE || + pi2 < PointIndex::BASE) + continue; + + /* + INDEX_2 i2(pi1, pi2); + i2.Sort(); + if (segmentht.Used(i2)) + continue; + */ + + bool debugflag = 0; + + if (debugflag) + { + (*testout) << "Combineimprove, face = " << faceindex + << "pi1 = " << pi1 << " pi2 = " << pi2 << endl; + } + + /* + // save version: + if (fixed.Get(pi1) || fixed.Get(pi2)) + continue; + if (pi2 < pi1) swap (pi1, pi2); + */ + + // more general + if (fixed[pi2]) + Swap (pi1, pi2); + + if (fixed[pi2]) + continue; + + double loch = mesh.GetH (mesh[pi1]); + + INDEX_2 si2 (pi1, pi2); + si2.Sort(); + + /* + if (edgetested.Used (si2)) + continue; + edgetested.Set (si2, 1); + */ + + hasonepi.SetSize(0); + hasbothpi.SetSize(0); + + for (k = 0; k < elementsonnode[pi1].Size(); k++) + { + const Element2d & el2 = mesh[elementsonnode[pi1][k]]; + + if (el2.IsDeleted()) continue; + + if (el2[0] == pi2 || el2[1] == pi2 || el2[2] == pi2) + { + hasbothpi.Append (elementsonnode[pi1][k]); + nv = Cross (Vec3d (mesh[el2[0]], mesh[el2[1]]), + Vec3d (mesh[el2[0]], mesh[el2[2]])); + } + else + { + hasonepi.Append (elementsonnode[pi1][k]); + } + } + + + Element2d & hel = mesh[hasbothpi[0]]; + for (k = 0; k < 3; k++) + if (hel[k] == pi1) + { + SelectSurfaceOfPoint (mesh[pi1], + hel.GeomInfoPi(k+1)); + GetNormalVector (surfnr, mesh[pi1], hel.GeomInfoPi(k+1), nv); + break; + } + if (k == 3) + { + cerr << "Neuer Fehler von Joachim, code 32434" << endl; + } + + + // nv = normals.Get(pi1); + + + + for (k = 0; k < elementsonnode[pi2].Size(); k++) + { + const Element2d & el2 = mesh[elementsonnode[pi2][k]]; + if (el2.IsDeleted()) continue; + + if (el2[0] == pi1 || el2[1] == pi1 || el2[2] == pi1) + ; + else + hasonepi.Append (elementsonnode[pi2][k]); + } + + bad1 = 0; + int illegal1 = 0, illegal2 = 0; + for (k = 0; k < hasonepi.Size(); k++) + { + const Element2d & el = mesh[hasonepi[k]]; + bad1 += CalcTriangleBadness (mesh[el[0]], mesh[el[1]], mesh[el[2]], + nv, -1, loch); + illegal1 += 1-mesh.LegalTrig(el); + } + + for (k = 0; k < hasbothpi.Size(); k++) + { + const Element2d & el = mesh[hasbothpi[k]]; + bad1 += CalcTriangleBadness (mesh[el[0]], mesh[el[1]], mesh[el[2]], + nv, -1, loch); + illegal1 += 1-mesh.LegalTrig(el); + } + bad1 /= (hasonepi.Size()+hasbothpi.Size()); + + p1 = mesh[pi1]; + p2 = mesh[pi2]; + + pnew = p1; + mesh[pi1] = pnew; + mesh[pi2] = pnew; + + bad2 = 0; + for (k = 0; k < hasonepi.Size(); k++) + { + Element2d & el = mesh[hasonepi[k]]; + double err = + CalcTriangleBadness (mesh[el[0]], mesh[el[1]], mesh[el[2]], + nv, -1, loch); + bad2 += err; + + Vec3d hnv = Cross (Vec3d (mesh[el[0]], + mesh[el[1]]), + Vec3d (mesh[el[0]], + mesh[el[2]])); + if (hnv * nv < 0) + bad2 += 1e10; + + for (l = 0; l < 3; l++) + if ( (normals[el[l]] * nv) < 0.5) + bad2 += 1e10; + + illegal2 += 1-mesh.LegalTrig(el); + } + bad2 /= hasonepi.Size(); + + mesh[pi1] = p1; + mesh[pi2] = p2; + + + if (debugflag) + { + (*testout) << "bad1 = " << bad1 << ", bad2 = " << bad2 << endl; + } + + + bool should = (bad2 < bad1 && bad2 < 1e4); + if (bad2 < 1e4) + { + if (illegal1 > illegal2) should = 1; + if (illegal2 > illegal1) should = 0; + } + + + if (should) + { + // (*testout) << "combine !" << endl; + // (*testout) << "bad1 = " << bad1 << ", bad2 = " << bad2 << endl; + + + mesh[pi1] = pnew; + PointGeomInfo gi; + bool gi_set(false); + + + Element2d *el1p; + l=0; + while(mesh[elementsonnode[pi1][l]].IsDeleted() && l<elementsonnode.EntrySize(pi1)) l++; + if(l<elementsonnode.EntrySize(pi1)) + el1p = &mesh[elementsonnode[pi1][l]]; + else + cerr << "OOPS!" << endl; + + for (l = 0; l < el1p->GetNP(); l++) + if ((*el1p)[l] == pi1) + { + gi = el1p->GeomInfoPi (l+1); + gi_set = true; + } + + // (*testout) << "Connect point " << pi2 << " to " << pi1 << "\n"; + for (k = 0; k < elementsonnode[pi2].Size(); k++) + { + Element2d & el = mesh[elementsonnode[pi2][k]]; + if(el.IsDeleted()) continue; + elementsonnode.Add (pi1, elementsonnode[pi2][k]); + + bool haspi1 = 0; + for (l = 0; l < el.GetNP(); l++) + if (el[l] == pi1) + haspi1 = 1; + if (haspi1) continue; + + for (l = 0; l < el.GetNP(); l++) + { + if (el[l] == pi2) + { + el[l] = pi1; + el.GeomInfoPi (l+1) = gi; + } + + fixed[el[l]] = 1; + } + } + + /* + for (k = 0; k < hasbothpi.Size(); k++) + { + cout << mesh[hasbothpi[k]] << endl; + for (l = 0; l < 3; l++) + cout << mesh[mesh[hasbothpi[k]][l]] << " "; + cout << endl; + } + */ + + for (k = 0; k < hasbothpi.Size(); k++) + { + mesh[hasbothpi[k]].Delete(); + /* + for (l = 0; l < 4; l++) + mesh[hasbothpi[k]][l] = PointIndex::BASE-1; + */ + } + + } + } + } + + // mesh.Compress(); + mesh.SetNextTimeStamp(); +} + + +void MeshOptimize2d :: CheckMeshApproximation (Mesh & mesh) +{ + // Check angles between elements and normals at corners + /* + + int i, j; + int ne = mesh.GetNSE(); + int surfnr; + + Vec3d n, ng; + ARRAY<Vec3d> ngs(3); + + (*mycout) << "Check Surface Approxiamtion" << endl; + (*testout) << "Check Surface Approxiamtion" << endl; + + for (i = 1; i <= ne; i++) + { + const Element2d & el = mesh.SurfaceElement(i); + surfnr = mesh.GetFaceDescriptor (el.GetIndex()).SurfNr(); + Vec3d n = Cross (mesh.Point (el.PNum(1)) - mesh.Point (el.PNum(2)), + mesh.Point (el.PNum(1)) - mesh.Point (el.PNum(3))); + n /= n.Length(); + + for (j = 1; j <= el.GetNP(); j++) + { + SelectSurfaceOfPoint (mesh.Point(el.PNum(j)), el.GeomInfoPi(j)); + GetNormalVector (surfnr, mesh.Point(el.PNum(j)), ng); + ng /= ng.Length(); + ngs.Elem(j) = ng; + + double angle = (180.0 / M_PI) * Angle (n, ng); + if (angle > 60) + { + (*testout) << "el " << i << " node " << el.PNum(j) + << "has angle = " << angle << endl; + } + } + + for (j = 1; j <= 3; j++) + { + double angle = (180.0 / M_PI) * Angle (ngs.Get(j), ngs.Get(j%3+1)); + if (angle > 60) + { + (*testout) << "el " << i << " node-node " + << ngs.Get(j) << " - " << ngs.Get(j%3+1) + << " has angle = " << angle << endl; + } + } + } + */ +} +} diff --git a/contrib/Netgen/libsrc/meshing/improve2.hpp b/contrib/Netgen/libsrc/meshing/improve2.hpp new file mode 100644 index 0000000000..0770a93b05 --- /dev/null +++ b/contrib/Netgen/libsrc/meshing/improve2.hpp @@ -0,0 +1,91 @@ +#ifndef FILE_IMPROVE2 +#define FILE_IMPROVE2 + + + +/// +class MeshOptimize2d +{ + int faceindex; + int improveedges; + double metricweight; + int writestatus; + +public: + /// + MeshOptimize2d (); + /// + void ImproveMesh (Mesh & mesh2d); + void ImproveMeshJacobian (Mesh & mesh2d); + + void EdgeSwapping (Mesh & mesh, int usemetric); + void CombineImprove (Mesh & mesh); + + void GenericImprove (Mesh & mesh); + + + void SetFaceIndex (int fi) { faceindex = fi; } + void SetImproveEdges (int ie) { improveedges = ie; } + void SetMetricWeight (double mw) { metricweight = mw; } + void SetWriteStatus (int ws) { writestatus = ws; } + + /// + virtual void SelectSurfaceOfPoint (const Point3d & p, + const PointGeomInfo & gi); + /// + virtual void ProjectPoint (INDEX /* surfind */, Point3d & /* p */) const { }; + /// + virtual void ProjectPoint2 (INDEX /* surfind */, INDEX /* surfind2 */, Point3d & /* p */) const { }; + /// liefert zu einem 3d-Punkt die geominfo (Dreieck) und liefert 1, wenn erfolgreich, + /// 0, wenn nicht (Punkt ausserhalb von chart) + virtual int CalcPointGeomInfo(PointGeomInfo& gi, const Point3d& /*p3*/) const + { gi.trignum = 1; return 1;}; + + virtual int CalcPointGeomInfo(int /* surfind */, PointGeomInfo& gi, const Point3d& p3) const + { return CalcPointGeomInfo (gi, p3); } + + /// + virtual void GetNormalVector(INDEX surfind, const Point3d & p, PointGeomInfo & gi, Vec3d & n) const; + virtual void GetNormalVector(INDEX surfind, const Point3d & p, Vec3d & n) const; + + void CheckMeshApproximation (Mesh & mesh); + + + /// + friend class Opti2SurfaceMinFunction; + /// + friend class Opti2EdgeMinFunction; + /// + friend double Opti2FunctionValueGrad (const Vector & x, Vector & grad); + /// + friend double Opti2EdgeFunctionValueGrad (const Vector & x, Vector & grad); + + + +}; + + +extern void CalcTriangleBadness (double x2, double x3, double y3, + double metricweight, + double h, double & badness, + double & g1x, double & g1y); + + + + +extern double CalcTriangleBadness (const Point3d & p1, + const Point3d & p2, + const Point3d & p3, + double metricweight, + double h); + +extern double CalcTriangleBadness (const Point3d & p1, + const Point3d & p2, + const Point3d & p3, + const Vec3d & n, + double metricweight, + double h); + +#endif + + diff --git a/contrib/Netgen/libsrc/meshing/improve2gen.cpp b/contrib/Netgen/libsrc/meshing/improve2gen.cpp new file mode 100644 index 0000000000..69f0e23b27 --- /dev/null +++ b/contrib/Netgen/libsrc/meshing/improve2gen.cpp @@ -0,0 +1,441 @@ +#include <mystdlib.h> + +#include "meshing.hpp" +#include <opti.hpp> + +namespace netgen +{ + + class ImprovementRule + { + public: + ARRAY<Element2d> oldels; + ARRAY<Element2d> newels; + ARRAY<INDEX_2> deledges; + ARRAY<int> incelsonnode; + ARRAY<int> reused; + int bonus; + int onp; + }; + + + void MeshOptimize2d :: GenericImprove (Mesh & mesh) + { + if (!faceindex) + { + if (writestatus) + PrintMessage (3, "Generic Improve"); + + for (faceindex = 1; faceindex <= mesh.GetNFD(); faceindex++) + GenericImprove (mesh); + + faceindex = 0; + } + + // int j, k, l, ri; + int np = mesh.GetNP(); + int ne = mesh.GetNSE(); + // SurfaceElementIndex sei; + + bool ok; + int olddef, newdef; + + ARRAY<ImprovementRule*> rules; + ARRAY<SurfaceElementIndex> elmap; + ARRAY<int> elrot; + ARRAY<PointIndex> pmap; + ARRAY<PointGeomInfo> pgi; + + int surfnr = mesh.GetFaceDescriptor (faceindex).SurfNr(); + + ImprovementRule * r1; + + // 2 triangles to quad + r1 = new ImprovementRule; + r1->oldels.Append (Element2d (1, 2, 3)); + r1->oldels.Append (Element2d (3, 2, 4)); + r1->newels.Append (Element2d (1, 2, 4, 3)); + r1->deledges.Append (INDEX_2 (2,3)); + r1->onp = 4; + r1->bonus = 2; + rules.Append (r1); + + // 2 quad to 1 quad + r1 = new ImprovementRule; + r1->oldels.Append (Element2d (1, 2, 3, 4)); + r1->oldels.Append (Element2d (4, 3, 2, 5)); + r1->newels.Append (Element2d (1, 2, 5, 4)); + r1->deledges.Append (INDEX_2 (2, 3)); + r1->deledges.Append (INDEX_2 (3, 4)); + r1->onp = 5; + r1->bonus = 0; + rules.Append (r1); + + // swap quads + r1 = new ImprovementRule; + r1->oldels.Append (Element2d (1, 2, 3, 4)); + r1->oldels.Append (Element2d (3, 2, 5, 6)); + r1->newels.Append (Element2d (1, 6, 3, 4)); + r1->newels.Append (Element2d (1, 2, 5, 6)); + r1->deledges.Append (INDEX_2 (2, 3)); + r1->onp = 6; + r1->bonus = 0; + rules.Append (r1); + + // three quads to 2 + r1 = new ImprovementRule; + r1->oldels.Append (Element2d (1, 2, 3, 4)); + r1->oldels.Append (Element2d (2, 5, 6, 3)); + r1->oldels.Append (Element2d (3, 6, 7, 4)); + r1->newels.Append (Element2d (1, 2, 5, 4)); + r1->newels.Append (Element2d (4, 5, 6, 7)); + r1->deledges.Append (INDEX_2 (2, 3)); + r1->deledges.Append (INDEX_2 (3, 4)); + r1->deledges.Append (INDEX_2 (3, 6)); + r1->onp = 7; + r1->bonus = -1; + rules.Append (r1); + + // quad + 2 connected trigs to quad + r1 = new ImprovementRule; + r1->oldels.Append (Element2d (1, 2, 3, 4)); + r1->oldels.Append (Element2d (2, 5, 3)); + r1->oldels.Append (Element2d (3, 5, 4)); + r1->newels.Append (Element2d (1, 2, 5, 4)); + r1->deledges.Append (INDEX_2 (2, 3)); + r1->deledges.Append (INDEX_2 (3, 4)); + r1->deledges.Append (INDEX_2 (3, 5)); + r1->onp = 5; + r1->bonus = 0; + rules.Append (r1); + + // quad + 2 non-connected trigs to quad (a and b) + r1 = new ImprovementRule; + r1->oldels.Append (Element2d (1, 2, 3, 4)); + r1->oldels.Append (Element2d (2, 6, 3)); + r1->oldels.Append (Element2d (1, 4, 5)); + r1->newels.Append (Element2d (1, 3, 4, 5)); + r1->newels.Append (Element2d (1, 2, 6, 3)); + r1->deledges.Append (INDEX_2 (1, 4)); + r1->deledges.Append (INDEX_2 (2, 3)); + r1->onp = 6; + r1->bonus = 0; + rules.Append (r1); + + r1 = new ImprovementRule; + r1->oldels.Append (Element2d (1, 2, 3, 4)); + r1->oldels.Append (Element2d (2, 6, 3)); + r1->oldels.Append (Element2d (1, 4, 5)); + r1->newels.Append (Element2d (1, 2, 4, 5)); + r1->newels.Append (Element2d (4, 2, 6, 3)); + r1->deledges.Append (INDEX_2 (1, 4)); + r1->deledges.Append (INDEX_2 (2, 3)); + r1->onp = 6; + r1->bonus = 0; + rules.Append (r1); + + // two quad + trig -> one quad + trig + r1 = new ImprovementRule; + r1->oldels.Append (Element2d (1, 2, 3, 4)); + r1->oldels.Append (Element2d (2, 5, 6, 3)); + r1->oldels.Append (Element2d (4, 3, 6)); + r1->newels.Append (Element2d (1, 2, 6, 4)); + r1->newels.Append (Element2d (2, 5, 6)); + r1->deledges.Append (INDEX_2 (2, 3)); + r1->deledges.Append (INDEX_2 (3, 4)); + r1->deledges.Append (INDEX_2 (3, 6)); + r1->onp = 6; + r1->bonus = -1; + rules.Append (r1); + + // swap quad + trig (a and b) + r1 = new ImprovementRule; + r1->oldels.Append (Element2d (1, 2, 3, 4)); + r1->oldels.Append (Element2d (2, 5, 3)); + r1->newels.Append (Element2d (2, 5, 3, 4)); + r1->newels.Append (Element2d (1, 2, 4)); + r1->deledges.Append (INDEX_2 (2, 3)); + r1->onp = 5; + r1->bonus = 0; + rules.Append (r1); + + r1 = new ImprovementRule; + r1->oldels.Append (Element2d (1, 2, 3, 4)); + r1->oldels.Append (Element2d (2, 5, 3)); + r1->newels.Append (Element2d (1, 2, 5, 3)); + r1->newels.Append (Element2d (1, 3, 4)); + r1->deledges.Append (INDEX_2 (2, 3)); + r1->onp = 5; + r1->bonus = 0; + rules.Append (r1); + + + // 2 quads to quad + 2 trigs + r1 = new ImprovementRule; + r1->oldels.Append (Element2d (1, 2, 3, 4)); + r1->oldels.Append (Element2d (3, 2, 5, 6)); + r1->newels.Append (Element2d (1, 5, 6, 4)); + r1->newels.Append (Element2d (1, 2, 5)); + r1->newels.Append (Element2d (4, 6, 3)); + r1->deledges.Append (INDEX_2 (2, 3)); + r1->onp = 6; + r1->bonus = 0; + // rules.Append (r1); + + + + + ARRAY<int> mapped(rules.Size()); + ARRAY<int> used(rules.Size()); + used = 0; + mapped = 0; + + + + for (int ri = 0; ri < rules.Size(); ri++) + { + ImprovementRule & rule = *rules[ri]; + rule.incelsonnode.SetSize (rule.onp); + rule.reused.SetSize (rule.onp); + + for (int j = 1; j <= rule.onp; j++) + { + rule.incelsonnode.Elem(j) = 0; + rule.reused.Elem(j) = 0; + } + + for (int j = 1; j <= rule.oldels.Size(); j++) + { + const Element2d & el = rule.oldels.Elem(j); + for (int k = 1; k <= el.GetNP(); k++) + rule.incelsonnode.Elem(el.PNum(k))--; + } + + for (int j = 1; j <= rule.newels.Size(); j++) + { + const Element2d & el = rule.newels.Elem(j); + for (int k = 1; k <= el.GetNP(); k++) + { + rule.incelsonnode.Elem(el.PNum(k))++; + rule.reused.Elem(el.PNum(k)) = 1; + } + } + } + + + + + TABLE<int,PointIndex::BASE> elonnode(np); + ARRAY<int,PointIndex::BASE> nelonnode(np); + TABLE<SurfaceElementIndex> nbels(ne); + + nelonnode = -4; + + for (SurfaceElementIndex sei = 0; sei < ne; sei++) + { + const Element2d & el = mesh[sei]; + if (el.GetIndex() == faceindex && !el.IsDeleted()) + { + for (int j = 0; j < el.GetNP(); j++) + elonnode.Add (el[j], sei); + } + 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]; + int used = 0; + for (int l = 0; l < nbels[sei].Size(); l++) + if (nbels[sei][l] == nbel) + used = 1; + if (!used) + nbels.Add (sei, nbel); + } + } + } + } + + + for (int ri = 0; ri < rules.Size(); ri++) + { + const ImprovementRule & rule = *rules[ri]; + + elmap.SetSize (rule.oldels.Size()); + elrot.SetSize (rule.oldels.Size()); + pmap.SetSize (rule.onp); + pgi.SetSize (rule.onp); + + + for (SurfaceElementIndex sei = 0; sei < ne; sei++) + { + if (multithread.terminate) + break; + if (mesh[sei].IsDeleted()) continue; + + elmap[0] = sei; + FlatArray<SurfaceElementIndex> neighbours = nbels[sei]; + + for (elrot[0] = 0; elrot[0] < mesh[sei].GetNP(); elrot[0]++) + { + const Element2d & el0 = mesh[sei]; + const Element2d & rel0 = rule.oldels[0]; + + if (el0.GetIndex() != faceindex) continue; + if (el0.IsDeleted()) continue; + if (el0.GetNP() != rel0.GetNP()) continue; + + + pmap = -1; + + for (int k = 0; k < el0.GetNP(); k++) + { + pmap.Elem(rel0[k]) = el0.PNumMod(k+elrot[0]+1); + pgi.Elem(rel0[k]) = el0.GeomInfoPiMod(k+elrot[0]+1); + } + + ok = 1; + for (int i = 1; i < elmap.Size(); i++) + { + // try to find a mapping for reference-element i + + const Element2d & rel = rule.oldels[i]; + bool possible = 0; + + for (elmap[i] = 0; elmap[i] < neighbours.Size(); elmap[i]++) + { + const Element2d & el = mesh[neighbours[elmap[i]]]; + if (el.IsDeleted()) continue; + if (el.GetNP() != rel.GetNP()) continue; + + for (elrot[i] = 0; elrot[i] < rel.GetNP(); elrot[i]++) + { + possible = 1; + + for (int k = 0; k < rel.GetNP(); k++) + if (pmap.Elem(rel[k]) != -1 && + pmap.Elem(rel[k]) != el.PNumMod (k+elrot[i]+1)) + possible = 0; + + if (possible) + { + for (int k = 0; k < el.GetNP(); k++) + { + pmap.Elem(rel[k]) = el.PNumMod(k+elrot[i]+1); + pgi.Elem(rel[k]) = el.GeomInfoPiMod(k+elrot[i]+1); + } + break; + } + } + if (possible) break; + } + + if (!possible) + { + ok = 0; + break; + } + + elmap[i] = neighbours[elmap[i]]; + } + + for(int i=0; ok && i<rule.deledges.Size(); i++) + { + ok = !mesh.IsSegment(pmap.Elem(rule.deledges[i].I1()), + pmap.Elem(rule.deledges[i].I2())); + } + + + + + if (!ok) continue; + + mapped[ri]++; + + olddef = 0; + for (int j = 1; j <= pmap.Size(); j++) + olddef += sqr (nelonnode[pmap.Get(j)]); + olddef += rule.bonus; + + newdef = 0; + for (int j = 1; j <= pmap.Size(); j++) + if (rule.reused.Get(j)) + newdef += sqr (nelonnode[pmap.Get(j)] + + rule.incelsonnode.Get(j)); + + if (newdef > olddef) + continue; + + // calc metric badness + double bad1 = 0, bad2 = 0; + Vec3d n; + + SelectSurfaceOfPoint (mesh.Point(pmap.Get(1)), pgi.Get(1)); + GetNormalVector (surfnr, mesh.Point(pmap.Get(1)), pgi.Elem(1), n); + + for (int j = 1; j <= rule.oldels.Size(); j++) + bad1 += mesh.SurfaceElement(elmap.Get(j)).CalcJacobianBadness (mesh.Points(), n); + + // check new element: + for (int j = 1; j <= rule.newels.Size(); j++) + { + const Element2d & rnel = rule.newels.Get(j); + Element2d nel(rnel.GetNP()); + for (int k = 1; k <= rnel.GetNP(); k++) + nel.PNum(k) = pmap.Get(rnel.PNum(k)); + + bad2 += nel.CalcJacobianBadness (mesh.Points(), n); + } + + if (bad2 > 1e3) continue; + + if (newdef == olddef && bad2 > bad1) continue; + + + // generate new element: + for (int j = 1; j <= rule.newels.Size(); j++) + { + const Element2d & rnel = rule.newels.Get(j); + Element2d nel(rnel.GetNP()); + nel.SetIndex (faceindex); + for (int k = 1; k <= rnel.GetNP(); k++) + { + nel.PNum(k) = pmap.Get(rnel.PNum(k)); + nel.GeomInfoPi(k) = pgi.Get(rnel.PNum(k)); + } + + mesh.AddSurfaceElement(nel); + } + + for (int j = 0; j < rule.oldels.Size(); j++) + mesh.DeleteSurfaceElement ( elmap[j] ); + + for (int j = 1; j <= pmap.Size(); j++) + nelonnode[pmap.Get(j)] += rule.incelsonnode.Get(j); + + used[ri]++; + } + } + } + + mesh.Compress(); + + for (int ri = 0; ri < rules.Size(); ri++) + { + PrintMessage (5, "rule ", ri+1, " ", + mapped[ri], "/", used[ri], " mapped/used"); + } + } + + + + +} diff --git a/contrib/Netgen/libsrc/meshing/improve3.cpp b/contrib/Netgen/libsrc/meshing/improve3.cpp new file mode 100644 index 0000000000..1b9c8c52f6 --- /dev/null +++ b/contrib/Netgen/libsrc/meshing/improve3.cpp @@ -0,0 +1,1947 @@ +#include <mystdlib.h> + +#include "meshing.hpp" + +#ifdef SOLIDGEOM +#include <csg.hpp> +#endif +#include <opti.hpp> + +namespace netgen +{ + +/* + Combine two points to one. + Set new point into the center, if both are + inner points. + Connect inner point to boundary point, if one + point is inner point. +*/ + +void MeshOptimize3d :: CombineImprove (Mesh & mesh, + OPTIMIZEGOAL goal) +{ + int np = mesh.GetNP(); + int ne = mesh.GetNE(); + + TABLE<ElementIndex, PointIndex::BASE> elementsonnode(np); + ARRAY<ElementIndex> hasonepi, hasbothpi; + + ARRAY<double> oneperr; + ARRAY<double> elerrs (ne); + + PrintMessage (3, "CombineImprove"); + (*testout) << "Start CombineImprove" << "\n"; + + // mesh.CalcSurfacesOfNode (); + char * savetask = multithread.task; + multithread.task = "Combine Improve"; + + + double totalbad = 0; + for (ElementIndex ei = 0; ei < ne; ei++) + { + double elerr = CalcBad (mesh.Points(), mesh[ei], 0); + totalbad += elerr; + elerrs[ei] = elerr; + } + + if (goal == OPT_QUALITY) + { + totalbad = CalcTotalBad (mesh.Points(), mesh.VolumeElements()); + (*testout) << "Total badness = " << totalbad << endl; + PrintMessage (5, "Total badness = ", totalbad); + } + + for (ElementIndex ei = 0; ei < ne; ei++) + if (!mesh[ei].IsDeleted()) + for (int j = 0; j < mesh[ei].GetNP(); j++) + elementsonnode.Add (mesh[ei][j], ei); + + INDEX_2_HASHTABLE<int> edgetested (np+1); + + int cnt = 0; + + for (ElementIndex ei = 0; ei < ne; ei++) + { + if (multithread.terminate) + break; + + multithread.percent = 100.0 * (ei+1) / ne; + + if (mesh.ElementType(ei) == FIXEDELEMENT) + continue; + + for (int j = 0; j < 6; j++) + { + Element & elemi = mesh[ei]; + if (elemi.IsDeleted()) continue; + + static const int tetedges[6][2] = + { { 0, 1 }, { 0, 2 }, { 0, 3 }, + { 1, 2 }, { 1, 3 }, { 2, 3 } }; + + PointIndex pi1 = elemi[tetedges[j][0]]; + PointIndex pi2 = elemi[tetedges[j][1]]; + + if (pi2 < pi1) Swap (pi1, pi2); + + INDEX_2 si2 (pi1, pi2); + si2.Sort(); + + if (edgetested.Used (si2)) continue; + edgetested.Set (si2, 1); + + + // hasonepoint.SetSize(0); + // hasbothpoints.SetSize(0); + hasonepi.SetSize(0); + hasbothpi.SetSize(0); + + FlatArray<ElementIndex> row1 = elementsonnode[pi1]; + for (int k = 0; k < row1.Size(); k++) + { + Element & elem = mesh[row1[k]]; + if (elem.IsDeleted()) continue; + + if (elem[0] == pi2 || elem[1] == pi2 || + elem[2] == pi2 || elem[3] == pi2) + { + hasbothpi.Append (row1[k]); + } + else + { + hasonepi.Append (row1[k]); + } + } + + FlatArray<ElementIndex> row2 = elementsonnode[pi2]; + for (int k = 0; k < row2.Size(); k++) + { + Element & elem = mesh[row2[k]]; + if (elem.IsDeleted()) continue; + + if (elem[0] == pi1 || elem[1] == pi1 || + elem[2] == pi1 || elem[3] == pi1) + ; + else + { + hasonepi.Append (row2[k]); + } + } + + double bad1 = 0; + for (int k = 0; k < hasonepi.Size(); k++) + bad1 += elerrs[hasonepi[k]]; + for (int k = 0; k < hasbothpi.Size(); k++) + bad1 += elerrs[hasbothpi[k]]; + + MeshPoint p1 = mesh[pi1]; + MeshPoint p2 = mesh[pi2]; + + // if (mesh.PointType(pi2) != INNERPOINT) + if (p2.Type() != INNERPOINT) + continue; + + MeshPoint pnew; + // if (mesh.PointType(pi1) != INNERPOINT) + if (p1.Type() != INNERPOINT) + pnew = p1; + else + pnew = Center (p1, p2); + + mesh[pi1] = pnew; + mesh[pi2] = pnew; + + oneperr.SetSize (hasonepi.Size()); + + double bad2 = 0; + for (int k = 0; k < hasonepi.Size(); k++) + { + const Element & elem = mesh[hasonepi[k]]; + double err = CalcTetBadness (mesh[elem[0]], mesh[elem[1]], + mesh[elem[2]], mesh[elem[3]], 0); + bad2 += err; + oneperr[k] = err; + } + + mesh[pi1] = p1; + mesh[pi2] = p2; + + + // if (mesh.PointType(pi1) != INNERPOINT) + if (p1.Type() != INNERPOINT) + { + for (int k = 0; k < hasonepi.Size(); k++) + { + Element & elem = mesh[hasonepi[k]]; + int l; + for (l = 0; l < 4; l++) + if (elem[l] == pi2) + { + elem[l] = pi1; + break; + } + + elem.flags.illegal_valid = 0; + if (!mesh.LegalTet(elem)) + bad2 += 1e4; + + if (l < 4) + { + elem.flags.illegal_valid = 0; + elem[l] = pi2; + } + } + } + + if (bad2 / hasonepi.Size() < + bad1 / (hasonepi.Size()+hasbothpi.Size())) + { + mesh[pi1] = pnew; + cnt++; + + FlatArray<ElementIndex> row = elementsonnode[pi2]; + for (int k = 0; k < row.Size(); k++) + { + Element & elem = mesh[row[k]]; + if (elem.IsDeleted()) continue; + + elementsonnode.Add (pi1, row[k]); + for (int l = 0; l < elem.GetNP(); l++) + if (elem[l] == pi2) + elem[l] = pi1; + + elem.flags.illegal_valid = 0; + if (!mesh.LegalTet (elem)) + (*testout) << "illegal tet " << elementsonnode[pi2][k] << endl; + } + + for (int k = 0; k < hasonepi.Size(); k++) + elerrs[hasonepi[k]] = oneperr[k]; + + for (int k = 0; k < hasbothpi.Size(); k++) + { + mesh[hasbothpi[k]].flags.illegal_valid = 0; + mesh[hasbothpi[k]].Delete(); + } + } + } + } + + mesh.Compress(); + mesh.MarkIllegalElements(); + + PrintMessage (5, cnt, " elements combined"); + (*testout) << "CombineImprove done" << "\n"; + + totalbad = 0; + for (ElementIndex ei = 0; ei < mesh.GetNE(); ei++) + totalbad += CalcBad (mesh.Points(), mesh[ei], 0); + + if (goal == OPT_QUALITY) + { + totalbad = CalcTotalBad (mesh.Points(), mesh.VolumeElements()); + (*testout) << "Total badness = " << totalbad << endl; + + int cntill = 0; + int ne = mesh.GetNE(); + for (ElementIndex ei = 0; ei < ne; ei++) + if (!mesh.LegalTet (mesh[ei])) + cntill++; + + PrintMessage (5, cntill, " illegal tets"); + } + multithread.task = savetask; +} + + + + + +/* + Mesh improvement by edge splitting. + If mesh quality is improved by inserting a node into an inner edge, + the edge is split into two parts. +*/ +void MeshOptimize3d :: SplitImprove (Mesh & mesh, + OPTIMIZEGOAL goal) +{ + int j, k, l; + Point3d p1, p2, pnew; + + ElementIndex ei; + SurfaceElementIndex sei; + PointIndex pi1, pi2; + + double bad1, bad2, badmax, badlimit; + + + int cnt = 0; + int np = mesh.GetNP(); + int ne = mesh.GetNE(); + + TABLE<ElementIndex,PointIndex::BASE> elementsonnode(np); + ARRAY<ElementIndex> hasbothpoints; + + BitArray origpoint(np), boundp(np); + origpoint.Set(); + + ARRAY<double> elerrs(ne); + BitArray illegaltet(ne); + illegaltet.Clear(); + + char * savetask = multithread.task; + multithread.task = "Split Improve"; + + + PrintMessage (3, "SplitImprove"); + (*testout) << "start SplitImprove" << "\n"; + + ARRAY<INDEX_3> locfaces; + + INDEX_2_HASHTABLE<int> edgetested (np); + + bad1 = 0; + badmax = 0; + for (ei = 0; ei < ne; ei++) + { + elerrs[ei] = CalcBad (mesh.Points(), mesh[ei], 0); + bad1 += elerrs[ei]; + if (elerrs[ei] > badmax) badmax = elerrs[ei]; + } + + PrintMessage (5, "badmax = ", badmax); + badlimit = 0.5 * badmax; + + + boundp.Clear(); + for (sei = 0; sei < mesh.GetNSE(); sei++) + for (j = 0; j < 3; j++) + boundp.Set (mesh[sei][j]); + + if (goal == OPT_QUALITY) + { + bad1 = CalcTotalBad (mesh.Points(), mesh.VolumeElements()); + (*testout) << "Total badness = " << bad1 << endl; + } + + for (ei = 0; ei < ne; ei++) + for (j = 0; j < mesh[ei].GetNP(); j++) + elementsonnode.Add (mesh[ei][j], ei); + + + mesh.MarkIllegalElements(); + if (goal == OPT_QUALITY || goal == OPT_LEGAL) + { + int cntill = 0; + for (ei = 0; ei < ne; ei++) + { + // if (!LegalTet (volelements.Get(i))) + if (mesh[ei].flags.illegal) + { + cntill++; + illegaltet.Set (ei+1); + } + } + // (*mycout) << cntill << " illegal tets" << endl; + } + + + for (ei = 0; ei < ne; ei++) + { + if (multithread.terminate) + break; + + multithread.percent = 100.0 * (ei+1) / ne; + + bool ltestmode = 0; + + + if (elerrs[ei] < badlimit && !illegaltet.Test(ei+1)) continue; + + if ((goal == OPT_LEGAL) && + !illegaltet.Test(ei+1) && + CalcBad (mesh.Points(), mesh[ei], 0) < 1e3) + continue; + + + Element & elem = mesh[ei]; + + if (ltestmode) + { + (*testout) << "test el " << ei << endl; + for (j = 0; j < 4; j++) + (*testout) << elem[j] << " "; + (*testout) << endl; + } + + + for (j = 0; j < 6; j++) + { + + static const int tetedges[6][2] = + { { 0, 1 }, { 0, 2 }, { 0, 3 }, + { 1, 2 }, { 1, 3 }, { 2, 3 } }; + + pi1 = elem[tetedges[j][0]]; + pi2 = elem[tetedges[j][1]]; + + if (pi2 < pi1) Swap (pi1, pi2); + if (pi2 > elementsonnode.Size()) continue; + + if (!origpoint.Test(pi1) || !origpoint.Test(pi2)) + continue; + + + INDEX_2 i2(pi1, pi2); + i2.Sort(); + + if (mesh.BoundaryEdge (pi1, pi2)) continue; + + if (edgetested.Used (i2) && !illegaltet.Test(ei+1)) continue; + edgetested.Set (i2, 1); + + hasbothpoints.SetSize (0); + for (k = 1; k <= elementsonnode.EntrySize(pi1); k++) + { + bool has1 = 0, has2 = 0; + + ElementIndex elnr = elementsonnode.Get(pi1, k); + Element & el = mesh[elnr]; + + for (l = 0; l < el.GetNP(); l++) + { + if (el[l] == pi1) has1 = 1; + if (el[l] == pi2) has2 = 1; + } + if (has1 && has2) + { // only once + for (l = 0; l < hasbothpoints.Size(); l++) + if (hasbothpoints[l] == elnr) + has1 = 0; + + if (has1) + hasbothpoints.Append (elnr); + } + } + + bad1 = 0; + for (k = 0; k < hasbothpoints.Size(); k++) + bad1 += CalcBad (mesh.Points(), mesh[hasbothpoints[k]], 0); + + + bool puretet = 1; + for (k = 0; k < hasbothpoints.Size(); k++) + if (mesh[hasbothpoints[k]].GetType() != TET) + puretet = 0; + if (!puretet) continue; + + p1 = mesh[pi1]; + p2 = mesh[pi2]; + + /* + pnew = Center (p1, p2); + + points.Elem(pi1) = pnew; + bad2 = 0; + for (k = 1; k <= hasbothpoints.Size(); k++) + bad2 += CalcBad (points, + volelements.Get(hasbothpoints.Get(k)), 0); + + points.Elem(pi1) = p1; + points.Elem(pi2) = pnew; + + for (k = 1; k <= hasbothpoints.Size(); k++) + bad2 += CalcBad (points, + volelements.Get(hasbothpoints.Get(k)), 0); + points.Elem(pi2) = p2; + */ + + + locfaces.SetSize (0); + for (k = 0; k < hasbothpoints.Size(); k++) + { + const Element & el = mesh[hasbothpoints[k]]; + + for (int l = 0; l < 4; l++) + if (el[l] == pi1 || el[l] == pi2) + { + INDEX_3 i3; + Element2d face; + el.GetFace (l+1, face); + for (int kk = 1; kk <= 3; kk++) + i3.I(kk) = face.PNum(kk); + locfaces.Append (i3); + } + } + + PointFunction1 pf (mesh.Points(), locfaces, -1); + OptiParameters par; + par.maxit_linsearch = 50; + par.maxit_bfgs = 20; + + pnew = Center (p1, p2); + Vector px(3); + px.Elem(1) = pnew.X(); + px.Elem(2) = pnew.Y(); + px.Elem(3) = pnew.Z(); + + if (elerrs[ei] > 0.1 * badmax) + BFGS (px, pf, par); + + bad2 = pf.Func (px); + + pnew.X() = px.Get(1); + pnew.Y() = px.Get(2); + pnew.Z() = px.Get(3); + + + int hpinew = mesh.AddPoint (pnew); + // ptyps.Append (INNERPOINT); + + for (k = 0; k < hasbothpoints.Size(); k++) + { + Element & oldel = mesh[hasbothpoints[k]]; + Element newel1 = oldel; + Element newel2 = oldel; + + oldel.flags.illegal_valid = 0; + newel1.flags.illegal_valid = 0; + newel2.flags.illegal_valid = 0; + + for (l = 0; l < 4; l++) + { + if (newel1[l] == pi2) newel1[l] = hpinew; + if (newel2[l] == pi1) newel2[l] = hpinew; + } + + if (!mesh.LegalTet (oldel)) bad1 += 1e6; + if (!mesh.LegalTet (newel1)) bad2 += 1e6; + if (!mesh.LegalTet (newel2)) bad2 += 1e6; + } + + // mesh.PointTypes().DeleteLast(); + mesh.Points().DeleteLast(); + + if (bad2 < bad1) + /* (bad1 > 1e4 && boundp.Test(pi1) && boundp.Test(pi2)) */ + { + cnt++; + + PointIndex pinew = mesh.AddPoint (pnew); + + for (k = 0; k < hasbothpoints.Size(); k++) + { + Element & oldel = mesh[hasbothpoints[k]]; + Element newel = oldel; + + newel.flags.illegal_valid = 0; + oldel.flags.illegal_valid = 0; + + for (l = 0; l < 4; l++) + { + origpoint.Clear (oldel[l]); + + if (oldel[l] == pi2) oldel[l] = pinew; + if (newel[l] == pi1) newel[l] = pinew; + } + mesh.AddVolumeElement (newel); + } + + j = 10; + } + } + } + + + mesh.Compress(); + PrintMessage (5, cnt, " splits performed"); + + (*testout) << "Splitt - Improve done" << "\n"; + + if (goal == OPT_QUALITY) + { + bad1 = CalcTotalBad (mesh.Points(), mesh.VolumeElements()); + (*testout) << "Total badness = " << bad1 << endl; + + int cntill = 0; + ne = mesh.GetNE(); + for (ei = 0; ei < ne; ei++) + { + if (!mesh.LegalTet (mesh[ei])) + cntill++; + } + // cout << cntill << " illegal tets" << endl; + } + + multithread.task = savetask; +} + + + + + +void MeshOptimize3d :: SwapImprove (Mesh & mesh, OPTIMIZEGOAL goal) +{ + int j, k, l; + + ElementIndex ei; + SurfaceElementIndex sei; + + PointIndex pi1, pi2, pi3, pi4, pi5, pi6; + int cnt = 0; + + Element el21(TET), el22(TET), el31(TET), el32(TET), el33(TET); + Element el1(TET), el2(TET), el3(TET), el4(TET); + Element el1b(TET), el2b(TET), el3b(TET), el4b(TET); + + double bad1, bad2, bad3; + + int np = mesh.GetNP(); + int ne = mesh.GetNE(); + int nse = mesh.GetNSE(); + + + // contains at least all elements at node + TABLE<ElementIndex,PointIndex::BASE> elementsonnode(np); + + ARRAY<ElementIndex> hasbothpoints; + + PrintMessage (3, "SwapImprove "); + (*testout) << "\n" << "Start SwapImprove" << endl; + + char * savetask = multithread.task; + multithread.task = "Swap Improve"; + + // mesh.CalcSurfacesOfNode (); + /* + for (i = 1; i <= GetNE(); i++) + if (volelements.Get(i).PNum(1)) + if (!LegalTet (volelements.Get(i))) + { + cout << "detected illegal tet, 1" << endl; + (*testout) << "detected illegal tet1: " << i << endl; + } + */ + + + INDEX_3_HASHTABLE<int> faces(mesh.GetNOpenElements()/3 + 2); + if (goal == OPT_CONFORM) + { + for (int i = 1; i <= mesh.GetNOpenElements(); i++) + { + const Element2d & hel = mesh.OpenElement(i); + INDEX_3 face(hel[0], hel[1], hel[2]); + face.Sort(); + faces.Set (face, 1); + } + } + + // Calculate total badness + if (goal == OPT_QUALITY) + { + bad1 = CalcTotalBad (mesh.Points(), mesh.VolumeElements()); + (*testout) << "Total badness = " << bad1 << endl; + } + + // find elements on node + for (ei = 0; ei < ne; ei++) + for (j = 0; j < mesh[ei].GetNP(); j++) + elementsonnode.Add (mesh[ei][j], ei); + + /* + BitArray illegaltet(GetNE()); + MarkIllegalElements(); + if (goal == OPT_QUALITY || goal == OPT_LEGAL) + { + int cntill = 0; + for (i = 1; i <= GetNE(); i++) + { + // if (!LegalTet (volelements.Get(i))) + if (VolumeElement(i).flags.illegal) + { + cntill++; + illegaltet.Set (i); + } + } + // (*mycout) << cntill << " illegal tets" << endl; + } + */ + + INDEX_2_HASHTABLE<int> edgeused(2 * ne + 5); + + for (ei = 0; ei < ne; ei++) + { + if (multithread.terminate) + break; + + multithread.percent = 100.0 * (ei+1) / ne; + + if (mesh.ElementType(ei) == FIXEDELEMENT) + continue; + + if (mesh[ei].IsDeleted()) + continue; + + if ((goal == OPT_LEGAL) && + mesh.LegalTet (mesh[ei]) && + CalcBad (mesh.Points(), mesh[ei], 0) < 1e3) + continue; + + + // int onlybedges = 1; + + for (j = 0; j < 6; j++) + { + // loop over edges + + const Element & elemi = mesh[ei]; + if (elemi.IsDeleted()) continue; + + + // (*testout) << "check element " << elemi << endl; + + int mattyp = elemi.GetIndex(); + + static const int tetedges[6][2] = + { { 0, 1 }, { 0, 2 }, { 0, 3 }, + { 1, 2 }, { 1, 3 }, { 2, 3 } }; + + pi1 = elemi[tetedges[j][0]]; + pi2 = elemi[tetedges[j][1]]; + + if (pi2 < pi1) Swap (pi1, pi2); + + if (mesh.BoundaryEdge (pi1, pi2)) continue; + + + INDEX_2 i2 (pi1, pi2); + i2.Sort(); + if (edgeused.Used(i2)) continue; + edgeused.Set (i2, 1); + + hasbothpoints.SetSize (0); + for (k = 0; k < elementsonnode[pi1].Size(); k++) + { + bool has1 = 0, has2 = 0; + ElementIndex elnr = elementsonnode[pi1][k]; + const Element & elem = mesh[elnr]; + + if (elem.IsDeleted()) continue; + + for (l = 0; l < elem.GetNP(); l++) + { + if (elem[l] == pi1) has1 = 1; + if (elem[l] == pi2) has2 = 1; + } + + if (has1 && has2) + { // only once + for (l = 0; l < hasbothpoints.Size(); l++) + if (hasbothpoints[l] == elnr) + has1 = 0; + + if (has1) + hasbothpoints.Append (elnr); + } + } + + bool puretet = 1; + for (k = 0; k < hasbothpoints.Size(); k++) + if (mesh[hasbothpoints[k]].GetType () != TET) + puretet = 0; + if (!puretet) + continue; + + int nsuround = hasbothpoints.Size(); + + if ( nsuround == 3 ) + { + Element & elem = mesh[hasbothpoints[0]]; + for (l = 0; l < 4; l++) + if (elem[l] != pi1 && elem[l] != pi2) + { + pi4 = pi3; + pi3 = elem[l]; + } + + el31[0] = pi1; + el31[1] = pi2; + el31[2] = pi3; + el31[3] = pi4; + el31.SetIndex (mattyp); + + if (WrongOrientation (mesh.Points(), el31)) + { + Swap (pi3, pi4); + el31[2] = pi3; + el31[3] = pi4; + } + + pi5 = 0; + for (k = 1; k < 3; k++) + { + const Element & elem = mesh[hasbothpoints[k]]; + bool has1 = 0; + for (l = 0; l < 4; l++) + if (elem[l] == pi4) + has1 = 1; + if (has1) + { + for (l = 0; l < 4; l++) + if (elem[l] != pi1 && elem[l] != pi2 && elem[l] != pi4) + pi5 = elem[l]; + } + } + + el32[0] = pi1; + el32[1] = pi2; + el32[2] = pi4; + el32[3] = pi5; + el32.SetIndex (mattyp); + + el33[0] = pi1; + el33[1] = pi2; + el33[2] = pi5; + el33[3] = pi3; + el33.SetIndex (mattyp); + + elementsonnode.Add (pi4, hasbothpoints[1]); + elementsonnode.Add (pi3, hasbothpoints[2]); + + bad1 = CalcBad (mesh.Points(), el31, 0) + + CalcBad (mesh.Points(), el32, 0) + + CalcBad (mesh.Points(), el33, 0); + + el31.flags.illegal_valid = 0; + el32.flags.illegal_valid = 0; + el33.flags.illegal_valid = 0; + + if (!mesh.LegalTet(el31) || + !mesh.LegalTet(el32) || + !mesh.LegalTet(el33)) + bad1 += 1e4; + + el21[0] = pi3; + el21[1] = pi4; + el21[2] = pi5; + el21[3] = pi2; + el21.SetIndex (mattyp); + + el22[0] = pi5; + el22[1] = pi4; + el22[2] = pi3; + el22[3] = pi1; + el22.SetIndex (mattyp); + + bad2 = CalcBad (mesh.Points(), el21, 0) + + CalcBad (mesh.Points(), el22, 0); + + el21.flags.illegal_valid = 0; + el22.flags.illegal_valid = 0; + + if (!mesh.LegalTet(el21) || + !mesh.LegalTet(el22)) + bad2 += 1e4; + + + if (goal == OPT_CONFORM && bad2 < 1e4) + { + INDEX_3 face(pi3, pi4, pi5); + face.Sort(); + if (faces.Used(face)) + { + // (*testout) << "3->2 swap, could improve conformity, bad1 = " << bad1 + // << ", bad2 = " << bad2 << endl; + if (bad2 < 1e4) + bad1 = 2 * bad2; + } + /* + else + { + INDEX_2 hi1(pi3, pi4); + hi1.Sort(); + INDEX_2 hi2(pi3, pi5); + hi2.Sort(); + INDEX_2 hi3(pi4, pi5); + hi3.Sort(); + + if (boundaryedges->Used (hi1) || + boundaryedges->Used (hi2) || + boundaryedges->Used (hi3) ) + bad1 = 2 * bad2; + } + */ + } + + if (bad2 < bad1) + { + // (*mycout) << "3->2 " << flush; + // (*testout) << "3->2 conversion" << endl; + cnt++; + + + /* + (*testout) << "3->2 swap, old els = " << endl + << mesh[hasbothpoints[0]] << endl + << mesh[hasbothpoints[1]] << endl + << mesh[hasbothpoints[2]] << endl + << "new els = " << endl + << el21 << endl + << el22 << endl; + */ + + + el21.flags.illegal_valid = 0; + el22.flags.illegal_valid = 0; + mesh[hasbothpoints[0]] = el21; + mesh[hasbothpoints[1]] = el22; + for (l = 0; l < 4; l++) + mesh[hasbothpoints[2]][l] = 0; + mesh[hasbothpoints[2]].Delete(); + + for (k = 0; k < 2; k++) + for (l = 0; l < 4; l++) + elementsonnode.Add (mesh[hasbothpoints[k]][l], hasbothpoints[k]); + } + } + + + if (nsuround == 4) + { + const Element & elem1 = mesh[hasbothpoints[0]]; + for (l = 0; l < 4; l++) + if (elem1[l] != pi1 && elem1[l] != pi2) + { + pi4 = pi3; + pi3 = elem1[l]; + } + + el1[0] = pi1; el1[1] = pi2; + el1[2] = pi3; el1[3] = pi4; + el1.SetIndex (mattyp); + + if (WrongOrientation (mesh.Points(), el1)) + { + Swap (pi3, pi4); + el1[2] = pi3; + el1[3] = pi4; + } + + pi5 = 0; + for (k = 1; k < 4; k++) + { + const Element & elem = mesh[hasbothpoints[k]]; + bool has1 = 0; + for (l = 0; l < 4; l++) + if (elem[l] == pi4) + has1 = 1; + if (has1) + { + for (l = 0; l < 4; l++) + if (elem[l] != pi1 && elem[l] != pi2 && elem[l] != pi4) + pi5 = elem[l]; + } + } + + pi6 = 0; + for (k = 1; k < 4; k++) + { + const Element & elem = mesh[hasbothpoints[k]]; + bool has1 = 0; + for (l = 0; l < 4; l++) + if (elem[l] == pi3) + has1 = 1; + if (has1) + { + for (l = 0; l < 4; l++) + if (elem[l] != pi1 && elem[l] != pi2 && elem[l] != pi3) + pi6 = elem[l]; + } + } + + /* + INDEX_2 i22(pi3, pi5); + i22.Sort(); + INDEX_2 i23(pi4, pi6); + i23.Sort(); + */ + + el1[0] = pi1; el1[1] = pi2; + el1[2] = pi3; el1[3] = pi4; + el1.SetIndex (mattyp); + + el2[0] = pi1; el2[1] = pi2; + el2[2] = pi4; el2[3] = pi5; + el2.SetIndex (mattyp); + + el3[0] = pi1; el3[1] = pi2; + el3[2] = pi5; el3[3] = pi6; + el3.SetIndex (mattyp); + + el4[0] = pi1; el4[1] = pi2; + el4[2] = pi6; el4[3] = pi3; + el4.SetIndex (mattyp); + + // elementsonnode.Add (pi4, hasbothpoints.Elem(2)); + // elementsonnode.Add (pi3, hasbothpoints.Elem(3)); + + bad1 = CalcBad (mesh.Points(), el1, 0) + + CalcBad (mesh.Points(), el2, 0) + + CalcBad (mesh.Points(), el3, 0) + + CalcBad (mesh.Points(), el4, 0); + + + el1.flags.illegal_valid = 0; + el2.flags.illegal_valid = 0; + el3.flags.illegal_valid = 0; + el4.flags.illegal_valid = 0; + + + if (goal != OPT_CONFORM) + { + if (!mesh.LegalTet(el1) || + !mesh.LegalTet(el2) || + !mesh.LegalTet(el3) || + !mesh.LegalTet(el4)) + bad1 += 1e4; + } + + el1[0] = pi3; el1[1] = pi5; + el1[2] = pi2; el1[3] = pi4; + el1.SetIndex (mattyp); + + el2[0] = pi3; el2[1] = pi5; + el2[2] = pi4; el2[3] = pi1; + el2.SetIndex (mattyp); + + el3[0] = pi3; el3[1] = pi5; + el3[2] = pi1; el3[3] = pi6; + el3.SetIndex (mattyp); + + el4[0] = pi3; el4[1] = pi5; + el4[2] = pi6; el4[3] = pi2; + el4.SetIndex (mattyp); + + bad2 = CalcBad (mesh.Points(), el1, 0) + + CalcBad (mesh.Points(), el2, 0) + + CalcBad (mesh.Points(), el3, 0) + + CalcBad (mesh.Points(), el4, 0); + + el1.flags.illegal_valid = 0; + el2.flags.illegal_valid = 0; + el3.flags.illegal_valid = 0; + el4.flags.illegal_valid = 0; + + if (goal != OPT_CONFORM) + { + if (!mesh.LegalTet(el1) || + !mesh.LegalTet(el2) || + !mesh.LegalTet(el3) || + !mesh.LegalTet(el4)) + bad2 += 1e4; + } + + + el1b[0] = pi4; el1b[1] = pi6; + el1b[2] = pi3; el1b[3] = pi2; + el1b.SetIndex (mattyp); + + el2b[0] = pi4; el2b[1] = pi6; + el2b[2] = pi2; el2b[3] = pi5; + el2b.SetIndex (mattyp); + + el3b[0] = pi4; el3b[1] = pi6; + el3b[2] = pi5; el3b[3] = pi1; + el3b.SetIndex (mattyp); + + el4b[0] = pi4; el4b[1] = pi6; + el4b[2] = pi1; el4b[3] = pi3; + el4b.SetIndex (mattyp); + + bad3 = CalcBad (mesh.Points(), el1b, 0) + + CalcBad (mesh.Points(), el2b, 0) + + CalcBad (mesh.Points(), el3b, 0) + + CalcBad (mesh.Points(), el4b, 0); + + el1b.flags.illegal_valid = 0; + el2b.flags.illegal_valid = 0; + el3b.flags.illegal_valid = 0; + el4b.flags.illegal_valid = 0; + + if (goal != OPT_CONFORM) + { + if (!mesh.LegalTet(el1b) || + !mesh.LegalTet(el2b) || + !mesh.LegalTet(el3b) || + !mesh.LegalTet(el4b)) + bad3 += 1e4; + } + + + /* + int swap2 = (bad2 < bad1) && (bad2 < bad3); + int swap3 = !swap2 && (bad3 < bad1); + + if ( ((bad2 < 10 * bad1) || + (bad2 < 1e6)) && mesh.BoundaryEdge (pi3, pi5)) + swap2 = 1; + else if ( ((bad3 < 10 * bad1) || + (bad3 < 1e6)) && mesh.BoundaryEdge (pi4, pi6)) + { + swap3 = 1; + swap2 = 0; + } + */ + bool swap2, swap3; + + if (goal != OPT_CONFORM) + { + swap2 = (bad2 < bad1) && (bad2 < bad3); + swap3 = !swap2 && (bad3 < bad1); + } + else + { + if (mesh.BoundaryEdge (pi3, pi5)) bad2 /= 1e6; + if (mesh.BoundaryEdge (pi4, pi6)) bad3 /= 1e6; + + swap2 = (bad2 < bad1) && (bad2 < bad3); + swap3 = !swap2 && (bad3 < bad1); + } + + + if (swap2 || swap3) + { + // (*mycout) << "4->4 " << flush; + cnt++; + // (*testout) << "4->4 conversion" << "\n"; + /* + (*testout) << "bad1 = " << bad1 + << " bad2 = " << bad2 + << " bad3 = " << bad3 << "\n"; + + (*testout) << "Points: " << pi1 << " " << pi2 << " " << pi3 + << " " << pi4 << " " << pi5 << " " << pi6 << "\n"; + (*testout) << "Elements: " + << hasbothpoints.Get(1) << " " + << hasbothpoints.Get(2) << " " + << hasbothpoints.Get(3) << " " + << hasbothpoints.Get(4) << " " << "\n"; + */ + + /* + { + int i1, j1; + for (i1 = 1; i1 <= 4; i1++) + { + for (j1 = 1; j1 <= 4; j1++) + (*testout) << volelements.Get(hasbothpoints.Get(i1)).PNum(j1) + << " "; + (*testout) << "\n"; + } + } + */ + } + + + if (swap2) + { + // (*mycout) << "bad1 = " << bad1 << " bad2 = " << bad2 << "\n"; + + + /* + (*testout) << "4->4 swap A, old els = " << endl + << mesh[hasbothpoints[0]] << endl + << mesh[hasbothpoints[1]] << endl + << mesh[hasbothpoints[2]] << endl + << mesh[hasbothpoints[3]] << endl + << "new els = " << endl + << el1 << endl + << el2 << endl + << el3 << endl + << el4 << endl; + */ + + + + el1.flags.illegal_valid = 0; + el2.flags.illegal_valid = 0; + el3.flags.illegal_valid = 0; + el4.flags.illegal_valid = 0; + + mesh[hasbothpoints[0]] = el1; + mesh[hasbothpoints[1]] = el2; + mesh[hasbothpoints[2]] = el3; + mesh[hasbothpoints[3]] = el4; + + for (k = 0; k < 4; k++) + for (l = 0; l < 4; l++) + elementsonnode.Add (mesh[hasbothpoints[k]][l], hasbothpoints[k]); + } + else if (swap3) + { + // (*mycout) << "bad1 = " << bad1 << " bad3 = " << bad3 << "\n"; + el1b.flags.illegal_valid = 0; + el2b.flags.illegal_valid = 0; + el3b.flags.illegal_valid = 0; + el4b.flags.illegal_valid = 0; + + + /* + (*testout) << "4->4 swap A, old els = " << endl + << mesh[hasbothpoints[0]] << endl + << mesh[hasbothpoints[1]] << endl + << mesh[hasbothpoints[2]] << endl + << mesh[hasbothpoints[3]] << endl + << "new els = " << endl + << el1b << endl + << el2b << endl + << el3b << endl + << el4b << endl; + */ + + + mesh[hasbothpoints[0]] = el1b; + mesh[hasbothpoints[1]] = el2b; + mesh[hasbothpoints[2]] = el3b; + mesh[hasbothpoints[3]] = el4b; + + for (k = 0; k < 4; k++) + for (l = 0; l < 4; l++) + elementsonnode.Add (mesh[hasbothpoints[k]][l], hasbothpoints[k]); + } + } + + if (nsuround >= 5) + { + Element hel(TET); + + ArrayMem<PointIndex, 50> suroundpts(nsuround); + ArrayMem<char, 50> tetused(nsuround); + + Element & elem = mesh[hasbothpoints[0]]; + + for (l = 0; l < 4; l++) + if (elem[l] != pi1 && elem[l] != pi2) + { + pi4 = pi3; + pi3 = elem[l]; + } + + hel[0] = pi1; + hel[1] = pi2; + hel[2] = pi3; + hel[3] = pi4; + hel.SetIndex (mattyp); + + if (WrongOrientation (mesh.Points(), hel)) + { + Swap (pi3, pi4); + hel[2] = pi3; + hel[3] = pi4; + } + + + // suroundpts.SetSize (nsuround); + suroundpts[0] = pi3; + suroundpts[1] = pi4; + + tetused = 0; + tetused[0] = 1; + + for (l = 2; l < nsuround; l++) + { + int oldpi = suroundpts[l-1]; + int newpi = 0; + + for (k = 0; k < nsuround && !newpi; k++) + if (!tetused[k]) + { + const Element & nel = mesh[hasbothpoints[k]]; + + for (int k2 = 0; k2 < 4 && !newpi; k2++) + if (nel[k2] == oldpi) + { + newpi = + nel[0] + nel[1] + nel[2] + nel[3] + - pi1 - pi2 - oldpi; + + tetused[k] = 1; + suroundpts[l] = newpi; + } + } + } + + + double bad1 = 0, bad2; + for (k = 0; k < nsuround; k++) + { + hel[0] = pi1; + hel[1] = pi2; + hel[2] = suroundpts[k]; + hel[3] = suroundpts[(k+1) % nsuround]; + hel.SetIndex (mattyp); + + bad1 += CalcBad (mesh.Points(), hel, 0); + } + + // (*testout) << "nsuround = " << nsuround << " bad1 = " << bad1 << endl; + + + int bestl = -1; + int confface = -1; + int confedge = -1; + double badopt = bad1; + + for (l = 0; l < nsuround; l++) + { + bad2 = 0; + + for (k = l+1; k <= nsuround + l - 2; k++) + { + hel[0] = suroundpts[l]; + hel[1] = suroundpts[k % nsuround]; + hel[2] = suroundpts[(k+1) % nsuround]; + hel[3] = pi2; + + bad2 += CalcBad (mesh.Points(), hel, 0); + hel.flags.illegal_valid = 0; + if (!mesh.LegalTet(hel)) bad2 += 1e4; + + hel[2] = suroundpts[k % nsuround]; + hel[1] = suroundpts[(k+1) % nsuround]; + hel[3] = pi1; + + bad2 += CalcBad (mesh.Points(), hel, 0); + + hel.flags.illegal_valid = 0; + if (!mesh.LegalTet(hel)) bad2 += 1e4; + } + // (*testout) << "bad2," << l << " = " << bad2 << endl; + + if ( bad2 < badopt ) + { + bestl = l; + badopt = bad2; + } + + + if (goal == OPT_CONFORM) + // (bad2 <= 100 * bad1 || bad2 <= 1e6)) + { + bool nottoobad = + (bad2 <= bad1) || + (bad2 <= 100 * bad1 && bad2 <= 1e18) || + (bad2 <= 1e8); + + for (k = l+1; k <= nsuround + l - 2; k++) + { + INDEX_3 hi3(suroundpts[l], + suroundpts[k % nsuround], + suroundpts[(k+1) % nsuround]); + hi3.Sort(); + if (faces.Used(hi3)) + { + // (*testout) << "could improve face conformity, bad1 = " << bad1 + // << ", bad 2 = " << bad2 << ", nottoobad = " << nottoobad << endl; + if (nottoobad) + confface = l; + } + } + + for (k = l+2; k <= nsuround+l-2; k++) + { + if (mesh.BoundaryEdge (suroundpts[l], + suroundpts[k % nsuround])) + { + /* + *testout << "could improve edge conformity, bad1 = " << bad1 + << ", bad 2 = " << bad2 << ", nottoobad = " << nottoobad << endl; + */ + if (nottoobad) + confedge = l; + } + } + } + } + + if (confedge != -1) + bestl = confedge; + if (confface != -1) + bestl = confface; + + if (bestl != -1) + { + // (*mycout) << nsuround << "->" << 2 * (nsuround-2) << " " << flush; + cnt++; + + for (k = bestl+1; k <= nsuround + bestl - 2; k++) + { + int k1; + + hel[0] = suroundpts[bestl]; + hel[1] = suroundpts[k % nsuround]; + hel[2] = suroundpts[(k+1) % nsuround]; + hel[3] = pi2; + hel.flags.illegal_valid = 0; + + /* + (*testout) << nsuround << "-swap, new el,top = " + << hel << endl; + */ + mesh.AddVolumeElement (hel); + for (k1 = 0; k1 < 4; k1++) + elementsonnode.Add (hel[k1], mesh.GetNE()-1); + + + hel[2] = suroundpts[k % nsuround]; + hel[1] = suroundpts[(k+1) % nsuround]; + hel[3] = pi1; + + /* + (*testout) << nsuround << "-swap, new el,bot = " + << hel << endl; + */ + + mesh.AddVolumeElement (hel); + for (k1 = 0; k1 < 4; k1++) + elementsonnode.Add (hel[k1], mesh.GetNE()-1); + } + + for (k = 0; k < nsuround; k++) + { + Element & rel = mesh[hasbothpoints[k]]; + /* + (*testout) << nsuround << "-swap, old el = " + << rel << endl; + */ + rel.Delete(); + for (int k1 = 0; k1 < 4; k1++) + rel[k1] = 0; + } + } + } + } + + /* + if (onlybedges) + { + (*testout) << "bad tet: " + << volelements.Get(i)[0] + << volelements.Get(i)[1] + << volelements.Get(i)[2] + << volelements.Get(i)[3] << "\n"; + + if (!mesh.LegalTet (volelements.Get(i))) + cerr << "Illegal tet" << "\n"; + } + */ + } + // (*mycout) << endl; + + /* + cout << "edgeused: "; + edgeused.PrintMemInfo(cout); + */ + PrintMessage (5, cnt, " swaps performed"); + + mesh.Compress (); + + /* + if (goal == OPT_QUALITY) + { + bad1 = CalcTotalBad (mesh.Points(), mesh.VolumeElements()); + // (*testout) << "Total badness = " << bad1 << endl; + } + */ + + /* + for (i = 1; i <= GetNE(); i++) + if (volelements.Get(i)[0]) + if (!mesh.LegalTet (volelements.Get(i))) + { + cout << "detected illegal tet, 2" << endl; + (*testout) << "detected illegal tet1: " << i << endl; + } + */ + + multithread.task = savetask; +} + + + + + + + + +/* + 2 -> 3 conversion +*/ + + + +void MeshOptimize3d :: SwapImprove2 (Mesh & mesh, OPTIMIZEGOAL goal) +{ + int j, k, l; + ElementIndex ei, eli1, eli2, elnr; + SurfaceElementIndex sei; + PointIndex pi1, pi2, pi3, pi4, pi5; + + int cnt = 0; + + Element el21(TET), el22(TET), el31(TET), el32(TET), el33(TET); + + double bad1, bad2; + + int np = mesh.GetNP(); + int ne = mesh.GetNE(); + int nse = mesh.GetNSE(); + + if (goal == OPT_CONFORM) return; + + // contains at least all elements at node + TABLE<ElementIndex, PointIndex::BASE> elementsonnode(np); + TABLE<SurfaceElementIndex, PointIndex::BASE> belementsonnode(np); + + PrintMessage (3, "SwapImprove2 "); + (*testout) << "\n" << "Start SwapImprove2" << "\n"; + // TestOk(); + + + + /* + CalcSurfacesOfNode (); + for (i = 1; i <= GetNE(); i++) + if (volelements.Get(i)[0]) + if (!mesh.LegalTet (volelements.Get(i))) + { + cout << "detected illegal tet, 1" << endl; + (*testout) << "detected illegal tet1: " << i << endl; + } + */ + + + // Calculate total badness + + bad1 = CalcTotalBad (mesh.Points(), mesh.VolumeElements()); + (*testout) << "Total badness = " << bad1 << endl; + // cout << "tot bad = " << bad1 << endl; + + // find elements on node + + for (ei = 0; ei < ne; ei++) + for (j = 0; j < mesh[ei].GetNP(); j++) + elementsonnode.Add (mesh[ei][j], ei); + + for (sei = 0; sei < nse; sei++) + for (j = 0; j < 3; j++) + belementsonnode.Add (mesh[sei][j], sei); + + for (eli1 = 0; eli1 < ne; eli1++) + { + if (multithread.terminate) + break; + + if (mesh.ElementType (eli1) == FIXEDELEMENT) + continue; + + if (mesh[eli1].GetType() != TET) + continue; + + if ((goal == OPT_LEGAL) && + mesh.LegalTet (mesh[eli1]) && + CalcBad (mesh.Points(), mesh[eli1], 0) < 1e3) + continue; + + // cout << "eli = " << eli1 << endl; + // (*testout) << "swapimp2, eli = " << eli1 << "; el = " << mesh[eli1] << endl; + + for (j = 0; j < 4; j++) + { + // loop over faces + + Element & elem = mesh[eli1]; + // if (elem[0] < PointIndex::BASE) continue; + if (elem.IsDeleted()) continue; + + int mattyp = elem.GetIndex(); + + switch (j) + { + case 0: + pi1 = elem.PNum(1); pi2 = elem.PNum(2); + pi3 = elem.PNum(3); pi4 = elem.PNum(4); + break; + case 1: + pi1 = elem.PNum(1); pi2 = elem.PNum(4); + pi3 = elem.PNum(2); pi4 = elem.PNum(3); + break; + case 2: + pi1 = elem.PNum(1); pi2 = elem.PNum(3); + pi3 = elem.PNum(4); pi4 = elem.PNum(2); + break; + case 3: + pi1 = elem.PNum(2); pi2 = elem.PNum(4); + pi3 = elem.PNum(3); pi4 = elem.PNum(1); + break; + } + + + bool bface = 0; + for (k = 0; k < belementsonnode[pi1].Size(); k++) + { + const Element2d & bel = + mesh[belementsonnode[pi1][k]]; + + bool bface1 = 1; + for (l = 0; l < 3; l++) + if (bel[l] != pi1 && bel[l] != pi2 && bel[l] != pi3) + { + bface1 = 0; + break; + } + + if (bface1) + { + bface = 1; + break; + } + } + + if (bface) continue; + + + FlatArray<ElementIndex> row = elementsonnode[pi1]; + for (k = 0; k < row.Size(); k++) + { + eli2 = row[k]; + + // cout << "\rei1 = " << eli1 << ", pi1 = " << pi1 << ", k = " << k << ", ei2 = " << eli2 + // << ", getne = " << mesh.GetNE(); + + if ( eli1 != eli2 ) + { + Element & elem2 = mesh[eli2]; + if (elem2.IsDeleted()) continue; + if (elem2.GetType() != TET) + continue; + + int comnodes=0; + for (l = 1; l <= 4; l++) + if (elem2.PNum(l) == pi1 || elem2.PNum(l) == pi2 || + elem2.PNum(l) == pi3) + { + comnodes++; + } + else + { + pi5 = elem2.PNum(l); + } + + if (comnodes == 3) + { + bad1 = CalcBad (mesh.Points(), elem, 0) + + CalcBad (mesh.Points(), elem2, 0); + + if (!mesh.LegalTet(elem) || + !mesh.LegalTet(elem2)) + bad1 += 1e4; + + + el31.PNum(1) = pi1; + el31.PNum(2) = pi2; + el31.PNum(3) = pi5; + el31.PNum(4) = pi4; + el31.SetIndex (mattyp); + + el32.PNum(1) = pi2; + el32.PNum(2) = pi3; + el32.PNum(3) = pi5; + el32.PNum(4) = pi4; + el32.SetIndex (mattyp); + + el33.PNum(1) = pi3; + el33.PNum(2) = pi1; + el33.PNum(3) = pi5; + el33.PNum(4) = pi4; + el33.SetIndex (mattyp); + + bad2 = CalcBad (mesh.Points(), el31, 0) + + CalcBad (mesh.Points(), el32, 0) + + CalcBad (mesh.Points(), el33, 0); + + + el31.flags.illegal_valid = 0; + el32.flags.illegal_valid = 0; + el33.flags.illegal_valid = 0; + + if (!mesh.LegalTet(el31) || + !mesh.LegalTet(el32) || + !mesh.LegalTet(el33)) + bad2 += 1e4; + + + bool do_swap = (bad2 < bad1); + + if ( ((bad2 < 1e6) || (bad2 < 10 * bad1)) && + mesh.BoundaryEdge (pi4, pi5)) + do_swap = 1; + + if (do_swap) + { + // cout << "do swap, eli1 = " << eli1 << "; eli2 = " << eli2 << endl; + // (*mycout) << "2->3 " << flush; + cnt++; + + el31.flags.illegal_valid = 0; + el32.flags.illegal_valid = 0; + el33.flags.illegal_valid = 0; + + mesh[eli1] = el31; + mesh[eli2] = el32; + + ElementIndex neli = + mesh.AddVolumeElement (el33); + + /* + if (!LegalTet(el31) || !LegalTet(el32) || + !LegalTet(el33)) + { + cout << "Swap to illegal tets !!!" << endl; + } + */ + // cout << "neli = " << neli << endl; + for (l = 0; l < 4; l++) + { + elementsonnode.Add (el31[l], eli1); + elementsonnode.Add (el32[l], eli2); + elementsonnode.Add (el33[l], neli); + } + + break; + } + } + } + } + } + } + + + PrintMessage (5, cnt, " swaps performed"); + + + + /* + CalcSurfacesOfNode (); + for (i = 1; i <= GetNE(); i++) + if (volelements.Get(i).PNum(1)) + if (!LegalTet (volelements.Get(i))) + { + cout << "detected illegal tet, 2" << endl; + (*testout) << "detected illegal tet2: " << i << endl; + } + */ + + + bad1 = CalcTotalBad (mesh.Points(), mesh.VolumeElements()); + (*testout) << "Total badness = " << bad1 << endl; + (*testout) << "swapimprove2 done" << "\n"; + // (*mycout) << "Vol = " << CalcVolume (points, volelements) << "\n"; +} + + +/* + void Mesh :: SwapImprove2 (OPTIMIZEGOAL goal) + { + int i, j; + int eli1, eli2; + int mattyp; + + Element el31(4), el32(4), el33(4); + double bad1, bad2; + + + INDEX_3_HASHTABLE<INDEX_2> elsonface (GetNE()); + + (*mycout) << "SwapImprove2 " << endl; + (*testout) << "\n" << "Start SwapImprove2" << "\n"; + + // Calculate total badness + + if (goal == OPT_QUALITY) + { + double bad1 = CalcTotalBad (points, volelements); + (*testout) << "Total badness = " << bad1 << endl; + } + + // find elements on node + + + Element2d face; + for (i = 1; i <= GetNE(); i++) + if ( (i > eltyps.Size()) || (eltyps.Get(i) != FIXEDELEMENT) ) + { + const Element & el = VolumeElement(i); + if (!el.PNum(1)) continue; + + for (j = 1; j <= 4; j++) + { + el.GetFace (j, face); + INDEX_3 i3 (face.PNum(1), face.PNum(2), face.PNum(3)); + i3.Sort(); + + + int bnr, posnr; + if (!elsonface.PositionCreate (i3, bnr, posnr)) + { + INDEX_2 i2; + elsonface.GetData (bnr, posnr, i3, i2); + i2.I2() = i; + elsonface.SetData (bnr, posnr, i3, i2); + } + else + { + INDEX_2 i2 (i, 0); + elsonface.SetData (bnr, posnr, i3, i2); + } + + // if (elsonface.Used (i3)) + // { + // INDEX_2 i2 = elsonface.Get(i3); + // i2.I2() = i; + // elsonface.Set (i3, i2); + // } + // else + // { + // INDEX_2 i2 (i, 0); + // elsonface.Set (i3, i2); + // } + + } + } + + BitArray original(GetNE()); + original.Set(); + + for (i = 1; i <= GetNSE(); i++) + { + const Element2d & sface = SurfaceElement(i); + INDEX_3 i3 (sface.PNum(1), sface.PNum(2), sface.PNum(3)); + i3.Sort(); + INDEX_2 i2(0,0); + elsonface.Set (i3, i2); + } + + + for (i = 1; i <= elsonface.GetNBags(); i++) + for (j = 1; j <= elsonface.GetBagSize(i); j++) + { + INDEX_3 i3; + INDEX_2 i2; + elsonface.GetData (i, j, i3, i2); + + + int eli1 = i2.I1(); + int eli2 = i2.I2(); + + if (eli1 && eli2 && original.Test(eli1) && original.Test(eli2) ) + { + Element & elem = volelements.Elem(eli1); + Element & elem2 = volelements.Elem(eli2); + + int pi1 = i3.I1(); + int pi2 = i3.I2(); + int pi3 = i3.I3(); + + int pi4 = elem.PNum(1) + elem.PNum(2) + elem.PNum(3) + elem.PNum(4) - pi1 - pi2 - pi3; + int pi5 = elem2.PNum(1) + elem2.PNum(2) + elem2.PNum(3) + elem2.PNum(4) - pi1 - pi2 - pi3; + + + + + + + el31.PNum(1) = pi1; + el31.PNum(2) = pi2; + el31.PNum(3) = pi3; + el31.PNum(4) = pi4; + el31.SetIndex (mattyp); + + if (WrongOrientation (points, el31)) + swap (pi1, pi2); + + + bad1 = CalcBad (points, elem, 0) + + CalcBad (points, elem2, 0); + + // if (!LegalTet(elem) || !LegalTet(elem2)) + // bad1 += 1e4; + + + el31.PNum(1) = pi1; + el31.PNum(2) = pi2; + el31.PNum(3) = pi5; + el31.PNum(4) = pi4; + el31.SetIndex (mattyp); + + el32.PNum(1) = pi2; + el32.PNum(2) = pi3; + el32.PNum(3) = pi5; + el32.PNum(4) = pi4; + el32.SetIndex (mattyp); + + el33.PNum(1) = pi3; + el33.PNum(2) = pi1; + el33.PNum(3) = pi5; + el33.PNum(4) = pi4; + el33.SetIndex (mattyp); + + bad2 = CalcBad (points, el31, 0) + + CalcBad (points, el32, 0) + + CalcBad (points, el33, 0); + + // if (!LegalTet(el31) || !LegalTet(el32) || + // !LegalTet(el33)) + // bad2 += 1e4; + + + int swap = (bad2 < bad1); + + INDEX_2 hi2b(pi4, pi5); + hi2b.Sort(); + + if ( ((bad2 < 1e6) || (bad2 < 10 * bad1)) && + boundaryedges->Used (hi2b) ) + swap = 1; + + if (swap) + { + (*mycout) << "2->3 " << flush; + + volelements.Elem(eli1) = el31; + volelements.Elem(eli2) = el32; + volelements.Append (el33); + + original.Clear (eli1); + original.Clear (eli2); + } + } + } + + (*mycout) << endl; + + if (goal == OPT_QUALITY) + { + bad1 = CalcTotalBad (points, volelements); + (*testout) << "Total badness = " << bad1 << endl; + } + + // FindOpenElements (); + + (*testout) << "swapimprove2 done" << "\n"; + } + +*/ +} diff --git a/contrib/Netgen/libsrc/meshing/improve3.hpp b/contrib/Netgen/libsrc/meshing/improve3.hpp new file mode 100644 index 0000000000..9b5b2c9bec --- /dev/null +++ b/contrib/Netgen/libsrc/meshing/improve3.hpp @@ -0,0 +1,50 @@ +#ifndef FILE_IMPROVE3 +#define FILE_IMPROVE3 + + + + +/// +class MeshOptimize3d +{ +public: + void CombineImprove (Mesh & mesh, OPTIMIZEGOAL goal = OPT_QUALITY); + void SplitImprove (Mesh & mesh, OPTIMIZEGOAL goal = OPT_QUALITY); + void SwapImprove (Mesh & mesh, OPTIMIZEGOAL goal = OPT_QUALITY); + void SwapImprove2 (Mesh & mesh, OPTIMIZEGOAL goal = OPT_QUALITY); +}; + + + +extern double CalcBad (const Mesh::T_POINTS & points, const Element & elem, + double h); + +extern double CalcTotalBad (const Mesh::T_POINTS & points, + const Mesh::T_VOLELEMENTS & elements); + +extern int WrongOrientation (const Mesh::T_POINTS & points, const Element & el); + + +/* Functional depending of inner point inside triangular surface */ + + + +class PointFunction1 : public MinFunction +{ + Mesh::T_POINTS & points; + const ARRAY<INDEX_3> & faces; + double h; +public: + PointFunction1 (Mesh::T_POINTS & apoints, + const ARRAY<INDEX_3> & afaces, + double ah); + + virtual double Func (const Vector & x) const; + virtual double FuncDeriv (const Vector & x, const Vector & dir, double & deriv) const; + virtual double FuncGrad (const Vector & x, Vector & g) const; + virtual double GradStopping (const Vector & x) const; +}; + + + +#endif diff --git a/contrib/Netgen/libsrc/meshing/localh.cpp b/contrib/Netgen/libsrc/meshing/localh.cpp new file mode 100644 index 0000000000..62025737f3 --- /dev/null +++ b/contrib/Netgen/libsrc/meshing/localh.cpp @@ -0,0 +1,682 @@ +#include <mystdlib.h> +#include "meshing.hpp" + + +namespace netgen +{ + +GradingBox :: GradingBox (const double * ax1, const double * ax2) +{ + int i; + + h2 = 0.5 * (ax2[0] - ax1[0]); + for (i = 0; i <= 2; i++) + { + /* + x1[i] = ax1[i]; + x2[i] = ax2[i]; + */ + xmid[i] = 0.5 * (ax1[i] + ax2[i]); + } + + /* + (*testout) << "new box: " << xmid[0] << "-" << xmid[1] << "-" << xmid[2] + << " h = " << (x2[0] - x1[0]) << endl; + */ + + for (i = 0; i < 8; i++) + childs[i] = NULL; + father = NULL; + + flags.cutboundary = 0; + flags.isinner = 0; + flags.oldcell = 0; + flags.pinner = 0; + + // hopt = x2[0] - x1[0]; + hopt = 2 * h2; +} + + + +BlockAllocator GradingBox :: ball(sizeof (GradingBox)); + +void * GradingBox :: operator new(size_t) +{ + return ball.Alloc(); +} + +void GradingBox :: operator delete (void * p) +{ + ball.Free (p); +} + + + + + + + +void GradingBox :: DeleteChilds() +{ + int i; + for (i = 0; i < 8; i++) + if (childs[i]) + { + childs[i]->DeleteChilds(); + delete childs[i]; + childs[i] = NULL; + } +} + + +LocalH :: LocalH (const Point3d & pmin, const Point3d & pmax, double agrading) +{ + double x1[3], x2[3]; + double hmax; + int i; + + boundingbox = Box3d (pmin, pmax); + grading = agrading; + + // a small enlargement, non-regular points + double val = 0.0879; + for (i = 1; i <= 3; i++) + { + + x1[i-1] = (1 + val * i) * pmin.X(i) - val * i * pmax.X(i); + x2[i-1] = 1.1 * pmax.X(i) - 0.1 * pmin.X(i); + } + + hmax = x2[0] - x1[0]; + for (i = 1; i <= 2; i++) + if (x2[i] - x1[i] > hmax) + hmax = x2[i] - x1[i]; + + for (i = 0; i <= 2; i++) + x2[i] = x1[i] + hmax; + + root = new GradingBox (x1, x2); + boxes.Append (root); +} + +LocalH :: ~LocalH () +{ + root->DeleteChilds(); + delete root; +} + +void LocalH :: Delete () +{ + root->DeleteChilds(); +} + +void LocalH :: SetH (const Point3d & p, double h) +{ + /* + (*testout) << "Set h at " << p << " to " << h << endl; + if (h < 1e-8) + { + cout << "do not set h to " << h << endl; + return; + } + */ + + if (fabs (p.X() - root->xmid[0]) > root->h2 || + fabs (p.Y() - root->xmid[1]) > root->h2 || + fabs (p.Z() - root->xmid[2]) > root->h2) + return; + + /* + if (p.X() < root->x1[0] || p.X() > root->x2[0] || + p.Y() < root->x1[1] || p.Y() > root->x2[1] || + p.Z() < root->x1[2] || p.Z() > root->x2[2]) + return; + */ + + + if (GetH(p) <= 1.2 * h) return; + + + GradingBox * box = root; + GradingBox * nbox = root; + GradingBox * ngb; + int childnr; + double x1[3], x2[3]; + + while (nbox) + { + box = nbox; + childnr = 0; + if (p.X() > box->xmid[0]) childnr += 1; + if (p.Y() > box->xmid[1]) childnr += 2; + if (p.Z() > box->xmid[2]) childnr += 4; + nbox = box->childs[childnr]; + }; + + + while (2 * box->h2 > h) + { + childnr = 0; + if (p.X() > box->xmid[0]) childnr += 1; + if (p.Y() > box->xmid[1]) childnr += 2; + if (p.Z() > box->xmid[2]) childnr += 4; + + double h2 = box->h2; + if (childnr & 1) + { + x1[0] = box->xmid[0]; + x2[0] = x1[0]+h2; // box->x2[0]; + } + else + { + x2[0] = box->xmid[0]; + x1[0] = x2[0]-h2; // box->x1[0]; + } + + if (childnr & 2) + { + x1[1] = box->xmid[1]; + x2[1] = x1[1]+h2; // box->x2[1]; + } + else + { + x2[1] = box->xmid[1]; + x1[1] = x2[1]-h2; // box->x1[1]; + } + + if (childnr & 4) + { + x1[2] = box->xmid[2]; + x2[2] = x1[2]+h2; // box->x2[2]; + } + else + { + x2[2] = box->xmid[2]; + x1[2] = x2[2]-h2; // box->x1[2]; + } + + ngb = new GradingBox (x1, x2); + box->childs[childnr] = ngb; + ngb->father = box; + + boxes.Append (ngb); + box = box->childs[childnr]; + } + + box->hopt = h; + + + double hbox = 2 * box->h2; // box->x2[0] - box->x1[0]; + double hnp = h + grading * hbox; + + Point3d np; + int i; + for (i = 1; i <= 3; i++) + { + np = p; + np.X(i) = p.X(i) + hbox; + SetH (np, hnp); + + np.X(i) = p.X(i) - hbox; + SetH (np, hnp); + } + /* + Point3d np; + int i1, i2, i3; + for (i1 = -1; i1 <= 1; i1++) + for (i2 = -1; i2 <= 1; i2++) + for (i3 = -1; i3 <= 1; i3++) + { + np.X() = p.X() + hbox * i1; + np.Y() = p.Y() + hbox * i2; + np.Z() = p.Z() + hbox * i3; + + SetH (np, hnp); + } + */ +} + + + +double LocalH :: GetH (const Point3d & x) const +{ + const GradingBox * box = root; + const GradingBox * nbox; + int childnr; + + while (1) + { + childnr = 0; + if (x.X() > box->xmid[0]) childnr += 1; + if (x.Y() > box->xmid[1]) childnr += 2; + if (x.Z() > box->xmid[2]) childnr += 4; + nbox = box->childs[childnr]; + if (nbox) + box = nbox; + else + { + // (*testout) << "diam = " << (box->x2[0] - box->x1[0]) + // << " h = " << box->hopt << endl; + return box->hopt; + } + } +} + + +/// minimal h in box (pmin, pmax) +double LocalH :: GetMinH (const Point3d & pmin, const Point3d & pmax) const +{ + Point3d pmin2, pmax2; + for (int j = 1; j <= 3; j++) + if (pmin.X(j) < pmax.X(j)) + { pmin2.X(j) = pmin.X(j); pmax2.X(j) = pmax.X(j); } + else + { pmin2.X(j) = pmax.X(j); pmax2.X(j) = pmin.X(j); } + + return GetMinHRec (pmin2, pmax2, root); +} + + +double LocalH :: GetMinHRec (const Point3d & pmin, const Point3d & pmax, + const GradingBox * box) const +{ + double h2 = box->h2; + if (pmax.X() < box->xmid[0]-h2 || pmin.X() > box->xmid[0]+h2 || + pmax.Y() < box->xmid[1]-h2 || pmin.Y() > box->xmid[1]+h2 || + pmax.Z() < box->xmid[2]-h2 || pmin.Z() > box->xmid[2]+h2) + return 1e8; + /* + if (pmax.X() < box->x1[0] || pmin.X() > box->x2[0] || + pmax.Y() < box->x1[1] || pmin.Y() > box->x2[1] || + pmax.Z() < box->x1[2] || pmin.Z() > box->x2[2]) + return 1e8; + */ + + + double hmin = 2 * box->h2; // box->x2[0] - box->x1[0]; + int i; + + for (i = 0; i <= 7; i++) + { + if (box->childs[i]) + { + double hi = GetMinHRec (pmin, pmax, box->childs[i]); + if (hi < hmin) + hmin = hi; + } + } + + return hmin; +} + + +void LocalH :: CutBoundaryRec (const Point3d & pmin, const Point3d & pmax, + GradingBox * box) +{ + double h2 = box->h2; + if (pmax.X() < box->xmid[0]-h2 || pmin.X() > box->xmid[0]+h2 || + pmax.Y() < box->xmid[1]-h2 || pmin.Y() > box->xmid[1]+h2 || + pmax.Z() < box->xmid[2]-h2 || pmin.Z() > box->xmid[2]+h2) + return; + /* + if (pmax.X() < box->x1[0] || pmin.X() > box->x2[0] || + pmax.Y() < box->x1[1] || pmin.Y() > box->x2[1] || + pmax.Z() < box->x1[2] || pmin.Z() > box->x2[2]) + return; + */ + + box->flags.cutboundary = 1; + for (int i = 0; i < 8; i++) + if (box->childs[i]) + CutBoundaryRec (pmin, pmax, box->childs[i]); +} + + + + +void LocalH :: FindInnerBoxes ( // int (*sameside)(const Point3d & p1, const Point3d & p2), + AdFront3 * adfront, + int (*testinner)(const Point3d & p1)) +{ + int i, j; + + int nf = adfront->GetNF(); + + for (i = 0; i < boxes.Size(); i++) + boxes[i] -> flags.isinner = 0; + + root->flags.isinner = 0; + + Point3d rpmid(root->xmid[0], root->xmid[1], root->xmid[2]); + Vec3d rv(root->h2, root->h2, root->h2); + Point3d rx2 = rpmid + rv; + Point3d rx1 = rpmid - rv; + + + root->flags.pinner = !adfront->SameSide (rpmid, rx2); + + if (testinner) + (*testout) << "inner = " << root->flags.pinner << " =?= " + << testinner(Point3d(root->xmid[0], root->xmid[1], root->xmid[2])) << endl; + + ARRAY<int> faceinds(nf); + ARRAY<Box3d> faceboxes(nf); + + for (i = 1; i <= nf; i++) + { + faceinds.Elem(i) = i; + adfront->GetFaceBoundingBox(i, faceboxes.Elem(i)); + } + + for (i = 0; i < 8; i++) + FindInnerBoxesRec2 (root->childs[i], adfront, faceboxes, faceinds, nf); +} + + +void LocalH :: +FindInnerBoxesRec2 (GradingBox * box, + class AdFront3 * adfront, + ARRAY<Box3d> & faceboxes, + ARRAY<int> & faceinds, int nfinbox) +{ + if (!box) return; + + int i, j; + + GradingBox * father = box -> father; + + Point3d c(box->xmid[0], box->xmid[1], box->xmid[2]); + Vec3d v(box->h2, box->h2, box->h2); + Box3d boxc(c-v, c+v); + + Point3d fc(father->xmid[0], father->xmid[1], father->xmid[2]); + Vec3d fv(father->h2, father->h2, father->h2); + Box3d fboxc(fc-fv, fc+fv); + + Box3d boxcfc(c,fc); + + + static ARRAY<int> faceused; + static ARRAY<int> faceused2; + static ARRAY<int> facenotused; + + faceused.SetSize(0); + facenotused.SetSize(0); + faceused2.SetSize(0); + + for (j = 1; j <= nfinbox; j++) + { + // adfront->GetFaceBoundingBox (faceinds.Get(j), facebox); + const Box3d & facebox = faceboxes.Get(faceinds.Get(j)); + + if (boxc.Intersect (facebox)) + faceused.Append(faceinds.Get(j)); + else + facenotused.Append(faceinds.Get(j)); + + if (boxcfc.Intersect (facebox)) + faceused2.Append (faceinds.Get(j)); + } + + for (j = 1; j <= faceused.Size(); j++) + faceinds.Elem(j) = faceused.Get(j); + for (j = 1; j <= facenotused.Size(); j++) + faceinds.Elem(j+faceused.Size()) = facenotused.Get(j); + + + if (!father->flags.cutboundary) + { + box->flags.isinner = father->flags.isinner; + box->flags.pinner = father->flags.pinner; + } + else + { + Point3d cf(father->xmid[0], father->xmid[1], father->xmid[2]); + + if (father->flags.isinner) + box->flags.pinner = 1; + else + { + if (adfront->SameSide (c, cf, &faceused2)) + box->flags.pinner = father->flags.pinner; + else + box->flags.pinner = 1 - father->flags.pinner; + } + + if (box->flags.cutboundary) + box->flags.isinner = 0; + else + box->flags.isinner = box->flags.pinner; + } + + int nf = faceused.Size(); + for (i = 0; i < 8; i++) + FindInnerBoxesRec2 (box->childs[i], adfront, faceboxes, faceinds, nf); +} + + + + + + + + + + + + +/* +void LocalH :: FindInnerBoxes ( // int (*sameside)(const Point3d & p1, const Point3d & p2), + AdFront3 * adfront, + int (*testinner)(const Point3d & p1)) +{ + int i; + for (i = 1; i <= boxes.Size(); i++) + boxes.Elem(i)->flags.isinner = 0; + + root->flags.isinner = 0; + + Point3d rpmid(root->xmid[0], root->xmid[1], root->xmid[2]); + Point3d rx2 = rpmid + Vec3d (root->h2, root->h2, root->h2); + + root->flags.pinner = !adfront->SameSide (rpmid, rx2); + + if (testinner) + (*testout) << "inner = " << root->flags.pinner << " =?= " + << testinner(Point3d(root->xmid[0], root->xmid[1], root->xmid[2])) << endl; + + + for (i = 2; i <= boxes.Size(); i++) + { + GradingBox * box = boxes.Elem(i); + GradingBox * father = box -> father; + + Point3d c(box->xmid[0], box->xmid[1], box->xmid[2]); + Vec3d v(box->h2, box->h2, box->h2); + Point3d x1 = c-v; + Point3d x2 = c+v; + + + if (!father->flags.cutboundary) + { + box->flags.isinner = father->flags.isinner; + box->flags.pinner = father->flags.pinner; + } + else + { + Point3d cf(father->xmid[0], father->xmid[1], father->xmid[2]); + + if (father->flags.isinner) + box->flags.pinner = 1; + else + { + if (adfront->SameSide (c, cf)) + box->flags.pinner = father->flags.pinner; + else + box->flags.pinner = 1 - father->flags.pinner; + } + + if (box->flags.cutboundary) + box->flags.isinner = 0; + else + box->flags.isinner = box->flags.pinner; + } + } + // FindInnerBoxesRec (inner, root); +} +*/ + + +void LocalH :: FindInnerBoxesRec ( int (*inner)(const Point3d & p), + GradingBox * box) +{ + int i; + if (box->flags.cutboundary) + { + for (i = 0; i < 8; i++) + if (box->childs[i]) + FindInnerBoxesRec (inner, box->childs[i]); + } + else + { + if (inner (Point3d (box->xmid[0], box->xmid[1], box->xmid[2]))) + SetInnerBoxesRec (box); + } +} + + +void LocalH :: SetInnerBoxesRec (GradingBox * box) +{ + box->flags.isinner = 1; + for (int i = 0; i < 8; i++) + if (box->childs[i]) + ClearFlagsRec (box->childs[i]); +} + +void LocalH :: ClearFlagsRec (GradingBox * box) +{ + box->flags.cutboundary = 0; + box->flags.isinner = 0; + for (int i = 0; i < 8; i++) + if (box->childs[i]) + ClearFlagsRec (box->childs[i]); +} + + +void LocalH :: WidenRefinement () +{ + int nb = boxes.Size(); + int i; + // (*testout) << "old boxes: " << nb << endl; + for (i = 1; i <= nb; i++) + { + GradingBox * box = boxes.Get(i); + // double h = box->x2[0] - box->x1[0]; + double h = box->hopt; + Point3d c(box->xmid[0], box->xmid[1], box->xmid[2]); + // (*testout) << " i = " << i + // << " c = " << c << " h = " << h << endl; + + for (int i1 = -1; i1 <= 1; i1++) + for (int i2 = -1; i2 <= 1; i2++) + for (int i3 = -1; i3 <= 1; i3++) + SetH (Point3d (c.X() + i1 * h, + c.Y() + i2 * h, + c.Z() + i3 * h), 1.001 * h); + } +} + +void LocalH :: GetInnerPoints (ARRAY<Point3d> & points) +{ + int i, nb = boxes.Size(); + + for (i = 1; i <= nb; i++) + { + GradingBox * box = boxes.Get(i); + /* + if (box->flags.pinner) + points.Append (box->randomip); + */ + // if (box->flags.pinner) + if (box->flags.isinner) + { + Point3d c(box->xmid[0], box->xmid[1], box->xmid[2]); + points.Append (c); + /* + cout << "add point " << c << "; h = " << box->hopt + << "; max-min = " << (box->x2[0]-box->x1[0]) << endl; + */ + } + } +} + + + +void LocalH :: GetOuterPoints (ARRAY<Point3d> & points) +{ + int i, nb = boxes.Size(); + + for (i = 1; i <= nb; i++) + { + GradingBox * box = boxes.Get(i); + if (!box->flags.isinner && + !box->flags.cutboundary) + { + Point3d c(box->xmid[0], box->xmid[1], box->xmid[2]); + points.Append (c); + } + } +} + + + +void LocalH :: Convexify () +{ + ConvexifyRec (root); +} + +void LocalH :: ConvexifyRec (GradingBox * box) +{ + Point3d center(box->xmid[0], box->xmid[1], box->xmid[2]); + Point3d hp; + + double size = 2 * box->h2; // box->x2[0] - box->x1[0]; + double dx = 0.6 * size; + + double maxh = box->hopt; + int i; + + + + for (i = 1; i <= 6; i++) + { + hp = center; + switch (i) + { + case 1: hp.X() += dx; break; + case 2: hp.X() -= dx; break; + case 3: hp.Y() += dx; break; + case 4: hp.Y() -= dx; break; + case 5: hp.Z() += dx; break; + case 6: hp.Z() -= dx; break; + } + + double hh = GetH (hp); + if (hh > maxh) maxh = hh; + } + + if (maxh < 0.95 * box->hopt) + SetH (center, maxh); + + for (i = 0; i < 8; i++) + if (box->childs[i]) + ConvexifyRec (box->childs[i]); +} + +void LocalH :: PrintMemInfo (ostream & ost) const +{ + ost << "LocalH: " << boxes.Size() << " boxes of " << sizeof(GradingBox) + << " bytes = " << boxes.Size()*sizeof(GradingBox) << " bytes" << endl; +} +} diff --git a/contrib/Netgen/libsrc/meshing/localh.hpp b/contrib/Netgen/libsrc/meshing/localh.hpp new file mode 100644 index 0000000000..7531bc7faf --- /dev/null +++ b/contrib/Netgen/libsrc/meshing/localh.hpp @@ -0,0 +1,145 @@ +#ifndef LOCALH +#define LOCALH + +/**************************************************************************/ +/* File: localh.hh */ +/* Author: Joachim Schoeberl */ +/* Date: 29. Jan. 97 */ +/**************************************************************************/ + + + + +/// box for grading +class GradingBox +{ + /* + /// xmin + float x1[3]; + /// xmax + float x2[3]; + */ + /// xmid + float xmid[3]; + /// half edgelength + float h2; + /// + GradingBox * childs[8]; + /// + GradingBox * father; + /// + double hopt; + /// + struct + { + unsigned int cutboundary:1; + unsigned int isinner:1; + unsigned int oldcell:1; + unsigned int pinner:1; + } flags; +public: + /// + GradingBox (const double * ax1, const double * ax2); + /// + void DeleteChilds(); + /// + friend class LocalH; + + + static BlockAllocator ball; + void * operator new(size_t); + void operator delete (void *); +}; + + + +/** + Control of 3D mesh grading + */ +class LocalH +{ + /// + GradingBox * root; + /// + double grading; + /// + ARRAY<GradingBox*> boxes; + /// + Box3d boundingbox; +public: + /// + LocalH (const Point3d & pmin, const Point3d & pmax, double grading); + /// + ~LocalH(); + /// + void Delete(); + /// + void SetGrading (double agrading) { grading = agrading; } + /// + void SetH (const Point3d & x, double h); + /// + double GetH (const Point3d & x) const; + /// minimal h in box (pmin, pmax) + double GetMinH (const Point3d & pmin, const Point3d & pmax) const; + + /// mark boxes intersecting with boundary-box + void CutBoundary (const Point3d & pmin, const Point3d & pmax) + { CutBoundaryRec (pmin, pmax, root); } + + /// find inner boxes + void FindInnerBoxes ( // int (*sameside)(const Point3d & p1, const Point3d & p2), + class AdFront3 * adfront, + int (*testinner)(const Point3d & p1)); + + /// clears all flags + void ClearFlags () + { ClearFlagsRec(root); } + + /// widen refinement zone + void WidenRefinement (); + + /// get points in inner elements + void GetInnerPoints (ARRAY<Point3d> & points); + + /// get points in outer closure + void GetOuterPoints (ARRAY<Point3d> & points); + + /// + void Convexify (); + /// + int GetNBoxes () { return boxes.Size(); } + const Box3d & GetBoundingBox () const + { return boundingbox; } + /// + void PrintMemInfo (ostream & ost) const; +private: + /// + double GetMinHRec (const Point3d & pmin, const Point3d & pmax, + const GradingBox * box) const; + /// + void CutBoundaryRec (const Point3d & pmin, const Point3d & pmax, + GradingBox * box); + + /// + void FindInnerBoxesRec ( int (*inner)(const Point3d & p), + GradingBox * box); + + /// + void FindInnerBoxesRec2 (GradingBox * box, + class AdFront3 * adfront, + ARRAY<Box3d> & faceboxes, + ARRAY<int> & finds, int nfinbox); + + + /// + void SetInnerBoxesRec (GradingBox * box); + + /// + void ClearFlagsRec (GradingBox * box); + + /// + void ConvexifyRec (GradingBox * box); +}; + + +#endif diff --git a/contrib/Netgen/libsrc/meshing/meshclass.cpp b/contrib/Netgen/libsrc/meshing/meshclass.cpp new file mode 100644 index 0000000000..25c44f337e --- /dev/null +++ b/contrib/Netgen/libsrc/meshing/meshclass.cpp @@ -0,0 +1,4744 @@ +#include <mystdlib.h> + +#include "meshing.hpp" + +namespace netgen +{ + + Mesh :: Mesh () + { + boundaryedges = NULL; + surfelementht = NULL; + segmentht = NULL; + + lochfunc = NULL; + mglevels = 1; + elementsearchtree = NULL; + elementsearchtreets = NextTimeStamp(); + majortimestamp = timestamp = NextTimeStamp(); + hglob = 1e10; + numvertices = -1; + dimension = 3; + topology = new MeshTopology (*this); + curvedelems = new CurvedElements (*this); + clusters = new AnisotropicClusters (*this); + ident = new Identifications (*this); + + hpelements = NULL; + coarsemesh = NULL; + + } + + Mesh :: ~Mesh() + { + delete lochfunc; + delete boundaryedges; + delete surfelementht; + delete segmentht; + delete curvedelems; + delete clusters; + delete topology; + delete ident; + + delete coarsemesh; + delete hpelements; + + for (int i = 0; i < materials.Size(); i++) + delete [] materials[i]; + } + + + Mesh & Mesh :: operator= (const Mesh & mesh2) + { + points = mesh2.points; + eltyps = mesh2.eltyps; + segments = mesh2.segments; + surfelements = mesh2.surfelements; + volelements = mesh2.volelements; + lockedpoints = mesh2.lockedpoints; + facedecoding = mesh2.facedecoding; + dimension = mesh2.dimension; + return *this; + } + + void Mesh :: DeleteMesh() + { + points.SetSize(0); + // ptyps.SetSize(0); + segments.SetSize(0); + surfelements.SetSize(0); + volelements.SetSize(0); + lockedpoints.SetSize(0); + surfacesonnode.SetSize(0); + + delete boundaryedges; + boundaryedges = NULL; + + openelements.SetSize(0); + facedecoding.SetSize(0); + + // ident -> Delete(); + delete ident; + ident = new Identifications (*this); + delete topology; + topology = new MeshTopology (*this); + delete curvedelems; + curvedelems = new CurvedElements (*this); + delete clusters; + clusters = new AnisotropicClusters (*this); + + timestamp = NextTimeStamp(); + } + + + + PointIndex Mesh :: AddPoint (const Point3d & p, int layer) + { + NgLock lock(mutex); + lock.Lock(); + + timestamp = NextTimeStamp(); + + PointIndex pi = points.Size() + PointIndex::BASE; + points.Append ( MeshPoint (p, layer, INNERPOINT) ); + + lock.UnLock(); + + return pi; + } + + + SegmentIndex Mesh :: AddSegment (const Segment & s) + { + NgLock lock(mutex); + lock.Lock(); + timestamp = NextTimeStamp(); + + int maxn = max2 (s.p1, s.p2); + maxn += 1-PointIndex::BASE; + + /* + if (maxn > ptyps.Size()) + { + int maxo = ptyps.Size(); + ptyps.SetSize (maxn); + for (int i = maxo; i < maxn; i++) + ptyps[i] = INNERPOINT; + } + + if (ptyps[s.p1] > EDGEPOINT) ptyps[s.p1] = EDGEPOINT; + if (ptyps[s.p2] > EDGEPOINT) ptyps[s.p2] = EDGEPOINT; + */ + + if (maxn <= points.Size()) + { + if (points[s.p1].Type() > EDGEPOINT) + points[s.p1].SetType (EDGEPOINT); + if (points[s.p2].Type() > EDGEPOINT) + points[s.p2].SetType (EDGEPOINT); + } + /* + else + { + cerr << "edge points nrs > points.Size" << endl; + } + */ + + SegmentIndex si = segments.Size(); + segments.Append (s); + + lock.UnLock(); + return si; + } + + SurfaceElementIndex Mesh :: AddSurfaceElement (const Element2d & el) + { + NgLock lock(mutex); + lock.Lock(); + timestamp = NextTimeStamp(); + + int maxn = el[0]; + for (int i = 1; i < el.GetNP(); i++) + if (el[i] > maxn) maxn = el[i]; + + maxn += 1-PointIndex::BASE; + + /* + if (maxn > ptyps.Size()) + { + int maxo = ptyps.Size(); + ptyps.SetSize (maxn); + for (i = maxo+PointIndex::BASE; + i < maxn+PointIndex::BASE; i++) + ptyps[i] = INNERPOINT; + + } + */ + if (maxn <= points.Size()) + { + for (int i = 0; i < el.GetNP(); i++) + if (points[el[i]].Type() > SURFACEPOINT) + points[el[i]].SetType(SURFACEPOINT); + } + /* + else + { + cerr << "surf points nrs > points.Size" << endl; + } + */ + + SurfaceElementIndex si = surfelements.Size(); + surfelements.Append (el); + + lock.UnLock(); + return si; + } + + + ElementIndex Mesh :: AddVolumeElement (const Element & el) + { + NgLock lock(mutex); + lock.Lock(); + + int maxn = el[0]; + for (int i = 1; i < el.GetNP(); i++) + if (el[i] > maxn) maxn = el[i]; + + maxn += 1-PointIndex::BASE; + + /* + if (maxn > ptyps.Size()) + { + int maxo = ptyps.Size(); + ptyps.SetSize (maxn); + for (i = maxo+PointIndex::BASE; + i < maxn+PointIndex::BASE; i++) + ptyps[i] = INNERPOINT; + } + */ + /* + if (maxn > points.Size()) + { + cerr << "add vol element before point" << endl; + } + */ + + int ve = volelements.Size(); + + volelements.Append (el); + volelements.Last().flags.illegal_valid = 0; + + while (volelements.Size() > eltyps.Size()) + eltyps.Append (FREEELEMENT); + + timestamp = NextTimeStamp(); + + lock.UnLock(); + return ve; + } + + + + + + + void Mesh :: Save (const string & filename) const + { + int i, j; + + double scale = 1; // globflags.GetNumFlag ("scale", 1); + int inverttets = 0; // globflags.GetDefineFlag ("inverttets"); + int invertsurf = 0; // globflags.GetDefineFlag ("invertsurfacemesh"); + + ofstream outfile(filename.c_str()); + + + outfile << "mesh3d" << "\n"; + + outfile << "dimension\n" << GetDimension() << "\n"; + + outfile << "\n"; + outfile << "# surfnr bcnr domin domout np p1 p2 p3" + << "\n"; + + outfile << "surfaceelementsgi" << "\n"; + // outfile << "surfaceelements" << "\n"; + outfile << GetNSE() << "\n"; + + SurfaceElementIndex sei; + for (sei = 0; sei < GetNSE(); sei++) + { + if ((*this)[sei].GetIndex()) + { + outfile.width(8); + outfile << GetFaceDescriptor((*this)[sei].GetIndex ()).SurfNr()+1; + outfile.width(8); + outfile << GetFaceDescriptor((*this)[sei].GetIndex ()).BCProperty(); + outfile.width(8); + outfile << GetFaceDescriptor((*this)[sei].GetIndex ()).DomainIn(); + outfile.width(8); + outfile << GetFaceDescriptor((*this)[sei].GetIndex ()).DomainOut(); + } + else + outfile << " 0 0 0"; + + + Element2d sel = (*this)[sei]; + if (invertsurf) + sel.Invert(); + + outfile.width(8); + outfile << sel.GetNP(); + + for (j = 0; j < sel.GetNP(); j++) + { + outfile.width(8); + outfile << sel[j]; + } + + for (j = 1; j <= sel.GetNP(); j++) + { + outfile.width(7); + outfile << " " << sel.GeomInfoPi(j).trignum; + } + outfile << endl; + } + + outfile << "\n" << "\n"; + outfile << "# matnr np p1 p2 p3 p4" << "\n"; + outfile << "volumeelements" << "\n"; + outfile << GetNE() << "\n"; + + for (ElementIndex ei = 0; ei < GetNE(); ei++) + { + outfile.width(8); + outfile << (*this)[ei].GetIndex(); + outfile.width(8); + outfile << (*this)[ei].GetNP(); + + Element el = (*this)[ei]; + if (inverttets) + el.Invert(); + + for (j = 0; j < el.GetNP(); j++) + { + outfile.width(8); + outfile << el[j]; + } + outfile << "\n"; + } + + + outfile << "\n" << "\n"; + outfile << " surf1 surf2 p1 p2" << "\n"; + outfile << "edgesegmentsgi2" << "\n"; + outfile << GetNSeg() << "\n"; + + for (i = 1; i <= GetNSeg(); i++) + { + const Segment & seg = LineSegment (i); + outfile.width(8); + outfile << seg.si; + outfile.width(8); + outfile << 0; + outfile.width(8); + outfile << seg.p1; + outfile.width(8); + outfile << seg.p2; + outfile << " "; + outfile.width(8); + outfile << seg.geominfo[0].trignum; + outfile << " "; + outfile.width(8); + outfile << seg.geominfo[1].trignum << endl; + + outfile << " "; + outfile.width(8); + outfile << seg.surfnr1+1; + outfile << " "; + outfile.width(8); + outfile << seg.surfnr2+1; + outfile << " "; + outfile.width(8); + outfile << seg.edgenr; + // outfile << seg.epgeominfo[0].edgenr; + /* + outfile.width(8); + outfile << seg.epgeominfo[0].lefttrig; + outfile.width(8); + outfile << seg.epgeominfo[0].righttrig; + */ + outfile << " "; + outfile.width(12); + outfile << seg.epgeominfo[0].dist; + outfile << " "; + outfile.width(8); + outfile << seg.epgeominfo[1].edgenr; + /* + outfile.width(8); + outfile << seg.epgeominfo[1].lefttrig; + outfile.width(8); + outfile << seg.epgeominfo[1].righttrig; + */ + outfile << " "; + outfile.width(12); + outfile << seg.epgeominfo[1].dist; + + outfile << "\n"; + } + + + outfile << "\n" << "\n"; + outfile << "# X Y Z" << "\n"; + outfile << "points" << "\n"; + outfile << GetNP() << "\n"; + outfile.precision(16); + outfile.setf (ios::fixed, ios::floatfield); + outfile.setf (ios::showpoint); + + PointIndex pi; + for (pi = PointIndex::BASE; + pi < GetNP()+PointIndex::BASE; pi++) + { + outfile.width(22); + outfile << (*this)[pi].X()/scale << " "; + outfile.width(22); + outfile << (*this)[pi].Y()/scale << " "; + outfile.width(22); + outfile << (*this)[pi].Z()/scale << "\n"; + } + + if (ident -> GetMaxNr() > 0) + { + outfile << "identifications\n"; + ARRAY<INDEX_2> identpairs; + int cnt = 0; + for (i = 1; i <= ident -> GetMaxNr(); i++) + { + ident -> GetPairs (i, identpairs); + cnt += identpairs.Size(); + } + outfile << cnt << "\n"; + for (i = 1; i <= ident -> GetMaxNr(); i++) + { + ident -> GetPairs (i, identpairs); + for (j = 1; j <= identpairs.Size(); j++) + { + outfile.width (8); + outfile << identpairs.Get(j).I1(); + outfile.width (8); + outfile << identpairs.Get(j).I2(); + outfile.width (8); + outfile << i << "\n"; + } + } + } + + int cntmat = 0; + for (i = 1; i <= materials.Size(); i++) + if (materials.Get(i) && strlen (materials.Get(i))) + cntmat++; + + if (cntmat) + { + outfile << "materials" << endl; + outfile << cntmat << endl; + for (i = 1; i <= materials.Size(); i++) + if (materials.Get(i) && strlen (materials.Get(i))) + outfile << i << " " << materials.Get(i) << endl; + } + + + int cnt_sing = 0; + for (PointIndex pi = PointIndex::BASE; pi < GetNP()+PointIndex::BASE; pi++) + if ((*this)[pi].IsSingular()) cnt_sing++; + + if (cnt_sing) + { + outfile << "singular_points" << endl << cnt_sing << endl; + for (PointIndex pi = PointIndex::BASE; pi < GetNP()+PointIndex::BASE; pi++) + if ((*this)[pi].IsSingular()) + outfile << int(pi) << 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) << 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) << 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) << 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) << endl; + } + + + } + + + void Mesh :: Load (const string & filename) + { + char str[100]; + int i, n; + + double scale = 1; // globflags.GetNumFlag ("scale", 1); + int inverttets = 0; // globflags.GetDefineFlag ("inverttets"); + int invertsurf = 0; // globflags.GetDefineFlag ("invertsurfacemesh"); + + ifstream infile(filename.c_str()); + if (!infile.good()) + throw NgException ("mesh file not found"); + + facedecoding.SetSize(0); + + while (infile.good()) + { + infile >> str; + + if (strcmp (str, "dimension") == 0) + { + infile >> dimension; + } + + if (strcmp (str, "surfaceelements") == 0) + { + infile >> n; + PrintMessage (3, n, " surface elements"); + for (i = 1; i <= n; i++) + { + int j; + int surfnr, bcp, domin, domout, nep, faceind = 0; + + infile >> surfnr >> bcp >> domin >> domout; + surfnr--; + + for (j = 1; j <= facedecoding.Size(); j++) + if (GetFaceDescriptor(j).SurfNr() == surfnr && + GetFaceDescriptor(j).BCProperty() == bcp && + GetFaceDescriptor(j).DomainIn() == domin && + GetFaceDescriptor(j).DomainOut() == domout) + faceind = j; + + if (!faceind) + { + faceind = AddFaceDescriptor (FaceDescriptor(surfnr, domin, domout, 0)); + GetFaceDescriptor(faceind).SetBCProperty (bcp); + } + + infile >> nep; + if (!nep) nep = 3; + + Element2d tri(nep); + tri.SetIndex(faceind); + + for (j = 1; j <= nep; j++) + infile >> tri.PNum(j); + + if (invertsurf) + tri.Invert(); + + AddSurfaceElement (tri); + } + } + + if (strcmp (str, "surfaceelementsgi") == 0) + { + infile >> n; + PrintMessage (3, n, " surface elements"); + for (i = 1; i <= n; i++) + { + int j; + int surfnr, bcp, domin, domout, nep, faceind = 0; + infile >> surfnr >> bcp >> domin >> domout; + surfnr--; + + for (j = 1; j <= facedecoding.Size(); j++) + if (GetFaceDescriptor(j).SurfNr() == surfnr && + GetFaceDescriptor(j).BCProperty() == bcp && + GetFaceDescriptor(j).DomainIn() == domin && + GetFaceDescriptor(j).DomainOut() == domout) + faceind = j; + + if (!faceind) + { + faceind = AddFaceDescriptor (FaceDescriptor(surfnr, domin, domout, 0)); + GetFaceDescriptor(faceind).SetBCProperty (bcp); + } + + infile >> nep; + if (!nep) nep = 3; + + Element2d tri(nep); + tri.SetIndex(faceind); + + for (j = 1; j <= nep; j++) + infile >> tri.PNum(j); + + for (j = 1; j <= nep; j++) + infile >> tri.GeomInfoPi(j).trignum; + + if (invertsurf) + tri.Invert(); + + AddSurfaceElement (tri); + } + } + + if (strcmp (str, "volumeelements") == 0) + { + infile >> n; + PrintMessage (3, n, " volume elements"); + for (i = 1; i <= n; i++) + { + Element el; + int hi, nep; + infile >> hi; + if (hi == 0) hi = 1; + el.SetIndex(hi); + infile >> nep; + el.SetNP(nep); + + for (int j = 0; j < nep; j++) + infile >> (int&)(el[j]); + + if (inverttets) + el.Invert(); + + AddVolumeElement (el); + } + } + + + if (strcmp (str, "edgesegments") == 0) + { + infile >> n; + for (i = 1; i <= n; i++) + { + Segment seg; + int hi; + infile >> seg.si >> hi >> seg.p1 >> seg.p2; + AddSegment (seg); + } + } + + + + if (strcmp (str, "edgesegmentsgi") == 0) + { + infile >> n; + for (i = 1; i <= n; i++) + { + Segment seg; + int hi; + infile >> seg.si >> hi >> seg.p1 >> seg.p2 + >> seg.geominfo[0].trignum + >> seg.geominfo[1].trignum; + AddSegment (seg); + } + } + if (strcmp (str, "edgesegmentsgi2") == 0) + { + infile >> n; + PrintMessage (3, n, " curve elements"); + + for (i = 1; i <= n; i++) + { + Segment seg; + int hi; + infile >> seg.si >> hi >> seg.p1 >> seg.p2 + >> seg.geominfo[0].trignum + >> seg.geominfo[1].trignum + >> seg.surfnr1 >> seg.surfnr2 + >> seg.edgenr + // >> seg.epgeominfo[0].edgenr + // >> seg.epgeominfo[0].lefttrig + // >> seg.epgeominfo[0].righttrig + >> seg.epgeominfo[0].dist + >> seg.epgeominfo[1].edgenr + // >> seg.epgeominfo[1].lefttrig + // >> seg.epgeominfo[1].righttrig + >> seg.epgeominfo[1].dist; + // seg.edgenr = seg.epgeominfo[0].edgenr; + seg.epgeominfo[0].edgenr = seg.epgeominfo[1].edgenr; + + seg.surfnr1--; + seg.surfnr2--; + + AddSegment (seg); + } + } + + if (strcmp (str, "points") == 0) + { + infile >> n; + PrintMessage (3, n, " points"); + for (i = 1; i <= n; i++) + { + Point3d p; + infile >> p.X() >> p.Y() >> p.Z(); + p.X() *= scale; + p.Y() *= scale; + p.Z() *= scale; + AddPoint (p); + } + } + + if (strcmp (str, "identifications") == 0) + { + infile >> n; + for (i = 1; i <= n; i++) + { + PointIndex pi1, pi2; + int ind; + infile >> pi1 >> pi2 >> ind; + ident -> Add (pi1, pi2, ind); + } + } + if (strcmp (str, "materials") == 0) + { + infile >> n; + for (i = 1; i <= n; i++) + { + int nr; + string mat; + infile >> nr >> mat; + SetMaterial (nr, mat.c_str()); + } + } + + if (strcmp (str, "singular_points") == 0) + { + infile >> n; + for (i = 1; i <= n; i++) + { + PointIndex pi; + infile >> pi; + (*this)[pi].SetSingular (1); + } + } + + if (strcmp (str, "singular_edge_left") == 0) + { + infile >> n; + for (i = 1; i <= n; i++) + { + SegmentIndex si; + infile >> si; + (*this)[si].singedge_left = 1; + } + } + if (strcmp (str, "singular_edge_right") == 0) + { + infile >> n; + for (i = 1; i <= n; i++) + { + SegmentIndex si; + infile >> si; + (*this)[si].singedge_right = 1; + } + } + + if (strcmp (str, "singular_face_inside") == 0) + { + infile >> n; + for (i = 1; i <= n; i++) + { + SurfaceElementIndex sei; + infile >> sei; + GetFaceDescriptor((*this)[sei].GetIndex()).domin_singular = 1; + } + } + + if (strcmp (str, "singular_face_outside") == 0) + { + infile >> n; + for (i = 1; i <= n; i++) + { + SurfaceElementIndex sei; + infile >> sei; + GetFaceDescriptor((*this)[sei].GetIndex()).domout_singular = 1; + } + } + + + + strcpy (str, ""); + } + + CalcSurfacesOfNode (); + // BuildConnectedNodes (); + topology -> Update(); + clusters -> Update(); + + SetNextMajorTimeStamp(); + // PrintMemInfo (cout); + } + + + + + + + void Mesh :: Merge (const string & filename) + { + char str[100]; + int i, n; + + ifstream infile(filename.c_str()); + if (!infile.good()) + throw NgException ("mesh file not found"); + + int oldnp = GetNP(); + + while (infile.good()) + { + infile >> str; + + if (strcmp (str, "surfaceelementsgi") == 0) + { + infile >> n; + PrintMessage (3, n, " surface elements"); + for (i = 1; i <= n; i++) + { + int j; + int surfnr, bcp, domin, domout, nep, faceind = 0; + infile >> surfnr >> bcp >> domin >> domout; + surfnr--; + + // surfnr = 0; + // bcp = 1; + domin = 2; + domout = 1; + + for (j = 1; j <= facedecoding.Size(); j++) + if (GetFaceDescriptor(j).SurfNr() == surfnr && + GetFaceDescriptor(j).BCProperty() == bcp && + GetFaceDescriptor(j).DomainIn() == domin && + GetFaceDescriptor(j).DomainOut() == domout) + faceind = j; + + if (!faceind) + { + faceind = AddFaceDescriptor (FaceDescriptor(surfnr, domin, domout, 0)); + GetFaceDescriptor(faceind).SetBCProperty (bcp); + } + + infile >> nep; + if (!nep) nep = 3; + + Element2d tri(nep); + tri.SetIndex(faceind); + + for (j = 1; j <= nep; j++) + { + infile >> tri.PNum(j); + tri.PNum(j) = tri.PNum(j) + oldnp; + } + + for (j = 1; j <= nep; j++) + infile >> tri.GeomInfoPi(j).trignum; + + AddSurfaceElement (tri); + } + } + + 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); + } + } + + strcpy (str, ""); + } + + CalcSurfacesOfNode (); + + topology -> Update(); + clusters -> Update(); + + SetNextMajorTimeStamp(); + } + + + + + + + + + + + bool Mesh :: TestOk () const + { + for (ElementIndex ei = 0; ei < volelements.Size(); ei++) + { + for (int j = 0; j < 4; j++) + if ( (*this)[ei][j] <= PointIndex::BASE-1) + { + (*testout) << "El " << ei << " has 0 nodes: "; + for (int k = 0; k < 4; k++) + (*testout) << (*this)[ei][k]; + break; + } + } + CheckMesh3D (*this); + return 1; + } + + void Mesh :: CalcSurfacesOfNode () + { + int i, j, k; + SurfaceElementIndex sei; + + surfacesonnode.SetSize (GetNP()); + if (boundaryedges) + delete boundaryedges; + if (surfelementht) + delete surfelementht; + if (segmentht) + delete segmentht; + + boundaryedges = new INDEX_2_CLOSED_HASHTABLE<int> + (3 * (GetNSE() + GetNOpenElements()) + GetNSeg() + 1); + + /* + surfelementht = new INDEX_3_HASHTABLE<int> (GetNSE()/4 + 1); + segmentht = new INDEX_2_HASHTABLE<int> (GetNSeg() + 1); + */ + + surfelementht = new INDEX_3_CLOSED_HASHTABLE<int> (3*GetNSE() + 1); + segmentht = new INDEX_2_CLOSED_HASHTABLE<int> (3*GetNSeg() + 1); + + for (sei = 0; sei < GetNSE(); sei++) + { + const Element2d & sel = surfelements[sei]; + if (sel.IsDeleted()) continue; + + int si = sel.GetIndex(); + + for (j = 0; j < sel.GetNP(); j++) + { + PointIndex pi = sel[j]; + bool found = 0; + for (k = 0; k < surfacesonnode[pi].Size(); k++) + if (surfacesonnode[pi][k] == si) + { + found = 1; + break; + } + + if (!found) + surfacesonnode.Add (pi, si); + + INDEX_2 i2; + i2.I1() = sel.PNumMod(j+1); + i2.I2() = sel.PNumMod(j+2); + i2.Sort(); + if (sel.GetNP() <= 4) + boundaryedges->Set (i2, 1); + } + } + /* + for (sei = 0; sei < GetNSE(); sei++) + { + const Element2d & sel = surfelements[sei]; + if (sel.IsDeleted()) continue; + + INDEX_3 i3; + i3.I1() = sel.PNum(1); + i3.I2() = sel.PNum(2); + i3.I3() = sel.PNum(3); + i3.Sort(); + surfelementht -> PrepareSet (i3); + } + + surfelementht -> AllocateElements(); + */ + for (sei = 0; sei < GetNSE(); sei++) + { + const Element2d & sel = surfelements[sei]; + if (sel.IsDeleted()) continue; + + INDEX_3 i3; + i3.I1() = sel.PNum(1); + i3.I2() = sel.PNum(2); + i3.I3() = sel.PNum(3); + i3.Sort(); + surfelementht -> Set (i3, sel.GetIndex()); + } + + int np = GetNP(); + // ptyps.SetSize(np); + // ptyps = INNERPOINT; + for (PointIndex pi = PointIndex::BASE; + pi < np+PointIndex::BASE; pi++) + points[pi].SetType (INNERPOINT); + + if (GetNFD() == 0) // || GetFaceDescriptor(1).SurfNr() == 0) + { + for (sei = 0; sei < GetNSE(); sei++) + { + const Element2d & sel = surfelements[sei]; + if (sel.IsDeleted()) continue; + for (j = 0; j < sel.GetNP(); j++) + { + PointIndex pi = SurfaceElement(sei)[j]; + points[pi].SetType(FIXEDPOINT); + } + } + } + else + { + for (sei = 0; sei < GetNSE(); sei++) + { + const Element2d & sel = surfelements[sei]; + if (sel.IsDeleted()) continue; + for (j = 0; j < sel.GetNP(); j++) + { + PointIndex pi = sel[j]; + int ns = surfacesonnode[pi].Size(); + if (ns == 1) + points[pi].SetType(SURFACEPOINT); + if (ns == 2) + points[pi].SetType(EDGEPOINT); + if (ns >= 3) + points[pi].SetType(FIXEDPOINT); + } + } + } + + for (i = 0; i < segments.Size(); i++) + { + const Segment & seg = segments[i]; + for (j = 1; j <= 2; j++) + { + PointIndex hi = (j == 1) ? seg.p1 : seg.p2; + + if (points[hi].Type() == INNERPOINT || + points[hi].Type() == SURFACEPOINT) + points[hi].SetType(EDGEPOINT); + } + } + + + for (i = 0; i < lockedpoints.Size(); i++) + points[lockedpoints[i]].SetType(FIXEDPOINT); + + for (i = 0; i < openelements.Size(); i++) + { + const Element2d & sel = openelements[i]; + for (j = 0; j < sel.GetNP(); j++) + { + INDEX_2 i2; + i2.I1() = sel.PNumMod(j+1); + i2.I2() = sel.PNumMod(j+2); + i2.Sort(); + boundaryedges->Set (i2, 1); + + points[sel[j]].SetType(FIXEDPOINT); + } + } + + eltyps.SetSize (GetNE()); + eltyps = FREEELEMENT; + + for (i = 0; i < GetNSeg(); i++) + { + const Segment & seg = segments[i]; + INDEX_2 i2(seg.p1, seg.p2); + i2.Sort(); + + boundaryedges -> Set (i2, 2); + segmentht -> Set (i2, i); + } + } + + + void Mesh :: FixPoints (const BitArray & fixpoints) + { + if (fixpoints.Size() != GetNP()) + { + cerr << "Mesh::FixPoints: sizes don�t fit" << endl; + return; + } + int np = GetNP(); + for (int i = 1; i <= np; i++) + if (fixpoints.Test(i)) + { + points.Elem(i).SetType (FIXEDPOINT); + } + } + + + void Mesh :: FindOpenElements (int dom) + { + int i, ii, j, k, l; + PointIndex pi; + SurfaceElementIndex sei; + Element2d hel; + + + if (1) + { // nodebased + + int np = GetNP(); + int ne = GetNE(); + int nse = GetNSE(); + + ARRAY<int,PointIndex::BASE> numonpoint(np); + + Element2d hel; + + numonpoint = 0; + ElementIndex ei; + for (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 (j = 0; j < el.GetNP(); j++) + numonpoint[el[j]]++; + } + } + + TABLE<ElementIndex,PointIndex::BASE> elsonpoint(numonpoint); + for (ei = 0; ei < ne; ei++) + { + const Element & el = (*this)[ei]; + if (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 (j = 0; j < el.GetNP(); j++) + elsonpoint.Add (el[j], ei); + } + } + + numonpoint = 0; + for (i = 0; i < nse; i++) + { + int ind = surfelements[i].GetIndex(); + if ( + GetFaceDescriptor(ind).DomainIn() && + (dom == 0 || dom == GetFaceDescriptor(ind).DomainIn()) + || + GetFaceDescriptor(ind).DomainOut() && + (dom == 0 || dom == GetFaceDescriptor(ind).DomainOut()) + ) + { + hel = surfelements[i]; + hel.NormalizeNumbering(); + numonpoint[hel[0]]++; + } + } + + TABLE<SurfaceElementIndex,PointIndex::BASE> selsonpoint(numonpoint); + for (i = 0; i < nse; i++) + { + int ind = surfelements[i].GetIndex(); + if ( + GetFaceDescriptor(ind).DomainIn() && + (dom == 0 || dom == GetFaceDescriptor(ind).DomainIn()) + || + GetFaceDescriptor(ind).DomainOut() && + (dom == 0 || dom == GetFaceDescriptor(ind).DomainOut()) + ) + { + hel = surfelements[i]; + hel.NormalizeNumbering(); + selsonpoint.Add (hel[0], i); + } + } + + + INDEX_3_CLOSED_HASHTABLE<INDEX_2> faceht(100); + openelements.SetSize(0); + + for (pi = PointIndex::BASE; + pi < np+PointIndex::BASE; pi++) + if (selsonpoint[pi].Size()+elsonpoint[pi].Size()) + { + faceht.SetSize (2 * selsonpoint[pi].Size() + 4 * elsonpoint[pi].Size()); + + FlatArray<SurfaceElementIndex> row = selsonpoint[pi]; + for (ii = 0; ii < row.Size(); ii++) + { + hel = SurfaceElement(row[ii]); + int ind = hel.GetIndex(); + + if (GetFaceDescriptor(ind).DomainIn() && + (dom == 0 || dom == GetFaceDescriptor(ind).DomainIn()) ) + { + hel.NormalizeNumbering(); + if (hel.PNum(1) == pi) + { + INDEX_3 i3(hel[0], hel[1], hel[2]); + INDEX_2 i2 (GetFaceDescriptor(ind).DomainIn(), + (hel.GetNP() == 3) + ? PointIndex (PointIndex::BASE-1) + : hel.PNum(4)); + faceht.Set (i3, i2); + } + } + if (GetFaceDescriptor(ind).DomainOut() && + (dom == 0 || dom == GetFaceDescriptor(ind).DomainOut()) ) + { + hel.Invert(); + hel.NormalizeNumbering(); + if (hel.PNum(1) == pi) + { + INDEX_3 i3(hel[0], hel[1], hel[2]); + INDEX_2 i2 (GetFaceDescriptor(ind).DomainOut(), + (hel.GetNP() == 3) + ? PointIndex (PointIndex::BASE-1) + : hel.PNum(4)); + faceht.Set (i3, i2); + } + } + } + + + FlatArray<ElementIndex> rowel = elsonpoint[pi]; + for (ii = 0; ii < rowel.Size(); ii++) + { + const Element & el = VolumeElement(rowel[ii]); + + if (dom == 0 || el.GetIndex() == dom) + { + for (j = 1; j <= el.GetNFaces(); j++) + { + el.GetFace (j, hel); + hel.Invert(); + hel.NormalizeNumbering(); + + if (hel[0] == pi) + { + INDEX_3 i3(hel[0], hel[1], hel[2]); + + if (faceht.Used (i3)) + { + INDEX_2 i2 = faceht.Get(i3); + if (i2.I1() == el.GetIndex()) + { + i2.I1() = PointIndex::BASE-1; + faceht.Set (i3, i2); + } + else + { + if (i2.I1() == 0) + { + PrintSysError ("more elements on face"); + (*testout) << "more elements on face!!!" << endl; + (*testout) << "el = " << el << endl; + (*testout) << "hel = " << hel << endl; + (*testout) << "face = " << i3 << endl; + (*testout) << "points = " << endl; + for (int jj = 1; jj <= 3; jj++) + (*testout) << "p = " << Point(i3.I(jj)) << endl; + } + } + } + else + { + hel.Invert(); + hel.NormalizeNumbering(); + INDEX_3 i3(hel[0], hel[1], hel[2]); + INDEX_2 i2(el.GetIndex(), + (hel.GetNP() == 3) + ? PointIndex (PointIndex::BASE-1) + : hel[3]); + faceht.Set (i3, i2); + } + } + } + } + } + + for (i = 1; i <= faceht.Size(); i++) + if (faceht.UsedPos (i)) + { + INDEX_3 i3; + INDEX_2 i2; + faceht.GetData (i, i3, i2); + if (i2.I1() != PointIndex::BASE-1) + { + Element2d tri; + tri.SetType ( (i2.I2() == PointIndex::BASE-1) ? TRIG : QUAD); + for (l = 0; l < 3; l++) + tri[l] = i3.I(l+1); + tri.PNum(4) = i2.I2(); + tri.SetIndex (i2.I1()); + + // tri.Invert(); + + openelements.Append (tri); + } + } + } + } + + +#ifdef OLD + + else if (GetNE() || 1) + { + // new version, general elemetns + // hash index: pnum1-3 + // hash data : domain nr, pnum4 + + openelements.SetSize(0); + + + const int steps = 4; + + for (k = 0; k < steps; k++) + { + + INDEX_3_CLOSED_HASHTABLE<INDEX_2> faceht( (5 * GetNE() + 2 * GetNSE() ) / steps +1); + + for (i = 1; i <= GetNSE(); i++) + { + hel = SurfaceElement(i); + int ind = hel.GetIndex(); + + + if (GetFaceDescriptor(ind).DomainIn() && + (dom == 0 || dom == GetFaceDescriptor(ind).DomainIn()) ) + { + hel.Invert(); + hel.NormalizeNumbering(); + if (hel.PNum(1) % steps == k) + { + INDEX_3 i3(hel.PNum(1), hel.PNum(2), hel.PNum(3)); + INDEX_2 i2 (GetFaceDescriptor(ind).DomainIn(), + (hel.GetNP() == 3) + ? PointIndex (PointIndex::BASE-1) + : hel.PNum(4)); + faceht.Set (i3, i2); + } + } + if (GetFaceDescriptor(ind).DomainOut() && + (dom == 0 || dom == GetFaceDescriptor(ind).DomainOut()) ) + { + hel.NormalizeNumbering(); + if (hel.PNum(1) % steps == k) + { + INDEX_3 i3(hel.PNum(1), hel.PNum(2), hel.PNum(3)); + INDEX_2 i2 (GetFaceDescriptor(ind).DomainOut(), + (hel.GetNP() == 3) + ? PointIndex(0) + : hel.PNum(4)); + faceht.Set (i3, i2); + } + } + } + + for (i = 1; i <= GetNE(); i++) + { + const Element & el = VolumeElement(i); + + if (dom == 0 || el.GetIndex() == dom) + { + for (j = 1; j <= el.GetNFaces(); j++) + { + el.GetFace (j, hel); + + hel.NormalizeNumbering(); + if (hel.PNum(1) % steps != k) + continue; + + INDEX_3 i3(hel.PNum(1), hel.PNum(2), hel.PNum(3)); + + int pos = faceht.Position (i3); + if (pos) + { + INDEX_2 i2; + faceht.GetData (pos, i2); + if (i2.I1() == el.GetIndex()) + { + i2.I1() = 0; + faceht.SetData (pos, i2); + } + else + { + if (i2.I1() == 0) + PrintSysError ("more elements on face"); + } + } + else + { + hel.Invert(); + hel.NormalizeNumbering(); + INDEX_3 i3(hel.PNum(1), hel.PNum(2), hel.PNum(3)); + INDEX_2 i2(el.GetIndex(), + (hel.GetNP() == 3) + ? PointIndex(0) + : hel.PNum(4)); + faceht.Set (i3, i2); + } + } + } + } + + for (i = 1; i <= faceht.Size(); i++) + if (faceht.UsedPos (i)) + { + INDEX_3 i3; + INDEX_2 i2; + faceht.GetData (i, i3, i2); + if (i2.I1() != 0) + { + Element2d tri; + tri.SetType ( (i2.I2() == 0) ? TRIG : QUAD); + for (l = 1; l <= 3; l++) + tri.PNum(l) = i3.I(l); + tri.PNum(4) = i2.I2(); + tri.SetIndex (i2.I1()); + + tri.Invert(); + + openelements.Append (tri); + } + } + /* + cout << "FindOpenElements, mem = "; + faceht.PrintMemInfo (cout); + */ + } + + + + + /* + // open hashing version: + + INDEX_3_HASHTABLE<INDEX_2> faceht(4 * GetNE()+GetNSE()+1); + + for (i = 1; i <= GetNSE(); i++) + { + Element2d hel = SurfaceElement(i); + int ind = hel.GetIndex(); + + + if (GetFaceDescriptor(ind).DomainIn() && + (dom == 0 || dom == GetFaceDescriptor(ind).DomainIn()) ) + { + hel.NormalizeNumbering(); + INDEX_3 i3(hel.PNum(1), hel.PNum(2), hel.PNum(3)); + INDEX_2 i2 (GetFaceDescriptor(ind).DomainIn(), + (hel.GetNP() == 3) ? 0 : hel.PNum(4)); + faceht.Set (i3, i2); + } + if (GetFaceDescriptor(ind).DomainOut() && + (dom == 0 || dom == GetFaceDescriptor(ind).DomainOut()) ) + { + hel.Invert(); + hel.NormalizeNumbering(); + INDEX_3 i3(hel.PNum(1), hel.PNum(2), hel.PNum(3)); + INDEX_2 i2 (GetFaceDescriptor(ind).DomainOut(), + (hel.GetNP() == 3) ? 0 : hel.PNum(4)); + faceht.Set (i3, i2); + } + } + + for (i = 1; i <= GetNE(); i++) + { + const Element & el = VolumeElement(i); + // INDEX_3 i3; + + if (dom == 0 || el.GetIndex() == dom) + { + for (j = 1; j <= el.GetNFaces(); j++) + { + Element2d hel; + el.GetFace (j, hel); + hel.Invert(); + + hel.NormalizeNumbering(); + INDEX_3 i3(hel.PNum(1), hel.PNum(2), hel.PNum(3)); + + if (faceht.Used (i3)) + { + INDEX_2 i2 = faceht.Get(i3); + if (i2.I1() == el.GetIndex()) + { + i2.I1() = 0; + faceht.Set (i3, i2); + } + else + { + if (i2.I1() == 0) + PrintSysError ("more elements on face"); + } + } + else + { + hel.Invert(); + hel.NormalizeNumbering(); + INDEX_3 i3(hel.PNum(1), hel.PNum(2), hel.PNum(3)); + INDEX_2 i2(el.GetIndex(), + (hel.GetNP() == 3) ? 0 : hel.PNum(4)); + faceht.Set (i3, i2); + } + } + } + } + + + openelements.SetSize(0); + for (i = 1; i <= faceht.GetNBags(); i++) + for (j = 1; j <= faceht.GetBagSize(i); j++) + { + INDEX_3 i3; + INDEX_2 i2; + faceht.GetData (i, j, i3, i2); + if (i2.I1() != 0) + { + Element2d tri; + tri.SetNP ( (i2.I2() == 0) ? 3 : 4); + for (k = 1; k <= 3; k++) + tri.PNum(k) = i3.I(k); + tri.PNum(4) = i2.I2(); + tri.SetIndex (i2.I1()); + + openelements.Append (tri); + } + } + */ + + } + else + { + for (i = 1; i <= GetNSE(); i++) + { + Element2d hel = SurfaceElement(i); + int ind = SurfaceElement(i).GetIndex(); + + if (GetFaceDescriptor(ind).DomainIn()) + openelements.Append (hel); + if (GetFaceDescriptor(ind).DomainOut()) + { + hel.Invert(); + openelements.Append (hel); + } + } + } +#endif + + + int cnt3 = 0, cnt4 = 0; + for (i = 1; i <= openelements.Size(); i++) + if (openelements.Elem(i).GetNP() == 3) + cnt3++; + else + cnt4++; + + + MyStr treequad; + if (cnt4) + treequad = MyStr(" (") + MyStr(cnt3) + MyStr (" + ") + + MyStr(cnt4) + MyStr(")"); + + PrintMessage (5, openelements.Size(), treequad, " open elements"); + + + for (i = 1; i <= openelements.Size(); i++) + { + const Element2d & sel = openelements.Get(i); + + if (boundaryedges) + for (j = 1; j <= sel.GetNP(); j++) + { + INDEX_2 i2; + i2.I1() = sel.PNumMod(j); + i2.I2() = sel.PNumMod(j+1); + i2.Sort(); + boundaryedges->Set (i2, 1); + } + + for (j = 1; j <= 3; j++) + { + int pi = sel.PNum(j); + if (pi < points.Size()+PointIndex::BASE) + points[pi].SetType (FIXEDPOINT); + } + } + + + for (i = 1; i <= GetNSeg(); i++) + { + const Segment & seg = LineSegment(i); + INDEX_2 i2(seg.p1, seg.p2); + i2.Sort(); + + if (!boundaryedges->Used (i2)) + cerr << "WARNING: no boundedge, but seg edge: " << i2 << endl; + + boundaryedges -> Set (i2, 2); + segmentht -> Set (i2, i-1); + } + } + + int Mesh :: HasOpenQuads () const + { + int i; + int no = GetNOpenElements(); + for (i = 1; i <= no; i++) + if (OpenElement(i).GetNP() == 4) + return 1; + return 0; + } + + + + + + void Mesh :: FindOpenSegments (int surfnr) + { + int i, j, k; + + // new version, general elemetns + // hash index: pnum1-2 + // hash data : surfnr, surfel-nr (pos) or segment nr(neg) + INDEX_2_HASHTABLE<INDEX_2> faceht(4 * GetNSE()+GetNSeg()+1); + + PrintMessage (5, "Test Opensegments"); + for (i = 1; i <= GetNSeg(); i++) + { + const Segment & seg = LineSegment (i); + + if (surfnr == 0 || seg.si == surfnr) + { + INDEX_2 key(seg.p1, seg.p2); + INDEX_2 data(seg.si, -i); + + if (faceht.Used (key)) + { + cerr << "ERROR: Segment " << seg << " already used" << endl; + (*testout) << "ERROR: Segment " << seg << " already used" << endl; + } + + faceht.Set (key, data); + } + } + + + for (i = 1; i <= GetNSeg(); i++) + { + const Segment & seg = LineSegment (i); + + if (surfnr == 0 || seg.si == surfnr) + { + INDEX_2 key(seg.p2, seg.p1); + if (!faceht.Used(key)) + { + cerr << "ERROR: Segment " << seg << " brother not used" << endl; + (*testout) << "ERROR: Segment " << seg << " brother not used" << endl; + } + } + } + + + for (i = 1; i <= GetNSE(); i++) + { + const Element2d & el = SurfaceElement(i); + if (el.IsDeleted()) continue; + + if (surfnr == 0 || el.GetIndex() == surfnr) + { + for (j = 1; j <= el.GetNP(); j++) + { + INDEX_2 seg (el.PNumMod(j), el.PNumMod(j+1)); + INDEX_2 data; + + if (seg.I1() <= 0 || seg.I2() <= 0) + cerr << "seg = " << seg << endl; + + if (faceht.Used(seg)) + { + data = faceht.Get(seg); + if (data.I1() == el.GetIndex()) + { + data.I1() = 0; + faceht.Set (seg, data); + } + else + { + PrintSysError ("hash table si not fitting for segment: ", + seg.I1(), "-", seg.I2(), " other = ", + data.I2()); + } + } + else + { + Swap (seg.I1(), seg.I2()); + data.I1() = el.GetIndex(); + data.I2() = i; + + faceht.Set (seg, data); + } + } + } + } + + (*testout) << "open segments: " << endl; + opensegments.SetSize(0); + for (i = 1; i <= faceht.GetNBags(); i++) + for (j = 1; j <= faceht.GetBagSize(i); j++) + { + INDEX_2 i2; + INDEX_2 data; + faceht.GetData (i, j, i2, data); + if (data.I1()) // surfnr + { + Segment seg; + seg.p1 = i2.I1(); + seg.p2 = i2.I2(); + seg.si = data.I1(); + + // find geomdata: + if (data.I2() > 0) + { + // segment due to triangle + const Element2d & el = SurfaceElement (data.I2()); + for (k = 1; k <= el.GetNP(); k++) + { + if (seg.p1 == el.PNum(k)) + seg.geominfo[0] = el.GeomInfoPi(k); + if (seg.p2 == el.PNum(k)) + seg.geominfo[1] = el.GeomInfoPi(k); + } + + (*testout) << "trig seg: "; + } + else + { + // segment due to line + const Segment & lseg = LineSegment (-data.I2()); + seg.geominfo[0] = lseg.geominfo[0]; + seg.geominfo[1] = lseg.geominfo[1]; + + (*testout) << "line seg: "; + } + + (*testout) << seg.p1 << " - " << seg.p2 + << " len = " << Dist (Point(seg.p1), Point(seg.p2)) + << endl; + + opensegments.Append (seg); + if (seg.geominfo[0].trignum <= 0 || seg.geominfo[1].trignum <= 0) + { + (*testout) << "Problem with open segment: " << seg << endl; + } + + } + } + + PrintMessage (3, opensegments.Size(), " open segments found"); + (*testout) << opensegments.Size() << " open segments found" << endl; + + /* + ptyps.SetSize (GetNP()); + for (i = 1; i <= ptyps.Size(); i++) + ptyps.Elem(i) = SURFACEPOINT; + + for (i = 1; i <= GetNSeg(); i++) + { + const Segment & seg = LineSegment (i); + ptyps.Elem(seg.p1) = EDGEPOINT; + ptyps.Elem(seg.p2) = EDGEPOINT; + } + for (i = 1; i <= GetNOpenSegments(); i++) + { + const Segment & seg = GetOpenSegment (i); + ptyps.Elem(seg.p1) = EDGEPOINT; + ptyps.Elem(seg.p2) = EDGEPOINT; + } + */ + for (i = 1; i <= points.Size(); i++) + points.Elem(i).SetType(SURFACEPOINT); + + for (i = 1; i <= GetNSeg(); i++) + { + const Segment & seg = LineSegment (i); + points[seg.p1].SetType(EDGEPOINT); + points[seg.p2].SetType(EDGEPOINT); + } + for (i = 1; i <= GetNOpenSegments(); i++) + { + const Segment & seg = GetOpenSegment (i); + points[seg.p1].SetType (EDGEPOINT); + points[seg.p2].SetType (EDGEPOINT); + } + + + + /* + + for (i = 1; i <= openelements.Size(); i++) + { + const Element2d & sel = openelements.Get(i); + + if (boundaryedges) + for (j = 1; j <= sel.GetNP(); j++) + { + INDEX_2 i2; + i2.I1() = sel.PNumMod(j); + i2.I2() = sel.PNumMod(j+1); + i2.Sort(); + boundaryedges->Set (i2, 1); + } + + for (j = 1; j <= 3; j++) + { + int pi = sel.PNum(j); + if (pi <= ptyps.Size()) + ptyps.Elem(pi) = FIXEDPOINT; + } + } + */ + } + + + void Mesh :: RemoveOneLayerSurfaceElements () + { + int i, j; + int np = GetNP(); + + FindOpenSegments(); + BitArray frontpoints(np); + + frontpoints.Clear(); + for (i = 1; i <= GetNOpenSegments(); i++) + { + const Segment & seg = GetOpenSegment(i); + frontpoints.Set (seg.p1); + frontpoints.Set (seg.p2); + } + + for (i = 1; i <= GetNSE(); i++) + { + Element2d & sel = surfelements.Elem(i); + int remove = 0; + for (j = 1; j <= sel.GetNP(); j++) + if (frontpoints.Test(sel.PNum(j))) + remove = 1; + if (remove) + sel.PNum(1) = 0; + } + + for (i = surfelements.Size(); i >= 1; i--) + { + if (surfelements.Elem(i).PNum(1) == 0) + { + surfelements.Elem(i) = surfelements.Last(); + surfelements.DeleteLast(); + } + } + timestamp = NextTimeStamp(); + // Compress(); + } + + + + + + void Mesh :: FreeOpenElementsEnvironment (int layers) + { + int i, j, k; + PointIndex pi; + const int large = 9999; + ARRAY<int,PointIndex::BASE> dist(GetNP()); + + dist = large; + + for (i = 1; i <= GetNOpenElements(); i++) + { + const Element2d & face = OpenElement(i); + for (j = 1; j <= face.GetNP(); j++) + dist[face.PNum(j)] = 1; + } + + for (k = 1; k <= layers; k++) + for (i = 1; i <= GetNE(); i++) + { + const Element & el = VolumeElement(i); + if (el[0] == -1 || el.IsDeleted()) continue; + + int elmin = large; + for (j = 0; j < el.GetNP(); j++) + if (dist[el[j]] < elmin) + elmin = dist[el[j]]; + + if (elmin < large) + { + for (j = 0; j < el.GetNP(); j++) + if (dist[el[j]] > elmin+1) + dist[el[j]] = elmin+1; + } + } + + int cntfree = 0; + for (i = 1; i <= GetNE(); i++) + { + const Element & el = VolumeElement(i); + if (el[0] == -1 || el.IsDeleted()) continue; + + int elmin = large; + for (j = 0; j < el.GetNP(); j++) + if (dist[el[j]] < elmin) + elmin = dist[el[j]]; + + eltyps.Elem(i) = (elmin <= layers) ? + FREEELEMENT : FIXEDELEMENT; + if (elmin <= layers) + cntfree++; + } + + PrintMessage (5, "free: ", cntfree, ", fixed: ", GetNE()-cntfree); + (*testout) << "free: " << cntfree << ", fixed: " << GetNE()-cntfree << endl; + + for (pi = PointIndex::BASE; + pi < GetNP()+PointIndex::BASE; pi++) + { + if (dist[pi] > layers+1) + points[pi].SetType(FIXEDPOINT); + } + } + + + + void Mesh :: SetLocalH (const Point3d & pmin, const Point3d & pmax, double grading) + { + Point3d c = Center (pmin, pmax); + double d = max3 (pmax.X()-pmin.X(), + pmax.Y()-pmin.Y(), + pmax.Z()-pmin.Z()); + d /= 2; + Point3d pmin2 = c - Vec3d (d, d, d); + Point3d pmax2 = c + Vec3d (d, d, d); + + + delete lochfunc; + lochfunc = new LocalH (pmin2, pmax2, grading); + } + + void Mesh :: RestrictLocalH (const Point3d & p, double hloc) + { + //cout << "restrict h in " << p << " to " << hloc << endl; + if (!lochfunc) + { + PrintWarning("RestrictLocalH called, creating mesh-size tree"); + + Point3d boxmin, boxmax; + GetBox (boxmin, boxmax); + SetLocalH (boxmin, boxmax, 0.8); + } + + lochfunc -> SetH (p, hloc); + } + + void Mesh :: RestrictLocalHLine (const Point3d & p1, + const Point3d & p2, + double hloc) + { + // cout << "restrict h along " << p1 << " - " << p2 << " to " << hloc << endl; + int i; + int steps = int (Dist (p1, p2) / hloc) + 2; + Vec3d v(p1, p2); + + for (i = 0; i <= steps; i++) + { + Point3d p = p1 + (double(i)/double(steps) * v); + RestrictLocalH (p, hloc); + } + } + + + void Mesh :: SetGlobalH (double h) + { + hglob = h; + } + + double Mesh :: MaxHDomain (int dom) const + { + if (maxhdomain.Size()) + return maxhdomain.Get(dom); + else + return 1e10; + } + + void Mesh :: SetMaxHDomain (const ARRAY<double> & mhd) + { + maxhdomain.SetSize(mhd.Size()); + for (int i = 1; i <= mhd.Size(); i++) + maxhdomain.Elem(i) = mhd.Get(i); + } + + + double Mesh :: GetH (const Point3d & p) const + { + double hmin = hglob; + if (lochfunc) + { + double hl = lochfunc->GetH (p); + if (hl < hglob) + hmin = hl; + } + return hmin; + } + + double Mesh :: GetMinH (const Point3d & pmin, const Point3d & pmax) + { + double hmin = hglob; + if (lochfunc) + { + double hl = lochfunc->GetMinH (pmin, pmax); + if (hl < hmin) + hmin = hl; + } + return hmin; + } + + + + + + double Mesh :: AverageH (int surfnr) const + { + int i, j, n; + double hi, hsum; + double maxh = 0, minh = 1e10; + + hsum = 0; + n = 0; + for (i = 1; i <= GetNSE(); i++) + { + const Element2d & el = SurfaceElement(i); + if (surfnr == 0 || el.GetIndex() == surfnr) + { + for (j = 1; j <= 3; j++) + { + hi = Dist (Point (el.PNumMod(j)), + Point (el.PNumMod(j+1))); + + hsum += hi; + + if (hi > maxh) maxh = hi; + if (hi < minh) minh = hi; + n++; + } + } + } + + PrintMessage (5, "minh = ", minh, " avh = ", (hsum/n), " maxh = ", maxh); + return (hsum / n); + } + + + + void Mesh :: CalcLocalH () + { + if (!lochfunc) + { + Point3d pmin, pmax; + GetBox (pmin, pmax); + SetLocalH (pmin, pmax, mparam.grading); + } + + PrintMessage (3, + "CalcLocalH: ", + GetNP(), " Points ", + GetNE(), " Elements ", + GetNSE(), " Surface Elements"); + + + int i; + for (i = 0; i < GetNSE(); i++) + { + const Element2d & el = surfelements[i]; + int j; + + if (el.GetNP() == 3) + { + double hel = -1; + for (j = 1; j <= 3; j++) + { + const Point3d & p1 = points[el.PNumMod(j)]; + const Point3d & p2 = points[el.PNumMod(j+1)]; + + /* + INDEX_2 i21(el.PNumMod(j), el.PNumMod(j+1)); + INDEX_2 i22(el.PNumMod(j+1), el.PNumMod(j)); + if (! identifiedpoints->Used (i21) && + ! identifiedpoints->Used (i22) ) + */ + if (!ident -> UsedSymmetric (el.PNumMod(j), + el.PNumMod(j+1))) + { + double hedge = Dist (p1, p2); + if (hedge > hel) + hel = hedge; + // lochfunc->SetH (Center (p1, p2), 2 * Dist (p1, p2)); + // (*testout) << "trigseth, p1,2 = " << el.PNumMod(j) << ", " << el.PNumMod(j+1) + // << " h = " << (2 * Dist(p1, p2)) << endl; + } + } + + if (hel > 0) + { + const Point3d & p1 = points[el.PNum(1)]; + const Point3d & p2 = points[el.PNum(2)]; + const Point3d & p3 = points[el.PNum(3)]; + lochfunc->SetH (Center (p1, p2, p3), hel); + } + } + else + { + { + const Point3d & p1 = points[el.PNum(1)]; + const Point3d & p2 = points[el.PNum(2)]; + lochfunc->SetH (Center (p1, p2), 2 * Dist (p1, p2)); + } + { + const Point3d & p1 = points[el.PNum(3)]; + const Point3d & p2 = points[el.PNum(4)]; + lochfunc->SetH (Center (p1, p2), 2 * Dist (p1, p2)); + } + } + } + + for (i = 0; i < GetNSeg(); i++) + { + const Segment & seg = segments[i]; + const Point3d & p1 = points[seg.p1]; + const Point3d & p2 = points[seg.p2]; + /* + INDEX_2 i21(seg.p1, seg.p2); + INDEX_2 i22(seg.p2, seg.p1); + if (identifiedpoints) + if (!identifiedpoints->Used (i21) && !identifiedpoints->Used (i22)) + */ + if (!ident -> UsedSymmetric (seg.p1, seg.p2)) + { + lochfunc->SetH (Center (p1, p2), Dist (p1, p2)); + } + } + /* + cerr << "do vol" << endl; + for (i = 1; i <= GetNE(); i++) + { + const Element & el = VolumeElement(i); + if (el.GetType() == TET) + { + int j, k; + for (j = 2; j <= 4; j++) + for (k = 1; k < j; k++) + { + const Point3d & p1 = Point (el.PNum(j)); + const Point3d & p2 = Point (el.PNum(k)); + lochfunc->SetH (Center (p1, p2), 2 * Dist (p1, p2)); + (*testout) << "set vol h to " << (2 * Dist (p1, p2)) << endl; + + } + } + } + */ + + /* + const char * meshsizefilename = + globflags.GetStringFlag ("meshsize", NULL); + if (meshsizefilename) + { + ifstream msf(meshsizefilename); + if (msf) + { + int nmsp; + msf >> nmsp; + for (i = 1; i <= nmsp; i++) + { + Point3d pi; + double hi; + msf >> pi.X() >> pi.Y() >> pi.Z(); + msf >> hi; + lochfunc->SetH (pi, hi); + } + } + } + */ + // lochfunc -> Convexify(); + // lochfunc -> PrintMemInfo (cout); + } + + + void Mesh :: CalcLocalHFromPointDistances(void) + { + PrintMessage (3, "Calculating local h from point distances"); + + if (!lochfunc) + { + Point3d pmin, pmax; + GetBox (pmin, pmax); + + SetLocalH (pmin, pmax, mparam.grading); + } + + PointIndex i,j; + double hl; + + + for (i = PointIndex::BASE; + i < GetNP()+PointIndex::BASE; i++) + { + for(j=i+1; j<GetNP()+PointIndex::BASE; j++) + { + const Point3d & p1 = points[i]; + const Point3d & p2 = points[j]; + hl = Dist(p1,p2); + RestrictLocalH(p1,hl); + RestrictLocalH(p2,hl); + //cout << "restricted h at " << p1 << " and " << p2 << " to " << hl << endl; + } + } + + + } + + + void Mesh :: CalcLocalHFromSurfaceCurvature (double elperr) + { + PrintMessage (3, "Calculating local h from surface curvature"); + + if (!lochfunc) + { + Point3d pmin, pmax; + GetBox (pmin, pmax); + + SetLocalH (pmin, pmax, mparam.grading); + } + + + INDEX_2_HASHTABLE<int> edges(3 * GetNP() + 2); + INDEX_2_HASHTABLE<int> bedges(GetNSeg() + 2); + int i, j; + + for (i = 1; i <= GetNSeg(); i++) + { + const Segment & seg = LineSegment(i); + INDEX_2 i2(seg.p1, seg.p2); + i2.Sort(); + bedges.Set (i2, 1); + } + for (i = 1; i <= GetNSE(); i++) + { + const Element2d & sel = SurfaceElement(i); + if (!sel.PNum(1)) + continue; + for (j = 1; j <= 3; j++) + { + INDEX_2 i2(sel.PNumMod(j), sel.PNumMod(j+1)); + i2.Sort(); + if (bedges.Used(i2)) continue; + + if (edges.Used(i2)) + { + int other = edges.Get(i2); + + const Element2d & elother = SurfaceElement(other); + + int pi3 = 1; + while ( (sel.PNum(pi3) == i2.I1()) || + (sel.PNum(pi3) == i2.I2())) + pi3++; + pi3 = sel.PNum(pi3); + + int pi4 = 1; + while ( (elother.PNum(pi4) == i2.I1()) || + (elother.PNum(pi4) == i2.I2())) + pi4++; + pi4 = elother.PNum(pi4); + + double rad = ComputeCylinderRadius (Point (i2.I1()), + Point (i2.I2()), + Point (pi3), + Point (pi4)); + + RestrictLocalHLine (Point(i2.I1()), Point(i2.I2()), rad/elperr); + + + /* + (*testout) << "pi1,2, 3, 4 = " << i2.I1() << ", " << i2.I2() << ", " << pi3 << ", " << pi4 + << " p1 = " << Point(i2.I1()) + << ", p2 = " << Point(i2.I2()) + // << ", p3 = " << Point(pi3) + // << ", p4 = " << Point(pi4) + << ", rad = " << rad << endl; + */ + } + else + edges.Set (i2, i); + } + } + + + // Restrict h due to line segments + + for (i = 1; i <= GetNSeg(); i++) + { + const Segment & seg = LineSegment(i); + const Point3d & p1 = Point(seg.p1); + const Point3d & p2 = Point(seg.p2); + RestrictLocalH (Center (p1, p2), Dist (p1, p2)); + } + + + + /* + + + int i, j; + int np = GetNP(); + int nseg = GetNSeg(); + int nse = GetNSE(); + + ARRAY<Vec3d> normals(np); + BitArray linepoint(np); + + linepoint.Clear(); + for (i = 1; i <= nseg; i++) + { + linepoint.Set (LineSegment(i).p1); + linepoint.Set (LineSegment(i).p2); + } + + for (i = 1; i <= np; i++) + normals.Elem(i) = Vec3d(0,0,0); + + for (i = 1; i <= nse; i++) + { + Element2d & el = SurfaceElement(i); + Vec3d nf = Cross (Vec3d (Point (el.PNum(1)), Point(el.PNum(2))), + Vec3d (Point (el.PNum(1)), Point(el.PNum(3)))); + for (j = 1; j <= 3; j++) + normals.Elem(el.PNum(j)) += nf; + } + + for (i = 1; i <= np; i++) + normals.Elem(i) /= (1e-12 + normals.Elem(i).Length()); + + for (i = 1; i <= nse; i++) + { + Element2d & el = SurfaceElement(i); + Vec3d nf = Cross (Vec3d (Point (el.PNum(1)), Point(el.PNum(2))), + Vec3d (Point (el.PNum(1)), Point(el.PNum(3)))); + nf /= nf.Length(); + Point3d c = Center (Point(el.PNum(1)), + Point(el.PNum(2)), + Point(el.PNum(3))); + + for (j = 1; j <= 3; j++) + { + if (!linepoint.Test (el.PNum(j))) + { + double dist = Dist (c, Point(el.PNum(j))); + double dn = (nf - normals.Get(el.PNum(j))).Length(); + + RestrictLocalH (Point(el.PNum(j)), dist / (dn+1e-12) /elperr); + } + } + } + */ + } + + + void Mesh :: RestrictLocalH (resthtype rht, int nr, double loch) + { + int i; + switch (rht) + { + case RESTRICTH_FACE: + { + for (i = 1; i <= GetNSE(); i++) + { + const Element2d & sel = SurfaceElement(i); + if (sel.GetIndex() == nr) + RestrictLocalH (RESTRICTH_SURFACEELEMENT, i, loch); + } + break; + } + case RESTRICTH_EDGE: + { + for (i = 1; i <= GetNSeg(); i++) + { + const Segment & seg = LineSegment(i); + if (seg.edgenr == nr) + RestrictLocalH (RESTRICTH_SEGMENT, i, loch); + } + break; + } + case RESTRICTH_POINT: + { + RestrictLocalH (Point (nr), loch); + break; + } + + case RESTRICTH_SURFACEELEMENT: + { + const Element2d & sel = SurfaceElement(nr); + Point3d p = Center (Point(sel.PNum(1)), + Point(sel.PNum(2)), + Point(sel.PNum(3))); + RestrictLocalH (p, loch); + break; + } + case RESTRICTH_SEGMENT: + { + const Segment & seg = LineSegment(nr); + RestrictLocalHLine (Point (seg.p1), Point(seg.p2), loch); + break; + } + } + } + + + void Mesh :: LoadLocalMeshSize (const char * meshsizefilename) + { + if (!meshsizefilename) return; + + ifstream msf(meshsizefilename); + + if (!msf) return; + + PrintMessage (3, "Load local mesh-size"); + int nmsp, nmsl; + msf >> 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 ("problem in mesh-size file\n"); + RestrictLocalH (pi, hi); + } + msf >> 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 ("problem in mesh-size file\n"); + RestrictLocalHLine (p1, p2, hi); + } + } + + + + void Mesh :: GetBox (Point3d & pmin, Point3d & pmax, int dom) const + { + if (points.Size() == 0) + { + pmin = pmax = Point3d(0,0,0); + return; + } + + if (dom <= 0) + { + pmin = Point3d (1e10, 1e10, 1e10); + pmax = Point3d (-1e10, -1e10, -1e10); + + for (PointIndex pi = PointIndex::BASE; + pi < GetNP()+PointIndex::BASE; pi++) + { + pmin.SetToMin ( (*this) [pi] ); + pmax.SetToMax ( (*this) [pi] ); + } + } + else + { + int j, nse = GetNSE(); + SurfaceElementIndex sei; + + pmin = Point3d (1e10, 1e10, 1e10); + pmax = Point3d (-1e10, -1e10, -1e10); + for (sei = 0; sei < nse; sei++) + { + const Element2d & el = (*this)[sei]; + if (el.IsDeleted() ) continue; + + if (dom == -1 || el.GetIndex() == dom) + { + for (j = 0; j < 3; j++) + { + pmin.SetToMin ( (*this) [el[j]] ); + pmax.SetToMax ( (*this) [el[j]] ); + } + } + } + } + + if (pmin.X() > 0.5e10) + { + pmin = pmax = Point3d(0,0,0); + } + } + + + + + void Mesh :: GetBox (Point3d & pmin, Point3d & pmax, POINTTYPE ptyp) const + { + if (points.Size() == 0) + { + pmin = pmax = Point3d(0,0,0); + return; + } + + pmin = Point3d (1e10, 1e10, 1e10); + pmax = Point3d (-1e10, -1e10, -1e10); + + for (PointIndex pi = PointIndex::BASE; + pi < GetNP()+PointIndex::BASE; pi++) + if (points[pi].Type() <= ptyp) + { + pmin.SetToMin ( (*this) [pi] ); + pmax.SetToMax ( (*this) [pi] ); + } + } + + + + + double Mesh :: ElementError (int eli) const + { + const Element & el = volelements.Get(eli); + return CalcTetBadness (points.Get(el[0]), points.Get(el[1]), + points.Get(el[2]), points.Get(el[3]), -1); + } + + void Mesh :: AddLockedPoint (PointIndex pi) + { + lockedpoints.Append (pi); + } + + void Mesh :: ClearLockedPoints () + { + lockedpoints.SetSize (0); + } + + + + void Mesh :: Compress () + { + int i, j; + ARRAY<int,PointIndex::BASE> op2np(GetNP()); + ARRAY<MeshPoint> hpoints; + BitArrayChar<PointIndex::BASE> pused(GetNP()); + + /* + (*testout) << "volels: " << endl; + for (i = 1; i <= volelements.Size(); i++) + { + for (j = 1; j <= volelements.Get(i).GetNP(); j++) + (*testout) << volelements.Get(i).PNum(j) << " "; + (*testout) << endl; + } + (*testout) << "np: " << GetNP() << endl; + */ + + for (i = 0; i < volelements.Size(); i++) + if (volelements[i][0] <= PointIndex::BASE-1 || + volelements[i].IsDeleted()) + { + volelements.Delete(i); + i--; + } + + + for (i = 0; i < surfelements.Size(); i++) + if (surfelements[i].IsDeleted()) + { + surfelements.Delete(i); + i--; + } + + for (i = 0; i < segments.Size(); i++) + if (segments[i].p1 <= PointIndex::BASE-1) + { + segments.Delete(i); + i--; + } + + pused.Clear(); + for (i = 0; i < volelements.Size(); i++) + { + const Element & el = volelements[i]; + for (j = 0; j < el.GetNP(); j++) + pused.Set (el[j]); + } + + for (i = 0; i < surfelements.Size(); i++) + { + const Element2d & el = surfelements[i]; + for (j = 0; j < el.GetNP(); j++) + pused.Set (el[j]); + } + + for (i = 0; i < segments.Size(); i++) + { + const Segment & seg = segments[i]; + pused.Set (seg.p1); + pused.Set (seg.p2); + } + + for (i = 0; i < openelements.Size(); i++) + { + const Element2d & el = openelements[i]; + for (j = 0; j < el.GetNP(); j++) + pused.Set(el[j]); + } + + for (i = 0; i < lockedpoints.Size(); i++) + pused.Set (lockedpoints[i]); + + + /* + // compress points doesn�t work for identified points ! + if (identifiedpoints) + { + for (i = 1; i <= identifiedpoints->GetNBags(); i++) + if (identifiedpoints->GetBagSize(i)) + { + pused.Set (); + break; + } + } + */ + // pused.Set(); + + + int npi = PointIndex::BASE-1; + + for (i = PointIndex::BASE; + i < points.Size()+PointIndex::BASE; i++) + if (pused.Test(i)) + { + npi++; + op2np[i] = npi; + hpoints.Append (points[i]); + } + else + op2np[i] = -1; + + + + points.SetSize(0); + for (i = 0; i < hpoints.Size(); i++) + points.Append (hpoints[i]); + + + for (i = 1; i <= volelements.Size(); i++) + { + Element & el = VolumeElement(i); + for (j = 0; j < el.GetNP(); j++) + el[j] = op2np[el[j]]; + } + + for (i = 1; i <= surfelements.Size(); i++) + { + Element2d & el = SurfaceElement(i); + for (j = 0; j < el.GetNP(); j++) + el[j] = op2np[el[j]]; + } + + for (i = 0; i < segments.Size(); i++) + { + Segment & seg = segments[i]; + seg.p1 = op2np[seg.p1]; + seg.p2 = op2np[seg.p2]; + } + + for (i = 1; i <= openelements.Size(); i++) + { + Element2d & el = openelements.Elem(i); + for (j = 0; j < el.GetNP(); j++) + el[j] = op2np[el[j]]; + } + + + for (i = 0; i < lockedpoints.Size(); i++) + lockedpoints[i] = op2np[lockedpoints[i]]; + + + CalcSurfacesOfNode(); + + + // FindOpenElements(); + timestamp = NextTimeStamp(); + + /* + (*testout) << "compress, done" << endl + << "np = " << points.Size() + << "ne = " << volelements.Size() << ", type.size = " << eltyps.Size() + << "volelements = " << volelements << endl; + */ + } + + + int Mesh :: CheckConsistentBoundary () const + { + int nf = GetNOpenElements(); + INDEX_2_HASHTABLE<int> edges(nf+2); + int i, j; + INDEX_2 i2; + int err = 0; + + + for (i = 1; i <= nf; i++) + { + const Element2d & sel = OpenElement(i); + + for (j = 1; j <= sel.GetNP(); j++) + { + i2.I1() = sel.PNumMod(j); + i2.I2() = sel.PNumMod(j+1); + + int sign = (i2.I2() > i2.I1()) ? 1 : -1; + i2.Sort(); + if (!edges.Used (i2)) + edges.Set (i2, 0); + + edges.Set (i2, edges.Get(i2) + sign); + /* + + if (edges.Used(i2)) + { + int hi; + hi = edges.Get(i2); + if (hi != 1) + err = 1; + edges.Set(i2, 2); + cnt2++; + } + else + { + swap (i2.I1(), i2.I2()); + edges.Set(i2, 1); + cnt1++; + } + */ + } + } + + + /* + if (cnt1 != cnt2) + err = 2; + */ + + for (i = 1; i <= edges.GetNBags(); i++) + for (j = 1; j <= edges.GetBagSize(i); j++) + { + int cnt = 0; + edges.GetData (i, j, i2, cnt); + if (cnt) + { + PrintError ("Edge ", i2.I1() , " - ", i2.I2(), " multiple times in surface mesh"); + err = 2; + } + } + + return err; + } + + + + int Mesh :: CheckOverlappingBoundary () + { + int i, j, k; + + Point3d pmin, pmax; + GetBox (pmin, pmax); + Box3dTree setree(pmin, pmax); + ARRAY<int> inters; + + bool overlap = 0; + bool incons_layers = 0; + + + for (i = 1; i <= GetNSE(); i++) + SurfaceElement(i).badel = 0; + + + for (i = 1; i <= GetNSE(); i++) + { + const Element2d & tri = SurfaceElement(i); + + Point3d tpmin (Point(tri[0])); + Point3d tpmax (tpmin); + + for (k = 1; k < tri.GetNP(); k++) + { + tpmin.SetToMin (Point (tri[k])); + tpmax.SetToMax (Point (tri[k])); + } + Vec3d diag(tpmin, tpmax); + + tpmax = tpmax + 0.1 * diag; + tpmin = tpmin - 0.1 * diag; + + setree.Insert (tpmin, tpmax, i); + } + + for (i = 1; i <= GetNSE(); i++) + { + const Element2d & tri = SurfaceElement(i); + + Point3d tpmin (Point(tri[0])); + Point3d tpmax (tpmin); + + for (k = 1; k < tri.GetNP(); k++) + { + tpmin.SetToMin (Point (tri[k])); + tpmax.SetToMax (Point (tri[k])); + } + + setree.GetIntersecting (tpmin, tpmax, inters); + + for (j = 1; j <= inters.Size(); j++) + { + const Element2d & tri2 = SurfaceElement(inters.Get(j)); + + if ( (*this)[tri[0]].GetLayer() != (*this)[tri2[0]].GetLayer()) + continue; + + if ( (*this)[tri[0]].GetLayer() != (*this)[tri[1]].GetLayer() || + (*this)[tri[0]].GetLayer() != (*this)[tri[2]].GetLayer()) + { + incons_layers = 1; + cout << "inconsistent layers in triangle" << endl; + } + + + const Point3d *trip1[3], *trip2[3]; + for (k = 1; k <= 3; k++) + { + trip1[k-1] = &Point (tri.PNum(k)); + trip2[k-1] = &Point (tri2.PNum(k)); + } + + if (IntersectTriangleTriangle (&trip1[0], &trip2[0])) + { + overlap = 1; + PrintWarning ("Intersecting elements" + ,i, " and ", inters.Get(j)); + + (*testout) << "Intersecting: " << endl; + (*testout) << "openelement " << i << " with open element " << inters.Get(j) << endl; + + cout << "el1 = " << tri << endl; + cout << "el2 = " << tri2 << endl; + cout << "layer1 = " << (*this)[tri[0]].GetLayer() << endl; + cout << "layer2 = " << (*this)[tri2[0]].GetLayer() << endl; + + + for (k = 1; k <= 3; k++) + (*testout) << tri.PNum(k) << " "; + (*testout) << endl; + for (k = 1; k <= 3; k++) + (*testout) << tri2.PNum(k) << " "; + (*testout) << endl; + + for (k = 0; k <= 2; k++) + (*testout) << *trip1[k] << " "; + (*testout) << endl; + for (k = 0; k <= 2; k++) + (*testout) << *trip2[k] << " "; + (*testout) << endl; + + + /* + INDEX_3 i3(tri.PNum(1), tri.PNum(2), tri.PNum(3)); + i3.Sort(); + for (k = 1; k <= GetNSE(); k++) + { + const Element2d & el2 = SurfaceElement(k); + INDEX_3 i3b(el2.PNum(1), el2.PNum(2), el2.PNum(3)); + i3b.Sort(); + if (i3 == i3b) + { + SurfaceElement(k).badel = 1; + } + } + */ + SurfaceElement(i).badel = 1; + SurfaceElement(inters.Get(j)).badel = 1; + } + } + } + + // bug 'fix' + if (incons_layers) overlap = 0; + + return overlap; + } + + + int Mesh :: CheckVolumeMesh () const + { + PrintMessage (3, "Checking volume mesh"); + + int ne = GetNE(); + DenseMatrix dtrans(3,3); + int i, j; + + PrintMessage (5, "elements: ", ne); + for (i = 1; i <= ne; i++) + { + Element & el = (Element&) VolumeElement(i); + el.flags.badel = 0; + int nip = el.GetNIP(); + for (j = 1; j <= nip; j++) + { + el.GetTransformation (j, Points(), dtrans); + double det = dtrans.Det(); + if (det > 0) + { + PrintError ("Element ", i , " has wrong orientation"); + el.flags.badel = 1; + } + } + } + + return 0; + } + + + bool Mesh :: LegalTrig (const Element2d & el) const + { + return 1; + if ( /* hp */ 1) // needed for old, simple hp-refinement + { + // trigs with 2 or more segments are illegal + int i; + int nseg = 0; + + if (!segmentht) + { + cerr << "no segmentht allocated" << endl; + return 0; + } + + // Point3d cp(0.5, 0.5, 0.5); + for (i = 1; i <= 3; i++) + { + INDEX_2 i2(el.PNumMod (i), el.PNumMod (i+1)); + i2.Sort(); + if (segmentht -> Used (i2)) + nseg++; + } + if (nseg >= 2) + return 0; + } + return 1; + } + + /// + bool Mesh :: LegalTet2 (Element & el) const + { + // return 1; + // Test, whether 4 points have a common surface plus + // at least 4 edges at the boundary + + int i, j, k; + + // non-tets are always legal + if (el.GetType() != TET) + { + el.SetLegal (1); + return 1; + } + + // element has at least 2 inner points ---> legal + int cnti = 0; + for (j = 0; j < 4; j++) + if (PointType(el[j]) == INNERPOINT) + cnti++; + if (cnti >= 2) + { + el.SetLegal (1); + return 1; + } + + // which faces are boundary faces ? + Element2d face; + int bface[4]; + + for (i = 1; i <= 4; i++) + { + el.GetFace (i, face); + INDEX_3 i3 (face.PNum(1), face.PNum(2), face.PNum(3)); + i3.Sort(); + bface[i-1] = surfelementht->Used (i3); + } + + int bedge[4][4]; + int segedge[4][4]; + for (i = 0; i < 4; i++) + for (j = 0; j < i; j++) + { + bool sege = 0, be = 0; + + INDEX_2 i2(el[i], el[j]); + i2.Sort(); + + /* + if (boundaryedges -> Used(i2)) + { + be = 1; + if (boundaryedges -> Get(i2) == 2) + sege = 1; + } + */ + int pos = boundaryedges -> Position(i2); + if (pos) + { + be = 1; + if (boundaryedges -> GetData(pos) == 2) + sege = 1; + } + + segedge[j][i] = segedge[i][j] = sege; + bedge[j][i] = bedge[i][j] = be; + } + + // two boundary faces and no edge is illegal + for (i = 0; i < 3; i++) + for (j = i+1; j < 4; j++) + { + if (bface[i] && bface[j]) + { + // common nodes: + int pi1 = 0, pi2; + while (pi1 == i || pi1 == j) + pi1++; + pi2 = 6 - i - j - pi1; + if (!segedge[pi1][pi2]) + { + // 2 boundary faces withoud edge in between + el.SetLegal (0); + return 0; + } + } + } + + + // three boundary edges meeting in a Surface point + for (i = 0; i < 4; i++) + { + bool alledges = 1; + if (PointType(el[i]) == SURFACEPOINT) + { + for (j = 0; j < 4; j++) + if (j != i) + { + if (!bedge[i][j]) + { + alledges = 0; + break; + } + } + if (alledges) + { + // cout << "tet illegal due to unmarked node" << endl; + el.SetLegal (0); + return 0; + } + } + } + + + /* + { + // having 3 boundary edges and 4 surface nodes ??? + int nodehasedge[4]; + int canbe = 1; // can be that illegal tet + + for (i = 0; i < 4; i++) + nodehasedge[i] = 0; + for (i = 1; i <= 4; i++) + { + if (PointType(el.PNum(i)) != SURFACEPOINT) + canbe = 0; + for (j = i+1; j <= 4; j++) + { + INDEX_2 i2(el.PNum(i), el.PNum(j)); + i2.Sort(); + if (boundaryedges->Used(i2)) + { + nodehasedge[i-1] = 1; + nodehasedge[j-1] = 1; + } + + } + } + for (i = 0; i < 4; i++) + if (!nodehasedge[i]) + canbe = 0; + + if (canbe) return 0; + + } + */ + + { + // two connected edges on surface, but no face + + int ltestmode = 0; // (el.PNum(1) == 10516); + + if (ltestmode) + { + (*testout) << "pnums: " << endl; + for (i = 1; i <= 4; i++) + (*testout) << el.PNum(i) << " "; + (*testout) << endl; + } + + for (i = 1; i <= 4; i++) + if (PointType(el.PNum(i)) == SURFACEPOINT) + for (j = 1; j <= 4; j++) + if (j != i) + for (k = j+1; k <= 4; k++) + if (k != i) + { + int fnr = 10 - i - j - k; + + if (!bface[fnr-1] && + bedge[i-1][j-1] && + bedge[i-1][k-1]) + { + el.SetLegal (0); + return 0; + } + /* + INDEX_2 e1(el.PNum(i), el.PNum(j)); + e1.Sort(); + INDEX_2 e2(el.PNum(i), el.PNum(k)); + e2.Sort(); + INDEX_3 face(el.PNum(i), el.PNum(j), el.PNum(k)); + face.Sort(); + + if (ltestmode) + { + (*testout) << "i, j, k = " << i << ", " << j << ", " << k << endl; + (*testout) << "eij = " << boundaryedges->Used(e1) + << " eik = " << boundaryedges->Used(e2) + << " face = " << surfelementht->Used (face) << endl; + + } + + if (boundaryedges->Used(e1) && + boundaryedges->Used(e2) && + !surfelementht->Used (face)) + { + // cout << "tet illegal due to last case" << endl; + el.SetLegal (0); + return 0; + } + */ + } + + } + + + { + // connected surface edge and edge edge, but no face + + for (i = 1; i <= 4; i++) + if (PointType(el.PNum(i)) == EDGEPOINT) + for (j = 1; j <= 4; j++) + if (j != i) + for (k = j+1; k <= 4; k++) + if (k != i) + { + int fnr = 10 - i - j - k; + + if (!bface[fnr-1] && + (bedge[i-1][j-1] && segedge[i-1][k-1] || + segedge[i-1][j-1] && bedge[i-1][k-1])) + { + el.SetLegal (0); + return 0; + } + } + + } + + + + + + + el.SetLegal (1); + return 1; + + /* + int i1, i2, i3, i4, j; + if (PointType(el.PNum(1)) != INNERPOINT && + PointType(el.PNum(2)) != INNERPOINT && + PointType(el.PNum(3)) != INNERPOINT && + PointType(el.PNum(4)) != INNERPOINT) + { + for (i1 = 1; i1 <= surfacesonnode.EntrySize(el.PNum(1)); i1++) + for (i2 = 1; i2 <= surfacesonnode.EntrySize(el.PNum(2)); i2++) + if (surfacesonnode.Get(el.PNum(1), i1) == + surfacesonnode.Get(el.PNum(2), i2)) + for (i3 = 1; i3 <= surfacesonnode.EntrySize(el.PNum(3)); i3++) + if (surfacesonnode.Get(el.PNum(1), i1) == + surfacesonnode.Get(el.PNum(3), i3)) + for (i4 = 1; i4 <= surfacesonnode.EntrySize(el.PNum(4)); i4++) + if (surfacesonnode.Get(el.PNum(1), i1) == + surfacesonnode.Get(el.PNum(4), i4)) + { + int j, numbe = 0; + INDEX_2 i2; + + for (j = 1; j <= 6; j++) + { + switch (j) + { + case 1: + i2.I1() = el.PNum(1); + i2.I2() = el.PNum(2); break; + case 2: + i2.I1() = el.PNum(1); + i2.I2() = el.PNum(3); break; + case 3: + i2.I1() = el.PNum(1); + i2.I2() = el.PNum(4); break; + case 4: + i2.I1() = el.PNum(2); + i2.I2() = el.PNum(3); break; + case 5: + i2.I1() = el.PNum(2); + i2.I2() = el.PNum(4); break; + case 6: + i2.I1() = el.PNum(3); + i2.I2() = el.PNum(4); break; + } + + i2.Sort(); + if (boundaryedges->Used (i2)) numbe++; + } + + if (numbe >= 4) + { + // (*testout) + // << "Tet illegal: " + // << "mat = " << el.GetIndex() << " " + // << "surf = " << surfacesonnode.Get(el.PNum(1), i1) + // << " " + // << el.PNum(1) << " " + // << el.PNum(2) << " " + // << el.PNum(3) << " " + // << el.PNum(4) << endl; + + return 0; + } + } + } + return 1; + */ + } + + + int Mesh :: GetNDomains() const + { + int ndom = 0; + + for (int k = 0; k < facedecoding.Size(); k++) + { + if (facedecoding[k].DomainIn() > ndom) + ndom = facedecoding[k].DomainIn(); + if (facedecoding[k].DomainOut() > ndom) + ndom = facedecoding[k].DomainOut(); + } + + return ndom; + } + + + + void Mesh :: SurfaceMeshOrientation () + { + int i, j; + int nse = GetNSE(); + + BitArray used(nse); + used.Clear(); + INDEX_2_HASHTABLE<int> edges(nse+1); + + bool haschanged = 0; + + + const Element2d & tri = SurfaceElement(1); + for (j = 1; j <= 3; j++) + { + INDEX_2 i2(tri.PNumMod(j), tri.PNumMod(j+1)); + edges.Set (i2, 1); + } + used.Set(1); + + bool unused; + do + { + bool changed; + do + { + changed = 0; + for (i = 1; i <= nse; i++) + if (!used.Test(i)) + { + Element2d & el = surfelements.Elem(i); + int found = 0, foundrev = 0; + for (j = 1; j <= 3; j++) + { + INDEX_2 i2(el.PNumMod(j), el.PNumMod(j+1)); + if (edges.Used(i2)) + foundrev = 1; + swap (i2.I1(), i2.I2()); + if (edges.Used(i2)) + found = 1; + } + + if (found || foundrev) + { + if (foundrev) + swap (el.PNum(2), el.PNum(3)); + + changed = 1; + for (j = 1; j <= 3; j++) + { + INDEX_2 i2(el.PNumMod(j), el.PNumMod(j+1)); + edges.Set (i2, 1); + } + used.Set (i); + } + } + if (changed) + haschanged = 1; + } + while (changed); + + + unused = 0; + for (i = 1; i <= nse; i++) + if (!used.Test(i)) + { + unused = 1; + const Element2d & tri = SurfaceElement(i); + for (j = 1; j <= 3; j++) + { + INDEX_2 i2(tri.PNumMod(j), tri.PNumMod(j+1)); + edges.Set (i2, 1); + } + used.Set(i); + break; + } + } + while (unused); + + if (haschanged) + timestamp = NextTimeStamp(); + } + + + void Mesh :: Split2Tets() + { + // int oldne, oldnse; + // int i, j, k, l; + + bool has_prisms = 0; + + int oldne = GetNE(); + for (int i = 1; i <= oldne; i++) + { + Element el = VolumeElement(i); + + if (el.GetType() == PRISM) + { + // prism, to 3 tets + + // make minimal node to node 1 + int minpi=0; + PointIndex minpnum; + minpnum = GetNP() + 1; + + for (int j = 1; j <= 6; j++) + { + if (el.PNum(j) < minpnum) + { + minpnum = el.PNum(j); + minpi = j; + } + } + + if (minpi >= 4) + { + for (int j = 1; j <= 3; j++) + swap (el.PNum(j), el.PNum(j+3)); + minpi -= 3; + } + + while (minpi > 1) + { + int hi = 0; + for (int j = 0; j <= 3; j+= 3) + { + hi = el.PNum(1+j); + el.PNum(1+j) = el.PNum(2+j); + el.PNum(2+j) = el.PNum(3+j); + el.PNum(3+j) = hi; + } + minpi--; + } + + /* + version 1: edge from pi2 to pi6, + version 2: edge from pi3 to pi5, + */ + + static const int ntets[2][12] = + { { 1, 4, 5, 6, 1, 2, 3, 6, 1, 2, 5, 6 }, + { 1, 4, 5, 6, 1, 2, 3, 5, 3, 1, 5, 6 } }; + + const int * min2pi; + + if (min2 (el.PNum(2), el.PNum(6)) < + min2 (el.PNum(3), el.PNum(5))) + { + min2pi = &ntets[0][0]; + // (*testout) << "version 1 "; + } + else + { + min2pi = &ntets[1][0]; + // (*testout) << "version 2 "; + } + + + int firsttet = 1; + for (int j = 1; j <= 3; j++) + { + Element nel(4); + 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) (*testout) << "no legal"; + (*testout) << endl; + } + + + + else if (el.GetType() == HEX) + { + // hex to A) 2 prisms or B) to 5 tets + + // make minimal node to node 1 + int minpi=0; + PointIndex minpnum; + minpnum = GetNP() + 1; + + for (int j = 1; j <= 8; j++) + { + if (el.PNum(j) < minpnum) + { + minpnum = el.PNum(j); + minpi = j; + } + } + + if (minpi >= 5) + { + for (int j = 1; j <= 4; j++) + swap (el.PNum(j), el.PNum(j+4)); + minpi -= 4; + } + + while (minpi > 1) + { + int hi = 0; + for (int j = 0; j <= 4; j+= 4) + { + hi = el.PNum(1+j); + el.PNum(1+j) = el.PNum(2+j); + el.PNum(2+j) = el.PNum(3+j); + el.PNum(3+j) = el.PNum(4+j); + el.PNum(4+j) = hi; + } + minpi--; + } + + + + static const int to_prisms[3][12] = + { { 0, 1, 2, 4, 5, 6, 0, 2, 3, 4, 6, 7 }, + { 0, 1, 5, 3, 2, 6, 0, 5, 4, 3, 5, 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 + + static const int ntets[2][8] = + { { 1, 2, 3, 5, 1, 3, 4, 5 }, + { 1, 2, 4, 5, 4, 2, 3, 5 }}; + + const int * min2pi; + + if (min2 (el.PNum(1), el.PNum(3)) < + min2 (el.PNum(2), el.PNum(4))) + min2pi = &ntets[0][0]; + else + min2pi = &ntets[1][0]; + + + int firsttet = 1; + for (int j = 1; j <= 2; j++) + { + Element nel(4); + 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; + + if (legal) + { + (*testout) << nel << " "; + if (firsttet) + { + VolumeElement(i) = nel; + firsttet = 0; + } + else + { + AddVolumeElement(nel); + } + } + } + (*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)); + } + + timestamp = NextTimeStamp(); + } + } + + void Mesh :: BuildElementSearchTree () + { + if (elementsearchtreets == GetTimeStamp()) + return; + + NgLock lock(mutex); + lock.Lock(); + + PrintMessage (4, "Rebuild element searchtree"); + + if (elementsearchtree) + delete elementsearchtree; + elementsearchtree = NULL; + + Box3d box; + int i, j; + int ne = GetNE(); + if (!ne) + { + lock.UnLock(); + return; + } + + box.SetPoint (Point (VolumeElement(1).PNum(1))); + for (i = 1; i <= ne; i++) + { + const Element & el = VolumeElement(i); + for (j = 1; j <= el.GetNP(); j++) + box.AddPoint (Point (el.PNum(j))); + } + + box.Increase (1.01 * box.CalcDiam()); + elementsearchtree = new Box3dTree (box.PMin(), box.PMax()); + + + + for (i = 1; i <= ne; i++) + { + const Element & el = VolumeElement(i); + box.SetPoint (Point (el.PNum(1))); + for (j = 1; j <= el.GetNP(); j++) + box.AddPoint (Point (el.PNum(j))); + + elementsearchtree -> Insert (box.PMin(), box.PMax(), i); + } + + elementsearchtreets = GetTimeStamp(); + + lock.UnLock(); + } + + + int Mesh :: GetElementOfPoint (const Point3d & p, + double lami[3], + bool build_searchtree, + const int index) const + { + if (dimension == 2) + { + int i, j; + Vec3d col1, col2, col3; + Vec3d rhs, sol; + double eps = 1e-6; + int ne; + + ARRAY<int> locels; + if (0) + { + elementsearchtree->GetIntersecting (p, p, locels); + ne = locels.Size(); + } + else + ne = GetNSE(); + ARRAY<Element2d> loctrigs; + Vec3d nv(0, 0, 1); + for (i = 1; i <= ne; i++) + { + int ii; + if (0) + ii = locels.Get(i); + else + ii = i; + + if((index >= 0) && (index != SurfaceElement(ii).GetIndex())) continue; + + //SZ + if(SurfaceElement(ii).GetType()==QUAD) + { + + const Element2d & el = SurfaceElement(ii); + + const Point3d & p1 = Point(el.PNum(1)); + const Point3d & p2 = Point(el.PNum(2)); + const Point3d & p3 = Point(el.PNum(3)); + const Point3d & p4 = Point(el.PNum(4)); + + // Coefficients of Bilinear Mapping from Ref-Elem to global Elem + // X = a + b x + c y + d x y + Vec3d a = p1; + Vec3d b = p2 - a; + Vec3d c = p4 - a; + Vec3d d = p3 - a - b - c; + + double dxb = d.X()*b.Y()-d.Y()*b.X(); + double dxc = d.X()*c.Y()-d.Y()*c.X(); + double dxa = d.X()*a.Y()-d.Y()*a.X(); + double dxp = d.X()*p.Y()-d.Y()*p.X(); + + double c0,c1,c2,rt; + lami[2]=0.; + double eps = 1.E-12; + + if(fabs(d.X()) <= eps && fabs(d.Y())<= eps) + { + //Solve Linear System + lami[0]=(c.Y()*(p.X()-a.X())-b.Y()*(p.Y()-a.Y()))/ + (b.X()*c.Y() -b.Y()*c.X()); + lami[1]=(-c.X()*(p.X()-a.X())+b.X()*(p.Y()-a.Y()))/ + (b.X()*c.Y() -b.Y()*c.X()); + } + else + if(fabs(dxb) <= eps) + { + lami[1] = (dxp-dxa)/dxc; + if(fabs(b.X()-d.X()*lami[1])>=eps) + lami[0] = (p.X()-a.X() - c.X()*lami[1])/(b.X()+d.X()*lami[1]); + else + lami[0] = (p.Y()-a.Y() - c.Y()*lami[1])/(b.Y()+d.Y()*lami[1]); + } + else + if(fabs(dxc) <= eps) + { + lami[0] = (dxp-dxa)/dxb; + if(fabs(c.X()-d.X()*lami[0])>=eps) + lami[1] = (p.X()-a.X() - b.X()*lami[0])/(c.X()+d.X()*lami[0]); + else + lami[1] = (p.Y()-a.Y() - b.Y()*lami[0])/(c.Y()+d.Y()*lami[0]); + } + else //Solve quadratic equation + { + if(fabs(d.X()) >= eps) + { + c2 = d.X()*dxc; + c1 = d.X()*dxc - c.X()*dxb - d.X()*(dxp-dxa); + c0 = -b.X()*(dxp -dxa) - (a.X()-p.X())*dxb; + } + else + { + c2 = d.Y()*dxc; + c1 = d.Y()*dxc - c.Y()*dxb - d.Y()*(dxp-dxa); + c0 = -b.Y()*(dxp -dxa) - (a.Y()-p.Y())*dxb; + } + + double rt = c1*c1 - 4*c2*c0; + if (rt < 0.) continue; + lami[1] = (-c1 + sqrt(rt))/2/c2; + if(lami[1]<=1. && lami[1]>=0.) + { + lami[0] = (dxp - dxa -dxc*lami[1])/dxb; + if(lami[0]<=1. && lami[0]>=0.) + return(ii); + } + + lami[1] = (-c1 - sqrt(rt))/2/c2; + lami[0] = (dxp - dxa -dxc*lami[1])/dxb; + } + + if( lami[0] <= 1.+eps && lami[0] >= -eps && lami[1]<=1.+eps && lami[1]>=-eps) + return(ii); + + continue; + + } + else + { + // SurfaceElement(ii).GetTets (loctets); + loctrigs.SetSize(1); + loctrigs.Elem(1) = SurfaceElement(ii); + + + + for (j = 1; j <= loctrigs.Size(); j++) + { + const Element2d & el = loctrigs.Get(j); + + + const Point3d & p1 = Point(el.PNum(1)); + const Point3d & p2 = Point(el.PNum(2)); + const Point3d & p3 = Point(el.PNum(3)); + /* + Box3d box; + box.SetPoint (p1); + box.AddPoint (p2); + box.AddPoint (p3); + box.AddPoint (p4); + if (!box.IsIn (p)) + continue; + */ + col1 = p2-p1; + col2 = p3-p1; + col3 = nv; + rhs = p - p1; + + SolveLinearSystem (col1, col2, col3, rhs, sol); + + if (sol.X() >= -eps && sol.Y() >= -eps && + sol.X() + sol.Y() <= 1+eps) + { + lami[0] = sol.X(); + lami[1] = sol.Y(); + lami[2] = sol.Z(); + + return ii; + } + } + } + } + + return 0; + } + else + + { + int i, j; + Vec3d col1, col2, col3; + Vec3d rhs, sol; + double eps = 1e-4; + int ne; + + ARRAY<int> locels; + if (elementsearchtree || build_searchtree) + { + // update if necessary: + const_cast<Mesh&>(*this).BuildElementSearchTree (); + elementsearchtree->GetIntersecting (p, p, locels); + ne = locels.Size(); + } + else + ne = GetNE(); + + ARRAY<Element> loctets; + for (i = 1; i <= ne; i++) + { + int ii; + if (elementsearchtree) + ii = locels.Get(i); + else + ii = i; + + VolumeElement(ii).GetTets (loctets); + + for (j = 1; j <= loctets.Size(); j++) + { + const Element & el = loctets.Get(j); + + const Point3d & p1 = Point(el.PNum(1)); + const Point3d & p2 = Point(el.PNum(2)); + const Point3d & p3 = Point(el.PNum(3)); + const Point3d & p4 = Point(el.PNum(4)); + + Box3d box; + box.SetPoint (p1); + box.AddPoint (p2); + box.AddPoint (p3); + box.AddPoint (p4); + if (!box.IsIn (p)) + continue; + + col1 = p2-p1; + col2 = p3-p1; + col3 = p4-p1; + rhs = p - p1; + + SolveLinearSystem (col1, col2, col3, rhs, sol); + + if (sol.X() >= -eps && sol.Y() >= -eps && sol.Z() >= -eps && + sol.X() + sol.Y() + sol.Z() <= 1+eps) + { + ARRAY<Element> loctetsloc; + ARRAY<Point3d> pointsloc; + + VolumeElement(ii).GetTetsLocal (loctetsloc); + VolumeElement(ii).GetNodesLocalNew (pointsloc); + + const Element & le = loctetsloc.Get(j); + + Point3d p = + pointsloc.Get(le.PNum(1)) + + sol.X() * Vec3d (pointsloc.Get(le.PNum(1)), pointsloc.Get(le.PNum(2))) + + sol.Y() * Vec3d (pointsloc.Get(le.PNum(1)), pointsloc.Get(le.PNum(3))) + + sol.Z() * Vec3d (pointsloc.Get(le.PNum(1)), pointsloc.Get(le.PNum(4))) ; + + + lami[0] = p.X(); + lami[1] = p.Y(); + lami[2] = p.Z(); + return ii; + } + } + } + + return 0; + } + } + + + void Mesh::GetIntersectingVolEls(const Point3d& p1, const Point3d& p2, + ARRAY<int> & locels) const + { + elementsearchtree->GetIntersecting (p1, p2, locels); + } + + void Mesh :: SplitIntoParts() + { + int i, j, dom; + int ne = GetNE(); + int np = GetNP(); + int nse = GetNSE(); + + BitArray surfused(nse); + BitArray pused (np); + + surfused.Clear(); + + dom = 0; + + while (1) + { + int cntd = 1; + + dom++; + + pused.Clear(); + + int found = 0; + for (i = 1; i <= nse; i++) + if (!surfused.Test(i)) + { + SurfaceElement(i).SetIndex (dom); + for (j = 1; j <= 3; j++) + pused.Set (SurfaceElement(i).PNum(j)); + found = 1; + cntd = 1; + surfused.Set(i); + break; + } + + if (!found) + break; + + int change; + do + { + change = 0; + for (i = 1; i <= nse; i++) + { + int is = 0, isnot = 0; + for (j = 1; j <= 3; j++) + if (pused.Test(SurfaceElement(i).PNum(j))) + is = 1; + else + isnot = 1; + + if (is && isnot) + { + change = 1; + for (j = 1; j <= 3; j++) + pused.Set (SurfaceElement(i).PNum(j)); + } + + if (is) + { + if (!surfused.Test(i)) + { + surfused.Set(i); + SurfaceElement(i).SetIndex (dom); + cntd++; + } + } + } + + + for (i = 1; i <= ne; i++) + { + int is = 0, isnot = 0; + for (j = 1; j <= 4; j++) + if (pused.Test(VolumeElement(i).PNum(j))) + is = 1; + else + isnot = 1; + + if (is && isnot) + { + change = 1; + for (j = 1; j <= 4; j++) + pused.Set (VolumeElement(i).PNum(j)); + } + + if (is) + { + VolumeElement(i).SetIndex (dom); + } + } + } + while (change); + + PrintMessage (3, "domain ", dom, " has ", cntd, " surfaceelements"); + } + + /* + facedecoding.SetSize (dom); + for (i = 1; i <= dom; i++) + { + facedecoding.Elem(i).surfnr = 0; + facedecoding.Elem(i).domin = i; + facedecoding.Elem(i).domout = 0; + } + */ + ClearFaceDescriptors(); + for (i = 1; i <= dom; i++) + AddFaceDescriptor (FaceDescriptor (0, i, 0, 0)); + CalcSurfacesOfNode(); + timestamp = NextTimeStamp(); + } + + void Mesh :: SplitSeparatedFaces () + { + int fdi; + int i, j; + int np = GetNP(); + + BitArray usedp(np); + + fdi = 1; + while (fdi <= GetNFD()) + { + int firstel = 0; + for (i = 1; i <= GetNSE(); i++) + if (SurfaceElement(i).GetIndex() == fdi) + { + firstel = i; + break; + } + if (!firstel) continue; + + usedp.Clear(); + for (j = 1; j <= SurfaceElement(firstel).GetNP(); j++) + usedp.Set (SurfaceElement(firstel).PNum(j)); + + int changed; + do + { + changed = 0; + for (i = 1; i <= GetNSE(); i++) + { + const Element2d & el = SurfaceElement(i); + if (el.GetIndex() != fdi) + continue; + + int has = 0; + int hasno = 0; + for (j = 1; j <= el.GetNP(); j++) + { + if (usedp.Test(el.PNum(j))) + has = 1; + else + hasno = 1; + } + if (has && hasno) + changed = 1; + + if (has) + for (j = 1; j <= el.GetNP(); j++) + usedp.Set (el.PNum(j)); + } + } + while (changed); + + int nface = 0; + for (i = 1; i <= GetNSE(); i++) + { + Element2d & el = SurfaceElement(i); + if (el.GetIndex() != fdi) + continue; + + int hasno = 0; + for (j = 1; j <= el.GetNP(); j++) + { + if (!usedp.Test(el.PNum(j))) + hasno = 1; + } + + if (hasno) + { + if (!nface) + { + FaceDescriptor nfd = GetFaceDescriptor(fdi); + nface = AddFaceDescriptor (nfd); + } + + el.SetIndex (nface); + } + } + fdi++; + } + } + + + void Mesh :: GetSurfaceElementsOfFace (int facenr, ARRAY<SurfaceElementIndex> & sei) const + { + sei.SetSize (0); + for (SurfaceElementIndex i = 0; i < GetNSE(); i++) + if ( (*this)[i].GetIndex () == facenr && (*this)[i][0] >= PointIndex::BASE && + !(*this)[i].IsDeleted() ) + sei.Append (i); + } + + + + + void Mesh :: CalcMinMaxAngle (double badellimit, double * retvalues) + { + int i, j; + int lpi1, lpi2, lpi3, lpi4; + double phimax = 0, phimin = 10; + double facephimax = 0, facephimin = 10; + int illegaltets = 0, negativetets = 0, badtets = 0; + + for (i = 1; i <= GetNE(); i++) + { + int badel = 0; + + Element & el = VolumeElement(i); + + if (el.GetType() != TET) + { + VolumeElement(i).flags.badel = 0; + continue; + } + + if (el.Volume(Points()) < 0) + { + badel = 1; + negativetets++; + } + + + if (!LegalTet (el)) + { + badel = 1; + illegaltets++; + (*testout) << "illegal tet: " << i << " "; + for (j = 1; j <= el.GetNP(); j++) + (*testout) << el.PNum(j) << " "; + (*testout) << endl; + } + + + // angles between faces + for (lpi1 = 1; lpi1 <= 3; lpi1++) + for (lpi2 = lpi1+1; lpi2 <= 4; lpi2++) + { + lpi3 = 1; + while (lpi3 == lpi1 || lpi3 == lpi2) + lpi3++; + lpi4 = 10 - lpi1 - lpi2 - lpi3; + + const Point3d & p1 = Point (el.PNum(lpi1)); + const Point3d & p2 = Point (el.PNum(lpi2)); + const Point3d & p3 = Point (el.PNum(lpi3)); + const Point3d & p4 = Point (el.PNum(lpi4)); + + Vec3d n(p1, p2); + n /= n.Length(); + Vec3d v1(p1, p3); + Vec3d v2(p1, p4); + + v1 -= (n * v1) * n; + v2 -= (n * v2) * n; + + double cosphi = (v1 * v2) / (v1.Length() * v2.Length()); + double phi = acos (cosphi); + if (phi > phimax) phimax = phi; + if (phi < phimin) phimin = phi; + + if ((180/M_PI) * phi > badellimit) + badel = 1; + } + + + // angles in faces + for (j = 1; j <= 4; j++) + { + Element2d face; + el.GetFace (j, face); + for (lpi1 = 1; lpi1 <= 3; lpi1++) + { + lpi2 = lpi1 % 3 + 1; + lpi3 = lpi2 % 3 + 1; + + const Point3d & p1 = Point (el.PNum(lpi1)); + const Point3d & p2 = Point (el.PNum(lpi2)); + const Point3d & p3 = Point (el.PNum(lpi3)); + + Vec3d v1(p1, p2); + Vec3d v2(p1, p3); + double cosphi = (v1 * v2) / (v1.Length() * v2.Length()); + double phi = acos (cosphi); + if (phi > facephimax) facephimax = phi; + if (phi < facephimin) facephimin = phi; + + if ((180/M_PI) * phi > badellimit) + badel = 1; + + } + } + + + VolumeElement(i).flags.badel = badel; + if (badel) badtets++; + } + + if (!GetNE()) + { + phimin = phimax = facephimin = facephimax = 0; + } + + if (!retvalues) + { + PrintMessage (1, ""); + PrintMessage (1, "between planes: phimin = ", (180/M_PI) * phimin, + " phimax = ", (180/M_PI) *phimax); + PrintMessage (1, "inside planes: phimin = ", (180/M_PI) * facephimin, + " phimax = ", (180/M_PI) * facephimax); + PrintMessage (1, ""); + } + else + { + retvalues[0] = (180/M_PI) * facephimin; + retvalues[1] = (180/M_PI) * facephimax; + retvalues[2] = (180/M_PI) * phimin; + retvalues[3] = (180/M_PI) * phimax; + } + PrintMessage (3, "negative tets: ", negativetets); + PrintMessage (3, "illegal tets: ", illegaltets); + PrintMessage (3, "bad tets: ", badtets); + } + + + int Mesh :: MarkIllegalElements () + { + int cnt = 0; + int i; + + for (i = 1; i <= GetNE(); i++) + { + LegalTet (VolumeElement(i)); + + /* + Element & el = VolumeElement(i); + int leg1 = LegalTet (el); + el.flags.illegal_valid = 0; + int leg2 = LegalTet (el); + + if (leg1 != leg2) + { + cerr << "legal differs!!" << endl; + (*testout) << "legal differs" << endl; + (*testout) << "elnr = " << i << ", el = " << el + << " leg1 = " << leg1 << ", leg2 = " << leg2 << endl; + } + + // el.flags.illegal = !LegalTet (el); + */ + cnt += VolumeElement(i).Illegal(); + } + return cnt; + } + +#ifdef NONE + void Mesh :: AddIdentification (int pi1, int pi2, int identnr) + { + INDEX_2 pair(pi1, pi2); + // pair.Sort(); + identifiedpoints->Set (pair, identnr); + if (identnr > maxidentnr) + maxidentnr = identnr; + timestamp = NextTimeStamp(); + } + + int Mesh :: GetIdentification (int pi1, int pi2) const + { + INDEX_2 pair(pi1, pi2); + if (identifiedpoints->Used (pair)) + return identifiedpoints->Get(pair); + else + return 0; + } + + int Mesh :: GetIdentificationSym (int pi1, int pi2) const + { + INDEX_2 pair(pi1, pi2); + if (identifiedpoints->Used (pair)) + return identifiedpoints->Get(pair); + + pair = INDEX_2 (pi2, pi1); + if (identifiedpoints->Used (pair)) + return identifiedpoints->Get(pair); + + return 0; + } + + + void Mesh :: GetIdentificationMap (int identnr, ARRAY<int> & identmap) const + { + int i, j; + + identmap.SetSize (GetNP()); + for (i = 1; i <= identmap.Size(); i++) + identmap.Elem(i) = 0; + + for (i = 1; i <= identifiedpoints->GetNBags(); i++) + for (j = 1; j <= identifiedpoints->GetBagSize(i); j++) + { + INDEX_2 i2; + int nr; + identifiedpoints->GetData (i, j, i2, nr); + + if (nr == identnr) + { + identmap.Elem(i2.I1()) = i2.I2(); + } + } + } + + + void Mesh :: GetIdentificationPairs (int identnr, ARRAY<INDEX_2> & identpairs) const + { + int i, j; + + identpairs.SetSize(0); + + for (i = 1; i <= identifiedpoints->GetNBags(); i++) + for (j = 1; j <= identifiedpoints->GetBagSize(i); j++) + { + INDEX_2 i2; + int nr; + identifiedpoints->GetData (i, j, i2, nr); + + if (identnr == 0 || nr == identnr) + identpairs.Append (i2); + } + } +#endif + + void Mesh :: ComputeNVertices () + { + int i, j, nv; + int ne = GetNE(); + int nse = GetNSE(); + + numvertices = 0; + for (i = 1; i <= ne; i++) + { + const Element & el = VolumeElement(i); + nv = el.GetNV(); + for (j = 0; j < nv; j++) + if (el[j] > numvertices) + numvertices = el[j]; + } + for (i = 1; i <= nse; i++) + { + const Element2d & el = SurfaceElement(i); + nv = el.GetNV(); + for (j = 1; j <= nv; j++) + if (el.PNum(j) > numvertices) + numvertices = el.PNum(j); + } + + numvertices += 1- PointIndex::BASE; + } + + int Mesh :: GetNV () const + { + if (numvertices < 0) + return GetNP(); + else + return numvertices; + } + + void Mesh :: SetNP (int np) + { + points.SetSize(np); + // ptyps.SetSize(np); + + int mlold = mlbetweennodes.Size(); + mlbetweennodes.SetSize(np); + if (np > mlold) + for (int i = mlold+PointIndex::BASE; + i < np+PointIndex::BASE; i++) + { + mlbetweennodes[i].I1() = PointIndex::BASE-1; + mlbetweennodes[i].I2() = PointIndex::BASE-1; + } + + GetIdentifications().SetMaxPointNr (np + PointIndex::BASE-1); + } + + + /* + void Mesh :: BuildConnectedNodes () + { + if (PureTetMesh()) + { + connectedtonode.SetSize(0); + return; + } + + + int i, j, k; + int np = GetNP(); + int ne = GetNE(); + TABLE<int> conto(np); + for (i = 1; i <= ne; i++) + { + const Element & el = VolumeElement(i); + + if (el.GetType() == PRISM) + { + for (j = 1; j <= 6; j++) + { + int n1 = el.PNum (j); + int n2 = el.PNum ((j+2)%6+1); + // if (n1 != n2) + { + int found = 0; + for (k = 1; k <= conto.EntrySize(n1); k++) + if (conto.Get(n1, k) == n2) + { + found = 1; + break; + } + if (!found) + conto.Add (n1, n2); + } + } + } + else if (el.GetType() == PYRAMID) + { + for (j = 1; j <= 4; j++) + { + int n1, n2; + switch (j) + { + case 1: n1 = 1; n2 = 4; break; + case 2: n1 = 4; n2 = 1; break; + case 3: n1 = 2; n2 = 3; break; + case 4: n1 = 3; n2 = 2; break; + } + + int found = 0; + for (k = 1; k <= conto.EntrySize(n1); k++) + if (conto.Get(n1, k) == n2) + { + found = 1; + break; + } + if (!found) + conto.Add (n1, n2); + } + } + } + + connectedtonode.SetSize(np); + for (i = 1; i <= np; i++) + connectedtonode.Elem(i) = 0; + + for (i = 1; i <= np; i++) + if (connectedtonode.Elem(i) == 0) + { + connectedtonode.Elem(i) = i; + ConnectToNodeRec (i, i, conto); + } + + + + } + + void Mesh :: ConnectToNodeRec (int node, int tonode, + const TABLE<int> & conto) + { + int i, n2; + // (*testout) << "connect " << node << " to " << tonode << endl; + for (i = 1; i <= conto.EntrySize(node); i++) + { + n2 = conto.Get(node, i); + if (!connectedtonode.Get(n2)) + { + connectedtonode.Elem(n2) = tonode; + ConnectToNodeRec (n2, tonode, conto); + } + } + } + */ + + + bool Mesh :: PureTrigMesh (int faceindex) const + { + if (!faceindex) + return !mparam.quad; + + int i; + for (i = 1; i <= GetNSE(); i++) + if (SurfaceElement(i).GetIndex() == faceindex && + SurfaceElement(i).GetNP() != 3) + return 0; + return 1; + } + + bool Mesh :: PureTetMesh () const + { + for (ElementIndex ei = 0; ei < GetNE(); ei++) + if (VolumeElement(ei).GetNP() != 4) + return 0; + return 1; + } + + void Mesh :: UpdateTopology() + { + topology->Update(); + clusters->Update(); + } + + + void Mesh :: SetMaterial (int domnr, const char * mat) + { + if (domnr > materials.Size()) + { + int olds = materials.Size(); + materials.SetSize (domnr); + for (int i = olds; i < domnr; i++) + materials[i] = 0; + } + materials.Elem(domnr) = new char[strlen(mat)+1]; + strcpy (materials.Elem(domnr), mat); + } + + const char * Mesh :: GetMaterial (int domnr) const + { + if (domnr <= materials.Size()) + return materials.Get(domnr); + return 0; + } + + + + + + void Mesh :: PrintMemInfo (ostream & ost) const + { + ost << "Mesh Mem:" << endl; + + ost << GetNP() << " Points, of size " + << sizeof (Point3d) << " + " << sizeof(POINTTYPE) << " = " + << GetNP() * (sizeof (Point3d) + sizeof(POINTTYPE)) << endl; + + ost << GetNSE() << " Surface elements, of size " + << sizeof (Element2d) << " = " + << GetNSE() * sizeof(Element2d) << endl; + + ost << GetNE() << " Volume elements, of size " + << sizeof (Element) << " = " + << GetNE() * sizeof(Element) << endl; + + ost << "surfs on node:"; + surfacesonnode.PrintMemInfo (cout); + + ost << "boundaryedges: "; + if (boundaryedges) + boundaryedges->PrintMemInfo (cout); + + ost << "surfelementht: "; + if (surfelementht) + surfelementht->PrintMemInfo (cout); + } +} diff --git a/contrib/Netgen/libsrc/meshing/meshclass.hpp b/contrib/Netgen/libsrc/meshing/meshclass.hpp new file mode 100644 index 0000000000..4ad0edbb9b --- /dev/null +++ b/contrib/Netgen/libsrc/meshing/meshclass.hpp @@ -0,0 +1,620 @@ +#ifndef MESHCLASS +#define MESHCLASS + +/**************************************************************************/ +/* File: meshclass.hh */ +/* Author: Joachim Schoeberl */ +/* Date: 20. Nov. 99 */ +/**************************************************************************/ + +/* + The mesh class +*/ + + + +enum resthtype { RESTRICTH_FACE, RESTRICTH_EDGE, + RESTRICTH_SURFACEELEMENT, RESTRICTH_POINT, RESTRICTH_SEGMENT }; + +class HPRefElement; + + +/// 2d/3d mesh +class Mesh +{ +public: + // typedef MoveableArray<MeshPoint> T_POINTS; + // typedef MoveableArray<Element> T_VOLELEMENTS; + // typedef MoveableArray<Element2d> T_SURFELEMENTS; + + typedef ARRAY<MeshPoint,PointIndex::BASE> T_POINTS; + typedef ARRAY<Element> T_VOLELEMENTS; + typedef ARRAY<Element2d> T_SURFELEMENTS; + + +private: + /// point coordinates + T_POINTS points; + /// type of point, is set in calcsurfacesofnode + // ARRAY<POINTTYPE,PointIndex::BASE> ptyps; + /// type of element, set in calcsurfacesofnode + ARRAY<ELEMENTTYPE> eltyps; + + /// line-segments at edges + ARRAY<Segment> segments; + /// surface elements, 2d-inner elements + T_SURFELEMENTS surfelements; + /// volume elements + T_VOLELEMENTS volelements; + /// points will be fixed forever + ARRAY<PointIndex> lockedpoints; + + + /// surface indices at boundary nodes + TABLE<int,PointIndex::BASE> surfacesonnode; + /// boundary edges (1..normal bedge, 2..segment) + INDEX_2_CLOSED_HASHTABLE<int> * boundaryedges; + /// + INDEX_2_CLOSED_HASHTABLE<int> * segmentht; + /// + INDEX_3_CLOSED_HASHTABLE<int> * surfelementht; + + /// faces of rest-solid + ARRAY<Element2d> openelements; + /// open segmenets for surface meshing + ARRAY<Segment> opensegments; + + + + /** + Representation of local mesh-size h + */ + LocalH * lochfunc; + /// + double hglob; + /// + ARRAY<double> maxhdomain; + + /** + the face-index of the surface element maps into + this table. + */ + ARRAY<FaceDescriptor> facedecoding; + + /// sub-domain materials + ARRAY<char*> materials; + + /// Periodic surface, close surface, etc. identifications + Identifications * ident; + + + /// number of vertices (if < 0, use np) + int numvertices; + + /// geometric search tree for interval intersection search + Box3dTree * elementsearchtree; + /// time stamp for tree + int elementsearchtreets; + + /// element -> face, element -> edge etc ... + class MeshTopology * topology; + /// methods for high order elements + class CurvedElements * curvedelems; + /// nodes identified by close points + class AnisotropicClusters * clusters; + + /// space dimension (2 or 3) + int dimension; + + /// changed by every minor modification (addpoint, ...) + int timestamp; + /// changed after finishing global algorithm (improve, ...) + int majortimestamp; + + /// mesh access semaphor. + NgMutex mutex; + + +public: + + // store coarse mesh before hp-refinement + ARRAY<HPRefElement> * hpelements; + Mesh * coarsemesh; + + + /// number of refinement levels + int mglevels; + /// refinement hierarchy + ARRAY<INDEX_2,PointIndex::BASE> mlbetweennodes; + /// parent element of volume element + ARRAY<int> mlparentelement; + /// parent element of surface element + ARRAY<int> mlparentsurfaceelement; + + + + /// + Mesh(); + /// + ~Mesh(); + + Mesh & operator= (const Mesh & mesh2); + + /// + void DeleteMesh(); + + /// + void ClearSurfaceElements() + { + surfelements.SetSize(0); + timestamp = NextTimeStamp(); + } + + /// + void ClearVolumeElements() + { + volelements.SetSize(0); + eltyps.SetSize(0); + timestamp = NextTimeStamp(); + } + + /// + void ClearSegments() + { + segments.SetSize(0); + timestamp = NextTimeStamp(); + } + + /// + bool TestOk () const; + + + PointIndex AddPoint (const Point3d & p, int layer = 1); + int GetNP () const { return points.Size(); } + + MeshPoint & Point(int i) { return points.Elem(i); } + MeshPoint & Point(PointIndex pi) { return points[pi]; } + const MeshPoint & Point(int i) const { return points.Get(i); } + const MeshPoint & Point(PointIndex pi) const { return points[pi]; } + + const MeshPoint & operator[] (PointIndex pi) const { return points[pi]; } + MeshPoint & operator[] (PointIndex pi) { return points[pi]; } + + /* + POINTTYPE PointType (int i) const { return ptyps.Get(i); } + POINTTYPE PointType (PointIndex pi) const { return ptyps[pi]; } + */ + POINTTYPE PointType (int i) const { return points.Get(i).Type(); } + POINTTYPE PointType (PointIndex pi) const { return points[pi].Type(); } + + + const T_POINTS & Points() const { return points; } + T_POINTS & Points() { return points; } + // ARRAY<POINTTYPE,PointIndex::BASE> & PointTypes() { return ptyps; } + + + + + + + SegmentIndex AddSegment (const Segment & s); + void DeleteSegment (int segnr) + { + segments.Elem(segnr).p1 = PointIndex::BASE-1; + segments.Elem(segnr).p2 = PointIndex::BASE-1; + } + + int GetNSeg () const { return segments.Size(); } + Segment & LineSegment(int i) { return segments.Elem(i); } + const Segment & LineSegment(int i) const { return segments.Get(i); } + + 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]; } + + + + + SurfaceElementIndex AddSurfaceElement (const Element2d & el); + void DeleteSurfaceElement (int eli) + { + surfelements.Elem(eli).Delete(); + surfelements.Elem(eli).PNum(1) = -1; + surfelements.Elem(eli).PNum(2) = -1; + surfelements.Elem(eli).PNum(3) = -1; + timestamp = NextTimeStamp(); + } + + void DeleteSurfaceElement (SurfaceElementIndex eli) + { + DeleteSurfaceElement (int(eli)+1); + } + + int GetNSE () const { return surfelements.Size(); } + Element2d & SurfaceElement(int i) { return surfelements.Elem(i); } + const Element2d & SurfaceElement(int i) const { return surfelements.Get(i); } + + Element2d & SurfaceElement(SurfaceElementIndex i) + { return surfelements[i]; } + const Element2d & SurfaceElement(SurfaceElementIndex i) const + { return surfelements[i]; } + + const Element2d & operator[] (SurfaceElementIndex ei) const + { return surfelements[ei]; } + Element2d & operator[] (SurfaceElementIndex ei) + { return surfelements[ei]; } + + + void GetSurfaceElementsOfFace (int facenr, ARRAY<SurfaceElementIndex> & sei) const; + + + + ElementIndex AddVolumeElement (const Element & el); + + int GetNE () const { return volelements.Size(); } + + Element & VolumeElement(int i) { return volelements.Elem(i); } + const Element & VolumeElement(int i) const { return volelements.Get(i); } + Element & VolumeElement(ElementIndex i) { return volelements[i]; } + const Element & VolumeElement(ElementIndex i) const { return volelements[i]; } + + const Element & operator[] (ElementIndex ei) const + { return volelements[ei]; } + Element & operator[] (ElementIndex ei) + { return volelements[ei]; } + + + + + + ELEMENTTYPE ElementType (int i) const { return eltyps.Get(i); } + ELEMENTTYPE ElementType (ElementIndex i) const { return eltyps[i]; } + + const T_VOLELEMENTS & VolumeElements() const { return volelements; } + T_VOLELEMENTS & VolumeElements() { return volelements; } + + + /// + double ElementError (int eli) const; + + /// + void AddLockedPoint (PointIndex pi); + /// + void ClearLockedPoints (); + + const ARRAY<PointIndex> & LockedPoints() const + { return lockedpoints; } + + /// Returns number of domains + int GetNDomains() const; + + + /// + int GetDimension() const + { return dimension; } + void SetDimension(int dim) + { dimension = dim; } + + /// sets internal tables + void CalcSurfacesOfNode (); + + /// additional (temporarily) fix points + void FixPoints (const BitArray & fixpoints); + + /** + finds elements without neighbour and + boundary elements without inner element. + Results are stored in openelements. + if dom == 0, all sub-domains, else subdomain dom */ + void FindOpenElements (int dom = 0); + + + /** + finds segments without surface element, + and surface elements without neighbours. + store in opensegmentsy + */ + void FindOpenSegments (int surfnr = 0); + /** + remove one layer of surface elements + */ + void RemoveOneLayerSurfaceElements (); + + + int GetNOpenSegments () { return opensegments.Size(); } + const Segment & GetOpenSegment (int nr) { return opensegments.Get(nr); } + + /** + Checks overlap of boundary + return == 1, iff overlap + */ + int CheckOverlappingBoundary (); + /** + Checks consistent boundary + return == 0, everything ok + */ + int CheckConsistentBoundary () const; + + /* + checks element orientation + */ + int CheckVolumeMesh () const; + + + /** + finds average h of surface surfnr if surfnr > 0, + else of all surfaces. + */ + double AverageH (int surfnr = 0) const; + /// Calculates localh + void CalcLocalH (); + /// + void SetLocalH (const Point3d & pmin, const Point3d & pmax, double grading); + /// + void RestrictLocalH (const Point3d & p, double hloc); + /// + void RestrictLocalHLine (const Point3d & p1, const Point3d & p2, + double hloc); + /// number of elements per radius + void CalcLocalHFromSurfaceCurvature(double elperr); + /// + void CalcLocalHFromPointDistances(void); + /// + void RestrictLocalH (resthtype rht, int nr, double loch); + /// + void LoadLocalMeshSize (const char * meshsizefilename); + /// + void SetGlobalH (double h); + /// + double MaxHDomain (int dom) const; + /// + void SetMaxHDomain (const ARRAY<double> & mhd); + /// + double GetH (const Point3d & p) const; + /// + double GetMinH (const Point3d & pmin, const Point3d & pmax); + /// + LocalH & LocalHFunction () { return * lochfunc; } + + /// Find bounding box + void GetBox (Point3d & pmin, Point3d & pmax, int dom = -1) const; + + /// Find bounding box of points of typ ptyp or less + void GetBox (Point3d & pmin, Point3d & pmax, POINTTYPE ptyp ) const; + + /// + int GetNOpenElements() const + { return openelements.Size(); } + /// + const Element2d & OpenElement(int i) const + { return openelements.Get(i); } + + + /// are also quads open elements + int HasOpenQuads () const; + + /// split into connected pieces + void SplitIntoParts (); + + /// + void SplitSeparatedFaces (); + + /// Refines mesh and projects points to true surface + // void Refine (int levels, const CSGeometry * geom); + + + bool BoundaryEdge (PointIndex pi1, PointIndex pi2) const + { + INDEX_2 i2 (pi1, pi2); + i2.Sort(); + return boundaryedges->Used (i2); + } + + bool IsSegment (PointIndex pi1, PointIndex pi2) const + { + INDEX_2 i2 (pi1, pi2); + i2.Sort(); + return segmentht->Used (i2); + } + + SegmentIndex SegmentNr (PointIndex pi1, PointIndex pi2) const + { + INDEX_2 i2 (pi1, pi2); + i2.Sort(); + return segmentht->Get (i2); + } + + + /** + Remove unused points. etc. + */ + void Compress (); + + /// + void Save (const string & filename) const; + /// + void Load (const string & filename); + /// + void Merge (const string & filename); + + + /// + void ImproveMesh (OPTIMIZEGOAL goal = OPT_QUALITY); + + /// + void ImproveMeshJacobian (OPTIMIZEGOAL goal = OPT_QUALITY); + + + /* +#ifdef SOLIDGEOM + /// old + void ImproveMesh (const CSGeometry & surfaces, + OPTIMIZEGOAL goal = OPT_QUALITY); +#endif + */ + + /** + free nodes in environment of openelements + for optimiztion + */ + void FreeOpenElementsEnvironment (int layers); + + /// + bool LegalTet (Element & el) const + { + if (el.IllegalValid()) + return !el.Illegal(); + return LegalTet2 (el); + } + /// + bool LegalTet2 (Element & el) const; + + + /// + bool LegalTrig (const Element2d & el) const; + /** + if values non-null, return values in 4-double array: + triangle angles min/max, tetangles min/max + if null, output results on cout + */ + void CalcMinMaxAngle (double badellimit, double * retvalues = NULL); + + /* + Marks elements which are dangerous to refine + return: number of illegal elements + */ + int MarkIllegalElements (); + + /// orient surface mesh, for one sub-domain only + void SurfaceMeshOrientation (); + + /// convert mixed element mesh to tet-mesh + void Split2Tets(); + + + /// build box-search tree + void BuildElementSearchTree (); + /// gives element of point, barycentric coordinates + int GetElementOfPoint (const Point3d & p, + double * lami, + bool build_searchtree = 0, + const int index = -1) const; + + /// give list of vol elements which are int the box(p1,p2) + void GetIntersectingVolEls(const Point3d& p1, const Point3d& p2, + ARRAY<int> & locels) const; + + /// + int AddFaceDescriptor(const FaceDescriptor& fd) + { return facedecoding.Append(fd); } + + + /// + void SetMaterial (int domnr, const char * mat); + /// + const char * GetMaterial (int domnr) const; + + + /// + void ClearFaceDescriptors() + { facedecoding.SetSize(0); } + + /// + int GetNFD () const + { return facedecoding.Size(); } + + const FaceDescriptor & GetFaceDescriptor (int i) const + { return facedecoding.Get(i); } + + /// + FaceDescriptor & GetFaceDescriptor (int i) + { return facedecoding.Elem(i); } + +#ifdef NONE + /* + Identify points pi1 and pi2, due to + identification nr identnr + */ + void AddIdentification (int pi1, int pi2, int identnr); + + int GetIdentification (int pi1, int pi2) const; + int GetIdentificationSym (int pi1, int pi2) const; + /// + INDEX_2_HASHTABLE<int> & GetIdentifiedPoints () + { + return *identifiedpoints; + } + + /// + void GetIdentificationMap (int identnr, ARRAY<int> & identmap) const; + /// + void GetIdentificationPairs (int identnr, ARRAY<INDEX_2> & identpairs) const; + /// + int GetMaxIdentificationNr () const + { + return maxidentnr; + } +#endif + + /// return periodic, close surface etc. identifications + Identifications & GetIdentifications () { return *ident; } + /// return periodic, close surface etc. identifications + const Identifications & GetIdentifications () const { return *ident; } + + + + /// find number of vertices + void ComputeNVertices (); + /// number of vertices (no edge-midpoints) + int GetNV () const; + /// remove edge points + void SetNP (int np); + + /* + /// build connected nodes along prism stack + void BuildConnectedNodes (); + void ConnectToNodeRec (int node, int tonode, + const TABLE<int> & conto); + */ + + bool PureTrigMesh (int faceindex = 0) const; + bool PureTetMesh () const; + + + const class MeshTopology & GetTopology () const + { return *topology; } + void UpdateTopology(); + + class CurvedElements & GetCurvedElements () const + { return *curvedelems; } + + const class AnisotropicClusters & GetClusters () const + { return *clusters; } + + + + int GetTimeStamp() const { return timestamp; } + void SetNextTimeStamp() + { timestamp = NextTimeStamp(); } + + int GetMajorTimeStamp() const { return majortimestamp; } + void SetNextMajorTimeStamp() + { majortimestamp = timestamp = NextTimeStamp(); } + + + /// return mutex + NgMutex & Mutex () { return mutex; } + + /// + friend void OptimizeRestart (Mesh & mesh3d); + /// + void PrintMemInfo (ostream & ost) const; + /// + friend class Meshing3; +}; + + + + +#endif diff --git a/contrib/Netgen/libsrc/meshing/meshfunc.cpp b/contrib/Netgen/libsrc/meshing/meshfunc.cpp new file mode 100644 index 0000000000..90fe9e68c5 --- /dev/null +++ b/contrib/Netgen/libsrc/meshing/meshfunc.cpp @@ -0,0 +1,688 @@ +#include <mystdlib.h> +#include "meshing.hpp" + +namespace netgen +{ + extern const char * tetrules[]; + // extern const char * tetrules2[]; + extern const char * prismrules2[]; + extern const char * pyramidrules[]; + extern const char * pyramidrules2[]; + + + extern double teterrpow; + MESHING3_RESULT MeshVolume (MeshingParameters & mp, Mesh& mesh3d) + { + int i, oldne; + PointIndex pi; + + int meshed; + int cntsteps; + + + ARRAY<INDEX_2> connectednodes; + + mesh3d.Compress(); + + // mesh3d.PrintMemInfo (cout); + + + + if (mesh3d.CheckOverlappingBoundary()) + throw NgException ("Stop meshing since boundary mesh is overlapping"); + + + int nonconsist = 0; + for (int k = 1; k <= mesh3d.GetNDomains(); k++) + { + PrintMessage (3, "Check subdomain ", k, " / ", mesh3d.GetNDomains()); + + mesh3d.FindOpenElements(k); + + /* + bool res = mesh3d.CheckOverlappingBoundary(); + if (res) + { + PrintError ("Surface is overlapping !!"); + nonconsist = 1; + } + */ + + bool res = mesh3d.CheckConsistentBoundary(); + if (res) + { + PrintError ("Surface mesh not consistent"); + nonconsist = 1; + } + } + + if (nonconsist) + { + PrintError ("Stop meshing since surface mesh not consistent"); + throw NgException ("Stop meshing since surface mesh not consistent"); + } + + double globmaxh = mp.maxh; + + for (int k = 1; k <= mesh3d.GetNDomains(); k++) + { + if (multithread.terminate) + break; + + PrintMessage (2, ""); + PrintMessage (1, "Meshing subdomain ", k, " of ", mesh3d.GetNDomains()); + + mp.maxh = min2 (globmaxh, mesh3d.MaxHDomain(k)); + + mesh3d.CalcSurfacesOfNode(); + mesh3d.FindOpenElements(k); + + if (!mesh3d.GetNOpenElements()) + continue; + + int qstep; + for (qstep = 1; qstep <= 3; qstep++) + { + if (mesh3d.HasOpenQuads()) + { + string rulefile = ngdir; + + const char ** rulep = NULL; + switch (qstep) + { + case 1: + rulefile += "/rules/prisms2.rls"; + rulep = prismrules2; + break; + case 2: // connect pyramid to triangle + rulefile += "/rules/pyramids2.rls"; + rulep = pyramidrules2; + break; + case 3: // connect to vis-a-vis point + rulefile += "/rules/pyramids.rls"; + rulep = pyramidrules; + break; + } + + // Meshing3 meshing(rulefile); + Meshing3 meshing(rulep); + + MeshingParameters mpquad = mp; + + mpquad.giveuptol = 15; + mpquad.baseelnp = 4; + mpquad.starshapeclass = 100; + + for (pi = PointIndex::BASE; + pi < mesh3d.GetNP()+PointIndex::BASE; pi++) + meshing.AddPoint (mesh3d[pi], pi); + + mesh3d.GetIdentifications().GetPairs (0, connectednodes); + for (i = 1; i <= connectednodes.Size(); i++) + meshing.AddConnectedPair (connectednodes.Get(i)); + + for (i = 1; i <= mesh3d.GetNOpenElements(); i++) + { + Element2d hel = mesh3d.OpenElement(i); + meshing.AddBoundaryElement (hel); + } + + oldne = mesh3d.GetNE(); + + meshing.GenerateMesh (mesh3d, mpquad); + + for (i = oldne + 1; i <= mesh3d.GetNE(); i++) + mesh3d.VolumeElement(i).SetIndex (k); + + (*testout) + << "mesh has " << mesh3d.GetNE() << " prism ?�elements" << endl; + + mesh3d.FindOpenElements(k); + } + } + + + if (mesh3d.HasOpenQuads()) + { + PrintSysError ("mesh has still open quads"); + throw NgException ("Stop meshing since too many attempts"); + // return MESHING3_GIVEUP; + } + + + if (mp.delaunay && mesh3d.GetNOpenElements()) + { + Meshing3 meshing((const char**)NULL); + + mesh3d.FindOpenElements(k); + + + for (pi = PointIndex::BASE; + pi < mesh3d.GetNP()+PointIndex::BASE; pi++) + meshing.AddPoint (mesh3d[pi], pi); + + + for (i = 1; i <= mesh3d.GetNOpenElements(); i++) + meshing.AddBoundaryElement (mesh3d.OpenElement(i)); + + oldne = mesh3d.GetNE(); + + meshing.Delaunay (mesh3d, mp); + + for (i = oldne + 1; i <= mesh3d.GetNE(); i++) + mesh3d.VolumeElement(i).SetIndex (k); + + PrintMessage (3, mesh3d.GetNP(), " points, ", + mesh3d.GetNE(), " elements"); + } + + + cntsteps = 0; + do + { + if (multithread.terminate) + break; + + mesh3d.FindOpenElements(k); + PrintMessage (5, mesh3d.GetNOpenElements(), " open faces"); + cntsteps++; + + if (cntsteps > mp.maxoutersteps) + throw NgException ("Stop meshing since too many attempts"); + + string rulefile = ngdir + "/tetra.rls"; + PrintMessage (1, "start tetmeshing"); + + // Meshing3 meshing(rulefile); + Meshing3 meshing(tetrules); + + + for (PointIndex pi = PointIndex::BASE; + pi < mesh3d.GetNP()+PointIndex::BASE; pi++) + meshing.AddPoint (mesh3d[pi], pi); + + for (i = 1; i <= mesh3d.GetNOpenElements(); i++) + meshing.AddBoundaryElement (mesh3d.OpenElement(i)); + + + oldne = mesh3d.GetNE(); + + mp.giveuptol = 15; + mp.sloppy = 5; + meshing.GenerateMesh (mesh3d, mp); + + for (ElementIndex ei = oldne; ei < mesh3d.GetNE(); ei++) + mesh3d[ei].SetIndex (k); + + + mesh3d.CalcSurfacesOfNode(); + mesh3d.FindOpenElements(k); + + teterrpow = 2; + if (mesh3d.GetNOpenElements() != 0) + { + meshed = 0; + PrintMessage (5, mesh3d.GetNOpenElements(), " open faces found"); + + // mesh3d.Save ("tmp.vol"); + + + MeshOptimize3d optmesh; + + const char * optstr = "mcmstmcmstmcmstmcm"; + int j; + for (j = 1; j <= strlen(optstr); j++) + { + mesh3d.CalcSurfacesOfNode(); + mesh3d.FreeOpenElementsEnvironment(2); + + switch (optstr[j-1]) + { + case 'c': optmesh.CombineImprove(mesh3d, OPT_REST); break; + case 'd': optmesh.SplitImprove(mesh3d, OPT_REST); break; + case 's': optmesh.SwapImprove(mesh3d, OPT_REST); break; + case 't': optmesh.SwapImprove2(mesh3d, OPT_REST); break; + case 'm': mesh3d.ImproveMesh(OPT_REST); break; + } + + } + + mesh3d.FindOpenElements(k); + PrintMessage (3, "Call remove problem"); + RemoveProblem (mesh3d); + mesh3d.FindOpenElements(k); + } + else + { + meshed = 1; + PrintMessage (1, "Success !"); + } + } + while (!meshed); + + PrintMessage (1, mesh3d.GetNP(), " points, ", + mesh3d.GetNE(), " elements"); + } + + mp.maxh = globmaxh; + + MeshQuality3d (mesh3d); + + return MESHING3_OK; + } + + + + + /* + + + MESHING3_RESULT MeshVolumeOld (MeshingParameters & mp, Mesh& mesh3d) + { + int i, k, oldne; + + + int meshed; + int cntsteps; + + + PlotStatistics3d * pstat; + if (globflags.GetNumFlag("silentflag", 1) <= 2) + pstat = new XPlotStatistics3d; + else + pstat = new TerminalPlotStatistics3d; + + cntsteps = 0; + do + { + cntsteps++; + if (cntsteps > mp.maxoutersteps) + { + return MESHING3_OUTERSTEPSEXCEEDED; + } + + + int noldp = mesh3d.GetNP(); + + + if ( (cntsteps == 1) && globflags.GetDefineFlag ("delaunay")) + { + cntsteps ++; + + mesh3d.CalcSurfacesOfNode(); + + + for (k = 1; k <= mesh3d.GetNDomains(); k++) + { + Meshing3 meshing(NULL, pstat); + + mesh3d.FindOpenElements(k); + + for (i = 1; i <= noldp; i++) + meshing.AddPoint (mesh3d.Point(i), i); + + for (i = 1; i <= mesh3d.GetNOpenElements(); i++) + { + if (mesh3d.OpenElement(i).GetIndex() == k) + meshing.AddBoundaryElement (mesh3d.OpenElement(i)); + } + + oldne = mesh3d.GetNE(); + if (globflags.GetDefineFlag ("blockfill")) + { + if (!globflags.GetDefineFlag ("localh")) + meshing.BlockFill + (mesh3d, mp.h * globflags.GetNumFlag ("relblockfillh", 1)); + else + meshing.BlockFillLocalH (mesh3d); + } + + MeshingParameters mpd; + meshing.Delaunay (mesh3d, mpd); + + for (i = oldne + 1; i <= mesh3d.GetNE(); i++) + mesh3d.VolumeElement(i).SetIndex (k); + } + } + + noldp = mesh3d.GetNP(); + + mesh3d.CalcSurfacesOfNode(); + mesh3d.FindOpenElements(); + for (k = 1; k <= mesh3d.GetNDomains(); k++) + { + Meshing3 meshing(globflags.GetStringFlag ("rules3d", NULL), pstat); + + Point3d pmin, pmax; + mesh3d.GetBox (pmin, pmax, k); + + rot.SetCenter (Center (pmin, pmax)); + + for (i = 1; i <= noldp; i++) + meshing.AddPoint (mesh3d.Point(i), i); + + for (i = 1; i <= mesh3d.GetNOpenElements(); i++) + { + if (mesh3d.OpenElement(i).GetIndex() == k) + meshing.AddBoundaryElement (mesh3d.OpenElement(i)); + } + + oldne = mesh3d.GetNE(); + + + if ( (cntsteps == 1) && globflags.GetDefineFlag ("blockfill")) + { + if (!globflags.GetDefineFlag ("localh")) + { + meshing.BlockFill + (mesh3d, + mp.h * globflags.GetNumFlag ("relblockfillh", 1)); + } + else + { + meshing.BlockFillLocalH (mesh3d); + } + } + + + mp.giveuptol = int(globflags.GetNumFlag ("giveuptol", 15)); + + meshing.GenerateMesh (mesh3d, mp); + + for (i = oldne + 1; i <= mesh3d.GetNE(); i++) + mesh3d.VolumeElement(i).SetIndex (k); + } + + + + mesh3d.CalcSurfacesOfNode(); + mesh3d.FindOpenElements(); + + teterrpow = 2; + if (mesh3d.GetNOpenElements() != 0) + { + meshed = 0; + (*mycout) << "Open elements found, old" << endl; + const char * optstr = "mcmcmcmcm"; + int j; + for (j = 1; j <= strlen(optstr); j++) + switch (optstr[j-1]) + { + case 'c': mesh3d.CombineImprove(); break; + case 'd': mesh3d.SplitImprove(); break; + case 's': mesh3d.SwapImprove(); break; + case 'm': mesh3d.ImproveMesh(2); break; + } + + (*mycout) << "Call remove" << endl; + RemoveProblem (mesh3d); + (*mycout) << "Problem removed" << endl; + } + else + meshed = 1; + } + while (!meshed); + + MeshQuality3d (mesh3d); + + return MESHING3_OK; + } + + */ + + + MESHING3_RESULT MeshMixedVolume(MeshingParameters & mp, Mesh& mesh3d) + { + int i, j; + MESHING3_RESULT res; + Point3d pmin, pmax; + + mp.giveuptol = 10; + mp.baseelnp = 4; + mp.starshapeclass = 100; + + // TerminalPlotStatistics3d pstat; + + Meshing3 meshing1("pyramids.rls"); + for (i = 1; i <= mesh3d.GetNP(); i++) + meshing1.AddPoint (mesh3d.Point(i), i); + + mesh3d.FindOpenElements(); + for (i = 1; i <= mesh3d.GetNOpenElements(); i++) + if (mesh3d.OpenElement(i).GetIndex() == 1) + meshing1.AddBoundaryElement (mesh3d.OpenElement(i)); + + res = meshing1.GenerateMesh (mesh3d, mp); + + mesh3d.GetBox (pmin, pmax); + PrintMessage (1, "Mesh pyramids, res = ", res); + if (res) + exit (1); + + + for (i = 1; i <= mesh3d.GetNE(); i++) + mesh3d.VolumeElement(i).SetIndex (1); + + // do delaunay + + mp.baseelnp = 0; + mp.starshapeclass = 5; + + Meshing3 meshing2(NULL); + for (i = 1; i <= mesh3d.GetNP(); i++) + meshing2.AddPoint (mesh3d.Point(i), i); + + mesh3d.FindOpenElements(); + for (i = 1; i <= mesh3d.GetNOpenElements(); i++) + if (mesh3d.OpenElement(i).GetIndex() == 1) + meshing2.AddBoundaryElement (mesh3d.OpenElement(i)); + + MeshingParameters mpd; + meshing2.Delaunay (mesh3d, mpd); + + for (i = 1; i <= mesh3d.GetNE(); i++) + mesh3d.VolumeElement(i).SetIndex (1); + + + mp.baseelnp = 0; + mp.giveuptol = 10; + + for (int trials = 1; trials <= 50; trials++) + { + if (multithread.terminate) + return MESHING3_TERMINATE; + + Meshing3 meshing3("tetra.rls"); + for (i = 1; i <= mesh3d.GetNP(); i++) + meshing3.AddPoint (mesh3d.Point(i), i); + + mesh3d.FindOpenElements(); + for (i = 1; i <= mesh3d.GetNOpenElements(); i++) + if (mesh3d.OpenElement(i).GetIndex() == 1) + meshing3.AddBoundaryElement (mesh3d.OpenElement(i)); + + if (trials > 1) + CheckSurfaceMesh2 (mesh3d); + res = meshing3.GenerateMesh (mesh3d, mp); + + for (i = 1; i <= mesh3d.GetNE(); i++) + mesh3d.VolumeElement(i).SetIndex (1); + + if (res == 0) break; + + + + for (i = 1; i <= mesh3d.GetNE(); i++) + { + const Element & el = mesh3d.VolumeElement(i); + if (el.GetNP() != 4) + { + for (j = 1; j <= el.GetNP(); j++) + mesh3d.AddLockedPoint (el.PNum(j)); + } + } + + mesh3d.CalcSurfacesOfNode(); + mesh3d.FindOpenElements(); + + MeshOptimize3d optmesh; + + teterrpow = 2; + const char * optstr = "mcmcmcmcm"; + for (j = 1; j <= strlen(optstr); j++) + switch (optstr[j-1]) + { + case 'c': optmesh.CombineImprove(mesh3d, OPT_REST); break; + case 'd': optmesh.SplitImprove(mesh3d); break; + case 's': optmesh.SwapImprove(mesh3d); break; + case 'm': mesh3d.ImproveMesh(); break; + } + + RemoveProblem (mesh3d); + } + + + PrintMessage (1, "Meshing tets, res = ", res); + if (res) + { + mesh3d.FindOpenElements(); + PrintSysError (1, "Open elemetns: ", mesh3d.GetNOpenElements()); + exit (1); + } + + + + for (i = 1; i <= mesh3d.GetNE(); i++) + { + const Element & el = mesh3d.VolumeElement(i); + if (el.GetNP() != 4) + { + for (j = 1; j <= el.GetNP(); j++) + mesh3d.AddLockedPoint (el.PNum(j)); + } + } + + mesh3d.CalcSurfacesOfNode(); + mesh3d.FindOpenElements(); + + MeshOptimize3d optmesh; + + teterrpow = 2; + const char * optstr = "mcmcmcmcm"; + for (j = 1; j <= strlen(optstr); j++) + switch (optstr[j-1]) + { + case 'c': optmesh.CombineImprove(mesh3d, OPT_REST); break; + case 'd': optmesh.SplitImprove(mesh3d); break; + case 's': optmesh.SwapImprove(mesh3d); break; + case 'm': mesh3d.ImproveMesh(); break; + } + + + return MESHING3_OK; + } + + + + + + + + MESHING3_RESULT OptimizeVolume (MeshingParameters & mp, + Mesh & mesh3d) + // const CSGeometry * geometry) + { + int i, j; + + PrintMessage (1, "Volume Optimization"); + + /* + if (!mesh3d.PureTetMesh()) + return MESHING3_OK; + */ + + // (*mycout) << "optstring = " << mp.optimize3d << endl; + /* + const char * optstr = globflags.GetStringFlag ("optimize3d", "cmh"); + int optsteps = int (globflags.GetNumFlag ("optsteps3d", 2)); + */ + + mesh3d.CalcSurfacesOfNode(); + for (i = 1; i <= mp.optsteps3d; i++) + { + if (multithread.terminate) + break; + + MeshOptimize3d optmesh; + + teterrpow = mp.opterrpow; + for (j = 1; j <= strlen(mp.optimize3d); j++) + { + if (multithread.terminate) + break; + + switch (mp.optimize3d[j-1]) + { + case 'c': optmesh.CombineImprove(mesh3d, OPT_REST); break; + case 'd': optmesh.SplitImprove(mesh3d); break; + case 's': optmesh.SwapImprove(mesh3d); break; + case 't': optmesh.SwapImprove2(mesh3d); break; +#ifdef SOLIDGEOM + case 'm': mesh3d.ImproveMesh(*geometry); break; + case 'M': mesh3d.ImproveMesh(*geometry); break; +#else + case 'm': mesh3d.ImproveMesh(); break; + case 'M': mesh3d.ImproveMesh(); break; +#endif + + case 'j': mesh3d.ImproveMeshJacobian(); break; + } + } + MeshQuality3d (mesh3d); + } + + return MESHING3_OK; + } + + + + + void RemoveIllegalElements (Mesh & mesh3d) + { + int it = 10; + int nillegal, oldn; + int i; + + PrintMessage (1, "Remove Illegal Elements"); + // return, if non-pure tet-mesh + /* + if (!mesh3d.PureTetMesh()) + return; + */ + mesh3d.CalcSurfacesOfNode(); + + nillegal = mesh3d.MarkIllegalElements(); + + MeshOptimize3d optmesh; + while (nillegal && (it--) > 0) + { + if (multithread.terminate) + break; + + PrintMessage (5, nillegal, " illegal tets"); + optmesh.SplitImprove (mesh3d, OPT_LEGAL); + + mesh3d.MarkIllegalElements(); // test + optmesh.SwapImprove (mesh3d, OPT_LEGAL); + mesh3d.MarkIllegalElements(); // test + optmesh.SwapImprove2 (mesh3d, OPT_LEGAL); + + oldn = nillegal; + nillegal = mesh3d.MarkIllegalElements(); + + if (oldn != nillegal) + it = 10; + } + PrintMessage (5, nillegal, " illegal tets"); + } +} diff --git a/contrib/Netgen/libsrc/meshing/meshfunc.hpp b/contrib/Netgen/libsrc/meshing/meshfunc.hpp new file mode 100644 index 0000000000..ab2d661050 --- /dev/null +++ b/contrib/Netgen/libsrc/meshing/meshfunc.hpp @@ -0,0 +1,41 @@ +#ifndef FILE_MESHFUNC +#define FILE_MESHFUNC + +/**************************************************************************/ +/* File: meshfunc.hh */ +/* Author: Johannes Gerstmayr */ +/* Date: 26. Jan. 98 */ +/**************************************************************************/ + + +/* + Functions for mesh-generations strategies + */ + +class Mesh; +// class CSGeometry; + +/// Build tet-mesh +MESHING3_RESULT MeshVolume(MeshingParameters & mp, Mesh& mesh3d); + +/// Build mixed-element mesh +MESHING3_RESULT MeshMixedVolume(MeshingParameters & mp, Mesh& mesh3d); + +/// Optimize tet-mesh +MESHING3_RESULT OptimizeVolume(MeshingParameters & mp, Mesh& mesh3d); +// const CSGeometry * geometry = NULL); + +void RemoveIllegalElements (Mesh & mesh3d); + + +enum MESHING_STEP { + MESHCONST_ANALYSE = 1, + MESHCONST_MESHEDGES = 2, + MESHCONST_MESHSURFACE = 3, + MESHCONST_OPTSURFACE = 4, + MESHCONST_MESHVOLUME = 5, + MESHCONST_OPTVOLUME = 6 +}; + + +#endif diff --git a/contrib/Netgen/libsrc/meshing/meshfunc2d.cpp b/contrib/Netgen/libsrc/meshing/meshfunc2d.cpp new file mode 100644 index 0000000000..f329d1df76 --- /dev/null +++ b/contrib/Netgen/libsrc/meshing/meshfunc2d.cpp @@ -0,0 +1,61 @@ +#include <mystdlib.h> +#include "meshing.hpp" + +namespace netgen +{ + + void Optimize2d (Mesh & mesh, MeshingParameters & mp) + { + int i, j; + + double h = mp.maxh; + + mesh.CalcSurfacesOfNode(); + + const char * optstr = mp.optimize2d; + int optsteps = mp.optsteps2d; + + // cout << "optstr = " << optstr << endl; + + for (i = 1; i <= optsteps; i++) + for (j = 1; j <= strlen(optstr); j++) + { + if (multithread.terminate) break; + switch (optstr[j-1]) + { + case 's': + { // topological swap + MeshOptimize2d meshopt; + meshopt.SetMetricWeight (0); + meshopt.EdgeSwapping (mesh, 0); + break; + } + case 'S': + { // metric swap + MeshOptimize2d meshopt; + meshopt.SetMetricWeight (0); + meshopt.EdgeSwapping (mesh, 1); + break; + } + case 'm': + { + MeshOptimize2d meshopt; + meshopt.SetMetricWeight (1); + meshopt.ImproveMesh(mesh); + break; + } + + case 'c': + { + MeshOptimize2d meshopt; + meshopt.SetMetricWeight (0.2); + meshopt.CombineImprove(mesh); + break; + } + default: + cerr << "Optimization code " << optstr[j-1] << " not defined" << endl; + } + } + } + +} diff --git a/contrib/Netgen/libsrc/meshing/meshing.hpp b/contrib/Netgen/libsrc/meshing/meshing.hpp new file mode 100644 index 0000000000..a4442867b3 --- /dev/null +++ b/contrib/Netgen/libsrc/meshing/meshing.hpp @@ -0,0 +1,60 @@ +#ifndef FILE_MESHING +#define FILE_MESHING + +#include <myadt.hpp> +#include <gprim.hpp> +#include <linalg.hpp> +#include <opti.hpp> + +namespace netgen +{ + + class CSGeometry; + + +#include "msghandler.hpp" + +#include "meshtype.hpp" +#include "localh.hpp" +#include "meshclass.hpp" +#include "global.hpp" + + +#include "meshtool.hpp" +#include "ruler2.hpp" +#include "adfront2.hpp" +#include "meshing2.hpp" +#include "improve2.hpp" + + +#include "geomsearch.hpp" +#include "adfront3.hpp" +#include "ruler3.hpp" + +#ifndef SMALLLIB +#define _INCLUDE_MORE +#endif +#ifdef LINUX +#define _INCLUDE_MORE +#endif + +#ifdef _INCLUDE_MORE +#include "meshing3.hpp" +#include "improve3.hpp" +#endif +#include "findip.hpp" + +#include "topology.hpp" +#include "curvedelems.hpp" +#include "clusters.hpp" + +#ifdef _INCLUDE_MORE +#include "meshfunc.hpp" +#endif +#include "bisect.hpp" +#include "hprefinement.hpp" +#include "boundarylayer.hpp" +#include "specials.hpp" +} + +#endif diff --git a/contrib/Netgen/libsrc/meshing/meshing2.cpp b/contrib/Netgen/libsrc/meshing/meshing2.cpp new file mode 100644 index 0000000000..e7643194c4 --- /dev/null +++ b/contrib/Netgen/libsrc/meshing/meshing2.cpp @@ -0,0 +1,1864 @@ +#include <mystdlib.h> +#include "meshing.hpp" + +namespace netgen +{ + static void glrender (int wait); + + + // global variable for visualization + + static ARRAY<Point3d> locpoints; + static ARRAY<int> legalpoints; + static ARRAY<Point2d> plainpoints; + static ARRAY<int> plainzones; + static ARRAY<INDEX_2> loclines; + static int geomtrig; + //static const char * rname; + static int cntelem, trials, nfaces; + static int oldnl; + static int qualclass; + + + Meshing2 :: Meshing2 (const Box3d & aboundingbox) + { + boundingbox = aboundingbox; + + LoadRules (NULL); + // LoadRules ("rules/quad.rls"); + // LoadRules ("rules/triangle.rls"); + + adfront = new AdFront2(boundingbox); + starttime = GetTime(); + } + + + Meshing2 :: ~Meshing2 () + { + delete adfront; + for (int i = 0; i < rules.Size(); i++) + delete rules[i]; + } + + void Meshing2 :: AddPoint (const Point3d & p, PointIndex globind, + MultiPointGeomInfo * mgi) + { + // (*testout) << "add point " << globind << endl; + adfront ->AddPoint (p, globind, mgi); + } + + void Meshing2 :: AddBoundaryElement (int i1, int i2, + const PointGeomInfo & gi1, const PointGeomInfo & gi2) + { + // (*testout) << "add line " << i1 << " - " << i2 << endl; + if (!gi1.trignum || !gi2.trignum) + { + PrintSysError ("addboundaryelement: illegal geominfo"); + } + adfront -> AddLine (i1, i2, gi1, gi2); + } + + + + void Meshing2 :: StartMesh () + { + foundmap.SetSize (rules.Size()); + canuse.SetSize (rules.Size()); + ruleused.SetSize (rules.Size()); + + foundmap = 0; + canuse = 0; + ruleused = 0; + + cntelem = 0; + trials = 0; + } + + void Meshing2 :: EndMesh () + { + for (int i = 0; i < ruleused.Size(); i++) + (*testout) << setw(4) << ruleused[i] + << " times used rule " << rules[i] -> Name() << endl; + } + + void Meshing2 :: SetStartTime (double astarttime) + { + starttime = astarttime; + } + + double Meshing2 :: CalcLocalH (const Point3d & /* p */, double gh) const + { + return gh; + } + + + + // should be class variables !!(?) + static Vec3d ex, ey; + static Point3d globp1; + + void Meshing2 :: DefineTransformation (Point3d & p1, Point3d & p2, + const PointGeomInfo * geominfo1, + const PointGeomInfo * geominfo2) + { + globp1 = p1; + ex = p2 - p1; + ex /= ex.Length(); + ey.X() = -ex.Y(); + ey.Y() = ex.X(); + ey.Z() = 0; + } + + void Meshing2 :: TransformToPlain (const Point3d & locpoint, + const MultiPointGeomInfo & geominf, + Point2d & plainpoint, double h, int & zone) + { + Vec3d p1p (globp1, locpoint); + + // p1p = locpoint - globp1; + p1p /= h; + plainpoint.X() = p1p * ex; + plainpoint.Y() = p1p * ey; + zone = 0; + } + + int Meshing2 :: TransformFromPlain (Point2d & plainpoint, + Point3d & locpoint, + PointGeomInfo & gi, + double h) + { + Vec3d p1p; + gi.trignum = 1; + + p1p = plainpoint.X() * ex + plainpoint.Y() * ey; + p1p *= h; + locpoint = globp1 + p1p; + return 0; + } + + + int Meshing2 :: BelongsToActiveChart (const Point3d & p, + const PointGeomInfo & gi) + { + return 1; + } + + + int Meshing2 :: ComputePointGeomInfo (const Point3d & p, PointGeomInfo & gi) + { + gi.trignum = 1; + return 0; + } + + + int Meshing2 :: ChooseChartPointGeomInfo (const MultiPointGeomInfo & mpgi, + PointGeomInfo & pgi) + { + pgi = mpgi.GetPGI(1); + return 0; + } + + + + int Meshing2 :: + IsLineVertexOnChart (const Point3d & p1, const Point3d & p2, + int endpoint, const PointGeomInfo & geominfo) + { + return 1; + } + + void Meshing2 :: + GetChartBoundary (ARRAY<Point2d> & points, + ARRAY<Point3d> & points3d, + ARRAY<INDEX_2> & lines, double h) const + { + points.SetSize (0); + points3d.SetSize (0); + lines.SetSize (0); + } + + double Meshing2 :: Area () const + { + return -1; + } + + + + + + MESHING2_RESULT Meshing2 :: GenerateMesh (Mesh & mesh, double gh, int facenr) + { + ARRAY<int> pindex, lindex; + ARRAY<int> delpoints, dellines; + + ARRAY<PointGeomInfo> upgeominfo; // unique info + ARRAY<MultiPointGeomInfo> mpgeominfo; // multiple info + + ARRAY<Element2d> locelements; + + int i, k, z1, z2, j, oldnp; + SurfaceElementIndex sei; + int baselineindex; + bool found; + int rulenr; + int globind; + Point3d p1, p2; + + const PointGeomInfo * blgeominfo1; + const PointGeomInfo * blgeominfo2; + + bool morerisc; + bool debugflag; + + double h, his, hshould; + + + // test for 3d overlaps + Box3dTree surfeltree (boundingbox.PMin(), + boundingbox.PMax()); + + ARRAY<int> intersecttrias; + ARRAY<Point3d> critpoints; + + // test for doubled edges + //INDEX_2_HASHTABLE<int> doubleedge(300000); + + + testmode = 0; + + StartMesh(); + + ARRAY<Point2d> chartboundpoints; + ARRAY<Point3d> chartboundpoints3d; + ARRAY<INDEX_2> chartboundlines; + + // illegal points: points with more then 50 elements per node + int maxlegalpoint, maxlegalline; + ARRAY<int,PointIndex::BASE> trigsonnode; + ARRAY<int,PointIndex::BASE> illegalpoint; + + trigsonnode.SetSize (mesh.GetNP()); + illegalpoint.SetSize (mesh.GetNP()); + + trigsonnode = 0; + illegalpoint = 0; + + + double totalarea = Area (); + double meshedarea = 0; + + // search tree for surface elements: + for (sei = 0; sei < mesh.GetNSE(); sei++) + { + const Element2d & sel = mesh[sei]; + + if (sel.IsDeleted()) continue; + + if (sel.GetIndex() == facenr) + { + const Point3d & sep1 = mesh[sel.PNum(1)]; + const Point3d & sep2 = mesh[sel.PNum(2)]; + const Point3d & sep3 = mesh[sel.PNum(3)]; + Point3d sepmin(sep1), sepmax(sep2); + sepmin.SetToMin (sep2); + sepmin.SetToMin (sep3); + sepmin.SetToMax (sep2); + sepmin.SetToMax (sep3); + + surfeltree.Insert (sepmin, sepmax, sei); + } + + + double trigarea = Cross (Vec3d (mesh.Point (sel.PNum(1)), + mesh.Point (sel.PNum(2))), + Vec3d (mesh.Point (sel.PNum(1)), + mesh.Point (sel.PNum(3)))).Length() / 2;; + + if (sel.GetNP() == 4) + trigarea += Cross (Vec3d (mesh.Point (sel.PNum(1)), + mesh.Point (sel.PNum(3))), + Vec3d (mesh.Point (sel.PNum(1)), + mesh.Point (sel.PNum(4)))).Length() / 2;; + meshedarea += trigarea; + + } + + + char * savetask = multithread.task; + multithread.task = "Surface meshing"; + + adfront ->SetStartFront (); + + + int plotnexttrial = 999; + // starttime = GetTime(); + while (!adfront ->Empty()) // && !multithread.terminate) + { + if (multithread.terminate) + throw NgException ("Meshing stopped"); + + + // known for STL meshing + if (totalarea > 0) + multithread.percent = 100 * meshedarea / totalarea; + /* + else + multithread.percent = 0; + */ + + locpoints.SetSize(0); + loclines.SetSize(0); + pindex.SetSize(0); + lindex.SetSize(0); + delpoints.SetSize(0); + dellines.SetSize(0); + locelements.SetSize(0); + + + + // plot statistics + if (trials > plotnexttrial) + { + PrintMessage (5, + "faces = ", nfaces, + " trials = ", trials, + " elements = ", mesh.GetNSE(), + " els/sec = ", + (mesh.GetNSE() / (GetTime() - starttime + 0.0001))); + plotnexttrial += 1000; + } + + + // unique-pgi, multi-pgi + upgeominfo.SetSize(0); + mpgeominfo.SetSize(0); + + + nfaces = adfront->GetNFL(); + trials ++; + + + if (trials % 1000 == 0) + { + (*testout) << "\n"; + for (i = 1; i <= canuse.Size(); i++) + { + (*testout) << foundmap.Get(i) << "/" + << canuse.Get(i) << "/" + << ruleused.Get(i) << " map/can/use rule " << rules.Get(i)->Name() << "\n"; + } + (*testout) << "\n"; + } + + + baselineindex = adfront -> SelectBaseLine (p1, p2, blgeominfo1, blgeominfo2, qualclass); + + // cout << "baseline = " << baselineindex << ", p1, p2 = " << p1 << ", " << p2 << endl; + + found = 1; + + + his = Dist (p1, p2); + + Point3d pmid = Center (p1, p2); + hshould = CalcLocalH (pmid, mesh.GetH (pmid)); + if (gh < hshould) + hshould = gh; + + mesh.RestrictLocalH (pmid, hshould); + + h = hshould; + + double hinner = (3 + qualclass) * max2 (his, hshould); + + adfront ->GetLocals (baselineindex, locpoints, mpgeominfo, loclines, + pindex, lindex, 2*hinner); + + + if (qualclass > 200) + { + PrintMessage (3, "give up with qualclass ", qualclass); + PrintMessage (3, "number of frontlines = ", adfront->GetNFL()); + // throw NgException ("Give up 2d meshing"); + break; + } + + /* + if (found && qualclass > 60) + { + found = 0; + } + */ + // morerisc = ((qualclass > 20) && (qualclass % 2 == 1)); + // morerisc = 1; + morerisc = 0; + + + PointIndex gpi1 = adfront -> GetGlobalIndex (pindex.Get(loclines[0].I1())); + PointIndex gpi2 = adfront -> GetGlobalIndex (pindex.Get(loclines[0].I2())); + + + debugflag = + debugparam.haltsegment && + ( (debugparam.haltsegmentp1 == gpi1) && + (debugparam.haltsegmentp2 == gpi2) || + (debugparam.haltsegmentp1 == gpi2) && + (debugparam.haltsegmentp2 == gpi1)) || + debugparam.haltnode && + ( (debugparam.haltsegmentp1 == gpi1) || + (debugparam.haltsegmentp2 == gpi1)); + + + if (debugparam.haltface && debugparam.haltfacenr == facenr) + { + debugflag = 1; + cout << "set debugflag" << endl; + } + + if (debugparam.haltlargequalclass && qualclass > 50) + debugflag = 1; + + + // problem recognition ! + if (found && + (gpi1 < illegalpoint.Size()+PointIndex::BASE) && + (gpi2 < illegalpoint.Size()+PointIndex::BASE) ) + { + if (illegalpoint[gpi1] || illegalpoint[gpi2]) + found = 0; + } + + + Point2d p12d, p22d; + + if (found) + { + oldnp = locpoints.Size(); + oldnl = loclines.Size(); + + if (debugflag) + (*testout) << "define new transformation" << endl; + + DefineTransformation (p1, p2, blgeominfo1, blgeominfo2); + + plainpoints.SetSize (locpoints.Size()); + plainzones.SetSize (locpoints.Size()); + + // (*testout) << endl; + + // (*testout) << "3d->2d transformation" << endl; + + for (i = 1; i <= locpoints.Size(); i++) + { + // (*testout) << "pindex(i) = " << pindex[i-1] << endl; + TransformToPlain (locpoints.Get(i), + mpgeominfo.Get(i), + plainpoints.Elem(i), h, plainzones.Elem(i)); + // (*testout) << mpgeominfo.Get(i).GetPGI(1).u << " " << mpgeominfo.Get(i).GetPGI(1).v << " "; + // (*testout) << plainpoints.Get(i).X() << " " << plainpoints.Get(i).Y() << endl; + } + // (*testout) << endl << endl << 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 (i = 2; i <= loclines.Size(); i++) // don't remove first line + { + // (*testout) << "loclines(i) = " << loclines.Get(i).I1() << " - " << loclines.Get(i).I2() << endl; + z1 = plainzones.Get(loclines.Get(i).I1()); + z2 = plainzones.Get(loclines.Get(i).I2()); + + + // one inner point, one outer + if ( (z1 >= 0) != (z2 >= 0)) + { + int innerp = (z1 >= 0) ? 1 : 2; + if (IsLineVertexOnChart (locpoints.Get(loclines.Get(i).I1()), + locpoints.Get(loclines.Get(i).I2()), + innerp, + adfront->GetLineGeomInfo (lindex.Get(i), innerp))) + // pgeominfo.Get(loclines.Get(i).I(innerp)))) + { + + if (!morerisc) + { + // use one end of line + int pini, pouti; + Vec2d v; + + pini = loclines.Get(i).I(innerp); + pouti = loclines.Get(i).I(3-innerp); + + Point2d pin (plainpoints.Get(pini)); + Point2d pout (plainpoints.Get(pouti)); + v = pout - pin; + double len = v.Length(); + if (len <= 1e-6) + (*testout) << "WARNING(js): inner-outer: short vector" << endl; + else + v /= len; + + /* + // don't elongate line towards base-line !! + if (Vec2d (pin, p12d) * v > 0 && + Vec2d (pin, p22d) * v > 0) + v *= -1; + */ + + Point2d newpout = pin + 1000 * v; + newpout = pout; + + + plainpoints.Append (newpout); + Point3d pout3d = locpoints.Get(pouti); + locpoints.Append (pout3d); + + plainzones.Append (0); + pindex.Append (0); + oldnp++; + loclines.Elem(i).I(3-innerp) = oldnp; + } + else + plainzones.Elem(loclines.Get(i).I(3-innerp)) = 0; + + + // (*testout) << "inner - outer correction" << endl; + } + else + { + // remove line + loclines.DeleteElement(i); + lindex.DeleteElement(i); + oldnl--; + i--; + } + } + + else if (z1 > 0 && z2 > 0 && (z1 != z2) || (z1 < 0) && (z2 < 0) ) + { + loclines.DeleteElement(i); + lindex.DeleteElement(i); + oldnl--; + i--; + } + } + + + + + + legalpoints.SetSize(plainpoints.Size()); + for (i = 1; i <= legalpoints.Size(); i++) + legalpoints.Elem(i) = 1; + + + for (i = 1; i <= plainpoints.Size(); i++) + { + if (plainzones.Elem(i) < 0) + { + plainpoints.Elem(i) = Point2d (1e4, 1e4); + legalpoints.Elem(i) = 0; + } + if (pindex.Elem(i) == 0) + legalpoints.Elem(i) = 0; + + if (plainpoints.Elem(i).Y() < 0) + legalpoints.Elem(i) = 0; + } + /* + for (i = 3; i <= plainpoints.Size(); i++) + if (sqr (plainpoints.Get(i).X()) + sqr (plainpoints.Get(i).Y()) + > sqr (2 + 0.2 * qualclass)) + legalpoints.Elem(i) = 0; + */ + + /* + int clp = 0; + for (i = 1; i <= plainpoints.Size(); i++) + if (legalpoints.Get(i)) + clp++; + (*testout) << "legalpts: " << clp << "/" << plainpoints.Size() << endl; + + // sort legal/illegal lines + int lastleg = 2; + int firstilleg = oldnl; + + while (lastleg < firstilleg) + { + while (legalpoints.Get(loclines.Get(lastleg).I1()) && + legalpoints.Get(loclines.Get(lastleg).I2()) && + lastleg < firstilleg) + lastleg++; + while ( ( !legalpoints.Get(loclines.Get(firstilleg).I1()) || + !legalpoints.Get(loclines.Get(firstilleg).I2())) && + lastleg < firstilleg) + firstilleg--; + + if (lastleg < firstilleg) + { + swap (loclines.Elem(lastleg), loclines.Elem(firstilleg)); + swap (lindex.Elem(lastleg), lindex.Elem(firstilleg)); + } + } + + (*testout) << "leglines " << lastleg << "/" << oldnl << endl; + */ + + + GetChartBoundary (chartboundpoints, + chartboundpoints3d, + chartboundlines, h); + + oldnp = plainpoints.Size(); + + maxlegalpoint = locpoints.Size(); + maxlegalline = loclines.Size(); + + + + if (mparam.checkchartboundary) + { + for (i = 1; i <= chartboundpoints.Size(); i++) + { + plainpoints.Append (chartboundpoints.Get(i)); + locpoints.Append (chartboundpoints3d.Get(i)); + legalpoints.Append (0); + } + + + for (i = 1; i <= chartboundlines.Size(); i++) + { + INDEX_2 line (chartboundlines.Get(i).I1()+oldnp, + chartboundlines.Get(i).I2()+oldnp); + loclines.Append (line); + // (*testout) << "line: " << line.I1() << "-" << line.I2() << endl; + } + } + + oldnl = loclines.Size(); + oldnp = plainpoints.Size(); + } + + + /* + if (qualclass > 100) + { + multithread.drawing = 1; + glrender(1); + cout << "qualclass 100, nfl = " << adfront->GetNFL() << endl; + } + */ + + if (found) + { + rulenr = ApplyRules (plainpoints, legalpoints, maxlegalpoint, + loclines, maxlegalline, locelements, + dellines, qualclass); + // (*testout) << "Rule Nr = " << rulenr << endl; + if (!rulenr) + { + found = 0; + if ( debugflag || debugparam.haltnosuccess ) + PrintWarning ("no rule found"); + } + } + + for (i = 1; i <= locelements.Size() && found; i++) + { + const Element2d & el = locelements.Get(i); + + for (j = 1; j <= el.GetNP(); j++) + if (el.PNum(j) <= oldnp && !pindex.Get(el.PNum(j))) + { + found = 0; + PrintSysError ("meshing2, index missing"); + } + } + + + if (found) + { + locpoints.SetSize (plainpoints.Size()); + upgeominfo.SetSize(locpoints.Size()); + + for (i = oldnp+1; i <= plainpoints.Size(); i++) + { + int err = + TransformFromPlain (plainpoints.Elem(i), locpoints.Elem(i), + upgeominfo.Elem(i), h); + + if (err) + { + found = 0; + + if ( debugflag || debugparam.haltnosuccess ) + PrintSysError ("meshing2, Backtransformation failed"); + + break; + } + } + } + + + // for (i = 1; i <= oldnl; i++) + // adfront -> ResetClass (lindex[i]); + + + /* + double violateminh; + if (qualclass <= 10) + violateminh = 3; + else + violateminh = 3 * qualclass; + + if (uselocalh && found) // && qualclass <= 10) + { + for (i = 1; i <= locelements.Size(); i++) + { + Point3d pmin = locpoints.Get(locelements.Get(i).PNum(1)); + Point3d pmax = pmin; + for (j = 2; j <= 3; j++) + { + const Point3d & hp = + locpoints.Get(locelements.Get(i).PNum(j)); + pmin.SetToMin (hp); + pmax.SetToMax (hp); + } + double minh = mesh.GetMinH (pmin, pmax); + if (h > violateminh * minh) + { + found = 0; + loclines.SetSize (oldnl); + locpoints.SetSize (oldnp); + } + } + } + */ + + + if (found) + { + double violateminh = 3 + 0.1 * sqr (qualclass); + double minh = 1e8; + double newedgemaxh = 0; + for (i = oldnl+1; i <= loclines.Size(); i++) + { + double eh = Dist (locpoints.Get(loclines.Get(i).I1()), + locpoints.Get(loclines.Get(i).I2())); + if (eh > newedgemaxh) + newedgemaxh = eh; + } + + for (i = 1; i <= locelements.Size(); i++) + { + Point3d pmin = locpoints.Get(locelements.Get(i).PNum(1)); + Point3d pmax = pmin; + for (j = 2; j <= locelements.Get(i).GetNP(); j++) + { + const Point3d & hp = + locpoints.Get(locelements.Get(i).PNum(j)); + pmin.SetToMin (hp); + pmax.SetToMax (hp); + } + double eh = mesh.GetMinH (pmin, pmax); + if (eh < minh) + minh = eh; + } + + for (i = 1; i <= locelements.Size(); i++) + for (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 (i = 1; i <= locelements.Size(); i++) + for (j = 1; j <= locelements.Get(i).GetNP(); j++) + { + int pi = locelements.Get(i).PNum(j); + if (pi <= oldnp) + { + + if (ChooseChartPointGeomInfo (mpgeominfo.Get(pi), upgeominfo.Elem(pi))) + { + // cannot select, compute new one + PrintWarning ("calc point geominfo instead of using"); + if (ComputePointGeomInfo (locpoints.Get(pi), upgeominfo.Elem(pi))) + { + found = 0; + PrintSysError ("meshing2d, geominfo failed"); + } + } + } + } + + /* + // use upgeominfo from ProjectFromPlane + for (i = oldnp+1; i <= locpoints.Size(); i++) + { + if (ComputePointGeomInfo (locpoints.Get(i), upgeominfo.Elem(i))) + { + found = 0; + if ( debugflag || debugparam.haltnosuccess ) + PrintSysError ("meshing2d, compute geominfo failed"); + } + } + */ + } + + + if (found && mparam.checkoverlap) + { + // cout << "checkoverlap" << endl; + // test for overlaps + + Point3d hullmin(1e10, 1e10, 1e10); + Point3d hullmax(-1e10, -1e10, -1e10); + + for (i = 1; i <= locelements.Size(); i++) + for (j = 1; j <= locelements.Get(i).GetNP(); j++) + { + const Point3d & p = locpoints.Get(locelements.Get(i).PNum(j)); + hullmin.SetToMin (p); + hullmax.SetToMax (p); + } + hullmin += Vec3d (-his, -his, -his); + hullmax += Vec3d ( his, his, his); + + surfeltree.GetIntersecting (hullmin, hullmax, intersecttrias); + + critpoints.SetSize (0); + for (i = oldnp+1; i <= locpoints.Size(); i++) + critpoints.Append (locpoints.Get(i)); + + for (i = 1; i <= locelements.Size(); i++) + { + const Element2d & tri = locelements.Get(i); + if (tri.GetNP() == 3) + { + const Point3d & tp1 = locpoints.Get(tri.PNum(1)); + const Point3d & tp2 = locpoints.Get(tri.PNum(2)); + const Point3d & tp3 = locpoints.Get(tri.PNum(3)); + + Vec3d tv1 (tp1, tp2); + Vec3d tv2 (tp1, tp3); + + double lam1, lam2; + for (lam1 = 0.2; lam1 <= 0.8; lam1 += 0.2) + for (lam2 = 0.2; lam2 + lam1 <= 0.8; lam2 += 0.2) + { + Point3d hp = tp1 + lam1 * tv1 + lam2 * tv2; + critpoints.Append (hp); + } + } + else if (tri.GetNP() == 4) + { + const Point3d & tp1 = locpoints.Get(tri.PNum(1)); + const Point3d & tp2 = locpoints.Get(tri.PNum(2)); + const Point3d & tp3 = locpoints.Get(tri.PNum(3)); + const Point3d & tp4 = locpoints.Get(tri.PNum(4)); + + double l1, l2; + for (l1 = 0.1; l1 <= 0.9; l1 += 0.1) + for (l2 = 0.1; l2 <= 0.9; l2 += 0.1) + { + Point3d hp; + hp.X() = + (1-l1)*(1-l2) * tp1.X() + + l1*(1-l2) * tp2.X() + + l1*l2 * tp3.X() + + (1-l1)*l2 * tp4.X(); + hp.Y() = + (1-l1)*(1-l2) * tp1.Y() + + l1*(1-l2) * tp2.Y() + + l1*l2 * tp3.Y() + + (1-l1)*l2 * tp4.Y(); + hp.Z() = + (1-l1)*(1-l2) * tp1.Z() + + l1*(1-l2) * tp2.Z() + + l1*l2 * tp3.Z() + + (1-l1)*l2 * tp4.Z(); + + + critpoints.Append (hp); + } + } + } + /* + for (i = oldnl+1; i <= loclines.Size(); i++) + { + Point3d hp = locpoints.Get(loclines.Get(i).I1()); + Vec3d hv(hp, locpoints.Get(loclines.Get(i).I2())); + int ncp = 2; + for (j = 1; j <= ncp; j++) + critpoints.Append ( hp + (double(j)/(ncp+1)) * hv); + } + */ + + + /* + for (i = oldnp+1; i <= locpoints.Size(); i++) + { + const Point3d & p = locpoints.Get(i); + */ + + + for (i = 1; i <= critpoints.Size(); i++) + { + const Point3d & p = critpoints.Get(i); + + + /* + for (j = 1; j <= mesh.GetNSE(); j++) + { + */ + int jj; + for (jj = 1; jj <= intersecttrias.Size(); jj++) + { + j = intersecttrias.Get(jj); + const Element2d & el = mesh.SurfaceElement(j); + + int ntrig = (el.GetNP() == 3) ? 1 : 2; + + int jl; + for (jl = 1; jl <= ntrig; jl++) + { + Point3d tp1, tp2, tp3; + + if (jl == 1) + { + tp1 = mesh.Point(el.PNum(1)); + tp2 = mesh.Point(el.PNum(2)); + tp3 = mesh.Point(el.PNum(3)); + } + else + { + tp1 = mesh.Point(el.PNum(1)); + tp2 = mesh.Point(el.PNum(3)); + tp3 = mesh.Point(el.PNum(4)); + } + + int onchart = 0; + for (k = 1; k <= el.GetNP(); k++) + if (BelongsToActiveChart (mesh.Point(el.PNum(k)), + el.GeomInfoPi(k))) + onchart = 1; + if (!onchart) + continue; + + Vec3d e1(tp1, tp2); + Vec3d e2(tp1, tp3); + Vec3d n = Cross (e1, e2); + n /= n.Length(); + double lam1, lam2, lam3; + lam3 = n * Vec3d (tp1, p); + LocalCoordinates (e1, e2, Vec3d (tp1, p), lam1, lam2); + + if (fabs (lam3) < 0.1 * hshould && + lam1 > 0 && lam2 > 0 && (lam1 + lam2) < 1) + { +#ifdef DEVELOP + cout << "overlap" << endl; + (*testout) << "overlap:" << endl + << "tri = " << tp1 << "-" << tp2 << "-" << tp3 << endl + << "point = " << p << endl + << "lam1, 2 = " << lam1 << ", " << lam2 << endl + << "lam3 = " << lam3 << endl; + + // cout << "overlap !!!" << endl; +#endif + for (int k = 1; k <= 5; k++) + adfront -> IncrementClass (lindex.Get(1)); + + found = 0; + + if ( debugflag || debugparam.haltnosuccess ) + PrintWarning ("overlapping"); + + + if (debugparam.haltoverlap) + { + debugflag = 1; + } + + /* + multithread.drawing = 1; + glrender(1); + */ + } + } + } + } + } + + + if (found) + { + // check, whether new front line already exists + + for (i = oldnl+1; i <= loclines.Size(); i++) + { + int nlgpi1 = loclines.Get(i).I1(); + int nlgpi2 = loclines.Get(i).I2(); + if (nlgpi1 <= pindex.Size() && nlgpi2 <= pindex.Size()) + { + nlgpi1 = adfront->GetGlobalIndex (pindex.Get(nlgpi1)); + nlgpi2 = adfront->GetGlobalIndex (pindex.Get(nlgpi2)); + + int exval = adfront->ExistsLine (nlgpi1, nlgpi2); + if (exval) + { + cout << "ERROR: new line exits, val = " << exval << endl; + (*testout) << "ERROR: new line exits, val = " << exval << endl; + found = 0; + + + if (debugparam.haltexistingline) + debugflag = 1; + + } + } + } + + } + + + /* + if (found) + { + // check, whether new triangles insert edges twice + for (i = 1; i <= locelements.Size(); i++) + for (j = 1; j <= 3; j++) + { + int tpi1 = locelements.Get(i).PNumMod (j); + int tpi2 = locelements.Get(i).PNumMod (j+1); + if (tpi1 <= pindex.Size() && tpi2 <= pindex.Size()) + { + tpi1 = adfront->GetGlobalIndex (pindex.Get(tpi1)); + tpi2 = adfront->GetGlobalIndex (pindex.Get(tpi2)); + + if (doubleedge.Used (INDEX_2(tpi1, tpi2))) + { + if (debugparam.haltexistingline) + debugflag = 1; + cerr << "ERROR Insert edge " + << tpi1 << " - " << tpi2 << " twice !!!" << endl; + found = 0; + } + doubleedge.Set (INDEX_2(tpi1, tpi2), 1); + } + } + } + */ + + + if (found) + { + // everything is ok, perform mesh update + + ruleused.Elem(rulenr)++; + + + pindex.SetSize(locpoints.Size()); + + for (i = oldnp+1; i <= locpoints.Size(); i++) + { + globind = mesh.AddPoint (locpoints.Get(i)); + pindex.Elem(i) = adfront -> AddPoint (locpoints.Get(i), globind); + } + + for (i = oldnl+1; i <= loclines.Size(); i++) + { + /* + for (j = 1; j <= locpoints.Size(); j++) + { + (*testout) << j << ": " << locpoints.Get(j) << endl; + } + */ + + /* + ComputeLineGeoInfo (locpoints.Get(loclines.Get(i).I1()), + locpoints.Get(loclines.Get(i).I2()), + gisize, geominfo); + */ + + if (pindex.Get(loclines.Get(i).I1()) == 0 || + pindex.Get(loclines.Get(i).I2()) == 0) + { + (*testout) << "pindex is 0" << endl; + } + + if (!upgeominfo.Get(loclines.Get(i).I1()).trignum || + !upgeominfo.Get(loclines.Get(i).I2()).trignum) + { + cout << "new el: illegal geominfo" << endl; + } + + adfront -> AddLine (pindex.Get(loclines.Get(i).I1()), + pindex.Get(loclines.Get(i).I2()), + upgeominfo.Get(loclines.Get(i).I1()), + upgeominfo.Get(loclines.Get(i).I2())); + } + for (i = 1; i <= locelements.Size(); i++) + { + Element2d mtri(locelements.Get(i).GetNP()); + mtri = locelements.Get(i); + mtri.SetIndex (facenr); + + + // compute triangle geominfo: + // (*testout) << "triggeominfo: "; + for (j = 1; j <= locelements.Get(i).GetNP(); j++) + { + mtri.GeomInfoPi(j) = upgeominfo.Get(locelements.Get(i).PNum(j)); + // (*testout) << mtri.GeomInfoPi(j).trignum << " "; + } + // (*testout) << endl; + + for (j = 1; j <= locelements.Get(i).GetNP(); j++) + { + mtri.PNum(j) = + locelements.Elem(i).PNum(j) = + adfront -> GetGlobalIndex (pindex.Get(locelements.Get(i).PNum(j))); + } + + + + + mesh.AddSurfaceElement (mtri); + cntelem++; + // cout << "elements: " << cntelem << endl; + + + + + const Point3d & sep1 = mesh.Point (mtri.PNum(1)); + const Point3d & sep2 = mesh.Point (mtri.PNum(2)); + const Point3d & sep3 = mesh.Point (mtri.PNum(3)); + + Point3d sepmin(sep1), sepmax(sep1); + for (j = 2; j <= mtri.GetNP(); j++) + { + sepmin.SetToMin (mesh.Point (mtri.PNum(j))); + sepmax.SetToMax (mesh.Point (mtri.PNum(j))); + } + + surfeltree.Insert (sepmin, sepmax, mesh.GetNSE()); + + + double trigarea = Cross (Vec3d (sep1, sep2), + Vec3d (sep1, sep3)).Length() / 2; + + if (mtri.GetNP() == 4) + { + const Point3d & sep4 = mesh.Point (mtri.PNum(4)); + trigarea += Cross (Vec3d (sep1, sep3), + Vec3d (sep1, sep4)).Length() / 2; + } + + meshedarea += trigarea; + + + + + for (j = 1; j <= locelements.Get(i).GetNP(); j++) + { + int gpi = locelements.Get(i).PNum(j); + + int oldts = trigsonnode.Size(); + if (gpi >= oldts+PointIndex::BASE) + { + trigsonnode.SetSize (gpi+1-PointIndex::BASE); + illegalpoint.SetSize (gpi+1-PointIndex::BASE); + for (k = oldts+PointIndex::BASE; + k <= gpi; k++) + { + trigsonnode[k] = 0; + illegalpoint[k] = 0; + } + } + + trigsonnode[gpi]++; + + if (trigsonnode[gpi] > 20) + { + illegalpoint[gpi] = 1; + // cout << "illegal point: " << gpi << endl; + (*testout) << "illegal point: " << gpi << endl; + } + + static int mtonnode = 0; + if (trigsonnode[gpi] > mtonnode) + mtonnode = trigsonnode[gpi]; + } + // cout << "els = " << cntelem << " trials = " << trials << endl; + // if (trials > 100) return; + } + + for (i = 1; i <= dellines.Size(); i++) + adfront -> DeleteLine (lindex.Get(dellines.Get(i))); + + // rname = rules.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 ) + { + cout << "success of rule" << rules.Get(rulenr)->Name() << endl; + multithread.drawing = 1; + multithread.testmode = 1; + multithread.pause = 1; + + + /* + extern STLGeometry * stlgeometry; + stlgeometry->ClearMarkedSegs(); + for (i = 1; i <= loclines.Size(); i++) + { + stlgeometry->AddMarkedSeg(locpoints.Get(loclines.Get(i).I1()), + locpoints.Get(loclines.Get(i).I2())); + } + */ + + (*testout) << "success of rule" << rules.Get(rulenr)->Name() << endl; + (*testout) << "trials = " << trials << endl; + + (*testout) << "old number of lines = " << oldnl << endl; + for (i = 1; i <= loclines.Size(); i++) + { + (*testout) << "line "; + for (j = 1; j <= 2; j++) + { + int hi = 0; + if (loclines.Get(i).I(j) >= 1 && + loclines.Get(i).I(j) <= pindex.Size()) + hi = adfront->GetGlobalIndex (pindex.Get(loclines.Get(i).I(j))); + + (*testout) << hi << " "; + } + (*testout) << " : " + << plainpoints.Get(loclines.Get(i).I1()) << " - " + << plainpoints.Get(loclines.Get(i).I2()) << " 3d: " + << locpoints.Get(loclines.Get(i).I1()) << " - " + << locpoints.Get(loclines.Get(i).I2()) + << endl; + } + + + + 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 (i = 1; i <= loclines.Size(); i++) + { + (*testout) << "line "; + for (j = 1; j <= 2; j++) + { + int hi = 0; + if (loclines.Get(i).I(j) >= 1 && + loclines.Get(i).I(j) <= pindex.Size()) + hi = adfront->GetGlobalIndex (pindex.Get(loclines.Get(i).I(j))); + + (*testout) << hi << " "; + } + (*testout) << " : " + << plainpoints.Get(loclines.Get(i).I1()) << " - " + << plainpoints.Get(loclines.Get(i).I2()) << " 3d: " + << locpoints.Get(loclines.Get(i).I1()) << " - " + << locpoints.Get(loclines.Get(i).I2()) + << endl; + } + + + /* + cout << "p1gi = " << blgeominfo[0].trignum + << ", p2gi = " << blgeominfo[1].trignum << endl; + */ + + glrender(1); + } + + +#ifdef MYGRAPH + if (silentflag<3) + { + if (testmode || trials%2 == 0) + { + plotsurf.DrawPnL(locpoints, loclines); + plotsurf.Plot(testmode, testmode); + } + } +#endif + } + + } + + PrintMessage (3, "Surface meshing done"); + + adfront->PrintOpenSegments (*testout); + + multithread.task = savetask; + + + // cout << "surfeltree.depth = " << surfeltree.Tree().Depth() << endl; + EndMesh (); + + if (!adfront->Empty()) + return MESHING2_GIVEUP; + + return MESHING2_OK; + } + + + + + + + + + +} + + + + + + + +#ifdef OPENGL + +/* *********************** Draw Surface Meshing **************** */ + + +#include <visual.hpp> +#include <stlgeom.hpp> + +namespace netgen +{ + + extern STLGeometry * stlgeometry; + extern Mesh * mesh; + VisualSceneSurfaceMeshing vssurfacemeshing; + + + + void glrender (int wait) + { + // cout << "plot adfront" << endl; + + if (multithread.drawing) + { + // vssurfacemeshing.Render(); + Render (); + + if (wait || multithread.testmode) + { + multithread.pause = 1; + } + while (multithread.pause); + } + } + + + + VisualSceneSurfaceMeshing :: VisualSceneSurfaceMeshing () + : VisualScene() + { + ; + } + + VisualSceneSurfaceMeshing :: ~VisualSceneSurfaceMeshing () + { + ; + } + + void VisualSceneSurfaceMeshing :: DrawScene () + { + int i, j, k; + + if (loclines.Size() != changeval) + { + center = Point<3>(0,0,-5); + rad = 0.1; + + CalcTransformationMatrices(); + changeval = loclines.Size(); + } + + glClearColor(backcolor, backcolor, backcolor, 1.0); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + SetLight(); + + // glEnable (GL_COLOR_MATERIAL); + + // glDisable (GL_SHADING); + // glColor3f (0.0f, 1.0f, 1.0f); + // glLineWidth (1.0f); + // glShadeModel (GL_SMOOTH); + + // glCallList (linelists.Get(1)); + + // SetLight(); + + glPushMatrix(); + glMultMatrixf (transformationmat); + + glShadeModel (GL_SMOOTH); + glDisable (GL_COLOR_MATERIAL); + glPolygonMode (GL_FRONT_AND_BACK, GL_FILL); + + glEnable (GL_BLEND); + glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + // glEnable (GL_LIGHTING); + + double shine = vispar.shininess; + double transp = vispar.transp; + + glMaterialf (GL_FRONT_AND_BACK, GL_SHININESS, shine); + glLogicOp (GL_COPY); + + + + /* + + float mat_col[] = { 0.2, 0.2, 0.8, 1 }; + glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, mat_col); + + glPolygonOffset (1, 1); + glEnable (GL_POLYGON_OFFSET_FILL); + + float mat_colbl[] = { 0.8, 0.2, 0.2, 1 }; + float mat_cololdl[] = { 0.2, 0.8, 0.2, 1 }; + float mat_colnewl[] = { 0.8, 0.8, 0.2, 1 }; + + + glPolygonMode (GL_FRONT_AND_BACK, GL_FILL); + glPolygonOffset (1, -1); + glLineWidth (3); + + for (i = 1; i <= loclines.Size(); i++) + { + if (i == 1) + { + glEnable (GL_POLYGON_OFFSET_FILL); + glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, mat_colbl); + } + else if (i <= oldnl) + glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, mat_cololdl); + else + glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, mat_colnewl); + + int pi1 = loclines.Get(i).I1(); + int pi2 = loclines.Get(i).I2(); + + if (pi1 >= 1 && pi2 >= 1) + { + Point3d p1 = locpoints.Get(pi1); + Point3d p2 = locpoints.Get(pi2); + + glBegin (GL_LINES); + glVertex3f (p1.X(), p1.Y(), p1.Z()); + glVertex3f (p2.X(), p2.Y(), p2.Z()); + glEnd(); + } + + glDisable (GL_POLYGON_OFFSET_FILL); + } + + + glLineWidth (1); + + + glPointSize (5); + float mat_colp[] = { 1, 0, 0, 1 }; + glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, mat_colp); + glBegin (GL_POINTS); + for (i = 1; i <= locpoints.Size(); i++) + { + Point3d p = locpoints.Get(i); + glVertex3f (p.X(), p.Y(), p.Z()); + } + glEnd(); + + + glPopMatrix(); + */ + + float mat_colp[] = { 1, 0, 0, 1 }; + + float mat_col2d1[] = { 1, 0.5, 0.5, 1 }; + float mat_col2d[] = { 1, 1, 1, 1 }; + glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, mat_col2d); + + double scalex = 0.1, scaley = 0.1; + + glBegin (GL_LINES); + for (i = 1; i <= loclines.Size(); i++) + { + glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, mat_col2d); + if (i == 1) + glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, mat_col2d1); + + int pi1 = loclines.Get(i).I1(); + int pi2 = loclines.Get(i).I2(); + + if (pi1 >= 1 && pi2 >= 1) + { + Point2d p1 = plainpoints.Get(pi1); + Point2d p2 = plainpoints.Get(pi2); + + glBegin (GL_LINES); + glVertex3f (scalex * p1.X(), scaley * p1.Y(), -5); + glVertex3f (scalex * p2.X(), scaley * p2.Y(), -5); + glEnd(); + } + } + glEnd (); + + + glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, mat_colp); + glBegin (GL_POINTS); + for (i = 1; i <= plainpoints.Size(); i++) + { + Point2d p = plainpoints.Get(i); + glVertex3f (scalex * p.X(), scaley * p.Y(), -5); + } + glEnd(); + + + + + + + glDisable (GL_POLYGON_OFFSET_FILL); + + glPopMatrix(); + DrawCoordinateCross (); + DrawNetgenLogo (); + glFinish(); + + /* + glDisable (GL_POLYGON_OFFSET_FILL); + + // cout << "draw surfacemeshing" << endl; + // + // if (changeval != stlgeometry->GetNT()) + // BuildScene(); + // changeval = stlgeometry->GetNT(); + + + glClearColor(backcolor, backcolor, backcolor, 1.0); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + SetLight(); + + glPushMatrix(); + glLoadMatrixf (transmat); + glMultMatrixf (rotmat); + + glShadeModel (GL_SMOOTH); + glDisable (GL_COLOR_MATERIAL); + glPolygonMode (GL_FRONT_AND_BACK, GL_FILL); + + glEnable (GL_BLEND); + glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + float mat_spec_col[] = { 1, 1, 1, 1 }; + glMaterialfv (GL_FRONT_AND_BACK, GL_SPECULAR, mat_spec_col); + + double shine = vispar.shininess; + double transp = vispar.transp; + + glMaterialf (GL_FRONT_AND_BACK, GL_SHININESS, shine); + glLogicOp (GL_COPY); + + + float mat_col[] = { 0.2, 0.2, 0.8, transp }; + float mat_colrt[] = { 0.2, 0.8, 0.8, transp }; + glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, mat_col); + + glPolygonOffset (1, 1); + glEnable (GL_POLYGON_OFFSET_FILL); + + glColor3f (1.0f, 1.0f, 1.0f); + + glEnable (GL_NORMALIZE); + + // glBegin (GL_TRIANGLES); + // for (j = 1; j <= stlgeometry -> GetNT(); j++) + // { + // glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, mat_col); + // if (j == geomtrig) + // glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, mat_colrt); + + + // const STLReadTriangle & tria = stlgeometry -> GetReadTriangle(j); + // glNormal3f (tria.normal.X(), + // tria.normal.Y(), + // tria.normal.Z()); + + // for (k = 0; k < 3; k++) + // { + // glVertex3f (tria.pts[k].X(), + // tria.pts[k].Y(), + // tria.pts[k].Z()); + // } + // } + // glEnd (); + + + + glDisable (GL_POLYGON_OFFSET_FILL); + + float mat_colbl[] = { 0.8, 0.2, 0.2, 1 }; + float mat_cololdl[] = { 0.2, 0.8, 0.2, 1 }; + float mat_colnewl[] = { 0.8, 0.8, 0.2, 1 }; + + + glPolygonMode (GL_FRONT_AND_BACK, GL_FILL); + glPolygonOffset (1, -1); + glLineWidth (3); + + for (i = 1; i <= loclines.Size(); i++) + { + if (i == 1) + { + glEnable (GL_POLYGON_OFFSET_FILL); + glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, mat_colbl); + } + else if (i <= oldnl) + glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, mat_cololdl); + else + glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, mat_colnewl); + + int pi1 = loclines.Get(i).I1(); + int pi2 = loclines.Get(i).I2(); + + if (pi1 >= 1 && pi2 >= 1) + { + Point3d p1 = locpoints.Get(pi1); + Point3d p2 = locpoints.Get(pi2); + + glBegin (GL_LINES); + glVertex3f (p1.X(), p1.Y(), p1.Z()); + glVertex3f (p2.X(), p2.Y(), p2.Z()); + glEnd(); + } + + glDisable (GL_POLYGON_OFFSET_FILL); + } + + + glLineWidth (1); + + + glPointSize (5); + float mat_colp[] = { 1, 0, 0, 1 }; + glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, mat_colp); + glBegin (GL_POINTS); + for (i = 1; i <= locpoints.Size(); i++) + { + Point3d p = locpoints.Get(i); + glVertex3f (p.X(), p.Y(), p.Z()); + } + glEnd(); + + + glPopMatrix(); + + + float mat_col2d1[] = { 1, 0.5, 0.5, 1 }; + float mat_col2d[] = { 1, 1, 1, 1 }; + glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, mat_col2d); + + double scalex = 0.1, scaley = 0.1; + + glBegin (GL_LINES); + for (i = 1; i <= loclines.Size(); i++) + { + glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, mat_col2d); + if (i == 1) + glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, mat_col2d1); + + int pi1 = loclines.Get(i).I1(); + int pi2 = loclines.Get(i).I2(); + + if (pi1 >= 1 && pi2 >= 1) + { + Point2d p1 = plainpoints.Get(pi1); + Point2d p2 = plainpoints.Get(pi2); + + glBegin (GL_LINES); + glVertex3f (scalex * p1.X(), scaley * p1.Y(), -5); + glVertex3f (scalex * p2.X(), scaley * p2.Y(), -5); + glEnd(); + } + } + glEnd (); + + + glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, mat_colp); + glBegin (GL_POINTS); + for (i = 1; i <= plainpoints.Size(); i++) + { + Point2d p = plainpoints.Get(i); + glVertex3f (scalex * p.X(), scaley * p.Y(), -5); + } + glEnd(); + + glFinish(); +*/ + } + + + void VisualSceneSurfaceMeshing :: BuildScene (int zoomall) + { + int i, j, k; + /* + center = stlgeometry -> GetBoundingBox().Center(); + rad = stlgeometry -> GetBoundingBox().Diam() / 2; + + CalcTransformationMatrices(); + */ + } + +} + + +#else +namespace netgen +{ + void glrender (int wait) + { ; } +} +#endif diff --git a/contrib/Netgen/libsrc/meshing/meshing2.hpp b/contrib/Netgen/libsrc/meshing/meshing2.hpp new file mode 100644 index 0000000000..a68a095d5e --- /dev/null +++ b/contrib/Netgen/libsrc/meshing/meshing2.hpp @@ -0,0 +1,149 @@ +#ifndef FILE_MESHING2 +#define FILE_MESHING2 + +/**************************************************************************/ +/* File: meshing2.hpp */ +/* Author: Joachim Schoeberl */ +/* Date: 01. Okt. 95 */ +/**************************************************************************/ + + + +enum MESHING2_RESULT +{ + MESHING2_OK = 0, + MESHING2_GIVEUP = 1 +}; + + +/* + +The basis class for 2D mesh generation. +Has the method GenerateMesh + +For surface mesh generation, or non-Euklidean meshing, +derive from Meshing2, and replace transformation. + +*/ + +class Meshing2 +{ + /// the current advancing front + AdFront2 * adfront; + /// rules for mesh generation + ARRAY<netrule*> rules; + /// statistics + ARRAY<int> ruleused, canuse, foundmap; + /// + Box3d boundingbox; + /// + double starttime; +public: + /// + Meshing2 (const Box3d & aboundingbox); + + /// + virtual ~Meshing2 (); + + /// Load rules, either from file, or compiled rules + void LoadRules (const char * filename); + + /// + MESHING2_RESULT GenerateMesh (Mesh & mesh, double gh, int facenr); + + /// + void AddPoint (const Point3d & p, PointIndex globind, MultiPointGeomInfo * mgi = NULL); + + /// + void AddBoundaryElement (INDEX i1, INDEX i2, + const PointGeomInfo & gi1, const PointGeomInfo & gi2); + + /// + void SetStartTime (double astarttime); + +protected: + /// + virtual void StartMesh (); + /// + virtual void EndMesh (); + /// + virtual double CalcLocalH (const Point3d & p, double gh) const; + + /// + virtual void DefineTransformation (Point3d & p1, Point3d & p2, + const PointGeomInfo * geominfo1, + const PointGeomInfo * geominfo2); + /// + virtual void TransformToPlain (const Point3d & locpoint, const MultiPointGeomInfo & geominfo, + Point2d & plainpoint, double h, int & zone); + /// return 0 .. ok + /// return >0 .. cannot transform point to true surface + virtual int TransformFromPlain (Point2d & plainpoint, + Point3d & locpoint, + PointGeomInfo & geominfo, + double h); + + /// projects to surface + /// return 0 .. ok + virtual int BelongsToActiveChart (const Point3d & p, + const PointGeomInfo & gi); + + /// computes geoinfo data for line with respect to + /// selected chart + virtual int ComputePointGeomInfo (const Point3d & p, + PointGeomInfo & gi); + + /// Tries to select unique geominfo on active chart + /// return 0: success + /// return 1: failed + virtual int ChooseChartPointGeomInfo (const MultiPointGeomInfo & mpgi, + PointGeomInfo & pgi); + + + + /* + tests, whether endpoint (= 1 or 2) of line segment p1-p2 + is inside of the selected chart. The endpoint must be on the + chart + */ + virtual int IsLineVertexOnChart (const Point3d & p1, const Point3d & p2, + int endpoint, const PointGeomInfo & geominfo); + + /* + get (projected) boundary of current chart + */ + virtual void GetChartBoundary (ARRAY<Point2d> & points, + ARRAY<Point3d> & points3d, + ARRAY<INDEX_2> & lines, double p) const; + + virtual double Area () const; + + +/** Applies 2D rules. + Tests all 2D rules */ + int ApplyRules (ARRAY<Point2d> & lpoints, + ARRAY<int> & legalpoints, + int maxlegalpoint, + ARRAY<INDEX_2> & llines, + int maxlegelline, + ARRAY<Element2d> & elements, ARRAY<INDEX> & dellines, + int tolerance); + + +}; + + + + + + + + +#endif + + + + + + + diff --git a/contrib/Netgen/libsrc/meshing/meshing3.cpp b/contrib/Netgen/libsrc/meshing/meshing3.cpp new file mode 100644 index 0000000000..c349b85e79 --- /dev/null +++ b/contrib/Netgen/libsrc/meshing/meshing3.cpp @@ -0,0 +1,1260 @@ +#include <mystdlib.h> +#include "meshing.hpp" + +namespace netgen +{ + +double minother; +double minwithoutother; + + + + + +MeshingStat3d :: MeshingStat3d () +{ + cntsucc = cnttrials = cntelem = qualclass = 0; + vol0 = h = 1; + problemindex = 1; +} + + +Meshing3 :: Meshing3 (const string & rulefilename) +{ + tolfak = 1; + + LoadRules (rulefilename.c_str(), NULL); + adfront = new AdFront3; + + problems.SetSize (rules.Size()); + foundmap.SetSize (rules.Size()); + canuse.SetSize (rules.Size()); + ruleused.SetSize (rules.Size()); + + for (int i = 1; i <= rules.Size(); i++) + { + problems.Elem(i) = new char[255]; + foundmap.Elem(i) = 0; + canuse.Elem(i) = 0; + ruleused.Elem(i) = 0; + } +} + + +Meshing3 :: Meshing3 (const char ** rulep) +{ + tolfak = 1; + + LoadRules (NULL, rulep); + adfront = new AdFront3; + + problems.SetSize (rules.Size()); + foundmap.SetSize (rules.Size()); + canuse.SetSize (rules.Size()); + ruleused.SetSize (rules.Size()); + + for (int i = 0; i < rules.Size(); i++) + { + problems[i] = new char[255]; + foundmap[i] = 0; + canuse[i] = 0; + ruleused[i] = 0; + } +} + +Meshing3 :: ~Meshing3 () +{ + delete adfront; + for (int i = 0; i < rules.Size(); i++) + { + delete [] problems[i]; + delete rules[i]; + } +} + + + +static double CalcLocH (const ARRAY<Point3d> & locpoints, + const ARRAY<Element2d> & locfaces, + double h) +{ + return h; + + // was war das ???? + + int i, j; + double hi, h1, d, dn, sum, weight, wi; + Point3d p0, pc; + Vec3d n, v1, v2; + + p0.X() = p0.Y() = p0.Z() = 0; + for (j = 1; j <= 3; j++) + { + p0.X() += locpoints.Get(locfaces.Get(1).PNum(j)).X(); + p0.Y() += locpoints.Get(locfaces.Get(1).PNum(j)).Y(); + p0.Z() += locpoints.Get(locfaces.Get(1).PNum(j)).Z(); + } + p0.X() /= 3; p0.Y() /= 3; p0.Z() /= 3; + + v1 = locpoints.Get(locfaces.Get(1).PNum(2)) - + locpoints.Get(locfaces.Get(1).PNum(1)); + v2 = locpoints.Get(locfaces.Get(1).PNum(3)) - + locpoints.Get(locfaces.Get(1).PNum(1)); + + h1 = v1.Length(); + n = Cross (v2, v1); + n /= n.Length(); + + sum = 0; + weight = 0; + + for (i = 1; i <= locfaces.Size(); i++) + { + pc.X() = pc.Y() = pc.Z() = 0; + for (j = 1; j <= 3; j++) + { + pc.X() += locpoints.Get(locfaces.Get(i).PNum(j)).X(); + pc.Y() += locpoints.Get(locfaces.Get(i).PNum(j)).Y(); + pc.Z() += locpoints.Get(locfaces.Get(i).PNum(j)).Z(); + } + pc.X() /= 3; pc.Y() /= 3; pc.Z() /= 3; + + d = Dist (p0, pc); + dn = n * (pc - p0); + hi = Dist (locpoints.Get(locfaces.Get(i).PNum(1)), + locpoints.Get(locfaces.Get(i).PNum(2))); + + if (dn > -0.2 * h1) + { + wi = 1 / (h1 + d); + wi *= wi; + } + else + wi = 0; + + sum += hi * wi; + weight += wi; + } + + return sum/weight; +} + + +PointIndex Meshing3 :: AddPoint (const Point3d & p, PointIndex globind) +{ + return adfront -> AddPoint (p, globind); +} + +void Meshing3 :: AddBoundaryElement (const Element2d & elem) +{ + adfront -> AddFace(elem); +} + +int Meshing3 :: AddConnectedPair (const INDEX_2 & apair) +{ + return adfront -> AddConnectedPair (apair); +} + +MESHING3_RESULT Meshing3 :: +GenerateMesh (Mesh & mesh, const MeshingParameters & mp) +{ + ARRAY<Point3d> locpoints; // local points + ARRAY<Element2d> locfaces; // local faces + ARRAY<PointIndex> pindex; // mapping from local to front point numbering + ARRAY<int> allowpoint; // point is allowd ? + ARRAY<INDEX> findex; // mapping from local to front face numbering + INDEX_2_HASHTABLE<int> connectedpairs(100); // connecgted pairs for prism meshing + + ARRAY<Point3d> plainpoints; // points in reference coordinates + ARRAY<int> delpoints, delfaces; // points and lines to be deleted + ARRAY<Element> locelements; // new generated elements + + int i, j, oldnp, oldnf; + int found; + referencetransform trans; + int rotind; + INDEX globind; + Point3d inp; + float err; + + INDEX locfacesplit; //index for faces in outer area + + int loktestmode = 0; + + int uselocalh = mparam.uselocalh; + + int giveuptol = mp.giveuptol; // + MeshingStat3d stat; // statistics + int plotstat_oldne = -1; + + + // for star-shaped domain meshing + ARRAY<MeshPoint> grouppoints; + ARRAY<Element2d> groupfaces; + ARRAY<PointIndex> grouppindex; + ARRAY<INDEX> groupfindex; + + + float minerr; + int hasfound; + double tetvol; + int giveup = 0; + + + ARRAY<Point3d> tempnewpoints; + ARRAY<Element2d> tempnewfaces; + ARRAY<int> tempdelfaces; + ARRAY<Element> templocelements; + + + stat.h = mp.maxh; + + adfront->SetStartFront (mp.baseelnp); + + + found = 0; + stat.vol0 = adfront -> Volume(); + tetvol = 0; + + stat.qualclass = 1; + + while (1) + { + if (multithread.terminate) + throw NgException ("Meshing stopped"); + + if (giveup) + break; + + // break if advancing front is empty + if (!mp.baseelnp && adfront->Empty()) + break; + + // break, if advancing front has no elements with + // mp.baseelnp nodes + if (mp.baseelnp && adfront->Empty (mp.baseelnp)) + break; + + + locpoints.SetSize(0); + locfaces.SetSize(0); + locelements.SetSize(0); + pindex.SetSize(0); + findex.SetSize(0); + + INDEX_2_HASHTABLE<int> connectedpairs(100); // 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 Element2d & bel = adfront->GetFace (baseelem); + const Point3d & p1 = adfront->GetPoint (bel.PNum(1)); + const Point3d & p2 = adfront->GetPoint (bel.PNum(2)); + const Point3d & p3 = adfront->GetPoint (bel.PNum(3)); + + (*testout) << endl << "base = " << bel << endl; + + + Point3d pmid = Center (p1, p2, p3); + + double his = (Dist (p1, p2) + Dist(p1, p3) + Dist(p2, p3)) / 3; + double hshould; + + hshould = mesh.GetH (pmid); + + if (adfront->GetFace (baseelem).GetNP() == 4) + hshould = max2 (his, hshould); + + double hmax = (his > hshould) ? his : hshould; + + // qualclass should come from baseelem !!!!! + double hinner = hmax * (1 + stat.qualclass); + double houter = hmax * (1 + 2 * stat.qualclass); + + stat.qualclass = + adfront -> GetLocals (baseelem, locpoints, locfaces, + pindex, findex, connectedpairs, + houter, hinner, + locfacesplit); + + + int pi1 = pindex.Get(locfaces[0].PNum(1)); + int pi2 = pindex.Get(locfaces[0].PNum(2)); + int pi3 = pindex.Get(locfaces[0].PNum(3)); + + /* + (*testout) << "baseel = " << baseelem << ", ind = " << findex.Get(1) << endl; + (*testout) << "pi = " << pi1 << ", " << pi2 << ", " << pi3 << endl; + */ + + loktestmode = 0; + // testmode = loktestmode; + // loktestmode = testmode = (adfront->GetFace (baseelem).GetNP() == 4) && (rules.Size() == 5); + + if (testmode) + { + (*testout) << "baseelem = " << baseelem << " qualclass = " << stat.qualclass << endl; + (*testout) << "locpoints = " << endl << locpoints << endl; + (*testout) << "connected = " << endl << connectedpairs << endl; + } + + + + // loch = CalcLocH (locpoints, locfaces, h); + + stat.nff = adfront->GetNF(); + stat.vol = adfront->Volume(); + if (stat.vol < 0) break; + + oldnp = locpoints.Size(); + oldnf = locfaces.Size(); + + + allowpoint.SetSize(locpoints.Size()); + if (uselocalh && stat.qualclass <= 3) + for (i = 1; i <= allowpoint.Size(); i++) + { + allowpoint.Elem(i) = + mesh.GetH (locpoints.Get(i)) > 0.4 * hshould / mp.sloppy; + } + else + for (i = 1; i <= allowpoint.Size(); i++) + allowpoint.Elem(i) = 1; + + + + + + if (stat.qualclass >= mp.starshapeclass) + { + // star-shaped domain removing + + grouppoints.SetSize (0); + groupfaces.SetSize (0); + grouppindex.SetSize (0); + groupfindex.SetSize (0); + + adfront -> GetGroup (findex.Get(1), grouppoints, groupfaces, + grouppindex, groupfindex); + + int onlytri = 1; + for (i = 1; i <= groupfaces.Size(); i++) + if (groupfaces.Get(i).GetNP() != 3) + onlytri = 0; + + if (onlytri && groupfaces.Size() <= 20 && + FindInnerPoint (grouppoints, groupfaces, inp)) + { + (*testout) << "inner point found" << endl; + + for (i = 1; i <= groupfaces.Size(); i++) + adfront -> DeleteFace (groupfindex.Get(i)); + + for (i = 1; i <= groupfaces.Size(); i++) + for (j = 1; j <= locfaces.Size(); j++) + if (findex.Get(j) == groupfindex.Get(i)) + delfaces.Append (j); + + + delfaces.SetSize (0); + + INDEX npi; + Element newel; + + npi = mesh.AddPoint (inp); + newel.SetNP(4); + newel.PNum(4) = npi; + + + for (i = 1; i <= groupfaces.Size(); i++) + { + for (j = 1; j <= 3; j++) + { + newel.PNum(j) = + adfront->GetGlobalIndex + (grouppindex.Get(groupfaces.Get(i).PNum(j))); + } + mesh.AddVolumeElement (newel); + } + continue; + } + } + + + + found = 0; + hasfound = 0; + minerr = 1e6; + + + // int optother = 0; + + /* + for (i = 1; i <= locfaces.Size(); i++) + { + (*testout) << "Face " << i << ": "; + for (j = 1; j <= locfaces.Get(i).GetNP(); j++) + (*testout) << pindex.Get(locfaces.Get(i).PNum(j)) << " "; + (*testout) << endl; + } + for (i = 1; i <= locpoints.Size(); i++) + { + (*testout) << "p" << i + << ", gi = " << pindex.Get(i) + << " = " << locpoints.Get(i) << endl; + } + */ + + minother = 1e10; + minwithoutother = 1e10; + + for (rotind = 1; rotind <= locfaces.Get(1).GetNP(); rotind++) + { + // set transformatino to reference coordinates + + if (locfaces.Get(1).GetNP() == 3) + { + trans.Set (locpoints.Get(locfaces.Get(1).PNumMod(1+rotind)), + locpoints.Get(locfaces.Get(1).PNumMod(2+rotind)), + locpoints.Get(locfaces.Get(1).PNumMod(3+rotind)), hshould); + } + else + { + trans.Set (locpoints.Get(locfaces.Get(1).PNumMod(1+rotind)), + locpoints.Get(locfaces.Get(1).PNumMod(2+rotind)), + locpoints.Get(locfaces.Get(1).PNumMod(4+rotind)), hshould); + } + + trans.ToPlain (locpoints, plainpoints); + + + for (i = 1; i <= allowpoint.Size(); i++) + { + if (plainpoints.Get(i).Z() > 0) + allowpoint.Elem(i) = 0; + } + + + if (loktestmode) + (*testout) << "plainpoints = " << endl << plainpoints << endl; + + stat.cnttrials++; + + + if (stat.cnttrials % 100 == 0) + { + (*testout) << "\n"; + for (i = 1; i <= canuse.Size(); i++) + { + (*testout) << foundmap.Get(i) << "/" + << canuse.Get(i) << "/" + << ruleused.Get(i) << " map/can/use rule " << rules.Get(i)->Name() << "\n"; + } + (*testout) << endl; + } + + found = ApplyRules (plainpoints, allowpoint, + locfaces, locfacesplit, connectedpairs, + locelements, delfaces, + stat.qualclass, mp.sloppy, rotind, err); + + if (loktestmode) + { + (*testout) << "Applyrules found " << found << endl; + } + + if (found) stat.cntsucc++; + + locpoints.SetSize (plainpoints.Size()); + for (i = oldnp+1; i <= plainpoints.Size(); i++) + trans.FromPlain (plainpoints.Elem(i), locpoints.Elem(i)); + + + + // avoid meshing from large to small mesh-size + + if (uselocalh && found && stat.qualclass <= 3) + { + for (i = 1; i <= locelements.Size(); i++) + { + Point3d pmin = locpoints.Get(locelements.Get(i).PNum(1)); + Point3d pmax = pmin; + for (j = 2; j <= 4; j++) + { + const Point3d & hp = locpoints.Get(locelements.Get(i).PNum(j)); + pmin.SetToMin (hp); + pmax.SetToMax (hp); + } + + if (mesh.GetMinH (pmin, pmax) < 0.4 * hshould / mp.sloppy) + found = 0; + } + } + if (found) + { + for (i = 1; i <= locelements.Size(); i++) + for (j = 1; j <= 4; j++) + { + const Point3d & hp = locpoints.Get(locelements.Get(i).PNum(j)); + if (Dist (hp, pmid) > hinner) + found = 0; + } + } + + + if (found) + ruleused.Elem(found)++; + + + if (stat.qualclass > 80) + { + cerr << "Sorry, I failed" << endl; + mesh.Save ("tempvol.out"); + exit (1); + } + + + // plotstat->Plot(stat); + + if (stat.cntelem != plotstat_oldne) + { + plotstat_oldne = stat.cntelem; + + PrintMessageCR (5, "El: ", stat.cntelem, + // << " trials: " << stat.cnttrials + " faces: ", stat.nff, + " vol = ", float(100 * stat.vol / stat.vol0)); + + multithread.percent = 100 - 100.0 * stat.vol / stat.vol0; + } + + + if (found && (!hasfound || err < minerr) ) + { + + if (testmode) + { + (*testout) << "testmode found" << endl; + for (i = 1; i <= plainpoints.Size(); i++) + { + (*testout) << "p"; + if (i <= pindex.Size()) + (*testout) << pindex.Get(i) << ": "; + else + (*testout) << "new: "; + (*testout) << plainpoints.Get(i) << endl; + } + } + + + + hasfound = found; + minerr = err; + + tempnewpoints.SetSize (0); + for (i = oldnp+1; i <= locpoints.Size(); i++) + tempnewpoints.Append (locpoints.Get(i)); + + tempnewfaces.SetSize (0); + for (i = oldnf+1; i <= locfaces.Size(); i++) + tempnewfaces.Append (locfaces.Get(i)); + + tempdelfaces.SetSize (0); + for (i = 1; i <= delfaces.Size(); i++) + tempdelfaces.Append (delfaces.Get(i)); + + templocelements.SetSize (0); + for (i = 1; i <= locelements.Size(); i++) + templocelements.Append (locelements.Get(i)); + + /* + optother = + strcmp (problems[found], "other") == 0; + */ + } + + locpoints.SetSize (oldnp); + locfaces.SetSize (oldnf); + delfaces.SetSize (0); + locelements.SetSize (0); + } + + + + if (hasfound) + { + + /* + if (optother) + (*testout) << "Other is optimal" << endl; + + if (minother < minwithoutother) + { + (*testout) << "Other is better, " << minother << " less " << minwithoutother << endl; + } + */ + + for (i = 1; i <= tempnewpoints.Size(); i++) + locpoints.Append (tempnewpoints.Get(i)); + for (i = 1; i <= tempnewfaces.Size(); i++) + locfaces.Append (tempnewfaces.Get(i)); + for (i = 1; i <= tempdelfaces.Size(); i++) + delfaces.Append (tempdelfaces.Get(i)); + for (i = 1; i <= templocelements.Size(); i++) + locelements.Append (templocelements.Get(i)); + + + if (testmode) + { + (*testout) << "testmode locpoints" << endl; + for (i = 1; i <= locpoints.Size(); i++) + { + (*testout) << "p"; + if (i <= pindex.Size()) + (*testout) << pindex.Get(i) << ": "; + else + (*testout) << "new: "; + (*testout) << locpoints.Get(i) << endl; + } + } + + + + pindex.SetSize(locpoints.Size()); + + for (i = oldnp+1; i <= locpoints.Size(); i++) + { + globind = mesh.AddPoint (locpoints.Get(i)); + pindex.Elem(i) = adfront -> AddPoint (locpoints.Get(i), globind); + } + + for (i = 1; i <= locelements.Size(); i++) + { + Point3d * hp1, * hp2, * hp3, * hp4; + hp1 = &locpoints.Elem(locelements.Get(i).PNum(1)); + hp2 = &locpoints.Elem(locelements.Get(i).PNum(2)); + hp3 = &locpoints.Elem(locelements.Get(i).PNum(3)); + hp4 = &locpoints.Elem(locelements.Get(i).PNum(4)); + + tetvol += (1.0 / 6.0) * ( Cross ( *hp2 - *hp1, *hp3 - *hp1) * (*hp4 - *hp1) ); + + for (j = 1; j <= locelements.Get(i).NP(); j++) + locelements.Elem(i).PNum(j) = + adfront -> GetGlobalIndex (pindex.Get(locelements.Get(i).PNum(j))); + + mesh.AddVolumeElement (locelements.Get(i)); + stat.cntelem++; + } + + for (i = oldnf+1; i <= locfaces.Size(); i++) + { + for (j = 1; j <= locfaces.Get(i).GetNP(); j++) + locfaces.Elem(i).PNum(j) = + pindex.Get(locfaces.Get(i).PNum(j)); + (*testout) << "add face " << locfaces.Get(i) << endl; + adfront->AddFace (locfaces.Get(i)); + } + + for (i = 1; i <= delfaces.Size(); i++) + { + adfront->DeleteFace (findex.Get(delfaces.Get(i))); + } + } + else + { + adfront->IncrementClass (findex.Get(1)); + } + + locelements.SetSize (0); + delpoints.SetSize(0); + delfaces.SetSize(0); + + if (stat.qualclass >= giveuptol) + giveup = 1; +#ifdef MYGRAPH + if (plotvolmesh && plotvolmesh->GiveUp()) + giveup = 1; +#endif + } + + + + for (i = 1; i <= ruleused.Size(); i++) + (*testout) << setw(4) << ruleused.Get(i) + << " times used rule " << rules.Get(i) -> Name() << endl; + + + if (!mp.baseelnp && adfront->Empty()) + return MESHING3_OK; + + if (mp.baseelnp && adfront->Empty (mp.baseelnp)) + return MESHING3_OK; + + if (stat.vol < -1e-15) + return MESHING3_NEGVOL; + + return MESHING3_NEGVOL; +} + + + + +enum blocktyp { BLOCKUNDEF, BLOCKINNER, BLOCKBOUND, BLOCKOUTER }; + +void Meshing3 :: BlockFill (Mesh & mesh, double gh) +{ + PrintMessage (3, "Block-filling called (obsolete) "); + + int i, j, i1, i2, i3, j1, j2, j3; + int n1, n2, n3, n, min1, min2, min3, max1, max2, max3; + int changed, filled; + double xmin, xmax, ymin, ymax, zmin, zmax; + double xminb, xmaxb, yminb, ymaxb, zminb, zmaxb; + double rad = 0.7 * gh; + + for (i = 1; i <= adfront->GetNP(); i++) + { + const Point3d & p = adfront->GetPoint(i); + if (i == 1) + { + xmin = xmax = p.X(); + ymin = ymax = p.Y(); + zmin = zmax = p.Z(); + } + else + { + if (p.X() < xmin) xmin = p.X(); + if (p.X() > xmax) xmax = p.X(); + if (p.Y() < ymin) ymin = p.Y(); + if (p.Y() > ymax) ymax = p.Y(); + if (p.Z() < zmin) zmin = p.Z(); + if (p.Z() > zmax) zmax = p.Z(); + } + } + + xmin -= 5 * gh; + ymin -= 5 * gh; + zmin -= 5 * gh; + + n1 = int ((xmax-xmin) / gh + 5); + n2 = int ((ymax-ymin) / gh + 5); + n3 = int ((zmax-zmin) / gh + 5); + n = n1 * n2 * n3; + + PrintMessage (5, "n1 = ", n1, " n2 = ", n2, " n3 = ", n3); + + ARRAY<blocktyp> inner(n); + ARRAY<int> pointnr(n), frontpointnr(n); + + + // initialize inner to 1 + + for (i = 1; i <= n; i++) + inner.Elem(i) = BLOCKUNDEF; + + + // set blocks cutting surfaces to 0 + + for (i = 1; i <= adfront->GetNF(); i++) + { + const Element2d & el = adfront->GetFace(i); + xminb = xmax; xmaxb = xmin; + yminb = ymax; ymaxb = ymin; + zminb = zmax; zmaxb = zmin; + + for (j = 1; j <= 3; j++) + { + const Point3d & p = adfront->GetPoint (el.PNum(j)); + if (p.X() < xminb) xminb = p.X(); + if (p.X() > xmaxb) xmaxb = p.X(); + if (p.Y() < yminb) yminb = p.Y(); + if (p.Y() > ymaxb) ymaxb = p.Y(); + if (p.Z() < zminb) zminb = p.Z(); + if (p.Z() > zmaxb) zmaxb = p.Z(); + } + + + + double filldist = 0.2; // globflags.GetNumFlag ("filldist", 0.4); + xminb -= filldist * gh; + xmaxb += filldist * gh; + yminb -= filldist * gh; + ymaxb += filldist * gh; + zminb -= filldist * gh; + zmaxb += filldist * gh; + + min1 = int ((xminb - xmin) / gh) + 1; + max1 = int ((xmaxb - xmin) / gh) + 1; + min2 = int ((yminb - ymin) / gh) + 1; + max2 = int ((ymaxb - ymin) / gh) + 1; + min3 = int ((zminb - zmin) / gh) + 1; + max3 = int ((zmaxb - zmin) / gh) + 1; + + + for (i1 = min1; i1 <= max1; i1++) + for (i2 = min2; i2 <= max2; i2++) + for (i3 = min3; i3 <= max3; i3++) + inner.Elem(i3 + (i2-1) * n3 + (i1-1) * n2 * n3) = BLOCKBOUND; + } + + + + + while (1) + { + int undefi = 0; + Point3d undefp; + + for (i1 = 1; i1 <= n1 && !undefi; i1++) + for (i2 = 1; i2 <= n2 && !undefi; i2++) + for (i3 = 1; i3 <= n3 && !undefi; i3++) + { + i = i3 + (i2-1) * n3 + (i1-1) * n2 * n3; + if (inner.Elem(i) == BLOCKUNDEF) + { + undefi = i; + undefp.X() = xmin + (i1-0.5) * gh; + undefp.Y() = ymin + (i2-0.5) * gh; + undefp.Z() = zmin + (i3-0.5) * gh; + } + } + + if (!undefi) + break; + + // PrintMessage (5, "Test point: ", undefp); + + if (adfront -> Inside (undefp)) + { + // (*mycout) << "inner" << endl; + inner.Elem(undefi) = BLOCKINNER; + } + else + { + // (*mycout) << "outer" << endl; + inner.Elem(undefi) = BLOCKOUTER; + } + + do + { + changed = 0; + for (i1 = 1; i1 <= n1; i1++) + for (i2 = 1; i2 <= n2; i2++) + for (i3 = 1; i3 <= n3; i3++) + { + i = i3 + (i2-1) * n3 + (i1-1) * n2 * n3; + + for (int k = 1; k <= 3; k++) + { + switch (k) + { + case 1: j = i + n2 * n3; break; + case 2: j = i + n3; break; + case 3: j = i + 1; break; + } + + if (j > n1 * n2 * n3) continue; + + if (inner.Elem(i) == BLOCKOUTER && inner.Elem(j) == BLOCKUNDEF) + { + changed = 1; + inner.Elem(j) = BLOCKOUTER; + } + if (inner.Elem(j) == BLOCKOUTER && inner.Elem(i) == BLOCKUNDEF) + { + changed = 1; + inner.Elem(i) = BLOCKOUTER; + } + if (inner.Elem(i) == BLOCKINNER && inner.Elem(j) == BLOCKUNDEF) + { + changed = 1; + inner.Elem(j) = BLOCKINNER; + } + if (inner.Elem(j) == BLOCKINNER && inner.Elem(i) == BLOCKUNDEF) + { + changed = 1; + inner.Elem(i) = BLOCKINNER; + } + } + } + } + while (changed); + + } + + + + filled = 0; + for (i = 1; i <= n; i++) + if (inner.Elem(i) == BLOCKINNER) + { + filled++; + } + PrintMessage (5, "Filled blocks: ", filled); + + for (i = 1; i <= n; i++) + { + pointnr.Elem(i) = 0; + frontpointnr.Elem(i) = 0; + } + + for (i1 = 1; i1 <= n1-1; i1++) + for (i2 = 1; i2 <= n2-1; i2++) + for (i3 = 1; i3 <= n3-1; i3++) + { + i = i3 + (i2-1) * n3 + (i1-1) * n2 * n3; + if (inner.Elem(i) == BLOCKINNER) + { + for (j1 = i1; j1 <= i1+1; j1++) + for (j2 = i2; j2 <= i2+1; j2++) + for (j3 = i3; j3 <= i3+1; j3++) + { + j = j3 + (j2-1) * n3 + (j1-1) * n2 * n3; + if (pointnr.Get(j) == 0) + { + Point3d hp(xmin + (j1-1) * gh, + ymin + (j2-1) * gh, + zmin + (j3-1) * gh); + pointnr.Elem(j) = mesh.AddPoint (hp); + frontpointnr.Elem(j) = + AddPoint (hp, pointnr.Elem(j)); + + } + } + } + } + + + for (i1 = 2; i1 <= n1-1; i1++) + for (i2 = 2; i2 <= n2-1; i2++) + for (i3 = 2; i3 <= n3-1; i3++) + { + i = i3 + (i2-1) * n3 + (i1-1) * n2 * n3; + if (inner.Elem(i) == BLOCKINNER) + { + int pn[9]; + pn[1] = pointnr.Get(i); + pn[2] = pointnr.Get(i+1); + pn[3] = pointnr.Get(i+n3); + pn[4] = pointnr.Get(i+n3+1); + pn[5] = pointnr.Get(i+n2*n3); + pn[6] = pointnr.Get(i+n2*n3+1); + pn[7] = pointnr.Get(i+n2*n3+n3); + pn[8] = pointnr.Get(i+n2*n3+n3+1); + static int elind[][4] = + { + { 1, 8, 2, 4 }, + { 1, 8, 4, 3 }, + { 1, 8, 3, 7 }, + { 1, 8, 7, 5 }, + { 1, 8, 5, 6 }, + { 1, 8, 6, 2 } + }; + for (j = 1; j <= 6; j++) + { + Element el(4); + for (int k = 1; k <= 4; k++) + el.PNum(k) = pn[elind[j-1][k-1]]; + + mesh.AddVolumeElement (el); + } + } + } + + + + for (i1 = 2; i1 <= n1-1; i1++) + for (i2 = 2; i2 <= n2-1; i2++) + for (i3 = 2; i3 <= n3-1; i3++) + { + i = i3 + (i2-1) * n3 + (i1-1) * n2 * n3; + if (inner.Elem(i) == BLOCKINNER) + { + int pi1, pi2, pi3, pi4; + + int pn1 = frontpointnr.Get(i); + int pn2 = frontpointnr.Get(i+1); + int pn3 = frontpointnr.Get(i+n3); + int pn4 = frontpointnr.Get(i+n3+1); + int pn5 = frontpointnr.Get(i+n2*n3); + int pn6 = frontpointnr.Get(i+n2*n3+1); + int pn7 = frontpointnr.Get(i+n2*n3+n3); + int pn8 = frontpointnr.Get(i+n2*n3+n3+1); + + for (int k = 1; k <= 6; k++) + { + switch (k) + { + case 1: // j3 = i3+1 + j = i + 1; + pi1 = pn2; + pi2 = pn6; + pi3 = pn4; + pi4 = pn8; + break; + case 2: // j3 = i3-1 + j = i - 1; + pi1 = pn1; + pi2 = pn3; + pi3 = pn5; + pi4 = pn7; + break; + case 3: // j2 = i2+1 + j = i + n3; + pi1 = pn3; + pi2 = pn4; + pi3 = pn7; + pi4 = pn8; + break; + case 4: // j2 = i2-1 + j = i - n3; + pi1 = pn1; + pi2 = pn5; + pi3 = pn2; + pi4 = pn6; + break; + case 5: // j1 = i1+1 + j = i + n3*n2; + pi1 = pn5; + pi2 = pn7; + pi3 = pn6; + pi4 = pn8; + break; + case 6: // j1 = i1-1 + j = i - n3*n2; + pi1 = pn1; + pi2 = pn2; + pi3 = pn3; + pi4 = pn4; + break; + } + + if (inner.Get(j) == BLOCKBOUND) + { + Element2d face; + face.PNum(1) = pi4; + face.PNum(2) = pi1; + face.PNum(3) = pi3; + AddBoundaryElement (face); + + face.PNum(1) = pi1; + face.PNum(2) = pi4; + face.PNum(3) = pi2; + AddBoundaryElement (face); + + } + } + } + } +} + + + +static const AdFront3 * locadfront; +static int TestInner (const Point3d & p) +{ + return locadfront->Inside (p); +} +static int TestSameSide (const Point3d & p1, const Point3d & p2) +{ + return locadfront->SameSide (p1, p2); +} + + + + +void Meshing3 :: BlockFillLocalH (Mesh & mesh, + const MeshingParameters & mp) +{ + int i, j; + + double filldist = mp.filldist; + + (*testout) << "blockfill local h" << endl; + (*testout) << "rel filldist = " << filldist << endl; + PrintMessage (3, "blockfill local h"); + + /* + (*mycout) << "boxes: " << mesh.LocalHFunction().GetNBoxes() << endl + << "filldist = " << filldist << endl; + */ + ARRAY<Point3d> npoints; + + adfront -> CreateTrees(); + + Point3d mpmin, mpmax; + // mesh.GetBox (mpmin, mpmax); + bool firstp = 1; + + double maxh = 0; + for (i = 1; i <= adfront->GetNF(); i++) + { + const Element2d & el = adfront->GetFace(i); + for (j = 1; j <= 3; j++) + { + const Point3d & p1 = adfront->GetPoint (el.PNumMod(j)); + const Point3d & p2 = adfront->GetPoint (el.PNumMod(j+1)); + double hi = Dist (p1, p2); + if (hi > maxh) maxh = hi; + + if (firstp) + { + mpmin = p1; + mpmax = p1; + firstp = 0; + } + else + { + mpmin.SetToMin (p1); + mpmax.SetToMax (p1); + } + } + } + + Point3d mpc = Center (mpmin, mpmax); + double d = max3(mpmax.X()-mpmin.X(), + mpmax.Y()-mpmin.Y(), + mpmax.Z()-mpmin.Z()) / 2; + mpmin = mpc - Vec3d (d, d, d); + mpmax = mpc + Vec3d (d, d, d); + Box3d meshbox (mpmin, mpmax); + + LocalH loch2 (mpmin, mpmax, 1); + + + if (mp.maxh < maxh) maxh = mp.maxh; + + int changed; + do + { + mesh.LocalHFunction().ClearFlags(); + + for (i = 1; i <= adfront->GetNF(); i++) + { + const Element2d & el = adfront->GetFace(i); + Point3d pmin = adfront->GetPoint (el.PNum(1)); + Point3d pmax = pmin; + + for (j = 2; j <= 3; j++) + { + const Point3d & p = adfront->GetPoint (el.PNum(j)); + pmin.SetToMin (p); + pmax.SetToMax (p); + } + + + double filld = filldist * Dist (pmin, pmax); + + pmin = pmin - Vec3d (filld, filld, filld); + pmax = pmax + Vec3d (filld, filld, filld); + // (*testout) << "cut : " << pmin << " - " << pmax << endl; + mesh.LocalHFunction().CutBoundary (pmin, pmax); + } + + locadfront = adfront; + mesh.LocalHFunction().FindInnerBoxes (adfront, NULL); + + npoints.SetSize(0); + mesh.LocalHFunction().GetInnerPoints (npoints); + + changed = 0; + for (i = 1; i <= npoints.Size(); i++) + { + if (mesh.LocalHFunction().GetH(npoints.Get(i)) > 1.5 * maxh) + { + mesh.LocalHFunction().SetH (npoints.Get(i), +maxh); + changed = 1; + } + } + } + while (changed); + + if (debugparam.slowchecks) + (*testout) << "Blockfill with points: " << endl; + for (i = 1; i <= npoints.Size(); i++) + { + if (meshbox.IsIn (npoints.Get(i))) + { + int gpnum = mesh.AddPoint (npoints.Get(i)); + adfront->AddPoint (npoints.Get(i), gpnum); + + if (debugparam.slowchecks) + { + (*testout) << npoints.Get(i) << endl; + if (!adfront->Inside(npoints.Get(i))) + { + cout << "add outside point" << endl; + (*testout) << "outside" << endl; + } + } + + } + } + + + + // find outer points + + loch2.ClearFlags(); + + for (i = 1; i <= adfront->GetNF(); i++) + { + const Element2d & el = adfront->GetFace(i); + Point3d pmin = adfront->GetPoint (el.PNum(1)); + Point3d pmax = pmin; + + for (j = 2; j <= 3; j++) + { + const Point3d & p = adfront->GetPoint (el.PNum(j)); + pmin.SetToMin (p); + pmax.SetToMax (p); + } + + loch2.SetH (Center (pmin, pmax), Dist (pmin, pmax)); + } + + for (i = 1; i <= adfront->GetNF(); i++) + { + const Element2d & el = adfront->GetFace(i); + Point3d pmin = adfront->GetPoint (el.PNum(1)); + Point3d pmax = pmin; + + for (j = 2; j <= 3; j++) + { + const Point3d & p = adfront->GetPoint (el.PNum(j)); + pmin.SetToMin (p); + pmax.SetToMax (p); + } + + double filld = filldist * Dist (pmin, pmax); + pmin = pmin - Vec3d (filld, filld, filld); + pmax = pmax + Vec3d (filld, filld, filld); + loch2.CutBoundary (pmin, pmax); + } + + locadfront = adfront; + loch2.FindInnerBoxes (adfront, NULL); + + npoints.SetSize(0); + loch2.GetOuterPoints (npoints); + + for (i = 1; i <= npoints.Size(); i++) + { + if (meshbox.IsIn (npoints.Get(i))) + { + int gpnum = mesh.AddPoint (npoints.Get(i)); + adfront->AddPoint (npoints.Get(i), gpnum); + } + } +} + +} diff --git a/contrib/Netgen/libsrc/meshing/meshing3.hpp b/contrib/Netgen/libsrc/meshing/meshing3.hpp new file mode 100644 index 0000000000..45f44751e3 --- /dev/null +++ b/contrib/Netgen/libsrc/meshing/meshing3.hpp @@ -0,0 +1,128 @@ +#ifndef FILE_MESHING3 +#define FILE_MESHING3 + + + + +enum MESHING3_RESULT +{ + MESHING3_OK = 0, + MESHING3_GIVEUP = 1, + MESHING3_NEGVOL = 2, + MESHING3_OUTERSTEPSEXCEEDED = 3, + MESHING3_TERMINATE = 4, + MESHING3_BADSURFACEMESH = 5 +}; + + +/// 3d volume mesh generation +class Meshing3 +{ + /// current state of front + AdFront3 * adfront; + /// 3d generation rules + ARRAY<vnetrule*> rules; + /// counts how often a rule is used + ARRAY<int> ruleused, canuse, foundmap; + /// describes, why a rule is not applied + ARRAY<char*> problems; + /// tolerance criterion + double tolfak; +public: + /// + Meshing3 (const string & rulefilename); + /// + Meshing3 (const char ** rulep); + /// + virtual ~Meshing3 (); + + /// + void LoadRules (const char * filename, const char ** prules); + /// + MESHING3_RESULT GenerateMesh (Mesh & mesh, const MeshingParameters & mp); + + /// + int ApplyRules (ARRAY<Point3d> & lpoints, ARRAY<int> & allowpoint, + ARRAY<Element2d> & lfaces, INDEX lfacesplit, + INDEX_2_HASHTABLE<int> & connectedpairs, + ARRAY<Element> & elements, + ARRAY<INDEX> & delfaces, int tolerance, + double sloppy, int rotind1, + float & retminerr); + + /// + PointIndex AddPoint (const Point3d & p, PointIndex globind); + /// + void AddBoundaryElement (const Element2d & elem); + /// + int AddConnectedPair (const INDEX_2 & pair); + + /// + void BlockFill (Mesh & mesh, double gh); + /// + void BlockFillLocalH (Mesh & mesh, const MeshingParameters & mp); + + /// uses points of adfront, and puts new elements into mesh + void Delaunay (Mesh & mesh, const MeshingParameters & mp); + /// + friend class PlotVolMesh; + /// + friend void TestRules (); +}; + + + + +/// status of mesh generation +class MeshingStat3d +{ +public: + /// + MeshingStat3d (); + /// + int cntsucc; + /// + int cnttrials; + /// + int cntelem; + /// + int nff; + /// + int qualclass; + /// + double vol0; + /// + double vol; + /// + double h; + /// + int problemindex; +}; + + + + + +/* +template <typename POINTARRAY, typename FACEARRAY> +extern int FindInnerPoint (POINTARRAY & grouppoints, + FACEARRAY & groupfaces, + Point3d & p); + +*/ + + + + + +#endif + + + + + + + + + + diff --git a/contrib/Netgen/libsrc/meshing/meshtool.cpp b/contrib/Netgen/libsrc/meshing/meshtool.cpp new file mode 100644 index 0000000000..89bb2b16dd --- /dev/null +++ b/contrib/Netgen/libsrc/meshing/meshtool.cpp @@ -0,0 +1,978 @@ +#include <mystdlib.h> + +#include "meshing.hpp" +#include <csg.hpp> +#include <geometry2d.hpp> + +namespace netgen +{ + + int CheckSurfaceMesh (const Mesh & mesh) + { + PrintMessage (3, "Check Surface mesh"); + + int nf = mesh.GetNSE(); + INDEX_2_HASHTABLE<int> edges(nf+2); + int i, j; + INDEX_2 i2; + int cnt1 = 0, cnt2 = 0; + + for (i = 1; i <= nf; i++) + for (j = 1; j <= 3; j++) + { + i2.I1() = mesh.SurfaceElement(i).PNumMod(j); + i2.I2() = mesh.SurfaceElement(i).PNumMod(j+1); + if (edges.Used(i2)) + { + int hi; + hi = edges.Get(i2); + if (hi != 1) + PrintSysError ("CheckSurfaceMesh, hi = ", hi); + edges.Set(i2, 2); + cnt2++; + } + else + { + Swap (i2.I1(), i2.I2()); + edges.Set(i2, 1); + cnt1++; + } + } + + + if (cnt1 != cnt2) + { + PrintUserError ("Surface mesh not consistent"); + // MyBeep(2); + // (*mycout) << "cnt1 = " << cnt1 << " cnt2 = " << cnt2 << endl; + return 0; + } + return 1; + } + + + + int CheckSurfaceMesh2 (const Mesh & mesh) + { + int i, j, k; + const Point3d *tri1[3], *tri2[3]; + + for (i = 1; i <= mesh.GetNOpenElements(); i++) + { + PrintDot (); + for (j = 1; j < i; j++) + { + for (k = 1; k <= 3; k++) + { + tri1[k-1] = &mesh.Point (mesh.OpenElement(i).PNum(k)); + tri2[k-1] = &mesh.Point (mesh.OpenElement(j).PNum(k)); + } + if (IntersectTriangleTriangle (&tri1[0], &tri2[0])) + { + PrintSysError ("Surface elements are intersecting"); + (*testout) << "Intersecting: " << endl; + for (k = 0; k <= 2; k++) + (*testout) << *tri1[k] << " "; + (*testout) << endl; + for (k = 0; k <= 2; k++) + (*testout) << *tri2[k] << " "; + (*testout) << endl; + } + + } + } + return 0; + } + + + + + + static double TriangleQualityInst (const Point3d & p1, const Point3d & p2, + const Point3d & p3) + { + // quality 0 (worst) .. 1 (optimal) + + Vec3d v1, v2, v3; + double s1, s2, s3; + double an1, an2, an3; + + v1 = p2 - p1; + v2 = p3 - p1; + v3 = p3 - p2; + + an1 = Angle (v1, v2); + v1 *= -1; + an2 = Angle (v1, v3); + an3 = Angle (v2, v3); + + s1 = sin (an1/2); + s2 = sin (an2/2); + s3 = sin (an3/2); + + return 8 * s1 * s2 * s3; + } + + + + + + + + + + + + + + + void MeshQuality2d (const Mesh & mesh) + { + int ncl = 20, cl; + ARRAY<INDEX> incl(ncl); + INDEX i; + SurfaceElementIndex sei; + double qual; + + incl = 0; + + for (sei = 0; sei < mesh.GetNSE(); sei++) + { + qual = TriangleQualityInst (mesh[mesh[sei][0]], + mesh[mesh[sei][1]], + mesh[mesh[sei][2]]); + + cl = int ( (ncl-1e-3) * qual ) + 1; + incl.Elem(cl)++; + } + + (*testout) << endl << endl; + + (*testout) << "Points: " << mesh.GetNP() << endl; + (*testout) << "Surface Elements: " << mesh.GetNSE() << endl; + + (*testout) << endl; + (*testout) << "Elements in qualityclasses:" << endl; + (*testout).precision(2); + for (i = 1; i <= ncl; i++) + { + (*testout) << setw(4) << double (i-1)/ncl << " - " + << setw(4) << double (i) / ncl << ": " + << incl.Get(i) << endl; + } + } + + + static double TetElementQuality (const Point3d & p1, const Point3d & p2, + const Point3d & p3, const Point3d & p4) + { + double vol, l, l4, l5, l6; + + + Vec3d v1 = p2 - p1; + Vec3d v2 = p3 - p1; + Vec3d v3 = p4 - p1; + + vol = fabs ((Cross (v1, v2) * v3)) / 6; + l4 = Dist (p2, p3); + l5 = Dist (p2, p4); + l6 = Dist (p3, p4); + + l = v1.Length() + v2.Length() + v3.Length() + l4 + l5 + l6; + + if (vol <= 1e-8 * l * l * l) return 1e-10; + + return vol/(l*l*l) * 1832.82; // 6^4 * sqrt(2) + } + + + + + + double teterrpow = 2; + + double CalcTetBadness (const Point3d & p1, const Point3d & p2, + const Point3d & p3, const Point3d & p4, double h) + { + double vol, l, ll, lll, ll1, ll2, ll3, ll4, ll5, ll6; + double err; + + Vec3d v1 (p1, p2); + Vec3d v2 (p1, p3); + Vec3d v3 (p1, p4); + + vol = -Determinant (v1, v2, v3) / 6; + + ll1 = v1.Length2(); + ll2 = v2.Length2(); + ll3 = v3.Length2(); + ll4 = Dist2 (p2, p3); + ll5 = Dist2 (p2, p4); + ll6 = Dist2 (p3, p4); + + ll = ll1 + ll2 + ll3 + ll4 + ll5 + ll6; + l = sqrt (ll); + lll = l * ll; + + if (vol <= 1e-24 * lll) + return 1e24; + + err = 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; + + 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, 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) / 6; + + 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; + + + + 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) + { + 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; + cout << "?"; + } + + double errpow = pow (err, teterrpow); + grad = (teterrpow * errpow / err) * graderr; + + return errpow; + } + + + + + + /* + + double CalcTetBadness (const Point3d & p1, const Point3d & p2, + const Point3d & p3, const Point3d & p4, double h) + { + double vol, l; + double err; + + + Vec3d v1 (p1, p2); + Vec3d v2 (p1, p3); + Vec3d v3 (p1, p4); + + vol = -Determinant (v1, v2, v3) / 6; + + double l1 = v1.Length(); + double l2 = v2.Length(); + double l3 = v3.Length(); + double l4 = Dist (p2, p3); + double l5 = Dist (p2, p4); + double l6 = Dist (p3, p4); + + l = l1 + l2 + l3 + l4 + l5 + l6; + + // just for timing + // l += 1e-40 * CalcTetBadnessNew (p1, p2, p3, p4, h); + + if (vol <= 1e-24 * l * l * l) + { + return 1e24; + } + + err = (l*l*l) / (1832.82 * vol); // 6^4 * sqrt(2) + + if (h > 0) + err += l / h + + h * (1 / l1 + 1/l2 + 1/l3 + 1/l4 + 1/l5 + 1/l6) - 12; + + return pow (err, teterrpow); + } + + + + double CalcTetBadnessGrad (const Point3d & p1, const Point3d & p2, + const Point3d & p3, const Point3d & p4, double h, + int pi, Vec3d & grad) + { + double vol, l; + double err; + + const Point3d *pp1, *pp2, *pp3, *pp4; + + pp1 = &p1; + pp2 = &p2; + pp3 = &p3; + pp4 = &p4; + + switch (pi) + { + case 2: + { + swap (pp1, pp2); + swap (pp3, pp4); + break; + } + case 3: + { + swap (pp1, pp3); + swap (pp2, pp4); + break; + } + case 4: + { + swap (pp1, pp4); + swap (pp3, pp2); + break; + } + } + + + Vec3d v1 (*pp1, *pp2); + Vec3d v2 (*pp1, *pp3); + Vec3d v3 (*pp1, *pp4); + + Vec3d v4 (*pp2, *pp3); + Vec3d v5 (*pp2, *pp4); + Vec3d v6 (*pp3, *pp4); + + + // Vec3d n; + // Cross (v1, v2, n); + // vol = - (n * v3) / 6; + + + vol = -Determinant (v1, v2, v3) / 6; + + Vec3d gradvol; + Cross (v5, v4, gradvol); + gradvol *= (-1.0/6.0); + + + double l1 = v1.Length(); + double l2 = v2.Length(); + double l3 = v3.Length(); + double l4 = v4.Length(); + double l5 = v5.Length(); + double l6 = v6.Length(); + + l = l1 + l2 + l3 +l4 + l5 + l6; + + Vec3d gradl1 (*pp2, *pp1); + Vec3d gradl2 (*pp3, *pp1); + Vec3d gradl3 (*pp4, *pp1); + gradl1 /= l1; + gradl2 /= l2; + gradl3 /= l3; + + Vec3d gradl (gradl1); + gradl += gradl2; + gradl += gradl3; + + + if (vol <= 1e-24 * l * l * l) + { + grad = Vec3d (0, 0, 0); + return 1e24; + } + + + double c1 = 1.0 / 1832.82; // 6^4 * sqrt(2) + err = c1 * (l*l*l) / vol; + + + gradl *= (c1 * 3 * l * l / vol); + Vec3d graderr(gradl); + gradvol *= ( -c1 * l * l * l / (vol * vol) ); + graderr+= gradvol; + + if (h > 0) + { + err += l / h + + h * ( 1 / l1 + 1 / l2 + 1 / l3 + + 1 / l4 + 1 / l5 + 1 / l6 ) - 12; + + graderr += (1/h - h/(l1*l1)) * gradl1; + graderr += (1/h - h/(l2*l2)) * gradl2; + graderr += (1/h - h/(l3*l3)) * gradl3; + cout << "?"; + } + + double errpow = pow (err, teterrpow); + grad = (teterrpow * errpow / err) * graderr; + + return errpow; + } + + */ + + + + + + /* + double CalcVolume (const ARRAY<Point3d> & points, + const Element & el) + { + Vec3d v1 = points.Get(el.PNum(2)) - + points.Get(el.PNum(1)); + Vec3d v2 = points.Get(el.PNum(3)) - + points.Get(el.PNum(1)); + Vec3d v3 = points.Get(el.PNum(4)) - + points.Get(el.PNum(1)); + + return -(Cross (v1, v2) * v3) / 6; + } + */ + + double CalcVolume (const ARRAY<Point3d> & points, + const ARRAY<Element> & elements) + { + double vol; + Vec3d v1, v2, v3; + + vol = 0; + for (int i = 0; i < elements.Size(); i++) + { + v1 = points.Get(elements[i][1]) - points.Get(elements[i][0]); + v2 = points.Get(elements[i][2]) - points.Get(elements[i][0]); + v3 = points.Get(elements[i][3]) - points.Get(elements[i][0]); + vol -= (Cross (v1, v2) * v3) / 6; + } + return vol; + } + + + + + void MeshQuality3d (const Mesh & mesh, ARRAY<int> * inclass) + { + int ncl = 20; + signed int cl; + ARRAY<INDEX> incl(ncl); + INDEX i; + double qual; + double sum = 0; + int nontet = 0; + + for (i = 1; i <= incl.Size(); i++) + incl.Elem(i) = 0; + + for (ElementIndex ei = 0; ei < mesh.GetNE(); ei++) + { + if (mesh[ei].GetType() != TET) + { + nontet++; + continue; + } + + qual = TetElementQuality (mesh.Point(mesh[ei][0]), + mesh.Point(mesh[ei][1]), + mesh.Point(mesh[ei][2]), + mesh.Point(mesh[ei][3])); + + if (qual > 1) qual = 1; + cl = int (ncl * qual ) + 1; + + if (cl < 1) cl = 1; + if (cl > ncl) cl = ncl; + + incl.Elem(cl)++; + if (inclass) (*inclass)[ei] = cl; + sum += 1/qual; + } + + (*testout) << endl << endl; + (*testout) << "Points: " << mesh.GetNP() << endl; + (*testout) << "Volume Elements: " << mesh.GetNE() << endl; + if (nontet) + (*testout) << nontet << " non tetrahedral elements" << endl; + (*testout) << endl; + + (*testout) << "Volume elements in qualityclasses:" << endl; + (*testout).precision(2); + for (i = 1; i <= ncl; i++) + { + (*testout) << setw(4) << double (i-1)/ncl << " - " + << setw(4) << double (i) / ncl << ": " + << incl.Get(i) << endl; + } + (*testout) << "total error: " << sum << endl; + } + + + void SaveEdges (const Mesh & mesh, const char * geomfile, double h, char * filename) + { + ofstream of (filename); + int i; + const Segment * seg; + + of << "edges" << endl; + of << geomfile << endl; + of << h << endl; + + of << mesh.GetNP() << endl; + for (i = 1; i <= mesh.GetNP(); i++) + of << mesh.Point(i).X() << " " + << mesh.Point(i).Y() << " " + << mesh.Point(i).Z() << "\n"; + + of << 2 * mesh.GetNSeg() << endl; + for (i = 1; i <= mesh.GetNSeg(); i++) + { + seg = &mesh.LineSegment(i); + + of << seg->p2 << " " << seg->p1 << " " << seg->si << "\n"; + } + + } + + + void SaveSurfaceMesh (const Mesh & mesh, + double h, + char * filename) + + { + INDEX i; + + ofstream outfile(filename); + + outfile << "surfacemesh" << endl; + outfile << h << endl; + + outfile << mesh.GetNP() << endl; + for (i = 1; i <= mesh.GetNP(); i++) + outfile << mesh.Point(i).X() << " " + << mesh.Point(i).Y() << " " + << mesh.Point(i).Z() << endl; + + + + outfile << mesh.GetNSE() << endl; + for (i = 1; i <= mesh.GetNSE(); i++) + { + const Element2d & el = mesh.SurfaceElement(i); + + if (mesh.GetFaceDescriptor(el.GetIndex()).DomainOut() == 0) + outfile << mesh.SurfaceElement(i).PNum(1) << " " + << mesh.SurfaceElement(i).PNum(2) << " " + << mesh.SurfaceElement(i).PNum(3) << endl; + if (mesh.GetFaceDescriptor(el.GetIndex()).DomainIn() == 0) + outfile << mesh.SurfaceElement(i).PNum(1) << " " + << mesh.SurfaceElement(i).PNum(3) << " " + << mesh.SurfaceElement(i).PNum(2) << endl; + } + } + + +#ifdef OLD + void Save2DMesh ( + const Mesh & mesh2d, + const ARRAY<SplineSegment *> * splines, + ostream & outfile) + + { + int i, j; + outfile.precision (6); + + outfile << "areamesh2" << endl; + + + outfile << endl; + outfile << mesh2d.GetNSeg() << endl; + for (i = 1; i <= mesh2d.GetNSeg(); i++) + outfile << mesh2d.LineSegment(i).si << " " + << mesh2d.LineSegment(i).p1 << " " + << mesh2d.LineSegment(i).p2 << " " << endl; + + + outfile << mesh2d.GetNSE() << endl; + for (i = 1; i <= mesh2d.GetNSE(); i++) + { + outfile << mesh2d.SurfaceElement(i).GetIndex() << " "; + outfile << mesh2d.SurfaceElement(i).GetNP() << " "; + for (j = 1; j <= mesh2d.SurfaceElement(i).GetNP(); j++) + outfile << mesh2d.SurfaceElement(i).PNum(j) << " "; + outfile << endl; + } + + outfile << mesh2d.GetNP() << endl; + for (i = 1; i <= mesh2d.GetNP(); i++) + outfile << mesh2d.Point(i).X() << " " + << mesh2d.Point(i).Y() << endl; + + if (splines) + { + outfile << splines->Size() << endl; + for (i = 1; i <= splines->Size(); i++) + splines->Get(i) -> PrintCoeff (outfile); + } + else + outfile << "0" << endl; + } +#endif + + + + + + + + + void SaveVolumeMesh (const Mesh & mesh, + const CSGeometry & geometry, + char * filename) + { + INDEX i; + + ofstream outfile(filename); + outfile << "volumemesh" << endl; + + outfile << mesh.GetNSE() << endl; + for (i = 1; i <= mesh.GetNSE(); i++) + { + if (mesh.SurfaceElement(i).GetIndex()) + outfile << mesh.GetFaceDescriptor(mesh.SurfaceElement(i).GetIndex ()).SurfNr() + << "\t"; + else + outfile << "0" << "\t"; + outfile << mesh.SurfaceElement(i)[0] << " " + << mesh.SurfaceElement(i)[1] << " " + << mesh.SurfaceElement(i)[2] << endl; + } + outfile << mesh.GetNE() << endl; + for (ElementIndex ei = 0; ei < mesh.GetNE(); ei++) + outfile << mesh[ei].GetIndex() << "\t" + << mesh[ei][0] << " " << mesh[ei][1] << " " + << mesh[ei][2] << " " << mesh[ei][3] << endl; + + outfile << mesh.GetNP() << endl; + for (i = 1; i <= mesh.GetNP(); i++) + outfile << mesh.Point(i).X() << " " + << mesh.Point(i).Y() << " " + << mesh.Point(i).Z() << endl; + +#ifdef SOLIDGEOM + outfile << geometry.GetNSurf() << endl; + for (i = 1; i <= geometry.GetNSurf(); i++) + geometry.GetSurface(i) -> Print (outfile); +#endif + } + + + + + int CheckCode () + { + return 1; + + /* + char st[100]; + ifstream ist("pw"); + + if (!ist.good()) return 0; + ist >> st; + if (strcmp (st, "JKULinz") == 0) return 1; + return 0; + */ + } + + + + /* ******************** CheckMesh ******************************* */ + + /// Checks, whether mesh contains a valid 3d mesh + int CheckMesh3D (const Mesh & mesh) + { + INDEX_3_HASHTABLE<int> faceused(mesh.GetNE()/3); + INDEX i; + int j, k, l; + INDEX_3 i3; + int ok = 1; + ElementIndex ei; + + for (i = 1; i <= mesh.GetNSE(); i++) + { + const Element2d & el = mesh.SurfaceElement(i); + + if (mesh.GetFaceDescriptor(el.GetIndex()).DomainIn() == 0 || + mesh.GetFaceDescriptor(el.GetIndex()).DomainOut() == 0) + { + for (j = 1; j <= 3; j++) + i3.I(j) = el.PNum(j); + + i3.Sort(); + faceused.Set (i3, 1); + } + } + + for (ei = 0; ei < mesh.GetNE(); ei++) + { + const Element & el = mesh[ei]; + + for (j = 1; j <= 4; j++) + { + l = 0; + for (k = 1; k <= 4; k++) + { + if (j != k) + { + l++; + i3.I(l) = el.PNum(k); + } + } + + i3.Sort(); + if (faceused.Used(i3)) + faceused.Set(i3, faceused.Get(i3)+1); + else + faceused.Set (i3, 1); + } + } + + + for (i = 1; i <= mesh.GetNSE(); i++) + { + const Element2d & el = mesh.SurfaceElement(i); + + for (j = 1; j <= 3; j++) + i3.I(j) = el.PNum(j); + + i3.Sort(); + k = faceused.Get (i3); + if (k != 2) + { + ok = 0; + (*testout) << "face " << i << " with points " + << i3.I1() << "-" << i3.I2() << "-" << i3.I3() + << " has " << k << " elements" << endl; + } + } + + for (ei = 0; ei < mesh.GetNE(); ei++) + { + const Element & el = mesh[ei]; + + for (j = 1; j <= 4; j++) + { + l = 0; + for (k = 1; k <= 4; k++) + { + if (j != k) + { + l++; + i3.I(l) = el.PNum(k); + } + } + + i3.Sort(); + k = faceused.Get(i3); + if (k != 2) + { + ok = 0; + (*testout) << "element " << ei << " with face " + << i3.I1() << "-" << i3.I2() << "-" + << i3.I3() + << " has " << k << " elements" << endl; + } + } + } + + + + + + /* + for (i = 1; i <= faceused.GetNBags(); i++) + for (j = 1; j <= faceused.GetBagSize(i); j++) + { + faceused.GetData(i, j, i3, k); + if (k != 2) + { + (*testout) << "Face: " << i3.I1() << "-" + << i3.I2() << "-" << i3.I3() << " has " + << k << " Faces " << endl; + cerr << "Face Error" << endl; + ok = 0; + } + } + */ + + + if (!ok) + { + (*testout) << "surfelements: " << endl; + for (i = 1; i <= mesh.GetNSE(); i++) + { + const Element2d & el = mesh.SurfaceElement(i); + (*testout) << setw(5) << i << ":" + << setw(6) << el.GetIndex() + << setw(6) << el.PNum(1) + << setw(4) << el.PNum(2) + << setw(4) << el.PNum(3) << endl; + } + (*testout) << "volelements: " << endl; + for (ElementIndex ei = 0; ei < mesh.GetNE(); ei++) + { + const Element & el = mesh[ei]; + (*testout) << setw(5) << i << ":" + << setw(6) << el.GetIndex() + << setw(6) << el[0] << setw(4) << el[1] + << setw(4) << el[2] << setw(4) << el[3] << endl; + } + } + + + return ok; + } + + + + void RemoveProblem (Mesh & mesh) + { + int i, j, k; + + mesh.FindOpenElements(); + int np = mesh.GetNP(); + + BitArrayChar<PointIndex::BASE> ppoints(np); + + int ndom = mesh.GetNDomains(); + + PrintMessage (3, "Elements before Remove: ", mesh.GetNE()); + for (k = 1; k <= ndom; k++) + { + ppoints.Clear(); + + for (i = 1; i <= mesh.GetNOpenElements(); i++) + { + const Element2d & sel = mesh.OpenElement(i); + if (sel.GetIndex() == k) + { + for (j = 1; j <= sel.GetNP(); j++) + ppoints.Set (sel.PNum(j)); + } + } + + for (ElementIndex ei = 0; ei < mesh.GetNE(); ei++) + { + const Element & el = mesh[ei]; + if (el.GetIndex() == k) + { + int todel = 0; + for (j = 0; j < el.GetNP(); j++) + if (ppoints.Test (el[j])) + todel = 1; + + if (el.GetNP() != 4) + todel = 0; + + if (todel) + { + mesh[ei].Delete(); + // ei--; + } + } + } + } + + mesh.Compress(); + PrintMessage (3, "Elements after Remove: ", mesh.GetNE()); + } + + +} diff --git a/contrib/Netgen/libsrc/meshing/meshtool.hpp b/contrib/Netgen/libsrc/meshing/meshtool.hpp new file mode 100644 index 0000000000..1baafe40ff --- /dev/null +++ b/contrib/Netgen/libsrc/meshing/meshtool.hpp @@ -0,0 +1,83 @@ +#ifndef FILE_MESHTOOL +#define FILE_MESHTOOL + + +/// +extern void MeshQuality2d (const Mesh & mesh); + +/// +extern void MeshQuality3d (const Mesh & mesh, + ARRAY<int> * inclass = NULL); + +/// +extern void SaveEdges (const Mesh & mesh, + const char * geomfile, + double h, + char * filename); + +/// +extern void SaveSurfaceMesh (const Mesh & mesh, + double h, + char * filename); +/* +/// +extern void Save2DMesh ( + const Mesh & mesh2d, + const ARRAY<class SplineSegment*> * splines, + ostream & outfile); +*/ + +class Surface; +/// +extern void SaveVolumeMesh ( + const ARRAY<Point3d> & points, + const ARRAY<Element> & elements, + const ARRAY<Element> & volelements, + const ARRAY<Surface*> & surfaces, + char * filename); + +/// +void SaveVolumeMesh (const Mesh & mesh, + const class CSGeometry & geometry, + char * filename); + +/// +extern int CheckCode (); + + +/// +extern double CalcTetBadness (const Point3d & p1, + const Point3d & p2, + const Point3d & p3, + const Point3d & p4, + double h); +/// +extern double CalcTetBadnessGrad (const Point3d & p1, + const Point3d & p2, + const Point3d & p3, + const Point3d & p4, + double h, int pi, + Vec3d & grad); + + +/** Calculates volume of an element. + The volume of the tetrahedron el is computed + */ +// extern double CalcVolume (const ARRAY<Point3d> & points, +// const Element & el); + +/** The total volume of all elements is computed. + This function calculates the volume of the mesh */ +extern double CalcVolume (const ARRAY<Point3d> & points, + const ARRAY<Element> & elements); + +/// +extern int CheckSurfaceMesh (const Mesh & mesh); + +/// +extern int CheckSurfaceMesh2 (const Mesh & mesh); +/// +extern int CheckMesh3D (const Mesh & mesh); +/// +extern void RemoveProblem (Mesh & mesh); +#endif diff --git a/contrib/Netgen/libsrc/meshing/meshtype.cpp b/contrib/Netgen/libsrc/meshing/meshtype.cpp new file mode 100644 index 0000000000..e26a0b48ce --- /dev/null +++ b/contrib/Netgen/libsrc/meshing/meshtype.cpp @@ -0,0 +1,2233 @@ +#include <mystdlib.h> + +#include "meshing.hpp" + + +namespace netgen +{ + + + + MultiPointGeomInfo :: MultiPointGeomInfo() + { + cnt = 0; + } + + int MultiPointGeomInfo :: + AddPointGeomInfo (const PointGeomInfo & gi) + { + for (int k = 0; k < cnt; k++) + if (mgi[k].trignum == gi.trignum) + return 0; + + if (cnt < MULTIPOINTGEOMINFO_MAX) + { + mgi[cnt] = gi; + cnt++; + return 0; + } + + throw NgException ("Please report error: MPGI Size too small\n"); + } + + + void MultiPointGeomInfo :: + Init () + { + cnt = 0; + } + + void MultiPointGeomInfo :: + DeleteAll () + { + cnt = 0; + } + + + + + Segment :: Segment() + { + p1 = -1; + p2 = -1; + edgenr = -1; + + singedge_left = 0; + singedge_right = 0; + seginfo = 0; + + si = -1; + + domin = -1; + domout = -1; + tlosurf = -1; + + surfnr1 = -1; + surfnr2 = -1; + pmid = -1; + meshdocval = 0; + /* + geominfo[0].trignum=-1; + geominfo[1].trignum=-1; + + epgeominfo[0].edgenr = 1; + epgeominfo[0].dist = 0; + epgeominfo[1].edgenr = 1; + epgeominfo[1].dist = 0; + */ + } + + + + Segment& Segment::operator=(const Segment & other) + { + p1 = other.p1; + p2 = other.p2; + edgenr = other.edgenr; + singedge_left = other.singedge_left; + singedge_right = other.singedge_right; + seginfo = other.seginfo; + si = other.si; + domin = other.domin; + domout = other.domout; + tlosurf = other.tlosurf; + geominfo[0] = other.geominfo[0]; + geominfo[1] = other.geominfo[1]; + surfnr1 = other.surfnr1; + surfnr2 = other.surfnr2; + epgeominfo[0] = other.epgeominfo[0]; + epgeominfo[1] = other.epgeominfo[1]; + pmid = other.pmid; + meshdocval = other.meshdocval; + + return *this; + } + + + ostream & operator<<(ostream & s, const Segment & seg) + { + s << seg.p1 << "(gi=" << seg.geominfo[0].trignum << ") - " + << seg.p2 << "(gi=" << seg.geominfo[1].trignum << ")" + << " si = " << seg.si; + return s; + } + + Element2d :: Element2d (int anp) + { + for (int i = 0; i < ELEMENT2D_MAXPOINTS; i++) + { + pnum[i] = 0; + geominfo[i].trignum = 0; + } + np = anp; + index = 0; + badel = 0; + deleted = 0; + switch (np) + { + case 3: typ = TRIG; break; + case 4: typ = QUAD; break; + case 6: typ = TRIG6; break; + case 8: typ = QUAD8; break; + } + order = 1; + refflag = 1; + } + + Element2d :: Element2d (ELEMENT_TYPE atyp) + { + for (int i = 0; i < ELEMENT2D_MAXPOINTS; i++) + { + pnum[i] = 0; + geominfo[i].trignum = 0; + } + + SetType (atyp); + + index = 0; + badel = 0; + deleted = 0; + order = 1; + refflag = 1; + } + + + + + Element2d :: Element2d (int pi1, int pi2, int pi3) +{ + pnum[0] = pi1; + pnum[1] = pi2; + pnum[2] = pi3; + np = 3; + typ = TRIG; + pnum[3] = 0; + pnum[4] = 0; + pnum[5] = 0; + + for (int i = 0; i < ELEMENT2D_MAXPOINTS; i++) + geominfo[i].trignum = 0; + index = 0; + badel = 0; + refflag = 1; + deleted = 0; + order = 1; +} + +Element2d :: Element2d (int pi1, int pi2, int pi3, int pi4) +{ + pnum[0] = pi1; + pnum[1] = pi2; + pnum[2] = pi3; + pnum[3] = pi4; + np = 4; + typ = QUAD; + + pnum[4] = 0; + pnum[5] = 0; + + for (int i = 0; i < ELEMENT2D_MAXPOINTS; i++) + geominfo[i].trignum = 0; + index = 0; + badel = 0; + refflag = 1; + deleted = 0; + order = 1; +} + + +/* +void Element2d :: SetType (ELEMENT_TYPE atyp) +{ + typ = atyp; + switch (typ) + { + case TRIG: np = 3; break; + case QUAD: np = 4; break; + case TRIG6: np = 6; break; + case QUAD6: np = 6; break; + default: + PrintSysError ("Element2d::SetType, illegal type ", typ); + } +} +*/ + + +void Element2d :: GetBox (const T_POINTS & points, Box3d & box) const +{ + box.SetPoint (points.Get(pnum[0])); + for (unsigned i = 1; i < np; i++) + box.AddPoint (points.Get(pnum[i])); +} + +void Element2d :: Invert2() +{ + switch (typ) + { + case TRIG: + { + Swap (pnum[1], pnum[2]); + break; + } + case QUAD: + { + Swap (pnum[0], pnum[3]); + Swap (pnum[1], pnum[2]); + break; + } + default: + { + cerr << "Element2d::Invert2, illegal element type " << int(typ) << endl; + } + } +} + +int Element2d::HasFace(const Element2d& el) const +{ + //nur f�r tets!!! hannes + for (int i = 1; i <= 3; i++) + { + if (PNumMod(i) == el[0] && + PNumMod(i+1) == el[1] && + PNumMod(i+2) == el[2]) + { + return 1; + } + } + return 0; +} + +void Element2d :: NormalizeNumbering2 () +{ + if (GetNP() == 3) + { + PointIndex pi1; + if (PNum(1) < PNum(2) && PNum(1) < PNum(3)) + return; + else + { + if (PNum(2) < PNum(3)) + { + pi1 = PNum(2); + PNum(2) = PNum(3); + PNum(3) = PNum(1); + PNum(1) = pi1; + } + else + { + pi1 = PNum(3); + PNum(3) = PNum(2); + PNum(2) = PNum(1); + PNum(1) = pi1; + } + } + } + else + { + int mini = 1; + for (int i = 2; i <= GetNP(); i++) + if (PNum(i) < PNum(mini)) mini = i; + + Element2d hel = (*this); + for (int i = 1; i <= GetNP(); i++) + PNum(i) = hel.PNumMod (i+mini-1); + } +} + + + + +ARRAY<IntegrationPointData*> ipdtrig; +ARRAY<IntegrationPointData*> ipdquad; + + +int Element2d :: GetNIP () const +{ + int nip; + switch (np) + { + case 3: nip = 1; break; + case 4: nip = 4; break; + default: nip = 0; break; + } + return nip; +} + +void Element2d :: +GetIntegrationPoint (int ip, Point2d & p, double & weight) const +{ + static double eltriqp[1][3] = + { + { 1.0/3.0, 1.0/3.0, 0.5 } + }; + + static double elquadqp[4][3] = + { + { 0, 0, 0.25 }, + { 0, 1, 0.25 }, + { 1, 0, 0.25 }, + { 1, 1, 0.25 } + }; + + double * pp = 0; + switch (typ) + { + case TRIG: pp = &eltriqp[0][0]; break; + case QUAD: pp = &elquadqp[ip-1][0]; break; + default: + PrintSysError ("Element2d::GetIntegrationPoint, illegal type ", typ); + } + + p.X() = pp[0]; + p.Y() = pp[1]; + weight = pp[2]; +} + +void Element2d :: +GetTransformation (int ip, const ARRAY<Point2d> & points, + DenseMatrix & trans) const +{ + int np = GetNP(); + static DenseMatrix pmat(2, np), dshape(2, np); + pmat.SetSize (2, np); + dshape.SetSize (2, np); + + Point2d p; + double w; + + GetPointMatrix (points, pmat); + GetIntegrationPoint (ip, p, w); + GetDShape (p, dshape); + + CalcABt (pmat, dshape, trans); + + /* + (*testout) << "p = " << p << endl + << "pmat = " << pmat << endl + << "dshape = " << dshape << endl + << "tans = " << trans << endl; + */ +} + +void Element2d :: +GetTransformation (int ip, class DenseMatrix & pmat, + class DenseMatrix & trans) const +{ + int np = GetNP(); + +#ifdef DEBUG + if (pmat.Width() != np || pmat.Height() != 2) + { + (*testout) << "GetTransofrmation: pmat doesn't fit" << endl; + return; + } +#endif + + ComputeIntegrationPointData (); + DenseMatrix * dshapep; + switch (typ) + { + case TRIG: dshapep = &ipdtrig.Get(ip)->dshape; break; + case QUAD: dshapep = &ipdquad.Get(ip)->dshape; break; + default: + PrintSysError ("Element2d::GetTransformation, illegal type ", typ); + } + + CalcABt (pmat, *dshapep, trans); +} + + + +void Element2d :: GetShape (const Point2d & p, Vector & shape) const +{ + if (shape.Size() != GetNP()) + { + cerr << "Element::GetShape: Length not fitting" << endl; + return; + } + + switch (typ) + { + case TRIG: + shape.Elem(1) = 1 - p.X() - p.Y(); + shape.Elem(2) = p.X(); + shape.Elem(3) = p.Y(); + break; + case QUAD: + shape.Elem(1) = (1-p.X()) * (1-p.Y()); + shape.Elem(2) = p.X() * (1-p.Y()); + shape.Elem(3) = p.X() * p.Y(); + shape.Elem(4) = (1-p.X()) * p.Y(); + break; + default: + PrintSysError ("Element2d::GetShape, illegal type ", typ); + } +} + +void Element2d :: +GetDShape (const Point2d & p, DenseMatrix & dshape) const +{ +#ifdef DEBUG + if (dshape.Height() != 2 || dshape.Width() != np) + { + PrintSysError ("Element::DShape: Sizes don't fit"); + return; + } +#endif + + switch (typ) + { + case TRIG: + dshape.Elem(1, 1) = -1; + dshape.Elem(1, 2) = 1; + dshape.Elem(1, 3) = 0; + dshape.Elem(2, 1) = -1; + dshape.Elem(2, 2) = 0; + dshape.Elem(2, 3) = 1; + break; + case QUAD: + dshape.Elem(1, 1) = -(1-p.Y()); + dshape.Elem(1, 2) = (1-p.Y()); + dshape.Elem(1, 3) = p.Y(); + dshape.Elem(1, 4) = -p.Y(); + dshape.Elem(2, 1) = -(1-p.X()); + dshape.Elem(2, 2) = -p.X(); + dshape.Elem(2, 3) = p.X(); + dshape.Elem(2, 4) = (1-p.X()); + break; + + default: + PrintSysError ("Element2d::GetDShape, illegal type ", typ); + } +} + + +void Element2d :: +GetPointMatrix (const ARRAY<Point2d> & points, + DenseMatrix & pmat) const +{ + int np = GetNP(); + +#ifdef DEBUG + if (pmat.Width() != np || pmat.Height() != 2) + { + cerr << "Element::GetPointMatrix: sizes don't fit" << endl; + return; + } +#endif + + for (int i = 1; i <= np; i++) + { + const Point2d & p = points.Get(PNum(i)); + pmat.Elem(1, i) = p.X(); + pmat.Elem(2, i) = p.Y(); + } +} + + + + + +double Element2d :: CalcJacobianBadness (const ARRAY<Point2d> & points) const +{ + int i, j; + int nip = GetNIP(); + static DenseMatrix trans(2,2); + static DenseMatrix pmat; + + pmat.SetSize (2, GetNP()); + GetPointMatrix (points, pmat); + + double err = 0; + for (i = 1; i <= nip; i++) + { + GetTransformation (i, pmat, trans); + + // Frobenius norm + double frob = 0; + for (j = 1; j <= 4; j++) + frob += sqr (trans.Get(j)); + frob = sqrt (frob); + frob /= 2; + + double det = trans.Det(); + + if (det <= 0) + err += 1e12; + else + err += frob * frob / det; + } + + err /= nip; + return err; +} + + + +static const int qip_table[4][4] = + { { 0, 1, 0, 3 }, + { 0, 1, 1, 2 }, + { 3, 2, 0, 3 }, + { 3, 2, 1, 2 } + }; + +double Element2d :: +CalcJacobianBadnessDirDeriv (const ARRAY<Point2d> & points, + int pi, Vec2d & dir, double & dd) const +{ + if (typ == QUAD) + { + Mat<2,2> trans, dtrans; + Mat<2,4> vmat, pmat; + + for (int j = 0; j < 4; j++) + { + const Point2d & p = points.Get( (*this)[j] ); + pmat(0, j) = p.X(); + pmat(1, j) = p.Y(); + } + + vmat = 0.0; + vmat(0, pi-1) = dir.X(); + vmat(1, pi-1) = dir.Y(); + + double err = 0; + dd = 0; + + for (int i = 0; i < 4; i++) + { + int ix1 = qip_table[i][0]; + int ix2 = qip_table[i][1]; + int iy1 = qip_table[i][2]; + int iy2 = qip_table[i][3]; + + trans(0,0) = pmat(0, ix2) - pmat(0,ix1); + trans(1,0) = pmat(1, ix2) - pmat(1,ix1); + trans(0,1) = pmat(0, iy2) - pmat(0,iy1); + trans(1,1) = pmat(1, iy2) - pmat(1,iy1); + + double det = trans(0,0)*trans(1,1)-trans(1,0)*trans(0,1); + + if (det <= 0) + { + dd = 0; + return 1e12; + } + + dtrans(0,0) = vmat(0, ix2) - vmat(0,ix1); + dtrans(1,0) = vmat(1, ix2) - vmat(1,ix1); + dtrans(0,1) = vmat(0, iy2) - vmat(0,iy1); + dtrans(1,1) = vmat(1, iy2) - vmat(1,iy1); + + + // Frobenius norm + double frob = 0; + for (int j = 0; j < 4; j++) + frob += sqr (trans(j)); + frob = sqrt (frob); + + double dfrob = 0; + for (int j = 0; j < 4; j++) + dfrob += trans(j) * dtrans(j); + dfrob = dfrob / frob; + + frob /= 2; + dfrob /= 2; + + + // ddet = \sum_j det (m_j) with m_j = trans, except col j = dtrans + double ddet + = dtrans(0,0) * trans(1,1) - trans(0,1) * dtrans(1,0) + + trans(0,0) * dtrans(1,1) - dtrans(0,1) * trans(1,0); + + err += frob * frob / det; + dd += (2 * frob * dfrob * det - frob * frob * ddet) / (det * det); + } + + err /= 4; + dd /= 4; + return err; + } + + int nip = GetNIP(); + static DenseMatrix trans(2,2), dtrans(2,2); + static DenseMatrix pmat, vmat; + + pmat.SetSize (2, GetNP()); + vmat.SetSize (2, GetNP()); + + GetPointMatrix (points, pmat); + + vmat = 0.0; + vmat.Elem(1, pi) = dir.X(); + vmat.Elem(2, pi) = dir.Y(); + + + double err = 0; + dd = 0; + + for (int i = 1; i <= nip; i++) + { + GetTransformation (i, pmat, trans); + GetTransformation (i, vmat, dtrans); + + // Frobenius norm + double frob = 0; + for (int j = 1; j <= 4; j++) + frob += sqr (trans.Get(j)); + frob = sqrt (frob); + + double dfrob = 0; + for (int j = 1; j <= 4; j++) + dfrob += trans.Get(j) * dtrans.Get(j); + dfrob = dfrob / frob; + + frob /= 2; + dfrob /= 2; + + double det = trans(0,0)*trans(1,1)-trans(1,0)*trans(0,1); + + // ddet = \sum_j det (m_j) with m_j = trans, except col j = dtrans + double ddet + = dtrans(0,0) * trans(1,1) - trans(0,1) * dtrans(1,0) + + trans(0,0) * dtrans(1,1) - dtrans(0,1) * trans(1,0); + + if (det <= 0) + err += 1e12; + else + { + err += frob * frob / det; + dd += (2 * frob * dfrob * det - frob * frob * ddet) / (det * det); + } + } + + err /= nip; + dd /= nip; + return err; +} + + + +double Element2d :: +CalcJacobianBadness (const T_POINTS & points, const Vec3d & n) const +{ + int i, j; + int nip = GetNIP(); + static DenseMatrix trans(2,2); + static DenseMatrix pmat; + + pmat.SetSize (2, GetNP()); + + Vec3d t1, t2; + n.GetNormal(t1); + Cross (n, t1, t2); + + for (i = 1; i <= nip; i++) + { + const Point3d & p = points.Get(PNum(i)); + pmat.Elem(1, i) = p.X() * t1.X() + p.Y() * t1.Y() + p.Z() * t1.Z(); + pmat.Elem(2, i) = p.X() * t2.X() + p.Y() * t2.Y() + p.Z() * t2.Z(); + } + + double err = 0; + for (i = 1; i <= nip; i++) + { + GetTransformation (i, pmat, trans); + + // Frobenius norm + double frob = 0; + for (j = 1; j <= 4; j++) + frob += sqr (trans.Get(j)); + frob = sqrt (frob); + frob /= 2; + + double det = trans.Det(); + if (det <= 0) + err += 1e12; + else + err += frob * frob / det; + } + + err /= nip; + return err; +} + + + +void Element2d :: ComputeIntegrationPointData () const +{ + switch (np) + { + case 3: if (ipdtrig.Size()) return; break; + case 4: if (ipdquad.Size()) return; break; + } + + for (int i = 1; i <= GetNIP(); i++) + { + IntegrationPointData * ipd = new IntegrationPointData; + Point2d hp; + GetIntegrationPoint (i, hp, ipd->weight); + ipd->p.X() = hp.X(); + ipd->p.Y() = hp.Y(); + ipd->p.Z() = 0; + + ipd->shape.SetSize(GetNP()); + ipd->dshape.SetSize(2, GetNP()); + + GetShape (hp, ipd->shape); + GetDShape (hp, ipd->dshape); + + switch (np) + { + case 3: ipdtrig.Append (ipd); break; + case 4: ipdquad.Append (ipd); break; + } + } +} + + + + + + + + + + +ostream & operator<<(ostream & s, const Element2d & el) +{ + s << "np = " << el.GetNP(); + for (int j = 1; j <= el.GetNP(); j++) + s << " " << el.PNum(j); + return s; +} + + +ostream & operator<<(ostream & s, const Element & el) +{ + s << "np = " << el.GetNP(); + for (int j = 0; j < el.GetNP(); j++) + s << " " << int(el[j]); + return s; +} + + +Element :: Element () +{ + typ = TET; + np = 4; + for (int i = 0; i < ELEMENT_MAXPOINTS; i++) + pnum[i] = 0; + index = 0; + flags.marked = 1; + flags.badel = 0; + flags.reverse = 0; + flags.illegal = 0; + flags.illegal_valid = 0; + flags.badness_valid = 0; + flags.refflag = 1; + flags.deleted = 0; + order = 1; + partitionNumber = -1; +} + + +Element :: Element (int anp) +{ + np = anp; + int i; + for (i = 0; i < ELEMENT_MAXPOINTS; i++) + pnum[i] = 0; + index = 0; + flags.marked = 1; + flags.badel = 0; + flags.reverse = 0; + flags.illegal = 0; + flags.illegal_valid = 0; + flags.badness_valid = 0; + flags.refflag = 1; + flags.deleted = 0; + switch (np) + { + case 4: typ = TET; break; + case 5: typ = PYRAMID; break; + case 6: typ = PRISM; break; + case 8: typ = HEX; break; + case 10: typ = TET10; break; + default: cerr << "Element::Element: unknown element with " << np << " points" << endl; + } + order = 1; +} + + +Element :: Element (ELEMENT_TYPE type) +{ + SetType (type); + + int i; + for (i = 0; i < ELEMENT_MAXPOINTS; i++) + pnum[i] = 0; + index = 0; + flags.marked = 1; + flags.badel = 0; + flags.reverse = 0; + flags.illegal = 0; + flags.illegal_valid = 0; + flags.badness_valid = 0; + flags.refflag = 1; + flags.deleted = 0; + order = 1; +} + + + + + +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; + order = el2.order; + hp_elnr = el2.hp_elnr; + return *this; +} + + + +void Element :: SetNP (int anp) +{ + np = anp; + switch (np) + { + case 4: typ = TET; break; + case 5: typ = PYRAMID; break; + case 6: typ = PRISM; break; + case 8: typ = HEX; break; + case 10: typ = TET10; break; + // + default: break; + cerr << "Element::SetNP unknown element with " << np << " points" << endl; + } +} + + + +void Element :: SetType (ELEMENT_TYPE atyp) +{ + typ = atyp; + switch (atyp) + { + case TET: np = 4; break; + case PYRAMID: np = 5; break; + case PRISM: np = 6; break; + case HEX: np = 8; break; + case TET10: np = 10; break; + case PRISM12: np = 12; break; + } +} + + + +void Element :: Invert() +{ + switch (GetNP()) + { + case 4: + { + Swap (PNum(3), PNum(4)); + break; + } + case 5: + { + Swap (PNum(1), PNum(4)); + Swap (PNum(2), PNum(3)); + break; + } + case 6: + { + Swap (PNum(1), PNum(4)); + Swap (PNum(2), PNum(5)); + Swap (PNum(3), PNum(6)); + break; + } + } +} + + +void Element :: Print (ostream & ost) const +{ + ost << np << " Points: "; + for (int i = 1; i <= np; i++) + ost << pnum[i-1] << " " << endl; +} + +void Element :: GetBox (const T_POINTS & points, Box3d & box) const +{ + box.SetPoint (points.Get(PNum(1))); + box.AddPoint (points.Get(PNum(2))); + box.AddPoint (points.Get(PNum(3))); + box.AddPoint (points.Get(PNum(4))); +} + +double Element :: Volume (const T_POINTS & points) const +{ + Vec3d v1 = points.Get(PNum(2)) - + points.Get(PNum(1)); + Vec3d v2 = points.Get(PNum(3)) - + points.Get(PNum(1)); + Vec3d v3 = points.Get(PNum(4)) - + points.Get(PNum(1)); + + return -(Cross (v1, v2) * v3) / 6; +} + + +void Element :: GetFace2 (int i, Element2d & face) const +{ + static const int tetfaces[][5] = + { { 3, 2, 3, 4, 0 }, + { 3, 3, 1, 4, 0 }, + { 3, 1, 2, 4, 0 }, + { 3, 2, 1, 3, 0 } }; + + static const int pyramidfaces[][5] = + { { 4, 1, 4, 3, 2 }, + { 3, 1, 2, 5, 0 }, + { 3, 2, 3, 5, 0 }, + { 3, 3, 4, 5, 0 }, + { 3, 4, 1, 5, 0 } }; + + static const int prismfaces[][5] = + { + { 3, 1, 3, 2, 0 }, + { 3, 4, 5, 6, 0 }, + { 4, 1, 2, 5, 4 }, + { 4, 2, 3, 6, 5 }, + { 4, 3, 1, 4, 6 } + }; + + switch (np) + { + case 4: // tet + case 10: // tet + { + face.SetType(TRIG); + for (int j = 1; j <= 3; j++) + face.PNum(j) = PNum(tetfaces[i-1][j]); + break; + } + case 5: // pyramid + { + // face.SetNP(pyramidfaces[i-1][0]); + face.SetType ( (i == 1) ? QUAD : TRIG); + for (int j = 1; j <= face.GetNP(); j++) + face.PNum(j) = PNum(pyramidfaces[i-1][j]); + break; + } + case 6: // prism + { + // face.SetNP(prismfaces[i-1][0]); + face.SetType ( (i >= 3) ? QUAD : TRIG); + for (int j = 1; j <= face.GetNP(); j++) + face.PNum(j) = PNum(prismfaces[i-1][j]); + break; + } + } +} + + + +void Element :: GetTets (ARRAY<Element> & locels) const +{ + GetTetsLocal (locels); + int i, j; + for (i = 1; i <= locels.Size(); i++) + for (j = 1; j <= 4; j++) + locels.Elem(i).PNum(j) = PNum ( locels.Elem(i).PNum(j) ); +} + +void Element :: GetTetsLocal (ARRAY<Element> & locels) const +{ + int i, j; + locels.SetSize(0); + switch (GetType()) + { + case TET: + { + int linels[1][4] = + { { 1, 2, 3, 4 }, + }; + for (i = 0; i < 1; i++) + { + Element tet(4); + for (j = 1; j <= 4; j++) + tet.PNum(j) = linels[i][j-1]; + locels.Append (tet); + } + break; + } + case TET10: + { + int linels[8][4] = + { { 1, 5, 6, 7 }, + { 5, 2, 8, 9 }, + { 6, 8, 3, 10 }, + { 7, 9, 10, 4 }, + { 5, 6, 7, 9 }, + { 5, 6, 9, 8 }, + { 6, 7, 9, 10 }, + { 6, 8, 10, 9 } }; + for (i = 0; i < 8; i++) + { + Element tet(4); + for (j = 1; j <= 4; j++) + tet.PNum(j) = linels[i][j-1]; + locels.Append (tet); + } + break; + } + case PYRAMID: + { + int linels[2][4] = + { { 1, 2, 3, 5 }, + { 1, 3, 4, 5 } }; + for (i = 0; i < 2; i++) + { + Element tet(4); + for (j = 1; j <= 4; j++) + tet.PNum(j) = linels[i][j-1]; + locels.Append (tet); + } + break; + } + case PRISM: + case PRISM12: + { + int linels[3][4] = + { { 1, 2, 3, 4 }, + { 4, 2, 3, 5 }, + { 6, 5, 4, 3 } + }; + for (i = 0; i < 3; i++) + { + Element tet(4); + for (j = 0; j < 4; j++) + tet[j] = linels[i][j]; + locels.Append (tet); + } + break; + } + case HEX: + { + int linels[6][4] = + { { 1, 7, 2, 3 }, + { 1, 7, 3, 4 }, + { 1, 7, 4, 8 }, + { 1, 7, 8, 5 }, + { 1, 7, 5, 6 }, + { 1, 7, 6, 2 } + }; + for (i = 0; i < 6; i++) + { + Element tet(4); + for (j = 0; j < 4; j++) + tet[j] = linels[i][j]; + locels.Append (tet); + } + break; + } + default: + { + cerr << "GetTetsLocal not implemented for el with " << GetNP() << " nodes" << endl; + } + } +} + +void Element :: GetNodesLocal (ARRAY<Point3d> & points) const +{ + const static double tetpoints[4][3] = + { { 0, 0, 0 }, + { 1, 0, 0 }, + { 0, 1, 0 }, + { 0, 0, 1 }}; + + const static double prismpoints[6][3] = + { { 0, 0, 0 }, + { 1, 0, 0 }, + { 0, 1, 0 }, + { 0, 0, 1 }, + { 1, 0, 1 }, + { 0, 1, 1 } }; + + const static double pyramidpoints[6][3] = + { { 0, 0, 0 }, + { 1, 0, 0 }, + { 1, 1, 0 }, + { 0, 1, 0 }, + { 0, 0, 1 } }; + + const static double tet10points[10][3] = + { { 0, 0, 0 }, + { 1, 0, 0 }, + { 0, 1, 0 }, + { 0, 0, 1 }, + { 0.5, 0, 0 }, + { 0, 0.5, 0 }, + { 0, 0, 0.5 }, + { 0.5, 0.5, 0 }, + { 0.5, 0, 0.5 }, + { 0, 0.5, 0.5 } }; + + const static double hexpoints[8][3] = + { + { 0, 0, 0 }, + { 1, 0, 0 }, + { 1, 1, 0 }, + { 1, 0, 0 }, + { 0, 0, 1 }, + { 1, 0, 1 }, + { 1, 1, 1 }, + { 1, 0, 1 } + }; + + int np, i; + const double (*pp)[3]; + switch (GetType()) + { + case TET: + { + np = 4; + pp = tetpoints; + break; + } + case PRISM: + case PRISM12: + { + np = 6; + pp = prismpoints; + break; + } + case TET10: + { + np = 10; + pp = tet10points; + break; + } + case PYRAMID: + { + np = 5; + pp = pyramidpoints; + break; + } + case HEX: + { + np = 8; + pp = hexpoints; + break; + } + default: + { + cout << "GetNodesLocal not impelemented for element " << GetType() << endl; + np = 0; + } + } + + points.SetSize(0); + for (i = 0; i < np; i++) + points.Append (Point3d (pp[i][0], pp[i][1], pp[i][2])); +} + + + + + + + +void Element :: GetNodesLocalNew (ARRAY<Point3d> & points) const +{ + const static double tetpoints[4][3] = + { + { 1, 0, 0 }, + { 0, 1, 0 }, + { 0, 0, 1 }, + { 0, 0, 0 } + }; + + const static double prismpoints[6][3] = + { + { 1, 0, 0 }, + { 0, 1, 0 }, + { 0, 0, 0 }, + { 1, 0, 1 }, + { 0, 1, 1 }, + { 0, 0, 1 } + }; + + const static double pyramidpoints[6][3] = + { { 0, 0, 0 }, + { 1, 0, 0 }, + { 1, 1, 0 }, + { 0, 1, 0 }, + { 0, 0, 1 } }; + + const static double tet10points[10][3] = + { { 0, 0, 0 }, + { 1, 0, 0 }, + { 0, 1, 0 }, + { 0, 0, 1 }, + { 0.5, 0, 0 }, + { 0, 0.5, 0 }, + { 0, 0, 0.5 }, + { 0.5, 0.5, 0 }, + { 0.5, 0, 0.5 }, + { 0, 0.5, 0.5 } }; + + const static double hexpoints[8][3] = + { + { 0, 0, 0 }, + { 1, 0, 0 }, + { 1, 1, 0 }, + { 0, 1, 0 }, + { 0, 0, 1 }, + { 1, 0, 1 }, + { 1, 1, 1 }, + { 0, 1, 1 } + }; + + + + int np, i; + const double (*pp)[3]; + switch (GetType()) + { + case TET: + { + np = 4; + pp = tetpoints; + break; + } + case PRISM: + case PRISM12: + { + np = 6; + pp = prismpoints; + break; + } + case TET10: + { + np = 10; + pp = tet10points; + break; + } + case PYRAMID: + { + np = 5; + pp = pyramidpoints; + break; + } + case HEX: + { + np = 8; + pp = hexpoints; + break; + } + default: + { + cout << "GetNodesLocal not impelemented for element " << GetType() << endl; + np = 0; + } + } + + points.SetSize(0); + for (i = 0; i < np; i++) + points.Append (Point3d (pp[i][0], pp[i][1], pp[i][2])); +} + + + + + + + + + + + + + + + + + +void Element :: GetSurfaceTriangles (ARRAY<Element2d> & surftrigs) const +{ + static int tet4trigs[][3] = + { { 2, 3, 4 }, + { 3, 1, 4 }, + { 1, 2, 4 }, + { 2, 1, 3 } }; + + // just a few: + static int tet10trigs[][3] = + { { 2, 8, 9 }, + { 3, 10, 8}, + { 4, 9, 10 }, + { 9, 8, 10 }, + { 3, 1, 4 }, + { 1, 2, 4 }, + { 2, 1, 3 } }; + + static int pyramidtrigs[][3] = + { + { 1, 3, 2 }, + { 1, 4, 3 }, + { 1, 2, 5 }, + { 2, 3, 5 }, + { 3, 4, 5 }, + { 4, 1, 5 } + }; + + static int prismtrigs[][3] = + { + { 1, 3, 2 }, + { 4, 5, 6 }, + { 1, 2, 4 }, + { 4, 2, 5 }, + { 2, 3, 5 }, + { 5, 3, 6 }, + { 3, 1, 6 }, + { 6, 1, 4 } + }; + + static int hextrigs[][3] = + { + { 1, 3, 2 }, + { 1, 4, 3 }, + { 5, 6, 7 }, + { 5, 7, 8 }, + { 1, 2, 6 }, + { 1, 6, 5 }, + { 2, 3, 7 }, + { 2, 7, 6 }, + { 3, 4, 8 }, + { 3, 8, 7 }, + { 4, 1, 8 }, + { 1, 5, 8 } + }; + + int j; + + int nf; + int (*fp)[3]; + + switch (GetType()) + { + case TET: + { + nf = 4; + fp = tet4trigs; + break; + } + case PYRAMID: + { + nf = 6; + fp = pyramidtrigs; + break; + } + case PRISM: + case PRISM12: + { + nf = 8; + fp = prismtrigs; + break; + } + case TET10: + { + nf = 7; + fp = tet10trigs; + break; + } + case HEX: + { + nf = 12; + fp = hextrigs; + break; + } + default: + { + nf = 0; + fp = NULL; + } + } + + + surftrigs.SetSize (nf); + for (j = 0; j < nf; j++) + { + surftrigs.Elem(j+1) = Element2d(3); + surftrigs.Elem(j+1).PNum(1) = fp[j][0]; + surftrigs.Elem(j+1).PNum(2) = fp[j][1]; + surftrigs.Elem(j+1).PNum(3) = fp[j][2]; + } +} + + + + + +ARRAY<IntegrationPointData*> ipdtet; +ARRAY<IntegrationPointData*> ipdtet10; + + +int Element :: GetNIP () const +{ + int nip; + switch (typ) + { + case TET: nip = 1; break; + case TET10: nip = 8; break; + default: nip = 0; break; + } + return nip; +} + +void Element :: +GetIntegrationPoint (int ip, Point3d & p, double & weight) const +{ + static double eltetqp[1][4] = + { + { 0.25, 0.25, 0.25, 1.0/6.0 } + }; + + static double eltet10qp[8][4] = + { + { 0.585410196624969, 0.138196601125011, 0.138196601125011, 1.0/24.0 }, + { 0.138196601125011, 0.585410196624969, 0.138196601125011, 1.0/24.0 }, + { 0.138196601125011, 0.138196601125011, 0.585410196624969, 1.0/24.0 }, + { 0.138196601125011, 0.138196601125011, 0.138196601125011, 1.0/24.0 }, + { 1, 0, 0, 1 }, + { 0, 1, 0, 1 }, + { 0, 0, 1, 1 }, + { 0, 0, 0, 1 }, + }; + + double * pp; + switch (typ) + { + case TET: pp = &eltetqp[0][0]; break; + case TET10: pp = &eltet10qp[ip-1][0]; break; + } + + p.X() = pp[0]; + p.Y() = pp[1]; + p.Z() = pp[2]; + weight = pp[3]; +} + +void Element :: +GetTransformation (int ip, const T_POINTS & points, + DenseMatrix & trans) const +{ + int np = GetNP(); + static DenseMatrix pmat(3, np), dshape(3, np); + pmat.SetSize (3, np); + dshape.SetSize (3, np); + + Point3d p; + double w; + + GetPointMatrix (points, pmat); + GetIntegrationPoint (ip, p, w); + GetDShape (p, dshape); + + CalcABt (pmat, dshape, trans); + + /* + (*testout) << "p = " << p << endl + << "pmat = " << pmat << endl + << "dshape = " << dshape << endl + << "tans = " << trans << endl; + */ +} + +void Element :: +GetTransformation (int ip, class DenseMatrix & pmat, + class DenseMatrix & trans) const +{ + int np = GetNP(); + + if (pmat.Width() != np || pmat.Height() != 3) + { + (*testout) << "GetTransofrmation: pmat doesn't fit" << endl; + return; + } + + ComputeIntegrationPointData (); + DenseMatrix * dshapep; + switch (GetType()) + { + case TET: dshapep = &ipdtet.Get(ip)->dshape; break; + case TET10: dshapep = &ipdtet10.Get(ip)->dshape; break; + } + + CalcABt (pmat, *dshapep, trans); +} + + + +void Element :: GetShape (const Point3d & p, Vector & shape) const +{ + if (shape.Size() != GetNP()) + { + cerr << "Element::GetShape: Length not fitting" << endl; + return; + } + + switch (typ) + { + case TET: + { + shape.Elem(1) = 1 - p.X() - p.Y() - p.Z(); + shape.Elem(2) = p.X(); + shape.Elem(3) = p.Y(); + shape.Elem(4) = p.Z(); + break; + } + case TET10: + { + double lam1 = 1 - p.X() - p.Y() - p.Z(); + double lam2 = p.X(); + double lam3 = p.Y(); + double lam4 = p.Z(); + + shape.Elem(5) = 4 * lam1 * lam2; + shape.Elem(6) = 4 * lam1 * lam3; + shape.Elem(7) = 4 * lam1 * lam4; + shape.Elem(8) = 4 * lam2 * lam3; + shape.Elem(9) = 4 * lam2 * lam4; + shape.Elem(10) = 4 * lam3 * lam4; + + shape.Elem(1) = lam1 - + 0.5 * (shape.Elem(5) + shape.Elem(6) + shape.Elem(7)); + shape.Elem(2) = lam2 - + 0.5 * (shape.Elem(5) + shape.Elem(8) + shape.Elem(9)); + shape.Elem(3) = lam3 - + 0.5 * (shape.Elem(6) + shape.Elem(8) + shape.Elem(10)); + shape.Elem(4) = lam4 - + 0.5 * (shape.Elem(7) + shape.Elem(9) + shape.Elem(10)); + break; + } + + case PRISM: + { + Point<3> hp = p; + shape(0) = hp(0) * (1-hp(2)); + shape(1) = hp(1) * (1-hp(2)); + shape(2) = (1-hp(0)-hp(1)) * (1-hp(2)); + shape(3) = hp(0) * hp(2); + shape(4) = hp(1) * hp(2); + shape(5) = (1-hp(0)-hp(1)) * hp(2); + break; + } + case HEX: + { + Point<3> hp = p; + shape(0) = (1-hp(0))*(1-hp(1))*(1-hp(2)); + shape(1) = ( hp(0))*(1-hp(1))*(1-hp(2)); + shape(2) = ( hp(0))*( hp(1))*(1-hp(2)); + shape(3) = (1-hp(0))*( hp(1))*(1-hp(2)); + shape(4) = (1-hp(0))*(1-hp(1))*( hp(2)); + shape(5) = ( hp(0))*(1-hp(1))*( hp(2)); + shape(6) = ( hp(0))*( hp(1))*( hp(2)); + shape(7) = (1-hp(0))*( hp(1))*( hp(2)); + break; + } + } +} + + +void Element :: GetShapeNew (const Point<3> & p, FlatVector & shape) const +{ + /* + if (shape.Size() < GetNP()) + { + cerr << "Element::GetShape: Length not fitting" << endl; + return; + } + */ + + switch (typ) + { + case TET: + { + shape(0) = p(0); + shape(1) = p(1); + shape(2) = p(2); + shape(3) = 1-p(0)-p(1)-p(2); + break; + } + + case PYRAMID: + { + double noz = 1-p(2); + if (noz == 0.0) noz = 1e-10; + + double xi = p(0) / noz; + double eta = p(1) / noz; + shape(0) = (1-xi)*(1-eta) * (noz); + shape(1) = ( xi)*(1-eta) * (noz); + shape(2) = ( xi)*( eta) * (noz); + shape(3) = (1-xi)*( eta) * (noz); + shape(4) = p(2); + break; + } + + case PRISM: + { + shape(0) = p(0) * (1-p(2)); + shape(1) = p(1) * (1-p(2)); + shape(2) = (1-p(0)-p(1)) * (1-p(2)); + shape(3) = p(0) * p(2); + shape(4) = p(1) * p(2); + shape(5) = (1-p(0)-p(1)) * p(2); + break; + } + case HEX: + { + shape(0) = (1-p(0))*(1-p(1))*(1-p(2)); + shape(1) = ( p(0))*(1-p(1))*(1-p(2)); + shape(2) = ( p(0))*( p(1))*(1-p(2)); + shape(3) = (1-p(0))*( p(1))*(1-p(2)); + shape(4) = (1-p(0))*(1-p(1))*( p(2)); + shape(5) = ( p(0))*(1-p(1))*( p(2)); + shape(6) = ( p(0))*( p(1))*( p(2)); + shape(7) = (1-p(0))*( p(1))*( p(2)); + break; + } + } +} + + + + +void Element :: +GetDShape (const Point3d & p, DenseMatrix & dshape) const +{ + int np = GetNP(); + if (dshape.Height() != 3 || dshape.Width() != np) + { + cerr << "Element::DShape: Sizes don't fit" << endl; + return; + } + + int i, j; + double eps = 1e-6; + Vector shaper(np), shapel(np); + + for (i = 1; i <= 3; i++) + { + Point3d pr(p), pl(p); + pr.X(i) += eps; + pl.X(i) -= eps; + + GetShape (pr, shaper); + GetShape (pl, shapel); + for (j = 1; j <= np; j++) + dshape.Elem(i, j) = (shaper.Get(j) - shapel.Get(j)) / (2 * eps); + } +} + + + +void Element :: +GetDShapeNew (const Point<3> & p, MatrixFixWidth<3> & dshape) const +{ + switch (typ) + { + case TET: + { + dshape = 0; + dshape(0,0) = 1; + dshape(1,1) = 1; + dshape(2,2) = 1; + dshape(3,0) = -1; + dshape(3,1) = -1; + dshape(3,2) = -1; + break; + } + case PRISM: + { + dshape = 0; + dshape(0,0) = 1-p(2); + dshape(0,2) = -p(0); + dshape(1,1) = 1-p(2); + dshape(1,2) = -p(1); + dshape(2,0) = -(1-p(2)); + dshape(2,1) = -(1-p(2)); + dshape(2,2) = -(1-p(0)-p(1)); + + dshape(3,0) = p(2); + dshape(3,2) = p(0); + dshape(4,1) = p(2); + dshape(4,2) = p(1); + dshape(5,0) = -p(2); + dshape(5,1) = -p(2); + dshape(5,2) = 1-p(0)-p(1); + break; + } + + default: + { + int np = GetNP(); + double eps = 1e-6; + Vector shaper(np), shapel(np); + + for (int i = 1; i <= 3; i++) + { + Point3d pr(p), pl(p); + pr.X(i) += eps; + pl.X(i) -= eps; + + GetShapeNew (pr, shaper); + GetShapeNew (pl, shapel); + for (int j = 1; j <= np; j++) + dshape.Elem(j, i) = (shaper.Get(j) - shapel.Get(j)) / (2 * eps); + } + } + } +} + +void Element :: +GetPointMatrix (const T_POINTS & points, + DenseMatrix & pmat) const +{ + int np = GetNP(); + /* + if (pmat.Width() != np || pmat.Height() != 3) + { + cerr << "Element::GetPointMatrix: sizes don't fit" << endl; + return; + } + */ + for (int i = 1; i <= np; i++) + { + const Point3d & p = points.Get(PNum(i)); + pmat.Elem(1, i) = p.X(); + pmat.Elem(2, i) = p.Y(); + pmat.Elem(3, i) = p.Z(); + } +} + + + + + + +double Element :: CalcJacobianBadness (const T_POINTS & points) const +{ + int i, j; + int nip = GetNIP(); + static DenseMatrix trans(3,3); + static DenseMatrix pmat; + + pmat.SetSize (3, GetNP()); + GetPointMatrix (points, pmat); + + double err = 0; + for (i = 1; i <= nip; i++) + { + GetTransformation (i, pmat, trans); + + // Frobenius norm + double frob = 0; + for (j = 1; j <= 9; j++) + frob += sqr (trans.Get(j)); + frob = sqrt (frob); + frob /= 3; + + double det = -trans.Det(); + + if (det <= 0) + err += 1e12; + else + err += frob * frob * frob / det; + } + + err /= nip; + return err; +} + +double Element :: +CalcJacobianBadnessDirDeriv (const T_POINTS & points, + int pi, Vec3d & dir, double & dd) const +{ + int i, j, k, l; + int nip = GetNIP(); + static DenseMatrix trans(3,3), dtrans(3,3), hmat(3,3); + static DenseMatrix pmat, vmat; + + pmat.SetSize (3, GetNP()); + vmat.SetSize (3, GetNP()); + + GetPointMatrix (points, pmat); + + for (i = 1; i <= np; i++) + for (j = 1; j <= 3; j++) + vmat.Elem(j, i) = 0; + for (j = 1; j <= 3; j++) + vmat.Elem(j, pi) = dir.X(j); + + + + double err = 0; + dd = 0; + + for (i = 1; i <= nip; i++) + { + GetTransformation (i, pmat, trans); + GetTransformation (i, vmat, dtrans); + + + // Frobenius norm + double frob = 0; + for (j = 1; j <= 9; j++) + frob += sqr (trans.Get(j)); + frob = sqrt (frob); + + double dfrob = 0; + for (j = 1; j <= 9; j++) + dfrob += trans.Get(j) * dtrans.Get(j); + dfrob = dfrob / frob; + + frob /= 3; + dfrob /= 3; + + + double det = trans.Det(); + double ddet = 0; + + for (j = 1; j <= 3; j++) + { + hmat = trans; + for (k = 1; k <= 3; k++) + hmat.Elem(k, j) = dtrans.Get(k, j); + ddet += hmat.Det(); + } + + + det *= -1; + ddet *= -1; + + + if (det <= 0) + err += 1e12; + else + { + err += frob * frob * frob / det; + dd += (3 * frob * frob * dfrob * det - frob * frob * frob * ddet) / (det * det); + } + } + + err /= nip; + dd /= nip; + return err; +} + + + + + +void Element :: ComputeIntegrationPointData () const +{ + switch (GetType()) + { + case TET: if (ipdtet.Size()) return; break; + case TET10: if (ipdtet10.Size()) return; break; + default: + PrintSysError ("Element::ComputeIntegrationPoint, illegal type ", int(typ)); + } + + int i; + for (i = 1; i <= GetNIP(); i++) + { + IntegrationPointData * ipd = new IntegrationPointData; + GetIntegrationPoint (i, ipd->p, ipd->weight); + ipd->shape.SetSize(GetNP()); + ipd->dshape.SetSize(3, GetNP()); + + GetShape (ipd->p, ipd->shape); + GetDShape (ipd->p, ipd->dshape); + + switch (GetType()) + { + case TET: ipdtet.Append (ipd); break; + case TET10: ipdtet10.Append (ipd); break; + default: + PrintSysError ("Element::ComputeIntegrationPoint(2), illegal type ", int(typ)); + } + } +} + + + + + + + + +FaceDescriptor :: FaceDescriptor() +{ + surfnr = domin = domout = bcprop = 0; + domin_singular = domout_singular = 0; + tlosurf = -1; +} + +FaceDescriptor :: +FaceDescriptor(int surfnri, int domini, int domouti, int tlosurfi) +{ + surfnr = surfnri; + domin = domini; + domout = domouti; + tlosurf = tlosurfi; + bcprop = surfnri; + domin_singular = domout_singular = 0; +} + +FaceDescriptor :: FaceDescriptor(const Segment & seg) +{ + surfnr = seg.si; + domin = seg.domin+1; + domout = seg.domout+1; + tlosurf = seg.tlosurf+1; + bcprop = 0; + domin_singular = domout_singular = 0; +} + +int FaceDescriptor :: SegmentFits (const Segment & seg) +{ + return + surfnr == seg.si && + domin == seg.domin+1 && + domout == seg.domout+1 && + tlosurf == seg.tlosurf+1; +} + + +ostream & operator<<(ostream & s, const FaceDescriptor & fd) +{ + s << "surfnr = " << fd.surfnr + << ", domin = " << fd.domin + << ", domout = " << fd.domout + << ", tlosurf = " << fd.tlosurf + << ", bcprop = " << fd.bcprop + << ", domin_sing = " << fd.domin_singular + << ", domout_sing = " << fd.domout_singular; + return s; +} + + + + + + +Identifications :: Identifications (Mesh & amesh) + : mesh(amesh) +{ + identifiedpoints = new INDEX_2_HASHTABLE<int>(100); + maxidentnr = 0; +} + +Identifications :: ~Identifications () +{ + delete identifiedpoints; +} + +void Identifications :: Delete () +{ + delete identifiedpoints; + identifiedpoints = new INDEX_2_HASHTABLE<int>(100); + maxidentnr = 0; +} + +void Identifications :: Add (PointIndex pi1, PointIndex pi2, int identnr) +{ + INDEX_2 pair (pi1, pi2); + identifiedpoints->Set (pair, identnr); + if (identnr > maxidentnr) maxidentnr = identnr; + // timestamp = NextTimeStamp(); +} + +int Identifications :: Get (PointIndex pi1, PointIndex pi2) const +{ + INDEX_2 pair(pi1, pi2); + if (identifiedpoints->Used (pair)) + return identifiedpoints->Get(pair); + else + return 0; +} + +int Identifications :: GetSymmetric (PointIndex pi1, PointIndex pi2) const +{ + INDEX_2 pair(pi1, pi2); + if (identifiedpoints->Used (pair)) + return identifiedpoints->Get(pair); + + pair = INDEX_2 (pi2, pi1); + if (identifiedpoints->Used (pair)) + return identifiedpoints->Get(pair); + + return 0; +} + + +void Identifications :: GetMap (int identnr, ARRAY<int,PointIndex::BASE> & identmap) const +{ + identmap.SetSize (mesh.GetNP()); + identmap = 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); + + if (nr == identnr || !identnr) + identmap.Elem(i2.I1()) = i2.I2(); + } +} + + +void Identifications :: GetPairs (int identnr, + ARRAY<INDEX_2> & identpairs) const +{ + int i, j; + + identpairs.SetSize(0); + + for (i = 1; i <= identifiedpoints->GetNBags(); i++) + for (j = 1; j <= identifiedpoints->GetBagSize(i); j++) + { + INDEX_2 i2; + int nr; + identifiedpoints->GetData (i, j, i2, nr); + + if (identnr == 0 || nr == identnr) + identpairs.Append (i2); + } +} + + +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); + } + } +} + + + + + +MeshingParameters :: MeshingParameters () +{ + 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; + meshsizefilename = NULL; + startinsurface = 0; + checkoverlap = 1; + checkchartboundary = 1; + curvaturesafety = 2; + segmentsperedge = 1; + parthread = 0; + + elsizeweight = 0.2; + giveuptol = 10; + maxoutersteps = 5; + starshapeclass = 5; + baseelnp = 0; + sloppy = 1; + + badellimit = 175; + secondorder = 0; +} + +void MeshingParameters :: Print (ostream & ost) const +{ + ost << "Meshing parameters: " << endl + << "optimize3d = " << optimize3d << endl + << "optsteps3d = " << optsteps3d << endl + << " optimize2d = " << optimize2d << endl + << " optsteps2d = " << optsteps2d << endl + << " opterrpow = " << opterrpow << endl + << " blockfill = " << blockfill << endl + << " filldist = " << filldist << endl + << " safety = " << safety << endl + << " relinnersafety = " << relinnersafety << endl + << " uselocalh = " << uselocalh << endl + << " grading = " << grading << endl + << " delaunay = " << delaunay << endl + << " maxh = " << maxh << endl; + if(meshsizefilename) + ost << " meshsizefilename = " << meshsizefilename << endl; + else + ost << " meshsizefilename = NULL" << endl; + ost << " startinsurface = " << startinsurface << endl + << " checkoverlap = " << checkoverlap << endl + << " checkchartboundary = " << checkchartboundary << endl + << " curvaturesafety = " << curvaturesafety << endl + << " segmentsperedge = " << segmentsperedge << endl + << " parthread = " << parthread << endl + << " elsizeweight = " << elsizeweight << endl + << " giveuptol = " << giveuptol << endl + << " maxoutersteps = " << maxoutersteps << endl + << " starshapeclass = " << starshapeclass << endl + << " baseelnp = " << baseelnp << endl + << " sloppy = " << sloppy << endl + << " badellimit = " << badellimit << endl + << " secondorder = " << secondorder << endl + << " elementorder = " << elementorder << endl + << " quad = " << quad << endl + << " inverttets = " << inverttets << endl + << " inverttrigs = " << inverttrigs << endl; +} + +void MeshingParameters :: CopyFrom(const MeshingParameters & other) +{ + //strcpy(optimize3d,other.optimize3d); + optimize3d = other.optimize3d; + optsteps3d = other.optsteps3d; + //strcpy(optimize2d,other.optimize2d); + optimize2d = other.optimize2d; + optsteps2d = other.optsteps2d; + opterrpow = other.opterrpow; + blockfill = other.blockfill; + filldist = other.filldist; + safety = other.safety; + relinnersafety = other.relinnersafety; + uselocalh = other.uselocalh; + grading = other.grading; + delaunay = other.delaunay; + maxh = other.maxh; + //strcpy(const_cast<char*>(meshsizefilename), other.meshsizefilename); + //const_cast<char*>(meshsizefilename) = other.meshsizefilename; //??? + startinsurface = other.startinsurface; + checkoverlap = other.checkoverlap; + checkchartboundary = other.checkchartboundary; + curvaturesafety = other.curvaturesafety; + segmentsperedge = other.segmentsperedge; + parthread = other.parthread; + elsizeweight = other.elsizeweight; + giveuptol = other.giveuptol; + maxoutersteps = other.maxoutersteps; + starshapeclass = other.starshapeclass; + baseelnp = other.baseelnp; + sloppy = other.sloppy; + badellimit = other.badellimit; + secondorder = other.secondorder; + elementorder = other.elementorder; + quad = other.quad; + inverttets = other.inverttets; + inverttrigs = other.inverttrigs; +} + + +DebugParameters :: DebugParameters () +{ + slowchecks = 0; + haltsuccess = 0; + haltnosuccess = 0; + haltlargequalclass = 0; + haltsegment = 0; + haltsegmentp1 = 0; + haltsegmentp2 = 0; +} + + + +} diff --git a/contrib/Netgen/libsrc/meshing/meshtype.hpp b/contrib/Netgen/libsrc/meshing/meshtype.hpp new file mode 100644 index 0000000000..363efd3226 --- /dev/null +++ b/contrib/Netgen/libsrc/meshing/meshtype.hpp @@ -0,0 +1,1025 @@ +#ifndef MESHTYPE +#define MESHTYPE + +//#include <algorithm> + +/**************************************************************************/ +/* File: meshtype.hpp */ +/* Author: Joachim Schoeberl */ +/* Date: 01. Okt. 95 */ +/**************************************************************************/ + +/* + Classes for NETGEN +*/ + + +enum ELEMENT_TYPE { + SEGMENT = 1, SEGMENT3 = 2, + TRIG = 10, QUAD=11, TRIG6 = 12, QUAD6 = 13, QUAD8 = 14, + TET = 20, TET10 = 21, + PYRAMID = 22, PRISM = 23, PRISM12 = 24, + HEX = 25 +}; + +typedef int ELEMENT_EDGE[2]; // initial point, end point +typedef int ELEMENT_FACE[4]; // points, last one is -1 for trig + + +#define ELEMENT_MAXPOINTS 12 +#define ELEMENT2D_MAXPOINTS 8 + + +enum POINTTYPE { FIXEDPOINT = 1, EDGEPOINT = 2, SURFACEPOINT = 3, INNERPOINT = 4 }; +enum ELEMENTTYPE { FREEELEMENT, FIXEDELEMENT }; +enum OPTIMIZEGOAL { OPT_QUALITY, OPT_CONFORM, OPT_REST, OPT_WORSTCASE, OPT_LEGAL }; + + +class Mesh; // Added by Christophe for Gmsh (ISO C++ forbids declaration of 'Mesh' with no type) + +// class CSGeometry; + +extern int GetTimeStamp(); +extern int NextTimeStamp(); + +class PointGeomInfo +{ +public: + int trignum; // for STL Meshing + double u, v; // for OCC Meshing + + PointGeomInfo () + : trignum(-1), u(0), v(0) { ; } +}; + +inline ostream & operator<< (ostream & ost, const PointGeomInfo & gi) +{ + return (ost << gi.trignum); +} + + + +#define MULTIPOINTGEOMINFO_MAX 100 +class MultiPointGeomInfo +{ + int cnt; + PointGeomInfo mgi[MULTIPOINTGEOMINFO_MAX]; +public: + MultiPointGeomInfo (); + int AddPointGeomInfo (const PointGeomInfo & gi); + void Init (); + void DeleteAll (); + + int GetNPGI () const { return cnt; } + const PointGeomInfo & GetPGI (int i) const { return mgi[i-1]; } +}; + + +class EdgePointGeomInfo +{ +public: + int edgenr; + double dist; + double u, v; // for OCC Meshing + + EdgePointGeomInfo () + : edgenr(0), dist(0.0), u(0.0), v(0.0) { ; } + + EdgePointGeomInfo & operator= (const EdgePointGeomInfo & gi2) + { + edgenr = gi2.edgenr; dist = gi2.dist; + u = gi2.u; v = gi2.v; + return *this; + } +}; + +inline ostream & operator<< (ostream & ost, const EdgePointGeomInfo & gi) +{ + return (ost << gi.edgenr); +} + + + + + +class PointIndex +{ + int i; +public: + PointIndex () { ; } + PointIndex (int ai) : i(ai) { ; } + PointIndex & operator= (const PointIndex &ai) { i = ai.i; return *this; } + PointIndex & operator= (int ai) { i = ai; return *this; } + operator int () const { return i; } + int GetInt () const { return i; } + PointIndex operator++ (int) { int hi = i; i++; return hi; } + PointIndex operator-- (int) { int hi = i; i--; return hi; } + +#ifdef BASE0 + enum { BASE = 0 }; +#else + enum { BASE = 1 }; +#endif +}; + +inline istream & operator>> (istream & ist, PointIndex & pi) +{ + int i; ist >> i; pi = i; return ist; +} + +inline ostream & operator<< (ostream & ost, const PointIndex & pi) +{ + return (ost << pi.GetInt()); +} + + + + +class ElementIndex +{ + int i; +public: + ElementIndex () { ; } + ElementIndex (int ai) : i(ai) { ; } + ElementIndex & operator= (const ElementIndex & ai) { i = ai.i; return *this; } + ElementIndex & operator= (int ai) { i = ai; return *this; } + operator int () const { return i; } + ElementIndex & operator++ (int) { i++; return *this; } + ElementIndex & operator-- (int) { i--; return *this; } +}; + +inline istream & operator>> (istream & ist, ElementIndex & pi) +{ + int i; ist >> i; pi = i; return ist; +} + +inline ostream & operator<< (ostream & ost, const ElementIndex & pi) +{ + return (ost << int(pi)); +} + + +class SurfaceElementIndex +{ + int i; +public: + SurfaceElementIndex () { ; } + SurfaceElementIndex (int ai) : i(ai) { ; } + SurfaceElementIndex & operator= (const SurfaceElementIndex & ai) + { i = ai.i; return *this; } + SurfaceElementIndex & operator= (int ai) { i = ai; return *this; } + operator int () const { return i; } + SurfaceElementIndex & operator++ (int) { i++; return *this; } + SurfaceElementIndex & operator-- (int) { i--; return *this; } +}; + +inline istream & operator>> (istream & ist, SurfaceElementIndex & pi) +{ + int i; ist >> i; pi = i; return ist; +} + +inline ostream & operator<< (ostream & ost, const SurfaceElementIndex & pi) +{ + return (ost << int(pi)); +} + +class SegmentIndex +{ + int i; +public: + SegmentIndex () { ; } + SegmentIndex (int ai) : i(ai) { ; } + SegmentIndex & operator= (const SegmentIndex & ai) + { i = ai.i; return *this; } + SegmentIndex & operator= (int ai) { i = ai; return *this; } + operator int () const { return i; } + SegmentIndex & operator++ (int) { i++; return *this; } + SegmentIndex & operator-- (int) { i--; return *this; } +}; + +inline istream & operator>> (istream & ist, SegmentIndex & pi) +{ + int i; ist >> i; pi = i; return ist; +} + +inline ostream & operator<< (ostream & ost, const SegmentIndex & pi) +{ + return (ost << int(pi)); +} + + + + +/** + Point in the mesh. + Contains layer (a new feature in 4.3 for overlapping meshes. + will contain pointtype + */ +class MeshPoint : public Point3d +{ + int layer; + bool singular; + POINTTYPE type; +public: + MeshPoint () : layer(1), singular(0), type(INNERPOINT) { ; } + MeshPoint (const Point3d & ap, int alayer = 1, POINTTYPE apt = INNERPOINT) + : Point3d (ap), layer(alayer), singular(0), type(apt) { ; } + + void SetPoint (const Point3d & ap) + { Point3d::operator= (ap); } + int GetLayer() const { return layer; } + + bool IsSingular() const { return singular; } + void SetSingular(bool s = 1) { singular = s; } + + POINTTYPE Type() const { return type; } + void SetType(POINTTYPE at) { type = at; } +}; + + + +// typedef MoveableArray<MeshPoint> T_POINTS; +typedef ARRAY<MeshPoint,PointIndex::BASE> T_POINTS; + + +class Element2d; +ostream & operator<<(ostream & s, const Element2d & el); + +/** + Triangle element for surface mesh generation. + */ +class Element2d +{ + /// point numbers + PointIndex pnum[ELEMENT2D_MAXPOINTS]; + /// geom info of corner points + PointGeomInfo geominfo[ELEMENT2D_MAXPOINTS]; + + /// surface nr + int index:16; + /// + ELEMENT_TYPE typ:6; + /// number of points + unsigned int np:4; + bool badel:1; + bool refflag:1; // marked for refinement + bool deleted:1; // element is deleted + + /// order for hp-FEM + unsigned int order:6; + + +public: + /// + Element2d (int anp = 3); + /// + Element2d (ELEMENT_TYPE type); + /// + Element2d (int pi1, int pi2, int pi3); + /// + Element2d (int pi1, int pi2, int pi3, int pi4); + /// + ELEMENT_TYPE GetType () const { return typ; } + /// + void SetType (ELEMENT_TYPE atyp) + { + typ = atyp; + switch (typ) + { + case TRIG: np = 3; break; + case QUAD: np = 4; break; + case TRIG6: np = 6; break; + case QUAD6: np = 6; break; + case QUAD8: np = 8; break; + default: + PrintSysError ("Element2d::SetType, illegal type ", typ); + } + } + /// + int GetNP() const { return np; } + /// + int GetNV() const + { + switch (typ) + { + case TRIG: + case TRIG6: return 3; + + case QUAD: + case QUAD8: + case QUAD6: return 4; + default: +#ifdef DEBUG + PrintSysError ("element2d::GetNV not implemented for typ", typ) +#endif + ; + } + return np; + } + + /// + PointIndex & operator[] (int i) { return pnum[i]; } + /// + const PointIndex & operator[] (int i) const { return pnum[i]; } + + /// + PointIndex & PNum (int i) { return pnum[i-1]; } + /// + const PointIndex & PNum (int i) const { return pnum[i-1]; } + /// + PointIndex & PNumMod (int i) { return pnum[(i-1) % np]; } + /// + const PointIndex & PNumMod (int i) const { return pnum[(i-1) % np]; } + /// + + /// + PointGeomInfo & GeomInfoPi (int i) { return geominfo[i-1]; } + /// + const PointGeomInfo & GeomInfoPi (int i) const { return geominfo[i-1]; } + /// + PointGeomInfo & GeomInfoPiMod (int i) { return geominfo[(i-1) % np]; } + /// + const PointGeomInfo & GeomInfoPiMod (int i) const { return geominfo[(i-1) % np]; } + + + void SetIndex (int si) { index = si; } + /// + int GetIndex () const { return index; } + + int GetOrder () const { return order; } + void SetOrder (int aorder) { order = aorder; } + + /// + void GetBox (const T_POINTS & points, Box3d & box) const; + /// invert orientation + inline void Invert (); + /// + void Invert2 (); + /// first point number is smallest + inline void NormalizeNumbering (); + /// + void NormalizeNumbering2 (); + + bool BadElement() const { return badel; } + + friend ostream & operator<<(ostream & s, const Element2d & el); + friend class Mesh; + + + /// get number of 'integration points' + int GetNIP () const; + void GetIntegrationPoint (int ip, Point2d & p, double & weight) const; + void GetTransformation (int ip, const ARRAY<Point2d> & points, + class DenseMatrix & trans) const; + void GetTransformation (int ip, class DenseMatrix & pmat, + class DenseMatrix & trans) const; + + void GetShape (const Point2d & p, class Vector & shape) const; + /// matrix 2 * np + void GetDShape (const Point2d & p, class DenseMatrix & dshape) const; + /// matrix 2 * np + void GetPointMatrix (const ARRAY<Point2d> & points, + class DenseMatrix & pmat) const; + + void ComputeIntegrationPointData () const; + + + double CalcJacobianBadness (const ARRAY<Point2d> & points) const; + double CalcJacobianBadness (const T_POINTS & points, + const Vec3d & n) const; + double CalcJacobianBadnessDirDeriv (const ARRAY<Point2d> & points, + int pi, Vec2d & dir, double & dd) const; + + + + void Delete () { deleted = 1; pnum[0] = pnum[1] = pnum[2] = pnum[3] = PointIndex::BASE-1; } + bool IsDeleted () const + { +#ifdef DEBUG + if (pnum[0] < PointIndex::BASE && !deleted) + cerr << "Surfelement has illegal pnum, but not marked as deleted" << endl; +#endif + return deleted; + } + + void SetRefinementFlag (bool rflag = 1) + { refflag = rflag; } + bool TestRefinementFlag () const + { return refflag; } + + int HasFace(const Element2d& el) const; + /// + int meshdocval; + /// + int hp_elnr; +}; + + + + +class IntegrationPointData +{ +public: + Point3d p; + double weight; + Vector shape; + DenseMatrix dshape; +}; + + + + +class Element; +ostream & operator<<(ostream & s, const Element & el); + + + +/** + Volume element + */ +class Element +{ +private: + /// point numbers + PointIndex pnum[ELEMENT_MAXPOINTS]; + /// + ELEMENT_TYPE typ:6; + /// number of points (4..tet, 5..pyramid, 6..prism, 8..hex, 10..quad tet, 12..quad prism) + int np:5; + /// + class flagstruct { + public: + bool marked:1; // marked for refinement + bool badel:1; // angles worse then limit + bool reverse:1; // for refinement a la Bey + bool illegal:1; // illegal, will be split or swaped + bool illegal_valid:1; // is illegal-flag valid ? + bool badness_valid:1; // is badness valid ? + bool refflag:1; // mark element for refinement + bool deleted:1; // element is deleted, will be removed from array + }; + /// surface or sub-domain index + short int index; + /// order for hp-FEM + unsigned int order:6; + /// stored shape-badness of element + float badness; + /// number of partition for parallel compution + short int partitionNumber; + /// + +public: + flagstruct flags; + + /// + Element (); + /// + Element (int anp); + /// + Element (ELEMENT_TYPE type); + /// + Element & operator= (const Element & el2); + + /// + void SetNP (int anp); + /// + void SetType (ELEMENT_TYPE atyp); + /// + int GetNP () const { return np; } + /// + int GetNV() const + { + switch (typ) + { + case TET: return 4; + case TET10: return 4; + case PRISM12: return 6; + case PRISM: return 6; //SZ + default: +#ifdef DEBUG + PrintSysError ("Element3d::GetNV not implemented for typ ", typ) +#endif + ; + } + return np; + } + // old style: + int NP () const { return np; } + + /// + ELEMENT_TYPE GetType () const { return typ; } + + /// + PointIndex & operator[] (int i) { return pnum[i]; } + /// + const PointIndex & operator[] (int i) const { return pnum[i]; } + + /// + PointIndex & PNum (int i) { return pnum[i-1]; } + /// + const PointIndex & PNum (int i) const { return pnum[i-1]; } + /// + PointIndex & PNumMod (int i) { return pnum[(i-1) % np]; } + /// + const PointIndex & PNumMod (int i) const { return pnum[(i-1) % np]; } + + /// + void SetIndex (int si) { index = si; } + /// + int GetIndex () const { return index; } + + int GetOrder () const { return order; } + void SetOrder (int aorder) { order = aorder; } + + /// + void GetBox (const T_POINTS & points, Box3d & box) const; + /// Calculates Volume of elemenet + double Volume (const T_POINTS & points) const; + /// + virtual void Print (ostream & ost) const; + /// + int GetNFaces () const + { + switch (typ) + { + case TET: + case TET10: return 4; + case PYRAMID: return 5; + case PRISM: + case PRISM12: return 5; + default: +#ifdef DEBUG + PrintSysError ("element3d::GetNFaces not implemented for typ", typ) +#endif + ; + } + return 0; + } + /// + inline void GetFace (int i, Element2d & face) const; + /// + void GetFace2 (int i, Element2d & face) const; + /// + void Invert (); + + /// split into 4 node tets + void GetTets (ARRAY<Element> & locels) const; + /// split into 4 node tets, local point nrs + void GetTetsLocal (ARRAY<Element> & locels) const; + /// returns coordinates of nodes + void GetNodesLocal (ARRAY<Point3d> & points) const; + void GetNodesLocalNew (ARRAY<Point3d> & points) const; + + /// split surface into 3 node trigs + void GetSurfaceTriangles (ARRAY<Element2d> & surftrigs) const; + + + /// get number of 'integration points' + int GetNIP () const; + void GetIntegrationPoint (int ip, Point3d & p, double & weight) const; + void GetTransformation (int ip, const T_POINTS & points, + class DenseMatrix & trans) const; + void GetTransformation (int ip, class DenseMatrix & pmat, + class DenseMatrix & trans) const; + + void GetShape (const Point3d & p, class Vector & shape) const; + void GetShapeNew (const Point<3> & p, class FlatVector & shape) const; + /// matrix 2 * np + void GetDShape (const Point3d & p, class DenseMatrix & dshape) const; + void GetDShapeNew (const Point<3> & p, class MatrixFixWidth<3> & dshape) const; + /// matrix 3 * np + void GetPointMatrix (const T_POINTS & points, + class DenseMatrix & pmat) const; + + void ComputeIntegrationPointData () const; + + + double CalcJacobianBadness (const T_POINTS & points) const; + double CalcJacobianBadnessDirDeriv (const T_POINTS & points, + int pi, Vec3d & dir, double & dd) const; + + /// + friend ostream & operator<<(ostream & s, const Element & el); + + void SetRefinementFlag (bool rflag = 1) + { flags.refflag = rflag; } + int TestRefinementFlag () const + { return flags.refflag; } + + int Illegal () const + { return flags.illegal; } + int IllegalValid () const + { return flags.illegal_valid; } + void SetIllegal (int aillegal) + { + flags.illegal = aillegal ? 1 : 0; + flags.illegal_valid = 1; + } + void SetLegal (int alegal) + { + flags.illegal = alegal ? 0 : 1; + flags.illegal_valid = 1; + } + + void Delete () { flags.deleted = 1; } + bool IsDeleted () const + { +#ifdef DEBUG + if (pnum[0] < PointIndex::BASE && !flags.deleted) + cerr << "Volelement has illegal pnum, but not marked as deleted" << endl; +#endif + + return flags.deleted; + } + + int GetPartition () const { return partitionNumber; } + void SetPartition (int nr) { partitionNumber = nr; }; + + int hp_elnr; +}; + + +class Segment; +ostream & operator<<(ostream & s, const Segment & seg); + + +/** + Edge segment. + */ +class Segment +{ +public: + /// + Segment(); + + friend ostream & operator<<(ostream & s, const Segment & seg); + + /// point index 1 + PointIndex p1; + /// point index 2 + PointIndex p2; + /// edge nr + int edgenr; + /// + unsigned int singedge_left:1; + unsigned int singedge_right:1; + + /// 0.. not first segment of segs, 1..first of class, 2..first of class, inverse + unsigned int seginfo:2; + + /// surface decoding index + int si; + /// domain number inner side + int domin; + /// domain number outer side + int domout; + /// top-level object number of surface + int tlosurf; + /// + PointGeomInfo geominfo[2]; + + /// surfaces describing edge + int surfnr1, surfnr2; + /// + EdgePointGeomInfo epgeominfo[2]; + /// + int pmid; // for second order + /// + int meshdocval; + + + PointIndex operator[] (int i) const + { return (i == 0) ? p1 : p2; } + + PointIndex & operator[] (int i) + { return (i == 0) ? p1 : p2; } + + Segment& operator=(const Segment & other); + + + int hp_elnr; +}; + + +// class Surface; +class FaceDescriptor; +ostream & operator<< (ostream & s, const FaceDescriptor & fd); + +/// +class FaceDescriptor +{ + /// which surface, 0 if not available + int surfnr; + /// domain nr inside + int domin; + /// domain nr outside + int domout; + /// top level object number of surface + int tlosurf; + /// boundary condition property + int bcprop; + +public: + FaceDescriptor(); + FaceDescriptor(int surfnri, int domini, int domouti, int tlosurfi); + FaceDescriptor(const Segment & seg); + + int SegmentFits (const Segment & seg); + + int SurfNr () const { return surfnr; } + int DomainIn () const { return domin; } + int DomainOut () const { return domout; } + int TLOSurface () const { return tlosurf; } + int BCProperty () const { return bcprop; } + void SetSurfNr (int sn) { surfnr = sn; } + void SetDomainIn (int di) { domin = di; } + void SetDomainOut (int dom) { domout = dom; } + void SetBCProperty (int bc) { bcprop = bc; } + + friend ostream & operator<<(ostream & s, const FaceDescriptor & fd); + + + /// + bool domin_singular; + bool domout_singular; + + +}; + + + + + + +class MeshingParameters +{ +public: + /** + 3d optimization strategy: + // m .. move nodes + // M .. move nodes, cheap functional + // s .. swap faces + // c .. combine elements + // d .. divide elements + // p .. plot, no pause + // P .. plot, Pause + // h .. Histogramm, no pause + // H .. Histogramm, pause + */ + char * optimize3d; + /// number of 3d optimization steps + int optsteps3d; + /** + 2d optimization strategy: + // s .. swap, opt 6 lines/node + // S .. swap, optimal elements + // m .. move nodes + // p .. plot, no pause + // P .. plot, pause + // c .. combine + **/ + char * optimize2d; + /// number of 2d optimization steps + int optsteps2d; + /// power of error (to approximate max err optimization) + double opterrpow; + /// do block filling ? + int blockfill; + /// block filling up to distance + double filldist; + /// radius of local environment (times h) + double safety; + /// radius of active environment (times h) + double relinnersafety; + /// use local h ? + int uselocalh; + /// grading for local h + double grading; + /// use delaunay meshing + int delaunay; + /// maximal mesh size + double maxh; + /// file for meshsize + const char * meshsizefilename; + /// start surfacemeshing from everywhere in surface + int startinsurface; + /// check overlapping surfaces (debug) + int checkoverlap; + /// check chart boundary (sometimes too restrictive) + int checkchartboundary; + /// safty factor for curvatures (elemetns per radius) + double curvaturesafety; + /// minimal number of segments per edge + double segmentsperedge; + /// use parallel threads + int parthread; + /// weight of element size w.r.t element shape + double elsizeweight; + /// init with default values + + + /// from mp3: + /// give up quality class + int giveuptol; + /// maximal outer steps + int maxoutersteps; + /// class starting star-shape filling + int starshapeclass; + /// if non-zero, baseelement must have baseelnp points + int baseelnp; + /// quality tolerances are handled less careful + int sloppy; + + /// limit for max element angle (150-180) + double badellimit; + + /// + int secondorder; + /// high order element curvature + int elementorder; + /// quad-dominated surface meshing + int quad; + /// + int inverttets; + /// + int inverttrigs; + /// + MeshingParameters (); + /// + void Print (ostream & ost) const; + + void CopyFrom(const MeshingParameters & other); +}; + +class DebugParameters +{ +public: + /// + int debugoutput; + /// use slow checks + int slowchecks; + /// + int haltsuccess; + /// + int haltnosuccess; + /// + int haltlargequalclass; + /// + int haltsegment; + /// + int haltnode; + /// + int haltsegmentp1; + /// + int haltsegmentp2; + /// + int haltexistingline; + /// + int haltoverlap; + /// + int haltface; + /// + int haltfacenr; + /// + DebugParameters (); +}; + + + + + + + +inline void Element2d :: Invert() +{ + if (typ == TRIG) + Swap (PNum(2), PNum(3)); + else + Invert2(); +} + + + + +inline void Element2d :: NormalizeNumbering () +{ + if (GetNP() == 3) + { + if (PNum(1) < PNum(2) && PNum(1) < PNum(3)) + return; + else + { + if (PNum(2) < PNum(3)) + { + PointIndex pi1 = PNum(2); + PNum(2) = PNum(3); + PNum(3) = PNum(1); + PNum(1) = pi1; + } + else + { + PointIndex pi1 = PNum(3); + PNum(3) = PNum(2); + PNum(2) = PNum(1); + PNum(1) = pi1; + } + } + } + else + NormalizeNumbering2(); +} + + + +static const int gftetfacesa[4][3] = + { { 1, 2, 3 }, + { 2, 0, 3 }, + { 0, 1, 3 }, + { 1, 0, 2 } }; + +inline void Element :: GetFace (int i, Element2d & face) const +{ + if (typ == TET) + { + face.SetType(TRIG); + face[0] = pnum[gftetfacesa[i-1][0]]; + face[1] = pnum[gftetfacesa[i-1][1]]; + face[2] = pnum[gftetfacesa[i-1][2]]; + } + else + GetFace2 (i, face); +} + + + + + + + +/** + Identification of periodic surfaces, close surfaces, etc. + */ +class Identifications +{ +private: + Mesh & mesh; + + /// identify points (thin layers, periodic b.c.) + INDEX_2_HASHTABLE<int> * identifiedpoints; + + /// number of identifications (or, actually used identifications ?) + int maxidentnr; + +public: + /// + Identifications (Mesh & amesh); + /// + ~Identifications (); + + void Delete (); + + /* + Identify points pi1 and pi2, due to + identification nr identnr + */ + void Add (PointIndex pi1, PointIndex pi2, int identnr); + + + int Get (PointIndex pi1, PointIndex pi2) const; + int GetSymmetric (PointIndex pi1, PointIndex pi2) const; + /// + INDEX_2_HASHTABLE<int> & GetIdentifiedPoints () + { + return *identifiedpoints; + } + + bool Used (PointIndex pi1, PointIndex pi2) + { + return identifiedpoints->Used (INDEX_2 (pi1, pi2)); + } + + bool UsedSymmetric (PointIndex pi1, PointIndex pi2) + { + return + identifiedpoints->Used (INDEX_2 (pi1, pi2)) || + identifiedpoints->Used (INDEX_2 (pi2, pi1)); + } + + /// + void GetMap (int identnr, ARRAY<int,PointIndex::BASE> & identmap) const; + /// + void GetPairs (int identnr, ARRAY<INDEX_2> & identpairs) const; + /// + int GetMaxNr () const { return maxidentnr; } + + /// remove secondorder + void SetMaxPointNr (int maxpnum); +}; + + + + + + + +#endif diff --git a/contrib/Netgen/libsrc/meshing/msghandler.cpp b/contrib/Netgen/libsrc/meshing/msghandler.cpp new file mode 100644 index 0000000000..04da502a73 --- /dev/null +++ b/contrib/Netgen/libsrc/meshing/msghandler.cpp @@ -0,0 +1,193 @@ +//File for handling warnings, errors, messages +#include <meshing.hpp> + +namespace netgen +{ + +int printmessage_importance = 5; +int printwarnings = 1; +int printerrors = 1; +int printdots = 1; +int printfnstart = 0; + +// extern void Ng_PrintDest(const MyStr& s); +extern void Ng_PrintDest(const char * s); + +//the dots for progression of program +void PrintDot(char ch) +{ + if (printdots) + { + char st[2]; + st[0] = ch; + st[1] = 0; + Ng_PrintDest(st); + } +} + +void PrintMessage(int importance, + const MyStr& s1, const MyStr& s2) +{ + if (importance <= printmessage_importance) + { + Ng_PrintDest(MyStr(" ")+s1+s2+MyStr("\n")); + } +} + +void PrintMessage(int importance, + const MyStr& s1, const MyStr& s2, const MyStr& s3, const MyStr& s4) +{ + if (importance <= printmessage_importance) + { + Ng_PrintDest(MyStr(" ")+s1+s2+s3+s4+MyStr("\n")); + } +} + +void PrintMessage(int importance, + const MyStr& s1, const MyStr& s2, const MyStr& s3, const MyStr& s4, + const MyStr& s5, const MyStr& s6, const MyStr& s7, const MyStr& s8) +{ + if (importance <= printmessage_importance) + { + Ng_PrintDest(MyStr(" ")+s1+s2+s3+s4+s5+s6+s7+s8+MyStr("\n")); + } +} + +void PrintMessageCR(int importance, + const MyStr& s1, const MyStr& s2, const MyStr& s3, const MyStr& s4, + const MyStr& s5, const MyStr& s6, const MyStr& s7, const MyStr& s8) +{ + if (importance <= printmessage_importance) + { + Ng_PrintDest(MyStr(" ")+s1+s2+s3+s4+s5+s6+s7+s8+MyStr("\r")); + } +} + +void PrintFnStart(const MyStr& s1, const MyStr& s2, const MyStr& s3, const MyStr& s4, + const MyStr& s5, const MyStr& s6, const MyStr& s7, const MyStr& s8) +{ + if (printfnstart) + Ng_PrintDest(MyStr(" Start Function: ")+s1+s2+s3+s4+s5+s6+s7+s8+MyStr("\n")); +} + +void PrintWarning(const MyStr& s1, const MyStr& s2, const MyStr& s3, const MyStr& s4, + const MyStr& s5, const MyStr& s6, const MyStr& s7, const MyStr& s8) +{ + if (printwarnings) + Ng_PrintDest(MyStr(" WARNING: ")+s1+s2+s3+s4+s5+s6+s7+s8+MyStr("\n")); +} + +void PrintError(const MyStr& s1, const MyStr& s2, const MyStr& s3, const MyStr& s4, + const MyStr& s5, const MyStr& s6, const MyStr& s7, const MyStr& s8) +{ + if (printerrors) + Ng_PrintDest(MyStr(" ERROR: ")+s1+s2+s3+s4+s5+s6+s7+s8+MyStr("\n")); +} + +void PrintFileError(const MyStr& s1, const MyStr& s2, const MyStr& s3, const MyStr& s4, + const MyStr& s5, const MyStr& s6, const MyStr& s7, const MyStr& s8) +{ + if (printerrors) + Ng_PrintDest(MyStr(" FILE ERROR: ")+s1+s2+s3+s4+s5+s6+s7+s8+MyStr("\n")); +} + +void PrintUserError(const MyStr& s1, const MyStr& s2, const MyStr& s3, const MyStr& s4, + const MyStr& s5, const MyStr& s6, const MyStr& s7, const MyStr& s8) +{ + Ng_PrintDest(MyStr(" USER ERROR: ")+s1+s2+s3+s4+s5+s6+s7+s8+MyStr("\n")); +} + +void PrintSysError(const MyStr& s1, const MyStr& s2, const MyStr& s3, const MyStr& s4, + const MyStr& s5, const MyStr& s6, const MyStr& s7, const MyStr& s8) +{ + if (printerrors) + Ng_PrintDest(MyStr(" SYSTEM ERROR: ")+s1+s2+s3+s4+s5+s6+s7+s8+MyStr("\n")); +} + +void PrintTime(const MyStr& s1, const MyStr& s2, const MyStr& s3, const MyStr& s4, + const MyStr& s5, const MyStr& s6, const MyStr& s7, const MyStr& s8) +{ + if (printmessage_importance >= 3) + Ng_PrintDest(MyStr(" Time = ")+s1+s2+s3+s4+s5+s6+s7+s8+MyStr("\n")); +} + + +static ARRAY<MyStr*> msgstatus_stack(0); +static MyStr msgstatus = ""; + + + + +void ResetStatus() +{ + SetStatMsg("idle"); + + for (int i = 0; i < msgstatus_stack.Size(); i++) + delete msgstatus_stack[i]; + msgstatus_stack.SetSize(0); + + // multithread.task = ""; + multithread.percent = 100.; +} + +void PushStatus(const MyStr& s) +{ + msgstatus_stack.Append(new MyStr (s)); + SetStatMsg(s); +} + +void PushStatusF(const MyStr& s) +{ + msgstatus_stack.Append(new MyStr (s)); + SetStatMsg(s); + PrintFnStart(s); +} + +void PopStatus() +{ + SetThreadPercent(100.); + if (msgstatus_stack.Size()) + { + if (msgstatus_stack.Size() > 1) + SetStatMsg (*msgstatus_stack.Last()); + else + SetStatMsg (""); + delete msgstatus_stack.Last(); + msgstatus_stack.SetSize(msgstatus_stack.Size()-1); + } + else + { + PrintSysError("PopStatus failed"); + } +} +/* +void SetStatMsgF(const MyStr& s) +{ + PrintFnStart(s); + SetStatMsg(s); +} +*/ + +void SetStatMsg(const MyStr& s) +{ + msgstatus = s; + multithread.task = msgstatus.c_str(); +} + +void SetThreadPercent(double percent) +{ + multithread.percent = percent; +} + + + +#ifdef SMALLLIB +void Ng_PrintDest(const char * s){cout << s <<flush;} +double GetTime(){return 0;} +void MyError(const char * ch) +{ + cerr << ch << endl; +} +#endif + +} diff --git a/contrib/Netgen/libsrc/meshing/msghandler.hpp b/contrib/Netgen/libsrc/meshing/msghandler.hpp new file mode 100644 index 0000000000..7de9425193 --- /dev/null +++ b/contrib/Netgen/libsrc/meshing/msghandler.hpp @@ -0,0 +1,52 @@ +#ifndef FILE_MSGHANDLER +#define FILE_MSGHANDLER + +/**************************************************************************/ +/* File: msghandler.hh */ +/* Author: Johannes Gerstmayr */ +/* Date: 20. Nov. 99 */ +/**************************************************************************/ + + +extern void PrintDot(char ch = '.'); + + +//Message Pipeline: + +//importance: importance of message: 1=very important, 3=middle, 5=low, 7=unimportant +extern void PrintMessage(int importance, + const MyStr& s1, const MyStr& s2=MyStr()); +extern void PrintMessage(int importance, + const MyStr& s1, const MyStr& s2, const MyStr& s3, const MyStr& s4=MyStr()); +extern 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 void PrintMessageCR(int importance, + const MyStr& s1, const MyStr& s2="", const MyStr& s3="", const MyStr& s4="", + const MyStr& s5="", const MyStr& s6="", const MyStr& s7="", const MyStr& s8=""); +extern void PrintFnStart(const MyStr& s1, const MyStr& s2="", const MyStr& s3="", const MyStr& s4="", + const MyStr& s5="", const MyStr& s6="", const MyStr& s7="", const MyStr& s8=""); +extern void PrintWarning(const MyStr& s1, const MyStr& s2="", const MyStr& s3="", const MyStr& s4="", + const MyStr& s5="", const MyStr& s6="", const MyStr& s7="", const MyStr& s8=""); +extern void PrintError(const MyStr& s1, const MyStr& s2="", const MyStr& s3="", const MyStr& s4="", + const MyStr& s5="", const MyStr& s6="", const MyStr& s7="", const MyStr& s8=""); +extern void PrintFileError(const MyStr& s1, const MyStr& s2="", const MyStr& s3="", const MyStr& s4="", + const MyStr& s5="", const MyStr& s6="", const MyStr& s7="", const MyStr& s8=""); +extern void PrintSysError(const MyStr& s1, const MyStr& s2="", const MyStr& s3="", const MyStr& s4="", + const MyStr& s5="", const MyStr& s6="", const MyStr& s7="", const MyStr& s8=""); +extern void PrintUserError(const MyStr& s1, const MyStr& s2="", const MyStr& s3="", const MyStr& s4="", + const MyStr& s5="", const MyStr& s6="", const MyStr& s7="", const MyStr& s8=""); +extern void PrintTime(const MyStr& s1="", const MyStr& s2="", const MyStr& s3="", const MyStr& s4="", + const MyStr& s5="", const MyStr& s6="", const MyStr& s7="", const MyStr& s8=""); +extern void SetStatMsg(const MyStr& s); + +extern void PushStatus(const MyStr& s); +extern void PushStatusF(const MyStr& s); +extern void PopStatus(); +extern void SetThreadPercent(double percent); + + +#endif + diff --git a/contrib/Netgen/libsrc/meshing/netrule2.cpp b/contrib/Netgen/libsrc/meshing/netrule2.cpp new file mode 100644 index 0000000000..c75c69d521 --- /dev/null +++ b/contrib/Netgen/libsrc/meshing/netrule2.cpp @@ -0,0 +1,226 @@ +#include <mystdlib.h> +#include "meshing.hpp" + +namespace netgen +{ + +netrule :: netrule () +{ + name = new char[1]; + name[0] = char(0); + quality = 0; +} + +netrule :: ~netrule() +{ + if(name != NULL) delete [] name; + for(int i=0; i<oldutofreearea_i.Size(); i++) + delete oldutofreearea_i[i]; +} + + +/* +void netrule :: GetFreeArea (ARRAY<Point2d> & afreearea) + { + int i; + + afreearea.SetSize (freearea.Size()); + for (i = 1; i <= freearea.Size(); i++) + afreearea[i] = freearea[i]; + } +*/ + + +void netrule :: SetFreeZoneTransformation (const Vector & devp, int tolclass) +{ + double lam1 = 1.0/tolclass; + double lam2 = 1.-lam1; + + double mem1[100], mem2[100], mem3[100]; + + int vs = oldutofreearea.Height(); + FlatVector devfree(vs, mem1); + FlatVector devfree1(vs, mem2); + FlatVector devfree2(vs, mem3); + + if (tolclass <= oldutofreearea_i.Size()) + { + oldutofreearea_i[tolclass-1] -> Mult (devp, devfree); + } + else + { + oldutofreearea.Mult (devp, devfree1); + oldutofreearealimit.Mult (devp, devfree2); + devfree.Set2 (lam1, devfree1, lam2, devfree2); + } + + + int fzs = freezone.Size(); + transfreezone.SetSize (fzs); + + if (fzs > 0) + { + transfreezone[0].X() = lam1 * freezone[0].X() + lam2 * freezonelimit[0].X() + devfree[0]; + transfreezone[0].Y() = lam1 * freezone[0].Y() + lam2 * freezonelimit[0].Y() + devfree[1]; + fzmaxx = fzminx = transfreezone[0].X(); + fzmaxy = fzminy = transfreezone[0].Y(); + } + + for (int i = 1; i < fzs; i++) + { + transfreezone[i].X() = lam1 * freezone[i].X() + lam2 * freezonelimit[i].X() + devfree[2*i]; + transfreezone[i].Y() = lam1 * freezone[i].Y() + lam2 * freezonelimit[i].Y() + devfree[2*i+1]; + + if (transfreezone[i].X() > fzmaxx) fzmaxx = transfreezone[i].X(); + if (transfreezone[i].X() < fzminx) fzminx = transfreezone[i].X(); + if (transfreezone[i].Y() > fzmaxy) fzmaxy = transfreezone[i].Y(); + if (transfreezone[i].Y() < fzminy) fzminy = transfreezone[i].Y(); + } + + for (int i = 0; i < fzs; i++) + { + Point2d p1 = transfreezone[i]; + Point2d p2 = transfreezone[(i+1) % fzs]; + + Vec2d vn (p2.Y() - p1.Y(), p1.X() - p2.X()); + + double len2 = vn.Length2(); + + if (len2 < 1e-10) + { + freesetinequ(i, 0) = 0; + freesetinequ(i, 1) = 0; + freesetinequ(i, 2) = -1; + } + else + { + vn /= sqrt (len2); // should not be necessary + + freesetinequ(i,0) = vn.X(); + freesetinequ(i,1) = vn.Y(); + freesetinequ(i,2) = -(p1.X() * vn.X() + p1.Y() * vn.Y()); + } + + /* + freesetinequ(i,0) = vn.X(); + freesetinequ(i,1) = vn.Y(); + freesetinequ(i,2) = -(p1.X() * vn.X() + p1.Y() * vn.Y()); + */ + } +} + + +/* +int netrule :: IsInFreeZone2 (const Point2d & p) const +{ + for (int i = 0; i < transfreezone.Size(); i++) + { + if (freesetinequ(i, 0) * p.X() + + freesetinequ(i, 1) * p.Y() + + freesetinequ(i, 2) > 0) return 0; + } + return 1; +} +*/ + +int netrule :: IsLineInFreeZone2 (const Point2d & p1, const Point2d & p2) const +{ + int i; + int left, right, allleft, allright; + double nx, ny, nl, c; + + if (p1.X() > fzmaxx && p2.X() > fzmaxx || + p1.X() < fzminx && p2.X() < fzminx || + p1.Y() > fzmaxy && p2.Y() > fzmaxy || + p1.Y() < fzminy && p2.Y() < fzminy) return 0; + + for (i = 1; i <= transfreezone.Size(); i++) + { + if (freesetinequ.Get(i, 1) * p1.X() + freesetinequ.Get(i, 2) * p1.Y() + + freesetinequ.Get(i, 3) > -1e-6 && + freesetinequ.Get(i, 1) * p2.X() + freesetinequ.Get(i, 2) * p2.Y() + + freesetinequ.Get(i, 3) > -1e-6 + ) return 0; + } + + nx = (p2.Y() - p1.Y()); + ny = -(p2.X() - p1.X()); + nl = sqrt (nx * nx + ny * ny); + if (nl > 1e-8) + { + nx /= nl; + ny /= nl; + c = - (p1.X() * nx + p1.Y() * ny); + + allleft = 1; + allright = 1; + + for (i = 1; i <= transfreezone.Size(); i++) + { + left = transfreezone.Get(i).X() * nx + transfreezone.Get(i).Y() + c < 1e-7; + right = transfreezone.Get(i).X() * nx + transfreezone.Get(i).Y() + c > -1e-7; + + if (!left) allleft = 0; + if (!right) allright = 0; + } + if (allleft || allright) return 0; + } + + return 1; +} + +int netrule :: ConvexFreeZone () const +{ + int n = transfreezone.Size(); + for (int i = 1; i <= n; i++) + { + if (! CCW (transfreezone.Get(i), + transfreezone.Get(i % n + 1), + transfreezone.Get( (i+1) % n + 1 ) ) ) + return 0; + } + return 1; +} + + +/* +float netrule :: CalcPointDist (int pi, const Point2d & p) const +{ + float dx = p.X() - points.Get(pi).X(); + float dy = p.Y() - points.Get(pi).Y(); + const threefloat * tf = &tolerances.Get(pi); + + return tf->f1 * dx * dx + tf->f2 * dx * dy + tf->f3 * dy * dy; +} +*/ + +float netrule :: CalcLineError (int li, const Vec2d & v) const +{ + float dx = v.X() - linevecs.Get(li).X(); + float dy = v.Y() - linevecs.Get(li).Y(); + + const threefloat * tf = &linetolerances.Get(li); + return tf->f1 * dx * dx + tf->f2 * dx * dy + tf->f3 * dy * dy; +} + + + + +/* +int GetNRules () + { + return rules.Size(); + } +*/ + + + + + + + + + + + +} diff --git a/contrib/Netgen/libsrc/meshing/netrule3.cpp b/contrib/Netgen/libsrc/meshing/netrule3.cpp new file mode 100644 index 0000000000..fe6a7417c1 --- /dev/null +++ b/contrib/Netgen/libsrc/meshing/netrule3.cpp @@ -0,0 +1,1138 @@ +#include <mystdlib.h> +#include "meshing.hpp" + +// #define MARK +// #include <prof.h> + + +namespace netgen +{ + + +vnetrule :: vnetrule () +{ + name = ""; + 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.Elem(j) = allp.Get(i+3*j-3); + + oldutofreezone->Mult (vp, vfp1); + oldutofreezonelimit->Mult (vp, vfp2); + + vfp1 *= lam1; + vfp1.Add (lam2, vfp2); + + for (j = 1; j <= nfp; j++) + transfreezone.Elem(j).X(i) = vfp1.Elem(j); + } + + // MARK(setfz2); + + + fzbox.SetPoint (transfreezone.Elem(1)); + for (i = 2; i <= freezone.Size(); i++) + fzbox.AddPoint (transfreezone.Elem(i)); + + + // MARK(setfz3); + + + for (fs = 1; fs <= freesets.Size(); fs++) + { + ARRAY<threeint> & freesetfaces = *freefaces.Get(fs); + DenseMatrix & freesetinequ = *freefaceinequ.Get(fs); + + for (i = 1; i <= freesetfaces.Size(); i++) + { + ti = &freesetfaces.Get(i); + const Point3d & p1 = transfreezone.Get(ti->i1); + const Point3d & p2 = transfreezone.Get(ti->i2); + const Point3d & p3 = transfreezone.Get(ti->i3); + + Vec3d v1(p1, p2); + Vec3d v2(p1, p3); + Vec3d n; + Cross (v1, v2, n); + + nl = n.Length(); + + if (nl < 1e-10) + { + freesetinequ.Set(1, 1, 0); + freesetinequ.Set(1, 2, 0); + freesetinequ.Set(1, 3, 0); + freesetinequ.Set(1, 4, -1); + } + else + { + // n /= nl; + + freesetinequ.Set(i, 1, n.X()/nl); + freesetinequ.Set(i, 2, n.Y()/nl); + freesetinequ.Set(i, 3, n.Z()/nl); + freesetinequ.Set(i, 4, + -(p1.X() * n.X() + p1.Y() * n.Y() + p1.Z() * n.Z()) / nl); + } + } + } + + /* + (*testout) << "Transformed freezone: " << endl; + for (i = 1; i <= transfreezone.Size(); i++) + (*testout) << transfreezone.Get(i) << " "; + (*testout) << endl; + */ +} + +int vnetrule :: ConvexFreeZone () const +{ + int i, j, k, fs; + + // (*mycout) << "Convex free zone...\n"; + + int ret1=1; + // int ret2=1; + + for (fs = 1; fs <= freesets.Size(); fs++) + { + const DenseMatrix & freesetinequ = *freefaceinequ.Get(fs); + + // const ARRAY<int> & freeset = *freesets.Get(fs); + const ARRAY<twoint> & freesetedges = *freeedges.Get(fs); + // const ARRAY<threeint> & freesetfaces = *freefaces.Get(fs); + + for (i = 1; i <= freesetedges.Size(); i++) + { + j = freesetedges.Get(i).i1; //triangle j with opposite point k + k = freesetedges.Get(i).i2; + + if ( freesetinequ.Get(j, 1) * transfreezone.Get(k).X() + + freesetinequ.Get(j, 2) * transfreezone.Get(k).Y() + + freesetinequ.Get(j, 3) * transfreezone.Get(k).Z() + + freesetinequ.Get(j, 4) > 0 ) + { + ret1=0; + } + } + + } + + return ret1; +} + + +int vnetrule :: IsInFreeZone (const Point3d & p) const +{ + int i, fs; + char inthis; + + + for (fs = 1; fs <= freesets.Size(); fs++) + { + inthis = 1; + ARRAY<threeint> & freesetfaces = *freefaces.Get(fs); + DenseMatrix & freesetinequ = *freefaceinequ.Get(fs); + + for (i = 1; i <= freesetfaces.Size() && inthis; i++) + { + if (freesetinequ.Get(i, 1) * p.X() + freesetinequ.Get(i, 2) * p.Y() + + freesetinequ.Get(i, 3) * p.Z() + freesetinequ.Get(i, 4) > 0) + inthis = 0; + } + + if (inthis) return 1; + } + + return 0; +} + + +int vnetrule :: IsTriangleInFreeZone (const Point3d & p1, + const Point3d & p2, + const Point3d & p3, + const ARRAY<int> & pi, int newone) +{ + int fs; + int infreeset, cannot = 0; + + + static ARRAY<int> pfi(3), pfi2(3); + + // convert from local index to freeset index + int i, j; + for (i = 1; i <= 3; i++) + { + pfi.Elem(i) = 0; + if (pi.Get(i)) + { + for (j = 1; j <= freezonepi.Size(); j++) + if (freezonepi.Get(j) == pi.Get(i)) + pfi.Elem(i) = j; + } + } + + for (fs = 1; fs <= freesets.Size(); fs++) + { + const ARRAY<int> & freeseti = *freesets.Get(fs); + for (i = 1; i <= 3; i++) + { + pfi2.Elem(i) = 0; + for (j = 1; j <= freeseti.Size(); j++) + if (pfi.Get(i) == freeseti.Get(j)) + pfi2.Elem(i) = pfi.Get(i); + } + + infreeset = IsTriangleInFreeSet(p1, p2, p3, fs, pfi2, newone); + if (infreeset == 1) return 1; + if (infreeset == -1) cannot = -1; + } + + return cannot; +} + + + +int vnetrule :: IsTriangleInFreeSet (const Point3d & p1, const Point3d & p2, + const Point3d & p3, int fs, + const ARRAY<int> & pi, int newone) +{ + int i, ii; + Vec3d n; + int allleft, allright; + int hos1, hos2, hos3, os1, os2, os3; + double hf, lam1, lam2, f, c1, c2, alpha; + double v1n, v2n, h11, h12, h22, dflam1, dflam2; + double lam1old, lam2old, fold; + double hpx, hpy, hpz, v1x, v1y, v1z, v2x, v2y, v2z; + int act1, act2, act3, it; + int cntout; + static ARRAY<int> activefaces; + int isin; + + + // MARK(triinfz); + + ARRAY<threeint> & freesetfaces = *freefaces.Get(fs); + DenseMatrix & freesetinequ = *freefaceinequ.Get(fs); + + + int cnt = 0; + for (i = 1; i <= 3; i++) + if (pi.Get(i)) cnt++; + + /* + (*testout) << "trig in free set : " << p1 << " - " << p2 << " - " << p3 << endl; + (*testout) << "common points: " << cnt << endl; + */ + if (!newone) + cnt = 0; + + if (cnt == 1) + { + // MARK(triinfz1); + + int upi = 0, lpiu = 0; + for (i = 1; i <= 3; i++) + if (pi.Get(i)) + { + upi = i; + lpiu = pi.Get(i); + } + + Vec3d v1, v2; + switch (upi) + { + case 1: + { + v1 = p2 - p1; + v2 = p3 - p1; + break; + } + case 2: + { + v1 = p3 - p2; + v2 = p1 - p2; + break; + } + case 3: + { + v1 = p1 - p3; + v2 = p2 - p3; + break; + } + } + + v1 /= v1.Length(); + v2 /= v2.Length(); + Cross (v1, v2, n); + n /= n.Length(); + + // (*testout) << "Test new: " << endl; + for (i = 1; i <= freesetfaces.Size(); i++) + { + if ( (freesetfaces.Get(i).i1 == lpiu) || + (freesetfaces.Get(i).i2 == lpiu) || + (freesetfaces.Get(i).i3 == lpiu) ) + { + // freeface has point + + + Vec3d a (freesetinequ.Get(i, 1), + freesetinequ.Get(i, 2), + freesetinequ.Get(i, 3)); + + // if (1 - fabs (a * n) < 1e-8 ) + // continue; + + Vec3d an; + Cross (a, n, an); + double lan = an.Length(); + if (lan < 1e-10) + continue; + + an /= lan; + + int out1 = (a * v1) > 0; + int out2 = (a * v2) > 0; + // (*testout) << "out1, out2 = " << out1 << ", " << out2 << endl; + if (out1 && out2) + return 0; + + if (!out1 && !out2) + continue; + + + // if ( ( (an * v1) < 0) && ( (an * v2) < 0) ) // falsch !!!! + // an *= -1; + + // solve an = lam1 v1 + lam2 v2 + double vii11 = v1 * v1; + double vii12 = v1 * v2; + double vii22 = v2 * v2; + double det = vii11 * vii22 - vii12 * vii12; + if ( fabs (det) < 1e-10 ) + continue; + double rs1 = an * v1; + double rs2 = an * v2; + + double lam1 = rs1 * vii22 - rs2 * vii12; + double lam2 = rs2 * vii11 - rs1 * vii12; + + if (fabs (lam1) > fabs (lam2)) + { + if (lam1 < 0) + an *= -1; + } + else + { + if (lam2 < 0) + an *= -1; + } + + + if (lam1 * lam2 < 0 && 0) + { + if (fabs (lam1) > 1e-14 && fabs (lam2) > 1e-14) + { + // (*mycout) << "lam1 lam2 < 0" << endl; + (*testout) << "lami different" << endl; + (*testout) << "v1 = " << v1 << endl; + (*testout) << "v2 = " << v2 << endl; + (*testout) << "n = " << n << endl; + (*testout) << "a = " << a << endl; + (*testout) << "an = " << an << endl; + (*testout) << "a * v1 = " << (a * v1) << endl; + (*testout) << "a * v2 = " << (a * v2) << endl; + (*testout) << "an * v1 = " << (an * v1) << endl; + (*testout) << "an * v2 = " << (an * v2) << endl; + + (*testout) << "vii = " << vii11 << ", " << vii12 << ", " << vii22 << endl; + (*testout) << "lami = " << lam1 << ", " << lam2 << endl; + (*testout) << "rs = " << rs1 << ", " << rs2 << endl; + continue; + } + } + + if (out1) + v1 = an; + else + v2 = an; + } + } + + return 1; + + /* + (*testout) << "overlap trig " << p1 << p2 << p3 << endl; + (*testout) << "upi = " << upi << endl; + (*testout) << "v1 = " << v1 << " v2 = " << v2 << endl; + */ + + switch (upi) + { + case 1: + { + v1 = p2 - p1; + v2 = p3 - p1; + break; + } + case 2: + { + v1 = p3 - p2; + v2 = p1 - p2; + break; + } + case 3: + { + v1 = p1 - p3; + v2 = p2 - p3; + break; + } + } + + v1 /= v1.Length(); + v2 /= v2.Length(); + Cross (v1, v2, n); + n /= n.Length(); + + // (*testout) << "orig v1, v2 = " << v1 << ", " << v2 << endl; + + + for (i = 1; i <= freesetfaces.Size(); i++) + { + if ( (freesetfaces.Get(i).i1 == lpiu) || + (freesetfaces.Get(i).i2 == lpiu) || + (freesetfaces.Get(i).i3 == lpiu) ) + { + /* + (*testout) << "v1, v2, now = " << v1 << ", " << v2 << endl; + + // freeface has point + (*testout) << "freesetface: " + << freesetfaces.Get(i).i1 << " " + << freesetfaces.Get(i).i2 << " " + << freesetfaces.Get(i).i3 << " "; + */ + + Vec3d a (freesetinequ.Get(i, 1), + freesetinequ.Get(i, 2), + freesetinequ.Get(i, 3)); + // (*testout) << "a = " << a << endl; + + + Vec3d an; + Cross (a, n, an); + double lan = an.Length(); + + // (*testout) << "an = " << an << endl; + + if (lan < 1e-10) + continue; + + an /= lan; + + // (*testout) << "a*v1 = " << (a*v1) << " a*v2 = " << (a*v2) << endl; + + int out1 = (a * v1) > 0; + // int out2 = (a * v2) > 0; + + + // (*testout) << "out1, 2 = " << out1 << ", " << out2 << endl; + + + double vii11 = v1 * v1; + double vii12 = v1 * v2; + double vii22 = v2 * v2; + double det = vii11 * vii22 - vii12 * vii12; + if ( fabs (det) < 1e-10 ) + continue; + double rs1 = an * v1; + double rs2 = an * v2; + + double lam1 = rs1 * vii22 - rs2 * vii12; + double lam2 = rs2 * vii11 - rs1 * vii12; + + // (*testout) << "lam1, lam2 = " << lam1 << ", " << lam2 << endl; + + + if (fabs (lam1) > fabs (lam2)) + { + if (lam1 < 0) + an *= -1; + } + else + { + if (lam2 < 0) + an *= -1; + } + + + if (lam1 * lam2 < 0) + { + if (fabs (lam1) > 1e-14 && fabs (lam2) > 1e-14) + { + // (*mycout) << "lam1 lam2 < 0" << endl; + (*testout) << "lami different" << endl; + (*testout) << "v1 = " << v1 << endl; + (*testout) << "v2 = " << v2 << endl; + (*testout) << "n = " << n << endl; + (*testout) << "a = " << a << endl; + (*testout) << "an = " << an << endl; + (*testout) << "a * v1 = " << (a * v1) << endl; + (*testout) << "a * v2 = " << (a * v2) << endl; + (*testout) << "an * v1 = " << (an * v1) << endl; + (*testout) << "an * v2 = " << (an * v2) << endl; + + (*testout) << "vii = " << vii11 << ", " << vii12 << ", " << vii22 << endl; + (*testout) << "lami = " << lam1 << ", " << lam2 << endl; + (*testout) << "rs = " << rs1 << ", " << rs2 << endl; + continue; + } + } + + if (out1) + v1 = an; + else + v2 = an; + + + + } + } + + return 1; + } + + + + if (cnt == 2) + { + // (*testout) << "tripoitns: " << p1 << " " << p2 << " " << p3 << endl; + + // MARK(triinfz2); + + int pi1 = 0, pi2 = 0, pi3 = 0; + Vec3d a1, a2; // outer normals + Vec3d trivec; // vector from common edge to third point of triangle + for (i = 1; i <= 3; i++) + if (pi.Get(i)) + { + pi2 = pi1; + pi1 = pi.Get(i); + } + else + pi3 = i; + + switch (pi3) + { + case 1: trivec = (p1 - p2); break; + case 2: trivec = (p2 - p3); break; + case 3: trivec = (p3 - p2); break; + } + + ARRAY<int> lpi(freezonepi.Size()); + for (i = 1; i <= lpi.Size(); i++) + lpi.Elem(i) = 0; + lpi.Elem(pi1) = 1; + lpi.Elem(pi2) = 1; + + int ff1 = 0, ff2 = 0; + for (i = 1; i <= freesetfaces.Size(); i++) + { + if (lpi.Get(freesetfaces.Get(i).i1) + + lpi.Get(freesetfaces.Get(i).i2) + + lpi.Get(freesetfaces.Get(i).i3) == 2) + { + ff2 = ff1; + ff1 = i; + } + } + + if (ff2 == 0) + return 1; + + a1 = Vec3d (freesetinequ.Get(ff1, 1), + freesetinequ.Get(ff1, 2), + freesetinequ.Get(ff1, 3)); + a2 = Vec3d (freesetinequ.Get(ff2, 1), + freesetinequ.Get(ff2, 2), + freesetinequ.Get(ff2, 3)); + + if ( ( (a1 * trivec) > 0) || ( (a2 * trivec) > 0)) + return 0; + + return 1; + } + + + if (cnt == 3) + { + // MARK(triinfz3); + + ARRAY<int> lpi(freezonepi.Size()); + for (i = 1; i <= lpi.Size(); i++) + lpi.Elem(i) = 0; + + for (i = 1; i <= 3; i++) + lpi.Elem(pi.Get(i)) = 1; + + for (i = 1; i <= freesetfaces.Size(); i++) + { + if (lpi.Get(freesetfaces.Get(i).i1) + + lpi.Get(freesetfaces.Get(i).i2) + + lpi.Get(freesetfaces.Get(i).i3) == 3) + { + return 0; + } + } + return 1; + } + + // MARK(triinfz0); + + + os1 = os2 = os3 = 0; + activefaces.SetSize(0); + + // is point inside ? + + for (i = 1; i <= freesetfaces.Size(); i++) + { + hos1 = freesetinequ.Get(i, 1) * p1.X() + + freesetinequ.Get(i, 2) * p1.Y() + + freesetinequ.Get(i, 3) * p1.Z() + + freesetinequ.Get(i, 4) > -1E-5; + + hos2 = freesetinequ.Get(i, 1) * p2.X() + + freesetinequ.Get(i, 2) * p2.Y() + + freesetinequ.Get(i, 3) * p2.Z() + + freesetinequ.Get(i, 4) > -1E-5; + + hos3 = freesetinequ.Get(i, 1) * p3.X() + + freesetinequ.Get(i, 2) * p3.Y() + + freesetinequ.Get(i, 3) * p3.Z() + + freesetinequ.Get(i, 4) > -1E-5; + + if (hos1 && hos2 && hos3) return 0; + + if (hos1) os1 = 1; + if (hos2) os2 = 1; + if (hos3) os3 = 1; + + if (hos1 || hos2 || hos3) activefaces.Append (i); + } + + if (!os1 || !os2 || !os3) return 1; + + v1x = p2.X() - p1.X(); + v1y = p2.Y() - p1.Y(); + v1z = p2.Z() - p1.Z(); + + v2x = p3.X() - p1.X(); + v2y = p3.Y() - p1.Y(); + v2z = p3.Z() - p1.Z(); + + n.X() = v1y * v2z - v1z * v2y; + n.Y() = v1z * v2x - v1x * v2z; + n.Z() = v1x * v2y - v1y * v2x; + n /= n.Length(); + + allleft = allright = 1; + for (i = 1; i <= transfreezone.Size() && (allleft || allright); i++) + { + const Point3d & p = transfreezone.Get(i); + float scal = (p.X() - p1.X()) * n.X() + + (p.Y() - p1.Y()) * n.Y() + + (p.Z() - p1.Z()) * n.Z(); + + if ( scal > 1E-8 ) allleft = 0; + if ( scal < -1E-8 ) allright = 0; + } + + if (allleft || allright) return 0; + + + lam1old = lam2old = lam1 = lam2 = 1.0 / 3.0; + + + // testout << endl << endl << "Start minimizing" << endl; + + it = 0; + int minit; + minit = 1000; + fold = 1E10; + + + + while (1) + { + it++; + + if (it > 1000) return -1; + + if (lam1 < 0) lam1 = 0; + if (lam2 < 0) lam2 = 0; + if (lam1 + lam2 > 1) lam1 = 1 - lam2; + + if (it > minit) + { + (*testout) << "it = " << it << endl; + (*testout) << "lam1/2 = " << lam1 << " " << lam2 << endl; + } + + hpx = p1.X() + lam1 * v1x + lam2 * v2x; + hpy = p1.Y() + lam1 * v1y + lam2 * v2y; + hpz = p1.Z() + lam1 * v1z + lam2 * v2z; + + f = 0; + + h11 = h12 = h22 = dflam1 = dflam2 = 0; + cntout = 0; + + isin = 1; + + for (i = 1; i <= activefaces.Size(); i++) + { + ii = activefaces.Get(i); + + hf = freesetinequ.Get(ii, 1) * hpx + + freesetinequ.Get(ii, 2) * hpy + + freesetinequ.Get(ii, 3) * hpz + + freesetinequ.Get(ii, 4); + + if (hf > -1E-7) isin = 0; + + hf += 1E-4; + if (hf > 0) + { + f += hf * hf; + + v1n = freesetinequ.Get(ii, 1) * v1x + + freesetinequ.Get(ii, 2) * v1y + + freesetinequ.Get(ii, 3) * v1z; + v2n = freesetinequ.Get(ii, 1) * v2x + + freesetinequ.Get(ii, 2) * v2y + + freesetinequ.Get(ii, 3) * v2z; + + h11 += 2 * v1n * v1n; + h12 += 2 * v1n * v2n; + h22 += 2 * v2n * v2n; + dflam1 += 2 * hf * v1n; + dflam2 += 2 * hf * v2n; + cntout++; + } + } + + if (isin) return 1; + + if (it > minit) + { + (*testout) << "f = " << f + << " dfdlam = " << dflam1 << " " << dflam2 << endl; + (*testout) << "h = " << h11 << " " << h12 << " " << h22 << endl; + (*testout) << "active: " << cntout << endl; + (*testout) << "lam1-lam1old = " << (lam1 - lam1old) << endl; + (*testout) << "lam2-lam2old = " << (lam2 - lam2old) << endl; + } + + + if (f >= fold) + { + lam1 = 0.100000000000000 * lam1 + 0.9000000000000000 * lam1old; + lam2 = 0.100000000000000 * lam2 + 0.9000000000000000 * lam2old; + } + else + { + lam1old = lam1; + lam2old = lam2; + fold = f; + + + if (f < 1E-9) return 1; + + h11 += 1E-10; + h22 += 1E-10; + c1 = - ( h22 * dflam1 - h12 * dflam2) / (h11 * h22 - h12 * h12); + c2 = - (-h12 * dflam1 + h11 * dflam2) / (h11 * h22 - h12 * h12); + alpha = 1; + + + if (it > minit) + (*testout) << "c1/2 = " << c1 << " " << c2 << endl; + + act1 = lam1 <= 1E-6 && c1 <= 0; + act2 = lam2 <= 1E-6 && c2 <= 0; + act3 = lam1 + lam2 >= 1 - 1E-6 && c1 + c2 >= 0; + + if (it > minit) + (*testout) << "act1,2,3 = " << act1 << act2 << act3 << endl; + + if (act1 && act2 || act1 && act3 || act2 && act3) return 0; + + if (act1) + { + c1 = 0; + c2 = - dflam2 / h22; + } + + if (act2) + { + c1 = - dflam1 / h11; + c2 = 0; + } + + if (act3) + { + c1 = - (dflam1 - dflam2) / (h11 + h22 - 2 * h12); + c2 = -c1; + } + + if (it > minit) + (*testout) << "c1/2 now = " << c1 << " " << c2 << endl; + + + if (f > 100 * sqrt (sqr (c1) + sqr (c2))) return 0; + + + if (lam1 + alpha * c1 < 0 && !act1) + alpha = -lam1 / c1; + if (lam2 + alpha * c2 < 0 && !act2) + alpha = -lam2 / c2; + if (lam1 + lam2 + alpha * (c1 + c2) > 1 && !act3) + alpha = (1 - lam1 - lam2) / (c1 + c2); + + if (it > minit) + (*testout) << "alpha = " << alpha << endl; + + lam1 += alpha * c1; + lam2 += alpha * c2; + } + } +} + + + + +int vnetrule :: IsQuadInFreeZone (const Point3d & p1, + const Point3d & p2, + const Point3d & p3, + const Point3d & p4, + const ARRAY<int> & pi, int newone) +{ + int fs; + int infreeset, cannot = 0; + + + static ARRAY<int> pfi(4), pfi2(4); + + // convert from local index to freeset index + int i, j; + for (i = 1; i <= 4; i++) + { + pfi.Elem(i) = 0; + if (pi.Get(i)) + { + for (j = 1; j <= freezonepi.Size(); j++) + if (freezonepi.Get(j) == pi.Get(i)) + pfi.Elem(i) = j; + } + } + + for (fs = 1; fs <= freesets.Size(); fs++) + { + const ARRAY<int> & freeseti = *freesets.Get(fs); + for (i = 1; i <= 4; i++) + { + pfi2.Elem(i) = 0; + for (j = 1; j <= freeseti.Size(); j++) + if (pfi.Get(i) == freeseti.Get(j)) + pfi2.Elem(i) = pfi.Get(i); + } + + infreeset = IsQuadInFreeSet(p1, p2, p3, p4, fs, pfi2, newone); + if (infreeset == 1) return 1; + if (infreeset == -1) cannot = -1; + } + + return cannot; +} + + +int vnetrule :: IsQuadInFreeSet (const Point3d & p1, const Point3d & p2, + const Point3d & p3, const Point3d & p4, + int fs, const ARRAY<int> & pi, int newone) +{ + int i; + + int cnt = 0; + for (i = 1; i <= 4; i++) + if (pi.Get(i)) cnt++; + + /* + (*testout) << "test quad in freeset: " << p1 << " - " << p2 << " - " << p3 << " - " << p4 << endl; + (*testout) << "pi = "; + for (i = 1; i <= pi.Size(); i++) + (*testout) << pi.Get(i) << " "; + (*testout) << endl; + (*testout) << "cnt = " << cnt << endl; + */ + if (cnt == 4) + { + return 1; + } + + if (cnt == 3) + { + return 1; + } + + static ARRAY<int> pi3(3); + int res; + + pi3.Elem(1) = pi.Get(1); + pi3.Elem(2) = pi.Get(2); + pi3.Elem(3) = pi.Get(3); + res = IsTriangleInFreeSet (p1, p2, p3, fs, pi3, newone); + if (res) return res; + + + pi3.Elem(1) = pi.Get(2); + pi3.Elem(2) = pi.Get(3); + pi3.Elem(3) = pi.Get(4); + res = IsTriangleInFreeSet (p2, p3, p4, fs, pi3, newone); + if (res) return res; + + pi3.Elem(1) = pi.Get(3); + pi3.Elem(2) = pi.Get(4); + pi3.Elem(3) = pi.Get(1); + res = IsTriangleInFreeSet (p3, p4, p1, fs, pi3, newone); + if (res) return res; + + pi3.Elem(1) = pi.Get(4); + pi3.Elem(2) = pi.Get(1); + pi3.Elem(3) = pi.Get(2); + res = IsTriangleInFreeSet (p4, p1, p2, fs, pi3, newone); + return res; +} + + + + + + + + + + + + +float vnetrule :: CalcPointDist (int pi, const Point3d & p) const +{ + float dx = p.X() - points.Get(pi).X(); + float dy = p.Y() - points.Get(pi).Y(); + float dz = p.Z() - points.Get(pi).Z(); + + // const threefloat * tf = &tolerances.Get(pi); + // return tf->f1 * dx * dx + tf->f2 * dx * dy + tf->f3 * dy * dy; + return tolerances.Get(pi) * (dx * dx + dy * dy + dz * dz); +} + + +int vnetrule :: TestOk () const +{ + ARRAY<int> cntpused(points.Size()); + ARRAY<int> edge1, edge2; + ARRAY<int> delf(faces.Size()); + int i, j, k; + int pi1, pi2; + int found; + + for (i = 1; i <= cntpused.Size(); i++) + cntpused.Elem(i) = 0; + for (i = 1; i <= faces.Size(); i++) + delf.Elem(i) = 0; + for (i = 1; i <= delfaces.Size(); i++) + delf.Elem(delfaces.Get(i)) = 1; + + + for (i = 1; i <= faces.Size(); i++) + if (delf.Get(i) || i > noldf) + for (j = 1; j <= faces.Get(i).GetNP(); j++) + cntpused.Elem(faces.Get(i).PNum(j))++; + + for (i = 1; i <= cntpused.Size(); i++) + if (cntpused.Get(i) > 0 && cntpused.Get(i) < 2) + { + return 0; + } + + + // (*testout) << endl; + for (i = 1; i <= faces.Size(); i++) + { + // (*testout) << "face " << i << endl; + for (j = 1; j <= faces.Get(i).GetNP(); j++) + { + pi1 = 0; pi2 = 0; + if (delf.Get(i)) + { + pi1 = faces.Get(i).PNumMod(j); + pi2 = faces.Get(i).PNumMod(j+1); + } + if (i > noldf) + { + pi1 = faces.Get(i).PNumMod(j+1); + pi2 = faces.Get(i).PNumMod(j); + } + + found = 0; + if (pi1) + { + for (k = 1; k <= edge1.Size(); k++) + if (edge1.Get(k) == pi1 && edge2.Get(k) == pi2) + { + found = 1; + edge1.DeleteElement(k); + edge2.DeleteElement(k); + k--; + // (*testout) << "Del edge " << pi1 << "-" << pi2 << endl; + } + if (!found) + { + edge1.Append (pi2); + edge2.Append (pi1); + // (*testout) << "Add edge " << pi1 << "-" << pi2 << endl; + } + } + } + } + + + if (edge1.Size() > 0) + { + return 0; + } + + /* + cntpused.SetSize(freezone.Size()); + for (i = 1; i <= cntpused.Size(); i++) + cntpused[i] = 0; + + for (i = 1; i <= freefaces.Size(); i++) + { + cntpused[freefaces[i].i1]++; + cntpused[freefaces[i].i2]++; + cntpused[freefaces[i].i3]++; + } + + for (i = 1; i <= cntpused.Size(); i++) + if (cntpused[i] < 3) + { + (*mycout) << "Fall 3" << endl; + return 0; + } + + + + for (i = 1; i <= freefaces.Size(); i++) + { + for (j = 1; j <= 3; j++) + { + if (j == 1) + { + pi1 = freefaces[i].i1; + pi2 = freefaces[i].i2; + } + if (j == 2) + { + pi1 = freefaces[i].i2; + pi2 = freefaces[i].i3; + } + if (j == 3) + { + pi1 = freefaces[i].i3; + pi2 = freefaces[i].i1; + } + + found = 0; + for (k = 1; k <= edge1.Size(); k++) + if (edge1[k] == pi1 && edge2[k] == pi2) + { + found = 1; + edge1.DeleteElement(k); + edge2.DeleteElement(k); + k--; + } + + if (!found) + { + edge1.Append (pi2); + edge2.Append (pi1); + } + } + } + + if (edge1.Size() > 0) + { + (*mycout) << "Fall 4" << endl; + return 0; + } + */ + return 1; +} + + +int vnetrule :: IsDelFace (int fn) const +{ + int i; + for (i = 1; i <= GetNDelF(); i++) + if (GetDelFace(i) == fn) return 1; + return 0; +} + +} diff --git a/contrib/Netgen/libsrc/meshing/parser2.cpp b/contrib/Netgen/libsrc/meshing/parser2.cpp new file mode 100644 index 0000000000..48ef280eb4 --- /dev/null +++ b/contrib/Netgen/libsrc/meshing/parser2.cpp @@ -0,0 +1,559 @@ +#include <mystdlib.h> +#include "meshing.hpp" + +namespace netgen +{ + + +void LoadMatrixLine (istream & ist, DenseMatrix & m, int line) +{ + char ch; + int pnum; + float f; + + ist >> ch; + while (ch != '}') + { + ist.putback (ch); + ist >> f; + ist >> ch; + ist >> pnum; + + if (ch == 'x' || ch == 'X') + m.Elem(line, 2 * pnum - 1) = f; + if (ch == 'y' || ch == 'Y') + m.Elem(line, 2 * pnum) = f; + + ist >> ch; + if (ch == ',') + ist >> ch; + } +} + + +void netrule :: LoadRule (istream & ist) +{ + char buf[256]; + char ch; + Point2d p; + INDEX_2 lin; + int i, j; + DenseMatrix tempoldutonewu(20, 20), tempoldutofreearea(20, 20), + tempoldutofreearealimit(20, 20); + + tempoldutonewu = 0; + tempoldutofreearea = 0; + tempoldutofreearealimit = 0; + + noldp = 0; + noldl = 0; + + ist.get (buf, sizeof(buf), '"'); + ist.get (ch); + ist.get (buf, sizeof(buf), '"'); + ist.get (ch); + + if(name != NULL) delete [] name; + name = new char[strlen (buf) + 1]; + strcpy (name, buf); + // (*mycout) << "Rule " << name << " found." << endl; + + do + { + ist >> buf; + + if (strcmp (buf, "quality") == 0) + + { + ist >> quality; + } + + else if (strcmp (buf, "mappoints") == 0) + { + ist >> ch; + + while (ch == '(') + { + ist >> p.X(); + ist >> ch; // ',' + ist >> p.Y(); + ist >> ch; // ')' + + points.Append (p); + noldp++; + + tolerances.SetSize (noldp); + tolerances.Elem(noldp).f1 = 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; // ')' + + lines.Append (lin); + linevecs.Append (points.Get(lin.I2()) - points.Get(lin.I1())); + noldl++; + linetolerances.SetSize (noldl); + linetolerances.Elem(noldl).f1 = 0; + linetolerances.Elem(noldl).f2 = 0; + linetolerances.Elem(noldl).f3 = 0; + + ist >> ch; + while (ch != ';') + { + if (ch == '{') + { + ist >> linetolerances.Elem(noldl).f1; + ist >> ch; // ',' + ist >> linetolerances.Elem(noldl).f2; + ist >> ch; // ',' + ist >> linetolerances.Elem(noldl).f3; + ist >> ch; // '}' + } + else if (ch == 'd') + { + dellines.Append (noldl); + ist >> ch; // 'e' + ist >> ch; // 'l' + } + + ist >> ch; + } + + ist >> ch; + } + + ist.putback (ch); + } + + else if (strcmp (buf, "newpoints") == 0) + { + ist >> ch; + + while (ch == '(') + { + ist >> p.X(); + ist >> ch; // ',' + ist >> p.Y(); + ist >> ch; // ')' + + points.Append (p); + + ist >> ch; + while (ch != ';') + { + if (ch == '{') + { + LoadMatrixLine (ist, tempoldutonewu, + 2 * (points.Size()-noldp) - 1); + + ist >> ch; // '{' + LoadMatrixLine (ist, tempoldutonewu, + 2 * (points.Size()-noldp)); + } + + ist >> ch; + } + + ist >> ch; + } + + ist.putback (ch); + } + + else if (strcmp (buf, "newlines") == 0) + { + ist >> ch; + + while (ch == '(') + { + ist >> lin.I1(); + ist >> ch; // ',' + ist >> lin.I2(); + ist >> ch; // ')' + + lines.Append (lin); + linevecs.Append (points.Get(lin.I2()) - points.Get(lin.I1())); + + ist >> ch; + while (ch != ';') + { + ist >> ch; + } + + ist >> ch; + } + + ist.putback (ch); + } + + else if (strcmp (buf, "freearea") == 0) + { + ist >> ch; + + while (ch == '(') + { + ist >> p.X(); + ist >> ch; // ',' + ist >> p.Y(); + ist >> ch; // ')' + + freezone.Append (p); + freezonelimit.Append (p); + + ist >> ch; + while (ch != ';') + { + if (ch == '{') + { + LoadMatrixLine (ist, tempoldutofreearea, + 2 * freezone.Size() - 1); + + ist >> ch; // '{' + LoadMatrixLine (ist, tempoldutofreearea, + 2 * freezone.Size()); + } + + ist >> ch; + } + + ist >> ch; + } + + for (i = 1; i <= tempoldutofreearealimit.Height(); i++) + for (j = 1; j <= tempoldutofreearealimit.Width(); j++) + tempoldutofreearealimit.Elem(i,j) = + tempoldutofreearea.Elem(i,j); + + + ist.putback (ch); + } + else if (strcmp (buf, "freearea2") == 0) + { + ist >> ch; + int freepi = 0; + tempoldutofreearealimit = 0; + + while (ch == '(') + { + freepi++; + + ist >> p.X(); + ist >> ch; // ',' + ist >> p.Y(); + ist >> ch; // ')' + + freezonelimit.Elem(freepi) = p; + + ist >> ch; + while (ch != ';') + { + if (ch == '{') + { + LoadMatrixLine (ist, tempoldutofreearealimit, + 2 * freepi - 1); + + ist >> ch; // '{' + LoadMatrixLine (ist, tempoldutofreearealimit, + 2 * freepi); + } + + ist >> ch; + } + + ist >> ch; + } + + ist.putback (ch); + } + + else if (strcmp (buf, "elements") == 0) + { + ist >> ch; + + while (ch == '(') + { + elements.Append (Element2d()); + + ist >> elements.Last().PNum(1); + ist >> ch; // ',' + + if (ch == ',') + { + ist >> elements.Last().PNum(2); + ist >> ch; // ',' + } + if (ch == ',') + { + ist >> elements.Last().PNum(3); + ist >> ch; // ',' + } + if (ch == ',') + { + elements.Last().SetType (QUAD); + ist >> elements.Last().PNum(4); + ist >> ch; // ',' + + // const Element2d & el = elements.Last(); + /* + orientations.Append (threeint(el.PNum(1), el.PNum(2), el.PNum(3))); + orientations.Append (threeint(el.PNum(2), el.PNum(3), el.PNum(4))); + orientations.Append (threeint(el.PNum(3), el.PNum(4), el.PNum(1))); + orientations.Append (threeint(el.PNum(4), el.PNum(1), el.PNum(2))); + */ + } + + ist >> ch; + while (ch != ';') + { + ist >> ch; + } + + ist >> ch; + } + + ist.putback (ch); + } + + else if (strcmp (buf, "orientations") == 0) + + { + ist >> ch; + + while (ch == '(') + { + // threeint a = threeint(); + orientations.Append (threeint()); + + ist >> orientations.Last().i1; + ist >> ch; // ',' + ist >> orientations.Last().i2; + ist >> ch; // ',' + ist >> orientations.Last().i3; + ist >> ch; // ',' + + ist >> ch; + while (ch != ';') + { + ist >> ch; + } + + ist >> ch; + } + + ist.putback (ch); + } + + else if (strcmp (buf, "endrule") != 0) + { + PrintSysError ("Parser error, unknown token ", buf); + } + } + while (!ist.eof() && strcmp (buf, "endrule") != 0); + + oldutonewu.SetSize (2 * (points.Size() - noldp), 2 * noldp); + oldutofreearea.SetSize (2 * freezone.Size(), 2 * noldp); + oldutofreearealimit.SetSize (2 * freezone.Size(), 2 * noldp); + + for (i = 1; i <= oldutonewu.Height(); i++) + for (j = 1; j <= oldutonewu.Width(); j++) + oldutonewu.Elem(i, j) = tempoldutonewu.Elem(i, j); + + for (i = 1; i <= oldutofreearea.Height(); i++) + for (j = 1; j <= oldutofreearea.Width(); j++) + oldutofreearea.Elem(i, j) = tempoldutofreearea.Elem(i, j); + + for (i = 1; i <= oldutofreearea.Height(); i++) + for (j = 1; j <= oldutofreearea.Width(); j++) + oldutofreearealimit.Elem(i, j) = tempoldutofreearealimit.Elem(i, j); + + freesetinequ.SetSize (freezone.Size()); + + + + { + char ok; + int minn; + ARRAY<int> pnearness (noldp); + + for (i = 1; i <= pnearness.Size(); i++) + pnearness.Elem(i) = 1000; + + for (j = 1; j <= 2; j++) + pnearness.Elem(GetPointNr (1, j)) = 0; + + do + { + ok = 1; + + for (i = 1; i <= noldl; i++) + { + minn = 1000; + for (j = 1; j <= 2; j++) + minn = min2 (minn, pnearness.Get(GetPointNr (i, j))); + + for (j = 1; j <= 2; j++) + if (pnearness.Get(GetPointNr (i, j)) > minn+1) + { + ok = 0; + pnearness.Elem(GetPointNr (i, j)) = minn+1; + } + } + } + while (!ok); + + lnearness.SetSize (noldl); + + for (i = 1; i <= noldl; i++) + { + lnearness.Elem(i) = 0; + for (j = 1; j <= 2; j++) + lnearness.Elem(i) += pnearness.Get(GetPointNr (i, j)); + } + } + + oldutofreearea_i.SetSize (10); + for (i = 0; i < oldutofreearea_i.Size(); i++) + { + oldutofreearea_i[i] = new DenseMatrix (oldutofreearea.Height(), oldutofreearea.Width()); + DenseMatrix & mati = *oldutofreearea_i[i]; + for (int j = 0; j < oldutofreearea.Height(); j++) + for (int k = 0; k < oldutofreearea.Width(); k++) + mati(j,k) = 1.0 / (i+1) * oldutofreearea(j,k) + (1 - 1.0/(i+1)) * oldutofreearealimit(j,k); + } +} + + + + +extern const char * triarules[]; +extern const char * quadrules[]; + +void Meshing2 :: LoadRules (const char * filename) +{ + char buf[256]; + istream * ist; + char *tr1 = NULL; + + /* + ifstream ist (filename); + if (!ist.good()) + { + cerr << "Rule description file " << filename << " not found" << endl; + exit (1); + } + */ + + + if (filename) + { + // (*mycout) << "rule-filename = " << filename << endl; + ist = new ifstream (filename); + } + else + { + /* connect tetrules to one string */ + const char ** hcp; + + if (!mparam.quad) + { + hcp = triarules; + PrintMessage (3, "load internal triangle rules"); + } + else + { + hcp = quadrules; + PrintMessage (3, "load internal quad rules"); + // LoadRules ("rules/quad.rls"); + } + + int len = 0; + while (*hcp) + { + len += strlen (*hcp); + hcp++; + } + tr1 = new char[len+1]; + tr1[0] = 0; + + + if (!mparam.quad) + hcp = triarules; + else + hcp = quadrules; + + + char * tt1 = tr1; + while (*hcp) + { + strcat (tt1, *hcp); + tt1 += strlen (*hcp); + hcp++; + } + + ist = new istringstream (tr1); + } + + + if (!ist->good()) + { + cerr << "Rule description file " << filename << " not found" << endl; + delete ist; + exit (1); + } + + while (!ist->eof()) + { + buf[0] = 0; + (*ist) >> buf; + + if (strcmp (buf, "rule") == 0) + { + netrule * rule = new netrule; + rule -> LoadRule(*ist); + rules.Append (rule); + } + } + + delete ist; + delete [] tr1; +} + +} diff --git a/contrib/Netgen/libsrc/meshing/parser3.cpp b/contrib/Netgen/libsrc/meshing/parser3.cpp new file mode 100644 index 0000000000..23ee84802e --- /dev/null +++ b/contrib/Netgen/libsrc/meshing/parser3.cpp @@ -0,0 +1,987 @@ +#include <mystdlib.h> +#include "meshing.hpp" + +namespace netgen +{ + +extern const char * tetrules[]; + +void LoadVMatrixLine (istream & ist, DenseMatrix & m, int line) +{ + char ch; + int pnum; + float f; + + ist >> ch; + while (ch != '}') + { + ist.putback (ch); + ist >> f; + ist >> ch; + ist >> pnum; + + if (ch == 'x' || ch == 'X') + m.Elem(line, 3 * pnum - 2) = f; + if (ch == 'y' || ch == 'Y') + m.Elem(line, 3 * pnum - 1) = f; + if (ch == 'z' || ch == 'Z') + m.Elem(line, 3 * pnum ) = f; + + if (ch == 'p' || ch == 'P') + { + m.Elem(line , 3 * pnum-2) = f; + m.Elem(line+1, 3 * pnum-1) = f; + m.Elem(line+2, 3 * pnum ) = f; + } + + ist >> ch; + if (ch == ',') + ist >> ch; + } +} + + + + + +int vnetrule :: NeighbourTrianglePoint (const threeint & t1, const threeint & t2) const +{ + ARRAY<int> tr1(3); + ARRAY<int> tr2(3); + tr1.Elem(1)=t1.i1; + tr1.Elem(2)=t1.i2; + tr1.Elem(3)=t1.i3; + tr2.Elem(1)=t2.i1; + tr2.Elem(2)=t2.i2; + tr2.Elem(3)=t2.i3; + + + int ret=0; + + for (int i=1; i<=3; i++) + { + for (int j=1; j<=3; j++) + { + if ((tr1.Get(i)==tr2.Get(j) && tr1.Get((i%3)+1)==tr2.Get((j%3)+1)) || + (tr1.Get(i)==tr2.Get((j%3)+1) && tr1.Get((i%3)+1)==tr2.Get(j))) + {ret = tr2.Get((j+1)%3+1);} + } + } + + return ret; + +} + +void vnetrule :: LoadRule (istream & ist) +{ + char buf[256]; + char ch, ok; + Point3d p; + Element2d face; + int i, j, i1, i2, i3, fs, ii, ii1, ii2, ii3; + twoint edge; + DenseMatrix tempoldutonewu(30, 20), + tempoldutofreezone(30, 20), + tempoldutofreezonelimit(30, 20), + tfz(20, 20), + tfzl(20, 20); + + tempoldutonewu = 0; + tempoldutofreezone = 0; + tfz = 0; + tfzl = 0; + + + noldp = 0; + noldf = 0; + + ist.get (buf, sizeof(buf), '"'); + ist.get (ch); + ist.get (buf, sizeof(buf), '"'); + ist.get (ch); + + name = new char[strlen (buf) + 1]; + strcpy (name, buf); + // (*mycout) << "Rule " << name << " found." << endl; + + do + { + ist >> buf; + + if (strcmp (buf, "quality") == 0) + + { + ist >> quality; + } + + else if (strcmp (buf, "flags") == 0) + { + ist >> ch; + while (ch != ';') + { + flags.Append (ch); + ist >> ch; + } + } + + else if (strcmp (buf, "mappoints") == 0) + { + ist >> ch; + + while (ch == '(') + { + ist >> p.X(); + ist >> ch; // ',' + ist >> p.Y(); + ist >> ch; // ',' + ist >> p.Z(); + ist >> ch; // ')' + + points.Append (p); + noldp++; + + tolerances.SetSize (noldp); + tolerances.Elem(noldp) = 1; + + ist >> ch; + while (ch != ';') + { + if (ch == '{') + { + ist >> tolerances.Elem(noldp); + ist >> ch; // '}' + } + + ist >> ch; + } + + ist >> ch; + } + + ist.putback (ch); + } + + + else if (strcmp (buf, "mapfaces") == 0) + { + ist >> ch; + + while (ch == '(') + { + face.SetType(TRIG); + ist >> face.PNum(1); + ist >> ch; // ',' + ist >> face.PNum(2); + ist >> ch; // ',' + ist >> face.PNum(3); + ist >> ch; // ')' or ',' + if (ch == ',') + { + face.SetType(QUAD); + ist >> face.PNum(4); + ist >> ch; // ')' + } + faces.Append (face); + noldf++; + + ist >> ch; + while (ch != ';') + { + if (ch == 'd') + { + delfaces.Append (noldf); + ist >> ch; // 'e' + ist >> ch; // 'l' + } + + ist >> ch; + } + + ist >> ch; + } + + ist.putback (ch); + } + + else if (strcmp (buf, "mapedges") == 0) + { + ist >> ch; + + while (ch == '(') + { + ist >> edge.i1; + ist >> ch; // ',' + ist >> edge.i2; + ist >> ch; // ')' + + edges.Append (edge); + + ist >> ch; + while (ch != ';') + { + ist >> ch; + } + + ist >> ch; + } + + ist.putback (ch); + } + + + else if (strcmp (buf, "newpoints") == 0) + { + ist >> ch; + + while (ch == '(') + { + ist >> p.X(); + ist >> ch; // ',' + ist >> p.Y(); + ist >> ch; // ',' + ist >> p.Z(); + ist >> ch; // ')' + + points.Append (p); + + ist >> ch; + while (ch != ';') + { + if (ch == '{') + { + LoadVMatrixLine (ist, tempoldutonewu, + 3 * (points.Size()-noldp) - 2); + + ist >> ch; // '{' + LoadVMatrixLine (ist, tempoldutonewu, + 3 * (points.Size()-noldp) - 1); + + ist >> ch; // '{' + LoadVMatrixLine (ist, tempoldutonewu, + 3 * (points.Size()-noldp) ); + } + + ist >> ch; + } + + ist >> ch; + } + + ist.putback (ch); + } + + else if (strcmp (buf, "newfaces") == 0) + { + ist >> ch; + + while (ch == '(') + { + face.SetType(TRIG); + ist >> face.PNum(1); + ist >> ch; // ',' + ist >> face.PNum(2); + ist >> ch; // ',' + ist >> face.PNum(3); + ist >> ch; // ')' or ',' + if (ch == ',') + { + face.SetType(QUAD); + ist >> face.PNum(4); + ist >> ch; // ')' + } + faces.Append (face); + + ist >> ch; + while (ch != ';') + { + ist >> ch; + } + + ist >> ch; + } + + ist.putback (ch); + } + + else if (strcmp (buf, "freezone") == 0) + { + ist >> ch; + + while (ch == '(') + { + ist >> p.X(); + ist >> ch; // ',' + ist >> p.Y(); + ist >> ch; // ',' + ist >> p.Z(); + ist >> ch; // ')' + + freezone.Append (p); + + ist >> ch; + while (ch != ';') + { + if (ch == '{') + { + LoadVMatrixLine (ist, tempoldutofreezone, + 3 * freezone.Size() - 2); + + ist >> ch; // '{' + LoadVMatrixLine (ist, tempoldutofreezone, + 3 * freezone.Size() - 1); + + ist >> ch; // '{' + LoadVMatrixLine (ist, tempoldutofreezone, + 3 * freezone.Size() ); + } + + ist >> ch; + } + + ist >> ch; + } + + ist.putback (ch); + } + else if (strcmp (buf, "freezone2") == 0) + { + int i, j, k, nfp; + Point3d p; + + nfp = 0; + ist >> ch; + + DenseMatrix hm1(3, 50), hm2(50, 50), hm3(50, 50); + hm3 = 0; + + while (ch == '{') + { + hm1 = 0; + nfp++; + LoadVMatrixLine (ist, hm1, 1); + + for (i = 1; i <= points.Size(); i++) + tfz.Elem(nfp, i) = hm1.Get(1, 3*i-2); + + + p.X() = p.Y() = p.Z() = 0; + for (i = 1; i <= points.Size(); i++) + { + p.X() += hm1.Get(1, 3*i-2) * points.Get(i).X(); + p.Y() += hm1.Get(1, 3*i-2) * points.Get(i).Y(); + p.Z() += hm1.Get(1, 3*i-2) * points.Get(i).Z(); + } + freezone.Append (p); + freezonelimit.Append (p); + + hm2 = 0; + for (i = 1; i <= 3 * noldp; i++) + hm2.Elem(i, i) = 1; + for (i = 1; i <= 3 * noldp; i++) + for (j = 1; j <= 3 * (points.Size() - noldp); j++) + hm2.Elem(j + 3 * noldp, i) = tempoldutonewu.Get(j, i); + + for (i = 1; i <= 3; i++) + for (j = 1; j <= 3 * noldp; j++) + { + double sum = 0; + for (k = 1; k <= 3 * points.Size(); k++) + sum += hm1.Get(i, k) * hm2.Get(k, j); + + hm3.Elem(i + 3 * (nfp-1), j) = sum; + } + + // (*testout) << "freepoint: " << p << endl; + + while (ch != ';') + ist >> ch; + + ist >> ch; + } + + tfzl = tfz; + + tempoldutofreezone = hm3; + tempoldutofreezonelimit = hm3; + ist.putback(ch); + } + + else if (strcmp (buf, "freezonelimit") == 0) + { + int i, j, k, nfp; + Point3d p; + + nfp = 0; + ist >> ch; + + DenseMatrix hm1(3, 50), hm2(50, 50), hm3(50, 50); + hm3 = 0; + + while (ch == '{') + { + hm1 = 0; + nfp++; + LoadVMatrixLine (ist, hm1, 1); + + for (i = 1; i <= points.Size(); i++) + tfzl.Elem(nfp, i) = hm1.Get(1, 3*i-2); + + + p.X() = p.Y() = p.Z() = 0; + for (i = 1; i <= points.Size(); i++) + { + p.X() += hm1.Get(1, 3*i-2) * points.Get(i).X(); + p.Y() += hm1.Get(1, 3*i-2) * points.Get(i).Y(); + p.Z() += hm1.Get(1, 3*i-2) * points.Get(i).Z(); + } + freezonelimit.Elem(nfp) = p; + + hm2 = 0; + for (i = 1; i <= 3 * noldp; i++) + hm2.Elem(i, i) = 1; + for (i = 1; i <= 3 * noldp; i++) + for (j = 1; j <= 3 * (points.Size() - noldp); j++) + hm2.Elem(j + 3 * noldp, i) = tempoldutonewu.Get(j, i); + + for (i = 1; i <= 3; i++) + for (j = 1; j <= 3 * noldp; j++) + { + double sum = 0; + for (k = 1; k <= 3 * points.Size(); k++) + sum += hm1.Get(i, k) * hm2.Get(k, j); + + hm3.Elem(i + 3 * (nfp-1), j) = sum; + } + + // (*testout) << "freepoint: " << p << endl; + + while (ch != ';') + ist >> ch; + + ist >> ch; + } + + tempoldutofreezonelimit = hm3; + ist.putback(ch); + } + + else if (strcmp (buf, "freeset") == 0) + { + freesets.Append (new ARRAY<int>); + + ist >> ch; + + while (ch != ';') + { + ist.putback (ch); + ist >> i; + freesets.Last()->Append(i); + ist >> ch; + } + } + + else if (strcmp (buf, "elements") == 0) + { + ist >> ch; + + while (ch == '(') + { + elements.Append (Element(TET)); + + // elements.Last().SetNP(1); + ist >> elements.Last().PNum(1); + ist >> ch; // ',' + + if (ch == ',') + { + // elements.Last().SetNP(2); + ist >> elements.Last().PNum(2); + ist >> ch; // ',' + } + if (ch == ',') + { + // elements.Last().SetNP(3); + ist >> elements.Last().PNum(3); + ist >> ch; // ',' + } + if (ch == ',') + { + // elements.Last().SetNP(4); + elements.Last().SetType(TET); + ist >> elements.Last().PNum(4); + ist >> ch; // ',' + } + if (ch == ',') + { + // elements.Last().SetNP(5); + elements.Last().SetType(PYRAMID); + ist >> elements.Last().PNum(5); + ist >> ch; // ',' + } + if (ch == ',') + { + // elements.Last().SetNP(6); + elements.Last().SetType(PRISM); + ist >> elements.Last().PNum(6); + ist >> ch; // ',' + } + + /* + orientations.Append (fourint()); + orientations.Last().i1 = elements.Last().PNum(1); + orientations.Last().i2 = elements.Last().PNum(2); + orientations.Last().i3 = elements.Last().PNum(3); + orientations.Last().i4 = elements.Last().PNum(4); + */ + + ist >> ch; + while (ch != ';') + { + ist >> ch; + } + + ist >> ch; + } + + ist.putback (ch); + } + + else if (strcmp (buf, "orientations") == 0) + + { + ist >> ch; + + while (ch == '(') + { + // fourint a = fourint(); + orientations.Append (fourint()); + + ist >> orientations.Last().i1; + ist >> ch; // ',' + ist >> orientations.Last().i2; + ist >> ch; // ',' + ist >> orientations.Last().i3; + ist >> ch; // ',' + ist >> orientations.Last().i4; + ist >> ch; // ',' + + + ist >> ch; + while (ch != ';') + { + ist >> ch; + } + + ist >> ch; + } + + ist.putback (ch); + } + + + else if (strcmp (buf, "endrule") != 0) + { + PrintSysError ("Parser3d, unknown token " , buf); + } + } + while (!ist.eof() && strcmp (buf, "endrule") != 0); + + + // (*testout) << endl; + // (*testout) << Name() << endl; + // (*testout) << "no1 = " << GetNO() << endl; + + oldutonewu.SetSize (3 * (points.Size() - noldp), 3 * noldp); + oldutonewu = 0; + + for (i = 1; i <= oldutonewu.Height(); i++) + for (j = 1; j <= oldutonewu.Width(); j++) + oldutonewu.Elem(i, j) = tempoldutonewu.Elem(i, j); + + + /* + oldutofreezone = new SparseMatrixFlex (3 * freezone.Size(), 3 * noldp); + oldutofreezonelimit = new SparseMatrixFlex (3 * freezone.Size(), 3 * noldp); + + oldutofreezone -> SetSymmetric(0); + oldutofreezonelimit -> SetSymmetric(0); + */ + + /* + oldutofreezone = new DenseMatrix (3 * freezone.Size(), 3 * noldp); + oldutofreezonelimit = new DenseMatrix (3 * freezone.Size(), 3 * noldp); + + for (i = 1; i <= oldutofreezone->Height(); i++) + for (j = 1; j <= oldutofreezone->Width(); j++) + // if (j == 4 || j >= 7) + { + if (tempoldutofreezone.Elem(i, j)) + (*oldutofreezone)(i, j) = tempoldutofreezone(i, j); + if (tempoldutofreezonelimit.Elem(i, j)) + (*oldutofreezonelimit)(i, j) = tempoldutofreezonelimit(i, j); + } + */ + + + + + oldutofreezone = new DenseMatrix (freezone.Size(), points.Size()); + oldutofreezonelimit = new DenseMatrix (freezone.Size(), points.Size()); + // oldutofreezone = new SparseMatrixFlex (freezone.Size(), points.Size()); + // oldutofreezonelimit = new SparseMatrixFlex (freezone.Size(), points.Size()); + + for (i = 1; i <= freezone.Size(); i++) + for (j = 1; j <= points.Size(); j++) + { + if (tfz.Elem(i, j)) + (*oldutofreezone).Elem(i, j) = tfz.Elem(i, j); + if (tfzl.Elem(i, j)) + (*oldutofreezonelimit).Elem(i, j) = tfzl.Elem(i, j); + } + + /* + (*testout) << "Rule " << Name() << endl; + (*testout) << "oldutofreezone = " << (*oldutofreezone) << endl; + (*testout) << "oldutofreezonelimit = " << (*oldutofreezonelimit) << endl; + */ + + freezonepi.SetSize (freezone.Size()); + for (i = 1; i <= freezonepi.Size(); i++) + freezonepi.Elem(i) = 0; + for (i = 1; i <= freezone.Size(); i++) + for (j = 1; j <= noldp; j++) + if (Dist (freezone.Get(i), points.Get(j)) < 1e-8) + freezonepi.Elem(i) = j; + + + + + for (i = 1; i <= elements.Size(); i++) + { + if (elements.Elem(i).GetNP() == 4) + { + orientations.Append (fourint()); + orientations.Last().i1 = elements.Get(i).PNum(1); + orientations.Last().i2 = elements.Get(i).PNum(2); + orientations.Last().i3 = elements.Get(i).PNum(3); + orientations.Last().i4 = elements.Get(i).PNum(4); + } + if (elements.Elem(i).GetNP() == 5) + { + orientations.Append (fourint()); + orientations.Last().i1 = elements.Get(i).PNum(1); + orientations.Last().i2 = elements.Get(i).PNum(2); + orientations.Last().i3 = elements.Get(i).PNum(3); + orientations.Last().i4 = elements.Get(i).PNum(5); + + orientations.Append (fourint()); + orientations.Last().i1 = elements.Get(i).PNum(1); + orientations.Last().i2 = elements.Get(i).PNum(3); + orientations.Last().i3 = elements.Get(i).PNum(4); + orientations.Last().i4 = elements.Get(i).PNum(5); + } + } + + + + if (freesets.Size() == 0) + { + freesets.Append (new ARRAY<int>); + for (i = 1; i <= freezone.Size(); i++) + freesets.Elem(1)->Append(i); + } + + + // testout << "Freezone: " << endl; + + // for (i = 1; i <= freezone.Size(); i++) + // (*testout) << "freepoint: " << freezone.Get(i) << endl; + Vector vp(points.Size()), vfp(freezone.Size()); + + + if (quality < 100) + { + for (i = 1; i <= 3; i++) + { + for (j = 1; j <= points.Size(); j++) + vp.Elem(j) = points.Get(j).X(i); + oldutofreezone->Mult(vp, vfp); + for (j = 1; j <= freezone.Size(); j++) + freezone.Elem(j).X(i) = vfp.Get(j); + } + // for (i = 1; i <= freezone.Size(); i++) + // (*testout) << "freepoint: " << freezone.Get(i) << endl; + } + + + for (fs = 1; fs <= freesets.Size(); fs++) + { + freefaces.Append (new ARRAY<threeint>); + + ARRAY<int> & freeset = *freesets.Elem(fs); + ARRAY<threeint> & freesetfaces = *freefaces.Last(); + + for (ii1 = 1; ii1 <= freeset.Size(); ii1++) + for (ii2 = 1; ii2 <= freeset.Size(); ii2++) + for (ii3 = 1; ii3 <= freeset.Size(); ii3++) + if (ii1 < ii2 && ii1 < ii3 && ii2 != ii3) + { + i1 = freeset.Get(ii1); + i2 = freeset.Get(ii2); + i3 = freeset.Get(ii3); + + Vec3d v1, v2, n; + + v1 = freezone.Get(i3) - freezone.Get(i1); + v2 = freezone.Get(i2) - freezone.Get(i1); + n = Cross (v1, v2); + n /= n.Length(); + // (*testout) << "i1,2,3 = " << i1 << ", " << i2 << ", " << i3 << endl; + // (*testout) << "v1 = " << v1 << " v2 = " << v2 << " n = " << n << endl; + ok = 1; + for (ii = 1; ii <= freeset.Size(); ii++) + { + i = freeset.Get(ii); + // (*testout) << "i = " << i << endl; + if (i != i1 && i != i2 && i != i3) + if ( (freezone.Get(i) - freezone.Get(i1)) * n < 0 ) ok = 0; + } + + if (ok) + { + freesetfaces.Append (threeint()); + freesetfaces.Last().i1 = i1; + freesetfaces.Last().i2 = i2; + freesetfaces.Last().i3 = i3; + } + } + } + + for (fs = 1; fs <= freesets.Size(); fs++) + { + freefaceinequ.Append (new DenseMatrix (freefaces.Get(fs)->Size(), 4)); + } + + + { + char ok; + int minn; + // ARRAY<int> pnearness (noldp); + pnearness.SetSize (noldp); + + for (i = 1; i <= pnearness.Size(); i++) + pnearness.Elem(i) = INT_MAX/10; + + for (j = 1; j <= GetNP(1); j++) + pnearness.Elem(GetPointNr (1, j)) = 0; + + do + { + ok = 1; + + for (i = 1; i <= noldf; i++) + { + minn = INT_MAX/10; + for (j = 1; j <= GetNP(i); j++) + minn = min2 (minn, pnearness.Get(GetPointNr (i, j))); + + for (j = 1; j <= GetNP(i); j++) + if (pnearness.Get(GetPointNr (i, j)) > minn+1) + { + ok = 0; + pnearness.Elem(GetPointNr (i, j)) = minn+1; + } + } + + for (i = 1; i <= elements.Size(); i++) + if (elements.Get(i).GetNP() == 6) + { + for (j = 1; j <= 3; j++) + { + int pi1 = elements.Get(i).PNum(j); + int pi2 = elements.Get(i).PNum(j+3); + + if (pnearness.Get(pi1) > pnearness.Get(pi2)+1) + { + ok = 0; + pnearness.Elem(pi1) = pnearness.Get(pi2)+1; + } + if (pnearness.Get(pi2) > pnearness.Get(pi1)+1) + { + ok = 0; + pnearness.Elem(pi2) = pnearness.Get(pi1)+1; + } + } + } + } + while (!ok); + + int maxpnearness = 0; + for (i = 1; i <= pnearness.Size(); i++) + maxpnearness = max2 (maxpnearness, pnearness.Get(i)); + + + fnearness.SetSize (noldf); + + for (i = 1; i <= noldf; i++) + { + fnearness.Elem(i) = 0; + for (j = 1; j <= GetNP(i); j++) + fnearness.Elem(i) += pnearness.Get(GetPointNr (i, j)); + } + } + + + //Table of edges: + for (fs = 1; fs <= freesets.Size(); fs++) + { + freeedges.Append (new ARRAY<twoint>); + + // ARRAY<int> & freeset = *freesets.Get(fs); + ARRAY<twoint> & freesetedges = *freeedges.Last(); + ARRAY<threeint> & freesetfaces = *freefaces.Get(fs); + int k,l; + INDEX ind; + + for (k = 1; k <= freesetfaces.Size(); k++) + { + threeint tr = freesetfaces.Get(k); + + for (l = k+1; l <= freesetfaces.Size(); l++) + { + ind = NeighbourTrianglePoint(freesetfaces.Get(k), freesetfaces.Get(l)); + if (!ind) continue; + + INDEX_3 f1(freesetfaces.Get(k).i1, + freesetfaces.Get(k).i2, + freesetfaces.Get(k).i3); + INDEX_3 f2(freesetfaces.Get(l).i1, + freesetfaces.Get(l).i2, + freesetfaces.Get(l).i3); + INDEX_2 edge(0, 0); + for (int f11 = 1; f11 <= 3; f11++) + for (int f12 = 1; f12 <= 3; f12++) + if (f11 != f12) + for (int f21 = 1; f21 <= 3; f21++) + for (int f22 = 1; f22 <= 3; f22++) + if (f1.I(f11) == f2.I(f21) && f1.I(f12) == f2.I(f22)) + { + edge.I(1) = f1.I(f11); + edge.I(2) = f1.I(f12); + } + // (*testout) << "edge = " << edge.I(1) << "-" << edge.I(2) << endl; + // (*testout) << "ind = " << ind << " edge = " << edge << endl; + for (int eli = 1; eli <= GetNOldF(); eli++) + { + if (GetNP(eli) == 4) + { + for (int elr = 1; elr <= 4; elr++) + { + if (GetPointNrMod (eli, elr) == edge.I(1) && + GetPointNrMod (eli, elr+2) == edge.I(2)) + { + /* + (*testout) << "edge is diagonal of rectangle" << endl; + (*testout) << "edge = " << edge.I(1) << "-" << edge.I(2) << endl; + (*testout) << "ind = " << ind << endl; + */ + ind = 0; + } + + } + } + } + + if (ind) + { + /* + (*testout) << "new edge from face " << k + << " = (" << freesetfaces.Get(k).i1 + << ", " << freesetfaces.Get(k).i2 + << ", " << freesetfaces.Get(k).i3 + << "), point " << ind << endl; + */ + freesetedges.Append(twoint(k,ind)); + } + } + } + } + +} + + + + + +void Meshing3 :: LoadRules (const char * filename, const char ** prules) +{ + char buf[256]; + istream * ist; + char *tr1 = NULL; + + if (filename) + { + PrintMessage (3, "rule-filename = ", filename); + ist = new ifstream (filename); + } + else + { + /* connect tetrules to one string */ + PrintMessage (3, "Use internal rules"); + if (!prules) prules = tetrules; + + const char ** hcp = prules; + int len = 0; + while (*hcp) + { + len += strlen (*hcp); + hcp++; + } + tr1 = new char[len+1]; + tr1[0] = 0; + hcp = prules; // tetrules; + + + char * tt1 = tr1; + while (*hcp) + { + strcat (tt1, *hcp); + tt1 += strlen (*hcp); + hcp++; + } + + ist = new istringstream (tr1); + } + + if (!ist->good()) + { + cerr << "Rule description file " << filename << " not found" << endl; + delete ist; + exit (1); + } + + while (!ist->eof()) + { + buf[0] = 0; + (*ist) >> buf; + + if (strcmp (buf, "rule") == 0) + { + vnetrule * rule = new vnetrule; + rule -> LoadRule(*ist); + rules.Append (rule); + if (!rule->TestOk()) + { + PrintSysError ("Parser3d: Rule ", rules.Size(), " not ok"); + exit (1); + } + } + else if (strcmp (buf, "tolfak") == 0) + { + (*ist) >> tolfak; + } + } + delete ist; + delete [] tr1; +} +} diff --git a/contrib/Netgen/libsrc/meshing/prism2rls.cpp b/contrib/Netgen/libsrc/meshing/prism2rls.cpp new file mode 100644 index 0000000000..7e696554c0 --- /dev/null +++ b/contrib/Netgen/libsrc/meshing/prism2rls.cpp @@ -0,0 +1,457 @@ +namespace netgen +{ +const char * prismrules2[] = { +"tolfak 0.5\n",\ +"\n",\ +"rule \"prism on quad\"\n",\ +"\n",\ +"quality 1\n",\ +"\n",\ +"mappoints\n",\ +"(0, 0, 0);\n",\ +"(1, 0, 0);\n",\ +"(1, 1, 0);\n",\ +"(0, 1, 0);\n",\ +"(0.5, 0, -0.86);\n",\ +"(0.5, 1, -0.86);\n",\ +"\n",\ +"mapfaces\n",\ +"(1, 2, 3, 4) del;\n",\ +"(1, 5, 2) del;\n",\ +"(4, 3, 6) del;\n",\ +"\n",\ +"newpoints\n",\ +"\n",\ +"newfaces\n",\ +"(5, 2, 3, 6);\n",\ +"(1, 5, 6, 4);\n",\ +"\n",\ +"elements\n",\ +"(1, 5, 2, 4, 6, 3);\n",\ +"\n",\ +"orientations\n",\ +"(1, 2, 3, 5);\n",\ +"(1, 3, 4, 6);\n",\ +"\n",\ +"freezone2\n",\ +"{ 1 P1 };\n",\ +"{ 1 P2 };\n",\ +"{ 1 P3 };\n",\ +"{ 1 P4 };\n",\ +"{ 1 P5 };\n",\ +"{ 1 P6 };\n",\ +"{ 0.3 P1, -0.1 P2, -0.1 P3, 0.3 P4, 0.3 P5, 0.3 P6 };\n",\ +"{ -0.1 P1, 0.3 P2, 0.3 P3, -0.1 P4, 0.3 P5, 0.3 P6 };\n",\ +"\n",\ +"freezonelimit\n",\ +"{ 1 P1 };\n",\ +"{ 1 P2 };\n",\ +"{ 1 P3 };\n",\ +"{ 1 P4 };\n",\ +"{ 1 P5 };\n",\ +"{ 1 P6 };\n",\ +"{ 0.25 P1, 0 P2, 0 P3, 0.25 P4, 0.25 P5, 0.25 P6 };\n",\ +"{ 0 P1, 0.25 P2, 0.25 P3, 0 P4, 0.25 P5, 0.25 P6 };\n",\ +"\n",\ +"freeset\n",\ +"1 2 4 5 6 7;\n",\ +"\n",\ +"freeset\n",\ +"2 3 4 5 6 8;\n",\ +"\n",\ +"endrule\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"rule \"prism on quad, one trig\"\n",\ +"\n",\ +"quality 2\n",\ +"\n",\ +"mappoints\n",\ +"(0, 0, 0);\n",\ +"(1, 0, 0);\n",\ +"(1, 1, 0);\n",\ +"(0, 1, 0);\n",\ +"(0.5, 0, -0.86);\n",\ +"(0.5, 1, -0.86);\n",\ +"\n",\ +"mapfaces\n",\ +"(1, 2, 3, 4) del;\n",\ +"(1, 5, 2) del;\n",\ +"\n",\ +"newpoints\n",\ +"\n",\ +"newfaces\n",\ +"(5, 2, 3, 6);\n",\ +"(1, 5, 6, 4);\n",\ +"(4, 6, 3);\n",\ +"\n",\ +"elements\n",\ +"(1, 5, 2, 4, 6, 3);\n",\ +"\n",\ +"orientations\n",\ +"(1, 2, 3, 5);\n",\ +"(1, 3, 4, 6);\n",\ +"\n",\ +"freezone2\n",\ +"{ 1 P1 };\n",\ +"{ 1 P2 };\n",\ +"{ 1 P3 };\n",\ +"{ 1 P4 };\n",\ +"{ 1 P5 };\n",\ +"{ 1 P6 };\n",\ +"{ 0.3 P1, -0.1 P2, -0.1 P3, 0.3 P4, 0.3 P5, 0.3 P6 };\n",\ +"{ -0.1 P1, 0.3 P2, 0.3 P3, -0.1 P4, 0.3 P5, 0.3 P6 };\n",\ +"\n",\ +"freezonelimit\n",\ +"{ 1 P1 };\n",\ +"{ 1 P2 };\n",\ +"{ 1 P3 };\n",\ +"{ 1 P4 };\n",\ +"{ 1 P5 };\n",\ +"{ 1 P6 };\n",\ +"{ 0.25 P1, 0 P2, 0 P3, 0.25 P4, 0.25 P5, 0.25 P6 };\n",\ +"{ 0 P1, 0.25 P2, 0.25 P3, 0 P4, 0.25 P5, 0.25 P6 };\n",\ +"\n",\ +"freeset\n",\ +"1 2 4 5 6 7;\n",\ +"\n",\ +"freeset\n",\ +"2 3 4 5 6 8;\n",\ +"\n",\ +"\n",\ +"endrule\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"rule \"prism on 2 quad\"\n",\ +"\n",\ +"quality 1\n",\ +"\n",\ +"mappoints\n",\ +"(0, 0, 0);\n",\ +"(1, 0, 0);\n",\ +"(1, 1, 0);\n",\ +"(0, 1, 0);\n",\ +"(0.5, 0, -0.86);\n",\ +"(0.5, 1, -0.86);\n",\ +"\n",\ +"mapfaces\n",\ +"(1, 2, 3, 4) del;\n",\ +"(2, 5, 6, 3) del;\n",\ +"(1, 5, 2) del;\n",\ +"(4, 3, 6) del;\n",\ +"\n",\ +"newpoints\n",\ +"\n",\ +"newfaces\n",\ +"(1, 5, 6, 4);\n",\ +"\n",\ +"elements\n",\ +"(1, 5, 2, 4, 6, 3);\n",\ +"\n",\ +"freezone2\n",\ +"{ 1 P1 };\n",\ +"{ 1 P2 };\n",\ +"{ 1 P3 };\n",\ +"{ 1 P4 };\n",\ +"{ 1 P5 };\n",\ +"{ 1 P6 };\n",\ +"{ 0.3 P1, -0.1 P2, -0.1 P3, 0.3 P4, 0.3 P5, 0.3 P6 };\n",\ +"\n",\ +"freezonelimit\n",\ +"{ 1 P1 };\n",\ +"{ 1 P2 };\n",\ +"{ 1 P3 };\n",\ +"{ 1 P4 };\n",\ +"{ 1 P5 };\n",\ +"{ 1 P6 };\n",\ +"{ 0.25 P1, 0 P2, 0 P3, 0.25 P4, 0.25 P5, 0.25 P6 };\n",\ +"\n",\ +"freeset\n",\ +"1 2 4 5 6 7;\n",\ +"\n",\ +"freeset\n",\ +"2 3 4 6;\n",\ +"\n",\ +"\n",\ +"endrule\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"rule \"prism on 2 quad, one trig\"\n",\ +"\n",\ +"quality 2\n",\ +"\n",\ +"mappoints\n",\ +"(0, 0, 0);\n",\ +"(1, 0, 0);\n",\ +"(1, 1, 0);\n",\ +"(0, 1, 0);\n",\ +"(0.5, 0, -0.86);\n",\ +"(0.5, 1, -0.86);\n",\ +"\n",\ +"mapfaces\n",\ +"(1, 2, 3, 4) del;\n",\ +"(2, 5, 6, 3) del;\n",\ +"(1, 5, 2) del;\n",\ +"\n",\ +"newpoints\n",\ +"\n",\ +"newfaces\n",\ +"(1, 5, 6, 4);\n",\ +"(4, 6, 3);\n",\ +"\n",\ +"elements\n",\ +"(1, 5, 2, 4, 6, 3);\n",\ +"\n",\ +"freezone2\n",\ +"{ 1 P1 };\n",\ +"{ 1 P2 };\n",\ +"{ 1 P3 };\n",\ +"{ 1 P4 };\n",\ +"{ 1 P5 };\n",\ +"{ 1 P6 };\n",\ +"{ 0.3 P1, -0.1 P2, -0.1 P3, 0.3 P4, 0.3 P5, 0.3 P6 };\n",\ +"\n",\ +"freezonelimit\n",\ +"{ 1 P1 };\n",\ +"{ 1 P2 };\n",\ +"{ 1 P3 };\n",\ +"{ 1 P4 };\n",\ +"{ 1 P5 };\n",\ +"{ 1 P6 };\n",\ +"{ 0.25 P1, 0 P2, 0 P3, 0.25 P4, 0.25 P5, 0.25 P6 };\n",\ +"\n",\ +"freeset\n",\ +"1 2 4 5 6 7;\n",\ +"\n",\ +"freeset\n",\ +"2 3 4 6;\n",\ +"\n",\ +"\n",\ +"endrule\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"rule \"prism on 2 quada\"\n",\ +"\n",\ +"quality 1\n",\ +"\n",\ +"mappoints\n",\ +"(0, 0, 0);\n",\ +"(1, 0, 0);\n",\ +"(1, 1, 0);\n",\ +"(0, 1, 0);\n",\ +"(0.5, 0, -0.86);\n",\ +"(0.5, 1, -0.86);\n",\ +"\n",\ +"mapfaces\n",\ +"(1, 2, 3, 4) del;\n",\ +"(5, 1, 4, 6) del;\n",\ +"(1, 5, 2) del;\n",\ +"(4, 3, 6) del;\n",\ +"\n",\ +"newpoints\n",\ +"\n",\ +"newfaces\n",\ +"(5, 2, 3, 6);\n",\ +"\n",\ +"elements\n",\ +"(1, 5, 2, 4, 6, 3);\n",\ +"\n",\ +"freezone2\n",\ +"{ 1 P1 };\n",\ +"{ 1 P2 };\n",\ +"{ 1 P3 };\n",\ +"{ 1 P4 };\n",\ +"{ 1 P5 };\n",\ +"{ 1 P6 };\n",\ +"{ -0.1 P1, 0.3 P2, 0.3 P3, -0.1 P4, 0.3 P5, 0.3 P6 };\n",\ +"\n",\ +"freezonelimit\n",\ +"{ 1 P1 };\n",\ +"{ 1 P2 };\n",\ +"{ 1 P3 };\n",\ +"{ 1 P4 };\n",\ +"{ 1 P5 };\n",\ +"{ 1 P6 };\n",\ +"{ 0 P1, 0.25 P2, 0.25 P3, 0 P4, 0.25 P5, 0.25 P6 };\n",\ +"\n",\ +"freeset\n",\ +"1 2 3 5 6 7;\n",\ +"\n",\ +"freeset\n",\ +"1 3 4 6;\n",\ +"\n",\ +"\n",\ +"endrule\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"rule \"fill prism\"\n",\ +"\n",\ +"quality 1\n",\ +"\n",\ +"mappoints\n",\ +"(0, 0, 0);\n",\ +"(1, 0, 0);\n",\ +"(1, 1, 0);\n",\ +"(0, 1, 0);\n",\ +"(0.5, 0, -0.86);\n",\ +"(0.5, 1, -0.86);\n",\ +"\n",\ +"mapfaces\n",\ +"(1, 2, 3, 4) del;\n",\ +"(2, 5, 6, 3) del;\n",\ +"(5, 1, 4, 6) del;\n",\ +"(1, 5, 2) del;\n",\ +"(4, 3, 6) del;\n",\ +"\n",\ +"newpoints\n",\ +"\n",\ +"newfaces\n",\ +"\n",\ +"\n",\ +"elements\n",\ +"(1, 5, 2, 4, 6, 3);\n",\ +"\n",\ +"freezone2\n",\ +"{ 1 P1 };\n",\ +"{ 1 P2 };\n",\ +"{ 1 P3 };\n",\ +"{ 1 P4 };\n",\ +"{ 1 P5 };\n",\ +"{ 1 P6 };\n",\ +"\n",\ +"freeset\n",\ +"1 2 4 5;\n",\ +"\n",\ +"freeset\n",\ +"2 3 4 6;\n",\ +"\n",\ +"endrule\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"rule \"prism on 3 quad, one trig\"\n",\ +"\n",\ +"quality 2\n",\ +"\n",\ +"mappoints\n",\ +"(0, 0, 0);\n",\ +"(1, 0, 0);\n",\ +"(1, 1, 0);\n",\ +"(0, 1, 0);\n",\ +"(0.5, 0, -0.86);\n",\ +"(0.5, 1, -0.86);\n",\ +"\n",\ +"mapfaces\n",\ +"(1, 2, 3, 4) del;\n",\ +"(2, 5, 6, 3) del;\n",\ +"(5, 1, 4, 6) del;\n",\ +"(1, 5, 2) del;\n",\ +"\n",\ +"newpoints\n",\ +"\n",\ +"newfaces\n",\ +"(4, 6, 3);\n",\ +"\n",\ +"\n",\ +"elements\n",\ +"(1, 5, 2, 4, 6, 3);\n",\ +"\n",\ +"freezone2\n",\ +"{ 1 P1 };\n",\ +"{ 1 P2 };\n",\ +"{ 1 P3 };\n",\ +"{ 1 P4 };\n",\ +"{ 1 P5 };\n",\ +"{ 1 P6 };\n",\ +"\n",\ +"freeset\n",\ +"1 2 4 5;\n",\ +"\n",\ +"freeset\n",\ +"2 3 4 6;\n",\ +"\n",\ +"endrule\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"rule \"flat prism\"\n",\ +"\n",\ +"quality 100\n",\ +"\n",\ +"mappoints\n",\ +"(0, 0, 0);\n",\ +"(1, 0, 0);\n",\ +"(0.5, 0.866, 0);\n",\ +"(0, 0, -1);\n",\ +"(1, 0, -1);\n",\ +"(0.5, 0.866, -1);\n",\ +"\n",\ +"\n",\ +"mapfaces\n",\ +"(1, 2, 3) del;\n",\ +"(5, 4, 6) del;\n",\ +"\n",\ +"newpoints\n",\ +"\n",\ +"newfaces\n",\ +"(1, 2, 4);\n",\ +"(4, 2, 5);\n",\ +"(2, 3, 5);\n",\ +"(5, 3, 6);\n",\ +"(3, 1, 6);\n",\ +"(6, 1, 4);\n",\ +"\n",\ +"\n",\ +"\n",\ +"elements\n",\ +"(1, 2, 3, 5, 4, 6);\n",\ +"\n",\ +"freezone2\n",\ +"{ 1 P1 };\n",\ +"{ 1 P2 };\n",\ +"{ 1 P5 };\n",\ +"{ 1 P6 };\n",\ +"endrule\n",\ +"\n",\ +0}; +} diff --git a/contrib/Netgen/libsrc/meshing/prism2rls_2.cpp b/contrib/Netgen/libsrc/meshing/prism2rls_2.cpp new file mode 100644 index 0000000000..baf0bef388 --- /dev/null +++ b/contrib/Netgen/libsrc/meshing/prism2rls_2.cpp @@ -0,0 +1,446 @@ +namespace netgen +{ +const char * prismrules2[] = { +"tolfak 0.5\n",\ +"\n",\ +"rule \"prism on quad\"\n",\ +"\n",\ +"quality 1\n",\ +"\n",\ +"mappoints\n",\ +"(0, 0, 0);\n",\ +"(1, 0, 0);\n",\ +"(1, 1, 0);\n",\ +"(0, 1, 0);\n",\ +"(0.5, 0, -0.86);\n",\ +"(0.5, 1, -0.86);\n",\ +"\n",\ +"mapfaces\n",\ +"(1, 2, 3, 4) del;\n",\ +"(1, 5, 2) del;\n",\ +"(4, 3, 6) del;\n",\ +"\n",\ +"newpoints\n",\ +"\n",\ +"newfaces\n",\ +"(5, 2, 3, 6);\n",\ +"(1, 5, 6, 4);\n",\ +"\n",\ +"elements\n",\ +"(1, 5, 2, 4, 6, 3);\n",\ +"\n",\ +"orientations\n",\ +"(1, 2, 3, 5);\n",\ +"(1, 3, 4, 6);\n",\ +"\n",\ +"freezone2\n",\ +"{ 1 P1 };\n",\ +"{ 1 P2 };\n",\ +"{ 1 P3 };\n",\ +"{ 1 P4 };\n",\ +"{ 1 P5 };\n",\ +"{ 1 P6 };\n",\ +"{ 0.3 P1, -0.1 P2, -0.1 P3, 0.3 P4, 0.3 P5, 0.3 P6 };\n",\ +"{ -0.1 P1, 0.3 P2, 0.3 P3, -0.1 P4, 0.3 P5, 0.3 P6 };\n",\ +"\n",\ +"freezonelimit\n",\ +"{ 1 P1 };\n",\ +"{ 1 P2 };\n",\ +"{ 1 P3 };\n",\ +"{ 1 P4 };\n",\ +"{ 1 P5 };\n",\ +"{ 1 P6 };\n",\ +"{ 0.25 P1, 0 P2, 0 P3, 0.25 P4, 0.25 P5, 0.25 P6 };\n",\ +"{ 0 P1, 0.25 P2, 0.25 P3, 0 P4, 0.25 P5, 0.25 P6 };\n",\ +"\n",\ +"\n",\ +"endrule\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"rule \"prism on quad, one trig\"\n",\ +"\n",\ +"quality 2\n",\ +"\n",\ +"mappoints\n",\ +"(0, 0, 0);\n",\ +"(1, 0, 0);\n",\ +"(1, 1, 0);\n",\ +"(0, 1, 0);\n",\ +"(0.5, 0, -0.86);\n",\ +"(0.5, 1, -0.86);\n",\ +"\n",\ +"mapfaces\n",\ +"(1, 2, 3, 4) del;\n",\ +"(1, 5, 2) del;\n",\ +"\n",\ +"newpoints\n",\ +"\n",\ +"newfaces\n",\ +"(5, 2, 3, 6);\n",\ +"(1, 5, 6, 4);\n",\ +"(4, 6, 3);\n",\ +"\n",\ +"elements\n",\ +"(1, 5, 2, 4, 6, 3);\n",\ +"\n",\ +"orientations\n",\ +"(1, 2, 3, 5);\n",\ +"(1, 3, 4, 6);\n",\ +"\n",\ +"freezone2\n",\ +"{ 1 P1 };\n",\ +"{ 1 P2 };\n",\ +"{ 1 P3 };\n",\ +"{ 1 P4 };\n",\ +"{ 1 P5 };\n",\ +"{ 1 P6 };\n",\ +"{ 0.3 P1, -0.1 P2, -0.1 P3, 0.3 P4, 0.3 P5, 0.3 P6 };\n",\ +"{ -0.1 P1, 0.3 P2, 0.3 P3, -0.1 P4, 0.3 P5, 0.3 P6 };\n",\ +"\n",\ +"freezonelimit\n",\ +"{ 1 P1 };\n",\ +"{ 1 P2 };\n",\ +"{ 1 P3 };\n",\ +"{ 1 P4 };\n",\ +"{ 1 P5 };\n",\ +"{ 1 P6 };\n",\ +"{ 0.25 P1, 0 P2, 0 P3, 0.25 P4, 0.25 P5, 0.25 P6 };\n",\ +"{ 0 P1, 0.25 P2, 0.25 P3, 0 P4, 0.25 P5, 0.25 P6 };\n",\ +"\n",\ +"\n",\ +"endrule\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"rule \"prism on 2 quad\"\n",\ +"\n",\ +"quality 1\n",\ +"\n",\ +"mappoints\n",\ +"(0, 0, 0);\n",\ +"(1, 0, 0);\n",\ +"(1, 1, 0);\n",\ +"(0, 1, 0);\n",\ +"(0.5, 0, -0.86);\n",\ +"(0.5, 1, -0.86);\n",\ +"\n",\ +"mapfaces\n",\ +"(1, 2, 3, 4) del;\n",\ +"(2, 5, 6, 3) del;\n",\ +"(1, 5, 2) del;\n",\ +"(4, 3, 6) del;\n",\ +"\n",\ +"newpoints\n",\ +"\n",\ +"newfaces\n",\ +"(1, 5, 6, 4);\n",\ +"\n",\ +"elements\n",\ +"(1, 5, 2, 4, 6, 3);\n",\ +"\n",\ +"freezone2\n",\ +"{ 1 P1 };\n",\ +"{ 1 P2 };\n",\ +"{ 1 P3 };\n",\ +"{ 1 P4 };\n",\ +"{ 1 P5 };\n",\ +"{ 1 P6 };\n",\ +"{ 0.3 P1, -0.1 P2, -0.1 P3, 0.3 P4, 0.3 P5, 0.3 P6 };\n",\ +"\n",\ +"freezonelimit\n",\ +"{ 1 P1 };\n",\ +"{ 1 P2 };\n",\ +"{ 1 P3 };\n",\ +"{ 1 P4 };\n",\ +"{ 1 P5 };\n",\ +"{ 1 P6 };\n",\ +"{ 0.25 P1, 0 P2, 0 P3, 0.25 P4, 0.25 P5, 0.25 P6 };\n",\ +"\n",\ +"freeset\n",\ +"1 2 4 5 6 7;\n",\ +"\n",\ +"freeset\n",\ +"2 3 4 6;\n",\ +"\n",\ +"\n",\ +"endrule\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"rule \"prism on 2 quad, one trig\"\n",\ +"\n",\ +"quality 2\n",\ +"\n",\ +"mappoints\n",\ +"(0, 0, 0);\n",\ +"(1, 0, 0);\n",\ +"(1, 1, 0);\n",\ +"(0, 1, 0);\n",\ +"(0.5, 0, -0.86);\n",\ +"(0.5, 1, -0.86);\n",\ +"\n",\ +"mapfaces\n",\ +"(1, 2, 3, 4) del;\n",\ +"(2, 5, 6, 3) del;\n",\ +"(1, 5, 2) del;\n",\ +"\n",\ +"newpoints\n",\ +"\n",\ +"newfaces\n",\ +"(1, 5, 6, 4);\n",\ +"(4, 6, 3);\n",\ +"\n",\ +"elements\n",\ +"(1, 5, 2, 4, 6, 3);\n",\ +"\n",\ +"freezone2\n",\ +"{ 1 P1 };\n",\ +"{ 1 P2 };\n",\ +"{ 1 P3 };\n",\ +"{ 1 P4 };\n",\ +"{ 1 P5 };\n",\ +"{ 1 P6 };\n",\ +"{ 0.3 P1, -0.1 P2, -0.1 P3, 0.3 P4, 0.3 P5, 0.3 P6 };\n",\ +"\n",\ +"freezonelimit\n",\ +"{ 1 P1 };\n",\ +"{ 1 P2 };\n",\ +"{ 1 P3 };\n",\ +"{ 1 P4 };\n",\ +"{ 1 P5 };\n",\ +"{ 1 P6 };\n",\ +"{ 0.25 P1, 0 P2, 0 P3, 0.25 P4, 0.25 P5, 0.25 P6 };\n",\ +"\n",\ +"freeset\n",\ +"1 2 4 5 6 7;\n",\ +"\n",\ +"freeset\n",\ +"2 3 4 6;\n",\ +"\n",\ +"\n",\ +"endrule\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"rule \"prism on 2 quada\"\n",\ +"\n",\ +"quality 1\n",\ +"\n",\ +"mappoints\n",\ +"(0, 0, 0);\n",\ +"(1, 0, 0);\n",\ +"(1, 1, 0);\n",\ +"(0, 1, 0);\n",\ +"(0.5, 0, -0.86);\n",\ +"(0.5, 1, -0.86);\n",\ +"\n",\ +"mapfaces\n",\ +"(1, 2, 3, 4) del;\n",\ +"(5, 1, 4, 6) del;\n",\ +"(1, 5, 2) del;\n",\ +"(4, 3, 6) del;\n",\ +"\n",\ +"newpoints\n",\ +"\n",\ +"newfaces\n",\ +"(5, 2, 3, 6);\n",\ +"\n",\ +"elements\n",\ +"(1, 5, 2, 4, 6, 3);\n",\ +"\n",\ +"freezone2\n",\ +"{ 1 P1 };\n",\ +"{ 1 P2 };\n",\ +"{ 1 P3 };\n",\ +"{ 1 P4 };\n",\ +"{ 1 P5 };\n",\ +"{ 1 P6 };\n",\ +"{ -0.1 P1, 0.3 P2, 0.3 P3, -0.1 P4, 0.3 P5, 0.3 P6 };\n",\ +"\n",\ +"freezonelimit\n",\ +"{ 1 P1 };\n",\ +"{ 1 P2 };\n",\ +"{ 1 P3 };\n",\ +"{ 1 P4 };\n",\ +"{ 1 P5 };\n",\ +"{ 1 P6 };\n",\ +"{ 0 P1, 0.25 P2, 0.25 P3, 0 P4, 0.25 P5, 0.25 P6 };\n",\ +"\n",\ +"freeset\n",\ +"1 2 3 5 6 7;\n",\ +"\n",\ +"freeset\n",\ +"1 3 4 6;\n",\ +"\n",\ +"\n",\ +"endrule\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"rule \"fill prism\"\n",\ +"\n",\ +"quality 1\n",\ +"\n",\ +"mappoints\n",\ +"(0, 0, 0);\n",\ +"(1, 0, 0);\n",\ +"(1, 1, 0);\n",\ +"(0, 1, 0);\n",\ +"(0.5, 0, -0.86);\n",\ +"(0.5, 1, -0.86);\n",\ +"\n",\ +"mapfaces\n",\ +"(1, 2, 3, 4) del;\n",\ +"(2, 5, 6, 3) del;\n",\ +"(5, 1, 4, 6) del;\n",\ +"(1, 5, 2) del;\n",\ +"(4, 3, 6) del;\n",\ +"\n",\ +"newpoints\n",\ +"\n",\ +"newfaces\n",\ +"\n",\ +"\n",\ +"elements\n",\ +"(1, 5, 2, 4, 6, 3);\n",\ +"\n",\ +"freezone2\n",\ +"{ 1 P1 };\n",\ +"{ 1 P2 };\n",\ +"{ 1 P3 };\n",\ +"{ 1 P4 };\n",\ +"{ 1 P5 };\n",\ +"{ 1 P6 };\n",\ +"\n",\ +"freeset\n",\ +"1 2 4 5;\n",\ +"\n",\ +"freeset\n",\ +"2 3 4 6;\n",\ +"\n",\ +"endrule\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"rule \"prism on 3 quad, one trig\"\n",\ +"\n",\ +"quality 2\n",\ +"\n",\ +"mappoints\n",\ +"(0, 0, 0);\n",\ +"(1, 0, 0);\n",\ +"(1, 1, 0);\n",\ +"(0, 1, 0);\n",\ +"(0.5, 0, -0.86);\n",\ +"(0.5, 1, -0.86);\n",\ +"\n",\ +"mapfaces\n",\ +"(1, 2, 3, 4) del;\n",\ +"(2, 5, 6, 3) del;\n",\ +"(5, 1, 4, 6) del;\n",\ +"(1, 5, 2) del;\n",\ +"\n",\ +"newpoints\n",\ +"\n",\ +"newfaces\n",\ +"(4, 6, 3);\n",\ +"\n",\ +"\n",\ +"elements\n",\ +"(1, 5, 2, 4, 6, 3);\n",\ +"\n",\ +"freezone2\n",\ +"{ 1 P1 };\n",\ +"{ 1 P2 };\n",\ +"{ 1 P3 };\n",\ +"{ 1 P4 };\n",\ +"{ 1 P5 };\n",\ +"{ 1 P6 };\n",\ +"\n",\ +"freeset\n",\ +"1 2 4 5;\n",\ +"\n",\ +"freeset\n",\ +"2 3 4 6;\n",\ +"\n",\ +"endrule\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"rule \"flat prism\"\n",\ +"\n",\ +"quality 1\n",\ +"\n",\ +"mappoints\n",\ +"(0, 0, 0);\n",\ +"(1, 0, 0);\n",\ +"(0.5, 0.866, 0);\n",\ +"(0, 0, -1);\n",\ +"(1, 0, -1);\n",\ +"(0.5, 0.866, -1);\n",\ +"\n",\ +"\n",\ +"mapfaces\n",\ +"(1, 2, 3) del;\n",\ +"(5, 4, 6) del;\n",\ +"\n",\ +"newpoints\n",\ +"\n",\ +"newfaces\n",\ +"(1, 2, 4);\n",\ +"(4, 2, 5);\n",\ +"(2, 3, 5);\n",\ +"(5, 3, 6);\n",\ +"(3, 1, 6);\n",\ +"(6, 1, 4);\n",\ +"\n",\ +"\n",\ +"\n",\ +"elements\n",\ +"(1, 2, 3, 5, 4, 6);\n",\ +"\n",\ +"freezone2\n",\ +"{ 1 P1 };\n",\ +"{ 1 P2 };\n",\ +"{ 1 P5 };\n",\ +"{ 1 P6 };\n",\ +"endrule\n",\ +"\n",\ +0}; +} diff --git a/contrib/Netgen/libsrc/meshing/pyramid2rls.cpp b/contrib/Netgen/libsrc/meshing/pyramid2rls.cpp new file mode 100644 index 0000000000..a97e7f13e5 --- /dev/null +++ b/contrib/Netgen/libsrc/meshing/pyramid2rls.cpp @@ -0,0 +1,309 @@ +namespace netgen +{ +const char * pyramidrules2[] = { +"tolfak 0.5\n",\ +"\n",\ +"rule \"Pyramid on quad\"\n",\ +"\n",\ +"quality 100\n",\ +"\n",\ +"mappoints\n",\ +"(0, 0, 0);\n",\ +"(1, 0, 0);\n",\ +"(1, 1, 0);\n",\ +"(0, 1, 0);\n",\ +"\n",\ +"mapfaces\n",\ +"(1, 2, 3, 4) del;\n",\ +"\n",\ +"newpoints\n",\ +"(0.5, 0.5, -0.5) \n",\ +" { 0.25 X1, 0.25 X2, 0.25 X3, 0.25 X4 } \n",\ +" { 0.25 Y1, 0.25 Y2, 0.25 Y3, 0.25 Y4 } { };\n",\ +"\n",\ +"newfaces\n",\ +"(1, 2, 5);\n",\ +"(2, 3, 5);\n",\ +"(3, 4, 5);\n",\ +"(4, 1, 5);\n",\ +"\n",\ +"elements\n",\ +"(1, 2, 3, 4, 5);\n",\ +"\n",\ +"freezone2\n",\ +"{ 1 P1 };\n",\ +"{ 1 P2 };\n",\ +"{ 1 P3 };\n",\ +"{ 1 P4 };\n",\ +"{ 1.4 P5, -0.1 P1, -0.1 P2, -0.1 P3, -0.1 P4 };\n",\ +"\n",\ +"freezonelimit\n",\ +"{ 1 P1 };\n",\ +"{ 1 P2 };\n",\ +"{ 1 P3 };\n",\ +"{ 1 P4 };\n",\ +"{ 1 P5 };\n",\ +"\n",\ +"freeset\n",\ +"1 2 3 5;\n",\ +"\n",\ +"freeset\n",\ +"1 3 4 5;\n",\ +"\n",\ +"endrule\n",\ +"\n",\ +"\n",\ +"rule \"small Pyramid on quad\"\n",\ +"\n",\ +"quality 100\n",\ +"\n",\ +"mappoints\n",\ +"(0, 0, 0);\n",\ +"(1, 0, 0);\n",\ +"(1, 1, 0);\n",\ +"(0, 1, 0);\n",\ +"\n",\ +"mapfaces\n",\ +"(1, 2, 3, 4) del;\n",\ +"\n",\ +"newpoints\n",\ +"(0.5, 0.5, -0.1 )\n",\ +" { 0.25 X1, 0.25 X2, 0.25 X3, 0.25 X4 } \n",\ +" { 0.25 Y1, 0.25 Y2, 0.25 Y3, 0.25 Y4 } { };\n",\ +"\n",\ +"newfaces\n",\ +"(1, 2, 5);\n",\ +"(2, 3, 5);\n",\ +"(3, 4, 5);\n",\ +"(4, 1, 5);\n",\ +"\n",\ +"elements\n",\ +"(1, 2, 3, 4, 5);\n",\ +"\n",\ +"freezone2\n",\ +"{ 1 P1 };\n",\ +"{ 1 P2 };\n",\ +"{ 1 P3 };\n",\ +"{ 1 P4 };\n",\ +"{ 1.4 P5, -0.1 P1, -0.1 P2, -0.1 P3, -0.1 P4 };\n",\ +"\n",\ +"freezonelimit\n",\ +"{ 1 P1 };\n",\ +"{ 1 P2 };\n",\ +"{ 1 P3 };\n",\ +"{ 1 P4 };\n",\ +"{ 1 P5 };\n",\ +"\n",\ +"freeset\n",\ +"1 2 3 5;\n",\ +"\n",\ +"freeset\n",\ +"1 3 4 5;\n",\ +"\n",\ +"endrule\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"rule \"connect pyramid\"\n",\ +"\n",\ +"quality 100\n",\ +"\n",\ +"mappoints\n",\ +"(0, 0, 0);\n",\ +"(1, 0, 0);\n",\ +"(1, 1, 0);\n",\ +"(0, 1, 0);\n",\ +"(0.5, 0.5, -0.5);\n",\ +"\n",\ +"mapfaces\n",\ +"(1, 2, 3, 4) del;\n",\ +"\n",\ +"newpoints\n",\ +"\n",\ +"newfaces\n",\ +"(1, 2, 5);\n",\ +"(2, 3, 5);\n",\ +"(3, 4, 5);\n",\ +"(4, 1, 5);\n",\ +"\n",\ +"elements\n",\ +"(1, 2, 3, 4, 5);\n",\ +"\n",\ +"freezone2\n",\ +"{ 1 P1 };\n",\ +"{ 1 P2 };\n",\ +"{ 1 P3 };\n",\ +"{ 1 P4 };\n",\ +"{ 1 P5 };\n",\ +"\n",\ +"freeset\n",\ +"1 2 3 5;\n",\ +"\n",\ +"freeset\n",\ +"1 3 4 5;\n",\ +"\n",\ +"endrule\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"rule \"pyramid with one trig\"\n",\ +"\n",\ +"quality 1\n",\ +"\n",\ +"mappoints\n",\ +"(0, 0, 0);\n",\ +"(1, 0, 0);\n",\ +"(1, 1, 0);\n",\ +"(0, 1, 0);\n",\ +"(0.5, 0.5, -0.5);\n",\ +"\n",\ +"mapfaces\n",\ +"(1, 2, 3, 4) del;\n",\ +"(2, 1, 5) del;\n",\ +"\n",\ +"newpoints\n",\ +"\n",\ +"newfaces\n",\ +"(2, 3, 5);\n",\ +"(3, 4, 5);\n",\ +"(4, 1, 5);\n",\ +"\n",\ +"elements\n",\ +"(1, 2, 3, 4, 5);\n",\ +"\n",\ +"freezone2\n",\ +"{ 1 P1 };\n",\ +"{ 1 P2 };\n",\ +"{ 1 P3 };\n",\ +"{ 1 P4 };\n",\ +"{ 1 P5 };\n",\ +"{ 0.34 P2, 0.34 P3, 0.34 P5, -0.02 P1 };\n",\ +"{ 0.34 P3, 0.34 P4, 0.34 P5, -0.02 P1 };\n",\ +"{ 0.34 P1, 0.34 P4, 0.34 P5, -0.02 P2 };\n",\ +"\n",\ +"freezonelimit\n",\ +"{ 1 P1 };\n",\ +"{ 1 P2 };\n",\ +"{ 1 P3 };\n",\ +"{ 1 P4 };\n",\ +"{ 1 P5 };\n",\ +"{ 0.333 P2, 0.333 P3, 0.334 P5, 0 P1 };\n",\ +"{ 0.333 P3, 0.333 P4, 0.334 P5, 0 P1 };\n",\ +"{ 0.333 P1, 0.333 P4, 0.334 P5, 0 P2 };\n",\ +"\n",\ +"orientations\n",\ +"(1, 2, 3, 5);\n",\ +"(1, 3, 4, 5);\n",\ +"\n",\ +"\n",\ +"freeset\n",\ +"1 2 3 5;\n",\ +"freeset\n",\ +"1 3 4 5;\n",\ +"freeset\n",\ +"2 3 5 6;\n",\ +"freeset\n",\ +"3 4 5 7;\n",\ +"freeset \n",\ +"1 4 5 8;\n",\ +"endrule\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"rule \"pyramid with two trig\"\n",\ +"\n",\ +"quality 1\n",\ +"\n",\ +"mappoints\n",\ +"(0, 0, 0);\n",\ +"(1, 0, 0);\n",\ +"(1, 1, 0);\n",\ +"(0, 1, 0);\n",\ +"(0.5, 0.5, -0.5);\n",\ +"\n",\ +"mapfaces\n",\ +"(1, 2, 3, 4) del;\n",\ +"(2, 1, 5) del;\n",\ +"(3, 2, 5) del;\n",\ +"newpoints\n",\ +"\n",\ +"newfaces\n",\ +"(3, 4, 5);\n",\ +"(4, 1, 5);\n",\ +"\n",\ +"elements\n",\ +"(1, 2, 3, 4, 5);\n",\ +"\n",\ +"freezone2\n",\ +"{ 1 P1 };\n",\ +"{ 1 P2 };\n",\ +"{ 1 P3 };\n",\ +"{ 1 P4 };\n",\ +"{ 1 P5 };\n",\ +"\n",\ +"freeset\n",\ +"1 2 3 5;\n",\ +"\n",\ +"freeset\n",\ +"1 3 4 5;\n",\ +"\n",\ +"endrule\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"rule \"pyramid with two trig, left\"\n",\ +"\n",\ +"quality 1\n",\ +"\n",\ +"mappoints\n",\ +"(0, 0, 0);\n",\ +"(1, 0, 0);\n",\ +"(1, 1, 0);\n",\ +"(0, 1, 0);\n",\ +"(0.5, 0.5, -0.5);\n",\ +"\n",\ +"mapfaces\n",\ +"(1, 2, 3, 4) del;\n",\ +"(2, 1, 5) del;\n",\ +"(1, 4, 5) del;\n",\ +"newpoints\n",\ +"\n",\ +"newfaces\n",\ +"(3, 4, 5);\n",\ +"(2, 3, 5);\n",\ +"\n",\ +"elements\n",\ +"(1, 2, 3, 4, 5);\n",\ +"\n",\ +"freezone2\n",\ +"{ 1 P1 };\n",\ +"{ 1 P2 };\n",\ +"{ 1 P3 };\n",\ +"{ 1 P4 };\n",\ +"{ 1 P5 };\n",\ +"\n",\ +"freeset\n",\ +"1 2 3 5;\n",\ +"\n",\ +"freeset\n",\ +"1 3 4 5;\n",\ +"\n",\ +"endrule\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +0}; +} diff --git a/contrib/Netgen/libsrc/meshing/pyramidrls.cpp b/contrib/Netgen/libsrc/meshing/pyramidrls.cpp new file mode 100644 index 0000000000..d4e997c1fe --- /dev/null +++ b/contrib/Netgen/libsrc/meshing/pyramidrls.cpp @@ -0,0 +1,263 @@ +namespace netgen +{ +const char * pyramidrules[] = { +"tolfak 0.5\n",\ +"\n",\ +"rule \"Pyramid on quad\"\n",\ +"\n",\ +"quality 100\n",\ +"\n",\ +"mappoints\n",\ +"(0, 0, 0);\n",\ +"(1, 0, 0);\n",\ +"(1, 1, 0);\n",\ +"(0, 1, 0);\n",\ +"\n",\ +"mapfaces\n",\ +"(1, 2, 3, 4) del;\n",\ +"\n",\ +"newpoints\n",\ +"(0.5, 0.5, -0.5) \n",\ +" { 0.25 X1, 0.25 X2, 0.25 X3, 0.25 X4 } \n",\ +" { 0.25 Y1, 0.25 Y2, 0.25 Y3, 0.25 Y4 } { };\n",\ +"\n",\ +"newfaces\n",\ +"(1, 2, 5);\n",\ +"(2, 3, 5);\n",\ +"(3, 4, 5);\n",\ +"(4, 1, 5);\n",\ +"\n",\ +"elements\n",\ +"(1, 2, 3, 4, 5);\n",\ +"\n",\ +"freezone2\n",\ +"{ 1 P1 };\n",\ +"{ 1 P2 };\n",\ +"{ 1 P3 };\n",\ +"{ 1 P4 };\n",\ +"{ 1.4 P5, -0.1 P1, -0.1 P2, -0.1 P3, -0.1 P4 };\n",\ +"\n",\ +"freezonelimit\n",\ +"{ 1 P1 };\n",\ +"{ 1 P2 };\n",\ +"{ 1 P3 };\n",\ +"{ 1 P4 };\n",\ +"{ 1 P5 };\n",\ +"\n",\ +"freeset\n",\ +"1 2 3 5;\n",\ +"\n",\ +"freeset\n",\ +"1 3 4 5;\n",\ +"\n",\ +"endrule\n",\ +"\n",\ +"\n",\ +"rule \"small Pyramid on quad\"\n",\ +"\n",\ +"quality 100\n",\ +"\n",\ +"mappoints\n",\ +"(0, 0, 0);\n",\ +"(1, 0, 0);\n",\ +"(1, 1, 0);\n",\ +"(0, 1, 0);\n",\ +"\n",\ +"mapfaces\n",\ +"(1, 2, 3, 4) del;\n",\ +"\n",\ +"newpoints\n",\ +"(0.5, 0.5, -0.1 )\n",\ +" { 0.25 X1, 0.25 X2, 0.25 X3, 0.25 X4 } \n",\ +" { 0.25 Y1, 0.25 Y2, 0.25 Y3, 0.25 Y4 } { };\n",\ +"\n",\ +"newfaces\n",\ +"(1, 2, 5);\n",\ +"(2, 3, 5);\n",\ +"(3, 4, 5);\n",\ +"(4, 1, 5);\n",\ +"\n",\ +"elements\n",\ +"(1, 2, 3, 4, 5);\n",\ +"\n",\ +"freezone2\n",\ +"{ 1 P1 };\n",\ +"{ 1 P2 };\n",\ +"{ 1 P3 };\n",\ +"{ 1 P4 };\n",\ +"{ 1.4 P5, -0.1 P1, -0.1 P2, -0.1 P3, -0.1 P4 };\n",\ +"\n",\ +"freezonelimit\n",\ +"{ 1 P1 };\n",\ +"{ 1 P2 };\n",\ +"{ 1 P3 };\n",\ +"{ 1 P4 };\n",\ +"{ 1 P5 };\n",\ +"\n",\ +"freeset\n",\ +"1 2 3 5;\n",\ +"\n",\ +"freeset\n",\ +"1 3 4 5;\n",\ +"\n",\ +"endrule\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"rule \"connect pyramid\"\n",\ +"\n",\ +"quality 1\n",\ +"\n",\ +"mappoints\n",\ +"(0, 0, 0);\n",\ +"(1, 0, 0);\n",\ +"(1, 1, 0);\n",\ +"(0, 1, 0);\n",\ +"(0.5, 0.5, -0.5);\n",\ +"\n",\ +"mapfaces\n",\ +"(1, 2, 3, 4) del;\n",\ +"\n",\ +"newpoints\n",\ +"\n",\ +"newfaces\n",\ +"(1, 2, 5);\n",\ +"(2, 3, 5);\n",\ +"(3, 4, 5);\n",\ +"(4, 1, 5);\n",\ +"\n",\ +"elements\n",\ +"(1, 2, 3, 4, 5);\n",\ +"\n",\ +"freezone2\n",\ +"{ 1 P1 };\n",\ +"{ 1 P2 };\n",\ +"{ 1 P3 };\n",\ +"{ 1 P4 };\n",\ +"{ 1 P5 };\n",\ +"\n",\ +"freeset\n",\ +"1 2 3 5;\n",\ +"\n",\ +"freeset\n",\ +"1 3 4 5;\n",\ +"\n",\ +"endrule\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"rule \"pyramid with one trig\"\n",\ +"\n",\ +"quality 1\n",\ +"\n",\ +"mappoints\n",\ +"(0, 0, 0);\n",\ +"(1, 0, 0);\n",\ +"(1, 1, 0);\n",\ +"(0, 1, 0);\n",\ +"(0.5, 0.5, -0.5);\n",\ +"\n",\ +"mapfaces\n",\ +"(1, 2, 3, 4) del;\n",\ +"(2, 1, 5) del;\n",\ +"\n",\ +"newpoints\n",\ +"\n",\ +"newfaces\n",\ +"(2, 3, 5);\n",\ +"(3, 4, 5);\n",\ +"(4, 1, 5);\n",\ +"\n",\ +"elements\n",\ +"(1, 2, 3, 4, 5);\n",\ +"\n",\ +"freezone2\n",\ +"{ 1 P1 };\n",\ +"{ 1 P2 };\n",\ +"{ 1 P3 };\n",\ +"{ 1 P4 };\n",\ +"{ 1 P5 };\n",\ +"{ 0.34 P2, 0.34 P3, 0.34 P5, -0.02 P1 };\n",\ +"{ 0.34 P3, 0.34 P4, 0.34 P5, -0.02 P1 };\n",\ +"{ 0.34 P1, 0.34 P4, 0.34 P5, -0.02 P3 };\n",\ +"\n",\ +"freezonelimit\n",\ +"{ 1 P1 };\n",\ +"{ 1 P2 };\n",\ +"{ 1 P3 };\n",\ +"{ 1 P4 };\n",\ +"{ 1 P5 };\n",\ +"{ 0.333 P2, 0.333 P3, 0.334 P5, 0 P1 };\n",\ +"{ 0.333 P3, 0.333 P4, 0.334 P5, 0 P1 };\n",\ +"{ 0.333 P1, 0.333 P4, 0.334 P5, 0 P3 };\n",\ +"\n",\ +"orientations\n",\ +"(1, 2, 3, 5);\n",\ +"(1, 3, 4, 5);\n",\ +"\n",\ +"\n",\ +"freeset\n",\ +"1 2 3 5;\n",\ +"freeset\n",\ +"1 3 4 5;\n",\ +"freeset\n",\ +"2 3 5 6;\n",\ +"freeset\n",\ +"3 4 5 7;\n",\ +"freeset \n",\ +"1 4 5 8;\n",\ +"endrule\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"rule \"pyramid with two trig\"\n",\ +"\n",\ +"quality 1\n",\ +"\n",\ +"mappoints\n",\ +"(0, 0, 0);\n",\ +"(1, 0, 0);\n",\ +"(1, 1, 0);\n",\ +"(0, 1, 0);\n",\ +"(0.5, 0.5, -0.5);\n",\ +"\n",\ +"mapfaces\n",\ +"(1, 2, 3, 4) del;\n",\ +"(2, 1, 5) del;\n",\ +"(3, 2, 5) del;\n",\ +"newpoints\n",\ +"\n",\ +"newfaces\n",\ +"(3, 4, 5);\n",\ +"(4, 1, 5);\n",\ +"\n",\ +"elements\n",\ +"(1, 2, 3, 4, 5);\n",\ +"\n",\ +"freezone2\n",\ +"{ 1 P1 };\n",\ +"{ 1 P2 };\n",\ +"{ 1 P3 };\n",\ +"{ 1 P4 };\n",\ +"{ 1 P5 };\n",\ +"\n",\ +"freeset\n",\ +"1 2 3 5;\n",\ +"\n",\ +"freeset\n",\ +"1 3 4 5;\n",\ +"\n",\ +"endrule\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +0}; +} diff --git a/contrib/Netgen/libsrc/meshing/quadrls.cpp b/contrib/Netgen/libsrc/meshing/quadrls.cpp new file mode 100644 index 0000000000..57fb010144 --- /dev/null +++ b/contrib/Netgen/libsrc/meshing/quadrls.cpp @@ -0,0 +1,765 @@ +namespace netgen +{ +const char * quadrules[] = { +"rule \"Free Quad (1)\"\n",\ +"\n",\ +"quality 1\n",\ +"\n",\ +"mappoints\n",\ +"(0, 0);\n",\ +"(1, 0);\n",\ +"\n",\ +"maplines\n",\ +"(1, 2) del;\n",\ +"\n",\ +"newpoints\n",\ +"(1, 1) { 1 X2 } { };\n",\ +"(0, 1) { } { };\n",\ +"\n",\ +"newlines\n",\ +"(3, 2);\n",\ +"(4, 3);\n",\ +"(1, 4);\n",\ +"\n",\ +"freearea\n",\ +"(0, 0);\n",\ +"(1, 0) { 1 X2 } { };\n",\ +"(1.5, 1.5) { 1.5 X2 } { };\n",\ +"(-0.5, 1.5) { -0.5 X2 } { };\n",\ +"\n",\ +"elements\n",\ +"(1, 2, 3, 4);\n",\ +"\n",\ +"endrule\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"rule \"Free Quad (5)\"\n",\ +"\n",\ +"quality 5\n",\ +"\n",\ +"mappoints\n",\ +"(0, 0);\n",\ +"(1, 0);\n",\ +"\n",\ +"maplines\n",\ +"(1, 2) del;\n",\ +"\n",\ +"newpoints\n",\ +"(1, 1) { 1 X2 } { };\n",\ +"(0, 1) { } { };\n",\ +"\n",\ +"newlines\n",\ +"(3, 2);\n",\ +"(4, 3);\n",\ +"(1, 4);\n",\ +"\n",\ +"freearea\n",\ +"(0, 0);\n",\ +"(1, 0) { 1 X2 } { };\n",\ +"(1.5, 1.5) { 1.5 X2 } { };\n",\ +"(-0.5, 1.5) { -0.5 X2 } { };\n",\ +"\n",\ +"freearea2\n",\ +"(0, 0);\n",\ +"(1, 0) { 1 X2 } { };\n",\ +"(1, 1) { 1 X2 } { };\n",\ +"(0, 1) { } { };\n",\ +"\n",\ +"elements\n",\ +"(1, 2, 3, 4);\n",\ +"\n",\ +"endrule\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"rule \"Quad Right (1)\"\n",\ +"\n",\ +"quality 1\n",\ +"\n",\ +"mappoints\n",\ +"(0, 0);\n",\ +"(1, 0);\n",\ +"(1, 1);\n",\ +"\n",\ +"maplines\n",\ +"(1, 2) del;\n",\ +"(2, 3) del;\n",\ +"\n",\ +"newpoints\n",\ +"(0, 1) { } { 1 y3 };\n",\ +"\n",\ +"newlines\n",\ +"(1, 4);\n",\ +"(4, 3);\n",\ +"\n",\ +"freearea\n",\ +"(0, 0);\n",\ +"(1, 0) { 1 X2 } { };\n",\ +"(1, 1) { 1 X3 } { 1 Y3 };\n",\ +"(-0.5, 1.5) { } { 1.5 Y3 };\n",\ +"\n",\ +"freearea2\n",\ +"(0, 0);\n",\ +"(1, 0) { 1 X2 } { };\n",\ +"(1, 1) { 1 X3 } { 1 Y3 };\n",\ +"(0, 1) { } { 1 Y3 };\n",\ +"\n",\ +"elements\n",\ +"(1, 2, 3, 4);\n",\ +"\n",\ +"endrule\n",\ +"\n",\ +"\n",\ +"\n",\ +"rule \"Quad P Right (2)\"\n",\ +"\n",\ +"quality 2\n",\ +"\n",\ +"mappoints\n",\ +"(0, 0);\n",\ +"(1, 0);\n",\ +"(1, 1);\n",\ +"\n",\ +"maplines\n",\ +"(1, 2) del;\n",\ +"\n",\ +"newpoints\n",\ +"(0, 1) { -1 X2, 1 X3 } { 1 Y3 };\n",\ +"\n",\ +"newlines\n",\ +"(1, 4);\n",\ +"(4, 3);\n",\ +"(3, 2);\n",\ +"\n",\ +"freearea\n",\ +"(0, 0);\n",\ +"(1, 0) { 1 X2 } { };\n",\ +"(1.2, 0.5) { 0.7 X2, 0.5 X3 } { 0.5 Y3 };\n",\ +"(1, 1) { 1 X3 } { 1 Y3 };\n",\ +"(-0.5, 1.5) { -2 X2, 1.5 X3 } { 1.5 Y3 };\n",\ +"\n",\ +"freearea2\n",\ +"(0, 0);\n",\ +"(1, 0) { 1 X2 } { };\n",\ +"(1, 0.5) { 0.5 X2, 0.5 X3 } { 0.5 Y3 };\n",\ +"(1, 1) { 1 X3 } { 1 Y3 };\n",\ +"(0, 1) { -1 X2, 1 X3 } { 1 Y3 };\n",\ +"\n",\ +"elements\n",\ +"(1, 2, 3, 4);\n",\ +"\n",\ +"\n",\ +"orientations\n",\ +"(1, 2, 3);\n",\ +"\n",\ +"\n",\ +"endrule\n",\ +"\n",\ +"\n",\ +"rule \"Quad Right PL (2)\"\n",\ +"\n",\ +"quality 2\n",\ +"\n",\ +"mappoints\n",\ +"(0, 0);\n",\ +"(1, 0);\n",\ +"(1, 1);\n",\ +"(0, 1);\n",\ +"\n",\ +"maplines\n",\ +"(1, 2) del;\n",\ +"(2, 3) del;\n",\ +"\n",\ +"newpoints\n",\ +"\n",\ +"newlines\n",\ +"(1, 4);\n",\ +"(4, 3);\n",\ +"\n",\ +"freearea\n",\ +"(0, 0);\n",\ +"(1, 0) { 1 X2 } { };\n",\ +"(1, 1) { 1 X3 } { 1 Y3 };\n",\ +"(0.5, 1.2) { -0.1 X2, 0.6 X3, 0.6 X4 } { -0.1 Y2, 0.6 Y3, 0.6 Y4 };\n",\ +"(0, 1) { 1 X4 } { 1 Y4 };\n",\ +"(-0.2, 0.5) { -0.1 X2, -0.1 X3, 0.6 X4 } { -0.1 Y2, -0.1 Y3, 0.6 Y4 };\n",\ +"\n",\ +"freearea2\n",\ +"(0, 0);\n",\ +"(1, 0) { 1 X2 } { };\n",\ +"(1, 1) { 1 X3 } { 1 Y3 };\n",\ +"(0.5, 1) { 0.5 X3, 0.5 X4 } { 0.5 Y3, 0.5 Y4 };\n",\ +"(0, 1) { 1 X4 } { 1 Y4 };\n",\ +"(0, 0.5) { 0.5 X4 } { 0.5 Y4 };\n",\ +"\n",\ +"elements\n",\ +"(1, 2, 3, 4);\n",\ +"\n",\ +"orientations\n",\ +"(1, 2, 3);\n",\ +"(1, 3, 4);\n",\ +"(1, 2, 4);\n",\ +"(4, 2, 3);\n",\ +"\n",\ +"\n",\ +"endrule\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"rule \"Left Quad (1)\"\n",\ +"\n",\ +"quality 1\n",\ +"\n",\ +"mappoints\n",\ +"(0, 0);\n",\ +"(1, 0);\n",\ +"(0, 1);\n",\ +"\n",\ +"maplines\n",\ +"(1, 2) del;\n",\ +"(3, 1) del;\n",\ +"\n",\ +"newpoints\n",\ +"(1, 1) { 1 X2, 1 X3 } { 1 Y3 };\n",\ +"\n",\ +"newlines\n",\ +"(3, 4);\n",\ +"(4, 2);\n",\ +"\n",\ +"freearea\n",\ +"(0, 0);\n",\ +"(1, 0) { 1 X2 } { };\n",\ +"(1.5, 1.5) { 1.5 X2, 1.5 X3 } { 1.5 Y3 };\n",\ +"(0, 1) { 1 X3 } { 1 Y3 };\n",\ +"\n",\ +"freearea2\n",\ +"(0, 0);\n",\ +"(1, 0) { 1 X2 } { };\n",\ +"(1, 1) { 1 X2, 1 X3 } { 1 Y3 };\n",\ +"(0, 1) { 1 X3 } { 1 Y3 };\n",\ +"\n",\ +"elements\n",\ +"(1, 2, 4, 3);\n",\ +"\n",\ +"endrule\n",\ +"\n",\ +"\n",\ +"\n",\ +"rule \"Left P Quad (2)\"\n",\ +"\n",\ +"quality 2\n",\ +"\n",\ +"mappoints\n",\ +"(0, 0);\n",\ +"(1, 0);\n",\ +"(0, 1);\n",\ +"\n",\ +"maplines\n",\ +"(1, 2) del;\n",\ +"\n",\ +"newpoints\n",\ +"(1, 1) { 1 X2, 1 X3 } { 1 Y3 };\n",\ +"\n",\ +"newlines\n",\ +"(1, 3);\n",\ +"(3, 4);\n",\ +"(4, 2);\n",\ +"\n",\ +"freearea\n",\ +"(0, 0);\n",\ +"(1, 0) { 1 X2 } { };\n",\ +"(1.5, 1.5) { 1.5 X2, 1.5 X3 } { 1.5 Y3 };\n",\ +"(0, 1) { 1 X3 } { 1 Y3 };\n",\ +"(-0.2, 0.6) { -0.2 X2, 0.6 X3 } { 0.6 Y3 };\n",\ +"\n",\ +"freearea2\n",\ +"(0, 0);\n",\ +"(1, 0) { 1 X2 } { };\n",\ +"(1, 1) { 1 X2, 1 X3 } { 1 Y3 };\n",\ +"(0, 1) { 1 X3 } { 1 Y3 };\n",\ +"(0, 0.5) { 0.5 X3 } { 0.5 Y3 };\n",\ +"\n",\ +"elements\n",\ +"(1, 2, 4, 3);\n",\ +"\n",\ +"endrule\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"rule \"Left Quad RP (2)\"\n",\ +"\n",\ +"quality 2\n",\ +"\n",\ +"mappoints\n",\ +"(0, 0);\n",\ +"(1, 0);\n",\ +"(0, 1);\n",\ +"(1, 1);\n",\ +"\n",\ +"maplines\n",\ +"(1, 2) del;\n",\ +"(3, 1) del;\n",\ +"\n",\ +"newpoints\n",\ +"\n",\ +"newlines\n",\ +"(3, 4);\n",\ +"(4, 2);\n",\ +"\n",\ +"freearea\n",\ +"(0, 0);\n",\ +"(1, 0) { 1 X2 } { };\n",\ +"(1.2, 0.5) { 0.6 X2, 0.6 X4, -0.1 X3 } { 0.6 Y2, 0.6 Y4, -0.1 Y3 };\n",\ +"(1, 1) { 1 X4 } { 1 Y4 };\n",\ +"(0.5, 1.2) { -0.1 X2, 0.6 X3, 0.6 X4 } { -0.1 Y2, 0.6 Y3, 0.6 Y4 };\n",\ +"(0, 1) { 1 X3 } { 1 Y3 };\n",\ +"\n",\ +"freearea2\n",\ +"(0, 0);\n",\ +"(1, 0) { 1 X2 } { };\n",\ +"(1, 0.5) { 0.5 X2, 0.5 X4 } { 0.5 Y2, 0.5 Y4 };\n",\ +"(1, 1) { 1 X4 } { 1 Y4 };\n",\ +"(0.5, 1) { 0.5 X3, 0.5 X4 } { 0.5 Y3, 0.5 Y4 };\n",\ +"(0, 1) { 1 X3 } { 1 Y3 };\n",\ +"\n",\ +"elements\n",\ +"(1, 2, 4, 3);\n",\ +"\n",\ +"orientations\n",\ +"(1, 2, 4);\n",\ +"(1, 4, 3);\n",\ +"\n",\ +"endrule\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"rule \"Two left (1)\"\n",\ +"\n",\ +"quality 1\n",\ +"\n",\ +"mappoints\n",\ +"(0, 0);\n",\ +"(1, 0);\n",\ +"(1, 1);\n",\ +"(0, 1);\n",\ +"\n",\ +"maplines\n",\ +"(1, 2) del;\n",\ +"(3, 4) del;\n",\ +"(4, 1) del;\n",\ +"\n",\ +"newpoints\n",\ +"\n",\ +"newlines\n",\ +"(3, 2);\n",\ +"\n",\ +"freearea\n",\ +"(0, 0);\n",\ +"(1, 0) { 1 X2 } { };\n",\ +"(1.5, 0.5) { 0.75 X2, 0.75 X3, -0.25 X4 } { 0.75 Y3, -0.25 Y4 };\n",\ +"(1, 1) { 1 X3 } { 1 Y3 };\n",\ +"(0, 1) { 1 X4 } { 1 Y4 };\n",\ +"\n",\ +"\n",\ +"freearea2\n",\ +"(0, 0);\n",\ +"(1, 0) { 1 X2 } { };\n",\ +"(1, 0.5) { 0.5 X2, 0.5 X3 } { 0.5 Y3 };\n",\ +"(1, 1) { 1 X3 } { 1 Y3 };\n",\ +"(0, 1) { 1 X4 } { 1 Y4 };\n",\ +"\n",\ +"elements\n",\ +"(1, 2, 3, 4);\n",\ +"\n",\ +"endrule\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"rule \"Two Right (1)\"\n",\ +"\n",\ +"quality 1\n",\ +"\n",\ +"mappoints\n",\ +"(0, 0);\n",\ +"(1, 0);\n",\ +"(1, 1);\n",\ +"(0, 1);\n",\ +"\n",\ +"maplines\n",\ +"(1, 2) del;\n",\ +"(2, 3) del;\n",\ +"(3, 4) del;\n",\ +"\n",\ +"newpoints\n",\ +"\n",\ +"newlines\n",\ +"(1, 4);\n",\ +"\n",\ +"freearea\n",\ +"(0, 0);\n",\ +"(1, 0) { 1 X2 } { };\n",\ +"(1, 1) { 1 X3 } { 1 Y3 };\n",\ +"(0, 1) { 1 X4 } { 1 Y4 };\n",\ +"(-0.5, 0.5) { -0.25 X2, -0.25 X3, 0.75 X4 } { -0.25 Y3, 0.75 Y4 };\n",\ +"\n",\ +"freearea2\n",\ +"(0, 0);\n",\ +"(1, 0) { 1 X2 } { };\n",\ +"(1, 1) { 1 X3 } { 1 Y3 };\n",\ +"(0, 1) { 1 X4 } { 1 Y4 };\n",\ +"(0, 0.5) { 0.5 X4 } { 0.5 Y4 };\n",\ +"\n",\ +"elements\n",\ +"(1, 2, 3, 4);\n",\ +"\n",\ +"endrule\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"rule \"Right 120 (1)\"\n",\ +"\n",\ +"quality 1000\n",\ +"\n",\ +"mappoints\n",\ +"(0, 0);\n",\ +"(1, 0);\n",\ +"(1.5, 0.866);\n",\ +"\n",\ +"maplines\n",\ +"(1, 2) del;\n",\ +"(2, 3) del;\n",\ +"\n",\ +"newpoints\n",\ +"(0.5, 0.866) { 1 X3, -1 X2 } { 1 Y3 };\n",\ +"\n",\ +"newlines\n",\ +"(1, 4);\n",\ +"(4, 3);\n",\ +"\n",\ +"freearea\n",\ +"(0, 0);\n",\ +"(1, 0) { 1 X2 } { };\n",\ +"(1.5, 0.866) { 1 X3 } { 1 Y3 };\n",\ +"(1, 1.732) { -2 X2, 2 X3 } { 2 Y3 };\n",\ +"(0, 1.732) { -3 X2, 2 X3 } { 2 Y3 };\n",\ +"(-0.5, 0.866) { -2 X2, 1 X3 } {1 Y3 };\n",\ +"\n",\ +"elements\n",\ +"(1, 2, 4);\n",\ +"(2, 3, 4);\n",\ +"\n",\ +"endrule\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"rule \"Left 120 (1)\"\n",\ +"\n",\ +"quality 1000\n",\ +"\n",\ +"mappoints\n",\ +"(0, 0);\n",\ +"(1, 0);\n",\ +"(-0.5, 0.866);\n",\ +"\n",\ +"maplines\n",\ +"(1, 2) del;\n",\ +"(3, 1) del;\n",\ +"\n",\ +"newpoints\n",\ +"(0.5, 0.866) { 1 X3, 1 X2 } { 1 Y3 };\n",\ +"\n",\ +"newlines\n",\ +"(3, 4);\n",\ +"(4, 2);\n",\ +"\n",\ +"freearea\n",\ +"(0, 0);\n",\ +"(1, 0) { 1 X2 } { };\n",\ +"(1.5, 0.866) { 2 X2, 1 X3 } { 1 Y3 };\n",\ +"(1, 1.732) { 2 X2, 2 X3 } { 2 Y3 };\n",\ +"(0, 1.732) { -1 X2, 2 X3 } { 2 Y3 };\n",\ +"(-0.5, 0.866) { 1 X3 } {1 Y3 };\n",\ +"\n",\ +"elements\n",\ +"(1, 2, 4);\n",\ +"(2, 3, 4);\n",\ +"\n",\ +"endrule\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"rule \"Left Right (1)\"\n",\ +"\n",\ +"quality 1\n",\ +"\n",\ +"mappoints\n",\ +"(0, 0);\n",\ +"(1, 0);\n",\ +"(1, 1);\n",\ +"(0, 1);\n",\ +"\n",\ +"maplines\n",\ +"(1, 2) del;\n",\ +"(2, 3) del;\n",\ +"(4, 1) del;\n",\ +"\n",\ +"\n",\ +"newlines\n",\ +"(4, 3);\n",\ +"\n",\ +"freearea\n",\ +"(0, 0);\n",\ +"(1, 0) { 1 X2 } { };\n",\ +"(1, 1) { 1 X3 } { 1 Y3 };\n",\ +"(0.5, 1.5) { -0.25 X2, 0.75 X3, 0.75 X4 } { 0.75 Y3, 0.75 Y4 };\n",\ +"(0, 1) { 1 X4 } { 1 Y4 };\n",\ +"\n",\ +"freearea2\n",\ +"(0, 0);\n",\ +"(1, 0) { 1 X2 } { };\n",\ +"(1, 1) { 1 X3 } { 1 Y3 };\n",\ +"(0.5, 1) { 0.5 X3, 0.5 X4 } { 0.5 Y3, 0.5 Y4 };\n",\ +"(0, 1) { 1 X4 } { 1 Y4 };\n",\ +"\n",\ +"\n",\ +"elements\n",\ +"(1, 2, 3, 4);\n",\ +"\n",\ +"endrule\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"rule \"Fill Quad\"\n",\ +"\n",\ +"quality 1\n",\ +"\n",\ +"mappoints\n",\ +"(0, 0);\n",\ +"(1, 0);\n",\ +"(1, 1);\n",\ +"(0, 1);\n",\ +"\n",\ +"maplines\n",\ +"(1, 2) del;\n",\ +"(2, 3) del;\n",\ +"(3, 4) del;\n",\ +"(4, 1) del;\n",\ +"\n",\ +"newpoints\n",\ +"\n",\ +"newlines\n",\ +"\n",\ +"freearea\n",\ +"(0, 0);\n",\ +"(1, 0) { 1 X2 } { 1 Y2 };\n",\ +"(1, 1) { 1 X3 } { 1 Y3 };\n",\ +"(0, 1) { 1 X4 } { 1 Y4 };\n",\ +"\n",\ +"elements\n",\ +"(1, 2, 3, 4);\n",\ +"\n",\ +"endrule\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"rule \"Fill Triangle\"\n",\ +"\n",\ +"quality 10\n",\ +"\n",\ +"mappoints\n",\ +"(0, 0);\n",\ +"(1, 0);\n",\ +"(0.5, 0.86);\n",\ +"\n",\ +"maplines\n",\ +"(1, 2) del;\n",\ +"(2, 3) del;\n",\ +"(3, 1) del;\n",\ +"\n",\ +"newpoints\n",\ +"\n",\ +"newlines\n",\ +"\n",\ +"freearea\n",\ +"(0, 0);\n",\ +"(1, 0) { 1 X2 } { 1 Y2 };\n",\ +"(0.5, 0.86) { 1 X3 } { 1 Y3 };\n",\ +"\n",\ +"elements\n",\ +"(1, 2, 3);\n",\ +"\n",\ +"endrule\n",\ +"\n",\ +"\n",\ +"\n",\ +"rule \"Right 60 (1)\"\n",\ +"\n",\ +"quality 10\n",\ +"\n",\ +"mappoints\n",\ +"(0, 0);\n",\ +"(1, 0) { 0.5, 0, 1.0 };\n",\ +"(0.5, 0.866) { 0.6, 0, 0.8 };\n",\ +"\n",\ +"maplines\n",\ +"(1, 2) del;\n",\ +"(2, 3) del;\n",\ +"\n",\ +"newpoints\n",\ +"\n",\ +"newlines\n",\ +"(1, 3);\n",\ +"\n",\ +"freearea\n",\ +"(0, 0);\n",\ +"(1, 0) { 1 X2 } { };\n",\ +"(0.5, 0.866) { 1 X3 } { 1 Y3 };\n",\ +"(-0.125, 0.6495) { -0.5 X2, 0.75 X3 } { -0.5 Y2, 0.75 Y3 };\n",\ +"\n",\ +"freearea2\n",\ +"(0, 0);\n",\ +"(1, 0) { 1 X2 } { };\n",\ +"(0.5, 0.866) { 1 X3 } { 1 Y3 };\n",\ +"(0.25, 0.433) { 0.5 X3 } { 0.5 Y3 };\n",\ +"\n",\ +"elements\n",\ +"(1, 2, 3);\n",\ +"\n",\ +"endrule\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"rule \"Vis A Vis (2)\"\n",\ +"\n",\ +"quality 2\n",\ +"\n",\ +"mappoints\n",\ +"(0, 0);\n",\ +"(1, 0);\n",\ +"(1, 1);\n",\ +"(0, 1);\n",\ +"\n",\ +"maplines\n",\ +"(1, 2) del;\n",\ +"(3, 4) del;\n",\ +"\n",\ +"newpoints\n",\ +"\n",\ +"newlines\n",\ +"(1, 4);\n",\ +"(3, 2);\n",\ +"\n",\ +"freearea\n",\ +"(0, 0);\n",\ +"(1, 0) { 1 X2 } { };\n",\ +"(1.5, 0.5) { 0.75 X2, 0.75 X3, -0.25 X4 } { 0.75 Y3, -0.25 Y4 };\n",\ +"(1, 1) { 1 X3 } { 1 Y3 };\n",\ +"(0, 1) { 1 X4 } { 1 Y4 };\n",\ +"(-0.5, 0.5) { -0.25 X2, -0.25 X3, 0.75 X4 } { -0.25 Y3, 0.75 Y4 };\n",\ +"\n",\ +"freearea2\n",\ +"(0, 0);\n",\ +"(1, 0) { 1 X2 } { };\n",\ +"(1, 0.5) { 0.5 X2, 0.5 X3 } { 0.5 Y3 };\n",\ +"(1, 1) { 1 X3 } { 1 Y3 };\n",\ +"(0, 1) { 1 X4 } { 1 Y4 };\n",\ +"(0, 0.5) { 0.5 X4 } { 0.5 Y4 };\n",\ +"\n",\ +"elements\n",\ +"(1, 2, 3, 4);\n",\ +"\n",\ +"orientations\n",\ +"(1, 3, 4);\n",\ +"(2, 3, 4);\n",\ +"(1, 2, 3);\n",\ +"(1, 2, 4);\n",\ +"\n",\ +"endrule\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"rule \"2 h Vis A Vis (1)\"\n",\ +"\n",\ +"quality 3000\n",\ +"\n",\ +"mappoints\n",\ +"(0, 0);\n",\ +"(1, 0);\n",\ +"(1, 1.732);\n",\ +"(0, 1.732);\n",\ +"\n",\ +"maplines\n",\ +"(1, 2) del;\n",\ +"(3, 4) del;\n",\ +"\n",\ +"newpoints\n",\ +"(0.5, 0.866) { 0.25 X3, 0.25 X4 } { 0.25 Y2, 0.25 Y3, 0.25 Y4 };\n",\ +"\n",\ +"newlines\n",\ +"(1, 5);\n",\ +"(5, 4);\n",\ +"(3, 5);\n",\ +"(5, 2);\n",\ +"\n",\ +"freearea\n",\ +"(0, 0);\n",\ +"(1, 0) { 1 X2 } { 1 Y2 };\n",\ +"(1.5, 0.866) { 0.75 X2, 0.75 X3, -0.25 X4 } { 0.75 Y2, 0.75 Y3, -0.25 Y4 };\n",\ +"(1, 1.732) { 1 X3 } { 1 Y3 };\n",\ +"(0, 1.732) { 1 X4 } { 1 Y4 };\n",\ +"(-0.5, 0.866) { 0.75 X4, -0.25 X2, -0.25 X3 } { 0.75 Y4, -0.25 Y3 };\n",\ +"\n",\ +"elements\n",\ +"(1, 2, 5);\n",\ +"(3, 4, 5);\n",\ +"\n",\ +"endrule\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +0}; +} diff --git a/contrib/Netgen/libsrc/meshing/refine.cpp b/contrib/Netgen/libsrc/meshing/refine.cpp new file mode 100644 index 0000000000..f7578d3394 --- /dev/null +++ b/contrib/Netgen/libsrc/meshing/refine.cpp @@ -0,0 +1,721 @@ +#include <mystdlib.h> +#include "meshing.hpp" + + +namespace netgen +{ + void Refinement :: Refine (Mesh & mesh) + { + // reduce 2nd order + mesh.ComputeNVertices(); + mesh.SetNP(mesh.GetNV()); + + + INDEX_2_HASHTABLE<int> between(mesh.GetNP() + 5); + + int oldne, oldns, oldnf; + + // refine edges + + ARRAY<EdgePointGeomInfo,PointIndex::BASE> epgi; + + oldns = mesh.GetNSeg(); + for (SegmentIndex si = 0; si < oldns; si++) + { + const Segment & el = mesh.LineSegment(si); + + INDEX_2 i2 = INDEX_2::Sort(el.p1, el.p2); + PointIndex pinew; + EdgePointGeomInfo ngi; + + if (between.Used(i2)) + { + pinew = between.Get(i2); + ngi = epgi[pinew]; + } + else + { + Point3d pnew; + + PointBetween (mesh.Point (el.p1), + mesh.Point (el.p2), 0.5, + el.surfnr1, el.surfnr2, + el.epgeominfo[0], el.epgeominfo[1], + pnew, ngi); + + pinew = mesh.AddPoint (pnew); + between.Set (i2, pinew); + + + if (pinew >= epgi.Size()+PointIndex::BASE) + epgi.SetSize (pinew+1-PointIndex::BASE); + epgi[pinew] = ngi; + } + + Segment ns1 = el; + Segment ns2 = el; + ns1.p2 = pinew; + ns1.epgeominfo[1] = ngi; + ns2.p1 = pinew; + ns2.epgeominfo[0] = ngi; + + mesh.LineSegment(si) = ns1; + mesh.AddSegment (ns2); + } + + // refine surface elements + ARRAY<PointGeomInfo,PointIndex::BASE> surfgi (8*mesh.GetNP()); + for (int i = PointIndex::BASE; + i < surfgi.Size()+PointIndex::BASE; i++) + surfgi[i].trignum = -1; + + + oldnf = mesh.GetNSE(); + for (SurfaceElementIndex sei = 0; sei < oldnf; sei++) + { + int j, k; + const Element2d & el = mesh.SurfaceElement(sei); + + switch (el.GetType()) + { + case TRIG: + case TRIG6: + { + ArrayMem<int,6> pnums(6); + ArrayMem<PointGeomInfo,6> pgis(6); + + static int betw[3][3] = + { { 2, 3, 4 }, + { 1, 3, 5 }, + { 1, 2, 6 } }; + + for (j = 1; j <= 3; j++) + { + pnums.Elem(j) = el.PNum(j); + pgis.Elem(j) = el.GeomInfoPi(j); + } + + for (j = 0; j < 3; j++) + { + PointIndex pi1 = pnums.Elem(betw[j][0]); + PointIndex pi2 = pnums.Elem(betw[j][1]); + + INDEX_2 i2 (pi1, pi2); + i2.Sort(); + + Point3d pb; + PointGeomInfo pgi; + PointBetween (mesh.Point (pi1), + mesh.Point (pi2), 0.5, + mesh.GetFaceDescriptor(el.GetIndex ()).SurfNr(), + el.GeomInfoPi (betw[j][0]), + el.GeomInfoPi (betw[j][1]), + pb, pgi); + + + pgis.Elem(4+j) = pgi; + if (between.Used(i2)) + pnums.Elem(4+j) = between.Get(i2); + else + { + pnums.Elem(4+j) = mesh.AddPoint (pb); + between.Set (i2, pnums.Get(4+j)); + } + + if (surfgi.Size() < pnums.Elem(4+j)) + surfgi.SetSize (pnums.Elem(4+j)); + surfgi.Elem(pnums.Elem(4+j)) = pgis.Elem(4+j); + } + + + static int reftab[4][3] = + { { 1, 6, 5 }, + { 2, 4, 6 }, + { 3, 5, 4 }, + { 6, 4, 5 } }; + + int ind = el.GetIndex(); + for (j = 0; j < 4; j++) + { + Element2d nel(TRIG); + for (k = 1; k <= 3; k++) + { + nel.PNum(k) = pnums.Get(reftab[j][k-1]); + nel.GeomInfoPi(k) = pgis.Get(reftab[j][k-1]); + } + nel.SetIndex(ind); + + if (j == 0) + mesh.SurfaceElement(sei) = nel; + else + mesh.AddSurfaceElement(nel); + } + break; + } + case QUAD: + case QUAD6: + case QUAD8: + { + ArrayMem<int,9> pnums(9); + ArrayMem<PointGeomInfo,9> pgis(9); + + static int betw[5][3] = + { { 1, 2, 5 }, + { 2, 3, 6 }, + { 3, 4, 7 }, + { 1, 4, 8 }, + { 1, 3, 9 } }; + + for (j = 1; j <= 4; j++) + { + pnums.Elem(j) = el.PNum(j); + pgis.Elem(j) = el.GeomInfoPi(j); + } + + for (j = 0; j < 5; j++) + { + int pi1 = pnums.Elem(betw[j][0]); + int pi2 = pnums.Elem(betw[j][1]); + + INDEX_2 i2 (pi1, pi2); + i2.Sort(); + + if (between.Used(i2)) + { + pnums.Elem(5+j) = between.Get(i2); + pgis.Elem(5+j) = surfgi.Get(pnums.Elem(4+j)); + } + else + { + Point3d pb; + PointBetween (mesh.Point (pi1), + mesh.Point (pi2), 0.5, + mesh.GetFaceDescriptor(el.GetIndex ()).SurfNr(), + el.GeomInfoPi (betw[j][0]), + el.GeomInfoPi (betw[j][1]), + pb, pgis.Elem(5+j)); + + pnums.Elem(5+j) = mesh.AddPoint (pb); + + between.Set (i2, pnums.Get(5+j)); + + if (surfgi.Size() < pnums.Elem(5+j)) + surfgi.SetSize (pnums.Elem(5+j)); + surfgi.Elem(pnums.Elem(5+j)) = pgis.Elem(5+j); + } + } + + static int reftab[4][4] = + { + { 1, 5, 9, 8 }, + { 5, 2, 6, 9 }, + { 8, 9, 7, 4 }, + { 9, 6, 3, 7 } }; + + int ind = el.GetIndex(); + for (j = 0; j < 4; j++) + { + Element2d nel(QUAD); + for (k = 1; k <= 4; k++) + { + nel.PNum(k) = pnums.Get(reftab[j][k-1]); + nel.GeomInfoPi(k) = pgis.Get(reftab[j][k-1]); + } + nel.SetIndex(ind); + + if (j == 0) + mesh.SurfaceElement(sei) = nel; + else + mesh.AddSurfaceElement(nel); + } + break; + } + default: + PrintSysError ("Refine: undefined surface element type ", int(el.GetType())); + } + } + + // refine volume elements + oldne = mesh.GetNE(); + for (ElementIndex ei = 0; ei < oldne; ei++) + { + int j, k; + + const Element & el = mesh.VolumeElement(ei); + switch (el.GetType()) + { + case TET: + case TET10: + { + ArrayMem<int,10> pnums(10); + static int betw[6][3] = + { { 1, 2, 5 }, + { 1, 3, 6 }, + { 1, 4, 7 }, + { 2, 3, 8 }, + { 2, 4, 9 }, + { 3, 4, 10 } }; + + int elrev = el.flags.reverse; + + for (j = 1; j <= 4; j++) + pnums.Elem(j) = el.PNum(j); + if (elrev) + swap (pnums.Elem(3), pnums.Elem(4)); + + for (j = 0; j < 6; j++) + { + INDEX_2 i2; + i2.I1() = pnums.Get(betw[j][0]); + i2.I2() = pnums.Get(betw[j][1]); + i2.Sort(); + + if (between.Used(i2)) + pnums.Elem(5+j) = between.Get(i2); + else + { + pnums.Elem(5+j) = mesh.AddPoint + (Center (mesh.Point(i2.I1()), + mesh.Point(i2.I2()))); + between.Set (i2, pnums.Elem(5+j)); + } + } + + static int reftab[8][4] = + { { 1, 5, 6, 7 }, + { 5, 2, 8, 9 }, + { 6, 8, 3, 10 }, + { 7, 9, 10, 4 }, + { 5, 6, 7, 9 }, + { 5, 6, 9, 8 }, + { 6, 7, 9, 10 }, + { 6, 8, 10, 9 } }; + /* + { { 1, 5, 6, 7 }, + { 5, 2, 8, 9 }, + { 6, 8, 3, 10 }, + { 7, 9, 10, 4 }, + { 5, 6, 7, 9 }, + { 5, 6, 8, 9 }, + { 6, 7, 9, 10 }, + { 6, 8, 9, 10 } }; + */ + static int reverse[8] = + { + 0, 0, 0, 0, 0, 1, 0, 1 + }; + + int ind = el.GetIndex(); + for (j = 0; j < 8; j++) + { + Element nel; + for (k = 1; k <= 4; k++) + nel.PNum(k) = pnums.Get(reftab[j][k-1]); + nel.SetIndex(ind); + nel.flags.reverse = reverse[j]; + if (elrev) + { + nel.flags.reverse = 1 - nel.flags.reverse; + swap (nel.PNum(3), nel.PNum(4)); + } + + if (j == 0) + mesh.VolumeElement(ei) = nel; + else + mesh.AddVolumeElement (nel); + } + break; + } + case HEX: + { + ArrayMem<int,27> pnums(27); + static int betw[13][3] = + { { 1, 2, 9 }, + { 3, 4, 10 }, + { 4, 1, 11 }, + { 2, 3, 12 }, + { 5, 6, 13 }, + { 7, 8, 14 }, + { 8, 5, 15 }, + { 6, 7, 16 }, + { 1, 5, 17 }, + { 2, 6, 18 }, + { 3, 7, 19 }, + { 4, 8, 20 }, + { 2, 8, 21 }, + }; + + static int fbetw[12][3] = + { { 1, 3, 22 }, + { 2, 4, 22 }, + { 5, 7, 23 }, + { 6, 8, 23 }, + { 1, 6, 24 }, + { 2, 5, 24 }, + { 2, 7, 25 }, + { 3, 6, 25 }, + { 3, 8, 26 }, + { 4, 7, 26 }, + { 1, 8, 27 }, + { 4, 5, 27 }, + }; + + + pnums = -1; + + for (j = 1; j <= 8; j++) + pnums.Elem(j) = el.PNum(j); + + + for (j = 0; j < 13; j++) + { + INDEX_2 i2; + i2.I1() = pnums.Get(betw[j][0]); + i2.I2() = pnums.Get(betw[j][1]); + i2.Sort(); + + if (between.Used(i2)) + pnums.Elem(9+j) = between.Get(i2); + else + { + pnums.Elem(9+j) = mesh.AddPoint + (Center (mesh.Point(i2.I1()), + mesh.Point(i2.I2()))); + between.Set (i2, pnums.Elem(9+j)); + } + } + + for (j = 0; j < 6; j++) + { + INDEX_2 i2a, i2b; + i2a.I1() = pnums.Get(fbetw[2*j][0]); + i2a.I2() = pnums.Get(fbetw[2*j][1]); + i2a.Sort(); + i2b.I1() = pnums.Get(fbetw[2*j+1][0]); + i2b.I2() = pnums.Get(fbetw[2*j+1][1]); + i2b.Sort(); + + if (between.Used(i2a)) + pnums.Elem(22+j) = between.Get(i2a); + else if (between.Used(i2b)) + pnums.Elem(22+j) = between.Get(i2b); + else + { + pnums.Elem(22+j) = mesh.AddPoint + (Center (mesh.Point(i2a.I1()), + mesh.Point(i2a.I2()))); + + between.Set (i2a, pnums.Elem(22+j)); + } + } + + static int reftab[8][8] = + { { 1, 9, 22, 11, 17, 24, 21, 27 }, + { 9, 2, 12, 22, 24, 18, 25, 21 }, + { 11, 22, 10, 4, 27, 21, 26, 20}, + { 22, 12, 3, 10, 21, 25, 19, 26}, + { 17, 24, 21, 27, 5, 13, 23, 15}, + { 24, 18, 25, 21, 13, 6, 16, 23}, + { 27, 21, 26, 20, 15, 23, 14, 8}, + { 21, 25, 19, 26, 23, 16, 7, 14} }; + + + int ind = el.GetIndex(); + for (j = 0; j < 8; j++) + { + Element nel(HEX); + for (k = 1; k <= 8; k++) + nel.PNum(k) = pnums.Get(reftab[j][k-1]); + nel.SetIndex(ind); + + if (j == 0) + mesh.VolumeElement(ei) = nel; + else + mesh.AddVolumeElement (nel); + } + break; + } + case PRISM: + { + ArrayMem<int,18> pnums(18); + static int betw[9][3] = + { { 3, 1, 7 }, + { 1, 2, 8 }, + { 3, 2, 9 }, + { 6, 4, 10 }, + { 4, 5, 11 }, + { 6, 5, 12 }, + { 1, 4, 13 }, + { 3, 6, 14 }, + { 2, 5, 15 }, + }; + + static int fbetw[6][3] = + { { 1, 6, 16 }, + { 3, 4, 16 }, + { 1, 5, 17 }, + { 2, 4, 17 }, + { 2, 6, 18 }, + { 3, 5, 18 }, + }; + + //int elrev = el.flags.reverse; + pnums = -1; + + for (j = 1; j <= 6; j++) + pnums.Elem(j) = el.PNum(j); + // if (elrev) + // swap (pnums.Elem(3), pnums.Elem(4)); + + for (j = 0; j < 9; j++) + { + INDEX_2 i2; + i2.I1() = pnums.Get(betw[j][0]); + i2.I2() = pnums.Get(betw[j][1]); + i2.Sort(); + + if (between.Used(i2)) + pnums.Elem(7+j) = between.Get(i2); + else + { + pnums.Elem(7+j) = mesh.AddPoint + (Center (mesh.Point(i2.I1()), + mesh.Point(i2.I2()))); + between.Set (i2, pnums.Elem(7+j)); + } + } + + for (j = 0; j < 3; j++) + { + INDEX_2 i2a, i2b; + i2a.I1() = pnums.Get(fbetw[2*j][0]); + i2a.I2() = pnums.Get(fbetw[2*j][1]); + i2a.Sort(); + i2b.I1() = pnums.Get(fbetw[2*j+1][0]); + i2b.I2() = pnums.Get(fbetw[2*j+1][1]); + i2b.Sort(); + + if (between.Used(i2a)) + pnums.Elem(16+j) = between.Get(i2a); + else if (between.Used(i2b)) + pnums.Elem(16+j) = between.Get(i2b); + else + { + pnums.Elem(16+j) = mesh.AddPoint + (Center (mesh.Point(i2a.I1()), + mesh.Point(i2a.I2()))); + + between.Set (i2a, pnums.Elem(16+j)); + } + } + + + static int reftab[8][6] = + { { 1, 8, 7, 13, 17, 16 }, + { 7, 8, 9, 16, 17, 18 }, + { 7, 9, 3, 16, 18, 14 }, + { 8, 2, 9, 17, 15, 18 }, + { 13, 17, 16, 4, 11, 10 }, + { 16, 17, 18, 10, 11, 12 }, + { 16, 18, 14, 10, 12, 6 }, + { 17, 15, 18, 11, 5, 12 } }; + + + int ind = el.GetIndex(); + for (j = 0; j < 8; j++) + { + Element nel(PRISM); + for (k = 1; k <= 6; k++) + nel.PNum(k) = pnums.Get(reftab[j][k-1]); + nel.SetIndex(ind); + + + //nel.flags.reverse = reverse[j]; + //if (elrev) + // { + //nel.flags.reverse = 1 - nel.flags.reverse; + //swap (nel.PNum(3), nel.PNum(4)); + + + if (j == 0) + mesh.VolumeElement(ei) = nel; + else + mesh.AddVolumeElement (nel); + } + break; + } + default: + PrintSysError ("Refine: undefined volume element type ", int(el.GetType())); + } + } + + + // update identification tables + for (int i = 1; i <= mesh.GetIdentifications().GetMaxNr(); i++) + { + ARRAY<int,PointIndex::BASE> identmap; + mesh.GetIdentifications().GetMap (i, identmap); + + for (int j = 1; j <= between.GetNBags(); j++) + for (int k = 1; k <= between.GetBagSize(j); k++) + { + INDEX_2 i2; + int newpi; + between.GetData (j, k, i2, newpi); + INDEX_2 oi2(identmap.Get(i2.I1()), + identmap.Get(i2.I2())); + oi2.Sort(); + if (between.Used (oi2)) + { + int onewpi = between.Get(oi2); + mesh.GetIdentifications().Add (newpi, onewpi, i); + } + } + + } + + mesh.ComputeNVertices(); + return; + + int cnttrials = 10; + int wrongels = 0; + for (int i = 1; i <= mesh.GetNE(); i++) + if (mesh.VolumeElement(i).Volume(mesh.Points()) < 0) + { + wrongels++; + mesh.VolumeElement(i).flags.badel = 1; + } + else + mesh.VolumeElement(i).flags.badel = 0; + + if (wrongels) + { + cout << "WARNING: " << wrongels << " with wrong orientation found" << endl; + + int np = mesh.GetNP(); + ARRAY<Point3d> should(np); + ARRAY<Point3d> can(np); + for (int i = 1; i <= np; i++) + { + should.Elem(i) = can.Elem(i) = mesh.Point(i); + } + for (int i = 1; i <= between.GetNBags(); i++) + for (int j = 1; j <= between.GetBagSize(i); j++) + { + INDEX_2 parent; + int child; + between.GetData (i, j, parent, child); + can.Elem(child) = Center (can.Elem(parent.I1()), + can.Elem(parent.I2())); + } + + BitArray boundp(np); + boundp.Clear(); + for (int i = 1; i <= mesh.GetNSE(); i++) + { + const Element2d & sel = mesh.SurfaceElement(i); + for (int j = 1; j <= sel.GetNP(); j++) + boundp.Set(sel.PNum(j)); + } + + + double lam = 0.5; + + while (lam < 0.9 && cnttrials > 0) + { + lam = 2; + do + { + lam *= 0.5; + cnttrials--; + + cout << "lam = " << lam << endl; + + for (int i = 1; i <= np; i++) + if (boundp.Test(i)) + { + for (int j = 1; j <= 3; j++) + mesh.Point(i).X(j) = + lam * should.Get(i).X(j) + + (1-lam) * can.Get(i).X(j); + } + else + mesh.Point(i) = can.Get(i); + + + BitArray free (mesh.GetNP()), fhelp(mesh.GetNP()); + free.Clear(); + for (int i = 1; i <= mesh.GetNE(); i++) + { + const Element & el = mesh.VolumeElement(i); + if (el.Volume(mesh.Points()) < 0) + for (int j = 1; j <= el.GetNP(); j++) + free.Set (el.PNum(j)); + } + for (int k = 1; k <= 3; k++) + { + fhelp.Clear(); + for (int i = 1; i <= mesh.GetNE(); i++) + { + const Element & el = mesh.VolumeElement(i); + int freeel = 0; + for (int j = 1; j <= el.GetNP(); j++) + if (free.Test(el.PNum(j))) + freeel = 1; + if (freeel) + for (int j = 1; j <= el.GetNP(); j++) + fhelp.Set (el.PNum(j)); + } + free.Or (fhelp); + } + + (*testout) << "smooth points: " << endl; + for (int i = 1; i <= free.Size(); i++) + if (free.Test(i)) + (*testout) << "p " << i << endl; + + (*testout) << "surf points: " << endl; + for (int i = 1; i <= mesh.GetNSE(); i++) + for (int j = 1; j <= 3; j++) + (*testout) << mesh.SurfaceElement(i).PNum(j) << endl; + + + + mesh.CalcSurfacesOfNode(); + free.Invert(); + mesh.FixPoints (free); + mesh.ImproveMesh (OPT_REST); + + + wrongels = 0; + for (int i = 1; i <= mesh.GetNE(); i++) + { + if (mesh.VolumeElement(i).Volume(mesh.Points()) < 0) + { + wrongels++; + mesh.VolumeElement(i).flags.badel = 1; + (*testout) << "wrong el: "; + for (int j = 1; j <= 4; j++) + (*testout) << mesh.VolumeElement(i).PNum(j) << " "; + (*testout) << endl; + } + else + mesh.VolumeElement(i).flags.badel = 0; + } + cout << "wrongels = " << wrongels << endl; + } + while (wrongels && cnttrials > 0); + + for (int i = 1; i <= np; i++) + can.Elem(i) = mesh.Point(i); + } + } + + if (cnttrials <= 0) + { + cerr << "ERROR: Sorry, reverted elements" << endl; + } + + mesh.ComputeNVertices(); + } +} diff --git a/contrib/Netgen/libsrc/meshing/ruler2.cpp b/contrib/Netgen/libsrc/meshing/ruler2.cpp new file mode 100644 index 0000000000..82c6dbe57d --- /dev/null +++ b/contrib/Netgen/libsrc/meshing/ruler2.cpp @@ -0,0 +1,646 @@ +#include <mystdlib.h> +#include "meshing.hpp" + +namespace netgen +{ +static double CalcElementBadness (const ARRAY<Point2d> & points, + const Element2d & elem) +{ + // badness = sqrt(3) /36 * circumference^2 / area - 1 + + // h / li + li / h - 2 + + Vec2d v12, v13, v23; + double l12, l13, l23, cir, area; + static const double c = sqrt(3.0) / 36; + + v12 = points.Get(elem.PNum(2)) - points.Get(elem.PNum(1)); + v13 = points.Get(elem.PNum(3)) - points.Get(elem.PNum(1)); + v23 = points.Get(elem.PNum(3)) - points.Get(elem.PNum(2)); + + l12 = v12.Length(); + l13 = v13.Length(); + l23 = v23.Length(); + + cir = l12 + l13 + l23; + area = 0.5 * (v12.X() * v13.Y() - v12.Y() * v13.X()); + if (area < 1e-6) + { + return 1e8; + } + + if (testmode) + { + (*testout) << "l = " << l12 << " + " << l13 << " + " << l23 << " = " + << cir << ", area = " << area << endl; + (*testout) << "shapeerr = " << 10 * (c * cir * cir / area - 1) << endl + << "sizeerr = " << 1/l12 + l12 + 1/l13 + l13 + 1/l23 + l23 - 6 + << endl; + } + + return 10 * (c * cir * cir / area - 1) + + 1/l12 + l12 + 1/l13 + l13 + 1/l23 + l23 - 6; +} + + + +int Meshing2 ::ApplyRules (ARRAY<Point2d> & lpoints, + ARRAY<int> & legalpoints, + int maxlegalpoint, + ARRAY<INDEX_2> & llines, + int maxlegalline, + ARRAY<Element2d> & elements, + ARRAY<INDEX> & dellines, int tolerance) +{ + int i, j, ri, nlok, npok, incnpok, refpi, locli = 0; + + double maxerr = 0.5 + 0.3 * tolerance; + double minelerr = 2 + 0.5 * tolerance * tolerance; + + + bool ok; + int found; // rule number + Vector oldu, newu; + Point2d np; + Vec2d linevec; + int oldnp; + INDEX_2 loclin; + double hf, elerr; + int noldlp, noldll; + int loctestmode; + + static ARRAY<int> pused, lused; + static ARRAY<int> pmap, lmap, pfixed; + static ARRAY<int> pnearness, lnearness; + + static ARRAY<Point2d> tempnewpoints; + static ARRAY<INDEX_2> tempnewlines; + static ARRAY<int> tempdellines; + static ARRAY<Element2d> tempelements; + + + + elements.SetSize (0); + dellines.SetSize (0); + + noldlp = lpoints.Size(); + noldll = llines.Size(); + + pused.SetSize (maxlegalpoint); + lused.SetSize (maxlegalline); + pnearness.SetSize (noldlp); + lnearness.SetSize (llines.Size()); + + + testmode = debugparam.debugoutput; + loctestmode = testmode; + + if (loctestmode) + { + (*testout) << endl << endl << "Check new environment" << endl; + (*testout) << "tolerance = " << tolerance << endl; + for (i = 1; i <= lpoints.Size(); i++) + (*testout) << "P" << i << " = " << lpoints.Get(i) << endl; + (*testout) << endl; + for (i = 1; i <= llines.Size(); i++) + (*testout) << "(" << llines.Get(i).I1() << "-" << llines.Get(i).I2() << ")" << endl; + } + + // check every rule + + found = 0; + + + for (i = 1; i <= noldlp; i++) + pnearness.Set(i, 1000); + + for (j = 1; j <= 2; j++) + pnearness.Set(llines.Get(1).I(j), 0); + + + do + { + ok = 1; + for (i = 1; i <= maxlegalline; i++) + { + const INDEX_2 & hline = llines.Get(i); + + /* + int minn = INT_MAX-1; + for (j = 1; j <= 2; j++) + { + int hi = pnearness.Get(hline.I(j)); + if (hi < minn) minn = hi; + } + */ + int minn = pnearness.Get(hline.I1()); + int minn2 = pnearness.Get(hline.I2()); + if (minn2 < minn) + minn = minn2; + + /* + for (j = 1; j <= 2; j++) + { + int hpi = hline.I(j); + if (pnearness.Get(hpi) > minn+1) + { + ok = 0; + pnearness.Set(hpi, minn+1); + } + } + */ + int hpi = hline.I1(); + if (pnearness.Get(hpi) > minn+1) + { + ok = 0; + pnearness.Set(hpi, minn+1); + } + hpi = hline.I2(); + if (pnearness.Get(hpi) > minn+1) + { + ok = 0; + pnearness.Set(hpi, minn+1); + } + } + } + while (!ok); + + for (i = 1; i <= maxlegalline /* lnearness.Size() */; i++) + { + lnearness.Set(i, 0); + for (j = 1; j <= 2; j++) + lnearness.Elem(i) += pnearness.Get(llines.Get(i).I(j)); + } + + + for (ri = 1; ri <= rules.Size(); ri++) + { + netrule * rule = rules.Get(ri); + + if (loctestmode) + (*testout) << "Rule " << rule->Name() << endl; + + if (rule->GetQuality() > tolerance) continue; + + pmap.SetSize (rule->GetNP()); + lmap.SetSize (rule->GetNL()); + + lused = 0; + pused = 0; + pmap = 0; + lmap = 0; + /* + for (i = 1; i <= lused.Size(); i++) + lused.Set (i, 0); + for (i = 1; i <= pused.Size(); i++) + pused.Set (i, 0); + for (i = 1; i <= pmap.Size(); i++) + pmap.Set(i, 0); + for (i = 1; i <= lmap.Size(); i++) + lmap.Set(i, 0); + */ + + lused[0] = 1; // .Set (1, 1); + lmap[0] = 1; // .Set (1, 1); + + for (j = 1; j <= 2; j++) + { + pmap.Elem(rule->GetPointNr (1, j)) = llines.Get(1).I(j); + pused.Elem(llines.Get(1).I(j))++; + } + + + nlok = 2; + + while (nlok >= 2) + { + + if (nlok <= rule->GetNOldL()) + + { + ok = 0; + while (!ok && lmap.Get(nlok) < maxlegalline /* llines.Size() */) + { + lmap.Elem(nlok)++; + locli = lmap.Get(nlok); + + if (!lused.Get(locli) && + lnearness.Get(locli) <= rule->GetLNearness (nlok) ) + { + ok = 1; + + loclin = llines.Get(locli); + + linevec.X() = lpoints.Get (loclin.I2()).X() - + lpoints.Get (loclin.I1()).X(); + linevec.Y() = lpoints.Get (loclin.I2()).Y() - + lpoints.Get (loclin.I1()).Y(); + + if (rule->CalcLineError (nlok, linevec) > maxerr) + ok = 0; + + for (j = 1; j <= 2 && ok; j++) + { + refpi = rule->GetPointNr (nlok, j); + + if (pmap.Get(refpi) != 0) + { + if (pmap.Get(refpi) != loclin.I(j)) + ok = 0; + } + else + { + if (rule->CalcPointDist (refpi, lpoints.Get(loclin.I(j))) > maxerr + || !legalpoints.Get(loclin.I(j)) + || pused.Get(loclin.I(j))) ok = 0; + } + } + } + } + + if (ok) + { + lused.Set (locli, 1); + for (j = 1; j <= 2; j++) + { + pmap.Set(rule->GetPointNr (nlok, j), loclin.I(j)); + pused.Elem(loclin.I(j))++; + } + + nlok++; + } + else + { + lmap.Elem(nlok) = 0; + nlok--; + + lused.Set (lmap.Get(nlok), 0); + for (j = 1; j <= 2; j++) + { + pused.Elem(llines.Get(lmap.Get(nlok)).I(j)) --; + if (! pused.Get (llines.Get (lmap.Get (nlok)).I(j))) + pmap.Set (rule->GetPointNr (nlok, j), 0); + } + } + } + + else + + { + + // all lines are mapped !! + + // map also all points: + + npok = 1; + incnpok = 1; + + pfixed.SetSize (pmap.Size()); + for (i = 1; i <= pmap.Size(); i++) + pfixed.Elem(i) = (pmap.Get(i) >= 1); + + while (npok >= 1) + { + + if (npok <= rule->GetNOldP()) + + { + if (pfixed.Get(npok)) + + { + if (incnpok) + npok++; + else + npok--; + } + + else + + { + ok = 0; + + if (pmap.Get(npok)) + pused.Elem(pmap.Get(npok))--; + + while (!ok && pmap.Get(npok) < maxlegalpoint) + { + 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 + + { + if (ok) + foundmap.Elem(ri)++; + + if (loctestmode) + (*testout) << "lines and points mapped" << endl; + + + ok = 1; + + // 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) + { + oldu.SetSize (2 * rule->GetNOldP()); + + for (i = 1; i <= rule->GetNOldP(); i++) + { + Vec2d ui(rule->GetPoint(i), lpoints.Get(pmap.Get(i))); + oldu.Set (2*i-1, ui.X()); + oldu.Set (2*i , ui.Y()); + } + + rule -> SetFreeZoneTransformation (oldu, tolerance); + } + + + if (ok && !rule->ConvexFreeZone()) + { + ok = 0; + if (loctestmode) (*testout) << "freezone not convex" << endl; + + /* + 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: + + for (i = 1; i <= maxlegalpoint && ok; i++) + { + if ( !pused.Get(i) && + rule->IsInFreeZone (lpoints.Get(i)) ) + { + ok = 0; + if (loctestmode) + (*testout) << "Point " << i << " in freezone" << endl; + } + } + + + for (i = maxlegalpoint+1; i <= lpoints.Size() && ok; i++) + { + if ( rule->IsInFreeZone (lpoints.Get(i)) ) + { + ok = 0; + if (loctestmode) + (*testout) << "Point " << i << " in freezone" << endl; + } + } + + for (i = 1; i <= maxlegalline && ok; i++) + { + if (!lused.Get(i) && + rule->IsLineInFreeZone (lpoints.Get(llines.Get(i).I1()), + lpoints.Get(llines.Get(i).I2()))) + { + ok = 0; + if (loctestmode) + (*testout) << "line " << llines.Get(i).I1() << "-" + << llines.Get(i).I2() << " in freezone" << endl; + } + } + for (i = maxlegalline+1; i <= llines.Size() && ok; i++) + { + if (rule->IsLineInFreeZone (lpoints.Get(llines.Get(i).I1()), + lpoints.Get(llines.Get(i).I2()))) + { + ok = 0; + if (loctestmode) + (*testout) << "line " << llines.Get(i).I1() << "-" + << llines.Get(i).I2() << " in freezone" << endl; + } + } + + + /* + // check orientations + + for (i = 1; i <= rule->GetNOrientations() && ok; i++) + { + if (CW (lpoints.Get(pmap.Get(rule->GetOrientation(i).i1)), + lpoints.Get(pmap.Get(rule->GetOrientation(i).i2)), + lpoints.Get(pmap.Get(rule->GetOrientation(i).i3))) ) + { + ok = 0; + if (loctestmode) + (*testout) << "Orientation " << i << " not ok" << endl; + } + } + */ + + + if (ok) + { + if (loctestmode) + (*testout) << "rule ok" << endl; + + // newu = rule->GetOldUToNewU() * oldu; + if (rule->GetNOldP() < rule->GetNP()) + { + newu.SetSize (rule->GetOldUToNewU().Height()); + rule->GetOldUToNewU().Mult (oldu, newu); + } + + // Setze neue Punkte: + + oldnp = rule->GetNOldP(); + + for (i = oldnp + 1; i <= rule->GetNP(); i++) + { + np = rule->GetPoint(i); + np.X() += newu.Elem (2 * (i-oldnp) - 1); + np.Y() += newu.Elem (2 * (i-oldnp)); + + pmap.Elem(i) = lpoints.Append (np); + } + + // Setze neue Linien: + + for (i = rule->GetNOldL() + 1; i <= rule->GetNL(); i++) + { + llines.Append (INDEX_2 (pmap.Get(rule->GetPointNr (i, 1)), + pmap.Get(rule->GetPointNr (i, 2)))); + } + + + // delete old lines: + + for (i = 1; i <= rule->GetNDelL(); i++) + dellines.Append (lmap.Get(rule->GetDelLine(i))); + + // insert new elements: + + for (i = 1; i <= rule->GetNE(); i++) + { + elements.Append (rule->GetElement(i)); + for (j = 1; j <= elements.Get(i).GetNP(); j++) + elements.Elem(i).PNum(j) = pmap.Get(elements.Get(i).PNum(j)); + } + + + elerr = 0; + for (i = 1; i <= elements.Size(); i++) + { + if (!mparam.quad) + hf = CalcElementBadness (lpoints, elements.Get(i)); + else + hf = elements.Get(i).CalcJacobianBadness (lpoints) * 5; + if (loctestmode) + (*testout) << "r " << rule->Name() << "bad = " << hf << endl; + if (hf > elerr) elerr = hf; + } + + if (loctestmode) + (*testout) << "error = " << elerr; + + + canuse.Elem(ri) ++; + + if (elerr < minelerr) + { + + if (loctestmode) + { + (*testout) << "rule = " << rule->Name() << endl; + (*testout) << "class = " << tolerance << endl; + (*testout) << "lpoints: " << endl; + for (i = 1; i <= lpoints.Size(); i++) + (*testout) << lpoints.Get(i) << endl; + (*testout) << "llines: " << endl; + for (i = 1; i <= llines.Size(); i++) + (*testout) << llines.Get(i).I1() << " " << llines.Get(i).I2() << endl; + + (*testout) << "Freezone: "; + for (i = 1; i <= rule -> GetTransFreeZone().Size(); i++) + (*testout) << rule->GetTransFreeZone().Get(i) << endl; + } + + + + minelerr = elerr; + found = ri; + + tempnewpoints.SetSize (0); + for (i = noldlp+1; i <= lpoints.Size(); i++) + tempnewpoints.Append (lpoints.Get(i)); + + tempnewlines.SetSize (0); + for (i = noldll+1; i <= llines.Size(); i++) + tempnewlines.Append (llines.Get(i)); + + tempdellines.SetSize (0); + for (i = 1; i <= dellines.Size(); i++) + tempdellines.Append (dellines.Get(i)); + + tempelements.SetSize (0); + for (i = 1; i <= elements.Size(); i++) + tempelements.Append (elements.Get(i)); + } + + lpoints.SetSize (noldlp); + llines.SetSize (noldll); + dellines.SetSize (0); + elements.SetSize (0); + ok = 0; + + } + + + npok = rule->GetNOldP(); + incnpok = 0; + } + } + + nlok = rule->GetNOldL(); + + lused.Set (lmap.Get(nlok), 0); + + for (j = 1; j <= 2; j++) + { + refpi = rule->GetPointNr (nlok, j); + pused.Elem(pmap.Get(refpi))--; + + if (pused.Get(pmap.Get(refpi)) == 0) + { + pmap.Set(refpi, 0); + } + } + } + } + } + + + if (found) + { + for (i = 0; i < tempnewpoints.Size(); i++) + lpoints.Append (tempnewpoints[i]); + for (i = 0; i < tempnewlines.Size(); i++) + llines.Append (tempnewlines[i]); + for (i = 0; i < tempdellines.Size(); i++) + dellines.Append (tempdellines[i]); + for (i = 0; i < tempelements.Size(); i++) + elements.Append (tempelements[i]); + } + + + return found; +} + + + + + +} diff --git a/contrib/Netgen/libsrc/meshing/ruler2.hpp b/contrib/Netgen/libsrc/meshing/ruler2.hpp new file mode 100644 index 0000000000..4ef855d4ec --- /dev/null +++ b/contrib/Netgen/libsrc/meshing/ruler2.hpp @@ -0,0 +1,166 @@ +#ifndef FILE_NETRULE +#define FILE_NETRULE + +/// +class netrule +{ +private: + /// + typedef struct tf + { float f1, f2, f3; } threefloat; + + class threeint + { + public: int i1, i2, i3; + threeint() { } + threeint(int ai1, int ai2, int ai3) + { i1 = ai1; i2 = ai2; i3 = ai3; } + }; + + + /// + int quality; + /// + char * name; + /// + ARRAY<Point2d> points; + /// + ARRAY<INDEX_2> lines; + /// + ARRAY<Point2d> freezone, freezonelimit; + /// + ARRAY<Point2d> transfreezone; + + /// + ARRAY<int> dellines; + /// + ARRAY<Element2d> elements; + /// + ARRAY<threefloat> tolerances, linetolerances; + /// + ARRAY<threeint> orientations; + /// + DenseMatrix oldutonewu, oldutofreearea, oldutofreearealimit; + /// + ARRAY<DenseMatrix*> oldutofreearea_i; + /// + MatrixFixWidth<3> freesetinequ; + + /// + ARRAY<Vec2d> linevecs; + + /// + int noldp, noldl; + /// + float fzminx, fzmaxx, fzminy, fzmaxy; + + /// topological distance of line to base element + ARRAY<int> lnearness; + +public: + + /// + netrule (); + /// + ~netrule(); + + /// + int GetNP () const { return points.Size(); } + /// + int GetNL () const { return lines.Size(); } + /// + int GetNE () const { return elements.Size(); } + /// + int GetNOldP () const { return noldp; } + /// + int GetNOldL () const { return noldl; } + /// + int GetNDelL () const { return dellines.Size(); } + /// + int GetNOrientations () const { return orientations.Size(); } + /// + int GetQuality () const { return quality; } + /// + int GetLNearness (int li) const { return lnearness.Get(li); } + + /// + const Point2d & GetPoint (int i) const { return points.Get(i); } + /// + const INDEX_2 & GetLine (int i) const { return lines.Get(i); } + /// + const Element2d & GetElement (int i) const { return elements.Get(i); } + /// + const threeint & GetOrientation (int i) const { return orientations.Get(i); } + /// + int GetDelLine (int i) const { return dellines.Get(i); } + + /// + void GetFreeZone (ARRAY<Point2d> & afreearea); + /// + + double CalcPointDist (int pi, const Point2d & p) const + { + double dx = p.X() - points.Get(pi).X(); + double dy = p.Y() - points.Get(pi).Y(); + const threefloat * tf = &tolerances.Get(pi); + return tf->f1 * dx * dx + tf->f2 * dx * dy + tf->f3 * dy * dy; + } + + /// + float CalcLineError (int li, const Vec2d & v) const; + + /// + void SetFreeZoneTransformation (const Vector & u, int tolclass); + + /// + bool IsInFreeZone (const Point2d & p) const + { + if (p.X() < fzminx || p.X() > fzmaxx || + p.Y() < fzminy || p.Y() > fzmaxy) return 0; + + for (int i = 0; i < transfreezone.Size(); i++) + { + if (freesetinequ(i, 0) * p.X() + + freesetinequ(i, 1) * p.Y() + + freesetinequ(i, 2) > 0) return 0; + } + return 1; + } + + /// + int IsLineInFreeZone (const Point2d & p1, const Point2d & p2) const + { + if (p1.X() > fzmaxx && p2.X() > fzmaxx || + p1.X() < fzminx && p2.X() < fzminx || + p1.Y() > fzmaxy && p2.Y() > fzmaxy || + p1.Y() < fzminy && p2.Y() < fzminy) return 0; + return IsLineInFreeZone2 (p1, p2); + } + /// + int IsLineInFreeZone2 (const Point2d & p1, const Point2d & p2) const; + /// + int ConvexFreeZone () const; + /// + const ARRAY<Point2d> & GetTransFreeZone () { return transfreezone; } + + /// + int GetPointNr (int ln, int endp) const { return lines.Get(ln).I(endp); } + + /// + const DenseMatrix & GetOldUToNewU () const { return oldutonewu; } + /// + const DenseMatrix & GetOldUToFreeArea () const { return oldutofreearea; } + /// + const char * Name () const { return name; } + + /// + void LoadRule (istream & ist); +}; + + + +/** Draws 2D rules. + Visual testing of 2D meshing rules */ +extern void DrawRules (); +#endif + diff --git a/contrib/Netgen/libsrc/meshing/ruler3.cpp b/contrib/Netgen/libsrc/meshing/ruler3.cpp new file mode 100644 index 0000000000..48ba5bc465 --- /dev/null +++ b/contrib/Netgen/libsrc/meshing/ruler3.cpp @@ -0,0 +1,1176 @@ +#include <mystdlib.h> +#include "meshing.hpp" + +// #define MARK +// #include <prof.h> + +namespace netgen +{ +extern double minother; +extern double minwithoutother; + + +static double CalcElementBadness (const ARRAY<Point3d> & points, + const Element & elem) +{ + double vol, l, l4, l5, l6; + if (elem.GetNP() != 4) + { + if (elem.GetNP() == 5) + { + double z = points.Get(elem.PNum(5)).Z(); + if (z > -1e-8) return 1e8; + return (-1 / z) - z; // - 2; + } + return 0; + } + + Vec3d v1 = points.Get(elem.PNum(2)) - points.Get(elem.PNum(1)); + Vec3d v2 = points.Get(elem.PNum(3)) - points.Get(elem.PNum(1)); + Vec3d v3 = points.Get(elem.PNum(4)) - points.Get(elem.PNum(1)); + + vol = - (Cross (v1, v2) * v3); + l4 = Dist (points.Get(elem.PNum(2)), points.Get(elem.PNum(3))); + l5 = Dist (points.Get(elem.PNum(2)), points.Get(elem.PNum(4))); + l6 = Dist (points.Get(elem.PNum(3)), points.Get(elem.PNum(4))); + + l = v1.Length() + v2.Length() + v3.Length() + l4 + l5 + l6; + + // testout << "vol = " << vol << " l = " << l << endl; + if (vol < 1e-8) return 1e10; + // (*testout) << "l^3/vol = " << (l*l*l / vol) << endl; + + double err = pow (l*l*l/vol, 1.0/3.0) / 12; + return err; +} + + + + + + +int Meshing3 :: ApplyRules +( + ARRAY<Point3d> & lpoints, // in: local points, out: old+new local points + ARRAY<int> & allowpoint, // in: 1 .. it is allowed to use pointi + ARRAY<Element2d> & lfaces, // in: local faces, out: old+new local faces + INDEX lfacesplit, // for local faces in outer radius + INDEX_2_HASHTABLE<int> & connectedpairs, // connected pairs for prism-meshing + ARRAY<Element> & elements, // out: new elements + ARRAY<INDEX> & delfaces, // out: face indices of faces to delete + int tolerance, // quality class: 1 best + double sloppy, // quality strength + int rotind1, // how to rotate base element + float & retminerr // element error + ) + +{ + int i, j, k, ri, nfok, npok, incnpok, refpi, locpi, locfi, locfr; + int hi, minn, hpi; + float hf, err, minerr, teterr, minteterr; + char ok, found, hc; + vnetrule * rule; + Vector oldu, newu, newu1, newu2, allp; + Vec3d ui; + Point3d np; + int oldnp, noldlp, noldlf; + const Element2d * locface = NULL; + int loktestmode; + + static ARRAY<int> pused; // point is already mapped + static ARRAY<int> fused; // face is already mapped + static ARRAY<int> pmap; // map of reference point to local point + static ARRAY<int> pfixed; // ??? + static ARRAY<int> fmapi; // face in reference is mapped to face nr ... + static ARRAY<int> fmapr; // face in reference is rotated to map + static ARRAY<Point3d> transfreezone; // transformed free-zone + static INDEX cnt = 0; + INDEX_2_HASHTABLE<int> ledges(lfaces.Size()); // edges in local environment + + static ARRAY<Point3d> tempnewpoints; + static ARRAY<Element2d> tempnewfaces; + static ARRAY<int> tempdelfaces; + static ARRAY<Element> tempelements; + static ARRAY<Box3d> triboxes; // bounding boxes of local faces + + + static ARRAY<int> pnearness; + static ARRAY<int> fnearness; + + cnt++; + + delfaces.SetSize (0); + elements.SetSize (0); + + + // determine topological distance of faces and points to + // base element + + + pnearness.SetSize (lpoints.Size()); + fnearness.SetSize (lfacesplit); + + for (i = 1; i <= pnearness.Size(); i++) + pnearness.Set(i, INT_MAX/10); + + for (j = 1; j <= lfaces.Get(1).GetNP(); j++) + pnearness.Set(lfaces.Get(1).PNum(j), 0); + + + // MARK(appl1); + do + { + ok = 1; + + for (i = 1; i <= lfacesplit; i++) + { + const Element2d & hface = lfaces.Get(i); + + minn = INT_MAX-1; + for (j = 1; j <= hface.GetNP(); j++) + { + hi = pnearness.Get(hface.PNum(j)); + if (hi < minn) minn = hi; + } + + for (j = 1; j <= hface.GetNP(); j++) + { + hpi = hface.PNum(j); + if (pnearness.Get(hpi) > minn+1) + { + ok = 0; + pnearness.Set(hpi, minn+1); + } + } + } + + for (i = 1; i <= connectedpairs.GetNBags(); i++) + for (j = 1; j <= connectedpairs.GetBagSize(i); j++) + { + INDEX_2 edge; + int val; + connectedpairs.GetData (i, j, edge, val); + + + if (edge.I1() > pnearness.Size() || + edge.I2() > pnearness.Size() || + edge.I1() < 1 || + edge.I2() < 1) + { + cerr << "pair out of range" << endl; + exit (1); + } + + if (pnearness.Get(edge.I1()) > + pnearness.Get(edge.I2()) + 1) + { + ; + ok = 0; + pnearness.Elem(edge.I1()) = + pnearness.Get(edge.I2()) + 1; + } + if (pnearness.Get(edge.I2()) > + pnearness.Get(edge.I1()) + 1) + { + ; + ok = 0; + pnearness.Elem(edge.I2()) = + pnearness.Get(edge.I1()) + 1; + } + } + } + while (!ok); + + + for (i = 1; i <= fnearness.Size(); i++) + { + fnearness.Set(i, 0); + for (j = 1; j <= lfaces.Get(i).GetNP(); j++) + fnearness.Elem(i) += pnearness.Get(lfaces.Get(i).PNum(j)); + } + + + // MARK(appl2); + + // find bounding boxes of faces + + triboxes.SetSize (lfaces.Size()); + for (i = 1; i <= lfaces.Size(); i++) + { + const Element2d & face = lfaces.Get(i); + triboxes.Elem(i).SetPoint (lpoints.Get(face.PNum(1))); + for (j = 2; j <= face.GetNP(); j++) + triboxes.Elem(i).AddPoint (lpoints.Get(face.PNum(j))); + } + + // MARK(appl3); + + /* + for (j = 1; j <= lfacesplit; j++) + for (k = 1; k <= lfaces.Get(j).GetNP(); k++) + { + INDEX_2 i2; + i2.I1() = lfaces.Get(j).PNumMod(k); + i2.I2() = lfaces.Get(j).PNumMod(k+1); + i2.Sort(); + ledges.Set (i2, 1); + } + */ + + for (j = 1; j <= lfacesplit; j++) + { + const Element2d & face = lfaces.Get(j); + int newp, oldp; + + newp = face.PNum(face.GetNP()); + for (k = 1; k <= face.GetNP(); k++) + { + oldp = newp; + newp = face.PNum(k); + + INDEX_2 i2(oldp, newp); + i2.Sort(); + ledges.Set (i2, 1); + } + } + + + pused.SetSize (lpoints.Size()); + fused.SetSize (lfaces.Size()); + + + + found = 0; + minerr = tolfak * tolerance * tolerance; + minteterr = sloppy * tolerance; + + if (testmode) + (*testout) << "cnt = " << cnt << " class = " << tolerance << endl; + + + // check each rule: + + // MARK(applyml); + + for (ri = 1; ri <= rules.Size(); ri++) + { + sprintf (problems.Elem(ri), ""); + + rule = rules.Get(ri); + + if (rule->GetNP(1) != lfaces.Get(1).GetNP()) + continue; + + if (rule->GetQuality() > tolerance) + { + if (testmode) + sprintf (problems.Elem(ri), "Quality not ok"); + continue; + } + + if (testmode) + sprintf (problems.Elem(ri), "no mapping found"); + + loktestmode = testmode || rule->TestFlag ('t'); + /* + if (tolerance > 8) + loktestmode = 1; + */ + + if (loktestmode) + (*testout) << "Rule " << ri << " = " << rule->Name() << endl; + + pmap.SetSize (rule->GetNP()); + fmapi.SetSize (rule->GetNF()); + fmapr.SetSize (rule->GetNF()); + + for (i = 1; i <= lfaces.Size(); i++) + fused.Set (i, 0); + for (i = 1; i <= lpoints.Size(); i++) + pused.Set (i, 0); + for (i = 1; i <= pmap.Size(); i++) + pmap.Set(i, 0); + for (i = 1; i <= fmapi.Size(); i++) + fmapi.Set(i, 0); + for (i = 1; i <= fmapr.Size(); i++) + fmapr.Set(i, rule->GetNP(i)); + + fused.Set (1, 1); + + fmapi.Set (1, 1); + fmapr.Set (1, rotind1); + + + for (j = 1; j <= lfaces.Get(1).GetNP(); j++) + { + locpi = lfaces.Get(1).PNumMod (j+rotind1); + pmap.Set (rule->GetPointNr (1, j), locpi); + pused.Elem(locpi)++; + } + + + + /* + map all faces + nfok .. first nfok-1 faces are mapped properly + */ + + nfok = 2; + while (nfok >= 2) + { + + if (nfok <= rule->GetNOldF()) + { + // not all faces mapped + + ok = 0; + locfi = fmapi.Get(nfok); + locfr = fmapr.Get(nfok); + + int actfnp = rule->GetNP(nfok); + + while (!ok) + { + locfr++; + if (locfr == actfnp + 1) + { + locfr = 1; + locfi++; + if (locfi > lfacesplit) break; + } + + + if (fnearness.Get(locfi) > rule->GetFNearness (nfok) || + fused.Get(locfi) || + actfnp != lfaces.Get(locfi).GetNP() ) + { + // face not feasible in any rotation + + locfr = actfnp; + } + else + { + + ok = 1; + + locface = &lfaces.Get(locfi); + + + // reference point already mapped differently ? + for (j = 1; j <= actfnp && ok; j++) + { + locpi = pmap.Get(rule->GetPointNr (nfok, j)); + + if (locpi && locpi != locface->PNumMod(j+locfr)) + ok = 0; + } + + // local point already used or point outside tolerance ? + for (j = 1; j <= actfnp && ok; j++) + { + refpi = rule->GetPointNr (nfok, j); + + if (pmap.Get(refpi) == 0) + { + locpi = locface->PNumMod (j + locfr); + + if (pused.Get(locpi)) + ok = 0; + else + { + const Point3d & lp = lpoints.Get(locpi); + const Point3d & rp = rule->GetPoint(refpi); + + if ( Dist2 (lp, rp) * rule->PointDistFactor(refpi) > minerr) + ok = 0; + } + } + } + } + } + + + if (ok) + { + // map face nfok + + fmapi.Set (nfok, locfi); + fmapr.Set (nfok, locfr); + fused.Set (locfi, 1); + + for (j = 1; j <= rule->GetNP (nfok); j++) + { + locpi = locface->PNumMod(j+locfr); + + if (rule->GetPointNr (nfok, j) <= 3 && + pmap.Get(rule->GetPointNr(nfok, j)) != locpi) + (*testout) << "change face1 point, mark1" << endl; + + pmap.Set(rule->GetPointNr (nfok, j), locpi); + pused.Elem(locpi)++; + } + + nfok++; + } + else + { + // backtrack one face + fmapi.Set (nfok, 0); + fmapr.Set (nfok, rule->GetNP(nfok)); + nfok--; + + fused.Set (fmapi.Get(nfok), 0); + for (j = 1; j <= rule->GetNP (nfok); j++) + { + refpi = rule->GetPointNr (nfok, j); + pused.Elem(pmap.Get(refpi))--; + + if (pused.Get(pmap.Get(refpi)) == 0) + { + pmap.Set(refpi, 0); + } + } + } + } + + else + + { + + // all faces are mapped + // now map all isolated points: + + if (loktestmode) + { + (*testout) << "Faces Ok" << endl; + sprintf (problems.Elem(ri), "Faces Ok"); + } + + npok = 1; + incnpok = 1; + + pfixed.SetSize (pmap.Size()); + for (i = 1; i <= pmap.Size(); i++) + pfixed.Set(i, (pmap.Get(i) != 0) ); + + while (npok >= 1) + { + + if (npok <= rule->GetNOldP()) + { + + if (pfixed.Get(npok)) + + { + if (incnpok) + npok++; + else + npok--; + } + + else + + { + locpi = pmap.Elem(npok); + ok = 0; + + if (locpi) + pused.Elem(locpi)--; + + while (!ok && locpi < lpoints.Size()) + { + ok = 1; + locpi++; + + if (pused.Get(locpi) || !allowpoint.Get(locpi) || + pnearness.Get(locpi) > rule->GetPNearness(npok)) + { + ok = 0; + } + else + { + const Point3d & lp = lpoints.Get(locpi); + const Point3d & rp = rule->GetPoint(npok); + + if ( Dist2 (lp, rp) * rule->PointDistFactor(npok) > minerr) + ok = 0; + } + } + + + if (ok) + { + pmap.Set (npok, locpi); + + if (npok <= 3) + (*testout) << "set face1 point, mark3" << endl; + + pused.Elem(locpi)++; + npok++; + incnpok = 1; + } + + else + + { + pmap.Set (npok, 0); + + if (npok <= 3) + (*testout) << "set face1 point, mark4" << endl; + + npok--; + incnpok = 0; + } + } + } + + else + + { + + // all points are mapped + + if (loktestmode) + { + (*testout) << "Mapping found!!: Rule " << rule->Name() << endl; + for (i = 1; i <= pmap.Size(); i++) + (*testout) << pmap.Get(i) << " "; + (*testout) << endl; + sprintf (problems.Elem(ri), "mapping found"); + (*testout) << rule->GetNP(1) << " = " << lfaces.Get(1).GetNP() << endl; + } + + ok = 1; + + + // check mapedges: + + for (i = 1; i <= rule->GetNEd(); i++) + { + int i1, i2; + i1 = pmap.Get(rule->GetEdge(i).i1); + i2 = pmap.Get(rule->GetEdge(i).i2); + + INDEX_2 in2(i1, i2); + in2.Sort(); + if (!ledges.Used (in2)) ok = 0; + } + + + // check prism edges: + for (i = 1; i <= rule->GetNE(); i++) + { + const Element & el = rule->GetElement (i); + if (el.GetType() == PRISM) + { + for (j = 1; j <= 3; j++) + { + int i1, i2; + i1 = pmap.Get(el.PNum(j)); + i2 = pmap.Get(el.PNum(j+3)); + + INDEX_2 in2(i1, i2); + in2.Sort(); + if (!connectedpairs.Used (in2)) ok = 0; + } + } + if (el.GetType() == PYRAMID) + { + if (loktestmode) + (*testout) << "map pyramid, rule = " << rule->Name() << endl; + for (j = 1; j <= 2; j++) + { + INDEX_2 in2; + if (j == 1) + { + in2.I1() = pmap.Get(el.PNum(2)); + in2.I2() = pmap.Get(el.PNum(3)); + } + else + { + in2.I1() = pmap.Get(el.PNum(1)); + in2.I2() = pmap.Get(el.PNum(4)); + } + in2.Sort(); + if (!connectedpairs.Used (in2)) + { + ok = 0; + if (loktestmode) + (*testout) << "no pair" << endl; + } + } + } + + } + + + + for (i = rule->GetNOldF() + 1; i <= rule->GetNF(); i++) + fmapi.Set(i, 0); + + + if (ok) + { + foundmap.Elem(ri)++; + } + + + + + // deviation of existing points + + oldu.SetSize (3 * rule->GetNOldP()); + newu.SetSize (3 * (rule->GetNP() - rule->GetNOldP())); + allp.SetSize (3 * rule->GetNP()); + + for (i = 1; i <= rule->GetNOldP(); i++) + { + const Point3d & lp = lpoints.Get(pmap.Get(i)); + const Point3d & rp = rule->GetPoint(i); + oldu.Set (3*i-2, lp.X()-rp.X()); + oldu.Set (3*i-1, lp.Y()-rp.Y()); + oldu.Set (3*i , lp.Z()-rp.Z()); + + allp.Set (3*i-2, lp.X()); + allp.Set (3*i-1, lp.Y()); + allp.Set (3*i , lp.Z()); + } + + if (rule->GetNP() > rule->GetNOldP()) + { + newu.SetSize (rule->GetOldUToNewU().Height()); + rule->GetOldUToNewU().Mult (oldu, newu); + } + + // int idiff = 3 * (rule->GetNP()-rule->GetNOldP()); + int idiff = 3 * rule->GetNOldP(); + for (i = rule->GetNOldP()+1; i <= rule->GetNP(); i++) + { + const Point3d & rp = rule->GetPoint(i); + allp.Set (3*i-2, rp.X() + newu.Get(3*i-2 - idiff)); + allp.Set (3*i-1, rp.Y() + newu.Get(3*i-1 - idiff)); + allp.Set (3*i , rp.Z() + newu.Get(3*i - idiff)); + } + + rule->SetFreeZoneTransformation (allp, + tolerance + int(sloppy)); + + if (!rule->ConvexFreeZone()) + { + ok = 0; + sprintf (problems.Elem(ri), "Freezone not convex"); + + if (loktestmode) + (*testout) << "Freezone not convex" << endl; + } + + if (loktestmode) + { + const ARRAY<Point3d> & fz = rule->GetTransFreeZone(); + (*testout) << "Freezone: " << endl; + for (i = 1; i <= fz.Size(); i++) + (*testout) << fz.Get(i) << endl; + } + + + // check freezone: + + for (i = 1; i <= lpoints.Size(); i++) + { + if ( !pused.Get(i) ) + { + const Point3d & lp = lpoints.Get(i); + + if (rule->fzbox.IsIn (lp)) + { + if (rule->IsInFreeZone(lp)) + { + if (loktestmode) + { + (*testout) << "Point " << i + << " in Freezone" << endl; + sprintf (problems.Elem(ri), + "locpoint %d in Freezone", i); + } + ok = 0; + break; + } + } + } + } + + for (i = 1; i <= lfaces.Size() && ok; i++) + { + static ARRAY<int> lpi(4); + + if (!fused.Get(i)) + { + int triin; + const Element2d & lfacei = lfaces.Get(i); + + if (!triboxes.Elem(i).Intersect (rule->fzbox)) + triin = 0; + else + { + int li, lj; + for (li = 1; li <= lfacei.GetNP(); li++) + { + int lpii = 0; + int pi = lfacei.PNum(li); + for (lj = 1; lj <= rule->GetNOldP(); lj++) + if (pmap.Get(lj) == pi) + lpii = lj; + lpi.Elem(li) = lpii; + } + + + if (lfacei.GetNP() == 3) + { + triin = rule->IsTriangleInFreeZone + ( + lpoints.Get(lfacei.PNum(1)), + lpoints.Get(lfacei.PNum(2)), + lpoints.Get(lfacei.PNum(3)), lpi, 1 + ); + } + else + { + triin = rule->IsQuadInFreeZone + ( + lpoints.Get(lfacei.PNum(1)), + lpoints.Get(lfacei.PNum(2)), + lpoints.Get(lfacei.PNum(3)), + lpoints.Get(lfacei.PNum(4)), + lpi, 1 + ); + } + } + + + if (triin == -1) + { + ok = 0; + } + + if (triin == 1) + { +#ifdef TEST_JS + ok = 0; + + if (loktestmode) + { + (*testout) << "El with " << lfaces.Get(i).GetNP() << " points in freezone: " + << lfaces.Get(i).PNum(1) << " - " + << lfaces.Get(i).PNum(2) << " - " + << lfaces.Get(i).PNum(3) << " - " + << lfaces.Get(i).PNum(4) << endl; + for (int lj = 1; lj <= lfaces.Get(i).GetNP(); lj++) + (*testout) << lpoints.Get(lfaces.Get(i).PNum(lj)) << " "; + + (*testout) << endl; + + sprintf (problems.Elem(ri), "triangle (%d, %d, %d) in Freezone", + lfaces.Get(i).PNum(1), lfaces.Get(i).PNum(2), + lfaces.Get(i).PNum(3)); + } +#else + if (loktestmode) + { + if (lfacei.GetNP() == 3) + { + (*testout) << "Triangle in freezone: " + << lfacei.PNum(1) << " - " + << lfacei.PNum(2) << " - " + << lfacei.PNum(3) + << ", or " + << lpoints.Get(lfacei.PNum(1)) << " - " + << lpoints.Get(lfacei.PNum(2)) << " - " + << lpoints.Get(lfacei.PNum(3)) + << endl; + (*testout) << "lpi = " << lpi.Get(1) << ", " + << lpi.Get(2) << ", " << lpi.Get(3) << endl; + } + else + (*testout) << "Quad in freezone: " + << lfacei.PNum(1) << " - " + << lfacei.PNum(2) << " - " + << lfacei.PNum(3) << " - " + << lfacei.PNum(4) + << ", or " + << lpoints.Get(lfacei.PNum(1)) << " - " + << lpoints.Get(lfacei.PNum(2)) << " - " + << lpoints.Get(lfacei.PNum(3)) << " - " + << lpoints.Get(lfacei.PNum(4)) + << endl; + + sprintf (problems.Elem(ri), "triangle (%d, %d, %d) in Freezone", + int(lfaces.Get(i).PNum(1)), + int(lfaces.Get(i).PNum(2)), + int(lfaces.Get(i).PNum(3))); + } + + hc = 0; + for (k = rule->GetNOldF() + 1; k <= rule->GetNF(); k++) + { + if (rule->GetPointNr(k, 1) <= rule->GetNOldP() && + rule->GetPointNr(k, 2) <= rule->GetNOldP() && + rule->GetPointNr(k, 3) <= rule->GetNOldP()) + { + for (j = 1; j <= 3; j++) + if (lfaces.Get(i).PNumMod(j ) == pmap.Get(rule->GetPointNr(k, 1)) && + lfaces.Get(i).PNumMod(j+1) == pmap.Get(rule->GetPointNr(k, 3)) && + lfaces.Get(i).PNumMod(j+2) == pmap.Get(rule->GetPointNr(k, 2))) + { + fmapi.Elem(k) = i; + hc = 1; + + + // (*testout) << "found from other side: " +// << rule->Name() +// << " ( " << pmap.Get (rule->GetPointNr(k, 1)) +// << " - " << pmap.Get (rule->GetPointNr(k, 2)) +// << " - " << pmap.Get (rule->GetPointNr(k, 3)) << " ) " +// << endl; + + strcpy (problems.Elem(ri), "other"); + } + } + } + + if (!hc) + { + if (loktestmode) + { + (*testout) << "Triangle in freezone: " + << lfaces.Get(i).PNum(1) << " - " + << lfaces.Get(i).PNum(2) << " - " + << lfaces.Get(i).PNum(3) << endl; + + sprintf (problems.Elem(ri), "triangle (%d, %d, %d) in Freezone", + int (lfaces.Get(i).PNum(1)), + int (lfaces.Get(i).PNum(2)), + int (lfaces.Get(i).PNum(3))); + } + ok = 0; + } +#endif + } + } + + } + + + if (ok) + { + err = 0; + for (i = 1; i <= rule->GetNOldP(); i++) + { + hf = rule->CalcPointDist (i, lpoints.Get(pmap.Get(i))); + if (hf > err) err = hf; + } + + + if (loktestmode) + { + (*testout) << "Rule ok" << endl; + sprintf (problems.Elem(ri), "Rule ok, err = %f", err); + } + + + // MARK(m2); + // newu = rule->GetOldUToNewU() * oldu; + + // set new points: + + oldnp = rule->GetNOldP(); + noldlp = lpoints.Size(); + noldlf = lfaces.Size(); + + + for (i = oldnp + 1; i <= rule->GetNP(); i++) + { + np = rule->GetPoint(i); + np.X() += newu.Elem (3 * (i-oldnp) - 2); + np.Y() += newu.Elem (3 * (i-oldnp) - 1); + np.Z() += newu.Elem (3 * (i-oldnp)); + + pmap.Elem(i) = lpoints.Append (np); + } + + // Set new Faces: + + for (i = rule->GetNOldF() + 1; i <= rule->GetNF(); i++) + if (!fmapi.Get(i)) + { + Element2d nface(rule->GetNP(i)); + for (j = 1; j <= nface.GetNP(); j++) + nface.PNum(j) = pmap.Get(rule->GetPointNr (i, j)); + + lfaces.Append (nface); + } + + + // Delete old Faces: + + for (i = 1; i <= rule->GetNDelF(); i++) + delfaces.Append (fmapi.Get(rule->GetDelFace(i))); + for (i = rule->GetNOldF()+1; i <= rule->GetNF(); i++) + if (fmapi.Get(i)) + { + delfaces.Append (fmapi.Get(i)); + fmapi.Elem(i) = 0; + } + + + // check orientation + for (i = 1; i <= rule->GetNO() && ok; i++) + { + const fourint * fouri; + + fouri = &rule->GetOrientation(i); + Vec3d v1 (lpoints.Get(pmap.Get(fouri->i1)), + lpoints.Get(pmap.Get(fouri->i2))); + Vec3d v2 (lpoints.Get(pmap.Get(fouri->i1)), + lpoints.Get(pmap.Get(fouri->i3))); + Vec3d v3 (lpoints.Get(pmap.Get(fouri->i1)), + lpoints.Get(pmap.Get(fouri->i4))); + + Vec3d n; + Cross (v1, v2, n); + if (n * v3 > -1e-7) + { + if (loktestmode) + { + sprintf (problems.Elem(ri), "Orientation wrong"); + (*testout) << "Orientation wrong" << endl; + } + ok = 0; + } + } + + + + // new points in free-zone ? + for (i = rule->GetNOldP() + 1; i <= rule->GetNP() && ok; i++) + if (!rule->IsInFreeZone (lpoints.Get(pmap.Get(i)))) + { + if (loktestmode) + { + (*testout) << "Newpoint " << lpoints.Get(pmap.Get(i)) + << " outside convex hull" << endl; + sprintf (problems.Elem(ri), "newpoint outside convex hull"); + } + ok = 0; + + } + + // insert new elements + + for (i = 1; i <= rule->GetNE(); i++) + { + elements.Append (rule->GetElement(i)); + for (j = 1; j <= elements.Get(i).NP(); j++) + elements.Elem(i).PNum(j) = pmap.Get(elements.Get(i).PNum(j)); + } + + + // Calculate Element badness + + teterr = 0; + for (i = 1; i <= elements.Size(); i++) + { + hf = CalcElementBadness (lpoints, elements.Get(i)); + if (hf > teterr) teterr = hf; + } + + /* + // keine gute Erfahrung am 25.1.2000, js + if (ok && teterr < 100 && + (rule->TestFlag('b') || tolerance > 10) ) + { + (*mycout) << "Reset teterr " + << rule->Name() + << " err = " << teterr + << endl; + teterr = 1; + } + */ + + // compare edgelength + if (rule->TestFlag('l')) + { + double oldlen = 0; + double newlen = 0; + + for (i = 1; i <= rule->GetNDelF(); i++) + { + const Element2d & face = + rule->GetFace (rule->GetDelFace(i)); + for (j = 1; j <= 3; j++) + { + const Point3d & p1 = + lpoints.Get(pmap.Get(face.PNumMod(j))); + const Point3d & p2 = + lpoints.Get(pmap.Get(face.PNumMod(j+1))); + oldlen += Dist(p1, p2); + } + } + + for (i = rule->GetNOldF()+1; i <= rule->GetNF(); i++) + { + const Element2d & face = rule->GetFace (i); + for (j = 1; j <= 3; j++) + { + const Point3d & p1 = + lpoints.Get(pmap.Get(face.PNumMod(j))); + const Point3d & p2 = + lpoints.Get(pmap.Get(face.PNumMod(j+1))); + newlen += Dist(p1, p2); + } + } + + if (oldlen < newlen) + { + ok = 0; + if (loktestmode) + sprintf (problems.Elem(ri), "oldlen < newlen"); + } + } + + + if (loktestmode) + (*testout) << "ok = " << int(ok) + << "teterr = " << teterr + << "minteterr = " << minteterr << endl; + + + if (ok && teterr < tolerance) + { + canuse.Elem(ri) ++; + /* + (*testout) << "can use rule " << rule->Name() + << ", err = " << teterr << endl; + for (i = 1; i <= pmap.Size(); i++) + (*testout) << pmap.Get(i) << " "; + (*testout) << endl; + */ + + if (strcmp (problems.Elem(ri), "other") == 0) + { + if (teterr < minother) + minother = teterr; + } + else + { + if (teterr < minwithoutother) + minwithoutother = teterr; + } + } + + if (ok && teterr < minteterr) + { + + if (loktestmode) + (*testout) << "use rule" << endl; + + found = ri; + minteterr = teterr; + + if (testmode) + { + for (i = 1; i <= rule->GetNOldP(); i++) + { + (*testout) << "P" << i << ": Ref: " + << rule->GetPoint (i) << " is: " + << lpoints.Get(pmap.Get(i)) << endl; + } + } + + tempnewpoints.SetSize (0); + for (i = noldlp+1; i <= lpoints.Size(); i++) + tempnewpoints.Append (lpoints.Get(i)); + + tempnewfaces.SetSize (0); + for (i = noldlf+1; i <= lfaces.Size(); i++) + tempnewfaces.Append (lfaces.Get(i)); + + tempdelfaces.SetSize (0); + for (i = 1; i <= delfaces.Size(); i++) + tempdelfaces.Append (delfaces.Get(i)); + + tempelements.SetSize (0); + for (i = 1; i <= elements.Size(); i++) + tempelements.Append (elements.Get(i)); + } + + lpoints.SetSize (noldlp); + lfaces.SetSize (noldlf); + delfaces.SetSize (0); + elements.SetSize (0); + } + + npok = rule->GetNOldP(); + incnpok = 0; + } + } + + nfok = rule->GetNOldF(); + + for (j = 1; j <= rule->GetNP (nfok); j++) + { + refpi = rule->GetPointNr (nfok, j); + pused.Elem(pmap.Get(refpi))--; + + if (pused.Get(pmap.Get(refpi)) == 0) + { + pmap.Set(refpi, 0); + } + } + + } + } + if (loktestmode) + (*testout) << "end rule" << endl; + } + + // (*testout) << "end" << endl; + + // if successfull, reload best choice + + if (found) + { + +#ifdef debug + // if face in advancing front ??? + for (i = 1; i <= tempnewfaces.Size(); i++) + { + hc = 1; + for (k = 1; k <= lfaces.Size() && hc; k++) + for (j = 1; j <= 3 && hc; j++) + if (tempnewfaces.Elem(i).PNumMod(j ) == lfaces.Get(k).PNum(1) && + tempnewfaces.Elem(i).PNumMod(j+1) == lfaces.Get(k).PNum(3) && + tempnewfaces.Elem(i).PNumMod(j+2) == lfaces.Get(k).PNum(2)) + { + tempdelfaces.Append(k); + tempnewfaces.Elem(i).PNum(1) = 0; + hc = 0; + cerr << "Ruler-reload necessary" << endl; + } + } +#endif + + for (i = 1; i <= tempnewpoints.Size(); i++) + lpoints.Append (tempnewpoints.Get(i)); + for (i = 1; i <= tempnewfaces.Size(); i++) + if (tempnewfaces.Get(i).PNum(1)) + lfaces.Append (tempnewfaces.Get(i)); + for (i = 1; i <= tempdelfaces.Size(); i++) + delfaces.Append (tempdelfaces.Get(i)); + for (i = 1; i <= tempelements.Size(); i++) + elements.Append (tempelements.Get(i)); + } + + retminerr = minerr; + return found; +} +} diff --git a/contrib/Netgen/libsrc/meshing/ruler3.hpp b/contrib/Netgen/libsrc/meshing/ruler3.hpp new file mode 100644 index 0000000000..483d83ed4e --- /dev/null +++ b/contrib/Netgen/libsrc/meshing/ruler3.hpp @@ -0,0 +1,210 @@ +#ifndef FILE_RULER3 +#define FILE_RULER3 + + +/** + 3D element generation rule. + */ +class vnetrule +{ +private: + /// rule is applicable for quality classes above this value + int quality; + /// name of rule + char * name; + /// point coordinates in reference position + ARRAY<Point3d> points; + /// old and new faces in reference numbering + ARRAY<Element2d> faces; + /// additional edges of rule + ARRAY<twoint> edges; + + /// points of freezone in reference coordinates + ARRAY<Point3d> freezone; + /// points of freezone in reference coordinates if tolcalss to infty + ARRAY<Point3d> freezonelimit; + /// point index, if point equal to mappoint, otherwise 0 + ARRAY<int> freezonepi; + /// faces of each convex part of freezone + ARRAY<ARRAY<threeint>*> freefaces; + /// set of points of each convex part of freezone + ARRAY<ARRAY<int>*> freesets; + /// points of transformed freezone + ARRAY<Point3d> transfreezone; + /// edges of each convex part of freezone + ARRAY<ARRAY<twoint>*> freeedges; + + /// face numbers to be deleted + ARRAY<int> delfaces; + /// elements to be generated + ARRAY<Element> elements; + /// tolerances for points and faces (used ??) + ARRAY<double> tolerances, linetolerances; + /// transformation matrix + DenseMatrix oldutonewu; + /// transformation matrix: deviation old point to dev. freezone + DenseMatrix * oldutofreezone; + /** transformation matrix: deviation old point to dev. freezone, + quality class to infinity */ + DenseMatrix * oldutofreezonelimit; + + // can be deleted: + // BaseMatrix *outf, *outfl; + + /** + a point is outside of convex part of freezone, + iff mat * (point, 1) >= 0 for each component (correct ?) + */ + ARRAY<DenseMatrix*> freefaceinequ; + /// + ARRAY<fourint> orientations; + /** + flags specified in rule-description file: + t .. test rule + */ + ARRAY<char> flags; + + /** + topological distance of face to base element + non-connected: > 100 (??) + */ + ARRAY<int> fnearness; + ARRAY<int> pnearness; + int maxpnearness; + + /// number of old points in rule + int noldp; + /// number of new poitns in rule + int noldf; + /// box containing free-zone +public: + // double fzminx, fzmaxx, fzminy, fzmaxy, fzminz, fzmaxz; + Box3d fzbox; + +public: + + /// + vnetrule (); + /// + ~vnetrule (); + /// + int GetNP () const { return points.Size(); } + /// + int GetNF () const { return faces.Size(); } + /// + int GetNE () const { return elements.Size(); } + /// + int GetNO () const { return orientations.Size(); } + /// + int GetNEd () const { return edges.Size(); } + /// + int GetNOldP () const { return noldp; } + /// + int GetNOldF () const { return noldf; } + /// + int GetNDelF () const { return delfaces.Size(); } + /// + int GetQuality () const { return quality; } + /// + int GetFNearness (int fi) const { return fnearness.Get(fi); } + /// + int GetPNearness (int pi) const { return pnearness.Get(pi); } + /// + int GetMaxPNearness () const { return maxpnearness; } + + + /// + const Point3d & GetPoint (int i) const { return points.Get(i); } + /// + const Element2d & GetFace (int i) const { return faces.Get(i); } + /// + const Element & GetElement (int i) const { return elements.Get(i); } + /// + const twoint & GetEdge (int i) const { return edges.Get(i); } + /// + int GetDelFace (int i) const { return delfaces.Get(i); } + /// + int IsDelFace (int fn) const; + + /// + float CalcPointDist (int pi, const Point3d & p) const; + /// + double PointDistFactor (int pi) const + { + return tolerances.Get(pi); + } + /// + void SetFreeZoneTransformation (const Vector & allp, + int tolclass); + /// + int IsInFreeZone (const Point3d & p) const; + /** + 0 not in free-zone + 1 in free-zone + -1 maybe + */ + int IsTriangleInFreeZone (const Point3d & p1, const Point3d & p2, + const Point3d & p3, const ARRAY<int> & pi, int newone); + /// + int IsQuadInFreeZone (const Point3d & p1, const Point3d & p2, + const Point3d & p3, const Point3d & p4, + const ARRAY<int> & pi, int newone); + /// + int IsTriangleInFreeSet (const Point3d & p1, const Point3d & p2, + const Point3d & p3, int fs, const ARRAY<int> & pi, int newone); + + /// + int IsQuadInFreeSet (const Point3d & p1, const Point3d & p2, + const Point3d & p3, const Point3d & p4, + int fs, const ARRAY<int> & pi, int newone); + + /// + int ConvexFreeZone () const; + + /// if t1 and t2 are neighbourtriangles, NTP returns the opposite Point of t1 in t2 + int NeighbourTrianglePoint (const threeint & t1, const threeint & t2) const; + /// + const Point3d & GetTransFreeZone (int i) { return transfreezone.Get(i); } + + /// + int GetNP (int fn) const + { return faces.Get(fn).GetNP(); } + /// + int GetPointNr (int fn, int endp) const + { return faces.Get(fn).PNum(endp); } + /// + int GetPointNrMod (int fn, int endp) const + { return faces.Get(fn).PNumMod(endp); } + /// + const fourint & GetOrientation (int i) { return orientations.Get(i); } + + /// + int TestFlag (char flag) const; + + /// + const DenseMatrix & GetOldUToNewU () const { return oldutonewu; } + // + // const DenseMatrix & GetOldUToFreeZone () const { return oldutofreezone; } + // + // const DenseMatrix & GetOldUToFreeZoneLimit () const + // { return oldutofreezonelimit; } + /// + const char * Name () const { return name; } + /// + void LoadRule (istream & ist); + + /// + const ARRAY<Point3d> & GetTransFreeZone () { return transfreezone; } + /// + int TestOk () const; + + /// + friend void TestRules (); + /// + // friend void Plot3DRule (const ROT3D & r, char key); +}; + + + +#endif + diff --git a/contrib/Netgen/libsrc/meshing/secondorder.cpp b/contrib/Netgen/libsrc/meshing/secondorder.cpp new file mode 100644 index 0000000000..d260eb20d7 --- /dev/null +++ b/contrib/Netgen/libsrc/meshing/secondorder.cpp @@ -0,0 +1,496 @@ +#include <mystdlib.h> +#include "meshing.hpp" + + +namespace netgen +{ + + + + Refinement :: Refinement () + { + ; + } + + Refinement :: ~Refinement () + { + ; + } + + void Refinement :: MakeSecondOrder (Mesh & mesh) + { + int nseg, nse, ne; + + mesh.ComputeNVertices(); + mesh.SetNP(mesh.GetNV()); + + INDEX_2_HASHTABLE<int> between(mesh.GetNP() + 5); + + + bool thinlayers = 0; + for (ElementIndex ei = 0; ei < mesh.GetNE(); ei++) + if (mesh[ei].GetType() == PRISM || + mesh[ei].GetType() == PRISM12) + thinlayers = 1; + + + nseg = mesh.GetNSeg(); + for (SegmentIndex si = 0; si < nseg; si++) + { + Segment & el = mesh.LineSegment(si); + + INDEX_2 i2 = INDEX_2::Sort (el.p1, el.p2); + + if (between.Used(i2)) + el.pmid = between.Get(i2); + else + { + Point3d pb; + EdgePointGeomInfo ngi; + PointBetween (mesh.Point (el.p1), + mesh.Point (el.p2), 0.5, + el.surfnr1, el.surfnr2, + el.epgeominfo[0], el.epgeominfo[1], + pb, ngi); + + el.pmid = mesh.AddPoint (pb); + between.Set (i2, el.pmid); + } + } + + // refine surface elements + nse = mesh.GetNSE(); + for (SurfaceElementIndex sei = 0; sei < nse; sei++) + { + int j; + const Element2d & el = mesh.SurfaceElement(sei); + + int onp; + + Element2d newel; + newel.SetIndex (el.GetIndex()); + + static int betw_trig[3][3] = + { { 1, 2, 3 }, + { 0, 2, 4 }, + { 0, 1, 5 } }; + static int betw_quad6[2][3] = + { { 0, 1, 4 }, + { 3, 2, 5 } }; + static int betw_quad8[4][3] = + { { 0, 1, 4 }, + { 3, 2, 5 }, + { 0, 3, 6 }, + { 1, 2, 7 } }; + int (*betw)[3]; + + switch (el.GetType()) + { + case TRIG: + case TRIG6: + { + betw = betw_trig; + newel.SetType (TRIG6); + onp = 3; + break; + } + case QUAD: + case QUAD6: + case QUAD8: + { + if (thinlayers) + { + betw = betw_quad6; + newel.SetType (QUAD6); + } + else + { + betw = betw_quad8; + newel.SetType (QUAD8); + } + onp = 4; + break; + } + default: + PrintSysError ("Unhandled element in secondorder:", int(el.GetType())); + } + + for (j = 0; j < onp; j++) + newel[j] = el[j]; + + int nnp = newel.GetNP(); + for (j = 0; j < nnp-onp; j++) + { + int pi1 = newel[betw[j][0]]; + int pi2 = newel[betw[j][1]]; + + INDEX_2 i2 = INDEX_2::Sort (pi1, pi2); + + if (between.Used(i2)) + newel[onp+j] = between.Get(i2); + else + { + Point3d pb; + PointGeomInfo newgi; + PointBetween (mesh.Point (pi1), + mesh.Point (pi2), 0.5, + mesh.GetFaceDescriptor(el.GetIndex ()).SurfNr(), + el.GeomInfoPi (betw[j][0]+1), + el.GeomInfoPi (betw[j][1]+1), + pb, newgi); + + newel[onp+j] = mesh.AddPoint (pb); + between.Set (i2, newel[onp+j]); + } + } + + mesh.SurfaceElement(sei) = newel; + } + + + // int i, j; + + + + // refine volume elements + ne = mesh.GetNE(); + for (int i = 1; i <= ne; i++) + { + int j; + const Element & el = mesh.VolumeElement(i); + int onp; + + Element newel; + newel.SetIndex (el.GetIndex()); + + static int betw_tet[6][3] = + { { 1, 2, 5 }, + { 1, 3, 6 }, + { 1, 4, 7 }, + { 2, 3, 8 }, + { 2, 4, 9 }, + { 3, 4, 10 } }; + static int betw_prism[6][3] = + { + { 1, 3, 7 }, + { 1, 2, 8 }, + { 2, 3, 9 }, + { 4, 6, 10 }, + { 4, 5, 11 }, + { 5, 6, 12 }, + }; + int (*betw)[3]; + + switch (el.GetType()) + { + case TET: + case TET10: + { + betw = betw_tet; + newel.SetType (TET10); + onp = 4; + break; + } + case PRISM: + case PRISM12: + { + betw = betw_prism; + newel.SetType (PRISM12); + onp = 6; + break; + } + default: + PrintSysError ("MakeSecondOrder, illegal vol type ", el.GetType()); + } + + + for (int j = 1; j <= onp; j++) + newel.PNum(j) = el.PNum(j); + int nnp = newel.GetNP(); + + for (int j = 0; j < nnp-onp; j++) + { + INDEX_2 i2(newel.PNum(betw[j][0]), + newel.PNum(betw[j][1])); + i2.Sort(); + + if (between.Used(i2)) + newel.PNum(onp+1+j) = between.Get(i2); + else + { + newel.PNum(onp+1+j) = mesh.AddPoint + (Center (mesh.Point(i2.I1()), + mesh.Point(i2.I2()))); + between.Set (i2, newel.PNum(onp+1+j)); + } + } + + mesh.VolumeElement (i) = newel; + } + + + // makes problems after linear mesh refinement, since + // 2nd order identifications are not removed + // update identification tables + for (int i = 1; i <= mesh.GetIdentifications().GetMaxNr(); i++) + { + ARRAY<int,PointIndex::BASE> identmap; + mesh.GetIdentifications().GetMap (i, identmap); + + for (INDEX_2_HASHTABLE<int>::Iterator it = between.Begin(); + it != between.End(); it++) + { + INDEX_2 i2; + int newpi; + between.GetData (it, i2, newpi); + INDEX_2 oi2(identmap.Get(i2.I1()), + identmap.Get(i2.I2())); + oi2.Sort(); + if (between.Used (oi2)) + { + int onewpi = between.Get(oi2); + mesh.GetIdentifications().Add (newpi, onewpi, i); + } + } + + /* + for (int j = 1; j <= between.GetNBags(); j++) + for (int k = 1; k <= between.GetBagSize(j); k++) + { + INDEX_2 i2; + int newpi; + between.GetData (j, k, i2, newpi); + INDEX_2 oi2(identmap.Get(i2.I1()), + identmap.Get(i2.I2())); + oi2.Sort(); + if (between.Used (oi2)) + { + int onewpi = between.Get(oi2); + mesh.GetIdentifications().Add (newpi, onewpi, i); + } + } + */ + } + + + // mesh.mglevels++; + int oldsize = mesh.mlbetweennodes.Size(); + mesh.mlbetweennodes.SetSize(mesh.GetNP()); + for (int i = oldsize; i < mesh.GetNP(); i++) + mesh.mlbetweennodes[i] = INDEX_2(0,0); + + /* + for (i = 1; i <= between.GetNBags(); i++) + for (j = 1; j <= between.GetBagSize(i); j++) + { + INDEX_2 oldp; + int newp; + between.GetData (i, j, oldp, newp); + mesh.mlbetweennodes.Elem(newp) = oldp; + } + */ + + for (INDEX_2_HASHTABLE<int>::Iterator it = between.Begin(); + it != between.End(); it++) + { + mesh.mlbetweennodes[between.GetData (it)] = between.GetHash(it); + } + + mesh.ComputeNVertices(); + + // ValidateSecondOrder (mesh); + } + + + void Refinement :: ValidateSecondOrder (Mesh & mesh) + { + PrintMessage (3, "Validate mesh"); + int np = mesh.GetNP(); + int ne = mesh.GetNE(); + // int i, j; + ARRAY<INDEX_2> parents(np); + + for (int i = 1; i <= np; i++) + parents.Elem(i) = INDEX_2(0,0); + + for (int i = 1; i <= ne; i++) + { + const Element & el = mesh.VolumeElement(i); + if (el.GetType() == TET10) + { + static int betweentab[6][3] = + { { 1, 2, 5 }, + { 1, 3, 6 }, + { 1, 4, 7 }, + { 2, 3, 8 }, + { 2, 4, 9 }, + { 3, 4, 10 } }; + for (int j = 0; j < 6; j++) + { + int f1 = el.PNum (betweentab[j][0]); + int f2 = el.PNum (betweentab[j][1]); + int son = el.PNum (betweentab[j][2]); + parents.Elem(son).I1() = f1; + parents.Elem(son).I2() = f2; + } + } + } + + ValidateRefinedMesh (mesh, parents); + } + + + void Refinement :: + ValidateRefinedMesh (Mesh & mesh, + ARRAY<INDEX_2> & parents) + { + // int i, j, k; + + // homotopy method + + int ne = mesh.GetNE(); + + int cnttrials = 100; + int wrongels = 0; + for (int i = 1; i <= ne; i++) + if (mesh.VolumeElement(i).CalcJacobianBadness (mesh.Points()) > 1e10) + { + wrongels++; + mesh.VolumeElement(i).flags.badel = 1; + } + else + mesh.VolumeElement(i).flags.badel = 0; + + double facok = 0; + double factry; + + BitArray illegalels(ne); + illegalels.Clear(); + + + if (wrongels) + { + cout << "WARNING: " << wrongels << " illegal element(s) found" << endl; + + int np = mesh.GetNP(); + ARRAY<Point3d> should(np); + ARRAY<Point3d> can(np); + + for (int i = 1; i <= np; i++) + { + should.Elem(i) = can.Elem(i) = mesh.Point(i); + } + + for (int i = 1; i <= parents.Size(); i++) + { + if (parents.Get(i).I1()) + can.Elem(i) = Center (can.Elem(parents.Get(i).I1()), + can.Elem(parents.Get(i).I2())); + } + + BitArray boundp(np); + boundp.Clear(); + for (int i = 1; i <= mesh.GetNSE(); i++) + { + const Element2d & sel = mesh.SurfaceElement(i); + for (int j = 1; j <= sel.GetNP(); j++) + boundp.Set(sel.PNum(j)); + } + + + (*testout) << "bpoints:" << endl; + for (int i = 1; i <= np; i++) + if (boundp.Test(i)) + (*testout) << i << endl; + + double lam = 0.5; + + while (facok < 1-1e-8 && cnttrials > 0) + { + lam *= 4; + if (lam > 2) lam = 2; + + do + { + // cout << "trials: " << cnttrials << endl; + lam *= 0.5; + cnttrials--; + + cout << "lam = " << lam << endl; + + factry = lam + (1-lam) * facok; + cout << "trying: " << factry << endl; + + for (int i = 1; i <= np; i++) + if (boundp.Test(i)) + { + for (int j = 1; j <= 3; j++) + mesh.Point(i).X(j) = + lam * should.Get(i).X(j) + + (1-lam) * can.Get(i).X(j); + } + else + mesh.Point(i) = can.Get(i); + + // (*testout) << "bad els: " << endl; + wrongels = 0; + for (int i = 1; i <= ne; i++) + { + if (!illegalels.Test(i) && + mesh.VolumeElement(i). + CalcJacobianBadness(mesh.Points()) > 1e10) + { + wrongels++; + Element & el = mesh.VolumeElement(i); + el.flags.badel = 1; + + + if (lam < 1e-4) + illegalels.Set(i); + + + /* + (*testout) << i << ": "; + for (j = 1; j <= el.GetNP(); j++) + (*testout) << el.PNum(j) << " "; + (*testout) << endl; + */ + } + else + mesh.VolumeElement(i).flags.badel = 0; + } + cout << "wrongels = " << wrongels << endl; + } + while (wrongels && cnttrials > 0); + + mesh.CalcSurfacesOfNode(); + mesh.ImproveMeshJacobian (OPT_WORSTCASE); + + facok = factry; + for (int i = 1; i <= np; i++) + can.Elem(i) = mesh.Point(i); + } + } + + + + for (int i = 1; i <= ne; i++) + { + if (illegalels.Test(i)) + { + cout << "illegal element: " << i << endl; + mesh.VolumeElement(i).flags.badel = 1; + } + else + mesh.VolumeElement(i).flags.badel = 0; + } + + /* + if (cnttrials <= 0) + { + cerr << "ERROR: Sorry, illegal elements:" << endl; + } + */ + } + +} diff --git a/contrib/Netgen/libsrc/meshing/smoothing2.cpp b/contrib/Netgen/libsrc/meshing/smoothing2.cpp new file mode 100644 index 0000000000..d26b20ad5d --- /dev/null +++ b/contrib/Netgen/libsrc/meshing/smoothing2.cpp @@ -0,0 +1,922 @@ +#include <mystdlib.h> + +#include "meshing.hpp" +#include <opti.hpp> + +namespace netgen +{ + + static const MeshOptimize2d * meshthis; + + +#ifdef OLD + + void CalcTriangleBadness (double x2, double x3, double y3, double metricweight, + double h, double & badness, double & g1x, double & g1y) + { + // badness = sqrt(3.0) /36 * circumference^2 / area - 1 + // p1 = (0, 0), p2 = (x2, 0), p3 = (x3, y3); + + Vec2d v23; + double l12, l13, l23, cir, area; + static const double c = sqrt(3.0) / 36; + double c1, c2, c3, c4; + + v23.X() = x3 - x2; + v23.Y() = y3; + + l12 = x2; + l13 = sqrt (x3*x3 + y3*y3); + l23 = v23.Length(); + + cir = l12 + l13 + l23; + area = 0.5 * x2 * y3; + + if (area <= 1e-24 * cir * cir) + { + g1x = 0; + g1y = 0; + badness = 1e10; + return; + } + + badness = c * cir * cir / area - 1; + + c1 = 2 * c * cir / area; + c2 = 0.5 * c * cir * cir / (area * area); + + g1x = c1 * ( - 1 - x3 / l13) - c2 * (-v23.Y()); + g1y = c1 * ( - y3 / l13) - c2 * ( v23.X()); + + // metricweight = 0.1; + if (metricweight > 0) + { + // area = (x2 - x1) * (y3 - y1) - (x3 - x1) * (y2 - y1); + // add: metricweight * (area / h^2 + h^2 / area - 2) + + const double area = x2 * y3; + const double dareax1 = -y3; + const double dareay1 = x3 - x2; + + const double areahh = area / (h * h); + const double fac = metricweight * (areahh - 1 / areahh) / area; + + badness += metricweight * (areahh + 1 / areahh - 2); + g1x += fac * dareax1; + g1y += fac * dareay1; + + /* + // add: metricweight * (l1^2/h^2 + l2^2/h^2 + l3^2/h2 + h^2/l1^2 + h^2/l2^2 + h^2/l3^2 - 6) + double h2 = h*h; + double l1 = x2*x2; + double l2 = x3*x3+y3*y3; + double l3 = (x2-x3)*(x2-x3)+y3*y3; + double dl1dx = 2*(-x2); + double dl1dy = 0; + double dl2dx = -2*x3; + double dl2dy = -2*y3; + + badness += (l1/h2 + l2/h2 + l3/h2 +h2/l1 + h2/l2 + h2/l3-6) * metricweight; + + g1x += metricweight * (dl1dx/h2-h2/(l1*l1)*dl1dx + dl2dx/h2-h2/(l2*l2)*dl2dx); + g1y += metricweight * (dl1dy/h2-h2/(l1*l1)*dl1dy + dl2dy/h2-h2/(l2*l2)*dl2dy); + */ + } + } + +#endif + + + /* + static const double c_trig = sqrt(3.0) / 12; + static const double c_trig4 = sqrt(3.0) / 3; + */ + static const double c_trig = 0.14433756; + static const double c_trig4 = 0.57735026; + + 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) + + double 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; + } + } + + + + + + + + + +#ifdef OLD + double CalcTriangleBadness (const Point3d & p1, + const Point3d & p2, + const Point3d & p3, + double metricweight, + double h) + { + double badness; + double g1x, g1y; + + Vec3d e1 (p1, p2); + Vec3d e2 (p1, p3); + + double e1l = e1.Length() + 1e-24; + e1 /= e1l; + double e1e2 = (e1 * e2); + e2.Add (-e1e2, e1); + double e2l = e2.Length(); + + CalcTriangleBadness ( e1l, e1e2, e2l, + metricweight, h, badness, g1x, g1y); + return badness; + } +#endif + + + + + double CalcTriangleBadness (const Point3d & p1, + const Point3d & p2, + const Point3d & p3, + double metricweight, + double h) + { + // badness = sqrt(3.0) / 12 * (\sum l_i^2) / area - 1 + // p1 = (0, 0), p2 = (x2, 0), p3 = (x3, y3); + + Vec3d e12(p1,p2); + Vec3d e13(p1,p3); + Vec3d e23(p2,p3); + + double l12_2 = e12.Length2(); + double l13_2 = e13.Length2(); + double l23_2 = e23.Length2(); + + double cir_2 = l12_2 + l13_2 + l23_2; + Vec3d area_v = Cross (e12, e13); + double area = 0.5 * area_v.Length(); + + if (area <= 1e-24 * cir_2) + return 1e10; + + double badness = c_trig * cir_2 / area - 1; + + if (metricweight > 0) + { + // area = (x2 - x1) * (y3 - y1) - (x3 - x1) * (y2 - y1); + // add: metricweight * (area / h^2 + h^2 / area - 2) + + const double areahh = area / (h * h); + badness += metricweight * (areahh + 1 / areahh - 2); + } + + return badness; + } + + + double CalcTriangleBadness (const Point3d & p1, + const Point3d & p2, + const Point3d & p3, + const Vec3d & n, + double metricweight, + double h) + { + Vec3d v1 (p1, p2); + Vec3d v2 (p1, p3); + + Vec3d e1 = v1; + Vec3d e2 = v2; + + e1 -= (e1 * n) * n; + e1 /= (e1.Length() + 1e-24); + e2 = Cross (n, e1); + + return CalcTriangleBadness ( (e1 * v1), (e1 * v2), (e2 * v2), + metricweight, h); + } + + + + + + static MeshPoint sp1; + static PointGeomInfo gi1; + static Vec3d n, t1, t2; + static ARRAY<SurfaceElementIndex> locelements(0); + static ARRAY<int> locrots(0); + static ARRAY<double> lochs(0); + // static int locerr2; + static double locmetricweight = 0; + static double loch; + static int surfi, surfi2; + static int uselocalh; + + + class Opti2SurfaceMinFunction : public MinFunction + { + const Mesh & mesh; + public: + Opti2SurfaceMinFunction (const Mesh & amesh) + : mesh(amesh) + { } ; + virtual double FuncGrad (const Vector & x, Vector & g) const; + virtual double Func (const Vector & x) const; + }; + + double Opti2SurfaceMinFunction :: + Func (const Vector & x) const + { + Vector g(x.Size()); + return FuncGrad (x, g); + } + + + double Opti2SurfaceMinFunction :: + FuncGrad (const Vector & x, Vector & grad) const + { + Vec3d n, vgrad; + Point3d pp1; + double g1x, g1y; + double badness, hbadness; + + vgrad = 0; + badness = 0; + + meshthis -> GetNormalVector (surfi, sp1, gi1, n); + + pp1 = sp1; + pp1.Add2 (x.Get(1), t1, x.Get(2), t2); + + // meshthis -> ProjectPoint (surfi, pp1); + // meshthis -> GetNormalVector (surfi, pp1, n); + + for (int j = 0; j < locelements.Size(); j++) + { + int roti = locrots[j]; + const Element2d & bel = mesh[locelements[j]]; + + Vec3d e1(pp1, mesh[bel.PNumMod(roti + 1)]); + Vec3d e2(pp1, mesh[bel.PNumMod(roti + 2)]); + + if (uselocalh) loch = lochs[j]; + + double e1l = e1.Length(); + if (Determinant(e1, e2, n) > 1e-8 * e1l * e2.Length()) + { + e1 /= e1l; + double e1e2 = e1 * e2; + e2.Add (-e1e2, e1); + double e2l = e2.Length(); + + CalcTriangleBadness ( e1l, e1e2, e2l, locmetricweight, loch, + hbadness, g1x, g1y); + + badness += hbadness; + vgrad.Add2 (g1x, e1, g1y / e2l, e2); + } + else + badness += 1e8; + } + + vgrad.Add (-(vgrad * n), n); + + grad.Elem(1) = vgrad * t1; + grad.Elem(2) = vgrad * t2; + return badness; + } + + + class Opti2EdgeMinFunction : public MinFunction + { + const Mesh & mesh; + public: + Opti2EdgeMinFunction (const Mesh & amesh) + : mesh(amesh) { } ; + + virtual double FuncGrad (const Vector & x, Vector & g) const; + virtual double Func (const Vector & x) const; + }; + + double Opti2EdgeMinFunction :: Func (const Vector & x) const + { + Vector g(x.Size()); + return FuncGrad (x, g); + } + + double Opti2EdgeMinFunction :: FuncGrad (const Vector & x, Vector & grad) const + { + int j, rot; + Vec3d n1, n2, v1, v2, e1, e2, vgrad; + Point3d pp1; + Vec2d g1; + double badness, hbadness; + + vgrad.X() = 0; + vgrad.Y() = 0; + vgrad.Z() = 0; + badness = 0; + + pp1 = sp1 + x.Get(1) * t1; + meshthis -> ProjectPoint2 (surfi, surfi2, pp1); + + for (j = 0; j < locelements.Size(); j++) + { + rot = locrots[j]; + const Element2d & bel = mesh[locelements[j]]; + + v1 = mesh[bel.PNumMod(rot + 1)] - pp1; + v2 = mesh[bel.PNumMod(rot + 2)] - pp1; + + e1 = v1; + e2 = v2; + e1 /= e1.Length(); + e2 -= (e1 * e2) * e1; + e2 /= e2.Length(); + + if (uselocalh) loch = lochs[j]; + CalcTriangleBadness ( (e1 * v1), (e1 * v2), (e2 * v2), locmetricweight, loch, + hbadness, g1.X(), g1.Y()); + + badness += hbadness; + + vgrad.X() += g1.X() * e1.X() + g1.Y() * e2.X(); + vgrad.Y() += g1.X() * e1.Y() + g1.Y() * e2.Y(); + vgrad.Z() += g1.X() * e1.Z() + g1.Y() * e2.Z(); + } + + meshthis -> GetNormalVector (surfi, pp1, n1); + meshthis -> GetNormalVector (surfi2, pp1, n2); + + v1 = Cross (n1, n2); + v1 /= v1.Length(); + + grad.Elem(1) = (vgrad * v1) * (t1 * v1); + + return badness; + } + + + + + class Opti2SurfaceMinFunctionJacobian : public MinFunction + { + const Mesh & mesh; + public: + Opti2SurfaceMinFunctionJacobian (const Mesh & amesh) + : mesh(amesh) + { } ; + virtual double FuncGrad (const Vector & x, Vector & g) const; + virtual double FuncDeriv (const Vector & x, const Vector & dir, double & deriv) const; + virtual double Func (const Vector & x) const; + }; + + double Opti2SurfaceMinFunctionJacobian :: + Func (const Vector & x) const + { + Vector g(x.Size()); + return FuncGrad (x, g); + } + + + double Opti2SurfaceMinFunctionJacobian :: + FuncGrad (const Vector & x, Vector & grad) const + { + // from 2d: + + int j, k, lpi, gpi; + Vec3d n, vgrad; + Point3d pp1; + Vec2d g1, vdir; + double badness, hbadness, hbad, hderiv; + + vgrad = 0; + badness = 0; + + meshthis -> GetNormalVector (surfi, sp1, gi1, n); + + pp1 = sp1; + pp1.Add2 (x.Get(1), t1, x.Get(2), t2); + + // meshthis -> ProjectPoint (surfi, pp1); + // meshthis -> GetNormalVector (surfi, pp1, n); + + static ARRAY<Point2d> pts2d; + pts2d.SetSize(mesh.GetNP()); + + grad = 0; + + for (j = 1; j <= locelements.Size(); j++) + { + lpi = locrots.Get(j); + const Element2d & bel = + mesh[locelements.Get(j)]; + + gpi = bel.PNum(lpi); + + for (k = 1; k <= bel.GetNP(); k++) + { + PointIndex pi = bel.PNum(k); + pts2d.Elem(pi) = Point2d (t1 * (mesh.Point(pi) - sp1), + t2 * (mesh.Point(pi) - sp1)); + } + pts2d.Elem(gpi) = Point2d (x.Get(1), x.Get(2)); + + + for (k = 1; k <= 2; k++) + { + if (k == 1) + vdir = Vec2d (1, 0); + else + vdir = Vec2d (0, 1); + + hbad = bel. + CalcJacobianBadnessDirDeriv (pts2d, lpi, vdir, hderiv); + + grad.Elem(k) += hderiv; + if (k == 1) + badness += hbad; + } + } + + + /* + 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; + Vec3d n, vgrad; + Point3d pp1; + Vec2d g1, vdir; + double badness, hbadness, hbad, hderiv; + + vgrad = 0; + badness = 0; + + meshthis -> GetNormalVector (surfi, sp1, gi1, n); + + pp1 = sp1; + pp1.Add2 (x.Get(1), t1, x.Get(2), t2); + + static ARRAY<Point2d> pts2d; + pts2d.SetSize(mesh.GetNP()); + + deriv = 0; + + for (j = 1; j <= locelements.Size(); j++) + { + lpi = locrots.Get(j); + const Element2d & bel = + mesh[locelements.Get(j)]; + + gpi = bel.PNum(lpi); + + for (k = 1; k <= bel.GetNP(); k++) + { + PointIndex pi = bel.PNum(k); + pts2d.Elem(pi) = Point2d (t1 * (mesh.Point(pi) - sp1), + t2 * (mesh.Point(pi) - sp1)); + } + pts2d.Elem(gpi) = Point2d (x.Get(1), x.Get(2)); + + + vdir = Vec2d (dir(0), dir(1)); + + hbad = bel. + CalcJacobianBadnessDirDeriv (pts2d, lpi, vdir, hderiv); + + deriv += hderiv; + badness += hbad; + } + + + return badness; + } + + + + + + + + MeshOptimize2d dummy; + + MeshOptimize2d :: MeshOptimize2d () + { + SetFaceIndex (0); + SetImproveEdges (0); + SetMetricWeight (0); + SetWriteStatus (1); + } + + + void MeshOptimize2d :: SelectSurfaceOfPoint (const Point3d & p, + const PointGeomInfo & gi) + { + ; + } + + void MeshOptimize2d :: ImproveMesh (Mesh & mesh) + { + if (!faceindex) + { + PrintMessage (3, "Smoothing"); + + for (faceindex = 1; faceindex <= mesh.GetNFD(); faceindex++) + { + ImproveMesh (mesh); + if (multithread.terminate) + throw NgException ("Meshing stopped"); + } + faceindex = 0; + return; + } + + CheckMeshApproximation (mesh); + + int i, j, k, surfi3; + SurfaceElementIndex sei; + + ARRAY<SurfaceElementIndex> seia; + mesh.GetSurfaceElementsOfFace (faceindex, seia); + + bool mixed = 0; + for (i = 0; i < seia.Size(); i++) + if (mesh[seia[i]].GetNP() != 3) + { + mixed = 1; + break; + } + + + int loci; + double fact; + int moveisok; + + PointGeomInfo ngi; + Point3d origp; + + Vec3d n1, n2; + Vector x(2), xedge(1); + + ARRAY<MeshPoint, PointIndex::BASE> savepoints(mesh.GetNP()); + uselocalh = mparam.uselocalh; + + ARRAY<int, PointIndex::BASE> nelementsonpoint(mesh.GetNP()); + nelementsonpoint = 0; + + for (i = 0; i < seia.Size(); i++) + { + const Element2d & el = mesh[seia[i]]; + for (j = 0; j < el.GetNP(); j++) + nelementsonpoint[el[j]]++; + } + + + TABLE<SurfaceElementIndex,PointIndex::BASE> elementsonpoint(nelementsonpoint); + for (i = 0; i < seia.Size(); i++) + { + const Element2d & el = mesh[seia[i]]; + for (j = 0; j < el.GetNP(); j++) + elementsonpoint.Add (el[j], seia[i]); + } + + loch = mparam.maxh; + locmetricweight = metricweight; + meshthis = this; + + Opti2SurfaceMinFunction surfminf(mesh); + Opti2EdgeMinFunction edgeminf(mesh); + Opti2SurfaceMinFunctionJacobian surfminfj(mesh); + + OptiParameters par; + par.maxit_linsearch = 8; + par.maxit_bfgs = 5; + + /* + if (improveedges) + for (i = 1; i <= mesh.GetNP(); i++) + if (mesh.PointType(i) == EDGEPOINT) + { + continue; + PrintDot (); + sp1 = mesh.Point(i); + + locelements.SetSize(0); + locrots.SetSize (0); + lochs.SetSize (0); + surfi = surfi2 = surfi3 = 0; + + for (j = 0; j < elementsonpoint[i].Size(); j++) + { + sei = elementsonpoint[i][j]; + const Element2d * bel = &mesh[sei]; + + if (!surfi) + surfi = mesh.GetFaceDescriptor(bel->GetIndex()).SurfNr(); + else if (surfi != mesh.GetFaceDescriptor(bel->GetIndex()).SurfNr()) + { + if (surfi2 != 0 && surfi2 != + mesh.GetFaceDescriptor(bel->GetIndex()).SurfNr()) + surfi3 = mesh.GetFaceDescriptor(bel->GetIndex()).SurfNr(); + else + surfi2 = mesh.GetFaceDescriptor(bel->GetIndex()).SurfNr(); + } + + locelements.Append (sei); + + if (bel->PNum(1) == i) + locrots.Append (1); + else if (bel->PNum(2) == i) + locrots.Append (2); + else + locrots.Append (3); + + if (uselocalh) + { + Point3d pmid = Center (mesh.Point(bel->PNum(1)), + mesh.Point(bel->PNum(2)), + mesh.Point(bel->PNum(3))); + lochs.Append (mesh.GetH(pmid)); + } + } + + if (surfi2 && !surfi3) + { + GetNormalVector (surfi, sp1, n1); + GetNormalVector (surfi2, sp1, n2); + t1 = Cross (n1, n2); + + xedge = 0; + BFGS (xedge, edgeminf, par, 1e-6); + + mesh.Point(i).X() += xedge.Get(1) * t1.X(); + mesh.Point(i).Y() += xedge.Get(1) * t1.Y(); + mesh.Point(i).Z() += xedge.Get(1) * t1.Z(); + ProjectPoint2 (surfi, surfi2, mesh.Point(i)); + } + } + */ + + + bool printeddot = 0; + char plotchar = '.'; + int modplot = 1; + if (mesh.GetNP() > 1000) + { + plotchar = '+'; + modplot = 10; + } + if (mesh.GetNP() > 10000) + { + plotchar = 'o'; + modplot = 100; + } + int cnt = 0; + + for (PointIndex pi = PointIndex::BASE; + pi < mesh.GetNP()+PointIndex::BASE; pi++) + + if (mesh.PointType(pi) == SURFACEPOINT) + { + if (multithread.terminate) + throw NgException ("Meshing stopped"); + + if (pi == 3679) + (*testout) << " old: " << mesh[pi] << endl; + + + cnt++; + if (cnt % modplot == 0 && writestatus) + { + printeddot = 1; + PrintDot (plotchar); + } + + if (elementsonpoint[pi].Size() == 0) + continue; + + sp1 = mesh[pi]; + + Element2d & hel = mesh[elementsonpoint[pi][0]]; + + int hpi = 0; + for (j = 1; j <= hel.GetNP(); j++) + if (hel.PNum(j) == pi) + { + hpi = j; + break; + } + + gi1 = hel.GeomInfoPi(hpi); + SelectSurfaceOfPoint (sp1, gi1); + + locelements.SetSize(0); + locrots.SetSize (0); + lochs.SetSize (0); + + for (j = 0; j < elementsonpoint[pi].Size(); j++) + { + sei = elementsonpoint[pi][j]; + const Element2d & bel = mesh[sei]; + surfi = mesh.GetFaceDescriptor(bel.GetIndex()).SurfNr(); + + locelements.Append (sei); + + for (k = 1; k <= bel.GetNP(); k++) + if (bel.PNum(k) == pi) + { + locrots.Append (k); + break; + } + + if (uselocalh) + { + Point3d pmid = Center (mesh[bel[0]], mesh[bel[1]], mesh[bel[2]]); + lochs.Append (mesh.GetH(pmid)); + } + } + + + GetNormalVector (surfi, sp1, gi1, n); + n.GetNormal (t1); + t2 = Cross (n, t1); + + // save points, and project to tangential plane + for (j = 0; j < locelements.Size(); j++) + { + const Element2d & el = mesh[locelements[j]]; + for (k = 0; k < el.GetNP(); k++) + savepoints[el[k]] = mesh[el[k]]; + } + + for (j = 0; j < locelements.Size(); j++) + { + const Element2d & el = mesh[locelements[j]]; + for (k = 0; k < el.GetNP(); k++) + { + PointIndex hpi = el[k]; + double lam = n * (mesh[hpi] - sp1); + mesh[hpi] -= lam * n; + } + } + + x = 0; + + if (mixed) + BFGS (x, surfminfj, par, 1e-6); + else + BFGS (x, surfminf, par, 1e-6); + + origp = mesh[pi]; + loci = 1; + fact = 1; + moveisok = 0; + + // restore other points + for (j = 0; j < locelements.Size(); j++) + { + const Element2d & el = mesh[locelements[j]]; + for (k = 0; k < el.GetNP(); k++) + { + PointIndex hpi = el[k]; + if (hpi != pi) mesh[hpi] = savepoints[hpi]; + } + } + + + //optimizer loop (if not whole distance is not possible, move only a bit!!!!) + while (loci <= 5 && !moveisok) + { + loci ++; + mesh[pi].X() = origp.X() + (x.Get(1) * t1.X() + x.Get(2) * t2.X())*fact; + mesh[pi].Y() = origp.Y() + (x.Get(1) * t1.Y() + x.Get(2) * t2.Y())*fact; + mesh[pi].Z() = origp.Z() + (x.Get(1) * t1.Z() + x.Get(2) * t2.Z())*fact; + fact = fact/2.; + + if (pi == 3679) + (*testout) << " before proj: " << mesh[pi] << endl; + + ProjectPoint (surfi, mesh[pi]); + + if (pi == 3679) + { + (*testout) << " after proj: " << mesh[pi] << endl; + (*testout) << "surfi =" << surfi << endl; + } + + moveisok = CalcPointGeomInfo(surfi, ngi, mesh[pi]); + // point lies on same chart in stlsurface + + if (moveisok) + { + for (j = 0; j < locelements.Size(); j++) + mesh[locelements[j]].GeomInfoPi(locrots[j]) = ngi; + } + else + { + mesh[pi] = origp; + } + + } + + if (pi == 3679) + (*testout) << " new: " << mesh[pi] << endl; + } + + + if (printeddot) + PrintDot ('\n'); + + CheckMeshApproximation (mesh); + mesh.SetNextTimeStamp(); + } + + void MeshOptimize2d :: GetNormalVector(INDEX /* surfind */, const Point3d & p, Vec3d & nv) const + { + nv = Vec3d (0, 0, 1); + } + + void MeshOptimize2d :: GetNormalVector(INDEX surfind, const Point3d & p, PointGeomInfo & gi, Vec3d & n) const + { + GetNormalVector (surfind, p, n); + } + +} diff --git a/contrib/Netgen/libsrc/meshing/smoothing3.cpp b/contrib/Netgen/libsrc/meshing/smoothing3.cpp new file mode 100644 index 0000000000..61c1910884 --- /dev/null +++ b/contrib/Netgen/libsrc/meshing/smoothing3.cpp @@ -0,0 +1,1546 @@ +#include <mystdlib.h> + +#include "meshing.hpp" +#ifdef SOLIDGEOM +#include <csg.hpp> +#endif +#include <opti.hpp> + + +namespace netgen +{ + + + PointFunction1 :: PointFunction1 (Mesh::T_POINTS & apoints, + const ARRAY<INDEX_3> & afaces, + double ah) + : points(apoints), faces(afaces) + { + h = ah; + } + + + double PointFunction1 :: Func (const Vector & vp) const + { + int j; + double badness = 0; + Point3d pp(vp(0), vp(1), vp(2)); + + for (j = 0; j < faces.Size(); j++) + { + const INDEX_3 & el = faces[j]; + + double bad = CalcTetBadness (points[el.I1()], + points[el.I3()], + points[el.I2()], + pp, 0); + badness += bad; + } + + return badness; + } + + + + double PointFunction1 :: + FuncDeriv (const Vector & x, const Vector & dir, double & deriv) const + { + static Vector hx(3); + static double eps = 1e-6; + + double dirlen = dir.L2Norm(); + if (dirlen < 1e-14) + { + deriv = 0; + return Func(x); + } + + hx.Set(1, x); + hx.Add(eps * h / dirlen, dir); + double fr = Func (hx); + hx.Set(1, x); + hx.Add(-eps * h / dirlen, dir); + double fl = Func (hx); + + deriv = (fr - fl) / (2 * eps * h) * dirlen; + + return Func(x); + } + + + double PointFunction1 :: FuncGrad (const Vector & x, Vector & g) const + { + static Vector hx(3); + static double eps = 1e-6; + + hx = x; + for (int i = 1; i <= 3; i++) + { + hx.Elem(i) = x.Get(i) + eps * h; + double fr = Func (hx); + hx.Elem(i) = x.Get(i) - eps * h; + double fl = Func (hx); + hx.Elem(i) = x.Get(i); + + g.Elem(i) = (fr - fl) / (2 * eps * h); + } + + return Func(x); + } + + double PointFunction1 :: GradStopping (const Vector & x) const + { + double f = Func(x); + return 1e-8 * f * f; + } + + + + + /* Cheap Functional depending of inner point inside triangular surface */ + + class CheapPointFunction1 : public MinFunction + { + Mesh::T_POINTS & points; + const ARRAY<INDEX_3> & faces; + DenseMatrix m; + double h; + public: + CheapPointFunction1 (Mesh::T_POINTS & apoints, + const ARRAY<INDEX_3> & afaces, + double ah); + + virtual double Func (const Vector & x) const; + virtual double FuncGrad (const Vector & x, Vector & g) const; + }; + + CheapPointFunction1 :: CheapPointFunction1 (Mesh::T_POINTS & apoints, + const ARRAY<INDEX_3> & afaces, + double ah) + : points(apoints), faces(afaces) + { + h = ah; + + + int i, nf = faces.Size(); + + m.SetSize (nf, 4); + + for (i = 1; i <= nf; i++) + { + const Point3d & p1 = points[faces.Get(i).I1()]; + const Point3d & p2 = points[faces.Get(i).I2()]; + const Point3d & p3 = points[faces.Get(i).I3()]; + Vec3d v1 (p1, p2); + Vec3d v2 (p1, p3); + Vec3d n; + Cross (v1, v2, n); + n /= n.Length(); + + m.Elem(i, 1) = n.X(); + m.Elem(i, 2) = n.Y(); + m.Elem(i, 3) = n.Z(); + m.Elem(i, 4) = - (n.X() * p1.X() + n.Y() * p1.Y() + n.Z() * p1.Z()); + } + } + + + double CheapPointFunction1 :: Func (const Vector & vp) const + { + + /* + int j; + double badness = 0; + Point3d pp(vp.Get(1), vp.Get(2), vp.Get(3)); + + for (j = 1; j <= faces.Size(); j++) + { + const INDEX_3 & el = faces.Get(j); + + double bad = CalcTetBadness (points.Get(el.I1()), + points.Get(el.I3()), + points.Get(el.I2()), + pp, 0); + badness += bad; + } + */ + + int i; + double badness = 0; + static Vector hv(4); + static Vector res; + res.SetSize (m.Height()); + + for (i = 1;i <= 3; i++) + hv.Elem(i) = vp.Get(i); + hv.Elem(4) = 1; + m.Mult (hv, res); + + for (i = 1; i <= res.Size(); i++) + { + if (res.Get(i) < 1e-10) + badness += 1e24; + else + badness += 1 / res.Get(i); + } + + return badness; + } + + + double CheapPointFunction1 :: FuncGrad (const Vector & x, Vector & g) const + { + static Vector hx(3); + static double eps = 1e-6; + + hx = x; + for (int i = 1; i <= 3; i++) + { + hx.Elem(i) = x.Get(i) + eps * h; + double fr = Func (hx); + hx.Elem(i) = x.Get(i) - eps * h; + double fl = Func (hx); + hx.Elem(i) = x.Get(i); + + g.Elem(i) = (fr - fl) / (2 * eps * h); + } + + return Func(x); + } + + + + + + + + + + + + + + + + /* ************* PointFunction **************************** */ + + + class PointFunction + { + public: + Mesh::T_POINTS & points; + const Mesh::T_VOLELEMENTS & elements; + TABLE<INDEX,PointIndex::BASE> elementsonpoint; + PointIndex actpind; + double h; + + public: + PointFunction (Mesh::T_POINTS & apoints, + const Mesh::T_VOLELEMENTS & aelements); + + virtual void SetPointIndex (PointIndex aactpind); + void SetLocalH (double ah) { h = ah; } + double GetLocalH () const { return h; } + virtual double PointFunctionValue (const Point3d & pp) const; + virtual double PointFunctionValueGrad (const Point3d & pp, Vector & grad) const; + virtual double PointFunctionValueDeriv (const Point3d & pp, const Vec3d & dir, double & deriv) const; + + int MovePointToInner (); + }; + + + PointFunction :: PointFunction (Mesh::T_POINTS & apoints, + const Mesh::T_VOLELEMENTS & aelements) + : points(apoints), elements(aelements), elementsonpoint(apoints.Size()) + { + INDEX i; + int j; + + for (i = 1; i <= elements.Size(); i++) + { + if (elements.Get(i).NP() == 4) + for (j = 1; j <= elements.Get(i).NP(); j++) + elementsonpoint.Add (elements.Get(i).PNum(j), i); + } + } + + void PointFunction :: SetPointIndex (PointIndex aactpind) + { + actpind = aactpind; + } + + double PointFunction :: PointFunctionValue (const Point3d & pp) const + { + int j; + INDEX eli; + const Element * el; + double badness; + // ARRAY<const Point3d*> p(4); + Point3d hp; + + badness = 0; + + hp = points[actpind]; + points[actpind] = pp; + + for (j = 0; j < elementsonpoint[actpind].Size(); j++) + { + eli = elementsonpoint[actpind][j]; + el = &elements.Get(eli); + badness += CalcTetBadness (points[el->PNum(1)], + points[el->PNum(2)], + points[el->PNum(3)], + points[el->PNum(4)], -1); + } + + points[actpind] = hp; + return badness; + } + + + double PointFunction :: PointFunctionValueGrad (const Point3d & pp, Vector & grad) const + { + double f, delta = h * 1e-6; + Point3d hpp; + + f = PointFunctionValue (pp); + + /* + hpp = pp; + hpp.X() = pp.X() + delta; + fr = PointFunctionValue (hpp); + hpp.X() = pp.X() - delta; + fl = PointFunctionValue (hpp); + grad.Elem(1) = (fr - fl) / (2 * delta); + + hpp = pp; + hpp.Y() = pp.Y() + delta; + fr = PointFunctionValue (hpp); + hpp.Y() = pp.Y() - delta; + fl = PointFunctionValue (hpp); + grad.Elem(2) = (fr - fl) / (2 * delta); + + hpp = pp; + hpp.Z() = pp.Z() + delta; + fr = PointFunctionValue (hpp); + hpp.Z() = pp.Z() - delta; + fl = PointFunctionValue (hpp); + grad.Elem(3) = (fr - fl) / (2 * delta); + */ + + + + // new gradient calculation + int j, k; + INDEX eli; + // double badness; + Point3d hp; + Vec3d vgradi, vgrad(0,0,0); + + // badness = 0; + + hp = points[actpind]; + points[actpind] = pp; + + for (j = 0; j < elementsonpoint[actpind].Size(); j++) + { + eli = elementsonpoint[actpind][j]; + const Element & el = elements.Get(eli); + + for (k = 1; k <= 4; k++) + if (el.PNum(k) == actpind) + { + CalcTetBadnessGrad (points[el.PNum(1)], + points[el.PNum(2)], + points[el.PNum(3)], + points[el.PNum(4)], -1, k, vgradi); + vgrad += vgradi; + } + } + points[actpind] = hp; + + for (j = 1; j <= 3; j++) + grad.Elem(j) = vgrad.X(j); + + return f; + } + + + double PointFunction :: PointFunctionValueDeriv (const Point3d & pp, const Vec3d & dir, + double & deriv) const + { + double f; + Point3d hpp; + + Vec3d dirn (dir); + double ldir = dir.Length(); + + int j, k; + INDEX eli; + // double badness; + Point3d hp; + Vec3d vgradi, vgrad(0,0,0); + + // badness = 0; + + hp = points[actpind]; + points[actpind] = pp; + f = 0; + + for (j = 0; j < elementsonpoint[actpind].Size(); j++) + { + eli = elementsonpoint[actpind][j]; + const Element & el = elements.Get(eli); + + for (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); + + vgrad += vgradi; + } + } + + points[actpind] = hp; + deriv = dir * vgrad; + return f; + } + + int PointFunction :: MovePointToInner () + { + int j, k; + + // try point movement + ARRAY<Element2d> faces; + + for (j = 0; j < elementsonpoint[actpind].Size(); j++) + { + const Element & el = + elements.Get(elementsonpoint[actpind][j]); + + for (k = 1; k <= 4; k++) + if (el.PNum(k) == actpind) + { + Element2d face; + el.GetFace (k, face); + Swap (face.PNum(2), face.PNum(3)); + faces.Append (face); + } + } + + Point3d hp; + int hi = FindInnerPoint (points, faces, hp); + if (hi) + { + cout << "inner point found" << endl; + points[actpind] = hp; + } + else + cout << "no inner point found" << endl; + + return hi; + } + + + + + + + class CheapPointFunction : public PointFunction + { + DenseMatrix m; + public: + CheapPointFunction (Mesh::T_POINTS & apoints, + const Mesh::T_VOLELEMENTS & aelements); + virtual void SetPointIndex (PointIndex aactpind); + virtual double PointFunctionValue (const Point3d & pp) const; + virtual double PointFunctionValueGrad (const Point3d & pp, Vector & grad) const; + }; + + + CheapPointFunction :: CheapPointFunction (Mesh::T_POINTS & apoints, + const Mesh::T_VOLELEMENTS & aelements) + : PointFunction (apoints, aelements) + { + ; + } + + + void CheapPointFunction :: SetPointIndex (PointIndex aactpind) + { + actpind = aactpind; + + int n = elementsonpoint[actpind].Size(); + int i, j; + int pi1, pi2, pi3; + + m.SetSize (n, 4); + + for (i = 0; i < n; i++) + { + pi1 = 0; + pi2 = 0; + pi3 = 0; + + const Element & el = elements.Get (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) = n.X(); + m.Elem(i, 2) = n.Y(); + m.Elem(i, 3) = n.Z(); + m.Elem(i, 4) = - (n.X() * p1.X() + n.Y() * p1.Y() + n.Z() * p1.Z()); + } + } + + double CheapPointFunction :: PointFunctionValue (const Point3d & pp) const + { + static Vector p4(4); + static Vector di; + int n = m.Height(); + + p4.Elem(1) = pp.X(); + p4.Elem(2) = pp.Y(); + p4.Elem(3) = pp.Z(); + p4.Elem(4) = 1; + + di.SetSize (n); + m.Mult (p4, di); + + double sum = 0; + for (int i = 1; i <= n; i++) + { + if (di.Get(i) > 0) + sum += 1 / di.Get(i); + else + return 1e16; + } + return sum; + } + + + + + double CheapPointFunction :: PointFunctionValueGrad (const Point3d & pp, Vector & grad) const + { + static Vector p4(4); + static Vector di; + + grad.SetSize (3); + int n = m.Height(); + + p4.Elem(1) = pp.X(); + p4.Elem(2) = pp.Y(); + p4.Elem(3) = pp.Z(); + p4.Elem(4) = 1; + + di.SetSize (n); + m.Mult (p4, di); + + double sum = 0; + grad = 0; + for (int i = 1; i <= n; i++) + { + if (di.Get(i) > 0) + { + double idi = 1 / di.Get(i); + sum += idi; + grad.Elem(1) -= idi * idi * m.Get(i, 1); + grad.Elem(2) -= idi * idi * m.Get(i, 2); + grad.Elem(3) -= idi * idi * m.Get(i, 3); + } + else + { + return 1e16; + } + } + return sum; + } + + + + + + + + + class Opti3FreeMinFunction : public MinFunction + { + const PointFunction & pf; + Point3d sp1; + + public: + Opti3FreeMinFunction (const PointFunction & apf); + void SetPoint (const Point3d & asp1) { sp1 = asp1; } + virtual double Func (const Vector & x) const; + virtual double FuncGrad (const Vector & x, Vector & g) const; + virtual double FuncDeriv (const Vector & x, const Vector & dir, double & deriv) const; + virtual double GradStopping (const Vector & x) const; + virtual void ApproximateHesse (const Vector & x, + DenseMatrix & hesse) const; + }; + + + + Opti3FreeMinFunction :: Opti3FreeMinFunction (const PointFunction & apf) + : pf(apf) + { + ; + } + + + double Opti3FreeMinFunction :: Func (const Vector & x) const + { + Point3d pp; + pp.X() = sp1.X() + x.Get(1); + pp.Y() = sp1.Y() + x.Get(2); + pp.Z() = sp1.Z() + x.Get(3); + + return pf.PointFunctionValue (pp); + } + + double Opti3FreeMinFunction :: FuncGrad (const Vector & x, Vector & grad) const + { + Point3d pp; + pp.X() = sp1.X() + x.Get(1); + pp.Y() = sp1.Y() + x.Get(2); + pp.Z() = sp1.Z() + x.Get(3); + + return pf.PointFunctionValueGrad (pp, grad); + } + + double Opti3FreeMinFunction :: FuncDeriv (const Vector & x, const Vector & dir, double & deriv) const + { + Point3d pp; + pp.X() = sp1.X() + x.Get(1); + pp.Y() = sp1.Y() + x.Get(2); + pp.Z() = sp1.Z() + x.Get(3); + + Vec3d vdir; + vdir.X() = dir.Get(1); + vdir.Y() = dir.Get(2); + vdir.Z() = dir.Get(3); + + return pf.PointFunctionValueDeriv (pp, vdir, deriv); + } + + double Opti3FreeMinFunction :: GradStopping (const Vector & x) const + { + double f = Func(x); + return 1e-3 * f / pf.GetLocalH(); + } + + + void Opti3FreeMinFunction :: ApproximateHesse (const Vector & x, + DenseMatrix & hesse) const + { + int n = x.Size(); + int i, j; + + static Vector hx; + hx.SetSize(n); + + double eps = 1e-8; + double f, f11, f12, f21, f22; + + f = Func(x); + + + for (i = 1; i <= n; i++) + { + for (j = 1; j < i; j++) + { + /* + hx = x; + hx.Elem(i) = x.Get(i) + eps; + hx.Elem(j) = x.Get(j) + eps; + f11 = Func(hx); + hx.Elem(i) = x.Get(i) + eps; + hx.Elem(j) = x.Get(j) - eps; + f12 = Func(hx); + hx.Elem(i) = x.Get(i) - eps; + hx.Elem(j) = x.Get(j) + eps; + f21 = Func(hx); + hx.Elem(i) = x.Get(i) - eps; + hx.Elem(j) = x.Get(j) - eps; + f22 = Func(hx); + */ + hesse.Elem(i, j) = hesse.Elem(j, i) = 0; + // (f11 + f22 - f12 - f21) / (2 * eps * eps); + } + + hx = x; + hx.Elem(i) = x.Get(i) + eps; + f11 = Func(hx); + hx.Elem(i) = x.Get(i) - eps; + f22 = Func(hx); + + hesse.Elem(i, i) = (f11 + f22 - 2 * f) / (eps * eps) + 1e-12; + } + } + + + + + + +#ifdef SOLIDGEOM + class Opti3SurfaceMinFunction : public MinFunction + { + const PointFunction & pf; + Point3d sp1; + const Surface * surf; + Vec3d t1, t2; + + public: + Opti3SurfaceMinFunction (const PointFunction & apf); + + void SetPoint (const Surface * asurf, const Point3d & asp1); + + void CalcNewPoint (const Vector & x, Point3d & np) const; + virtual double Func (const Vector & x) const; + virtual double FuncGrad (const Vector & x, Vector & g) const; + }; + + + Opti3SurfaceMinFunction :: Opti3SurfaceMinFunction (const PointFunction & apf) + : MinFunction(), pf(apf) + { + ; + } + + void Opti3SurfaceMinFunction :: SetPoint (const Surface * asurf, const Point3d & asp1) + { + Vec3d n; + sp1 = asp1; + surf = asurf; + + Vec<3> hn; + surf -> GetNormalVector (sp1, hn); + n = hn; + + n.GetNormal (t1); + t1 /= t1.Length(); + t2 = Cross (n, t1); + } + + + void Opti3SurfaceMinFunction :: CalcNewPoint (const Vector & x, + Point3d & np) const + { + np.X() = sp1.X() + x.Get(1) * t1.X() + x.Get(2) * t2.X(); + np.Y() = sp1.Y() + x.Get(1) * t1.Y() + x.Get(2) * t2.Y(); + np.Z() = sp1.Z() + x.Get(1) * t1.Z() + x.Get(2) * t2.Z(); + + Point<3> hnp = np; + surf -> Project (hnp); + np = hnp; + } + + + double Opti3SurfaceMinFunction :: Func (const Vector & x) const + { + Point3d pp1; + + CalcNewPoint (x, pp1); + return pf.PointFunctionValue (pp1); + } + + + + double Opti3SurfaceMinFunction :: FuncGrad (const Vector & x, Vector & grad) const + { + Vec3d n, vgrad; + Point3d pp1; + double badness; + static Vector freegrad(3); + + CalcNewPoint (x, pp1); + + badness = pf.PointFunctionValueGrad (pp1, freegrad); + vgrad.X() = freegrad.Get(1); + vgrad.Y() = freegrad.Get(2); + vgrad.Z() = freegrad.Get(3); + + Vec<3> hn; + surf -> GetNormalVector (pp1, hn); + n = hn; + + vgrad -= (vgrad * n) * n; + + grad.Elem(1) = vgrad * t1; + grad.Elem(2) = vgrad * t2; + + return badness; + } +#endif + + + + + + + + +#ifdef SOLIDGEOM + class Opti3EdgeMinFunction : public MinFunction + { + const PointFunction & pf; + Point3d sp1; + const Surface *surf1, *surf2; + Vec3d t1; + + public: + Opti3EdgeMinFunction (const PointFunction & apf); + + void SetPoint (const Surface * asurf1, const Surface * asurf2, + const Point3d & asp1); + void CalcNewPoint (const Vector & x, Point3d & np) const; + virtual double FuncGrad (const Vector & x, Vector & g) const; + virtual double Func (const Vector & x) const; + }; + + Opti3EdgeMinFunction :: Opti3EdgeMinFunction (const PointFunction & apf) + : MinFunction(), pf(apf) + { + ; + } + + void Opti3EdgeMinFunction :: SetPoint (const Surface * asurf1, + const Surface * asurf2, + const Point3d & asp1) + { + Vec3d n1, n2; + sp1 = asp1; + surf1 = asurf1; + surf2 = asurf2; + + Vec<3> hn1, hn2; + surf1 -> GetNormalVector (sp1, hn1); + surf2 -> GetNormalVector (sp1, hn2); + n1 = hn1; + n2 = hn2; + t1 = Cross (n1, n2); + } + + void Opti3EdgeMinFunction :: CalcNewPoint (const Vector & x, + Point3d & np) const +{ + np.X() = sp1.X() + x.Get(1) * t1.X(); + np.Y() = sp1.Y() + x.Get(1) * t1.Y(); + np.Z() = sp1.Z() + x.Get(1) * t1.Z(); + Point<3> hnp = np; + ProjectToEdge (surf1, surf2, hnp); + np = hnp; +} + +double Opti3EdgeMinFunction :: Func (const Vector & x) const +{ + Vector g(x.Size()); + return FuncGrad (x, g); +} + + +double Opti3EdgeMinFunction :: FuncGrad (const Vector & x, Vector & grad) const +{ + Vec3d n1, n2, v1, vgrad; + Point3d pp1; + double badness; + static Vector freegrad(3); + + CalcNewPoint (x, pp1); + + + badness = pf.PointFunctionValueGrad (pp1, freegrad); + + vgrad.X() = freegrad.Get(1); + vgrad.Y() = freegrad.Get(2); + vgrad.Z() = freegrad.Get(3); + + Vec<3> hn1, hn2; + surf1 -> GetNormalVector (pp1, hn1); + surf2 -> GetNormalVector (pp1, hn2); + n1 = hn1; + n2 = hn2; + + v1 = Cross (n1, n2); + v1 /= v1.Length(); + + grad.Elem(1) = (vgrad * v1) * (t1 * v1); + return badness; +} +#endif + + + + +double CalcBad (const Mesh::T_POINTS & points, const Element & elem, + double h) +{ + if (elem.GetType() == TET) + return CalcTetBadness (points[elem.PNum(1)], + points[elem.PNum(2)], + points[elem.PNum(3)], + points[elem.PNum(4)], h); + return 0; +} + + +extern double teterrpow; +double CalcTotalBad (const Mesh::T_POINTS & points, + const Mesh::T_VOLELEMENTS & elements) +{ + int i; + double sum = 0; + double elbad; + + tets_in_qualclass.SetSize(20); + for (i = 1; i <= 20; i++) + tets_in_qualclass.Elem(i) = 0; + + + for (i = 1; i <= elements.Size(); i++) + { + elbad = pow (CalcBad (points, elements.Get(i), 0), 1/teterrpow); + + int qualclass = int (20 / elbad + 1); + if (qualclass < 1) qualclass = 1; + if (qualclass > 20) qualclass = 20; + tets_in_qualclass.Elem(qualclass)++; + + sum += elbad; + } + return sum; +} + +int WrongOrientation (const Mesh::T_POINTS & points, const Element & el) +{ + const Point3d & p1 = points[el.PNum(1)]; + const Point3d & p2 = points[el.PNum(2)]; + const Point3d & p3 = points[el.PNum(3)]; + const Point3d & p4 = points[el.PNum(4)]; + + Vec3d v1(p1, p2); + Vec3d v2(p1, p3); + Vec3d v3(p1, p4); + Vec3d n; + + Cross (v1, v2, n); + double vol = n * v3; + + return (vol > 0); +} + + + + + + + + + + + +/* ************* JacobianPointFunction **************************** */ + + + + +class JacobianPointFunction : public MinFunction +{ +public: + Mesh::T_POINTS & points; + const Mesh::T_VOLELEMENTS & elements; + TABLE<INDEX> elementsonpoint; + PointIndex actpind; + +public: + JacobianPointFunction (Mesh::T_POINTS & apoints, + const Mesh::T_VOLELEMENTS & aelements); + + virtual void SetPointIndex (PointIndex aactpind); + virtual double Func (const Vector & x) const; + virtual double FuncGrad (const Vector & x, Vector & g) const; + virtual double FuncDeriv (const Vector & x, const Vector & dir, double & deriv) const; +}; + + +JacobianPointFunction :: +JacobianPointFunction (Mesh::T_POINTS & apoints, + const Mesh::T_VOLELEMENTS & aelements) + : points(apoints), elements(aelements), elementsonpoint(apoints.Size()) +{ + INDEX i; + int j; + + for (i = 1; i <= elements.Size(); i++) + { + for (j = 1; j <= elements.Get(i).NP(); j++) + elementsonpoint.Add1 (elements.Get(i).PNum(j), i); + } +} + +void JacobianPointFunction :: SetPointIndex (PointIndex aactpind) +{ + actpind = aactpind; +} + + +double JacobianPointFunction :: Func (const Vector & v) const +{ + int j; + double badness = 0; + + Point3d hp = points.Elem(actpind); + points.Elem(actpind) = hp + Vec3d (v.Get(1), v.Get(2), v.Get(3)); + + for (j = 1; j <= elementsonpoint.EntrySize(actpind); j++) + { + int eli = elementsonpoint.Get(actpind, j); + badness += elements.Get(eli).CalcJacobianBadness (points); + } + + points.Elem(actpind) = hp; + + return badness; +} + + + + + +double JacobianPointFunction :: +FuncGrad (const Vector & x, Vector & g) const +{ + int j, k; + int lpi; + double badness = 0, hbad; + + Point3d hp = points.Elem(actpind); + points.Elem(actpind) = hp + Vec3d (x.Get(1), x.Get(2), x.Get(3)); + + double hderiv; + Vec3d vdir; + g.SetSize(3); + g = 0; + + for (j = 1; j <= elementsonpoint.EntrySize(actpind); j++) + { + int eli = elementsonpoint.Get(actpind, j); + const Element & el = elements.Get(eli); + + lpi = 0; + for (k = 1; k <= el.GetNP(); k++) + if (el.PNum(k) == actpind) + lpi = k; + if (!lpi) cerr << "loc point not found" << endl; + + for (k = 1; k <= 3; k++) + { + vdir = Vec3d(0,0,0); + vdir.X(k) = 1; + + hbad = elements.Get(eli). + CalcJacobianBadnessDirDeriv (points, lpi, vdir, hderiv); + g.Elem(k) += hderiv; + if (k == 1) + badness += hbad; + } + } + + points.Elem(actpind) = hp; + + return badness; +} + + +double JacobianPointFunction :: +FuncDeriv (const Vector & x, const Vector & dir, double & deriv) const +{ + int j, k; + int lpi; + double badness = 0; + + Point3d hp = points.Elem(actpind); + points.Elem(actpind) = hp + Vec3d (x.Get(1), x.Get(2), x.Get(3)); + + double hderiv; + deriv = 0; + Vec3d vdir(dir.Get(1), dir.Get(2), dir.Get(3)); + + for (j = 1; j <= elementsonpoint.EntrySize(actpind); j++) + { + int eli = elementsonpoint.Get(actpind, j); + const Element & el = elements.Get(eli); + + lpi = 0; + for (k = 1; k <= el.GetNP(); k++) + if (el.PNum(k) == actpind) + lpi = k; + if (!lpi) cerr << "loc point not found" << endl; + + badness += elements.Get(eli). + CalcJacobianBadnessDirDeriv (points, lpi, vdir, hderiv); + deriv += hderiv; + } + + points.Elem(actpind) = hp; + + return badness; + + /* + (*testout) << "bad1 = " << badness << " der = " << deriv << endl; + + + + static Vector hx(3); + static double eps = 1e-6; + + double dirlen = dir.L2Norm(); + if (dirlen < 1e-14) + { + deriv = 0; + return Func(x); + } + + hx.Set(1, x); + hx.Add(eps / dirlen, dir); + double fr = Func (hx); + hx.Set(1, x); + hx.Add(-eps / dirlen, dir); + double fl = Func (hx); + + deriv = (fr - fl) / (2 * eps) * dirlen; + + + (*testout) << "bad2 = " << Func(x) << " der = " << deriv << endl; + + + return Func(x); + */ +} + + + + + + + + + + +#ifdef SOLIDGEOMxxxx +void Mesh :: ImproveMesh (const CSGeometry & geometry, OPTIMIZEGOAL goal) +{ + INDEX i, eli; + int j; + int typ = 1; + + if (!&geometry || geometry.GetNSurf() == 0) + { + ImproveMesh (goal); + return; + } + + char * savetask = multithread.task; + multithread.task = "Smooth Mesh"; + + + TABLE<INDEX> surfelementsonpoint(points.Size()); + Vector x(3), xsurf(2), xedge(1); + int surf, surf1, surf2, surf3; + + int uselocalh = mparam.uselocalh; + + (*testout).precision(8); + (*testout) << "Improve Mesh" << "\n"; + PrintMessage (3, "ImproveMesh"); + // (*mycout) << "Vol = " << CalcVolume (points, volelements) << endl; + + + for (i = 1; i <= surfelements.Size(); i++) + for (j = 1; j <= 3; j++) + surfelementsonpoint.Add1 (surfelements.Get(i).PNum(j), i); + + + PointFunction * pf; + if (typ == 1) + pf = new PointFunction(points, volelements); + else + pf = new CheapPointFunction(points, volelements); + + // pf->SetLocalH (h); + + Opti3FreeMinFunction freeminf(*pf); + Opti3SurfaceMinFunction surfminf(*pf); + Opti3EdgeMinFunction edgeminf(*pf); + + OptiParameters par; + par.maxit_linsearch = 20; + par.maxit_bfgs = 20; + + + + for (i = 1; i <= points.Size(); i++) + { + // if (ptyps.Get(i) == FIXEDPOINT) continue; + if (ptyps.Get(i) != INNERPOINT) continue; + + if (multithread.terminate) + throw NgException ("Meshing stopped"); + /* + if (multithread.terminate) + break; + */ + multithread.percent = 100.0 * i /points.Size(); + + if (points.Size() < 1000) + PrintDot (); + else + if (i % 10 == 0) + PrintDot ('+'); + + // (*testout) << "Now point " << i << "\n"; + // (*testout) << "Old: " << points.Get(i) << "\n"; + + pf->SetPointIndex (i); + + // if (uselocalh) + { + double lh = GetH (points.Get(i)); + pf->SetLocalH (GetH (points.Get(i))); + par.typx = lh / 10; + // (*testout) << "lh(" << points.Get(i) << ") = " << lh << "\n"; + } + + surf1 = surf2 = surf3 = 0; + + for (j = 1; j <= surfelementsonpoint.EntrySize(i); j++) + { + eli = surfelementsonpoint.Get(i, j); + int surfi = surfelements.Get(eli).GetIndex(); + + if (surfi) + { + surf = GetFaceDescriptor(surfi).SurfNr(); + + if (!surf1) + surf1 = surf; + else if (surf1 != surf) + { + if (!surf2) + surf2 = surf; + else if (surf2 != surf) + surf3 = surf; + } + } + else + { + surf1 = surf2 = surf3 = 1; // simulates corner point + } + } + + + if (surf2 && !surf3) + { + // (*testout) << "On Edge" << "\n"; + /* + xedge = 0; + edgeminf.SetPoint (geometry.GetSurface(surf1), + geometry.GetSurface(surf2), + points.Elem(i)); + BFGS (xedge, edgeminf, par); + + edgeminf.CalcNewPoint (xedge, points.Elem(i)); + */ + } + + if (surf1 && !surf2) + { + // (*testout) << "In Surface" << "\n"; + /* + xsurf = 0; + surfminf.SetPoint (geometry.GetSurface(surf1), + points.Get(i)); + BFGS (xsurf, surfminf, par); + + surfminf.CalcNewPoint (xsurf, points.Elem(i)); + */ + } + + if (!surf1) + { + // (*testout) << "In Volume" << "\n"; + x = 0; + freeminf.SetPoint (points.Elem(i)); + // par.typx = + BFGS (x, freeminf, par); + + points.Elem(i).X() += x.Get(1); + points.Elem(i).Y() += x.Get(2); + points.Elem(i).Z() += x.Get(3); + } + + // (*testout) << "New Point: " << points.Elem(i) << "\n" << "\n"; + + } + PrintDot ('\n'); + // (*mycout) << "Vol = " << CalcVolume (points, volelements) << endl; + + multithread.task = savetask; + +} +#endif + + +void Mesh :: ImproveMesh (OPTIMIZEGOAL goal) +{ + int typ = 1; + int j; + + (*testout) << "Improve Mesh" << "\n"; + PrintMessage (3, "ImproveMesh"); + + int np = GetNP(); + int ne = GetNE(); + + + ARRAY<double,PointIndex::BASE> perrs(np); + perrs = 1.0; + + double bad1 = 0; + double badmax = 0; + + if (goal == OPT_QUALITY) + { + for (int i = 1; i <= ne; i++) + { + const Element & el = VolumeElement(i); + if (el.GetType() != TET) + continue; + + double hbad = CalcBad (points, el, 0); + for (j = 0; j < 4; j++) + perrs[el[j]] += hbad; + + bad1 += hbad; + } + + for (PointIndex i = PointIndex::BASE; i < np+PointIndex::BASE; i++) + if (perrs[i] > badmax) + badmax = perrs[i]; + badmax = 0; + } + + if (goal == OPT_QUALITY) + { + bad1 = CalcTotalBad (points, volelements); + (*testout) << "Total badness = " << bad1 << endl; + PrintMessage (5, "Total badness = ", bad1); + } + + Vector x(3); + + (*testout).precision(8); + + int uselocalh = mparam.uselocalh; + + + PointFunction * pf; + + if (typ == 1) + pf = new PointFunction(points, volelements); + else + pf = new CheapPointFunction(points, volelements); + + // pf->SetLocalH (h); + + Opti3FreeMinFunction freeminf(*pf); + + OptiParameters par; + par.maxit_linsearch = 20; + par.maxit_bfgs = 20; + + + char * savetask = multithread.task; + multithread.task = "Smooth Mesh"; + + for (PointIndex i = PointIndex::BASE; + i < points.Size()+PointIndex::BASE; i++) + if (PointType(i) == INNERPOINT && perrs[i] > 0.01 * badmax) + { + if (multithread.terminate) + throw NgException ("Meshing stopped"); + + multithread.percent = 100.0 * (i+1-PointIndex::BASE) / points.Size(); + + if (points.Size() < 1000) + PrintDot (); + else + if ( (i+1-PointIndex::BASE) % 10 == 0) + PrintDot ('+'); + + double lh = GetH(points[i]); + pf->SetLocalH (lh); + par.typx = lh; + + freeminf.SetPoint (points[i]); + pf->SetPointIndex (i); + + x = 0; + int pok; + pok = freeminf.Func (x) < 1e10; + + if (!pok) + { + pok = pf->MovePointToInner (); + + freeminf.SetPoint (points[i]); + pf->SetPointIndex (i); + } + + if (pok) + { + BFGS (x, freeminf, par); + + points[i].X() += x.Get(1); + points[i].Y() += x.Get(2); + points[i].Z() += x.Get(3); + } + } + PrintDot ('\n'); + + + delete pf; + + multithread.task = savetask; + + if (goal == OPT_QUALITY) + { + bad1 = CalcTotalBad (points, volelements); + (*testout) << "Total badness = " << bad1 << endl; + PrintMessage (5, "Total badness = ", bad1); + } +} + + + + +// Improve Condition number of Jacobian, any elements +void Mesh :: ImproveMeshJacobian (OPTIMIZEGOAL goal) +{ + int i, j; + + (*testout) << "Improve Mesh Jacobian" << "\n"; + PrintMessage (3, "ImproveMesh Jacobian"); + + int np = GetNP(); + int ne = GetNE(); + + + Vector x(3); + + (*testout).precision(8); + + JacobianPointFunction pf(points, volelements); + + + OptiParameters par; + par.maxit_linsearch = 20; + par.maxit_bfgs = 20; + + BitArray badnodes(np); + badnodes.Clear(); + + for (i = 1; i <= ne; i++) + { + const Element & el = VolumeElement(i); + double bad = el.CalcJacobianBadness (Points()); + if (bad > 1) + for (j = 1; j <= el.GetNP(); j++) + badnodes.Set (el.PNum(j)); + } + + + char * savetask = multithread.task; + multithread.task = "Smooth Mesh Jacobian"; + + for (i = 1; i <= points.Size(); i++) + if (PointType(i) == INNERPOINT) + { + + (*testout) << "improvejac, p = " << i << endl; + + if (goal == OPT_WORSTCASE && !badnodes.Test(i)) + continue; + // (*testout) << "smoot p " << i << endl; + + /* + if (multithread.terminate) + break; + */ + if (multithread.terminate) + throw NgException ("Meshing stopped"); + + multithread.percent = 100.0 * i / points.Size(); + + if (points.Size() < 1000) + PrintDot (); + else + if (i % 10 == 0) + PrintDot ('+'); + + double lh = GetH(points.Get(i)); + par.typx = lh; + + pf.SetPointIndex (i); + + x = 0; + int pok = (pf.Func (x) < 1e10); + + if (pok) + { + BFGS (x, pf, par); + + points.Elem(i).X() += x.Get(1); + points.Elem(i).Y() += x.Get(2); + points.Elem(i).Z() += x.Get(3); + } + else + { + cout << "el not ok" << endl; + } + } + PrintDot ('\n'); + + + multithread.task = savetask; +} + + + + +} diff --git a/contrib/Netgen/libsrc/meshing/specials.cpp b/contrib/Netgen/libsrc/meshing/specials.cpp new file mode 100644 index 0000000000..ae9877cc2e --- /dev/null +++ b/contrib/Netgen/libsrc/meshing/specials.cpp @@ -0,0 +1,193 @@ +#include <mystdlib.h> +#include "meshing.hpp" + + +namespace netgen +{ + +// A special function for Hermann Landes, Erlangen + + +void CutOffAndCombine (Mesh & mesh, const Mesh & othermesh) +{ + int i, j; + int nse = othermesh.GetNSE(); + int onp = othermesh.GetNP(); + + int ne = mesh.GetNE(); + + PrintMessage (1, "other mesh has ", + othermesh.GetNP(), " points, ", + othermesh.GetNSE(), " surface elements."); + + ARRAY<Box3d> otherbounds(nse); + Box3d otherbox; + + double maxh = 0; + for (i = 1; i <= nse; i++) + { + const Element2d & sel = othermesh.SurfaceElement(i); + sel.GetBox(othermesh.Points(), otherbounds.Elem(i)); + + double loch = othermesh.GetH (othermesh.Point (sel.PNum(1))); + otherbounds.Elem(i).Increase(loch); + if (loch > maxh) maxh = loch; + } + + otherbox.SetPoint (othermesh.Point(1)); + for (i = 1; i <= othermesh.GetNP(); i++) + otherbox.AddPoint (othermesh.Point(i)); + otherbox.Increase (maxh); + + for (i = 1; i <= ne; i++) + { + Box3d box; + int remove = 0; + + const Element & el = mesh.VolumeElement(i); + el.GetBox(mesh.Points(), box); + + if (i % 10000 == 0) + cout << "+" << flush; + + if (box.Intersect(otherbox)) + { + for (j = 1; j <= nse && !remove; j++) + if (box.Intersect(otherbounds.Get(j))) + remove = 1; + } + + if (remove) + mesh.VolumeElement(i).Delete(); + } + cout << endl; + + BitArray connected(mesh.GetNP()); + connected.Clear(); + for (i = 1; i <= mesh.GetNSE(); i++) + { + const Element2d & el = mesh.SurfaceElement(i); + for (j = 1; j <= 3; j++) + connected.Set(el.PNum(j)); + } + + bool changed; + do + { + changed = 0; + for (i = 1; i <= mesh.GetNE(); i++) + { + const Element & el = mesh.VolumeElement(i); + int has = 0, hasnot = 0; + if (el[0]) + { + for (j = 0; j < 4; j++) + { + if (connected.Test(el[j])) + has = 1; + else + hasnot = 1; + } + if (has && hasnot) + { + changed = 1; + for (j = 0; j < 4; j++) + connected.Set (el[j]); + } + } + } + cout << "." << flush; + } + while (changed); + cout << endl; + + for (i = 1; i <= mesh.GetNE(); i++) + { + const Element & el = mesh.VolumeElement(i); + int hasnot = 0; + if (el[0]) + { + for (j = 0; j < 4; j++) + { + if (!connected.Test(el[j])) + hasnot = 1; + } + if (hasnot) + mesh.VolumeElement(i).Delete(); + } + } + + mesh.Compress(); + + mesh.FindOpenElements(); + BitArray locked(mesh.GetNP()); + locked.Set(); + for (i = 1; i <= mesh.GetNOpenElements(); i++) + for (j = 1; j <= 3; j++) + locked.Clear (mesh.OpenElement(i).PNum(j)); + + for (i = 1; i <= locked.Size(); i++) + if (locked.Test(i)) + { + mesh.AddLockedPoint (i); + } + + + + + ARRAY<int> pmat(onp); + + for (i = 1; i <= onp; i++) + pmat.Elem(i) = mesh.AddPoint (othermesh.Point(i)); + + int fnum = + mesh.AddFaceDescriptor (FaceDescriptor(0,0,1,0)); + + for (i = 1; i <= othermesh.GetNSE(); i++) + { + Element2d tri = othermesh.SurfaceElement(i); + for (j = 1; j <= 3; j++) + tri.PNum(j) = pmat.Get(tri.PNum(j)); + tri.SetIndex(fnum); + mesh.AddSurfaceElement (tri); + } + + for (i = 1; i <= onp; i++) + mesh.AddLockedPoint (pmat.Elem(i)); + + mesh.CalcSurfacesOfNode(); + mesh.CalcLocalH(); +} + + + + +void HelmholtzMesh (Mesh & mesh) +{ + int i, j; + double ri, ra, rinf; + + cout << "ri = "; + cin >> ri; + cout << "ra = "; + cin >> ra; + cout << "rinf = "; + cin >> rinf; + + double det = ri * ra * rinf - ri * ri * rinf; + double a = (ri - rinf) / det; + double b = (ri*ri - ra * rinf) / det; + for (i = 1; i <= mesh.GetNP(); i++) + { + Point3d & p = mesh.Point(i); + double rold = sqrt (sqr(p.X()) + sqr(p.Y()) + sqr(p.Z())); + if (rold < ri) continue; + + double rnew = 1 / (a * rold - b); + double fac = rnew / rold; + p.X() *= fac; + p.Y() *= fac; + p.Z() *= fac; + } +} +} diff --git a/contrib/Netgen/libsrc/meshing/specials.hpp b/contrib/Netgen/libsrc/meshing/specials.hpp new file mode 100644 index 0000000000..700ba4596b --- /dev/null +++ b/contrib/Netgen/libsrc/meshing/specials.hpp @@ -0,0 +1,16 @@ +#ifndef FILE_SPECIALS +#define FILE_SPECIALS + +/* + + Very special implementations .. + + */ + + +/// +extern void CutOffAndCombine (Mesh & mesh, const Mesh & othermesh); + +extern void HelmholtzMesh (Mesh & mesh); + +#endif diff --git a/contrib/Netgen/libsrc/meshing/tetrarls.cpp b/contrib/Netgen/libsrc/meshing/tetrarls.cpp new file mode 100644 index 0000000000..cb28648b6a --- /dev/null +++ b/contrib/Netgen/libsrc/meshing/tetrarls.cpp @@ -0,0 +1,1466 @@ +namespace netgen +{ +const char * tetrules[] = { +"tolfak 0.5\n",\ +"\n",\ +"rule \"Free Tetrahedron\"\n",\ +"\n",\ +"quality 1\n",\ +"\n",\ +"mappoints\n",\ +"(0, 0, 0);\n",\ +"(1, 0, 0);\n",\ +"(0.5, 0.866, 0);\n",\ +"\n",\ +"mapfaces\n",\ +"(1, 2, 3) del;\n",\ +"\n",\ +"newpoints\n",\ +"(0.5, 0.288, -0.816)\n",\ +" { 0.333 X1, 0.333 X2, 0.333 X3 }\n",\ +" { 0.333 Y1, 0.333 Y2, 0.333 Y3 } { };\n",\ +"\n",\ +"newfaces\n",\ +"(4, 1, 2);\n",\ +"(4, 2, 3);\n",\ +"(4, 3, 1);\n",\ +"\n",\ +"elements\n",\ +"(1, 2, 3, 4);\n",\ +"\n",\ +"freezone2\n",\ +"{ 1 P1 };\n",\ +"{ 1 P2 };\n",\ +"{ 1 P3 };\n",\ +"{ 1.6 P4, -0.2 P1, -0.2 P2, -0.2 P3 };\n",\ +"{ -0.5 P1, 0.5 P2, 0.5 P3, 0.5 P4 };\n",\ +"{ 0.5 P1, -0.5 P2, 0.5 P3, 0.5 P4 };\n",\ +"{ 0.5 P1, 0.5 P2, -0.5 P3, 0.5 P4 };\n",\ +"endrule\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"rule \"Tetrahedron 60\"\n",\ +"\n",\ +"quality 1\n",\ +"\n",\ +"flags c;\n",\ +"\n",\ +"mappoints\n",\ +"(0, 0, 0);\n",\ +"(1, 0, 0) { 0.5 } ;\n",\ +"(0.5, 0.866, 0) { 0.5 };\n",\ +"(0.5, 0.288, -0.816) { 0.5 };\n",\ +"\n",\ +"mapfaces\n",\ +"(1, 2, 3) del;\n",\ +"(1, 4, 2) del;\n",\ +"\n",\ +"newpoints\n",\ +"\n",\ +"newfaces\n",\ +"(1, 4, 3);\n",\ +"(4, 2, 3);\n",\ +"\n",\ +"elements\n",\ +"(1, 2, 3, 4);\n",\ +"\n",\ +"freezone2\n",\ +"{ 1 P1 };\n",\ +"{ 1 P2 };\n",\ +"{ 1 P3 };\n",\ +"{ 1 P4 };\n",\ +"{ -0.35 P1, 0.45 P2, 0.45 P3, 0.45 P4 };\n",\ +"{ 0.45 P1, -0.35 P2, 0.45 P3, 0.45 P4 };\n",\ +"{ -0.05 P1, -0.05 P2, 0.7 P3, 0.4 P4 };\n",\ +"\n",\ +"\n",\ +"freezonelimit\n",\ +"{ 1 P1 };\n",\ +"{ 1 P2 };\n",\ +"{ 1 P3 };\n",\ +"{ 1 P4 };\n",\ +"{ 0.3333 P2, 0.3333 P3, 0.3334 P4 };\n",\ +"{ 0.3333 P1, 0.3333 P3, 0.3334 P4 };\n",\ +"{ 0.65 P3, 0.35 P4 };\n",\ +"endrule\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"rule \"Tetrahedron 60 with edge(1)\"\n",\ +"\n",\ +"quality 1\n",\ +"\n",\ +"flags c;\n",\ +"\n",\ +"mappoints\n",\ +"(0, 0, 0);\n",\ +"(1, 0, 0) { 0.8 };\n",\ +"(0.5, 0.866, 0) { 0.8 };\n",\ +"(0.5, 0.288, -0.816) { 0.8 };\n",\ +"\n",\ +"mapfaces\n",\ +"(1, 2, 3) del;\n",\ +"(1, 4, 2) del;\n",\ +"\n",\ +"mapedges\n",\ +"(3, 4);\n",\ +"\n",\ +"newpoints\n",\ +"\n",\ +"newfaces\n",\ +"(1, 4, 3);\n",\ +"(4, 2, 3);\n",\ +"\n",\ +"elements\n",\ +"(1, 2, 3, 4);\n",\ +"\n",\ +"\n",\ +"freezone2\n",\ +"{ 1 P1 };\n",\ +"{ 1 P2 };\n",\ +"{ 1 P3 };\n",\ +"{ 1 P4 };\n",\ +"{ 0.4 P1, 0.4 P4, 0.4 P3, -0.2 P2 };\n",\ +"{ 0.4 P2, 0.4 P4, 0.4 P3, -0.2 P1 };\n",\ +"\n",\ +"freezonelimit\n",\ +"{ 1 P1 };\n",\ +"{ 1 P2 };\n",\ +"{ 1 P3 };\n",\ +"{ 1 P4 };\n",\ +"{ 0.3333 P1, 0.3333 P4, 0.3334 P3 };\n",\ +"{ 0.3333 P2, 0.3333 P4, 0.3334 P3 };\n",\ +"endrule\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"rule \"Tetrahedron Vis a Vis Point (1)\"\n",\ +"\n",\ +"quality 100\n",\ +"\n",\ +"mappoints\n",\ +"(0, 0, 0);\n",\ +"(1, 0, 0) { 0.5 };\n",\ +"(0.5, 0.866, 0) { 0.5 };\n",\ +"(0.5, 0.288, -0.816) { 0.5 };\n",\ +"\n",\ +"mapfaces\n",\ +"(1, 2, 3) del;\n",\ +"\n",\ +"newpoints\n",\ +"\n",\ +"newfaces\n",\ +"(4, 3, 1);\n",\ +"(4, 2, 3);\n",\ +"(4, 1, 2);\n",\ +"\n",\ +"elements\n",\ +"(1, 2, 3, 4);\n",\ +"\n",\ +"freezone2\n",\ +"{ 1 P1 };\n",\ +"{ 1 P2 };\n",\ +"{ 1 P3 };\n",\ +"{ 1 P4 };\n",\ +"{ -0.5 P1, 0.5 P2, 0.5 P3, 0.5 P4 };\n",\ +"{ 0.5 P1, -0.5 P2, 0.5 P3, 0.5 P4 };\n",\ +"{ 0.5 P1, 0.5 P2, -0.5 P3, 0.5 P4 };\n",\ +"{ 0.8 P1, -0.1 P2, -0.1 P3, 0.4 P4 };\n",\ +"{ -0.1 P1, 0.8 P2, -0.1 P3, 0.4 P4 };\n",\ +"{ -0.1 P1, -0.1 P2, 0.8 P3, 0.4 P4 };\n",\ +"\n",\ +"freezonelimit\n",\ +"{ 1 P1 };\n",\ +"{ 1 P2 };\n",\ +"{ 1 P3 };\n",\ +"{ 1 P4 };\n",\ +"{ 0.3333 P2, 0.3333 P3, 0.3334 P4 };\n",\ +"{ 0.3333 P1, 0.3333 P3, 0.3334 P4 };\n",\ +"{ 0.3333 P1, 0.3333 P2, 0.3334 P4 };\n",\ +"{ 0.7 P1, 0.3 P4 };\n",\ +"{ 0.7 P2, 0.3 P4 };\n",\ +"{ 0.7 P3, 0.3 P4 };\n",\ +"endrule\n",\ +"\n",\ +"\n",\ +"\n",\ +"rule \"Tetrahedron Vis a Vis Point with edge(1)\"\n",\ +"\n",\ +"quality 1\n",\ +"\n",\ +"\n",\ +"\n",\ +"mappoints\n",\ +"(0, 0, 0);\n",\ +"(1, 0, 0) { 0.5 };\n",\ +"(0.5, 0.866, 0) { 0.5 };\n",\ +"(0.5, 0.288, -0.816) { 0.5 };\n",\ +"\n",\ +"mapfaces\n",\ +"(1, 2, 3) del;\n",\ +"\n",\ +"mapedges\n",\ +"(1, 4);\n",\ +"\n",\ +"newpoints\n",\ +"\n",\ +"newfaces\n",\ +"(4, 3, 1);\n",\ +"(4, 2, 3);\n",\ +"(4, 1, 2);\n",\ +"\n",\ +"elements\n",\ +"(1, 2, 3, 4);\n",\ +"\n",\ +"\n",\ +"freezone2\n",\ +"{ 1 P1 };\n",\ +"{ 1 P2 };\n",\ +"{ 1 P3 };\n",\ +"{ 1 P4 };\n",\ +"{ -0.35 P1, 0.45 P2, 0.45 P3, 0.45 P4 };\n",\ +"{ 0.45 P1, -0.35 P2, 0.45 P3, 0.45 P4 };\n",\ +"{ 0.45 P1, 0.45 P2, -0.35 P3, 0.45 P4 };\n",\ +"{ -0.05 P1, 0.7 P2, -0.05 P3, 0.4 P4 };\n",\ +"{ -0.05 P1, -0.05 P2, 0.7 P3, 0.4 P4 };\n",\ +"\n",\ +"freezonelimit\n",\ +"{ 1 P1 };\n",\ +"{ 1 P2 };\n",\ +"{ 1 P3 };\n",\ +"{ 1 P4 };\n",\ +"{ 0.3333 P2, 0.3333 P3, 0.3334 P4 };\n",\ +"{ 0.3333 P1, 0.3333 P3, 0.3334 P4 };\n",\ +"{ 0.3333 P1, 0.3333 P2, 0.3334 P4 };\n",\ +"{ 0.65 P2, 0.35 P4 };\n",\ +"{ 0.65 P3, 0.35 P4 };\n",\ +"endrule\n",\ +"\n",\ +"\n",\ +"\n",\ +"rule \"Tetrahedron Vis a Vis Point with 2 edges (1)\"\n",\ +"\n",\ +"quality 1\n",\ +"\n",\ +"mappoints\n",\ +"(0, 0, 0);\n",\ +"(1, 0, 0) { 0.5 };\n",\ +"(0.5, 0.866, 0) { 0.5 };\n",\ +"(0.5, 0.288, -0.816) { 0.5 };\n",\ +"\n",\ +"mapfaces\n",\ +"(1, 2, 3) del;\n",\ +"\n",\ +"mapedges\n",\ +"(1, 4);\n",\ +"(2, 4);\n",\ +"\n",\ +"newpoints\n",\ +"\n",\ +"newfaces\n",\ +"(4, 3, 1);\n",\ +"(4, 2, 3);\n",\ +"(4, 1, 2);\n",\ +"\n",\ +"elements\n",\ +"(1, 2, 3, 4);\n",\ +"\n",\ +"\n",\ +"freezone2\n",\ +"{ 1 P1 };\n",\ +"{ 1 P2 };\n",\ +"{ 1 P3 };\n",\ +"{ 1 P4 };\n",\ +"{ -0.35 P1, 0.45 P2, 0.45 P3, 0.45 P4 };\n",\ +"{ 0.45 P1, -0.35 P2, 0.45 P3, 0.45 P4 };\n",\ +"{ 0.45 P1, 0.45 P2, -0.35 P3, 0.45 P4 };\n",\ +"{ -0.05 P1, -0.05 P2, 0.7 P3, 0.4 P4 };\n",\ +"\n",\ +"freezonelimit\n",\ +"{ 1 P1 };\n",\ +"{ 1 P2 };\n",\ +"{ 1 P3 };\n",\ +"{ 1 P4 };\n",\ +"{ 0.3333 P2, 0.3333 P3, 0.3334 P4 };\n",\ +"{ 0.3333 P1, 0.3333 P3, 0.3334 P4 };\n",\ +"{ 0.3333 P1, 0.3333 P2, 0.3334 P4 };\n",\ +"{ 0.65 P3, 0.35 P4 };\n",\ +"endrule\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"rule \"Tetrahedron Vis a Vis Point with 3 edges (1)\"\n",\ +"\n",\ +"quality 1\n",\ +"\n",\ +"mappoints\n",\ +"(0, 0, 0);\n",\ +"(1, 0, 0) { 0.5 };\n",\ +"(0.5, 0.866, 0) { 0.5 };\n",\ +"(0.5, 0.288, -0.816) { 0.5 };\n",\ +"\n",\ +"mapfaces\n",\ +"(1, 2, 3) del;\n",\ +"\n",\ +"mapedges\n",\ +"(1, 4);\n",\ +"(2, 4);\n",\ +"(3, 4);\n",\ +"\n",\ +"newpoints\n",\ +"\n",\ +"newfaces\n",\ +"(4, 3, 1);\n",\ +"(4, 2, 3);\n",\ +"(4, 1, 2);\n",\ +"\n",\ +"elements\n",\ +"(1, 2, 3, 4);\n",\ +"\n",\ +"\n",\ +"freezone2\n",\ +"{ 1 P1 };\n",\ +"{ 1 P2 };\n",\ +"{ 1 P3 };\n",\ +"{ 1 P4 };\n",\ +"{ -0.35 P1, 0.45 P2, 0.45 P3, 0.45 P4 };\n",\ +"{ 0.45 P1, -0.35 P2, 0.45 P3, 0.45 P4 };\n",\ +"{ 0.45 P1, 0.45 P2, -0.35 P3, 0.45 P4 };\n",\ +"\n",\ +"freezonelimit\n",\ +"{ 1 P1 };\n",\ +"{ 1 P2 };\n",\ +"{ 1 P3 };\n",\ +"{ 1 P4 };\n",\ +"{ 0.3333 P2, 0.3333 P3, 0.3334 P4 };\n",\ +"{ 0.3333 P1, 0.3333 P3, 0.3334 P4 };\n",\ +"{ 0.3333 P1, 0.3333 P2, 0.3334 P4 };\n",\ +"endrule\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"rule \"Tetrahedron Vis a Vis Triangle (1)\"\n",\ +"\n",\ +"quality 100\n",\ +"\n",\ +"mappoints\n",\ +"(0, 0, 0);\n",\ +"(1, 0, 0) { 0.5 };\n",\ +"(0.5, 0.866, 0) { 0.5 };\n",\ +"(0, 0, -0.816) { 0.5 };\n",\ +"(1, 0, -0.816) { 0.5 };\n",\ +"(0.5, 0.866, -0.816) { 0.5 };\n",\ +"\n",\ +"mapfaces\n",\ +"(1, 2, 3) del;\n",\ +"(4, 6, 5) del;\n",\ +"\n",\ +"newpoints\n",\ +"\n",\ +"newfaces\n",\ +"(1, 2, 4);\n",\ +"(2, 5, 4);\n",\ +"(2, 3, 6);\n",\ +"(2, 6, 5);\n",\ +"(3, 1, 4);\n",\ +"(3, 4, 6);\n",\ +"\n",\ +"\n",\ +"elements\n",\ +"(1, 2, 3, 4);\n",\ +"(4, 2, 3, 6);\n",\ +"(4, 2, 6, 5);\n",\ +"\n",\ +"freezone2\n",\ +"{ 1 P1 };\n",\ +"{ 1 P2 };\n",\ +"{ 1 P3 };\n",\ +"{ 1 P4 };\n",\ +"{ 1 P5 };\n",\ +"{ 1 P6 };\n",\ +"{ -0.2 P1, 0.35 P2, 0.35 P3, -0.2 P4, 0.35 P5, 0.35 P6 };\n",\ +"{ 0.35 P1, -0.2 P2, 0.35 P3, 0.35 P4, -0.2 P5, 0.35 P6 };\n",\ +"{ 0.35 P1, 0.35 P2, -0.2 P3, 0.35 P4, 0.35 P5, -0.2 P6 };\n",\ +"endrule\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"rule \"Octaeder 1\"\n",\ +"\n",\ +"quality 100\n",\ +"\n",\ +"mappoints\n",\ +"(0, 0, 0);\n",\ +"(1, 0, 0) { 0.95 };\n",\ +"(0.5, 0.866, 0) { 0.95 };\n",\ +"(0.5, -0.288, -0.816) { 0.5 };\n",\ +"\n",\ +"mapfaces\n",\ +"(1, 2, 3) del;\n",\ +"(1, 4, 2) del;\n",\ +"\n",\ +"newpoints\n",\ +"(1, 0.578, -0.816) { 0.5 X3, 0.5 X4 } { 0.5 Y3, 0.5 Y4} { 0.5 Z3, 0.5 Z4 };\n",\ +"(0, 0.578, -0.816) { 0.5 X3, 0.5 X4 } { 0.5 Y3, 0.5 Y4} { 0.5 Z3, 0.5 Z4 };\n",\ +"\n",\ +"newfaces\n",\ +"(2, 3, 5);\n",\ +"(3, 1, 6);\n",\ +"(3, 6, 5);\n",\ +"(2, 5, 4);\n",\ +"(1, 4, 6);\n",\ +"(4, 5, 6);\n",\ +"\n",\ +"elements\n",\ +"(3, 4, 1, 2);\n",\ +"(3, 4, 2, 5);\n",\ +"(3, 4, 5, 6);\n",\ +"(3, 4, 6, 1);\n",\ +"\n",\ +"freezone\n",\ +"(0, 0, 0);\n",\ +"(1, 0, 0) { 1 X2 } { } { };\n",\ +"(0.5, 0.866, 0) { 1 X3 } { 1 Y3 } { };\n",\ +"(0.5, -0.288, -0.816) { 1 X4 } { 1 Y4 } { 1 Z4 };\n",\ +"(-0.5, 1, -1.5) { 0.5 X3, 0.5 X4 } { 0.5 Y3, 0.5 Y4 } { 1 Z4 };\n",\ +"( 1.5, 1, -1.5) { 0.5 X3, 0.5 X4 } { 0.5 Y3, 0.5 Y4 } { 1 Z4 };\n",\ +"\n",\ +"endrule\n",\ +"\n",\ +"\n",\ +"\n",\ +"rule \"Octaeder 2\"\n",\ +"\n",\ +"quality 100\n",\ +"\n",\ +"mappoints\n",\ +"(0, 0, 0);\n",\ +"(1, 0, 0) { 0.95 };\n",\ +"(0.5, 0.866, 0) { 0.95 };\n",\ +"(0.5, -0.288, -0.816) { 0.5 };\n",\ +"(1, 0.578, -0.816) { 0.5 };\n",\ +"\n",\ +"mapfaces\n",\ +"(1, 2, 3) del;\n",\ +"(1, 4, 2) del;\n",\ +"\n",\ +"newpoints\n",\ +"(0, 0.578, -0.816) { 0.5 X3, 0.5 X4 } { 0.5 Y3, 0.5 Y4} { 0.5 Z3, 0.5 Z4 };\n",\ +"\n",\ +"newfaces\n",\ +"(2, 3, 5);\n",\ +"(3, 1, 6);\n",\ +"(3, 6, 5);\n",\ +"(2, 5, 4);\n",\ +"(1, 4, 6);\n",\ +"(4, 5, 6);\n",\ +"\n",\ +"elements\n",\ +"(3, 4, 1, 2);\n",\ +"(3, 4, 2, 5);\n",\ +"(3, 4, 5, 6);\n",\ +"(3, 4, 6, 1);\n",\ +"\n",\ +"freezone\n",\ +"(0, 0, 0);\n",\ +"(1, 0, 0) { 1 X2 } { } { };\n",\ +"(0.5, 0.866, 0) { 1 X3 } { 1 Y3 } { };\n",\ +"(0.5, -0.288, -0.816) { 1 X4 } { 1 Y4 } { 1 Z4 };\n",\ +"(1, 0.578, -0.816) { 1 X5 } { 1 Y5 } { 1 Z5 };\n",\ +"\n",\ +"(0.9, 0.097, -0.544) { 0.333 X2, 0.333 X4, 0.333 X5 }\n",\ +" { 0.333 Y2, 0.333 Y4, 0.333 Y5 }\n",\ +" { 0.333 Z2, 0.333 Z4, 0.333 Z5 };\n",\ +"(0.9, 0.481, -0.272) { 0.333 X2, 0.333 X3, 0.333 X5 }\n",\ +" { 0.333 Y2, 0.333 Y3, 0.333 Y5 }\n",\ +" { 0.333 Z2, 0.333 Z3, 0.333 Z5 };\n",\ +"\n",\ +"(-0.5, 1, -1.5) { 0.5 X3, 0.5 X4 } { 0.5 Y3, 0.5 Y4 } { 0.5 Z4, 0.5 Z5 };\n",\ +"\n",\ +"endrule\n",\ +"\n",\ +"\n",\ +"rule \"Octaeder 2a\"\n",\ +"\n",\ +"\n",\ +"quality 100\n",\ +"\n",\ +"mappoints\n",\ +"(0, 0, 0);\n",\ +"(1, 0, 0) { 0.95 };\n",\ +"(0.5, 0.866, 0) { 0.95 };\n",\ +"(0.5, -0.288, -0.816) { 0.5 };\n",\ +"(1, 0.578, -0.816) { 0.5 };\n",\ +"\n",\ +"mapfaces\n",\ +"(1, 2, 3) del;\n",\ +"(3, 2, 5) del;\n",\ +"\n",\ +"newpoints\n",\ +"(0, 0.578, -0.816)\n",\ +" { -1 X2, 1 X3, 1 X4 }\n",\ +" { -1 Y2, 1 Y3, 1 Y4 }\n",\ +" { -1 Z2, 1 Z3, 1 Z4 };\n",\ +"\n",\ +"newfaces\n",\ +"(1, 2, 4);\n",\ +"(3, 1, 6);\n",\ +"(3, 6, 5);\n",\ +"(2, 5, 4);\n",\ +"(1, 4, 6);\n",\ +"(4, 5, 6);\n",\ +"\n",\ +"elements\n",\ +"(3, 4, 1, 2);\n",\ +"(3, 4, 2, 5);\n",\ +"(3, 4, 5, 6);\n",\ +"(3, 4, 6, 1);\n",\ +"\n",\ +"freezone\n",\ +"(0, 0, 0);\n",\ +"(1, 0, 0) { 1 X2 } { } { };\n",\ +"(0.5, 0.866, 0) { 1 X3 } { 1 Y3 } { };\n",\ +"(0.5, -0.288, -0.816) { 1 X4 } { 1 Y4 } { 1 Z4 };\n",\ +"(1, 0.578, -0.816) { 1 X5 } { 1 Y5 } { 1 Z5 };\n",\ +"\n",\ +"(0.9, 0.097, -0.544) { 0.333 X2, 0.333 X4, 0.333 X5 }\n",\ +" { 0.333 Y2, 0.333 Y4, 0.333 Y5 }\n",\ +" { 0.333 Z2, 0.333 Z4, 0.333 Z5 };\n",\ +"\n",\ +"(0.5, -0.097, -0.272) { 0.333 X2, 0.333 X4, 0.333 X1 }\n",\ +" { 0.333 Y2, 0.333 Y4, 0.333 Y1 }\n",\ +" { 0.333 Z2, 0.333 Z4, 0.333 Z1 };\n",\ +"\n",\ +"(-0.5, 1, -1.5) { 0.5 X3, 0.5 X4 } { 0.5 Y3, 0.5 Y4 } { 0.5 Z4, 0.5 Z5 };\n",\ +"\n",\ +"endrule\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"rule \"Pyramid 1\"\n",\ +"\n",\ +"quality 100\n",\ +"\n",\ +"mappoints\n",\ +"(0, 0, 0);\n",\ +"(1, 0, 0) { 1 };\n",\ +"(0.5, 0.866, 0) { 1 };\n",\ +"(0.5, -0.288, -0.816) { 1 };\n",\ +"\n",\ +"mapfaces\n",\ +"(1, 2, 3) del;\n",\ +"(1, 4, 2) del;\n",\ +"\n",\ +"newpoints\n",\ +"(1, 0.578, -0.816) { 0.5 X3, 0.5 X4 } { 0.5 Y3, 0.5 Y4} { 0.5 Z3, 0.5 Z4 };\n",\ +"\n",\ +"newfaces\n",\ +"(1, 4, 3);\n",\ +"(2, 3, 5);\n",\ +"(2, 5, 4);\n",\ +"(4, 5, 3);\n",\ +"\n",\ +"elements\n",\ +"(1, 2, 3, 4);\n",\ +"(4, 2, 3, 5);\n",\ +"\n",\ +"\n",\ +"freezone\n",\ +"(0, 0, 0);\n",\ +"(1, 0, 0) { 1 X2 } { } { };\n",\ +"(0.5, 0.866, 0) { 1 X3 } { 1 Y3 } { };\n",\ +"(0.5, -0.288, -0.816) { 1 X4 } { 1 Y4 } { 1 Z4 };\n",\ +"(0, 1, -1) { 0.5 X3, 0.5 X4 } { 1 Y3 } { 1 Z4 };\n",\ +"(1.5, 1, -1.5) { 0.5 X3, 0.5 X4 } { 0.5 Y3, 0.5 Y4} { 0.5 Z3, 0.5 Z4 };\n",\ +"\n",\ +"endrule\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"rule \"Tetrahedron 2 times 60\"\n",\ +"\n",\ +"quality 1\n",\ +"\n",\ +"mappoints\n",\ +"(0, 0, 0);\n",\ +"(1, 0, 0) { 0.3 };\n",\ +"(0.5, 0.866, 0) { 0.3 };\n",\ +"(0.5, 0.288, -0.816) { 0.3 };\n",\ +"\n",\ +"mapfaces\n",\ +"(1, 2, 3) del;\n",\ +"(1, 4, 2) del;\n",\ +"(2, 4, 3) del;\n",\ +"\n",\ +"newpoints\n",\ +"\n",\ +"newfaces\n",\ +"(1, 4, 3);\n",\ +"\n",\ +"elements\n",\ +"(1, 2, 3, 4);\n",\ +"\n",\ +"freezone2\n",\ +"{ 1 P1 };\n",\ +"{ 1 P2 };\n",\ +"{ 1 P3 };\n",\ +"{ 1 P4 };\n",\ +"{ 0.4 P1, 0.4 P4, 0.4 P3, -0.2 P2 };\n",\ +"\n",\ +"freezonelimit\n",\ +"{ 1 P1 };\n",\ +"{ 1 P2 };\n",\ +"{ 1 P3 };\n",\ +"{ 1 P4 };\n",\ +"{ 0.3333 P1, 0.3333 P3, 0.3334 P4 };\n",\ +"endrule\n",\ +"\n",\ +"\n",\ +"\n",\ +"rule \"Fill Tetrahedron (1)\"\n",\ +"\n",\ +"quality 1\n",\ +"\n",\ +"mappoints\n",\ +"(0, 0, 0);\n",\ +"(1, 0, 0) { 0.2 };\n",\ +"(0.5, 0.866, 0) { 0.2 };\n",\ +"(0.5, 0.288, -0.816) { 0.2 };\n",\ +"\n",\ +"mapfaces\n",\ +"(1, 2, 3) del;\n",\ +"(1, 4, 2) del;\n",\ +"(2, 4, 3) del;\n",\ +"(3, 4, 1) del;\n",\ +"\n",\ +"newpoints\n",\ +"\n",\ +"newfaces\n",\ +"\n",\ +"elements\n",\ +"(1, 2, 3, 4);\n",\ +"\n",\ +"freezone2\n",\ +"{ 1 P1 };\n",\ +"{ 1 P2 };\n",\ +"{ 1 P3 };\n",\ +"{ 1 P4 };\n",\ +"endrule\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"rule \"Tetrahedron 120 (1)\"\n",\ +"\n",\ +"quality 1\n",\ +"\n",\ +"mappoints\n",\ +"(0, 0, 0);\n",\ +"(1, 0, 0) { 1 };\n",\ +"(0.5, 0.866, 0) { 1 };\n",\ +"(0.5, -0.674, -0.544) { 1 };\n",\ +"\n",\ +"mapfaces\n",\ +"(1, 2, 3) del;\n",\ +"(1, 4, 2) del;\n",\ +"\n",\ +"newpoints\n",\ +"(0.5, 0.288, -0.816)\n",\ +" { -0.5 X1, -0.5 X2, 1 X3, 1 X4 }\n",\ +" { -0.5 Y1, -0.5 Y2, 1 Y3, 1 Y4}\n",\ +" { -0.5 Z1, -0.5 Z2, 1 Z3, 1 Z4};\n",\ +"\n",\ +"newfaces\n",\ +"(1, 5, 3);\n",\ +"(3, 5, 2);\n",\ +"(1, 4, 5);\n",\ +"(2, 5, 4);\n",\ +"\n",\ +"elements\n",\ +"(1, 2, 3, 5);\n",\ +"(1, 4, 2, 5);\n",\ +"\n",\ +"\n",\ +"freezone2\n",\ +"{ 1 P1 };\n",\ +"{ 1 P2 };\n",\ +"{ 1 P3 };\n",\ +"{ 1 P4 };\n",\ +"{ 1.3 P5, -0.3 P1 };\n",\ +"{ 1.3 P5, -0.3 P2 };\n",\ +"\n",\ +"freezonelimit\n",\ +"{ 1 P1 };\n",\ +"{ 1 P2 };\n",\ +"{ 1 P3 };\n",\ +"{ 1 P4 };\n",\ +"{ 1 P5 };\n",\ +"{ 1 P5 };\n",\ +"endrule\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"rule \"Tetrahedron 2 times 120 (1)\"\n",\ +"\n",\ +"quality 100\n",\ +"\n",\ +"mappoints\n",\ +"(0, 0, 0);\n",\ +"(1, 0, 0) { 1 };\n",\ +"(0.5, 0.866, 0) { 1 };\n",\ +"(0.5, -0.674, -0.544) { 0.8 };\n",\ +"(1.334, 0.77, -0.544) { 0.8 };\n",\ +"\n",\ +"mapfaces\n",\ +"(1, 2, 3) del;\n",\ +"(1, 4, 2) del;\n",\ +"(3, 2, 5) del;\n",\ +"\n",\ +"newpoints\n",\ +"(0.5, 0.288, -0.816) { 0.25 X1, -0.5 X2, 0.25 X3, 0.5 X4, 0.5 X5 }\n",\ +" { 0.25 Y1, -0.5 Y2, 0.25 Y3, 0.5 Y4, 0.5 Y5 }\n",\ +" { 0.25 Z1, -0.5 Z2, 0.25 Z3, 0.5 Z4, 0.5 Z5 };\n",\ +"\n",\ +"newfaces\n",\ +"(6, 3, 1);\n",\ +"(6, 1, 4);\n",\ +"(6, 4, 2);\n",\ +"(6, 2, 5);\n",\ +"(6, 5, 3);\n",\ +"\n",\ +"elements\n",\ +"(1, 2, 3, 6);\n",\ +"(1, 4, 2, 6);\n",\ +"(2, 5, 3, 6);\n",\ +"\n",\ +"freezone2\n",\ +"{ 1 P1 };\n",\ +"{ 1 P2 };\n",\ +"{ 1 P3 };\n",\ +"{ 1 P4 };\n",\ +"{ 1 P5 };\n",\ +"{ 1.4 P6, -0.4 P2 };\n",\ +"{ 1.4 P6, -0.4 P1 };\n",\ +"{ 1.4 P6, -0.4 P3 };\n",\ +"endrule\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"rule \"four Tetrahedron non convex (4)\"\n",\ +"\n",\ +"quality 4\n",\ +"flags l;\n",\ +"\n",\ +"mappoints\n",\ +"(0, 0, 0);\n",\ +"(1, 0, 0) { 0.1 };\n",\ +"(0.5, 1, 0) { 0.1 };\n",\ +"(0.5, 0, -1) { 0.1 };\n",\ +"(0.5, 0.3, -0.3) { 0.1 };\n",\ +"\n",\ +"mapfaces\n",\ +"(1, 2, 3) del;\n",\ +"(1, 4, 2) del;\n",\ +"(1, 5, 4) del;\n",\ +"(1, 3, 5) del;\n",\ +"\n",\ +"\n",\ +"newpoints\n",\ +"(0.5, 0.1, -0.1)\n",\ +" { 0.333 X1, 0.333 X2, 0.334 X5 }\n",\ +" { 0.333 Y1, 0.333 Y2, 0.334 Y5 }\n",\ +" { 0.333 Z1, 0.333 Z2, 0.334 Z5 };\n",\ +"\n",\ +"newfaces\n",\ +"(6, 2, 3) del;\n",\ +"(6, 4, 2) del;\n",\ +"(6, 5, 4) del;\n",\ +"(6, 3, 5) del;\n",\ +"\n",\ +"\n",\ +"elements\n",\ +"(1, 2, 3, 6);\n",\ +"(1, 4, 2, 6);\n",\ +"(1, 5, 4, 6);\n",\ +"(1, 3, 5, 6);\n",\ +"\n",\ +"\n",\ +"freezone2\n",\ +"{ 1 P1 };\n",\ +"{ 1 P2 };\n",\ +"{ 1 P3 };\n",\ +"{ 1 P4 };\n",\ +"{ 1 P5 };\n",\ +"{ 1.5 P6, -0.5 P1 };\n",\ +"\n",\ +"freezonelimit\n",\ +"{ 1 P1 };\n",\ +"{ 1 P2 };\n",\ +"{ 1 P3 };\n",\ +"{ 1 P4 };\n",\ +"{ 1 P5 };\n",\ +"{ 1 P6 };\n",\ +"\n",\ +"\n",\ +"\n",\ +"freeset\n",\ +"1 6 2 3;\n",\ +"\n",\ +"freeset\n",\ +"1 6 3 5;\n",\ +"\n",\ +"freeset\n",\ +"1 6 5 4;\n",\ +"\n",\ +"freeset\n",\ +"1 6 4 2;\n",\ +"\n",\ +"endrule\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"rule \"five Tetrahedron non convex (4)\"\n",\ +"\n",\ +"quality 4\n",\ +"flags l;\n",\ +"\n",\ +"mappoints\n",\ +"(0, 0, 0);\n",\ +"(1, 0, 0) { 0.5 };\n",\ +"(0.5, 1, 0) { 0.5 };\n",\ +"(0, 0.8, -0.2) { 0.5 };\n",\ +"(0, 0.2, -0.8) { 0.5 };\n",\ +"(0.5, 0, -1) { 0.5 };\n",\ +"\n",\ +"\n",\ +"mapfaces\n",\ +"(1, 2, 3) del;\n",\ +"(1, 3, 4) del;\n",\ +"(1, 4, 5) del;\n",\ +"(1, 5, 6) del;\n",\ +"(1, 6, 2) del;\n",\ +"\n",\ +"newpoints\n",\ +"(0.1, 0.1, -0.1)\n",\ +" { 0.75 X1, 0.05 X2, 0.05 X3, 0.05 X4, 0.05 X5, 0.05 X6 }\n",\ +" { 0.75 Y1, 0.05 Y2, 0.05 Y3, 0.05 Y4, 0.05 Y5, 0.05 Y6 }\n",\ +" { 0.75 Z1, 0.05 Z2, 0.05 Z3, 0.05 Z4, 0.05 Z5, 0.05 Z6 };\n",\ +"\n",\ +"newfaces\n",\ +"(7, 2, 3);\n",\ +"(7, 3, 4);\n",\ +"(7, 4, 5);\n",\ +"(7, 5, 6);\n",\ +"(7, 6, 2);\n",\ +"\n",\ +"\n",\ +"elements\n",\ +"(1, 2, 3, 7);\n",\ +"(1, 3, 4, 7);\n",\ +"(1, 4, 5, 7);\n",\ +"(1, 5, 6, 7);\n",\ +"(1, 6, 2, 7);\n",\ +"\n",\ +"\n",\ +"freezone2\n",\ +"{ 1 P1 };\n",\ +"{ 1 P2 };\n",\ +"{ 1 P3 };\n",\ +"{ 1 P4 };\n",\ +"{ 1 P5 };\n",\ +"{ 1 P6 };\n",\ +"{ 1.5 P7, -0.5 P1 };\n",\ +"\n",\ +"freezonelimit\n",\ +"{ 1 P1 };\n",\ +"{ 1 P2 };\n",\ +"{ 1 P3 };\n",\ +"{ 1 P4 };\n",\ +"{ 1 P5 };\n",\ +"{ 1 P6 };\n",\ +"{ 1 P7 };\n",\ +"\n",\ +"\n",\ +"\n",\ +"freeset\n",\ +"1 7 2 3;\n",\ +"\n",\ +"freeset\n",\ +"1 7 3 4;\n",\ +"\n",\ +"freeset\n",\ +"1 7 4 5;\n",\ +"\n",\ +"freeset\n",\ +"1 7 5 6;\n",\ +"\n",\ +"freeset\n",\ +"1 7 6 2;\n",\ +"\n",\ +"endrule\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"rule \"four Tetrahedron non convex (6)\"\n",\ +"\n",\ +"quality 6\n",\ +"flags l;\n",\ +"\n",\ +"mappoints\n",\ +"(0, 0, 0);\n",\ +"(1, 0, 0) { 0.5 };\n",\ +"(0.5, 1, 0) { 0.5 };\n",\ +"(0.5, 0, -1) { 0.5 };\n",\ +"(0.5, 0.3, -0.3) { 0.5 };\n",\ +"\n",\ +"mapfaces\n",\ +"(1, 2, 3) del;\n",\ +"(1, 4, 2) del;\n",\ +"(1, 5, 4) del;\n",\ +"(1, 3, 5) del;\n",\ +"\n",\ +"\n",\ +"newpoints\n",\ +"(0.095, 0.003, -0.003)\n",\ +" { 0.9 X1, 0.09 X2, 0.01 X5 }\n",\ +" { 0.9 Y1, 0.09 Y2, 0.01 Y5 }\n",\ +" { 0.9 Z1, 0.09 Z2, 0.01 Z5 };\n",\ +"\n",\ +"newfaces\n",\ +"(6, 2, 3) del;\n",\ +"(6, 4, 2) del;\n",\ +"(6, 5, 4) del;\n",\ +"(6, 3, 5) del;\n",\ +"\n",\ +"\n",\ +"elements\n",\ +"(1, 2, 3, 6);\n",\ +"(1, 4, 2, 6);\n",\ +"(1, 5, 4, 6);\n",\ +"(1, 3, 5, 6);\n",\ +"\n",\ +"\n",\ +"freezone2\n",\ +"{ 1 P1 };\n",\ +"{ 1 P2 };\n",\ +"{ 1 P3 };\n",\ +"{ 1 P4 };\n",\ +"{ 1 P5 };\n",\ +"{ 1.499 P6, -0.5 P1, 0.001 P2 };\n",\ +"\n",\ +"freezonelimit\n",\ +"{ 1 P1 };\n",\ +"{ 1 P2 };\n",\ +"{ 1 P3 };\n",\ +"{ 1 P4 };\n",\ +"{ 1 P5 };\n",\ +"{ 1 P6 };\n",\ +"\n",\ +"\n",\ +"\n",\ +"freeset\n",\ +"1 6 2 3;\n",\ +"\n",\ +"freeset\n",\ +"1 6 3 5;\n",\ +"\n",\ +"freeset\n",\ +"1 6 5 4;\n",\ +"\n",\ +"freeset\n",\ +"1 6 4 2;\n",\ +"\n",\ +"endrule\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"rule \"four Tetrahedron non convex (6)\"\n",\ +"\n",\ +"quality 100\n",\ +"\n",\ +"\n",\ +"mappoints\n",\ +"(0, 0, 0);\n",\ +"(1, 0, 0) { 0.5 };\n",\ +"(0.5, 1, 0) { 0.5 };\n",\ +"(0.5, 0, -1) { 0.5 };\n",\ +"(0.5, 0.4, -0.4) { 0.5 };\n",\ +"\n",\ +"mapfaces\n",\ +"(1, 2, 3) del;\n",\ +"(1, 4, 2) del;\n",\ +"(4, 5, 2) del;\n",\ +"(5, 3, 2) del;\n",\ +"\n",\ +"newpoints\n",\ +"(0.925, 0.02, -0.02)\n",\ +" { 0.05 X1, 0.9 X2, 0.05 X5 }\n",\ +" { 0.05 Y1, 0.9 Y2, 0.05 Y5 }\n",\ +" { 0.05 Z1, 0.9 Z2, 0.05 Z5 };\n",\ +"\n",\ +"newfaces\n",\ +"(3, 1, 6);\n",\ +"(1, 4, 6);\n",\ +"(4, 5, 6);\n",\ +"(5, 3, 6);\n",\ +"\n",\ +"elements\n",\ +"(3, 1, 2, 6);\n",\ +"(1, 4, 2, 6);\n",\ +"(4, 5, 2, 6);\n",\ +"(5, 3, 2, 6);\n",\ +"\n",\ +"orientations\n",\ +"(3, 1, 2, 5);\n",\ +"(1, 4, 2, 5);\n",\ +"(2, 4, 5, 1);\n",\ +"(3, 2, 5, 1);\n",\ +"(5, 4, 2, 3);\n",\ +"\n",\ +"freezone2\n",\ +"{ 1 P1 };\n",\ +"{ 1 P2 };\n",\ +"{ 1 P3 };\n",\ +"{ 1 P4 };\n",\ +"{ 1 P5 };\n",\ +"{ 1.5 P6, -0.5 P2 };\n",\ +"\n",\ +"freezonelimit\n",\ +"{ 1 P1 };\n",\ +"{ 1 P2 };\n",\ +"{ 1 P3 };\n",\ +"{ 1 P4 };\n",\ +"{ 1 P5 };\n",\ +"{ 1 P6 };\n",\ +"\n",\ +"freeset\n",\ +"3 1 2 6;\n",\ +"\n",\ +"freeset\n",\ +"1 4 2 6;\n",\ +"\n",\ +"freeset\n",\ +"4 5 2 6;\n",\ +"\n",\ +"freeset\n",\ +"5 3 2 6;\n",\ +"\n",\ +"endrule\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"rule \"three Tetrahedron non convex (4)\"\n",\ +"\n",\ +"quality 4\n",\ +"flags l;\n",\ +"\n",\ +"mappoints\n",\ +"(0, 0, 0);\n",\ +"(1, 0, 0) { 0.5 };\n",\ +"(0.5, 1, 0) { 0.5 };\n",\ +"(0.5, 0, -1) { 0.5 };\n",\ +"\n",\ +"mapfaces\n",\ +"(1, 2, 3) del;\n",\ +"(1, 4, 2) del;\n",\ +"(1, 3, 4) del;\n",\ +"\n",\ +"newpoints\n",\ +"(0.5, 0.25, -0.25)\n",\ +" { 0.25 X1, 0.25 X2, 0.25 X3, 0.25 X4 }\n",\ +" { 0.25 Y1, 0.25 Y2, 0.25 Y3, 0.25 Y4 }\n",\ +" { 0.25 Z1, 0.25 Z2, 0.25 Z3, 0.25 Z4 };\n",\ +"\n",\ +"newfaces\n",\ +"(5, 2, 3);\n",\ +"(5, 4, 2);\n",\ +"(5, 3, 4);\n",\ +"\n",\ +"elements\n",\ +"(2, 3, 1, 5);\n",\ +"(3, 4, 1, 5);\n",\ +"(4, 2, 1, 5;\n",\ +"\n",\ +"orientations\n",\ +"(1, 2, 4, 3);\n",\ +"\n",\ +"freezone2\n",\ +"{ 1 P1 };\n",\ +"{ 1 P2 };\n",\ +"{ 1 P3 };\n",\ +"{ 1 P4 };\n",\ +"{ 1.5 P5, -0.5 P1 };\n",\ +"\n",\ +"freezonelimit\n",\ +"{ 1 P1 };\n",\ +"{ 1 P2 };\n",\ +"{ 1 P3 };\n",\ +"{ 1 P4 };\n",\ +"{ 1 P5 };\n",\ +"\n",\ +"freeset\n",\ +"1 2 3 5;\n",\ +"\n",\ +"freeset\n",\ +"1 3 4 5;\n",\ +"\n",\ +"freeset\n",\ +"1 4 2 5;\n",\ +"\n",\ +"endrule\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"rule \"three Tetrahedron non convex (6)\"\n",\ +"\n",\ +"quality 100\n",\ +"\n",\ +"\n",\ +"mappoints\n",\ +"(0, 0, 0);\n",\ +"(1, 0, 0) { 0.5 };\n",\ +"(0.5, 1, 0) { 0.5 };\n",\ +"(0.5, 0, -1) { 0.5 };\n",\ +"\n",\ +"mapfaces\n",\ +"(1, 2, 3) del;\n",\ +"(1, 4, 2) del;\n",\ +"(1, 3, 4) del;\n",\ +"\n",\ +"newpoints\n",\ +"(0.2, 0.1, -0.1)\n",\ +" { 0.7 X1, 0.1 X2, 0.1 X3, 0.1 X4 }\n",\ +" { 0.7 Y1, 0.1 Y2, 0.1 Y3, 0.1 Y4 }\n",\ +" { 0.7 Z1, 0.1 Z2, 0.1 Z3, 0.1 Z4 };\n",\ +"\n",\ +"newfaces\n",\ +"(5, 2, 3);\n",\ +"(5, 4, 2);\n",\ +"(5, 3, 4);\n",\ +"\n",\ +"elements\n",\ +"(2, 3, 1, 5);\n",\ +"(3, 4, 1, 5);\n",\ +"(4, 2, 1, 5;\n",\ +"\n",\ +"orientations\n",\ +"(1, 2, 3, 4);\n",\ +"\n",\ +"freezone2\n",\ +"{ 1 P1 };\n",\ +"{ 1 P2 };\n",\ +"{ 1 P3 };\n",\ +"{ 1 P4 };\n",\ +"{ 1.5 P5, -0.5 P1 };\n",\ +"\n",\ +"freezonelimit\n",\ +"{ 1 P1 };\n",\ +"{ 1 P2 };\n",\ +"{ 1 P3 };\n",\ +"{ 1 P4 };\n",\ +"{ 1 P5 };\n",\ +"\n",\ +"freeset\n",\ +"1 2 3 5;\n",\ +"\n",\ +"freeset\n",\ +"1 3 4 5;\n",\ +"\n",\ +"freeset\n",\ +"1 4 2 5;\n",\ +"\n",\ +"endrule\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"rule \"four Tetrahedron non convex (6)\"\n",\ +"\n",\ +"quality 100\n",\ +"\n",\ +"\n",\ +"mappoints\n",\ +"(0, 0, 0);\n",\ +"(1, 0, 0) { 0.5 };\n",\ +"(0.5, 1, 0) { 0.5 };\n",\ +"(0.5, 0, -1) { 0.5 };\n",\ +"(0.5, 0.4, -0.4) { 0.5 };\n",\ +"\n",\ +"mapfaces\n",\ +"(1, 2, 3) del;\n",\ +"(1, 4, 2) del;\n",\ +"(4, 5, 2) del;\n",\ +"(5, 3, 2) del;\n",\ +"\n",\ +"newpoints\n",\ +"(0.7, 0.08, -0.08) { 0.6 X2, 0.2 X5 } { 0.2 Y5 } { 0.2 Z5 };\n",\ +"\n",\ +"newfaces\n",\ +"(3, 1, 6);\n",\ +"(1, 4, 6);\n",\ +"(4, 5, 6);\n",\ +"(5, 3, 6);\n",\ +"\n",\ +"elements\n",\ +"(3, 1, 2, 6);\n",\ +"(1, 4, 2, 6);\n",\ +"(4, 5, 2, 6);\n",\ +"(5, 3, 2, 6);\n",\ +"\n",\ +"\n",\ +"orientations\n",\ +"(3, 1, 2, 5);\n",\ +"(5, 1, 2, 4);\n",\ +"\n",\ +"freezone\n",\ +"(0, 0, 0);\n",\ +"(1, 0, 0) { 1 X2 } { } { };\n",\ +"(0.5, 1, 0) { 1 X3 } { 1 Y3 } { };\n",\ +"(0.5, 0, -1) { 1 X4 } { 1 Y4 } { 1 Z4 };\n",\ +"(0.5, 0.4, -0.4) { 1 X5 } { 1 Y5 } { 1 Z5 };\n",\ +"(0.55, 0.12, -0.12) { 0.4 X2, 0.3 X5 } { 0.3 Y5 } { 0.3 Z5 };\n",\ +"\n",\ +"freeset\n",\ +"3 1 2 6;\n",\ +"\n",\ +"freeset\n",\ +"1 4 2 6;\n",\ +"\n",\ +"freeset\n",\ +"4 5 2 6;\n",\ +"\n",\ +"freeset\n",\ +"5 3 2 6;\n",\ +"\n",\ +"endrule\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"rule \"Tetrahedron 2 in 60 (12)\"\n",\ +"\n",\ +"quality 100\n",\ +"\n",\ +"mappoints\n",\ +"(0, 0, 0);\n",\ +"(1, 0, 0) { 0.5 };\n",\ +"(0.5, 1, 0) { 0.5 };\n",\ +"(0.5, 0, -1) { 0.5 };\n",\ +"\n",\ +"mapfaces\n",\ +"(1, 2, 3) del;\n",\ +"(1, 4, 2) del;\n",\ +"\n",\ +"newpoints\n",\ +"(0.5, 0.1, -0.1)\n",\ +" { 0.4 X1, 0.4 X2, 0.1 X3, 0.1 X4 }\n",\ +" { 0.4 Y1, 0.4 Y2, 0.1 Y3, 0.1 Y4 }\n",\ +" { 0.4 Z1, 0.4 Z2, 0.1 Z3, 0.1 Z4 };\n",\ +"\n",\ +"newfaces\n",\ +"(5, 2, 3);\n",\ +"(5, 3, 1);\n",\ +"(5, 4, 2);\n",\ +"(5, 1, 4);\n",\ +"\n",\ +"elements\n",\ +"(1, 2, 3, 5);\n",\ +"(1, 2, 5, 4);\n",\ +"\n",\ +"freezone2\n",\ +"{ 1 P1 };\n",\ +"{ 1 P2 };\n",\ +"{ 1 P3 };\n",\ +"{ 1 P4 };\n",\ +"{ 1.5 P5, -0.25 P1, -0.25 P2 };\n",\ +"\n",\ +"freezonelimit\n",\ +"{ 1 P1 };\n",\ +"{ 1 P2 };\n",\ +"{ 1 P3 };\n",\ +"{ 1 P4 };\n",\ +"{ 1 P5 };\n",\ +"\n",\ +"freeset\n",\ +"1 2 3 5;\n",\ +"\n",\ +"freeset\n",\ +"1 2 4 5;\n",\ +"\n",\ +"endrule\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"rule \"Tetrahedron 120, but more than 180 (13)\"\n",\ +"\n",\ +"quality 100\n",\ +"\n",\ +"mappoints\n",\ +"(0, 0, 0);\n",\ +"(1, 0, 0) { 1 };\n",\ +"(0.5, 0.866, 0) { 1 };\n",\ +"(0.5, -0.866, 0) { 1 };\n",\ +"\n",\ +"mapfaces\n",\ +"(1, 2, 3) del;\n",\ +"(1, 4, 2);\n",\ +"\n",\ +"newpoints\n",\ +"(0.5, 0, -0.3) { 0.5 X3, 0.5 X4 } { 0.5 Y3, 0.5 Y4} { 0.5 Z3, 0.5 Z4 };\n",\ +"\n",\ +"newfaces\n",\ +"(1, 5, 3);\n",\ +"(3, 5, 2);\n",\ +"(2, 5, 1);\n",\ +"\n",\ +"elements\n",\ +"(1, 2, 3, 5);\n",\ +"\n",\ +"\n",\ +"freezone\n",\ +"(0, 0, 0);\n",\ +"(1, 0, 0) { 1 X2 } { } { };\n",\ +"(0.5, 0.866, 0) { 1 X3 } { 1 Y3 } { };\n",\ +"(0.5, -0.1, -0.4) { 0.5 X3, 0.5 X4 } { 0.5 Y3, 0.5 Y4} { 0.5 Z3, 0.5 Z4 };\n",\ +"\n",\ +"endrule\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"rule \"Free Tetrahedron (14)\"\n",\ +"\n",\ +"quality 100\n",\ +"\n",\ +"mappoints\n",\ +"(0, 0, 0);\n",\ +"(1, 0, 0) { 1.0 };\n",\ +"(0.5, 0.866, 0) { 1.0 };\n",\ +"\n",\ +"mapfaces\n",\ +"(1, 2, 3) del;\n",\ +"\n",\ +"newpoints\n",\ +"(0.5, 0.288, -0.2) { 0.333 X2, 0.333 X3 } { 0.333 Y3 } { };\n",\ +"\n",\ +"newfaces\n",\ +"(4, 1, 2);\n",\ +"(4, 2, 3);\n",\ +"(4, 3, 1);\n",\ +"\n",\ +"elements\n",\ +"(1, 2, 3, 4);\n",\ +"\n",\ +"freezone\n",\ +"(0, 0, 0);\n",\ +"(1, 0, 0) { 1 X2 } { } { };\n",\ +"(0.5, 0.866, 0) { 1 X3 } { 1 Y3 } { };\n",\ +"(0.5, 0.288, -0.25) { 0.333 X2, 0.333 X3 } { 0.333 Y3 } { };\n",\ +"\n",\ +"endrule\n",\ +"\n",\ +"\n",\ +"\n",\ +"rule \"Free Tetrahedron (15)\"\n",\ +"\n",\ +"quality 100\n",\ +"\n",\ +"mappoints\n",\ +"(0, 0, 0);\n",\ +"(1, 0, 0) { 1.0 };\n",\ +"(0.5, 0.866, 0) { 1.0 };\n",\ +"\n",\ +"mapfaces\n",\ +"(1, 2, 3) del;\n",\ +"\n",\ +"newpoints\n",\ +"(0.5, 0.288, -0.1) { 0.333 X2, 0.333 X3 } { 0.333 Y3 } { };\n",\ +"\n",\ +"newfaces\n",\ +"(4, 1, 2);\n",\ +"(4, 2, 3);\n",\ +"(4, 3, 1);\n",\ +"\n",\ +"elements\n",\ +"(1, 2, 3, 4);\n",\ +"\n",\ +"freezone\n",\ +"(0, 0, 0);\n",\ +"(1, 0, 0) { 1 X2 } { } { };\n",\ +"(0.5, 0.866, 0) { 1 X3 } { 1 Y3 } { };\n",\ +"(0.5, 0.288, -0.15) { 0.333 X2, 0.333 X3 } { 0.333 Y3 } { };\n",\ +"\n",\ +"endrule\n", +0}; +} diff --git a/contrib/Netgen/libsrc/meshing/topology.cpp b/contrib/Netgen/libsrc/meshing/topology.cpp new file mode 100644 index 0000000000..9c0e79d531 --- /dev/null +++ b/contrib/Netgen/libsrc/meshing/topology.cpp @@ -0,0 +1,1595 @@ +#include <mystdlib.h> + +#include "meshing.hpp" + +namespace netgen +{ + +MeshTopology :: MeshTopology (const Mesh & amesh) + : mesh(amesh) +{ + buildedges = 1; + buildfaces = 1; + vert2element = 0; + vert2surfelement = 0; + vert2segment = 0; + timestamp = -1; + + edge2vert.SetName ("edge2vert"); + face2vert.SetName ("face2vert"); + edges.SetName ("el2edge"); + faces.SetName ("el2face"); + surfedges.SetName ("surfel2edge"); + segedges.SetName ("segment2edge"); + surffaces.SetName ("surfel2face"); + surf2volelement.SetName ("surfel2el"); + face2surfel.SetName ("face2surfel"); +} + +MeshTopology :: ~MeshTopology () +{ + delete vert2element; + delete vert2surfelement; + delete vert2segment; +} + +void MeshTopology :: Update() +{ + int i, j, k; + + if (timestamp > mesh.GetTimeStamp()) return; + + int ne = mesh.GetNE(); + int nse = mesh.GetNSE(); + int nseg = mesh.GetNSeg(); + int np = mesh.GetNP(); + int nv = mesh.GetNV(); + int nfa = 0; + int ned = edge2vert.Size(); + + PrintMessage (3, "Update mesh topology"); + + (*testout) << "ne = " << ne << endl; + (*testout) << "nse = " << nse << endl; + (*testout) << "nseg = " << nseg << endl; + (*testout) << "np = " << np << endl; + (*testout) << "nv = " << nv << endl; + + delete vert2element; + delete vert2surfelement; + delete vert2segment; + ARRAY<int,PointIndex::BASE> cnt(nv); + ARRAY<int> vnums; + + (*testout) << "tables deleted" << endl; + + /* + generate: + vertex to element + vertex to surface element + vertex to segment + */ + + cnt = 0; + for (i = 1; i <= ne; i++) + { + const Element & el = mesh.VolumeElement(i); + int nelv = el.GetNV(); + for (j = 1; j <= nelv; j++) + cnt[el.PNum(j)]++; + } + + vert2element = new TABLE<int,PointIndex::BASE> (cnt); + for (i = 1; i <= ne; i++) + { + const Element & el = mesh.VolumeElement(i); + int nelv = el.GetNV(); + for (j = 1; j <= nelv; j++) + vert2element->AddSave (el.PNum(j), i); + } + + cnt = 0; + for (SurfaceElementIndex sei = 0; sei < nse; sei++) + { + const Element2d & el = mesh[sei]; + int nelv = el.GetNV(); + for (j = 0; j < nelv; j++) + cnt[el[j]]++; + } + + vert2surfelement = new TABLE<int,PointIndex::BASE> (cnt); + for (SurfaceElementIndex sei = 0; sei < nse; sei++) + { + const Element2d & el = mesh[sei]; + int nelv = el.GetNV(); + for (j = 0; j < nelv; j++) + vert2surfelement->AddSave (el[j], sei+1); + } + + + cnt = 0; + for (i = 1; i <= nseg; i++) + { + const Segment & seg = mesh.LineSegment(i); + cnt[seg.p1]++; + cnt[seg.p2]++; + } + + vert2segment = new TABLE<int,PointIndex::BASE> (cnt); + for (i = 1; i <= nseg; i++) + { + const Segment & seg = mesh.LineSegment(i); + vert2segment->AddSave (seg.p1, i); + vert2segment->AddSave (seg.p2, i); + } + + + + + if (buildedges) + { + PrintMessage (5, "Update edges "); + + edges.SetSize(ne); + surfedges.SetSize(nse); + segedges.SetSize(nseg); + + for (i = 1; i <= ne; i++) + for (j = 0; j < 12; j++) + edges.Elem(i)[j] = 0; + for (i = 1; i <= nse; i++) + for (j = 0; j < 4; j++) + surfedges.Elem(i)[j] = 0; + + // keep existing edges + cnt = 0; + for (i = 0; i < edge2vert.Size(); i++) + cnt[edge2vert[i][0]]++; + TABLE<int,PointIndex::BASE> vert2edge (cnt); + for (i = 0; i < edge2vert.Size(); i++) + vert2edge.AddSave (edge2vert[i][0], i+1); + + // ensure all coarse grid and intermediate level edges + cnt = 0; + for (i = 1; i <= mesh.mlbetweennodes.Size(); i++) + { + int pa[2]; + pa[0] = mesh.mlbetweennodes.Get(i).I1(); + pa[1] = mesh.mlbetweennodes.Get(i).I2(); + if (pa[0] > pa[1]) Swap (pa[0], pa[1]); + if (pa[0] > 0) + cnt.Elem(pa[0])++; + } + TABLE<int,PointIndex::BASE> vert2vertcoarse (cnt); + for (i = 1; i <= mesh.mlbetweennodes.Size(); i++) + { + int pa[2]; + pa[0] = mesh.mlbetweennodes.Get(i).I1(); + pa[1] = mesh.mlbetweennodes.Get(i).I2(); + if (pa[0] > pa[1]) swap (pa[0], pa[1]); + if (pa[0] > 0) + vert2vertcoarse.AddSave1 (pa[0], pa[1]); + } + + + ARRAY<int,PointIndex::BASE> edgenr(nv), edgeflag(nv); + for (i = PointIndex::BASE; i < nv+PointIndex::BASE; i++) + edgeflag[i] = 0; + ned = edge2vert.Size(); + ARRAY<INDEX_3> missing; + + for (i = 1; i <= nv; i++) + { + for (j = 1; j <= vert2edge.EntrySize(i); j++) + { + int ednr = vert2edge.Get(i,j); + int i2 = edge2vert.Get(ednr)[1]; + edgeflag.Elem(i2) = i; + edgenr.Elem(i2) = ednr; + } + for (j = 1; j <= vert2vertcoarse.EntrySize(i); j++) + { + int v2 = vert2vertcoarse.Get(i,j); + if (edgeflag.Get(v2) < i) + { + ned++; + edgenr.Elem(v2) = ned; + edgeflag.Elem(v2) = i; + missing.Append (INDEX_3(i,v2,ned)); + } + } + + for (j = 1; j <= vert2element->EntrySize(i); j++) + { + int elnr = vert2element->Get(i,j); + const Element & el = mesh.VolumeElement (elnr); + + int neledges = GetNEdges (el.GetType()); + const ELEMENT_EDGE * eledges = GetEdges (el.GetType()); + + for (k = 0; k < neledges; k++) + { + INDEX_2 edge(el.PNum(eledges[k][0]), + el.PNum(eledges[k][1])); + + int edgedir = (edge.I1() > edge.I2()); + if (edgedir) swap (edge.I1(), edge.I2()); + + if (edge.I1() != i) + continue; + + if (edgeflag.Get (edge.I2()) < i) + { + ned++; + edgenr.Elem(edge.I2()) = ned; + edgeflag.Elem(edge.I2()) = i; + } + + int edgenum = edgenr.Elem(edge.I2()); + if (edgedir) edgenum *= -1; + edges.Elem(elnr)[k] = edgenum; + } + } + + for (j = 1; j <= vert2surfelement->EntrySize(i); j++) + { + int elnr = vert2surfelement->Get(i,j); + const Element2d & el = mesh.SurfaceElement (elnr); + + int neledges = GetNEdges (el.GetType()); + const ELEMENT_EDGE * eledges = GetEdges (el.GetType()); + + for (k = 0; k < neledges; k++) + { + INDEX_2 edge(el.PNum(eledges[k][0]), + el.PNum(eledges[k][1])); + + int edgedir = (edge.I1() > edge.I2()); + if (edgedir) swap (edge.I1(), edge.I2()); + + if (edge.I1() != i) + continue; + + if (edgeflag.Get (edge.I2()) < i) + { + ned++; + edgenr.Elem(edge.I2()) = ned; + edgeflag.Elem(edge.I2()) = i; + } + + int edgenum = edgenr.Elem(edge.I2()); + if (edgedir) edgenum *= -1; + surfedges.Elem(elnr)[k] = edgenum; + } + } + + for (j = 1; j <= vert2segment->EntrySize(i); j++) + { + int elnr = vert2segment->Get(i,j); + const Segment & el = mesh.LineSegment (elnr); + + INDEX_2 edge(el.p1, el.p2); + + int edgedir = (edge.I1() > edge.I2()); + if (edgedir) swap (edge.I1(), edge.I2()); + + if (edge.I1() != i) + continue; + + if (edgeflag.Get (edge.I2()) < i) + { + ned++; + edgenr.Elem(edge.I2()) = ned; + edgeflag.Elem(edge.I2()) = i; + } + int edgenum = edgenr.Elem(edge.I2()); + + if (edgedir) edgenum *= -1; + segedges.Elem(elnr) = edgenum; + } + } + + + edge2vert.SetSize (ned); + for (i = 1; i <= ne; i++) + { + const Element & el = mesh.VolumeElement (i); + + int neledges = GetNEdges (el.GetType()); + const ELEMENT_EDGE * eledges = GetEdges (el.GetType()); + + for (k = 0; k < neledges; k++) + { + INDEX_2 edge(el.PNum(eledges[k][0]), + el.PNum(eledges[k][1])); + + int edgedir = (edge.I1() > edge.I2()); + if (edgedir) swap (edge.I1(), edge.I2()); + + int edgenum = abs (edges.Elem(i)[k]); + + edge2vert.Elem(edgenum)[0] = edge.I1(); + edge2vert.Elem(edgenum)[1] = edge.I2(); + } + } + for (i = 1; i <= nse; i++) + { + const Element2d & el = mesh.SurfaceElement (i); + + int neledges = GetNEdges (el.GetType()); + const ELEMENT_EDGE * eledges = GetEdges (el.GetType()); + + for (k = 0; k < neledges; k++) + { + INDEX_2 edge(el.PNum(eledges[k][0]), + el.PNum(eledges[k][1])); + + int edgedir = (edge.I1() > edge.I2()); + if (edgedir) swap (edge.I1(), edge.I2()); + + int edgenum = abs (surfedges.Elem(i)[k]); + + edge2vert.Elem(edgenum)[0] = edge.I1(); + edge2vert.Elem(edgenum)[1] = edge.I2(); + } + } + + for (i = 1; i <= nseg; i++) + { + const Segment & el = mesh.LineSegment (i); + + INDEX_2 edge(el.p1, el.p2); + int edgedir = (edge.I1() > edge.I2()); + if (edgedir) swap (edge.I1(), edge.I2()); + + int edgenum = abs (segedges.Elem(i)); + + edge2vert.Elem(edgenum)[0] = edge.I1(); + edge2vert.Elem(edgenum)[1] = edge.I2(); + } + + for (i = 1; i <= missing.Size(); i++) + { + INDEX_3 i3 = missing.Get(i); + edge2vert.Elem(i3.I3())[0] = i3.I1(); + edge2vert.Elem(i3.I3())[1] = i3.I2(); + } + + /* + (*testout) << "edge table:" << endl; + (*testout) << "edge2vert:" << endl; + for (i = 1; i <= edge2vert.Size(); i++) + (*testout) << "edge " << i << ", v1,2 = " << edge2vert.Elem(i)[0] << ", " << edge2vert.Elem(i)[1] << endl; + (*testout) << "surfedges:" << endl; + for (i = 1; i <= surfedges.Size(); i++) + (*testout) << "el " << i << ", edges = " + << surfedges.Elem(i)[0] << ", " + << surfedges.Elem(i)[1] << ", " + << surfedges.Elem(i)[2] << endl; + */ + } + + + // cout << "build edges done" << endl; + +#ifdef OLD + if (buildedges == 2) + { // old style with hash-table + edges.SetSize(ne); + surfedges.SetSize(nse); + INDEX_2_HASHTABLE<int> vert2edge(ne+nse+1); + + // keep coarse grid edges + for (i = 1; i <= ned; i++) + { + INDEX_2 edge (edge2vert.Get(i)[0], + edge2vert.Get(i)[1]); + edge.Sort (); + vert2edge.Set (edge, i); + } + + + + for (i = 1; i <= ne; i++) + { + const Element & el = mesh.VolumeElement(i); + + int neledges = GetNEdges (el.GetType()); + const ELEMENT_EDGE * eledges = GetEdges (el.GetType()); + + for (j = 0; j < 12; j++) + edges.Elem(i)[j] = 0; + for (j = 0; j < neledges; j++) + { + int edgenum; + int edgedir; + + INDEX_2 edge(el.PNum(eledges[j][0]), + el.PNum(eledges[j][1])); + + edgedir = (edge.I1() > edge.I2()); + if (edgedir) swap (edge.I1(), edge.I2()); + + if (vert2edge.Used (edge)) + edgenum = vert2edge.Get(edge); + else + { + ned++; + vert2edge.Set (edge, ned); + edgenum = ned; + /* + edge2vert.SetSize(edge2vert.Size()+1); + edge2vert.Last()[0] = edge.I1(); + edge2vert.Last()[1] = edge.I2(); + */ + edge2vert.Append (edge); + } + + if (edgedir) edgenum *= -1; + edges.Elem(i)[j] = edgenum; + } + } + + for (i = 1; i <= nse; i++) + { + const Element2d & el = mesh.SurfaceElement(i); + + int neledges = GetNEdges (el.GetType()); + const ELEMENT_EDGE * eledges = GetEdges (el.GetType()); + + for (j = 0; j < 4; j++) + surfedges.Elem(i)[j] = 0; + for (j = 0; j < neledges; j++) + { + int edgenum; + int edgedir; + + INDEX_2 edge(el.PNum(eledges[j][0]), + el.PNum(eledges[j][1])); + + edgedir = (edge.I1() > edge.I2()); + if (edgedir) swap (edge.I1(), edge.I2()); + + if (vert2edge.Used (edge)) + edgenum = vert2edge.Get(edge); + else + { + ned++; + vert2edge.Set (edge, ned); + edgenum = ned; + + /* + edge2vert.SetSize(edge2vert.Size()+1); + edge2vert.Last()[0] = edge.I1(); + edge2vert.Last()[1] = edge.I2(); + */ + edge2vert.Append (edge); + if (mesh.GetDimension() == 3 && mesh.GetNE()) + cerr << "surface edge: should be in use: " + << edge.I1() << "-" << edge.I2() << endl; + } + + if (edgedir) edgenum *= -1; + surfedges.Elem(i)[j] = edgenum; + } + } + + + // find edges only in intermediate level + + for (i = 1; i <= np; i++) + { + int parents[2]; + + if (i <= mesh.mlbetweennodes.Size()) + { + parents[0] = mesh.mlbetweennodes.Get(i).I1(); + parents[1] = mesh.mlbetweennodes.Get(i).I2(); + } + else + parents[0] = parents[1] = 0; + + if (parents[0] && parents[1]) + { + INDEX_2 edge(parents[0], parents[1]); + int edgedir = (edge.I1() > edge.I2()); + if (edgedir) swap (edge.I1(), edge.I2()); + + if (!vert2edge.Used (edge)) + { + ned++; + vert2edge.Set (edge, ned); + /* + edge2vert.SetSize(edge2vert.Size()+1); + edge2vert.Last()[0] = edge.I1(); + edge2vert.Last()[1] = edge.I2(); + */ + edge2vert.Append (edge); + } + } + } + + /* + cout << "edge2vert: "; + edge2vert.PrintMemInfo(cout); + cout << "edges: "; + edges.PrintMemInfo(cout); + cout << "hashtable: "; + vert2edge.PrintMemInfo(cout); + */ + + if (mesh.GetDimension() == 2) + { + surffaces.SetSize(mesh.GetNSeg()); + for (i = 1; i <= mesh.GetNSeg(); i++) + { + const Segment & seg = mesh.LineSegment (i); + + INDEX_2 edge(seg.p1, seg.p2); + int edgenum; + int edgedir = (edge.I1() > edge.I2()); + if (edgedir) swap (edge.I1(), edge.I2()); + + if (vert2edge.Used (edge)) + edgenum = vert2edge.Get(edge); + else + { + ned++; + vert2edge.Set (edge, ned); + edgenum = ned; + + /* + edge2vert.SetSize(edge2vert.Size()+1); + edge2vert.Last()[0] = edge.I1(); + edge2vert.Last()[1] = edge.I2(); + */ + edge2vert.Append (edge); + } + + + if (edgedir) edgenum *= -1; + surffaces.Elem(i) = edgenum; + } + } + } + +#endif + + + // generate faces + if (buildfaces) // && mesh.GetDimension() == 3) + { + PrintMessage (5, "Update faces "); + + faces.SetSize(ne); + surffaces.SetSize(nse); + + // face2vert.SetSize(0); // keep old faces + nfa = face2vert.Size(); + // INDEX_3_HASHTABLE<int> vert2face(ne+nse+1); + INDEX_3_CLOSED_HASHTABLE<int> vert2face(8*ne+2*nse+nfa+2); + + for (i = 1; i <= face2vert.Size(); i++) + { + INDEX_3 f; + f.I1() = face2vert.Get(i)[0]; + f.I2() = face2vert.Get(i)[1]; + f.I3() = face2vert.Get(i)[2]; + vert2face.Set (f, i); + } + + for (i = 1; i <= ne; i++) + { + const Element & el = mesh.VolumeElement (i); + + int nelfaces = GetNFaces (el.GetType()); + const ELEMENT_FACE * elfaces = GetFaces (el.GetType()); + + for (j = 0; j < 6; j++) + faces.Elem(i)[j] = 0; + for (j = 0; j < nelfaces; j++) + if (elfaces[j][3] == 0) + + { // triangle + + int facenum; + int facedir; + + INDEX_3 face(el.PNum(elfaces[j][0]), + el.PNum(elfaces[j][1]), + el.PNum(elfaces[j][2])); + + facedir = 0; + if (face.I1() > face.I2()) + { + swap (face.I1(), face.I2()); + facedir += 1; + } + if (face.I2() > face.I3()) + { + swap (face.I2(), face.I3()); + facedir += 2; + } + if (face.I1() > face.I2()) + { + swap (face.I1(), face.I2()); + facedir += 4; + } + + if (vert2face.Used (face)) + facenum = vert2face.Get(face); + else + { + nfa++; + vert2face.Set (face, nfa); + facenum = nfa; + + INDEX_4 hface; + face2vert.Append (hface); + // face2vert.SetSize(face2vert.Size()+1); + face2vert.Last()[0] = face.I1(); + face2vert.Last()[1] = face.I2(); + face2vert.Last()[2] = face.I3(); + face2vert.Last()[3] = 0; + + } + + faces.Elem(i)[j] = 8*(facenum-1)+facedir+1; + } + + else + + { + // quad + int facenum; + int facedir; + INDEX_4Q face4(el.PNum(elfaces[j][0]), + el.PNum(elfaces[j][1]), + el.PNum(elfaces[j][2]), + el.PNum(elfaces[j][3])); + + facedir = 0; + if (min2 (face4.I1(), face4.I2()) > + min2 (face4.I4(), face4.I3())) + { // z - flip + facedir += 1; + swap (face4.I1(), face4.I4()); + swap (face4.I2(), face4.I3()); + } + if (min2 (face4.I1(), face4.I4()) > + min2 (face4.I2(), face4.I3())) + { // x - flip + facedir += 2; + swap (face4.I1(), face4.I2()); + swap (face4.I3(), face4.I4()); + } + if (face4.I2() > face4.I4()) + { // diagonal flip + facedir += 4; + swap (face4.I2(), face4.I4()); + } + // face4.Sort(); + + INDEX_3 face(face4.I1(), face4.I2(), face4.I3()); + + if (vert2face.Used (face)) + { + facenum = vert2face.Get(face); + } + else + { + nfa++; + vert2face.Set (face, nfa); + facenum = nfa; + + // face2vert.SetSize(face2vert.Size()+1); + + INDEX_4 hface; + face2vert.Append (hface); + face2vert.Last()[0] = face4.I1(); + face2vert.Last()[1] = face4.I2(); + face2vert.Last()[2] = face4.I3(); + face2vert.Last()[3] = face4.I4(); + + } + + faces.Elem(i)[j] = 8*(facenum-1)+facedir+1; + } + } + + face2surfel.SetSize(nfa+nse); + for (i = 1; i <= face2surfel.Size(); i++) + face2surfel.Elem(i) = 0; + + for (i = 1; i <= nse; i++) + { + const Element2d & el = mesh.SurfaceElement (i); + + const ELEMENT_FACE * elfaces = GetFaces (el.GetType()); + + if (elfaces[0][3] == 0) + + { // triangle + + int facenum; + int facedir; + + INDEX_3 face(el.PNum(elfaces[0][0]), + el.PNum(elfaces[0][1]), + el.PNum(elfaces[0][2])); + + facedir = 0; + if (face.I1() > face.I2()) + { + swap (face.I1(), face.I2()); + facedir += 1; + } + if (face.I2() > face.I3()) + { + swap (face.I2(), face.I3()); + facedir += 2; + } + if (face.I1() > face.I2()) + { + swap (face.I1(), face.I2()); + facedir += 4; + } + + if (vert2face.Used (face)) + facenum = vert2face.Get(face); + else + { + nfa++; + vert2face.Set (face, nfa); + facenum = nfa; + + // face2vert.SetSize(face2vert.Size()+1); + INDEX_4 hface; + face2vert.Append (hface); + face2vert.Last()[0] = face.I1(); + face2vert.Last()[1] = face.I2(); + face2vert.Last()[2] = face.I3(); + face2vert.Last()[3] = 0; + } + + surffaces.Elem(i) = 8*(facenum-1)+facedir+1; + face2surfel.Elem(facenum) = i; + } + + else + + { + // quad + int facenum; + int facedir; + + INDEX_4Q face4(el.PNum(elfaces[0][0]), + el.PNum(elfaces[0][1]), + el.PNum(elfaces[0][2]), + el.PNum(elfaces[0][3])); + + facedir = 0; + if (min2 (face4.I1(), face4.I2()) > + min2 (face4.I4(), face4.I3())) + { // z - orientation + facedir += 1; + swap (face4.I1(), face4.I4()); + swap (face4.I2(), face4.I3()); + } + if (min2 (face4.I1(), face4.I4()) > + min2 (face4.I2(), face4.I3())) + { // x - orientation + facedir += 2; + swap (face4.I1(), face4.I2()); + swap (face4.I3(), face4.I4()); + } + if (face4.I2() > face4.I4()) + { + facedir += 4; + swap (face4.I2(), face4.I4()); + } + + INDEX_3 face(face4.I1(), face4.I2(), face4.I3()); + + if (vert2face.Used (face)) + facenum = vert2face.Get(face); + else + { + nfa++; + vert2face.Set (face, nfa); + facenum = nfa; + + // face2vert.SetSize(face2vert.Size()+1); + INDEX_4 hface; + face2vert.Append (hface); + face2vert.Last()[0] = face4.I1(); + face2vert.Last()[1] = face4.I2(); + face2vert.Last()[2] = face4.I3(); + face2vert.Last()[3] = face4.I3(); + } + + surffaces.Elem(i) = 8*(facenum-1)+facedir+1; + face2surfel.Elem(facenum) = i; + } + } + + surf2volelement.SetSize (nse); + for (i = 1; i <= nse; i++) + { + surf2volelement.Elem(i)[0] = 0; + surf2volelement.Elem(i)[1] = 0; + } + for (i = 1; i <= ne; i++) + for (j = 0; j < 6; j++) + { + int fnum = (faces.Get(i)[j]-1) / 8 + 1; + if (fnum > 0 && face2surfel.Elem(fnum)) + { + int sel = face2surfel.Elem(fnum); + surf2volelement.Elem(sel)[1] = + surf2volelement.Elem(sel)[0]; + surf2volelement.Elem(sel)[0] = i; + } + } + + + face2vert.SetAllocSize (face2vert.Size()); + + /* + cout << "face2vert: "; + face2vert.PrintMemInfo(cout); + cout << "faces: "; + faces.PrintMemInfo(cout); + cout << "hashtable: "; + vert2face.PrintMemInfo(cout); + */ + + + ARRAY<char> face_els(nfa), face_surfels(nfa); + face_els = 0; + face_surfels = 0; + ARRAY<int> hfaces; + for (i = 1; i <= ne; i++) + { + GetElementFaces (i, hfaces); + for (j = 0; j < hfaces.Size(); j++) + face_els[hfaces[j]-1]++; + } + for (i = 1; i <= nse; i++) + face_surfels[GetSurfaceElementFace (i)-1]++; + + if (ne) + { + int cnt_err = 0; + for (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++; + (*testout) << "illegal face : " << i << endl; + (*testout) << "points = " << face2vert[i] << endl; + (*testout) << "pos = "; + for (int j = 0; j < 4; j++) + if (face2vert[i].I(j+1) >= 1) + (*testout) << mesh[(PointIndex)face2vert[i].I(j+1)] << " "; + (*testout) << endl; + } + } + if (cnt_err) + cout << cnt_err << " elements are not matching !!!" << endl; + } + } + + /* + for (i = 1; i <= ne; i++) + { + (*testout) << "Element " << i << endl; + (*testout) << "edges: " << endl; + for (j = 0; j < 9; j++) + (*testout) << edges.Elem(i)[j] << " "; + (*testout) << "faces: " << endl; + for (j = 0; j < 6; j++) + (*testout) << faces.Elem(i)[j] << " "; + } + */ + timestamp = NextTimeStamp(); +} + + + + +int MeshTopology :: GetNVertices (ELEMENT_TYPE et) +{ + switch (et) + { + case SEGMENT: + case SEGMENT3: + return 2; + + case TRIG: + case TRIG6: + return 3; + + case QUAD: + case QUAD6: + case QUAD8: + return 4; + + case TET: + case TET10: + return 4; + + case PYRAMID: + return 5; + + case PRISM: + case PRISM12: + return 6; + + case HEX: + return 8; + + default: + cerr << "Ng_ME_GetNVertices, illegal element type " << et << endl; + } + return 0; +} + +int MeshTopology :: GetNEdges (ELEMENT_TYPE et) +{ + switch (et) + { + case SEGMENT: + case SEGMENT3: + return 1; + + case TRIG: + case TRIG6: + return 3; + + case QUAD: + case QUAD6: + case QUAD8: + return 4; + + case TET: + case TET10: + return 6; + + case PYRAMID: + return 8; + + case PRISM: + case PRISM12: + return 9; + + case HEX: + return 12; + + default: + cerr << "Ng_ME_GetNEdges, illegal element type " << et << endl; + } + return 0; +} + + +int MeshTopology :: GetNFaces (ELEMENT_TYPE et) +{ + switch (et) + { + case SEGMENT: + case SEGMENT3: + return 0; + + case TRIG: + case TRIG6: + return 1; + + case QUAD: + case QUAD6: + case QUAD8: + return 1; + + case TET: + case TET10: + return 4; + + case PYRAMID: + return 5; + + case PRISM: + case PRISM12: + return 5; + + case HEX: + return 6; + + default: + cerr << "Ng_ME_GetNVertices, illegal element type " << et << endl; + } + return 0; +} + + + + +const Point3d * MeshTopology :: GetVertices (ELEMENT_TYPE et) +{ + static Point3d segm_points [] = + { Point3d (1, 0, 0), + Point3d (0, 0, 0) }; + + static Point3d trig_points [] = + { Point3d ( 1, 0, 0 ), + Point3d ( 0, 1, 0 ), + Point3d ( 0, 0, 0 ) }; + + static Point3d quad_points [] = + { Point3d ( 0, 0, 0 ), + Point3d ( 1, 0, 0 ), + Point3d ( 1, 1, 0 ), + Point3d ( 0, 1, 0 ) }; + + static Point3d tet_points [] = + { Point3d ( 1, 0, 0 ), + Point3d ( 0, 1, 0 ), + Point3d ( 0, 0, 1 ), + Point3d ( 0, 0, 0 ) }; + + static Point3d pyramid_points [] = + { + Point3d ( 0, 0, 0 ), + Point3d ( 1, 0, 0 ), + Point3d ( 1, 1, 0 ), + Point3d ( 0, 1, 0 ), + Point3d ( 0, 0, 1-1e-7 ), + }; + + static Point3d prism_points[] = + { + Point3d ( 1, 0, 0 ), + Point3d ( 0, 1, 0 ), + Point3d ( 0, 0, 0 ), + Point3d ( 1, 0, 1 ), + Point3d ( 0, 1, 1 ), + Point3d ( 0, 0, 1 ) + }; + + + static Point3d hex_points [] = + { Point3d ( 0, 0, 0 ), + Point3d ( 1, 0, 0 ), + Point3d ( 1, 1, 0 ), + Point3d ( 0, 1, 0 ), + Point3d ( 0, 0, 1 ), + Point3d ( 1, 0, 1 ), + Point3d ( 1, 1, 1 ), + Point3d ( 0, 1, 1 ) }; + + + switch (et) + { + case SEGMENT: + case SEGMENT3: + return segm_points; + + case TRIG: + case TRIG6: + return trig_points; + + case QUAD: + case QUAD6: + case QUAD8: + return quad_points; + + case TET: + case TET10: + return tet_points; + + case PYRAMID: + return pyramid_points; + + case PRISM: + case PRISM12: + return prism_points; + + case HEX: + return hex_points; + default: + cerr << "Ng_ME_GetVertices, illegal element type " << et << endl; + } + return 0; +} + + + + +const ELEMENT_EDGE * MeshTopology :: GetEdges (ELEMENT_TYPE et) +{ + static int segm_edges[1][2] = + { { 1, 2 }}; + + static int trig_edges[3][2] = + { { 3, 1 }, + { 2, 3 }, + { 1, 2 }}; + + static int quad_edges[4][2] = + { { 1, 2 }, + { 3, 4 }, + { 4, 1 }, + { 2, 3 }}; + + + static int tet_edges[6][2] = + { { 4, 1 }, + { 4, 2 }, + { 4, 3 }, + { 1, 2 }, + { 1, 3 }, + { 2, 3 }}; + + static int prism_edges[9][2] = + { { 3, 1 }, + { 1, 2 }, + { 3, 2 }, + { 6, 4 }, + { 4, 5 }, + { 6, 5 }, + { 3, 6 }, + { 1, 4 }, + { 2, 5 }}; + + static int pyramid_edges[8][2] = + { { 1, 2 }, + { 2, 3 }, + { 1, 4 }, + { 4, 3 }, + { 1, 5 }, + { 2, 5 }, + { 3, 5 }, + { 4, 5 }}; + + static int hex_edges[12][2] = + { + { 1, 2 }, + { 3, 4 }, + { 4, 1 }, + { 2, 3 }, + { 5, 6 }, + { 7, 8 }, + { 8, 5 }, + { 6, 7 }, + { 1, 5 }, + { 2, 6 }, + { 3, 7 }, + { 4, 8 }, + }; + + switch (et) + { + case SEGMENT: + case SEGMENT3: + return segm_edges; + + case TRIG: + case TRIG6: + return trig_edges; + + case QUAD: + case QUAD6: + case QUAD8: + return quad_edges; + + case TET: + case TET10: + return tet_edges; + + case PYRAMID: + return pyramid_edges; + + case PRISM: + case PRISM12: + return prism_edges; + + case HEX: + return hex_edges; + default: + cerr << "Ng_ME_GetEdges, illegal element type " << et << endl; + } + return 0; +} + + +const ELEMENT_FACE * MeshTopology :: GetFaces (ELEMENT_TYPE et) +{ + static int trig_faces[1][4] = + { { 1, 2, 3, 0 } }; + static int quad_faces[1][4] = + { { 1, 2, 3, 4 } }; + + static int tet_faces[4][4] = + { { 4, 2, 3, 0 }, + { 4, 3, 1, 0 }, + { 4, 1, 2, 0 }, + { 1, 3, 2, 0 } }; + + static int prism_faces[5][4] = + { + { 1, 3, 2, 0 }, + { 4, 5, 6, 0 }, + { 3, 1, 4, 6 }, + { 1, 2, 5, 4 }, + { 2, 3, 6, 5 } + }; + + static int pyramid_faces[5][4] = + { + { 1, 2, 5, 0 }, + { 2, 3, 5, 0 }, + { 3, 4, 5, 0 }, + { 4, 1, 5, 0 }, + { 1, 4, 3, 2 } + }; + + static int hex_faces[6][4] = + { + { 1, 4, 3, 2 }, + { 5, 6, 7, 8 }, + { 1, 2, 6, 5 }, + { 2, 3, 7, 6 }, + { 3, 4, 8, 7 }, + { 4, 1, 5, 8 } + }; + + + + switch (et) + { + case TRIG: + case TRIG6: + return trig_faces; + + case QUAD: + case QUAD6: + case QUAD8: + return quad_faces; + + + case TET: + case TET10: + return tet_faces; + + case PRISM: + case PRISM12: + return prism_faces; + + case PYRAMID: + return pyramid_faces; + + case SEGMENT: + case SEGMENT3: + + case HEX: + return hex_faces; + + default: + cerr << "Ng_ME_GetVertices, illegal element type " << et << endl; + } + return 0; +} + + + + + + + + + + + + +void MeshTopology :: GetElementEdges (int elnr, ARRAY<int> & eledges) const +{ + int ned = GetNEdges (mesh.VolumeElement(elnr).GetType()); + eledges.SetSize (ned); + for (int i = 0; i < ned; i++) + eledges[i] = abs (edges.Get(elnr)[i]); +} +void MeshTopology :: GetElementFaces (int elnr, ARRAY<int> & elfaces) const +{ + int i; + int nfa = GetNFaces (mesh.VolumeElement(elnr).GetType()); + elfaces.SetSize (nfa); + for (i = 1; i <= nfa; i++) + elfaces.Elem(i) = (faces.Get(elnr)[i-1]-1) / 8 + 1; +} + +void MeshTopology :: GetElementEdgeOrientations (int elnr, ARRAY<int> & eorient) const +{ + int i; + int ned = GetNEdges (mesh.VolumeElement(elnr).GetType()); + eorient.SetSize (ned); + for (i = 1; i <= ned; i++) + eorient.Elem(i) = (edges.Get(elnr)[i-1] > 0) ? 1 : -1; +} + +void MeshTopology :: GetElementFaceOrientations (int elnr, ARRAY<int> & forient) const +{ + int i; + int nfa = GetNFaces (mesh.VolumeElement(elnr).GetType()); + forient.SetSize (nfa); + for (i = 1; i <= nfa; i++) + forient.Elem(i) = (faces.Get(elnr)[i-1]-1) % 8; +} + + + +int MeshTopology :: GetElementEdges (int elnr, int * eledges, int * orient) const +{ + int i; + // int ned = GetNEdges (mesh.VolumeElement(elnr).GetType()); + + if (mesh.GetDimension()==3 || 1) + { + if (orient) + { + for (i = 0; i < 12; i++) + { + if (!edges.Get(elnr)[i]) return i; + eledges[i] = abs (edges.Get(elnr)[i]); + orient[i] = (edges.Get(elnr)[i] > 0 ) ? 1 : -1; + } + } + else + { + for (i = 0; i < 12; i++) + { + if (!edges.Get(elnr)[i]) return i; + eledges[i] = abs (edges.Get(elnr)[i]); + } + } + return 12; + } + else + { + if (orient) + { + for (i = 0; i < 4; i++) + { + if (!surfedges.Get(elnr)[i]) return i; + eledges[i] = abs (surfedges.Get(elnr)[i]); + orient[i] = (surfedges.Get(elnr)[i] > 0 ) ? 1 : -1; + } + } + else + { + if (!surfedges.Get(elnr)[i]) return i; + for (i = 0; i < 4; i++) + eledges[i] = abs (surfedges.Get(elnr)[i]); + } + return 4; + // return GetSurfaceElementEdges (elnr, eledges, orient); + } +} + +int MeshTopology :: GetElementFaces (int elnr, int * elfaces, int * orient) const +{ + int i; + // int nfa = GetNFaces (mesh.VolumeElement(elnr).GetType()); + if (orient) + { + for (i = 0; i < 6; i++) + { + if (!faces.Get(elnr)[i]) return i; + elfaces[i] = (faces.Get(elnr)[i]-1) / 8 + 1; + orient[i] = (faces.Get(elnr)[i]-1) % 8; + } + } + else + { + for (i = 0; i < 6; i++) + { + if (!faces.Get(elnr)[i]) return i; + elfaces[i] = (faces.Get(elnr)[i]-1) / 8 + 1; + } + } + return 6; +} + +void MeshTopology :: GetSurfaceElementEdges (int elnr, ARRAY<int> & eledges) const +{ + int i; + if (mesh.GetDimension()==3 || 1) + { + int ned = GetNEdges (mesh.SurfaceElement(elnr).GetType()); + eledges.SetSize (ned); + for (i = 1; i <= ned; i++) + eledges.Elem(i) = abs (surfedges.Get(elnr)[i-1]); + } + else + { + cout << "surfeledge(" << elnr << ") = " << flush; + eledges.SetSize(1); + eledges.Elem(1) = abs (segedges.Get(elnr)); + cout << eledges.Elem(1) << endl; + } +} + +int MeshTopology :: GetSurfaceElementFace (int elnr) const +{ + return (surffaces.Get(elnr)-1) / 8 + 1; +} + +void MeshTopology :: +GetSurfaceElementEdgeOrientations (int elnr, ARRAY<int> & eorient) const +{ + int ned = GetNEdges (mesh.SurfaceElement(elnr).GetType()); + eorient.SetSize (ned); + for (int i = 1; i <= ned; i++) + eorient.Elem(i) = (surfedges.Get(elnr)[i-1] > 0) ? 1 : -1; +} + +int MeshTopology :: GetSurfaceElementFaceOrientation (int elnr) const +{ + return (surffaces.Get(elnr)-1) % 8; +} + +int MeshTopology :: GetSurfaceElementEdges (int elnr, int * eledges, int * orient) const +{ + int i; + if (mesh.GetDimension() == 3 || 1) + { + if (orient) + { + for (i = 0; i < 4; i++) + { + if (!surfedges.Get(elnr)[i]) return i; + eledges[i] = abs (surfedges.Get(elnr)[i]); + orient[i] = (surfedges.Get(elnr)[i] > 0 ) ? 1 : -1; + } + } + else + { + for (i = 0; i < 4; i++) + { + if (!surfedges.Get(elnr)[i]) return i; + eledges[i] = abs (surfedges.Get(elnr)[i]); + } + } + return 4; + } + else + { + eledges[0] = abs (segedges.Get(elnr)); + if (orient) + orient[0] = segedges.Get(elnr) > 0 ? 1 : -1; + } + return 1; +} + + +void MeshTopology :: GetFaceVertices (int fnr, ARRAY<int> & vertices) const +{ + vertices.SetSize(4); + int i; + for (i = 1; i <= 4; i++) + vertices.Elem(i) = face2vert.Get(fnr)[i-1]; + if (vertices.Elem(4) == 0) + vertices.SetSize(3); +} + +void MeshTopology :: GetFaceVertices (int fnr, int * vertices) const +{ + for (int i = 0; i <= 3; i++) + vertices[i] = face2vert.Get(fnr)[i]; +} + + +void MeshTopology :: GetEdgeVertices (int ednr, int & v1, int & v2) const +{ + v1 = edge2vert.Get(ednr)[0]; + v2 = edge2vert.Get(ednr)[1]; +} + + +void MeshTopology :: GetFaceEdges (int fnr, ARRAY<int> & edges) const +{ + ArrayMem<int,4> pi(4); + ArrayMem<int,12> eledges; + + edges.SetSize (0); + GetFaceVertices (fnr, pi); + + // GetVertexElements (pi[0], els); + FlatArray<int> els = GetVertexElements (pi[0]); + + // find one element having all vertices of the face + for (int i = 0; i < els.Size(); i++) + { + const Element & el = mesh.VolumeElement(els[i]); + + int cntv = 0; + for (int j = 0; j < el.GetNV(); j++) + for (int k = 0; k < pi.Size(); k++) + if (el[j] == pi[k]) + cntv++; + + if (cntv == pi.Size()) + { + GetElementEdges (els[i], eledges); + + for (int j = 0; j < eledges.Size(); j++) + { + int vi1, vi2; + GetEdgeVertices (eledges[j], vi1, vi2); + bool has1 = 0; + bool has2 = 0; + for (int k = 0; k < pi.Size(); k++) + { + if (vi1 == pi[k]) has1 = 1; + if (vi2 == pi[k]) has2 = 1; + } + if (has1 && has2) + edges.Append (eledges[j]); + } + + return; + } + } +} + + +ELEMENT_TYPE MeshTopology :: GetFaceType (int fnr) const +{ + if (face2vert.Get(fnr)[3] == 0) return TRIG; else return QUAD; +} + + +void MeshTopology :: GetVertexElements (int vnr, ARRAY<int> & elements) const +{ + if (vert2element) + { + int i; + int ne = vert2element->EntrySize(vnr); + elements.SetSize(ne); + for (i = 1; i <= ne; i++) + elements.Elem(i) = vert2element->Get(vnr, i); + } +} + + +FlatArray<int> MeshTopology :: GetVertexElements (int vnr) const +{ + if (vert2element) + return (*vert2element)[vnr]; + return FlatArray<int> (0,0); +} + +FlatArray<int> MeshTopology :: GetVertexSurfaceElements (int vnr) const +{ + if (vert2surfelement) + return (*vert2surfelement)[vnr]; + return FlatArray<int> (0,0); +} + + +void MeshTopology :: GetVertexSurfaceElements( int vnr, + ARRAY<int>& elements ) const +{ + if (vert2surfelement) + { + int i; + int ne = vert2surfelement->EntrySize(vnr); + elements.SetSize(ne); + for (i = 1; i <= ne; i++) + elements.Elem(i) = vert2surfelement->Get(vnr, i); + } +} + +} diff --git a/contrib/Netgen/libsrc/meshing/topology.hpp b/contrib/Netgen/libsrc/meshing/topology.hpp new file mode 100644 index 0000000000..3c5ac1397f --- /dev/null +++ b/contrib/Netgen/libsrc/meshing/topology.hpp @@ -0,0 +1,113 @@ +#ifndef TOPOLOGY +#define TOPOLOGY + +/**************************************************************************/ +/* File: topology.hh */ +/* Author: Joachim Schoeberl */ +/* Date: 27. Apr. 01 */ +/**************************************************************************/ + +/* + Mesh topology + (Elements, Faces, Edges, Vertices +*/ + + +class MeshTopology +{ + const Mesh & mesh; + int buildedges; + int buildfaces; + + MoveableArray<INDEX_2> edge2vert; + MoveableArray<INDEX_4> face2vert; + MoveableArray<int[12]> edges; + MoveableArray<int[6]> faces; + MoveableArray<int[4]> surfedges; + MoveableArray<int> segedges; + MoveableArray<int> surffaces; + MoveableArray<INDEX_2> surf2volelement; + MoveableArray<int> face2surfel; + TABLE<int,PointIndex::BASE> *vert2element; + TABLE<int,PointIndex::BASE> *vert2surfelement; + TABLE<int,PointIndex::BASE> *vert2segment; + int timestamp; +public: + MeshTopology (const Mesh & amesh); + ~MeshTopology (); + + void SetBuildEdges (int be) + { buildedges = be; } + void SetBuildFaces (int bf) + { buildfaces = bf; } + + int HasEdges () const + { return buildedges; } + int HasFaces () const + { return buildedges; } + + void Update(); + + + int GetNEdges () const + { return edge2vert.Size(); } + int GetNFaces () const + { return face2vert.Size(); } + + static int GetNVertices (ELEMENT_TYPE et); + static int GetNEdges (ELEMENT_TYPE et); + static int GetNFaces (ELEMENT_TYPE et); + + static const Point3d * GetVertices (ELEMENT_TYPE et); + static const ELEMENT_EDGE * GetEdges (ELEMENT_TYPE et); + static const ELEMENT_FACE * GetFaces (ELEMENT_TYPE et); + + + + int GetSegmentEdge (int segnr) const { return abs(segedges[segnr-1]); } + int GetSegmentEdgeOrientation (int segnr) const { return sgn(segedges[segnr-1]); } + + void GetSegmentEdge (int segnr, int & enr, int & orient) const + { + enr = abs(segedges.Get(segnr)); + orient = segedges.Get(segnr) > 0 ? 1 : -1; + } + + void GetElementEdges (int elnr, ARRAY<int> & edges) const; + void GetElementFaces (int elnr, ARRAY<int> & faces) const; + void GetElementEdgeOrientations (int elnr, ARRAY<int> & eorient) const; + void GetElementFaceOrientations (int elnr, ARRAY<int> & forient) const; + + int GetElementEdges (int elnr, int * edges, int * orient) const; + int GetElementFaces (int elnr, int * faces, int * orient) const; + + void GetFaceVertices (int fnr, ARRAY<int> & vertices) const; + void GetFaceVertices (int fnr, int * vertices) const; + void GetEdgeVertices (int fnr, int & v1, int & v2) const; + void GetFaceEdges (int fnr, ARRAY<int> & edges) const; + + ELEMENT_TYPE GetFaceType (int fnr) const; + + void GetSurfaceElementEdges (int elnr, ARRAY<int> & edges) const; + int GetSurfaceElementFace (int elnr) const; + void GetSurfaceElementEdgeOrientations (int elnr, ARRAY<int> & eorient) const; + int GetSurfaceElementFaceOrientation (int elnr) const; + + int GetSurfaceElementEdges (int elnr, int * edges, int * orient) const; + + void GetSurface2VolumeElement (int selnr, int & elnr1, int & elnr2) const + { + elnr1 = surf2volelement.Get(selnr)[0]; + elnr2 = surf2volelement.Get(selnr)[1]; + } + + int GetFace2SurfaceElement (int fnr) const { return face2surfel[fnr-1]; } + + void GetVertexElements (int vnr, ARRAY<int> & elements) const; + FlatArray<int> GetVertexElements (int vnr) const; + + void GetVertexSurfaceElements( int vnr, ARRAY<int>& elements ) const; + FlatArray<int> GetVertexSurfaceElements (int vnr) const; +}; + +#endif diff --git a/contrib/Netgen/libsrc/meshing/triarls.cpp b/contrib/Netgen/libsrc/meshing/triarls.cpp new file mode 100644 index 0000000000..923763306d --- /dev/null +++ b/contrib/Netgen/libsrc/meshing/triarls.cpp @@ -0,0 +1,468 @@ +namespace netgen +{ +const char * triarules[] = { +"rule \"Free Triangle (1)\"\n",\ +"\n",\ +"quality 1\n",\ +"\n",\ +"mappoints\n",\ +"(0, 0);\n",\ +"(1, 0) { 1.0, 0, 1.0 };\n",\ +"\n",\ +"maplines\n",\ +"(1, 2) del;\n",\ +"\n",\ +"newpoints\n",\ +"(0.5, 0.866) { 0.5 X2 } { };\n",\ +"\n",\ +"newlines\n",\ +"(1, 3);\n",\ +"(3, 2);\n",\ +"\n",\ +"freearea\n",\ +"(0, 0);\n",\ +"(1, 0) { 1 X2 } { };\n",\ +"(1.5, 0.7) { 0.5 X2 } { };\n",\ +"(0.5, 1.5) { 0.5 X2 } { };\n",\ +"(-0.5, 0.7) { 0.5 X2 } { };\n",\ +"\n",\ +"freearea2\n",\ +"(0, 0);\n",\ +"(1, 0) { 1 X2 } { };\n",\ +"(0.5, 0.866) { 0.5 X2 } { };\n",\ +"(0.5, 0.866) { 0.5 X2 } { };\n",\ +"(0.5, 0.866) { 0.5 X2 } { };\n",\ +"\n",\ +"\n",\ +"elements\n",\ +"(1, 2, 3);\n",\ +"\n",\ +"endrule\n",\ +"\n",\ +"\n",\ +"rule \"Free Triangle (5)\"\n",\ +"\n",\ +"quality 5\n",\ +"\n",\ +"mappoints\n",\ +"(0, 0);\n",\ +"(1, 0) { 1.0, 0, 1.0 };\n",\ +"\n",\ +"maplines\n",\ +"(1, 2) del;\n",\ +"\n",\ +"newpoints\n",\ +"(0.5, 0.5) { 0.5 X2 } { };\n",\ +"\n",\ +"newlines\n",\ +"(1, 3);\n",\ +"(3, 2);\n",\ +"\n",\ +"freearea\n",\ +"(0, 0);\n",\ +"(1, 0) { 1 X2 } { };\n",\ +"(1, 0.7) { 1 X2 } { };\n",\ +"(0, 0.7) { } { };\n",\ +"\n",\ +"freearea2\n",\ +"(0, 0);\n",\ +"(1, 0) { 1 X2 } { };\n",\ +"(0.5, 0.5) { 0.5 X2 } { };\n",\ +"(0.5, 0.5) { 0.5 X2 } { };\n",\ +"\n",\ +"\n",\ +"elements\n",\ +"(1, 2, 3);\n",\ +"\n",\ +"endrule\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"rule \"Free Triangle (10)\"\n",\ +"\n",\ +"quality 10\n",\ +"\n",\ +"mappoints\n",\ +"(0, 0);\n",\ +"(1, 0) { 1.0, 0, 1.0 };\n",\ +"\n",\ +"maplines\n",\ +"(1, 2) del;\n",\ +"\n",\ +"newpoints\n",\ +"(0.5, 0.3) { 0.5 X2 } { };\n",\ +"\n",\ +"newlines\n",\ +"(1, 3);\n",\ +"(3, 2);\n",\ +"\n",\ +"freearea\n",\ +"(0, 0);\n",\ +"(1, 0) { 1 X2 } { };\n",\ +"(1, 0.5) { 1 X2 } { };\n",\ +"(0, 0.5) { } { };\n",\ +"\n",\ +"freearea2\n",\ +"(0, 0);\n",\ +"(1, 0) { 1 X2 } { };\n",\ +"(0.5, 0.3) { 0.5 X2 } { };\n",\ +"(0.5, 0.3) { 0.5 X2 } { };\n",\ +"\n",\ +"\n",\ +"elements\n",\ +"(1, 2, 3);\n",\ +"\n",\ +"endrule\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"rule \"Free Triangle (20)\"\n",\ +"\n",\ +"quality 20\n",\ +"\n",\ +"mappoints\n",\ +"(0, 0);\n",\ +"(1, 0) { 1.0, 0, 1.0 };\n",\ +"\n",\ +"maplines\n",\ +"(1, 2) del;\n",\ +"\n",\ +"newpoints\n",\ +"(0.5, 0.1) { 0.5 X2 } { };\n",\ +"\n",\ +"newlines\n",\ +"(1, 3);\n",\ +"(3, 2);\n",\ +"\n",\ +"freearea\n",\ +"(0, 0);\n",\ +"(1, 0) { 1 X2 } { };\n",\ +"(1, 0.2) { 1 X2 } { };\n",\ +"(0, 0.2) { } { };\n",\ +"\n",\ +"freearea2\n",\ +"(0, 0);\n",\ +"(1, 0) { 1 X2 } { };\n",\ +"(0.5, 0.1) { 0.5 X2 } { };\n",\ +"(0.5, 0.1) { 0.5 X2 } { };\n",\ +"\n",\ +"\n",\ +"elements\n",\ +"(1, 2, 3);\n",\ +"\n",\ +"endrule\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"rule \"Right 60 (1)\"\n",\ +"\n",\ +"quality 1\n",\ +"\n",\ +"mappoints\n",\ +"(0, 0);\n",\ +"(1, 0) { 0.5, 0, 1.0 };\n",\ +"(0.5, 0.866) { 0.6, 0, 0.8 };\n",\ +"\n",\ +"maplines\n",\ +"(1, 2) del;\n",\ +"(2, 3) del;\n",\ +"\n",\ +"newpoints\n",\ +"\n",\ +"newlines\n",\ +"(1, 3);\n",\ +"\n",\ +"freearea\n",\ +"(0, 0);\n",\ +"(1, 0) { 1 X2 } { };\n",\ +"(0.5, 0.866) { 1 X3 } { 1 Y3 };\n",\ +"(-0.125, 0.6495) { -0.5 X2, 0.75 X3 } { -0.5 Y2, 0.75 Y3 };\n",\ +"\n",\ +"freearea2\n",\ +"(0, 0);\n",\ +"(1, 0) { 1 X2 } { };\n",\ +"(0.5, 0.866) { 1 X3 } { 1 Y3 };\n",\ +"(0.25, 0.433) { 0.5 X3 } { 0.5 Y3 };\n",\ +"\n",\ +"elements\n",\ +"(1, 2, 3);\n",\ +"\n",\ +"endrule\n",\ +"\n",\ +"\n",\ +"\n",\ +"rule \"Left 60 (1)\"\n",\ +"\n",\ +"quality 1\n",\ +"\n",\ +"mappoints\n",\ +"(0, 0);\n",\ +"(1, 0);\n",\ +"(0.5, 0.866);\n",\ +"\n",\ +"maplines\n",\ +"(1, 2) del;\n",\ +"(3, 1) del;\n",\ +"\n",\ +"newpoints\n",\ +"\n",\ +"newlines\n",\ +"(3, 2);\n",\ +"\n",\ +"freearea\n",\ +"(0, 0);\n",\ +"(1, 0) { 1 X2 } { };\n",\ +"(1.125, 0.6495) { 0.75 X2, 0.75 X3 } { 0.75 Y3 };\n",\ +"(0.5, 0.866) { 1 X3 } { 1 Y3 };\n",\ +"\n",\ +"freearea2\n",\ +"(0, 0);\n",\ +"(1, 0) { 1 X2 } { };\n",\ +"(0.75, 0.433) { 0.5 X2, 0.5 X3 } { 0.5 Y2, 0.5 Y3 };\n",\ +"(0.5, 0.866) { 1 X3 } { 1 Y3 };\n",\ +"\n",\ +"elements\n",\ +"(1, 2, 3);\n",\ +"\n",\ +"endrule\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"rule \"Right 120 (1)\"\n",\ +"\n",\ +"quality 1\n",\ +"\n",\ +"mappoints\n",\ +"(0, 0);\n",\ +"(1, 0);\n",\ +"(1.5, 0.866);\n",\ +"\n",\ +"maplines\n",\ +"(1, 2) del;\n",\ +"(2, 3) del;\n",\ +"\n",\ +"newpoints\n",\ +"(0.5, 0.866) { 1 X3, -1 X2 } { 1 Y3 };\n",\ +"\n",\ +"newlines\n",\ +"(1, 4);\n",\ +"(4, 3);\n",\ +"\n",\ +"freearea\n",\ +"(0, 0);\n",\ +"(1, 0) { 1 X2 } { };\n",\ +"(1.5, 0.866) { 1 X3 } { 1 Y3 };\n",\ +"(1, 1.732) { -2 X2, 2 X3 } { 2 Y3 };\n",\ +"(0, 1.732) { -3 X2, 2 X3 } { 2 Y3 };\n",\ +"(-0.5, 0.866) { -2 X2, 1 X3 } {1 Y3 };\n",\ +"\n",\ +"elements\n",\ +"(1, 2, 4);\n",\ +"(2, 3, 4);\n",\ +"\n",\ +"endrule\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"rule \"Left 120 (1)\"\n",\ +"\n",\ +"quality 1\n",\ +"\n",\ +"mappoints\n",\ +"(0, 0);\n",\ +"(1, 0);\n",\ +"(-0.5, 0.866);\n",\ +"\n",\ +"maplines\n",\ +"(1, 2) del;\n",\ +"(3, 1) del;\n",\ +"\n",\ +"newpoints\n",\ +"(0.5, 0.866) { 1 X3, 1 X2 } { 1 Y3 };\n",\ +"\n",\ +"newlines\n",\ +"(3, 4);\n",\ +"(4, 2);\n",\ +"\n",\ +"freearea\n",\ +"(0, 0);\n",\ +"(1, 0) { 1 X2 } { };\n",\ +"(1.5, 0.866) { 2 X2, 1 X3 } { 1 Y3 };\n",\ +"(1, 1.732) { 2 X2, 2 X3 } { 2 Y3 };\n",\ +"(0, 1.732) { -1 X2, 2 X3 } { 2 Y3 };\n",\ +"(-0.5, 0.866) { 1 X3 } {1 Y3 };\n",\ +"\n",\ +"elements\n",\ +"(1, 2, 4);\n",\ +"(2, 3, 4);\n",\ +"\n",\ +"endrule\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"rule \"Left Right 120 (1)\"\n",\ +"\n",\ +"quality 1\n",\ +"\n",\ +"mappoints\n",\ +"(0, 0);\n",\ +"(1, 0);\n",\ +"(-0.5, 0.866);\n",\ +"(1.5, 0.866);\n",\ +"\n",\ +"maplines\n",\ +"(1, 2) del;\n",\ +"(3, 1) del;\n",\ +"(2, 4) del;\n",\ +"\n",\ +"newpoints\n",\ +"(0.5, 0.866) { 0.5 X3, 0.5 X4 } { 0.5 Y3, 0.5 Y4 };\n",\ +"\n",\ +"newlines\n",\ +"(3, 5);\n",\ +"(5, 4);\n",\ +"\n",\ +"freearea\n",\ +"(0, 0);\n",\ +"(1, 0) { 1 X2 } { };\n",\ +"(1.5, 0.866) { 1 X4 } { 1 Y4 };\n",\ +"(1, 1.299) { -0.5 X2, 0.375 X3, 1.125 X4 } { -0.5 Y2, 0.375 Y3, 1.125 Y4 };\n",\ +"(0, 1.299) { 1.125 X3, 0.375 X4 } { 1.125 Y3, 0.375 Y4 };\n",\ +"(-0.5, 0.866) { 1 X3 } { 1 Y3 };\n",\ +"\n",\ +"elements\n",\ +"(1, 2, 5);\n",\ +"(3, 1, 5);\n",\ +"(2, 4, 5);\n",\ +"\n",\ +"endrule\n",\ +"\n",\ +"\n",\ +"rule \"Fill Triangle\"\n",\ +"\n",\ +"quality 1\n",\ +"\n",\ +"mappoints\n",\ +"(0, 0);\n",\ +"(1, 0);\n",\ +"(0.5, 0.866);\n",\ +"\n",\ +"maplines\n",\ +"(1, 2) del;\n",\ +"(2, 3) del;\n",\ +"(3, 1) del;\n",\ +"\n",\ +"newpoints\n",\ +"\n",\ +"newlines\n",\ +"\n",\ +"freearea\n",\ +"(0, 0);\n",\ +"(1, 0) { 1 X2 } { 1 Y2 };\n",\ +"(0.5, 0.866) { 1 X3 } { 1 Y3 };\n",\ +"\n",\ +"elements\n",\ +"(1, 2, 3);\n",\ +"\n",\ +"endrule\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"rule \"Vis A Vis (1)\"\n",\ +"\n",\ +"quality 1\n",\ +"\n",\ +"mappoints\n",\ +"(0, 0);\n",\ +"(1, 0);\n",\ +"(0.5, 0.866);\n",\ +"\n",\ +"maplines\n",\ +"(1, 2) del;\n",\ +"\n",\ +"newpoints\n",\ +"\n",\ +"newlines\n",\ +"(1, 3);\n",\ +"(3, 2);\n",\ +"\n",\ +"freearea\n",\ +"(0, 0);\n",\ +"(1, 0) { 1 X2 } { };\n",\ +"(1.2, 0.693) { 0.8 X2, 0.8 X3 } { 0.8 Y2, 0.8 Y3 };\n",\ +"(0.5, 0.866) { 1 X3 } { 1 Y3 };\n",\ +"(-0.2, 0.693) { -0.6 X2, 0.8 X3 } { -0.6 Y2, 0.8 Y3 };\n",\ +"\n",\ +"freearea2\n",\ +"(0, 0);\n",\ +"(1, 0) { 1 X2 } { };\n",\ +"(0.75, 0.433) { 0.5 X2, 0.5 X3 } { 0.5 Y2, 0.5 Y3 };\n",\ +"(0.5, 0.866) { 1 X3 } { 1 Y3 };\n",\ +"(0.25, 0.433) { 0.5 X3 } { 0.5 Y3 };\n",\ +"\n",\ +"elements\n",\ +"(1, 2, 3);\n",\ +"\n",\ +"endrule\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"rule \"2 h Vis A Vis (1)\"\n",\ +"\n",\ +"quality 3\n",\ +"\n",\ +"mappoints\n",\ +"(0, 0);\n",\ +"(1, 0);\n",\ +"(1, 1.732);\n",\ +"(0, 1.732);\n",\ +"\n",\ +"maplines\n",\ +"(1, 2) del;\n",\ +"(3, 4) del;\n",\ +"\n",\ +"newpoints\n",\ +"(0.5, 0.866) { 0.25 X3, 0.25 X4 } { 0.25 Y2, 0.25 Y3, 0.25 Y4 };\n",\ +"\n",\ +"newlines\n",\ +"(1, 5);\n",\ +"(5, 4);\n",\ +"(3, 5);\n",\ +"(5, 2);\n",\ +"\n",\ +"freearea\n",\ +"(0, 0);\n",\ +"(1, 0) { 1 X2 } { 1 Y2 };\n",\ +"(1.5, 0.866) { 0.75 X2, 0.75 X3, -0.25 X4 } { 0.75 Y2, 0.75 Y3, -0.25 Y4 };\n",\ +"(1, 1.732) { 1 X3 } { 1 Y3 };\n",\ +"(0, 1.732) { 1 X4 } { 1 Y4 };\n",\ +"(-0.5, 0.866) { 0.75 X4, -0.25 X2, -0.25 X3 } { 0.75 Y4, -0.25 Y3 };\n",\ +"\n",\ +"elements\n",\ +"(1, 2, 5);\n",\ +"(3, 4, 5);\n",\ +"\n",\ +"endrule\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +"\n",\ +0}; +} diff --git a/contrib/Netgen/libsrc/meshing/zrefine.cpp b/contrib/Netgen/libsrc/meshing/zrefine.cpp new file mode 100644 index 0000000000..7b4d4804a9 --- /dev/null +++ b/contrib/Netgen/libsrc/meshing/zrefine.cpp @@ -0,0 +1,735 @@ +#include <mystdlib.h> +#include "meshing.hpp" + +#include <csg.hpp> + +namespace netgen +{ + + // find singular edges + void SelectSingularEdges (const Mesh & mesh, const CSGeometry & geom, + INDEX_2_HASHTABLE<int> & singedges, + ZRefinementOptions & opt) + { + int i, j; + + // edges selected in csg input file + for (i = 1; i <= geom.singedges.Size(); i++) + { + const SingularEdge & se = *geom.singedges.Get(i); + for (j = 1; j <= se.segms.Size(); j++) + { + INDEX_2 i2 = se.segms.Get(j); + singedges.Set (i2, 1); + } + } + + // edges interactively selected + for (i = 1; i <= mesh.GetNSeg(); i++) + { + const Segment & seg = mesh.LineSegment(i); + if (seg.singedge_left || seg.singedge_right) + { + INDEX_2 i2(seg.p1, seg.p2); + i2.Sort(); + singedges.Set (i2, 1); + } + } + } + + + /** + Convert elements (vol-tets, surf-trigs) into prisms/quads + */ + void MakePrismsSingEdge (Mesh & mesh, INDEX_2_HASHTABLE<int> & singedges) + { + int i, j, k; + + // volume elements + for (i = 1; i <= mesh.GetNE(); i++) + { + Element & el = mesh.VolumeElement(i); + if (el.GetType() != TET) continue; + + for (j = 1; j <= 3; j++) + for (k = j+1; k <= 4; k++) + { + INDEX_2 edge(el.PNum(j), el.PNum(k)); + edge.Sort(); + if (singedges.Used (edge)) + { + int pi3 = 1, pi4 = 1; + while (pi3 == j || pi3 == k) pi3++; + pi4 = 10 - j - k - pi3; + + int p3 = el.PNum(pi3); + int p4 = el.PNum(pi4); + + el.SetType(PRISM); + el.PNum(1) = edge.I1(); + el.PNum(2) = p3; + el.PNum(3) = p4; + el.PNum(4) = edge.I2(); + el.PNum(5) = p3; + el.PNum(6) = p4; + } + } + } + + // surface elements + for (i = 1; i <= mesh.GetNSE(); i++) + { + Element2d & el = mesh.SurfaceElement(i); + if (el.GetType() != TRIG) continue; + + for (j = 1; j <= 3; j++) + { + k = (j % 3) + 1; + INDEX_2 edge(el.PNum(j), el.PNum(k)); + edge.Sort(); + + if (singedges.Used (edge)) + { + int pi3 = 6-j-k; + int p3 = el.PNum(pi3); + int p1 = el.PNum(j); + int p2 = el.PNum(k); + + el.SetType(QUAD); + el.PNum(1) = p2; + el.PNum(2) = p3; + el.PNum(3) = p3; + el.PNum(4) = p1; + } + } + } + } + + + /* + Convert tets and pyramids next to close (identified) points into prisms + */ + void MakePrismsClosePoints (Mesh & mesh) + { + int i, j, k; + for (i = 1; i <= mesh.GetNE(); i++) + { + Element & el = mesh.VolumeElement(i); + if (el.GetType() == TET) + { + for (j = 1; j <= 3; j++) + for (k = j+1; k <= 4; k++) + { + INDEX_2 edge(el.PNum(j), el.PNum(k)); + edge.Sort(); + if (mesh.GetIdentifications().GetSymmetric (el.PNum(j), el.PNum(k))) + { + int pi3 = 1, pi4 = 1; + while (pi3 == j || pi3 == k) pi3++; + pi4 = 10 - j - k - pi3; + + int p3 = el.PNum(pi3); + int p4 = el.PNum(pi4); + + el.SetType(PRISM); + el.PNum(1) = edge.I1(); + el.PNum(2) = p3; + el.PNum(3) = p4; + el.PNum(4) = edge.I2(); + el.PNum(5) = p3; + el.PNum(6) = p4; + } + } + } + + if (el.GetType() == PYRAMID) + { + // pyramid, base face = 1,2,3,4 + + for (j = 0; j <= 1; j++) + { + int pi1 = el.PNum( (j+0) % 4 + 1); + int pi2 = el.PNum( (j+1) % 4 + 1); + int pi3 = el.PNum( (j+2) % 4 + 1); + int pi4 = el.PNum( (j+3) % 4 + 1); + int pi5 = el.PNum(5); + + INDEX_2 edge1(pi1, pi4); + INDEX_2 edge2(pi2, pi3); + edge1.Sort(); + edge2.Sort(); + if (mesh.GetIdentifications().GetSymmetric (pi1, pi4) && + mesh.GetIdentifications().GetSymmetric (pi2, pi3)) + { + int p3 = el.PNum(pi3); + int p4 = el.PNum(pi4); + + el.SetType(PRISM); + el.PNum(1) = pi1; + el.PNum(2) = pi2; + el.PNum(3) = pi5; + el.PNum(4) = pi4; + el.PNum(5) = pi3; + el.PNum(6) = pi5; + } + } + } + } + + for (i = 1; i <= mesh.GetNSE(); i++) + { + Element2d & el = mesh.SurfaceElement(i); + if (el.GetType() != TRIG) continue; + + for (j = 1; j <= 3; j++) + { + k = (j % 3) + 1; + INDEX_2 edge(el.PNum(j), el.PNum(k)); + edge.Sort(); + + if (mesh.GetIdentifications().GetSymmetric (el.PNum(j), el.PNum(k))) + { + int pi3 = 6-j-k; + int p3 = el.PNum(pi3); + int p1 = el.PNum(j); + int p2 = el.PNum(k); + + el.SetType(QUAD); + el.PNum(1) = p2; + el.PNum(2) = p3; + el.PNum(3) = p3; + el.PNum(4) = p1; + } + } + } + } + + + +#ifdef OLD + void MakeCornerNodes (Mesh & mesh, + INDEX_HASHTABLE<int> & cornernodes) + { + int i, j; + int nseg = mesh.GetNSeg(); + ARRAY<int> edgesonpoint(mesh.GetNP()); + for (i = 1; i <= mesh.GetNP(); i++) + edgesonpoint.Elem(i) = 0; + + for (i = 1; i <= nseg; i++) + { + for (j = 1; j <= 2; j++) + { + int pi = (j == 1) ? + mesh.LineSegment(i).p1 : + mesh.LineSegment(i).p2; + edgesonpoint.Elem(pi)++; + } + } + + /* + cout << "cornernodes: "; + for (i = 1; i <= edgesonpoint.Size(); i++) + if (edgesonpoint.Get(i) >= 6) + { + cornernodes.Set (i, 1); + cout << i << " "; + } + cout << endl; + */ + // cornernodes.Set (5, 1); + } +#endif + + + void RefinePrisms (Mesh & mesh, const CSGeometry * geom, + ZRefinementOptions & opt) + { + int i, j, k; + bool found, change; + int cnt = 0; + + + // markers for z-refinement: p1, p2, levels + // p1-p2 is an edge to be refined + ARRAY<INDEX_3> ref_uniform; + ARRAY<INDEX_3> ref_singular; + ARRAY<INDEX_4 > ref_slices; + + BitArray first_id(geom->identifications.Size()); + first_id.Set(); + + + INDEX_2_HASHTABLE<int> & identpts = + mesh.GetIdentifications().GetIdentifiedPoints (); + + if (&identpts) + { + for (i = 1; i <= identpts.GetNBags(); i++) + for (j = 1; j <= identpts.GetBagSize(i); j++) + { + INDEX_2 pair; + int idnr; + identpts.GetData(i, j, pair, idnr); + const CloseSurfaceIdentification * csid = + dynamic_cast<const CloseSurfaceIdentification*> + (geom->identifications.Get(idnr)); + if (csid) + { + if (!csid->GetSlices().Size()) + { + if (first_id.Test (idnr)) + { + first_id.Clear(idnr); + ref_uniform.Append (INDEX_3 (pair.I1(), pair.I2(), csid->RefLevels())); + ref_singular.Append (INDEX_3 (pair.I1(), pair.I2(), csid->RefLevels1())); + ref_singular.Append (INDEX_3 (pair.I2(), pair.I1(), csid->RefLevels2())); + } + } + else + { + const ARRAY<double> & slices = csid->GetSlices(); + INDEX_4 i4; + i4[0] = pair.I1(); + i4[1] = pair.I2(); + i4[2] = idnr; + i4[3] = csid->GetSlices().Size(); + ref_slices.Append (i4); + } + } + } + } + + + + ARRAY<EdgePointGeomInfo> epgi; + + while (1) + { + cnt++; + PrintMessage (3, "Z-Refinement, level = ", cnt); + INDEX_2_HASHTABLE<int> refedges(mesh.GetNSE()+1); + + + found = 0; + // mark prisms due to close surface flags: + int oldsize = ref_uniform.Size(); + for (i = 1; i <= oldsize; i++) + { + int pi1 = ref_uniform.Get(i).I1(); + int pi2 = ref_uniform.Get(i).I2(); + int levels = ref_uniform.Get(i).I3(); + + if (levels > 0) + { + const Point3d & p1 = mesh.Point(pi1); + const Point3d & p2 = mesh.Point(pi2); + int npi; + + INDEX_2 edge(pi1, pi2); + edge.Sort(); + if (!refedges.Used(edge)) + { + Point3d np = Center (p1, p2); + npi = mesh.AddPoint (np); + refedges.Set (edge, npi); + found = 1; + } + + ref_uniform.Elem(i) = INDEX_3(pi1, npi, levels-1); + ref_uniform.Append (INDEX_3(pi2, npi, levels-1)); + } + } + for (i = 1; i <= ref_singular.Size(); i++) + { + int pi1 = ref_singular.Get(i).I1(); + int pi2 = ref_singular.Get(i).I2(); + int levels = ref_singular.Get(i).I3(); + + if (levels > 0) + { + const Point3d & p1 = mesh.Point(pi1); + const Point3d & p2 = mesh.Point(pi2); + int npi; + + INDEX_2 edge(pi1, pi2); + edge.Sort(); + if (!refedges.Used(edge)) + { + Point3d np = Center (p1, p2); + npi = mesh.AddPoint (np); + refedges.Set (edge, npi); + found = 1; + } + else + npi = refedges.Get (edge); + + ref_singular.Elem(i) = INDEX_3(pi1, npi, levels-1); + } + } + + for (i = 1; i <= ref_slices.Size(); i++) + { + int pi1 = ref_slices.Get(i)[0]; + int pi2 = ref_slices.Get(i)[1]; + int idnr = ref_slices.Get(i)[2]; + int slicenr = ref_slices.Get(i)[3]; + + if (slicenr > 0) + { + const Point3d & p1 = mesh.Point(pi1); + const Point3d & p2 = mesh.Point(pi2); + int npi; + + const CloseSurfaceIdentification * csid = + dynamic_cast<const CloseSurfaceIdentification*> + (geom->identifications.Get(idnr)); + + + INDEX_2 edge(pi1, pi2); + edge.Sort(); + if (!refedges.Used(edge)) + { + const ARRAY<double> & slices = csid->GetSlices(); + double slicefac = slices.Get(slicenr); + double slicefaclast = + (slicenr == slices.Size()) ? 1 : slices.Get(slicenr+1); + + Point3d np = p1 + (slicefac / slicefaclast) * (p2-p1); + npi = mesh.AddPoint (np); + refedges.Set (edge, npi); + found = 1; + } + else + npi = refedges.Get (edge); + + ref_slices.Elem(i)[1] = npi; + ref_slices.Elem(i)[3] --; + } + } + + + + + for (i = 1; i <= mesh.GetNE(); i++) + { + Element & el = mesh.VolumeElement (i); + if (el.GetType() != PRISM) + continue; + + for (j = 1; j <= 3; j++) + { + int pi1 = el.PNum(j); + int pi2 = el.PNum(j+3); + const Point3d & p1 = mesh.Point(pi1); + const Point3d & p2 = mesh.Point(pi2); + + bool ref = 0; + + /* + if (Dist (p1, p2) > mesh.GetH (Center (p1, p2))) + ref = 1; + */ + + /* + if (cnt <= opt.minref) + ref = 1; + */ + + /* + if ((pi1 == 460 || pi2 == 460 || + pi1 == 461 || pi2 == 461) && cnt <= 8) ref = 1; + */ + if (ref == 1) + { + INDEX_2 edge(pi1, pi2); + edge.Sort(); + if (!refedges.Used(edge)) + { + Point3d np = Center (p1, p2); + int npi = mesh.AddPoint (np); + refedges.Set (edge, npi); + found = 1; + } + } + } + } + + if (!found) break; + + // build closure: + PrintMessage (5, "start closure"); + do + { + PrintMessage (5, "start loop"); + change = 0; + for (i = 1; i <= mesh.GetNE(); i++) + { + Element & el = mesh.VolumeElement (i); + if (el.GetType() != PRISM) + continue; + + bool hasref = 0, hasnonref = 0; + for (j = 1; j <= 3; j++) + { + int pi1 = el.PNum(j); + int pi2 = el.PNum(j+3); + if (pi1 != pi2) + { + INDEX_2 edge(pi1, pi2); + edge.Sort(); + if (refedges.Used(edge)) + hasref = 1; + else + hasnonref = 1; + } + } + + if (hasref && hasnonref) + { + // cout << "el " << i << " in closure" << endl; + change = 1; + for (j = 1; j <= 3; j++) + { + int pi1 = el.PNum(j); + int pi2 = el.PNum(j+3); + const Point3d & p1 = mesh.Point(pi1); + const Point3d & p2 = mesh.Point(pi2); + + INDEX_2 edge(pi1, pi2); + edge.Sort(); + if (!refedges.Used(edge)) + { + Point3d np = Center (p1, p2); + int npi = mesh.AddPoint (np); + refedges.Set (edge, npi); + } + } + } + } + } + while (change); + + PrintMessage (5, "Do segments"); + + // (*testout) << "closure formed, np = " << mesh.GetNP() << endl; + + int oldns = mesh.GetNSeg(); + + for (i = 1; i <= oldns; i++) + { + const Segment & el = mesh.LineSegment(i); + + INDEX_2 i2(el.p1, el.p2); + i2.Sort(); + + int pnew; + EdgePointGeomInfo ngi; + + if (refedges.Used(i2)) + { + pnew = refedges.Get(i2); + // ngi = epgi.Get(pnew); + } + else + { + continue; + + // Point3d pb; + + // /* + // geom->PointBetween (mesh.Point (el.p1), + // mesh.Point (el.p2), + // el.surfnr1, el.surfnr2, + // el.epgeominfo[0], el.epgeominfo[1], + // pb, ngi); + // */ + // pb = Center (mesh.Point (el.p1), mesh.Point (el.p2)); + + // pnew = mesh.AddPoint (pb); + + // refedges.Set (i2, pnew); + + // if (pnew > epgi.Size()) + // epgi.SetSize (pnew); + // epgi.Elem(pnew) = ngi; + } + + Segment ns1 = el; + Segment ns2 = el; + ns1.p2 = pnew; + ns1.epgeominfo[1] = ngi; + ns2.p1 = pnew; + ns2.epgeominfo[0] = ngi; + + mesh.LineSegment(i) = ns1; + mesh.AddSegment (ns2); + } + + PrintMessage (5, "Segments done, NSeg = ", mesh.GetNSeg()); + + // do refinement + int oldne = mesh.GetNE(); + for (i = 1; i <= oldne; i++) + { + Element & el = mesh.VolumeElement (i); + if (el.GetNP() != 6) + continue; + + int npi[3]; + for (j = 1; j <= 3; j++) + { + int pi1 = el.PNum(j); + int pi2 = el.PNum(j+3); + + if (pi1 == pi2) + npi[j-1] = pi1; + else + { + INDEX_2 edge(pi1, pi2); + edge.Sort(); + if (refedges.Used (edge)) + npi[j-1] = refedges.Get(edge); + else + { + /* + (*testout) << "ERROR: prism " << i << " has hanging node !!" + << ", edge = " << edge << endl; + cerr << "ERROR: prism " << i << " has hanging node !!" << endl; + */ + npi[j-1] = 0; + } + } + } + + if (npi[0]) + { + Element nel1(6), nel2(6); + for (j = 1; j <= 3; j++) + { + nel1.PNum(j) = el.PNum(j); + nel1.PNum(j+3) = npi[j-1]; + nel2.PNum(j) = npi[j-1]; + nel2.PNum(j+3) = el.PNum(j+3); + } + nel1.SetIndex (el.GetIndex()); + nel2.SetIndex (el.GetIndex()); + mesh.VolumeElement (i) = nel1; + mesh.AddVolumeElement (nel2); + } + } + + + PrintMessage (5, "Elements done, NE = ", mesh.GetNE()); + + + // do surface elements + int oldnse = mesh.GetNSE(); + // cout << "oldnse = " << oldnse << endl; + for (i = 1; i <= oldnse; i++) + { + Element2d & el = mesh.SurfaceElement (i); + if (el.GetType() != QUAD) + continue; + + int index = el.GetIndex(); + int npi[2]; + for (j = 1; j <= 2; j++) + { + int pi1, pi2; + + if (j == 1) + { + pi1 = el.PNum(1); + pi2 = el.PNum(4); + } + else + { + pi1 = el.PNum(2); + pi2 = el.PNum(3); + } + + if (pi1 == pi2) + npi[j-1] = pi1; + else + { + INDEX_2 edge(pi1, pi2); + edge.Sort(); + if (refedges.Used (edge)) + npi[j-1] = refedges.Get(edge); + else + { + npi[j-1] = 0; + } + } + } + + if (npi[0]) + { + Element2d nel1(QUAD), nel2(QUAD); + for (j = 1; j <= 4; j++) + { + nel1.PNum(j) = el.PNum(j); + nel2.PNum(j) = el.PNum(j); + } + nel1.PNum(3) = npi[1]; + nel1.PNum(4) = npi[0]; + nel2.PNum(1) = npi[0]; + nel2.PNum(2) = npi[1]; + /* + for (j = 1; j <= 2; j++) + { + nel1.PNum(j) = el.PNum(j); + nel1.PNum(j+2) = npi[j-1]; + nel2.PNum(j) = npi[j-1]; + nel2.PNum(j+2) = el.PNum(j+2); + } + */ + nel1.SetIndex (el.GetIndex()); + nel2.SetIndex (el.GetIndex()); + + mesh.SurfaceElement (i) = nel1; + mesh.AddSurfaceElement (nel2); + + int si = mesh.GetFaceDescriptor (index).SurfNr(); + + Point<3> hp = mesh.Point(npi[0]); + geom->GetSurface(si)->Project (hp); + mesh.Point (npi[0]).SetPoint (hp); + + hp = mesh.Point(npi[1]); + geom->GetSurface(si)->Project (hp); + mesh.Point (npi[1]).SetPoint (hp); + + // geom->GetSurface(si)->Project (mesh.Point(npi[0])); + // geom->GetSurface(si)->Project (mesh.Point(npi[1])); + } + } + + PrintMessage (5, "Surface elements done, NSE = ", mesh.GetNSE()); + + } + } + + + + void ZRefinement (Mesh & mesh, const CSGeometry * geom, + ZRefinementOptions & opt) + { + INDEX_2_HASHTABLE<int> singedges(mesh.GetNSeg()); + + SelectSingularEdges (mesh, *geom, singedges, opt); + MakePrismsSingEdge (mesh, singedges); + MakePrismsClosePoints (mesh); + + RefinePrisms (mesh, geom, opt); + } + + + + ZRefinementOptions :: ZRefinementOptions() + { + minref = 0; + } + +} diff --git a/contrib/Netgen/libsrc/occ/Makefile b/contrib/Netgen/libsrc/occ/Makefile new file mode 100644 index 0000000000..6fe1d8bc0d --- /dev/null +++ b/contrib/Netgen/libsrc/occ/Makefile @@ -0,0 +1,11 @@ +# +# Makefile for open cascade library +# +src = occgeom.cpp occmeshsurf.cpp occgenmesh.cpp + +lib = occ +libpath = libsrc/occ +# +# +include ../makefile.inc + diff --git a/contrib/Netgen/libsrc/occ/occgenmesh.cpp b/contrib/Netgen/libsrc/occ/occgenmesh.cpp new file mode 100644 index 0000000000..822edf3681 --- /dev/null +++ b/contrib/Netgen/libsrc/occ/occgenmesh.cpp @@ -0,0 +1,1245 @@ +#ifdef OCCGEOMETRY + +#include <mystdlib.h> +#include <occgeom.hpp> +#include <meshing.hpp> + +#include <stlgeom.hpp> + + +namespace netgen +{ + +#include "occmeshsurf.hpp" + +#define TCL_OK 0 +#define TCL_ERROR 1 + +extern STLParameters stlparam; + +#define DIVIDEEDGESECTIONS 1000 +#define IGNORECURVELENGTH 1e-4 + + +void DivideEdge (TopoDS_Edge & edge, + ARRAY<MeshPoint> & ps, + ARRAY<double> & params, + Mesh & mesh) +{ + double s0, s1; + int j; + double maxh = mparam.maxh; + int nsubedges = 1; + gp_Pnt pnt, oldpnt; + double svalue[DIVIDEEDGESECTIONS]; + + GProp_GProps system; + BRepGProp::LinearProperties(edge, system); + double L = system.Mass(); + + Handle(Geom_Curve) c = BRep_Tool::Curve(edge, s0, s1); + + double hvalue[DIVIDEEDGESECTIONS+1]; + hvalue[0] = 0; + pnt = c->Value(s0); + + double olddist = 0; + double dist = 0; + + for (int i = 1; i <= DIVIDEEDGESECTIONS; i++) + { + oldpnt = pnt; + pnt = c->Value(s0+(i/double(DIVIDEEDGESECTIONS))*(s1-s0)); + hvalue[i] = hvalue[i-1] + + 1.0/mesh.GetH(Point3d(pnt.X(), pnt.Y(), pnt.Z()))* + pnt.Distance(oldpnt); + + olddist = dist; + dist = pnt.Distance(oldpnt); + } + + // nsubedges = int(ceil(hvalue[DIVIDEEDGESECTIONS])); + nsubedges = max (1, int(floor(hvalue[DIVIDEEDGESECTIONS]+0.5))); + + ps.SetSize(nsubedges-1); + params.SetSize(nsubedges+1); + + int i = 1; + int i1 = 0; + do + { + if (hvalue[i1]/hvalue[DIVIDEEDGESECTIONS]*nsubedges >= i) + { + params[i] = s0+(i1/double(DIVIDEEDGESECTIONS))*(s1-s0); + pnt = c->Value(params[i]); + ps[i-1] = MeshPoint (Point3d(pnt.X(), pnt.Y(), pnt.Z())); + i++; + } + i1++; + if (i1 > DIVIDEEDGESECTIONS) + { + nsubedges = i; + ps.SetSize(nsubedges-1); + params.SetSize(nsubedges+1); + cout << "divide edge: local h too small" << endl; + } + } while (i < nsubedges); + + params[0] = s0; + params[nsubedges] = s1; + + if (params[nsubedges] <= params[nsubedges-1]) + { + cout << "CORRECTED" << endl; + ps.SetSize (nsubedges-2); + params.SetSize (nsubedges); + params[nsubedges] = s1; + } +} + + + + +static void FindEdges (OCCGeometry & geom, Mesh & mesh) +{ + int i, j; + + char * savetask = multithread.task; + multithread.task = "Edge meshing"; + + (*testout) << "edge meshing" << endl; + + TopExp_Explorer exp0, exp01, exp1, exp2, exp3; + + int nvertices = geom.vmap.Extent(); + int nedges = geom.emap.Extent(); + for (i = 1; i <= nvertices; i++) + { + gp_Pnt pnt = BRep_Tool::Pnt (TopoDS::Vertex(geom.vmap(i))); + MeshPoint mp( Point3d(pnt.X(), pnt.Y(), pnt.Z()) ); + + /* + int exists = 0; + + for (j = 1; !exists && (j <= mesh.GetNP()); j++) + if ((mesh.Point(j)-Point<3>(mp)).Length() < 1e-6) + exists = 1; + + if (!exists) + */ + + mesh.AddPoint (mp); + } + + int facenr = 0; + int edgenr = 0; + + int total = 0; + int solidnr = 0; + + ARRAY<int> face2solid; + face2solid.SetSize (geom.fmap.Extent()); + face2solid = 0; + + /* + for (exp0.Init(geom.shape, TopAbs_SOLID); exp0.More(); exp0.Next()) + { + solidnr++; + for (exp01.Init(exp0.Current(), TopAbs_SHELL); exp01.More(); exp01.Next()) + { + TopoDS_Shape shell = exp01.Current(); + for (exp1.Init(shell, TopAbs_FACE); exp1.More(); exp1.Next()) + { + TopoDS_Face face = TopoDS::Face(exp1.Current()); + facenr = geom.fmap.FindIndex(face); + face2solid[facenr-1] = solidnr; + + for (exp2.Init (face, TopAbs_WIRE); exp2.More(); exp2.Next()) + { + TopoDS_Shape wire = exp2.Current(); + + for (exp3.Init (wire, TopAbs_EDGE); exp3.More(); exp3.Next()) + { + total++; + } + } + } + } + } + */ + + for (exp0.Init(geom.shape, TopAbs_SOLID); exp0.More(); exp0.Next()) + { + solidnr++; + for (exp1.Init(exp0.Current(), TopAbs_FACE); exp1.More(); exp1.Next()) + { + TopoDS_Face face = TopoDS::Face(exp1.Current()); + facenr = geom.fmap.FindIndex(face); + face2solid[facenr-1] = solidnr; + } + } + + + for (int i3 = 1; i3 <= geom.fmap.Extent(); i3++) + for (exp2.Init (geom.fmap(i3), TopAbs_WIRE); exp2.More(); exp2.Next()) + for (exp3.Init (exp2.Current(), TopAbs_EDGE); exp3.More(); exp3.Next()) + total++; + + + int curr = 0; + + + solidnr = 0; + /* + for (exp0.Init(geom.shape, TopAbs_SOLID); exp0.More(); exp0.Next()) + { + solidnr++; + for (exp01.Init(exp0.Current(), TopAbs_SHELL); exp01.More(); exp01.Next()) + { + TopoDS_Shape shell = exp01.Current(); + + for (exp1.Init(shell, TopAbs_FACE); exp1.More(); exp1.Next()) + { + + TopoDS_Face face = TopoDS::Face(exp1.Current()); + */ + + for (int i3 = 1; i3 <= geom.fmap.Extent(); i3++) + + + { + { + { + TopoDS_Face face = TopoDS::Face(geom.fmap(i3)); + solidnr = face2solid[i3-1]; + + + facenr = geom.fmap.FindIndex (face); + + mesh.AddFaceDescriptor (FaceDescriptor(facenr, solidnr, 0, 0)); + Handle(Geom_Surface) occface = BRep_Tool::Surface(face); + + for (exp2.Init (face, TopAbs_WIRE); exp2.More(); exp2.Next()) + { + TopoDS_Shape wire = exp2.Current(); + + for (exp3.Init (wire, TopAbs_EDGE); exp3.More(); exp3.Next()) + { + curr++; + + multithread.percent = 100 * curr / (double) total; + if (multithread.terminate) return; + + TopoDS_Edge edge = TopoDS::Edge (exp3.Current()); + if (BRep_Tool::Degenerated(edge)) continue; + + if (geom.vmap.FindIndex(TopExp::FirstVertex (edge)) == + geom.vmap.FindIndex(TopExp::LastVertex (edge))) + { + GProp_GProps system; + BRepGProp::LinearProperties(edge, system); + + if (system.Mass() < 1e-5) + { + cout << "ignoring edge " << geom.emap.FindIndex (edge) + << ". closed edge with length < 1e-5" << endl; + continue; + } + } + + + Handle(Geom2d_Curve) cof; + double s0, s1; + cof = BRep_Tool::CurveOnSurface (edge, face, s0, s1); + + int geomedgenr = geom.emap.FindIndex(edge); + + ARRAY <MeshPoint> mp; + ARRAY <double> params; + + DivideEdge (edge, mp, params, mesh); + + + ARRAY <int> pnums; + pnums.SetSize (mp.Size()+2); + + pnums[0] = geom.vmap.FindIndex (TopExp::FirstVertex (edge)); + pnums[pnums.Size()-1] = geom.vmap.FindIndex (TopExp::LastVertex (edge)); + + for (i = 1; i <= mp.Size(); i++) + { + int exists = 0; + + for (j = 1; !exists && (j <= mesh.GetNP()-nvertices); j++) + if ((mesh.Point(nvertices+j)-Point<3>(mp[i-1])).Length() < 1e-6) exists = 1; + + if (exists) + { + pnums[i] = nvertices+j-1; + } + else + { + mesh.AddPoint (mp[i-1]); + pnums[i] = mesh.GetNP(); + } + } + + for (i = 1; i <= mp.Size()+1; i++) + { + edgenr++; + Segment seg; + + seg.p1 = pnums[i-1]; + seg.p2 = pnums[i]; + seg.edgenr = edgenr; + seg.si = facenr; + seg.epgeominfo[0].dist = params[i-1]; + seg.epgeominfo[1].dist = params[i]; + seg.epgeominfo[0].edgenr = geomedgenr; + seg.epgeominfo[1].edgenr = geomedgenr; + + gp_Pnt2d p2d; + p2d = cof->Value(params[i-1]); + // if (i == 1) p2d = cof->Value(s0); + seg.epgeominfo[0].u = p2d.X(); + seg.epgeominfo[0].v = p2d.Y(); + p2d = cof->Value(params[i]); + // if (i == mp.Size()+1) p2d = cof -> Value(s1); + seg.epgeominfo[1].u = p2d.X(); + seg.epgeominfo[1].v = p2d.Y(); + + /* + if (occface->IsUPeriodic()) + { + cout << "U Periodic" << endl; + if (fabs(seg.epgeominfo[1].u-seg.epgeominfo[0].u) > + fabs(seg.epgeominfo[1].u- + (seg.epgeominfo[0].u-occface->UPeriod()))) + seg.epgeominfo[0].u = p2d.X()+occface->UPeriod(); + + if (fabs(seg.epgeominfo[1].u-seg.epgeominfo[0].u) > + fabs(seg.epgeominfo[1].u- + (seg.epgeominfo[0].u+occface->UPeriod()))) + seg.epgeominfo[0].u = p2d.X()-occface->UPeriod(); + } + + if (occface->IsVPeriodic()) + { + cout << "V Periodic" << endl; + if (fabs(seg.epgeominfo[1].v-seg.epgeominfo[0].v) > + fabs(seg.epgeominfo[1].v- + (seg.epgeominfo[0].v-occface->VPeriod()))) + seg.epgeominfo[0].v = p2d.Y()+occface->VPeriod(); + + if (fabs(seg.epgeominfo[1].v-seg.epgeominfo[0].v) > + fabs(seg.epgeominfo[1].v- + (seg.epgeominfo[0].v+occface->VPeriod()))) + seg.epgeominfo[0].v = p2d.Y()-occface->VPeriod(); + } + */ + + if (edge.Orientation() == TopAbs_REVERSED) + { + swap (seg.p1, seg.p2); + swap (seg.epgeominfo[0].dist, seg.epgeominfo[1].dist); + swap (seg.epgeominfo[0].u, seg.epgeominfo[1].u); + swap (seg.epgeominfo[0].v, seg.epgeominfo[1].v); + } + + mesh.AddSegment (seg); + + } + } + } + } + } + } + mesh.CalcSurfacesOfNode(); + multithread.task = savetask; +} + + + + +static void OCCMeshSurface (OCCGeometry & geom, Mesh & mesh, int perfstepsend) +{ + int i, j, k; + int changed; + + char * savetask = multithread.task; + multithread.task = "Surface meshing"; + + geom.facemeshstatus = 0; + + int noldp = mesh.GetNP(); + + double starttime = GetTime(); + + ARRAY<int> glob2loc(noldp); + + int projecttype = PARAMETERSPACE; + + //int projecttype = PLANESPACE; + + int notrys = 1; + + int surfmesherror = 0; + + for (k = 1; k <= mesh.GetNFD(); k++) + { + (*testout) << "mesh face " << k << endl; + multithread.percent = 100 * k / (mesh.GetNFD()+1e-10); + geom.facemeshstatus[k-1] = -1; + + + /* + if (k != 138) + { + cout << "skipped" << endl; + continue; + } + */ + + FaceDescriptor & fd = mesh.GetFaceDescriptor(k); + + int oldnf = mesh.GetNSE(); + + Box<3> bb = geom.GetBoundingBox(); + + Meshing2OCCSurfaces meshing(TopoDS::Face(geom.fmap(k)), bb, projecttype); + + if (meshing.GetProjectionType() == PLANESPACE) + PrintMessage (2, "Face ", k, " / ", mesh.GetNFD(), " (plane space projection)"); + else + PrintMessage (2, "Face ", k, " / ", mesh.GetNFD(), " (parameter space projection)"); + + if (surfmesherror) + cout << "Surface meshing error occured before (in " << surfmesherror << " faces)" << endl; + + // Meshing2OCCSurfaces meshing(f2, bb); + meshing.SetStartTime (starttime); + + (*testout) << "Face " << k << endl << endl; + + + if (meshing.GetProjectionType() == PLANESPACE) + { + int cntp = 0; + glob2loc = 0; + for (i = 1; i <= mesh.GetNSeg(); i++) + { + Segment & seg = mesh.LineSegment(i); + if (seg.si == k) + { + for (j = 1; j <= 2; j++) + { + int pi = (j == 1) ? seg.p1 : seg.p2; + if (!glob2loc.Get(pi)) + { + meshing.AddPoint (mesh.Point(pi), pi); + cntp++; + glob2loc.Elem(pi) = cntp; + } + } + } + } + + for (i = 1; i <= mesh.GetNSeg(); i++) + { + Segment & seg = mesh.LineSegment(i); + if (seg.si == k) + { + PointGeomInfo gi0, gi1; + gi0.trignum = gi1.trignum = k; + gi0.u = seg.epgeominfo[0].u; + gi0.v = seg.epgeominfo[0].v; + gi1.u = seg.epgeominfo[1].u; + gi1.v = seg.epgeominfo[1].v; + + meshing.AddBoundaryElement (glob2loc.Get(seg.p1), glob2loc.Get(seg.p2), gi0, gi1); + (*testout) << gi0.u << " " << gi0.v << endl; + (*testout) << gi1.u << " " << gi1.v << endl; + } + } + } + else + { + int cntp = 0; + + for (i = 1; i <= mesh.GetNSeg(); i++) + if (mesh.LineSegment(i).si == k) + cntp+=2; + + + ARRAY< PointGeomInfo > gis; + + gis.SetAllocSize (cntp); + gis.SetSize (0); + + for (i = 1; i <= mesh.GetNSeg(); i++) + { + Segment & seg = mesh.LineSegment(i); + if (seg.si == k) + { + PointGeomInfo gi0, gi1; + gi0.trignum = gi1.trignum = k; + gi0.u = seg.epgeominfo[0].u; + gi0.v = seg.epgeominfo[0].v; + gi1.u = seg.epgeominfo[1].u; + gi1.v = seg.epgeominfo[1].v; + + int locpnum[2] = {0, 0}; + + for (j = 0; j < 2; j++) + { + PointGeomInfo gi = (j == 0) ? gi0 : gi1; + + int l; + for (l = 0; l < gis.Size() && locpnum[j] == 0; l++) + { + double dist = sqr (gis[l].u-gi.u)+sqr(gis[l].v-gi.v); + + if (dist < 1e-10) + locpnum[j] = l+1; + } + + if (locpnum[j] == 0) + { + int pi = (j == 0) ? seg.p1 : seg.p2; + meshing.AddPoint (mesh.Point(pi), pi); + + gis.SetSize (gis.Size()+1); + gis[l] = gi; + locpnum[j] = l+1; + } + } + + meshing.AddBoundaryElement (locpnum[0], locpnum[1], gi0, gi1); + (*testout) << gi0.u << " " << gi0.v << endl; + (*testout) << gi1.u << " " << gi1.v << endl; + + } + } + } + + + + + + + double maxh = mparam.maxh; + mparam.checkoverlap = 0; + // int noldpoints = mesh->GetNP(); + int noldsurfel = mesh.GetNSE(); + + MESHING2_RESULT res; + + try { + res = meshing.GenerateMesh (mesh, maxh, k); + } + + catch (SingularMatrixException) + { + (*myerr) << "Singular Matrix" << endl; + res = MESHING2_GIVEUP; + } + + catch (UVBoundsException) + { + (*myerr) << "UV bounds exceeded" << endl; + res = MESHING2_GIVEUP; + } + + projecttype = PARAMETERSPACE; + + if (res != MESHING2_OK) + { + if (notrys == 1) + { + for (int i = noldsurfel+1; i <= mesh.GetNSE(); i++) + mesh.DeleteSurfaceElement (i); + + mesh.Compress(); + + cout << "retry Surface " << k << endl; + + k--; + projecttype*=-1; + notrys++; + continue; + } + else + { + geom.facemeshstatus[k-1] = -1; + PrintError ("Problem in Surface mesh generation"); + surfmesherror++; + // throw NgException ("Problem in Surface mesh generation"); + } + } + else + { + geom.facemeshstatus[k-1] = 1; + } + + notrys = 1; + + for (i = oldnf+1; i <= mesh.GetNSE(); i++) + mesh.SurfaceElement(i).SetIndex (k); + + } + + if (surfmesherror) + { + cout << "WARNING! NOT ALL FACES HAVED BEEN MESHED" << endl; + cout << "SURFACE MESHING ERROR OCCURED IN " << surfmesherror << " FACES:" << endl; + for (int i = 1; i <= geom.fmap.Extent(); i++) + if (geom.facemeshstatus[i-1] == -1) + cout << "Face " << i << endl; + cout << endl; + cout << "for more information open IGES/STEP Topology Explorer" << endl; + throw NgException ("Problem in Surface mesh generation"); + } + + + if (multithread.terminate || perfstepsend < MESHCONST_OPTSURFACE) + return; + + multithread.task = "Optimizing surface"; + + for (k = 1; k <= mesh.GetNFD(); k++) + { + (*testout) << "optimize face " << k << endl; + multithread.percent = 100 * k / (mesh.GetNFD()+1e-10); + + FaceDescriptor & fd = mesh.GetFaceDescriptor(k); + + PrintMessage (1, "Optimize Surface ", k); + for (i = 1; i <= mparam.optsteps2d; i++) + { + if (multithread.terminate) return; + + { + MeshOptimize2dOCCSurfaces meshopt(geom); + meshopt.SetFaceIndex (k); + meshopt.SetImproveEdges (0); + meshopt.SetMetricWeight (0.2); + meshopt.SetWriteStatus (0); + + meshopt.EdgeSwapping (mesh, (i > mparam.optsteps2d/2)); + } + + if (multithread.terminate) return; + { + MeshOptimize2dOCCSurfaces meshopt(geom); + meshopt.SetFaceIndex (k); + meshopt.SetImproveEdges (0); + meshopt.SetMetricWeight (0.2); + meshopt.SetWriteStatus (0); + + meshopt.ImproveMesh (mesh); + } + + { + MeshOptimize2dOCCSurfaces meshopt(geom); + meshopt.SetFaceIndex (k); + meshopt.SetImproveEdges (0); + meshopt.SetMetricWeight (0.2); + meshopt.SetWriteStatus (0); + + meshopt.CombineImprove (mesh); + } + + if (multithread.terminate) return; + { + MeshOptimize2dOCCSurfaces meshopt(geom); + meshopt.SetFaceIndex (k); + meshopt.SetImproveEdges (0); + meshopt.SetMetricWeight (0.2); + meshopt.SetWriteStatus (0); + + meshopt.ImproveMesh (mesh); + } + } + + } + + + mesh.CalcSurfacesOfNode(); + mesh.Compress(); + + multithread.task = savetask; +} + +double ComputeH (double kappa) +{ + double hret; + kappa *= mparam.curvaturesafety; + + if (mparam.maxh * kappa < 1) + hret = mparam.maxh; + else + hret = 1 / kappa; + + if (mparam.maxh < hret) + hret = mparam.maxh; + + return (hret); +} + + +class Line +{ +public: + Point<3> p0, p1; + double 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; + + 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 Length () + { + return (p1-p0).Length(); + }; +}; + + + +void RestrictHTriangle (gp_Pnt2d & par0, gp_Pnt2d & par1, gp_Pnt2d & par2, + BRepLProp_SLProps * prop, Mesh & mesh, double maxside, int depth, double h = 0) +{ + gp_Pnt2d parmid; + + parmid.SetX(0.3*(par0.X()+par1.X()+par2.X())); + parmid.SetY(0.3*(par0.Y()+par1.Y()+par2.Y())); + + if (depth == 0) + { + prop->SetParameters (parmid.X(), parmid.Y()); + if (!prop->IsCurvatureDefined()) + { + (*testout) << "curvature not defined!" << endl; + return; + } + double curvature = max(fabs(prop->MinCurvature()), fabs(prop->MaxCurvature())); + if (curvature < 1e-3) + { + (*testout) << "curvature too small (" << curvature << ")!" << endl; + // return; + } + h = ComputeH (curvature+1e-10); + } + + if (h < maxside) + { + gp_Pnt2d pm0; + gp_Pnt2d pm1; + gp_Pnt2d pm2; + + pm0.SetX(0.5*(par1.X()+par2.X())); pm0.SetY(0.5*(par1.Y()+par2.Y())); + pm1.SetX(0.5*(par0.X()+par2.X())); pm1.SetY(0.5*(par0.Y()+par2.Y())); + pm2.SetX(0.5*(par1.X()+par0.X())); pm2.SetY(0.5*(par1.Y()+par0.Y())); + + RestrictHTriangle (pm0, pm1, pm2, prop, mesh, maxside/2, depth+1, h); + RestrictHTriangle (par0, pm1, pm2, prop, mesh, maxside/2, depth+1, h); + RestrictHTriangle (par1, pm0, pm2, prop, mesh, maxside/2, depth+1, h); + RestrictHTriangle (par2, pm1, pm0, prop, mesh, maxside/2, depth+1, h); + } + else + { + prop->SetParameters (parmid.X(), parmid.Y()); + gp_Pnt pnt = prop->Value(); + Point3d p3d(pnt.X(), pnt.Y(), pnt.Z()); + mesh.RestrictLocalH (p3d, h); + + prop->SetParameters (par0.X(), par0.Y()); + pnt = prop->Value(); + p3d = Point3d(pnt.X(), pnt.Y(), pnt.Z()); + mesh.RestrictLocalH (p3d, h); + + prop->SetParameters (par1.X(), par1.Y()); + pnt = prop->Value(); + p3d = Point3d(pnt.X(), pnt.Y(), pnt.Z()); + mesh.RestrictLocalH (p3d, h); + + prop->SetParameters (par2.X(), par2.Y()); + pnt = prop->Value(); + p3d = Point3d(pnt.X(), pnt.Y(), pnt.Z()); + mesh.RestrictLocalH (p3d, h); + + // (*testout) << "p = " << p3d << ", h = " << h << ", maxside = " << maxside << endl; + /* + (*testout) << pnt.X() << " " << pnt.Y() << " " << pnt.Z() << endl; + + prop->SetParameters (par0.X(), par0.Y()); + pnt = prop->Value(); + (*testout) << pnt.X() << " " << pnt.Y() << " " << pnt.Z() << endl; + + prop->SetParameters (par1.X(), par1.Y()); + pnt = prop->Value(); + (*testout) << pnt.X() << " " << pnt.Y() << " " << pnt.Z() << endl; + + prop->SetParameters (par2.X(), par2.Y()); + pnt = prop->Value(); + (*testout) << pnt.X() << " " << pnt.Y() << " " << pnt.Z() << endl; + */ + } +} + + + + +int OCCGenerateMesh (OCCGeometry & geom, + Mesh *& mesh, + int perfstepsstart, int perfstepsend, + char * optstr) +{ + int i, j; + + multithread.percent = 0; + + if (perfstepsstart <= MESHCONST_ANALYSE) + { + delete mesh; + mesh = new Mesh(); + + mesh->SetGlobalH (mparam.maxh); + + ARRAY<double> maxhdom; + maxhdom.SetSize (geom.NrSolids()); + maxhdom = mparam.maxh; + + mesh->SetMaxHDomain (maxhdom); + + Box<3> bb = geom.GetBoundingBox(); + bb.Increase (bb.Diam()/10); + + mesh->SetLocalH (bb.PMin(), bb.PMax(), 0.5); + + + if (mparam.uselocalh) + { + + char * savetask = multithread.task; + multithread.percent = 0; + + mesh->SetLocalH (bb.PMin(), bb.PMax(), mparam.grading); + + int nedges = geom.emap.Extent(); + int i; + + double maxedgelen = 0; + double minedgelen = 1e99; + + + multithread.task = "Setting local mesh size (elements per edge)"; + + // setting elements per edge + + for (i = 1; i <= nedges && !multithread.terminate; i++) + { + TopoDS_Edge e = TopoDS::Edge (geom.emap(i)); + multithread.percent = 100 * (i-1)/double(nedges); + if (BRep_Tool::Degenerated(e)) continue; + + GProp_GProps system; + BRepGProp::LinearProperties(e, system); + double len = system.Mass(); + + if (len < IGNORECURVELENGTH) + { + (*testout) << "ignored" << endl; + continue; + } + + + double localh = len/mparam.segmentsperedge; + double s0, s1; + Handle(Geom_Curve) c = BRep_Tool::Curve(e, s0, s1); + + maxedgelen = max (maxedgelen, len); + minedgelen = min (minedgelen, len); + + int j; + int maxj = (int) ceil (localh); + for (j = 0; j <= localh; j++) + { + gp_Pnt pnt = c->Value (s0+double(j)/maxj*(s1-s0)); + mesh->RestrictLocalH (Point3d(pnt.X(), pnt.Y(), pnt.Z()), localh); + } + } + + + + + multithread.task = "Setting local mesh size (edge curvature)"; + + + // setting edge curvature + + // int nsections = 10; + int nsections = 20; + + for (i = 1; i <= nedges && !multithread.terminate; i++) + { + 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); + + int j; + for (j = 1; j <= nsections; j++) + // for (j = 0; j < nsections; j++) + { + double s = s0 + j/(double) nsections * (s1-s0); + prop.SetParameter (s); + double curvature = prop.Curvature(); + + if (curvature >= 1e99) continue; + + gp_Pnt pnt = c->Value (s); + + mesh->RestrictLocalH (Point3d(pnt.X(), pnt.Y(), pnt.Z()), + ComputeH (fabs(curvature))); + } + } + + + + multithread.task = "Setting local mesh size (face curvature)"; + + // setting face curvature + + int nfaces = geom.fmap.Extent(); + + for (i = 1; i <= nfaces && !multithread.terminate; i++) + { + multithread.percent = 100 * (i-1)/double(nfaces); + TopoDS_Face face = TopoDS::Face(geom.fmap(i)); + TopLoc_Location loc; + Handle(Geom_Surface) surf = BRep_Tool::Surface (face); + Handle(Poly_Triangulation) triangulation = BRep_Tool::Triangulation (face, loc); + if (triangulation.IsNull()) continue; + + BRepAdaptor_Surface sf(face, Standard_True); + BRepLProp_SLProps prop(sf, 2, 1e-5); + + int ntriangles = triangulation -> NbTriangles(); + for (j = 1; j <= ntriangles; j++) + { + int k; + gp_Pnt p[3]; + gp_Pnt2d par[3]; + + for (k = 1; k <=3; k++) + { + int n = triangulation->Triangles()(j)(k); + p[k-1] = triangulation->Nodes()(n).Transformed(loc); + par[k-1] = triangulation->UVNodes()(n); + } + + double maxside = 0; + maxside = max (maxside, p[0].Distance(p[1])); + maxside = max (maxside, p[0].Distance(p[2])); + maxside = max (maxside, p[1].Distance(p[2])); + + RestrictHTriangle (par[0], par[1], par[2], &prop, *mesh, maxside, 0); + } + } + + + + // setting close edges + + if (stlparam.resthcloseedgeenable) + { + multithread.task = "Setting local mesh size (close edges)"; + + int sections = 100; + + ARRAY<Line> lines(sections*nedges); + + Box3dTree* searchtree = + new Box3dTree (bb.PMin(), bb.PMax()); + + int nlines = 0; + for (int i = 1; i <= nedges && !multithread.terminate; i++) + { + TopoDS_Edge edge = TopoDS::Edge (geom.emap(i)); + if (BRep_Tool::Degenerated(edge)) continue; + + double s0, s1; + Handle(Geom_Curve) c = BRep_Tool::Curve(edge, s0, s1); + BRepAdaptor_Curve brepc(edge); + BRepLProp_CLProps prop(brepc, 1, 1e-5); + prop.SetParameter (s0); + + gp_Vec d0 = prop.D1().Normalized(); + double s_start = s0; + int count = 0; + for (int j = 1; j <= sections; j++) + { + double s = s0 + (s1-s0)*(double)j/(double)sections; + prop.SetParameter (s); + gp_Vec d1 = prop.D1().Normalized(); + double cosalpha = fabs(d0*d1); + if ((j == sections) || (cosalpha < cos(10.0/180.0*M_PI))) + { + count++; + gp_Pnt p0 = c->Value (s_start); + gp_Pnt p1 = c->Value (s); + lines[nlines].p0 = Point<3> (p0.X(), p0.Y(), p0.Z()); + lines[nlines].p1 = Point<3> (p1.X(), p1.Y(), p1.Z()); + + Box3d box; + box.SetPoint (Point3d(lines[nlines].p0)); + box.AddPoint (Point3d(lines[nlines].p1)); + + searchtree->Insert (box.PMin(), box.PMax(), nlines+1); + nlines++; + + s_start = s; + d0 = d1; + } + } + } + + ARRAY<int> linenums; + + for (int i = 0; i < nlines; i++) + { + multithread.percent = (100*i)/double(nlines); + Line & line = lines[i]; + + Box3d box; + box.SetPoint (Point3d(line.p0)); + box.AddPoint (Point3d(line.p1)); + double maxhline = max (mesh->GetH(box.PMin()), + mesh->GetH(box.PMax())); + box.Increase(maxhline); + + double mindist = 1e99; + linenums.SetSize(0); + searchtree->GetIntersecting(box.PMin(),box.PMax(),linenums); + + for (int j = 0; j < linenums.Size(); j++) + { + int num = linenums[j]-1; + if (i == num) continue; + if ((line.p0-lines[num].p0).Length2() < 1e-15) continue; + if ((line.p0-lines[num].p1).Length2() < 1e-15) continue; + if ((line.p1-lines[num].p0).Length2() < 1e-15) continue; + if ((line.p1-lines[num].p1).Length2() < 1e-15) continue; + mindist = min (mindist, line.Dist(lines[num])); + } + + mindist *= stlparam.resthcloseedgefac; + + if (mindist < 1e-3) + { + (*testout) << "extremely small local h: " << mindist + << " --> setting to 1e-3" << endl; + mindist = 1e-3; + } + + mesh->RestrictLocalHLine(line.p0, line.p1, mindist); + } + } + + + + multithread.task = savetask; + + } + } + + + if (multithread.terminate || perfstepsend <= MESHCONST_ANALYSE) + return TCL_OK; + + if (perfstepsstart <= MESHCONST_MESHEDGES) + { + FindEdges (geom, *mesh); + + /* + cout << "Removing redundant points" << endl; + + int i, j; + int np = mesh->GetNP(); + ARRAY<int> equalto; + + equalto.SetSize (np); + equalto = 0; + + for (i = 1; i <= np; i++) + { + for (j = i+1; j <= np; j++) + { + if (!equalto[j-1] && (Dist2 (mesh->Point(i), mesh->Point(j)) < 1e-12)) + equalto[j-1] = i; + } + } + + for (i = 1; i <= np; i++) + if (equalto[i-1]) + { + cout << "Point " << i << " is equal to Point " << equalto[i-1] << endl; + for (j = 1; j <= mesh->GetNSeg(); j++) + { + Segment & seg = mesh->LineSegment(j); + if (seg.p1 == i) seg.p1 = equalto[i-1]; + if (seg.p2 == i) seg.p2 = equalto[i-1]; + } + } + + cout << "Removing degenerated segments" << endl; + for (j = 1; j <= mesh->GetNSeg(); j++) + { + Segment & seg = mesh->LineSegment(j); + if (seg.p1 == seg.p2) + { + mesh->DeleteSegment(j); + cout << "Deleting Segment " << j << endl; + } + } + + mesh->Compress(); + */ + + /* + for (int i = 1; i <= geom.fmap.Extent(); i++) + { + Handle(Geom_Surface) hf1 = + BRep_Tool::Surface(TopoDS::Face(geom.fmap(i))); + for (int j = i+1; j <= geom.fmap.Extent(); j++) + { + Handle(Geom_Surface) hf2 = + BRep_Tool::Surface(TopoDS::Face(geom.fmap(j))); + if (hf1 == hf2) cout << "face " << i << " and face " << j << " lie on same surface" << endl; + } + } + */ + + + +#ifdef LOG_STREAM + (*logout) << "Edges meshed" << endl + << "time = " << GetTime() << " sec" << endl + << "points: " << mesh->GetNP() << endl; +#endif + } + + if (multithread.terminate || perfstepsend <= MESHCONST_MESHEDGES) + return TCL_OK; + + if (perfstepsstart <= MESHCONST_MESHSURFACE) + { + OCCMeshSurface (geom, *mesh, perfstepsend); + if (multithread.terminate) return TCL_OK; + +#ifdef LOG_STREAM + (*logout) << "Surfaces meshed" << endl + << "time = " << GetTime() << " sec" << endl + << "points: " << mesh->GetNP() << endl; +#endif + +#ifdef STAT_STREAM + (*statout) << mesh->GetNSeg() << " & " + << mesh->GetNSE() << " & - &" + << GetTime() << " & " << endl; +#endif + + // MeshQuality2d (*mesh); + mesh->CalcSurfacesOfNode(); + } + + if (multithread.terminate || perfstepsend <= MESHCONST_OPTSURFACE) + return TCL_OK; + + + if (perfstepsstart <= MESHCONST_MESHVOLUME) + { + multithread.task = "Volume meshing"; + + MESHING3_RESULT res = + MeshVolume (mparam, *mesh); + + if (res != MESHING3_OK) return TCL_ERROR; + + if (multithread.terminate) return TCL_OK; + + RemoveIllegalElements (*mesh); + if (multithread.terminate) return TCL_OK; + + MeshQuality3d (*mesh); + +#ifdef STAT_STREAM + (*statout) << GetTime() << " & "; +#endif + +#ifdef LOG_STREAM + (*logout) << "Volume meshed" << endl + << "time = " << GetTime() << " sec" << endl + << "points: " << mesh->GetNP() << endl; +#endif + } + + if (multithread.terminate || perfstepsend <= MESHCONST_MESHVOLUME) + return TCL_OK; + + + if (perfstepsstart <= MESHCONST_OPTVOLUME) + { + multithread.task = "Volume optimization"; + + OptimizeVolume (mparam, *mesh); + if (multithread.terminate) return TCL_OK; + +#ifdef STAT_STREAM + (*statout) << GetTime() << " & " + << mesh->GetNE() << " & " + << mesh->GetNP() << " " << '\\' << '\\' << " \\" << "hline" << endl; +#endif + +#ifdef LOG_STREAM + (*logout) << "Volume optimized" << endl + << "time = " << GetTime() << " sec" << endl + << "points: " << mesh->GetNP() << endl; +#endif + + + cout << "Optimization complete" << endl; + + } + + (*testout) << "NP: " << mesh->GetNP() << endl; + for (i = 1; i <= mesh->GetNP(); i++) + (*testout) << mesh->Point(i) << endl; + + (*testout) << endl << "NSegments: " << mesh->GetNSeg() << endl; + for (i = 1; i <= mesh->GetNSeg(); i++) + (*testout) << mesh->LineSegment(i) << endl; + + + + return TCL_OK; +} +} + +#endif diff --git a/contrib/Netgen/libsrc/occ/occgeom.cpp b/contrib/Netgen/libsrc/occ/occgeom.cpp new file mode 100644 index 0000000000..e24f52fa0a --- /dev/null +++ b/contrib/Netgen/libsrc/occ/occgeom.cpp @@ -0,0 +1,1102 @@ +#ifdef OCCGEOMETRY + +#include <mystdlib.h> +#include <occgeom.hpp> +#include "ShapeAnalysis_ShapeTolerance.hxx" +#include "ShapeAnalysis_ShapeContents.hxx" +#include "ShapeAnalysis_CheckSmallFace.hxx" +#include "ShapeAnalysis_DataMapOfShapeListOfReal.hxx" +#include "BRepAlgoAPI_Fuse.hxx" +#include "BRepCheck_Analyzer.hxx" +#include "BRepLib.hxx" +#include "ShapeBuild_ReShape.hxx" +#include "ShapeFix.hxx" +#include "ShapeFix_FixSmallFace.hxx" + + +namespace netgen +{ + +void OCCGeometry :: PrintNrShapes () +{ + TopExp_Explorer e; + int count = 0; + for (e.Init(shape, TopAbs_COMPSOLID); e.More(); e.Next()) count++; + cout << "CompSolids: " << count << endl; + + cout << "Solids : " << somap.Extent() << endl; + cout << "Shells : " << shmap.Extent() << endl; + cout << "Faces : " << fmap.Extent() << endl; + cout << "Edges : " << emap.Extent() << endl; + cout << "Vertices : " << vmap.Extent() << endl; +} + + +void PrintContents (OCCGeometry * geom) +{ + ShapeAnalysis_ShapeContents cont; + cont.Clear(); + cont.Perform(geom->shape); + + (*testout) << "OCC CONTENTS" << endl; + (*testout) << "============" << endl; + (*testout) << "SOLIDS : " << cont.NbSolids() << endl; + (*testout) << "SHELLS : " << cont.NbShells() << endl; + (*testout) << "FACES : " << cont.NbFaces() << endl; + (*testout) << "WIRES : " << cont.NbWires() << endl; + (*testout) << "EDGES : " << cont.NbEdges() << endl; + (*testout) << "VERTICES : " << cont.NbVertices() << endl; + + TopExp_Explorer e; + int count = 0; + for (e.Init(geom->shape, TopAbs_COMPOUND); e.More(); e.Next()) + count++; + (*testout) << "Compounds: " << count << endl; + + count = 0; + for (e.Init(geom->shape, TopAbs_COMPSOLID); e.More(); e.Next()) + count++; + (*testout) << "CompSolids: " << count << endl; + + (*testout) << endl; + + cout << "Highest entry in topology hierarchy: " << endl; + if (count) + cout << count << " composite solid(s)" << endl; + else + if (geom->somap.Extent()) + cout << geom->somap.Extent() << " solid(s)" << endl; + else + if (geom->shmap.Extent()) + cout << geom->shmap.Extent() << " shells(s)" << endl; + else + if (geom->fmap.Extent()) + cout << geom->fmap.Extent() << " face(s)" << endl; + else + if (geom->wmap.Extent()) + cout << geom->wmap.Extent() << " wire(s)" << endl; + else + if (geom->emap.Extent()) + cout << geom->emap.Extent() << " edge(s)" << endl; + else + if (geom->vmap.Extent()) + cout << geom->vmap.Extent() << " vertices(s)" << endl; + else + cout << "no entities" << endl; + +} + + + +void OCCGeometry :: HealGeometry () +{ + int nrc = 0, nrcs = 0, + nrso = somap.Extent(), + nrsh = shmap.Extent(), + nrf = fmap.Extent(), + nrw = wmap.Extent(), + nre = emap.Extent(), + nrv = vmap.Extent(); + + TopExp_Explorer e; + for (e.Init(shape, TopAbs_COMPOUND); e.More(); e.Next()) nrc++; + for (e.Init(shape, TopAbs_COMPSOLID); e.More(); e.Next()) nrcs++; + + double surfacecont = 0; + + for (int i = 1; i <= fmap.Extent(); i++) + { + GProp_GProps system; + BRepGProp::LinearProperties(fmap(i), system); + surfacecont += system.Mass(); + } + + cout << "Starting geometry healing procedure (tolerance: " << tolerance << ")" << endl + << "-----------------------------------" << endl; + + if (fixsmalledges) + { + cout << endl << "- fixing small edges" << endl; + + Handle(ShapeFix_Wire) sfw; + Handle_ShapeBuild_ReShape rebuild = new ShapeBuild_ReShape; + rebuild->Apply(shape); + + for (int i = 1; i <= fmap.Extent(); i++) + { + TopExp_Explorer exp1; + for (exp1.Init (fmap(i), TopAbs_WIRE); exp1.More(); exp1.Next()) + { + TopoDS_Wire oldwire = TopoDS::Wire(exp1.Current()); + sfw = new ShapeFix_Wire (oldwire, TopoDS::Face(fmap(i)),tolerance); + sfw->ModifyTopologyMode() = Standard_True; + + if (sfw->FixSmall (false, tolerance)) + { + cout << "Fixed small edge in wire " << wmap.FindIndex (oldwire) << endl; + TopoDS_Wire newwire = sfw->Wire(); + rebuild->Replace(oldwire, newwire, Standard_False); + } + if ((sfw->StatusSmall(ShapeExtend_FAIL1)) || + (sfw->StatusSmall(ShapeExtend_FAIL2)) || + (sfw->StatusSmall(ShapeExtend_FAIL3))) + cout << "Failed to fix small edge in wire " << wmap.FindIndex (oldwire) << endl; + + + } + } + + shape = rebuild->Apply(shape); + + + + { + Handle_ShapeBuild_ReShape rebuild = new ShapeBuild_ReShape; + rebuild->Apply(shape); + TopExp_Explorer exp1; + 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) << endl; + rebuild->Remove(edge, false); + } + } + } + shape = rebuild->Apply(shape); + } + + + Handle(ShapeFix_Wireframe) sfwf = new ShapeFix_Wireframe; + sfwf->SetPrecision(tolerance); + sfwf->Load (shape); + + 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; + } + + + 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; + } + + + shape = sfwf->Shape(); + } + + + + + + if (fixspotstripfaces) + { + + cout << endl << "- fixing spot and strip faces" << endl; + Handle(ShapeFix_FixSmallFace) sffsm = new ShapeFix_FixSmallFace(); + sffsm -> Init (shape); + sffsm -> SetPrecision (tolerance); + sffsm -> Perform(); + + shape = sffsm -> FixShape(); + } + + if (sewfaces) + { + cout << endl << "- sewing faces" << endl; + + TopExp_Explorer exp0; + + BRepOffsetAPI_Sewing sewedObj(tolerance); + + for (exp0.Init (shape, TopAbs_FACE); exp0.More(); exp0.Next()) + { + TopoDS_Face face = TopoDS::Face (exp0.Current()); + sewedObj.Add (face); + } + + sewedObj.Perform(); + + if (!sewedObj.SewedShape().IsNull()) + shape = sewedObj.SewedShape(); + else + cout << " not possible"; + } + + if (makesolids) + { + cout << endl << "- making solids" << endl; + + TopExp_Explorer exp0; + + BRepBuilderAPI_MakeSolid ms; + int count = 0; + for (exp0.Init(shape, TopAbs_SHELL); exp0.More(); exp0.Next()) + { + count++; + ms.Add (TopoDS::Shell(exp0.Current())); + } + + if (!count) + { + cout << " not possible (no shells)" << endl; + } + else + { + BRepCheck_Analyzer ba(ms); + if (ba.IsValid ()) + { + Handle(ShapeFix_Shape) sfs = new ShapeFix_Shape; + sfs->Init (ms); + sfs->SetPrecision(tolerance); + sfs->SetMaxTolerance(tolerance); + sfs->Perform(); + shape = sfs->Shape(); + + for (exp0.Init(shape, TopAbs_SOLID); exp0.More(); exp0.Next()) + { + TopoDS_Solid solid = TopoDS::Solid(exp0.Current()); + TopoDS_Solid newsolid = solid; + BRepLib::OrientClosedSolid (newsolid); + Handle_ShapeBuild_ReShape rebuild = new ShapeBuild_ReShape; + // rebuild->Apply(shape); + rebuild->Replace(solid, newsolid, Standard_False); + TopoDS_Shape newshape = rebuild->Apply(shape, TopAbs_COMPSOLID, 1); + // TopoDS_Shape newshape = rebuild->Apply(shape); + shape = newshape; + } + } + else + cout << " not possible" << endl; + } + } + + BuildFMap(); + + double newsurfacecont = 0; + + for (int i = 1; i <= fmap.Extent(); i++) + { + GProp_GProps system; + BRepGProp::LinearProperties(fmap(i), 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 (e.Init(shape, TopAbs_COMPOUND); e.More(); e.Next()) nnrc++; + for (e.Init(shape, TopAbs_COMPSOLID); e.More(); e.Next()) nnrcs++; + + cout << "-----------------------------------" << endl; + cout << "Compounds : " << nnrc << " (" << nrc << ")" << endl; + cout << "Composite solids: " << nnrcs << " (" << nrcs << ")" << endl; + cout << "Solids : " << nnrso << " (" << nrso << ")" << endl; + cout << "Shells : " << nnrsh << " (" << nrsh << ")" << endl; + cout << "Wires : " << nnrw << " (" << nrw << ")" << endl; + cout << "Faces : " << nnrf << " (" << nrf << ")" << endl; + cout << "Edges : " << nnre << " (" << nre << ")" << endl; + cout << "Vertices : " << nnrv << " (" << nrv << ")" << endl; + cout << endl; + cout << "Totol surface area : " << newsurfacecont << " (" << surfacecont << ")" << endl; + cout << endl; + +} + + + + +void OCCGeometry :: BuildFMap() +{ + somap.Clear(); + shmap.Clear(); + fmap.Clear(); + wmap.Clear(); + emap.Clear(); + vmap.Clear(); + + TopExp_Explorer exp0, exp1, exp2, exp3, exp4, exp5; + + for (exp0.Init(shape, TopAbs_SOLID); + exp0.More(); exp0.Next()) + { + TopoDS_Solid solid = TopoDS::Solid (exp0.Current()); + + if (somap.FindIndex(TopoDS::Solid (exp0.Current())) < 1) + { + somap.Add (TopoDS::Solid (exp0.Current())); + + for (exp1.Init(exp0.Current(), TopAbs_SHELL); + exp1.More(); exp1.Next()) + { + TopoDS_Shell shell = TopoDS::Shell (exp1.Current().Composed (exp0.Current().Orientation())); + 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().Composed(shell.Orientation())); + if (fmap.FindIndex(face) < 1) + { + fmap.Add (face); + + for (exp3.Init(exp2.Current(), TopAbs_WIRE); + exp3.More(); exp3.Next()) + { + TopoDS_Wire wire = TopoDS::Wire (exp3.Current().Composed(face.Orientation())); + 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().Composed(wire.Orientation())); + 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(exp0.Current(), TopAbs_SHELL, TopAbs_SOLID); + exp1.More(); exp1.Next()) + { + TopoDS_Shape shell = exp1.Current().Composed (exp0.Current().Orientation()); + 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().Composed(shell.Orientation())); + if (fmap.FindIndex(face) < 1) + { + fmap.Add (face); + + for (exp3.Init(exp2.Current(), TopAbs_WIRE); + exp3.More(); exp3.Next()) + { + TopoDS_Wire wire = TopoDS::Wire (exp3.Current()); + if (wmap.FindIndex(wire) < 1) + { + wmap.Add (wire); + + for (exp4.Init(exp3.Current(), TopAbs_EDGE); + exp4.More(); exp4.Next()) + { + TopoDS_Edge edge = TopoDS::Edge(exp4.Current()); + if (emap.FindIndex(edge) < 1) + { + emap.Add (edge); + for (exp5.Init(exp4.Current(), TopAbs_VERTEX); + exp5.More(); exp5.Next()) + { + TopoDS_Vertex vertex = TopoDS::Vertex(exp5.Current()); + if (vmap.FindIndex(vertex) < 1) + vmap.Add (vertex); + } + } + } + } + } + } + } + } + } + + + // Free Faces + + for (exp2.Init(shape, TopAbs_FACE, TopAbs_SHELL); + exp2.More(); exp2.Next()) + { + TopoDS_Face face = TopoDS::Face(exp2.Current()); + if (fmap.FindIndex(face) < 1) + { + fmap.Add (face); + + for (exp3.Init(exp2.Current(), TopAbs_WIRE); + exp3.More(); exp3.Next()) + { + TopoDS_Wire wire = TopoDS::Wire (exp3.Current()); + if (wmap.FindIndex(wire) < 1) + { + wmap.Add (wire); + + for (exp4.Init(exp3.Current(), TopAbs_EDGE); + exp4.More(); exp4.Next()) + { + TopoDS_Edge edge = TopoDS::Edge(exp4.Current()); + if (emap.FindIndex(edge) < 1) + { + emap.Add (edge); + for (exp5.Init(exp4.Current(), TopAbs_VERTEX); + exp5.More(); exp5.Next()) + { + TopoDS_Vertex vertex = TopoDS::Vertex(exp5.Current()); + if (vmap.FindIndex(vertex) < 1) + vmap.Add (vertex); + } + } + } + } + } + } + } + + + // Free Wires + + for (exp3.Init(shape, TopAbs_WIRE, TopAbs_FACE); + exp3.More(); exp3.Next()) + { + TopoDS_Wire wire = TopoDS::Wire (exp3.Current()); + if (wmap.FindIndex(wire) < 1) + { + wmap.Add (wire); + + for (exp4.Init(exp3.Current(), TopAbs_EDGE); + exp4.More(); exp4.Next()) + { + TopoDS_Edge edge = TopoDS::Edge(exp4.Current()); + if (emap.FindIndex(edge) < 1) + { + emap.Add (edge); + for (exp5.Init(exp4.Current(), TopAbs_VERTEX); + exp5.More(); exp5.Next()) + { + TopoDS_Vertex vertex = TopoDS::Vertex(exp5.Current()); + if (vmap.FindIndex(vertex) < 1) + vmap.Add (vertex); + } + } + } + } + } + + + // Free Edges + + for (exp4.Init(shape, TopAbs_EDGE, TopAbs_WIRE); + exp4.More(); exp4.Next()) + { + TopoDS_Edge edge = TopoDS::Edge(exp4.Current()); + if (emap.FindIndex(edge) < 1) + { + emap.Add (edge); + for (exp5.Init(exp4.Current(), TopAbs_VERTEX); + exp5.More(); exp5.Next()) + { + TopoDS_Vertex vertex = TopoDS::Vertex(exp5.Current()); + if (vmap.FindIndex(vertex) < 1) + vmap.Add (vertex); + } + } + } + + + // Free Vertices + + for (exp5.Init(shape, TopAbs_VERTEX, TopAbs_EDGE); + exp5.More(); exp5.Next()) + { + TopoDS_Vertex vertex = TopoDS::Vertex(exp5.Current()); + if (vmap.FindIndex(vertex) < 1) + vmap.Add (vertex); + } + + + + + facemeshstatus.SetSize (fmap.Extent()); + facemeshstatus = 0; + + fvispar.SetSize (fmap.Extent()); + evispar.SetSize (emap.Extent()); + vvispar.SetSize (vmap.Extent()); +} + + + +void OCCGeometry :: SewFaces () +{ + (*testout) << "Trying to sew faces ..." << endl; + cout << "Trying to sew faces ..." << flush; + + BRepOffsetAPI_Sewing sewedObj(1); + // BRepOffsetAPI_Sewing sewedObj(healingtolerance); + + 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"; + + /* + ShapeUpgrade_ShellSewing sewing; + TopoDS_Shape sh = sewing.ApplySewing (shape); + shape = sh; + */ +} + + + + + +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->Apply(shape); + rebuild->Replace(solid, newsolid, Standard_False); + // TopoDS_Shape newshape = rebuild->Apply(shape); + + TopoDS_Shape newshape = rebuild->Apply(shape, TopAbs_SHAPE, 1); + shape = newshape; + } + + cout << " done" << endl; + } + else + cout << " not possible" << endl; +} + + +void OCCGeometry :: BuildVisualizationMesh () +{ + cout << "Preparing visualization (deflection = " << vispar.occdeflection << ") ... " << flush; + BRepTools::Clean (shape); + BRepMesh_IncrementalMesh::BRepMesh_IncrementalMesh (shape, vispar.occdeflection, true); + cout << "done" << endl; + + Bnd_Box bb; + BRepBndLib::Add (shape, bb); + + double x1,y1,z1,x2,y2,z2; + bb.Get (x1,y1,z1,x2,y2,z2); + Point<3> p1 = Point<3> (x1,y1,z1); + Point<3> p2 = Point<3> (x2,y2,z2); + + (*testout) << "Bounding Box = [" << p1 << " - " << p2 << "]" << endl; + boundingbox = Box<3> (p1,p2); + SetCenter(); +} + + + + bool OCCGeometry :: FastProject (int surfi, Point<3> & ap, double& u, double& v) const + { + gp_Pnt p(ap(0), ap(1), ap(2)); + + Handle(Geom_Surface) surface = BRep_Tool::Surface(TopoDS::Face(fmap(surfi))); + + gp_Pnt x = surface->Value (u,v); + + if (p.SquareDistance(x) <= sqr(PROJECTION_TOLERANCE)) return true; + + gp_Vec du, dv; + + surface->D1(u,v,x,du,dv); + + int count = 0; + + gp_Pnt xold; + gp_Vec n; + double det, lambda, mu; + + do { + count++; + + n = du^dv; + + det = Det3 (n.X(), du.X(), dv.X(), + n.Y(), du.Y(), dv.Y(), + n.Z(), du.Z(), dv.Z()); + + if (det < 1e-15) return false; + + lambda = Det3 (n.X(), p.X()-x.X(), dv.X(), + n.Y(), p.Y()-x.Y(), dv.Y(), + n.Z(), p.Z()-x.Z(), dv.Z())/det; + + mu = Det3 (n.X(), du.X(), p.X()-x.X(), + n.Y(), du.Y(), p.Y()-x.Y(), + n.Z(), du.Z(), p.Z()-x.Z())/det; + + u += lambda; + v += mu; + + xold = x; + surface->D1(u,v,x,du,dv); + + } while (xold.SquareDistance(x) > sqr(PROJECTION_TOLERANCE) && count < 50); + +// (*testout) << "FastProject count: " << count << endl; + + if (count == 50) return false; + + ap = Point<3> (x.X(), x.Y(), x.Z()); + + return true; + } + + +OCCGeometry * LoadOCC_IGES (const char * filename) +{ + OCCGeometry * occgeo; + occgeo = new OCCGeometry; + + IGESControl_Reader reader; + +#ifdef OCC52 + Standard_Integer stat = reader.ReadFile((char*)filename); +#else + Standard_Integer stat = reader.LoadFile((char*)filename); + reader.Clear(); +#endif + +#ifdef OCC52 + reader.TransferRoots(); // Tranlate IGES -> OCC +#else + reader.TransferRoots(Standard_False); // Tranlate IGES -> OCC +#endif + + occgeo->shape = reader.OneShape(); + occgeo->changed = 1; + occgeo->BuildFMap(); + occgeo->BuildVisualizationMesh(); + PrintContents (occgeo); + + return occgeo; +} + +OCCGeometry * LoadOCC_STEP (const char * filename) +{ + OCCGeometry * occgeo; + occgeo = new OCCGeometry; + + STEPControl_Reader reader; + Standard_Integer stat = reader.ReadFile((char*)filename); + Standard_Integer nb = reader.NbRootsForTransfer(); + reader.TransferRoots (); // Tranlate STEP -> OCC + occgeo->shape = reader.OneShape(); + occgeo->changed = 1; + occgeo->BuildFMap(); + occgeo->BuildVisualizationMesh(); + PrintContents (occgeo); + + return occgeo; +} + +char * shapesname[] = + {" ", "CompSolids", "Solids", "Shells", + "Faces", "Wires", "Edges", "Vertices"}; + +char * shapename[] = + {" ", "CompSolid", "Solid", "Shell", + "Face", "Wire", "Edge", "Vertex"}; + +char * orientationstring[] = + {"+", "-"}; + +void OCCGeometry :: RecursiveTopologyTree (const TopoDS_Shape & sh, + stringstream & str, + TopAbs_ShapeEnum l, + bool isfree, + const char * lname) +{ + if (l > TopAbs_VERTEX) return; + + TopExp_Explorer e; + int count = 0; + int count2; + + 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; + } + + int nrsubshapes = 0; + + if (l <= TopAbs_WIRE) + { + TopExp_Explorer e2; + for (e2.Init (e.Current(), TopAbs_ShapeEnum (l+1)); + e2.More(); e2.Next()) + nrsubshapes++; + } + + str << "{" << shapename[l] << " " << count2; + + if (l <= TopAbs_EDGE) + { + str << " (" << orientationstring[e.Current().Orientation()]; + if (nrsubshapes != 0) str << ", " << nrsubshapes; + str << ") } "; + } + else + str << " } "; + + RecursiveTopologyTree (e.Current(), str, TopAbs_ShapeEnum (l+1), + false, (char*)lname2.str().c_str()); + + } +} + +void OCCGeometry :: GetTopologyTree (stringstream & str) +{ + cout << "Building topology tree ... " << flush; + RecursiveTopologyTree (shape, str, TopAbs_COMPSOLID, false, "CompSolids"); + RecursiveTopologyTree (shape, str, TopAbs_SOLID, true, "FreeSolids"); + RecursiveTopologyTree (shape, str, TopAbs_SHELL, true, "FreeShells"); + RecursiveTopologyTree (shape, str, TopAbs_FACE, true, "FreeFaces"); + RecursiveTopologyTree (shape, str, TopAbs_WIRE, true, "FreeWires"); + RecursiveTopologyTree (shape, str, TopAbs_EDGE, true, "FreeEdges"); + RecursiveTopologyTree (shape, str, TopAbs_VERTEX, true, "FreeVertices"); + str << flush; + // cout << "done" << endl; +} + +void OCCGeometry :: CheckIrregularEntities(stringstream & str) +{ + ShapeAnalysis_CheckSmallFace csm; + + csm.SetTolerance (1e-6); + + TopTools_DataMapOfShapeListOfShape mapEdges; + ShapeAnalysis_DataMapOfShapeListOfReal mapParam; + TopoDS_Compound theAllVert; + + int spotfaces = 0; + int stripsupportfaces = 0; + int singlestripfaces = 0; + int stripfaces = 0; + int facessplitbyvertices = 0; + int stretchedpinfaces = 0; + int smoothpinfaces = 0; + int twistedfaces = 0; + int edgessamebutnotidentified = 0; + + cout << "checking faces ... " << flush; + + int i; + for (i = 1; i <= fmap.Extent(); i++) + { + TopoDS_Face face = TopoDS::Face (fmap(i)); + TopoDS_Edge e1, e2; + + if (csm.CheckSpotFace (face)) + { + if (!spotfaces++) + str << "SpotFace {Spot face} "; + + (*testout) << "Face " << i << " is a spot face" << endl; + str << "SpotFace/Face" << i << " "; + str << "{Face " << i << " } "; + } + + if (csm.IsStripSupport (face)) + { + if (!stripsupportfaces++) + str << "StripSupportFace {Strip support face} "; + + (*testout) << "Face " << i << " has strip support" << endl; + str << "StripSupportFace/Face" << i << " "; + str << "{Face " << i << " } "; + } + + if (csm.CheckSingleStrip(face, e1, e2)) + { + if (!singlestripfaces++) + str << "SingleStripFace {Single strip face} "; + + (*testout) << "Face " << i << " is a single strip (edge " << emap.FindIndex(e1) + << " and edge " << emap.FindIndex(e2) << " are identical)" << endl; + str << "SingleStripFace/Face" << i << " "; + str << "{Face " << i << " (edge " << emap.FindIndex(e1) + << " and edge " << emap.FindIndex(e2) << " are identical)} "; + } + + if (csm.CheckStripFace(face, e1, e2)) + { + if (!stripfaces++) + str << "StripFace {Strip face} "; + + (*testout) << "Face " << i << " is a strip (edge " << emap.FindIndex(e1) + << " and edge " << emap.FindIndex(e2) + << " are identical)" << endl; + str << "StripFace/Face" << i << " "; + str << "{Face " << i << " (edge " << emap.FindIndex(e1) + << " and edge " << emap.FindIndex(e2) << " are identical)} "; + } + + if (int count = csm.CheckSplittingVertices(face, mapEdges, mapParam, theAllVert)) + { + if (!facessplitbyvertices++) + str << "FaceSplitByVertices {Face split by vertices} "; + + (*testout) << "Face " << i << " is split by " << count + << " vertex/vertices " << endl; + str << "FaceSplitByVertices/Face" << i << " "; + str << "{Face " << i << " (split by " << count << "vertex/vertices)} "; + } + + int whatrow, sens; + if (int type = csm.CheckPin (face, whatrow, sens)) + { + if (type == 1) + { + if (!smoothpinfaces++) + str << "SmoothPinFace {Smooth pin face} "; + + (*testout) << "Face " << i << " is a smooth pin" << endl; + str << "SmoothPinFace/Face" << i << " "; + str << "{Face " << i << " } "; + } + else + { + if (!stretchedpinfaces++) + str << "StretchedPinFace {Stretched pin face} "; + + (*testout) << "Face " << i << " is a streched pin" << endl; + str << "StretchedPinFace/Face" << i << " "; + str << "{Face " << i << " } "; + } + } + + double paramu, paramv; + if (csm.CheckTwisted (face, paramu, paramv)) + { + if (!twistedfaces++) + str << "TwistedFace {Twisted face} "; + + (*testout) << "Face " << i << " is twisted" << endl; + str << "TwistedFace/Face" << i << " "; + str << "{Face " << i << " } "; + } + } + + cout << "done" << endl; + cout << "checking edges ... " << flush; + + double dmax; + int cnt = 0; + ARRAY <double> edgeLengths; + ARRAY <int> order; + edgeLengths.SetSize (emap.Extent()); + order.SetSize (emap.Extent()); + + for (i = 1; i <= emap.Extent(); i++) + { + TopoDS_Edge edge1 = TopoDS::Edge (emap(i)); + GProp_GProps system; + BRepGProp::LinearProperties(edge1, system); + edgeLengths[i-1] = system.Mass(); + /* + int j; + for (j = i+1; j <= emap.Extent(); j++) + { + TopoDS_Edge edge2 = TopoDS::Edge (emap(j)); + + if (csm.CheckStripEdges(edge1, edge2, csm.Tolerance(), dmax)) + { + if (!edgessamebutnotidentified++) + str << "EdgesSameButNotIdentified {Edges same but not identified} "; + + cnt++; + (*testout) << "Edge " << i << " and edge " << j + << " are on one strip (same but not identified)" << endl; + str << "EdgesSameButNotIdentified/Edge" << cnt << " "; + str << "{Edge " << i << " and Edge " << j << "} "; + } + } + */ + } + + 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; + + /* + for (i = 1; i <= shmap.Extent(); i++) + { + TopoDS_Shell shell = TopoDS::Shell (shmap(i)); + if (!shell.Closed()) + cout << "Shell " << i << " is not closed" << endl; + if (shell.Infinite()) + cout << "Shell " << i << " is infinite" << endl; + + BRepCheck_Analyzer ba(shell); + if (!ba.IsValid ()) + cout << "Shell " << i << " is not valid" << endl; + } + + for (i = 1; i <= somap.Extent(); i++) + { + TopoDS_Solid solid = TopoDS::Solid (somap(i)); + if (!solid.Closed()) + cout << "Solid " << i << " is not closed" << endl; + if (solid.Infinite()) + cout << "Solid " << i << " is infinite" << endl; + + BRepCheck_Analyzer ba(solid); + if (!ba.IsValid ()) + cout << "Solid " << i << " is not valid" << 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; +} + +} + + +#endif diff --git a/contrib/Netgen/libsrc/occ/occgeom.hpp b/contrib/Netgen/libsrc/occ/occgeom.hpp new file mode 100644 index 0000000000..5082ab3b91 --- /dev/null +++ b/contrib/Netgen/libsrc/occ/occgeom.hpp @@ -0,0 +1,279 @@ +#ifndef FILE_OCCGEOM +#define FILE_OCCGEOM + +/* *************************************************************************/ +/* File: occgeom.hpp */ +/* Author: Robert Gaisbauer */ +/* Date: 26. May 03 */ +/* *************************************************************************/ + +#ifdef OCCGEOMETRY + +#include <meshing.hpp> + +#include "BRep_Tool.hxx" +#include "Geom_Curve.hxx" +#include "Geom2d_Curve.hxx" +#include "Geom_Surface.hxx" +#include "GeomAPI_ProjectPointOnSurf.hxx" +#include "GeomAPI_ProjectPointOnCurve.hxx" +#include "BRepTools.hxx" +#include "TopExp.hxx" +#include "BRepBuilderAPI_MakeVertex.hxx" +#include "BRepBuilderAPI_MakeShell.hxx" +#include "BRepBuilderAPI_MakeSolid.hxx" +#include "BRepOffsetAPI_Sewing.hxx" +#include "BRepLProp_SLProps.hxx" +#include "BRepAdaptor_Surface.hxx" +#include "Poly_Triangulation.hxx" +#include "Poly_Array1OfTriangle.hxx" +#include "TColgp_Array1OfPnt2d.hxx" +#include "Poly_Triangle.hxx" +#include "GProp_GProps.hxx" +#include "BRepGProp.hxx" +#include "Geom_Surface.hxx" +#include "TopExp.hxx" +#include "gp_Pnt.hxx" +#include "TopoDS.hxx" +#include "TopoDS_Solid.hxx" +#include "TopExp_Explorer.hxx" +#include "BRep_Tool.hxx" +#include "Geom_Curve.hxx" +#include "Geom2d_Curve.hxx" +#include "Geom_Surface.hxx" +#include "GeomAPI_ProjectPointOnSurf.hxx" +#include "GeomAPI_ProjectPointOnCurve.hxx" +#include "TopoDS_Wire.hxx" +#include "BRepTools_WireExplorer.hxx" +#include "BRepTools.hxx" +#include "TopTools_IndexedMapOfShape.hxx" +#include "TopExp.hxx" +#include "BRepBuilderAPI_MakeVertex.hxx" +#include "BRepBuilderAPI_MakeShell.hxx" +#include "BRepBuilderAPI_MakeSolid.hxx" +#include "BRepOffsetAPI_Sewing.hxx" +#include "BRepLProp_CLProps.hxx" +#include "BRepLProp_SLProps.hxx" +#include "BRepAdaptor_Surface.hxx" +#include "BRepAdaptor_Curve.hxx" +#include "Poly_Triangulation.hxx" +#include "Poly_Array1OfTriangle.hxx" +#include "TColgp_Array1OfPnt2d.hxx" +#include "Poly_Triangle.hxx" +#include "GProp_GProps.hxx" +#include "BRepGProp.hxx" +#include "IGESControl_Reader.hxx" +#include "STEPControl_Reader.hxx" +#include "TopoDS_Shape.hxx" +#include "TopoDS_Face.hxx" +#include "IGESToBRep_Reader.hxx" +#include "Interface_Static.hxx" +#include "GeomAPI_ExtremaCurveCurve.hxx" +#include "Standard_ErrorHandler.hxx" +#include "Standard_Failure.hxx" +#include "ShapeUpgrade_ShellSewing.hxx" +#include "ShapeFix_Shape.hxx" +#include "ShapeFix_Wireframe.hxx" +#include "BRepMesh.hxx" +#include "BRepMesh_IncrementalMesh.hxx" +#include "BRepBndLib.hxx" +#include "Bnd_Box.hxx" +#include "ShapeAnalysis.hxx" +#include "ShapeBuild_ReShape.hxx" +#include "IGESControl_Writer.hxx" +#include "STEPControl_Writer.hxx" +#include "StlAPI_Writer.hxx" +#include "STEPControl_StepModelType.hxx" + +namespace netgen +{ + +#include "../visualization/vispar.hpp" + // class VisualizationParameters; + // extern VisualizationParameters vispar; + + +#include "occmeshsurf.hpp" + +#define PROJECTION_TOLERANCE 1e-10 + + +#define ENTITYISVISIBLE 1 +#define ENTITYISHIGHLIGHTED 2 +#define ENTITYISDRAWABLE 4 + +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; } +}; + + + +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; +} + + + +#define OCCGEOMETRYVISUALIZATIONNOCHANGE 0 +#define OCCGEOMETRYVISUALIZATIONFULLCHANGE 1 + // == compute transformation matrices and redraw +#define OCCGEOMETRYVISUALIZATIONHALFCHANGE 2 + // == redraw + +class OCCGeometry +{ + Point<3> center; + +public: + TopoDS_Shape shape; + TopTools_IndexedMapOfShape fmap, emap, vmap, somap, shmap, wmap; + Box<3> boundingbox; + + int changed; + ARRAY<int> facemeshstatus; + + ARRAY<EntityVisualizationCode> fvispar, evispar, vvispar; + + double tolerance; + bool fixsmalledges; + bool fixspotstripfaces; + bool sewfaces; + bool makesolids; + + + OCCGeometry() + { + somap.Clear(); + shmap.Clear(); + fmap.Clear(); + wmap.Clear(); + emap.Clear(); + vmap.Clear(); + } + + + void BuildFMap(); + + Box<3> GetBoundingBox() + { return boundingbox; } + + int NrSolids() + { return somap.Extent(); } + + void SetCenter() + { center = boundingbox.Center(); } + + Point<3> Center() + { return center; } + + void Project (int surfi, Point<3> & p) const + { + static int cnt = 0; + if (++cnt % 1000 == 0) cout << "Project cnt = " << cnt << endl; + + gp_Pnt pnt(p(0), p(1), p(2)); + + GeomAPI_ProjectPointOnSurf proj(pnt, BRep_Tool::Surface(TopoDS::Face(fmap(surfi)))); + if (proj.NbPoints() == 0) + { + cout << "Projection fails" << endl; + } + else + { + pnt = proj.NearestPoint(); + p = Point<3> (pnt.X(), pnt.Y(), pnt.Z()); + } + } + + bool FastProject (int surfi, Point<3> & ap, double& u, double& v) const; + + + OCCSurface GetSurface (int surfi) + { + cout << "OCCGeometry::GetSurface using PLANESPACE" << endl; + return OCCSurface (TopoDS::Face(fmap(surfi)), PLANESPACE); + } + + + void BuildVisualizationMesh (); + + void RecursiveTopologyTree (const TopoDS_Shape & sh, + stringstream & str, + TopAbs_ShapeEnum l, + bool free, + const char * lname); + + void GetTopologyTree (stringstream & str); + + void PrintNrShapes (); + + void CheckIrregularEntities (stringstream & str); + + void SewFaces(); + + void MakeSolid(); + + void HealGeometry(); + + 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 PrintContents (OCCGeometry * geom); + +OCCGeometry * LoadOCC_IGES (const char * filename); +OCCGeometry * LoadOCC_STEP (const char * filename); + +} + +#endif + +#endif diff --git a/contrib/Netgen/libsrc/occ/occmeshsurf.cpp b/contrib/Netgen/libsrc/occ/occmeshsurf.cpp new file mode 100644 index 0000000000..034571c9ae --- /dev/null +++ b/contrib/Netgen/libsrc/occ/occmeshsurf.cpp @@ -0,0 +1,592 @@ +#ifdef OCCGEOMETRY + +#include <mystdlib.h> + +#include <occgeom.hpp> +#include <meshing.hpp> + + +namespace netgen +{ +#include "occmeshsurf.hpp" + + +void OCCSurface :: GetNormalVector (const Point<3> & p, + const PointGeomInfo & geominfo, + Vec<3> & n) const +{ + gp_Pnt pnt; + gp_Vec du, dv; + + /* + double gu = geominfo.u; + double gv = geominfo.v; + + if (fabs (gu) < 1e-3) gu = 0; + if (fabs (gv) < 1e-3) gv = 0; + + occface->D1(gu,gv,pnt,du,dv); + */ + + occface->D1(geominfo.u,geominfo.v,pnt,du,dv); + + n = Cross (Vec<3>(du.X(), du.Y(), du.Z()), + Vec<3>(dv.X(), dv.Y(), dv.Z())); + n.Normalize(); + + if (orient == TopAbs_REVERSED) n = -1*n; + // (*testout) << "GetNormalVector" << endl; +} + + +void OCCSurface :: DefineTangentialPlane (const Point<3> & ap1, + const PointGeomInfo & geominfo1, + const Point<3> & ap2, + const PointGeomInfo & geominfo2) +{ + if (projecttype == PLANESPACE) + { + p1 = ap1; p2 = ap2; + + // cout << "p1 = " << p1 << endl; + // cout << "p2 = " << p2 << endl; + + GetNormalVector (p1, geominfo1, ez); + + ex = p2 - p1; + ex -= (ex * ez) * ez; + ex.Normalize(); + ey = Cross (ez, ex); + + GetNormalVector (p2, geominfo2, n2); + + nmid = 0.5*(n2+ez); + + ez = nmid; + ez.Normalize(); + + ex = (p2 - p1).Normalize(); + ez -= (ez * ex) * ex; + ez.Normalize(); + ey = Cross (ez, ex); + nmid = ez; + } + else + { + if ( (geominfo1.u < umin) || + (geominfo1.u > umax) || + (geominfo2.u < umin) || + (geominfo2.u > umax) || + (geominfo1.v < vmin) || + (geominfo1.v > vmax) || + (geominfo2.v < vmin) || + (geominfo2.v > vmax) ) throw UVBoundsException(); + + + p1 = ap1; p2 = ap2; + psp1 = Point<2>(geominfo1.u, geominfo1.v); + psp2 = Point<2>(geominfo2.u, geominfo2.v); + + Vec<3> n; + GetNormalVector (p1, geominfo1, n); + + gp_Pnt pnt; + gp_Vec du, dv; + occface->D1 (geominfo1.u, geominfo1.v, pnt, du, dv); + + DenseMatrix D1(3,2), D1T(2,3), DDTinv(2,2); + D1(0,0) = du.X(); D1(1,0) = du.Y(); D1(2,0) = du.Z(); + D1(0,1) = dv.X(); D1(1,1) = dv.Y(); D1(2,1) = dv.Z(); + + /* + (*testout) << "DefineTangentialPlane" << endl + << "---------------------" << endl; + (*testout) << "D1 = " << endl << D1 << endl; + */ + + Transpose (D1, D1T); + DenseMatrix D1TD1(3,3); + + D1TD1 = D1T*D1; + if (D1TD1.Det() == 0) throw SingularMatrixException(); + + CalcInverse (D1TD1, DDTinv); + DenseMatrix Y(3,2); + Vec<3> y1 = (ap2-ap1).Normalize(); + Vec<3> y2 = Cross(n, y1).Normalize(); + for (int i = 0; i < 3; i++) + { + Y(i,0) = y1(i); + Y(i,1) = y2(i); + } + + DenseMatrix A(2,2); + A = DDTinv * D1T * Y; + DenseMatrix Ainv(2,2); + + if (A.Det() == 0) throw SingularMatrixException(); + + CalcInverse (A, Ainv); + + for (int i = 0; i < 2; i++) + for (int j = 0; j < 2; j++) + { + Amat(i,j) = A(i,j); + Amatinv(i,j) = Ainv(i,j); + } + + Vec<2> temp = Amatinv * (psp2-psp1); + + + double r = temp.Length(); + // double alpha = -acos (temp(0)/r); + double alpha = -atan2 (temp(1),temp(0)); + DenseMatrix R(2,2); + R(0,0) = cos (alpha); + R(1,0) = -sin (alpha); + R(0,1) = sin (alpha); + R(1,1) = cos (alpha); + + + A = A*R; + + if (A.Det() == 0) throw SingularMatrixException(); + + CalcInverse (A, Ainv); + + + for (int i = 0; i < 2; i++) + for (int j = 0; j < 2; j++) + { + Amat(i,j) = A(i,j); + Amatinv(i,j) = Ainv(i,j); + } + + temp = Amatinv * (psp2-psp1); + + }; + +} + + +void OCCSurface :: ToPlane (const Point<3> & p3d, + const PointGeomInfo & geominfo, + Point<2> & pplane, + double h, int & zone) const +{ + if (projecttype == PLANESPACE) + { + Vec<3> p1p, n; + GetNormalVector (p3d, geominfo, n); + + p1p = p3d - p1; + pplane(0) = (p1p * ex) / h; + pplane(1) = (p1p * ey) / h; + + if (n * nmid < 0) + zone = -1; + else + zone = 0; + } + else + { + pplane = Point<2>(geominfo.u, geominfo.v); + // (*testout) << "(u,v) = " << geominfo.u << ", " << geominfo.v << endl; + pplane = Point<2> (1/h * (Amatinv * (pplane-psp1))); + // pplane = Point<2> (h * (Amatinv * (pplane-psp1))); + // pplane = Point<2> (1/h * ((pplane-psp1))); + + zone = 0; + }; +} + + +void OCCSurface :: FromPlane (const Point<2> & pplane, + Point<3> & p3d, + PointGeomInfo & gi, + double h) +{ + if (projecttype == PLANESPACE) + { + // cout << "2d : " << pplane << endl; + p3d = p1 + (h * pplane(0)) * ex + (h * pplane(1)) * ey; + // cout << "3d : " << p3d << endl; + Project (p3d, gi); + // cout << "proj : " << p3d << endl; + } + else + { + // Point<2> pspnew = Point<2>(1/h * (Amat * Vec<2>(pplane)) + Vec<2>(psp1)); + Point<2> pspnew = Point<2>(h * (Amat * Vec<2>(pplane)) + Vec<2>(psp1)); + // Point<2> pspnew = Point<2>(h * (Vec<2>(pplane)) + Vec<2>(psp1)); + gi.u = pspnew(0); + gi.v = pspnew(1); + gi.trignum = 1; + gp_Pnt val = occface->Value (gi.u, gi.v); + p3d = Point<3> (val.X(), val.Y(), val.Z()); + }; +} + + + +void OCCSurface :: Project (Point<3> & p, PointGeomInfo & gi) +{ + // static int cnt = 0; + // if (cnt++ % 1000 == 0) cout << "********************************************** OCCSurfce :: Project, cnt = " << cnt << endl; + + gp_Pnt pnt(p(0), p(1), p(2)); + + // cout << "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); + gi.trignum = 1; + + p = Point<3> (pnt.X(), pnt.Y(), pnt.Z()); +} + + +Meshing2OCCSurfaces :: Meshing2OCCSurfaces (const TopoDS_Shape & asurf, + const Box<3> & abb, int aprojecttype) + : Meshing2(Box3d(abb.PMin(), abb.PMax())), surface(TopoDS::Face(asurf), aprojecttype) +{ + ; +} + + +void Meshing2OCCSurfaces :: DefineTransformation (Point3d & p1, Point3d & p2, + const PointGeomInfo * geominfo1, + const PointGeomInfo * geominfo2) +{ + ((OCCSurface&)surface).DefineTangentialPlane (p1, *geominfo1, p2, *geominfo2); +} + +void Meshing2OCCSurfaces :: TransformToPlain (const Point3d & locpoint, + const MultiPointGeomInfo & geominfo, + Point2d & planepoint, + double h, int & zone) +{ + Point<2> hp; + surface.ToPlane (locpoint, geominfo.GetPGI(1), hp, h, zone); + planepoint.X() = hp(0); + planepoint.Y() = hp(1); +} + +int Meshing2OCCSurfaces :: TransformFromPlain (Point2d & planepoint, + Point3d & locpoint, + PointGeomInfo & gi, + double h) +{ + Point<3> hp; + Point<2> hp2 (planepoint.X(), planepoint.Y()); + surface.FromPlane (hp2, hp, gi, h); + locpoint = hp; + return 0; +} + + + +double Meshing2OCCSurfaces :: CalcLocalH (const Point3d & p, double gh) const +{ + return gh; +} + + + + + + +MeshOptimize2dOCCSurfaces :: MeshOptimize2dOCCSurfaces (const OCCGeometry & ageometry) + : MeshOptimize2d(), geometry(ageometry) +{ + ; +} + + +void MeshOptimize2dOCCSurfaces :: ProjectPoint (INDEX surfind, Point3d & p) const +{ + Point<3> hp = p; + geometry.Project (surfind, hp); + p = hp; +} + +void MeshOptimize2dOCCSurfaces :: ProjectPoint2 (INDEX surfind, INDEX surfind2, + Point3d & p) const +{ + TopExp_Explorer exp0, exp1; + bool done = false; + Handle(Geom_Curve) c; + + for (exp0.Init(geometry.fmap(surfind), TopAbs_EDGE); !done && exp0.More(); exp0.Next()) + for (exp1.Init(geometry.fmap(surfind2), TopAbs_EDGE); !done && exp1.More(); exp1.Next()) + { + if (TopoDS::Edge(exp0.Current()).IsSame(TopoDS::Edge(exp1.Current()))) + { + done = true; + double s0, s1; + c = BRep_Tool::Curve(TopoDS::Edge(exp0.Current()), s0, s1); + } + } + + gp_Pnt pnt(p.X(), p.Y(), p.Z()); + GeomAPI_ProjectPointOnCurve proj(pnt, c); + pnt = proj.NearestPoint(); + p.X() = pnt.X(); + p.Y() = pnt.Y(); + p.Z() = pnt.Z(); + +} + +void MeshOptimize2dOCCSurfaces :: +GetNormalVector(INDEX surfind, const Point3d & p, PointGeomInfo & geominfo, Vec3d & n) const +{ + gp_Pnt pnt; + gp_Vec du, dv; + + Handle(Geom_Surface) occface; + occface = BRep_Tool::Surface(TopoDS::Face(geometry.fmap(surfind))); + + occface->D1(geominfo.u,geominfo.v,pnt,du,dv); + + n = Cross (Vec<3>(du.X(), du.Y(), du.Z()), + Vec<3>(dv.X(), dv.Y(), dv.Z())); + n.Normalize(); + + if (geometry.fmap(surfind).Orientation() == TopAbs_REVERSED) n = -1*n; + + // GetNormalVector (surfind, p, n); +} + + +void MeshOptimize2dOCCSurfaces :: +GetNormalVector(INDEX surfind, const Point3d & p, Vec3d & n) const +{ + // static int cnt = 0; + // if (cnt++ % 1000 == 0) cout << "GetNV cnt = " << cnt << endl; + Standard_Real u,v; + + gp_Pnt pnt(p.X(), p.Y(), p.Z()); + + Handle(Geom_Surface) occface; + occface = BRep_Tool::Surface(TopoDS::Face(geometry.fmap(surfind))); + + GeomAPI_ProjectPointOnSurf proj(pnt, occface); + + if (proj.NbPoints() < 1) + { + cout << "ERROR: OCCSurface :: GetNormalVector: GeomAPI_ProjectPointOnSurf failed!" + << endl; + cout << p << endl; + return; + } + + proj.LowerDistanceParameters (u, v); + + gp_Vec du, dv; + occface->D1(u,v,pnt,du,dv); + + /* + if (!occface->IsCNu (1) || !occface->IsCNv (1)) + (*testout) << "SurfOpt: Differentiation FAIL" << endl; + */ + + n = Cross (Vec3d(du.X(), du.Y(), du.Z()), + Vec3d(dv.X(), dv.Y(), dv.Z())); + n.Normalize(); + + if (geometry.fmap(surfind).Orientation() == TopAbs_REVERSED) n = -1*n; +} + + +int MeshOptimize2dOCCSurfaces :: +CalcPointGeomInfo(int surfind, PointGeomInfo& gi, const Point3d& p) const +{ + Standard_Real u,v; + + gp_Pnt pnt(p.X(), p.Y(), p.Z()); + + Handle(Geom_Surface) occface; + occface = BRep_Tool::Surface(TopoDS::Face(geometry.fmap(surfind))); + + GeomAPI_ProjectPointOnSurf proj(pnt, occface); + + if (proj.NbPoints() < 1) + { + cout << "ERROR: OCCSurface :: GetNormalVector: GeomAPI_ProjectPointOnSurf failed!" + << endl; + cout << p << endl; + return 0; + } + + proj.LowerDistanceParameters (u, v); + + gi.u = u; + gi.v = v; + return 1; +} + + + + + + +OCCRefinementSurfaces :: OCCRefinementSurfaces (const OCCGeometry & ageometry) + : Refinement(), geometry(ageometry) +{ + ; +} + +OCCRefinementSurfaces :: ~OCCRefinementSurfaces () +{ + ; +} + +/* +inline double Det3 (double a00, double a01, double a02, + double a10, double a11, double a12, + double a20, double a21, double a22) +{ + return a00*a11*a22 + a01*a12*a20 + a10*a21*a02 - a20*a11*a02 - a10*a01*a22 - a21*a12*a00; +} + +bool ProjectToSurface (gp_Pnt & p, Handle(Geom_Surface) surface, double& u, double& v) +{ + gp_Pnt x = surface->Value (u,v); + + if (p.SquareDistance(x) <= sqr(PROJECTION_TOLERANCE)) return true; + + gp_Vec du, dv; + + surface->D1(u,v,x,du,dv); + + int count = 0; + + gp_Pnt xold; + gp_Vec n; + double det, lambda, mu; + + do { + count++; + + n = du^dv; + + det = Det3 (n.X(), du.X(), dv.X(), + n.Y(), du.Y(), dv.Y(), + n.Z(), du.Z(), dv.Z()); + + if (det < 1e-15) return false; + + lambda = Det3 (n.X(), p.X()-x.X(), dv.X(), + n.Y(), p.Y()-x.Y(), dv.Y(), + n.Z(), p.Z()-x.Z(), dv.Z())/det; + + mu = Det3 (n.X(), du.X(), p.X()-x.X(), + n.Y(), du.Y(), p.Y()-x.Y(), + n.Z(), du.Z(), p.Z()-x.Z())/det; + + u += lambda; + v += mu; + + xold = x; + surface->D1(u,v,x,du,dv); + + } while (xold.SquareDistance(x) > sqr(PROJECTION_TOLERANCE) || count > 50); + + if (count > 50) return false; + + p = x; + + return true; +} +*/ + +void OCCRefinementSurfaces :: +PointBetween (const Point3d & p1, const Point3d & p2, double secpoint, + int surfi, + const PointGeomInfo & gi1, + const PointGeomInfo & gi2, + Point3d & newp, PointGeomInfo & newgi) +{ + Point<3> hnewp; + hnewp = p1+secpoint*(p2-p1); + + if (surfi > 0) + { + + double u = gi1.u+secpoint*(gi2.u-gi1.u); + double v = gi1.v+secpoint*(gi2.v-gi1.v); + + if (!geometry.FastProject (surfi, hnewp, u, v)) + { + cout << "Fast projection to surface fails! Using OCC projection" << endl; + geometry.Project (surfi, hnewp); + } + + newgi.trignum = 1; + } + + newp = hnewp; +} + + +void OCCRefinementSurfaces :: +PointBetween (const Point3d & p1, const Point3d & p2, double secpoint, + int surfi1, int surfi2, + const EdgePointGeomInfo & ap1, + const EdgePointGeomInfo & ap2, + Point3d & newp, EdgePointGeomInfo & newgi) +{ + double s0, s1; + + Point<3> hnewp = p1+secpoint*(p2-p1); + gp_Pnt pnt(hnewp(0), hnewp(1), hnewp(2)); + GeomAPI_ProjectPointOnCurve proj(pnt, BRep_Tool::Curve(TopoDS::Edge(geometry.emap(ap1.edgenr)), s0, s1)); + pnt = proj.NearestPoint(); + hnewp = Point<3> (pnt.X(), pnt.Y(), pnt.Z()); + newp = hnewp; + newgi = ap1; +}; + + +void OCCRefinementSurfaces :: ProjectToSurface (Point<3> & p, int surfi) +{ + if (surfi > 0) + geometry.Project (surfi, p); +}; + +void OCCRefinementSurfaces :: ProjectToSurface (Point<3> & p, int surfi, PointGeomInfo & gi) +{ + if (surfi > 0) + if (!geometry.FastProject (surfi, p, gi.u, gi.v)) + { + cout << "Fast projection to surface fails! Using OCC projection" << endl; + geometry.Project (surfi, p); + } +}; + + + +} + + +#endif diff --git a/contrib/Netgen/libsrc/occ/occmeshsurf.hpp b/contrib/Netgen/libsrc/occ/occmeshsurf.hpp new file mode 100644 index 0000000000..bda8a05a64 --- /dev/null +++ b/contrib/Netgen/libsrc/occ/occmeshsurf.hpp @@ -0,0 +1,201 @@ +#ifdef OCCGEOMETRY + +#ifndef FILE_OCCMESHSURF +#define FILE_OCCMESHSURF + +#include "occgeom.hpp" + +#define PARAMETERSPACE -1 +#define PLANESPACE 1 + +class OCCGeometry; + +class SingularMatrixException +{}; + +class UVBoundsException +{}; + +class OCCSurface +{ +public: + TopoDS_Face topods_face; + Handle(Geom_Surface) occface; + TopAbs_Orientation orient; + int projecttype; + +protected: + Point<3> p1; + Point<3> p2; + + /// in plane, directed p1->p2 + Vec<3> ex; + /// in plane + Vec<3> ey; + /// outer normal direction + Vec<3> ez; + + /// normal vector in p2 + Vec<3> n2; + + /// average normal vector + Vec<3> nmid; + + // for transformation to parameter space + Point<2> psp1; + Point<2> psp2; + Vec<2> psex; + Vec<2> psey; + Mat<2,2> Amat, Amatinv; + + // UV Bounds + double umin, umax, vmin, vmax; + +public: + OCCSurface (const TopoDS_Face & aface, int aprojecttype) + { + topods_face = aface; + occface = BRep_Tool::Surface(topods_face); + orient = topods_face.Orientation(); + projecttype = aprojecttype; + ShapeAnalysis::GetFaceUVBounds (topods_face, umin, umax, vmin, vmax); + umin -= fabs(umax-umin)/100.0; + vmin -= fabs(vmax-vmin)/100.0; + umax += fabs(umax-umin)/100.0; + vmax += fabs(vmax-vmin)/100.0; + // projecttype = PLANESPACE; + /* + TopExp_Explorer exp1; + exp1.Init (topods_face, TopAbs_WIRE); + orient = TopAbs::Compose (orient, exp1.Current().Orientation()); + */ + }; + + ~OCCSurface() + {}; + + void Project (Point<3> & p, PointGeomInfo & gi); + + void GetNormalVector (const Point<3> & p, + const PointGeomInfo & geominfo, + Vec<3> & n) const; + + /** + Defines tangential plane in ap1. + The local x-coordinate axis point to the direction of ap2 */ + void DefineTangentialPlane (const Point<3> & ap1, + const PointGeomInfo & geominfo1, + const Point<3> & ap2, + const PointGeomInfo & geominfo2); + + + /// Transforms 3d point p3d to local coordinates pplane + void ToPlane (const Point<3> & p3d, const PointGeomInfo & geominfo, + Point<2> & pplane, double h, int & zone) const; + + /// Transforms point pplane in local coordinates to 3d point + void FromPlane (const Point<2> & pplane, + Point<3> & p3d, + PointGeomInfo & gi, + double h); +}; + + + +/// +class Meshing2OCCSurfaces : public Meshing2 +{ + /// + OCCSurface surface; + +public: + /// + Meshing2OCCSurfaces (const TopoDS_Shape & asurf, const Box<3> & aboundingbox, int aprojecttype); + + /// + int GetProjectionType () + { return surface.projecttype; } + +protected: + /// + virtual void DefineTransformation (Point3d & p1, Point3d & p2, + const PointGeomInfo * geominfo1, + const PointGeomInfo * geominfo2); + /// + virtual void TransformToPlain (const Point3d & locpoint, + const MultiPointGeomInfo & geominfo, + Point2d & plainpoint, + double h, int & zone); + /// + virtual int TransformFromPlain (Point2d & plainpoint, + Point3d & locpoint, + PointGeomInfo & gi, + double h); + /// + virtual double CalcLocalH (const Point3d & p, double gh) const; + +}; + + + +/// +class MeshOptimize2dOCCSurfaces : public MeshOptimize2d + { + /// + const OCCGeometry & geometry; + +public: + /// + MeshOptimize2dOCCSurfaces (const OCCGeometry & ageometry); + + /// + virtual void ProjectPoint (INDEX surfind, Point3d & p) const; + /// + virtual void ProjectPoint2 (INDEX surfind, INDEX surfind2, Point3d & p) const; + /// + virtual void GetNormalVector(INDEX surfind, const Point3d & p, Vec3d & n) const; + /// + virtual void GetNormalVector(INDEX surfind, const Point3d & p, PointGeomInfo & gi, Vec3d & n) const; + + + virtual int CalcPointGeomInfo(int surfind, PointGeomInfo& gi, const Point3d& p3) const; + +}; + + + +class OCCGeometry; + + +class OCCRefinementSurfaces : public Refinement +{ + const OCCGeometry & geometry; + +public: + OCCRefinementSurfaces (const OCCGeometry & ageometry); + virtual ~OCCRefinementSurfaces (); + + virtual void PointBetween (const Point3d & p1, const Point3d & p2, double secpoint, + int surfi, + const PointGeomInfo & gi1, + const PointGeomInfo & gi2, + Point3d & newp, PointGeomInfo & newgi); + + virtual void PointBetween (const Point3d & p1, const Point3d & p2, double secpoint, + int surfi1, int surfi2, + const EdgePointGeomInfo & ap1, + const EdgePointGeomInfo & ap2, + Point3d & newp, EdgePointGeomInfo & newgi); + + virtual void ProjectToSurface (Point<3> & p, int surfi); + + virtual void ProjectToSurface (Point<3> & p, int surfi, PointGeomInfo & gi); +}; + + + +#endif + + + +#endif diff --git a/contrib/Netgen/libsrc/opti/Makefile b/contrib/Netgen/libsrc/opti/Makefile new file mode 100644 index 0000000000..d73441553f --- /dev/null +++ b/contrib/Netgen/libsrc/opti/Makefile @@ -0,0 +1,10 @@ +# +# Makefile for optimisation library +# +src = bfgs.cpp linsearch.cpp linopt.cpp +# +lib = opti +libpath = libsrc/opti +# +# +include ../makefile.inc diff --git a/contrib/Netgen/libsrc/opti/bfgs.cpp b/contrib/Netgen/libsrc/opti/bfgs.cpp new file mode 100644 index 0000000000..31a499a64d --- /dev/null +++ b/contrib/Netgen/libsrc/opti/bfgs.cpp @@ -0,0 +1,367 @@ +/***************************************************************************/ +/* */ +/* Vorlesung Optimierung I, Gfrerer, WS94/95 */ +/* BFGS-Verfahren zur L�sung freier nichtlinearer Optimierungsprobleme */ +/* */ +/* Programmautor: Joachim Sch�berl */ +/* Matrikelnummer: 9155284 */ +/* */ +/***************************************************************************/ + +#include <mystdlib.h> +#include <myadt.hpp> + +#include <linalg.hpp> +#include "opti.hpp" + + +namespace netgen +{ + +void Cholesky (const DenseMatrix & a, + DenseMatrix & l, Vector & d) +{ + // Factors A = L D L^T + + double x; + + int i, j, k; + int n = a.Height(); + + // (*testout) << "a = " << a << endl; + + l = a; + + for (i = 1; i <= n; i++) + { + for (j = i; j <= n; j++) + { + x = l.Get(i, j); + + for (k = 1; k < i; k++) + x -= l.Get(i, k) * l.Get(j, k) * d.Get(k); + + if (i == j) + { + d.Elem(i) = x; + } + else + { + l.Elem(j, i) = x / d.Get(k); + } + } + } + + for (i = 1; i <= n; i++) + { + l.Elem(i, i) = 1; + for (j = i+1; j <= n; j++) + l.Elem(i, j) = 0; + } + + /* + // Multiply: + (*testout) << "multiplied factors: " << endl; + for (i = 1; i <= n; i++) + for (j = 1; j <= n; j++) + { + x = 0; + for (k = 1; k <= n; k++) + x += l.Get(i, k) * l.Get(j, k) * d.Get(k); + (*testout) << x << " "; + } + (*testout) << endl; + */ +} + + +void MultLDLt (const DenseMatrix & l, const Vector & d, const Vector & g, Vector & p) +{ + int i, j, n; + double val; + + n = l.Height(); + p = g; + for (i = 1; i <= n; i++) + { + val = 0; + for (j = i; j <= n; j++) + val += p.Get(j) * l.Get(j, i); + p.Set(i, val); + } + for (i = 1; i <= n; i++) + p.Elem(i) *= d.Get(i); + + for (i = n; i >= 1; i--) + { + val = 0; + for (j = 1; j <= i; j++) + val += p.Get(j) * l.Get(i, j); + p.Set(i, val); + } +} + +void SolveLDLt (const DenseMatrix & l, const Vector & d, const Vector & g, Vector & p) +{ + int i, j, n; + double val; + + n = l.Height(); + p = g; + + for (i = 1; i <= n; i++) + { + val = 0; + for (j = 1; j < i; j++) + val += p.Get(j) * l.Get(i, j); + p.Elem(i) -= val; + } + for (i = 1; i <= n; i++) + p.Elem(i) /= d.Get(i); + + for (i = n; i >= 1; i--) + { + val = 0; + for (j = i+1; j <= n; j++) + val += p.Get(j) * l.Get(j, i); + p.Elem(i) -= val; + } +} + +int LDLtUpdate (DenseMatrix & l, Vector & d, double a, const Vector & u) +{ + // Bemerkung: Es wird a aus R erlaubt + // Rueckgabewert: 0 .. D bleibt positiv definit + // 1 .. sonst + + int i, j, n; + + n = l.Height(); + + Vector v(n); + double t, told, xi; + + told = 1; + v = u; + + for (j = 1; j <= n; j++) + { + t = told + a * sqr (v.Elem(j)) / d.Get(j); + + if (t <= 0) return 1; + + xi = a * v.Elem(j) / (d.Get(j) * t); + + d.Elem(j) *= t / told; + + for (i = j + 1; i <= n; i++) + { + v.Elem(i) -= v.Elem(j) * l.Elem(i, j); + l.Elem(i, j) += xi * v.Elem(i); + } + + told = t; + } + + return 0; +} + + +double BFGS ( + Vector & x, // i: Startwert + // o: Loesung, falls IFAIL = 0 + const MinFunction & fun, + const OptiParameters & par, + double eps + ) + + +{ + + int i, j, n = x.Size(); + long it; + char a1crit, a3acrit; + + + Vector d(n), g(n), p(n), temp(n), bs(n), xneu(n), y(n), s(n), x0(n); + DenseMatrix l(n); + DenseMatrix hesse(n); + + double /* normg, */ alphahat, hd, fold; + double a1, a2; + const double mu1 = 0.1, sigma = 0.1, xi1 = 1, xi2 = 10; + const double tau = 0.1, tau1 = 0.1, tau2 = 0.6; + + Vector typx(x.Size()); // i: typische Groessenordnung der Komponenten + double f, f0; + double typf; // i: typische Groessenordnung der Loesung + double fmin = -1e5; // i: untere Schranke fuer Funktionswert + // double eps = 1e-8; // i: Abbruchschranke fuer relativen Gradienten + double tauf = 0.1; // i: Abbruchschranke fuer die relative Aenderung der + // Funktionswerte + int ifail; // o: 0 .. Erfolg + // -1 .. Unterschreitung von fmin + // 1 .. kein Erfolg bei Liniensuche + // 2 .. �berschreitung von itmax + + typx = par.typx; + typf = par.typf; + + + l = 0; + for (i = 1; i <= n; i++) + l.Elem(i, i) = 1; + + f = fun.FuncGrad (x, g); + f0 = f; + x0 = x; + + + it = 0; + do + { + // Restart + + if (it % (5 * n) == 0) + { + + for (i = 1; i <= n; i++) + d.Elem(i) = typf/ sqr (typx.Get(i)); // 1; + for (i = 2; i <= n; i++) + for (j = 1; j < i; j++) + l.Elem(i, j) = 0; + + /* + hesse = 0; + for (i = 1; i <= n; i++) + hesse.Elem(i, i) = typf / sqr (typx.Get(i)); + + fun.ApproximateHesse (x, hesse); + + Cholesky (hesse, l, d); + */ + } + + it++; + if (it > par.maxit_bfgs) + { + ifail = 2; + break; + } + + + // Solve with factorized B + + SolveLDLt (l, d, g, p); + + + p *= -1; + y = g; + + fold = f; + + // line search + + alphahat = 1; + lines (x, xneu, p, f, g, fun, par, alphahat, fmin, + mu1, sigma, xi1, xi2, tau, tau1, tau2, ifail); + + /* + if (it > par.maxit_bfgs/2) + { + (*testout) << "x = " << x << endl; + (*testout) << "xneu = " << xneu << endl; + (*testout) << "f = " << f << endl; + (*testout) << "g = " << g << endl; + } + */ + + + // (*testout) << "it = " << it << " f = " << f << endl; + // if (ifail != 0) break; + + s.Set2 (1, xneu, -1, x); + y *= -1; + y.Add (1,g); // y += g; + + x = xneu; + + // BFGS Update + + MultLDLt (l, d, s, bs); + + a1 = y * s; + a2 = s * bs; + + if (a1 > 0 && a2 > 0) + { + if (LDLtUpdate (l, d, 1 / a1, y) != 0) + { + cerr << "update error1" << endl; + ifail = 1; + break; + } + + if (LDLtUpdate (l, d, -1 / a2, bs) != 0) + { + cerr << "update error2" << endl; + ifail = 1; + break; + } + } + + // Calculate stop conditions + + hd = eps * max2 (typf, fabs (f)); + a1crit = 1; + for (i = 1; i <= n; i++) + if ( fabs (g.Elem(i)) * max2 (typx.Elem(i), fabs (x.Elem(i))) > hd) + a1crit = 0; + + + a3acrit = (fold - f <= tauf * max2 (typf, fabs (f))); + + // testout << "g = " << g << endl; + // testout << "a1crit, a3crit = " << int(a1crit) << ", " << int(a3acrit) << endl; + + /* + // Output for tests + + normg = sqrt (g * g); + + testout << "it =" << setw (5) << it + << " f =" << setw (12) << setprecision (5) << f + << " |g| =" << setw (12) << setprecision (5) << normg; + + testout << " x = (" << setw (12) << setprecision (5) << x.Elem(1); + for (i = 2; i <= n; i++) + testout << "," << setw (12) << setprecision (5) << x.Elem(i); + testout << ")" << endl; + */ + + // (*testout) << "it = " << it << " f = " << f << " x = " << x << endl + // << " g = " << g << " p = " << p << endl << endl; + + // (*testout) << "|g| = " << g.L2Norm() << endl; + + if (g.L2Norm() < fun.GradStopping (x)) break; + + } + while (!a1crit || !a3acrit); + + /* + (*testout) << "it = " << it << " g = " << g << " f = " << f + << " fail = " << ifail << endl; + */ + if (f0 < f || (ifail == 1)) + { + (*testout) << "fail, f = " << f << " f0 = " << f0 << endl; + f = f0; + x = x0; + } + + // (*testout) << "x = " << x << ", x0 = " << x0 << endl; + return f; +} + +} diff --git a/contrib/Netgen/libsrc/opti/linopt.cpp b/contrib/Netgen/libsrc/opti/linopt.cpp new file mode 100644 index 0000000000..a5d381e6b7 --- /dev/null +++ b/contrib/Netgen/libsrc/opti/linopt.cpp @@ -0,0 +1,73 @@ +#include <mystdlib.h> +#include <myadt.hpp> + +#include <linalg.hpp> +#include "opti.hpp" + +namespace netgen +{ + +void LinearOptimize (const DenseMatrix & a, const Vector & b, + const Vector & c, Vector & x) + + { + int i1, i2, i3, j; + DenseMatrix m(3), inv(3); + Vector rs(3), hx(3), res(a.Height()), res2(3); + double f, fmin; + int nrest; + + if (a.Width() != 3) + { + cerr << "LinearOptimize only implemented for 3 unknowns" << endl; + return; + } + + fmin = 1e10; + x = 0; + nrest = a.Height(); + for (i1 = 1; i1 <= nrest; i1++) + for (i2 = i1 + 1; i2 <= nrest; i2++) + for (i3 = i2 + 1; i3 <= nrest; i3++) + { + for (j = 1; j <= 3; j++) + { + m.Elem(1, j) = a.Get(i1, j); + m.Elem(2, j) = a.Get(i2, j); + m.Elem(3, j) = a.Get(i3, j); + } + + rs.Elem(1) = b.Get(i1); + rs.Elem(2) = b.Get(i2); + rs.Elem(3) = b.Get(i3); + + if (fabs (m.Det()) < 1e-12) continue; + + CalcInverse (m, inv); + inv.Mult (rs, hx); + + a.Residuum (hx, b, res); +// m.Residuum (hx, rs, res2); + f = c * hx; + +/* + testout -> precision(12); + (*testout) << "i = (" << i1 << "," << i2 << "," << i3 + << "), f = " << f << " x = " << x << " res = " << res + << " resmin = " << res.Min() + << " res2 = " << res2 << " prod = " << prod << endl; +*/ + + + double rmin = res.Elem(1); + for (int hi = 2; hi <= res.Size(); hi++) + if (res.Elem(hi) < rmin) rmin = res.Elem(hi); + + if ( (f < fmin) && rmin >= -1e-8) + { + fmin = f; + x = hx; + } + } + } +} diff --git a/contrib/Netgen/libsrc/opti/linsearch.cpp b/contrib/Netgen/libsrc/opti/linsearch.cpp new file mode 100644 index 0000000000..c847911dae --- /dev/null +++ b/contrib/Netgen/libsrc/opti/linsearch.cpp @@ -0,0 +1,346 @@ +/***************************************************************************/ +/* */ +/* Problem: Liniensuche */ +/* */ +/* Programmautor: Joachim Sch�berl */ +/* Matrikelnummer: 9155284 */ +/* */ +/* Algorithmus nach: */ +/* */ +/* Optimierung I, Gfrerer, WS94/95 */ +/* Algorithmus 2.1: Liniensuche Problem (ii) */ +/* */ +/***************************************************************************/ + + + +#include <mystdlib.h> + +#include <myadt.hpp> // min, max, sqr + +#include <linalg.hpp> +#include "opti.hpp" + + +namespace netgen +{ +const double eps0 = 1E-15; + +// Liniensuche + + +double MinFunction :: Func (const Vector & /* x */) const +{ + cerr << "Func of MinFunction called" << endl; + return 0; +} + +void MinFunction :: Grad (const Vector & /* x */, Vector & /* g */) const +{ + cerr << "Grad of MinFunction called" << endl; +} + +double MinFunction :: FuncGrad (const Vector & x, Vector & g) const +{ + int n = x.Size(); + int i, j; + + static Vector xr; + static Vector xl; + xr.SetSize(n); + xl.SetSize(n); + + double eps = 1e-6; + double fl, fr; + + for (i = 1; i <= n; i++) + { + xr.Set (1, x); + xl.Set (1, x); + xr.Elem(i) += eps; + xl.Elem(i) -= eps; + + fl = Func (xl); + fr = Func (xr); + + g.Elem(i) = (fr - fl) / (2 * eps); + } + + double f = Func(x); + // (*testout) << "f = " << f << " grad = " << g << endl; + return f; +} + + +double MinFunction :: FuncDeriv (const Vector & x, const Vector & dir, double & deriv) const +{ + Vector g(x.Size()); + double f = FuncGrad (x, g); + deriv = (g * dir); + + // (*testout) << "g = " << g << ", dir = " << dir << ", deriv = " << deriv << endl; + return f; +} + +void MinFunction :: ApproximateHesse (const Vector & x, + DenseMatrix & hesse) const +{ + int n = x.Size(); + int i, j; + + static Vector hx; + hx.SetSize(n); + + double eps = 1e-6; + double f, f11, f12, f21, f22; + + for (i = 1; i <= n; i++) + { + for (j = 1; j < i; j++) + { + hx = x; + hx.Elem(i) = x.Get(i) + eps; + hx.Elem(j) = x.Get(j) + eps; + f11 = Func(hx); + hx.Elem(i) = x.Get(i) + eps; + hx.Elem(j) = x.Get(j) - eps; + f12 = Func(hx); + hx.Elem(i) = x.Get(i) - eps; + hx.Elem(j) = x.Get(j) + eps; + f21 = Func(hx); + hx.Elem(i) = x.Get(i) - eps; + hx.Elem(j) = x.Get(j) - eps; + f22 = Func(hx); + + hesse.Elem(i, j) = hesse.Elem(j, i) = + (f11 + f22 - f12 - f21) / (2 * eps * eps); + } + + hx = x; + f = Func(x); + hx.Elem(i) = x.Get(i) + eps; + f11 = Func(hx); + hx.Elem(i) = x.Get(i) - eps; + f22 = Func(hx); + + hesse.Elem(i, i) = (f11 + f22 - 2 * f) / (eps * eps); + } + // (*testout) << "hesse = " << hesse << endl; +} + + + + + + + +/// Line search, modified Mangasarien conditions +void lines (Vector & x, // i: initial point of line-search + Vector & xneu, // o: solution, if successful + Vector & p, // i: search direction + double & f, // i: function-value at x + // o: function-value at xneu, iff ifail = 0 + Vector & g, // i: gradient at x + // o: gradient at xneu, iff ifail = 0 + const MinFunction & fun, // function to minimize + const OptiParameters & par, + double & alphahat, // i: initial value for alpha_hat + // o: solution alpha iff ifail = 0 + double fmin, // i: lower bound for f + double mu1, // i: Parameter mu_1 of Alg.2.1 + double sigma, // i: Parameter sigma of Alg.2.1 + double xi1, // i: Parameter xi_1 of Alg.2.1 + double xi2, // i: Parameter xi_1 of Alg.2.1 + double tau, // i: Parameter tau of Alg.2.1 + double tau1, // i: Parameter tau_1 of Alg.2.1 + double tau2, // i: Parameter tau_2 of Alg.2.1 + int & ifail) // o: 0 on success + // -1 bei termination because lower limit fmin + // 1 bei illegal termination due to different reasons + +{ + double phi0, phi0prime, phi1, phi1prime, phihatprime; + double alpha1, alpha2, alphaincr, c; + char flag = 1; + long it; + + alpha1 = 0; + alpha2 = 1e50; + phi0 = phi1 = f; + + phi0prime = g * p; + + + if (phi0prime > 0) + { + ifail = 1; + return; + } + + phi1prime = phi0prime; + + // (*testout) << "phi0prime = " << phi0prime << endl; + + // it = 100000l; + it = 0; + + while (it++ <= par.maxit_linsearch) + { + // (*testout) << "alphahat = " << alphahat << endl; + + xneu.Set2 (1, x, alphahat, p); + + // f = fun.FuncGrad (xneu, g); + // f = fun.Func (xneu); + f = fun.FuncDeriv (xneu, p, phihatprime); + + // (*testout) << "f = " << f << " phip = " << phihatprime << endl; + + if (f < fmin) + { + ifail = -1; + break; + } + + + if (alpha2 - alpha1 < eps0 * alpha2) + { + ifail = 0; + break; + } + + // (*testout) << "i = " << it << " al = " << alphahat << " f = " << f << " fprime " << phihatprime << endl;; + + if (f - phi0 > mu1 * alphahat * phi1prime + eps0 * fabs (phi0)) + + { + + flag = 0; + alpha2 = alphahat; + + c = + (f - phi1 - phi1prime * (alphahat-alpha1)) / + sqr (alphahat-alpha1); + + alphahat = alpha1 - 0.5 * phi1prime / c; + + if (alphahat > alpha2) + alphahat = alpha1 + 1/(4*c) * + ( (sigma+mu1) * phi0prime - 2*phi1prime + + sqrt (sqr(phi1prime - mu1 * phi0prime) - + 4 * (phi1 - phi0 - mu1 * alpha1 * phi0prime) * c)); + + alphahat = max2 (alphahat, alpha1 + tau * (alpha2 - alpha1)); + alphahat = min2 (alphahat, alpha2 - tau * (alpha2 - alpha1)); + + // (*testout) << " if-branch" << endl; + + } + + else + + { + /* + f = fun.FuncGrad (xneu, g); + phihatprime = g * p; + */ + f = fun.FuncDeriv (xneu, p, phihatprime); + + if (phihatprime < sigma * phi0prime * (1 + eps0)) + + { + if (phi1prime < phihatprime) + // Approximationsfunktion ist konvex + + alphaincr = (alphahat - alpha1) * phihatprime / + (phi1prime - phihatprime); + + else + alphaincr = 1e99; // MAXDOUBLE; + + if (flag) + { + alphaincr = max2 (alphaincr, xi1 * (alphahat-alpha1)); + alphaincr = min2 (alphaincr, xi2 * (alphahat-alpha1)); + } + else + { + alphaincr = max2 (alphaincr, tau1 * (alpha2 - alphahat)); + alphaincr = min2 (alphaincr, tau2 * (alpha2 - alphahat)); + } + + alpha1 = alphahat; + alphahat += alphaincr; + phi1 = f; + phi1prime = phihatprime; + } + + else + + { + ifail = 0; // Erfolg !! + break; + } + + // (*testout) << " else, " << endl; + + } + + } + + // (*testout) << "linsearch: it = " << it << " ifail = " << ifail << endl; + + fun.FuncGrad (xneu, g); + + + if (it < 0) + ifail = 1; + + // (*testout) << "fail = " << ifail << endl; +} + + + + + + + + + + + + + + + + + + + +void SteepestDescent (Vector & x, const MinFunction & fun, + const OptiParameters & par) +{ + int it, n = x.Size(); + Vector xnew(n), p(n), g(n), g2(n); + double val, alphahat; + int fail; + + val = fun.FuncGrad(x, g); + + alphahat = 1; + // testout << "f = "; + for (it = 0; it < 10; it++) + { + // testout << val << " "; + + // p = -g; + p.Set (-1, g); + + lines (x, xnew, p, val, g, fun, par, alphahat, -1e5, + 0.1, 0.1, 1, 10, 0.1, 0.1, 0.6, fail); + + x = xnew; + } + // testout << endl; +} +} diff --git a/contrib/Netgen/libsrc/opti/opti.hpp b/contrib/Netgen/libsrc/opti/opti.hpp new file mode 100644 index 0000000000..5fa0735bd0 --- /dev/null +++ b/contrib/Netgen/libsrc/opti/opti.hpp @@ -0,0 +1,142 @@ +#ifndef FILE_OPTI +#define FILE_OPTI + +/**************************************************************************/ +/* File: opti.hpp */ +/* Author: Joachim Schoeberl */ +/* Date: 01. Jun. 95 */ +/**************************************************************************/ + + + +namespace netgen +{ + + /** + Function to be minimized. + */ + class MinFunction + { + public: + /// + virtual double Func (const Vector & x) const; + /// + virtual void Grad (const Vector & x, Vector & g) const; + /// function and gradient + virtual double FuncGrad (const Vector & x, Vector & g) const; + /// directional derivative + virtual double FuncDeriv (const Vector & x, const Vector & dir, double & deriv) const; + /// if |g| < gradaccuray, then stop bfgs + virtual double GradStopping (const Vector & /* x */) const { return 0; } + + /// + virtual void ApproximateHesse (const Vector & /* x */, + DenseMatrix & /* hesse */) const; + }; + + + class OptiParameters + { + public: + int maxit_linsearch; + int maxit_bfgs; + double typf; + double typx; + + OptiParameters () + { + maxit_linsearch = 100; + maxit_bfgs = 100; + typf = 1; + typx = 1; + } + }; + + + /** Implementation of BFGS method. + Efficient method for non-linear minimiztion problems. + @param x initial value and solution + @param fun function to be minimized + */ + extern double BFGS (Vector & x, const MinFunction & fun, + const OptiParameters & par, + double eps = 1e-8); + + /** Steepest descent method. + Simple method for non-linear minimization problems. + @param x initial value and solution + @param fun function to be minimized + */ + void SteepestDescent (Vector & x, const MinFunction & fun, + const OptiParameters & par); + + + extern void lines ( + Vector & x, // i: Ausgangspunkt der Liniensuche + Vector & xneu, // o: Loesung der Liniensuche bei Erfolg + Vector & p, // i: Suchrichtung + double & f, // i: Funktionswert an der Stelle x + // o: Funktionswert an der Stelle xneu, falls ifail = 0 + Vector & g, // i: Gradient an der Stelle x + // o: Gradient an der Stelle xneu, falls ifail = 0 + + const MinFunction & fun, // function to minmize + const OptiParameters & par, // parameters + double & alphahat, // i: Startwert f�r alpha_hat + // o: Loesung falls ifail = 0 + double fmin, // i: untere Schranke f�r f + double mu1, // i: Parameter mu_1 aus Alg.2.1 + double sigma, // i: Parameter sigma aus Alg.2.1 + double xi1, // i: Parameter xi_1 aus Alg.2.1 + double xi2, // i: Parameter xi_1 aus Alg.2.1 + double tau, // i: Parameter tau aus Alg.2.1 + double tau1, // i: Parameter tau_1 aus Alg.2.1 + double tau2, // i: Parameter tau_2 aus Alg.2.1 + int & ifail); // o: 0 bei erfolgreicher Liniensuche + // -1 bei Abbruch wegen Unterschreiten von fmin + // 1 bei Abbruch, aus sonstigen Gr�nden + + + + + /** + Solvers linear programming problem. + + \begin{verbatim} + min c^t x + A x <= b + \end{verbatim} + */ + extern void LinearOptimize (const DenseMatrix & a, const Vector & b, + const Vector & c, Vector & x); + + +#ifdef NONE + + /** + Simple projection iteration. + + find $u = argmin_{v >= 0} 0.5 u A u - f u$ + */ + extern void ApproxProject (const BaseMatrix & a, Vector & u, + const Vector & f, + double tau, int its); + + + /** + CG Algorithm for quadratic programming problem. + See: Dostal ... + + d ... diag(A) ^{-1} + */ + extern void ApproxProjectCG (const BaseMatrix & a, Vector & x, + const Vector & b, const class DiagMatrix & d, + double gamma, int & steps, int & changes); + +#endif + + +} + +#endif + diff --git a/contrib/Netgen/libsrc/stlgeom/Makefile b/contrib/Netgen/libsrc/stlgeom/Makefile new file mode 100644 index 0000000000..007a979cad --- /dev/null +++ b/contrib/Netgen/libsrc/stlgeom/Makefile @@ -0,0 +1,11 @@ +# +# Makefile for geometric library +# +src = stlgeom.cpp stltopology.cpp stlgeomchart.cpp stlgeommesh.cpp meshstlsurface.cpp stlline.cpp stltool.cpp +# +lib = stlgeom +libpath = libsrc/stlgeom +# +# +include ../makefile.inc +# diff --git a/contrib/Netgen/libsrc/stlgeom/meshstlsurface.cpp b/contrib/Netgen/libsrc/stlgeom/meshstlsurface.cpp new file mode 100644 index 0000000000..5af12d7aa9 --- /dev/null +++ b/contrib/Netgen/libsrc/stlgeom/meshstlsurface.cpp @@ -0,0 +1,1130 @@ +#include <mystdlib.h> +#include <myadt.hpp> + +#include <linalg.hpp> +#include <gprim.hpp> + +#include <meshing.hpp> + + +#include "stlgeom.hpp" + + +namespace netgen +{ + +static void STLFindEdges (STLGeometry & geom, + class Mesh & mesh) +{ + int i, j, k; + double h; + + h = mparam.maxh; + + // mark edge points: + int ngp = geom.GetNP(); + + geom.RestrictLocalH(mesh, h); + + PushStatusF("Mesh Lines"); + + ARRAY<STLLine*> meshlines; + ARRAY<Point3d> meshpoints; + + PrintMessage(3,"Mesh Lines"); + + for (i = 1; i <= geom.GetNLines(); i++) + { + meshlines.Append(geom.GetLine(i)->Mesh(geom.GetPoints(), meshpoints, h, mesh)); + SetThreadPercent(100.0 * (double)i/(double)geom.GetNLines()); + } + + geom.meshpoints.SetSize(0); //testing + geom.meshlines.SetSize(0); //testing + for (i = 1; i <= meshpoints.Size(); i++) + { + geom.meshpoints.Append(meshpoints.Get(i)); //testing + + int pim = mesh.AddPoint(meshpoints.Get(i)); + } + //(++++++++++++++testing + for (i = 1; i <= geom.GetNLines(); i++) + { + geom.meshlines.Append(meshlines.Get(i)); + } + //++++++++++++++testing) + + PrintMessage(7,"feed with edges"); + + for (i = 1; i <= meshlines.Size(); i++) + { + STLLine* line = meshlines.Get(i); + (*testout) << "store line " << i << endl; + for (j = 1; j <= line->GetNS(); j++) + { + int p1, p2; + + line->GetSeg(j, p1, p2); + int trig1, trig2, trig1b, trig2b; + + if (p1 == p2) + cout << "Add Segment, p1 == p2 == " << p1 << endl; + + // Test auf geschlossener Rand mit 2 Segmenten + + if ((j == 2) && (line->GetNS() == 2)) + { + int oldp1, oldp2; + line->GetSeg (1, oldp1, oldp2); + if (oldp1 == p2 && oldp2 == p1) + { + PrintMessage(7,"MESSAGE: don't use second segment"); + continue; + } + } + + + //mesh point number + //p1 = geom2meshnum.Get(p1); // for unmeshed lines!!! + //p2 = geom2meshnum.Get(p2); // for unmeshed lines!!! + + //left and right trigs + trig1 = line->GetLeftTrig(j); + trig2 = line->GetRightTrig(j); + trig1b = line->GetLeftTrig(j+1); + trig2b = line->GetRightTrig(j+1); + + (*testout) << "j = " << j << ", p1 = " << p1 << ", p2 = " << p2 << endl; + (*testout) << "segm-trigs: " + << "trig1 = " << trig1 + << ", trig1b = " << trig1b + << ", trig2 = " << trig2 + << ", trig2b = " << trig2b << endl; + + if (trig1 <= 0 || trig2 <= 0 || trig1b <= 0 || trig2b <= 0) + { + cout << "negative trigs, " + << ", trig1 = " << trig1 + << ", trig1b = " << trig1b + << ", trig2 = " << trig2 + << ", trig2b = " << trig2b << endl; + } + /* + (*testout) << " trigs p1: " << trig1 << " - " << trig2 << endl; + (*testout) << " trigs p2: " << trig1b << " - " << trig2b << endl; + (*testout) << " charts p1: " << geom.GetChartNr(trig1) << " - " << geom.GetChartNr(trig2) << endl; + (*testout) << " charts p2: " << geom.GetChartNr(trig1b) << " - " << geom.GetChartNr(trig2b) << endl; + */ + Point3d hp, hp2; + Segment seg; + seg.p1 = p1; + seg.p2 = p2; + seg.si = geom.GetTriangle(trig1).GetFaceNum(); + seg.edgenr = i; + + seg.epgeominfo[0].edgenr = i; + seg.epgeominfo[0].dist = line->GetDist(j); + seg.epgeominfo[1].edgenr = i; + seg.epgeominfo[1].dist = line->GetDist(j+1); + /* + (*testout) << "seg = " + << "edgenr " << seg.epgeominfo[0].edgenr + << " dist " << seg.epgeominfo[0].dist + << " edgenr " << seg.epgeominfo[1].edgenr + << " dist " << seg.epgeominfo[1].dist << endl; + */ + + seg.geominfo[0].trignum = trig1; + seg.geominfo[1].trignum = trig1b; + + /* + geom.SelectChartOfTriangle (trig1); + hp = hp2 = mesh.Point (seg.p1); + seg.geominfo[0].trignum = geom.Project (hp); + + (*testout) << "hp = " << hp2 << ", hp proj = " << hp << ", trignum = " << seg.geominfo[0].trignum << endl; + if (Dist (hp, hp2) > 1e-5 || seg.geominfo[0].trignum == 0) + { + (*testout) << "PROBLEM" << endl; + } + + geom.SelectChartOfTriangle (trig1b); + hp = hp2 = mesh.Point (seg.p2); + seg.geominfo[1].trignum = geom.Project (hp); + + (*testout) << "hp = " << hp2 << ", hp proj = " << hp << ", trignum = " << seg.geominfo[1].trignum << endl; + if (Dist (hp, hp2) > 1e-5 || seg.geominfo[1].trignum == 0) + { + (*testout) << "PROBLEM" << endl; + } + */ + + + if (Dist (mesh.Point(seg.p1), mesh.Point(seg.p2)) < 1e-10) + { + (*testout) << "ERROR: Line segment of length 0" << endl; + (*testout) << "pi1, 2 = " << seg.p1 << ", " << seg.p2 << endl; + (*testout) << "p1, 2 = " << mesh.Point(seg.p1) + << ", " << mesh.Point(seg.p2) << endl; + throw NgException ("Line segment of length 0"); + } + + mesh.AddSegment (seg); + + + Segment seg2; + seg2.p1 = p2; + seg2.p2 = p1; + seg2.si = geom.GetTriangle(trig2).GetFaceNum(); + seg2.edgenr = i; + + seg2.epgeominfo[0].edgenr = i; + seg2.epgeominfo[0].dist = line->GetDist(j+1); + seg2.epgeominfo[1].edgenr = i; + seg2.epgeominfo[1].dist = line->GetDist(j); + /* + (*testout) << "seg = " + << "edgenr " << seg2.epgeominfo[0].edgenr + << " dist " << seg2.epgeominfo[0].dist + << " edgenr " << seg2.epgeominfo[1].edgenr + << " dist " << seg2.epgeominfo[1].dist << endl; + */ + + seg2.geominfo[0].trignum = trig2b; + seg2.geominfo[1].trignum = trig2; + + /* + geom.SelectChartOfTriangle (trig2); + hp = hp2 = mesh.Point (seg.p1); + seg2.geominfo[0].trignum = geom.Project (hp); + + (*testout) << "hp = " << hp2 << ", hp proj = " << hp << ", trignum = " << seg.geominfo[0].trignum << endl; + if (Dist (hp, hp2) > 1e-5 || seg2.geominfo[0].trignum == 0) + { + (*testout) << "Get GeomInfo PROBLEM" << endl; + } + + + geom.SelectChartOfTriangle (trig2b); + hp = hp2 = mesh.Point (seg.p2); + seg2.geominfo[1].trignum = geom.Project (hp); + (*testout) << "hp = " << hp2 << ", hp proj = " << hp << ", trignum = " << seg.geominfo[1].trignum << endl; + if (Dist (hp, hp2) > 1e-5 || seg2.geominfo[1].trignum == 0) + { + (*testout) << "Get GeomInfo PROBLEM" << endl; + } + */ + + mesh.AddSegment (seg2); + + + /* + // should be start triangle and end triangle + int bothtrigs1[2] = { trig1, trig1 }; + meshing.AddBoundaryElement (p1, p2, sizeof (bothtrigs1), &bothtrigs1); + + int bothtrigs2[2] = { trig2, trig2 }; + meshing.AddBoundaryElement (p2, p1, sizeof (bothtrigs2), &bothtrigs2); + */ + } + } + + PopStatus(); +} + + + + +void STLSurfaceMeshing1 (STLGeometry & geom, + class Mesh & mesh, + int retrynr); + +int STLSurfaceMeshing (STLGeometry & geom, + class Mesh & mesh) +{ + int i, j; + PrintFnStart("Do Surface Meshing"); + + geom.PrepareSurfaceMeshing(); + + if (mesh.GetNSeg() == 0) + STLFindEdges (geom, mesh); + + int nopen; + int outercnt = 20; + + // mesh.Save ("mesh.edges"); + + for (i = 1; i <= mesh.GetNSeg(); i++) + { + const Segment & seg = mesh.LineSegment (i); + if (seg.geominfo[0].trignum <= 0 || seg.geominfo[1].trignum <= 0) + { + (*testout) << "Problem with segment " << i << ": " << seg << endl; + } + } + + + do + { + outercnt--; + if (outercnt <= 0) + return MESHING3_OUTERSTEPSEXCEEDED; + + if (multithread.terminate) + { + return MESHING3_TERMINATE; + } + + mesh.FindOpenSegments(); + nopen = mesh.GetNOpenSegments(); + + if (nopen) + { + int trialcnt = 0; + while (nopen && trialcnt <= 5) + { + if (multithread.terminate) + { + return MESHING3_TERMINATE; + } + trialcnt++; + STLSurfaceMeshing1 (geom, mesh, trialcnt); + + mesh.FindOpenSegments(); + nopen = mesh.GetNOpenSegments(); + + if (nopen) + { + geom.ClearMarkedSegs(); + for (i = 1; i <= nopen; i++) + { + const Segment & seg = mesh.GetOpenSegment (i); + geom.AddMarkedSeg(mesh.Point(seg.p1),mesh.Point(seg.p2)); + } + + geom.InitMarkedTrigs(); + for (i = 1; i <= nopen; i++) + { + const Segment & seg = mesh.GetOpenSegment (i); + geom.SetMarkedTrig(seg.geominfo[0].trignum,1); + geom.SetMarkedTrig(seg.geominfo[1].trignum,1); + } + + MeshOptimizeSTLSurface optmesh(geom); + optmesh.SetFaceIndex (0); + optmesh.SetImproveEdges (0); + optmesh.SetMetricWeight (0); + + mesh.CalcSurfacesOfNode(); + optmesh.EdgeSwapping (mesh, 0); + mesh.CalcSurfacesOfNode(); + optmesh.ImproveMesh (mesh); + } + + mesh.Compress(); + mesh.FindOpenSegments(); + nopen = mesh.GetNOpenSegments(); + + if (trialcnt <= 5 && nopen) + { + mesh.RemoveOneLayerSurfaceElements(); + + if (trialcnt >= 4) + { + mesh.FindOpenSegments(); + mesh.RemoveOneLayerSurfaceElements(); + + mesh.FindOpenSegments (); + nopen = mesh.GetNOpenSegments(); + } + } + } + + + if (multithread.terminate) + return MESHING3_TERMINATE; + + if (nopen) + { + + PrintMessage(3,"Meshing failed, trying to refine"); + + mesh.FindOpenSegments (); + nopen = mesh.GetNOpenSegments(); + + mesh.FindOpenSegments (); + mesh.RemoveOneLayerSurfaceElements(); + mesh.FindOpenSegments (); + mesh.RemoveOneLayerSurfaceElements(); + + // Open edge-segments will be refined ! + INDEX_2_HASHTABLE<int> openseght (nopen+1); + for (i = 1; i <= mesh.GetNOpenSegments(); i++) + { + const Segment & seg = mesh.GetOpenSegment (i); + INDEX_2 i2(seg.p1, seg.p2); + i2.Sort(); + openseght.Set (i2, 1); + } + + + mesh.FindOpenSegments (); + mesh.RemoveOneLayerSurfaceElements(); + mesh.FindOpenSegments (); + mesh.RemoveOneLayerSurfaceElements(); + + + INDEX_2_HASHTABLE<int> newpht(100); + + int nsegold = mesh.GetNSeg(); + for (i = 1; i <= nsegold; i++) + { + Segment seg = mesh.LineSegment(i); + INDEX_2 i2(seg.p1, seg.p2); + i2.Sort(); + if (openseght.Used (i2)) + { + // segment will be split + PrintMessage(7,"Split segment ", int(seg.p1), "-", int(seg.p2)); + + Segment nseg1, nseg2; + EdgePointGeomInfo newgi; + + const EdgePointGeomInfo & gi1 = seg.epgeominfo[0]; + const EdgePointGeomInfo & gi2 = seg.epgeominfo[1]; + + newgi.dist = 0.5 * (gi1.dist + gi2.dist); + newgi.edgenr = gi1.edgenr; + + int hi; + + Point3d newp; + int newpi; + + if (!newpht.Used (i2)) + { + newp = geom.GetLine (gi1.edgenr)-> + GetPointInDist (geom.GetPoints(), newgi.dist, hi); + newpi = mesh.AddPoint (newp); + newpht.Set (i2, newpi); + } + else + { + newpi = newpht.Get (i2); + newp = mesh.Point (newpi); + } + + nseg1 = seg; + nseg2 = seg; + nseg1.p2 = newpi; + nseg1.epgeominfo[1] = newgi; + + nseg2.p1 = newpi; + nseg2.epgeominfo[0] = newgi; + + mesh.LineSegment(i) = nseg1; + mesh.AddSegment (nseg2); + + mesh.RestrictLocalH (Center (mesh.Point(nseg1.p1), + mesh.Point(nseg1.p2)), + Dist (mesh.Point(nseg1.p1), + mesh.Point(nseg1.p2))); + mesh.RestrictLocalH (Center (mesh.Point(nseg2.p1), + mesh.Point(nseg2.p2)), + Dist (mesh.Point(nseg2.p1), + mesh.Point(nseg2.p2))); + } + } + + } + + nopen = -1; + } + + else + + { + PrintMessage(5,"mesh is closed, verifying ..."); + + // no open elements, check wrong elemetns (intersecting..) + + + + PrintMessage(5,"check overlapping"); + // mesh.FindOpenElements(); // would leed to locked points + mesh.CheckOverlappingBoundary(); + + geom.InitMarkedTrigs(); + + for (i = 1; i <= mesh.GetNSE(); i++) + if (mesh.SurfaceElement(i).BadElement()) + { + int trig = mesh.SurfaceElement(i).PNum(1); + geom.SetMarkedTrig(trig,1); + PrintMessage(7, "overlapping element, will be removed"); + } + + + + ARRAY<Point3d> refpts; + ARRAY<double> refh; + + // was commented: + + for (i = 1; i <= mesh.GetNSE(); i++) + if (mesh.SurfaceElement(i).BadElement()) + { + for (j = 1; j <= 3; j++) + { + refpts.Append (mesh.Point (mesh.SurfaceElement(i).PNum(j))); + refh.Append (mesh.GetH (refpts.Last()) / 2); + } + mesh.DeleteSurfaceElement(i); + } + + // delete wrong oriented element + for (i = 1; i <= mesh.GetNSE(); i++) + { + const Element2d & el = mesh.SurfaceElement(i); + if (!el.PNum(1)) + continue; + + Vec3d n = Cross (Vec3d (mesh.Point(el.PNum(1)), + mesh.Point(el.PNum(2))), + Vec3d (mesh.Point(el.PNum(1)), + mesh.Point(el.PNum(3)))); + Vec3d ng = geom.GetTriangle(el.GeomInfoPi(1).trignum).Normal(); + if (n * ng < 0) + { + refpts.Append (mesh.Point (mesh.SurfaceElement(i).PNum(1))); + refh.Append (mesh.GetH (refpts.Last()) / 2); + mesh.DeleteSurfaceElement(i); + } + } + // end comments + + for (i = 1; i <= refpts.Size(); i++) + mesh.RestrictLocalH (refpts.Get(i), refh.Get(i)); + + mesh.RemoveOneLayerSurfaceElements(); + + mesh.Compress(); + + mesh.FindOpenSegments (); + nopen = mesh.GetNOpenSegments(); + + /* + if (!nopen) + { + // mesh is still ok + + void STLSurfaceOptimization (STLGeometry & geom, + class Mesh & mesh, + MeshingParameters & mparam) + + } + */ + } + + } + while (nopen); + + mesh.Compress(); + mesh.CalcSurfacesOfNode(); + + return MESHING3_OK; +} + + + + + + +void STLSurfaceMeshing1 (STLGeometry & geom, + class Mesh & mesh, + int retrynr) +{ + int i, j, k; + double h; + + + h = mparam.maxh; + + mesh.FindOpenSegments(); + + ARRAY<int> spiralps(0); + spiralps.SetSize(0); + for (i = 1; i <= geom.GetNP(); i++) + { + if (geom.GetSpiralPoint(i)) {spiralps.Append(i);} + } + + PrintMessage(7,"NO spiralpoints = ", spiralps.Size()); + int spfound; + int sppointnum; + int spcnt = 0; + + ARRAY<int> meshsp(mesh.GetNP()); + for (i = 1; i <= mesh.GetNP(); i++) + { + meshsp.Elem(i) = 0; + for (j = 1; j <= spiralps.Size(); j++) + if (Dist2(geom.GetPoint(spiralps.Get(j)), mesh.Point(i)) < 1e-20) + meshsp.Elem(i) = spiralps.Get(j); + } + + + ARRAY<int> opensegsperface(mesh.GetNFD()); + for (i = 1; i <= mesh.GetNFD(); i++) + opensegsperface.Elem(i) = 0; + for (i = 1; i <= mesh.GetNOpenSegments(); i++) + { + int si = mesh.GetOpenSegment (i).si; + if (si >= 1 && si <= mesh.GetNFD()) + { + opensegsperface.Elem(si)++; + } + else + { + cerr << "illegal face index" << endl; + } + } + + + double starttime = GetTime (); + + for (int fnr = 1; fnr <= mesh.GetNFD(); fnr++) + if (opensegsperface.Get(fnr)) + { + if (multithread.terminate) + return; + + PrintMessage(5,"Meshing surface ", fnr, "/", mesh.GetNFD()); + MeshingSTLSurface meshing (geom); + + meshing.SetStartTime (starttime); + + for (i = 1; i <= mesh.GetNP(); i++) + { + /* + spfound = 0; + for (j = 1; j <= spiralps.Size(); j++) + { + if (Dist2(geom.GetPoint(spiralps.Get(j)),mesh.Point(i)) < 1e-20) + {spfound = 1; sppointnum = spiralps.Get(j);} + } + */ + sppointnum = 0; + if (i <= meshsp.Size()) + sppointnum = meshsp.Get(i); + + //spfound = 0; + if (sppointnum) + { + MultiPointGeomInfo mgi; + + int ntrigs = geom.NOTrigsPerPoint(sppointnum); + spcnt++; + + for (j = 0; j < ntrigs; j++) + { + PointGeomInfo gi; + gi.trignum = geom.TrigPerPoint(sppointnum, j+1); + mgi.AddPointGeomInfo (gi); + } + + // Einfuegen von ConePoint: Point bekommt alle + // Dreiecke (werden dann intern kopiert) + // Ein Segment zum ConePoint muss vorhanden sein !!! + + meshing.AddPoint (mesh.Point(i), i, &mgi); + + } + else + { + meshing.AddPoint (mesh.Point(i), i); + } + } + + + for (i = 1; i <= mesh.GetNOpenSegments(); i++) + { + const Segment & seg = mesh.GetOpenSegment (i); + if (seg.si == fnr) + meshing.AddBoundaryElement (seg.p1, seg.p2, seg.geominfo[0], seg.geominfo[1]); + } + + + PrintMessage(3,"start meshing, trialcnt = ", retrynr); + + /* + (*testout) << "start meshing with h = " << h << endl; + */ + meshing.GenerateMesh (mesh, h, fnr); // face index +#ifdef OPENGL + extern void Render(); + Render(); +#endif + } + + + mesh.CalcSurfacesOfNode(); +} + + + +void STLSurfaceOptimization (STLGeometry & geom, + class Mesh & mesh, + MeshingParameters & mparam) +{ + PrintFnStart("optimize STL Surface"); + + + MeshOptimizeSTLSurface optmesh(geom); + // + + int i, j; + /* + for (i = 1; i <= mparam.optsteps2d; i++) + { + EdgeSwapping (mesh, 1, 1); + CombineImprove (mesh, 1); + optmesh.ImproveMesh (mesh, 0, 10, 1, 1); + } + */ + + optmesh.SetFaceIndex (0); + optmesh.SetImproveEdges (0); + optmesh.SetMetricWeight (mparam.elsizeweight); + + PrintMessage(5,"optimize string = ", mparam.optimize2d, " elsizew = ", mparam.elsizeweight); + + for (i = 1; i <= mparam.optsteps2d; i++) + for (j = 1; j <= strlen(mparam.optimize2d); j++) + { + if (multithread.terminate) + break; + + (*testout) << "optimize, before, step = " << mparam.optimize2d[j-1] << mesh.Point (3679) << endl; + + mesh.CalcSurfacesOfNode(); + switch (mparam.optimize2d[j-1]) + { + case 's': + { + optmesh.EdgeSwapping (mesh, 0); + break; + } + case 'S': + { + optmesh.EdgeSwapping (mesh, 1); + break; + } + case 'm': + { + optmesh.ImproveMesh(mesh); + break; + } + case 'c': + { + optmesh.CombineImprove (mesh); + break; + } + } + (*testout) << "optimize, after, step = " << mparam.optimize2d[j-1] << mesh.Point (3679) << endl; + } + + geom.surfaceoptimized = 1; + + mesh.Compress(); + mesh.CalcSurfacesOfNode(); + + +} + + + +MeshingSTLSurface :: MeshingSTLSurface (STLGeometry & ageom) + : Meshing2(Box3d (ageom.GetBoundingBox().PMin(), + ageom.GetBoundingBox().PMax())), geom(ageom) +{ + ; +} + +void MeshingSTLSurface :: DefineTransformation (Point3d & p1, Point3d & p2, + const PointGeomInfo * geominfo, + const PointGeomInfo * geominfo2) +{ + transformationtrig = geominfo[0].trignum; + + geom.DefineTangentialPlane(p1, p2, transformationtrig); +} + +void MeshingSTLSurface :: TransformToPlain (const Point3d & locpoint, const MultiPointGeomInfo & gi, + Point2d & plainpoint, double h, int & zone) +{ + int trigs[10000]; + int i; + + if (gi.GetNPGI() >= 9999) + { + PrintError("In Transform to plane: increase size of trigs!!!"); + } + + for (i = 1; i <= gi.GetNPGI(); i++) + trigs[i-1] = gi.GetPGI(i).trignum; + trigs[gi.GetNPGI()] = 0; + + // int trig = gi.trignum; + // (*testout) << "locpoint = " << locpoint; + + Point<2> hp2d; + geom.ToPlane (locpoint, trigs, hp2d, h, zone, 1); + plainpoint = hp2d; + + // geom.ToPlane (locpoint, NULL, plainpoint, h, zone, 1); + /* + (*testout) << " plainpoint = " << plainpoint + << " h = " << h + << endl; + */ +} + +/* +int MeshingSTLSurface :: ComputeLineGeoInfo (const Point3d & p1, const Point3d & p2, + int & geoinfosize, void *& geoinfo) +{ + static int geomtrig[2] = { 0, 0 }; + + Point3d hp; + hp = p1; + geomtrig[0] = geom.Project (hp); + + hp = p2; + geomtrig[1] = geom.Project (hp); + + geoinfosize = sizeof (geomtrig); + geoinfo = &geomtrig; + + if (geomtrig[0] == 0) + { + return 1; + } + return 0; +} +*/ + + +int MeshingSTLSurface :: ComputePointGeomInfo (const Point3d & p, PointGeomInfo & gi) +{ + // compute triangle of point, + // if non-unique: 0 + + Point<3> hp = p; + gi.trignum = geom.Project (hp); + + if (!gi.trignum) + { + return 1; + } + + return 0; +} + + +int MeshingSTLSurface :: +ChooseChartPointGeomInfo (const MultiPointGeomInfo & mpgi, + PointGeomInfo & pgi) +{ + int i; + + for (i = 1; i <= mpgi.GetNPGI(); i++) + if (geom.TrigIsInOC (mpgi.GetPGI(i).trignum, geom.meshchart)) + { + pgi = mpgi.GetPGI(i); + return 0; + } + /* + for (i = 0; i < mpgi.cnt; i++) + { + // (*testout) << "d" << endl; + if (geom.TrigIsInOC (mpgi.mgi[i].trignum, geom.meshchart)) + { + pgi = mpgi.mgi[i]; + return 0; + } + } + */ + PrintMessage(7,"INFORM: no gi on chart"); + pgi.trignum = 1; + return 1; +} + + + +int MeshingSTLSurface :: +IsLineVertexOnChart (const Point3d & p1, const Point3d & p2, + int endpoint, const PointGeomInfo & gi) +{ + Vec3d baselinenormal = geom.meshtrignv; + + int lineendtrig = gi.trignum; + + + return geom.TrigIsInOC (lineendtrig, geom.meshchart); + + // Vec3d linenormal = geom.GetTriangleNormal (lineendtrig); + // return ( (baselinenormal * linenormal) > cos (30 * (M_PI/180)) ); +} + +void MeshingSTLSurface :: +GetChartBoundary (ARRAY<Point2d > & points, + ARRAY<Point3d > & points3d, + ARRAY<INDEX_2> & lines, double h) const +{ + points.SetSize (0); + points3d.SetSize (0); + lines.SetSize (0); + geom.GetMeshChartBoundary (points, points3d, lines, h); +} + + + + +int MeshingSTLSurface :: TransformFromPlain (Point2d & plainpoint, + Point3d & locpoint, + PointGeomInfo & gi, + double h) +{ + //return 0, wenn alles OK + Point<3> hp3d; + int res = geom.FromPlane (plainpoint, hp3d, h); + locpoint = hp3d; + ComputePointGeomInfo (locpoint, gi); + return res; +} + + +int MeshingSTLSurface :: +BelongsToActiveChart (const Point3d & p, + const PointGeomInfo & gi) +{ + return (geom.TrigIsInOC(gi.trignum, geom.meshchart) != 0); +} + + + +double MeshingSTLSurface :: CalcLocalH (const Point3d & p, double gh) const +{ + return gh; +} + +double MeshingSTLSurface :: Area () const +{ + return geom.Area(); +} + + + + + + +MeshOptimizeSTLSurface :: MeshOptimizeSTLSurface (STLGeometry & ageom) + : MeshOptimize2d(), geom(ageom) +{ + ; +} + + +void MeshOptimizeSTLSurface :: SelectSurfaceOfPoint (const Point3d & p, + const PointGeomInfo & gi) +{ + // (*testout) << "sel char: " << gi.trignum << endl; + + geom.SelectChartOfTriangle (gi.trignum); + // geom.SelectChartOfPoint (p); +} + + +void MeshOptimizeSTLSurface :: ProjectPoint (INDEX surfind, Point3d & p) const +{ + Point<3> hp = p; + if (!geom.Project (hp)) + { + PrintMessage(7,"project failed"); + + if (!geom.ProjectOnWholeSurface(hp)) + { + PrintMessage(7, "project on whole surface failed"); + } + } + p = hp; + // geometry.GetSurface(surfind)->Project (p); +} + +void MeshOptimizeSTLSurface :: ProjectPoint2 (INDEX surfind, INDEX surfind2, Point3d & p) const +{ + /* + ProjectToEdge ( geometry.GetSurface(surfind), + geometry.GetSurface(surfind2), p); + */ +} + +int MeshOptimizeSTLSurface :: CalcPointGeomInfo(PointGeomInfo& gi, const Point3d& p3) const +{ + Point<3> hp = p3; + gi.trignum = geom.Project (hp); + + if (gi.trignum) + { + return 1; + } + + return 0; + +} + +void MeshOptimizeSTLSurface :: GetNormalVector(INDEX surfind, const Point3d & p, Vec3d & n) const +{ + n = geom.GetChartNormalVector(); + + /* + geometry.GetSurface(surfind)->CalcGradient (p, n); + n /= n.Length(); + if (geometry.GetSurface(surfind)->Inverse()) + n *= -1; + */ +} + + + + + + + + + + +RefinementSTLGeometry :: RefinementSTLGeometry (const STLGeometry & ageom) + : Refinement(), geom(ageom) +{ + ; +} + +RefinementSTLGeometry :: ~RefinementSTLGeometry () +{ + ; +} + +void RefinementSTLGeometry :: +PointBetween (const Point3d & p1, const Point3d & p2, double secpoint, + int surfi, + const PointGeomInfo & gi1, + const PointGeomInfo & gi2, + Point3d & newp, PointGeomInfo & newgi) +{ + newp = p1+secpoint*(p2-p1); + + /* + (*testout) << "surf-between: p1 = " << p1 << ", p2 = " << p2 + << ", gi = " << gi1 << " - " << gi2 << endl; + */ + + if (gi1.trignum > 0) + { + // ((STLGeometry&)geom).SelectChartOfTriangle (gi1.trignum); + + Point<3> np1 = newp; + Point<3> np2 = newp; + ((STLGeometry&)geom).SelectChartOfTriangle (gi1.trignum); + int tn1 = geom.Project (np1); + + ((STLGeometry&)geom).SelectChartOfTriangle (gi2.trignum); + int tn2 = geom.Project (np2); + + newgi.trignum = tn1; //urspruengliche version + newp = np1; //urspruengliche version + + if (!newgi.trignum) + { newgi.trignum = tn2; newp = np2; } + if (!newgi.trignum) newgi.trignum = gi1.trignum; + + /* + if (tn1 != 0 && tn2 != 0 && ((STLGeometry&)geom).GetAngle(tn1,tn2) < M_PI*0.05) { + newgi.trignum = tn1; + newp = np1; + } + else + { + newp = ((STLGeometry&)geom).PointBetween(p1, gi1.trignum, p2, gi2.trignum); + tn1 = ((STLGeometry&)geom).Project(newp); + newgi.trignum = tn1; + + if (!tn1) + { + newp = Center (p1, p2); + newgi.trignum = 0; + + } + } + */ + } + else + { + // (*testout) << "WARNING: PointBetween got geominfo = 0" << endl; + newp = p1+secpoint*(p2-p1); + newgi.trignum = 0; + } + + // (*testout) << "newp = " << newp << ", ngi = " << newgi << endl; +} + +void RefinementSTLGeometry :: +PointBetween (const Point3d & p1, const Point3d & p2, double secpoint, + int surfi1, int surfi2, + const EdgePointGeomInfo & gi1, + const EdgePointGeomInfo & gi2, + Point3d & newp, EdgePointGeomInfo & newgi) +{ + /* + (*testout) << "edge-between: p1 = " << p1 << ", p2 = " << p2 + << ", gi1,2 = " << gi1 << ", " << gi2 << endl; + */ + /* + newp = Center (p1, p2); + ((STLGeometry&)geom).SelectChartOfTriangle (gi1.trignum); + newgi.trignum = geom.Project (newp); + */ + int hi; + newgi.dist = (1.0-secpoint) * gi1.dist + secpoint*gi2.dist; + newgi.edgenr = gi1.edgenr; + + /* + (*testout) << "p1 = " << p1 << ", p2 = " << p2 << endl; + (*testout) << "refedge: " << gi1.edgenr + << " d1 = " << gi1.dist << ", d2 = " << gi2.dist << endl; + */ + newp = geom.GetLine (gi1.edgenr)->GetPointInDist (geom.GetPoints(), newgi.dist, hi); + + // (*testout) << "newp = " << newp << endl; +} + + +void RefinementSTLGeometry :: ProjectToSurface (Point<3> & p, int surfi) +{ + cout << "RefinementSTLGeometry :: ProjectToSurface not implemented!" << endl; +} + + +void RefinementSTLGeometry :: ProjectToSurface (Point<3> & p, int surfi, + PointGeomInfo & gi) +{ + ((STLGeometry&)geom).SelectChartOfTriangle (gi.trignum); + gi.trignum = geom.Project (p); + // if (!gi.trignum) + // cout << "projectSTL failed" << endl; +} + + +} diff --git a/contrib/Netgen/libsrc/stlgeom/meshstlsurface.hpp b/contrib/Netgen/libsrc/stlgeom/meshstlsurface.hpp new file mode 100644 index 0000000000..f190d107a5 --- /dev/null +++ b/contrib/Netgen/libsrc/stlgeom/meshstlsurface.hpp @@ -0,0 +1,121 @@ +#ifndef FILE_MESHSTLSURF +#define FILE_MESHSTLSURF + +/* *************************************************************************/ +/* File: meshstlsurf.hpp */ +/* Author: Johannes Gerstmayr, Joachim Schoeberl */ +/* Date: 01. Aug. 99 */ +/* *************************************************************************/ + +/* + +The interface between mesh generation and stl geometry + +*/ + + +/// +class MeshingSTLSurface : public Meshing2 +{ + /// + STLGeometry & geom; + /// + int transformationtrig; +public: + /// + MeshingSTLSurface (STLGeometry & ageom); + +protected: + /// + virtual void DefineTransformation (Point3d & p1, Point3d & p2, + const PointGeomInfo * geominfo1, + const PointGeomInfo * geominfo2); + /// + virtual void TransformToPlain (const Point3d & locpoint, const MultiPointGeomInfo & geominfo, + Point2d & plainpoint, double h, int & zone); + /// + virtual int TransformFromPlain (Point2d & plainpoint, + Point3d & locpoint, + PointGeomInfo & gi, + double h); + /// + virtual int BelongsToActiveChart (const Point3d & p, + const PointGeomInfo & gi); + + /// + virtual int ComputePointGeomInfo (const Point3d & p, PointGeomInfo & gi); + /// + virtual int ChooseChartPointGeomInfo (const MultiPointGeomInfo & mpgi, + PointGeomInfo & pgi); + + /// + virtual int IsLineVertexOnChart (const Point3d & p1, const Point3d & p2, + int endpoint, const PointGeomInfo & gi); + + virtual void GetChartBoundary (ARRAY<Point2d > & points, + ARRAY<Point3d > & poitns3d, + ARRAY<INDEX_2> & lines, double h) const; + + /// + virtual double CalcLocalH (const Point3d & p, double gh) const; + + /// + virtual double Area () const; +}; + + + +/// +class MeshOptimizeSTLSurface : public MeshOptimize2d + { + /// + STLGeometry & geom; + +public: + /// + MeshOptimizeSTLSurface (STLGeometry & ageom); + + /// + virtual void SelectSurfaceOfPoint (const Point3d & p, + const PointGeomInfo & gi); + /// + virtual void ProjectPoint (INDEX surfind, Point3d & p) const; + /// + virtual void ProjectPoint2 (INDEX surfind, INDEX surfind2, Point3d & p) const; + /// + virtual int CalcPointGeomInfo(PointGeomInfo& gi, const Point3d& p3) const; + /// + virtual void GetNormalVector(INDEX surfind, const Point3d & p, Vec3d & n) const; +}; + + + + +class RefinementSTLGeometry : public Refinement +{ + const STLGeometry & geom; + +public: + RefinementSTLGeometry (const STLGeometry & ageom); + virtual ~RefinementSTLGeometry (); + + virtual void PointBetween (const Point3d & p1, const Point3d & p2, double secpoint, + int surfi, + const PointGeomInfo & gi1, + const PointGeomInfo & gi2, + Point3d & newp, PointGeomInfo & newgi); + + virtual void PointBetween (const Point3d & p1, const Point3d & p2, double secpoint, + int surfi1, int surfi2, + const EdgePointGeomInfo & ap1, + const EdgePointGeomInfo & ap2, + Point3d & newp, EdgePointGeomInfo & newgi); + + virtual void ProjectToSurface (Point<3> & p, int surfi); + virtual void ProjectToSurface (Point<3> & p, int surfi, PointGeomInfo & gi); +}; + + + +#endif + diff --git a/contrib/Netgen/libsrc/stlgeom/stlgeom.cpp b/contrib/Netgen/libsrc/stlgeom/stlgeom.cpp new file mode 100644 index 0000000000..2d3a358cfa --- /dev/null +++ b/contrib/Netgen/libsrc/stlgeom/stlgeom.cpp @@ -0,0 +1,3476 @@ +#include <mystdlib.h> + +#include <myadt.hpp> +#include <linalg.hpp> +#include <gprim.hpp> + +#include <meshing.hpp> + +#include "stlgeom.hpp" + + +namespace netgen +{ + +//globalen searchtree fuer gesamte geometry aktivieren +int geomsearchtreeon = 0; + +int usechartnormal = 1; + +//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +void STLMeshing (STLGeometry & geom, + Mesh & mesh) +{ + geom.Clear(); + geom.BuildEdges(); + geom.MakeAtlas(mesh); + geom.CalcFaceNums(); + geom.AddFaceEdges(); + geom.LinkEdges(); + + 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(), edgedata(*this), selectedmultiedge() +{ + externaledges.SetSize(0); + Clear(); + meshchart = 0; // initialize all ?? JS + + if (geomsearchtreeon) + searchtree = new Box3dTree (GetBoundingBox().PMin() - Vec3d(1,1,1), + GetBoundingBox().PMax() + Vec3d(1,1,1)); + else + searchtree = NULL; + + status = STL_GOOD; + statustext = "Good Geometry"; + smoothedges = NULL; +} + +STLGeometry :: ~STLGeometry() +{ + ; +} + +void STLGeometry :: STLInfo(double* data) +{ + data[0] = GetNT(); + + Box<3> b = GetBoundingBox(); + data[1] = b.PMin()(0); + data[2] = b.PMax()(0); + data[3] = b.PMin()(1); + data[4] = b.PMax()(1); + data[5] = b.PMin()(2); + data[6] = b.PMax()(2); + + int i; + + int cons = 1; + for (i = 1; i <= GetNT(); i++) + { + if (NONeighbourTrigs(i) != 3) {cons = 0;} + } + data[7] = cons; +} + +void STLGeometry :: MarkNonSmoothNormals() +{ + + PrintFnStart("Mark Non-Smooth Normals"); + + int i,j; + + markedtrigs.SetSize(GetNT()); + + for (i = 1; i <= GetNT(); i++) + { + SetMarkedTrig(i, 0); + } + + double dirtyangle = stlparam.yangle/180.*M_PI; + + int cnt = 0; + int p1,p2; + for (i = 1; i <= GetNT(); i++) + { + for (j = 1; j <= NONeighbourTrigs(i); j++) + { + if (GetAngle(i, NeighbourTrig(i,j)) > dirtyangle) + { + GetTriangle(i).GetNeighbourPoints(GetTriangle(NeighbourTrig(i,j)), p1, p2); + if (!IsEdge(p1,p2)) + { + if (!IsMarkedTrig(i)) {SetMarkedTrig(i,1); cnt++;} + } + } + } + } + + PrintMessage(5,"marked ",cnt," non-smooth trig-normals"); + +} + +void STLGeometry :: SmoothNormals() +{ + multithread.terminate = 0; + + // UseExternalEdges(); + + BuildEdges(); + + + DenseMatrix m(3), hm(3); + Vector rhs(3), sol(3), hv(3), hv2(3); + + Vec<3> ri; + + double wnb = stldoctor.smoothnormalsweight; // neigbour normal weight + double wgeom = 1-wnb; // geometry normal weight + + + // minimize + // wgeom sum_T \sum ri \| ri^T (n - n_geom) \|^2 + // + wnb sum_SE \| ri x (n - n_nb) \|^2 + + int i, j, k, l; + int nt = GetNT(); + + PushStatusF("Smooth Normals"); + + int testmode; + + for (i = 1; i <= nt; i++) + { + + SetThreadPercent( 100.0 * (double)i / (double)nt); + + const STLTriangle & trig = GetTriangle (i); + + m = 0; + rhs = 0; + + // normal of geometry: + Vec<3> ngeom = trig.GeomNormal(points); + ngeom.Normalize(); + + for (j = 1; j <= 3; j++) + { + int pi1 = trig.PNumMod (j); + int pi2 = trig.PNumMod (j+1); + + // edge vector + ri = GetPoint (pi2) - GetPoint (pi1); + + for (k = 0; k < 3; k++) + for (l = 0; l < 3; l++) + hm.Elem(k+1, l+1) = wgeom * ri(k) * ri(l); + + + for (k = 0; k < 3; k++) + hv.Elem(k+1) = ngeom(k); + + hm.Mult (hv, hv2); + /* + if (testmode) + (*testout) << "add vec " << hv2 << endl + << " add m " << hm << endl; + */ + rhs.Add (1, hv2); + m += hm; + + + int nbt = 0; + int fp1,fp2; + for (k = 1; k <= NONeighbourTrigs(i); k++) + { + trig.GetNeighbourPoints(GetTriangle(NeighbourTrig(i, k)),fp1,fp2); + if (fp1 == pi1 && fp2 == pi2) + { + nbt = NeighbourTrig(i, k); + } + } + + if (!nbt) + { + cerr << "ERROR: stlgeom::Smoothnormals, nbt = 0" << endl; + } + + // smoothed normal + Vec<3> nnb = GetTriangle(nbt).Normal(); // neighbour normal + nnb.Normalize(); + + if (!IsEdge(pi1,pi2)) + { + double lr2 = ri * ri; + for (k = 0; k < 3; k++) + { + for (l = 0; l < k; l++) + { + hm.Elem(k+1, l+1) = -wnb * ri(k) * ri(l); + hm.Elem(l+1, k+1) = -wnb * ri(k) * ri(l); + } + + hm.Elem(k+1, k+1) = wnb * (lr2 - ri(k) * ri(k)); + } + + for (k = 0; k < 3; k++) + hv.Elem(k+1) = nnb(k); + + hm.Mult (hv, hv2); + /* + if (testmode) + (*testout) << "add nb vec " << hv2 << endl + << " add nb m " << hm << endl; + */ + + rhs.Add (1, hv2); + m += hm; + } + } + + m.Solve (rhs, sol); + Vec3d newn(sol.Get(1), sol.Get(2), sol.Get(3)); + newn /= (newn.Length() + 1e-24); + + GetTriangle(i).SetNormal(newn); + // setnormal (sol); + } + + /* + for (i = 1; i <= nt; i++) + SetMarkedTrig(i, 0); + + + + int crloop; + for (crloop = 1; crloop <= 3; crloop++) + { + + // find critical: + + ARRAY<INDEX_2> critpairs; + for (i = 1; i <= nt; i++) + { + const STLTriangle & trig = GetTriangle (i); + + Vec3d ngeom = GetTriangleNormal (i); // trig.Normal(points); + ngeom /= (ngeom.Length() + 1e-24); + + for (j = 1; j <= 3; j++) + { + int pi1 = trig.PNumMod (j); + int pi2 = trig.PNumMod (j+1); + + int nbt = 0; + int fp1,fp2; + for (k = 1; k <= NONeighbourTrigs(i); k++) + { + trig.GetNeighbourPoints(GetTriangle(NeighbourTrig(i, k)),fp1,fp2); + if (fp1 == pi1 && fp2 == pi2) + { + nbt = NeighbourTrig(i, k); + } + } + + if (!nbt) + { + cerr << "ERROR: stlgeom::Smoothnormals, nbt = 0" << endl; + } + + Vec3d nnb = GetTriangleNormal(nbt); // neighbour normal + nnb /= (nnb.Length() + 1e-24); + + if (!IsEdge(pi1,pi2)) + { + if (Angle (nnb, ngeom) > 150 * M_PI/180) + { + SetMarkedTrig(i, 1); + SetMarkedTrig(nbt, 1); + critpairs.Append (INDEX_2 (i, nbt)); + } + } + + } + } + + if (!critpairs.Size()) + { + break; + } + + if (critpairs.Size()) + { + + ARRAY<int> friends; + double area1 = 0, area2 = 0; + + for (i = 1; i <= critpairs.Size(); i++) + { + int tnr1 = critpairs.Get(i).I1(); + int tnr2 = critpairs.Get(i).I2(); + (*testout) << "t1 = " << tnr1 << ", t2 = " << tnr2 + << " angle = " << Angle (GetTriangleNormal (tnr1), + GetTriangleNormal (tnr2)) + << endl; + + // who has more friends ? + int side; + area1 = 0; + area2 = 0; + for (side = 1; side <= 2; side++) + { + friends.SetSize (0); + friends.Append ( (side == 1) ? tnr1 : tnr2); + + for (j = 1; j <= 3; j++) + { + int fsize = friends.Size(); + for (k = 1; k <= fsize; k++) + { + int testtnr = friends.Get(k); + Vec3d ntt = GetTriangleNormal(testtnr); + ntt /= (ntt.Length() + 1e-24); + + for (l = 1; l <= NONeighbourTrigs(testtnr); l++) + { + int testnbnr = NeighbourTrig(testtnr, l); + Vec3d nbt = GetTriangleNormal(testnbnr); + nbt /= (nbt.Length() + 1e-24); + + if (Angle (nbt, ntt) < 15 * M_PI/180) + { + int ii; + int found = 0; + for (ii = 1; ii <= friends.Size(); ii++) + { + if (friends.Get(ii) == testnbnr) + { + found = 1; + break; + } + } + if (!found) + friends.Append (testnbnr); + } + } + } + } + + // compute area: + for (k = 1; k <= friends.Size(); k++) + { + double area = + GetTriangle (friends.Get(k)).Area(points); + + if (side == 1) + area1 += area; + else + area2 += area; + } + + } + + (*testout) << "area1 = " << area1 << " area2 = " << area2 << endl; + if (area1 < 0.1 * area2) + { + Vec3d n = GetTriangleNormal (tnr1); + n *= -1; + SetTriangleNormal(tnr1, n); + } + if (area2 < 0.1 * area1) + { + Vec3d n = GetTriangleNormal (tnr2); + n *= -1; + SetTriangleNormal(tnr2, n); + } + } + } + } + */ + + calcedgedataanglesnew = 1; + PopStatus(); +} + + +int STLGeometry :: AddEdge(int p1, int p2) +{ + STLEdge e(p1,p2); + e.SetLeftTrig(GetLeftTrig(p1,p2)); + e.SetRightTrig(GetRightTrig(p1,p2)); + return edges.Append(e); +} + +void STLGeometry :: STLDoctorConfirmEdge() +{ + StoreEdgeData(); + if (GetSelectTrig() >= 1 && GetSelectTrig() <= GetNT() && GetNodeOfSelTrig()) + { + if (stldoctor.selectmode == 1) + { + int p1 = GetTriangle(GetSelectTrig()).PNum(GetNodeOfSelTrig()); + int p2 = GetTriangle(GetSelectTrig()).PNumMod(GetNodeOfSelTrig()+1); + edgedata.Elem(edgedata.GetEdgeNum(p1,p2)).SetStatus (ED_CONFIRMED); + } + else if (stldoctor.selectmode == 3 || stldoctor.selectmode == 4) + { + int i; + for (i = 1; i <= selectedmultiedge.Size(); i++) + { + int p1 = selectedmultiedge.Get(i).i1; + int p2 = selectedmultiedge.Get(i).i2; + edgedata.Elem(edgedata.GetEdgeNum(p1,p2)).SetStatus (ED_CONFIRMED); + } + } + } +} + +void STLGeometry :: STLDoctorCandidateEdge() +{ + StoreEdgeData(); + if (GetSelectTrig() >= 1 && GetSelectTrig() <= GetNT() && GetNodeOfSelTrig()) + { + if (stldoctor.selectmode == 1) + { + int p1 = GetTriangle(GetSelectTrig()).PNum(GetNodeOfSelTrig()); + int p2 = GetTriangle(GetSelectTrig()).PNumMod(GetNodeOfSelTrig()+1); + edgedata.Elem(edgedata.GetEdgeNum(p1,p2)).SetStatus (ED_CANDIDATE); + } + else if (stldoctor.selectmode == 3 || stldoctor.selectmode == 4) + { + int i; + for (i = 1; i <= selectedmultiedge.Size(); i++) + { + int p1 = selectedmultiedge.Get(i).i1; + int p2 = selectedmultiedge.Get(i).i2; + edgedata.Elem(edgedata.GetEdgeNum(p1,p2)).SetStatus (ED_CANDIDATE); + } + } + } +} + +void STLGeometry :: STLDoctorExcludeEdge() +{ + StoreEdgeData(); + if (GetSelectTrig() >= 1 && GetSelectTrig() <= GetNT() && GetNodeOfSelTrig()) + { + if (stldoctor.selectmode == 1) + { + int p1 = GetTriangle(GetSelectTrig()).PNum(GetNodeOfSelTrig()); + int p2 = GetTriangle(GetSelectTrig()).PNumMod(GetNodeOfSelTrig()+1); + edgedata.Elem(edgedata.GetEdgeNum(p1,p2)).SetStatus(ED_EXCLUDED); + } + else if (stldoctor.selectmode == 3 || stldoctor.selectmode == 4) + { + int i; + for (i = 1; i <= selectedmultiedge.Size(); i++) + { + int p1 = selectedmultiedge.Get(i).i1; + int p2 = selectedmultiedge.Get(i).i2; + edgedata.Elem(edgedata.GetEdgeNum(p1,p2)).SetStatus(ED_EXCLUDED); + } + } + } +} + +void STLGeometry :: STLDoctorUndefinedEdge() +{ + StoreEdgeData(); + if (GetSelectTrig() >= 1 && GetSelectTrig() <= GetNT() && GetNodeOfSelTrig()) + { + if (stldoctor.selectmode == 1) + { + int p1 = GetTriangle(GetSelectTrig()).PNum(GetNodeOfSelTrig()); + int p2 = GetTriangle(GetSelectTrig()).PNumMod(GetNodeOfSelTrig()+1); + edgedata.Elem(edgedata.GetEdgeNum(p1,p2)).SetStatus(ED_UNDEFINED); + } + else if (stldoctor.selectmode == 3 || stldoctor.selectmode == 4) + { + int i; + for (i = 1; i <= selectedmultiedge.Size(); i++) + { + int p1 = selectedmultiedge.Get(i).i1; + int p2 = selectedmultiedge.Get(i).i2; + edgedata.Elem(edgedata.GetEdgeNum(p1,p2)).SetStatus(ED_UNDEFINED); + } + } + } +} + +void STLGeometry :: STLDoctorSetAllUndefinedEdges() +{ + edgedata.ResetAll(); +} + +void STLGeometry :: STLDoctorEraseCandidateEdges() +{ + StoreEdgeData(); + edgedata.ChangeStatus(ED_CANDIDATE, ED_UNDEFINED); +} + +void STLGeometry :: STLDoctorConfirmCandidateEdges() +{ + StoreEdgeData(); + edgedata.ChangeStatus(ED_CANDIDATE, ED_CONFIRMED); +} + +void STLGeometry :: STLDoctorConfirmedToCandidateEdges() +{ + StoreEdgeData(); + edgedata.ChangeStatus(ED_CONFIRMED, ED_CANDIDATE); +} + +void STLGeometry :: STLDoctorDirtyEdgesToCandidates() +{ + StoreEdgeData(); +} + +void STLGeometry :: STLDoctorLongLinesToCandidates() +{ + StoreEdgeData(); +} + +twoint STLGeometry :: GetNearestSelectedDefinedEdge() +{ + Point<3> pestimate = Center(GetTriangle(GetSelectTrig()).center, + GetPoint(GetTriangle(GetSelectTrig()).PNum(GetNodeOfSelTrig()))); + //Point3d pestimate = GetTriangle(GetSelectTrig()).center; + + int i, j, en; + ARRAY<int> vic; + GetVicinity(GetSelectTrig(),4,vic); + + + twoint fedg; + fedg.i1 = 0; + fedg.i2 = 0; + double mindist = 1E50; + double dist; + Point<3> p; + + for (i = 1; i <= vic.Size(); i++) + { + const STLTriangle& t = GetTriangle(vic.Get(i)); + for (j = 1; j <= 3; j++) + { + en = edgedata.GetEdgeNum(t.PNum(j),t.PNumMod(j+1)); + if (edgedata.Get(en).GetStatus() != ED_UNDEFINED) + { + p = pestimate; + dist = GetDistFromLine(GetPoint(t.PNum(j)),GetPoint(t.PNumMod(j+1)),p); + if (dist < mindist) + { + mindist = dist; + fedg.i1 = t.PNum(j); + fedg.i2 = t.PNumMod(j+1); + } + } + } + } + return fedg; +} + +void STLGeometry :: BuildSelectedMultiEdge(twoint ep) +{ + if (edgedata.Size() == 0 || + !GetEPPSize()) + { + return; + } + + selectedmultiedge.SetSize(0); + int tenum = GetTopEdgeNum (ep.i1, ep.i2); + + if (edgedata.Get(tenum).GetStatus() == ED_UNDEFINED) + { + twoint epnew = GetNearestSelectedDefinedEdge(); + if (epnew.i1) + { + ep = epnew; + tenum = GetTopEdgeNum (ep.i1, ep.i2); + } + } + + selectedmultiedge.Append(twoint(ep)); + + if (edgedata.Get(tenum).GetStatus() == ED_UNDEFINED) + { + return; + } + + edgedata.BuildLineWithEdge(ep.i1,ep.i2,selectedmultiedge); +} + +void STLGeometry :: BuildSelectedEdge(twoint ep) +{ + if (edgedata.Size() == 0 || + !GetEPPSize()) + { + return; + } + + selectedmultiedge.SetSize(0); + + selectedmultiedge.Append(twoint(ep)); +} + +void STLGeometry :: BuildSelectedCluster(twoint ep) +{ + if (edgedata.Size() == 0 || + !GetEPPSize()) + { + return; + } + + selectedmultiedge.SetSize(0); + + int tenum = GetTopEdgeNum (ep.i1, ep.i2); + + if (edgedata.Get(tenum).GetStatus() == ED_UNDEFINED) + { + twoint epnew = GetNearestSelectedDefinedEdge(); + if (epnew.i1) + { + ep = epnew; + tenum = GetTopEdgeNum (ep.i1, ep.i2); + } + } + + selectedmultiedge.Append(twoint(ep)); + + if (edgedata.Get(tenum).GetStatus() == ED_UNDEFINED) + { + return; + } + + edgedata.BuildClusterWithEdge(ep.i1,ep.i2,selectedmultiedge); +} + +void STLGeometry :: ImportEdges() +{ + StoreEdgeData(); + + PrintMessage(5, "import edges from file 'edges.ng'"); + ifstream fin("edges.ng"); + + int ne; + fin >> ne; + + ARRAY<Point<3> > eps; + + int i; + Point<3> p; + for (i = 1; i <= 2*ne; i++) + { + fin >> p(0); + fin >> p(1); + fin >> p(2); + eps.Append(p); + } + AddEdges(eps); +} + +void STLGeometry :: AddEdges(const ARRAY<Point<3> >& eps) +{ + int i; + int ne = eps.Size()/2; + + ARRAY<int> epsi; + Box<3> bb = GetBoundingBox(); + bb.Increase(1); + + Point3dTree pointtree (bb.PMin(), + bb.PMax()); + ARRAY<int> pintersect; + + double gtol = GetBoundingBox().Diam()/1.E10; + Point<3> p; + + for (i = 1; i <= GetNP(); i++) + { + p = GetPoint(i); + pointtree.Insert (p, i); + } + + int error = 0; + for (i = 1; i <= 2*ne; i++) + { + p = eps.Get(i); + Point3d pmin = p - Vec3d (gtol, gtol, gtol); + Point3d pmax = p + Vec3d (gtol, gtol, gtol); + + pointtree.GetIntersecting (pmin, pmax, pintersect); + if (pintersect.Size() > 1) + { + PrintError("Found too much points in epsilon-dist"); + error = 1; + } + else if (pintersect.Size() == 0) + { + error = 1; + PrintError("edgepoint does not exist!"); + PrintMessage(5,"p=",Point3d(eps.Get(i))); + } + else + { + epsi.Append(pintersect.Get(1)); + } + } + + if (error) return; + + int en; + for (i = 1; i <= ne; i++) + { + if (epsi.Get(2*i-1) == epsi.Get(2*i)) {PrintError("Edge with zero length!");} + else + { + en = edgedata.GetEdgeNum(epsi.Get(2*i-1),epsi.Get(2*i)); + edgedata.Elem(en).SetStatus (ED_CONFIRMED); + } + } + +} + + + +void STLGeometry :: ImportExternalEdges(const char * filename) +{ + //AVL edges!!!!!! + + ifstream inf (filename); + char ch; + int cnt = 0; + int records, units, i, j; + PrintFnStart("Import edges from ",filename); + + const int flen=30; + char filter[flen+1]; + filter[flen] = 0; + char buf[20]; + + ARRAY<Point3d> importpoints; + ARRAY<int> importlines; + ARRAY<int> importpnums; + + while (inf.good()) + { + inf.get(ch); + // (*testout) << cnt << ": " << ch << endl; + + for (i = 0; i < flen; i++) + filter[i] = filter[i+1]; + filter[flen-1] = ch; + // (*testout) << filter << endl; + + if (strcmp (filter+flen-7, "RECORDS") == 0) + { + inf.get(ch); // '=' + inf >> records; + } + if (strcmp (filter+flen-5, "UNITS") == 0) + { + inf.get(ch); // '=' + inf >> units; + } + + if (strcmp (filter+flen-17, "EDGE NODE NUMBERS") == 0) + { + int nodenr; + importlines.SetSize (units); + for (i = 1; i <= units; i++) + { + inf >> nodenr; + importlines.Elem(i) = nodenr; + // (*testout) << nodenr << endl; + } + } + + if (strcmp (filter+flen-23, "EDGE POINT COORD IN DIR") == 0) + { + int coord; + + inf >> coord; + + importpoints.SetSize (units); + + inf >> ch; + inf.putback (ch); + + int nodenr; + for (i = 1; i <= units; i++) + { + for (j = 0; j < 12; j++) + inf.get (buf[j]); + buf[12] = 0; + + importpoints.Elem(i).X(coord) = 1000 * atof (buf); + } + } + } + + /* + (*testout) << "lines: " << endl; + for (i = 1; i <= importlines.Size(); i++) + (*testout) << importlines.Get(i) << endl; + (*testout) << "points: " << endl; + for (i = 1; i <= importpoints.Size(); i++) + (*testout) << importpoints.Get(i) << endl; + */ + + + + importpnums.SetSize (importpoints.Size()); + + + Box3d bb (GetBoundingBox().PMin() + Vec3d (-1,-1,-1), + GetBoundingBox().PMax() + Vec3d (1, 1, 1)); + + Point3dTree pointtree (bb.PMin(), + bb.PMax()); + + + PrintMessage(7,"stl - bb: ",bb.PMin(), " - ", bb.PMax()); + + Box3d ebb; + ebb.SetPoint (importpoints.Get(1)); + for (i = 1; i <= importpoints.Size(); i++) + ebb.AddPoint (importpoints.Get(i)); + PrintMessage(7,"edgep - bb: ", ebb.PMin(), " - ", ebb.PMax()); + + ARRAY<int> pintersect; + + double gtol = GetBoundingBox().Diam()/1.E6; + + for (i = 1; i <= GetNP(); i++) + { + Point3d p = GetPoint(i); + // (*testout) << "stlpt: " << p << endl; + pointtree.Insert (p, i); + } + + + for (i = 1; i <= importpoints.Size(); i++) + { + Point3d p = importpoints.Get(i); + Point3d pmin = p - Vec3d (gtol, gtol, gtol); + Point3d pmax = p + Vec3d (gtol, gtol, gtol); + + pointtree.GetIntersecting (pmin, pmax, pintersect); + if (pintersect.Size() > 1) + { + importpnums.Elem(i) = 0; + PrintError("Found too many points in epsilon-dist"); + } + else if (pintersect.Size() == 0) + { + importpnums.Elem(i) = 0; + PrintError("Edgepoint does not exist!"); + } + else + { + importpnums.Elem(i) = pintersect.Get(1); + } + } + + // if (!error) + { + PrintMessage(7,"found all edge points in stl file"); + + + StoreEdgeData(); + + int oldp = 0; + + for (i = 1; i <= importlines.Size(); i++) + { + int newp = importlines.Get(i); + if (!importpnums.Get(abs(newp))) + newp = 0; + + if (oldp && newp) + { + int en = edgedata.GetEdgeNum(importpnums.Get(oldp), + importpnums.Get(abs(newp))); + edgedata.Elem(en).SetStatus (ED_CONFIRMED); + } + + if (newp < 0) + oldp = 0; + else + oldp = newp; + } + } + + +} + + + +void STLGeometry :: ExportEdges() +{ + PrintFnStart("Save edges to file 'edges.ng'"); + + ofstream fout("edges.ng"); + fout.precision(16); + + int n = edgedata.GetNConfEdges(); + + fout << n << endl; + + int i; + for (i = 1; i <= edgedata.Size(); i++) + { + if (edgedata.Get(i).GetStatus() == ED_CONFIRMED) + { + const STLTopEdge & e = edgedata.Get(i); + fout << GetPoint(e.PNum(1))(0) << " " << GetPoint(e.PNum(1))(1) << " " << GetPoint(e.PNum(1))(2) << endl; + fout << GetPoint(e.PNum(2))(0) << " " << GetPoint(e.PNum(2))(1) << " " << GetPoint(e.PNum(2))(2) << endl; + } + } + +} + +void STLGeometry :: LoadEdgeData(const char* file) +{ + StoreEdgeData(); + + PrintFnStart("Load edges from file '", file, "'"); + ifstream fin(file); + + edgedata.Read(fin); + + // calcedgedataanglesnew = 1; +} + +void STLGeometry :: SaveEdgeData(const char* file) +{ + PrintFnStart("save edges to file '", file, "'"); + ofstream fout(file); + + edgedata.Write(fout); +} + + + + + + + +/* +void STLGeometry :: SaveExternalEdges() +{ + ofstream fout("externaledgesp3.ng"); + fout.precision(16); + + int n = NOExternalEdges(); + fout << n << endl; + + int i; + for (i = 1; i <= n; i++) + { + twoint e = GetExternalEdge(i); + fout << GetPoint(e.i1)(0) << " " << GetPoint(e.i1)(1) << " " << GetPoint(e.i1)(2) << endl; + fout << GetPoint(e.i2)(0) << " " << GetPoint(e.i2)(1) << " " << GetPoint(e.i2)(2) << endl; + } + +} +*/ +void STLGeometry :: StoreExternalEdges() +{ + storedexternaledges.SetSize(0); + undoexternaledges = 1; + int i; + for (i = 1; i <= externaledges.Size(); i++) + { + storedexternaledges.Append(externaledges.Get(i)); + } + +} + +void STLGeometry :: UndoExternalEdges() +{ + if (!undoexternaledges) + { + PrintMessage(1, "undo not further possible!"); + return; + } + RestoreExternalEdges(); + undoexternaledges = 0; +} + +void STLGeometry :: RestoreExternalEdges() +{ + externaledges.SetSize(0); + int i; + for (i = 1; i <= storedexternaledges.Size(); i++) + { + externaledges.Append(storedexternaledges.Get(i)); + } + +} + + +void STLGeometry :: AddExternalEdgeAtSelected() +{ + StoreExternalEdges(); + if (GetSelectTrig() >= 1 && GetSelectTrig() <= GetNT()) + { + int p1 = GetTriangle(GetSelectTrig()).PNum(GetNodeOfSelTrig()); + int p2 = GetTriangle(GetSelectTrig()).PNumMod(GetNodeOfSelTrig()+1); + if (!IsExternalEdge(p1,p2)) {AddExternalEdge(p1,p2);} + } +} + +void STLGeometry :: AddClosedLinesToExternalEdges() +{ + StoreExternalEdges(); + + int i, j; + for (i = 1; i <= GetNLines(); i++) + { + STLLine* l = GetLine(i); + if (l->StartP() == l->EndP()) + { + for (j = 1; j < l->NP(); j++) + { + int p1 = l->PNum(j); + int p2 = l->PNum(j+1); + + if (!IsExternalEdge(p1,p2)) {AddExternalEdge(p1,p2);} + } + } + } +} + +void STLGeometry :: AddLongLinesToExternalEdges() +{ + StoreExternalEdges(); + + double diamfact = stldoctor.dirtytrigfact; + double diam = GetBoundingBox().Diam(); + + int i, j; + for (i = 1; i <= GetNLines(); i++) + { + STLLine* l = GetLine(i); + if (l->GetLength(points) >= diamfact*diam) + { + for (j = 1; j < l->NP(); j++) + { + int p1 = l->PNum(j); + int p2 = l->PNum(j+1); + + if (!IsExternalEdge(p1,p2)) {AddExternalEdge(p1,p2);} + } + } + } +} + +void STLGeometry :: AddAllNotSingleLinesToExternalEdges() +{ + StoreExternalEdges(); + + int i, j; + for (i = 1; i <= GetNLines(); i++) + { + STLLine* l = GetLine(i); + if (GetNEPP(l->StartP()) > 1 || GetNEPP(l->EndP()) > 1) + { + for (j = 1; j < l->NP(); j++) + { + int p1 = l->PNum(j); + int p2 = l->PNum(j+1); + + if (!IsExternalEdge(p1,p2)) {AddExternalEdge(p1,p2);} + } + } + } +} + +void STLGeometry :: DeleteDirtyExternalEdges() +{ + //delete single triangle edges and single edge-lines in clusters" + StoreExternalEdges(); + + int i, j; + for (i = 1; i <= GetNLines(); i++) + { + STLLine* l = GetLine(i); + if (l->NP() <= 3 || (l->StartP() == l->EndP() && l->NP() == 4)) + { + for (j = 1; j < l->NP(); j++) + { + int p1 = l->PNum(j); + int p2 = l->PNum(j+1); + + if (IsExternalEdge(p1,p2)) {DeleteExternalEdge(p1,p2);} + } + } + } +} + +void STLGeometry :: AddExternalEdgesFromGeomLine() +{ + StoreExternalEdges(); + if (GetSelectTrig() >= 1 && GetSelectTrig() <= GetNT()) + { + int p1 = GetTriangle(GetSelectTrig()).PNum(GetNodeOfSelTrig()); + int p2 = GetTriangle(GetSelectTrig()).PNumMod(GetNodeOfSelTrig()+1); + + if (IsEdge(p1,p2)) + { + int edgenum = IsEdgeNum(p1,p2); + if (!IsExternalEdge(p1,p2)) {AddExternalEdge(p1,p2);} + + int noend = 1; + int startp = p1; + int laste = edgenum; + int np1, np2; + while (noend) + { + if (GetNEPP(startp) == 2) + { + if (GetEdgePP(startp,1) != laste) {laste = GetEdgePP(startp,1);} + else {laste = GetEdgePP(startp,2);} + np1 = GetEdge(laste).PNum(1); + np2 = GetEdge(laste).PNum(2); + + if (!IsExternalEdge(np1, np2)) {AddExternalEdge(np1, np2);} + else {noend = 0;} + if (np1 != startp) {startp = np1;} + else {startp = np2;} + } + else {noend = 0;} + } + + startp = p2; + laste = edgenum; + noend = 1; + while (noend) + { + if (GetNEPP(startp) == 2) + { + if (GetEdgePP(startp,1) != laste) {laste = GetEdgePP(startp,1);} + else {laste = GetEdgePP(startp,2);} + np1 = GetEdge(laste).PNum(1); + np2 = GetEdge(laste).PNum(2); + + if (!IsExternalEdge(np1, np2)) {AddExternalEdge(np1, np2);} + else {noend = 0;} + if (np1 != startp) {startp = np1;} + else {startp = np2;} + } + else {noend = 0;} + } + + } + + } + +} + +void STLGeometry :: ClearEdges() +{ + edgesfound = 0; + edges.SetSize(0); + //edgedata.SetSize(0); + // externaledges.SetSize(0); + edgesperpoint.SetSize(0); + undoexternaledges = 0; + +} + +void STLGeometry :: STLDoctorBuildEdges() +{ + // if (!trigsconverted) {return;} + ClearEdges(); + + meshlines.SetSize(0); + FindEdgesFromAngles(); +} + +void STLGeometry :: DeleteExternalEdgeAtSelected() +{ + StoreExternalEdges(); + if (GetSelectTrig() >= 1 && GetSelectTrig() <= GetNT()) + { + int p1 = GetTriangle(GetSelectTrig()).PNum(GetNodeOfSelTrig()); + int p2 = GetTriangle(GetSelectTrig()).PNumMod(GetNodeOfSelTrig()+1); + if (IsExternalEdge(p1,p2)) {DeleteExternalEdge(p1,p2);} + } +} + +void STLGeometry :: DeleteExternalEdgeInVicinity() +{ + StoreExternalEdges(); + if (!stldoctor.showvicinity || vicinity.Size() != GetNT()) {return;} + + int i, j, k, p1, p2; + + for (i = 1; i <= GetNT(); i++) + { + if (vicinity.Elem(i)) + { + for (j = 1; j <= 3; j++) + { + p1 = GetTriangle(i).PNum(j); + p2 = GetTriangle(i).PNumMod(j+1); + + if (IsExternalEdge(p1,p2)) + { + DeleteExternalEdge(p1,p2); + } + } + } + } +} + +void STLGeometry :: BuildExternalEdgesFromEdges() +{ + StoreExternalEdges(); + + if (GetNE() == 0) {PrintWarning("Edges possibly not generated!");} + + int i, p1, p2; + externaledges.SetSize(0); + + for (i = 1; i <= GetNE(); i++) + { + STLEdge e = GetEdge(i); + AddExternalEdge(e.PNum(1), e.PNum(2)); + } + +} + + +void STLGeometry :: AddExternalEdge(int p1, int p2) +{ + externaledges.Append(twoint(p1,p2)); +} + +void STLGeometry :: DeleteExternalEdge(int p1, int p2) +{ + + int i; + int found = 0; + for (i = 1; i <= NOExternalEdges(); i++) + { + if ((GetExternalEdge(i).i1 == p1 && GetExternalEdge(i).i2 == p2) || + (GetExternalEdge(i).i1 == p2 && GetExternalEdge(i).i2 == p1)) {found = 1;}; + if (found && i < NOExternalEdges()) + { + externaledges.Elem(i) = externaledges.Get(i+1); + } + } + if (!found) {PrintWarning("edge not found");} + else + { + externaledges.SetSize(externaledges.Size()-1); + } + +} + +int STLGeometry :: IsExternalEdge(int p1, int p2) +{ + int i; + for (i = 1; i <= NOExternalEdges(); i++) + { + if ((GetExternalEdge(i).i1 == p1 && GetExternalEdge(i).i2 == p2) || + (GetExternalEdge(i).i1 == p2 && GetExternalEdge(i).i2 == p1)) {return 1;}; + } + return 0; +} + +void STLGeometry :: DestroyDirtyTrigs() +{ + + PrintFnStart("Destroy dirty triangles"); + PrintMessage(5,"original number of triangles=", GetNT()); + + //destroy every triangle with other than 3 neighbours; + int changed = 1; + int i, j, k; + while (changed) + { + changed = 0; + Clear(); + + for (i = 1; i <= GetNT(); i++) + { + int dirty = NONeighbourTrigs(i) < 3; + + for (j = 1; j <= 3; j++) + { + int pnum = GetTriangle(i).PNum(j); + /* + if (pnum == 1546) + { + // for (k = 1; k <= NOTrigsPerPoint(pnum); k++) + } + */ + if (NOTrigsPerPoint(pnum) <= 2) + dirty = 1; + } + + int pi1 = GetTriangle(i).PNum(1); + int pi2 = GetTriangle(i).PNum(2); + int pi3 = GetTriangle(i).PNum(3); + if (pi1 == pi2 || pi1 == pi3 || pi2 == pi3) + { + PrintMessage(5,"triangle with Volume 0: ", i, " nodes: ", pi1, ", ", pi2, ", ", pi3); + dirty = 1; + } + + if (dirty) + { + for (k = i+1; k <= GetNT(); k++) + { + trias.Elem(k-1) = trias.Get(k); + // readtrias: not longer permanent, JS + // readtrias.Elem(k-1) = readtrias.Get(k); + } + int size = GetNT(); + trias.SetSize(size-1); + // readtrias.SetSize(size-1); + changed = 1; + break; + } + } + } + + FindNeighbourTrigs(); + PrintMessage(5,"final number of triangles=", GetNT()); +} + +void STLGeometry :: CalcNormalsFromGeometry() +{ + int i; + for (i = 1; i <= GetNT(); i++) + { + const STLTriangle & tr = GetTriangle(i); + const Point3d& p1 = GetPoint(tr.PNum(1)); + const Point3d& p2 = GetPoint(tr.PNum(2)); + const Point3d& p3 = GetPoint(tr.PNum(3)); + + Vec3d normal = Cross (p2-p1, p3-p1); + + if (normal.Length() != 0) + { + normal /= (normal.Length()); + } + GetTriangle(i).SetNormal(normal); + } + PrintMessage(5,"Normals calculated from geometry!!!"); + + calcedgedataanglesnew = 1; +} + +void STLGeometry :: SetSelectTrig(int trig) +{ + stldoctor.selecttrig = trig; +} + +int STLGeometry :: GetSelectTrig() const +{ + return stldoctor.selecttrig; +} + +void STLGeometry :: SetNodeOfSelTrig(int n) +{ + stldoctor.nodeofseltrig = n; +} + +int STLGeometry :: GetNodeOfSelTrig() const +{ + return stldoctor.nodeofseltrig; +} + +void STLGeometry :: MoveSelectedPointToMiddle() +{ + if (GetSelectTrig() >= 1 && GetSelectTrig() <= GetNT()) + { + int p = GetTriangle(GetSelectTrig()).PNum(GetNodeOfSelTrig()); + Point<3> pm(0.,0.,0.); //Middlevector; + Point<3> p0(0.,0.,0.); + PrintMessage(5,"original point=", Point3d(GetPoint(p))); + + int i; + int cnt = 0; + for (i = 1; i <= trigsperpoint.EntrySize(p); i++) + { + const STLTriangle& tr = GetTriangle(trigsperpoint.Get(p,i)); + int j; + for (j = 1; j <= 3; j++) + { + if (tr.PNum(j) != p) + { + cnt++; + pm(0) += GetPoint(tr.PNum(j))(0); + pm(1) += GetPoint(tr.PNum(j))(1); + pm(2) += GetPoint(tr.PNum(j))(2); + } + } + } + + Point<3> origp = GetPoint(p); + double fact = 0.2; + + SetPoint(p, p0 + fact*(1./(double)cnt)*(pm-p0)+(1.-fact)*(origp-p0)); + + PrintMessage(5,"middle point=", Point3d (GetPoint(p))); + + PrintMessage(5,"moved point ", Point3d (p)); + + } +} + +void STLGeometry :: PrintSelectInfo() +{ + + int trig = GetSelectTrig(); + int p = GetTriangle(trig).PNum(GetNodeOfSelTrig()); + + PrintMessage(1,"touch triangle ", GetSelectTrig() + , ", local node ", GetNodeOfSelTrig() + , " (=", GetTriangle(GetSelectTrig()).PNum(GetNodeOfSelTrig()), ")"); + if (AtlasMade() && GetSelectTrig() >= 1 && GetSelectTrig() <= GetNT()) + { + PrintMessage(1," chartnum=",GetChartNr(GetSelectTrig())); + /* + PointBetween(Center(Center(GetPoint(GetTriangle(270).PNum(1)), + GetPoint(GetTriangle(270).PNum(2))), + GetPoint(GetTriangle(270).PNum(3))),270, + Center(Center(GetPoint(GetTriangle(trig).PNum(1)), + GetPoint(GetTriangle(trig).PNum(2))), + GetPoint(GetTriangle(trig).PNum(3))),trig); + */ + //PointBetween(Point3d(5.7818, 7.52768, 4.14879),260,Point3d(6.80292, 6.55392, 4.70184),233); + } +} + +void STLGeometry :: ShowSelectedTrigChartnum() +{ + int st = GetSelectTrig(); + + if (st >= 1 && st <= GetNT() && AtlasMade()) + PrintMessage(1,"selected trig ", st, " has chartnumber ", GetChartNr(st)); +} + +void STLGeometry :: ShowSelectedTrigCoords() +{ + int st = GetSelectTrig(); + + /* + //testing!!!! + ARRAY<int> trigs; + GetSortedTrianglesAroundPoint(GetTriangle(st).PNum(GetNodeOfSelTrig()),st,trigs); + */ + + if (st >= 1 && st <= GetNT()) + { + PrintMessage(1, "coordinates of selected trig ", st, ":"); + PrintMessage(1, " p1 = ", GetTriangle(st).PNum(1), " = ", + Point3d (GetPoint(GetTriangle(st).PNum(1)))); + PrintMessage(1, " p2 = ", GetTriangle(st).PNum(2), " = ", + Point3d (GetPoint(GetTriangle(st).PNum(2)))); + PrintMessage(1, " p3 = ", GetTriangle(st).PNum(3), " = ", + Point3d (GetPoint(GetTriangle(st).PNum(3)))); + } +} + +void STLGeometry :: LoadMarkedTrigs() +{ + PrintFnStart("load marked trigs from file 'markedtrigs.ng'"); + ifstream fin("markedtrigs.ng"); + + int n; + fin >> n; + if (n != GetNT() || n == 0) {PrintError("Not a suitable marked-trig-file!"); return;} + + int i, m; + for (i = 1; i <= n; i++) + { + fin >> m; + SetMarkedTrig(i, m); + } + + fin >> n; + if (n != 0) + { + int i, m; + Point<3> p1, p2; + for (i = 1; i <= n; i++) + { + fin >> p1(0); fin >> p1(1); fin >> p1(2); + fin >> p2(0); fin >> p2(1); fin >> p2(2); + AddMarkedSeg(p1,p2); + } + } +} + +void STLGeometry :: SaveMarkedTrigs() +{ + PrintFnStart("save marked trigs to file 'markedtrigs.ng'"); + ofstream fout("markedtrigs.ng"); + + int n = GetNT(); + fout << n << endl; + + int i, m; + for (i = 1; i <= n; i++) + { + fout << IsMarkedTrig(i) << "\n"; + } + + n = GetNMarkedSegs(); + fout << n << endl; + + Point<3> p1,p2; + for (i = 1; i <= n; i++) + { + GetMarkedSeg(i,p1,p2); + fout << p1(0) << " " << p1(1) << " " << p1(2) << " "; + fout << p2(0) << " " << p2(1) << " " << p2(2) << " " << "\n"; + } + +} + +void STLGeometry :: NeighbourAnglesOfSelectedTrig() +{ + int st = GetSelectTrig(); + + if (st >= 1 && st <= GetNT()) + { + int i; + PrintMessage(1,"Angle to triangle ", st, ":"); + for (i = 1; i <= NONeighbourTrigs(st); i++) + { + PrintMessage(1," triangle ", NeighbourTrig(st,i), ": angle = " + , 180./M_PI*GetAngle(st, NeighbourTrig(st,i)), "�" + , ", calculated = ", 180./M_PI*Angle(GetTriangle(st).GeomNormal(points), + GetTriangle(NeighbourTrig(st,i)).GeomNormal(points)), "�"); + } + } +} + +void STLGeometry :: GetVicinity(int starttrig, int size, ARRAY<int>& vic) +{ + if (starttrig == 0 || starttrig > GetNT()) {return;} + + ARRAY<int> vicarray; + vicarray.SetSize(GetNT()); + + int i; + for (i = 1; i <= vicarray.Size(); i++) + { + vicarray.Elem(i) = 0; + } + + vicarray.Elem(starttrig) = 1; + + int j = 0,k; + + ARRAY <int> list1; + list1.SetSize(0); + ARRAY <int> list2; + list2.SetSize(0); + list1.Append(starttrig); + + while (j < size) + { + j++; + for (i = 1; i <= list1.Size(); i++) + { + for (k = 1; k <= NONeighbourTrigs(i); k++) + { + int nbtrig = NeighbourTrig(list1.Get(i),k); + if (nbtrig && vicarray.Get(nbtrig) == 0) + { + list2.Append(nbtrig); + vicarray.Elem(nbtrig) = 1; + } + } + } + list1.SetSize(0); + for (i = 1; i <= list2.Size(); i++) + { + list1.Append(list2.Get(i)); + } + list2.SetSize(0); + } + + vic.SetSize(0); + for (i = 1; i <= vicarray.Size(); i++) + { + if (vicarray.Get(i)) {vic.Append(i);} + } +} + +void STLGeometry :: CalcVicinity(int starttrig) +{ + if (starttrig == 0 || starttrig > GetNT()) {return;} + + vicinity.SetSize(GetNT()); + + if (!stldoctor.showvicinity) {return;} + + int i; + for (i = 1; i <= vicinity.Size(); i++) + { + vicinity.Elem(i) = 0; + } + + vicinity.Elem(starttrig) = 1; + + int j = 0,k; + + ARRAY <int> list1; + list1.SetSize(0); + ARRAY <int> list2; + list2.SetSize(0); + list1.Append(starttrig); + + // int cnt = 1; + while (j < stldoctor.vicinity) + { + j++; + for (i = 1; i <= list1.Size(); i++) + { + for (k = 1; k <= NONeighbourTrigs(i); k++) + { + int nbtrig = NeighbourTrig(list1.Get(i),k); + if (nbtrig && vicinity.Get(nbtrig) == 0) + { + list2.Append(nbtrig); + vicinity.Elem(nbtrig) = 1; + //cnt++; + } + } + } + list1.SetSize(0); + for (i = 1; i <= list2.Size(); i++) + { + list1.Append(list2.Get(i)); + } + list2.SetSize(0); + } + +} + +int STLGeometry :: Vicinity(int trig) const +{ + if (trig <= vicinity.Size() && trig >=1) + { + return vicinity.Get(trig); + } + else {PrintSysError("In STLGeometry::Vicinity");} + return 0; +} + +void STLGeometry :: InitMarkedTrigs() +{ + markedtrigs.SetSize(GetNT()); + int i; + for (i = 1; i <= GetNT(); i++) + { + SetMarkedTrig(i, 0); + } +} + +void STLGeometry :: MarkDirtyTrigs() +{ + PrintFnStart("mark dirty trigs"); + int i,j; + + markedtrigs.SetSize(GetNT()); + + for (i = 1; i <= GetNT(); i++) + { + SetMarkedTrig(i, 0); + } + + int found; + double dirtyangle = stlparam.yangle/2./180.*M_PI; + int cnt = 0; + for (i = 1; i <= GetNT(); i++) + { + found = 0; + for (j = 1; j <= NONeighbourTrigs(i); j++) + { + if (GetAngle(i, NeighbourTrig(i,j)) > dirtyangle) + { + found++; + } + } + if (found && GetTriangle(i).MinHeight(points) < + stldoctor.dirtytrigfact*GetTriangle(i).MaxLength(points)) + { + SetMarkedTrig(i, 1); cnt++; + } + /* + else if (found == 3) + { + SetMarkedTrig(i, 1); cnt++; + } + */ + } + + PrintMessage(1, "marked ", cnt, " dirty trigs"); +} + + +void STLGeometry :: MarkTopErrorTrigs() +{ + int cnt = 0; + markedtrigs.SetSize(GetNT()); + for (int i = 1; i <= GetNT(); i++) + { + const STLTriangle & trig = GetTriangle(i); + + SetMarkedTrig(i, trig.flags.toperror); + if (trig.flags.toperror) cnt++; + } + PrintMessage(1,"marked ", cnt, " inconsistent triangles"); +} + + + +double STLGeometry :: CalcTrigBadness(int i) +{ + int j; + double maxbadness = 0; + int p1, p2; + for (j = 1; j <= NONeighbourTrigs(i); j++) + { + GetTriangle(i).GetNeighbourPoints(GetTriangle(NeighbourTrig(i,j)), p1, p2); + + if (!IsEdge(p1,p2) && GetGeomAngle(i, NeighbourTrig(i,j)) > maxbadness) + { + maxbadness = GetGeomAngle(i, NeighbourTrig(i,j)); + } + } + return maxbadness; + +} + +void STLGeometry :: GeomSmoothRevertedTrigs() +{ + double revertedangle = stldoctor.smoothangle/180.*M_PI; + double fact = stldoctor.dirtytrigfact; + + MarkRevertedTrigs(); + + int i, j, k, l, p; + + for (i = 1; i <= GetNT(); i++) + { + if (IsMarkedTrig(i)) + { + for (j = 1; j <= 3; j++) + { + double origbadness = CalcTrigBadness(i); + + p = GetTriangle(i).PNum(j); + Point<3> pm(0.,0.,0.); //Middlevector; + Point<3> p0(0.,0.,0.); + + int cnt = 0; + + for (k = 1; k <= trigsperpoint.EntrySize(p); k++) + { + const STLTriangle& tr = GetTriangle(trigsperpoint.Get(p,k)); + for (l = 1; l <= 3; l++) + { + if (tr.PNum(l) != p) + { + cnt++; + pm(0) += GetPoint(tr.PNum(l))(0); + pm(1) += GetPoint(tr.PNum(l))(1); + pm(2) += GetPoint(tr.PNum(l))(2); + } + } + } + Point3d origp = GetPoint(p); + Point3d newp = p0 + fact*(1./(double)cnt)*(pm-p0)+(1.-fact)*(origp-p0); + + SetPoint(p, newp); + + if (CalcTrigBadness(i) > 0.9*origbadness) {SetPoint(p,origp); PrintDot('f');} + else {PrintDot('s');} + } + } + } + MarkRevertedTrigs(); +} + +void STLGeometry :: MarkRevertedTrigs() +{ + int i,j; + if (edgesperpoint.Size() != GetNP()) {BuildEdges();} + + PrintFnStart("mark reverted trigs"); + + InitMarkedTrigs(); + + int found; + double revertedangle = stldoctor.smoothangle/180.*M_PI; + + int cnt = 0; + int p1, p2; + for (i = 1; i <= GetNT(); i++) + { + found = 0; + for (j = 1; j <= NONeighbourTrigs(i); j++) + { + GetTriangle(i).GetNeighbourPoints(GetTriangle(NeighbourTrig(i,j)), p1, p2); + + if (!IsEdge(p1,p2)) + { + if (GetGeomAngle(i, NeighbourTrig(i,j)) > revertedangle) + { + found = 1; + break; + } + } + } + + if (found) + { + SetMarkedTrig(i, 1); cnt++; + } + + } + + PrintMessage(5, "found ", cnt, " reverted trigs"); + + +} + +void STLGeometry :: SmoothDirtyTrigs() +{ + PrintFnStart("smooth dirty trigs"); + + MarkDirtyTrigs(); + + int i,j; + int changed = 1; + int p1, p2; + + while (changed) + { + changed = 0; + for (i = 1; i <= GetNT(); i++) + { + if (IsMarkedTrig(i)) + { + int foundtrig = 0; + double maxlen = 0; + // JS: darf normalvector nicht ueber kurze Seite erben + maxlen = GetTriangle(i).MaxLength(GetPoints()) / 2.1; //JG: bei flachem dreieck auch kurze Seite + + for (j = 1; j <= NONeighbourTrigs(i); j++) + { + if (!IsMarkedTrig(NeighbourTrig(i,j))) + { + GetTriangle(i).GetNeighbourPoints(GetTriangle(NeighbourTrig(i,j)),p1,p2); + if (Dist(GetPoint(p1),GetPoint(p2)) >= maxlen) + { + foundtrig = NeighbourTrig(i,j); + maxlen = Dist(GetPoint(p1),GetPoint(p2)); + } + } + } + if (foundtrig) + { + GetTriangle(i).SetNormal(GetTriangle(foundtrig).Normal()); + changed = 1; + SetMarkedTrig(i,0); + } + } + } + } + + calcedgedataanglesnew = 1; + + + MarkDirtyTrigs(); + + int cnt = 0; + for (i = 1; i <= GetNT(); i++) + { + if (IsMarkedTrig(i)) {cnt++;} + } + + PrintMessage(5,"NO marked dirty trigs=", cnt); + +} + +int STLGeometry :: IsMarkedTrig(int trig) const +{ + if (trig <= markedtrigs.Size() && trig >=1) + { + return markedtrigs.Get(trig); + } + else {PrintSysError("In STLGeometry::IsMarkedTrig");} + + return 0; +} + +void STLGeometry :: SetMarkedTrig(int trig, int num) +{ + if (trig <= markedtrigs.Size() && trig >=1) + { + markedtrigs.Elem(trig) = num; + } + else {PrintSysError("In STLGeometry::SetMarkedTrig");} +} + +void STLGeometry :: Clear() +{ + PrintFnStart("Clear"); + + surfacemeshed = 0; + surfaceoptimized = 0; + volumemeshed = 0; + + selectedmultiedge.SetSize(0); + meshlines.SetSize(0); + // neighbourtrigs.SetSize(0); + outerchartspertrig.SetSize(0); + atlas.SetSize(0); + ClearMarkedSegs(); + ClearSpiralPoints(); + ClearLineEndPoints(); + + SetSelectTrig(0); + SetNodeOfSelTrig(1); + facecnt = 0; + + SetThreadPercent(100.); + + ClearEdges(); +} + +double STLGeometry :: Area() +{ + double ar = 0; + int i; + for (i = 1; i <= GetNT(); i++) + { + ar += GetTriangle(i).Area(points); + } + return ar; +} + +double STLGeometry :: GetAngle(int t1, int t2) +{ + return Angle(GetTriangle(t1).Normal(),GetTriangle(t2).Normal()); +} + +double STLGeometry :: GetGeomAngle(int t1, int t2) +{ + Vec3d n1 = GetTriangle(t1).GeomNormal(points); + Vec3d n2 = GetTriangle(t2).GeomNormal(points); + return Angle(n1,n2); +} + + +void STLGeometry :: InitSTLGeometry(const ARRAY<STLReadTriangle> & readtrias) +{ + PrintFnStart("Init STL Geometry"); + STLTopology::InitSTLGeometry(readtrias); + + int i, j, k; + + const double geometry_tol_fact = 1E8; //distances lower than max_box_size/tol are ignored + + int np = GetNP(); + PrintMessage(5,"NO points= ", GetNP()); + normals.SetSize(GetNP()); + ARRAY<int> normal_cnt(GetNP()); // counts number of added normals in a point + + for (i = 1; i <= np; i++) + { + normal_cnt.Elem(i) = 0; + normals.Elem(i) = Vec3d (0,0,0); + } + + for(i = 1; i <= GetNT(); i++) + { + // STLReadTriangle t = GetReadTriangle(i); + // STLTriangle st; + + Vec<3> n = GetTriangle(i).Normal (); + + for (k = 1; k <= 3; k++) + { + int pi = GetTriangle(i).PNum(k); + + normal_cnt.Elem(pi)++; + SetNormal(pi, GetNormal(pi) + n); + } + } + + //normalize the normals + for (i = 1; i <= GetNP(); i++) + { + SetNormal(i,1./(double)normal_cnt.Get(i)*GetNormal(i)); + } + + trigsconverted = 1; + + vicinity.SetSize(GetNT()); + markedtrigs.SetSize(GetNT()); + for (i = 1; i <= GetNT(); i++) + { + markedtrigs.Elem(i) = 0; + vicinity.Elem(i) = 1; + } + + ha_points.SetSize(GetNP()); + for (i = 1; i <= GetNP(); i++) + ha_points.Elem(i) = 0; + + calcedgedataanglesnew = 0; + edgedatastored = 0; + edgedata.Clear(); + + + if (GetStatus() == STL_ERROR) return; + + CalcEdgeData(); + CalcEdgeDataAngles(); + + ClearLineEndPoints(); + + CheckGeometryOverlapping(); +} + +void STLGeometry :: TopologyChanged() +{ + calcedgedataanglesnew = 1; +} + +int STLGeometry :: CheckGeometryOverlapping() +{ + int i, j, k; + + Box<3> geombox = GetBoundingBox(); + Point<3> pmin = geombox.PMin(); + Point<3> pmax = geombox.PMax(); + + Box3dTree setree(pmin, pmax); + ARRAY<int> inters; + + int oltrigs = 0; + markedtrigs.SetSize(GetNT()); + + for (i = 1; i <= GetNT(); i++) + SetMarkedTrig(i, 0); + + for (i = 1; i <= GetNT(); i++) + { + const STLTriangle & tri = GetTriangle(i); + + Point<3> tpmin = tri.box.PMin(); + Point<3> tpmax = tri.box.PMax(); + Vec<3> diag = tpmax - tpmin; + + tpmax = tpmax + 0.001 * diag; + tpmin = tpmin - 0.001 * diag; + + setree.Insert (tpmin, tpmax, i); + } + + for (i = 1; i <= GetNT(); i++) + { + const STLTriangle & tri = GetTriangle(i); + + Point<3> tpmin = tri.box.PMin(); + Point<3> tpmax = tri.box.PMax(); + + setree.GetIntersecting (tpmin, tpmax, inters); + + for (j = 1; j <= inters.Size(); j++) + { + const STLTriangle & tri2 = GetTriangle(inters.Get(j)); + + const Point3d *trip1[3], *trip2[3]; + Point3d hptri1[3], hptri2[3]; + /* + for (k = 1; k <= 3; k++) + { + trip1[k-1] = &GetPoint (tri.PNum(k)); + trip2[k-1] = &GetPoint (tri2.PNum(k)); + } + */ + + for (k = 0; k < 3; k++) + { + hptri1[k] = GetPoint (tri[k]); + hptri2[k] = GetPoint (tri2[k]); + trip1[k] = &hptri1[k]; + trip2[k] = &hptri2[k]; + } + + if (IntersectTriangleTriangle (&trip1[0], &trip2[0])) + { + oltrigs++; + PrintMessage(5,"Intersecting Triangles: trig ",i," with ",inters.Get(j),"!"); + SetMarkedTrig(i, 1); + SetMarkedTrig(inters.Get(j), 1); + } + } + } + + PrintMessage(3,"Check Geometry Overlapping: overlapping triangles = ",oltrigs); + return oltrigs; +} + +/* +void STLGeometry :: InitSTLGeometry() +{ + STLTopology::InitSTLGeometry(); + + int i, j, k; + + const double geometry_tol_fact = 1E8; //distances lower than max_box_size/tol are ignored + + + trias.SetSize(0); + points.SetSize(0); + normals.SetSize(0); + + ARRAY<int> normal_cnt; // counts number of added normals in a point + + Box3d bb (GetBoundingBox().PMin() + Vec3d (-1,-1,-1), + GetBoundingBox().PMax() + Vec3d (1, 1, 1)); + + Point3dTree pointtree (bb.PMin(), + bb.PMax()); + ARRAY<int> pintersect; + + double gtol = GetBoundingBox().CalcDiam()/geometry_tol_fact; + + for(i = 1; i <= GetReadNT(); i++) + { + //if (i%500==499) {(*mycout) << (double)i/(double)GetReadNT()*100. << "%" << endl;} + + STLReadTriangle t = GetReadTriangle(i); + STLTriangle st; + Vec3d n = t.normal; + + for (k = 0; k < 3; k++) + { + Point3d p = t.pts[k]; + + Point3d pmin = p - Vec3d (gtol, gtol, gtol); + Point3d pmax = p + Vec3d (gtol, gtol, gtol); + + pointtree.GetIntersecting (pmin, pmax, pintersect); + + if (pintersect.Size() > 1) + (*mycout) << "found too much " << char(7) << endl; + int foundpos = 0; + if (pintersect.Size()) + foundpos = pintersect.Get(1); + + if (foundpos) + { + normal_cnt[foundpos]++; + SetNormal(foundpos,GetNormal(foundpos)+n); + // (*testout) << "found p " << p << endl; + } + else + { + foundpos = AddPoint(p); + AddNormal(n); + normal_cnt.Append(1); + + pointtree.Insert (p, foundpos); + } + //(*mycout) << "foundpos=" << foundpos << endl; + st.pts[k] = foundpos; + } + + if ( (st.pts[0] == st.pts[1]) || + (st.pts[0] == st.pts[2]) || + (st.pts[1] == st.pts[2]) ) + { + (*mycout) << "ERROR: STL Triangle degenerated" << endl; + } + else + { + // do not add ? js + AddTriangle(st); + } + //(*mycout) << "TRIG" << i << " = " << st << endl; + + } + //normal the normals + for (i = 1; i <= GetNP(); i++) + { + SetNormal(i,1./(double)normal_cnt[i]*GetNormal(i)); + } + + trigsconverted = 1; + + vicinity.SetSize(GetNT()); + markedtrigs.SetSize(GetNT()); + for (i = 1; i <= GetNT(); i++) + { + markedtrigs.Elem(i) = 0; + vicinity.Elem(i) = 1; + } + + ha_points.SetSize(GetNP()); + for (i = 1; i <= GetNP(); i++) + ha_points.Elem(i) = 0; + + calcedgedataanglesnew = 0; + edgedatastored = 0; + edgedata.Clear(); + + CalcEdgeData(); + CalcEdgeDataAngles(); + + ClearLineEndPoints(); + + (*mycout) << "done" << endl; +} +*/ + + + +void STLGeometry :: SetLineEndPoint(int pn) +{ + if (pn <1 || pn > lineendpoints.Size()) {PrintSysError("Illegal pnum in SetLineEndPoint!!!"); return; } + lineendpoints.Elem(pn) = 1; +} + +int STLGeometry :: IsLineEndPoint(int pn) +{ + // return 0; + if (pn <1 || pn > lineendpoints.Size()) + {PrintSysError("Illegal pnum in IsLineEndPoint!!!"); return 0;} + return lineendpoints.Get(pn); +} + +void STLGeometry :: ClearLineEndPoints() +{ + lineendpoints.SetSize(GetNP()); + int i; + for (i = 1; i <= GetNP(); i++) + { + lineendpoints.Elem(i) = 0; + } +} + +int STLGeometry :: IsEdge(int p1, int p2) +{ + int i,j; + for (i = 1; i <= GetNEPP(p1); i++) + { + for (j = 1; j <= GetNEPP(p2); j++) + { + if (GetEdgePP(p1,i) == GetEdgePP(p2,j)) {return 1;} + } + } + return 0; +} + +int STLGeometry :: IsEdgeNum(int p1, int p2) +{ + int i,j; + for (i = 1; i <= GetNEPP(p1); i++) + { + for (j = 1; j <= GetNEPP(p2); j++) + { + if (GetEdgePP(p1,i) == GetEdgePP(p2,j)) {return GetEdgePP(p1,i);} + } + } + return 0; +} + + +void STLGeometry :: BuildEdges() +{ + //PrintFnStart("build edges"); + edges.SetSize(0); + meshlines.SetSize(0); + FindEdgesFromAngles(); +} + +void STLGeometry :: UseExternalEdges() +{ + int i; + for (i = 1; i <= NOExternalEdges(); i++) + { + AddEdge(GetExternalEdge(i).i1,GetExternalEdge(i).i2); + } + //BuildEdgesPerPointy(); +} + +void STLGeometry :: UndoEdgeChange() +{ + if (edgedatastored) + { + RestoreEdgeData(); + } + else + { + PrintWarning("no edge undo possible"); + } +} + + +void STLGeometry :: StoreEdgeData() +{ + // edgedata_store = edgedata; + + edgedata.Store(); + edgedatastored = 1; + + // put stlgeom-edgedata to stltopology edgedata + /* + int i; + for (i = 1; i <= GetNTE(); i++) + { + const STLTopEdge & topedge = GetTopEdge (i); + int ednum = edgedata.GetEdgeNum (topedge.PNum(1), + topedge.PNum(2)); + topedges.Elem(i).SetStatus (edgedata.Get (ednum).status); + } + */ +} + +void STLGeometry :: RestoreEdgeData() +{ + // edgedata = edgedata_store; + edgedata.Restore(); + edgedatastored=0; +} + + +void STLGeometry :: CalcEdgeData() +{ + PushStatus("Calc Edge Data"); + + int np1, np2; + double ang; + int i; + + int ecnt = 0; + edgedata.SetSize(GetNT()/2*3); + + for (i = 1; i <= GetNT(); i++) + { + SetThreadPercent((double)i/(double)GetNT()*100.); + + const STLTriangle & t1 = GetTriangle(i); + + for (int j = 1; j <= NONeighbourTrigs(i); j++) + { + int nbti = NeighbourTrig(i,j); + if (nbti > i) + { + const STLTriangle & t2 = GetTriangle(nbti); + + if (t1.IsNeighbourFrom(t2)) + { + ecnt++; if (ecnt > edgedata.Size()) {PrintError("In Calc edge data, illegal geometry");} + + t1.GetNeighbourPoints(t2,np1,np2); + + /* ang = GetAngle(i,nbti); + if (ang < -M_PI) {ang += 2*M_PI;}*/ + + + // edgedata.Add(STLEdgeData(0, np1, np2, i, nbti),ecnt); + edgedata.Elem(ecnt).SetStatus(ED_UNDEFINED); + + // edgedata.Elem(ecnt).top = this; + // edgedata.Elem(ecnt).topedgenr = GetTopEdgeNum (np1, np2); + } + } + } + } + + //BuildEdgesPerPoint(); + PopStatus(); +} + +void STLGeometry :: CalcEdgeDataAngles() +{ + PrintMessage(5,"calc edge data angles"); + + double ang; + int i; + int t1,t2; + + for (i = 1; i <= GetNTE(); i++) + { + STLTopEdge & edge = GetTopEdge (i); + double cosang = + GetTriangle(edge.TrigNum(1)).Normal() * + GetTriangle(edge.TrigNum(2)).Normal(); + edge.SetCosAngle (cosang); + } + + for (i = 1; i <= edgedata.Size(); i++) + { + /* + const STLEdgeData& e = edgedata.Get(i); + ang = GetAngle(e.lt,e.rt); + if (ang < -M_PI) {ang += 2*M_PI;} + edgedata.Elem(i).angle = fabs(ang); + */ + } + +} + +void STLGeometry :: FindEdgesFromAngles() +{ + // PrintFnStart("find edges from angles"); + + double min_edge_angle = stlparam.yangle/180.*M_PI; + double cont_min_edge_angle = stlparam.contyangle/180.*M_PI; + + double cos_min_edge_angle = cos (min_edge_angle); + double cos_cont_min_edge_angle = cos (cont_min_edge_angle); + + if (calcedgedataanglesnew) {CalcEdgeDataAngles(); calcedgedataanglesnew = 0;} + + int i; + for (i = 1; i <= edgedata.Size(); i++) + { + STLTopEdge & sed = edgedata.Elem(i); + if (sed.GetStatus() == ED_CANDIDATE || + sed.GetStatus() == ED_UNDEFINED) + { + if (sed.CosAngle() <= cos_min_edge_angle) + { + sed.SetStatus (ED_CANDIDATE); + } + else + { + sed.SetStatus(ED_UNDEFINED); + } + } + } + + if (stlparam.contyangle < stlparam.yangle) + { + int changed = 1; + int its = 0; + while (changed && stlparam.contyangle < stlparam.yangle) + { + its++; + //(*mycout) << "." << flush; + changed = 0; + for (i = 1; i <= edgedata.Size(); i++) + { + STLTopEdge & sed = edgedata.Elem(i); + if (sed.CosAngle() <= cos_cont_min_edge_angle + && sed.GetStatus() == ED_UNDEFINED && + (edgedata.GetNConfCandEPP(sed.PNum(1)) == 1 || + edgedata.GetNConfCandEPP(sed.PNum(2)) == 1)) + { + changed = 1; + sed.SetStatus (ED_CANDIDATE); + } + } + } + } + + int confcand = 0; + if (edgedata.GetNConfEdges() == 0) + { + confcand = 1; + } + + for (i = 1; i <= edgedata.Size(); i++) + { + STLTopEdge & sed = edgedata.Elem(i); + if (sed.GetStatus() == ED_CONFIRMED || + (sed.GetStatus() == ED_CANDIDATE && confcand)) + { + STLEdge se(sed.PNum(1),sed.PNum(2)); + se.SetLeftTrig(sed.TrigNum(1)); + se.SetRightTrig(sed.TrigNum(2)); + AddEdge(se); + } + } + BuildEdgesPerPoint(); + + + + //(*mycout) << "its for continued angle = " << its << endl; + PrintMessage(5,"built ", GetNE(), " edges with yellow angle = ", stlparam.yangle, " degree"); + +} + +/* +void STLGeometry :: FindEdgesFromAngles() +{ + double yangle = stlparam.yangle; + char * savetask = multithread.task; + multithread.task = "find edges"; + + const double min_edge_angle = yangle/180.*M_PI; + + int np1, np2; + double ang; + int i; + + //(*mycout) << "area=" << Area() << endl; + + for (i = 1; i <= GetNT(); i++) + { + multithread.percent = (double)i/(double)GetReadNT()*100.; + + const STLTriangle & t1 = GetTriangle(i); + //NeighbourTrigs(nt,i); + + for (int j = 1; j <= NONeighbourTrigs(i); j++) + { + int nbti = NeighbourTrig(i,j); + if (nbti > i) + { + const STLTriangle & t2 = GetTriangle(nbti); + + if (t1.IsNeighbourFrom(t2)) + { + ang = GetAngle(i,nbti); + if (ang < -M_PI*0.5) {ang += 2*M_PI;} + + t1.GetNeighbourPoints(t2,np1,np2); + + if (fabs(ang) >= min_edge_angle) + { + STLEdge se(np1,np2); + se.SetLeftTrig(i); + se.SetRightTrig(nbti); + AddEdge(se); + } + } + } + } + } + + (*mycout) << "added " << GetNE() << " edges" << endl; + + //BuildEdgesPerPoint(); + + multithread.percent = 100.; + multithread.task = savetask; + +} +*/ +void STLGeometry :: BuildEdgesPerPoint() +{ + //cout << "*** build edges per point" << endl; + edgesperpoint.SetSize(GetNP()); + + //add edges to points + int i, j; + for (i = 1; i <= GetNE(); i++) + { + //(*mycout) << "EDGE " << GetEdge(i).PNum(1) << " - " << GetEdge(i).PNum(2) << endl; + for (int j = 1; j <= 2; j++) + { + AddEdgePP(GetEdge(i).PNum(j),i); + } + } +} + +void STLGeometry :: AddFaceEdges() +{ + PrintFnStart("Add starting edges for faces"); + + //f�r Kugel eine STLLine hinzuf�gen (Vorteil: verfeinerbar, unabh�ngig von Aufl�sung der Geometrie!!!): + //Grenze von 1. gefundener chart + + ARRAY<int> edgecnt; + ARRAY<int> chartindex; + edgecnt.SetSize(GetNOFaces()); + chartindex.SetSize(GetNOFaces()); + + int i,j; + for (i = 1; i <= GetNOFaces(); i++) + { + edgecnt.Elem(i) = 0; + chartindex.Elem(i) = 0; + } + + for (i = 1; i <= GetNT(); i++) + { + int fn = GetTriangle(i).GetFaceNum(); + if (!chartindex.Get(fn)) {chartindex.Elem(fn) = GetChartNr(i);} + for (j = 1; j <= 3; j++) + { + edgecnt.Elem(fn) += GetNEPP(GetTriangle(i).PNum(j)); + } + } + + for (i = 1; i <= GetNOFaces(); i++) + { + if (!edgecnt.Get(i)) {PrintMessage(5,"Face", i, " has no edge!");} + } + + int changed = 0; + int k, p1, p2; + for (i = 1; i <= GetNOFaces(); i++) + { + if (!edgecnt.Get(i)) + { + const STLChart& c = GetChart(chartindex.Get(i)); + for (j = 1; j <= c.GetNChartT(); j++) + { + const STLTriangle& t1 = GetTriangle(c.GetChartTrig(j)); + for (k = 1; k <= 3; k++) + { + int nt = NeighbourTrig(c.GetChartTrig(j),k); + if (GetChartNr(nt) != chartindex.Get(i)) + { + t1.GetNeighbourPoints(GetTriangle(nt),p1,p2); + AddEdge(p1,p2); + changed = 1; + } + } + } + } + + } + + if (changed) BuildEdgesPerPoint(); + +} + +void STLGeometry :: LinkEdges() +{ + PushStatusF("Link Edges"); + PrintMessage(5,"have now ", GetNE(), " edges with yellow angle = ", stlparam.yangle, " degree"); + + int i; + + lines.SetSize(0); + int starte; + int edgecnt = 0; + int found; + int rev; //indicates, that edge is inserted reverse + + //worked edges + ARRAY<int> we(GetNE()); + + //setlineendpoints; wenn 180�, dann keine endpunkte + //nur punkte mit 2 edges kommen in frage, da bei mehr oder weniger punkten ohnehin ein meshpoint hinkommt + + Vec3d v1,v2; + double cos_eca = cos(stlparam.edgecornerangle/180.*M_PI); + int ecnt = 0; + int lp1, lp2; + if (stlparam.edgecornerangle < 180) + { + for (i = 1; i <= GetNP(); i++) + { + if (GetNEPP(i) == 2) + { + if (GetEdge(GetEdgePP(i,1)).PNum(2) == GetEdge(GetEdgePP(i,2)).PNum(1) || + GetEdge(GetEdgePP(i,1)).PNum(1) == GetEdge(GetEdgePP(i,2)).PNum(2)) + { + lp1 = 1; lp2 = 2; + } + else + { + lp1 = 2; lp2 = 1; + } + + v1 = Vec3d(GetPoint(GetEdge(GetEdgePP(i,1)).PNum(1)), + GetPoint(GetEdge(GetEdgePP(i,1)).PNum(2))); + v2 = Vec3d(GetPoint(GetEdge(GetEdgePP(i,2)).PNum(lp1)), + GetPoint(GetEdge(GetEdgePP(i,2)).PNum(lp2))); + if ((v1*v2)/sqrt(v1.Length2()*v2.Length2()) < cos_eca) + { + //(*testout) << "add edgepoint " << i << endl; + SetLineEndPoint(i); + ecnt++; + } + } + } + } + PrintMessage(5, "added ", ecnt, " mesh_points due to edge corner angle (", + stlparam.edgecornerangle, " degree)"); + + for (i = 1; i <= GetNE(); i++) {we.Elem(i) = 0;} + + while(edgecnt < GetNE()) + { + SetThreadPercent((double)edgecnt/(double)GetNE()*100.); + + STLLine* line = new STLLine(this); + + //find start edge + int j = 1; + found = 0; + //try second time, if only rings are left!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + int second = 0; + + //find a starting edge at point with 1 or more than 2 edges or at lineendpoint + while (!found && j<=GetNE()) + { + if (!we.Get(j)) + { + if (GetNEPP(GetEdge(j).PNum(1)) != 2 || IsLineEndPoint(GetEdge(j).PNum(1))) + { + starte = j; + found = 1; + rev = 0; + } + else + if (GetNEPP(GetEdge(j).PNum(2)) != 2 || IsLineEndPoint(GetEdge(j).PNum(2))) + { + starte = j; + found = 1; + rev = 1; + } + else if (second) + { + starte = j; + found = 1; + rev = 0; //0 or 1 are possible + } + } + j++; + if (!second && j == GetNE()) {second = 1; j = 1;} + } + + if (!found) {PrintSysError("No starting edge found, edgecnt=", edgecnt, ", GETNE=", GetNE());} + + line->AddPoint(GetEdge(starte).PNum(1+rev)); + line->AddPoint(GetEdge(starte).PNum(2-rev)); + if (!rev) + { + line->AddLeftTrig(GetEdge(starte).LeftTrig()); + line->AddRightTrig(GetEdge(starte).RightTrig()); + } + else + { + line->AddLeftTrig(GetEdge(starte).RightTrig()); + line->AddRightTrig(GetEdge(starte).LeftTrig()); + } + edgecnt++; we.Elem(starte) = 1; + + //add segments to line as long as segments other than starting edge are found or lineendpoint is reached + found = 1; + int other; + while(found) + { + found = 0; + int fp = GetEdge(starte).PNum(2-rev); + if (GetNEPP(fp) == 2 && !IsLineEndPoint(fp)) + { + //find the "other" edge of point fp + other = 0; + if (GetEdgePP(fp,1) == starte) {other = 1;} + + starte = GetEdgePP(fp,1+other); + + //falls ring -> aufhoeren !!!!!!!!!!! + if (!we.Elem(starte)) + { + found = 1; + rev = 0; + if (GetEdge(starte).PNum(2) == fp) {rev = 1;} + else if (GetEdge(starte).PNum(1) != fp) {PrintSysError("In Link Edges!");} + + line->AddPoint(GetEdge(starte).PNum(2-rev)); + if (!rev) + { + line->AddLeftTrig(GetEdge(starte).LeftTrig()); + line->AddRightTrig(GetEdge(starte).RightTrig()); + } + else + { + line->AddLeftTrig(GetEdge(starte).RightTrig()); + line->AddRightTrig(GetEdge(starte).LeftTrig()); + } + edgecnt++; we.Elem(starte) = 1; + } + } + } + AddLine(line); + } + PrintMessage(5,"number of lines generated = ", GetNLines()); + + //check, which lines must have at least one midpoint + INDEX_2_HASHTABLE<int> lineht(GetNLines()+1); + + for (i = 1; i <= GetNLines(); i++) + { + if (GetLine(i)->StartP() == GetLine(i)->EndP()) + { + GetLine(i)->DoSplit(); + } + } + + for (i = 1; i <= GetNLines(); i++) + { + INDEX_2 lineep (GetLine(i)->StartP(),GetLine(i)->EndP()); + lineep.Sort(); + + if (lineht.Used (lineep)) + { + GetLine(i)->DoSplit(); + int other = lineht.Get(lineep); + GetLine(other)->DoSplit(); + } + else + { + lineht.Set (lineep, i); + } + } + + for (i = 1; i <= GetNLines(); i++) + { + STLLine* line = GetLine(i); + for (int ii = 1; ii <= line->GetNS(); ii++) + { + int p1, p2; + line->GetSeg(ii,p1,p2); + // (*mycout) << "SEG " << p1 << " - " << p2 << endl; + } + } + + PopStatus(); +} + +int STLGeometry :: GetNOBodys() +{ + int markedtrigs = 0; + int starttrig = 1; + int i, k, nnt; + int bodycnt = 0; + + ARRAY<int> bodynum(GetNT()); + + for (i = 1; i <= GetNT(); i++) + bodynum.Elem(i)=0; + + + while (markedtrigs < GetNT()) + { + for (i = starttrig; i <= GetNT(); i++) + { + if (!bodynum.Get(i)) + { + starttrig = i; + break; + } + } + //add all triangles around starttriangle, which is reachable without going over an edge + ARRAY<int> todolist; + ARRAY<int> nextlist; + bodycnt++; + markedtrigs++; + bodynum.Elem(starttrig) = bodycnt; + todolist.Append(starttrig); + int p1, p2; + + while(todolist.Size()) + { + for (i = 1; i <= todolist.Size(); i++) + { + const STLTriangle& tt = GetTriangle(todolist.Get(i)); + for (k = 1; k <= NONeighbourTrigs(todolist.Get(i)); k++) + { + nnt = NeighbourTrig(todolist.Get(i),k); + if (!bodynum.Get(nnt)) + { + nextlist.Append(nnt); + bodynum.Elem(nnt) = bodycnt; + markedtrigs++; + } + } + } + + todolist.SetSize(0); + for (i = 1; i <= nextlist.Size(); i++) + { + todolist.Append(nextlist.Get(i)); + } + nextlist.SetSize(0); + } + } + PrintMessage(3, "Geometry has ", bodycnt, " separated bodys"); + + return bodycnt; +} + +void STLGeometry :: CalcFaceNums() +{ + int markedtrigs = 0; + int starttrig; + int laststarttrig = 1; + int i, k, nnt; + facecnt = 0; + + + for (i = 1; i <= GetNT(); i++) + GetTriangle(i).SetFaceNum(0); + + + while (markedtrigs < GetNT()) + { + for (i = laststarttrig; i <= GetNT(); i++) + { + if (!GetTriangle(i).GetFaceNum()) + { + starttrig = i; + laststarttrig = i; + break; + } + } + //add all triangles around starttriangle, which is reachable without going over an edge + ARRAY<int> todolist; + ARRAY<int> nextlist; + facecnt++; + markedtrigs++; + GetTriangle(starttrig).SetFaceNum(facecnt); + todolist.Append(starttrig); + int p1, p2; + + while(todolist.Size()) + { + for (i = 1; i <= todolist.Size(); i++) + { + const STLTriangle& tt = GetTriangle(todolist.Get(i)); + for (k = 1; k <= NONeighbourTrigs(todolist.Get(i)); k++) + { + nnt = NeighbourTrig(todolist.Get(i),k); + STLTriangle& nt = GetTriangle(nnt); + if (!nt.GetFaceNum()) + { + tt.GetNeighbourPoints(nt,p1,p2); + if (!IsEdge(p1,p2)) + { + nextlist.Append(nnt); + nt.SetFaceNum(facecnt); + markedtrigs++; + } + } + } + } + + todolist.SetSize(0); + for (i = 1; i <= nextlist.Size(); i++) + { + todolist.Append(nextlist.Get(i)); + } + nextlist.SetSize(0); + } + } + GetNOBodys(); + PrintMessage(3,"generated ", facecnt, " faces"); +} + +void STLGeometry :: ClearSpiralPoints() +{ + spiralpoints.SetSize(GetNP()); + int i; + for (i = 1; i <= spiralpoints.Size(); i++) + { + spiralpoints.Elem(i) = 0; + } +} + + +void STLGeometry :: BuildSmoothEdges () +{ + if (smoothedges) delete smoothedges; + + smoothedges = new INDEX_2_HASHTABLE<int> (GetNE()/10 + 1); + + + // Jack: Ok ? + // UseExternalEdges(); + + PushStatusF("Build Smooth Edges"); + + int i, j, k, l; + int nt = GetNT(); + Vec3d ng1, ng2; + + for (i = 1; i <= nt; i++) + { + if (multithread.terminate) + {PopStatus();return;} + + SetThreadPercent(100.0 * (double)i / (double)nt); + + const STLTriangle & trig = GetTriangle (i); + + Vec3d ng1 = trig.GeomNormal(points); + ng1 /= (ng1.Length() + 1e-24); + + for (j = 1; j <= 3; j++) + { + int nbt = NeighbourTrig (i, j); + + Vec3d ng2 = GetTriangle(nbt).GeomNormal(points); + ng2 /= (ng2.Length() + 1e-24); + + + int pi1, pi2; + + trig.GetNeighbourPoints(GetTriangle(nbt), pi1, pi2); + + if (!IsEdge(pi1,pi2)) + { + if (ng1 * ng2 < 0) + { + PrintMessage(7,"smoothedge found"); + INDEX_2 i2(pi1, pi2); + i2.Sort(); + smoothedges->Set (i2, 1); + } + } + } + } + + PopStatus(); +} + + + + + +int STLGeometry :: IsSmoothEdge (int pi1, int pi2) const +{ + if (!smoothedges) + return 0; + INDEX_2 i2(pi1, pi2); + i2.Sort(); + return smoothedges->Used (i2); +} + + + + +//function is not used now +int IsInArray(int n, const ARRAY<int>& ia) +{ + int i; + for (i = 1; i <= ia.Size(); i++) + { + if (ia.Get(i) == n) {return 1;} + } + return 0; +} + +void STLGeometry :: AddConeAndSpiralEdges() +{ + PrintMessage(5,"have now ", GetNE(), " edges with yellow angle = ", stlparam.yangle, " degree"); + + PrintFnStart("AddConeAndSpiralEdges"); + + int i,j,k,n; + // int changed = 0; + + //check edges, where inner chart and no outer chart come together without an edge + int np1, np2, nt; + int cnt = 0; + + for (i = 1; i <= GetNOCharts(); i++) + { + STLChart& chart = GetChart(i); + for (j = 1; j <= chart.GetNChartT(); j++) + { + int t = chart.GetChartTrig(j); + const STLTriangle& tt = GetTriangle(t); + + for (k = 1; k <= 3; k++) + { + nt = NeighbourTrig(t,k); + if (GetChartNr(nt) != i && !TrigIsInOC(nt,i)) + { + tt.GetNeighbourPoints(GetTriangle(nt),np1,np2); + if (!IsEdge(np1,np2)) + { + STLEdge se(np1,np2); + se.SetLeftTrig(t); + se.SetRightTrig(nt); + int edgenum = AddEdge(se); + AddEdgePP(np1,edgenum); + AddEdgePP(np2,edgenum); + //changed = 1; + PrintWarning("Found a spiral like structure: chart=", i, + ", trig=", t, ", p1=", np1, ", p2=", np2); + cnt++; + } + } + } + } + + } + + PrintMessage(5, "found ", cnt, " spiral like structures"); + PrintMessage(5, "added ", cnt, " edges due to spiral like structures"); + + cnt = 0; + int edgecnt = 0; + + ARRAY<int> trigsaroundp; + ARRAY<int> chartpointchecked; //gets number of chart, if in this chart already checked + chartpointchecked.SetSize(GetNP()); + + for (i = 1; i <= GetNP(); i++) + { + chartpointchecked.Elem(i) = 0; + } + + int onoc, notonoc, tpp, pn; + int p1, p2, tn1, tn2, l, problem; + + if (!stldoctor.conecheck) {PrintWarning("++++++++++++ \ncone checking deactivated by user!!!!!\n+++++++++++++++"); return ;} + + PushStatus("Find Critical Points"); + + int addedges = 0; + + for (i = 1; i <= GetNOCharts(); i++) + { + SetThreadPercent((double)i/(double)GetNOCharts()*100.); + if (multithread.terminate) + {PopStatus();return;} + + STLChart& chart = GetChart(i); + for (j = 1; j <= chart.GetNChartT(); j++) + { + int t = chart.GetChartTrig(j); + const STLTriangle& tt = GetTriangle(t); + + for (k = 1; k <= 3; k++) + { + pn = tt.PNum(k); + if (chartpointchecked.Get(pn) == i) + {continue;} + + int checkpoint = 0; + for (n = 1; n <= trigsperpoint.EntrySize(pn); n++) + { + if (trigsperpoint.Get(pn,n) != t && + GetChartNr(trigsperpoint.Get(pn,n)) != i && + !TrigIsInOC(trigsperpoint.Get(pn,n),i)) {checkpoint = 1;}; + } + if (checkpoint) + { + chartpointchecked.Elem(pn) = i; + + int worked = 0; + int spworked = 0; + GetSortedTrianglesAroundPoint(pn,t,trigsaroundp); + trigsaroundp.Append(t); + + problem = 0; + for (l = 2; l <= trigsaroundp.Size()-1; l++) + { + tn1 = trigsaroundp.Get(l-1); + tn2 = trigsaroundp.Get(l); + const STLTriangle& t1 = GetTriangle(tn1); + const STLTriangle& t2 = GetTriangle(tn2); + t1.GetNeighbourPoints(t2, p1, p2); + if (IsEdge(p1,p2)) break; + + if (GetChartNr(tn2) != i && !TrigIsInOC(tn2,i)) {problem = 1;} + } + + if (problem) + { + for (l = 2; l <= trigsaroundp.Size()-1; l++) + { + tn1 = trigsaroundp.Get(l-1); + tn2 = trigsaroundp.Get(l); + const STLTriangle& t1 = GetTriangle(tn1); + const STLTriangle& t2 = GetTriangle(tn2); + t1.GetNeighbourPoints(t2, p1, p2); + if (IsEdge(p1,p2)) break; + + if ((GetChartNr(tn1) == i && GetChartNr(tn2) != i && TrigIsInOC(tn2,i)) || + (GetChartNr(tn2) == i && GetChartNr(tn1) != i && TrigIsInOC(tn1,i))) + { + if (addedges || !GetNEPP(pn)) + { + STLEdge se(p1,p2); + se.SetLeftTrig(tn1); + se.SetRightTrig(tn2); + int edgenum = AddEdge(se); + AddEdgePP(p1,edgenum); + AddEdgePP(p2,edgenum); + edgecnt++; + } + if (!addedges && !GetSpiralPoint(pn)) + { + SetSpiralPoint(pn); + spworked = 1; + } + worked = 1; + } + } + } + //backwards: + problem = 0; + for (l = trigsaroundp.Size()-1; l >= 2; l--) + { + tn1 = trigsaroundp.Get(l+1); + tn2 = trigsaroundp.Get(l); + const STLTriangle& t1 = GetTriangle(tn1); + const STLTriangle& t2 = GetTriangle(tn2); + t1.GetNeighbourPoints(t2, p1, p2); + if (IsEdge(p1,p2)) break; + + if (GetChartNr(tn2) != i && !TrigIsInOC(tn2,i)) {problem = 1;} + } + if (problem) + for (l = trigsaroundp.Size()-1; l >= 2; l--) + { + tn1 = trigsaroundp.Get(l+1); + tn2 = trigsaroundp.Get(l); + const STLTriangle& t1 = GetTriangle(tn1); + const STLTriangle& t2 = GetTriangle(tn2); + t1.GetNeighbourPoints(t2, p1, p2); + if (IsEdge(p1,p2)) break; + + if ((GetChartNr(tn1) == i && GetChartNr(tn2) != i && TrigIsInOC(tn2,i)) || + (GetChartNr(tn2) == i && GetChartNr(tn1) != i && TrigIsInOC(tn1,i))) + { + if (addedges || !GetNEPP(pn)) + { + STLEdge se(p1,p2); + se.SetLeftTrig(tn1); + se.SetRightTrig(tn2); + int edgenum = AddEdge(se); + AddEdgePP(p1,edgenum); + AddEdgePP(p2,edgenum); + edgecnt++; + } + if (!addedges && !GetSpiralPoint(pn)) + { + SetSpiralPoint(pn); + spworked = 1; + //if (GetNEPP(pn) == 0) {(*mycout) << "ERROR: spiralpoint with no edge found!" << endl;} + } + worked = 1; + } + } + + if (worked) + { + //(*testout) << "set edgepoint due to spirals: pn=" << i << endl; + SetLineEndPoint(pn); + } + if (spworked) + { + /* + (*mycout) << "Warning: Critical Point " << tt.PNum(k) + << "( chart " << i << ", trig " << t + << ") has been neutralized!!!" << endl; + */ + cnt++; + } + // markedpoints.Elem(tt.PNum(k)) = 1; + } + } + } + } + PrintMessage(5, "found ", cnt, " critical points!"); + PrintMessage(5, "added ", edgecnt, " edges due to critical points!"); + + PopStatus(); + + //search points where inner chart and outer chart and "no chart" trig come together at edge-point + + PrintMessage(7,"search for special chart points"); + for (i = 1; i <= GetNOCharts(); i++) + { + STLChart& chart = GetChart(i); + for (j = 1; j <= chart.GetNChartT(); j++) + { + int t = chart.GetChartTrig(j); + const STLTriangle& tt = GetTriangle(t); + + for (k = 1; k <= 3; k++) + { + pn = tt.PNum(k); + if (GetNEPP(pn) == 2) + { + onoc = 0; + notonoc = 0; + for (n = 1; n <= trigsperpoint.EntrySize(pn); n++) + { + tpp = trigsperpoint.Get(pn,n); + if (tpp != t && GetChartNr(tpp) != i) + { + if (TrigIsInOC(tpp,i)) {onoc = 1;} + if (!TrigIsInOC(tpp,i)) {notonoc = 1;} + } + } + if (onoc && notonoc && !IsLineEndPoint(pn)) + { + GetSortedTrianglesAroundPoint(pn,t,trigsaroundp); + int here = 1; //we start on this side of edge, !here = there + int thereOC = 0; + int thereNotOC = 0; + for (l = 2; l <= trigsaroundp.Size(); l++) + { + GetTriangle(trigsaroundp.Get(l-1)). + GetNeighbourPoints(GetTriangle(trigsaroundp.Get(l)), p1, p2); + if (IsEdge(p1,p2)) {here = (here+1)%2;} + if (!here && TrigIsInOC(trigsaroundp.Get(l),i)) {thereOC = 1;} + if (!here && !TrigIsInOC(trigsaroundp.Get(l),i)) {thereNotOC = 1;} + } + if (thereOC && thereNotOC) + { + //(*mycout) << "Special OCICnotC - point " << pn << " found!" << endl; + //(*testout) << "set edgepoint due to spirals: pn=" << i << endl; + SetLineEndPoint(pn); + } + } + } + } + } + } + PrintMessage(5,"have now ", GetNE(), " edges with yellow angle = ", stlparam.yangle, " degree"); +} + +//get trigs at a point, started with starttrig, then every left +void STLGeometry :: GetSortedTrianglesAroundPoint(int p, int starttrig, ARRAY<int>& trigs) +{ + int acttrig = starttrig; + trigs.SetAllocSize(trigsperpoint.EntrySize(p)); + trigs.SetSize(0); + trigs.Append(acttrig); + int i, j, t, p1, p2, locindex1, locindex2; + + //(*mycout) << "trigs around point " << p << endl; + + int end = 0; + while (!end) + { + const STLTriangle& at = GetTriangle(acttrig); + for (i = 1; i <= trigsperpoint.EntrySize(p); i++) + { + t = trigsperpoint.Get(p,i); + const STLTriangle& nt = GetTriangle(t); + if (at.IsNeighbourFrom(nt)) + { + at.GetNeighbourPoints(nt, p1, p2); + if (p2 == p) {Swap(p1,p2);} + if (p1 != p) {PrintSysError("In GetSortedTrianglesAroundPoint!!!");} + + for (j = 1; j <= 3; j++) + { + if (at.PNum(j) == p1) {locindex1 = j;}; + if (at.PNum(j) == p2) {locindex2 = j;}; + } + if ((locindex2+1)%3+1 == locindex1) + { + if (t != starttrig) + { + trigs.Append(t); + // (*mycout) << "trig " << t << endl; + acttrig = t; + } + else + { + end = 1; + } + break; + } + } + } + } + +} + +/* +int STLGeometry :: NeighbourTrig(int trig, int nr) const +{ + return neighbourtrigs.Get(trig,nr); +} +*/ + + + +void STLGeometry :: SmoothGeometry () +{ + int i, j, k; + + int np = GetNP(); + double maxerr0, maxerr; + + for (i = 1; i <= np; i++) + { + if (GetNEPP(i)) continue; + + maxerr0 = 0; + for (j = 1; j <= NOTrigsPerPoint(i); j++) + { + int tnum = TrigPerPoint(i, j); + double err = Angle (GetTriangle(tnum).Normal (), + GetTriangle(tnum).GeomNormal(GetPoints())); + if (err > maxerr0) + maxerr0 = err; + } + + Point3d pi = GetPoint (i); + if (maxerr0 < 1.1) continue; // about 60 degree + + maxerr0 /= 2; // should be at least halfen + + for (k = 1; k <= NOTrigsPerPoint(i); k++) + { + const STLTriangle & trig = GetTriangle (TrigPerPoint (i, k)); + Point3d c = Center(GetPoint (trig.PNum(1)), + GetPoint (trig.PNum(2)), + GetPoint (trig.PNum(3))); + + Point3d np = pi + 0.1 * (c - pi); + SetPoint (i, np); + + maxerr = 0; + for (j = 1; j <= NOTrigsPerPoint(i); j++) + { + int tnum = TrigPerPoint(i, j); + double err = Angle (GetTriangle(tnum).Normal (), + GetTriangle(tnum).GeomNormal(GetPoints())); + if (err > maxerr) + maxerr = err; + } + + if (maxerr < maxerr0) + { + pi = np; + } + } + + SetPoint (i, pi); + } +} +} diff --git a/contrib/Netgen/libsrc/stlgeom/stlgeom.hpp b/contrib/Netgen/libsrc/stlgeom/stlgeom.hpp new file mode 100644 index 0000000000..c9bfb1e535 --- /dev/null +++ b/contrib/Netgen/libsrc/stlgeom/stlgeom.hpp @@ -0,0 +1,450 @@ +#ifndef FILE_STLGEOM +#define FILE_STLGEOM + +/**************************************************************************/ +/* File: stlgeom.hpp */ +/* Author: Joachim Schoeberl */ +/* Author2: Johannes Gerstmayr */ +/* Date: 26. Jul. 99 */ +/**************************************************************************/ + +/** + STL Geometry + + + Terminology: + + Point ... coordinates of STL triangles + Triangle (short Trig) STL triangle + TopEdge .... edge in topology, boundary of STL triangles (many) + Edge .... Edges which will occur in the mesh (confirmed edges, less) +*/ + + +#include <gprim.hpp> +#include <meshing.hpp> + + + +namespace netgen +{ + extern int IsInArray(int n, const ARRAY<int>& ia); + extern int AddIfNotExists(ARRAY<int>& list, int x); + + +#include "stltopology.hpp" +#include "stltool.hpp" +#include "stlline.hpp" + + + + + + + + class STLEdgeDataList + { + ARRAY<int> storedstatus; + STLTopology & geom; + public: + + STLEdgeDataList(STLTopology & ageom); + ~STLEdgeDataList(); + + void Store (); + void Restore (); + + void SetSize(int /* size */) { }; + void Clear() { }; + int Size() const { return geom.GetNTE(); } + const STLTopEdge & Get(int i) const { return geom.GetTopEdge(i); } + STLTopEdge & Elem(int i) { return geom.GetTopEdge(i); } + + int GetNEPP(int pn) const {return geom.NTopEdgesPerPoint(pn); } + int GetEdgePP(int pn, int vi) const {return geom.TopEdgePerPoint(pn, vi);}; + + //void AddEdgePP(int pn, int vn) { } ; + + void ResetAll(); + void ChangeStatus(int status1, int status2); + + int GetEdgeNum(int np1, int np2) const + { return geom.GetTopEdgeNum (np1, np2); } + + int GetNConfEdges() const; + + void Write(ofstream& of) const; + void Read(ifstream& ifs); + + void BuildLineWithEdge(int ep1, int ep2, ARRAY<twoint>& line); + void BuildClusterWithEdge(int ep1, int ep2, ARRAY<twoint>& line); + + int GetNEPPStat(int p, int status) const; + int GetNConfCandEPP(int p) const; + }; + + + + + + + class STLGeometry : public STLTopology + { + // edges to be meshed: + ARRAY<STLEdge> edges; + //edges per point + TABLE<int> edgesperpoint; + + // line: a connection of edges + ARRAY<STLLine*> lines; + ARRAY<int> lineendpoints; //per geometrypoint, 1 = is endpoint; 0 = no endpoint, + + ARRAY<Vec3d> normals; //normals belong to points! + + ARRAY<twoint> externaledges; + + int undoexternaledges; + ARRAY<twoint> storedexternaledges; + + STLEdgeDataList edgedata; + // STLEdgeDataList edgedata_store; + int calcedgedataanglesnew; + + int edgedatastored; + + + + int facecnt; + //meshpoint is only set, if an edge is at this point!!! + + ARRAY<int> vicinity; //is one, if a triangle belongs to vicinity (eg. of selecttrig) + ARRAY<int> markedtrigs; //is one, if a triangle belongs to marked triangles (calcdirtystrigs) + ARRAY<Point3d> markedsegs; //every pointpair is a segment!!! + ARRAY<twoint> selectedmultiedge; + + + //spiralpoints: + ARRAY<int> spiralpoints; + // + ARRAY<STLChart*> atlas; + //marks all already charted trigs with chartnumber + ARRAY<int> chartmark; + //outerchartspertrig, ascending sorted + TABLE<int> outerchartspertrig; + + + //for meshing and project: + ARRAY<int> meshcharttrigs; //per trig: 1=belong to chart, 0 not + int meshchart; + + ARRAY<int> ha_points; // help array, np long, filled with 0 + + + // sharp geometric edges not declared as edges + // (not considered for spiral check) + INDEX_2_HASHTABLE<int> * smoothedges; + + + //transformation: + Vec<3> meshtrignv; + Vec<3> ex, ey, ez; + Point<3> p1; + + public: + int edgesfound; + int surfacemeshed; + int surfaceoptimized; + int volumemeshed; + + int trigsconverted; //when STLTriangles exist -> 1 + + //for selecting nodes + //int selecttrig, nodeofseltrig; + + //only for testing; + ARRAY<STLLine*> meshlines; + ARRAY<Point3d> meshpoints; + + public: + STLGeometry(); + virtual ~STLGeometry(); + + + void Clear(); + + + + void STLInfo(double* data); + //stldoctor: + void SmoothNormals(); + void MarkNonSmoothNormals(); + + void CalcEdgeData(); + void CalcEdgeDataAngles(); + + const STLEdgeDataList& EdgeDataList() const {return edgedata;} + + void UndoEdgeChange(); + void StoreEdgeData(); + void RestoreEdgeData(); + + //void ClearSelectedMultiEdge() {selectedmultiedge.SetSize(0);} + //void AddSelectedMultiEdge(twoint ep) {selectedmultiedge.Append(ep);} + //int SelectedMultiEdgeSize() {return selectedmultiedge.Size();} + const ARRAY<twoint>& SelectedMultiEdge() {return selectedmultiedge;} + twoint GetNearestSelectedDefinedEdge(); + void BuildSelectedMultiEdge(twoint ep); + void BuildSelectedEdge(twoint ep); + void BuildSelectedCluster(twoint ep); + + void ImportEdges(); + void AddEdges(const ARRAY<Point<3> >& eps); + void ExportEdges(); + void LoadEdgeData(const char* file); + void SaveEdgeData(const char* file); + // void SetEdgeAtSelected(int mode); + + + void STLDoctorConfirmEdge(); + void STLDoctorCandidateEdge(); + void STLDoctorExcludeEdge(); + void STLDoctorUndefinedEdge(); + + void STLDoctorSetAllUndefinedEdges(); + void STLDoctorEraseCandidateEdges(); + void STLDoctorConfirmCandidateEdges(); + void STLDoctorConfirmedToCandidateEdges(); + + void STLDoctorDirtyEdgesToCandidates(); + void STLDoctorLongLinesToCandidates(); + + void UndoExternalEdges(); + void StoreExternalEdges(); + void RestoreExternalEdges(); + + void ImportExternalEdges(const char * filename); // Flame edges, JS + // void LoadExternalEdges(); + + void BuildExternalEdgesFromEdges(); + void SaveExternalEdges(); + void AddExternalEdgeAtSelected(); + void AddClosedLinesToExternalEdges(); + void AddLongLinesToExternalEdges(); + void AddAllNotSingleLinesToExternalEdges(); + void STLDoctorBuildEdges(); + void AddExternalEdgesFromGeomLine(); + void DeleteDirtyExternalEdges(); + void DeleteExternalEdgeAtSelected(); + void DeleteExternalEdgeInVicinity(); + void AddExternalEdge(int p1, int p2); + void DeleteExternalEdge(int p1, int p2); + int IsExternalEdge(int p1, int p2); + int NOExternalEdges() const {return externaledges.Size();} + twoint GetExternalEdge(int i) const {return externaledges.Get(i);} + + void DestroyDirtyTrigs(); + void CalcNormalsFromGeometry(); + void MoveSelectedPointToMiddle(); + void NeighbourAnglesOfSelectedTrig(); + void PrintSelectInfo(); + void ShowSelectedTrigChartnum(); + void ShowSelectedTrigCoords(); + void SmoothGeometry (); + + + void LoadMarkedTrigs(); + void SaveMarkedTrigs(); + void ClearMarkedSegs() {markedsegs.SetSize(0);} + void AddMarkedSeg(const Point<3> & p1, const Point<3> & p2) + { + markedsegs.Append(p1);markedsegs.Append(p2); + } + + void GetMarkedSeg(int i, Point<3> & p1, Point<3> & p2) + { + p1=markedsegs.Get(i*2-1); + p2=markedsegs.Get(i*2); + } + int GetNMarkedSegs() {return markedsegs.Size()/2;} + void CalcVicinity(int starttrig); + void GetVicinity(int starttrig, int size, ARRAY<int>& vic); + + int Vicinity(int trig) const; + + void InitMarkedTrigs(); + void MarkDirtyTrigs(); + void SmoothDirtyTrigs(); + void GeomSmoothRevertedTrigs(); + void MarkRevertedTrigs(); + double CalcTrigBadness(int i); + int IsMarkedTrig(int trig) const; + void SetMarkedTrig(int trig, int num); + void MarkTopErrorTrigs (); + + //Selected triangle + void SetSelectTrig(int trig); + int GetSelectTrig() const; + void SetNodeOfSelTrig(int n); + int GetNodeOfSelTrig() const; + + + int AddNormal(const Vec3d& n) {return normals.Append(n);} + const Vec3d & GetNormal(int nr) const {return normals.Get(nr);} + void SetNormal(int nr, const Vec3d& n) {normals.Elem(nr) = n;} + + int AddEdge(const STLEdge& v) {return edges.Append(v);} + int AddEdge(int p1, int p2); + + STLEdge GetEdge(int nr) {return edges.Get(nr);} + int GetNE() {return edges.Size();} + + double Area(); + + double GetAngle(int t1, int t2); + double GetGeomAngle(int t1, int t2); + //if triangles t1 and t2 touch, return 1 and in p1, p2 the touching points + //int TrigsTouch(int t1, int t2, int& p1, int& p2); + + + + /// + + ///ReadTriangle->STLTriangle, initialise some important variables, always after load!!! + virtual void InitSTLGeometry (const ARRAY<STLReadTriangle> & readtrigs); + virtual void TopologyChanged(); //do some things, if topology changed! + int CheckGeometryOverlapping(); + + //get NO edges per point + int GetEPPSize() const {return edgesperpoint.Size();}; + int GetNEPP(int pn) + { + if (edgesperpoint.Size() == 0) {BuildEdgesPerPoint();} + return edgesperpoint.EntrySize(pn); + }; + int GetEdgePP(int pn, int vi) + { + if (edgesperpoint.Size() == 0) {BuildEdgesPerPoint();} + return edgesperpoint.Get(pn,vi); + }; + void AddEdgePP(int pn, int vn) {edgesperpoint.Add1(pn,vn);}; + //von 2 punkten ermitteln, ob sie eine Kante sind + int IsEdge(int p1, int p2); + int IsEdgeNum(int p1, int p2); + + ///Build EdgeSegments + void ClearEdges(); + void BuildEdges(); + void BuildEdgesPerPoint(); + void UseExternalEdges(); + + + void FindEdgesFromAngles(); + void CalcFaceNums(); + int GetNOBodys(); + int GetNOFaces() {return facecnt;} + void LinkEdges(); + + void AddConeAndSpiralEdges(); + void AddFaceEdges(); //each face should have at least one starting edge (outherwise it won't be meshed) + + void GetDirtyChartTrigs(int chartnum, STLChart& chart, const ARRAY<int>& outercharttrigs, + ARRAY<int>& chartpointchecked, ARRAY<int>& dirtytrigs); + + void ClearSpiralPoints(); + void SetSpiralPoint(int pn) {spiralpoints.Elem(pn) = 1;}; + int GetSpiralPoint(int pn) const {return spiralpoints.Get(pn);}; + + void GetSortedTrianglesAroundPoint(int p, int starttrig, ARRAY<int>& trigs); + + // smooth edges: sharp geometric edges not declared as edges + void BuildSmoothEdges (); + int IsSmoothEdge (int pi1, int pi2) const; + + + //make charts with regions of a max. angle + void MakeAtlas(class Mesh & mesh); + + //outerchartspertrig, sorted! + int GetOCPTSize() const {return outerchartspertrig.Size();}; + int GetNOCPT(int tn) const {return outerchartspertrig.EntrySize(tn);}; + int GetOCPT(int tn, int vi) const {return outerchartspertrig.Get(tn,vi);}; + void SetOCPT(int tn, int vi, int ocn) {outerchartspertrig.Set(tn,vi,ocn);}; + void AddOCPT(int tn, int ocn) {outerchartspertrig.Add1(tn, ocn);}; + int TrigIsInOC(int tn, int ocn) const; + + //get chart number of a trig or 0 if unmarked + int GetChartNr(int i) const; + int GetMarker(int i) const + { return chartmark.Get(i); } + void SetMarker(int nr, int m); + int GetNOCharts() const; + //get a chart from atlas + const STLChart& GetChart(int nr) const; + STLChart& GetChart(int nr) {return *(atlas.Get(nr));}; + int AtlasMade() const; + + void GetInnerChartLimes(ARRAY<twoint>& limes, int chartnum); + + //FOR MESHING + int GetMeshChartNr () { return meshchart; } + void GetMeshChartBoundary (ARRAY<Point2d > & points, + ARRAY<Point3d > & points3d, + ARRAY<INDEX_2> & lines, double h); + + + Point<3> PointBetween(const Point<3> & p1, int t1, const Point<3> & p2, int t2); + + //select triangles in meshcharttrigs of actual (defined by trig) whole chart + void PrepareSurfaceMeshing(); + // + void DefineTangentialPlane(const Point<3> & ap1, const Point<3> & ap2, int trig); + // + void SelectChartOfTriangle (int trignum); + // + void SelectChartOfPoint (const Point<3> & p); + // + const Vec<3> & GetChartNormalVector () const { return meshtrignv; } + + // list of trigs + void ToPlane (const Point<3> & locpoint, int * trigs, Point<2> & plainpoint, + double h, int& zone, int checkchart); + //return 0, wenn alles OK, 1 sonst + int FromPlane (const Point<2> & plainpoint, Point<3> & locpoint, double h); + + //get nearest point in actual chart and return any triangle where it lies on + int ProjectNearest(Point<3> & p3d) const; + //project point with normal nv from last define tangential plane + + int LastTrig() const; + int Project(Point<3> & p3d) const; + int ProjectOnWholeSurface (Point<3> & p3d) const; + + int GetNLines() const {return lines.Size();} + int AddLine(STLLine* line) {return lines.Append(line);} + STLLine* GetLine(int nr) const {return lines.Get(nr);} + int GetLineP(int lnr, int pnr) const {return lines.Get(lnr)->PNum(pnr);} + int GetLineNP(int nr) const {return lines.Get(nr)->NP();} + + void SetLineEndPoint(int pn); + int IsLineEndPoint(int pn); + int LineEndPointsSet() const {return lineendpoints.Size() == GetNP();} + void ClearLineEndPoints(); + + void RestrictLocalH(class Mesh & mesh, double gh); + void RestrictLocalHCurv(class Mesh & mesh, double gh); + void RestrictHChartDistOneChart(int chartnum, ARRAY<int>& acttrigs, class Mesh & mesh, + double gh, double fact, double minh); + + friend class MeshingSTLSurface; + }; + + +#include "meshstlsurface.hpp" + + + extern int STLMeshingDummy (STLGeometry* stlgeometry, Mesh*& mesh, + int perfstepsstart, int perfstepsend, char* optstring); + + +} +#endif diff --git a/contrib/Netgen/libsrc/stlgeom/stlgeomchart.cpp b/contrib/Netgen/libsrc/stlgeom/stlgeomchart.cpp new file mode 100644 index 0000000000..c2f64f5f1f --- /dev/null +++ b/contrib/Netgen/libsrc/stlgeom/stlgeomchart.cpp @@ -0,0 +1,801 @@ +//20.11.1999 third part of stlgeom.cc, functions with chart and atlas + +#include <mystdlib.h> + +#include <myadt.hpp> +#include <linalg.hpp> +#include <gprim.hpp> + +#include <meshing.hpp> + +#include "stlgeom.hpp" + +namespace netgen +{ + +int chartdebug = 0; + + + +void STLGeometry :: MakeAtlas(Mesh & mesh) +{ + + double h, h2; + + h = mparam.maxh; + + + PushStatusF("Make Atlas"); + + int i,j,k,l,m,ctl; + + double atlasminh = 5e-3 * Dist (boundingbox.PMin(), boundingbox.PMax()); + PrintMessage(5, "atlasminh = ", atlasminh); + + //speedup for make atlas + if (GetNT() > 50000) + { + mesh.SetGlobalH(0.05*Dist (boundingbox.PMin(), boundingbox.PMax())); + } + + + atlas.SetSize(0); + ClearSpiralPoints(); + BuildSmoothEdges(); + + + double chartangle = stlparam.chartangle; + double outerchartangle = stlparam.outerchartangle; + + chartangle = chartangle/180.*M_PI; + outerchartangle = outerchartangle/180.*M_PI; + + double coschartangle = cos(chartangle); + double cosouterchartangle = cos(outerchartangle); + double cosouterchartanglehalf = cos(0.5*outerchartangle); + double sinchartangle = sin(chartangle); + double sinouterchartangle = sin(outerchartangle); + + ARRAY<int> outermark(GetNT()); //marks all trigs form actual outer region + ARRAY<int> outertested(GetNT()); //marks tested trigs for outer region + ARRAY<int> pointstochart(GetNP()); //point in chart becomes chartnum + ARRAY<int> innerpointstochart(GetNP()); //point in chart becomes chartnum + ARRAY<int> chartpoints; //point in chart becomes chartnum + ARRAY<int> innerchartpoints; + ARRAY<int> dirtycharttrigs; + ARRAY<int> chartpointchecked; + + ARRAY<int> chartdistacttrigs; //outercharttrigs + chartdistacttrigs.SetSize(GetNT()); + for (i = 1; i <= GetNT(); i++) + { + chartdistacttrigs.Elem(i) = 0; + } + + STLBoundary chartbound(this); //knows the actual chart boundary + int chartboundarydivisions = 10; + markedsegs.SetSize(0); //for testing!!! + + chartpointchecked.SetSize(GetNP()); //for dirty-chart-trigs + + outermark.SetSize(GetNT()); + outertested.SetSize(GetNT()); + pointstochart.SetSize(GetNP()); + innerpointstochart.SetSize(GetNP()); + chartmark.SetSize(GetNT()); + + for (i = 1; i <= GetNP(); i++) + { + innerpointstochart.Elem(i) = 0; + pointstochart.Elem(i) = 0; + chartpointchecked.Elem(i) = 0; + } + + double eps = 1e-12 * Dist (boundingbox.PMin(), boundingbox.PMax()); + + int spiralcheckon = stldoctor.spiralcheck; + if (!spiralcheckon) {PrintWarning("++++++++++++\nspiral deactivated by user!!!!\n+++++++++++++++"); } + + for (i = 1; i <= GetNT(); i++) + { + chartmark.Elem(i) = 0; + } + + for (i = 1; i <= GetNT(); i++) + { + outermark.Elem(i) = 0; + outertested.Elem(i) = 0; + } + + int markedtrigcnt = 0; + int found = 1; + double atlasarea = Area(); + double workedarea = 0; + double showinc = 100.*5000./(double)GetNT(); + double nextshow = 0; + Point<3> startp; + int lastunmarked = 1; + int prelastunmarked; + + PrintMessage(5,"one dot per 5000 triangles: "); + + while(markedtrigcnt < GetNT() && found) + { + if (multithread.terminate) + {PopStatus();return;} + + if (workedarea / atlasarea*100. >= nextshow) + {PrintDot(); nextshow+=showinc;} + + SetThreadPercent(100.0 * workedarea / atlasarea); + + /* + for (j = 1; j <= GetNT(); j++) + { + outermark.Elem(j) = 0; + } + */ + STLChart * chart = new STLChart(this); + atlas.Append(chart); + + //find unmarked trig + prelastunmarked = lastunmarked; + j = lastunmarked; + found = 0; + while (!found && j <= GetNT()) + { + if (!GetMarker(j)) {found = 1; lastunmarked = j;} + else {j++;} + } + + chartpoints.SetSize(0); + innerchartpoints.SetSize(0); + chartbound.Clear(); + chartbound.SetChart(chart); + + if (!found) {PrintSysError("Make Atlas, no starttrig found"); return;} + + //find surrounding trigs + int starttrig = j; + + double mindist, tdist; + startp = GetPoint(GetTriangle(starttrig).PNum(1)); + + int accepted; + int chartnum = GetNOCharts(); + + Vec<3> sn = GetTriangle(starttrig).Normal(); + chart->SetNormal (startp, sn); + + + SetMarker(starttrig, chartnum); + markedtrigcnt++; + chart->AddChartTrig(starttrig); + chartbound.AddTriangle(GetTriangle(starttrig)); + + workedarea += GetTriangle(starttrig).Area(points); + + for (i = 1; i <= 3; i++) + { + innerpointstochart.Elem(GetTriangle(starttrig).PNum(i)) = chartnum; + pointstochart.Elem(GetTriangle(starttrig).PNum(i)) = chartnum; + chartpoints.Append(GetTriangle(starttrig).PNum(i)); + innerchartpoints.Append(GetTriangle(starttrig).PNum(i)); + } + + Vec<3> n2, n3; + int changed = 1; + int nt; + int ic; + int oldstartic = 1; + int oldstartic2; + int np1, np2; + + while (changed) + { + changed = 0; + oldstartic2 = oldstartic; + oldstartic = chart->GetNT(); + // for (ic = oldstartic2; ic <= chart->GetNT(); ic++) + for (ic = oldstartic2; ic <= oldstartic; ic++) + { + i = chart->GetTrig(ic); + if (GetMarker(i) == chartnum) + { + for (j = 1; j <= NONeighbourTrigs(i); j++) + { + nt = NeighbourTrig(i,j); + GetTriangle(i).GetNeighbourPoints(GetTriangle(nt),np1,np2); + if (GetMarker(nt) == 0 && !IsEdge(np1,np2)) + { + n2 = GetTriangle(nt).Normal(); + if ( (n2 * sn) >= coschartangle ) + { + + accepted = 1; + /* + //alter spiralentest, schnell, aber ungenau + for (k = 1; k <= 3; k++) + { + //find overlapping charts: + Point3d pt = GetPoint(GetTriangle(nt).PNum(k)); + if (innerpointstochart.Get(GetTriangle(nt).PNum(k)) != chartnum) + { + for (l = 1; l <= chartpoints.Size(); l++) + { + Vec3d vptpl(GetPoint(chartpoints.Get(l)), pt); + double vlen = vptpl.Length(); + if (vlen > 0) + { + vptpl /= vlen; + if ( fabs( vptpl * sn) > sinchartangle ) + { + accepted = 0; + break; + } + } + } + + } + } + */ + + int nnp1, nnp2; + int nnt; + //find overlapping charts exacter: + for (k = 1; k <= 3; k++) + { + nnt = NeighbourTrig(nt,k); + if (GetMarker(nnt) != chartnum) + { + GetTriangle(nt).GetNeighbourPoints(GetTriangle(nnt),nnp1,nnp2); + + accepted = chartbound.TestSeg(GetPoint(nnp1), + GetPoint(nnp2), + sn,sinchartangle,1 /*chartboundarydivisions*/ ,points, eps); + + + n3 = GetTriangle(nnt).Normal(); + if ( (n3 * sn) >= coschartangle && + IsSmoothEdge (nnp1, nnp2) ) + accepted = 1; + } + if (!accepted) {break;} + } + + /* + mindist = 1E50; + for (int ii = 1; ii <= 3; ii++) + { + tdist = Dist(GetPoint(GetTriangle(nt).PNum(ii)),startp); + if (tdist < mindist) {mindist = tdist;} + } + if (mindist > maxdist1) {accepted = 0;} + */ + + if (accepted) + { + SetMarker(nt, chartnum); + changed = 1; + markedtrigcnt++; + workedarea += GetTriangle(nt).Area(points); + chart->AddChartTrig(nt); + + chartbound.AddTriangle(GetTriangle(nt)); + + for (k = 1; k <= 3; k++) + { + if (innerpointstochart.Get(GetTriangle(nt).PNum(k)) + != chartnum) + { + innerpointstochart.Elem(GetTriangle(nt).PNum(k)) = chartnum; + pointstochart.Elem(GetTriangle(nt).PNum(k)) = chartnum; + chartpoints.Append(GetTriangle(nt).PNum(k)); + innerchartpoints.Append(GetTriangle(nt).PNum(k)); + } + } + } + } + } + } + } + } + } + + + //find outertrigs + + // chartbound.Clear(); + // warum, ic-bound auf edge macht Probleme js ??? + + + outermark.Elem(starttrig) = chartnum; + //chart->AddOuterTrig(starttrig); + changed = 1; + oldstartic = 1; + while (changed) + { + changed = 0; + oldstartic2 = oldstartic; + oldstartic = chart->GetNT(); + //for (ic = oldstartic2; ic <= chart->GetNT(); ic++) + for (ic = oldstartic2; ic <= oldstartic; ic++) + { + i = chart->GetTrig(ic); + + if (outermark.Get(i) == chartnum) + { + for (j = 1; j <= NONeighbourTrigs(i); j++) + { + nt = NeighbourTrig(i,j); + if (outermark.Get(nt) == chartnum) + continue; + + const STLTriangle & ntrig = GetTriangle(nt); + GetTriangle(i).GetNeighbourPoints(GetTriangle(nt),np1,np2); + + if (IsEdge (np1, np2)) + continue; + + + /* + if (outertested.Get(nt) == chartnum) + continue; + */ + outertested.Elem(nt) = chartnum; + + + n2 = GetTriangle(nt).Normal(); + /* + double ang; + ang = Angle(n2,sn); + if (ang < -M_PI*0.5) {ang += 2*M_PI;} + + (*testout) << "ang < ocharang = " << (fabs(ang) <= outerchartangle); + (*testout) << " = " << ( (n2 * sn) >= cosouterchartangle) << endl; + + // if (fabs(ang) <= outerchartangle) + */ + //abfragen, ob noch im tolerierten Winkel + if ( (n2 * sn) >= cosouterchartangle ) + { + accepted = 1; + + int isdirtytrig = 0; + Vec<3> gn = GetTriangle(nt).GeomNormal(points); + double gnlen = gn.Length(); + + if (n2 * gn <= cosouterchartanglehalf * gnlen) + {isdirtytrig = 1;} + + //zurueckweisen, falls eine Spiralartige outerchart entsteht + int nnp1, nnp2; + int nnt; + //find overlapping charts exacter: + //do not check dirty trigs! + + + if (spiralcheckon && !isdirtytrig) + for (k = 1; k <= 3; k++) + { + nnt = NeighbourTrig(nt,k); + + if (outermark.Elem(nnt) != chartnum) + { + GetTriangle(nt).GetNeighbourPoints(GetTriangle(nnt),nnp1,nnp2); + + accepted = + chartbound.TestSeg(GetPoint(nnp1),GetPoint(nnp2), + sn,sinouterchartangle, 0 /*chartboundarydivisions*/ ,points, eps); + + + n3 = GetTriangle(nnt).Normal(); + if ( (n3 * sn) >= cosouterchartangle && + IsSmoothEdge (nnp1, nnp2) ) + accepted = 1; + } + if (!accepted) {break;} + } + + //} + + + // outer chart is only small environment of + // inner chart: + if (accepted) + { + accepted = 0; + + for (k = 1; k <= 3; k++) + { + if (innerpointstochart.Get(ntrig.PNum(k)) == chartnum) + { + accepted = 1; + break; + } + } + + if (!accepted) + for (k = 1; k <= 3; k++) + { + Point<3> pt = GetPoint(ntrig.PNum(k)); + h2 = sqr(mesh.GetH(pt)); + + for (l = 1; l <= innerchartpoints.Size(); l++) + { + tdist = Dist2(pt, GetPoint (innerchartpoints.Get(l))); + if (tdist < 4 * h2) + { + accepted = 1; + break; + } + } + if (accepted) {break;} + } + } + + + if (accepted) + { + changed = 1; + outermark.Elem(nt) = chartnum; + + if (GetMarker(nt) != chartnum) + { + chartbound.AddTriangle(GetTriangle(nt)); + chart->AddOuterTrig(nt); + for (k = 1; k <= 3; k++) + { + if (pointstochart.Get(GetTriangle(nt).PNum(k)) + != chartnum) + { + pointstochart.Elem(GetTriangle(nt).PNum(k)) = chartnum; + chartpoints.Append(GetTriangle(nt).PNum(k)); + } + } + } + } + } + } + } + } + } + //end of while loop for outer chart + GetDirtyChartTrigs(chartnum, *chart, outermark, chartpointchecked, dirtycharttrigs); + //dirtycharttrigs are local (chart) point numbers!!!!!!!!!!!!!!!! + + if (dirtycharttrigs.Size() != 0 && + (dirtycharttrigs.Size() != chart->GetNChartT() || dirtycharttrigs.Size() != 1)) + { + if (dirtycharttrigs.Size() == chart->GetNChartT() && dirtycharttrigs.Size() != 1) + { + //if all trigs would be eliminated -> leave 1 trig! + dirtycharttrigs.SetSize(dirtycharttrigs.Size() - 1); + } + for (k = 1; k <= dirtycharttrigs.Size(); k++) + { + int tn = chart->GetChartTrig(dirtycharttrigs.Get(k)); + outermark.Elem(tn) = 0; //not necessary, for later use + SetMarker(tn, 0); + markedtrigcnt--; + workedarea -= GetTriangle(tn).Area(points); + } + chart->MoveToOuterChart(dirtycharttrigs); + lastunmarked = 1; + lastunmarked = prelastunmarked; + } + + //calculate an estimate meshsize, not to produce to large outercharts, with factor 2 larger! + RestrictHChartDistOneChart(chartnum, chartdistacttrigs, mesh, h, 0.5, atlasminh); + } + + PrintMessage(5,""); + PrintMessage(5,"NO charts=", atlas.Size()); + + int cnttrias = 0; + //int found2; + outerchartspertrig.SetSize(GetNT()); + + for (i = 1; i <= atlas.Size(); i++) + { + int j; + //found2 = 1; + for (j = 1; j <= GetChart(i).GetNT(); j++) + { + int tn = GetChart(i).GetTrig(j); + AddOCPT(tn,i); + + } + + cnttrias += GetChart(i).GetNT(); + } + PrintMessage(5, "NO outer chart trias=", cnttrias); + + //sort outerchartspertrig + for (i = 1; i <= GetNT(); i++) + { + int j,k, swap; + for (k = 1; k < GetNOCPT(i); k++) + { + + for (j = 1; j < GetNOCPT(i); j++) + { + swap = GetOCPT(i,j); + if (GetOCPT(i,j+1) < swap) + { + SetOCPT(i,j,GetOCPT(i,j+1)); + SetOCPT(i,j+1,swap); + } + } + } + + // check make atlas + if (GetChartNr(i) <= 0 || GetChartNr(i) > GetNOCharts()) + { + PrintSysError("Make Atlas: chartnr(", i, ")=0!!"); + }; + } + + mesh.SetGlobalH(mparam.maxh); + + + AddConeAndSpiralEdges(); + + PrintMessage(5,"Make Atlas finished"); + + PopStatus(); +} + + +int STLGeometry::TrigIsInOC(int tn, int ocn) const +{ + if (tn < 1 || tn > GetNT()) + { + // assert (1); + abort (); + PrintSysError("STLGeometry::TrigIsInOC illegal tn: ", tn); + + return 0; + } + + /* + int firstval = 0; + int i; + for (i = 1; i <= GetNOCPT(tn); i++) + { + if (GetOCPT(tn, i) == ocn) {firstval = 1;} + } + */ + + int found = 0; + + int inc = 1; + while (inc <= GetNOCPT(tn)) {inc *= 2;} + inc /= 2; + + int start = inc; + + while (!found && inc > 0) + { + if (GetOCPT(tn,start) > ocn) {inc = inc/2; start -= inc;} + else if (GetOCPT(tn,start) < ocn) {inc = inc/2; if (start+inc <= GetNOCPT(tn)) {start += inc;}} + else {found = 1;} + } + + return GetOCPT(tn, start) == ocn; +} + +int STLGeometry :: GetChartNr(int i) const +{ + if (i > chartmark.Size()) + { + PrintSysError("GetChartNr(", i, ") not possible!!!"); + i = 1; + } + return chartmark.Get(i); +} +/* +int STLGeometry :: GetMarker(int i) const +{ + return chartmark.Get(i); +} +*/ +void STLGeometry :: SetMarker(int nr, int m) +{ + chartmark.Elem(nr) = m; +} +int STLGeometry :: GetNOCharts() const +{ + return atlas.Size(); +} +const STLChart& STLGeometry :: GetChart(int nr) const +{ + if (nr > atlas.Size()) + { + PrintSysError("GetChart(", nr, ") not possible!!!"); + nr = 1; + } + return *(atlas.Get(nr)); +} + +int STLGeometry :: AtlasMade() const +{ + return chartmark.Size() != 0; +} + + +//return 1 if not exists +int AddIfNotExists(ARRAY<int>& list, int x) +{ + int i; + for (i = 1; i <= list.Size(); i++) + { + if (list.Get(i) == x) {return 0;} + } + list.Append(x); + return 1; +} + +void STLGeometry :: GetInnerChartLimes(ARRAY<twoint>& limes, int chartnum) +{ + int j, k; + + int t, nt, np1, np2; + STLTriangle tt; + + limes.SetSize(0); + + STLChart& chart = GetChart(chartnum); + + for (j = 1; j <= chart.GetNChartT(); j++) + { + t = chart.GetChartTrig(j); + const STLTriangle& tt = GetTriangle(t); + for (k = 1; k <= 3; k++) + { + nt = NeighbourTrig(t,k); + if (GetChartNr(nt) != chartnum) + { + tt.GetNeighbourPoints(GetTriangle(nt),np1,np2); + if (!IsEdge(np1,np2)) + { + limes.Append(twoint(np1,np2)); + /* + p3p1 = GetPoint(np1); + p3p2 = GetPoint(np2); + if (AddIfNotExists(limes,np1)) + { + plimes1.Append(p3p1); + //plimes1trigs.Append(t); + //plimes1origin.Append(np1); + } + if (AddIfNotExists(limes1,np2)) + { + plimes1.Append(p3p2); + //plimes1trigs.Append(t); + //plimes1origin.Append(np2); + } + //chart.AddILimit(twoint(np1,np2)); + + for (int di = 1; di <= divisions; di++) + { + double f1 = (double)di/(double)(divisions+1.); + double f2 = (divisions+1.-(double)di)/(double)(divisions+1.); + + plimes1.Append(Point3d(p3p1.X()*f1+p3p2.X()*f2, + p3p1.Y()*f1+p3p2.Y()*f2, + p3p1.Z()*f1+p3p2.Z()*f2)); + //plimes1trigs.Append(t); + //plimes1origin.Append(0); + } + */ + } + } + } + } +} + + + +void STLGeometry :: GetDirtyChartTrigs(int chartnum, STLChart& chart, + const ARRAY<int>& outercharttrigs, + ARRAY<int>& chartpointchecked, + ARRAY<int>& dirtytrigs) +{ + dirtytrigs.SetSize(0); + int j,k,n; + + int np1, np2, nt; + int cnt = 0; + + for (j = 1; j <= chart.GetNChartT(); j++) + { + int t = chart.GetChartTrig(j); + const STLTriangle& tt = GetTriangle(t); + + for (k = 1; k <= 3; k++) + { + nt = NeighbourTrig(t,k); + if (GetChartNr(nt) != chartnum && outercharttrigs.Get(nt) != chartnum) + { + tt.GetNeighbourPoints(GetTriangle(nt),np1,np2); + if (!IsEdge(np1,np2)) + { + dirtytrigs.Append(j); //local numbers!!! + cnt++; + break; //only once per trig!!! + } + } + } + } + cnt = 0; + + int addedges = 0; + int p1, p2, tn1, tn2, l, problem, pn; + ARRAY<int> trigsaroundp; + + for (j = chart.GetNChartT(); j >= 1; j--) + { + int t = chart.GetChartTrig(j); + const STLTriangle& tt = GetTriangle(t); + + for (k = 1; k <= 3; k++) + { + pn = tt.PNum(k); + //if (chartpointchecked.Get(pn) == chartnum) + //{continue;} + + int checkpoint = 0; + for (n = 1; n <= trigsperpoint.EntrySize(pn); n++) + { + if (trigsperpoint.Get(pn,n) != t && //ueberfluessig??? + GetChartNr(trigsperpoint.Get(pn,n)) != chartnum && + outercharttrigs.Get(trigsperpoint.Get(pn,n)) != chartnum) {checkpoint = 1;}; + } + if (checkpoint) + { + chartpointchecked.Elem(pn) = chartnum; + + int worked = 0; + GetSortedTrianglesAroundPoint(pn,t,trigsaroundp); + trigsaroundp.Append(t); //ring + + problem = 0; + //forward: + for (l = 2; l <= trigsaroundp.Size()-1; l++) + { + tn1 = trigsaroundp.Get(l-1); + tn2 = trigsaroundp.Get(l); + const STLTriangle& t1 = GetTriangle(tn1); + const STLTriangle& t2 = GetTriangle(tn2); + t1.GetNeighbourPoints(t2, p1, p2); + if (IsEdge(p1,p2)) break; + + if (GetChartNr(tn2) != chartnum && outercharttrigs.Get(tn2) != chartnum) {problem = 1;} + } + + //backwards: + for (l = trigsaroundp.Size()-1; l >= 2; l--) + { + tn1 = trigsaroundp.Get(l+1); + tn2 = trigsaroundp.Get(l); + const STLTriangle& t1 = GetTriangle(tn1); + const STLTriangle& t2 = GetTriangle(tn2); + t1.GetNeighbourPoints(t2, p1, p2); + if (IsEdge(p1,p2)) break; + + if (GetChartNr(tn2) != chartnum && outercharttrigs.Get(tn2) != chartnum) {problem = 1;} + } + if (problem && !IsInArray(j,dirtytrigs)) + { + dirtytrigs.Append(j); + cnt++; + break; //only once per triangle + } + } + } + } + +} + +} diff --git a/contrib/Netgen/libsrc/stlgeom/stlgeommesh.cpp b/contrib/Netgen/libsrc/stlgeom/stlgeommesh.cpp new file mode 100644 index 0000000000..863019c04c --- /dev/null +++ b/contrib/Netgen/libsrc/stlgeom/stlgeommesh.cpp @@ -0,0 +1,1592 @@ +//20.11.1999 second part of stlgeom.cc, mainly mesh functions + +#include <mystdlib.h> + +#include <myadt.hpp> +#include <linalg.hpp> +#include <gprim.hpp> + +#include <meshing.hpp> + +#include "stlgeom.hpp" + +namespace netgen +{ +int EdgeUsed(int p1, int p2, ARRAY<INDEX_2>& edges, INDEX_2_HASHTABLE<int>& hashtab) +{ + if (p1 > p2) {swap (p1,p2);} + + if (hashtab.Used(INDEX_2(p1,p2))) + {return hashtab.Get(INDEX_2(p1,p2));} + + return 0; +} + +Point<3> STLGeometry :: PointBetween(const Point<3> & p1, int t1, + const Point<3> & p2, int t2) +{ + //funktioniert nicht in allen F�llen! + + PrintWarning("Point between"); + + + ClearMarkedSegs(); + + InitMarkedTrigs(); + SetMarkedTrig(t1,1); + SetMarkedTrig(t2,1); + + TABLE<Point3d> edgepoints; + TABLE<double> edgepointdists; + TABLE<int> edgepointorigines; + TABLE<int> edgepointoriginps; + + ARRAY<int> edgetrigs; + ARRAY<INDEX_2> edgepointnums; + ARRAY<int> edgetriglocinds; + + int size = 3*GetNT(); + INDEX_2_HASHTABLE<int> hashtab(size); + + int divisions = 10; + + edgepoints.SetSize(size); + edgepointdists.SetSize(size); + edgepointorigines.SetSize(size); + edgepointoriginps.SetSize(size); + + edgetrigs.SetSize(size); + edgepointnums.SetSize(size); + edgetriglocinds.SetSize(size); + + ARRAY<int> edgelist1; + ARRAY<int> edgelist2; + + edgelist1.SetSize(0); + edgelist2.SetSize(0); + + + int i, j, k, l, m; + int edgecnt = 0; + + //first triangle: + for (i = 1; i <= 3; i++) + { + int ptn1 = GetTriangle(t1).PNum(i); + int ptn2 = GetTriangle(t1).PNumMod(i+1); + + if (ptn1 > ptn2) {swap(ptn1,ptn2);} + + Point3d pt1 = GetPoint(ptn1); + Point3d pt2 = GetPoint(ptn2); + + edgecnt++; + edgetrigs.Elem(edgecnt) = t1; + edgepointnums.Elem(edgecnt) = INDEX_2(ptn1,ptn2); + hashtab.Set(edgepointnums.Get(edgecnt),edgecnt); + + edgetriglocinds.Elem(edgecnt) = i; + edgelist1.Append(edgecnt); + + for (j = 1; j <= divisions; j++) + { + double lfact = (double)j/(double)divisions; + Point3d pbtw(lfact*pt1.X()+(1.-lfact)*pt2.X(), + lfact*pt1.Y()+(1.-lfact)*pt2.Y(), + lfact*pt1.Z()+(1.-lfact)*pt2.Z()); + + //AddMarkedSeg(p1,pbtw); + + edgepoints.Add1(edgecnt,pbtw); + edgepointdists.Add1(edgecnt,Dist(pbtw,p1)); + edgepointorigines.Add1(edgecnt,0); + edgepointoriginps.Add1(edgecnt,0); + } + } + + int finished = 0; + int endpointorigine = 0; + int endpointoriginp = 0; + double endpointmindist = 1E50; + + int cnt = 0; + int maxsize = 0; + while (!finished) + { + finished = 1; + + if (edgelist1.Size() > maxsize) {maxsize = edgelist1.Size();} + + for (i = 1; i <= edgelist1.Size(); i++) + { + int en = edgelist1.Get(i); + int trig = edgetrigs.Get(en); + int edgenum = edgetriglocinds.Get(en); + int tn = NeighbourTrigSorted(trig,edgenum); + + if (tn != t2) + { + for (k = 1; k <= 3; k++) + { + int pnt1 = GetTriangle(tn).PNum(k); + int pnt2 = GetTriangle(tn).PNumMod(k+1); + + if (pnt1 > pnt2) {swap(pnt1,pnt2);} + + Point3d pt1 = GetPoint(pnt1); + Point3d pt2 = GetPoint(pnt2); + + //AddMarkedSeg(pt1,pt2); + + //if (!(pnt1 == ep1 && pnt2 == ep2)) + // { + int edgeused = 0; + int edgenum = EdgeUsed(pnt1, pnt2, edgepointnums, hashtab); + if (edgenum != en) + { + if (edgenum != 0) + {edgeused = 1;} + else + { + edgecnt++; + edgenum = edgecnt; + + edgetrigs.Elem(edgenum) = tn; + edgepointnums.Elem(edgenum) = INDEX_2(pnt1,pnt2); + hashtab.Set(edgepointnums.Get(edgenum),edgenum); + edgetriglocinds.Elem(edgenum) = k; + } + + if (edgenum > size || edgenum == 0) {PrintSysError("edgenum = ", edgenum);} + + double minofmindist = 1E50; + int changed = 0; + + for (l = 1; l <= divisions; l++) + { + double lfact = (double)l/(double)divisions; + Point3d pbtw(lfact*pt1.X()+(1.-lfact)*pt2.X(), + lfact*pt1.Y()+(1.-lfact)*pt2.Y(), + lfact*pt1.Z()+(1.-lfact)*pt2.Z()); + + double mindist = 1E50; + int index=0; + + for (m = 1; m <= divisions; m++) + { + const Point3d& p = edgepoints.Get(en,m); + if (Dist(pbtw,p) + edgepointdists.Get(en,m) < mindist) + {mindist = Dist(pbtw,p) + edgepointdists.Get(en,m); index = m;} + } + + //if (mindist < endpointmindist) {finished = 0;} + if (mindist < minofmindist) {minofmindist = mindist;} + + + if (!edgeused) + { + //AddMarkedSeg(pbtw,edgepoints.Get(en,index)); + + edgepoints.Add1(edgenum,pbtw); + edgepointdists.Add1(edgenum,mindist); + edgepointorigines.Add1(edgenum,en); + edgepointoriginps.Add1(edgenum,index); + changed = 1; + } + else + { + if (mindist < edgepointdists.Get(edgenum,l)) + { + edgepointdists.Set(edgenum,l,mindist); + edgepointorigines.Set(edgenum,l,en); + edgepointoriginps.Set(edgenum,l,index); + changed = 1; + } + } + } + if (minofmindist < endpointmindist-1E-10 && changed) + { + finished = 0; + edgelist2.Append(edgenum); + } + } + } + } + else + { + double mindist = 1E50; + int index; + for (m = 1; m <= divisions; m++) + { + const Point3d& p = edgepoints.Get(en,m); + if (Dist(p2,p) + edgepointdists.Get(en,m) < mindist) + {mindist = Dist(p2,p) + edgepointdists.Get(en,m); index = m;} + } + if (mindist < endpointmindist) + { + endpointorigine = en; + endpointoriginp = index; + endpointmindist = mindist; + } + } + } + edgelist1.SetSize(0); + for (i = 1; i <= edgelist2.Size(); i++) + { + edgelist1.Append(edgelist2.Get(i)); + } + } + + if (!endpointorigine) {PrintSysError("No connection found!");} + + ARRAY<Point3d> plist; + + plist.Append(p2); + int laste = endpointorigine; + int lastp = endpointoriginp; + int lle, llp; + + + while (laste) + { + plist.Append(edgepoints.Get(laste,lastp)); + + lle = laste; + llp = lastp; + laste = edgepointorigines.Get(lle,llp); + lastp = edgepointoriginps.Get(lle,llp); + } + + plist.Append(p1); + + for (i = 1; i <= plist.Size()-1; i++) + { + AddMarkedSeg(plist.Get(i),plist.Get(i+1)); + } + + PrintMessage(5,"PointBetween: complexity=", maxsize); + + + Point3d pm; + double dist = 0; + int found = 0; + + for (i = 1; i <= plist.Size()-1; i++) + { + dist += Dist(plist.Get(i),plist.Get(i+1)); + if (dist > endpointmindist*0.5) + { + double segl = Dist(plist.Get(i), plist.Get(i+1)); + double d = dist - endpointmindist * 0.5; + pm = Point3d(d/segl*plist.Get(i).X() + (1.-d/segl)*plist.Get(i+1).X(), + d/segl*plist.Get(i).Y() + (1.-d/segl)*plist.Get(i+1).Y(), + d/segl*plist.Get(i).Z() + (1.-d/segl)*plist.Get(i+1).Z()); + found = 1; + break; + } + } + if (!found) {PrintWarning("Problem in PointBetween"); pm = Center(p1,p2);} + + AddMarkedSeg(pm, Point3d(0.,0.,0.)); + + return pm; + +} + + +void STLGeometry :: PrepareSurfaceMeshing() +{ + meshchart = -1; //clear no old chart + meshcharttrigs.SetSize(GetNT()); + int i; + for (i = 1; i <= GetNT(); i++) + {meshcharttrigs.Elem(i) = 0;} +} + +void STLGeometry::GetMeshChartBoundary (ARRAY<Point2d > & points, + ARRAY<Point3d > & points3d, + ARRAY<INDEX_2> & lines, double h) +{ + int i, j; + twoint seg, newseg; + int zone; + int psize; + Point<2> p2; + + const STLChart& chart = GetChart(meshchart); + + + for (i = 1; i <= chart.GetNOLimit(); i++) + { + seg = chart.GetOLimit(i); + INDEX_2 i2; + for (j = 1; j <= 2; j++) + { + int pi = (j == 1) ? seg.i1 : seg.i2; + int lpi; + if (ha_points.Get(pi) == 0) + { + const Point<3> & p3d = GetPoint (pi); + Point<2> p2d; + + points3d.Append (p3d); + ToPlane(p3d, 0, p2d, h, zone, 0); + points.Append (p2d); + + lpi = points.Size(); + ha_points.Elem(pi) = lpi; + } + else + lpi = ha_points.Get(pi); + + i2.I(j) = lpi; + } + lines.Append (i2); + + /* + seg = chart.GetOLimit(i); + psize = points.Size(); + + newseg.i1 = psize+1; + newseg.i2 = psize+2; + + ToPlane(GetPoint(seg.i1), 0, p2, h, zone, 0); + points.Append(p2); + points3d.Append (GetPoint(seg.i1)); + ToPlane(GetPoint(seg.i2), 0, p2, h, zone, 0); + points.Append(p2); + points3d.Append (GetPoint(seg.i2)); + lines.Append (INDEX_2 (points.Size()-1, points.Size())); + */ + } + + for (i = 1; i <= chart.GetNOLimit(); i++) + { + seg = chart.GetOLimit(i); + ha_points.Elem(seg.i1) = 0; + ha_points.Elem(seg.i2) = 0; + } +} + +void STLGeometry :: DefineTangentialPlane (const Point<3> & ap1, const Point<3> & ap2, int trig) +{ + p1 = ap1; //save for ToPlane, in data of STLGeometry class + Point<3> p2 = ap2; //only locally used + + meshchart = GetChartNr(trig); + + if (usechartnormal) + meshtrignv = GetChart(meshchart).GetNormal(); + else + meshtrignv = GetTriangle(trig).Normal(); + + //meshtrignv = GetTriangle(trig).Normal(points); + + meshtrignv /= meshtrignv.Length(); + + GetTriangle(trig).ProjectInPlain(points, meshtrignv, p2); + + + ez = meshtrignv; + ez /= ez.Length(); + ex = p2 - p1; + ex -= (ex * ez) * ez; + ex /= ex.Length(); + ey = Cross (ez, ex); + +} + + +void STLGeometry :: SelectChartOfTriangle (int trignum) +{ + meshchart = GetChartNr(trignum); + meshtrignv = GetTriangle(trignum).Normal(); +} + + +void STLGeometry :: SelectChartOfPoint (const Point<3> & p) +{ + int i, ii, j, k; + + ARRAY<int> trigsinbox; + + Box<3> box(p,p); + box.Increase (1e-6); + GetTrianglesInBox (box, trigsinbox); + + + // for (i = 1; i <= GetNT(); i++) + for (ii = 1; ii <= trigsinbox.Size(); ii++) + { + i = trigsinbox.Get(ii); + Point<3> hp = p; + if (GetTriangle(i).GetNearestPoint(points, hp) <= 1E-8) + { + SelectChartOfTriangle (i); + break; + } + } + return; +} + + + +void STLGeometry :: ToPlane (const Point<3> & locpoint, int * trigs, + Point<2> & plainpoint, double h, int& zone, + int checkchart) +{ + if (checkchart) + { + + //check if locpoint lies on actual chart: + zone = 0; + + + // Point3d p; + int i = 1; + const STLChart& chart = GetChart(meshchart); + int foundinchart = 0; + const double range = 1e-6; //1e-4 old + + + + + if (trigs) + { + int * htrigs = trigs; + int ci = 1; + while (*htrigs) + { + if (TrigIsInOC (*htrigs, meshchart)) + { + foundinchart = 1; + break; + } + htrigs++; + } + } + + else + { + ARRAY<int> trigsinbox; + + if (!geomsearchtreeon) + { + //alter chart-tree + Box<3> box(locpoint, locpoint); + box.Increase (range); + chart.GetTrianglesInBox (box.PMin(), box.PMax(), trigsinbox); + } + else + { + ARRAY<int> trigsinbox2; + Box<3> box(locpoint, locpoint); + box.Increase (range); + GetTrianglesInBox (box, trigsinbox2); + for (i = 1; i <= trigsinbox2.Size(); i++) + { + if (TrigIsInOC(trigsinbox2.Get(i),meshchart)) {trigsinbox.Append(trigsinbox2.Get(i));} + } + + } + + + for (i = 1; i <= trigsinbox.Size(); i++) + { + Point<3> p = locpoint; + if (GetTriangle(trigsinbox.Get(i)).GetNearestPoint(points, p) + <= 1E-8) + { + foundinchart = 1; + break; + } + + } + } + + //do not use this point (but do correct projection (joachim) + if (!foundinchart) + { + zone = -1; // plainpoint.X() = 11111; plainpoint.Y() = 11111; return; + } + } + + else + { + zone = 0; + } + + //transform in plane + Vec<3> p1p = locpoint - p1; + plainpoint(0) = (p1p * ex) / h; + plainpoint(1) = (p1p * ey) / h; + +} + +int STLGeometry :: FromPlane (const Point<2> & plainpoint, + Point<3> & locpoint, double h) +{ + Point2d plainpoint2 (plainpoint); + + plainpoint2.X() *= h; + plainpoint2.Y() *= h; + Vec3d p1p = plainpoint2.X() * ex + plainpoint2.Y() * ey; + locpoint = p1 + p1p; + + + int rv = Project(locpoint); + if (!rv) {return 1;} //project nicht gegangen + return 0; +} + +int lasttrig; +int STLGeometry :: LastTrig() const {return lasttrig;} + +//project normal to tangential plane +int STLGeometry :: Project(Point<3> & p3d) const +{ + Point<3> p, pf; + + int i, j, k; + int fi = 0; + int cnt = 0; + int different = 0; + const double lamtol = 1e-6; + + const STLChart& chart = GetChart(meshchart); + + int nt = chart.GetNT(); + + QuadraticFunction3d quadfun(p3d, meshtrignv); + + /* + Vec3d hv = meshtrignv; + hv /= hv.Length(); + Vec3d t1, t2; + hv.GetNormal (t1); + Cross (hv, t1, t2); + */ + + for (j = 1; j <= nt; j++) + { + i = chart.GetTrig(j); + + const Point<3> & c = GetTriangle(i).center; + /* + double d1 = t1 * (c-p3d); + double d2 = t2 * (c-p3d); + */ + /* + if (d1 * d1 + d2 * d2 > sqr (GetTriangle(i).rad)) + continue; + */ + if (quadfun.Eval(c) > sqr (GetTriangle(i).rad)) + continue; + + p = p3d; + Vec<3> lam; + int err = GetTriangle(i).ProjectInPlain(points, meshtrignv, p, lam); + int inside = (err == 0 && lam(0) > -lamtol && + lam(1) > -lamtol && (1-lam(0)-lam(1)) > -lamtol); + + + /* + p = p3d; + GetTriangle(i).ProjectInPlain(points, meshtrignv, p); + if (GetTriangle(i).PointInside(points, p)) + */ + if (inside) + { + if (cnt != 0) + { + if (Dist2(p,pf)>=1E-16) + { + // (*testout) << "ERROR: found two points to project which are different" << endl; + //(*testout) << "p=" << p << ", pf=" << pf << endl; + different = 1; + } + } + pf = p; fi = i; cnt++; + } + + if (inside) + break; + + } + + // if (cnt == 2) {(*testout) << "WARNING: found 2 triangles to project" << endl;} + //if (cnt == 3) {(*testout) << "WARNING: found 3 triangles to project" << endl;} + //if (cnt > 3) {(*testout) << "WARNING: found more than 3 triangles to project" << endl;} + + if (fi != 0) {lasttrig = fi;} + if (fi != 0 && !different) {p3d = pf; return fi;} + + // (*testout) << "WARNING: Project failed" << endl; + return 0; + +} + +//project normal to tangential plane +int STLGeometry :: ProjectOnWholeSurface(Point<3> & p3d) const +{ + Point<3> p, pf; + + int i, k; + int fi = 0; + int cnt = 0; + int different = 0; + const double lamtol = 1e-6; + + for (i = 1; i <= GetNT(); i++) + { + p = p3d; + Vec<3> lam; + int err = + GetTriangle(i).ProjectInPlain(points, meshtrignv, p, lam); + int inside = (err == 0 && lam(0) > -lamtol && + lam(1) > -lamtol && (1-lam(0)-lam(1)) > -lamtol); + + /* + p = p3d; + GetTriangle(i).ProjectInPlain(points, meshtrignv, p); + if (GetTriangle(i).PointInside(points, p)) + */ + if (inside) + { + if (cnt != 0) + { + if (Dist2(p,pf)>=1E-16) + { + // (*testout) << "ERROR: found two points to project which are different" << endl; + // (*testout) << "p=" << p << ", pf=" << pf << endl; + different = 1; + } + } + pf = p; fi = i; cnt++; + } + } + /* + if (cnt == 2) {(*testout) << "WARNING: found 2 triangles to project" << endl;} + if (cnt == 3) {(*testout) << "WARNING: found 3 triangles to project" << endl;} + if (cnt > 3) {(*testout) << "WARNING: found more than 3 triangles to project" << endl;} + */ + if (fi != 0) {lasttrig = fi;} + if (fi != 0 && !different) {p3d = pf; return fi;} + + // (*testout) << "WARNING: Project failed" << endl; + return 0; + +} + + +int STLGeometry :: ProjectNearest(Point<3> & p3d) const +{ + Point<3> p, pf; + + //set new chart + const STLChart& chart = GetChart(meshchart); + int i; + double nearest = 1E50; + double dist; + int ft = 0; + + for (i = 1; i <= chart.GetNT(); i++) + { + p = p3d; + dist = GetTriangle(chart.GetTrig(i)).GetNearestPoint(points, p); + if (dist < nearest) + { + pf = p; + nearest = dist; + ft = chart.GetTrig(i); + } + } + p3d = pf; + //if (!ft) {(*testout) << "ERROR: ProjectNearest failed" << endl;} + + return ft; +} + + + + +//Restrict local h due to curvature for make atlas +void STLGeometry :: RestrictLocalHCurv(class Mesh & mesh, double gh) +{ + PushStatusF("Restrict H due to surface curvature"); + + //bei jedem Dreieck alle Nachbardreiecke vergleichen, und, fallskein Kante dazwischen, + //die Meshsize auf ein bestimmtes Mass limitieren + int i,j; + + int p1,p2,p3,p4; + Point<3> p1p, p2p, p3p, p4p; + double mindist, ang; + Vec<3> n, ntn; + double rzyl, sinang, localh; + + // double localhfact = 0.5; + double geometryignorelength = 1E-4; + double minlocalh = stlparam.atlasminh; + + Box<3> bb = GetBoundingBox(); + // mesh.SetLocalH(bb.PMin() - Vec3d(10, 10, 10),bb.PMax() + Vec3d(10, 10, 10), + // mparam.grading); + + // mesh.SetGlobalH(gh); + + double mincalch = 1E10; + double maxcalch = -1E10; + + double objectsize = bb.Diam(); + double geometryignoreedgelength = objectsize * 1e-5; + + if (stlparam.resthatlasenable) + { + ARRAY<double> minh; //minimales h pro punkt + minh.SetSize(GetNP()); + for (i = 1; i <= GetNP(); i++) + { + minh.Elem(i) = gh; + } + + for (i = 1; i <= GetNT(); i++) + { + SetThreadPercent((double)i/(double)GetNT()*100.); + + if (multithread.terminate) + {PopStatus(); return;} + + const STLTriangle& trig = GetTriangle(i); + n = GetTriangle(i).Normal(); + for (j = 1; j <= 3; j++) + { + const STLTriangle& nt = GetTriangle(NeighbourTrig(i,j)); + + trig.GetNeighbourPointsAndOpposite(nt,p1,p2,p3); + + //checken, ob p1-p2 eine Kante sind + if (IsEdge(p1,p2)) continue; + + p4 = trig.PNum(1) + trig.PNum(2) + trig.PNum(3) - p1 - p2; + + p1p = GetPoint(p1); p2p = GetPoint(p2); + p3p = GetPoint(p3); p4p = GetPoint(p4); + + double h1 = GetDistFromInfiniteLine(p1p,p2p, p4p); + double h2 = GetDistFromInfiniteLine(p1p,p2p, p3p); + double diaglen = Dist (p1p, p2p); + + if (diaglen < geometryignoreedgelength) + continue; + rzyl = ComputeCylinderRadius + (n, GetTriangle(NeighbourTrig(i,j)).Normal(), + h1, h2); + + + if (h1 < 1e-3 * diaglen && h2 < 1e-3 * diaglen) + continue; + if (h1 < 1e-5 * objectsize && h2 < 1e-5 * objectsize) + continue; + + + // rzyl = mindist/(2*sinang); + localh = 10.*rzyl / stlparam.resthatlasfac; + if (localh < mincalch) {mincalch = localh;} + if (localh > maxcalch) {maxcalch = localh;} + + if (localh < minlocalh) {localh = minlocalh;} + if (localh < gh) + { + minh.Elem(p1) = min2(minh.Elem(p1),localh); + minh.Elem(p2) = min2(minh.Elem(p2),localh); + } + + //if (localh < 0.2) {localh = 0.2;} + mesh.RestrictLocalHLine(p1p, p2p, localh); + } + + } + } + PrintMessage(7, "done\nATLAS H: nmin local h=", mincalch); + PrintMessage(7, "ATLAS H: max local h=", maxcalch); + PrintMessage(7, "Local h tree has ", mesh.LocalHFunction().GetNBoxes(), " boxes of size ", + (int)sizeof(GradingBox)); + + PopStatus(); + +} + //restrict local h due to near edges and due to outer chart distance +void STLGeometry :: RestrictLocalH(class Mesh & mesh, double gh) +{ + + //bei jedem Dreieck alle Nachbardreiecke vergleichen, und, fallskein Kante dazwischen, + //die Meshsize auf ein bestimmtes Mass limitieren + int i,j; + + int p1,p2,p3,p4; + Point3d p1p, p2p, p3p, p4p; + double mindist, ang; + Vec3d n, ntn; + double rzyl, sinang, localh; + + // double localhfact = 0.5; + double geometryignorelength = 1E-4; + + Box<3> bb = GetBoundingBox(); + //mesh.SetLocalH(bb.PMin() - Vec3d(10, 10, 10),bb.PMax() + Vec3d(10, 10, 10), + // mparam.grading); + + //mesh.SetGlobalH(gh); + + double mincalch = 1E10; + double maxcalch = -1E10; + + double objectsize = bb.Diam(); + double geometryignoreedgelength = objectsize * 1e-5; + + if (stlparam.resthsurfcurvenable) + { + PushStatusF("Restrict H due to surface curvature"); + + ARRAY<double> minh; //minimales h pro punkt + minh.SetSize(GetNP()); + for (i = 1; i <= GetNP(); i++) + { + minh.Elem(i) = gh; + } + + for (i = 1; i <= GetNT(); i++) + { + SetThreadPercent((double)i/(double)GetNT()*100.); + if (i%20000==19999) {PrintMessage(7, (double)i/(double)GetNT()*100. , "%");} + + if (multithread.terminate) + {PopStatus(); return;} + + const STLTriangle& trig = GetTriangle(i); + n = GetTriangle(i).Normal(); + for (j = 1; j <= 3; j++) + { + const STLTriangle& nt = GetTriangle(NeighbourTrig(i,j)); + + trig.GetNeighbourPointsAndOpposite(nt,p1,p2,p3); + + //checken, ob p1-p2 eine Kante sind + if (IsEdge(p1,p2)) continue; + + p4 = trig.PNum(1) + trig.PNum(2) + trig.PNum(3) - p1 - p2; + + p1p = GetPoint(p1); p2p = GetPoint(p2); + p3p = GetPoint(p3); p4p = GetPoint(p4); + + double h1 = GetDistFromInfiniteLine(p1p,p2p, p4p); + double h2 = GetDistFromInfiniteLine(p1p,p2p, p3p); + double diaglen = Dist (p1p, p2p); + + if (diaglen < geometryignoreedgelength) + continue; + rzyl = ComputeCylinderRadius + (n, GetTriangle (NeighbourTrig(i,j)).Normal(), + h1, h2); + + + if (h1 < 1e-3 * diaglen && h2 < 1e-3 * diaglen) + continue; + if (h1 < 1e-5 * objectsize && h2 < 1e-5 * objectsize) + continue; + + + // rzyl = mindist/(2*sinang); + localh = rzyl / stlparam.resthsurfcurvfac; + if (localh < mincalch) {mincalch = localh;} + if (localh > maxcalch) {maxcalch = localh;} + if (localh < gh) + { + minh.Elem(p1) = min2(minh.Elem(p1),localh); + minh.Elem(p2) = min2(minh.Elem(p2),localh); + } + + //if (localh < 0.2) {localh = 0.2;} + mesh.RestrictLocalHLine(p1p, p2p, localh); + + if (localh < 0.1) + { + localh = 0.1; + } + + } + } + PrintMessage(7, "done\nmin local h=", mincalch, "\nmax local h=", maxcalch); + PopStatus(); + } + + if (stlparam.resthcloseedgeenable) + { + PushStatusF("Restrict H due to close edges"); + //geht nicht f�r spiralen!!!!!!!!!!!!!!!!!! + + double disttohfact = sqr(10.0 / stlparam.resthcloseedgefac); + int k,l; + double h1, h2, dist; + int rc = 0; + Point3d p3p1, p3p2; + double mindist = 1E50; + + PrintMessage(7,"build search tree..."); + Box3dTree* searchtree = new Box3dTree (GetBoundingBox().PMin() - Vec3d(1,1,1), + GetBoundingBox().PMax() + Vec3d(1,1,1)); + + ARRAY<Point3d> pmins(GetNLines()); + ARRAY<Point3d> pmaxs(GetNLines()); + + double maxhline; + for (i = 1; i <= GetNLines(); i++) + { + maxhline = 0; + STLLine* l1 = GetLine(i); + Point3d pmin(GetPoint(l1->StartP())), pmax(GetPoint(l1->StartP())), px; + + for (j = 2; j <= l1->NP(); j++) + { + px = GetPoint(l1->PNum(j)); + maxhline = max2(maxhline,mesh.GetH(px)); + pmin.SetToMin (px); + pmax.SetToMax (px); + } + Box3d box(pmin,pmax); + box.Increase(maxhline); + + searchtree->Insert (box.PMin(), box.PMax(), i); + pmins.Elem(i) = box.PMin(); + pmaxs.Elem(i) = box.PMax(); + } + + ARRAY<int> linenums; + int k2; + + for (i = 1; i <= GetNLines(); i++) + { + SetThreadPercent((double)i/(double)GetNLines()*100.); + if (multithread.terminate) + {PopStatus(); return;} + + linenums.SetSize(0); + searchtree->GetIntersecting(pmins.Get(i),pmaxs.Get(i),linenums); + + STLLine* l1 = GetLine(i); + for (j = 1; j <= l1->NP(); j++) + { + p3p1 = GetPoint(l1->PNum(j)); + h1 = sqr(mesh.GetH(p3p1)); + + for (k2 = 1; k2 <= linenums.Size(); k2++) + { + k = linenums.Get(k2); + if (k <= i) {continue;} + /* + //old, without searchtrees + for (k = i+1; k <= GetNLines(); k++) + { + */ + STLLine* l2 = GetLine(k); + for (l = 1; l <= l2->NP(); l++) + { + const Point3d& p3p2 = GetPoint(l2->PNum(l)); + h2 = sqr(mesh.GetH(p3p2)); + dist = Dist2(p3p1,p3p2)*disttohfact; + if (dist > 1E-12) + { + if (dist < h1) + { + mesh.RestrictLocalH(p3p1,sqrt(dist)); + rc++; + mindist = min2(mindist,sqrt(dist)); + } + if (dist < h2) + { + mesh.RestrictLocalH(p3p2,sqrt(dist)); + rc++; + mindist = min2(mindist,sqrt(dist)); + } + } + } + } + } + } + PrintMessage(5, "done\n Restricted h in ", rc, " points due to near edges!"); + PopStatus(); + } + + if (stlparam.resthedgeangleenable) + { + PushStatusF("Restrict h due to close edges"); + + int ecnt = 0; + int lp1, lp2; + int i; + Vec3d v1,v2; + double rzyl; + double mincalch = 1E50; + double maxcalch = -1E50; + + for (i = 1; i <= GetNP(); i++) + { + SetThreadPercent((double)i/(double)GetNP()*100.); + if (multithread.terminate) + {PopStatus(); return;} + + if (GetNEPP(i) == 2 && !IsLineEndPoint(i)) + { + if (GetEdge(GetEdgePP(i,1)).PNum(2) == GetEdge(GetEdgePP(i,2)).PNum(1) || + GetEdge(GetEdgePP(i,1)).PNum(1) == GetEdge(GetEdgePP(i,2)).PNum(2)) + { + lp1 = 1; lp2 = 2; + } + else + { + lp1 = 2; lp2 = 1; + } + + v1 = Vec3d(GetPoint(GetEdge(GetEdgePP(i,1)).PNum(1)), + GetPoint(GetEdge(GetEdgePP(i,1)).PNum(2))); + v2 = Vec3d(GetPoint(GetEdge(GetEdgePP(i,2)).PNum(lp1)), + GetPoint(GetEdge(GetEdgePP(i,2)).PNum(lp2))); + + rzyl = ComputeCylinderRadius(v1, v2, v1.Length(), v2.Length()); + + localh = rzyl / stlparam.resthedgeanglefac; + if (localh < mincalch) {mincalch = localh;} + if (localh > maxcalch) {maxcalch = localh;} + + if (localh != 0) + mesh.RestrictLocalH(GetPoint(i), localh); + } + } + PrintMessage(7,"edge-angle min local h=", mincalch, "\nedge-angle max local h=", maxcalch); + PopStatus(); + } + + if (stlparam.resthchartdistenable) + { + PushStatusF("Restrict H due to outer chart distance"); + + // mesh.LocalHFunction().Delete(); + + //berechne minimale distanz von chart zu einem nicht-outerchart-punkt in jedem randpunkt einer chart + + ARRAY<int> acttrigs; //outercharttrigs + acttrigs.SetSize(GetNT()); + for (i = 1; i <= GetNT(); i++) + { + acttrigs.Elem(i) = 0; + } + for (i = 1; i <= GetNOCharts(); i++) + { + SetThreadPercent((double)i/(double)GetNOCharts()*100.); + if (multithread.terminate) + {PopStatus(); return;} + + RestrictHChartDistOneChart(i, acttrigs, mesh, gh, 1., 0.); + } + + PopStatus(); + } + + if (stlparam.resthlinelengthenable) + { + //restrict h due to short lines + PushStatusF("Restrict H due to line-length"); + + double minhl = 1E50; + double linefact = 1./stlparam.resthlinelengthfac; + double l; + for (i = 1; i <= GetNLines(); i++) + { + SetThreadPercent((double)i/(double)GetNLines()*100.); + if (multithread.terminate) + {PopStatus(); return;} + + l = GetLine(i)->GetLength(points); + + const Point3d& p1 = GetPoint(GetLine(i)->StartP()); + const Point3d& p2 = GetPoint(GetLine(i)->EndP()); + + if (l != 0) + { + minhl = min2(minhl,l*linefact); + + mesh.RestrictLocalH(p1, l*linefact); + mesh.RestrictLocalH(p2, l*linefact); + } + } + PopStatus(); + PrintMessage(5, "minh due to line length=", minhl); + } +} + +void STLGeometry :: RestrictHChartDistOneChart(int chartnum, ARRAY<int>& acttrigs, + class Mesh & mesh, double gh, double fact, double minh) +{ + int i = chartnum; + int j; + + double limessafety = stlparam.resthchartdistfac*fact; // original: 2 + double localh; + + double f1,f2; + // mincalch = 1E10; + //maxcalch = -1E10; + ARRAY<int> limes1; + ARRAY<int> limes2; + + ARRAY<Point3d> plimes1; + ARRAY<Point3d> plimes2; + + ARRAY<int> plimes1trigs; //check from wich trig the points come + ARRAY<int> plimes2trigs; + + ARRAY<int> plimes1origin; //either the original pointnumber or zero, if new point + + int divisions = 10; + + int k, t, nt, np1, np2; + Point3d p3p1, p3p2; + STLTriangle tt; + + limes1.SetSize(0); + limes2.SetSize(0); + plimes1.SetSize(0); + plimes2.SetSize(0); + plimes1trigs.SetSize(0); + plimes2trigs.SetSize(0); + plimes1origin.SetSize(0); + + STLChart& chart = GetChart(i); + chart.ClearOLimit(); + chart.ClearILimit(); + + for (j = 1; j <= chart.GetNChartT(); j++) + { + t = chart.GetChartTrig(j); + tt = GetTriangle(t); + for (k = 1; k <= 3; k++) + { + nt = NeighbourTrig(t,k); + if (GetChartNr(nt) != i) + { + tt.GetNeighbourPoints(GetTriangle(nt),np1,np2); + if (!IsEdge(np1,np2) && !GetSpiralPoint(np1) && !GetSpiralPoint(np2)) + { + p3p1 = GetPoint(np1); + p3p2 = GetPoint(np2); + if (AddIfNotExists(limes1,np1)) + { + plimes1.Append(p3p1); + plimes1trigs.Append(t); + plimes1origin.Append(np1); + } + if (AddIfNotExists(limes1,np2)) + { + plimes1.Append(p3p2); + plimes1trigs.Append(t); + plimes1origin.Append(np2); + } + chart.AddILimit(twoint(np1,np2)); + + for (int di = 1; di <= divisions; di++) + { + f1 = (double)di/(double)(divisions+1.); + f2 = (divisions+1.-(double)di)/(double)(divisions+1.); + + plimes1.Append(Point3d(p3p1.X()*f1+p3p2.X()*f2, + p3p1.Y()*f1+p3p2.Y()*f2, + p3p1.Z()*f1+p3p2.Z()*f2)); + plimes1trigs.Append(t); + plimes1origin.Append(0); + } + } + } + } + } + + + for (j = 1; j <= chart.GetNT(); j++) + { + acttrigs.Elem(chart.GetTrig(j)) = i; + } + + for (j = 1; j <= chart.GetNOuterT(); j++) + { + t = chart.GetOuterTrig(j); + tt = GetTriangle(t); + for (k = 1; k <= 3; k++) + { + nt = NeighbourTrig(t,k); + + if (acttrigs.Get(nt) != i) + { + tt.GetNeighbourPoints(GetTriangle(nt),np1,np2); + + if (!IsEdge(np1,np2)) + { + p3p1 = GetPoint(np1); + p3p2 = GetPoint(np2); + + if (AddIfNotExists(limes2,np1)) {plimes2.Append(p3p1); plimes2trigs.Append(t);} + if (AddIfNotExists(limes2,np2)) {plimes2.Append(p3p2); plimes2trigs.Append(t);} + chart.AddOLimit(twoint(np1,np2)); + + for (int di = 1; di <= divisions; di++) + { + f1 = (double)di/(double)(divisions+1.); + f2 = (divisions+1.-(double)di)/(double)(divisions+1.); + + plimes2.Append(Point3d(p3p1.X()*f1+p3p2.X()*f2, + p3p1.Y()*f1+p3p2.Y()*f2, + p3p1.Z()*f1+p3p2.Z()*f2)); + plimes2trigs.Append(t); + } + } + } + } + } + + + double chartmindist = 1E50; + + if (plimes2.Size()) + { + Box3d bbox; + bbox.SetPoint (plimes2.Get(1)); + for (j = 2; j <= plimes2.Size(); j++) + bbox.AddPoint (plimes2.Get(j)); + Point3dTree stree(bbox.PMin(), bbox.PMax()); + for (j = 1; j <= plimes2.Size(); j++) + stree.Insert (plimes2.Get(j), j); + ARRAY<int> foundpts; + + for (j = 1; j <= plimes1.Size(); j++) + { + double mindist = 1E50; + double dist; + + const Point3d & p1 = plimes1.Get(j); + double boxs = mesh.GetH (plimes1.Get(j)) * limessafety; + + Point3d pmin = p1 - Vec3d (boxs, boxs, boxs); + Point3d pmax = p1 + Vec3d (boxs, boxs, boxs); + + stree.GetIntersecting (pmin, pmax, foundpts); + + + for (int kk = 1; kk <= foundpts.Size(); kk++) + { + k = foundpts.Get(kk); + dist = Dist2(plimes1.Get(j),plimes2.Get(k)); + if (dist < mindist) + { + mindist = dist; + } + } + + /* + const Point3d & p1 = plimes1.Get(j); + double his = mesh.GetH (plimes1.Get(j)); + + double xmin = p1.X() - his * limessafety; + double xmax = p1.X() + his * limessafety; + double ymin = p1.Y() - his * limessafety; + double ymax = p1.Y() + his * limessafety; + double zmin = p1.Z() - his * limessafety; + double zmax = p1.Z() + his * limessafety; + + for (k = 1; k <= plimes2.Size(); k++) + { + const Point3d & p2 = plimes2.Get(k); + if (p2.X() >= xmin && p2.X() <= xmax && + p2.Y() >= ymin && p2.Y() <= ymax && + p2.Z() >= zmin && p2.Z() <= zmax) + { + dist = Dist2(plimes1.Get(j),plimes2.Get(k)); + if (dist < mindist) + { + mindist = dist; + } + } + } + */ + mindist = sqrt(mindist); + localh = mindist/limessafety; + + if (localh < minh && localh != 0) {localh = minh;} //minh is generally 0! (except make atlas) + if (localh < gh && localh > 0) + { + mesh.RestrictLocalH(plimes1.Get(j), localh); + // if (mindist < mincalch) {mincalch = mindist;} + // if (mindist > maxcalch) {maxcalch = mindist;} + if (mindist < chartmindist) {chartmindist = mindist;} + } + } + } + +} + + +//void * STLMeshingDummy (void *) +int STLMeshingDummy (STLGeometry* stlgeometry, Mesh*& mesh, + int perfstepsstart, int perfstepsend, char* optstring) +{ + if (perfstepsstart > perfstepsend) return 0; + + multithread.terminate = 0; + int success = 1; + //int trialcntouter = 0; + + if (perfstepsstart <= MESHCONST_MESHEDGES) + { + + mesh = new Mesh(); + mesh -> SetGlobalH (mparam.maxh); + mesh -> SetLocalH (stlgeometry->GetBoundingBox().PMin() - Vec3d(10, 10, 10), + stlgeometry->GetBoundingBox().PMax() + Vec3d(10, 10, 10), + mparam.grading); + mesh -> LoadLocalMeshSize (mparam.meshsizefilename); + + success = 0; + + //mesh->DeleteMesh(); + + STLMeshing (*stlgeometry, *mesh); + + stlgeometry->edgesfound = 1; + stlgeometry->surfacemeshed = 0; + stlgeometry->surfaceoptimized = 0; + stlgeometry->volumemeshed = 0; + } + + if (multithread.terminate) + return 0; + + if (perfstepsstart <= MESHCONST_MESHSURFACE && + perfstepsend >= MESHCONST_MESHSURFACE) + { + + if (!stlgeometry->edgesfound) + { + PrintUserError("You have to do 'analyse geometry' first!!!"); + return 0; + } + if (stlgeometry->surfacemeshed || stlgeometry->surfacemeshed) + { + PrintUserError("Already meshed. Please start again with 'Analyse Geometry'!!!"); + return 0; + } + + success = 0; + int retval = STLSurfaceMeshing (*stlgeometry, *mesh); + if (retval == MESHING3_OK) + { + PrintMessage(3,"Success !!!!"); + stlgeometry->surfacemeshed = 1; + stlgeometry->surfaceoptimized = 0; + stlgeometry->volumemeshed = 0; + success = 1; + } + else if (retval == MESHING3_OUTERSTEPSEXCEEDED) + { + PrintError("Give up because of too many trials. Meshing aborted!"); + } + else if (retval == MESHING3_TERMINATE) + { + PrintWarning("Meshing Stopped by user!"); + } + else + { + PrintError("Surface meshing not successful. Meshing aborted!"); + } + +#ifdef STAT_STREAM + (*statout) << mesh->GetNSeg() << " & " << endl + << mesh->GetNSE() << " & " << endl + << GetTime() << " & "; +#endif + } + if (multithread.terminate) + return 0; + + if (success) + { + if (perfstepsstart <= MESHCONST_OPTSURFACE && + perfstepsend >= MESHCONST_OPTSURFACE) + { + if (!stlgeometry->edgesfound) + { + PrintUserError("You have to do 'meshing->analyse geometry' first!!!"); + return 0; + } + if (!stlgeometry->surfacemeshed) + { + PrintUserError("You have to do 'meshing->mesh surface' first!!!"); + return 0; + } + if (stlgeometry->volumemeshed) + { + PrintWarning("Surface optimization with meshed volume is dangerous!!!"); + } + + if (!optstring || strlen(optstring) == 0) + { + mparam.optimize2d = "smcm"; + } + else + { + mparam.optimize2d = optstring; + } + + STLSurfaceOptimization (*stlgeometry, *mesh, mparam); + + if (stlparam.recalc_h_opt) + { + mesh -> SetLocalH (stlgeometry->GetBoundingBox().PMin() - Vec3d(10, 10, 10), + stlgeometry->GetBoundingBox().PMax() + Vec3d(10, 10, 10), + mparam.grading); + mesh -> LoadLocalMeshSize (mparam.meshsizefilename); + mesh -> CalcLocalHFromSurfaceCurvature (stlparam.resthsurfmeshcurvfac); + mparam.optimize2d = "cmsmSm"; + STLSurfaceOptimization (*stlgeometry, *mesh, mparam); +#ifdef STAT_STREAM + (*statout) << GetTime() << " & "; +#endif + +#ifdef OPENGL + extern void Render(); + Render(); +#endif + } + stlgeometry->surfaceoptimized = 1; + } + if (multithread.terminate) + return 0; + + if (perfstepsstart <= MESHCONST_MESHVOLUME && + perfstepsend >= MESHCONST_MESHVOLUME) + { + if (stlgeometry->volumemeshed) + { + PrintUserError("Volume already meshed!"); return 0; + } + + if (!stlgeometry->edgesfound) + { + PrintUserError("You have to do 'meshing->analyse geometry' first!!!"); + return 0; + } + if (!stlgeometry->surfacemeshed) + { + PrintUserError("You have to do 'meshing->mesh surface' first!!!"); + return 0; + } + if (!stlgeometry->surfaceoptimized) + { + PrintWarning("You should do 'meshing->optimize surface' first!!!"); + } + + PrintMessage(5,"Check Overlapping boundary: "); + mesh->FindOpenElements(); + mesh->CheckOverlappingBoundary(); + PrintMessage(5,""); + + if (stlparam.recalc_h_opt) + { + mesh -> SetLocalH (stlgeometry->GetBoundingBox().PMin() - Vec3d(10, 10, 10), + stlgeometry->GetBoundingBox().PMax() + Vec3d(10, 10, 10), + mparam.grading); + mesh -> LoadLocalMeshSize (mparam.meshsizefilename); + mesh -> CalcLocalH (); + } + + + PrintMessage(5,"Volume meshing"); + int retval = MeshVolume (mparam, *mesh); + if (retval == MESHING3_OK) + { + RemoveIllegalElements(*mesh); + stlgeometry->volumemeshed = 1; + } + else if (retval == MESHING3_OUTERSTEPSEXCEEDED) + { + PrintError("Give up because of too many trials. Meshing aborted!"); + return 0; + } + else if (retval == MESHING3_TERMINATE) + { + PrintWarning("Meshing Stopped by user!"); + } + else + { + PrintError("Volume meshing not successful. Meshing aborted!"); + return 0; + } + +#ifdef STAT_STREAM + (*statout) << GetTime() << " & " << endl; +#endif + MeshQuality3d (*mesh); + } + + if (multithread.terminate) + return 0; + + if (perfstepsstart <= MESHCONST_OPTVOLUME && + perfstepsend >= MESHCONST_OPTVOLUME) + { + if (!stlgeometry->edgesfound) + { + PrintUserError("You have to do 'meshing->analyse geometry' first!!!"); + return 0; + } + if (!stlgeometry->surfacemeshed) + { + PrintUserError("You have to do 'meshing->mesh surface' first!!!"); + return 0; + } + if (!stlgeometry->volumemeshed) + { + PrintUserError("You have to do 'meshing->mesh volume' first!!!"); + return 0; + } + + if (!optstring || strlen(optstring) == 0) + { + mparam.optimize3d = "cmdmstm"; + } + else + { + mparam.optimize3d = optstring; + } + + + OptimizeVolume (mparam, *mesh); + +#ifdef STAT_STREAM + (*statout) << GetTime() << " & " << endl; + (*statout) << mesh->GetNE() << " & " << endl + << mesh->GetNP() << " " << '\\' << '\\' << " \\" << "hline" << endl; +#endif + +#ifdef OPENGL + extern void Render(); + Render(); +#endif + + } + } + + + return 0; +} + + + +} diff --git a/contrib/Netgen/libsrc/stlgeom/stlline.cpp b/contrib/Netgen/libsrc/stlgeom/stlline.cpp new file mode 100644 index 0000000000..0fe01967e6 --- /dev/null +++ b/contrib/Netgen/libsrc/stlgeom/stlline.cpp @@ -0,0 +1,780 @@ +#include <mystdlib.h> + +#include <myadt.hpp> +#include <linalg.hpp> +#include <gprim.hpp> + +#include <meshing.hpp> + +#include "stlgeom.hpp" + +namespace netgen +{ + +//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +//++++++++++++++ EDGE DATA ++++++++++++++++++++++++++++++++++++++++++ +//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + + +/* +void STLEdgeData :: Write(ofstream& of) const +{ + of // << angle << " " + << p1 << " " + << p2 << " " + << lt << " " + << rt << " " + // << status + << endl; +} + +void STLEdgeData :: Read(ifstream& ifs) +{ + // ifs >> angle; + ifs >> p1; + ifs >> p2; + ifs >> lt; + ifs >> rt; + // ifs >> status; +} + + +int STLEdgeData :: GetStatus () const +{ + if (topedgenr <= 0 || topedgenr > top->GetNTE()) return 0; + return top->GetTopEdge (topedgenr).GetStatus(); +} + +void STLEdgeData ::SetStatus (int stat) +{ + if (topedgenr >= 1 && topedgenr <= top->GetNTE()) + top->GetTopEdge (topedgenr).SetStatus(stat); +} + + +float STLEdgeData :: CosAngle() const +{ + return top->GetTopEdge (topedgenr).CosAngle(); +} + + + +void STLEdgeDataList :: ResetAll() +{ + int i; + for (i = 1; i <= edgedata.Size(); i++) + { + edgedata.Elem(i).SetUndefined(); + } +} + +void STLEdgeDataList :: ResetCandidates() +{ + int i; + for (i = 1; i <= edgedata.Size(); i++) + { + if (edgedata.Get(i).Candidate()) + {edgedata.Elem(i).SetUndefined();} + } +} + +int STLEdgeDataList :: GetNConfEdges() const +{ + int i; + int cnt = 0; + for (i = 1; i <= edgedata.Size(); i++) + { + if (edgedata.Get(i).Confirmed()) {cnt++;} + } + return cnt; +} + +void STLEdgeDataList :: ConfirmCandidates() +{ + int i; + for (i = 1; i <= edgedata.Size(); i++) + { + if (edgedata.Get(i).Candidate()) + {edgedata.Elem(i).SetConfirmed();} + } +} + +int STLEdgeDataList :: GetEdgeNum(int np1, int np2) const +{ + INDEX_2 ed(np1,np2); + ed.Sort(); + if (hashtab.Used(ed)) + { + return hashtab.Get(ed); + } + +// int i; +// for (i = 1; i <= Size(); i++) +// { +// if ((Get(i).p1 == np1 && Get(i).p2 == np2) || +// (Get(i).p2 == np1 && Get(i).p1 == np2)) +// { +// return i; +// } +// } + + return 0; +} + +const STLEdgeDataList& STLEdgeDataList :: operator=(const STLEdgeDataList& edl) +{ + int i; + SetSize(edl.Size()); + for (i = 1; i <= Size(); i++) + { + Add(edl.Get(i), i); + } + return *this; +} + +void STLEdgeDataList :: Add(const STLEdgeData& ed, int i) +{ + INDEX_2 edge(ed.p1,ed.p2); + edge.Sort(); + hashtab.Set(edge, i); + Elem(i) = ed; + AddEdgePP(ed.p1,i); + AddEdgePP(ed.p2,i); +} + +void STLEdgeDataList :: Write(ofstream& of) const +{ + of.precision(16); + int i; + of << Size() << endl; + + for (i = 1; i <= Size(); i++) + { + Get(i).Write(of); + } +} + +void STLEdgeDataList :: Read(ifstream& ifs) +{ + int i,n; + ifs >> n; + + SetSize(n); + STLEdgeData ed; + for (i = 1; i <= n; i++) + { + ed.Read(ifs); + Add(ed,i); + } +} + +int STLEdgeDataList :: GetNEPPStat(int p, int status) const +{ + int i; + int cnt = 0; + for (i = 1; i <= GetNEPP(p); i++) + { + if (Get(GetEdgePP(p,i)).GetStatus() == status) + { + cnt++; + } + } + return cnt; +} + +int STLEdgeDataList :: GetNConfCandEPP(int p) const +{ + int i; + int cnt = 0; + for (i = 1; i <= GetNEPP(p); i++) + { + if (Get(GetEdgePP(p,i)).ConfCand()) + { + cnt++; + } + } + return cnt; +} + + +void STLEdgeDataList :: BuildLineWithEdge(int ep1, int ep2, ARRAY<twoint>& line) +{ + int status = Get(GetEdgeNum(ep1,ep2)).GetStatus(); + + int found, pstart, p, en, pnew, ennew; + int closed = 0; + int j, i; + for (j = 1; j <= 2; j++) + { + if (j == 1) {p = ep1;} + if (j == 2) {p = ep2;} + + pstart = p; + en = GetEdgeNum(ep1,ep2); + + found = 1; + while (found && !closed) + { + found = 0; + + if (GetNEPPStat(p,status) == 2) + { + for (i = 1; i <= GetNEPP(p); i++) + { + const STLEdgeData& e = Get(GetEdgePP(p,i)); + if (GetEdgePP(p,i) != en && e.GetStatus() == status) + { + if (e.p1 == p) + {pnew = e.p2;} + else + {pnew = e.p1;} + + ennew = GetEdgePP(p,i); + } + } + if (pnew == pstart) {closed = 1;} + else + { + line.Append(twoint(p,pnew)); + p = pnew; + en = ennew; + found = 1; + } + } + } + } + +} +*/ + + + + +STLEdgeDataList :: STLEdgeDataList (STLTopology & ageom) + : geom(ageom) +{ + ; +} + +STLEdgeDataList :: ~STLEdgeDataList() +{ + ; +} + + +void STLEdgeDataList :: Store () +{ + int i, ne = geom.GetNTE(); + storedstatus.SetSize(ne); + for (i = 1; i <= ne; i++) + { + storedstatus.Elem(i) = Get(i).GetStatus(); + } +} + +void STLEdgeDataList :: Restore () +{ + int i, ne = geom.GetNTE(); + if (storedstatus.Size() == ne) + for (i = 1; i <= ne; i++) + geom.GetTopEdge(i).SetStatus (storedstatus.Elem(i)); +} + + +void STLEdgeDataList :: ResetAll() +{ + int i, ne = geom.GetNTE(); + for (i = 1; i <= ne; i++) + geom.GetTopEdge (i).SetStatus (ED_UNDEFINED); +} + +int STLEdgeDataList :: GetNConfEdges() const +{ + int i, ne = geom.GetNTE(); + int cnt = 0; + for (i = 1; i <= ne; i++) + if (geom.GetTopEdge (i).GetStatus() == ED_CONFIRMED) + cnt++; + return cnt; +} + +void STLEdgeDataList :: ChangeStatus(int status1, int status2) +{ + int i, ne = geom.GetNTE(); + for (i = 1; i <= ne; i++) + if (geom.GetTopEdge (i).GetStatus() == status1) + geom.GetTopEdge (i).SetStatus (status2); +} + +/* +void STLEdgeDataList :: Add(const STLEdgeData& ed, int i) +{ + INDEX_2 edge(ed.p1,ed.p2); + edge.Sort(); + hashtab.Set(edge, i); + Elem(i) = ed; + AddEdgePP(ed.p1,i); + AddEdgePP(ed.p2,i); +} +*/ + +void STLEdgeDataList :: Write(ofstream& of) const +{ + + /* + of.precision(16); + int i; + of << Size() << endl; + + for (i = 1; i <= Size(); i++) + { + Get(i).Write(of); + } + + */ + of.precision(16); + int i, ne = geom.GetNTE(); + //of << GetNConfEdges() << endl; + of << geom.GetNTE() << endl; + + for (i = 1; i <= ne; i++) + { + const STLTopEdge & edge = geom.GetTopEdge(i); + //if (edge.GetStatus() == ED_CONFIRMED) + of << edge.GetStatus() << " "; + + const Point3d & p1 = geom.GetPoint (edge.PNum(1)); + const Point3d & p2 = geom.GetPoint (edge.PNum(2)); + of << p1.X() << " " + << p1.Y() << " " + << p1.Z() << " " + << p2.X() << " " + << p2.Y() << " " + << p2.Z() << endl; + } + +} + +void STLEdgeDataList :: Read(ifstream& ifs) +{ + int i, nce; + Point3d p1, p2; + int pi1, pi2; + int status, ednum; + + ifs >> nce; + for (i = 1; i <= nce; i++) + { + ifs >> status; + ifs >> p1.X() >> p1.Y() >> p1.Z(); + ifs >> p2.X() >> p2.Y() >> p2.Z(); + + pi1 = geom.GetPointNum (p1); + pi2 = geom.GetPointNum (p2); + ednum = geom.GetTopEdgeNum (pi1, pi2); + + + if (ednum) + { + geom.GetTopEdge(ednum).SetStatus (status); + // geom.GetTopEdge (ednum).SetStatus (ED_CONFIRMED); + } + } + /* + int i,n; + ifs >> n; + + SetSize(n); + STLEdgeData ed; + for (i = 1; i <= n; i++) + { + ed.Read(ifs); + Add(ed,i); + } + */ +} + +int STLEdgeDataList :: GetNEPPStat(int p, int status) const +{ + int i; + int cnt = 0; + for (i = 1; i <= GetNEPP(p); i++) + { + if (Get(GetEdgePP(p,i)).GetStatus() == status) + { + cnt++; + } + } + return cnt; +} + +int STLEdgeDataList :: GetNConfCandEPP(int p) const +{ + int i; + int cnt = 0; + for (i = 1; i <= GetNEPP(p); i++) + { + if (Get(GetEdgePP(p,i)).GetStatus() == ED_CANDIDATE || + Get(GetEdgePP(p,i)).GetStatus() == ED_CONFIRMED) + { + cnt++; + } + } + return cnt; +} + + +void STLEdgeDataList :: BuildLineWithEdge(int ep1, int ep2, ARRAY<twoint>& line) +{ + int status = Get(GetEdgeNum(ep1,ep2)).GetStatus(); + + int found, pstart, p, en, pnew, ennew; + int closed = 0; + int j, i; + for (j = 1; j <= 2; j++) + { + if (j == 1) {p = ep1;} + if (j == 2) {p = ep2;} + + pstart = p; + en = GetEdgeNum(ep1,ep2); + + found = 1; + while (found && !closed) + { + found = 0; + + if (GetNEPPStat(p,status) == 2) + { + for (i = 1; i <= GetNEPP(p); i++) + { + const STLTopEdge & e = Get(GetEdgePP(p,i)); + if (GetEdgePP(p,i) != en && e.GetStatus() == status) + { + if (e.PNum(1) == p) + {pnew = e.PNum(2);} + else + {pnew = e.PNum(1);} + + ennew = GetEdgePP(p,i); + } + } + if (pnew == pstart) {closed = 1;} + else + { + line.Append(twoint(p,pnew)); + p = pnew; + en = ennew; + found = 1; + } + } + } + } + +} + +int Exists(int p1, int p2, const ARRAY<twoint>& line) +{ + int i; + for (i = 1; i <= line.Size(); i++) + { + if (line.Get(i).i1 == p1 && line.Get(i).i2 == p2 || + line.Get(i).i1 == p2 && line.Get(i).i2 == p1) {return 1;} + } + return 0; +} + +void STLEdgeDataList :: BuildClusterWithEdge(int ep1, int ep2, ARRAY<twoint>& line) +{ + int status = Get(GetEdgeNum(ep1,ep2)).GetStatus(); + + int p, en; + int j, i, k; + int oldend; + int newend = 1; + int pnew, ennew; + + int changed = 1; + while (changed) + { + changed = 0; + for (j = 1; j <= 2; j++) + { + oldend = newend; + newend = line.Size(); + for (k = oldend; k <= line.Size(); k++) + { + if (j == 1) p = line.Get(k).i1; + if (j == 2) p = line.Get(k).i2; + en = GetEdgeNum(line.Get(k).i1, line.Get(k).i2); + + for (i = 1; i <= GetNEPP(p); i++) + { + pnew = 0; + const STLTopEdge & e = Get(GetEdgePP(p,i)); + if (GetEdgePP(p,i) != en && e.GetStatus() == status) + { + if (e.PNum(1) == p) + {pnew = e.PNum(2);} + else + {pnew = e.PNum(1);} + + ennew = GetEdgePP(p,i); + } + if (pnew && !Exists(p,pnew,line)) + { + changed = 1; + line.Append(twoint(p,pnew)); + p = pnew; + en = ennew; + } + } + + } + } + + } + +} + + + + + + + + + + +//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +//+++++++++++++++++++ STL LINE +++++++++++++++++++++++++++++++ +//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +STLLine :: STLLine(const STLGeometry * ageometry) + : pts(), lefttrigs(), righttrigs() +{ + geometry = ageometry; + split = 0; +} + +int STLLine :: GetNS() const +{ + if (pts.Size() <= 1) {return 0;} + return pts.Size()-1; +} +void STLLine :: GetSeg(int nr, int& p1, int& p2) const +{ + p1 = pts.Get(nr); + p2 = pts.Get(nr+1); +} + +int STLLine :: GetLeftTrig(int nr) const +{ + if (nr > lefttrigs.Size()) {PrintSysError("In STLLine::GetLeftTrig!!!"); return 0;} + return lefttrigs.Get(nr); +} + +int STLLine :: GetRightTrig(int nr) const +{ + if (nr > righttrigs.Size()) {PrintSysError("In STLLine::GetRightTrig!!!"); return 0;} + return righttrigs.Get(nr); +} + +double STLLine :: GetSegLen(const ARRAY<Point<3> >& ap, int nr) const +{ + return Dist(ap.Get(PNum(nr)),ap.Get(PNum(nr+1))); +} + +double STLLine :: GetLength(const ARRAY<Point<3> >& ap) const +{ + double len = 0; + for (int i = 2; i <= pts.Size(); i++) + { + len += (ap.Get(pts.Get(i)) - ap.Get(pts.Get(i-1))).Length(); + } + return len; +} + +void STLLine :: GetBoundingBox (const ARRAY<Point<3> > & ap, Box<3> & box) const +{ + box.Set (ap.Get (pts[0])); + for (int i = 1; i < pts.Size(); i++) + box.Add (ap.Get(pts[i])); +} + + + +Point<3> STLLine :: +GetPointInDist(const ARRAY<Point<3> >& ap, double dist, int& index) const +{ + if (dist <= 0) + { + index = 1; + return ap.Get(StartP()); + } + + double len = 0; + int i; + for (i = 1; i < pts.Size(); i++) + { + double seglen = Dist (ap.Get(pts.Get(i)), + ap.Get(pts.Get(i+1))); + + if (len + seglen > dist) + { + index = i; + double relval = (dist - len) / (seglen + 1e-16); + Vec3d v (ap.Get(pts.Get(i)), ap.Get(pts.Get(i+1))); + return ap.Get(pts.Get(i)) + relval * v; + } + + len += seglen; + } + + index = pts.Size() - 1; + return ap.Get(EndP()); +} + + +/* +double stlgh; +double GetH(const Point3d& p, double x) +{ + return stlgh;//+0.5)*(x+0.5); +} +*/ +STLLine* STLLine :: Mesh(const ARRAY<Point<3> >& ap, + ARRAY<Point3d>& mp, double ghi, + class Mesh& mesh) const +{ + STLLine* line = new STLLine(geometry); + + //stlgh = ghi; //uebergangsloesung!!!! + + double len = GetLength(ap); + double inthl = 0; //integral of 1/h + double dist = 0; + double h; + int ind; + Point3d p; + + int i, j; + + Box<3> bbox; + GetBoundingBox (ap, bbox); + double diam = bbox.Diam(); + + double minh = mesh.LocalHFunction().GetMinH (bbox.PMin(), bbox.PMax()); + + double maxseglen = 0; + for (i = 1; i <= GetNS(); i++) + maxseglen = max2 (maxseglen, GetSegLen (ap, i)); + + int nph = 10+int(maxseglen / minh); //anzahl der integralauswertungen pro segment + + ARRAY<double> inthi(GetNS()*nph); + ARRAY<double> curvelen(GetNS()*nph); + + + for (i = 1; i <= GetNS(); i++) + { + double seglen = GetSegLen(ap,i); + for (j = 1; j <= nph; j++) + { + p = GetPointInDist(ap,dist,ind); + //h = GetH(p,dist/len); + h = mesh.GetH(p); + + + dist += GetSegLen(ap,i)/(double)nph; + + inthl += GetSegLen(ap,i)/nph/(h); + inthi.Elem((i-1)*nph+j) = GetSegLen(ap,i)/nph/h; + curvelen.Elem((i-1)*nph+j) = GetSegLen(ap,i)/nph; + } + } + + + int inthlint = int(inthl+1); + + if ( (inthlint < 3) && (StartP() == EndP())) + { + inthlint = 3; + } + if ( (inthlint == 1) && ShouldSplit()) + { + inthlint = 2; + } + + double fact = inthl/(double)inthlint; + dist = 0; + j = 1; + + + p = ap.Get(StartP()); + int pn = AddPointIfNotExists(mp, p, 1e-10*diam); + + int segn = 1; + line->AddPoint(pn); + line->AddLeftTrig(GetLeftTrig(segn)); + line->AddRightTrig(GetRightTrig(segn)); + line->AddDist(dist); + + inthl = 0; //restart each meshseg + for (i = 1; i <= inthlint; i++) + { + while (inthl < 1.000000001 && j <= inthi.Size()) + // while (inthl-1. < 1e-9) && j <= inthi.Size()) + { + inthl += inthi.Get(j)/fact; + dist += curvelen.Get(j); + j++; + } + + //went to far: + j--; + double tofar = (inthl - 1)/inthi.Get(j); + inthl -= tofar*inthi.Get(j); + dist -= tofar*curvelen.Get(j)*fact; + + if (i == inthlint && fabs(dist - len) >= 1E-8) + { + PrintSysError("meshline failed!!!"); + } + + if (i != inthlint) + { + p = GetPointInDist(ap,dist,ind); + pn = AddPointIfNotExists(mp, p, 1e-10*diam); + segn = ind; + line->AddPoint(pn); + line->AddLeftTrig(GetLeftTrig(segn)); + line->AddRightTrig(GetRightTrig(segn)); + line->AddDist(dist); + } + + inthl = tofar*inthi.Get(j); + dist += tofar*curvelen.Get(j)*fact; + j++; + } + + p = ap.Get(EndP()); + pn = AddPointIfNotExists(mp, p, 1e-10*diam); + segn = GetNS(); + line->AddPoint(pn); + line->AddLeftTrig(GetLeftTrig(segn)); + line->AddRightTrig(GetRightTrig(segn)); + line->AddDist(dist); + + for (int ii = 1; ii <= line->GetNS(); ii++) + { + int p1, p2; + line->GetSeg(ii,p1,p2); + } + /* + (*testout) << "line, " << ap.Get(StartP()) << "-" << ap.Get(EndP()) + << " len = " << Dist (ap.Get(StartP()), ap.Get(EndP())) << endl; + */ + return line; +} +} diff --git a/contrib/Netgen/libsrc/stlgeom/stlline.hpp b/contrib/Netgen/libsrc/stlgeom/stlline.hpp new file mode 100644 index 0000000000..70393ca060 --- /dev/null +++ b/contrib/Netgen/libsrc/stlgeom/stlline.hpp @@ -0,0 +1,188 @@ +#ifndef FILE_STLLINE +#define FILE_STLLINE + + +/**************************************************************************/ +/* File: stlline.hh */ +/* Author: Joachim Schoeberl */ +/* Author2: Johannes Gerstmayr */ +/* Date: 20. Nov. 99 */ +/**************************************************************************/ + +class STLGeometry; +class STLTopology; + +class STLEdge +{ +public: + int pts[2]; + int trigs[2]; //left and right trig + + STLEdge (const int * apts) {pts[0] = apts[0]; pts[1] = apts[1];} + STLEdge (int v1, int v2) {pts[0] = v1; pts[1] = v2;} + STLEdge () {pts[0]=0;pts[1]=0;} + int PNum(int i) const {return pts[(i-1)];} + + int LeftTrig() const {return trigs[0];} + int RightTrig() const {return trigs[1];} + void SetLeftTrig(int i) {trigs[0] = i;} + void SetRightTrig(int i) {trigs[1] = i;} +}; + +enum STL_ED_STATUS { ED_EXCLUDED, ED_CONFIRMED, ED_CANDIDATE, ED_UNDEFINED }; + + +/* + +class STLEdgeData +{ +public: + // float angle; + int p1; + int p2; + int lt; //left trig + int rt; //right trig + // int status; + + STLTopology * top; // pointer to stl topology + int topedgenr; // number of corresponding topology edge + + STLEdgeData() {}; + STLEdgeData(float anglei, int p1i, int p2i, int lti, int rti) +{ +// angle = anglei; +p1 = p1i; p2 = p2i; + lt = lti; rt = rti; + } + + int GetStatus () const; + void SetStatus (int stat); + + void SetExcluded() { SetStatus (ED_EXCLUDED); } + void SetConfirmed() { SetStatus (ED_CONFIRMED); } + void SetCandidate() { SetStatus (ED_CANDIDATE); } + void SetUndefined() { SetStatus (ED_UNDEFINED); } + + int Excluded() const {return GetStatus() == ED_EXCLUDED;} + int Confirmed() const {return GetStatus() == ED_CONFIRMED;} + int Candidate() const {return GetStatus() == ED_CANDIDATE;} + int Undefined() const {return GetStatus() == ED_UNDEFINED;} + int ConfCand() const {return GetStatus() == ED_CONFIRMED || GetStatus() == ED_CANDIDATE;} + + float CosAngle() const; + + void Write(ofstream& of) const; + void Read(ifstream& ifs); +}; + +class STLEdgeDataList +{ +private: + INDEX_2_HASHTABLE<int> hashtab; + ARRAY<STLEdgeData> edgedata; + TABLE<int> edgesperpoint; + +public: + + STLEdgeDataList():edgedata(),hashtab(1),edgesperpoint() {}; + const STLEdgeDataList& operator=(const STLEdgeDataList& edl); + void SetSize(int size) + { + edgedata.SetSize(size); + hashtab.SetSize(size); + edgesperpoint.SetSize(size); + } + void Clear() {SetSize(0);} + int Size() const {return edgedata.Size();} + const STLEdgeData& Get(int i) const {return edgedata.Get(i);} + STLEdgeData& Elem(int i) {return edgedata.Elem(i);} + void Add(const STLEdgeData& ed, int i); + + int GetNEPP(int pn) const + { + return edgesperpoint.EntrySize(pn); + }; + int GetEdgePP(int pn, int vi) const + { + return edgesperpoint.Get(pn,vi); + }; + void AddEdgePP(int pn, int vn) {edgesperpoint.Add(pn,vn);}; + + void ResetAll(); + void ResetCandidates(); + void ConfirmCandidates(); + int GetEdgeNum(int np1, int np2) const; + + int GetNConfEdges() const; + + void Write(ofstream& of) const; + void Read(ifstream& ifs); + + void BuildLineWithEdge(int ep1, int ep2, ARRAY<twoint>& line); + + int GetNEPPStat(int p, int status) const; + int GetNConfCandEPP(int p) const; +}; +*/ + + + + + + + + + + + + + + + + +//a line defined by several points (polyline) +class STLLine +{ +private: + const STLGeometry * geometry; + ARRAY<int> pts; + ARRAY<int> lefttrigs; + ARRAY<int> righttrigs; + ARRAY<double> dists; + int split; + +public: + STLLine(const STLGeometry * ageometry); + void AddPoint(int i) {pts.Append(i);} + int PNum(int i) const {return pts.Get(i);} + int NP() const {return pts.Size();} + int GetNS() const; + void GetSeg(int nr, int& p1, int& p2) const; + double GetSegLen(const ARRAY<Point<3> >& ap, int nr) const; + int GetLeftTrig(int nr) const; + int GetRightTrig(int nr) const; + double GetDist(int nr) const { return dists.Get(nr);}; + void GetBoundingBox (const ARRAY<Point<3> > & ap, Box<3> & box) const; + + void AddLeftTrig(int nr) {lefttrigs.Append(nr);} + void AddRightTrig(int nr) {righttrigs.Append(nr);} + void AddDist (double dist) {dists.Append(dist); } + int StartP() const {return pts.Get(1);} + int EndP() const {return pts.Get(pts.Size());} + + double GetLength(const ARRAY<Point<3> >& ap) const; + + //suche punkt in entfernung (in linienkoordinaten) dist + //in index ist letzter punkt VOR dist (d.h. max pts.Size()-1) + Point<3> GetPointInDist(const ARRAY<Point<3> >& ap, double dist, int& index) const; + + //return a meshed polyline + STLLine* Mesh(const ARRAY<Point<3> >& ap, + ARRAY<Point3d>& mp, double ghi, + class Mesh& mesh) const; + + void DoSplit() {split = 1;} + int ShouldSplit() const {return split;} +}; + +#endif diff --git a/contrib/Netgen/libsrc/stlgeom/stltool.cpp b/contrib/Netgen/libsrc/stlgeom/stltool.cpp new file mode 100644 index 0000000000..c19fed4ca0 --- /dev/null +++ b/contrib/Netgen/libsrc/stlgeom/stltool.cpp @@ -0,0 +1,1288 @@ +#include <mystdlib.h> + +#include <myadt.hpp> +#include <linalg.hpp> +#include <gprim.hpp> + +#include <meshing.hpp> + +#include "stlgeom.hpp" + +namespace netgen +{ + + +//add a point into a pointlist, return pointnumber +int AddPointIfNotExists(ARRAY<Point3d>& ap, const Point3d& p, double eps) +{ + int i; + for (i = 1; i <= ap.Size(); i++) + { + if (Dist(ap.Get(i),p) <= eps ) {return i;} + } + return ap.Append(p); +} + +//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +double GetDistFromLine(const Point<3> & lp1, const Point<3> & lp2, + Point<3> & p) +{ + Vec3d vn = lp2 - lp1; + Vec3d v1 = p - lp1; + Vec3d v2 = lp2 - p; + + Point3d pold = p; + + if (v2 * vn <= 0) {p = lp2; return (pold - p).Length();} + if (v1 * vn <= 0) {p = lp1; return (pold - p).Length();} + + double vnl = vn.Length(); + if (vnl == 0) {return Dist(lp1,p);} + + vn /= vnl; + p = lp1 + (v1 * vn) * vn; + return (pold - p).Length(); +} + +double GetDistFromInfiniteLine(const Point<3>& lp1, const Point<3>& lp2, const Point<3>& p) +{ + Vec3d vn(lp1, lp2); + Vec3d v1(lp1, p); + + double vnl = vn.Length(); + + if (vnl == 0) + { + return Dist (lp1, p); + } + else + { + return Cross (vn, v1).Length() / vnl; + } +} + + + +//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +//Binary IO-Manipulation + + + +void FIOReadInt(istream& ios, int& i) +{ + const int ilen = sizeof(int); + + char buf[ilen]; + int j; + for (j = 0; j < ilen; j++) + { + ios.get(buf[j]); + } + memcpy(&i, &buf, ilen); +} + +void FIOWriteInt(ostream& ios, const int& i) +{ + const int ilen = sizeof(int); + + char buf[ilen]; + memcpy(&buf, &i, ilen); + + int j; + for (j = 0; j < ilen; j++) + { + ios << buf[j]; + } +} + +void FIOReadDouble(istream& ios, double& i) +{ + const int ilen = sizeof(double); + + char buf[ilen]; + int j; + for (j = 0; j < ilen; j++) + { + ios.get(buf[j]); + } + memcpy(&i, &buf, ilen); +} + +void FIOWriteDouble(ostream& ios, const double& i) +{ + const int ilen = sizeof(double); + + char buf[ilen]; + memcpy(&buf, &i, ilen); + + int j; + for (j = 0; j < ilen; j++) + { + ios << buf[j]; + } +} + +void FIOReadFloat(istream& ios, float& i) +{ + const int ilen = sizeof(float); + + char buf[ilen]; + int j; + for (j = 0; j < ilen; j++) + { + ios.get(buf[j]); + } + memcpy(&i, &buf, ilen); +} + +void FIOWriteFloat(ostream& ios, const float& i) +{ + const int ilen = sizeof(float); + + char buf[ilen]; + memcpy(&buf, &i, ilen); + + int j; + for (j = 0; j < ilen; j++) + { + ios << buf[j]; + } +} + +void FIOReadString(istream& ios, char* str, int len) +{ + int j; + for (j = 0; j < len; j++) + { + ios.get(str[j]); + } +} + +//read string and add terminating 0 +void FIOReadStringE(istream& ios, char* str, int len) +{ + int j; + for (j = 0; j < len; j++) + { + ios.get(str[j]); + } + str[len] = 0; +} + +void FIOWriteString(ostream& ios, char* str, int len) +{ + int j; + for (j = 0; j < len; j++) + { + ios << str[j]; + } +} + + +/* +void FIOReadInt(istream& ios, int& i) +{ + const int ilen = sizeof(int); + + char buf[ilen]; + int j; + for (j = 0; j < ilen; j++) + { + ios.get(buf[ilen-j-1]); + } + memcpy(&i, &buf, ilen); +} + +void FIOWriteInt(ostream& ios, const int& i) +{ + const int ilen = sizeof(int); + + char buf[ilen]; + memcpy(&buf, &i, ilen); + + int j; + for (j = 0; j < ilen; j++) + { + ios << buf[ilen-j-1]; + } +} + +void FIOReadDouble(istream& ios, double& i) +{ + const int ilen = sizeof(double); + + char buf[ilen]; + int j; + for (j = 0; j < ilen; j++) + { + ios.get(buf[ilen-j-1]); + } + memcpy(&i, &buf, ilen); +} + +void FIOWriteDouble(ostream& ios, const double& i) +{ + const int ilen = sizeof(double); + + char buf[ilen]; + memcpy(&buf, &i, ilen); + + int j; + for (j = 0; j < ilen; j++) + { + ios << buf[ilen-j-1]; + } +} + +void FIOReadFloat(istream& ios, float& i) +{ + const int ilen = sizeof(float); + + char buf[ilen]; + int j; + for (j = 0; j < ilen; j++) + { + ios.get(buf[ilen-j-1]); + } + memcpy(&i, &buf, ilen); +} + +void FIOWriteFloat(ostream& ios, const float& i) +{ + const int ilen = sizeof(float); + + char buf[ilen]; + memcpy(&buf, &i, ilen); + + int j; + for (j = 0; j < ilen; j++) + { + ios << buf[ilen-j-1]; + } +} + +void FIOReadString(istream& ios, char* str, int len) +{ + int j; + for (j = 0; j < len; j++) + { + ios.get(str[j]); + } +} + +//read string and add terminating 0 +void FIOReadStringE(istream& ios, char* str, int len) +{ + int j; + for (j = 0; j < len; j++) + { + ios.get(str[j]); + } + str[len] = 0; +} + +void FIOWriteString(ostream& ios, char* str, int len) +{ + int j; + for (j = 0; j < len; j++) + { + ios << str[j]; + } +} +*/ + +//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +STLReadTriangle :: STLReadTriangle (const Point<3> * apts, + const Vec<3> & anormal) +{ + pts[0] = apts[0]; + pts[1] = apts[1]; + pts[2] = apts[2]; + normal = anormal; +} + + + +STLTriangle :: STLTriangle(const int * apts) +{ + pts[0] = apts[0]; + pts[1] = apts[1]; + pts[2] = apts[2]; + + facenum = 0; +} + +int STLTriangle :: IsNeighbourFrom(const STLTriangle& t) const +{ + //triangles must have same orientation!!! + int i, j; + for(i = 0; i <= 2; i++) + { + for(j = 0; j <= 2; j++) + { + if (t.pts[(i+1)%3] == pts[j] && + t.pts[i] == pts[(j+1)%3]) + {return 1;} + } + } + return 0; +} + +int STLTriangle :: IsWrongNeighbourFrom(const STLTriangle& t) const +{ + //triangles have not same orientation!!! + int i, j; + for(i = 0; i <= 2; i++) + { + for(j = 0; j <= 2; j++) + { + if (t.pts[(i+1)%3] == pts[(j+1)%3] && + t.pts[i] == pts[j]) + {return 1;} + } + } + return 0; +} + +void STLTriangle :: GetNeighbourPoints(const STLTriangle& t, int& p1, int& p2) const +{ + int i, j; + for(i = 1; i <= 3; i++) + { + for(j = 1; j <= 3; j++) + { + if (t.PNumMod(i+1) == PNumMod(j) && + t.PNumMod(i) == PNumMod(j+1)) + {p1 = PNumMod(j); p2 = PNumMod(j+1); return;} + } + } + PrintSysError("Get neighbourpoints failed!"); +} + +int STLTriangle :: GetNeighbourPointsAndOpposite(const STLTriangle& t, int& p1, int& p2, int& po) const +{ + int i, j; + for(i = 1; i <= 3; i++) + { + for(j = 1; j <= 3; j++) + { + if (t.PNumMod(i+1) == PNumMod(j) && + t.PNumMod(i) == PNumMod(j+1)) + {p1 = PNumMod(j); p2 = PNumMod(j+1); po = PNumMod(j+2); return 1;} + } + } + return 0; +} + +Vec<3> STLTriangle :: GeomNormal(const ARRAY<Point<3> >& ap) const +{ + const Point<3> & p1 = ap.Get(PNum(1)); + const Point<3> & p2 = ap.Get(PNum(2)); + const Point<3> & p3 = ap.Get(PNum(3)); + + return Cross(p2-p1, p3-p1); +} + + +void STLTriangle :: SetNormal (const Vec<3> & n) +{ + double len = n.Length(); + if (len > 0) + { + normal = n; + normal.Normalize(); + } + else + { + normal = Vec<3> (1, 0, 0); + } +} + + +void STLTriangle :: ChangeOrientation() +{ + normal *= -1; + Swap(pts[0],pts[1]); +} + + + +double STLTriangle :: Area(const ARRAY<Point<3> >& ap) const +{ + return 0.5 * Cross(ap.Get(PNum(2))-ap.Get(PNum(1)), + ap.Get(PNum(3))-ap.Get(PNum(1))).Length(); +} + +double STLTriangle :: MinHeight(const ARRAY<Point<3> >& ap) const +{ + double ml = MaxLength(ap); + if (ml != 0) {return 2.*Area(ap)/ml;} + PrintWarning("max Side Length of a triangle = 0!!!"); + return 0; +} + +double STLTriangle :: MaxLength(const ARRAY<Point<3> >& ap) const +{ + return max3(Dist(ap.Get(PNum(1)),ap.Get(PNum(2))), + Dist(ap.Get(PNum(2)),ap.Get(PNum(3))), + Dist(ap.Get(PNum(3)),ap.Get(PNum(1)))); +} + +void STLTriangle :: ProjectInPlain(const ARRAY<Point<3> >& ap, + const Vec<3> & n, Point<3> & pp) const +{ + const Point<3> & p1 = ap.Get(PNum(1)); + const Point<3> & p2 = ap.Get(PNum(2)); + const Point<3> & p3 = ap.Get(PNum(3)); + + Vec<3> v1 = p2 - p1; + Vec<3> v2 = p3 - p1; + Vec<3> nt = Cross(v1, v2); + + double c = - (p1(0)*nt(0) + p1(1)*nt(1) + p1(2)*nt(2)); + + double prod = n * nt; + + if (fabs(prod) == 0) + { + pp = Point<3>(1.E20,1.E20,1.E20); + return; + } + + double nfact = -(pp(0)*nt(0) + pp(1)*nt(1) + pp(2)*nt(2) + c) / (prod); + pp = pp + (nfact) * n; + +} + + +int STLTriangle :: ProjectInPlain (const ARRAY<Point<3> >& ap, + const Vec<3> & nproj, + Point<3> & pp, Vec<3> & lam) const +{ + const Point<3> & p1 = ap.Get(PNum(1)); + const Point<3> & p2 = ap.Get(PNum(2)); + const Point<3> & p3 = ap.Get(PNum(3)); + + Vec<3> v1 = p2-p1; + Vec<3> v2 = p3-p1; + + Mat<3> mat; + for (int i = 0; i < 3; i++) + { + mat(i,0) = v1(i); + mat(i,1) = v2(i); + mat(i,2) = nproj(i); + } + + int err = 0; + mat.Solve (pp-p1, lam); + // int err = SolveLinearSystem (v1, v2, nproj, pp-p1, lam); + + if (!err) + { + // pp = p1 + lam(0) * v1 + lam(1) * v2; + + pp(0) = p1(0) + lam(0) * v1(0) + lam(1) * v2(0); + pp(1) = p1(1) + lam(0) * v1(1) + lam(1) * v2(1); + pp(2) = p1(2) + lam(0) * v1(2) + lam(1) * v2(2); + } + return err; +} + + + + + +void STLTriangle :: ProjectInPlain(const ARRAY<Point<3> >& ap, + Point<3> & pp) const +{ + const Point<3> & p1 = ap.Get(PNum(1)); + const Point<3> & p2 = ap.Get(PNum(2)); + const Point<3> & p3 = ap.Get(PNum(3)); + + Vec<3> v1 = p2 - p1; + Vec<3> v2 = p3 - p1; + Vec<3> nt = Cross(v1, v2); + + double c = - (p1(0)*nt(0) + p1(1)*nt(1) + p1(2)*nt(2)); + + double prod = nt * nt; + + double nfact = -(pp(0)*nt(0) + pp(1)*nt(1) + pp(2)*nt(2) + c) / (prod); + + pp = pp + (nfact) * nt; +} + +int STLTriangle :: PointInside(const ARRAY<Point<3> > & ap, + const Point<3> & pp) const +{ + const Point<3> & p1 = ap.Get(PNum(1)); + const Point<3> & p2 = ap.Get(PNum(2)); + const Point<3> & p3 = ap.Get(PNum(3)); + + Vec<3> v1 = p2 - p1; + Vec<3> v2 = p3 - p1; + Vec<3> v = pp - p1; + double det, l1, l2; + Vec<3> ex, ey, ez; + + + ez = GeomNormal(ap); + ez /= ez.Length(); + ex = v1; + ex /= ex.Length(); + ey = Cross (ez, ex); + + Vec<2> v1p(v1*ex, v1*ey); + Vec<2> v2p(v2*ex, v2*ey); + Vec<2> vp(v*ex, v*ey); + + det = v2p(1) * v1p(0) - v2p(0) * v1p(1); + + if (fabs(det) == 0) {return 0;} + + l2 = (vp(1) * v1p(0) - vp(0) * v1p(1)) / det; + + if (v1p(0) != 0.) + { + l1 = (vp(0) - l2 * v2p(0)) / v1p(0); + } + else if (v1p(1) != 0.) + { + l1 = (vp(1) - l2 * v2p(1)) / v1p(1); + } + else {return 0;} + + if (l1 >= -1E-10 && l2 >= -1E-10 && l1 + l2 <= 1.+1E-10) {return 1;} + return 0; +} + +double STLTriangle :: GetNearestPoint(const ARRAY<Point<3> >& ap, + Point<3> & p3d) const +{ + Point<3> p = p3d; + ProjectInPlain(ap, p); + double dist = (p - p3d).Length(); + + if (PointInside(ap, p)) {p3d = p; return dist;} + else + { + Point<3> pf; + double nearest = 1E50; + int fi = 0; + int j; + + for (j = 1; j <= 3; j++) + { + p = p3d; + dist = GetDistFromLine(ap.Get(PNum(j)), ap.Get(PNumMod(j+1)), p); + if (dist < nearest) + { + nearest = dist; + pf = p; + } + } + p3d = pf; + return nearest; + } +} + +int STLTriangle :: HasEdge(int p1, int p2) const +{ + int i; + for (i = 1; i <= 3; i++) + { + if (p1 == PNum(i) && p2 == PNumMod(i+1)) {return 1;} + } + return 0; +} + +ostream& operator<<(ostream& os, const STLTriangle& t) +{ + os << "["; + os << t[0] << ","; + os << t[1] << ","; + os << t[2] << "]"; + + return os; +} + + + +STLTopEdge :: STLTopEdge () +{ + pts[0] = pts[1] = 0; + trigs[0] = trigs[1] = 0; + cosangle = 1; + status = ED_UNDEFINED; +} + +STLTopEdge :: STLTopEdge (int p1, int p2, int trig1, int trig2) +{ + pts[0] = p1; + pts[1] = p2; + trigs[0] = trig1; + trigs[1] = trig2; + cosangle = 1; + status = ED_UNDEFINED; +} + + + + +//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +//+++++++++++++++++++ STL CHART +++++++++++++++++++++++++++++++ +//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +STLChart :: STLChart(STLGeometry * ageometry) +{ + charttrigs = new ARRAY<int> (0,0); + outertrigs = new ARRAY<int> (0,0); + ilimit = new ARRAY<twoint> (0,0); + olimit = new ARRAY<twoint> (0,0); + + geometry = ageometry; + + if ( (stlparam.usesearchtree == 1)) + searchtree = new Box3dTree (geometry->GetBoundingBox().PMin() - Vec3d(1,1,1), + geometry->GetBoundingBox().PMax() + Vec3d(1,1,1)); + else + searchtree = NULL; +} + +void STLChart :: AddChartTrig(int i) +{ + charttrigs->Append(i); + + const STLTriangle & trig = geometry->GetTriangle(i); + const Point3d & p1 = geometry->GetPoint (trig.PNum(1)); + const Point3d & p2 = geometry->GetPoint (trig.PNum(2)); + const Point3d & p3 = geometry->GetPoint (trig.PNum(3)); + + Point3d pmin(p1), pmax(p1); + pmin.SetToMin (p2); + pmin.SetToMin (p3); + pmax.SetToMax (p2); + pmax.SetToMax (p3); + + if (!geomsearchtreeon && (stlparam.usesearchtree == 1)) + {searchtree->Insert (pmin, pmax, i);} +} + +void STLChart :: AddOuterTrig(int i) +{ + outertrigs->Append(i); + + const STLTriangle & trig = geometry->GetTriangle(i); + const Point3d & p1 = geometry->GetPoint (trig.PNum(1)); + const Point3d & p2 = geometry->GetPoint (trig.PNum(2)); + const Point3d & p3 = geometry->GetPoint (trig.PNum(3)); + + Point3d pmin(p1), pmax(p1); + pmin.SetToMin (p2); + pmin.SetToMin (p3); + pmax.SetToMax (p2); + pmax.SetToMax (p3); + + if (!geomsearchtreeon && (stlparam.usesearchtree==1)) + {searchtree->Insert (pmin, pmax, i);} +} + +int STLChart :: IsInWholeChart(int nr) const +{ + int i; + for (i = 1; i <= charttrigs->Size(); i++) + { + if (charttrigs->Get(i) == nr) {return 1;} + } + for (i = 1; i <= outertrigs->Size(); i++) + { + if (outertrigs->Get(i) == nr) {return 1;} + } + return 0; +} + +void STLChart :: GetTrianglesInBox (const Point3d & pmin, + const Point3d & pmax, + ARRAY<int> & trias) const +{ + if (geomsearchtreeon) {PrintMessage(5,"geomsearchtreeon is set!!!");} + + if (searchtree) + searchtree -> GetIntersecting (pmin, pmax, trias); + else + { + int i; + Box3d box1(pmin, pmax); + box1.Increase (1e-4); + Box3d box2; + + trias.SetSize(0); + + int nt = GetNT(); + for (i = 1; i <= nt; i++) + { + + int trignum = GetTrig(i); + const STLTriangle & trig = geometry->GetTriangle(trignum); + box2.SetPoint (geometry->GetPoint (trig.PNum(1))); + box2.AddPoint (geometry->GetPoint (trig.PNum(2))); + box2.AddPoint (geometry->GetPoint (trig.PNum(3))); + + if (box1.Intersect (box2)) + { + trias.Append (trignum); + } + } + } +} + +//trigs may contain the same triangle double +void STLChart :: MoveToOuterChart(const ARRAY<int>& trigs) +{ + if (!trigs.Size()) {return;} + int i; + for (i = 1; i <= trigs.Size(); i++) + { + if (charttrigs->Get(trigs.Get(i)) != -1) + {AddOuterTrig(charttrigs->Get(trigs.Get(i)));} + charttrigs->Elem(trigs.Get(i)) = -1; + } + DelChartTrigs(trigs); +} + +//trigs may contain the same triangle double +void STLChart :: DelChartTrigs(const ARRAY<int>& trigs) +{ + if (!trigs.Size()) {return;} + + int i; + for (i = 1; i <= trigs.Size(); i++) + { + charttrigs->Elem(trigs.Get(i)) = -1; + } + + int cnt = 0; + for (i = 1; i <= charttrigs->Size(); i++) + { + if (charttrigs->Elem(i) == -1) + { + cnt++; + } + if (cnt != 0 && i < charttrigs->Size()) + { + charttrigs->Elem(i-cnt+1) = charttrigs->Get(i+1); + } + } + i = charttrigs->Size() - trigs.Size(); + charttrigs->SetSize(i); + + if (!geomsearchtreeon && stlparam.usesearchtree == 1) + { + PrintMessage(7, "Warning: unsecure routine due to first use of searchtrees!!!"); + //bould new searchtree!!! + searchtree = new Box3dTree (geometry->GetBoundingBox().PMin() - Vec3d(1,1,1), + geometry->GetBoundingBox().PMax() + Vec3d(1,1,1)); + + for (i = 1; i <= charttrigs->Size(); i++) + { + const STLTriangle & trig = geometry->GetTriangle(i); + const Point3d & p1 = geometry->GetPoint (trig.PNum(1)); + const Point3d & p2 = geometry->GetPoint (trig.PNum(2)); + const Point3d & p3 = geometry->GetPoint (trig.PNum(3)); + + Point3d pmin(p1), pmax(p1); + pmin.SetToMin (p2); + pmin.SetToMin (p3); + pmax.SetToMax (p2); + pmax.SetToMax (p3); + + searchtree->Insert (pmin, pmax, i); + } + } +} + + +void STLChart :: SetNormal (const Point<3> & apref, const Vec<3> & anormal) +{ + pref = apref; + normal = anormal; + double len = normal.Length(); + if (len) normal /= len; + else normal = Vec<3> (1, 0, 0); + + t1 = normal.GetNormal (); + t2 = Cross (normal, t1); +} + +Point<2> STLChart :: Project2d (const Point<3> & p3d) const +{ + Vec<3> v = p3d-pref; + return Point<2> (t1 * v, t2 * v); +} + + + +/* + Point3d p1, p2, center; + double rad; + int i1, i2; +public: +*/ +STLBoundarySeg :: +STLBoundarySeg (int ai1, int ai2, const ARRAY<Point<3> > & points, + const STLChart * chart) +{ + i1 = ai1; + i2 = ai2; + p1 = points.Get(i1); + p2 = points.Get(i2); + center = ::netgen::Center (p1, p2); + rad = Dist (p1, center); + + p2d1 = chart->Project2d (p1); + p2d2 = chart->Project2d (p2); + + boundingbox.Set (p2d1); + boundingbox.Add (p2d2); +} + +void STLBoundarySeg :: Swap () +{ + ::netgen::Swap (i1, i2); + ::netgen::Swap (p1, p2); +} + + + +STLBoundary :: STLBoundary (STLGeometry * ageometry) + : boundary(), geometry(ageometry) +{ + ; +} + + +void STLBoundary :: AddOrDelSegment(const STLBoundarySeg & seg) +{ + int i; + int found = 0; + for (i = 1; i <= boundary.Size(); i++) + { + if (found) {boundary.Elem(i-1) = boundary.Get(i);} + if (boundary.Get(i) == seg) {found = 1;} + } + if (!found) + { + boundary.Append(seg); + } + else + { + boundary.SetSize(boundary.Size()-1); + } +} + +void STLBoundary ::AddTriangle(const STLTriangle & t) +{ + int i; + int found1 = 0; + int found2 = 0; + int found3 = 0; + int offset = 0; + + + STLBoundarySeg seg1(t[0],t[1], geometry->GetPoints(), chart); + STLBoundarySeg seg2(t[1],t[2], geometry->GetPoints(), chart); + STLBoundarySeg seg3(t[2],t[0], geometry->GetPoints(), chart); + + seg1.SetSmoothEdge (geometry->IsSmoothEdge (seg1.I1(), seg1.I2())); + seg2.SetSmoothEdge (geometry->IsSmoothEdge (seg2.I1(), seg2.I2())); + seg3.SetSmoothEdge (geometry->IsSmoothEdge (seg3.I1(), seg3.I2())); + + /* + for (i = 1; i <= boundary.Size(); i++) + { + if (offset) {boundary.Elem(i-offset) = boundary.Get(i);} + if (boundary.Get(i) == seg1) {found1 = 1; offset++;} + if (boundary.Get(i) == seg2) {found2 = 1; offset++;} + if (boundary.Get(i) == seg3) {found3 = 1; offset++;} + } + + if (offset) + { + boundary.SetSize(boundary.Size()-offset); + } + */ + for (i = boundary.Size(); i >= 1; i--) + { + if (boundary.Get(i) == seg1) + { boundary.DeleteElement (i); found1 = 1; } + else if (boundary.Get(i) == seg2) + { boundary.DeleteElement (i); found2 = 1; } + else if (boundary.Get(i) == seg3) + { boundary.DeleteElement (i); found3 = 1; } + } + + if (!found1) {seg1.Swap(); boundary.Append(seg1);} + if (!found2) {seg2.Swap(); boundary.Append(seg2);} + if (!found3) {seg3.Swap(); boundary.Append(seg3);} +} + +int STLBoundary :: TestSeg(const Point<3>& p1, const Point<3> & p2, const Vec<3> & sn, + double sinchartangle, int divisions, ARRAY<Point<3> >& points, double eps) +{ + + if (usechartnormal) + return TestSegChartNV (p1, p2, sn); + + // for statistics + { + int i; + static ARRAY<int> cntclass; + static int cnt = 0; + static int cnti = 0, cnto = 0; + static long int cntsegs = 0; + if (cntclass.Size() == 0) + { + cntclass.SetSize (20); + for (i = 1; i <= cntclass.Size(); i++) + cntclass.Elem(i) = 0; + } + + cntsegs += NOSegments(); + int cla = int (log (double(NOSegments()+1)) / log(2.0)); + if (cla < 1) cla = 1; + if (cla > cntclass.Size()) cla = cntclass.Size(); + cntclass.Elem(cla)++; + cnt++; + if (divisions) + cnti++; + else + cnto++; + if (cnt > 100000) + { + cnt = 0; + /* + (*testout) << "TestSeg-calls for classes:" << endl; + (*testout) << cnti << " inner calls, " << cnto << " outercalls" << endl; + (*testout) << "total testes segments: " << cntsegs << endl; + for (i = 1; i <= cntclass.Size(); i++) + { + (*testout) << int (exp (i * log(2.0))) << " bnd segs: " << cntclass.Get(i) << endl; + } + */ + } + } + + + int i,j,k; + Point<3> seg1p/*, seg2p*/; + Point<3> sp1,sp2; + double lambda1, lambda2, vlen2; + Vec<3> vptpl; + double sinchartangle2 = sqr(sinchartangle); + double scal; + int possible; + + double maxval = -1; + double maxvalnew = -1; + + + + double scalp1 = p1(0) * sn(0) + p1(1) * sn(1) + p1(2) * sn(2); + double scalp2 = p2(0) * sn(0) + p2(1) * sn(1) + p2(2) * sn(2); + double minl = min2(scalp1, scalp2); + double maxl = max2(scalp1, scalp2); + Point<3> c = Center (p1, p2); + double dist1 = Dist (c, p1); + + int nseg = NOSegments(); + for (j = 1; j <= nseg; j++) + { + const STLBoundarySeg & seg = GetSegment(j); + + + if (seg.IsSmoothEdge()) + continue; + + + sp1 = seg.P1(); + sp2 = seg.P2(); + + // Test, ob Spiral Konfikt moeglich + + possible = 1; + + double scalsp1 = sp1(0) * sn(0) + sp1(1) * sn(1) + sp1(2) * sn(2); + double scalsp2 = sp2(0) * sn(0) + sp2(1) * sn(1) + sp2(2) * sn(2); + + double minsl = min2(scalsp1, scalsp2); + double maxsl = max2(scalsp1, scalsp2); + + double maxdiff = max2 (maxsl - minl, maxl - minsl); + + /* + Point3d sc = Center (sp1, sp2); + double mindist = Dist(c, sc) - dist1 - GetSegment(j).Radius(); + if (maxdiff < sinchartangle * mindist) + { + possible = 0; + } + */ + + double hscal = maxdiff + sinchartangle * (dist1 + seg.Radius()); + if (hscal * hscal < sinchartangle * Dist2(c, seg.center )) + possible = 0; + + + /* + if (possible) + { + double mindist2ex = MinDistLL2 (p1, p2, sp1, sp2); + if (maxdiff * maxdiff < sinchartangle2 * mindist2ex) + possible = 0; + } + */ + + if (possible) + { + LinearPolynomial2V lp (scalp1 - scalsp1, + scalp2 - scalp1, + -(scalsp2 - scalsp1)); + QuadraticPolynomial2V slp; + slp.Square (lp); + + + Vec3d v (p1, sp1); + Vec3d vl (p1, p2); + Vec3d vsl (sp1, sp2); + + QuadraticPolynomial2V qp (v.Length2(), + -2 * (v * vl), + 2 * (v * vsl), + vl.Length2(), + -2 * (vl * vsl), + vsl.Length2()); + + slp.Add (-sinchartangle2, qp); + + double hv = slp.MaxUnitSquare(); + + if (hv > eps) return 0; + /* + if (hv > maxvalnew) + maxvalnew = hv; + */ + } + + + if (possible && 0) + + for (i = 0; i <= divisions; i++) + { + + lambda1 = (double)i/(double)divisions; + seg1p = Point3d(p1(0)*lambda1+p2(0)*(1.-lambda1), + p1(1)*lambda1+p2(1)*(1.-lambda1), + p1(2)*lambda1+p2(2)*(1.-lambda1)); + + + + for (k = 0; k <= divisions; k++) + { + lambda2 = (double)k/(double)divisions; + vptpl = Vec3d(sp1(0)*lambda2+sp2(0)*(1.-lambda2)-seg1p(0), + sp1(1)*lambda2+sp2(1)*(1.-lambda2)-seg1p(1), + sp1(2)*lambda2+sp2(2)*(1.-lambda2)-seg1p(2)); + + vlen2 = vptpl.Length2(); + + // if (vlen2 > 0) + { + scal = vptpl * sn; + double hv = scal*scal - sinchartangle2*vlen2; + + + + /* + if (hv > maxval) + maxval = hv; + */ + if (hv > eps) return 0; + } + } + } + } + + return 1; + // return (maxvalnew < eps); +} + + + +// checks, whether 2d projection intersects +int STLBoundary :: TestSegChartNV(const Point3d & p1, const Point3d& p2, + const Vec3d& sn) +{ + int i, j; + int nseg = NOSegments(); + + Point<2> p2d1 = chart->Project2d (p1); + Point<2> p2d2 = chart->Project2d (p2); + + Box<2> box2d; + box2d.Set (p2d1); + box2d.Add (p2d2); + /* + Point2d pmin(p2d1); + pmin.SetToMin (p2d2); + Point2d pmax(p2d1); + pmax.SetToMax (p2d2); + */ + + Line2d l1 (p2d1, p2d2); + + double lam1, lam2; + double eps = 1e-3; + + for (j = 1; j <= nseg; j++) + { + const STLBoundarySeg & seg = GetSegment(j); + + if (!box2d.Intersect (seg.BoundingBox())) + continue; + /* + if (seg.P2DMin()(0) > pmax(0)) continue; + if (seg.P2DMin()(1) > pmax(1)) continue; + if (seg.P2DMax()(0) < pmin(0)) continue; + if (seg.P2DMax()(1) < pmin(1)) continue; + */ + + if (seg.IsSmoothEdge()) continue; + + const Point<2> & sp1 = seg.P2D1(); + const Point<2> & sp2 = seg.P2D2(); + + + Line2d l2 (sp1, sp2); + + int err = + CrossPointBarycentric (l1, l2, lam1, lam2); + /* + if (chartdebug) + { + + (*testout) << "lam1 = " << lam1 << ", lam2 = " << lam2 << endl; + (*testout) << "p2d = " << p2d1 << ", " << p2d2 << endl; + (*testout) << "sp2d = " << sp1 << ", " << sp2 << endl; + (*testout) << "i1,2 = " << seg.I1() << ", " << seg.I2() << endl; + + } + */ + if (!err && lam1 > eps && lam1 < 1-eps && + lam2 > eps && lam2 < 1-eps) + return 0; + } + return 1; +} + + + +STLDoctorParams :: STLDoctorParams() +{ + drawmeshededges = 1; + geom_tol_fact = 1E-6; + longlinefact = 0; + showexcluded = 1; + + selectmode = 0; + edgeselectmode = 0; + useexternaledges = 0; + showfaces = 0; + showtouchedtrigchart = 1; + showedgecornerpoints = 1; + conecheck = 1; + spiralcheck = 1; + selecttrig = 0; + nodeofseltrig = 1; + selectwithmouse = 1; + showmarkedtrigs = 1; + dirtytrigfact = 0.001; + smoothangle = 90; + smoothnormalsweight = 0.2; + vicinity = 0; + showvicinity = 0; +} + + + +STLDoctorParams stldoctor; + +void STLDoctorParams :: Print (ostream & ost) const +{ + ost << "STL doctor parameters:" << endl + << "selecttrig = " << selecttrig << endl + << "selectlocalpoint = " << nodeofseltrig << endl + << "selectwithmouse = " << selectwithmouse << endl + << "showmarkedtrigs = " << showmarkedtrigs << endl + << "dirtytrigfact = " << dirtytrigfact << endl + << "smoothangle = " << smoothangle << endl; +} + + +STLParameters :: STLParameters() +{ + yangle = 30; + contyangle = 20; + edgecornerangle = 60; + chartangle = 15; + outerchartangle = 70; + + usesearchtree = 0; + atlasminh = 1E-4; + resthsurfcurvfac = 2; + resthsurfcurvenable = 0; + resthatlasfac = 2; + resthatlasenable = 1; + resthchartdistfac = 1.2; + resthchartdistenable = 1; + resthlinelengthfac = 0.5; + resthlinelengthenable = 1; + resthcloseedgefac = 1; + resthcloseedgeenable = 1; + resthedgeanglefac = 1; + resthedgeangleenable = 0; + resthsurfmeshcurvfac = 1; + resthsurfmeshcurvenable = 0; + recalc_h_opt = 1; +} + +void STLParameters :: Print (ostream & ost) const +{ + ost << "STL parameters:" << endl + << "yellow angle = " << yangle << endl + << "continued yellow angle = " << contyangle << endl + << "edgecornerangle = " << edgecornerangle << endl + << "chartangle = " << chartangle << endl + << "outerchartangle = " << outerchartangle << endl + << "restrict h due to ..., enable and safety factor: " << endl + << "surface curvature: " << resthsurfcurvenable + << ", fac = " << resthsurfcurvfac << endl + << "atlas surface curvature: " << resthatlasenable + << ", fac = " << resthatlasfac << endl + << "chart distance: " << resthchartdistenable + << ", fac = " << resthchartdistfac << endl + << "line length: " << resthlinelengthenable + << ", fac = " << resthlinelengthfac << endl + << "close edges: " << resthcloseedgeenable + << ", fac = " << resthcloseedgefac << endl + << "edge angle: " << resthedgeangleenable + << ", fac = " << resthedgeanglefac << endl; +} + + +STLParameters stlparam; + + +} diff --git a/contrib/Netgen/libsrc/stlgeom/stltool.hpp b/contrib/Netgen/libsrc/stlgeom/stltool.hpp new file mode 100644 index 0000000000..278a7ce4ee --- /dev/null +++ b/contrib/Netgen/libsrc/stlgeom/stltool.hpp @@ -0,0 +1,271 @@ +#ifndef FILE_STLTOOL +#define FILE_STLTOOL + + +//#include "gprim/gprim.hh" + +/**************************************************************************/ +/* File: stlgeom.hh */ +/* Author: Joachim Schoeberl */ +/* Author2: Johannes Gerstmayr */ +/* Date: 20. Nov. 99 */ +/**************************************************************************/ + + + +// use one normal vector for whole chart +extern int usechartnormal; +extern int chartdebug; + +extern int geomsearchtreeon; +extern int AddPointIfNotExists(ARRAY<Point3d>& ap, const Point3d& p, double eps = 1e-8); +//get distance from line lp1-lp2 to point p +extern double GetDistFromLine(const Point<3>& lp1, const Point<3>& lp2, Point<3>& p); +extern double GetDistFromInfiniteLine(const Point<3>& lp1, const Point<3>& lp2, const Point<3>& p); + + +extern void FIOReadInt(istream& ios, int& i); +extern void FIOWriteInt(ostream& ios, const int& i); +extern void FIOReadDouble(istream& ios, double& i); +extern void FIOWriteDouble(ostream& ios, const double& i); +extern void FIOReadFloat(istream& ios, float& i); +extern void FIOWriteFloat(ostream& ios, const float& i); +extern void FIOReadString(istream& ios, char* str, int len); +extern void FIOReadStringE(istream& ios, char* str, int len); +extern void FIOWriteString(ostream& ios, char* str, int len); + + +typedef ARRAY <int> * ARRAYINTPTR; + +class STLGeometry; + +class STLChart +{ +private: + STLGeometry * geometry; + ARRAY<int>* charttrigs; // trigs which only belong to this chart + ARRAY<int>* outertrigs; // trigs which belong to other charts + Box3dTree * searchtree; // ADT containing outer trigs + + ARRAY<twoint>* olimit; //outer limit of outer chart + ARRAY<twoint>* ilimit; //outer limit of inner chart + + +public: + + STLChart(STLGeometry * ageometry); + void AddChartTrig(int i); + void AddOuterTrig(int i); + + int IsInWholeChart(int nr) const; + + int GetChartTrig(int i) const {return charttrigs->Get(i);} + int GetOuterTrig(int i) const {return outertrigs->Get(i);} + //get all trigs: + int GetTrig(int i) const + { + if (i <= charttrigs->Size()) {return charttrigs->Get(i);} + else {return outertrigs->Get(i-charttrigs->Size());} + } + + int GetNChartT() const {return charttrigs->Size();} + int GetNOuterT() const {return outertrigs->Size();} + int GetNT() const {return charttrigs->Size()+outertrigs->Size(); } + + void GetTrianglesInBox (const Point3d & pmin, + const Point3d & pmax, + ARRAY<int> & trias) const; + void AddOLimit(twoint l) {olimit->Append(l);} + void AddILimit(twoint l) {ilimit->Append(l);} + + void ClearOLimit() {olimit->SetSize(0);} + void ClearILimit() {ilimit->SetSize(0);} + + int GetNOLimit() const {return olimit->Size();} + int GetNILimit() const {return ilimit->Size();} + + twoint GetOLimit(int i) const {return olimit->Get(i);} + twoint GetILimit(int i) const {return ilimit->Get(i);} + + //move triangles trigs (local chart-trig numbers) to outer chart + void MoveToOuterChart(const ARRAY<int>& trigs); + void DelChartTrigs(const ARRAY<int>& trigs); + + + // define local coordinate system, JS: +private: + Vec<3> normal; + Point<3> pref; + Vec<3> t1, t2; +public: + void SetNormal (const Point<3> & apref, const Vec<3> & anormal); + const Vec<3> & GetNormal () const { return normal; } + Point<2> Project2d (const Point<3> & p3d) const; +}; + +class STLBoundarySeg +{ + Point<3> p1, p2, center; + Point<2> p2d1, p2d2; + Box<2> boundingbox; + // Point<2> p2dmin, p2dmax; + + double rad; + int i1, i2; + int smoothedge; +public: + STLBoundarySeg () { ; } + STLBoundarySeg (int ai1, int ai2, const ARRAY<Point<3> > & points, + const STLChart * achart); + + int operator== (const STLBoundarySeg & s2) const + { return i1 == s2.i1 && i2 == s2.i2; } + void Swap (); + int I1() const { return i1; } + int I2() const { return i2; } + const Point<3> & P1() const { return p1; } + const Point<3> & P2() const { return p2; } + const Point<2> & P2D1() const { return p2d1; } + const Point<2> & P2D2() const { return p2d2; } + const Point<2> & P2DMin() const { return boundingbox.PMin(); } + const Point<2> & P2DMax() const { return boundingbox.PMax(); } + const Point<3> & Center() const { return center; } + const Box<2> & BoundingBox() const { return boundingbox; } + double Radius () const { return rad; } + + void SetSmoothEdge (int se) { smoothedge = se; } + int IsSmoothEdge () const { return smoothedge; } + friend class STLBoundary; +}; + +class STLBoundary +{ +private: + STLGeometry * geometry; + const STLChart * chart; + ARRAY<STLBoundarySeg> boundary; +public: + STLBoundary(STLGeometry * ageometry); + // : boundary() {}; + + void Clear() {boundary.SetSize(0);}; + void SetChart (const STLChart * achart) { chart = achart; } + //don't check, if already exists! + void AddNewSegment(const STLBoundarySeg & seg) {boundary.Append(seg);}; + //check if segment exists + void AddOrDelSegment(const STLBoundarySeg & seg); + //addordelsegment for all 3 triangle segments! + void AddTriangle(const STLTriangle & t); + int NOSegments() {return boundary.Size();}; + const STLBoundarySeg & GetSegment(int i) {return boundary.Get(i);} + + int TestSeg(const Point<3> & p1, const Point<3> & p2, const Vec<3> & sn, + double sinchartangle, int divisions, ARRAY<Point<3> >& points, + double eps); + + int TestSegChartNV(const Point3d& p1, const Point3d& p2, const Vec3d& sn); +}; + + +class STLDoctorParams +{ +public: + int drawmeshededges; + double geom_tol_fact; + + double longlinefact; + int showexcluded; + + int selectmode; //0==trig, 1==edge, 2==point, 3==multiedge, 4==line cluster + int edgeselectmode; + + int useexternaledges; + int showfaces; + int showedgecornerpoints; + int showtouchedtrigchart; + int conecheck; + int spiralcheck; + int selecttrig; + int nodeofseltrig; + int selectwithmouse; + int showmarkedtrigs; + double dirtytrigfact; + double smoothangle; + + double smoothnormalsweight; + + int showvicinity; + int vicinity; + /// + STLDoctorParams(); + /// + void Print (ostream & ost) const; +}; + +extern STLDoctorParams stldoctor; + + + +class STLParameters +{ +public: + /// angle for edge detection + double yangle; + double contyangle; //edges continued with contyangle + /// angle of geometry edge at which the mesher should set a point + double edgecornerangle; + /// angle inside on chart + double chartangle; + /// angle for overlapping parts of char + double outerchartangle; + /// 0 .. no, 1 .. local, (2 .. global) + int usesearchtree; + /// + double resthatlasfac; + int resthatlasenable; + double atlasminh; + + double resthsurfcurvfac; + int resthsurfcurvenable; + + double resthchartdistfac; + int resthchartdistenable; + + double resthcloseedgefac; + int resthcloseedgeenable; + + double resthedgeanglefac; + int resthedgeangleenable; + + double resthsurfmeshcurvfac; + int resthsurfmeshcurvenable; + + double resthlinelengthfac; + int resthlinelengthenable; + + /// + int recalc_h_opt; + /// + STLParameters(); + /// + void Print (ostream & ost) const; +}; + +extern STLParameters stlparam; + + +void STLMeshing (STLGeometry & geom, + class Mesh & mesh); + + +int STLSurfaceMeshing (STLGeometry & geom, + class Mesh & mesh); + +void STLSurfaceOptimization (STLGeometry & geom, + class Mesh & mesh, + class MeshingParameters & mparam); + + + + +#endif diff --git a/contrib/Netgen/libsrc/stlgeom/stltopology.cpp b/contrib/Netgen/libsrc/stlgeom/stltopology.cpp new file mode 100644 index 0000000000..1d5315fbec --- /dev/null +++ b/contrib/Netgen/libsrc/stlgeom/stltopology.cpp @@ -0,0 +1,1067 @@ +#include <mystdlib.h> + +#include <myadt.hpp> +#include <linalg.hpp> +#include <gprim.hpp> + +#include <meshing.hpp> + +#include "stlgeom.hpp" + +namespace netgen +{ + + +STLTopology :: STLTopology() + : trias(), topedges(), points(), ht_topedges(NULL), + neighbourtrigs(), trigsperpoint() +{ + ; +} + +STLTopology :: ~STLTopology() +{ + ; +} + + + + +STLGeometry * STLTopology :: LoadBinary (istream & ist) +{ + STLGeometry * geom = new STLGeometry(); + ARRAY<STLReadTriangle> readtrigs; + + PrintMessage(1,"Read STL binary file"); + + if (sizeof(int) != 4 || sizeof(float) != 4) + { + PrintWarning("for stl-binary compatibility only use 32 bit compilation!!!"); + } + + //specific settings for stl-binary format + const int namelen = 80; //length of name of header in file + const int nospaces = 2; //number of spaces after a triangle + + //read header: name + char buf[namelen+1]; + FIOReadStringE(ist,buf,namelen); + PrintMessage(5,"header = ",buf); + + //Read Number of facets + int nofacets; + FIOReadInt(ist,nofacets); + PrintMessage(5,"NO facets = ",nofacets); + + Point<3> pts[3]; + Vec<3> normal; + + int cntface, j; + int vertex = 0; + float f; + char spaces[nospaces+1]; + + for (cntface = 0; cntface < nofacets; cntface++) + { + if (cntface % 10000 == 9999) { PrintDot(); } + + FIOReadFloat(ist,f); normal(0) = f; + FIOReadFloat(ist,f); normal(1) = f; + FIOReadFloat(ist,f); normal(2) = f; + + for (j = 0; j < 3; j++) + { + FIOReadFloat(ist,f); pts[j](0) = f; + FIOReadFloat(ist,f); pts[j](1) = f; + FIOReadFloat(ist,f); pts[j](2) = f; + } + + readtrigs.Append (STLReadTriangle (pts, normal)); + FIOReadString(ist,spaces,nospaces); + } + + + geom->InitSTLGeometry(readtrigs); + + return geom; +} + + +void STLTopology :: SaveBinary (const char* filename, const char* aname) +{ + ofstream ost(filename); + PrintFnStart("Write STL binary file '",filename,"'"); + + if (sizeof(int) != 4 || sizeof(float) != 4) + {PrintWarning("for stl-binary compatibility only use 32 bit compilation!!!");} + + //specific settings for stl-binary format + const int namelen = 80; //length of name of header in file + const int nospaces = 2; //number of spaces after a triangle + + //write header: aname + int i, j; + char buf[namelen+1]; + int strend = 0; + for(i = 0; i <= namelen; i++) + { + if (aname[i] == 0) {strend = 1;} + if (!strend) {buf[i] = aname[i];} + else {buf[i] = 0;} + } + + FIOWriteString(ost,buf,namelen); + PrintMessage(5,"header = ",buf); + + //RWrite Number of facets + int nofacets = GetNT(); + FIOWriteInt(ost,nofacets); + PrintMessage(5,"NO facets = ", nofacets); + + float f; + char spaces[nospaces+1]; + for (i = 0; i < nospaces; i++) {spaces[i] = ' ';} + spaces[nospaces] = 0; + + for (i = 1; i <= GetNT(); i++) + { + const STLTriangle & t = GetTriangle(i); + + const Vec<3> & n = t.Normal(); + f = n(0); FIOWriteFloat(ost,f); + f = n(1); FIOWriteFloat(ost,f); + f = n(2); FIOWriteFloat(ost,f); + + for (j = 1; j <= 3; j++) + { + const Point3d p = GetPoint(t.PNum(j)); + + f = p.X(); FIOWriteFloat(ost,f); + f = p.Y(); FIOWriteFloat(ost,f); + f = p.Z(); FIOWriteFloat(ost,f); + } + FIOWriteString(ost,spaces,nospaces); + } + PrintMessage(5,"done"); +} + + +void STLTopology :: SaveSTLE (const char* filename) +{ + ofstream outf (filename); + int i, j; + + outf << GetNT() << endl; + for (i = 1; i <= GetNT(); i++) + { + const STLTriangle & t = GetTriangle(i); + for (j = 1; j <= 3; j++) + { + const Point3d p = GetPoint(t.PNum(j)); + outf << p.X() << " " << p.Y() << " " << p.Z() << endl; + } + } + + + int ned = 0; + for (i = 1; i <= GetNTE(); i++) + { + if (GetTopEdge (i).GetStatus() == ED_CONFIRMED) + ned++; + } + + outf << ned << endl; + + for (i = 1; i <= GetNTE(); i++) + { + const STLTopEdge & edge = GetTopEdge (i); + if (edge.GetStatus() == ED_CONFIRMED) + for (j = 1; j <= 2; j++) + { + const Point3d p = GetPoint(edge.PNum(j)); + outf << p.X() << " " << p.Y() << " " << p.Z() << endl; + } + } +} + + + +STLGeometry * STLTopology :: LoadNaomi (istream & ist) +{ + int i; + STLGeometry * geom = new STLGeometry(); + ARRAY<STLReadTriangle> readtrigs; + + PrintFnStart("read NAOMI file format"); + + char buf[100]; + Vec<3> normal; + + int cntface = 0; + int cntvertex = 0; + double px, py, pz; + + + int noface, novertex; + ARRAY<Point<3> > readpoints; + + ist >> buf; + if (strcmp (buf, "NODES") == 0) + { + ist >> novertex; + PrintMessage(5,"nuber of vertices = ", novertex); + for (i = 0; i < novertex; i++) + { + ist >> px; + ist >> py; + ist >> pz; + readpoints.Append(Point<3> (px,py,pz)); + } + } + else + { + PrintFileError("no node information"); + } + + + ist >> buf; + if (strcmp (buf, "2D_EDGES") == 0) + { + ist >> noface; + PrintMessage(5,"number of faces=",noface); + int dummy, p1, p2, p3; + Point<3> pts[3]; + + for (i = 0; i < noface; i++) + { + ist >> dummy; //2 + ist >> dummy; //1 + ist >> p1; + ist >> p2; + ist >> p3; + ist >> dummy; //0 + + pts[0] = readpoints.Get(p1); + pts[1] = readpoints.Get(p2); + pts[2] = readpoints.Get(p3); + + normal = Cross (pts[1]-pts[0], pts[2]-pts[0]) . Normalize(); + + readtrigs.Append (STLReadTriangle (pts, normal)); + + } + PrintMessage(5,"read ", readtrigs.Size(), " triangles"); + } + else + { + PrintMessage(5,"read='",buf,"'\n"); + PrintFileError("ERROR: no Triangle information"); + } + + geom->InitSTLGeometry(readtrigs); + + return geom; +} + +void STLTopology :: Save (const char* filename) +{ + PrintFnStart("Write stl-file '",filename, "'"); + + ofstream fout(filename); + fout << "solid\n"; + + char buf1[50]; + char buf2[50]; + char buf3[50]; + + int i, j; + for (i = 1; i <= GetNT(); i++) + { + const STLTriangle & t = GetTriangle(i); + + fout << "facet normal "; + const Vec3d& n = GetTriangle(i).Normal(); + + sprintf(buf1,"%1.9g",n.X()); + sprintf(buf2,"%1.9g",n.Y()); + sprintf(buf3,"%1.9g",n.Z()); + + fout << buf1 << " " << buf2 << " " << buf3 << "\n"; + fout << "outer loop\n"; + + for (j = 1; j <= 3; j++) + { + const Point3d p = GetPoint(t.PNum(j)); + + sprintf(buf1,"%1.9g",p.X()); + sprintf(buf2,"%1.9g",p.Y()); + sprintf(buf3,"%1.9g",p.Z()); + + fout << "vertex " << buf1 << " " << buf2 << " " << buf3 << "\n"; + } + + fout << "endloop\n"; + fout << "endfacet\n"; + } + fout << "endsolid\n"; + + + // write also NETGEN surface mesh: + ofstream fout2("geom.surf"); + fout2 << "surfacemesh" << endl; + fout2 << GetNP() << endl; + for (i = 1; i <= GetNP(); i++) + { + for (j = 0; j < 3; j++) + { + fout2.width(8); + fout2 << GetPoint(i)(j); + } + + fout2 << endl; + } + + fout2 << GetNT() << endl; + for (i = 1; i <= GetNT(); i++) + { + const STLTriangle & t = GetTriangle(i); + for (j = 1; j <= 3; j++) + { + fout2.width(8); + fout2 << t.PNum(j); + } + fout2 << endl; + } +} + + +STLGeometry * STLTopology ::Load (istream & ist) +{ + int i; + STLGeometry * geom = new STLGeometry(); + + ARRAY<STLReadTriangle> readtrigs; + + char buf[100]; + Point<3> pts[3]; + Vec<3> normal; + + int cntface = 0; + int vertex = 0; + bool badnormals = 0; + + while (ist.good()) + { + ist >> buf; + + int n = strlen (buf); + for (i = 0; i < n; i++) + buf[i] = tolower (buf[i]); + + if (strcmp (buf, "facet") == 0) + { + cntface++; + } + + if (strcmp (buf, "normal") == 0) + { + ist >> normal(0) + >> normal(1) + >> normal(2); + normal.Normalize(); + } + + if (strcmp (buf, "vertex") == 0) + { + ist >> pts[vertex](0) + >> pts[vertex](1) + >> pts[vertex](2); + + vertex++; + + if (vertex == 3) + { + if (normal.Length() <= 1e-5) + + { + normal = Cross (pts[1]-pts[0], pts[2]-pts[0]); + normal.Normalize(); + } + + else + + { + Vec<3> hnormal; + hnormal = Cross (pts[1]-pts[0], pts[2]-pts[0]); + hnormal.Normalize(); + + if (normal * hnormal < 0.5) + { + badnormals = 1; + } + } + + vertex = 0; + + if ( (Dist2 (pts[0], pts[1]) > 1e-16) && + (Dist2 (pts[0], pts[2]) > 1e-16) && + (Dist2 (pts[1], pts[2]) > 1e-16) ) + + readtrigs.Append (STLReadTriangle (pts, normal)); + } + } + } + + if (badnormals) + { + PrintWarning("File has normal vectors which differ extremly from geometry->correct with stldoctor!!!"); + } + + geom->InitSTLGeometry(readtrigs); + return geom; +} + + + + + + + + + + + + + +void STLTopology :: InitSTLGeometry(const ARRAY<STLReadTriangle> & readtrigs) +{ + int i, j, k; + + // const double geometry_tol_fact = 1E6; + // distances lower than max_box_size/tol are ignored + + trias.SetSize(0); + points.SetSize(0); + + PrintMessage(3,"number of triangles = ", readtrigs.Size()); + + if (!readtrigs.Size()) + return; + + + boundingbox.Set (readtrigs[0][0]); + for (i = 0; i < readtrigs.Size(); i++) + for (k = 0; k < 3; k++) + boundingbox.Add (readtrigs[i][k]); + + PrintMessage(5,"boundingbox: ", Point3d(boundingbox.PMin()), " - ", + Point3d(boundingbox.PMax())); + + Box<3> bb = boundingbox; + bb.Increase (1); + + pointtree = new Point3dTree (bb.PMin(), bb.PMax()); + + + + ARRAY<int> pintersect; + + pointtol = boundingbox.Diam() * stldoctor.geom_tol_fact; + PrintMessage(5,"point tolerance = ", pointtol); + + for(i = 0; i < readtrigs.Size(); i++) + { + const STLReadTriangle & t = readtrigs[i]; + STLTriangle st; + Vec<3> n = t.Normal(); + st.SetNormal (t.Normal()); + + for (k = 0; k < 3; k++) + { + Point<3> p = t[k]; + + Point<3> pmin = p - Vec<3> (pointtol, pointtol, pointtol); + Point<3> pmax = p + Vec<3> (pointtol, pointtol, pointtol); + + pointtree->GetIntersecting (pmin, pmax, pintersect); + + if (pintersect.Size() > 1) + PrintError("too many close points"); + int foundpos = -1; + if (pintersect.Size()) + foundpos = pintersect[0]; + + if (foundpos == -1) + { + foundpos = AddPoint(p); + pointtree->Insert (p, foundpos); + } + st[k] = foundpos; + } + + if ( (st[0] == st[1]) || + (st[0] == st[2]) || + (st[1] == st[2]) ) + { + PrintError("STL Triangle degenerated"); + } + else + { + AddTriangle(st); + } + + } + + FindNeighbourTrigs(); +} + + + + +int STLTopology :: GetPointNum (const Point<3> & p) +{ + Point<3> pmin = p - Vec<3> (pointtol, pointtol, pointtol); + Point<3> pmax = p + Vec<3> (pointtol, pointtol, pointtol); + + ARRAY<int> pintersect; + + pointtree->GetIntersecting (pmin, pmax, pintersect); + if (pintersect.Size() == 1) + return pintersect[0]; + else + return 0; +} + + + +void STLTopology :: FindNeighbourTrigs() +{ + // if (topedges.Size()) return; + + PushStatusF("Find Neighbour Triangles"); + + int i, j, k, l; + + // build up topology tables + + int np = GetNP(); + int nt = GetNT(); + + INDEX_2_HASHTABLE<int> * oldedges = ht_topedges; + ht_topedges = new INDEX_2_HASHTABLE<int> (GetNP()+1); + topedges.SetSize(0); + + for (i = 1; i <= nt; i++) + { + STLTriangle & trig = GetTriangle(i); + + + for (j = 1; j <= 3; j++) + { + int pi1 = trig.PNumMod (j+1); + int pi2 = trig.PNumMod (j+2); + + INDEX_2 i2(pi1, pi2); + i2.Sort(); + + int enr; + int othertn; + + if (ht_topedges->Used(i2)) + { + enr = ht_topedges->Get(i2); + topedges.Elem(enr).TrigNum(2) = i; + + othertn = topedges.Get(enr).TrigNum(1); + STLTriangle & othertrig = GetTriangle(othertn); + + trig.NBTrigNum(j) = othertn; + trig.EdgeNum(j) = enr; + for (k = 1; k <= 3; k++) + if (othertrig.EdgeNum(k) == enr) + othertrig.NBTrigNum(k) = i; + } + else + { + enr = topedges.Append (STLTopEdge (pi1, pi2, i, 0)); + ht_topedges->Set (i2, enr); + trig.EdgeNum(j) = enr; + } + } + } + + + PrintMessage(5,"topology built, checking"); + + topology_ok = 1; + int ne = GetNTE(); + + for (i = 1; i <= nt; i++) + GetTriangle(i).flags.toperror = 0; + + for (i = 1; i <= nt; i++) + for (j = 1; j <= 3; j++) + { + const STLTopEdge & edge = GetTopEdge (GetTriangle(i).EdgeNum(j)); + if (edge.TrigNum(1) != i && edge.TrigNum(2) != i) + { + topology_ok = 0; + GetTriangle(i).flags.toperror = 1; + } + } + + for (i = 1; i <= ne; i++) + { + const STLTopEdge & edge = GetTopEdge (i); + if (!edge.TrigNum(2)) + { + topology_ok = 0; + GetTriangle(edge.TrigNum(1)).flags.toperror = 1; + } + } + + if (topology_ok) + { + orientation_ok = 1; + for (i = 1; i <= nt; i++) + { + const STLTriangle & t = GetTriangle (i); + for (j = 1; j <= 3; j++) + { + const STLTriangle & nbt = GetTriangle (t.NBTrigNum(j)); + if (!t.IsNeighbourFrom (nbt)) + orientation_ok = 0; + } + } + } + else + orientation_ok = 0; + + + + status = STL_GOOD; + statustext = ""; + if (!topology_ok || !orientation_ok) + { + status = STL_ERROR; + if (!topology_ok) + statustext = "Topology not ok"; + else + statustext = "Orientation not ok"; + } + + + PrintMessage(3,"topology_ok = ",topology_ok); + PrintMessage(3,"orientation_ok = ",orientation_ok); + PrintMessage(3,"topology found"); + + // generate point -> trig table + + trigsperpoint.SetSize(GetNP()); + for (i = 1; i <= GetNT(); i++) + for (j = 1; j <= 3; j++) + trigsperpoint.Add1(GetTriangle(i).PNum(j),i); + + + //check trigs per point: + /* + for (i = 1; i <= GetNP(); i++) + { + if (trigsperpoint.EntrySize(i) < 3) + { + (*testout) << "ERROR: Point " << i << " has " << trigsperpoint.EntrySize(i) << " triangles!!!" << endl; + } + } + */ + topedgesperpoint.SetSize (GetNP()); + for (i = 1; i <= ne; i++) + for (j = 1; j <= 2; j++) + topedgesperpoint.Add1 (GetTopEdge (i).PNum(j), i); + + PrintMessage(5,"point -> trig table generated"); + + + + // transfer edge data: + // .. to be done + delete oldedges; + + + + for (STLTrigIndex ti = 0; ti < GetNT(); ti++) + { + STLTriangle & trig = trias[ti]; + for (k = 0; k < 3; k++) + { + STLPointIndex pi = trig[k] - STLBASE; + STLPointIndex pi2 = trig[(k+1)%3] - STLBASE; + STLPointIndex pi3 = trig[(k+2)%3] - STLBASE; + + // vector along edge + Vec<3> ve = points[pi2] - points[pi]; + ve.Normalize(); + + // vector along third point + Vec<3> vt = points[pi3] - points[pi]; + vt -= (vt * ve) * ve; + vt.Normalize(); + + Vec<3> vn = trig.GeomNormal (points); + vn.Normalize(); + + double phimin = 10, phimax = -1; // out of (0, 2 pi) + + for (j = 0; j < trigsperpoint[pi].Size(); j++) + { + STLTrigIndex ti2 = trigsperpoint[pi][j] - STLBASE; + const STLTriangle & trig2 = trias[ti2]; + + if (ti == ti2) continue; + + bool hasboth = 0; + for (l = 0; l < 3; l++) + if (trig2[l] - STLBASE == pi2) + { + hasboth = 1; + break; + } + if (!hasboth) continue; + + STLPointIndex pi4; + for (l = 0; l < 3; l++) + if (trig2[l] - STLBASE != pi && trig2[l] - STLBASE != pi2) + pi4 = trig2[l] - STLBASE; + + Vec<3> vt2 = points[pi4] - points[pi]; + + double phi = atan2 (vt2 * vn, vt2 * vt); + if (phi < 0) phi += 2 * M_PI; + + if (phi < phimin) + { + phimin = phi; + trig.NBTrig (0, (k+2)%3) = ti2 + STLBASE; + } + if (phi > phimax) + { + phimax = phi; + trig.NBTrig (1, (k+2)%3) = ti2 + STLBASE; + } + } + } + } + + + + + if (status == STL_GOOD) + { + // for compatibility: + neighbourtrigs.SetSize(GetNT()); + for (i = 1; i <= GetNT(); i++) + for (k = 1; k <= 3; k++) + AddNeighbourTrig (i, GetTriangle(i).NBTrigNum(k)); + } + else + { + // assemble neighbourtrigs (should be done only for illegal topology): + + neighbourtrigs.SetSize(GetNT()); + + int tr, found; + int wrongneighbourfound = 0; + for (i = 1; i <= GetNT(); i++) + { + SetThreadPercent((double)i/(double)GetNT()*100.); + if (multithread.terminate) + { + PopStatus(); + return; + } + + for (k = 1; k <= 3; k++) + { + for (j = 1; j <= trigsperpoint.EntrySize(GetTriangle(i).PNum(k)); j++) + { + tr = trigsperpoint.Get(GetTriangle(i).PNum(k),j); + if (i != tr && (GetTriangle(i).IsNeighbourFrom(GetTriangle(tr)) + || GetTriangle(i).IsWrongNeighbourFrom(GetTriangle(tr)))) + { + if (GetTriangle(i).IsWrongNeighbourFrom(GetTriangle(tr))) + { + /*(*testout) << "ERROR: triangle " << i << " has a wrong neighbour triangle!!!" << endl;*/ + wrongneighbourfound ++; + } + + found = 0; + for (int ii = 1; ii <= NONeighbourTrigs(i); ii++) + {if (NeighbourTrig(i,ii) == tr) {found = 1;break;};} + if (! found) {AddNeighbourTrig(i,tr);} + } + } + } + if (NONeighbourTrigs(i) != 3) + { + PrintError("TRIG ",i," has ",NONeighbourTrigs(i)," neighbours!!!!"); + for (int kk=1; kk <= NONeighbourTrigs(i); kk++) + { + PrintMessage(5,"neighbour-trig",kk," = ",NeighbourTrig(i,kk)); + } + }; + } + if (wrongneighbourfound) + { + PrintError("++++++++++++++++++++\n"); + PrintError(wrongneighbourfound, " wrong oriented neighbourtriangles found!"); + PrintError("try to correct it (with stldoctor)!"); + PrintError("++++++++++++++++++++\n"); + + status = STL_ERROR; + statustext = "STL Mesh not consistent"; + + multithread.terminate = 1; +#ifdef STAT_STREAM + (*statout) << "non-conform stl geometry \\hline" << endl; +#endif + } + } + + TopologyChanged(); + + PopStatus(); +} + + + + + + + +void STLTopology :: GetTrianglesInBox (/* + const Point<3> & pmin, + const Point<3> & pmax, + */ + const Box<3> & box, + ARRAY<int> & trias) const +{ + if (searchtree) + + searchtree -> GetIntersecting (box.PMin(), box.PMax(), trias); + + else + { + int i; + Box<3> box1 = box; + box1.Increase (1e-4); + + trias.SetSize(0); + + int nt = GetNT(); + for (i = 1; i <= nt; i++) + { + if (box1.Intersect (GetTriangle(i).box)) + { + trias.Append (i); + } + } + } +} + + + +void STLTopology :: AddTriangle(const STLTriangle& t) +{ + trias.Append(t); + + const Point<3> & p1 = GetPoint (t.PNum(1)); + const Point<3> & p2 = GetPoint (t.PNum(2)); + const Point<3> & p3 = GetPoint (t.PNum(3)); + + Box<3> box; + box.Set (p1); + box.Add (p2); + box.Add (p3); + /* + // Point<3> pmin(p1), pmax(p1); + pmin.SetToMin (p2); + pmin.SetToMin (p3); + pmax.SetToMax (p2); + pmax.SetToMax (p3); + */ + + trias.Last().box = box; + trias.Last().center = Center (p1, p2, p3); + double r1 = Dist (p1, trias.Last().center); + double r2 = Dist (p2, trias.Last().center); + double r3 = Dist (p3, trias.Last().center); + trias.Last().rad = max2 (max2 (r1, r2), r3); + + if (geomsearchtreeon) + {searchtree->Insert (box.PMin(), box.PMax(), trias.Size());} +} + + + + +int STLTopology :: GetLeftTrig(int p1, int p2) const +{ + int i; + for (i = 1; i <= trigsperpoint.EntrySize(p1); i++) + { + if (GetTriangle(trigsperpoint.Get(p1,i)).HasEdge(p1,p2)) {return trigsperpoint.Get(p1,i);} + } + PrintSysError("ERROR in GetLeftTrig !!!"); + + return 0; +} + +int STLTopology :: GetRightTrig(int p1, int p2) const +{ + return GetLeftTrig(p2,p1); +} + + +int STLTopology :: NeighbourTrigSorted(int trig, int edgenum) const +{ + int i, p1, p2; + int psearch = GetTriangle(trig).PNum(edgenum); + + for (i = 1; i <= 3; i++) + { + GetTriangle(trig).GetNeighbourPoints(GetTriangle(NeighbourTrig(trig,i)),p1,p2); + if (p1 == psearch) {return NeighbourTrig(trig,i);} + } + + PrintSysError("ERROR in NeighbourTrigSorted"); + return 0; +} + + + + + + +int STLTopology :: GetTopEdgeNum (int pi1, int pi2) const +{ + if (!ht_topedges) return 0; + + INDEX_2 i2(pi1, pi2); + i2.Sort(); + + if (!ht_topedges->Used(i2)) return 0; + return ht_topedges->Get(i2); +} + + + + +void STLTopology :: InvertTrig (int trig) +{ + if (trig >= 1 && trig <= GetNT()) + { + GetTriangle(trig).ChangeOrientation(); + FindNeighbourTrigs(); + } + else + { + PrintUserError("no triangle selected!"); + } +} + + + + +void STLTopology :: DeleteTrig (int trig) +{ + if (trig >= 1 && trig <= GetNT()) + { + trias.DeleteElement(trig); + FindNeighbourTrigs(); + } + else + { + PrintUserError("no triangle selected!"); + } +} + + + +void STLTopology :: OrientAfterTrig (int trig) +{ + int starttrig = trig; + + if (starttrig >= 1 && starttrig <= GetNT()) + { + + ARRAY <int> oriented; + oriented.SetSize(GetNT()); + int i; + for (i = 1; i <= oriented.Size(); i++) + { + oriented.Elem(i) = 0; + } + + oriented.Elem(starttrig) = 1; + + int j = 0,k; + + ARRAY <int> list1; + list1.SetSize(0); + ARRAY <int> list2; + list2.SetSize(0); + list1.Append(starttrig); + + int cnt = 1; + int end = 0; + int nt; + while (!end) + { + end = 1; + for (i = 1; i <= list1.Size(); i++) + { + const STLTriangle& tt = GetTriangle(list1.Get(i)); + for (k = 1; k <= 3; k++) + { + nt = tt.NBTrigNum (k); // NeighbourTrig(list1.Get(i),k); + if (oriented.Get(nt) == 0) + { + if (tt.IsWrongNeighbourFrom(GetTriangle(nt))) + { + GetTriangle(nt).ChangeOrientation(); + } + oriented.Elem(nt) = 1; + list2.Append(nt); + cnt++; + end = 0; + } + } + } + list1.SetSize(0); + for (i = 1; i <= list2.Size(); i++) + { + list1.Append(list2.Get(i)); + } + list2.SetSize(0); + } + + PrintMessage(5,"NO corrected triangles = ",cnt); + if (cnt == GetNT()) + { + PrintMessage(5,"ALL triangles oriented in same way!"); + } + else + { + PrintWarning("NOT ALL triangles oriented in same way!"); + } + + // topedges.SetSize(0); + FindNeighbourTrigs(); + } + else + { + PrintUserError("no triangle selected!"); + } +} + + +} diff --git a/contrib/Netgen/libsrc/stlgeom/stltopology.hpp b/contrib/Netgen/libsrc/stlgeom/stltopology.hpp new file mode 100644 index 0000000000..80e5a68178 --- /dev/null +++ b/contrib/Netgen/libsrc/stlgeom/stltopology.hpp @@ -0,0 +1,362 @@ +#ifndef FILE_STLTOPOLOGY +#define FILE_STLTOPOLOGY + +/**************************************************************************/ +/* File: stltopology.hpp */ +/* Author: Joachim Schoeberl */ +/* Author2: Johannes Gerstmayr */ +/* Date: 26. Jul. 99 */ +/**************************************************************************/ + +/* + The STLTopology contains topologic information as + triangle->point, point->triangles, triangle->edge, 2-points->edge,... +*/ + + +class STLGeometry; + +#define STLBASE 1 + +class STLPointIndex +{ + int i; +public: + STLPointIndex () { ; } + STLPointIndex (int ai) : i(ai) { ; } + STLPointIndex & operator= (const STLPointIndex & ai) { i = ai.i; return *this; } + STLPointIndex & operator= (int ai) { i = ai; return *this; } + operator int () const { return i; } + STLPointIndex operator++ (int) { return i++; } + STLPointIndex operator-- (int) { return i--; } +}; + + + +class STLTrigIndex +{ + int i; +public: + STLTrigIndex () { ; } + STLTrigIndex (int ai) : i(ai) { ; } + STLTrigIndex & operator= (const STLTrigIndex & ai) { i = ai.i; return *this; } + STLTrigIndex & operator= (int ai) { i = ai; return *this; } + operator int () const { return i; } + STLTrigIndex operator++ (int) { return i++; } + STLTrigIndex operator-- (int) { return i--; } +}; + + + + + +// triangle structure for loading stl files +class STLReadTriangle +{ + Vec<3> normal; + Point<3> pts[3]; +public: + STLReadTriangle (const Point<3> * apts, const Vec<3> & anormal); + STLReadTriangle () {}; + const Point<3> & operator[] (int i) const { return pts[i]; } + const Vec<3> & Normal() const { return normal; } +}; + + + +class STLTriangle +{ + // topology edges of triangle, edge[i] opposite to point[i] + int topedges[3]; + // neighbour triangles, trig[i] opposite to point[i] + int nbtrigs[2][3]; + // normalized stored normal vector ?? + Vec<3> normal; + // point numbers of triangle + int pts[3]; + // front-side and back-side domains + int domains[2]; + + +public: + + Box<3> box; + Point<3> center; + double rad; + int facenum; + + struct + { + unsigned int toperror : 1; + } flags; + + + + + STLTriangle (const int * apts); + STLTriangle () {pts[0]=0;pts[1]=0;pts[2]=0;} + + int operator[] (int i) const { return pts[i]; } + int & operator[] (int i) { return pts[i]; } + + int EdgeNum(int i) const { return topedges[(i-1)]; } + int & EdgeNum(int i) { return topedges[(i-1)]; } + + int NBTrig (bool side, int i) const { return nbtrigs[side][i]; } + int & NBTrig (bool side, int i) { return nbtrigs[side][i]; } + + + int Domain (bool side) const { return domains[side]; } + int & Domain (bool side) { return domains[side]; } + + + + // obsolete: + int PNum(int i) const { return pts[(i-1)]; } + int & PNum(int i) { return pts[(i-1)]; } + int PNumMod(int i) const { return pts[(i-1)%3]; } + int & PNumMod(int i) { return pts[(i-1)%3]; } + + int EdgeNumMod(int i) const { return topedges[(i-1)%3]; } + int & EdgeNumMod(int i) { return topedges[(i-1)%3]; } + + int NBTrigNum(int i) const { return nbtrigs[0][(i-1)]; } + int & NBTrigNum(int i) { return nbtrigs[0][(i-1)]; } + int NBTrigNumMod(int i) const { return nbtrigs[0][(i-1)%3]; } + int & NBTrigNumMod(int i) { return nbtrigs[0][(i-1)%3]; } + + + // consistently oriented neighbour: + int IsNeighbourFrom(const STLTriangle& t) const; + // opposite to consistently oriented neighbour: + int IsWrongNeighbourFrom(const STLTriangle& t) const; + + ///Get the two points of neighbour-Triangles in orientation of this-Triangle + void GetNeighbourPoints(const STLTriangle& t, int& p1, int& p2) const; + int GetNeighbourPointsAndOpposite(const STLTriangle& t, int& p1, int& p2, int& po) const; + + + + // NON-normalized geometry - normal vector + Vec<3> GeomNormal(const ARRAY<Point<3> >& ap) const; + + // Stored normal vector, normalized + void SetNormal (const Vec<3> & n); + const Vec<3> & Normal () const { return normal; } + + + void ChangeOrientation(); + + //project with a certain normal vector in plane + void ProjectInPlain(const ARRAY<Point<3> >& ap, + const Vec<3> & n, Point<3> & pp) const; + //project with the triangle's normal vector in plane + void ProjectInPlain(const ARRAY<Point<3> > & ap, Point<3> & pp) const; + + + /* + Project the point pp along the nproj into the plane of + the triangle. The triangle normal is given by ntrig to + avoid numerical instabilities. + The local coordinates lam are defined by + + pp(input) = P1 + lam1 v1 + lam2 v2 + lam3 n + + the result is + + pp(output) = P1 + lam1 v1 + lam2 v2 + */ + int ProjectInPlain (const ARRAY<Point<3> >& ap, + const Vec<3> & nproj, + Point<3> & pp, Vec<3> & lam) const; + + int PointInside(const ARRAY<Point<3> >& ap, const Point<3> & pp) const; + + //get nearest point on triangle and distance to it + double GetNearestPoint(const ARRAY<Point<3> >& ap, + Point<3> & p3d) const; + + double Area(const ARRAY<Point<3> >& ap) const; + + double MinHeight(const ARRAY<Point<3> >& ap) const; + double MaxLength(const ARRAY<Point<3> >& ap) const; + //max length of a side of triangle + + int GetFaceNum() {return facenum;} + void SetFaceNum(int i) {facenum = i;} + + int HasEdge(int p1, int p2) const; +}; + + +/** + Topology Edge: + Useful unside a face. + A edges sharing more than 2 faces: trigs are undefined + */ +class STLTopEdge +{ + int pts[2]; + int trigs[2]; + double cosangle; + int status; // excluded, confirmed, candidate, undefined +public: + STLTopEdge (); + STLTopEdge (int p1, int p2, int trig1, int trig2); + + int operator[] (int i) const { return pts[i]; } + int & operator[] (int i) { return pts[i]; } + + + int PNum(int i) const { return pts[(i-1)]; } + int & PNum(int i) { return pts[(i-1)]; } + int PNumMod(int i) const { return pts[(i-1)%2]; } + int & PNumMod(int i) { return pts[(i-1)%2]; } + + int TrigNum(int i) const { return trigs[(i-1)]; } + int & TrigNum(int i) { return trigs[(i-1)]; } + int TrigNumMod(int i) const { return trigs[(i-1)%2]; } + int & TrigNumMod(int i) { return trigs[(i-1)%2]; } + + void SetCosAngle (double ca) { cosangle = ca; } + double CosAngle () const { return cosangle; } + double Angle () const { return acos (cosangle); } + + void SetStatus (int stat) { status = stat; } + int GetStatus () const { return status; } +}; + + + +ostream& operator<<(ostream& os, const STLTriangle& t); + + + + + + + +class STLTopology +{ +protected: + ARRAY<STLTriangle> trias; + ARRAY<STLTopEdge> topedges; + ARRAY<Point<3> > points; + + // mapping of sorted pair of points to topedge + INDEX_2_HASHTABLE<int> * ht_topedges; + // mapping of node to trigs + TABLE<int> trigsperpoint; + // mapping of node to edges + TABLE<int> topedgesperpoint; + + // searchtree for trigs and points + + Box3dTree * searchtree; // ADT + Point3dTree * pointtree; + + Box<3> boundingbox; + double pointtol; + +public: + enum STL_GEOM_STATUS { STL_GOOD, STL_WARNING, STL_ERROR }; + +protected: + STL_GEOM_STATUS status; + string statustext; + + bool topology_ok; + bool orientation_ok; + +public: + STLTopology(); + virtual ~STLTopology(); + + static STLGeometry * LoadNaomi (istream & ist); + static STLGeometry * Load (istream & ist); + static STLGeometry * LoadBinary (istream & ist); + + void Save (const char* filename); + void SaveBinary (const char* filename, const char* aname); + void SaveSTLE (const char * filename); // stores trigs and edges + + virtual void InitSTLGeometry (const ARRAY<STLReadTriangle> & readtrigs); + + virtual void TopologyChanged() {}; //do some things, if topology changed! + + /// Generate topology tables + void FindNeighbourTrigs(); + + + void GetTrianglesInBox (const Box<3> & box, + ARRAY<int> & trias) const; + + + int GetNP() const { return points.Size(); } + int AddPoint(const Point<3> & p) { return points.Append(p); } + const Point<3> & GetPoint(int nr) const { return points.Get(nr); } + int GetPointNum (const Point<3> & p); + void SetPoint(int nr, const Point<3> & p) { points.Elem(nr) = p; } + const ARRAY<Point<3> >& GetPoints() const { return points; } + + const Point<3> & operator[] (STLPointIndex i) const { return points[i]; } + Point<3> & operator[] (STLPointIndex i) { return points[i]; } + + + + + int GetNT() const { return trias.Size(); } + void AddTriangle(const STLTriangle& t); + const STLTriangle & GetTriangle (int nr) const { return trias.Get(nr); } + STLTriangle & GetTriangle (int nr) { return trias.Elem(nr); } + + const STLTriangle & operator[] (STLTrigIndex i) const { return trias[i]; } + STLTriangle & operator[] (STLTrigIndex i) { return trias[i]; } + + + int GetNTE() const { return topedges.Size(); } + const STLTopEdge & GetTopEdge (int nr) const { return topedges.Get(nr); } + STLTopEdge & GetTopEdge (int nr) { return topedges.Elem(nr); } + int GetTopEdgeNum (int pi1, int pi2) const; + + + int NOTrigsPerPoint(int pn) { return trigsperpoint.EntrySize(pn); } + int TrigPerPoint(int pn, int i) { return trigsperpoint.Get(pn, i); } + + + int NTopEdgesPerPoint (int pn) const { return topedgesperpoint.EntrySize(pn); } + int TopEdgePerPoint (int pn, int ei) const { return topedgesperpoint.Get(pn, ei); } + + + bool Topology_Ok() const { return topology_ok; } + bool Orientation_Ok() const { return orientation_ok; } + + STL_GEOM_STATUS GetStatus () const { return status; } + const string & GetStatusText () const { return statustext; } + + void InvertTrig (int trig); + void DeleteTrig (int trig); + void OrientAfterTrig (int trig); + + + // Table will be constructed, if topology is not ok + /// neighbourtrigs for surfacetrigs + TABLE<int> neighbourtrigs; + + /// get nr-th neighbour Triangle for triangle trig + int NONeighbourTrigs(int trig) const { return neighbourtrigs.EntrySize(trig); } + int NeighbourTrig(int trig, int nr) const { return neighbourtrigs.Get(trig,nr); } + int NeighbourTrigSorted(int trig, int nr) const; + void AddNeighbourTrig(int i, int nt) { neighbourtrigs.Add1(i, nt); } + + + + + int GetLeftTrig (int p1, int p2) const; + int GetRightTrig (int p1, int p2) const; + + const Box<3> & GetBoundingBox () const { return boundingbox; } +}; + + +#endif diff --git a/contrib/Netgen/libsrc/visualization/Makefile b/contrib/Netgen/libsrc/visualization/Makefile new file mode 100644 index 0000000000..a6302092d9 --- /dev/null +++ b/contrib/Netgen/libsrc/visualization/Makefile @@ -0,0 +1,13 @@ +# +# Makefile for visualization library +# +src = stlmeshing.cpp mvdraw.cpp vscsg.cpp vsmesh.cpp vsocc.cpp vssolution.cpp meshdoc.cpp +# +lib = vis +libpath = libsrc/visualization +# +# +include ../makefile.inc +# + + diff --git a/contrib/Netgen/libsrc/visualization/meshdoc.cpp b/contrib/Netgen/libsrc/visualization/meshdoc.cpp new file mode 100644 index 0000000000..4c0f064c05 --- /dev/null +++ b/contrib/Netgen/libsrc/visualization/meshdoc.cpp @@ -0,0 +1,615 @@ +#include <mystdlib.h> + +#include <meshing.hpp> + +#include "incvis.hpp" + + + +namespace netgen +{ +#include "mvdraw.hpp" +#include "meshdoc.hpp" + + +MeshDoctorParameters meshdoctor; +VisualSceneMeshDoctor vsmeshdoc; + +extern AutoPtr<Mesh> mesh; + + int Ng_MeshDoctor (ClientData clientData, + Tcl_Interp * interp, + int argc, tcl_const char *argv[]) +{ + cout << "Mesh Doctor:" << endl; + int i; + for (i = 0; i < argc; i++) + cout << argv[i] << " "; + cout << endl; + + meshdoctor.active = + atoi (Tcl_GetVar (interp, "meshdoctor.active", 0)); + + + if (argc >= 2) + { + if (strcmp (argv[1], "markedgedist") == 0) + { + vsmeshdoc.SetMarkEdgeDist (atoi (argv[2])); + } + + if (strcmp (argv[1], "deletemarkedsegments") == 0) + { + for (i = 1; i <= mesh->GetNSeg(); i++) + if (vsmeshdoc.IsSegmentMarked (i)) + mesh->DeleteSegment (i); + + // for (i = 1; i <= mesh->GetNSE(); i++) + // mesh->SurfaceElement(i).SetIndex (1); + mesh->Compress(); + } + } + + + vsmeshdoc.UpdateTables (); + vsmeshdoc.BuildScene(); + return TCL_OK; +} + + + + + +VisualSceneMeshDoctor :: VisualSceneMeshDoctor () + : VisualScene() +{ + filledlist = 0; + outlinelist = 0; + edgelist = 0; + selelement = 0; + locpi = 1; + selpoint = 0; + selpoint2 = 0; + markedgedist = 1; + + UpdateTables (); +} + +VisualSceneMeshDoctor :: ~VisualSceneMeshDoctor () +{ + ; +} + +void VisualSceneMeshDoctor :: DrawScene () +{ + int i, j, k; + + if (!mesh) return; + + int hchval = mesh->GetNP() + mesh->GetNE() + mesh->GetNSE(); + if (changeval != hchval) + { + changeval = hchval; + BuildScene(); + } + + + glClearColor(backcolor, backcolor, backcolor, 1.0); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + glEnable (GL_COLOR_MATERIAL); + glColor3f (1.0f, 1.0f, 1.0f); + glLineWidth (1.0f); + + SetLight(); + + glPushMatrix(); + glMultMatrixf (transformationmat); + + glInitNames (); + glPushName (0); + + glPolygonOffset (1, 1); + glEnable (GL_POLYGON_OFFSET_FILL); + + SetClippingPlane (); + + if (vispar.drawfilledtrigs) + glCallList (filledlist); + + glDisable (GL_POLYGON_OFFSET_FILL); + + if (vispar.drawoutline) + glCallList (outlinelist); + + glPolygonOffset (-1, -1); + glEnable (GL_POLYGON_OFFSET_LINE); + + if (vispar.drawedges) + glCallList (edgelist); + + + glDisable (GL_POLYGON_OFFSET_LINE); + + + + glPopName(); + + if (selpoint > 0 && selpoint <= mesh->GetNP()) + { + GLfloat matcolblue[] = { 0, 0, 1, 1 }; + + glPointSize (10); + glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, matcolblue); + glBegin (GL_POINTS); + + const Point3d p = mesh->Point(selpoint); + glVertex3f (p.X(), p.Y(), p.Z()); + glEnd(); + } + + glDisable(GL_CLIP_PLANE0); + + + glPopMatrix(); + glFinish(); +} + + + + +void VisualSceneMeshDoctor :: BuildScene (int zoomall) +{ + int i, j, k; + + + if (zoomall) + { + Point3d pmin, pmax; + mesh->GetBox (pmin, pmax, -1); + + if (vispar.centerpoint) + center = mesh->Point (vispar.centerpoint); + else + center = Center (pmin, pmax); + + rad = 0.5 * Dist (pmin, pmax); + + glEnable (GL_NORMALIZE); + + CalcTransformationMatrices(); + } + + + + + if (filledlist) + { + glDeleteLists (filledlist, 1); + glDeleteLists (outlinelist, 1); + glDeleteLists (edgelist, 1); + } + + + filledlist = glGenLists (1); + glNewList (filledlist, GL_COMPILE); + + glPolygonMode (GL_FRONT_AND_BACK, GL_FILL); + + static float matcol0[] = { 0.0f, 0.0f, 0.0f, 1.0f }; + static float matcol1[] = { 1.0f, 1.0f, 1.0f, 1.0f }; + static float matcolsel[] = { 1.0f, 0.0f, 0.0f, 1.0f }; + static float matcolnosel[] = { 0.0f, 1.0f, 0.0f, 1.0f }; + + glLineWidth (1.0f); + + glDisable (GL_COLOR_MATERIAL); + + for (i = 1; i <= mesh->GetNSE(); i++) + { + glLoadName (i); + + // copy to be thread-safe + Element2d el = mesh->SurfaceElement (i); + + int drawel = 1; + for (j = 1; j <= el.GetNP(); j++) + { + if (!el.PNum(j)) + drawel = 0; + } + + if (!drawel) + continue; + + GLfloat matcol[] = { 0, 1, 0, 1 }; + GLfloat matcolsel[] = { 1, 0, 0, 1 }; + + if (i == selelement) + glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, matcolsel); + else + glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, matcol); + + if (el.GetNP() == 3) + { + glBegin (GL_TRIANGLES); + + const Point3d & lp1 = mesh->Point (el.PNum(1)); + const Point3d & lp2 = mesh->Point (el.PNum(2)); + const Point3d & lp3 = mesh->Point (el.PNum(3)); + Vec3d n = Cross (Vec3d (lp1, lp2), Vec3d (lp1, lp3)); + n /= (n.Length()+1e-12); + glNormal3d (n.X(), n.Y(), n.Z()); + + if (!vispar.colormeshsize) + { + glVertex3d (lp1.X(), lp1.Y(), lp1.Z()); + glVertex3d (lp2.X(), lp2.Y(), lp2.Z()); + glVertex3d (lp3.X(), lp3.Y(), lp3.Z()); + } + else + { + double h1 = mesh->GetH (lp1); + double h2 = mesh->GetH (lp2); + double h3 = mesh->GetH (lp3); + + SetOpenGlColor (h1, 0.1, 10); + glVertex3d (lp1.X(), lp1.Y(), lp1.Z()); + + SetOpenGlColor (h2, 0.1, 10); + glVertex3d (lp2.X(), lp2.Y(), lp2.Z()); + + SetOpenGlColor (h3, 0.1, 10); + glVertex3d (lp3.X(), lp3.Y(), lp3.Z()); + } + glEnd(); + } + else if (el.GetNP() == 4) + { + glBegin (GL_QUADS); + + const Point3d & lp1 = mesh->Point (el.PNum(1)); + const Point3d & lp2 = mesh->Point (el.PNum(2)); + const Point3d & lp3 = mesh->Point (el.PNum(4)); + const Point3d & lp4 = mesh->Point (el.PNum(3)); + Vec3d n = Cross (Vec3d (lp1, lp2), + Vec3d (lp1, Center (lp3, lp4))); + n /= (n.Length()+1e-12); + glNormal3d (n.X(), n.Y(), n.Z()); + glVertex3d (lp1.X(), lp1.Y(), lp1.Z()); + glVertex3d (lp2.X(), lp2.Y(), lp2.Z()); + glVertex3d (lp4.X(), lp4.Y(), lp4.Z()); + glVertex3d (lp3.X(), lp3.Y(), lp3.Z()); + glEnd(); + } + else if (el.GetNP() == 6) + { + glBegin (GL_TRIANGLES); + static int trigs[4][3] = { + { 1, 6, 5 }, + { 2, 4, 6 }, + { 3, 5, 4 }, + { 4, 5, 6 } }; + + for (j = 0; j < 4; j++) + { + const Point3d & lp1 = mesh->Point (el.PNum(trigs[j][0])); + const Point3d & lp2 = mesh->Point (el.PNum(trigs[j][1])); + const Point3d & lp3 = mesh->Point (el.PNum(trigs[j][2])); + Vec3d n = Cross (Vec3d (lp1, lp2), Vec3d (lp1, lp3)); + n /= (n.Length() + 1e-12); + glNormal3d (n.X(), n.Y(), n.Z()); + glVertex3d (lp1.X(), lp1.Y(), lp1.Z()); + glVertex3d (lp2.X(), lp2.Y(), lp2.Z()); + glVertex3d (lp3.X(), lp3.Y(), lp3.Z()); + } + glEnd(); + } + } + glLoadName (0); + + glEndList (); + + + + outlinelist = glGenLists (1); + glNewList (outlinelist, GL_COMPILE); + + glLineWidth (1.0f); + glPolygonMode (GL_FRONT_AND_BACK, GL_LINE); + + glColor3f (0.0f, 0.0f, 0.0f); + glEnable (GL_COLOR_MATERIAL); + + for (i = 1; i <= mesh->GetNSE(); i++) + { + Element2d el = mesh->SurfaceElement(i); + + int drawel = 1; + for (j = 1; j <= el.GetNP(); j++) + { + if (!el.PNum(j)) + drawel = 0; + } + + if (!drawel) + continue; + + + if (el.GetNP() == 3) + { + glBegin (GL_TRIANGLES); + + const Point3d & lp1 = mesh->Point (el.PNum(1)); + const Point3d & lp2 = mesh->Point (el.PNum(2)); + const Point3d & lp3 = mesh->Point (el.PNum(3)); + Vec3d n = Cross (Vec3d (lp1, lp2), Vec3d (lp1, lp3)); + n /= (n.Length() + 1e-12); + glNormal3d (n.X(), n.Y(), n.Z()); + glVertex3d (lp1.X(), lp1.Y(), lp1.Z()); + glVertex3d (lp2.X(), lp2.Y(), lp2.Z()); + glVertex3d (lp3.X(), lp3.Y(), lp3.Z()); + glEnd(); + } + else if (el.GetNP() == 4) + { + glBegin (GL_QUADS); + + const Point3d & lp1 = mesh->Point (el.PNum(1)); + const Point3d & lp2 = mesh->Point (el.PNum(2)); + const Point3d & lp3 = mesh->Point (el.PNum(4)); + const Point3d & lp4 = mesh->Point (el.PNum(3)); + Vec3d n = Cross (Vec3d (lp1, lp2), + Vec3d (lp1, Center (lp3, lp4))); + n /= (n.Length() + 1e-12); + glNormal3d (n.X(), n.Y(), n.Z()); + glVertex3d (lp1.X(), lp1.Y(), lp1.Z()); + glVertex3d (lp2.X(), lp2.Y(), lp2.Z()); + glVertex3d (lp4.X(), lp4.Y(), lp4.Z()); + glVertex3d (lp3.X(), lp3.Y(), lp3.Z()); + glEnd(); + } + else if (el.GetNP() == 6) + { + glBegin (GL_LINES); + + const Point3d & lp1 = mesh->Point (el.PNum(1)); + const Point3d & lp2 = mesh->Point (el.PNum(2)); + const Point3d & lp3 = mesh->Point (el.PNum(3)); + const Point3d & lp4 = mesh->Point (el.PNum(4)); + const Point3d & lp5 = mesh->Point (el.PNum(5)); + const Point3d & lp6 = mesh->Point (el.PNum(6)); + + Vec3d n = Cross (Vec3d (lp1, lp2), Vec3d (lp1, lp3)); + n /= (n.Length()+1e-12); + glNormal3d (n.X(), n.Y(), n.Z()); + + glVertex3d (lp1.X(), lp1.Y(), lp1.Z()); + glVertex3d (lp6.X(), lp6.Y(), lp6.Z()); + glVertex3d (lp2.X(), lp2.Y(), lp2.Z()); + glVertex3d (lp6.X(), lp6.Y(), lp6.Z()); + + glVertex3d (lp1.X(), lp1.Y(), lp1.Z()); + glVertex3d (lp5.X(), lp5.Y(), lp5.Z()); + glVertex3d (lp3.X(), lp3.Y(), lp3.Z()); + glVertex3d (lp5.X(), lp5.Y(), lp5.Z()); + + glVertex3d (lp2.X(), lp2.Y(), lp2.Z()); + glVertex3d (lp4.X(), lp4.Y(), lp4.Z()); + glVertex3d (lp3.X(), lp3.Y(), lp3.Z()); + glVertex3d (lp4.X(), lp4.Y(), lp4.Z()); + glEnd(); + } + } + glLoadName (0); + glEndList (); + + + + + + edgelist = glGenLists (1); + glNewList (edgelist, GL_COMPILE); + + glDisable (GL_COLOR_MATERIAL); + + GLfloat matcoledge[] = { 0, 0, 1, 1 }; + GLfloat matcolseledge[] = { 1, 0, 1, 1 }; + + glLineWidth (2.0f); + + for (i = 1; i <= mesh->GetNSeg(); i++) + { + const Segment & seg = mesh->LineSegment(i); + const Point3d & p1 = mesh->Point(seg.p1); + const Point3d & p2 = mesh->Point(seg.p2); + + if (edgedist.Get(seg.p1) <= markedgedist && + edgedist.Get(seg.p2) <= markedgedist) + { + glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, + matcolseledge); + glLineWidth (4.0f); + } + else + { + glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, + matcoledge); + glLineWidth (2.0f); + } + glBegin (GL_LINES); + glVertex3f (p1.X(), p1.Y(), p1.Z()); + glVertex3f (p2.X(), p2.Y(), p2.Z()); + glEnd(); + } + + glLineWidth (1.0f); + glEndList (); +} + + + + +void VisualSceneMeshDoctor :: MouseDblClick (int px, int py) +{ + cout << "dblclick: " << px << " - " << py << endl; + + int i, j, k, hits; + + // select surface triangle by mouse click + GLuint selbuf[10000]; + glSelectBuffer (10000, selbuf); + + + glRenderMode (GL_SELECT); + + GLint viewport[4]; + glGetIntegerv (GL_VIEWPORT, viewport); + + glMatrixMode (GL_PROJECTION); + glPushMatrix(); + + GLdouble projmat[16]; + glGetDoublev (GL_PROJECTION_MATRIX, projmat); + + glLoadIdentity(); + gluPickMatrix (px, viewport[3] - py, 1, 1, viewport); + glMultMatrixd (projmat); + + + glClearColor(backcolor, backcolor, backcolor, 1.0); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + glMatrixMode (GL_MODELVIEW); + + glPushMatrix(); + glMultMatrixf (transformationmat); + + glInitNames(); + glPushName (1); + + glPolygonOffset (1, 1); + glEnable (GL_POLYGON_OFFSET_FILL); + + glCallList (filledlist); + + glDisable (GL_POLYGON_OFFSET_FILL); + + glPopName(); + + glMatrixMode (GL_PROJECTION); + glPopMatrix(); + + glMatrixMode (GL_MODELVIEW); + glPopMatrix(); + + glFlush(); + + + hits = glRenderMode (GL_RENDER); + + cout << "hits = " << hits << endl; + + int minname = 0; + GLuint mindepth = 0; + for (i = 0; i < hits; i++) + { + int curname = selbuf[4*i+3]; + GLuint curdepth = selbuf[4*i+1]; + + if (curname && + (curdepth < mindepth || !minname)) + { + mindepth = curdepth; + minname = curname; + } + } + + cout << "clicked element: " << minname << endl; + + ClickElement (minname); + + BuildScene (); +} + + + + +void VisualSceneMeshDoctor :: SetMarkEdgeDist (int dist) +{ + markedgedist = dist; + BuildScene(); +} + +void VisualSceneMeshDoctor :: ClickElement (int elnr) +{ + selelement = elnr; + + int oldlocpi = locpi; + locpi = locpi % 3 + 1; + + if (selelement > 0 && selelement <= mesh->GetNSE()) + { + selpoint = mesh->SurfaceElement(selelement).PNum(locpi); + selpoint2 = mesh->SurfaceElement(selelement).PNum(oldlocpi); + cout << "selpts = " << selpoint << ", " << selpoint2 << endl; + } + + UpdateTables(); +} + + +void VisualSceneMeshDoctor :: UpdateTables () +{ + if (!mesh) return; + + edgedist.SetSize(mesh->GetNP()); + int i, changed; + + for (i = 1; i <= mesh->GetNP(); i++) + edgedist.Elem(i) = 10000; + + for (i = 1; i <= mesh->GetNSeg(); i++) + { + const Segment & seg = mesh->LineSegment(i); + if (seg.p1 == selpoint && seg.p2 == selpoint2 || + seg.p2 == selpoint && seg.p1 == selpoint2) + { + edgedist.Elem(selpoint) = 1; + edgedist.Elem(selpoint2) = 1; + } + } + + do + { + changed = 0; + + for (i = 1; i <= mesh->GetNSeg(); i++) + { + const Segment & seg = mesh->LineSegment(i); + + int edist = min2 (edgedist.Get(seg.p1), edgedist.Get(seg.p2)); + edist++; + + if (edgedist.Get(seg.p1) > edist) + { + edgedist.Elem(seg.p1) = edist; + changed = 1; + } + if (edgedist.Get(seg.p2) > edist) + { + edgedist.Elem(seg.p2) = edist; + changed = 1; + } + } + } + while (changed); +} + +int VisualSceneMeshDoctor :: IsSegmentMarked (int segnr) const +{ + const Segment & seg = mesh->LineSegment(segnr); + return (edgedist.Get(seg.p1) <= markedgedist && + edgedist.Get(seg.p2) <= markedgedist); +} +} diff --git a/contrib/Netgen/libsrc/visualization/meshdoc.hpp b/contrib/Netgen/libsrc/visualization/meshdoc.hpp new file mode 100644 index 0000000000..5cc11aef78 --- /dev/null +++ b/contrib/Netgen/libsrc/visualization/meshdoc.hpp @@ -0,0 +1,37 @@ + +class VisualSceneMeshDoctor : public VisualScene +{ + int filledlist; + int outlinelist; + int edgelist; + + int selelement, locpi; + int selpoint, selpoint2; + + // for edgemarking: + ARRAY<int> edgedist; + int markedgedist; + + +public: + VisualSceneMeshDoctor (); + virtual ~VisualSceneMeshDoctor (); + + virtual void BuildScene (int zoomall = 0); + virtual void DrawScene (); + virtual void MouseDblClick (int px, int py); + + void SetMarkEdgeDist (int dist); + void ClickElement (int elnr); + void UpdateTables (); + int IsSegmentMarked (int segnr) const; +}; + +class MeshDoctorParameters +{ +public: + int active; +}; + + +extern MeshDoctorParameters meshdoctor; diff --git a/contrib/Netgen/libsrc/visualization/mvdraw.cpp b/contrib/Netgen/libsrc/visualization/mvdraw.cpp new file mode 100644 index 0000000000..265dc970b4 --- /dev/null +++ b/contrib/Netgen/libsrc/visualization/mvdraw.cpp @@ -0,0 +1,1335 @@ +#include <mystdlib.h> +#include <myadt.hpp> +#include <meshing.hpp> +#include <csg.hpp> +#include <geometry2d.hpp> +#include <stlgeom.hpp> + +#include "incvis.hpp" + + + +namespace netgen +{ + +#include "mvdraw.hpp" + + Point3d VisualScene :: center; + double VisualScene :: rad; + GLdouble VisualScene :: backcolor; + GLuint VisualScene :: fontbase = 0; + + // texture for color decoding + GLubyte * VisualScene :: colortexture = NULL; + GLuint VisualScene :: coltexname = 1; + int VisualScene :: ntexcols = -1; + + + float VisualScene :: lookatmat[16]; + float VisualScene :: transmat[16]; + float VisualScene :: rotmat[16]; + float VisualScene :: centermat[16]; + float VisualScene :: transformationmat[16]; + + + + VisualizationParameters :: VisualizationParameters() + { + lightamb = 0.3; + lightdiff = 0.7; + lightspec = 1; + shininess = 50; + transp = 0.3; + locviewer = 0; + showstltrias = 0; + centerpoint = 0; + usedispllists = 1; + strcpy (selectvisual, "cross"); + + use_center_coords = false; + }; + VisualizationParameters vispar; + + + + double dist = 0; + // double dist = 6; + // vorher: pnear = 2; + double pnear = 0.1; + double pfar = 10; + + + + extern STLGeometry * stlgeometry; + extern AutoPtr<SplineGeometry2d> geometry2d; + extern AutoPtr<Mesh> mesh; + extern ARRAY<SpecialPoint> specpoints; + + + VisualScene :: VisualScene () + { + changeval = -1; + backcolor = 0; + } + + + VisualScene :: ~VisualScene() + { + ; + } + + + void Render () + { + multithread.redraw = 1; + } + + + void VisualScene :: BuildScene (int zoomall) + { + center = Point3d (0,0,0); + rad = 1; + + CalcTransformationMatrices(); + + glEnable(GL_DEPTH_TEST); + glDisable (GL_DITHER); + + GLfloat ambvals[] = { 0.4f, 0.4f, 0.4f, 1.0f }; + GLfloat diffvals[] = { 0.5f, 0.5f, 0.5f, 1.0f }; + GLfloat specvals[] = { 0.7f, 0.7f, 0.7f, 1.0f }; + glLightfv(GL_LIGHT0, GL_AMBIENT, ambvals); + glLightfv(GL_LIGHT0, GL_DIFFUSE, diffvals); + glLightfv(GL_LIGHT0, GL_SPECULAR, specvals); + + GLfloat light_position[] = { 1, 3, 3, 0 }; + glLightfv(GL_LIGHT0, GL_POSITION, light_position); + + glLightModeli (GL_LIGHT_MODEL_TWO_SIDE, 0); + glEnable(GL_LIGHTING); + glEnable(GL_LIGHT0); + } + + + void VisualScene :: DrawScene () + { + if (changeval == -1) + BuildScene(); + changeval = 0; + + glClearColor(backcolor, backcolor, backcolor, 1.0); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + glEnable (GL_COLOR_MATERIAL); + glColor3f (1.0f, 1.0f, 1.0f); + glLineWidth (1.0f); + + DrawCoordinateCross (); + DrawNetgenLogo (); + glFinish(); + } + + + void VisualScene :: CalcTransformationMatrices() + { + + // prepare model view matrix + + glPushMatrix(); + + glLoadIdentity(); + gluLookAt (0, 0, 6, 0, 0, 0, 0, 1, 0); + glGetFloatv (GL_MODELVIEW_MATRIX, lookatmat); + + glLoadIdentity(); + glTranslatef(0.0f, 0.0f, -dist); + glGetFloatv (GL_MODELVIEW_MATRIX, transmat); + + glLoadIdentity(); + glGetFloatv (GL_MODELVIEW_MATRIX, rotmat); + + glScalef (1/rad, 1/rad, 1/rad); + glTranslated (-center.X(), -center.Y(), -center.Z()); + glGetFloatv (GL_MODELVIEW_MATRIX, centermat); + + glLoadIdentity(); + glMultMatrixf (lookatmat); + glMultMatrixf (transmat); + glMultMatrixf (rotmat); + glMultMatrixf (centermat); + glGetFloatv (GL_MODELVIEW_MATRIX, transformationmat); + + glPopMatrix(); + } + + + void VisualScene :: ArbitraryRotation (const ARRAY<double> & alpha, const ARRAY<Vec3d> & vec) + { + glPushMatrix(); + + glLoadIdentity(); + + for(int i=0; i<alpha.Size() && i<vec.Size(); i++) + { + glRotatef(alpha[i], vec[i].X(), vec[i].Y(), vec[i].Z()); + } + + glGetFloatv (GL_MODELVIEW_MATRIX, rotmat); + + glLoadIdentity(); + glMultMatrixf (lookatmat); + glMultMatrixf (transmat); + glMultMatrixf (rotmat); + glMultMatrixf (centermat); + glGetFloatv (GL_MODELVIEW_MATRIX, transformationmat); + + glPopMatrix(); + } + + + + void VisualScene :: ArbitraryRotation (const double alpha, const Vec3d & vec) + { + ARRAY<double> a(1); a[0] = alpha; + ARRAY<Vec3d> v(1); v[0] = vec; + + ArbitraryRotation(a,v); + } + + void VisualScene :: StandardRotation (const char * dir) + { + glPushMatrix(); + + glLoadIdentity(); + + if (strcmp (dir, "xy") == 0) + ; + else if (strcmp (dir, "yx") == 0) + glRotatef(180.0, 1.0f, 1.0f, 0.0f); + else if (strcmp (dir, "xz") == 0) + glRotatef(-90.0, 1.0f, 0.0f, 0.0f); + else if (strcmp (dir, "zx") == 0) + { + glRotatef(180.0, 1.0f, 1.0f, 0.0f); + glRotatef(-90.0, 1.0f, 0.0f, 0.0f); + } + else if (strcmp (dir, "yz") == 0) + { + glRotatef(-90.0, 0.0f, 0.0f, 1.0f); + glRotatef(-90.0, 0.0f, 1.0f, 0.0f); + } + else if (strcmp (dir, "zy") == 0) + glRotatef(90.0, 0.0f, 1.0f, 0.0f); + + + glGetFloatv (GL_MODELVIEW_MATRIX, rotmat); + + glLoadIdentity(); + glMultMatrixf (lookatmat); + glMultMatrixf (transmat); + glMultMatrixf (rotmat); + glMultMatrixf (centermat); + glGetFloatv (GL_MODELVIEW_MATRIX, transformationmat); + + glPopMatrix(); + } + + void VisualScene :: MouseMove(int oldx, int oldy, + int newx, int newy, + char mode) + { + int deltax = newx - oldx; + int deltay = newy - oldy; + + glPushMatrix(); + glLoadIdentity (); + + switch (mode) + { + case 'r': + { + glRotatef(float(deltax)/2, 0.0f, 1.0f, 0.0f); + glRotatef(float(deltay)/2, 1.0f, 0.0f, 0.0f); + glMultMatrixf (rotmat); + glGetFloatv (GL_MODELVIEW_MATRIX, rotmat); + break; + } + case 'm': + { + GLdouble projmat[16], modelviewmat[16]; + GLint viewport[4]; + glGetDoublev (GL_PROJECTION_MATRIX, projmat); + glGetDoublev (GL_MODELVIEW_MATRIX, modelviewmat); + glGetIntegerv (GL_VIEWPORT, viewport); + + // vorher pvz1/2 = 0 + GLdouble pvx1 = 0, pvy1 = 0, pvz1 = 0.95; + GLdouble pvx2 = deltax, pvy2 = -deltay, pvz2 = 0.95; + + GLdouble px1, py1, pz1; + GLdouble px2, py2, pz2; + + gluUnProject (pvx1, pvy1, pvz1, + modelviewmat, projmat, viewport, + &px1, &py1, &pz1); + gluUnProject (pvx2, pvy2, pvz2, + modelviewmat, projmat, viewport, + &px2, &py2, &pz2); + /* + gluUnProject (oldx, oldy, 1, + modelviewmat, projmat, viewport, + &px1, &py1, &pz1); + gluUnProject (newx, newy, 1, + modelviewmat, projmat, viewport, + &px2, &py2, &pz2); + */ + + /* + cout << "pv1 = " << pvx1 << ", " << pvy1 << ", " << pvz1 << endl; + cout << "p1 = " << px1 << ", " << py1 << ", " << pz1 << endl; + */ + + glTranslated (px2-px1, py2-py1, pz2-pz1); + + glMultMatrixf (transmat); + glGetFloatv (GL_MODELVIEW_MATRIX, transmat); + break; + } + case 'z': + { + // glTranslatef(0.0f, 0.0f, -dist); + glScaled (exp (float (-deltay)/100), + exp (float (-deltay)/100), + exp (float (-deltay)/100)); + // glTranslatef(0.0f, 0.0f, dist); + glMultMatrixf (transmat); + glGetFloatv (GL_MODELVIEW_MATRIX, transmat); + break; + } + } + + glLoadIdentity(); + glMultMatrixf (lookatmat); + glMultMatrixf (transmat); + glMultMatrixf (rotmat); + glMultMatrixf (centermat); + glGetFloatv (GL_MODELVIEW_MATRIX, transformationmat); + + glPopMatrix(); + } + + + void VisualScene :: LookAt (const Point<3> & cam, const Point<3> & obj, + const Point<3> & camup) + { + glPushMatrix(); + glLoadIdentity (); + gluLookAt (cam(0), cam(1), cam(2), + obj(0), obj(1), obj(2), + camup(0), camup(1), camup(2)); + glMultMatrixf (centermat); + glGetFloatv (GL_MODELVIEW_MATRIX, transformationmat); + glPopMatrix(); + } + + + void VisualScene :: SetClippingPlane () + { + if (vispar.clipenable) + { + Vec3d n = vispar.clipnormal; + n /= (n.Length()+1e-10); + clipplane[0] = n.X(); + clipplane[1] = n.Y(); + clipplane[2] = n.Z(); + clipplane[3] = -(Vec3d(center) * n) + rad * vispar.clipdist; + + glClipPlane(GL_CLIP_PLANE0, clipplane); + glEnable(GL_CLIP_PLANE0); + } + else + glDisable (GL_CLIP_PLANE0); + } + + + + + void VisualScene :: MouseDblClick (int /* px */, int /* py */) + { + ; + } + + + + void VisualScene :: SetLight() + { + GLfloat vals[3]; + double lightamb = vispar.lightamb; + vals[0] = vals[1] = vals[2] = lightamb; + glLightfv(GL_LIGHT0, GL_AMBIENT, vals); + + double lightdiff = vispar.lightdiff; + vals[0] = vals[1] = vals[2] = lightdiff; + glLightfv(GL_LIGHT0, GL_DIFFUSE, vals); + + double lightspec = vispar.lightspec; + vals[0] = vals[1] = vals[2] = lightspec; + glLightfv(GL_LIGHT0, GL_SPECULAR, vals); + + glMaterialf (GL_FRONT_AND_BACK, GL_SHININESS, vispar.shininess); + glLightModeli (GL_LIGHT_MODEL_LOCAL_VIEWER, vispar.locviewer); + + float mat_spec_col[] = { 1, 1, 1, 1 }; + glMaterialfv (GL_FRONT_AND_BACK, GL_SPECULAR, mat_spec_col); + + glEnable (GL_LIGHTING); + glEnable (GL_LIGHT0); + } + + + + + void VisualScene :: SetOpenGlColor(double h, double hmin, double hmax, + int logscale) + { + double value; + + if (!logscale) + value = (h - hmin) / (hmax - hmin); + else + { + if (hmax <= 0) hmax = 1; + if (hmin <= 0) hmin = 1e-4 * hmax; + value = (log(fabs(h)) - log(hmin)) / (log(hmax) - log(hmin)); + } + + if (!invcolor) + value = 1 - value; + + glTexCoord1f ( 0.999 * value + 0.001); + // glTexCoord1f ( value ); + + if (value > 1) value = 1; + if (value < 0) value = 0; + + value *= 4; + + static const double colp[][3] = + { + { 1, 0, 0 }, + { 1, 1, 0 }, + { 0, 1, 0 }, + { 0, 1, 1 }, + { 0, 0, 1 }, + // { 1, 0, 1 }, + // { 1, 0, 0 }, + }; + + int i = int(value); + double r = value - i; + + GLdouble col[3]; + for (int j = 0; j < 3; j++) + col[j] = (1-r) * colp[i][j] + r * colp[i+1][j]; + + glColor3d (col[0], col[1], col[2]); + } + + + /* + void VisualScene :: CreateTexture (int ncols, int linear, int typ) + { + + static const double colp[][3] = + { + { 1, 0, 0 }, + { 1, 1, 0 }, + { 0, 1, 0 }, + { 0, 1, 1 }, + { 0, 0, 1 }, + }; + + + + if (ntexcols != 1024) + { + ntexcols = 1024; + + // glPixelStorei (GL_UNPACK_ALIGNMENT, 1); + glGenTextures (1, &coltexname); + glBindTexture (GL_TEXTURE_1D, coltexname); + glTexParameteri (GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_CLAMP); + glTexParameteri (GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri (GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST); + + for (int level = 0; level <= 11; level++) + { + ncols = 2048 >> level; + cout << "ncols = " << ncols << endl; + + colortexture = new GLubyte[4*ncols+12]; + + 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]; + for (int j = 0; j < 3; j++) + col[j] = (1-r) * colp[iv][j] + r * colp[iv+1][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); + + if (ncols > 20) + if ( i % (ncols / 10) == 0) + { + colortexture[4*i] = GLubyte (0); + colortexture[4*i+1] = GLubyte (0); + colortexture[4*i+2] = GLubyte (0); + colortexture[4*i+4] = GLubyte (0); + colortexture[4*i+5] = GLubyte (0); + colortexture[4*i+6] = GLubyte (0); + } + } + + glTexImage1D (GL_TEXTURE_1D, level, 4, ncols, 0, GL_RGBA, GL_UNSIGNED_BYTE, colortexture); + } + } + + glTexEnvf (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, typ); // DECAL or MODULATE + glBindTexture (GL_TEXTURE_1D, coltexname); + } + */ + + + void VisualScene :: CreateTexture (int ncols, int linear, int typ) + { + if (ncols < 2) ncols = 2; + + if (linear) ncols = 32; + else ncols = 8; + + if (ntexcols != ncols) + { + if (colortexture) + { + glDeleteTextures (1, &coltexname); + delete colortexture; + } + + ntexcols = ncols; + + colortexture = new GLubyte[4*ncols+12]; + + 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]; + for (int j = 0; j < 3; j++) + col[j] = (1-r) * colp[iv][j] + r * colp[iv+1][j]; + + colortexture[4*i] = GLubyte (255 * col[0]); + colortexture[4*i+1] = GLubyte (255 * col[1]); + colortexture[4*i+2] = GLubyte (255 * col[2]); + colortexture[4*i+3] = GLubyte(255); + } + + // glPixelStorei (GL_UNPACK_ALIGNMENT, 1); + + glGenTextures (1, &coltexname); + glBindTexture (GL_TEXTURE_1D, coltexname); + + glTexParameteri (GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_CLAMP); + glTexParameteri (GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri (GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + + glTexImage1D (GL_TEXTURE_1D, 0, 4, ncols, 0, GL_RGBA, GL_UNSIGNED_BYTE, colortexture); + } + + glTexEnvf (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, typ); // DECAL or MODULATE + + glBindTexture (GL_TEXTURE_1D, coltexname); + if (linear) + { + glTexParameteri (GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri (GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + } + else + { + glTexParameteri (GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri (GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + } + } + + + + + + /* + void VisualScene :: CreateTexture (int ncols, int linear, int typ) + { + if (ncols < 2) ncols = 2; + + if (linear) ncols = 32; + else ncols = 8; + + if (ntexcols != ncols) + { + if (colortexture) + { + glDeleteTextures (1, &coltexname); + delete colortexture; + } + + ntexcols = ncols; + + colortexture = new GLubyte[4*ncols+12]; + + 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]; + for (int j = 0; j < 3; j++) + col[j] = (1-r) * colp[iv][j] + r * colp[iv+1][j]; + + colortexture[4*i+4] = GLubyte (255 * col[0]); + colortexture[4*i+5] = GLubyte (255 * col[1]); + colortexture[4*i+6] = GLubyte (255 * col[2]); + colortexture[4*i+7] = GLubyte(255); + } + for (int j = 0; j < 4; j++) + { + colortexture[j] = colortexture[4+j]; + colortexture[ncols*4+4+j] = colortexture[ncols*4+j]; + } + + // glPixelStorei (GL_UNPACK_ALIGNMENT, 1); + + glGenTextures (1, &coltexname); + glBindTexture (GL_TEXTURE_1D, coltexname); + + glTexParameteri (GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_CLAMP); + glTexParameteri (GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri (GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + + glTexImage1D (GL_TEXTURE_1D, 0, 4, ncols, 0, GL_RGBA, GL_UNSIGNED_BYTE, colortexture+4); + int bcol[] = { 0, 0, -1, -1 }; + glTexParameteriv (GL_TEXTURE_1D, GL_TEXTURE_BORDER_COLOR, bcol); + } + + glTexEnvf (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, typ); // DECAL or MODULATE + + glBindTexture (GL_TEXTURE_1D, coltexname); + if (linear) + { + glTexParameteri (GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri (GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + } + else + { + glTexParameteri (GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri (GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + } + } + */ + + + + + + void VisualScene :: DrawColorBar (double minval, double maxval, int logscale, bool linear) + { + if (!vispar.drawcolorbar) return; + + CreateTexture (8, linear, GL_DECAL); + + if (logscale && maxval <= 0) maxval = 1; + if (logscale && minval <= 0) minval = 1e-4 * maxval; + + double minx = -1; + double maxx = 1; + double miny = 0.75; + double maxy = 0.8; + + glEnable (GL_COLOR_MATERIAL); + glEnable (GL_TEXTURE_1D); + glNormal3d (0, 0, 1); + glPolygonMode (GL_FRONT_AND_BACK, GL_FILL); + + glDisable (GL_DEPTH_TEST); + glBegin (GL_QUAD_STRIP); + + for (double x = minx; x <= maxx; x += (maxx - minx) / 50) + { + SetOpenGlColor (x, minx, maxx); + // glTexCoord1f ( 0.999 * (x-minx) / (maxx-minx) + 0.001); + + glVertex3d (x, miny, -5); + glVertex3d (x, maxy, -5); + } + glEnd(); + + glDisable (GL_TEXTURE_1D); + + + glEnable (GL_COLOR_MATERIAL); + GLfloat textcol[3] = { 1 - backcolor, 1 - backcolor, 1 - backcolor }; + glColor3fv (textcol); + + glPushAttrib (GL_LIST_BIT); + glListBase (fontbase); + + char buf[20]; + for (int i = 0; i <= 4; i++) + { + double x = minx + i * (maxx-minx) / 4; + glRasterPos3d (x, 0.7,-5); + + double val; + if (logscale) + val = minval * pow (maxval / minval, i / 4.0); + else + val = minval + i * (maxval-minval) / 4; + + sprintf (buf, "%8.3e", val); + glCallLists (strlen (buf), GL_UNSIGNED_BYTE, buf); + } + + glPopAttrib (); + glEnable (GL_DEPTH_TEST); + } + + + void VisualScene :: DrawCoordinateCross () + { + if (!vispar.drawcoordinatecross) return; + + glDisable (GL_DEPTH_TEST); + glMatrixMode (GL_PROJECTION); + glPushMatrix(); + glLoadIdentity(); + + glMatrixMode (GL_MODELVIEW); + glPushMatrix(); + glLoadIdentity(); + + GLint viewport[4]; + glGetIntegerv (GL_VIEWPORT, viewport); + + glTranslatef (-1, -1, 0.0); + glScalef (40.0 / viewport[2], 40.0 / viewport[3], 1); + glTranslatef (2.0, 2.0, 0.0); + glMultMatrixf (rotmat); + + glEnable (GL_COLOR_MATERIAL); + glDisable (GL_LIGHTING); + + GLfloat textcol[3] = { 1 - backcolor, + 1 - backcolor, + 1 - backcolor }; + glColor3fv (textcol); + + glLineWidth (1.0f); + + float len = 1; + glBegin(GL_LINES); + glVertex3f (0.0f, 0.0f, 0.0f); + glVertex3f (len, 0.0f, 0.0f); + glVertex3f (0.0f, 0.0f, 0.0f); + glVertex3f (0.0f, len, 0.0f); + glVertex3f (0.0f, 0.0f, 0.0f); + glVertex3f (0.0f, 0.0f, len); + glEnd (); + + + glPushAttrib (GL_LIST_BIT); + glListBase (fontbase); + + char buf[20]; + + glRasterPos3d (len, 0.0f, 0.0f); + sprintf (buf, "x"); + glCallLists (strlen (buf), GL_UNSIGNED_BYTE, buf); + glRasterPos3d (0.0f, len, 0.0f); + sprintf (buf, "y"); + glCallLists (strlen (buf), GL_UNSIGNED_BYTE, buf); + glRasterPos3d (0.0f, 0.0f, len); + sprintf (buf, "z"); + glCallLists (strlen (buf), GL_UNSIGNED_BYTE, buf); + + glPopAttrib (); + glEnable (GL_LIGHTING); + + glMatrixMode (GL_PROJECTION); + glPopMatrix(); + glMatrixMode (GL_MODELVIEW); + glPopMatrix(); + glEnable (GL_DEPTH_TEST); + } + + + void VisualScene :: DrawNetgenLogo () + { + if (!vispar.drawnetgenlogo) return; + + glDisable (GL_DEPTH_TEST); + glMatrixMode (GL_PROJECTION); + glPushMatrix(); + glLoadIdentity(); + + glMatrixMode (GL_MODELVIEW); + glPushMatrix(); + glLoadIdentity(); + + GLint viewport[4]; + glGetIntegerv (GL_VIEWPORT, viewport); + + + + glTranslatef (1, -1, 0.0); + glScalef (40.0 / viewport[2], 40.0 / viewport[3], 1); + glTranslatef (-6.0, 2.0, 0.0); + + glDisable (GL_CLIP_PLANE0); + // glDisable (GL_LIGHTING); + + glEnable (GL_COLOR_MATERIAL); + GLfloat textcol[3] = { 1 - backcolor, + 1 - backcolor, + 1 - backcolor }; + glColor3fv (textcol); + + glLineWidth (1.0f); + + glPushAttrib (GL_LIST_BIT); + glListBase (fontbase); + + char buf[20]; + + glRasterPos3d (0.0f, 0.0f, 0.0f); + sprintf (buf, "Netgen 4.4"); + glCallLists (strlen (buf), GL_UNSIGNED_BYTE, buf); + + glPopAttrib (); + + glMatrixMode (GL_PROJECTION); + glPopMatrix(); + glMatrixMode (GL_MODELVIEW); + glPopMatrix(); + glEnable (GL_DEPTH_TEST); + } + + + + + + /* *********************** Draw 2D Geometry **************** */ + + + VisualSceneGeometry2d :: VisualSceneGeometry2d () + : VisualScene() + { + ; + } + + VisualSceneGeometry2d :: ~VisualSceneGeometry2d () + { + ; + } + + + + void VisualSceneGeometry2d :: DrawScene () + { + if (changeval != geometry2d->GetSplines().Size()) + BuildScene(); + changeval = geometry2d->GetSplines().Size(); + + + glClearColor(backcolor, backcolor, backcolor, 1.0); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + SetLight(); + + // glEnable (GL_LIGHT0); + glDisable (GL_LIGHTING); + glPushMatrix(); + glMultMatrixf (transformationmat); + + // SetClippingPlane (); + + glShadeModel (GL_SMOOTH); + glEnable (GL_COLOR_MATERIAL); + glPolygonMode (GL_FRONT_AND_BACK, GL_LINE); + + // float mat_col[] = { 0, 0, 1, 1 }; + // glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, mat_col); + glColor3f (0, 0, 1); + + + ARRAY<Point<2> > points, otherpoints; + + for (int i = 1; i <= geometry2d->GetSplines().Size(); i++) + { + geometry2d->GetSplines().Get(i)->GetPoints (20, points); + + glBegin (GL_LINE_STRIP); + for (int j = 0; j < points.Size(); j++) + glVertex3f (points[j](0), points[j](1), 0); + glEnd(); + } + + glColor3f (1, 0, 0); + + for (int i = 1; i <= geometry2d->GetSplines().Size(); i++) + { + int other = geometry2d->GetSplines().Get(i)->copyfrom; + if (other != -1) + { + geometry2d->GetSplines().Get(i)->GetPoints (6, points); + geometry2d->GetSplines().Get(other)->GetPoints (6, otherpoints); + glBegin (GL_LINES); + for (int j = 1; j < 5; j++) + { + glVertex3f (points[j](0), points[j](1), 0); + glVertex3f (otherpoints[j](0), otherpoints[j](1), 0); + } + glEnd (); + } + } + + + + glPopMatrix(); + + DrawCoordinateCross (); + DrawNetgenLogo (); + + glFinish(); + } + + + void VisualSceneGeometry2d :: BuildScene (int zoomall) + { + Box<2> bbox; + + geometry2d->GetBoundingBox (bbox); + + Point<2> c = Center (bbox.PMin(), bbox.PMax()); + + center = Point3d (c(0), c(1), 0); + rad = Dist (bbox.PMin(), bbox.PMax()) / 2; + + CalcTransformationMatrices(); + } + + + + + + + + + + + /* *********************** Draw STL Geometry **************** */ + + + VisualSceneSTLGeometry :: VisualSceneSTLGeometry () + : VisualScene() + { + ; + } + + VisualSceneSTLGeometry :: ~VisualSceneSTLGeometry () + { + ; + } + + void VisualSceneSTLGeometry :: DrawScene () + { + if (changeval != stlgeometry->GetNT()) + BuildScene(); + + changeval = stlgeometry->GetNT(); + + + glClearColor(backcolor, backcolor, backcolor, 1.0); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + SetLight(); + + + glPushMatrix(); + glMultMatrixf (transformationmat); + + + + + glShadeModel (GL_SMOOTH); + glDisable (GL_COLOR_MATERIAL); + glPolygonMode (GL_FRONT_AND_BACK, GL_FILL); + + glEnable (GL_BLEND); + glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + + double shine = vispar.shininess; + // double transp = vispar.transp; + + glMaterialf (GL_FRONT_AND_BACK, GL_SHININESS, shine); + glLogicOp (GL_COPY); + + + float mat_col[] = { 0.2f, 0.2f, 0.8f, 1.0f}; + glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, mat_col); + + glPolygonOffset (1, 1); + glEnable (GL_POLYGON_OFFSET_FILL); + + glCallList (trilists.Get(1)); + + glDisable (GL_POLYGON_OFFSET_FILL); + + + int showtrias = vispar.showstltrias; + + if (showtrias) + { + float mat_coll[] = { 0.2f, 0.2f, 0.2f, 1.0f }; + glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, mat_coll); + glPolygonMode (GL_FRONT_AND_BACK, GL_LINE); + + glCallList (trilists.Get(1)); + } + + /* + + glBegin (GL_TRIANGLES); + for (j = 1; j <= stlgeometry -> GetNT(); j++) + { + const STLTriangle & tria = stlgeometry -> GetTriangle(j); + glNormal3f (tria.normal.X(), + tria.normal.Y(), + tria.normal.Z()); + + for (k = 0; k < 3; k++) + { + glVertex3f (tria.pts[k].X(), + tria.pts[k].Y(), + tria.pts[k].Z()); + } + } + glEnd (); + */ + + + + + glPopMatrix(); + glFinish(); + } + + + void VisualSceneSTLGeometry :: BuildScene (int zoomall) + { + // cout << "rebuild stl geometry scene" << endl; + + center = stlgeometry -> GetBoundingBox().Center(); + rad = stlgeometry -> GetBoundingBox().Diam() / 2; + + + CalcTransformationMatrices(); + + for (int i = 1; i <= trilists.Size(); i++) + glDeleteLists (trilists.Elem(i), 1); + trilists.SetSize(0); + + + trilists.Append (glGenLists (1)); + glNewList (trilists.Last(), GL_COMPILE); + + glEnable (GL_NORMALIZE); + + glBegin (GL_TRIANGLES); + for (int j = 1; j <= stlgeometry -> GetNT(); j++) + { + const Vec3d & n = stlgeometry->GetTriangle(j).Normal(); + glNormal3f (n.X(), n.Y(), n.Z()); + + for (int k = 1; k <= 3; k++) + { + const Point3d & p = + stlgeometry->GetPoint (stlgeometry -> GetTriangle(j).PNum(k)); + glVertex3f (p.X(),p.Y(), p.Z()); + } + } + glEnd (); + + glEndList (); + } + + + + + + + + + + + + + VisualSceneSpecPoints :: VisualSceneSpecPoints () + : VisualScene() + { + ; + } + + VisualSceneSpecPoints :: ~VisualSceneSpecPoints () + { + ; + } + + + void VisualSceneSpecPoints :: DrawScene () + { + if (!mesh) + { + VisualScene::DrawScene(); + return; + } + + if (changeval != specpoints.Size()) + BuildScene(); + changeval = specpoints.Size(); + + + + glClearColor(backcolor, backcolor, backcolor, 1.0); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + glEnable (GL_COLOR_MATERIAL); + glColor3f (1.0f, 1.0f, 1.0f); + glLineWidth (1.0f); + + glPushMatrix(); + glMultMatrixf (transformationmat); + + // glEnable (GL_COLOR); + // glDisable (GL_COLOR_MATERIAL); + if (vispar.drawedtangents) + { + glColor3d (1, 0, 0); + glBegin (GL_LINES); + for (int i = 1; i <= specpoints.Size(); i++) + { + const Point3d p1 = specpoints.Get(i).p; + const Point3d p2 = specpoints.Get(i).p + len * specpoints.Get(i).v; + glVertex3d (p1.X(), p1.Y(), p1.Z()); + glVertex3d (p2.X(), p2.Y(), p2.Z()); + } + glEnd(); + } + + if (vispar.drawededges) + { + glColor3d (1, 0, 0); + glBegin (GL_LINES); + for (int i = 1; i <= mesh->GetNSeg(); i++) + { + const Segment & seg = mesh -> LineSegment (i); + glVertex3dv ( &(*mesh)[seg.p1].X() ); + glVertex3dv ( &(*mesh)[seg.p2].X() ); + } + glEnd(); + } + + if (vispar.drawededgenrs) + { + glEnable (GL_COLOR_MATERIAL); + GLfloat textcol[3] = { 1 - backcolor, + 1 - backcolor, + 1 - backcolor }; + glColor3fv (textcol); + glNormal3d (0, 0, 1); + glPushAttrib (GL_LIST_BIT); + glListBase (fontbase); + + char buf[20]; + for (int i = 1; i <= mesh->GetNSeg(); i++) + { + const Segment & seg = mesh -> LineSegment (i); + const Point3d p1 = mesh -> Point (seg.p1); + const Point3d p2 = mesh -> Point (seg.p2); + + const Point3d p = Center (p1, p2); + glRasterPos3d (p.X(), p.Y(), p.Z()); + + sprintf (buf, "%d", seg.edgenr); + glCallLists (strlen (buf), GL_UNSIGNED_BYTE, buf); + } + + glPopAttrib (); + glDisable (GL_COLOR_MATERIAL); + } + + + if (vispar.drawedpoints) + { + glColor3d (0, 0, 1); + glPointSize( 3.0 ); + + /* + float range[2]; + glGetFloatv(GL_POINT_SIZE_RANGE, &range[0]); + cout << "max ptsize = " << range[0] << "-" << range[1] << endl; + */ + + + glBegin( GL_POINTS ); + for (int i = 1; i <= mesh -> GetNP(); i++) + { + const Point3d & p = mesh -> Point(i); + if (i % 2) + glVertex3f( p.X(), p.Y(), p.Z()); + } + glEnd(); + + static GLubyte knoedel[] = + { + 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, + }; + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + + glDisable (GL_COLOR_MATERIAL); + glDisable (GL_LIGHTING); + glDisable (GL_CLIP_PLANE0); + + for (int i = 1; i <= mesh -> GetNP(); i++) + { + const Point3d & p = mesh -> Point(i); + glRasterPos3d (p.X(), p.Y(), p.Z()); + glBitmap (7, 7, 3, 3, 0, 0, &knoedel[0]); + } + + } + + if (vispar.drawedpointnrs) + { + glEnable (GL_COLOR_MATERIAL); + GLfloat textcol[3] = { 1 - backcolor, + 1 - backcolor, + 1 - backcolor }; + glColor3fv (textcol); + glNormal3d (0, 0, 1); + glPushAttrib (GL_LIST_BIT); + glListBase (fontbase); + + char buf[20]; + for (int i = 1; i <= mesh->GetNP(); i++) + { + const Point3d & p = mesh->Point(i); + glRasterPos3d (p.X(), p.Y(), p.Z()); + + sprintf (buf, "%d", i); + glCallLists (strlen (buf), GL_UNSIGNED_BYTE, 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).p1)); + for (int i = 1; i <= mesh->GetNSeg(); i++) + { + box.AddPoint (mesh->Point (mesh->LineSegment(i).p1)); + box.AddPoint (mesh->Point (mesh->LineSegment(i).p2)); + } + } + else if (specpoints.Size() >= 2) + { + box.SetPoint (specpoints.Get(1).p); + for (int i = 2; i <= specpoints.Size(); i++) + box.AddPoint (specpoints.Get(i).p); + } + else + { + box = Box3d (Point3d (0,0,0), Point3d (1,1,1)); + } + + if (zoomall == 2 && ((vispar.centerpoint >= 1 && vispar.centerpoint <= mesh->GetNP()) || + vispar.use_center_coords)) + { + if (vispar.use_center_coords) + { + center.X() = vispar.centerx; center.Y() = vispar.centery; center.Z() = vispar.centerz; + } + else + center = mesh->Point (vispar.centerpoint); + } + else + center = Center (box.PMin(), box.PMax()); + + + rad = 0.5 * Dist (box.PMin(), box.PMax()); + + + CalcTransformationMatrices(); + } + +} diff --git a/contrib/Netgen/libsrc/visualization/mvdraw.hpp b/contrib/Netgen/libsrc/visualization/mvdraw.hpp new file mode 100644 index 0000000000..5665533979 --- /dev/null +++ b/contrib/Netgen/libsrc/visualization/mvdraw.hpp @@ -0,0 +1,370 @@ +#ifndef FILE_MVDRAW +#define FILE_MVDRAW + +#include "vispar.hpp" + +/* + +class VisualizationParameters +{ +public: + double lightamb; + double lightdiff; + double lightspec; + double shininess; + double transp; + int locviewer; + char selectvisual[20]; + int showstltrias; + + Vec3d clipnormal; + double clipdist; + int clipenable; + int clipplanetimestamp; + + int colormeshsize; + + int drawfilledtrigs; + int drawbadels; + int drawoutline; + int drawedges; + int subdivisions; + + int drawprisms; + int drawpyramids; + int drawhexes; + double shrink; + int drawidentified; + int drawpointnumbers; + int drawedgenumbers; + int drawfacenumbers; + int drawelementnumbers; + int drawdomainsurf; + int drawtets; + int drawtetsdomain; + + int drawededges; + int drawedpoints; + int drawedpointnrs; + int drawedtangents; + int drawededgenrs; + + int drawcurveproj; + int drawcurveprojedge; + + + int centerpoint; + int drawelement; + + // stl: + int stlshowtrias; + int stlshowfilledtrias; + int stlshowedges; + int stlshowmarktrias; + int stlshowactivechart; + int stlchartnumber; + int stlchartnumberoffset; + + // occ: + int occshowvolumenr; + bool occshowsurfaces; + bool occshowedges; + bool occvisproblemfaces; + bool occzoomtohighlightedentity; + + bool whitebackground; + int stereo; + bool usedispllists; + bool drawcoordinatecross; + bool drawcolorbar; + bool drawnetgenlogo; + + +public: + VisualizationParameters(); +}; +extern VisualizationParameters vispar; +*/ + + + + + + +extern void InitDrawMesh (); +extern void DrawMesh (); +extern void MouseMove(int oldx, int oldy, + int newx, int newy, + char mode); + +extern void Render (); + + +class VisualScene +{ +protected: + static Point3d center; + static double rad; + + static float lookatmat[16]; + static float transmat[16]; + static float rotmat[16]; + static float centermat[16]; + static float transformationmat[16]; + + GLdouble clipplane[4]; + + int changeval; + static GLdouble backcolor; + +public: + static GLuint fontbase; + static GLubyte * colortexture; + static GLuint coltexname; + static int ntexcols; + // static bool linear_colors; + int invcolor; + + +public: + VisualScene (); + virtual ~VisualScene(); + + virtual void BuildScene (int zoomall = 0); + virtual void DrawScene (); + + void CalcTransformationMatrices(); + void StandardRotation (const char * dir); + void ArbitraryRotation (const ARRAY<double> & alpha, const ARRAY<Vec3d> & vec); + void ArbitraryRotation (const double alpha, const Vec3d & vec); + + void MouseMove(int oldx, int oldy, + int newx, int newy, + char mode); + + void LookAt (const Point<3> & cam, const Point<3> & obj, + const Point<3> & camup); + + void SetClippingPlane (); + + virtual void MouseDblClick (int px, int py); + + void SetLight (); + static void SetBackGroundColor (double col) + { backcolor = col; } + + void CreateTexture (int ncols, int linear, int typ = GL_DECAL); + void DrawColorBar (double minval, double maxval, int logscale = 0, bool linear = 1); + void DrawCoordinateCross (); + void DrawNetgenLogo (); + void SetOpenGlColor(double val, double valmin, double valmax, int logscale = 0); +}; + + +class VisualSceneGeometry : public VisualScene +{ + ARRAY<int> trilists; + int selsurf; +public: + VisualSceneGeometry (); + virtual ~VisualSceneGeometry (); + + virtual void SelectSurface (int aselsurf); + virtual void BuildScene (int zoomall = 0); + virtual void DrawScene (); +}; + + + +class VisualSceneSTLGeometry : public VisualScene +{ + ARRAY<int> trilists; + +public: + VisualSceneSTLGeometry (); + virtual ~VisualSceneSTLGeometry (); + + virtual void BuildScene (int zoomall = 0); + virtual void DrawScene (); +}; + + +class VisualSceneGeometry2d : public VisualScene +{ +public: + VisualSceneGeometry2d (); + virtual ~VisualSceneGeometry2d (); + + virtual void BuildScene (int zoomall = 0); + virtual void DrawScene (); +}; + + +#ifdef OCCGEOMETRY +class VisualSceneOCCGeometry : public VisualScene +{ + ARRAY<int> trilists; + ARRAY<int> linelists; + int selsurf; +public: + VisualSceneOCCGeometry (); + virtual ~VisualSceneOCCGeometry (); + + virtual void BuildScene (int zoomall = 0); + virtual void DrawScene (); + virtual void MouseDblClick (int px, int py); +}; +#endif + + + + +#ifdef STEP +class VisualSceneSTEPGeometry : public VisualScene +{ + ARRAY<int> gllists; + +public: + VisualSceneSTEPGeometry (); + virtual ~VisualSceneSTEPGeometry (); + + virtual void BuildScene (int zoomall = 0); + virtual void DrawScene (); +}; +#endif + + +class VisualSceneSTLMeshing : public VisualScene +{ + ARRAY<int> trilists; + int selecttrig, nodeofseltrig; + +public: + VisualSceneSTLMeshing (); + virtual ~VisualSceneSTLMeshing (); + + virtual void BuildScene (int zoomall = 0); + virtual void DrawScene (); + virtual void MouseDblClick (int px, int py); + + int seltria; +}; + + + + +class VisualSceneSurfaceMeshing : public VisualScene +{ +public: + VisualSceneSurfaceMeshing (); + virtual ~VisualSceneSurfaceMeshing (); + + virtual void BuildScene (int zoomall = 0); + virtual void DrawScene (); +}; + + + + + + + +class VisualSceneMesh : public VisualScene +{ + int filledlist; + int linelist; + int pointnumberlist; + + int tetlist; + int prismlist; + int pyramidlist; + int hexlist; + + int badellist; + int identifiedlist; + int domainsurflist; + + int vstimestamp, selecttimestamp; + int filledtimestamp; + int linetimestamp; + int pointnumbertimestamp; + + int tettimestamp; + int prismtimestamp; + int pyramidtimestamp; + int hextimestamp; + + int badeltimestamp; + int identifiedtimestamp; + int domainsurftimestamp; + + NgLock *lock; + + int selface, selelement; + int selpoint, selpoint2, locpi; + int seledge; + + double minh, maxh; // for meshsize coloring + +public: + VisualSceneMesh (); + virtual ~VisualSceneMesh (); + + virtual void BuildScene (int zoomall = 0); + virtual void DrawScene (); + virtual void MouseDblClick (int px, int py); + + int SelectedFace () const + { return selface; } + void SetSelectedFace (int asf) + { selface = asf; selecttimestamp = GetTimeStamp(); } + + int SelectedEdge () const + { return seledge; } + int SelectedElement () const + { return selelement; } + int SelectedPoint () const + { return selpoint; } +private: + void BuildFilledList(); + void BuildLineList(); + void BuildPointNumberList(); + + void BuildTetList(); + void BuildPrismList(); + void BuildPyramidList(); + void BuildHexList(); + + void BuildBadelList(); + void BuildIdentifiedList(); + void BuildDomainSurfList(); +}; + + + + + + + +class VisualSceneSpecPoints : public VisualScene +{ +public: + VisualSceneSpecPoints (); + virtual ~VisualSceneSpecPoints (); + + virtual void BuildScene (int zoomall = 0); + virtual void DrawScene (); + + double len; +}; + +// extern struct Tcl_Interp * hinterp; + + +extern void AddVisualizationScene (const string & name, + VisualScene * vs); + + + +#endif + diff --git a/contrib/Netgen/libsrc/visualization/soldata.hpp b/contrib/Netgen/libsrc/visualization/soldata.hpp new file mode 100644 index 0000000000..44e0d0a56e --- /dev/null +++ b/contrib/Netgen/libsrc/visualization/soldata.hpp @@ -0,0 +1,45 @@ +#ifndef FILE_SOLDATA +#define FILE_SOLDATA + + +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 GetSurfValue (int /* selnr */, + double /* lam1 */, double /* lam2 */, + double * /* values */) + { return false; } + + void SetMultiDimComponent (int mc) + { multidimcomponent = mc; } +}; + + +#endif + diff --git a/contrib/Netgen/libsrc/visualization/stlmeshing.cpp b/contrib/Netgen/libsrc/visualization/stlmeshing.cpp new file mode 100644 index 0000000000..45adac9d75 --- /dev/null +++ b/contrib/Netgen/libsrc/visualization/stlmeshing.cpp @@ -0,0 +1,1074 @@ +#include <mystdlib.h> +#include <myadt.hpp> + +#include <linalg.hpp> +#include <stlgeom.hpp> + +#include <meshing.hpp> +#include <visual.hpp> + +namespace netgen +{ + +/* +//mmm +#include "stlgeom/modeller.hpp" +*/ + +/* *********************** Draw STL Geometry **************** */ + +extern STLGeometry * stlgeometry; +extern AutoPtr<Mesh> mesh; + + +#ifdef OPENGL + +// #include "../../ngtcltk/mvdraw.hpp" + + +VisualSceneSTLMeshing :: VisualSceneSTLMeshing () + : VisualScene() +{ + selecttrig = 0; + nodeofseltrig = 1; + stlgeometry->SetSelectTrig(selecttrig); + stlgeometry->SetNodeOfSelTrig(nodeofseltrig); +} + +VisualSceneSTLMeshing :: ~VisualSceneSTLMeshing () +{ + ; +} + +void VisualSceneSTLMeshing :: DrawScene () +{ + int i, j, k; + + if (changeval != stlgeometry->GetNT()) + BuildScene(); + changeval = stlgeometry->GetNT(); + + int colormeshsize = vispar.colormeshsize; + + double hmin, hmax; + + if (colormeshsize) + { + hmax = -1E50; + hmin = +1E50; + double ms; + + for (i = 1; i <= stlgeometry->GetNP(); i++) + { + ms = mesh->GetH (stlgeometry->GetPoint(i)); + hmin = min2(hmin,ms); + hmax = max2(hmax,ms); + } + + //hmax = mparam.maxh; + //hmin = mesh->GetMinH (stlgeometry->GetBoundingBox().PMin(), + // stlgeometry->GetBoundingBox().PMax()); + + if (hmin == 0) hmin = 0.1 * hmax; + //hmax *= 1.1; + } + + + + glClearColor(backcolor, backcolor, backcolor, 1.0); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + + SetLight(); + + glPushMatrix(); + glMultMatrixf (transformationmat); + + SetClippingPlane (); + + glShadeModel (GL_SMOOTH); + glDisable (GL_COLOR_MATERIAL); + glPolygonMode (GL_FRONT_AND_BACK, GL_FILL); + + glEnable (GL_BLEND); + glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + float mat_spec_col[] = { 1, 1, 1, 1 }; + glMaterialfv (GL_FRONT_AND_BACK, GL_SPECULAR, mat_spec_col); + + double shine = vispar.shininess; + double transp = vispar.transp; + + glMaterialf (GL_FRONT_AND_BACK, GL_SHININESS, shine); + glLogicOp (GL_COPY); + + float mat_colred[] = { 0.9f, 0.0f, 0.0f, 1.0f }; + float mat_colgreen[] = { 0.0f, 0.9f, 0.0f, 1.0f }; + float mat_colblue[] = { 0.1f, 0.1f, 1.0f, 1.0f }; + + float mat_colbluegreen[] = { 0.1f, 0.5f, 0.9f, 1.0f }; + float mat_colpink[] = { 1.0f, 0.1f, 0.5f, 1.0f }; + float mat_colviolet[] = { 1.0f, 0.1f, 1.0f, 1.0f }; + float mat_colbrown[] = { 0.8f, 0.6f, 0.1f, 1.0f }; + float mat_colorange[] = { 0.9f, 0.7f, 0.1f, 1.0f }; + float mat_colturquis[] = { 0.0f, 1.0f, 0.8f, 1.0f }; + + float mat_colgrey[] = { 0.3f, 0.3f, 0.3f, 1.0f }; + + float mat_collred[] = { 1.0f, 0.5f, 0.5f, 1.0f }; + float mat_collgreen[] = { 0.2f, 1.9f, 0.2f, 1.0f }; + float mat_collbrown[] = { 1.0f, 0.8f, 0.3f, 1.0f }; + + float mat_collgrey[] = { 0.8f, 0.8f, 0.8f, 1.0f }; + float mat_colmgrey[] = { 0.4f, 0.4f, 0.4f, 1.0f }; + + float mat_colstlbody[] = { 0.0f, 0.0f, 0.8f, 1.0f }; + float mat_colseltrig[] = { 0.7f, 0.7f, 0.3f, 1.0f }; + float mat_colseledge[] = { 0.7f, 0.7f, 1.0f, 1.0f }; + + glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, mat_colblue); + + float pgoff = 0.5f; + + glPolygonOffset (pgoff*1, pgoff*1); + glEnable (GL_POLYGON_OFFSET_FILL); + + glEnable (GL_NORMALIZE); + + /* + { + //mmm + //test modeller + Modeller model; + + //MoZylinder z1(Point3d(0,0,0),Vec3d(100,0,0),20,0.01); + //model.Add(&z1); + //MoZylinder z2(Point3d(50,50,0),Vec3d(0,-100,0),20,0.01); + //model.Add(&z2); + + MoZylinder z1(Point3d(0,0,0),Vec3d(100,0,0),20,0.01); + MoZylinder z2(Point3d(50,50,0),Vec3d(0,-100,0),20,0.01); + MoCombine cb1(&z1,&z2); + model.Add(&cb1); + + ARRAY<MoTriangle> trigs; + model.GetTriangles(trigs); + int i, k; + glBegin (GL_TRIANGLES); + for (i = 1; i <= trigs.Size(); i++) + { + const MoTriangle & tria = trigs.Get(i); + glNormal3f (tria.normal.X(), + tria.normal.Y(), + tria.normal.Z()); + + for (k = 0; k < 3; k++) + { + glVertex3f (tria.pts[k].X(), + tria.pts[k].Y(), + tria.pts[k].Z()); + } + } + glEnd (); + + + } + +*/ + + + + + if (!stlgeometry->trigsconverted) + { + glBegin (GL_TRIANGLES); + for (j = 1; j <= stlgeometry -> GetNT(); j++) + { + /* + if (j % 10 == seltria) + glMaterialfv (GL_FRONT_AND_BACK, + GL_AMBIENT_AND_DIFFUSE, mat_colred); + */ + + const Vec3d & n = stlgeometry->GetTriangle(j).Normal(); + glNormal3f (n.X(), n.Y(), n.Z()); + /* + const STLReadTriangle & tria = stlgeometry -> GetReadTriangle(j); + glNormal3f (tria.normal.X(), + tria.normal.Y(), + tria.normal.Z()); + */ + + + for (k = 1; k <= 3; k++) + { + const Point3d & tp = stlgeometry->GetPoint(stlgeometry->GetTriangle(j).PNum(k)); + glVertex3f (tp.X(), tp.Y(), tp.Z()); + + } + /* + if (j%10 == seltria) + glMaterialfv (GL_FRONT_AND_BACK, + GL_AMBIENT_AND_DIFFUSE, mat_colblue); + */ + } + glEnd (); + + glDisable (GL_POLYGON_OFFSET_FILL); + + int showtrias = vispar.stlshowtrias; + + if (showtrias) + { + float mat_coll[] = { 0.2, 0.2, 0.2, 1 }; + glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, mat_coll); + glPolygonMode (GL_FRONT_AND_BACK, GL_LINE); + + glEnable (GL_NORMALIZE); + + glBegin (GL_TRIANGLES); + for (j = 1; j <= stlgeometry -> GetNT(); j++) + { + const Vec3d & n = stlgeometry->GetTriangle(j).Normal(); + glNormal3f (n.X(), n.Y(), n.Z()); + /* + const STLReadTriangle & tria = stlgeometry -> GetReadTriangle(j); + glNormal3f (tria.normal.X(), + tria.normal.Y(), + tria.normal.Z()); + */ + + for (k = 1; k <= 3; k++) + { + const Point3d & tp = + stlgeometry->GetPoint(stlgeometry->GetTriangle(j).PNum(k)); + glVertex3f (tp.X(), tp.Y(), tp.Z()); + + } + + /* + for (k = 0; k < 3; k++) + { + glVertex3f (tria.pts[k].X(), + tria.pts[k].Y(), + tria.pts[k].Z()); + } + */ + } + glEnd (); + } + } + else + { + int showfilledtrias = vispar.stlshowfilledtrias; + + //(*mycout) << "in " << showfilledtrias << ", NT=" << stlgeometry -> GetNT() << endl; + + int chartnumber; + if (vispar.stlshowmarktrias) + chartnumber = vispar.stlchartnumber + vispar.stlchartnumberoffset; + else + chartnumber = stlgeometry->GetMeshChartNr(); + + if (showfilledtrias) + { + glPolygonMode (GL_FRONT_AND_BACK, GL_FILL); + if (colormeshsize) + glEnable (GL_COLOR_MATERIAL); + + glPolygonOffset (pgoff*4, pgoff*4); + glEnable (GL_POLYGON_OFFSET_FILL); + glEnable (GL_NORMALIZE); + + + glBegin (GL_TRIANGLES); + + int selt = stlgeometry -> GetSelectTrig(); + if (stldoctor.selectmode != 0) + {selt = 0; } //do not show selected triangle!!!! + + glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, mat_colstlbody); + + for (j = 1; j <= stlgeometry -> GetNT(); j++) + { + if (stldoctor.showvicinity && !stlgeometry->Vicinity(j)) {continue;} + + if (j == selt) + { + glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, mat_colseltrig); + } + else if (j == selt+1) + { + glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, mat_colstlbody); + } + + const STLTriangle& st = stlgeometry -> GetTriangle(j); + + const Vec3d & n = stlgeometry->GetTriangle(j).Normal(); + glNormal3f (n.X(), n.Y(), n.Z()); + + /* + const STLReadTriangle& tria = stlgeometry -> GetReadTriangle(j); + glNormal3f (tria.normal.X(), + tria.normal.Y(), + tria.normal.Z()); + */ + for (k = 0; k < 3; k++) + { + const Point3d & p = stlgeometry->GetPoint(st[k]); + if (colormeshsize) + { + SetOpenGlColor (mesh->GetH (p), hmin, hmax, 1); + } + + glVertex3f (p.X(), p.Y(), p.Z()); + } + } + + glEnd (); + } + + int foundseltrig = stlgeometry -> GetSelectTrig(); + if (foundseltrig == 0 || foundseltrig > stlgeometry->GetNT() || + (stldoctor.showvicinity && !stlgeometry->Vicinity(foundseltrig))) + {foundseltrig = 0;} + + if (foundseltrig) + { + + glPolygonOffset (pgoff*0, 0); + glEnable (GL_POLYGON_OFFSET_FILL); + + //glDisable (GL_POLYGON_OFFSET_FILL); + glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, mat_colseledge); + glPolygonMode (GL_FRONT_AND_BACK, GL_LINE); + + glEnable (GL_NORMALIZE); + + if (stldoctor.selectmode == 2) + { + //point + const STLTriangle& st = stlgeometry -> GetTriangle(foundseltrig); + const Point3d & p1 = stlgeometry->GetPoint(st[0]); + const Point3d & p2 = stlgeometry->GetPoint(st[1]); + const Point3d & p3 = stlgeometry->GetPoint(st[2]); + + double cs = (Dist(p1,p2)+Dist(p2,p3)+Dist(p3,p1))/100.; + + const Point3d & p = stlgeometry->GetPoint(st[nodeofseltrig-1]); + + glLineWidth (4); + glBegin (GL_LINES); + glVertex3f(p.X()+cs, p.Y()+cs, p.Z()+cs); + glVertex3f(p.X()-cs, p.Y()-cs, p.Z()-cs); + + glVertex3f(p.X()-cs, p.Y()+cs, p.Z()+cs); + glVertex3f(p.X()+cs, p.Y()-cs, p.Z()-cs); + + glVertex3f(p.X()-cs, p.Y()+cs, p.Z()+cs); + glVertex3f(p.X()+cs, p.Y()-cs, p.Z()-cs); + + glVertex3f(p.X()+cs, p.Y()-cs, p.Z()+cs); + glVertex3f(p.X()-cs, p.Y()+cs, p.Z()-cs); + + glEnd (); + glLineWidth (1); + } + else if (stldoctor.selectmode == 1 || + stldoctor.selectmode == 3 || + stldoctor.selectmode == 4) + { + //multiedge + + const ARRAY<twoint>& me = stlgeometry->SelectedMultiEdge(); + if (stlgeometry->GetSelectTrig() > 0 && + stlgeometry->GetSelectTrig() <= stlgeometry->GetNT() && + me.Size()) + { + + int en = stlgeometry->EdgeDataList().GetEdgeNum(me.Get(1).i1,me.Get(1).i2); + int status = stlgeometry->EdgeDataList().Get(en).GetStatus(); + + switch (status) + { + case ED_CONFIRMED: + glMaterialfv (GL_FRONT_AND_BACK, + GL_AMBIENT_AND_DIFFUSE, mat_collgreen); + break; + case ED_CANDIDATE: + glMaterialfv (GL_FRONT_AND_BACK, + GL_AMBIENT_AND_DIFFUSE, mat_collbrown); + break; + case ED_EXCLUDED: + glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, mat_collred); + break; + } + + glLineWidth (2); + glBegin (GL_LINES); + for (j = 1; j <= me.Size(); j++) + { + Point3d p1 = stlgeometry->GetPoint(me.Get(j).i1); + Point3d p2 = stlgeometry->GetPoint(me.Get(j).i2); + + glVertex3f(p1.X(), p1.Y(), p1.Z()); + glVertex3f(p2.X(), p2.Y(), p2.Z()); + } + glEnd (); + glLineWidth (1); + } + } + } + + int showmarktrias = vispar.stlshowmarktrias || vispar.stlshowactivechart; + + if (stldoctor.showmarkedtrigs) + { + //(*mycout) << "marked" << endl; + glPolygonMode (GL_FRONT_AND_BACK, GL_LINE); //GL_LINE + glPolygonOffset (pgoff*1, pgoff*1); + glEnable (GL_POLYGON_OFFSET_FILL); + glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, mat_colbluegreen); + glEnable (GL_NORMALIZE); + + glBegin (GL_TRIANGLES); + + for (j = 1; j <= stlgeometry -> GetNT(); j++) + { + if (stldoctor.showvicinity && !stlgeometry->Vicinity(j)) + {continue;} + + if (!stlgeometry->IsMarkedTrig(j)) + {continue;} + + const STLTriangle& st = stlgeometry -> GetTriangle(j); + + const Vec3d & n = stlgeometry->GetTriangle(j).Normal(); + glNormal3f (n.X(), n.Y(), n.Z()); + /* + const STLReadTriangle& tria = stlgeometry -> GetReadTriangle(j); + glNormal3f (tria.normal.X(), + tria.normal.Y(), + tria.normal.Z()); + */ + for (k = 0; k < 3; k++) + { + const Point3d & p = stlgeometry->GetPoint(st[k]); + glVertex3f (p.X(), p.Y(), p.Z()); + } + } + glEnd (); + + //show OpenSegments on original geometry + glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, mat_colviolet); + glPolygonMode (GL_FRONT_AND_BACK, GL_LINE); + glPolygonOffset (pgoff*1, 1); + + glEnable (GL_NORMALIZE); + + glBegin (GL_LINES); + + if (stlgeometry->GetNMarkedSegs()) + { + Point<3> p1,p2; + for (j = 1; j <= stlgeometry -> GetNMarkedSegs(); j++) + { + stlgeometry->GetMarkedSeg(j,p1,p2); + glVertex3dv(&p1(0)); + glVertex3dv(&p2(0)); + } + } + glEnd (); + } + + + if (stldoctor.showfaces) + { + int facenumber = vispar.stlchartnumber + vispar.stlchartnumberoffset; + + glPolygonMode (GL_FRONT_AND_BACK, GL_FILL); + glPolygonOffset (pgoff*3, 3); + glEnable (GL_POLYGON_OFFSET_FILL); + glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, mat_collgrey); + glEnable (GL_NORMALIZE); + + glBegin (GL_TRIANGLES); + + for (j = 1; j <= stlgeometry -> GetNT(); j++) + { + if (stldoctor.showvicinity && !stlgeometry->Vicinity(j)) + {continue;} + + //(*mycout) << " facenum = " << stlgeometry->GetTriangle(j).GetFaceNum() << " "; + if (stlgeometry->GetTriangle(j).GetFaceNum() != facenumber) + {continue;} + + const STLTriangle& st = stlgeometry -> GetTriangle(j); + + const Vec3d & n = stlgeometry->GetTriangle(j).Normal(); + glNormal3f (n.X(), n.Y(), n.Z()); + /* + const STLReadTriangle& tria = stlgeometry -> GetReadTriangle(j); + glNormal3f (tria.normal.X(), + tria.normal.Y(), + tria.normal.Z()); + */ + for (k = 0; k < 3; k++) + { + Point3d p = stlgeometry->GetPoint(st[k]); + glVertex3f (p.X(), p.Y(), p.Z()); + } + } + glEnd (); + } + + if (showmarktrias && stlgeometry->AtlasMade()) + { + glPolygonMode (GL_FRONT_AND_BACK, GL_FILL); + glPolygonOffset (pgoff*3, 3); + glEnable (GL_POLYGON_OFFSET_FILL); + + glBegin (GL_TRIANGLES); + + if (chartnumber >= 1 && chartnumber <= stlgeometry->GetNOCharts()) + { + glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, mat_colbrown); + const STLChart& chart = stlgeometry->GetChart(chartnumber); + for (j = 1; j <= chart.GetNChartT(); j++) + { + /* + if (j == charttrignumber) + {glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, mat_colred);} + else + {glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, mat_colbrown);} + */ + const STLTriangle& st = stlgeometry -> GetTriangle(chart.GetChartTrig(j)); + + + const Vec3d & n = stlgeometry->GetTriangle(chart.GetChartTrig(j)).Normal(); + glNormal3f (n.X(), n.Y(), n.Z()); + /* + const STLReadTriangle& tria = stlgeometry -> GetReadTriangle(chart.GetChartTrig(j)); + glNormal3f (tria.normal.X(), + tria.normal.Y(), + tria.normal.Z()); + */ + for (k = 0; k < 3; k++) + { + glVertex3f (stlgeometry->GetPoint(st[k])(0), + stlgeometry->GetPoint(st[k])(1), + stlgeometry->GetPoint(st[k])(2)); + } + } + glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, mat_colgreen); + + for (j = 1; j <= chart.GetNOuterT(); j++) + { + + const STLTriangle& st = stlgeometry -> GetTriangle(chart.GetOuterTrig(j)); + + const Vec3d & n = stlgeometry->GetTriangle(chart.GetOuterTrig(j)).Normal(); + glNormal3f (n.X(), n.Y(), n.Z()); + + + /* + const STLReadTriangle& tria = stlgeometry -> GetReadTriangle(chart.GetOuterTrig(j)); + glNormal3f (tria.normal.X(), + tria.normal.Y(), + tria.normal.Z()); + */ + for (k = 0; k < 3; k++) + { + glVertex3f (stlgeometry->GetPoint(st[k])(0), + stlgeometry->GetPoint(st[k])(1), + stlgeometry->GetPoint(st[k])(2)); + } + } + } + glEnd (); + } + + int showtrias = vispar.stlshowtrias; + + if (showtrias) + { + glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, mat_colgrey); + glPolygonMode (GL_FRONT_AND_BACK, GL_LINE); + glPolygonOffset (pgoff*2, 2); + glEnable (GL_POLYGON_OFFSET_FILL); + glEnable (GL_NORMALIZE); + + glBegin (GL_TRIANGLES); + + for (j = 1; j <= stlgeometry -> GetNT(); j++) + { + if (stldoctor.showvicinity && !stlgeometry->Vicinity(j)) {continue;} + + const STLTriangle& st = stlgeometry -> GetTriangle(j); + + const Vec3d & n = stlgeometry->GetTriangle(j).Normal(); + glNormal3f (n.X(), n.Y(), n.Z()); + /* + const STLReadTriangle& tria = stlgeometry -> GetReadTriangle(j); + glNormal3f (tria.normal.X(), + tria.normal.Y(), + tria.normal.Z()); + */ + for (k = 0; k < 3; k++) + { + glVertex3f (stlgeometry->GetPoint(st[k])(0), + stlgeometry->GetPoint(st[k])(1), + stlgeometry->GetPoint(st[k])(2)); + } + } + glEnd (); + } + + int showedges = vispar.stlshowedges; + + if (showedges) + { + glPolygonOffset (pgoff*1, 1); + glEnable (GL_POLYGON_OFFSET_FILL); + //glDisable (GL_POLYGON_OFFSET_FILL); + + glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, mat_colgreen); + glPolygonMode (GL_FRONT_AND_BACK, GL_LINE); + + glEnable (GL_NORMALIZE); + + glBegin (GL_LINES); + + /* + if (stldoctor.useexternaledges) + { + glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, mat_colorange); + for (j = 1; j <= stlgeometry -> NOExternalEdges(); j++) + { + twoint v = stlgeometry->GetExternalEdge(j); + Point3d p1 = stlgeometry->GetPoint(v.i1); + Point3d p2 = stlgeometry->GetPoint(v.i2); + + Vec3d n1 = stlgeometry->GetNormal(v.i1); + Vec3d n2 = stlgeometry->GetNormal(v.i2); + + glNormal3f(n1.X(), n1.Y(), n1.Z()); + glVertex3f(p1.X(), p1.Y(), p1.Z()); + glNormal3f(n2.X(), n2.Y(), n2.Z()); + glVertex3f(p2.X(), p2.Y(), p2.Z()); + } + } + */ + + + if (!stlgeometry->meshlines.Size() || !stldoctor.drawmeshededges) + { + /* + for (j = 1; j <= stlgeometry -> GetNE(); j++) + { + STLEdge v = stlgeometry->GetEdge(j); + Point3d p1 = stlgeometry->GetPoint(v.pts[0]); + Point3d p2 = stlgeometry->GetPoint(v.pts[1]); + + Vec3d n1 = stlgeometry->GetNormal(v.pts[0]); + Vec3d n2 = stlgeometry->GetNormal(v.pts[1]); + + glNormal3f(n1.X(), n1.Y(), n1.Z()); + glVertex3f(p1.X(), p1.Y(), p1.Z()); + glNormal3f(n2.X(), n2.Y(), n2.Z()); + glVertex3f(p2.X(), p2.Y(), p2.Z()); + } + */ + const STLEdgeDataList& ed = stlgeometry->EdgeDataList(); + for (i = 1; i <= ed.Size(); i++) + { + if (ed.Get(i).GetStatus() != ED_UNDEFINED) + { + switch (ed.Get(i).GetStatus()) + { + case ED_CONFIRMED: + glMaterialfv (GL_FRONT_AND_BACK, + GL_AMBIENT_AND_DIFFUSE, mat_colgreen); + break; + case ED_CANDIDATE: + glMaterialfv (GL_FRONT_AND_BACK, + GL_AMBIENT_AND_DIFFUSE, mat_colbrown); + break; + case ED_EXCLUDED: + glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, mat_colred); + break; + } + + if (ed.Get(i).GetStatus() == ED_EXCLUDED && !stldoctor.showexcluded) continue; + + Point3d p1 = stlgeometry->GetPoint(ed.Get(i).PNum(1)); + Point3d p2 = stlgeometry->GetPoint(ed.Get(i).PNum(2)); + glVertex3f(p1.X(), p1.Y(), p1.Z()); + glVertex3f(p2.X(), p2.Y(), p2.Z()); + } + } + } + + /* + else + if (stlgeometry->meshlines.Size() == 0) + { + for (j = 1; j <= stlgeometry->GetNLines(); j++) + { + STLLine* line = stlgeometry->GetLine(j); + int pn1, pn2; + for (int k = 1; k <= line->NP()-1; k++) + { + pn1 = line->PNum(k); + pn2 = line->PNum(k+1); + + Point3d p1 = stlgeometry->GetPoint(pn1); + Point3d p2 = stlgeometry->GetPoint(pn2); + + Vec3d n1 = stlgeometry->GetNormal(pn1); + Vec3d n2 = stlgeometry->GetNormal(pn2); + + glNormal3f(n1.X(), n1.Y(), n1.Z()); + glVertex3f(p1.X(), p1.Y(), p1.Z()); + glNormal3f(n2.X(), n2.Y(), n2.Z()); + glVertex3f(p2.X(), p2.Y(), p2.Z()); + } + } + } + */ + + else if (stlgeometry->meshlines.Size() != 0) + { + glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, mat_colgreen); + for (j = 1; j <= stlgeometry->meshlines.Size(); j++) + { + STLLine* line = stlgeometry->meshlines.Get(j); + int pn1, pn2; + for (int k = 1; k <= line->NP()-1; k++) + { + pn1 = line->PNum(k); + pn2 = line->PNum(k+1); + + Point3d p1 = stlgeometry->meshpoints.Get(pn1); + Point3d p2 = stlgeometry->meshpoints.Get(pn2); + + glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, mat_colgreen); + glVertex3f(p1.X(), p1.Y(), p1.Z()); + glVertex3f(p2.X(), p2.Y(), p2.Z()); + + + glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, mat_colred); + double cs = 0.02*Dist(p1,p2); + glVertex3f(p1.X()+cs, p1.Y()+cs, p1.Z()+cs); + glVertex3f(p1.X()-cs, p1.Y()-cs, p1.Z()-cs); + glVertex3f(p2.X()+cs, p2.Y()+cs, p2.Z()+cs); + glVertex3f(p2.X()-cs, p2.Y()-cs, p2.Z()-cs); + + glVertex3f(p1.X()-cs, p1.Y()+cs, p1.Z()+cs); + glVertex3f(p1.X()+cs, p1.Y()-cs, p1.Z()-cs); + glVertex3f(p2.X()-cs, p2.Y()+cs, p2.Z()+cs); + glVertex3f(p2.X()+cs, p2.Y()-cs, p2.Z()-cs); + + } + } + } + + + glEnd (); + } + + if (stldoctor.showedgecornerpoints && stlgeometry->LineEndPointsSet()) + { + glPointSize (5); + glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, mat_colred); + glBegin (GL_POINTS); + for (i = 1; i <= stlgeometry->GetNP(); i++) + { + if (stlgeometry->IsLineEndPoint(i)) + { + const Point3d p = stlgeometry->GetPoint(i); + glVertex3f (p.X(), p.Y(), p.Z()); + } + } + glEnd(); + + } + + + } + + + glPopMatrix(); + + if (vispar.colormeshsize) + DrawColorBar (hmin, hmax, 1); + + glFinish(); +} + + +void VisualSceneSTLMeshing :: BuildScene (int zoomall) +{ + if (selecttrig && zoomall == 2) + center = stlgeometry -> GetPoint ( stlgeometry->GetTriangle(selecttrig).PNum(nodeofseltrig)); + else + center = stlgeometry -> GetBoundingBox().Center(); + + rad = stlgeometry -> GetBoundingBox().Diam() / 2; + + CalcTransformationMatrices(); +} + + + +void VisualSceneSTLMeshing :: MouseDblClick (int px, int py) +{ + // (*mycout) << "dblclick: " << px << " - " << py << endl; + + + int i, j, k, hits; + + // select surface triangle by mouse click + + GLuint selbuf[10000]; + glSelectBuffer (10000, selbuf); + + + glRenderMode (GL_SELECT); + + GLint viewport[4]; + glGetIntegerv (GL_VIEWPORT, viewport); + + /* + (*mycout) << "viewport = " << viewport[0] << " " + << viewport[1] << " " << viewport[2] << " " << viewport[3] << endl; + */ + + glMatrixMode (GL_PROJECTION); + glPushMatrix(); + + + GLdouble projmat[16]; + glGetDoublev (GL_PROJECTION_MATRIX, projmat); + + glLoadIdentity(); + gluPickMatrix (px, viewport[3] - py, 1, 1, viewport); + glMultMatrixd (projmat); + + + + glClearColor(backcolor, backcolor, backcolor, 1.0); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + glMatrixMode (GL_MODELVIEW); + + glPushMatrix(); + glMultMatrixf (transformationmat); + + + glInitNames(); + glPushName (1); + + + glEnable (GL_POLYGON_OFFSET_FILL); + for (j = 1; j <= stlgeometry -> GetNT(); j++) + { + if (stldoctor.showvicinity && !stlgeometry->Vicinity(j)) {continue;} + + const STLTriangle& st = stlgeometry -> GetTriangle(j); + + //const STLReadTriangle& tria = stlgeometry -> GetReadTriangle(j); + //glNormal3f (tria.normal.X(), tria.normal.Y(), tria.normal.Z()); + + if (stldoctor.selectmode == 0) + { + glLoadName (j); + glBegin (GL_TRIANGLES); + for (k = 0; k < 3; k++) + { + Point3d p = stlgeometry->GetPoint(st[k]); + glVertex3f (p.X(), p.Y(), p.Z()); + } + glEnd (); + } + else if (stldoctor.selectmode == 1 || stldoctor.selectmode == 3 + || stldoctor.selectmode == 4) + { + Point3d pm = Center(stlgeometry->GetPoint(st[0]), + stlgeometry->GetPoint(st[1]), + stlgeometry->GetPoint(st[2])); + + for (k = 0; k < 3; k++) + { + glLoadName (j*3+k-2); + glBegin (GL_TRIANGLES); + + Point3d p1 = stlgeometry->GetPoint(st[k]); + Point3d p2 = stlgeometry->GetPoint(st[(k+1)%3]); + glVertex3f (p1.X(), p1.Y(), p1.Z()); + glVertex3f (p2.X(), p2.Y(), p2.Z()); + glVertex3f (pm.X(), pm.Y(), pm.Z()); + + glEnd (); + } + } + else + { + Point3d pm1 = Center(stlgeometry->GetPoint(st[0]), + stlgeometry->GetPoint(st[1])); + Point3d pm2 = Center(stlgeometry->GetPoint(st[1]), + stlgeometry->GetPoint(st[2])); + Point3d pm3 = Center(stlgeometry->GetPoint(st[2]), + stlgeometry->GetPoint(st[0])); + + Point3d p1 = stlgeometry->GetPoint(st[0]); + Point3d p2 = stlgeometry->GetPoint(st[1]); + Point3d p3 = stlgeometry->GetPoint(st[2]); + + glLoadName (j*4-3); + glBegin (GL_TRIANGLES); + glVertex3f (p1.X(), p1.Y(), p1.Z()); + glVertex3f (pm1.X(), pm1.Y(), pm1.Z()); + glVertex3f (pm3.X(), pm3.Y(), pm3.Z()); + glEnd (); + + glLoadName (j*4-2); + glBegin (GL_TRIANGLES); + glVertex3f (p2.X(), p2.Y(), p2.Z()); + glVertex3f (pm2.X(), pm2.Y(), pm2.Z()); + glVertex3f (pm1.X(), pm1.Y(), pm1.Z()); + glEnd (); + + glLoadName (j*4-1); + glBegin (GL_TRIANGLES); + glVertex3f (p3.X(), p3.Y(), p3.Z()); + glVertex3f (pm3.X(), pm3.Y(), pm3.Z()); + glVertex3f (pm2.X(), pm2.Y(), pm2.Z()); + glEnd (); + + glLoadName (j*4); + glBegin (GL_TRIANGLES); + glVertex3f (pm1.X(), pm1.Y(), pm1.Z()); + glVertex3f (pm2.X(), pm2.Y(), pm2.Z()); + glVertex3f (pm3.X(), pm3.Y(), pm3.Z()); + glEnd (); + } + } + + glPopName(); + + glMatrixMode (GL_PROJECTION); + glPopMatrix(); + + glMatrixMode (GL_MODELVIEW); + glPopMatrix(); + + glFlush(); + + + hits = glRenderMode (GL_RENDER); + + // (*mycout) << "hits = " << hits << endl; + + //int minrec = -1; + int minname = 0; + GLuint mindepth = 0; + for (i = 0; i < hits; i++) + { + int curname = selbuf[4*i+3]; + GLuint curdepth = selbuf[4*i+1]; + + /* + (*mycout) << selbuf[4*i] << " " << selbuf[4*i+1] << " " + << selbuf[4*i+2] << " " << selbuf[4*i+3] << endl; + */ + if (curname && + (curdepth < mindepth || !minname)) + { + //minrec = i; + mindepth = curdepth; + minname = curname; + } + } + + if (!minname) {return;} + + if (stldoctor.selectmode == 0) + { + int oldtrig = selecttrig; + selecttrig = minname; + if (selecttrig == oldtrig) + nodeofseltrig = (nodeofseltrig % 3) + 1; + else + nodeofseltrig = 1; + + stlgeometry->SetSelectTrig(selecttrig); + stlgeometry->SetNodeOfSelTrig(nodeofseltrig); + stlgeometry->PrintSelectInfo(); + + } + else if (stldoctor.selectmode == 1 || stldoctor.selectmode == 3 || stldoctor.selectmode == 4) + { + selecttrig = (minname-1) / 3 + 1; + nodeofseltrig = minname-selecttrig*3+3; + + stlgeometry->SetSelectTrig(selecttrig); + stlgeometry->SetNodeOfSelTrig(nodeofseltrig); + stlgeometry->PrintSelectInfo(); + + if (stldoctor.selectmode == 1) + { + stlgeometry->BuildSelectedEdge(twoint(stlgeometry->GetTriangle(selecttrig).PNumMod(nodeofseltrig), + stlgeometry->GetTriangle(selecttrig).PNumMod(nodeofseltrig+1))); + } + if (stldoctor.selectmode == 3) + { + stlgeometry->BuildSelectedMultiEdge(twoint(stlgeometry->GetTriangle(selecttrig).PNumMod(nodeofseltrig), + stlgeometry->GetTriangle(selecttrig).PNumMod(nodeofseltrig+1))); + } + else if (stldoctor.selectmode == 4) + { + stlgeometry->BuildSelectedCluster(twoint(stlgeometry->GetTriangle(selecttrig).PNumMod(nodeofseltrig), + stlgeometry->GetTriangle(selecttrig).PNumMod(nodeofseltrig+1))); + } + + switch (stldoctor.edgeselectmode) + { + case 1: stlgeometry->STLDoctorUndefinedEdge(); break; + case 2: stlgeometry->STLDoctorConfirmEdge(); break; + case 3: stlgeometry->STLDoctorCandidateEdge(); break; + case 4: stlgeometry->STLDoctorExcludeEdge(); break; + default: break; + } + } + else if (stldoctor.selectmode == 2) + { + selecttrig = (minname-1) / 4 + 1; + nodeofseltrig = minname-selecttrig*4+4; + if (nodeofseltrig == 4) {nodeofseltrig = 1;} + + stlgeometry->SetSelectTrig(selecttrig); + stlgeometry->SetNodeOfSelTrig(nodeofseltrig); + stlgeometry->PrintSelectInfo(); + + } + + if (stldoctor.showtouchedtrigchart && stlgeometry->AtlasMade() && stlgeometry->GetSelectTrig()) + { + vispar.stlchartnumber = stlgeometry->GetChartNr(stlgeometry->GetSelectTrig()); + vispar.stlchartnumberoffset = 0; + } + +} + + + + +VisualSceneSTLMeshing vsstlmeshing; + +#endif + + + + +} diff --git a/contrib/Netgen/libsrc/visualization/vispar.hpp b/contrib/Netgen/libsrc/visualization/vispar.hpp new file mode 100644 index 0000000000..3a35294182 --- /dev/null +++ b/contrib/Netgen/libsrc/visualization/vispar.hpp @@ -0,0 +1,89 @@ +#ifndef FILE_VISPAR +#define FILE_VISPAR + +class VisualizationParameters +{ +public: + double lightamb; + double lightdiff; + double lightspec; + double shininess; + double transp; + int locviewer; + char selectvisual[20]; + int showstltrias; + + Vec3d clipnormal; + double clipdist; + int clipenable; + int clipplanetimestamp; + + int colormeshsize; + + int drawfilledtrigs; + int drawbadels; + int drawoutline; + int drawedges; + int subdivisions; + + int drawprisms; + int drawpyramids; + int drawhexes; + double shrink; + int drawidentified; + int drawpointnumbers; + int drawedgenumbers; + int drawfacenumbers; + int drawelementnumbers; + int drawdomainsurf; + int drawtets; + int drawtetsdomain; + + int drawededges; + int drawedpoints; + int drawedpointnrs; + int drawedtangents; + int drawededgenrs; + int drawmetispartition; + + int drawcurveproj; + int drawcurveprojedge; + + + int centerpoint; + int drawelement; + + // stl: + int stlshowtrias; + int stlshowfilledtrias; + int stlshowedges; + int stlshowmarktrias; + int stlshowactivechart; + int stlchartnumber; + int stlchartnumberoffset; + + // occ: + int occshowvolumenr; + bool occshowsurfaces; + bool occshowedges; + bool occvisproblemfaces; + bool occzoomtohighlightedentity; + double occdeflection; + + bool whitebackground; + int stereo; + bool usedispllists; + bool drawcoordinatecross; + bool drawcolorbar; + bool drawnetgenlogo; + + bool use_center_coords; + double centerx,centery,centerz; + + +public: + VisualizationParameters(); +}; +extern VisualizationParameters vispar; + +#endif diff --git a/contrib/Netgen/libsrc/visualization/visual.hpp b/contrib/Netgen/libsrc/visualization/visual.hpp new file mode 100644 index 0000000000..3e5910b351 --- /dev/null +++ b/contrib/Netgen/libsrc/visualization/visual.hpp @@ -0,0 +1,26 @@ +#ifndef FILE_VISUAL +#define FILE_VISUAL + +/* *************************************************************************/ +/* File: visual.hpp */ +/* Author: Joachim Schoeberl */ +/* Date: 02. Dec. 01 */ +/* *************************************************************************/ + +/* + +Visualization + +*/ + +#include <incvis.hpp> + +namespace netgen +{ +#include "mvdraw.hpp" +#include "soldata.hpp" +#include "vssolution.hpp" +#include "meshdoc.hpp" +} + +#endif diff --git a/contrib/Netgen/libsrc/visualization/vscsg.cpp b/contrib/Netgen/libsrc/visualization/vscsg.cpp new file mode 100644 index 0000000000..d17c0c38e2 --- /dev/null +++ b/contrib/Netgen/libsrc/visualization/vscsg.cpp @@ -0,0 +1,199 @@ +#include <mystdlib.h> +#include "incvis.hpp" + +#include <myadt.hpp> +#include <meshing.hpp> +#include <csg.hpp> +#include <stlgeom.hpp> + + +namespace netgen +{ +#include "mvdraw.hpp" + +/* *********************** Draw Geometry **************** */ + + + + +extern AutoPtr<CSGeometry> geometry; + + +VisualSceneGeometry :: VisualSceneGeometry () + : VisualScene() +{ + selsurf = 0; +} + +VisualSceneGeometry :: ~VisualSceneGeometry () +{ + ; +} + +void VisualSceneGeometry :: SelectSurface (int aselsurf) +{ + selsurf = aselsurf; + DrawScene(); +} + + +void VisualSceneGeometry :: DrawScene () +{ + int i; + + if (changeval != geometry->GetChangeVal()) + BuildScene(); + changeval = geometry->GetChangeVal(); + + glClearColor(backcolor, backcolor, backcolor, 1.0); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + SetLight(); + + + glPushMatrix(); + glMultMatrixf (transformationmat); + + SetClippingPlane (); + + glShadeModel (GL_SMOOTH); + glDisable (GL_COLOR_MATERIAL); + glPolygonMode (GL_FRONT_AND_BACK, GL_FILL); + + glEnable (GL_BLEND); + glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + /* + float mat_spec_col[] = { 1, 1, 1, 1 }; + glMaterialfv (GL_FRONT_AND_BACK, GL_SPECULAR, mat_spec_col); + */ + + double shine = vispar.shininess; + double transp = vispar.transp; + + glMaterialf (GL_FRONT_AND_BACK, GL_SHININESS, shine); + glLogicOp (GL_COPY); + + glEnable (GL_NORMALIZE); + + for (i = 0; i < geometry->GetNTopLevelObjects(); i++) + { + const TopLevelObject * tlo = geometry -> GetTopLevelObject (i); + if (tlo->GetVisible() && !tlo->GetTransparent()) + { + float mat_col[] = { tlo->GetRed(), tlo->GetGreen(), tlo->GetBlue(), 1 }; + glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, mat_col); + + glCallList (trilists[i]); + } + } + + + glPolygonOffset (1, 1); + glEnable (GL_POLYGON_OFFSET_FILL); + + glLogicOp (GL_NOOP); + for (i = 0; i < geometry->GetNTopLevelObjects(); i++) + { + const TopLevelObject * tlo = geometry -> GetTopLevelObject (i); + if (tlo->GetVisible() && tlo->GetTransparent()) + { + float mat_col[] = { tlo->GetRed(), tlo->GetGreen(), tlo->GetBlue(), transp }; + + glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, mat_col); + + glCallList (trilists[i]); + } + } + + glDisable (GL_POLYGON_OFFSET_FILL); + + glPopMatrix(); + + glDisable(GL_CLIP_PLANE0); + + DrawCoordinateCross (); + DrawNetgenLogo (); + + glFinish(); + +} + + +void VisualSceneGeometry :: BuildScene (int zoomall) +{ + int i, j, k; + + Box<3> box; + int hasp = 0; + for (i = 0; i < geometry->GetNTopLevelObjects(); i++) + { + const TriangleApproximation & ta = + *geometry->GetTriApprox(i); + if (!&ta) continue; + + for (j = 0; j < ta.GetNP(); j++) + { + if (hasp) + box.Add (ta.GetPoint(j)); + else + { + hasp = 1; + box.Set (ta.GetPoint(j)); + } + } + } + if (hasp) + { + center = box.Center(); + rad = box.Diam() / 2; + } + else + { + center = Point3d(0,0,0); + rad = 1; + } + + CalcTransformationMatrices(); + + for (i = 0; i < trilists.Size(); i++) + glDeleteLists (trilists[i], 1); + trilists.SetSize(0); + + for (i = 0; i < geometry->GetNTopLevelObjects(); i++) + { + trilists.Append (glGenLists (1)); + glNewList (trilists.Last(), GL_COMPILE); + + glEnable (GL_NORMALIZE); + const TriangleApproximation & ta = + *geometry->GetTriApprox(i); + if (&ta) + { + glBegin (GL_TRIANGLES); + for (j = 0; j < ta.GetNT(); j++) + { + + for (k = 0; k < 3; k++) + { + int pi = ta.GetTriangle(j)[k]; + glNormal3f (ta.GetNormal (pi)(0), + ta.GetNormal (pi)(1), + ta.GetNormal (pi)(2)); + glVertex3f (ta.GetPoint(pi)(0), + ta.GetPoint(pi)(1), + ta.GetPoint(pi)(2)); + } + } + glEnd (); + } + glEndList (); + } + +} + + + + + +} diff --git a/contrib/Netgen/libsrc/visualization/vsmesh.cpp b/contrib/Netgen/libsrc/visualization/vsmesh.cpp new file mode 100644 index 0000000000..c53e5223be --- /dev/null +++ b/contrib/Netgen/libsrc/visualization/vsmesh.cpp @@ -0,0 +1,3114 @@ +#include <mystdlib.h> +#include "incvis.hpp" + + +#include <myadt.hpp> +#include <meshing.hpp> +#include <csg.hpp> +#include <stlgeom.hpp> + +namespace netgen +{ + +#include "mvdraw.hpp" + + + // #define FAST3DELEMENTS + + + + extern AutoPtr<Mesh> mesh; + extern STLGeometry * stlgeometry; + VisualSceneMesh vsmesh; + + + + VisualSceneMesh :: VisualSceneMesh () + : VisualScene() + { + filledlist = 0; + linelist = 0; + badellist = 0; + tetlist = 0; + prismlist = 0; + hexlist = 0; + pyramidlist = 0; + identifiedlist = 0; + pointnumberlist = 0; + domainsurflist = 0; + + vstimestamp = GetTimeStamp(); + selecttimestamp = GetTimeStamp(); + filledtimestamp = GetTimeStamp(); + linetimestamp = GetTimeStamp(); + pointnumbertimestamp = GetTimeStamp(); + + tettimestamp = GetTimeStamp(); + prismtimestamp = GetTimeStamp(); + hextimestamp = GetTimeStamp(); + pyramidtimestamp = GetTimeStamp(); + + badeltimestamp = GetTimeStamp(); + identifiedtimestamp = GetTimeStamp(); + domainsurftimestamp = GetTimeStamp(); + + + selface = -1; + selelement = -1; + locpi = 1; + selpoint = -1; + selpoint2 = -1; + seledge = -1; + } + + VisualSceneMesh :: ~VisualSceneMesh () + { + ; + } + + + // ARRAY<Point3d> drawel; + + void VisualSceneMesh :: DrawScene () + { + if (!mesh) + { + VisualScene::DrawScene(); + return; + } + + lock = NULL; + + BuildScene(); + + glClearColor(backcolor, backcolor, backcolor, 1.0); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + glEnable (GL_COLOR_MATERIAL); + glColor3f (1.0f, 1.0f, 1.0f); + glLineWidth (1.0f); + + SetLight(); + + glPushMatrix(); + glMultMatrixf (transformationmat); + + GLdouble projmat[16]; + glGetDoublev (GL_PROJECTION_MATRIX, projmat); + + + glInitNames (); + glPushName (0); + + // glEnable (GL_LINE_SMOOTH); + // glEnable (GL_BLEND); + // glEnable (GL_POLYGON_SMOOTH); + // glDisable (GL_DEPTH_TEST); + // glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + // glHint (GL_LINE_SMOOTH_HINT, GL_DONT_CARE); + + glDisable (GL_COLOR_MATERIAL); + + GLfloat matcol0[] = { 0, 0, 0, 1 }; + GLfloat matcol1[] = { 1, 1, 1, 1 }; + GLfloat matcolf[] = { 0, 1, 0, 1 }; + GLfloat matcolb[] = { 0.5, 0, 0, 1 }; + GLfloat matcolblue[] = { 0, 0, 1, 1 }; + + glMatrixMode (GL_MODELVIEW); + + glMaterialfv(GL_FRONT, GL_EMISSION, matcol0); + glMaterialfv(GL_BACK, GL_EMISSION, matcol0); + glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, matcol1); + glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, matcolf); + glMaterialfv(GL_BACK, GL_AMBIENT_AND_DIFFUSE, matcolb); + + glPolygonMode (GL_FRONT_AND_BACK, GL_FILL); + + // glPolygonOffset (1,10); + glPolygonOffset (2,2); + glEnable (GL_POLYGON_OFFSET_FILL); + + SetClippingPlane (); + + if (vispar.drawfilledtrigs) + { + if (filledtimestamp < mesh->GetTimeStamp () || + filledtimestamp < selecttimestamp) + { + BuildFilledList (); + } + glCallList (filledlist); + } + + if (vispar.drawbadels) + glCallList (badellist); + + if (vispar.drawprisms) + { + BuildPrismList (); + static float prismcol[] = { 1.0f, 1.0f, 0.0f, 1.0f }; + glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, prismcol); + glLineWidth (1.0f); + glCallList (prismlist); + } + + if (vispar.drawpyramids) + { + BuildPyramidList (); + static float pyramidcol[] = { 1.0f, 1.0f, 0.0f, 1.0f }; + glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, pyramidcol); + glLineWidth (1.0f); + glCallList (pyramidlist); + } + + if (vispar.drawhexes) + { + BuildHexList (); + static float hexcol[] = { 1.0f, 0.0f, 0.0f, 1.0f }; + glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, hexcol); + glLineWidth (1.0f); + glCallList (hexlist); + } + + if (vispar.drawtets) + { + BuildTetList (); + static float tetcol[] = { 1.0f, 1.0f, 0.0f, 1.0f }; + glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, tetcol); + glLineWidth (1.0f); + glCallList (tetlist); + } + + if (vispar.drawdomainsurf) + { + BuildDomainSurfList(); + glCallList (domainsurflist); + } + + glDisable (GL_POLYGON_OFFSET_FILL); + + // draw lines + + glMatrixMode (GL_MODELVIEW); + + glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, matcol0); + glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, matcol0); + glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, matcol0); + + glPolygonMode (GL_FRONT_AND_BACK, GL_LINE); + glLineWidth (1.0f); + glColor3f (0.0f, 0.0f, 0.0f); + glDisable (GL_LINE_SMOOTH); + + if (vispar.drawoutline) + { + glPolygonOffset (1, 1); + glEnable (GL_POLYGON_OFFSET_LINE); + + if (linetimestamp < mesh->GetTimeStamp ()) + BuildLineList (); + + glCallList (linelist); + glDisable (GL_POLYGON_OFFSET_LINE); + } + + if (vispar.drawidentified) + { + glPolygonOffset (1, -1); + glEnable (GL_POLYGON_OFFSET_LINE); + glCallList (identifiedlist); + glDisable (GL_POLYGON_OFFSET_LINE); + } + + if (vispar.drawpointnumbers || + vispar.drawedgenumbers || + vispar.drawfacenumbers || + vispar.drawelementnumbers) + glCallList (pointnumberlist); + + + glPopName(); + + if (vispar.drawedges) + { + GLfloat matcoledge[] = { 0, 0, 1, 1 }; + GLfloat matcolsingedge[] = { 1, 0, 1, 1 }; + + glEnable (GL_POLYGON_OFFSET_LINE); + glPolygonOffset (1, -1); + glLineWidth (2); + + + for (int i = 1; i <= mesh->GetNSeg(); i++) + { + const Segment & seg = mesh->LineSegment(i); + const Point3d & p1 = (*mesh)[seg.p1]; + const Point3d & p2 = (*mesh)[seg.p2]; + + if (seg.singedge_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.edgenr == seledge) + glLineWidth(5); + else + glLineWidth(2); + + if (mesh->GetCurvedElements().IsHighOrder()) { + + int j; + int hoplotn = 1 << vispar.subdivisions; + // mesh->GetCurvedElements().GetNVisualSubsecs(); + + Point<3> x; + glBegin (GL_LINE_STRIP); + + for (int j = 0; j <= hoplotn; j++) + { + mesh->GetCurvedElements().CalcSegmentTransformation ((double) j/hoplotn, i-1, x); + glVertex3d (x(0), x(1), x(2)); + } + + glEnd(); + + } else { + + glBegin (GL_LINES); + glVertex3f (p1.X(), p1.Y(), p1.Z()); + glVertex3f (p2.X(), p2.Y(), p2.Z()); + glEnd(); + + } + } + + glLineWidth (2); + glDisable (GL_POLYGON_OFFSET_LINE); + } + + + if (selpoint > 0 && selpoint <= mesh->GetNP()) + { + glPointSize (10); + glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, matcolblue); + glBegin (GL_POINTS); + + const Point3d p = mesh->Point(selpoint); + glVertex3f (p.X(), p.Y(), p.Z()); + glEnd(); + } + + + glDisable(GL_CLIP_PLANE0); + + glPopMatrix(); + + if (vispar.colormeshsize) + DrawColorBar (minh, maxh, 1); + + DrawCoordinateCross (); + DrawNetgenLogo (); + + if (lock) + { + lock -> UnLock(); + delete lock; + } + + glFinish(); + } + + + void VisualSceneMesh :: BuildScene (int zoomall) + { + if (!mesh) + { + VisualScene::BuildScene (zoomall); + return; + } + + int i, j; + + + Point3d pmin, pmax; + static double oldrad = 0; + + ARRAY<Element2d> faces; + + int meshtimestamp = mesh->GetTimeStamp(); + if (meshtimestamp > vstimestamp || zoomall) + { + mesh->GetBox (pmin, pmax, SURFACEPOINT); + + + if (selpoint >= 1 && zoomall == 2) + center = mesh->Point (selpoint); + else if (vispar.use_center_coords && zoomall == 2) + { + center.X() = vispar.centerx; center.Y() = vispar.centery; center.Z() = vispar.centerz; + } + else if (vispar.centerpoint >= 1 && zoomall == 2) + center = mesh->Point (vispar.centerpoint); + else + center = Center (pmin, pmax); + + rad = 0.5 * Dist (pmin, pmax); + + + if (rad > 1.5 * oldrad || + mesh->GetMajorTimeStamp() > vstimestamp || + zoomall) + { + CalcTransformationMatrices(); + oldrad = rad; + } + } + + glEnable (GL_NORMALIZE); + + if (pointnumberlist) + { + glDeleteLists (pointnumberlist, 1); + pointnumberlist = 0; + } + + if (badellist) + { + glDeleteLists (badellist, 1); + badellist = 0; + } + /* + if (prismlist) + { + glDeleteLists (prismlist, 1); + prismlist = 0; + } + + if (pyramidlist) + { + glDeleteLists (pyramidlist, 1); + pyramidlist = 0; + } + + if (hexlist) + { + glDeleteLists (hexlist, 1); + hexlist = 0; + } + */ + if (identifiedlist) + { + glDeleteLists (identifiedlist, 1); + identifiedlist = 0; + } + + + pointnumberlist = glGenLists (1); + glNewList (pointnumberlist, GL_COMPILE); + + if (vispar.drawpointnumbers || + vispar.drawedgenumbers || + vispar.drawfacenumbers || + vispar.drawelementnumbers) + { + glEnable (GL_COLOR_MATERIAL); + GLfloat textcol[3] = { 1 - backcolor, + 1 - backcolor, + 1 - backcolor }; + glColor3fv (textcol); + glNormal3d (0, 0, 1); + glPushAttrib (GL_LIST_BIT); + glListBase (fontbase); + + char buf[30]; + + if (vispar.drawpointnumbers) + for (i = 1; i <= mesh->GetNP(); i++) + { + const Point3d & p = mesh->Point(i); + glRasterPos3d (p.X(), p.Y(), p.Z()); + + sprintf (buf, "%d", i); + + glCallLists (strlen (buf), GL_UNSIGNED_BYTE, buf); + } + + if (vispar.drawedgenumbers) + { + const MeshTopology & top = mesh->GetTopology(); + for (i = 1; i <= top.GetNEdges(); i++) + { + int v1, v2; + top.GetEdgeVertices (i, v1, v2); + const Point3d & p1 = mesh->Point(v1); + const Point3d & p2 = mesh->Point(v2); + const Point3d p = Center (p1, p2); + glRasterPos3d (p.X(), p.Y(), p.Z()); + + sprintf (buf, "%d", i); + + glCallLists (strlen (buf), GL_UNSIGNED_BYTE, buf); + } + } + + + if (vispar.drawfacenumbers) + { + const MeshTopology & top = mesh->GetTopology(); + ARRAY<int> v; + for (i = 1; i <= top.GetNFaces(); i++) + { + top.GetFaceVertices (i, v); + const Point3d & p1 = mesh->Point(v.Elem(1)); + const Point3d & p2 = mesh->Point(v.Elem(2)); + const Point3d & p3 = mesh->Point(v.Elem(3)); + Point3d p; + if (v.Elem(4) == 0) + { + p = Center (p1, p2, p3); + } + else + { + const Point3d & p4 = mesh->Point(v.Elem(4)); + Point3d hp1 = Center (p1, p2); + Point3d hp2 = Center (p3, p4); + p = Center (hp1, hp2); + } + + glRasterPos3d (p.X(), p.Y(), p.Z()); + sprintf (buf, "%d", i); + glCallLists (strlen (buf), GL_UNSIGNED_BYTE, buf); + } + } + + + glPopAttrib (); + glDisable (GL_COLOR_MATERIAL); + } + glEndList (); + + + + + + + + + + + + + + badellist = glGenLists (1); + glNewList (badellist, GL_COMPILE); + + if (vispar.drawbadels) + { + // SetClippingPlane (); + + static float badelcol[] = { 1.0f, 0.0f, 1.0f, 1.0f }; + glLineWidth (1.0f); + + for (i = 1; i <= mesh->GetNE(); i++) + { + if (mesh->VolumeElement(i).flags.badel || + mesh->VolumeElement(i).flags.illegal || + (i == vispar.drawelement)) + { + // copy to be thread-safe + Element el = mesh->VolumeElement (i); + el.GetSurfaceTriangles (faces); + + glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, badelcol); + + + // if ( (el.GetNP() == 4) || (el.GetNP() == 10)) + if (el.PNum(1)) + { + glBegin (GL_TRIANGLES); + + for (j = 1; j <= faces.Size(); j++) + { + Element2d & face = faces.Elem(j); + const Point3d & lp1 = mesh->Point (el.PNum(face.PNum(1))); + const Point3d & lp2 = mesh->Point (el.PNum(face.PNum(2))); + const Point3d & lp3 = mesh->Point (el.PNum(face.PNum(3))); + Vec3d n = Cross (Vec3d (lp1, lp2), Vec3d (lp1, lp3)); + n /= (n.Length()+1e-12); + glNormal3d (n.X(), n.Y(), n.Z()); + glVertex3d (lp1.X(), lp1.Y(), lp1.Z()); + glVertex3d (lp2.X(), lp2.Y(), lp2.Z()); + glVertex3d (lp3.X(), lp3.Y(), lp3.Z()); + } + + glEnd(); + } + } + } + + + + for (i = 1; i <= mesh->GetNE(); i++) + { + if (mesh->VolumeElement(i).flags.badel) + { + // copy to be thread-safe + Element el = mesh->VolumeElement (i); + if ( (el.GetNP() == 4) || (el.GetNP() == 10)) + { + glBegin (GL_LINES); + glVertex3d (0,0,0); + const Point3d & p = mesh->Point(el.PNum(1)); + glVertex3d (p.X(), p.Y(), p.Z()); + glEnd(); + } + } + } + + + for (i = 1; i <= mesh->GetNE(); i++) + { + Element el = mesh->VolumeElement (i); + int hascp = 0; + for (j = 1; j <= el.GetNP(); j++) + if (el.PNum(j) == vispar.centerpoint) + hascp = 1; + + if (hascp) + { + (*testout) << "draw el " << i << " : "; + for (j = 1; j <= el.GetNP(); j++) + (*testout) << el.PNum(j) << " "; + (*testout) << endl; + + if (el.GetNP() == 4) + { + int et[6][2] = + { { 1, 2 }, + { 1, 3 }, + { 1, 4 }, + { 2, 3 }, + { 2, 4 }, + { 3, 4 } } ; + + for (j = 0; j < 6; j++) + { + glBegin (GL_LINES); + const Point3d & p1 = mesh->Point (el.PNum(et[j][0])); + const Point3d & p2 = mesh->Point (el.PNum(et[j][1])); + glVertex3d (p1.X(), p1.Y(), p1.Z()); + glVertex3d (p2.X(), p2.Y(), p2.Z()); + glEnd (); + } + } + + + if (el.GetNP() == 10) + { + int et[12][2] = + { { 1, 5 }, + { 2, 5 }, + { 1, 6 }, + { 3, 6 }, + { 1, 7 }, + { 4, 7 }, + { 2, 8 }, + { 3, 8 }, + { 2, 9 }, + { 4, 9 }, + { 3, 10 }, + { 4, 10 } }; + + for (j = 0; j < 12; j++) + { + glBegin (GL_LINES); + const Point3d & p1 = mesh->Point (el.PNum(et[j][0])); + const Point3d & p2 = mesh->Point (el.PNum(et[j][1])); + glVertex3d (p1.X(), p1.Y(), p1.Z()); + glVertex3d (p2.X(), p2.Y(), p2.Z()); + glEnd (); + } + } + } + } + + + for (i = 1; i <= mesh->GetNSE(); i++) + { + Element2d el = mesh->SurfaceElement(i); + if (!el.BadElement()) + continue; + + int drawel = 1; + for (j = 1; j <= el.GetNP(); j++) + if (!el.PNum(j)) + drawel = 0; + + if (!drawel) + continue; + + cout << int (el.GetType()) << " " << flush; + switch (el.GetType()) + { + case TRIG: + { + glBegin (GL_TRIANGLES); + + Point3d & lp1 = mesh->Point (el.PNum(1)); + Point3d & lp2 = mesh->Point (el.PNum(2)); + Point3d & lp3 = mesh->Point (el.PNum(3)); + Vec3d n = Cross (Vec3d (lp1, lp2), Vec3d (lp1, lp3)); + n /= (n.Length() + 1e-12); + glNormal3dv (&n.X()); + glVertex3dv (&lp1.X()); + glVertex3dv (&lp2.X()); + glVertex3dv (&lp3.X()); + glEnd(); + break; + } + case QUAD: + { + glBegin (GL_QUADS); + + const Point3d & lp1 = mesh->Point (el.PNum(1)); + const Point3d & lp2 = mesh->Point (el.PNum(2)); + const Point3d & lp3 = mesh->Point (el.PNum(4)); + const Point3d & lp4 = mesh->Point (el.PNum(3)); + Vec3d n = Cross (Vec3d (lp1, lp2), + Vec3d (lp1, Center (lp3, lp4))); + n /= (n.Length() + 1e-12); + glNormal3d (n.X(), n.Y(), n.Z()); + glVertex3d (lp1.X(), lp1.Y(), lp1.Z()); + glVertex3d (lp2.X(), lp2.Y(), lp2.Z()); + glVertex3d (lp4.X(), lp4.Y(), lp4.Z()); + glVertex3d (lp3.X(), lp3.Y(), lp3.Z()); + glEnd(); + break; + } + case TRIG6: + { + int lines[6][2] = { + { 1, 6 }, { 2, 6 }, + { 1, 5 }, { 3, 5 }, + { 2, 4 }, { 3, 4 } }; + + glBegin (GL_LINES); + for (j = 0; j < 6; j++) + { + glVertex3dv (&mesh->Point (el.PNum(lines[j][0])).X()); + glVertex3dv (&mesh->Point (el.PNum(lines[j][0])).X()); + } + glEnd(); + break; + } + + case QUAD6: + { + int lines[6][2] = { + { 1, 5 }, { 2, 5 }, + { 3, 6 }, { 4, 6 }, + { 1, 4 }, { 2, 3 } }; + + glBegin (GL_LINES); + + for (j = 0; j < 6; j++) + { + const Point3d & lp1 = mesh->Point (el.PNum(lines[j][0])); + const Point3d & lp2 = mesh->Point (el.PNum(lines[j][1])); + + glVertex3d (lp1.X(), lp1.Y(), lp1.Z()); + glVertex3d (lp2.X(), lp2.Y(), lp2.Z()); + } + glEnd (); + break; + } + default: + PrintSysError ("Cannot draw surface element of type ", + int(el.GetType())); + } + } + glLoadName (0); + + } + glEndList (); + + + + + + if (1) + { + + identifiedlist = glGenLists (1); + glNewList (identifiedlist, GL_COMPILE); + + GLfloat identifiedcol[] = { 1, 0, 1, 1 }; + + glLineWidth (3); + + + // for (i = 1; i <= mesh->GetNSeg(); i++) + INDEX_2_HASHTABLE<int> & idpts = + mesh->GetIdentifications().GetIdentifiedPoints(); + if (&idpts) + for (i = 1; i <= idpts.GetNBags(); i++) + for (j = 1; j <= idpts.GetBagSize(i); j++) + { + INDEX_2 pts; + int val; + + idpts.GetData (i, j, pts, val); + const Point3d & p1 = mesh->Point(pts.I1()); + const Point3d & p2 = mesh->Point(pts.I2()); + + glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, + identifiedcol); + + glBegin (GL_LINES); + glVertex3f (p1.X(), p1.Y(), p1.Z()); + glVertex3f (p2.X(), p2.Y(), p2.Z()); + glEnd(); + } + + glEndList (); + } + + vstimestamp = meshtimestamp; + } + + + + + void VisualSceneMesh :: BuildFilledList() + { + // clock_t starttime, endtime; + // starttime = clock(); + + if (!lock) + { + lock = new NgLock (mesh->Mutex()); + lock -> Lock(); + } + + filledtimestamp = NextTimeStamp(); + + if (filledlist) + glDeleteLists (filledlist, 1); + + filledlist = glGenLists (1); + glNewList (filledlist, GL_COMPILE); + + + bool checkvicinity = (stlgeometry != NULL) && stldoctor.showvicinity; + + glEnable (GL_NORMALIZE); + + glLineWidth (1.0f); + + Vector locms; + + if (vispar.colormeshsize) + { + glEnable (GL_COLOR_MATERIAL); + locms.SetSize (mesh->GetNP()); + double maxh = -1; + double minh = 1e99; + for (int i = 1; i <= locms.Size(); i++) + { + Point3d p = mesh->Point(i); + locms.Elem(i) = mesh->GetH (p); + if (locms.Elem(i) > maxh) maxh = locms.Elem(i); + if (locms.Elem(i) < minh) minh = locms.Elem(i); + } + if (!locms.Size()) + { minh = 1; maxh = 10; } + } + else + glDisable (GL_COLOR_MATERIAL); + + + GLfloat matcol[] = { 0, 1, 0, 1 }; + GLfloat matcolsel[] = { 1, 0, 0, 1 }; + + CurvedElements & curv = mesh->GetCurvedElements(); + int hoplotn = 1 << vispar.subdivisions; + + + for (int col = 1; col <= 2; col++) + { + if (col == 2) + glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, matcolsel); + else + glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, matcol); + + + for (SurfaceElementIndex sei = 0; sei < mesh->GetNSE(); sei++) + { + const Element2d & el = (*mesh)[sei]; + + bool drawel = !el.IsDeleted(); + + if (checkvicinity) + for (int j = 0; j < el.GetNP(); j++) + if (!stlgeometry->Vicinity(el.GeomInfoPi(j+1).trignum)) + drawel = 0; + + if (!drawel) + continue; + + if (vispar.colormeshsize && col == 2) + continue; + if (!vispar.colormeshsize && + (col == 2) != (el.GetIndex() == selface)) + continue; + + glLoadName (sei+1); + + switch (el.GetType()) + { + case TRIG: + { + if (curv.IsHighOrder() && curv.IsSurfaceElementCurved(sei)) + { + Point<2> xr[3]; + Point<3> xg; + Vec<3> dx, dy, n; + + glBegin (GL_TRIANGLES); + + for (int i = 0; i < hoplotn; i++) + for (int j = 0; j < hoplotn-i; j++) + for (int k = 0; k < 2; k++) + { + if (k == 0) + { + xr[0](0) = (double) i/hoplotn; xr[0](1) = (double) j/hoplotn; + xr[1](0) = (double)(i+1)/hoplotn; xr[1](1) = (double) j/hoplotn; + xr[2](0) = (double) i/hoplotn; xr[2](1) = (double)(j+1)/hoplotn; + } + else + { + if (j == hoplotn-i-1) continue; + xr[0](0) = (double)(i+1)/hoplotn; xr[0](1) = (double) j/hoplotn; + xr[1](0) = (double)(i+1)/hoplotn; xr[1](1) = (double)(j+1)/hoplotn; + xr[2](0) = (double) i/hoplotn; xr[2](1) = (double)(j+1)/hoplotn; + }; + + for (int l=0; l<3; l++) + { + Mat<3,2> dxdxi; + + curv.CalcSurfaceTransformation (xr[l], sei, xg, dxdxi); + for (int i = 0; i < 3; i++) + { + dx(i) = dxdxi(i,0); + dy(i) = dxdxi(i,1); + } + n = Cross (dx, dy); + n.Normalize(); + glNormal3d (n(0), n(1), n(2)); + glVertex3d (xg(0), xg(1), xg(2)); + } + } + + glEnd(); + } + else // not high order + { + glBegin (GL_TRIANGLES); + + 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); + glNormal3dv (n); + + if (vispar.colormeshsize) + { + SetOpenGlColor (locms.Get(el[0]), minh, maxh, 1); + glVertex3dv (lp0); + SetOpenGlColor (locms.Get(el[1]), minh, maxh, 1); + glVertex3dv (lp1); + SetOpenGlColor (locms.Get(el[2]), minh, maxh, 1); + glVertex3dv (lp2); + } + else + { + glVertex3dv (lp0); + glVertex3dv (lp1); + glVertex3dv (lp2); + } + + glEnd(); + } + + break; + } + case QUAD: + { + // cout << "BuildFilledList: QUAD" << endl; + // CurvedElements & curv = mesh->GetCurvedElements(); + 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); + 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++) + { + Point3d & lp1 = mesh->Point (el.PNum(trigs[j][0])); + Point3d & lp2 = mesh->Point (el.PNum(trigs[j][1])); + Point3d & lp3 = mesh->Point (el.PNum(trigs[j][2])); + Vec3d n = Cross (Vec3d (lp1, lp2), Vec3d (lp1, lp3)); + glNormal3dv (&n.X()); + + glVertex3dv (&lp1.X()); + glVertex3dv (&lp2.X()); + glVertex3dv (&lp3.X()); + } + glEnd(); + break; + } + + case QUAD6: + { + glBegin (GL_QUADS); + static int quads[2][4] = { + { 1, 5, 6, 4 }, + { 5, 2, 3, 6 } }; + + for (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++) + { + 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++) + { + Point3d & hp = mesh->Point (el[j]); + c.X() += 0.5 * hp.X(); + c.Y() += 0.5 * hp.Y(); + c.Z() += 0.5 * hp.Z(); + } + + for (int j = 0; j < 8; j++) + { + Point3d & lp1 = mesh->Point (el.PNum(boundary[j])); + Point3d & lp2 = mesh->Point (el.PNum(boundary[j+1])); + + Vec3d n = Cross (Vec3d (c, lp1), Vec3d (c, lp2)); + n /= (n.Length() + 1e-12); + glNormal3dv (&n.X()); + glVertex3dv (&lp1.X()); + glVertex3dv (&lp2.X()); + glVertex3dv (&c.X()); + } + glEnd(); + break; + } + + + default: + PrintSysError ("Cannot draw (2) surface element of type ", + int(el.GetType())); + } + } + } + glLoadName (0); + glEndList (); + + // endtime = clock(); + // cout << "BuildFillList time = " << double(endtime - starttime)/CLOCKS_PER_SEC << endl; + } + + + void VisualSceneMesh :: BuildLineList() + { + SurfaceElementIndex sei; + + if (!lock) + { + lock = new NgLock (mesh->Mutex()); + lock -> Lock(); + } + + linetimestamp = NextTimeStamp(); + + + bool checkvicinity = (stlgeometry != NULL) && stldoctor.showvicinity; + + if (linelist) + glDeleteLists (linelist, 1); + + linelist = glGenLists (1); + glNewList (linelist, GL_COMPILE); + + + glLineWidth (1.0f); + + int hoplotn = 1 << vispar.subdivisions; + + for (sei = 0; sei < mesh->GetNSE(); sei++) + { + const Element2d & el = (*mesh)[sei]; + + bool drawel = !el.IsDeleted(); + if (checkvicinity) + for (int j = 0; j < el.GetNP(); j++) + if (!stlgeometry->Vicinity(el.GeomInfoPi(j+1).trignum)) + drawel = 0; + + if (!drawel) + continue; + + switch (el.GetType()) + { + case TRIG: + { + CurvedElements & curv = mesh->GetCurvedElements(); + if (curv.IsHighOrder() && curv.IsSurfaceElementCurved(sei)) + { + 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); + + 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 (); + } + + void VisualSceneMesh :: BuildPointNumberList() + { + ; + } + + + + + + + inline long int Fact (int n) + { + long int res = 1; + for (int i = 2; i <= n; i++) + res *= i; + return res; + } + inline int Binom (int n, int i) + { + return Fact(n) / Fact(i) / Fact(n-i); + } + + 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) = Binom (order, j) * pow (x, j) * pow (1-x, order-j); + } + + 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() + { + + +#ifdef FAST3DELEMENTS + + + cout << "start fast test" << endl; + + int i, j; + ARRAY<Element2d> faces; + + if (tettimestamp > mesh->GetTimeStamp () && + tettimestamp > vispar.clipplanetimestamp ) + return; + + if (!lock) + { + lock = new NgLock (mesh->Mutex()); + lock -> Lock(); + } + + tettimestamp = NextTimeStamp(); + + if (tetlist) + glDeleteLists (tetlist, 1); + + + tetlist = glGenLists (1); + glNewList (tetlist, GL_COMPILE); + + + BitArray shownode(mesh->GetNP()); + if (vispar.clipenable) + { + shownode.Clear(); + for (i = 1; i <= shownode.Size(); i++) + { + Point3d p = mesh->Point(i); + + double val = + p.X() * clipplane[0] + + p.Y() * clipplane[1] + + p.Z() * clipplane[2] + + clipplane[3]; + + if (val > 0) + shownode.Set (i); + } + } + else + shownode.Set(); + + + static float tetcols[][4] = + { + { 1.0f, 1.0f, 0.0f, 1.0f }, + { 1.0f, 0.0f, 0.0f, 1.0f }, + { 0.0f, 1.0f, 0.0f, 1.0f }, + { 0.0f, 0.0f, 1.0f, 1.0f } + }; + + + ARRAY<int> elfaces; + + const MeshTopology & top = mesh->GetTopology(); + CurvedElements & curv = mesh->GetCurvedElements(); + + ARRAY<int> displayface(top.GetNFaces()); + for (i = 0; i < top.GetNFaces(); i++) + displayface[i] = -1; + + + for (i = 1; i <= mesh->GetNE(); i++) + { + if (vispar.drawtetsdomain > 0 && + vispar.drawtetsdomain != mesh->VolumeElement(i).GetIndex()) + continue; + + Element el = (*mesh)[(ElementIndex) (i-1)]; + + if (el.GetType() == TET) + { + if (el.PNum(1)) + { + bool drawtet = 1; + for (j = 1; j <= el.GetNP(); j++) + if (!shownode.Test(el.PNum(j))) + drawtet = 0; + if (!drawtet) continue; + + { + top.GetElementFaces (i, elfaces); + + for (j = 0; j < 4; j++) + displayface[elfaces[j]-1] *= -1; + } + } + } + } + + + for (i = 1; i <= mesh->GetNE(); i++) + { + if (vispar.drawtetsdomain > 0 && + vispar.drawtetsdomain != mesh->VolumeElement(i).GetIndex()) + continue; + + if (mesh->VolumeElement(i).GetType() == TET) + { + // copy to be thread-safe + Element el = mesh->VolumeElement (i); + el.GetSurfaceTriangles (faces); + + if (el.PNum(1)) + { + bool drawtet = 1; + for (j = 1; j <= el.GetNP(); j++) + if (!shownode.Test(el.PNum(j))) + drawtet = 0; + if (!drawtet) continue; + + int ind = el.GetIndex() % 4; + if (vispar.drawmetispartition && (el.GetPartition()!=-1)) + ind = el.GetPartition() % 4; + (*testout) << "ind = " << ind << endl; + glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, tetcols[ind]); + + + top.GetElementFaces (i, elfaces); + + glBegin (GL_TRIANGLES); + + for (j = 0; j < faces.Size(); j++) + { + if (displayface[elfaces[j]-1] == -1) continue; + + Element2d & face = faces.Elem(j+1); + + if (curv.IsHighOrder() && curv.IsElementCurved(i-1)) + { + int hoplotn = 1 << vispar.subdivisions; + // int hoplotn = curv.GetNVisualSubsecs(); + + const Point3d * facepoint = MeshTopology :: GetVertices (TET); + const ELEMENT_FACE * elface = MeshTopology :: GetFaces(TET); + + Vec<3> x0,x1,d0,d1; + Point<3> xg; + x0 = facepoint[face.PNum(3)-1] - facepoint[face.PNum(1)-1]; + x1 = facepoint[face.PNum(2)-1] - facepoint[face.PNum(1)-1]; + x0.Normalize(); + x1.Normalize(); + + for (int m0 = 0; m0 < hoplotn; m0++) + for (int m1 = 0; m1 < hoplotn-m0; m1++) + for (int k = 0; k < 2; k++) + { + Vec<3> dx, dy, dz, n; + Point<4> la[3]; + int l; + for (l = 0; l<3; l++) la[l] = Point<4>(0.,0.,0.,0.); + + if (k == 0) + { + la[0](face.PNum(1)-1) = (m0 )/(double)hoplotn; + la[0](face.PNum(2)-1) = (m1 )/(double)hoplotn; + la[0](face.PNum(3)-1) = 1-la[0](face.PNum(1)-1)-la[0](face.PNum(2)-1); + + la[1](face.PNum(1)-1) = (m0+1)/(double)hoplotn; + la[1](face.PNum(2)-1) = (m1 )/(double)hoplotn; + la[1](face.PNum(3)-1) = 1-la[1](face.PNum(1)-1)-la[1](face.PNum(2)-1); + + la[2](face.PNum(1)-1) = (m0 )/(double)hoplotn; + la[2](face.PNum(2)-1) = (m1+1)/(double)hoplotn; + la[2](face.PNum(3)-1) = 1-la[2](face.PNum(1)-1)-la[2](face.PNum(2)-1); + } else + { + if (m1 == hoplotn-m0-1) continue; + la[0](face.PNum(1)-1) = (m0+1)/(double)hoplotn; + la[0](face.PNum(2)-1) = (m1+1)/(double)hoplotn; + la[0](face.PNum(3)-1) = 1-la[0](face.PNum(1)-1)-la[0](face.PNum(2)-1); + + la[1](face.PNum(1)-1) = (m0 )/(double)hoplotn; + la[1](face.PNum(2)-1) = (m1+1)/(double)hoplotn; + la[1](face.PNum(3)-1) = 1-la[1](face.PNum(1)-1)-la[1](face.PNum(2)-1); + + la[2](face.PNum(1)-1) = (m0+1)/(double)hoplotn; + la[2](face.PNum(2)-1) = (m1 )/(double)hoplotn; + la[2](face.PNum(3)-1) = 1-la[2](face.PNum(1)-1)-la[2](face.PNum(2)-1); + } + + for (l = 0; l<3; l++) + { + Mat<3,3> dxdxi; + Point<3> xr( la[l](0), la[l](1), la[l](2) ); + curv.CalcElementTransformation (xr, i-1, xg, dxdxi); + for (int i = 0; i < 3; i++) + { + dx(i) = dxdxi(i,0); + dy(i) = dxdxi(i,1); + dz(i) = dxdxi(i,2); + } + + d0 = x0(0)*dx + x0(1)*dy + x0(2)*dz; + d1 = x1(0)*dx + x1(1)*dy + x1(2)*dz; + n = Cross (d0, d1); + glNormal3d ( n(0), n(1), n(2)); + glVertex3d (xg(0), xg(1), xg(2)); + } + } + + } else { + const Point3d & lp1 = mesh->Point (el.PNum(face.PNum(1))); + const Point3d & lp2 = mesh->Point (el.PNum(face.PNum(2))); + const Point3d & lp3 = mesh->Point (el.PNum(face.PNum(3))); + Vec3d n = Cross (Vec3d (lp1, lp3), Vec3d (lp1, lp2)); + n /= (n.Length()+1e-12); + glNormal3d (n.X(), n.Y(), n.Z()); + glVertex3d (lp1.X(), lp1.Y(), lp1.Z()); + glVertex3d (lp2.X(), lp2.Y(), lp2.Z()); + glVertex3d (lp3.X(), lp3.Y(), lp3.Z()); + } + } + + glEnd(); + } + + } + } + glEndList (); + + + + +#else + + if (tettimestamp > mesh->GetTimeStamp () && + tettimestamp > vispar.clipplanetimestamp ) + return; + + if (!lock) + { + lock = new NgLock (mesh->Mutex()); + lock -> Lock(); + } + + tettimestamp = NextTimeStamp(); + + if (tetlist) + glDeleteLists (tetlist, 1); + + + tetlist = glGenLists (1); + glNewList (tetlist, GL_COMPILE); + + + + int i, j, k, l; + ARRAY<Element2d> faces; + + + BitArray shownode(mesh->GetNP()); + if (vispar.clipenable) + { + shownode.Clear(); + for (i = 1; i <= shownode.Size(); i++) + { + Point3d p = mesh->Point(i); + + double val = + p.X() * clipplane[0] + + p.Y() * clipplane[1] + + p.Z() * clipplane[2] + + clipplane[3]; + + if (val > 0) + shownode.Set (i); + } + } + else + shownode.Set(); + + + static float tetcols[][4] = + { + { 1.0f, 1.0f, 0.0f, 1.0f }, + { 1.0f, 0.0f, 0.0f, 1.0f }, + { 0.0f, 1.0f, 0.0f, 1.0f }, + { 0.0f, 0.0f, 1.0f, 1.0f } + }; + + + CurvedElements & curv = mesh->GetCurvedElements(); + + for (ElementIndex ei = 0; ei < mesh->GetNE(); ei++) + { + i = ei + 1; + + if (vispar.drawtetsdomain > 0 && + vispar.drawtetsdomain != mesh->VolumeElement(i).GetIndex()) + continue; + + const Element & el = (*mesh)[ei]; + + if (el.GetType() == TET && !el.IsDeleted()) + { + + bool drawtet = 1; + for (j = 0; j < 4; j++) + if (!shownode.Test(el[j])) + drawtet = 0; + if (!drawtet) continue; + + + int ind = el.GetIndex() % 4; + if (vispar.drawmetispartition && (el.GetPartition()!=-1)) + ind = el.GetPartition() % 4; + glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, tetcols[ind]); + + + if (curv.IsHighOrder() && curv.IsElementCurved(ei)) + { + const ELEMENT_FACE * faces = MeshTopology :: GetFaces (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); + } + } + + + else + + { + el.GetSurfaceTriangles (faces); + + Point3d c; + if (vispar.shrink < 1) + c = Center (Center (mesh->Point (el.PNum(1)), + mesh->Point (el.PNum(2))), + Center (mesh->Point (el.PNum(3)), + mesh->Point (el.PNum(4)))); + + + glBegin (GL_TRIANGLES); + + for (j = 0; j < faces.Size(); j++) + { + const Element2d & face = faces[j]; + + /* + if (curv.IsHighOrder() && curv.IsElementCurved(i-1)) + { + int hoplotn = 1 << vispar.subdivisions; + // int hoplotn = curv.GetNVisualSubsecs(); + + const Point3d * facepoint = MeshTopology :: GetVertices (TET); + const ELEMENT_FACE * elface = MeshTopology :: GetFaces(TET); + + Vec<3> x0,x1,d0,d1; + Point<3> xg; + x0 = facepoint[face.PNum(3)-1] - facepoint[face.PNum(1)-1]; + x1 = facepoint[face.PNum(2)-1] - facepoint[face.PNum(1)-1]; + x0.Normalize(); + x1.Normalize(); + + for (int m0 = 0; m0 < hoplotn; m0++) + for (int m1 = 0; m1 < hoplotn-m0; m1++) + for (k = 0; k < 2; k++) + { + Vec<3> dx, dy, dz, n; + Point<4> la[3]; + + for (l = 0; l<3; l++) la[l] = Point<4>(0.,0.,0.,0.); + + if (k == 0) + { + la[0](face.PNum(1)-1) = (m0 )/(double)hoplotn; + la[0](face.PNum(2)-1) = (m1 )/(double)hoplotn; + la[0](face.PNum(3)-1) = 1-la[0](face.PNum(1)-1)-la[0](face.PNum(2)-1); + + la[1](face.PNum(1)-1) = (m0+1)/(double)hoplotn; + la[1](face.PNum(2)-1) = (m1 )/(double)hoplotn; + la[1](face.PNum(3)-1) = 1-la[1](face.PNum(1)-1)-la[1](face.PNum(2)-1); + + la[2](face.PNum(1)-1) = (m0 )/(double)hoplotn; + la[2](face.PNum(2)-1) = (m1+1)/(double)hoplotn; + la[2](face.PNum(3)-1) = 1-la[2](face.PNum(1)-1)-la[2](face.PNum(2)-1); + } else + { + if (m1 == hoplotn-m0-1) continue; + la[0](face.PNum(1)-1) = (m0+1)/(double)hoplotn; + la[0](face.PNum(2)-1) = (m1+1)/(double)hoplotn; + la[0](face.PNum(3)-1) = 1-la[0](face.PNum(1)-1)-la[0](face.PNum(2)-1); + + la[1](face.PNum(1)-1) = (m0 )/(double)hoplotn; + la[1](face.PNum(2)-1) = (m1+1)/(double)hoplotn; + la[1](face.PNum(3)-1) = 1-la[1](face.PNum(1)-1)-la[1](face.PNum(2)-1); + + la[2](face.PNum(1)-1) = (m0+1)/(double)hoplotn; + la[2](face.PNum(2)-1) = (m1 )/(double)hoplotn; + la[2](face.PNum(3)-1) = 1-la[2](face.PNum(1)-1)-la[2](face.PNum(2)-1); + } + + for (l = 0; l<3; l++) + { + Mat<3,3> dxdxi; + Point<3> xr( la[l](0), la[l](1), la[l](2) ); + curv.CalcElementTransformation (xr, i-1, xg, dxdxi); + for (int i = 0; i < 3; i++) + { + dx(i) = dxdxi(i,0); + dy(i) = dxdxi(i,1); + dz(i) = dxdxi(i,2); + } + + d0 = x0(0)*dx + x0(1)*dy + x0(2)*dz; + d1 = x1(0)*dx + x1(1)*dy + x1(2)*dz; + n = Cross (d0, d1); + glNormal3d ( n(0), n(1), n(2)); + glVertex3d (xg(0), xg(1), xg(2)); + } + } + + } else + */ + { + Point3d lp1 = mesh->Point (el.PNum(face.PNum(1))); + Point3d lp2 = mesh->Point (el.PNum(face.PNum(2))); + Point3d lp3 = mesh->Point (el.PNum(face.PNum(3))); + Vec3d n = Cross (Vec3d (lp1, lp3), Vec3d (lp1, lp2)); + n /= (n.Length()+1e-12); + glNormal3d (n.X(), n.Y(), n.Z()); + + if (vispar.shrink < 1) + { + lp1 = c + vispar.shrink * (lp1 - c); + lp2 = c + vispar.shrink * (lp2 - c); + lp3 = c + vispar.shrink * (lp3 - c); + } + + glVertex3d (lp1.X(), lp1.Y(), lp1.Z()); + glVertex3d (lp2.X(), lp2.Y(), lp2.Z()); + glVertex3d (lp3.X(), lp3.Y(), lp3.Z()); + } + } + + glEnd(); + } + } + } + + glEndList (); + +#endif + } + + + + + void VisualSceneMesh :: BuildPrismList() + { + if (prismtimestamp > mesh->GetTimeStamp () && + prismtimestamp > vispar.clipplanetimestamp ) + return; + + if (!lock) + { + lock = new NgLock (mesh->Mutex()); + lock -> Lock(); + } + + prismtimestamp = NextTimeStamp(); + + + + if (prismlist) + glDeleteLists (prismlist, 1); + + prismlist = glGenLists (1); + glNewList (prismlist, GL_COMPILE); + + static float prismcol[] = { 0.0f, 1.0f, 1.0f, 1.0f }; + glLineWidth (1.0f); + + ARRAY<Element2d> faces; + + + glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, prismcol); + + for (ElementIndex ei = 0; ei < mesh->GetNE(); ei++) + { + const Element & el = (*mesh)[ei]; + if (el.GetType() == PRISM && !el.IsDeleted()) + { + int j; + int i = ei + 1; + + CurvedElements & curv = mesh->GetCurvedElements(); + if (curv.IsHighOrder() && curv.IsElementCurved(ei)) + { + const ELEMENT_FACE * faces = MeshTopology :: GetFaces (PRISM); + const Point3d * vertices = MeshTopology :: GetVertices (PRISM); + + Point<3> grid[11][11]; + Point<3> fpts[4]; + int order = vispar.subdivisions+1; + + for (int trig = 0; trig < 2; trig++) + { + for (int j = 0; j < 3; j++) + fpts[j] = vertices[faces[trig][j]-1]; + + static Point<3> c(1.0/3.0, 1.0/3.0, 0.5); + if (vispar.shrink < 1) + for (int j = 0; j < 3; j++) + fpts[j] += (1-vispar.shrink) * (c-fpts[j]); + + for (int ix = 0; ix <= order; ix++) + for (int iy = 0; iy <= order; iy++) + { + double lami[3] = + { (1-double(ix)/order) * (1-double(iy)/order), + ( double(ix)/order) * (1-double(iy)/order), + double(iy)/order }; + + Point<3> xl; + for (int l = 0; l < 3; l++) + xl(l) = lami[0] * fpts[0](l) + lami[1] * fpts[1](l) + + lami[2] * fpts[2](l); + + curv.CalcElementTransformation (xl, i-1, grid[ix][iy]); + } + + for (int j = 0; j <= order; j++) + ToBernstein (order, &grid[j][0], &grid[0][1]-&grid[0][0]); + for (int j = 0; j <= order; j++) + ToBernstein (order, &grid[0][j], &grid[1][0]-&grid[0][0]); + + glMap2d(GL_MAP2_VERTEX_3, + 0.0, 1.0, &grid[0][1](0)-&grid[0][0](0), order+1, + 0.0, 1.0, &grid[1][0](0)-&grid[0][0](0), order+1, + &grid[0][0](0)); + glEnable(GL_MAP2_VERTEX_3); + glEnable(GL_AUTO_NORMAL); + + glMapGrid2f(8, 0.0, 0.999, 8, 0.0, 1.0); + glEvalMesh2(GL_FILL, 0, 8, 0, 8); + + glDisable (GL_AUTO_NORMAL); + glDisable (GL_MAP2_VERTEX_3); + } + + for (int quad = 2; quad < 5; quad++) + { + for (int j = 0; j < 4; j++) + fpts[j] = vertices[faces[quad][j]-1]; + + static Point<3> c(1.0/3.0, 1.0/3.0, 0.5); + if (vispar.shrink < 1) + for (int j = 0; j < 4; j++) + fpts[j] += (1-vispar.shrink) * (c-fpts[j]); + + for (int ix = 0; ix <= order; ix++) + for (int iy = 0; iy <= order; iy++) + { + double lami[4] = + { (1-double(ix)/order) * (1-double(iy)/order), + ( double(ix)/order) * (1-double(iy)/order), + ( double(ix)/order) * ( double(iy)/order), + (1-double(ix)/order) * ( double(iy)/order) }; + + Point<3> xl; + for (int l = 0; l < 3; l++) + xl(l) = + lami[0] * fpts[0](l) + lami[1] * fpts[1](l) + + lami[2] * fpts[2](l) + lami[3] * fpts[3](l); + + curv.CalcElementTransformation (xl, ei, grid[ix][iy]); + } + + for (int j = 0; j <= order; j++) + ToBernstein (order, &grid[j][0], &grid[0][1]-&grid[0][0]); + for (int j = 0; j <= order; j++) + ToBernstein (order, &grid[0][j], &grid[1][0]-&grid[0][0]); + + glMap2d(GL_MAP2_VERTEX_3, + 0.0, 1.0, &grid[0][1](0)-&grid[0][0](0), order+1, + 0.0, 1.0, &grid[1][0](0)-&grid[0][0](0), order+1, + &grid[0][0](0)); + glEnable(GL_MAP2_VERTEX_3); + glEnable(GL_AUTO_NORMAL); + + glMapGrid2f(8, 0.0, 1.0, 8, 0.0, 1.0); + glEvalMesh2(GL_FILL, 0, 8, 0, 8); + + glDisable (GL_AUTO_NORMAL); + glDisable (GL_MAP2_VERTEX_3); + } + + + + + + /* + int hoplotn = 1 << vispar.subdivisions; + // int hoplotn = curv.GetNVisualSubsecs(); + + const Point3d * facepoint = MeshTopology :: GetVertices (TRIG); + const ELEMENT_FACE * elface = MeshTopology :: GetFaces(TRIG); + + glBegin (GL_TRIANGLES); + + for (int trig = 0; trig<2; trig++) + { + + Vec<3> x0,x1,d0,d1; + x0 = facepoint[1] - facepoint[2]; + x1 = facepoint[0] - facepoint[2]; + x0.Normalize(); + x1.Normalize(); + if (trig == 1) swap (x0,x1); + + Point<3> xr[3]; + Point<3> xg; + Vec<3> dx, dy, dz, n; + + for (int i1 = 0; i1 < hoplotn; i1++) + for (int j1 = 0; j1 < hoplotn-i1; j1++) + for (int k = 0; k < 2; k++) + { + if (k == 0) + { + xr[0](0) = (double) i1/hoplotn; xr[0](1) = (double) j1/hoplotn; + xr[1](0) = (double)(i1+1)/hoplotn; xr[1](1) = (double) j1/hoplotn; + xr[2](0) = (double) i1/hoplotn; xr[2](1) = (double)(j1+1)/hoplotn; + } else + { + if (j1 == hoplotn-i1-1) continue; + xr[0](0) = (double)(i1+1)/hoplotn; xr[0](1) = (double) j1/hoplotn; + xr[1](0) = (double)(i1+1)/hoplotn; xr[1](1) = (double)(j1+1)/hoplotn; + xr[2](0) = (double) i1/hoplotn; xr[2](1) = (double)(j1+1)/hoplotn; + }; + + for (int l=0; l<3; l++) + { + Mat<3,3> dxdxi; + xr[l](2) = (double) trig; + curv.CalcElementTransformation (xr[l], i-1, xg, dxdxi); + for (int i = 0; i < 3; i++) + { + dx(i) = dxdxi(i,0); + dy(i) = dxdxi(i,1); + dz(i) = dxdxi(i,2); + } + + Vec<3> d0 = x0(0)*dx + x0(1)*dy + x0(2)*dz; + Vec<3> d1 = x1(0)*dx + x1(1)*dy + x1(2)*dz; + n = Cross (d1, d0); + glNormal3d (n(0), n(1), n(2)); + glVertex3d (xg(0), xg(1), xg(2)); + } + } + + } + + glEnd (); + + glBegin (GL_QUADS); + + for (int quad = 0; quad<3; quad++) + { + const Point3d * facepoint = MeshTopology :: GetVertices (PRISM); + + Vec<3> x0,x1; + int xyz; + + switch (quad) + { + case 0: + x0 = facepoint[5] - facepoint[2]; + x1 = facepoint[0] - facepoint[2]; + xyz = 0; + break; + case 1: + x0 = facepoint[4] - facepoint[0]; + x1 = facepoint[1] - facepoint[0]; + xyz = 0; + break; + case 2: + x0 = facepoint[1] - facepoint[2]; + x1 = facepoint[5] - facepoint[2]; + xyz = 1; + break; + } + + x0.Normalize(); + x1.Normalize(); + + swap (x0,x1); + + Point<3> xr[4]; + Point<3> xg; + Vec<3> dx, dy, dz, n; + + for (int i1 = 0; i1 < hoplotn; i1++) + for (int j1 = 0; j1 < hoplotn; j1++) + { + xr[0](xyz) = (double) i1/hoplotn; xr[0](2) = (double) j1/hoplotn; + xr[1](xyz) = (double)(i1+1)/hoplotn; xr[1](2) = (double) j1/hoplotn; + xr[2](xyz) = (double)(i1+1)/hoplotn; xr[2](2) = (double)(j1+1)/hoplotn; + xr[3](xyz) = (double) i1/hoplotn; xr[3](2) = (double)(j1+1)/hoplotn; + + for (int l=0; l<4; l++) + { + switch (quad) + { + case 0: xr[l](1) = 0; break; + case 1: xr[l](1) = 1-xr[l](0); break; + case 2: xr[l](0) = 0; break; + } + + Mat<3,3> dxdxi; + curv.CalcElementTransformation (xr[l], i-1, xg, dxdxi); + for (int i = 0; i < 3; i++) + { + dx(i) = dxdxi(i,0); + dy(i) = dxdxi(i,1); + dz(i) = dxdxi(i,2); + } + + Vec<3> d0 = x0(0)*dx + x0(1)*dy + x0(2)*dz; + Vec<3> d1 = x1(0)*dx + x1(1)*dy + x1(2)*dz; + n = Cross (d1, d0); + glNormal3d (n(0), n(1), n(2)); + glVertex3d (xg(0), xg(1), xg(2)); + } + } + } + glEnd (); + */ + } + else + { + Point3d c(0,0,0); + if (vispar.shrink < 1) + { + for (j = 1; j <= 6; j++) + { + Point3d p = mesh->Point(el.PNum(j)); + c.X() += p.X() / 6; + c.Y() += p.Y() / 6; + c.Z() += p.Z() / 6; + } + } + + el.GetSurfaceTriangles (faces); + glBegin (GL_TRIANGLES); + for (j = 1; j <= faces.Size(); j++) + { + Element2d & face = faces.Elem(j); + Point3d lp1 = mesh->Point (el.PNum(face.PNum(1))); + Point3d lp2 = mesh->Point (el.PNum(face.PNum(2))); + Point3d lp3 = mesh->Point (el.PNum(face.PNum(3))); + Vec3d n = Cross (Vec3d (lp1, lp3), Vec3d (lp1, lp2)); + n /= (n.Length()+1e-12); + glNormal3d (n.X(), n.Y(), n.Z()); + if (vispar.shrink < 1) + { + lp1 = c + vispar.shrink * (lp1 - c); + lp2 = c + vispar.shrink * (lp2 - c); + lp3 = c + vispar.shrink * (lp3 - c); + } + glVertex3d (lp1.X(), lp1.Y(), lp1.Z()); + glVertex3d (lp2.X(), lp2.Y(), lp2.Z()); + glVertex3d (lp3.X(), lp3.Y(), lp3.Z()); + } + + glEnd(); + } + } + } + glEndList (); + } + + + + + void VisualSceneMesh :: BuildHexList() + { + if (hextimestamp > mesh->GetTimeStamp () && + hextimestamp > vispar.clipplanetimestamp ) + return; + + if (!lock) + { + lock = new NgLock (mesh->Mutex()); + lock -> Lock(); + } + + hextimestamp = NextTimeStamp(); + + if (hexlist) glDeleteLists (hexlist, 1); + + hexlist = glGenLists (1); + glNewList (hexlist, GL_COMPILE); + + + static float hexcol[] = { 1.0f, 1.0f, 0.0f, 1.0f }; + glLineWidth (1.0f); + glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, hexcol); + + ARRAY<Element2d> faces; + int hoplotn = 1 << vispar.subdivisions; + + for (ElementIndex ei = 0; ei < mesh->GetNE(); ei++) + { + const Element & el = (*mesh)[ei]; + if (el.GetType() == HEX && !el.IsDeleted()) + { + CurvedElements & curv = mesh->GetCurvedElements(); + if (curv.IsHighOrder() && curv.IsElementCurved(ei)) + { + /* // classical + glBegin (GL_QUADS); + + const ELEMENT_FACE * faces = MeshTopology :: GetFaces (HEX); + const Point3d * vertices = MeshTopology :: GetVertices (HEX); + + Point<3> grid[33][33]; + Vec<3> gridn[33][33]; + Point<3> fpts[4]; + for (int quad = 0; quad<6; quad++) + { + for (int j = 0; j < 4; j++) + fpts[j] = vertices[faces[quad][j]-1]; + + static Point<3> c(0.5, 0.5, 0.5); + if (vispar.shrink < 1) + for (int j = 0; j < 4; j++) + fpts[j] += (1-vispar.shrink) * (c-fpts[j]); + + Vec<3> taux = fpts[1]-fpts[0]; + Vec<3> tauy = fpts[3]-fpts[0]; + + for (int ix = 0; ix <= hoplotn; ix++) + for (int iy = 0; iy <= hoplotn; iy++) + { + Point<3> xl; + Mat<3,3> dxdxi; + double lami[4] = + { (1-double(ix)/hoplotn) * (1-double(iy)/hoplotn), + ( double(ix)/hoplotn) * (1-double(iy)/hoplotn), + ( double(ix)/hoplotn) * ( double(iy)/hoplotn), + (1-double(ix)/hoplotn) * ( double(iy)/hoplotn) }; + for (int l = 0; l < 3; l++) + xl(l) = lami[0] * fpts[0](l) + lami[1] * fpts[1](l) + + lami[2] * fpts[2](l) + lami[3] * fpts[3](l); + + curv.CalcElementTransformation (xl, ei, grid[ix][iy], dxdxi); + + Vec<3> gtaux = dxdxi * taux; + Vec<3> gtauy = dxdxi * tauy; + gridn[ix][iy] = Cross (gtauy, gtaux).Normalize(); + } + + for (int ix = 0; ix < hoplotn; ix++) + for (int iy = 0; iy < hoplotn; iy++) + { + glNormal3dv (gridn[ix][iy]); + glVertex3dv (grid[ix][iy]); + + glNormal3dv (gridn[ix+1][iy]); + glVertex3dv (grid[ix+1][iy]); + + glNormal3dv (gridn[ix+1][iy+1]); + glVertex3dv (grid[ix+1][iy+1]); + + glNormal3dv (gridn[ix][iy+1]); + glVertex3dv (grid[ix][iy+1]); + } + } + + glEnd (); + */ + + const ELEMENT_FACE * faces = MeshTopology :: GetFaces (HEX); + const Point3d * vertices = MeshTopology :: GetVertices (HEX); + + Point<3> grid[11][11]; + Point<3> fpts[4]; + int order = vispar.subdivisions+1; + + for (int quad = 0; quad<6; quad++) + { + for (int j = 0; j < 4; j++) + fpts[j] = vertices[faces[quad][j]-1]; + + static Point<3> c(0.5, 0.5, 0.5); + if (vispar.shrink < 1) + for (int j = 0; j < 4; j++) + fpts[j] += (1-vispar.shrink) * (c-fpts[j]); + + for (int ix = 0; ix <= order; ix++) + for (int iy = 0; iy <= order; iy++) + { + double lami[4] = + { (1-double(ix)/order) * (1-double(iy)/order), + ( double(ix)/order) * (1-double(iy)/order), + ( double(ix)/order) * ( double(iy)/order), + (1-double(ix)/order) * ( double(iy)/order) }; + + Point<3> xl; + for (int l = 0; l < 3; l++) + xl(l) = lami[0] * fpts[0](l) + lami[1] * fpts[1](l) + + lami[2] * fpts[2](l) + lami[3] * fpts[3](l); + + curv.CalcElementTransformation (xl, ei, grid[ix][iy]); + } + + for (int j = 0; j <= order; j++) + ToBernstein (order, &grid[j][0], &grid[0][1]-&grid[0][0]); + for (int j = 0; j <= order; j++) + ToBernstein (order, &grid[0][j], &grid[1][0]-&grid[0][0]); + + glMap2d(GL_MAP2_VERTEX_3, + 0.0, 1.0, &grid[0][1](0)-&grid[0][0](0), order+1, + 0.0, 1.0, &grid[1][0](0)-&grid[0][0](0), order+1, + &grid[0][0](0)); + glEnable(GL_MAP2_VERTEX_3); + glEnable(GL_AUTO_NORMAL); + + glMapGrid2f(8, 0.0, 1.0, 8, 0.0, 1.0); + glEvalMesh2(GL_FILL, 0, 8, 0, 8); + + glDisable (GL_AUTO_NORMAL); + glDisable (GL_MAP2_VERTEX_3); + } + } + else + { + Point3d c(0,0,0); + if (vispar.shrink < 1) + { + for (int j = 1; j <= 8; j++) + { + Point3d p = mesh->Point(el.PNum(j)); + c.X() += p.X(); + c.Y() += p.Y(); + c.Z() += p.Z(); + } + c.X() /= 8; + c.Y() /= 8; + c.Z() /= 8; + } + + glBegin (GL_TRIANGLES); + + el.GetSurfaceTriangles (faces); + for (int j = 1; j <= faces.Size(); j++) + { + Element2d & face = faces.Elem(j); + Point<3> lp1 = mesh->Point (el.PNum(face.PNum(1))); + Point<3> lp2 = mesh->Point (el.PNum(face.PNum(2))); + Point<3> lp3 = mesh->Point (el.PNum(face.PNum(3))); + Vec<3> n = Cross (lp3-lp1, lp2-lp1); + n.Normalize(); + glNormal3dv (n); + + if (vispar.shrink < 1) + { + lp1 = c + vispar.shrink * (lp1 - c); + lp2 = c + vispar.shrink * (lp2 - c); + lp3 = c + vispar.shrink * (lp3 - c); + } + + glVertex3dv (lp1); + glVertex3dv (lp2); + glVertex3dv (lp3); + } + + glEnd(); + } + } + } + glEndList (); + } + + + + + + + + + + void VisualSceneMesh :: BuildPyramidList() + { + if (pyramidtimestamp > mesh->GetTimeStamp () && + pyramidtimestamp > vispar.clipplanetimestamp ) + return; + + if (!lock) + { + lock = new NgLock (mesh->Mutex()); + lock -> Lock(); + } + + pyramidtimestamp = NextTimeStamp(); + + + if (pyramidlist) + glDeleteLists (pyramidlist, 1); + + + + + pyramidlist = glGenLists (1); + glNewList (pyramidlist, GL_COMPILE); + + static float pyramidcol[] = { 1.0f, 0.0f, 1.0f, 1.0f }; + glLineWidth (1.0f); + ARRAY<Element2d> faces; + + for (ElementIndex ei = 0; ei < mesh->GetNE(); ei++) + { + const Element & el = (*mesh)[ei]; + if (el.GetType() == PYRAMID && !el.IsDeleted()) + { + int j; + int i = ei + 1; + + CurvedElements & curv = mesh->GetCurvedElements(); + if (curv.IsHighOrder() && curv.IsElementCurved(ei)) + { + + const ELEMENT_FACE * faces = MeshTopology :: GetFaces (PYRAMID); + const Point3d * vertices = MeshTopology :: GetVertices (PYRAMID); + + Point<3> grid[11][11]; + Point<3> fpts[4]; + int order = vispar.subdivisions+1; + + for (int trig = 0; trig < 4; trig++) + { + for (int j = 0; j < 3; j++) + fpts[j] = vertices[faces[trig][j]-1]; + + static Point<3> c(0.375, 0.375, 0.25); + if (vispar.shrink < 1) + for (int j = 0; j < 3; j++) + fpts[j] += (1-vispar.shrink) * (c-fpts[j]); + + for (int ix = 0; ix <= order; ix++) + for (int iy = 0; iy <= order; iy++) + { + double lami[3] = + { (1-double(ix)/order) * (1-double(iy)/order), + ( double(ix)/order) * (1-double(iy)/order), + double(iy)/order }; + + Point<3> xl; + for (int l = 0; l < 3; l++) + xl(l) = lami[0] * fpts[0](l) + lami[1] * fpts[1](l) + + lami[2] * fpts[2](l); + + curv.CalcElementTransformation (xl, i-1, grid[ix][iy]); + } + + for (int j = 0; j <= order; j++) + ToBernstein (order, &grid[j][0], &grid[0][1]-&grid[0][0]); + for (int j = 0; j <= order; j++) + ToBernstein (order, &grid[0][j], &grid[1][0]-&grid[0][0]); + + glMap2d(GL_MAP2_VERTEX_3, + 0.0, 1.0, &grid[0][1](0)-&grid[0][0](0), order+1, + 0.0, 1.0, &grid[1][0](0)-&grid[0][0](0), order+1, + &grid[0][0](0)); + glEnable(GL_MAP2_VERTEX_3); + glEnable(GL_AUTO_NORMAL); + + glMapGrid2f(8, 0.0, 0.999, 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); + + glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, pyramidcol); + if (el.PNum(1)) + { + glBegin (GL_TRIANGLES); + + for (int j = 1; j <= faces.Size(); j++) + { + Element2d & face = faces.Elem(j); + Point3d lp1 = mesh->Point (el.PNum(face.PNum(1))); + Point3d lp2 = mesh->Point (el.PNum(face.PNum(2))); + Point3d lp3 = mesh->Point (el.PNum(face.PNum(3))); + Vec3d n = Cross (Vec3d (lp1, lp2), Vec3d (lp1, lp3)); + n /= (n.Length()+1e-12); + n *= -1; + glNormal3d (n.X(), n.Y(), n.Z()); + + if (vispar.shrink < 1) + { + lp1 = c + vispar.shrink * (lp1 - c); + lp2 = c + vispar.shrink * (lp2 - c); + lp3 = c + vispar.shrink * (lp3 - c); + } + + glVertex3d (lp1.X(), lp1.Y(), lp1.Z()); + glVertex3d (lp2.X(), lp2.Y(), lp2.Z()); + glVertex3d (lp3.X(), lp3.Y(), lp3.Z()); + } + + glEnd(); + } + } + } + } + glEndList (); + } + + void VisualSceneMesh :: BuildBadelList() + { + ; + } + + void VisualSceneMesh :: BuildIdentifiedList() + { + ; + } + + void VisualSceneMesh :: BuildDomainSurfList() + { + if (domainsurflist) + glDeleteLists (domainsurflist, 1); + + domainsurflist = glGenLists (1); + glNewList (domainsurflist, GL_COMPILE); + + int i, j; + glLineWidth (1.0f); + + glDisable (GL_COLOR_MATERIAL); + + for (i = 1; i <= mesh->GetNSE(); i++) + { + Element2d el = mesh->SurfaceElement (i); + + int drawel = 1; + for (j = 1; j <= el.GetNP(); j++) + { + if (!el.PNum(j)) + drawel = 0; + } + + if (!drawel) + continue; + + if (el.GetIndex() < 1 || el.GetIndex() > mesh->GetNFD()) + continue; + int domin = mesh->GetFaceDescriptor(el.GetIndex()).DomainIn(); + int domout = mesh->GetFaceDescriptor(el.GetIndex()).DomainOut(); + + int fac; + if (domin == vispar.drawdomainsurf) + fac = 1; + else if (domout == vispar.drawdomainsurf) + fac = -1; + else + continue; + + + GLfloat matcol[] = { 1, 0, 0, 1 }; + glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, matcol); + + + if (el.GetNP() == 3) + { + glBegin (GL_TRIANGLES); + + const Point3d & lp1 = mesh->Point (el.PNum(1)); + const Point3d & lp2 = mesh->Point (el.PNum(2)); + const Point3d & lp3 = mesh->Point (el.PNum(3)); + Vec3d n = Cross (Vec3d (lp1, lp2), Vec3d (lp1, lp3)); + n /= ( fac * (n.Length()+1e-12)); + glNormal3d (n.X(), n.Y(), n.Z()); + + if (!vispar.colormeshsize) + { + glVertex3d (lp1.X(), lp1.Y(), lp1.Z()); + glVertex3d (lp2.X(), lp2.Y(), lp2.Z()); + glVertex3d (lp3.X(), lp3.Y(), lp3.Z()); + } + glEnd(); + } + else if (el.GetNP() == 4) + { + glBegin (GL_QUADS); + + const Point3d & lp1 = mesh->Point (el.PNum(1)); + const Point3d & lp2 = mesh->Point (el.PNum(2)); + const Point3d & lp3 = mesh->Point (el.PNum(4)); + const Point3d & lp4 = mesh->Point (el.PNum(3)); + Vec3d n = Cross (Vec3d (lp1, lp2), + Vec3d (lp1, Center (lp3, lp4))); + n /= (fac * (n.Length()+1e-12)); + glNormal3d (n.X(), n.Y(), n.Z()); + glVertex3d (lp1.X(), lp1.Y(), lp1.Z()); + glVertex3d (lp2.X(), lp2.Y(), lp2.Z()); + glVertex3d (lp4.X(), lp4.Y(), lp4.Z()); + glVertex3d (lp3.X(), lp3.Y(), lp3.Z()); + glEnd(); + } + else if (el.GetNP() == 6) + { + glBegin (GL_TRIANGLES); + static int trigs[4][3] = { + { 1, 6, 5 }, + { 2, 4, 6 }, + { 3, 5, 4 }, + { 4, 5, 6 } }; + + for (j = 0; j < 4; j++) + { + const Point3d & lp1 = mesh->Point (el.PNum(trigs[j][0])); + const Point3d & lp2 = mesh->Point (el.PNum(trigs[j][1])); + const Point3d & lp3 = mesh->Point (el.PNum(trigs[j][2])); + Vec3d n = Cross (Vec3d (lp1, lp2), Vec3d (lp1, lp3)); + n /= (fac * (n.Length() + 1e-12)); + glNormal3d (n.X(), n.Y(), n.Z()); + glVertex3d (lp1.X(), lp1.Y(), lp1.Z()); + glVertex3d (lp2.X(), lp2.Y(), lp2.Z()); + glVertex3d (lp3.X(), lp3.Y(), lp3.Z()); + } + glEnd(); + } + } + glEndList (); + } + + + + + + + + + + + + + void VisualSceneMesh :: MouseDblClick (int px, int py) + { + int i, hits; + + // select surface triangle by mouse click + + GLuint selbuf[10000]; + glSelectBuffer (10000, selbuf); + + + glRenderMode (GL_SELECT); + + GLint viewport[4]; + glGetIntegerv (GL_VIEWPORT, viewport); + + + glMatrixMode (GL_PROJECTION); + glPushMatrix(); + + GLdouble projmat[16]; + glGetDoublev (GL_PROJECTION_MATRIX, projmat); + + glLoadIdentity(); + gluPickMatrix (px, viewport[3] - py, 1, 1, viewport); + glMultMatrixd (projmat); + + + + glClearColor(backcolor, backcolor, backcolor, 1.0); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + glMatrixMode (GL_MODELVIEW); + + glPushMatrix(); + glMultMatrixf (transformationmat); + + + // SetClippingPlane(); + + glInitNames(); + glPushName (1); + + glPolygonOffset (1, 1); + glEnable (GL_POLYGON_OFFSET_FILL); + + glDisable(GL_CLIP_PLANE0); + + if (vispar.clipenable) + { + Vec<3> n(clipplane[0], clipplane[1], clipplane[2]); + double len = Abs(n); + double mu = -clipplane[3] / (len*len); + Point<3> p (mu * n); + n /= len; + Vec<3> t1 = n.GetNormal (); + Vec<3> t2 = Cross (n, t1); + + double xi1mid = (center - p) * t1; + double xi2mid = (center - p) * t2; + + glLoadName (0); + glBegin (GL_QUADS); + glVertex3dv (p + (xi1mid-rad) * t1 + (xi2mid-rad) * t2); + glVertex3dv (p + (xi1mid+rad) * t1 + (xi2mid-rad) * t2); + glVertex3dv (p + (xi1mid+rad) * t1 + (xi2mid+rad) * t2); + glVertex3dv (p + (xi1mid-rad) * t1 + (xi2mid+rad) * t2); + glEnd (); + } + + // SetClippingPlane(); + + glCallList (filledlist); + + glDisable (GL_POLYGON_OFFSET_FILL); + + glPopName(); + + glMatrixMode (GL_PROJECTION); + glPopMatrix(); + + glMatrixMode (GL_MODELVIEW); + glPopMatrix(); + + glFlush(); + + + hits = glRenderMode (GL_RENDER); + + // cout << "hits = " << hits << endl; + + int minname = 0; + GLuint mindepth = 0; + + // find clippingplane + GLuint clipdepth = 0; // GLuint(-1); + + for (i = 0; i < hits; i++) + { + int curname = selbuf[4*i+3]; + if (!curname) clipdepth = selbuf[4*i+1]; + } + + for (i = 0; i < hits; i++) + { + int curname = selbuf[4*i+3]; + GLuint curdepth = selbuf[4*i+1]; + /* + cout << selbuf[4*i] << " " << selbuf[4*i+1] << " " + << selbuf[4*i+2] << " " << selbuf[4*i+3] << endl; + */ + if (curname && (curdepth > clipdepth) && + (curdepth < mindepth || !minname)) + { + mindepth = curdepth; + minname = curname; + } + } + + seledge = -1; + if (minname) + { + const Element2d & sel = mesh->SurfaceElement(minname); + + + cout << "select element " << minname + << " on face " << sel.GetIndex() << endl; + cout << "Nodes: "; + for (i = 1; i <= sel.GetNP(); i++) + cout << sel.PNum(i) << " "; + cout << endl; + + selelement = minname; + selface = mesh->SurfaceElement(minname).GetIndex(); + + locpi = (locpi % sel.GetNP()) + 1; + selpoint2 = selpoint; + selpoint = sel.PNum(locpi); + cout << "selected point " << selpoint + << ", pos = " << mesh->Point (selpoint) + << endl; + + for (i = 1; i <= mesh->GetNSeg(); i++) + { + const Segment & seg = mesh->LineSegment(i); + if (seg.p1 == selpoint && seg.p2 == selpoint2 || + seg.p2 == selpoint && seg.p1 == selpoint2) + { + seledge = seg.edgenr; + cout << "seledge = " << seledge << endl; + } + } + + } + else + { + selface = -1; + selelement = -1; + selpoint = -1; + selpoint2 = -1; + } + + glDisable(GL_CLIP_PLANE0); + + selecttimestamp = NextTimeStamp(); + } + + + + + +} + + + + + + + + + + diff --git a/contrib/Netgen/libsrc/visualization/vsocc.cpp b/contrib/Netgen/libsrc/visualization/vsocc.cpp new file mode 100644 index 0000000000..12cfc5e179 --- /dev/null +++ b/contrib/Netgen/libsrc/visualization/vsocc.cpp @@ -0,0 +1,743 @@ +#ifdef OCCGEOMETRY + + +#include <mystdlib.h> +#include <myadt.hpp> +#include <meshing.hpp> + +// #include <csg.hpp> +// #include <stlgeom.hpp> + +#include <occgeom.hpp> + +#include "TopoDS_Shape.hxx" +#include "TopoDS_Vertex.hxx" +#include "TopExp_Explorer.hxx" +#include "BRep_Tool.hxx" +#include "TopoDS.hxx" +#include "gp_Pnt.hxx" +#include "Geom_Curve.hxx" +#include "Poly_Triangulation.hxx" +#include "Poly_Array1OfTriangle.hxx" +#include "TColgp_Array1OfPnt2d.hxx" +#include "Poly_Triangle.hxx" +#include "Poly_Polygon3D.hxx" +#include "Poly_PolygonOnTriangulation.hxx" +// #include "BRepMesh.hxx" +// #include "BRepMesh_IncrementalMesh.hxx" + +#include "incvis.hpp" + + +namespace netgen +{ +#include "mvdraw.hpp" + + +extern OCCGeometry * occgeometry; + + + + +/* *********************** Draw OCC Geometry **************** */ + + +VisualSceneOCCGeometry :: VisualSceneOCCGeometry () + : VisualScene() +{ + trilists.SetSize(0); + linelists.SetSize(1); + +} + +VisualSceneOCCGeometry :: ~VisualSceneOCCGeometry () +{ + ; +} + +void VisualSceneOCCGeometry :: DrawScene () +{ + // int i, j, k; + + if ( occgeometry->changed ) + { + BuildScene(); + occgeometry -> changed = 0; + } + + glClearColor(backcolor, backcolor, backcolor, 1.0); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + SetLight(); + + glPushMatrix(); + glMultMatrixf (transformationmat); + + glShadeModel (GL_SMOOTH); + glDisable (GL_COLOR_MATERIAL); + glPolygonMode (GL_FRONT_AND_BACK, GL_FILL); + + glEnable (GL_BLEND); + glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + // glEnable (GL_LIGHTING); + + double shine = vispar.shininess; + // double transp = vispar.transp; + + glMaterialf (GL_FRONT_AND_BACK, GL_SHININESS, shine); + glLogicOp (GL_COPY); + + + float mat_col[] = { 0.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); + + GLfloat matcoledge[] = { 0, 0, 1, 1 }; + GLfloat matcolhiedge[] = { 1, 0, 0, 1 }; + + glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, + matcoledge); + glLineWidth (1.0f); + + if (vispar.occshowedges) glCallList (linelists.Get(1)); + if (vispar.occshowsurfaces) glCallList (trilists.Get(1)); + + glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, + matcolhiedge); + glLineWidth (5.0f); + + if (vispar.occshowedges) glCallList (linelists.Get(2)); + + for (int i = 1; i <= occgeometry->vmap.Extent(); i++) + if (occgeometry->vvispar[i-1].IsHighlighted()) + { + glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, + matcolhiedge); + glLineWidth (5.0f); + + glBegin (GL_LINES); + + gp_Pnt p = BRep_Tool::Pnt(TopoDS::Vertex(occgeometry->vmap(i))); + double d = rad/100; + glVertex3f (p.X()-d, p.Y(), p.Z()); + glVertex3f (p.X()+d, p.Y(), p.Z()); + glVertex3f (p.X(), p.Y()-d, p.Z()); + glVertex3f (p.X(), p.Y()+d, p.Z()); + glVertex3f (p.X(), p.Y(), p.Z()-d); + glVertex3f (p.X(), p.Y(), p.Z()+d); + glEnd(); + } + + glDisable (GL_POLYGON_OFFSET_FILL); + + glPopMatrix(); + // DrawCoordinateCross (); + // DrawNetgenLogo (); + glFinish(); + + glDisable (GL_POLYGON_OFFSET_FILL); +} + + +/* +void VisualSceneOCCGeometry :: BuildScene (int zoomall) +{ + int i = 0, j, k; + + TopExp_Explorer ex, ex_edge; + + if (vispar.occvisproblemfaces || (occgeometry -> changed != 2)) + { + Box<3> bb = occgeometry -> GetBoundingBox(); + + center = bb.Center(); + rad = bb.Diam() / 2; + + + + if (vispar.occvisproblemfaces) + { + for (i = 1; i <= occgeometry->fmap.Extent(); i++) + if (occgeometry->facemeshstatus[i-1] == -1) + { + GProp_GProps system; + BRepGProp::LinearProperties(occgeometry->fmap(i), system); + gp_Pnt pnt = system.CentreOfMass(); + center = Point<3> (pnt.X(), pnt.Y(), pnt.Z()); + cout << "Setting center to mid of face " << i << " = " << center << endl; + } + } + + + CalcTransformationMatrices(); + } + + + for (i = 1; i <= linelists.Size(); i++) + glDeleteLists (linelists.Elem(i), 1); + linelists.SetSize(0); + + linelists.Append (glGenLists (1)); + glNewList (linelists.Last(), GL_COMPILE); + + i = 0; + for (ex_edge.Init(occgeometry -> shape, TopAbs_EDGE); + ex_edge.More(); ex_edge.Next()) + { + if (BRep_Tool::Degenerated(TopoDS::Edge(ex_edge.Current()))) continue; + i++; + + + TopoDS_Edge edge = TopoDS::Edge(ex_edge.Current()); + + Handle(Poly_PolygonOnTriangulation) aEdgePoly; + Handle(Poly_Triangulation) T; + TopLoc_Location aEdgeLoc; + BRep_Tool::PolygonOnTriangulation(edge, aEdgePoly, T, aEdgeLoc); + + if(aEdgePoly.IsNull()) + { + cout << "cannot visualize edge " << i << endl; + continue; + } + + glBegin (GL_LINE_STRIP); + + int nbnodes = aEdgePoly -> NbNodes(); + for (j = 1; j <= nbnodes; j++) + { + gp_Pnt p = (T -> Nodes())(aEdgePoly->Nodes()(j)).Transformed(aEdgeLoc); + glVertex3f (p.X(), p.Y(), p.Z()); + } + + glEnd (); + + + } + + glEndList (); + + for (i = 1; i <= trilists.Size(); i++) + glDeleteLists (trilists.Elem(i), 1); + trilists.SetSize(0); + + + trilists.Append (glGenLists (1)); + glNewList (trilists.Last(), GL_COMPILE); + + i = 0; + + TopExp_Explorer exp0, exp1, exp2, exp3; + int shapenr = 0; + for (exp0.Init(occgeometry -> shape, TopAbs_SOLID); exp0.More(); exp0.Next()) + { + shapenr++; + + if (vispar.occshowvolumenr != 0 && + vispar.occshowvolumenr != shapenr) continue; + + float mat_col[4]; + mat_col[3] = 1; + switch (shapenr) + { + case 1: + mat_col[0] = 0.2; + mat_col[1] = 0.2; + mat_col[2] = 0.8; + break; + case 2: + mat_col[0] = 0.8; + mat_col[1] = 0.2; + mat_col[2] = 0.8; + break; + case 3: + mat_col[0] = 0.2; + mat_col[1] = 0.8; + mat_col[2] = 0.8; + break; + case 4: + mat_col[0] = 0.8; + mat_col[1] = 0.2; + mat_col[2] = 0.2; + break; + case 5: + mat_col[0] = 0.8; + mat_col[1] = 0.8; + mat_col[2] = 0.8; + break; + case 6: + mat_col[0] = 0.6; + mat_col[1] = 0.6; + mat_col[2] = 0.6; + break; + case 7: + mat_col[0] = 0.2; + mat_col[1] = 0.8; + mat_col[2] = 0.2; + break; + case 8: + mat_col[0] = 0.8; + mat_col[1] = 0.8; + mat_col[2] = 0.2; + break; + default: + // mat_col[0] = 1-(1.0/double(shapenr)); + // mat_col[1] = 0.5; + mat_col[0] = 0.5+double((shapenr*shapenr*shapenr*shapenr) % 10)/20.0; + mat_col[1] = 0.5+double(int(shapenr*shapenr*shapenr*shapenr*sin(double(shapenr))) % 10)/20.0; + mat_col[2] = 0.5+double((shapenr*shapenr*shapenr) % 10)/20.0; + } + + glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, mat_col); + + for (exp1.Init(exp0.Current(), TopAbs_SHELL); exp1.More(); exp1.Next()) + for (exp2.Init(exp1.Current().Composed(exp0.Current().Orientation()), TopAbs_FACE); exp2.More(); exp2.Next()) + { + TopoDS_Face face = TopoDS::Face (exp2.Current().Composed(exp1.Current().Orientation())); + + i = occgeometry->fmap.FindIndex(face); + + TopLoc_Location loc; + Handle(Geom_Surface) surf = BRep_Tool::Surface (face); + BRepAdaptor_Surface sf(face, Standard_False); + BRepLProp_SLProps prop(sf, 1, 1e-5); + Handle(Poly_Triangulation) triangulation = BRep_Tool::Triangulation (face, loc); + + if (triangulation.IsNull()) + { + cout << "cannot visualize face " << i << endl; + continue; + } + + if (vispar.occvisproblemfaces) + { + switch (occgeometry->facemeshstatus[i-1]) + { + case 0: + mat_col[0] = 0.2; + mat_col[1] = 0.2; + mat_col[2] = 0.8; + break; + case 1: + mat_col[0] = 0.2; + mat_col[1] = 0.8; + mat_col[2] = 0.2; + break; + case -1: + mat_col[0] = 0.8; + mat_col[1] = 0.2; + mat_col[2] = 0.2; + break; + } + glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, mat_col); + + } + glBegin (GL_TRIANGLES); + + int ntriangles = triangulation -> NbTriangles(); + for (j = 1; j <= ntriangles; j++) + { + Poly_Triangle triangle = (triangulation -> Triangles())(j); + for (k = 1; k <= 3; k++) + { + gp_Pnt2d uv = (triangulation -> UVNodes())(triangle(k)); + gp_Pnt pnt; + gp_Vec du, dv; + prop.SetParameters (uv.X(), uv.Y()); + surf->D0 (uv.X(), uv.Y(), pnt); + gp_Vec n; + + if (prop.IsNormalDefined()) + n = prop.Normal(); + else + n = gp_Vec (0,0,0); + + if (face.Orientation() == TopAbs_REVERSED) n *= -1; + glNormal3f (n.X(), n.Y(), n.Z()); + glVertex3f (pnt.X(), pnt.Y(), pnt.Z()); + } + } + glEnd (); + + } + } + + + glEndList (); + +} +*/ + + +void VisualSceneOCCGeometry :: BuildScene (int zoomall) +{ + if (occgeometry -> changed == OCCGEOMETRYVISUALIZATIONFULLCHANGE) + { + center = occgeometry -> Center(); + rad = occgeometry -> GetBoundingBox().Diam() / 2; + + if (vispar.occzoomtohighlightedentity) + { + bool hilite = false; + bool hiliteonepoint = false; + Bnd_Box bb; + + for (int i = 1; i <= occgeometry->fmap.Extent(); i++) + if (occgeometry->fvispar[i-1].IsHighlighted()) + { + hilite = true; + BRepBndLib::Add (occgeometry->fmap(i), bb); + } + + for (int i = 1; i <= occgeometry->emap.Extent(); i++) + if (occgeometry->evispar[i-1].IsHighlighted()) + { + hilite = true; + BRepBndLib::Add (occgeometry->emap(i), bb); + } + + for (int i = 1; i <= occgeometry->vmap.Extent(); i++) + if (occgeometry->vvispar[i-1].IsHighlighted()) + { + hiliteonepoint = true; + BRepBndLib::Add (occgeometry->vmap(i), bb); + } + + if (hilite || hiliteonepoint) + { + double x1,y1,z1,x2,y2,z2; + bb.Get (x1,y1,z1,x2,y2,z2); + Point<3> p1 = Point<3> (x1,y1,z1); + Point<3> p2 = Point<3> (x2,y2,z2); + Box<3> boundingbox(p1,p2); + + center = boundingbox.Center(); + if (hiliteonepoint) + rad = occgeometry -> GetBoundingBox().Diam() / 100; + else + rad = boundingbox.Diam() / 2; + } + } + + CalcTransformationMatrices(); + } + + + // Clear lists + + for (int i = 1; i <= linelists.Size(); i++) + glDeleteLists (linelists.Elem(i), 1); + linelists.SetSize(0); + + for (int i = 1; i <= trilists.Size(); i++) + glDeleteLists (trilists.Elem(i), 1); + trilists.SetSize(0); + + + // Total wireframe + + linelists.Append (glGenLists (1)); + glNewList (linelists.Last(), GL_COMPILE); + + for (int i = 1; i <= occgeometry->emap.Extent(); i++) + { + TopoDS_Edge edge = TopoDS::Edge(occgeometry->emap(i)); + if (BRep_Tool::Degenerated(edge)) continue; + if (occgeometry->evispar[i-1].IsHighlighted()) continue; + + Handle(Poly_PolygonOnTriangulation) aEdgePoly; + Handle(Poly_Triangulation) T; + TopLoc_Location aEdgeLoc; + BRep_Tool::PolygonOnTriangulation(edge, aEdgePoly, T, aEdgeLoc); + + if(aEdgePoly.IsNull()) + { + (*testout) << "visualizing edge " << occgeometry->emap.FindIndex (edge) + << " without using the occ visualization triangulation" << endl; + + double s0, s1; + Handle(Geom_Curve) c = BRep_Tool::Curve(edge, s0, s1); + + glBegin (GL_LINE_STRIP); + for (int i = 0; i<=50; i++) + { + gp_Pnt p = c->Value (s0 + i*(s1-s0)/50.0); + glVertex3f (p.X(),p.Y(),p.Z()); + } + glEnd (); + + continue; + } + + int nbnodes = aEdgePoly -> NbNodes(); + glBegin (GL_LINE_STRIP); + for (int j = 1; j <= nbnodes; j++) + { + gp_Pnt p = (T -> Nodes())(aEdgePoly->Nodes()(j)).Transformed(aEdgeLoc); + glVertex3f (p.X(), p.Y(), p.Z()); + } + glEnd (); + } + + glEndList (); + + + // Highlighted edge list + + linelists.Append (glGenLists (1)); + glNewList (linelists.Last(), GL_COMPILE); + + for (int i = 1; i <= occgeometry->emap.Extent(); i++) + if (occgeometry->evispar[i-1].IsHighlighted()) + { + TopoDS_Edge edge = TopoDS::Edge(occgeometry->emap(i)); + if (BRep_Tool::Degenerated(edge)) continue; + + Handle(Poly_PolygonOnTriangulation) aEdgePoly; + Handle(Poly_Triangulation) T; + TopLoc_Location aEdgeLoc; + BRep_Tool::PolygonOnTriangulation(edge, aEdgePoly, T, aEdgeLoc); + + if(aEdgePoly.IsNull()) + { + (*testout) << "visualizing edge " << occgeometry->emap.FindIndex (edge) + << " without using the occ visualization triangulation" << endl; + + double s0, s1; + Handle(Geom_Curve) c = BRep_Tool::Curve(edge, s0, s1); + + glBegin (GL_LINE_STRIP); + for (int i = 0; i<=50; i++) + { + gp_Pnt p = c->Value (s0 + i*(s1-s0)/50.0); + glVertex3f (p.X(),p.Y(),p.Z()); + } + glEnd (); + + continue; + } + + int nbnodes = aEdgePoly -> NbNodes(); + glBegin (GL_LINE_STRIP); + for (int j = 1; j <= nbnodes; j++) + { + gp_Pnt p = (T -> Nodes())(aEdgePoly->Nodes()(j)).Transformed(aEdgeLoc); + glVertex3f (p.X(), p.Y(), p.Z()); + } + glEnd (); + } + + glEndList (); + + + + + + // display faces + + trilists.Append (glGenLists (1)); + glNewList (trilists.Last(), GL_COMPILE); + + for (int i = 1; i <= occgeometry->fmap.Extent(); i++) + { + glLoadName (i); + float mat_col[4]; + mat_col[3] = 1; + + if (!occgeometry->fvispar[i-1].IsHighlighted()) + { + mat_col[0] = 0.2; + mat_col[1] = 0.2; + mat_col[2] = 0.8; + } + 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); + + TopoDS_Face face = TopoDS::Face(occgeometry->fmap(i)); + TopLoc_Location loc; + Handle(Geom_Surface) surf = BRep_Tool::Surface (face); + BRepAdaptor_Surface sf(face, Standard_False); + BRepLProp_SLProps prop(sf, 1, 1e-5); + Handle(Poly_Triangulation) triangulation = BRep_Tool::Triangulation (face, loc); + + if (triangulation.IsNull()) + { + cout << "cannot visualize face " << i << endl; + occgeometry->fvispar[i-1].SetNotDrawable(); + continue; + } + + gp_Pnt2d uv; + gp_Pnt pnt; + gp_Vec n; + + glBegin (GL_TRIANGLES); + + int ntriangles = triangulation -> NbTriangles(); + for (int j = 1; j <= ntriangles; j++) + { + Poly_Triangle triangle = (triangulation -> Triangles())(j); + for (int k = 1; k <= 3; k++) + { + uv = (triangulation -> UVNodes())(triangle(k)); + prop.SetParameters (uv.X(), uv.Y()); + + pnt = (triangulation -> Nodes())(triangle(k)).Transformed(loc); + + // 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); + } + + if (face.Orientation() == TopAbs_REVERSED) n *= -1; + glNormal3f (n.X(), n.Y(), n.Z()); + glVertex3f (pnt.X(), pnt.Y(), pnt.Z()); + } + } + glEnd (); + + } + glEndList (); + +} + +void SelectFaceInOCCDialogTree (int facenr); + +void VisualSceneOCCGeometry :: MouseDblClick (int px, int py) +{ + int hits; + + // select surface triangle by mouse click + + GLuint selbuf[10000]; + glSelectBuffer (10000, selbuf); + + + glRenderMode (GL_SELECT); + + GLint viewport[4]; + glGetIntegerv (GL_VIEWPORT, viewport); + + + glMatrixMode (GL_PROJECTION); + glPushMatrix(); + + GLdouble projmat[16]; + glGetDoublev (GL_PROJECTION_MATRIX, projmat); + + glLoadIdentity(); + gluPickMatrix (px, viewport[3] - py, 1, 1, viewport); + glMultMatrixd (projmat); + + + + glClearColor(backcolor, backcolor, backcolor, 1.0); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + glMatrixMode (GL_MODELVIEW); + + glPushMatrix(); + glMultMatrixf (transformationmat); + + + + glInitNames(); + glPushName (1); + + glPolygonOffset (1, 1); + glEnable (GL_POLYGON_OFFSET_FILL); + + glDisable(GL_CLIP_PLANE0); + + 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); + + + // selecttimestamp = NextTimeStamp(); +} + + + + + + +} + + + +#endif + + diff --git a/contrib/Netgen/libsrc/visualization/vssolution.cpp b/contrib/Netgen/libsrc/visualization/vssolution.cpp new file mode 100644 index 0000000000..62b6faab83 --- /dev/null +++ b/contrib/Netgen/libsrc/visualization/vssolution.cpp @@ -0,0 +1,3005 @@ +#include <mystdlib.h> +#include "incvis.hpp" + + +#include <myadt.hpp> +#include <meshing.hpp> +#include <csg.hpp> +#include <stlgeom.hpp> + +#include <visual.hpp> + + +namespace netgen +{ + + extern AutoPtr<Mesh> mesh; + + + VisualSceneSolution :: SolData :: SolData () + : name (0), data (0), solclass(0) + { ; } + + VisualSceneSolution :: SolData :: ~SolData () + { + delete [] name; + delete data; + delete solclass; + } + + + VisualSceneSolution :: VisualSceneSolution () + : VisualScene() + { + surfellist = 0; + linelist = 0; + clipplanelist = 0; + isolinelist = 0; + clipplane_isolinelist = 0; + surface_vector_list = 0; + cone_list = 0; + + surfeltimestamp = GetTimeStamp(); + surfellinetimestamp = GetTimeStamp(); + clipplanetimestamp = GetTimeStamp(); + solutiontimestamp = GetTimeStamp(); + fieldlinestimestamp = GetTimeStamp(); + surface_vector_timestamp = GetTimeStamp(); + AddVisualizationScene ("solution", &vssolution); + } + + VisualSceneSolution :: ~VisualSceneSolution () + { + ClearSolutionData(); + } + + void VisualSceneSolution :: AddSolutionData (SolData * sd) + { + int funcnr = -1; + for (int i = 0; i < soldata.Size(); i++) + { + if (strcmp (soldata[i]->name, sd->name) == 0) + { + delete soldata[i]; + soldata[i] = sd; + funcnr = i; + break; + } + } + + if (funcnr == -1) + { + soldata.Append (sd); + funcnr = soldata.Size()-1; + } + + SolData * nsd = soldata[funcnr]; + + nsd->size = 0; + if (mesh) + { + switch (nsd->soltype) + { + case SOL_NODAL: nsd->size = mesh->GetNV(); break; + case SOL_ELEMENT: nsd->size = mesh->GetNE(); break; + case SOL_SURFACE_ELEMENT: nsd->size = mesh->GetNSE(); break; + case SOL_NONCONTINUOUS: + { + switch (nsd->order) + { + case 0: nsd->size = mesh->GetNE(); break; + case 1: nsd->size = 6 * mesh->GetNE(); break; + case 2: nsd->size = 18 * mesh->GetNE(); break; + } + break; + } + case SOL_SURFACE_NONCONTINUOUS: + { + switch (nsd->order) + { + case 0: nsd->size = mesh->GetNSE(); break; + case 1: nsd->size = 4 * mesh->GetNSE(); break; + case 2: nsd->size = 9 * mesh->GetNSE(); break; + } + break; + } + } + solutiontimestamp = NextTimeStamp(); + } + } + + + void VisualSceneSolution :: ClearSolutionData () + { + for (int i = 0; i < soldata.Size(); i++) + delete soldata[i]; + soldata.SetSize (0); + } + + void VisualSceneSolution :: UpdateSolutionTimeStamp () + { + solutiontimestamp = NextTimeStamp(); + } + + VisualSceneSolution::SolData * VisualSceneSolution :: GetSolData (int i) + { + if (i >= 0 && i < soldata.Size()) + return soldata[i]; + else + return NULL; + } + + + + + void VisualSceneSolution :: SaveSolutionData (const char * filename) + { + PrintMessage (1, "Write solution data to file ", filename); + int i, j, k; + + ofstream ost(filename); + for (i = 0; i < soldata.Size(); i++) + { + const SolData & sol = *soldata[i]; + + ost << "solution " + << sol.name + << " -size=" << sol.size + << " -components=" << sol.components + << " -order=" << sol.order; + if (sol.iscomplex) + ost << " -complex"; + + switch (sol.soltype) + { + case SOL_NODAL: + ost << " -type=nodal"; break; + case SOL_ELEMENT: + ost << " -type=element"; break; + case SOL_SURFACE_ELEMENT: + ost << " -type=surfaceelement"; break; + case SOL_NONCONTINUOUS: + ost << " -type=noncontinuous"; break; + case SOL_SURFACE_NONCONTINUOUS: + ost << " -type=surfacenoncontinuous"; break; + } + + ost << endl; + for (j = 0; j < sol.size; j++) + { + for (k = 0; k < sol.components; k++) + ost << sol.data[j*sol.dist+k] << " "; + ost << "\n"; + } + } + } + + + + + void VisualSceneSolution :: DrawScene () + { + if (!mesh) + { + VisualScene::DrawScene(); + return; + } + + static NgLock mem_lock(mem_mutex); + mem_lock.Lock(); + + NgLock meshlock (mesh->Mutex(), 1); + + BuildScene(); + + CreateTexture (numtexturecols, lineartexture, GL_MODULATE); + + glClearColor(backcolor, backcolor, backcolor, 1); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + SetLight(); + + glPushMatrix(); + glMultMatrixf (transformationmat); + + + + glMatrixMode (GL_MODELVIEW); + + glPolygonMode (GL_FRONT_AND_BACK, GL_FILL); + + // glPolygonOffset (1, 1); + glPolygonOffset (2, 10); + glEnable (GL_POLYGON_OFFSET_FILL); + + glEnable (GL_COLOR_MATERIAL); + + + if (usetexture) + glEnable (GL_TEXTURE_1D); + + + if (vispar.drawfilledtrigs || vispar.drawtetsdomain > 0 || vispar.drawdomainsurf > 0) + { + SetClippingPlane (); + + glCallList (surfellist); + glCallList (surface_vector_list); + + glDisable(GL_CLIP_PLANE0); + } + + if (showclipsolution) + glCallList (clipplanelist); + + + if (draw_fieldlines) + { + BuildFieldLinesPlot (); + + if (num_fieldlineslists <= 1) + glCallList (fieldlineslist); + else + { // animated + int start = int (time / 10 * num_fieldlineslists); + for (int ln = 0; ln < 10; ln++) + { + int nr = fieldlineslist + (start + ln) % num_fieldlineslists; + glCallList (nr); + } + } + } + + if (usetexture) + glDisable (GL_TEXTURE_1D); + + + + glDisable (GL_POLYGON_OFFSET_FILL); + + glDisable (GL_COLOR_MATERIAL); + + + GLfloat matcol0[] = { 0, 0, 0, 1 }; + glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, matcol0); + glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, matcol0); + glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, matcol0); + + glPolygonMode (GL_FRONT_AND_BACK, GL_LINE); + glLineWidth (1.0f); + glColor3f (0.0f, 0.0f, 0.0f); + glDisable (GL_LINE_SMOOTH); + + + if (vispar.drawoutline && !numisolines) + { + SetClippingPlane (); + glCallList (linelist); + glDisable(GL_CLIP_PLANE0); + } + + if (numisolines) + { + SetClippingPlane (); + glCallList (isolinelist); + + glDisable(GL_CLIP_PLANE0); + glCallList (clipplane_isolinelist); + } + + glPopMatrix(); + + glDisable(GL_CLIP_PLANE0); + DrawColorBar (minval, maxval, logscale, lineartexture); + + if (vispar.drawcoordinatecross) + DrawCoordinateCross (); + DrawNetgenLogo (); + + glFinish(); + + + // delete lock; + mem_lock.UnLock(); + } + + + + static void RealVec3d (const double * values, Vec3d & v, + bool iscomplex, bool imag) + { + if (!iscomplex) + { + v.X() = values[0]; + v.Y() = values[1]; + v.Z() = values[2]; + } + else + { + if (!imag) + { + v.X() = values[0]; + v.Y() = values[2]; + v.Z() = values[4]; + } + else + { + v.X() = values[1]; + v.Y() = values[3]; + v.Z() = values[5]; + } + } + } + + + static void RealVec3d (const double * values, Vec3d & v, + bool iscomplex, double phaser, double phasei) + { + if (!iscomplex) + { + v.X() = values[0]; + v.Y() = values[1]; + v.Z() = values[2]; + } + else + { + for (int i = 0; i < 3; i++) + v.X(i+1) = phaser * values[2*i] + phasei * values[2*i+1]; + } + } + + + + + void VisualSceneSolution :: BuildScene (int zoomall) + { + int i, j, k; + + if (!mesh) + { + VisualScene::BuildScene (zoomall); + return; + } + + if (!cone_list) + { + cone_list = glGenLists (1); + glNewList (cone_list, GL_COMPILE); + DrawCone (Point<3> (0,0,0), Point<3> (0,0,1), 0.4); + glEndList(); + } + + + vispar.colormeshsize = 1; + + // recalc clipping plane + SetClippingPlane (); + glDisable(GL_CLIP_PLANE0); + + + SolData * sol = NULL; + SolData * vsol = NULL; + + if (scalfunction != -1) + sol = soldata[scalfunction]; + if (vecfunction != -1) + vsol = soldata[vecfunction]; + + if (mesh->GetTimeStamp () > solutiontimestamp) + { + sol = NULL; + vsol = NULL; + } + + + if (sol && sol->solclass) sol->solclass->SetMultiDimComponent (multidimcomponent); + if (vsol && vsol->solclass) vsol->solclass->SetMultiDimComponent (multidimcomponent); + + if (!autoscale || scalfunction == -1) + { + minval = mminval; + maxval = mmaxval; + } + else + { + if (mesh->GetTimeStamp () > surfeltimestamp || + vispar.clipplanetimestamp > clipplanetimestamp || + solutiontimestamp > surfeltimestamp) + { + GetMinMax (scalfunction, scalcomp, minval, maxval); + } + } + + + if (mesh->GetTimeStamp() > surfeltimestamp || + solutiontimestamp > surfeltimestamp || + zoomall) + { + if (mesh->GetTimeStamp() > surfeltimestamp || + zoomall) + { + // mesh has changed + + Point3d pmin, pmax; + static double oldrad = 0; + + mesh->GetBox (pmin, pmax, -1); + center = Center (pmin, pmax); + rad = 0.5 * Dist (pmin, pmax); + + glEnable (GL_NORMALIZE); + + if (rad > 1.5 * oldrad || + mesh->GetMajorTimeStamp() > surfeltimestamp || + zoomall) + { + CalcTransformationMatrices(); + oldrad = rad; + } + } + + if (surfellist) + glDeleteLists (surfellist, 1); + + surfellist = glGenLists (1); + glNewList (surfellist, GL_COMPILE); + + DrawSurfaceElements(); + + glEndList (); + + surfeltimestamp = max2 (solutiontimestamp, mesh->GetTimeStamp()); + } + + + if (mesh->GetTimeStamp() > surfellinetimestamp || + solutiontimestamp > surfellinetimestamp || + zoomall) + { + if (linelist) + glDeleteLists (linelist, 1); + + linelist = glGenLists (1); + glNewList (linelist, GL_COMPILE); + + DrawSurfaceElementLines(); + + glEndList (); + + surfellinetimestamp = max2 (solutiontimestamp, mesh->GetTimeStamp()); + } + + + + if (mesh->GetTimeStamp() > surface_vector_timestamp || + solutiontimestamp > surface_vector_timestamp || + zoomall) + { + if (surface_vector_list) + glDeleteLists (surface_vector_list, 1); + + surface_vector_list = glGenLists (1); + glNewList (surface_vector_list, GL_COMPILE); + + glEnable (GL_NORMALIZE); + DrawSurfaceVectors(); + + glEndList (); + + surface_vector_timestamp = + max2 (mesh->GetTimeStamp(), solutiontimestamp); + } + + + if (clipplanetimestamp < vispar.clipplanetimestamp || + clipplanetimestamp < solutiontimestamp) + { + + // cout << "clipsolution = " << clipsolution << endl; + if (vispar.clipenable && clipsolution) + { + // lock->UnLock(); + NgLock mlock (mesh->Mutex(), 0); + mlock.UnLock(); + mesh->BuildElementSearchTree(); + mlock.Lock(); + + // lock->Lock(); + } + + if (clipplanelist) + glDeleteLists (clipplanelist, 1); + + + clipplanelist = glGenLists (1); + glNewList (clipplanelist, GL_COMPILE); + + if (vispar.clipenable && clipsolution == 1 && sol) + { + glDisable(GL_CLIP_PLANE0); + + ARRAY<ClipPlaneTrig> cpt; + GetClippingPlaneTrigs (cpt); + + glNormal3d (-clipplane[0], -clipplane[1], -clipplane[2]); + + glBegin (GL_TRIANGLES); + for (i = 0; i < cpt.Size(); i++) + DrawClipPlaneTrig (sol, scalcomp, cpt[i], 0); // 2*subdivisions); + glEnd(); + + glEnable(GL_CLIP_PLANE0); + } + + + if (vispar.clipenable && clipsolution == 2 && vsol) + { + if (autoscale) + GetMinMax (vecfunction, 0, minval, maxval); + + + bool drawelem; + ARRAY<ClipPlanePoint> cpp; + GetClippingPlaneGrid (cpp); + + for (i = 0; i < cpp.Size(); i++) + { + const ClipPlanePoint & p = cpp[i]; + double values[6]; + Vec3d v; + + drawelem = GetValues (vsol, p.elnr, p.lam1, p.lam2, p.lam3, values); + RealVec3d (values, v, vsol->iscomplex, imag_part); + + double val = v.Length(); + + // "drawelem": added 07.04.2004 (FB) + if (drawelem && val > 1e-10 * maxval) + { + v *= (rad / val / gridsize * 0.5); + + SetOpenGlColor (val, minval, maxval, logscale); + DrawCone (p.p, p.p+v, rad / gridsize * 0.2); + } + } + } + + glEndList (); + } + + if ( + numisolines && + (clipplanetimestamp < vispar.clipplanetimestamp || + clipplanetimestamp < solutiontimestamp) + ) + { + if (isolinelist) glDeleteLists (isolinelist, 1); + + isolinelist = glGenLists (1); + glNewList (isolinelist, GL_COMPILE); + + Point<3> points[1100]; + double values[1100]; + + int nse = mesh->GetNSE(); + + if (sol) + { + glBegin (GL_LINES); + + for (SurfaceElementIndex sei = 0; sei < nse; sei++) + { + const Element2d & el = (*mesh)[sei]; + + if (el.GetType() == TRIG || el.GetType() == TRIG6) + { + Point<3> lp1, lp2, lp3; + if (!mesh->GetCurvedElements().IsHighOrder()) + { + GetPointDeformation (el[0]-1, lp1); + GetPointDeformation (el[1]-1, lp2); + GetPointDeformation (el[2]-1, lp3); + } + + int n = 1 << subdivisions; + int ii = 0; + int ix, iy; + for (iy = 0; iy <= n; iy++) + for (ix = 0; ix <= n-iy; ix++) + { + double x = double(ix) / n; + double y = double(iy) / n; + + // TODO: consider return value (bool: draw/don't draw element) + GetSurfValue (sol, sei, x, y, scalcomp, values[ii]); + Point<2> xref(x,y); + + if (mesh->GetCurvedElements().IsHighOrder()) + mesh->GetCurvedElements(). + CalcSurfaceTransformation (xref, sei, points[ii]); + else + points[ii] = lp3 + x * (lp1-lp3) + y * (lp2-lp3); + + if (deform) + { + Vec<3> def; + GetSurfDeformation (sei, x, y, def); + points[ii] += def; + } + ii++; + } + + ii = 0; + for (iy = 0; iy < n; iy++, 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]], + minval, maxval, numisolines); + if (ix < n-iy-1) + DrawIsoLines (points[index[3]], points[index[4]], points[index[5]], + values[index[3]], values[index[4]], values[index[5]], + minval, maxval, numisolines); + } + } + + + if (el.GetType() == QUAD || el.GetType() == QUAD6 || el.GetType() == QUAD8 ) + { + Point<3> lpi[4]; + Vec<3> vx, vy, vtwist, def; + if (!mesh->GetCurvedElements().IsHighOrder()) + { + for (int j = 0; j < 4; j++) + GetPointDeformation (el[j]-1, lpi[j]); + vx = lpi[1]-lpi[0]; + vy = lpi[3]-lpi[0]; + vtwist = (lpi[0]-lpi[1]) + (lpi[2]-lpi[3]); + } + + int n = 1 << subdivisions; + int ix, iy, ii = 0; + for (iy = 0; iy <= n; iy++) + for (ix = 0; ix <= n; ix++, ii++) + { + double x = double(ix) / n; + double y = double(iy) / n; + + // TODO: consider return value (bool: draw/don't draw element) + GetSurfValue (sol, sei, x, y, scalcomp, values[ii]); + Point<2> xref(x,y); + + if (mesh->GetCurvedElements().IsHighOrder()) + mesh->GetCurvedElements(). + CalcSurfaceTransformation (xref, sei, points[ii]); + else + points[ii] = lpi[0] + x * vx + y * vy + x*y * vtwist; + + if (deform) + { + GetSurfDeformation (sei, x, y, def); + points[ii] += def; + } + } + + 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], + minval, maxval, numisolines); + DrawIsoLines (points[ii+1], points[ii+n+2], points[ii+n+1], + values[ii+1], values[ii+n+2], values[ii+n+1], + minval, maxval, numisolines); + } + } + } + glEnd(); + } + glEndList (); + + if (clipplane_isolinelist) glDeleteLists (clipplane_isolinelist, 1); + + if (vispar.clipenable && clipsolution == 1 && sol) + { + clipplane_isolinelist = glGenLists (1); + glNewList (clipplane_isolinelist, GL_COMPILE); + + ARRAY<ClipPlaneTrig> cpt; + GetClippingPlaneTrigs (cpt); + bool drawelem; + + glNormal3d (-clipplane[0], -clipplane[1], -clipplane[2]); + + if (numisolines) + for (i = 0; i < cpt.Size(); i++) + { + const ClipPlaneTrig & trig = cpt[i]; + double vali[3]; + for (j = 0; j < 3; j++) + drawelem = GetValue (sol, trig.elnr, + trig.points[j].lami(0), + trig.points[j].lami(1), + trig.points[j].lami(2), scalcomp, vali[j]); + + if ( drawelem ) + DrawIsoLines (trig.points[0].p, + trig.points[1].p, + trig.points[2].p, + vali[0], vali[1], vali[2], minval, maxval, numisolines); + } + glEndList (); + } + glEnd(); + + + } + + clipplanetimestamp = max2 (vispar.clipplanetimestamp, solutiontimestamp); + } + + + void VisualSceneSolution :: BuildFieldLinesPlot () + { + if (fieldlinestimestamp >= solutiontimestamp) + return; + fieldlinestimestamp = solutiontimestamp; + + + if (fieldlineslist) + glDeleteLists (fieldlineslist, num_fieldlineslists); + + if (vecfunction == -1) + return; + + + const SolData * vsol = soldata[vecfunction]; + + num_fieldlineslists = (vsol -> iscomplex) ? 100 : 1; + + Point3d pmin, pmax; + mesh->GetBox (pmin, pmax); + double lami[3]; + int i; + bool drawelem; + + fieldlineslist = glGenLists (num_fieldlineslists); + + for (int ln = 0; ln < num_fieldlineslists; ln++) + { + glNewList (fieldlineslist + ln, GL_COMPILE); + + double phi = 2*M_PI*ln / num_fieldlineslists; + double phaser = cos(phi); + double phasei = sin(phi); + + for (i = 1; i <= num_fieldlines / num_fieldlineslists+1; i++) + { + Point3d p (pmin.X() + double (rand()) / RAND_MAX * (pmax.X()-pmin.X()), + pmin.Y() + double (rand()) / RAND_MAX * (pmax.Y()-pmin.Y()), + pmin.Z() + double (rand()) / RAND_MAX * (pmax.Z()-pmin.Z())); + + ElementIndex elnr = mesh->GetElementOfPoint (p, lami)-1; + (*testout) << "p = " << p << "; elnr = " << elnr << endl; + if (elnr != -1) + { + Vec3d v; + double values[6]; + drawelem = GetValues (vsol, elnr, lami[0], lami[1], lami[2], values); + RealVec3d (values, v, vsol->iscomplex, phaser, phasei); + + double val = v.Length(); + + if (!fieldlines_randomstart || + (double (rand()) / RAND_MAX) < (val / maxval)) + { + int i; + Point3d p0 = p; + v *= (rad / val * 0.02); + SetOpenGlColor (val, minval, maxval, logscale); + + Point3d p2 = p + v; + cout << " p " << p << endl; + // "drawelem": added 07.04.2004 (FB) + if ( drawelem ) DrawCylinder (p, p2, rad * 0.003); + p = p2; + + for(i=0;i<20;i++) + { + ElementIndex elnr = mesh->GetElementOfPoint (p, lami)-1; + + if (elnr != -1) + { + drawelem = GetValues (vsol, elnr, lami[0], lami[1], lami[2], values); + RealVec3d (values, v, vsol->iscomplex, phaser, phasei); + val = v.Length(); + v *= (rad / val * 0.02); + + SetOpenGlColor (val, minval, maxval, logscale); + p2 = p +v; + // "drawelem": added 07.04.2004 (FB) + if ( drawelem ) DrawCylinder (p, p2, rad * 0.003); + p = p2; + } + else break; + } + p=p0; + for(i=0;i<20;i++) + { + ElementIndex elnr = mesh->GetElementOfPoint (p, lami)-1; + + if (elnr != -1) + { + drawelem = GetValues (vsol, elnr, lami[0], lami[1], lami[2], values); + RealVec3d (values, v, vsol->iscomplex, phaser, phasei); + + val = v.Length(); + v *= (rad / val * 0.02); + + SetOpenGlColor (val, minval, maxval, logscale); + p2 = p - v; + // "drawelem": added 07.04.2004 (FB) + if ( drawelem ) DrawCylinder (p, p2, rad * 0.003); + p = p2; + } + else break; + } + } + } + } + glEndList (); + } + } + + + + + void VisualSceneSolution :: DrawSurfaceElements () + { + const SolData * sol = NULL; + const SolData * vsol = NULL; + bool drawelem = 0; + + if (scalfunction != -1) + sol = soldata[scalfunction]; + if (vecfunction != -1) + vsol = soldata[vecfunction]; + + if (mesh->GetTimeStamp () > solutiontimestamp) + { + sol = NULL; + vsol = NULL; + } + + glLineWidth (1.0f); + + if (!sol || !sol->draw_surface) + glDisable (GL_TEXTURE_1D); + + Point<3> points[1100]; + Vec<3> nvs[1100]; + double values[1100]; + + int nse = mesh->GetNSE(); + + glBegin (GL_TRIANGLES); + + // glColor3f (0.4, 0.4, 0.4); + // glColor3d (0.8, 0.8, 0.8); + glColor3d (1.0, 1.0, 1.0); + + for(SurfaceElementIndex sei = 0; sei < nse; sei++) + { + const Element2d & el = (*mesh)[sei]; + + if(vispar.drawdomainsurf > 0 && + ((mesh->GetDimension() == 3 && + vispar.drawdomainsurf != mesh->GetFaceDescriptor(el.GetIndex()).DomainIn() && + vispar.drawdomainsurf != mesh->GetFaceDescriptor(el.GetIndex()).DomainOut()) || + (mesh->GetDimension() == 2 && el.GetIndex() != vispar.drawdomainsurf))) continue; + + + if ( el.GetType() == TRIG || el.GetType() == TRIG6 ) + { + Point<3> p1, p2, p3; + if (!mesh->GetCurvedElements().IsHighOrder()) + { + GetPointDeformation (el[0]-1, p1, sei); + GetPointDeformation (el[1]-1, p2, sei); + GetPointDeformation (el[2]-1, p3, sei); + } + + int n = 1 << subdivisions; + int ii = 0; + for (int iy = 0; iy <= n; iy++) + for (int ix = 0; ix <= n-iy; ix++) + { + double x = double(ix) / n; + double y = double(iy) / n; + + if (sol && sol->draw_surface) + drawelem = GetSurfValue (sol, sei, x, y, scalcomp, values[ii]); + + Point<2> xref(x,y); + Mat<3,2> dxdxi; + + if (mesh->GetCurvedElements().IsHighOrder()) + { + mesh->GetCurvedElements(). + CalcSurfaceTransformation (xref, sei, points[ii], dxdxi); + nvs[ii] = Cross (dxdxi.Col(0), dxdxi.Col(1)); + nvs[ii].Normalize(); + } + else + { + points[ii] = p3 + x * (p1-p3) + y * (p2-p3); + nvs[ii] = Cross (p2-p1, p3-p1); + nvs[ii].Normalize(); + } + + if (deform) + { + Vec<3> def; + GetSurfDeformation (sei, x, y, def); + points[ii] += def; + } + ii++; + } + + ii = 0; + for (int iy = 0; iy < n; iy++, ii++) + for (int ix = 0; ix < n-iy; ix++, ii++) + { + double x = double(ix) / n; + double y = double(iy) / n; + + int index[] = { ii, ii+1, ii+n-iy+1, + ii+1, ii+n-iy+2, ii+n-iy+1 }; + + int np = (ix == n-iy-1) ? 3 : 6; + for (int j = 0; j < np; j++) + { + if (sol && sol->draw_surface && drawelem) + SetOpenGlColor (values[index[j]], minval, maxval, logscale); + else + glColor3f (0.4f, 0.4f, 0.4f); + + glNormal3dv (nvs[index[j]]); + glVertex3dv (points[index[j]]); + } + } + } + } + glEnd (); + + + + + + glBegin (GL_QUADS); + for (SurfaceElementIndex sei = 0; sei < nse; sei++) + { + const Element2d & el = (*mesh)[sei]; + + if(vispar.drawdomainsurf > 0 && + ((mesh->GetDimension() == 3 && + vispar.drawdomainsurf != mesh->GetFaceDescriptor(el.GetIndex()).DomainIn() && + vispar.drawdomainsurf != mesh->GetFaceDescriptor(el.GetIndex()).DomainOut()) || + (mesh->GetDimension() == 2 && el.GetIndex() != vispar.drawdomainsurf))) continue; + + if ( el.GetType() == QUAD || el.GetType() == QUAD6 ) + { + Point<3> lpi[4]; + Vec<3> vx, vy, vtwist; + + if (!mesh->GetCurvedElements().IsHighOrder()) + { + 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]); + } + Vec<3> nv = Cross (lpi[1]-lpi[0], Center (lpi[2],lpi[3]) - lpi[0]); + nv.Normalize(); + glNormal3dv (nv); + + int n = 1 << subdivisions; + int ii = 0; + int ix, iy; + for (iy = 0; iy <= n; iy++) + for (ix = 0; ix <= n; ix++) + { + double x = double(ix) / n; + double y = double(iy) / n; + + Point<2> xref(x,y); + Mat<3,2> dxdxi; + + if (sol && sol->draw_surface) + drawelem = GetSurfValue (sol, sei, x, y, scalcomp, values[ii]); + + if (mesh->GetCurvedElements().IsHighOrder()) + { + mesh->GetCurvedElements(). + CalcSurfaceTransformation (xref, sei, points[ii], dxdxi); + nvs[ii] = Cross (dxdxi.Col(0), dxdxi.Col(1)); + nvs[ii].Normalize(); + } + else + { + points[ii] = lpi[0] + x * vx + y * vy + x*y * vtwist; + nvs[ii] = Cross (vx, vy); + nvs[ii].Normalize(); + } + + if (deform) + { + Vec<3> def; + GetSurfDeformation (sei, x, y, def); + points[ii] += def; + } + + ii++; + } + + ii = 0; + for (iy = 0; iy < n; iy++, ii++) + for (ix = 0; ix < n; ix++, ii++) + { + double x = double(ix) / n; + double y = double(iy) / n; + + int index[] = { ii, ii+1, ii+n+2, ii+n+1 }; + + for (int j = 0; j < 4; j++) + { + if (sol && sol->draw_surface && drawelem) + SetOpenGlColor (values[index[j]], minval, maxval, logscale); + else + glColor3f (0.4f, 0.4f, 0.4f); + + glNormal3dv (nvs[index[j]]); + glVertex3dv (points[index[j]]); + } + } + } + } + glEnd(); + + if (usetexture) + glEnable (GL_TEXTURE_1D); + } + + + // Bernstein Pol B_{n,i}(x) = n! / i! / (n-i)! (1-x)^{n-i} x^i + static double Bernstein (int n, int i, double x) + { + int j; + double val = 1; + for (j = 1; j <= i; j++) + val *= x / j; + for (j = 1; j <= n-i; j++) + val *= (1-x) / j; + for (j = 1; j <= n; j++) + val *= j; + return val; + } + + void VisualSceneSolution :: DrawSurfaceElementLines () + { + int i, j, k, l; + SurfaceElementIndex sei; + + /* + int p = 4; + DenseMatrix mat(p+1,p+1), invmat(p+1,p+1); + for (i = 0; i <= p; i++) + for (j = 0; j <= p; j++) + mat.Elem(i+1,j+1) = Bernstein(p, i, double(j)/p); + CalcIo +nverse (mat, invmat); + */ + + glLineWidth (1.0f); + glNormal3d (1, 0, 0); + + int nse = mesh->GetNSE(); + + for (sei = 0; sei < nse; sei++) + { + Element2d & el = (*mesh)[sei]; + + int nv; + if (el.GetType() == TRIG || el.GetType() == TRIG6) + nv = 3; + else + nv = 4; + + Point<3> p1, p2, p3, p4; + if (!mesh->GetCurvedElements().IsHighOrder()) + { + p1 = (*mesh)[el[0]]; + p2 = (*mesh)[el[1]]; + p3 = (*mesh)[el[2]]; + if (nv == 4) + p4 = (*mesh)[el[3]]; + } + + + // glBegin (GL_LINE_LOOP); + int n = 1 << subdivisions; + // n = p; + + Point<3> pnt; + for (k = 0; k < nv; k++) + { + Point<2> p0; + Vec<2> vtau; + if (nv == 3) + switch (k) + { + case 0: + p0 = Point<2> (0,0); + vtau = Vec<2> (1,0); + break; + case 1: + p0 = Point<2> (1,0); + vtau = Vec<2> (-1,1); + break; + case 2: + p0 = Point<2> (0,1); + vtau = Vec<2> (0,-1); + break; + } + else + switch (k) + { + case 0: + p0 = Point<2> (0,0); + vtau = Vec<2> (1,0); + break; + case 1: + p0 = Point<2> (1,0); + vtau = Vec<2> (0,1); + break; + case 2: + p0 = Point<2> (1,1); + vtau = Vec<2> (-1,0); + break; + case 3: + p0 = Point<2> (0,1); + vtau = Vec<2> (0,-1); + break; + } + + + glBegin (GL_LINE_STRIP); + Point<3> pts[33], pts2[33]; + if (n > 32) cerr << "too many subdivisions, code 433425" << endl; + + for (int ix = 0; ix <= n; ix++) + { + Point<2> p = p0 + (double(ix) / n) * vtau; + double x = p(0); + double y = p(1); + + if (mesh->GetCurvedElements().IsHighOrder()) + mesh->GetCurvedElements(). + CalcSurfaceTransformation (p, sei, pnt); + else + { + if (nv == 3) + pnt = p3 + x * (p1-p3) + y * (p2-p3); + else + pnt = p1 + x * (p2-p1) + y * (p4-p1) + x*y * ( (p1-p2)+(p3-p4) ); + } + + if (deform) + { + Vec<3> def; + GetSurfDeformation (sei, x, y, def); + pnt += def; + } + + glVertex3dv (pnt); + + pts[ix] = pnt; + } + glEnd (); + + + + + + /* + // convert from point-values to Bernstein basis + for (i = 0; i < 3; i++) + for (j = 0; j <= p; j++) + { + pts2[j](i) = 0; + for (l = 0; l <= p; l++) + pts2[j](i) += invmat(l,j) * pts[l](i); + } + + + glMap1d(GL_MAP1_VERTEX_3, 0.0, 1.0, 3, n+1, &pts2[0](0)); + glEnable(GL_MAP1_VERTEX_3); + + int steps = 1 << subdivisions; + +// glBegin (GL_LINE_STRIP); +// for (int hi = 0; hi <= 10; hi++) +// glEvalCoord1d (double(hi)/10.0); +// glEnd (); + + glMapGrid1d (steps, 0.0, 1.0); + glEvalMesh1(GL_LINE, 0, steps); + glDisable(GL_MAP1_VERTEX_3); + */ + } + + } + + } + + + + + + + + + + + + + + + + + + + + +void VisualSceneSolution :: DrawSurfaceVectors () +{ + int j, k; + int dir, dir1, dir2; + SurfaceElementIndex sei; + + const SolData * vsol = NULL; + 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); + + double s, t; + + // draw surface cones + // if (0) + /* + if (vsol->soltype==SOL_SURFACE_ELEMENT || + vsol->soltype==SOL_SURFACE_NONCONTINUOUS || + vsol->soltype==SOL_VIRTUALFUNCTION) + */ + + if (vsol->draw_surface && showsurfacesolution) + { + int nse = mesh->GetNSE(); + for (sei = 0; sei < nse; sei++) + { + const Element2d & el = (*mesh)[sei]; + + if (el.GetType() != TRIG && el.GetType() != TRIG6) continue; + + Point<3> lp[3]; + Point<2> p2d[3]; + /* + for (k = 0; k < 3; k++) + lp[k] = mesh->Point (el[k]); + */ + lp[0] = mesh->Point(el[2]); + lp[1] = mesh->Point(el[0]); + lp[2] = mesh->Point(el[1]); + + + Vec<3> n = Cross (lp[1]-lp[0], lp[2]-lp[0]); + Vec<3> na (fabs (n(0)), fabs(n(1)), fabs(n(2))); + if (na(0) > na(1) && na(0) > na(2)) + dir = 1; + else if (na(1) > na(2)) + dir = 2; + else + dir = 3; + + dir1 = (dir % 3) + 1; + dir2 = (dir1 % 3) + 1; + + for (k = 0; k < 3; k++) + { + p2d[k] = Point<2> ((lp[k](dir1-1) - pmin(dir1-1)) / (2*rad), + (lp[k](dir2-1) - pmin(dir2-1)) / (2*rad)); + } + + double minx2d, maxx2d, miny2d, maxy2d; + minx2d = maxx2d = p2d[0](0); + miny2d = maxy2d = p2d[0](1); + for (k = 1; k < 3; k++) + { + minx2d = min2 (minx2d, p2d[k](0)); + maxx2d = max2 (maxx2d, p2d[k](0)); + miny2d = min2 (miny2d, p2d[k](1)); + maxy2d = max2 (maxy2d, p2d[k](1)); + } + + double mat11 = p2d[1](0) - p2d[0](0); + double mat21 = p2d[1](1) - p2d[0](1); + double mat12 = p2d[2](0) - p2d[0](0); + double mat22 = p2d[2](1) - p2d[0](1); + + double det = mat11*mat22-mat21*mat12; + double inv11 = mat22/det; + double inv21 = -mat21/det; + double inv12 = -mat12/det; + double inv22 = mat11/det; + + // 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); + // "drawelem": added 07.04.2004 (FB) + if ( drawelem ) DrawCone (cp, cp+4*v, 0.8*rad / gridsize); + + + /* + v /= val; + + glPushMatrix(); + glTranslated (cp(0), cp(1), cp(2)); + + double l = 2*rad/gridsize; + double r = 0.8*rad/gridsize; + glScaled (l, l, l); + + double phi = acos (v(2)); + glRotated (-180/M_PI*phi, v(1), -v(0), 0); + + glCallList (cone_list); + glPopMatrix(); + */ + } + } + } + } +} + + + + +void VisualSceneSolution :: +DrawIsoLines (const Point3d & p1, + const Point3d & p2, + const Point3d & p3, + double val1, double val2, double val3, + double minval, double maxval, int n) +{ + DrawIsoLines2 (p1, p2, p1, p3, val1, val2, val1, val3, minval, maxval, n); + DrawIsoLines2 (p2, p1, p2, p3, val2, val1, val2, val3, minval, maxval, n); + DrawIsoLines2 (p3, p1, p3, p2, val3, val1, val3, val2, minval, maxval, n); +} + +void VisualSceneSolution :: +DrawIsoLines2 (const Point3d & p1, + const Point3d & p2, + const Point3d & p3, + const Point3d & p4, + double val1, double val2, double val3, double val4, + double minval, double maxval, int n) +{ + if (val1 > val2) + DrawIsoLines2 (p2, p1, p3, p4, val2, val1, val3, val4, minval, maxval, n); + if (val3 > val4) + DrawIsoLines2 (p1, p2, p4, p3, val1, val2, val4, val3, minval, maxval, n); + + val2 += 1e-10; + val4 += 1e-10; + + double fac = (maxval-minval) / n; + double idelta1 = 1.0 / (val2 - val1); + double idelta2 = 1.0 / (val4 - val3); + + int mini = int ((max2 (val1, val3) - minval) / fac); + int maxi = int ((min2 (val2, val4) - minval) / fac); + if (mini < 0) mini = 0; + if (maxi > n-1) maxi = n-1; + + for (int i = mini; i <= maxi+1; i++) + { + double val = minval + i * fac; + double lam1 = (val - val1) * idelta1; + double lam2 = (val - val3) * idelta2; + if (lam1 >= 0 && lam1 <= 1 && lam2 >= 0 && lam2 <= 1) + { + Point3d lp1 = p1 + lam1 * Vec3d (p1, p2); + Point3d lp2 = p3 + lam2 * Vec3d (p3, p4); + glVertex3d (lp1.X(), lp1.Y(), lp1.Z()); + glVertex3d (lp2.X(), lp2.Y(), lp2.Z()); + glVertex3d (lp2.X(), lp2.Y(), lp2.Z()); + glVertex3d (lp1.X(), lp1.Y(), lp1.Z()); + } + } +} + + + + + + + +void VisualSceneSolution :: +GetMinMax (int funcnr, int comp, double & minv, double & maxv) const +{ + int i, j; + const SolData * sol; + double val; + bool considerElem; + + bool hasit = false; + minv = 0; maxv = 1; + if (funcnr != -1) + { + sol = soldata[funcnr]; + if (sol->draw_volume) + { + int ne = mesh->GetNE(); + for (int i = 0; i < ne; i++) + { + // "considerElem": added 07.04.2004 (FB) + considerElem = GetValue (sol, i, 0.333, 0.333, 0.333, comp, val); + if (considerElem) + { + if (val > maxv || !hasit) + maxv = val; + if (val < minv || !hasit) + minv = val; + hasit = true; + } + } + } + if (sol->draw_surface) + { + int nse = mesh->GetNSE(); + for (int i = 0; i < nse; i++) + { + // "considerElem": added 07.04.2004 (FB) + considerElem = GetSurfValue (sol, i, 0.333, 0.333, comp, val); + if (considerElem) + { + if (val > maxv || !hasit) + maxv = val; + if (val < minv || !hasit) + minv = val; + hasit = true; + } + } + } + } +} + + + + + +bool VisualSceneSolution :: +GetValues (const SolData * data, ElementIndex elnr, + double lam1, double lam2, double lam3, + double * values) const +{ + bool ok; + 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 :: +GetValue (const SolData * data, ElementIndex elnr, + double lam1, double lam2, double lam3, + int comp, double & val) const +{ + val = 0; + bool ok = 0; + + if (comp == 0) + { + ArrayMem<double,20> values(data->components); + ok = GetValues (data, elnr, lam1, lam2, lam3, &values[0]); + + switch (evalfunc) + { + case FUNC_ABS: + { + for (int ci = 0; ci < data->components; ci++) + val += sqr (values[ci]); + val = sqrt (val); + break; + } + case FUNC_ABS_TENSOR: + { + int d; + switch (data->components) + { + case 1: d = 1; break; + case 3: d = 2; break; + case 6: d = 3; break; + } + int ci; + for (ci = 0; ci < d; ci++) + val += sqr (values[ci]); + for (ci = d; ci < data->components; ci++) + val += 2*sqr (values[ci]); + val = sqrt (val); + break; + } + + case FUNC_MISES: + { + int d; + switch(data->components) + { + case 1: d = 1; break; + case 3: d = 2; break; + case 6: d = 3; break; + } + int ci; + double trace = 0.; + for (ci = 0; ci < d; ci++) + trace += 1./3.*(values[ci]); + for (ci = 0; ci < d; ci++) + val += sqr (values[ci]-trace); + for (ci = d; ci < data->components; ci++) + val += 2.*sqr (values[ci]); + val = sqrt (val); + break; + } + case FUNC_MAIN: + { + int d; + switch(data->components) + { + case 1: d = 1; break; + case 3: d = 2; break; + case 6: d = 3; break; + } + Mat<3,3> m ; + Vec<3> ev; + int ci; + for (ci = 0; ci < d; ci++) + m(ci,ci) = (values[ci]); + m(0,1) = m(1,0) = values[3]; + m(0,2) = m(2,0) = values[4]; + m(1,2) = m(2,1) = values[5]; + + EigenValues (m, ev); + double help; + for (int i=0; i<d; i++) + { + for (int j=d-1; i<j; j--) + { + if ( abs(ev(j)) > abs(ev(j-1)) ) + { + help = ev(j); + ev(j) = ev(j-1); + ev(j-1) = help; + } + } + } + val = (ev(0)); + break; + } + } + + return ok; + } + + + switch (data->soltype) + { + case SOL_VIRTUALFUNCTION: + { + double values[20]; + ok = data->solclass->GetValue (elnr, lam1, lam2, lam3, values); + + val = values[comp-1]; + return ok; + } + case SOL_NODAL: + { + const Element & el = (*mesh)[elnr]; + + double lami[8]; + int np, i; + + switch (el.GetType()) + { + case TET: + case TET10: + { + lami[1] = lam1; + lami[2] = lam2; + lami[3] = lam3; + lami[0] = 1-lam1-lam2-lam3; + np = 4; + break; + } + case PRISM: + case PRISM12: + { + lami[0] = (1-lam3) * (1-lam1-lam2); + lami[1] = (1-lam3) * lam1; + lami[2] = (1-lam3) * lam2; + lami[3] = (lam3) * (1-lam1-lam2); + lami[4] = (lam3) * lam1; + lami[5] = (lam3) * lam2; + np = 6; + break; + } + } + + for (i = 0; i < np; i++) + val += lami[i] * data->data[(el[i]-1) * data->dist + comp-1]; + + return 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]; + int np, i; + + switch (el.GetType()) + { + case TET: + case TET10: + { + lami[1] = lam1; + lami[2] = lam2; + lami[3] = lam3; + lami[0] = 1-lam1-lam2-lam3; + np = 4; + break; + } + case PRISM: + case PRISM12: + { + lami[0] = (1-lam3) * (1-lam1-lam2); + lami[1] = (1-lam3) * lam1; + lami[2] = (1-lam3) * lam2; + lami[3] = (lam3) * (1-lam1-lam2); + lami[4] = (lam3) * lam1; + lami[5] = (lam3) * lam2; + np = 6; + break; + } + case PYRAMID: + { + if (lam3 > 1-1e-5) + { + lami[0] = lami[1] = lami[2] = lami[3] = 0; + lami[4] = 1; + } + else + { + double x0 = lam1 / (1-lam3); + double y0 = lam2 / (1-lam3); + lami[0] = (1-x0) * (1-y0) * (1-lam3); + lami[1] = ( x0) * (1-y0) * (1-lam3); + lami[2] = ( x0) * ( y0) * (1-lam3); + lami[3] = (1-x0) * ( y0) * (1-lam3); + lami[4] = lam3; + np = 5; + } + break; + } + default: + np = 0; + } + + int base; + if (data->order == 1) + base = 6 * elnr; + else + base = 10 * elnr; + + + for (i = 0; i < np; i++) + val += lami[i] * data->data[(base+i) * data->dist + comp-1]; + + return 1; + } + + case SOL_MARKED_ELEMENTS: + { + val = (*mesh)[elnr].TestRefinementFlag(); + return 1; + } + + case SOL_ELEMENT_ORDER: + { + val = (*mesh)[elnr].GetOrder(); + return 1; + } + } + return 0; +} + + + + +bool VisualSceneSolution :: +GetSurfValues (const SolData * data, SurfaceElementIndex selnr, + double lam1, double lam2, + double * values) const +{ + bool ok; + switch (data->soltype) + { + case SOL_VIRTUALFUNCTION: + { + ok = data->solclass->GetSurfValue (selnr, lam1, lam2, values); + break; + } + default: + { + for (int i = 0; i < data->components; i++) + ok = GetSurfValue (data, selnr, lam1, lam2, i+1, values[i]); + } + } + return ok; +} + + + +bool VisualSceneSolution :: +GetSurfValue (const SolData * data, SurfaceElementIndex selnr, + double lam1, double lam2, + int comp, double & val) const +{ + bool ok; + if (comp == 0) + { + val = 0; + ArrayMem<double,20> values(data->components); + ok = GetSurfValues (data, selnr, lam1, lam2, &values[0]); + + switch (evalfunc) + { + case FUNC_ABS: + { + for (int ci = 0; ci < data->components; ci++) + val += sqr (values[ci]); + val = sqrt (val); + break; + } + case FUNC_ABS_TENSOR: + { + int d; + switch (data->components) + { + case 1: d = 1; break; + case 3: d = 2; break; + case 6: d = 3; break; + } + int ci; + for (ci = 0; ci < d; ci++) + val += sqr (values[ci]); + for (ci = d; ci < data->components; ci++) + val += 2*sqr (values[ci]); + val = sqrt (val); + break; + } + + case FUNC_MISES: + { + int d; + switch(data->components) + { + case 1: d = 1; break; + case 3: d = 2; break; + case 6: d = 3; break; + } + int ci; + double trace = 0.; + for (ci = 0; ci < d; ci++) + trace += 1./3.*(values[ci]); + for (ci = 0; ci < d; ci++) + val += sqr (values[ci]-trace); + for (ci = d; ci < data->components; ci++) + val += 2.*sqr (values[ci]); + val = sqrt (val); + break; + } + case FUNC_MAIN: + { + int d; + switch(data->components) + { + case 1: d = 1; break; + case 3: d = 2; break; + case 6: d = 3; break; + } + Mat<3,3> m ; + Vec<3> ev; + int ci; + for (ci = 0; ci < d; ci++) + m(ci,ci) = (values[ci]); + m(0,1) = m(1,0) = values[3]; + m(0,2) = m(2,0) = values[4]; + m(1,2) = m(2,1) = values[5]; + + EigenValues (m, ev); + double help; + for (int i=0; i<d; i++) + { + for (int j=d-1; i<j; j--) + { + if ( abs(ev(j)) > abs(ev(j-1)) ) + { + help = ev(j); + ev(j) = ev(j-1); + ev(j-1) = help; + } + } + } + val = (ev(0)); + break; + } + } + + return ok; + + + /* + int ci; + double val = 0; + for (ci = 1; ci <= data->components; ci++) + val += sqr (GetSurfValue (data, selnr, lam1, lam2, ci)); + return sqrt (val); + */ + } + + + switch (data->soltype) + { + case SOL_VIRTUALFUNCTION: + { + ArrayMem<double,20> values(data->components); + bool ok; + + ok = data->solclass->GetSurfValue (selnr, lam1, lam2, &values[0]); + + if (ok) + { + if (!data->iscomplex) + val = values[comp-1]; + else + { + // cout << "time = " << time << ", cos = " << cos(time) << endl; + val = values[comp-1]*cos(3*time) + values[comp]*sin(3*time); + } + } + + return ok; + } + + + case SOL_NODAL: + { + const Element2d & el = (*mesh)[selnr]; + + double lami[8]; + int np, i; + val = 0; + double lam3 = 1-lam1-lam2; + + switch (el.GetType()) + { + case TRIG: + /* + lami[0] = lam3; + lami[1] = lam1; + lami[2] = lam2; + */ + lami[0] = lam1; + lami[1] = lam2; + lami[2] = lam3; + np = 3; + break; + + case TRIG6: + /* + lami[0] = lam3*(2*lam3-1); + lami[1] = lam1*(2*lam1-1); + lami[2] = lam2*(2*lam2-1); + */ + // hierarchical basis: + lami[0] = lam3; + lami[1] = lam1; + lami[2] = lam2; + lami[3] = 4*lam1*lam2; + lami[4] = 4*lam2*lam3; + lami[5] = 4*lam1*lam3; + np = 6; + break; + + case QUAD: + case QUAD6: + lami[0] = (1-lam1)*(1-lam2); + lami[1] = lam1 * (1-lam2); + lami[2] = lam1 * lam2; + lami[3] = (1-lam1) * lam2; + np = 4; + break; + + default: + np = 0; + } + + for (i = 0; i < np; i++) + val += lami[i] * data->data[(el[i]-1) * data->dist + comp-1]; + + return 1; + } + + case SOL_ELEMENT: + { + int el1, el2; + mesh->GetTopology().GetSurface2VolumeElement (selnr+1, el1, el2); + el1--; + + val = data->data[el1 * data->dist+comp-1]; + return 1; + } + + case SOL_NONCONTINUOUS: + { + val = 0; + // ????? + return 0; + } + + case SOL_SURFACE_ELEMENT: + { + val = data->data[selnr * data->dist + comp-1]; + return 1; + } + + case SOL_SURFACE_NONCONTINUOUS: + { + const Element2d & el = (*mesh)[selnr]; + + double lami[8]; + int np, i; + val = 0; + int order = data->order; + + switch (order) + { + case 0: + return data->data[selnr * data->dist + comp-1]; + case 1: + { + switch (el.GetType()) + { + case TRIG: + case TRIG6: + { + lami[1] = lam1; + lami[2] = lam2; + lami[0] = 1-lam1-lam2; + np = 3; + break; + } + } + break; + } + case 2: + { + switch (el.GetType()) + { + case TRIG: + { + lami[1] = lam1; + lami[2] = lam2; + lami[0] = 1-lam1-lam2; + np = 3; + break; + } + case TRIG6: + { + double lam3 = 1-lam1-lam2; + lami[1] = 2*lam1 * (lam1-0.5); + lami[2] = 2*lam2 * (lam2-0.5); + lami[0] = 2*lam3 * (lam3-0.5); + lami[3] = 4*lam1*lam2; + lami[4] = 4*lam2*lam3; + lami[5] = 4*lam1*lam3; + np = 6; + break; + } + } + break; + } + } + + int base; + if (order == 1) + base = 4 * selnr; + else + base = 9 * selnr; + + for (i = 0; i < np; i++) + { + val += lami[i] * data->data[(base+i) * data->dist + comp-1]; + } + return 1; + } + + case SOL_MARKED_ELEMENTS: + { + val = (*mesh)[selnr].TestRefinementFlag(); + return 1; + } + + case SOL_ELEMENT_ORDER: + { + val = (*mesh)[selnr].GetOrder(); + return 1; + } + + } + return 0; +} + + +void VisualSceneSolution :: +GetDeformation (ElementIndex elnr, double lam1, double lam2, double lam3, + Vec<3> & def) const +{ + if (deform && vecfunction != -1) + { + GetValues (soldata[vecfunction], elnr, lam1, lam2, lam3, &def(0)); + def *= scaledeform; + + if (soldata[vecfunction]->dist == 2) def(2) = 0; + } + else + def = 0; +} + + +void VisualSceneSolution :: +GetSurfDeformation (SurfaceElementIndex elnr, double lam1, double lam2, + Vec<3> & def) const +{ + if (deform && vecfunction != -1) + { + GetSurfValues (soldata[vecfunction], elnr, lam1, lam2, &def(0)); + def *= scaledeform; + + if (soldata[vecfunction]->dist == 2) def(2) = 0; + } + else + def = 0; +} + +void VisualSceneSolution :: GetPointDeformation (int pnum, Point<3> & p, + SurfaceElementIndex elnr) const +{ + p = mesh->Point (pnum+1); + + if (deform && vecfunction != -1) + { + const SolData * vsol = soldata[vecfunction]; + + Vec<3> v(0,0,0); + if (vsol->soltype == SOL_NODAL) + { + v = Vec3d(vsol->data[pnum * vsol->dist], + vsol->data[pnum * vsol->dist+1], + vsol->data[pnum * vsol->dist+2]); + } + else if (vsol->soltype == SOL_SURFACE_NONCONTINUOUS) + { + const Element2d & el = (*mesh)[elnr]; + for (int j = 0; j < el.GetNP(); j++) + if (el[j] == pnum+1) + { + int base = (4*elnr+j-1) * vsol->dist; + v = Vec3d(vsol->data[base], + vsol->data[base+1], + vsol->data[base+2]); + } + } + + if (vsol->dist == 2) v(2) = 0; + + v *= scaledeform; + p += v; + } +} + + + + + + + + +void VisualSceneSolution :: GetClippingPlaneTrigs (ARRAY<ClipPlaneTrig> & trigs) +{ + // cout << "get clipplane trigs" << endl; + + int ii, j, k, l; + ElementIndex ei; + + int np = mesh->GetNP(); + int ne = mesh->GetNE(); + + ARRAY<double> nodevals(np); + + for (int i = 0; i < np; i++) + { + Point<3> p; + GetPointDeformation(i, p); + nodevals[i] = + p(0) * clipplane[0] + + p(1) * clipplane[1] + + p(2) * clipplane[2] + + clipplane[3]; + } + + const int edgei[6][2] = + { + { 0, 1 }, + { 0, 2 }, + { 0, 3 }, + { 1, 2 }, + { 1, 3 }, + { 2, 3 } + }; + double edgelam[6]; + Point<3> edgep[6]; + double nodevali[4]; + + int cntce; + int cpe1 = 0, cpe2 = 0, cpe3 = 0; + + ARRAY<Element> loctets; + ARRAY<Element> loctetsloc; + ARRAY<Point3d> pointsloc; + + + int n = 1 << subdivisions; + ARRAY<Point<3> > grid((n+1)*(n+1)*(n+1)); + ARRAY<Point<3> > locgrid((n+1)*(n+1)*(n+1)); + ARRAY<double> val((n+1)*(n+1)*(n+1)); + + + for (ei = 0; ei < ne; ei++) + { + ELEMENT_TYPE type = (*mesh)[ei].GetType(); + if (type == HEX || type == PRISM || type == TET || type == PYRAMID) + { + const Element & el = (*mesh)[ei]; + + Vector shape(el.GetNP()); + + int ii = 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; + if (type == PRISM) + ploc = Point<3> (double(ix) / n * (1-double(iy)/n), double(iy) / n, double(iz) / n); + if (type == TET) + ploc = Point<3> (double(ix) / n * (1-double(iy)/n) * (1-double(iz)/n), + double(iy) / n * (1-double(iz)/n), + double(iz) / n); + if (type == HEX) + ploc = Point<3> (double(ix) / n, double(iy) / n, double(iz) / n); + if (type == PYRAMID) + ploc = Point<3> (double(ix) / n * (1-double(iz)/n), + double(iy) / n * (1-double(iz)/n), + double(iz)/n); + + Point<3> pglob; + + if (mesh->GetCurvedElements().IsHighOrder()) + { + mesh->GetCurvedElements(). + CalcElementTransformation (ploc, ei, pglob); + } + else + { + el.GetShapeNew (ploc, shape); + for (int j = 0; j < 3; j++) + { + pglob(j) = 0; + for (int k = 0; k < el.GetNP(); k++) + pglob(j) += shape(k) * (*mesh)[el[k]].X(j+1); + } + } + + locgrid[ii] = ploc; + grid[ii] = pglob; + val[ii] = + pglob(0) * clipplane[0] + + pglob(1) * clipplane[1] + + pglob(2) * clipplane[2] + + clipplane[3]; + } + + 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 }; + + int tets[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 (int ii = 0; ii < 6; ii++) + { + int teti[4]; + for (int k = 0; k < 4; k++) + teti[k] = pi[tets[ii][k]-1]; + + for (j = 0; j < 4; j++) + nodevali[j] = val[teti[j]]; + + cntce = 0; + for (j = 0; j < 6; j++) + { + int lpi1 = edgei[j][0]; + int lpi2 = edgei[j][1]; + if ( (nodevali[lpi1] > 0) != + (nodevali[lpi2] > 0) ) + { + edgelam[j] = nodevali[lpi2] / (nodevali[lpi2] - nodevali[lpi1]); + Point<3> p1 = grid[teti[lpi1]]; + Point<3> p2 = grid[teti[lpi2]]; + + edgep[j] = p1 + (1-edgelam[j]) * (p2-p1); + + cntce++; + cpe3 = cpe2; + cpe2 = cpe1; + cpe1 = j; + if (cntce >= 3) + { + ClipPlaneTrig cpt; + cpt.elnr = ei; + + for (int k = 0; k < 3; k++) + { + int ednr; + switch (k) + { + case 0: ednr = cpe1; break; + case 1: ednr = cpe2; break; + case 2: ednr = cpe3; break; + } + cpt.points[k].p = edgep[ednr]; + + int pi1 = edgei[ednr][0]; + int pi2 = edgei[ednr][1]; + Point<3> p1 = locgrid[teti[pi1]]; + Point<3> p2 = locgrid[teti[pi2]]; + for (l = 0; l < 3; l++) + cpt.points[k].lami(l) = + edgelam[ednr] * p1(l) + + (1-edgelam[ednr]) * p2(l); + } + + trigs.Append (cpt); + } + } + } + } + } + } + + else + { + + // const Element & el = mesh->VolumeElement(i); + + (*mesh)[ei].GetTets (loctets); + (*mesh)[ei].GetTetsLocal (loctetsloc); + // (*mesh)[ei].GetNodesLocal (pointsloc); + (*mesh)[ei].GetNodesLocalNew (pointsloc); + + for (ii = 0; ii < loctets.Size(); ii++) + { + const Element & el = loctets[ii]; + + for (j = 0; j < 4; j++) + nodevali[j] = nodevals.Get(el[j]); + + cntce = 0; + for (j = 0; j < 6; j++) + { + int lpi1 = edgei[j][0]; + int lpi2 = edgei[j][1]; + if ( (nodevali[lpi1] > 0) != + (nodevali[lpi2] > 0) ) + { + edgelam[j] = nodevali[lpi2] / (nodevali[lpi2] - nodevali[lpi1]); + Point<3> p1, p2; + GetPointDeformation (el[lpi1]-1, p1); + GetPointDeformation (el[lpi2]-1, p2); + + edgep[j] = p1 + (1-edgelam[j]) * (p2-p1); + + cntce++; + cpe3 = cpe2; + cpe2 = cpe1; + cpe1 = j; + if (cntce >= 3) + { + ClipPlaneTrig cpt; + cpt.elnr = ei; + + for (k = 0; k < 3; k++) + { + int ednr; + switch (k) + { + case 0: ednr = cpe1; break; + case 1: ednr = cpe2; break; + case 2: ednr = cpe3; break; + } + cpt.points[k].p = edgep[ednr]; + + int pi1 = edgei[ednr][0]; + int pi2 = edgei[ednr][1]; + Point<3> p1 = pointsloc.Get (loctetsloc[ii][pi1]); + Point<3> p2 = pointsloc.Get (loctetsloc[ii][pi2]); + for (l = 0; l < 3; l++) + cpt.points[k].lami(l) = + edgelam[ednr] * p1(l) + + (1-edgelam[ednr]) * p2(l); + } + + trigs.Append (cpt); + } + } + } + } + } + + } +} + +void VisualSceneSolution :: GetClippingPlaneGrid (ARRAY<ClipPlanePoint> & pts) +{ + int i, j, k; + int np = mesh->GetNV(); + int ne = mesh->GetNE(); + + Vec3d n(clipplane[0], clipplane[1], clipplane[2]); + + double mu = -clipplane[3] / n.Length2(); + Point3d p(mu*n.X(), mu * n.Y(), mu * n.Z()); + + n /= n.Length(); + Vec3d t1, t2; + n.GetNormal (t1); + t2 = Cross (n, t1); + + double xi1, xi2; + + double xi1mid = (center - p) * t1; + double xi2mid = (center - p) * t2; + + pts.SetSize(0); + + int elnr; + double lami[3]; + + // cout << "getclippingplanegrid. xoffset = " << xoffset << ", yoffset = "; + // cout << yoffset << endl; + + 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) + // for (xi1 = xi1mid-rad; xi1 <= xi1mid+rad; xi1 += rad / gridsize) + // for (xi2 = xi2mid-rad; xi2 <= xi2mid+rad; xi2 += rad / gridsize) + { + Point3d hp = p + xi1 * t1 + xi2 * t2; + + elnr = mesh->GetElementOfPoint (hp, lami)-1; + + if (elnr != -1) + { + ClipPlanePoint cpp; + cpp.p = hp; + cpp.elnr = elnr; + cpp.lam1 = lami[0]; + cpp.lam2 = lami[1]; + cpp.lam3 = lami[2]; + pts.Append (cpp); + } + } +}; + + + +void VisualSceneSolution :: +SetOpenGlColor(double h, double hmin, double hmax, int logscale) +{ + double value; + + if (!logscale) + value = (h - hmin) / (hmax - hmin); + else + { + if (hmax <= 0) hmax = 1; + if (hmin <= 0) hmin = 1e-4 * hmax; + value = (log(fabs(h)) - log(hmin)) / (log(hmax) - log(hmin)); + } + + if (!invcolor) + value = 1 - value; + + if (usetexture) + { + glTexCoord1f ( 0.999 * value + 0.001); + return; + }; + + if (value > 1) value = 1; + if (value < 0) value = 0; + + value *= 4; + + 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 VisualSceneSolution :: +DrawCone (const Point<3> & p1, const Point<3> & p2, double r) +{ + int n = 10, i; + Vec<3> p1p2 = p2 - p1; + + p1p2.Normalize(); + Vec<3> p2p1 = -p1p2; + + Vec<3> t1 = p1p2.GetNormal(); + Vec<3> t2 = Cross (p1p2, t1); + + Point<3> oldp = p1 + r * t1; + Vec<3> oldn = t1; + + Point<3> p; + Vec<3> normal; + + Mat<2> rotmat; + Vec<2> cs, newcs; + cs(0) = 1; + cs(1) = 0; + rotmat(0,0) = rotmat(1,1) = cos(2*M_PI/n); + rotmat(1,0) = sin(2*M_PI/n); + rotmat(0,1) = -rotmat(1,0); + + glBegin (GL_TRIANGLES); + double phi; + for (i = 1; i <= n; i++) + { + /* + phi = 2 * M_PI * i / n; + normal = cos(phi) * t1 + sin(phi) * t2; + */ + newcs = rotmat * cs; + cs = newcs; + normal = cs(0) * t1 + cs(1) * t2; + + p = p1 + r * normal; + + // cone + glNormal3dv (normal); + glVertex3dv (p); + glVertex3dv (p2); + glNormal3dv (oldn); + glVertex3dv (oldp); + + // base-circle + glNormal3dv (p2p1); + glVertex3dv (p); + glVertex3dv (p1); + glVertex3dv (oldp); + + oldp = p; + oldn = normal; + } + glEnd (); +} + + + +void VisualSceneSolution :: +DrawCylinder (const Point<3> & p1, const Point<3> & p2, double r) +{ + int n = 10, i; + Vec<3> p1p2 = p2 - p1; + + p1p2.Normalize(); + Vec<3> p2p1 = -p1p2; + + Vec<3> t1 = p1p2.GetNormal(); + Vec<3> t2 = Cross (p1p2, t1); + + Point<3> oldhp1 = p1 + r * t1; + Point<3> oldhp2 = p2 + r * t1; + Vec<3> oldn = t1; + + Point<3> hp1, hp2; + Vec<3> normal; + + Mat<2> rotmat; + Vec<2> cs, newcs; + cs(0) = 1; + cs(1) = 0; + rotmat(0,0) = rotmat(1,1) = cos(2*M_PI/n); + rotmat(1,0) = sin(2*M_PI/n); + rotmat(0,1) = -rotmat(1,0); + + glBegin (GL_QUADS); + double phi; + for (i = 1; i <= n; i++) + { + newcs = rotmat * cs; + cs = newcs; + normal = cs(0) * t1 + cs(1) * t2; + + hp1 = p1 + r * normal; + hp2 = p2 + r * normal; + + // cylinder + glNormal3dv (normal); + + glVertex3dv (hp1); + glVertex3dv (hp2); + glVertex3dv (oldhp2); + glVertex3dv (oldhp1); + + oldhp1 = hp1; + oldhp2 = hp2; + oldn = normal; + } + glEnd (); +} + + + + + + + + + + + + + +void VisualSceneSolution :: MouseDblClick (int px, int py) +{ + ; +} + + +void VisualSceneSolution :: +DrawClipPlaneTrig (const SolData * sol, + int comp, + const ClipPlaneTrig & trig, + int level) +{ + int j; + double val; + if (level <= 0) + for (j = 0; j < 3; j++) + { + Point<3> p; + if (mesh->GetCurvedElements().IsHighOrder()) + { + mesh->GetCurvedElements(). + CalcElementTransformation (trig.points[j].lami, trig.elnr, p); + } + else + p = trig.points[j].p; + + if (deform) + { + Vec<3> def; + GetDeformation (trig.elnr, + trig.points[j].lami(0), + trig.points[j].lami(1), + trig.points[j].lami(2), def); + p += def; + } + + + // TODO: consider return value (bool: draw/don't draw element) + GetValue (sol, trig.elnr, + trig.points[j].lami(0), + trig.points[j].lami(1), + trig.points[j].lami(2), scalcomp, val); + + SetOpenGlColor (val, minval, maxval, logscale); + glVertex3dv (p); + } + else + { + Point<3> newp = Center (trig.points[1].p, trig.points[2].p); + Point<3> newlami = Center (trig.points[1].lami, trig.points[2].lami); + ClipPlaneTrig t1, t2; + t1.elnr = t2.elnr = trig.elnr; + t1.points[0].p = newp; + t1.points[0].lami = newlami; + t1.points[1] = trig.points[2]; + t1.points[2] = trig.points[0]; + t2.points[0].p = newp; + t2.points[0].lami = newlami; + t2.points[1] = trig.points[0]; + t2.points[2] = trig.points[1]; + DrawClipPlaneTrig (sol, comp, t1, level-1); + DrawClipPlaneTrig (sol, comp, t2, level-1); + } +} + + + + + +int Ng_Vis_Set (ClientData clientData, + Tcl_Interp * interp, + int argc, tcl_const char *argv[]) + +{ + int i; + if (argc >= 2) + { + if (strcmp (argv[1], "parameters") == 0) + { + vssolution.imag_part = + atoi (Tcl_GetVar (interp, "visoptions.imaginary", 0)); + vssolution.usetexture = + atoi (Tcl_GetVar (interp, "visoptions.usetexture", 0)); + vssolution.invcolor = + atoi (Tcl_GetVar (interp, "visoptions.invcolor", 0)); + + vssolution.clipsolution = 0; + + if (strcmp (Tcl_GetVar (interp, "visoptions.clipsolution", 0), + "scal") == 0) + vssolution.clipsolution = 1; + if (strcmp (Tcl_GetVar (interp, "visoptions.clipsolution", 0), + "vec") == 0) + vssolution.clipsolution = 2; + + // SZ const -> tcl_const + tcl_const char * scalname = + Tcl_GetVar (interp, "visoptions.scalfunction", 0); + // SZ const -> tcl_const + tcl_const char * vecname = + Tcl_GetVar (interp, "visoptions.vecfunction", 0); + + vssolution.scalfunction = -1; + vssolution.vecfunction = -1; + + int pointpos; // SZ + char * pch; + pch=strchr(scalname,'.'); + pointpos = int(pch-scalname+1); + + for (i = 0; i < vssolution.soldata.Size(); i++) + { + if (strlen (vssolution.soldata[i]->name) == + pointpos-1 && + strncmp (vssolution.soldata[i]->name, scalname, + pointpos-1) == 0) + { + vssolution.scalfunction = i; + vssolution.scalcomp = atoi (scalname + pointpos); + } + if (strcmp (vssolution.soldata[i]->name, vecname) == 0) + vssolution.vecfunction = i; + } + + + tcl_const char * evalname = + Tcl_GetVar (interp, "visoptions.evaluate", 0); + + if (strcmp(evalname, "abs") == 0) vssolution.evalfunc = VisualSceneSolution::FUNC_ABS; + if (strcmp(evalname, "abstens") == 0) vssolution.evalfunc = VisualSceneSolution::FUNC_ABS_TENSOR; + if (strcmp(evalname, "mises") == 0) vssolution.evalfunc = VisualSceneSolution::FUNC_MISES; + if (strcmp(evalname, "main") == 0) vssolution.evalfunc = VisualSceneSolution::FUNC_MAIN; + + vssolution.gridsize = + atoi (Tcl_GetVar (interp, "visoptions.gridsize", 0)); + + vssolution.xoffset = + atof (Tcl_GetVar (interp, "visoptions.xoffset", 0)); + + // cout << "x-offset:" << vssolution.xoffset << endl; + + vssolution.yoffset = + atof (Tcl_GetVar (interp, "visoptions.yoffset", 0)); + + vssolution.autoscale = + atoi (Tcl_GetVar (interp, "visoptions.autoscale", 0)); + + /* + vssolution.linear_colors = + atoi (Tcl_GetVar (interp, "visoptions.lineartexture", 0)); + */ + vssolution.logscale = + atoi (Tcl_GetVar (interp, "visoptions.logscale", 0)); + + vssolution.mminval = + atof (Tcl_GetVar (interp, "visoptions.mminval", 0)); + vssolution.mmaxval = + atof (Tcl_GetVar (interp, "visoptions.mmaxval", 0)); + + vssolution.showclipsolution = + atoi (Tcl_GetVar (interp, "visoptions.showclipsolution", 0)); + vssolution.showsurfacesolution = + atoi (Tcl_GetVar (interp, "visoptions.showsurfacesolution", 0)); + vssolution.lineartexture = + atoi (Tcl_GetVar (interp, "visoptions.lineartexture", 0)); + vssolution.numtexturecols = + atoi (Tcl_GetVar (interp, "visoptions.numtexturecols", 0)); + + vssolution.multidimcomponent = + atoi (Tcl_GetVar (interp, "visoptions.multidimcomponent", 0)); + + vssolution.draw_fieldlines = + atoi (Tcl_GetVar (interp, "visoptions.drawfieldlines", 0)); + vssolution.num_fieldlines = + atoi (Tcl_GetVar (interp, "visoptions.numfieldlines", 0)); + vssolution.fieldlines_randomstart = + atoi (Tcl_GetVar (interp, "visoptions.fieldlinesrandomstart", 0)); + + + vssolution.deform = + atoi (Tcl_GetVar (interp, "visoptions.deformation", 0)); + vssolution.scaledeform = + atof (Tcl_GetVar (interp, "visoptions.scaledeform1", 0)) * + atof (Tcl_GetVar (interp, "visoptions.scaledeform2", 0)); + + + if (atoi (Tcl_GetVar (interp, "visoptions.isolines", 0))) + vssolution.numisolines = atoi (Tcl_GetVar (interp, "visoptions.numiso", 0)); + else + vssolution.numisolines = 0; + + vssolution.subdivisions = + atoi (Tcl_GetVar (interp, "visoptions.subdivisions", 0)); + vssolution.UpdateSolutionTimeStamp(); + } + + if (argc >= 3 && strcmp (argv[1], "time") == 0) + { + vssolution.time = double (atoi (argv[2])) / 1000; + vssolution.solutiontimestamp = NextTimeStamp(); + // cout << "time = " << vssolution.time << endl; + } + + } + return TCL_OK; +} + +int Ng_Vis_Field (ClientData clientData, + Tcl_Interp * interp, + int argc, tcl_const char *argv[]) +{ + int i; + static char buf[1000]; + buf[0] = 0; + + if (argc >= 2) + { + if (strcmp (argv[1], "setfield") == 0) + { + if (argc < 3) + return TCL_ERROR; + + for (i = 0; i < vssolution.GetNSolData(); i++) + if (strcmp (vssolution.GetSolData(i)->name, argv[2]) == 0) + { + cout << "found soldata " << i << endl; + } + } + + if (strcmp (argv[1], "getnfieldnames") == 0) + { + sprintf (buf, "%d", vssolution.GetNSolData()); + } + + if (strcmp (argv[1], "getfieldname") == 0) + { + sprintf (buf, "%s", vssolution.GetSolData(atoi(argv[2])-1)->name); + } + + if (strcmp (argv[1], "iscomplex") == 0) + { + sprintf (buf, "%d", vssolution.GetSolData(atoi(argv[2])-1)->iscomplex); + } + + if (strcmp (argv[1], "getfieldcomponents") == 0) + { + sprintf (buf, "%d", vssolution.GetSolData(atoi(argv[2])-1)->components); + } + + + if (strcmp (argv[1], "getfieldnames") == 0) + { + for (i = 0; i < vssolution.GetNSolData(); i++) + { + strcat (buf, vssolution.GetSolData(i)->name); + strcat (buf, " "); + } + strcat (buf, "var1 var2 var3"); + Tcl_SetResult (interp, buf, TCL_STATIC); + } + + if (strcmp (argv[1], "setcomponent") == 0) + { + cout << "set component " << argv[2] << endl; + } + + if (strcmp (argv[1], "getactivefield") == 0) + { + sprintf (buf, "1"); + } + + if (strcmp (argv[1], "getdimension") == 0) + { + sprintf (buf, "%d", mesh->GetDimension()); + } + } + + Tcl_SetResult (interp, buf, TCL_STATIC); + return TCL_OK; +} + + +extern "C" int Ng_Vis_Init (Tcl_Interp * interp); + +int Ng_Vis_Init (Tcl_Interp * interp) +{ + Tcl_CreateCommand (interp, "Ng_Vis_Set", Ng_Vis_Set, + (ClientData)NULL, + (Tcl_CmdDeleteProc*) NULL); + + Tcl_CreateCommand (interp, "Ng_Vis_Field", Ng_Vis_Field, + (ClientData)NULL, + (Tcl_CmdDeleteProc*) NULL); + + + return TCL_OK; +} +} diff --git a/contrib/Netgen/libsrc/visualization/vssolution.hpp b/contrib/Netgen/libsrc/visualization/vssolution.hpp new file mode 100644 index 0000000000..d20654b5fc --- /dev/null +++ b/contrib/Netgen/libsrc/visualization/vssolution.hpp @@ -0,0 +1,220 @@ +#ifndef FILE_VSSOLUTION +#define FILE_VSSOLUTION + + + + + +extern int Ng_Vis_Set (ClientData clientData, + Tcl_Interp * interp, + int argc, tcl_const char *argv[]); + +class VisualSceneSolution : public VisualScene +{ + class ClipPlaneTrig + { + public: + struct ps + { + Point<3> lami; + Point<3> p; + }; + ps points[3]; + ElementIndex elnr; + }; + + class ClipPlanePoint + { + public: + ElementIndex elnr; + double lam1, lam2, lam3; + Point<3> p; + }; + + + int surfellist; + int linelist; + int clipplanelist; + int isolinelist; + int clipplane_isolinelist; + int surface_vector_list; + int cone_list; + + bool draw_fieldlines; + int num_fieldlines; + bool fieldlines_randomstart; + int fieldlineslist; + int num_fieldlineslists; + + int surfeltimestamp, clipplanetimestamp, solutiontimestamp; + int surfellinetimestamp; + int fieldlinestimestamp, surface_vector_timestamp; + double minval, maxval; + + + + NgLock *lock; + +public: + + enum EvalFunc { + FUNC_ABS = 1, + FUNC_ABS_TENSOR = 2, + FUNC_MISES = 3, + FUNC_MAIN = 4 + }; + EvalFunc evalfunc; + + enum SolType + { + SOL_NODAL = 1, + SOL_ELEMENT = 2, + SOL_SURFACE_ELEMENT = 3, + SOL_NONCONTINUOUS = 4, + SOL_SURFACE_NONCONTINUOUS = 5, + SOL_VIRTUALFUNCTION = 6, + SOL_MARKED_ELEMENTS = 10, + SOL_ELEMENT_ORDER = 11, + }; + + class SolData + { + public: + SolData (); + ~SolData (); + + char * name; + double * data; + int components; + int dist; + int order; + bool iscomplex; + bool draw_volume; + bool draw_surface; + SolType soltype; + SolutionData * solclass; + + // internal variables: + int size; + }; + + ARRAY<SolData*> soldata; + + + + int usetexture; + int clipsolution; // 0..no, 1..scal, 2..vec + int scalfunction, scalcomp, vecfunction; + int gridsize; + double xoffset, yoffset; + + int autoscale, logscale; + double mminval, mmaxval; + int numisolines; + int subdivisions; + + bool showclipsolution; + bool showsurfacesolution; + bool lineartexture; + int numtexturecols; + + int multidimcomponent; + + // bool fieldlineplot; + double time; + + int deform; + double scaledeform; + bool imag_part; + +public: + VisualSceneSolution (); + virtual ~VisualSceneSolution (); + + virtual void BuildScene (int zoomall = 0); + virtual void DrawScene (); + virtual void MouseDblClick (int px, int py); + + void BuildFieldLinesPlot (); + + void AddSolutionData (SolData * soldata); + void ClearSolutionData (); + void UpdateSolutionTimeStamp (); + SolData * GetSolData (int i); + int GetNSolData () { return soldata.Size(); } + + void SaveSolutionData (const char * filename); +private: + void GetMinMax (int funcnr, int comp, double & minv, double & maxv) const; + + void GetClippingPlaneTrigs (ARRAY<ClipPlaneTrig> & trigs); + void GetClippingPlaneGrid (ARRAY<ClipPlanePoint> & pts); + void DrawCone (const Point<3> & p1, const Point<3> & p2, double r); + void DrawCylinder (const Point<3> & p1, const Point<3> & p2, double r); + + + // Get Function Value, local coordinates lam1, lam2, lam3, + bool GetValue (const SolData * data, ElementIndex elnr, + double lam1, double lam2, double lam3, + int comp, double & val) const; + bool GetSurfValue (const SolData * data, SurfaceElementIndex elnr, + double lam1, double lam2, + int comp, double & val) const; + bool GetValues (const SolData * data, ElementIndex elnr, + double lam1, double lam2, double lam3, + double * values) const; + bool GetSurfValues (const SolData * data, SurfaceElementIndex elnr, + double lam1, double lam2, + double * values) const; + + void GetDeformation (ElementIndex elnr, double lam1, double lam2, double lam3, + Vec<3> & def) const; + void GetSurfDeformation (SurfaceElementIndex selnr, double lam1, double lam2, + Vec<3> & def) const; + + void GetPointDeformation (int pnum, Point<3> & p, SurfaceElementIndex elnr = -1) const; + + /// draw elements (build lists) + void DrawSurfaceElements (); + void DrawSurfaceElementLines (); + void DrawSurfaceVectors (); + + void DrawIsoLines (const Point3d & p1, + const Point3d & p2, + const Point3d & p3, + double val1, double val2, double val3, + double minval, double maxval, int n); + + // draw isolines between lines (p1,p2) and (p3,p4) + void DrawIsoLines2 (const Point3d & p1, + const Point3d & p2, + const Point3d & p3, + const Point3d & p4, + double val1, double val2, double val3, double val4, + double minval, double maxval, int n); + + + void DrawClipPlaneTrig (const SolData * sol, + int comp, + const ClipPlaneTrig & trig, + int level); + + void SetOpenGlColor(double val, double valmin, double valmax, int logscale = 0); + + + friend int Ng_Vis_Set (ClientData clientData, + Tcl_Interp * interp, + int argc, tcl_const char *argv[]); + + + +}; + + +extern VisualSceneSolution vssolution; + + + + +#endif + diff --git a/contrib/Netgen/nglib_addon.cpp b/contrib/Netgen/nglib_addon.cpp new file mode 100644 index 0000000000..391e036012 --- /dev/null +++ b/contrib/Netgen/nglib_addon.cpp @@ -0,0 +1,105 @@ +// small additions to the netgen interface library for Gmsh + +#include "meshing.hpp" +#include "mystdlib.h" + +namespace nglib { +#include "nglib.h" +} + +using namespace netgen; + +#include <iostream> +#include "Message.h" + +namespace nglib +{ + +class mystreambuf: public streambuf +{ + int index; + char txt[1024]; + public: + mystreambuf() { + index = 0; + } + int sync(){ + txt[index] = '\0'; + if(!index || + (index == 1 && (txt[0] == '.' || txt[0] == '+' || txt[0] == ' '))){ + // ignore these messages + } + else{ + if(!strncmp(txt, "ERROR", 5)) + Msg(FATAL, txt); + else + Msg(INFO, txt); + } + index = 0; + return 0; + } + int overflow(int ch){ + if(index < 1023){ + txt[index] = ch; + if(txt[index] == '\n') txt[index] = ' '; + if(!index && txt[0] == ' '){ + // skip initial spaces + } + else{ + index++; + } + } + return 0; + } +}; + +// replaces the standard Ng_Init +void NgAddOn_Init () +{ + //mycout = &cout; + //myerr = &cerr; + //testout = new ofstream ("test.out"); + + mycout = new ostream(new mystreambuf()); + myerr = new ostream(new mystreambuf()); + testout = new ofstream ("/dev/null"); +} + +// generates volume mesh from surface mesh, without optimization +Ng_Result NgAddOn_GenerateVolumeMesh (Ng_Mesh * mesh, Ng_Meshing_Parameters * mp) +{ + Mesh * m = (Mesh*)mesh; + + + MeshingParameters mparam; + mparam.maxh = mp->maxh; + mparam.meshsizefilename = mp->meshsize_filename; + + m->CalcLocalH(); + + MeshVolume (mparam, *m); + //RemoveIllegalElements (*m); + //OptimizeVolume (mparam, *m); + + return NG_OK; +} + +// optimizes an existing 3D mesh +Ng_Result NgAddOn_OptimizeVolumeMesh (Ng_Mesh * mesh, Ng_Meshing_Parameters * mp) +{ + Mesh * m = (Mesh*)mesh; + + MeshingParameters mparam; + mparam.maxh = mp->maxh; + mparam.meshsizefilename = mp->meshsize_filename; + + m->CalcLocalH(); + + //MeshVolume (mparam, *m); + RemoveIllegalElements (*m); + OptimizeVolume (mparam, *m); + + return NG_OK; +} + +} diff --git a/contrib/Netgen/nglib_addon.h b/contrib/Netgen/nglib_addon.h new file mode 100644 index 0000000000..32c39b147f --- /dev/null +++ b/contrib/Netgen/nglib_addon.h @@ -0,0 +1,8 @@ +#ifndef _NGLIB_ADDON_H_ +#define _NGLIB_ADDON_H_ + +void NgAddOn_Init(); +Ng_Result NgAddOn_GenerateVolumeMesh(Ng_Mesh * mesh, Ng_Meshing_Parameters * mp); +Ng_Result NgAddOn_OptimizeVolumeMesh(Ng_Mesh * mesh, Ng_Meshing_Parameters * mp); + +#endif diff --git a/contrib/Netgen/nglib_addon.o b/contrib/Netgen/nglib_addon.o new file mode 100644 index 0000000000000000000000000000000000000000..3dd308e5258043078f7ccddbe02f1b94ba438b36 GIT binary patch literal 291636 zcmezO_SZQE1_mJp2w-GjU|?ooV41_fpa2qKWME)10WmN!cOU};%MJzx?f?b`26ias z2dRsXFG;N^0kI%BK0d@XA_T%lkj!r&`WcuQ7z8*N7#Ok|7+B!a@$m(j$;FkqN%=X& zC8bG*m}Y>~GCg2m;Ml>yz`)ADARNKKz!1~GzydN0WR607d~SY9d}dx|NqkyqUNS>` zyo+OqBS;E{*&Z-3fGp*n!N34=hnNKe0|O`wIAJOvW|X8B<>EBs3Dk@^P%|8$W^f_Q zNGdLdaTpk|xC0!9AbXKifthfz`1s`fyyBAh<ov`OkPH^TykKBp@L^!!UI2+hF%M|G za)Z=^Fs2#k@xl&@YcU1}?l%y>fOLT|vKhrCMVWc&U}2D7FwF3Q*vkWsAgD4B#RMWi z7?M6fK8eo*B@@iJWlvyWV4T6gz#{>1hu94U1_r4H1{NfDq$elGr&c7V7L>%7Bqm{o z2geTv28MP92Hp)IJF(&T_|%N}w4%h^RER95J2)E{7#MvR82CWxf{B4ad<6pogF*%a z1Cl%Pa^fNBG`^su2us{@onc^L&|qNTZ-Mv)ViyAg0~-SagE)v6AD@#*z>F`Tw9UZ4 zzXoE41jrpAy`X%j2r&bkK8i|{OY)1rX$(DHz-f#Dn%6*DFmQZ)N@{Tl+z1BD@IWyG zo;J}80>!fg1A~+U0|OH)1A|cw1B(MFkAlJsR91kp$8iP*#^VeO41x>{jG(yHMKc45 zE1AH+zyJz=Bryht8V;sq`y2m%sF|x=QBxybF@ceRV~XN`28%=n3l9d?qYbhQA}3@S z80woJgXCInFf!D5FtGL3w>++Zs!6m^WMpVyWZ<w!U|`q{GK+(GnO_5g0^IC5$`v)W z7-nZS$S{bUkYQk`U;G-`Y(o&=gMqcPe#vX79n7`(>~NaTz*_6Uw5*1Mc^Sxq2@L=L z*S9b*_{?Ka&~Ij7blArrW0S?eV3Ew#;laSX0l{WDqTkHG;IofG!TbOJHx>;H3>FCt zj0r9O|9k)czXHl<fbwU6`~$LUf8zf)76~jW^)Hx~SubE<fQH!u4+hpyn|KBWP&hU? zajuxWn1RK@iGgGCVg`;0&I}Bb7c=loUd$jcc`<{?<i!jU7Rd}U9t=zeC+}fU0O_+x zV3^S0#JK^aXF?1Eg9igED=3_6>ZB_?7+7X{Ffed<Ffi0W)Uv2FIC0Ja*+2OZNG;1v zkT{8UyW+N+r4z|+Sq}yViJEHZiu%K!D?AvObnBCES9mZm9tGKHk-)T~!HIJV)E$A= zi<u-q?tsK2(?eT(1_qG2MorEgp!jKU;#^>Thk>KflYs?f9@xLK3>_0<m?S{zCde`r z%#dX$nIOwhF+rB0W`Zn3!vtA|mIf!z853g|7#g$wf3b98P-x&};IMFF;Hi;`)B}ar z#26+C4+iFmAbabNfZeHTGoOJ0Y)1>5g2e&`0}lqqkDxer*vD|CA%=mWA?g2@ni?sQ zhGqtlgcb%C4+f?{4+e%EAa{WL+u+2x1gzhQfn!1(D4dxCE$SG2JQx@~Js22NkkqZP zsAG@;`vt6y@gz(hBo0asNOEgIaS1XXq#xwo1}DxPjY<qG4NMFiAhC%y3=E)fYRvrq z1*8w`$5@d4j2B^gL3z@HfngyeE*LC9`YaR~5*nO1*Gz6=0O!fwiT~e#@&zbAqGWt1 z2bQL5GnkgyW`oKD=4GwjY;S5iL3x-3oQFYa9!>rN0r@Qi<Yy3&uOT3xKtSGwfV>6) zc^>@otRD!-Um+mBgMj=T0`d(6<WmU9dk~P<As{b+U!LU)0r?vQ<o6JeUqC><1t!nH zz{tbEz$gPv?vzll_ArB=X<m9xW|E;{Ze?*vQEFmtQfZni0|SF=P>_ER0|SG8N@|&Y zUTF@ffeFfA`xpNI0?I?6IuKN6fa(iSIXFe}|At0o1_k|228J3>DUlgW3@VQE7&7!b z85kYrF{pGfGpN)su$SmJFz7kXV+hc1V9<7)$Kavgz@XqbkHNwEE`tiFe6wiz{{UP@ zEnr~v{{PPqT)xd?5CN5ep!&@F|DU@a3=9HLKCk!xKW9PqTPQLFOps+z0M*-|`g`}n z|6gEbMT0Ygf_@Y8KgYQYHZ=|GCACUYBKi#sTr)ZuR2=p(@K`V~D9qqwP|<H<U~rhn zAOLbJ)LlFlObm<@m?7qZ${kP`fcy`uqiwtx7;Lpb<r`B)qb5@UsC={3gw&A}l|l71 zgN*n8KOHcApzuQuJ5acR$~sWJ(%{78(5T5|fx`?}kRL&Q1C_Bb|9Suao%8=ca}%iH z1?ru_yHquh9tZ=dg~<TwhQMV&ZD1Bimxh5+fPsMl)Sw0>CPq+8pM`;esRz^?TLLkF z3Di7e1htnf7#JAAeE=S)j0mXV2{Ibgss|YWHHxt+z$b`-vBr^oHUk4=tbhOy$aM?` zpmy^A|9|%|Ffi-@YXK1)^BLzc&1L3v1ogQX1Oy%Hz@mI0YZ(|oR)qZj{}0rE@&QRe ztYOe$U|`7k|Nk4v`7vN|5CJu74hzgQz6K^i$2tZEu=+Xw|9`V#U|>iADFxexTRkWw z&iw!X?G6J2(*c(M|NqSgX@Z#x*EgFLBrL+00I>z^UPhMx|Nq_rwNF8EQ1=>u^6mfs zfB%5m>|k*afo2{^NPsT@W)@WIz)`Cin6EG}a6MQEb^@cx8V2Sw5I*M`1_n@SVLrjY zz;u{_f%yQG-T<OkGceC#VBorfq;Cp@&$$4kZ#4sR2Ll7w8zlJ#2%mEYNS=X#xdduX z1_J}v9VB%L5I*M$sJaNKIuD3A$f00&Izaevbrv9X3=GT$AbK?evjPJH*9|0dB_Mpx zB~Wt(K<XG6m_C5$)eKB87#P??5b8l=3?M$60z^F%D4iT;U|_lcRlkOTf$I#C`Uwy| z=M0eg)eKA}knn)GcQpf34#fWu{u%}*kiV}iWPpU%8V05mh&(KOm=ZwtFff2JC)458 z3``*Zzd*7N<o_278929q>|<bHvVp2Mfzm2aS^`9`W?<rBVBmU!q@M-C=iC6%&-e$T zjuDg|km7?8lpgLZWPpV;BRD;*W?<aIz`%6@VIJca2%mEf)VviS^B5Qy=YZ(d42+=g zL9(9_ls=v;WPsb>096+OiC0)SF$O^RaQl5g>KGUpH5eEe4>K?@N<e4^sQVdyfX1dE z?qWExhJoP=gwNH%z`$^Vfq?-U-wbac;vjp#>Rv$jaCJ){_AtzV(i5O`1(XK$a}P5x zFhIkbK?Wqgnt|yG0|U1Y#D2CDYZ#c$K=>>z3=C{1Rx>bdVPN3)fXc5}!@#r#!e?2) zz`(X*H3QQW1_o{ysC>s7a7hi~v+QADVC#USD{cp<e8w7Zx&rZ8ZZI&gWvpgk3SnU2 zwt>oftYKgRjSbl>WMKKiz`*9Qnt{oLfq~lsDzCAIfk_9#XBA*zVAEL5z$C)Jz-<DR z=U4+yHy}Q%4g&)l$7%*fP<R?Z<XK;=0oNDY1`8QjJs22RU#w;Tr5|n`sQigF450J_ z;<KhOFtDCj%>YU#+!|2%6>At6LH^fR$iUjbz`(j<H3K8a|0+=Vjx`L7Jq!%oDhnA{ z=P)p^cC2P#EMZ{aR)ET9tYKixf$&*(Ffg!YtY%;Y`CkSq@396vj>9dpkb(6I0|Tqa zYH*pxEdiC+Si`^w^1sAF2G$P@46GWf85lwS7lF!itO2*jxJ4E+u<<Z3uyU-1q$dH0 zJj;tU4B&Jmu#kaGgMoqN#cBoyQ2g^i<w5BW6#qO68Q5GH7+6lMW?%rtKL=EP#To_% zkpDRrGO#5uFtDsx&A<TiKMPd8V+{iX$p0)08Q5wV7+5-1GcbVs&j6LrSi`^o@;}2u z2DTXt3@jO|85lws7`XmG<vrGb#|A-swk-?{EFP=D>6PmTR9<5ZxZVWu*)A|JuxP9X z*Kb^3pz<7R7#Kk1#+QW*Y@l&lXq%D|R9Ax<5Fpxvf$=A(CU;?Ayau8j7#M$pXd4E` zlOWoHf$=qnHeq0V2ciua7+-*B9R|h^AX<Zg@fC<xVPJd@q7@hzkAr9#2FAA_T7rS` z4Tu(DV0;Op1sE8ggJ>QG#?v60gMslZh-P76yc)m&PCuafim?Wg9~nXADzrS~ShAXd z5mdiG%OQ>>YZw?~Ams~_1p@<^4=R72EM#DE0Pz_Z7{T?*Y6eD7eF8HlXEnHu4l7SN za@K&$Ay7TWRKUOh=8HheSEdROp8*`NAa{XUYhbzn;y#8H1_pMYg$)1yGcd5{tYKhC zfbt)J`0K&;a?F9m2iJo25PP9~&W802j2sLM94S!wj`a+TpmMzh!UxGS++<+jfW|jh z<a!2%3k(d5(EQ02u%3YdRK7#YE3kUdIC2a`KbOLK22jJ23!0z6@&%w06C%&~VLdqg zaYE~PuzUmq0|zvJao$)DPLG_>b^=&lg@J)R0jht=dhmn;=K?6dVLbzbFarbE2Pl6s z0|P?@0}~4<enX&i0F?HD(jHLS1xh<WX&WeQ0i{i#v;maXfzldKS_MigKxr8$EdixP zptJy#=7G{2P?`lwGeBt2_$K3R1_s8D;3)<M#>Wf{jGq}87;iE#Fg{^mVEoR&!1#%Q zf$=K?1LF?{2F7m;42-uJz~w6=sI9@wz`%Hyfr0T60|VnT1_s8b3=B++3=E9-7#JA; zGB7YcU|?YU&%gkxw;BI2Ffcx3U|_t?z`%H)fr0TC0|OHiWQ>(oZs5F|!U%3*GcYi4 z{zkC5xIqnYP#R%i;F974cMCv$S}q4DTZVywD~*p8qyjRo?83<)1xgbj5f@GdX$A)N z3Md;S4(jDFK*bxN;xY^j?BHGxR2)>dgVcb;CqUIGGBB`%`XL~3B?bm|P<tK32Bkkx z9|y!%V_;wh^_4(u4F(2wP}?2ER%2j*6m>3~pfP+7P@XDPfxDAyC)gn%ix{|$I52?R z&mhad!1Wd(&KKPPPRk%geEAIw4AvkP1B2o*gc>DjB(^#d+XRX2)4;&s0@17O)c`IZ zKs<wW2sH*r8W<Qrd4++2!Qg8H149@{1p|YjMgs$bACzs~zyNB?fOv+!4dAo}Vq1$g zFfd#Lu^1SvRT>x=+@b8Hpy6c*JINGbSCUf$1A`Y-Jfs1fzd^jDv<3zSZxD-tA*r!} zfx#2XzTd#W0G_L0U`YDfz`zKauVY|f$avYnz_=NrChH!;{HzZR3=BUZ;yE)AZZ5pl zz`$S#5igEJV&^t6FieDqmk1!lE5%eGf}lAFP@HOl$|aDH3nzmX5?hCXfdj16g_A*> zfq_E<ss<#k17(B6L48}0IUsRR-x0*tWnka{)qx<kAp-*kxC8FO$zaOBz!Ag1P${m$ z$pE#t(!qfN#0Jf?R{B8MEDQ{lVPMO_^)v&63nK$)Xa;00hz$y7aM#_15j4jKnVfZD z1cx(Nn+qd2ej#p#sDZc{q6Xq-h#H8S85uxjDQGwaWPT_EIBivitHAB8+}yyx0L{Wx zHVzD6_sB3XR3$^%vJ4DW6C1#DI3Q<MEoxw3&<C*?7^;!dfA!x6=vV;*!)Eyg1_p4x zWMJ4OfnXmrLa>kDK(Nm(L$I$JBG`9S5ozr4@dgIQRS<h$yCdBE9W;3dwd)TkuR++1 zEL?DN7&$*QFffDK?hFi!0!teh7|(;vVH9zN`-@Rcw}AoFrUx~1%mNx<bLEUyVhs!o zpfL#s21Y9#gqaS%5Nx+84Gauf5Hr2(8yFZMv(Jn{y$uWuw;|$Tli>M+G3;&w1H*2J zcvO4?15+1-9S6!siy`c!@CF7@9|z=~QcxUqL&Pgh8yFaOLfCyEaV04GMFVu6k%4gv zC?7%HJXH`LR*X{>8W<RqA?l~rG%zq7gRtj-{0nvS@~I6B45AS6H9HXOO*{zpc2F4t zRkH^)4FzQ%bVR5*R@(q>OM={gx(gwGp|62~5i+gJculQ=fzcmg*L_e~R|{c30oltB zVLxAm2<LY%8W@-$X^-*ewFU+TNVqX^2*cGd@g0TR#Uu<Wiy&@elJrN2%RXpeV8{iV z&!mP(Crmoa8yFa4A>u}5aJMnpJVdbFYY^<f6a+h33&BnS#jhm9oRmKekotmwfhiSK z{tH6HQ$haHg0OSi5$-RpZeU=rgoszS!qXvBV+DfU4oc^(5H&rZyaQ!V1cf2gzte&n z7#Oxe)GPpXw!lmVrUf83=z%#*i$H#dgg?^~P<`|XBEH13fq}sp!d_W}aN7n@euS(c zVcHGK*WmJxfoU%&%^ZQKKYR{ewlf`mh{XQTz`%G2qUI>bkDwt(1_q`xj13G7kTlP9 z$+Llh0bIT^FkOm3=)DB0Pr+pv1Ji@g4GawPA?ADpsRuI|m_CB)BN!VLo-p=Yg!_M9 zZeRe9Su!v%{rlO#zyL{O%#3T{X@i+vq=A6}k_MQ0pENKqM1c)r7G4QAhgsSW!Bzs* zM^JM#wjs>XJp(Vhm<@vvY|A!;8oN0S42+;MpMindVGF`c50D$cWjO=0FDNZR*}=OT z7#Nu$?uk@``-M4f8iJh+Y7aowXM)lIxaGyboQ22>%mo+WX^gp&9pRoj`343i&>%4b z19NA30|T_%$~=8y0|PrGuQ9Izl_#YTH>`4LU|=wZvMU=H7(we57#Nt>oNQoVgp@7J zYZo*yFqT8qtbK{FYcnVhLh=Ih7TX2}20n<IT^S7w4B-&=X;3|42Vvhplp)M_Kf&_? z^CL-wna@FOFi1Ou`86o6A$0-sr`rt-3~>;1zJS_Skai36-^p;jEX*7Y3=HaEH7u+P z8zA){0|N^iNF0*(Sa^>%Ffax})QHSR=#>J63AlaAz#@~<0Ik~@SX2ue7#NHp>QzBy zbrO{Q4&G*CQT^WlUN-_7fL8;RV~{ovi<&;P-DSbRq88G?!1NiSSNqWca2uOJf`LW* z@dF6kg@Hx;3Alm4zz_pc=fcPUYInidAR4p;2h;`tg#)CG%?M8C;B4l?2<nG|`l{eI z2}lj3jSW%L12q%0MgttCE{qJxkUlP0eF_7(-w0-d%JvluEZR?1U~XX1F>wI(>lheh z8CZ0jpllfi79CJN0=dnCfkh_{>aP+87M*ygzg94?=p;b>mBPTHlL+ZkFdTroCzFAJ z;Q#}R&Ll|SgG9k@@MQq?ds%dLt1vRa)O>be0JE7HSadm|Y!(I<U1_NKJ`60nGHB*x zLFVVcW<uC3x;iS1pt_!shk->m5~>$m*Sat=WP|1eK(2tZS#+aRVB##g?P%&PL49+m zdV9#&1K2K*xD5k~ZU?G+Kx1i)4h$^1n^46;^#voi&)~wy05S*UmqVy(z<L81Sajc@ zii6dMFtF(UK@|t9k6>WYQ$rO8O)W8kg<Kdx>zY90x?neh?1iNhaR%`CFI*fnqXbHO z4h#&8koGymoqHHq^vuA9fdT>4IAsLedw_vOF9B5?>`rhU<H884BN$IGu;>+_ssZag z!@#093soGf{sIGw-YQgau=*<uEP7W^#X)`qEpGz5UmVoI2RRR7FB1op4H5^}VNh{c zyWNq2fe98DpfO|6`aF=|LE-@nEP78+?P8k502;$((dR)G2el!YA{bco(b6R2J_ZJ+ z7zP%7UsUysnG6g}DGV(7rD)<H^%)E-`peM7LF#iDSoF`KiG$P^FtF(VM->OVvx0%e zKpj;aY;O$%i-A9?I9PoH1B*d9syNvFEetFMD^SJ3>L)O;7+gRV2dkgLz+wnVbfCZo zrxURHH4H3<nrP}l{@TF6Vi<@j4pzT|fyJ;ARUGX8Jq#>{3sJ?v>JKom7@kBG2dh8A zz+(6jRUE7yG~dAB!U!7E2h9tB(ht)~1_sdF5}198fr04{1B;O)s$NiEiJ60e#mEa) zoKcK{fmwoq#i$5X9MpGUc3@yJnu8`@#K6GZz`$a31XUa~9>d(iz+&_jRh$8&zJr0q zSQb?rtbPgui?JW7I9UA*1{UKoRB^ESISeeu%TdL_>K8Du7@tQK2diHKT5^mk4pzT{ zfyG1vRUE8-4FiiwB&s+lk1#{Vd>9#=7#Nr@fRcv`BUt<jlnoNU!@y#aslo^@Cv_ND zOu8ZEFcYL6;RMwS9H2T3)UVHEVBjcWU@_@Iv5ONF<{T9aEGFB~#6jw77+6e>p^5Ki zVBlzAU@`fCCJs{H!oXq*scb=x1f^$)`5g=_rdn9k_b{-STA_)9%%8x(Vw$1?b3cn| zy8~nlikX4MbTY(`3>FM5rc==Lg4_TplOcL{FtC^|K~n=Ve-8tTDQfuuQGbAe#q=H) z^+y<3%s9}*L3W*BU@?<G69<`phJnS*2~8ZN{sIGwSrD2yNc|NC7PA^Oagh243@m0n z&~TW;z+$!@8V<4yEM~i*;Sj^XVzx&C5<UzJEasqb14!tzn1kAuF!l-f_#2Du1O*0$ z46p=??FkK524B#eAp?u;iv|Wp&^l}e1{Mc3Ch(XxsQu;;g~V<~Vz1%j2ARUyz`)|L zEd|_W1Fef^oXyY4&;S_=W%1(Y2C+f&sm$CEaSjOv29_MCI4ErgL&ZUJW62P4F3_5G zbEr6I&dmiX-oU`XqR$Vu3pD4&s>Tm?1D6K_1M@<NILJ*blOW=pFBlk@UqHoU7#LXY zK*YH~^_mPn8^~?!8Vn4~5&Z06HfVf_5hBj^0yNhN8mtDH$iTp!hG27)AlPg-5NwVU zNbD~NHs?MBo2>}!e6XRcAoXAt0|Q$uLYz|xp`P6ki4D>VRmRzZ5a$d<uo?293P7t~ zAkhM`VI4x8@iT(WbP2&`c!ppz+9B9XGZAdYT?jUlHiFGAj&K9}UnI6Kg3YlWi4BSt zsCJG7ggE<l1e-${!DcRoDh4e-Z$+?~^$=_}W(1pcHiFHjk6^RjL9p315$1Cu*~_*G zp@!o%LJcc;{Sr7h<Kv@3!mzJO14((}l)@(AV(41N5Fa0fRn7n^7hGa!nv__anH&#a z0q2<<Tw-XLoRL@*Us9BqSyJqo?CNTonVVFa>Kf!7Tw<1!pPZPJ3O1Tp?PkTPC7{K1 z0m+#p=`$}*P0h|vOLMIVE-^HU_slPj4^B<ZPRT3^E-^F)^Zg4_^K$c3NOKR^+=BdK z*WeP9w1WI%Pea4__}rx8lEjkK_!3v_hGSVRXi{96mrP<%S{7&Im**ztRg$XFtfDwQ zwIt7#)IhW>%}YrwO3TSFC()&*rDSNbEJ#XB&Q43r%yA_xuFWcn3ra!W^M)o8Ea7dD zUk3FF*zAxnKSP7~_~eR;#H7qJLnDLu_~Oj?<ebFf;`oxvg4FoTytI5*P>Kr)#+D5r zQl7-7Vvs>lV~ouF(j8M${PW`7Q}a@b5=&CU@^eaaQ+-p5Gh71#$^!g?<Bbgc(&Iq_ znR)5)0g0e}H6^J<#b8S@jPWlh$;{2HBF`8@BbaME^D;}Iv5Y17pvhG)H3P{jD9c}w z0vJ^lB_76Q66t<MH3{9@XtK!5dO?LDK4}BjGLUpiWll;wXn$RNQf6KXDBdzsa|%*H z+nAz4!h%Z-O(2D3ej22>#9CH@!`3V>wIn??&n&kxIlr_79OobdEFt<c^NVq61t~K$ zhNw%+%t=iuO~bF2r~(|>QRXG7#U(IT`9WQ3np>G#R0MHo2=P9RPp_zmFGwva&d*EC z$t<aiFEe0>j}Of&&&*4S4@xaA&4rZAP+JU5P$S(n$S*kF&>WgekTMBK+yo>Hc99>v z+Hr=~YAHDZklGDgF~lQ+%QM*(6xm?^2A5c5<`;t`Q%yiQ1E$&7w>UjBAh`;vh?vke z$uCIFa}DqYRgPFI9s)6Ik_pP00oaQg!+11bV)KEs5j0~5mk_YaG&v_Vu?SR)L8?s8 zd~n4E^({O|Twn&m;>G|J-jH&P_;`UE2M%Gl!(nD(MlB=~ic5;}l5-2dZi1>cG7L)1 z%`Z#!%*jbjPt0-6NzF~oD=7v$1vx3?I~%&<2uRF^3)liseU3;WxH1&PVewIZ#3?sT z&dD!Mg~Ul-c`n!@s87JIH8gNe%t`hEHI_VF%NX=Si&Kk=_0v;Js}eKwQuX!HbBi<d z{lKM!J_C3oLVRLMN`9VRazOz@dUCQ+d~$wnL1s>BiXKCJyt|LTlcP_3yeCqN4ztvU zsdB-qDk`|dB0fGdACx2+us0B)HHDR%hJlWurfm_Jveq>+G%+`^Fg7!>u!b|utr;@& zN~}u2N*GEqGK;MOGz@f%G;Omr40Mb&ZM8HEbWAjDD~ge}Sy(Y3b3!00iVY3S3=|D@ z42%qPGz@f1L3$w31}SZmO4DpW?NXiMk`yZ|5DVHu1&i7#*jZU;=B1=oSm_&p9iwAp zYNlgsWL;8G0ueIPv`qwg#T?=zb4_al8~|0q*c=Y5tqrUV4UCMfH4JntAjVi|g2ar> zt#ynnEOaakEsd<>!DUW7Xz!_&m4<<irKYVi*pDE885(HXg4}1I3E~-pNkc<TTQ!g% zG}ufaq6V7QR@fuR*$C7aH;A`3a@4a1ZDh_ZK(-E-E<+SuNr}a&2wjH8Xs$$Z9$tr( zVReL|u_kU;K(v5b&*1PeG(oW%?0IOw;I<i>My-t;wah@#VWMem4Qn4lOf|)6D%b`? z+-4)SgFxmRg5w)x0W@Y)O7e>!cHs0SsCY#V7-F;-x`F~m%K+vb&<^CB)Dlobgc$7x z5bcIA?bdaw;Cy6_n%h8G)kKqlw5$~Z(q*b?TWo9;Ush03q=Kd$l*|pyAi3Sp97<bg z+NOb0wWf{%C?m%E#%JcmC#9xa=^KKCEg{M*G<A%P5c0{TMR0i?GZTbFYF-LL!V;Xd z<9*}vOG{9U)G;)&fa(EBp_pc926G2U3dKA_OPCXqO4H&YeO!obMh2jQ2r8muWCU>$ zB!|Oe#mEqn)=Xh33zT_`j36F_3xabq_BH@!)rB(w85x3e7SZM)rz%rTYin$&ic~X^ zlN!j(g3=`L5CJ$-7(q)Ch`)^>1)Y%*IB1MaASIoVDWrmc%EIy@v7WMkSqLi7U}F;C z?3SKdl9Qhdafcalq(E&lf+kKQ3y1?Cj)d9oO{@dVAohTAoRgk)L1_|Xhy!9Tw7iEH z4f8m}|Av;}U@(M`&=QDPOD*B{fJOnp-UW+*2T8zI8yg^d+1L<V)fgLrQZQ(s!v<-X z!_EqtMnROZv8Js<v6+cAsD3my2Gxv)SnEbm%?Pgzkr~!tV?Y&sDtKT9I#2_)#28eU zLxf@DHDGaAs1xgdLj#0&i5L??4xobkVn_g?qzPk4JV2w!7!pOska#28aU={Z!ChFH z2T8KV=E(7f;yO~@V-5-{@c0zimdw2P#InT997rfwAX{T>2~H*^(1r;(X+nd9R7)*j z)_^jGqn>qfUTQ@N+-sl)0kLsy2GI&LC#f{IfJ}41T4Cm-r;_I!Q_$dBGLk8I;D9ti zDff*bnHv^%5FR8FNexJ_ec-`9aO{D`#y|sWkRUKILXJL&1yD;Zz_CZFZI*EJU6Ud9 zmFAHfQs%`Fy|Az<D20Z&i4jTlmMO?h$uReT#s(oFj#9axhPa6dq{20URxZ%MAS+0~ z)`PqJncxtCw*262dJ=0)Q1{*15KCj7RC7SJImnz;P;!8T2uhI#tzeAIQG88wy=DqF z*R{;r&`Hlay`Tir%r!9sM;+0on1FOb4M_#DVGaeA07RQ&3f2lWCLNTGA;zGVktodz zNM0Z{`I~|bcg+MxP;qKWI>a87Ledb`9%$Z1rAVyKO+Z$;1|$a?#|In7gDo!r^~oT% zlNjWtV6D)=Dj+-JKsup@q=MMwxdp5hYD@ug#DU_U*c!kTtP>F{1rWEOG_LT*3K`K+ z0ErH8Tp${>rYNl{R6C7O`|3n{4s1F~>($Uv%LvqU1GT47Ta%=O8q!>wwV|UHxaSHn z5z$ICMXj|UnFd;c7(+VV#t?6j*%ks%un{+L2Xdqd!rQ6Yu$G!BN+n0lmKxY~q_olu z9kop1PDE;|krFSk;R-|Oa0NI{U{itMlx=JQE@X*KLC6z{pg=T-xezi>2sYA$w5}r3 z6eGw)3z&)U8APz5#^$8C6RsOnAUJAS!c7HDFOp*-Y+@4RMnmvm2`Dh(6OUjcO;MT& zC@CDmA+?S`p4bFi3?60ySqz!D1lwu?84e;g3X$hL!DhnqKgvLsDRg)Y+AjfD?9kjw zo?noMw+tP%Aj4ZAub?+_Orb+)P@7SzKvOelPafLJBC)iEj9?nYTN_|$6q%Zml*F9D z<C;*j@(Vx{viU`};21GQX)KspK->)R4>Sx-&A=f_YJx}%29@4WOA$kDIr(|%3Z;3) zndy0{DGIQmaZ^jkV6mwssB4Y2XKeuLS|enT2b~!}gWcdEb_-30vi!^xFx${TlOaC7 ztRyK1bkrhv#v3ATuE_u$t^$wRfd;UOP4e>dQmyojGz@gi3?L&Pu(AQVq64hL)jAn8 za}HMsDdC_hOu=%l)_JA5sYRK|*cF*WWnHb4^K)_%OAwZ#m}L%?b+s<Z%*CO`1SI8Z zotvMRT9Q~)iQPU6n6#^PZfbFHVtQ&ZE`?BOSL?)_9PDb06LWH0twH0Ixdl1UNdrSj zpTZ10h!XD!l7J3p21C{wfI<Q^<6wpspoRwVa22lB@xk%wIr&M62xC#g!xAnJR+^kx zlA4}hlnL?-*lc4+oS8v;IA+iuj)@60qd=p`&=_PVTr-+k@x_@{sZej3K@Btq_x(*R z(af<xF$b&>Y*>C?GRy=Euue0`;DI@0@W9*<G}IKIUyxW>ni^kFl2MeJm=X`t6klS6 z;$idnV6eC=#%zf>wBm;j*g>0H=Fq7mgeY`073y<v2MgP5h&im=2~!B_K|vIP8rz5o z5OZiTi?9JSq-73i4`DR(V5Wg5VzAG{n4?7wq?m%KMY9}Q(qgsT1kxBolu!uE1H2&} zcJw(Qb65!qQ)&pBy~f&;HHY>ev04rFH_QcSB_+&oNFW4wC&T*6pt(z=kcISRkZ19O zyo2MB)T0Fkw9v-qBB;aAD?n5i1slfWa1pEx15*#KLE@3rgI$yYo997KL^ucMF%-g5 z8)~&=4((e)eF*gofwTsxaUkg@FEKY2T)~+``$JHZEFk&N0-O)wb2OQG>EKCH98;$d z;lvzJtx=L+1Xc=~PX(oa3+N<<5v0z9r9s3>KogKtK!ZI_de(4HLMmSiXd?{fHWSbw zv$2u2uAv!txYz<R;0pCUrqQW|pei=r+6c*LMYz$R;soK0Jn-^Fh+1et3!0O%Fon!P z85y7!aApuSQ1cz_t-;I2G9lw@7G_XQXc^cXstDv;M|+Hd%K~4rHN%}!L94|~!8MC3 z*4B^(W@5$A5)3}rJ2No{RKkNj4x4;K^EkMM08RZv)Vh{g8-TomtRGx1gA<nptV;sT zCWfGD0ihYJ5Me@Ieo-#i0rAl4s}f>}B_uS_sz)Qk_~3X<Ev}gm2l;}}_D(HMh9+~g zFfcTXN2mbDA~^4Y8k5!xm{T3#h7f2Tq}b5d3^Z$)mIkQ@Eg|^@)ay0SF*5<x{ovIy zP+7<Xilq^_s<SlKw5=#bnnJMx%}*K{7@1%s1xsjM0-aKT)?t>WkhTO=)Dqf)wls&- z#ZX~bKES>>71C}tgp>m4rM@LB!D3t13aNhJI>7}Td^pn*S|B0Z0LuK9sF@z8i$K%X zSk@uHQV$N-z;vOx1X`eBbqOe*KvT!?&IVSaja)0BH63a_WC?5KVAW*^)defW6b!-1 z*U$hu`U7>4C8QT*XaH>(T4Ic}VlzFttO8VOIO$nKk{2k88X7=bI#81lsRSJMkcJ2T z)L;rW%{3UZ5(FGF&@vZlrX{S{fzgm9CEnPh5^7u-N{MR=DRB)AP}8&ptWg3n*%GxE zg~I|!i4IDGm_<6s0%)0zEd(J2JepQ*nA@PuC#bIt4WL;I%7><7qEb(R4_Z3VMc4sy z9`=yS^+eO94NW}IIsxhsC<RJ9pg2Zz5RO1A$N`y+6kxh=vq28Rp({5Nq6?fTP;)m@ z5(c?~xTwp`1QoN;@V90F_jADntdDDKtjT~f^$S`uVr-&mn;IV+4_b%`TFsx5SriXi zcwuI0YHX%s4bcFf6b9=sMd$#nx&*E6N6`XV4F>MYfYn=SG8B{)rDUe1#Y5JinHa!3 zz*gXD)e2nvgL-hqMh5Y|@kOa=$@!&u&}CtU29Pd{A!3<IT4Hi)Nin1jFa#~w0xe=Q zG=%1OLqq5?Ekn?nsfuE-YAeJd7BIgU+-HIqVP>ugsws?(K-EifVsZwoTL&^*2fmaA z)R2N(3hn5DrgLB`T7u&<Q{usWaEP&nhNjRJZHAyVXu9ALDMQdI9MIA`L-;ZrL+DZm zLqkhY?<_L~wI>E?dKiMLW0?8iu3lzJJhU$lwGK3p0A4_cW*sOI!rS&x(?I=DgaI(~ zpq+l0d4|}XkH<Wy0WkAG0|YR`jEFZ3)G^OYi3jP1nFJd}fSG1YylEz&<ed@^GXZWQ zbhrU#q6z6HLQMdh2u@V6h828Vz!0>K1|v?4pq+a|*kTt@qQDlapiu{OgTdn;i76?d zT#{Op3hM8JD=W}~8PF<5Gf1NyT3O+0)<Tm3sI7%!7Pz&j2g(OU;MKlZY{BkOP_6|n z4@PK!83kF21#ih18bKQn*c}R5Ap>4&30fQj$|q1|pgamLDj^jlT6%`Gx(woTu{O{_ zR$_5Aq``&IgxbzA1T{x-1}L<{P0&>V-pM%JWQ;cM0f`aN;%S5ybQeL}4$vS$jbegM z!Q~Fvm^ic#0e1&XJ=hWOp0=S8tksC39^ByuweF!!UV`dD{cebQu=$AO0jiO32D_m# ztaXPs8DLKZ#<12mipycC0IUbrwuCk*u<L;I^9`Uw<G%698L7$H@x_U`sqvsH0#f;d z)>I*R1KJuRkR2^RohDS%V7UmCzY1~^lT(q)7;wfnhK>(mO%;Zq6-(gS(HPPWgp%+E zI!ag=fqHF4sp$5&26zV>#DhA1(2@Z~0i+jcXbf$`;B*G4DFZ6;z%+LI4K2a7KdSK% z+XK7<yg|FRGE<<Pa72KBOGs#_<1bsFT>(QVjl&V3LJ<}SV6$N^K(jwHuec;JCnp}P z24X*GjTTa@qvlXhjSu#`A>K$Z1lf;bwkzE0V1_B!LU=I1l!6;BP-j3Vkg>-F)O!2{ z28t`dMnhZywH#77STlf{dC+E^nYktdj*(?>`wlerTx<c_1DFm@x1d#0pyiB)CPtdL z_AWq2@}b5;w85%=(Eb2x@ccP^g|anb)ijwyYG9XwM(2u6@<21)kQo{1_$WjSTmh#f zmLwMBl){>Wpp{J(#qo}yA-edC%#_q3E2z_b<3UQH(E{xSSwQ0-x;n)Kwl3QQI?w=< zho(>O;9~Q5h&iCrz)25O51K%;8%!<CEZCxLR4bq+AsG~q3@-2>`3>Sc*fI*3k)UM= z;GzRG)n8E@ACy`ESr%%7-j^%}CE23X0*LcKt%uB{)bvcq8azYTTrb>Q&??m8c<A6# zd}aw`LJ&NxsRbG9#2gt_z`m<Q2O^F!HmU$wK5K~SR8SEEaUGItL0ukj>N17YhR`6- zOwCI{sLDxA%!Y;(T0}xCB@<{QpoBI^7sw3IG%B>NfEofVx1qrT%Z^YNn?lTjwliR( z4Bo-T@H)aZ7c{wG-~=v{A$3qrYF>It2Gn?H&lYMtv?ziF2-J8eg=veSDZDCz80wmf zY+X)fZe|J89@K=0-5XGQ(7XXQ#WgqA8tRFZ%;K!lykwZc(6Sur0cZ^h^8gkngDNkW z5#ZSrsIkfU1<*PQG_?xe@c<ok1?MY}v}-^zw54VbO1+?lEW~$a$SOg?XetwnK{Lrv zwT94vRG1!6QiCXP4M@%fWjK4#JR``$c+iwFWXZE3sN;*`D)1OELX~SkvY%yqe0p9f zXfL&)IY!R$42};jc6AK~Pj=gbN(VDzG^dbkBxo-s$V?MZGY4X(2|+W1<AV{(p(Fc- zu+YGC0>}<Sum*6TmxA{9LxU1EZ@?2TBvU|B6DkEuTfxPkV9x~`=9&viT#%dx%7^h8 ziA5<88(>QqiVcn8edFPhu$&qkpPE}xQW;;A3R%`>Xl4%ey%}_kf}tt20S__(NjcaA z%*h8sxP>@pLXnh!TF2PtKn+3Dxu6CHG*h4jj3H>67u<USRkonslObrfwxSrVe1sI^ z@L~$mdrI_7cEvg@3$hg4eJX~um5~&pwcSCJ!1!DT-CSa5g4O^lhPa>@yY=RfGC3G( zJxmq4-T2F7bI5Qgt~3L6KyEG$CqSobVNQUnLw5w;bZdy+5$4e911&y^b8~~dgOLIo zb+Fvf9M&p<#0rLTbf@8{4<K2}1SNPt=?L6XMRpRXfW+@0=o}CzkT4aaI|sGeKugF_ z=iqV&erG^Cs8DC1szrANY8`{-3TR@1E}+5|O}WXa#-m3ObV38<6m+Fvmms>y@Ztg7 zlZNDduxZ$oz={X7?kZ?<89Dob+OeS009IJQ+9%Lth$t~3Jz8+a0@WU%Ib}3+z^MVM z9~L?A#E}>bu5OJS!7WqRtTN127!B184NYXtkR=jGEk+CIR0d3|DI|3oLXAK;+!U+{ zG;;&B8?6uk%@kK)YifdSCsqK}!L)C1BHZYtXAN&?T0jRQij5&{OjzJS3L5WVxVV#^ zbrIN?ka`O?i46-H3k%SgaZzenYEf}2qAd+?E?8M%G#8)^ZAi<R3N3ATTN_f8AY#W1 z;&7zsLCbES+1-j_5*?2eb=3C)X3qxU2T)8P;ty8XnG~T$ASBCs2N%O7K$D8FX@5gY zXxAJXe`w8RSlEHIgSytBpmWl*hBUz;3BVFEPwyREYz7gAs>w~PfJ|wC`!NVr7BC5@ zx}sE&!BDe|ARCpSj=@{}!85EG#01w|aJB`N7odrE<njVqpFwjgv=oJTEw~tN0JyGA zPAo`F&Mbkp(2?8?lR&sTwWtiT+Q1Mte~;JU2pi3dQj0;FT_M#w_y7(_2*8V7=&2l# zId5>=5266HCIHEAXuS}a72d(creIA_$HEHc=vb&JXzc>fk^)f4YyzFYNA2_>nVMMv zax<jM4_gBO^R%TUWVI}`M8y@{5F;G*tP`OfD@#bj!8^FvD6s^^ct|S`D(Z+>F9e&$ zwScwd3w%J6jmQ-SL~DT$T1@~K1}7Hl#DW4u4uTnG1`$Oz(FiuF5A!RGhI$f5OA3)j zk&J}2)j(%nfR+Rx#ib#dq0o8_Grd9$1GQ;DNfwmkEntm*nBzfxaYz|%1Y0%$Gag1m z-3~P$8fzF%hGZ-2g3{uQc=#SNBLnErKg=xDEQW5DC0sXje;%Y43Q3FbNHl|pqK7*q z%8(^dLJ(CNN0@+n#Yjm36eg$|q2A2QD^4wfq)Q{%0tW1UG=w$+a0MU4Bv%4G<$z>R zPZ?r4I7y&47@*^3sBr~LZm^6QTx<rl4%9@4WdkG7ss=pi3+i&1VNfoV!eKO0(4)2A zVWEWTQk-cR=3b--GcrJHgX1+4ivy9<JX+0;-6*JE(UU7YFcI+rn$$-QN@(Q6TYykL zE|Z8#1&|^swJ5O|QmYt&77!p?iq{i}@Gu1%0UF1G767322gv3?9gFUG3=@cQHM9gW z0<CQz#uAw2@PY>FT%s%k4Jm>8BGBm&Z~<ZjI}QdGJTMwHB|_sGmf8`XHHRAJ3hv*+ zGY@F71hRjKG8JkGl)`BTA{T*HUl45zuFQnw1LW)kTF^nN*;t*7l&?T*Lx?sL8Vu-} z0?D~Z84Q1hg_X8&8l%q$H<j3g6yzNYk8IFV6+GU8+X_v*1S5i2Hy}qB>`WL~LW9xJ zWQ@ZNSR#xB%VC)pbo2}f{wEZ%#JT_x{jf7&V4jB2I6Mzp<^*c?p!e`dP6WY*phf)f zU_k5V6L1AI89*t@Vj|cCyhIn&1^}(mAt5r*69xtD2sVm`mat%Vpmh=mgodF7w6hAM z;UzrDvEmnO5bp^ZjR%eRn}P!dG$IczsN)k$E1)GmY-r8U1Tt|5UXYMjS^*kp2hDGQ z=b~WRiWAdd6)U925nK$ORzjACOe;ZVlR;aWK%M)dQs@+r5omoBcxD9BsSbt=wI{<A zxgy5YK#Sx-GbRvs!q!4TLlC`_4N1k&Oa-N2u?XsUgA4-A*yMuO*%p^4LgoOBU@MoP z#-eqX;oS*%JeYvAx&}dtJ!|kG&Jg#37C9lMI9P&)_5zWdVhYv-?Nq`il8uZZT_=!R zL4r{E^wg4g_&`6@BGl0aLv!fjFie{ajZw5ijZDkTgUpv0!B#^-{f-u-CXfL-Xjnoi zB!8HI3<C8BKs7PAH){ks(g-OG&<un%8*mu~s!YJq1IjqCB}2rx4XdL-@eDQywKss~ zCP=-C%SFjx=U5kkd<qSG)clNQ8g3t&g3SPT%fM!WT?XlIg2ovjvY?s_A&c5KK(h%o za*zT5Y7xjNcnF|&3D8W!6#`I$pg{l%f%vq{qT-VH{4{7#K&EiKgNqG~QKWJC5?vX{ zjR@~T#!j)A22uw13VbLP-7sW#<|HCJ6H-or3^oEg6Do_-m8hyfwj&$~86d<o3#1C} zMo58*sR-GLkf6-V#~PgGV0R)b!Rc5mN<nTxxEK+vIF!PjjR;ySDv{j|4nP#ABZAlr z>~tg*I9-mZ64l{|pvJBe?rubIV=9C?ySOx|7<#OZ5$NPCq%sOxzQC3sKuZEBg_N(% zAZCDjgid<aplO`MB4||zTOkHB3$kMqRvx3ZvO&vGpt`|f1M>&$SSzfCK-~kSV8slQ z^UPsJ!a87(0vWU(3(2#vfe=U|18N$Sf*A_sLMhx<AWD4`v~esH??VeJZ03NwL{N94 zH5yTjfI0<A;V}@hoW%%gBx<>j&+AYlp%!3sD%fOjrn0tXNXpO80q^>^Fwtay?2O1y zO9P8o8fY@WFExOO7=lg=NJ%Uz&&)&IcL0$x0!g7MH`cT*H8iq-?|8ES4gDK|mXm>( zoP!t085)5P9<cyzo`7tHgBs!kQViPQ0^V0=%@FTclAoKI9ABPa1UtXL60uJMyyOtF zPXoNGqSyj*%qT=0)HN^z*#Ox>fw_MJw)rABJ{f*^CurZi5opO9sD1-2X9KS_L)``n zS#1d3`vB7jUTvQYS!oMCN!ZB561sFB;$hJFB_@yp3b9HY>`u^fdWcT2A)syVkk$WY zka7V{Inow*;<jHxU5jTECfZtfBiNEVP?&<JSRv!OM)0L~hLBxmuzDEQw1ge039-@H z$Tb&yBocJ-HGDBO$b9gyE1G&kxO&uCXd}={KTsKf#XV5xq3-I3*zaNlJ~{@z!w^1Y z4Kfdl{h(vWLFcJ}&xQe6h2zju*a{m|*SmlYHw7Jw0*Yv;?%??3qEyiBAh1*dX?B2C z9)kN1koGcK{DODOqUm!D3djU?gbYFFeL+@h<>cq3B9bjA*BF6Ld;ysYO1@b9X9!9; z$te0j=2{y<cJijA7MB#|SE8GVwq6R=(}tk5i>?vbP*Cd~&GYbG(va#A-S?)TBP~)( z;LZTYA=t|hv*2sljX;OAfV_)-ngt~G!RxvZT42Wbg3e1v>;{2G2()<#iZ*D10#k<2 zA{Uyz5!=S0R)E%*V(e3atbD|}PsPX-lA|#U0<8^0*8y6w1u_dGb3%v6&>RcOoFGRV zfmRcOCh<V~%|HUM$^b2(Axn#3+XcYK#v_hiFhW1s1L9%Gk{+lY*kmGPQ-YBhv`+_f zmJw+EAjBPz!UEZWc-#e9^Z~U4azGBqNYK_n&<#RXR+%ZV0^d^8wiwjoM>@Y9R3br6 zYYqlQGTMGUluTiinF21sVby{w;v51<ssOE4gp@jvo;kE*Z3H__1+*~^<Pjs#u__Rs zLV6+?A#RkJg5oXo1Cxx*ARQ5S6d7fv;Ex|{8o-B9Km!ib257Gj=4d3(fc${X$v9U8 z8ks>_%P7u;E&c%=g9GiHgBB+u2OubNKy@<OMh8T0Fv?5;E%40*t!@UL-T;d9yma_+ zNT4P86fdQ>LRk(EURZAkS|?v@g1AJ$(A-E9G}2T6Dpo;*jF2RSo)bZ9F2VjYfs8Z2 z!xXyO9b_&zaG~i3W2u&*5wc^Pja&opF5EJLH3&chPDqRTLA$fiG@@0YpaqyXTncs| zw15MTWFZ+0u0cT)EzlYqQG=R8t1dK`fU8iD2FkZQSb-PzL*fTi{}&q?AtJ~Kw2&0C z_8%N6R-gsUuoWfHLz<vzwAch>5ICp96o8vqC8<TZnR%dtl|ZLk!CGcWs$mMis==!$ zK+A69i%as064Rk)PZ@#Mu_9Wv;B6mf(0UDGlo4pxD28rSGr`3TXelqae1hmRG>S)E zy=w%jrG4Wwi@~dcQ=wT5wzL(r>=zW1(1jpIpi_xJ4Ob&`=#ft_1+a_`8l(dU3}~G( z+)(KF8YmAJ#}{WL79rUKavZuYh!TXZ;?xpU=fO%HQ|JgEq#<c&idwM-L;Y+V?;DRW z0%R;?ku*pQWL08P4z#}tUu6o3T~MiktO!*rWI<AVVqOZ^Pe`Uf2dIz&2NZ}f=b`nc zpsq9m)%qaIuow$kwgPc-QED1!3=|x-MzC{x;PyZZ1RTKt-E0ohkMKx(QDPF*G*|-w z7N}^Z!HO9e4bR-*umbJb0htBrxr0{mLPz>R83@wogjfPvv<Yflfx-e5^H9%&+ItXX zka<#&3D(f0nUYytkPn-*1}*XgmpCv-qQyLR#~FgW4mAhnK+voVs4#{$Goj9dE)j!= zC<(?x+PUb)gPQ@+9T}hqL-I7(RZw|Egn(PpP}e|*58$rB9wXS(6L{wgs8tSg5o9%( zH3NLm9K15p4%+Ggl{m$QNJXIqc;8Z9YB^$*9jXE2d>JFqxklhvfsMFBg3SoDAQe<x z7$U?WJt|QA;%*06K>M>`RqzG?xI{*3OTyNMA{h?KWgtsIG{$ObuxXI9!60#u-Z+Jw zYy?&aZuLOth9EX0YAIy*;jYV2RKa{<%@7aof`ErQK%FWoG(Lh-3&5^~#3r~N1J$9R zy&m9AQlOI-%@Jc3u+@g3h6t$n1i$hGoE$-iQGgm$29~gsBCHv(B?NFSY6MCs#fBIy zL(o!PP?`YAgX061CZMetByn(>K-%+TjAEH*vMZjX0_pkS)eH-J3@3sX<l=B5$i+sW z)vKTexDn{cCD8s765Sl+9Sl051XOaPr!`ARLx+I7kqtm=dO;7v!e;=Uq)9l`;7zW? zl$4^>V#ww#BiPzkctAi(BqPuYRZvC;g%l|03@srN@MZx%cbY@3a1Ba^4f(>>p~CDj zfwY7{_CSnB-BROCobjO337zyn2X5wr&IE%LvY>OXP!a*e<wh0|8d|s-f!44>d<Z+g z1d^U%KE&q&3uuv>3fja7S#z6`3KN660$TaPJPd2|LtO#tEP!rLg1CtoI}HsGR)A)A z!9^adr3$vw7`EyZW+$j10F6#sLIN9R3*Nv*UvCYct%h0w?Y+aS!0s(Wv{S3_g{39j z25_$ivZ@Wa4mXA^NF`t=wE2S1E_0~4t^p8htQm0JP=|DcG4z%?<h$n>k~6@!&>3nX z>8IolQ?MPzphdD3seb9;n=NxntQZhX@JU1<`BXpmcz<sz106s2_~6hWH%DjJcu&88 z(2#i7pdkMsD?^Y(n7>b`uWP)Uqo+@3kgJsuNGv$S2SuSVSP*IgOr;4((9P4wHQvuZ zB;L(G)X&ArRL7bjH?<hzV`I=FS5U4oHZTPrT4xMeGzt;`9T%Ki01g&o1L!44#-J6N z6~$ODss;NFbR{IX(gYa?@-9dKbRQYwu1-k(2R5nL*eEx#A_G*#8G{a00`I=pw6?G| zu+{<30;FZ;rRIT(Hqh08(7Mjd#JV^&IX^EYzbGZO2&C6g6LyIg$XlS@1o5DoP{HGc zpi0tGQwMsJS7B*lN_<K_sQXuvngY`cy~+z*J0n^z#;_%yAg6+hG)Qp*3JfS0Tq{B@ z&c$(iFV1QaWICv!iC;IYUbJRN$u9+Ufgs7oQj-A`uF#MKtr9IZHZm#5&&-1zLS+nE z@>x;r7!>3fX#=@i*2)T`Cjg{K$IuRR9Dt#bg>`C9No7GXWY)nLw1g8~ldF%bud823 zNMwMkj)9#OIHW-ui&N9V_ie(og4?2~_60+ffVF|{Rs?G+ElNv;UeyWHY6{vhgsK&K zo2O9<ShKN(3CLdSviux$y=FM|f_0i28i94@<R@pRrl5w9Ii^-{=y-xIg#_z1Gcf?` zE-ozs&DRv?=jG+6K#wyv2CamwC=PLS@^Q7v%qszhskxa2D5+T|<(KBABo<Ysrht!^ z2F)xPgAUUI<tt;*TEmKBPd^veh<KxTXCMDySC@DX$6yb*S$0-BmXKTNprM=rJ$eje zh>j)XRyvTQprHYm1}!0k*kJ_n9K;S|oOVDGKIqUis6p_AV5+GDnw$gs9wZNS2VCAn zQ^(NI6dtx2X{C9|(C7rM<b${YoFpJOnu5~}cq}agbdV}kDJVx98XFpc4$=e_1S$Es ziJ5s&Nzf`dSYm{vesG)^8k?Jeodt@Kl+@&W(7nqrEm%^6TVismOKNd)QD#9&ei6h7 zQv*nP%1tauEy_&Hfq4tGybER}WG@~##hV#JJerx33OfVN7__1b;!E%uX`Udd%(Tqp z#FEVXykaXILvu(h<(1}^r52TBCc}?#)6_9EhXgz<&{GqOk~2z*Qei0zv>FR+Ht5Ky ziejhy3geUzkhG4W1>`zG44tri4=M^Rpx2n@7v$&Ur&mJ52DDxZVkqcT(qd3q5CT)7 zV`yOkz63G3w5TjK1!OubNI*-OAlksW)ETS*nma+>v@`<8YI06#G3d5(m}SrtM2tbF z{Zte?=4BS=mlWj}WF|Yq6zUjSnu4!TOv%hm%`48#hsHa|2bLD#OA|rotreFf<`zIq zHPqBGGB5<+<CvS6m0yHS+63&4+|m-*wXVjXV}L+4mM>UL$H>6KK*z#5qX6Vd(0#$6 zO28Pjt^({!&}s-+3V;=x9sxnAX;3eN(~ps%A=u@~`H4lvsh~OsYzSx(1lSPJ<dKn~ z3D^(0={c!osX4_U6(A27nnOI0layLgo|+0SP{5MLpydweRzotd5x8tIGBU6LC;Z%; zg2bZKyb`DnKqec5mNCFIg9;;1x-~L3hU65O22hESn4F5HPshl_43Zttdtb(&(Q#12 z+Zf~{P)!Q00ZmW`@sO`E#$Dk-C+koY!|FGv&G7y^$YxOOh^!cAUkR&Xn8~PfRmPy3 zzL0%n3|gE3>OjK0Xbkn6F=!zGSOT;X0MxUDsem=Qk=+KL;{lC;yQJo%mZX9*7^H=b z#p8ws2u09wC1=nj+`*8F2AbF)JvwaOGcv%Y9N8r3z1*;x7LrIH>#2|(ZfFTM2vs$* zInX*Bw^Iy_!6v}eLG^~D7MJ)#4yQ2&Er&o3bLdF5F=(v;IKP;nPM&!qJJ1Yb63AF5 zJ!{956mS&{30Tmg1Z0DaL9+!F#b6cSN*sKw1UyDTlkead1<jU&V-$2<2~@pt3Rp4j zglz${+cgMu?w2{(7UL9G$a(SZsU>~^P**`mzTxQwydDVTTjW+FiYHCM+M#{~8w@oH zI!X;Q${2PZi81JYkP2`i4p9y=8s<^lelP_qhBz72q6SSEqXr-(CSWFk0u*F2wj>WV z%P%<I&;V>KIK;sRc7TnBb}QjdhfN9_gC<uYp%3XQ!$SrfPB5!b!v|~u$lc)OQO2No zSQK|d&lQ6ih3;-_hG9A!>A+m*Hd&BGpkfF`e`bX%Hoag^Lxzly(=S%lj(XN$AB9vF zKxQ?JK@-WSJ_0pmQUm-wAx&>^;)Hn*HG)wbX9+hKDYVd2kr`wO9n3hqp@n21HeW;h z0WBS1v!aMNhi(Wq2F*f(<J=H38w9f&Yiyf={ZI_a4xnHKP5Ge&4rnACoReY3K?`k| zamW#XWSS$m0D+cNkQ@e^MT0vTG<{Z43{?Y8(vYBs+F%TtRRdcMx&;I5C3A2;0;&V7 z7@IQ;4IEQapo*X+2#g0F_kq+0P$8(>plefLZi9}@z%nOlDnRzKp)rbSpp@XKXALT2 zf>R+^6&jmD=15V}jyY5XB;c)mGV@YV-2)u}gSp2TG*bi#3&>a>5iT=CG8N)3Pz1xK zjNm4lL$;yAlL_vk!4Ta<NC^QuF$8X+1!~j9*c^2P4JG(cj0B~6BWO5)(*wMSgPkh^ zw*$@9=ysq4HmbX^S%RfFvVbfWK`{tgz@R%39t@!J3)y!#)I;+IO8Wzn3_+6zD7g<b zl~hrT+Ef9D3^?(_5`i&jW(k}+K(j#LoC2C}s3?XuZj7K6E_9F&*@=ecpuB?O6iAk_ zgzE)If;BXmqo{;9+8i=`j%=zCw9SR;aHK?tmb}rjo3RBXO=8R3IE)6xswJv*;BbOC z9-P};A<o5?9nByLpt%v%7>F*|<On<g!e&E^El}%mJVk{Gs=<ih08OZ%MmuV)fodj7 zk~G9(C?q|?CMS?x3~FE?5)JM^#xNCc@PdjJ(3A&0FQ7*$eox@B4og;r-mHOQBsA;c zND}Z6!jWTfXoHmOsIge=p9UKCfTj}YT5?#J!_u`Wq(p?oqcLcX1)N(!vna5hB&-LF zYC1R#gFC{IE+Kdn6vd-PChn;vsG6Woa?K3#3ywDh5B7QD3{js<16Nm9&`cAk#gEcC zf%*xpYBUBNJpwOUzz#$yj7&fiDIo8efR5Y%6-FkYIS9B8uwraE+tAE0B?ZL+kdnw8 zS`s0$GM=0aZr-~>Gct-{VBeU4rU8)CsR?LI9^zVPa|zn|fW#G6cN(LZ3(v+TpizBP zvmwz=Ox22MCOD0nfMy6#&4g5@@LY^GwTN5_8=@HsN&`mFzy!w|I7BrJbWA{V4yd-E zx*Qbept1uN94IM}7;7+dEyzw#?n5yOnrqP=2@eX824o-NQ17T`4fQ6x)o%itO+ob{ zXfQDqX~-R%Fo}sPLnOmNu@7+`d<p|PfMWt0aRn8P(9DlN3{lL)7Ew-m)+osi(ho2J zO-P`43p5!4PS2nT22k!ZHbkpTpsfIufHyQjH5`(GKuH63-~+5kGXb5|0I~pXE-b@9 z%|(tMY{nuY$F-;^A9{y5>}Up<EubkXP=X^SI$)^<Y#by$Kt-7kcp3uSzky_Z*bxmd zJ79$~)cxpPGgN;#rlcSlh^1HRsAmlxoIz3ri6U%cN`~ebYC$3HsAr9#-2^oEff~cm zo}LM4asv{>&^`e)rD4ydM#x5kY;%J2Q(V9k0Z_MMYaAIGf?7vVWeANf@Udj@fEQMs zM((L4aCK0v!AL^jh%v^}fHX8hRtAbxQ1~Y1BtvVuV*fNh(DV@4YHWjk7S0%oLH0Z9 zS-WLcfD;A8$0nd@9OU3dOBE)d(;7g@-2^n(0t#&tBk){{Q)Y={QBh(gxYU4!IC7e? zgj)ou#w=huz@@IWTV`Gg=x!ZoSpstnjs^rYjpC`4%+L*l1{zEl+O2}wgFbKuE$>ON z2WBADo}g6F3CaF>sXmF7sYTFeLh&57j9_GmS06OWK<N(@Rxm5U$;JdUgM<=u;GQe2 zV#F3DhTwKSvPlRFkVK)zqqlotT~5Mb1Zt8YnFkFaXVB#i{$;5}If(@YnR)3>(1}Z^ zb&v(k$SKIk1eX@5v%%8N`FX{e#U-hEB`5}B9d<A>#-Rmdpp%|8SQb(fAjZ_O=4?|m zrBDML%Tht>wmqPJLhI&{P^w$NOacWS$YqH+$<XOdoO#{=l;<IeK+bX0vkp!zf$$;j z0ZsOyq!`pxZ)^(LLj$LwH8{4UWC=GKlDpw!)WOE_Dd172AkYff%w$vtppDd`6*k0J zY-oaNFq-w)>;{bk!2<xj31w)3Y92^2nwfAfA;Q<KC_fjP$3fGSi6y1bJ<cYexlepy zj3-Quks=VA1+Ea!p}GQGmb+vYmn7za=6!J`4kK`d07(oWvr)A{lM8A{K!eN}a!e+U zR)Yy>(zYVCD7CmG1AIF-sMP`~reUcaTk^q(MZe&9OSmDfnGm1)<R^k!9f>)h%oq$i zM$`m$y$miVL3#*Stu@Cm5_B*JIK2j^mbim2!G>mD=p9AK1(KlwLJ>4Fd=o1?AWZ{E za2aA5>@+k$sDfta;M5X?7(^%RDjQtB0!?p&D`L<rGpHgqM!WVF#ihn5Hb4?Iv@4tf z>+(Xn^DyrcD63$36Beu}&1X=7?*Xv{UJ!u0)b6PzzL|MYD?k(8$XNrHKwwoC%nBF{ zvkKW`pn+qMiD;Gu8$%XnLlZdYA_dSaKPWetfac1Ptu+D7euF~N7<#!c%zkY48JeIP z3C$_)sU=SNkb{9tK=a|q=EDj#Xlv92G_wu1&J;4>1QI~x5}2hZ;R&jzo$@POK?4}@ z01Y+*T^J4NY@yFBW3dxt1<WdA=rjyTmVvS)d{PK9LIP`uptftUR*)bs_<<S$FtwnN zbJDX$5(1}tV@v4iF37QLXo#c?nq@o^i$Q{crHLt!MjX}}-p~kH9n{X?f}G3}&%BcS zfW)E_sAg=9W)oC}Al;x!6r?*iwIH!5u_QGGG}wj52urXLsH&mnz?vtnDd~`zI1|u< z0OXW|G+PadJy?$nMq`aVLnCB!F*;`8CFf3h)}F9=CUBsGYz9??D2dJzt_G(m&<3a< zwATt+w}9+^*enFB*9vnujK=B#OSqvpt#!`NEr72&$JUItfT@56b#Nl|uw)a^iV9>W zVq_FpXA-nR092|%CvUJi)dXZNXah|#xNrm2C6M4mUmXCm1=>_Lft@UeWr)B8WD3+w zM?Gub)FN2wFohg;jhrt`!O{rTp1B1@`DKXpA10tx3D~>~a|mc%LPe^7K!~TWXOyeE zzoQS%{+pp8lIh^6F+$b{>BS)_@k&h2Ps&V$+<RmKTK7P}A)q7<3ua_b8d_p86_*3t zic(WS#R9yP$t%k&%FhEW7X?QRw$8PYIUZf0(grjRk(!>E6Osx!o!11kcmvrtXc-kW zh>GkRlx$_;12qa#nnN85DNkWiMqsystijBca5Xsf7iB_bT1`yRdbMcI1Wl9SbfzW5 zo}$cjNY#om{{`)U_-5w$CRRA+r9(GJnt%>RKn@qQbPucGO+af&z{_v&w0;duK@D3Z zD_m0oAk9GE#G-7^oE%UvLPHNy0E2qKpzuOXJXlo2N(IQ|9jGzsUzC}eR{~x@2@ZN} zg^H08w1tnR0cIMgS}+O$-Ng%PW?(bH&;VQ;fE7V?IhAJSq(FTU3|@>0UTulX1S2Et z8la}Rr<Op?@=pV|=)s;b0j=0Ui5AGn0JK2@YhHn31(Y11sRYt!hh<2VBy0$3b)i}W zNhI*LNkB?cCb&#=PX$%9p!*n-OEUA)!}4=nbD*(>z5)oASkRmWcOK}h2XMQ|1kx?V z>NF$J;GAb3Xgz2ul8tE23pS1iHKm{p;7nKp7_!O>RHGwS?LtBjw1Nmr2*Qd{(7Ga! z(@a3CgFv;0320GGMKPLDpwNZ68YPi}CY@2$LL6*pf+h;<nfO9i4?|stmd{}!33VPM zCZU_8u-b13?j1lDB)fvnd;!}7YOJH$gSMInY9y?Bhu8zN05!#cq6Ow?P>~8MK|rex zQT+!=8Q8K8bk!l6azwKCb8`WQ1=dC&xb5lY0#Xeb<V7_GtkDF01(AsvB$*N8J5YW= zH51}T(1Zc(mMU03&IGg|36fYK?SFW81Dq>i!H1eY+*3<1&4={Y(3gLMiVhR>WlJXT zWlKiTm2a@Lfu#vzXaUN#sH@6BVF$ie#sq!Yk_l+p64*bW^+}+_Zw#{onv-E(LQN4k zECD5q{M>@ll2pGi*y44Nm#`%YLo-l24_PV1nc($CVc=-RnjXNDqG2GlPT(;y*z!p% z1MjB6pw*S2*aR({D=kV5DauR-RRCbqO+YKLkjn*V*-1>AF$zF34P=3no;6q~wFGWH zX#FavMnerbLnLKTPq?R+z*p3RLdyiSG7Q;aCZN**AhBerX$y`e(0OM_^KsZ?36yVP zCPVECEl5c$Nref5!vSmLn4l^I>4v0O&<I&7tkQ#Ic@xljE)@5I)@6a*Yitb7C3q7P zC<CGz3$hN9+2PCn!2yH5I?DvKlnP{#323nqBw&b{J^}>{%w&XJA(^?U!QgEJAj_~O zK10wX5L_KpD=3wvR+PYnafhlIx>Aq{kZ|<{?My&30&8C!6k4c?L54u{LTW_`svJ(Y z7=fw{KMeICvp_u;@TLb)FqnW=ZJ|c48RWJW&<+Vur3fzqv6M!p;N25YLj#I3^GbYE zb3OCY^1<#h0j=;tHXBy=L6eIKXyF$mdM&|w3{5~Qmnw=OS3TuJP9X%JTmZRj6}0sx zzN9EIv!oa-Y6rW}3F<P`oM?pX9@n7Yd~ln`ngP7V1pD4M@UD397P(?WGsJ-kCZP3G z6~%5jiI8bD?3y8)lR>)-t@I5+D_~$d@bk;_a#M35f}k?U61>v`y0rm*1fB_EVHIR? z2Q;uuKx?DG?Q!U$R@9mtS`|TCOQ2yOPyq#QU%L8a8oGiu;6s+8Lr?5Mu@F>#5jMdP zR04vx!h?6RBbfj_;Sv;NprnH2WH1+8X_|m`go8Z*-H;6{%m`a-<eC`(9uxsv4mu4K zu?^D%x{`{pDTXMfpnCz{Ji`cekQYoq%bvhV6m+Q(s01>BEGfd3ia;A|K#>nkl7w9c zI@SVwta-3uJglvY)w__vYQhGBj=#WaAlT>dtu&^frB9H|iPh&s#}dx{Hy|5`N?<Oq zO*z4-CGeR8Q_zYmeC`7$E}~s&4mBH^l!H@C96@(rqgY3jW5KiiaJ^9D91+(=nSvIO zp|~6DP*64oB`9O)mIR_5ZU!+MG>!y4kpi;16<orC0*NSBn?W=|oeSkaHUW`l5Nr)O zw1<gepig2kWDJJrn1}6m0_lX-A`rJZ=Hx)#g|c-5cQI!P*9SERb%U2FVl5pcwHup5 zXtLu4vb75mC7|;iKx^}mqaD)%NaLR9h=*8U1eq%dN+ms|nn5(VW`ZwJN3Zyh7L$S2 zY(lF(V@+F>s?QX(P7qtwho+sv%Fh(BbP&?9gVrRbpv8XRy2B7E4$e$C!_d$W$z87C z;?&s)nnuy<KaibR^A0vca8-e(h^2Z^2STRlK@JCHcSvPz3Od99<PF$5J5oJ>vlax| zPl_jy3<6gN@VeX-u_O?yM@&JB_dpe)DQM9is3HWN3IO&ZuBr}OID%?B`1xXJC+mQm zK!RU_yb%V0{er04K+6dsc@e8$NC|xx(2>EQ-J8(lgJKD>uEk!#AyzA5cO}V5onRej zh_cZWQJ7+hDT37;XlW%%7=xV)OZTRrMUs%@Vh-ujl9TlD*L@`ThG6waf?34XfQFDQ zIT+0~Y(Wj(fP%XcB*8F3^&nz}CM40Bf{vd6MHDPMBgY`A*&9-2A?ifXqEF;B0<sKb zCc+L#`AABJgxG<lS|lL~@z;#dIZmWn(FDC#1TDnGRx2WDrL;x_t>uJ-9ejxlIOsr2 zJ3&>6u_06(obPakpgGh@gepTL$jm-QdPUQZvmOL3G{xaukh3B2YzjKN1MGNn$S@8G z&PJ-aP&<OAMmS0}Os6B60j@C+wVx5Z8wd?mXf<vG%_X4qo1k1`3Oe5dQv1Obg7>)) z3OKwKpAn9}9fl9^)OoNwpWx{N)dxg|H16uo2y(R*0e@nz=@4rf;eiH96sFM7g(MCl zT}ZH!gWfqsz@Y@|H_#a?C<z*z&tOgl?e_(Ffk;Q=ugHjVF~K^FIAe&bzKDx$!reFG z%pp{1A=YU^(vK<VPA*V(ge7(|qXklzAnGg7`bgwB2iXIPWtj1%MkEzm5aY2_Rm8;< z{#pv!0f(G~1?|0=qSsTP)tA`nDHP3=)>MeakdWB`Sl<n_2ohY_8$!jwIS6NtL0ZH> zpyOtYqqxK{0cULmT9yfkXsFYmg{3hxe!(s^g`fTd-8M^-(~;^LwED^zWe+l<6^_mM zNT#6GScnChSiN8hT1g4YBBr1fl#m(=t`K{Tg<(J5I?DvtzzjTXL7N<)@kpFKHN<*M zxZ}VX4i*u(`j+T!#a(Zi;An_rn1FQ<60{zaU_v1}T@b9hP!~GlP8tMjFT|QtXt+XC zG$ehaFD}BUE71c7fBi+Qs|nU%#2Q3g9Y$=-6RyRGHHlC?hFC)ii4{}OqD)XGHHH?E zrqFaxas)xD8bnQoSW1bo2{~hdiU$y%=%fp=083p)Y@88Qn<4eN%+TvH&~Z_C>N1d4 zN^3IEx>87PhipTI)nuS0qmY^mDh|#~IKvLU37kMZW{RT-MbnS77DFr`g*ppbi@`1t z0K3u@w2Tzwc+k#vyity3ExyS&Q|OIX7zGEK8Th8&OcBdYu{z%bHs6V>4nVUDZ*66Y ztB(k+t%#|s5DQDOx|hi0fV-wLg`AyFAWX6Mun?<BvAYeN6o_;o!CDHsZh?S93D!}F z1*uRsgB@uKO}(I_8AwR3_-iQQTuiWjBF-4%YA51in{eGkoH>MQCeWf^<dP4xa~>4> zWX1-hwm?)zh()fDsKzj!w7d>69!q6JTm<2-iok0pz(-DisuXC?${f8m0xgimRvV$} zrnEu=Evtn@3#8!&tB^oTUO{ELG3??jaMr<@zfn%&BTy-sq3mQpG(oYLfwN))ExE<v zY*3<tjQ5y=*5iUbfw&L`d&dNe)p#o>=v8PK<r5Zj@K#Wub;5YOVFEqcpR`~{9>PQG z7@Faz0I<3n*&J}!5HT}l1|Q7CNHyT#$5o+X+Jn2Yf?oJWL>ObQuwXaA!Ba4_?E+gK zL27~~SZP5o;UdDp1S>AYYGi2mf*orLb-F2NQ8B1dZwgvW4DNZ8p1|=}XT<x3V3kI^ zQN&ei#HS0wRU7eU5vtx0ORga?W(r?&4J|;CBag&90;!A;bsb_2Ho`8DkuWRBC^jHg zV5#qjk3IA{4}PXR=nQFSC1;^&TWn;2SodfOT0LG-?Bp2i8V^=)g>iqBDQI0eq>O|d zEeETiK#Q-zg}WhK9Hnpvo9CGcTcQZLS_L}Cj+mA)M=cRiG{MGe&=*pgB9>Rftp<m` zIi&3YseRB3Z4{$%E*UXLIrzd9MH9~25VX1*M-V~W1>M$Y3R-6kDlbey>#LC)7od~7 zL02<iSy+hT1W*?Uv;-8sQWYA&ko|v{p^G{YiDDFJ)DE{%(8Y9+C0cj_1+7$eOo3cd zXo^_qjVFpsVXME*Aaw)2C^L3UNpZ~#@`fyRbxcVygt*NDby^eIizXmd2tA&8$)F`x z0Y#wA!;n3{pp=BX!~<Ekp$V!6SGdifeWwI12W=_>DMZ*0I@&U^ES0dkK?hEQv>Kx5 zb<Hg(sf1XICq6)W!78E74Tf%-GzG1%$CE~(c?MF?SwQAQ@kU2*YKdzmJU-mv*1(Sp zg2X#0iotmRbSNmOxG)7R83*M7&@~z$8DyJbHp13<qvSth(Ehqi_{KKS(IAlE04*{{ z_L`{$^cpj0vNE;6RxV(*1GF|DWH2c7Kr8ZLr(BqV)~zGk0dY0lWN3p6tC=RCR0mqK z=%i=unpaX(3F1Rs4qA4O$5e1^;0+T?xPed?gV(JlmZU;QJ&OJFQk_6opg`=yQ`#Dt z;L-|mI%xY1`r?06#Cmo}T*GPx3rKLAg4VTznn|EV|KOO$7fOcMSM$Rbc|y<SHbtE5 z39-`@wDugmB!w=~hQ|)!aLlZLh99)9K{U1T1R3tOGd@kQTFsgPddCBfOIjdRHfVuO zv6%%@l?^(t6Ix~CGQi3@IUjaki79A(dquHtepxE$5>)UhVW3-U?5uQ*EG%@4OwBN> ze9%gGaI!Rlm&>5|1K&Xds-aNA6WZQ3GQs5<&rIA~6ih8qYAF1M!0KOknFd;@kH?*6 zpat-t1ZW0YX$~rL%s@-G;WzMrH`~JsC|EWl#yg<nTp(LS&7q!lg;h+jg3t`U92pvh zFni2E%ZNb*p&4l5Eyz)zYk@$)3vw=qhPeb*nBWZ*aG?mfmjLDz@Gh9pV(2x#X7Gi# zP={DRX4paQ0NF;CttKGj(Lw-hE$E!Q#F9jCX=4Uj+KVT8AVnz5epvXxd{0a~fEphz zi6x1kdeSdA9$RF9q@k{XouCE{2WV*p3kR5MpiMPUN&yECXw@tz4MF5#t|KaLK$Qu| ze#p_c2-iWXFqEJIt-U1}RFno0qyYmu1Q8xZpryW8>_rO{Xi$;sd9Z&$mz=^^?Lwmf z<{|P67DNz(_e`U-T1hBcKnV#{D}yQlY*n2Zd?hc`<<Jm;g%hZ%1Em&{LI_8V2ifKT zN;i;n3txtdYBfB}pp_~y`32S?2N@2n)j|6i6LTT0VKdN@UM#5rW)*b9In0y9*a!+( zzr@^B__<!_^{bg7N(T^cS%<T}CCLy({R=ru3VN3wXnA9?xmi(uKJ>;lGtddG;DQ>o zqPC*gy(kfM;TY(kDIM_5SLqM|$Q4!K!!?Y-_n9T-SHQ0PG6Su>ML$y;VUQMR{8`5m za#s`h=D5tf^rZX>h>>QXx*vK8n3awZ=>9JY6O78*475@e5^0cv9hx+ap-b;z2ROiK z?1z4sK?1`W+QEb$B>_Ke54~>*vKOiA1k(@gRbtbRI)-TmU;YX`_Y2M4XsHZpKJFxd zy1W&p92VJ-Oa;kMSXIJ?(ICSVpo8V0u?yNlYX(}9i!Y4vhAHHnI*4)5bLxUqOCYDP znSqiWK9gaGK;pH*1Y{nxItEWq7^grjaz|JM>zF}<8=PQ4g)(SiEI65iR=`5qBanmy zOEIvRfYo`>uqEo0IWy2|T4etrTMH^NVV1yX9F~E~d0Yq0fzB)_MLllR48B$t>RYtL z1+xuC!)%2XX;2>;8agA)MGIco5qF>iZ9VhyQj46xxgMNa;EQ3gTW$tgcnS`2(5lCZ zV#gG>qWruPV{miS47BhOB59&&n}(~k4RfIhs{O73e!=k;Fauo!+%h3eLs+7K3=@G* zdv?o7Oo#0L2jxV}oNNfWXbh|jT33XFu0ae+1zpVwKhX(?W>Yk^P!m8WTYv%!>>jA? zpcRbBDFiL5%s`6|K@Bi7&}u{UvJ`BPG32gLP*|Z>hVW2AwHJJJ6Jp*AURHtU%^*SK zo?7BxT9R4>HXq?oEWrfI21rVYFxxpluPn79GYvABgFOH(;ffF;=ZBoc;Eh>GUWK$y zVP!t{<ZKB#FA!`7!c6dKb>P!~A;%}0fmTE!$A%eb6(TtJLCXz6#RI5X0_9vYBS<$N zW*J)XU<e8rB;!GLg3j1LA4M<&tzJa75gPw6<3UFVfULu14fbIJ(BV0mc^*Nj$&fN1 zz6ueVB?%QnW}sz(;A{w5X9xB++Aue|cMT9$Vipwvpo`-S4G=ZItF-}Yv4wCcY-$hc zQfP3%q83(S!Dvt`1vz-oN-z_o5-cb+8H>w6r~9Ki416kiUJ9aAL%0og0ugq%fyyqB zTL`$x9JR~>ISaF(0u^Lv0fx<8kfYkn;EUmKI1D-m1S)yK4g{?<11D<GdNA}d1$^r& zxMc=DKnRkxpd|M4#R9`eM&Obd#RDK8A&O?C1F%5XqJZs$EKvfLAg1x4aedHLD3Gna z!Ju=zV3iC!IzWrou;d(AQXvoxprcGs;uzD(;BCc-+5*{PEF~f2I!JJZ0gh9wDGOe% z5iraMSs@OW!8SZ2?g)mCnW3+eHv_GsLmnhV=%8@@h8bw>9V8AQ%P^tY)eN-s4OD)> zj|IjyW(KW;AV&b>+{O&D11Y#sHNnQjp#3WN#F`m=EgRxoVsO$oMXoSlht9zYS7_;h zY6WN|2IS~Jj6ML?rAbilfEHfBw1J!cNN$6daTtLHa-#`!jVu9I1$pB-Im8U>Dj~SL zkTrr`1|RJ;gRfY_5o)OUA0?b{cTG%D=M=#Qi+Dm@gLUbI8GNl44p$INOQ3Ey(s%~O zSr{N2a3v{1izCe7OTA#O13L$l;z5yT23j`-E?YrMn?N-utggiuoru*CkR*fLUo%A+ zB1Q>wSg#E-vIWruo%w*&`*`#cwb}ucAaDj0p<TWBG!t0QU<O+Mg<P(ffmU3Bf)!Sv zAcr?7-0_7jcy$3dU_l)|(5ftSqd_LXOe7}zflY*EKgcN*1Ops>fdV)mz)xC2Jzx)1 z{Xz?K^kw2^pha8Ag*oi5GE5UFE!^SDtPo9Ia6o~UHbDw^XcHKm1F**cs1`&&M-tr8 zz+K+sTor@e9Gq1Ed=(R>^FiK#G-=F0i<v;40UeqN7RFk};q?a69wyWUZ)RrL@-A+( zKy?NzRbkX<pv6{@bPEl2$mEon8DtfX8E6R*D2JGVmi~YX9)!P9R;GXx9{3JA>;VcI z14Ha*Li3TifhJ~wfX_#`m+_gw7ZM>H3W@=kk4Q{VxGNxY96O{i4mbrTOzd?MXr&OI z(1#=@5?xHNnli_+s2{t-3D#WjrA)B!2IpH?aKnxqCD9XzstcBKA@vZXJS5Er1nV=> zj3cg!BQ15n<`8h6WdTanB;*i66(MMu8FIQa11<gnWpiU_BvKfC$Tb<Lc7(6xf*B7z z$N**ysF(p|QW8@M#2U;6erBY_DE2xObZjDcE&*C)qOWB)GY8!+h;+OmTmz*wBxpe! zBz7Q$Fs%CnTHgk$RE%N!slho7dzb|zgNq&9^`Ql}A{V9$XYB`Hfd+E|w7Rf>7F7@z z!OqygTIs>;0QG=inH!@Igth<;Qn|o%;;qm?tKV=09w>#GftGB6Qo0%F1W!nX1`lN{ z6&lP=yww-<B5Bl)9!w`_@&-}yp>>Tw3%KyO7H{0*u9_^c?evDa2YW>XT0e%*9guj% z7oP;H9Sdw7HmIWrRx<F_Xs~n#c90n~*_m0u78rn5lz}1@?;ZoFrTFU@e9k3Uqu|p_ zT>XJB3JKR1_;eGh8{o_5ph0a0T9F3IF|c9>In+T}3U4BX6w&Zy-e#cXYsd)=WID(Y zgrU%(6ntq7Vknk!A78kmm-6U`j6;igOVE}jqukWu49JABv5A=`WNI2TQB#tcmYJGT zke``XQVfwd11+8dmC9z2MRU*vL-8Jt!5-k1uh4a2#zs2EM%KBB6<}lXiXgfTVW-_< zG|WLO(jWl^KL8OFPR2%%C3;|IVNT8%nxc6NH23Tm9B%?T-WD<ogHhI6qLdbxCK!SS zPf<-kE5$&o;qbT>ErDRzfV&{GL@6^cHDa5ICZGqFcOi4qu%*>zh}C)6gB!XR1%AyB zxcnjHG4S$gP&dW^Jmm%69p@Ts2)g46a=bO9Ig40v2elh)xH)K{9VlU$z;2~PcLOww zz$Q&Ff(N{e4U6^QMP;BX#Vd1jQ%j06q0>2*kfVxl8V5e*I~b-1d|M5gzhDN#(qL)| z*x!(;K6B7|LF80o4q7(|Dp)`{2RUsM3RXkVq#L>&ps6rNJ!{Y!I&i3(Bi0H+LKV71 z51xT=geJ5S#|TWw>O8EW3AGj;G;sToTI?9+85)C}3fF@@I3cOTH?aU}B<$d5=xqeh zh9M}WfWi;b1~UgOfdmDsIcSk0Y#s*7UI?5K4Z2&xH?aV+!VWq#m<ir;0=d%1J+&kt zF|!C3t?>CPNI2tglm+B?baT*|o-jwj2AQB`CTM&L><>Z-8+6YC*aav~L|&{2Zv4Vs z>zh~sz0b=WwDJ%+5yHX@(vF3tJe)xTvKed|D7k^wvV$)<1gCPi4X_J9Q6mYK?jRPz zEW(xA3_+`5eG?(q82c4Lm(W==fTy&;*Xcm2E6}QkVpF4%qSRDKg<=j`d<ZHv%t7k{ zD~cUmK&s8GAXQjWenmlUW*$VTG3c^BV<R0yOCxKrL?U#J6j%bZGzuhxUNM=&SM3?Y zy#k6fV`E4V!sbw6G@4H>;XVM>OrRND_(}oT>JRh^3S=WvPC_yP)U*c0Iyn4|Q(O@y zpjJ@k@a2Bk-Hg+XIBO=5iCEnPZ(e)m6{i+K&UH42F9F1EJuIkTG(239`y&W%n?a1m zoOZ@FU~djubO%oK*zG4^ANB?-c=ZS3P9jJF1zOaH#UgXiial_m1g*XUwa<;AE`fO& zMw^(SItG>z5xzGB-E@L{8xm$XAWZ`!--86o2oPt&SNB0(VGde02QD%}YtlgO1LYo2 zss_0nM8i@Drh804#zIR2YX(p=3x16VG>d``hc-4eLvB)<Lz|RIpsTV{Q_^8e8x1ve zAnio3L|P)~x?6n%P%{tKP6R17Dg&h~u(&yBsT=x61hit+&I+^|60|1)WFU%WQ%zg^ znoaDibc{`nz&jd1Rzn-T=AiX$=sGj=N))0EjbiPrbj%DOn;<|I!nK%VS_al)2GU_+ zW&*aPxU?t@#UcwFx=cX23=NG8Alg#Xk#vE!XXqFjo0~!8N{iBv90HLvGlqByWS>!4 zeoiX%RCjo&>KIx;cXELA8iCZM=0FNgun9(nCJ+~cBEtwpyD4bPq>+gMctI;z8lpQD zyub@=15^nlvLQ-R(=nvYOhA2xlFZ!HV(<klV6BFlIz}egFT*g0uh4^DgafUMjg29v zwi}yZ9qKSNLQb}@av4vT0b~zS>4&BtS}LRHM=Ouvi}|p-6PDXxwIhoAaF@xb=L4d; z3SKS;r<OqOn*--M(9%M4P$dc}wcuOyKzSY(YN#a=RyTpGYlN}T>KbMhXbuh9STaUA zCIZ!o2t&XcpoVxP7K3h6h3PkfUR4bXI7n9kw!YEC9Nq>4*B!9p3e_SDn3>RG%Oeqd zs~f@!P~76y3UOT-xUmnp4+&DL;tPH=h(eHskT$I!s;6+<2x{v?6oWKFu0QevI{|7d zWUDH6=YlnZ6(eazxr56bba*9XMJUJ(*kc!Ty%GHCE^tfT2zp?Cd`M(~E2v*>55Axa z*;6R9ET|Cxb{1GIKEuH7hI*2aVPLg*3`6s?DP$F_IcOOus9rWkJ?IJ5wT7U3p<o8! zu><TOsC&&}7FcN7f-EoxErHZ9&@l(Cd`v6?u{5m>tPQQfbsNr*2Q|0B#^SLS>~)B> zpw*P1xHJbXe*{|#TA~QD47BnPVXZL{)`E@2V=e4}XxL51=Abo=D5VHIYk~?B)ItP% zY6Y+EL^2mt0zeWxk|6rEo*;Wc;fLKwBT#DzyKbzeL&Fialn7SJK$`aEFfQ0<X3)w7 zM#Bni><+>7TTmu=^dI6u==u_HTtnRe>sG=n#pVWF%|)~X3<?Bf8&JB9$W27hW@t!5 z037{rm*5UyaB~!DHdqf4W`lf*6phew*90=wg+2I;Kz(wkHR#%juo2`k3T#BzPK1ph zN5VV?TUHH=NpSK(O-x26kYP<2O&~F0MrZ(*)C6)i!VM(FA&PMzb718ku}K1153b+> z7fhCD6*{(LPC}@l+8Y4gB?zjTK=Fa*2gtB5_Vflx)+y<!Fg>oBDESp+4ai7X@Zw9m z;BiB^23&ywawJGmNM!+J<D5BY88LE!Y7SbOTak)f^MZGGpr#}ODF;-S!K^_l0U_5W zBV{mRJZ1!H7eFsiM%IeYi>S&$E`g>f$c{biu>rmT7*i)c_mi00jX`6@s5XG27ugij ze1)Ww2oD-#h9oFxkPN}+S6Ey@mPO$RLQES#9xQgvM9J#VATSEc&neA?o%aCs0KWWU z1lpK^RWp{11G{t^nr5KJ<4ph{*MmX?O)DZ)K>0Ma0%{^GK=9^D(C#l(UASTxR8D~w zdn0E?&=C=!b`43H51W<XZiIVk3B)PTASA&b;E>0vnSgh2*9Z8F1UuK70rg^5=x$fg zrmJE@BLi$BJtg@Ckii4ct+miWp3Gv8%=8TZqLftVY#?Zg0@CNtE6Xe{P0T4SO)5@J zhK`^ZYJ$dbjE$`GK*L|@Mc}L5!9$-21%^fzpdka$SV%s?Tw~Dn;)Z4hI)+9T)}Y}G zbUDzW6(G4H#6C1|q#Hw9@1TYE6~#!q)O1V?!PjwuEK1H#O-m~V_oPAV<IxBA!%~xN zjP1Z<`z9t9a3`SZ(lIrMY}iE@n3<Q7S^+W@?0Rzp6Ev-;@)n?hY$FR$Edt8d&LB5I zG8X)dSLm&~=Ah;16~z!|fh!PWW9XbSxM70YQipX2O;BSTT&KY;a?OP7D1lySjcPe4 zo#8VDl&!%!V5T@H<|IR#>>)*odBth@MY-U(hWZEIoI+XW5Ay_kVK~?`=Ad=u;GPg@ z1$jj=IJwvu+kyRU4q8kOmNdmaE`;W3BU7ACb4|$vZN)JKoA2q9Y3%9>-d|!ImYNLZ zLiW9Y{06CPvH1<YKpPrY&@KkdZ|0!&+AvQTK|BG8E|5RL#Sv&7HrPv$1<k&RB{s%7 zFs0CWB^<E<^&U3Yf%<`PzZto@x`KRb7!UOs$mhnsi6vmJPbNqn?pbI_hSjt1UKZAf zG&h4Z1<^fd4$YIGg~%1f5D!8l6xQ~^>p`q8Lh&Fd@-hR0jpETf1`-E*3}a3RwA>j| zJ7Dz+u5m}S^hM0bqZwq98ix;^i5Po?uXx6u#t4KV?$JloHOz)+euIxcdLkA2pwi78 zw89!W>_C+OsPF|XxCW<W(1K>roCNIJaF`3>4IMPA3=NU&fR1~C_Oiq48i=(h>;KT5 z3to@~ubn`KK!@$Z!1Yovv|fUk1e=wH1t_HCf!-8K(6yjOfgg&oAnPE*0-$keNT~;3 zWel|hmZZ#yv<74g$TX<g;IUfNA{}ZEflLWKIslR>VSdAr8VxP6SOYE=4Gj==DX0wx z30zQp0%;9E!WBLO0?kyY;R@!#T!1qzfEtc)b3s-?0v1&1pjrj0rtq2q*8(-g6Fe>r z2}5Yup|v;B)1?uz7Pu)Ob4fG>p#^RVYQvEP^Nfr<i?L~jn+z>4NifpT)Uy~x7t}1A zwI?+ANUGRDtB=7`mauAqsLBm8$%I-Pxu#@-XH1dnZqUI$ph5_~6d9WB&?;oK#s+AC zGT2SjXitFLgxq{Ea?}I6$OtxI0?ieWS`yYoKywjvKExclP!yJ3aAa6$3xL=_!s0?} za2#W6LO|jezB(Cuc$&jjCxco#p!N);oH2)bgE;47vmLyI548mo<QEKY!N8*%cAg1t z=OMWYw0IdD-DdEp0M9z%4_)G&7mwbkf+Yd;f)O<dfC3T8mC&#=haR9vvoHjw2DDZn z=muO+ihz~|sQC_>BJk&Wv{oS0Gemg;tEHF?y&&k~ba3W^k4C~{6cm!M%!TF{&|+&y z{6hwBsp=}fVC3irH$9=z4_}~+Bay-iL~sQO%R1(kkVHaNHwGKUqs2PRoz~V2j(M5I z`6Wg91)0gtIi<y*r82N_0?<|xW2_58^2#8i1n`9*d8sLI5$MoBS|VHovJ4;(y7tRZ z6Vycp_5YJ07RDE)7C^@az@2E=5CBH|9kj$7(guZh1R?Pb*%SzCY@r99B^Eyt(}=f( z%-O=q39QBt(UOO+B}Z&+M|L$auEpJ)w?x_AXNb*>@HRbUavPGLiO`2J84ek~3Q8>~ zN-a*!D@n|Qt{Vd_Ek}tKNRkFEGzawzOrTu_NF@RDF1!(k&B@@AWK8Rz4HVGyS4w&+ zR)?Up53v~yUX=@KY9eb#7z}E&A<IBR3o@~d*Ueyq(X}HCh8A<=nGGJo$6^B1cxwi~ zbl=jF)CyS61)cS72s<JJZJib3NO;inbFrZr;(S?iOEb_iCins4@D19qm9K_&Rut|U zGlwt2H-Rknfi~65K`Yxqsl^y34o*a{)B??e&{e*m#gtGdxq=t`;@m$5vJR9a2<gYQ zlgu2x=pE)PNcjwME+`X2(zFF^4Lt1RP!gPtbN@8RY9gJEWCnNz6a2Id3;1Go?9R7< zt!=jeEkg(O-a!kW!5%|xr{f8D&?#dE@t(nk@vzm*j(XPUi(^3!A<i>6j05`%epZJC z=pbEik%Qe|M20`kVijaQ5zd8|tjK4NT7VX|<8vD+37gP%HIQXQI21fi0zTs#>0}Vc zf`ZgM$dUaPpf&g?ZU#FNmdau0^b#4Ycz3K3>0;Ra7hH>li8KcLqF~4-ZO|@eaPdxL zY!lqiMx;3ecD7l-k4}cBZ3_eFrUY2gNM^J^wxhxKxLJU<I3UM4$R1GEhZ%1H+JpdV zI9q^DC<YY{Fb5Es4j>j{?tddP?$CF_fp^z}wyA+8X&{T1LF=YaYB11zAB8oP1!!vm zBwSF|Sz3U0DnM!|s5m%}U=It(Y8{-_637nBYzx(dt1hyDZ)pI{lYv&GLFyuq!$9!{ zsf*ATVW8H0P%A*2njtw0qo6i~G<C3Q1MO&rX#*F?h>8ZjbpgBEEI@k;AZf{5(-xAJ zprMGhqJg^;`Mf67(>N?pPY;IHP*9DaW;uA>7Pu|~yA@G+z?c7HcPqXa#a&|<LZ<bx zg&X#20<_rxM>0diCO)?itQ!nbCLvG)h+u^P+5v&$I&fl#B{kUL-T0h`s0AQN22$uk z3S2xcBUtd`(Mw!uk0+)G7x8#B6Drr?+c}`g4z?<glt2X+so?O`Fwn68?FT`QBy<x& zxelC`@Z>SDiLk7KbefX|o^VDlnIS{6;E8ZZxeQu{QEZY49{>PvF+lImTYz@4fSnKB z;|T2vfUXV%xf*oU8i+<qWXSi}fqU`62JxVQLCiL%5o+HUX%{GX0uG@MTs|PmGSFrf zJnq8p9>|7WjAGRYrC3Gr18jFNX86E{IkATiq`b%P8gNp<5;BlgJkY`l%{34`u*+9$ zAvqSblLk3VEI=nlg9>!mR$~%k4U*&_u?9}Yu(3s`KS5@LA|7TWL60T|gF3>Fde$&U zD;SzUoedi)gc=Po$^x{p15}lRF7X4|1PerX2OlY|B$s7EXX7Ay$>0WqDsXHXKx<$< z^GcwaU{2E3hG>NE;()pcJ^UapggFRH3>6fhc~(~!ZZgP8ShVEkLbX^kfU~M`3Ur_V zv=FA)$fUwb-w+fL#zva9h~?)-pylV_i3$Vo=1Yw93EIv9NfRi;uoj@b3ZT#hZ_tFa zQ;-MTVLK_EjX*&JuAtFsc4L%`3s;XbqkvX4;cy5jcENtoFwjA#(E=H6kCAIi3i!l4 z%#34<l5yZV43Tu86(*p)3wYdy;}lM~$wsaLxSRr6=m(8%xCTRn26UIe<|9BGY9Y}A z3LQ{%foRy?M%<wi<c%mY(PIoUr;6zqWIgEafoFS+<O6b#1!yk@sD!ZqZN>mK8R6sl zsMQ(V>!8DLKnLoA(>QpQ3wX~9meB}fl*Ss|08pzDs{yb~3@r>n8#s{T)C77v29ZID zT>im}EL)h_u!%!hEP)$dpe-<<KtYcrSos6<LTaHaG{l|stRo=h0;rRO>{<)ZE)!6| z!tw*m**Id}FanxSBjM&Dl`}A#4I`ndqVTGUf~tbK4PM1T(g4g!F#p1wgzis>o1FBl zVQzxtOAKXTM>*+P!yJV}8Q4`wAqHDr0gVGth=D>M9#G&ofw>JW(HllU3R_TtYJ!&K zFuaFi5Qgi)CPB9EhvfTa=0QUiE#JV>1k80XJ`VR;1gDmOO@pNrM?GtZP$J|UcncG( zxdW;%u>wgSEMI8D5-+^Eg+wQM#;^b_mIoz03(z8YP@c8`H5I|j9F0@JtNn1ey1)mr zf!Z`IHQ6`?w3Q7}+v_51$C5B}Ju!8{&Qq~~AK?s*X><p}A`IkkPzu1|I`9c9DWIXt zcw`4Urldd)DYpQvOhwLvgzO>GUeGO<My@Cpr@&4ZfW?i1kpU##fGT@rH^7QhLU}E@ z482SQ<zXj1YsfxwaA^x`Pk@dkGDezF05t)ua}q0IONT*of0p1QhKe)u(o1s^k(LyL zj&d+IvMvGbtN?EzHa0WU1Z|B5O%-A^KH%$RP2qb<K@ntP2}yZq5oHNlR0Vb^?p6ot z!O=)MaJD-@OLQS2iq#G9j0n!<VBbKhUF6mfl0DG+3s$1KW`eG04e<B$3xRFl#8Q=^ z9x#n$8niOQYg%w>2{=%o2?SoS;P(z{^^33)R6>A_gJd|k&EVddduoXfI30i%jah)! z`=W##IEXAjtAD{QM>EvHAy~<XWEadlXj=3v4u&Ntumzws!^jpu=O95gfRYI;d0-lB zXn-&ZYBqRuADUVrhQsS<tN{hJ3uXtjen7b0&=AQ)*CcT8!1ohbfEEuUyBwBo2s_;b zWC+5|ARZ)QL930Cjf8fzVR;2+15O8nMw&pTfmUT$q9sUc2DpG#38;|`IygDi%`?K) z1uS7@sN?G5?h0WW=>&%cxj8yRxyCx4etxb&5IGYaYX<0ga_|XM&>{tN_AKF{1kf^S zun*0lYviFrqaeqC6BJb30(5*cxB>#LO9oXy#!wkF&w~cYz$YDm-GYCd!3@%>fW|YL zPEa;PG@H?y!0-jh2uFZYrv<3s!z?P$Ovc%LLR)-ngdD2QI14lQf@2(R0q0Ocp#&K_ zz!?2NTXc->B8V<ng$1q6;R}wT?y&%^GzLW-EXH7=1d3BosNr=Ra+@2}G6StvMousw z(?N#748`6JM{zjrQ3p_(MK&B_m<4EYFeouvn4vC2f)zrj@rxLDfCUU}2m$rbUQ}H; zM+fj}LK+`{rWIJ`11$kEG_fc!1eJT>p$hO&UV#yu4>=nIv>zs~2qXwUDiBn`gM{OA zQqxL6G8UlYd_jBaK@4jH8~|0q*c=Y5LEDN9t>MNNWu|Aq&DF6q*D<s%PEF6uOUs8@ zrekTLV`N>N3F3nq9*|8(DfytIr9in$QwOxt$k@m_B|kU66l@kq8Kiwul9LZQ4h5<g z+BQi~1!;!aV2(Um0zM<a0(62fbmxbAYJRRK$TiR=jDa=Cyu2cCP#S82w-Ol}K?T9# z2?{y`$i}DwRGTa@Z2~QMtpKlW23NTV+ssT1bWBVvtP658Q=qOlG_U|03)=COlAm0b zm;;jl9ZX|vWSvnEpPB=YKSM)Pa1#xq%>`OG3rW`~>#t0qmq8dqPXI*Ai005Vg})HB zKsj;*t_N@N2|wl+dQLO6UW2&@w>xkQ(xM*ci{u7~dRRV$-bZZ#UnL8*9-Kcwg$rnT zEGVNJgHG6iq%;r-Z8yQPJIs98{nKEbu>LUANcd1FG>9Q32@a1z3_=<Pg_fkC1+d7` zW^4he9bw@_Al{IRPHSrh)K%!<>JeI6fQ~9ATvfx*@U?)q)WHQW=<Hl@ph3kgV5j9; zfEI9qt7@nWn)eMYu{eo9VnZ3O!fpWGlm}njiEt9k6Cj#M7ebO1Mr~<{k`-{d4yGBc zNdaFYiNj@Bt8pA52&tDb-G{a=5?k=YCb4082AUM%YayYovjD9f1Xt=X0Sido2#S4T zLlQZGf-(_k;UPG^!_2gVGzu-CW@F7nSc4gN6%Se|hinJLObgKJHc%o4rCDU>!}2^< zTX5I(mZ&XDY|(_X!Y4v6QoRpdTxbNF835(RVj}~Kg1pjP$TXe>XoVhPcEB7wI{=!* zfE;ZGudu*fcMH(EIW)zf$`M=_8X8#`SVQ*3f)#@*T~lK-9YZrv=O1Dl=oAGVLsL^D z9W(1Z=$>Ryy8$F-p<`m5l$ZiL=M2={GBh<a(lN9yN=-}4Nlb?r0TnmaF|<xe%}FhR zEm4Mwo9Gx?BW*B-8g6ExV`hz6PntnaNkgkAL8r4B8)00_YYAEo2uU1}#0;yKj3M1c zW9)1EE#Yy1x9|d)jx@}Lqzhk(WeHyi2+IV}Isob>Ncu%9w~)*>f(&Y6%!q)@#pN1U z@qt=GS%TIa;t3sa%p+Bo&~6oqTR`XAVw`P-IXD8c3YX(>8iDRwW9UX6yx|5ZRUss_ zn#bnu%uHCApw6FI8lcR0A^FwN6`=>+Wv~s6M7xX__u+CN%KSCD10kB+Q%gXj1mH0T zOZX~CsOw<SY6)6u2r43tE#Qqv@OT)kh(wqT+6)OY5X+DT&X`3WsxZWoL_qhT20&d1 z8=Qx_5RwHz?!#7cBb)^~)yFRY>L`$TVQ}+6i4D^qU=3kV4X_Fk+K99SE$&0k4e%Bp zaTycV=F>3Hv4k(^gL(+IfCBC%l=#PVC&Vn!MXi3Nxlli$Oa&mqz$C!06gsI4wHdqD z;p(8K`sPCxoPxX!(t(jl%s~eG=BGf48@y&CD+O;Ch4i-qG9gX}tzJY9SWD0<Mo?1& zTn}j&=$H~0!iEO0zEwab!d37^g3z$G1g#DPnQjSMr3Y%Q!mJ@S^wI4>@e(}T3{mz& zBO=7m7~x8k;4_3Y)-Yomiw?+C6QoHG>LFUfSM@=CiB^$8atzK&12i5CHVhJMphGXf zTuA&FK-%D#4g;O02UZ8oF`)aH!H0x^orG5#c&{*2TX1R#m<zEDb+I5K+(2#wD?_-^ zDIYQqW(iueh@66;zK2DqCFs0jNR(SZ)-+mz*7SkKKn)>#8!SPq=s+r9_a?)F3e(e| zMI%o6pt&{BWD9tyE9jOo#Go-`qXT4vB=~S@$g$y`d7xuiA%27}FvAgBxGE+yh#{bG zbJVkja3J$mmPROD5k#<=Lsdcb_<_#;$jPiq^()OyN-fIFONYA%Yc4mmz|?`$C<0C~ zw8S(EHZ<y#m;!B7LEQrzxQB)is3{08V;~#Ia7T}!0m3MdL&2G|#Lp8^m4N(-JzD)d zktz%HGjX8q!rsV$r8G!BvjnY61EnTQBk+O9;Bg-#$gC-Bh8m9#K&N@4+YUK<2r^M) zl;Rqc0zNkgRF7kx=wb<90tO8{wCn(Lq&egSeM=))rU0Gxi+<V;)a{^^+@Q+V60{%- z>^0ExsET5j)V$(U-^7xl%nFoAVaxzF1UC{;T<Z$C_#V366|`3fY8&E?<#<CwBrCu< z36u<s(UJ#tA3{%%2e}#Kc056j)oq}LCyMRhjjfOb6`YX>Jyy;VzPJi|Xj_67SwTX~ z6k7N|hlngeD~=#C;G?X=Qo$=5@jDe%=7KFpp1K322*2QXGl&V`Py&_VE?|X_gli0& zGQ{mlki~?<3Y0n_24isnW^94n0ghE@A^}$opanzt%4_INL4+LxJ_QuXc!-loOi<R& z`MCw9C8_9n&Ly!V5fXTybxnBOi#uT%nd31VT0DXFb9*Hw=O<+*<~b#%<fRrvj$5;Y zFJ6L18EmNmtgx|!1`}@U4K1-4P9Tgx1q&#Pf%Y6C`x(P_=ymPr3ofwad}3UIS$~4= za)7VVaMA;xgn$-KE}2CxsYRJ(&{#q%n=xDr3omf%+7h<7$`W+YE_h)J(M7b8IhJsR zIfg*^Le9nrOHBr4T1YXDwBR0RJq}xK4;f7KEQaWTw$Y7nH61PC3ZaQDIJE?EQVi%8 zcxceU)=@!|8nirxHN2s<FD#*9^aTt-ojFu<VYB6_#aJ!G>0(2R5DYC)w?mH=hq@SV zpAdcE1~XBbLrsINkpi!hfi^+FZCdD1IcRu{;83}x39NLrgbW-(!_U&h5^}hfF;v_V zwyeq$wyX*!gBG@iM#yf#Kg@)>3Jgsr-k~PYk}hx_hdK|**`UgRkeeWB5q;Fz(iD;! zp{WGJJuqEpgCy_;UO3zW&a{MF1R37IbP>v+4Tg&#x?uf%$N;z{d?6UrJ(i$VS)ke) z7Gt2u1%(nQPC+zYx1o)ETf!GbA(;*`1ZF6tjYh~wRENXX(p$n;J3$SH7-k8&upTs? z14?@!yI`inG6!n7;2i4)xgFGo#u~r42D$NS!W`X(WIhwn0A#VbS$tVRNs$UPLx36( zhOjI25QE;9poL0^aco2IEH8MT4>a#>VS+Yb4LWWTF<xz`sbgYfq+^Oa)@=z|;^a_l zXl4zX2?z14b&ZY8%`B`zq`9?@3Fw4KGmMdG(3zBGpiysdMGhV|w*;+m0-0i{X>DR{ zV69_f0hydnEGo$?$;{7#bjBcq;UJrIObv}dgY2Loa_~WzmY{<SD~iGVlA_Y&5-S~3 z6Yymor~}=gQ!lZNbHkP@fkG4-^&rX=dit1&0c4CBmLi~0YYq)^{KbzMO6G#=!CUaa z);ZyD4{mqB3J<hVSu>PDPb4?M)T0$PuvJL7?8jEvz)i(D!j8JU2(BJB!-hUfZwXrS z1S)=UxB@m1i#s$xJrpcMrx@iQ>Rt6n4#QypT2TmEiiPY>69dRJ9g)cgx$FZiVD^Ld z#jyvMX>e+ZUjTHFCm4C48oMt*O%L$cGY-Fi#(iNHLThPwc!Q(a6127pR4$qrKnhA& zc*Dv?Sa^X)hml4I{Gh|hW{{y*tjb}7$#6eoS8IekObzl4q>%$#=>>BzEJc8v49dT_ zTng^aRu-f}8&0t3gpFjw7Hq+cg^y%Iiv!ePKr0L&W6$8T(=0&?y^s?Id>q>h+6)2* zFfLa@OoEO#Lp_W#iUkXJ_}DbuR#5$e9^P<OP!r)JvF2C}MIMyKYc8@vjB!`&X&5wC z32sC}lQDQd8tC+4P~~NbBfWrn_7F{wt8h?9Q}JkmjEX`up^l~Eb{#|yr2XKYS^^(Q zg{`)OB@I}M5E`MNkyKE^1C5u0Xk1ZC?jR}Tm~?1bfX<r1oC5F8p}7U88z6?EcgHX~ znxGD^bwE)j^pGS=(BePjM2!{%CWtN)%4`@cv6_O7at#X3w>EOpG5}4!gM45O8VEtU zX9!m+01dA|ltD8u^bBZdm_Yk!AQPeC52E1Z0XV-ITcT!Q^o#;39YDt)LB<pjL&flM zBakF?EY}>ecMaVLP+A46!fpm+%o*Zj>{T=BNH%C3GqnUd>|qY=+2Qb`i6MM764vks z`7R{2q!=;)4;h~iHh>>_0~x*pDe%cpPRxP0(HwP#0~VFwL%HEf@fzrtpORXPY$AG9 z18HEvBFfAd`#3h-X3+Hs2s4qbh7Xe(r$C2E!3h{t&B5K^ms$?>820MM5R^X=#`~p~ z6K4Z-{ZL3zW@27?PAV+IpnHjMM3^bsC2{C!349zEy2)tnK}w{svx^`R2_M+UQ9gn_ zN_bcwv_=z8o`>Wo_*Nk3CPG{V57<NKgNcxg0vW(JCNzK#TfT`SL?O<Bm&MRwZk)~m z=Lq}*?-+$5=omuG!CcU|AZ#foez!s0glhyBp3bql4b+k&V&EONsuPDxV4HeC!|b3! z5?A<u$};dkIi#jQL=lz|b+9^k?gFhI#gl44`(i;BTY{Ebf<_K3LF+p!ib1EgK}PDa zPMN^N26VLy%tDCUOu<9l&<(TTC^A481~0xLqw|mg0JescU>HHlCtP6!s+AzdLL7n; zNSNsaRM$b2Bf<)QfrtnzOX#c=Xe}xDIQpW@3b)LP@XVBw4A?~jxSR<tu;CU%oQfG{ zCXlHJn4!?%gq5P;Acm-b1R-n%DUKi{Ivav+bU`v4>N-dT1=>Fb-}r_!fs7?+@k}T{ z-3y%?!{J_BVMozag*l}Ejajr~87C*`ad1pv(Fhx0hk6q_+7I(4&gLPwO=JmMz6#pL z3d)qY=3!yEkE9`fjN%hM$d4%Mag4mfmcYWi0c~x<y4Ki7-eHa;ecT;KHHl}`-7_aA zH67Ma!lB(9stDR-h4R7@b26b56gc!58X+r%>JCmVfr>&R8ha<k&;X$h+RF+~E%8Be zD$0snScrjoW?)57J&<V>s6~)OjMm@9JMjWrTnvjnXmr7vdARZ##<YxkYDoZWFc9h( z94$A{`TKCCh!BGdL3LyGJZJ+F!X9V{Sl6j)80dgJV9fx%3JtW06}&~z1hh~s)h)=? z6)Iz8pab482;&;+STi_fmN*s_C00VmY(Z-uiY<yWtDuJnTY^?vgI0+`uc%G|&8k9% zMM3M7K?5(Aph*^oVhhMftEDCACQl<%Q)}q8M(E>ah6b=@yCz1EfhcIEF*E?JodubQ zBmwRuK;zT`=2o10i@|1tMi(%2;M$I7XaE|e1~&t+xCT_zfI<L7!%_o=(YOW_!A9e7 z45aH04I21~X*iva^EfozI$$0KZ-K3X+@XilMW9hQq!TMaOmIpxGyt7fiX1wK&;T6` z3W+T2dx+t&Wdbq|k=9`bqb#t4D>e>J1)t~x9@D|;Ua%@i7&_;qCKlm0(-f=*<O2Mr zLe)Xc1<hl^jD>C%f+tIGon&YL9Y;k3i6%I;!m3fYpG-hzf%2;pY}FUcVC-Rl+Pijy zo*imv09w(D92dy>29!cgj3CS5aHUjZ$GjBSgsG#RwLd)AAfp863ERlO2uZbXVsSRi z*|07?G{=An0FeD8gb2tq*Gy{zCp~M&loYr_V69BJ!LX&vL<cp<G^oL_aZ|{QprHY% zG(-(P(9%^<%N`!Fpb`k;6L{D{;uJk>K!f6--NpvsW0g>+C%_SfHQ$2{9zf_qodm(H z3pN!4vdfyGD7CmG1AKM^XcxE%Xn9g<kZW*Akf(EqM?7fHx0QhoLIAWU+{zG10J<?8 zRs|R#NkR698zYGXySn?j`h{45_KX*ofY%#>Y_%}ZWbh9N@$~hKa&`B2^nuhipef)~ z|A3JAz)(jY&yYwf104|0+27C2Kgie05X=L)%*qJN4EGNT4smu2cC|7F^L<?19eu!7 zfySm>Qj3#|G7C!bi=Z_VXws+H$O5vt6EfLm2&<GpyG7wbpczB>UQ=*Y1={clo^FF} zHid~o4$MzVE+~TC#|PRYV+7vB3EsaN584I`K0X7q;mHJTCo85bWKS!!TnDcQ1C1FQ z8i3YBgVP@3ZVXU5GlLF>nxLJ-08MU&Ca58ScP0;P2~x7d&<smQpj#-=^9F30wF%UH zCgzYHC5a9MWecRktI+cWXzezhP(UlUFgyTTZHhiYW@uoDGKq<y5mpysi5J)?HPqkG zY!CA`WT*xUiMqrW!$Kp_ZW2g6g2k~Y4OI-i;GHNiy%-?~tBSC@7sn1$3_Cyt5ojb5 zx?>n}%nufqqO?OXOaUb*3{#*+x@AHKgbfW~%e!G|3lf~LASTkuptC%{=R|-EhV(&U z`+6a+2Ms~`!738aigA>L2CcC{C(?r3EN1YQCrXu#?nN_*si3BVlb*Fper{rBo+spZ zC_@87)M00Iy%sR#D7yViA(uH2)NTpU?q3RS4ms&rhxqt|T$7j#Ys(R^-_QV|1L_1P z=YS$m&M&Ei*5m|@K<I!P0cuW`7NsFV8a8^2JwZa^nn1?3gc}NKBteeJg7_X0)+k5p zq6al7ag@Mxpqqgd;`j|Q3QmO@0t$3U4h&8$K?DIT(C`}rYMUbTKwV?akd#=QnH-;A zTvC*pm}`@qkyxZtT#{mC1!BdQ6eVVs6oW<W6zrfC9%u-y*wDm8(NM?GNY~N~RACqz zfVMhR6hlnQ%!lZ~ZIU%)@eM>d)N*i*1Y3fGStP=CH<%!<$bs5y1X&G-kN_Pl3(8K0 z2B2;ulm%TTZD;^m#}4W_f*4Q}plj9*4PcAb5oST!S;6^`IxZi4SPy221X|+`&e&KS z2e$*lfEx%Zra;qqSet5~1@Qz7gmiDv+SXu)1_YNFnnJ=B60b?6X`ac!C5DDbvFe$O z<8(wr1JELTe3oO{Y3NF-o!}Y-sfP($dyf?Iknn<AW(4stEYk+(<LQ0ER?p)$4Hga1 z!?~eTs+I<t*4FXy;QhjxdFk=U4usU@!TBx*pfbl%3%nK#WPvsO5JwvuXkG+0f00Ab z)Dq@+xOYH@mO_#yXu*COXhRxY5zKKp#jXKvLBaXK@!-k?oNA3>y&Py#!)CMvBu5w; zfR@CAj5ag?Ej9=BDZn`u60&HvlvqNNOlE#D*2EHQjN}T~DsqtjL8f7G1!$=^#Dky{ zD50(}fsDf&8bFpuXXY2jgHi&@ltpkp)ZZl*F!^8uWV>P0)i^@{dUFCIspJ&9=76#; zI0Rv*GU9YQ;z&7gEev)~E<!u3H;Bu6=x`m1?ch_sAhyG5CS2OVOZC7?ks_!VZarwN zFM*^5S_KSWV`yk#Y6u$oGBY(bHnj%D6^g@35C+3W_;EQ5wbBHK3b-}`yA{;S!s{&X z279nlByVLQY=^aYaoKJR%RxxmD-haY4NzR#4GlnxV;zdkOu*xTU@q!eLr4b_SsNG_ z!VexoW?+V2CBg}WGA3*;0VVvwr~86~1+<VBZwP`Gd}7338p3`;3Cqv`wD=UdV${$K zv}6=)F;al0!c7A$F2(B_BTLvI2$KE)Z}8Gcu(6=UrT9%i9Toy7DAKBt0(h$xz7!Q# z{KHRTfM#jqg3=P#WRQ2Q<9*}Hi!w`K?N|6JQm9eTzL%i^wCIM-(?i?tFyC9ijByR{ zP6p=-YZOxnB~Tp3nt}~Mn3<MSTATr`W#B74p)SQz2*X@w3f2d%xb&<`Qgd<&U}m7D zT4Pu)hx!(gSWUs&phgs@re?#9AXFe4qerwUSi5U*iAh>PezB*aVSIdUQgKOQNosrv zqNW3_pv0Siphbc)YNshUA8LF>aEYN&yk~xKd~j-Nc1mUuB(}j7PCU{eh%sbm0l4W@ zW^D*=kD(8OL60O4&Icc$2T}u_;Q+N57(mnI;MofJjcM>{SNL^nCZHK#*c1lnxOMm_ z5qRnXBmzE=5i(2!>JBBA<QKsP3E^ut;j6Gf%Pm0_I>=l|sQ_9x394|BM2un8E$B!( z(5`fZ93*8xM|3RVKESr?7&3ff1iNMdRAD2BAAD&W+-=aT0lV}X%msT6TriMeGw22# zq}$EVW5pb0AOOE7oI$tOz%IG~4gEti0O(XYNGgM-e6VW`4L}RVK%r@906l;ZmJ?v( z==iNeo?U=NCUm8&p#kWaIAlAGO<~0oN|3>9Br1|1>t3NV37~72Q7kZnWkKk{Vo<+A z$BT&b62t~4J!{Ycepu*1CKQQsp$SMIwBzZX3L9@Qhjd$sa{_1q8^{F6idm=|;LEJ= zraxnN5Rj1mK%HjLeqva<f!`TsXaHYL1+^734xxcdT-bn2hLo+~JOW=21v4G)dRPQP zO(!ngOkl=4A&$+46)o@uPf)824a{Mw1DYDi3OY!k0l99>+8Rp{2_5POO$&qefrD?3 zF$EnPgTIh8HL%o#PT|7x72GG#HYCUtNRbFzBZVYl2I(6iiNJgR7SJv02su1S#n2GR z1CTY75HI5_CoP~2G$iApu7obz1eZKu|AEs0X_gZxDlH({3~OS<;uTz_C1~&mRItGP z0CuyX0jP3=l$JOaGNYE3SZu^wV8TwdgIj9=I!O*({ehALIJjV^YC&B@TIfN_HfZSy zTGfN>NmJ0yFt8o4EP`SO_AH3Six5jt3sBTch6#rf)-u!*GIUS0L$DU3ur))7FoyaP zC14R@L0SOgDM?|=T@V(-2SQ+0Lkl}%Q!l)@gGDH`kqff{;R#rTLM<RV1mQMdDNsQR zP>_?4p#k(DLPG<ne-QSQ7Ko4n22Yt9oC=<dK$NGTQBwltDd^k??2S&)0vfPKjGz^Q zA!vyVDA$=HL=2(jDMG{u+UPU{Ez$rrI^n9Jp^P;e;nODIrPvUk;wnlFL5n<4Tn3pI zG&F>5wgM+z*a4?_+fk_Y;x9!(_99JXqUKgKgRnO@4M7zgip#++H8cb*q5v15piqNU z3y`#dJxQWkhOg{2gxx0!iv`&6uV{fqLLfoPF-YDrgdJc8Hy(BhFvv?_k3f6~jeBCe z12G?^oCNuT$dJd{%mg_Tq@Nh;v6YU7uvHo`Z^A|eP*WU^SwnmY1$V({2wDe%oK`Sn z4jQOLWGHxn1&ub?%s<ROaF@fQ4Qe(qAqF=bvoth>P2s~VG6WSO;B)~CI=IzP8;S4@ zq<Fwn5Q3`7)Vva-6hu)78gM626oO8K!&(#?!j=e_8bkL98G_Dv0~dt|5mRVUh!8P@ z6@{RgUvN<flf&m%^nEE1-{LF`L9@r;WP&go627oKP2da&J9PtZK1a8iKyiqA8zyQh z$1n;<fe1P?4aN0f*BTmvCKMqBBJ@ZYn8UFrNObG)7Kxx*5!p`o-Zn#&AcNV6H9?|V z2r0CnxeInPCoH+ZPYwZj3miERUqVv>abAMhfLbh~9ngk4j04XEknRcgf)V}96ud@Y zEgC`7t;nGXFB(w-6CMOmKNA(GcnU|*)Go5Em~lvoMeq^~7J<;=THFx`HJ!MqgBy>f zfCSA)BYVUURJ4H82rM;{6?Bk7gK!avC?G+{$`B|ZL0h@87m%R)K*7E+fo{?^1kI&` z3rK_r^xPU#xCm&P8>Gh25H#luE+AoY(D22YOknHoA?X_8Q=G*kY-Sm5E3B<(1a&Dm zE5f!$;LY=>_7W%@p~K2VcmPLd+YmO34R<-%rG|!}*=0!42p_G-+g5~@1CY?dTQGv^ zNaR?AoylNmh!R*N1QMjsg61mFOgF0Wu(*JY;X`}~jeG2Q3pElT=A#yhsJC>YR!gY5 zu@{NPkcG#@SdX<pgiX=I;|=CZlt9FBJPJPN;wcVcC-K4T#Edy;pc0WD;iVNU+F%1$ z(7XwEIVdH9ODd?@#Do~!a4bb3XpsVP`Y;3)B47((=?`u-)J7tF11TQx6olaIbKo-) z5M?1~rj$Tg2wJO$y)1++jxaTYMLcLN1gM-t5;2B077=P-Ya<LnYa_sAAxsXRXOVAj zhU9RFhjEsNCeY;*aJRr637ugF=Rx@8%cR*&piDG@<SeYQhUpPp<sxhW2iyl>7aJOa z&P#)oizd)kI@Iyl(<P>bc*{mm^$1R!&{%<;Z(?W&z0e&xNCLH!NIyc#FK9-Ct?ht$ z40iGf*lXZ?0P!i*3Szwlu>-Y?G{H9>jCB1qBuQZ}Cru&yM2K|;*0K_`Rs}g!;f+U> zK!pbc)aOJ7E}rrdc1Rs8s4-)cG^^mn8Z0WI8%bg2!+iisrQoQ9non%#!7ad2Zo*EL zgIQ*12wMRKOPg@(p|%nkfRLgDUUoV;2D`?GI6C>bLe_$sf~J*=jSL{W??6-7hK8U6 z?a+_=Mbc-LlbM%V3_fiPRNCqo=olJVSm)=ZCgtQOXG1O`H?-6QiDJ9=)6fvKj0c=x z5Yw{Y;4}oCPY25VAV)z(EMVPl&@pb{5*48dybc5!42A{>7eW?#LT;zWxb6aMJ!l*W zn?~@0PPj(2S#m>Aje^VFVCSM_ZEWV_+|UOy8@Hn%Yf&&3)EdH8_`t&pRu7m$7xox} zR`7soEki@l@)~gX!LC;&!m;4%aFJRwnc#t4(CjU?6&4`p;PwLnv%q1ESgUCWTf&3W zYpA&ZIr?!gDg~K}!-ddAq~ME`5laj3L<`!+M$f!tWNom%CnB+e69_1UgBg&(hmg2^ zVh%Oc6?*9ilnXh6$IuXU12l3FSin@mbUNnb<R>SVq(b`<#r}DzPT<@MUb2nHn?@$M zv_g{sOd57fJLK#aLqpigCU^uwJZlI#GY*u;4Gq!OXu?WSWPcc%V;B#bVRzEA4lPc_ zVk0PWv6^FqtR89v@{D$7UJ0lygUn!qrqS@X9F0sYaLiyEf^H=R7ZR|1W(ZmY1<He_ za1qc_AW#?}MBr-!AiY3n*@2PuPzrO*@&L4;2*qw#c>vvWWe6${!08V)&0*LBDM6u? z2F6->L)3%QFm;2AQMhh!)<!JWG6XGh!s|+~6Tv|Yp0ULrB;e*MtbjyYT?DcUlq7Hk zC%APA(TkLMVMm?8V+ZUWLqkwa35qpvS&AHruoQ<85O^D-ur*gOYs}#7CRl7i>?IIY zkd`5|$pTvm1vAss0@@(}IUej}6f<!;9AYSHa}(!EEl90^y?u#xOc+K8VQo-?)@>0^ zAaK7C2q0Js5)#j#RWy)AM~1K^T(H2xi~s^A!`pMP(1&%hp&1?SLU`yy4a6Dla1*h# z5MgViV9qrJ6)fO5HH0P@xP4G-a3y<iDFO)&YX)$$$<xopH6q?9-r2`L*wrQ8!!g(c zxs3>#-Y+&b%SbHFfHd#SLEESyx5j1Wm4T1*&<D32ao+ZBXb4+vWoijsD+4Q>KntZn z`3f$9l18DPFtWt!P*5oVT^ovC2B2O`O2{18nXE|V0c>>@n)?hvr#yk&ZD<HuqXcPN z!Mz4<o5JFmfThUA1gM@0$cI&;pmU)hIRR=gBxpcZgJT}Tg+@1#wwXh%0M*~vD^d%{ zJ{cm-GsIT6dL$NSgeB&bLRVxP!j7B55{4j;n4z6BOr+J8aBHCZHlgVla^h7$elhqE zWoUM{K;2YHAWke`y78IpT$Gv!TXb#+T6%^xt|03+VP1rnGSFBfE`1xCz}y3|6U|jY zklYMY18X3X=4DH`b~Mwi4M8WTLPHZ`KimeC#iInm)X)@W1Jn>SdxA2-OShd8i&H`S zHbE!FK$@o{Wnn`@Bm-O_MnaoPNc{`=N<J*55hz8XjgJ%X8J;c&>Z(0L=D_xoTQm6P zm!&2q<)lIurDx`qKsRrif{x88Ha0>Wqyt-po(O8=qX<LBHX&Vm15jJa5VZKOq8Mhj zZ)&a$*km0u6CFcK%zH2m4MD2{A*mYLrG%B*p!Iy9(huYwECFU{46_960nbcV+(+wx zEJ13fVbKZ;7HB*oH6}re2ywX&>@1Wb5}Mht*nqodZV4$3achND8BoU|B{H;YfH8su zPqHDX6&55&6%~BZBWzy}#P5cn{tPIp3=KgQIi#Y3$0kZeg&8o&brWi)Bor=a9pvED z5^!G**}Vip7JMufTob6iLb@3nwi4eElpl~&0K9-Tw1kwrSO;}6eF|ywLYs2%1%S|? zgg31~fr*)}VD%L)Q&C&emXMkVXNtn!l(vKvwYaUq+LpG2w@KkK4t73j;K03yS}9?A z2Ula-2(+vae=HC(8s7GWM1c|L$S!0P;ckRS0n|j?Ap$oNbQn-UK`QLLBO}<!T=2pR zmQx@p25uG92AnZv<_I>`HOL!M0VACnXJ|+$gTM}uL)Ho%pMf@62$^7L46zWZ3z|b9 zVn`hwLS>1e0YVFCY{XH|8Y1AB133p7Tn*qYp)KJWpay^syY@}Z^~_7lhxo<_w3ZY( zLgD>gSa%7&W*E}r#~rVRM##oPkJQH47GVTmVhYW~hDM;Jn~<RxXl{UI1EOObsqX~3 zk03D@+QKygt^UOBJ4l)WjfjJ)U_wa>RBZYs=BBy^K(;ob?T|2nuLVW+6l#_Rc@r!` z$S#m)K>K10z{9y{<1|L_WuY*ekg9&L@kXE(m7w4RS1e#5LN>w&mLOK5_0>RD;!S4G zu#qK@c54P`b00F3VFt?7#TJ>+)0&JxOD~b`eF2@f4n9xKK*!7kzTF?X@5BhUmJ(zL z$RlRZJqZ@jjtQ*wj@B$Rhq?e1kho7LGJ-9jgqaRa`7pzA7>c{W1TqjQoM5g1Z)^me z!31rIAeu==u*Hu!TmTLj&>_x<s0OzSpamb?0?_G0*t^*v8?ZYGI(Ci4P0+nQINU@a z$RQ~SK39XDk_;jHDbPItPCrmh@SFut1kh1?xPu_If)VJLAyE6t47xNO-DR+X3KmSM zg|O4@K%3n1i=g}Dj6f?$K}7`2d>Bn29hd~?7lDuJfmV#5#iF3I7(m*w1UW=GIMnT} zJq@9SFKmq_NE0Z58ybODXM!>>Eba-o!pIZW;`D@e{)`M!CZJ)yH}Zs?rsWB>8@5&x z#cq%z;8sEc8ny6%nP=z;t=Hgwfi2BMG7q*()(Etw5Y)nj`N|L!dmy`DnG8L$p#B0K zpa}C9+ImWuL!cf5sf2k9J;4~kPB?+visCbLyCGgf8ta2KYK>qk3SnM^HEM|pG31u4 z5o}c-%p`bCN1PKOW`Qrkb1zCv$;?X!T?qo7Couyh#9}j(irmZ;SfLAAF^DL1jlhMj z8MuRLX=a^a1W^V)1p#tEUUEiePD(LE*w6@c1`k5FIY_q|Xz8$_k%f+tshM?JVo647 z5kxgu!q@_Q_+CbSK?y_@d_V*E4lfgH@TFJ~VM8O(GR0z(<kFI){L;LX#G*>j$O8C4 z3j-ZP>&)WJyu8#RxR{}ip>=*vN^)vW4qVJg$I!X}RhhAlp*8%{uB61A94mbzP#tds zS_)ZF44z>F_g_H!z^#z-s-XcQFik)jU9B<8N7$-IP&h+VFo*(s9AXP}0g@Rggkd5e zC9t#(E&Y&fb2f4f@J<0=SPQQ7(aTNLC66dN4Uu(1+I!BB=mUk3p%G|JBe-}ogl&Ze zCw{nlQL{I)(S}CI#z9+<u;N)E4|-{Zp%G|pBdFvvHb7Z~gltq^xhv?L7khXOuK+#? z2-ZpiEnftgfO-i#vH>YMt^uGEFzl_Z8Ng?-!w&>NM41+RuFwort`-}bDH`e+7#V=W z-UzgI5OSD5c<2L{eru%h8tB-$88|iPm*?fC=0XPAK?l)5atfC80X?(<<OZ<K(Ds=T z=*S>&eFbZCg5v=#Q9$p)4FKJ#fRq{`i-m9xryChVx}ngdh2IpkkrAZ!2yB@kHn)TQ z0&%htXdNEJE6@fzY9hjKy^(8X0Pd7-VxWnXBk`LA-uQrPIi3+{X&@xwLzg2XMFiM0 zMxf)9Ky|I55$JMRQ2m7Dapaa3erJFVR}40W9pZqVbxk0LU=SHILEZ?Hz%75oxRnuT z^&(ymkq`^G$GAY&5E}#7muDEk7D6J0CM3W?+kikNA|x4+;9OAm3p7LpZF69bT7m2& z*40=CupmPQ&=v%29VFZX5C?;@FvKIE1(DE{V+pw>97lPIH{~G4DPZ{lQsBZ|fl{2} zHwmH<8az-=PHJu{^p-3`lER0m@e5MY3E`m(QcS}b)qvGWupR?!wI@9Kj6jPaLGgtU zfh9#83mWi-Hl$w(DR@B1*$B4g5n;S3ba)df$w24)Nl5h&d!QvtP%0<`kdZVX8bN1d zJL*|mGdSf}7^gt{=Ah0-v57@)W?lufVgsEhWB{IY$W5$37BsXp0t;hSc(4P?%#5G~ zER-?=EuI9|5(o*DLKW;1Jl$zil!0hdh;mqW2a7vk&3=S+kj!cdImQUw2-PsqA(lq3 znIZNYxu$>tj{deO%E38sH-oi+Pb9<AqJ%BH#1?=cADEdyLliCPz#J5WG{%8m`<SAZ zArLLd-EA!42;I|<%Q>)%nqV}pZ~`wagx@@bsMau?h%)XD4>DZZ!L=e%n+0~d8!qP> z8iCfRf-=9M5ooC>sG2u40<F=kD0a%PK)<61R!>7h3RJcG1;-mZ<yXM(9m3i`H$`oK zL3D${8H;Y;%)AI_J_aoW1y||NGz&|chDM-;q2SD80xe0Pkq_&vLc+-eWEQAp?xbh! zn^=KlET}R>SDRQ70aKfq7m08JHno{~kubH16$I2KR>0L}=0y=QHws}c0kw%0aJ89v znJ{x<<5Spz43u36g;yr1mV|^Cl9|}TAh80bHo!L%dJ41==vaD`C^Lm_i2y|z*naFW z1u_Ea^8nw(3Yc#o<po+yffPX1x~G<ax6!~3U^arS;KWGpX3z=-+*W~Ieh15(s1_I+ zAdE%3=?;9GlV@IXQEFl_ta}Dp9E$8^=s>9<sDuak7@lgOK1azzphd4>!(1WdAI$8a zROl>*kr|c(z|as$9b9KgYEf}&GHl=uwx$yv5@4T$vku5r=*1>#5Lkk4`~#bYG%Dy> z3_F0@2(&yD#m}gQqZfXthMRy4f-a)~$DVNtWbsQdG&Z5J4_a}GVhOaMhX*WZTPUc7 zfi+-ZhGAIb2)<+kY%#(jPy$Dd7{`<puo`UoVNEJ+SepvAh!qyt@X&?16)u3ytpz@? zP<8|tRL=SNMJdqbRG=IMavW+9TKXndKvY39f^TLXgb(!+beT1}E|@B)F3`PX&Z&7N zsnC<+v0G+nfKZ2|(Iqo67iJrz7l&$_1xOc25mZk&=&(x{(5Zuvp%>VaT3DFD^9?Mk z8i5wILaHXvGFDJb8-W&}!p{57PlFsY4L&Fw_o3gQ)Q&x)Tf&{>8Wdb&XaYHi7-lTi z(}=+ZKu~I83bIGcG;Q&vQ$r)r;!vnZEHrH)9<kK4g?S{CbdR8>RhWa2y#X^6hd02j zUB?u+qWruPV`zgHG<a8RWNcQDpP5$zAK(P7;Y8nA1J(x49>$=PCZXGD(h`$X5!wtv z9z-3D0&4?Z;sF|q0`Ii}?ZQb(%>mn(0~z-;292H?nVNy*t&{Wf@=}vaQd0^NGmD^R zo0^+x>Oe<P^U~5Fx(qdSKtrg;M%H<0X(k9U6Y%XNW%)3}L33m#7U20b(9+Nn&~hcH zY9r91&Wd99)coAw)Wo9X4C53l9a9q%9YaG?BWsZA{5+^q(9I{1Auf<Gs5&S~g^ed` z>KK|s?o264O)AaINlDHx1!pnXH7kbZW(J^5MmdSaC9s)4kS54&DY@XqsR(;4jKBkI zps+0|N`>A-W(>NL)X>7z3}g;wBNev#(+t#M0VOv`$!UhRZyTD3EMUn1Pj3Udyb?nP zT89H^JO+mjJVPtEbinL@)ylAv5ww;SobOP5X=nsm+6rnN8XAGtqJo;Vuz<jIRWUpW zKzD<J(>2PK%b;sLz@nJf6bC?yK-gkYm`%`j7RW8w3Lv<Jrl7ly1E57D%!e>DVS}Ym z55lWen5o95(0O`jtpY26;iiMGg9SU>6+C1LW`egILn>U5-EJ_;AngncBft)HLpTtW zePLRl>vUj#h94LKb00JiaJde2UoOZvXp<AXJ_2eqXw4t4xWylyU{j#Zb<Hh+UG8B7 zTNDU$ENGM(lr`XP#pOy<uqhA|!5ToT2$9`}VG^V<M8LdEa8(kVnv<Gb0$ThDT@M5E zKXe}_%(ak^B$R<cS7@S{2XeQgo;76gYDiHk^qy-&BOJNS&=5%}RI__(3A{a+nU@ZV zGFTpjE#HH?6H?NE^B^dmU`ZB6o4}@haD|Q$sPT<q8(JeQ*f<_^VK8(U3bL02o}xj{ za{^76LFfG-tqst6LgYw;w>Dsh<bfm2654G-Z!f?zlp!cbq1gcGBS5;Ga94n@PltyR ztc3v0$Y`+%wi;G6!EP8gg`R>63o&y8NL~j|M1qz*z(Nu<DGmy1n48hdXi$*`aSha= z;5r#};4*yp0kTCh$S>G19wd%_#t`WKa)=D(-gT%PG!8(qVhEdiMr_IO%ye~4OM@=> zc26yFFUl{49^(x<&mGcwf`tuQ3W9`{p%G|xBd85!VhNeBz!grgV8AHIKrsil7(EzJ zF1$5xb%lBfbd51IQyRf;r-ug-p@0BqZpcV8D7C<HHCllQO@y#)4WIvqW)Ae2gbfsf zOazsg7(E$d*osD2c7#<BFdJam5GD=_EOeVJaP)pKYY~VWKrVv#(HOP_66OS$r{GS2 z9!81FYIDbw6p(R{ERU2F!DEV!DJjmdCSgEgCbZvT3|dBooV(F2MPL1b?q5SQbb}$* z!;&)iba-oUryDeD;GC0K4A0vr3rY|Lg$b%^XnX~w7N?dFqul_Z5~>xnlDQ<Ys07@I zh6OfyH37*yu&{>a9bCx?v@kXpZY0zi&%ENy6zJH7F>Ey=EHa@6!s<*|a)QMrMxHZ+ zm<A0@aPtG+*-y+(4MwsFHa-n22Ec_P&U(ZUG@Wh>YUEjfx(lFs8R|<6H&_HiZ9;QJ zuyK5Vw_k8P_FBX}CqF4M2i#VIg*9yC7wSTI9zui$q=d#98it@-(~%6u-Y5&p&nbni z&@_gvXM{xnd@u=SDNf7GAm)Ioa3?+MAV^mPT(RaQ=7fN{J+Ksvqa|Quh*gtonKfh~ zBe)uYFBE{rEvRD$S!e@VQGmM00OWRCY>Nz#^isOOz!<cG5>gVtC*Q%9qcLc;Bq+U@ z8ABx?2@INQpalXnEnu|wajz`^SqK`RA!Go~Wd+9Yg_bafLGrL6$i-l%gB@xCJF1F! z2jjlM0AweTjz%&BZEnFBzCII|!;N8wRT>%_LhnI?hd$BX2=aza|6=Uv2DyMZZy*~2 z_6DM(Y7AN_i7Ul`!=E^(;_ldjY#_p!*p~}{Mnj<OBWSwCnmk~|0D)vkaHRmqIwIUk zaFKv9Xq_EOsDe{5JW-?990c5rv=#umMIX|(f)>rtiyH|U0?`Al=b#+qWdOu_o~RW7 zM8-O-O$XZg04l37_c0J@5TSX0W6-KE<QRc<ILM6?$oxAbIzaWWF=)OVuLXvn0)d1q z1+f9LlE4}=QBPWgL-fEW_u*%Z+N9){Cgr3eDl5<u1^lOHn1Jp|f$UAh7;iI%FBV3O z$AG<Q3|jRIu5@4$#-LM6LERWbW7w)+GngD|IfHcUKnl2j23b4~32)33f<SIS%D9-i zLDQ|EeG{Oy_OSU2==6oL5v=hAbBZx&EicHKaL0kX0`(JgCXIk|A(01nF1XZ1OiUZY zm-xc0gcWPB3!uQ|1vu0}iHm?`p!zugGJ}R$OBg{$wxFd0wvfq$>P4&}F$OIP1}A2i z`@rroGzKmA1;r>h{=fkObsDVQiD5qSZbVqX!`4iL#&IE~JJcEr6UcH5LwI;Y?1fr_ z%MXwh&ycnD#-N3~$WAwdo*V~uJlM%7X5w@>#88xNfFSqcOJ!Jh0fHO^(uC6@Y?}a$ zL6Z^4zJT_X(E<kUHv$0!>gs@Q)PbZCP+<!#NnnSa!V)@W1Q0M8zF!X(`mh;zXpF*L z2ueEO(1#j`GdSQTA}z9q<y6pWVw6w;<y5e#uml6Q4{8mrBm>T$kl;W*R46aCBt13H z$_ms4M_f9OC@Db`{P;^s@Kx53k`k8O;jV{`gTbyxHU{+)z~u}=1bU088A8ModY+mw zXaz2KI3Fg5(~qEm3bgCuA*+PJ-bS=2(TgR}+Ffw?B5Z(!t}%3dI5_Koy@<D1!f8La zq=J>hm}QlTA@TxWq_PCJf#7w%&~g^30D~{^h4}>RazkU#vR+65hPH4DOM1j<Dc&*- zv|JcD3{9X%y%-v!1R`3Kl^DN5N+f7TgD?1nde8(mZw&GxIMN_KhNclxya%xdwd6BF z*_=g;Yq1xGCa7y#h%pFj`3PS|4D~*|d_)Okc%VQ-0kbr~8ON|96P8$!3QhP5V5r@g zF-*F3@KO&Jy|BqIm>n3=3$=rkh=p5%rD%m6w2D;lKzm%UbW1^CLW&(|E=4YHL04lV zZOs7PpohPB1s~Iny?BMM>@|lBksBJrSN0-Apx2h0Aw*#N(2PM#Qo+S5Ob!~tn29DJ z8Qdg=_zK!U$7~jZ&g29a1PJrM`4T>I2Faj?&?XNd+Xxh$sEbRH@)gvv;Dgg(i5aP& zgfB3Kxf0?kW7xr-hM;f(yBq32EC~*31>Ry2z7!K?k1>4dB|N&I1Beh8K&`_W`jAoz znq5GPH<82I%mQvGG!>&5irWtmQ&G!4)b*Q~L5sblGlOha!EF`Rat*Zh6xk#2at+#^ zf(${!y+<gJ@RVZk<)z3G0*+{S0wrWRygY%$0&F}UY9!p5pwt958fqf$K!F>HrHFzZ zFp89UA;Dn?b1~dPs699n4<zft3nb{CaKw}y<cuB2P%dchwAjP|X}_2;s2NyMjB>mg z;s7?#svYRwMnhxJip+{)@X2iO!D6s&pf;tBp_u^)W3Kx)hA*pxp0of>2WFPg(gGzp zL%oT8>Je0KfG3YIn_H-hD{*Lt4c&q!VBqIFf!qh`)Zn!lbGQxK>wquL#O^uRbQOHx zD{5?FcPBWdL)L|Z!#5tZJR5RO2mIPoWB9^NsKsy_j6tg{A?-rYVn%Q^096BX4XnWi zOS?Fn;htIoooRtN13VcDI>8O<d-%#fs09|#C<VCzlu1al&;(>MHXA{!TbvTpq0=13 zpw)!nf(2?TEa$*lr_eCQ?>o>WvLDD$&{&<5p0#^wiBn=aQf&fSsff=Olw^zFF7P^J zsOg|VONe!dg@>REtRRC2FdxCjP+(qySOz9xheN<NWfK>fpcOhG3tclaK~wwi=}^#A zKIoi))Dn;^ELvf`J5=YO<yfd|AWnrRKWN|+%uOKcK#l=T+#y^8J;?^V^athq7Gu!L zOO)t<*lP$&YKXhbHLXF}nLvzSKf}c-H66A9-WYa3rx`2|j6qGhiek@_)FSYXYES}) zTTfgpn1U^UrZ`vFfk2=HP1woCu6Zd?o$e^H1zOgLFJugjL5E+0`sRklpoNj362TDU z8IT7kOiiFt$}rvn7ABwt7x9SLgshBmPb~qRln6~*@D+{FV1*YEu!saZ7vwbJf)tdn zLB@m24P>W)%PO>xf{o}v?S>~>3hV}_WAtDE+YN0-BTZ0&mNR0BDR{mjChy>xow9&* zNbzPp_}mow{&Hv$530+-Z3T1C@j7VJzMw^z*rt7v^in+S3tN5(vLBiXz?88CbT|nv z0WN=Fi3I9tq-kHMqacGtcv=q7V=4(50BbuyV-;xt9Cnx^++nbi33ih)*rD*VGf*QL zpM#NRY|%E88Ka)-h|>_{5hYBA!<J^^a<~O_p&IdFj66Gw?qo|yCxUP|BO3x9)kDfb zu(hAKoJ^!s@nj;@<H~S_EIb>bHYH&TN^v?5oD_(3Bxaive3}PR69x6|XIyS2JjDw; z#uDyqh%-T14wU!cMKp0qm%tP+agHW<Je@Id<`8#C9q8^qPz_8VaS}1bOI-3HIK>NF zjSGtra|7t8HJNdO+(`rtcN>Fxf}pAhrv)TteuxFo0VK$5EwsWXE}qOFdf+p>jxL}j z&SsGPEaspED#d0NMfv&g-YDoWQAjTbbOdKbF+_u3eoCsDl@54UMsjW@Y?p^IXw50& zY#&q5**@Uqx5kj&-pRR%70`_uAf-A+MvxO}Q*#pG!r*N_s7s}g>;#Yefj6#zHo{<( zwV-Rqz%6``S3r3R+6gu{gboy$fL2?A{bK@J0tsrPfgK2nERY;j54dRyO{L}#>&?K2 z>ZBoNLeL6ckkv?O8?Fm<pbnBQw35~Yc3vVb2cwn+FjH|CtRMriI0Iggdgc|U!p<rK z-91Mzw7?+(DX6f!1+-)_wW!23z&j1zc?K_=1MRKM%u9!)PZQ9ojNqJL2%ioI8*KtQ zQxOy+=CEV6;PC)sz*cm_3UpYX0~Q*Fpe+~3R)X9TY=mpcJC=nkCa?n+aYX~Z0Ki`M zf%{f4ze9)S(M&f4`5hDpCa@+9G=$MTXbLtAegvjVYC%Z`%xLHeX}Hl4m%>cO6=bGh zGobw(=%Q_Czu&|FvOpKz5f(6IP+ed*1*IlK9RgcN2zLmyc?NR{+>a)(g@uMDpp|@} zENEzqb|fK&-7w2QVE|r)YG??_mf(^IvWWofB_szyhZf-uLJJv?J3xVtD~K#$=DFgs z5EdXPc7ie=y7LVUk(A;z4(vyi-nfYY<QxDD^RRcT(a#fyO-)0a=+LvpLDxFil6$te z3222P>e=ELw%|Nx+yu0!5nKj<Zk7NQxv(?>T2crp1E3>Y(2M{rg3*sC1}!&*ddd~g zk>eoyK+!>zDX>j*m~{&5L`P7-K@$v^GBHHCuYoitLyAg_0ag>#m3jC*j@DN~wBJeb zxC`tcN2puKGzAuXh-R}1Y(*nH+@Ki{w5|>m*@h;d1#qDJ4_5&VLs)vp>wV<8Bb4p| zDPc&k@lT3jSbG4lB^|I8OeV0kZ!k~8hK3BuPfw63D9DtG31|r&awda!D@?GS6h~B8 zLo7g<;{y4E*vy4>x(nn`kO4$F0Nc!$3212`vQMFnJ+y#?`yZOPh$#)gQv;bn-muwE z#8kcsXcZ!|rI^u2f<5rLD_Gn?*A*ht2E2rX&Q3xNCo0h3rlXyVZUS1Yi0lVLSk8nL zXyk+#{@y4lxrktwloZ3Tx6L3eK%_`DL><yYyTbvcx*^;-C8hMm=%He11i)5)!V(1{ znM2Y9&LMfc-oW03fR$Fz1!yL)Rh@9VO+f28L4(`~5ok3?PO5=)XQ7j-C`YZEfX;G7 zNu%(b07;~<!VH=rh{@HU!XD45>n5;upa`$QE&_)a%^>fCD}NHK1$h$GZ8QKM^#tw! zB8D|hjEx|NVZbd#_ooSH#U&`j!SyAnmO~an8^we7AVI5mRNFyiFfpMAIhGx268@&9 z3B0Lks!4uR6Li!pzNV&$ofYn;CT!iOxe@d{C0MY64u=J`K9D4kd;7SX942_1ny7c# z<2MD?R>Ev*f>w7z5<RA?!7&dhsEJK{5GUhmY8s;~^CskEm?_}&i_}OY!Q*(EnxvQl z3qGW#rZKF84U26^IGMl>$u%^At%OC7cES~@iK{E_rX~qt2r7L*P6o|PJA$vEMH^=} zA;B=>nwqf1xo}ULfEKwz$`a7B){0_CFUrIUoVZMkp+zes^hii$koF<85d&M!ie#%P zbV0HSXb~o;#cyb00v!ed#Sz$c6ibPU7Kp8=ty0wWz<3ii_Esr$*(y;Ez}hN>t@VU^ zAF1R)@~DXkJc|=u{@`hrf{u_yDLFt<4Ym#*t0crHyyXasQrIXHEPugW505^m=|qJa z+<5ecDQrO|JnSHe0`3L4wNTp#)>|g7t^``9BxE|mEmIN<BeG>mLcvHx%ajDuh-sOE zR?DI!I(Skiw`FSL>Pp<bKPI3ZXef4@fKHADm2L3ELs7B;wc6nQKh&lvXxT4{)o^b^ z%TI{!VFQcABvMf2fUju^TN#Y-8|*AUgePGlB;*Z{Cvi7TVGDiXmZJO91hnKA6y)Ig z6<peoU^#)NDe76XcuR7;P1DT05`}0(qgZ&G)Qo~QDQHbHYMT^cJnqIQXx%a-!9WuT zEFeLPkRgpxxCFk+z|qhs9^V~{CZ>>~dmJeasvXvT!fbxRmJ*vA!JPw+R1-6(gCWH+ z{y2u(g7dCL&}<H#J_l4g?y*f`{D`NeNtAY25P{lj(D@D6;%9i+K*9pF#Q}V*hM@^) zu`#G^16KhJCtOt`#HYC1mS!kho6s`=L^r71067wOqmmd?h-*!PmN28FViV9(Wk~i1 zEj~s}{2Cg9W`1F#N~9+qNW%`=_JA$@g$Jt%XiYA}TF@F?bZcSOfno-ndLa=-RAfLb zMr~0-PX@)Cr?59A%}{4=u*V?QHY8|8F-lNF^B-D91ce0Hi%`$ubtAO#2ue55<)26c zV6YX&NP!G30^n8>V+Xup2aP+}5@IA{p>-oXcA&-*$Rr@ALgyWkuU0UDtsaJ30Euk4 zqe%)OcuNr}j37gWurh#%97(v5NK}p_>c|A5%6lT3g~XJJ#Iy%Nhs|P7wvf&qu_KkB z@XsW+A!rU=MGa2^CZILUpz;ABf+!Q9$q$<9@MaiL;|SyuXl_Am1HzUq!|g!Np(I!Y zD#Y<M{y+<&QGylZLvX%Fq;qrVrX^xMhP%}VTjz|^XD0A<&Y&s}><(gVCD7cnKv}nl zy{shM&ND+a^UNt|=7H94V`=7rOvl~IgDtr>H-g6nIB-lr=dMCpd2k85tvoaQjXc!j zr!YbatQ*#V!EEEf7Dr=qCD^%;5|luUf-S+_#6w#mjW!YC2-c0eg-3)3@ig#=(G3e8 zP}2!owu2U3LoyjOk|5z=0$L~yiabNm0v20H`wprC8b&y)E|52IH}8lDBT&Hraw6{5 z9TA2Q*SLePu7)LE6VS3{P$_C?0$L4>Xk~#{^}*V9u$@Sdz=8${u2K~g9*`Cmw0Qtu z$BVEOwzt*<v@{dVQg|tD0gV6@Tk%E%#9Gvb9qQt4toaCgyAHb460e0=n|1KjpfLZ! zDh<?NG(o!~8DDt9T6Jde&}s_QQi3LF(ArIuBn^sFa2^L0Nni#MF^1lz1FZu^GZj+1 z8-nr*vZ;6j2yQI;7$9g3DT?`!ScW^9l+Z!6=-}al(x4+E`w(u=5n%|CgMCC4T|~6z zh%kki#vJTYdCZCelKY5m%z?5!af5oMu;W<acAA3L>w-!lxCmM40Nj*=Cjpd}oGEA> zFiLtu&y>Wq<UqazmDhM0a;EUbzOeic@*X(Hz<mW5AtGmje1)?eX9_!t6drQu{xStE z$pwWixM~ACg9uCUH{(FI;v3ung%aUboC%^8XF+}|&J?t=7)vV-WIE1PoGE-Iun}}C z05sT4K_`oX8Up4B3B0X16TGcBkUjVU3alH}Ou=ZynSyqWK@u&dE5R`dDKrVhC)g64 ztvHY+L^u)0#4s@)#NCP`N;fQcKush_m1hcHg$#=%NI00n*BqO|)*PcpBhJbS6i7H* zam0iXs8j$s(G?O>n72(5V+c{LI8)FD4wPhJ3R<rV%H!s+bJ9TRn6wlEX*)rhY^I1M zywHSa3R=4hvcb?4v``k&WHSbh0m7PWriRcKBP2ec=@M_4L##z<vVr_ZC`DpzvVoip z(umhWY)v*(#3ELxf02p<q+kSv0+<W+8LlQ9C^5mBY$ljZHdD~rSd0h+8w`&(B5Z)S zt)P(xT4#%9Ds*%Y9xqT+@dgmwShOaaDPl=0G>{;%40kdqp@V3$!NUi+$wo|GA=qRi z#t`C~Y{ZmPgqv){m_kI8%@ncp7a9++#0t%QL^s($$&|<@8)6YI)J{{-3RzHr054(5 zN(Z3EjUzk>pf=fH$8W-IfcX=)eUG>%8_1WS!Wmza4Y5=f$$O|7669g92s97j%ljZ- z;cl`aR(e7$L-&^{Xgww<Yz;y67_pWTXtJRm_leOD289w@lg-t~)z{T8B;M7<-PNiD zw2{LUv@BG^K*!v~K$8I`?dIqVlLoEk1WTJBq(dSDAkyZbbp)xwuI?a1tqgUbEMqGp zosb|;cPm2!oxo5>7b`<UFyG9|&<HGGW@Ts$W>{Dmn&^bMhFBRHfG9%)D<ealfXE<6 zUr!e+BO{%FAkSc5D<fkF!_dge$VA7(HNwisRL7bjC^aoJ4|2CLWJf+|dcW8tzO106 zNCim}<V`b8$eu^c1{r+qDD-+*=ptQn9Fy_}2!nB7B4uifI^Te-3D)+3x&*Nx50551 z%`MzEL3a*n8Gx#Db5j#dYwP&<l+>KmlFYpHc;f6e08QOEYJq13Ax1#F4{fx;m%w5V zJ7W`QWrdc%kb=VuVjlQh3=`kf;ta_B6Hb|+J%}({VEe%c*kTG=cM8d4phct=#Sl|6 z^Yi=*N;32FiXn^T@Hhsd0m(6-qhJipAi@Z9Aa3+c%uWqXP0r6t@h?h&-79En47nf> zR+J!l)zB182a-MDLz}>t130CYl&6A@B?YBgQ_z}MaQ%<N>(E3BJ7XMl?*O=L0axRe zhLGVM7!A7%)Dl{$pf7VlcB>JxW57p;#KZ5<2{w*T$poF~5pQS=RtCC9&NDA9-!<4Q zJ}B5QJ}B5E-rC4f%LtzGAfAC<D*;MKU{^v4Nmx#UdjjSu&;@oNjbP6}TcM_)1*6b7 zhTgbtVF5A65F`gO7v@hxQ_$K`kYczJ+;MM6(8o|Oo4cl@r{eWCxcv<Bq_uTGQGQlx za!E*jaA^_fUOQ-thA;2L9<AokGu5De#^Y!+bPK>~$`tH8=tae#zKfO#YD|C@lj2EM zsP+?+T!?W8I4_|k7*Hw!4@*OWD=aZ5GbOQvv}|RGMHe_2kjfL75=d#20xD==Q9)ec z0zY2>Ph`Lyf@BMlLqPt=bp!>ZM6s?@1y!}6qM8A9BYjwEvW>AF;_MmFsxs8GXG}qh zcd?y4gV0Lp(KDv7b7;*?;VWQ4`OVN2v^W?%!UB_kWLea(LipV{EHxRLI>Co);y!!^ zWF@Hk2Q5zV7=bn^h1e+px;+cBS03g#SaAWXoxqMYhg~v8ilYNSEke*S^BDUxK(-R? za3o{Ei}aBl4_hCP%kie5!(2gSoS`Xb4K8?^3!xTyoC{CjfzHpvc`>`G31l@4F>w&& zjW7o66{KbcsI3SobTCs7I2jQe@-8?xzM7h%w7YQo7}_=hFXji0@IVU#_|jBF2!dS( zO5k7yIH{o3o49QObx}a3yMoGKuw7^y2TV;-S_`;M!a9hAyq?Asw1yTXbRkZKyWAAi zIEJPZ=nXaIrjYpnqWuH!;lnSgLFwQV>lwnmd}2)^va3&Qsvx4jPpnZGoqn|ad8Y6s zy0D~X3R{v3FI`dM4xIdm%^{%9DlCpbEhtma>Q|K10kREjB*GFCtbK3XX%b?IF{q^n zx^)Yb&=J{)sIm|JOdCj51wGOR6dc7yCKXoth8hMs7ND!h40H@FjW7>THHELzMI>mD z-*6P^h}s8F2M%>%6_OUT?i*534O$Wm31fJ+LUskbZH^j=NJbmELM|!5tW2Qi3qwm_ zBrS$;E#T4?*)@jH-HF)41m+qTjaCLASz+Xwg40<jr7e;kLxdg-cNvl7F5=vW(}5_( zE1CmgnlM}lZxP~+N0`gdY5XCHJ1mWnuR}n0Do(dT4{Ss#%8}EYA*j>`3E*=SVzWG! zgokn!0E(-SwP6GyY&Sgi#AjiQwWvWd9@HQKU08_RkpcISu{aTB2RM=$plg6|n1SJ5 z*h)m~?nMM6(cy_`2BDocWol-IGoryk3e$;RVSpBDBNs2`7Le{Cyp$v8Hb{XD*|QC< z72pfBq25L}5|*@ark=!LX!!$ktcE7E3IMJ2Ms_XivKhE*A<Yw9Wnpp-q|F3&CTOiV zvRUwZUra%(twH?`LsM8SiefBmP6UxCAm$>SH?Cl40d+BaAvH8G42_H-!zYFyYmhS$ z7Gui-ykTe0`lRNi!wz{eg)gIq8VV0l!e*L53<3?nIq6wLI7TqHLJA8^hnPdvL3R1% z7v(1Az)$ivg)h2>ItQMx;n9LCLM-7%fsA$p9|sK)f;kB-%fm|~!afCE+YB)aWVVx@ zwKW4c-`g0&cK(2>RwCO1@I}S22~0?D&)gJik%K%^f~PfLj*@3lG~sR!fEF`@lPz|a zz>@-MkfRumyG3A*vIQJP6Ye$veCacO7ZK?)Se=Akz?q|V7r{{p>Fqn?X&1nkN)zWc zV%><-ktqAE(8CX2OQTm5@Fmuyxsqtt;&LwP8f#4F!t`Od7uE{I?p_=fF^c)1su*^f z4rc9Zfzkv-(Fm%45gIXE25SdmcNx57LaTdFYydgUFE}1iyhDc3u(%SX9f)EE$dy>k zfK_PF<5WNgVM7Lypw5L2k;2LqB0>_m`n86c53evmOU;o>3wVVIE4WZ<HfT=(*(Z>y z4Z3aszE&LSTtt-#S}hH#GA&?tVxgD|t5Glw##(2BmRKV@8mZ1iyZaog!AP|xtjITl z7x~7Tw#9~K(C(k1sfC56En<lZctQ%Cs|<9oo+oMwUlt9!ObJpC7@C4sM}q>u93g=+ zN(L*hjPRWr0x}-Ci;JuYcZ~pAjtvPeXv+f0O`rw_*h8Qu4~{AU;v`sJM=y8LPS!<r z5=;|%HiR$aMuY~)CE#EJF<?%D(YUfB)M+qlFx-Yc1A=tnsT1JGE)(fEVjYRom5^o? zdgg+;5~d9!3}Kxx5}ir3b72-^gepq!44!A<?uF^Ya4@W`hQq;zrl1ArkikOGqH*w` zGD0n$>;mq=;OMAXqIA^IT#Kv`!@00AaD)>;NfVw%4NXBSp25xq9c2aH>S1UGT7O(o z3>s20vcop<i{b#(n#9P}6<1ASiM??H33Bk9D6}?$n*l57p*4vaeAP14H|DS{1fY@$ z>MyL*=Ex4lTbG!@S1UuUfYl|45JM^Sv7~q8%ES!59vNyJyfQHZtwRQtrG}=kV_;DX z#whfSTwNh1W2;TfK&yUHibr@43}g{FXrKinR)bM$6W_!V8)F?rZ2~&Z%ESUzo0x&t z3L|P0@C+n4HyY>|TbN*uFq(mu5JQ}XGIwEahV|4_W8cIQaEsR`6O=H}rYjJGbRc7q zY7sPTIO`G6!G+Mq2zJ+iZoaXF<Ok65SxEMUD@D$}XjX!<0iwx<R@{KB#phZ?7Di9< zpq0DGp=S<l9KeDP9Q2s=9;)MDV+|m6X7J^*&?^(sO*8}r0dk6grg01-F&zzSk(q%O z;3B&kmWyDnh77+zNoc~vY7HpKgJ*ysPKOu1kQhPaCeV6ZaBeb#Ezp4ECI|_&0haVp zeFC+@Ne^NLY@r1-ba1#FY9dZIgUWG;dGG=li<7~jOr#UR*S<LC=Rn2`%;0Ngq3(o_ z8JIy&CPWQf>|Qr^&Ib<`Iq6vk<(ETEhOe82nhdTEz%C`p=%D;^&^Q$6{-^w$vQ(Ji z@J<yZIG`)W4B<w@N8-#t>pCGB(SR7gm<EHafh@Oy)+5HQuAnspM)98D!US?)wlxE! zd_xS7fOcD$8^Oyr(ArK!`DOuH{Q=Ho20EtZW?0HM(8^CpT1Q#GXl@1{0>@Em7~^Xt zn;D@rP>_-=NE`0*4Zcd$47+R0Kx;c8!3tV<2`S&;O7XfBk>4?TiDpJ94HOL5BDA8H zZ=kiE$f0L$32E5Ff)5<@pqzv=#~Hi2qLgo-MVa_aGz0|!I6V_E64TM}@(r}I6WI<# zDFKaiNT!C6_^g2zK9H`b8GJn@H1ZJT8)&s4q<n+zqJo$WA)z*4$>he6Rs;C5EKn$# zfzH(=!sSpCG0Qiof$;JTv~CdDJQOE`Lzze?qLpu;Rfx#uBFZ<=Y$nJnM3{@Ue1jeb zhCQ&1u@_tLwS>@!ffrja$H0m$*fapFuZP_hTxAt_{sKIR>z0#P;#gFaSc!TYX1tM( zA*`1V>Sy4;1Q>iR6xK_C&ERKlT0+~)X0XM9<_Hl>P4FQ<2ocztKtnUoDm-x60aJ~d zV300<MLtK^C({s|Sut*5LTcB+*ViFT1}7sk*u)n&-oai2r2^vZ1+A3Aee0E(2}(B` zp9gSU5o`uJToRmQVJ-)|)X)sHx(t$cO|VyF_$))-gas=*VW+B_!55W5Z3Hzlu>=+@ zF+y`QKI<U+kD$d7XlWX<hd@0<i1Dy}RS+LS;{cY{37e0yzX{|Eq_#0W-B`CdnVCRl z7>KbR+ioW__}P`vP();I=)4EmmvGNReM>}OLiaqu57a~KQa6L2TnV)kGv<i52EIcH z7HzO|E8%8Cs#I`F1jirLY+^zTZa7l66V@FEEt*44ABLbp1Z)8;vyu^LDBW{whOpFR z;}poU77Nf4GvcPQ%wP-VKzhI~f&~G{3{Yl7l0a_sn1b!YJ)H$I7%8zrmE&%X!IqXG zSqFBG8T6iNSn~#*M$58LdqC?+U;|U=Jxo*70XT?1Km&v@4QN9{W}roFpxDFZG!s*- z%|f_S0$>JXxCEu;3RQ3D3RjQe5NNLsmqRQ}p^*now$PjhH5lCQHh`?8!fcnKUiS{w z0-Co7hHJra4s<~SF6W@HwZ|1z;1Mn4h5w*7lQkA6LW(a`UxAzmsyV?U(Z(sR;FbZl zqtwknYrXJABh0zPITM!~QKw8{i3`<>P`w!83GD&n3QwHVRS;W1@rz}W2}?Ml4lhD< zL&FiNLkM;ytR_`3GK6+aVe8;vu0*sqK@;eZ5(9hf4M|kVWvGsXPRGM6f)$yt!zN+Y zSi&wUhZP8T6Fa1Agrr<h<HrnkJ|j-!VC4$d*oSqStRtX-U<O^j1v3uTtuchT4y!SS z5g^Yx>RCr3jKL@)4I`n7qVOq-f+~VL2s%B0+d<&E8JDvVBS)}f9AO5*!v)@7ffg>X zIuR195U)8Qc@5IfMN<X#o0Fb3+;3P_fj#G>hX`%7f(Fw~D4s*JGXgrg0$H^J3sh_t z<5>-320iBy)oiqtFt9YNjg*Kn;<v!ZHOL!QsKRvU;?t4qiA9GNTn9>X91<J3K4?p( z^zo@q34^M3Oi6(S4|H%3mI^R(A1n&+=0an~loZz#gl`>FQlN{A%wVg+h_-+z3r#>a zKy6HcZJPkyTMu5M1oIoT)d#a0-in1zW5fN5HK8M|BMJh?qLZFAWL*(_1r*k%560Ri zYlhOi;>`5C)D(rxyb|y}SqpPBO~|Sw*k(6qdk(awrr5}!q$o2zuQb;RRH8w*nwEk% z;IJ_^(lIl!E`#$e%|Luu0)xdrY?+&dIi$@3-*;sOTjqw4fzKZ!xBJj`;~^KcScd#y z>)l|6!o%7eQboXa4WgAxXqG^BC__qfEbRhwlpKJr7gVu<BMNJy0Je4xmjekptPEUD zVpg)|D6LFPM?v&iGhl4=gGM=M5m2#_MQTcVYF-g2QVpRoo|0Ky0^%b@IwBE3A{~(k z49yHcsQ|hS7-{eTwnz_Y(;}p~4LYO~T#2J^ctj5g%q@z9q6ww7YluZZfvAGj0x*|B z8@p!a@DXy9go?!i+>>Oei|?>I4iaS;ISN)(!kh)#5DE`VFax${lyDHDWG8EekoW+9 zPrs00aOq%aXbCMHjG+BIOVAj0v7uQ3bVweYB)}0~Pzl-502VPb!I1`_?M;v|V0Xd; z6gr-TB!L{Vkfyp(3ZBj%>he6e2Hf30P;v(~&XKGHJIM^XOBL)94Feq*jTV$}8$caD z961toc^g~@sOJaOf!-hoon(s7QI^J7XJ+9>gIeT>q6fYAhq|f_t_go803AJw&q?4_ z72uGA)?U!w65M!@n~)c*!<P_X7GV}B<tp3+kOQ%rfSxm8C!WIM)Dm{DCoED4gda*~ zfEy00$zW^QV5UPV6hkx6sx(jmW@!v57SJt$wcud>NiBr6u8>-spapEm!Hj6%L(?OU z^ap7MBen1?Q2MMeJK=47So0mW#tr5fcrpih2RS;?T@SGksoiY>>40LWgSEV2;izC} z32hI77QG?+6~1PTklo;(9P)w@S5T(}G>@5D5|ZzmnFq4~+TenD4jv;!rUQ#$sClr6 zg4~Z3lJA>Xfv^Ipp$!XWsK&$!B#qW+o1Ver21Y6HUC)-FSuxaI&t{<2eAsq9Bk84d z+p`&L*&fJ#XoQ0)GtlBWaC(N_Hiy#Jfo5;S20EDET?uS@23d#{WH=4Lx#igmwr~!c zi@{EZI20DiXgLO_g+{KKcqSh#QJPga4KYM91if4b9Ucow@z8N=SjA@vxd+}7Hg$+v zhT^mhRHnju8<@qYB}%&ory-zX6=4Y2$%uW;X0WqiaRxSVPQ|^e8Ds+y=>hwmW;4(f z8@>>Q7S6;ulHiVJkaa}3mEeA6Gtjz26lX(|EG!*huitS+A=1ue$o?m5<ekezI-20V zWg^WXZr3uAu}*l;GLZ%m+Occ~JKh(b&dp%UE|El_xs<fnfwU$d5d-Q#o5N0%MKTy# z9DvGPPzgq2IRLT22r|MRl#1A^Ok|Xy?^Je4%_~mzO)M$OtblY1EkVm3iVcl2QZv&t zN+2zKShuh|Go>U0E(Dp&PDw0Dgb0DBD9lWBjIr!&HU}+Y1?K`|cs2$3-q0MhiWFS+ zAS96c0fvT1F2vm#0GW@JTTyl4>=Bs5)|Y}j4R#K+kOsL5%!lMv2#H#-pju(%nh74> z#2h&Q*@4GpaBbki7}0q)hpkn`=`?fDnpN=HA#>1rQ_%cBl3ILWh!`xxs7OH8;&Cmq zPOyU!wFkZ!z+EHY)dh<;l&jUvK`UNyr6f|~3{e9>V$K7S;6cM4hM+@ozzb91Aqq(X z=Ac7wL8;Xc6y{*tps51Z7Dh=HW)L%>E!J>w?tz;R3TCXjOu-7FnqW<7*kUJh*zvM3 zm%)1tq^4Pv#ZKm+<+aG63hx|%ybSgzBm^KNK2Jl<g{<H-hpm_;<XotU(55CzD1r<G zb)LZmDr~(h%sgD~gqnvnfFTBAPNAE_7Rtg5w=_mC4?vj?92!vbvAGvgL_<dsVetnW zt_Rrxig|1r@s8T#(};EO9@>XBhaH!T(^K#u#P27_1T)M(u&Du%@wog0pCRxq%_)I& zqRc@{gOSr2Y_Jxd%*;VY_(F;`(80IhVhy^=+R_5j+lICBu|}>5$TG;nQ$qvL!mY4W zP^sz)I?fHestqI`Qk0li4092z=ZL6)z%h()5oirA#6_S}X2C8phO8{Kgk4t)4LYnY zvV_|Rah4gni-J;%GgC@SbD<6bEw#lTL`JY=31txF3=5bwsICY$2A^~X4jPwKSTuo_ z-6FdIo<`uIg3rgsE~zEZ@+%m$4jAe&L&#QDtbv5Q2oEEGz=pV_7MB#|S3=E#t@DMY zYD7AMG~5i$afA)FjAv+sYy)ceK++9lpE%5J=n@H--SAmUSm0PfH<7?-ya^Vv3JSg^ z6m;hiO4WnYbRtXz$7(PlR-wblFo&ZD8qB>g8XoJ=$i^0SkY!bwkkY|5Cl#KGVFSO= zY=u!z!7PE%Fz;Zq1iI7=Qc*kS=M|SA+k`sJic)u2!WDxXXyDbHkn9I*?Sk%TvQRYC zF)%U!WqV5tGfm7nCUek$4J1E6GCn-yKx>ad4FXGOiGbz{Xi~=0a5aKt3aGDP>S0YE zj7b%9Q1cv@OF$lgH?NUffG}fm9<&cK7O5DAsYe@_L2B(`bvB-M9(MIGZ^CL7Se*r0 zV2$iacmZb)uaOPm5rM^{;40WJI3A@2fVUxFtFB>jhG9C6bPo*`_(BcTb}8!lwNSN) zMkdI1Yw!v>_{<7u!Dz9eSsBL6N*NI|E9S7Z-j;}4yutBr4qB`YPLc=-<RAjg-s78B z0U3;x6rjpsF@+^TLZ{5IxdY@NSYX0vv>XC8ANQP!xiQM{HdH<C85MKbYHC~#GBk&+ zt~N9`h913&q!w#fA$NSx=2$@XVGA#0E#STqs2KvSK|o8l!RZ?jMWCQE1jQYg0on)( zW}ue5P|t(L0uc+GaL=xQj>5+7G_1NYTnXJCgcLYnH^E#98)JvjxMCJ*VVV*0;yLty zG(kOrAuKi7C<T1%H+=0Kl6LeW1GZ8f=2%PEs%V&N!O;$OKejLhml&{lH0X?pIcyC% z%uGZb2A%i8>SM@s31WT*WDG_upwG^LF2{gW`_Lo-&o1VmVgi((!KoG51F(h^BvnAH zMa<HGOaxhrrV2JkgS=7+yHY$Wm9T3-Td9P$CdM4LfE^Z^@H!OgV|a`~;|JB@*w)0r z(g3`3g}QA35-#|ARoHZ3?M}fvJg^1oFmJ$}4NGY7n1lKQTD3!51Md^T+zwkcWo`nQ zR6|h>Uo~aTP@IupR03bcV`*lf$&i+lp9ophV`*ln$pC5+rRJ4bS*7J9rWcnKl_r-! z8#$nbiNz+liAC9|DWLHO&_-<o9YgD+#FW$=n1G><p><JeS!z*nDon^o$Iv=6Cnq&M z5w6M@ArxN*I^-Cp)&yc+UTSeMs)Q-n+%%A*U~0{D46VWEw<DZmu49O$*#%peZ)pZ? z)x$bIptE8@c>*qB4qE;W>7;>Hn}a)P2u;Xkx;ZqQ3=Kd|f`k)fRS9I=7RwMG>bbF4 z4FJ!qKn<{FK=eDIF#wwDEw(6z43xr#Q_+S_A>*l-6)b3xJh-xec7x&h2DF?V90)K8 zP~RE3fPkhY<W>;Gr_jL(%;7)O^GZ=Pf_(_rh+bE~)~|!w&rm0TDcG6lXeA|z$v9Wc zfX>ne6=B%?fxAHhI#L=}c!Avn9>W5UR)dC=P;)7o!!qIP<k2fD)V1s=+CUS7kp2*2 zc-|a#Oe#Epz^*U^t!xJG>oPPqgshf>g%qs#LpB=Q{v%kM8Fn%%%mVmm2|NmjNFK=5 zASiG^rvgE$C1@JMFcn8>hwN&2gBe!l!M049gI04RM-`%ig&v)cwKs!oHu4rJ(AjS& zjzx5xVaLQl0v#IV*g_a$9@5w#eBc%J=u%`iK*kdx`+Y!e03}&$W<%7WY_|f107yBO z6b|k4g8L2b@Gd;`=5B1pLk1Giy8NJ`A321P3lBtQAR-bW{d`EWhQ%YiPDDLq7CCI- z^&NcOFKFopN-W_{QbZ(J^yR;Z!45N&S$t$SfxUvXWH>mr1iEAxbRq(YZi5FM5sozh z*@V7y*vAO8v=`bjfUS&&WnzTsuoR3Z?V3T1f{wg_x7HVBR=8zWfF~5-hY(tVmYNh> zV4L70vPLq4b@`y%!{LbvbhIb9MnXs+SG|TNkeNo9lfXxdxZ)WcK|Nv=hj!dG0c-&{ z$j9Ks4r@NZP6I$G4q$l@mm?vgPndP48Ol}{oQ{NP2iKfPBPqoA5zoL1QQBcaggRnD zjKk3eFd!3Ju*3=*IfunIBsk4M>%T#%z|b7D-W%K$gQ-AIy;#E<_q3TAWUvfg`eD_M zb^Z)iOTre5!;*xh1#~{1z!3-7qZMAWfrj{@p#od&4YL8BIm}_H4?1)OFZYNF6x{O~ zpv3^#DlFLYYnVe2l`CrUhr}Ax5qL8Jr~(5gV{p>|w2B*CwLl{mQQN|N3NaZ%Le0k? zbx;eOz^Agp!V_(H7i*kD>ORCEI_&UNnBQ@^jVM<^3`eV2VTYo^Y=B2ImcWIV;!x}G z1~RyI%ETN{H%D3Gg*`n&+YI11vW5?RlM;~F2FyMETwEg{%fl_rH4$4%k~0#Epu(1# z3`vQ_naS~)`NcLMah>9l6e}wbE54*CF|!0BYNr4_FTv0NG^ti>XkvgEdN(vMG1at= z_l+;fOoeuo42+C4bu28+z-vl;<I^&8av(AmnmU$77CIIn<si}c%)CtKVii#5*3!%X zs-?K3C^a!RsWc6u4`iODr4dvzxumiHW|cW;{|mI#f({BAnuAu1R}_Plfqi9XrDJGd z1X<$Z8=qI28(&Zgwbl@H*aWmC4_ZJCD)tP`LCcdXilGX@MnD24AMURB%#zfi#FG3X zh^zvxa8m%=Z3+ttkdf)B2)j)nr$ZQ;gO(;k?Kac2h1i{*S^_a0Y<MP_c3W70gDoCh zfgufM!qydo;}oTu1+Dr82Pr7F!7}Ec(<~v~bWke<>`=HQG<O7-Si;kiXL4|fp&?Q- z@=OMw(}R3w1$xg6x;mM#G2k98sPuHygCAq6U;@o8u(h&qUl|)f59ct4t(G-}9ghR= zvJtd1xh$Xz+CGCdq7`8lLbrRuEd(WGa6t=QDM-96d9c~nqLkv2#1iOnPv)>Csc;(% z%|S~(D^lY<^NT?ktQHbaB-?2YwF~OI<eb#RBACyh%|(R0u$s^U+T{hg18gs`Nx&3r zzH4xap%KX8APjOmxU*E8T7u$h=%gnVZMT3~f!zV|zVR>xun>TZ?Ga2KhK5Lbu^XPA zpAX$YX%1bd>`l;E6Oblo#H8k@!5jtYAQ9GXoSL5o)t#1@2|e?S1lvKHp!$;%Np`$( zQX=d``qYZ#ROkhWprJ%VP>Kfio(X%w&;X$q;uJ{EA~s%-wPQ_mn8S9kRi-%89jGn> zxq{d<?`-565L{wt3Mm}ng}7&OuwguoQ$Ee1r+gAjA<l+`%?6kINF5i@qFGS;52puV z1r|Zu@pNx2AuWEwMnJkakUK)bF2Zq1s5#LlB3~H_H4)S@0jE6BiAUgp0<Z+6=z_&3 zsD6NmKsvvKQ>SrBW-208TEN!IVlx|7VuD*nq@*6O9Rb1l;3Bdp1=J#f`UHA@Iovk# z{b33=7uhH1bsF4ks6SwQV)Fph1_JpYIlrJXEf>0$$pW^L7Vbeq1K5$_=1^xCg4!j> zaYit`nM3UW?fQW>Awca=NYQEmTAGWJHQ@Ced>#WlE<!kIn1D=04pH>F6lOBiCr~c2 z;R!K58Js9GbCXJ;O$7_sB3pQvL03~5!a@wT&5l@$Ou?puLaW3qCqFqcClzdGUSd%Z z?5s-**x9sjOQD{DWhe+2Lc+=x!Xan|vBNbv8Qg;_&rC^$ZW^-yt>(oSO{7|73O3vo zViA@afylB9JRoKW-b#+%wk5Xkat0NLAS1y2B5+10x-KvQ>A_bWfXt2ejZaQY&Pa`i zL?$%d!xksQV-Vgeh9*x^lZ~M%nnfrn2;>mRRilu;BSU6>F}QmInRNpT+7=rc8bNN- zhRcG=P1rr!N%{FXi8%!siB|eXAaM)ON@#Gu!~(Q-8QM5@%Pj%V7FvOt8^I+OFrzHt z+Fh+vQj?L)KvQU(lA7#lot9aVnu1%ADOldsIwQ3Lw<6<=)CyPY%)FA+qP)Z$-0Cb~ zN?fgTQqxLsD>MN~yISWb<56RrpIqW<T?E+@0uLuNKbnH&U9F3gGgI?QGSf2ggomL4 zLY1p^aYlYQsCj|gkrpr|5XA-gpz|ycF^1+6OOR@?8kq88+(w&26c@W%7iVV{l;crp z22tQ@U7D9!0;)lAI=~#N!qvL8pdhs<Ik7kuw*xHUYFw=oQ?g2nOVTn^bMT}SLqjBG zuGXNCBcKD+qfP~@akU078vwI$I|(#7o}UPD2grhyB+&2*G~$glAt%#=dTnR{Z<dq@ zQtE1*nxBTM1zjOTfvYvBbAVT+IaGzKHK-SZUnx|Dt94>Q0o-#Y5a&Wq8b!*y#)$<5 zuGXObF)SV-Lu@EYN>W{|lQQ!Xiz<-}ME49t0Vr4ER%Dc!=W3k~8ZLqcBc^5fr6sP` zB}Juqh>U}w$P_H^YMqpt4z~+>4XQDQV&kOLbXV)-(jp|KXl^%7E-iAkPR&CkH^_J^ zav-GUrMQAd+6szNlQWAm^Yb8sX`nMep^FxL<B|4;fyANvz<lE&#U}XbOG8kJsskU* zgZIcFrhx||KzE>kN11%%;T@cKNN*lu1SrkvfKD6%?J@(^K{+`|iOJcpl@%7C{RQA5 zCkxO%f{NmJ=R}B#_#DugCZKyaq2`z87p25kr55Ewt+xPeH>fC%56>@3DYnuvGJ>3F z5e%u};=#&`LFey)9Ri&VMhYcEi+BvR;7|kCkYN3An=Fy9fH4OhYHbLzUdPD7LdVq5 z2o%<6_8DsGSQx+tH9>MPvq0mhP!C&Zf^HXudJj}Xfo+BkaDp0e7LZseN=?r!E=etl zPlkpKwDtz=Zh$n0pewRqwYLRmO9I#u&=4)SoooTxApjP#04>E&167^SQ5}@=e&hf$ z$FSHnzzuX#n`vrUYF>$JP;h)E=o~Fj%Lfv*a2G;1Ygm8|Bf;rJsKY?Ro~d9HQEtmX zaS6Cpk&}Zk-xYM)1Xz=+HK<t;?;D?zSzM4`oQhBb3nuu05|&^By8+%PhPM-p46qsK zS_ZQ#y(qsNoJ8Org)W~5w_(7BT7cG|gNIJRNd*+(pm+hxfrA`2UWjSCp>e!#Ji-ds z%p{n-pr#(eTWCdtdAu)pTpj96NKOW~B`rY9-cjQLoVUS_0<BPoqzuq9Zg5iyo@}6Q z^G1pcQ?R*6T^!i*Y$UH6Lc2|H55sMP8i;9LaEYNYXjm{F)^r2+H;PkBpu=Al#*pDJ zB%LN8S<t8(rbdXzpy%Ha<uE)h#9<F?^=WAy$Q{sF0WIc64QOaCBPJ-!AVy*Lk~N|< zhsG(qYY9!)pmH4Ianxlv$gyV$Hw8Hc(Q^pgBxrvh#>b33B=aD%Sde-J?m|!!MYbQ* z<toWQwHu@cDO#aQAjTC}<|W6MXO?8d7nh`D=EFkSLemyhgjrzJpoXSsI$V>ijU4T* z!QEMyZs<HXJY9gwT5!NYy^GQ7ftL$7y2a_KB{})YP~%~X#W9VCZmmJ;3&RaIgBSq` z7*Krz;lqrCuIxq_2|Z-U0*{fFph5)fFsP{&i8)BFG=c;nWDPe`@S8!Df%JgF4P19Y zq7$~f8tw{1&=fV~z84ep91kwyU_M1M-ZT?rBDC5l0I^|ygznNpHr-4UY&v`@2cC&= znhrJ*YC5z>j~D{AFoKOA!^0i-P$o9TpkBI>BW%zTH2rBEAD@z%lUkCQmmZJbBGlnY zs9sQ4ARaL{hs93ZgA3RcgB%F14#C}OWRqdbpb^1~Q80m4??Ngp*ungm`5m$zHQw3) zRO!c~4R=^T*F+;lH+VllFho6U1`WEl!veG@7_F>?Z32Ktw1o-kpbnDJkhPBxqftf` zAWN??PEs^9Fg4U<$jQ%3R{#^(6qrF3q~w<-<)nfq%MA@cYquSPf*d2^*9kZ|2D`?G zI6C>bT3O{}=7DxPmL`|L&kHg%1g&XBJunD#D5fp81A}mzMd|rL7NC{Y-~a}>2i)+0 z#W`q=GPur%%b?^a=z<5tp(cg~2xl4^AiPZIL?Mt9K*c+$2BK|bL&_nbMbtR`1ok7u zCl;U;&R{QEfFh%!7~yD?W+tgF10O{M9YMxeTV{cFjyO2gc!D>!;SE1S(9uM2L(vNb z*ivM0vI2V%DH_3i3(z^%kgN+@Rt#>#!DAMhiAncpkT>GsZ1kLNin_^*c#k3*3ifD9 zNj`Mq*#dTqG;WWQ=NCMMJnBkVViP>}6OSxl%cF6-ACfl7^99<{zTngnM^Jr^ShEhY zpNz~#@JJ*J*ty#Xe?j~KKP}e+v}_rY{y?W-gVP@<+kq1&dA>zDI0>3DkPl8G)2jpz zQX<n_;to~<rEhZL#{lAU&;=OaR+%333@OJP=-fV;1`|4X$-)fQfr6JM7N7;s;D|;D zK`&!41SJ9rA{<hkL*g3T7>BJ|Mx;8B?O+=a2@h?VHHn2B#7<+()0xOj2k56Y`R13U zCMM;i`ljaEWagE?7SkDm)>0K4nINsDvj8o{t|)d&EKWtzWQDoM$^y1X+7M(4I5c3j zff@9OR=5o824~b9XlRIJgJ&jaJ$Ej+vyEAup{+PZ*J$Vp(FiVwpv`#DVq!@B3|(dl zACxkKtlTBeQKn!sq2>prf_VrVka7{aZ_J^Jp<3OFQektXpvBF2T?Xr|Kob$V$tEDP zpcycr1XgFk7APYE-2&oILkrN#Vn_=Fw6qsoC?drfWI`E-UB&?=MIfsnr}9|9mhQqW zF@iOVEuf)F!0j;ekXOzbK{ruYK+npCFZD%>=H#*f?@Wke5X<h2jA5|>8Ggp$kL0od zuvXCNoaKoHFg>u53#8xxr)0QqEI`Y3A>|Ar8G%C#heamA<%tE*Lu0^Q6L8xCsoe-# zE{Z?)EzB(;-AzLab7=RPV8(&matG;gp*N9G&pSp>O^}X}VLW(b54~puTE~j&SWtkV z2N5)#;ddmYh=baL*&~J>XADnS=-HJ(!ot(ELOshE-T&|=lr@7>PJVJWIERDQ)k5cj zjX=Ya#YPs8A$$W310B#w_&VSr^(2snVk>>PC}dV6ttd4WJZk`!01p~K2GEldk#!h@ zPV%%g15I6EDPBQqfx$r!asW8QVZ|$GZ7?`H!(_k?f;kLSWue7{3984Oja;*`a1^wt z$0{45>oi2@1gC4HHZ$zVV?&s$;1Otn{j7d8v++eBWONOd<IpvN#u|(q^{l}$2hG`_ z)yycN2aW|$*jNzf9B8=@IaVE1;KB@s6&bj^3AYG;BtQ!B0Eqcum%~ay=vX2S-<m<x zx|V@QJ|H`WQLh+uFG@_w%u9F5uh2pa1Q>x1x4?hTprH}yVmn9*#wZ711G6A=z=_eq z!U9@IAqm0ieS{FGfdMW)EkNs{!Br1j5;cI3Zj1{6cT^GnfOPI51qif_1T8?2%2m+f zYG{nZPk4d46k0w(`U+rQf)WCW)<Z5Hgft5=w|ZMxqMS!g&@+(R2cf1R^_*bm78}At z3F2xC&>C!TrUwNi*k4fh!)i-{R$|)&4BJp^0b0+E8hRF%&_Pc#=(Zz63s{2!;v}g3 z&~!@BddLP@$Yxgy*x9xSZz38Ju)CB{Y$4j05NlBO%7Q$H)KDYnQs`zFa0v<DKnrp* z$Pl6(f^GAU1$=EUJbK}UI$9z{9c?5wkRf}35Stu8T{URI1z&Xww;B|~;FJW9SQ4WY zeyboPRxM$N*5Zp*s1-y9Bis(8oodi=TTA$QSA>_K%f%3B6`ro3784tikkSU4L9L;i zl=9Ociwlr8#UO1l0gEDbDj9(q%f)6ENIR8GEDgXLmC`bEQo+lBKn({&OVCla6~&O{ z*-$C4S&%J1*lf@-Gtn_IGBUwzH(0`srZoiF4~|}F60-!YX9X7_2pJ=2)ock`cnU73 zEn#QEBI^e?c!Ns}O(1TB1p^tIY%JjmL=ldFWOR`8z|IA^1<ZiP7_s&u@5;fb9xUN& zL~+_{01FHf?ZtTtg(ZBMC~i9;E4_*LBBZ^5={@)YO59dKy$7AyKs$(tSQi+%26%(E zRzYUE{R>j_a`RIlOL8%K?V#(MAZy)mIf^p37~*paTJsbX|DfWVNPpsPjDjMS6oVj* zQ|L?`C>(HXFCf)ilvzB8x!^_gkkZ}~v;-AWpTjO70^Mc>*=7hTZ@?MM5_E1YxI_Tu zdaw{Q?Ryg$PS9obW#ARknZ@z>1+X>JmayYv;pGTynF&0jL+v8cDs!mupaB4AeFIvv zh2lxL6^5w&W@5dAYzL&ifv)(r1T6|fu?p6^f%%4_q-+8TH{7W?IVZmuI(S54GBE{f zg#?*3WNs2%2SMwzOw#HzOHEtU`pnQ0vi1#9Eo2f^IfB*{Kr1;&#~EDz;i=FJVXGvJ z5ZBv))2bzW2^&HNTFAi$3lM1w=2cvE7OY@J8$7XuuWduv0j;lKi#0HkF@CEc1%e)y znj5rO4w}ZGjX_w=4YvyFJwk~MzY9nz!$HgS@H&bzw~$nZL(c&wGE(uB;YP5<Ca@L_ z-T;G+5W&lEOHEv5IEm(>mEj<Bk;`z<`bgBE2bJN_q;Cq{w{2-;23e+Th?GFV?KPxA z53l#|l;KA3Za*~Z!3$V;ibQX~;I#_5e1(?bMzHmYFy|wzKs&UX$Y@8l1GNkXt%F1j zPqh3+QBo$M3@0s_U@61F<u3YVQEo-~c_rXmpNw@3VKY2Npb=cu1t6fq>9H;VK{J5T zRUe?kqM^+{*zJR`@CL2#1h+dt&I2cCNSO*PN}+u;q)Bi?B)7TxWEz6^@<SHpVKzHa z57fnP3eNQ%mhjc2a5o~k9?8w1LrkIVD$ttCiee<E5?J7Y-B-9Tm;$*8)b=DQe85XN zpa%<L_7{xd!<bm&2JAb~A;;iFZ-$njV{gGjcb1@IZ!3zyi!9)4kdXWf8gB$^CM_aC z=e!!kdj=cEgYN~yu_qaH+A;~g$6+XXzW}~S5@$4%;1@hqj){RLv5tq<H+t46r!HBV zz}8;kbScT1h~P>Nkfp>ro8a;dOW0AnhHxK1Tx<zj=4T07*$EkjFoEvAF@#-}2y4<2 zllYO=Y(R4WWaR?1bA)zYFgQ7b7e`@cNP-JBND3iih%=xEi9%P0Lc|awb(SO~6~cF4 zkzyL5br_(NYtc${OVHuG;249)DN1aTS{gux-5`+$8l<;`FBe6aZvs6}1<4}VT!bZP zDJQt7f-5H>`$8;-j`<<qkwr=*qc6Pxr!LgO(k(GL6;xD)lz_Zw1e*FptD-@N(qdbq z2`+14+9|G};ma~XPJqS~n6iW~%Y@57aw@LCw1hhhGFJndECG+7W7f{5khV8QHpVal zchwAEdI@(OtZIfW0fM;J62A1(60-CX?n?X>Glo;ZYb_y(5_9Uu64zQw3}f(D$?(;c zIDKUaUtMVlUtNi$7~JY79Il{4;1PE@qW5=kt*6A|8N@ULw0(h?4Yq`@phR*XJZXU$ z#3m&?bt<kkljv^6QK7<DN#b-PBpDIwQo^+<bn_p<I3iq?!dF7V-41apDCdHM7j(ci zwD|^K2?@#tU`b+qM4%oe);okNQDRLZZha#t^<izbpeGC>s!w9m7{R&|zJ?JVW0vqW zj0hoE0S1ablA;PycR|W1P_1GKU$uxZ+zi^IMkEqKs}|7%3}Oqm8j{!;M6Vv*Q}c6! zQxl7lGmN1Z#~T`fmcA4lnwUUNUqDd-@*3;}hP1@wROsRxL$H@1YZt)V_u=B8rX^(Y zO-5pIMhR#UBy89bveFT?eunTe^Gb9S4D7(`CqVm-4UH_Ub2IZ&D@q`GjZIB8!5e)I zEsd;m6Dv?9ObpFH+l8SLMX8{}7C;kyU|nVg7GTNLoYY*TB}Jfk2kp}Z8Hf-zv;-}( ztSBzYC`wHQ9bBLTI)l*C%(^JG7<7go$W%j39YX`i5qlsXCg+#tL0t)wF*E`%RDu@J zh~*NNpf#G1!4M1Rjwx6j3R*Y`?VQ79kgFC$BjgwXZwmsgzQL^Np@*(QOFJ}eXv3gL zRR=z8cq#+D+90;UM(`|*aE{>NH3fCN4s41i==ezRt~5*dvQ8r`AqvjRhz2Vtx<N@9 zwID_fA`_6=uAsFrc!w}RDh%U6-52!C3h76KIvc);6|NP~V~s4~3q^6c(*!yW2BVFk zN4TT)z))RlXn?TDH3)w3igAi-uu(jyFCK3RQjnTgVw3`Lm~UpDb3S;_JT&}ZXFlO_ zmofBgcbL2Iy2lc3Jmgw7$kpS<DTt++zKIp+_9ImqsJ^p=E5>D-b5SbjKnRFe@TDR% zh)U?3jAKd)C|IB!Q_%8UoS71ogkVvD>+Um@tZ5E49O7i8;D-#Hxu=%+fDTlG?i{xS zEmy#6xv2?cVU>v)WLq!H5wLi{by_Woqd?cOK&%C)5=7EQavx+AD9A6^Fy1p0!pQ_D zA$TN0j+2K>Xo2esYzyHaW1%UCo)*Y~w)hvpS%B_shSVcyYv3$lM*|yzi~&W4p(T8A zFp`i3bYLDy2)3Np5;PbK?w!IVQ40X1rAf#+2pj|`RWD|F4(ddLV-Lw_s3W0EiNFm+ zu>UYi9()#q`f_;2BvDt_;x!1l|AScbW(lh9QJoHUs-Y!(p(`lhz@C8y7napS7~zF) zxtk??u_`RI;AM)XIdX8J6*2gH2U&Oqoz;LZKZThO%OhY<fxQCpBMBaYSb(y!4df4` zG7F#cur6u?og@y@PfU1XTh9i%Z2&SL1oJ0+S{x-9;l77@7uqDi=U(_qHb|4!8fknC zer_<#Qq0IB-X8e+GFZ&P=A&SS!`%)_j^LPs8cs~0!A*zEM1jw1hOJ%$ooI}j>_O!T z*alc4gxd|Zl8A7F6cf-uvt|JA_5`299d8ux;TY@z*(?khc`^odK#GkFK<!58u`rgP z1-li+U{&xzE2w@@L8@Z_Iz$J{<TYq{FT^*nUIwf^30jy7Zcl=&1A7l8=|lZwWQ5(R zpwb7&NRlPWND@v1VB<&uMVWae!6k{Xb`X52E!<sj7sC$4wgfGUg%sFOUzxxb7(!zN zmI!d!ZV9*5H7GbAyi5kPwF-4)pE!>g8Y1b0jvad>7H5Pd=D?0$v;?i$MU4eWSX)9D z)tVVV{Yb3y;TAv|5$4dO;A(B?q-PzFUz}M2I@Jl%>VYrng$F3A<&ahbsZOwf+2RUq z1E4qoS`i|3AK*)D;jVys*%Iw&Y61xlPgetaI4&UrAe|09YikB9*$I@HV7bst)3(?M zX_=_0xe1oLWGyXW3t^1Spd;WApBWi|7T!X$7(~X%0JJt1G%jys09suNO~VjLv`Wns z>^f*e3v#RiwD`d6(m{`rg!&v+CwToOTqk&*4c^~0GJr2j#pZZ$sQ^uqSk1<@#u98U zs0PET3l;&;M1t%Z*oIP^u7M<7{BDA@qtQdj$iM()zY2ON!E|AS5bWF$oNhA2elZ=Y z1)$+wzu<VJx)s`l##)LR85p4Kn?p4V6s5S$LN3JcdKztD6n3MNkpXC}F|@dXCrwaV z0H<gW15#ud8bQ}R;Y+#T3!O59ydlBsn37@$?o@#-!IeTxK*~Vn3Ph7<UNWdz8c>v4 zkXQs+aEI4lh9;;wpoOwyN=k5I8C*Z=0R_mJ4b(vcsYJK{s+9<*Tfmf}Xm-slD1qE` zj@RKJ&0wWa7sD>UGBSWK&&HVuAsGWg5*07OsU@zN@Q8tJs4y~sugHd51vAdb0JL%% zRG@)NFQkM3u@;&uVRbJ`nuRn|!56w%gL=4`d9a9pFOi1XXJi06vK3^Fp%L_?C9us% z_TjV19BMo$44w3>K`95C;^2#KVKzaMF~V?s#v=DyT=PnbDv=F_4Uyn7m~i-5!p(%b z8@!(^u_P5V43U~wQtY3X3f?XV^@{=Iv@>kwtC0yVz0ko8aNEZ>HP<sQ4RT<XkpXDM zF^(J$S@URW3Eh%_FN_S0kd217tYAHM=&mLs1Na(bSa_LQLWaN*Q9(Gw;QcOWH3DyI z;H`XcHXrcof>l}A#xtM|AEcH8^mb7A;gXmago4hS*TFWPVPpVbJq;UFGBN<Iat1XT z43UK3;~CIVKqCXtf?SX)BhUpbkP}^D>d^{lq)G_XKZkk%GDQsOs6eL@ph1gNL&MkI zA{h<Jm_`P$>n_1D2lgMq@eCA;K|Knb;~7Q<(8YPs1dq=LkUf0R77tP`g|Fj<J00v) zBhUsD@Jcaoz=1pi3ockmhR-(SaseZu!<UM}tTZ!#WGA%Xf>}s}?;yz@+$%ORfFGZU zFdx?TgjLO8Kf=r>#zPPbkjFEO42)1(PI!X@R9=CKFh|6lUto8F>Uv_Vhg1~c9vPzg z11+Y76i?99ZV2-xN~%Ne!w?aiIL9-L4B)G55rK;ydC<a;2z%fo4zQSmk7q!A1amt$ zIg*?RLBlYh(j8+w!^i->ycXsSaCri<0iFn9cEgeh5&nS`6VOa%&EV(~Qk0tNm!Fbq z2Hl@;4C;0kn^=GjBM0|GjV)mlgy3Vv5n_;HFfFkpBee)23Yi=%PAvclf$qZwP52ob zS%a^%1eGktmKK_zJ^J8jyMj!RGDA%rW5~o>UUEiePD(LM&=h<_SW+VBx-sx+&7fW4 zpcD!9si7f~2TVZfTrtK{j11t1q=Nhg3P5NoGz5DM<R;YgfMP1n2|2L2xZDCh_a8Kk z2U(5g4Dl7nTX?k@8X>C(B@E<)J@Qh^!L0~GBj_30*g_$%9DG8GJ>p0Y@HvK%R-2)b zF-r3p#iuDbuHgOi_SWc2p^*X^JckSIXoEV?C=0EO3_yoFU|VQ~ZUTjCt&9vnOP(Pm zizOs;L*vxQ0JP8;+z2&>$)FUa&@h8elz^rKQ33%{nS$yx9Q`|El#S^GjDd}nVb;gS z@E$YFm9Uc07}{V1yV}SAv<MpN9eAG(dHR@u3&2aQ;H?7G)k#JM(38rE3ls2k1KcR| z?lyb{G(6bRJY-}5Ix_*%(1EXjMp8_Yr;tyZ!|)VJ5+@Kope{M$G(51UkQ$_*_1QR6 z8MGuJ-racGu*Q%pNr;LFtjn*AKzHdt=MM0uD73l)fAFA<G+-P}2euWd48(65p=DS` z2Jki6@N@yo1&~Z(WB^+83`s+vwat)mI8X(JS&HL#3(`_7Xp)AMyx;<sG;a}FjzyYj zL@miOG9V?v5L}i;nsEe{W*HfP)|#W_8Y9rT<B-*Ju!seh)1Vv#j#3bVq=X4+#z10D z!$8N#0JLrz(@v1NNH!TmCfv!e33^Nl(jsQkVikRvmM_u)a(SsG>7Z@C&|Vd6tC0z) zZ;yGH9G3PCd`&k<3&_jxx)5~oFSzo6$q;i$8*<kY_aSmd2GB!+p=B28IZ&u(V4f#u zWB^)O4vsLG(~unv@&w6Fg&r{kIl2ydS{y7pqZF@roQms|IU@tm5^}umMN3t9EP<R= z1lb`AJ8;ejbcive{DudJks+kUH!^^&A2%`pt<?sXdT>?HwkxcUhR0smVR7KY=Zp+M ztGQ8p1nc}88Ng1VgPKh^ieW}0H&+b}prH?4qE3VhK}XVoZc&76fQNO<6%1hmxTYxm zSv+1%E&~loKpW7YBjjLCflUe^1s^D}!M$u`09rQ=s$mR~lpxpfcx;6oRtG7Uu;f(G zf^(E0M^E%d2B4MbAnU<V4RRXs=?XI0WCS^S4s#mC6mm#9;mCv>VFxt_7737Pb|VA$ zN_1H8fI|%AP~<R#F8Uxk{lLp}$dP;K?J)S#a+sy);YNHQ;c0}SuDQh%&+rzQH3RN~ z+yq{bgWCE;73A<$=q8|LQ;;SNBxFJ7@Inf5s0?YPqX~F}C!}P=Oc-V;6aTpU4Kf2; zK@M6D4@uKdr@`X}I=x1+Q}Gn!W+=nwc$|v6Acrp;#}>$-&?Yi1nYg-QFUUcwKu`k2 z$N;o>91?xd%~nPRpw-eKAtM9Onq)|kjtD?-fkUXkG;wu>mAlX)9li<~<~Jh)`0`^D z6IdG>8ZX5A6J`r?>23tMpxem63^L(Kgky1(?nb82!WnIuC(3c9hz5m;t1GV39lm53 z=6&>}Xk-9dtqUq%4Uv?91Dimx2#Re`J>nXK*y{r>rI5zhLFdAvL_8MjO(3WIfn%Mt z#73ZWHzzh{;4R(Zi&kO50}e5eLyZie$;QaQ9Q8C9!XZbXbce45g;|OoZp5clJf*ui z%CG>Qq64XPhcwAephKge9AsN;XqE}twP0ibTCbW|q+y_Au4!#xZ4A0U47`Zf05rad zrTT}TRSPl+6sT~InnMOl&^!uV9%O=N3=;J)TDS(-ycg!c6X-BpNFs%n2k349`#{4$ z2N#XojhUI5kcofHD#je80gmKMBt7Wa3ADNwuS*S0pcf?Jc2bZx>^3J%H(3}UZy`r= z6GBsPei3AOn~?$bfHncCfHpJXEhSh}3BHCH9^KH<4A^=jboax`P?%d%3qjYc8pMNV zRXkyhVEFo8xUoji<3qruJv3b*7iuu`j67lK!V_{js*wTe0ksH)uoXg{kn^B%D>R1s z-V;_I;4;w!rVv`%gH|J>MlYr}z~O}>b`3qD(^ZIofsLsm1q{5-gLI`}W}$~PG-RCg ztPvpt>1$xB1P2XBB|K<wsRV}&NF_XMaH#|b4oD>|aNzwEST02@=76Ohl)yoECM0x_ zrj_86_@GH{lyEmgF99ISD_}tdE#6^C12WABoehI89fpOtDfBd8aFYj|67jkcVwe+X zO&@YYIy0|CA==O=7T$seb&7~;L4!`wg?P>s-UR_U!^i-%JQ&p8GBkn85YsGmG&G9G zbCAA~frSNf8G>4=Ks94)GlNzI<8&s-y~H~XPh;5<rGUfcINYsd`1)g5aKRG^?9^I( zeLINPu{V!F>z7gdZe##jIt+;$Xgz3T06U-8$N;`(7|A8z!VQ+>v3U&EVuiMg;p=!| zW*8ZOra2*Ynn6Yd!AS%Z_Gk$opYbRSVl!yog&tju&w0sZ0iYnla{RtI%n&@S6_D0U zoQ+`kf?b$j(PPfY05ow2X#_*_0uf#&G`3*~S~QCiuNd|kA{Nm?*9{S2FaBmP$X2BJ z2W)YLuf1ysTFi^$XmH?wQUN?U7=fG(5+TB|_#3*0@I|}0qJ{`7aJO(l#uEq&q^2!K zd25C!Zb2;!Vv1Ws&=I(h;6vS`X=DgG02h+IpfW_2Xl8gzTab0QJqXr|rLZ-GuZlH+ zIt7+6L5>7PEYVKGUDkpu!S6JjMXe!xjVLbn;ZGGHe`76a4dE+7VFnu+!WM!Wnm~6j z7#V`rae`vX$Pl!A6EYBi2q=6dEy!lng4PheR1;yPp)qs^pNS=;VF6AYpl~PbFPP~l z<*Wsyhy-~L6y!L{S&-vE#jII8mQvOdYJ?%mWIkHy0W|?S9*um{iIE{_ZU$$<2l>s& z5VTklQplo(CbU6?#WsRvEPRb2EO^nAvXLQd%^^5CK`tR2$^?p7Lwr>cD3I`$u%Hu7 zQ9=qFG9ZV+(*fAgAQ8e&B~ZYEmQtcvh8{kIZNO8$LeI;@9e?<WR}*;gY6>clh$>z| z2eN{_1JVKwAP{9_2wKhw%Cv?s8KTNC6a2-i5x({!STDBX6}~(Z<`j6C8$t3r(N4ot zyc*%ls351|E?(g$uHteZ{xktH9DDH!UnB}M*vJsHt`ib1&`TbS3_(jEK|)4`pmmAh z;uWSIW-*Qu3}iE`0EDz-4dJJI!i+F71T7N;nQsm~WdNKuK#2rqI`-s>Y&df1Y7CvU zGlVW3#p5<m>1u+dbTx(!RDfIyDxh&Y0LM74A$-9e%$w**%E%D3&<tF<A}ImaRk&>< zSh~X3lp&c33Q2g78X1BXmw~JW$0kUQa3~WfT~XJQp;Zc?Si)Pnf~J;GN(gYsfE<SE zXpjhDrxGY#K}*q4EJKeL!ZzS3UD4MxA~jGw9YFzsRJuB47N;hIwo3XJfXHI#0Iey= zg~i53`K2YGBeC-mb5lV}E<rg1d~8c@4!SU84Qo+qT4r8qZfYKeHppt$wA9?>{1muZ zmS#G};B#tnQp-|vKsJDmhB2}LiIx_p<|Y<pr-Bw;f((Q$Wi>Pdy8vQSd<J-REa+%n zLrd@ySEx8#*vQBPWE#fsts#7w9mucHSOrl=hM?7Tpn|{<Nd_fHn4yOn?qOw+HON^P zQ!8vB5!=R!u+(H5V>`sY3RBR6ApGY<n1jy1fJ6osKf~5sgA4+B7M|`v>+>Lf2E{RG zA&?>H08&T}1uZ6nl($exwB(7p9NsuAHQCcA)7aG&z62D{B11!Clz|@tMj<aUgpU$K zo1mZtZIDa_b)}IZXk{D73x+WN8W|cx7P%UMyax>d<haFeKO|d2moQ-lFDQ0UT!0+B zV9UT`c;G04%t;e(HE1Di0Aj`rZK<ZA31mDJT4v+-1!Q{&bZG@*dx)V4Y^W3#T98(U zks)YF7$|WV8G<h2LUK8*PQz~>z6~OV@FiC;OU*4{)<UBS!X+umK}JI%L#u|MrCX@6 zVrmMRcLVzj5ic++i1QW14wPLYAkQFWb^@V-ZJ!9pu^<zOa{{)VB8KqgV6Xtio(K(L zfdKP0QAr2BSp=GTK)WuW*$=*~3uZ57M4}FK5(plU(U6G_aA^cT5)@`U+yjVMgqlxW z;KBE!APwz9=bH>ctHe-}47ex(r4)Dp0=J%|@PiZ}(7>~10G01Xu(5eF(4bzip;-m= z#0yi<i4Hg>Kn+2w*T60W=>j<n9?PJ`XrRn$h$Mqt%s`80Bk)2N$kI8C89k8kpkxS5 z6G&QMwH0RJ2Rg_Ur;9)?gq>T07GOw*8@WP`Pr~9J$kGUG?ty7RoAfjUtv(~lJw&++ zW(#_`i+U<4l3xs6Q($^9Tn4+m04at*0c2zdEtg;}LZ|VD9Nan#C!(xYLvtcdH^N#9 zq`DF2W&&=7*^A*=l-2;cV_~{5LKJoY1uoYbnj)6+<ID_@t7<`ejj$v@lxcSqcOh#- zcNl!R9Uh0F&ZlA~ap<`Trr=Y<Jbf~aTwNjO)M2_3b=@7BEB%7wv6+G4WY}r$c$^Gr zLlGaSh<zdG@r}A-4$Z~EhVd|+=#4$lGCtJYZDs^H6cV0`2s;l_8bh}5fh!sK3Ou;q zF-#?xz7vC?r5Mb~8k*1=624vzX1WEup$g6TSerVCKuOMlOw>c%3Tv&wOfxfsEPXLD zgfEhVZ)*g%J7HN8RzIQ}j8qXS7{bPeL96Rf1KP+Kx)cCp52)P2V{Tc1cM7Nycha-= zNzF?y$$$j~dhr4aR<Pso8)^nI3B_3GA`C<5b?lfvG>2${tvK+@FUn2K0c}qQbvlg< z;miGCfeBAMh~xxqU0`HTOSoYmCqZ`oLWH261uYyz4MLbLMEDkTEFr`+km=wFez%;& z64aY@!9{}+(t(0zpm}lp9YsSk(A7DRo+2!%!rDLZ<$oY^K(S$D2w(1pBm|p}KoWwj z$}<G5e*^a!VUn;^0u4XZ)*s~jM57c)j}ekDp{*p$mIi#48<NpbM?z92G#i0Eh}2sl z!e&S>3sNFr9H?$&h`RC(pBEr~ET}<9eJs#IH%MB5-P#V$nns486>Xqqn-M7FK)!*6 z7c4E~vkh+#3%*Vb7F?FFGer!|QNjx~f#b6e()WS(ui&f8;O0YD--0~__6pdKq<9Eo z0cz(8b>$mA=V3ci(8v(FN{yKC#M-ffFG7R)6W-)T2}aPhJ77-}ADr-B6*Rqox<1gd z12ln*l3p+)k9d3FT^?A>!A@;~`3UBAM9e`ACnnI~rX$rOumS~stR>7QaDf5}CL>rP zgxL*CCPd^`NI3xwG;4<BlFEWq@cp!~E|obbZ5ErFm?#?Q7#JCV>@zep*0hGQjSNA@ zVOA7_HO7M)LRO$l0F&c$K*!If#)HKny)h%u5wnmn%y{4Ul++xEFlgWrGKd-P8()%N zT2PQ$1d%ZXt?n^|3}u4la`MYj<sjpjAUVj{--h679ki$nQVxKYgn>#>(5w%1a5LUF zzC1G}H7`Ct8)AzE<g{-Kkh8%u5Md)j(DE(Bf?6X}Q_zxHkZNNi&>laqhP=e0qWp3s z9Xduv7T_&_NYcnwnHU>c=vY{1rda8N&k%r4;{}(Pf<wwP+0`gB#nl>omU%qnuyBw% zGsv_jk}^XBgc>a83>bozn1NG0C<4K;25Z`Y>NQaC7{X+X3_%O5z=M3|pb8DCyhpMS zGIao2|LF+2;1InPY5{58BWnPUG{QB2(ndUDfx01l=@rZw@Uj3}tQ#3ZPqhH05Dfzz z=+Y=y;zqU!bn9Vm5{@k;Ae%rvabyjks|gVrFq{U<)Ht06O3JXb1`1rFoR}Hljj$6v z{460$=FuF9q$Lw_ma~x|Xf+y2%t9?UG>4wc3QFx720HLHhv43tH<HOlnZ>TT$)JV2 zU_XEswV@bj0vX$b8wlk?DI-JB3N}y*f?5QN5p*j+w+S1?2jqe*vMx?e%!^0(0oH$q zg)r1?xRp?&p~6rKn?>eOgI#kW)*&p*%ZDzPHnfCv-;v#C0oIn6UxK0!R{TI(wD84i zFh@c|6c)}<F06b<3Se`nL9R%F4C`OR41@UzW||?SM+g(fXKFxlfH&A=>yms(nFx0< zD4`?!(;TV-)g?GpAxwr8g*eSM1<NB$HG;3W!{tAy$DkC{x7cD7YBVG|10eo{ma|~z z7=Z@)P|_<jB48m2;X+7k7MMXyb4>=D4ax#W@TGUexgKgZB*ySr0r5mK)ED3q8`3H< zf-k>=*$6N0;CTR>!KPp{T+6^`v?k{y78hqG$AiUS=9*~Qrh)tfDm_8*jFc=5jZt)f zOmVb_Z4E)3G+_i<FNYGq=tVQkWk_a&CsQFCCc#A;s&Qxz0neTqIzsPk0EGbdTUU)h zPC?fTx~aj?QOgii9fRvIYwMJJc*_BtL=2&)xFY8SLj!~=*JNu$CoLm{3E%*O9)OBd z6C`sOI%$D7*C1O>AQM8Z2CITtZ9=rw5KVBa!Hp1v)!<wRiFs^(wn)i`w00o2nxWbX z%Cn%rMfNa42PEkRfJ4e0p%E0;ko*I&7L*&&4Y5qgkB6uM<uOAiEenKxP)LKa8y-Cn zn?aez&`HY@p%vaji_e7J%wc2%TEB!Xt>Vo^hQ{z_Ajl}!GHU}TJ&^GbSEHGa?o>mQ zcweahz$&5Ip*I$Q8pjNIrMdA1r6u5&v`%qJij`G9<O1!a(zN)@l2q_v;SgB`uyk@p zVo`iaQDSCEF<976!A=3u1UJ^SEw)fJL}`FyHX+TSwt}z0w!~r~Si%s=D$itBS4e{s zV~D^Az7o_Nx{U%>2pEBua)PRVLzoP-vPP5&WV*!J2z*==mgXhMHK1q+E+N-w*lMwY zQfRBd2(<hZnsOk0cq1dw^3#f9EFlMu6G%iN1s_-x6i=Wgpdoy+4rB~i1a$ZahykfC zV9hi{%}%CYj0;LjT!W3{gMv#eGV_bUy{_aWP{RkDxj-vtG5rN{2SFzqnm`7CVKM1V zc6eiTV-CWNMw*cGC16Pi9QH)H5iPM%*@@uBDkK;YodBfdL6j4rqq{T;#R^0y!uFVv z9*Tybqb0zep-pnEL^u*Q$WFQ=VI$f!3dj_M8_md0j)n%%IRhFwG8N%SM4yS&1ZiXm z*;Yg&HwJh^&Pa*(jZZJiFD-~q%gIlK6|?X)*Rc49)+6x32-+in=4(h<2^E9&5+Dt2 z*xo?OeF3h)k(}xp;GLYC9BdXJkQ{6tACw7hUBi6?x||K%tTciz=_bW5hOlaYX1*~( zb}Ga#$aO<Na<C<mrwS5NpiMXUl5SkyfkXy$E&$CN&?ur_q?pC~#up@}xF%<!IzGTV z85SepsxBU>YXMq%j#Ae_6PFRFk%C;jkzJAD>DNF{6DHqi&`J=bUXU@4o9m2>D7Fc$ z&jhk5B_Gs6g{A}p$mkvUm8luTI4sQ)q>h%cCa5uQWMl|A<AwUR<$$_%u-+NmHpp^) z>f4qJvJKXggWCof$D_V&6(HMS-9NZ(kTr|cx2+On8?3(ww+*s{i2AmrfNX<xGU2vC z#=NO-TPnylSeF!T8+?qA%vL$B8~~~uk@~TqtcTuHOixAbDP~gAQv_W%Lu5}eJ+%bf zA+*F|Ay|Ugo+5nHjX89{9$pB8w!1)kijXBb&`KUwgF}l>(p`e5rwHAhL%z|lo??0` ztO*0(Tm$o<kr8NfO+_)5kOTJ#3HB5r1MFa9K(!Q{0dFf98G-idK;~qi`;(1~K$~_z zLO6Poqz9vMdMdaliPo763NA4;iucSf2H}##lGGqX?-IW22PG^(o-j0rx(n_bI0MyN zV8yV7JFuhx%jPun1fu&1+NT6<HbBxP!lk5m!pI1;IS3RZhM*G@!Tv()PSMaiCGegB zX#Wv)yki785z4|G5-fC#oGgTI5FKxbE69!<=t>&2LWd414Ka!U+5|+Ms4;^?4UVw| z8m2SEcmrrx4|P0a0r3pZQ3x7(2Qe}M+OR_v@4&YCfNvN;nmwmON=t)h8_*6TD)?pq z%4Nhj41E6)WtEGO5q#GYuF)A9CNRW^4SX{bW!^EgfF9IH$Kn`t`2uK41f$0d-{A!F z6LMn@xdtS=0fwi?Z35|lkZ&|vkJ}7qkDFqf(0bfpn|$L_D@uwIlS@zr$Us}esE~0D zp_{%aPb7w*kr))0g1Yqt+lax%;9;|r{CJd>Gicg|{DKhFt0KOUiZs?>1|4fKg6xK% zj|))7AK)%P9a|y2<RK*tN<e*E*q8*&1;(i3Ewpt(7RUv#aSFH#P)9{*>jLn&3~cNI z?gB{BL7#L09;<<kXTV*6I>JEPFaVF=z{WV>E}&;hOar9@*z7&b1t#=NiQrKsLj%y5 zqamoa0x^t?Oi+gdX&VjTp(aDvQWbb8ppM$n)(HWiwL)5ku*EK*iU@i93Dm_0VNf^U zssz+{H3zK+OpOnY2hA;K<`;ux;#2cdtjtVJjm>nd89>V8-EvFPauU;vA$lx8XDz|> zq(P-nG=U5Qt+TYUig!-T$w^8~&W_K?EG~hbmS6!oDySG-^W>#glz^sN3@t!c4uDT8 zi1&?8%Y%r4uB3zPxQO?S&&*3ntpJN_>cCeP7p0~p=a=R|%m7`L2VGqZY04m0pc=vV zO@l0lHeJ9J*kVvnSb%H;F(9k&;o{IvKGOWVp$V$DoQ+%q+{!@v#Zt>s^GaNUg5xt? zGXroQ01I*qsHVhcq#=GIed7~TQsRqJ(^894^O7NVY#ABBw{GL~Bw^2hqXorq&_){2 zGGO2MqSV~{vQ$iKVapxi){-2AhL-V|#zQT(W<W|$;rT@=uv0fIK+}!I7NDu5^8BI{ zP}(pyfZZ7fN-;1|@KOh8Lc&NH@Qv6Y<G@J*vUu9i0(!VDtdWHjU1srMci=w9!pIbI zq!AW9pk^s((<HLD!085>yFg=ssi{SY#i{WSVFR7a+@w+%&rl~hzo0TLw*)F{q=W4w z3@686*Ld(1#a321nR%(jB}JvlC5V$TEI_^{u;Ix9w95_>YG@mtjNrS=LFRzM%*Y6| z2OK;)h9m^r@Ps4;9i}ld0_}eWE!Q`MNy35|>qZ7c1B8zZ4G=y;-T;N`oCzcN)@CHD zppJ%2u0tn1!5#*c0MJ}QhD#tDqTpMxz^fyXN+Hzk&!~HH@Ou%mK?-UxVuO?s{9+Hd z-@tj#$Ov?DEoe9%9MT})!onB(-W2?{<J&N01izRA<^&@n&^}&hVu0S$Yh;QN)Z~XS zWUCWoM~)Hv-U^u2h8AX!RZZXk0DBu89+Y?<Vk64tDv+N+B{&%=1nXuikVin~krOxA zHeVUR_xr*F22!XQp~V9%xM1N!hKJz0v7m_)u^Y<>zCRe|3UJB*#R|e5<fjDq1}a!$ zfUS^%*@h)CKy4!@oZ;4C?$<IhgROglSq&}^Q9Vk9poVPVf`+p-1ENSoF63d2EKmVk zY-j}DR|G25G<CqutK7s2Bq2!go}3RpObT3iLYh|A3{Hu~sYoYb!Au41Z!R`6DakKM z%mJGN-r8ga>Fz*NkD)1=W=ptoSL@Q^ROo&v0-8)fDqXE}5{uGPlXCKtvmuusKsQn0 zvdYi^p~2NUEwiY&1ftK#2)@nRf`HAYU~M3)Q8a@xC@yPFauSP6T&)X=Qp=F6gM>J^ zjjL|}UT6q9LLCz3kiY|pg7!K=LcJir7@`{_1Zl|@loUaPKnseX`{TgJi-8RU3qm%= zp;ytMhysr^fqV-|iJ<#lAf+<Me7Jic3`@u;y^#@U`!%FuhN?m<8!%!Qk}7fS{W5}Y zj)pk|K8Oek49vY=xPllw4UDwu0I6Cvhx9aY>IBX5LUe+9CCF=vK-;uYLJ8e*gglRD z0Mi`O`NZWa=)MR&YsZ|N{AB3b9QaKx6b2UjL`#sjgHq9~z?YJd&a(vR1r-4y`3TqH z(`p7$?3!y0(&<)|3hS2;2npCJmmpp6Yw3*4;l(*D9YR(Hf-^EGK@*A^=n<BN(CPuS z!yYB7p^Ms#j6fUYAx$OdDey3pVbugil7|`Xq-PDfn+Fy=utl4=BG1Uk47$n=S`Xn$ z8?X~24Io#l1*ewyfsPae^>B=gKwIBYJc6EPp&o<z0+%JAJ61u)f)){i?;H*&f~|f; zyIlaiJU0ca1b5FscQz*_f;J|BPB=^|O(U=-0&;`1C1?*;v8fT#>J?K>(4GuPIS=02 zYXsVe4=$TPyOJRcLrq%<!wAMO*0ilCj?XVhEG$ipFDS_<N=;0O&n+!Ut%xtN(lIhM z(=j$R0+|eQ9(3=n5omjLMKO3AL}qe4NCxa`J1ZSC0}CB96Oj5`(7B8HAeR`MYU-Go zgHKD0_l<`PktC(2Lkt5QEp2XKqGM=a1l9(TPA-LRYX(Uhnj2Z5$%ASOgnlD)QzN*7 zq|!8q45(~3Ha7<!`55mT586xusWU)s0%Zwf3j^@Uk5I`(P%)BN0;*j>DnRQqj4e#S zbw0RnotToD2X!<=4(_G$qRbLhIZFe`DUiPL1)#wjh=VLNb&M^I&2+%Kox$Sq$)!c{ z#ffF95CvctTbjWf1yPckmx89m#J~XNDu@!$wj78FAcvV4Kq|<1-+0j3m&s)%5IG|w z(C%|cJ_YUi2GvnUMxb5a6~$16;8@fFZQ9U@kIzkl#6^jnm5zx4q=JnH&&q(p5@IIE z#U=)jnie4k-HQzhMbMdgCeUgZssK`*gCs%u%mjMACR7qMbOuf|V3T3n&@sjwK-<m1 zSs0WNpk*1DvNVKrlZ=ck;1x1x4>!oOhDeIR+kAsd42@Cp9@dpykiFc{MkB@<NJh}C zPNZ4jZQd}meB+agQWHy3p@{@iI)S#A<MkS>SR&3wLsL*XK(YqBkrBLqD+M&Fkza{w zJ8Z8BQdpq`EQz**X2($Mfmx3crIwI32ywo`GjK$jIk3Sba9Ng$+_E9b92f9GKcGRr zc<_(~(yD9H%z?NEy4MpF2e|fnl4dMug4GDN4HRN*CaBa;&4X6Gpo?5kQXQxy0aq24 zCXibIjEta14Zu=>H*ryA4z&nW+d+DMa64h0K9GY@6B#TUgGvYu107He0_uW6YklG@ zHpwqY%>&iVAm!j;c>jXbJW#a+uB?-D@{3{ZE6^T&6yF=d9DrbuWVb2UbdZ-pX~H)i zR=31w=9Q!t<t65TiqN#wB3S5?lJ<?v<8d1Z%U+-}LyAj^@+)!K2x(h`f`)JjXoQ@L z(R={4us9>XJU20~64nj}UDAURqM(WZ6ov4BB`G{D;pT(w(}GMFg3^t(b!lEoYEfEF zemN{KVP}1Tq`}DwGJ-{>&2Zx(HbW-qKt@|zgKOWk#LOI+&9HHNkTf=%Ar2wU=Wt70 zGp#{8xgqmoARDZ$^UIKZZVW$G03=H#`z>I0K&^*t7ywyd4Qk~j=jWBB7L~-8<b#%L zfRi>PFpS{`4}jEy90M&;5IG9c9f6J=lN2aMpiMkjtac4Z1_hFyb#ZD5s2vEdQH?=u zWt6lCJ-Lq>E-{1H1hp8t*&XC#YwP0F)a?AUG+1!J7HWbdLBU}R^*Ah9Lf0xn&$1$` z#50Fl=~@9_lN_9ynw^qa1j^^AMWCUh7G&iE$UP9pf<{lEA!Y*I;s=t%>R8AiG5M}6 z$S-ycE-^_f$S?LZG(>7_x?*)IWQhdGHQ-bS@+T}@(JK-B;c5wK9>VG{kY$9+KTv@S zvJx{~QJfC$wHH_B!OK9%Y8v9~Fac?V6fuz17!c2bXRcsgg>Ae9Nr7So+HZxYW9T_+ zq<PL1Yz64L$`UikIaHux1~LN<vdG%HqBuRZ1X^hu!*{xa<Uo$VDA>u*)@Bf!V3`TB zA_HU($PERh2sfaY@aS%UHXEQhjHIH)tfClX6R6z)DoS8$0U)jb9iEk1l$)6cYP9E< zmcaMNgErqn_Gp6?f`SF3v?IwC;OX2FG^@a=1Ke^iPAx%cKp2De;-eIC=t+Z|pa38I zfUpW&0q9vn)<c+TS~Ea04s=@wr0a<5cn0X`w<UPO+0X<uY+-1mYiR}wDMJGz15NAr zvVxK#6%->uWfAhKhIGhE1#tHe6ywltE_zSG7`~?;WF5o?aK&q63|e>r>Hr%eWT1-{ zU{wMvmNG$W5`s$%O(8CV?=r&LLj<=cF?xo^p!>5RkzxoRwE{T@><%ykQi{U!Yo@cI zYXFIsq7BFz!|%63coE@wkfnwOP%k5_#oc=`2Hk~)*AGahp!Qu1EpV+D1sMt&1`W=1 zLG71-wZO*V?d+h%9{lPon2(H%LF-?@1Mx^gkgzl|1|>0292*&fHXwsf_W`MgcwH0H z@6RkMb`5X~3eF6U2On(=>gX85H~1nM3fTz`k1#_6V|YxWnp9#5Nhq25#aNR_urabt zup^K0*@SkwL@><Fh+`~*4Uo-*cif?g4ID}!U&CDw-V+59LBv^6u`6i15@dwe7_<Wo zC9<)YVGP>e1qyphw5|ML2L=^`@&Y6{;T1C;2N^?VRZ$&Of-nPK<KZ*|eM>dO8Q|Nj zA<lq}DdP@nBO_x-;z4yr7Qz|u`Ua;n4AHj&K-`goFazE<z-fk&5w!7#>JIQpePF+U zHc%0YA0uPPJ|I*xD&X#bZ-2rY9#~R&P$j|)V$zxkwx~@*m;rAO;|ve%K?**T9TFVy zRw_;-z?&N|lYA<|8H7_Q#*P9=)PffML-P&%Y9D-I3ND3FVuiG#9$Nc>Dn%n>_~s&* zjiCAv5-1kX;TmJmjvdIbCp36qmU{<hnn6qh4Ny4gS;Lp08-q6IprkNJy8&K=z>Ema z1n-6fU*`a})`W;64edyLs2M@Y@W_DgXo2|(v-|-K3xkFcz@dqrO2KXlNX|quk#H(Q zF%ivwpzfp*G?L-_Q*b*DdM7VdXMwhf64jVMay;R*3AGW;*+km~3VBfMgVuvVYg_1w z-{4I1^wbiNIH)y_<R-}4bW~}uF`4Ok`9;tHHDmZT4cvi+aI+aiD=0C-!kTcQ4M~`o zh9F9Q_+m~xZU84EoJN7ovMxwX&4vXIbWvia2}ls)U~ABf8B87)Iwl}NP{@IU2E-}O z&xHpLdQ||=yoS(v2x}KA(*kA=+~9)J67cjAq)-4YNkqxKnArzCX_`Y#0G&<gsApZ8 zhg1|mP80~vGzE)7Jqzlk!aNHP43HpHz9cm#CmpH)zQ_?40nn~FmeRx&tPg4isH+V( zgK$-YQF)t!4ZtzH0E!TBi3PvW2Ie}<&_W%OL8LXP1sJ0&AhTg7L?TvKfSTlx<}P^F z0yIgFrLO?laS;sa0+fLV5+MC7a8Cu>0#&!7{JawIIsC>thOoo$EI};<0;^KN=Uzj) zPOzpn^wex)&{aN=1O#oD85x5XL4jI(h9ILs6{(RiXf-IPfsHI=4qg0W3|ch_sdS)5 zz(Nf=iH^2p(-6rUu0ENDuC9>9Ft8aiNcRRQEa7V<VeWx;bivL7xeuC|!M+4l6wnSG zvDQP@pF)rL#*8LY$fgjYO)~^7V~3iCSafO(THc8g&=6M}8H3hig2L7a6p&!=K-~{p zNkK6D@U1j8hOcUbg`SZyXo(>-f}tx-K@kkL8d5ky9YCy?A&Whs<v9EX5}194mL`w^ zIIveSZ6Vs55NlA@l!AN*%4fv76zf7#V>9S>6JkxlwtCbUzMK*6Z%AVpBb7o!gVam{ zUor|!T8Jg1#-K%dC`k((#h{QzSWaS;!WVABVijIH!}2(0tU|3IIzHicK&A-6M}ESJ zCD5`vG%uN=r&X8>NDWCyaRUuTYX+p^2sUH|I+UQ;#GnAOiV##F>KN!4S{hlW=j10P z=0JAUfEN=Qn;L0?WI*?S=A|Vjr<UXw<bzfOfn^OLN9P+GS*L-D?mXDCL`}#d8zbxF zoYLYF(2@P1HH{$E7LbJ?7-b;*@)%3R_&X?q4RI8DhRCHXxDEnspTI2K%uot9R9%p< z9nfK;-~lJ35*f7I5gI#?NP(8faMu`{Lb5zKcrc4(RC}P8PeJZyF-~#y3ywE509SLK zpzTZG(HhK)QjE<ZZ4qduMKuz%<iamF9>0+R&^8Nvu_Y{QVXika1}$|2mCc5hu;FF2 zM2=#uVF0K#<D_Tp4o)Uu*Td|9cS@k~2MZan9pIS6YqBAdkx)w<Q&QX#VcVFD@kFFK zR3%8Cqn>pTcta9#S`7^ls-fD$5_2-4=i?c}mm9)D4pyg`LmRdD{A3C?31q61p0!JA zGB_XlL8r%!;VTc}Mnj5IcoKtHg_ieGqr(7UD&$ftYcxAh%Y78h=1`?j_u*`gfx;27 zMaUA=9w*co!?{Js7__JolCMl5zBMuiUFHL+s}Vxb?!F<&Hc-+rG6pUC1F14H2Ce&p zG{&In(LxBdF<}YzCCCrRn}Tq*#NgM{z-)%*dn04$%?i*+u>^S$Guz|0n?N(n0<vBL zn%xN)g`*7yzv%|<esFuo$k+n9>k1rxpdf{X8urQzJ=pLzz(5Np(IOSJC=V1}hL-S3 z4K)Cv`GzRZLYhU;dfEa$dJ2nvOW5WfkSD=j1N)gY4?^rfZF*Tiat~2%#NO_*fOI#B z3uCN}F3?Iwl(5B>AfbT(^EFY9#?#_LtVM(dvyrg{q$WgU1ybS=-V}mGBYe03YQ7<6 zG(ycMF7)6QU}<ZC)=HuTBDmB6B^88cVAhiqfY=&Zpt1(m%mQ^Zi;av-(xB}u=w-BK zW+v8!rHMJ<yBHu+pex(WAj?tnb5g*KDTsuHrjDVRC1`zZMq+VBSz=CUDntUL1GI+N z7_*UOXb#!^0bT!x)UH9S!-VEbXmT>dS)hTMbs#U{X<|WF?ZJ~ATnp~@75wTSSowhN z4r9bYg5WtROv9m#DofA}(5ZPPMk%<OQI?QZVVEXB+fe8xfP4#W)F2iRLW2wDEF)vs z3PM9mGe}DimT(Zs6&4OAAQPe0Y+z|(jx*@e4wwz_;ZUdzkO~HDJ}80WHq{bt6x3+X zyyT+P+|;}hxCG1&w2B4hE<+1UEg-YNO{n5j;>|G$N<~%<H3QuGfjI$DYC}p9=t=@2 z{E5<v^2{p(wayYtV8f2M(w?CKLMhZe9*M;nVc`4&8CkT1j80+3mnB>!NGE7FM`{UN z2<9PpcM%qEkoF8BBcW767>Uo&C>Y65XyeTp+F2stK69u#sOzj59D{-!BW?0hOVUA0 zUm?8Ayb>J+13N9GrW<JUSFxcP;uZ-bW6%Xh6~&l$VPcwL4PNbu*lS=2J8vPsJTEsj z7qW656syp6^B5gGOL&P7+NJ<$JAqQTkqKypAEXZglff2treHUD2KWUV#CvA?WE!}- zLYj1-W)*ah61+?qxwu2={NXmi5E=m(1*QpN!5_?Rkaz~W8svOvel-ED#{+r7!VtAM zfW|y-yNy7jY48Rqnh!wsBMtxHHU-=sgqwoaoi%}9HDrmy7e*!qus!%Dpu2w{4QzyB z<T4nyBS1wm?5<&qo;b)6M0zF28(|9AD~OfnCh*%{aCrq*ViF2?7o4lxL3R-1Qt)0q z(5ORjY6)T-)C94Z3=w{yl!BIIh;=7uLl($%Xc7%hEdlS_0|`OOB9Mi|I2T;x!1Y3n zb1WzT?M?xgI3}QLT_Eiwn9IQ#5$<p!6VQz*pmx2H321Q^D3y?!-pwF3f|lk%ldDT= zPAaTCC)O`!5KT}|Ksh<!+K<FQF-FmhVjyAwlGqesXaF${q!Uy+JA(TCAm2IWK$lY! zYmz0zAjg~>s5xlU8YYPKV9>ZSG65|F14WJ@ENh@f94HMEo9G}7TSx?fCYDSP%f67U z0~v{I3FJ^?(ky`<&=HhMdWtrKXmZW8HgMFlwq^ir^h*VeO+xn*g2q^j4UIAlLCM<? zy45|?2+D&@7iAhlxsb*;W(|N?dxqGi3Gp{*85yX^H?%~^AQzMtF!$hYJDV7y^f3`S za5kMy5G%(Jw!+;5VnAvn6cXB#f)<GgTZ~*YGa>WAn8mdrr0<HM#}KZ^ngM*447}mt z>F44a5pRUl;sABLij52qEe=z26HUy?L=(``H%P&Q*p378ijfIy;hUi)RK~~zv;q#4 z%#BPyi`zhD5L^;H<$>Mj2^uGbx((i92=Wewq;AY{SCDIv%Trv2fVvL|L%{VEqUm7* zzn22$aA*$)>?M%jh<7V^K?)XkLhpot#*is)cft(7a3g#k8XCA5ZUmSA#Jdz%T7sU) zPS~X|129|)A6>@fQbX(mAUHz>)K>8ejz=11gSIKLHziGsAgdq<dm+dhx3Q=V1>!;l zt^RjRfsRd^fYvPH%rxK>297;514xUN$XGOXOi6Lg4Dt?!P9Hg@q!>c0R3ntK3RlRQ zfOH_6;F*^UD%t~zQVSAcYiUe~^Shx5s%B{Q?3j`g4BB4|D!Gk7;Xp)o1<etFG$FeT zY7S}svw-PBGs!i#prjHOQYb?XxIzkK5?B}1TfwmF224PA3lI^tkTRas2o6pyam_@E zVRwYJ@LoDJm%)rSG67vY0IKW2g)Sm-L0kY!TClD(E)PRSI5R;9R$IHLmiT1mLA&uL z@H++IrKJ&QkvzERVFX#POqx~ZQ1d}S3+lmVR>7@;_d}tcgcuC=BG_Zl%94<0kcY%w z^Gb>;L5Un1|DY8ssPPBRiU>QvTw;UG5^g-yH{eEmVo54==&RU2FVzWrMglZLpp5t6 ziVPzYT*g3KoZ#aed{c8h^U|P4eV8ED*}}pOQntW7W{S2IiBKRK8X?=_8WfxlP8_ht zZgeaxKrw16_(&WmX@cX8q%eh#_d^?eNIgvAs#QGQM<NY?HSw^`yg9mr6s4y6<)@^Y zAx3bF3_#(JfAY=905tsyY1+a<5xV5S#28wMg3SR1nURSxtk(}R8Y*N8U2BUZ1ig8{ z$ON=R7u4c{8v#qh(0UQ6It>8LavLIf1k(0`^emu_erVt$HJgl~tJ0AzfV&ICfaX@P zHz9*a$W3m-_Jc-?0uaqM^zjyB$o4j(y@TTfJ`>P7Wl#x#@CP_~8kv9=BSQ*OV`#aC zR^AZy0&>X%i(`0Bfvs7FTWn+kT7e8|FdG_MLYC1RnSc@rDD=RNA~_BrnFlhHV*)y8 zAH}Ce2GCs|V9z4r3}y|iOd#x0h&?EiawgF8gNcqHtP^t}M}yi7#5)C2b%6^fL^Tat zJq-_Qc>5V8eBl8C3jv}X51*ie_EkXR3eXY}b_ze-Zg4z<LK_jg(3C~Ab?`YfSkyw> z0|+}XqZVoh@gWJf1aqR!1a=-T!a`69h2kml0~1p6Kts}+A-SZoAQe1H4VkSoG6YRp z7aNuq6oA$%8G+g!h8B<`?1D=S4G`*0!Ae}M!54E|fseW~!l4qZ#ML@6rywH{ze=zY zSL>9_^vn|cD#1!ztt-GZUZrLbHLljh1)y~_cwGus0y?V>G=73tWdZ0wC|B$BqQrs> zyw;n7mAG0b=am%Y;8zJ&;%Z$`nwLz#_h2QU5X~#i#cyU}PF`uQE0)m)*cy6pjDr#v zJlmRBLhC+IS^&uynSj>2fC^6|6VS?UaNP%!gk@*c)B!nJCmu&P(gae!plJaQB|x-T zGvGS63OuM~WCU8tQEXxoA77lA4r=d#k1>WEodneh5;Zab9le`aq+y_Au4!#xZ45r* z0d!as=*TJqYikB@-HUqA70d<`&}HMG6Lvs{U_oY^jZ8pG%OMpPXhk(BcbI^tw;>EO z@PS+L#crNHu2zr(4q^JC#{s24%mK|1L0TtZ`%~kQ>VDX%wML+$xIm!~j~CDaY_Q!h z86y+WnrTS9fYu#@;{_&(6fZ_#TcE!5Om>At4*XO?^xEGPp4~Atf};qo5q*3Dw8R-) z2_m@x<O3rU=w=op6VNhch#$<MJ0YM&C-_(cP(g&^%m5=}Xmp|<V1^@QnL%3p*i18Y zC14upP#I{w0$Mta;u9n<K>Y$;DTq?X;R$oxN7g__dx|TO5A895Ew6^B0!#;h6C)^i zVNSpuk`^%2T?5SHA?XuzbOGwI5zyUGCa@LGc&vsrKS{AS6RUmJ;InjKVGgTjVW|hx z%Xq>U<yao*xkNC7p|jL*4}r2DILCs9#=)u41Z~GF=l~@2#E*8`Q5tLn3btk!ZagG( z;I7BxXrr_gXg3pF#z2ZJ*s5E&dGLrP#z+&8Nl-(<*&g}iD-+lnSh(59g$pPx;c+aU zz8>_DQ7pL*K063GdjT3Fp!K#W*$cK!3RY0SG8e%z0_98x&@3dxo_HgeO|ae`EK%XN ziD-K*VD^AdlL$77hvZ_&DHkxip_^FYfsJlAbblgL7*Eh6pPm8oBxn~D{QMac*cw{6 zJ<wqZcyfXA(YGLjF1JK2adDqA11@eso57%dgRVoy663JbPQdO&Jvzz+w(u41QmEJA zF2xfDDCb0h47X+=aI_(;A~)BxEjBblOurbJfL7ar4!MLH5TBS-47raARHH$TyTCjt z5qu_6Jmee|wBr{|%wg+5GNA`J8$!=w4lXf=TH=|UjB=!mt5IeOwsslp2vhL+jnFI! zqKr&HtAD|z73gF~kPvhd5)o)P?E)VV3<@;N87^~JTMV~m&>6uH&7kl>ZmfWoAwx4V zydMv88Q8H<2Do=kl2ZdR!5ibTO!in9Xo7mIctRC)&IVjN*ttl9TCj!9Si=_NTq1%J zTnr-Z^g}hCfa}1;p`jz>5J0dia2x_?0$m4<$EV;EHbBRQLGJUhFxRxUPRWnYFNI#$ zYXVya4Ymj5J0lZNv$-O*D7CmWr^E^@1Ufks%rF5hU<S1%LFck+80bKYLMUZq0_qon zq@e=PvI|BTW4T-uSHcI~<CR|ux(mi2KEOLU*d#tE*d#t6IoK>dDA+6>bYBwqj3ThR z!G0>uE6&JFgZm57P=F*lu)n~bK=BPo1m-?yMM8=*4GmKA<DoXY1_c{{Txc901X`41 z=ma?q4B^5|=pjm=KnJA((EVDt{BN3)AD@{AF%rA?!N+$Y3{TBV&Ig}R3uz$0Rzrgo zfISJ$V&Fqy!CYuV5T6?i4O8;tVdjEPA9B(HAH)SV6CCD=Ipv9!#qoLhpu^aprM?Ah zToP6S!CF$VaEIj|yjFwaAH{Tt{ou2)5ccP!=B1Zpz$}JNSAeC#enj=M5h(S7#G$DZ zN}-iH_*`X~k{=JT5-DQ9H>iORBm`Rw4wu}-3aCPu+aTQ~e1;nur{u>YG(!9fJ_8GC zE_6q*p|K{`ad7a;MvS$LkcEo`M#4c$@^m15P1q<YY$P1CE&*J4gBC!70?)|A(h#=W z*AlXy+{gs9NEuw~AgMBjsxkqs|IG$9rD2k=1b}_C4Z3I!I>!uNy$BhPGJ$map$%4~ z-Z1D6E)+My8?2Vly+@FQ0QM$mEEk&giMAgy5)L1UNAC+mm&X!s9C!&L)HtNMFxWAq z;5Y+?HLQ~WI!zNCyr8fIOF(^qV=NI%5aJyP2d!;I2|yzg&>B=wNe)}I299H})!?us zISL^I)R56qQ_wP2H2XkzkAc#Ni6x}ChIk!j4e|bj*n>I{ZV73<5FI~Q2f{&)1{c~y z8-r~i+!VG-77@p=c|r8F3ayQxF-^R!;7M!5x=_SGxG8AiEn2Wc&tyTwE~(bR$EaaZ z3+qe4GCO!BBq-q+!J`&x2l0^#w*+$_+!VAL7u{2k!~^#f+zGJcM08+63La=q1q}p3 zhV3Ao1{2Up2*nl_@dcnN*Ai41LIxL$Kzu_@Xo(tM4&_3Z%|UJg)G*KipP*%FrekPk z4L(C3qzo)(XlMi$OiBX@8JU8X8H0Kv#h^1ybwH=7gO1qGNlF8+F$WcB@O{Ve$@%%& znW-Rs;M-`7j35WmL&i`*8O#*4EErsvn1Ytyf(}RnZ8ioS^lxMx4?1E5q}j+6w89mt z%u>@9rVP3#8PvCgC<85Sg(w3pvjizKG6k)!1X~4K3JE&C*%%ZSkgx%rl@E5Fktt}o zAXKX<+y-M)(5S0*d}$KId;?QW9b*d<@TCIaYjz>Rprw6Kz2-;*su5N?CMJ+=)1|Oj zFtLExTnY+3h_fs-Z4u+W;AW&HC?l8}8tH&;A;?3hv_w{E0BS@-R6>sN&p~pesR_i9 zNjcd_(E_>;!Pv+;K0ht3I2C-$A~<+-%uEbGUIHa4XbX_I{v|Z!f%>M!7K%nX21W*; zyk!V#6hPTVrl7@s@H72Eo%d8LYj}&_6t>(B+`|QFMzoAgjf|k9`lg_>;J}qOs2>bf z1zEESZ8kwEaGM__Pq-0nWDM$9rlcm9m7sbSqt|PUujOy#1Uje&sjY7cTi%7kM<Cb1 z+kVt^raAV8KgfZwramaN!L>$k3Gv=H!qe~v84hcbL)w<6uq9A%??a0}P;7$y4lDJ% zNpXV(%o5Nrp_869N?ROeF|3aTOCzwBK1DVg8l%_+wI9;#hFJ_7tc6*O=3{tlLlY^K z!t8z$A17uI2cWe3L2-d-u*2L2-77^(U>h1BjDh+Wqm^q4Tlj^DW@yX7)Ce{g2MZ1~ zkCNgP@E{P<$OWRA4RQb|DU)OxXjBMd8rm?6DQw{vR_`DuTT<-9J?;Xsk5t#A4#a>0 z7so&hS%!noK826WKnzD7nIWs>0QH*jm7TCV-@$<n?x{kHFj(S+tXn0iq#$Mp1nxbG z%0*(wMBui;$}pJk$jO?x#z5efpp;fHn;<&^NDD_$<e?Y_83KR|dBClMltVCk;KK^U zmt=$nG2k{K$|RU=<b)sYQ4NSi$fFvtrVyyCu(E=VK!Wbs1~*Y`Q}eT}40H+-i%K#R zbF2(?Qj3c6i>!=vpu<nbI-uqhxRDHLCV?By#TJkj5U9b8Xrd!E(IDd<)(oJt=;KSk zmk5K~Xbkb7yEDv85Msufu-OENkx*Me&8=cXYlhr{#G=GpNc$AD{IH_fH?=q;GcP>= zB%WH5T2ySsfGGqu1*D_c(99ygpd>RlvntgXd>=EYxdLv!<`<L{m!uXHLxn*NYS1}D zFx5tI)sS8WOgU6sQwOrwG{2xEwWz2dAKWDY9a;|SO@J?mOv}v40XZMEU)~bj3<rs% zfG!>fwc<ftbWnf7%*47lF)g*E5~LPvh>->O)~}+}oXotu)FL!lP?O%w1axsFcwQs} zq|H!M$HWkPHCK8O<YFzD4WRbBnTd5uYEEKlULx2ILron})7;p|IybQbtQ~ACw8fp9 zTATrjPSBht_-04wxHPosU0ec6FL}kKMW7>@pmu|r-=Na~GE$SXK^I))B!c^Jpq;vq zTfLG&GN9?5lBE37yp+Tum_tB!m4S4Y7L_HIloq9;`PJOm4AibKPE7}GFE1`gElN#E z2lsctPPQ-rH~T?J7<|(j)HxQANJ|CZ2wI++nVtdeDnPVYf=x`%EK4mdD1lrwY6yx? zaI(lvtjI3~r7Td|fSP6ri93+Ti!%}nQXyw2K)Z<skPaazho$D^!F+9K0O|h~=j0a@ zz`SZ`0O{=|C8nh2<YeY%A{=FCXax31acXjYUP^vZN-C_kWoT#t?s29<wiu#F89`#a zurv{pS~YbHjUc_XOz<rtC8;IFP(K(NL3(XaiK5JOxQwwOIB8-wkc^EWw^kULLJyjR z4Fj5jmh(b-i%=OOQ}}XTQ_ull;GPbWHspn}hUOS~7XR89Q)84p4cPSKT_R%&J5Ly^ zN06IF&~XfGHlS_UMQX+wL+U0xdST10!3)lzWj|;+GkBN<DU?7?F){_MLxu(}<iG+G z(AgcJ<c2oRgT<N9ix6Rp*`4zXD&30mb76ME2J|uQgzOv#M<d7;ur3a6Pg%gs25qN> zE>5y$U|?W~kMc9kOV7znGBWc^cT7p~&x`km7QtcpIi<O&pxAc}2q*)s(l#>mOOFQ$ zWag#EBZ_rbD>rcQWvs~nDvhiHz&sO8hTH-u+Z@CORRf^(4USi^-SJT-hVkGl5i^tH zLD%?YCgx;TC6;97=fx-HrNpOzu4pSw2J;OvGa2+ti;MI#^OAE)Q&RQQlauvR5{t?+ z^Yl&h4D^$=we>UeAvYB;kZ7<KXyC@sKoeZ&WrC{L%&OFQh~o`Gq6I~n`9+x}m0<4} zYBDf@gDgHVB_%&kFS($AA>Q4`-^tM@KHf7P9-@Xuun_gk%Pes%gWG~o?Lv%dLcWIh zIjJ-a!&Rd?A?bqr5K4n+B{^i1GE0i};ddhFWe`ldu#`(E$_9_Yu%IF2Vq$$pta&7d zz<?V}?GPC3=Fu#MAej+V(orkXk?d4r!+z9Yc&&^P6d08!tPO%uV}jZhpn92L@rg(o z=!O$YDFdq$(O59dt%N%TH1Y;+Q-S<ml95>qZg&`AX?F~6-%&3vaD<bAYZ>-%ijNBM zgf?sqkwezi${joh2HIQ)>GgoN!GUKNGvmQM#dz>;pUk|p{P=?6)Y6oED+bUG3S5%l z;TcnqA;pH^^FoYFLA&TcCSn+*1MW0Jn!upVaFA{TXm1$QDW;&gJh(P19Z0_zG^_&` zggFXouMubi2FOIv1>(?iOF&%EkUwl>2d)>oeaRHGBdpj0a^)C864YfegBlSZ4<1SY z-!+CX3fkvHtmZR?U36gtG85Vp0Z~S#pbc73|3SJ%us%v~i6z`l@OU+3)g*XP398AE z@oFU1kd7I2VIasxT;tIukUk!YRiN=^*d4%N=UQ8%E%q^mZ}$P24fO`>8f_#Y$O;W3 zQ}~7-Q&13rf)Co`L$(((g&q$+cLo}MNS#s8P9aFQ(gYq#P>Ydl0f}G>K1e?tW;Qqk zQO!mVL1%Es8>Rs?2!gaw)fBW32(M%CcoTGAoOd$#<_6F#XKn$S!B|`p096l8X`nP~ zWD43jgyI6IjYg&>kRC5A6ugmx*aTz(blxZ_H4T0Zi>WDWaXBpV;1hIE<G^u<9J(mx znn4T$^_b(q`#It11-d#6WC6%yD7sP$F*PXS(~y^n&=4P=SsV{OH9fT`z5qH70NOl- z5-RB4z#1xsCa8vi14s)z+Ye3tVEHuAMmkV`8_6~dKN*^$sf8G33|bHXH!LMTJ~^=@ z8M++N6tp@7udCsaYGex9&jl(hz-u-%40J5aA={6!d(0p{9%h$ofOl|wKtNfRwUHC# zLRVzxloli>7DHFWnu2zQ5pWM^rx?f?MyBwcVy2+|TA;!lt!{uU3<fzIXYv89WCyK| z1v|nuz}wHzAU;01q9QRVv&_)YJRZG90S&T%ya8Eb3QDrp(Ay><eqxA^3JJznr-Am3 zA+75G-;``(s>u)^6<lHwAD@{I8ey>t2G@U}&07`4pm7N+hRpn8$bh~Tm=7J02dOAF zj1P`4N=<{_JPAIT-vDw_Vld(&J`<2OLu93{*73pdpq&t@De>i*B^mL>B`KNt@O^!t z^o6e9$N-xbEQ|k5;oH7U5$CCbBEiVi40a#^OvcC*bRPt09iNdY=uAsUHH**&9_K`N z38Ykoj*(#&X3!flFm!>7R=6(ovK6$83X=K|w!<9_V!)C*hPk*$GR+|C`Y?1rs!8}| z1xS@D4jp)^VO%<3c7WO@qz&TfrDib16Ej?fsu0ge8Aze4M|@gQVs5G-0|Ns9{vSd` literal 0 HcmV?d00001 diff --git a/contrib/Tetgen/LICENSE b/contrib/Tetgen/LICENSE new file mode 100644 index 0000000000..456b0bbe48 --- /dev/null +++ b/contrib/Tetgen/LICENSE @@ -0,0 +1,65 @@ +TetGen License +-------------- + +The software (TetGen) is licensed under the terms of the MIT license +with the following exceptions: + +Distribution of modified versions of this code is permissible UNDER +THE CONDITION THAT THIS CODE AND ANY MODIFICATIONS MADE TO IT IN THE +SAME SOURCE FILES tetgen.h AND tetgen.cxx REMAIN UNDER COPYRIGHT OF +THE ORIGINAL AUTHOR, BOTH SOURCE AND OBJECT CODE ARE MADE FREELY +AVAILABLE WITHOUT CHARGE, AND CLEAR NOTICE IS GIVEN OF THE +MODIFICATIONS. + +Distribution of this code for any commercial purpose is permissible +ONLY BY DIRECT ARRANGEMENT WITH THE COPYRIGHT OWNER. + +The full license text is reproduced below. + +This means that TetGen is no free software, but for private, research, +and educational purposes it can be used at absolutely no cost and +without further arrangements. + + +For details, see http://tetgen.berlios.de + +============================================================================== + +TetGen +A Quality Tetrahedral Mesh Generator and 3D Delaunay Triangulator +Version 1.3 (Released on June 13, 2004). + +Copyright 2002, 2004 Hang Si +Rathausstr. 9, 10178 Berlin, Germany +si@wias-berlin.de + +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: + +Distribution of modified versions of this code is permissible UNDER +THE CONDITION THAT THIS CODE AND ANY MODIFICATIONS MADE TO IT IN THE +SAME SOURCE FILES tetgen.h AND tetgen.cxx REMAIN UNDER COPYRIGHT OF +THE ORIGINAL AUTHOR, BOTH SOURCE AND OBJECT CODE ARE MADE FREELY +AVAILABLE WITHOUT CHARGE, AND CLEAR NOTICE IS GIVEN OF THE +MODIFICATIONS. + +Distribution of this code for any commercial purpose is permissible +ONLY BY DIRECT ARRANGEMENT WITH THE COPYRIGHT OWNER. + +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 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 +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +============================================================================== \ No newline at end of file diff --git a/contrib/Tetgen/Makefile b/contrib/Tetgen/Makefile new file mode 100644 index 0000000000..4d58517923 --- /dev/null +++ b/contrib/Tetgen/Makefile @@ -0,0 +1,53 @@ +# $Id: Makefile,v 1.1 2005-09-21 17:29:39 geuzaine Exp $ +# +# Copyright (C) 1997-2005 C. Geuzaine, J.-F. Remacle +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +# USA. +# +# Please report all bugs and problems to <gmsh@geuz.org>. + +include ../../variables + +LIB = ../../lib/libGmshTetgen.a +# Do not optimize (same as Triangle...) +CFLAGS = ${FLAGS} -DTETLIBRARY + +SRC = predicates.cxx tetgen.cxx +OBJ = ${SRC:.cxx=.o} + +.SUFFIXES: .o .cxx + +${LIB}: ${OBJ} + ${AR} ${LIB} ${OBJ} + ${RANLIB} ${LIB} + +.cxx.o: + ${CXX} ${CFLAGS} -c $< + +clean: + rm -f *.o + +depend: + (sed '/^# DO NOT DELETE THIS LINE/q' Makefile && \ + ${CXX} -MM ${CFLAGS} ${SRC} \ + ) >Makefile.new + cp Makefile Makefile.bak + cp Makefile.new Makefile + rm -f Makefile.new + +# DO NOT DELETE THIS LINE +predicates.o: predicates.cxx tetgen.h +tetgen.o: tetgen.cxx tetgen.h diff --git a/contrib/Tetgen/predicates.cxx b/contrib/Tetgen/predicates.cxx new file mode 100644 index 0000000000..e3dd38ae48 --- /dev/null +++ b/contrib/Tetgen/predicates.cxx @@ -0,0 +1,4176 @@ +/*****************************************************************************/ +/* */ +/* Routines for Arbitrary Precision Floating-point Arithmetic */ +/* and Fast Robust Geometric Predicates */ +/* (predicates.c) */ +/* */ +/* May 18, 1996 */ +/* */ +/* Placed in the public domain by */ +/* Jonathan Richard Shewchuk */ +/* School of Computer Science */ +/* Carnegie Mellon University */ +/* 5000 Forbes Avenue */ +/* Pittsburgh, Pennsylvania 15213-3891 */ +/* jrs@cs.cmu.edu */ +/* */ +/* This file contains C implementation of algorithms for exact addition */ +/* and multiplication of floating-point numbers, and predicates for */ +/* robustly performing the orientation and incircle tests used in */ +/* computational geometry. The algorithms and underlying theory are */ +/* described in Jonathan Richard Shewchuk. "Adaptive Precision Floating- */ +/* Point Arithmetic and Fast Robust Geometric Predicates." Technical */ +/* Report CMU-CS-96-140, School of Computer Science, Carnegie Mellon */ +/* University, Pittsburgh, Pennsylvania, May 1996. (Submitted to */ +/* Discrete & Computational Geometry.) */ +/* */ +/* This file, the paper listed above, and other information are available */ +/* from the Web page http://www.cs.cmu.edu/~quake/robust.html . */ +/* */ +/*****************************************************************************/ + +/*****************************************************************************/ +/* */ +/* Using this code: */ +/* */ +/* First, read the short or long version of the paper (from the Web page */ +/* above). */ +/* */ +/* Be sure to call exactinit() once, before calling any of the arithmetic */ +/* functions or geometric predicates. Also be sure to turn on the */ +/* optimizer when compiling this file. */ +/* */ +/* */ +/* Several geometric predicates are defined. Their parameters are all */ +/* points. Each point is an array of two or three floating-point */ +/* numbers. The geometric predicates, described in the papers, are */ +/* */ +/* orient2d(pa, pb, pc) */ +/* orient2dfast(pa, pb, pc) */ +/* orient3d(pa, pb, pc, pd) */ +/* orient3dfast(pa, pb, pc, pd) */ +/* incircle(pa, pb, pc, pd) */ +/* incirclefast(pa, pb, pc, pd) */ +/* insphere(pa, pb, pc, pd, pe) */ +/* inspherefast(pa, pb, pc, pd, pe) */ +/* */ +/* Those with suffix "fast" are approximate, non-robust versions. Those */ +/* without the suffix are adaptive precision, robust versions. There */ +/* are also versions with the suffices "exact" and "slow", which are */ +/* non-adaptive, exact arithmetic versions, which I use only for timings */ +/* in my arithmetic papers. */ +/* */ +/* */ +/* An expansion is represented by an array of floating-point numbers, */ +/* sorted from smallest to largest magnitude (possibly with interspersed */ +/* zeros). The length of each expansion is stored as a separate integer, */ +/* and each arithmetic function returns an integer which is the length */ +/* of the expansion it created. */ +/* */ +/* Several arithmetic functions are defined. Their parameters are */ +/* */ +/* e, f Input expansions */ +/* elen, flen Lengths of input expansions (must be >= 1) */ +/* h Output expansion */ +/* b Input scalar */ +/* */ +/* The arithmetic functions are */ +/* */ +/* grow_expansion(elen, e, b, h) */ +/* grow_expansion_zeroelim(elen, e, b, h) */ +/* expansion_sum(elen, e, flen, f, h) */ +/* expansion_sum_zeroelim1(elen, e, flen, f, h) */ +/* expansion_sum_zeroelim2(elen, e, flen, f, h) */ +/* fast_expansion_sum(elen, e, flen, f, h) */ +/* fast_expansion_sum_zeroelim(elen, e, flen, f, h) */ +/* linear_expansion_sum(elen, e, flen, f, h) */ +/* linear_expansion_sum_zeroelim(elen, e, flen, f, h) */ +/* scale_expansion(elen, e, b, h) */ +/* scale_expansion_zeroelim(elen, e, b, h) */ +/* compress(elen, e, h) */ +/* */ +/* All of these are described in the long version of the paper; some are */ +/* described in the short version. All return an integer that is the */ +/* length of h. Those with suffix _zeroelim perform zero elimination, */ +/* and are recommended over their counterparts. The procedure */ +/* fast_expansion_sum_zeroelim() (or linear_expansion_sum_zeroelim() on */ +/* processors that do not use the round-to-even tiebreaking rule) is */ +/* recommended over expansion_sum_zeroelim(). Each procedure has a */ +/* little note next to it (in the code below) that tells you whether or */ +/* not the output expansion may be the same array as one of the input */ +/* expansions. */ +/* */ +/* */ +/* If you look around below, you'll also find macros for a bunch of */ +/* simple unrolled arithmetic operations, and procedures for printing */ +/* expansions (commented out because they don't work with all C */ +/* compilers) and for generating random floating-point numbers whose */ +/* significand bits are all random. Most of the macros have undocumented */ +/* requirements that certain of their parameters should not be the same */ +/* variable; for safety, better to make sure all the parameters are */ +/* distinct variables. Feel free to send email to jrs@cs.cmu.edu if you */ +/* have questions. */ +/* */ +/*****************************************************************************/ + +#include <stdio.h> +#include <stdlib.h> +#include <math.h> +#ifdef CPU86 +#include <float.h> +#endif /* CPU86 */ +#ifdef LINUX +#include <fpu_control.h> +#endif /* LINUX */ + +#include "tetgen.h" // Defines the symbol REAL (float or double). + +/* On some machines, the exact arithmetic routines might be defeated by the */ +/* use of internal extended precision floating-point registers. Sometimes */ +/* this problem can be fixed by defining certain values to be volatile, */ +/* thus forcing them to be stored to memory and rounded off. This isn't */ +/* a great solution, though, as it slows the arithmetic down. */ +/* */ +/* To try this out, write "#define INEXACT volatile" below. Normally, */ +/* however, INEXACT should be defined to be nothing. ("#define INEXACT".) */ + +#define INEXACT /* Nothing */ +/* #define INEXACT volatile */ + +/* #define REAL double */ /* float or double */ +#define REALPRINT doubleprint +#define REALRAND doublerand +#define NARROWRAND narrowdoublerand +#define UNIFORMRAND uniformdoublerand + +/* Which of the following two methods of finding the absolute values is */ +/* fastest is compiler-dependent. A few compilers can inline and optimize */ +/* the fabs() call; but most will incur the overhead of a function call, */ +/* which is disastrously slow. A faster way on IEEE machines might be to */ +/* mask the appropriate bit, but that's difficult to do in C. */ + +#define Absolute(a) ((a) >= 0.0 ? (a) : -(a)) +/* #define Absolute(a) fabs(a) */ + +/* Many of the operations are broken up into two pieces, a main part that */ +/* performs an approximate operation, and a "tail" that computes the */ +/* roundoff error of that operation. */ +/* */ +/* The operations Fast_Two_Sum(), Fast_Two_Diff(), Two_Sum(), Two_Diff(), */ +/* Split(), and Two_Product() are all implemented as described in the */ +/* reference. Each of these macros requires certain variables to be */ +/* defined in the calling routine. The variables `bvirt', `c', `abig', */ +/* `_i', `_j', `_k', `_l', `_m', and `_n' are declared `INEXACT' because */ +/* they store the result of an operation that may incur roundoff error. */ +/* The input parameter `x' (or the highest numbered `x_' parameter) must */ +/* also be declared `INEXACT'. */ + +#define Fast_Two_Sum_Tail(a, b, x, y) \ + bvirt = x - a; \ + y = b - bvirt + +#define Fast_Two_Sum(a, b, x, y) \ + x = (REAL) (a + b); \ + Fast_Two_Sum_Tail(a, b, x, y) + +#define Fast_Two_Diff_Tail(a, b, x, y) \ + bvirt = a - x; \ + y = bvirt - b + +#define Fast_Two_Diff(a, b, x, y) \ + x = (REAL) (a - b); \ + Fast_Two_Diff_Tail(a, b, x, y) + +#define Two_Sum_Tail(a, b, x, y) \ + bvirt = (REAL) (x - a); \ + avirt = x - bvirt; \ + bround = b - bvirt; \ + around = a - avirt; \ + y = around + bround + +#define Two_Sum(a, b, x, y) \ + x = (REAL) (a + b); \ + Two_Sum_Tail(a, b, x, y) + +#define Two_Diff_Tail(a, b, x, y) \ + bvirt = (REAL) (a - x); \ + avirt = x + bvirt; \ + bround = bvirt - b; \ + around = a - avirt; \ + y = around + bround + +#define Two_Diff(a, b, x, y) \ + x = (REAL) (a - b); \ + Two_Diff_Tail(a, b, x, y) + +#define Split(a, ahi, alo) \ + c = (REAL) (splitter * a); \ + abig = (REAL) (c - a); \ + ahi = c - abig; \ + alo = a - ahi + +#define Two_Product_Tail(a, b, x, y) \ + Split(a, ahi, alo); \ + Split(b, bhi, blo); \ + err1 = x - (ahi * bhi); \ + err2 = err1 - (alo * bhi); \ + err3 = err2 - (ahi * blo); \ + y = (alo * blo) - err3 + +#define Two_Product(a, b, x, y) \ + x = (REAL) (a * b); \ + Two_Product_Tail(a, b, x, y) + +/* Two_Product_Presplit() is Two_Product() where one of the inputs has */ +/* already been split. Avoids redundant splitting. */ + +#define Two_Product_Presplit(a, b, bhi, blo, x, y) \ + x = (REAL) (a * b); \ + Split(a, ahi, alo); \ + err1 = x - (ahi * bhi); \ + err2 = err1 - (alo * bhi); \ + err3 = err2 - (ahi * blo); \ + y = (alo * blo) - err3 + +/* Two_Product_2Presplit() is Two_Product() where both of the inputs have */ +/* already been split. Avoids redundant splitting. */ + +#define Two_Product_2Presplit(a, ahi, alo, b, bhi, blo, x, y) \ + x = (REAL) (a * b); \ + err1 = x - (ahi * bhi); \ + err2 = err1 - (alo * bhi); \ + err3 = err2 - (ahi * blo); \ + y = (alo * blo) - err3 + +/* Square() can be done more quickly than Two_Product(). */ + +#define Square_Tail(a, x, y) \ + Split(a, ahi, alo); \ + err1 = x - (ahi * ahi); \ + err3 = err1 - ((ahi + ahi) * alo); \ + y = (alo * alo) - err3 + +#define Square(a, x, y) \ + x = (REAL) (a * a); \ + Square_Tail(a, x, y) + +/* Macros for summing expansions of various fixed lengths. These are all */ +/* unrolled versions of Expansion_Sum(). */ + +#define Two_One_Sum(a1, a0, b, x2, x1, x0) \ + Two_Sum(a0, b , _i, x0); \ + Two_Sum(a1, _i, x2, x1) + +#define Two_One_Diff(a1, a0, b, x2, x1, x0) \ + Two_Diff(a0, b , _i, x0); \ + Two_Sum( a1, _i, x2, x1) + +#define Two_Two_Sum(a1, a0, b1, b0, x3, x2, x1, x0) \ + Two_One_Sum(a1, a0, b0, _j, _0, x0); \ + Two_One_Sum(_j, _0, b1, x3, x2, x1) + +#define Two_Two_Diff(a1, a0, b1, b0, x3, x2, x1, x0) \ + Two_One_Diff(a1, a0, b0, _j, _0, x0); \ + Two_One_Diff(_j, _0, b1, x3, x2, x1) + +#define Four_One_Sum(a3, a2, a1, a0, b, x4, x3, x2, x1, x0) \ + Two_One_Sum(a1, a0, b , _j, x1, x0); \ + Two_One_Sum(a3, a2, _j, x4, x3, x2) + +#define Four_Two_Sum(a3, a2, a1, a0, b1, b0, x5, x4, x3, x2, x1, x0) \ + Four_One_Sum(a3, a2, a1, a0, b0, _k, _2, _1, _0, x0); \ + Four_One_Sum(_k, _2, _1, _0, b1, x5, x4, x3, x2, x1) + +#define Four_Four_Sum(a3, a2, a1, a0, b4, b3, b1, b0, x7, x6, x5, x4, x3, x2, \ + x1, x0) \ + Four_Two_Sum(a3, a2, a1, a0, b1, b0, _l, _2, _1, _0, x1, x0); \ + Four_Two_Sum(_l, _2, _1, _0, b4, b3, x7, x6, x5, x4, x3, x2) + +#define Eight_One_Sum(a7, a6, a5, a4, a3, a2, a1, a0, b, x8, x7, x6, x5, x4, \ + x3, x2, x1, x0) \ + Four_One_Sum(a3, a2, a1, a0, b , _j, x3, x2, x1, x0); \ + Four_One_Sum(a7, a6, a5, a4, _j, x8, x7, x6, x5, x4) + +#define Eight_Two_Sum(a7, a6, a5, a4, a3, a2, a1, a0, b1, b0, x9, x8, x7, \ + x6, x5, x4, x3, x2, x1, x0) \ + Eight_One_Sum(a7, a6, a5, a4, a3, a2, a1, a0, b0, _k, _6, _5, _4, _3, _2, \ + _1, _0, x0); \ + Eight_One_Sum(_k, _6, _5, _4, _3, _2, _1, _0, b1, x9, x8, x7, x6, x5, x4, \ + x3, x2, x1) + +#define Eight_Four_Sum(a7, a6, a5, a4, a3, a2, a1, a0, b4, b3, b1, b0, x11, \ + x10, x9, x8, x7, x6, x5, x4, x3, x2, x1, x0) \ + Eight_Two_Sum(a7, a6, a5, a4, a3, a2, a1, a0, b1, b0, _l, _6, _5, _4, _3, \ + _2, _1, _0, x1, x0); \ + Eight_Two_Sum(_l, _6, _5, _4, _3, _2, _1, _0, b4, b3, x11, x10, x9, x8, \ + x7, x6, x5, x4, x3, x2) + +/* Macros for multiplying expansions of various fixed lengths. */ + +#define Two_One_Product(a1, a0, b, x3, x2, x1, x0) \ + Split(b, bhi, blo); \ + Two_Product_Presplit(a0, b, bhi, blo, _i, x0); \ + Two_Product_Presplit(a1, b, bhi, blo, _j, _0); \ + Two_Sum(_i, _0, _k, x1); \ + Fast_Two_Sum(_j, _k, x3, x2) + +#define Four_One_Product(a3, a2, a1, a0, b, x7, x6, x5, x4, x3, x2, x1, x0) \ + Split(b, bhi, blo); \ + Two_Product_Presplit(a0, b, bhi, blo, _i, x0); \ + Two_Product_Presplit(a1, b, bhi, blo, _j, _0); \ + Two_Sum(_i, _0, _k, x1); \ + Fast_Two_Sum(_j, _k, _i, x2); \ + Two_Product_Presplit(a2, b, bhi, blo, _j, _0); \ + Two_Sum(_i, _0, _k, x3); \ + Fast_Two_Sum(_j, _k, _i, x4); \ + Two_Product_Presplit(a3, b, bhi, blo, _j, _0); \ + Two_Sum(_i, _0, _k, x5); \ + Fast_Two_Sum(_j, _k, x7, x6) + +#define Two_Two_Product(a1, a0, b1, b0, x7, x6, x5, x4, x3, x2, x1, x0) \ + Split(a0, a0hi, a0lo); \ + Split(b0, bhi, blo); \ + Two_Product_2Presplit(a0, a0hi, a0lo, b0, bhi, blo, _i, x0); \ + Split(a1, a1hi, a1lo); \ + Two_Product_2Presplit(a1, a1hi, a1lo, b0, bhi, blo, _j, _0); \ + Two_Sum(_i, _0, _k, _1); \ + Fast_Two_Sum(_j, _k, _l, _2); \ + Split(b1, bhi, blo); \ + Two_Product_2Presplit(a0, a0hi, a0lo, b1, bhi, blo, _i, _0); \ + Two_Sum(_1, _0, _k, x1); \ + Two_Sum(_2, _k, _j, _1); \ + Two_Sum(_l, _j, _m, _2); \ + Two_Product_2Presplit(a1, a1hi, a1lo, b1, bhi, blo, _j, _0); \ + Two_Sum(_i, _0, _n, _0); \ + Two_Sum(_1, _0, _i, x2); \ + Two_Sum(_2, _i, _k, _1); \ + Two_Sum(_m, _k, _l, _2); \ + Two_Sum(_j, _n, _k, _0); \ + Two_Sum(_1, _0, _j, x3); \ + Two_Sum(_2, _j, _i, _1); \ + Two_Sum(_l, _i, _m, _2); \ + Two_Sum(_1, _k, _i, x4); \ + Two_Sum(_2, _i, _k, x5); \ + Two_Sum(_m, _k, x7, x6) + +/* An expansion of length two can be squared more quickly than finding the */ +/* product of two different expansions of length two, and the result is */ +/* guaranteed to have no more than six (rather than eight) components. */ + +#define Two_Square(a1, a0, x5, x4, x3, x2, x1, x0) \ + Square(a0, _j, x0); \ + _0 = a0 + a0; \ + Two_Product(a1, _0, _k, _1); \ + Two_One_Sum(_k, _1, _j, _l, _2, x1); \ + Square(a1, _j, _1); \ + Two_Two_Sum(_j, _1, _l, _2, x5, x4, x3, x2) + +/* splitter = 2^ceiling(p / 2) + 1. Used to split floats in half. */ +static REAL splitter; +static REAL epsilon; /* = 2^(-p). Used to estimate roundoff errors. */ +/* A set of coefficients used to calculate maximum roundoff errors. */ +static REAL resulterrbound; +static REAL ccwerrboundA, ccwerrboundB, ccwerrboundC; +static REAL o3derrboundA, o3derrboundB, o3derrboundC; +static REAL iccerrboundA, iccerrboundB, iccerrboundC; +static REAL isperrboundA, isperrboundB, isperrboundC; + +/*****************************************************************************/ +/* */ +/* doubleprint() Print the bit representation of a double. */ +/* */ +/* Useful for debugging exact arithmetic routines. */ +/* */ +/*****************************************************************************/ + +/* +void doubleprint(number) +double number; +{ + unsigned long long no; + unsigned long long sign, expo; + int exponent; + int i, bottomi; + + no = *(unsigned long long *) &number; + sign = no & 0x8000000000000000ll; + expo = (no >> 52) & 0x7ffll; + exponent = (int) expo; + exponent = exponent - 1023; + if (sign) { + printf("-"); + } else { + printf(" "); + } + if (exponent == -1023) { + printf( + "0.0000000000000000000000000000000000000000000000000000_ ( )"); + } else { + printf("1."); + bottomi = -1; + for (i = 0; i < 52; i++) { + if (no & 0x0008000000000000ll) { + printf("1"); + bottomi = i; + } else { + printf("0"); + } + no <<= 1; + } + printf("_%d (%d)", exponent, exponent - 1 - bottomi); + } +} +*/ + +/*****************************************************************************/ +/* */ +/* floatprint() Print the bit representation of a float. */ +/* */ +/* Useful for debugging exact arithmetic routines. */ +/* */ +/*****************************************************************************/ + +/* +void floatprint(number) +float number; +{ + unsigned no; + unsigned sign, expo; + int exponent; + int i, bottomi; + + no = *(unsigned *) &number; + sign = no & 0x80000000; + expo = (no >> 23) & 0xff; + exponent = (int) expo; + exponent = exponent - 127; + if (sign) { + printf("-"); + } else { + printf(" "); + } + if (exponent == -127) { + printf("0.00000000000000000000000_ ( )"); + } else { + printf("1."); + bottomi = -1; + for (i = 0; i < 23; i++) { + if (no & 0x00400000) { + printf("1"); + bottomi = i; + } else { + printf("0"); + } + no <<= 1; + } + printf("_%3d (%3d)", exponent, exponent - 1 - bottomi); + } +} +*/ + +/*****************************************************************************/ +/* */ +/* expansion_print() Print the bit representation of an expansion. */ +/* */ +/* Useful for debugging exact arithmetic routines. */ +/* */ +/*****************************************************************************/ + +/* +void expansion_print(elen, e) +int elen; +REAL *e; +{ + int i; + + for (i = elen - 1; i >= 0; i--) { + REALPRINT(e[i]); + if (i > 0) { + printf(" +\n"); + } else { + printf("\n"); + } + } +} +*/ + +/*****************************************************************************/ +/* */ +/* doublerand() Generate a double with random 53-bit significand and a */ +/* random exponent in [0, 511]. */ +/* */ +/*****************************************************************************/ + +/* +double doublerand() +{ + double result; + double expo; + long a, b, c; + long i; + + a = random(); + b = random(); + c = random(); + result = (double) (a - 1073741824) * 8388608.0 + (double) (b >> 8); + for (i = 512, expo = 2; i <= 131072; i *= 2, expo = expo * expo) { + if (c & i) { + result *= expo; + } + } + return result; +} +*/ + +/*****************************************************************************/ +/* */ +/* narrowdoublerand() Generate a double with random 53-bit significand */ +/* and a random exponent in [0, 7]. */ +/* */ +/*****************************************************************************/ + +/* +double narrowdoublerand() +{ + double result; + double expo; + long a, b, c; + long i; + + a = random(); + b = random(); + c = random(); + result = (double) (a - 1073741824) * 8388608.0 + (double) (b >> 8); + for (i = 512, expo = 2; i <= 2048; i *= 2, expo = expo * expo) { + if (c & i) { + result *= expo; + } + } + return result; +} +*/ + +/*****************************************************************************/ +/* */ +/* uniformdoublerand() Generate a double with random 53-bit significand. */ +/* */ +/*****************************************************************************/ + +/* +double uniformdoublerand() +{ + double result; + long a, b; + + a = random(); + b = random(); + result = (double) (a - 1073741824) * 8388608.0 + (double) (b >> 8); + return result; +} +*/ + +/*****************************************************************************/ +/* */ +/* floatrand() Generate a float with random 24-bit significand and a */ +/* random exponent in [0, 63]. */ +/* */ +/*****************************************************************************/ + +/* +float floatrand() +{ + float result; + float expo; + long a, c; + long i; + + a = random(); + c = random(); + result = (float) ((a - 1073741824) >> 6); + for (i = 512, expo = 2; i <= 16384; i *= 2, expo = expo * expo) { + if (c & i) { + result *= expo; + } + } + return result; +} +*/ + +/*****************************************************************************/ +/* */ +/* narrowfloatrand() Generate a float with random 24-bit significand and */ +/* a random exponent in [0, 7]. */ +/* */ +/*****************************************************************************/ + +/* +float narrowfloatrand() +{ + float result; + float expo; + long a, c; + long i; + + a = random(); + c = random(); + result = (float) ((a - 1073741824) >> 6); + for (i = 512, expo = 2; i <= 2048; i *= 2, expo = expo * expo) { + if (c & i) { + result *= expo; + } + } + return result; +} +*/ + +/*****************************************************************************/ +/* */ +/* uniformfloatrand() Generate a float with random 24-bit significand. */ +/* */ +/*****************************************************************************/ + +/* +float uniformfloatrand() +{ + float result; + long a; + + a = random(); + result = (float) ((a - 1073741824) >> 6); + return result; +} +*/ + +/*****************************************************************************/ +/* */ +/* exactinit() Initialize the variables used for exact arithmetic. */ +/* */ +/* `epsilon' is the largest power of two such that 1.0 + epsilon = 1.0 in */ +/* floating-point arithmetic. `epsilon' bounds the relative roundoff */ +/* error. It is used for floating-point error analysis. */ +/* */ +/* `splitter' is used to split floating-point numbers into two half- */ +/* length significands for exact multiplication. */ +/* */ +/* I imagine that a highly optimizing compiler might be too smart for its */ +/* own good, and somehow cause this routine to fail, if it pretends that */ +/* floating-point arithmetic is too much like real arithmetic. */ +/* */ +/* Don't change this routine unless you fully understand it. */ +/* */ +/*****************************************************************************/ + +REAL exactinit() +{ + REAL half; + REAL check, lastcheck; + int every_other; +#ifdef LINUX + int cword; +#endif /* LINUX */ + +#ifdef CPU86 +#ifdef SINGLE + _control87(_PC_24, _MCW_PC); /* Set FPU control word for single precision. */ +#else /* not SINGLE */ + _control87(_PC_53, _MCW_PC); /* Set FPU control word for double precision. */ +#endif /* not SINGLE */ +#endif /* CPU86 */ +#ifdef LINUX +#ifdef SINGLE + /* cword = 4223; */ + cword = 4210; /* set FPU control word for single precision */ +#else /* not SINGLE */ + /* cword = 4735; */ + cword = 4722; /* set FPU control word for double precision */ +#endif /* not SINGLE */ + _FPU_SETCW(cword); +#endif /* LINUX */ + + every_other = 1; + half = 0.5; + epsilon = 1.0; + splitter = 1.0; + check = 1.0; + /* Repeatedly divide `epsilon' by two until it is too small to add to */ + /* one without causing roundoff. (Also check if the sum is equal to */ + /* the previous sum, for machines that round up instead of using exact */ + /* rounding. Not that this library will work on such machines anyway. */ + do { + lastcheck = check; + epsilon *= half; + if (every_other) { + splitter *= 2.0; + } + every_other = !every_other; + check = 1.0 + epsilon; + } while ((check != 1.0) && (check != lastcheck)); + splitter += 1.0; + + /* Error bounds for orientation and incircle tests. */ + resulterrbound = (3.0 + 8.0 * epsilon) * epsilon; + ccwerrboundA = (3.0 + 16.0 * epsilon) * epsilon; + ccwerrboundB = (2.0 + 12.0 * epsilon) * epsilon; + ccwerrboundC = (9.0 + 64.0 * epsilon) * epsilon * epsilon; + o3derrboundA = (7.0 + 56.0 * epsilon) * epsilon; + o3derrboundB = (3.0 + 28.0 * epsilon) * epsilon; + o3derrboundC = (26.0 + 288.0 * epsilon) * epsilon * epsilon; + iccerrboundA = (10.0 + 96.0 * epsilon) * epsilon; + iccerrboundB = (4.0 + 48.0 * epsilon) * epsilon; + iccerrboundC = (44.0 + 576.0 * epsilon) * epsilon * epsilon; + isperrboundA = (16.0 + 224.0 * epsilon) * epsilon; + isperrboundB = (5.0 + 72.0 * epsilon) * epsilon; + isperrboundC = (71.0 + 1408.0 * epsilon) * epsilon * epsilon; + + return epsilon; /* Added by H. Si 30 Juli, 2004. */ +} + +/*****************************************************************************/ +/* */ +/* grow_expansion() Add a scalar to an expansion. */ +/* */ +/* Sets h = e + b. See the long version of my paper for details. */ +/* */ +/* Maintains the nonoverlapping property. If round-to-even is used (as */ +/* with IEEE 754), maintains the strongly nonoverlapping and nonadjacent */ +/* properties as well. (That is, if e has one of these properties, so */ +/* will h.) */ +/* */ +/*****************************************************************************/ + +int grow_expansion(int elen, REAL *e, REAL b, REAL *h) +/* e and h can be the same. */ +{ + REAL Q; + INEXACT REAL Qnew; + int eindex; + REAL enow; + INEXACT REAL bvirt; + REAL avirt, bround, around; + + Q = b; + for (eindex = 0; eindex < elen; eindex++) { + enow = e[eindex]; + Two_Sum(Q, enow, Qnew, h[eindex]); + Q = Qnew; + } + h[eindex] = Q; + return eindex + 1; +} + +/*****************************************************************************/ +/* */ +/* grow_expansion_zeroelim() Add a scalar to an expansion, eliminating */ +/* zero components from the output expansion. */ +/* */ +/* Sets h = e + b. See the long version of my paper for details. */ +/* */ +/* Maintains the nonoverlapping property. If round-to-even is used (as */ +/* with IEEE 754), maintains the strongly nonoverlapping and nonadjacent */ +/* properties as well. (That is, if e has one of these properties, so */ +/* will h.) */ +/* */ +/*****************************************************************************/ + +int grow_expansion_zeroelim(int elen, REAL *e, REAL b, REAL *h) +/* e and h can be the same. */ +{ + REAL Q, hh; + INEXACT REAL Qnew; + int eindex, hindex; + REAL enow; + INEXACT REAL bvirt; + REAL avirt, bround, around; + + hindex = 0; + Q = b; + for (eindex = 0; eindex < elen; eindex++) { + enow = e[eindex]; + Two_Sum(Q, enow, Qnew, hh); + Q = Qnew; + if (hh != 0.0) { + h[hindex++] = hh; + } + } + if ((Q != 0.0) || (hindex == 0)) { + h[hindex++] = Q; + } + return hindex; +} + +/*****************************************************************************/ +/* */ +/* expansion_sum() Sum two expansions. */ +/* */ +/* Sets h = e + f. See the long version of my paper for details. */ +/* */ +/* Maintains the nonoverlapping property. If round-to-even is used (as */ +/* with IEEE 754), maintains the nonadjacent property as well. (That is, */ +/* if e has one of these properties, so will h.) Does NOT maintain the */ +/* strongly nonoverlapping property. */ +/* */ +/*****************************************************************************/ + +int expansion_sum(int elen, REAL *e, int flen, REAL *f, REAL *h) +/* e and h can be the same, but f and h cannot. */ +{ + REAL Q; + INEXACT REAL Qnew; + int findex, hindex, hlast; + REAL hnow; + INEXACT REAL bvirt; + REAL avirt, bround, around; + + Q = f[0]; + for (hindex = 0; hindex < elen; hindex++) { + hnow = e[hindex]; + Two_Sum(Q, hnow, Qnew, h[hindex]); + Q = Qnew; + } + h[hindex] = Q; + hlast = hindex; + for (findex = 1; findex < flen; findex++) { + Q = f[findex]; + for (hindex = findex; hindex <= hlast; hindex++) { + hnow = h[hindex]; + Two_Sum(Q, hnow, Qnew, h[hindex]); + Q = Qnew; + } + h[++hlast] = Q; + } + return hlast + 1; +} + +/*****************************************************************************/ +/* */ +/* expansion_sum_zeroelim1() Sum two expansions, eliminating zero */ +/* components from the output expansion. */ +/* */ +/* Sets h = e + f. See the long version of my paper for details. */ +/* */ +/* Maintains the nonoverlapping property. If round-to-even is used (as */ +/* with IEEE 754), maintains the nonadjacent property as well. (That is, */ +/* if e has one of these properties, so will h.) Does NOT maintain the */ +/* strongly nonoverlapping property. */ +/* */ +/*****************************************************************************/ + +int expansion_sum_zeroelim1(int elen, REAL *e, int flen, REAL *f, REAL *h) +/* e and h can be the same, but f and h cannot. */ +{ + REAL Q; + INEXACT REAL Qnew; + int index, findex, hindex, hlast; + REAL hnow; + INEXACT REAL bvirt; + REAL avirt, bround, around; + + Q = f[0]; + for (hindex = 0; hindex < elen; hindex++) { + hnow = e[hindex]; + Two_Sum(Q, hnow, Qnew, h[hindex]); + Q = Qnew; + } + h[hindex] = Q; + hlast = hindex; + for (findex = 1; findex < flen; findex++) { + Q = f[findex]; + for (hindex = findex; hindex <= hlast; hindex++) { + hnow = h[hindex]; + Two_Sum(Q, hnow, Qnew, h[hindex]); + Q = Qnew; + } + h[++hlast] = Q; + } + hindex = -1; + for (index = 0; index <= hlast; index++) { + hnow = h[index]; + if (hnow != 0.0) { + h[++hindex] = hnow; + } + } + if (hindex == -1) { + return 1; + } else { + return hindex + 1; + } +} + +/*****************************************************************************/ +/* */ +/* expansion_sum_zeroelim2() Sum two expansions, eliminating zero */ +/* components from the output expansion. */ +/* */ +/* Sets h = e + f. See the long version of my paper for details. */ +/* */ +/* Maintains the nonoverlapping property. If round-to-even is used (as */ +/* with IEEE 754), maintains the nonadjacent property as well. (That is, */ +/* if e has one of these properties, so will h.) Does NOT maintain the */ +/* strongly nonoverlapping property. */ +/* */ +/*****************************************************************************/ + +int expansion_sum_zeroelim2(int elen, REAL *e, int flen, REAL *f, REAL *h) +/* e and h can be the same, but f and h cannot. */ +{ + REAL Q, hh; + INEXACT REAL Qnew; + int eindex, findex, hindex, hlast; + REAL enow; + INEXACT REAL bvirt; + REAL avirt, bround, around; + + hindex = 0; + Q = f[0]; + for (eindex = 0; eindex < elen; eindex++) { + enow = e[eindex]; + Two_Sum(Q, enow, Qnew, hh); + Q = Qnew; + if (hh != 0.0) { + h[hindex++] = hh; + } + } + h[hindex] = Q; + hlast = hindex; + for (findex = 1; findex < flen; findex++) { + hindex = 0; + Q = f[findex]; + for (eindex = 0; eindex <= hlast; eindex++) { + enow = h[eindex]; + Two_Sum(Q, enow, Qnew, hh); + Q = Qnew; + if (hh != 0) { + h[hindex++] = hh; + } + } + h[hindex] = Q; + hlast = hindex; + } + return hlast + 1; +} + +/*****************************************************************************/ +/* */ +/* fast_expansion_sum() Sum two expansions. */ +/* */ +/* Sets h = e + f. See the long version of my paper for details. */ +/* */ +/* If round-to-even is used (as with IEEE 754), maintains the strongly */ +/* nonoverlapping property. (That is, if e is strongly nonoverlapping, h */ +/* will be also.) Does NOT maintain the nonoverlapping or nonadjacent */ +/* properties. */ +/* */ +/*****************************************************************************/ + +int fast_expansion_sum(int elen, REAL *e, int flen, REAL *f, REAL *h) +/* h cannot be e or f. */ +{ + REAL Q; + INEXACT REAL Qnew; + INEXACT REAL bvirt; + REAL avirt, bround, around; + int eindex, findex, hindex; + REAL enow, fnow; + + enow = e[0]; + fnow = f[0]; + eindex = findex = 0; + if ((fnow > enow) == (fnow > -enow)) { + Q = enow; + enow = e[++eindex]; + } else { + Q = fnow; + fnow = f[++findex]; + } + hindex = 0; + if ((eindex < elen) && (findex < flen)) { + if ((fnow > enow) == (fnow > -enow)) { + Fast_Two_Sum(enow, Q, Qnew, h[0]); + enow = e[++eindex]; + } else { + Fast_Two_Sum(fnow, Q, Qnew, h[0]); + fnow = f[++findex]; + } + Q = Qnew; + hindex = 1; + while ((eindex < elen) && (findex < flen)) { + if ((fnow > enow) == (fnow > -enow)) { + Two_Sum(Q, enow, Qnew, h[hindex]); + enow = e[++eindex]; + } else { + Two_Sum(Q, fnow, Qnew, h[hindex]); + fnow = f[++findex]; + } + Q = Qnew; + hindex++; + } + } + while (eindex < elen) { + Two_Sum(Q, enow, Qnew, h[hindex]); + enow = e[++eindex]; + Q = Qnew; + hindex++; + } + while (findex < flen) { + Two_Sum(Q, fnow, Qnew, h[hindex]); + fnow = f[++findex]; + Q = Qnew; + hindex++; + } + h[hindex] = Q; + return hindex + 1; +} + +/*****************************************************************************/ +/* */ +/* fast_expansion_sum_zeroelim() Sum two expansions, eliminating zero */ +/* components from the output expansion. */ +/* */ +/* Sets h = e + f. See the long version of my paper for details. */ +/* */ +/* If round-to-even is used (as with IEEE 754), maintains the strongly */ +/* nonoverlapping property. (That is, if e is strongly nonoverlapping, h */ +/* will be also.) Does NOT maintain the nonoverlapping or nonadjacent */ +/* properties. */ +/* */ +/*****************************************************************************/ + +int fast_expansion_sum_zeroelim(int elen, REAL *e, int flen, REAL *f, REAL *h) +/* h cannot be e or f. */ +{ + REAL Q; + INEXACT REAL Qnew; + INEXACT REAL hh; + INEXACT REAL bvirt; + REAL avirt, bround, around; + int eindex, findex, hindex; + REAL enow, fnow; + + enow = e[0]; + fnow = f[0]; + eindex = findex = 0; + if ((fnow > enow) == (fnow > -enow)) { + Q = enow; + enow = e[++eindex]; + } else { + Q = fnow; + fnow = f[++findex]; + } + hindex = 0; + if ((eindex < elen) && (findex < flen)) { + if ((fnow > enow) == (fnow > -enow)) { + Fast_Two_Sum(enow, Q, Qnew, hh); + enow = e[++eindex]; + } else { + Fast_Two_Sum(fnow, Q, Qnew, hh); + fnow = f[++findex]; + } + Q = Qnew; + if (hh != 0.0) { + h[hindex++] = hh; + } + while ((eindex < elen) && (findex < flen)) { + if ((fnow > enow) == (fnow > -enow)) { + Two_Sum(Q, enow, Qnew, hh); + enow = e[++eindex]; + } else { + Two_Sum(Q, fnow, Qnew, hh); + fnow = f[++findex]; + } + Q = Qnew; + if (hh != 0.0) { + h[hindex++] = hh; + } + } + } + while (eindex < elen) { + Two_Sum(Q, enow, Qnew, hh); + enow = e[++eindex]; + Q = Qnew; + if (hh != 0.0) { + h[hindex++] = hh; + } + } + while (findex < flen) { + Two_Sum(Q, fnow, Qnew, hh); + fnow = f[++findex]; + Q = Qnew; + if (hh != 0.0) { + h[hindex++] = hh; + } + } + if ((Q != 0.0) || (hindex == 0)) { + h[hindex++] = Q; + } + return hindex; +} + +/*****************************************************************************/ +/* */ +/* linear_expansion_sum() Sum two expansions. */ +/* */ +/* Sets h = e + f. See either version of my paper for details. */ +/* */ +/* Maintains the nonoverlapping property. (That is, if e is */ +/* nonoverlapping, h will be also.) */ +/* */ +/*****************************************************************************/ + +int linear_expansion_sum(int elen, REAL *e, int flen, REAL *f, REAL *h) +/* h cannot be e or f. */ +{ + REAL Q, q; + INEXACT REAL Qnew; + INEXACT REAL R; + INEXACT REAL bvirt; + REAL avirt, bround, around; + int eindex, findex, hindex; + REAL enow, fnow; + REAL g0; + + enow = e[0]; + fnow = f[0]; + eindex = findex = 0; + if ((fnow > enow) == (fnow > -enow)) { + g0 = enow; + enow = e[++eindex]; + } else { + g0 = fnow; + fnow = f[++findex]; + } + if ((eindex < elen) && ((findex >= flen) + || ((fnow > enow) == (fnow > -enow)))) { + Fast_Two_Sum(enow, g0, Qnew, q); + enow = e[++eindex]; + } else { + Fast_Two_Sum(fnow, g0, Qnew, q); + fnow = f[++findex]; + } + Q = Qnew; + for (hindex = 0; hindex < elen + flen - 2; hindex++) { + if ((eindex < elen) && ((findex >= flen) + || ((fnow > enow) == (fnow > -enow)))) { + Fast_Two_Sum(enow, q, R, h[hindex]); + enow = e[++eindex]; + } else { + Fast_Two_Sum(fnow, q, R, h[hindex]); + fnow = f[++findex]; + } + Two_Sum(Q, R, Qnew, q); + Q = Qnew; + } + h[hindex] = q; + h[hindex + 1] = Q; + return hindex + 2; +} + +/*****************************************************************************/ +/* */ +/* linear_expansion_sum_zeroelim() Sum two expansions, eliminating zero */ +/* components from the output expansion. */ +/* */ +/* Sets h = e + f. See either version of my paper for details. */ +/* */ +/* Maintains the nonoverlapping property. (That is, if e is */ +/* nonoverlapping, h will be also.) */ +/* */ +/*****************************************************************************/ + +int linear_expansion_sum_zeroelim(int elen, REAL *e, int flen, REAL *f, + REAL *h) +/* h cannot be e or f. */ +{ + REAL Q, q, hh; + INEXACT REAL Qnew; + INEXACT REAL R; + INEXACT REAL bvirt; + REAL avirt, bround, around; + int eindex, findex, hindex; + int count; + REAL enow, fnow; + REAL g0; + + enow = e[0]; + fnow = f[0]; + eindex = findex = 0; + hindex = 0; + if ((fnow > enow) == (fnow > -enow)) { + g0 = enow; + enow = e[++eindex]; + } else { + g0 = fnow; + fnow = f[++findex]; + } + if ((eindex < elen) && ((findex >= flen) + || ((fnow > enow) == (fnow > -enow)))) { + Fast_Two_Sum(enow, g0, Qnew, q); + enow = e[++eindex]; + } else { + Fast_Two_Sum(fnow, g0, Qnew, q); + fnow = f[++findex]; + } + Q = Qnew; + for (count = 2; count < elen + flen; count++) { + if ((eindex < elen) && ((findex >= flen) + || ((fnow > enow) == (fnow > -enow)))) { + Fast_Two_Sum(enow, q, R, hh); + enow = e[++eindex]; + } else { + Fast_Two_Sum(fnow, q, R, hh); + fnow = f[++findex]; + } + Two_Sum(Q, R, Qnew, q); + Q = Qnew; + if (hh != 0) { + h[hindex++] = hh; + } + } + if (q != 0) { + h[hindex++] = q; + } + if ((Q != 0.0) || (hindex == 0)) { + h[hindex++] = Q; + } + return hindex; +} + +/*****************************************************************************/ +/* */ +/* scale_expansion() Multiply an expansion by a scalar. */ +/* */ +/* Sets h = be. See either version of my paper for details. */ +/* */ +/* Maintains the nonoverlapping property. If round-to-even is used (as */ +/* with IEEE 754), maintains the strongly nonoverlapping and nonadjacent */ +/* properties as well. (That is, if e has one of these properties, so */ +/* will h.) */ +/* */ +/*****************************************************************************/ + +int scale_expansion(int elen, REAL *e, REAL b, REAL *h) +/* e and h cannot be the same. */ +{ + INEXACT REAL Q; + INEXACT REAL sum; + INEXACT REAL product1; + REAL product0; + int eindex, hindex; + REAL enow; + INEXACT REAL bvirt; + REAL avirt, bround, around; + INEXACT REAL c; + INEXACT REAL abig; + REAL ahi, alo, bhi, blo; + REAL err1, err2, err3; + + Split(b, bhi, blo); + Two_Product_Presplit(e[0], b, bhi, blo, Q, h[0]); + hindex = 1; + for (eindex = 1; eindex < elen; eindex++) { + enow = e[eindex]; + Two_Product_Presplit(enow, b, bhi, blo, product1, product0); + Two_Sum(Q, product0, sum, h[hindex]); + hindex++; + Two_Sum(product1, sum, Q, h[hindex]); + hindex++; + } + h[hindex] = Q; + return elen + elen; +} + +/*****************************************************************************/ +/* */ +/* scale_expansion_zeroelim() Multiply an expansion by a scalar, */ +/* eliminating zero components from the */ +/* output expansion. */ +/* */ +/* Sets h = be. See either version of my paper for details. */ +/* */ +/* Maintains the nonoverlapping property. If round-to-even is used (as */ +/* with IEEE 754), maintains the strongly nonoverlapping and nonadjacent */ +/* properties as well. (That is, if e has one of these properties, so */ +/* will h.) */ +/* */ +/*****************************************************************************/ + +int scale_expansion_zeroelim(int elen, REAL *e, REAL b, REAL *h) +/* e and h cannot be the same. */ +{ + INEXACT REAL Q, sum; + REAL hh; + INEXACT REAL product1; + REAL product0; + int eindex, hindex; + REAL enow; + INEXACT REAL bvirt; + REAL avirt, bround, around; + INEXACT REAL c; + INEXACT REAL abig; + REAL ahi, alo, bhi, blo; + REAL err1, err2, err3; + + Split(b, bhi, blo); + Two_Product_Presplit(e[0], b, bhi, blo, Q, hh); + hindex = 0; + if (hh != 0) { + h[hindex++] = hh; + } + for (eindex = 1; eindex < elen; eindex++) { + enow = e[eindex]; + Two_Product_Presplit(enow, b, bhi, blo, product1, product0); + Two_Sum(Q, product0, sum, hh); + if (hh != 0) { + h[hindex++] = hh; + } + Fast_Two_Sum(product1, sum, Q, hh); + if (hh != 0) { + h[hindex++] = hh; + } + } + if ((Q != 0.0) || (hindex == 0)) { + h[hindex++] = Q; + } + return hindex; +} + +/*****************************************************************************/ +/* */ +/* compress() Compress an expansion. */ +/* */ +/* See the long version of my paper for details. */ +/* */ +/* Maintains the nonoverlapping property. If round-to-even is used (as */ +/* with IEEE 754), then any nonoverlapping expansion is converted to a */ +/* nonadjacent expansion. */ +/* */ +/*****************************************************************************/ + +int compress(int elen, REAL *e, REAL *h) +/* e and h may be the same. */ +{ + REAL Q, q; + INEXACT REAL Qnew; + int eindex, hindex; + INEXACT REAL bvirt; + REAL enow, hnow; + int top, bottom; + + bottom = elen - 1; + Q = e[bottom]; + for (eindex = elen - 2; eindex >= 0; eindex--) { + enow = e[eindex]; + Fast_Two_Sum(Q, enow, Qnew, q); + if (q != 0) { + h[bottom--] = Qnew; + Q = q; + } else { + Q = Qnew; + } + } + top = 0; + for (hindex = bottom + 1; hindex < elen; hindex++) { + hnow = h[hindex]; + Fast_Two_Sum(hnow, Q, Qnew, q); + if (q != 0) { + h[top++] = q; + } + Q = Qnew; + } + h[top] = Q; + return top + 1; +} + +/*****************************************************************************/ +/* */ +/* estimate() Produce a one-word estimate of an expansion's value. */ +/* */ +/* See either version of my paper for details. */ +/* */ +/*****************************************************************************/ + +REAL estimate(int elen, REAL *e) +{ + REAL Q; + int eindex; + + Q = e[0]; + for (eindex = 1; eindex < elen; eindex++) { + Q += e[eindex]; + } + return Q; +} + +/*****************************************************************************/ +/* */ +/* orient2dfast() Approximate 2D orientation test. Nonrobust. */ +/* orient2dexact() Exact 2D orientation test. Robust. */ +/* orient2dslow() Another exact 2D orientation test. Robust. */ +/* orient2d() Adaptive exact 2D orientation test. Robust. */ +/* */ +/* Return a positive value if the points pa, pb, and pc occur */ +/* in counterclockwise order; a negative value if they occur */ +/* in clockwise order; and zero if they are collinear. The */ +/* result is also a rough approximation of twice the signed */ +/* area of the triangle defined by the three points. */ +/* */ +/* Only the first and last routine should be used; the middle two are for */ +/* timings. */ +/* */ +/* The last three use exact arithmetic to ensure a correct answer. The */ +/* result returned is the determinant of a matrix. In orient2d() only, */ +/* this determinant is computed adaptively, in the sense that exact */ +/* arithmetic is used only to the degree it is needed to ensure that the */ +/* returned value has the correct sign. Hence, orient2d() is usually quite */ +/* fast, but will run more slowly when the input points are collinear or */ +/* nearly so. */ +/* */ +/*****************************************************************************/ + +REAL orient2dfast(REAL *pa, REAL *pb, REAL *pc) +{ + REAL acx, bcx, acy, bcy; + + acx = pa[0] - pc[0]; + bcx = pb[0] - pc[0]; + acy = pa[1] - pc[1]; + bcy = pb[1] - pc[1]; + return acx * bcy - acy * bcx; +} + +REAL orient2dexact(REAL *pa, REAL *pb, REAL *pc) +{ + INEXACT REAL axby1, axcy1, bxcy1, bxay1, cxay1, cxby1; + REAL axby0, axcy0, bxcy0, bxay0, cxay0, cxby0; + REAL aterms[4], bterms[4], cterms[4]; + INEXACT REAL aterms3, bterms3, cterms3; + REAL v[8], w[12]; + int vlength, wlength; + + INEXACT REAL bvirt; + REAL avirt, bround, around; + INEXACT REAL c; + INEXACT REAL abig; + REAL ahi, alo, bhi, blo; + REAL err1, err2, err3; + INEXACT REAL _i, _j; + REAL _0; + + Two_Product(pa[0], pb[1], axby1, axby0); + Two_Product(pa[0], pc[1], axcy1, axcy0); + Two_Two_Diff(axby1, axby0, axcy1, axcy0, + aterms3, aterms[2], aterms[1], aterms[0]); + aterms[3] = aterms3; + + Two_Product(pb[0], pc[1], bxcy1, bxcy0); + Two_Product(pb[0], pa[1], bxay1, bxay0); + Two_Two_Diff(bxcy1, bxcy0, bxay1, bxay0, + bterms3, bterms[2], bterms[1], bterms[0]); + bterms[3] = bterms3; + + Two_Product(pc[0], pa[1], cxay1, cxay0); + Two_Product(pc[0], pb[1], cxby1, cxby0); + Two_Two_Diff(cxay1, cxay0, cxby1, cxby0, + cterms3, cterms[2], cterms[1], cterms[0]); + cterms[3] = cterms3; + + vlength = fast_expansion_sum_zeroelim(4, aterms, 4, bterms, v); + wlength = fast_expansion_sum_zeroelim(vlength, v, 4, cterms, w); + + return w[wlength - 1]; +} + +REAL orient2dslow(REAL *pa, REAL *pb, REAL *pc) +{ + INEXACT REAL acx, acy, bcx, bcy; + REAL acxtail, acytail; + REAL bcxtail, bcytail; + REAL negate, negatetail; + REAL axby[8], bxay[8]; + INEXACT REAL axby7, bxay7; + REAL deter[16]; + int deterlen; + + INEXACT REAL bvirt; + REAL avirt, bround, around; + INEXACT REAL c; + INEXACT REAL abig; + REAL a0hi, a0lo, a1hi, a1lo, bhi, blo; + REAL err1, err2, err3; + INEXACT REAL _i, _j, _k, _l, _m, _n; + REAL _0, _1, _2; + + Two_Diff(pa[0], pc[0], acx, acxtail); + Two_Diff(pa[1], pc[1], acy, acytail); + Two_Diff(pb[0], pc[0], bcx, bcxtail); + Two_Diff(pb[1], pc[1], bcy, bcytail); + + Two_Two_Product(acx, acxtail, bcy, bcytail, + axby7, axby[6], axby[5], axby[4], + axby[3], axby[2], axby[1], axby[0]); + axby[7] = axby7; + negate = -acy; + negatetail = -acytail; + Two_Two_Product(bcx, bcxtail, negate, negatetail, + bxay7, bxay[6], bxay[5], bxay[4], + bxay[3], bxay[2], bxay[1], bxay[0]); + bxay[7] = bxay7; + + deterlen = fast_expansion_sum_zeroelim(8, axby, 8, bxay, deter); + + return deter[deterlen - 1]; +} + +REAL orient2dadapt(REAL *pa, REAL *pb, REAL *pc, REAL detsum) +{ + INEXACT REAL acx, acy, bcx, bcy; + REAL acxtail, acytail, bcxtail, bcytail; + INEXACT REAL detleft, detright; + REAL detlefttail, detrighttail; + REAL det, errbound; + REAL B[4], C1[8], C2[12], D[16]; + INEXACT REAL B3; + int C1length, C2length, Dlength; + REAL u[4]; + INEXACT REAL u3; + INEXACT REAL s1, t1; + REAL s0, t0; + + INEXACT REAL bvirt; + REAL avirt, bround, around; + INEXACT REAL c; + INEXACT REAL abig; + REAL ahi, alo, bhi, blo; + REAL err1, err2, err3; + INEXACT REAL _i, _j; + REAL _0; + + acx = (REAL) (pa[0] - pc[0]); + bcx = (REAL) (pb[0] - pc[0]); + acy = (REAL) (pa[1] - pc[1]); + bcy = (REAL) (pb[1] - pc[1]); + + Two_Product(acx, bcy, detleft, detlefttail); + Two_Product(acy, bcx, detright, detrighttail); + + Two_Two_Diff(detleft, detlefttail, detright, detrighttail, + B3, B[2], B[1], B[0]); + B[3] = B3; + + det = estimate(4, B); + errbound = ccwerrboundB * detsum; + if ((det >= errbound) || (-det >= errbound)) { + return det; + } + + Two_Diff_Tail(pa[0], pc[0], acx, acxtail); + Two_Diff_Tail(pb[0], pc[0], bcx, bcxtail); + Two_Diff_Tail(pa[1], pc[1], acy, acytail); + Two_Diff_Tail(pb[1], pc[1], bcy, bcytail); + + if ((acxtail == 0.0) && (acytail == 0.0) + && (bcxtail == 0.0) && (bcytail == 0.0)) { + return det; + } + + errbound = ccwerrboundC * detsum + resulterrbound * Absolute(det); + det += (acx * bcytail + bcy * acxtail) + - (acy * bcxtail + bcx * acytail); + if ((det >= errbound) || (-det >= errbound)) { + return det; + } + + Two_Product(acxtail, bcy, s1, s0); + Two_Product(acytail, bcx, t1, t0); + Two_Two_Diff(s1, s0, t1, t0, u3, u[2], u[1], u[0]); + u[3] = u3; + C1length = fast_expansion_sum_zeroelim(4, B, 4, u, C1); + + Two_Product(acx, bcytail, s1, s0); + Two_Product(acy, bcxtail, t1, t0); + Two_Two_Diff(s1, s0, t1, t0, u3, u[2], u[1], u[0]); + u[3] = u3; + C2length = fast_expansion_sum_zeroelim(C1length, C1, 4, u, C2); + + Two_Product(acxtail, bcytail, s1, s0); + Two_Product(acytail, bcxtail, t1, t0); + Two_Two_Diff(s1, s0, t1, t0, u3, u[2], u[1], u[0]); + u[3] = u3; + Dlength = fast_expansion_sum_zeroelim(C2length, C2, 4, u, D); + + return(D[Dlength - 1]); +} + +REAL orient2d(REAL *pa, REAL *pb, REAL *pc) +{ + REAL detleft, detright, det; + REAL detsum, errbound; + + detleft = (pa[0] - pc[0]) * (pb[1] - pc[1]); + detright = (pa[1] - pc[1]) * (pb[0] - pc[0]); + det = detleft - detright; + + if (detleft > 0.0) { + if (detright <= 0.0) { + return det; + } else { + detsum = detleft + detright; + } + } else if (detleft < 0.0) { + if (detright >= 0.0) { + return det; + } else { + detsum = -detleft - detright; + } + } else { + return det; + } + + errbound = ccwerrboundA * detsum; + if ((det >= errbound) || (-det >= errbound)) { + return det; + } + + return orient2dadapt(pa, pb, pc, detsum); +} + +/*****************************************************************************/ +/* */ +/* orient3dfast() Approximate 3D orientation test. Nonrobust. */ +/* orient3dexact() Exact 3D orientation test. Robust. */ +/* orient3dslow() Another exact 3D orientation test. Robust. */ +/* orient3d() Adaptive exact 3D orientation test. Robust. */ +/* */ +/* Return a positive value if the point pd lies below the */ +/* plane passing through pa, pb, and pc; "below" is defined so */ +/* that pa, pb, and pc appear in counterclockwise order when */ +/* viewed from above the plane. Returns a negative value if */ +/* pd lies above the plane. Returns zero if the points are */ +/* coplanar. The result is also a rough approximation of six */ +/* times the signed volume of the tetrahedron defined by the */ +/* four points. */ +/* */ +/* Only the first and last routine should be used; the middle two are for */ +/* timings. */ +/* */ +/* The last three use exact arithmetic to ensure a correct answer. The */ +/* result returned is the determinant of a matrix. In orient3d() only, */ +/* this determinant is computed adaptively, in the sense that exact */ +/* arithmetic is used only to the degree it is needed to ensure that the */ +/* returned value has the correct sign. Hence, orient3d() is usually quite */ +/* fast, but will run more slowly when the input points are coplanar or */ +/* nearly so. */ +/* */ +/*****************************************************************************/ + +REAL orient3dfast(REAL *pa, REAL *pb, REAL *pc, REAL *pd) +{ + REAL adx, bdx, cdx; + REAL ady, bdy, cdy; + REAL adz, bdz, cdz; + + adx = pa[0] - pd[0]; + bdx = pb[0] - pd[0]; + cdx = pc[0] - pd[0]; + ady = pa[1] - pd[1]; + bdy = pb[1] - pd[1]; + cdy = pc[1] - pd[1]; + adz = pa[2] - pd[2]; + bdz = pb[2] - pd[2]; + cdz = pc[2] - pd[2]; + + return adx * (bdy * cdz - bdz * cdy) + + bdx * (cdy * adz - cdz * ady) + + cdx * (ady * bdz - adz * bdy); +} + +REAL orient3dexact(REAL *pa, REAL *pb, REAL *pc, REAL *pd) +{ + INEXACT REAL axby1, bxcy1, cxdy1, dxay1, axcy1, bxdy1; + INEXACT REAL bxay1, cxby1, dxcy1, axdy1, cxay1, dxby1; + REAL axby0, bxcy0, cxdy0, dxay0, axcy0, bxdy0; + REAL bxay0, cxby0, dxcy0, axdy0, cxay0, dxby0; + REAL ab[4], bc[4], cd[4], da[4], ac[4], bd[4]; + REAL temp8[8]; + int templen; + REAL abc[12], bcd[12], cda[12], dab[12]; + int abclen, bcdlen, cdalen, dablen; + REAL adet[24], bdet[24], cdet[24], ddet[24]; + int alen, blen, clen, dlen; + REAL abdet[48], cddet[48]; + int ablen, cdlen; + REAL deter[96]; + int deterlen; + int i; + + INEXACT REAL bvirt; + REAL avirt, bround, around; + INEXACT REAL c; + INEXACT REAL abig; + REAL ahi, alo, bhi, blo; + REAL err1, err2, err3; + INEXACT REAL _i, _j; + REAL _0; + + Two_Product(pa[0], pb[1], axby1, axby0); + Two_Product(pb[0], pa[1], bxay1, bxay0); + Two_Two_Diff(axby1, axby0, bxay1, bxay0, ab[3], ab[2], ab[1], ab[0]); + + Two_Product(pb[0], pc[1], bxcy1, bxcy0); + Two_Product(pc[0], pb[1], cxby1, cxby0); + Two_Two_Diff(bxcy1, bxcy0, cxby1, cxby0, bc[3], bc[2], bc[1], bc[0]); + + Two_Product(pc[0], pd[1], cxdy1, cxdy0); + Two_Product(pd[0], pc[1], dxcy1, dxcy0); + Two_Two_Diff(cxdy1, cxdy0, dxcy1, dxcy0, cd[3], cd[2], cd[1], cd[0]); + + Two_Product(pd[0], pa[1], dxay1, dxay0); + Two_Product(pa[0], pd[1], axdy1, axdy0); + Two_Two_Diff(dxay1, dxay0, axdy1, axdy0, da[3], da[2], da[1], da[0]); + + Two_Product(pa[0], pc[1], axcy1, axcy0); + Two_Product(pc[0], pa[1], cxay1, cxay0); + Two_Two_Diff(axcy1, axcy0, cxay1, cxay0, ac[3], ac[2], ac[1], ac[0]); + + Two_Product(pb[0], pd[1], bxdy1, bxdy0); + Two_Product(pd[0], pb[1], dxby1, dxby0); + Two_Two_Diff(bxdy1, bxdy0, dxby1, dxby0, bd[3], bd[2], bd[1], bd[0]); + + templen = fast_expansion_sum_zeroelim(4, cd, 4, da, temp8); + cdalen = fast_expansion_sum_zeroelim(templen, temp8, 4, ac, cda); + templen = fast_expansion_sum_zeroelim(4, da, 4, ab, temp8); + dablen = fast_expansion_sum_zeroelim(templen, temp8, 4, bd, dab); + for (i = 0; i < 4; i++) { + bd[i] = -bd[i]; + ac[i] = -ac[i]; + } + templen = fast_expansion_sum_zeroelim(4, ab, 4, bc, temp8); + abclen = fast_expansion_sum_zeroelim(templen, temp8, 4, ac, abc); + templen = fast_expansion_sum_zeroelim(4, bc, 4, cd, temp8); + bcdlen = fast_expansion_sum_zeroelim(templen, temp8, 4, bd, bcd); + + alen = scale_expansion_zeroelim(bcdlen, bcd, pa[2], adet); + blen = scale_expansion_zeroelim(cdalen, cda, -pb[2], bdet); + clen = scale_expansion_zeroelim(dablen, dab, pc[2], cdet); + dlen = scale_expansion_zeroelim(abclen, abc, -pd[2], ddet); + + ablen = fast_expansion_sum_zeroelim(alen, adet, blen, bdet, abdet); + cdlen = fast_expansion_sum_zeroelim(clen, cdet, dlen, ddet, cddet); + deterlen = fast_expansion_sum_zeroelim(ablen, abdet, cdlen, cddet, deter); + + return deter[deterlen - 1]; +} + +REAL orient3dslow(REAL *pa, REAL *pb, REAL *pc, REAL *pd) +{ + INEXACT REAL adx, ady, adz, bdx, bdy, bdz, cdx, cdy, cdz; + REAL adxtail, adytail, adztail; + REAL bdxtail, bdytail, bdztail; + REAL cdxtail, cdytail, cdztail; + REAL negate, negatetail; + INEXACT REAL axby7, bxcy7, axcy7, bxay7, cxby7, cxay7; + REAL axby[8], bxcy[8], axcy[8], bxay[8], cxby[8], cxay[8]; + REAL temp16[16], temp32[32], temp32t[32]; + int temp16len, temp32len, temp32tlen; + REAL adet[64], bdet[64], cdet[64]; + int alen, blen, clen; + REAL abdet[128]; + int ablen; + REAL deter[192]; + int deterlen; + + INEXACT REAL bvirt; + REAL avirt, bround, around; + INEXACT REAL c; + INEXACT REAL abig; + REAL a0hi, a0lo, a1hi, a1lo, bhi, blo; + REAL err1, err2, err3; + INEXACT REAL _i, _j, _k, _l, _m, _n; + REAL _0, _1, _2; + + Two_Diff(pa[0], pd[0], adx, adxtail); + Two_Diff(pa[1], pd[1], ady, adytail); + Two_Diff(pa[2], pd[2], adz, adztail); + Two_Diff(pb[0], pd[0], bdx, bdxtail); + Two_Diff(pb[1], pd[1], bdy, bdytail); + Two_Diff(pb[2], pd[2], bdz, bdztail); + Two_Diff(pc[0], pd[0], cdx, cdxtail); + Two_Diff(pc[1], pd[1], cdy, cdytail); + Two_Diff(pc[2], pd[2], cdz, cdztail); + + Two_Two_Product(adx, adxtail, bdy, bdytail, + axby7, axby[6], axby[5], axby[4], + axby[3], axby[2], axby[1], axby[0]); + axby[7] = axby7; + negate = -ady; + negatetail = -adytail; + Two_Two_Product(bdx, bdxtail, negate, negatetail, + bxay7, bxay[6], bxay[5], bxay[4], + bxay[3], bxay[2], bxay[1], bxay[0]); + bxay[7] = bxay7; + Two_Two_Product(bdx, bdxtail, cdy, cdytail, + bxcy7, bxcy[6], bxcy[5], bxcy[4], + bxcy[3], bxcy[2], bxcy[1], bxcy[0]); + bxcy[7] = bxcy7; + negate = -bdy; + negatetail = -bdytail; + Two_Two_Product(cdx, cdxtail, negate, negatetail, + cxby7, cxby[6], cxby[5], cxby[4], + cxby[3], cxby[2], cxby[1], cxby[0]); + cxby[7] = cxby7; + Two_Two_Product(cdx, cdxtail, ady, adytail, + cxay7, cxay[6], cxay[5], cxay[4], + cxay[3], cxay[2], cxay[1], cxay[0]); + cxay[7] = cxay7; + negate = -cdy; + negatetail = -cdytail; + Two_Two_Product(adx, adxtail, negate, negatetail, + axcy7, axcy[6], axcy[5], axcy[4], + axcy[3], axcy[2], axcy[1], axcy[0]); + axcy[7] = axcy7; + + temp16len = fast_expansion_sum_zeroelim(8, bxcy, 8, cxby, temp16); + temp32len = scale_expansion_zeroelim(temp16len, temp16, adz, temp32); + temp32tlen = scale_expansion_zeroelim(temp16len, temp16, adztail, temp32t); + alen = fast_expansion_sum_zeroelim(temp32len, temp32, temp32tlen, temp32t, + adet); + + temp16len = fast_expansion_sum_zeroelim(8, cxay, 8, axcy, temp16); + temp32len = scale_expansion_zeroelim(temp16len, temp16, bdz, temp32); + temp32tlen = scale_expansion_zeroelim(temp16len, temp16, bdztail, temp32t); + blen = fast_expansion_sum_zeroelim(temp32len, temp32, temp32tlen, temp32t, + bdet); + + temp16len = fast_expansion_sum_zeroelim(8, axby, 8, bxay, temp16); + temp32len = scale_expansion_zeroelim(temp16len, temp16, cdz, temp32); + temp32tlen = scale_expansion_zeroelim(temp16len, temp16, cdztail, temp32t); + clen = fast_expansion_sum_zeroelim(temp32len, temp32, temp32tlen, temp32t, + cdet); + + ablen = fast_expansion_sum_zeroelim(alen, adet, blen, bdet, abdet); + deterlen = fast_expansion_sum_zeroelim(ablen, abdet, clen, cdet, deter); + + return deter[deterlen - 1]; +} + +REAL orient3dadapt(REAL *pa, REAL *pb, REAL *pc, REAL *pd, REAL permanent) +{ + INEXACT REAL adx, bdx, cdx, ady, bdy, cdy, adz, bdz, cdz; + REAL det, errbound; + + INEXACT REAL bdxcdy1, cdxbdy1, cdxady1, adxcdy1, adxbdy1, bdxady1; + REAL bdxcdy0, cdxbdy0, cdxady0, adxcdy0, adxbdy0, bdxady0; + REAL bc[4], ca[4], ab[4]; + INEXACT REAL bc3, ca3, ab3; + REAL adet[8], bdet[8], cdet[8]; + int alen, blen, clen; + REAL abdet[16]; + int ablen; + REAL *finnow, *finother, *finswap; + REAL fin1[192], fin2[192]; + int finlength; + + REAL adxtail, bdxtail, cdxtail; + REAL adytail, bdytail, cdytail; + REAL adztail, bdztail, cdztail; + INEXACT REAL at_blarge, at_clarge; + INEXACT REAL bt_clarge, bt_alarge; + INEXACT REAL ct_alarge, ct_blarge; + REAL at_b[4], at_c[4], bt_c[4], bt_a[4], ct_a[4], ct_b[4]; + int at_blen, at_clen, bt_clen, bt_alen, ct_alen, ct_blen; + INEXACT REAL bdxt_cdy1, cdxt_bdy1, cdxt_ady1; + INEXACT REAL adxt_cdy1, adxt_bdy1, bdxt_ady1; + REAL bdxt_cdy0, cdxt_bdy0, cdxt_ady0; + REAL adxt_cdy0, adxt_bdy0, bdxt_ady0; + INEXACT REAL bdyt_cdx1, cdyt_bdx1, cdyt_adx1; + INEXACT REAL adyt_cdx1, adyt_bdx1, bdyt_adx1; + REAL bdyt_cdx0, cdyt_bdx0, cdyt_adx0; + REAL adyt_cdx0, adyt_bdx0, bdyt_adx0; + REAL bct[8], cat[8], abt[8]; + int bctlen, catlen, abtlen; + INEXACT REAL bdxt_cdyt1, cdxt_bdyt1, cdxt_adyt1; + INEXACT REAL adxt_cdyt1, adxt_bdyt1, bdxt_adyt1; + REAL bdxt_cdyt0, cdxt_bdyt0, cdxt_adyt0; + REAL adxt_cdyt0, adxt_bdyt0, bdxt_adyt0; + REAL u[4], v[12], w[16]; + INEXACT REAL u3; + int vlength, wlength; + REAL negate; + + INEXACT REAL bvirt; + REAL avirt, bround, around; + INEXACT REAL c; + INEXACT REAL abig; + REAL ahi, alo, bhi, blo; + REAL err1, err2, err3; + INEXACT REAL _i, _j, _k; + REAL _0; + + adx = (REAL) (pa[0] - pd[0]); + bdx = (REAL) (pb[0] - pd[0]); + cdx = (REAL) (pc[0] - pd[0]); + ady = (REAL) (pa[1] - pd[1]); + bdy = (REAL) (pb[1] - pd[1]); + cdy = (REAL) (pc[1] - pd[1]); + adz = (REAL) (pa[2] - pd[2]); + bdz = (REAL) (pb[2] - pd[2]); + cdz = (REAL) (pc[2] - pd[2]); + + Two_Product(bdx, cdy, bdxcdy1, bdxcdy0); + Two_Product(cdx, bdy, cdxbdy1, cdxbdy0); + Two_Two_Diff(bdxcdy1, bdxcdy0, cdxbdy1, cdxbdy0, bc3, bc[2], bc[1], bc[0]); + bc[3] = bc3; + alen = scale_expansion_zeroelim(4, bc, adz, adet); + + Two_Product(cdx, ady, cdxady1, cdxady0); + Two_Product(adx, cdy, adxcdy1, adxcdy0); + Two_Two_Diff(cdxady1, cdxady0, adxcdy1, adxcdy0, ca3, ca[2], ca[1], ca[0]); + ca[3] = ca3; + blen = scale_expansion_zeroelim(4, ca, bdz, bdet); + + Two_Product(adx, bdy, adxbdy1, adxbdy0); + Two_Product(bdx, ady, bdxady1, bdxady0); + Two_Two_Diff(adxbdy1, adxbdy0, bdxady1, bdxady0, ab3, ab[2], ab[1], ab[0]); + ab[3] = ab3; + clen = scale_expansion_zeroelim(4, ab, cdz, cdet); + + ablen = fast_expansion_sum_zeroelim(alen, adet, blen, bdet, abdet); + finlength = fast_expansion_sum_zeroelim(ablen, abdet, clen, cdet, fin1); + + det = estimate(finlength, fin1); + errbound = o3derrboundB * permanent; + if ((det >= errbound) || (-det >= errbound)) { + return det; + } + + Two_Diff_Tail(pa[0], pd[0], adx, adxtail); + Two_Diff_Tail(pb[0], pd[0], bdx, bdxtail); + Two_Diff_Tail(pc[0], pd[0], cdx, cdxtail); + Two_Diff_Tail(pa[1], pd[1], ady, adytail); + Two_Diff_Tail(pb[1], pd[1], bdy, bdytail); + Two_Diff_Tail(pc[1], pd[1], cdy, cdytail); + Two_Diff_Tail(pa[2], pd[2], adz, adztail); + Two_Diff_Tail(pb[2], pd[2], bdz, bdztail); + Two_Diff_Tail(pc[2], pd[2], cdz, cdztail); + + if ((adxtail == 0.0) && (bdxtail == 0.0) && (cdxtail == 0.0) + && (adytail == 0.0) && (bdytail == 0.0) && (cdytail == 0.0) + && (adztail == 0.0) && (bdztail == 0.0) && (cdztail == 0.0)) { + return det; + } + + errbound = o3derrboundC * permanent + resulterrbound * Absolute(det); + det += (adz * ((bdx * cdytail + cdy * bdxtail) + - (bdy * cdxtail + cdx * bdytail)) + + adztail * (bdx * cdy - bdy * cdx)) + + (bdz * ((cdx * adytail + ady * cdxtail) + - (cdy * adxtail + adx * cdytail)) + + bdztail * (cdx * ady - cdy * adx)) + + (cdz * ((adx * bdytail + bdy * adxtail) + - (ady * bdxtail + bdx * adytail)) + + cdztail * (adx * bdy - ady * bdx)); + if ((det >= errbound) || (-det >= errbound)) { + return det; + } + + finnow = fin1; + finother = fin2; + + if (adxtail == 0.0) { + if (adytail == 0.0) { + at_b[0] = 0.0; + at_blen = 1; + at_c[0] = 0.0; + at_clen = 1; + } else { + negate = -adytail; + Two_Product(negate, bdx, at_blarge, at_b[0]); + at_b[1] = at_blarge; + at_blen = 2; + Two_Product(adytail, cdx, at_clarge, at_c[0]); + at_c[1] = at_clarge; + at_clen = 2; + } + } else { + if (adytail == 0.0) { + Two_Product(adxtail, bdy, at_blarge, at_b[0]); + at_b[1] = at_blarge; + at_blen = 2; + negate = -adxtail; + Two_Product(negate, cdy, at_clarge, at_c[0]); + at_c[1] = at_clarge; + at_clen = 2; + } else { + Two_Product(adxtail, bdy, adxt_bdy1, adxt_bdy0); + Two_Product(adytail, bdx, adyt_bdx1, adyt_bdx0); + Two_Two_Diff(adxt_bdy1, adxt_bdy0, adyt_bdx1, adyt_bdx0, + at_blarge, at_b[2], at_b[1], at_b[0]); + at_b[3] = at_blarge; + at_blen = 4; + Two_Product(adytail, cdx, adyt_cdx1, adyt_cdx0); + Two_Product(adxtail, cdy, adxt_cdy1, adxt_cdy0); + Two_Two_Diff(adyt_cdx1, adyt_cdx0, adxt_cdy1, adxt_cdy0, + at_clarge, at_c[2], at_c[1], at_c[0]); + at_c[3] = at_clarge; + at_clen = 4; + } + } + if (bdxtail == 0.0) { + if (bdytail == 0.0) { + bt_c[0] = 0.0; + bt_clen = 1; + bt_a[0] = 0.0; + bt_alen = 1; + } else { + negate = -bdytail; + Two_Product(negate, cdx, bt_clarge, bt_c[0]); + bt_c[1] = bt_clarge; + bt_clen = 2; + Two_Product(bdytail, adx, bt_alarge, bt_a[0]); + bt_a[1] = bt_alarge; + bt_alen = 2; + } + } else { + if (bdytail == 0.0) { + Two_Product(bdxtail, cdy, bt_clarge, bt_c[0]); + bt_c[1] = bt_clarge; + bt_clen = 2; + negate = -bdxtail; + Two_Product(negate, ady, bt_alarge, bt_a[0]); + bt_a[1] = bt_alarge; + bt_alen = 2; + } else { + Two_Product(bdxtail, cdy, bdxt_cdy1, bdxt_cdy0); + Two_Product(bdytail, cdx, bdyt_cdx1, bdyt_cdx0); + Two_Two_Diff(bdxt_cdy1, bdxt_cdy0, bdyt_cdx1, bdyt_cdx0, + bt_clarge, bt_c[2], bt_c[1], bt_c[0]); + bt_c[3] = bt_clarge; + bt_clen = 4; + Two_Product(bdytail, adx, bdyt_adx1, bdyt_adx0); + Two_Product(bdxtail, ady, bdxt_ady1, bdxt_ady0); + Two_Two_Diff(bdyt_adx1, bdyt_adx0, bdxt_ady1, bdxt_ady0, + bt_alarge, bt_a[2], bt_a[1], bt_a[0]); + bt_a[3] = bt_alarge; + bt_alen = 4; + } + } + if (cdxtail == 0.0) { + if (cdytail == 0.0) { + ct_a[0] = 0.0; + ct_alen = 1; + ct_b[0] = 0.0; + ct_blen = 1; + } else { + negate = -cdytail; + Two_Product(negate, adx, ct_alarge, ct_a[0]); + ct_a[1] = ct_alarge; + ct_alen = 2; + Two_Product(cdytail, bdx, ct_blarge, ct_b[0]); + ct_b[1] = ct_blarge; + ct_blen = 2; + } + } else { + if (cdytail == 0.0) { + Two_Product(cdxtail, ady, ct_alarge, ct_a[0]); + ct_a[1] = ct_alarge; + ct_alen = 2; + negate = -cdxtail; + Two_Product(negate, bdy, ct_blarge, ct_b[0]); + ct_b[1] = ct_blarge; + ct_blen = 2; + } else { + Two_Product(cdxtail, ady, cdxt_ady1, cdxt_ady0); + Two_Product(cdytail, adx, cdyt_adx1, cdyt_adx0); + Two_Two_Diff(cdxt_ady1, cdxt_ady0, cdyt_adx1, cdyt_adx0, + ct_alarge, ct_a[2], ct_a[1], ct_a[0]); + ct_a[3] = ct_alarge; + ct_alen = 4; + Two_Product(cdytail, bdx, cdyt_bdx1, cdyt_bdx0); + Two_Product(cdxtail, bdy, cdxt_bdy1, cdxt_bdy0); + Two_Two_Diff(cdyt_bdx1, cdyt_bdx0, cdxt_bdy1, cdxt_bdy0, + ct_blarge, ct_b[2], ct_b[1], ct_b[0]); + ct_b[3] = ct_blarge; + ct_blen = 4; + } + } + + bctlen = fast_expansion_sum_zeroelim(bt_clen, bt_c, ct_blen, ct_b, bct); + wlength = scale_expansion_zeroelim(bctlen, bct, adz, w); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, wlength, w, + finother); + finswap = finnow; finnow = finother; finother = finswap; + + catlen = fast_expansion_sum_zeroelim(ct_alen, ct_a, at_clen, at_c, cat); + wlength = scale_expansion_zeroelim(catlen, cat, bdz, w); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, wlength, w, + finother); + finswap = finnow; finnow = finother; finother = finswap; + + abtlen = fast_expansion_sum_zeroelim(at_blen, at_b, bt_alen, bt_a, abt); + wlength = scale_expansion_zeroelim(abtlen, abt, cdz, w); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, wlength, w, + finother); + finswap = finnow; finnow = finother; finother = finswap; + + if (adztail != 0.0) { + vlength = scale_expansion_zeroelim(4, bc, adztail, v); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, vlength, v, + finother); + finswap = finnow; finnow = finother; finother = finswap; + } + if (bdztail != 0.0) { + vlength = scale_expansion_zeroelim(4, ca, bdztail, v); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, vlength, v, + finother); + finswap = finnow; finnow = finother; finother = finswap; + } + if (cdztail != 0.0) { + vlength = scale_expansion_zeroelim(4, ab, cdztail, v); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, vlength, v, + finother); + finswap = finnow; finnow = finother; finother = finswap; + } + + if (adxtail != 0.0) { + if (bdytail != 0.0) { + Two_Product(adxtail, bdytail, adxt_bdyt1, adxt_bdyt0); + Two_One_Product(adxt_bdyt1, adxt_bdyt0, cdz, u3, u[2], u[1], u[0]); + u[3] = u3; + finlength = fast_expansion_sum_zeroelim(finlength, finnow, 4, u, + finother); + finswap = finnow; finnow = finother; finother = finswap; + if (cdztail != 0.0) { + Two_One_Product(adxt_bdyt1, adxt_bdyt0, cdztail, u3, u[2], u[1], u[0]); + u[3] = u3; + finlength = fast_expansion_sum_zeroelim(finlength, finnow, 4, u, + finother); + finswap = finnow; finnow = finother; finother = finswap; + } + } + if (cdytail != 0.0) { + negate = -adxtail; + Two_Product(negate, cdytail, adxt_cdyt1, adxt_cdyt0); + Two_One_Product(adxt_cdyt1, adxt_cdyt0, bdz, u3, u[2], u[1], u[0]); + u[3] = u3; + finlength = fast_expansion_sum_zeroelim(finlength, finnow, 4, u, + finother); + finswap = finnow; finnow = finother; finother = finswap; + if (bdztail != 0.0) { + Two_One_Product(adxt_cdyt1, adxt_cdyt0, bdztail, u3, u[2], u[1], u[0]); + u[3] = u3; + finlength = fast_expansion_sum_zeroelim(finlength, finnow, 4, u, + finother); + finswap = finnow; finnow = finother; finother = finswap; + } + } + } + if (bdxtail != 0.0) { + if (cdytail != 0.0) { + Two_Product(bdxtail, cdytail, bdxt_cdyt1, bdxt_cdyt0); + Two_One_Product(bdxt_cdyt1, bdxt_cdyt0, adz, u3, u[2], u[1], u[0]); + u[3] = u3; + finlength = fast_expansion_sum_zeroelim(finlength, finnow, 4, u, + finother); + finswap = finnow; finnow = finother; finother = finswap; + if (adztail != 0.0) { + Two_One_Product(bdxt_cdyt1, bdxt_cdyt0, adztail, u3, u[2], u[1], u[0]); + u[3] = u3; + finlength = fast_expansion_sum_zeroelim(finlength, finnow, 4, u, + finother); + finswap = finnow; finnow = finother; finother = finswap; + } + } + if (adytail != 0.0) { + negate = -bdxtail; + Two_Product(negate, adytail, bdxt_adyt1, bdxt_adyt0); + Two_One_Product(bdxt_adyt1, bdxt_adyt0, cdz, u3, u[2], u[1], u[0]); + u[3] = u3; + finlength = fast_expansion_sum_zeroelim(finlength, finnow, 4, u, + finother); + finswap = finnow; finnow = finother; finother = finswap; + if (cdztail != 0.0) { + Two_One_Product(bdxt_adyt1, bdxt_adyt0, cdztail, u3, u[2], u[1], u[0]); + u[3] = u3; + finlength = fast_expansion_sum_zeroelim(finlength, finnow, 4, u, + finother); + finswap = finnow; finnow = finother; finother = finswap; + } + } + } + if (cdxtail != 0.0) { + if (adytail != 0.0) { + Two_Product(cdxtail, adytail, cdxt_adyt1, cdxt_adyt0); + Two_One_Product(cdxt_adyt1, cdxt_adyt0, bdz, u3, u[2], u[1], u[0]); + u[3] = u3; + finlength = fast_expansion_sum_zeroelim(finlength, finnow, 4, u, + finother); + finswap = finnow; finnow = finother; finother = finswap; + if (bdztail != 0.0) { + Two_One_Product(cdxt_adyt1, cdxt_adyt0, bdztail, u3, u[2], u[1], u[0]); + u[3] = u3; + finlength = fast_expansion_sum_zeroelim(finlength, finnow, 4, u, + finother); + finswap = finnow; finnow = finother; finother = finswap; + } + } + if (bdytail != 0.0) { + negate = -cdxtail; + Two_Product(negate, bdytail, cdxt_bdyt1, cdxt_bdyt0); + Two_One_Product(cdxt_bdyt1, cdxt_bdyt0, adz, u3, u[2], u[1], u[0]); + u[3] = u3; + finlength = fast_expansion_sum_zeroelim(finlength, finnow, 4, u, + finother); + finswap = finnow; finnow = finother; finother = finswap; + if (adztail != 0.0) { + Two_One_Product(cdxt_bdyt1, cdxt_bdyt0, adztail, u3, u[2], u[1], u[0]); + u[3] = u3; + finlength = fast_expansion_sum_zeroelim(finlength, finnow, 4, u, + finother); + finswap = finnow; finnow = finother; finother = finswap; + } + } + } + + if (adztail != 0.0) { + wlength = scale_expansion_zeroelim(bctlen, bct, adztail, w); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, wlength, w, + finother); + finswap = finnow; finnow = finother; finother = finswap; + } + if (bdztail != 0.0) { + wlength = scale_expansion_zeroelim(catlen, cat, bdztail, w); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, wlength, w, + finother); + finswap = finnow; finnow = finother; finother = finswap; + } + if (cdztail != 0.0) { + wlength = scale_expansion_zeroelim(abtlen, abt, cdztail, w); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, wlength, w, + finother); + finswap = finnow; finnow = finother; finother = finswap; + } + + return finnow[finlength - 1]; +} + +REAL orient3d(REAL *pa, REAL *pb, REAL *pc, REAL *pd) +{ + REAL adx, bdx, cdx, ady, bdy, cdy, adz, bdz, cdz; + REAL bdxcdy, cdxbdy, cdxady, adxcdy, adxbdy, bdxady; + REAL det; + REAL permanent, errbound; + + adx = pa[0] - pd[0]; + bdx = pb[0] - pd[0]; + cdx = pc[0] - pd[0]; + ady = pa[1] - pd[1]; + bdy = pb[1] - pd[1]; + cdy = pc[1] - pd[1]; + adz = pa[2] - pd[2]; + bdz = pb[2] - pd[2]; + cdz = pc[2] - pd[2]; + + bdxcdy = bdx * cdy; + cdxbdy = cdx * bdy; + + cdxady = cdx * ady; + adxcdy = adx * cdy; + + adxbdy = adx * bdy; + bdxady = bdx * ady; + + det = adz * (bdxcdy - cdxbdy) + + bdz * (cdxady - adxcdy) + + cdz * (adxbdy - bdxady); + + permanent = (Absolute(bdxcdy) + Absolute(cdxbdy)) * Absolute(adz) + + (Absolute(cdxady) + Absolute(adxcdy)) * Absolute(bdz) + + (Absolute(adxbdy) + Absolute(bdxady)) * Absolute(cdz); + errbound = o3derrboundA * permanent; + if ((det > errbound) || (-det > errbound)) { + return det; + } + + return orient3dadapt(pa, pb, pc, pd, permanent); +} + +/*****************************************************************************/ +/* */ +/* incirclefast() Approximate 2D incircle test. Nonrobust. */ +/* incircleexact() Exact 2D incircle test. Robust. */ +/* incircleslow() Another exact 2D incircle test. Robust. */ +/* incircle() Adaptive exact 2D incircle test. Robust. */ +/* */ +/* Return a positive value if the point pd lies inside the */ +/* circle passing through pa, pb, and pc; a negative value if */ +/* it lies outside; and zero if the four points are cocircular.*/ +/* The points pa, pb, and pc must be in counterclockwise */ +/* order, or the sign of the result will be reversed. */ +/* */ +/* Only the first and last routine should be used; the middle two are for */ +/* timings. */ +/* */ +/* The last three use exact arithmetic to ensure a correct answer. The */ +/* result returned is the determinant of a matrix. In incircle() only, */ +/* this determinant is computed adaptively, in the sense that exact */ +/* arithmetic is used only to the degree it is needed to ensure that the */ +/* returned value has the correct sign. Hence, incircle() is usually quite */ +/* fast, but will run more slowly when the input points are cocircular or */ +/* nearly so. */ +/* */ +/*****************************************************************************/ + +REAL incirclefast(REAL *pa, REAL *pb, REAL *pc, REAL *pd) +{ + REAL adx, ady, bdx, bdy, cdx, cdy; + REAL abdet, bcdet, cadet; + REAL alift, blift, clift; + + adx = pa[0] - pd[0]; + ady = pa[1] - pd[1]; + bdx = pb[0] - pd[0]; + bdy = pb[1] - pd[1]; + cdx = pc[0] - pd[0]; + cdy = pc[1] - pd[1]; + + abdet = adx * bdy - bdx * ady; + bcdet = bdx * cdy - cdx * bdy; + cadet = cdx * ady - adx * cdy; + alift = adx * adx + ady * ady; + blift = bdx * bdx + bdy * bdy; + clift = cdx * cdx + cdy * cdy; + + return alift * bcdet + blift * cadet + clift * abdet; +} + +REAL incircleexact(REAL *pa, REAL *pb, REAL *pc, REAL *pd) +{ + INEXACT REAL axby1, bxcy1, cxdy1, dxay1, axcy1, bxdy1; + INEXACT REAL bxay1, cxby1, dxcy1, axdy1, cxay1, dxby1; + REAL axby0, bxcy0, cxdy0, dxay0, axcy0, bxdy0; + REAL bxay0, cxby0, dxcy0, axdy0, cxay0, dxby0; + REAL ab[4], bc[4], cd[4], da[4], ac[4], bd[4]; + REAL temp8[8]; + int templen; + REAL abc[12], bcd[12], cda[12], dab[12]; + int abclen, bcdlen, cdalen, dablen; + REAL det24x[24], det24y[24], det48x[48], det48y[48]; + int xlen, ylen; + REAL adet[96], bdet[96], cdet[96], ddet[96]; + int alen, blen, clen, dlen; + REAL abdet[192], cddet[192]; + int ablen, cdlen; + REAL deter[384]; + int deterlen; + int i; + + INEXACT REAL bvirt; + REAL avirt, bround, around; + INEXACT REAL c; + INEXACT REAL abig; + REAL ahi, alo, bhi, blo; + REAL err1, err2, err3; + INEXACT REAL _i, _j; + REAL _0; + + Two_Product(pa[0], pb[1], axby1, axby0); + Two_Product(pb[0], pa[1], bxay1, bxay0); + Two_Two_Diff(axby1, axby0, bxay1, bxay0, ab[3], ab[2], ab[1], ab[0]); + + Two_Product(pb[0], pc[1], bxcy1, bxcy0); + Two_Product(pc[0], pb[1], cxby1, cxby0); + Two_Two_Diff(bxcy1, bxcy0, cxby1, cxby0, bc[3], bc[2], bc[1], bc[0]); + + Two_Product(pc[0], pd[1], cxdy1, cxdy0); + Two_Product(pd[0], pc[1], dxcy1, dxcy0); + Two_Two_Diff(cxdy1, cxdy0, dxcy1, dxcy0, cd[3], cd[2], cd[1], cd[0]); + + Two_Product(pd[0], pa[1], dxay1, dxay0); + Two_Product(pa[0], pd[1], axdy1, axdy0); + Two_Two_Diff(dxay1, dxay0, axdy1, axdy0, da[3], da[2], da[1], da[0]); + + Two_Product(pa[0], pc[1], axcy1, axcy0); + Two_Product(pc[0], pa[1], cxay1, cxay0); + Two_Two_Diff(axcy1, axcy0, cxay1, cxay0, ac[3], ac[2], ac[1], ac[0]); + + Two_Product(pb[0], pd[1], bxdy1, bxdy0); + Two_Product(pd[0], pb[1], dxby1, dxby0); + Two_Two_Diff(bxdy1, bxdy0, dxby1, dxby0, bd[3], bd[2], bd[1], bd[0]); + + templen = fast_expansion_sum_zeroelim(4, cd, 4, da, temp8); + cdalen = fast_expansion_sum_zeroelim(templen, temp8, 4, ac, cda); + templen = fast_expansion_sum_zeroelim(4, da, 4, ab, temp8); + dablen = fast_expansion_sum_zeroelim(templen, temp8, 4, bd, dab); + for (i = 0; i < 4; i++) { + bd[i] = -bd[i]; + ac[i] = -ac[i]; + } + templen = fast_expansion_sum_zeroelim(4, ab, 4, bc, temp8); + abclen = fast_expansion_sum_zeroelim(templen, temp8, 4, ac, abc); + templen = fast_expansion_sum_zeroelim(4, bc, 4, cd, temp8); + bcdlen = fast_expansion_sum_zeroelim(templen, temp8, 4, bd, bcd); + + xlen = scale_expansion_zeroelim(bcdlen, bcd, pa[0], det24x); + xlen = scale_expansion_zeroelim(xlen, det24x, pa[0], det48x); + ylen = scale_expansion_zeroelim(bcdlen, bcd, pa[1], det24y); + ylen = scale_expansion_zeroelim(ylen, det24y, pa[1], det48y); + alen = fast_expansion_sum_zeroelim(xlen, det48x, ylen, det48y, adet); + + xlen = scale_expansion_zeroelim(cdalen, cda, pb[0], det24x); + xlen = scale_expansion_zeroelim(xlen, det24x, -pb[0], det48x); + ylen = scale_expansion_zeroelim(cdalen, cda, pb[1], det24y); + ylen = scale_expansion_zeroelim(ylen, det24y, -pb[1], det48y); + blen = fast_expansion_sum_zeroelim(xlen, det48x, ylen, det48y, bdet); + + xlen = scale_expansion_zeroelim(dablen, dab, pc[0], det24x); + xlen = scale_expansion_zeroelim(xlen, det24x, pc[0], det48x); + ylen = scale_expansion_zeroelim(dablen, dab, pc[1], det24y); + ylen = scale_expansion_zeroelim(ylen, det24y, pc[1], det48y); + clen = fast_expansion_sum_zeroelim(xlen, det48x, ylen, det48y, cdet); + + xlen = scale_expansion_zeroelim(abclen, abc, pd[0], det24x); + xlen = scale_expansion_zeroelim(xlen, det24x, -pd[0], det48x); + ylen = scale_expansion_zeroelim(abclen, abc, pd[1], det24y); + ylen = scale_expansion_zeroelim(ylen, det24y, -pd[1], det48y); + dlen = fast_expansion_sum_zeroelim(xlen, det48x, ylen, det48y, ddet); + + ablen = fast_expansion_sum_zeroelim(alen, adet, blen, bdet, abdet); + cdlen = fast_expansion_sum_zeroelim(clen, cdet, dlen, ddet, cddet); + deterlen = fast_expansion_sum_zeroelim(ablen, abdet, cdlen, cddet, deter); + + return deter[deterlen - 1]; +} + +REAL incircleslow(REAL *pa, REAL *pb, REAL *pc, REAL *pd) +{ + INEXACT REAL adx, bdx, cdx, ady, bdy, cdy; + REAL adxtail, bdxtail, cdxtail; + REAL adytail, bdytail, cdytail; + REAL negate, negatetail; + INEXACT REAL axby7, bxcy7, axcy7, bxay7, cxby7, cxay7; + REAL axby[8], bxcy[8], axcy[8], bxay[8], cxby[8], cxay[8]; + REAL temp16[16]; + int temp16len; + REAL detx[32], detxx[64], detxt[32], detxxt[64], detxtxt[64]; + int xlen, xxlen, xtlen, xxtlen, xtxtlen; + REAL x1[128], x2[192]; + int x1len, x2len; + REAL dety[32], detyy[64], detyt[32], detyyt[64], detytyt[64]; + int ylen, yylen, ytlen, yytlen, ytytlen; + REAL y1[128], y2[192]; + int y1len, y2len; + REAL adet[384], bdet[384], cdet[384], abdet[768], deter[1152]; + int alen, blen, clen, ablen, deterlen; + int i; + + INEXACT REAL bvirt; + REAL avirt, bround, around; + INEXACT REAL c; + INEXACT REAL abig; + REAL a0hi, a0lo, a1hi, a1lo, bhi, blo; + REAL err1, err2, err3; + INEXACT REAL _i, _j, _k, _l, _m, _n; + REAL _0, _1, _2; + + Two_Diff(pa[0], pd[0], adx, adxtail); + Two_Diff(pa[1], pd[1], ady, adytail); + Two_Diff(pb[0], pd[0], bdx, bdxtail); + Two_Diff(pb[1], pd[1], bdy, bdytail); + Two_Diff(pc[0], pd[0], cdx, cdxtail); + Two_Diff(pc[1], pd[1], cdy, cdytail); + + Two_Two_Product(adx, adxtail, bdy, bdytail, + axby7, axby[6], axby[5], axby[4], + axby[3], axby[2], axby[1], axby[0]); + axby[7] = axby7; + negate = -ady; + negatetail = -adytail; + Two_Two_Product(bdx, bdxtail, negate, negatetail, + bxay7, bxay[6], bxay[5], bxay[4], + bxay[3], bxay[2], bxay[1], bxay[0]); + bxay[7] = bxay7; + Two_Two_Product(bdx, bdxtail, cdy, cdytail, + bxcy7, bxcy[6], bxcy[5], bxcy[4], + bxcy[3], bxcy[2], bxcy[1], bxcy[0]); + bxcy[7] = bxcy7; + negate = -bdy; + negatetail = -bdytail; + Two_Two_Product(cdx, cdxtail, negate, negatetail, + cxby7, cxby[6], cxby[5], cxby[4], + cxby[3], cxby[2], cxby[1], cxby[0]); + cxby[7] = cxby7; + Two_Two_Product(cdx, cdxtail, ady, adytail, + cxay7, cxay[6], cxay[5], cxay[4], + cxay[3], cxay[2], cxay[1], cxay[0]); + cxay[7] = cxay7; + negate = -cdy; + negatetail = -cdytail; + Two_Two_Product(adx, adxtail, negate, negatetail, + axcy7, axcy[6], axcy[5], axcy[4], + axcy[3], axcy[2], axcy[1], axcy[0]); + axcy[7] = axcy7; + + + temp16len = fast_expansion_sum_zeroelim(8, bxcy, 8, cxby, temp16); + + xlen = scale_expansion_zeroelim(temp16len, temp16, adx, detx); + xxlen = scale_expansion_zeroelim(xlen, detx, adx, detxx); + xtlen = scale_expansion_zeroelim(temp16len, temp16, adxtail, detxt); + xxtlen = scale_expansion_zeroelim(xtlen, detxt, adx, detxxt); + for (i = 0; i < xxtlen; i++) { + detxxt[i] *= 2.0; + } + xtxtlen = scale_expansion_zeroelim(xtlen, detxt, adxtail, detxtxt); + x1len = fast_expansion_sum_zeroelim(xxlen, detxx, xxtlen, detxxt, x1); + x2len = fast_expansion_sum_zeroelim(x1len, x1, xtxtlen, detxtxt, x2); + + ylen = scale_expansion_zeroelim(temp16len, temp16, ady, dety); + yylen = scale_expansion_zeroelim(ylen, dety, ady, detyy); + ytlen = scale_expansion_zeroelim(temp16len, temp16, adytail, detyt); + yytlen = scale_expansion_zeroelim(ytlen, detyt, ady, detyyt); + for (i = 0; i < yytlen; i++) { + detyyt[i] *= 2.0; + } + ytytlen = scale_expansion_zeroelim(ytlen, detyt, adytail, detytyt); + y1len = fast_expansion_sum_zeroelim(yylen, detyy, yytlen, detyyt, y1); + y2len = fast_expansion_sum_zeroelim(y1len, y1, ytytlen, detytyt, y2); + + alen = fast_expansion_sum_zeroelim(x2len, x2, y2len, y2, adet); + + + temp16len = fast_expansion_sum_zeroelim(8, cxay, 8, axcy, temp16); + + xlen = scale_expansion_zeroelim(temp16len, temp16, bdx, detx); + xxlen = scale_expansion_zeroelim(xlen, detx, bdx, detxx); + xtlen = scale_expansion_zeroelim(temp16len, temp16, bdxtail, detxt); + xxtlen = scale_expansion_zeroelim(xtlen, detxt, bdx, detxxt); + for (i = 0; i < xxtlen; i++) { + detxxt[i] *= 2.0; + } + xtxtlen = scale_expansion_zeroelim(xtlen, detxt, bdxtail, detxtxt); + x1len = fast_expansion_sum_zeroelim(xxlen, detxx, xxtlen, detxxt, x1); + x2len = fast_expansion_sum_zeroelim(x1len, x1, xtxtlen, detxtxt, x2); + + ylen = scale_expansion_zeroelim(temp16len, temp16, bdy, dety); + yylen = scale_expansion_zeroelim(ylen, dety, bdy, detyy); + ytlen = scale_expansion_zeroelim(temp16len, temp16, bdytail, detyt); + yytlen = scale_expansion_zeroelim(ytlen, detyt, bdy, detyyt); + for (i = 0; i < yytlen; i++) { + detyyt[i] *= 2.0; + } + ytytlen = scale_expansion_zeroelim(ytlen, detyt, bdytail, detytyt); + y1len = fast_expansion_sum_zeroelim(yylen, detyy, yytlen, detyyt, y1); + y2len = fast_expansion_sum_zeroelim(y1len, y1, ytytlen, detytyt, y2); + + blen = fast_expansion_sum_zeroelim(x2len, x2, y2len, y2, bdet); + + + temp16len = fast_expansion_sum_zeroelim(8, axby, 8, bxay, temp16); + + xlen = scale_expansion_zeroelim(temp16len, temp16, cdx, detx); + xxlen = scale_expansion_zeroelim(xlen, detx, cdx, detxx); + xtlen = scale_expansion_zeroelim(temp16len, temp16, cdxtail, detxt); + xxtlen = scale_expansion_zeroelim(xtlen, detxt, cdx, detxxt); + for (i = 0; i < xxtlen; i++) { + detxxt[i] *= 2.0; + } + xtxtlen = scale_expansion_zeroelim(xtlen, detxt, cdxtail, detxtxt); + x1len = fast_expansion_sum_zeroelim(xxlen, detxx, xxtlen, detxxt, x1); + x2len = fast_expansion_sum_zeroelim(x1len, x1, xtxtlen, detxtxt, x2); + + ylen = scale_expansion_zeroelim(temp16len, temp16, cdy, dety); + yylen = scale_expansion_zeroelim(ylen, dety, cdy, detyy); + ytlen = scale_expansion_zeroelim(temp16len, temp16, cdytail, detyt); + yytlen = scale_expansion_zeroelim(ytlen, detyt, cdy, detyyt); + for (i = 0; i < yytlen; i++) { + detyyt[i] *= 2.0; + } + ytytlen = scale_expansion_zeroelim(ytlen, detyt, cdytail, detytyt); + y1len = fast_expansion_sum_zeroelim(yylen, detyy, yytlen, detyyt, y1); + y2len = fast_expansion_sum_zeroelim(y1len, y1, ytytlen, detytyt, y2); + + clen = fast_expansion_sum_zeroelim(x2len, x2, y2len, y2, cdet); + + ablen = fast_expansion_sum_zeroelim(alen, adet, blen, bdet, abdet); + deterlen = fast_expansion_sum_zeroelim(ablen, abdet, clen, cdet, deter); + + return deter[deterlen - 1]; +} + +REAL incircleadapt(REAL *pa, REAL *pb, REAL *pc, REAL *pd, REAL permanent) +{ + INEXACT REAL adx, bdx, cdx, ady, bdy, cdy; + REAL det, errbound; + + INEXACT REAL bdxcdy1, cdxbdy1, cdxady1, adxcdy1, adxbdy1, bdxady1; + REAL bdxcdy0, cdxbdy0, cdxady0, adxcdy0, adxbdy0, bdxady0; + REAL bc[4], ca[4], ab[4]; + INEXACT REAL bc3, ca3, ab3; + REAL axbc[8], axxbc[16], aybc[8], ayybc[16], adet[32]; + int axbclen, axxbclen, aybclen, ayybclen, alen; + REAL bxca[8], bxxca[16], byca[8], byyca[16], bdet[32]; + int bxcalen, bxxcalen, bycalen, byycalen, blen; + REAL cxab[8], cxxab[16], cyab[8], cyyab[16], cdet[32]; + int cxablen, cxxablen, cyablen, cyyablen, clen; + REAL abdet[64]; + int ablen; + REAL fin1[1152], fin2[1152]; + REAL *finnow, *finother, *finswap; + int finlength; + + REAL adxtail, bdxtail, cdxtail, adytail, bdytail, cdytail; + INEXACT REAL adxadx1, adyady1, bdxbdx1, bdybdy1, cdxcdx1, cdycdy1; + REAL adxadx0, adyady0, bdxbdx0, bdybdy0, cdxcdx0, cdycdy0; + REAL aa[4], bb[4], cc[4]; + INEXACT REAL aa3, bb3, cc3; + INEXACT REAL ti1, tj1; + REAL ti0, tj0; + REAL u[4], v[4]; + INEXACT REAL u3, v3; + REAL temp8[8], temp16a[16], temp16b[16], temp16c[16]; + REAL temp32a[32], temp32b[32], temp48[48], temp64[64]; + int temp8len, temp16alen, temp16blen, temp16clen; + int temp32alen, temp32blen, temp48len, temp64len; + REAL axtbb[8], axtcc[8], aytbb[8], aytcc[8]; + int axtbblen, axtcclen, aytbblen, aytcclen; + REAL bxtaa[8], bxtcc[8], bytaa[8], bytcc[8]; + int bxtaalen, bxtcclen, bytaalen, bytcclen; + REAL cxtaa[8], cxtbb[8], cytaa[8], cytbb[8]; + int cxtaalen, cxtbblen, cytaalen, cytbblen; + REAL axtbc[8], aytbc[8], bxtca[8], bytca[8], cxtab[8], cytab[8]; + int axtbclen, aytbclen, bxtcalen, bytcalen, cxtablen, cytablen; + REAL axtbct[16], aytbct[16], bxtcat[16], bytcat[16], cxtabt[16], cytabt[16]; + int axtbctlen, aytbctlen, bxtcatlen, bytcatlen, cxtabtlen, cytabtlen; + REAL axtbctt[8], aytbctt[8], bxtcatt[8]; + REAL bytcatt[8], cxtabtt[8], cytabtt[8]; + int axtbcttlen, aytbcttlen, bxtcattlen, bytcattlen, cxtabttlen, cytabttlen; + REAL abt[8], bct[8], cat[8]; + int abtlen, bctlen, catlen; + REAL abtt[4], bctt[4], catt[4]; + int abttlen, bcttlen, cattlen; + INEXACT REAL abtt3, bctt3, catt3; + REAL negate; + + INEXACT REAL bvirt; + REAL avirt, bround, around; + INEXACT REAL c; + INEXACT REAL abig; + REAL ahi, alo, bhi, blo; + REAL err1, err2, err3; + INEXACT REAL _i, _j; + REAL _0; + + adx = (REAL) (pa[0] - pd[0]); + bdx = (REAL) (pb[0] - pd[0]); + cdx = (REAL) (pc[0] - pd[0]); + ady = (REAL) (pa[1] - pd[1]); + bdy = (REAL) (pb[1] - pd[1]); + cdy = (REAL) (pc[1] - pd[1]); + + Two_Product(bdx, cdy, bdxcdy1, bdxcdy0); + Two_Product(cdx, bdy, cdxbdy1, cdxbdy0); + Two_Two_Diff(bdxcdy1, bdxcdy0, cdxbdy1, cdxbdy0, bc3, bc[2], bc[1], bc[0]); + bc[3] = bc3; + axbclen = scale_expansion_zeroelim(4, bc, adx, axbc); + axxbclen = scale_expansion_zeroelim(axbclen, axbc, adx, axxbc); + aybclen = scale_expansion_zeroelim(4, bc, ady, aybc); + ayybclen = scale_expansion_zeroelim(aybclen, aybc, ady, ayybc); + alen = fast_expansion_sum_zeroelim(axxbclen, axxbc, ayybclen, ayybc, adet); + + Two_Product(cdx, ady, cdxady1, cdxady0); + Two_Product(adx, cdy, adxcdy1, adxcdy0); + Two_Two_Diff(cdxady1, cdxady0, adxcdy1, adxcdy0, ca3, ca[2], ca[1], ca[0]); + ca[3] = ca3; + bxcalen = scale_expansion_zeroelim(4, ca, bdx, bxca); + bxxcalen = scale_expansion_zeroelim(bxcalen, bxca, bdx, bxxca); + bycalen = scale_expansion_zeroelim(4, ca, bdy, byca); + byycalen = scale_expansion_zeroelim(bycalen, byca, bdy, byyca); + blen = fast_expansion_sum_zeroelim(bxxcalen, bxxca, byycalen, byyca, bdet); + + Two_Product(adx, bdy, adxbdy1, adxbdy0); + Two_Product(bdx, ady, bdxady1, bdxady0); + Two_Two_Diff(adxbdy1, adxbdy0, bdxady1, bdxady0, ab3, ab[2], ab[1], ab[0]); + ab[3] = ab3; + cxablen = scale_expansion_zeroelim(4, ab, cdx, cxab); + cxxablen = scale_expansion_zeroelim(cxablen, cxab, cdx, cxxab); + cyablen = scale_expansion_zeroelim(4, ab, cdy, cyab); + cyyablen = scale_expansion_zeroelim(cyablen, cyab, cdy, cyyab); + clen = fast_expansion_sum_zeroelim(cxxablen, cxxab, cyyablen, cyyab, cdet); + + ablen = fast_expansion_sum_zeroelim(alen, adet, blen, bdet, abdet); + finlength = fast_expansion_sum_zeroelim(ablen, abdet, clen, cdet, fin1); + + det = estimate(finlength, fin1); + errbound = iccerrboundB * permanent; + if ((det >= errbound) || (-det >= errbound)) { + return det; + } + + Two_Diff_Tail(pa[0], pd[0], adx, adxtail); + Two_Diff_Tail(pa[1], pd[1], ady, adytail); + Two_Diff_Tail(pb[0], pd[0], bdx, bdxtail); + Two_Diff_Tail(pb[1], pd[1], bdy, bdytail); + Two_Diff_Tail(pc[0], pd[0], cdx, cdxtail); + Two_Diff_Tail(pc[1], pd[1], cdy, cdytail); + if ((adxtail == 0.0) && (bdxtail == 0.0) && (cdxtail == 0.0) + && (adytail == 0.0) && (bdytail == 0.0) && (cdytail == 0.0)) { + return det; + } + + errbound = iccerrboundC * permanent + resulterrbound * Absolute(det); + det += ((adx * adx + ady * ady) * ((bdx * cdytail + cdy * bdxtail) + - (bdy * cdxtail + cdx * bdytail)) + + 2.0 * (adx * adxtail + ady * adytail) * (bdx * cdy - bdy * cdx)) + + ((bdx * bdx + bdy * bdy) * ((cdx * adytail + ady * cdxtail) + - (cdy * adxtail + adx * cdytail)) + + 2.0 * (bdx * bdxtail + bdy * bdytail) * (cdx * ady - cdy * adx)) + + ((cdx * cdx + cdy * cdy) * ((adx * bdytail + bdy * adxtail) + - (ady * bdxtail + bdx * adytail)) + + 2.0 * (cdx * cdxtail + cdy * cdytail) * (adx * bdy - ady * bdx)); + if ((det >= errbound) || (-det >= errbound)) { + return det; + } + + finnow = fin1; + finother = fin2; + + if ((bdxtail != 0.0) || (bdytail != 0.0) + || (cdxtail != 0.0) || (cdytail != 0.0)) { + Square(adx, adxadx1, adxadx0); + Square(ady, adyady1, adyady0); + Two_Two_Sum(adxadx1, adxadx0, adyady1, adyady0, aa3, aa[2], aa[1], aa[0]); + aa[3] = aa3; + } + if ((cdxtail != 0.0) || (cdytail != 0.0) + || (adxtail != 0.0) || (adytail != 0.0)) { + Square(bdx, bdxbdx1, bdxbdx0); + Square(bdy, bdybdy1, bdybdy0); + Two_Two_Sum(bdxbdx1, bdxbdx0, bdybdy1, bdybdy0, bb3, bb[2], bb[1], bb[0]); + bb[3] = bb3; + } + if ((adxtail != 0.0) || (adytail != 0.0) + || (bdxtail != 0.0) || (bdytail != 0.0)) { + Square(cdx, cdxcdx1, cdxcdx0); + Square(cdy, cdycdy1, cdycdy0); + Two_Two_Sum(cdxcdx1, cdxcdx0, cdycdy1, cdycdy0, cc3, cc[2], cc[1], cc[0]); + cc[3] = cc3; + } + + if (adxtail != 0.0) { + axtbclen = scale_expansion_zeroelim(4, bc, adxtail, axtbc); + temp16alen = scale_expansion_zeroelim(axtbclen, axtbc, 2.0 * adx, + temp16a); + + axtcclen = scale_expansion_zeroelim(4, cc, adxtail, axtcc); + temp16blen = scale_expansion_zeroelim(axtcclen, axtcc, bdy, temp16b); + + axtbblen = scale_expansion_zeroelim(4, bb, adxtail, axtbb); + temp16clen = scale_expansion_zeroelim(axtbblen, axtbb, -cdy, temp16c); + + temp32alen = fast_expansion_sum_zeroelim(temp16alen, temp16a, + temp16blen, temp16b, temp32a); + temp48len = fast_expansion_sum_zeroelim(temp16clen, temp16c, + temp32alen, temp32a, temp48); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, + temp48, finother); + finswap = finnow; finnow = finother; finother = finswap; + } + if (adytail != 0.0) { + aytbclen = scale_expansion_zeroelim(4, bc, adytail, aytbc); + temp16alen = scale_expansion_zeroelim(aytbclen, aytbc, 2.0 * ady, + temp16a); + + aytbblen = scale_expansion_zeroelim(4, bb, adytail, aytbb); + temp16blen = scale_expansion_zeroelim(aytbblen, aytbb, cdx, temp16b); + + aytcclen = scale_expansion_zeroelim(4, cc, adytail, aytcc); + temp16clen = scale_expansion_zeroelim(aytcclen, aytcc, -bdx, temp16c); + + temp32alen = fast_expansion_sum_zeroelim(temp16alen, temp16a, + temp16blen, temp16b, temp32a); + temp48len = fast_expansion_sum_zeroelim(temp16clen, temp16c, + temp32alen, temp32a, temp48); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, + temp48, finother); + finswap = finnow; finnow = finother; finother = finswap; + } + if (bdxtail != 0.0) { + bxtcalen = scale_expansion_zeroelim(4, ca, bdxtail, bxtca); + temp16alen = scale_expansion_zeroelim(bxtcalen, bxtca, 2.0 * bdx, + temp16a); + + bxtaalen = scale_expansion_zeroelim(4, aa, bdxtail, bxtaa); + temp16blen = scale_expansion_zeroelim(bxtaalen, bxtaa, cdy, temp16b); + + bxtcclen = scale_expansion_zeroelim(4, cc, bdxtail, bxtcc); + temp16clen = scale_expansion_zeroelim(bxtcclen, bxtcc, -ady, temp16c); + + temp32alen = fast_expansion_sum_zeroelim(temp16alen, temp16a, + temp16blen, temp16b, temp32a); + temp48len = fast_expansion_sum_zeroelim(temp16clen, temp16c, + temp32alen, temp32a, temp48); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, + temp48, finother); + finswap = finnow; finnow = finother; finother = finswap; + } + if (bdytail != 0.0) { + bytcalen = scale_expansion_zeroelim(4, ca, bdytail, bytca); + temp16alen = scale_expansion_zeroelim(bytcalen, bytca, 2.0 * bdy, + temp16a); + + bytcclen = scale_expansion_zeroelim(4, cc, bdytail, bytcc); + temp16blen = scale_expansion_zeroelim(bytcclen, bytcc, adx, temp16b); + + bytaalen = scale_expansion_zeroelim(4, aa, bdytail, bytaa); + temp16clen = scale_expansion_zeroelim(bytaalen, bytaa, -cdx, temp16c); + + temp32alen = fast_expansion_sum_zeroelim(temp16alen, temp16a, + temp16blen, temp16b, temp32a); + temp48len = fast_expansion_sum_zeroelim(temp16clen, temp16c, + temp32alen, temp32a, temp48); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, + temp48, finother); + finswap = finnow; finnow = finother; finother = finswap; + } + if (cdxtail != 0.0) { + cxtablen = scale_expansion_zeroelim(4, ab, cdxtail, cxtab); + temp16alen = scale_expansion_zeroelim(cxtablen, cxtab, 2.0 * cdx, + temp16a); + + cxtbblen = scale_expansion_zeroelim(4, bb, cdxtail, cxtbb); + temp16blen = scale_expansion_zeroelim(cxtbblen, cxtbb, ady, temp16b); + + cxtaalen = scale_expansion_zeroelim(4, aa, cdxtail, cxtaa); + temp16clen = scale_expansion_zeroelim(cxtaalen, cxtaa, -bdy, temp16c); + + temp32alen = fast_expansion_sum_zeroelim(temp16alen, temp16a, + temp16blen, temp16b, temp32a); + temp48len = fast_expansion_sum_zeroelim(temp16clen, temp16c, + temp32alen, temp32a, temp48); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, + temp48, finother); + finswap = finnow; finnow = finother; finother = finswap; + } + if (cdytail != 0.0) { + cytablen = scale_expansion_zeroelim(4, ab, cdytail, cytab); + temp16alen = scale_expansion_zeroelim(cytablen, cytab, 2.0 * cdy, + temp16a); + + cytaalen = scale_expansion_zeroelim(4, aa, cdytail, cytaa); + temp16blen = scale_expansion_zeroelim(cytaalen, cytaa, bdx, temp16b); + + cytbblen = scale_expansion_zeroelim(4, bb, cdytail, cytbb); + temp16clen = scale_expansion_zeroelim(cytbblen, cytbb, -adx, temp16c); + + temp32alen = fast_expansion_sum_zeroelim(temp16alen, temp16a, + temp16blen, temp16b, temp32a); + temp48len = fast_expansion_sum_zeroelim(temp16clen, temp16c, + temp32alen, temp32a, temp48); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, + temp48, finother); + finswap = finnow; finnow = finother; finother = finswap; + } + + if ((adxtail != 0.0) || (adytail != 0.0)) { + if ((bdxtail != 0.0) || (bdytail != 0.0) + || (cdxtail != 0.0) || (cdytail != 0.0)) { + Two_Product(bdxtail, cdy, ti1, ti0); + Two_Product(bdx, cdytail, tj1, tj0); + Two_Two_Sum(ti1, ti0, tj1, tj0, u3, u[2], u[1], u[0]); + u[3] = u3; + negate = -bdy; + Two_Product(cdxtail, negate, ti1, ti0); + negate = -bdytail; + Two_Product(cdx, negate, tj1, tj0); + Two_Two_Sum(ti1, ti0, tj1, tj0, v3, v[2], v[1], v[0]); + v[3] = v3; + bctlen = fast_expansion_sum_zeroelim(4, u, 4, v, bct); + + Two_Product(bdxtail, cdytail, ti1, ti0); + Two_Product(cdxtail, bdytail, tj1, tj0); + Two_Two_Diff(ti1, ti0, tj1, tj0, bctt3, bctt[2], bctt[1], bctt[0]); + bctt[3] = bctt3; + bcttlen = 4; + } else { + bct[0] = 0.0; + bctlen = 1; + bctt[0] = 0.0; + bcttlen = 1; + } + + if (adxtail != 0.0) { + temp16alen = scale_expansion_zeroelim(axtbclen, axtbc, adxtail, temp16a); + axtbctlen = scale_expansion_zeroelim(bctlen, bct, adxtail, axtbct); + temp32alen = scale_expansion_zeroelim(axtbctlen, axtbct, 2.0 * adx, + temp32a); + temp48len = fast_expansion_sum_zeroelim(temp16alen, temp16a, + temp32alen, temp32a, temp48); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, + temp48, finother); + finswap = finnow; finnow = finother; finother = finswap; + if (bdytail != 0.0) { + temp8len = scale_expansion_zeroelim(4, cc, adxtail, temp8); + temp16alen = scale_expansion_zeroelim(temp8len, temp8, bdytail, + temp16a); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp16alen, + temp16a, finother); + finswap = finnow; finnow = finother; finother = finswap; + } + if (cdytail != 0.0) { + temp8len = scale_expansion_zeroelim(4, bb, -adxtail, temp8); + temp16alen = scale_expansion_zeroelim(temp8len, temp8, cdytail, + temp16a); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp16alen, + temp16a, finother); + finswap = finnow; finnow = finother; finother = finswap; + } + + temp32alen = scale_expansion_zeroelim(axtbctlen, axtbct, adxtail, + temp32a); + axtbcttlen = scale_expansion_zeroelim(bcttlen, bctt, adxtail, axtbctt); + temp16alen = scale_expansion_zeroelim(axtbcttlen, axtbctt, 2.0 * adx, + temp16a); + temp16blen = scale_expansion_zeroelim(axtbcttlen, axtbctt, adxtail, + temp16b); + temp32blen = fast_expansion_sum_zeroelim(temp16alen, temp16a, + temp16blen, temp16b, temp32b); + temp64len = fast_expansion_sum_zeroelim(temp32alen, temp32a, + temp32blen, temp32b, temp64); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp64len, + temp64, finother); + finswap = finnow; finnow = finother; finother = finswap; + } + if (adytail != 0.0) { + temp16alen = scale_expansion_zeroelim(aytbclen, aytbc, adytail, temp16a); + aytbctlen = scale_expansion_zeroelim(bctlen, bct, adytail, aytbct); + temp32alen = scale_expansion_zeroelim(aytbctlen, aytbct, 2.0 * ady, + temp32a); + temp48len = fast_expansion_sum_zeroelim(temp16alen, temp16a, + temp32alen, temp32a, temp48); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, + temp48, finother); + finswap = finnow; finnow = finother; finother = finswap; + + + temp32alen = scale_expansion_zeroelim(aytbctlen, aytbct, adytail, + temp32a); + aytbcttlen = scale_expansion_zeroelim(bcttlen, bctt, adytail, aytbctt); + temp16alen = scale_expansion_zeroelim(aytbcttlen, aytbctt, 2.0 * ady, + temp16a); + temp16blen = scale_expansion_zeroelim(aytbcttlen, aytbctt, adytail, + temp16b); + temp32blen = fast_expansion_sum_zeroelim(temp16alen, temp16a, + temp16blen, temp16b, temp32b); + temp64len = fast_expansion_sum_zeroelim(temp32alen, temp32a, + temp32blen, temp32b, temp64); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp64len, + temp64, finother); + finswap = finnow; finnow = finother; finother = finswap; + } + } + if ((bdxtail != 0.0) || (bdytail != 0.0)) { + if ((cdxtail != 0.0) || (cdytail != 0.0) + || (adxtail != 0.0) || (adytail != 0.0)) { + Two_Product(cdxtail, ady, ti1, ti0); + Two_Product(cdx, adytail, tj1, tj0); + Two_Two_Sum(ti1, ti0, tj1, tj0, u3, u[2], u[1], u[0]); + u[3] = u3; + negate = -cdy; + Two_Product(adxtail, negate, ti1, ti0); + negate = -cdytail; + Two_Product(adx, negate, tj1, tj0); + Two_Two_Sum(ti1, ti0, tj1, tj0, v3, v[2], v[1], v[0]); + v[3] = v3; + catlen = fast_expansion_sum_zeroelim(4, u, 4, v, cat); + + Two_Product(cdxtail, adytail, ti1, ti0); + Two_Product(adxtail, cdytail, tj1, tj0); + Two_Two_Diff(ti1, ti0, tj1, tj0, catt3, catt[2], catt[1], catt[0]); + catt[3] = catt3; + cattlen = 4; + } else { + cat[0] = 0.0; + catlen = 1; + catt[0] = 0.0; + cattlen = 1; + } + + if (bdxtail != 0.0) { + temp16alen = scale_expansion_zeroelim(bxtcalen, bxtca, bdxtail, temp16a); + bxtcatlen = scale_expansion_zeroelim(catlen, cat, bdxtail, bxtcat); + temp32alen = scale_expansion_zeroelim(bxtcatlen, bxtcat, 2.0 * bdx, + temp32a); + temp48len = fast_expansion_sum_zeroelim(temp16alen, temp16a, + temp32alen, temp32a, temp48); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, + temp48, finother); + finswap = finnow; finnow = finother; finother = finswap; + if (cdytail != 0.0) { + temp8len = scale_expansion_zeroelim(4, aa, bdxtail, temp8); + temp16alen = scale_expansion_zeroelim(temp8len, temp8, cdytail, + temp16a); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp16alen, + temp16a, finother); + finswap = finnow; finnow = finother; finother = finswap; + } + if (adytail != 0.0) { + temp8len = scale_expansion_zeroelim(4, cc, -bdxtail, temp8); + temp16alen = scale_expansion_zeroelim(temp8len, temp8, adytail, + temp16a); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp16alen, + temp16a, finother); + finswap = finnow; finnow = finother; finother = finswap; + } + + temp32alen = scale_expansion_zeroelim(bxtcatlen, bxtcat, bdxtail, + temp32a); + bxtcattlen = scale_expansion_zeroelim(cattlen, catt, bdxtail, bxtcatt); + temp16alen = scale_expansion_zeroelim(bxtcattlen, bxtcatt, 2.0 * bdx, + temp16a); + temp16blen = scale_expansion_zeroelim(bxtcattlen, bxtcatt, bdxtail, + temp16b); + temp32blen = fast_expansion_sum_zeroelim(temp16alen, temp16a, + temp16blen, temp16b, temp32b); + temp64len = fast_expansion_sum_zeroelim(temp32alen, temp32a, + temp32blen, temp32b, temp64); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp64len, + temp64, finother); + finswap = finnow; finnow = finother; finother = finswap; + } + if (bdytail != 0.0) { + temp16alen = scale_expansion_zeroelim(bytcalen, bytca, bdytail, temp16a); + bytcatlen = scale_expansion_zeroelim(catlen, cat, bdytail, bytcat); + temp32alen = scale_expansion_zeroelim(bytcatlen, bytcat, 2.0 * bdy, + temp32a); + temp48len = fast_expansion_sum_zeroelim(temp16alen, temp16a, + temp32alen, temp32a, temp48); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, + temp48, finother); + finswap = finnow; finnow = finother; finother = finswap; + + + temp32alen = scale_expansion_zeroelim(bytcatlen, bytcat, bdytail, + temp32a); + bytcattlen = scale_expansion_zeroelim(cattlen, catt, bdytail, bytcatt); + temp16alen = scale_expansion_zeroelim(bytcattlen, bytcatt, 2.0 * bdy, + temp16a); + temp16blen = scale_expansion_zeroelim(bytcattlen, bytcatt, bdytail, + temp16b); + temp32blen = fast_expansion_sum_zeroelim(temp16alen, temp16a, + temp16blen, temp16b, temp32b); + temp64len = fast_expansion_sum_zeroelim(temp32alen, temp32a, + temp32blen, temp32b, temp64); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp64len, + temp64, finother); + finswap = finnow; finnow = finother; finother = finswap; + } + } + if ((cdxtail != 0.0) || (cdytail != 0.0)) { + if ((adxtail != 0.0) || (adytail != 0.0) + || (bdxtail != 0.0) || (bdytail != 0.0)) { + Two_Product(adxtail, bdy, ti1, ti0); + Two_Product(adx, bdytail, tj1, tj0); + Two_Two_Sum(ti1, ti0, tj1, tj0, u3, u[2], u[1], u[0]); + u[3] = u3; + negate = -ady; + Two_Product(bdxtail, negate, ti1, ti0); + negate = -adytail; + Two_Product(bdx, negate, tj1, tj0); + Two_Two_Sum(ti1, ti0, tj1, tj0, v3, v[2], v[1], v[0]); + v[3] = v3; + abtlen = fast_expansion_sum_zeroelim(4, u, 4, v, abt); + + Two_Product(adxtail, bdytail, ti1, ti0); + Two_Product(bdxtail, adytail, tj1, tj0); + Two_Two_Diff(ti1, ti0, tj1, tj0, abtt3, abtt[2], abtt[1], abtt[0]); + abtt[3] = abtt3; + abttlen = 4; + } else { + abt[0] = 0.0; + abtlen = 1; + abtt[0] = 0.0; + abttlen = 1; + } + + if (cdxtail != 0.0) { + temp16alen = scale_expansion_zeroelim(cxtablen, cxtab, cdxtail, temp16a); + cxtabtlen = scale_expansion_zeroelim(abtlen, abt, cdxtail, cxtabt); + temp32alen = scale_expansion_zeroelim(cxtabtlen, cxtabt, 2.0 * cdx, + temp32a); + temp48len = fast_expansion_sum_zeroelim(temp16alen, temp16a, + temp32alen, temp32a, temp48); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, + temp48, finother); + finswap = finnow; finnow = finother; finother = finswap; + if (adytail != 0.0) { + temp8len = scale_expansion_zeroelim(4, bb, cdxtail, temp8); + temp16alen = scale_expansion_zeroelim(temp8len, temp8, adytail, + temp16a); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp16alen, + temp16a, finother); + finswap = finnow; finnow = finother; finother = finswap; + } + if (bdytail != 0.0) { + temp8len = scale_expansion_zeroelim(4, aa, -cdxtail, temp8); + temp16alen = scale_expansion_zeroelim(temp8len, temp8, bdytail, + temp16a); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp16alen, + temp16a, finother); + finswap = finnow; finnow = finother; finother = finswap; + } + + temp32alen = scale_expansion_zeroelim(cxtabtlen, cxtabt, cdxtail, + temp32a); + cxtabttlen = scale_expansion_zeroelim(abttlen, abtt, cdxtail, cxtabtt); + temp16alen = scale_expansion_zeroelim(cxtabttlen, cxtabtt, 2.0 * cdx, + temp16a); + temp16blen = scale_expansion_zeroelim(cxtabttlen, cxtabtt, cdxtail, + temp16b); + temp32blen = fast_expansion_sum_zeroelim(temp16alen, temp16a, + temp16blen, temp16b, temp32b); + temp64len = fast_expansion_sum_zeroelim(temp32alen, temp32a, + temp32blen, temp32b, temp64); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp64len, + temp64, finother); + finswap = finnow; finnow = finother; finother = finswap; + } + if (cdytail != 0.0) { + temp16alen = scale_expansion_zeroelim(cytablen, cytab, cdytail, temp16a); + cytabtlen = scale_expansion_zeroelim(abtlen, abt, cdytail, cytabt); + temp32alen = scale_expansion_zeroelim(cytabtlen, cytabt, 2.0 * cdy, + temp32a); + temp48len = fast_expansion_sum_zeroelim(temp16alen, temp16a, + temp32alen, temp32a, temp48); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, + temp48, finother); + finswap = finnow; finnow = finother; finother = finswap; + + + temp32alen = scale_expansion_zeroelim(cytabtlen, cytabt, cdytail, + temp32a); + cytabttlen = scale_expansion_zeroelim(abttlen, abtt, cdytail, cytabtt); + temp16alen = scale_expansion_zeroelim(cytabttlen, cytabtt, 2.0 * cdy, + temp16a); + temp16blen = scale_expansion_zeroelim(cytabttlen, cytabtt, cdytail, + temp16b); + temp32blen = fast_expansion_sum_zeroelim(temp16alen, temp16a, + temp16blen, temp16b, temp32b); + temp64len = fast_expansion_sum_zeroelim(temp32alen, temp32a, + temp32blen, temp32b, temp64); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp64len, + temp64, finother); + finswap = finnow; finnow = finother; finother = finswap; + } + } + + return finnow[finlength - 1]; +} + +REAL incircle(REAL *pa, REAL *pb, REAL *pc, REAL *pd) +{ + REAL adx, bdx, cdx, ady, bdy, cdy; + REAL bdxcdy, cdxbdy, cdxady, adxcdy, adxbdy, bdxady; + REAL alift, blift, clift; + REAL det; + REAL permanent, errbound; + + adx = pa[0] - pd[0]; + bdx = pb[0] - pd[0]; + cdx = pc[0] - pd[0]; + ady = pa[1] - pd[1]; + bdy = pb[1] - pd[1]; + cdy = pc[1] - pd[1]; + + bdxcdy = bdx * cdy; + cdxbdy = cdx * bdy; + alift = adx * adx + ady * ady; + + cdxady = cdx * ady; + adxcdy = adx * cdy; + blift = bdx * bdx + bdy * bdy; + + adxbdy = adx * bdy; + bdxady = bdx * ady; + clift = cdx * cdx + cdy * cdy; + + det = alift * (bdxcdy - cdxbdy) + + blift * (cdxady - adxcdy) + + clift * (adxbdy - bdxady); + + permanent = (Absolute(bdxcdy) + Absolute(cdxbdy)) * alift + + (Absolute(cdxady) + Absolute(adxcdy)) * blift + + (Absolute(adxbdy) + Absolute(bdxady)) * clift; + errbound = iccerrboundA * permanent; + if ((det > errbound) || (-det > errbound)) { + return det; + } + + return incircleadapt(pa, pb, pc, pd, permanent); +} + +/*****************************************************************************/ +/* */ +/* inspherefast() Approximate 3D insphere test. Nonrobust. */ +/* insphereexact() Exact 3D insphere test. Robust. */ +/* insphereslow() Another exact 3D insphere test. Robust. */ +/* insphere() Adaptive exact 3D insphere test. Robust. */ +/* */ +/* Return a positive value if the point pe lies inside the */ +/* sphere passing through pa, pb, pc, and pd; a negative value */ +/* if it lies outside; and zero if the five points are */ +/* cospherical. The points pa, pb, pc, and pd must be ordered */ +/* so that they have a positive orientation (as defined by */ +/* orient3d()), or the sign of the result will be reversed. */ +/* */ +/* Only the first and last routine should be used; the middle two are for */ +/* timings. */ +/* */ +/* The last three use exact arithmetic to ensure a correct answer. The */ +/* result returned is the determinant of a matrix. In insphere() only, */ +/* this determinant is computed adaptively, in the sense that exact */ +/* arithmetic is used only to the degree it is needed to ensure that the */ +/* returned value has the correct sign. Hence, insphere() is usually quite */ +/* fast, but will run more slowly when the input points are cospherical or */ +/* nearly so. */ +/* */ +/*****************************************************************************/ + +REAL inspherefast(REAL *pa, REAL *pb, REAL *pc, REAL *pd, REAL *pe) +{ + REAL aex, bex, cex, dex; + REAL aey, bey, cey, dey; + REAL aez, bez, cez, dez; + REAL alift, blift, clift, dlift; + REAL ab, bc, cd, da, ac, bd; + REAL abc, bcd, cda, dab; + + aex = pa[0] - pe[0]; + bex = pb[0] - pe[0]; + cex = pc[0] - pe[0]; + dex = pd[0] - pe[0]; + aey = pa[1] - pe[1]; + bey = pb[1] - pe[1]; + cey = pc[1] - pe[1]; + dey = pd[1] - pe[1]; + aez = pa[2] - pe[2]; + bez = pb[2] - pe[2]; + cez = pc[2] - pe[2]; + dez = pd[2] - pe[2]; + + ab = aex * bey - bex * aey; + bc = bex * cey - cex * bey; + cd = cex * dey - dex * cey; + da = dex * aey - aex * dey; + + ac = aex * cey - cex * aey; + bd = bex * dey - dex * bey; + + abc = aez * bc - bez * ac + cez * ab; + bcd = bez * cd - cez * bd + dez * bc; + cda = cez * da + dez * ac + aez * cd; + dab = dez * ab + aez * bd + bez * da; + + alift = aex * aex + aey * aey + aez * aez; + blift = bex * bex + bey * bey + bez * bez; + clift = cex * cex + cey * cey + cez * cez; + dlift = dex * dex + dey * dey + dez * dez; + + return (dlift * abc - clift * dab) + (blift * cda - alift * bcd); +} + +REAL insphereexact(REAL *pa, REAL *pb, REAL *pc, REAL *pd, REAL *pe) +{ + INEXACT REAL axby1, bxcy1, cxdy1, dxey1, exay1; + INEXACT REAL bxay1, cxby1, dxcy1, exdy1, axey1; + INEXACT REAL axcy1, bxdy1, cxey1, dxay1, exby1; + INEXACT REAL cxay1, dxby1, excy1, axdy1, bxey1; + REAL axby0, bxcy0, cxdy0, dxey0, exay0; + REAL bxay0, cxby0, dxcy0, exdy0, axey0; + REAL axcy0, bxdy0, cxey0, dxay0, exby0; + REAL cxay0, dxby0, excy0, axdy0, bxey0; + REAL ab[4], bc[4], cd[4], de[4], ea[4]; + REAL ac[4], bd[4], ce[4], da[4], eb[4]; + REAL temp8a[8], temp8b[8], temp16[16]; + int temp8alen, temp8blen, temp16len; + REAL abc[24], bcd[24], cde[24], dea[24], eab[24]; + REAL abd[24], bce[24], cda[24], deb[24], eac[24]; + int abclen, bcdlen, cdelen, dealen, eablen; + int abdlen, bcelen, cdalen, deblen, eaclen; + REAL temp48a[48], temp48b[48]; + int temp48alen, temp48blen; + REAL abcd[96], bcde[96], cdea[96], deab[96], eabc[96]; + int abcdlen, bcdelen, cdealen, deablen, eabclen; + REAL temp192[192]; + REAL det384x[384], det384y[384], det384z[384]; + int xlen, ylen, zlen; + REAL detxy[768]; + int xylen; + REAL adet[1152], bdet[1152], cdet[1152], ddet[1152], edet[1152]; + int alen, blen, clen, dlen, elen; + REAL abdet[2304], cddet[2304], cdedet[3456]; + int ablen, cdlen; + REAL deter[5760]; + int deterlen; + int i; + + INEXACT REAL bvirt; + REAL avirt, bround, around; + INEXACT REAL c; + INEXACT REAL abig; + REAL ahi, alo, bhi, blo; + REAL err1, err2, err3; + INEXACT REAL _i, _j; + REAL _0; + + Two_Product(pa[0], pb[1], axby1, axby0); + Two_Product(pb[0], pa[1], bxay1, bxay0); + Two_Two_Diff(axby1, axby0, bxay1, bxay0, ab[3], ab[2], ab[1], ab[0]); + + Two_Product(pb[0], pc[1], bxcy1, bxcy0); + Two_Product(pc[0], pb[1], cxby1, cxby0); + Two_Two_Diff(bxcy1, bxcy0, cxby1, cxby0, bc[3], bc[2], bc[1], bc[0]); + + Two_Product(pc[0], pd[1], cxdy1, cxdy0); + Two_Product(pd[0], pc[1], dxcy1, dxcy0); + Two_Two_Diff(cxdy1, cxdy0, dxcy1, dxcy0, cd[3], cd[2], cd[1], cd[0]); + + Two_Product(pd[0], pe[1], dxey1, dxey0); + Two_Product(pe[0], pd[1], exdy1, exdy0); + Two_Two_Diff(dxey1, dxey0, exdy1, exdy0, de[3], de[2], de[1], de[0]); + + Two_Product(pe[0], pa[1], exay1, exay0); + Two_Product(pa[0], pe[1], axey1, axey0); + Two_Two_Diff(exay1, exay0, axey1, axey0, ea[3], ea[2], ea[1], ea[0]); + + Two_Product(pa[0], pc[1], axcy1, axcy0); + Two_Product(pc[0], pa[1], cxay1, cxay0); + Two_Two_Diff(axcy1, axcy0, cxay1, cxay0, ac[3], ac[2], ac[1], ac[0]); + + Two_Product(pb[0], pd[1], bxdy1, bxdy0); + Two_Product(pd[0], pb[1], dxby1, dxby0); + Two_Two_Diff(bxdy1, bxdy0, dxby1, dxby0, bd[3], bd[2], bd[1], bd[0]); + + Two_Product(pc[0], pe[1], cxey1, cxey0); + Two_Product(pe[0], pc[1], excy1, excy0); + Two_Two_Diff(cxey1, cxey0, excy1, excy0, ce[3], ce[2], ce[1], ce[0]); + + Two_Product(pd[0], pa[1], dxay1, dxay0); + Two_Product(pa[0], pd[1], axdy1, axdy0); + Two_Two_Diff(dxay1, dxay0, axdy1, axdy0, da[3], da[2], da[1], da[0]); + + Two_Product(pe[0], pb[1], exby1, exby0); + Two_Product(pb[0], pe[1], bxey1, bxey0); + Two_Two_Diff(exby1, exby0, bxey1, bxey0, eb[3], eb[2], eb[1], eb[0]); + + temp8alen = scale_expansion_zeroelim(4, bc, pa[2], temp8a); + temp8blen = scale_expansion_zeroelim(4, ac, -pb[2], temp8b); + temp16len = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp8blen, temp8b, + temp16); + temp8alen = scale_expansion_zeroelim(4, ab, pc[2], temp8a); + abclen = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp16len, temp16, + abc); + + temp8alen = scale_expansion_zeroelim(4, cd, pb[2], temp8a); + temp8blen = scale_expansion_zeroelim(4, bd, -pc[2], temp8b); + temp16len = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp8blen, temp8b, + temp16); + temp8alen = scale_expansion_zeroelim(4, bc, pd[2], temp8a); + bcdlen = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp16len, temp16, + bcd); + + temp8alen = scale_expansion_zeroelim(4, de, pc[2], temp8a); + temp8blen = scale_expansion_zeroelim(4, ce, -pd[2], temp8b); + temp16len = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp8blen, temp8b, + temp16); + temp8alen = scale_expansion_zeroelim(4, cd, pe[2], temp8a); + cdelen = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp16len, temp16, + cde); + + temp8alen = scale_expansion_zeroelim(4, ea, pd[2], temp8a); + temp8blen = scale_expansion_zeroelim(4, da, -pe[2], temp8b); + temp16len = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp8blen, temp8b, + temp16); + temp8alen = scale_expansion_zeroelim(4, de, pa[2], temp8a); + dealen = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp16len, temp16, + dea); + + temp8alen = scale_expansion_zeroelim(4, ab, pe[2], temp8a); + temp8blen = scale_expansion_zeroelim(4, eb, -pa[2], temp8b); + temp16len = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp8blen, temp8b, + temp16); + temp8alen = scale_expansion_zeroelim(4, ea, pb[2], temp8a); + eablen = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp16len, temp16, + eab); + + temp8alen = scale_expansion_zeroelim(4, bd, pa[2], temp8a); + temp8blen = scale_expansion_zeroelim(4, da, pb[2], temp8b); + temp16len = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp8blen, temp8b, + temp16); + temp8alen = scale_expansion_zeroelim(4, ab, pd[2], temp8a); + abdlen = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp16len, temp16, + abd); + + temp8alen = scale_expansion_zeroelim(4, ce, pb[2], temp8a); + temp8blen = scale_expansion_zeroelim(4, eb, pc[2], temp8b); + temp16len = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp8blen, temp8b, + temp16); + temp8alen = scale_expansion_zeroelim(4, bc, pe[2], temp8a); + bcelen = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp16len, temp16, + bce); + + temp8alen = scale_expansion_zeroelim(4, da, pc[2], temp8a); + temp8blen = scale_expansion_zeroelim(4, ac, pd[2], temp8b); + temp16len = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp8blen, temp8b, + temp16); + temp8alen = scale_expansion_zeroelim(4, cd, pa[2], temp8a); + cdalen = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp16len, temp16, + cda); + + temp8alen = scale_expansion_zeroelim(4, eb, pd[2], temp8a); + temp8blen = scale_expansion_zeroelim(4, bd, pe[2], temp8b); + temp16len = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp8blen, temp8b, + temp16); + temp8alen = scale_expansion_zeroelim(4, de, pb[2], temp8a); + deblen = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp16len, temp16, + deb); + + temp8alen = scale_expansion_zeroelim(4, ac, pe[2], temp8a); + temp8blen = scale_expansion_zeroelim(4, ce, pa[2], temp8b); + temp16len = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp8blen, temp8b, + temp16); + temp8alen = scale_expansion_zeroelim(4, ea, pc[2], temp8a); + eaclen = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp16len, temp16, + eac); + + temp48alen = fast_expansion_sum_zeroelim(cdelen, cde, bcelen, bce, temp48a); + temp48blen = fast_expansion_sum_zeroelim(deblen, deb, bcdlen, bcd, temp48b); + for (i = 0; i < temp48blen; i++) { + temp48b[i] = -temp48b[i]; + } + bcdelen = fast_expansion_sum_zeroelim(temp48alen, temp48a, + temp48blen, temp48b, bcde); + xlen = scale_expansion_zeroelim(bcdelen, bcde, pa[0], temp192); + xlen = scale_expansion_zeroelim(xlen, temp192, pa[0], det384x); + ylen = scale_expansion_zeroelim(bcdelen, bcde, pa[1], temp192); + ylen = scale_expansion_zeroelim(ylen, temp192, pa[1], det384y); + zlen = scale_expansion_zeroelim(bcdelen, bcde, pa[2], temp192); + zlen = scale_expansion_zeroelim(zlen, temp192, pa[2], det384z); + xylen = fast_expansion_sum_zeroelim(xlen, det384x, ylen, det384y, detxy); + alen = fast_expansion_sum_zeroelim(xylen, detxy, zlen, det384z, adet); + + temp48alen = fast_expansion_sum_zeroelim(dealen, dea, cdalen, cda, temp48a); + temp48blen = fast_expansion_sum_zeroelim(eaclen, eac, cdelen, cde, temp48b); + for (i = 0; i < temp48blen; i++) { + temp48b[i] = -temp48b[i]; + } + cdealen = fast_expansion_sum_zeroelim(temp48alen, temp48a, + temp48blen, temp48b, cdea); + xlen = scale_expansion_zeroelim(cdealen, cdea, pb[0], temp192); + xlen = scale_expansion_zeroelim(xlen, temp192, pb[0], det384x); + ylen = scale_expansion_zeroelim(cdealen, cdea, pb[1], temp192); + ylen = scale_expansion_zeroelim(ylen, temp192, pb[1], det384y); + zlen = scale_expansion_zeroelim(cdealen, cdea, pb[2], temp192); + zlen = scale_expansion_zeroelim(zlen, temp192, pb[2], det384z); + xylen = fast_expansion_sum_zeroelim(xlen, det384x, ylen, det384y, detxy); + blen = fast_expansion_sum_zeroelim(xylen, detxy, zlen, det384z, bdet); + + temp48alen = fast_expansion_sum_zeroelim(eablen, eab, deblen, deb, temp48a); + temp48blen = fast_expansion_sum_zeroelim(abdlen, abd, dealen, dea, temp48b); + for (i = 0; i < temp48blen; i++) { + temp48b[i] = -temp48b[i]; + } + deablen = fast_expansion_sum_zeroelim(temp48alen, temp48a, + temp48blen, temp48b, deab); + xlen = scale_expansion_zeroelim(deablen, deab, pc[0], temp192); + xlen = scale_expansion_zeroelim(xlen, temp192, pc[0], det384x); + ylen = scale_expansion_zeroelim(deablen, deab, pc[1], temp192); + ylen = scale_expansion_zeroelim(ylen, temp192, pc[1], det384y); + zlen = scale_expansion_zeroelim(deablen, deab, pc[2], temp192); + zlen = scale_expansion_zeroelim(zlen, temp192, pc[2], det384z); + xylen = fast_expansion_sum_zeroelim(xlen, det384x, ylen, det384y, detxy); + clen = fast_expansion_sum_zeroelim(xylen, detxy, zlen, det384z, cdet); + + temp48alen = fast_expansion_sum_zeroelim(abclen, abc, eaclen, eac, temp48a); + temp48blen = fast_expansion_sum_zeroelim(bcelen, bce, eablen, eab, temp48b); + for (i = 0; i < temp48blen; i++) { + temp48b[i] = -temp48b[i]; + } + eabclen = fast_expansion_sum_zeroelim(temp48alen, temp48a, + temp48blen, temp48b, eabc); + xlen = scale_expansion_zeroelim(eabclen, eabc, pd[0], temp192); + xlen = scale_expansion_zeroelim(xlen, temp192, pd[0], det384x); + ylen = scale_expansion_zeroelim(eabclen, eabc, pd[1], temp192); + ylen = scale_expansion_zeroelim(ylen, temp192, pd[1], det384y); + zlen = scale_expansion_zeroelim(eabclen, eabc, pd[2], temp192); + zlen = scale_expansion_zeroelim(zlen, temp192, pd[2], det384z); + xylen = fast_expansion_sum_zeroelim(xlen, det384x, ylen, det384y, detxy); + dlen = fast_expansion_sum_zeroelim(xylen, detxy, zlen, det384z, ddet); + + temp48alen = fast_expansion_sum_zeroelim(bcdlen, bcd, abdlen, abd, temp48a); + temp48blen = fast_expansion_sum_zeroelim(cdalen, cda, abclen, abc, temp48b); + for (i = 0; i < temp48blen; i++) { + temp48b[i] = -temp48b[i]; + } + abcdlen = fast_expansion_sum_zeroelim(temp48alen, temp48a, + temp48blen, temp48b, abcd); + xlen = scale_expansion_zeroelim(abcdlen, abcd, pe[0], temp192); + xlen = scale_expansion_zeroelim(xlen, temp192, pe[0], det384x); + ylen = scale_expansion_zeroelim(abcdlen, abcd, pe[1], temp192); + ylen = scale_expansion_zeroelim(ylen, temp192, pe[1], det384y); + zlen = scale_expansion_zeroelim(abcdlen, abcd, pe[2], temp192); + zlen = scale_expansion_zeroelim(zlen, temp192, pe[2], det384z); + xylen = fast_expansion_sum_zeroelim(xlen, det384x, ylen, det384y, detxy); + elen = fast_expansion_sum_zeroelim(xylen, detxy, zlen, det384z, edet); + + ablen = fast_expansion_sum_zeroelim(alen, adet, blen, bdet, abdet); + cdlen = fast_expansion_sum_zeroelim(clen, cdet, dlen, ddet, cddet); + cdelen = fast_expansion_sum_zeroelim(cdlen, cddet, elen, edet, cdedet); + deterlen = fast_expansion_sum_zeroelim(ablen, abdet, cdelen, cdedet, deter); + + return deter[deterlen - 1]; +} + +REAL insphereslow(REAL *pa, REAL *pb, REAL *pc, REAL *pd, REAL *pe) +{ + INEXACT REAL aex, bex, cex, dex, aey, bey, cey, dey, aez, bez, cez, dez; + REAL aextail, bextail, cextail, dextail; + REAL aeytail, beytail, ceytail, deytail; + REAL aeztail, beztail, ceztail, deztail; + REAL negate, negatetail; + INEXACT REAL axby7, bxcy7, cxdy7, dxay7, axcy7, bxdy7; + INEXACT REAL bxay7, cxby7, dxcy7, axdy7, cxay7, dxby7; + REAL axby[8], bxcy[8], cxdy[8], dxay[8], axcy[8], bxdy[8]; + REAL bxay[8], cxby[8], dxcy[8], axdy[8], cxay[8], dxby[8]; + REAL ab[16], bc[16], cd[16], da[16], ac[16], bd[16]; + int ablen, bclen, cdlen, dalen, aclen, bdlen; + REAL temp32a[32], temp32b[32], temp64a[64], temp64b[64], temp64c[64]; + int temp32alen, temp32blen, temp64alen, temp64blen, temp64clen; + REAL temp128[128], temp192[192]; + int temp128len, temp192len; + REAL detx[384], detxx[768], detxt[384], detxxt[768], detxtxt[768]; + int xlen, xxlen, xtlen, xxtlen, xtxtlen; + REAL x1[1536], x2[2304]; + int x1len, x2len; + REAL dety[384], detyy[768], detyt[384], detyyt[768], detytyt[768]; + int ylen, yylen, ytlen, yytlen, ytytlen; + REAL y1[1536], y2[2304]; + int y1len, y2len; + REAL detz[384], detzz[768], detzt[384], detzzt[768], detztzt[768]; + int zlen, zzlen, ztlen, zztlen, ztztlen; + REAL z1[1536], z2[2304]; + int z1len, z2len; + REAL detxy[4608]; + int xylen; + REAL adet[6912], bdet[6912], cdet[6912], ddet[6912]; + int alen, blen, clen, dlen; + REAL abdet[13824], cddet[13824], deter[27648]; + int deterlen; + int i; + + INEXACT REAL bvirt; + REAL avirt, bround, around; + INEXACT REAL c; + INEXACT REAL abig; + REAL a0hi, a0lo, a1hi, a1lo, bhi, blo; + REAL err1, err2, err3; + INEXACT REAL _i, _j, _k, _l, _m, _n; + REAL _0, _1, _2; + + Two_Diff(pa[0], pe[0], aex, aextail); + Two_Diff(pa[1], pe[1], aey, aeytail); + Two_Diff(pa[2], pe[2], aez, aeztail); + Two_Diff(pb[0], pe[0], bex, bextail); + Two_Diff(pb[1], pe[1], bey, beytail); + Two_Diff(pb[2], pe[2], bez, beztail); + Two_Diff(pc[0], pe[0], cex, cextail); + Two_Diff(pc[1], pe[1], cey, ceytail); + Two_Diff(pc[2], pe[2], cez, ceztail); + Two_Diff(pd[0], pe[0], dex, dextail); + Two_Diff(pd[1], pe[1], dey, deytail); + Two_Diff(pd[2], pe[2], dez, deztail); + + Two_Two_Product(aex, aextail, bey, beytail, + axby7, axby[6], axby[5], axby[4], + axby[3], axby[2], axby[1], axby[0]); + axby[7] = axby7; + negate = -aey; + negatetail = -aeytail; + Two_Two_Product(bex, bextail, negate, negatetail, + bxay7, bxay[6], bxay[5], bxay[4], + bxay[3], bxay[2], bxay[1], bxay[0]); + bxay[7] = bxay7; + ablen = fast_expansion_sum_zeroelim(8, axby, 8, bxay, ab); + Two_Two_Product(bex, bextail, cey, ceytail, + bxcy7, bxcy[6], bxcy[5], bxcy[4], + bxcy[3], bxcy[2], bxcy[1], bxcy[0]); + bxcy[7] = bxcy7; + negate = -bey; + negatetail = -beytail; + Two_Two_Product(cex, cextail, negate, negatetail, + cxby7, cxby[6], cxby[5], cxby[4], + cxby[3], cxby[2], cxby[1], cxby[0]); + cxby[7] = cxby7; + bclen = fast_expansion_sum_zeroelim(8, bxcy, 8, cxby, bc); + Two_Two_Product(cex, cextail, dey, deytail, + cxdy7, cxdy[6], cxdy[5], cxdy[4], + cxdy[3], cxdy[2], cxdy[1], cxdy[0]); + cxdy[7] = cxdy7; + negate = -cey; + negatetail = -ceytail; + Two_Two_Product(dex, dextail, negate, negatetail, + dxcy7, dxcy[6], dxcy[5], dxcy[4], + dxcy[3], dxcy[2], dxcy[1], dxcy[0]); + dxcy[7] = dxcy7; + cdlen = fast_expansion_sum_zeroelim(8, cxdy, 8, dxcy, cd); + Two_Two_Product(dex, dextail, aey, aeytail, + dxay7, dxay[6], dxay[5], dxay[4], + dxay[3], dxay[2], dxay[1], dxay[0]); + dxay[7] = dxay7; + negate = -dey; + negatetail = -deytail; + Two_Two_Product(aex, aextail, negate, negatetail, + axdy7, axdy[6], axdy[5], axdy[4], + axdy[3], axdy[2], axdy[1], axdy[0]); + axdy[7] = axdy7; + dalen = fast_expansion_sum_zeroelim(8, dxay, 8, axdy, da); + Two_Two_Product(aex, aextail, cey, ceytail, + axcy7, axcy[6], axcy[5], axcy[4], + axcy[3], axcy[2], axcy[1], axcy[0]); + axcy[7] = axcy7; + negate = -aey; + negatetail = -aeytail; + Two_Two_Product(cex, cextail, negate, negatetail, + cxay7, cxay[6], cxay[5], cxay[4], + cxay[3], cxay[2], cxay[1], cxay[0]); + cxay[7] = cxay7; + aclen = fast_expansion_sum_zeroelim(8, axcy, 8, cxay, ac); + Two_Two_Product(bex, bextail, dey, deytail, + bxdy7, bxdy[6], bxdy[5], bxdy[4], + bxdy[3], bxdy[2], bxdy[1], bxdy[0]); + bxdy[7] = bxdy7; + negate = -bey; + negatetail = -beytail; + Two_Two_Product(dex, dextail, negate, negatetail, + dxby7, dxby[6], dxby[5], dxby[4], + dxby[3], dxby[2], dxby[1], dxby[0]); + dxby[7] = dxby7; + bdlen = fast_expansion_sum_zeroelim(8, bxdy, 8, dxby, bd); + + temp32alen = scale_expansion_zeroelim(cdlen, cd, -bez, temp32a); + temp32blen = scale_expansion_zeroelim(cdlen, cd, -beztail, temp32b); + temp64alen = fast_expansion_sum_zeroelim(temp32alen, temp32a, + temp32blen, temp32b, temp64a); + temp32alen = scale_expansion_zeroelim(bdlen, bd, cez, temp32a); + temp32blen = scale_expansion_zeroelim(bdlen, bd, ceztail, temp32b); + temp64blen = fast_expansion_sum_zeroelim(temp32alen, temp32a, + temp32blen, temp32b, temp64b); + temp32alen = scale_expansion_zeroelim(bclen, bc, -dez, temp32a); + temp32blen = scale_expansion_zeroelim(bclen, bc, -deztail, temp32b); + temp64clen = fast_expansion_sum_zeroelim(temp32alen, temp32a, + temp32blen, temp32b, temp64c); + temp128len = fast_expansion_sum_zeroelim(temp64alen, temp64a, + temp64blen, temp64b, temp128); + temp192len = fast_expansion_sum_zeroelim(temp64clen, temp64c, + temp128len, temp128, temp192); + xlen = scale_expansion_zeroelim(temp192len, temp192, aex, detx); + xxlen = scale_expansion_zeroelim(xlen, detx, aex, detxx); + xtlen = scale_expansion_zeroelim(temp192len, temp192, aextail, detxt); + xxtlen = scale_expansion_zeroelim(xtlen, detxt, aex, detxxt); + for (i = 0; i < xxtlen; i++) { + detxxt[i] *= 2.0; + } + xtxtlen = scale_expansion_zeroelim(xtlen, detxt, aextail, detxtxt); + x1len = fast_expansion_sum_zeroelim(xxlen, detxx, xxtlen, detxxt, x1); + x2len = fast_expansion_sum_zeroelim(x1len, x1, xtxtlen, detxtxt, x2); + ylen = scale_expansion_zeroelim(temp192len, temp192, aey, dety); + yylen = scale_expansion_zeroelim(ylen, dety, aey, detyy); + ytlen = scale_expansion_zeroelim(temp192len, temp192, aeytail, detyt); + yytlen = scale_expansion_zeroelim(ytlen, detyt, aey, detyyt); + for (i = 0; i < yytlen; i++) { + detyyt[i] *= 2.0; + } + ytytlen = scale_expansion_zeroelim(ytlen, detyt, aeytail, detytyt); + y1len = fast_expansion_sum_zeroelim(yylen, detyy, yytlen, detyyt, y1); + y2len = fast_expansion_sum_zeroelim(y1len, y1, ytytlen, detytyt, y2); + zlen = scale_expansion_zeroelim(temp192len, temp192, aez, detz); + zzlen = scale_expansion_zeroelim(zlen, detz, aez, detzz); + ztlen = scale_expansion_zeroelim(temp192len, temp192, aeztail, detzt); + zztlen = scale_expansion_zeroelim(ztlen, detzt, aez, detzzt); + for (i = 0; i < zztlen; i++) { + detzzt[i] *= 2.0; + } + ztztlen = scale_expansion_zeroelim(ztlen, detzt, aeztail, detztzt); + z1len = fast_expansion_sum_zeroelim(zzlen, detzz, zztlen, detzzt, z1); + z2len = fast_expansion_sum_zeroelim(z1len, z1, ztztlen, detztzt, z2); + xylen = fast_expansion_sum_zeroelim(x2len, x2, y2len, y2, detxy); + alen = fast_expansion_sum_zeroelim(z2len, z2, xylen, detxy, adet); + + temp32alen = scale_expansion_zeroelim(dalen, da, cez, temp32a); + temp32blen = scale_expansion_zeroelim(dalen, da, ceztail, temp32b); + temp64alen = fast_expansion_sum_zeroelim(temp32alen, temp32a, + temp32blen, temp32b, temp64a); + temp32alen = scale_expansion_zeroelim(aclen, ac, dez, temp32a); + temp32blen = scale_expansion_zeroelim(aclen, ac, deztail, temp32b); + temp64blen = fast_expansion_sum_zeroelim(temp32alen, temp32a, + temp32blen, temp32b, temp64b); + temp32alen = scale_expansion_zeroelim(cdlen, cd, aez, temp32a); + temp32blen = scale_expansion_zeroelim(cdlen, cd, aeztail, temp32b); + temp64clen = fast_expansion_sum_zeroelim(temp32alen, temp32a, + temp32blen, temp32b, temp64c); + temp128len = fast_expansion_sum_zeroelim(temp64alen, temp64a, + temp64blen, temp64b, temp128); + temp192len = fast_expansion_sum_zeroelim(temp64clen, temp64c, + temp128len, temp128, temp192); + xlen = scale_expansion_zeroelim(temp192len, temp192, bex, detx); + xxlen = scale_expansion_zeroelim(xlen, detx, bex, detxx); + xtlen = scale_expansion_zeroelim(temp192len, temp192, bextail, detxt); + xxtlen = scale_expansion_zeroelim(xtlen, detxt, bex, detxxt); + for (i = 0; i < xxtlen; i++) { + detxxt[i] *= 2.0; + } + xtxtlen = scale_expansion_zeroelim(xtlen, detxt, bextail, detxtxt); + x1len = fast_expansion_sum_zeroelim(xxlen, detxx, xxtlen, detxxt, x1); + x2len = fast_expansion_sum_zeroelim(x1len, x1, xtxtlen, detxtxt, x2); + ylen = scale_expansion_zeroelim(temp192len, temp192, bey, dety); + yylen = scale_expansion_zeroelim(ylen, dety, bey, detyy); + ytlen = scale_expansion_zeroelim(temp192len, temp192, beytail, detyt); + yytlen = scale_expansion_zeroelim(ytlen, detyt, bey, detyyt); + for (i = 0; i < yytlen; i++) { + detyyt[i] *= 2.0; + } + ytytlen = scale_expansion_zeroelim(ytlen, detyt, beytail, detytyt); + y1len = fast_expansion_sum_zeroelim(yylen, detyy, yytlen, detyyt, y1); + y2len = fast_expansion_sum_zeroelim(y1len, y1, ytytlen, detytyt, y2); + zlen = scale_expansion_zeroelim(temp192len, temp192, bez, detz); + zzlen = scale_expansion_zeroelim(zlen, detz, bez, detzz); + ztlen = scale_expansion_zeroelim(temp192len, temp192, beztail, detzt); + zztlen = scale_expansion_zeroelim(ztlen, detzt, bez, detzzt); + for (i = 0; i < zztlen; i++) { + detzzt[i] *= 2.0; + } + ztztlen = scale_expansion_zeroelim(ztlen, detzt, beztail, detztzt); + z1len = fast_expansion_sum_zeroelim(zzlen, detzz, zztlen, detzzt, z1); + z2len = fast_expansion_sum_zeroelim(z1len, z1, ztztlen, detztzt, z2); + xylen = fast_expansion_sum_zeroelim(x2len, x2, y2len, y2, detxy); + blen = fast_expansion_sum_zeroelim(z2len, z2, xylen, detxy, bdet); + + temp32alen = scale_expansion_zeroelim(ablen, ab, -dez, temp32a); + temp32blen = scale_expansion_zeroelim(ablen, ab, -deztail, temp32b); + temp64alen = fast_expansion_sum_zeroelim(temp32alen, temp32a, + temp32blen, temp32b, temp64a); + temp32alen = scale_expansion_zeroelim(bdlen, bd, -aez, temp32a); + temp32blen = scale_expansion_zeroelim(bdlen, bd, -aeztail, temp32b); + temp64blen = fast_expansion_sum_zeroelim(temp32alen, temp32a, + temp32blen, temp32b, temp64b); + temp32alen = scale_expansion_zeroelim(dalen, da, -bez, temp32a); + temp32blen = scale_expansion_zeroelim(dalen, da, -beztail, temp32b); + temp64clen = fast_expansion_sum_zeroelim(temp32alen, temp32a, + temp32blen, temp32b, temp64c); + temp128len = fast_expansion_sum_zeroelim(temp64alen, temp64a, + temp64blen, temp64b, temp128); + temp192len = fast_expansion_sum_zeroelim(temp64clen, temp64c, + temp128len, temp128, temp192); + xlen = scale_expansion_zeroelim(temp192len, temp192, cex, detx); + xxlen = scale_expansion_zeroelim(xlen, detx, cex, detxx); + xtlen = scale_expansion_zeroelim(temp192len, temp192, cextail, detxt); + xxtlen = scale_expansion_zeroelim(xtlen, detxt, cex, detxxt); + for (i = 0; i < xxtlen; i++) { + detxxt[i] *= 2.0; + } + xtxtlen = scale_expansion_zeroelim(xtlen, detxt, cextail, detxtxt); + x1len = fast_expansion_sum_zeroelim(xxlen, detxx, xxtlen, detxxt, x1); + x2len = fast_expansion_sum_zeroelim(x1len, x1, xtxtlen, detxtxt, x2); + ylen = scale_expansion_zeroelim(temp192len, temp192, cey, dety); + yylen = scale_expansion_zeroelim(ylen, dety, cey, detyy); + ytlen = scale_expansion_zeroelim(temp192len, temp192, ceytail, detyt); + yytlen = scale_expansion_zeroelim(ytlen, detyt, cey, detyyt); + for (i = 0; i < yytlen; i++) { + detyyt[i] *= 2.0; + } + ytytlen = scale_expansion_zeroelim(ytlen, detyt, ceytail, detytyt); + y1len = fast_expansion_sum_zeroelim(yylen, detyy, yytlen, detyyt, y1); + y2len = fast_expansion_sum_zeroelim(y1len, y1, ytytlen, detytyt, y2); + zlen = scale_expansion_zeroelim(temp192len, temp192, cez, detz); + zzlen = scale_expansion_zeroelim(zlen, detz, cez, detzz); + ztlen = scale_expansion_zeroelim(temp192len, temp192, ceztail, detzt); + zztlen = scale_expansion_zeroelim(ztlen, detzt, cez, detzzt); + for (i = 0; i < zztlen; i++) { + detzzt[i] *= 2.0; + } + ztztlen = scale_expansion_zeroelim(ztlen, detzt, ceztail, detztzt); + z1len = fast_expansion_sum_zeroelim(zzlen, detzz, zztlen, detzzt, z1); + z2len = fast_expansion_sum_zeroelim(z1len, z1, ztztlen, detztzt, z2); + xylen = fast_expansion_sum_zeroelim(x2len, x2, y2len, y2, detxy); + clen = fast_expansion_sum_zeroelim(z2len, z2, xylen, detxy, cdet); + + temp32alen = scale_expansion_zeroelim(bclen, bc, aez, temp32a); + temp32blen = scale_expansion_zeroelim(bclen, bc, aeztail, temp32b); + temp64alen = fast_expansion_sum_zeroelim(temp32alen, temp32a, + temp32blen, temp32b, temp64a); + temp32alen = scale_expansion_zeroelim(aclen, ac, -bez, temp32a); + temp32blen = scale_expansion_zeroelim(aclen, ac, -beztail, temp32b); + temp64blen = fast_expansion_sum_zeroelim(temp32alen, temp32a, + temp32blen, temp32b, temp64b); + temp32alen = scale_expansion_zeroelim(ablen, ab, cez, temp32a); + temp32blen = scale_expansion_zeroelim(ablen, ab, ceztail, temp32b); + temp64clen = fast_expansion_sum_zeroelim(temp32alen, temp32a, + temp32blen, temp32b, temp64c); + temp128len = fast_expansion_sum_zeroelim(temp64alen, temp64a, + temp64blen, temp64b, temp128); + temp192len = fast_expansion_sum_zeroelim(temp64clen, temp64c, + temp128len, temp128, temp192); + xlen = scale_expansion_zeroelim(temp192len, temp192, dex, detx); + xxlen = scale_expansion_zeroelim(xlen, detx, dex, detxx); + xtlen = scale_expansion_zeroelim(temp192len, temp192, dextail, detxt); + xxtlen = scale_expansion_zeroelim(xtlen, detxt, dex, detxxt); + for (i = 0; i < xxtlen; i++) { + detxxt[i] *= 2.0; + } + xtxtlen = scale_expansion_zeroelim(xtlen, detxt, dextail, detxtxt); + x1len = fast_expansion_sum_zeroelim(xxlen, detxx, xxtlen, detxxt, x1); + x2len = fast_expansion_sum_zeroelim(x1len, x1, xtxtlen, detxtxt, x2); + ylen = scale_expansion_zeroelim(temp192len, temp192, dey, dety); + yylen = scale_expansion_zeroelim(ylen, dety, dey, detyy); + ytlen = scale_expansion_zeroelim(temp192len, temp192, deytail, detyt); + yytlen = scale_expansion_zeroelim(ytlen, detyt, dey, detyyt); + for (i = 0; i < yytlen; i++) { + detyyt[i] *= 2.0; + } + ytytlen = scale_expansion_zeroelim(ytlen, detyt, deytail, detytyt); + y1len = fast_expansion_sum_zeroelim(yylen, detyy, yytlen, detyyt, y1); + y2len = fast_expansion_sum_zeroelim(y1len, y1, ytytlen, detytyt, y2); + zlen = scale_expansion_zeroelim(temp192len, temp192, dez, detz); + zzlen = scale_expansion_zeroelim(zlen, detz, dez, detzz); + ztlen = scale_expansion_zeroelim(temp192len, temp192, deztail, detzt); + zztlen = scale_expansion_zeroelim(ztlen, detzt, dez, detzzt); + for (i = 0; i < zztlen; i++) { + detzzt[i] *= 2.0; + } + ztztlen = scale_expansion_zeroelim(ztlen, detzt, deztail, detztzt); + z1len = fast_expansion_sum_zeroelim(zzlen, detzz, zztlen, detzzt, z1); + z2len = fast_expansion_sum_zeroelim(z1len, z1, ztztlen, detztzt, z2); + xylen = fast_expansion_sum_zeroelim(x2len, x2, y2len, y2, detxy); + dlen = fast_expansion_sum_zeroelim(z2len, z2, xylen, detxy, ddet); + + ablen = fast_expansion_sum_zeroelim(alen, adet, blen, bdet, abdet); + cdlen = fast_expansion_sum_zeroelim(clen, cdet, dlen, ddet, cddet); + deterlen = fast_expansion_sum_zeroelim(ablen, abdet, cdlen, cddet, deter); + + return deter[deterlen - 1]; +} + +REAL insphereadapt(REAL *pa, REAL *pb, REAL *pc, REAL *pd, REAL *pe, + REAL permanent) +{ + INEXACT REAL aex, bex, cex, dex, aey, bey, cey, dey, aez, bez, cez, dez; + REAL det, errbound; + + INEXACT REAL aexbey1, bexaey1, bexcey1, cexbey1; + INEXACT REAL cexdey1, dexcey1, dexaey1, aexdey1; + INEXACT REAL aexcey1, cexaey1, bexdey1, dexbey1; + REAL aexbey0, bexaey0, bexcey0, cexbey0; + REAL cexdey0, dexcey0, dexaey0, aexdey0; + REAL aexcey0, cexaey0, bexdey0, dexbey0; + REAL ab[4], bc[4], cd[4], da[4], ac[4], bd[4]; + INEXACT REAL ab3, bc3, cd3, da3, ac3, bd3; + REAL abeps, bceps, cdeps, daeps, aceps, bdeps; + REAL temp8a[8], temp8b[8], temp8c[8], temp16[16], temp24[24], temp48[48]; + int temp8alen, temp8blen, temp8clen, temp16len, temp24len, temp48len; + REAL xdet[96], ydet[96], zdet[96], xydet[192]; + int xlen, ylen, zlen, xylen; + REAL adet[288], bdet[288], cdet[288], ddet[288]; + int alen, blen, clen, dlen; + REAL abdet[576], cddet[576]; + int ablen, cdlen; + REAL fin1[1152]; + int finlength; + + REAL aextail, bextail, cextail, dextail; + REAL aeytail, beytail, ceytail, deytail; + REAL aeztail, beztail, ceztail, deztail; + + INEXACT REAL bvirt; + REAL avirt, bround, around; + INEXACT REAL c; + INEXACT REAL abig; + REAL ahi, alo, bhi, blo; + REAL err1, err2, err3; + INEXACT REAL _i, _j; + REAL _0; + + aex = (REAL) (pa[0] - pe[0]); + bex = (REAL) (pb[0] - pe[0]); + cex = (REAL) (pc[0] - pe[0]); + dex = (REAL) (pd[0] - pe[0]); + aey = (REAL) (pa[1] - pe[1]); + bey = (REAL) (pb[1] - pe[1]); + cey = (REAL) (pc[1] - pe[1]); + dey = (REAL) (pd[1] - pe[1]); + aez = (REAL) (pa[2] - pe[2]); + bez = (REAL) (pb[2] - pe[2]); + cez = (REAL) (pc[2] - pe[2]); + dez = (REAL) (pd[2] - pe[2]); + + Two_Product(aex, bey, aexbey1, aexbey0); + Two_Product(bex, aey, bexaey1, bexaey0); + Two_Two_Diff(aexbey1, aexbey0, bexaey1, bexaey0, ab3, ab[2], ab[1], ab[0]); + ab[3] = ab3; + + Two_Product(bex, cey, bexcey1, bexcey0); + Two_Product(cex, bey, cexbey1, cexbey0); + Two_Two_Diff(bexcey1, bexcey0, cexbey1, cexbey0, bc3, bc[2], bc[1], bc[0]); + bc[3] = bc3; + + Two_Product(cex, dey, cexdey1, cexdey0); + Two_Product(dex, cey, dexcey1, dexcey0); + Two_Two_Diff(cexdey1, cexdey0, dexcey1, dexcey0, cd3, cd[2], cd[1], cd[0]); + cd[3] = cd3; + + Two_Product(dex, aey, dexaey1, dexaey0); + Two_Product(aex, dey, aexdey1, aexdey0); + Two_Two_Diff(dexaey1, dexaey0, aexdey1, aexdey0, da3, da[2], da[1], da[0]); + da[3] = da3; + + Two_Product(aex, cey, aexcey1, aexcey0); + Two_Product(cex, aey, cexaey1, cexaey0); + Two_Two_Diff(aexcey1, aexcey0, cexaey1, cexaey0, ac3, ac[2], ac[1], ac[0]); + ac[3] = ac3; + + Two_Product(bex, dey, bexdey1, bexdey0); + Two_Product(dex, bey, dexbey1, dexbey0); + Two_Two_Diff(bexdey1, bexdey0, dexbey1, dexbey0, bd3, bd[2], bd[1], bd[0]); + bd[3] = bd3; + + temp8alen = scale_expansion_zeroelim(4, cd, bez, temp8a); + temp8blen = scale_expansion_zeroelim(4, bd, -cez, temp8b); + temp8clen = scale_expansion_zeroelim(4, bc, dez, temp8c); + temp16len = fast_expansion_sum_zeroelim(temp8alen, temp8a, + temp8blen, temp8b, temp16); + temp24len = fast_expansion_sum_zeroelim(temp8clen, temp8c, + temp16len, temp16, temp24); + temp48len = scale_expansion_zeroelim(temp24len, temp24, aex, temp48); + xlen = scale_expansion_zeroelim(temp48len, temp48, -aex, xdet); + temp48len = scale_expansion_zeroelim(temp24len, temp24, aey, temp48); + ylen = scale_expansion_zeroelim(temp48len, temp48, -aey, ydet); + temp48len = scale_expansion_zeroelim(temp24len, temp24, aez, temp48); + zlen = scale_expansion_zeroelim(temp48len, temp48, -aez, zdet); + xylen = fast_expansion_sum_zeroelim(xlen, xdet, ylen, ydet, xydet); + alen = fast_expansion_sum_zeroelim(xylen, xydet, zlen, zdet, adet); + + temp8alen = scale_expansion_zeroelim(4, da, cez, temp8a); + temp8blen = scale_expansion_zeroelim(4, ac, dez, temp8b); + temp8clen = scale_expansion_zeroelim(4, cd, aez, temp8c); + temp16len = fast_expansion_sum_zeroelim(temp8alen, temp8a, + temp8blen, temp8b, temp16); + temp24len = fast_expansion_sum_zeroelim(temp8clen, temp8c, + temp16len, temp16, temp24); + temp48len = scale_expansion_zeroelim(temp24len, temp24, bex, temp48); + xlen = scale_expansion_zeroelim(temp48len, temp48, bex, xdet); + temp48len = scale_expansion_zeroelim(temp24len, temp24, bey, temp48); + ylen = scale_expansion_zeroelim(temp48len, temp48, bey, ydet); + temp48len = scale_expansion_zeroelim(temp24len, temp24, bez, temp48); + zlen = scale_expansion_zeroelim(temp48len, temp48, bez, zdet); + xylen = fast_expansion_sum_zeroelim(xlen, xdet, ylen, ydet, xydet); + blen = fast_expansion_sum_zeroelim(xylen, xydet, zlen, zdet, bdet); + + temp8alen = scale_expansion_zeroelim(4, ab, dez, temp8a); + temp8blen = scale_expansion_zeroelim(4, bd, aez, temp8b); + temp8clen = scale_expansion_zeroelim(4, da, bez, temp8c); + temp16len = fast_expansion_sum_zeroelim(temp8alen, temp8a, + temp8blen, temp8b, temp16); + temp24len = fast_expansion_sum_zeroelim(temp8clen, temp8c, + temp16len, temp16, temp24); + temp48len = scale_expansion_zeroelim(temp24len, temp24, cex, temp48); + xlen = scale_expansion_zeroelim(temp48len, temp48, -cex, xdet); + temp48len = scale_expansion_zeroelim(temp24len, temp24, cey, temp48); + ylen = scale_expansion_zeroelim(temp48len, temp48, -cey, ydet); + temp48len = scale_expansion_zeroelim(temp24len, temp24, cez, temp48); + zlen = scale_expansion_zeroelim(temp48len, temp48, -cez, zdet); + xylen = fast_expansion_sum_zeroelim(xlen, xdet, ylen, ydet, xydet); + clen = fast_expansion_sum_zeroelim(xylen, xydet, zlen, zdet, cdet); + + temp8alen = scale_expansion_zeroelim(4, bc, aez, temp8a); + temp8blen = scale_expansion_zeroelim(4, ac, -bez, temp8b); + temp8clen = scale_expansion_zeroelim(4, ab, cez, temp8c); + temp16len = fast_expansion_sum_zeroelim(temp8alen, temp8a, + temp8blen, temp8b, temp16); + temp24len = fast_expansion_sum_zeroelim(temp8clen, temp8c, + temp16len, temp16, temp24); + temp48len = scale_expansion_zeroelim(temp24len, temp24, dex, temp48); + xlen = scale_expansion_zeroelim(temp48len, temp48, dex, xdet); + temp48len = scale_expansion_zeroelim(temp24len, temp24, dey, temp48); + ylen = scale_expansion_zeroelim(temp48len, temp48, dey, ydet); + temp48len = scale_expansion_zeroelim(temp24len, temp24, dez, temp48); + zlen = scale_expansion_zeroelim(temp48len, temp48, dez, zdet); + xylen = fast_expansion_sum_zeroelim(xlen, xdet, ylen, ydet, xydet); + dlen = fast_expansion_sum_zeroelim(xylen, xydet, zlen, zdet, ddet); + + ablen = fast_expansion_sum_zeroelim(alen, adet, blen, bdet, abdet); + cdlen = fast_expansion_sum_zeroelim(clen, cdet, dlen, ddet, cddet); + finlength = fast_expansion_sum_zeroelim(ablen, abdet, cdlen, cddet, fin1); + + det = estimate(finlength, fin1); + errbound = isperrboundB * permanent; + if ((det >= errbound) || (-det >= errbound)) { + return det; + } + + Two_Diff_Tail(pa[0], pe[0], aex, aextail); + Two_Diff_Tail(pa[1], pe[1], aey, aeytail); + Two_Diff_Tail(pa[2], pe[2], aez, aeztail); + Two_Diff_Tail(pb[0], pe[0], bex, bextail); + Two_Diff_Tail(pb[1], pe[1], bey, beytail); + Two_Diff_Tail(pb[2], pe[2], bez, beztail); + Two_Diff_Tail(pc[0], pe[0], cex, cextail); + Two_Diff_Tail(pc[1], pe[1], cey, ceytail); + Two_Diff_Tail(pc[2], pe[2], cez, ceztail); + Two_Diff_Tail(pd[0], pe[0], dex, dextail); + Two_Diff_Tail(pd[1], pe[1], dey, deytail); + Two_Diff_Tail(pd[2], pe[2], dez, deztail); + if ((aextail == 0.0) && (aeytail == 0.0) && (aeztail == 0.0) + && (bextail == 0.0) && (beytail == 0.0) && (beztail == 0.0) + && (cextail == 0.0) && (ceytail == 0.0) && (ceztail == 0.0) + && (dextail == 0.0) && (deytail == 0.0) && (deztail == 0.0)) { + return det; + } + + errbound = isperrboundC * permanent + resulterrbound * Absolute(det); + abeps = (aex * beytail + bey * aextail) + - (aey * bextail + bex * aeytail); + bceps = (bex * ceytail + cey * bextail) + - (bey * cextail + cex * beytail); + cdeps = (cex * deytail + dey * cextail) + - (cey * dextail + dex * ceytail); + daeps = (dex * aeytail + aey * dextail) + - (dey * aextail + aex * deytail); + aceps = (aex * ceytail + cey * aextail) + - (aey * cextail + cex * aeytail); + bdeps = (bex * deytail + dey * bextail) + - (bey * dextail + dex * beytail); + det += (((bex * bex + bey * bey + bez * bez) + * ((cez * daeps + dez * aceps + aez * cdeps) + + (ceztail * da3 + deztail * ac3 + aeztail * cd3)) + + (dex * dex + dey * dey + dez * dez) + * ((aez * bceps - bez * aceps + cez * abeps) + + (aeztail * bc3 - beztail * ac3 + ceztail * ab3))) + - ((aex * aex + aey * aey + aez * aez) + * ((bez * cdeps - cez * bdeps + dez * bceps) + + (beztail * cd3 - ceztail * bd3 + deztail * bc3)) + + (cex * cex + cey * cey + cez * cez) + * ((dez * abeps + aez * bdeps + bez * daeps) + + (deztail * ab3 + aeztail * bd3 + beztail * da3)))) + + 2.0 * (((bex * bextail + bey * beytail + bez * beztail) + * (cez * da3 + dez * ac3 + aez * cd3) + + (dex * dextail + dey * deytail + dez * deztail) + * (aez * bc3 - bez * ac3 + cez * ab3)) + - ((aex * aextail + aey * aeytail + aez * aeztail) + * (bez * cd3 - cez * bd3 + dez * bc3) + + (cex * cextail + cey * ceytail + cez * ceztail) + * (dez * ab3 + aez * bd3 + bez * da3))); + if ((det >= errbound) || (-det >= errbound)) { + return det; + } + + return insphereexact(pa, pb, pc, pd, pe); +} + +REAL insphere(REAL *pa, REAL *pb, REAL *pc, REAL *pd, REAL *pe) +{ + REAL aex, bex, cex, dex; + REAL aey, bey, cey, dey; + REAL aez, bez, cez, dez; + REAL aexbey, bexaey, bexcey, cexbey, cexdey, dexcey, dexaey, aexdey; + REAL aexcey, cexaey, bexdey, dexbey; + REAL alift, blift, clift, dlift; + REAL ab, bc, cd, da, ac, bd; + REAL abc, bcd, cda, dab; + REAL aezplus, bezplus, cezplus, dezplus; + REAL aexbeyplus, bexaeyplus, bexceyplus, cexbeyplus; + REAL cexdeyplus, dexceyplus, dexaeyplus, aexdeyplus; + REAL aexceyplus, cexaeyplus, bexdeyplus, dexbeyplus; + REAL det; + REAL permanent, errbound; + + aex = pa[0] - pe[0]; + bex = pb[0] - pe[0]; + cex = pc[0] - pe[0]; + dex = pd[0] - pe[0]; + aey = pa[1] - pe[1]; + bey = pb[1] - pe[1]; + cey = pc[1] - pe[1]; + dey = pd[1] - pe[1]; + aez = pa[2] - pe[2]; + bez = pb[2] - pe[2]; + cez = pc[2] - pe[2]; + dez = pd[2] - pe[2]; + + aexbey = aex * bey; + bexaey = bex * aey; + ab = aexbey - bexaey; + bexcey = bex * cey; + cexbey = cex * bey; + bc = bexcey - cexbey; + cexdey = cex * dey; + dexcey = dex * cey; + cd = cexdey - dexcey; + dexaey = dex * aey; + aexdey = aex * dey; + da = dexaey - aexdey; + + aexcey = aex * cey; + cexaey = cex * aey; + ac = aexcey - cexaey; + bexdey = bex * dey; + dexbey = dex * bey; + bd = bexdey - dexbey; + + abc = aez * bc - bez * ac + cez * ab; + bcd = bez * cd - cez * bd + dez * bc; + cda = cez * da + dez * ac + aez * cd; + dab = dez * ab + aez * bd + bez * da; + + alift = aex * aex + aey * aey + aez * aez; + blift = bex * bex + bey * bey + bez * bez; + clift = cex * cex + cey * cey + cez * cez; + dlift = dex * dex + dey * dey + dez * dez; + + det = (dlift * abc - clift * dab) + (blift * cda - alift * bcd); + + aezplus = Absolute(aez); + bezplus = Absolute(bez); + cezplus = Absolute(cez); + dezplus = Absolute(dez); + aexbeyplus = Absolute(aexbey); + bexaeyplus = Absolute(bexaey); + bexceyplus = Absolute(bexcey); + cexbeyplus = Absolute(cexbey); + cexdeyplus = Absolute(cexdey); + dexceyplus = Absolute(dexcey); + dexaeyplus = Absolute(dexaey); + aexdeyplus = Absolute(aexdey); + aexceyplus = Absolute(aexcey); + cexaeyplus = Absolute(cexaey); + bexdeyplus = Absolute(bexdey); + dexbeyplus = Absolute(dexbey); + permanent = ((cexdeyplus + dexceyplus) * bezplus + + (dexbeyplus + bexdeyplus) * cezplus + + (bexceyplus + cexbeyplus) * dezplus) + * alift + + ((dexaeyplus + aexdeyplus) * cezplus + + (aexceyplus + cexaeyplus) * dezplus + + (cexdeyplus + dexceyplus) * aezplus) + * blift + + ((aexbeyplus + bexaeyplus) * dezplus + + (bexdeyplus + dexbeyplus) * aezplus + + (dexaeyplus + aexdeyplus) * bezplus) + * clift + + ((bexceyplus + cexbeyplus) * aezplus + + (cexaeyplus + aexceyplus) * bezplus + + (aexbeyplus + bexaeyplus) * cezplus) + * dlift; + errbound = isperrboundA * permanent; + if ((det > errbound) || (-det > errbound)) { + return det; + } + + return insphereadapt(pa, pb, pc, pd, pe, permanent); +} diff --git a/contrib/Tetgen/tetgen.cxx b/contrib/Tetgen/tetgen.cxx new file mode 100644 index 0000000000..34721f2b83 --- /dev/null +++ b/contrib/Tetgen/tetgen.cxx @@ -0,0 +1,22807 @@ +/////////////////////////////////////////////////////////////////////////////// +// // +// TetGen // +// // +// A Quality Tetrahedral Mesh Generator and 3D Delaunay Triangulator // +// // +// Version 1.3 // +// June 13, 2004 // +// // +// Copyright 2002, 2004 // +// Hang Si // +// Rathausstr. 9, 10178 Berlin, Germany // +// si@wias-berlin.de // +// // +// You can obtain TetGen via internet: http://tetgen.berlios.de. It may be // +// freely copied, modified, and redistributed under the copyright notices // +// given in the file LICENSE. // +// // +/////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// +// // +// tetgen.cxx // +// // +// The C++ implementation file of the TetGen library. // +// // +/////////////////////////////////////////////////////////////////////////////// + +#include "tetgen.h" + +// +// Begin of class 'tetgenio' implementation +// + +/////////////////////////////////////////////////////////////////////////////// +// // +// initialize() Initialize all variables of 'tetgenio'. // +// // +// It is called by the only class constructor 'tetgenio()' implicitly. Thus, // +// all variables are guaranteed to be initialized. Each array is initialized // +// to be a 'NULL' pointer, and its length is equal zero. Some variables have // +// their default value, 'firstnumber' equals zero, 'mesh_dim' equals 3, and // +// 'numberofcorners' equals 4. Another possible use of this routine is to // +// call it before to re-use an object. // +// // +/////////////////////////////////////////////////////////////////////////////// + +void tetgenio::initialize() +{ + firstnumber = 0; // Default item index is numbered from Zero. + mesh_dim = 3; // Default mesh dimension is 3. + + pointlist = (REAL *) NULL; + pointattributelist = (REAL *) NULL; + addpointlist = (REAL *) NULL; + pointmarkerlist = (int *) NULL; + numberofpoints = 0; + numberofpointattributes = 0; + numberofaddpoints = 0; + + tetrahedronlist = (int *) NULL; + tetrahedronattributelist = (REAL *) NULL; + tetrahedronvolumelist = (REAL *) NULL; + neighborlist = (int *) NULL; + numberoftetrahedra = 0; + numberofcorners = 4; // Default is 4 nodes per element. + numberoftetrahedronattributes = 0; + + trifacelist = (int *) NULL; + trifacemarkerlist = (int *) NULL; + numberoftrifaces = 0; + + facetlist = (facet *) NULL; + facetmarkerlist = (int *) NULL; + numberoffacets = 0; + + edgelist = (int *) NULL; + edgemarkerlist = (int *) NULL; + numberofedges = 0; + + holelist = (REAL *) NULL; + numberofholes = 0; + + regionlist = (REAL *) NULL; + numberofregions = 0; +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// deinitialize() Free the memory allocated in 'tetgenio'. // +// // +// It is called by the class destructor '~tetgenio()' implicitly. Hence, the // +// occupied memory by arrays of an object will be automatically released on // +// the deletion of the object. However, this routine assumes that the memory // +// is allocated by C++ memory allocation operator 'new', thus it is freed by // +// the C++ array deletor 'delete []'. If one uses the C/C++ library function // +// 'malloc()' to allocate memory for arrays, one has to free them with the // +// 'free()' function, and call routine 'initialize()' once to disable this // +// routine on deletion of the object. // +// // +/////////////////////////////////////////////////////////////////////////////// + +void tetgenio::deinitialize() +{ + if (pointlist != (REAL *) NULL) { + delete [] pointlist; + } + if (pointattributelist != (REAL *) NULL) { + delete [] pointattributelist; + } + if (addpointlist != (REAL *) NULL) { + delete [] addpointlist; + } + if (pointmarkerlist != (int *) NULL) { + delete [] pointmarkerlist; + } + + if (tetrahedronlist != (int *) NULL) { + delete [] tetrahedronlist; + } + if (tetrahedronattributelist != (REAL *) NULL) { + delete [] tetrahedronattributelist; + } + if (tetrahedronvolumelist != (REAL *) NULL) { + delete [] tetrahedronvolumelist; + } + if (neighborlist != (int *) NULL) { + delete [] neighborlist; + } + + if (trifacelist != (int *) NULL) { + delete [] trifacelist; + } + if (trifacemarkerlist != (int *) NULL) { + delete [] trifacemarkerlist; + } + + if (edgelist != (int *) NULL) { + delete [] edgelist; + } + if (edgemarkerlist != (int *) NULL) { + delete [] edgemarkerlist; + } + + if (facetlist != (facet *) NULL) { + facet *f; + polygon *p; + int i, j; + for (i = 0; i < numberoffacets; i++) { + f = &facetlist[i]; + for (j = 0; j < f->numberofpolygons; j++) { + p = &f->polygonlist[j]; + delete [] p->vertexlist; + } + delete [] f->polygonlist; + if (f->holelist != (REAL *) NULL) { + delete [] f->holelist; + } + } + delete [] facetlist; + } + if (facetmarkerlist != (int *) NULL) { + delete [] facetmarkerlist; + } + + if (holelist != (REAL *) NULL) { + delete [] holelist; + } + + if (regionlist != (REAL *) NULL) { + delete [] regionlist; + } +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// load_node_call() Load a list of nodes. // +// // +// It is a support routine for routines: 'load_nodes()', 'load_poly()', and // +// 'load_tetmesh()'. 'infile' is the file handle contains the node list. It // +// may point to a .node, or .poly or .smesh file. 'markers' indicates each // +// node contains an additional marker (integer) or not. 'infilename' is the // +// name of the file being read, it is only appeared in error message. // +// // +// The 'firstnumber' (0 or 1) is automatically determined by the number of // +// the first index of the first point. // +// // +/////////////////////////////////////////////////////////////////////////////// + +bool tetgenio::load_node_call(FILE* infile, int markers, char* infilename) +{ + char inputline[INPUTLINESIZE]; + char *stringptr; + REAL x, y, z, attrib; + int firstnode, currentmarker; + int index, attribindex; + int i, j; + + // Initialize 'pointlist', 'pointattributelist', and 'pointmarkerlist'. + pointlist = new REAL[numberofpoints * mesh_dim]; + if (pointlist == (REAL *) NULL) { + printf("Error: Out of memory.\n"); + exit(1); + } + if (numberofpointattributes > 0) { + pointattributelist = new REAL[numberofpoints * numberofpointattributes]; + if (pointattributelist == (REAL *) NULL) { + printf("Error: Out of memory.\n"); + exit(1); + } + } + if (markers) { + pointmarkerlist = new int[numberofpoints]; + if (pointmarkerlist == (int *) NULL) { + printf("Error: Out of memory.\n"); + exit(1); + } + } + + // Read the point section. + index = 0; + attribindex = 0; + for (i = 0; i < numberofpoints; i++) { + stringptr = readnumberline(inputline, infile, infilename); + if (i == 0) { + firstnode = (int) strtol (stringptr, &stringptr, 0); + if ((firstnode == 0) || (firstnode == 1)) { + firstnumber = firstnode; + } + } + stringptr = findnextnumber(stringptr); + if (*stringptr == '\0') { + printf("Error: Point %d has no x coordinate.\n", firstnumber + i); + break; + } + x = (REAL) strtod(stringptr, &stringptr); + stringptr = findnextnumber(stringptr); + if (*stringptr == '\0') { + printf("Error: Point %d has no y coordinate.\n", firstnumber + i); + break; + } + y = (REAL) strtod(stringptr, &stringptr); + stringptr = findnextnumber(stringptr); + if (*stringptr == '\0') { + printf("Error: Point %d has no z coordinate.\n", firstnumber + i); + break; + } + z = (REAL) strtod(stringptr, &stringptr); + pointlist[index++] = x; + pointlist[index++] = y; + pointlist[index++] = z; + // Read the point attributes. + for (j = 0; j < numberofpointattributes; j++) { + stringptr = findnextnumber(stringptr); + if (*stringptr == '\0') { + attrib = 0.0; + } else { + attrib = (REAL) strtod(stringptr, &stringptr); + } + pointattributelist[attribindex++] = attrib; + } + if (markers) { + // Read a point marker. + stringptr = findnextnumber(stringptr); + if (*stringptr == '\0') { + currentmarker = 0; + } else { + currentmarker = (int) strtol (stringptr, &stringptr, 0); + } + pointmarkerlist[i] = currentmarker; + } + } + if (i < numberofpoints) { + // Failed to read points due to some error. + delete [] pointlist; + pointlist = (REAL *) NULL; + if (markers) { + delete [] pointmarkerlist; + pointmarkerlist = (int *) NULL; + } + if (numberofpointattributes > 0) { + delete [] pointattributelist; + pointattributelist = (REAL *) NULL; + } + numberofpoints = 0; + return false; + } + return true; +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// load_node() Load a list of nodes from a .node file. // +// // +// 'filename' is the inputfile without suffix. The node list is in 'filename.// +// node'. On completion, the node list is returned in 'pointlist'. // +// // +/////////////////////////////////////////////////////////////////////////////// + +bool tetgenio::load_node(char* filename) +{ + FILE *infile; + char innodefilename[FILENAMESIZE]; + char inputline[INPUTLINESIZE]; + char *stringptr; + int markers; + + // Assembling the actual file names we want to open. + strcpy(innodefilename, filename); + strcat(innodefilename, ".node"); + + // Try to open a .node file. + infile = fopen(innodefilename, "r"); + if (infile == (FILE *) NULL) { + printf("File I/O Error: Cannot access file %s.\n", innodefilename); + return false; + } + printf("Opening %s.\n", innodefilename); + // Read number of points, number of dimensions, number of point + // attributes, and number of boundary markers. + stringptr = readnumberline(inputline, infile, innodefilename); + numberofpoints = (int) strtol (stringptr, &stringptr, 0); + stringptr = findnextnumber(stringptr); + if (*stringptr == '\0') { + mesh_dim = 3; + } else { + mesh_dim = (int) strtol (stringptr, &stringptr, 0); + } + stringptr = findnextnumber(stringptr); + if (*stringptr == '\0') { + numberofpointattributes = 0; + } else { + numberofpointattributes = (int) strtol (stringptr, &stringptr, 0); + } + stringptr = findnextnumber(stringptr); + if (*stringptr == '\0') { + markers = 0; + } else { + markers = (int) strtol (stringptr, &stringptr, 0); + } + + if (mesh_dim != 3) { + printf("Error: load_node() only works for 3D points.\n"); + fclose(infile); + return false; + } + if (numberofpoints < 4) { + printf("File I/O error: There should have at least 4 points.\n"); + fclose(infile); + return false; + } + + // Load the list of nodes. + if (!load_node_call(infile, markers, innodefilename)) { + fclose(infile); + return false; + } + fclose(infile); + return true; +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// load_addnodes() Load a list of additional nodes into 'addpointlists'. // +// // +// 'filename' is the filename of the original inputfile without suffix. The // +// additional nodes are found in file 'filename-a.node'. // +// // +/////////////////////////////////////////////////////////////////////////////// + +bool tetgenio::load_addnodes(char* filename) +{ + FILE *infile; + char addnodefilename[FILENAMESIZE]; + char inputline[INPUTLINESIZE]; + char *stringptr; + REAL x, y, z; + int index; + int i; + + // Additional nodes are saved in file "filename-a.node". + strcpy(addnodefilename, filename); + strcat(addnodefilename, "-a.node"); + infile = fopen(addnodefilename, "r"); + if (infile != (FILE *) NULL) { + printf("Opening %s.\n", addnodefilename); + } else { + // Strange! However, it is not a fatal error. + printf("Warning: Can't opening %s. Skipped.\n", addnodefilename); + numberofaddpoints = 0; + return false; + } + + // Read the number of additional points. + stringptr = readnumberline(inputline, infile, addnodefilename); + numberofaddpoints = (int) strtol (stringptr, &stringptr, 0); + if (numberofaddpoints == 0) { + // It looks this file contains no point. + fclose(infile); + return false; + } + // Initialize 'addpointlist'; + addpointlist = new REAL[numberofaddpoints * mesh_dim]; + if (addpointlist == (REAL *) NULL) { + printf("Error: Out of memory.\n"); + exit(1); + } + + // Read the list of additional points. + index = 0; + for (i = 0; i < numberofaddpoints; i++) { + stringptr = readnumberline(inputline, infile, addnodefilename); + stringptr = findnextnumber(stringptr); + if (*stringptr == '\0') { + printf("Error: Point %d has no x coordinate.\n", firstnumber + i); + break; + } + x = (REAL) strtod(stringptr, &stringptr); + stringptr = findnextnumber(stringptr); + if (*stringptr == '\0') { + printf("Error: Point %d has no y coordinate.\n", firstnumber + i); + break; + } + y = (REAL) strtod(stringptr, &stringptr); + stringptr = findnextnumber(stringptr); + if (*stringptr == '\0') { + printf("Error: Point %d has no z coordinate.\n", firstnumber + i); + break; + } + z = (REAL) strtod(stringptr, &stringptr); + addpointlist[index++] = x; + addpointlist[index++] = y; + addpointlist[index++] = z; + } + fclose(infile); + + if (i < numberofaddpoints) { + // Failed to read to additional points due to some error. + delete [] addpointlist; + addpointlist = (REAL *) NULL; + numberofaddpoints = 0; + return false; + } + return true; +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// load_poly() Load a piecewise linear complex described in a .poly or // +// .smesh file. // +// // +// 'filename' is the inputfile without suffix. The PLC is in 'filename.poly' // +// or 'filename.smesh', and possibly plus 'filename.node' (when the first // +// line of the file starts with a zero). On completion, the PLC is returned // +// in 'pointlist', 'facetlist', 'holelist' and 'regionlist'. // +// // +/////////////////////////////////////////////////////////////////////////////// + +bool tetgenio::load_poly(char* filename) +{ + FILE *infile, *polyfile; + char innodefilename[FILENAMESIZE]; + char inpolyfilename[FILENAMESIZE]; + char insmeshfilename[FILENAMESIZE]; + char inputline[INPUTLINESIZE]; + char *stringptr, *infilename; + int smesh, markers, currentmarker; + int readnodefile, index; + int i, j, k; + + // Assembling the actual file names we want to open. + strcpy(innodefilename, filename); + strcpy(inpolyfilename, filename); + strcpy(insmeshfilename, filename); + strcat(innodefilename, ".node"); + strcat(inpolyfilename, ".poly"); + strcat(insmeshfilename, ".smesh"); + + // First assume it is a .poly file. + smesh = 0; + // Try to open a .poly file. + polyfile = fopen(inpolyfilename, "r"); + if (polyfile == (FILE *) NULL) { + // .poly doesn't exist! Try to open a .smesh file. + polyfile = fopen(insmeshfilename, "r"); + if (polyfile == (FILE *) NULL) { + printf("File I/O Error: Cannot access file %s and %s.\n", + inpolyfilename, insmeshfilename); + return false; + } else { + printf("Opening %s.\n", insmeshfilename); + } + smesh = 1; + } else { + printf("Opening %s.\n", inpolyfilename); + } + // Read number of points, number of dimensions, number of point + // attributes, and number of boundary markers. + stringptr = readnumberline(inputline, polyfile, inpolyfilename); + numberofpoints = (int) strtol (stringptr, &stringptr, 0); + stringptr = findnextnumber(stringptr); + if (*stringptr == '\0') { + mesh_dim = 3; // If it is not provided, set the default value. + } else { + mesh_dim = (int) strtol (stringptr, &stringptr, 0); + } + stringptr = findnextnumber(stringptr); + if (*stringptr == '\0') { + numberofpointattributes = 0; // The default value. + } else { + numberofpointattributes = (int) strtol (stringptr, &stringptr, 0); + } + stringptr = findnextnumber(stringptr); + if (*stringptr == '\0') { + markers = 0; // If it is not provided, set the default value. + } else { + markers = (int) strtol (stringptr, &stringptr, 0); + } + if (numberofpoints > 0) { + readnodefile = 0; + if (smesh) { + infilename = insmeshfilename; + } else { + infilename = inpolyfilename; + } + infile = polyfile; + } else { + // If the .poly or .smesh file claims there are zero points, that + // means the points should be read from a separate .node file. + readnodefile = 1; + infilename = innodefilename; + } + + if (readnodefile) { + // Read the points from the .node file. + printf("Opening %s.\n", innodefilename); + infile = fopen(innodefilename, "r"); + if (infile == (FILE *) NULL) { + printf("File I/O Error: Cannot access file %s.\n", innodefilename); + return false; + } + // Read number of points, number of dimensions, number of point + // attributes, and number of boundary markers. + stringptr = readnumberline(inputline, infile, innodefilename); + numberofpoints = (int) strtol (stringptr, &stringptr, 0); + stringptr = findnextnumber(stringptr); + if (*stringptr == '\0') { + mesh_dim = 3; + } else { + mesh_dim = (int) strtol (stringptr, &stringptr, 0); + } + stringptr = findnextnumber(stringptr); + if (*stringptr == '\0') { + numberofpointattributes = 0; + } else { + numberofpointattributes = (int) strtol (stringptr, &stringptr, 0); + } + stringptr = findnextnumber(stringptr); + if (*stringptr == '\0') { + markers = 0; + } else { + markers = (int) strtol (stringptr, &stringptr, 0); + } + } + + if (mesh_dim != 3) { + printf("Error: load_poly() only works for 3D points.\n"); + fclose(infile); + return false; + } + if (numberofpoints < 4) { + printf("File I/O error: There should have at least 4 points.\n"); + fclose(infile); + return false; + } + + // Load the list of nodes. + if (!load_node_call(infile, markers, infilename)) { + fclose(infile); + return false; + } + + if (readnodefile) { + fclose(infile); + } + + // Read number of facets and number of boundary markers. + stringptr = readnumberline(inputline, polyfile, inpolyfilename); + numberoffacets = (int) strtol (stringptr, &stringptr, 0); + stringptr = findnextnumber(stringptr); + if (*stringptr == '\0') { + markers = 0; + } else { + markers = (int) strtol (stringptr, &stringptr, 0); + } + + if (numberoffacets <= 0) { + // This input file is trivial, return anyway. + fclose(polyfile); + return true; + } + + // Initialize the 'facetlist', 'facetmarkerlist'. + facetlist = new facet[numberoffacets]; + if (markers == 1) { + facetmarkerlist = new int[numberoffacets]; + } + + facet *f; + polygon *p; + + // Read data into 'facetlist', 'facetmarkerlist'. + if (smesh == 0) { + // Facets are in .poly file format. + for (i = 1; i <= numberoffacets; i++) { + f = &(facetlist[i - 1]); + init(f); + f->numberofholes = 0; + currentmarker = 0; + // Read number of polygons, number of holes, and a boundary marker. + stringptr = readnumberline(inputline, polyfile, inpolyfilename); + f->numberofpolygons = (int) strtol (stringptr, &stringptr, 0); + stringptr = findnextnumber(stringptr); + if (*stringptr != '\0') { + f->numberofholes = (int) strtol (stringptr, &stringptr, 0); + if (markers == 1) { + stringptr = findnextnumber(stringptr); + if (*stringptr != '\0') { + currentmarker = (int) strtol(stringptr, &stringptr, 0); + } + } + } + // Initialize facetmarker if it needs. + if (markers == 1) { + facetmarkerlist[i - 1] = currentmarker; + } + // Each facet should has at least one polygon. + if (f->numberofpolygons <= 0) { + printf("Error: Wrong number of polygon in %d facet.\n", i); + break; + } + // Initialize the 'f->polygonlist'. + f->polygonlist = new polygon[f->numberofpolygons]; + // Go through all polygons, read in their vertices. + for (j = 1; j <= f->numberofpolygons; j++) { + p = &(f->polygonlist[j - 1]); + init(p); + // Read number of vertices of this polygon. + stringptr = readnumberline(inputline, polyfile, inpolyfilename); + p->numberofvertices = (int) strtol(stringptr, &stringptr, 0); + if (p->numberofvertices < 1) { + printf("Error: Wrong polygon %d in facet %d\n", j, i); + break; + } + // Initialize 'p->vertexlist'. + p->vertexlist = new int[p->numberofvertices]; + // Read all vertices of this polygon. + for (k = 1; k <= p->numberofvertices; k++) { + stringptr = findnextnumber(stringptr); + if (*stringptr == '\0') { + // Try to load another non-empty line and continue to read the + // rest of vertices. + stringptr = readnumberline(inputline, polyfile, inpolyfilename); + if (*stringptr == '\0') { + printf("Error: Missing %d endpoints of polygon %d in facet %d", + p->numberofvertices - k, j, i); + break; + } + } + p->vertexlist[k - 1] = (int) strtol (stringptr, &stringptr, 0); + } + } + if (j <= f->numberofpolygons) { + // This must be caused by an error. However, there're j - 1 polygons + // have been read. Reset the 'f->numberofpolygon'. + if (j == 1) { + // This is the first polygon. + delete [] f->polygonlist; + } + f->numberofpolygons = j - 1; + // No hole will be read even it exists. + f->numberofholes = 0; + break; + } + // If this facet has holes pints defined, read them. + if (f->numberofholes > 0) { + // Initialize 'f->holelist'. + f->holelist = new REAL[f->numberofholes * 3]; + // Read the holes' coordinates. + index = 0; + for (j = 1; j <= f->numberofholes; j++) { + stringptr = readnumberline(inputline, polyfile, inpolyfilename); + for (k = 1; k <= 3; k++) { + stringptr = findnextnumber(stringptr); + if (*stringptr == '\0') { + printf("Error: Hole %d in facet %d has no coordinates", j, i); + break; + } + f->holelist[index++] = (REAL) strtod (stringptr, &stringptr); + } + if (k <= 3) { + // This must be caused by an error. + break; + } + } + if (j <= f->numberofholes) { + // This must be caused by an error. + break; + } + } + } + if (i <= numberoffacets) { + // This must be caused by an error. + numberoffacets = i - 1; + fclose(polyfile); + return false; + } + } else { // poly == 0 + // Read the facets from a .smesh file. + for (i = 1; i <= numberoffacets; i++) { + f = &(facetlist[i - 1]); + init(f); + // Initialize 'f->facetlist'. In a .smesh file, each facetlist only + // contains exactly one polygon, no hole. + f->numberofpolygons = 1; + f->polygonlist = new polygon[f->numberofpolygons]; + p = &(f->polygonlist[0]); + init(p); + // Read number of vertices of this polygon. + stringptr = readnumberline(inputline, polyfile, insmeshfilename); + p->numberofvertices = (int) strtol (stringptr, &stringptr, 0); + if (p->numberofvertices < 1) { + printf("Error: Wrong number of vertex in facet %d\n", i); + break; + } + // Initialize 'p->vertexlist'. + p->vertexlist = new int[p->numberofvertices]; + for (k = 1; k <= p->numberofvertices; k++) { + stringptr = findnextnumber(stringptr); + if (*stringptr == '\0') { + // Try to load another non-empty line and continue to read the + // rest of vertices. + stringptr = readnumberline(inputline, polyfile, inpolyfilename); + if (*stringptr == '\0') { + printf("Error: Missing %d endpoints in facet %d", + p->numberofvertices - k, i); + break; + } + } + p->vertexlist[k - 1] = (int) strtol (stringptr, &stringptr, 0); + } + if (k <= p->numberofvertices) { + // This must be caused by an error. + break; + } + // Read facet's boundary marker at last. + if (markers == 1) { + stringptr = findnextnumber(stringptr); + if (*stringptr == '\0') { + currentmarker = 0; + } else { + currentmarker = (int) strtol(stringptr, &stringptr, 0); + } + facetmarkerlist[i - 1] = currentmarker; + } + } + if (i <= numberoffacets) { + // This must be caused by an error. + numberoffacets = i - 1; + fclose(polyfile); + return false; + } + } + + // Read the hole section. + stringptr = readnumberline(inputline, polyfile, inpolyfilename); + if (*stringptr != '\0') { + numberofholes = (int) strtol (stringptr, &stringptr, 0); + } else { + numberofholes = 0; + } + if (numberofholes > 0) { + // Initialize 'holelist'. + holelist = new REAL[numberofholes * 3]; + for (i = 0; i < 3 * numberofholes; i += 3) { + stringptr = readnumberline(inputline, polyfile, inpolyfilename); + stringptr = findnextnumber(stringptr); + if (*stringptr == '\0') { + printf("Error: Hole %d has no x coord.\n", firstnumber + (i / 3)); + break; + } else { + holelist[i] = (REAL) strtod(stringptr, &stringptr); + } + stringptr = findnextnumber(stringptr); + if (*stringptr == '\0') { + printf("Error: Hole %d has no y coord.\n", firstnumber + (i / 3)); + break; + } else { + holelist[i + 1] = (REAL) strtod(stringptr, &stringptr); + } + stringptr = findnextnumber(stringptr); + if (*stringptr == '\0') { + printf("Error: Hole %d has no z coord.\n", firstnumber + (i / 3)); + break; + } else { + holelist[i + 2] = (REAL) strtod(stringptr, &stringptr); + } + } + if (i < 3 * numberofholes) { + // This must be caused by an error. + fclose(polyfile); + return false; + } + } + + // Read the region section. The 'region' section is optional, if we don't + // reach the end of the file, try read it in. + do { + stringptr = fgets(inputline, INPUTLINESIZE, polyfile); + if (stringptr == (char *) NULL) { + break; + } + // Skip anything that doesn't look like a number, a comment, + // or the end of a line. + while ((*stringptr != '\0') && (*stringptr != '#') + && (*stringptr != '.') && (*stringptr != '+') && (*stringptr != '-') + && ((*stringptr < '0') || (*stringptr > '9'))) { + stringptr++; + } + // If it's a comment or end of line, read another line and try again. + } while ((*stringptr == '#') || (*stringptr == '\0')); + + if (stringptr != (char *) NULL && *stringptr != '\0') { + numberofregions = (int) strtol (stringptr, &stringptr, 0); + } else { + numberofregions = 0; + } + if (numberofregions > 0) { + // Initialize 'regionlist'. + regionlist = new REAL[numberofregions * 5]; + index = 0; + for (i = 0; i < numberofregions; i++) { + stringptr = readnumberline(inputline, polyfile, inpolyfilename); + stringptr = findnextnumber(stringptr); + if (*stringptr == '\0') { + printf("Error: Region %d has no x coordinate.\n", firstnumber + i); + break; + } else { + regionlist[index++] = (REAL) strtod(stringptr, &stringptr); + } + stringptr = findnextnumber(stringptr); + if (*stringptr == '\0') { + printf("Error: Region %d has no y coordinate.\n", firstnumber + i); + break; + } else { + regionlist[index++] = (REAL) strtod(stringptr, &stringptr); + } + stringptr = findnextnumber(stringptr); + if (*stringptr == '\0') { + printf("Error: Region %d has no z coordinate.\n", firstnumber + i); + break; + } else { + regionlist[index++] = (REAL) strtod(stringptr, &stringptr); + } + stringptr = findnextnumber(stringptr); + if (*stringptr == '\0') { + printf("Error: Region %d has no region attrib.\n", firstnumber + i); + break; + } else { + regionlist[index++] = (REAL) strtod(stringptr, &stringptr); + } + stringptr = findnextnumber(stringptr); + if (*stringptr == '\0') { + regionlist[index] = regionlist[index - 1]; + } else { + regionlist[index] = (REAL) strtod(stringptr, &stringptr); + } + index++; + } + if (i < numberofregions) { + // This must be caused by an error. + fclose(polyfile); + return false; + } + } + + // End of reading poly/smesh file. + fclose(polyfile); + return true; +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// load_off() Load a polyhedron described in a .off file. // +// // +// The .off format is one of file formats of the Geomview, an interactive // +// program for viewing and manipulating geometric objects. More information // +// is available form: http://www.geomview.org. // +// // +// 'filename' is a input filename with extension .off or without extension ( // +// the .off will be added in this case). On completion, the polyhedron is // +// returned in 'pointlist' and 'facetlist'. // +// // +/////////////////////////////////////////////////////////////////////////////// + +bool tetgenio::load_off(char* filename) +{ + FILE *fp; + tetgenio::facet *f; + tetgenio::polygon *p; + char infilename[FILENAMESIZE]; + char buffer[INPUTLINESIZE]; + char *bufferp; + double *coord; + int nverts = 0, iverts = 0; + int nfaces = 0, ifaces = 0; + int nedges = 0; + int line_count = 0, i; + + strncpy(infilename, filename, 1024 - 1); + infilename[FILENAMESIZE - 1] = '\0'; + if (infilename[0] == '\0') { + printf("Error: No filename.\n"); + return false; + } + if (strcmp(&infilename[strlen(infilename) - 4], ".off") != 0) { + strcat(infilename, ".off"); + } + + if (!(fp = fopen(infilename, "r"))) { + printf("File I/O Error: Unable to open file %s\n", infilename); + return false; + } + printf("Opening %s.\n", infilename); + + // OFF requires the index starts from '0'. + firstnumber = 0; + + while ((bufferp = readline(buffer, fp, &line_count)) != NULL) { + // Check section + if (nverts == 0) { + // Read header + bufferp = strstr(bufferp, "OFF"); + if (bufferp != NULL) { + // Read mesh counts + bufferp = findnextnumber(bufferp); // Skip field "OFF". + if (*bufferp == '\0') { + // Read a non-empty line. + bufferp = readline(buffer, fp, &line_count); + } + if ((sscanf(bufferp, "%d%d%d", &nverts, &nfaces, &nedges) != 3) + || (nverts == 0)) { + printf("Syntax error reading header on line %d in file %s\n", + line_count, infilename); + fclose(fp); + return false; + } + // Allocate memory for 'tetgenio' + if (nverts > 0) { + numberofpoints = nverts; + pointlist = new REAL[nverts * 3]; + assert(pointlist != NULL); + } + if (nfaces > 0) { + numberoffacets = nfaces; + facetlist = new tetgenio::facet[nfaces]; + assert(facetlist); + } + } + } else if (iverts < nverts) { + // Read vertex coordinates + coord = &pointlist[iverts * 3]; + for (i = 0; i < 3; i++) { + if (*bufferp == '\0') { + printf("Syntax error reading vertex coords on line %d in file %s\n", + line_count, infilename); + fclose(fp); + return false; + } + coord[i] = (REAL) strtod(bufferp, &bufferp); + bufferp = findnextnumber(bufferp); + } + iverts++; + } else if (ifaces < nfaces) { + // Get next face + f = &facetlist[ifaces]; + init(f); + // In .off format, each facet has one polygon, no hole. + f->numberofpolygons = 1; + f->polygonlist = new tetgenio::polygon[1]; + p = &f->polygonlist[0]; + init(p); + // Read the number of vertices, it should be greater than 0. + p->numberofvertices = (int) strtol(bufferp, &bufferp, 0); + if (p->numberofvertices == 0) { + printf("Syntax error reading polygon on line %d in file %s\n", + line_count, infilename); + fclose(fp); + return false; + } + // Allocate memory for face vertices + p->vertexlist = new int[p->numberofvertices]; + for (i = 0; i < p->numberofvertices; i++) { + bufferp = findnextnumber(bufferp); + if (*bufferp == '\0') { + printf("Syntax error reading polygon on line %d in file %s\n", + line_count, infilename); + fclose(fp); + return false; + } + p->vertexlist[i] = (int) strtol(bufferp, &bufferp, 0); + } + ifaces++; + } else { + // Should never get here + printf("Found extra text starting at line %d in file %s\n", line_count, + infilename); + break; + } + } + + // Close file + fclose(fp); + + // Check whether read all points + if (iverts != nverts) { + printf("Expected %d vertices, but read only %d vertices in file %s\n", + nverts, iverts, infilename); + return false; + } + + // Check whether read all faces + if (ifaces != nfaces) { + printf("Expected %d faces, but read only %d faces in file %s\n", + nfaces, ifaces, infilename); + return false; + } + + return true; +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// load_ply() Load a polyhedron described in a .ply file. // +// // +// 'filename' is the file name with extension .ply or without extension (the // +// .ply will be added in this case). // +// // +// This is a simplified version of reading .ply files, which only reads the // +// set of vertices and the set of faces. Other informations (such as color, // +// material, texture, etc) in .ply file are ignored. Complete routines for // +// reading and writing ,ply files are available from: http://www.cc.gatech. // +// edu/projects/large_models/ply.html. Except the header section, ply file // +// format has exactly the same format for listing vertices and polygons as // +// off file format. // +// // +// On completion, 'pointlist' and 'facetlist' together return the polyhedron.// +// // +/////////////////////////////////////////////////////////////////////////////// + +bool tetgenio::load_ply(char* filename) +{ + FILE *fp; + tetgenio::facet *f; + tetgenio::polygon *p; + char infilename[FILENAMESIZE]; + char buffer[INPUTLINESIZE]; + char *bufferp, *str; + double *coord; + int endheader = 0, format = 0; + int nverts = 0, iverts = 0; + int nfaces = 0, ifaces = 0; + int line_count = 0, i; + + strncpy(infilename, filename, FILENAMESIZE - 1); + infilename[FILENAMESIZE - 1] = '\0'; + if (infilename[0] == '\0') { + printf("Error: No filename.\n"); + return false; + } + if (strcmp(&infilename[strlen(infilename) - 4], ".ply") != 0) { + strcat(infilename, ".ply"); + } + + if (!(fp = fopen(infilename, "r"))) { + printf("Error: Unable to open file %s\n", infilename); + return false; + } + printf("Opening %s.\n", infilename); + + // PLY requires the index starts from '0'. + firstnumber = 0; + + while ((bufferp = readline(buffer, fp, &line_count)) != NULL) { + if (!endheader) { + // Find if it is the keyword "end_header". + str = strstr(bufferp, "end_header"); + // strstr() is case sensitive. + if (!str) str = strstr(bufferp, "End_header"); + if (!str) str = strstr(bufferp, "End_Header"); + if (str) { + // This is the end of the header section. + endheader = 1; + continue; + } + // Parse the number of vertices and the number of faces. + if (nverts == 0 || nfaces == 0) { + // Find if it si the keyword "element". + str = strstr(bufferp, "element"); + if (!str) str = strstr(bufferp, "Element"); + if (str) { + bufferp = findnextfield(str); + if (*bufferp == '\0') { + printf("Syntax error reading element type on line%d in file %s\n", + line_count, infilename); + fclose(fp); + return false; + } + if (nverts == 0) { + // Find if it is the keyword "vertex". + str = strstr(bufferp, "vertex"); + if (!str) str = strstr(bufferp, "Vertex"); + if (str) { + bufferp = findnextnumber(str); + if (*bufferp == '\0') { + printf("Syntax error reading vertex number on line"); + printf(" %d in file %s\n", line_count, infilename); + fclose(fp); + return false; + } + nverts = (int) strtol(bufferp, &bufferp, 0); + // Allocate memory for 'tetgenio' + if (nverts > 0) { + numberofpoints = nverts; + pointlist = new REAL[nverts * 3]; + assert(pointlist != NULL); + } + } + } + if (nfaces == 0) { + // Find if it is the keyword "face". + str = strstr(bufferp, "face"); + if (!str) str = strstr(bufferp, "Face"); + if (str) { + bufferp = findnextnumber(str); + if (*bufferp == '\0') { + printf("Syntax error reading face number on line"); + printf(" %d in file %s\n", line_count, infilename); + fclose(fp); + return false; + } + nfaces = (int) strtol(bufferp, &bufferp, 0); + // Allocate memory for 'tetgenio' + if (nfaces > 0) { + numberoffacets = nfaces; + facetlist = new tetgenio::facet[nfaces]; + assert(facetlist); + } + } + } + } // It is not the string "element". + } + if (format == 0) { + // Find the keyword "format". + str = strstr(bufferp, "format"); + if (!str) str = strstr(bufferp, "Format"); + if (str) { + format = 1; + bufferp = findnextfield(str); + // Find if it is the string "ascii". + str = strstr(bufferp, "ascii"); + if (!str) str = strstr(bufferp, "ASCII"); + if (!str) { + printf("This routine only reads ascii format of ply files.\n"); + printf("Hint: You can convert the binary to ascii format by\n"); + printf(" using the provided ply tools:\n"); + printf(" ply2ascii < %s > ascii_%s\n", infilename, infilename); + fclose(fp); + return false; + } + } + } + } else if (iverts < nverts) { + // Read vertex coordinates + coord = &pointlist[iverts * 3]; + for (i = 0; i < 3; i++) { + if (*bufferp == '\0') { + printf("Syntax error reading vertex coords on line %d in file %s\n", + line_count, infilename); + fclose(fp); + return false; + } + coord[i] = (REAL) strtod(bufferp, &bufferp); + bufferp = findnextnumber(bufferp); + } + iverts++; + } else if (ifaces < nfaces) { + // Get next face + f = &facetlist[ifaces]; + init(f); + // In .off format, each facet has one polygon, no hole. + f->numberofpolygons = 1; + f->polygonlist = new tetgenio::polygon[1]; + p = &f->polygonlist[0]; + init(p); + // Read the number of vertices, it should be greater than 0. + p->numberofvertices = (int) strtol(bufferp, &bufferp, 0); + if (p->numberofvertices == 0) { + printf("Syntax error reading polygon on line %d in file %s\n", + line_count, infilename); + fclose(fp); + return false; + } + // Allocate memory for face vertices + p->vertexlist = new int[p->numberofvertices]; + for (i = 0; i < p->numberofvertices; i++) { + bufferp = findnextnumber(bufferp); + if (*bufferp == '\0') { + printf("Syntax error reading polygon on line %d in file %s\n", + line_count, infilename); + fclose(fp); + return false; + } + p->vertexlist[i] = (int) strtol(bufferp, &bufferp, 0); + } + ifaces++; + } else { + // Should never get here + printf("Found extra text starting at line %d in file %s\n", line_count, + infilename); + break; + } + } + + // Close file + fclose(fp); + + // Check whether read all points + if (iverts != nverts) { + printf("Expected %d vertices, but read only %d vertices in file %s\n", + nverts, iverts, infilename); + return false; + } + + // Check whether read all faces + if (ifaces != nfaces) { + printf("Expected %d faces, but read only %d faces in file %s\n", + nfaces, ifaces, infilename); + return false; + } + + return true; +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// load_stl() Load a surface mesh described in a .stl file. // +// // +// 'filename' is the file name with extension .stl or without extension (the // +// .stl will be added in this case). // +// // +// The .stl or stereolithography format is an ASCII or binary file used in // +// manufacturing. It is a list of the triangular surfaces that describe a // +// computer generated solid model. This is the standard input for most rapid // +// prototyping machines. // +// // +// On completion, 'pointlist' and 'facetlist' together return the polyhedron.// +// Note: After load_stl(), there exist many duplicated points in 'pointlist'.// +// They will be unified during the Delaunay tetrahedralization process. // +// // +/////////////////////////////////////////////////////////////////////////////// + +bool tetgenio::load_stl(char* filename) +{ + FILE *fp; + tetgenmesh::list *plist; + tetgenio::facet *f; + tetgenio::polygon *p; + char infilename[FILENAMESIZE]; + char buffer[INPUTLINESIZE]; + char *bufferp, *str; + double *coord; + int solid = 0; + int nverts = 0, iverts = 0; + int nfaces = 0; + int line_count = 0, i; + + strncpy(infilename, filename, FILENAMESIZE - 1); + infilename[FILENAMESIZE - 1] = '\0'; + if (infilename[0] == '\0') { + printf("Error: No filename.\n"); + return false; + } + if (strcmp(&infilename[strlen(infilename) - 4], ".stl") != 0) { + strcat(infilename, ".stl"); + } + + if (!(fp = fopen(infilename, "r"))) { + printf("Error: Unable to open file %s\n", infilename); + return false; + } + printf("Opening %s.\n", infilename); + + // STL file has no number of points available. Use a list to read points. + plist = new tetgenmesh::list(sizeof(double) * 3, NULL, 1024); + + while ((bufferp = readline(buffer, fp, &line_count)) != NULL) { + // The ASCII .stl file must start with the lower case keyword solid and + // end with endsolid. + if (solid == 0) { + // Read header + bufferp = strstr(bufferp, "solid"); + if (bufferp != NULL) { + solid = 1; + } + } else { + // We're inside the block of the solid. + str = bufferp; + // Is this the end of the solid. + bufferp = strstr(bufferp, "endsolid"); + if (bufferp != NULL) { + solid = 0; + } else { + // Read the XYZ coordinates if it is a vertex. + bufferp = str; + bufferp = strstr(bufferp, "vertex"); + if (bufferp != NULL) { + coord = (double *) plist->append(NULL); + for (i = 0; i < 3; i++) { + bufferp = findnextnumber(bufferp); + if (*bufferp == '\0') { + printf("Syntax error reading vertex coords on line %d\n", + line_count); + delete plist; + fclose(fp); + return false; + } + coord[i] = (REAL) strtod(bufferp, &bufferp); + } + } + } + } + } + fclose(fp); + + nverts = plist->len(); + // nverts should be an integer times 3 (every 3 vertices denote a face). + if (nverts == 0 || (nverts % 3 != 0)) { + printf("Error: Wrong number of vertices in file %s.\n", infilename); + delete plist; + return false; + } + numberofpoints = nverts; + pointlist = new REAL[nverts * 3]; + assert(pointlist != NULL); + for (i = 0; i < nverts; i++) { + coord = (double *) (* plist)[i]; + iverts = i * 3; + pointlist[iverts] = (REAL) coord[0]; + pointlist[iverts + 1] = (REAL) coord[1]; + pointlist[iverts + 2] = (REAL) coord[2]; + } + + nfaces = (int) (nverts / 3); + numberoffacets = nfaces; + facetlist = new tetgenio::facet[nfaces]; + assert(facetlist != NULL); + + // Default use '1' as the array starting index. + firstnumber = 1; + iverts = firstnumber; + for (i = 0; i < nfaces; i++) { + f = &facetlist[i]; + init(f); + // In .stl format, each facet has one polygon, no hole. + f->numberofpolygons = 1; + f->polygonlist = new tetgenio::polygon[1]; + p = &f->polygonlist[0]; + init(p); + // Each polygon has three vertices. + p->numberofvertices = 3; + p->vertexlist = new int[p->numberofvertices]; + p->vertexlist[0] = iverts; + p->vertexlist[1] = iverts + 1; + p->vertexlist[2] = iverts + 2; + iverts += 3; + } + + delete plist; + return true; +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// load_medit() Load a surface mesh described in .mesh file. // +// // +// 'filename' is the file name with extension .mesh or without entension ( // +// the .mesh will be added in this case). .mesh is the file format of Medit, // +// a user-friendly interactive mesh viewing program. // +// // +// This routine ONLY reads the sections containing vertices and triangles, // +// other sections (such as tetrahedra, edges, ...) are ignored. // +// // +/////////////////////////////////////////////////////////////////////////////// + +bool tetgenio::load_medit(char* filename) +{ + FILE *fp; + tetgenio::facet *f; + tetgenio::polygon *p; + char infilename[FILENAMESIZE]; + char buffer[INPUTLINESIZE]; + char *bufferp, *str; + double *coord; + int nverts = 0; + int nfaces = 0; + int line_count = 0; + int corners = 0; // 3 (triangle) or 4 (quad). + int i, j; + + strncpy(infilename, filename, FILENAMESIZE - 1); + infilename[FILENAMESIZE - 1] = '\0'; + if (infilename[0] == '\0') { + printf("Error: No filename.\n"); + return false; + } + if (strcmp(&infilename[strlen(infilename) - 5], ".mesh") != 0) { + strcat(infilename, ".mesh"); + } + + if (!(fp = fopen(infilename, "r"))) { + printf("Error: Unable to open file %s\n", infilename); + return false; + } + printf("Opening %s.\n", infilename); + + // Default uses the index starts from '1'. + firstnumber = 1; + + while ((bufferp = readline(buffer, fp, &line_count)) != NULL) { + if (*bufferp == '#') continue; // A comment line is skipped. + if (nverts == 0) { + // Find if it is the keyword "Vertices". + str = strstr(bufferp, "Vertices"); + if (!str) str = strstr(bufferp, "vertices"); + if (!str) str = strstr(bufferp, "VERTICES"); + if (str) { + // Read the number of vertices. + bufferp = findnextnumber(str); // Skip field "Vertices". + if (*bufferp == '\0') { + // Read a non-empty line. + bufferp = readline(buffer, fp, &line_count); + } + nverts = (int) strtol(bufferp, &bufferp, 0); + // Allocate memory for 'tetgenio' + if (nverts > 0) { + numberofpoints = nverts; + pointlist = new REAL[nverts * 3]; + assert(pointlist != NULL); + } + // Read the follwoing node list. + for (i = 0; i < nverts; i++) { + bufferp = readline(buffer, fp, &line_count); + if (bufferp == NULL) { + printf("Unexpected end of file on line %d in file %s\n", + line_count, infilename); + fclose(fp); + return false; + } + // Read vertex coordinates + coord = &pointlist[i * 3]; + for (j = 0; j < 3; j++) { + if (*bufferp == '\0') { + printf("Syntax error reading vertex coords on line"); + printf(" %d in file %s\n", line_count, infilename); + fclose(fp); + return false; + } + coord[j] = (REAL) strtod(bufferp, &bufferp); + bufferp = findnextnumber(bufferp); + } + } + continue; + } + } + if (nfaces == 0) { + // Find if it is the keyword "Triangles" or "Quadrilaterals". + str = strstr(bufferp, "Triangles"); + if (!str) str = strstr(bufferp, "triangles"); + if (!str) str = strstr(bufferp, "TRIANGLES"); + if (str) { + corners = 3; + } else { + str = strstr(bufferp, "Quadrilaterals"); + if (!str) str = strstr(bufferp, "quadrilaterals"); + if (!str) str = strstr(bufferp, "QUADRILATERALS"); + if (str) { + corners = 4; + } + } + if (corners == 3 || corners == 4) { + // Read the number of triangles (or quadrilaterals). + bufferp = findnextnumber(str); // Skip field "Triangles". + if (*bufferp == '\0') { + // Read a non-empty line. + bufferp = readline(buffer, fp, &line_count); + } + nfaces = strtol(bufferp, &bufferp, 0); + // Allocate memory for 'tetgenio' + if (nfaces > 0) { + numberoffacets = nfaces; + facetlist = new tetgenio::facet[nfaces]; + assert(facetlist != NULL); + facetmarkerlist = new int[nfaces]; + assert(facetmarkerlist != NULL); + } + // Read the following list of faces. + for (i = 0; i < nfaces; i++) { + bufferp = readline(buffer, fp, &line_count); + if (bufferp == NULL) { + printf("Unexpected end of file on line %d in file %s\n", + line_count, infilename); + fclose(fp); + return false; + } + f = &facetlist[i]; + tetgenio::init(f); + // In .mesh format, each facet has one polygon, no hole. + f->numberofpolygons = 1; + f->polygonlist = new tetgenio::polygon[1]; + p = &f->polygonlist[0]; + tetgenio::init(p); + p->numberofvertices = corners; + // Allocate memory for face vertices + p->vertexlist = new int[p->numberofvertices]; + assert(p->vertexlist != NULL); + // Read the vertices of the face. + for (j = 0; j < corners; j++) { + if (*bufferp == '\0') { + printf("Syntax error reading face on line %d in file %s\n", + line_count, infilename); + fclose(fp); + return false; + } + p->vertexlist[j] = (int) strtol(bufferp, &bufferp, 0); + if (firstnumber == 1) { + // Check if a '0' index appears. + if (p->vertexlist[j] == 0) { + // The first index is set to be 0. + firstnumber = 0; + } + } + bufferp = findnextnumber(bufferp); + } + // Read the marker of the face if it exists. + facetmarkerlist[i] = 0; + if (*bufferp != '\0') { + facetmarkerlist[i] = (int) strtol(bufferp, &bufferp, 0); + } + } + continue; + } + } + if (nverts > 0 && nfaces > 0) break; // Ignore other data. + } + + // Close file + fclose(fp); + + return true; +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// load_plc() Load a piecewise linear complex from file. // +// // +// This is main entrance for loading plcs from different file formats into // +// tetgenio. 'filename' is the input file name without extention. 'object' // +// indicates which file format is used to describ the plc. // +// // +/////////////////////////////////////////////////////////////////////////////// + +bool tetgenio::load_plc(char* filename, int object) +{ + enum tetgenbehavior::objecttype type; + + type = (enum tetgenbehavior::objecttype) object; + switch (type) { + case tetgenbehavior::NODES: + return load_node(filename); + case tetgenbehavior::POLY: + return load_poly(filename); + case tetgenbehavior::OFF: + return load_off(filename); + case tetgenbehavior::PLY: + return load_ply(filename); + case tetgenbehavior::STL: + return load_stl(filename); + case tetgenbehavior::MEDIT: + return load_medit(filename); + default: + return load_poly(filename); + } +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// load_tetmesh() Load a tetrahedral mesh from files. // +// // +// 'filename' is the inputfile without suffix. The nodes of the tetrahedral // +// mesh is in "filename.node", the elements is in "filename.ele", if the // +// "filename.face" and "filename.vol" exists, they will also be read. // +// // +/////////////////////////////////////////////////////////////////////////////// + +bool tetgenio::load_tetmesh(char* filename) +{ + FILE *infile; + char innodefilename[FILENAMESIZE]; + char inelefilename[FILENAMESIZE]; + char infacefilename[FILENAMESIZE]; + char inedgefilename[FILENAMESIZE]; + char involfilename[FILENAMESIZE]; + char inputline[INPUTLINESIZE]; + char *stringptr, *infilename; + REAL attrib, volume; + int volelements; + int markers, corner; + int index, attribindex; + int i, j; + + // Assembling the actual file names we want to open. + strcpy(innodefilename, filename); + strcpy(inelefilename, filename); + strcpy(infacefilename, filename); + strcpy(inedgefilename, filename); + strcpy(involfilename, filename); + strcat(innodefilename, ".node"); + strcat(inelefilename, ".ele"); + strcat(infacefilename, ".face"); + strcat(inedgefilename, ".edge"); + strcat(involfilename, ".vol"); + + // Read the points from a .node file. + infilename = innodefilename; + printf("Opening %s.\n", infilename); + infile = fopen(infilename, "r"); + if (infile == (FILE *) NULL) { + printf("File I/O Error: Cannot access file %s.\n", infilename); + return false; + } + // Read number of points, number of dimensions, number of point + // attributes, and number of boundary markers. + stringptr = readnumberline(inputline, infile, infilename); + numberofpoints = (int) strtol (stringptr, &stringptr, 0); + stringptr = findnextnumber(stringptr); + if (*stringptr == '\0') { + mesh_dim = 3; + } else { + mesh_dim = (int) strtol (stringptr, &stringptr, 0); + } + stringptr = findnextnumber(stringptr); + if (*stringptr == '\0') { + numberofpointattributes = 0; + } else { + numberofpointattributes = (int) strtol (stringptr, &stringptr, 0); + } + stringptr = findnextnumber(stringptr); + if (*stringptr == '\0') { + markers = 0; // Default value. + } else { + markers = (int) strtol (stringptr, &stringptr, 0); + } + + if (mesh_dim != 3) { + printf("Error: load_tetmesh() only works for 3D points.\n"); + fclose(infile); + return false; + } + if (numberofpoints < 4) { + printf("File I/O error: Input should has at least 4 points.\n"); + fclose(infile); + return false; + } + + // Load the list of nodes. + if (!load_node_call(infile, markers, infilename)) { + fclose(infile); + return false; + } + + // Read the elements from a .ele file. + infilename = inelefilename; + printf("Opening %s.\n", infilename); + infile = fopen(infilename, "r"); + if (infile != (FILE *) NULL) { + // Read number of elements, number of corners (4 or 10), number of + // element attributes. + stringptr = readnumberline(inputline, infile, infilename); + numberoftetrahedra = (int) strtol (stringptr, &stringptr, 0); + stringptr = findnextnumber(stringptr); + if (*stringptr == '\0') { + numberofcorners = 4; // Default read 4 nodes per element. + } else { + numberofcorners = (int) strtol (stringptr, &stringptr, 0); + } + stringptr = findnextnumber(stringptr); + if (*stringptr == '\0') { + numberoftetrahedronattributes = 0; // Default no attribute. + } else { + numberoftetrahedronattributes = (int) strtol (stringptr, &stringptr, 0); + } + if (numberofcorners != 4 && numberofcorners != 10) { + printf("Error: Wrong number of corners %d (should be 4 or 10).\n", + numberofcorners); + fclose(infile); + return false; + } + // Allocate memory for tetrahedra. + if (numberoftetrahedra > 0) { + tetrahedronlist = new int[numberoftetrahedra * numberofcorners]; + if (tetrahedronlist == (int *) NULL) { + printf("Error: Out of memory.\n"); + exit(1); + } + // Allocate memory for output tetrahedron attributes if necessary. + if (numberoftetrahedronattributes > 0) { + tetrahedronattributelist = new REAL[numberoftetrahedra * + numberoftetrahedronattributes]; + if (tetrahedronattributelist == (REAL *) NULL) { + printf("Error: Out of memory.\n"); + exit(1); + } + } + } + // Read the list of tetrahedra. + index = 0; + attribindex = 0; + for (i = 0; i < numberoftetrahedra; i++) { + // Read tetrahedron index and the tetrahedron's corners. + stringptr = readnumberline(inputline, infile, infilename); + for (j = 0; j < numberofcorners; j++) { + stringptr = findnextnumber(stringptr); + if (*stringptr == '\0') { + printf("Error: Tetrahedron %d is missing vertex %d in %s.\n", + i + firstnumber, j + 1, infilename); + exit(1); + } + corner = (int) strtol(stringptr, &stringptr, 0); + if (corner < firstnumber || corner >= numberofpoints + firstnumber) { + printf("Error: Tetrahedron %d has an invalid vertex index.\n", + i + firstnumber); + exit(1); + } + tetrahedronlist[index++] = corner; + } + // Read the tetrahedron's attributes. + for (j = 0; j < numberoftetrahedronattributes; j++) { + stringptr = findnextnumber(stringptr); + if (*stringptr == '\0') { + attrib = 0.0; + } else { + attrib = (REAL) strtod(stringptr, &stringptr); + } + tetrahedronattributelist[attribindex++] = attrib; + } + } + fclose(infile); + } + + // Read the hullfaces or subfaces from a .face file if it exists. + infilename = infacefilename; + infile = fopen(infilename, "r"); + if (infile != (FILE *) NULL) { + printf("Opening %s.\n", infilename); + // Read number of faces, boundary markers. + stringptr = readnumberline(inputline, infile, infilename); + numberoftrifaces = (int) strtol (stringptr, &stringptr, 0); + stringptr = findnextnumber(stringptr); + if (*stringptr == '\0') { + markers = 0; // Default there is no marker per face. + } else { + markers = (int) strtol (stringptr, &stringptr, 0); + } + if (numberoftrifaces > 0) { + trifacelist = new int[numberoftrifaces * 3]; + if (trifacelist == (int *) NULL) { + printf("Error: Out of memory.\n"); + exit(1); + } + if (markers) { + trifacemarkerlist = new int[numberoftrifaces * 3]; + if (trifacemarkerlist == (int *) NULL) { + printf("Error: Out of memory.\n"); + exit(1); + } + } + } + // Read the list of faces. + index = 0; + for (i = 0; i < numberoftrifaces; i++) { + // Read face index and the face's three corners. + stringptr = readnumberline(inputline, infile, infilename); + for (j = 0; j < 3; j++) { + stringptr = findnextnumber(stringptr); + if (*stringptr == '\0') { + printf("Error: Face %d is missing vertex %d in %s.\n", + i + firstnumber, j + 1, infilename); + exit(1); + } + corner = (int) strtol(stringptr, &stringptr, 0); + if (corner < firstnumber || corner >= numberofpoints + firstnumber) { + printf("Error: Face %d has an invalid vertex index.\n", + i + firstnumber); + exit(1); + } + trifacelist[index++] = corner; + } + // Read the boundary marker if it exists. + if (markers) { + stringptr = findnextnumber(stringptr); + if (*stringptr == '\0') { + attrib = 0.0; + } else { + attrib = (REAL) strtod(stringptr, &stringptr); + } + trifacemarkerlist[i] = (int) attrib; + } + } + fclose(infile); + } + + // Read the boundary edges from a .edge file if it exists. + infilename = inedgefilename; + infile = fopen(infilename, "r"); + if (infile != (FILE *) NULL) { + printf("Opening %s.\n", infilename); + // Read number of boundary edges. + stringptr = readnumberline(inputline, infile, infilename); + numberofedges = (int) strtol (stringptr, &stringptr, 0); + if (numberofedges > 0) { + edgelist = new int[numberofedges * 2]; + if (edgelist == (int *) NULL) { + printf("Error: Out of memory.\n"); + exit(1); + } + } + // Read the list of faces. + index = 0; + for (i = 0; i < numberofedges; i++) { + // Read face index and the edge's two endpoints. + stringptr = readnumberline(inputline, infile, infilename); + for (j = 0; j < 2; j++) { + stringptr = findnextnumber(stringptr); + if (*stringptr == '\0') { + printf("Error: Edge %d is missing vertex %d in %s.\n", + i + firstnumber, j + 1, infilename); + exit(1); + } + corner = (int) strtol(stringptr, &stringptr, 0); + if (corner < firstnumber || corner >= numberofpoints + firstnumber) { + printf("Error: Edge %d has an invalid vertex index.\n", + i + firstnumber); + exit(1); + } + edgelist[index++] = corner; + } + } + fclose(infile); + } + + // Read the volume constraints from a .vol file if it exists. + infilename = involfilename; + infile = fopen(infilename, "r"); + if (infile != (FILE *) NULL) { + printf("Opening %s.\n", infilename); + // Read number of tetrahedra. + stringptr = readnumberline(inputline, infile, infilename); + volelements = (int) strtol (stringptr, &stringptr, 0); + if (volelements != numberoftetrahedra) { + printf("Warning: %s and %s disagree on number of tetrahedra.\n", + inelefilename, involfilename); + volelements = 0; + } + if (volelements > 0) { + tetrahedronvolumelist = new REAL[volelements]; + if (tetrahedronvolumelist == (REAL *) NULL) { + printf("Error: Out of memory.\n"); + exit(1); + } + } + // Read the list of volume constraints. + for (i = 0; i < volelements; i++) { + stringptr = readnumberline(inputline, infile, infilename); + stringptr = findnextnumber(stringptr); + if (*stringptr == '\0') { + volume = -1.0; // No constraint on this tetrahedron. + } else { + volume = (REAL) strtod(stringptr, &stringptr); + } + tetrahedronvolumelist[i] = volume; + } + fclose(infile); + } + + return true; +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// save_nodes() Save points to a .node file. // +// // +// 'filename' is a string containing the file name without suffix. // +// // +/////////////////////////////////////////////////////////////////////////////// + +void tetgenio::save_nodes(char* filename) +{ + FILE *fout; + char outnodefilename[FILENAMESIZE]; + int i, j; + + sprintf(outnodefilename, "%s.node", filename); + printf("Saving nodes to %s\n", outnodefilename); + fout = fopen(outnodefilename, "w"); + fprintf(fout, "%d %d %d %d\n", numberofpoints, mesh_dim, + numberofpointattributes, pointmarkerlist != NULL ? 1 : 0); + for (i = 0; i < numberofpoints; i++) { + if (mesh_dim == 2) { + fprintf(fout, "%d %.16g %.16g", i + firstnumber, pointlist[i * 2], + pointlist[i * 2 + 1]); + } else { + fprintf(fout, "%d %.16g %.16g %.16g", i + firstnumber, + pointlist[i * 3], pointlist[i * 3 + 1], pointlist[i * 3 + 2]); + } + for (j = 0; j < numberofpointattributes; j++) { + fprintf(fout, " %.16g", + pointattributelist[i * numberofpointattributes+j]); + } + if (pointmarkerlist != NULL) { + fprintf(fout, " %d", pointmarkerlist[i]); + } + fprintf(fout, "\n"); + } + + fclose(fout); +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// save_elements() Save elements to a .ele file. // +// // +// 'filename' is a string containing the file name without suffix. // +// // +/////////////////////////////////////////////////////////////////////////////// + +void tetgenio::save_elements(char* filename) +{ + FILE *fout; + char outelefilename[FILENAMESIZE]; + int i, j; + + sprintf(outelefilename, "%s.ele", filename); + printf("Saving elements to %s\n", outelefilename); + fout = fopen(outelefilename, "w"); + fprintf(fout, "%d %d %d\n", numberoftetrahedra, numberofcorners, + numberoftetrahedronattributes); + for (i = 0; i < numberoftetrahedra; i++) { + fprintf(fout, "%d", i + firstnumber); + for (j = 0; j < numberofcorners; j++) { + fprintf(fout, " %5d", tetrahedronlist[i * numberofcorners + j]); + } + for (j = 0; j < numberoftetrahedronattributes; j++) { + fprintf(fout, " %g", + tetrahedronattributelist[i * numberoftetrahedronattributes + j]); + } + fprintf(fout, "\n"); + } + + fclose(fout); +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// save_faces() Save faces to a .face file. // +// // +// 'filename' is a string containing the file name without suffix. // +// // +/////////////////////////////////////////////////////////////////////////////// + +void tetgenio::save_faces(char* filename) +{ + FILE *fout; + char outfacefilename[FILENAMESIZE]; + int i; + + sprintf(outfacefilename, "%s.face", filename); + printf("Saving faces to %s\n", outfacefilename); + fout = fopen(outfacefilename, "w"); + fprintf(fout, "%d %d\n", numberoftrifaces, + trifacemarkerlist != NULL ? 1 : 0); + for (i = 0; i < numberoftrifaces; i++) { + fprintf(fout, "%d %5d %5d %5d", i + firstnumber, trifacelist[i * 3], + trifacelist[i * 3 + 1], trifacelist[i * 3 +2]); + if (trifacemarkerlist != NULL) { + fprintf(fout, " %d", trifacemarkerlist[i]); + } + fprintf(fout, "\n"); + } + + fclose(fout); +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// save_edges() Save egdes to a .edge file. // +// // +// 'filename' is a string containing the file name without suffix. // +// // +/////////////////////////////////////////////////////////////////////////////// + +void tetgenio::save_edges(char* filename) +{ + FILE *fout; + char outedgefilename[FILENAMESIZE]; + int i; + + sprintf(outedgefilename, "%s.edge", filename); + printf("Saving edges to %s\n", outedgefilename); + fout = fopen(outedgefilename, "w"); + fprintf(fout, "%d %d\n", numberofedges, edgemarkerlist != NULL ? 1 : 0); + for (i = 0; i < numberofedges; i++) { + fprintf(fout, "%d %4d %4d", i + firstnumber, edgelist[i * 2], + edgelist[i * 2 + 1]); + if (edgemarkerlist != NULL) { + fprintf(fout, " %d", edgemarkerlist[i]); + } + fprintf(fout, "\n"); + } + + fclose(fout); +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// save_neighbors() Save egdes to a .neigh file. // +// // +// 'filename' is a string containing the file name without suffix. // +// // +/////////////////////////////////////////////////////////////////////////////// + +void tetgenio::save_neighbors(char* filename) +{ + FILE *fout; + char outneighborfilename[FILENAMESIZE]; + int i; + + sprintf(outneighborfilename, "%s.neigh", filename); + printf("Saving neighbors to %s\n", outneighborfilename); + fout = fopen(outneighborfilename, "w"); + fprintf(fout, "%d %d\n", numberoftetrahedra, mesh_dim + 1); + for (i = 0; i < numberoftetrahedra; i++) { + if (mesh_dim == 2) { + fprintf(fout, "%d %5d %5d %5d", i + firstnumber, neighborlist[i * 3], + neighborlist[i * 3 + 1], neighborlist[i * 3 + 2]); + } else { + fprintf(fout, "%d %5d %5d %5d %5d", i + firstnumber, + neighborlist[i * 4], neighborlist[i * 4 + 1], + neighborlist[i * 4 + 2], neighborlist[i * 4 + 3]); + } + fprintf(fout, "\n"); + } + + fclose(fout); +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// save_poly() Save segments or facets to a .poly file. // +// // +// 'filename' is a string containing the file name without suffix. It only // +// save the facets, holes and regions. The nodes are saved in a .node file // +// by routine save_nodes(). // +// // +/////////////////////////////////////////////////////////////////////////////// + +void tetgenio::save_poly(char* filename) +{ + FILE *fout; + facet *f; + polygon *p; + char outpolyfilename[FILENAMESIZE]; + int i, j, k; + + sprintf(outpolyfilename, "%s.poly", filename); + printf("Saving poly to %s\n", outpolyfilename); + fout = fopen(outpolyfilename, "w"); + + // The zero indicates that the vertices are in a separate .node file. + // Followed by number of dimensions, number of vertex attributes, + // and number of boundary markers (zero or one). + fprintf(fout, "%d %d %d %d\n", 0, mesh_dim, numberofpointattributes, + pointmarkerlist != NULL ? 1 : 0); + + // Save segments or facets. + if (mesh_dim == 2) { + // Number of segments, number of boundary markers (zero or one). + fprintf(fout, "%d %d\n", numberofedges, edgemarkerlist != NULL ? 1 : 0); + for (i = 0; i < numberofedges; i++) { + fprintf(fout, "%d %4d %4d", i + firstnumber, edgelist[i * 2], + edgelist[i * 2 + 1]); + if (edgemarkerlist != NULL) { + fprintf(fout, " %d", edgemarkerlist[i]); + } + fprintf(fout, "\n"); + } + } else { + // Number of facets, number of boundary markers (zero or one). + fprintf(fout, "%d %d\n", numberoffacets, facetmarkerlist != NULL ? 1 : 0); + for (i = 0; i < numberoffacets; i++) { + f = &(facetlist[i]); + fprintf(fout, "%d %d %d # %d\n", f->numberofpolygons,f->numberofholes, + facetmarkerlist != NULL ? facetmarkerlist[i] : 0, i + firstnumber); + // Output polygons of this facet. + for (j = 0; j < f->numberofpolygons; j++) { + p = &(f->polygonlist[j]); + fprintf(fout, "%d ", p->numberofvertices); + for (k = 0; k < p->numberofvertices; k++) { + if (((k + 1) % 10) == 0) { + fprintf(fout, "\n "); + } + fprintf(fout, " %d", p->vertexlist[k]); + } + fprintf(fout, "\n"); + } + // Output holes of this facet. + for (j = 0; j < f->numberofholes; j++) { + fprintf(fout, "%d %.12g %.12g %.12g\n", j + firstnumber, + f->holelist[j * 3], f->holelist[j * 3 + 1], f->holelist[j * 3 + 2]); + } + } + } + + // Save holes. + fprintf(fout, "%d\n", numberofholes); + for (i = 0; i < numberofholes; i++) { + // Output x, y coordinates. + fprintf(fout, "%d %.12g %.12g", i + firstnumber, holelist[i * mesh_dim], + holelist[i * mesh_dim + 1]); + if (mesh_dim == 3) { + // Output z coordinate. + fprintf(fout, " %.12g", holelist[i * mesh_dim + 2]); + } + fprintf(fout, "\n"); + } + + // Save regions. + fprintf(fout, "%d\n", numberofregions); + for (i = 0; i < numberofregions; i++) { + if (mesh_dim == 2) { + // Output the index, x, y coordinates, attribute (region number) + // and maximum area constraint (maybe -1). + fprintf(fout, "%d %.12g %.12g %.12g %.12g\n", i + firstnumber, + regionlist[i * 4], regionlist[i * 4 + 1], + regionlist[i * 4 + 2], regionlist[i * 4 + 3]); + } else { + // Output the index, x, y, z coordinates, attribute (region number) + // and maximum volume constraint (maybe -1). + fprintf(fout, "%d %.12g %.12g %.12g %.12g %.12g\n", i + firstnumber, + regionlist[i * 5], regionlist[i * 5 + 1], + regionlist[i * 5 + 2], regionlist[i * 5 + 3], + regionlist[i * 5 + 4]); + } + } + + fclose(fout); +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// readline() Read a nonempty line from a file. // +// // +// A line is considered "nonempty" if it contains something more than white // +// spaces. If a line is considered empty, it will be dropped and the next // +// line will be read, this process ends until reaching the end-of-file or a // +// non-empty line. Return NULL if it is the end-of-file, otherwise, return // +// a pointer to the first non-whitespace character of the line. // +// // +/////////////////////////////////////////////////////////////////////////////// + +char* tetgenio::readline(char *string, FILE *infile, int *linenumber) +{ + char *result; + + // Search for a non-empty line. + do { + result = fgets(string, INPUTLINESIZE - 1, infile); + (*linenumber)++; + if (result == (char *) NULL) { + return (char *) NULL; + } + // Skip white spaces. + while ((*result == ' ') || (*result == '\t')) result++; + // If it's end of line, read another line and try again. + } while (*result == '\0'); + return result; +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// findnextfield() Find the next field of a string. // +// // +// Jumps past the current field by searching for whitespace or a comma, then // +// jumps past the whitespace or the comma to find the next field. // +// // +/////////////////////////////////////////////////////////////////////////////// + +char* tetgenio::findnextfield(char *string) +{ + char *result; + + result = string; + // Skip the current field. Stop upon reaching whitespace or a comma. + while ((*result != '\0') && (*result != ' ') && (*result != '\t') && + (*result != ',')) { + result++; + } + // Now skip the whitespace or the comma, stop at anything else that looks + // like a character, or the end of a line. + while ((*result == ' ') || (*result == '\t') || (*result == ',')) { + result++; + } + return result; +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// readnumberline() Read a nonempty number line from a file. // +// // +// A line is considered "nonempty" if it contains something that looks like // +// a number. Comments (prefaced by `#') are ignored. // +// // +/////////////////////////////////////////////////////////////////////////////// + +char* tetgenio::readnumberline(char *string, FILE *infile, char *infilename) +{ + char *result; + + // Search for something that looks like a number. + do { + result = fgets(string, INPUTLINESIZE, infile); + if (result == (char *) NULL) { + printf(" Error: Unexpected end of file in %s.\n", infilename); + exit(1); + } + // Skip anything that doesn't look like a number, a comment, + // or the end of a line. + while ((*result != '\0') && (*result != '#') + && (*result != '.') && (*result != '+') && (*result != '-') + && ((*result < '0') || (*result > '9'))) { + result++; + } + // If it's a comment or end of line, read another line and try again. + } while ((*result == '#') || (*result == '\0')); + return result; +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// findnextnumber() Find the next field of a number string. // +// // +// Jumps past the current field by searching for whitespace or a comma, then // +// jumps past the whitespace or the comma to find the next field that looks // +// like a number. // +// // +/////////////////////////////////////////////////////////////////////////////// + +char* tetgenio::findnextnumber(char *string) +{ + char *result; + + result = string; + // Skip the current field. Stop upon reaching whitespace or a comma. + while ((*result != '\0') && (*result != '#') && (*result != ' ') && + (*result != '\t') && (*result != ',')) { + result++; + } + // Now skip the whitespace and anything else that doesn't look like a + // number, a comment, or the end of a line. + while ((*result != '\0') && (*result != '#') + && (*result != '.') && (*result != '+') && (*result != '-') + && ((*result < '0') || (*result > '9'))) { + result++; + } + // Check for a comment (prefixed with `#'). + if (*result == '#') { + *result = '\0'; + } + return result; +} + +// +// End of class 'tetgenio' implementation +// + +static REAL PI = 3.14159265358979323846264338327950288419716939937510582; + +// +// Begin of class 'tetgenbehavior' implementation +// + +/////////////////////////////////////////////////////////////////////////////// +// // +// tetgenbehavior() Initialize veriables of 'tetgenbehavior'. // +// // +/////////////////////////////////////////////////////////////////////////////// + +tetgenbehavior::tetgenbehavior() +{ + // Initialize command line switches. + plc = 0; + refine = 0; + quality = 0; + minratio = 2.0; + goodratio = 0.0; + minangle = 20.0; + goodangle = 0.0; + varvolume = 0; + fixedvolume = 0; + maxvolume = -1.0; + regionattrib = 0; + insertaddpoints = 0; + removesliver = 0; + maxdihedral = 0.0; + detectinter = 0; + checkclosure = 0; + zeroindex = 0; + jettison = 0; + facesout = 0; + edgesout = 0; + neighout = 0; + meditview = 0; + gidview = 0; + geomview = 0; + order = 1; + nobound = 0; + nonodewritten = 0; + noelewritten = 0; + nofacewritten = 0; + noiterationnum = 0; + nobisect = 0; + noflip = 0; + steiner = -1; + dopermute = 0; + srandseed = 1; + nomerge = 0; + docheck = 0; + quiet = 0; + verbose = 0; + useshelles = 0; + epsilon = 1.0e-8; + object = NONE; + // Initialize strings + commandline[0] = '\0'; + infilename[0] = '\0'; + outfilename[0] = '\0'; +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// versioninfo() Print the version information of TetGen. // +// // +/////////////////////////////////////////////////////////////////////////////// + +void tetgenbehavior::versioninfo() +{ + printf("Version 1.3.2 (Released on December 13, 2004).\n"); +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// syntax() Print list of command line switches and exit the program. // +// // +/////////////////////////////////////////////////////////////////////////////// + +void tetgenbehavior::syntax() +{ + printf(" tetgen [-pq__a__AriMS__T__dzo_fengGOBNEFICQVvh] input_file\n"); + printf(" -p Tetrahedralizes a piecewise linear complex.\n"); + printf(" -q Quality mesh generation. A minimum radius-edge ratio may\n"); + printf(" be specified (default 2.0).\n"); + printf(" -a Applies a maximum tetrahedron volume constraint.\n"); + printf(" -A Assigns attributes to identify tetrahedra in certain "); + printf("regions.\n"); + printf(" -r Reconstructs/Refines a previously generated mesh.\n"); + printf(" -i Inserts a list of additional points into mesh.\n"); + printf(" -M Does not merge coplanar facets.\n"); + printf(" -S Specifies maximum number of added Steiner points.\n"); + printf(" -T Set a tolerance for coplanar test (default 1e-8).\n"); + printf(" -d Detect intersections of PLC facets.\n"); + printf(" -z Numbers all output items starting from zero.\n"); + printf(" -j Jettison unused vertices from output .node file.\n"); + printf(" -o2 Generates second-order subparametric elements.\n"); + printf(" -f Outputs faces (including non-boundary faces) to .face "); + printf("file.\n"); + printf(" -e Outputs subsegments to .edge file.\n"); + printf(" -n Outputs tetrahedra neighbors to .neigh file.\n"); + printf(" -g Outputs mesh to .mesh file for viewing by Medit.\n"); + printf(" -G Outputs mesh to .msh file for viewing by Gid.\n"); + printf(" -O Outputs mesh to .off file for viewing by Geomview.\n"); + printf(" -B Suppresses output of boundary information.\n"); + printf(" -N Suppresses output of .node file.\n"); + printf(" -E Suppresses output of .ele file.\n"); + printf(" -F Suppresses output of .face file.\n"); + printf(" -I Suppresses mesh iteration numbers.\n"); + printf(" -C Checks the consistency of the final mesh.\n"); + printf(" -Q Quiet: No terminal output except errors.\n"); + printf(" -V Verbose: Detailed information, more terminal output.\n"); + printf(" -v Prints the version information.\n"); + printf(" -h Help: A brief instruction for using TetGen.\n"); +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// usage() Print a brief instruction for using TetGen. // +// // +/////////////////////////////////////////////////////////////////////////////// + +void tetgenbehavior::usage() +{ + printf("TetGen\n"); + printf("A Quality Tetrahedral Mesh Generator and 3D Delaunay "); + printf("Triangulator\n"); + versioninfo(); + printf("\n"); + printf("Copyright 2002, 2004\n"); + printf("Hang Si\n"); + printf("Rathausstr. 9, 10178 Berlin, Germany\n"); + printf("si@wias-berlin.de\n"); + printf("\n"); + printf("What Can TetGen Do?\n"); + printf("\n"); + printf(" TetGen generates exact Delaunay tetrahedralizations, exact\n"); + printf(" constrained Delaunay tetrahedralizations, and quality "); + printf("tetrahedral\n meshes. The latter are nicely graded and whose "); + printf("tetrahedra have\n radius-edge ratio bounded, thus are suitable "); + printf("for finite element and\n finite volume analysis.\n"); + printf("\n"); + printf("Command Line Syntax:\n"); + printf("\n"); + printf(" Below is the command line syntax of TetGen with a list of "); + printf("short\n"); + printf(" descriptions. Underscores indicate that numbers may optionally\n"); + printf(" follow certain switches. Do not leave any space between a "); + printf("switch\n"); + printf(" and its numeric parameter. \'input_file\' contains input data\n"); + printf(" depending on the switches you supplied which may be a "); + printf(" piecewise\n"); + printf(" linear complex or a list of nodes. File formats and detailed\n"); + printf(" description of command line switches are found in user's "); + printf("manual.\n"); + printf("\n"); + syntax(); + printf("\n"); + printf("Examples of How to Use TetGen:\n"); + printf("\n"); + printf(" \'tetgen object\' reads vertices from object.node, and writes "); + printf("their\n Delaunay tetrahedralization to object.1.node and "); + printf("object.1.ele.\n"); + printf("\n"); + printf(" \'tetgen -p object\' reads a PLC from object.poly or object."); + printf("smesh (and\n possibly object.node) and writes its constrained "); + printf("Delaunay\n tetrahedralization to object.1.node, object.1.ele and "); + printf("object.1.face.\n"); + printf("\n"); + printf(" \'tetgen -pq1.414a.1 object\' reads a PLC from object.poly or\n"); + printf(" object.smesh (and possibly object.node), generates a mesh "); + printf("whose\n tetrahedra have radius-edge ratio smaller than 1.414 and "); + printf("have volume\n of 0.1 or less, and writes the mesh to "); + printf("object.1.node, object.1.ele\n and object.1.face.\n"); + printf("\n"); + printf("Please send bugs/comments to Hang Si <si@wias-berlin.de>\n"); +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// parse_commandline() Read the command line, identify switches, and set // +// up options and file names. // +// // +// 'argc' and 'argv' are the same parameters passed to the function main() // +// of a C/C++ program. They together represent the command line user invoked // +// from an environment in which TetGen is running. // +// // +// When TetGen is invoked from an environment. 'argc' is nonzero, switches // +// and input filename should be supplied as zero-terminated strings in // +// argv[0] through argv[argc - 1] and argv[0] shall be the name used to // +// invoke TetGen, i.e. "tetgen". Switches are previously started with a // +// dash '-' to identify them from the input filename. // +// // +// When TetGen is called from within another program. 'argc' is set to zero. // +// switches are given in one zero-terminated string (no previous dash is // +// required.), and 'argv' is a pointer points to this string. No input // +// filename is required (usually the input data has been directly created by // +// user in the 'tetgenio' structure). A default filename 'tetgen-tmpfile' // +// will be created for debugging output purpose. // +// // +/////////////////////////////////////////////////////////////////////////////// + +bool tetgenbehavior::parse_commandline(int argc, char **argv) +{ + int startindex; + int increment; + int meshnumber; + int i, j, k; + char workstring[1024]; + + // First determine the input style of the switches. + if (argc == 0) { + startindex = 0; // Switches are given without a dash. + argc = 1; // For running the following for-loop once. + commandline[0] = '\0'; + } else { + startindex = 1; + strcpy(commandline, argv[0]); + strcat(commandline, " "); + } + + for (i = startindex; i < argc; i++) { + // Remember the command line switches. + strcat(commandline, argv[i]); + strcat(commandline, " "); + if (startindex == 1) { + // Is this string a filename? + if (argv[i][0] != '-') { + strncpy(infilename, argv[i], 1024 - 1); + infilename[1024 - 1] = '\0'; + // Go to the next string directly. + continue; + } + } + // Parse the individual switch from the string. + for (j = startindex; argv[i][j] != '\0'; j++) { + if (argv[i][j] == 'p') { + plc = 1; + } else if (argv[i][j] == 'r') { + refine = 1; + } else if (argv[i][j] == 'q') { + quality = 1; + if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) || + (argv[i][j + 1] == '.')) { + k = 0; + while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) || + (argv[i][j + 1] == '.')) { + j++; + workstring[k] = argv[i][j]; + k++; + } + workstring[k] = '\0'; + minratio = (REAL) strtod(workstring, (char **) NULL); + } + } else if (argv[i][j] == 'a') { + quality = 1; + if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) || + (argv[i][j + 1] == '.')) { + fixedvolume = 1; + k = 0; + while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) || + (argv[i][j + 1] == '.') || (argv[i][j + 1] == 'e') || + (argv[i][j + 1] == '-') || (argv[i][j + 1] == '+')) { + j++; + workstring[k] = argv[i][j]; + k++; + } + workstring[k] = '\0'; + maxvolume = (REAL) strtod(workstring, (char **) NULL); + if (maxvolume <= 0.0) { + printf("Error: Number after -a must be greater than zero.\n"); + return false; + } + } else { + varvolume = 1; + } + } else if (argv[i][j] == 'A') { + regionattrib = 1; + } else if (argv[i][j] == 'i') { + insertaddpoints = 1; + } else if (argv[i][j] == 's') { + removesliver = 1; + if ((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) { + k = 0; + while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) || + (argv[i][j + 1] == '.')) { + j++; + workstring[k] = argv[i][j]; + k++; + } + workstring[k] = '\0'; + maxdihedral = (REAL) strtod(workstring, (char **) NULL); + if (maxdihedral <= 0.0 || maxdihedral >= 180.0) { + printf("Error: Number after -s must between 0 and 180.\n"); + return false; + } + } else { + maxdihedral = 175.0; + } + maxdihedral = maxdihedral * 3.1415926535897932 / 180.; + } else if (argv[i][j] == 'd') { + detectinter = 1; + } else if (argv[i][j] == 'c') { + checkclosure = 1; + } else if (argv[i][j] == 'z') { + zeroindex = 1; + } else if (argv[i][j] == 'j') { + jettison = 1; + } else if (argv[i][j] == 'e') { + edgesout = 1; + } else if (argv[i][j] == 'n') { + neighout = 1; + } else if (argv[i][j] == 'g') { + meditview = 1; + } else if (argv[i][j] == 'G') { + gidview = 1; + } else if (argv[i][j] == 'O') { + geomview = 1; + } else if (argv[i][j] == 'B') { + nobound = 1; + } else if (argv[i][j] == 'N') { + nonodewritten = 1; + } else if (argv[i][j] == 'E') { + noelewritten = 1; + } else if (argv[i][j] == 'F') { + nofacewritten = 1; + } else if (argv[i][j] == 'I') { + noiterationnum = 1; + } else if (argv[i][j] == 'o') { + if (argv[i][j + 1] == '2') { + j++; + order = 2; + } + } else if (argv[i][j] == 'Y') { + noflip = 1; // nobisect++; + } else if (argv[i][j] == 'S') { + if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) || + (argv[i][j + 1] == '.')) { + k = 0; + while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) || + (argv[i][j + 1] == '.') || (argv[i][j + 1] == 'e') || + (argv[i][j + 1] == '-') || (argv[i][j + 1] == '+')) { + j++; + workstring[k] = argv[i][j]; + k++; + } + workstring[k] = '\0'; + steiner = (int) strtol(workstring, (char **) NULL, 0); + } + } else if (argv[i][j] == 'P') { + dopermute = 1; + if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) || + (argv[i][j + 1] == '.')) { + k = 0; + while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) || + (argv[i][j + 1] == '.') || (argv[i][j + 1] == 'e') || + (argv[i][j + 1] == '-') || (argv[i][j + 1] == '+')) { + j++; + workstring[k] = argv[i][j]; + k++; + } + workstring[k] = '\0'; + srandseed = (int) strtol(workstring, (char **) NULL, 0); + } + } else if (argv[i][j] == 'M') { + nomerge = 1; + } else if (argv[i][j] == 'T') { + if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) || + (argv[i][j + 1] == '.')) { + k = 0; + while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) || + (argv[i][j + 1] == '.') || (argv[i][j + 1] == 'e') || + (argv[i][j + 1] == '-') || (argv[i][j + 1] == '+')) { + j++; + workstring[k] = argv[i][j]; + k++; + } + workstring[k] = '\0'; + epsilon = (REAL) strtod(workstring, (char **) NULL); + } + if (epsilon <= 0.0) { + printf("Error: Number after -T must be greater than zero.\n"); + return false; + } + } else if (argv[i][j] == 'C') { + docheck++; + } else if (argv[i][j] == 'Q') { + quiet = 1; + } else if (argv[i][j] == 'V') { + verbose++; + } else if (argv[i][j] == 'v') { + versioninfo(); + exit(0); + } else if ((argv[i][j] == 'h') || (argv[i][j] == 'H') || + (argv[i][j] == '?')) { + usage(); + exit(0); + } else { + printf("Warning: Unknown switch -%c.\n", argv[i][j]); + } + } + } + + if (startindex == 0) { + // Set a temporary filename for debugging output. + strcpy(infilename, "tetgen-tmpfile"); + } else { + if (infilename[0] == '\0') { + // No input file name. Print the syntax and exit. + syntax(); + exit(0); + } + // Recognize the object from file extension if it is available. + if (!strcmp(&infilename[strlen(infilename) - 5], ".node")) { + infilename[strlen(infilename) - 5] = '\0'; + object = NODES; + } else if (!strcmp(&infilename[strlen(infilename) - 5], ".poly")) { + infilename[strlen(infilename) - 5] = '\0'; + object = POLY; + plc = 1; + } else if (!strcmp(&infilename[strlen(infilename) - 6], ".smesh")) { + infilename[strlen(infilename) - 6] = '\0'; + object = POLY; + plc = 1; + } else if (!strcmp(&infilename[strlen(infilename) - 4], ".off")) { + infilename[strlen(infilename) - 4] = '\0'; + object = OFF; + plc = 1; + } else if (!strcmp(&infilename[strlen(infilename) - 4], ".ply")) { + infilename[strlen(infilename) - 4] = '\0'; + object = PLY; + plc = 1; + } else if (!strcmp(&infilename[strlen(infilename) - 4], ".stl")) { + infilename[strlen(infilename) - 4] = '\0'; + object = STL; + plc = 1; + } else if (!strcmp(&infilename[strlen(infilename) - 5], ".mesh")) { + infilename[strlen(infilename) - 5] = '\0'; + object = MEDIT; + plc = 1; + } else if (!strcmp(&infilename[strlen(infilename) - 4], ".ele")) { + infilename[strlen(infilename) - 4] = '\0'; + object = MESH; + refine = 1; + } + } + plc = plc || detectinter || checkclosure; + useshelles = plc || refine || quality; + goodratio = minratio; + goodratio *= goodratio; + + // Detect improper combinations of switches. + if (plc && refine) { + printf("Error: Switch -r cannot use together with -p.\n"); + return false; + } + if (refine && (plc || noiterationnum)) { + printf("Error: Switches %s cannot use together with -r.\n", + "-p, -d, -c, and -I"); + return false; + } + if (detectinter && (quality || insertaddpoints || (order == 2) || neighout + || checkclosure || docheck)) { + printf("Error: Switches %s cannot use together with -d.\n", + "-c, -q, -i, -o2, -n, and -C"); + return false; + } + if (checkclosure && (quality || insertaddpoints || (order == 2) || neighout + || detectinter || docheck)) { + printf("Error: Switches %s cannot use together with -c.\n", + "-d, -q, -i, -o2, -n, and -C"); + return false; + } + + // Be careful not to allocate space for element area constraints that + // will never be assigned any value (other than the default -1.0). + if (!refine && !plc) { + varvolume = 0; + } + // Be careful not to add an extra attribute to each element unless the + // input supports it (PLC in, but not refining a preexisting mesh). + if (refine || !plc) { + regionattrib = 0; + } + // Calculate the goodangle for testing bad subfaces. + goodangle = cos(minangle * PI / 180.0); + goodangle *= goodangle; + + increment = 0; + strcpy(workstring, infilename); + j = 1; + while (workstring[j] != '\0') { + if ((workstring[j] == '.') && (workstring[j + 1] != '\0')) { + increment = j + 1; + } + j++; + } + meshnumber = 0; + if (increment > 0) { + j = increment; + do { + if ((workstring[j] >= '0') && (workstring[j] <= '9')) { + meshnumber = meshnumber * 10 + (int) (workstring[j] - '0'); + } else { + increment = 0; + } + j++; + } while (workstring[j] != '\0'); + } + if (noiterationnum) { + strcpy(outfilename, infilename); + } else if (increment == 0) { + strcpy(outfilename, infilename); + strcat(outfilename, ".1"); + } else { + workstring[increment] = '%'; + workstring[increment + 1] = 'd'; + workstring[increment + 2] = '\0'; + sprintf(outfilename, workstring, meshnumber + 1); + } + + return true; +} + +// +// End of class 'tetgenbehavior' implementation +// + +// +// Begin of class 'tetgenmesh' implementation +// + +// +// Begin of class 'list', 'memorypool' and 'link' implementation +// + +// Following are predefined compare functions for primitive data types. +// These functions take two pointers of the corresponding date type, +// perform the comparation. Return -1, 0 or 1 indicating the default +// linear order of two operators. + +// Compare two 'integers'. +int tetgenmesh::compare_2_ints(const void* x, const void* y) { + if (* (int *) x < * (int *) y) { + return -1; + } else if (* (int *) x > * (int *) y) { + return 1; + } else { + return 0; + } +} + +// Compare two 'longs'. Note: in 64-bit machine the 'long' type is 64-bit +// (8-byte) where the 'int' only 32-bit (4-byte). +int tetgenmesh::compare_2_longs(const void* x, const void* y) { + if (* (long *) x < * (long *) y) { + return -1; + } else if (* (long *) x > * (long *) y) { + return 1; + } else { + return 0; + } +} + +// Compare two 'unsigned longs'. +int tetgenmesh::compare_2_unsignedlongs(const void* x, const void* y) { + if (* (unsigned long *) x < * (unsigned long *) y) { + return -1; + } else if (* (unsigned long *) x > * (unsigned long *) y) { + return 1; + } else { + return 0; + } +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// set_compfunc() Determine the size of primitive data types and set the // +// corresponding predefined linear order functions. // +// // +// 'str' is a zero-end string indicating a primitive data type, like 'int', // +// 'long' or 'unsigned long'. Every string ending with a '*' is though as a // +// type of pointer and the type 'unsign long' is used for it. // +// // +// When the type of 'str' is determined, the size of this type (in byte) is // +// returned in 'itbytes', and the pointer of corresponding predefined linear // +// order functions is returned in 'pcomp'. // +// // +/////////////////////////////////////////////////////////////////////////////// + +void tetgenmesh::set_compfunc(char* str, int* itbytes, compfunc* pcomp) +{ + // First figure out whether it is a pointer or not. + if (str[strlen(str) - 1] == '*') { + *itbytes = sizeof(unsigned long); + *pcomp = &compare_2_unsignedlongs; + return; + } + // Then determine other types. + if (strcmp(str, "int") == 0) { + *itbytes = sizeof(int); + *pcomp = &compare_2_ints; + } else if (strcmp(str, "long") == 0) { + *itbytes = sizeof(long); + *pcomp = &compare_2_longs; + } else if (strcmp(str, "unsigned long") == 0) { + *itbytes = sizeof(unsigned long); + *pcomp = &compare_2_unsignedlongs; + } else { + // It is an unknown type. + printf("Error in set_compfunc(): unknown type %s.\n", str); + exit(1); + } +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// listinit() Initialize a list for storing a data type. // +// // +// Determine the size of each item, set the maximum size allocated at onece, // +// set the expand size in case the list is full, and set the linear order // +// function if it is provided (default is NULL). // +// // +/////////////////////////////////////////////////////////////////////////////// + +void tetgenmesh::list:: +listinit(int itbytes, compfunc pcomp, int mitems,int exsize) +{ + assert(itbytes > 0 && mitems > 0 && exsize > 0); + + itembytes = itbytes; + comp = pcomp; + maxitems = mitems; + expandsize = exsize; + base = (char *) malloc(maxitems * itembytes); + if (base == (char *) NULL) { + printf("Error: Out of memory.\n"); + exit(1); + } + items = 0; +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// append() Add a new item at the end of the list. // +// // +// A new space at the end of this list will be allocated for storing the new // +// item. If the memory is not sufficient, reallocation will be performed. If // +// 'appitem' is not NULL, the contents of this pointer will be copied to the // +// new allocated space. Returns the pointer to the new allocated space. // +// // +/////////////////////////////////////////////////////////////////////////////// + +void* tetgenmesh::list::append(void *appitem) +{ + // Do we have enough space? + if (items == maxitems) { + char* newbase = (char *) realloc(base, (maxitems + expandsize) * + itembytes); + if (newbase == (char *) NULL) { + printf("Error: Out of memory.\n"); + exit(1); + } + base = newbase; + maxitems += expandsize; + } + if (appitem != (void *) NULL) { + memcpy(base + items * itembytes, appitem, itembytes); + } + items++; + return (void *) (base + (items - 1) * itembytes); +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// insert() Insert an item before 'pos' (range from 0 to items - 1). // +// // +// A new space will be inserted at the position 'pos', that is, items lie // +// after pos (including the item at pos) will be moved one space downwords. // +// If 'insitem' is not NULL, its contents will be copied into the new // +// inserted space. Return a pointer to the new inserted space. // +// // +/////////////////////////////////////////////////////////////////////////////// + +void* tetgenmesh::list::insert(int pos, void* insitem) +{ + if (pos >= items) { + return append(insitem); + } + // Do we have enough space. + if (items == maxitems) { + char* newbase = (char *) realloc(base, (maxitems + expandsize) * + itembytes); + if (newbase == (char *) NULL) { + printf("Error: Out of memory.\n"); + exit(1); + } + base = newbase; + maxitems += expandsize; + } + // Do block move. + memmove(base + (pos + 1) * itembytes, // dest + base + pos * itembytes, // src + (items - pos) * itembytes); // size in bytes + // Insert the item. + if (insitem != (void *) NULL) { + memcpy(base + pos * itembytes, insitem, itembytes); + } + items++; + return (void *) (base + pos * itembytes); +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// del() Delete an item at 'pos' (range from 0 to items - 1). // +// // +// The space at 'pos' will be overlapped by other items, that is, items lie // +// after pos will be moved one space upwords. // +// // +/////////////////////////////////////////////////////////////////////////////// + +void tetgenmesh::list::del(int pos) +{ + // If 'pos' is the last itemof the list, nothing need to do. + if (pos >= 0 && pos < items - 1) { + // Do block move. + memmove(base + pos * itembytes, // dest + base + (pos + 1) * itembytes, // src + (items - pos - 1) * itembytes); + } + if (items > 0) { + items--; + } +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// hasitem() Search in this list to find if 'checkitem' exists. // +// // +// This routine assumes that a linear order function has been set. It loops // +// through the entire list, compares each item to 'checkitem'. If it exists, // +// return its position (between 0 to items - 1), otherwise, return -1. // +// // +/////////////////////////////////////////////////////////////////////////////// + +int tetgenmesh::list::hasitem(void* checkitem) +{ + int i; + + for (i = 0; i < items; i++) { + if (comp != (compfunc) NULL) { + if ((* comp)((void *)(base + i * itembytes), checkitem) == 0) { + return i; + } + } + } + return -1; +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// remove() Remove an item (indicated by its pointer) from the list. // +// // +// If the list contains more than one copy of the pointer, only the first // +// copy is removed. The returned value is the index of the removed item. // +// // +/////////////////////////////////////////////////////////////////////////////// + +int tetgenmesh::list::remove(void* remitem) +{ + int pos = hasitem(remitem); + if (pos != -1) { + del(pos); + } + return pos; +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// sort() Sort the items with respect to a linear order function. // +// // +// Uses QuickSort routines (qsort) of the standard C/C++ library (stdlib.h). // +// // +/////////////////////////////////////////////////////////////////////////////// + +void tetgenmesh::list::sort() +{ + qsort((void *) base, (size_t) items, (size_t) itembytes, comp); +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// memorypool() The constructors of memorypool. // +// // +/////////////////////////////////////////////////////////////////////////////// + +tetgenmesh::memorypool::memorypool() +{ + firstblock = nowblock = (void **) NULL; + nextitem = (void *) NULL; + deaditemstack = (void *) NULL; + pathblock = (void **) NULL; + pathitem = (void *) NULL; + itemwordtype = POINTER; + alignbytes = 0; + itembytes = itemwords = 0; + itemsperblock = 0; + items = maxitems = 0l; + unallocateditems = 0; + pathitemsleft = 0; +} + +tetgenmesh::memorypool:: +memorypool(int bytecount, int itemcount, enum wordtype wtype, int alignment) +{ + poolinit(bytecount, itemcount, wtype, alignment); +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// ~memorypool() Free to the operating system all memory taken by a pool. // +// // +/////////////////////////////////////////////////////////////////////////////// + +tetgenmesh::memorypool::~memorypool() +{ + while (firstblock != (void **) NULL) { + nowblock = (void **) *(firstblock); + free(firstblock); + firstblock = nowblock; + } +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// poolinit() Initialize a pool of memory for allocation of items. // +// // +// A `pool' is created whose records have size at least `bytecount'. Items // +// will be allocated in `itemcount'-item blocks. Each item is assumed to be // +// a collection of words, and either pointers or floating-point values are // +// assumed to be the "primary" word type. (The "primary" word type is used // +// to determine alignment of items.) If `alignment' isn't zero, all items // +// will be `alignment'-byte aligned in memory. `alignment' must be either a // +// multiple or a factor of the primary word size; powers of two are safe. // +// `alignment' is normally used to create a few unused bits at the bottom of // +// each item's pointer, in which information may be stored. // +// // +/////////////////////////////////////////////////////////////////////////////// + +void tetgenmesh::memorypool:: +poolinit(int bytecount, int itemcount, enum wordtype wtype, int alignment) +{ + int wordsize; + + // Initialize values in the pool. + itemwordtype = wtype; + wordsize = (itemwordtype == POINTER) ? sizeof(void *) : sizeof(REAL); + // Find the proper alignment, which must be at least as large as: + // - The parameter `alignment'. + // - The primary word type, to avoid unaligned accesses. + // - sizeof(void *), so the stack of dead items can be maintained + // without unaligned accesses. + if (alignment > wordsize) { + alignbytes = alignment; + } else { + alignbytes = wordsize; + } + if (sizeof(void *) > alignbytes) { + alignbytes = sizeof(void *); + } + itemwords = ((bytecount + alignbytes - 1) / alignbytes) + * (alignbytes / wordsize); + itembytes = itemwords * wordsize; + itemsperblock = itemcount; + + // Allocate a block of items. Space for `itemsperblock' items and one + // pointer (to point to the next block) are allocated, as well as space + // to ensure alignment of the items. + firstblock = (void **) malloc(itemsperblock * itembytes + sizeof(void *) + + alignbytes); + if (firstblock == (void **) NULL) { + printf("Error: Out of memory.\n"); + exit(1); + } + // Set the next block pointer to NULL. + *(firstblock) = (void *) NULL; + restart(); +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// restart() Deallocate all items in this pool. // +// // +// The pool is returned to its starting state, except that no memory is // +// freed to the operating system. Rather, the previously allocated blocks // +// are ready to be reused. // +// // +/////////////////////////////////////////////////////////////////////////////// + +void tetgenmesh::memorypool::restart() +{ + unsigned long alignptr; + + items = 0; + maxitems = 0; + + // Set the currently active block. + nowblock = firstblock; + // Find the first item in the pool. Increment by the size of (void *). + alignptr = (unsigned long) (nowblock + 1); + // Align the item on an `alignbytes'-byte boundary. + nextitem = (void *) + (alignptr + (unsigned long) alignbytes - + (alignptr % (unsigned long) alignbytes)); + // There are lots of unallocated items left in this block. + unallocateditems = itemsperblock; + // The stack of deallocated items is empty. + deaditemstack = (void *) NULL; +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// alloc() Allocate space for an item. // +// // +/////////////////////////////////////////////////////////////////////////////// + +void* tetgenmesh::memorypool::alloc() +{ + void *newitem; + void **newblock; + unsigned long alignptr; + + // First check the linked list of dead items. If the list is not + // empty, allocate an item from the list rather than a fresh one. + if (deaditemstack != (void *) NULL) { + newitem = deaditemstack; // Take first item in list. + deaditemstack = * (void **) deaditemstack; + } else { + // Check if there are any free items left in the current block. + if (unallocateditems == 0) { + // Check if another block must be allocated. + if (*nowblock == (void *) NULL) { + // Allocate a new block of items, pointed to by the previous block. + newblock = (void **) malloc(itemsperblock * itembytes + sizeof(void *) + + alignbytes); + if (newblock == (void **) NULL) { + printf("Error: Out of memory.\n"); + exit(1); + } + *nowblock = (void *) newblock; + // The next block pointer is NULL. + *newblock = (void *) NULL; + } + // Move to the new block. + nowblock = (void **) *nowblock; + // Find the first item in the block. + // Increment by the size of (void *). + alignptr = (unsigned long) (nowblock + 1); + // Align the item on an `alignbytes'-byte boundary. + nextitem = (void *) + (alignptr + (unsigned long) alignbytes - + (alignptr % (unsigned long) alignbytes)); + // There are lots of unallocated items left in this block. + unallocateditems = itemsperblock; + } + // Allocate a new item. + newitem = nextitem; + // Advance `nextitem' pointer to next free item in block. + if (itemwordtype == POINTER) { + nextitem = (void *) ((void **) nextitem + itemwords); + } else { + nextitem = (void *) ((REAL *) nextitem + itemwords); + } + unallocateditems--; + maxitems++; + } + items++; + return newitem; +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// dealloc() Deallocate space for an item. // +// // +// The deallocated space is stored in a queue for later reuse. // +// // +/////////////////////////////////////////////////////////////////////////////// + +void tetgenmesh::memorypool::dealloc(void *dyingitem) +{ + // Push freshly killed item onto stack. + *((void **) dyingitem) = deaditemstack; + deaditemstack = dyingitem; + items--; +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// traversalinit() Prepare to traverse the entire list of items. // +// // +// This routine is used in conjunction with traverse(). // +// // +/////////////////////////////////////////////////////////////////////////////// + +void tetgenmesh::memorypool::traversalinit() +{ + unsigned long alignptr; + + // Begin the traversal in the first block. + pathblock = firstblock; + // Find the first item in the block. Increment by the size of (void *). + alignptr = (unsigned long) (pathblock + 1); + // Align with item on an `alignbytes'-byte boundary. + pathitem = (void *) + (alignptr + (unsigned long) alignbytes - + (alignptr % (unsigned long) alignbytes)); + // Set the number of items left in the current block. + pathitemsleft = itemsperblock; +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// traverse() Find the next item in the list. // +// // +// This routine is used in conjunction with traversalinit(). Be forewarned // +// that this routine successively returns all items in the list, including // +// deallocated ones on the deaditemqueue. It's up to you to figure out which // +// ones are actually dead. It can usually be done more space-efficiently by // +// a routine that knows something about the structure of the item. // +// // +/////////////////////////////////////////////////////////////////////////////// + +void* tetgenmesh::memorypool::traverse() +{ + void *newitem; + unsigned long alignptr; + + // Stop upon exhausting the list of items. + if (pathitem == nextitem) { + return (void *) NULL; + } + // Check whether any untraversed items remain in the current block. + if (pathitemsleft == 0) { + // Find the next block. + pathblock = (void **) *pathblock; + // Find the first item in the block. Increment by the size of (void *). + alignptr = (unsigned long) (pathblock + 1); + // Align with item on an `alignbytes'-byte boundary. + pathitem = (void *) + (alignptr + (unsigned long) alignbytes - + (alignptr % (unsigned long) alignbytes)); + // Set the number of items left in the current block. + pathitemsleft = itemsperblock; + } + newitem = pathitem; + // Find the next item in the block. + if (itemwordtype == POINTER) { + pathitem = (void *) ((void **) pathitem + itemwords); + } else { + pathitem = (void *) ((REAL *) pathitem + itemwords); + } + pathitemsleft--; + return newitem; +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// linkinit() Initialize a link for storing items. // +// // +// The input parameters are the size of each item, a pointer of a linear // +// order function and the number of items allocating in one memory bulk. // +// // +/////////////////////////////////////////////////////////////////////////////// + +void tetgenmesh::link::linkinit(int bytecount, compfunc pcomp, int itemcount) +{ + assert(bytecount > 0 && itemcount > 0); + + // Remember the real size of each item. + linkitembytes = bytecount; + // Set the linear order function for this link. + comp = pcomp; + + // Call the constructor of 'memorypool' to initialize its variables. + // like: itembytes, itemwords, items, ... Each node has size + // bytecount + 2 * sizeof(void **), and total 'itemcount + 2' (because + // link has additional two nodes 'head' and 'tail'). + poolinit(bytecount + 2 * sizeof(void **), itemcount + 2, POINTER, 0); + + // Initial state of this link. + head = (void **) alloc(); + tail = (void **) alloc(); + *head = (void *) tail; + *(head + 1) = NULL; + *tail = NULL; + *(tail + 1) = (void *) head; + nextlinkitem = *head; + curpos = 1; + linkitems = 0; +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// clear() Deallocate all nodes in this link. // +// // +// The link is returned to its starting state, except that no memory is // +// freed to the operating system. Rather, the previously allocated blocks // +// are ready to be reused. // +// // +/////////////////////////////////////////////////////////////////////////////// + +void tetgenmesh::link::clear() +{ + // Reset the pool. + restart(); + + // Initial state of this link. + head = (void **) alloc(); + tail = (void **) alloc(); + *head = (void *) tail; + *(head + 1) = NULL; + *tail = NULL; + *(tail + 1) = (void *) head; + nextlinkitem = *head; + curpos = 1; + linkitems = 0; +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// move() Causes 'nextlinkitem' to traverse the specified number of nodes,// +// updates 'curpos' to be the node to which 'nextlinkitem' points. // +// // +// 'numberofnodes' is a number indicating how many nodes need be traversed // +// (not counter the current node) need be traversed. It may be positive(move // +// forward) or negative (move backward). Return TRUE if it is successful. // +// // +/////////////////////////////////////////////////////////////////////////////// + +bool tetgenmesh::link::move(int numberofnodes) +{ + void **nownode; + int i; + + nownode = (void **) nextlinkitem; + if (numberofnodes > 0) { + // Move forward. + i = 0; + while ((i < numberofnodes) && *nownode) { + nownode = (void **) *nownode; + i++; + } + if (*nownode == NULL) return false; + nextlinkitem = (void *) nownode; + curpos += numberofnodes; + } else if (numberofnodes < 0) { + // Move backward. + i = 0; + numberofnodes = -numberofnodes; + while ((i < numberofnodes) && *(nownode + 1)) { + nownode = (void **) *(nownode + 1); + i++; + } + if (*(nownode + 1) == NULL) return false; + nextlinkitem = (void *) nownode; + curpos -= numberofnodes; + } + return true; +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// locate() Locates the node at the specified position. // +// // +// The number 'pos' (between 1 and 'linkitems') indicates the location. This // +// routine first decides the shortest path traversing from 'curpos' to 'pos',// +// i.e., from head, tail or 'curpos'. Routine 'move()' is called to really // +// traverse the link. If success, 'nextlinkitem' points to the node, 'curpos'// +// and 'pos' are equal. Otherwise, return FALSE. // +// // +/////////////////////////////////////////////////////////////////////////////// + +bool tetgenmesh::link::locate(int pos) +{ + int headdist, taildist, curdist; + int abscurdist, mindist; + + if (pos < 1 || pos > linkitems) return false; + + headdist = pos - 1; + taildist = linkitems - pos; + curdist = pos - curpos; + abscurdist = curdist >= 0 ? curdist : -curdist; + + if (headdist > taildist) { + if (taildist > abscurdist) { + mindist = curdist; + } else { + // taildist <= abs(curdist) + mindist = -taildist; + goend(); + } + } else { + // headdist <= taildist + if (headdist > abscurdist) { + mindist = curdist; + } else { + // headdist <= abs(curdist) + mindist = headdist; + rewind(); + } + } + + return move(mindist); +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// add() Add a node at the end of this link. // +// // +// A new node is appended to the end of the link. If 'newitem' is not NULL, // +// its conents will be copied to the data slot of the new node. Returns the // +// pointer to the newest added node. // +// // +/////////////////////////////////////////////////////////////////////////////// + +void* tetgenmesh::link::add(void* newitem) +{ + void **newnode = tail; + if (newitem != (void *) NULL) { + memcpy((void *)(newnode + 2), newitem, linkitembytes); + } + tail = (void **) alloc(); + *tail = NULL; + *newnode = (void*) tail; + *(tail + 1) = (void*) newnode; + linkitems++; + return (void *)(newnode + 2); +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// insert() Inserts a node before the specified position. // +// // +// 'pos' (between 1 and 'linkitems') indicates the inserting position. This // +// routine inserts a new node before the node of 'pos'. If 'newitem' is not // +// NULL, its conents will be copied into the data slot of the new node. If // +// 'pos' is larger than 'linkitems', it is equal as 'add()'. A pointer to // +// the newest inserted item is returned. // +// // +/////////////////////////////////////////////////////////////////////////////// + +void* tetgenmesh::link::insert(int pos, void* insitem) +{ + if (!locate(pos)) { + return add(insitem); + } + + void **nownode = (void **) nextlinkitem; + + // Insert a node before 'nownode'. + void **newnode = (void **) alloc(); + if (insitem != (void *) NULL) { + memcpy((void *)(newnode + 2), insitem, linkitembytes); + } + + *(void **)(*(nownode + 1)) = (void *) newnode; + *newnode = (void *) nownode; + *(newnode + 1) = *(nownode + 1); + *(nownode + 1) = (void *) newnode; + + linkitems++; + + nextlinkitem = (void *) newnode; + return (void *)(newnode + 2); +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// del() Delete a node containing the given pointer. // +// // +// Returns a pointer of the deleted data. If you try to delete a non-existed // +// node (e.g. link is empty or a wrong index is given) return NULL. // +// // +/////////////////////////////////////////////////////////////////////////////// + +void* tetgenmesh::link::del(void* delitem) +{ + void **deadnode = (void **) ((void **) delitem - 2); + + // now delete the nownode + void **nextnode = (void **) *deadnode; + void **prevnode = (void **) *(deadnode + 1); + *prevnode = (void *) nextnode; + *(nextnode + 1) = (void *) prevnode; + + dealloc((void *) deadnode); + linkitems--; + + nextlinkitem = (void *) nextnode; + return (void *)(deadnode + 2); +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// del() Delete a node at the specified position. // +// // +// 'pos' between 1 and 'linkitems'. Returns a pointer of the deleted data. // +// If you try to delete a non-existed node (e.g. link is empty or a wrong // +// index is given) return NULL. // +// // +/////////////////////////////////////////////////////////////////////////////// + +void* tetgenmesh::link::del(int pos) +{ + if (!locate(pos) || (linkitems == 0)) { + return (void *) NULL; + } + return del((void *) ((void **) nextlinkitem + 2)); + /* + void **deadnode = (void **)nextlinkitem; + + // now delete the nownode + void **nextnode = (void **) *deadnode; + void **prevnode = (void **) *(deadnode + 1); + *prevnode = (void *) nextnode; + *(nextnode + 1) = (void *) prevnode; + + dealloc((void *) deadnode); + linkitems--; + + nextlinkitem = (void *) nextnode; + return (void *)(deadnode + 2); + */ +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// getitem() The link traversal routine. // +// // +// Returns the node to which 'nextlinkitem' points. Returns a 'NULL' if the // +// end of the link is reaching. Both 'nextlinkitem' and 'curpos' will be // +// updated after this operation. // +// // +/////////////////////////////////////////////////////////////////////////////// + +void* tetgenmesh::link::getitem() +{ + if (nextlinkitem == (void *) tail) return NULL; + void **nownode = (void **) nextlinkitem; + nextlinkitem = *nownode; + curpos += 1; + return (void *)(nownode + 2); +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// getnitem() Returns the node at a specified position. // +// // +// 'pos' between 1 and 'linkitems'. After this operation, 'nextlinkitem' and // +// 'curpos' will be updated to indicate this node. // +// // +/////////////////////////////////////////////////////////////////////////////// + +void* tetgenmesh::link::getnitem(int pos) +{ + if (!locate(pos)) return NULL; + return (void *)((void **) nextlinkitem + 2); +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// hasitem() Search in this link to find if 'checkitem' exists. // +// // +// If 'checkitem' exists, return its position (between 1 to 'linkitems'), // +// otherwise, return -1. This routine requires the linear order function has // +// been set. // +// // +/////////////////////////////////////////////////////////////////////////////// + +int tetgenmesh::link::hasitem(void* checkitem) +{ + void *pathitem; + int count; + + rewind(); + pathitem = getitem(); + count = 0; + while (pathitem) { + count ++; + if (comp) { + if ((* comp)(pathitem, checkitem) == 0) { + return count; + } + } + pathitem = getitem(); + } + return -1; +} + +// +// End of class 'list', 'memorypool' and 'link' implementation +// + +// +// Begin of mesh manipulation primitives +// + +// +// Begin of tables initialization. +// + +// For enumerating three edges of a triangle. + +int tetgenmesh::plus1mod3[3] = {1, 2, 0}; +int tetgenmesh::minus1mod3[3] = {2, 0, 1}; + +// Table 've' takes an edge version as input, returns the next edge version +// in the same edge ring. + +int tetgenmesh::ve[6] = { 2, 5, 4, 1, 0, 3 }; + +// Tables 'vo', 'vd' and 'va' take an edge version, return the positions of +// the origin, destination and apex in the triangle. + +int tetgenmesh::vo[6] = { 0, 1, 1, 2, 2, 0 }; +int tetgenmesh::vd[6] = { 1, 0, 2, 1, 0, 2 }; +int tetgenmesh::va[6] = { 2, 2, 0, 0, 1, 1 }; + +// The following tables are for tetrahedron primitives (operate on trifaces). + +// For 'org()', 'dest()' and 'apex()'. Use 'loc' as the first index and +// 'ver' as the second index. + +int tetgenmesh::locver2org[4][6] = { + 0, 1, 1, 2, 2, 0, + 0, 3, 3, 1, 1, 0, + 1, 3, 3, 2, 2, 1, + 2, 3, 3, 0, 0, 2 +}; +int tetgenmesh::locver2dest[4][6] = { + 1, 0, 2, 1, 0, 2, + 3, 0, 1, 3, 0, 1, + 3, 1, 2, 3, 1, 2, + 3, 2, 0, 3, 2, 0 +}; +int tetgenmesh::locver2apex[4][6] = { + 2, 2, 0, 0, 1, 1, + 1, 1, 0, 0, 3, 3, + 2, 2, 1, 1, 3, 3, + 0, 0, 2, 2, 3, 3 +}; + +// For oppo() primitives, use 'loc' as the index. + +int tetgenmesh::loc2oppo[4] = { 3, 2, 0, 1 }; + +// For fnext() primitive. Use 'loc' as the first index and 'ver' as the +// second index. Returns a new 'loc' and new 'ver' in an array. (It is +// only valid for edge version equals one of {0, 2, 4}.) + +int tetgenmesh::locver2nextf[4][6][2] = { + { {1, 5}, {-1, -1}, {2, 5}, {-1, -1}, {3, 5}, {-1, -1} }, + { {3, 3}, {-1, -1}, {2, 1}, {-1, -1}, {0, 1}, {-1, -1} }, + { {1, 3}, {-1, -1}, {3, 1}, {-1, -1}, {0, 3}, {-1, -1} }, + { {2, 3}, {-1, -1}, {1, 1}, {-1, -1}, {0, 5}, {-1, -1} } +}; + +// +// End of tables initialization. +// + +// Some macros for convenience + +#define Div2 >> 1 +#define Mod2 & 01 + +// NOTE: These bit operators should only be used in macros below. + +// Get orient(Range from 0 to 2) from face version(Range from 0 to 5). + +#define Orient(V) ((V) Div2) + +// Determine edge ring(0 or 1) from face version(Range from 0 to 5). + +#define EdgeRing(V) ((V) Mod2) + +// +// Begin of primitives for tetrahedra +// + +// Each tetrahedron contains four pointers to its neighboring tetrahedra, +// with face indices. To save memory, both information are kept in a +// single pointer. To make this possible, all tetrahedra are aligned to +// eight-byte boundaries, so that the last three bits of each pointer are +// zeros. A face index (in the range 0 to 3) is compressed into the last +// two bits of each pointer by the function 'encode()'. The function +// 'decode()' decodes a pointer, extracting a face index and a pointer to +// the beginning of a tetrahedron. + +inline void tetgenmesh::decode(tetrahedron ptr, triface& t) { + t.loc = (int) ((unsigned long) (ptr) & (unsigned long) 3l); + t.tet = (tetrahedron *) ((unsigned long) (ptr) & ~(unsigned long) 7l); +} + +inline tetgenmesh::tetrahedron tetgenmesh::encode(triface& t) { + return (tetrahedron) ((unsigned long) t.tet | (unsigned long) t.loc); +} + +// sym() finds the abutting tetrahedron on the same face. + +inline void tetgenmesh::sym(triface& t1, triface& t2) { + tetrahedron ptr = t1.tet[t1.loc]; + decode(ptr, t2); +} + +inline void tetgenmesh::symself(triface& t) { + tetrahedron ptr = t.tet[t.loc]; + decode(ptr, t); +} + +// Bond two tetrahedra together at their faces. + +inline void tetgenmesh::bond(triface& t1, triface& t2) { + t1.tet[t1.loc] = encode(t2); + t2.tet[t2.loc] = encode(t1); +} + +// Dissolve a bond (from one side). Note that the other tetrahedron will +// still think it is connected to this tetrahedron. Usually, however, +// the other tetrahedron is being deleted entirely, or bonded to another +// tetrahedron, so it doesn't matter. + +inline void tetgenmesh::dissolve(triface& t) { + t.tet[t.loc] = (tetrahedron) dummytet; +} + +// These primitives determine or set the origin, destination, apex or +// opposition of a tetrahedron with respect to 'loc' and 'ver'. + +inline tetgenmesh::point tetgenmesh::org(triface& t) { + return (point) t.tet[locver2org[t.loc][t.ver] + 4]; +} + +inline tetgenmesh::point tetgenmesh::dest(triface& t) { + return (point) t.tet[locver2dest[t.loc][t.ver] + 4]; +} + +inline tetgenmesh::point tetgenmesh::apex(triface& t) { + return (point) t.tet[locver2apex[t.loc][t.ver] + 4]; +} + +inline tetgenmesh::point tetgenmesh::oppo(triface& t) { + return (point) t.tet[loc2oppo[t.loc] + 4]; +} + +inline void tetgenmesh::setorg(triface& t, point pointptr) { + t.tet[locver2org[t.loc][t.ver] + 4] = (tetrahedron) pointptr; +} + +inline void tetgenmesh::setdest(triface& t, point pointptr) { + t.tet[locver2dest[t.loc][t.ver] + 4] = (tetrahedron) pointptr; +} + +inline void tetgenmesh::setapex(triface& t, point pointptr) { + t.tet[locver2apex[t.loc][t.ver] + 4] = (tetrahedron) pointptr; +} + +inline void tetgenmesh::setoppo(triface& t, point pointptr) { + t.tet[loc2oppo[t.loc] + 4] = (tetrahedron) pointptr; +} + +// These primitives were drived from Mucke's triangle-edge data structure +// to change face-edge relation in a tetrahedron (esym, enext and enext2) +// or between two tetrahedra (fnext). + +// If e0 = e(i, j), e1 = e(j, i), that is e0 and e1 are the two directions +// of the same undirected edge of a face. e0.sym() = e1 and vice versa. + +inline void tetgenmesh::esym(triface& t1, triface& t2) { + t2.tet = t1.tet; + t2.loc = t1.loc; + t2.ver = t1.ver + (EdgeRing(t1.ver) ? -1 : 1); +} + +inline void tetgenmesh::esymself(triface& t) { + t.ver += (EdgeRing(t.ver) ? -1 : 1); +} + +// If e0 and e1 are both in the same edge ring of a face, e1 = e0.enext(). + +inline void tetgenmesh::enext(triface& t1, triface& t2) { + t2.tet = t1.tet; + t2.loc = t1.loc; + t2.ver = ve[t1.ver]; +} + +inline void tetgenmesh::enextself(triface& t) { + t.ver = ve[t.ver]; +} + +// enext2() is equal to e2 = e0.enext().enext() + +inline void tetgenmesh::enext2(triface& t1, triface& t2) { + t2.tet = t1.tet; + t2.loc = t1.loc; + t2.ver = ve[ve[t1.ver]]; +} + +inline void tetgenmesh::enext2self(triface& t) { + t.ver = ve[ve[t.ver]]; +} + +// If f0 and f1 are both in the same face ring of a face, f1 = f0.fnext(). +// If f1 exists, return true. Otherwise, return false, i.e., f0 is a +// boundary or hull face. + +inline bool tetgenmesh::fnext(triface& t1, triface& t2) { + return getnextface(&t1, &t2); +} + +inline bool tetgenmesh::fnextself(triface& t) { + return getnextface(&t, NULL); +} + +// enextfnext() and enext2fnext() are combination primitives of enext(), +// enext2() and fnext(). + +inline void tetgenmesh::enextfnext(triface& t1, triface& t2) { + enext(t1, t2); + fnextself(t2); +} + +inline void tetgenmesh::enextfnextself(triface& t) { + enextself(t); + fnextself(t); +} + +inline void tetgenmesh::enext2fnext(triface& t1, triface& t2) { + enext2(t1, t2); + fnextself(t2); +} + +inline void tetgenmesh::enext2fnextself(triface& t) { + enext2self(t); + fnextself(t); +} + +// Primitives to infect or cure a tetrahedron with the virus. The last +// third bit of the pointer is marked for infection. These rely on the +// assumption that all tetrahedron are aligned to eight-byte boundaries. + +inline void tetgenmesh::infect(triface& t) { + t.tet[0] = (tetrahedron) ((unsigned long) t.tet[0] | (unsigned long) 4l); +} + +inline void tetgenmesh::uninfect(triface& t) { + t.tet[0] = (tetrahedron) ((unsigned long) t.tet[0] & ~ (unsigned long) 4l); +} + +// Test a tetrahedron for viral infection. + +inline bool tetgenmesh::infected(triface& t) { + return (((unsigned long) t.tet[0] & (unsigned long) 4l) != 0); +} + +// Check or set a tetrahedron's attributes. + +inline REAL tetgenmesh::elemattribute(tetrahedron* ptr, int attnum) { + return ((REAL *) (ptr))[elemattribindex + attnum]; +} + +inline void tetgenmesh:: +setelemattribute(tetrahedron* ptr, int attnum, REAL value){ + ((REAL *) (ptr))[elemattribindex + attnum] = value; +} + +// Check or set a tetrahedron's maximum volume bound. + +inline REAL tetgenmesh::volumebound(tetrahedron* ptr) { + return ((REAL *) (ptr))[volumeboundindex]; +} + +inline void tetgenmesh::setvolumebound(tetrahedron* ptr, REAL value) { + ((REAL *) (ptr))[volumeboundindex] = value; +} + +// +// End of primitives for tetrahedra +// + +// +// Begin of primitives for subfaces/subsegments +// + +// Each subface contains three pointers to its neighboring subfaces, with +// edge versions. To save memory, both information are kept in a single +// pointer. To make this possible, all subfaces are aligned to eight-byte +// boundaries, so that the last three bits of each pointer are zeros. An +// edge version (in the range 0 to 5) is compressed into the last three +// bits of each pointer by 'sencode()'. 'sdecode()' decodes a pointer, +// extracting an edge version and a pointer to the beginning of a subface. + +inline void tetgenmesh::sdecode(shellface sptr, face& s) { + s.shver = (int) ((unsigned long) (sptr) & (unsigned long) 7l); + s.sh = (shellface *) ((unsigned long) (sptr) & ~ (unsigned long) 7l); +} + +inline tetgenmesh::shellface tetgenmesh::sencode(face& s) { + return (shellface) ((unsigned long) s.sh | (unsigned long) s.shver); +} + +// spivot() finds the other subface (from this subface) that shares the +// same edge. + +inline void tetgenmesh::spivot(face& s1, face& s2) { + shellface sptr = s1.sh[Orient(s1.shver)]; + sdecode(sptr, s2); +} + +inline void tetgenmesh::spivotself(face& s) { + shellface sptr = s.sh[Orient(s.shver)]; + sdecode(sptr, s); +} + +// sbond() bonds two subfaces together, i.e., after bonding, both faces +// are pointing to each other. + +inline void tetgenmesh::sbond(face& s1, face& s2) { + s1.sh[Orient(s1.shver)] = sencode(s2); + s2.sh[Orient(s2.shver)] = sencode(s1); +} + +// sbond1() only bonds s2 to s1, i.e., after bonding, s1 is pointing to s2, +// but s2 is not pointing to s1. + +inline void tetgenmesh::sbond1(face& s1, face& s2) { + s1.sh[Orient(s1.shver)] = sencode(s2); +} + +// Dissolve a subface bond (from one side). Note that the other subface +// will still think it's connected to this subface. + +inline void tetgenmesh::sdissolve(face& s) { + s.sh[Orient(s.shver)] = (shellface) dummysh; +} + +// These primitives determine or set the origin, destination, or apex +// of a subface with respect to the edge version. + +inline tetgenmesh::point tetgenmesh::sorg(face& s) { + return (point) s.sh[3 + vo[s.shver]]; +} + +inline tetgenmesh::point tetgenmesh::sdest(face& s) { + return (point) s.sh[3 + vd[s.shver]]; +} + +inline tetgenmesh::point tetgenmesh::sapex(face& s) { + return (point) s.sh[3 + va[s.shver]]; +} + +inline void tetgenmesh::setsorg(face& s, point pointptr) { + s.sh[3 + vo[s.shver]] = (shellface) pointptr; +} + +inline void tetgenmesh::setsdest(face& s, point pointptr) { + s.sh[3 + vd[s.shver]] = (shellface) pointptr; +} + +inline void tetgenmesh::setsapex(face& s, point pointptr) { + s.sh[3 + va[s.shver]] = (shellface) pointptr; +} + +// These primitives were drived from Mucke[2]'s triangle-edge data structure +// to change face-edge relation in a subface (sesym, senext and senext2). + +inline void tetgenmesh::sesym(face& s1, face& s2) { + s2.sh = s1.sh; + s2.shver = s1.shver + (EdgeRing(s1.shver) ? -1 : 1); +} + +inline void tetgenmesh::sesymself(face& s) { + s.shver += (EdgeRing(s.shver) ? -1 : 1); +} + +inline void tetgenmesh::senext(face& s1, face& s2) { + s2.sh = s1.sh; + s2.shver = ve[s1.shver]; +} + +inline void tetgenmesh::senextself(face& s) { + s.shver = ve[s.shver]; +} + +inline void tetgenmesh::senext2(face& s1, face& s2) { + s2.sh = s1.sh; + s2.shver = ve[ve[s1.shver]]; +} + +inline void tetgenmesh::senext2self(face& s) { + s.shver = ve[ve[s.shver]]; +} + +// If f0 and f1 are both in the same face ring, then f1 = f0.fnext(), + +inline void tetgenmesh::sfnext(face& s1, face& s2) { + getnextsface(&s1, &s2); +} + +inline void tetgenmesh::sfnextself(face& s) { + getnextsface(&s, NULL); +} + +// These primitives read or set a pointer of the badface structure. The +// pointer is stored sh[11]. + +inline tetgenmesh::badface* tetgenmesh::shell2badface(face& s) { + return (badface*) s.sh[11]; +} + +inline void tetgenmesh::setshell2badface(face& s, badface* value) { + s.sh[11] = (shellface) value; +} + +// Check or set a subface's maximum area bound. + +inline REAL tetgenmesh::areabound(face& s) { + return ((REAL *) (s.sh))[areaboundindex]; +} + +inline void tetgenmesh::setareabound(face& s, REAL value) { + ((REAL *) (s.sh))[areaboundindex] = value; +} + +// These primitives read or set a shell marker. Shell markers are used +// to hold user boundary information. + +inline int tetgenmesh::shellmark(face& s) { + return ((int *) (s.sh))[shmarkindex]; +} + +inline void tetgenmesh::setshellmark(face& s, int value) { + ((int *) (s.sh))[shmarkindex] = value; +} + +// These primitives set or read the type of the subface or subsegment. + +inline enum tetgenmesh::shestype tetgenmesh::shelltype(face& s) { + return (enum shestype) ((int *) (s.sh))[shmarkindex + 1]; +} + +inline void tetgenmesh::setshelltype(face& s, enum shestype value) { + ((int *) (s.sh))[shmarkindex + 1] = (int) value; +} + +// Primitives to infect or cure a subface with the virus. These rely on the +// assumption that all tetrahedra are aligned to eight-byte boundaries. + +inline void tetgenmesh::sinfect(face& s) { + s.sh[6] = (shellface) ((unsigned long) s.sh[6] | (unsigned long) 4l); +} + +inline void tetgenmesh::suninfect(face& s) { + s.sh[6] = (shellface)((unsigned long) s.sh[6] & ~(unsigned long) 4l); +} + +// Test a subface for viral infection. + +inline bool tetgenmesh::sinfected(face& s) { + return (((unsigned long) s.sh[6] & (unsigned long) 4l) != 0); +} + +// +// End of primitives for subfaces/subsegments +// + +// +// Begin of primitives for interacting between tetrahedra and subfaces +// + +// tspivot() finds a subface abutting on this tetrahdera. + +inline void tetgenmesh::tspivot(triface& t, face& s) { + shellface sptr = (shellface) t.tet[8 + t.loc]; + sdecode(sptr, s); +} + +// stpivot() finds a tetrahedron abutting a subface. + +inline void tetgenmesh::stpivot(face& s, triface& t) { + tetrahedron ptr = (tetrahedron) s.sh[6 + EdgeRing(s.shver)]; + decode(ptr, t); +} + +// tsbond() bond a tetrahedron to a subface. + +inline void tetgenmesh::tsbond(triface& t, face& s) { + t.tet[8 + t.loc] = (tetrahedron) sencode(s); + s.sh[6 + EdgeRing(s.shver)] = (shellface) encode(t); +} + +// tsdissolve() dissolve a bond (from the tetrahedron side). + +inline void tetgenmesh::tsdissolve(triface& t) { + t.tet[8 + t.loc] = (tetrahedron) dummysh; +} + +// stdissolve() dissolve a bond (from the subface side). + +inline void tetgenmesh::stdissolve(face& s) { + s.sh[6 + EdgeRing(s.shver)] = (shellface) dummytet; +} + +// +// End of primitives for interacting between tetrahedra and subfaces +// + +// +// Begin of primitives for interacting between subfaces and subsegs +// + +// sspivot() finds a subsegment abutting a subface. + +inline void tetgenmesh::sspivot(face& s, face& edge) { + shellface sptr = (shellface) s.sh[8 + Orient(s.shver)]; + sdecode(sptr, edge); +} + +// ssbond() bond a subface to a subsegment. + +inline void tetgenmesh::ssbond(face& s, face& edge) { + s.sh[8 + Orient(s.shver)] = sencode(edge); + edge.sh[0] = sencode(s); +} + +// ssdisolve() dissolve a bond (from the subface side) + +inline void tetgenmesh::ssdissolve(face& s) { + s.sh[8 + Orient(s.shver)] = (shellface) dummysh; +} + +// +// End of primitives for interacting between subfaces and subsegs +// + +// +// Begin of primitives for points +// + +inline int tetgenmesh::pointmark(point pt) { + return ((int *) (pt))[pointmarkindex]; +} + +inline void tetgenmesh::setpointmark(point pt, int value) { + ((int *) (pt))[pointmarkindex] = value; +} + +// These two primitives set and read the type of the point. + +inline enum tetgenmesh::verttype tetgenmesh::pointtype(point pt) { + return (enum verttype) ((int *) (pt))[pointmarkindex + 1]; +} + +inline void tetgenmesh::setpointtype(point pt, enum verttype value) { + ((int *) (pt))[pointmarkindex + 1] = (int) value; +} + +// These two primitives set and read a pointer to a tetrahedron. + +inline tetgenmesh::tetrahedron tetgenmesh::point2tet(point pt) { + return ((tetrahedron *) (pt))[point2simindex]; +} + +inline void tetgenmesh::setpoint2tet(point pt, tetrahedron value) { + ((tetrahedron *) (pt))[point2simindex] = value; +} + +// These two primitives set and read a pointer to a subface/subsegment. +// Note: they use the same field as the above. Don't use them together. + +inline tetgenmesh::shellface tetgenmesh::point2sh(point pt) { + return (shellface) ((tetrahedron *) (pt))[point2simindex]; +} + +inline void tetgenmesh::setpoint2sh(point pt, shellface value) { + ((tetrahedron *) (pt))[point2simindex] = (tetrahedron) value; +} + +// These two primitives set and read a pointer to a point. +// Note: they use the same field as the above. Don't use them together. + +inline tetgenmesh::point tetgenmesh::point2pt(point pt) { + return (point) ((tetrahedron *) (pt))[point2simindex]; +} + +inline void tetgenmesh::setpoint2pt(point pt, point value) { + ((tetrahedron *) (pt))[point2simindex] = (tetrahedron) value; +} + +// These primitives set and read a pointer to its parent point. They're used +// only in qulaity conforming Delaunay mesh algorithm. + +inline tetgenmesh::point tetgenmesh::point2ppt(point pt) { + return (point) ((tetrahedron *) (pt))[point2simindex + 1]; +} + +inline void tetgenmesh::setpoint2ppt(point pt, point value) { + ((tetrahedron *) (pt))[point2simindex + 1] = (tetrahedron) value; +} + +// Get the pre-calculated lifting point of a facet (specified by its mark). + +inline tetgenmesh::point tetgenmesh::getliftpoint(int facetmark) { + return (point) &liftpointarray[(facetmark - 1) * 3]; +} + +// +// End of primitives for points +// + +// +// Begin of advanced primitives +// + +// adjustedgering() adjusts the edge version so that it belongs to the +// indicated edge ring. The 'direction' only can be 0(CCW) or 1(CW). +// If the edge is not in the wanted edge ring, reverse it. + +inline void tetgenmesh::adjustedgering(triface& t, int direction) { + if (EdgeRing(t.ver) != direction) { + esymself(t); + } +} + +inline void tetgenmesh::adjustedgering(face& s, int direction) { + if (EdgeRing(s.shver) != direction) { + sesymself(s); + } +} + +// isdead() returns TRUE if the tetrahedron or subface has been dealloced. + +inline bool tetgenmesh::isdead(triface* t) { + if (t->tet == (tetrahedron *) NULL) return true; + else return t->tet[4] == (tetrahedron) NULL; +} + +inline bool tetgenmesh::isdead(face* s) { + if (s->sh == (shellface *) NULL) return true; + else return s->sh[3] == (shellface) NULL; +} + +// isfacehaspoint() returns TRUE if the 'testpoint' is one of the vertices +// of the subface 's'. + +inline bool tetgenmesh::isfacehaspoint(face* s, point testpoint) { + return (s->sh[3] == (shellface) testpoint) || + (s->sh[4] == (shellface) testpoint) || + (s->sh[5] == (shellface) testpoint); +} + +// isfacehasedge() returns TRUE if the edge (given by its two endpoints) is +// one of the three edges of the subface 's'. + +inline bool tetgenmesh::isfacehasedge(face* s, point tend1, point tend2) { + return (isfacehaspoint(s, tend1) && isfacehaspoint(s, tend2)); +} + +// issymexist() returns TRUE if the adjoining tetrahedron is not 'duumytet'. + +inline bool tetgenmesh::issymexist(triface* t) { + tetrahedron *ptr = (tetrahedron *) + ((unsigned long)(t->tet[t->loc]) & ~(unsigned long)7l); + return ptr != dummytet; +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// getnextface() Get the successor of 'tface1' in the face ring. // +// // +// If 'tface1' is not a boundary (or hull) face, then its successor in the // +// face ring exists. The successor is returned in 'tface2' if it is not a // +// NULL, or the 'tface1' itself is used to return this face. On finish, the // +// function returns TRUE. // +// // +// If 'tface1' is a boundary (or hull) face, its successor does not exist. // +// This case, return FALSE and 'tface1' remains unchanged. // +// // +/////////////////////////////////////////////////////////////////////////////// + +bool tetgenmesh::getnextface(triface* tface1, triface* tface2) +{ + point torg, tdest; + int tloc, tver; + + // Where the next face locates, in 'tface1' or in its neigbhour? It can be + // quickly determined by checking the edge ring of 'tface1'. + if (EdgeRing(tface1->ver) == CW) { + // The next face is in the neigbhour of 'tface1'. + if (!issymexist(tface1)) { + // Hit outer space - The next face does not exist. + return false; + } + torg = org(*tface1); + tdest = dest(*tface1); + if (tface2) { + sym(*tface1, *tface2); + findedge(tface2, torg, tdest); + } else { + symself(*tface1); + findedge(tface1, torg, tdest); + } + } else { + // The next face is in 'tface1'. + if (tface2) { + *tface2 = *tface1; + } + } + + if (tface2) { + tloc = tface2->loc; + tver = tface2->ver; + tface2->loc = locver2nextf[tloc][tver][0]; + tface2->ver = locver2nextf[tloc][tver][1]; + } else { + tloc = tface1->loc; + tver = tface1->ver; + tface1->loc = locver2nextf[tloc][tver][0]; + tface1->ver = locver2nextf[tloc][tver][1]; + } + return true; +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// getnextsface() Finds the next subface in the face ring. // +// // +// For saving space in the data structure of subface, there only exists one // +// face ring around a segment (see programming manual). This routine imple- // +// ments the double face ring as desired in Muecke's data structure. // +// // +/////////////////////////////////////////////////////////////////////////////// + +void tetgenmesh::getnextsface(face* s1, face* s2) +{ + face neighsh, spinsh; + face testseg; + + sspivot(*s1, testseg); + if (testseg.sh != dummysh) { + testseg.shver = 0; + if (sorg(testseg) == sorg(*s1)) { + spivot(*s1, neighsh); + } else { + spinsh = *s1; + do { + neighsh = spinsh; + spivotself(spinsh); + } while (spinsh.sh != s1->sh); + } + } else { + spivot(*s1, neighsh); + } + if (sorg(neighsh) != sorg(*s1)) { + sesymself(neighsh); + } + if (s2 != (face *) NULL) { + *s2 = neighsh; + } else { + *s1 = neighsh; + } +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// tsspivot() Finds a subsegment abutting on a tetrahderon's edge. // +// // +// The edge is represented in the primary edge of 'checkedge'. If there is a // +// subsegment bonded at this edge, it is returned in handle 'checkseg', the // +// edge direction of 'checkseg' is conformed to 'checkedge'. If there isn't, // +// set 'checkseg.sh = dummysh' to indicate it is not a subsegment. // +// // +// To find whether an edge of a tetrahedron is a subsegment or not. First we // +// need find a subface around this edge to see if it contains a subsegment. // +// The reason is there is no direct connection between a tetrahedron and its // +// adjoining subsegments. // +// // +/////////////////////////////////////////////////////////////////////////////// + +void tetgenmesh::tsspivot(triface* checkedge, face* checkseg) +{ + triface spintet; + face parentsh; + point tapex; + int hitbdry; + + spintet = *checkedge; + tapex = apex(*checkedge); + hitbdry = 0; + do { + tspivot(spintet, parentsh); + if (parentsh.sh != dummysh) { + // Find a subface! + findedge(&parentsh, org(*checkedge), dest(*checkedge)); + sspivot(parentsh, *checkseg); + if (checkseg->sh != dummysh) { + // Find a subsegment! Correct its edge direction before return. + if (sorg(*checkseg) != sorg(parentsh)) { + sesymself(*checkseg); + } + } + return; + } + if (!fnextself(spintet)) { + hitbdry++; + if (hitbdry < 2) { + esym(*checkedge, spintet); + if (!fnextself(spintet)) { + hitbdry++; + } + } + } + } while ((apex(spintet) != tapex) && (hitbdry < 2)); + // Not find. + checkseg->sh = dummysh; +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// sstpivot() Finds a tetrahedron abutting a subsegment. // +// // +// This is the inverse operation of 'tsspivot()'. One subsegment shared by // +// arbitrary number of tetrahedron, the returned tetrahedron is not unique. // +// The edge direction of the returned tetrahedron is conformed to the given // +// subsegment. // +// // +/////////////////////////////////////////////////////////////////////////////// + +void tetgenmesh::sstpivot(face* checkseg, triface* retedge) +{ + face parentsh; + + // Get the subface which holds the subsegment. + sdecode(checkseg->sh[0], parentsh); + assert(parentsh.sh != dummysh); + // Get a tetraheron to which the subface attches. + stpivot(parentsh, *retedge); + if (retedge->tet == dummytet) { + sesymself(parentsh); + stpivot(parentsh, *retedge); + assert(retedge->tet != dummytet); + } + // Correct the edge direction before return. + findedge(retedge, sorg(*checkseg), sdest(*checkseg)); +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// findorg() Finds a point in the given handle (tetrahedron or subface). // +// // +// If 'dorg' is a one of vertices of the given handle, set the origin of // +// this handle be that point and return TRUE. Otherwise, return FALSE and // +// 'tface' remains unchanged. // +// // +/////////////////////////////////////////////////////////////////////////////// + +bool tetgenmesh::findorg(triface* tface, point dorg) +{ + if (org(*tface) == dorg) { + return true; + } else { + if (dest(*tface) == dorg) { + enextself(*tface); + return true; + } else { + if (apex(*tface) == dorg) { + enext2self(*tface); + return true; + } else { + if (oppo(*tface) == dorg) { + // Keep 'tface' referring to the same tet after fnext(). + adjustedgering(*tface, CCW); + fnextself(*tface); + enext2self(*tface); + return true; + } + } + } + } + return false; +} + +bool tetgenmesh::findorg(face* sface, point dorg) +{ + if (sorg(*sface) == dorg) { + return true; + } else { + if (sdest(*sface) == dorg) { + senextself(*sface); + return true; + } else { + if (sapex(*sface) == dorg) { + senext2self(*sface); + return true; + } + } + } + return false; +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// findedge() Find an edge in the given handle (tetrahedron or subface). // +// // +// The edge is given in two points 'eorg' and 'edest'. It is assumed that // +// the edge must exist in the given handle (tetrahedron or subface). This // +// routine sets the right edge version for the input handle. // +// // +/////////////////////////////////////////////////////////////////////////////// + +void tetgenmesh::findedge(triface* tface, point eorg, point edest) +{ + int i; + + for (i = 0; i < 3; i++) { + if (org(*tface) == eorg) { + if (dest(*tface) == edest) { + // Edge is found, return. + return; + } + } else { + if (org(*tface) == edest) { + if (dest(*tface) == eorg) { + // Edge is found, but need to inverse the direction. + esymself(*tface); + return; + } + } + } + enextself(*tface); + } + // It should not be here. + assert(i < 3); +} + +void tetgenmesh::findedge(face* sface, point eorg, point edest) +{ + int i; + + for (i = 0; i < 3; i++) { + if (sorg(*sface) == eorg) { + if (sdest(*sface) == edest) { + // Edge is found, return. + return; + } + } else { + if (sorg(*sface) == edest) { + if (sdest(*sface) == eorg) { + // Edge is found, but need to inverse the direction. + sesymself(*sface); + return; + } + } + } + senextself(*sface); + } + // It should not be here. + assert(i < 3); +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// findface() Find the face has the given origin, destination and apex. // +// // +// On input, 'fface' is a handle which may contain the three corners or may // +// not or may be dead. On return, it represents exactly the face with the // +// given origin, destination and apex. // +// // +/////////////////////////////////////////////////////////////////////////////// + +void tetgenmesh::findface(triface *fface, point forg, point fdest, point fapex) +{ + triface spintet; + enum finddirectionresult collinear; + int hitbdry; + + if (!isdead(fface)) { + // First check the easiest case, that 'fface' is just the right one. + if (org(*fface) == forg && dest(*fface) == fdest && + apex(*fface) == fapex) return; + } else { + // The input handle is dead, use the 'recenttet' if it is alive. + if (!isdead(&recenttet)) *fface = recenttet; + } + + if (!isdead(fface)) { + if (!findorg(fface, forg)) { + // 'forg' is not a corner of 'fface', locate it. + preciselocate(forg, fface); + } + // It is possible that forg is not found in a non-convex mesh. + if (org(*fface) == forg) { + collinear = finddirection(fface, fdest); + if (collinear == RIGHTCOLLINEAR) { + // fdest is just the destination. + } else if (collinear == LEFTCOLLINEAR) { + enext2self(*fface); + esymself(*fface); + } else if (collinear == TOPCOLLINEAR) { + fnextself(*fface); + enext2self(*fface); + esymself(*fface); + } + } + // It is possible taht fdest is not found in a non-convex mesh. + if ((org(*fface) == forg) && (dest(*fface) == fdest)) { + // Find the apex of 'fapex'. + spintet = *fface; + hitbdry = 0; + do { + if (apex(spintet) == fapex) { + // We have done. Be careful the edge direction of 'spintet', + // it may reversed because of hitting boundary once. + if (org(spintet) != org(*fface)) { + esymself(spintet); + } + *fface = spintet; + return; + } + if (!fnextself(spintet)) { + hitbdry ++; + if (hitbdry < 2) { + esym(*fface, spintet); + if (!fnextself(spintet)) { + hitbdry ++; + } + } + } + } while (hitbdry < 2 && apex(spintet) != apex(*fface)); + // It is possible that fapex is not found in a non-convex mesh. + } + } + + if (isdead(fface) || (org(*fface) != forg) || (dest(*fface) != fdest) || + (apex(*fface) != fapex)) { + // Too bad, the input handle is useless. We have to find a handle + // for 'fface' contains the 'forg' and 'fdest'. Here a brute force + // search is performed. + if (b->verbose > 1) { + printf("Warning in findface(): Perform a brute-force searching.\n"); + } + enum verttype forgty, fdestty, fapexty; + int share, i; + forgty = pointtype(forg); + fdestty = pointtype(fdest); + fapexty = pointtype(fapex); + setpointtype(forg, DEADVERTEX); + setpointtype(fdest, DEADVERTEX); + setpointtype(fapex, DEADVERTEX); + tetrahedrons->traversalinit(); + fface->tet = tetrahedrontraverse(); + while (fface->tet != (tetrahedron *) NULL) { + share = 0; + for (i = 0; i < 4; i++) { + if (pointtype((point) fface->tet[4 + i]) == DEADVERTEX) share ++; + } + if (share == 3) { + // Found! Set the correct face and desired corners. + if (pointtype((point) fface->tet[4]) != DEADVERTEX) { + fface->loc = 2; + } else if (pointtype((point) fface->tet[5]) != DEADVERTEX) { + fface->loc = 3; + } else if (pointtype((point) fface->tet[6]) != DEADVERTEX) { + fface->loc = 1; + } else { // pointtype((point) fface->tet[7]) != DEADVERTEX + fface->loc = 0; + } + findedge(fface, forg, fdest); + break; + } + fface->tet = tetrahedrontraverse(); + } + setpointtype(forg, forgty); + setpointtype(fdest, fdestty); + setpointtype(fapex, fapexty); + if (fface->tet == (tetrahedron *) NULL) { + // It is impossible to reach here. + printf("Internal error: Fail to find the indicated face.\n"); + internalerror(); + } + } +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// getonextseg() Get the next SEGMENT counterclockwise with the same org. // +// // +// 's' is a subface. This routine reteuns the segment which is counterclock- // +// wise with the origin of s. // +// // +/////////////////////////////////////////////////////////////////////////////// + +void tetgenmesh::getonextseg(face* s, face* lseg) +{ + face checksh, checkseg; + point forg; + + forg = sorg(*s); + checksh = *s; + do { + // Go to the edge at forg's left side. + senext2self(checksh); + // Check if there is a segment attaching this edge. + sspivot(checksh, checkseg); + if (checkseg.sh != dummysh) break; + // No segment! Go to the neighbor of this subface. + spivotself(checksh); + // It should always meet a segment before come back. + assert(checksh.sh != s->sh); + if (sorg(checksh) != forg) { + sesymself(checksh); + assert(sorg(checksh) == forg); + } + } while (true); + assert(checkseg.sh != dummysh); + if (sorg(checkseg) != forg) sesymself(checkseg); + *lseg = checkseg; +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// getseghasorg() Get the segment containing the given point. // +// // +// On input we know 'dorg' is an endpoint of the segment containing 'sseg'. // +// This routine search along 'sseg' for the vertex 'dorg'. On return, 'sseg' // +// contains 'dorg' as its origin. // +// // +/////////////////////////////////////////////////////////////////////////////// + +void tetgenmesh::getseghasorg(face* sseg, point dorg) +{ + face nextseg; + point checkpt; + + nextseg = *sseg; + checkpt = sorg(nextseg); + while ((checkpt != dorg) && (pointtype(checkpt) == FREESEGVERTEX)) { + // Search dorg along the original direction of sseg. + senext2self(nextseg); + spivotself(nextseg); + nextseg.shver = 0; + if (sdest(nextseg) != checkpt) sesymself(nextseg); + checkpt = sorg(nextseg); + } + if (checkpt == dorg) { + *sseg = nextseg; + return; + } + nextseg = *sseg; + checkpt = sdest(nextseg); + while ((checkpt != dorg) && (pointtype(checkpt) == FREESEGVERTEX)) { + // Search dorg along the destinational direction of sseg. + senextself(nextseg); + spivotself(nextseg); + nextseg.shver = 0; + if (sorg(nextseg) != checkpt) sesymself(nextseg); + checkpt = sdest(nextseg); + } + if (checkpt == dorg) { + sesym(nextseg, *sseg); + return; + } + // Should not be here. + assert(0); +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// getsubsegfarorg() Get the origin of the parent segment of a subseg. // +// // +/////////////////////////////////////////////////////////////////////////////// + +tetgenmesh::point tetgenmesh::getsubsegfarorg(face* sseg) +{ + face prevseg; + point checkpt; + + checkpt = sorg(*sseg); + senext2(*sseg, prevseg); + spivotself(prevseg); + // Search dorg along the original direction of sseg. + while (prevseg.sh != dummysh) { + prevseg.shver = 0; + if (sdest(prevseg) != checkpt) sesymself(prevseg); + checkpt = sorg(prevseg); + senext2self(prevseg); + spivotself(prevseg); + } + return checkpt; +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// getsubsegfardest() Get the dest. of the parent segment of a subseg. // +// // +/////////////////////////////////////////////////////////////////////////////// + +tetgenmesh::point tetgenmesh::getsubsegfardest(face* sseg) +{ + face nextseg; + point checkpt; + + checkpt = sdest(*sseg); + senext(*sseg, nextseg); + spivotself(nextseg); + // Search dorg along the destinational direction of sseg. + while (nextseg.sh != dummysh) { + nextseg.shver = 0; + if (sorg(nextseg) != checkpt) sesymself(nextseg); + checkpt = sdest(nextseg); + senextself(nextseg); + spivotself(nextseg); + } + return checkpt; +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// printtet() Print out the details of a tetrahedron on screen. // +// // +// It's also used when the highest level of verbosity (`-VVV') is specified. // +// // +/////////////////////////////////////////////////////////////////////////////// + +void tetgenmesh::printtet(triface* tface) +{ + triface tmpface, prtface; + point tmppt; + face tmpsh; + int facecount; + + printf("Tetra x%lx with loc(%i) and ver(%i):", + (unsigned long)(tface->tet), tface->loc, tface->ver); + if (infected(*tface)) { + printf(" (infected)"); + } + printf("\n"); + + tmpface = *tface; + facecount = 0; + while(facecount < 4) { + tmpface.loc = facecount; + sym(tmpface, prtface); + if(prtface.tet == dummytet) { + printf(" [%i] Outer space.\n", facecount); + } else { + printf(" [%i] x%lx loc(%i).", facecount, + (unsigned long)(prtface.tet), prtface.loc); + if (infected(prtface)) { + printf(" (infected)"); + } + printf("\n"); + } + facecount ++; + } + + tmppt = org(*tface); + if(tmppt == (point) NULL) { + printf(" Org [%i] NULL\n", locver2org[tface->loc][tface->ver]); + } else { + printf(" Org [%i] x%lx (%.12g,%.12g,%.12g) %d\n", + locver2org[tface->loc][tface->ver], (unsigned long)(tmppt), + tmppt[0], tmppt[1], tmppt[2], pointmark(tmppt)); + } + tmppt = dest(*tface); + if(tmppt == (point) NULL) { + printf(" Dest[%i] NULL\n", locver2dest[tface->loc][tface->ver]); + } else { + printf(" Dest[%i] x%lx (%.12g,%.12g,%.12g) %d\n", + locver2dest[tface->loc][tface->ver], (unsigned long)(tmppt), + tmppt[0], tmppt[1], tmppt[2], pointmark(tmppt)); + } + tmppt = apex(*tface); + if(tmppt == (point) NULL) { + printf(" Apex[%i] NULL\n", locver2apex[tface->loc][tface->ver]); + } else { + printf(" Apex[%i] x%lx (%.12g,%.12g,%.12g) %d\n", + locver2apex[tface->loc][tface->ver], (unsigned long)(tmppt), + tmppt[0], tmppt[1], tmppt[2], pointmark(tmppt)); + } + tmppt = oppo(*tface); + if(tmppt == (point) NULL) { + printf(" Oppo[%i] NULL\n", loc2oppo[tface->loc]); + } else { + printf(" Oppo[%i] x%lx (%.12g,%.12g,%.12g) %d\n", + loc2oppo[tface->loc], (unsigned long)(tmppt), + tmppt[0], tmppt[1], tmppt[2], pointmark(tmppt)); + } + + if (b->useshelles) { + tmpface = *tface; + facecount = 0; + while(facecount < 4) { + tmpface.loc = facecount; + tspivot(tmpface, tmpsh); + if(tmpsh.sh != dummysh) { + printf(" [%i] x%lx ID(%i).\n", facecount, + (unsigned long)(tmpsh.sh), shellmark(tmpsh)); + } + facecount ++; + } + } +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// printsh() Print out the details of a subface or subsegment on screen. // +// // +// It's also used when the highest level of verbosity (`-VVV') is specified. // +// // +/////////////////////////////////////////////////////////////////////////////// + +void tetgenmesh::printsh(face* sface) +{ + face prtsh; + triface prttet; + point printpoint; + + if (sapex(*sface) != NULL) { + printf("subface x%lx, ver %d, mark %d:", + (unsigned long)(sface->sh), sface->shver, shellmark(*sface)); + } else { + printf("Subsegment x%lx, ver %d, mark %d:", + (unsigned long)(sface->sh), sface->shver, shellmark(*sface)); + } + if (sinfected(*sface)) { + printf(" (infected)"); + } + if (shell2badface(*sface)) { + printf(" (queued)"); + } + if (sapex(*sface) != NULL) { + if (shelltype(*sface) == PROTCYLSUBFACE) { + printf(" (cyls)"); + } else if (shelltype(*sface) == PROTSPHSUBFACE) { + printf(" (sphs)"); + } + } else { + if (shelltype(*sface) == SHARPSEGMENT) { + printf(" (sharp)"); + } else if (shelltype(*sface) == PROTCYLSEGMENT) { + printf(" (cyls)"); + } else if (shelltype(*sface) == PROTSPHSEGMENT) { + printf(" (sphs)"); + } + } + printf("\n"); + + sdecode(sface->sh[0], prtsh); + if (prtsh.sh == dummysh) { + printf(" [0] = No shell\n"); + } else { + printf(" [0] = x%lx %d\n", (unsigned long)(prtsh.sh), prtsh.shver); + } + sdecode(sface->sh[1], prtsh); + if (prtsh.sh == dummysh) { + printf(" [1] = No shell\n"); + } else { + printf(" [1] = x%lx %d\n", (unsigned long)(prtsh.sh), prtsh.shver); + } + sdecode(sface->sh[2], prtsh); + if (prtsh.sh == dummysh) { + printf(" [2] = No shell\n"); + } else { + printf(" [2] = x%lx %d\n", (unsigned long)(prtsh.sh), prtsh.shver); + } + + printpoint = sorg(*sface); + if (printpoint == (point) NULL) + printf(" Org [%d] = NULL\n", vo[sface->shver]); + else + printf(" Org [%d] = x%lx (%.12g,%.12g,%.12g) %d\n", + vo[sface->shver], (unsigned long)(printpoint), printpoint[0], + printpoint[1], printpoint[2], pointmark(printpoint)); + printpoint = sdest(*sface); + if (printpoint == (point) NULL) + printf(" Dest[%d] = NULL\n", vd[sface->shver]); + else + printf(" Dest[%d] = x%lx (%.12g,%.12g,%.12g) %d\n", + vd[sface->shver], (unsigned long)(printpoint), printpoint[0], + printpoint[1], printpoint[2], pointmark(printpoint)); + + if (sapex(*sface) != NULL) { + printpoint = sapex(*sface); + if (printpoint == (point) NULL) + printf(" Apex[%d] = NULL\n", va[sface->shver]); + else + printf(" Apex[%d] = x%lx (%.12g,%.12g,%.12g) %d\n", + va[sface->shver], (unsigned long)(printpoint), printpoint[0], + printpoint[1], printpoint[2], pointmark(printpoint)); + + decode(sface->sh[6], prttet); + if (prttet.tet == dummytet) { + printf(" [6] = Outer space\n"); + } else { + printf(" [6] = x%lx %d\n", + (unsigned long)(prttet.tet), prttet.loc); + } + decode(sface->sh[7], prttet); + if (prttet.tet == dummytet) { + printf(" [7] = Outer space\n"); + } else { + printf(" [7] = x%lx %d\n", + (unsigned long)(prttet.tet), prttet.loc); + } + + sdecode(sface->sh[8], prtsh); + if (prtsh.sh == dummysh) { + printf(" [8] = No subsegment\n"); + } else { + printf(" [8] = x%lx %d\n", + (unsigned long)(prtsh.sh), prtsh.shver); + } + sdecode(sface->sh[9], prtsh); + if (prtsh.sh == dummysh) { + printf(" [9] = No subsegment\n"); + } else { + printf(" [9] = x%lx %d\n", + (unsigned long)(prtsh.sh), prtsh.shver); + } + sdecode(sface->sh[10], prtsh); + if (prtsh.sh == dummysh) { + printf(" [10]= No subsegment\n"); + } else { + printf(" [10]= x%lx %d\n", + (unsigned long)(prtsh.sh), prtsh.shver); + } + } +} + +// +// End of advanced primitives +// + +// +// End of mesh manipulation primitives +// + +// +// Begin of mesh items searching routines +// + +/////////////////////////////////////////////////////////////////////////////// +// // +// makepoint2tetmap() Construct a mapping from points to tetrahedra. // +// // +// Traverses all the tetrahedra, provides each corner of each tetrahedron // +// with a pointer to that tetrahedera. Some pointers will be overwritten by // +// other pointers because each point may be a corner of several tetrahedra, // +// but in the end every point will point to a tetrahedron that contains it. // +// // +/////////////////////////////////////////////////////////////////////////////// + +void tetgenmesh::makepoint2tetmap() +{ + triface tetloop; + point pointptr; + + if (b->verbose) { + printf(" Constructing mapping from points to tetrahedra.\n"); + } + + tetrahedrons->traversalinit(); + tetloop.tet = tetrahedrontraverse(); + while (tetloop.tet != (tetrahedron *) NULL) { + // Check all four points of the tetrahedron. + pointptr = org(tetloop); + setpoint2tet(pointptr, encode(tetloop)); + pointptr = dest(tetloop); + setpoint2tet(pointptr, encode(tetloop)); + pointptr = apex(tetloop); + setpoint2tet(pointptr, encode(tetloop)); + pointptr = oppo(tetloop); + setpoint2tet(pointptr, encode(tetloop)); + // Get the next tetrahedron in the list. + tetloop.tet = tetrahedrontraverse(); + } +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// makeindex2pointmap() Create a map from index to vertices. // +// // +// 'idx2verlist' returns the created map. Traverse all vertices, a pointer // +// to each vertex is set into the array. The pointer to the first vertex is // +// saved in 'idx2verlist[0]'. Don't forget to minus 'in->firstnumber' when // +// to get the vertex form its index. // +// // +/////////////////////////////////////////////////////////////////////////////// + +void tetgenmesh::makeindex2pointmap(point*& idx2verlist) +{ + point pointloop; + int idx; + + if (b->verbose) { + printf(" Constructing mapping from indices to points.\n"); + } + + idx2verlist = new point[points->items]; + + points->traversalinit(); + pointloop = pointtraverse(); + idx = 0; + while (pointloop != (point) NULL) { + idx2verlist[idx] = pointloop; + idx++; + pointloop = pointtraverse(); + } +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// makesegmentmap() Create a map from vertices (their indices) to // +// segments incident at the same vertices. // +// // +// Two arrays 'idx2seglist' and 'segsperverlist' together return the map. // +// They form a sparse matrix structure with size (n + 1) x (n + 1), n is the // +// number of segments. idx2seglist contains row information and // +// segsperverlist contains all (non-zero) elements. The i-th entry of // +// idx2seglist is the starting position of i-th row's (non-zero) elements in // +// segsperverlist. The number of elements of i-th row is calculated by the // +// (i+1)-th entry minus i-th entry of idx2seglist. // +// // +// NOTE: These two arrays will be created inside this routine, don't forget // +// to free them after using. // +// // +/////////////////////////////////////////////////////////////////////////////// + +void tetgenmesh:: +makesegmentmap(int*& idx2seglist, shellface**& segsperverlist) +{ + shellface *shloop; + int i, j, k; + + if (b->verbose) { + printf(" Constructing mapping from points to segments.\n"); + } + + // Create and initialize 'idx2seglist'. + idx2seglist = new int[points->items + 1]; + for (i = 0; i < points->items + 1; i++) { + idx2seglist[i] = 0; + } + + // Loop the set of segments once, counter the number of segments sharing + // each vertex. + subsegs->traversalinit(); + shloop = shellfacetraverse(subsegs); + while (shloop != (shellface *) NULL) { + // Increment the number of sharing segments for each endpoint. + for (i = 0; i < 2; i++) { + j = pointmark((point) shloop[3 + i]) - in->firstnumber; + idx2seglist[j]++; + } + shloop = shellfacetraverse(subsegs); + } + + // Calculate the total length of array 'facesperverlist'. + j = idx2seglist[0]; + idx2seglist[0] = 0; // Array starts from 0 element. + for (i = 0; i < points->items; i++) { + k = idx2seglist[i + 1]; + idx2seglist[i + 1] = idx2seglist[i] + j; + j = k; + } + // The total length is in the last unit of idx2seglist. + segsperverlist = new shellface*[idx2seglist[i]]; + // Loop the set of segments again, set the info. of segments per vertex. + subsegs->traversalinit(); + shloop = shellfacetraverse(subsegs); + while (shloop != (shellface *) NULL) { + for (i = 0; i < 2; i++) { + j = pointmark((point) shloop[3 + i]) - in->firstnumber; + segsperverlist[idx2seglist[j]] = shloop; + idx2seglist[j]++; + } + shloop = shellfacetraverse(subsegs); + } + // Contents in 'idx2seglist' are shifted, now shift them back. + for (i = points->items - 1; i >= 0; i--) { + idx2seglist[i + 1] = idx2seglist[i]; + } + idx2seglist[0] = 0; +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// makesubfacemap() Create a map from vertices (their indices) to // +// subfaces incident at the same vertices. // +// // +// Two arrays 'idx2facelist' and 'facesperverlist' together return the map. // +// They form a sparse matrix structure with size (n + 1) x (n + 1), n is the // +// number of subfaces. idx2facelist contains row information and // +// facesperverlist contains all (non-zero) elements. The i-th entry of // +// idx2facelist is the starting position of i-th row's(non-zero) elements in // +// facesperverlist. The number of elements of i-th row is calculated by the // +// (i+1)-th entry minus i-th entry of idx2facelist. // +// // +// NOTE: These two arrays will be created inside this routine, don't forget // +// to free them after using. // +// // +/////////////////////////////////////////////////////////////////////////////// + +void tetgenmesh:: +makesubfacemap(int*& idx2facelist, shellface**& facesperverlist) +{ + shellface *shloop; + int i, j, k; + + if (b->verbose) { + printf(" Constructing mapping from points to subfaces.\n"); + } + + // Create and initialize 'idx2facelist'. + idx2facelist = new int[points->items + 1]; + for (i = 0; i < points->items + 1; i++) { + idx2facelist[i] = 0; + } + + // Loop the set of subfaces once, counter the number of subfaces sharing + // each vertex. + subfaces->traversalinit(); + shloop = shellfacetraverse(subfaces); + while (shloop != (shellface *) NULL) { + // Increment the number of sharing segments for each endpoint. + for (i = 0; i < 3; i++) { + j = pointmark((point) shloop[3 + i]) - in->firstnumber; + idx2facelist[j]++; + } + shloop = shellfacetraverse(subfaces); + } + + // Calculate the total length of array 'facesperverlist'. + j = idx2facelist[0]; + idx2facelist[0] = 0; // Array starts from 0 element. + for (i = 0; i < points->items; i++) { + k = idx2facelist[i + 1]; + idx2facelist[i + 1] = idx2facelist[i] + j; + j = k; + } + // The total length is in the last unit of idx2facelist. + facesperverlist = new shellface*[idx2facelist[i]]; + // Loop the set of segments again, set the info. of segments per vertex. + subfaces->traversalinit(); + shloop = shellfacetraverse(subfaces); + while (shloop != (shellface *) NULL) { + for (i = 0; i < 3; i++) { + j = pointmark((point) shloop[3 + i]) - in->firstnumber; + facesperverlist[idx2facelist[j]] = shloop; + idx2facelist[j]++; + } + shloop = shellfacetraverse(subfaces); + } + // Contents in 'idx2facelist' are shifted, now shift them back. + for (i = points->items - 1; i >= 0; i--) { + idx2facelist[i + 1] = idx2facelist[i]; + } + idx2facelist[0] = 0; +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// maketetrahedronmap() Create a map from vertices (their indices) to // +// tetrahedra incident at the same vertices. // +// // +// Two arrays 'idx2tetlist' and 'tetsperverlist' together return the map. // +// They form a sparse matrix structure with size (n + 1) x (n + 1), n is the // +// number of tetrahedra. idx2tetlist contains row information and // +// tetsperverlist contains all (non-zero) elements. The i-th entry of // +// idx2tetlist is the starting position of i-th row's (non-zero) elements in // +// tetsperverlist. The number of elements of i-th row is calculated by the // +// (i+1)-th entry minus i-th entry of idx2tetlist. // +// // +// NOTE: These two arrays will be created inside this routine, don't forget // +// to free them after using. // +// // +/////////////////////////////////////////////////////////////////////////////// + +void tetgenmesh:: +maketetrahedronmap(int*& idx2tetlist, tetrahedron**& tetsperverlist) +{ + tetrahedron *tetloop; + int i, j, k; + + if (b->verbose) { + printf(" Constructing mapping from points to tetrahedra.\n"); + } + + // Create and initialize 'idx2tetlist'. + idx2tetlist = new int[points->items + 1]; + for (i = 0; i < points->items + 1; i++) { + idx2tetlist[i] = 0; + } + + // Loop the set of tetrahedra once, counter the number of tetrahedra + // sharing each vertex. + tetrahedrons->traversalinit(); + tetloop = tetrahedrontraverse(); + while (tetloop != (tetrahedron *) NULL) { + // Increment the number of sharing tetrahedra for each endpoint. + for (i = 0; i < 4; i++) { + j = pointmark((point) tetloop[4 + i]) - in->firstnumber; + idx2tetlist[j]++; + } + tetloop = tetrahedrontraverse(); + } + + // Calculate the total length of array 'tetsperverlist'. + j = idx2tetlist[0]; + idx2tetlist[0] = 0; // Array starts from 0 element. + for (i = 0; i < points->items; i++) { + k = idx2tetlist[i + 1]; + idx2tetlist[i + 1] = idx2tetlist[i] + j; + j = k; + } + // The total length is in the last unit of idx2tetlist. + tetsperverlist = new tetrahedron*[idx2tetlist[i]]; + // Loop the set of tetrahedra again, set the info. of tet. per vertex. + tetrahedrons->traversalinit(); + tetloop = tetrahedrontraverse(); + while (tetloop != (tetrahedron *) NULL) { + for (i = 0; i < 4; i++) { + j = pointmark((point) tetloop[4 + i]) - in->firstnumber; + tetsperverlist[idx2tetlist[j]] = tetloop; + idx2tetlist[j]++; + } + tetloop = tetrahedrontraverse(); + } + // Contents in 'idx2tetlist' are shifted, now shift them back. + for (i = points->items - 1; i >= 0; i--) { + idx2tetlist[i + 1] = idx2tetlist[i]; + } + idx2tetlist[0] = 0; +} + +// +// End of mesh items searching routines +// + +// +// Begin of linear algebra functions +// + +// dot() returns the dot product: v1 dot v2. + +inline REAL tetgenmesh::dot(REAL* v1, REAL* v2) +{ + return v1[0] * v2[0] + v1[1] * v2[1] + v1[2] * v2[2]; +} + +// cross() computes the cross product: n = v1 cross v2. + +inline void tetgenmesh::cross(REAL* v1, REAL* v2, REAL* n) +{ + n[0] = v1[1] * v2[2] - v2[1] * v1[2]; + n[1] = -(v1[0] * v2[2] - v2[0] * v1[2]); + n[2] = v1[0] * v2[1] - v2[0] * v1[1]; +} + +// initm44() initializes a 4x4 matrix. +void tetgenmesh::initm44(REAL a00, REAL a01, REAL a02, REAL a03, + REAL a10, REAL a11, REAL a12, REAL a13, + REAL a20, REAL a21, REAL a22, REAL a23, + REAL a30, REAL a31, REAL a32, REAL a33, + REAL M[4][4]) +{ + M[0][0] = a00; M[0][1] = a01; M[0][2] = a02; M[0][3] = a03; + M[1][0] = a10; M[1][1] = a11; M[1][2] = a12; M[1][3] = a13; + M[2][0] = a20; M[2][1] = a21; M[2][2] = a22; M[2][3] = a23; + M[3][0] = a30; M[3][1] = a31; M[3][2] = a32; M[3][3] = a33; +} + +// m4xm4() multiplies 2 4x4 matrics: m1 = m1 * m2. +void tetgenmesh::m4xm4(REAL m1[4][4], REAL m2[4][4]) +{ + REAL tmp[4]; + int i, j; + + for (i = 0; i < 4; i++) { // i-th row + for (j = 0; j < 4; j++) { // j-th col + tmp[j] = m1[i][0] * m2[0][j] + m1[i][1] * m2[1][j] + + m1[i][2] * m2[2][j] + m1[i][3] * m2[3][j]; + } + for (j = 0; j < 4; j++) + m1[i][j] = tmp[j]; + } +} + +// m4xv4() multiplies a 4x4 matrix and 4x1 vector: v2 = m * v1 +void tetgenmesh::m4xv4(REAL v2[4], REAL m[4][4], REAL v1[4]) +{ + v2[0] = m[0][0]*v1[0] + m[0][1]*v1[1] + m[0][2]*v1[2] + m[0][3]*v1[3]; + v2[1] = m[1][0]*v1[0] + m[1][1]*v1[1] + m[1][2]*v1[2] + m[1][3]*v1[3]; + v2[2] = m[2][0]*v1[0] + m[2][1]*v1[1] + m[2][2]*v1[2] + m[2][3]*v1[3]; + v2[3] = m[3][0]*v1[0] + m[3][1]*v1[1] + m[3][2]*v1[2] + m[3][3]*v1[3]; +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// lu_decmp() Compute the LU decomposition of a matrix. // +// // +// Compute the LU decomposition of a (non-singular) square matrix A using // +// partial pivoting and implicit row exchanges. The result is: // +// A = P * L * U, // +// where P is a permutation matrix, L is unit lower triangular, and U is // +// upper triangular. The factored form of A is used in combination with // +// 'lu_solve()' to solve linear equations: Ax = b, or invert a matrix. // +// // +// The inputs are a square matrix 'lu[N..n+N-1][N..n+N-1]', it's size is 'n'.// +// On output, 'lu' is replaced by the LU decomposition of a rowwise permuta- // +// tion of itself, 'ps[N..n+N-1]' is an output vector that records the row // +// permutation effected by the partial pivoting, effectively, 'ps' array // +// tells the user what the permutation matrix P is; 'd' is output as +1/-1 // +// depending on whether the number of row interchanges was even or odd, // +// respectively. // +// // +// Return true if the LU decomposition is successfully computed, otherwise, // +// return false in case that A is a singular matrix. // +// // +/////////////////////////////////////////////////////////////////////////////// + +bool tetgenmesh::lu_decmp(REAL lu[3][3], int n, int* ps, REAL* d, int N) +{ + REAL scales[3]; + REAL pivot, biggest, mult, tempf; + int pivotindex = 0; + int i, j, k; + + *d = 1.0; // No row interchanges yet. + + for (i = N; i < n + N; i++) { // For each row. + // Find the largest element in each row for row equilibration + biggest = 0.0; + for (j = N; j < n + N; j++) + if (biggest < (tempf = fabs(lu[i][j]))) + biggest = tempf; + if (biggest != 0.0) + scales[i] = 1.0 / biggest; + else { + scales[i] = 0.0; + return false; // Zero row: singular matrix. + } + ps[i] = i; // Initialize pivot sequence. + } + + for (k = N; k < n + N - 1; k++) { // For each column. + // Find the largest element in each column to pivot around. + biggest = 0.0; + for (i = k; i < n + N; i++) { + if (biggest < (tempf = fabs(lu[ps[i]][k]) * scales[ps[i]])) { + biggest = tempf; + pivotindex = i; + } + } + if (biggest == 0.0) { + return false; // Zero column: singular matrix. + } + if (pivotindex != k) { // Update pivot sequence. + j = ps[k]; + ps[k] = ps[pivotindex]; + ps[pivotindex] = j; + *d = -(*d); // ...and change the parity of d. + } + + // Pivot, eliminating an extra variable each time + pivot = lu[ps[k]][k]; + for (i = k + 1; i < n + N; i++) { + lu[ps[i]][k] = mult = lu[ps[i]][k] / pivot; + if (mult != 0.0) { + for (j = k + 1; j < n + N; j++) + lu[ps[i]][j] -= mult * lu[ps[k]][j]; + } + } + } + + // (lu[ps[n + N - 1]][n + N - 1] == 0.0) ==> A is singular. + return lu[ps[n + N - 1]][n + N - 1] != 0.0; +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// lu_solve() Solves the linear equation: Ax = b, after the matrix A // +// has been decomposed into the lower and upper triangular // +// matrices L and U, where A = LU. // +// // +// 'lu[N..n+N-1][N..n+N-1]' is input, not as the matrix 'A' but rather as // +// its LU decomposition, computed by the routine 'lu_decmp'; 'ps[N..n+N-1]' // +// is input as the permutation vector returned by 'lu_decmp'; 'b[N..n+N-1]' // +// is input as the right-hand side vector, and returns with the solution // +// vector. 'lu', 'n', and 'ps' are not modified by this routine and can be // +// left in place for successive calls with different right-hand sides 'b'. // +// // +/////////////////////////////////////////////////////////////////////////////// + +void tetgenmesh::lu_solve(REAL lu[3][3], int n, int* ps, REAL* b, int N) +{ + int i, j; + REAL X[3], dot; + + for (i = N; i < n + N; i++) X[i] = 0.0; + + // Vector reduction using U triangular matrix. + for (i = N; i < n + N; i++) { + dot = 0.0; + for (j = N; j < i + N; j++) + dot += lu[ps[i]][j] * X[j]; + X[i] = b[ps[i]] - dot; + } + + // Back substitution, in L triangular matrix. + for (i = n + N - 1; i >= N; i--) { + dot = 0.0; + for (j = i + 1; j < n + N; j++) + dot += lu[ps[i]][j] * X[j]; + X[i] = (X[i] - dot) / lu[ps[i]][i]; + } + + for (i = N; i < n + N; i++) b[i] = X[i]; +} + +// +// End of linear algebra functions +// + +// +// Begin of geometric tests +// + +// All the following routines require the input objects are not degenerate. +// i.e., a triangle must has three non-collinear corners; an edge must +// has two identical endpoints. Degenerate cases should have to detect +// first and then handled as special cases. + +/////////////////////////////////////////////////////////////////////////////// +// // +// edge_vertex_collinear_inter() Test whether an edge (ab) and a vertex // +// (p) are intersecting or not. // +// // +// p and ab are collinear. Possible cases are p is coincident to a (p = a), // +// or coincident to b (p = b), or inside ab (a < p < b), or outside ab (p < // +// a or p > b). These cases can be quickly determined by comparing the // +// homogeneous coordinates of a, b, and p (which are not all equal). // +// // +// The return value indicates one of the three cases: DISJOINT, SHAREVERTEX // +// (p = a or p = b), and INTERSECT (a < p < b). // +// // +/////////////////////////////////////////////////////////////////////////////// + +enum tetgenmesh::intersectresult tetgenmesh:: +edge_vertex_collinear_inter(REAL* A, REAL* B, REAL* P) +{ + int i = 0; + do { + if (A[i] < B[i]) { + if (P[i] < A[i]) { + return DISJOINT; + } else if (P[i] > A[i]) { + if (P[i] < B[i]) { + return INTERSECT; + } else if (P[i] > B[i]) { + return DISJOINT; + } else { + // assert(P[i] == B[i]); + return SHAREVERTEX; + } + } else { + // assert(P[i] == A[i]); + return SHAREVERTEX; + } + } else if (A[i] > B[i]) { + if (P[i] < B[i]) { + return DISJOINT; + } else if (P[i] > B[i]) { + if (P[i] < A[i]) { + return INTERSECT; + } else if (P[i] > A[i]) { + return DISJOINT; + } else { + // assert(P[i] == A[i]); + return SHAREVERTEX; + } + } else { + // assert(P[i] == B[i]); + return SHAREVERTEX; + } + } + // i-th coordinates are equal, try i+1-th; + i++; + } while (i < 3); + // Should never be here. + assert(i >= 3); + return DISJOINT; +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// edge_edge_coplanar_inter() Test whether two edges (ab) and (pq) are // +// intersecting or not. // +// // +// ab and pq are coplanar. Possible cases are ab and pq are disjointed, or // +// proper intersecting (intersect at a point other than their vertices), or // +// collinear and intersecting, or sharing at a vertex, or ab and pq are co- // +// incident (i.e., the same edge). // +// // +// A reference point R is required, which is exactly not coplanar with these // +// two edges. Since the caller know these two edges are coplanar, it must // +// be able to provide (or calculate) such a point. // +// // +// The return value indicates one of the four cases: DISJOINT, SHAREVERTEX, // +// SHAREEDGE, and INTERSECT. // +// // +/////////////////////////////////////////////////////////////////////////////// + +enum tetgenmesh::intersectresult tetgenmesh:: +edge_edge_coplanar_inter(REAL* A, REAL* B, REAL* P, REAL* Q, REAL* R) +{ + REAL s1, s2, s3, s4; + + assert(R != NULL); + + s1 = orient3d(A, B, R, P); + s2 = orient3d(A, B, R, Q); + if (s1 * s2 > 0.0) { + // Both p and q are at the same side of ab. + return DISJOINT; + } + s3 = orient3d(P, Q, R, A); + s4 = orient3d(P, Q, R, B); + if (s3 * s4 > 0.0) { + // Both a and b are at the same side of pq. + return DISJOINT; + } + + // Possible degenerate cases are: + // (1) Only one of p and q is collinear with ab; + // (2) Both p and q are collinear with ab; + // (3) Only one of a and b is collinear with pq. + enum intersectresult abp, abq; + enum intersectresult pqa, pqb; + + if (s1 == 0.0) { + // p is collinear with ab. + abp = edge_vertex_collinear_inter(A, B, P); + if (abp == INTERSECT) { + // p is inside ab. + return INTERSECT; + } + if (s2 == 0.0) { + // q is collinear with ab. Case (2). + abq = edge_vertex_collinear_inter(A, B, Q); + if (abq == INTERSECT) { + // q is inside ab. + return INTERSECT; + } + if (abp == SHAREVERTEX && abq == SHAREVERTEX) { + // ab and pq are identical. + return SHAREEDGE; + } + pqa = edge_vertex_collinear_inter(P, Q, A); + if (pqa == INTERSECT) { + // a is inside pq. + return INTERSECT; + } + pqb = edge_vertex_collinear_inter(P, Q, B); + if (pqb == INTERSECT) { + // b is inside pq. + return INTERSECT; + } + if (abp == SHAREVERTEX || abq == SHAREVERTEX) { + // either p or q is coincident with a or b. + // ONLY one case is possible, otherwise, shoule be SHAREEDGE. + assert(abp ^ abq); + return SHAREVERTEX; + } + // The last case. They are disjointed. + assert((abp == DISJOINT) && (abp == abq && abq == pqa && pqa == pqb)); + return DISJOINT; + } else { + // p is collinear with ab. Case (1). + assert(abp == SHAREVERTEX || abp == DISJOINT); + return abp; + } + } + // p is NOT collinear with ab. + if (s2 == 0.0) { + // q is collinear with ab. Case (1). + abq = edge_vertex_collinear_inter(A, B, Q); + assert(abq == SHAREVERTEX || abq == DISJOINT || abq == INTERSECT); + return abq; + } + + // We have found p and q are not collinear with ab. However, it is still + // possible that a or b is collinear with pq (ONLY one of a and b). + if (s3 == 0.0) { + // a is collinear with pq. Case (3). + assert(s4 != 0.0); + pqa = edge_vertex_collinear_inter(P, Q, A); + // This case should have been detected in above. + assert(pqa != SHAREVERTEX); + assert(pqa == INTERSECT || pqa == DISJOINT); + return pqa; + } + if (s4 == 0.0) { + // b is collinear with pq. Case (3). + assert(s3 != 0.0); + pqb = edge_vertex_collinear_inter(P, Q, B); + // This case should have been detected in above. + assert(pqb != SHAREVERTEX); + assert(pqb == INTERSECT || pqb == DISJOINT); + return pqb; + } + + // ab and pq are intersecting properly. + return INTERSECT; +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// Notations // +// // +// Let ABC be the plane passes through a, b, and c; ABC+ be the halfspace // +// including the set of all points x, such that orient3d(a, b, c, x) > 0; // +// ABC- be the other halfspace, such that for each point x in ABC-, // +// orient3d(a, b, c, x) < 0. For the set of x which are on ABC, orient3d(a, // +// b, c, x) = 0. // +// // +/////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// +// // +// triangle_vertex_coplanar_inter() Test whether a triangle (abc) and a // +// point (p) are intersecting or not. // +// // +// abc and p are coplanar. Possible cases are p is inside abc, or on an edge // +// of, or coincident with a vertex of, or outside abc. // +// // +// A reference point R is required, which is exactly not coplanar with the // +// triangle and the vertex. Since the caller know they are coplanar, it must // +// be able to provide (or calculate) such a point. // +// // +// The return value indicates one of the four cases: DISJOINT, SHAREVERTEX, // +// and INTERSECT. // +// // +/////////////////////////////////////////////////////////////////////////////// + +enum tetgenmesh::intersectresult tetgenmesh:: +triangle_vertex_coplanar_inter(REAL* A, REAL* B, REAL* C, REAL* P, REAL* R) +{ + REAL s1, s2, s3; + int sign; + + assert(R != (REAL *) NULL); + + // Adjust the orientation of a, b, c and r, so that we can assume that + // r is strictly in ABC- (i.e., r is above ABC wrt. right-hand rule). + s1 = orient3d(A, B, C, R); + assert(s1 != 0.0); + sign = s1 < 0.0 ? 1 : -1; + + // Test starts from here. + s1 = orient3d(A, B, R, P) * sign; + if (s1 < 0.0) { + // p is in ABR-. + return DISJOINT; + } + s2 = orient3d(B, C, R, P) * sign; + if (s2 < 0.0) { + // p is in BCR-. + return DISJOINT; + } + s3 = orient3d(C, A, R, P) * sign; + if (s3 < 0.0) { + // p is in CAR-. + return DISJOINT; + } + if (s1 == 0.0) { + // p is on ABR. + if (s2 == 0.0) { + // p is on BCR. + assert(s3 > 0.0); + // p is coincident with b. + return SHAREVERTEX; + } + if (s3 == 0.0) { + // p is on CAR. + // p is coincident with a. + return SHAREVERTEX; + } + // p is on edge ab. + return INTERSECT; + } + // p is in ABR+. + if (s2 == 0.0) { + // p is on BCR. + if (s3 == 0.0) { + // p is on CAR. + // p is coincident with c. + return SHAREVERTEX; + } + // p is on edge bc. + return INTERSECT; + } + if (s3 == 0.0) { + // p is on CAR. + // p is on edge ca. + return INTERSECT; + } + + // p is strictly inside abc. + return INTERSECT; +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// triangle_edge_coplanar_inter() Test whether a triangle (abc) and an // +// edge (pq) are intersecting or not. // +// // +// A reference point R is required, which is exactly not coplanar with the // +// triangle and the edge. Since the caller know they are coplanar, it must // +// be able to provide (or calculate) such a point. // +// // +// The return value indicates one of the four cases: DISJOINT, SHAREVERTEX, // +// SHAREEDGE, and INTERSECT. // +// // +/////////////////////////////////////////////////////////////////////////////// + +enum tetgenmesh::intersectresult tetgenmesh:: +triangle_edge_coplanar_inter(REAL* A, REAL* B, REAL* C, REAL* P, REAL* Q, + REAL* R) +{ + enum intersectresult abpq, bcpq, capq; + enum intersectresult abcp, abcq; + + // Test if pq is intersecting one of edges of abc. + abpq = edge_edge_coplanar_inter(A, B, P, Q, R); + if (abpq == INTERSECT || abpq == SHAREEDGE) { + return abpq; + } + bcpq = edge_edge_coplanar_inter(B, C, P, Q, R); + if (bcpq == INTERSECT || bcpq == SHAREEDGE) { + return bcpq; + } + capq = edge_edge_coplanar_inter(C, A, P, Q, R); + if (capq == INTERSECT || capq == SHAREEDGE) { + return capq; + } + + // Test if p and q is inside abc. + abcp = triangle_vertex_coplanar_inter(A, B, C, P, R); + if (abcp == INTERSECT) { + return INTERSECT; + } + abcq = triangle_vertex_coplanar_inter(A, B, C, Q, R); + if (abcq == INTERSECT) { + return INTERSECT; + } + + // Combine the test results of edge intersectings and triangle insides + // to detect whether abc and pq are sharing vertex or disjointed. + if (abpq == SHAREVERTEX) { + // p or q is coincident with a or b. + assert(abcp ^ abcq); + return SHAREVERTEX; + } + if (bcpq == SHAREVERTEX) { + // p or q is coincident with b or c. + assert(abcp ^ abcq); + return SHAREVERTEX; + } + if (capq == SHAREVERTEX) { + // p or q is coincident with c or a. + assert(abcp ^ abcq); + return SHAREVERTEX; + } + + // They are disjointed. + return DISJOINT; +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// triangle_edge_inter_tail() Test whether a triangle (abc) and an edge // +// (pq) are intersecting or not. // +// // +// s1 and s2 are results of pre-performed orientation tests. s1 = orient3d( // +// a, b, c, p); s2 = orient3d(a, b, c, q). // +// // +// To separate this routine from triangle_edge_inter() can save two // +// orientation tests in triangle_triangle_inter(). // +// // +// The return value indicates one of the four cases: DISJOINT, SHAREVERTEX, // +// SHAREEDGE, and INTERSECT. // +// // +/////////////////////////////////////////////////////////////////////////////// + +enum tetgenmesh::intersectresult tetgenmesh:: +triangle_edge_inter_tail(REAL* A, REAL* B, REAL* C, REAL* P, REAL* Q, REAL s1, + REAL s2) +{ + REAL s3, s4, s5; + int sign; + + if (s1 * s2 > 0.0) { + // p, q are at the same halfspace of ABC, no intersection. + return DISJOINT; + } + + if (s1 * s2 < 0.0) { + // p, q are both not on ABC (and not sharing vertices, edges of abc). + // Adjust the orientation of a, b, c and p, so that we can assume that + // p is strictly in ABC-, and q is strictly in ABC+. + sign = s1 < 0.0 ? 1 : -1; + s3 = orient3d(A, B, P, Q) * sign; + if (s3 < 0.0) { + // q is at ABP-. + return DISJOINT; + } + s4 = orient3d(B, C, P, Q) * sign; + if (s4 < 0.0) { + // q is at BCP-. + return DISJOINT; + } + s5 = orient3d(C, A, P, Q) * sign; + if (s5 < 0.0) { + // q is at CAP-. + return DISJOINT; + } + if (s3 == 0.0) { + // q is on ABP. + if (s4 == 0.0) { + // q is on BCP (and q must in CAP+). + assert(s5 > 0.0); + // pq intersects abc at vertex b. + return SHAREVERTEX; + } + if (s5 == 0.0) { + // q is on CAP (and q must in BCP+). + // pq intersects abc at vertex a. + return SHAREVERTEX; + } + // q in both BCP+ and CAP+. + // pq crosses ab properly. + return INTERSECT; + } + // q is in ABP+; + if (s4 == 0.0) { + // q is on BCP. + if (s5 == 0.0) { + // q is on CAP. + // pq intersects abc at vertex c. + return SHAREVERTEX; + } + // pq crosses bc properly. + return INTERSECT; + } + // q is in BCP+; + if (s5 == 0.0) { + // q is on CAP. + // pq crosses ca properly. + return INTERSECT; + } + // q is in CAP+; + // pq crosses abc properly. + return INTERSECT; + } + + if (s1 != 0.0 || s2 != 0.0) { + // Either p or q is coplanar with abc. ONLY one of them is possible. + if (s1 == 0.0) { + // p is coplanar with abc, q can be used as reference point. + assert(s2 != 0.0); + return triangle_vertex_coplanar_inter(A, B, C, P, Q); + } else { + // q is coplanar with abc, p can be used as reference point. + assert(s2 == 0.0); + return triangle_vertex_coplanar_inter(A, B, C, Q, P); + } + } + + // pq is coplanar with abc. Calculate a point which is exactly + // non-coplanar with a, b, and c. + REAL R[3], N[3]; + REAL ax, ay, az, bx, by, bz; + + ax = A[0] - B[0]; + ay = A[1] - B[1]; + az = A[2] - B[2]; + bx = A[0] - C[0]; + by = A[1] - C[1]; + bz = A[2] - C[2]; + N[0] = ay * bz - by * az; + N[1] = az * bx - bz * ax; + N[2] = ax * by - bx * ay; + // The normal should not be a zero vector. + assert((fabs(N[0]) + fabs(N[1]) + fabs(N[2])) > 0.0); + // The reference point R is lifted from A to the normal direction with + // a non-zero distance. + R[0] = N[0] + A[0]; + R[1] = N[1] + A[1]; + R[2] = N[2] + A[2]; + // Becareful the case: if the non-zero component(s) in N is smaller than + // the machine epsilon (i.e., 2^(-16) for double), R will exactly equal + // to A due to the round-off error. Do check if it is. + if (R[0] == A[0] && R[1] == A[1] && R[2] == A[2]) { + int i, j; + for (i = 0; i < 3; i++) { + assert (R[i] == A[i]); + j = 2; + do { + if (N[i] > 0.0) { + N[i] += (j * macheps); + } else { + N[i] -= (j * macheps); + } + R[i] = N[i] + A[i]; + j *= 2; + } while (R[i] == A[i]); + } + } + + return triangle_edge_coplanar_inter(A, B, C, P, Q, R); +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// triangle_edge_inter() Test whether a triangle (abc) and an edge (pq) // +// are intersecting or not. // +// // +// The return value indicates one of the four cases: DISJOINT, SHAREVERTEX, // +// SHAREEDGE, and INTERSECT. // +// // +/////////////////////////////////////////////////////////////////////////////// + +enum tetgenmesh::intersectresult tetgenmesh:: +triangle_edge_inter(REAL* A, REAL* B, REAL* C, REAL* P, REAL* Q) +{ + REAL s1, s2; + + // Test the locations of p and q with respect to ABC. + s1 = orient3d(A, B, C, P); + s2 = orient3d(A, B, C, Q); + + return triangle_edge_inter_tail(A, B, C, P, Q, s1, s2); +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// triangle_triangle_inter() Test whether two triangle (abc) and (opq) // +// are intersecting or not. // +// // +// The return value indicates one of the five cases: DISJOINT, SHAREVERTEX, // +// SHAREEDGE, SHAREFACE, and INTERSECT. // +// // +/////////////////////////////////////////////////////////////////////////////// + +enum tetgenmesh::intersectresult tetgenmesh:: +triangle_triangle_inter(REAL* A, REAL* B, REAL* C, REAL* O, REAL* P, REAL* Q) +{ + REAL s_o, s_p, s_q; + REAL s_a, s_b, s_c; + + s_o = orient3d(A, B, C, O); + s_p = orient3d(A, B, C, P); + s_q = orient3d(A, B, C, Q); + if ((s_o * s_p > 0.0) && (s_o * s_q > 0.0)) { + // o, p, q are all in the same halfspace of ABC. + return DISJOINT; + } + + s_a = orient3d(O, P, Q, A); + s_b = orient3d(O, P, Q, B); + s_c = orient3d(O, P, Q, C); + if ((s_a * s_b > 0.0) && (s_a * s_c > 0.0)) { + // a, b, c are all in the same halfspace of OPQ. + return DISJOINT; + } + + enum intersectresult abcop, abcpq, abcqo; + int shareedge = 0; + + abcop = triangle_edge_inter_tail(A, B, C, O, P, s_o, s_p); + if (abcop == INTERSECT) { + return INTERSECT; + } else if (abcop == SHAREEDGE) { + shareedge++; + } + abcpq = triangle_edge_inter_tail(A, B, C, P, Q, s_p, s_q); + if (abcpq == INTERSECT) { + return INTERSECT; + } else if (abcpq == SHAREEDGE) { + shareedge++; + } + abcqo = triangle_edge_inter_tail(A, B, C, Q, O, s_q, s_o); + if (abcqo == INTERSECT) { + return INTERSECT; + } else if (abcqo == SHAREEDGE) { + shareedge++; + } + if (shareedge == 3) { + // opq are coincident with abc. + return SHAREFACE; + } + // It is only possible either no share edge or one. + assert(shareedge == 0 || shareedge == 1); + + // Continue to detect whether opq and abc are intersecting or not. + enum intersectresult opqab, opqbc, opqca; + + opqab = triangle_edge_inter_tail(O, P, Q, A, B, s_a, s_b); + if (opqab == INTERSECT) { + return INTERSECT; + } + opqbc = triangle_edge_inter_tail(O, P, Q, B, C, s_b, s_c); + if (opqbc == INTERSECT) { + return INTERSECT; + } + opqca = triangle_edge_inter_tail(O, P, Q, C, A, s_c, s_a); + if (opqca == INTERSECT) { + return INTERSECT; + } + + // At this point, two triangles are not intersecting and not coincident. + // They may be share an edge, or share a vertex, or disjoint. + if (abcop == SHAREEDGE) { + assert(abcpq == SHAREVERTEX && abcqo == SHAREVERTEX); + // op is coincident with an edge of abc. + return SHAREEDGE; + } + if (abcpq == SHAREEDGE) { + assert(abcop == SHAREVERTEX && abcqo == SHAREVERTEX); + // pq is coincident with an edge of abc. + return SHAREEDGE; + } + if (abcqo == SHAREEDGE) { + assert(abcop == SHAREVERTEX && abcpq == SHAREVERTEX); + // qo is coincident with an edge of abc. + return SHAREEDGE; + } + + // They may share a vertex or disjoint. + if (abcop == SHAREVERTEX) { + // o or p is coincident with a vertex of abc. + if (abcpq == SHAREVERTEX) { + // p is the coincident vertex. + assert(abcqo != SHAREVERTEX); + } else { + // o is the coincident vertex. + assert(abcqo == SHAREVERTEX); + } + return SHAREVERTEX; + } + if (abcpq == SHAREVERTEX) { + // q is the coincident vertex. + assert(abcqo == SHAREVERTEX); + return SHAREVERTEX; + } + + // They are disjoint. + return DISJOINT; +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// iscollinear() Check if three points are collinear with respect to a // +// given relative tolerance. // +// // +// 'epspp' is the relative tolerance provided by caller. The collinearity is // +// determined by evaluating the angle q between the two vectors formed from // +// thes three points. If q <= epspp, then they are assumed be collinear. // +// // +/////////////////////////////////////////////////////////////////////////////// + +bool tetgenmesh::iscollinear(REAL* A, REAL* B, REAL* C, REAL epspp) +{ + REAL V[3], W[3]; + REAL Lv, Lw, d, q; + + V[0] = A[0] - B[0]; + V[1] = A[1] - B[1]; + V[2] = A[2] - B[2]; + W[0] = A[0] - C[0]; + W[1] = A[1] - C[1]; + W[2] = A[2] - C[2]; + Lv = sqrt(V[0] * V[0] + V[1] * V[1] + V[2] * V[2]); + Lw = sqrt(W[0] * W[0] + W[1] * W[1] + W[2] * W[2]); + + d = (V[0] * W[0] + V[1] * W[1] + V[2] * W[2]) / (Lv * Lw); + if (d > 1.0) { + q = 0.0; + } else if (d < -1.0) { + q = 0.0; // q = PI; + } else { + q = acos(fabs(d)); + } + + return q <= epspp; +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// iscoplanar() Check if four points are coplanar with respect to a given // +// relative tolerance. // +// // +// 'vol6' is the six times of the signed volume of the tetrahedron formed by // +// the four points. 'epspp' is the relative tolerance provided by the caller.// +// This coplanarity is determined by evaluating the value: // +// // +// q = fabs(vol6) / L^3 // +// // +// where L is the average edge length of the tetrahedron. If q <= epspp, // +// then these four points are assumed be coplanar. // +// // +/////////////////////////////////////////////////////////////////////////////// + +bool tetgenmesh:: +iscoplanar(REAL* k, REAL* l, REAL* m, REAL* n, REAL vol6, REAL epspp) +{ + REAL L, q; + REAL x, y, z; + + x = k[0] - l[0]; + y = k[1] - l[1]; + z = k[2] - l[2]; + L = sqrt(x * x + y * y + z * z); + x = l[0] - m[0]; + y = l[1] - m[1]; + z = l[2] - m[2]; + L += sqrt(x * x + y * y + z * z); + x = m[0] - k[0]; + y = m[1] - k[1]; + z = m[2] - k[2]; + L += sqrt(x * x + y * y + z * z); + x = k[0] - n[0]; + y = k[1] - n[1]; + z = k[2] - n[2]; + L += sqrt(x * x + y * y + z * z); + x = l[0] - n[0]; + y = l[1] - n[1]; + z = l[2] - n[2]; + L += sqrt(x * x + y * y + z * z); + x = m[0] - n[0]; + y = m[1] - n[1]; + z = m[2] - n[2]; + L += sqrt(x * x + y * y + z * z); + assert(L > 0.0); + L /= 6.0; + q = fabs(vol6) / (L * L * L); + + return q <= epspp; +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// iscospheric() Check if five points are coplanar with respect to a // +// given relative tolerance. // +// // +// The cosphere is determined by comparing the distance between the radius R // +// of the circumsphere S of the first four points and the distance from the // +// circumcenter C of S to the fifth points P, i.e., to calculate the value: // +// // +// q = fabs(P - C) / R // +// // +// If q <= epspp, then these five points are assumed to be cospherical. // +// // +/////////////////////////////////////////////////////////////////////////////// + +bool tetgenmesh:: +iscospheric(REAL* k, REAL* l, REAL* m, REAL* n, REAL* o, REAL epspp) +{ + REAL ori, *p5; + REAL cent[3], R, D, q; + + ori = orient3d(k, l, m, n); + if (iscoplanar(k, l, m, n, ori, epspp)) { + ori = orient3d(k, l, m, o); + assert(!iscoplanar(k, l, m, o, ori, epspp)); + circumsphere(k, l, m, o, cent, &R); + p5 = n; + } else { + circumsphere(k, l, m, n, cent, &R); + p5 = o; + } + D = distance(p5, cent); + q = fabs(D - R) / R; + + return q <= epspp; +} + +// +// End of geometric tests +// + +// +// Begin of Geometric quantities calculators +// + +// distance() computs the Euclidean distance between two points. +inline REAL tetgenmesh::distance(REAL* p1, REAL* p2) +{ + return sqrt((p2[0] - p1[0]) * (p2[0] - p1[0]) + + (p2[1] - p1[1]) * (p2[1] - p1[1]) + + (p2[2] - p1[2]) * (p2[2] - p1[2])); +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// shortdistance() Returns the shortest distance from point p to a line // +// defined by two points e1 and e2. // +// // +// First compute the projection length l_p of the vector v1 = p - e1 along // +// the vector v2 = e2 - e1. Then Pythagoras' Theorem is used to compute the // +// shortest distance. // +// // +// This routine allows that p is collinear with the line. In this case, the // +// return value is zero. The two points e1 and e2 should not be identical. // +// // +/////////////////////////////////////////////////////////////////////////////// + +REAL tetgenmesh::shortdistance(REAL* p, REAL* e1, REAL* e2) +{ + REAL v1[3], v2[3]; + REAL len, l_p; + + v1[0] = e2[0] - e1[0]; + v1[1] = e2[1] - e1[1]; + v1[2] = e2[2] - e1[2]; + v2[0] = p[0] - e1[0]; + v2[1] = p[1] - e1[1]; + v2[2] = p[2] - e1[2]; + + len = sqrt(dot(v1, v1)); + assert(len != 0.0); + v1[0] /= len; + v1[1] /= len; + v1[2] /= len; + l_p = dot(v1, v2); + + return sqrt(dot(v2, v2) - l_p * l_p); +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// interiorangle() Return the interior angle (0 - 2 * PI) between vectors // +// o->p1 and o->p2. // +// // +// 'n' is the normal of the plane containing face (o, p1, p2). The interior // +// angle is the total angle rotating from o->p1 around n to o->p2. Exchange // +// the position of p1 and p2 will get the complement angle of the other one. // +// i.e., interiorangle(o, p1, p2) = 2 * PI - interiorangle(o, p2, p1). Set // +// 'n' be NULL if you only want the interior angle between 0 - PI. // +// // +/////////////////////////////////////////////////////////////////////////////// + +REAL tetgenmesh::interiorangle(REAL* o, REAL* p1, REAL* p2, REAL* n) +{ + REAL v1[3], v2[3], np[3]; + REAL theta, costheta, lenlen; + REAL ori, len1, len2; + + // Get the interior angle (0 - PI) between o->p1, and o->p2. + v1[0] = p1[0] - o[0]; + v1[1] = p1[1] - o[1]; + v1[2] = p1[2] - o[2]; + v2[0] = p2[0] - o[0]; + v2[1] = p2[1] - o[1]; + v2[2] = p2[2] - o[2]; + len1 = sqrt(dot(v1, v1)); + len2 = sqrt(dot(v2, v2)); + lenlen = len1 * len2; + assert(lenlen != 0.0); + costheta = dot(v1, v2) / lenlen; + if (costheta > 1.0) { + costheta = 1.0; // Roundoff. + } else if (costheta < -1.0) { + costheta = -1.0; // Roundoff. + } + theta = acos(costheta); + if (n != NULL) { + // Get a point above the face (o, p1, p2); + np[0] = o[0] + n[0]; + np[1] = o[1] + n[1]; + np[2] = o[2] + n[2]; + // Adjust theta (0 - 2 * PI). + ori = orient3d(p1, o, np, p2); + if (ori > 0.0) { + theta = 2 * PI - theta; + } + } + + return theta; +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// projpt2edge() Return the projection point from a point to an edge. // +// // +/////////////////////////////////////////////////////////////////////////////// + +void tetgenmesh::projpt2edge(REAL* p, REAL* e1, REAL* e2, REAL* prj) +{ + REAL v1[3], v2[3]; + REAL len, l_p; + + v1[0] = e2[0] - e1[0]; + v1[1] = e2[1] - e1[1]; + v1[2] = e2[2] - e1[2]; + v2[0] = p[0] - e1[0]; + v2[1] = p[1] - e1[1]; + v2[2] = p[2] - e1[2]; + + len = sqrt(dot(v1, v1)); + assert(len != 0.0); + v1[0] /= len; + v1[1] /= len; + v1[2] /= len; + l_p = dot(v1, v2); + + prj[0] = e1[0] + l_p * v1[0]; + prj[1] = e1[1] + l_p * v1[1]; + prj[2] = e1[2] + l_p * v1[2]; +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// projpt2face() Return the projection point from a point to a face. // +// // +/////////////////////////////////////////////////////////////////////////////// + +void tetgenmesh::projpt2face(REAL* p, REAL* f1, REAL* f2, REAL* f3, REAL* prj) +{ + REAL fnormal[3], v1[3]; + REAL len, dist; + + // Get the unit face normal. + facenormal(f1, f2, f3, fnormal, &len); + assert(len > 0.0); + fnormal[0] /= len; + fnormal[1] /= len; + fnormal[2] /= len; + // Get the vector v1 = |p - f1|. + v1[0] = p[0] - f1[0]; + v1[1] = p[1] - f1[1]; + v1[2] = p[2] - f1[2]; + // Get the project distance. + dist = dot(fnormal, v1); + assert(fabs(dist) >= b->epsilon); + + // Get the project point. + prj[0] = p[0] - dist * fnormal[0]; + prj[1] = p[1] - dist * fnormal[1]; + prj[2] = p[2] - dist * fnormal[2]; +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// facenormal() Calculate the normal of a face given by three points. // +// // +/////////////////////////////////////////////////////////////////////////////// + +void tetgenmesh::facenormal(REAL* pa, REAL* pb, REAL* pc, REAL* n, REAL* nlen) +{ + REAL v1[3], v2[3]; + + v1[0] = pb[0] - pa[0]; + v1[1] = pb[1] - pa[1]; + v1[2] = pb[2] - pa[2]; + v2[0] = pc[0] - pa[0]; + v2[1] = pc[1] - pa[1]; + v2[2] = pc[2] - pa[2]; + + cross(v1, v2, n); + if (nlen != (REAL *) NULL) { + *nlen = sqrt(dot(n, n)); + } +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// edgeorthonormal() Return the unit normal of an edge in a given plane. // +// // +// The edge is from e1 to e2, the plane is defined by given an additional // +// point op, which is non-collinear with the edge. In addition, the side of // +// the edge in which op lies defines the positive position of the normal. // +// // +// Let v1 be the unit vector from e1 to e2, v2 be the unit edge vector from // +// e1 to op, fn be the unit face normal calculated by fn = v1 x v2. Then the // +// unit edge normal of e1e2 pointing to op is n = fn x v1. Note, we should // +// not change the position of fn and v1, otherwise, we get the edge normal // +// pointing to the other side of op. // +// // +/////////////////////////////////////////////////////////////////////////////// + +void tetgenmesh::edgeorthonormal(REAL* e1, REAL* e2, REAL* op, REAL* n) +{ + REAL v1[3], v2[3], fn[3]; + REAL len; + + // Get the edge vector v1. + v1[0] = e2[0] - e1[0]; + v1[1] = e2[1] - e1[1]; + v1[2] = e2[2] - e1[2]; + // Get the edge vector v2. + v2[0] = op[0] - e1[0]; + v2[1] = op[1] - e1[1]; + v2[2] = op[2] - e1[2]; + // Get the face normal fn = v1 x v2. + cross(v1, v2, fn); + // Get the edge normal n pointing to op. n = fn x v1. + cross(fn, v1, n); + // Normalize the vector. + len = sqrt(dot(n, n)); + n[0] /= len; + n[1] /= len; + n[2] /= len; +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// facedihedral() Return the dihedral angle (in radian) between two // +// adjoining faces. // +// // +// 'pa', 'pb' are the shared edge of these two faces, 'pc1', and 'pc2' are // +// apexes of these two faces. Return the angle (between 0 to 2*pi) between // +// the normal of face (pa, pb, pc1) and normal of face (pa, pb, pc2). // +// // +/////////////////////////////////////////////////////////////////////////////// + +REAL tetgenmesh::facedihedral(REAL* pa, REAL* pb, REAL* pc1, REAL* pc2) +{ + REAL n1[3], n2[3]; + REAL n1len, n2len; + REAL costheta, ori; + REAL theta; + + facenormal(pa, pb, pc1, n1, &n1len); + facenormal(pa, pb, pc2, n2, &n2len); + costheta = dot(n1, n2) / (n1len * n2len); + theta = acos(costheta); + ori = orient3d(pa, pb, pc1, pc2); + if (ori > 0.0) { + theta = 2 * PI - theta; + } + + return theta; +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// tetalldihedral() Get all(six) dihedral angles in tetrahedron formed by // +// vertices a, b, c and d. Return by array adDihed[6]. // +// // +// The order in which the dihedrals are assigned matters for computation of // +// solid angles. The way they're currently set up, combining them as (0,1,2),// +// (0,3,4), (1,3,5), (2,4,5) gives (in order) solid angles at vertices a, b, // +// c and d. // +// // +/////////////////////////////////////////////////////////////////////////////// + +void tetgenmesh:: +tetalldihedral(point pa, point pb, point pc, point pd, REAL dihed[6]) +{ + REAL n0[3], n1[3], n2[3], n3[3]; + REAL n0len, n1len, n2len, n3len; + REAL dotp; + + facenormal(pc, pb, pd, n0, &n0len); + facenormal(pa, pc, pd, n1, &n1len); + facenormal(pb, pa, pd, n2, &n2len); + facenormal(pa, pb, pc, n3, &n3len); + + n0[0] /= n0len; n0[1] /= n0len; n0[2] /= n0len; + n1[0] /= n1len; n1[1] /= n1len; n1[2] /= n1len; + n2[0] /= n2len; n2[1] /= n2len; n2[2] /= n2len; + n3[0] /= n3len; n3[1] /= n3len; n3[2] /= n3len; + + dotp = -dot(n0, n1); + if (dotp > 1.) dotp = 1.; + else if (dotp < -1.) dotp = -1.; + dihed[5] = acos(dotp); // Edge CD + + dotp = -dot(n0, n2); + if (dotp > 1.) dotp = 1.; + else if (dotp < -1.) dotp = -1.; + dihed[4] = acos(dotp); // Edge BD + + dotp = -dot(n0, n3); + if (dotp > 1.) dotp = 1.; + else if (dotp < -1.) dotp = -1.; + dihed[3] = acos(dotp); // Edge BC + + dotp = -dot(n1, n2); + if (dotp > 1.) dotp = 1.; + else if (dotp < -1.) dotp = -1.; + dihed[2] = acos(dotp); // Edge AD + + dotp = -dot(n1, n3); + if (dotp > 1.) dotp = 1.; + else if (dotp < -1.) dotp = -1.; + dihed[1] = acos(dotp); // Edge AC + + dotp = -dot(n2, n3); + if (dotp > 1.) dotp = 1.; + else if (dotp < -1.) dotp = -1.; + dihed[0] = acos(dotp); // Edge AB +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// circumsphere() Calculate the smallest circumsphere (center and radius) // +// of the given three or four points. // +// // +// The circumsphere of four points (a tetrahedron) is unique if they are not // +// degenerate. If 'pd = NULL', the smallest circumsphere of three points is // +// the diametral sphere of the triangle if they are not degenerate. // +// // +// Return TRUE if the input points are not degenerate and the circumcenter // +// and circumradius are returned in 'cent' and 'radius' respectively if they // +// are not NULLs. Otherwise, return FALSE indicated the points are degenrate.// +// // +/////////////////////////////////////////////////////////////////////////////// + +bool tetgenmesh:: +circumsphere(REAL* pa, REAL* pb, REAL* pc, REAL* pd, REAL* cent, REAL* radius) +{ + REAL A[3][3], rhs[3], D; + int indx[3]; + + // Compute the coefficient matrix A (3x3). + A[0][0] = pb[0] - pa[0]; + A[0][1] = pb[1] - pa[1]; + A[0][2] = pb[2] - pa[2]; + A[1][0] = pc[0] - pa[0]; + A[1][1] = pc[1] - pa[1]; + A[1][2] = pc[2] - pa[2]; + if (pd != NULL) { + A[2][0] = pd[0] - pa[0]; + A[2][1] = pd[1] - pa[1]; + A[2][2] = pd[2] - pa[2]; + } else { + cross(A[0], A[1], A[2]); + } + + // Compute the right hand side vector b (3x1). + rhs[0] = 0.5 * dot(A[0], A[0]); + rhs[1] = 0.5 * dot(A[1], A[1]); + if (pd != NULL) { + rhs[2] = 0.5 * dot(A[2], A[2]); + } else { + rhs[2] = 0.0; + } + + // Solve the 3 by 3 equations use LU decomposition with partial pivoting + // and backward and forward substitute.. + if (!lu_decmp(A, 3, indx, &D, 0)) { + if (radius != (REAL *) NULL) *radius = 0.0; + return false; + } + lu_solve(A, 3, indx, rhs, 0); + if (cent != (REAL *) NULL) { + cent[0] = pa[0] + rhs[0]; + cent[1] = pa[1] + rhs[1]; + cent[2] = pa[2] + rhs[2]; + } + if (radius != (REAL *) NULL) { + *radius = sqrt(rhs[0] * rhs[0] + rhs[1] * rhs[1] + rhs[2] * rhs[2]); + } + return true; +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// inscribedsphere() Compute the radius and center of the biggest // +// inscribed sphere of a given tetrahedron. // +// // +// The tetrahedron is given by its four points, it must not be degenerate. // +// The center and radius are returned in 'cent' and 'radius' respectively if // +// they are not NULLs. // +// // +// Geometrical fact. For any simplex in d dimension, // +// r/h1 + r/h2 + ... r/hn = 1 (n <= d + 1); // +// where r is the radius of inscribed ball, and h is the height of each side // +// of the simplex. The value of 'r/h' is just the barycenter coordinates of // +// each vertex of the simplex. Therefore, we can compute the radius and // +// center of the smallest inscribed ball as following equations: // +// r = 1.0 / (1/h1 + 1/h2 + ... + 1/hn); (1) // +// C = r/h1 * P1 + r/h2 * P2 + ... + r/hn * Pn; (2) // +// where C is the vector of center, P1, P2, .. Pn are vectors of vertices. // +// Here (2) contains n linear equations with n variables. (h, P) must be a // +// pair, h is the height from P to its opposite face. // +// // +/////////////////////////////////////////////////////////////////////////////// + +void tetgenmesh:: +inscribedsphere(REAL* pa, REAL* pb, REAL* pc, REAL* pd, REAL* cent, + REAL* radius) +{ + REAL A[3][3], rhs[3], D; + REAL N[3][4], H[4]; // Normals (colume vectors) and heights of each face. + REAL rd; + int indx[3], i, j; + + // Compute the normals of 4 faces. + A[0][0] = pa[0] - pd[0]; + A[0][1] = pa[1] - pd[1]; + A[0][2] = pa[2] - pd[2]; + A[1][0] = pb[0] - pd[0]; + A[1][1] = pb[1] - pd[1]; + A[1][2] = pb[2] - pd[2]; + A[2][0] = pc[0] - pd[0]; + A[2][1] = pc[1] - pd[1]; + A[2][2] = pc[2] - pd[2]; + // Compute inverse of matrix A, to get the 3 normals of 4 faces. + lu_decmp(A, 3, indx, &D, 0); // Decompose the matrix just once. + for (j = 0; j < 3; j++) { + for (i = 0; i < 3; i++) rhs[i] = 0.0; + rhs[j] = -1.0; + lu_solve(A, 3, indx, rhs, 0); + for (i = 0; i < 3; i++) N[i][j] = rhs[i]; + } + // Compute the last normal by summing 3 computed vectors, because sum over + // a closed sufrace is 0. + N[0][3] = - N[0][0] - N[0][1] - N[0][2]; + N[1][3] = - N[1][0] - N[1][1] - N[1][2]; + N[2][3] = - N[2][0] - N[2][1] - N[2][2]; + // Compute the length of normals. + for (i = 0; i < 4; i++) { + // H[i] is the inverse of height of its corresponding face. + H[i] = sqrt(N[0][i] * N[0][i] + N[1][i] * N[1][i] + N[2][i] * N[2][i]); + } + // Compute the radius use eq. (1). + rd = 1.0 / (H[0] + H[1] + H[2] + H[3]); + if (radius != (REAL*) NULL) *radius = rd; + if (cent != (REAL*) NULL) { + // Compute the center use eq. (2). + cent[0] = rd * (H[0] * pa[0] + H[1] * pb[0] + H[2] * pc[0] + H[3] * pd[0]); + cent[1] = rd * (H[0] * pa[1] + H[1] * pb[1] + H[2] * pc[1] + H[3] * pd[1]); + cent[2] = rd * (H[0] * pa[2] + H[1] * pb[2] + H[2] * pc[2] + H[3] * pd[2]); + } +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// rotatepoint() Create a point by rotating an existing point. // +// // +// Create a 3D point by rotating point 'p' with an angle 'rotangle' (in arc // +// degree) around a rotating axis given by a vector from point 'p1' to 'p2'. // +// The rotation is according with right-hand rule, i.e., use your right-hand // +// to grab the axis with your thumber pointing to its positive direction, // +// your fingers indicate the rotating direction. // +// // +// The rotating steps are the following: // +// 1. Translate vector 'p1->p2' to origin, M1; // +// 2. Rotate vector around the Y-axis until it lies in the YZ plane, M2; // +// 3. Rotate vector around the X-axis until it lies on the Z axis, M3; // +// 4. Perform the rotation of 'p' around the z-axis, M4; // +// 5. Undo Step 3, M5; // +// 6. Undo Step 2, M6; // +// 7. Undo Step 1, M7; // +// Use matrix multiplication to combine the above sequences, we get: // +// p0' = T * p0, where T = M7 * M6 * M5 * M4 * M3 * M2 * M1 // +// // +/////////////////////////////////////////////////////////////////////////////// + +void tetgenmesh::rotatepoint(REAL* p, REAL rotangle, REAL* p1, REAL* p2) +{ + REAL T[4][4], pp0[4], p0t[4], p2t[4]; + REAL roty, rotx, alphaR, projlen; + REAL dx, dy, dz; + + initm44(1, 0, 0, -p1[0], + 0, 1, 0, -p1[1], + 0, 0, 1, -p1[2], + 0, 0, 0, 1, T); + pp0[0] = p[0]; pp0[1] = p[1]; pp0[2] = p[2]; pp0[3] = 1.0; + m4xv4(p0t, T, pp0); // Step 1 + pp0[0] = p2[0]; pp0[1] = p2[1]; pp0[2] = p2[2]; pp0[3] = 1.0; + m4xv4(p2t, T, pp0); // Step 1 + + // Get the rotation angle around y-axis; + dx = p2t[0]; + dz = p2t[2]; + projlen = sqrt(dx * dx + dz * dz); + if (projlen <= (b->epsilon * 1e-2) * longest) { + roty = 0; + } else { + roty = acos(dz / projlen); + if (dx < 0) { + roty = -roty; + } + } + + initm44(cos(-roty), 0, sin(-roty), 0, + 0, 1, 0, 0, + -sin(-roty), 0, cos(-roty), 0, + 0, 0, 0, 1, T); + pp0[0] = p0t[0]; pp0[1] = p0t[1]; pp0[2] = p0t[2]; pp0[3] = 1.0; + m4xv4(p0t, T, pp0); // Step 2 + pp0[0] = p2t[0]; pp0[1] = p2t[1]; pp0[2] = p2t[2]; pp0[3] = 1.0; + m4xv4(p2t, T, pp0); // Step 2 + + // Get the rotation angle around x-axis + dy = p2t[1]; + dz = p2t[2]; + projlen = sqrt(dy * dy + dz * dz); + if (projlen <= (b->epsilon * 1e-2) * longest) { + rotx = 0; + } else { + rotx = acos(dz / projlen); + if (dy < 0) { + rotx = -rotx; + } + } + + initm44(1, 0, 0, 0, + 0, cos(rotx), -sin(rotx), 0, + 0, sin(rotx), cos(rotx), 0, + 0, 0, 0, 1, T); + pp0[0] = p0t[0]; pp0[1] = p0t[1]; pp0[2] = p0t[2]; pp0[3] = 1.0; + m4xv4(p0t, T, pp0); // Step 3 + // pp0[0] = p2t[0]; pp0[1] = p2t[1]; pp0[2] = p2t[2]; pp0[3] = 1.0; + // m4xv4(p2t, T, pp0); // Step 3 + + alphaR = rotangle; + initm44(cos(alphaR), -sin(alphaR), 0, 0, + sin(alphaR), cos(alphaR), 0, 0, + 0, 0, 1, 0, + 0, 0, 0, 1, T); + pp0[0] = p0t[0]; pp0[1] = p0t[1]; pp0[2] = p0t[2]; pp0[3] = 1.0; + m4xv4(p0t, T, pp0); // Step 4 + + initm44(1, 0, 0, 0, + 0, cos(-rotx), -sin(-rotx), 0, + 0, sin(-rotx), cos(-rotx), 0, + 0, 0, 0, 1, T); + pp0[0] = p0t[0]; pp0[1] = p0t[1]; pp0[2] = p0t[2]; pp0[3] = 1.0; + m4xv4(p0t, T, pp0); // Step 5 + + initm44(cos(roty), 0, sin(roty), 0, + 0, 1, 0, 0, + -sin(roty), 0, cos(roty), 0, + 0, 0, 0, 1, T); + pp0[0] = p0t[0]; pp0[1] = p0t[1]; pp0[2] = p0t[2]; pp0[3] = 1.0; + m4xv4(p0t, T, pp0); // Step 6 + + initm44(1, 0, 0, p1[0], + 0, 1, 0, p1[1], + 0, 0, 1, p1[2], + 0, 0, 0, 1, T); + pp0[0] = p0t[0]; pp0[1] = p0t[1]; pp0[2] = p0t[2]; pp0[3] = 1.0; + m4xv4(p0t, T, pp0); // Step 7 + + p[0] = p0t[0]; + p[1] = p0t[1]; + p[2] = p0t[2]; +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// spherelineint() 3D line sphere (or circle) intersection. // +// // +// The line is given by two points p1, and p2, the sphere is centered at c // +// with radius r. This function returns a pointer array p which first index // +// indicates the number of intersection point, followed by coordinate pairs. // +// // +// The following code are adapted from: http://astronomy.swin.edu.au/pbourke // +// /geometry/sphereline. Paul Bourke pbourke@swin.edu.au // +// // +/////////////////////////////////////////////////////////////////////////////// + +void tetgenmesh::spherelineint(REAL* p1, REAL* p2, REAL* C, REAL R, REAL p[7]) +{ + REAL x1, y1, z1; // P1 coordinates (point of line) + REAL x2, y2, z2; // P2 coordinates (point of line) + REAL x3, y3, z3, r; // P3 coordinates and radius (sphere) + REAL a, b, c, mu, i ; + + x1 = p1[0]; y1 = p1[1]; z1 = p1[2]; + x2 = p2[0]; y2 = p2[1]; z2 = p2[2]; + x3 = C[0]; y3 = C[1]; z3 = C[2]; + r = R; + + a = (x2 - x1) * (x2 - x1) + + (y2 - y1) * (y2 - y1) + + (z2 - z1) * (z2 - z1); + b = 2 * ( (x2 - x1) * (x1 - x3) + + (y2 - y1) * (y1 - y3) + + (z2 - z1) * (z1 - z3) ) ; + c = (x3 * x3) + (y3 * y3) + (z3 * z3) + + (x1 * x1) + (y1 * y1) + (z1 * z1) + - 2 * (x3 * x1 + y3 * y1 + z3 * z1) - (r * r) ; + i = b * b - 4 * a * c ; + + if (i < 0.0) { + // no intersection + p[0] = 0.0; + } else if (i == 0.0) { + // one intersection + p[0] = 1.0; + mu = -b / (2 * a) ; + p[1] = x1 + mu * (x2 - x1); + p[2] = y1 + mu * (y2 - y1); + p[3] = z1 + mu * (z2 - z1); + } else { + assert(i > 0.0); + // two intersections + p[0] = 2.0; + // first intersection + mu = (-b + sqrt((b * b) - 4 * a * c)) / (2 * a); + p[1] = x1 + mu * (x2 - x1); + p[2] = y1 + mu * (y2 - y1); + p[3] = z1 + mu * (z2 - z1); + // second intersection + mu = (-b - sqrt((b * b) - 4 * a * c)) / (2 * a); + p[4] = x1 + mu * (x2 - x1); + p[5] = y1 + mu * (y2 - y1); + p[6] = z1 + mu * (z2 - z1); + } +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// linelineint() Calculate The shortest line between two lines in 3D. // +// // +// Two 3D lines generally don't intersect at a point, they may be parallel ( // +// no intersections), or they may be coincident (infinite intersections) but // +// most often only their projection onto a plane intersect. When they don't // +// exactly intersect at a point they can be connected by a line segment, the // +// shortest line segment is unique and is often considered to be their inter-// +// section in 3D. // +// // +// The following code are adapted from: http://astronomy.swin.edu.au/pbourke // +// /geometry/lineline3d. Paul Bourke pbourke@swin.edu.au // +// // +// Calculate the line segment PaPb that is the shortest route between two // +// lines P1P2 and P3P4. This function returns a pointer array p which first // +// index indicates there exists solution or not, 0 means no solution, 1 meas // +// has solution followed by two coordinate pairs. // +// // +/////////////////////////////////////////////////////////////////////////////// + +void tetgenmesh::linelineint(REAL *p1,REAL *p2, REAL *p3, REAL *p4, REAL p[7]) +{ + REAL p13[3], p43[3], p21[3]; + REAL d1343, d4321, d1321, d4343, d2121; + REAL numer, denom; + REAL mua, mub; + + p13[0] = p1[0] - p3[0]; + p13[1] = p1[1] - p3[1]; + p13[2] = p1[2] - p3[2]; + p43[0] = p4[0] - p3[0]; + p43[1] = p4[1] - p3[1]; + p43[2] = p4[2] - p3[2]; + if (p43[0] == 0.0 && p43[1] == 0.0 && p43[2] == 0.0) { + p[0] = 0.0; + return; + } + + p21[0] = p2[0] - p1[0]; + p21[1] = p2[1] - p1[1]; + p21[2] = p2[2] - p1[2]; + if (p21[0] == 0.0 && p21[1] == 0.0 && p21[2] == 0.0) { + p[0] = 0.0; + return; + } + + d1343 = p13[0] * p43[0] + p13[1] * p43[1] + p13[2] * p43[2]; + d4321 = p43[0] * p21[0] + p43[1] * p21[1] + p43[2] * p21[2]; + d1321 = p13[0] * p21[0] + p13[1] * p21[1] + p13[2] * p21[2]; + d4343 = p43[0] * p43[0] + p43[1] * p43[1] + p43[2] * p43[2]; + d2121 = p21[0] * p21[0] + p21[1] * p21[1] + p21[2] * p21[2]; + + denom = d2121 * d4343 - d4321 * d4321; + if (denom == 0.0) { + p[0] = 0.0; + return; + } + numer = d1343 * d4321 - d1321 * d4343; + mua = numer / denom; + mub = (d1343 + d4321 * mua) / d4343; + + p[0] = 1.0; + p[1] = p1[0] + mua * p21[0]; + p[2] = p1[1] + mua * p21[1]; + p[3] = p1[2] + mua * p21[2]; + p[4] = p3[0] + mub * p43[0]; + p[5] = p3[1] + mub * p43[1]; + p[6] = p3[2] + mub * p43[2]; +} + +// +// End of Geometric quantities calculators +// + +// +// Begin of memory management routines +// + +/////////////////////////////////////////////////////////////////////////////// +// // +// dummyinit() Initialize the tetrahedron that fills "outer space" and // +// the omnipresent subface. // +// // +// The tetrahedron that fills "outer space" called 'dummytet', is pointed to // +// by every tetrahedron and subface on a boundary (be it outer or inner) of // +// the tetrahedralization. Also, 'dummytet' points to one of the tetrahedron // +// on the convex hull(until the holes and concavities are carved), making it // +// possible to find a starting tetrahedron for point location. // +// // +// The omnipresent subface,'dummysh', is pointed to by every tetrahedron or // +// subface that doesn't have a full complement of real subface to point to. // +// // +/////////////////////////////////////////////////////////////////////////////// + +void tetgenmesh::dummyinit(int tetwords, int shwords) +{ + unsigned long alignptr; + + // Set up 'dummytet', the 'tetrahedron' that occupies "outer space". + dummytetbase = (tetrahedron *) new char[tetwords * sizeof(tetrahedron) + + tetrahedrons->alignbytes]; + // Align 'dummytet' on a 'tetrahedrons->alignbytes'-byte boundary. + alignptr = (unsigned long) dummytetbase; + dummytet = (tetrahedron *) + (alignptr + (unsigned long) tetrahedrons->alignbytes + - (alignptr % (unsigned long) tetrahedrons->alignbytes)); + // Initialize the four adjoining tetrahedra to be "outer space". These + // will eventually be changed by various bonding operations, but their + // values don't really matter, as long as they can legally be + // dereferenced. + dummytet[0] = (tetrahedron) dummytet; + dummytet[1] = (tetrahedron) dummytet; + dummytet[2] = (tetrahedron) dummytet; + dummytet[3] = (tetrahedron) dummytet; + // Four null vertex points. + dummytet[4] = (tetrahedron) NULL; + dummytet[5] = (tetrahedron) NULL; + dummytet[6] = (tetrahedron) NULL; + dummytet[7] = (tetrahedron) NULL; + + if (b->useshelles) { + // Set up 'dummysh', the omnipresent "subface" pointed to by any + // tetrahedron side or subface end that isn't attached to a real + // subface. + dummyshbase = (shellface *) new char[shwords * sizeof(shellface) + + subfaces->alignbytes]; + // Align 'dummysh' on a 'subfaces->alignbytes'-byte boundary. + alignptr = (unsigned long) dummyshbase; + dummysh = (shellface *) + (alignptr + (unsigned long) subfaces->alignbytes + - (alignptr % (unsigned long) subfaces->alignbytes)); + // Initialize the three adjoining subfaces to be the omnipresent + // subface. These will eventually be changed by various bonding + // operations, but their values don't really matter, as long as they + // can legally be dereferenced. + dummysh[0] = (shellface) dummysh; + dummysh[1] = (shellface) dummysh; + dummysh[2] = (shellface) dummysh; + // Three null vertex points. + dummysh[3] = (shellface) NULL; + dummysh[4] = (shellface) NULL; + dummysh[5] = (shellface) NULL; + // Initialize the two adjoining tetrahedra to be "outer space". + dummysh[6] = (shellface) dummytet; + dummysh[7] = (shellface) dummytet; + // Initialize the three adjoining subsegments to be "out boundary". + dummysh[8] = (shellface) dummysh; + dummysh[9] = (shellface) dummysh; + dummysh[10] = (shellface) dummysh; + // Initialize the pointer to badface structure. + dummysh[11] = (shellface) NULL; + // Initialize the four adjoining subfaces of 'dummytet' to be the + // omnipresent subface. + dummytet[8 ] = (tetrahedron) dummysh; + dummytet[9 ] = (tetrahedron) dummysh; + dummytet[10] = (tetrahedron) dummysh; + dummytet[11] = (tetrahedron) dummysh; + } +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// initializepointpool() Calculate the size of the point data structure // +// and initialize its memory pool. // +// // +// This routine also computes the 'pointmarkindex' and 'point2simindex' // +// indices used to find values within each point. // +// // +/////////////////////////////////////////////////////////////////////////////// + +void tetgenmesh::initializepointpool() +{ + enum wordtype wtype; + int pointsize; + + // The index within each point at which a element pointer is found. Ensure + // the index is aligned to a sizeof(tetrahedron)-byte address. + point2simindex = ((3 + in->numberofpointattributes) * sizeof(REAL) + + sizeof(tetrahedron) - 1) / sizeof(tetrahedron); + if (b->plc || b->refine) { + // Increase the point size by two pointers. One points to a simplex: + // - a tetrahedron containing it, read by point2tet(); + // - a subface containing it, read by point2sh(); + // - a (sharp) subsegment it relates, read by point2sh(); + // - a (duplicated) point of it, read by point2pt(); + // and one points to another point (its parent, used in conforming + // Delaunay meshing algorithm), read by point2ppt(). + pointsize = (point2simindex + 2) * sizeof(tetrahedron); + } else { + pointsize = point2simindex * sizeof(tetrahedron); + } + // The index within each point at which the boundary marker is found, + // Ensure the point marker is aligned to a sizeof(int)-byte address. + pointmarkindex = (pointsize + sizeof(int) - 1) / sizeof(int); + // Now point size is the REALs (inidcated by vertexmarkindex) plus: + // - an integer for boundary marker; + // - an integer for vertex type; + pointsize = (pointmarkindex + 2) * sizeof(int); + // Decide the wordtype used in vertex pool. + wtype = (sizeof(REAL) >= sizeof(tetrahedron)) ? FLOATINGPOINT : POINTER; + // Initialize the pool of vertices. + points = new memorypool(pointsize, VERPERBLOCK, wtype, 0); +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// initializetetshpools() Calculate the sizes of the tetrahedron and // +// subface data structures and initialize their // +// memory pools. // +// // +// This routine also computes the 'highorderindex', 'elemattribindex', and // +// 'volumeboundindex' indices used to find values within each tetrahedron. // +// // +// There are two types of boundary elements, whihc are subfaces and subsegs, // +// they are stored in seperate pools. However, the data structures of them // +// are the same. A subsegment can be regarded as a degenerate subface, i.e.,// +// one of its three corners is not used. We set the apex of it be 'NULL' to // +// distinguish it's a subsegment. // +// // +/////////////////////////////////////////////////////////////////////////////// + +void tetgenmesh::initializetetshpools() +{ + int elesize, shsize; + + // The number of bytes occupied by a tetrahedron. There are four pointers + // to other tetrahedra, four pointers to corners, and possibly four + // pointers to subfaces. + elesize = (8 + b->useshelles * 4) * sizeof(tetrahedron); + // The index within each element at which its attributes are found, where + // the index is measured in REALs. + elemattribindex = (elesize + sizeof(REAL) - 1) / sizeof(REAL); + // The index within each element at which the maximum voulme bound is + // found, where the index is measured in REALs. Note that if the + // `b->regionattrib' flag is set, an additional attribute will be added. + volumeboundindex = elemattribindex + in->numberoftetrahedronattributes + + b->regionattrib; + // If element attributes or an constraint are needed, increase the number + // of bytes occupied by an element. + if (b->varvolume) { + elesize = (volumeboundindex + 1) * sizeof(REAL); + } else if (in->numberoftetrahedronattributes + b->regionattrib > 0) { + elesize = volumeboundindex * sizeof(REAL); + } + // If the high order elements are required (-o2 switch is used), an + // additional pointer pointed to the list of extra nodes is allocated + // for each element. + if (b->order == 2) { + highorderindex = (elesize + sizeof(int) - 1) / sizeof(int); + elesize = (highorderindex + 1) * sizeof(int); + } + // If element neighbor graph is requested, make sure there's room to + // store an integer index in each element. This integer index can + // occupy the same space as the subface pointers. + if (b->neighout && (elesize <= 8 * sizeof(tetrahedron))) { + elesize = 8 * sizeof(tetrahedron) + sizeof(int); + } + // Having determined the memory size of an element, initialize the pool. + tetrahedrons = new memorypool(elesize, ELEPERBLOCK, POINTER, 8); + + if (b->useshelles) { + // The number of bytes occupied by a subface. The list of pointers + // stored in a subface are: three to other subfaces, three to corners, + // three to subsegments, two to tetrahedra, and one to a badface. + shsize = 12 * sizeof(shellface); + // The index within each subface at which the maximum area bound is + // found, where the index is measured in REALs. + areaboundindex = (shsize + sizeof(REAL) - 1) / sizeof(REAL); + // If -q switch is in use, increase the number of bytes occupied by + // a subface for saving maximum area bound. + if (b->quality) { + shsize = (areaboundindex + 1) * sizeof(REAL); + } else { + shsize = areaboundindex * sizeof(REAL); + } + // The index within subface at which the facet marker is found. Ensure + // the marker is aligned to a sizeof(int)-byte address. + shmarkindex = (shsize + sizeof(int) - 1) / sizeof(int); + // Increase the number of bytes by two integers, one for facet marker, + // and one for shellface type. + shsize = (shmarkindex + 2) * sizeof(int); + // Initialize the pool of subfaces. Each subface record is eight-byte + // aligned so it has room to store an edge version (from 0 to 5) in + // the least three bits. + subfaces = new memorypool(shsize, SUBPERBLOCK, POINTER, 8); + // Initialize the pool of subsegments. The subsegment's record is same + // with subface. + subsegs = new memorypool(shsize, SUBPERBLOCK, POINTER, 8); + // Initialize the "outer space" tetrahedron and omnipresent subface. + dummyinit(tetrahedrons->itemwords, subfaces->itemwords); + } else { + // Initialize the "outer space" tetrahedron. + dummyinit(tetrahedrons->itemwords, 0); + } +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// tetrahedrondealloc() Deallocate space for a tet., marking it dead. // +// // +/////////////////////////////////////////////////////////////////////////////// + +void tetgenmesh::tetrahedrondealloc(tetrahedron *dyingtetrahedron) +{ + // Set tetrahedron's vertices to NULL. This makes it possible to detect + // dead tetrahedra when traversing the list of all tetrahedra. + dyingtetrahedron[4] = (tetrahedron) NULL; + dyingtetrahedron[5] = (tetrahedron) NULL; + dyingtetrahedron[6] = (tetrahedron) NULL; + dyingtetrahedron[7] = (tetrahedron) NULL; + tetrahedrons->dealloc((void *) dyingtetrahedron); +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// tetrahedrontraverse() Traverse the tetrahedra, skipping dead ones. // +// // +/////////////////////////////////////////////////////////////////////////////// + +tetgenmesh::tetrahedron* tetgenmesh::tetrahedrontraverse() +{ + tetrahedron *newtetrahedron; + + do { + newtetrahedron = (tetrahedron *) tetrahedrons->traverse(); + if (newtetrahedron == (tetrahedron *) NULL) { + return (tetrahedron *) NULL; + } + } while (newtetrahedron[7] == (tetrahedron) NULL); // Skip dead ones. + return newtetrahedron; +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// shellfacedealloc() Deallocate space for a shellface, marking it dead. // +// Used both for dealloc a subface and subsegment. // +// // +/////////////////////////////////////////////////////////////////////////////// + +void tetgenmesh::shellfacedealloc(memorypool *pool, shellface *dyingsh) +{ + // Set shellface's vertices to NULL. This makes it possible to detect dead + // shellfaces when traversing the list of all shellfaces. + dyingsh[3] = (shellface) NULL; + dyingsh[4] = (shellface) NULL; + dyingsh[5] = (shellface) NULL; + pool->dealloc((void *) dyingsh); +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// shellfacetraverse() Traverse the subfaces, skipping dead ones. Used // +// for both subfaces and subsegments pool traverse. // +// // +/////////////////////////////////////////////////////////////////////////////// + +tetgenmesh::shellface* tetgenmesh::shellfacetraverse(memorypool *pool) +{ + shellface *newshellface; + + do { + newshellface = (shellface *) pool->traverse(); + if (newshellface == (shellface *) NULL) { + return (shellface *) NULL; + } + } while (newshellface[3] == (shellface) NULL); // Skip dead ones. + return newshellface; +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// badfacedealloc() Deallocate space for a badface, marking it dead. // +// // +/////////////////////////////////////////////////////////////////////////////// + +void tetgenmesh::badfacedealloc(memorypool *pool, badface *dying) +{ + // Set badface's forg to NULL. This makes it possible to detect dead + // ones when traversing the list of all items. + dying->forg = (point) NULL; + pool->dealloc((void *) dying); +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// badfacetraverse() Traverse the pools, skipping dead ones. // +// // +/////////////////////////////////////////////////////////////////////////////// + +tetgenmesh::badface* tetgenmesh::badfacetraverse(memorypool *pool) +{ + badface *newsh; + + do { + newsh = (badface *) pool->traverse(); + if (newsh == (badface *) NULL) { + return (badface *) NULL; + } + } while (newsh->forg == (point) NULL); // Skip dead ones. + return newsh; +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// pointdealloc() Deallocate space for a point, marking it dead. // +// // +/////////////////////////////////////////////////////////////////////////////// + +void tetgenmesh::pointdealloc(point dyingpoint) +{ + // Mark the point as dead. This makes it possible to detect dead points + // when traversing the list of all points. + setpointtype(dyingpoint, DEADVERTEX); + points->dealloc((void *) dyingpoint); +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// pointtraverse() Traverse the points, skipping dead ones. // +// // +/////////////////////////////////////////////////////////////////////////////// + +tetgenmesh::point tetgenmesh::pointtraverse() +{ + point newpoint; + + do { + newpoint = (point) points->traverse(); + if (newpoint == (point) NULL) { + return (point) NULL; + } + } while (pointtype(newpoint) == DEADVERTEX); // Skip dead ones. + return newpoint; +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// maketetrahedron() Create a new tetrahedron. // +// // +/////////////////////////////////////////////////////////////////////////////// + +void tetgenmesh::maketetrahedron(triface *newtet) +{ + newtet->tet = (tetrahedron *) tetrahedrons->alloc(); + // Initialize the four adjoining tetrahedra to be "outer space". + newtet->tet[0] = (tetrahedron) dummytet; + newtet->tet[1] = (tetrahedron) dummytet; + newtet->tet[2] = (tetrahedron) dummytet; + newtet->tet[3] = (tetrahedron) dummytet; + // Four NULL vertices. + newtet->tet[4] = (tetrahedron) NULL; + newtet->tet[5] = (tetrahedron) NULL; + newtet->tet[6] = (tetrahedron) NULL; + newtet->tet[7] = (tetrahedron) NULL; + // Initialize the four adjoining subfaces to be the omnipresent subface. + if (b->useshelles) { + newtet->tet[8 ] = (tetrahedron) dummysh; + newtet->tet[9 ] = (tetrahedron) dummysh; + newtet->tet[10] = (tetrahedron) dummysh; + newtet->tet[11] = (tetrahedron) dummysh; + } + for (int i = 0; i < in->numberoftetrahedronattributes; i++) { + setelemattribute(newtet->tet, i, 0.0); + } + if (b->varvolume) { + setvolumebound(newtet->tet, -1.0); + } + // Initialize the location and version to be Zero. + newtet->loc = 0; + newtet->ver = 0; +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// makeshellface() Create a new shellface with version zero. Used for // +// both subfaces and seusegments. // +// // +/////////////////////////////////////////////////////////////////////////////// + +void tetgenmesh::makeshellface(memorypool *pool, face *newface) +{ + newface->sh = (shellface *) pool->alloc(); + //Initialize the three adjoining subfaces to be the omnipresent subface. + newface->sh[0] = (shellface) dummysh; + newface->sh[1] = (shellface) dummysh; + newface->sh[2] = (shellface) dummysh; + // Three NULL vertices. + newface->sh[3] = (shellface) NULL; + newface->sh[4] = (shellface) NULL; + newface->sh[5] = (shellface) NULL; + // Initialize the two adjoining tetrahedra to be "outer space". + newface->sh[6] = (shellface) dummytet; + newface->sh[7] = (shellface) dummytet; + // Initialize the three adjoining subsegments to be the omnipresent + // subsegments. + newface->sh [8] = (shellface) dummysh; + newface->sh [9] = (shellface) dummysh; + newface->sh[10] = (shellface) dummysh; + // Initialize the pointer to badface structure. + newface->sh[11] = (shellface) NULL; + if (b->quality) { + // Initialize the maximum area bound. + setareabound(*newface, 0.0); + } + // Set the boundary marker to zero. + setshellmark(*newface, 0); + // Set the type be NONPROTSUBFACE. + setshelltype(*newface, NONPROTSUBFACE); + // Initialize the version to be Zero. + newface->shver = 0; +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// makepoint() Create a new point. // +// // +/////////////////////////////////////////////////////////////////////////////// + +void tetgenmesh::makepoint(point* pnewpoint) +{ + int ptmark, i; + + *pnewpoint = (point) points->alloc(); + // Initialize three coordinates. + (*pnewpoint)[0] = 0.0; + (*pnewpoint)[1] = 0.0; + (*pnewpoint)[2] = 0.0; + // Initialize the list of user-defined attributes. + for (i = 0; i < in->numberofpointattributes; i++) { + (*pnewpoint)[3 + i] = 0.0; + } + if (b->plc || b->refine) { + // Initialize the point-to-tetrahedron filed. + setpoint2tet(*pnewpoint, NULL); + // Initialize the other pointer to its parent point. + setpoint2ppt(*pnewpoint, NULL); + } + // Initialize the point marker (starting from in->firstnumber). + ptmark = (int) points->items - (in->firstnumber == 1 ? 0 : 1); + setpointmark(*pnewpoint, ptmark); + // Initialize the point type be UNUSEDVERTEX. + setpointtype(*pnewpoint, UNUSEDVERTEX); +} + +// +// End of memory management routines +// + +// +// Begin of point location routines +// + +/////////////////////////////////////////////////////////////////////////////// +// // +// randomnation() Generate a random number between 0 and 'choices' - 1. // +// // +/////////////////////////////////////////////////////////////////////////////// + +unsigned long tetgenmesh::randomnation(unsigned int choices) +{ + randomseed = (randomseed * 1366l + 150889l) % 714025l; + return randomseed / (714025l / choices + 1); +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// distance2() Returns the square "distance" of a tetrahedron to point p. // +// // +/////////////////////////////////////////////////////////////////////////////// + +REAL tetgenmesh::distance2(tetrahedron* tetptr, point p) +{ + point p1, p2, p3, p4; + REAL dx, dy, dz; + + p1 = (point) tetptr[4]; + p2 = (point) tetptr[5]; + p3 = (point) tetptr[6]; + p4 = (point) tetptr[7]; + + dx = p[0] - 0.25 * (p1[0] + p2[0] + p3[0] + p4[0]); + dy = p[1] - 0.25 * (p1[1] + p2[1] + p3[1] + p4[1]); + dz = p[2] - 0.25 * (p1[2] + p2[2] + p3[2] + p4[2]); + + return dx * dx + dy * dy + dz * dz; +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// preciselocate() Find a simplex containing a given point. // +// // +// This routine implements the simple Walk-through point location algorithm. // +// Begins its search from 'searchtet', assume there is a line segment L from // +// a vertex of 'searchtet' to the query point 'searchpoint', and simply walk // +// towards 'searchpoint' by traversing all faces intersected by L. // +// // +// On completion, 'searchtet' is a tetrahedron that contains 'searchpoint'. // +// The returned value indicates one of the following cases: // +// - Returns ONVERTEX if the point lies on an existing vertex. 'searchtet' // +// is a handle whose origin is the existing vertex. // +// - Returns ONEDGE if the point lies on a mesh edge. 'searchtet' is a // +// handle whose primary edge is the edge on which the point lies. // +// - Returns ONFACE if the point lies strictly within a face. 'searchtet' // +// is a handle whose primary face is the face on which the point lies. // +// - Returns INTETRAHEDRON if the point lies strictly in a tetrahededron. // +// 'searchtet' is a handle on the tetrahedron that contains the point. // +// - Returns OUTSIDE if the point lies outside the mesh. 'searchtet' is a // +// handle whose location is the face the point is to 'above' of. // +// // +// WARNING: This routine is designed for convex triangulations, and will not // +// generally work after the holes and concavities have been carved. // +// // +/////////////////////////////////////////////////////////////////////////////// + +enum tetgenmesh::locateresult tetgenmesh:: +preciselocate(point searchpoint, triface* searchtet) +{ + triface backtracetet; + triface walkthroface; + point forg, fdest, fapex, toppo; + REAL ori1, ori2, ori3, ori4; + long tetnumber; + int side; + + // 'searchtet' should be a valid tetrahedron. + if (searchtet->tet == dummytet) { + symself(*searchtet); + assert(searchtet->tet != dummytet); + } + assert(!isdead(searchtet)); + + searchtet->ver = 0; // Keep in CCW edge ring. + // Find a face of 'searchtet' such that the 'searchpoint' lies strictly + // above it. Such face should always exist. + for (searchtet->loc = 0; searchtet->loc < 4; searchtet->loc++) { + forg = org(*searchtet); + fdest = dest(*searchtet); + fapex = apex(*searchtet); + ori1 = orient3d(forg, fdest, fapex, searchpoint); + if (ori1 < 0.0) break; + } + assert(searchtet->loc < 4); + + // Define 'tetnumber' for exit the loop when it's running endless. + tetnumber = 0l; + while (tetnumber <= tetrahedrons->items) { + // Check if we are reaching the boundary of the triangulation. + if (searchtet->tet == dummytet) { + *searchtet = backtracetet; + return OUTSIDE; + } + // Initialize the face for returning the walk-through face. + walkthroface.tet = (tetrahedron *) NULL; + // Adjust the edge ring, so that 'ori1 < 0.0' holds. + searchtet->ver = 0; + // 'toppo' remains unchange for the following orientation tests. + toppo = oppo(*searchtet); + // Check the three sides of 'searchtet' to find the face through which + // we can walk next. + for (side = 0; side < 3; side++) { + forg = org(*searchtet); + fdest = dest(*searchtet); + ori2 = orient3d(forg, fdest, toppo, searchpoint); + if (ori2 == 0.0) { + // They are coplanar, check if 'searchpoint' lies inside, or on an + // edge, or coindice with a vertex of face (forg, fdest, toppo). + fapex = apex(*searchtet); + ori3 = orient3d(fdest, fapex, toppo, searchpoint); + if (ori3 < 0.0) { + // Outside the face (fdest, fapex, toppo), walk through it. + enextself(*searchtet); + fnext(*searchtet, walkthroface); + break; + } + ori4 = orient3d(fapex, forg, toppo, searchpoint); + if (ori4 < 0.0) { + // Outside the face (fapex, forg, toppo), walk through it. + enext2self(*searchtet); + fnext(*searchtet, walkthroface); + break; + } + // Remember, ori1 < 0.0, which means 'searchpoint' will not + // on edge (forg, fdest) or on vertex forg or fdest. + assert(ori1 < 0.0); + // The rest possible cases are: + // (1) 'searchpoint' lies on edge (fdest, toppo); + // (2) 'searchpoint' lies on edge (toppo, forg); + // (3) 'searchpoint' coincident with toppo; + // (4) 'searchpoint' lies inside face (forg, fdest, toppo). + fnextself(*searchtet); + if (ori3 == 0.0) { + if (ori4 == 0.0) { + // Case (4). + enext2self(*searchtet); + return ONVERTEX; + } else { + // Case (1). + enextself(*searchtet); + return ONEDGE; + } + } + if (ori4 == 0.0) { + // Case (2). + enext2self(*searchtet); + return ONEDGE; + } + // Case (4). + return ONFACE; + } else if (ori2 < 0.0) { + // Outside the face (forg, fdest, toppo), walk through it. + fnext(*searchtet, walkthroface); + break; + } + // Go to check next side. + enextself(*searchtet); + } + if (side >= 3) { + // Found! Inside tetrahedron. + return INTETRAHEDRON; + } + // We walk through the face 'walkthroface' and continue the searching. + assert(walkthroface.tet != (tetrahedron *) NULL); + // Store the face handle in 'backtracetet' before we take the real walk. + // So we are able to restore the handle to 'searchtet' if we are + // reaching the outer boundary. + backtracetet = walkthroface; + sym(walkthroface, *searchtet); + tetnumber++; + } + + // Should never be here. + printf("Internal error in preciselocate(): Point location failed.\n"); + internalerror(); + return OUTSIDE; +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// locate() Find a simplex containing a given point. // +// // +// This routine implements Muecke's Jump-and-walk point location algorithm. // +// It improves the simple walk-through by "jumping" to a good starting point // +// via random sampling. Searching begins from one of handles: the input // +// 'searchtet', a recently encountered tetrahedron 'recenttet', or from one // +// chosen from a random sample. The choice is made by determining which one // +// 's barycenter is closest to the point we are searcing for. Having chosen // +// the starting tetrahedron, the simple Walk-through algorithm is used to do // +// the real walking. // +// // +// On completion, 'searchtet' is a tetrahedron that contains 'searchpoint'. // +// The returned value indicates one of the following cases: // +// - Returns ONVERTEX if the point lies on an existing vertex. 'searchtet' // +// is a handle whose origin is the existing vertex. // +// - Returns ONEDGE if the point lies on a mesh edge. 'searchtet' is a // +// handle whose primary edge is the edge on which the point lies. // +// - Returns ONFACE if the point lies strictly within a face. 'searchtet' // +// is a handle whose primary face is the face on which the point lies. // +// - Returns INTETRAHEDRON if the point lies strictly in a tetrahededron. // +// 'searchtet' is a handle on the tetrahedron that contains the point. // +// - Returns OUTSIDE if the point lies outside the mesh. 'searchtet' is a // +// handle whose location is the face the point is to 'above' of. // +// // +// WARNING: This routine is designed for convex triangulations, and will not // +// generally work after the holes and concavities have been carved. // +// // +/////////////////////////////////////////////////////////////////////////////// + +enum tetgenmesh::locateresult tetgenmesh:: +locate(point searchpoint, triface *searchtet) +{ + tetrahedron *firsttet, *tetptr; + void **sampleblock; + long sampleblocks, samplesperblock, samplenum; + long tetblocks, i, j; + unsigned long alignptr; + REAL searchdist, dist; + + // 'searchtet' should be a valid tetrahedron. + if (isdead(searchtet)) { + searchtet->tet = dummytet; + } + if (searchtet->tet == dummytet) { + // This is an 'Outer Space' handle, get a hull tetrahedron. + searchtet->loc = 0; + symself(*searchtet); + } + assert(!isdead(searchtet)); + + // Record the distance from the suggested starting tetrahedron to the + // point we seek. + searchdist = distance2(searchtet->tet, searchpoint); + + // If a recently encountered tetrahedron has been recorded and has not + // been deallocated, test it as a good starting point. + if (!isdead(&recenttet) && (recenttet.tet != searchtet->tet)) { + dist = distance2(recenttet.tet, searchpoint); + if (dist < searchdist) { + *searchtet = recenttet; + searchdist = dist; + } + } + + // Select "good" candidate using k random samples, taking the closest one. + // The number of random samples taken is proportional to the cube root + // of the number of tetrahedra in the mesh. The next bit of code assumes + // that the number of tetrahedra increases monotonically. + while (SAMPLEFACTOR * samples * samples * samples < tetrahedrons->items) { + samples++; + } + // Find how much blocks in current tet pool. + tetblocks = (tetrahedrons->maxitems + ELEPERBLOCK - 1) / ELEPERBLOCK; + // Find the average samles per block. Each block at least have 1 sample. + samplesperblock = 1 + (samples / tetblocks); + sampleblocks = samples / samplesperblock; + sampleblock = tetrahedrons->firstblock; + for (i = 0; i < sampleblocks; i++) { + alignptr = (unsigned long) (sampleblock + 1); + firsttet = (tetrahedron *) + (alignptr + (unsigned long) tetrahedrons->alignbytes + - (alignptr % (unsigned long) tetrahedrons->alignbytes)); + for (j = 0; j < samplesperblock; j++) { + if (i == tetblocks - 1) { + // This is the last block. + samplenum = randomnation((int) + (tetrahedrons->maxitems - (i * ELEPERBLOCK))); + } else { + samplenum = randomnation(ELEPERBLOCK); + } + tetptr = (tetrahedron *) + (firsttet + (samplenum * tetrahedrons->itemwords)); + if (tetptr[4] != (tetrahedron) NULL) { + dist = distance2(tetptr, searchpoint); + if (dist < searchdist) { + searchtet->tet = tetptr; + searchdist = dist; + } + } + } + sampleblock = (void **) *sampleblock; + } + + // Call simple walk-through to locate the point. + return preciselocate(searchpoint, searchtet); +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// adjustlocate() Adjust the precise location of a vertex with respect to // +// a given tetrahedron using a given relative tolerance. // +// // +// 'precise' is the precise location (returned from preciselocate()) of the // +// point 'searchpoint' with respect to the tetrahedron 'searchtet'. 'epspp' // +// is the given relative tolerance. // +// // +// This routine reevaluates the orientations of searchpoint with respect to // +// the four faces of searchtet. Detects the coplanarities by additinal tests // +// which are based on the given tolerance. If 'precise' is ONFACE or ONEDGE, // +// we can save one or two orientation tests. // +// // +// On completion, 'searchtet' is a tetrahedron that contains 'searchpoint'. // +// The returned value indicates one of the following cases: // +// - Returns ONVERTEX if the point lies on an existing vertex. 'searchtet' // +// is a handle whose origin is the existing vertex. // +// - Returns ONEDGE if the point lies on a mesh edge. 'searchtet' is a // +// handle whose primary edge is the edge on which the point lies. // +// - Returns ONFACE if the point lies strictly within a face. 'searchtet' // +// is a handle whose primary face is the face on which the point lies. // +// - Returns INTETRAHEDRON if the point lies strictly in a tetrahededron. // +// 'searchtet' is a handle on the tetrahedron that contains the point. // +// - Returns OUTSIDE if the point lies outside the mesh. 'searchtet' is a // +// handle whose location is the face the point is to 'above' of. // +// // +// WARNING: This routine detect degenerate case using relative tolerance. // +// It is better used after locate() or preciselocate(). For general inputs, // +// it may not able to tell the correct location. // +// // +/////////////////////////////////////////////////////////////////////////////// + +enum tetgenmesh::locateresult tetgenmesh:: +adjustlocate(point searchpoint, triface* searchtet, enum locateresult precise, + REAL epspp) +{ + point torg, tdest, tapex, toppo; + REAL s1, s2, s3, s4; + + // For the given 'searchtet', the orientations tests are: + // s1: (tdest, torg, tapex, searchpoint); + // s2: (torg, tdest, toppo, searchpoint); + // s3: (tdest, tapex, toppo, searchpoint); + // s4: (tapex, torg, toppo, searchpoint); + adjustedgering(*searchtet, CCW); + torg = org(*searchtet); + tdest = dest(*searchtet); + tapex = apex(*searchtet); + toppo = oppo(*searchtet); + + switch (precise) { + case ONVERTEX: + // This case we don't need do any further test. + return ONVERTEX; + case ONEDGE: + // (torg, tdest); + s1 = 0.0; + s2 = 0.0; + break; + case ONFACE: + // (tdest, torg, tapex); + s1 = 0.0; + s2 = orient3d(torg, tdest, toppo, searchpoint); + break; + default: // INTETRAHEDRON or OUTSIDE + s1 = orient3d(tdest, torg, tapex, searchpoint); + s2 = orient3d(torg, tdest, toppo, searchpoint); + } + + if (s1 != 0.0) { + if (iscoplanar(tdest, torg, tapex, searchpoint, s1, epspp)) { + s1 = 0.0; + } + } + if (s1 < 0.0) { + return OUTSIDE; + } + + if (s2 != 0.0) { + if (iscoplanar(torg, tdest, toppo, searchpoint, s2, epspp)) { + s2 = 0.0; + } + } + if (s2 < 0.0) { + fnextself(*searchtet); + return OUTSIDE; + } + + s3 = orient3d(tdest, tapex, toppo, searchpoint); + if (s3 != 0.0) { + if (iscoplanar(tdest, tapex, toppo, searchpoint, s3, epspp)) { + s3 = 0.0; + } + } + if (s3 < 0.0) { + enextfnextself(*searchtet); + return OUTSIDE; + } + + s4 = orient3d(tapex, torg, toppo, searchpoint); + if (s4 != 0.0) { + if (iscoplanar(tapex, torg, toppo, searchpoint, s4, epspp)) { + s4 = 0.0; + } + } + if (s4 < 0.0) { + enext2fnextself(*searchtet); + return OUTSIDE; + } + + // Determine degenerate cases. + if (s1 == 0.0) { + if (s2 == 0.0) { + if (s3 == 0.0) { + // On tdest. + enextself(*searchtet); + return ONVERTEX; + } + if (s4 == 0.0) { + // On torg. + return ONVERTEX; + } + // On edge (torg, tdest). + return ONEDGE; + } + if (s3 == 0.0) { + if (s4 == 0.0) { + // On tapex. + enext2self(*searchtet); + return ONVERTEX; + } + // On edge (tdest, tapex). + enextself(*searchtet); + return ONEDGE; + } + if (s4 == 0.0) { + // On edge (tapex, torg). + enext2self(*searchtet); + return ONEDGE; + } + // On face (torg, tdest, tapex). + return ONFACE; + } + if (s2 == 0.0) { + fnextself(*searchtet); + if (s3 == 0.0) { + if (s4 == 0.0) { + // On toppo. + enext2self(*searchtet); + return ONVERTEX; + } + // On edge (tdest, toppo). + enextself(*searchtet); + return ONEDGE; + } + if (s4 == 0.0) { + // On edge (toppo, torg). + enext2self(*searchtet); + return ONEDGE; + } + // On face (torg, tdest, toppo). + return ONFACE; + } + if (s3 == 0.0) { + enextfnextself(*searchtet); + if (s4 == 0.0) { + // On edge (tapex, toppo). + enextself(*searchtet); + return ONEDGE; + } + // On face (tdest, tapex, toppo). + return ONFACE; + } + if (s4 == 0.0) { + enext2fnextself(*searchtet); + // On face (tapex, torg, toppo). + return ONFACE; + } + + // Inside tetrahedron. + return INTETRAHEDRON; +} + +// +// End of point location routines +// + +// +// Begin of mesh transformation routines +// + +/////////////////////////////////////////////////////////////////////////////// +// // +// categorizeface() Determine the flip type of a given face. // +// // +// On input, 'horiz' represents the face we want to flip (you can imagine it // +// is parallel to the horizon). Let the tetrahedron above it be abcd, where // +// abc is 'horiz'. // +// // +// If abc is a hull face, it is unflipable, and is locally Delaunay. In the // +// following, we assume abc is an interior face, and the other tetrahedron // +// adjoining at abc is bace. // +// // +// If the convex hull CH of the set {a, b, c, d, e} only has four vertices, // +// i.e., one vertex lies inside CH, then abc is unflipable, and is locally // +// Delaunay. If CH is the vertex set itself, we have the following cases to // +// determine whether abc is flipable or not. // +// // +// If no four points of {a, b, c, d, e} are coplanar, a 2-to-3 flip can be // +// applied to abc if the edge de crosses the triangle abc; a 3-to-2 flip can // +// be applied to abc if ab crosses cde, and abde exists, otherwise, face abc // +// is unflipable, i.e., the tetrahedron abde is not present. // +// // +// If four points of {a, b, c, d, e} are coplanar (two faces are coplanar). // +// Assume faces abd and abe are coplanar (it is impossible be abc). If a, b, // +// d, e form a non-convex quadrilateral, then abc is unflipable, furthermore,// +// it is locally Delaunay. Assume they are convex quadrilateral, if abd and // +// abe are hull faces, a 2-to-2 flip can be applied to abc; if abd and abe // +// are interior faces, assume two tetrahedra adjoining abd and abe at the // +// opposite sides are abdg and abef, respectively. If g = f, a 4-to-4 flip // +// can be applied to abc, otherwise, abc is unflipable. // +// // +// There are other cases which can cause abc unflipable. If abc is a subface,// +// a 2-to-3 flip is forbidden; if ab is a subsegment, flips 3-to-2, 2-to-2, // +// and 4-to-4 are forbidden. // +// // +// This routine determines the suitable type of flip operation for 'horiz'. // +// - Returns T23 if a 2-to-3 flip is applicable. 'horiz' is same as input. // +// - Returns T32 if a 3-to-2 flip is applicable. 'horiz' is adjusted so // +// that the primary edge of 'horiz' is the flipable edge. // +// - Returns T22 if a 2-to-2 or 4-to-4 flip is applicable. 'horiz' is // +// adjusted so that the primary edge of 'horiz' is the flipable edge. // +// - Returns FORBIDDENFACE indicates although a 2-to-3 flip is applicable, // +// but it is a subface and should not be flipped away. // +// - Returns FORBIDDENEDGE indicates although a 3-to-2, or 2-to-2, or // +// 4-to-4 flip is applicable, but the flipable edge is a subsegment and // +// should not be flipped away. 'horiz' is adjusted so that the primary // +// edge of 'horiz' is the flipable edge. // +// - Returns UNFLIPABLE indicates it is unflipable due to the absence of // +// a tetrahedron. 'horiz' is adjusted so that the primary edge of 'horiz'// +// is the unflipable edge. Possibly, It is a subsegment. // +// - Returns NONCONVEX indicates it is unflipable and is locally Delaunay. // +// // +// Given a face abc, with two adjoining tetrahedra abcd and bace. If abc is // +// flipable, i.e., T23, T32, T22 or T44, its flip type can be determined by // +// doing five orientation tests: two tests for determining that d, e lie on // +// the different sides of abc, three tests for determining if the edge de // +// intersects the face abc. However, if we use the neighbor information of // +// the mesh data structure, we can reduce the five orientation tests to at // +// most three tests, that is, the two tests for determining whether d and e // +// lie on the different sides of abc can be saved. // +// // +/////////////////////////////////////////////////////////////////////////////// + +enum tetgenmesh::fliptype tetgenmesh::categorizeface(triface& horiz) +{ + triface symhoriz, casing; + face checksh, checkseg; + face cassh1, cassh2; + point pa, pb, pc, pd, pe, pf, pg; + point abdoppo, bcdoppo, cadoppo; + REAL ori1, ori2, ori3; + int adjtet; + + sym(horiz, symhoriz); + if (symhoriz.tet == dummytet) { + // A hull face is unflipable and locally Delaunay. + return NONCONVEX; + } + + adjustedgering(horiz, CCW); + findedge(&symhoriz, dest(horiz), org(horiz)); + pa = org(horiz); + pb = dest(horiz); + pc = apex(horiz); + pd = oppo(horiz); + pe = oppo(symhoriz); + + // Find the number of adjacent tetrahedra of abc, which have d, e, and one + // of corners of abc as their corners. This number can be 0, 1 and 2. + abdoppo = bcdoppo = cadoppo = (point) NULL; + adjtet = 0; + fnext(horiz, casing); // at edge 'ab'. + symself(casing); + if (casing.tet != dummytet) { + abdoppo = oppo(casing); + if (abdoppo == pe) adjtet++; + } + enextfnext(horiz, casing); // at edge 'bc'. + symself(casing); + if (casing.tet != dummytet) { + bcdoppo = oppo(casing); + if (bcdoppo == pe) adjtet++; + } + enext2fnext(horiz, casing); // at edge 'ca'. + symself(casing); + if (casing.tet != dummytet) { + cadoppo = oppo(casing); + if (cadoppo == pe) adjtet++; + } + + if (adjtet == 0) { + // No adjacent tetrahedron. Types T23, T22 and T44 are possible. + ori1 = orient3d(pa, pb, pd, pe); + if (checksubfaces && ori1 != 0.0) { + // Are abd and abe subfaces and belong to the same facet? + fnext(horiz, casing); + tspivot(casing, cassh1); + fnext(symhoriz, casing); + tspivot(casing, cassh2); + if (cassh1.sh != dummysh && cassh2.sh != dummysh) { + // Two adjoining boundary faces. If the common edge of them is not + // a subsegment, they belong to the same facet. + findedge(&cassh1, pa, pb); + sspivot(cassh1, checkseg); + if (checkseg.sh == dummysh) { + // The four points are forced to be coplanar. + ori1 = 0.0; + } + } + if (ori1 != 0.0) { + // Check if abd and bae are approximately coplanar. + if (iscoplanar(pa, pb, pd, pe, ori1, b->epsilon)) ori1 = 0.0; + } + } + if (ori1 < 0.0) { + // e lies above abd, unflipable, tet abde is not present. +#ifdef SELF_CHECK + if (!nonconvex) { + // abd and abe should not be hull faces, check it. + fnext(horiz, casing); + symself(casing); + assert(casing.tet != dummytet); + fnext(symhoriz, casing); + symself(casing); + assert(casing.tet != dummytet); + } +#endif + if (checksubfaces) { + // The nonconvexbility may be casued by existing an subsegment. + tsspivot(&horiz, &checkseg); + if (checkseg.sh != dummysh) { + return FORBIDDENEDGE; + } + } + return UNFLIPABLE; + } + ori2 = orient3d(pb, pc, pd, pe); + if (checksubfaces && ori2 != 0.0) { + // Are bcd and cbe subfaces and belong to the same facet? + enextfnext(horiz, casing); + tspivot(casing, cassh1); + enext2fnext(symhoriz, casing); + tspivot(casing, cassh2); + if (cassh1.sh != dummysh && cassh2.sh != dummysh) { + // Two adjoining boundary faces. If the common edge of them is not + // a subsegment, they belong to the same facet. + findedge(&cassh1, pb, pc); + sspivot(cassh1, checkseg); + if (checkseg.sh == dummysh) { + // The four points are forced to be coplanar. + ori2 = 0.0; + } + } + if (ori2 != 0.0) { + // Check if bcd and cbe are approximately coplanar. + if (iscoplanar(pb, pc, pd, pe, ori2, b->epsilon)) ori2 = 0.0; + } + } + if (ori2 < 0.0) { + // e lies above bcd, unflipable, tet bcde is not present. +#ifdef SELF_CHECK + if (!nonconvex) { + // bcd and cbe should not be hull faces, check it. + enextfnext(horiz, casing); + symself(casing); + assert(casing.tet != dummytet); + enext2fnext(symhoriz, casing); + symself(casing); + assert(casing.tet != dummytet); + } +#endif + enextself(horiz); + if (checksubfaces) { + // The nonconvexbility may be casued by existing an subsegment. + tsspivot(&horiz, &checkseg); + if (checkseg.sh != dummysh) { + return FORBIDDENEDGE; + } + } + return UNFLIPABLE; + } + ori3 = orient3d(pc, pa, pd, pe); + if (checksubfaces && ori3 != 0.0) { + // Are cad and ace subfaces and belong to the same facet? + enext2fnext(horiz, casing); + tspivot(casing, cassh1); + enextfnext(symhoriz, casing); + tspivot(casing, cassh2); + if (cassh1.sh != dummysh && cassh2.sh != dummysh) { + // Two adjoining boundary faces. If the common edge of them is not + // a subsegment, they belong to the same facet. + findedge(&cassh1, pc, pa); + sspivot(cassh1, checkseg); + if (checkseg.sh == dummysh) { + // The four points are forced to be coplanar. + ori3 = 0.0; + } + } + if (ori3 != 0.0) { + // Check if cad and ace are approximately coplanar. + if (iscoplanar(pc, pa, pd, pe, ori3, b->epsilon)) ori3 = 0.0; + } + } + if (ori3 < 0.0) { + // e lies above cad, unflipable, tet cade is not present. +#ifdef SELF_CHECK + if (!nonconvex) { + // cad and ace should not be hull faces, check it. + enext2fnext(horiz, casing); + symself(casing); + assert(casing.tet != dummytet); + enextfnext(symhoriz, casing); + symself(casing); + assert(casing.tet != dummytet); + } +#endif + enext2self(horiz); + if (checksubfaces) { + // The nonconvexbility may be casued by existing an subsegment. + tsspivot(&horiz, &checkseg); + if (checkseg.sh != dummysh) { + return FORBIDDENEDGE; + } + } + return UNFLIPABLE; + } + if (ori1 == 0.0) { + // e is coplanar with abd. + if (ori2 * ori3 == 0.0) { + // only one zero is possible. + // assert(!(ori2 == 0.0 && ori3 == 0.0)); + // Three points (d, e, and a or b) are collinear, abc is unflipable + // and locally Delaunay. + return NONCONVEX; + } + } else if (ori2 == 0.0) { + // e is coplanar with bcd. + if (ori1 * ori3 == 0.0) { + // only one zero is possible. + // assert(!(ori1 == 0.0 && ori3 == 0.0)); + // Three points (d, e, and b or c) are collinear, abc is unflipable + // and locally Delaunay. + return NONCONVEX; + } + // Adjust 'horiz' and 'symhoriz' be the edge bc. + enextself(horiz); + enext2self(symhoriz); + } else if (ori3 == 0.0) { + // e is coplanar with cad. + if (ori1 * ori2 == 0.0) { + // only one zero is possible. + // assert(!(ori1 == 0.0 && ori2 == 0.0)); + // Three points (d, e, and c or a) are collinear, abc is unflipable + // and locally Delaunay. + return NONCONVEX; + } + // Adjust 'horiz' and 'symhoriz' be the edge ca. + enext2self(horiz); + enextself(symhoriz); + } else { + // e lies below all three faces, flipable. + if (checksubfaces) { + tspivot(horiz, checksh); + if (checksh.sh != dummysh) { + // To flip a subface is forbidden. + return FORBIDDENFACE; + } + } + return T23; + } + // Four points are coplanar, T22 or T44 is possible. + if (checksubfaces) { + tsspivot(&horiz, &checkseg); + if (checkseg.sh != dummysh) { + // To flip a subsegment is forbidden. + return FORBIDDENEDGE; + } + tspivot(horiz, checksh); + if (checksh.sh != dummysh) { + // To flip a subface is forbidden. + return FORBIDDENFACE; + } + } + // Assume the four coplanar points are a, b, d, e, abd and abe are two + // coplanar faces. If both abd and abe are hull faces, flipable(T22). + // If they are interior faces, get the opposite tetrahedra abdf and + // abeg, if f = g, flipable (T44). Otherwise, unflipable. + pf = pg = (point) NULL; + fnext(horiz, casing); + symself(casing); + if (casing.tet != dummytet) { + pf = oppo(casing); + } + fnext(symhoriz, casing); + symself(casing); + if (casing.tet != dummytet) { + pg = oppo(casing); + } + if (pf == (point) NULL && pg == (point) NULL) { + // abd and abe are hull faces, flipable. + return T22; + } else if (pf == pg) { + // abd and abe are interior faces, flipable. + return T44; + } else { + // ab has more than four faces around it, unflipable. + return UNFLIPABLE; + } + } else if (adjtet == 1) { + // One of its three edges is locally non-convex. Type T32 is possible. + // Adjust current configuration so that edge ab is non-convex. + if (bcdoppo == pe) { + // Edge bc is non-convex. Adjust 'horiz' and 'symhoriz' be edge bc. + enextself(horiz); + enext2self(symhoriz); + pa = org(horiz); + pb = dest(horiz); + pc = apex(horiz); + } else if (cadoppo == pe) { + // Edge ca is non-convex. Adjust 'horiz' and 'symhoriz' be edge ca. + enext2self(horiz); + enextself(symhoriz); + pa = org(horiz); + pb = dest(horiz); + pc = apex(horiz); + } else { + // Edge ab is non-convex. + assert(abdoppo == pe); + } // Now ab is the non-convex edge. + // In order to be flipable, ab should cross face cde. Check it. + ori1 = orient3d(pc, pd, pe, pa); + if (checksubfaces && ori1 != 0.0) { + // Are cad and ace subfaces and belong to the same facet? + enext2fnext(horiz, casing); + tspivot(casing, cassh1); + enextfnext(symhoriz, casing); + tspivot(casing, cassh2); + if (cassh1.sh != dummysh && cassh2.sh != dummysh) { + // Two adjoining boundary faces. If the common edge of them is not + // a subsegment, they belong to the same facet. + findedge(&cassh1, pc, pa); + sspivot(cassh1, checkseg); + if (checkseg.sh == dummysh) { + // The four points are forced to be coplanar. + ori1 = 0.0; + } + } + } + if (ori1 <= 0.0) { + // a lies above cde, unflipable, and abc is locally Delaunay. + return NONCONVEX; + } + ori2 = orient3d(pd, pc, pe, pb); + if (checksubfaces && ori2 != 0.0) { + // Are bcd and cbe subfaces and belong to the same facet? + enextfnext(horiz, casing); + tspivot(casing, cassh1); + enext2fnext(symhoriz, casing); + tspivot(casing, cassh2); + if (cassh1.sh != dummysh && cassh2.sh != dummysh) { + // Two adjoining boundary faces. If the common edge of them is not + // a subsegment, they belong to the same facet. + findedge(&cassh1, pb, pc); + sspivot(cassh1, checkseg); + if (checkseg.sh == dummysh) { + // The four points are forced to be coplanar. + ori2 = 0.0; + } + } + } + if (ori2 <= 0.0) { + // b lies above dce, unflipable, and abc is locally Delaunay. + return NONCONVEX; + } + // Edge ab crosses face cde properly. + if (checksubfaces) { + // If abc is subface, then ab must be a subsegment (because abde is + // a tetrahedron and ab crosses cde properly). + tsspivot(&horiz, &checkseg); + if (checkseg.sh != dummysh) { + // To flip a subsegment is forbidden. + return FORBIDDENEDGE; + } + // Both abd and bae should not be subfaces (because they're not + // coplanar and ab is not a subsegment). However, they may be + // subfaces and belong to a facet (created during facet recovery), + // that is, abde is an invalid tetrahedron. Find this case out. + fnext(horiz, casing); + tspivot(casing, cassh1); + fnext(symhoriz, casing); + tspivot(casing, cassh2); + if (cassh1.sh != dummysh || cassh2.sh != dummysh) { + // Unfortunately, they're subfaces. Corrections need be done here. + printf("Warning: A tetrahedron spans two subfaces of a facet.\n"); + // Temporarily, let it be there. + return NONCONVEX; + } + } + return T32; + } else { + assert(adjtet == 2); + // The convex hull of {a, b, c, d, e} has only four vertices, abc is + // unflipable, furthermore, it is locally Delaunay. + return NONCONVEX; + } +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// enqueueflipface(), enqueueflipedge() Add a face or an edge to the end // +// of a queue. // +// // +// This face or edge may be non-Delaunay and will be checked. Corresponding // +// flip operation will be applied on it if it is non-Delaunay. The vertices // +// of the face or edge are stored seperatly used to ensure the face or edge // +// is still the same one when we save it. Sometimes, other flipping will // +// cause this face or edge be changed or dead. // +// // +/////////////////////////////////////////////////////////////////////////////// + +void tetgenmesh::enqueueflipface(triface& checkface, queue* flipqueue) +{ + badface *queface; + + queface = (badface *) flipqueue->push((void *) NULL); + queface->tt = checkface; + queface->forg = org(checkface); + queface->fdest = dest(checkface); + queface->fapex = apex(checkface); +} + +void tetgenmesh::enqueueflipedge(face& checkedge, queue* flipqueue) +{ + badface *queface; + + queface = (badface *) flipqueue->push((void *) NULL); + queface->ss = checkedge; + queface->forg = sorg(checkedge); + queface->fdest = sdest(checkedge); +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// flip23() Perform a 2-to-3 flip. // +// // +// On input, 'flipface' represents the face will be flipped. Let it is abc, // +// the two tetrahedra sharing abc are abcd, bace. abc is not a subface. // +// // +// A 2-to-3 flip is to change two tetrahedra abcd, bace to three tetrahedra // +// edab, edbc, and edca. As a result, face abc has been removed and three // +// new faces eda, edb and edc have been created. // +// // +// On completion, 'flipface' returns edab. If 'flipqueue' is not NULL, all // +// possibly non-Delaunay faces are added into it. // +// // +/////////////////////////////////////////////////////////////////////////////// + +void tetgenmesh::flip23(triface* flipface, queue* flipqueue) +{ + triface abcd, bace; // Old configuration. + triface oldabd, oldbcd, oldcad; + triface abdcasing, bcdcasing, cadcasing; + face abdsh, bcdsh, cadsh; + triface oldbae, oldcbe, oldace; + triface baecasing, cbecasing, acecasing; + face baesh, cbesh, acesh; + triface edab, edbc, edca; // New configuration. + point pa, pb, pc, pd, pe; + REAL attrib, volume; + int i; + + abcd = *flipface; + adjustedgering(abcd, CCW); // abcd represents edge ab. + sym(abcd, bace); + findedge(&bace, dest(abcd), org(abcd)); // bace represents edge ba. + pa = org(abcd); + pb = dest(abcd); + pc = apex(abcd); + pd = oppo(abcd); + pe = oppo(bace); + + if (b->verbose > 2) { + printf(" Do T23 on face (%d, %d, %d, %d).\n", pointmark(pa), + pointmark(pb), pointmark(pc), pointmark(pd)); + } + flip23s++; + +#ifdef SELF_CHECK + // Edge de must cross face abc properly. + assert(orient3d(pa, pb, pd, pe) >= 0.0); + assert(orient3d(pb, pc, pd, pe) >= 0.0); + assert(orient3d(pc, pa, pd, pe) >= 0.0); +#endif + + // Storing the old configuration outside the convex hull. + fnext(abcd, oldabd); + enextfnext(abcd, oldbcd); + enext2fnext(abcd, oldcad); + fnext(bace, oldbae); + enext2fnext(bace, oldcbe); + enextfnext(bace, oldace); + sym(oldabd, abdcasing); + sym(oldbcd, bcdcasing); + sym(oldcad, cadcasing); + sym(oldbae, baecasing); + sym(oldcbe, cbecasing); + sym(oldace, acecasing); + if (checksubfaces) { + tspivot(oldabd, abdsh); + tspivot(oldbcd, bcdsh); + tspivot(oldcad, cadsh); + tspivot(oldbae, baesh); + tspivot(oldcbe, cbesh); + tspivot(oldace, acesh); + } + + // Creating the new configuration inside the convex hull. + edab.tet = abcd.tet; // Update abcd to be edab. + setorg (edab, pe); + setdest(edab, pd); + setapex(edab, pa); + setoppo(edab, pb); + edbc.tet = bace.tet; // Update bace to be edbc. + setorg (edbc, pe); + setdest(edbc, pd); + setapex(edbc, pb); + setoppo(edbc, pc); + maketetrahedron(&edca); // Create edca. + setorg (edca, pe); + setdest(edca, pd); + setapex(edca, pc); + setoppo(edca, pa); + // Set the element attributes of the new tetrahedron 'edca'. + for (i = 0; i < in->numberoftetrahedronattributes; i++) { + attrib = elemattribute(abcd.tet, i); + setelemattribute(edca.tet, i, attrib); + } + // Set the volume constraint of the new tetrahedron 'edca' if the -ra + // switches are not used together. In -ra case, the various volume + // constraints can be spreaded very far. + if (b->varvolume && !b->refine) { + volume = volumebound(abcd.tet); + setvolumebound(edca.tet, volume); + } + + // Clear old bonds in edab(was abcd) and edbc(was bace). + for (i = 0; i < 4; i ++) { + edab.loc = i; + dissolve(edab); + edbc.loc = i; + dissolve(edbc); + } + // Bond the faces inside the convex hull. + edab.loc = 0; + edca.loc = 1; + bond(edab, edca); + edab.loc = 1; + edbc.loc = 0; + bond(edab, edbc); + edbc.loc = 1; + edca.loc = 0; + bond(edbc, edca); + // Bond the faces on the convex hull. + edab.loc = 2; + bond(edab, abdcasing); + edab.loc = 3; + bond(edab, baecasing); + edbc.loc = 2; + bond(edbc, bcdcasing); + edbc.loc = 3; + bond(edbc, cbecasing); + edca.loc = 2; + bond(edca, cadcasing); + edca.loc = 3; + bond(edca, acecasing); + // There may exist subfaces that need to be bonded to new configuarton. + if (checksubfaces) { + // Clear old flags in edab(was abcd) and edbc(was bace). + for (i = 0; i < 4; i ++) { + edab.loc = i; + tsdissolve(edab); + edbc.loc = i; + tsdissolve(edbc); + } + if (abdsh.sh != dummysh) { + edab.loc = 2; + tsbond(edab, abdsh); + } + if (baesh.sh != dummysh) { + edab.loc = 3; + tsbond(edab, baesh); + } + if (bcdsh.sh != dummysh) { + edbc.loc = 2; + tsbond(edbc, bcdsh); + } + if (cbesh.sh != dummysh) { + edbc.loc = 3; + tsbond(edbc, cbesh); + } + if (cadsh.sh != dummysh) { + edca.loc = 2; + tsbond(edca, cadsh); + } + if (acesh.sh != dummysh) { + edca.loc = 3; + tsbond(edca, acesh); + } + } + + edab.loc = 0; + edbc.loc = 0; + edca.loc = 0; + if (b->verbose > 3) { + printf(" Updating edab "); + printtet(&edab); + printf(" Updating edbc "); + printtet(&edbc); + printf(" Creating edca "); + printtet(&edca); + } + + if (flipqueue != (queue *) NULL) { + enextfnext(edab, abdcasing); + enqueueflipface(abdcasing, flipqueue); + enext2fnext(edab, baecasing); + enqueueflipface(baecasing, flipqueue); + enextfnext(edbc, bcdcasing); + enqueueflipface(bcdcasing, flipqueue); + enext2fnext(edbc, cbecasing); + enqueueflipface(cbecasing, flipqueue); + enextfnext(edca, cadcasing); + enqueueflipface(cadcasing, flipqueue); + enext2fnext(edca, acecasing); + enqueueflipface(acecasing, flipqueue); + } + + // Save a live handle in 'recenttet'. + recenttet = edbc; + // Set the return handle be edab. + *flipface = edab; +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// flip32() Perform a 3-to-2 flip. // +// // +// On input, 'flipface' represents the face will be flipped. Let it is eda, // +// where edge ed is locally non-convex. Three tetrahedra sharing ed are edab,// +// edbc, and edca. ed is not a subsegment. // +// // +// A 3-to-2 flip is to change the three tetrahedra edab, edbc, and edca into // +// another two tetrahedra abcd and bace. As a result, the edge ed has been // +// removed and the face abc has been created. // +// // +// On completion, 'flipface' returns abcd. If 'flipqueue' is not NULL, all // +// possibly non-Delaunay faces are added into it. // +// // +/////////////////////////////////////////////////////////////////////////////// + +void tetgenmesh::flip32(triface* flipface, queue* flipqueue) +{ + triface edab, edbc, edca; // Old configuration. + triface oldabd, oldbcd, oldcad; + triface abdcasing, bcdcasing, cadcasing; + face abdsh, bcdsh, cadsh; + triface oldbae, oldcbe, oldace; + triface baecasing, cbecasing, acecasing; + face baesh, cbesh, acesh; + triface abcd, bace; // New configuration. + point pa, pb, pc, pd, pe; + int i; + + edab = *flipface; + adjustedgering(edab, CCW); + fnext(edab, edbc); + symself(edbc); + findedge(&edbc, org(edab), dest(edab)); + fnext(edbc, edca); + symself(edca); + findedge(&edca, org(edab), dest(edab)); + pa = apex(edab); + pb = oppo(edab); + pc = oppo(edbc); + pd = dest(edab); + pe = org(edab); + + if (b->verbose > 2) { + printf(" Do T32 on face (%d, %d, %d, %d).\n", + pointmark(pe), pointmark(pd), pointmark(pa), pointmark(pb)); + } + flip32s++; + +#ifdef SELF_CHECK + // Edge de must cross face abc properly. + assert(orient3d(pa, pb, pc, pd) <= 0.0); + assert(orient3d(pb, pa, pc, pe) <= 0.0); +#endif + + // Storing the old configuration outside the convex hull. + enextfnext(edab, oldabd); + enext2fnext(edab, oldbae); + enextfnext(edbc, oldbcd); + enext2fnext(edbc, oldcbe); + enextfnext(edca, oldcad); + enext2fnext(edca, oldace); + sym(oldabd, abdcasing); + sym(oldbcd, bcdcasing); + sym(oldcad, cadcasing); + sym(oldbae, baecasing); + sym(oldcbe, cbecasing); + sym(oldace, acecasing); + if (checksubfaces) { + tspivot(oldabd, abdsh); + tspivot(oldbcd, bcdsh); + tspivot(oldcad, cadsh); + tspivot(oldbae, baesh); + tspivot(oldcbe, cbesh); + tspivot(oldace, acesh); + } + + // Creating the new configuration inside the convex hull. + abcd.tet = edab.tet; // Update edab to be abcd. + setorg (abcd, pa); + setdest(abcd, pb); + setapex(abcd, pc); + setoppo(abcd, pd); + bace.tet = edbc.tet; // Update edbc to be bace. + setorg (bace, pb); + setdest(bace, pa); + setapex(bace, pc); + setoppo(bace, pe); + // Dealloc a redundant tetrahedron (edca). + tetrahedrondealloc(edca.tet); + + // Clear the old bonds in abcd (was edab) and bace (was edbc). + for (i = 0; i < 4; i ++) { + abcd.loc = i; + dissolve(abcd); + bace.loc = i; + dissolve(bace); + } + // Bond the inside face of the convex hull. + abcd.loc = 0; + bace.loc = 0; + bond(abcd, bace); + // Bond the outside faces of the convex hull. + abcd.loc = 1; + bond(abcd, abdcasing); + abcd.loc = 2; + bond(abcd, bcdcasing); + abcd.loc = 3; + bond(abcd, cadcasing); + bace.loc = 1; + bond(bace, baecasing); + bace.loc = 3; + bond(bace, cbecasing); + bace.loc = 2; + bond(bace, acecasing); + if (checksubfaces) { + // Clear old bonds in abcd(was edab) and bace(was edbc). + for (i = 0; i < 4; i ++) { + abcd.loc = i; + tsdissolve(abcd); + bace.loc = i; + tsdissolve(bace); + } + if (abdsh.sh != dummysh) { + abcd.loc = 1; + tsbond(abcd, abdsh); + } + if (baesh.sh != dummysh) { + bace.loc = 1; + tsbond(bace, baesh); + } + if (bcdsh.sh != dummysh) { + abcd.loc = 2; + tsbond(abcd, bcdsh); + } + if (cbesh.sh != dummysh) { + bace.loc = 3; + tsbond(bace, cbesh); + } + if (cadsh.sh != dummysh) { + abcd.loc = 3; + tsbond(abcd, cadsh); + } + if (acesh.sh != dummysh) { + bace.loc = 2; + tsbond(bace, acesh); + } + } + + abcd.loc = 0; + bace.loc = 0; + if (b->verbose > 3) { + printf(" Updating abcd "); + printtet(&abcd); + printf(" Updating bace "); + printtet(&bace); + printf(" Deleting edca "); + printtet(&edca); + } + + if (flipqueue != (queue *) NULL) { + fnext(abcd, abdcasing); + enqueueflipface(abdcasing, flipqueue); + fnext(bace, baecasing); + enqueueflipface(baecasing, flipqueue); + enextfnext(abcd, bcdcasing); + enqueueflipface(bcdcasing, flipqueue); + enextfnext(bace, cbecasing); + enqueueflipface(cbecasing, flipqueue); + enext2fnext(abcd, cadcasing); + enqueueflipface(cadcasing, flipqueue); + enext2fnext(bace, acecasing); + enqueueflipface(acecasing, flipqueue); + } + + // Save a live handle in 'recenttet'. + recenttet = abcd; + // Set the return handle be abcd. + *flipface = abcd; +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// flip22() Perform a 2-to-2 (or 4-to-4) flip. // +// // +// On input, 'flipface' represents the face will be flipped. Let it is abe, // +// ab is the flipable edge, the two tetrahedra sharing abe are abce and bade,// +// hence a, b, c and d are coplanar. If abc, bad are interior faces, the two // +// tetrahedra opposite to e are bacf and abdf. ab is not a subsegment. // +// // +// A 2-to-2 flip is to change two tetrahedra abce and bade into another two // +// tetrahedra dcae and cdbe. If bacf and abdf exist, they're changed to cdaf // +// and dcbf, thus a 4-to-4 flip. As a result, two or four tetrahedra have // +// rotated counterclockwise (using right-hand rule with thumb points to e): // +// abce->dcae, bade->cdbe, and bacf->cdaf, abdf->dcbf. // +// // +// If abc and bad are subfaces, a 2-to-2 flip is performed simultaneously by // +// calling routine flip22sub(), hence abc->dca, bad->cdb. The edge rings of // +// the flipped subfaces dca and cdb have the same orientation as abc and bad.// +// Hence, they have the same orientation as other subfaces of the facet with // +// respect to the lift point of this facet. // +// // +// On completion, 'flipface' holds edge dc of tetrahedron dcae. 'flipqueue' // +// contains all possibly non-Delaunay faces if it is not NULL. // +// // +/////////////////////////////////////////////////////////////////////////////// + +void tetgenmesh::flip22(triface* flipface, queue* flipqueue) +{ + triface abce, bade; + triface oldbce, oldcae, oldade, olddbe; + triface bcecasing, caecasing, adecasing, dbecasing; + face bcesh, caesh, adesh, dbesh; + triface bacf, abdf; + triface oldacf, oldcbf, oldbdf, olddaf; + triface acfcasing, cbfcasing, bdfcasing, dafcasing; + face acfsh, cbfsh, bdfsh, dafsh; + face abc, bad; + point pa, pb, pc, pd, pe, pf; + int mirrorflag; + + adjustedgering(*flipface, CCW); // 'flipface' is bae. + fnext(*flipface, abce); + esymself(abce); + adjustedgering(*flipface, CW); // 'flipface' is abe. + fnext(*flipface, bade); + assert(bade.tet != dummytet); + esymself(bade); + pa = org(abce); + pb = dest(abce); + pc = apex(abce); + pd = apex(bade); + pe = oppo(bade); + assert(oppo(abce) == pe); + sym(abce, bacf); + mirrorflag = bacf.tet != dummytet; + if (mirrorflag) { + findedge(&bacf, pb, pa); + sym(bade, abdf); + assert(abdf.tet != dummytet); + findedge(&abdf, pa, pb); + pf = oppo(bacf); + assert(oppo(abdf) == pf); + } + + if (b->verbose > 2) { + printf(" Do %s on edge (%d, %d).\n", mirrorflag ? "T44" : "T22", + pointmark(pa), pointmark(pb)); + } + mirrorflag ? flip44s++ : flip22s++; + +#ifdef SELF_CHECK + // The quadrilateral formed by a, b, c, and d must be convex. + assert(orient3d(pc, pd, pe, pa) <= 0.0); + assert(orient3d(pd, pc, pe, pb) <= 0.0); +#endif + + // Save the old configuration at the convex hull. + enextfnext(abce, oldbce); + enext2fnext(abce, oldcae); + enextfnext(bade, oldade); + enext2fnext(bade, olddbe); + sym(oldbce, bcecasing); + sym(oldcae, caecasing); + sym(oldade, adecasing); + sym(olddbe, dbecasing); + if (checksubfaces) { + tspivot(oldbce, bcesh); + tspivot(oldcae, caesh); + tspivot(oldade, adesh); + tspivot(olddbe, dbesh); + tspivot(abce, abc); + tspivot(bade, bad); + } + if (mirrorflag) { + enextfnext(bacf, oldacf); + enext2fnext(bacf, oldcbf); + enextfnext(abdf, oldbdf); + enext2fnext(abdf, olddaf); + sym(oldacf, acfcasing); + sym(oldcbf, cbfcasing); + sym(oldbdf, bdfcasing); + sym(olddaf, dafcasing); + if (checksubfaces) { + tspivot(oldacf, acfsh); + tspivot(oldcbf, cbfsh); + tspivot(oldbdf, bdfsh); + tspivot(olddaf, dafsh); + } + } + + // Rotate abce, bade one-quarter turn counterclockwise. + bond(oldbce, caecasing); + bond(oldcae, adecasing); + bond(oldade, dbecasing); + bond(olddbe, bcecasing); + if (checksubfaces) { + // Check for subfaces and rebond them to the rotated tets. + if (caesh.sh == dummysh) { + tsdissolve(oldbce); + } else { + tsbond(oldbce, caesh); + } + if (adesh.sh == dummysh) { + tsdissolve(oldcae); + } else { + tsbond(oldcae, adesh); + } + if (dbesh.sh == dummysh) { + tsdissolve(oldade); + } else { + tsbond(oldade, dbesh); + } + if (bcesh.sh == dummysh) { + tsdissolve(olddbe); + } else { + tsbond(olddbe, bcesh); + } + } + if (mirrorflag) { + // Rotate bacf, abdf one-quarter turn counterclockwise. + bond(oldcbf, acfcasing); + bond(oldacf, dafcasing); + bond(olddaf, bdfcasing); + bond(oldbdf, cbfcasing); + if (checksubfaces) { + // Check for subfaces and rebond them to the rotated tets. + if (acfsh.sh == dummysh) { + tsdissolve(oldcbf); + } else { + tsbond(oldcbf, acfsh); + } + if (dafsh.sh == dummysh) { + tsdissolve(oldacf); + } else { + tsbond(oldacf, dafsh); + } + if (bdfsh.sh == dummysh) { + tsdissolve(olddaf); + } else { + tsbond(olddaf, bdfsh); + } + if (cbfsh.sh == dummysh) { + tsdissolve(oldbdf); + } else { + tsbond(oldbdf, cbfsh); + } + } + } + + // New vertex assignments for the rotated tetrahedra. + setorg(abce, pd); // Update abce to dcae + setdest(abce, pc); + setapex(abce, pa); + setorg(bade, pc); // Update bade to cdbe + setdest(bade, pd); + setapex(bade, pb); + if (mirrorflag) { + setorg(bacf, pc); // Update bacf to cdaf + setdest(bacf, pd); + setapex(bacf, pa); + setorg(abdf, pd); // Update abdf to dcbf + setdest(abdf, pc); + setapex(abdf, pb); + } + + // Are there subfaces need to be flipped? + if (checksubfaces && abc.sh != dummysh) { + assert(bad.sh != dummysh); + // Adjust the edge be ab, so the rotation of subfaces is according with + // the rotation of tetrahedra. + findedge(&abc, pa, pb); + // Flip an edge of two subfaces, ignore non-Delaunay edges. + flip22sub(&abc, NULL); + } + + if (b->verbose > 3) { + printf(" Updating abce "); + printtet(&abce); + printf(" Updating bade "); + printtet(&bade); + if (mirrorflag) { + printf(" Updating bacf "); + printtet(&bacf); + printf(" Updating abdf "); + printtet(&abdf); + } + } + + if (flipqueue != (queue *) NULL) { + enextfnext(abce, bcecasing); + enqueueflipface(bcecasing, flipqueue); + enext2fnext(abce, caecasing); + enqueueflipface(caecasing, flipqueue); + enextfnext(bade, adecasing); + enqueueflipface(adecasing, flipqueue); + enext2fnext(bade, dbecasing); + enqueueflipface(dbecasing, flipqueue); + if (mirrorflag) { + enextfnext(bacf, acfcasing); + enqueueflipface(acfcasing, flipqueue); + enext2fnext(bacf, cbfcasing); + enqueueflipface(cbfcasing, flipqueue); + enextfnext(abdf, bdfcasing); + enqueueflipface(bdfcasing, flipqueue); + enext2fnext(abdf, dafcasing); + enqueueflipface(dafcasing, flipqueue); + } + // The two new faces dcae (abce), cdbe (bade) may still not be locally + // Delaunay, and may need be flipped (flip23). On the other hand, in + // conforming Delaunay algorithm, two new subfaces dca (abc), and cdb + // (bad) may be non-conforming Delaunay, they need be queued if they + // are locally Delaunay but non-conforming Delaunay. + enqueueflipface(abce, flipqueue); + enqueueflipface(bade, flipqueue); + } + + // Save a live handle in 'recenttet'. + recenttet = abce; +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// flip22sub() Perform a 2-to-2 flip on a subface edge. // +// // +// The flip edge is given by subface 'flipedge'. Let it is abc, where ab is // +// the flipping edge. The other subface is bad, where a, b, c, d form a // +// convex quadrilateral. ab is not a subsegment. // +// // +// A 2-to-2 subface flip is to change two subfaces abc and bad to another // +// two subfaces dca and cdb. Hence, edge ab has been removed and dc becomes // +// an edge. If a point e is above abc, this flip is equal to rotate abc and // +// bad counterclockwise using right-hand rule with thumb points to e. It is // +// important to know that the edge rings of the flipped subfaces dca and cdb // +// are keeping the same orientation as their original subfaces. So they have // +// the same orientation with respect to the lift point of this facet. // +// // +// During rotating, the face rings of the four edges bc, ca, ad, and de need // +// be re-connected. If the edge is not a subsegment, then its face ring has // +// only two faces, a sbond() will bond them together. If it is a subsegment, // +// one should use sbond1() twice to bond two different handles to the rotat- // +// ing subface, one is predecssor (-casin), another is successor (-casout). // +// // +// If 'flipqueue' is not NULL, it returns four edges bc, ca, ad, de, which // +// may be non-Delaunay. // +// // +/////////////////////////////////////////////////////////////////////////////// + +void tetgenmesh::flip22sub(face* flipedge, queue* flipqueue) +{ + face abc, bad; + face oldbc, oldca, oldad, olddb; + face bccasin, bccasout, cacasin, cacasout; + face adcasin, adcasout, dbcasin, dbcasout; + face bc, ca, ad, db; + face spinsh; + point pa, pb, pc, pd; + + abc = *flipedge; + spivot(abc, bad); + if (sorg(bad) != sdest(abc)) { + sesymself(bad); + } + pa = sorg(abc); + pb = sdest(abc); + pc = sapex(abc); + pd = sapex(bad); + + if (b->verbose > 2) { + printf(" Flip sub edge (%d, %d).\n", pointmark(pa), pointmark(pb)); + } + + // Save the old configuration outside the quadrilateral. + senext(abc, oldbc); + senext2(abc, oldca); + senext(bad, oldad); + senext2(bad, olddb); + // Get the outside connection. Becareful if there is a subsegment on the + // quadrilateral, two casings (casin and casout) are needed to save for + // keeping the face link. + spivot(oldbc, bccasout); + sspivot(oldbc, bc); + if (bc.sh != dummysh) { + // 'bc' is a subsegment. + assert(bccasout.sh != dummysh); + if (oldbc.sh != bccasout.sh) { + // 'oldbc' is not self-bonded. + spinsh = bccasout; + do { + bccasin = spinsh; + spivotself(spinsh); + } while (spinsh.sh != oldbc.sh); + } else { + bccasout.sh = dummysh; + } + ssdissolve(oldbc); + } + spivot(oldca, cacasout); + sspivot(oldca, ca); + if (ca.sh != dummysh) { + // 'ca' is a subsegment. + assert(cacasout.sh != dummysh); + if (oldca.sh != cacasout.sh) { + // 'oldca' is not self-bonded. + spinsh = cacasout; + do { + cacasin = spinsh; + spivotself(spinsh); + } while (spinsh.sh != oldca.sh); + } else { + cacasout.sh = dummysh; + } + ssdissolve(oldca); + } + spivot(oldad, adcasout); + sspivot(oldad, ad); + if (ad.sh != dummysh) { + // 'ad' is a subsegment. + assert(adcasout.sh != dummysh); + if (oldad.sh != adcasout.sh) { + // 'adcasout' is not self-bonded. + spinsh = adcasout; + do { + adcasin = spinsh; + spivotself(spinsh); + } while (spinsh.sh != oldad.sh); + } else { + adcasout.sh = dummysh; + } + ssdissolve(oldad); + } + spivot(olddb, dbcasout); + sspivot(olddb, db); + if (db.sh != dummysh) { + // 'db' is a subsegment. + assert(dbcasout.sh != dummysh); + if (olddb.sh != dbcasout.sh) { + // 'dbcasout' is not self-bonded. + spinsh = dbcasout; + do { + dbcasin = spinsh; + spivotself(spinsh); + } while (spinsh.sh != olddb.sh); + } else { + dbcasout.sh = dummysh; + } + ssdissolve(olddb); + } + + // Rotate abc and bad one-quarter turn counterclockwise. + if (ca.sh != dummysh) { + if (cacasout.sh != dummysh) { + sbond1(cacasin, oldbc); + sbond1(oldbc, cacasout); + } else { + // Bond 'oldbc' to itself. + sbond(oldbc, oldbc); + // Make sure that dummysh always correctly bonded. + dummysh[0] = sencode(oldbc); + } + ssbond(oldbc, ca); + } else { + sbond(oldbc, cacasout); + } + if (ad.sh != dummysh) { + if (adcasout.sh != dummysh) { + sbond1(adcasin, oldca); + sbond1(oldca, adcasout); + } else { + // Bond 'oldca' to itself. + sbond(oldca, oldca); + // Make sure that dummysh always correctly bonded. + dummysh[0] = sencode(oldca); + } + ssbond(oldca, ad); + } else { + sbond(oldca, adcasout); + } + if (db.sh != dummysh) { + if (dbcasout.sh != dummysh) { + sbond1(dbcasin, oldad); + sbond1(oldad, dbcasout); + } else { + // Bond 'oldad' to itself. + sbond(oldad, oldad); + // Make sure that dummysh always correctly bonded. + dummysh[0] = sencode(oldad); + } + ssbond(oldad, db); + } else { + sbond(oldad, dbcasout); + } + if (bc.sh != dummysh) { + if (bccasout.sh != dummysh) { + sbond1(bccasin, olddb); + sbond1(olddb, bccasout); + } else { + // Bond 'olddb' to itself. + sbond(olddb, olddb); + // Make sure that dummysh always correctly bonded. + dummysh[0] = sencode(olddb); + } + ssbond(olddb, bc); + } else { + sbond(olddb, bccasout); + } + + // New vertex assignments for the rotated subfaces. + setsorg(abc, pd); // Update abc to dca. + setsdest(abc, pc); + setsapex(abc, pa); + setsorg(bad, pc); // Update bad to cdb. + setsdest(bad, pd); + setsapex(bad, pb); + + if (flipqueue != (queue *) NULL) { + enqueueflipedge(bccasout, flipqueue); + enqueueflipedge(cacasout, flipqueue); + enqueueflipedge(adcasout, flipqueue); + enqueueflipedge(dbcasout, flipqueue); + } +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// flip() Flips non-locally Delaunay faces in flipqueue until it is empty.// +// // +// Assumpation: Current tetrahedralization is non-Delaunay after inserting // +// a point or performing a flip operation, all possibly non-Delaunay faces // +// are in 'flipqueue'. // +// // +// If 'plastflip' is not NULL, it is used to return a stack of recently // +// flipped faces. This stack will be used to reverse the flips done in this // +// routine later for removing a newly inserted point because it encroaches // +// any subfaces or subsegments. // +// // +// If the quality mesh step is starting, (indicated by pools 'badsubsegs', // +// 'badsubfaces' and 'badtetrahedrons' are not NULLs.) we will check the // +// encroached subface or subsegments of a hull face, and queuing tetrahedra // +// for quality checking. // +// // +// The return value is the total number of flips done during this invocation.// +// // +/////////////////////////////////////////////////////////////////////////////// + +long tetgenmesh::flip(queue* flipqueue, flipstacker **plastflip) +{ + badface *qface; + flipstacker *newflip; + triface flipface, symface; + face checkseg, checksh; + enum fliptype fc; + bool flipped; + REAL sign, bakepsilon; + long flipcount; + int epscount; + int i; + + if (b->verbose > 1) { + printf(" Do flipface queue: %ld faces.\n", flipqueue->len()); + } + + flipcount = flip23s + flip32s + flip22s + flip44s; + + if (plastflip != (flipstacker **) NULL) { + // Initialize the stack of the flip sequence. + flipstackers->restart(); + *plastflip = (flipstacker *) NULL; + } + + // Loop until the queue is empty. + while ((qface = (badface *) flipqueue->pop()) != NULL) { + // Get a face. + flipface = qface->tt; + // Check the validity of this face. + if (isdead(&flipface) || flipface.tet == dummytet || + (org(flipface) != qface->forg) || + (dest(flipface) != qface->fdest) || + (apex(flipface) != qface->fapex) || + (oppo(flipface) == (point) NULL)) continue; + flipped = false; + sym(flipface, symface); + // Only do check when the adjacent tet exists and it's not a "fake" tet. + if (symface.tet != dummytet && oppo(symface) != (point) NULL) { + // For positive orientation that insphere() test requires. + adjustedgering(flipface, CW); + sign = insphere(org(flipface), dest(flipface), apex(flipface), + oppo(flipface), oppo(symface)); + } else { + sign = -1.0; // A hull face is locally Delaunay. + } + if (sign > 0.0) { + // 'flipface' is non-locally Delaunay, try to flip it. + if (checksubfaces) { + bakepsilon = b->epsilon; + epscount = 0; + while (epscount < 16) { + fc = categorizeface(flipface); + if (fc == NONCONVEX) { + b->epsilon *= 1e-2; + epscount++; + continue; + } + break; + } + b->epsilon = bakepsilon; + // assert(epscount < 16); + if (epscount == 16) { + if (b->verbose) { + printf("Warning: Can't flip a degenerate tetrahedron.\n"); + } + fc = NONCONVEX; + } + } else { + fc = categorizeface(flipface); + assert(fc != NONCONVEX); + } + switch (fc) { + // The following face types are flipable. + case T44: + case T22: + flip22(&flipface, flipqueue); + flipped = true; + break; + case T23: + flip23(&flipface, flipqueue); + flipped = true; + break; + case T32: + flip32(&flipface, flipqueue); + flipped = true; + break; + // The following face types are unflipable. + case UNFLIPABLE: + break; + case FORBIDDENFACE: + // Meet an encroaching subface, unflipable. + break; + case FORBIDDENEDGE: + // Meet an encroaching subsegment, unflipable. + break; + // This case is only possible when the domain is nonconvex. + case NONCONVEX: + assert(nonconvex); + break; + } + if (plastflip != (flipstacker **) NULL && flipped) { + // Push the flipped face into stack. + newflip = (flipstacker *) flipstackers->alloc(); + newflip->flippedface = flipface; + newflip->fc = fc; + newflip->forg = org(flipface); + newflip->fdest = dest(flipface); + newflip->fapex = apex(flipface); + newflip->prevflip = *plastflip; + *plastflip = newflip; + } + } + if (!flipped) { + // 'flipface' is locally Delaunay, or it is non-locally Delaunay but + // not flipable because it is a subface or contains a subsegment. + if (badsubsegs != (memorypool *) NULL) { + // Check for encroaching subsegments, add them into list. + for (i = 0; i < 3; i++) { + tsspivot(&flipface, &checkseg); + if ((checkseg.sh != dummysh) && !shell2badface(checkseg)) { + checkseg4encroach(&checkseg, NULL, true); + } + enextself(flipface); + } + } + if (badsubfaces != (memorypool *) NULL) { + // Check for encroaching subface, add it into list. + tspivot(flipface, checksh); + if ((checksh.sh != dummysh) && !shell2badface(checksh)) { + checksub4encroach(&checksh, NULL, true); + } + } + if (badtetrahedrons != (memorypool *) NULL) { + // Put the tetrahedra at both sides into list for quality check. + qualchecktetlist->append(&flipface); + if (symface.tet != dummytet) { + qualchecktetlist->append(&symface); + } + } + } + } + + flipcount = flip23s + flip32s + flip22s + flip44s - flipcount; + if (b->verbose > 1) { + printf(" %ld flips.\n", flipcount); + } + + return flipcount; +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// undoflip() Undo the most recent flip sequence induced by flip(). // +// // +// 'lastflip' is the stack of recently flipped faces. Walks through the list // +// of flips, in the reverse of the order in which they were done, and undoes // +// them. // +// // +/////////////////////////////////////////////////////////////////////////////// + +void tetgenmesh::undoflip(flipstacker *lastflip) +{ + while (lastflip != (flipstacker *) NULL) { + // Get the right flipped face. + findface(&lastflip->flippedface, lastflip->forg, lastflip->fdest, + lastflip->fapex); + switch (lastflip->fc) { + case T23: + // The reverse operation of T23 is T32. + flip32(&lastflip->flippedface, NULL); + break; + case T32: + // The reverse operation of T32 is T23. + flip23(&lastflip->flippedface, NULL); + break; + case T22: + case T44: + // The reverse operation of T22 or T44 is again T22 or T44. + flip22(&lastflip->flippedface, NULL); + break; + } + // Go on and process the next transformation. + lastflip = lastflip->prevflip; + } +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// splittetrahedron() Insert a point into a tetrahedron, split it into // +// four tetrahedra. // +// // +// The tetrahedron is given by 'splittet'. Let it is abcd. The inserting // +// point 'newpoint' v should lie strictly inside abcd. // +// // +// Splitting a tetrahedron is to shrink abcd to abcv, and create three new // +// tetrahedra badv, cbdv, and acdv. // +// // +// On completion, 'splittet' returns abcv. If 'flipqueue' is not NULL, it // +// contains all possibly non-locally Delaunay faces. // +// // +/////////////////////////////////////////////////////////////////////////////// + +void tetgenmesh:: +splittetrahedron(point newpoint, triface* splittet, queue* flipqueue) +{ + triface oldabd, oldbcd, oldcad; // Old configuration. + triface abdcasing, bcdcasing, cadcasing; + face abdsh, bcdsh, cadsh; + triface abcv, badv, cbdv, acdv; // New configuration. + point pa, pb, pc, pd; + REAL attrib, volume; + int i; + + abcv = *splittet; + abcv.ver = 0; + // Set the changed vertices and new tetrahedron. + pa = org(abcv); + pb = dest(abcv); + pc = apex(abcv); + pd = oppo(abcv); + + if (b->verbose > 1) { + printf(" Inserting point %d in tetrahedron (%d, %d, %d, %d).\n", + pointmark(newpoint), pointmark(pa), pointmark(pb), pointmark(pc), + pointmark(pd)); + } + + fnext(abcv, oldabd); + enextfnext(abcv, oldbcd); + enext2fnext(abcv, oldcad); + sym(oldabd, abdcasing); + sym(oldbcd, bcdcasing); + sym(oldcad, cadcasing); + maketetrahedron(&badv); + maketetrahedron(&cbdv); + maketetrahedron(&acdv); + + // Set 'badv' vertices. + setorg (badv, pb); + setdest(badv, pa); + setapex(badv, pd); + setoppo(badv, newpoint); + // Set 'cbdv' vertices. + setorg (cbdv, pc); + setdest(cbdv, pb); + setapex(cbdv, pd); + setoppo(cbdv, newpoint); + // Set 'acdv' vertices. + setorg (acdv, pa); + setdest(acdv, pc); + setapex(acdv, pd); + setoppo(acdv, newpoint); + // Set 'abcv' vertices + setoppo(abcv, newpoint); + + // Set the element attributes of the new tetrahedra. + for (i = 0; i < in->numberoftetrahedronattributes; i++) { + attrib = elemattribute(abcv.tet, i); + setelemattribute(badv.tet, i, attrib); + setelemattribute(cbdv.tet, i, attrib); + setelemattribute(acdv.tet, i, attrib); + } + // Set the volume constraint of the new tetrahedra. + if (b->varvolume) { + volume = volumebound(abcv.tet); + setvolumebound(badv.tet, volume); + setvolumebound(cbdv.tet, volume); + setvolumebound(acdv.tet, volume); + } + + // Bond the new triangles to the surrounding tetrahedron. + bond(badv, abdcasing); + bond(cbdv, bcdcasing); + bond(acdv, cadcasing); + // There may exist subfaces need to be bonded to the new tetrahedra. + if (checksubfaces) { + tspivot(oldabd, abdsh); + if (abdsh.sh != dummysh) { + tsdissolve(oldabd); + tsbond(badv, abdsh); + } + tspivot(oldbcd, bcdsh); + if (bcdsh.sh != dummysh) { + tsdissolve(oldbcd); + tsbond(cbdv, bcdsh); + } + tspivot(oldcad, cadsh); + if (cadsh.sh != dummysh) { + tsdissolve(oldcad); + tsbond(acdv, cadsh); + } + } + badv.loc = 3; + cbdv.loc = 2; + bond(badv, cbdv); + cbdv.loc = 3; + acdv.loc = 2; + bond(cbdv, acdv); + acdv.loc = 3; + badv.loc = 2; + bond(acdv, badv); + badv.loc = 1; + bond(badv, oldabd); + cbdv.loc = 1; + bond(cbdv, oldbcd); + acdv.loc = 1; + bond(acdv, oldcad); + + badv.loc = 0; + cbdv.loc = 0; + acdv.loc = 0; + if (b->verbose > 3) { + printf(" Updating abcv "); + printtet(&abcv); + printf(" Creating badv "); + printtet(&badv); + printf(" Creating cbdv "); + printtet(&cbdv); + printf(" Creating acdv "); + printtet(&acdv); + } + + if (flipqueue != (queue *) NULL) { + enqueueflipface(abcv, flipqueue); + enqueueflipface(badv, flipqueue); + enqueueflipface(cbdv, flipqueue); + enqueueflipface(acdv, flipqueue); + } + + // Save a handle for quick point location. + recenttet = abcv; + // Set the return handle be abcv. + *splittet = abcv; +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// unsplittetrahedron() Reverse the operation of inserting a point into a // +// tetrahedron, so as to remove the newly inserted // +// point from the mesh. // +// // +// Assume the origional tetrahedron is abcd, it was split by v into four // +// tetrahedra abcv, badv, cbdv, and acdv. 'splittet' represents face abc of // +// abcv (i.e., its opposite is v). // +// // +// Point v is removed by expanding abcv to abcd, deleting three tetrahedra // +// badv, cbdv and acdv. On return, point v is not deleted in this routine. // +// // +/////////////////////////////////////////////////////////////////////////////// + +void tetgenmesh::unsplittetrahedron(triface* splittet) +{ + triface abcv, badv, cbdv, acdv; + triface oldabv, oldbcv, oldcav; + triface badcasing, cbdcasing, acdcasing; + face badsh, cbdsh, acdsh; + + abcv = *splittet; + adjustedgering(abcv, CCW); // for sure. + fnext(abcv, oldabv); + fnext(oldabv, badv); + esymself(badv); + enextfnext(abcv, oldbcv); + fnext(oldbcv, cbdv); + esymself(cbdv); + enext2fnext(abcv, oldcav); + fnext(oldcav, acdv); + esymself(acdv); + + if (b->verbose > 1) { + printf(" Removing point %d in tetrahedron (%d, %d, %d, %d).\n", + pointmark(oppo(abcv)), pointmark(org(abcv)), pointmark(dest(abcv)), + pointmark(apex(abcv)), pointmark(apex(badv))); + } + + sym(badv, badcasing); + tspivot(badv, badsh); + sym(cbdv, cbdcasing); + tspivot(cbdv, cbdsh); + sym(acdv, acdcasing); + tspivot(acdv, acdsh); + + // Expanding abcv to abcd. + setoppo(abcv, apex(badv)); + bond(oldabv, badcasing); + if (badsh.sh != dummysh) { + tsbond(oldabv, badsh); + } + bond(oldbcv, cbdcasing); + if (cbdsh.sh != dummysh) { + tsbond(oldbcv, cbdsh); + } + bond(oldcav, acdcasing); + if (acdsh.sh != dummysh) { + tsbond(oldcav, acdsh); + } + + // Delete the three split-out tetrahedra. + tetrahedrondealloc(badv.tet); + tetrahedrondealloc(cbdv.tet); + tetrahedrondealloc(acdv.tet); +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// splittetface() Insert a point on a face of a mesh. // +// // +// 'splittet' is the splitting face. Let it is abcd, where abc is the face // +// will be split. If abc is not a hull face, abce is the tetrahedron at the // +// opposite of d. // +// // +// To split face abc by a point v is to shrink the tetrahedra abcd to abvd, // +// create two new tetrahedra bcvd, cavd. If abc is not a hull face, shrink // +// the tetrahedra bace to bave, create two new tetrahedra cbve, acve. // +// // +// If abc is a subface, it is split into three subfaces simultaneously by // +// calling routine splitsubface(), hence, abv, bcv, cav. The edge rings of // +// the split subfaces have the same orientation as abc's. // +// // +// On completion, 'splittet' returns abvd. If 'flipqueue' is not NULL, it // +// contains all possibly non-locally Delaunay faces. // +// // +/////////////////////////////////////////////////////////////////////////////// + +void tetgenmesh:: +splittetface(point newpoint, triface* splittet, queue* flipqueue) +{ + triface abcd, bace; // Old configuration. + triface oldbcd, oldcad, oldace, oldcbe; + triface bcdcasing, cadcasing, acecasing, cbecasing; + face abcsh, bcdsh, cadsh, acesh, cbesh; + triface abvd, bcvd, cavd, bave, cbve, acve; // New configuration. + point pa, pb, pc, pd, pe; + REAL attrib, volume; + bool mirrorflag; + int i; + + abcd = *splittet; + // abcd.ver = 0; // Adjust to be CCW edge ring. + adjustedgering(abcd, CCW); + pa = org(abcd); + pb = dest(abcd); + pc = apex(abcd); + pd = oppo(abcd); + // Is there a second tetrahderon? + mirrorflag = issymexist(&abcd); + if (mirrorflag) { + // This is an interior face. + sym(abcd, bace); + findedge(&bace, dest(abcd), org(abcd)); + pe = oppo(bace); + } + if (checksubfaces) { + // Is there a subface need to be split together? + tspivot(abcd, abcsh); + if (abcsh.sh != dummysh) { + // Exists! Keep the edge ab of both handles be the same. + findedge(&abcsh, org(abcd), dest(abcd)); + } + } + + if (b->verbose > 1) { + printf(" Inserting point %d on face (%d, %d, %d).\n", pointmark(newpoint), + pointmark(pa), pointmark(pb), pointmark(pc)); + } + +#ifdef SELF_CHECK + // Make sure no inversed tetrahedron has been created. + assert(orient3d(pa, pb, pd, newpoint) >= 0.0); + assert(orient3d(pb, pc, pd, newpoint) >= 0.0); + assert(orient3d(pc, pa, pd, newpoint) >= 0.0); +#endif + + // Save the old configuration at faces bcd and cad. + enextfnext(abcd, oldbcd); + enext2fnext(abcd, oldcad); + sym(oldbcd, bcdcasing); + sym(oldcad, cadcasing); + // Create two new tetrahedra. + maketetrahedron(&bcvd); + maketetrahedron(&cavd); + if (mirrorflag) { + // Save the old configuration at faces bce and cae. + enextfnext(bace, oldace); + enext2fnext(bace, oldcbe); + sym(oldace, acecasing); + sym(oldcbe, cbecasing); + // Create two new tetrahedra. + maketetrahedron(&acve); + maketetrahedron(&cbve); + } else { + // Splitting a boundary face increases the number of boundary faces. + hullsize += 2; + } + + // Set vertices to the changed tetrahedron and new tetrahedra. + abvd = abcd; // Update 'abcd' to 'abvd'. + setapex(abvd, newpoint); + setorg (bcvd, pb); // Set 'bcvd'. + setdest(bcvd, pc); + setapex(bcvd, newpoint); + setoppo(bcvd, pd); + setorg (cavd, pc); // Set 'cavd'. + setdest(cavd, pa); + setapex(cavd, newpoint); + setoppo(cavd, pd); + // Set the element attributes of the new tetrahedra. + for (i = 0; i < in->numberoftetrahedronattributes; i++) { + attrib = elemattribute(abvd.tet, i); + setelemattribute(bcvd.tet, i, attrib); + setelemattribute(cavd.tet, i, attrib); + } + if (b->varvolume) { + // Set the area constraint of the new tetrahedra. + volume = volumebound(abvd.tet); + setvolumebound(bcvd.tet, volume); + setvolumebound(cavd.tet, volume); + } + if (mirrorflag) { + bave = bace; // Update 'bace' to 'bave'. + setapex(bave, newpoint); + setorg (acve, pa); // Set 'acve'. + setdest(acve, pc); + setapex(acve, newpoint); + setoppo(acve, pe); + setorg (cbve, pc); // Set 'cbve'. + setdest(cbve, pb); + setapex(cbve, newpoint); + setoppo(cbve, pe); + // Set the element attributes of the new tetrahedra. + for (i = 0; i < in->numberoftetrahedronattributes; i++) { + attrib = elemattribute(bave.tet, i); + setelemattribute(acve.tet, i, attrib); + setelemattribute(cbve.tet, i, attrib); + } + if (b->varvolume) { + // Set the area constraint of the new tetrahedra. + volume = volumebound(bave.tet); + setvolumebound(acve.tet, volume); + setvolumebound(cbve.tet, volume); + } + } + + // Bond the new tetrahedra to the surrounding tetrahedra. + bcvd.loc = 1; + bond(bcvd, bcdcasing); + cavd.loc = 1; + bond(cavd, cadcasing); + bcvd.loc = 3; + bond(bcvd, oldbcd); + cavd.loc = 2; + bond(cavd, oldcad); + bcvd.loc = 2; + cavd.loc = 3; + bond(bcvd, cavd); + if (mirrorflag) { + acve.loc = 1; + bond(acve, acecasing); + cbve.loc = 1; + bond(cbve, cbecasing); + acve.loc = 3; + bond(acve, oldace); + cbve.loc = 2; + bond(cbve, oldcbe); + acve.loc = 2; + cbve.loc = 3; + bond(acve, cbve); + // Bond two new coplanar facets. + bcvd.loc = 0; + cbve.loc = 0; + bond(bcvd, cbve); + cavd.loc = 0; + acve.loc = 0; + bond(cavd, acve); + } + + // There may exist subface needed to be bonded to the new tetrahedra. + if (checksubfaces) { + tspivot(oldbcd, bcdsh); + if (bcdsh.sh != dummysh) { + tsdissolve(oldbcd); + bcvd.loc = 1; + tsbond(bcvd, bcdsh); + } + tspivot(oldcad, cadsh); + if (cadsh.sh != dummysh) { + tsdissolve(oldcad); + cavd.loc = 1; + tsbond(cavd, cadsh); + } + if (mirrorflag) { + tspivot(oldace, acesh); + if (acesh.sh != dummysh) { + tsdissolve(oldace); + acve.loc = 1; + tsbond(acve, acesh); + } + tspivot(oldcbe, cbesh); + if (cbesh.sh != dummysh) { + tsdissolve(oldcbe); + cbve.loc = 1; + tsbond(cbve, cbesh); + } + } + // Is there a subface needs to be split together? + if (abcsh.sh != dummysh) { + // Split this subface 'abc' into three i.e, abv, bcv, cav. + splitsubface(newpoint, &abcsh, (queue *) NULL); + } + } + + // Save a handle for quick point location. + recenttet = abvd; + // Set the return handle be abvd. + *splittet = abvd; + + bcvd.loc = 0; + cavd.loc = 0; + if (mirrorflag) { + cbve.loc = 0; + acve.loc = 0; + } + if (b->verbose > 3) { + printf(" Updating abvd "); + printtet(&abvd); + printf(" Creating bcvd "); + printtet(&bcvd); + printf(" Creating cavd "); + printtet(&cavd); + if (mirrorflag) { + printf(" Updating bave "); + printtet(&bave); + printf(" Creating cbve "); + printtet(&cbve); + printf(" Creating acve "); + printtet(&acve); + } + } + + if (flipqueue != (queue *) NULL) { + fnextself(abvd); + enqueueflipface(abvd, flipqueue); + fnextself(bcvd); + enqueueflipface(bcvd, flipqueue); + fnextself(cavd); + enqueueflipface(cavd, flipqueue); + if (mirrorflag) { + fnextself(bave); + enqueueflipface(bave, flipqueue); + fnextself(cbve); + enqueueflipface(cbve, flipqueue); + fnextself(acve); + enqueueflipface(acve, flipqueue); + } + } +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// unsplittetface() Reverse the operation of inserting a point on a face, // +// so as to remove the newly inserted point. // +// // +// Assume the original face is abc, the tetrahedron containing abc is abcd. // +// If abc is not a hull face, bace is the tetrahedron at the opposite of d. // +// After face abc was split by a point v, tetrahedron abcd had been split // +// into three tetrahedra, abvd, bcvd, cavd, and bace (if it exists) had been // +// split into bave, cbve, acve. 'splittet' represents abvd (its apex is v). // +// // +// Point v is removed by expanding abvd to abcd, deleting two tetrahedra // +// bcvd, cavd. Expanding bave(if it exists) to bace, deleting two tetrahedra // +// cbve, acve. If abv is a subface, routine unsplitsubface() will be called // +// to reverse the operation of splitting a subface. On completion, point v // +// is not deleted in this routine. // +// // +/////////////////////////////////////////////////////////////////////////////// + +void tetgenmesh::unsplittetface(triface* splittet) +{ + triface abvd, bcvd, cavd, bave, cbve, acve; + triface oldbvd, oldvad, oldvbe, oldave; + triface bcdcasing, cadcasing, cbecasing, acecasing; + face bcdsh, cadsh, cbesh, acesh; + face abvsh; + bool mirrorflag; + + abvd = *splittet; + adjustedgering(abvd, CCW); // for sure. + enextfnext(abvd, oldbvd); + fnext(oldbvd, bcvd); + esymself(bcvd); + enextself(bcvd); + enext2fnext(abvd, oldvad); + fnext(oldvad, cavd); + esymself(cavd); + enext2self(cavd); + // Is there a second tetrahedron? + sym(abvd, bave); + mirrorflag = bave.tet != dummytet; + if (mirrorflag) { + findedge(&bave, dest(abvd), org(abvd)); + enextfnext(bave, oldave); + fnext(oldave, acve); + esymself(acve); + enextself(acve); + enext2fnext(bave, oldvbe); + fnext(oldvbe, cbve); + esymself(cbve); + enext2self(cbve); + } else { + // Unsplit a hull face decrease the number of boundary faces. + hullsize -= 2; + } + // Is there a subface at abv. + tspivot(abvd, abvsh); + if (abvsh.sh != dummysh) { + // Exists! Keep the edge ab of both handles be the same. + findedge(&abvsh, org(abvd), dest(abvd)); + } + + if (b->verbose > 1) { + printf(" Removing point %d on face (%d, %d, %d).\n", + pointmark(apex(abvd)), pointmark(org(abvd)), pointmark(dest(abvd)), + pointmark(dest(bcvd))); + } + + fnextself(bcvd); // bcvd has changed to bcdv. + sym(bcvd, bcdcasing); + tspivot(bcvd, bcdsh); + fnextself(cavd); // cavd has changed to cadv. + sym(cavd, cadcasing); + tspivot(cavd, cadsh); + if (mirrorflag) { + fnextself(acve); // acve has changed to acev. + sym(acve, acecasing); + tspivot(acve, acesh); + fnextself(cbve); // cbve has changed to cbev. + sym(cbve, cbecasing); + tspivot(cbve, cbesh); + } + + // Expand abvd to abcd. + setapex(abvd, dest(bcvd)); + bond(oldbvd, bcdcasing); + if (bcdsh.sh != dummysh) { + tsbond(oldbvd, bcdsh); + } + bond(oldvad, cadcasing); + if (cadsh.sh != dummysh) { + tsbond(oldvad, cadsh); + } + if (mirrorflag) { + // Expanding bave to bace. + setapex(bave, dest(acve)); + bond(oldave, acecasing); + if (acesh.sh != dummysh) { + tsbond(oldave, acesh); + } + bond(oldvbe, cbecasing); + if (cbesh.sh != dummysh) { + tsbond(oldvbe, cbesh); + } + } + + // Unsplit a subface if there exists. + if (abvsh.sh != dummysh) { + unsplitsubface(&abvsh); + } + + // Delete the split-out tetrahedra. + tetrahedrondealloc(bcvd.tet); + tetrahedrondealloc(cavd.tet); + if (mirrorflag) { + tetrahedrondealloc(acve.tet); + tetrahedrondealloc(cbve.tet); + } +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// splitsubface() Insert a point on a subface, split it into three. // +// // +// The subface is 'splitface'. Let it is abc. The inserting point 'newpoint'// +// v should lie inside abc. If the neighbor tetrahedra of abc exist, i.e., // +// abcd and bace, they should have been split by routine splittetface() // +// before calling this routine, so the connection between the new tetrahedra // +// and new subfaces can be correctly set. // +// // +// To split subface abc by point v is to shrink abc to abv, create two new // +// subfaces bcv and cav. Set the connection between updated and new created // +// subfaces. If there is a subsegment at edge bc or ca, connection of new // +// subface (bcv or cav) to its casing subfaces is a face link, 'casingin' is // +// the predecessor and 'casingout' is the successor. It is important to keep // +// the orientations of the edge rings of the updated and created subfaces be // +// the same as abc's. So they have the same orientation as other subfaces of // +// this facet with respect to the lift point of this facet. // +// // +// On completion, 'splitface' returns abv. If 'flipqueue' is not NULL, it // +// returns all possibly non-Delaunay edges. // +// // +/////////////////////////////////////////////////////////////////////////////// + +void tetgenmesh:: +splitsubface(point newpoint, face* splitface, queue* flipqueue) +{ + triface abvd, bcvd, cavd, bave, cbve, acve; + face abc, oldbc, oldca, bc, ca, spinsh; + face bccasin, bccasout, cacasin, cacasout; + face abv, bcv, cav; + point pa, pb, pc; + + abc = *splitface; + // The newly created subfaces will have the same edge ring as abc. + adjustedgering(abc, CCW); + pa = sorg(abc); + pb = sdest(abc); + pc = sapex(abc); + + if (b->verbose > 1) { + printf(" Inserting point %d on subface (%d, %d, %d).\n", + pointmark(newpoint), pointmark(pa), pointmark(pb), pointmark(pc)); + } + + // Save the old configuration at edge bc and ca. Subsegments may appear + // at both sides, save the face links and dissolve them. + senext(abc, oldbc); + senext2(abc, oldca); + spivot(oldbc, bccasout); + sspivot(oldbc, bc); + if (bc.sh != dummysh) { + if (oldbc.sh != bccasout.sh) { + // 'oldbc' is not self-bonded. + spinsh = bccasout; + do { + bccasin = spinsh; + spivotself(spinsh); + } while (spinsh.sh != oldbc.sh); + } else { + bccasout.sh = dummysh; + } + ssdissolve(oldbc); + } + spivot(oldca, cacasout); + sspivot(oldca, ca); + if (ca.sh != dummysh) { + if (oldca.sh != cacasout.sh) { + // 'oldca' is not self-bonded. + spinsh = cacasout; + do { + cacasin = spinsh; + spivotself(spinsh); + } while (spinsh.sh != oldca.sh); + } else { + cacasout.sh = dummysh; + } + ssdissolve(oldca); + } + // Create two new subfaces. + makeshellface(subfaces, &bcv); + makeshellface(subfaces, &cav); + + // Set the vertices of changed and new subfaces. + abv = abc; // Update 'abc' to 'abv'. + setsapex(abv, newpoint); + setsorg(bcv, pb); // Set 'bcv'. + setsdest(bcv, pc); + setsapex(bcv, newpoint); + setsorg(cav, pc); // Set 'cav'. + setsdest(cav, pa); + setsapex(cav, newpoint); + if (b->quality) { + // Copy yhr area bound into the new subfaces. + setareabound(bcv, areabound(abv)); + setareabound(cav, areabound(abv)); + } + // Copy the boundary mark into the new subfaces. + setshellmark(bcv, shellmark(abv)); + setshellmark(cav, shellmark(abv)); + // Copy the subface type into the new subfaces. + setshelltype(bcv, shelltype(abv)); + setshelltype(cav, shelltype(abv)); + // Bond the new subfaces to the surrounding subfaces. + if (bc.sh != dummysh) { + if (bccasout.sh != dummysh) { + sbond1(bccasin, bcv); + sbond1(bcv, bccasout); + } else { + // Bond 'bcv' to itsself. + sbond(bcv, bcv); + } + ssbond(bcv, bc); + } else { + sbond(bcv, bccasout); + } + if (ca.sh != dummysh) { + if (cacasout.sh != dummysh) { + sbond1(cacasin, cav); + sbond1(cav, cacasout); + } else { + // Bond 'cav' to itself. + sbond(cav, cav); + } + ssbond(cav, ca); + } else { + sbond(cav, cacasout); + } + senext2self(bcv); + sbond(bcv, oldbc); + senextself(cav); + sbond(cav, oldca); + senext2self(bcv); + senextself(cav); + sbond(bcv, cav); + + // Bond the new subfaces to the new tetrahedra if they exist. + stpivot(abv, abvd); + if (abvd.tet != dummytet) { + // Get two new tetrahedra and their syms. + findedge(&abvd, sorg(abv), sdest(abv)); + enextfnext(abvd, bcvd); + assert(bcvd.tet != dummytet); + fnextself(bcvd); + enext2fnext(abvd, cavd); + assert(cavd.tet != dummytet); + fnextself(cavd); + // Bond two new subfaces to the two new tetrahedra. + tsbond(bcvd, bcv); + tsbond(cavd, cav); + } + // Set the connection at the other sides if the tetrahedra exist. + sesymself(abv); // bav + stpivot(abv, bave); + if (bave.tet != dummytet) { + sesymself(bcv); // cbv + sesymself(cav); // acv + // Get two new tetrahedra and their syms. + findedge(&bave, sorg(abv), sdest(abv)); + enextfnext(bave, acve); + assert(acve.tet != dummytet); + fnextself(acve); + enext2fnext(bave, cbve); + assert(cbve.tet != dummytet); + fnextself(cbve); + // Bond two new subfaces to the two new tetrahedra. + tsbond(acve, cav); + tsbond(cbve, bcv); + } + + bcv.shver = 0; + cav.shver = 0; + if (b->verbose > 3) { + printf(" Updating abv "); + printsh(&abv); + printf(" Creating bcv "); + printsh(&bcv); + printf(" Creating cav "); + printsh(&cav); + } + + if (flipqueue != (queue *) NULL) { + enqueueflipedge(abv, flipqueue); + enqueueflipedge(bcv, flipqueue); + enqueueflipedge(cav, flipqueue); + } + + // Set the return handle be abv. + *splitface = abv; +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// unsplitsubface() Reverse the operation of inserting a point on a // +// subface, so as to remove the newly inserted point. // +// // +// Assume the original subface is abc, it was split by a point v into three // +// subfaces abv, bcv and cav. 'splitsh' represents abv. // +// // +// To remove point v is to expand abv to abc, delete bcv and cav. If edge bc // +// or ca is a subsegment, the connection at a subsegment is a subface link, // +// '-casin' and '-casout' are used to save the predecessor and successor of // +// bcv or cav. On completion, point v is not deleted in this routine. // +// // +/////////////////////////////////////////////////////////////////////////////// + +void tetgenmesh::unsplitsubface(face* splitsh) +{ + face abv, bcv, cav; + face oldbv, oldva, bc, ca, spinsh; + face bccasin, bccasout, cacasin, cacasout; + + abv = *splitsh; + senext(abv, oldbv); + spivot(oldbv, bcv); + if (sorg(bcv) != sdest(oldbv)) { + sesymself(bcv); + } + senextself(bcv); + senext2(abv, oldva); + spivot(oldva, cav); + if (sorg(cav) != sdest(oldva)) { + sesymself(cav); + } + senext2self(cav); + + if (b->verbose > 1) { + printf(" Removing point %d on subface (%d, %d, %d).\n", + pointmark(sapex(abv)), pointmark(sorg(abv)), pointmark(sdest(abv)), + pointmark(sdest(bcv))); + } + + spivot(bcv, bccasout); + sspivot(bcv, bc); + if (bc.sh != dummysh) { + if (bcv.sh != bccasout.sh) { + // 'bcv' is not self-bonded. + spinsh = bccasout; + do { + bccasin = spinsh; + spivotself(spinsh); + } while (spinsh.sh != bcv.sh); + } else { + bccasout.sh = dummysh; + } + } + spivot(cav, cacasout); + sspivot(cav, ca); + if (ca.sh != dummysh) { + if (cav.sh != cacasout.sh) { + // 'cav' is not self-bonded. + spinsh = cacasout; + do { + cacasin = spinsh; + spivotself(spinsh); + } while (spinsh.sh != cav.sh); + } else { + cacasout.sh = dummysh; + } + } + + // Expand abv to abc. + setsapex(abv, sdest(bcv)); + if (bc.sh != dummysh) { + if (bccasout.sh != dummysh) { + sbond1(bccasin, oldbv); + sbond1(oldbv, bccasout); + } else { + // Bond 'oldbv' to itself. + sbond(oldbv, oldbv); + } + ssbond(oldbv, bc); + } else { + sbond(oldbv, bccasout); + } + if (ca.sh != dummysh) { + if (cacasout.sh != dummysh) { + sbond1(cacasin, oldva); + sbond1(oldva, cacasout); + } else { + // Bond 'oldva' to itself. + sbond(oldva, oldva); + } + ssbond(oldva, ca); + } else { + sbond(oldva, cacasout); + } + + // Delete two split-out subfaces. + shellfacedealloc(subfaces, bcv.sh); + shellfacedealloc(subfaces, cav.sh); +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// splittetedge() Insert a point on an edge of the mesh. // +// // +// The edge is given by 'splittet'. Assume its four corners are a, b, n1 and // +// n2, where ab is the edge will be split. Around ab may exist any number of // +// tetrahedra. For convenience, they're ordered in a sequence following the // +// right-hand rule with your thumb points from a to b. Let the vertex set of // +// these tetrahedra be {a, b, n1, n2, ..., n(i)}. NOTE the tetrahedra around // +// ab may not connect to each other (can only happen when ab is a subsegment,// +// hence some faces abn(i) are subfaces). If ab is a subsegment, abn1 must // +// be a subface. // +// // +// To split edge ab by a point v is to split all tetrahedra containing ab by // +// v. More specifically, for each such tetrahedron, an1n2b, it is shrunk to // +// an1n2v, and a new tetrahedra bn2n1v is created. If ab is a subsegment, or // +// some faces of the splitting tetrahedra are subfaces, they must be split // +// either by calling routine 'splitsubedge()'. // +// // +// On completion, 'splittet' returns avn1n2. If 'flipqueue' is not NULL, it // +// returns all faces which may become non-Delaunay after this operation. // +// // +/////////////////////////////////////////////////////////////////////////////// + +void tetgenmesh:: +splittetedge(point newpoint, triface* splittet, queue* flipqueue) +{ + triface *bots, *newtops; + triface oldtop, topcasing; + triface spintet, tmpbond0, tmpbond1; + face abseg, splitsh, topsh, spinsh; + point pa, pb, n1, n2; + REAL attrib, volume; + int wrapcount, hitbdry; + int i, j; + + if (checksubfaces) { + // Is there a subsegment need to be split together? + tsspivot(splittet, &abseg); + if (abseg.sh != dummysh) { + abseg.shver = 0; + // Orient the edge direction of 'splittet' be abseg. + if (org(*splittet) != sorg(abseg)) { + esymself(*splittet); + } + } + } + spintet = *splittet; + pa = org(spintet); + pb = dest(spintet); + + if (b->verbose > 1) { + printf(" Inserting point %d on edge (%d, %d).\n", + pointmark(newpoint), pointmark(pa), pointmark(pb)); + } + + // Collect the tetrahedra containing the splitting edge (ab). + n1 = apex(spintet); + hitbdry = 0; + wrapcount = 1; + if (checksubfaces && abseg.sh != dummysh) { + // It may happen that some tetrahedra containing ab (a subsegment) are + // completely disconnected with others. If it happens, use the face + // link of ab to cross the boundary. + while (true) { + if (!fnextself(spintet)) { + // Meet a boundary, walk through it. + hitbdry ++; + tspivot(spintet, spinsh); + assert(spinsh.sh != dummysh); + findedge(&spinsh, pa, pb); + sfnextself(spinsh); + stpivot(spinsh, spintet); + assert(spintet.tet != dummytet); + findedge(&spintet, pa, pb); + // Remember this position (hull face) in 'splittet'. + *splittet = spintet; + // Split two hull faces increase the hull size; + hullsize += 2; + } + if (apex(spintet) == n1) break; + wrapcount ++; + } + if (hitbdry > 0) { + wrapcount -= hitbdry; + } + } else { + // All the tetrahedra containing ab are connected together. If there + // are subfaces, 'splitsh' keeps one of them. + splitsh.sh = dummysh; + while (hitbdry < 2) { + if (checksubfaces && splitsh.sh == dummysh) { + tspivot(spintet, splitsh); + } + if (fnextself(spintet)) { + if (apex(spintet) == n1) break; + wrapcount++; + } else { + hitbdry ++; + if (hitbdry < 2) { + esym(*splittet, spintet); + } + } + } + if (hitbdry > 0) { + // ab is on the hull. + wrapcount -= 1; + // 'spintet' now is a hull face, inverse its edge direction. + esym(spintet, *splittet); + // Split two hull faces increases the number of hull faces. + hullsize += 2; + } + } + + // Make arrays of updating (bot, oldtop) and new (newtop) tetrahedra. + bots = new triface[wrapcount]; + newtops = new triface[wrapcount]; + // Spin around ab, gather tetrahedra and set up new tetrahedra. + spintet = *splittet; + for (i = 0; i < wrapcount; i++) { + // Get 'bots[i] = an1n2b'. + enext2fnext(spintet, bots[i]); + esymself(bots[i]); + // Create 'newtops[i]'. + maketetrahedron(&(newtops[i])); + // Go to the next. + fnextself(spintet); + if (checksubfaces && abseg.sh != dummysh) { + if (!issymexist(&spintet)) { + // We meet a hull face, walk through it. + tspivot(spintet, spinsh); + assert(spinsh.sh != dummysh); + findedge(&spinsh, pa, pb); + sfnextself(spinsh); + stpivot(spinsh, spintet); + assert(spintet.tet != dummytet); + findedge(&spintet, pa, pb); + } + } + } + + // Set the vertices of updated and new tetrahedra. + for (i = 0; i < wrapcount; i++) { + // Update 'bots[i] = an1n2v'. + setoppo(bots[i], newpoint); + // Set 'newtops[i] = bn2n1v'. + n1 = dest(bots[i]); + n2 = apex(bots[i]); + // Set 'newtops[i]'. + setorg(newtops[i], pb); + setdest(newtops[i], n2); + setapex(newtops[i], n1); + setoppo(newtops[i], newpoint); + // Set the element attributes of a new tetrahedron. + for (j = 0; j < in->numberoftetrahedronattributes; j++) { + attrib = elemattribute(bots[i].tet, j); + setelemattribute(newtops[i].tet, j, attrib); + } + if (b->varvolume) { + // Set the area constraint of a new tetrahedron. + volume = volumebound(bots[i].tet); + setvolumebound(newtops[i].tet, volume); + } +#ifdef SELF_CHECK + // Make sure no inversed tetrahedron has been created. + assert(orient3d(pa, n1, n2, newpoint) <= 0.0); + assert(orient3d(pb, n2, n1, newpoint) <= 0.0); +#endif + } + + // Bond newtops to topcasings and bots. + for (i = 0; i < wrapcount; i++) { + // Get 'oldtop = n1n2va' from 'bots[i]'. + enextfnext(bots[i], oldtop); + sym(oldtop, topcasing); + bond(newtops[i], topcasing); + if (checksubfaces) { + tspivot(oldtop, topsh); + if (topsh.sh != dummysh) { + tsdissolve(oldtop); + tsbond(newtops[i], topsh); + } + } + enextfnext(newtops[i], tmpbond0); + bond(oldtop, tmpbond0); + } + // Bond between newtops. + fnext(newtops[0], tmpbond0); + enext2fnext(bots[0], spintet); + for (i = 1; i < wrapcount; i ++) { + if (issymexist(&spintet)) { + enext2fnext(newtops[i], tmpbond1); + bond(tmpbond0, tmpbond1); + } + fnext(newtops[i], tmpbond0); + enext2fnext(bots[i], spintet); + } + // Bond the last to the first if no boundary. + if (issymexist(&spintet)) { + enext2fnext(newtops[0], tmpbond1); + bond(tmpbond0, tmpbond1); + } + + // Is there exist subfaces and subsegment need to be split? + if (checksubfaces) { + if (abseg.sh != dummysh) { + // A subsegment needs be split. + spivot(abseg, splitsh); + assert(splitsh.sh != dummysh); + } + if (splitsh.sh != dummysh) { + // Split subfaces (and subsegment). + findedge(&splitsh, pa, pb); + splitsubedge(newpoint, &splitsh, (queue *) NULL); + } + } + + if (b->verbose > 3) { + for (i = 0; i < wrapcount; i++) { + printf(" Updating bots[%i] ", i); + printtet(&(bots[i])); + printf(" Creating newtops[%i] ", i); + printtet(&(newtops[i])); + } + } + + if (flipqueue != (queue *) NULL) { + for (i = 0; i < wrapcount; i++) { + enqueueflipface(bots[i], flipqueue); + enqueueflipface(newtops[i], flipqueue); + } + } + + // Set the return handle be avn1n2. It is got by transforming from + // 'bots[0]' (which is an1n2v). + fnext(bots[0], spintet); // spintet is an1vn2. + esymself(spintet); // spintet is n1avn2. + enextself(spintet); // spintet is avn1n2. + *splittet = spintet; + + delete [] bots; + delete [] newtops; +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// unsplittetedge() Reverse the operation of splitting an edge, so as to // +// remove the newly inserted point. // +// // +// Assume the original edge is ab, the tetrahedron containing ab is abn1n2. // +// After ab was split by a point v, every tetrahedron containing ab (e.g., // +// abn1n2) has been split into two (e.g., an1n2v and bn2n1v). 'splittet' // +// represents avn1n2 (i.e., its destination is v). // +// // +// To remove point v is to expand each split tetrahedron containing ab (e.g.,// +// (avn1n2 to abn1n2), then delete the redundant one(e.g., vbn1n2). If there // +// exists any subface around ab, routine unsplitsubedge() will be called to // +// reverse the operation of splitting a edge (or a subsegment) of subfaces. // +// On completion, point v is not deleted in this routine. // +// // +/////////////////////////////////////////////////////////////////////////////// + +void tetgenmesh::unsplittetedge(triface* splittet) +{ + triface *bots, *newtops; + triface oldtop, topcasing; + triface spintet; + face avseg, splitsh, topsh, spinsh; + point pa, pv, n1; + int wrapcount, hitbdry; + int i; + + spintet = *splittet; + pa = org(spintet); + pv = dest(spintet); + if (checksubfaces) { + // Is there a subsegment need to be unsplit together? + tsspivot(splittet, &avseg); + if (avseg.sh != dummysh) { + // The subsegment's direction should conform to 'splittet'. + if (sorg(avseg) != pa) { + sesymself(avseg); + } + } + } + + n1 = apex(spintet); + hitbdry = 0; + wrapcount = 1; + if (checksubfaces && avseg.sh != dummysh) { + // It may happen that some tetrahedra containing ab (a subsegment) are + // completely disconnected with others. If it happens, use the face + // link of ab to cross the boundary. + while (true) { + if (!fnextself(spintet)) { + // Meet a boundary, walk through it. + hitbdry ++; + tspivot(spintet, spinsh); + assert(spinsh.sh != dummysh); + findedge(&spinsh, pa, pv); + sfnextself(spinsh); + stpivot(spinsh, spintet); + assert(spintet.tet != dummytet); + findedge(&spintet, pa, pv); + // Remember this position (hull face) in 'splittet'. + *splittet = spintet; + // Split two hull faces increase the hull size; + hullsize += 2; + } + if (apex(spintet) == n1) break; + wrapcount ++; + } + if (hitbdry > 0) { + wrapcount -= hitbdry; + } + } else { + // All the tetrahedra containing ab are connected together. If there + // are subfaces, 'splitsh' keeps one of them. + splitsh.sh = dummysh; + while (hitbdry < 2) { + if (checksubfaces && splitsh.sh == dummysh) { + tspivot(spintet, splitsh); + } + if (fnextself(spintet)) { + if (apex(spintet) == n1) break; + wrapcount++; + } else { + hitbdry ++; + if (hitbdry < 2) { + esym(*splittet, spintet); + } + } + } + if (hitbdry > 0) { + // ab is on the hull. + wrapcount -= 1; + // 'spintet' now is a hull face, inverse its edge direction. + esym(spintet, *splittet); + // Split two hull faces increases the number of hull faces. + hullsize += 2; + } + } + + // Make arrays of updating (bot, oldtop) and new (newtop) tetrahedra. + bots = new triface[wrapcount]; + newtops = new triface[wrapcount]; + // Spin around av, gather tetrahedra and set up new tetrahedra. + spintet = *splittet; + for (i = 0; i < wrapcount; i++) { + // Get 'bots[i] = an1n2v'. + enext2fnext(spintet, bots[i]); + esymself(bots[i]); + // Get 'oldtop = n1n2va'. + enextfnext(bots[i], oldtop); + // Get 'newtops[i] = 'bn1n2v' + fnext(oldtop, newtops[i]); // newtop = n1n2bv + esymself(newtops[i]); // newtop = n2n1bv + enext2self(newtops[i]); // newtop = bn2n1v + // Go to the next. + fnextself(spintet); + if (checksubfaces && avseg.sh != dummysh) { + if (!issymexist(&spintet)) { + // We meet a hull face, walk through it. + tspivot(spintet, spinsh); + assert(spinsh.sh != dummysh); + findedge(&spinsh, pa, pv); + sfnextself(spinsh); + stpivot(spinsh, spintet); + assert(spintet.tet != dummytet); + findedge(&spintet, pa, pv); + } + } + } + + if (b->verbose > 1) { + printf(" Removing point %d from edge (%d, %d).\n", + pointmark(oppo(bots[0])), pointmark(org(bots[0])), + pointmark(org(newtops[0]))); + } + + for (i = 0; i < wrapcount; i++) { + // Expand an1n2v to an1n2b. + setoppo(bots[i], org(newtops[i])); + // Get 'oldtop = n1n2va' from 'bot[i]'. + enextfnext(bots[i], oldtop); + // Get 'topcasing' from 'newtop[i]' + sym(newtops[i], topcasing); + // Bond them. + bond(oldtop, topcasing); + if (checksubfaces) { + tspivot(newtops[i], topsh); + if (topsh.sh != dummysh) { + tsbond(oldtop, topsh); + } + } + // Delete the tetrahedron above an1n2v. + tetrahedrondealloc(newtops[i].tet); + } + + // If there exists any subface, unsplit them. + if (checksubfaces) { + if (avseg.sh != dummysh) { + spivot(avseg, splitsh); + assert(splitsh.sh != dummysh); + } + if (splitsh.sh != dummysh) { + findedge(&splitsh, pa, pv); + unsplitsubedge(&splitsh); + } + } + + delete [] bots; + delete [] newtops; +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// splitsubedge() Insert a point on an edge of the surface mesh. // +// // +// The splitting edge is given by 'splitsh'. Assume its three corners are a, // +// b, c, where ab is the edge will be split. ab may be a subsegment. // +// // +// To split edge ab is to split all subfaces conatining ab. If ab is not a // +// subsegment, there are only two subfaces need be split, otherwise, there // +// may have any number of subfaces need be split. Each splitting subface abc // +// is shrunk to avc, a new subface vbc is created. It is important to keep // +// the orientations of edge rings of avc and vbc be the same as abc's. If ab // +// is a subsegment, it is shrunk to av and a new subsegment vb is created. // +// // +// If there are tetrahedra adjoining to the splitting subfaces, they should // +// be split before calling this routine, so the connection between the new // +// tetrahedra and the new subfaces can be correctly set. // +// // +// On completion, 'splitsh' returns avc. If 'flipqueue' is not NULL, it // +// returns all edges which may be non-Delaunay. // +// // +/////////////////////////////////////////////////////////////////////////////// + +void tetgenmesh::splitsubedge(point newpoint, face* splitsh, queue* flipqueue) +{ + triface abcd, bace, vbcd, bvce; + face startabc, spinabc, spinsh; + face oldbc, bccasin, bccasout; + face ab, bc; + face avc, vbc, vbc1; + face av, vb; + point pa, pb; + + startabc = *splitsh; + // Is there a subsegment? + sspivot(startabc, ab); + if (ab.sh != dummysh) { + ab.shver = 0; + if (sorg(startabc) != sorg(ab)) { + sesymself(startabc); + } + } + pa = sorg(startabc); + pb = sdest(startabc); + + if (b->verbose > 1) { + printf(" Inserting point %d on subedge (%d, %d).\n", + pointmark(newpoint), pointmark(pa), pointmark(pb)); + } + + // Spin arround ab, split every subface containing ab. + spinabc = startabc; + do { + // Adjust spinabc be edge ab. + if (sorg(spinabc) != pa) { + sesymself(spinabc); + } + // Save old configuration at edge bc, if bc has a subsegment, save the + // face link of it and dissolve it from bc. + senext(spinabc, oldbc); + spivot(oldbc, bccasout); + sspivot(oldbc, bc); + if (bc.sh != dummysh) { + if (spinabc.sh != bccasout.sh) { + // 'spinabc' is not self-bonded. + spinsh = bccasout; + do { + bccasin = spinsh; + spivotself(spinsh); + } while (spinsh.sh != oldbc.sh); + } else { + bccasout.sh = dummysh; + } + ssdissolve(oldbc); + } + // Create a new subface. + makeshellface(subfaces, &vbc); + // Split abc. + avc = spinabc; // Update 'abc' to 'avc'. + setsdest(avc, newpoint); + // Make 'vbc' be in the same edge ring as 'avc'. + vbc.shver = avc.shver; + setsorg(vbc, newpoint); // Set 'vbc'. + setsdest(vbc, pb); + setsapex(vbc, sapex(avc)); + if (b->quality) { + // Copy yhr area bound into the new subfaces. + setareabound(vbc, areabound(avc)); + } + // Copy the shell marker and shell type into the new subface. + setshellmark(vbc, shellmark(avc)); + setshelltype(vbc, shelltype(avc)); + // Set the connection between updated and new subfaces. + senext2self(vbc); + sbond(vbc, oldbc); + // Set the connection between new subface and casings. + senext2self(vbc); + if (bc.sh != dummysh) { + if (bccasout.sh != dummysh) { + // Insert 'vbc' into face link. + sbond1(bccasin, vbc); + sbond1(vbc, bccasout); + } else { + // Bond 'vbc' to itself. + sbond(vbc, vbc); + } + ssbond(vbc, bc); + } else { + sbond(vbc, bccasout); + } + // Go to next subface at edge ab. + spivotself(spinabc); + if (spinabc.sh == dummysh) { + break; // 'ab' is a hull edge. + } + } while (spinabc.sh != startabc.sh); + + // Get the new subface vbc above the updated subface avc (= startabc). + senext(startabc, oldbc); + spivot(oldbc, vbc); + if (sorg(vbc) == newpoint) { + sesymself(vbc); + } + assert(sorg(vbc) == sdest(oldbc) && sdest(vbc) == sorg(oldbc)); + senextself(vbc); + // Set the face link for the new created subfaces around edge vb. + spinabc = startabc; + do { + // Go to the next subface at edge av. + spivotself(spinabc); + if (spinabc.sh == dummysh) { + break; // 'ab' is a hull edge. + } + if (sorg(spinabc) != pa) { + sesymself(spinabc); + } + // Get the new subface vbc1 above the updated subface avc (= spinabc). + senext(spinabc, oldbc); + spivot(oldbc, vbc1); + if (sorg(vbc1) == newpoint) { + sesymself(vbc1); + } + assert(sorg(vbc1) == sdest(oldbc) && sdest(vbc1) == sorg(oldbc)); + senextself(vbc1); + // Set the connection: vbc->vbc1. + sbond1(vbc, vbc1); + // For the next connection. + vbc = vbc1; + } while (spinabc.sh != startabc.sh); + + // Split ab if it is a subsegment. + if (ab.sh != dummysh) { + // Update subsegment ab to av. + av = ab; + setsdest(av, newpoint); + // Create a new subsegment vb. + makeshellface(subsegs, &vb); + setsorg(vb, newpoint); + setsdest(vb, pb); + // vb gets the same mark and segment type as av. + setshellmark(vb, shellmark(av)); + setshelltype(vb, shelltype(av)); + // Save the old connection at ab (re-use the handles oldbc, bccasout). + senext(av, oldbc); + spivot(oldbc, bccasout); + // Bond av and vb (bonded at their "fake" edges). + senext2(vb, bccasin); + sbond(bccasin, oldbc); + if (bccasout.sh != dummysh) { + // There is a subsegment connecting with ab at b. It will connect + // to vb at b after splitting. + bccasout.shver = 0; + assert(sorg(bccasout) == pb); + senext2self(bccasout); + senext(vb, bccasin); + sbond(bccasin, bccasout); + } + // Bond all new subfaces (vbc) to vb. + spinabc = startabc; + do { + // Adjust spinabc be edge av. + if (sorg(spinabc) != pa) { + sesymself(spinabc); + } + // Get new subface vbc above the updated subface avc (= spinabc). + senext(spinabc, oldbc); + spivot(oldbc, vbc); + if (sorg(vbc) == newpoint) { + sesymself(vbc); + } + senextself(vbc); + // Bond the new subface and the new subsegment. + ssbond(vbc, vb); + // Go to the next. + spivotself(spinabc); + assert(spinabc.sh != dummysh); + } while (spinabc.sh != startabc.sh); + } + + // Bond the new subfaces to new tetrahedra if they exist. New tetrahedra + // should have been created before calling this routine. + spinabc = startabc; + do { + // Adjust spinabc be edge av. + if (sorg(spinabc) != pa) { + sesymself(spinabc); + } + // Get new subface vbc above the updated subface avc (= spinabc). + senext(spinabc, oldbc); + spivot(oldbc, vbc); + if (sorg(vbc) == newpoint) { + sesymself(vbc); + } + senextself(vbc); + // Get the adjacent tetrahedra at 'spinabc'. + stpivot(spinabc, abcd); + if (abcd.tet != dummytet) { + findedge(&abcd, sorg(spinabc), sdest(spinabc)); + enextfnext(abcd, vbcd); + fnextself(vbcd); + assert(vbcd.tet != dummytet); + tsbond(vbcd, vbc); + sym(vbcd, bvce); + sesymself(vbc); + tsbond(bvce, vbc); + } else { + // One side is empty, check the other side. + sesymself(spinabc); + stpivot(spinabc, bace); + if (bace.tet != dummytet) { + findedge(&bace, sorg(spinabc), sdest(spinabc)); + enext2fnext(bace, bvce); + fnextself(bvce); + assert(bvce.tet != dummytet); + sesymself(vbc); + tsbond(bvce, vbc); + } + } + // Go to the next. + spivotself(spinabc); + if (spinabc.sh == dummysh) { + break; // 'ab' is a hull edge. + } + } while (spinabc.sh != startabc.sh); + + if (b->verbose > 3) { + spinabc = startabc; + do { + // Adjust spinabc be edge av. + if (sorg(spinabc) != pa) { + sesymself(spinabc); + } + printf(" Updating abc:\n"); + printsh(&spinabc); + // Get new subface vbc above the updated subface avc (= spinabc). + senext(spinabc, oldbc); + spivot(oldbc, vbc); + if (sorg(vbc) == newpoint) { + sesymself(vbc); + } + senextself(vbc); + printf(" Creating vbc:\n"); + printsh(&vbc); + // Go to the next. + spivotself(spinabc); + if (spinabc.sh == dummysh) { + break; // 'ab' is a hull edge. + } + } while (spinabc.sh != startabc.sh); + } + + if (flipqueue != (queue *) NULL) { + spinabc = startabc; + do { + // Adjust spinabc be edge av. + if (sorg(spinabc) != pa) { + sesymself(spinabc); + } + senext2(spinabc, oldbc); // Re-use oldbc. + enqueueflipedge(oldbc, flipqueue); + // Get new subface vbc above the updated subface avc (= spinabc). + senext(spinabc, oldbc); + spivot(oldbc, vbc); + if (sorg(vbc) == newpoint) { + sesymself(vbc); + } + senextself(vbc); + senext(vbc, oldbc); // Re-use oldbc. + enqueueflipedge(oldbc, flipqueue); + // Go to the next. + spivotself(spinabc); + if (spinabc.sh == dummysh) { + break; // 'ab' is a hull edge. + } + } while (spinabc.sh != startabc.sh); + } +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// unsplitsubedge() Reverse the operation of splitting an edge of subface,// +// so as to remove a point from the edge. // +// // +// Assume the original edge is ab, the subface containing it is abc. It was // +// split by a point v into avc, and vbc. 'splitsh' represents avc, further- // +// more, if av is a subsegment, av should be the zero version of the split // +// subsegment (i.e., av.shver = 0), so we are sure that the destination (v) // +// of both avc and av is the deleting point. // +// // +// To remove point v is to expand avc to abc, delete vbc, do the same for // +// other subfaces containing av and vb. If av and vb are subsegments, expand // +// av to ab, delete vb. On completion, point v is not deleted. // +// // +/////////////////////////////////////////////////////////////////////////////// + +void tetgenmesh::unsplitsubedge(face* splitsh) +{ + face startavc, spinavc, spinbcv; + face oldvc, bccasin, bccasout, spinsh; + face av, vb, bc; + point pa, pv, pb; + + startavc = *splitsh; + sspivot(startavc, av); + if (av.sh != dummysh) { + // Orient the direction of subsegment to conform the subface. + if (sorg(av) != sorg(startavc)) { + sesymself(av); + } + assert(av.shver == 0); + } + senext(startavc, oldvc); + spivot(oldvc, vb); // vb is subface vbc + if (sorg(vb) != sdest(oldvc)) { + sesymself(vb); + } + senextself(vb); + pa = sorg(startavc); + pv = sdest(startavc); + pb = sdest(vb); + + if (b->verbose > 1) { + printf(" Removing point %d from subedge (%d, %d).\n", + pointmark(pv), pointmark(pa), pointmark(pb)); + } + + // Spin arround av, unsplit every subface containing av. + spinavc = startavc; + do { + // Adjust spinavc be edge av. + if (sorg(spinavc) != pa) { + sesymself(spinavc); + } + // Save old configuration at edge bc, if bc has a subsegment, save the + // face link of it. + senext(spinavc, oldvc); + spivot(oldvc, spinbcv); + if (sorg(spinbcv) != sdest(oldvc)) { + sesymself(spinbcv); + } + senext2self(spinbcv); + spivot(spinbcv, bccasout); + sspivot(spinbcv, bc); + if (bc.sh != dummysh) { + if (spinbcv.sh != bccasout.sh) { + // 'spinbcv' is not self-bonded. + spinsh = bccasout; + do { + bccasin = spinsh; + spivotself(spinsh); + } while (spinsh.sh != spinbcv.sh); + } else { + bccasout.sh = dummysh; + } + } + // Expand avc to abc. + setsdest(spinavc, pb); + if (bc.sh != dummysh) { + if (bccasout.sh != dummysh) { + sbond1(bccasin, oldvc); + sbond1(oldvc, bccasout); + } else { + // Bond 'oldbc' to itself. + sbond(oldvc, oldvc); + } + ssbond(oldvc, bc); + } else { + sbond(oldvc, bccasout); + } + // Delete bcv. + shellfacedealloc(subfaces, spinbcv.sh); + // Go to next subface at edge av. + spivotself(spinavc); + if (spinavc.sh == dummysh) { + break; // 'av' is a hull edge. + } + } while (spinavc.sh != startavc.sh); + + // Is there a subsegment need to be unsplit? + if (av.sh != dummysh) { + senext(av, oldvc); // Re-use oldvc. + spivot(oldvc, vb); + vb.shver = 0; + assert(sdest(av) == sorg(vb)); + senext(vb, spinbcv); // Re-use spinbcv. + spivot(spinbcv, bccasout); + // Expand av to ab. + setsdest(av, pb); + sbond(oldvc, bccasout); + // Delete vb. + shellfacedealloc(subsegs, vb.sh); + } +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// insertsite() Insert a point into the mesh. // +// // +// The 'newpoint' is located. If 'searchtet->tet' is not NULL, the search // +// for the containing tetrahedron begins from 'searchtet', otherwise, a full // +// point location procedure is called. If 'newpoint' is found inside a // +// tetrahedron, the tetrahedron is split into four (by splittetrahedron()); // +// if 'newpoint' lies on a face, the face is split into three, thereby // +// splitting the two adjacent tetrahedra into six (by splittetface()); if // +// 'newpoint' lies on an edge, the edge is split into two, thereby, every // +// tetrahedron containing this edge is split into two. If 'newpoint' lies on // +// an existing vertex, no action is taken, and the value DUPLICATEPOINT is // +// returned and 'searchtet' is set to a handle whose origin is the vertex. // +// // +// If 'flipqueue' is not NULL, after 'newpoint' is inserted, it returns all // +// faces which may become non-Delaunay due to the newly inserted point. Flip // +// operations can be performed as necessary on them to maintain the Delaunay // +// property. // +// // +/////////////////////////////////////////////////////////////////////////////// + +enum tetgenmesh::insertsiteresult tetgenmesh:: +insertsite(point newpoint, triface* searchtet, bool approx, queue* flipqueue) +{ + enum locateresult intersect, exactloc; + point checkpt; + REAL epspp, checklen; + int count; + + if (b->verbose > 1) { + printf(" Insert point to mesh: (%.12g, %.12g, %.12g) %d.\n", + newpoint[0], newpoint[1], newpoint[2], pointmark(newpoint)); + } + + if (searchtet->tet == (tetrahedron *) NULL) { + // Search for a tetrahedron containing 'newpoint'. + searchtet->tet = dummytet; + exactloc = locate(newpoint, searchtet); + } else { + // Start searching from the tetrahedron provided by the caller. + exactloc = preciselocate(newpoint, searchtet); + } + intersect = exactloc; + if (approx && (exactloc != ONVERTEX)) { + // Adjust the exact location to an approx. location wrt. epsilon. + epspp = b->epsilon; + count = 0; + while (count < 16) { + intersect = adjustlocate(newpoint, searchtet, exactloc, epspp); + if (intersect == ONVERTEX) { + checkpt = org(*searchtet); + checklen = distance(checkpt, newpoint); + if (checklen / longest > b->epsilon) { + epspp *= 1e-2; + count++; + continue; + } + } + break; + } + } + // Keep current search state for next searching. + recenttet = *searchtet; + + // Insert the point using the right routine + switch (intersect) { + case ONVERTEX: + // There's already a vertex there. Return in 'searchtet' a tetrahedron + // whose origin is the existing vertex. + if (b->verbose > 1) { + printf(" Not insert for duplicating point.\n"); + } + return DUPLICATEPOINT; + + case OUTSIDE: + if (b->verbose > 1) { + printf(" Not insert for locating outside the mesh.\n"); + } + return OUTSIDEPOINT; + + case ONEDGE: + // 'newpoint' falls on an edge. + splittetedge(newpoint, searchtet, flipqueue); + return SUCCESSONEDGE; + + case ONFACE: + // 'newpoint' falls on a face. + splittetface(newpoint, searchtet, flipqueue); + return SUCCESSONFACE; + + case INTETRAHEDRON: + // 'newpoint' falls inside a tetrahedron. + splittetrahedron(newpoint, searchtet, flipqueue); + return SUCCESSINTET; + } + + // Impossible case. + assert(0); + return OUTSIDEPOINT; +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// undosite() Undo the most recently point insertion. // +// // +// 'insresult' indicates in where the newpoint has been inserted, i.e., in a // +// tetrahedron, on a face, or on an edge. A correspoding routine will be // +// called to undo the point insertion. 'splittet' is a handle represent one // +// of the resulting tetrahedra, but it may be changed after transformation, // +// even may be dead. Four points 'torg', ... 'toppo' are the corners which // +// 'splittet' should have. On finish, 'newpoint' is not removed. // +// // +/////////////////////////////////////////////////////////////////////////////// + +void tetgenmesh:: +undosite(enum insertsiteresult insresult, triface* splittet, point torg, + point tdest, point tapex, point toppo) +{ + // Set the four corners of 'splittet' exactly be 'torg', ... 'toppo'. + findface(splittet, torg, tdest, tapex); + if (oppo(*splittet) != toppo) { + symself(*splittet); + assert(oppo(*splittet) == toppo); + // The sym() operation may inverse the edge, correct it if so. + findedge(splittet, torg, tdest); + } + + // Unsplit the tetrahedron according to 'insresult'. + switch (insresult) { + case SUCCESSINTET: + // 'splittet' should be the face with 'newpoint' as its opposite. + unsplittetrahedron(splittet); + break; + case SUCCESSONFACE: + // 'splittet' should be the one of three splitted face with 'newpoint' + // as its apex. + unsplittetface(splittet); + break; + case SUCCESSONEDGE: + // 'splittet' should be the tet with destination is 'newpoint'. + unsplittetedge(splittet); + break; + } +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// inserthullsite() Insert a point which is outside the convex hull. // +// // +// The inserting point 'inspoint' lies outside the tetrahedralization.'horiz'// +// is one of the convex hull faces which are visible from it. (You can image // +// that is is parallel to the horizon). To insert a point outside the convex // +// hull we have to enlarge current convex hull of the tetrahedralization for // +// including this point. This routine collects convex hull faces which are // +// visible from the inserting point, constructs new tetrahedra from these // +// faces and the inserting point. On return, 'inspoint' has become a vertex // +// of the augmented tetrahedralization. The convex hull has been updated. // +// 'flipcheckqueue' returns the old convex hull faces which may become non- // +// Delaunay and need be flipped. // +// // +// The caller can optionally provide two variables. 'hulllink' is a link for // +// saving newly created hull faces (containing 'inspoint') which may not // +// convex. Non-convex hull faces will be detected and finished by mounting // +// new tetrahedra with other hull vertex near them. 'worklist' is an array, // +// used for face matching. // +// // +/////////////////////////////////////////////////////////////////////////////// + +void tetgenmesh:: +inserthullsite(point inspoint, triface* horiz, queue* flipqueue, + link* hulllink, int* worklist) +{ + link *myhulllink; + triface newtet, hullface; + triface oldhull, newhull; + point workpt[3]; + bool finished; + int *myworklist; + int idx, share; + int i, j, k; + + if (b->verbose > 1) { + printf(" Collect visible convex hull faces.\n"); + } + + // Check if the 'hulllink' is provided by the caller. + if (hulllink != (link *) NULL) { + myhulllink = (link *) NULL; + } else { + myhulllink = new link(sizeof(triface), NULL, 256); + hulllink = myhulllink; + } + + // Check if the 'worklist' is provided by the caller. + if (worklist != (int *) NULL) { + myworklist = (int *) NULL; + } else { + myworklist = new int[in->numberofpoints]; + for (i = 0; i < in->numberofpoints; i++) { + myworklist[i] = 0; + } + worklist = myworklist; + } + + adjustedgering(*horiz, CW); + // Create a new tetrahedron from 'horiz' and 'inspoint'. + maketetrahedron(&newtet); + setorg (newtet, org(*horiz)); + setdest(newtet, dest(*horiz)); + setapex(newtet, apex(*horiz)); + setoppo(newtet, inspoint); + // Make the connection of two tets. + bond(newtet, *horiz); + // 'horiz' becomes interior face. + enqueueflipface(*horiz, flipqueue); + // Add the three sides of 'newtet' to 'hulllink'. + fnext(newtet, hullface); + hulllink->add(&hullface); + enextfnext(newtet, hullface); + hulllink->add(&hullface); + enext2fnext(newtet, hullface); + hulllink->add(&hullface); + if (b->verbose > 3) { + printf(" Creating newtet "); + printtet(&newtet); + } + // Hull face number decreased caused by face bond() operation. + hullsize--; + + // Loop untill 'hulllink' is empty. Find other visible convex hull faces, + // create tetrahedra from them and 'inspoint'. Update 'hulllink'. + while (hulllink->len() > 0) { + // Remove the top hull face from the link, its apex is 'inspoint'. + hullface = * (triface *) hulllink->del(1); + // Get the neighbor convex hull face at the edge of 'hullface'. This is + // done by rotating faces around the edge from the inside until reach + // outer space (The rotation of faces should always terminate). + esym(hullface, oldhull); + while (fnextself(oldhull)) ; + // Is 'inspoint' visible from 'oldhull'? + if (orient3d(org(oldhull), dest(oldhull), apex(oldhull), inspoint) < 0.0) { + // 'oldhull' is visible from 'inspoint'. Create a new tetrahedron + // from them. + maketetrahedron(&newtet); + setorg(newtet, org(oldhull)); + setdest(newtet, dest(oldhull)); + setapex(newtet, apex(oldhull)); + setoppo(newtet, inspoint); + // Bond 'newtet' to 'oldhull'. + bond(newtet, oldhull); + // Hull face number decrease caused by bond(). + hullsize--; + // Bond 'newtet' to 'hullface'. + fnext(newtet, newhull); + bond(newhull, hullface); + // 'oldhull' becomes interior face. + enqueueflipface(oldhull, flipqueue); + // Check other two sides of 'newtet'. If one exists in 'hulllink'. + // remove the one in 'hulllink' (it is finished), otherwise, it + // becomes a new hull face, add it into 'hulllink'. + for (i = 0; i < 2; i++) { + // Get 'newhull' and set flags for its vertices. + if (i == 0) { + enextfnext(newtet, newhull); + } else { + enext2fnext(newtet, newhull); + } + workpt[0] = org(newhull); + workpt[1] = dest(newhull); + workpt[2] = apex(newhull); + for (k = 0; k < 3; k++) { + idx = pointmark(workpt[k]) - in->firstnumber; + worklist[idx] = 1; + } + // Search 'newhull' in 'hulllink'. + finished = false; + for (j = 0; j < hulllink->len() && !finished; j++) { + hullface = * (triface *) hulllink->getnitem(j + 1); + workpt[0] = org(hullface); + workpt[1] = dest(hullface); + workpt[2] = apex(hullface); + share = 0; + for (k = 0; k < 3; k++) { + idx = pointmark(workpt[k]) - in->firstnumber; + if (worklist[idx] == 1) { + share++; + } + } + if (share == 3) { + // Two faces are identical. Bond them togther. + bond(newhull, hullface); + // Remove 'hullface' from the link. + hulllink->del(j + 1); + finished = true; + } + } + if (!finished) { + // 'newhull' becomes a hull face, add it into 'hulllink'. + hulllink->add(&newhull); + } + // Clear used flags. + workpt[0] = org(newhull); + workpt[1] = dest(newhull); + workpt[2] = apex(newhull); + for (k = 0; k < 3; k++) { + idx = pointmark(workpt[k]) - in->firstnumber; + worklist[idx] = 0; + } + } + } else { + // 'hullface' becomes a convex hull face. + hullsize++; + // Let 'dummytet[0]' points to it for next point location. + dummytet[0] = encode(hullface); + } + } + + if (myhulllink != (link *) NULL) { + delete myhulllink; + } + if (myworklist != (int *) NULL) { + delete [] myworklist; + } +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// collectcavtets() Collect all tetrahedra whose circumsphere conatining // +// the given point. // +// // +// This routine first locates the newpoint. Note the mesh may not be convex, // +// the locate() function may not find it. However, if we start from a very // +// close neighborhood, the function preciselocate() can be used. Here we // +// assume "recenttet" suggests such a starting point. 'cavtetlist' is a list // +// returns the tetrahedra. It is empty on input. // +// // +/////////////////////////////////////////////////////////////////////////////// + +void tetgenmesh::collectcavtets(point newpoint, list* cavtetlist) +{ + triface starttet, neightet; + enum locateresult loc; + REAL sign; + int i, j; + + // First locate the newpoint. 'recenttet' suggests the starting point. + starttet = recenttet; + loc = preciselocate(newpoint, &starttet); + if (loc == OUTSIDE) { + // Principlly, the newpoint should lie inside or on the hull. But it + // may happen practically when the newpoint is just slightly lies + // outside the hull due to the rounding error. + loc = ONFACE; // This line is no meaning. + } + + // Now starttet contains newpoint. + infect(starttet); + cavtetlist->append(&starttet); + // Check the adjacent tet. + sym(starttet, neightet); + if (neightet.tet != dummytet) { + // For positive orientation that insphere() test requires. + adjustedgering(neightet, CW); + sign = insphere(org(neightet), dest(neightet), apex(neightet), + oppo(neightet), newpoint); + if (sign >= 0.0) { + // Add neightet into list. + infect(neightet); + cavtetlist->append(&neightet); + } + } + + // Find the other tetrahedra by looping in list. + for (i = 0; i < cavtetlist->len(); i++) { + starttet = * (triface *)(* cavtetlist)[i]; + // Check the other three neighbors of starttet. + adjustedgering(starttet, CCW); + for (j = 0; j < 3; j++) { + fnext(starttet, neightet); + symself(neightet); + if ((neightet.tet != dummytet) && !infected(neightet)) { + // For positive orientation that insphere() test requires. + adjustedgering(neightet, CW); + sign = insphere(org(neightet), dest(neightet), apex(neightet), + oppo(neightet), newpoint); + if (sign >= 0.0) { + // Add neightet into list. + infect(neightet); + cavtetlist->append(&neightet); + } + } + enextself(starttet); + } + } + + // Having find all tetrahedra, uninfect them before return. + for (i = 0; i < cavtetlist->len(); i++) { + starttet = * (triface *)(* cavtetlist)[i]; + assert(infected(starttet)); + uninfect(starttet); + } +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// removetetbypeeloff() Remove a boundary tetrahedron by peeling off it // +// from the mesh. // +// // +// 'badtet' (abcd) is a boundary tetrahedron and going to be peeled off. abc // +// and bad are the outer boundary faces. To remove 'abcd' from the mesh is // +// simply detach its two inner faces (dca and cdb) from the adjoining tets. // +// A 2-to-2 flip is applied to transform subfaces abc and bad to dca and cdb.// +// // +/////////////////////////////////////////////////////////////////////////////// + +void tetgenmesh::removetetbypeeloff(triface *badtet, queue* flipqueue) +{ + triface abcd, badc; + triface dcacasing, cdbcasing; + face abc, bad; + + if (b->verbose > 1) { + printf(" by peeling off it from boundary.\n"); + } + + abcd = *badtet; + adjustedgering(abcd, CCW); + // Get subfaces abc, bad. + fnext(abcd, badc); + esymself(badc); + tspivot(abcd, abc); + tspivot(badc, bad); + assert(abc.sh != dummysh && bad.sh != dummysh); + findedge(&abc, org(abcd), dest(abcd)); + findedge(&bad, org(badc), dest(badc)); + // Get the casing tets at the two inner sides of 'badtet'. + enextfnext(abcd, cdbcasing); + enext2fnext(abcd, dcacasing); + symself(cdbcasing); + symself(dcacasing); + assert(cdbcasing.tet != dummytet && dcacasing.tet != dummytet); + + // Do a 2-to-2 flip on abc and bad, transform abc->dca, bad->cdb. + flip22sub(&abc, NULL); + // Detach abcd from its inner sides. + dissolve(cdbcasing); + dissolve(dcacasing); + // Make its inner sides be boundary. + tsbond(cdbcasing, bad); + tsbond(dcacasing, abc); + // Delete abcd. + tetrahedrondealloc(abcd.tet); + + if (flipqueue != (queue *) NULL) { + // Edge cd maybe non-Delaunay. + adjustedgering(cdbcasing, CCW); + fnextself(cdbcasing); + enqueueflipface(cdbcasing, flipqueue); + adjustedgering(dcacasing, CCW); + fnextself(dcacasing); + enqueueflipface(dcacasing, flipqueue); + // Do flipping. + flip(flipqueue, NULL); + } +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// removetetbyflip32() Remove a tetrahedron by doing a 3-to-2 flip. // +// // +// 'badtet' (abcd) is the bad tetrahedron which is going to be removed by a // +// 3-to-2 flip. abc represents one of the internal faces, bad is another. // +// If abc and bad are subfaces, a 2-to-2 flip is performed to transform abc, // +// bad into dca, cdb, before the 3-to-2 flip is applying. // +// // +/////////////////////////////////////////////////////////////////////////////// + +void tetgenmesh::removetetbyflip32(triface *badtet, queue* flipqueue) +{ + triface abcd, badc; + triface cdab, dcba; + triface baccasing, abdcasing; + triface dcacasing, cdbcasing; + face abc, bad; + + if (b->verbose > 1) { + printf(" by doing a 3-to-2 flip.\n"); + } + + abcd = *badtet; + adjustedgering(abcd, CCW); + fnext(abcd, badc); + esymself(badc); + sym(abcd, baccasing); + sym(badc, abdcasing); + assert(baccasing.tet != dummytet && abdcasing.tet != dummytet); + assert(oppo(baccasing) == oppo(abdcasing)); + + // Get subfaces abc, bad. + tspivot(abcd, abc); + tspivot(badc, bad); + if (abc.sh != dummysh) { + // Because ab should not be a subsegment. + assert(bad.sh != dummysh); + findedge(&abc, org(abcd), dest(abcd)); + findedge(&bad, org(badc), dest(badc)); + // Detach abc, bad from tetrahedra at both sides. + stdissolve(abc); + stdissolve(bad); + sesymself(abc); + sesymself(bad); + stdissolve(abc); + stdissolve(bad); + sesymself(abc); + sesymself(bad); + // Detach tetrahedra witch hold abc and bad. + tsdissolve(abcd); + tsdissolve(badc); + tsdissolve(baccasing); + tsdissolve(abdcasing); + // Perform a 2-to-2 flip on abc, bad, transform abc->dca, bad->cdb. + flip22sub(&abc, NULL); + // Insert the flipped subfaces abc and bad into tetrahedra. + enextfnext(abcd, dcba); // dcba = bcda + esymself(dcba); // dcba = cbda + enext2fnext(abcd, cdab); // cdab = cadb + esymself(cdab); // cdab = acdb + findedge(&abc, org(cdab), dest(cdab)); + tsbond(cdab, abc); + findedge(&bad, org(dcba), dest(dcba)); + tsbond(dcba, bad); + // Bond the other sides of cdab, dcba, they may outer space. + sym(cdab, dcacasing); + sym(dcba, cdbcasing); + sesymself(abc); + sesymself(bad); + tsbond(dcacasing, abc); + tsbond(cdbcasing, bad); + } + // Do a 3-to-2 flip on face abc to remove tetrahedron abcd. + flip32(&abcd, flipqueue); + // Do flipping if necessary. + if (flipqueue != (queue *) NULL) { + flip(flipqueue, NULL); + } +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// removetetbycflips() Remove a tetrahedron by a combination of flips. // +// // +// 'badtet' (abcd) is the tetrahedron which is going to be removed. It can't // +// be removed simply by a 3-to-2 flip. // +// // +// A flipstack is used for remembering flips have done, in case falure, we // +// can restore the original state. // +// // +/////////////////////////////////////////////////////////////////////////////// + +bool tetgenmesh::removetetbycflips(triface *badtet, queue* flipqueue) +{ + triface abcd; + triface bacd, baec; + triface abdc, abfd; + flipstacker *lastflip, *newflip; + enum fliptype fc; + int flipcount; + + abcd = *badtet; + adjustedgering(abcd, CCW); + esym(abcd, bacd); + if (issymexist(&bacd)) { + fnext(bacd, baec); + assert(baec.tet != dummytet); + } else { + // This side is empty. But the tet can not be peeled off. + return false; + } + fnext(abcd, abdc); + if (issymexist(&abdc)) { + fnext(abdc, abfd); + assert(abfd.tet != dummytet); + } else { + // This side is empty. But the tet can not be peeled off. + return false; + } + assert(apex(baec) != apex(abfd)); + + if (b->verbose > 1) { + printf(" by doing a combination of flips.\n"); + } + + // Initialize the stack of the flip sequence. + flipstackers->restart(); + lastflip = (flipstacker *) NULL; + + // Flip faces above abc. + flipcount = 0; + do { + assert(baec.tet != dummytet); + fc = categorizeface(baec); + if (fc == T23) { + flip23(&baec, NULL); + } else if (fc == T22 || fc == T44) { + flip22(&baec, NULL); + } + if (fc == T23 || fc == T22 || fc == T44) { + // Push the flipped face into stack. + newflip = (flipstacker *) flipstackers->alloc(); + newflip->flippedface = baec; + newflip->fc = fc; + newflip->forg = org(baec); + newflip->fdest = dest(baec); + newflip->fapex = apex(baec); + newflip->prevflip = lastflip; + lastflip = newflip; + // Check the flipped side. + fnext(bacd, baec); + if (apex(baec) == apex(abfd)) { + // We have made 'abcd' flipable. + removetetbyflip32(&abcd, flipqueue); + return true; + } + flipcount++; + } else { + // Face is unflipable, break the loop. + break; + } + } while (flipcount < 16); + + // Flip faces above bad. + fnext(bacd, baec); + assert(apex(abfd) != apex(baec)); + flipcount = 0; + do { + assert(abfd.tet != dummytet); + fc = categorizeface(abfd); + if (fc == T23) { + flip23(&abfd, NULL); + } else if (fc == T22 || fc == T44) { + flip22(&abfd, NULL); + } + if (fc == T23 || fc == T22 || fc == T44) { + // Push the flipped face into stack. + newflip = (flipstacker *) flipstackers->alloc(); + newflip->flippedface = abfd; + newflip->fc = fc; + newflip->forg = org(abfd); + newflip->fdest = dest(abfd); + newflip->fapex = apex(abfd); + newflip->prevflip = lastflip; + lastflip = newflip; + // Check the flipped side. + fnext(abdc, abfd); + if (apex(abfd) == apex(baec)) { + // We have made 'abcd' flipable. + removetetbyflip32(&abcd, flipqueue); + return true; + } + flipcount++; + } else { + // Face is unflipable, break the loop. + break; + } + } while (flipcount < 16); + + // Unable to use a combination of flips. + if (b->verbose > 1) { + printf(" Not success.\n"); + } + // Restore the flips we've done. + undoflip(lastflip); + return false; +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// removebadtet() Remove a bad tetrahedron from the mesh. // +// // +// 'bt' indicates the type of the 'badtet', assume it is abcd. If it is a // +// SLIVER, ab and cd are the two diagonal edges; if it is a CAP, abc is the // +// bottom face (the projection of d is inside abc); if it is ILLEGAL, abc, // +// bad are the two boundary subfaces (which are on the same facet). // +// // +// This routine first classifies the type of operation can be used to remove // +// 'badtet', e.g. simpley do a 3-to-2 flip, or combine several flips. Then // +// do the corresponding flip operation. // +// // +/////////////////////////////////////////////////////////////////////////////// + +bool tetgenmesh:: +removebadtet(enum badtettype bt, triface *badtet, queue* flipqueue) +{ + triface abcd, badc, cdab, dcba; + triface bcdcasing, cadcasing; + triface baccasing, abdcasing; + face ab, cd; + point pa, pb, pc, pd; + + abcd = *badtet; + adjustedgering(abcd, CCW); + pa = org(abcd); + pb = dest(abcd); + pc = apex(abcd); + pd = oppo(abcd); + + if (b->verbose > 1) { + printf(" Remove tetrahedron (%d, %d, %d, %d).\n", pointmark(pa), + pointmark(pb), pointmark(pc), pointmark(pd)); + } + + // Get the casing tets at the four sides of 'badtet'. + fnext(abcd, badc); + esymself(badc); + sym(abcd, baccasing); + sym(badc, abdcasing); + tsspivot(&abcd, &ab); + enextfnext(abcd, dcba); // dcba = bcda + esymself(dcba); // dcba = cbda + enext2self(dcba); + enext2fnext(abcd, cdab); // cdab = cadb + esymself(cdab); // cdab = acdb + enextself(cdab); + sym(dcba, bcdcasing); + sym(cdab, cadcasing); + tsspivot(&dcba, &cd); + + if (ab.sh != dummysh && cd.sh != dummysh) { + printf("Warning: Two subsegments (%d, %d), (%d, %d) cross in one tet.\n", + pointmark(pa), pointmark(pb), pointmark(pc), pointmark(pd)); + return false; + } + + if (bt == ILLEGAL || bt == SLIVER) { + if (cd.sh == dummysh) { + // Test if edge 'cd' is removeable. + if (bcdcasing.tet == dummytet && cadcasing.tet == dummytet) { + removetetbypeeloff(&cdab, flipqueue); + return true; + } + if (oppo(bcdcasing) == oppo(cadcasing)) { + removetetbyflip32(&cdab, flipqueue); + return true; + } + } + if (ab.sh == dummysh) { + // Test if edge 'ab' is removeable. + if (baccasing.tet == dummytet && abdcasing.tet == dummytet) { + removetetbypeeloff(&abcd, flipqueue); + return true; + } + if (oppo(baccasing) == oppo(abdcasing)) { + removetetbyflip32(&abcd, flipqueue); + return true; + } + } + // 'badtet' can not be easily removed, try to remove it by a combination + // of flips. + if (cd.sh == dummysh) { + if (removetetbycflips(&cdab, flipqueue)) { + return true; + } + } + if (ab.sh == dummysh) { + if (removetetbycflips(&abcd, flipqueue)) { + return true; + } + } + if (b->verbose) { + printf("Warning: Unable to remove bad tet (%d, %d, %d, %d).\n", + pointmark(pa), pointmark(pb), pointmark(pc), pointmark(pd)); + } + return false; + } + + return false; +} + +// +// End of mesh transformation routines +// + +// +// Begin of incremental flip Delaunay triangulation routines +// + +/////////////////////////////////////////////////////////////////////////////// +// // +// incrflipinit() Create an initial tetrahedralization. // +// // +// The initial tetrahedralization only contains one tetrahedron formed from // +// four affinely linear independent vertices from the input point set. // +// // +// 'insertqueue' returns the rest of vertices of the input point set. These // +// vertices will be inserted one by one in the later step. // +// // +/////////////////////////////////////////////////////////////////////////////// + +void tetgenmesh::incrflipinit(queue* insertqueue) +{ + triface newtet; + point *plist, pointloop; + point pa, pb, pc, pd; + REAL det; + int count; + int i, j; + + if (b->verbose > 1) { + printf(" Constructing an initial tetrahedron.\n"); + } + + // Create a point list and initialize it. + plist = new point[in->numberofpoints]; + i = 0; + points->traversalinit(); + pointloop = pointtraverse(); + while (pointloop != (point) NULL) { + plist[i++] = pointloop; + pointloop = pointtraverse(); + } + assert(i == in->numberofpoints); + + if (b->dopermute) { + // Do permutation. Initialize the random seed. + randomseed = b->srandseed; + for (i = 0; i < in->numberofpoints; i++) { + // Get a index j (from 0 to in->numberofpoints - i - 1). + j = (int) randomnation(in->numberofpoints - i); + // Exchange the i-th point and (j + i)-th point. + pointloop = plist[j + i]; + plist[j + i] = plist[i]; + plist[i] = pointloop; + } + } + + // Set the plist into insertqueue. + if (!insertqueue->empty()) { + insertqueue->clear(); + } + for (i = 0; i < in->numberofpoints; i++) { + pointloop = plist[i]; + insertqueue->push(&pointloop); + } + delete [] plist; + + // Get the first two point 'pa'. + pa = * (point *) insertqueue->pop(); + + // Get the second point 'pb', which is not identical with 'pa'. + count = 0; + pb = * (point *) insertqueue->pop(); + while ((pb != (point) NULL) && (count < in->numberofpoints)) { + if ((pb[0] == pa[0]) && (pb[1] == pa[1]) && (pb[2] == pa[2])) { + // 'pb' is identical to 'pa', skip it. + insertqueue->push(&pb); + } else { + break; + } + pb = * (point *) insertqueue->pop(); + count++; + } + if (pb == (point) NULL) { + printf("\nAll points are identical, no triangulation be constructed.\n"); + exit(1); + } + + // Get the third point 'pc', which is not collinear with 'pa' and 'pb'. + count = 0; + pc = * (point *) insertqueue->pop(); + while ((pc != (point) NULL) && (count < in->numberofpoints)) { + if (iscollinear(pa, pb, pc, (b->epsilon * 1e-2))) { + // They are collinear or identical, put it back to queue. + insertqueue->push(&pc); + } else { + break; + } + pc = * (point *) insertqueue->pop(); + count++; + } + if (pc == (point) NULL) { + printf("\nAll points are collinear, no triangulation be constructed.\n"); + exit(1); + } + + // Get the fourth point which is not coplanar with pa, pb, and pc. + count = 0; + pd = * (point *) insertqueue->pop(); + while ((pd != (point) NULL) && (count < in->numberofpoints)) { + det = orient3d(pa, pb, pc, pd); + if (det == 0.0) { + // They are coplanar or identical, put it back to queue. + insertqueue->push(&pd); + } else { + break; + } + pd = * (point *) insertqueue->pop(); + count++; + } + if (pd == (point) NULL) { + printf("\nAll points are coplanar, no triangulation be constructed.\n"); + exit(1); + } + if (det > 0.0) { + pointloop = pa; pa = pb; pb = pointloop; + } + + // Create the tetrahedron with corners pa, pb, pc and pd. + maketetrahedron(&newtet); + setorg(newtet, pa); + setdest(newtet, pb); + setapex(newtet, pc); + setoppo(newtet, pd); + // Set the vertices be FREEVOLVERTEX to indicate they belong to the mesh. + setpointtype(pa, FREEVOLVERTEX); + setpointtype(pb, FREEVOLVERTEX); + setpointtype(pc, FREEVOLVERTEX); + setpointtype(pd, FREEVOLVERTEX); + // Bond to 'dummytet' for point location. + dummytet[0] = encode(newtet); + if (b->verbose > 3) { + printf(" Creating tetra "); + printtet(&newtet); + } + // At init, all faces of this tet are hull faces. + hullsize = 4; +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// incrflipdelaunay() Construct a delaunay tetrahedrization from a set of // +// 3D points using the incremental flip algorithm. // +// // +// The incremental flip algorithm is described in the paper of Edelsbrunner // +// and Shah, "Incremental Topological Flipping Works for Regular Triangulat- // +// ions", Algorithmica 15: 223-241, 1996. It can be described as follows: // +// // +// S be a set of points in 3D, Let 4 <= i <= n and assume that the // +// Delaunay triangulation of the first i-1 points in S is already // +// constructed; call it D(i-1). Add the i-th point p_i (belong to S) to // +// the triangulation,and restore Delaunayhood by flipping; this result // +// in D(i). Repeat this procedure until i = n. // +// // +// This strategy always leads to the Ddelaunay triangulation of a point set. // +// The return value is the number of convex hull faces of this point set. // +// // +/////////////////////////////////////////////////////////////////////////////// + +long tetgenmesh::incrflipdelaunay() +{ + triface starttet; + point pointloop; + queue *flipqueue; + queue *insertqueue; + link *hulllink; + enum insertsiteresult insres; + int *worklist, i; + + if (!b->quiet) { + if (!b->noflip) { + printf("Constructing Delaunay tetrahedrization.\n"); + } else { + printf("Constructing tetrahedrization.\n"); + } + } + + // Initialize 'flipqueue'. + flipqueue = new queue(sizeof(badface)); + // Create a queue for all inserting points. + insertqueue = new queue(sizeof(point*), in->numberofpoints); + // Create a 'hulllink' used in inserthullsite(). + hulllink = new link(sizeof(triface), NULL, 256); + // Create and initialize 'worklist' used in inserthullsite(). + worklist = new int[in->numberofpoints]; + for (i = 0; i < in->numberofpoints; i++) worklist[i] = 0; + // Initialize global counters. + flip23s = flip32s = flip22s = flip44s = 0; + + // Algorithm starts from here. + + // Construct an initial tetrahedralization and fill 'insertqueue'. + incrflipinit(insertqueue); + + // Loop untill all points are inserted. + while (!insertqueue->empty()) { + pointloop = * (point *) insertqueue->pop(); + // It will become a mesh point unless it duplicates an existing point. + setpointtype(pointloop, FREEVOLVERTEX); + // Try to insert the point first. + starttet.tet = (tetrahedron *) NULL; + insres = insertsite(pointloop, &starttet, false, flipqueue); + if (insres == OUTSIDEPOINT) { + // Point locates outside the convex hull. + inserthullsite(pointloop, &starttet, flipqueue, hulllink, worklist); + } else if (insres == DUPLICATEPOINT) { + if (b->object != tetgenbehavior::STL) { + if (!b->quiet) { + printf("Warning: Point %d is identical with point %d.\n", + pointmark(pointloop), pointmark(org(starttet))); + } + // Count the number of duplicated points. + dupverts++; + } + // Remember it is a duplicated point. + setpointtype(pointloop, DUPLICATEDVERTEX); + if (b->plc || b->refine) { + // Set a pointer to the point it duplicates. + setpoint2pt(pointloop, org(starttet)); + } + } + if (!b->noflip) { + // Call flip algorithm to recover Delaunayness. + flip(flipqueue, NULL); + } else { + // Not perform flip. + flipqueue->clear(); + } + } + + delete flipqueue; + delete insertqueue; + delete hulllink; + delete [] worklist; + + if (!b->noflip && b->verbose) { + printf(" Total flips: %ld, where T23 %ld, T32 %ld, T22 %ld, T44 %ld\n", + flip23s + flip32s + flip22s + flip44s, + flip23s, flip32s, flip22s, flip44s); + } + + return hullsize; +} + +// +// End of incremental flip Delaunay triangulation routines +// + +// +// Begin of surface triangulation routines +// + +/////////////////////////////////////////////////////////////////////////////// +// // +// The lift points // +// // +// A 'lifting point' of a facet is a point which lies exactly non-coplanar // +// with the plane containing that facet. With such an additional point, the // +// three-dimensional geometric predicates (orient3d, insphere) can be used // +// to substitute the lower dimensional predicates (orient2d, incircle). The // +// advantage is there is no need to project 3D points back into 2D, so the // +// rounding error can be avoid. // +// // +// These points are calculated during the initialization of triangulating // +// the facets. It is important to orient subfaces of the same facet to have // +// the same orientation with respect to its lift point. This way guarantees // +// the test results are consistent. We take the convention that the lift // +// point of a facet always lies above the CCW edge rings of subfaces of the // +// same facet. By this convention, given three points a, b, and c in a facet,// +// we say c has the counterclockwise order with ab is corresponding to say // +// that c is below the plane abp, where p is the lift point. // +// // +/////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// +// // +// locatesub() Find a point in the surface mesh. // +// // +// Searching begins from the input 'searchsh', it should be a handle on the // +// convex hull of the facet triangulation. // +// // +// On completion, 'searchsh' is a subface that contains 'searchpoint'. // +// - Returns ONVERTEX if the point lies on an existing vertex. 'searchsh' // +// is a handle whose origin is the existing vertex. // +// - Returns ONEDGE if the point lies on a mesh edge. 'searchsh' is a // +// handle whose primary edge is the edge on which the point lies. // +// - Returns ONFACE if the point lies strictly within a subface. // +// 'searchsh' is a handle on which the point lies. // +// - Returns OUTSIDE if the point lies outside the triangulation. // +// // +// WARNING: This routine is designed for convex triangulations, and will not // +// not generally work after the holes and concavities have been carved. // +// // +/////////////////////////////////////////////////////////////////////////////// + +enum tetgenmesh::locateresult tetgenmesh:: +locatesub(point searchpt, face* searchsh, point abovept) +{ + face backtracksh, checkedge; + point forg, fdest, fapex, liftpoint; + REAL orgori, destori; + int moveleft, i; + + if (searchsh->sh == dummysh) { + searchsh->shver = 0; + spivotself(*searchsh); + assert(searchsh->sh != dummysh); + } + + // Set the liftpoint. (Note, the liftpoint is always above the face.) + if (abovept == (point) NULL) { + liftpoint = getliftpoint(shellmark(*searchsh)); + adjustedgering(*searchsh, CCW); + } else { + liftpoint = abovept; + forg = sorg(*searchsh); + fdest = sdest(*searchsh); + fapex = sapex(*searchsh); + orgori = orient3d(forg, fdest, fapex, liftpoint); + assert(orgori != 0.0); + if (orgori > 0.0) { + sesymself(*searchsh); + } + } + + // Orient 'searchsh' so that 'searchpt' is below it (i.e., searchpt has + // CCW orientation with respect to searchsh in plane). Such edge + // should always exist. Save it as (forg, fdest). + for (i = 0; i < 3; i++) { + forg = sorg(*searchsh); + fdest = sdest(*searchsh); + if (orient3d(forg, fdest, liftpoint, searchpt) > 0.0) break; + senextself(*searchsh); + } + assert(i < 3); + + while (1) { + fapex = sapex(*searchsh); + // Check whether the apex is the point we seek. + if (fapex[0] == searchpt[0] && fapex[1] == searchpt[1] && + fapex[2] == searchpt[2]) { + senext2self(*searchsh); + return ONVERTEX; + } + // Does the point lie on the other side of the line defined by the + // triangle edge opposite the triangle's destination? + destori = orient3d(forg, fapex, liftpoint, searchpt); + // Does the point lie on the other side of the line defined by the + // triangle edge opposite the triangle's origin? + orgori = orient3d(fapex, fdest, liftpoint, searchpt); + if (destori > 0.0) { + moveleft = 1; + } else { + if (orgori > 0.0) { + moveleft = 0; + } else { + // The point must be on the boundary of or inside this triangle. + if (destori == 0.0) { + senext2self(*searchsh); + return ONEDGE; + } + if (orgori == 0.0) { + senextself(*searchsh); + return ONEDGE; + } + return ONFACE; + } + } + // Move to another triangle. Leave a trace `backtracksh' in case + // walking off a boundary of the triangulation. + if (moveleft) { + senext2(*searchsh, backtracksh); + fdest = fapex; + } else { + senext(*searchsh, backtracksh); + forg = fapex; + } + spivot(backtracksh, *searchsh); + // Check for walking right out of the triangulation. + if (searchsh->sh == dummysh) { + // Go back to the last triangle. + *searchsh = backtracksh; + return OUTSIDE; + } + // To keep the same orientation wrt. liftpoint. + // adjustedgering(*searchsh, CCW); + if (sorg(*searchsh) != forg) { + sesymself(*searchsh); + } + assert((sorg(*searchsh) == forg) && (sdest(*searchsh) == fdest)); + } +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// flipsub() Flip all non-Delaunay edges in a given queue of subfaces. // +// // +// Assumpation: Current triangulation is non-Delaunay after inserting a // +// point or performing a flip operation, all possibly non-Delaunay edges are // +// in 'facequeue'. The return value is the total number of flips done during // +// this invocation. // +// // +/////////////////////////////////////////////////////////////////////////////// + +long tetgenmesh::flipsub(queue* flipqueue) +{ + badface *qedge; + face flipedge, symedge, bdedge; + point pa, pb, pc, pd, liftpoint; + REAL sign; + int edgeflips; + + if (b->verbose > 1) { + printf(" Start do edge queue: %ld edges.\n", flipqueue->len()); + } + + edgeflips = 0; + + while ((qedge = (badface *) flipqueue->pop()) != NULL) { + flipedge = qedge->ss; + if (flipedge.sh == dummysh) continue; + if ((sorg(flipedge) != qedge->forg) || + (sdest(flipedge) != qedge->fdest)) continue; + sspivot(flipedge, bdedge); + if (bdedge.sh != dummysh) continue; // Can't flip a subsegment. + spivot(flipedge, symedge); + if (symedge.sh == dummysh) continue; // Can't flip a hull edge. + pa = sorg(flipedge); + pb = sdest(flipedge); + pc = sapex(flipedge); + pd = sapex(symedge); + liftpoint = getliftpoint(shellmark(flipedge)); + // Check whether pd lies inside the circumcircle of pa, pb, pc or not. + sign = insphere(pa, pb, pc, liftpoint, pd) + * orient3d(pa, pb, pc, liftpoint); + if (sign > 0.0) { + // Flip the non-Delaunay edge. + flip22sub(&flipedge, flipqueue); + edgeflips++; + } + } + + if (b->verbose > 1) { + printf(" Total %d flips.\n", edgeflips); + } + + return edgeflips; +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// incrflipinitsub() Create a initial triangulation. // +// // +// The initial triangulation only consists of one triangle formed by three // +// non-collinear points. 'facetidx' is the index of the facet in 'facetlist' // +// (starts from 1) of the tetgenio structure; 'ptlist' is a list of indices // +// of the facet vertices; 'idx2verlist' is a map from indices to vertices. // +// // +// The 'lift point' of this facet is calculated. If not all vertices of the // +// facet are collinear, such point is found by lifting the centroid of the // +// set of vertices for a certain distance along the normal of this facet. // +// // +/////////////////////////////////////////////////////////////////////////////// + +bool tetgenmesh:: +incrflipinitsub(int facetidx, list* ptlist, point* idx2verlist) +{ + face newsh; + point pt1, pt2, pt3; + point liftpoint, ptloop; + REAL cent[3], norm[3]; + REAL v1[3], v2[3]; + REAL smallcos, cosa; + REAL liftdist, len, vol; + int smallidx; + int idx, i; + + if (ptlist->len() > 3) { + // Find a (non-degenerate) vector from the vertex set. + idx = * (int *) (* ptlist)[0]; + pt1 = idx2verlist[idx - in->firstnumber]; + len = 0.0; + // Loop the set of vertices until a not too small edge be found. + for (i = 1; i < ptlist->len(); i++) { + idx = * (int *) (* ptlist)[i]; + pt2 = idx2verlist[idx - in->firstnumber]; + v1[0] = pt2[0] - pt1[0]; + v1[1] = pt2[1] - pt1[1]; + v1[2] = pt2[2] - pt1[2]; + len = sqrt(dot(v1, v1)); + if ((len / longest) > (b->epsilon * 1e+2)) break; + } + // Remember this size as lift distance. + liftdist = len; + // 'v1' is a reasonable vector, normalize it. + for (i = 0; i < 3; i++) v1[i] /= len; + // Continue to find another (non-degenerate) vector, which forms an + // angle with v1 most close to 90 degree. + smallcos = 1.0; // The cosine value of 0 degree. + for (i = 1; i < ptlist->len(); i++) { + idx = * (int *) (* ptlist)[i]; + pt3 = idx2verlist[idx - in->firstnumber]; + if (pt3 == pt2) continue; // Skip the same point. + v2[0] = pt3[0] - pt1[0]; + v2[1] = pt3[1] - pt1[1]; + v2[2] = pt3[2] - pt1[2]; + len = sqrt(dot(v2, v2)); + if (len > 0.0) { // v2 is not too small. + cosa = fabs(dot(v1, v2)) / len; + if (cosa < smallcos) { + smallidx = idx; + smallcos = cosa; + } + } else { // len == 0.0, two identical points defined in a facet. + printf("Warning: Facet %d has two identical vertices: %d, %d.\n", + facetidx, pointmark(pt1), pointmark(pt3)); + return false; // Invalid polygon, do not procced. + } + } + if (smallcos == 1.0) { + // The input set of vertices is not a good set (or nearly degenerate). + printf("Warning: Facet %d with vertices: ", facetidx); + for (i = 0; i < 3; i++) { + idx = * (int *) (* ptlist)[i]; + ptloop = idx2verlist[idx - in->firstnumber]; + printf("%d ", pointmark(ptloop)); + } + printf("... is degenerate.\n"); + return false; // Invalid polygon, do not procced. + } + // Get the right point to form v2. + pt3 = idx2verlist[smallidx - in->firstnumber]; + assert(pt3 != pt2); + v2[0] = pt3[0] - pt1[0]; + v2[1] = pt3[1] - pt1[1]; + v2[2] = pt3[2] - pt1[2]; + len = sqrt(dot(v2, v2)); + assert(len > 0.0); + // Remember this size as lift distance. + liftdist = (liftdist > len ? liftdist : len); + // 'v2' is a reasonable vector, normalize it. + for (i = 0; i < 3; i++) v2[i] /= len; + } else { + // There are only three vertices of this facet (a triangle). + idx = * (int *) (* ptlist)[0]; + pt1 = idx2verlist[idx - in->firstnumber]; + idx = * (int *) (* ptlist)[1]; + pt2 = idx2verlist[idx - in->firstnumber]; + idx = * (int *) (* ptlist)[2]; + pt3 = idx2verlist[idx - in->firstnumber]; + v1[0] = pt2[0] - pt1[0]; + v1[1] = pt2[1] - pt1[1]; + v1[2] = pt2[2] - pt1[2]; + len = sqrt(dot(v1, v1)); + if (len == 0.0) { + printf("Warning: Facet %d has two identical vertices: %d, %d.\n", + facetidx, pointmark(pt1), pointmark(pt2)); + return false; // Invalid polygon, do not procced. + } + // Remember this size as lift distance. + liftdist = len; + // 'v1' is a reasonable vector, normalize it. + for (i = 0; i < 3; i++) v1[i] /= len; + v2[0] = pt3[0] - pt1[0]; + v2[1] = pt3[1] - pt1[1]; + v2[2] = pt3[2] - pt1[2]; + len = sqrt(dot(v2, v2)); + if (len == 0.0) { + printf("Warning: Facet %d has two identical vertices: %d, %d.\n", + facetidx, pointmark(pt1), pointmark(pt3)); + return false; // Invalid polygon, do not procced. + } + // Remember this size as lift distance. + liftdist = (liftdist > len ? liftdist : len); + // 'v2' is a reasonable vector, normalize it. + for (i = 0; i < 3; i++) v2[i] /= len; + } + // Calculate the unit normal of this facet. + cross(v1, v2, norm); + + // Calculate the centroid point of the vertex set. At the same time, check + // whether vertices of this facet are roughly coplanar or not. + cent[0] = cent[1] = cent[2] = 0.0; + for (i = 0; i < ptlist->len(); i++) { + idx = * (int *) (* ptlist)[i]; + ptloop = idx2verlist[idx - in->firstnumber]; + if (ptlist->len() > 3) { + vol = orient3d(pt1, pt2, pt3, ptloop); + if (vol != 0.0) { + if (!iscoplanar(pt1, pt2, pt3, ptloop, vol, b->epsilon * 1e+3)) { + printf("Warning: Facet %d has a non-coplanar vertex %d.\n", + facetidx, pointmark(ptloop)); + // This is not a fatal problem, we still can procced. + } + } + } + cent[0] += ptloop[0]; + cent[1] += ptloop[1]; + cent[2] += ptloop[2]; + } + for (i = 0; i < 3; i++) cent[i] /= ptlist->len(); + // Calculate the lifting point of the facet. It is lifted from 'cent' + // along the normal direction with a certain ditance. + liftpoint = getliftpoint(facetidx); + for (i = 0; i < 3; i++) { + liftpoint[i] = cent[i] + liftdist * norm[i]; + } + + // Create the initial triangle. The liftpoint is above (pt1, pt2, pt3). + makeshellface(subfaces, &newsh); + setsorg(newsh, pt1); + setsdest(newsh, pt2); + setsapex(newsh, pt3); + // Remeber the facet it belongs to. + setshellmark(newsh, facetidx); + // Set vertices be type FACETVERTEX to indicate they belong to a facet. + setpointtype(pt1, FACETVERTEX); + setpointtype(pt2, FACETVERTEX); + setpointtype(pt3, FACETVERTEX); + // Bond this subface to 'dummysh' for point location routine. + dummysh[0] = sencode(newsh); + + return true; +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// collectvisiblesubs() Collect convex hull edges which are visible from // +// the inserting point. Construct new subfaces from // +// these edges and the point. // +// // +// 'facetidx' is the index of the facet in 'in->facetlist' (starts from 1), // +// 'inspoint' is located outside current triangulation, 'horiz' is the hull // +// edge it is visible. 'flipqueue' returns the visible hull edges which have // +// become interior edges on completion of this routine. // +// // +/////////////////////////////////////////////////////////////////////////////// + +void tetgenmesh:: +collectvisiblesubs(int facetidx, point inspoint, face* horiz, queue* flipqueue) +{ + face newsh, hullsh; + face rightsh, leftsh, spinedge; + point horg, hdest, liftpoint; + bool aboveflag; + + liftpoint = getliftpoint(facetidx); + + // Create a new subface above 'horiz'. + adjustedgering(*horiz, CCW); + makeshellface(subfaces, &newsh); + setsorg(newsh, sdest(*horiz)); + setsdest(newsh, sorg(*horiz)); + setsapex(newsh, inspoint); + setshellmark(newsh, facetidx); + // Make the connection. + sbond(newsh, *horiz); + // 'horiz' becomes interior edge. + enqueueflipedge(*horiz, flipqueue); + + // Finish the hull edges at the right side of the newsh. + hullsh = *horiz; + while (1) { + senext(newsh, rightsh); + // Get the right hull edge of 'horiz' by spinning inside edges around + // the origin of 'horiz' until reaching the 'dummysh'. + spinedge = hullsh; + do { + hullsh = spinedge; + senext2self(hullsh); + spivot(hullsh, spinedge); + adjustedgering(spinedge, CCW); + } while (spinedge.sh != dummysh); + // Test whether 'inspoint' is visible from 'hullsh'. + horg = sorg(hullsh); + hdest = sdest(hullsh); + aboveflag = orient3d(horg, hdest, liftpoint, inspoint) < 0.0; + if (aboveflag) { + // It's a visible hull edge. + makeshellface(subfaces, &newsh); + setsorg(newsh, sdest(hullsh)); + setsdest(newsh, sorg(hullsh)); + setsapex(newsh, inspoint); + setshellmark(newsh, facetidx); + // Make the connection. + sbond(newsh, hullsh); + senext2(newsh, leftsh); + sbond(leftsh, rightsh); + // 'horiz' becomes interior edge. + enqueueflipedge(hullsh, flipqueue); + } else { + // 'rightsh' is a new hull edge. + dummysh[0] = sencode(rightsh); + break; + } + } + + // Finish the hull edges at the left side of the newsh. + hullsh = *horiz; + spivot(*horiz, newsh); + while (1) { + senext2(newsh, leftsh); + // Get the left hull edge of 'horiz' by spinning edges around the + // destination of 'horiz'. + spinedge = hullsh; + do { + hullsh = spinedge; + senextself(hullsh); + spivot(hullsh, spinedge); + adjustedgering(spinedge, CCW); + } while (spinedge.sh != dummysh); + // Test whether 'inspoint' is visible from 'hullsh'. + horg = sorg(hullsh); + hdest = sdest(hullsh); + aboveflag = orient3d(horg, hdest, liftpoint, inspoint) < 0.0; + if (aboveflag) { + // It's a visible hull edge. + makeshellface(subfaces, &newsh); + setsorg(newsh, sdest(hullsh)); + setsdest(newsh, sorg(hullsh)); + setsapex(newsh, inspoint); + setshellmark(newsh, facetidx); + // Make the connection. + sbond(newsh, hullsh); + senext(newsh, rightsh); + sbond(rightsh, leftsh); + // 'horiz' becomes interior edge. + enqueueflipedge(hullsh, flipqueue); + } else { + // 'leftsh' is a new hull edge. + dummysh[0] = sencode(leftsh); + break; + } + } +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// incrflipdelaunaysub() Create a Delaunay triangulation from a 3D point // +// set using the incremental flip algorithm. // +// // +// 'facetidx' is the index of the facet in 'in->facetlist' (starts from 1), // +// 'ptlist' is the index list of the vertices of the facet, 'idx2verlist' is // +// a map from indices to vertices. // +// // +/////////////////////////////////////////////////////////////////////////////// + +void tetgenmesh:: +incrflipdelaunaysub(int facetidx, list* ptlist, point* idx2verlist, + queue* flipqueue) +{ + face startsh; + point pointloop; + enum locateresult loc; + int idx, i; + + for (i = 1; i < ptlist->len(); i++) { + idx = * (int *) (* ptlist)[i]; + pointloop = idx2verlist[idx - in->firstnumber]; + // Set vertices be type FACETVERTEX to indicate they belong to a facet. + setpointtype(pointloop, FACETVERTEX); + startsh.sh = dummysh; + loc = locatesub(pointloop, &startsh, NULL); + if (loc == ONVERTEX) continue; + if (loc == ONFACE) { + splitsubface(pointloop, &startsh, flipqueue); + } else if (loc == ONEDGE) { + splitsubedge(pointloop, &startsh, flipqueue); + } else if (loc == OUTSIDE) { + collectvisiblesubs(facetidx, pointloop, &startsh, flipqueue); + } + flipsub(flipqueue); + } +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// finddirectionsub() Find the first subface in a facet on the path from // +// one point to another. // +// // +// Finds the subface in the facet that intersects a line segment drawn from // +// the origin of `searchsh' to the point `tend', and returns the result in // +// `searchsh'. The origin of `searchsh' does not change, even though the // +// subface returned may differ from the one passed in. // +// // +// The return value notes whether the destination or apex of the found face // +// is collinear with the two points in question. // +// // +/////////////////////////////////////////////////////////////////////////////// + +enum tetgenmesh::finddirectionresult tetgenmesh:: +finddirectionsub(face* searchsh, point tend) +{ + face checksh; + point startpoint, liftpoint; + point leftpoint, rightpoint; + REAL leftccw, rightccw; + int leftflag, rightflag; + + adjustedgering(*searchsh, CCW); + liftpoint = getliftpoint(shellmark(*searchsh)); + startpoint = sorg(*searchsh); + rightpoint = sdest(*searchsh); + leftpoint = sapex(*searchsh); + // Is `tend' to the left? + leftccw = orient3d(tend, startpoint, liftpoint, leftpoint); + leftflag = leftccw > 0.0; + // Is `tend' to the right? + rightccw = orient3d(startpoint, tend, liftpoint, rightpoint); + rightflag = rightccw > 0.0; + if (leftflag && rightflag) { + // `searchsh' faces directly away from `tend'. We could go left or + // right. Ask whether it's a triangle or a boundary on the left. + senext2(*searchsh, checksh); + spivotself(checksh); + if (checksh.sh == dummysh) { + leftflag = 0; + } else { + rightflag = 0; + } + } + while (leftflag) { + // Turn left until satisfied. + senext2self(*searchsh); + spivotself(*searchsh); + if (searchsh->sh == dummysh) { + printf("Internal error in finddirectionsub(): Unable to find a\n"); + printf(" triangle leading from %d to %d.\n", pointmark(startpoint), + pointmark(tend)); + internalerror(); + } + adjustedgering(*searchsh, CCW); + leftpoint = sapex(*searchsh); + rightccw = leftccw; + leftccw = orient3d(tend, startpoint, liftpoint, leftpoint); + leftflag = leftccw > 0.0; + } + while (rightflag) { + // Turn right until satisfied. + spivotself(*searchsh); + if (searchsh->sh == dummysh) { + printf("Internal error in finddirectionsub(): Unable to find a\n"); + printf(" triangle leading from %d to %d.\n", pointmark(startpoint), + pointmark(tend)); + internalerror(); + } + adjustedgering(*searchsh, CCW); + senextself(*searchsh); + rightpoint = sdest(*searchsh); + leftccw = rightccw; + rightccw = orient3d(startpoint, tend, liftpoint, rightpoint); + rightflag = rightccw > 0.0; + } + if (leftccw == 0.0) { + return LEFTCOLLINEAR; + } else if (rightccw == 0.0) { + return RIGHTCOLLINEAR; + } else { + return ACROSSEDGE; + } +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// insertsubseg() Create a subsegment and insert it between two subfaces. // +// // +// The new subsegment is inserted at the edge described by the handle 'tri'. // +// If 'tri' is not on the hull, the segment is inserted between two faces. // +// If 'tri' is a hull face, the initial face ring of this segment will be // +// set only one face which is self-bonded. The official face ring will be // +// constructed later in routine unifysegments(). // +// // +/////////////////////////////////////////////////////////////////////////////// + +void tetgenmesh::insertsubseg(face* tri) +{ + face oppotri; + face newsubseg; + + // Check if there's already a subsegment here. + sspivot(*tri, newsubseg); + if (newsubseg.sh == dummysh) { + // Make new subsegment and initialize its vertices. + makeshellface(subsegs, &newsubseg); + setsorg(newsubseg, sorg(*tri)); + setsdest(newsubseg, sdest(*tri)); + // Bond new subsegment to the two triangles it is sandwiched between. + ssbond(*tri, newsubseg); + spivot(*tri, oppotri); + // 'oppotri' might be "out space". + if (oppotri.sh != dummysh) { + ssbond(oppotri, newsubseg); + } else { + // Outside! Bond '*tri' to itself. + sbond(*tri, *tri); + } + } +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// scoutsegmentsub() Scout the first triangle on the path from one point // +// to another, and check for completion (reaching the // +// second point), a collinear point,or the intersection // +// of two segments. // +// // +// Returns true if the entire segment is successfully inserted, and false if // +// the job must be finished by constrainededge(). // +// // +/////////////////////////////////////////////////////////////////////////////// + +bool tetgenmesh::scoutsegmentsub(face* searchsh, point tend) +{ + face newsubseg; + face crosssub, crosssubseg; + point leftpoint, rightpoint; + enum finddirectionresult collinear; + + collinear = finddirectionsub(searchsh, tend); + rightpoint = sdest(*searchsh); + leftpoint = sapex(*searchsh); + if (rightpoint == tend || leftpoint == tend) { + // The segment is already an edge. + if (leftpoint == tend) { + senext2self(*searchsh); + } + // Insert a subsegment. + insertsubseg(searchsh); + return true; + } else if (collinear == LEFTCOLLINEAR) { + // We've collided with a vertex between the segment's endpoints. + // Make the collinear vertex be the triangle's origin. + senextself(*searchsh); // lprevself(*searchtri); + // Insert a subsegment. + insertsubseg(searchsh); + // Insert the remainder of the segment. + return scoutsegmentsub(searchsh, tend); + } else if (collinear == RIGHTCOLLINEAR) { + // We've collided with a vertex between the segment's endpoints. + // Insert a subsegment. + insertsubseg(searchsh); + // Make the collinear vertex be the triangle's origin. + senextself(*searchsh); // lnextself(*searchtri); + // Insert the remainder of the segment. + return scoutsegmentsub(searchsh, tend); + } else { + senext(*searchsh, crosssub); // lnext(*searchtri, crosstri); + // Check for a crossing segment. + sspivot(crosssub, crosssubseg); + assert(crosssubseg.sh == dummysh); + return false; + } +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// delaunayfixup() Enforce the Delaunay condition at an edge, fanning out // +// recursively from an existing point. Pay special // +// attention to stacking inverted triangles. // +// // +// This is a support routine for inserting segments into a constrained // +// Delaunay triangulation. // +// // +// The origin of 'fixupsh' is treated as if it has just been inserted, and // +// the local Delaunay condition needs to be enforced. It is only enforced in // +// one sector, however, that being the angular range defined by 'fixupsh'. // +// // +// `leftside' indicates whether or not fixupsh is to the left of the segment // +// being inserted. (Imagine that the segment is pointing up from endpoint1 // +// to endpoint2.) // +// // +/////////////////////////////////////////////////////////////////////////////// + +void tetgenmesh::delaunayfixup(face* fixupsh, int leftside) +{ + face nearsh, farsh, faredge; + point nearpoint, leftpoint, rightpoint, farpoint; + point liftpoint; + REAL sign; + + // It is up to the caller, that 'fixupsh' must be in CCW edge ring. + // adjustedgering(*fixupsh, CCW); + assert((fixupsh->shver % 2) == 0); + senext(*fixupsh, nearsh); + spivot(nearsh, farsh); + if (nearsh.sh == farsh.sh) { + farsh.sh = dummysh; + } + // Check if the edge opposite the origin of fixupsh can be flipped. + if (farsh.sh == dummysh) { + return; + } + adjustedgering(farsh, CCW); + sspivot(nearsh, faredge); + if (faredge.sh != dummysh) { + return; + } + // Find all the relevant vertices. + liftpoint = getliftpoint(shellmark(*fixupsh)); + nearpoint = sapex(nearsh); + leftpoint = sorg(nearsh); + rightpoint = sdest(nearsh); + farpoint = sapex(farsh); + // Check whether the previous polygon point is a reflex point. + if (leftside) { + if (orient3d(nearpoint, leftpoint, liftpoint, farpoint) <= 0.0) { + // leftpoint is a reflex point too. Nothing can + // be done until a convex section is found. + return; + } + } else { + if (orient3d(farpoint, rightpoint, liftpoint, nearpoint) <= 0.0) { + // rightpoint is a reflex point too. Nothing can + // be done until a convex section is found. + return; + } + } + if (orient3d(rightpoint, leftpoint, liftpoint, farpoint) > 0.0) { + // farsh is not an inverted triangle, and farpoint is not a reflex + // point. As there are no reflex vertices, fixupsh isn't an + // inverted triangle, either. Hence, test the edge between the + // triangles to ensure it is locally Delaunay. + sign = insphere(leftpoint, farpoint, rightpoint, liftpoint, nearpoint) + * orient3d(leftpoint, farpoint, rightpoint, liftpoint); + if (sign <= 0.0) { + return; + } + // Not locally Delaunay; go on to an edge flip. + } // else farsh is inverted; remove it from the stack by flipping. + flip22sub(&nearsh, NULL); + senext2self(*fixupsh); // Restore the origin of fixupsh after the flip. + // Recursively process the two triangles that result from the flip. + delaunayfixup(fixupsh, leftside); + delaunayfixup(&farsh, leftside); +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// constrainededge() Force a segment into a constrained Delaunay // +// triangulation by deleting the triangles it // +// intersects, and triangulating the polygons that // +// form on each side of it. // +// // +// Generates a single subsegment connecting `tstart' to `tend'. The triangle // +// `startsh' has `tstart' as its origin. // +// // +/////////////////////////////////////////////////////////////////////////////// + +void tetgenmesh::constrainededge(face* startsh, point tend) +{ + face fixupsh, fixupsh2; + face crosssubseg, newsubseg; + point tstart, farpoint; + point liftpoint; + REAL area; + int collision; + int done; + + liftpoint = getliftpoint(shellmark(*startsh)); + tstart = sorg(*startsh); + // Always works in the CCW edge ring. + adjustedgering(*startsh, CCW); + // Make sure the 'tstart' remians be the origin. + if (sorg(*startsh) != tstart) { + senextself(*startsh); + assert(sorg(*startsh) == tstart); + } + senext(*startsh, fixupsh); + flip22sub(&fixupsh, NULL); + // `collision' indicates whether we have found a vertex directly + // between endpoint1 and endpoint2. + collision = 0; + done = 0; + do { + farpoint = sorg(fixupsh); + // `farpoint' is the extreme point of the polygon we are "digging" + // to get from tstart to tend. + if (farpoint == tend) { + spivot(fixupsh, fixupsh2); // oprev(fixupsh, fixupsh2); + adjustedgering(fixupsh2, CCW); + senextself(fixupsh2); + // Enforce the Delaunay condition around tend. + delaunayfixup(&fixupsh, 0); + delaunayfixup(&fixupsh2, 1); + done = 1; + } else { + // Check whether farpoint is to the left or right of the segment + // being inserted, to decide which edge of fixupsh to dig + // through next. + area = orient3d(tstart, tend, liftpoint, farpoint); + if (area == 0.0) { + // We've collided with a vertex between tstart and tend. + collision = 1; + spivot(fixupsh, fixupsh2); // oprev(fixupsh, fixupsh2); + adjustedgering(fixupsh2, CCW); + senextself(fixupsh2); + // Enforce the Delaunay condition around farpoint. + delaunayfixup(&fixupsh, 0); + delaunayfixup(&fixupsh2, 1); + done = 1; + } else { + if (area > 0.0) { // farpoint is to the left of the segment. + spivot(fixupsh, fixupsh2); // oprev(fixupsh, fixupsh2); + adjustedgering(fixupsh2, CCW); + senextself(fixupsh2); + // Enforce the Delaunay condition around farpoint, on the + // left side of the segment only. + delaunayfixup(&fixupsh2, 1); + // Flip the edge that crosses the segment. After the edge is + // flipped, one of its endpoints is the fan vertex, and the + // destination of fixupsh is the fan vertex. + senext2self(fixupsh); // lprevself(fixupsh); + } else { // farpoint is to the right of the segment. + delaunayfixup(&fixupsh, 0); + // Flip the edge that crosses the segment. After the edge is + // flipped, one of its endpoints is the fan vertex, and the + // destination of fixupsh is the fan vertex. + spivotself(fixupsh); // oprevself(fixupsh); + adjustedgering(fixupsh, CCW); + senextself(fixupsh); + } + // Check for two intersecting segments. + sspivot(fixupsh, crosssubseg); + if (crosssubseg.sh == dummysh) { + flip22sub(&fixupsh, NULL);// May create inverted triangle at left. + } else { + // We've collided with a segment between tstart and tend. + /* collision = 1; + // Insert a vertex at the intersection. + segmentintersection(m, b, &fixupsh, &crosssubseg, tend); + done = 1; + */ + assert(0); + } + } + } + } while (!done); + // Insert a subsegment to make the segment permanent. + insertsubseg(&fixupsh); + // If there was a collision with an interceding vertex, install another + // segment connecting that vertex with endpoint2. + if (collision) { + // Insert the remainder of the segment. + if (!scoutsegmentsub(&fixupsh, tend)) { + constrainededge(&fixupsh, tend); + } + } +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// insertsegmentsub() Insert a PSLG segment into a triangulation. // +// // +/////////////////////////////////////////////////////////////////////////////// + +void tetgenmesh::insertsegmentsub(point tstart, point tend) +{ + face searchsh1, searchsh2; + + if (b->verbose > 2) { + printf(" Insert subsegment (%d, %d).\n", pointmark(tstart), + pointmark(tend)); + } + + // Find a triangle whose origin is the segment's first endpoint. + searchsh1.sh = dummysh; + // Search for the segment's first endpoint by point location. + if (locatesub(tstart, &searchsh1, NULL) != ONVERTEX) { + printf("Internal error in insertsegmentsub():"); + printf(" Unable to locate PSLG vertex %d.\n", pointmark(tstart)); + internalerror(); + } + // Scout the beginnings of a path from the first endpoint + // toward the second. + if (scoutsegmentsub(&searchsh1, tend)) { + // The segment was easily inserted. + return; + } + // The first endpoint may have changed if a collision with an intervening + // vertex on the segment occurred. + tstart = sorg(searchsh1); + + // Find a boundary triangle to search from. + searchsh2.sh = dummysh; + // Search for the segment's second endpoint by point location. + if (locatesub(tend, &searchsh2, NULL) != ONVERTEX) { + printf("Internal error in insertsegmentsub():"); + printf(" Unable to locate PSLG vertex %d.\n", pointmark(tend)); + internalerror(); + } + // Scout the beginnings of a path from the second endpoint + // toward the first. + if (scoutsegmentsub(&searchsh2, tstart)) { + // The segment was easily inserted. + return; + } + // The second endpoint may have changed if a collision with an intervening + // vertex on the segment occurred. + tend = sorg(searchsh2); + + // Insert the segment directly into the triangulation. + constrainededge(&searchsh1, tend); +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// infecthullsub() Virally infect all of the triangles of the convex hull // +// that are not protected by subsegments. // +// // +/////////////////////////////////////////////////////////////////////////////// + +void tetgenmesh::infecthullsub(memorypool* viri) +{ + face hulltri, nexttri, starttri; + face hullsubseg; + shellface **deadshellface; + + // Find a triangle handle on the hull. + hulltri.sh = dummysh; + hulltri.shver = 0; + spivotself(hulltri); + adjustedgering(hulltri, CCW); + // Remember where we started so we know when to stop. + starttri = hulltri; + // Go once counterclockwise around the convex hull. + do { + // Ignore triangles that are already infected. + if (!sinfected(hulltri)) { + // Is the triangle protected by a subsegment? + sspivot(hulltri, hullsubseg); + if (hullsubseg.sh == dummysh) { + // The triangle is not protected; infect it. + if (!sinfected(hulltri)) { + sinfect(hulltri); + deadshellface = (shellface **) viri->alloc(); + *deadshellface = hulltri.sh; + } + } + } + // To find the next hull edge, go clockwise around the next vertex. + senextself(hulltri); // lnextself(hulltri); + spivot(hulltri, nexttri); // oprev(hulltri, nexttri); + if (nexttri.sh == hulltri.sh) { + nexttri.sh = dummysh; // 'hulltri' is self-bonded. + } else { + adjustedgering(nexttri, CCW); + senextself(nexttri); + } + while (nexttri.sh != dummysh) { + hulltri = nexttri; + spivot(hulltri, nexttri); // oprev(hulltri, nexttri); + if (nexttri.sh == hulltri.sh) { + nexttri.sh = dummysh; // 'hulltri' is self-bonded. + } else { + adjustedgering(nexttri, CCW); + senextself(nexttri); + } + } + } while (hulltri != starttri); +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// plaguesub() Spread the virus from all infected triangles to any // +// neighbors not protected by subsegments. Delete all // +// infected triangles. // +// // +// This is the procedure that actually creates holes and concavities. // +// // +/////////////////////////////////////////////////////////////////////////////// + +void tetgenmesh::plaguesub(memorypool* viri) +{ + face testtri, neighbor, ghostsh; + face neighborsubseg; + shellface **virusloop; + shellface **deadshellface; + int i; + + // Loop through all the infected triangles, spreading the virus to + // their neighbors, then to their neighbors' neighbors. + viri->traversalinit(); + virusloop = (shellface **) viri->traverse(); + while (virusloop != (shellface **) NULL) { + testtri.sh = *virusloop; + // Check each of the triangle's three neighbors. + for (i = 0; i < 3; i++) { + // Find the neighbor. + spivot(testtri, neighbor); + // Check for a subsegment between the triangle and its neighbor. + sspivot(testtri, neighborsubseg); + // Check if the neighbor is nonexistent or already infected. + if ((neighbor.sh == dummysh) || sinfected(neighbor)) { + if (neighborsubseg.sh != dummysh) { + // There is a subsegment separating the triangle from its + // neighbor, but both triangles are dying, so the subsegment + // dies too. + shellfacedealloc(subsegs, neighborsubseg.sh); + if (neighbor.sh != dummysh) { + // Make sure the subsegment doesn't get deallocated again + // later when the infected neighbor is visited. + ssdissolve(neighbor); + } + } + } else { // The neighbor exists and is not infected. + if (neighborsubseg.sh == dummysh) { + // There is no subsegment protecting the neighbor, so the + // neighbor becomes infected. + sinfect(neighbor); + // Ensure that the neighbor's neighbors will be infected. + deadshellface = (shellface **) viri->alloc(); + *deadshellface = neighbor.sh; + } else { // The neighbor is protected by a subsegment. + // Remove this triangle from the subsegment. + ssbond(neighbor, neighborsubseg); + } + } + senextself(testtri); + } + virusloop = (shellface **) viri->traverse(); + } + + ghostsh.sh = dummysh; // A handle of outer space. + viri->traversalinit(); + virusloop = (shellface **) viri->traverse(); + while (virusloop != (shellface **) NULL) { + testtri.sh = *virusloop; + // Record changes in the number of boundary edges, and disconnect + // dead triangles from their neighbors. + for (i = 0; i < 3; i++) { + spivot(testtri, neighbor); + if (neighbor.sh != dummysh) { + // Disconnect the triangle from its neighbor. + // sdissolve(neighbor); + sbond(neighbor, ghostsh); + } + senextself(testtri); + } + // Return the dead triangle to the pool of triangles. + shellfacedealloc(subfaces, testtri.sh); + virusloop = (shellface **) viri->traverse(); + } + // Empty the virus pool. + viri->restart(); +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// carveholessub() Find the holes and infect them. Find the area // +// constraints and infect them. Infect the convex hull. // +// Spread the infection and kill triangles. Spread the // +// area constraints. // +// // +// This routine mainly calls other routines to carry out all these functions.// +// // +/////////////////////////////////////////////////////////////////////////////// + +void tetgenmesh::carveholessub(int holes, REAL* holelist) +{ + face searchtri, triangleloop; + shellface **holetri; + memorypool *viri; + enum locateresult intersect; + int i; + + // Initialize a pool of viri to be used for holes, concavities. + viri = new memorypool(sizeof(shellface *), 1024, POINTER, 0); + + // Mark as infected any unprotected triangles on the boundary. + // This is one way by which concavities are created. + infecthullsub(viri); + + if (holes > 0) { + // Infect each triangle in which a hole lies. + for (i = 0; i < 3 * holes; i += 3) { + // Ignore holes that aren't within the bounds of the mesh. + if ((holelist[i] >= xmin) && (holelist[i] <= xmax) + && (holelist[i + 1] >= ymin) && (holelist[i + 1] <= ymax) + && (holelist[i + 2] >= zmin) && (holelist[i + 2] <= zmax)) { + // Start searching from some triangle on the outer boundary. + searchtri.sh = dummysh; + // Find a triangle that contains the hole. + intersect = locatesub(&holelist[i], &searchtri, NULL); + if ((intersect != OUTSIDE) && (!sinfected(searchtri))) { + // Infect the triangle. This is done by marking the triangle + // as infected and including the triangle in the virus pool. + sinfect(searchtri); + holetri = (shellface **) viri->alloc(); + *holetri = searchtri.sh; + } + } + } + } + + if (viri->items > 0) { + // Carve the holes and concavities. + plaguesub(viri); + } + // The virus pool should be empty now. + + // Free up memory. + delete viri; +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// triangulatefacet() Create the constrained Delaunay triang. of a facet. // +// // +// 'facetidx' is the index of the facet in 'in->facetlist' (starts from 1), // +// 'idx2verlist' is a map from indices to vertices. 'ptlist' and 'conlist' // +// are two lists used to assemble the input data for each facet, 'ptlist' // +// stores the index set of its vertices, 'conlist' stores the set of its // +// segments, they should be empty on input and output. // +// // +// On completion, the CDT of this facet is constructed in pool 'subfaces'. // +// Every isolated point on the facet will be set a type of FACETVERTEX. // +// // +/////////////////////////////////////////////////////////////////////////////// + +void tetgenmesh:: +triangulatefacet(int facetidx, list* ptlist, list* conlist, point* idx2verlist, + queue* flipqueue) +{ + tetgenio::facet *f; + tetgenio::polygon *p; + point tstart, tend; + int end1, end2; + int *cons, idx1, idx2; + int i, j; + + if (b->verbose > 1) { + printf(" Triangulate facet %d.\n", facetidx); + } + + // Get the pointer of the facet. + f = &in->facetlist[facetidx - 1]; + + // Are there duplicated points? + if ((b->object == tetgenbehavior::STL) || dupverts) { + // Loop all polygons of this facet. + for (i = 0; i < f->numberofpolygons; i++) { + p = &(f->polygonlist[i]); + // Loop other vertices of this polygon. + for (j = 0; j < p->numberofvertices; j++) { + idx1 = p->vertexlist[j]; + tstart = idx2verlist[idx1 - in->firstnumber]; + if (pointtype(tstart) == DUPLICATEDVERTEX) { + // Reset the index of vertex-j. + tend = point2pt(tstart); + idx2 = pointmark(tend); + p->vertexlist[j] = idx2; + } + } + } + } + + // Loop all polygons of this facet, get the sets of vertices and segments. + for (i = 0; i < f->numberofpolygons; i++) { + p = &(f->polygonlist[i]); + // Get the first vertex. + end1 = p->vertexlist[0]; + if ((end1 < in->firstnumber) || + (end1 >= in->firstnumber + in->numberofpoints)) { + if (!b->quiet) { + printf("Warning: Invalid the 1st vertex %d of polygon", end1); + printf(" %d in facet %d.\n", i + 1, facetidx); + } + break; // Skip to mesh this facet. + } + // Save it in 'ptlist' if it didn't be added, and set its position. + idx1 = ptlist->hasitem(&end1); + if (idx1 == -1) { + ptlist->append(&end1); + idx1 = ptlist->len() - 1; + } + // Loop other vertices of this polygon. + for (j = 1; j <= p->numberofvertices; j++) { + // get a vertex. + if (j < p->numberofvertices) { + end2 = p->vertexlist[j]; + } else { + end2 = p->vertexlist[0]; // Form a loop from last to first. + } + if ((end2 < in->firstnumber) || + (end2 >= in->firstnumber + in->numberofpoints)) { + if (!b->quiet) { + printf("Warning: Invalid vertex %d in polygon %d", end2, i + 1); + printf(" in facet %d.\n", facetidx); + } + } else { + if (end1 != end2) { + // 'end1' and 'end2' form a segment. Save 'end2' in 'ptlist' if + // it didn't be added before. + idx2 = ptlist->hasitem(&end2); + if (idx2 == -1) { + ptlist->append(&end2); + idx2 = ptlist->len() - 1; + } + // Save the segment in 'conlist'. + cons = (int *) conlist->append(NULL); + cons[0] = idx1; + cons[1] = idx2; + // Set the start for next continuous segment. + end1 = end2; + idx1 = idx2; + } else { + // It's a (degenerate) segment with identical endpoints, which + // represents an isolate vertex in facet. + if (p->numberofvertices > 2) { + // This may be an error in the input, anyway, we let it be. + if (!b->quiet) { + printf("Warning: Polygon %d has two identical vertices", i + 1); + printf(" in facet %d.\n", facetidx); + } + } + // Set the vertex type be 'FACETVERTEX'. + // setpointtype(idx2verlist[end1 - in->firstnumber], FACETVERTEX); + // Ignore this vertex. + } + } + if (p->numberofvertices == 2) { + // This case the polygon is either a segment or an isolated vertex. + break; + } + } + } + + // Have got the vertex list and segment list. + if (b->verbose > 1) { + printf(" %d vertices, %d segments", ptlist->len(), conlist->len()); + if (f->numberofholes > 0) { + printf(", %d holes\n", f->numberofholes); + } + printf(".\n"); + } + + if (ptlist->len() > 2) { + // Construct an initial triangulation. + if (incrflipinitsub(facetidx, ptlist, idx2verlist)) { + if (ptlist->len() > 3) { + // Create the Delaunay triangulation of 'ptlist'. + incrflipdelaunaysub(facetidx, ptlist, idx2verlist, flipqueue); + } + // Insert segments (in 'conlist') into the Delaunay triangulation. + for (i = 0; i < conlist->len(); i++) { + cons = (int *)(* conlist)[i]; + idx1 = * (int *)(* ptlist)[cons[0]]; + tstart = idx2verlist[idx1 - in->firstnumber]; + idx2 = * (int *)(* ptlist)[cons[1]]; + tend = idx2verlist[idx2 - in->firstnumber]; + insertsegmentsub(tstart, tend); + } + if (ptlist->len() > 3 && conlist->len() > 3) { + // Carve holes and concavities. + carveholessub(f->numberofholes, f->holelist); + } + } + } + + // Clear working lists. + ptlist->clear(); + conlist->clear(); +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// unifysegments() Unify identical segments and build facet connections. // +// // +// After the surface mesh has been created. Each facet has its own segments. // +// There are many segments having the same endpoints, which are indentical. // +// This routine has two purposes: (1) identify the set of segments which // +// have the same endpoints and unify them into one segment, remove redundant // +// ones; and (2) create the face rings of the unified segments, hence, setup // +// the facet connections. // +// // +/////////////////////////////////////////////////////////////////////////////// + +void tetgenmesh::unifysegments() +{ + list *sfacelist; + shellface **facesperverlist; + face subsegloop, testseg; + face sface, sface1, sface2; + point torg, tdest; + REAL da1, da2; + int *idx2facelist; + int idx, k, m; + + if (b->verbose) { + printf(" Unifying segments.\n"); + } + + // Compute a mapping from indices of vertices to subfaces. + makesubfacemap(idx2facelist, facesperverlist); + // Initialize 'sfacelist' for constructing the face link of each segment. + sfacelist = new list(sizeof(face), NULL); + + subsegs->traversalinit(); + subsegloop.sh = shellfacetraverse(subsegs); + while (subsegloop.sh != (shellface *) NULL) { + subsegloop.shver = 0; // For sure. + torg = sorg(subsegloop); + tdest = sdest(subsegloop); + idx = pointmark(torg) - in->firstnumber; + // Loop through the set of subfaces containing 'torg'. Get all the + // subfaces containing the edge (torg, tdest). Save and order them + // in 'sfacelist', the ordering is defined by the right-hand rule + // with thumb points from torg to tdest. + for (k = idx2facelist[idx]; k < idx2facelist[idx + 1]; k++) { + sface.sh = facesperverlist[k]; + sface.shver = 0; + // sface may be died due to the removing of duplicated subfaces. + if (!isdead(&sface) && isfacehasedge(&sface, torg, tdest)) { + // 'sface' contains this segment. + findedge(&sface, torg, tdest); + // Save it in 'sfacelist'. + if (sfacelist->len() < 2) { + sfacelist->append(&sface); + } else { + for (m = 0; m < sfacelist->len() - 1; m++) { + sface1 = * (face *)(* sfacelist)[m]; + sface2 = * (face *)(* sfacelist)[m + 1]; + da1 = facedihedral(torg, tdest, sapex(sface1), sapex(sface)); + da2 = facedihedral(torg, tdest, sapex(sface1),sapex(sface2)); + if (da1 < da2) { + break; // Insert it after m. + } + } + sfacelist->insert(m + 1, &sface); + } + } + } + if (b->verbose > 1) { + printf(" Identifying %d segments of (%d %d).\n", sfacelist->len(), + pointmark(torg), pointmark(tdest)); + } + // Set the connection between this segment and faces containing it, + // at the same time, remove redundant segments. + for (k = 0; k < sfacelist->len(); k++) { + sface = *(face *)(* sfacelist)[k]; + sspivot(sface, testseg); + // If 'testseg' is not 'subsegloop', it is a redundant segment that + // needs be removed. BE CAREFUL it may already be removed. Do not + // remove it twice, i.e., we need do test 'isdead()' together. + if ((testseg.sh != subsegloop.sh) && !isdead(&testseg)) { + shellfacedealloc(subsegs, testseg.sh); + } + // 'ssbond' bonds the subface and the segment together, and dissloves + // the old bond as well. + ssbond(sface, subsegloop); + } + // Set connection between these faces. + sface = *(face *)(* sfacelist)[0]; + for (k = 1; k <= sfacelist->len(); k++) { + if (k < sfacelist->len()) { + sface1 = *(face *)(* sfacelist)[k]; + } else { + sface1 = *(face *)(* sfacelist)[0]; // Form a face loop. + } + /* + // Check if these two subfaces are the same. It is possible when user + // defines one facet (or polygon) two or more times. If they are, + // they should not be bonded together, instead of that, one of them + // should be delete from the surface mesh. + if ((sfacelist->len() > 1) && sapex(sface) == sapex(sface1)) { + // They are duplicated faces. + if (b->verbose) { + printf(" A duplicated subface (%d, %d, %d) is removed.\n", + pointmark(torg), pointmark(tdest), pointmark(sapex(sface))); + } + if (k == sfacelist->len()) { + // 'sface' is the last face, however, it is same as the first one. + // In order to form the ring, we have to let the second last + // face bond to the first one 'sface1'. + shellfacedealloc(subfaces, sface.sh); + assert(sfacelist->len() >= 2); + assert(k == sfacelist->len()); + sface = *(face *)(* sfacelist)[k - 2]; + } else { + // 'sface1' is in the middle and may be the last one. + shellfacedealloc(subfaces, sface1.sh); + // Skip this face and go to the next one. + continue; + } + } + */ + if (b->verbose > 2) { + printf(" Bond subfaces (%d, %d, %d) and (%d, %d, %d).\n", + pointmark(torg), pointmark(tdest), pointmark(sapex(sface)), + pointmark(torg), pointmark(tdest), pointmark(sapex(sface1))); + } + sbond1(sface, sface1); + sface = sface1; + } + // Clear the working list. + sfacelist->clear(); + subsegloop.sh = shellfacetraverse(subsegs); + } + + delete [] idx2facelist; + delete [] facesperverlist; + delete sfacelist; +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// mergefacets() Merge adjacent facets to be one facet if they are // +// coplanar and have the same boundary marker. // +// // +// Segments between two merged facets will be removed from the mesh. If all // +// segments around a vertex have been removed, change its vertex type to be // +// FACETVERTEX. Edge flips will be performed to ensure the Delaunay criteria // +// of the triangulation of merged facets. // +// // +/////////////////////////////////////////////////////////////////////////////// + +void tetgenmesh::mergefacets(queue* flipqueue) +{ + face parentsh, neighsh, neineighsh; + face segloop; + point eorg, edest; + REAL ori; + bool mergeflag; + int* segspernodelist; + int fidx1, fidx2; + int i, j; + + if (b->verbose) { + printf(" Merging coplanar facets.\n"); + } + // Create and initialize 'segspernodelist'. + segspernodelist = new int[points->items + 1]; + for (i = 0; i < points->items + 1; i++) { + segspernodelist[i] = 0; + } + + // Loop the segments, counter the number of segments sharing each vertex. + subsegs->traversalinit(); + segloop.sh = shellfacetraverse(subsegs); + while (segloop.sh != (shellface *) NULL) { + // Increment the number of sharing segments for each endpoint. + for (i = 0; i < 2; i++) { + j = pointmark((point) segloop.sh[3 + i]); + segspernodelist[j]++; + } + segloop.sh = shellfacetraverse(subsegs); + } + + // Loop the segments, find out dead segments. + subsegs->traversalinit(); + segloop.sh = shellfacetraverse(subsegs); + while (segloop.sh != (shellface *) NULL) { + eorg = sorg(segloop); + edest = sdest(segloop); + spivot(segloop, parentsh); + spivot(parentsh, neighsh); + spivot(neighsh, neineighsh); + if (parentsh.sh != neighsh.sh && parentsh.sh == neineighsh.sh) { + // Exactly two subfaces at this segment. + fidx1 = shellmark(parentsh) - 1; + fidx2 = shellmark(neighsh) - 1; + // Possibly merge them if they are not in the same facet. + if (fidx1 != fidx2) { + // Test if they are coplanar. + ori = orient3d(eorg, edest, sapex(parentsh), sapex(neighsh)); + if (ori != 0.0) { + if (iscoplanar(eorg, edest, sapex(parentsh), sapex(neighsh), ori, + b->epsilon)) { + ori = 0.0; // They are assumed as coplanar. + } + } + if (ori == 0.0) { + mergeflag = (in->facetmarkerlist == (int *) NULL || + in->facetmarkerlist[fidx1] == in->facetmarkerlist[fidx2]); + if (mergeflag) { + // This segment becomes dead. + if (b->verbose > 1) { + printf(" Removing segment (%d, %d).\n", pointmark(eorg), + pointmark(edest)); + } + ssdissolve(parentsh); + ssdissolve(neighsh); + shellfacedealloc(subsegs, segloop.sh); + j = pointmark(eorg); + segspernodelist[j]--; + if (segspernodelist[j] == 0) { + setpointtype(eorg, FACETVERTEX); + } + j = pointmark(edest); + segspernodelist[j]--; + if (segspernodelist[j] == 0) { + setpointtype(edest, FACETVERTEX); + } + // Add 'parentsh' to queue checking for flip. + enqueueflipedge(parentsh, flipqueue); + } + } + } + } + segloop.sh = shellfacetraverse(subsegs); + } + + if (!flipqueue->empty()) { + // Restore the Delaunay property in the facet triangulation. + flipsub(flipqueue); + } + + delete [] segspernodelist; +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// meshsurface() Create a surface triangulation of a PLC. // +// // +// The surface mesh consists of a set of subfaces which are two dimensional // +// constrained Delaunay triangulations of the facets of the PLC and a set of // +// subsegments which are edges bounded the facets. Subfaces belong to one // +// facet are connecting each other. Around each subsegment is a subface ring,// +// which saves the connection between facets sharing at this subsegment. // +// // +// This routine first creates the CDTs separatly, that is, each facet will // +// be meshed into a set of subfaces and subsegments. As a result, subfaces // +// only have connections to subfaces which are belong to the same facet. And // +// subsegments are over-created. Then, routine unifysegment() is called to // +// remove redundant subsegments and create the face ring around subsegments. // +// // +// Return the number of (input) segments. // +// // +/////////////////////////////////////////////////////////////////////////////// + +long tetgenmesh::meshsurface() +{ + list *ptlist, *conlist; + queue *flipqueue; + point *idx2verlist; + int i; + + if (!b->quiet) { + printf("Creating surface mesh.\n"); + } + + // Compute a mapping from indices to points. + makeindex2pointmap(idx2verlist); + // Initialize 'liftpointarray'. + liftpointarray = new REAL[in->numberoffacets * 3]; + // Initialize 'flipqueue'. + flipqueue = new queue(sizeof(badface)); + // Two re-useable lists 'ptlist' and 'conlist'. + ptlist = new list("int"); + conlist = new list(sizeof(int) * 2, NULL); + + // Loop the facet list, triangulate each facet. On finish, all subfaces + // are in 'subfaces', all segments are in 'subsegs' (Note: there exist + // duplicated segments). + for (i = 0; i < in->numberoffacets; i++) { + triangulatefacet(i + 1, ptlist, conlist, idx2verlist, flipqueue); + } + + // Unify segments in 'subsegs', remove redundant segments. Face links + // of segments are also built. + unifysegments(); + + if (b->object == tetgenbehavior::STL) { + // Remove redundant vertices (for .stl input mesh). + jettisonnodes(); + } + + if (!b->nomerge) { + // Merge adjacent facets if they are coplanar. + mergefacets(flipqueue); + } + + delete [] idx2verlist; + delete flipqueue; + delete conlist; + delete ptlist; + + return subsegs->items; +} + +// +// End of surface triangulation routines +// + +/////////////////////////////////////////////////////////////////////////////// +// // +// interecursive() Recursively do intersection test on a set of triangles.// +// // +// Recursively split the set 'subfacearray' of subfaces into two sets using // +// a cut plane parallel to x-, or, y-, or z-axies. The split criteria are // +// follows. Assume the cut plane is H, and H+ denotes the left halfspace of // +// H, and H- denotes the right halfspace of H; and s be a subface: // +// // +// (1) If all points of s lie at H+, put it into left array; // +// (2) If all points of s lie at H-, put it into right array; // +// (3) If some points of s lie at H+ and some of lie at H-, or some // +// points lie on H, put it into both arraies. // +// // +// Partitions by x-axis if axis == '0'; by y-axis if axis == '1'; by z-axis // +// if axis == '2'. If current cut plane is parallel to the x-axis, the next // +// one will be parallel to y-axis, and the next one after the next is z-axis,// +// and then alternately return back to x-axis. // +// // +// Stop splitting when the number of triangles of the input array is not // +// decreased anymore. Do tests on the current set. // +// // +/////////////////////////////////////////////////////////////////////////////// + +void tetgenmesh:: +interecursive(shellface** subfacearray, int arraysize, int axis, REAL bxmin, + REAL bxmax, REAL bymin, REAL bymax, REAL bzmin, REAL bzmax, + int* internum) +{ + shellface **leftarray, **rightarray; + face sface1, sface2; + point p1, p2, p3; + point p4, p5, p6; + enum intersectresult intersect; + REAL split; + bool toleft, toright; + int leftsize, rightsize; + int i, j; + + if (b->verbose > 1) { + printf(" Recur %d faces. Bbox (%g, %g, %g),(%g, %g, %g). %s-axis\n", + arraysize, bxmin, bymin, bzmin, bxmax, bymax, bzmax, + axis == 0 ? "x" : (axis == 1 ? "y" : "z")); + } + + leftarray = new shellface*[arraysize]; + if (leftarray == NULL) { + printf("Error in interecursive(): Insufficient memory.\n"); + exit(1); + } + rightarray = new shellface*[arraysize]; + if (rightarray == NULL) { + printf("Error in interecursive(): Insufficient memory.\n"); + exit(1); + } + leftsize = rightsize = 0; + + if (axis == 0) { + // Split along x-axis. + split = 0.5 * (bxmin + bxmax); + } else if (axis == 1) { + // Split along y-axis. + split = 0.5 * (bymin + bymax); + } else { + // Split along z-axis. + split = 0.5 * (bzmin + bzmax); + } + + for (i = 0; i < arraysize; i++) { + sface1.sh = subfacearray[i]; + p1 = (point) sface1.sh[3]; + p2 = (point) sface1.sh[4]; + p3 = (point) sface1.sh[5]; + toleft = toright = false; + if (p1[axis] < split) { + toleft = true; + if (p2[axis] >= split || p3[axis] >= split) { + toright = true; + } + } else if (p1[axis] > split) { + toright = true; + if (p2[axis] <= split || p3[axis] <= split) { + toleft = true; + } + } else { + // p1[axis] == split; + toleft = true; + toright = true; + } + // At least one is true; + assert(!(toleft == false && toright == false)); + if (toleft) { + leftarray[leftsize] = sface1.sh; + leftsize++; + } + if (toright) { + rightarray[rightsize] = sface1.sh; + rightsize++; + } + } + + if (leftsize < arraysize && rightsize < arraysize) { + // Continue to partition the input set. Now 'subfacearray' has been + // split into two sets, it's memory can be freed. 'leftarray' and + // 'rightarray' will be freed in the next recursive (after they're + // partitioned again or performing tests). + delete [] subfacearray; + // Continue to split these two sets. + if (axis == 0) { + interecursive(leftarray, leftsize, 1, bxmin, split, bymin, bymax, + bzmin, bzmax, internum); + interecursive(rightarray, rightsize, 1, split, bxmax, bymin, bymax, + bzmin, bzmax, internum); + } else if (axis == 1) { + interecursive(leftarray, leftsize, 2, bxmin, bxmax, bymin, split, + bzmin, bzmax, internum); + interecursive(rightarray, rightsize, 2, bxmin, bxmax, split, bymax, + bzmin, bzmax, internum); + } else { + interecursive(leftarray, leftsize, 0, bxmin, bxmax, bymin, bymax, + bzmin, split, internum); + interecursive(rightarray, rightsize, 0, bxmin, bxmax, bymin, bymax, + split, bzmax, internum); + } + } else { + if (b->verbose > 1) { + printf(" Checking intersecting faces.\n"); + } + // Perform a brute-force compare on the set. + for (i = 0; i < arraysize; i++) { + sface1.sh = subfacearray[i]; + p1 = (point) sface1.sh[3]; + p2 = (point) sface1.sh[4]; + p3 = (point) sface1.sh[5]; + for (j = i + 1; j < arraysize; j++) { + sface2.sh = subfacearray[j]; + p4 = (point) sface2.sh[3]; + p5 = (point) sface2.sh[4]; + p6 = (point) sface2.sh[5]; + intersect = triangle_triangle_inter(p1, p2, p3, p4, p5, p6); + if (intersect == INTERSECT || intersect == SHAREFACE) { + if (!b->quiet) { + if (intersect == INTERSECT) { + printf(" Facet #%d intersects facet #%d at triangles:\n", + shellmark(sface1), shellmark(sface2)); + printf(" (%4d, %4d, %4d) and (%4d, %4d, %4d)\n", + pointmark(p1), pointmark(p2), pointmark(p3), + pointmark(p4), pointmark(p5), pointmark(p6)); + } else { + printf(" Facet #%d duplicates facet #%d at triangle:\n", + shellmark(sface1), shellmark(sface2)); + printf(" (%4d, %4d, %4d)\n", pointmark(p1), pointmark(p2), + pointmark(p3)); + } + } + // Increase the number of intersecting pairs. + (*internum)++; + // Infect these two faces (although they may already be infected). + sinfect(sface1); + sinfect(sface2); + } + } + } + // Don't forget to free all three arrays. No further partition. + delete [] leftarray; + delete [] rightarray; + delete [] subfacearray; + } +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// detectinterfaces() Detect intersecting triangles. // +// // +// Given a set of triangles, find the pairs of intersecting triangles from // +// them. Here the set of triangles is in 'subfaces' which is a surface mesh // +// of a PLC (.poly or .smesh). // +// // +// To detect whether or not two triangles are intersecting is done by the // +// routine 'triangle_triangle_inter()'. The algorithm for the test is very // +// simple and stable. It is based on geometric orientation test which uses // +// exact arithmetics. // +// // +// Use divide-and-conquer algorithm for reducing the number of intersection // +// tests. Start from the bounding box of the input point set, recursively // +// partition the box into smaller boxes, until the number of triangles in a // +// box is not decreased anymore. Then perform triangle-triangle tests on the // +// remaining set of triangles. The memory allocated in the input set is // +// freed immediately after it has been partitioned into two arrays. So it // +// can be re-used for the consequent partitions. // +// // +// On return, pool 'subfaces' will be cleared, and only the intersecting // +// triangles remain for output (to a .face file). // +// // +/////////////////////////////////////////////////////////////////////////////// + +void tetgenmesh::detectinterfaces() +{ + shellface **subfacearray; + face shloop; + int internum; + int i; + + if (!b->quiet) { + printf("Detecting intersecting facets.\n"); + } + + // Construct a map from indices to subfaces; + subfacearray = new shellface*[subfaces->items]; + subfaces->traversalinit(); + shloop.sh = shellfacetraverse(subfaces); + i = 0; + while (shloop.sh != (shellface *) NULL) { + subfacearray[i] = shloop.sh; + shloop.sh = shellfacetraverse(subfaces); + i++; + } + + internum = 0; + // Recursively split the set of triangles into two sets using a cut plane + // parallel to x-, or, y-, or z-axies. Stop splitting when the number + // of subfaces is not decreasing anymore. Do tests on the current set. + interecursive(subfacearray, subfaces->items, 0, xmin, xmax, ymin, ymax, + zmin, zmax, &internum); + + if (!b->quiet) { + if (internum > 0) { + printf("\n!! Found %d pairs of faces are intersecting.\n\n", internum); + } else { + printf("\nNo faces are intersecting.\n\n"); + } + } + + if (internum > 0) { + // Traverse all subfaces, deallocate those have not been infected (they + // are not intersecting faces). Uninfect those have been infected. + // After this loop, only intersecting faces remain. + subfaces->traversalinit(); + shloop.sh = shellfacetraverse(subfaces); + while (shloop.sh != (shellface *) NULL) { + if (sinfected(shloop)) { + suninfect(shloop); + } else { + shellfacedealloc(subfaces, shloop.sh); + } + shloop.sh = shellfacetraverse(subfaces); + } + } else { + // Deallocate all subfaces. + subfaces->restart(); + } +} + +// +// Begin of segments recovery routines +// + +/////////////////////////////////////////////////////////////////////////////// +// // +// markacutevertices() Set the proper type (ACUTEVERTEX, NONACUTEVERTEX) // +// for segment vertices. // +// // +// Parameter 'acuteangle' gives the upperbound (in degree). Angles which are // +// smaller or equal than it are assumed as acute angles. A vertex is acute // +// if at least two segments incident at it with an acute angle. // +// // +/////////////////////////////////////////////////////////////////////////////// + +void tetgenmesh::markacutevertices(REAL acuteangle) +{ + shellface** segsperverlist; + face segloop, workseg, inciseg; + point eorg, edest, eapex; + REAL cosbound, anglearc; + REAL v1[3], v2[3], L, D; + bool isacute; + int* idx2seglist; + int idx, i, j, k; + + if (b->verbose) { + printf(" Marking segments have acute corners.\n"); + } + + // Constructing a map from vertex to segments. + makesegmentmap(idx2seglist, segsperverlist); + + // Initialize all vertices be unknown. + subsegs->traversalinit(); + segloop.sh = shellfacetraverse(subsegs); + while (segloop.sh != (shellface *) NULL) { + // Check and set types for the two ends of this segment. + for (segloop.shver = 0; segloop.shver < 2; segloop.shver++) { + eorg = sorg(segloop); + setpointtype(eorg, FACETVERTEX); + } + segloop.sh = shellfacetraverse(subsegs); + } + + anglearc = acuteangle * 3.1415926535897932 / 180.0; + cosbound = cos(anglearc); + + // Loop over the set of subsegments. + subsegs->traversalinit(); + segloop.sh = shellfacetraverse(subsegs); + while (segloop.sh != (shellface *) NULL) { + // Check and set types for the two ends of this segment. + for (segloop.shver = 0; segloop.shver < 2; segloop.shver++) { + eorg = sorg(segloop); + if ((pointtype(eorg) != ACUTEVERTEX) && + (pointtype(eorg) != NONACUTEVERTEX)) { + // This vertex has no type be set yet. + idx = pointmark(eorg) - in->firstnumber; + isacute = false; + for (i = idx2seglist[idx]; i < idx2seglist[idx + 1] && !isacute; i++) { + workseg.sh = segsperverlist[i]; + workseg.shver = 0; + if (sorg(workseg) != eorg) { + sesymself(workseg); + } + assert(sorg(workseg) == eorg); + edest = sdest(workseg); + for (j = i + 1; j < idx2seglist[idx + 1] && !isacute; j++) { + inciseg.sh = segsperverlist[j]; + inciseg.shver = 0; + assert(inciseg.sh != workseg.sh); + if (sorg(inciseg) != eorg) { + sesymself(inciseg); + } + assert(sorg(inciseg) == eorg); + eapex = sdest(inciseg); + // Check angles between segs (eorg, edest) and (eorg, eapex). + for (k = 0; k < 3; k++) { + v1[k] = edest[k] - eorg[k]; + v2[k] = eapex[k] - eorg[k]; + } + L = sqrt(v1[0] * v1[0] + v1[1] * v1[1] + v1[2] * v1[2]); + for (k = 0; k < 3; k++) v1[k] /= L; + L = sqrt(v2[0] * v2[0] + v2[1] * v2[1] + v2[2] * v2[2]); + for (k = 0; k < 3; k++) v2[k] /= L; + D = v1[0] * v2[0] + v1[1] * v2[1] + v1[2] * v2[2]; + if (D >= cosbound) { + isacute = true; + } + } + } + if (isacute) { + setpointtype(eorg, ACUTEVERTEX); + } else { + setpointtype(eorg, NONACUTEVERTEX); + } + } + } + segloop.sh = shellfacetraverse(subsegs); + } + + delete [] idx2seglist; + delete [] segsperverlist; +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// finddirection() Find the first tetrahedron on the path from one point // +// to another. // +// // +// Find the tetrahedron that intersects a line segment L (from the origin of // +// 'searchtet' to the point 'tend'), and returns the result in 'searchtet'. // +// The origin of 'searchtet' does not change, even though the tetrahedron // +// returned may differ from the one passed in. This routine is used to find // +// the direction to move in to get from one point to another. // +// // +// The return value notes the location of the line segment L with respect to // +// 'searchtet': // +// - Returns RIGHTCOLLINEAR indicates L is collinear with the line segment // +// from the origin to the destination of 'searchtet'. // +// - Returns LEFTCOLLINEAR indicates L is collinear with the line segment // +// from the origin to the apex of 'searchtet'. // +// - Returns TOPCOLLINEAR indicates L is collinear with the line segment // +// from the origin to the opposite of 'searchtet'. // +// - Returns ACROSSEDGE indicates L intersects with the line segment from // +// the destination to the apex of 'searchtet'. // +// - Returns ACROSSFACE indicates L intersects with the face opposite to // +// the origin of 'searchtet'. // +// - Returns BELOWHULL indicates L crosses outside the mesh domain. This // +// can only happen when the domain is non-convex. // +// // +// NOTE: This routine only works correctly when the mesh is exactly Delaunay.// +// // +/////////////////////////////////////////////////////////////////////////////// + +enum tetgenmesh::finddirectionresult tetgenmesh:: +finddirection(triface *searchtet, point tend) +{ + triface neightet; + point tstart, tdest, tapex, toppo; + REAL ori1, ori2, ori3; + + tstart = org(*searchtet); + assert(tstart != tend); + adjustedgering(*searchtet, CCW); + if (tstart != org(*searchtet)) { + enextself(*searchtet); // For keeping the same origin. + } + tdest = dest(*searchtet); + if (tdest == tend) { + return RIGHTCOLLINEAR; + } + tapex = apex(*searchtet); + if (tapex == tend) { + return LEFTCOLLINEAR; + } + + ori1 = orient3d(tstart, tdest, tapex, tend); + if (ori1 > 0.0) { + // 'tend' is below the face, get the neighbor of this side. + sym(*searchtet, neightet); + if (neightet.tet != dummytet) { + findorg(&neightet, tstart); + adjustedgering(neightet, CCW); + if (org(neightet) != tstart) { + enextself(neightet); // keep the same origin. + } + // Set the changed configuratiuon. + *searchtet = neightet; + ori1 = -1.0; + tdest = dest(*searchtet); + tapex = apex(*searchtet); + } else { + // A hull face. Only possible for a nonconvex mesh. +#ifdef SELF_CHECK + assert(nonconvex); +#endif + return BELOWHULL; + } + } + + // Repeatedly change the 'searchtet', remain 'tstart' be its origin, until + // find a tetrahedron contains 'tend' or is crossed by the line segment + // from 'tstart' to 'tend'. + while (true) { + toppo = oppo(*searchtet); + if (toppo == tend) { + return TOPCOLLINEAR; + } + ori2 = orient3d(tstart, toppo, tdest, tend); + if (ori2 > 0.0) { + // 'tend' is below the face, get the neighbor at this side. + fnext(*searchtet, neightet); + symself(neightet); + if (neightet.tet != dummytet) { + findorg(&neightet, tstart); + adjustedgering(neightet, CCW); + if (org(neightet) != tstart) { + enextself(neightet); // keep the same origin. + } + // Set the changed configuration. + *searchtet = neightet; + ori1 = -1.0; + tdest = dest(*searchtet); + tapex = apex(*searchtet); + // Continue the search from the changed 'searchtet'. + continue; + } else { + // A hull face. Only possible for a nonconvex mesh. +#ifdef SELF_CHECK + assert(nonconvex); +#endif + return BELOWHULL; + } + } + ori3 = orient3d(tapex, toppo, tstart, tend); + if (ori3 > 0.0) { + // 'tend' is below the face, get the neighbor at this side. + enext2fnext(*searchtet, neightet); + symself(neightet); + if (neightet.tet != dummytet) { + findorg(&neightet, tstart); + adjustedgering(neightet, CCW); + if (org(neightet) != tstart) { + enextself(neightet); // keep the same origin. + } + // Set the changed configuration. + *searchtet = neightet; + ori1 = -1.0; + tdest = dest(*searchtet); + tapex = apex(*searchtet); + // Continue the search from the changed 'searchtet'. + continue; + } else { + // A hull face. Only possible for a nonconvex mesh. +#ifdef SELF_CHECK + assert(nonconvex); +#endif + return BELOWHULL; + } + } + // Now 'ori1', 'ori2' and 'ori3' are possible be 0.0 or all < 0.0; + if (ori1 < 0.0) { + // Possible cases are: ACROSSFACE, ACROSSEDGE, TOPCOLLINEAR. + if (ori2 < 0.0) { + if (ori3 < 0.0) { + return ACROSSFACE; + } else { // ori3 == 0.0; + // Cross edge (apex, oppo) + enext2fnextself(*searchtet); + esymself(*searchtet); // org(*searchtet) == tstart; + return ACROSSEDGE; + } + } else { // ori2 == 0.0; + if (ori3 < 0.0) { + // Cross edge (dest, oppo) + fnextself(*searchtet); + esymself(*searchtet); + enextself(*searchtet); // org(*searchtet) == tstart; + return ACROSSEDGE; + } else { // ori3 == 0.0; + // Collinear with edge (org, oppo) + return TOPCOLLINEAR; + } + } + } else { // ori1 == 0.0; + // Possible cases are: RIGHTCOLLINEAR, LEFTCOLLINEAR, ACROSSEDGE. + if (ori2 < 0.0) { + if (ori3 < 0.0) { + // Cross edge (tdest, tapex) + return ACROSSEDGE; + } else { // ori3 == 0.0 + // Collinear with edge (torg, tapex) + return LEFTCOLLINEAR; + } + } else { // ori2 == 0.0; + assert(ori3 != 0.0); + // Collinear with edge (torg, tdest) + return RIGHTCOLLINEAR; + } + } + } +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// getsearchtet() Find a tetrahedron whose origin is either 'p1' or 'p2'. // +// // +// On return, the origin of 'searchtet' is either 'p1' or 'p2', and 'tend' // +// returns the other point. 'searchtet' serves as the starting tetrahedron // +// for searching of the line segment from 'p1' to 'p2' or vice versa. // +// // +/////////////////////////////////////////////////////////////////////////////// + +void tetgenmesh:: +getsearchtet(point p1, point p2, triface* searchtet, point* tend) +{ + tetrahedron encodedtet1, encodedtet2; + + // Is there a valid handle provided by the user? + if ((searchtet->tet != (tetrahedron *) NULL) && !isdead(searchtet)) { + // Find which endpoint the handle holds. + if (findorg(searchtet, p1)) { + *tend = p2; + return; + } else { + if (findorg(searchtet, p2)) { + *tend = p1; + return; + } + } + } + // If not, search the handle stored in 'p1' or 'p2'. + *tend = (point) NULL; + encodedtet1 = point2tet(p1); + encodedtet2 = point2tet(p2); + if (encodedtet1 != (tetrahedron) NULL) { + decode(encodedtet1, *searchtet); + // Be careful, here 'searchtet' may be dead. + if (findorg(searchtet, p1)) { + *tend = p2; + } + } else if (encodedtet2 != (tetrahedron) NULL) { + decode(encodedtet2, *searchtet); + // Be careful, here 'searchtet' may be dead. + if (findorg(searchtet, p2)) { + *tend = p1; + } + } + // If still not, perform a full point location. The starting tetrahedron + // is chosen as follows: Use the handle stored in 'p1' or 'p2' if it is + // alive; otherwise, start from a tetrahedron on the convex hull. + if (*tend == (point) NULL) { + if (encodedtet1 != (tetrahedron) NULL) { + decode(encodedtet1, *searchtet); + // Be careful, here 'searchtet' may be dead. + } + if (isdead(searchtet)) { + if (encodedtet2 != (tetrahedron) NULL) { + decode(encodedtet2, *searchtet); + // Be careful, here 'searchtet' may be dead. + } + if (isdead(searchtet)) { + searchtet->tet = dummytet; + searchtet->loc = 0; + symself(*searchtet); + } + assert(!isdead(searchtet)); + } + if (locate(p1, searchtet) != ONVERTEX) { + printf("Internal error in getsearchtet(): Failed to locate point\n"); + printf(" (%.12g, %.12g, %.12g) %d.\n", p1[0], p1[1], p1[2], + pointmark(p1)); + internalerror(); + } + // Remember this handle in 'p1' to enhance the search speed. + setpoint2tet(p1, encode(*searchtet)); + *tend = p2; + } +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// isedgeencroached() Check whether or not a subsegment is encroached by // +// a given point. // +// // +// A segment with endpoints 'p1' and 'p2' is encroached by the point 'testpt'// +// if it lies in the diametral sphere of this segment. The degenerate case // +// that 'testpt' lies on the sphere can be treated as either be encroached // +// or not so. If you want to regard this case as be encroached, set the flag // +// 'degflag' be TRUE. // +// // +/////////////////////////////////////////////////////////////////////////////// + +bool tetgenmesh:: +isedgeencroached(point p1, point p2, point testpt, bool degflag) +{ + REAL dotproduct; + + // Check if the segment is facing an angle larger than 90 degree? + dotproduct = (p1[0] - testpt[0]) * (p2[0] - testpt[0]) + + (p1[1] - testpt[1]) * (p2[1] - testpt[1]) + + (p1[2] - testpt[2]) * (p2[2] - testpt[2]); + if (dotproduct < 0) { + return true; + } else if (dotproduct == 0 && degflag) { + return true; + } else { + return false; + } +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// scoutrefpoint() Search the reference point of a missing segment. // +// // +// A segment S is missing in current Delaunay tetrahedralization DT and will // +// be split by inserting a point V in it. The two end points of S are the // +// origin of 'searchtet' and 'tend'. And we know that S is crossing the face // +// of 'searchtet' opposite to its origin (may be intersecting with the edge // +// from the destination to the apex of the 'searchtet'). The search of P is // +// completed by walking through all faces of DT across by S. // +// // +// The reference point P of S is an existing vertex of DT which is 'respon- // +// sible' for deciding where to insert V. P is chosen as follows: // +// (1) P encroaches upon S; and // +// (2) the circumradius of the smallest circumsphere of the triangle // +// formed by the two endpoints of S and P is maximum over other // +// encroaching points of S. // +// The reference point of S may not unique, choose arbitrary one if there're // +// several points available. // +// // +// Warning: This routine is correct when the tetrahedralization is Delaunay // +// and convex. Otherwise, the search loop may not terminate. // +// // +/////////////////////////////////////////////////////////////////////////////// + +tetgenmesh::point tetgenmesh::scoutrefpoint(triface* searchtet, point tend) +{ + triface checkface; + point tstart, testpt, refpoint; + REAL cent[3], radius, largest; + REAL ahead; + bool ncollinear; + int sides; + + if (b->verbose > 2) { + printf(" Scout the reference point of segment (%d, %d).\n", + pointmark(org(*searchtet)), pointmark(tend)); + } + + tstart = org(*searchtet); + refpoint = (point) NULL; + + // Check the three vertices of the crossing face. + testpt = apex(*searchtet); + if (isedgeencroached(tstart, tend, testpt, true)) { + ncollinear = circumsphere(tstart, tend, testpt, NULL, cent, &radius); + assert(ncollinear); + refpoint = testpt; + largest = radius; + } + testpt = dest(*searchtet); + if (isedgeencroached(tstart, tend, testpt, true)) { + ncollinear = circumsphere(tstart, tend, testpt, NULL, cent, &radius); + assert(ncollinear); + if (refpoint == (point) NULL) { + refpoint = testpt; + largest = radius; + } else { + if (radius > largest) { + refpoint = testpt; + largest = radius; + } + } + } + testpt = oppo(*searchtet); + if (isedgeencroached(tstart, tend, testpt, true)) { + ncollinear = circumsphere(tstart, tend, testpt, NULL, cent, &radius); + assert(ncollinear); + if (refpoint == (point) NULL) { + refpoint = testpt; + largest = radius; + } else { + if (radius > largest) { + refpoint = testpt; + largest = radius; + } + } + } + // Check the opposite vertex of the neighboring tet in case the segment + // crosses the edge (leftpoint, rightpoint) of the crossing face. + sym(*searchtet, checkface); + if (checkface.tet != dummytet) { + testpt = oppo(checkface); + if (isedgeencroached(tstart, tend, testpt, true)) { + ncollinear = circumsphere(tstart, tend, testpt, NULL, cent, &radius); + assert(ncollinear); + if (refpoint == (point) NULL) { + refpoint = testpt; + largest = radius; + } else { + if (radius > largest) { + refpoint = testpt; + largest = radius; + } + } + } + } + + // Walk through all crossing faces. + enextfnext(*searchtet, checkface); + sym(checkface, *searchtet); + while (true) { + // Check if we are reaching the boundary of the triangulation. + assert(searchtet->tet != dummytet); + // Search for an adjoining tetrahedron we can walk through. + searchtet->ver = 0; + // 'testpt' is the shared vertex for the following orientation tests. + testpt = oppo(*searchtet); + if (testpt == tend) { + // The searching is finished. + break; + } else { + // 'testpt' may encroach the segment. + if ((testpt != tstart) && (testpt != refpoint)) { + if (isedgeencroached(tstart, tend, testpt, true)) { + ncollinear = circumsphere(tstart, tend, testpt, NULL, cent, &radius); + if (!ncollinear) { + // 'testpt' is collinear with the segment. It may happen when a + // set of collinear and continuous segments is defined by two + // extreme endpoints. In this case, we should choose 'testpt' + // as the splitting point immediately. No new point should be + // created. + refpoint = testpt; + break; + } + if (refpoint == (point) NULL) { + refpoint = testpt; + largest = radius; + } else { + if (radius > largest) { + refpoint = testpt; + largest = radius; + } + } + } + } + } + // Check three side-faces of 'searchtet' to find the one through + // which we can walk next. + for (sides = 0; sides < 3; sides++) { + fnext(*searchtet, checkface); + ahead = orient3d(org(checkface), dest(checkface), testpt, tend); + if (ahead < 0.0) { + // We can walk through this face and continue the searching. + sym(checkface, *searchtet); + break; + } + enextself(*searchtet); + } + assert (sides < 3); + } + + assert(refpoint != (point) NULL); + return refpoint; +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// getsegmentorigin() Return the origin of the (unsplit) segment. // +// // +// After a segment (or a subsegment) is split. Two resulting subsegments are // +// connecting each other through the pointers saved in their data fields. // +// With these pointers, the whole (unsplit) segment can be found. 'splitseg' // +// may be a split subsegment. Returns the origin of the unsplit segment. // +// // +/////////////////////////////////////////////////////////////////////////////// + +tetgenmesh::point tetgenmesh::getsegmentorigin(face* splitseg) +{ + face workseg; + point farorg; + + farorg = sorg(*splitseg); + if ((pointtype(farorg) != ACUTEVERTEX) && + (pointtype(farorg) != NONACUTEVERTEX)) { + workseg = *splitseg; + do { + senext2self(workseg); + spivotself(workseg); + if (workseg.sh != dummysh) { + workseg.shver = 0; // It's a subsegment. + if (sdest(workseg) != farorg) { + sesymself(workseg); + assert(sdest(workseg) == farorg); + } + farorg = sorg(workseg); + if ((pointtype(farorg) == ACUTEVERTEX) || + (pointtype(farorg) == NONACUTEVERTEX)) break; + } + } while (workseg.sh != dummysh); + } + assert((pointtype(farorg) == ACUTEVERTEX) || + (pointtype(farorg) == NONACUTEVERTEX)); + return farorg; +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// getsplitpoint() Get a point for splitting a segment. // +// // +// 'splitseg' is the segment will be split. 'refpoint' is a reference point // +// for splitting this segment. Moreover, it should not collinear with the // +// splitting segment. (The collinear case will be detected by iscollinear() // +// before entering this routine.) The calculation of the splitting point is // +// governed by three rules introduced in my paper. // +// // +// After the position is calculated, a new point is created at this location.// +// The new point has one of the two pointtypes: FREESEGVERTEX indicating it // +// is an inserting vertex on segment, and NONACUTEVERTEX indicating it is an // +// endpoint of a segment which original has type-3 now becomes type-2. // +// // +/////////////////////////////////////////////////////////////////////////////// + +tetgenmesh::point tetgenmesh::getsplitpoint(face* splitseg, point refpoint) +{ + point splitpoint; + point farorg, fardest; + point ei, ej, ek, c; + REAL v[3], r, split; + bool acuteorg, acutedest; + int stype, ptmark; + int i; + + // First determine the type of the segment (type-1, type-2, or type-3). + farorg = getsegmentorigin(splitseg); + acuteorg = (pointtype(farorg) == ACUTEVERTEX); + sesymself(*splitseg); + fardest = getsegmentorigin(splitseg); + acutedest = (pointtype(fardest) == ACUTEVERTEX); + sesymself(*splitseg); + + if (acuteorg) { + if (acutedest) { + stype = 3; + } else { + stype = 2; + ek = farorg; + } + } else { + if (acutedest) { + stype = 2; + // Adjust splitseg, so that its origin is acute. + sesymself(*splitseg); + ek = fardest; + } else { + stype = 1; + } + } + ei = sorg(*splitseg); + ej = sdest(*splitseg); + + if (b->verbose > 1) { + printf(" Splitting segment (%d, %d) type-%d with refpoint %d.\n", + pointmark(ei), pointmark(ej), stype, pointmark(refpoint)); + } + + if (stype == 1 || stype == 3) { + // Use rule-1. + REAL eij, eip, ejp; + eij = distance(ei, ej); + eip = distance(ei, refpoint); + ejp = distance(ej, refpoint); + if ((eip < ejp) && (eip < 0.5 * eij)) { + c = ei; + r = eip; + } else if ((eip > ejp) && (ejp < 0.5 * eij)) { + c = ej; + ej = ei; + r = ejp; + } else { + c = ei; + r = 0.5 * eij; + } + split = r / eij; + for (i = 0; i < 3; i++) { + v[i] = c[i] + split * (ej[i] - c[i]); + } + } else { + // Use rule-2 or rule-3. + REAL eki, ekj, ekp, evj, evp, eiv; + c = ek; + eki = distance(ek, ei); // eki may equal zero. + ekj = distance(ek, ej); + ekp = distance(ek, refpoint); + // Calculate v (the going to split position between ei, ej). + r = ekp; + assert(eki < r && r < ekj); + split = r / ekj; + for (i = 0; i < 3; i++) { + v[i] = c[i] + split * (ej[i] - c[i]); + } + evj = ekj - r; // distance(v, ej); + evp = distance(v, refpoint); + if (evj < evp) { + // v is rejected, use rule-3. + eiv = distance(ei, v); + if (evp <= 0.5 * eiv) { + r = eki + eiv - evp; + } else { + r = eki + 0.5 * eiv; + } + assert(eki < r && r < ekj); + split = r / ekj; + for (i = 0; i < 3; i++) { + v[i] = c[i] + split * (ej[i] - c[i]); + } + if (b->verbose > 1) { + printf(" Using rule-3.\n"); + } + } + } + + if (b->verbose > 1) { + if (stype == 2) { + printf(" Split = %.12g.\n", distance(ei, v) / distance(ei, ej)); + } else { + printf(" Split = %.12g.\n", distance(c, v) / distance(c, ej)); + } + } + + // Allocate a point from points. + splitpoint = (point) points->alloc(); + // Set its coordinates. + for (i = 0; i < 3; i++) { + splitpoint[i] = v[i]; + } + // Interpolate its attributes. + for (i = 0; i < in->numberofpointattributes; i++) { + splitpoint[i + 3] = c[i + 3] + split * (ej[i + 3] - c[i + 3]); + } + // Remember the index (starts from 'in->firstnumber') of this vertex. + ptmark = (int) points->items - (in->firstnumber == 1 ? 0 : 1); + setpointmark(splitpoint, ptmark); + if (stype == 3) { + // Change a type-3 segment into two type-2 segments. + setpointtype(splitpoint, NONACUTEVERTEX); + } else { + // Set it's type be FREESEGVERTEX. + setpointtype(splitpoint, FREESEGVERTEX); + } + // Init this field. + setpoint2tet(splitpoint, NULL); + + return splitpoint; +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// delaunizesegments() Split segments repeatedly until they appear in a // +// Delaunay tetrahedralization together. // +// // +// Given a PLC X, which has a set V of vertices and a set of segments. Start // +// from a Delaunay tetrahedralization D of V, this routine recovers segments // +// of X in D by incrementally inserting points on missing segments, updating // +// D with the newly inserted points into D', which remains to be a Delaunay // +// tetrahedralization and respects the segments of X. Hence, each segment of // +// X appears as a union of edges in D'. // +// // +// This routine dynamically maintains two meshes, one is DT, another is the // +// surface mesh F of X. DT and F have exactly the same vertices. They are // +// updated simultaneously with the newly inserted points. // +// // +// Missing segments are found by looping the set S of segments, checking the // +// existence of each segment in DT. Once a segment is found missing in DT, // +// it is split into two subsegments by inserting a point into both DT and F, // +// and S is updated accordingly. However, the inserted point may cause some // +// other existing segments be non-Delaunay, hence are missing from the DT. // +// In order to force all segments to appear in DT, we have to loop S again // +// after some segments are split. (A little ugly method) Use a handle to // +// remember the last segment be split in one loop, hence all segments after // +// it are existing and need not be checked. // +// // +// In priciple, a segment on the convex hull should exist in DT. However, if // +// there are four coplanar points on the convex hull, and the DT only can // +// contain one diagonal edge which is unfortunately not the segment, then it // +// is missing. During the recovery of the segment, it is possible that the // +// calculated inserting point for recovering this convex hull segment is not // +// exact enough and lies (slightly) outside the DT. In order to insert the // +// point, we enlarge the convex hull of the DT, so it can contain the point // +// and remains convex. 'inserthullsite()' is called under this case. // +// // +/////////////////////////////////////////////////////////////////////////////// + +void tetgenmesh::delaunizesegments() +{ + queue *flipqueue; + triface searchtet; + face segloop, lastsplit; + face splitsh; + point p1, p2; + point tend, checkpoint; + point refpoint, splitpoint; + enum finddirectionresult collinear; + enum insertsiteresult success; + bool finish; + + if (!b->quiet) { + printf("Delaunizing segments.\n"); + } + + // Mark segment vertices (acute or not) for determining segment types. + markacutevertices(60.0); + // Construct a map from points to tetrahedra for speeding point location. + makepoint2tetmap(); + // Initialize a queue for returning non-Delaunay faces and edges. + flipqueue = new queue(sizeof(badface)); + // 'lastsplit' is the last segment be split in one loop, all segments + // after it are existing. At first, set it be NULL; + lastsplit.sh = (shellface *) NULL; + + finish = false; + while (!finish && (steinerleft != 0)) { + subsegs->traversalinit(); + segloop.sh = shellfacetraverse(subsegs); + while ((segloop.sh != (shellface *) NULL) && (steinerleft != 0)) { + // Search the segment in DT. + p1 = sorg(segloop); + p2 = sdest(segloop); + if (b->verbose > 2) { + printf(" Checking segment (%d, %d).\n", pointmark(p1), pointmark(p2)); + } + getsearchtet(p1, p2, &searchtet, &tend); + collinear = finddirection(&searchtet, tend); + if (collinear == LEFTCOLLINEAR) { + checkpoint = apex(searchtet); + } else if (collinear == RIGHTCOLLINEAR) { + checkpoint = dest(searchtet); + } else if (collinear == TOPCOLLINEAR) { + checkpoint = oppo(searchtet); + } else { + assert(collinear == ACROSSFACE || collinear == ACROSSEDGE); + checkpoint = (point) NULL; + } + if (checkpoint != tend) { + // The segment is missing. + if (checkpoint != (point) NULL) { + splitpoint = checkpoint; + } else { + refpoint = scoutrefpoint(&searchtet, tend); + if (iscollinear(p1, p2, refpoint, b->epsilon)) { + splitpoint = refpoint; + } else { + splitpoint = getsplitpoint(&segloop, refpoint); + // Insert 'splitpoint' into DT. + success = insertsite(splitpoint, &searchtet, false, flipqueue); + if (success == OUTSIDEPOINT) { + // A convex hull edge is mssing, and the inserting point lies + // (slightly) outside the convex hull due to the significant + // digits lost in the calculation. Enlarge the convex hull. + inserthullsite(splitpoint, &searchtet, flipqueue, NULL, NULL); + } + if (steinerleft > 0) steinerleft--; + // Remember a handle in 'splitpoint' to enhance the speed of + // consequent point location. + setpoint2tet(splitpoint, encode(searchtet)); + // Maintain Delaunayness in DT. + flip(flipqueue, NULL); + } + } + // Insert 'splitpoint' into F. + spivot(segloop, splitsh); + splitsubedge(splitpoint, &splitsh, flipqueue); + flipsub(flipqueue); + // Remember 'segloop'. + lastsplit = segloop; + } else { + // The segment exists. + if (segloop.sh == lastsplit.sh) { + finish = true; + break; + } + } + segloop.sh = shellfacetraverse(subsegs); + } + if (lastsplit.sh == (shellface *) NULL) { + // No missing segment! + finish = true; + } + } + + delete flipqueue; +} + +// +// End of segments recovery routines +// + +// +// Begin of constrained Delaunay triangulation routines +// + +/////////////////////////////////////////////////////////////////////////////// +// // +// insertsubface() Insert a subface into the Delaunay tetrahedralization. // +// // +// Search the subface in current Delaunay tetrahedralization. Return TRUE if // +// the subface exists, i.e., it appears as a face of the DT and is inserted. // +// Otherwise, return FALSE indicating it is a missing face. // +// // +/////////////////////////////////////////////////////////////////////////////// + +bool tetgenmesh::insertsubface(face* insertsh, triface* searchtet) +{ + triface spintet, symtet; + face testsh, testseg; + face spinsh, casin, casout; + point tapex, checkpoint; + enum finddirectionresult collinear; + int hitbdry; + + // Search one edge of 'insertsh'. + getsearchtet(sorg(*insertsh), sdest(*insertsh), searchtet, &checkpoint); + collinear = finddirection(searchtet, checkpoint); + if (collinear == LEFTCOLLINEAR) { + enext2self(*searchtet); + esymself(*searchtet); + } else if (collinear == TOPCOLLINEAR) { + fnextself(*searchtet); + enext2self(*searchtet); + esymself(*searchtet); + } + if (dest(*searchtet) != checkpoint) { + // The edge is missing => subface is missing. + return false; + } + + // Spin around the edge (torg, tdest), look for a face containing tapex. + tapex = sapex(*insertsh); + spintet = *searchtet; + hitbdry = 0; + do { + if (apex(spintet) == tapex) { + // The subface is exist in DT. We will insert this subface. Before + // insertion, make sure there is no subface at this position. + tspivot(spintet, testsh); + if (testsh.sh == dummysh) { + adjustedgering(spintet, CCW); + findedge(insertsh, org(spintet), dest(spintet)); + tsbond(spintet, *insertsh); + sym(spintet, symtet); // 'symtet' maybe outside, use it anyway. + sesymself(*insertsh); + tsbond(symtet, *insertsh); + } else { + // There already exists one subface. They're Duplicated. + printf("Warning: Two subfaces are found duplicated at "); + printf("(%d, %d, %d)\n", pointmark(sorg(testsh)), + pointmark(sdest(testsh)), pointmark(sapex(testsh))); + printf(" The one of facet #%d is ignored.\n", shellmark(*insertsh)); + // printf(" Hint: -d switch can find all duplicated facets.\n"); + } + return true; + } + if (!fnextself(spintet)) { + hitbdry ++; + if (hitbdry < 2) { + esym(*searchtet, spintet); + if (!fnextself(spintet)) { + hitbdry ++; + } + } + } + } while (hitbdry < 2 && apex(spintet) != apex(*searchtet)); + + // The face is missing. + return false; +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// tritritest() Test if two triangles are intersecting in their interior. // +// // +// One triangles is represented by 'checktet', the other is given by three // +// corners 'p1', 'p2' and 'p3'. This routine calls triangle_triangle_inter() // +// to detect whether or not these two triangles are exactly intersecting in // +// their interior (excluding the cases share a vertex, share an edge, or are // +// coincide). // +// // +/////////////////////////////////////////////////////////////////////////////// + +bool tetgenmesh::tritritest(triface* checktet, point p1, point p2, point p3) +{ + point forg, fdest, fapex; + enum intersectresult intersect; + + forg = org(*checktet); + fdest = dest(*checktet); + fapex = apex(*checktet); + +#ifdef SELF_CHECK + REAL ax, ay, az, bx, by, bz; + REAL n[3]; + // face (torg, tdest, tapex) should not be degenerate. However p1, p2, + // and p3 may be collinear. Check it. + ax = forg[0] - fdest[0]; + ay = forg[1] - fdest[1]; + az = forg[2] - fdest[2]; + bx = forg[0] - fapex[0]; + by = forg[1] - fapex[1]; + bz = forg[2] - fapex[2]; + n[0] = ay * bz - by * az; + n[1] = az * bx - bz * ax; + n[2] = ax * by - bx * ay; + assert(fabs(n[0]) + fabs(n[1]) + fabs(n[2]) > 0.0); + // The components of n should not smaller than the machine epsilon. + + ax = p1[0] - p2[0]; + ay = p1[1] - p2[1]; + az = p1[2] - p2[2]; + bx = p1[0] - p3[0]; + by = p1[1] - p3[1]; + bz = p1[2] - p3[2]; + n[0] = ay * bz - by * az; + n[1] = az * bx - bz * ax; + n[2] = ax * by - bx * ay; + assert(fabs(n[0]) + fabs(n[1]) + fabs(n[2]) > 0.0); + // The components of n should not smaller than the machine epsilon. +#endif + + intersect = triangle_triangle_inter(forg, fdest, fapex, p1, p2, p3); + return intersect == INTERSECT; +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// initializecavity() Create the initial fronts. // +// // +// 'floorlist' is a list of coplanar subfaces, they are oriented in the same // +// direction pointing to the ceiling. 'ceilinglist' is a list of faces of // +// tetrahedra which are crossing the cavity, they form the rest part of the // +// boundary of the cavity. 'frontlink' is used to return the list of fronts, // +// it is empty on input. // +// // +/////////////////////////////////////////////////////////////////////////////// + +void tetgenmesh:: +initializecavity(list* floorlist, list* ceillist, list* floorptlist, + list* ceilptlist, link* frontlink, link* ptlink) +{ + triface neightet, casingtet; + triface faketet; + face worksh; + int i; + + // First add all faces in 'floorlist' into 'frontlink'. + for (i = 0; i < floorlist->len(); i++) { + worksh = * (face *)(* floorlist)[i]; + // Current side of 'worksh' should be empty. + stpivot(worksh, neightet); + assert(neightet.tet == dummytet); + // Check another side, if there is no tetrahedron, create a 'fake' + // tetrahedron in order to hold this side. It will be removed + // during filling the cavity. + sesymself(worksh); + stpivot(worksh, casingtet); + if (casingtet.tet == dummytet) { + maketetrahedron(&faketet); + setorg(faketet, sorg(worksh)); + setdest(faketet, sdest(worksh)); + setapex(faketet, sapex(worksh)); + setoppo(faketet, (point) NULL); // Indicates it is 'fake'. + tsbond(faketet, worksh); + frontlink->add(&faketet); + } else { + frontlink->add(&casingtet); + } + } + // Second add all casing faces in 'ceilinglist' into 'frontlink'. + for (i = 0; i < ceillist->len(); i++) { + neightet = * (triface *) (* ceillist)[i]; + // The ceil is a face of cavity tetrahedron (going to be deleted). + assert(infected(neightet)); + sym(neightet, casingtet); + if (casingtet.tet == dummytet) { + // This side is on the hull. Create a 'fake' tetrahedron in order to + // hold this side. It will be removed during filling the cavity. + tspivot(neightet, worksh); + maketetrahedron(&faketet); + setorg(faketet, org(neightet)); + setdest(faketet, dest(neightet)); + setapex(faketet, apex(neightet)); + setoppo(faketet, (point) NULL); // Indicates it is 'fake'. + if (worksh.sh != dummysh) { + sesymself(worksh); + tsbond(faketet, worksh); + } + frontlink->add(&faketet); + } else { + frontlink->add(&casingtet); + } + } + // Put points in 'equatptlist' and 'ceilptlist' into 'ptlink'. + for (i = 0; i < floorptlist->len(); i++) { + ptlink->add((point *)(* floorptlist)[i]); + } + for (i = 0; i < ceilptlist->len(); i++) { + ptlink->add((point *)(* ceilptlist)[i]); + } +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// reducecavity() Reduce the cavity by chopping off tetrahedra formed by // +// faces in 'frontlink' without creating new edges. // +// // +// When a face of cavity has three neighbors which are sharing a same vertex,// +// form a tetrahedron from the face and the vertex, consequently, four faces // +// of the cavity are removed. If only two of its three neighbors share a // +// common vertex, it only can form a tetrahedron when no vertex of the // +// cavity lies inside the tetrahedorn, consequently, three faces are removed // +// from the cavity and a face(at the open side) becomes a face of the cavity.// +// // +// Not every face of the cavity can be removed by this way. This routine // +// returns when there is no face can be removed. // +// // +/////////////////////////////////////////////////////////////////////////////// + +bool tetgenmesh::reducecavity(link* frontlink, link* ptlink, queue* flipqueue) +{ + triface front, *neigh[3], *checkface; + triface newtet, newface; + face checksh; + point *ploop; + point forg, fdest; + point workpt[3], shareoppo; + REAL sign; + bool isneighbor, isconvex; + int loopcount, share; + int i, j, k; + + if (b->verbose > 2) { + printf(" Reducecavity: %d faces.\n", (int) frontlink->len()); + } + + loopcount = 0; + while (loopcount < frontlink->len()) { + // Get and remove a front face from 'fronlink'. + front = * (triface *) frontlink->del(1); + // Make the front point to insde the cavity. + adjustedgering(front, CW); + if (b->verbose > 2) { + printf(" Get front (%d, %d, %d).\n", pointmark(org(front)), + pointmark(dest(front)), pointmark(apex(front))); + } + // Find the three neighbors of 'front' in 'frontlink'. They must exist, + // because the cavity is closed. + for (i = 0; i < 3; i++) { + forg = org(front); + fdest = dest(front); + isneighbor = false; + for (j = 0; j < frontlink->len() && !isneighbor; j++) { + checkface = (triface *) frontlink->getnitem(j + 1); + for (k = 0; k < 3; k++) { + workpt[0] = org(*checkface); + workpt[1] = dest(*checkface); + if (workpt[0] == forg) { + if (workpt[1] == fdest) isneighbor = true; + } else if (workpt[0] == fdest) { + if (workpt[1] == forg) isneighbor = true; + } + if (isneighbor) { + neigh[i] = checkface; + break; + } + enextself(*checkface); + } + } + assert(isneighbor); + enextself(front); + } + + // Find the number of common apexes. + for (i = 0; i < 3; i++) { + workpt[i] = apex(*neigh[i]); + } + if (workpt[0] == workpt[1]) { + shareoppo = workpt[0]; + if (workpt[1] == workpt[2]) { + share = 3; + } else { + share = 2; + } + } else if (workpt[0] == workpt[2]) { + shareoppo = workpt[0]; + share = 2; + } else { + if (workpt[1] == workpt[2]) { + shareoppo = workpt[1]; + share = 2; + } else { + share = 1; + } + } + + if (share == 2) { + // It is possible that the open side is also a cavity face, but not + // pop up because there are more than two cavity faces sharing the + // edge. Check is there a cavity face having this edge and having + // its apex be 'shareoppo'. + for (i = 0; i < 3; i++) { + if (workpt[i] != shareoppo) { + // 'neigh[i]' is the open side. Get the edge. + forg = org(*neigh[i]); + fdest = dest(*neigh[i]); + break; + } + } + assert(i < 3); + // Search faces containing edge (forg, fdest) in 'frontlist'. If + // the found face containing 'shareoppo', stop; + for (j = 0; j < frontlink->len() && share != 3; j++) { + checkface = (triface *) frontlink->getnitem(j + 1); + // Skip if it is one of the neighbors. + if ((checkface == neigh[0]) || (checkface == neigh[1]) || + (checkface == neigh[2])) continue; + isneighbor = false; + for (k = 0; k < 3; k++) { + workpt[0] = org(*checkface); + workpt[1] = dest(*checkface); + if (workpt[0] == forg) { + if (workpt[1] == fdest) isneighbor = true; + } else if (workpt[0] == fdest) { + if (workpt[1] == forg) isneighbor = true; + } + if (isneighbor) { + if (apex(*checkface) == shareoppo) { + // Find! Change the old neighbor at this side be this one. + neigh[i] = checkface; + share = 3; + break; + } + } + enextself(*checkface); + } + } + } + + isconvex = true; + if (share == 2 || share == 3) { + // It is possible to reduce the cavity by constructing a tetrahedron + // from the face 'front' and 'shareoppo'. However, we have to make + // sure that this tetrahedron is valid, i.e., shareoppo should lie + // above front. + workpt[0] = org(front); + workpt[1] = dest(front); + workpt[2] = apex(front); + sign = orient3d(workpt[0], workpt[1], workpt[2], shareoppo); + if (sign > 0.0) { + // It is not a valid tetrahedron, skip to create it. + isconvex = false; + } else if (sign == 0.0) { + // These four points are coplanar. If there are only three faces + // left, we should stop here. Create a degenerate tetrahedron + // on these four faces and return. It will be repaired later. + if (frontlink->len() > 3) { + isconvex = false; + } + } + } + if (share == 2 && isconvex) { + // Check if we can reduce the tetrahedron formed by the front and the + // shareoppo. The condition is no vertex is inside the tetrahedron. + for (i = 0; i < ptlink->len() && isconvex; i++) { + ploop = (point *) ptlink->getnitem(i + 1); + if (*ploop == workpt[0] || *ploop == workpt[1] || *ploop == workpt[2] + || *ploop == shareoppo) continue; + sign = orient3d(workpt[0], workpt[1], workpt[2], *ploop); + isconvex = sign > 0.0; + if (isconvex) continue; + sign = orient3d(workpt[1], workpt[0], shareoppo, *ploop); + isconvex = sign > 0.0; + if (isconvex) continue; + sign = orient3d(workpt[2], workpt[1], shareoppo, *ploop); + isconvex = sign > 0.0; + if (isconvex) continue; + sign = orient3d(workpt[0], workpt[2], shareoppo, *ploop); + isconvex = sign > 0.0; + } + } + + if (share == 1 || !isconvex) { + // Put 'front' back into 'frontlink'. + frontlink->add(&front); + loopcount++; // Increase the loop counter. + continue; + } else { + // Find a reducable tetrahedron. Reset the loop counter. + loopcount = 0; + } + + if (b->verbose > 2) { + for (i = 0; i < 3; i++) { + if (apex(*neigh[i]) == shareoppo) { + printf(" (%d, %d, %d).\n", pointmark(org(*neigh[i])), + pointmark(dest(*neigh[i])), pointmark(apex(*neigh[i]))); + } + } + } + + // The front will be finished by two or three faces. + maketetrahedron(&newtet); + setorg(newtet, org(front)); + setdest(newtet, dest(front)); + setapex(newtet, apex(front)); + setoppo(newtet, shareoppo); + // 'front' may be a 'fake' tet. + tspivot(front, checksh); + if (oppo(front) == (point) NULL) { + // Dealloc the 'fake' tet. + tetrahedrondealloc(front.tet); + // This side (newtet) is a boundary face, let 'dummytet' bond to it. + // Otherwise, 'dummytet' may point to a dead tetrahedron after the + // old cavity tets are removed. + dummytet[0] = encode(newtet); + } else { + // Bond two tetrahedra, also dissolve the old bond at 'front'. + bond(newtet, front); + // 'front' becomes an interior face, add it to 'flipqueue'. + if (flipqueue != (queue *) NULL) { + enqueueflipface(front, flipqueue); + } + } + if (checksh.sh != dummysh) { + if (oppo(front) == (point) NULL) { + stdissolve(checksh); + } + sesymself(checksh); + tsbond(newtet, checksh); + } + // Bond the neighbor faces to 'newtet'. + for (i = 0; i < 3; i++) { + fnext(newtet, newface); + if (apex(*neigh[i]) == shareoppo) { + // This side is finished. 'neigh[i]' may be a 'fake' tet. + tspivot(*neigh[i], checksh); + if (oppo(*neigh[i]) == (point) NULL) { + // Dealloc the 'fake' tet. + tetrahedrondealloc(neigh[i]->tet); + // This side (newface) is a boundary face, let 'dummytet' bond to + // it. Otherwise, 'dummytet' may point to a dead tetrahedron + // after the old cavity tets are removed. + dummytet[0] = encode(newface); + } else { + // Bond two tetrahedra, also dissolve the old bond at 'neigh[i]'. + bond(newface, *neigh[i]); + // 'neigh[i]' becomes an interior face, add it to 'flipqueue'. + if (flipqueue != (queue *) NULL) { + enqueueflipface(*neigh[i], flipqueue); + } + } + if (checksh.sh != dummysh) { + if (oppo(*neigh[i]) == (point) NULL) { + stdissolve(checksh); + } + sesymself(checksh); + tsbond(newface, checksh); + } + // Remove it from the link. + frontlink->del(neigh[i]); + } else { + // This side is unfinished. Add 'newface' into 'frontlink'. + frontlink->add(&newface); + } + // Get the face in 'newtet' corresponding to 'neigh[i]'. + enextself(newtet); + } + } // End of while loop. + + return frontlink->len() == 0; +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// reducecavity1() Reduce the cavity by forming a new tetrahedron from a // +// cavity face to a visible point. As a result, create // +// one or more new edges inside the cavity. // +// // +// We know that the cavity is not simply reducable, we have to create new // +// faces inside the cavity in order to reduce the cavity. This routine finds // +// the most suitable edge we can create in the cavity. // +// // +/////////////////////////////////////////////////////////////////////////////// + +bool tetgenmesh::reducecavity1(link* frontlink, queue* flipqueue) +{ + list *edgelist; + triface front, *neigh[3], *checkface; + triface newtet, newface; + face checksh; + point forg, fdest; + point workpt[3], *edgeends; + REAL sign; + bool isneighbor, isvalid; + bool isexist, isfind; + bool isreducable; + unsigned long count; + int loopcount; + int i, j, k; + + if (b->verbose > 2) { + printf(" Reducecavity1: %d faces.\n", (int) frontlink->len()); + } + + // Initialize 'edgelist'. Each edge has two endpoints and 1 counter. + edgelist = new list(sizeof(point) * 3, NULL); + + loopcount = 0; + while (loopcount < frontlink->len()) { + front = * (triface *) frontlink->getnitem(loopcount + 1); + // Make the front point to the inside of the cavity. + adjustedgering(front, CW); + if (b->verbose > 2) { + printf(" Get front (%d, %d, %d).\n", pointmark(org(front)), + pointmark(dest(front)), pointmark(apex(front))); + } + // Find the three neighbors of 'front' in 'frontlink'. + for (i = 0; i < 3; i++) { + forg = org(front); + fdest = dest(front); + isneighbor = false; + for (j = 0; j < frontlink->len() && !isneighbor; j++) { + if (j == loopcount) continue; + checkface = (triface *) frontlink->getnitem(j + 1); + for (k = 0; k < 3; k++) { + workpt[0] = org(*checkface); + workpt[1] = dest(*checkface); + if (workpt[0] == forg) { + if (workpt[1] == fdest) isneighbor = true; + } else if (workpt[0] == fdest) { + if (workpt[1] == forg) isneighbor = true; + } + if (isneighbor) { + neigh[i] = checkface; + break; + } + enextself(*checkface); + } + } + assert(isneighbor); + enextself(front); + } + // Check the three edges which are possibly created in cavity. + for (i = 0; i < 3; i++) { + // 'forg', 'fdest' is the edge. + forg = apex(front); + fdest = apex(*neigh[i]); + // Two face vertices. + workpt[0] = org(front); + workpt[1] = dest(front); + // Only do check if these four points form a positive volume. Allow + // the case that they are coplanar. + sign = orient3d(workpt[0], workpt[1], forg, fdest); + if (sign <= 0.0) { + // Check the face (forg, fdest, workpt[i]) is valid or not. + isvalid = true; + for (j = 0; j < 2 && isvalid; j++) { + // Skip the following tests if the face is (nearly) degenerate. + if (iscollinear(forg, fdest, workpt[j], b->epsilon)) { + isvalid = false; + } + for (k = 0; k < frontlink->len() && isvalid; k++) { + if (k == loopcount) continue; + checkface = (triface *) frontlink->getnitem(k + 1); + if (checkface == neigh[i]) continue; + isvalid = !tritritest(checkface, forg, fdest, workpt[j]); + } + } + if (isvalid) { + // This edge can be created. Check in 'edgelist', if it is not + // in there, add it, if it exists, increase its counter. + isexist = false; + for (j = 0; j < edgelist->len() && !isexist; j++) { + edgeends = (point *)(* edgelist)[j]; + if (edgeends[0] == forg) { + if (edgeends[1] == fdest) isexist = true; + } else if (edgeends[0] == fdest) { + if (edgeends[1] == forg) isexist = true; + } + } + if (!isexist) { + // Not exist, add it into 'edgelist'. + if (b->verbose > 2) { + printf(" Add edge (%d, %d).\n", pointmark(forg), + pointmark(fdest)); + } + edgeends = (point *) edgelist->append(NULL); + edgeends[0] = forg; + edgeends[1] = fdest; + edgeends[2] = (point) 1; + } else { + // Exist, only increase its counter. + if (b->verbose > 2) { + printf(" Increase edge (%d, %d)'s counter.\n", + pointmark(forg), pointmark(fdest)); + } + count = (unsigned long)(edgeends[2]); + edgeends[2] = (point) (++count); + } + } + } + enextself(front); + } + loopcount++; + } + + isreducable = edgelist->len() > 0; + + if (edgelist->len() > 0) { + // Get the edge which has the largest counter. + k = 0; + for (i = 0; i < edgelist->len(); i++) { + edgeends = (point *)(* edgelist)[i]; + count = (unsigned long)(edgeends[2]); + if (k < (int) count) { + k = (int) count; + j = i; + } + } + // Get the edge we want to create. + edgeends = (point *)(* edgelist)[j]; + if (b->verbose > 2) { + printf(" Create new edge (%d, %d).\n", pointmark(edgeends[0]), + pointmark(edgeends[1])); + } + // Find two adjacent faces in 'frontlink' conatining this edge's ends. + neigh[0] = neigh[1] = (triface *) NULL; + isfind = false; + for (i = 0; i < frontlink->len() && !isfind; i++) { + checkface = (triface *) frontlink->getnitem(i + 1); + for (j = 0; j < 3; j++) { + if (apex(*checkface) == edgeends[0]) { + neigh[0] = checkface; + break; + } + enextself(*checkface); + } + if (neigh[0] != (triface *) NULL) { + forg = org(*neigh[0]); + fdest = dest(*neigh[0]); + for (k = 0; k < frontlink->len(); k++) { + if (k == i) continue; + checkface = (triface *) frontlink->getnitem(k + 1); + isneighbor = false; + for (j = 0; j < 3; j++) { + workpt[0] = org(*checkface); + workpt[1] = dest(*checkface); + if (workpt[0] == forg) { + if (workpt[1] == fdest) isneighbor = true; + } else if (workpt[0] == fdest) { + if (workpt[1] == forg) isneighbor = true; + } + if (isneighbor) break; + enextself(*checkface); + } + if (isneighbor) { + if (apex(*checkface) == edgeends[1]) { + neigh[1] = checkface; + isfind = true; + break; + } + } + } + if (neigh[1] == (triface *) NULL) { + neigh[0] = (triface *) NULL; + } + } + } + assert(isfind); + if (b->verbose > 2) { + for (i = 0; i < 2; i++) { + printf(" Finish face (%d, %d, %d).\n", pointmark(org(*neigh[i])), + pointmark(dest(*neigh[i])), pointmark(apex(*neigh[i]))); + } + } + // Make the front point inside the cavity. + front = *neigh[0]; + adjustedgering(front, CW); + maketetrahedron(&newtet); + setorg(newtet, org(front)); + setdest(newtet, dest(front)); + setapex(newtet, apex(front)); + setoppo(newtet, edgeends[1]); + // 'front' may be a 'fake' tet. + tspivot(front, checksh); + if (oppo(front) == (point) NULL) { + // Dealloc the 'fake' tet. + tetrahedrondealloc(front.tet); + // This side (newtet) is a boundary face, let 'dummytet' bond to it. + // Otherwise, 'dummytet' may point to a dead tetrahedron after the + // old cavity tets are removed. + dummytet[0] = encode(newtet); + } else { + // Bond two tetrahedra, also dissolve the old bond at 'front'. + bond(newtet, front); + // 'front' becomes an interior face, add it to 'flipqueue'. + if (flipqueue != (queue *) NULL) { + enqueueflipface(front, flipqueue); + } + } + if (checksh.sh != dummysh) { + if (oppo(front) == (point) NULL) { + stdissolve(checksh); + } + sesymself(checksh); + tsbond(newtet, checksh); + } + fnext(newtet, newface); + // 'neigh[1]' may be a 'fake' tet. + tspivot(*neigh[1], checksh); + if (oppo(*neigh[1]) == (point) NULL) { + // Dealloc the 'fake' tet. + tetrahedrondealloc(neigh[1]->tet); + // This side (newface) is a boundary face, let 'dummytet' bond to it. + // Otherwise, 'dummytet' may point to a dead tetrahedron after the + // old cavity tets are removed. + dummytet[0] = encode(newface); + } else { + // Bond two tetrahedra, also dissolve the old bond at 'newface'. + bond(*neigh[1], newface); + // 'neigh[0]' becomes an interior face, add it to 'flipqueue'. + if (flipqueue != (queue *) NULL) { + enqueueflipface(*neigh[1], flipqueue); + } + } + if (checksh.sh != dummysh) { + if (oppo(*neigh[1]) == (point) NULL) { + stdissolve(checksh); + } + sesymself(checksh); + tsbond(newface, checksh); + } + // Remove 'neigh[0]', 'neigh[1]' from 'frontlink'. + frontlink->del(neigh[0]); + frontlink->del(neigh[1]); + // Add two new faces into 'frontlink'. + enextfnext(newtet, newface); + frontlink->add(&newface); + enext2fnext(newtet, newface); + frontlink->add(&newface); + } + + delete edgelist; + return isreducable; +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// triangulatecavity() Triangulate a cavity by filling a set of Delaunay // +// tetrahedra inside. // +// // +// The boundary of the cavity is consisted of two list of triangular faces. // +// 'floorlist' is a list of coplanar subfaces. All subfaces are oriented in // +// the same direction so that the cavity is in the above part of each face. // +// 'ceilinglist' is a list of faces of tetrahedra which are crossing the // +// cavity, they form the rest part of the boundary of the cavity. // +// // +/////////////////////////////////////////////////////////////////////////////// + +void tetgenmesh:: +triangulatecavity(list* floorlist, list* ceillist, list* floorptlist, + list* ceilptlist) +{ + link *frontlink; + link *ptlink; + queue *flipqueue; + + if (b->verbose > 1) { + printf(" Triangulate cavity %d floors, %d ceilings.\n", + floorlist->len(), ceillist->len()); + } + + // Initialize flipqueue; + flipqueue = new queue(sizeof(badface)); + // Initialize 'frontlink', 'ptlink'. + frontlink = new link(sizeof(triface), NULL, 256); + ptlink = new link(sizeof(point), NULL, 256); + + initializecavity(floorlist, ceillist, floorptlist, ceilptlist, frontlink, + ptlink); + + // Loop until 'frontlink' is empty. + while (frontlink->len() > 0) { + // Shrink the cavity by finishing easy connected fronts. + if (!reducecavity(frontlink, ptlink, flipqueue)) { + // Create new fronts inside the cavity (may insert point(s)). + if (!reducecavity1(frontlink, flipqueue)) { + // reducecavity2(frontlink, flipqueue); + assert(0); + } + } + } + // Some inner faces may need be flipped. + flip(flipqueue, NULL); + + delete frontlink; + delete ptlink; + delete flipqueue; +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// formmissingregion() Form the missing region from a given missing face. // +// // +// 'missingsh' is a missing subface. Start from it, we can find the missing // +// adjoinging subfaces. More detail, remember that all missing subfaces have // +// been infected, and missing region of a facet is bounded by facet segments.// +// All missing subfaces of the region can be found by checking the neighbors // +// of 'missingsh', and the neighbors of the neighbors, and so on. // +// // +// 'missingshlist' returns all missing subfaces of this region, furthermore, // +// the edge rings of these subfaces are oriented in the same direction. // +// 'equatptlist' returns the vertices of the missing subfaces. Both lists // +// should be empty on input. 'worklist' is used for marking vertices of the // +// missing region. // +// // +/////////////////////////////////////////////////////////////////////////////// + +void tetgenmesh:: +formmissingregion(face* missingsh, list* missingshlist, list* equatptlist, + int* worklist) +{ + face neighsh, worksh, workseg; + point workpt[3]; + int idx, i, j; + + // Add 'missingsh' into 'missingshlist'. + missingshlist->append(missingsh); + // Save and mark its three vertices. + workpt[0] = sorg(*missingsh); + workpt[1] = sdest(*missingsh); + workpt[2] = sapex(*missingsh); + for (i = 0; i < 3; i++) { + idx = pointmark(workpt[i]) - in->firstnumber; + worklist[idx] = 1; + equatptlist->append(&workpt[i]); + } + // Temporarily uninfect it (avoid to save it again). + suninfect(*missingsh); + + // Find other missing subfaces. + for (i = 0; i < missingshlist->len(); i++) { + // Get a missing subface. + worksh = * (face *)(* missingshlist)[i]; + // Check three neighbors of this face. + for (j = 0; j < 3; j++) { + sspivot(worksh, workseg); + if (workseg.sh == dummysh) { + spivot(worksh, neighsh); + if (sinfected(neighsh)) { + // Find a missing subface, adjust the edge ring. + if (sorg(neighsh) != sdest(worksh)) { + sesymself(neighsh); + } + if (b->verbose > 2) { + printf(" Add missing subface (%d, %d, %d).\n", + pointmark(sorg(neighsh)), pointmark(sdest(neighsh)), + pointmark(sapex(neighsh))); + } + missingshlist->append(&neighsh); + // Save and mark its apex. + workpt[0] = sapex(neighsh); + idx = pointmark(workpt[0]) - in->firstnumber; + worklist[idx] = 1; + equatptlist->append(&workpt[0]); + // Temporarily uninfect it (avoid to save it again). + suninfect(neighsh); + } + } + senextself(worksh); + } + } + + // The missing region has been formed. Infect missing subfaces again. + for (i = 0; i < missingshlist->len(); i++) { + worksh = * (face *)(* missingshlist)[i]; + sinfect(worksh); + } +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// scoutcrossingedge() Search an edge crossing the missing region. // +// // +// 'missingshlist' contains all subfaces of the missing region. This routine // +// first form a 'boundedgelist' consists of all boundary edges of the region,// +// which are existing in DT (because they are either edges of existing faces // +// or segments of the facet). A crossing edge is found by rotating faces of // +// DT around one of the boundary edges. It is possible that there is no edge // +// crosses the missing region (e.g. the region has a degenerate point set). // +// // +// If find a croosing edge, return TRUE, and 'crossedgelist' contains this // +// edge. Otherwise, return FALSE. Both 'boundedgelist' and 'crossedgelist' // +// should be empty on input. // +// // +/////////////////////////////////////////////////////////////////////////////// + +bool tetgenmesh:: +scoutcrossingedge(list* missingshlist, list* boundedgelist, + list* crossedgelist, int* worklist) +{ + triface starttet, spintet, worktet; + face startsh, neighsh, worksh, workseg; + point torg, tdest, tapex, workpt[3]; + enum finddirectionresult collinear; + bool crossflag, inlistflag; + int hitbdry, i, j, k; + + // Form the 'boundedgelist'. Loop through 'missingshlist', check edges + // of these subfaces. If an edge is a subsegment, or the neighbor + // subface is uninfected, add it to 'boundedgelist'. + for (i = 0; i < missingshlist->len(); i++) { + worksh = * (face *)(* missingshlist)[i]; + for (j = 0; j < 3; j++) { + sspivot(worksh, workseg); + if (workseg.sh == dummysh) { + spivot(worksh, neighsh); + if (!sinfected(neighsh)) { + boundedgelist->append(&worksh); + } + } else { + boundedgelist->append(&worksh); + } + senextself(worksh); + } + } + + crossflag = false; + // Find a crossing edge. It is possible there is no such edge. We need to + // loop through all edges of 'boundedgelist' for sure we don't miss any. + for (i = 0; i < boundedgelist->len() && !crossflag; i++) { + startsh = * (face *)(* boundedgelist)[i]; + // 'startsh' holds an existing edge of the DT, find it. + torg = sorg(startsh); + tdest = sdest(startsh); + tapex = sapex(startsh); + getsearchtet(torg, tdest, &starttet, &workpt[0]); + collinear = finddirection(&starttet, workpt[0]); + if (collinear == LEFTCOLLINEAR) { + enext2self(starttet); + esymself(starttet); + } else if (collinear == TOPCOLLINEAR) { + fnextself(starttet); + enext2self(starttet); + esymself(starttet); + } + assert(dest(starttet) == workpt[0]); + // Find the crossing edge by rotating faces around 'starttet'. + spintet = starttet; + hitbdry = 0; + do { + if (fnextself(spintet)) { + // Check if the opposite edge of 'spintet' crosses the region. + workpt[1] = apex(spintet); + workpt[2] = oppo(spintet); + j = pointmark(workpt[1]) - in->firstnumber; + k = pointmark(workpt[2]) - in->firstnumber; + if (worklist[j] == 1 || worklist[k] == 1) { + // One of the two points is a vertex of the missing region. This + // edge can not cross this region. + inlistflag = false; + } else { + // Check if the edge crosses the region by performing a triangle + // triangle intersection test. ('workpt[0]' is the dest of the + // rotating edge 'spintet'). + inlistflag = (triangle_triangle_inter(torg, tdest, tapex, workpt[0], + workpt[1], workpt[2]) == INTERSECT); + } + if (inlistflag) { + // Find an edge crossing the missing region. Save it. + worktet = spintet; + adjustedgering(worktet, CCW); + enextfnextself(worktet); + enextself(worktet); + // Add this edge (worktet) into 'crossedgelist'. + crossedgelist->append(&worktet); + break; + } + if (apex(spintet) == apex(starttet)) break; + } else { + hitbdry++; + // It is only possible to hit boundary once. + if (hitbdry < 2) { + esym(starttet, spintet); + } + } + } while (hitbdry < 2); + crossflag = (crossedgelist->len() == 1); + } + + return crossflag; +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// rearrangesubfaces() Rearrange the set of subfaces of a missing region // +// so that they conform to the faces of DT. // +// // +// The missing region formed by subfaces of 'missingshlist' contains a set // +// of degenerate vertices, hence the set of subfaces don't match the set of // +// faces in DT. Instead of forcing them to present in DT, we re-arrange the // +// connection of them so that the new subfaces conform to the faces of DT. // +// // +// 'boundedgelist' is a set of boundary edges of the region, these edges(may // +// be subsegments) must exist in DT. The process of rearrangement can be // +// described as follows: // +// - Form an inital link of boundary egdes; // +// - For each boundary edge (it must exist in DT), // +// - Remove it from the link; // +// - Look for a face in DT which contains this edge and has its apex // +// be a region vertex; Such face should exist (otherwise, an edge // +// will cross the region). // +// - Create a new subface on this face; insert it into the surface // +// mesh (the old subface connected at this edge will automatically // +// be disconnecte; // +// - Check the other two edges of this new created subface, if one // +// matches a boundary edge, remove the edge from the link (it is // +// finished) and bond them together. Otherwise, add a new boundary // +// to the link. // +// - Loop until the link of boundary edge is empty. // +// // +// On completion, we have created and inserted a set of new subfaces which // +// conform to faces of DT. The set of old subfaces in 'missingshlist' are // +// deleted. The region vertices in 'equatptlist' are unmarked. // +// // +/////////////////////////////////////////////////////////////////////////////// + +void tetgenmesh:: +rearrangesubfaces(list* missingshlist, list* boundedgelist, list* equatptlist, + int* worklist) +{ + link *boundedgelink; + triface starttet, spintet, neightet, worktet; + face shloop, newsh, neighsh, spinsh, worksh; + face workseg, casingin, casingout; + point torg, tdest, workpt; + point liftpoint; + enum finddirectionresult collinear; + REAL area, ori1, ori2; + bool matchflag, finishflag; + int shmark, idx, hitbdry; + int i, j; + + // Initialize the boundary edge link. + boundedgelink = new link(sizeof(face), NULL, 256); + + // Create an initial boundary link. + for (i = 0; i < boundedgelist->len(); i++) { + shloop = * (face *)(* boundedgelist)[i]; + if (i == 0) { + if (b->quality) { + // area will be copied to all new created subfaces. + area = areabound(shloop); + } + // 'shmark' will be set to all new created subfaces. + shmark = shellmark(shloop); + // Get the liftpoint of this facet for later checking. + liftpoint = getliftpoint(shmark); + } + sspivot(shloop, workseg); + if (workseg.sh == dummysh) { + // This edge is an interior edge. + spivot(shloop, neighsh); + boundedgelink->add(&neighsh); + } else { + // This side has a segment, the edge exists. + boundedgelink->add(&shloop); + } + } + + // Loop until the link is empty. Each boundary edge will be finished by a + // new subface. After a new subface is created, it will be inserted into + // both the surface mesh and the DT, and new boundary edge will be added + // into the link. + while (boundedgelink->len() > 0) { + // Remove the top boundary edge from the link. + shloop = * (face *) boundedgelink->del(1); + sspivot(shloop, workseg); // 'workseg' indicates it is a segment or not. + torg = sorg(shloop); + tdest = sdest(shloop); + // Find a tetrahedron containing edge (torg, tdest). + getsearchtet(torg, tdest, &starttet, &workpt); + collinear = finddirection(&starttet, workpt); + if (collinear == LEFTCOLLINEAR) { + enext2self(starttet); + esymself(starttet); + } else if (collinear == TOPCOLLINEAR) { + fnextself(starttet); + enext2self(starttet); + esymself(starttet); + } + assert(dest(starttet) == workpt); + // Spinning faces around this edge, find the one lies on the facet AND + // is not a subface yet. + matchflag = false; + spintet = starttet; + hitbdry = 0; + do { + workpt = apex(spintet); + idx = pointmark(workpt) - in->firstnumber; + if (worklist[idx] == 1) { + // This face is on the facet. + if (workseg.sh != dummysh) { + // 'shloop' is a segment. + if (workpt != sapex(shloop)) { + // Be careful that 'workpt' may not be the vertex that we're + // looking for. Because the missing region may be non-convex. + // However, the right vertex should be at the same side of + // the apex of 'shloop'. + ori1 = orient3d(torg, tdest, liftpoint, sapex(shloop)); + ori2 = orient3d(torg, tdest, liftpoint, workpt); + assert(ori1 != 0.0 && ori2 != 0.0); + if ((ori1 > 0.0 && ori2 > 0.0) || (ori1 < 0.0 && ori2 < 0.0)) { + matchflag = true; + break; + } + } else { + // This face is already exist! It is possible. Created by + // previous recovering procedures. + matchflag = true; + break; + } + } else { + // 'shloop' is not a segment. Only insert a subface when there + // does not already exist a subface. + tspivot(spintet, neighsh); + if (neighsh.sh == dummysh) { + // This face is not a subface yet. + matchflag = true; + break; + } + } + } + if (!fnextself(spintet)) { + hitbdry ++; + if (hitbdry < 2) { + esym(starttet, spintet); + if (!fnextself(spintet)) { + hitbdry ++; + } + } + } + } while (hitbdry < 2 && apex(spintet) != apex(starttet)); + assert(matchflag == true); + tspivot(spintet, neighsh); + if (neighsh.sh != dummysh) { + printf("Error: Invalid PLC.\n"); + printf(" Facet #%d and facet #%d overlap each other.\n", + shellmark(neighsh), shellmark(shloop)); + printf(" It might be caused by a facet is defined more than once.\n"); + printf(" Hint: Use -d switch to find all overlapping facets.\n"); + exit(1); + } + // The side of 'spintet' is at which a new subface will be attached. + adjustedgering(spintet, CCW); + // Create the new subface. + makeshellface(subfaces, &newsh); + setsorg(newsh, org(spintet)); + setsdest(newsh, dest(spintet)); + setsapex(newsh, apex(spintet)); + if (b->quality) { + // Copy the areabound into the new subface. + setareabound(newsh, area); + } + setshellmark(newsh, shmark); + // Insert it into the current mesh. + tsbond(spintet, newsh); + sym(spintet, neightet); + if (neightet.tet != dummytet) { + sesym(newsh, neighsh); + tsbond(neightet, neighsh); + } + // Insert it into the surface mesh. + sspivot(shloop, workseg); + if (workseg.sh == dummysh) { + sbond(shloop, newsh); + } else { + // There is a subsegment, 'shloop' is the subface which is going to + // die. Insert the 'newsh' at the place of 'shloop' into its face + // link, so as to dettach 'shloop'. The original connection is: + // -> casingin -> shloop -> casingout ->, it will be changed with: + // -> casingin -> newsh -> casingout ->. Pay attention to the + // case when this subsegment is dangling in the mesh, i.e., 'shloop' + // is bonded to itself. + spivot(shloop, casingout); + if (shloop.sh != casingout.sh) { + // 'shloop' is not bonded to itself. + spinsh = casingout; + do { + casingin = spinsh; + spivotself(spinsh); + } while (sapex(spinsh) != sapex(shloop)); + assert(casingin.sh != shloop.sh); + // Bond casingin -> newsh -> casingout. + sbond1(casingin, newsh); + sbond1(newsh, casingout); + } else { + // Bond newsh -> newsh. + sbond(newsh, newsh); + } + // Bond the segment. + ssbond(newsh, workseg); + } + // Check other two sides of this new subface. If a side is not bonded + // to any edge in the link, it will be added to the link. + for (i = 0; i < 2; i++) { + if (i == 0) { + senext(newsh, worksh); + } else { + senext2(newsh, worksh); + } + torg = sorg(worksh); + tdest = sdest(worksh); + finishflag = false; + for (j = 0; j < boundedgelink->len() && !finishflag; j++) { + neighsh = * (face *) boundedgelink->getnitem(j + 1); + if ((sorg(neighsh) == torg && sdest(neighsh) == tdest) || + (sorg(neighsh) == tdest && sdest(neighsh) == torg)) { + // Find a boundary edge. Bond them and exit the loop. + sspivot(neighsh, workseg); + if (workseg.sh == dummysh) { + sbond(neighsh, worksh); + } else { + // There is a subsegment, 'neighsh' is the subface which is + // going to die. Do the same as above for 'worksh'. + spivot(neighsh, casingout); + if (neighsh.sh != casingout.sh) { + // 'neighsh' is not bonded to itself. + spinsh = casingout; + do { + casingin = spinsh; + spivotself(spinsh); + } while (sapex(spinsh) != sapex(neighsh)); + assert(casingin.sh != neighsh.sh); + // Bond casingin -> worksh -> casingout. + sbond1(casingin, worksh); + sbond1(worksh, casingout); + } else { + // Bond worksh -> worksh. + sbond(worksh, worksh); + } + // Bond the segment. + ssbond(worksh, workseg); + } + // Remove this boundary edge from the link. + boundedgelink->del(j + 1); + finishflag = true; + } + } + if (!finishflag) { + // It's a new boundary edge, add it to link. + boundedgelink->add(&worksh); + } + } + } + + // Deallocate the set of old missing subfaces. + for (i = 0; i < missingshlist->len(); i++) { + worksh = * (face *)(* missingshlist)[i]; + shellfacedealloc(subfaces, worksh.sh); + } + // Unmark region vertices in 'worklist'. + for (i = 0; i < equatptlist->len(); i++) { + workpt = * (point *)(* equatptlist)[i]; + idx = pointmark(workpt) - in->firstnumber; + worklist[idx] = 0; + } + + delete boundedgelink; +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// recoversubfaces() Recover the set of subfaces of a missing region so // +// that they become faces of the DT. // +// // +// 'missingshlist' contains a set of missing subfaces which form the missing // +// region. A cavity retriangulation method is used to recover these subfaces // +// in the DT. To do so, first find all the tetrahedra in DT that intersect // +// the relative interior of the missing region. Then delete them from the DT,// +// this will form a cavity C inside the DT. Now we want to retriangulate the // +// C and want the missing subfaces will appear after the retriangulation. To // +// complete this, we first insert the missing subfaces into the C, so as to // +// split it into two disjointed cavity. Then retriangulate them separately. // +// (See the intoduction of the routine triangulatecavity() for the cavity // +// retriangulation method.) // +// // +// On input, 'crossedgelist' contains an edge which is crossing the missing // +// region. All tetrahedra containing this edge must cross the region. It is // +// possible there are other crossing edges as well. They can be found by // +// checking the edges of the discovered crossing tetrahedra. Through this // +// way, other crossing tetrahedra of the region can be found incrementally. // +// However, it doesn't guarantee we can get all crossing tetrahedra of this // +// region. The discovered tetrahedra are connected each other. There may // +// exist other tetrahedra which are crossing the region but disjoint with // +// the set of discovered tetrahedra. Due to this fact, we need to check the // +// missing subfaces once more. Only recover those which are crossed by the // +// set of discovered tetrahedra. The other subfaces remain missing and will // +// be recovered later. // +// // +// On completion, we have modified the DT to incorporate a set of subfaces. // +// The recovered subfaces of 'missingshlist' are uninfected. The region // +// vertices in 'equatptlist' are unmarked. // +// // +/////////////////////////////////////////////////////////////////////////////// + +void tetgenmesh:: +recoversubfaces(list* missingshlist, list* crossedgelist, list* equatptlist, + int* worklist) +{ + list *crossshlist, *crosstetlist; + list *belowfacelist, *abovefacelist; + list *belowptlist, *aboveptlist; + triface starttet, spintet, neightet, worktet; + face startsh, neighsh, worksh, workseg; + point torg, tdest, tapex, workpt[3]; + REAL checksign, orgori, destori; + bool crossflag, inlistflag; + bool belowflag, aboveflag; + int idx, share; + int i, j, k; + + // Initialize the working lists. + crossshlist = new list(sizeof(face), NULL); + crosstetlist = new list(sizeof(triface), NULL); + belowfacelist = new list(sizeof(triface), NULL); + abovefacelist = new list(sizeof(triface), NULL); + belowptlist = new list("point *"); + aboveptlist = new list("point *"); + + // Get a face as horizon. + startsh = * (face *)(* missingshlist)[0]; + torg = sorg(startsh); + tdest = sdest(startsh); + tapex = sapex(startsh); + + // Collect the set of crossing tetrahedra by rotating crossing edges. At + // the beginning, 'crossedgelist' contains one crossing edge, others + // will be discovered after newly crossing tetrahedra are found. + for (i = 0; i < crossedgelist->len(); i++) { + starttet = * (triface *)(* crossedgelist)[i]; + adjustedgering(starttet, CCW); + if (b->verbose > 2) { + printf(" Collect tets containing edge (%d, %d).\n", + pointmark(org(starttet)), pointmark(dest(starttet))); + } + orgori = orient3d(torg, tdest, tapex, org(starttet)); + destori = orient3d(torg, tdest, tapex, dest(starttet)); + assert(orgori * destori < 0.0); + spintet = starttet; + do { + // The face rotation should not meet boundary. + fnextself(spintet); + // Check the validity of the PLC. + tspivot(spintet, worksh); + if (worksh.sh != dummysh) { + printf("Error: Invalid PLC.\n"); + printf(" Two subfaces (%d, %d, %d) and (%d, %d, %d)\n", + pointmark(torg), pointmark(tdest), pointmark(tapex), + pointmark(sorg(worksh)), pointmark(sdest(worksh)), + pointmark(sapex(worksh))); + printf(" are found intersecting each other.\n"); + printf(" Hint: Use -d switch to find all intersecting facets.\n"); + exit(1); + } + if (!infected(spintet)) { + if (b->verbose > 2) { + printf(" Add crossing tet (%d, %d, %d, %d).\n", + pointmark(org(spintet)), pointmark(dest(spintet)), + pointmark(apex(spintet)), pointmark(oppo(spintet))); + } + infect(spintet); + crosstetlist->append(&spintet); + } + // Check whether other two edges of 'spintet' is a crossing edge. + // It can be quickly checked from the apex of 'spintet', if it is + // not on the facet, then there exists a crossing edge. + workpt[0] = apex(spintet); + idx = pointmark(workpt[0]) - in->firstnumber; + if (worklist[idx] != 1) { + // Either edge (dest, apex) or edge (apex, org) crosses. + checksign = orient3d(torg, tdest, tapex, workpt[0]); + assert(checksign != 0.0); + if (checksign * orgori < 0.0) { + enext2(spintet, worktet); // edge (apex, org). + workpt[1] = org(spintet); + } else { + assert(checksign * destori < 0.0); + enext(spintet, worktet); // edge (dest, apex). + workpt[1] = dest(spintet); + } + // 'worktet' represents the crossing edge. Add it into list only + // it doesn't exist in 'crossedgelist'. + inlistflag = false; + for (j = 0; j < crossedgelist->len() && !inlistflag; j++) { + neightet = * (triface *)(* crossedgelist)[j]; + if (org(neightet) == workpt[0]) { + if (dest(neightet) == workpt[1]) inlistflag = true; + } else if (org(neightet) == workpt[1]) { + if (dest(neightet) == workpt[0]) inlistflag = true; + } + } + if (!inlistflag) { + crossedgelist->append(&worktet); + } + } + } while (apex(spintet) != apex(starttet)); + } + + // Identifying the boundary faces of the cavity. + for (i = 0; i < crosstetlist->len(); i++) { + starttet = * (triface *)(* crosstetlist)[i]; + assert(infected(starttet)); + adjustedgering(starttet, CCW); + // Only need to check two sides of starttet. Current side and the side + // of fnext() are sharing the crossing edge, the two neighbors must + // be crossing tetrahedra. Hence these two sides can't be boundaries + // of the cavity. + for (j = 0; j < 2; j++) { + if (j == 0) { + enextfnext(starttet, worktet); + } else { + enext2fnext(starttet, worktet); + } + sym(worktet, neightet); + // If the neighbor doesn't exist or exists but doesn't be infected, + // it's a boundary face of the cavity, save it. + if (neightet.tet == dummytet || !infected(neightet)) { + workpt[0] = org(worktet); + workpt[1] = dest(worktet); + workpt[2] = apex(worktet); + belowflag = aboveflag = false; + share = 0; + for (k = 0; k < 3; k++) { + idx = pointmark(workpt[k]) - in->firstnumber; + if (worklist[idx] == 0) { + // It's not a vertices of facet, find which side it lies. + checksign = orient3d(torg, tdest, tapex, workpt[k]); + assert(checksign != 0.0); + if (checksign > 0.0) { + // It lies "below" the facet wrt. 'startsh'. + worklist[idx] = 2; + belowptlist->append(&workpt[k]); + } else if (checksign < 0.0) { + // It lies "above" the facet wrt. 'startsh'. + worklist[idx] = 3; + aboveptlist->append(&workpt[k]); + } + } + if (worklist[idx] == 2) { + // This face lies "below" the facet wrt. 'startsh'. + belowflag = true; + } else if (worklist[idx] == 3) { + // This face lies "above" the facet wrt. 'startsh'. + aboveflag = true; + } else { + // In degenerate case, this face may just be the equator. + assert(worklist[idx] == 1); + share++; + } + } + // The degenerate case has been ruled out. + assert(share < 3); + // Only one flag is possible for a cavity face. + assert(belowflag ^ aboveflag); + if (belowflag) { + belowfacelist->append(&worktet); + } else if (aboveflag) { + abovefacelist->append(&worktet); + } + } + } + } + + // Form the set of missing subfaces which are crossed by tetrahedra of + // 'crosstetlist'. It is a subset of 'missingshlist'. These faces + // need be recovered (using cavity filling algorithm). Other subfaces + // remain infected and will be recovered later. + for (i = 0; i < missingshlist->len(); i++) { + worksh = * (face *)(* missingshlist)[i]; + assert(sinfected(worksh)); + torg = sorg(worksh); + tdest = sdest(worksh); + tapex = sapex(worksh); + crossflag = false; + for (j = 0; j < crosstetlist->len() && !crossflag; j++) { + starttet = * (triface *)(* crosstetlist)[j]; + adjustedgering(starttet, CCW); + // Only need to check two sides of worktet. + for (k = 0; k < 2 && !crossflag; k++) { + if (k == 0) { + worktet = starttet; + } else { + fnext(starttet, worktet); + } + // torg, tdest and tapex SHOULD be non-collinear. + crossflag = tritritest(&worktet, torg, tdest, tapex); + } + } + if (crossflag) { + // 'worksh' is crossed by 'worktet', uninfect it. + suninfect(worksh); + crossshlist->append(&worksh); + } + } + + // Clear flags set in 'worklist'. + for (i = 0; i < equatptlist->len(); i++) { + workpt[0] = * (point *)(* equatptlist)[i]; + idx = pointmark(workpt[0]) - in->firstnumber; + // assert(worklist[idx] == 1); + worklist[idx] = 0; + } + for (i = 0; i < belowptlist->len(); i++) { + workpt[0] = * (point *)(* belowptlist)[i]; + idx = pointmark(workpt[0]) - in->firstnumber; + // assert(worklist[idx] == 2); + worklist[idx] = 0; + } + for (i = 0; i < aboveptlist->len(); i++) { + workpt[0] = * (point *)(* aboveptlist)[i]; + idx = pointmark(workpt[0]) - in->firstnumber; + // assert(worklist[idx] == 3); + worklist[idx] = 0; + } + + assert (aboveptlist->len() > 0); + // Retriangulate the upper part of the cavity. + triangulatecavity(crossshlist, abovefacelist, equatptlist, aboveptlist); + + // Inverse the direction of faces in 'missingshlist'. + for (i = 0; i < crossshlist->len(); i++) { + worksh = * (face *)(* crossshlist)[i]; + sesymself(worksh); + * (face *)(* crossshlist)[i] = worksh; + } + + assert(belowptlist->len() > 0); + // Retriangulate the lower part of the cavity. + triangulatecavity(crossshlist, belowfacelist, equatptlist, belowptlist); + + // Delete old tetrahedra of this cavity. + for (i = 0; i < crosstetlist->len(); i++) { + worktet = * (triface *)(* crosstetlist)[i]; + tetrahedrondealloc(worktet.tet); + } + + delete crossshlist; + delete crosstetlist; + delete belowfacelist; + delete abovefacelist; + delete belowptlist; + delete aboveptlist; +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// constrainedfacets() Insert PLC facets into the Delaunay tetrahedraliz- // +// ation of the PLC vertices. // +// // +// This is the last step of our CDT algorithm, which transforms a Delaunay // +// tetrahedralization DT into a constrained Delaunay tetrahedralization by // +// forcing all subfaces of the surface mesh F of the PLC into the DT. It is // +// important that all PLC segments have been previously recovered in DT, so // +// the existence of a CDT is guaranteed (by our CDT theorem). Hence, all // +// subfaces of F can be recovered in the DT without inserting vertices. // +// // +// The process of constrained facets can be though of "merging" the surface // +// mesh F completely into the Delaunay tetrahedralization DT. Recover the // +// subfaces in DT if they are not matching. Hence, the process is divided // +// into two steps: first insert all existing subfaces of F into DT, that is, // +// each subface already appears as a face of DT; at the same time, queue all // +// missing subfaces. Then recover missing subfaces (explained below). The // +// second step changes a DT into a CDT. // +// // +// When a subface s of a facet f is found missing in DT, most probably, some // +// other subfaces near to s and belong to f are also missing. The set of // +// adjoining missing subfaces of f forms a missing region. It is obvious to // +// see that this region is closed and is bounded by the edges of existing // +// subfaces or the segments of f. Instead of recovering missing subfaces of // +// this region one by one, they are recovered together, i.e., each time a // +// closed missing region will be recovered. // +// // +// There are two possibilities can from a mssing region R: (1) Some edges of // +// DT intersect subfaces in R; (2) No edge of DT cross R, but another set of // +// faces of DT spans R, this is because the existence of degeneracies (five // +// or more vertices of R are cospherical). If it is case (1), we modify DT // +// so that its faces spans R. A cavity retriangulation algorithm is used to // +// recover the region. If it is case (2), F is modified so that the set of // +// subfaces of F matches faces in DT. A face rearrangment algorithm is used. // +// // +/////////////////////////////////////////////////////////////////////////////// + +void tetgenmesh::constrainedfacets() +{ + queue *missingshqueue; + list *missingshlist; + list *boundedgelist; + list *crossedgelist; + list *equatptlist; + triface searchtet; + face subloop; + int *worklist; + int i; + + if (!b->quiet) { + printf("Constraining facets.\n"); + } + + // Compute a mapping from points to tetrahedra. + makepoint2tetmap(); + // Initialize the queue to store the set of missing subfaces. + missingshqueue = new queue(sizeof(face)); + // Initialize the working lists. + missingshlist = new list(sizeof(face), NULL); + boundedgelist = new list(sizeof(face), NULL); + crossedgelist = new list(sizeof(triface), NULL); + equatptlist = new list("point *"); + // Initialize the list for matching vertices. + worklist = new int[points->items]; + for (i = 0; i < points->items; i++) { + worklist[i] = 0; + } + + // Step 1, go through all subfaces, insert existing subfaces into DT. + // Missing subfaces are queued. Moreover, they are infected so that + // can be distinguished from existing ones. + searchtet.tet = (tetrahedron *) NULL; + subfaces->traversalinit(); + subloop.sh = shellfacetraverse(subfaces); + while (subloop.sh != (shellface *) NULL) { + if (!insertsubface(&subloop, &searchtet)) { + if (b->verbose > 1) { + printf(" Queuing missing subface (%d, %d, %d).\n", + pointmark(sorg(subloop)), pointmark(sdest(subloop)), + pointmark(sapex(subloop))); + } + sinfect(subloop); + missingshqueue->push(&subloop); + } + subloop.sh = shellfacetraverse(subfaces); + } + + // Step 2, recover all missing subfaces. + while (!missingshqueue->empty()) { + subloop = * (face *) missingshqueue->pop(); + if (!isdead(&subloop) && sinfected(subloop)) { + if (b->verbose > 1) { + printf(" Recovering subface (%d, %d, %d).\n", + pointmark(sorg(subloop)), pointmark(sdest(subloop)), + pointmark(sapex(subloop))); + } + // Other operation may have recovered this subface. + if (!insertsubface(&subloop, &searchtet)) { + // First form the missing region. + formmissingregion(&subloop, missingshlist, equatptlist, worklist); + // Are there crossing tetrahedra? + if (scoutcrossingedge(missingshlist, boundedgelist, crossedgelist, + worklist)) { + // There are! Recover by retriangulating cavities. + recoversubfaces(missingshlist, crossedgelist, equatptlist, worklist); + // There may remain some un-recovered subfaces. Don't ignore them. + for (i = 0; i < missingshlist->len(); i++) { + subloop = * (face *)(* missingshlist)[i]; + if (sinfected(subloop)) { + // Put it back into queue. + missingshqueue->push(&subloop); + } + } + } else { + // No crossing tetrahedra. Rearrange subfaces in surface mesh. + rearrangesubfaces(missingshlist, boundedgelist, equatptlist, + worklist); + } + // Clear all working lists. + missingshlist->clear(); + boundedgelist->clear(); + crossedgelist->clear(); + equatptlist->clear(); + } else { + // This subface has been recovered. Only uninfect it. + suninfect(subloop); + } + } + } + + delete missingshqueue; + delete missingshlist; + delete boundedgelist; + delete crossedgelist; + delete equatptlist; + delete [] worklist; +} + +// +// End of constrained Delaunay triangulation routines +// + +// +// Begin of carving out holes and concavities routines +// + +/////////////////////////////////////////////////////////////////////////////// +// // +// indenthull() Remove redundant tetrahedra on the convex hull. // +// // +// All tetrahedra on the hull which are not protected by subfaces will be // +// removed. As a result, the convex tetrahedralization becomes concave, and // +// the new hull is formed by subfaces. // +// // +/////////////////////////////////////////////////////////////////////////////// + +void tetgenmesh::indenthull() +{ + memorypool *viri; + link *hulllink; + tetrahedron **virusloop; + triface tetloop, hullface; + triface checkface, neightet; + face checksh; + point p1, p2, p3; + bool indentflag;; + int i; + + if (b->verbose) { + printf(" Indenting hulls.\n"); + } + + // Initialize a pool of viri. + viri = new memorypool(sizeof(tetrahedron *), 1024, POINTER, 0); + // Initialize the hulllink. + hulllink = new link(sizeof(triface), NULL, 1024); + + // Find out all hull faces which are not protected by subfaces. At the + // same time, infect all tetrahedra which has faces on the hull and + // are protected by subfaces. + tetrahedrons->traversalinit(); + tetloop.tet = tetrahedrontraverse(); + while (tetloop.tet != (tetrahedron *) NULL) { + indentflag = true; + for (tetloop.loc = 0; tetloop.loc < 4; tetloop.loc++) { + // Is this face on the hull? + sym(tetloop, neightet); + if (neightet.tet == dummytet) { + // Is the face protected by a subface? + tspivot(tetloop, checksh); + if (checksh.sh == dummysh) { + // Add this face into hulllink. + hulllink->add(&tetloop); + } else { + // It is protected by a subface. + indentflag = false; + } + } + } + if (!indentflag) { + // Infect it to indicate it is at interior space. + virusloop = (tetrahedron **) viri->alloc(); + *virusloop = tetloop.tet; + } + tetloop.tet = tetrahedrontraverse(); + } + + // Loop until the hulllink is empty. + while (hulllink->len() > 0) { + // Remove a hullface from the link. + hullface = * (triface *) hulllink->del(1); + // The tet may already be removed. + if (isdead(&hullface)) continue; + if (b->verbose > 1) { + printf(" Indenting face (%d, %d, %d).\n", pointmark(org(hullface)), + pointmark(dest(hullface)), pointmark(apex(hullface))); + } + // The tet may be an interior one (if it is infected). + indentflag = !infected(hullface); + // Check if hullface can be indented. + adjustedgering(hullface, CCW); + for (i = 0; i < 3 && indentflag; i++) { + fnext(hullface, checkface); + sym(checkface, neightet); + tspivot(checkface, checksh); + if (neightet.tet != dummytet) { + // The neighbor exists. + if (checksh.sh == dummysh) { + // This side is not protected by a subface. If the neighbor is + // marked as an interior tet, hullface survives. + indentflag = !infected(neightet); + } else { + // It is protected by a subface. + if (!infected(neightet)) { + // This is a new discovered interior tet. Infect it. + infect(neightet); + virusloop = (tetrahedron **) viri->alloc(); + *virusloop = neightet.tet; + } + } + } + enextself(hullface); + } + if (!indentflag) { + // hullface survives. + p1 = org(hullface); + p2 = dest(hullface); + p3 = apex(hullface); + printf("Warning: Face (%d, %d, %d) is open.\n", pointmark(p1), + pointmark(p2), pointmark(p3)); + if (!infected(hullface)) { + // Infect it and add it into viris. + infect(hullface); + virusloop = (tetrahedron **) viri->alloc(); + *virusloop = hullface.tet; + } + continue; + } + // Indent hullface. That is, remove it from the hull. The hullsize is + // changed, new discoved open hullfaces will be added to hulllink. + for (i = 0; i < 3; i++) { + fnext(hullface, checkface); + sym(checkface, neightet); + tspivot(checkface, checksh); + if (neightet.tet != dummytet) { + // The neighbor exists. + if (checksh.sh == dummysh) { + // This side is not protected. + assert(!infected(neightet)); + hulllink->add(&neightet); + } else { + // It is protected. + assert(infected(neightet)); + stdissolve(checksh); + } + // It becomes a new hull face. + dissolve(neightet); + hullsize++; + } else { + // This side is hull face also. + if (checksh.sh != dummysh) { + // A dangling subface. It will be isolated. + stdissolve(checksh); + } + // Decrease the hullsize. + hullsize--; + } + enextself(hullface); + } + // Delete the tetrahedron. + tetrahedrondealloc(hullface.tet); + // Decrease the hullsize. + hullsize--; + } + + // Uninfect infected tetrahedra. + viri->traversalinit(); + virusloop = (tetrahedron **) viri->traverse(); + while (virusloop != (tetrahedron **) NULL) { + neightet.tet = *virusloop; + uninfect(neightet); + virusloop = (tetrahedron **) viri->traverse(); + } + + delete viri; + delete hulllink; +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// infecthull() Virally infect all of the tetrahedra of the convex hull // +// that are not protected by subfaces. Where there are // +// subfaces, set boundary markers as appropriate. // +// // +// Memorypool 'viri' is used to return all the infected tetrahedra. // +// // +/////////////////////////////////////////////////////////////////////////////// + +void tetgenmesh::infecthull(memorypool *viri) +{ + triface tetloop, tsymtet; + tetrahedron **deadtet; + face hullface; + // point horg, hdest, hapex; + + if (b->verbose) { + printf(" Marking concavities for elimination.\n"); + } + tetrahedrons->traversalinit(); + tetloop.tet = tetrahedrontraverse(); + while (tetloop.tet != (tetrahedron *) NULL) { + // Is this tetrahedron on the hull? + for (tetloop.loc = 0; tetloop.loc < 4; tetloop.loc++) { + sym(tetloop, tsymtet); + if (tsymtet.tet == dummytet) { + // Is the tetrahedron protected by a subface? + tspivot(tetloop, hullface); + if (hullface.sh == dummysh) { + // The tetrahedron is not protected; infect it. + if (!infected(tetloop)) { + infect(tetloop); + deadtet = (tetrahedron **) viri->alloc(); + *deadtet = tetloop.tet; + break; // Go and get next tet. + } + } else { + // The tetrahedron is protected; set boundary markers if appropriate. + if (shellmark(hullface) == 0) { + setshellmark(hullface, 1); + /* + horg = sorg(hullface); + hdest = sdest(hullface); + hapex = sapex(hullface); + if (pointmark(horg) == 0) { + setpointmark(horg, 1); + } + if (pointmark(hdest) == 0) { + setpointmark(hdest, 1); + } + if (pointmark(hapex) == 0) { + setpointmark(hapex, 1); + } + */ + } + } + } + } + tetloop.tet = tetrahedrontraverse(); + } +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// plague() Spread the virus from all infected tetrahedra to any // +// neighbors not protected by subfaces. Delete all infected // +// tetrahedra. // +// // +// This is the procedure that actually creates holes and concavities. // +// // +// This procedure operates in two phases. The first phase identifies all // +// the tetrahedra that will die, and marks them as infected. They are // +// marked to ensure that each tetrahedron is added to the virus pool only // +// once, so the procedure will terminate. // +// // +// The second phase actually eliminates the infected tetrahedra. It also // +// eliminates orphaned segments and points(not done now). // +// // +/////////////////////////////////////////////////////////////////////////////// + +void tetgenmesh::plague(memorypool *viri) +{ + tetrahedron **virusloop; + tetrahedron **deadtet; + triface testtet, neighbor; + face neighsh, testseg; + face spinsh, casingin, casingout; + point checkpt; + int *tetspernodelist; + int i, j; + + if (b->verbose) { + printf(" Marking neighbors of marked tetrahedra.\n"); + } + // Loop through all the infected tetrahedra, spreading the virus to + // their neighbors, then to their neighbors' neighbors. + viri->traversalinit(); + virusloop = (tetrahedron **) viri->traverse(); + while (virusloop != (tetrahedron **) NULL) { + testtet.tet = *virusloop; + // Temporarily uninfect this tetrahedron, not necessary. + uninfect(testtet); + // Check each of the tetrahedron's four neighbors. + for (testtet.loc = 0; testtet.loc < 4; testtet.loc++) { + // Find the neighbor. + sym(testtet, neighbor); + // Check for a shell between the tetrahedron and its neighbor. + tspivot(testtet, neighsh); + // Check if the neighbor is nonexistent or already infected. + if ((neighbor.tet == dummytet) || infected(neighbor)) { + if (neighsh.sh != dummysh) { + // There is a subface separating the tetrahedron from its neighbor, + // but both tetrahedra are dying, so the subface dies too. + // Before deallocte this subface, dissolve the connections between + // other subfaces, subsegments and tetrahedra. + neighsh.shver = 0; + // For keep the same enext() direction. + findedge(&testtet, sorg(neighsh), sdest(neighsh)); + for (i = 0; i < 3; i++) { + sspivot(neighsh, testseg); + if (testseg.sh != dummysh) { + // A subsegment is found at this side, dissolve this subface + // from the face link of this subsegment. + testseg.shver = 0; + spinsh = neighsh; + if (sorg(spinsh) != sorg(testseg)) { + sesymself(spinsh); + } + spivot(spinsh, casingout); + if (casingout.sh == spinsh.sh) { + // This is a trivial face link, only 'neighsh' itself, + // the subsegment at this side is also died. + shellfacedealloc(subsegs, testseg.sh); + } else { + spinsh = casingout; + do { + casingin = spinsh; + spivotself(spinsh); + } while (spinsh.sh != neighsh.sh); + // Set the link casingin->casingout. + sbond1(casingin, casingout); + // Bond the subsegment anyway. + ssbond(casingin, testseg); + } + } + senextself(neighsh); + enextself(testtet); + } + shellfacedealloc(subfaces, neighsh.sh); + if (neighbor.tet != dummytet) { + // Make sure the subface doesn't get deallocated again later + // when the infected neighbor is visited. + tsdissolve(neighbor); + } + } + } else { // The neighbor exists and is not infected. + if (neighsh.sh == dummysh) { + // There is no subface protecting the neighbor, infect it. + infect(neighbor); + // Ensure that the neighbor's neighbors will be infected. + deadtet = (tetrahedron **) viri->alloc(); + *deadtet = neighbor.tet; + } else { // The neighbor is protected by a subface. + // Remove this tetrahedron from the subface. + stdissolve(neighsh); + // The subface becomes a boundary. Set markers accordingly. + if (shellmark(neighsh) == 0) { + setshellmark(neighsh, 1); + } + } + } + } + // Remark the tetrahedron as infected, so it doesn't get added to the + // virus pool again. + infect(testtet); + virusloop = (tetrahedron **) viri->traverse(); + } + + if (b->verbose) { + printf(" Deleting marked tetrahedra.\n"); + } + + // Create and initialize 'segspernodelist'. + tetspernodelist = new int[points->items + 1]; + for (i = 0; i < points->items + 1; i++) tetspernodelist[i] = 0; + + // Loop the tetrahedra list, counter the number of tets sharing each node. + tetrahedrons->traversalinit(); + testtet.tet = tetrahedrontraverse(); + while (testtet.tet != (tetrahedron *) NULL) { + // Increment the number of sharing tets for each endpoint. + for (i = 0; i < 4; i++) { + j = pointmark((point) testtet.tet[4 + i]); + tetspernodelist[j]++; + } + testtet.tet = tetrahedrontraverse(); + } + + viri->traversalinit(); + virusloop = (tetrahedron **) viri->traverse(); + while (virusloop != (tetrahedron **) NULL) { + testtet.tet = *virusloop; + // Record changes in the number of boundary faces, and disconnect + // dead tetrahedra from their neighbors. + for (testtet.loc = 0; testtet.loc < 4; testtet.loc++) { + sym(testtet, neighbor); + if (neighbor.tet == dummytet) { + // There is no neighboring tetrahedron on this face, so this face + // is a boundary face. This tetrahedron is being deleted, so this + // boundary face is deleted. + hullsize--; + } else { + // Disconnect the tetrahedron from its neighbor. + dissolve(neighbor); + // There is a neighboring tetrahedron on this face, so this face + // becomes a boundary face when this tetrahedron is deleted. + hullsize++; + } + } + // Check the four corners of this tet if they're isolated. + for (i = 0; i < 4; i++) { + checkpt = (point) testtet.tet[4 + i]; + j = pointmark(checkpt); + tetspernodelist[j]--; + if (tetspernodelist[j] == 0) { + setpointtype(checkpt, UNUSEDVERTEX); + } + } + // Return the dead tetrahedron to the pool of tetrahedra. + tetrahedrondealloc(testtet.tet); + virusloop = (tetrahedron **) viri->traverse(); + } + + delete [] tetspernodelist; + // Empty the virus pool. + viri->restart(); +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// regionplague() Spread regional attributes and/or volume constraints // +// (from a .poly file) throughout the mesh. // +// // +// This procedure operates in two phases. The first phase spreads an // +// attribute and/or an volume constraint through a (segment-bounded) region. // +// The tetrahedra are marked to ensure that each tetrahedra is added to the // +// virus pool only once, so the procedure will terminate. // +// // +// The second phase uninfects all infected tetrahedra, returning them to // +// normal. // +// // +/////////////////////////////////////////////////////////////////////////////// + +void tetgenmesh:: +regionplague(memorypool *viri, REAL attribute, REAL volume) +{ + tetrahedron **virusloop; + tetrahedron **regiontet; + triface testtet, neighbor; + face neighsh; + + if (b->verbose > 1) { + printf(" Marking neighbors of marked tetrahedra.\n"); + } + // Loop through all the infected tetrahedra, spreading the attribute + // and/or volume constraint to their neighbors, then to their neighbors' + // neighbors. + viri->traversalinit(); + virusloop = (tetrahedron **) viri->traverse(); + while (virusloop != (tetrahedron **) NULL) { + testtet.tet = *virusloop; + // Temporarily uninfect this tetrahedron, not necessary. + uninfect(testtet); + if (b->regionattrib) { + // Set an attribute. + setelemattribute(testtet.tet, in->numberoftetrahedronattributes, + attribute); + } + if (b->varvolume) { + // Set an volume constraint. + setvolumebound(testtet.tet, volume); + } + // Check each of the tetrahedron's four neighbors. + for (testtet.loc = 0; testtet.loc < 4; testtet.loc++) { + // Find the neighbor. + sym(testtet, neighbor); + // Check for a subface between the tetrahedron and its neighbor. + tspivot(testtet, neighsh); + // Make sure the neighbor exists, is not already infected, and + // isn't protected by a subface, or is protected by a nonsolid + // subface. + if ((neighbor.tet != dummytet) && !infected(neighbor) + && (neighsh.sh == dummysh)) { + // Infect the neighbor. + infect(neighbor); + // Ensure that the neighbor's neighbors will be infected. + regiontet = (tetrahedron **) viri->alloc(); + *regiontet = neighbor.tet; + } + } + // Remark the tetrahedron as infected, so it doesn't get added to the + // virus pool again. + infect(testtet); + virusloop = (tetrahedron **) viri->traverse(); + } + + // Uninfect all tetrahedra. + if (b->verbose > 1) { + printf(" Unmarking marked tetrahedra.\n"); + } + viri->traversalinit(); + virusloop = (tetrahedron **) viri->traverse(); + while (virusloop != (tetrahedron **) NULL) { + testtet.tet = *virusloop; + uninfect(testtet); + virusloop = (tetrahedron **) viri->traverse(); + } + // Empty the virus pool. + viri->restart(); +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// carveholes() Find the holes and infect them. Find the volume // +// constraints and infect them. Infect the convex hull. // +// Spread the infection and kill tetrahedra. Spread the // +// volume constraints. // +// // +// This routine mainly calls other routines to carry out all these functions.// +// // +/////////////////////////////////////////////////////////////////////////////// + +void tetgenmesh::carveholes() +{ + memorypool *viri; + triface searchtet; + triface *holetets; + triface *regiontets; + tetrahedron *tptr; + tetrahedron **holetet; + tetrahedron **regiontet; + enum locateresult intersect; + int i; + + if (!b->quiet) { + printf("Removing unwanted tetrahedra.\n"); + if (b->verbose && (in->numberofholes > 0)) { + printf(" Marking holes for elimination.\n"); + } + } + + if (in->numberofholes > 0) { + // Allocate storage for the tetrahedra in which hole points fall. + holetets = (triface *) new triface[in->numberofholes]; + } + if (in->numberofregions > 0) { + // Allocate storage for the tetrahedra in which region points fall. + regiontets = (triface *) new triface[in->numberofregions]; + } + + // Now, we have to find all the holes and regions BEFORE we infect hull + // and carve the holes, because locate() won't work when there exist + // infect tetrahedra and the tetrahedronlization is no longer convex. + + if (in->numberofholes > 0) { + // Infect each tetrahedron in which a hole lies. + for (i = 0; i < 3 * in->numberofholes; i += 3) { + // Ignore holes that aren't within the bounds of the mesh. + if ((in->holelist[i] >= xmin) && (in->holelist[i] <= xmax) + && (in->holelist[i + 1] >= ymin) + && (in->holelist[i + 1] <= ymax) + && (in->holelist[i + 2] >= zmin) + && (in->holelist[i + 2] <= zmax)) { + searchtet.tet = dummytet; + // Find a tetrahedron that contains the hole. + intersect = locate(&in->holelist[i], &searchtet); + if ((intersect != OUTSIDE) && (!infected(searchtet))) { + // Record the tetrahedron for processing carve hole. + holetets[i / 3] = searchtet; + } + } + } + } + + if (in->numberofregions > 0) { + // Find the starting tetrahedron for each region. + for (i = 0; i < in->numberofregions; i++) { + regiontets[i].tet = dummytet; + // Ignore region points that aren't within the bounds of the mesh. + if ((in->regionlist[5 * i] >= xmin) + && (in->regionlist[5 * i] <= xmax) + && (in->regionlist[5 * i + 1] >= ymin) + && (in->regionlist[5 * i + 1] <= ymax) + && (in->regionlist[5 * i + 2] >= zmin) + && (in->regionlist[5 * i + 2] <= zmax)) { + searchtet.tet = dummytet; + // Find a tetrahedron that contains the region point. + intersect = locate(&in->regionlist[5 * i], &searchtet); + if ((intersect != OUTSIDE) && (!infected(searchtet))) { + // Record the tetrahedron for processing after the + // holes have been carved. + regiontets[i] = searchtet; + } + } + } + } + + // Initialize a pool of viri to be used for holes, concavities, + // regional attributes, and/or regional volume constraints. + viri = new memorypool(sizeof(tetrahedron *), 1024, POINTER, 0); + // Mark as infected any unprotected tetrahedra on the boundary. + // This is one way by which concavities are created. + infecthull(viri); + + if (in->numberofholes > 0) { + // Infect the hole tetrahedron. This is done by marking the + // tetrahedron as infect and including the tetrahedron in + // the virus pool. + for (i = 0; i < in->numberofholes; i++) { + infect(holetets[i]); + holetet = (tetrahedron **) viri->alloc(); + *holetet = holetets[i].tet; + } + } + + if (viri->items > 0) { + // Carve the holes and concavities. + plague(viri); + } + // The virus pool should be empty now. + + if (in->numberofregions > 0) { + if (!b->quiet) { + if (b->regionattrib) { + if (b->varvolume) { + printf("Spreading regional attributes and volume constraints.\n"); + } else { + printf("Spreading regional attributes.\n"); + } + } else { + printf("Spreading regional volume constraints.\n"); + } + } + if (b->regionattrib && !b->refine) { + // Assign every tetrahedron a regional attribute of zero. + tetrahedrons->traversalinit(); + tptr = tetrahedrontraverse(); + while (tptr != (tetrahedron *) NULL) { + setelemattribute(tptr, in->numberoftetrahedronattributes, 0.0); + tptr = tetrahedrontraverse(); + } + } + for (i = 0; i < in->numberofregions; i++) { + if (regiontets[i].tet != dummytet) { + // Make sure the tetrahedron under consideration still exists. + // It may have been eaten by the virus. + if (!isdead(&(regiontets[i]))) { + // Put one tetrahedron in the virus pool. + infect(regiontets[i]); + regiontet = (tetrahedron **) viri->alloc(); + *regiontet = regiontets[i].tet; + // Apply one region's attribute and/or volume constraint. + regionplague(viri, in->regionlist[5 * i + 3], + in->regionlist[5 * i + 4]); + // The virus pool should be empty now. + } + } + } + if (b->regionattrib && !b->refine) { + // Note the fact that each tetrahedron has an additional attribute. + in->numberoftetrahedronattributes++; + } + } + + // Free up memory. + delete viri; + if (in->numberofholes > 0) { + delete [] holetets; + } + if (in->numberofregions > 0) { + delete [] regiontets; + } +} + +// +// End of carving out holes and concavities routines +// + +// +// Begin of mesh update routines +// + +/////////////////////////////////////////////////////////////////////////////// +// // +// reconstructmesh() Reconstruct a tetrahedral mesh from a list of // +// tetrahedra and possibly a list of boundary faces. // +// // +// The list of tetrahedra is stored in 'in->tetrahedronlist', the list of // +// boundary faces is stored in 'in->trifacelist'. The tetrahedral mesh is // +// reconstructed in memorypool 'tetrahedrons', its boundary faces (subfaces) // +// are reconstructed in 'subfaces', its boundary edges (subsegments) are // +// reconstructed in 'subsegs'. If the -a switch is used, this procedure will // +// also read a list of REALs from 'in->tetrahedronvolumelist' and set a // +// maximum volume constraint on each tetrahedron. // +// // +// If the user has provided the boundary faces in 'in->trifacelist', they // +// will be inserted the mesh. Otherwise subfaces will be identified from the // +// mesh. All hull faces (including faces of the internal holes) will be // +// recognized as subfaces, internal faces between two tetrahedra which have // +// different attributes will also be recognized as subfaces. // +// // +// Subsegments will be identified after subfaces are reconstructed. Edges at // +// the intersections of non-coplanar subfaces are recognized as subsegments. // +// Edges between two coplanar subfaces with different boundary markers are // +// also recognized as subsegments. // +// // +// The facet index of each subface will be set automatically after we have // +// recovered subfaces and subsegments. That is, the set of subfaces, which // +// are coplanar and have the same boundary marker will be recognized as a // +// facet and has a unique index, stored as the facet marker in each subface // +// of the set, the real boundary marker of each subface will be found in // +// 'in->facetmarkerlist' by the index. Facet index will be used in Delaunay // +// refinement for detecting two incident facets. // +// // +// Points which are not corners of tetrahedra will be inserted into the mesh.// +// Return the number of faces on the hull after the reconstruction. // +// // +/////////////////////////////////////////////////////////////////////////////// + +long tetgenmesh::reconstructmesh() +{ + tetrahedron **tetsperverlist; + shellface **facesperverlist; + triface tetloop, neightet, neineightet, spintet; + face subloop, neighsh, neineighsh, subseg; + face sface1, sface2; + point *idx2verlist; + point torg, tdest, tapex, toppo; + point norg, ndest, napex; + list *neighshlist, *markerlist; + REAL sign, attrib, volume; + REAL da1, da2; + bool bondflag, insertsegflag; + int *idx2tetlist; + int *idx2facelist; + int *worklist; + int facetidx, marker; + int iorg, idest, iapex, ioppo; + int inorg, indest, inapex; + int index, i, j; + + if (!b->quiet) { + printf("Reconstructing mesh.\n"); + } + + // Create a map from index to points. + makeindex2pointmap(idx2verlist); + + // Create the tetrahedra. + for (i = 0; i < in->numberoftetrahedra; i++) { + // Create a new tetrahedron and set its four corners, make sure that + // four corners form a positive orientation. + maketetrahedron(&tetloop); + index = i * in->numberofcorners; + // Although there may be 10 nodes, we only read the first 4. + iorg = in->tetrahedronlist[index] - in->firstnumber; + idest = in->tetrahedronlist[index + 1] - in->firstnumber; + iapex = in->tetrahedronlist[index + 2] - in->firstnumber; + ioppo = in->tetrahedronlist[index + 3] - in->firstnumber; + torg = idx2verlist[iorg]; + tdest = idx2verlist[idest]; + tapex = idx2verlist[iapex]; + toppo = idx2verlist[ioppo]; + sign = orient3d(torg, tdest, tapex, toppo); + if (sign > 0.0) { + norg = torg; torg = tdest; tdest = norg; + } else if (sign == 0.0) { + printf("Warning: Tetrahedron %d is degenerate.\n", i + in->firstnumber); + } + setorg(tetloop, torg); + setdest(tetloop, tdest); + setapex(tetloop, tapex); + setoppo(tetloop, toppo); + // Temporarily set the vertices be type FREEVOLVERTEX, to indicate that + // they belong to the mesh. These types may be changed later. + setpointtype(torg, FREEVOLVERTEX); + setpointtype(tdest, FREEVOLVERTEX); + setpointtype(tapex, FREEVOLVERTEX); + setpointtype(toppo, FREEVOLVERTEX); + // Set element attributes if they exist. + for (j = 0; j < in->numberoftetrahedronattributes; j++) { + index = i * in->numberoftetrahedronattributes; + attrib = in->tetrahedronattributelist[index + j]; + setelemattribute(tetloop.tet, j, attrib); + } + // If -a switch is used (with no number follows) Set a volume + // constraint if it exists. + if (b->varvolume) { + if (in->tetrahedronvolumelist != (REAL *) NULL) { + volume = in->tetrahedronvolumelist[i]; + } else { + volume = -1.0; + } + setvolumebound(tetloop.tet, volume); + } + } + + // Set the connection between tetrahedra. + hullsize = 0l; + // Create a map from nodes to tetrahedra. + maketetrahedronmap(idx2tetlist, tetsperverlist); + // Initialize the worklist. + worklist = new int[points->items]; + for (i = 0; i < points->items; i++) { + worklist[i] = 0; + } + + // Loop all tetrahedra, bond two tetrahedra if they share a common face. + tetrahedrons->traversalinit(); + tetloop.tet = tetrahedrontraverse(); + while (tetloop.tet != (tetrahedron *) NULL) { + // Loop the four sides of the tetrahedron. + for (tetloop.loc = 0; tetloop.loc < 4; tetloop.loc++) { + sym(tetloop, neightet); + if (neightet.tet != dummytet) continue; // This side has finished. + torg = org(tetloop); + tdest = dest(tetloop); + tapex = apex(tetloop); + iorg = pointmark(torg) - in->firstnumber; + idest = pointmark(tdest) - in->firstnumber; + iapex = pointmark(tapex) - in->firstnumber; + worklist[iorg] = 1; + worklist[idest] = 1; + worklist[iapex] = 1; + bondflag = false; + // Search its neighbor in the adjacent tets of torg. + for (j = idx2tetlist[iorg]; j < idx2tetlist[iorg + 1] && !bondflag; + j++) { + if (tetsperverlist[j] == tetloop.tet) continue; // Skip myself. + neightet.tet = tetsperverlist[j]; + for (neightet.loc = 0; neightet.loc < 4; neightet.loc++) { + sym(neightet, neineightet); + if (neineightet.tet == dummytet) { + norg = org(neightet); + ndest = dest(neightet); + napex = apex(neightet); + inorg = pointmark(norg) - in->firstnumber; + indest = pointmark(ndest) - in->firstnumber; + inapex = pointmark(napex) - in->firstnumber; + if ((worklist[inorg] + worklist[indest] + worklist[inapex]) == 3) { + // Find! Bond them together and break the loop. + bond(tetloop, neightet); + bondflag = true; + break; + } + } + } + } + if (!bondflag) { + hullsize++; // It's a hull face. + // Bond this side to outer space. + dummytet[0] = encode(tetloop); + if (in->pointmarkerlist != (int *) NULL) { + // Set its three corners's markers be boundary (hull) vertices. + if (in->pointmarkerlist[iorg] == 0) { + in->pointmarkerlist[iorg] = 1; + } + if (in->pointmarkerlist[idest] == 0) { + in->pointmarkerlist[idest] = 1; + } + if (in->pointmarkerlist[iapex] == 0) { + in->pointmarkerlist[iapex] = 1; + } + } + } + worklist[iorg] = 0; + worklist[idest] = 0; + worklist[iapex] = 0; + } + tetloop.tet = tetrahedrontraverse(); + } + + // Subfaces will be inserted into the mesh. + if (in->trifacelist != (int *) NULL) { + // Recover subfaces from 'in->trifacelist'. + for (i = 0; i < in->numberoftrifaces; i++) { + index = i * 3; + iorg = in->trifacelist[index] - in->firstnumber; + idest = in->trifacelist[index + 1] - in->firstnumber; + iapex = in->trifacelist[index + 2] - in->firstnumber; + // Look for the location of this subface. + worklist[iorg] = 1; + worklist[idest] = 1; + worklist[iapex] = 1; + bondflag = false; + // Search its neighbor in the adjacent tets of torg. + for (j = idx2tetlist[iorg]; j < idx2tetlist[iorg + 1] && !bondflag; + j++) { + neightet.tet = tetsperverlist[j]; + for (neightet.loc = 0; neightet.loc < 4; neightet.loc++) { + norg = org(neightet); + ndest = dest(neightet); + napex = apex(neightet); + inorg = pointmark(norg) - in->firstnumber; + indest = pointmark(ndest) - in->firstnumber; + inapex = pointmark(napex) - in->firstnumber; + if ((worklist[inorg] + worklist[indest] + worklist[inapex]) == 3) { + bondflag = true; // Find! + break; + } + } + } + if (bondflag) { + // Create a new subface and insert it into the mesh. + makeshellface(subfaces, &subloop); + torg = idx2verlist[iorg]; + tdest = idx2verlist[idest]; + tapex = idx2verlist[iapex]; + setsorg(subloop, torg); + setsdest(subloop, tdest); + setsapex(subloop, tapex); + // Set the vertices be FREESUBVERTEX to indicate they belong to a + // facet of the domain. They may be changed later. + setpointtype(torg, FREESUBVERTEX); + setpointtype(tdest, FREESUBVERTEX); + setpointtype(tapex, FREESUBVERTEX); + if (in->trifacemarkerlist != (int *) NULL) { + setshellmark(subloop, in->trifacemarkerlist[i]); + } + adjustedgering(neightet, CCW); + findedge(&subloop, org(neightet), dest(neightet)); + tsbond(neightet, subloop); + sym(neightet, neineightet); + if (neineightet.tet != dummytet) { + sesymself(subloop); + tsbond(neineightet, subloop); + } + } else { + printf("Warning: Subface %d is discarded.\n", i + in->firstnumber); + } + worklist[iorg] = 0; + worklist[idest] = 0; + worklist[iapex] = 0; + } + } else { + // Indentify subfaces from the mesh. + tetrahedrons->traversalinit(); + tetloop.tet = tetrahedrontraverse(); + while (tetloop.tet != (tetrahedron *) NULL) { + // Loop the four sides of the tetrahedron. + for (tetloop.loc = 0; tetloop.loc < 4; tetloop.loc++) { + tspivot(tetloop, subloop); + if (subloop.sh != dummysh) continue; + bondflag = false; + sym(tetloop, neightet); + if (neightet.tet == dummytet) { + // It's a hull face. Insert a subface at here. + bondflag = true; + } else { + // It's an interior face. Insert a subface if two tetrahedra have + // different attributes (i.e., they belong to two regions). + if (in->numberoftetrahedronattributes > 0) { + if (elemattribute(neightet.tet, + in->numberoftetrahedronattributes - 1) != + elemattribute(tetloop.tet, + in->numberoftetrahedronattributes - 1)) { + bondflag = true; + } + } + } + if (bondflag) { + adjustedgering(tetloop, CCW); + makeshellface(subfaces, &subloop); + torg = org(tetloop); + tdest = dest(tetloop); + tapex = apex(tetloop); + setsorg(subloop, torg); + setsdest(subloop, tdest); + setsapex(subloop, tapex); + // Set the vertices be FACETVERTEX to indicate they belong to a + // facet of the domain. They may be changed later. + setpointtype(torg, FACETVERTEX); + setpointtype(tdest, FACETVERTEX); + setpointtype(tapex, FACETVERTEX); + tsbond(tetloop, subloop); + if (neightet.tet != dummytet) { + sesymself(subloop); + tsbond(neightet, subloop); + } + } + } + tetloop.tet = tetrahedrontraverse(); + } + } + + // Set the connection between subfaces. An subsegment may have more than + // two subfaces sharing it, 'neighshlist' stores all subfaces sharing + // one edge. + neighshlist = new list(sizeof(face), NULL); + // Create a map from nodes to subfaces. + makesubfacemap(idx2facelist, facesperverlist); + + // Loop over the set of subfaces, setup the connection between subfaces. + subfaces->traversalinit(); + subloop.sh = shellfacetraverse(subfaces); + while (subloop.sh != (shellface *) NULL) { + for (i = 0; i < 3; i++) { + spivot(subloop, neighsh); + if (neighsh.sh == dummysh) { + // This side is 'empty', operate on it. + torg = sorg(subloop); + tdest = sdest(subloop); + tapex = sapex(subloop); + neighshlist->append(&subloop); + iorg = pointmark(torg) - in->firstnumber; + // Search its neighbor in the adjacent list of torg. + for (j = idx2facelist[iorg]; j < idx2facelist[iorg + 1]; j++) { + neighsh.sh = facesperverlist[j]; + if (neighsh.sh == subloop.sh) continue; + neighsh.shver = 0; + if (isfacehasedge(&neighsh, torg, tdest)) { + findedge(&neighsh, torg, tdest); + // Insert 'neighsh' into 'neighshlist'. + if (neighshlist->len() < 2) { + neighshlist->append(&neighsh); + } else { + for (index = 0; index < neighshlist->len() - 1; index++) { + sface1 = * (face *)(* neighshlist)[index]; + sface2 = * (face *)(* neighshlist)[index + 1]; + da1 = facedihedral(torg, tdest, sapex(sface1), sapex(neighsh)); + da2 = facedihedral(torg, tdest, sapex(sface1), sapex(sface2)); + if (da1 < da2) { + break; // Insert it after index. + } + } + neighshlist->insert(index + 1, &neighsh); + } + } + } + // Bond the subfaces in 'neighshlist'. + if (neighshlist->len() > 1) { + neighsh = * (face *)(* neighshlist)[0]; + for (j = 1; j <= neighshlist->len(); j++) { + if (j < neighshlist->len()) { + neineighsh = * (face *)(* neighshlist)[j]; + } else { + neineighsh = * (face *)(* neighshlist)[0]; + } + sbond1(neighsh, neineighsh); + neighsh = neineighsh; + } + } else { + // No neighbor subface be found, bond 'subloop' to itself. + sbond(subloop, subloop); + } + neighshlist->clear(); + } + senextself(subloop); + } + subloop.sh = shellfacetraverse(subfaces); + } + + // Subsegments will be introudced. + subfaces->traversalinit(); + subloop.sh = shellfacetraverse(subfaces); + while (subloop.sh != (shellface *) NULL) { + for (i = 0; i < 3; i++) { + sspivot(subloop, subseg); + if (subseg.sh == dummysh) { + // This side has no subsegment bonded, check it. + torg = sorg(subloop); + tdest = sdest(subloop); + tapex = sapex(subloop); + spivot(subloop, neighsh); + spivot(neighsh, neineighsh); + insertsegflag = false; + if (subloop.sh == neighsh.sh || subloop.sh != neineighsh.sh) { + // This side is either self-bonded or more than two subfaces, + // insert a subsegment at this side. + insertsegflag = true; + } else { + // Only two subfaces case. + assert(subloop.sh != neighsh.sh); + napex = sapex(neighsh); + sign = orient3d(torg, tdest, tapex, napex); + if (iscoplanar(torg, tdest, tapex, napex, sign, b->epsilon)) { + // Although they are coplanar, we still need to check if they + // have the same boundary marker. + insertsegflag = (shellmark(subloop) != shellmark(neighsh)); + } else { + // Non-coplanar. + insertsegflag = true; + } + } + if (insertsegflag) { + // Create a subsegment at this side. + makeshellface(subsegs, &subseg); + setsorg(subseg, torg); + setsdest(subseg, tdest); + // At the moment, all segment vertices have type FACETVERTEX. + // They will be set to type ACUTEVERTEX or NONACUTEVERTEX by + // routine markacutevertices() later. + // setpointtype(torg, SEGMENTVERTEX); + // setpointtype(tdest, SEGMENTVERTEX); + // Bond all subfaces to this subsegment. + neighsh = subloop; + do { + ssbond(neighsh, subseg); + spivotself(neighsh); + } while (neighsh.sh != subloop.sh); + } + } + senextself(subloop); + } + subloop.sh = shellfacetraverse(subfaces); + } + // Remember the number of input segments. + insegment = subsegs->items; + // Find the acute vertices and set them be type ACUTEVERTEX. + + // Indentify the facet and set facet index for each subface. + markerlist = new list("int"); + + subfaces->traversalinit(); + subloop.sh = shellfacetraverse(subfaces); + while (subloop.sh != (shellface *) NULL) { + // Only operate on uninfected subface, after operating, infect it. + if (!sinfected(subloop)) { + // A new facet has found. + marker = shellmark(subloop); + markerlist->append(&marker); + facetidx = markerlist->len(); // 'facetidx' starts from 1. + setshellmark(subloop, facetidx); + sinfect(subloop); + neighshlist->append(&subloop); + // Find out all subfaces of this facet (bounded by subsegments). + for (i = 0; i < neighshlist->len(); i++) { + neighsh = * (face *) (* neighshlist)[i]; + for (j = 0; j < 3; j++) { + sspivot(neighsh, subseg); + if (subseg.sh == dummysh) { + spivot(neighsh, neineighsh); + if (!sinfected(neineighsh)) { + // 'neineighsh' is in the same facet as 'subloop'. + assert(shellmark(neineighsh) == marker); + setshellmark(neineighsh, facetidx); + sinfect(neineighsh); + neighshlist->append(&neineighsh); + } + } + senextself(neighsh); + } + } + neighshlist->clear(); + } + subloop.sh = shellfacetraverse(subfaces); + } + // Save the facet markers in 'in->facetmarkerlist'. + in->numberoffacets = markerlist->len(); + in->facetmarkerlist = new int[in->numberoffacets]; + for (i = 0; i < in->numberoffacets; i++) { + marker = * (int *) (* markerlist)[i]; + in->facetmarkerlist[i] = marker; + } + // Uninfect all subfaces. + subfaces->traversalinit(); + subloop.sh = shellfacetraverse(subfaces); + while (subloop.sh != (shellface *) NULL) { + assert(sinfected(subloop)); + suninfect(subloop); + subloop.sh = shellfacetraverse(subfaces); + } + + // The mesh contains boundary now. + checksubfaces = 1; + + if (b->quality) { + // Check and recover the Delaunay property. + queue* flipqueue = new queue(sizeof(badface)); + checkdelaunay(flipqueue); + if (!flipqueue->empty()) { + // Call flip algorithm to recover Delaunayness. + flip(flipqueue, NULL); + } + delete flipqueue; + } + + delete markerlist; + delete neighshlist; + delete [] worklist; + delete [] idx2tetlist; + delete [] tetsperverlist; + delete [] idx2facelist; + delete [] facesperverlist; + delete [] idx2verlist; + + return hullsize; +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// insertaddpoints() Insert additional points in 'in->addpointlist'. // +// // +/////////////////////////////////////////////////////////////////////////////// + +void tetgenmesh::insertaddpoints() +{ + queue *flipqueue; + triface searchtet; + face checksh, checkseg; + point newpoint; + point p1, p2, p3, p4; + enum locateresult loc; + REAL ori; + int ptmark; + int index; + int i, j; + + if (!b->quiet) { + printf("Insert additional points into mesh.\n"); + } + // Initialize 'flipqueue'. + flipqueue = new queue(sizeof(badface)); + recenttet.tet = dummytet; + + index = 0; + for (i = 0; i < in->numberofaddpoints; i++) { + // Create a newpoint. + newpoint = (point) points->alloc(); + newpoint[0] = in->addpointlist[index++]; + newpoint[1] = in->addpointlist[index++]; + newpoint[2] = in->addpointlist[index++]; + for (j = 0; j < in->numberofpointattributes; j++) { + newpoint[3 + j] = 0.0; + } + // Remember the point index (starts from 'in->firstnumber'). + ptmark = (int) points->items - (in->firstnumber == 1 ? 0 : 1); + setpointmark(newpoint, ptmark); + // Find the location of the inserted point. + searchtet = recenttet; + loc = locate(newpoint, &searchtet); + if (loc != OUTSIDE) { + if (loc != ONVERTEX) { + loc = adjustlocate(newpoint, &searchtet, loc, b->epsilon); + } + } + if (loc == OUTSIDE) { + // Perform a brute-force search. + tetrahedrons->traversalinit(); + searchtet.tet = tetrahedrontraverse(); + while (searchtet.tet != (tetrahedron *) NULL) { + p1 = (point) searchtet.tet[4]; + p2 = (point) searchtet.tet[5]; + p3 = (point) searchtet.tet[6]; + p4 = (point) searchtet.tet[7]; + ori = orient3d(p2, p1, p3, newpoint); + if (ori >= 0) { + ori = orient3d(p1, p2, p4, newpoint); + if (ori >= 0) { + ori = orient3d(p2, p3, p4, newpoint); + if (ori >= 0) { + ori = orient3d(p3, p1, p4, newpoint); + if (ori >= 0) { + // 'newpoint' lies inside, or on a face, or on an edge, or + // a vertex of 'searchtet'. + loc = adjustlocate(newpoint, &searchtet, OUTSIDE, b->epsilon); + if (loc != OUTSIDE) break; + } + } + } + } + searchtet.tet = tetrahedrontraverse(); + } + } + // Insert the point if it not lies outside or on a vertex. + switch (loc) { + case INTETRAHEDRON: + setpointtype(newpoint, FREEVOLVERTEX); + splittetrahedron(newpoint, &searchtet, flipqueue); + break; + case ONFACE: + tspivot(searchtet, checksh); + if (checksh.sh != dummysh) { + setpointtype(newpoint, FREESUBVERTEX); + } else { + setpointtype(newpoint, FREEVOLVERTEX); + } + splittetface(newpoint, &searchtet, flipqueue); + break; + case ONEDGE: + tsspivot(&searchtet, &checkseg); + if (checkseg.sh != dummysh) { + setpointtype(newpoint, FREESEGVERTEX); + } else { + tspivot(searchtet, checksh); + if (checksh.sh != dummysh) { + setpointtype(newpoint, FREESUBVERTEX); + } else { + setpointtype(newpoint, FREEVOLVERTEX); + } + } + splittetedge(newpoint, &searchtet, flipqueue); + break; + case ONVERTEX: + if (b->verbose) { + printf("Warning: Point (%.17g, %.17g, %.17g) falls on a vertex.\n", + newpoint[0], newpoint[1], newpoint[2]); + } + break; + case OUTSIDE: + if (b->verbose) { + printf("Warning: Point (%.17g, %.17g, %.17g) lies outside the mesh.\n", + newpoint[0], newpoint[1], newpoint[2]); + } + break; + } + // Remember the tetrahedron for next point searching. + recenttet = searchtet; + if (loc == ONVERTEX || loc == OUTSIDE) { + pointdealloc(newpoint); + } else { + flip(flipqueue, NULL); + } + } + + delete flipqueue; +} + +// +// End of mesh update routines +// + +// +// Begin of Delaunay refinement routines +// + +/////////////////////////////////////////////////////////////////////////////// +// // +// initializerpsarray() Calculate the initial radii of protecting spheres // +// of all acute vertices, save in 'rpsarray'. // +// // +/////////////////////////////////////////////////////////////////////////////// + +void tetgenmesh::initializerpsarray(REAL* rpsarray) +{ + list *neightetlist; + tetrahedron tetptr; + triface starttet, neightet; + point pointloop, workpt[3]; + REAL rps, len; + int index, i, j; + + if (b->verbose) { + printf(" Initializing protecting spheres.\n"); + } + + // Initialize the point2tet field of each point. + points->traversalinit(); + pointloop = pointtraverse(); + while (pointloop != (point) NULL) { + setpoint2tet(pointloop, (tetrahedron) NULL); + pointloop = pointtraverse(); + } + // Construct a map from points to tetrahedra. + makepoint2tetmap(); + // Initialize 'neightetlist'. + neightetlist = new list(sizeof(triface), NULL, 256); + + points->traversalinit(); + pointloop = pointtraverse(); + while (pointloop != (point) NULL) { + tetptr = point2tet(pointloop); + // Only calculate lfs(p) if it is acute and is not dangling. + if ((pointtype(pointloop) == ACUTEVERTEX) && + (tetptr != (tetrahedron) NULL)) { + decode(tetptr, starttet); + assert((starttet.tet != NULL) && (starttet.tet != dummytet)); + // Find all tetrahedra sharing 'pointloop'. + findorg(&starttet, pointloop); + infect(starttet); + neightetlist->append(&starttet); + for (i = 0; i < neightetlist->len(); i++) { + starttet = * (triface *)(* neightetlist)[i]; + assert(infected(starttet)); + // The origin of 'starttet' should be 'pointloop'. + adjustedgering(starttet, CCW); + if (org(starttet) != pointloop) { + enextself(starttet); + } + assert(org(starttet) == pointloop); + // Let 'starttet' be the opposite face of 'pointloop'. + enextfnextself(starttet); + assert(oppo(starttet) == pointloop); + // Get three neighbors of faces having 'pointloop'. + adjustedgering(starttet, CCW); + for (j = 0; j < 3; j++) { + fnext(starttet, neightet); + symself(neightet); + // Add it into list if is is not outer space and not infected. + if ((neightet.tet != dummytet) && !infected(neightet)) { + findorg(&neightet, pointloop); + infect(neightet); + neightetlist->append(&neightet); + } + enextself(starttet); + } + } + // 'neightetlist' contains all tetrahedra sharing at 'pointloop'. Get + // the shortest edge length of edges sharing at 'pointloop'. + rps = longest; + for (i = 0; i < neightetlist->len(); i++) { + starttet = * (triface *)(* neightetlist)[i]; + assert(org(starttet) == pointloop); + workpt[0] = dest(starttet); + workpt[1] = apex(starttet); + workpt[2] = oppo(starttet); + for (j = 0; j < 3; j++) { + len = distance(workpt[j], pointloop); + if (pointtype(workpt[j]) == ACUTEVERTEX) { + len /= 3.0; + } else { + len /= 2.0; + } + if (len < rps) rps = len; + } + } + // Uninfect tetrahedra and clear 'neightetlist'. + for (i = 0; i < neightetlist->len(); i++) { + starttet = * (triface *)(* neightetlist)[i]; + uninfect(starttet); + } + neightetlist->clear(); + } else { + // A non-acute or dangling vertex. + rps = 0.0; + } + // Return the local feature size of pointloop. + index = pointmark(pointloop) - in->firstnumber; + rpsarray[index] = rps; + pointloop = pointtraverse(); + } + + delete neightetlist; +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// marksharpfacets() Make a map of facets which form sharp corners. // +// // +// A sharp corner between two facets has a dihedral angle smaller than the // +// 'dihedbound' (in degrees). The map is returned in an integer array // +// 'idx2facetlist'. If idx2facetlist[facetidx - 1] is '1', it means that // +// facet form a sharp corner with other facet. // +// // +// NOTE: idx2facetlist is created inside this routine, don't forget to free // +// it after using. // +// // +/////////////////////////////////////////////////////////////////////////////// + +void tetgenmesh::marksharpfacets(int*& idx2facetlist, REAL dihedbound) +{ + list *incishlist; + triface adjtet; + face segloop, prevseg, checkseg; + face subloop, parentsh, spinsh; + face neighsh, checksh; + point eorg, edest; + REAL anglebound, angle; + int facetidx; + int i, j; + + if (b->verbose) { + printf(" Marking facets have sharp corners.\n"); + } + + anglebound = dihedbound * 3.1415926535897932 / 180.; + // Create and initialize 'idx2facetlist'. + idx2facetlist = new int[in->numberoffacets + 1]; + for (i = 0; i < in->numberoffacets + 1; i++) idx2facetlist[i] = 0; + // A list keeps incident and not co-facet subfaces around a subsegment. + incishlist = new list(sizeof(face), NULL); + + // Loop the set of subsegments once, counter the number of incident + // facets of each facet. + subsegs->traversalinit(); + segloop.sh = shellfacetraverse(subsegs); + while (segloop.sh != (shellface *) NULL) { + // A subsegment may be split into many pieces, we only need one piece + // for getting the incident facets. Only operate on the one which + // contains the origin of the unsplit subsegment. + segloop.shver = 0; + senext2(segloop, prevseg); + spivotself(prevseg); + if (prevseg.sh == dummysh) { + // Operate on this subsegment. + segloop.shver = 0; + spivot(segloop, parentsh); + assert(parentsh.sh != dummysh); + spivot(parentsh, spinsh); + if (spinsh.sh != parentsh.sh) { + // This subface is not self-bonded. + eorg = sorg(segloop); + edest = sdest(segloop); + // Get all incident subfaces around 'segloop'. + spinsh = parentsh; + do { + if (sorg(spinsh) != eorg) { + sesymself(spinsh); + } + incishlist->append(&spinsh); + spivotself(spinsh); + } while (spinsh.sh != parentsh.sh); + // Check the pair of adjacent subfaces for small angle. + spinsh = * (face *)(* incishlist)[0]; + for (i = 1; i <= incishlist->len(); i++) { + if (i == incishlist->len()) { + neighsh = * (face *)(* incishlist)[0]; + } else { + neighsh = * (face *)(* incishlist)[i]; + } + // Only do test when the side spinsh is faceing inward. + stpivot(spinsh, adjtet); + if (adjtet.tet != dummytet) { + angle = facedihedral(eorg, edest, sapex(spinsh), sapex(neighsh)); + if (angle < anglebound) { + facetidx = shellmark(spinsh); + idx2facetlist[facetidx - 1] = 1; + facetidx = shellmark(neighsh); + idx2facetlist[facetidx - 1] = 1; + } + } + spinsh = neighsh; + } + incishlist->clear(); + } + } + segloop.sh = shellfacetraverse(subsegs); + } + + // Ensure all the sharp facets are marked. The mergefacet() operation + // may leave several facets having different markers merged. + incishlist->clear(); + subfaces->traversalinit(); + subloop.sh = shellfacetraverse(subfaces); + while (subloop.sh != (shellface *) NULL) { + // Only operate on sharp and unmarked subfaces. + facetidx = shellmark(subloop); + if (!sinfected(subloop) && (idx2facetlist[facetidx - 1] == 1)) { + sinfect(subloop); + incishlist->append(&subloop); + // Find out all subfaces of this facet (bounded by subsegments). + for (i = 0; i < incishlist->len(); i++) { + neighsh = * (face *) (* incishlist)[i]; + for (j = 0; j < 3; j++) { + sspivot(neighsh, checkseg); + if (checkseg.sh == dummysh) { + spivot(neighsh, checksh); + if (!sinfected(checksh)) { + // 'checksh' is in the same facet as 'subloop'. + sinfect(checksh); + // Check if it is marked. + facetidx = shellmark(checksh); + if (idx2facetlist[facetidx - 1] == 0) { + idx2facetlist[facetidx - 1] = 1; + } + incishlist->append(&checksh); + } + } + senextself(neighsh); + } + } + incishlist->clear(); + } + subloop.sh = shellfacetraverse(subfaces); + } + // Uninfect all sharp subfaces. + subfaces->traversalinit(); + subloop.sh = shellfacetraverse(subfaces); + while (subloop.sh != (shellface *) NULL) { + if (sinfected(subloop)) { + facetidx = shellmark(subloop); + assert(idx2facetlist[facetidx - 1] == 1); + suninfect(subloop); + } + subloop.sh = shellfacetraverse(subfaces); + } + + delete incishlist; +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// enqueuebadtet() Add a bad tetrahedron to the end of a queue. // +// // +// The queue is actually a set of 64 queues. // +// // +/////////////////////////////////////////////////////////////////////////////// + +void tetgenmesh:: +enqueuebadtet(triface *instet, REAL ratio, point insorg, point insdest, + point insapex, point insoppo, point inscent) +{ + badtetrahedron *newtet; + int queuenumber; + + // Allocate space for the bad tetrahedron. + newtet = (badtetrahedron *) badtetrahedrons->alloc(); + newtet->tet = *instet; + newtet->key = ratio; + newtet->cent[0] = inscent[0]; + newtet->cent[1] = inscent[1]; + newtet->cent[2] = inscent[2]; + newtet->tetorg = insorg; + newtet->tetdest = insdest; + newtet->tetapex = insapex; + newtet->tetoppo = insoppo; + newtet->nexttet = (badtetrahedron *) NULL; + // Determine the appropriate queue to put the bad tetrahedron into. + if (ratio > b->goodratio) { + queuenumber = (int) ((ratio - b->goodratio) / 0.5); + // 'queuenumber' may overflow (negative) caused by a very large ratio. + if ((queuenumber > 63) || (queuenumber < 0)) { + queuenumber = 63; + } + } else { + // It's not a bad ratio; put the tet in the lowest-priority queue. + queuenumber = 0; + } + // Add the tetrahedron to the end of a queue. + *tetquetail[queuenumber] = newtet; + // Maintain a pointer to the NULL pointer at the end of the queue. + tetquetail[queuenumber] = &newtet->nexttet; + + if (b->verbose > 2) { + printf(" Queueing bad tet: (%d, %d, %d, %d), ratio %g, qnum %d.\n", + pointmark(insorg), pointmark(insdest), pointmark(insapex), + pointmark(insoppo), sqrt(ratio), queuenumber); + } +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// dequeuebadtet() Remove a tetrahedron from the front of the queue. // +// // +/////////////////////////////////////////////////////////////////////////////// + +tetgenmesh::badtetrahedron* tetgenmesh::dequeuebadtet() +{ + badtetrahedron *result; + int queuenumber; + + // Look for a nonempty queue. + for (queuenumber = 63; queuenumber >= 0; queuenumber--) { + result = tetquefront[queuenumber]; + if (result != (badtetrahedron *) NULL) { + // Remove the tetrahedron from the queue. + tetquefront[queuenumber] = result->nexttet; + // Maintain a pointer to the NULL pointer at the end of the queue. + if (tetquefront[queuenumber] == (badtetrahedron *) NULL) { + tetquetail[queuenumber] = &tetquefront[queuenumber]; + } + return result; + } + } + return (badtetrahedron *) NULL; +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// checkseg4encroach() Check a subsegment to see if it is encroached. // +// // +// A subsegment is encroached if there is a vertex in its diametral circle // +// (that is, the subsegment faces an angle greater than 90 degrees). // +// // +// If 'testpt' is not NULL, only check whether 'testsubseg' is encroached by // +// it or not. Otherwise, check all apexes of faces containing 'testsubseg', // +// to see if there is one encroaches it. // +// // +// If 'enqueueflag' is TRUE, add 'testsubseg' to queue 'badsubsegs' if it is // +// encroached. // +// // +/////////////////////////////////////////////////////////////////////////////// + +bool tetgenmesh:: +checkseg4encroach(face* testsubseg, point testpt, bool enqueueflag) +{ + badface *encsubseg; + triface starttet, spintet; + point eorg, edest, eapex, encpt; + REAL cent[3], radius, dist, diff; + bool enq; + int hitbdry; + + eorg = sorg(*testsubseg); + edest = sdest(*testsubseg); + cent[0] = 0.5 * (eorg[0] + edest[0]); + cent[1] = 0.5 * (eorg[1] + edest[1]); + cent[2] = 0.5 * (eorg[2] + edest[2]); + radius = distance(cent, eorg); + + enq = false; + encpt = (point) NULL; + if (testpt == (point) NULL) { + // Check if it is encroached by traversing all faces containing it. + sstpivot(testsubseg, &starttet); + eapex = apex(starttet); + spintet = starttet; + hitbdry = 0; + do { + dist = distance(cent, apex(spintet)); + diff = dist - radius; + if (fabs(diff) / radius <= b->epsilon) diff = 0.0; // Rounding. + if (diff < 0.0) { + enq = true; + encpt = apex(spintet); + break; + } + if (!fnextself(spintet)) { + hitbdry++; + if (hitbdry < 2) { + esym(starttet, spintet); + if (!fnextself(spintet)) { + hitbdry++; + } + } + } + } while (apex(spintet) != eapex && (hitbdry < 2)); + } else { + // Only check if 'testsubseg' is encroached by 'testpt'. + dist = distance(cent, testpt); + diff = dist - radius; + if (fabs(diff) / radius <= b->epsilon) diff = 0.0; // Rounding. + if (diff < 0.0) { + enq = true; + } + } + + if (enq && enqueueflag) { + if (b->verbose > 2) { + printf(" Queuing encroaching subsegment (%d, %d).\n", + pointmark(eorg), pointmark(edest)); + } + encsubseg = (badface *) badsubsegs->alloc(); + encsubseg->ss = *testsubseg; + encsubseg->forg = eorg; + encsubseg->fdest = edest; + encsubseg->foppo = encpt; + // Set the pointer of 'encsubseg' into 'testseg'. It has two purposes: + // (1) We can regonize it is encroached; (2) It is uniquely queued. + setshell2badface(encsubseg->ss, encsubseg); + } + + return enq; +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// checksub4encroach() Check a subface to see if it is encroached. If so, // +// add it to the list. // +// // +// A subface is encroached if there is a vertex in its diametral sphere. If // +// 'testpt != NULL', only test if 'testsub' is encroached by it. Otherwise, // +// test the opposites of the adjoining tetrahedra of 'testsub' at both side // +// to see whether it is encroached or not. If 'enqueueflag = TRUE', add // +// 'testsub' into pool 'badsubfaces'. Return TRUE if 'testsub' is encroached,// +// return FALSE if it is not. // +// // +/////////////////////////////////////////////////////////////////////////////// + +bool tetgenmesh:: +checksub4encroach(face* testsub, point testpt, bool enqueueflag) +{ + badface *encsub; + triface abuttet; + point forg, fdest, fapex, encpt; + REAL cent[3], radius, dist, diff; + bool enq, bqual, ncollinear; + int quenumber, i; + + enq = false; + encpt = (point) NULL; + bqual = checksub4badqual(testsub); + + if (!bqual) { + forg = sorg(*testsub); + fdest = sdest(*testsub); + fapex = sapex(*testsub); + ncollinear = circumsphere(forg, fdest, fapex, NULL, cent, &radius); + assert(ncollinear == true); + + if (testpt == (point) NULL) { + stpivot(*testsub, abuttet); + if (abuttet.tet != dummytet) { + dist = distance(cent, oppo(abuttet)); + diff = dist - radius; + if (fabs(diff) / radius <= b->epsilon) diff = 0.0; // Rounding. + enq = diff < 0.0; + if (enq) encpt = oppo(abuttet); + } + if (!enq) { + sesymself(*testsub); + stpivot(*testsub, abuttet); + if (abuttet.tet != dummytet) { + dist = distance(cent, oppo(abuttet)); + diff = dist - radius; + if (fabs(diff) / radius <= b->epsilon) diff = 0.0; // Rounding. + enq = diff < 0.0; + if (enq) encpt = oppo(abuttet); + } + } + } else { + // Only do test when 'testpt' is one of its corners. + if (testpt != forg && testpt != fdest && testpt != fapex) { + dist = distance(cent, testpt); + diff = dist - radius; + if (fabs(diff) / radius <= b->epsilon) diff = 0.0; // Rounding. + enq = diff < 0.0; + } + } + } + + if ((enq || bqual) && enqueueflag) { + encsub = (badface *) badsubfaces->alloc(); + encsub->ss = *testsub; + encsub->forg = sorg(*testsub); + encsub->fdest = sdest(*testsub); + encsub->fapex = sapex(*testsub); + encsub->foppo = encpt; + if (enq) { + for (i = 0; i < 3; i++) encsub->cent[i] = cent[i]; + } else { + for (i = 0; i < 3; i++) encsub->cent[i] = 0.0; + } + encsub->nextface = (badface *) NULL; + // Set the pointer of 'encsubseg' into 'testsub'. It has two purposes: + // (1) We can regonize it is encroached; (2) It is uniquely queued. + setshell2badface(encsub->ss, encsub); + quenumber = bqual ? 1 : 0; + // Add the subface to the end of a queue. + *subquetail[quenumber] = encsub; + // Maintain a pointer to the NULL pointer at the end of the queue. + subquetail[quenumber] = &encsub->nextface; + if (b->verbose > 2) { + printf(" Queuing %s subface (%d, %d, %d).\n", + enq ? "encroached" : "badqual", pointmark(encsub->forg), + pointmark(encsub->fdest), pointmark(encsub->fapex)); + } + } + + return enq || bqual; +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// checksub4badquality() Test if the quality of a subface is bad. // +// // +// A subface has bad quality if: (1) its minimum internal angle is smaller // +// than 20 degree; or (2) its area is larger than a maximum area condition. // +// Return TRUE if it is bad. // +// // +/////////////////////////////////////////////////////////////////////////////// + +bool tetgenmesh::checksub4badqual(face* testsub) +{ + face sametestsub; + face subseg1, subseg2; + point torg, tdest, tapex; + point anglevertex; + REAL dxod, dyod, dzod; + REAL dxda, dyda, dzda; + REAL dxao, dyao, dzao; + REAL dxod2, dyod2, dzod2; + REAL dxda2, dyda2, dzda2; + REAL dxao2, dyao2, dzao2; + REAL apexlen, orglen, destlen; + REAL angle, area; + bool enq; + + enq = false; + torg = sorg(*testsub); + tdest = sdest(*testsub); + tapex = sapex(*testsub); + dxod = torg[0] - tdest[0]; + dyod = torg[1] - tdest[1]; + dzod = torg[2] - tdest[2]; + dxda = tdest[0] - tapex[0]; + dyda = tdest[1] - tapex[1]; + dzda = tdest[2] - tapex[2]; + dxao = tapex[0] - torg[0]; + dyao = tapex[1] - torg[1]; + dzao = tapex[2] - torg[2]; + dxod2 = dxod * dxod; + dyod2 = dyod * dyod; + dzod2 = dzod * dzod; + dxda2 = dxda * dxda; + dyda2 = dyda * dyda; + dzda2 = dzda * dzda; + dxao2 = dxao * dxao; + dyao2 = dyao * dyao; + dzao2 = dzao * dzao; + // Find the lengths of the triangle's three edges. + apexlen = dxod2 + dyod2 + dzod2; + orglen = dxda2 + dyda2 + dzda2; + destlen = dxao2 + dyao2 + dzao2; + if ((apexlen < orglen) && (apexlen < destlen)) { + // The edge opposite the apex is shortest. + // Find the square of the cosine of the angle at the apex. + angle = dxda * dxao + dyda * dyao + dzda * dzao; + angle = angle * angle / (orglen * destlen); + anglevertex = tapex; + senext(*testsub, sametestsub); + sspivot(sametestsub, subseg1); + senext2(*testsub, sametestsub); + sspivot(sametestsub, subseg2); + } else if (orglen < destlen) { + // The edge opposite the origin is shortest. + // Find the square of the cosine of the angle at the origin. + angle = dxod * dxao + dyod * dyao + dzod * dzao; + angle = angle * angle / (apexlen * destlen); + anglevertex = torg; + sspivot(*testsub, subseg1); + senext2(*testsub, sametestsub); + sspivot(sametestsub, subseg2); + } else { + // The edge opposite the destination is shortest. + // Find the square of the cosine of the angle at the destination. + angle = dxod * dxda + dyod * dyda + dzod * dzda; + angle = angle * angle / (apexlen * orglen); + anglevertex = tdest; + sspivot(*testsub, subseg1); + senext(*testsub, sametestsub); + sspivot(sametestsub, subseg2); + } + + // Check if both edges that form the angle are segments. + if ((subseg1.sh != dummysh) && (subseg2.sh != dummysh)) { + // The angle is a segment intersection. Don't add this bad subface to + // the list; there's nothing that can be done about a small angle + // between two segments. + angle = 0.0; + } else if (pointtype(anglevertex) == ACUTEVERTEX) { + // If the small angle vertex is acute, do not refine this face. + angle = 0.0; + } + + // Check whether the angle is smaller than permitted. + if (angle > b->goodangle) { + enq = true; + } + + if (!enq && areabound(*testsub) > 0.0) { + // Check whether the area is larger than desired. A variation form of + // Heron's formula which only uses the squares of the edge lengthes + // is used to calculated the area of a 3D triangle. + area = apexlen + orglen - destlen; + area = area * area; + area = 4 * apexlen * orglen - area; + area = 0.25 * sqrt(fabs(area)); + if (area > areabound(*testsub)) { + enq = true; + } + } + + return enq; +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// checktet4badqual() Test a tetrahedron for quality measures. // +// // +// Tests a tetrahedron to see if it satisfies the minimum ratio condition // +// and the maximum volume condition. Tetrahedra that aren't upto spec are // +// added to the bad tetrahedron queue. // +// // +/////////////////////////////////////////////////////////////////////////////// + +bool tetgenmesh::checktet4badqual(triface* testtet) +{ + point torg, tdest, tapex, toppo; + REAL dxod, dyod, dzod, dxda, dyda, dzda, dxao, dyao, dzao; + REAL dxop, dyop, dzop, dxdp, dydp, dzdp, dxap, dyap, dzap; + REAL dxod2, dyod2, dzod2, dxda2, dyda2, dzda2, dxao2, dyao2, dzao2; + REAL dxop2, dyop2, dzop2, dxdp2, dydp2, dzdp2, dxap2, dyap2, dzap2; + REAL dxoc, dyoc, dzoc, dxoc2, dyoc2, dzoc2; + REAL edgelen[6], cent[3]; + REAL smedgelen, averlen, volume; + REAL radius, ratio2; + int i; + + torg = org(*testtet); + tdest = dest(*testtet); + tapex = apex(*testtet); + toppo = oppo(*testtet); + + dxod = torg[0] - tdest[0]; + dyod = torg[1] - tdest[1]; + dzod = torg[2] - tdest[2]; + dxda = tdest[0] - tapex[0]; + dyda = tdest[1] - tapex[1]; + dzda = tdest[2] - tapex[2]; + dxao = tapex[0] - torg[0]; + dyao = tapex[1] - torg[1]; + dzao = tapex[2] - torg[2]; + + dxop = torg[0] - toppo[0]; + dyop = torg[1] - toppo[1]; + dzop = torg[2] - toppo[2]; + dxdp = tdest[0] - toppo[0]; + dydp = tdest[1] - toppo[1]; + dzdp = tdest[2] - toppo[2]; + dxap = tapex[0] - toppo[0]; + dyap = tapex[1] - toppo[1]; + dzap = tapex[2] - toppo[2]; + + dxod2 = dxod * dxod; + dyod2 = dyod * dyod; + dzod2 = dzod * dzod; + dxda2 = dxda * dxda; + dyda2 = dyda * dyda; + dzda2 = dzda * dzda; + dxao2 = dxao * dxao; + dyao2 = dyao * dyao; + dzao2 = dzao * dzao; + + dxop2 = dxop * dxop; + dyop2 = dyop * dyop; + dzop2 = dzop * dzop; + dxdp2 = dxdp * dxdp; + dydp2 = dydp * dydp; + dzdp2 = dzdp * dzdp; + dxap2 = dxap * dxap; + dyap2 = dyap * dyap; + dzap2 = dzap * dzap; + + // Find the smallest edge length of 'testtet'. + edgelen[0] = dxod2 + dyod2 + dzod2; + edgelen[1] = dxda2 + dyda2 + dzda2; + edgelen[2] = dxao2 + dyao2 + dzao2; + edgelen[3] = dxop2 + dyop2 + dzop2; + edgelen[4] = dxdp2 + dydp2 + dzdp2; + edgelen[5] = dxap2 + dyap2 + dzap2; + smedgelen = averlen = edgelen[0]; + for (i = 1; i < 6; i++) { + averlen += sqrt(edgelen[i]); + if (smedgelen > edgelen[i]) { + smedgelen = edgelen[i]; + } + } + averlen /= 6.0; + + // Find the circumcenter and circumradius of 'testtet'. + circumsphere(torg, tdest, tapex, toppo, cent, NULL); + dxoc = torg[0] - cent[0]; + dyoc = torg[1] - cent[1]; + dzoc = torg[2] - cent[2]; + dxoc2 = dxoc * dxoc; + dyoc2 = dyoc * dyoc; + dzoc2 = dzoc * dzoc; + radius = dxoc2 + dyoc2 + dzoc2; + + // Calculate the square of radius-edge ratio. + ratio2 = radius / smedgelen; + + // Check whether the ratio is smaller than permitted. + if (ratio2 > b->goodratio) { + // Add this tet to the list of bad tetrahedra. + enqueuebadtet(testtet, ratio2, torg, tdest, tapex, toppo, cent); + return true; + } + if (b->varvolume || b->fixedvolume) { + volume = orient3d(torg, tdest, tapex, toppo); + if (volume < 0) volume = -volume; + volume /= 6.0; + // Check whether the volume is larger than permitted. + if (b->fixedvolume && (volume > b->maxvolume)) { + // Add this tetrahedron to the list of bad tetrahedra. + enqueuebadtet(testtet, 0, torg, tdest, tapex, toppo, cent); + return true; + } else if (b->varvolume) { + // Nonpositive volume constraints are treated as unconstrained. + if ((volume > volumebound(testtet->tet)) && + (volumebound(testtet->tet) > 0.0)) { + // Add this tetrahedron to the list of bad tetrahedron. + enqueuebadtet(testtet, 0, torg, tdest, tapex, toppo, cent); + return true; + } + } + } + return false; +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// checktet4illtet() Test a tetrahedron to see if it is illegal. // +// // +// A tetrahedron is assumed as illegal if its four corners are defined on // +// one facet. A tetrahedron has zero volume is illegal. Add it into queue // +// if it is illegal. // +// // +/////////////////////////////////////////////////////////////////////////////// + +bool tetgenmesh::checktet4illtet(triface* testtet, list* illtetlist) +{ + badtetrahedron *badtet; + triface neighface; + face testsh, neighsh, testseg; + bool isill; + int i; + + isill = false; + testtet->loc = 0; + testtet->ver = 0; + tspivot(*testtet, testsh); // edge ab + if (testsh.sh != dummysh) { + // Check subfaces at edges ab, bc, ca. + findedge(&testsh, org(*testtet), dest(*testtet)); + for (i = 0; i < 3; i++) { + sspivot(testsh, testseg); + if (testseg.sh == dummysh) { + fnext(*testtet, neighface); + tspivot(neighface, neighsh); + if (neighsh.sh != dummysh) { + isill = true; + break; + } + } + enextself(*testtet); + senextself(testsh); + } + } + if (!isill) { + testtet->loc = 0; + testtet->ver = 0; + fnextself(*testtet); + esymself(*testtet); + tspivot(*testtet, testsh); + if (testsh.sh != dummysh) { + // Check subfaces at edges ad, db. + findedge(&testsh, org(*testtet), dest(*testtet)); + for (i = 0; i < 2; i++) { + enextself(*testtet); + senextself(testsh); + sspivot(testsh, testseg); + if (testseg.sh == dummysh) { + fnext(*testtet, neighface); + tspivot(neighface, neighsh); + if (neighsh.sh != dummysh) { + isill = true; + break; + } + } + } + } + } + if (!isill) { + testtet->loc = 0; + testtet->ver = 0; + enextfnextself(*testtet); + esymself(*testtet); + enext2self(*testtet); // edge cd. + tspivot(*testtet, testsh); + if (testsh.sh != dummysh) { + findedge(&testsh, org(*testtet), dest(*testtet)); + sspivot(testsh, testseg); + if (testseg.sh == dummysh) { + fnext(*testtet, neighface); + tspivot(neighface, neighsh); + if (neighsh.sh != dummysh) { + isill = true; + } + } + } + } + if (isill) { + badtet = (badtetrahedron *) illtetlist->append(NULL); + badtet->tet = *testtet; + badtet->tetorg = org(*testtet); + badtet->tetdest = dest(*testtet); + badtet->tetapex = apex(*testtet); + badtet->tetoppo = oppo(*testtet); + if (b->verbose > 2) { + printf(" Queuing illtet (%d, %d, %d, %d).\n", + pointmark(badtet->tetorg), pointmark(badtet->tetdest), + pointmark(badtet->tetapex), pointmark(badtet->tetoppo)); + } + } + return isill; +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// checktet4sliver() Test a tetrahedron for large dihedral angle. // +// // +/////////////////////////////////////////////////////////////////////////////// + +bool tetgenmesh::checktet4sliver(triface* testtet, list* illtetlist) +{ + badtetrahedron *badtet; + point pa, pb, pc, pd; + REAL dihed[6]; + bool issliver; + + pa = (point) testtet->tet[4]; + pb = (point) testtet->tet[5]; + pc = (point) testtet->tet[6]; + pd = (point) testtet->tet[7]; + tetalldihedral(pa, pb, pc, pd, dihed); + + issliver = false; + testtet->loc = 0; + testtet->ver = 0; + if (dihed[0] > b->maxdihedral) { // Edge ab + issliver = true; + } + if (!issliver && (dihed[1] > b->maxdihedral)) { // Edge ac + enext2self(*testtet); + issliver = true; + } + if (!issliver && (dihed[2] > b->maxdihedral)) { // Edge ad + fnextself(*testtet); + enext2self(*testtet); + esymself(*testtet); + issliver = true; + } + if (!issliver && (dihed[3] > b->maxdihedral)) { // Edge bc + enextself(*testtet); + issliver = true; + } + if (!issliver && (dihed[4] > b->maxdihedral)) { // Edge bd + fnextself(*testtet); + enextself(*testtet); + esymself(*testtet); + issliver = true; + } + if (!issliver && (dihed[5] > b->maxdihedral)) { // Edge cd + enextfnextself(*testtet); + enextself(*testtet); + esymself(*testtet); + issliver = true; + } + + if (issliver) { + badtet = (badtetrahedron *) illtetlist->append(NULL); + badtet->tet = *testtet; + badtet->tetorg = org(*testtet); + badtet->tetdest = dest(*testtet); + badtet->tetapex = apex(*testtet); + badtet->tetoppo = oppo(*testtet); + if (b->verbose > 2) { + printf(" Queuing sliver (%d, %d, %d, %d).\n", + pointmark(badtet->tetorg), pointmark(badtet->tetdest), + pointmark(badtet->tetapex), pointmark(badtet->tetoppo)); + } + } + return issliver; +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// checkseg4splitting() Check an encroached subsegment to see if it is // +// suitable to be split. // +// // +// If a subsegment is one of edges of a subface which is on the sharp corner,// +// it is not suitable to be split. If the volume constraint is set, it is // +// still suitable to be split if there is a tetrahedron around it which has // +// volume larger than volumebound. To avoid resulting too skinny tetrahedron,// +// we compare the longest edge length to the cubic root of volumebound. // +// // +/////////////////////////////////////////////////////////////////////////////// + +bool tetgenmesh::checkseg4splitting(face* testseg, REAL* rpsarray, bool bqual) +{ + triface spintet; + face parentsh, spinsh; + point eorg, edest, fapex; + bool acuteorg, acutedest; + REAL rpslimit; + REAL L, L3; + int ptidx; + + eorg = sorg(*testseg); + edest = sdest(*testseg); + acuteorg = pointtype(eorg) == ACUTEVERTEX; + acutedest = pointtype(edest) == ACUTEVERTEX; + if ((acuteorg && acutedest) || (!acuteorg && !acutedest)) { + // Can be split. + return true; + } + // Now exactly one vertex is acute. + assert(acuteorg || acutedest); + if (!bqual) { + // We're not forced to split it. However, if it is encroached by an + // existing vertex, we must split it, otherwise, not split it. + return checkseg4encroach(testseg, NULL, false); + } + + L = distance(eorg, edest); + if (acuteorg) { + ptidx = pointmark(eorg) - in->firstnumber; + } else { + assert(acutedest); + ptidx = pointmark(edest) - in->firstnumber; + } + rpslimit = rpsarray[ptidx] / 4.0; + if (L > (rpslimit * 1.1)) { + // The edge is not too small, can be split. + return true; + } + // L <= rpslimit. We should not split it. However, it may still be + // split if its length is too long wrt. the volume constraints. + if (b->varvolume || b->fixedvolume) { + L3 = L * L * L / 6.0; + if (b->fixedvolume && (L3 > b->maxvolume)) { + // This edge is too long wrt. the maximum volume bound. Split it. + return true; + } + if (b->varvolume) { + spivot(*testseg, parentsh); + if (sorg(parentsh) != eorg) sesymself(parentsh); + stpivot(parentsh, spintet); + if (spintet.tet == dummytet) { + sesymself(parentsh); + stpivot(parentsh, spintet); + assert(spintet.tet != dummytet); + } + findedge(&spintet, eorg, edest); + fapex = apex(spintet); + while (true) { + if (!fnextself(spintet)) { + // Meet a boundary, walk through it. + tspivot(spintet, spinsh); + assert(spinsh.sh != dummysh); + findedge(&spinsh, eorg, edest); + sfnextself(spinsh); + stpivot(spinsh, spintet); + assert(spintet.tet != dummytet); + findedge(&spintet, eorg, edest); + } + if ((L3 > volumebound(spintet.tet)) && + (volumebound(spintet.tet) > 0.0)) { + // This edge is too long wrt. the maximum volume bound. Split it. + return true; + } + if (apex(spintet) == fapex) break; + } + } + } + + // Not split it. + return false; +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// checksub4splitting() Check an encroached subface to see if it is // +// suitable to be split. // +// // +// If a subface is on the sharp corner, it is not suitable to be split. If // +// the volume constraint is set, it is still suitable to be split if there // +// is a tetrahedron around it which has volume larger than volumebound. To // +// avoid resulting too skinny tet, we compare the longest edge length to the // +// cubic root of volumebound. // +// // +/////////////////////////////////////////////////////////////////////////////// + +bool tetgenmesh::checksub4splitting(face* testsh) +{ + triface testtet; + point p[3]; + REAL L, L3; + int i; + + if (b->varvolume || b->fixedvolume) { + // Check if all the tetrahedra having this subface are conforming to + // the volume bound specified in b.maxvolume. Here we don't use each + // tetrahedron's volume for comparsion, instead is an approximate + // volume (one sixth of the cubic of its longest edge length). We + // hope this way can find skinny tetrahedra and split them. + p[0] = sorg(*testsh); + p[1] = sdest(*testsh); + p[2] = sapex(*testsh); + // Get the longest edge length of testsh = L. + L = distance(p[0], p[1]); + L3 = distance(p[1], p[2]); + L = (L >= L3 ? L : L3); + L3 = distance(p[2], p[0]); + L = (L >= L3 ? L : L3); + + L3 = L * L * L / 6.0; + if (b->fixedvolume && (L3 > b->maxvolume)) { + // This face is too large wrt. the maximum volume bound. Split it. + return true; + } + if (b->varvolume) { + for (i = 0; i < 2; i ++) { + stpivot(*testsh, testtet); + if (testtet.tet != dummytet) { + if ((L3 > volumebound(testtet.tet)) && + (volumebound(testtet.tet) > 0.0)) { + // This face is too large wrt. the maximum volume bound. + return true; + } + } + sesymself(*testsh); + } + } + } + return false; +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// doqualchecktetlist() Put bad-quality tetrahedra in 'qualchecktetlist' // +// into queue and clear it. // +// // +// 'qualchecktetlist' stores a list of tetrahedra which are possibly bad- // +// quality, furthermore, one tetrahedron may appear many times in it. For // +// testing and queuing each bad-quality tetrahedron only once, infect it // +// after testing, later on, only test the one which is not infected. On // +// finish, uninfect them. // +// // +/////////////////////////////////////////////////////////////////////////////// + +void tetgenmesh::doqualchecktetlist() +{ + triface testtet; + int i; + + for (i = 0; i < qualchecktetlist->len(); i++) { + testtet = * (triface *) (* qualchecktetlist)[i]; + if (!isdead(&testtet) && !infected(testtet)) { + checktet4badqual(&testtet); + infect(testtet); + } + } + for (i = 0; i < qualchecktetlist->len(); i++) { + testtet = * (triface *) (* qualchecktetlist)[i]; + if (!isdead(&testtet) && infected(testtet)) { + uninfect(testtet); + } + } + qualchecktetlist->clear(); +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// tallencsegs() Check for encroached segments, save them in list. // +// // +// If both 'testpt' and 'cavtetlist' are not NULLs, then check the segments // +// in 'cavtetlist' to see if they're encroached by 'testpt'. Otherwise, // +// check the entire list of segments to see if they're encroached by any of // +// mesh vertices. // +// // +/////////////////////////////////////////////////////////////////////////////// + +bool tetgenmesh::tallencsegs(point testpt, list *cavtetlist) +{ + triface starttet, neightet; + face checkseg; + long oldencnum; + int i, j; + + // Remember the current number of encroached segments. + oldencnum = badsubsegs->items; + + if (cavtetlist != (list *) NULL) { + assert(testpt != (point) NULL); + // Check segments in the list of tetrahedra. + for (i = 0; i < cavtetlist->len(); i++) { + starttet = * (triface *)(* cavtetlist)[i]; + infect(starttet); // Indicate it has been tested. + sym(starttet, neightet); + if (!infected(neightet)) { + // Test all three edges of this face. + for (j = 0; j < 3; j++) { + tsspivot(&starttet, &checkseg); + if (checkseg.sh != dummysh) { + if (!shell2badface(checkseg)) { + checkseg4encroach(&checkseg, testpt, true); + } + } + enextself(starttet); + } + } + adjustedgering(starttet, CCW); + fnext(starttet, neightet); + symself(neightet); + if ((neightet.tet == dummytet) || !infected(neightet)) { + fnext(starttet, neightet); + // Test the tow other edges of this face. + for (j = 0; j < 2; j++) { + enextself(neightet); + tsspivot(&neightet, &checkseg); + if (checkseg.sh != dummysh) { + if (!shell2badface(checkseg)) { + checkseg4encroach(&checkseg, testpt, true); + } + } + } + } + enextfnext(starttet, neightet); + symself(neightet); + if ((neightet.tet == dummytet) || !infected(neightet)) { + enextfnext(starttet, neightet); + // Only test the next edge of this face. + enextself(neightet); + tsspivot(&neightet, &checkseg); + if (checkseg.sh != dummysh) { + if (!shell2badface(checkseg)) { + checkseg4encroach(&checkseg, testpt, true); + } + } + } + } + // Uninfect all tetrahedra in the list. + for (i = 0; i < cavtetlist->len(); i++) { + starttet = * (triface *)(* cavtetlist)[i]; + assert(infected(starttet)); + uninfect(starttet); + } + } else { + // Check the entire list of segments. + subsegs->traversalinit(); + checkseg.sh = shellfacetraverse(subsegs); + while (checkseg.sh != (shellface *) NULL) { + checkseg4encroach(&checkseg, NULL, true); + checkseg.sh = shellfacetraverse(subsegs); + } + } + + return (badsubsegs->items > oldencnum); +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// tallencsubs() Find all encroached subfaces and save them in list. // +// // +// If 'cavtetlist' and 'testpt' are not NULL, only check subfaces which are // +// in cavtetlist. Otherwise check all subfaces in current mesh. If 'protonly'// +// is TRUE, only check subfaces which are in protecting cylinders & spheres. // +// Return TRUE if at least one encorached subface is found. // +// // +/////////////////////////////////////////////////////////////////////////////// + +bool tetgenmesh::tallencsubs(point testpt, list* cavtetlist) +{ + triface starttet, neightet; + face checksh; + long oldencnum; + int i, j; + + // Remember the current number of encroached segments. + oldencnum = badsubfaces->items; + + if (cavtetlist != (list *) NULL) { + assert(testpt != (point) NULL); + // Check subfaces in the list of tetrahedra. + for (i = 0; i < cavtetlist->len(); i++) { + starttet = * (triface *)(* cavtetlist)[i]; + infect(starttet); // Indicate it has been tested. + sym(starttet, neightet); + if (!infected(neightet)) { + // Test if this face is encroached. + tspivot(starttet, checksh); + if (checksh.sh != dummysh) { + // If it is not encroached, test it. + if (shell2badface(checksh) == NULL) { + checksub4encroach(&checksh, testpt, true); + } + } + } + adjustedgering(starttet, CCW); + // Check the other three sides of this tet. + for (j = 0; j < 3; j++) { + fnext(starttet, neightet); + symself(neightet); + if ((neightet.tet == dummytet) || !infected(neightet)) { + fnext(starttet, neightet); + // Test if this face is encroached. + tspivot(neightet, checksh); + if (checksh.sh != dummysh) { + // If it is not encroached, test it. + if (shell2badface(checksh) == NULL) { + checksub4encroach(&checksh, testpt, true); + } + } + } + enextself(starttet); + } + } + // Uninfect all tetrahedra in the list. + for (i = 0; i < cavtetlist->len(); i++) { + starttet = * (triface *)(* cavtetlist)[i]; + assert(infected(starttet)); + uninfect(starttet); + } + } else { + // Check the entire list of subfaces. + subfaces->traversalinit(); + checksh.sh = shellfacetraverse(subfaces); + while (checksh.sh != (shellface *) NULL) { + // If it is not encroached, test it. + checksub4encroach(&checksh, NULL, true); + checksh.sh = shellfacetraverse(subfaces); + } + } + + return (badsubfaces->items > oldencnum); +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// tallbadtetrahedrons() Test every tetrahedron in the mesh for quality // +// measures. // +// // +/////////////////////////////////////////////////////////////////////////////// + +void tetgenmesh::tallbadtetrahedrons() +{ + triface tetloop; + + tetrahedrons->traversalinit(); + tetloop.tet = tetrahedrontraverse(); + while (tetloop.tet != (tetrahedron *) NULL) { + checktet4badqual(&tetloop); + tetloop.tet = tetrahedrontraverse(); + } +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// tallilltets() Test every tetrahedron in the mesh for illegal tet. // +// // +/////////////////////////////////////////////////////////////////////////////// + +void tetgenmesh::tallilltets(list* illtetlist) +{ + triface tetloop; + REAL bakdihedral; + + bakdihedral = b->maxdihedral; + b->maxdihedral = 3.1415926535897932 * (1.0 - b->epsilon); + + tetrahedrons->traversalinit(); + tetloop.tet = tetrahedrontraverse(); + while (tetloop.tet != (tetrahedron *) NULL) { + if (!checktet4illtet(&tetloop, illtetlist)) { + checktet4sliver(&tetloop, illtetlist); + } + tetloop.tet = tetrahedrontraverse(); + } + + b->maxdihedral = bakdihedral; +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// tallslivers() Test every tetrahedron in the mesh for sliver checking. // +// // +/////////////////////////////////////////////////////////////////////////////// + +void tetgenmesh::tallslivers(list* illtetlist) +{ + triface tetloop; + + tetrahedrons->traversalinit(); + tetloop.tet = tetrahedrontraverse(); + while (tetloop.tet != (tetrahedron *) NULL) { + checktet4sliver(&tetloop, illtetlist); + tetloop.tet = tetrahedrontraverse(); + } +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// removeilltets() Repair mesh by removing illegal elements. // +// // +/////////////////////////////////////////////////////////////////////////////// + +void tetgenmesh::removeilltets() +{ + badtetrahedron *badtet; + list *illtetlist; + queue *flipqueue; + int i; + + if (!b->quiet) { + printf("Removing illegal tetrahedra.\n"); + } + // Initialize the pool of bad tetrahedra. + illtetlist = new list(sizeof(badtetrahedron), NULL, 1024); + // Initialize 'flipqueue'. + flipqueue = new queue(sizeof(badface)); + // Initialize the pool of recently flipped faces. + flipstackers = new memorypool(sizeof(flipstacker), 1024, POINTER, 0); + + // Test all tetrahedra to see if they're slivers. + tallilltets(illtetlist); + do { + for (i = 0; i < illtetlist->len(); i++) { + badtet = (badtetrahedron *)(* illtetlist)[i]; + if (!isdead(&badtet->tet) && (org(badtet->tet) == badtet->tetorg) && + (dest(badtet->tet) == badtet->tetdest) && + (apex(badtet->tet) == badtet->tetapex) && + (oppo(badtet->tet) == badtet->tetoppo)) { + removebadtet(ILLEGAL, &badtet->tet, flipqueue); + } + } + illtetlist->clear(); + tallilltets(illtetlist); + } while (illtetlist->len() > 0); + + delete flipstackers; + delete flipqueue; + delete illtetlist; +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// removeslivers() Repair mesh by removing slivers. // +// // +/////////////////////////////////////////////////////////////////////////////// + +void tetgenmesh::removeslivers() +{ + badtetrahedron *badtet; + list *illtetlist; + int i; + + if (!b->quiet) { + printf("Removing slivers.\n"); + } + + // Initialize the pool of bad tetrahedra. + illtetlist = new list(sizeof(badtetrahedron), NULL, 1024); + // Initialize the pool of recently flipped faces. + flipstackers = new memorypool(sizeof(flipstacker), 1024, POINTER, 0); + + // Test all tetrahedra to see if they're slivers. + tallslivers(illtetlist); + for (i = 0; i < illtetlist->len(); i++) { + badtet = (badtetrahedron *)(* illtetlist)[i]; + if (!isdead(&badtet->tet) && (org(badtet->tet) == badtet->tetorg) && + (dest(badtet->tet) == badtet->tetdest) && + (apex(badtet->tet) == badtet->tetapex) && + (oppo(badtet->tet) == badtet->tetoppo)) { + // It's a sliver, remove it. + removebadtet(SLIVER, &badtet->tet, NULL); + } + } + illtetlist->clear(); + + delete flipstackers; + delete illtetlist; +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// repairencsegs() Repair all the encroached subsegments until no // +// subsegment is encroached. // +// // +// At beginning, all encroached subsegments are stored in pool 'badsubsegs'. // +// Each encroached subsegment is repaired by splitting it, i.e., inserting a // +// point somewhere in it. Newly inserted points may encroach upon other // +// subsegments, these are also repaired. // +// // +// After splitting a segment, the Delaunay property of the mesh is recovered // +// by flip operations. 'flipqueue' returns a list of updated faces which may // +// be non-locally Delaunay. // +// // +/////////////////////////////////////////////////////////////////////////////// + +void tetgenmesh::repairencsegs(REAL* rpsarray, bool bqual, queue* flipqueue) +{ + badface *encloop; + triface starttet; + face startsh, spinsh, checksh; + face splitseg, checkseg; + point eorg, edest; + point newpoint, ppt; + bool acuteorg, acutedest; + REAL rps, len, split; + int ptidx, i; + + if (b->verbose > 1) { + printf(" Splitting encroached subsegments.\n"); + } + + // Note that steinerleft == -1 if an unlimited number of Steiner points + // is allowed. Loop until 'badsubsegs' is empty. + while ((badsubsegs->items > 0) && (steinerleft != 0)) { + badsubsegs->traversalinit(); + encloop = badfacetraverse(badsubsegs); + while ((encloop != (badface *) NULL) && (steinerleft != 0)) { + splitseg = encloop->ss; + // Every splitseg has a pointer to encloop, now clear it. + assert(shell2badface(splitseg) == encloop); + setshell2badface(splitseg, NULL); + eorg = sorg(splitseg); + edest = sdest(splitseg); + assert((eorg == encloop->forg) && (edest == encloop->fdest)); + if (b->verbose > 1) { + printf(" Get encseg (%d, %d).\n", pointmark(eorg), pointmark(edest)); + } + + if (checkseg4splitting(&splitseg, rpsarray, bqual)) { + // Decide the position to split the segment. Use the cutting sphere + // if any of the endpoints is acute. + acuteorg = (pointtype(eorg) == ACUTEVERTEX); + acutedest = (pointtype(edest) == ACUTEVERTEX); + if (acuteorg || acutedest) { + if (!acuteorg) { + // eorg is not acute, but edest is. Exchange eorg, edest. + eorg = edest; + edest = sorg(splitseg); + } + // Now, eorg must be acute. + len = distance(eorg, edest); + // Get the radius of the current protecting sphere. + ptidx = pointmark(eorg) - in->firstnumber; + rps = rpsarray[ptidx]; + // Calculate the suitable radius to split the segment. It should + // be no larger than half of the segment length. + while (rps > 0.51 * len) { + rps *= 0.5; + } + assert((rps * 16.0) > rpsarray[ptidx]); + // Where to split the segment. + split = rps / len; + ppt = eorg; + } else { + split = 0.5; + ppt = (point) NULL; + } + + // Create the new point. + makepoint(&newpoint); + // Set its coordinates. + for (i = 0; i < 3; i++) { + newpoint[i] = eorg[i] + split * (edest[i] - eorg[i]); + } + // Interpolate its attributes. + for (i = 0; i < in->numberofpointattributes; i++) { + newpoint[i + 3] = eorg[i + 3] + split * (edest[i + 3] - eorg[i + 3]); + } + // Set the parent point into the newpoint. + setpoint2ppt(newpoint, ppt); + // Set the type of the newpoint. + setpointtype(newpoint, FREESEGVERTEX); + // Set splitseg into the newpoint. + setpoint2sh(newpoint, sencode(splitseg)); + + // Insert new point into the mesh. It should be always success. + splitseg.shver = 0; + sstpivot(&splitseg, &starttet); + splittetedge(newpoint, &starttet, flipqueue); + if (steinerleft > 0) steinerleft--; + + // Check the two new subsegments to see if they're encroached. + checkseg4encroach(&splitseg, NULL, true); + if (badsubfaces != (memorypool *) NULL) { + // Check the subfaces link of s to see if they're encroached. + spivot(splitseg, startsh); + spinsh = startsh; + do { + findedge(&spinsh, sorg(splitseg), sdest(splitseg)); + // The next two lines are only for checking. + sspivot(spinsh, checkseg); + assert(checkseg.sh == splitseg.sh); + checksh = spinsh; + if (!shell2badface(checksh)) { + checksub4encroach(&checksh, NULL, true); + } + // The above operation may change the edge. + findedge(&spinsh, sorg(splitseg), sdest(splitseg)); + spivotself(spinsh); + } while (spinsh.sh != startsh.sh); + } + senextself(splitseg); + spivotself(splitseg); + assert(splitseg.sh != (shellface *) NULL); + splitseg.shver = 0; + checkseg4encroach(&splitseg, NULL, true); + if (badsubfaces != (memorypool *) NULL) { + // Check the subfaces link of s to see if they're encroached. + spivot(splitseg, startsh); + spinsh = startsh; + do { + findedge(&spinsh, sorg(splitseg), sdest(splitseg)); + // The next two lines are only for checking. + sspivot(spinsh, checkseg); + assert(checkseg.sh == splitseg.sh); + checksh = spinsh; + if (!shell2badface(checksh)) { + checksub4encroach(&checksh, NULL, true); + } + // The above operation may change the edge. + findedge(&spinsh, sorg(splitseg), sdest(splitseg)); + spivotself(spinsh); + } while (spinsh.sh != startsh.sh); + } + + // Recover Delaunay property by flipping. All existing segments which + // are encroached by the new point will be discovered during flips + // and be queued in list. + flip(flipqueue, NULL); + // Queuing bad-quality tetrahedra if need. + if (badtetrahedrons != (memorypool *) NULL) { + doqualchecktetlist(); + } + } + + // Remove this entry from list. + badfacedealloc(badsubsegs, encloop); + // Get the next encroached segments. + encloop = badfacetraverse(badsubsegs); + } + } +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// repairencsubs() Repair all the encroached subfaces until no subface is // +// encroached. // +// // +// At beginning, all encroached subfaces are stored in pool 'badsubfaces'. // +// Each encroached subface is repaired by splitting it, i.e., inserting a // +// point at its circumcenter. However, if this point encroaches upon one or // +// more subsegments then we don not add it and instead split the subsegments.// +// Newly inserted points may encroach upon other subfaces, these are also // +// repaired. // +// // +// After splitting a subface, the Delaunay property of the mesh is recovered // +// by flip operations. 'flipqueue' returns a list of updated faces and may // +// be non-locally Delaunay. // +// // +/////////////////////////////////////////////////////////////////////////////// + +void tetgenmesh::repairencsubs(REAL* rpsarray, int* idx2facetlist, + list* cavtetlist, queue* flipqueue) +{ + badface *encloop; + triface starttet; + face splitsub, neisplitsub; + face checksh, checkseg; + point newpoint, checkpt; + point pa, pb; + enum locateresult loc; + REAL epspp, dist; + bool enq, reject; + bool splitit, bqual; + int facetidx, quenumber; + int epscount; + int i; + + if (b->verbose > 1) { + printf(" Splitting encroached subfaces.\n"); + } + + // Note that steinerleft == -1 if an unlimited number of Steiner points + // is allowed. Loop until the list 'badsubfaces' is empty. + while ((badsubfaces->items > 0) && (steinerleft != 0)) { + // Look for a nonempty queue. + encloop = (badface *) NULL; + for (quenumber = 1; quenumber >= 0; quenumber--) { + encloop = subquefront[quenumber]; + if (encloop != (badface *) NULL) { + // Remove the badface from the queue. + subquefront[quenumber] = encloop->nextface; + // Maintain a pointer to the NULL pointer at the end of the queue. + if (subquefront[quenumber] == (badface *) NULL) { + subquetail[quenumber] = &subquefront[quenumber]; + } + break; + } + } + assert(encloop != (badface *) NULL); + if (b->verbose > 2) { + printf(" Dequeuing ensub (%d, %d, %d) [%d].\n", + pointmark(encloop->forg), pointmark(encloop->fdest), + pointmark(encloop->fapex), quenumber); + } + + // Clear the pointer saved in encloop->ss. + splitsub = encloop->ss; + setshell2badface(splitsub, NULL); + // The subface may be not the same one when it was determined to be + // encroached. If its adjacent encroached subface was split, the + // consequent flips may change it into another subface. + enq = ((sorg(splitsub) == encloop->forg) && + (sdest(splitsub) == encloop->fdest) && + (sapex(splitsub) == encloop->fapex)); + if (enq) { + // This subface is encroached or has bad quality. + bqual = (quenumber == 1); + facetidx = shellmark(splitsub); + // Split it if it is bad quality or is not sharp. + splitit = bqual || (idx2facetlist[facetidx - 1] != 1); + if (!splitit) { + // Split it if it's neighboring tets have too big volume. + bqual = checksub4splitting(&splitsub); + splitit = (bqual == true); + } + if (splitit) { + // We can or force to split this subface. + makepoint(&newpoint); + // If it is a bad quality face, calculate its circumcenter. + if (quenumber == 1) { + circumsphere(encloop->forg, encloop->fdest, encloop->fapex, NULL, + encloop->cent, NULL); + } + // Set the coordinates of newpoint. + for (i = 0; i < 3; i++) newpoint[i] = encloop->cent[i]; + stpivot(splitsub, starttet); + if (starttet.tet == dummytet) { + sesymself(splitsub); + stpivot(splitsub, starttet); + } + assert(starttet.tet != dummytet); + // Locate the newpoint in facet (resulting in splitsub). + loc = locatesub(newpoint, &splitsub, oppo(starttet)); + stpivot(splitsub, starttet); + if (starttet.tet == dummytet) { + sesymself(splitsub); + stpivot(splitsub, starttet); + } + assert(starttet.tet != dummytet); + // Look if the newpoint encroaches upon some segments. + recenttet = starttet; // Used for the input of preciselocate(). + collectcavtets(newpoint, cavtetlist); + assert(cavtetlist->len() > 0); + reject = tallencsegs(newpoint, cavtetlist); + // Clear the list for the next use. + cavtetlist->clear(); + if (!reject) { + // Remove the encroached subface by inserting the newpoint. + if (loc != ONVERTEX) { + // Adjust the location of newpoint wrt. starttet. + epspp = b->epsilon; + epscount = 0; + while (epscount < 16) { + loc = adjustlocate(newpoint, &starttet, ONFACE, epspp); + if (loc == ONVERTEX) { + checkpt = org(starttet); + dist = distance(checkpt, newpoint); + if ((dist / longest) > b->epsilon) { + epspp *= 1e-2; + epscount++; + continue; + } + } + break; + } + } + pa = org(starttet); + pb = dest(starttet); + findedge(&splitsub, pa, pb); + // Let splitsub be face abc. ab is the current edge. + if (loc == ONFACE) { + // Split the face abc into three faces abv, bcv, cav. + splittetface(newpoint, &starttet, flipqueue); + // Adjust splitsub be abv. + findedge(&splitsub, pa, pb); + assert(sapex(splitsub) == newpoint); + // Check the three new subfaces to see if they're encroached. + // splitsub may be queued (it exists before split). + checksh = splitsub; + if (!shell2badface(checksh)) { + checksub4encroach(&checksh, NULL, true); // abv + } + senext(splitsub, checksh); + spivotself(checksh); + // It is a new created face and should not be infected. + assert(checksh.sh != dummysh && !shell2badface(checksh)); + checksub4encroach(&checksh, NULL, true); // bcv + senext2(splitsub, checksh); + spivotself(checksh); + // It is a new created face and should not be infected. + assert(checksh.sh != dummysh && !shell2badface(checksh)); + checksub4encroach(&checksh, NULL, true); // cav + } else if (loc == ONEDGE) { + // Let the adjacent subface be bad. ab is the spliting edge. + // Split two faces abc, bad into 4 faces avc, vbc, avd, vbd. + sspivot(splitsub, checkseg); + assert(checkseg.sh == dummysh); + // Remember the neighbor subface abd (going to be split also). + spivot(splitsub, neisplitsub); + findedge(&neisplitsub, pa, pb); + // Split two faces abc, abd into four faces avc, vbc, avd, vbd. + splittetedge(newpoint, &starttet, flipqueue); + // Adjust splitsub be avc, neisplitsub be avd. + findedge(&splitsub, pa, newpoint); + findedge(&neisplitsub, pa, newpoint); + // Check the four new subfaces to see if they're encroached. + // splitsub may be an infected one (it exists before split). + checksh = splitsub; + if (!shell2badface(checksh)) { + checksub4encroach(&checksh, NULL, true); // avc + } + // Get vbc. + senext(splitsub, checksh); + spivotself(checksh); + // vbc is newly created. + assert(checksh.sh != dummysh && !shell2badface(checksh)); + checksub4encroach(&checksh, NULL, true); // vbc + // neisplitsub may be an infected one (it exists before split). + checksh = neisplitsub; + if (!shell2badface(checksh)) { + checksub4encroach(&checksh, NULL, true); // avd + } + // Get vbd. + senext(neisplitsub, checksh); + spivotself(checksh); + // vbd is newly created. + assert(checksh.sh != dummysh && !shell2badface(checksh)); + checksub4encroach(&checksh, NULL, true); // vbd + } else { + printf("Internal error in splitencsub(): Point %d locates %s.\n", + pointmark(newpoint), loc == ONVERTEX ? "on vertex" : "outside"); + internalerror(); + } + if (steinerleft > 0) steinerleft--; + // Recover Delaunay property by flipping. All existing subfaces + // which are encroached by the new point will be discovered + // during flips and be queued in list. + flip(flipqueue, NULL); + // There should be no encroached segments. + // assert(badsubsegs->items == 0); + // Queuing bad-quality tetrahedra if need. + if (badtetrahedrons != (memorypool *) NULL) { + doqualchecktetlist(); + } + } else { + // newpoint encroaches upon some segments. Rejected. + /* + if (bqual) { + // Re-queue this face to process it later. + badface *splitsub = encloop->ss; + encsub = (badface *) badsubfaces->alloc(); + encsub->ss = splitsub; + encsub->forg = sorg(splitsub); + encsub->fdest = sdest(splitsub); + encsub->fapex = sapex(splitsub); + encsub->foppo = encloop->foppo; + for (i = 0; i < 3; i++) encsub->cent[i] = newpoint[i]; + encsub->nextface = (badface *) NULL; + setshell2badface(encsub->ss, encsub); + // Add the subface to the end of a queue. + *subquetail[quenumber] = encsub; + // Maintain a pointer to the NULL pointer at the end of the queue. + subquetail[quenumber] = &encsub->nextface; + if (b->verbose > 2) { + printf(" Requeuing subface (%d, %d, %d) [%d].\n", + pointmark(encsub->forg), pointmark(encsub->fdest), + pointmark(encsub->fapex), quenumber); + } + } + */ + // Delete the newpoint. + pointdealloc(newpoint); + // Repair all the encroached segments. + if (badsubsegs->items > 0) { + repairencsegs(rpsarray, bqual, flipqueue); + } + } + } + } else { + // enq = false! This subface has been changed, check it again. + checksub4encroach(&splitsub, NULL, true); + } + // Remove this entry from list. + badfacedealloc(badsubfaces, encloop); + } +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// repairbadtets() Repair all bad-quality tetrahedra until no tetrahedron // +// is considered as bad-quality. // +// // +// At beginning, all bad-quality tetrahedra are stored in 'badtetrahedrons'. // +// Each bad tetrahedron is repaired by splitting it, i.e., inserting a point // +// at its circumcenter. However, if this point encroaches any subsegment or // +// subface, we do not add it and instead split the subsegment or subface. // +// Newly inserted points may create other bad-quality tetrahedra, these are // +// also repaired. // +// // +// After splitting a subface, the Delaunay property of the mesh is recovered // +// by flip operations. 'flipqueue' returns a list of updated faces and may // +// be non-locally Delaunay. // +// // +/////////////////////////////////////////////////////////////////////////////// + +void tetgenmesh::repairbadtets(REAL* rpsarray, int* idx2facetlist, + list* cavtetlist, queue* flipqueue) +{ + badtetrahedron *badtet; + triface starttet; + point newpoint; + point torg, tdest, tapex, toppo; + enum insertsiteresult success; + bool reject; + int i; + + // Loop until pool 'badtetrahedrons' is empty. Note that steinerleft == -1 + // if an unlimited number of Steiner points is allowed. + while ((badtetrahedrons->items > 0) && (steinerleft != 0)) { + badtet = dequeuebadtet(); + assert (badtet != (badtetrahedron *) NULL); + // Make sure that this tetrahedron is still the same tetrahedron it was + // when it was tested and determined to be of bad quality. Subsequent + // transformations may have made it a different tetrahedron. + if (!isdead(&badtet->tet) && org(badtet->tet) == badtet->tetorg && + dest(badtet->tet) == badtet->tetdest && + apex(badtet->tet) == badtet->tetapex && + oppo(badtet->tet) == badtet->tetoppo) { + // Create a newpoint at the circumcenter of this tetrahedron. + makepoint(&newpoint); + for (i = 0; i < 3; i++) newpoint[i] = badtet->cent[i]; + for (i = 0; i < in->numberofpointattributes; i++) newpoint[3 + i] = 0.0; + // Set it's type be FREEVOLVERTEX. + setpointtype(newpoint, FREEVOLVERTEX); + + // Look if the newpoint encroaches upon some segments, subfaces. + recenttet = badtet->tet; // Used for the input of preciselocate(). + collectcavtets(newpoint, cavtetlist); + assert(cavtetlist->len() > 0); + reject = tallencsegs(newpoint, cavtetlist); + if (!reject) { + reject = tallencsubs(newpoint, cavtetlist); + } + // Clear the list for the next use. + cavtetlist->clear(); + + if (!reject) { + // Insert the point, it should be always success. + starttet = badtet->tet; + success = insertsite(newpoint, &starttet, true, flipqueue); + if (success != DUPLICATEPOINT) { + if (steinerleft > 0) steinerleft--; + // Recover Delaunay property by flipping. + flip(flipqueue, NULL); + // Queuing bad-quality tetrahedra if need. + doqualchecktetlist(); + } else { + // !!! It's a bug!!! + pointdealloc(newpoint); + } + } else { + // newpoint encroaches upon some segments or subfaces. Rejected. + pointdealloc(newpoint); + if (badsubsegs->items > 0) { + // Repair all the encroached segments. + repairencsegs(rpsarray, false, flipqueue); + } + if (badsubfaces->items > 0) { + // Repair all the encroached subfaces. + repairencsubs(rpsarray, idx2facetlist, cavtetlist, flipqueue); + } + } + } + // Remove the bad-quality tetrahedron from the pool. + badtetrahedrons->dealloc((void *) badtet); + } +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// enforcequality() Remove all the encroached subsegments, subfaces and // +// bad tetrahedra from the tetrahedral mesh. // +// // +/////////////////////////////////////////////////////////////////////////////// + +void tetgenmesh::enforcequality() +{ + queue *flipqueue; + list *cavtetlist; + REAL *rpsarray; + int *idx2facetlist; + int i; + + if (!b->quiet) { + printf("Adding Steiner points to enforce quality.\n"); + } + + // Initialize working queues, lists. + flipqueue = new queue(sizeof(badface)); + cavtetlist = new list(sizeof(triface), NULL, 256); + rpsarray = new REAL[points->items]; + + // Mark segment vertices (acute or not) for determining segment types. + markacutevertices(89.0); + // Mark facets have sharp corners (for termination). + marksharpfacets(idx2facetlist, 89.0); + // Calculate the protecting spheres for all acute points. + initializerpsarray(rpsarray); + + // Initialize the pool of encroached subsegments. + badsubsegs = new memorypool(sizeof(badface), SUBPERBLOCK, POINTER, 0); + // Test all segments to see if they're encroached. + tallencsegs(NULL, NULL); + if (b->verbose && badsubsegs->items > 0) { + printf(" Splitting encroached subsegments.\n"); + } + // Fix encroached subsegments without noting any encr. subfaces. + repairencsegs(rpsarray, true, flipqueue); + + // Initialize the pool of encroached subfaces. + badsubfaces = new memorypool(sizeof(badface), SUBPERBLOCK, POINTER, 0); + // Initialize the queues of badfaces. + for (i = 0; i < 2; i++) subquefront[i] = (badface *) NULL; + for (i = 0; i < 2; i++) subquetail[i] = &subquefront[i]; + // Test all subfaces to see if they're encroached. + tallencsubs(NULL, NULL); + if (b->verbose && badsubfaces->items > 0) { + printf(" Splitting encroached subfaces.\n"); + } + // Fix encroached subfaces without noting bad tetrahedra. + repairencsubs(rpsarray, idx2facetlist, cavtetlist, flipqueue); + // At this point, the mesh should be (conforming) Delaunay. + + // Next, fix bad quality tetrahedra. + if ((b->minratio > 0.0) || b->varvolume || b->fixedvolume) { + // Initialize the pool of bad tetrahedra. + badtetrahedrons = new memorypool(sizeof(badtetrahedron), ELEPERBLOCK, + POINTER, 0); + // Initialize the list of bad tetrahedra. + qualchecktetlist = new list(sizeof(triface), NULL); + // Initialize the queues of bad tetrahedra. + for (i = 0; i < 64; i++) tetquefront[i] = (badtetrahedron *) NULL; + for (i = 0; i < 64; i++) tetquetail[i] = &tetquefront[i]; + // Test all tetrahedra to see if they're bad. + tallbadtetrahedrons(); + if (b->verbose && badtetrahedrons->items > 0) { + printf(" Splitting bad tetrahedra.\n"); + } + repairbadtets(rpsarray, idx2facetlist, cavtetlist, flipqueue); + // At this point, it should no bad quality tetrahedra. + delete qualchecktetlist; + delete badtetrahedrons; + } + + delete badsubfaces; + delete badsubsegs; + delete cavtetlist; + delete flipqueue; + delete [] idx2facetlist; + delete [] rpsarray; +} + +// +// End of Delaunay refinement routines +// + +// +// Begin of I/O rouitnes +// + +/////////////////////////////////////////////////////////////////////////////// +// // +// transfernodes() Transfer nodes from 'io->pointlist' to 'this->points'. // +// // +// Initializing 'this->points'. Transferring all points from 'in->pointlist'// +// into it. All points are indexed (start from in->firstnumber). Each point // +// is initialized be UNUSEDVERTEX. The bounding box (xmin, xmax, ymin, ymax,// +// zmin, zmax) and the diameter (longest) of the point set are calculated. // +// // +/////////////////////////////////////////////////////////////////////////////// + +void tetgenmesh::transfernodes() +{ + point pointloop; + REAL x, y, z; + int coordindex; + int attribindex; + int i, j; + + // Read the points. + coordindex = 0; + attribindex = 0; + for (i = 0; i < in->numberofpoints; i++) { + makepoint(&pointloop); + // Read the point coordinates. + x = pointloop[0] = in->pointlist[coordindex++]; + y = pointloop[1] = in->pointlist[coordindex++]; + z = pointloop[2] = in->pointlist[coordindex++]; + // Read the point attributes. + for (j = 0; j < in->numberofpointattributes; j++) { + pointloop[3 + j] = in->pointattributelist[attribindex++]; + } + // Determine the smallest and largests x, y and z coordinates. + if (i == 0) { + xmin = xmax = x; + ymin = ymax = y; + zmin = zmax = z; + } else { + xmin = (x < xmin) ? x : xmin; + xmax = (x > xmax) ? x : xmax; + ymin = (y < ymin) ? y : ymin; + ymax = (y > ymax) ? y : ymax; + zmin = (z < zmin) ? z : zmin; + zmax = (z > zmax) ? z : zmax; + } + } + // 'longest' is the largest possible edge length formed by input vertices. + // It is used as the measure to distinguish two identical points. + x = xmax - xmin; + y = ymax - ymin; + z = zmax - zmin; + longest = sqrt(x * x + y * y + z * z); + if (longest == 0.0) { + printf("Error: The point set is trivial.\n"); + exit(1); + } +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// jettisonnodes() Jettison unused or duplicated vertices. // +// // +// Unused points are those input points which are outside the mesh domain or // +// have no connection (isolated) to the mesh. Duplicated points exist for // +// example if the input PLC is read from a .stl mesh file (marked during the // +// Delaunay tetrahedralization step. This routine remove these points from // +// points list. All existing points are reindexed. // +// // +/////////////////////////////////////////////////////////////////////////////// + +void tetgenmesh::jettisonnodes() +{ + point pointloop; + bool jetflag; + int idx; + + if (!b->quiet) { + printf("Jettisoning redundants points.\n"); + } + + points->traversalinit(); + pointloop = pointtraverse(); + idx = in->firstnumber; + while (pointloop != (point) NULL) { + jetflag = (pointtype(pointloop) == DUPLICATEDVERTEX) || + (pointtype(pointloop) == UNUSEDVERTEX); + if (jetflag) { + // It is a duplicated point, delete it. + pointdealloc(pointloop); + } else { + // Index it. + setpointmark(pointloop, idx); + idx++; + } + pointloop = pointtraverse(); + } +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// highorder() Create extra nodes for quadratic subparametric elements. // +// // +// 'highordertable' is an array (size = numberoftetrahedra * 6) for storing // +// high-order nodes of each tetrahedron. This routine is used only when -o2 // +// switch is used. // +// // +/////////////////////////////////////////////////////////////////////////////// + +void tetgenmesh::highorder() +{ + triface tetloop, worktet; + triface spintet, adjtet; + point torg, tdest, tapex; + point *extralist, *adjextralist; + point newpoint; + int hitbdry, ptmark; + int i, j; + + // The 'edgeindex' (from 0 to 5) is list as follows: + // 0 - (v0, v1), 1 - (v1, v2), 2 - (v2, v0) + // 3 - (v3, v0), 4 - (v3, v1), 5 - (v3, v2) + // Define an edgeindex map: (loc, ver)->edgeindex. + int edgeindexmap[4][6] = {0, 0, 1, 1, 2, 2, + 3, 3, 4, 4, 0, 0, + 4, 4, 5, 5, 1, 1, + 5, 5, 3, 3, 2, 2}; + + if (!b->quiet) { + printf("Adding vertices for second-order tetrahedra.\n"); + } + + // Initialize the 'highordertable'. + highordertable = new point[tetrahedrons->items * 6]; + if (highordertable == (point *) NULL) { + printf("Error: Out of memory.\n"); + exit(1); + } + + // The following line ensures that dead items in the pool of nodes cannot + // be allocated for the extra nodes associated with high order elements. + // This ensures that the primary nodes (at the corners of elements) will + // occur earlier in the output files, and have lower indices, than the + // extra nodes. + points->deaditemstack = (void *) NULL; + + // Assign an entry for each tetrahedron to find its extra nodes. At the + // mean while, initialize all extra nodes be NULL. + i = 0; + tetrahedrons->traversalinit(); + tetloop.tet = tetrahedrontraverse(); + while (tetloop.tet != (tetrahedron *) NULL) { + tetloop.tet[highorderindex] = (tetrahedron) &highordertable[i]; + for (j = 0; j < 6; j++) { + highordertable[i + j] = (point) NULL; + } + i += 6; + tetloop.tet = tetrahedrontraverse(); + } + + // To create a unique node on each edge. Loop over all tetrahedra, and + // look at the six edges of each tetrahedron. If the extra node in + // the tetrahedron corresponding to this edge is NULL, create a node + // for this edge, at the same time, set the new node into the extra + // node lists of all other tetrahedra sharing this edge. + tetrahedrons->traversalinit(); + tetloop.tet = tetrahedrontraverse(); + while (tetloop.tet != (tetrahedron *) NULL) { + // Get the list of extra nodes. + extralist = (point *) tetloop.tet[highorderindex]; + for (i = 0; i < 6; i++) { + if (extralist[i] == (point) NULL) { + // Operate on this edge. + worktet = tetloop; + worktet.loc = 0; worktet.ver = 0; + // Get the correct edge in 'worktet'. + switch(i) { + case 0: // (v0, v1) + break; + case 1: // (v1, v2) + enextself(worktet); + break; + case 2: // (v2, v0) + enext2self(worktet); + break; + case 3: // (v3, v0) + fnextself(worktet); + enext2self(worktet); + break; + case 4: // (v3, v1) + enextself(worktet); + fnextself(worktet); + enext2self(worktet); + break; + case 5: // (v3, v2) + enext2self(worktet); + fnextself(worktet); + enext2self(worktet); + } + // Create a new node on this edge. + torg = org(worktet); + tdest = dest(worktet); + // Create a new node in the middle of the edge. + newpoint = (point) points->alloc(); + // Interpolate its attributes. + for (j = 0; j < 3 + in->numberofpointattributes; j++) { + newpoint[j] = 0.5 * (torg[j] + tdest[j]); + } + ptmark = (int) points->items - (in->firstnumber == 1 ? 0 : 1); + setpointmark(newpoint, ptmark); + // Add this node to its extra node list. + extralist[i] = newpoint; + // Set 'newpoint' into extra node lists of other tetrahedra + // sharing this edge. + tapex = apex(worktet); + spintet = worktet; + hitbdry = 0; + while (hitbdry < 2) { + if (fnextself(spintet)) { + // Get the extra node list of 'spintet'. + adjextralist = (point *) spintet.tet[highorderindex]; + // Find the index of its extra node list. + j = edgeindexmap[spintet.loc][spintet.ver]; + // Only set 'newpoint' into 'adjextralist' if it is a NULL. + // Because two faces can belong to the same tetrahedron. + if (adjextralist[j] == (point) NULL) { + adjextralist[j] = newpoint; + } + if (apex(spintet) == tapex) { + break; + } + } else { + hitbdry++; + if (hitbdry < 2) { + esym(worktet, spintet); + } + } + } + } + } + tetloop.tet = tetrahedrontraverse(); + } +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// outnodes() Output the points to a .node file or a tetgenio structure. // +// // +// Note: each point has already been numbered on input (the first index is // +// 'in->firstnumber'). // +// // +/////////////////////////////////////////////////////////////////////////////// + +void tetgenmesh::outnodes(tetgenio* out) +{ + FILE *outfile; + char outnodefilename[FILENAMESIZE]; + point pointloop; + int nextras, bmark, marker; + int coordindex, attribindex; + int pointnumber, index, i; + + if (out == (tetgenio *) NULL) { + strcpy(outnodefilename, b->outfilename); + strcat(outnodefilename, ".node"); + } + + if (!b->quiet) { + if (out == (tetgenio *) NULL) { + printf("Writing %s.\n", outnodefilename); + } else { + printf("Writing nodes.\n"); + } + } + + nextras = in->numberofpointattributes; + bmark = !b->nobound && in->pointmarkerlist; + + if (out == (tetgenio *) NULL) { + outfile = fopen(outnodefilename, "w"); + if (outfile == (FILE *) NULL) { + printf("File I/O Error: Cannot create file %s.\n", outnodefilename); + exit(1); + } + // Number of points, number of dimensions, number of point attributes, + // and number of boundary markers (zero or one). + fprintf(outfile, "%ld %d %d %d\n", points->items, 3, nextras, bmark); + } else { + // Allocate space for 'pointlist'; + out->pointlist = new REAL[points->items * 3]; + if (out->pointlist == (REAL *) NULL) { + printf("Error: Out of memory.\n"); + exit(1); + } + // Allocate space for 'pointattributelist' if necessary; + if (nextras > 0) { + out->pointattributelist = new REAL[points->items * nextras]; + if (out->pointattributelist == (REAL *) NULL) { + printf("Error: Out of memory.\n"); + exit(1); + } + } + // Allocate space for 'pointmarkerlist' if necessary; + if (bmark) { + out->pointmarkerlist = new int[points->items]; + if (out->pointmarkerlist == (int *) NULL) { + printf("Error: Out of memory.\n"); + exit(1); + } + } + out->numberofpoints = points->items; + out->numberofpointattributes = nextras; + coordindex = 0; + attribindex = 0; + } + + points->traversalinit(); + pointloop = pointtraverse(); + pointnumber = in->firstnumber; + index = 0; + while (pointloop != (point) NULL) { + if (bmark) { + // Determine the boundary marker. + if (index < in->numberofpoints) { + // Input point's marker is directly copied to output. + marker = in->pointmarkerlist[index]; + if (marker == 0) { + // Change the marker if it is a boundary point. + marker = ((pointtype(pointloop) != UNUSEDVERTEX) && + (pointtype(pointloop) != FREEVOLVERTEX) && + (pointtype(pointloop) != DUPLICATEDVERTEX)) + ? 1 : 0; + } + } else if ((pointtype(pointloop) != UNUSEDVERTEX) && + (pointtype(pointloop) != FREEVOLVERTEX) && + (pointtype(pointloop) != DUPLICATEDVERTEX)) { + // A boundary vertex has marker 1. + marker = 1; + } else { + // Free or internal point has a zero marker. + marker = 0; + } + } + if (out == (tetgenio *) NULL) { + // Point number, x, y and z coordinates. + fprintf(outfile, "%4d %.17g %.17g %.17g", pointnumber, + pointloop[0], pointloop[1], pointloop[2]); + for (i = 0; i < nextras; i++) { + // Write an attribute. + fprintf(outfile, " %.17g", pointloop[3 + i]); + } + if (bmark) { + // Write the boundary marker. + fprintf(outfile, " %d", marker); + } + fprintf(outfile, "\n"); + } else { + // X, y, and z coordinates. + out->pointlist[coordindex++] = pointloop[0]; + out->pointlist[coordindex++] = pointloop[1]; + out->pointlist[coordindex++] = pointloop[2]; + // Point attributes. + for (i = 0; i < nextras; i++) { + // Output an attribute. + out->pointattributelist[attribindex++] = pointloop[3 + i]; + } + if (bmark) { + // Output the boundary marker. + out->pointmarkerlist[index] = marker; + } + } + pointloop = pointtraverse(); + pointnumber++; + index++; + } + + if (out == (tetgenio *) NULL) { + fprintf(outfile, "# Generated by %s\n", b->commandline); + fclose(outfile); + } +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// outelements() Output the tetrahedra to an .ele file or a tetgenio // +// structure. // +// // +/////////////////////////////////////////////////////////////////////////////// + +void tetgenmesh::outelements(tetgenio* out) +{ + FILE *outfile; + char outelefilename[FILENAMESIZE]; + tetrahedron* tptr; + int *tlist; + REAL *talist; + int pointindex; + int attribindex; + point p1, p2, p3, p4; + point *extralist; + int elementnumber; + int eextras; + int i; + + if (out == (tetgenio *) NULL) { + strcpy(outelefilename, b->outfilename); + strcat(outelefilename, ".ele"); + } + + if (!b->quiet) { + if (out == (tetgenio *) NULL) { + printf("Writing %s.\n", outelefilename); + } else { + printf("Writing elements.\n"); + } + } + + eextras = in->numberoftetrahedronattributes; + if (out == (tetgenio *) NULL) { + outfile = fopen(outelefilename, "w"); + if (outfile == (FILE *) NULL) { + printf("File I/O Error: Cannot create file %s.\n", outelefilename); + exit(1); + } + // Number of tetras, points per tetra, attributes per tetra. + fprintf(outfile, "%ld %d %d\n", tetrahedrons->items, + b->order == 1 ? 4 : 10, eextras); + } else { + // Allocate memory for output tetrahedra. + out->tetrahedronlist = new int[tetrahedrons->items * + (b->order == 1 ? 4 : 10)]; + if (out->tetrahedronlist == (int *) NULL) { + printf("Error: Out of memory.\n"); + exit(1); + } + // Allocate memory for output tetrahedron attributes if necessary. + if (eextras > 0) { + out->tetrahedronattributelist = new REAL[tetrahedrons->items * eextras]; + if (out->tetrahedronattributelist == (REAL *) NULL) { + printf("Error: Out of memory.\n"); + exit(1); + } + } + out->numberoftetrahedra = tetrahedrons->items; + out->numberofcorners = b->order == 1 ? 4 : 10; + out->numberoftetrahedronattributes = eextras; + tlist = out->tetrahedronlist; + talist = out->tetrahedronattributelist; + pointindex = 0; + attribindex = 0; + } + + tetrahedrons->traversalinit(); + tptr = tetrahedrontraverse(); + elementnumber = in->firstnumber; + while (tptr != (tetrahedron *) NULL) { + p1 = (point) tptr[4]; + p2 = (point) tptr[5]; + p3 = (point) tptr[6]; + p4 = (point) tptr[7]; + if (out == (tetgenio *) NULL) { + // Tetrahedron number, indices for four points. + fprintf(outfile, "%5d %5d %5d %5d %5d", elementnumber, + pointmark(p1), pointmark(p2), pointmark(p3), pointmark(p4)); + if (b->order == 2) { + extralist = (point *) tptr[highorderindex]; + // Tetrahedron number, indices for four points plus six extra points. + fprintf(outfile, " %5d %5d %5d %5d %5d %5d", + pointmark(extralist[0]), pointmark(extralist[1]), + pointmark(extralist[2]), pointmark(extralist[3]), + pointmark(extralist[4]), pointmark(extralist[5])); + } + for (i = 0; i < eextras; i++) { + fprintf(outfile, " %.17g", elemattribute(tptr, i)); + } + fprintf(outfile, "\n"); + } else { + tlist[pointindex++] = pointmark(p1); + tlist[pointindex++] = pointmark(p2); + tlist[pointindex++] = pointmark(p3); + tlist[pointindex++] = pointmark(p4); + if (b->order == 2) { + extralist = (point *) tptr[highorderindex]; + tlist[pointindex++] = pointmark(extralist[0]); + tlist[pointindex++] = pointmark(extralist[1]); + tlist[pointindex++] = pointmark(extralist[2]); + tlist[pointindex++] = pointmark(extralist[3]); + tlist[pointindex++] = pointmark(extralist[4]); + tlist[pointindex++] = pointmark(extralist[5]); + } + for (i = 0; i < eextras; i++) { + talist[attribindex++] = elemattribute(tptr, i); + } + } + tptr = tetrahedrontraverse(); + elementnumber++; + } + + if (out == (tetgenio *) NULL) { + fprintf(outfile, "# Generated by %s\n", b->commandline); + fclose(outfile); + } +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// outfaces() Output all faces to a .face file or a tetgenio structure. // +// // +// This routines outputs all triangular faces (including outer boundary // +// faces and inner faces) of this mesh. // +// // +/////////////////////////////////////////////////////////////////////////////// + +void tetgenmesh::outfaces(tetgenio* out) +{ + FILE *outfile; + char facefilename[FILENAMESIZE]; + int *elist; + int *emlist; + int index; + triface tface, tsymface; + face checkmark; + point torg, tdest, tapex; + long faces; + int bmark, faceid, marker; + int facenumber; + + if (out == (tetgenio *) NULL) { + strcpy(facefilename, b->outfilename); + strcat(facefilename, ".face"); + } + + if (!b->quiet) { + if (out == (tetgenio *) NULL) { + printf("Writing %s.\n", facefilename); + } else { + printf("Writing faces.\n"); + } + } + + faces = (4l * tetrahedrons->items + hullsize) / 2l; + bmark = !b->nobound && in->facetmarkerlist; + + if (out == (tetgenio *) NULL) { + outfile = fopen(facefilename, "w"); + if (outfile == (FILE *) NULL) { + printf("File I/O Error: Cannot create file %s.\n", facefilename); + exit(1); + } + fprintf(outfile, "%ld %d\n", faces, bmark); + } else { + // Allocate memory for 'trifacelist'. + out->trifacelist = new int[faces * 3]; + if (out->trifacelist == (int *) NULL) { + printf("Error: Out of memory.\n"); + exit(1); + } + // Allocate memory for 'trifacemarkerlist' if necessary. + if (bmark) { + out->trifacemarkerlist = new int[faces]; + if (out->trifacemarkerlist == (int *) NULL) { + printf("Error: Out of memory.\n"); + exit(1); + } + } + out->numberoftrifaces = faces; + elist = out->trifacelist; + emlist = out->trifacemarkerlist; + index = 0; + } + + tetrahedrons->traversalinit(); + tface.tet = tetrahedrontraverse(); + facenumber = in->firstnumber; + // To loop over the set of faces, loop over all tetrahedra, and look at + // the four faces of each one. If there isn't another tetrahedron + // adjacent to this face, operate on the face. If there is another + // adjacent tetrahedron, operate on the face only if the current + // tetrahedron has a smaller pointer than its neighbor. This way, each + // face is considered only once. + while (tface.tet != (tetrahedron *) NULL) { + for (tface.loc = 0; tface.loc < 4; tface.loc ++) { + sym(tface, tsymface); + if ((tsymface.tet == dummytet) || (tface.tet < tsymface.tet)) { + torg = org(tface); + tdest = dest(tface); + tapex = apex(tface); + if (bmark) { + // Get the boundary marker of this face. If it is an inner face, + // it has no boundary marker, set it be zero. + if (b->useshelles) { + // Shell face is used. + tspivot(tface, checkmark); + if (checkmark.sh == dummysh) { + marker = 0; // It is an inner face. + } else { + faceid = shellmark(checkmark) - 1; + marker = in->facetmarkerlist[faceid]; + } + } else { + // Shell face is not used, only distinguish outer and inner face. + marker = tsymface.tet != dummytet ? 1 : 0; + } + } + if (out == (tetgenio *) NULL) { + // Face number, indices of three vertices. + fprintf(outfile, "%5d %4d %4d %4d", facenumber, + pointmark(torg), pointmark(tdest), pointmark(tapex)); + if (bmark) { + // Output a boundary marker. + fprintf(outfile, " %d", marker); + } + fprintf(outfile, "\n"); + } else { + // Output indices of three vertices. + elist[index++] = pointmark(torg); + elist[index++] = pointmark(tdest); + elist[index++] = pointmark(tapex); + if (bmark) { + emlist[facenumber - in->firstnumber] = marker; + } + } + facenumber++; + } + } + tface.tet = tetrahedrontraverse(); + } + + if (out == (tetgenio *) NULL) { + fprintf(outfile, "# Generated by %s\n", b->commandline); + fclose(outfile); + } +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// outhullfaces() Output outer boundary faces to a .face file or a // +// tetgenio structure. // +// // +// The normal of each face is arranged to point inside of the domain (use // +// right-hand rule). This routines will outputs convex hull faces if the // +// mesh is a Delaunay tetrahedralization. // +// // +/////////////////////////////////////////////////////////////////////////////// + +void tetgenmesh::outhullfaces(tetgenio* out) +{ + FILE *outfile; + char facefilename[FILENAMESIZE]; + int *elist; + int index; + triface tface, tsymface; + face checkmark; + point torg, tdest, tapex; + int facenumber; + + if (out == (tetgenio *) NULL) { + strcpy(facefilename, b->outfilename); + strcat(facefilename, ".face"); + } + + if (!b->quiet) { + if (out == (tetgenio *) NULL) { + printf("Writing %s.\n", facefilename); + } else { + printf("Writing faces.\n"); + } + } + + if (out == (tetgenio *) NULL) { + outfile = fopen(facefilename, "w"); + if (outfile == (FILE *) NULL) { + printf("File I/O Error: Cannot create file %s.\n", facefilename); + exit(1); + } + fprintf(outfile, "%ld 0\n", hullsize); + } else { + // Allocate memory for 'trifacelist'. + out->trifacelist = new int[hullsize * 3]; + if (out->trifacelist == (int *) NULL) { + printf("Error: Out of memory.\n"); + exit(1); + } + out->numberoftrifaces = hullsize; + elist = out->trifacelist; + index = 0; + } + + tetrahedrons->traversalinit(); + tface.tet = tetrahedrontraverse(); + facenumber = in->firstnumber; + // To loop over the set of hull faces, loop over all tetrahedra, and look + // at the four faces of each one. If there isn't another tetrahedron + // adjacent to this face, operate on the face. + while (tface.tet != (tetrahedron *) NULL) { + for (tface.loc = 0; tface.loc < 4; tface.loc ++) { + sym(tface, tsymface); + if (tsymface.tet == dummytet) { + torg = org(tface); + tdest = dest(tface); + tapex = apex(tface); + if (out == (tetgenio *) NULL) { + // Face number, indices of three vertices. + fprintf(outfile, "%5d %4d %4d %4d", facenumber, + pointmark(torg), pointmark(tdest), pointmark(tapex)); + fprintf(outfile, "\n"); + } else { + // Output indices of three vertices. + elist[index++] = pointmark(torg); + elist[index++] = pointmark(tdest); + elist[index++] = pointmark(tapex); + } + facenumber++; + } + } + tface.tet = tetrahedrontraverse(); + } + + if (out == (tetgenio *) NULL) { + fprintf(outfile, "# Generated by %s\n", b->commandline); + fclose(outfile); + } +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// outsubfaces() Output subfaces (i.e. boundary faces) to a .face file or // +// a tetgenio structure. // +// // +// The boundary faces are exist in 'subfaces'. For listing triangle vertices // +// in the same sense for all triangles in the mesh, the direction determined // +// by right-hand rule is pointer to the inside of the volume. // +// // +/////////////////////////////////////////////////////////////////////////////// + +void tetgenmesh::outsubfaces(tetgenio* out) +{ + FILE *outfile; + char facefilename[FILENAMESIZE]; + int *elist; + int *emlist; + int index; + triface abuttingtet; + face faceloop; + point torg, tdest, tapex; + int bmark, faceid, marker; + int facenumber; + + if (out == (tetgenio *) NULL) { + strcpy(facefilename, b->outfilename); + strcat(facefilename, ".face"); + } + + if (!b->quiet) { + if (out == (tetgenio *) NULL) { + printf("Writing %s.\n", facefilename); + } else { + printf("Writing faces.\n"); + } + } + + bmark = !b->nobound && in->facetmarkerlist; + + if (out == (tetgenio *) NULL) { + outfile = fopen(facefilename, "w"); + if (outfile == (FILE *) NULL) { + printf("File I/O Error: Cannot create file %s.\n", facefilename); + exit(1); + } + // Number of subfaces. + fprintf(outfile, "%ld %d\n", subfaces->items, bmark); + } else { + // Allocate memory for 'trifacelist'. + out->trifacelist = new int[subfaces->items * 3]; + if (out->trifacelist == (int *) NULL) { + printf("Error: Out of memory.\n"); + exit(1); + } + // Allocate memory for 'trifacemarkerlist', if necessary. + if (bmark) { + out->trifacemarkerlist = new int[subfaces->items]; + if (out->trifacemarkerlist == (int *) NULL) { + printf("Error: Out of memory.\n"); + exit(1); + } + } + out->numberoftrifaces = subfaces->items; + elist = out->trifacelist; + emlist = out->trifacemarkerlist; + index = 0; + } + + subfaces->traversalinit(); + faceloop.sh = shellfacetraverse(subfaces); + facenumber = in->firstnumber; + while (faceloop.sh != (shellface *) NULL) { + stpivot(faceloop, abuttingtet); + if (abuttingtet.tet == dummytet) { + sesymself(faceloop); + stpivot(faceloop, abuttingtet); + // assert(abuttingtet.tet != dummytet) { + } + if (abuttingtet.tet != dummytet) { + // If there is a tetrahedron containing this subface, orient it so + // that the normal of this face points to inside of the volume by + // right-hand rule. + adjustedgering(abuttingtet, CCW); + torg = org(abuttingtet); + tdest = dest(abuttingtet); + tapex = apex(abuttingtet); + } else { + // This may happen when only a surface mesh be generated. + torg = sorg(faceloop); + tdest = sdest(faceloop); + tapex = sapex(faceloop); + } + if (bmark) { + faceid = shellmark(faceloop) - 1; + marker = in->facetmarkerlist[faceid]; + } + if (out == (tetgenio *) NULL) { + fprintf(outfile, "%5d %4d %4d %4d", facenumber, + pointmark(torg), pointmark(tdest), pointmark(tapex)); + if (bmark) { + fprintf(outfile, " %d", marker); + } + fprintf(outfile, "\n"); + } else { + // Output three vertices of this face; + elist[index++] = pointmark(torg); + elist[index++] = pointmark(tdest); + elist[index++] = pointmark(tapex); + if (bmark) { + emlist[facenumber - in->firstnumber] = marker; + } + } + facenumber++; + faceloop.sh = shellfacetraverse(subfaces); + } + + if (out == (tetgenio *) NULL) { + fprintf(outfile, "# Generated by %s\n", b->commandline); + fclose(outfile); + } +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// outsubsegments() Output segments (i.e. boundary edges) to a .edge file // +// or a tetgenio structure. // +// // +// The boundary edges are stored in 'subsegs'. // +// // +/////////////////////////////////////////////////////////////////////////////// + +void tetgenmesh::outsubsegments(tetgenio* out) +{ + FILE *outfile; + char edgefilename[FILENAMESIZE]; + int *elist; + int index; + face edgeloop; + point torg, tdest; + int edgenumber; + + if (out == (tetgenio *) NULL) { + strcpy(edgefilename, b->outfilename); + strcat(edgefilename, ".edge"); + } + + if (!b->quiet) { + if (out == (tetgenio *) NULL) { + printf("Writing %s.\n", edgefilename); + } else { + printf("Writing faces.\n"); + } + } + + if (out == (tetgenio *) NULL) { + outfile = fopen(edgefilename, "w"); + if (outfile == (FILE *) NULL) { + printf("File I/O Error: Cannot create file %s.\n", edgefilename); + exit(1); + } + // Number of subsegments. + fprintf(outfile, "%ld\n", subsegs->items); + } else { + // Allocate memory for 'edgelist'. + out->edgelist = new int[subsegs->items * 2]; + if (out->edgelist == (int *) NULL) { + printf("Error: Out of memory.\n"); + exit(1); + } + out->numberofedges = subsegs->items; + elist = out->edgelist; + index = 0; + } + + subsegs->traversalinit(); + edgeloop.sh = shellfacetraverse(subsegs); + edgenumber = in->firstnumber; + while (edgeloop.sh != (shellface *) NULL) { + torg = sorg(edgeloop); + tdest = sdest(edgeloop); + if (out == (tetgenio *) NULL) { + fprintf(outfile, "%5d %4d %4d\n", edgenumber, pointmark(torg), + pointmark(tdest)); + } else { + // Output three vertices of this face; + elist[index++] = pointmark(torg); + elist[index++] = pointmark(tdest); + } + edgenumber++; + edgeloop.sh = shellfacetraverse(subsegs); + } + + if (out == (tetgenio *) NULL) { + fprintf(outfile, "# Generated by %s\n", b->commandline); + fclose(outfile); + } +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// outneighbors() Output a list of neighbors to a .neigh file or a // +// tetgenio structure. // +// // +/////////////////////////////////////////////////////////////////////////////// + +void tetgenmesh::outneighbors(tetgenio* out) +{ + FILE *outfile; + char neighborfilename[FILENAMESIZE]; + int *nlist; + int index; + tetrahedron *tptr; + triface tetloop, tetsym; + int neighbor1, neighbor2, neighbor3, neighbor4; + int elementnumber; + + if (out == (tetgenio *) NULL) { + strcpy(neighborfilename, b->outfilename); + strcat(neighborfilename, ".neigh"); + } + + if (!b->quiet) { + if (out == (tetgenio *) NULL) { + printf("Writing %s.\n", neighborfilename); + } else { + printf("Writing neighbors.\n"); + } + } + + if (out == (tetgenio *) NULL) { + outfile = fopen(neighborfilename, "w"); + if (outfile == (FILE *) NULL) { + printf("File I/O Error: Cannot create file %s.\n", neighborfilename); + exit(1); + } + // Number of tetrahedra, four faces per tetrahedron. + fprintf(outfile, "%ld %d\n", tetrahedrons->items, 4); + } else { + // Allocate memory for 'neighborlist'. + out->neighborlist = new int[tetrahedrons->items * 4]; + if (out->neighborlist == (int *) NULL) { + printf("Error: Out of memory.\n"); + exit(1); + } + nlist = out->neighborlist; + index = 0; + } + + tetrahedrons->traversalinit(); + tptr = tetrahedrontraverse(); + elementnumber = in->firstnumber; + while (tptr != (tetrahedron *) NULL) { + * (int *) (tptr + 8) = elementnumber; + tptr = tetrahedrontraverse(); + elementnumber++; + } + * (int *) (dummytet + 8) = -1; + + tetrahedrons->traversalinit(); + tetloop.tet = tetrahedrontraverse(); + elementnumber = in->firstnumber; + while (tetloop.tet != (tetrahedron *) NULL) { + tetloop.loc = 2; + sym(tetloop, tetsym); + neighbor1 = * (int *) (tetsym.tet + 8); + tetloop.loc = 3; + sym(tetloop, tetsym); + neighbor2 = * (int *) (tetsym.tet + 8); + tetloop.loc = 1; + sym(tetloop, tetsym); + neighbor3 = * (int *) (tetsym.tet + 8); + tetloop.loc = 0; + sym(tetloop, tetsym); + neighbor4 = * (int *) (tetsym.tet + 8); + if (out == (tetgenio *) NULL) { + // Tetrahedra number, neighboring tetrahedron numbers. + fprintf(outfile, "%4d %4d %4d %4d %4d\n", elementnumber, + neighbor1, neighbor2, neighbor3, neighbor4); + } else { + nlist[index++] = neighbor1; + nlist[index++] = neighbor2; + nlist[index++] = neighbor3; + nlist[index++] = neighbor4; + } + tetloop.tet = tetrahedrontraverse(); + elementnumber++; + } + + if (out == (tetgenio *) NULL) { + fprintf(outfile, "# Generated by %s\n", b->commandline); + fclose(outfile); + } +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// outsmesh() Write surface mesh to a .smesh file, which can be read and // +// tetrahedralized by TetGen. // +// // +// You can specify a filename (without suffix) in 'smfilename'. If you don't // +// supply a filename (let smfilename be NULL), the default name stored in // +// 'tetgenbehavior' will be used. // +// // +/////////////////////////////////////////////////////////////////////////////// + +void tetgenmesh::outsmesh(char* smfilename) +{ + FILE *outfile; + char smefilename[FILENAMESIZE]; + face faceloop; + point pointloop; + point p1, p2, p3; + int pointnumber; + int nextras, bmark; + int faceid, marker; + + if (smfilename != (char *) NULL && smfilename[0] != '\0') { + strcpy(smefilename, smfilename); + } else if (b->outfilename[0] != '\0') { + strcpy(smefilename, b->outfilename); + } else { + strcpy(smefilename, "unnamed"); + } + strcat(smefilename, ".smesh"); + + if (!b->quiet) { + printf("Writing %s.\n", smefilename); + } + outfile = fopen(smefilename, "w"); + if (outfile == (FILE *) NULL) { + printf("File I/O Error: Cannot create file %s.\n", smefilename); + return; + } + + fprintf(outfile, "# %s. TetGen's input file.\n", smefilename); + + nextras = in->numberofpointattributes; + bmark = !b->nobound && in->pointmarkerlist; + + fprintf(outfile, "\n# part 1: node list.\n"); + // Number of points, number of dimensions, number of point attributes, + // and number of boundary markers (zero or one). + fprintf(outfile, "%ld %d %d %d\n", points->items, 3, nextras, bmark); + + points->traversalinit(); + pointloop = pointtraverse(); + pointnumber = in->firstnumber; + while (pointloop != (point) NULL) { + // Point coordinates. + fprintf(outfile, "%4d %.17g %.17g %.17g", pointnumber, + pointloop[0], pointloop[1], pointloop[2]); + if (in->numberofpointattributes > 0) { + // Write an attribute, ignore others if more than one. + fprintf(outfile, " %.17g", pointloop[3]); + } + fprintf(outfile, "\n"); + setpointmark(pointloop, pointnumber); + pointloop = pointtraverse(); + pointnumber++; + } + + bmark = !b->nobound && in->facetmarkerlist; + + fprintf(outfile, "\n# part 2: facet list.\n"); + // Number of facets, boundary marker. + fprintf(outfile, "%ld %d\n", subfaces->items, bmark); + + subfaces->traversalinit(); + faceloop.sh = shellfacetraverse(subfaces); + while (faceloop.sh != (shellface *) NULL) { + p1 = sorg(faceloop); + p2 = sdest(faceloop); + p3 = sapex(faceloop); + if (bmark) { + faceid = shellmark(faceloop) - 1; + marker = in->facetmarkerlist[faceid]; + } + fprintf(outfile, "3 %4d %4d %4d", pointmark(p1), pointmark(p2), + pointmark(p3)); + if (bmark) { + fprintf(outfile, " %d", marker); + } + fprintf(outfile, "\n"); + faceloop.sh = shellfacetraverse(subfaces); + } + + fprintf(outfile, "\n# part 3: hole list.\n"); + fprintf(outfile, "0\n"); + + fprintf(outfile, "\n# part 4: region list.\n"); + fprintf(outfile, "0\n"); + + fprintf(outfile, "# Generated by %s\n", b->commandline); + fclose(outfile); +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// outmesh2medit() Write mesh to a .mesh file, which can be read and // +// rendered by Medit (a free mesh viewer from INRIA). // +// // +// You can specify a filename (without suffix) in 'mfilename'. If you don't // +// supply a filename (let mfilename be NULL), the default name stored in // +// 'tetgenbehavior' will be used. The output file will have the suffix .mesh.// +// // +/////////////////////////////////////////////////////////////////////////////// + +void tetgenmesh::outmesh2medit(char* mfilename) +{ + FILE *outfile; + char mefilename[FILENAMESIZE]; + tetrahedron* tetptr; + triface tface, tsymface; + face segloop, checkmark; + point pointloop, p1, p2, p3, p4; + long faces; + int pointnumber; + int i; + + if (mfilename != (char *) NULL && mfilename[0] != '\0') { + strcpy(mefilename, mfilename); + } else if (b->outfilename[0] != '\0') { + strcpy(mefilename, b->outfilename); + } else { + strcpy(mefilename, "unnamed"); + } + strcat(mefilename, ".mesh"); + + if (!b->quiet) { + printf("Writing %s.\n", mefilename); + } + outfile = fopen(mefilename, "w"); + if (outfile == (FILE *) NULL) { + printf("File I/O Error: Cannot create file %s.\n", mefilename); + return; + } + + fprintf(outfile, "MeshVersionFormatted 1\n"); + fprintf(outfile, "\n"); + fprintf(outfile, "Dimension\n"); + fprintf(outfile, "3\n"); + fprintf(outfile, "\n"); + + fprintf(outfile, "\n# Set of mesh vertices\n"); + fprintf(outfile, "Vertices\n"); + fprintf(outfile, "%ld\n", points->items); + + points->traversalinit(); + pointloop = pointtraverse(); + pointnumber = 1; // Medit need start number form 1. + while (pointloop != (point) NULL) { + // Point coordinates. + fprintf(outfile, "%.17g %.17g %.17g", + pointloop[0], pointloop[1], pointloop[2]); + if (in->numberofpointattributes > 0) { + // Write an attribute, ignore others if more than one. + fprintf(outfile, " %.17g\n", pointloop[3]); + } else { + fprintf(outfile, " 0\n"); + } + setpointmark(pointloop, pointnumber); + pointloop = pointtraverse(); + pointnumber++; + } + + // Compute the number of edges. + faces = (4l * tetrahedrons->items + hullsize) / 2l; + + fprintf(outfile, "\n# Set of Triangles\n"); + fprintf(outfile, "Triangles\n"); + fprintf(outfile, "%ld\n", faces); + + tetrahedrons->traversalinit(); + tface.tet = tetrahedrontraverse(); + // To loop over the set of faces, loop over all tetrahedra, and look at + // the four faces of each tetrahedron. If there isn't another tetrahedron + // adjacent to the face, operate on the face. If there is another adj- + // acent tetrahedron, operate on the face only if the current tetrahedron + // has a smaller pointer than its neighbor. This way, each face is + // considered only once. + while (tface.tet != (tetrahedron *) NULL) { + for (tface.loc = 0; tface.loc < 4; tface.loc ++) { + sym(tface, tsymface); + if (tface.tet < tsymface.tet || tsymface.tet == dummytet) { + p1 = org (tface); + p2 = dest(tface); + p3 = apex(tface); + fprintf(outfile, "%5d %5d %5d", + pointmark(p1), pointmark(p2), pointmark(p3)); + fprintf(outfile, " 0\n"); + } + } + tface.tet = tetrahedrontraverse(); + } + + fprintf(outfile, "\n# Set of Tetrahedra\n"); + fprintf(outfile, "Tetrahedra\n"); + fprintf(outfile, "%ld\n", tetrahedrons->items); + + tetrahedrons->traversalinit(); + tetptr = tetrahedrontraverse(); + while (tetptr != (tetrahedron *) NULL) { + p1 = (point) tetptr[4]; + p2 = (point) tetptr[5]; + p3 = (point) tetptr[6]; + p4 = (point) tetptr[7]; + fprintf(outfile, "%5d %5d %5d %5d", + pointmark(p1), pointmark(p2), pointmark(p3), pointmark(p4)); + if (in->numberoftetrahedronattributes > 0) { + fprintf(outfile, " %.17g", elemattribute(tetptr, 0)); + } else { + fprintf(outfile, " 0"); + } + fprintf(outfile, "\n"); + tetptr = tetrahedrontraverse(); + } + + fprintf(outfile, "\nCorners\n"); + fprintf(outfile, "%d\n", in->numberofpoints); + + for (i = 0; i < in->numberofpoints; i++) { + fprintf(outfile, "%4d\n", i + 1); + } + + if (b->useshelles) { + fprintf(outfile, "\nEdges\n"); + fprintf(outfile, "%ld\n", subsegs->items); + + subsegs->traversalinit(); + segloop.sh = shellfacetraverse(subsegs); + while (segloop.sh != (shellface *) NULL) { + p1 = sorg(segloop); + p2 = sdest(segloop); + fprintf(outfile, "%5d %5d", pointmark(p1), pointmark(p2)); + fprintf(outfile, " 0\n"); + segloop.sh = shellfacetraverse(subsegs); + } + } + + fprintf(outfile, "\nEnd\n"); + fclose(outfile); +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// outmesh2gid() Write mesh to a .ele.msh file and a .face.msh file, // +// which can be imported and rendered by Gid. // +// // +// You can specify a filename (without suffix) in 'gfilename'. If you don't // +// supply a filename (let gfilename be NULL), the default name stored in // +// 'tetgenbehavior' will be used. The suffixes (.ele.msh and .face.msh) will // +// be automatically added. // +// // +/////////////////////////////////////////////////////////////////////////////// + +void tetgenmesh::outmesh2gid(char* gfilename) +{ + FILE *outfile; + char gidfilename[FILENAMESIZE]; + tetrahedron* tetptr; + triface tface, tsymface; + face sface; + point pointloop, p1, p2, p3, p4; + int pointnumber; + int elementnumber; + + if (gfilename != (char *) NULL && gfilename[0] != '\0') { + strcpy(gidfilename, gfilename); + } else if (b->outfilename[0] != '\0') { + strcpy(gidfilename, b->outfilename); + } else { + strcpy(gidfilename, "unnamed"); + } + strcat(gidfilename, ".ele.msh"); + + if (!b->quiet) { + printf("Writing %s.\n", gidfilename); + } + outfile = fopen(gidfilename, "w"); + if (outfile == (FILE *) NULL) { + printf("File I/O Error: Cannot create file %s.\n", gidfilename); + return; + } + + fprintf(outfile, "mesh dimension = 3 elemtype tetrahedron nnode = 4\n"); + fprintf(outfile, "coordinates\n"); + + points->traversalinit(); + pointloop = pointtraverse(); + pointnumber = 1; // Gid need start number form 1. + while (pointloop != (point) NULL) { + // Point coordinates. + fprintf(outfile, "%4d %.17g %.17g %.17g", pointnumber, + pointloop[0], pointloop[1], pointloop[2]); + if (in->numberofpointattributes > 0) { + // Write an attribute, ignore others if more than one. + fprintf(outfile, " %.17g", pointloop[3]); + } + fprintf(outfile, "\n"); + setpointmark(pointloop, pointnumber); + pointloop = pointtraverse(); + pointnumber++; + } + + fprintf(outfile, "end coordinates\n"); + fprintf(outfile, "elements\n"); + + tetrahedrons->traversalinit(); + tetptr = tetrahedrontraverse(); + elementnumber = 1; + while (tetptr != (tetrahedron *) NULL) { + p1 = (point) tetptr[4]; + p2 = (point) tetptr[5]; + p3 = (point) tetptr[6]; + p4 = (point) tetptr[7]; + fprintf(outfile, "%5d %5d %5d %5d %5d", elementnumber, + pointmark(p1), pointmark(p2), pointmark(p3), pointmark(p4)); + if (in->numberoftetrahedronattributes > 0) { + fprintf(outfile, " %.17g", elemattribute(tetptr, 0)); + } + fprintf(outfile, "\n"); + tetptr = tetrahedrontraverse(); + elementnumber++; + } + + fprintf(outfile, "end elements\n"); + fclose(outfile); + + if (gfilename != (char *) NULL && gfilename[0] != '\0') { + strcpy(gidfilename, gfilename); + } else if (b->outfilename[0] != '\0') { + strcpy(gidfilename, b->outfilename); + } else { + strcpy(gidfilename, "unnamed"); + } + strcat(gidfilename, ".face.msh"); + + if (!b->quiet) { + printf("Writing %s.\n", gidfilename); + } + outfile = fopen(gidfilename, "w"); + if (outfile == (FILE *) NULL) { + printf("File I/O Error: Cannot create file %s.\n", gidfilename); + return; + } + + fprintf(outfile, "mesh dimension = 3 elemtype triangle nnode = 3\n"); + fprintf(outfile, "coordinates\n"); + + points->traversalinit(); + pointloop = pointtraverse(); + pointnumber = 1; // Gid need start number form 1. + while (pointloop != (point) NULL) { + // Point coordinates. + fprintf(outfile, "%4d %.17g %.17g %.17g", pointnumber, + pointloop[0], pointloop[1], pointloop[2]); + if (in->numberofpointattributes > 0) { + // Write an attribute, ignore others if more than one. + fprintf(outfile, " %.17g", pointloop[3]); + } + fprintf(outfile, "\n"); + setpointmark(pointloop, pointnumber); + pointloop = pointtraverse(); + pointnumber++; + } + + fprintf(outfile, "end coordinates\n"); + fprintf(outfile, "elements\n"); + + tetrahedrons->traversalinit(); + tface.tet = tetrahedrontraverse(); + elementnumber = 1; + while (tface.tet != (tetrahedron *) NULL) { + for (tface.loc = 0; tface.loc < 4; tface.loc ++) { + sym(tface, tsymface); + if ((tface.tet < tsymface.tet) || (tsymface.tet == dummytet)) { + p1 = org(tface); + p2 = dest(tface); + p3 = apex(tface); + if (tsymface.tet == dummytet) { + // It's a hull face, output it. + fprintf(outfile, "%5d %d %d %d\n", elementnumber, + pointmark(p1), pointmark(p2), pointmark(p3)); + elementnumber++; + } else if (b->useshelles) { + // Only output it if it's a subface. + tspivot(tface, sface); + if (sface.sh != dummysh) { + fprintf(outfile, "%5d %d %d %d\n", elementnumber, + pointmark(p1), pointmark(p2), pointmark(p3)); + elementnumber++; + } + } + } + } + tface.tet = tetrahedrontraverse(); + } + + fprintf(outfile, "end elements\n"); + fclose(outfile); +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// outmesh2off() Write the mesh to an .off file. // +// // +// .off, the Object File Format, is one of the popular file formats from the // +// Geometry Center's Geomview package (http://www.geomview.org). // +// // +/////////////////////////////////////////////////////////////////////////////// + +void tetgenmesh::outmesh2off(char* ofilename) +{ + FILE *outfile; + char offfilename[FILENAMESIZE]; + triface tface, tsymface; + point pointloop, p1, p2, p3; + long faces; + int shift; + + if (ofilename != (char *) NULL && ofilename[0] != '\0') { + strcpy(offfilename, ofilename); + } else if (b->outfilename[0] != '\0') { + strcpy(offfilename, b->outfilename); + } else { + strcpy(offfilename, "unnamed"); + } + strcat(offfilename, ".off"); + + if (!b->quiet) { + printf("Writing %s.\n", offfilename); + } + outfile = fopen(offfilename, "w"); + if (outfile == (FILE *) NULL) { + printf("File I/O Error: Cannot create file %s.\n", offfilename); + return; + } + + // Calculate the number of triangular faces in the tetrahedral mesh. + faces = (4l * tetrahedrons->items + hullsize) / 2l; + + // Number of points, faces, and edges(not used, here show hullsize). + fprintf(outfile, "OFF\n%ld %ld %ld\n", points->items, faces, hullsize); + + // Write the points. + points->traversalinit(); + pointloop = pointtraverse(); + while (pointloop != (point) NULL) { + fprintf(outfile, " %.17g %.17g %.17g\n", pointloop[0], pointloop[1], + pointloop[2]); + pointloop = pointtraverse(); + } + + // OFF always use zero as the first index. + shift = in->firstnumber == 1 ? 1 : 0; + + tetrahedrons->traversalinit(); + tface.tet = tetrahedrontraverse(); + // To loop over the set of faces, loop over all tetrahedra, and look at + // the four faces of each tetrahedron. If there isn't another tetrahedron + // adjacent to the face, operate on the face. If there is another adj- + // acent tetrahedron, operate on the face only if the current tetrahedron + // has a smaller pointer than its neighbor. This way, each face is + // considered only once. + while (tface.tet != (tetrahedron *) NULL) { + for (tface.loc = 0; tface.loc < 4; tface.loc ++) { + sym(tface, tsymface); + if ((tface.tet < tsymface.tet) || (tsymface.tet == dummytet)) { + p1 = org(tface); + p2 = dest(tface); + p3 = apex(tface); + // Face number, indices of three vertexs. + fprintf(outfile, "3 %4d %4d %4d\n", pointmark(p1) - shift, + pointmark(p2) - shift, pointmark(p3) - shift); + } + } + tface.tet = tetrahedrontraverse(); + } + + fprintf(outfile, "# Generated by %s\n", b->commandline); + fclose(outfile); +} + +// +// End of I/O rouitnes +// + +// +// Begin of user interaction routines +// + +/////////////////////////////////////////////////////////////////////////////// +// // +// internalerror() Ask the user to send me the defective product. Exit. // +// // +/////////////////////////////////////////////////////////////////////////////// + +void tetgenmesh::internalerror() +{ + printf(" Please report this bug to sihang@mail.berlios.de. Include the\n"); + printf(" message above, your input data set, and the exact command\n"); + printf(" line you used to run this program, thank you.\n"); + exit(1); +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// checkmesh() Test the mesh for topological consistency. // +// // +/////////////////////////////////////////////////////////////////////////////// + +void tetgenmesh::checkmesh() +{ + triface tetraloop; + triface oppotet, oppooppotet; + point tetorg, tetdest, tetapex, tetoppo; + point oppodest, oppoapex; + REAL oritest; + int horrors; + + if (!b->quiet) { + printf(" Checking consistency of mesh...\n"); + } + horrors = 0; + // Run through the list of tetrahedra, checking each one. + tetrahedrons->traversalinit(); + tetraloop.tet = tetrahedrontraverse(); + while (tetraloop.tet != (tetrahedron *) NULL) { + // Check all four faces of the tetrahedron. + for (tetraloop.loc = 0; tetraloop.loc < 4; tetraloop.loc++) { + tetorg = org(tetraloop); + tetdest = dest(tetraloop); + tetapex = apex(tetraloop); + tetoppo = oppo(tetraloop); + if (tetraloop.loc == 0) { // Only test for inversion once. + oritest = orient3d(tetorg, tetdest, tetapex, tetoppo); + if (oritest >= 0.0) { + printf(" !! !! %s ", oritest > 0.0 ? "Inverted" : "Degenerated"); + printtet(&tetraloop); + printf(" orient3d = %.17g.\n", oritest); + horrors++; + } + } + // Find the neighboring tetrahedron on this face. + sym(tetraloop, oppotet); + if (oppotet.tet != dummytet) { + // Check that the tetrahedron's neighbor knows it's a neighbor. + sym(oppotet, oppooppotet); + if ((tetraloop.tet != oppooppotet.tet) + || (tetraloop.loc != oppooppotet.loc)) { + printf(" !! !! Asymmetric tetra-tetra bond:\n"); + if (tetraloop.tet == oppooppotet.tet) { + printf(" (Right tetrahedron, wrong orientation)\n"); + } + printf(" First "); + printtet(&tetraloop); + printf(" Second (nonreciprocating) "); + printtet(&oppotet); + horrors++; + } + // Check that both tetrahedra agree on the identities + // of their shared vertices. + if (findorg(&oppotet, tetorg)) { + oppodest = dest(oppotet); + oppoapex = apex(oppotet); + } else { + oppodest = (point) NULL; + } + if ((tetdest != oppoapex) || (tetapex != oppodest)) { + printf(" !! !! Mismatched face coordinates between two tetras:\n"); + printf(" First mismatched "); + printtet(&tetraloop); + printf(" Second mismatched "); + printtet(&oppotet); + horrors++; + } + } + } + tetraloop.tet = tetrahedrontraverse(); + } + if (horrors == 0) { + if (!b->quiet) { + printf(" In my studied opinion, the mesh appears to be consistent.\n"); + } + } else if (horrors == 1) { + printf(" !! !! !! !! Precisely one festering wound discovered.\n"); + } else { + printf(" !! !! !! !! %d abominations witnessed.\n", horrors); + } +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// checkshells() Test the boundary mesh for topological consistency. // +// // +/////////////////////////////////////////////////////////////////////////////// + +void tetgenmesh::checkshells() +{ + triface oppotet, oppooppotet, testtet; + face shloop, segloop, spin; + face testsh, testseg, testshsh; + point shorg, shdest, segorg, segdest; + REAL checksign; + bool same; + int horrors; + int i; + + if (!b->quiet) { + printf(" Checking consistency of the mesh boundary...\n"); + } + horrors = 0; + + // Run through the list of subfaces, checking each one. + subfaces->traversalinit(); + shloop.sh = shellfacetraverse(subfaces); + while (shloop.sh != (shellface *) NULL) { + // Check two connected tetrahedra if they exist. + shloop.shver = 0; + stpivot(shloop, oppotet); + if (oppotet.tet != dummytet) { + tspivot(oppotet, testsh); + if (testsh.sh != shloop.sh) { + printf(" !! !! Wrong tetra-subface connection.\n"); + printf(" Tetra: "); + printtet(&oppotet); + printf(" Subface: "); + printsh(&shloop); + horrors++; + } + if (oppo(oppotet) != (point) NULL) { + adjustedgering(oppotet, CCW); + checksign = orient3d(sorg(shloop), sdest(shloop), sapex(shloop), + oppo(oppotet)); + if (checksign >= 0.0) { + printf(" !! !! Wrong subface orientation.\n"); + printf(" Subface: "); + printsh(&shloop); + horrors++; + } + } + } + sesymself(shloop); + stpivot(shloop, oppooppotet); + if (oppooppotet.tet != dummytet) { + tspivot(oppooppotet, testsh); + if (testsh.sh != shloop.sh) { + printf(" !! !! Wrong tetra-subface connection.\n"); + printf(" Tetra: "); + printtet(&oppooppotet); + printf(" Subface: "); + printsh(&shloop); + horrors++; + } + if (oppotet.tet != dummytet) { + sym(oppotet, testtet); + if (testtet.tet != oppooppotet.tet) { + printf(" !! !! Wrong tetra-subface-tetra connection.\n"); + printf(" Tetra 1: "); + printtet(&oppotet); + printf(" Subface: "); + printsh(&shloop); + printf(" Tetra 2: "); + printtet(&oppooppotet); + horrors++; + } + } + if (oppo(oppooppotet) != (point) NULL) { + adjustedgering(oppooppotet, CCW); + checksign = orient3d(sorg(shloop), sdest(shloop), sapex(shloop), + oppo(oppooppotet)); + if (checksign >= 0.0) { + printf(" !! !! Wrong subface orientation.\n"); + printf(" Subface: "); + printsh(&shloop); + horrors++; + } + } + } + // Check connection between subfaces. + shloop.shver = 0; + for (i = 0; i < 3; i++) { + shorg = sorg(shloop); + shdest = sdest(shloop); + sspivot(shloop, testseg); + if (testseg.sh != dummysh) { + segorg = sorg(testseg); + segdest = sdest(testseg); + same = ((shorg == segorg) && (shdest == segdest)) + || ((shorg == segdest) && (shdest == segorg)); + if (!same) { + printf(" !! !! Wrong subface-subsegment connection.\n"); + printf(" Subface: "); + printsh(&shloop); + printf(" Subsegment: "); + printsh(&testseg); + horrors++; + } + } + spivot(shloop, testsh); + if (testsh.sh != dummysh) { + segorg = sorg(testsh); + segdest = sdest(testsh); + same = ((shorg == segorg) && (shdest == segdest)) + || ((shorg == segdest) && (shdest == segorg)); + if (!same) { + printf(" !! !! Wrong subface-subface connection.\n"); + printf(" Subface 1: "); + printsh(&shloop); + printf(" Subface 2: "); + printsh(&testsh); + horrors++; + } + spivot(testsh, testshsh); + shorg = sorg(testshsh); + shdest = sdest(testshsh); + same = ((shorg == segorg) && (shdest == segdest)) + || ((shorg == segdest) && (shdest == segorg)); + if (!same) { + printf(" !! !! Wrong subface-subface connection.\n"); + printf(" Subface 1: "); + printsh(&testsh); + printf(" Subface 2: "); + printsh(&testshsh); + horrors++; + } + if (testseg.sh == dummysh) { + if (testshsh.sh != shloop.sh) { + printf(" !! !! Wrong subface-subface connection.\n"); + printf(" Subface 1: "); + printsh(&shloop); + printf(" Subface 2: "); + printsh(&testsh); + horrors++; + } + } + } + senextself(shloop); + } + shloop.sh = shellfacetraverse(subfaces); + } + + // Run through the list of subsegs, checking each one. + subsegs->traversalinit(); + segloop.sh = shellfacetraverse(subsegs); + while (segloop.sh != (shellface *) NULL) { + segorg = sorg(segloop); + segdest = sdest(segloop); + spivot(segloop, testsh); + if (testsh.sh == dummysh) { + printf(" !! !! Wrong subsegment-subface connection.\n"); + printf(" Subsegment: "); + printsh(&segloop); + horrors++; + segloop.sh = shellfacetraverse(subsegs); + continue; + } + shorg = sorg(testsh); + shdest = sdest(testsh); + same = ((shorg == segorg) && (shdest == segdest)) + || ((shorg == segdest) && (shdest == segorg)); + if (!same) { + printf(" !! !! Wrong subsegment-subface connection.\n"); + printf(" Subsegment : "); + printsh(&segloop); + printf(" Subface : "); + printsh(&testsh); + horrors++; + segloop.sh = shellfacetraverse(subsegs); + continue; + } + // Check the connection of face loop around this subsegment. + spin = testsh; + i = 0; + do { + spivotself(spin); + shorg = sorg(spin); + shdest = sdest(spin); + same = ((shorg == segorg) && (shdest == segdest)) + || ((shorg == segdest) && (shdest == segorg)); + if (!same) { + printf(" !! !! Wrong subsegment-subface connection.\n"); + printf(" Subsegment : "); + printsh(&segloop); + printf(" Subface : "); + printsh(&testsh); + horrors++; + break; + } + i++; + } while (spin.sh != testsh.sh && i < 1000); + if (i >= 1000) { + printf(" !! !! Wrong subsegment-subface connection.\n"); + printf(" Subsegment : "); + printsh(&segloop); + horrors++; + } + segloop.sh = shellfacetraverse(subsegs); + } + if (horrors == 0) { + if (!b->quiet) { + printf(" Mesh boundaries connected correctly.\n"); + } + } else { + printf(" !! !! !! !! %d boundary connection viewed with horror.\n", + horrors); + return; + } +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// checkdelaunay() Ensure that the mesh is constrained Delaunay. // +// // +// If 'flipqueue' is not NULL, non-locally Delaunay faces are saved in it. // +// // +/////////////////////////////////////////////////////////////////////////////// + +void tetgenmesh::checkdelaunay(queue* flipqueue) +{ + triface tetraloop; + triface oppotet; + face opposhelle; + point tetorg, tetdest, tetapex, tetoppo; + point oppooppo; + REAL sign; + int shouldbedelaunay; + int horrors; + + if (!b->quiet) { + printf(" Checking Delaunay property of the mesh...\n"); + } + horrors = 0; + // Run through the list of triangles, checking each one. + tetrahedrons->traversalinit(); + tetraloop.tet = tetrahedrontraverse(); + while (tetraloop.tet != (tetrahedron *) NULL) { + // Check all four faces of the tetrahedron. + for (tetraloop.loc = 0; tetraloop.loc < 4; tetraloop.loc++) { + tetorg = org(tetraloop); + tetdest = dest(tetraloop); + tetapex = apex(tetraloop); + tetoppo = oppo(tetraloop); + sym(tetraloop, oppotet); + oppooppo = oppo(oppotet); + // Only test that the face is locally Delaunay if there is an + // adjoining tetrahedron whose pointer is larger (to ensure that + // each pair isn't tested twice). + shouldbedelaunay = (oppotet.tet != dummytet) + && (tetoppo != (point) NULL) + && (oppooppo != (point) NULL) + && (tetraloop.tet < oppotet.tet); + if (checksubfaces && shouldbedelaunay) { + // If a shell edge separates the triangles, then the edge is + // constrained, so no local Delaunay test should be done. + tspivot(tetraloop, opposhelle); + if (opposhelle.sh != dummysh){ + shouldbedelaunay = 0; + } + } + if (shouldbedelaunay) { + sign = insphere(tetdest, tetorg, tetapex, tetoppo, oppooppo); + if (checksubfaces && sign > 0.0) { + if (iscospheric(tetdest, tetorg, tetapex, tetoppo, oppooppo, + b->epsilon)) sign = 0.0; + } + if (sign > 0.0) { + if (flipqueue) { + enqueueflipface(tetraloop, flipqueue); + } else { + printf(" !! Non-locally Delaunay face (%d, %d, %d).\n", + pointmark(tetorg), pointmark(tetdest), pointmark(tetapex)); + } + horrors++; + } + } + } + tetraloop.tet = tetrahedrontraverse(); + } + if (flipqueue == (queue *) NULL) { + if (horrors == 0) { + if (!b->quiet) { + printf(" The mesh is %s.\n", + checksubfaces ? "constrained Delaunay" : "Delaunay"); + } + } else { + printf(" !! !! !! !! %d obscenities viewed with horror.\n", horrors); + } + } +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// checkconforming() Ensure that the mesh is conforming Delaunay. // +// // +/////////////////////////////////////////////////////////////////////////////// + +void tetgenmesh::checkconforming() +{ + face segloop, shloop; + int encsubsegs, encsubfaces; + + if (!b->quiet) { + printf(" Checking conforming Delaunay property of mesh...\n"); + } + encsubsegs = encsubfaces = 0; + // Run through the list of subsegments, check each one. + subsegs->traversalinit(); + segloop.sh = shellfacetraverse(subsegs); + while (segloop.sh != (shellface *) NULL) { + if (checkseg4encroach(&segloop, NULL, false)) { + printf(" !! !! Non-conforming subsegment: "); + printsh(&segloop); + encsubsegs++; + } + segloop.sh = shellfacetraverse(subsegs); + } + // Run through the list of subfaces, check each one. + subfaces->traversalinit(); + shloop.sh = shellfacetraverse(subfaces); + while (shloop.sh != (shellface *) NULL) { + if (checksub4encroach(&shloop, NULL, false)) { + printf(" !! !! Non-conforming subface: "); + printsh(&shloop); + encsubfaces++; + } + shloop.sh = shellfacetraverse(subfaces); + } + if (encsubsegs == 0 && encsubfaces == 0) { + if (!b->quiet) { + printf(" The mesh is conforming Delaunay.\n"); + } + } else { + if (encsubsegs > 0) { + printf(" !! !! %d subsegments are non-conforming.\n", encsubsegs); + } + if (encsubfaces > 0) { + printf(" !! !! %d subfaces are non-conforming.\n", encsubfaces); + } + } +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// qualitystatistics() Print statistics about the quality of the mesh. // +// // +/////////////////////////////////////////////////////////////////////////////// + +void tetgenmesh::qualitystatistics() +{ + triface tetloop; + point p[4]; + char sbuf[128]; + REAL radiusratiotable[12]; + REAL aspectratiotable[16]; + REAL dx[6], dy[6], dz[6]; + REAL edgelength[6]; + REAL alldihed[6]; + REAL cent[3]; + REAL shortest, longest; + REAL smallestvolume, biggestvolume; + REAL smallestdiangle, biggestdiangle; + REAL tetvol; + REAL tetlongest2; + REAL minaltitude; + REAL cirradius, insradius; + REAL shortlen, longlen; + REAL tetaspect, tetradius; + REAL smalldiangle, bigdiangle; + int radiustable[12]; + int aspecttable[16]; + int dihedangletable[18]; + int radiusindex; + int aspectindex; + int tendegree; + int i, j, k; + + printf("Mesh quality statistics:\n\n"); + + radiusratiotable[0] = 0.707; radiusratiotable[1] = 1.0; + radiusratiotable[2] = 1.1; radiusratiotable[3] = 1.2; + radiusratiotable[4] = 1.4; radiusratiotable[5] = 1.6; + radiusratiotable[6] = 1.8; radiusratiotable[7] = 2.0; + radiusratiotable[8] = 2.5; radiusratiotable[9] = 3.0; + radiusratiotable[10] = 10.0; radiusratiotable[11] = 0.0; + + aspectratiotable[0] = 1.5; aspectratiotable[1] = 2.0; + aspectratiotable[2] = 2.5; aspectratiotable[3] = 3.0; + aspectratiotable[4] = 4.0; aspectratiotable[5] = 6.0; + aspectratiotable[6] = 10.0; aspectratiotable[7] = 15.0; + aspectratiotable[8] = 25.0; aspectratiotable[9] = 50.0; + aspectratiotable[10] = 100.0; aspectratiotable[11] = 300.0; + aspectratiotable[12] = 1000.0; aspectratiotable[13] = 10000.0; + aspectratiotable[14] = 100000.0; aspectratiotable[15] = 0.0; + + for (i = 0; i < 12; i++) { + radiustable[i] = 0; + } + for (i = 0; i < 16; i++) { + aspecttable[i] = 0; + } + for (i = 0; i < 18; i++) { + dihedangletable[i] = 0; + } + + minaltitude = xmax - xmin + ymax - ymin + zmax - zmin; + minaltitude = minaltitude * minaltitude; + shortest = minaltitude; + longest = 0.0; + smallestvolume = minaltitude; + biggestvolume = 0.0; + smallestdiangle = 180.0; + biggestdiangle = 0.0; + + // Loop all elements, calculate quality parameters for each element. + tetrahedrons->traversalinit(); + tetloop.tet = tetrahedrontraverse(); + while (tetloop.tet != (tetrahedron *) NULL) { + p[0] = org(tetloop); + p[1] = dest(tetloop); + p[2] = apex(tetloop); + p[3] = oppo(tetloop); + tetlongest2 = 0.0; + + // Calculate the longest and shortest edge length. + for (i = 0; i < 3; i++) { + j = plus1mod3[i]; + k = minus1mod3[i]; + dx[i] = p[j][0] - p[k][0]; + dy[i] = p[j][1] - p[k][1]; + dz[i] = p[j][2] - p[k][2]; + edgelength[i] = dx[i] * dx[i] + dy[i] * dy[i] + dz[i] * dz[i]; + if (i == 0) { + shortlen = longlen = edgelength[i]; + } else { + shortlen = edgelength[i] < shortlen ? edgelength[i] : shortlen; + longlen = edgelength[i] > longlen ? edgelength[i] : longlen; + } + if (edgelength[i] > tetlongest2) { + tetlongest2 = edgelength[i]; + } + if (edgelength[i] > longest) { + longest = edgelength[i]; + } + if (edgelength[i] < shortest) { + shortest = edgelength[i]; + } + } + for (i = 3; i < 6; i++) { + j = i - 3; + k = 3; + dx[i] = p[j][0] - p[k][0]; + dy[i] = p[j][1] - p[k][1]; + dz[i] = p[j][2] - p[k][2]; + edgelength[i] = dx[i] * dx[i] + dy[i] * dy[i] + dz[i] * dz[i]; + shortlen = edgelength[i] < shortlen ? edgelength[i] : shortlen; + longlen = edgelength[i] > longlen ? edgelength[i] : longlen; + if (edgelength[i] > tetlongest2) { + tetlongest2 = edgelength[i]; + } + if (edgelength[i] > longest) { + longest = edgelength[i]; + } + if (edgelength[i] < shortest) { + shortest = edgelength[i]; + } + } + + // Calculate the largest and smallest volume. + tetvol = orient3d(p[0], p[1], p[2], p[3]) / 6.0; + if (tetvol < 0) tetvol = -tetvol; + if (tetvol < smallestvolume) { + smallestvolume = tetvol; + } + if (tetvol > biggestvolume) { + biggestvolume = tetvol; + } + + // Calculate the largest and smallest dihedral angles. + tetalldihedral(p[0], p[1], p[2], p[3], alldihed); + for (i = 0; i < 6; i++) { + alldihed[i] = alldihed[i] * 180.0 / PI; + if (i == 0) { + smalldiangle = bigdiangle = alldihed[i]; + } else { + smalldiangle = alldihed[i] < smalldiangle ? alldihed[i] : smalldiangle; + bigdiangle = alldihed[i] > bigdiangle ? alldihed[i] : bigdiangle; + } + if (alldihed[i] < smallestdiangle) { + smallestdiangle = alldihed[i]; + } else if (alldihed[i] > biggestdiangle) { + biggestdiangle = alldihed[i]; + } + } + tendegree = (int) (smalldiangle / 10.); + dihedangletable[tendegree]++; + tendegree = (int) (bigdiangle / 10.); + dihedangletable[tendegree]++; + + // Calculate aspect ratio and radius-edge ratio for this element. + tetaspect = 0.0; + if (!circumsphere(p[0], p[1], p[2], p[3], cent, &cirradius)) { + // ! Very bad element. + tetaspect = 1.e+8; + tetradius = 100.0; + } else { + inscribedsphere(p[0], p[1], p[2], p[3], cent, &insradius); + } + if (tetaspect == 0.0) { + tetradius = cirradius / sqrt(shortlen); + tetaspect = sqrt(longlen) / (2.0 * insradius); + + } + aspectindex = 0; + while ((tetaspect > aspectratiotable[aspectindex]) && (aspectindex < 15)) { + aspectindex++; + } + aspecttable[aspectindex]++; + radiusindex = 0; + while ((tetradius > radiusratiotable[radiusindex]) && (radiusindex < 11)) { + radiusindex++; + } + radiustable[radiusindex]++; + + tetloop.tet = tetrahedrontraverse(); + } + + shortest = sqrt(shortest); + longest = sqrt(longest); + minaltitude = sqrt(minaltitude); + + printf(" Smallest volume: %16.5g | Largest volume: %16.5g\n", + smallestvolume, biggestvolume); + printf(" Shortest edge: %16.5g | Longest edge: %16.5g\n", + shortest, longest); + sprintf(sbuf, "%.17g", biggestdiangle); + if (strlen(sbuf) > 8) { + sbuf[8] = '\0'; + } + printf(" Smallest dihedral: %14.5g | Largest dihedral: %s\n\n", + smallestdiangle, sbuf); + + printf(" Radius-edge ratio histogram:\n"); + printf(" < %-6.6g : %8d | %6.6g - %-6.6g : %8d\n", + radiusratiotable[0], radiustable[0], radiusratiotable[5], + radiusratiotable[6], radiustable[6]); + for (i = 1; i < 5; i++) { + printf(" %6.6g - %-6.6g : %8d | %6.6g - %-6.6g : %8d\n", + radiusratiotable[i - 1], radiusratiotable[i], radiustable[i], + radiusratiotable[i + 5], radiusratiotable[i + 6], + radiustable[i + 6]); + } + printf(" %6.6g - %-6.6g : %8d | %6.6g - : %8d\n", + radiusratiotable[4], radiusratiotable[5], radiustable[5], + radiusratiotable[10], radiustable[11]); + printf(" (A tetrahedron's radius-edge ratio is its radius of "); + printf("circumsphere divided\n"); + printf(" by its shortest edge length)\n\n"); + + printf(" Aspect ratio histogram:\n"); + printf(" 1.1547 - %-6.6g : %8d | %6.6g - %-6.6g : %8d\n", + aspectratiotable[0], aspecttable[0], aspectratiotable[7], + aspectratiotable[8], aspecttable[8]); + for (i = 1; i < 7; i++) { + printf(" %6.6g - %-6.6g : %8d | %6.6g - %-6.6g : %8d\n", + aspectratiotable[i - 1], aspectratiotable[i], aspecttable[i], + aspectratiotable[i + 7], aspectratiotable[i + 8], + aspecttable[i + 8]); + } + printf(" %6.6g - %-6.6g : %8d | %6.6g - : %8d\n", + aspectratiotable[6], aspectratiotable[7], aspecttable[7], + aspectratiotable[14], aspecttable[15]); + printf(" (A tetrahedron's aspect ratio is its longest edge length"); + printf(" divided by the\n"); + printf(" diameter of its inscribed sphere)\n\n"); + + printf(" Dihedral Angle histogram:\n"); + for (i = 0; i < 9; i++) { + printf(" %3d - %2d degrees: %8d | %3d - %3d degrees: %8d\n", + i * 10, i * 10 + 10, dihedangletable[i], + i * 10 + 90, i * 10 + 100, dihedangletable[i + 9]); + } + printf("\n"); +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// statistics() Print all sorts of cool facts. // +// // +/////////////////////////////////////////////////////////////////////////////// + +void tetgenmesh::statistics() +{ + printf("\nStatistics:\n\n"); + printf(" Input points: %d\n", in->numberofpoints); + if (b->refine) { + printf(" Input tetrahedra: %d\n", in->numberoftetrahedra); + } + if (b->plc) { + printf(" Input facets: %d\n", in->numberoffacets); + printf(" Input holes: %d\n", in->numberofholes); + printf(" Input regions: %d\n", in->numberofregions); + } + + printf("\n Mesh points: %ld\n", points->items); + printf(" Mesh tetrahedra: %ld\n", tetrahedrons->items); + if (b->plc || b->refine) { + printf(" Mesh faces: %ld\n", (4l * tetrahedrons->items + hullsize) / 2l); + } + if (b->plc || b->refine) { + printf(" Mesh subfaces: %ld\n", subfaces->items); + printf(" Mesh subsegments: %ld\n\n", subsegs->items); + } else { + printf(" Convex hull faces: %ld\n\n", hullsize); + } + if (b->verbose) { + // if (b->quality || b->removesliver) { + qualitystatistics(); + // } + printf("\n"); + } +} + +// +// End of user interaction routines +// + +// +// Begin of constructor and destructor of tetgenmesh +// + +/////////////////////////////////////////////////////////////////////////////// +// // +// ~tetgenmesh() Deallocte memory occupied by a tetgenmesh object. // +// // +/////////////////////////////////////////////////////////////////////////////// + +tetgenmesh::~tetgenmesh() +{ + in = (tetgenio *) NULL; + b = (tetgenbehavior *) NULL; + + if (tetrahedrons != (memorypool *) NULL) { + delete tetrahedrons; + } + if (subfaces != (memorypool *) NULL) { + delete subfaces; + } + if (subsegs != (memorypool *) NULL) { + delete subsegs; + } + if (points != (memorypool *) NULL) { + delete points; + } + if (dummytetbase != (tetrahedron *) NULL) { + delete [] dummytetbase; + } + if (dummyshbase != (shellface *) NULL) { + delete [] dummyshbase; + } + if (liftpointarray != (REAL *) NULL) { + delete [] liftpointarray; + } + if (highordertable != (point *) NULL) { + delete [] highordertable; + } +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// tetgenmesh() Initialize a tetgenmesh object. // +// // +/////////////////////////////////////////////////////////////////////////////// + +tetgenmesh::tetgenmesh() +{ + in = (tetgenio *) NULL; + b = (tetgenbehavior *) NULL; + + tetrahedrons = (memorypool *) NULL; + subfaces = (memorypool *) NULL; + subsegs = (memorypool *) NULL; + points = (memorypool *) NULL; + badsubsegs = (memorypool *) NULL; + badsubfaces = (memorypool *) NULL; + badtetrahedrons = (memorypool *) NULL; + flipstackers = (memorypool *) NULL; + + dummytet = (tetrahedron *) NULL; + dummytetbase = (tetrahedron *) NULL; + dummysh = (shellface *) NULL; + dummyshbase = (shellface *) NULL; + + liftpointarray = (REAL *) NULL; + highordertable = (point *) NULL; + + xmax = xmin = ymax = ymin = zmax = zmin = 0.0; + longest = 0.0; + hullsize = 0l; + insegment = 0l; + pointmarkindex = 0; + point2simindex = 0; + highorderindex = 0; + elemattribindex = 0; + volumeboundindex = 0; + shmarkindex = 0; + areaboundindex = 0; + checksubfaces = 0; + checkquality = 0; + nonconvex = 0; + dupverts = 0; + samples = 0l; + randomseed = 0l; + macheps = 0.0; + flip23s = flip32s = flip22s = flip44s = 0l; +} + +// +// End of constructor and destructor of tetgenmesh +// + +// +// End of class 'tetgenmesh' implementation. +// + +/////////////////////////////////////////////////////////////////////////////// +// // +// tetrahedralize() The interface for users using TetGen library to // +// generate tetrahedral meshes with all features. // +// // +// The sequence is roughly as follows. Many of these steps can be skipped, // +// depending on the command line switches. // +// // +// - Initialize constants and parse the command line. // +// - Read the vertices from a file and either // +// - tetrahedralize them (no -r), or // +// - read an old mesh from files and reconstruct it (-r). // +// - Insert the PLC segments and facets (-p). // +// - Read the holes (-p), regional attributes (-pA), and regional volume // +// constraints (-pa). Carve the holes and concavities, and spread the // +// regional attributes and volume constraints. // +// - Enforce the constraints on minimum quality bound (-q) and maximum // +// volume (-a). Also enforce the conforming Delaunay property (-q and -a). // +// - Promote the mesh's linear tetrahedra to higher order elements (-o). // +// - Write the output files and print the statistics. // +// - Check the consistency and Delaunay property of the mesh (-C). // +// // +/////////////////////////////////////////////////////////////////////////////// + +#include <time.h> // Defined type clock_t, constant CLOCKS_PER_SEC. + +void tetrahedralize(tetgenbehavior *b, tetgenio *in, tetgenio *out) +{ + tetgenmesh m; + clock_t tv0, tv1, tv2, tv3, tv4, tv5, tv6, tv7, tv8; + + if (!b->quiet) { + tv0 = clock(); + } + + m.b = b; + m.in = in; + + m.macheps = exactinit(); + m.initializepointpool(); + m.initializetetshpools(); + m.steinerleft = b->steiner; + + if (!b->quiet) { + tv1 = clock(); + } + + m.transfernodes(); + if (b->refine) { + m.reconstructmesh(); + } else { + m.incrflipdelaunay(); + } + + if (!b->quiet) { + tv2 = clock(); + if (b->refine) { + printf("Mesh reconstruction seconds: %g\n", + (tv2 - tv1) / (REAL) CLOCKS_PER_SEC); + } else if (!b->detectinter) { + printf("Delaunay seconds: %g\n", (tv2 - tv1) / (REAL) CLOCKS_PER_SEC); + } + } + + if (b->useshelles && !b->refine) { + m.insegment = m.meshsurface(); + if (b->detectinter) { + m.detectinterfaces(); + } else { + if (!b->nobisect) { + m.delaunizesegments(); + m.checksubfaces = 1; + m.constrainedfacets(); + } + } + } + + if (!b->quiet) { + tv3 = clock(); + if (b->useshelles && !b->refine) { + if (b->detectinter) { + printf("Intersection seconds: %g\n", + (tv3 - tv2) / (REAL) CLOCKS_PER_SEC); + } else { + if (!b->nobisect) { + printf("Segment and facet seconds: %g\n", + (tv3 - tv2) / (REAL) CLOCKS_PER_SEC); + } + } + } + } + + if (b->plc && !b->refine && !b->detectinter) { + if (b->checkclosure) { + m.indenthull(); + } else { + m.carveholes(); + } + m.nonconvex = 1; + } + + if (!b->quiet) { + tv4 = clock(); + if (b->plc && !b->refine && !b->detectinter) { + printf("Hole seconds: %g\n", (tv4 - tv3) / (REAL) CLOCKS_PER_SEC); + } + } + + if ((b->plc || b->refine) && !b->detectinter && !b->checkclosure) { + m.removeilltets(); + } + + if (!b->quiet) { + tv5 = clock(); + if ((b->plc || b->refine) && !b->detectinter) { + printf("Repair seconds: %g\n", (tv5 - tv4) / (REAL) CLOCKS_PER_SEC); + } + } + + if (b->insertaddpoints) { + if (in->numberofaddpoints == 0) { + in->load_addnodes(b->infilename); + } + if (in->numberofaddpoints > 0) { + m.insertaddpoints(); + } + } + + if (!b->quiet) { + tv6 = clock(); + if ((b->plc || b->refine) && (in->numberofaddpoints > 0)) { + printf("Add points seconds: %g\n", (tv6 - tv5) / (REAL) CLOCKS_PER_SEC); + } + } + + if (b->quality && (m.tetrahedrons->items > 0)) { + m.enforcequality(); + } + + if (!b->quiet) { + tv7 = clock(); + if (b->quality && (m.tetrahedrons->items > 0)) { + printf("Quality seconds: %g\n", (tv7 - tv6) / (REAL) CLOCKS_PER_SEC); + } + } + + if ((b->plc || b->refine) && b->removesliver) { + m.removeslivers(); + } + + if (!b->quiet) { + tv8 = clock(); + if ((b->plc || b->refine) && b->removesliver) { + printf("Sliver repair seconds: %g\n", + (tv8 - tv7) / (REAL) CLOCKS_PER_SEC); + } + } + + if (b->order > 1) { + m.highorder(); + } + + if (!b->quiet) { + printf("\n"); + } + + if (out != (tetgenio *) NULL) { + out->firstnumber = in->firstnumber; + out->mesh_dim = in->mesh_dim; + } + + if (b->nonodewritten || b->noiterationnum) { + if (!b->quiet) { + printf("NOT writing a .node file.\n"); + } + } else { + if (b->detectinter) { + if (m.subfaces->items > 0l) { + // Only output when there are intersecting faces. + m.outnodes(out); + } + } else { + m.outnodes(out); + } + } + + if (b->noelewritten) { + if (!b->quiet) { + printf("NOT writing an .ele file.\n"); + } + } else { + if (!b->detectinter) { + if (m.tetrahedrons->items > 0l) { + m.outelements(out); + } + } + } + + if (b->nofacewritten) { + if (!b->quiet) { + printf("NOT writing an .face file.\n"); + } + } else { + if (b->facesout) { + if (m.tetrahedrons->items > 0l) { + // Output all faces. + m.outfaces(out); + } + } else { + if (b->detectinter) { + if (m.subfaces->items > 0l) { + // Only output when there are intersecting faces. + m.outsubfaces(out); + } + } else if (b->plc || b->refine) { + if (m.tetrahedrons->items > 0l) { + // Output boundary faces. + m.outsubfaces(out); + } + } else { + if (m.tetrahedrons->items > 0l) { + // Output convex hull faces. + m.outhullfaces(out); + } + } + } + } + + if (b->edgesout && b->plc) { + m.outsubsegments(out); + } + + if (!out && b->plc && ((b->object == tetgenbehavior::OFF) || + (b->object == tetgenbehavior::PLY) || + (b->object == tetgenbehavior::STL))) { + m.outsmesh(b->outfilename); + } + + if (!out && b->meditview) { + m.outmesh2medit(b->outfilename); + } + + if (!out && b->gidview) { + m.outmesh2gid(b->outfilename); + } + + if (!out && b->geomview) { + m.outmesh2off(b->outfilename); + } + + if (b->neighout) { + m.outneighbors(out); + } + + if (!b->quiet) { + tv7 = clock(); + printf("\nOutput seconds: %g\n", (tv7 - tv6) / (REAL) CLOCKS_PER_SEC); + printf("Total running seconds: %g\n", + (tv7 - tv0) / (REAL) CLOCKS_PER_SEC); + } + + if (b->docheck) { + m.checkmesh(); + if (m.checksubfaces) { + m.checkshells(); + } + if (b->docheck > 1) { + m.checkdelaunay(NULL); + if (b->docheck > 2) { + if (b->quality || b->refine) { + m.checkconforming(); + } + } + } + } + + if (!b->quiet) { + m.statistics(); + } +} + +#ifndef TETLIBRARY + +/////////////////////////////////////////////////////////////////////////////// +// // +// main() The entrance for running TetGen from command line. // +// // +/////////////////////////////////////////////////////////////////////////////// + +int main(int argc, char *argv[]) + +#else // with TETLIBRARY + +/////////////////////////////////////////////////////////////////////////////// +// // +// tetrahedralize() The entrance for calling TetGen from another program. // +// // +/////////////////////////////////////////////////////////////////////////////// + +void tetrahedralize(char *switches, tetgenio *in, tetgenio *out) + +#endif // not TETLIBRARY + +{ + tetgenbehavior b; + +#ifndef TETLIBRARY + + tetgenio in; + + if (!b.parse_commandline(argc, argv)) { + exit(1); + } + if (b.refine) { + if (!in.load_tetmesh(b.infilename)) { + exit(1); + } + } else { + if (!in.load_plc(b.infilename, (int) b.object)) { + exit(1); + } + } + tetrahedralize(&b, &in, NULL); + + return 0; + +#else // with TETLIBRARY + + if (!b.parse_commandline(switches)) { + exit(1); + } + tetrahedralize(&b, in, out); + +#endif // not TETLIBRARY +} diff --git a/contrib/Tetgen/tetgen.h b/contrib/Tetgen/tetgen.h new file mode 100644 index 0000000000..cbe84252e8 --- /dev/null +++ b/contrib/Tetgen/tetgen.h @@ -0,0 +1,1764 @@ +/////////////////////////////////////////////////////////////////////////////// +// // +// TetGen // +// // +// A Quality Tetrahedral Mesh Generator and 3D Delaunay Triangulator // +// // +// Version 1.3 // +// June 13, 2004 // +// // +// Copyright 2002, 2004 // +// Hang Si // +// Rathausstr. 9, 10178 Berlin, Germany // +// si@wias-berlin.de // +// // +// You can obtain TetGen via internet: http://tetgen.berlios.de. It may be // +// freely copied, modified, and redistributed under the copyright notices // +// given in the file LICENSE. // +// // +// TetGen is a program for generating quality tetrahedral meshes and three- // +// dimensional Delaunay triangulations. It currently computes exact // +// Delaunay tetrahedralizations, constrained Delaunay tetrahedralizations, // +// and quality tetrahedral meshes. The latter are nicely graded and whose // +// tetrahedra have radius-edge ratio bounded, and are conforming Delaunay // +// if there are no input angles smaller than 60 degree. // +// // +// TetGen incorporates a suit of geometrical and mesh generation algorithms. // +// A brief description of these algorithms used in TetGen can be found in // +// the first section of the user's manual. References are given for users // +// who are interesting in these approaches. However, the main references // +// are listed below: // +// // +// The efficient Delaunay tetrahedralization algorithm is: H. Edelsbrunner // +// and N. R. Shah, "Incremental Topological Flipping Works for Regular // +// Triangulations". Algorithmica 15: 223-241, 1996. // +// // +// The constrained Delaunay tetrahedralization algorithm is described in: // +// H. Si and K. Gaertner, "An Algorithm for Three-Dimensional Constrained // +// Delaunay Triangles". Proceedings of the 4th International Conference on // +// Engineering Computational Technology, Lisbon, September 2004. // +// // +// The Delaunay refinement algorithm is from: J. R. Shewchuk, "Tetrahedral // +// Mesh Generation by Delaunay Refinement". Proceedings of the 14th Annual // +// Symposium on Computational Geometry, pages 86-95, 1998. // +// // +// The mesh data structure of TetGen is a combination of two types of mesh // +// data structures. The tetrahedron-based mesh data structure introduced // +// by Shewchuk is eligible to implement algorithms of generating Delaunay // +// tetrahedralizations. However, constrained Delaunay tetrahedralization // +// and quality mesh generation algorithms require other mesh elements // +// (subfaces, subsegments) be handled at the same time. The triangle-edge // +// data structure from Muecke is adopted for this purpose. Handling // +// these data types together is through a set of fast mesh manipulation // +// primitives. References of these two data structures are found below: // +// // +// J. R. Shewchuk, "Delaunay Refinement Mesh Generation". PhD thesis, // +// Carnegie Mellon University, 1997. // +// // +// E. P. Muecke, "Shapes and Implementations in Three-Dimensional // +// Geometry". PhD thesis, Univ. of Illinois, Urbana, Illinois, 1993. // +// // +// The research of mesh generation is definitly on the move. A lot of state- // +// of-the-art algorithms need to be implemented and evaluated. I heartily // +// welcome new algorithms especially for quality conforming Delaunay mesh // +// generation and anisotropic conforming Delaunay mesh generation. If you // +// have any idea on new approaches, please please kindly let me know. // +// // +// TetGen is supported by the "pdelib" project of Weierstrass Institute for // +// Applied Analysis and Stochastics (WIAS) in Berlin. It is a collection // +// of software components for solving non-linear partial differential // +// equations including 2D and 3D mesh generators, sparse matrix solvers, // +// and scientific visualization tools, etc. For more information please // +// see: http://www.wias-berlin.de/software/pdelib. // +// // +/////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// +// // +// tetgen.h // +// // +// Header file of the TetGen library. Also is the user-level header file. // +// // +/////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// +// // +// TetGen Library Overview // +// // +// TetGen library is comprised by several data types and global functions. // +// // +// If you quickly go through this file, you will find there are only three // +// main data types defined, which are "tetgenio", "tetgenbehavior", and // +// "tetgenmesh". Tetgenio is used to pass data into and out of mesh routines // +// of the library; tetgenbehavior sets the command line options selected by // +// user and thus controls the behaviors of TetGen; tetgenmesh, the biggest // +// data type I've ever defined, contains everything for creating Delaunay // +// tetrahedralizations and tetrahedral meshes. These data types are defined // +// as C++ classes. // +// // +// There are few global functions as well. "tetrahedralize()" is the (only) // +// user interface for calling TetGen from other programs. Two functions // +// "orient3d()" and "insphere()" are incorporated from a public C code for // +// performing exact geometrical tests. // +// // +/////////////////////////////////////////////////////////////////////////////// + +#ifndef tetgenH +#define tetgenH + +// To compile TetGen as a library (e.g. libtet.a) but not as an executable +// program, define the TETLIBRARY symbol. The library of TetGen can be +// linked with programs which want to call TetGen as a function. + +// #define TETLIBRARY + +// Uncomment the following line to disable assert macros. These macros are +// inserted in places where I hope to catch bugs. Somewhat, they slow down +// the speed of TetGen. They can be ignored by adding the -DNDEBUG +// compiler switch or uncomment the following line + +// #define NDEBUG + +// To insert lots of self-checks for internal errors, define the SELF_CHECK +// symbol. This will slow down the program significantly. + +// #define SELF_CHECK + +// For single precision ( which will save some memory and reduce paging ), +// define the symbol SINGLE by using the -DSINGLE compiler switch or by +// writing "#define SINGLE" below. +// +// For double precision ( which will allow you to refine meshes to a smaller +// edge length), leave SINGLE undefined. + +// #define SINGLE + +#ifdef SINGLE + #define REAL float +#else + #define REAL double +#endif // not defined SINGLE + +// Here is the most general used head files for all C/C++ codes + +#include <stdio.h> // Standard IO: FILE, NULL, EOF, printf(), ... +#include <stdlib.h> // Standard lib: abort(), system(), getenv(), ... +#include <string.h> // String lib: strcpy(), strcat(), strcmp(), ... +#include <math.h> // Math lib: sin(), sqrt(), pow(), ... +#include <assert.h> + +/////////////////////////////////////////////////////////////////////////////// +// // +// The tetgenio data type // +// // +// Used to pass data into and out of the library of TetGen. // +// // +// If you want to program with the library of TetGen, it's necessary for you // +// to understand the tetgenio data type, while the other two data types can // +// be hidden through calling the global function "tetrahedralize()". As you // +// will see below, that basically tetgenio is nothing more than a collection // +// of arrays. These arrays are used to store points, tetrahedra, (triangular)// +// faces, boundary markers, and so forth. They are used to describe data in // +// input & output files of TetGen. If you understand TetGen's file formats, // +// then it is straighforward for you to understand these arrays. The file // +// formats of TetGen are described in the third section of the user's manual.// +// // +// Once you create an object of tetgenio, all arrays are initialized to NULL.// +// This is done by routine "initialize()", it is automatically called by the // +// constructor. Before you set data into these arrays, you need to allocate // +// enough memory for them. After you use the object, you need to clear the // +// memory occupied by these arrays. Routine "deinitialize()" will be auto- // +// matically called on deletion of the object. It will clear the memory in // +// each array if it is not a NULL. However, it assumes that the memory is // +// allocated by C++ operator 'new'. If you use malloc() to allocate memory, // +// you should free them yourself, after they're freed, call "initialize()" // +// once to disable "deinitialize()". // +// // +// In all cases, the first item in any array is stored starting at index [0].// +// However, that item is item number `firstnumber' which may be '0' or '1'. // +// Be sure to set the 'firstnumber' be '1' if your indices pointing into the // +// pointlist is starting from '1'. Default, it is initialized be '0'. // +// // +// Tetgenio also contains routines for reading and writing TetGen's files as // +// well. Both the library of TetGen and TetView use these routines to parse // +// input files, i.e., .node, .poly, .smesh, .ele, .face, and .edge files. // +// Other routines are provided mainly for debugging purpose. // +// // +/////////////////////////////////////////////////////////////////////////////// + +class tetgenio { + + public: + + // Maximum number of characters in a file name (including the null). + enum {FILENAMESIZE = 1024}; + + // Maxi. numbers of chars in a line read from a file (incl. the null). + enum {INPUTLINESIZE = 1024}; + + // The polygon data structure. A "polygon" is a planar polygon. It can + // be arbitrary shaped (convex or non-convex) and bounded by non- + // crossing segments, i.e., the number of vertices it has indictes the + // same number of edges. + // 'vertexlist' is a list of vertex indices (integers), its length is + // indicated by 'numberofvertices'. The vertex indices are odered in + // either counterclockwise or clockwise way. + typedef struct { + int *vertexlist; + int numberofvertices; + } polygon; + + static void init(polygon* p) { + p->vertexlist = (int *) NULL; + p->numberofvertices = 0; + } + + // The facet data structure. A "facet" is a planar facet. It is used + // to represent a planar straight line graph (PSLG) in two dimension. + // A PSLG contains a list of polygons. It also may conatin holes in it, + // indicated by a list of hole points (their coordinates). + typedef struct { + polygon *polygonlist; + int numberofpolygons; + REAL *holelist; + int numberofholes; + } facet; + + static void init(facet* f) { + f->polygonlist = (polygon *) NULL; + f->numberofpolygons = 0; + f->holelist = (REAL *) NULL; + f->numberofholes = 0; + } + + public: + + // Items are numbered starting from 'firstnumber' (0 or 1), default is 0. + int firstnumber; + + // Dimension of the mesh (2 or 3), default is 3. + int mesh_dim; + + // `pointlist': An array of point coordinates. The first point's x + // coordinate is at index [0] and its y coordinate at index [1], its + // z coordinate is at index [2], followed by the coordinates of the + // remaining points. Each point occupies three REALs. + // `pointattributelist': An array of point attributes. Each point's + // attributes occupy `numberofpointattributes' REALs. + // 'addpointlist': An array of additional point coordinates. + // `pointmarkerlist': An array of point markers; one int per point. + REAL *pointlist; + REAL *pointattributelist; + REAL *addpointlist; + int *pointmarkerlist; + int numberofpoints; + int numberofpointattributes; + int numberofaddpoints; + + // `elementlist': An array of element (triangle or tetrahedron) corners. + // The first element's first corner is at index [0], followed by its + // other corners in counterclockwise order, followed by any other + // nodes if the element represents a nonlinear element. Each element + // occupies `numberofcorners' ints. + // `elementattributelist': An array of element attributes. Each + // element's attributes occupy `numberofelementattributes' REALs. + // `elementconstraintlist': An array of constraints, i.e. triangle's + // area or tetrahedron's volume; one REAL per element. Input only. + // `neighborlist': An array of element neighbors; 3 or 4 ints per + // element. Output only. + int *tetrahedronlist; + REAL *tetrahedronattributelist; + REAL *tetrahedronvolumelist; + int *neighborlist; + int numberoftetrahedra; + int numberofcorners; + int numberoftetrahedronattributes; + + // `facetlist': An array of facets. Each entry is a structure of facet. + // `facetmarkerlist': An array of facet markers; one int per facet. + facet *facetlist; + int *facetmarkerlist; + int numberoffacets; + + // `holelist': An array of holes. The first hole's x, y and z + // coordinates are at indices [0], [1] and [2], followed by the + // remaining holes. Three REALs per hole. + REAL *holelist; + int numberofholes; + + // `regionlist': An array of regional attributes and area or volume + // constraints. The first constraint's x, y and z coordinates are at + // indices [0], [1] and [2], followed by the regional attribute and + // index [3], followed by the maximum area or volume at index [4], + // followed by the remaining area or volume constraints. Five REALs + // per constraint. + // Note that each regional attribute is used only if you select the `A' + // switch, and each constraint is used only if you select the `a' + // switch (with no number following), but omitting one of these + // switches does not change the memory layout. + REAL *regionlist; + int numberofregions; + + // `trifacelist': An array of triangular face endpoints. The first + // face's endpoints are at indices [0], [1] and [2], followed by the + // remaining faces. Three ints per face. + // `trifacemarkerlist': An array of face markers; one int per face. + int *trifacelist; + int *trifacemarkerlist; + int numberoftrifaces; + + // `edgelist': An array of edge endpoints. The first edge's endpoints + // are at indices [0] and [1], followed by the remaining edges. Two + // ints per edge. + // `edgemarkerlist': An array of edge markers; one int per edge. + int *edgelist; + int *edgemarkerlist; + int numberofedges; + + public: + + // Initialize routine. + void initialize(); + void deinitialize(); + + // Input & output routines. + bool load_node_call(FILE* infile, int markers, char* nodefilename); + bool load_node(char* filename); + bool load_addnodes(char* filename); + bool load_poly(char* filename); + bool load_off(char* filename); + bool load_ply(char* filename); + bool load_stl(char* filename); + bool load_medit(char* filename); + bool load_plc(char* filename, int object); + bool load_tetmesh(char* filename); + void save_nodes(char* filename); + void save_elements(char* filename); + void save_faces(char* filename); + void save_edges(char* filename); + void save_neighbors(char* filename); + void save_poly(char* filename); + + // Read line and parse string functions. + char *readline(char* string, FILE* infile, int *linenumber); + char *findnextfield(char* string); + char *readnumberline(char* string, FILE* infile, char* infilename); + char *findnextnumber(char* string); + + // Constructor and destructor. + tetgenio() {initialize();} + ~tetgenio() {deinitialize();} +}; + +/////////////////////////////////////////////////////////////////////////////// +// // +// The tetgenbehavior data type // +// // +// Used to parse command line switches and file names. // +// // +// It includes a list of variables corresponding to the commandline switches // +// for control the behavior of TetGen. These varibales are all initialized // +// to their default values. // +// // +// Routine "parse_commandline()" defined in this data type is used to change // +// the vaules of the variables. This routine accepts the standard parameters // +// ('argc' and 'argv') that pass to C/C++ main() function. It also accepts a // +// string which contains the command line options. // +// // +// You don't need to understand this data type. It can be implicitly called // +// by the global function "tetrahedralize()" defined below. The necessary // +// thing you need to know is the meaning of command line switches of TetGen. // +// They are described in the third section of the user's manual. // +// // +/////////////////////////////////////////////////////////////////////////////// + +class tetgenbehavior { + + public: + + // Labels define the objects which are acceptable by TetGen. They are + // recoggnized from the extensions of the input filenames. + // - NODES, a list of nodes (.node); + // - POLY, a piecewise linear complex (.poly or .smesh); + // - OFF, a polyhedron (.off, Geomview's file format); + // - PLY, a polyhedron (.ply, file format from gatech); + // - STL, a surface mesh (.stl, stereolithography format); + // - MEDIT, a surface mesh (.mesh, Medit's file format); + // - MESH, a tetrahedral mesh (.ele). + // If no extension is available, the imposed commandline switch + // (-p or -r) implies the object. + + enum objecttype {NONE, NODES, POLY, OFF, PLY, STL, MEDIT, MESH}; + + // Variables of command line switches. After each variable are the + // corresponding switch and its default value. Read the user's manul + // or online instructions to find out the meaning of these switches. + + int plc; // '-p' switch, 0. + int refine; // '-r' switch, 0. + int quality; // '-q' switch, 0. + REAL minratio; // number after '-q' switch, 2.0. + REAL goodratio; // number calculated from 'minratio', 0.0. + REAL minangle; // minimum angle bound, 20.0. + REAL goodangle; // cosine squared of minangle, 0.0. + int varvolume; // '-a' switch without number, 0. + int fixedvolume; // '-a' switch with number, 0. + REAL maxvolume; // number after '-a' switch, -1.0. + int removesliver; // '-s' switch, 0. + REAL maxdihedral; // number after '-s' switch, 0.0. + int insertaddpoints; // '-i' switch, 0. + int regionattrib; // '-A' switch, 0. + REAL epsilon; // number after '-T' switch, 1.0e-8. + int nomerge; // not merge two coplanar facets, '-M' switch, 0. + int detectinter; // '-d' switch, 0. + int checkclosure; // '-c' switch, 0. + int zeroindex; // '-z' switch, 0. + int jettison; // '-j' switch, 0. + int order; // element order, specified after '-o' switch, 1. + int facesout; // '-f' switch, 0. + int edgesout; // '-e' switch, 0. + int neighout; // '-n' switch, 0. + int meditview; // '-g' switch, 0. + int gidview; // '-G' switch, 0. + int geomview; // '-O' switch, 0. + int nobound; // '-B' switch, 0. + int nonodewritten; // '-N' switch, 0. + int noelewritten; // '-E' switch, 0. + int nofacewritten; // '-F' switch, 0. + int noiterationnum; // '-I' switch, 0. + int nobisect; // count of how often '-Y' switch is selected, 0. + int noflip; // do not perform flips. '-Y' switch. 0. + int steiner; // number after '-S' switch. 0. + int dopermute; // do permutation. '-P' switch, 0. + int srandseed; // number of a random seed after '-P' switch, 1. + int docheck; // '-C' switch, 0. + int quiet; // '-Q' switch, 0. + int verbose; // count of how often '-V' switch is selected, 0. + int useshelles; // '-p', '-r', '-q', 'd', or 'c' switch, 0. + enum objecttype object; // determined by -p, or -r switch. NONE. + + // Variables used to save command line switches and in/out file names. + char commandline[1024]; + char infilename[1024]; + char outfilename[1024]; + + // Default initialize and de-initialize functions. + tetgenbehavior(); + ~tetgenbehavior() {} + + void versioninfo(); + void syntax(); + void usage(); + + // Command line parse routine. + bool parse_commandline(int argc, char **argv); + bool parse_commandline(char *switches) { + return parse_commandline(0, &switches); + } +}; + +/////////////////////////////////////////////////////////////////////////////// +// // +// Geometric predicates // +// // +// TetGen uses two basic geometric predicates, which are orientation test, // +// and locally Delaunay test (insphere test). // +// // +// Orientation test: let a, b, c be a sequence of 3 points in R^3 and are // +// not collinear, there exists a unique plane H passes through them. Let H+ // +// H- be the two spaces separated by H, which are defined as follows (using // +// left-hand rule): make a fist using your left hand in such a way that your // +// fingers follow the order of a, b and c, then your thumb is pointing to H+.// +// The orientation test is to determine whether another point d lies in H+ // +// (also say that d has positive orientation), or in H- (also say that d has // +// negative orientation), or on H (zero orientation). // +// // +// Locally Delaunay test (insphere test): let a, b, c, d be 4 points in R^3 // +// and are not coplanar, there exists a unique circumsphere S passes through // +// these 4 points. The task is to check if another point e lies outside, on // +// or inside S. // +// // +// The following routines use arbitrary precision floating-point arithmetic // +// to implement these geometric predicates. They are fast and robust. It is // +// provided by J. R. Schewchuk in public domain. See the following link: // +// http://www.cs.cmu.edu/~quake/robust.html. The source code are found in a // +// separate file "predicates.cxx". // +// // +/////////////////////////////////////////////////////////////////////////////// + +REAL exactinit(); +REAL orient3d(REAL *pa, REAL *pb, REAL *pc, REAL *pd); +REAL insphere(REAL *pa, REAL *pb, REAL *pc, REAL *pd, REAL *pe); + +/////////////////////////////////////////////////////////////////////////////// +// // +// The tetgenmesh data type // +// // +// Includes data types and mesh routines for Delaunay tetrahedralizations // +// and tetrahedral meshes. // +// // +// An object of tetgenmesh can be used to store a triangular or tetrahedral // +// mesh and its settings. TetGen's functions operates on one mesh each time. // +// This type allows reusing of the same function for different meshes. // +// // +// The mesh data structure (tetrahedron-based and triangle-edge data struct- // +// ures) are declared in this data type. There are other accessary data type // +// defined as well, they are used for efficient memory management and fast // +// link list operations, etc. // +// // +// All algorithms TetGen used are implemented in this data type as member // +// functions. References of these algorithms can be found in user's manual. // +// // +// You don't need to study this data type if you only want to use TetGen's // +// library to create tetrahedral mesh. The global function "tetrahedralize()"// +// implicitly creates the object and calls its member functions due to the // +// command line switches you used. // +// // +/////////////////////////////////////////////////////////////////////////////// + +class tetgenmesh { + + public: + + // Maximum number of characters in a file name (including the null). + enum {FILENAMESIZE = 1024}; + + // For efficiency, a variety of data structures are allocated in bulk. + // The following constants determine how many of each structure is + // allocated at once. + enum {VERPERBLOCK = 4092, SUBPERBLOCK = 4092, ELEPERBLOCK = 8188}; + + // Used for the point location scheme of Mucke, Saias, and Zhu, to + // decide how large a random sample of tetrahedra to inspect. + enum {SAMPLEFACTOR = 11}; + + // Labels that signify two edge rings of a triangle defined in Muecke's + // triangle-edge data structure, one (CCW) traversing edges in count- + // erclockwise direction and one (CW) in clockwise direction. + enum {CCW = 0, CW = 1}; + + // Labels that signify whether a record consists primarily of pointers + // or of floating-point words. Used to make decisions about data + // alignment. + enum wordtype {POINTER, FLOATINGPOINT}; + + // Labels that signify the type of a vertex. An UNUSEDVERTEX is a vertex + // read from input (.node file or tetgenio structure) or an isolated + // vertex (outside the mesh). It is the default type for a newpoint. + enum verttype {UNUSEDVERTEX, NONACUTEVERTEX, ACUTEVERTEX, FREESEGVERTEX, + FACETVERTEX, PROTCYLSPHVERTEX, FREECYLSPHVERTEX, + PROTCYLVERTEX, PROTSPHVERTEX, FREECYLVERTEX, + FREESPHVERTEX, FREESUBVERTEX, FREEVOLVERTEX, + DUPLICATEDVERTEX, DEADVERTEX = -32768}; + + // Labels that signify the type of a subsegment or a subface. An input + // (sub)segment may have type NONSHARPSEGMENT, SHARPSEGMENT. Segments + // preceding with "PROT" are artificially created for protecting the + // internal region of cylinders and spheres. A subface may have one of + // the three types PROTCYLSUBFACE, PROTSPHSUBFACE, and NONPROTSUBFACE. + enum shestype {NONSHARPSEGMENT, SHARPSEGMENT, PROTCYLSEGMENT, + PROTSPHSEGMENT, PROTCYLSUBFACE, PROTSPHSUBFACE, + NONPROTSUBFACE}; + + // Labels that signify the type of flips which can be applied on a face. + // A flipable face has one of the types T23, T32, T22, and T44. Types + // NONCONVEX, FORBIDDEN and UNFLIPABLE indicate non-flipable faces. + enum fliptype {T23, T32, T22, T44, UNFLIPABLE, FORBIDDENFACE, + FORBIDDENEDGE, NONCONVEX}; + + // Labels that signify the type of a bad tetrahedron. + enum badtettype {SKINNY, CAP, SLIVER, ILLEGAL}; + + // Labels that signify the result of triangle-triangle intersection. + // The result indicates that two triangles t1 and t2 are completely + // DISJOINT, or adjoint only at a vertex SHAREVERTEX, or adjoint at + // an edge SHAREEDGE, or coincident SHAREFACE, or INTERSECT. + enum intersectresult {DISJOINT, SHAREVERTEX, SHAREEDGE, SHAREFACE, + INTERSECT}; + + // Labels that signify the result of point location. The result of a + // search indicates that the point falls inside a tetrahedron, inside + // a triangle, on an edge, on a vertex, or outside the mesh. + enum locateresult {INTETRAHEDRON, ONFACE, ONEDGE, ONVERTEX, OUTSIDE}; + + // Labels that signify the result of vertex insertion. The result + // indicates that the vertex was inserted with complete success, was + // inserted but encroaches upon a subsegment, was not inserted because + // it lies on a segment, or was not inserted because another vertex + // occupies the same location. + enum insertsiteresult {SUCCESSINTET, SUCCESSONFACE, SUCCESSONEDGE, + ENCROACHINGPOINT, DUPLICATEPOINT, OUTSIDEPOINT}; + + // Labels that signify the result of direction finding. The result + // indicates that a segment connecting the two query points accross + // an edge of the direction triangle/tetrahedron, across a face of + // the direction tetrahedron, along the left edge of the direction + // triangle/tetrahedron, along the right edge of the direction + // triangle/tetrahedron, or along the top edge of the tetrahedron. + enum finddirectionresult {ACROSSEDGE, ACROSSFACE, LEFTCOLLINEAR, + RIGHTCOLLINEAR, TOPCOLLINEAR, BELOWHULL}; + +/////////////////////////////////////////////////////////////////////////////// +// // +// The basic mesh element data structures // +// // +// There are four types of mesh elements: tetrahedra, subfaces, subsegments, // +// and points, where subfaces and subsegments are triangles and edges which // +// appear on boundaries. A tetrahedralization of a 3D point set comprises // +// tetrahedra and points; a surface mesh of a 3D domain comprises subfaces // +// (triangles), subsegments and points; and it is the elements of all the // +// four types consist of a tetrahedral mesh of a 3D domain. However, TetGen // +// uses three data types: 'tetrahedron', 'shellface', and 'point' to repres- // +// ent the basic mesh elements. A 'tetrahedron' is a tetrahedron; while a // +// 'shellface' can represent either a subface or a subsegment; and a 'point' // +// represent a point. Theese three data types, linked by pointers comprise // +// a tetrahedralization or a mesh. // +// // +// The data type 'tetrahedron' primarily consists of a list of four pointers // +// to its corners, a list of four pointers to its adjoining tetrahedra, a // +// list of four pointers to its adjoining subfaces(when subfaces are needed).// +// Optinoally, (depending on the selected switches), it may contain an arbi- // +// trary number of user-defined floating-point attributes, an optional max- // +// imum volume constraint (-a switch), and a pointer to a list of high-order // +// nodes (-o2 switch). Because the size of a tetrahedron is not determined // +// until running time, it is not simply declared as a structure. // +// // +// For purpose of storing geometric information, it is important to know the // +// ordering of the vertices of a tetrahedron. Let v0, v1, v2, and v3 be the // +// four nodes corresponding to the order of their storage in a tetrahedron. // +// v3 always has negative orientation with respect to v0, v1, v2 (in other // +// words, v3 lies above the oriented plane passes through v0, v1, v2). Let // +// the four faces of the tetrahedron be f0, f1, f2, and f3. Vertices of each // +// face are stipulated as follows: f0 (v0, v1, v2), f1 (v0, v3, v1), f2 (v1, // +// v3, v2), f3 (v2, v3, v0). Adjoining tetrahedra as well as subfaces are // +// stored in the order of its faces, e.g., the first adjoining tetrahedra is // +// the neighbor at f0, and so on. // +// // +// A subface is represented by the data type 'shellface'. It has three // +// pointers to its vertices, three pointers to its adjoining subfaces, three // +// pointers to subsegments, two pointers to its adjoining tetrahedra, and a // +// boundary marker (an integer). Furthermore, the pointers to vertices, // +// adjoining subfaces, and subsegments are ordered in a way that indicates // +// their geometric relation. Let the three vertices according to the order // +// of their storage be v0, v1 and v2, respectively, and e0, e1 and e2 be the // +// three edges, then we have: e0 (v0, v1), e1 (v1, v2), e2 (v2, v0). Adjoin- // +// ing subfaces and subsegments are stored in the order of its edges. // +// // +// A subsegment is also represented by a 'shellface'. It has exactly the // +// same data fields as a subface has, but only uses some of them. It has two // +// pointers to its endpoints, two pointers to its adjoining (and collinear) // +// subsegments, one pointer to a subface containing it (there may exist any // +// number of subfaces having it, choose one of them arbitrarily). The geome- // +// tric relation between its endpoints and adjoining (collinear) subsegments // +// is kept with respect to the storing order of its endpoints. The adjoining // +// subsegment at the first endpoint is saved ahead of the other. // +// // +// The data type 'point' is relatively simple. A point is a list of floating // +// -point numbers, starting with the x, y, and z coordinates, followed by an // +// arbitrary number of optional user-defined floating-point attributes, an // +// integer boundary marker, an integer for the point type, and a pointer to // +// a tetrahedron. The latter is used for speeding up point location during // +// the mesh generation. // +// // +// For a tetrahedron on a boundary (or a hull) of the mesh, some or all of // +// the adjoining tetrahedra may not be present. For an interior tetrahedron, // +// often no neighboring subfaces are present, Such absent tetrahedra and // +// subfaces are never represented by the NULL pointers; they are represented // +// by two special records: `dummytet', the tetrahedron fills "outer space", // +// and `dummysh', the vacuous subfaces which are omnipresent. // +// // +// Tetrahedra and adjoining subfaces are glued together through the pointers // +// saved in each data fields of them. Subfaces and adjoining subsegments are // +// connected in the same fashion. However, there are no pointers directly // +// gluing tetrahedra and adjoining subsegments. For the purpose of saving // +// space, the connections between tetrahedra and subsegments are entirely // +// mediated through subfaces. The following part is an explaination of how // +// subfaces are connected in TetGen. // +// // +/////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// +// // +// The subface-subface and subface-subsegment connections // +// // +// Adjoining subfaces sharing a common edge are connected in such a way that // +// they form a face ring around the edge. It is in deed a single linked list // +// which is cyclic, e.g., one can start from any subface in it and traverse // +// back. When the edge is not a subsegment, the ring only has two coplanar // +// subfaces which are pointing to each other. Otherwise, the face ring may // +// have any number of subfaces (and are not all coplanar). // +// // +// The face ring around a subsegment is formed as follows. Let s be a sub- // +// segment, and f be a subface containing s as an edge. The direction of s // +// is stipulated from its first endpoint to its second (the first and second // +// endpoints are according to their storage in s). When the direction of s // +// is determined, other two edges of f are oriented following this direction.// +// The "directional normal" of f is a ray starts from any point in f, points // +// to the direction of the cross product of any of two edge vectors of f. // +// // +// The face ring of s is a cyclic ordered set of subfaces containing s, i.e.,// +// F(s) = {f1, f2, ..., fn}, n >= 1. Where the order is defined as follows: // +// let fi, fj be two faces in F(s), the "normal-angle", nangle(i,j) (range // +// from 0 to 360 degree) is the angle between the directional normals of fi // +// and fj; that fi is in front of fj (or symbolically, fi < fj) if there // +// exists another fk in F(s), and nangle(k, i) < nangle(k, j). The face ring // +// of s can be represented as: f1 < f2 < ... < fn < f1. // +// // +// The easiest way to imagine how a face ring is formed is to use the right- // +// hand rule. Make a fist using your right hand with the thumb pointing to // +// the direction of the subsegment. The face ring is connected following the // +// direction of your fingers. // +// // +// The subface and subsegment are also connected through pointers stored in // +// their own data fields. Every subface has a pointer ti its adjoining sub- // +// segment. However, a subsegment only has one pointer to a subface which is // +// containing it. Such subface can be choosn arbitrarily, other subfaces are // +// found through the face ring. // +// // +/////////////////////////////////////////////////////////////////////////////// + + // The tetrahedron data structure. Fields of a tetrahedron contains: + // - a list of four adjoining tetrahedra; + // - a list of four vertices; + // - a list of four subfaces (optional, used for -p switch); + // - a list of user-defined floating-point attributes (optional); + // - a volume constraint (optional, used for -a switch); + // - a pointer to a list of high-ordered nodes (optional, -o2 switch); + + typedef REAL **tetrahedron; + + // The shellface data structure. Fields of a shellface contains: + // - a list of three adjoining subfaces; + // - a list of three vertices; + // - a list of two adjoining tetrahedra; + // - a list of three adjoining subsegments; + // - a pointer to a badface containing it (optional, used for -q); + // - an area constraint (optional, used for -q); + // - an integer for boundary marker; + // - an integer for type: SHARPSEGMENT, NONSHARPSEGMENT, ...; + + typedef REAL **shellface; + + // The point data structure. It is actually an array of REALs: + // - x, y and z coordinates; + // - a list of user-defined point attributes (optional); + // - a pointer to a simplex (tet, tri, edge, or vertex); + // - a pointer to a parent point (optional, used for -q); + // - an integer for boundary marker; + // - an integer for verttype: INPUTVERTEX, FREEVERTEX, ...; + + typedef REAL *point; + +/////////////////////////////////////////////////////////////////////////////// +// // +// The mesh handle (triface, face) data types // +// // +// Two special data types, 'triface' and 'face' are defined for maintaining // +// and updating meshes. They are like pointers (or handles), which allow you // +// to hold one particular part of the mesh, i.e., a tetrahedron, a triangle, // +// an edge and a vertex. However, these data types do not themselves store // +// any part of the mesh. The mesh is made of the data types defined above. // +// // +// Muecke's "triangle-edge" data structure is the prototype for these data // +// types. It allows a universal representation for every tetrahedron, // +// triangle, edge and vertex. For understanding the following descriptions // +// of these handle data structures, readers are required to read both the // +// introduction and implementation detail of "triangle-edge" data structure // +// in Muecke's thesis. // +// // +// A 'triface' represents a face of a tetrahedron and an oriented edge of // +// the face simultaneously. It has a pointer 'tet' to a tetrahedron, an // +// integer 'loc' (range from 0 to 3) as the face index, and an integer 'ver' // +// (range from 0 to 5) as the edge version. A face of the tetrahedron can be // +// uniquly determined by the pair (tet, loc), and an oriented edge of this // +// face can be uniquly determined by the triple (tet, loc, ver). Therefore, // +// different usages of one triface are possible. If we only use the pair // +// (tet, loc), it refers to a face, and if we add the 'ver' additionally to // +// the pair, it is an oriented edge of this face. // +// // +// A 'face' represents a subface and an oriented edge of it simultaneously. // +// It has a pointer 'sh' to a subface, an integer 'shver'(range from 0 to 5) // +// as the edge version. The pair (sh, shver) determines a unique oriented // +// edge of this subface. A 'face' is also used to represent a subsegment, // +// in this case, 'sh' points to the subsegment, and 'shver' indicates the // +// one of two orientations of this subsegment, hence, it only can be 0 or 1. // +// // +// Mesh navigation and updating are accomplished through a set of mesh // +// manipulation primitives which operate on trifaces and faces. They are // +// introduced below. // +// // +/////////////////////////////////////////////////////////////////////////////// + + class triface { + + public: + + tetrahedron* tet; + int loc, ver; + + // Constructors; + triface() : tet(0), loc(0), ver(0) {} + // Operators; + triface& operator=(const triface& t) { + tet = t.tet; loc = t.loc; ver = t.ver; + return *this; + } + bool operator==(triface& t) { + return tet == t.tet && loc == t.loc && ver == t.ver; + } + bool operator!=(triface& t) { + return tet != t.tet || loc != t.loc || ver != t.ver; + } + }; + + class face { + + public: + + shellface *sh; + int shver; + + // Constructors; + face() : sh(0), shver(0) {} + // Operators; + face& operator=(const face& s) { + sh = s.sh; shver = s.shver; + return *this; + } + bool operator==(face& s) {return (sh == s.sh) && (shver == s.shver);} + bool operator!=(face& s) {return (sh != s.sh) || (shver != s.shver);} + }; + +/////////////////////////////////////////////////////////////////////////////// +// // +// The badface structure // +// // +// This structure has several usages in TetGen. A 'badface' can represent a // +// tetrahedron face possibly be non-locally Delaunay and will be flipped if // +// it is. A 'badface' can hold an encroached subsegment or subface needs to // +// be split in conforming Delaunay process. // +// // +// A badface has the following fields: 'tt' points to a tetrahedral face // +// which is possibly non-locally Delaunay. 'ss' points to an encroached // +// subsegment or subface. 'cent' is the diametric circumcent of the 'shface',// +// Three vertices 'forg', 'fdest' and 'fapex' are stored so that one can // +// check whether a face is still the same. 'prevface' and 'nextface' are // +// used to implement a double link for managing many badfaces. // +// // +/////////////////////////////////////////////////////////////////////////////// + + struct badface { + triface tt; + face ss; + REAL cent[3]; + point forg, fdest, fapex, foppo; + struct badface *prevface, *nextface; + }; + + // A queue structure used to store bad tetrahedra. Each tetrahedron's + // vertices are stored so that one can check whether a tetrahedron is + // still the same. + + struct badtetrahedron { + triface tet; // A bad tet. + REAL key; // radius-edge ratio^2. + REAL cent[3]; // The circumcenters' coordinates. + point tetorg, tetdest, tetapex, tetoppo; // The four vertices. + struct badtetrahedron *nexttet; // Pointer to next bad tet. + }; + + // A stack of faces flipped during the most recent vertex insertion. + // The stack is used to undo the point insertion if the point + // encroaches upon other subfaces or subsegments. + + struct flipstacker { + triface flippedface; // A recently flipped face. + enum fliptype fc; // The flipped type T23, T32, T22 or T44. + point forg, fdest, fapex; // The three vertices for checking. + struct flipstacker *prevflip; // Previous flip in the stack. + }; + +/////////////////////////////////////////////////////////////////////////////// +// // +// The list, link and queue data structures // +// // +// These data types are used to manipulate a set of (same-typed) data items. // +// For a given set S = {a, b, c, ...}, a list stores the elements of S in a // +// piece of continuous memory. It allows quickly accessing each element of S,// +// thus is suitable for storing a fix-sized set. While a link stores its // +// elements incontinuously. It allows quickly inserting or deleting one item,// +// thus is good for storing a size-changable set. A queue is basically a // +// special case of a link where one data element joins the link at the end // +// and leaves in an ordered fashion at the other end. // +// // +// These data types are all implemented with dynamic memory re-allocation. // +// // +/////////////////////////////////////////////////////////////////////////////// + + // The compfunc data type. "compfunc" is a pointer to a linear-order + // function, which takes two 'void*' arguments and returning an 'int'. + // + // A function: int cmp(const T &, const T &), is said to realize a + // linear order on the type T if there is a linear order <= on T such + // that for all x and y in T satisfy the following relation: + // -1 if x < y. + // comp(x, y) = 0 if x is equivalent to y. + // +1 if x > y. + typedef int (*compfunc) (const void *, const void *); + + // The predefined compare functions for primitive data types. They + // take two pointers of the corresponding date type, perform the + // comparation, and return -1, 0 or 1 indicating the default linear + // order of them. + + // Compare two 'integers'. + static int compare_2_ints(const void* x, const void* y); + // Compare two 'longs'. + static int compare_2_longs(const void* x, const void* y); + // Compare two 'unsigned longs'. + static int compare_2_unsignedlongs(const void* x, const void* y); + + // The function used to determine the size of primitive data types and + // set the corresponding predefined linear order functions for them. + static void set_compfunc(char* str, int* itembytes, compfunc* pcomp); + +/////////////////////////////////////////////////////////////////////////////// +// // +// List data structure. // +// // +// A 'list' is an array of items with automatically reallocation of memory. // +// It behaves like an array. // +// // +// 'base' is the starting address of the array; The memory unit in list is // +// byte, i.e., sizeof(char). 'itembytes' is the size of each item in byte, // +// so that the next item in list will be found at the next 'itembytes' // +// counted from the current position. // +// // +// 'items' is the number of items stored in list. 'maxitems' indicates how // +// many items can be stored in this list. 'expandsize' is the increasing // +// size (items) when the list is full. // +// // +// 'comp' is a pointer pointing to a linear order function for the list. // +// default it is set to 'NULL'. // +// // +// The index of list always starts from zero, i.e., for a list L contains // +// n elements, the first element is L[0], and the last element is L[n-1]. // +// This feature lets lists likes C/C++ arrays. // +// // +/////////////////////////////////////////////////////////////////////////////// + + class list { + + public: + + char *base; + int itembytes; + int items, maxitems, expandsize; + compfunc comp; + + public: + + list(int itbytes, compfunc pcomp, int mitems = 256, int exsize = 128) { + listinit(itbytes, pcomp, mitems, exsize); + } + list(char* str, int mitems = 256, int exsize = 128) { + set_compfunc(str, &itembytes, &comp); + listinit(itembytes, comp, mitems, exsize); + } + ~list() { free(base); } + + void *operator[](int i) { return (void *) (base + i * itembytes); } + + void listinit(int itbytes, compfunc pcomp, int mitems, int exsize); + void setcomp(compfunc compf) { comp = compf; } + void clear() { items = 0; } + int len() { return items; } + void *append(void* appitem); + void *insert(int pos, void* insitem); + void del(int pos); + int hasitem(void* checkitem); + int remove(void* remitem); + void sort(); + }; + +/////////////////////////////////////////////////////////////////////////////// +// // +// Memorypool data structure. // +// // +// A type used to allocate memory. (It is incorporated from Shewchuk's // +// Triangle program) // +// // +// firstblock is the first block of items. nowblock is the block from which // +// items are currently being allocated. nextitem points to the next slab // +// of free memory for an item. deaditemstack is the head of a linked list // +// (stack) of deallocated items that can be recycled. unallocateditems is // +// the number of items that remain to be allocated from nowblock. // +// // +// Traversal is the process of walking through the entire list of items, and // +// is separate from allocation. Note that a traversal will visit items on // +// the "deaditemstack" stack as well as live items. pathblock points to // +// the block currently being traversed. pathitem points to the next item // +// to be traversed. pathitemsleft is the number of items that remain to // +// be traversed in pathblock. // +// // +// itemwordtype is set to POINTER or FLOATINGPOINT, and is used to suggest // +// what sort of word the record is primarily made up of. alignbytes // +// determines how new records should be aligned in memory. itembytes and // +// itemwords are the length of a record in bytes (after rounding up) and // +// words. itemsperblock is the number of items allocated at once in a // +// single block. items is the number of currently allocated items. // +// maxitems is the maximum number of items that have been allocated at // +// once; it is the current number of items plus the number of records kept // +// on deaditemstack. // +// // +/////////////////////////////////////////////////////////////////////////////// + + class memorypool { + + public: + + void **firstblock, **nowblock; + void *nextitem; + void *deaditemstack; + void **pathblock; + void *pathitem; + wordtype itemwordtype; + int alignbytes; + int itembytes, itemwords; + int itemsperblock; + long items, maxitems; + int unallocateditems; + int pathitemsleft; + + public: + + memorypool(); + memorypool(int, int, enum wordtype, int); + ~memorypool(); + + void poolinit(int, int, enum wordtype, int); + void restart(); + void *alloc(); + void dealloc(void*); + void traversalinit(); + void *traverse(); + }; + +/////////////////////////////////////////////////////////////////////////////// +// // +// Link data structure. // +// // +// A 'link' is a double linked nodes. It uses the memorypool data structure // +// for memory management. Following is an image of a link. // +// // +// head-> ____0____ ____1____ ____2____ _________<-tail // +// |__next___|--> |__next___|--> |__next___|--> |__NULL___| // +// |__NULL___|<-- |__prev___|<-- |__prev___|<-- |__prev___| // +// | | |_ _| |_ _| | | // +// | | |_ Data1 _| |_ Data2 _| | | // +// |_________| |_________| |_________| |_________| // +// // +// The unit size for storage is size of pointer, which may be 4-byte (in 32- // +// bit machine) or 8-byte (in 64-bit machine). The real size of an item is // +// stored in 'linkitembytes'. // +// // +// 'head' and 'tail' are pointers pointing to the first and last nodes. They // +// do not conatin data (See above). // +// // +// 'nextlinkitem' is a pointer pointing to a node which is the next one will // +// be traversed. 'curpos' remembers the position (1-based) of the current // +// traversing node. // +// // +// 'linkitems' indicates how many items in link. Note it is different with // +// 'items' of memorypool. // +// // +// The index of link starts from 1, i.e., for a link K contains n elements, // +// the first element of the link is K[1], and the last element is K[n]. // +// See the above figure. // +// // +/////////////////////////////////////////////////////////////////////////////// + + class link : public memorypool { + + public: + + void **head, **tail; + void *nextlinkitem; + int linkitembytes; + int linkitems; + int curpos; + compfunc comp; + + public: + + link(int _itembytes, compfunc _comp, int itemcount) { + linkinit(_itembytes, _comp, itemcount); + } + link(char* str, int itemcount) { + set_compfunc(str, &linkitembytes, &comp); + linkinit(linkitembytes, comp, itemcount); + } + + void linkinit(int _itembytes, compfunc _comp, int itemcount); + void setcomp(compfunc compf) { comp = compf; } + void rewind() { nextlinkitem = *head; curpos = 1; } + void goend() { nextlinkitem = *(tail + 1); curpos = linkitems; } + long len() { return linkitems; } + void clear(); + bool move(int numberofnodes); + bool locate(int pos); + void *add(void* newitem); + void *insert(int pos, void* insitem); + void *del(void* delitem); + void *del(int pos); + void *getitem(); + void *getnitem(int pos); + int hasitem(void* checkitem); + }; + +/////////////////////////////////////////////////////////////////////////////// +// // +// Queue data structure. // +// // +// A 'queue' is a basically a link. Following is an image of a queue. // +// ___________ ___________ ___________ // +// Pop() <-- |_ _|<--|_ _|<--|_ _| <-- Push() // +// |_ Data0 _| |_ Data1 _| |_ Data2 _| // +// |___________| |___________| |___________| // +// queue head queue tail // +// // +/////////////////////////////////////////////////////////////////////////////// + + class queue : public link { + + public: + + queue(int bytes, int count = 256) : link(bytes, NULL, count) {} + queue(char* str, int count = 256) : link(str, count) {} + + int empty() { return linkitems == 0; } + void *push(void* newitem) { return link::add(newitem); } + void *bot() { return link::getnitem(1); } + void *pop() { return link::del(1); } + }; + +/////////////////////////////////////////////////////////////////////////////// +// // +// Following are variables used in 'tetgenmesh' for miscellaneous purposes. // +// // +/////////////////////////////////////////////////////////////////////////////// + + // Pointer to an object of 'tetgenio', which contains input data. + tetgenio *in; + + // Pointer to an object of 'tetgenbehavor', which contains the user- + // defined command line swithes and filenames. + tetgenbehavior *b; + + // Variables used to allocate and access memory for tetrahedra, subfaces + // subsegments, points, encroached subfaces, encroached subsegments, + // bad-quality tetrahedra, and so on. + memorypool *tetrahedrons; + memorypool *subfaces; + memorypool *subsegs; + memorypool *points; + memorypool *badsubsegs; + memorypool *badsubfaces; + memorypool *badtetrahedrons; + memorypool *flipstackers; + + // Pointer to a recently visited tetrahedron. Improves point location + // if proximate points are inserted sequentially. + triface recenttet; + + // Pointer to the 'tetrahedron' that occupies all of "outer space". + tetrahedron *dummytet; + tetrahedron *dummytetbase; // Keep base address so we can free it later. + + // Pointer to the omnipresent subface. Referenced by any tetrahedron, + // or subface that isn't connected to a subface at that location. + shellface *dummysh; + shellface *dummyshbase; // Keep base address so we can free it later. + + // List of lifting points of facets used for surface triangulation. + REAL *liftpointarray; + + // List used for Delaunay refinement algorithm. + list *qualchecktetlist; + + // Queues that maintain the bad (badly-shaped or too large) tetrahedra. + // The tails are pointers to the pointers that have to be filled in to + // enqueue an item. The queues are ordered from 63 (highest priority) + // to 0 (lowest priority). + badface *subquefront[2], **subquetail[2]; + badtetrahedron *tetquefront[64], **tetquetail[64]; + + // Array (size = numberoftetrahedra * 6) for storing high-order nodes of + // tetrahedra (only used when -o2 switch is selected). + point *highordertable; + + REAL xmax, xmin, ymax, ymin, zmax, zmin; // Bounding box of points. + REAL longest; // The longest possible edge length. + long hullsize; // Number of faces of convex hull. + long insegment; // Number of input segments. + int steinerleft; // Number of Steiner points not yet used. + int pointmarkindex; // Index to find boundary marker of a point. + int point2simindex; // Index to find a simplex adjacent to a point. + int highorderindex; // Index to find extra nodes for highorder elements. + int elemattribindex; // Index to find attributes of a tetrahedron. + int volumeboundindex; // Index to find volume bound of a tetrahedron. + int shmarkindex; // Index to find boundary marker of a subface. + int areaboundindex; // Index to find area bound of a subface. + int checksubfaces; // Are there subfaces in the mesh yet? + int checkquality; // Has quality triangulation begun yet? + int nonconvex; // Is current mesh non-convex? + int dupverts; // Are there duplicated vertices? + long samples; // Number of random samples for point location. + unsigned long randomseed; // Current random number seed. + REAL macheps; // The machine epsilon. + long flip23s, flip32s, flip22s, flip44s; // Number of flips performed. + +/////////////////////////////////////////////////////////////////////////////// +// // +// Fast lookup tables for mesh manipulation primitives. // +// // +// Mesh manipulation primitives (given below) are basic operations on mesh // +// data structures. They answer basic queries on mesh handles, such as "what // +// is the origin (or destination, or apex) of the face?", "what is the next // +// (or previous) edge in the edge ring?", and "what is the next face in the // +// face ring?", and so on. // +// // +// The implementation of basic queries can take advangtage of the fact that // +// the mesh data structures additionally store geometric informations. For // +// example, we have ordered the four vertices (from 0 to 3) and four faces // +// (from 0 to 3) of a tetrahedron, and for each face of the tetrahedron, a // +// sequence of vertices has stipulated, therefore the origin of any face of // +// the tetrahedron can be quickly determined by a table 'locver2org', which // +// takes the index of the face and the edge version as inputs. A list of // +// fast lookup tables are defined below. They're just like global variables. // +// All tables are initialized once at the runtime and used by all objects of // +// tetgenmesh. // +// // +/////////////////////////////////////////////////////////////////////////////// + + // For enext() primitive, uses 'ver' as the index. + static int ve[6]; + + // For org(), dest() and apex() primitives, uses 'ver' as the index. + static int vo[6], vd[6], va[6]; + + // For org(), dest() and apex() primitives, uses 'loc' as the first + // index and 'ver' as the second index. + static int locver2org[4][6]; + static int locver2dest[4][6]; + static int locver2apex[4][6]; + + // For oppo() primitives, uses 'loc' as the index. + static int loc2oppo[4]; + + // For fnext() primitives, uses 'loc' as the first index and 'ver' as + // the second index, returns an array containing a new 'loc' and a + // new 'ver'. Note: Only valid for 'ver' equals one of {0, 2, 4}. + static int locver2nextf[4][6][2]; + + // For enumerating three edges of a triangle. + static int plus1mod3[3]; + static int minus1mod3[3]; + +/////////////////////////////////////////////////////////////////////////////// +// // +// Mesh manipulation primitives // +// // +// A serial of mesh operations such as topological maintenance, navigation, // +// local modification, etc., is accomplished through a set of mesh manipul- // +// ation primitives. These primitives are indeed very simple functions which // +// take one or two handles ('triface's and 'face's) as parameters, perform // +// basic operations such as "glue two tetrahedra at a face", "return the // +// origin of a tetrahedron", "return the subface adjoining at the face of a // +// tetrahedron", and so on. // +// // +// In the following, symbols t, t1, and t2 denote handles of type 'triface', // +// i.e., t is a face of a tetrahedron. Likewise, handles of type 'face' are // +// denoted by s, s1, s2; e denotes an oriented edge, and v denotes a vertex. // +// // +// The basic primitives for tetrahedra are: // +// // +// sym(t1, t2) t1 and t2 refer to the same face but point to two // +// different tetrahedra respectively. // +// bond(t1, t2) Bonds t1 and t2 together. t1 and t2 should refer to // +// the same face. // +// dissolve(t) Detaches the adjoining tetrahedron from t. t bonds to // +// 'dummytet' after this operation. // +// // +// v = org(t) v is the origin of t. // +// v = dest(t) v is the destination of t. // +// v = apex(t) v is the apex of t. // +// v = oppo(t) v is the opposite of t. // +// // +// esym(t1, t2) t2 is the inversed edge of t1, i.e., t1 and t2 are two // +// directed edges of the same undirected edge. // +// enext(t1, t2) t2 is the successor of t1 in the edge ring. // +// enext2(t1, t2) t2 is the precessor of t1 in the edge ring. // +// // +// fnext(t1, t2) t2 is the successor of t1 in the face ring. // +// // +// The basic primitives for subfaces (as well as subsegments) are: // +// // +// spivot(s1, s2) s1 and s2 refer to the same edge but point to two // +// different subfaces respectively. // +// sbond(s1, s2) Bonds s1 and s2 together (at an edge). // +// sbond1(s1, s2) Only bonds s2 to s1 (but not s1 to s2). It is used // +// for creating the face ring. // +// sdissolve(s) Detaches the adjoining subface from s. s bonds to // +// 'dummysh' after this operation. // +// // +// v = sorg(s) v is the origin of s. // +// v = sdest(s) v is the destination of s. // +// v = sapex(s) v is the apex of s. // +// // +// sesym(s1, s2) s2 is the inversed edge of s1. // +// senext(s1, s2) s2 is the successor of s1 in the edge ring. // +// senext2(s1, s2) s2 is the precessor of s1 in the edge ring.. // +// // +// For interacting tetrahedra and subfaces: // +// // +// tspivot(t, s) Returns the adjoining subface of t in s. s may hold // +// 'dummysh' when t is an internal face. // +// stpivot(s, t) Returns the adjoining tetrahedron of s in t. t may be // +// 'dummytet'. // +// tsbond(t, s) Bond t and s together. t and s must represent the // +// same face. // +// tsdissolve(t) Detaches the adjoining subface from t. // +// stdissolve(s) Detaches the adjoining tetrahedron from s. // +// // +// For interacting subfaces and subsegments: // +// // +// sspivot(s, e) Returns the adjoining subsegment of s in e. // +// ssbond(s, e) Bond s and e together. s and e must represent the // +// same edge. // +// ssdissolve(s) Detaches the adjoining subsegment from s. // +// // +/////////////////////////////////////////////////////////////////////////////// + + // Primitives for tetrahedra. + inline void decode(tetrahedron ptr, triface& t); + inline tetrahedron encode(triface& t); + inline void sym(triface& t1, triface& t2); + inline void symself(triface& t); + inline void bond(triface& t1, triface& t2); + inline void dissolve(triface& t); + inline point org(triface& t); + inline point dest(triface& t); + inline point apex(triface& t); + inline point oppo(triface& t); + inline void setorg(triface& t, point pointptr); + inline void setdest(triface& t, point pointptr); + inline void setapex(triface& t, point pointptr); + inline void setoppo(triface& t, point pointptr); + inline void esym(triface& t1, triface& t2); + inline void esymself(triface& t); + inline void enext(triface& t1, triface& t2); + inline void enextself(triface& t); + inline void enext2(triface& t1, triface& t2); + inline void enext2self(triface& t); + inline bool fnext(triface& t1, triface& t2); + inline bool fnextself(triface& t); + inline void enextfnext(triface& t1, triface& t2); + inline void enextfnextself(triface& t); + inline void enext2fnext(triface& t1, triface& t2); + inline void enext2fnextself(triface& t); + inline void infect(triface& t); + inline void uninfect(triface& t); + inline bool infected(triface& t); + inline REAL elemattribute(tetrahedron* ptr, int attnum); + inline void setelemattribute(tetrahedron* ptr, int attnum, REAL value); + inline REAL volumebound(tetrahedron* ptr); + inline void setvolumebound(tetrahedron* ptr, REAL value); + + // Primitives for subfaces and subsegments. + inline void sdecode(shellface sptr, face& s); + inline shellface sencode(face& s); + inline void spivot(face& s1, face& s2); + inline void spivotself(face& s); + inline void sbond(face& s1, face& s2); + inline void sbond1(face& s1, face& s2); + inline void sdissolve(face& s); + inline point sorg(face& s); + inline point sdest(face& s); + inline point sapex(face& s); + inline void setsorg(face& s, point pointptr); + inline void setsdest(face& s, point pointptr); + inline void setsapex(face& s, point pointptr); + inline void sesym(face& s1, face& s2); + inline void sesymself(face& s); + inline void senext(face& s1, face& s2); + inline void senextself(face& s); + inline void senext2(face& s1, face& s2); + inline void senext2self(face& s); + inline void sfnext(face&, face&); + inline void sfnextself(face&); + inline badface* shell2badface(face& s); + inline void setshell2badface(face& s, badface* value); + inline REAL areabound(face& s); + inline void setareabound(face& s, REAL value); + inline int shellmark(face& s); + inline void setshellmark(face& s, int value); + inline enum shestype shelltype(face& s); + inline void setshelltype(face& s, enum shestype value); + inline void sinfect(face& s); + inline void suninfect(face& s); + inline bool sinfected(face& s); + + // Primitives for interacting tetrahedra and subfaces. + inline void tspivot(triface& t, face& s); + inline void stpivot(face& s, triface& t); + inline void tsbond(triface& t, face& s); + inline void tsdissolve(triface& t); + inline void stdissolve(face& s); + + // Primitives for interacting subfaces and subsegs. + inline void sspivot(face& s, face& edge); + inline void ssbond(face& s, face& edge); + inline void ssdissolve(face& s); + + // Primitives for points. + inline int pointmark(point pt); + inline void setpointmark(point pt, int value); + inline enum verttype pointtype(point pt); + inline void setpointtype(point pt, enum verttype value); + inline tetrahedron point2tet(point pt); + inline void setpoint2tet(point pt, tetrahedron value); + inline shellface point2sh(point pt); + inline void setpoint2sh(point pt, shellface value); + inline point point2pt(point pt); + inline void setpoint2pt(point pt, point value); + inline point point2ppt(point pt); + inline void setpoint2ppt(point pt, point value); + inline point getliftpoint(int facetmark); + + // Advanced primitives. + inline void adjustedgering(triface& t, int direction); + inline void adjustedgering(face& s, int direction); + inline bool isdead(triface* t); + inline bool isdead(face* s); + inline bool isfacehaspoint(face* t, point testpoint); + inline bool isfacehasedge(face* s, point tend1, point tend2); + inline bool issymexist(triface* t); + bool getnextface(triface*, triface*); + void getnextsface(face*, face*); + void tsspivot(triface*, face*); + void sstpivot(face*, triface*); + bool findorg(triface* t, point dorg); + bool findorg(face* s, point dorg); + void findedge(triface* t, point eorg, point edest); + void findedge(face* s, point eorg, point edest); + void findface(triface *fface, point forg, point fdest, point fapex); + void getonextseg(face* s, face* lseg); + void getseghasorg(face* sseg, point dorg); + point getsubsegfarorg(face* sseg); + point getsubsegfardest(face* sseg); + void printtet(triface*); + void printsh(face*); + +/////////////////////////////////////////////////////////////////////////////// +// // +// Primitive geometric test functions // +// // +// A primitive operation is a function f that maps a set Q of k objects to // +// +1, 0, or -1. Primitive geometric functions operater on geometric objects // +// (points, segments, triangles, polyhedron, etc), determine the geometric // +// relations between them. Like the orientation of a sequence of d+1 points // +// in d-dimension, whether or not a point lies inside a triangle, and so on. // +// Algorithms for solving geometric problems are always based on the answers // +// of some primitives so that the corresponding deterministic rules can be // +// applied. However, the implementation of geometric algorithms is not a // +// trivial task even for one which is very simple and only relies on few // +// primitives. The correctness of primitives is crucial for the cotrol flow. // +// // +// The following functions perform various primitives geometric tests, some // +// perform tests with exact arithmetic and some do not. // +// // +// The triangle-triangle intersection test is implemented with exact arithm- // +// etic. It exactly tells whether or not two triangles in three dimensions // +// intersect. Before implementing this test myself, I tried two C codes // +// (implemented by Thomas Moeller and Philippe Guigue, respectively), which // +// are all public available and very efficient. However both of them failed // +// frequently. Another unsuitable problem is that both codes only tell // +// whether or not two triangles are intersecting and not distinguish the // +// cases whether they are exactly intersecting in interior or they share a // +// vertex, or share an edge. All the latter cases are acceptable and should // +// return not intersection in TetGen. // +// // +/////////////////////////////////////////////////////////////////////////////// + + // Triangle-triangle intersection tests + enum intersectresult edge_vertex_collinear_inter(REAL*, REAL*, REAL*); + enum intersectresult edge_edge_coplanar_inter(REAL*, REAL*, REAL*, + REAL*, REAL*); + enum intersectresult triangle_vertex_coplanar_inter(REAL*, REAL*, REAL*, + REAL*, REAL*); + enum intersectresult triangle_edge_coplanar_inter(REAL*, REAL*, REAL*, + REAL*, REAL*, REAL*); + enum intersectresult triangle_edge_inter_tail(REAL*, REAL*, REAL*, REAL*, + REAL*, REAL, REAL); + enum intersectresult triangle_edge_inter(REAL*, REAL*, REAL*, REAL*, + REAL*); + enum intersectresult triangle_triangle_inter(REAL*, REAL*, REAL*, REAL*, + REAL*, REAL*); + + // Degenerate cases tests + bool iscollinear(REAL*, REAL*, REAL*, REAL epspp); + bool iscoplanar(REAL*, REAL*, REAL*, REAL*, REAL vol6, REAL epspp); + bool iscospheric(REAL*, REAL*, REAL*, REAL*, REAL*, REAL epspp); + + // Linear algebra functions + inline REAL dot(REAL* v1, REAL* v2); + inline void cross(REAL* v1, REAL* v2, REAL* n); + void initm44(REAL a00, REAL a01, REAL a02, REAL a03, + REAL a10, REAL a11, REAL a12, REAL a13, + REAL a20, REAL a21, REAL a22, REAL a23, + REAL a30, REAL a31, REAL a32, REAL a33, REAL M[4][4]); + void m4xm4(REAL m1[4][4], REAL m2[4][4]); + void m4xv4(REAL v2[4], REAL m[4][4], REAL v1[4]); + bool lu_decmp(REAL lu[3][3], int n, int* ps, REAL* d, int N); + void lu_solve(REAL lu[3][3], int n, int* ps, REAL* b, int N); + + // Geometric quantities calculators. + inline REAL distance(REAL* p1, REAL* p2); + REAL shortdistance(REAL* p, REAL* e1, REAL* e2); + REAL interiorangle(REAL* o, REAL* p1, REAL* p2, REAL* n); + void projpt2edge(REAL* p, REAL* e1, REAL* e2, REAL* prj); + void projpt2face(REAL* p, REAL* f1, REAL* f2, REAL* f3, REAL* prj); + void facenormal(REAL* pa, REAL* pb, REAL* pc, REAL* n, REAL* nlen); + void edgeorthonormal(REAL* e1, REAL* e2, REAL* op, REAL* n); + REAL facedihedral(REAL* pa, REAL* pb, REAL* pc1, REAL* pc2); + void tetalldihedral(point, point, point, point, REAL dihed[6]); + bool circumsphere(REAL*, REAL*, REAL*, REAL*, REAL* cent, REAL* radius); + void inscribedsphere(REAL*, REAL*, REAL*, REAL*, REAL* cent, REAL* radius); + void rotatepoint(REAL* p, REAL rotangle, REAL* p1, REAL* p2); + void spherelineint(REAL* p1, REAL* p2, REAL* C, REAL R, REAL p[7]); + void linelineint(REAL *p1,REAL *p2, REAL *p3, REAL *p4, REAL p[7]); + + // Memory managment routines. + void dummyinit(int, int); + void initializepointpool(); + void initializetetshpools(); + void tetrahedrondealloc(tetrahedron*); + tetrahedron *tetrahedrontraverse(); + void shellfacedealloc(memorypool*, shellface*); + shellface *shellfacetraverse(memorypool*); + void badfacedealloc(memorypool*, badface*); + badface *badfacetraverse(memorypool*); + void pointdealloc(point); + point pointtraverse(); + void maketetrahedron(triface*); + void makeshellface(memorypool*, face*); + void makepoint(point*); + + // Mesh items searching routines. + void makepoint2tetmap(); + void makeindex2pointmap(point*& idx2verlist); + void makesegmentmap(int*& idx2seglist, shellface**& segsperverlist); + void makesubfacemap(int*& idx2facelist, shellface**& facesperverlist); + void maketetrahedronmap(int*& idx2tetlist, tetrahedron**& tetsperverlist); + + // Point location routines. + unsigned long randomnation(unsigned int choices); + REAL distance2(tetrahedron* tetptr, point p); + enum locateresult preciselocate(point searchpoint, triface* searchtet); + enum locateresult locate(point searchpoint, triface* searchtet); + enum locateresult adjustlocate(point searchpoint, triface* searchtet, + enum locateresult precise, REAL epspp); + + // Mesh transformation routines. + enum fliptype categorizeface(triface& horiz); + void enqueueflipface(triface& checkface, queue* flipqueue); + void enqueueflipedge(face& checkedge, queue* flipqueue); + void flip23(triface* flipface, queue* flipqueue); + void flip32(triface* flipface, queue* flipqueue); + void flip22(triface* flipface, queue* flipqueue); + void flip22sub(face* flipedge, queue* flipqueue); + long flip(queue* flipqueue, flipstacker **plastflip); + void undoflip(flipstacker *lastflip); + + void splittetrahedron(point newpoint, triface* splittet, queue* flipqueue); + void unsplittetrahedron(triface* splittet); + void splittetface(point newpoint, triface* splittet, queue* flipqueue); + void unsplittetface(triface* splittet); + void splitsubface(point newpoint, face* splitface, queue* flipqueue); + void unsplitsubface(face* splitsh); + void splittetedge(point newpoint, triface* splittet, queue* flipqueue); + void unsplittetedge(triface* splittet); + void splitsubedge(point newpoint, face* splitsh, queue* flipqueue); + void unsplitsubedge(face* splitsh); + enum insertsiteresult insertsite(point newpoint, triface* searchtet, + bool approx, queue* flipqueue); + void undosite(enum insertsiteresult insresult, triface* splittet, + point torg, point tdest, point tapex, point toppo); + void inserthullsite(point inspoint, triface* horiz, queue* flipqueue, + link* hulllink, int* worklist); + void collectcavtets(point newpoint, list* cavtetlist); + + void removetetbypeeloff(triface *badtet, queue* flipqueue); + void removetetbyflip32(triface *badtet, queue* flipqueue); + bool removetetbycflips(triface *badtet, queue* flipqueue); + bool removebadtet(enum badtettype bt, triface *badtet, queue* flipqueue); + + // Incremental flip Delaunay triangulation routines. + void incrflipinit(queue* insertqueue); + long incrflipdelaunay(); + + // Surface triangulation routines. + enum locateresult locatesub(point searchpt, face* searchsh, point abovept); + long flipsub(queue* flipqueue); + bool incrflipinitsub(int facetidx, list* ptlist, point* idx2verlist); + void collectvisiblesubs(int facetidx, point inspoint, face* horiz, + queue* flipqueue); + void incrflipdelaunaysub(int facetidx, list* ptlist, point* idx2verlist, + queue* flipqueue); + enum finddirectionresult finddirectionsub(face* searchsh, point tend); + void insertsubseg(face* tri); + bool scoutsegmentsub(face* searchsh, point tend); + void delaunayfixup(face* fixupsh, int leftside); + void constrainededge(face* startsh, point tend); + void insertsegmentsub(point tstart, point tend); + void infecthullsub(memorypool* viri); + void plaguesub(memorypool* viri); + void carveholessub(int holes, REAL* holelist); + void triangulatefacet(int facetidx, list* ptlist, list* conlist, + point* idx2verlist, queue* flipqueue); + void unifysegments(); + void mergefacets(queue* flipqueue); + long meshsurface(); + + // Detect intersecting facets of PLC. + void interecursive(shellface** subfacearray, int arraysize, int axis, + REAL bxmin, REAL bxmax, REAL bymin, REAL bymax, + REAL bzmin, REAL bzmax, int* internum); + void detectinterfaces(); + + // Segments recovery routines. + void markacutevertices(REAL acuteangle); + enum finddirectionresult finddirection(triface* searchtet, point tend); + void getsearchtet(point p1, point p2, triface* searchtet, point* tend); + bool isedgeencroached(point p1, point p2, point testpt, bool degflag); + point scoutrefpoint(triface* searchtet, point tend); + point getsegmentorigin(face* splitseg); + point getsplitpoint(face* splitseg, point refpoint); + void delaunizesegments(); + + // Constrained Delaunay triangulation routines. + bool insertsubface(face* insertsh, triface* searchtet); + bool tritritest(triface* checktet, point p1, point p2, point p3); + void initializecavity(list* floorlist, list* ceillist, list* floorptlist, + list* ceilptlist, link* frontlink, link* ptlink); + bool reducecavity(link* frontlink, link* ptlink, queue* flipqueue); + bool reducecavity1(link* frontlink, queue* flipqueue); + void triangulatecavity(list* floorlist, list* ceillist, list* floorptlist, + list* ceilptlist); + void formmissingregion(face* missingsh, list* missingshlist, + list* equatptlist, int* worklist); + bool scoutcrossingedge(list* missingshlist, list* boundedgelist, + list* crossedgelist, int* worklist); + void rearrangesubfaces(list* missingshlist, list* boundedgelist, + list* equatptlist, int* worklist); + void recoversubfaces(list* missingshlist, list* crossedgelist, + list* equatptlist, int* worklist); + void constrainedfacets(); + + // Carving out holes and concavities routines. + void indenthull(); + void infecthull(memorypool *viri); + void plague(memorypool *viri); + void regionplague(memorypool *viri, REAL attribute, REAL volume); + void carveholes(); + + // Mesh update rotuines. + long reconstructmesh(); + void insertaddpoints(); + + // Delaunay refinement routines. + void initializerpsarray(REAL* rpsarray); + void marksharpfacets(int*& idx2facetlist, REAL dihedbound); + void enqueuebadtet(triface *instet, REAL ratio, point insorg, + point insdest, point insapex, point insoppo, + point inscent); + badtetrahedron* dequeuebadtet(); + bool checkseg4encroach(face* testseg, point testpt, bool enqueueflag); + bool checksub4encroach(face* testsub, point testpt, bool enqueueflag); + bool checksub4badqual(face* testsub); + bool checktet4badqual(triface* testtet); + bool checktet4illtet(triface* testtet, list* illtetlist); + bool checktet4sliver(triface* testtet, list* illtetlist); + bool checkseg4splitting(face* testseg, REAL* rpsarray, bool bqual); + bool checksub4splitting(face* testsub); + void doqualchecktetlist(); + bool tallencsegs(point testpt, list *cavtetlist); + bool tallencsubs(point testpt, list *cavtetlist); + void tallbadtetrahedrons(); + void tallilltets(list* illtetlist); + void tallslivers(list* illtetlist); + void removeilltets(); + void removeslivers(); + void repairencsegs(REAL* rpsarray, bool bqual, queue* flipqueue); + void repairencsubs(REAL* rpsarray, int* idx2facetlist, list* cavtetlist, + queue* flipqueue); + void repairbadtets(REAL* rpsarray, int* idx2facetlist, list* cavtetlist, + queue* flipqueue); + void enforcequality(); + + // I/O routines + void transfernodes(); + void jettisonnodes(); + void highorder(); + void outnodes(tetgenio* out); + void outelements(tetgenio* out); + void outfaces(tetgenio* out); + void outhullfaces(tetgenio* out); + void outsubfaces(tetgenio* out); + void outsubsegments(tetgenio* out); + void outneighbors(tetgenio* out); + void outsmesh(char* smfilename); + void outmesh2medit(char* mfilename); + void outmesh2gid(char* gfilename); + void outmesh2off(char* ofilename); + + // User interaction routines. + void internalerror(); + void checkmesh(); + void checkshells(); + void checkdelaunay(queue* flipqueue); + void checkconforming(); + void qualitystatistics(); + void statistics(); + + public: + + // Constructor and destructor. + tetgenmesh(); + ~tetgenmesh(); + +}; // End of class tetgenmesh. + +/////////////////////////////////////////////////////////////////////////////// +// // +// tetrahedralize() Interface for using TetGen's library to generate // +// Delaunay tetrahedralizations, constrained Delaunay // +// tetrahedralizations, quality tetrahedral meshes. // +// // +// Two functions (interfaces) are available. The difference is only the way // +// of passing switches. One directly accepts an object of 'tetgenbehavior', // +// the other accepts a string which is the same as one can used in command // +// line. The latter may be more convenient for users who don't know the // +// 'tetgenbehavir' structure. // +// // +// 'in' is the input object containing a PLC or a list of points. It should // +// not be a NULL. 'out' is for outputting the mesh or tetrahedralization // +// created by TetGen. If it is NULL, the output will be redirect to file(s). // +// // +/////////////////////////////////////////////////////////////////////////////// + +void tetrahedralize(tetgenbehavior *b, tetgenio *in, tetgenio *out); +void tetrahedralize(char *switches, tetgenio *in, tetgenio *out); + +#endif // #ifndef tetgenH diff --git a/contrib/Triangle/Makefile b/contrib/Triangle/Makefile new file mode 100644 index 0000000000..f032dbb4e9 --- /dev/null +++ b/contrib/Triangle/Makefile @@ -0,0 +1,55 @@ +# $Id: Makefile,v 1.1 2005-09-21 17:29:40 geuzaine Exp $ +# +# Copyright (C) 1997-2005 C. Geuzaine, J.-F. Remacle +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +# USA. +# +# Please report all bugs and problems to <gmsh@geuz.org>. + +include ../../variables + +LIB = ../../lib/libGmshTriangle.a + +# Don't optimize triangle: it crashes on Linux +# CFLAGS = ${OPTIM} ${FLAGS} -DTRILIBRARY +CFLAGS = ${FLAGS} -DTRILIBRARY + +SRC = triangle.c + +OBJ = ${SRC:.c=.o} + +.SUFFIXES: .o .c + +${LIB}: ${OBJ} + ${AR} ${LIB} ${OBJ} + ${RANLIB} ${LIB} + +.c.o: + ${CC} ${CFLAGS} -c $< + +clean: + rm -f *.o + +depend: + (sed '/^# DO NOT DELETE THIS LINE/q' Makefile && \ + ${CC} -MM ${CFLAGS} ${SRC} \ + ) >Makefile.new + cp Makefile Makefile.bak + cp Makefile.new Makefile + rm -f Makefile.new + +# DO NOT DELETE THIS LINE +triangle.o: triangle.c triangle.h diff --git a/contrib/Triangle/README b/contrib/Triangle/README new file mode 100644 index 0000000000..8570b1e278 --- /dev/null +++ b/contrib/Triangle/README @@ -0,0 +1,74 @@ + +If you want to use Jonathan Shewchuk's Triangle as an alternative +isotropic 2D mesh generator in Gmsh, please download Triangle from the +author's web site at http://www.cs.cmu.edu/~quake/triangle.html, +unpack the archive and copy the two files 'triangle.c' and +'triangle.h' in this directory. Then run configure and rebuild Gmsh. + +Please note that by doing so, you agree to Triangle's licensing +requirements (stated below). Most notably, you can only redistribute +Gmsh if no compensation is received. + +============================================================================== + +Triangle +A Two-Dimensional Quality Mesh Generator and Delaunay Triangulator. +Version 1.5 + +Copyright 1993, 1995, 1997, 1998, 2002, 2004 Jonathan Richard Shewchuk +2360 Woolsey #H +Berkeley, California 94705-1927 +Please send bugs and comments to jrs@cs.berkeley.edu + +Created as part of the Archimedes project (tools for parallel FEM). +Supported in part by NSF Grant CMS-9318163 and an NSERC 1967 Scholarship. +There is no warranty whatsoever. Use at your own risk. + + +Triangle generates exact Delaunay triangulations, constrained Delaunay +triangulations, Voronoi diagrams, and quality conforming Delaunay +triangulations. The latter can be generated with no small angles, and are +thus suitable for finite element analysis. Show Me graphically displays +the contents of the geometric files used by Triangle. Show Me can also +write images in PostScript form. + +Information on the algorithms used by Triangle, including complete +references, can be found in the comments at the beginning of the triangle.c +source file. Another listing of these references, with PostScript copies +of some of the papers, is available from the Web page + + http://www.cs.cmu.edu/~quake/triangle.research.html + +------------------------------------------------------------------------------ + +These programs may be freely redistributed under the condition that the +copyright notices (including the copy of this notice in the code comments +and the copyright notice printed when the `-h' switch is selected) are +not removed, and no compensation is received. Private, research, and +institutional use is free. You may distribute modified versions of this +code UNDER THE CONDITION THAT THIS CODE AND ANY MODIFICATIONS MADE TO IT +IN THE SAME FILE REMAIN UNDER COPYRIGHT OF THE ORIGINAL AUTHOR, BOTH +SOURCE AND OBJECT CODE ARE MADE FREELY AVAILABLE WITHOUT CHARGE, AND +CLEAR NOTICE IS GIVEN OF THE MODIFICATIONS. Distribution of this code as +part of a commercial system is permissible ONLY BY DIRECT ARRANGEMENT +WITH THE AUTHOR. (If you are not directly supplying this code to a +customer, and you are instead telling them how they can obtain it for +free, then you are not required to make any arrangement with me.) + +------------------------------------------------------------------------------ + +If you use Triangle, and especially if you use it to accomplish real +work, I would like very much to hear from you. A short letter or email +(to jrs@cs.cmu.edu) describing how you use Triangle will mean a lot to +me. The more people I know are using this program, the more easily I can +justify spending time on improvements and on the three-dimensional +successor to Triangle, which in turn will benefit you. Also, I can put +you on a list to receive email whenever a new version of Triangle is +available. + +If you use a mesh generated by Triangle or plotted by Show Me in a +publication, please include an acknowledgment as well. + + +Jonathan Richard Shewchuk +April 27, 2004 diff --git a/contrib/Triangle/triangle.c b/contrib/Triangle/triangle.c new file mode 100644 index 0000000000..203100baca --- /dev/null +++ b/contrib/Triangle/triangle.c @@ -0,0 +1,16008 @@ +/*****************************************************************************/ +/* */ +/* 888888888 ,o, / 888 */ +/* 888 88o88o " o8888o 88o8888o o88888o 888 o88888o */ +/* 888 888 888 88b 888 888 888 888 888 d888 88b */ +/* 888 888 888 o88^o888 888 888 "88888" 888 8888oo888 */ +/* 888 888 888 C888 888 888 888 / 888 q888 */ +/* 888 888 888 "88o^888 888 888 Cb 888 "88oooo" */ +/* "8oo8D */ +/* */ +/* A Two-Dimensional Quality Mesh Generator and Delaunay Triangulator. */ +/* (triangle.c) */ +/* */ +/* Version 1.5 */ +/* April 27, 2004 */ +/* */ +/* Copyright 1993, 1995, 1997, 1998, 2002, 2004 */ +/* Jonathan Richard Shewchuk */ +/* 2360 Woolsey #H */ +/* Berkeley, California 94705-1927 */ +/* jrs@cs.berkeley.edu */ +/* */ +/* This program may be freely redistributed under the condition that the */ +/* copyright notices (including this entire header and the copyright */ +/* notice printed when the `-h' switch is selected) are not removed, and */ +/* no compensation is received. Private, research, and institutional */ +/* use is free. You may distribute modified versions of this code UNDER */ +/* THE CONDITION THAT THIS CODE AND ANY MODIFICATIONS MADE TO IT IN THE */ +/* SAME FILE REMAIN UNDER COPYRIGHT OF THE ORIGINAL AUTHOR, BOTH SOURCE */ +/* AND OBJECT CODE ARE MADE FREELY AVAILABLE WITHOUT CHARGE, AND CLEAR */ +/* NOTICE IS GIVEN OF THE MODIFICATIONS. Distribution of this code as */ +/* part of a commercial system is permissible ONLY BY DIRECT ARRANGEMENT */ +/* WITH THE AUTHOR. (If you are not directly supplying this code to a */ +/* customer, and you are instead telling them how they can obtain it for */ +/* free, then you are not required to make any arrangement with me.) */ +/* */ +/* Hypertext instructions for Triangle are available on the Web at */ +/* */ +/* http://www.cs.cmu.edu/~quake/triangle.html */ +/* */ +/* Some of the references listed below are marked with an asterisk. [*] */ +/* These references are available for downloading from the Web page */ +/* */ +/* http://www.cs.cmu.edu/~quake/triangle.research.html */ +/* */ +/* Three papers discussing aspects of Triangle are available. A short */ +/* overview appears in "Triangle: Engineering a 2D Quality Mesh */ +/* Generator and Delaunay Triangulator," in Applied Computational */ +/* Geometry: Towards Geometric Engineering, Ming C. Lin and Dinesh */ +/* Manocha, editors, Lecture Notes in Computer Science volume 1148, */ +/* pages 203-222, Springer-Verlag, Berlin, May 1996 (from the First ACM */ +/* Workshop on Applied Computational Geometry). [*] */ +/* */ +/* The algorithms are discussed in the greatest detail in "Delaunay */ +/* Refinement Algorithms for Triangular Mesh Generation," Computational */ +/* Geometry: Theory and Applications 22(1-3):21-74, May 2002. [*] */ +/* */ +/* More detail about the data structures may be found in my dissertation: */ +/* "Delaunay Refinement Mesh Generation," Ph.D. thesis, Technical Report */ +/* CMU-CS-97-137, School of Computer Science, Carnegie Mellon University, */ +/* Pittsburgh, Pennsylvania, 18 May 1997. [*] */ +/* */ +/* Triangle was created as part of the Archimedes project in the School of */ +/* Computer Science at Carnegie Mellon University. Archimedes is a */ +/* system for compiling parallel finite element solvers. For further */ +/* information, see Hesheng Bao, Jacobo Bielak, Omar Ghattas, Loukas F. */ +/* Kallivokas, David R. O'Hallaron, Jonathan R. Shewchuk, and Jifeng Xu, */ +/* "Large-scale Simulation of Elastic Wave Propagation in Heterogeneous */ +/* Media on Parallel Computers," Computer Methods in Applied Mechanics */ +/* and Engineering 152(1-2):85-102, 22 January 1998. */ +/* */ +/* Triangle's Delaunay refinement algorithm for quality mesh generation is */ +/* a hybrid of one due to Jim Ruppert, "A Delaunay Refinement Algorithm */ +/* for Quality 2-Dimensional Mesh Generation," Journal of Algorithms */ +/* 18(3):548-585, May 1995 [*], and one due to L. Paul Chew, "Guaranteed- */ +/* Quality Mesh Generation for Curved Surfaces," Proceedings of the Ninth */ +/* Annual Symposium on Computational Geometry (San Diego, California), */ +/* pages 274-280, Association for Computing Machinery, May 1993. */ +/* */ +/* The Delaunay refinement algorithm has been modified so that it */ +/* consistently meshes domains with small input angles, as described in */ +/* my lengthy journal article listed above, or in abbreviated form in */ +/* Jonathan Richard Shewchuk, "Mesh Generation for Domains with Small */ +/* Angles," Proceedings of the Sixteenth Annual Symposium on */ +/* Computational Geometry (Hong Kong), pages 1-10, Association for */ +/* Computing Machinery, June 2000. [*] */ +/* */ +/* My implementation of the divide-and-conquer and incremental Delaunay */ +/* triangulation algorithms follows closely the presentation of Guibas */ +/* and Stolfi, even though I use a triangle-based data structure instead */ +/* of their quad-edge data structure. (In fact, I originally implemented */ +/* Triangle using the quad-edge data structure, but the switch to a */ +/* triangle-based data structure sped Triangle by a factor of two.) The */ +/* mesh manipulation primitives and the two aforementioned Delaunay */ +/* triangulation algorithms are described by Leonidas J. Guibas and Jorge */ +/* Stolfi, "Primitives for the Manipulation of General Subdivisions and */ +/* the Computation of Voronoi Diagrams," ACM Transactions on Graphics */ +/* 4(2):74-123, April 1985. */ +/* */ +/* Their O(n log n) divide-and-conquer algorithm is adapted from Der-Tsai */ +/* Lee and Bruce J. Schachter, "Two Algorithms for Constructing the */ +/* Delaunay Triangulation," International Journal of Computer and */ +/* Information Science 9(3):219-242, 1980. Triangle's improvement of the */ +/* divide-and-conquer algorithm by alternating between vertical and */ +/* horizontal cuts was introduced by Rex A. Dwyer, "A Faster Divide-and- */ +/* Conquer Algorithm for Constructing Delaunay Triangulations," */ +/* Algorithmica 2(2):137-151, 1987. */ +/* */ +/* The incremental insertion algorithm was first proposed by C. L. Lawson, */ +/* "Software for C1 Surface Interpolation," in Mathematical Software III, */ +/* John R. Rice, editor, Academic Press, New York, pp. 161-194, 1977. */ +/* For point location, I use the algorithm of Ernst P. Mucke, Isaac */ +/* Saias, and Binhai Zhu, "Fast Randomized Point Location Without */ +/* Preprocessing in Two- and Three-Dimensional Delaunay Triangulations," */ +/* Proceedings of the Twelfth Annual Symposium on Computational Geometry, */ +/* ACM, May 1996. [*] If I were to randomize the order of vertex */ +/* insertion (I currently don't bother), their result combined with the */ +/* result of Kenneth L. Clarkson and Peter W. Shor, "Applications of */ +/* Random Sampling in Computational Geometry II," Discrete & */ +/* Computational Geometry 4(1):387-421, 1989, would yield an expected */ +/* O(n^{4/3}) bound on running time. */ +/* */ +/* The O(n log n) sweepline Delaunay triangulation algorithm is taken from */ +/* Steven Fortune, "A Sweepline Algorithm for Voronoi Diagrams", */ +/* Algorithmica 2(2):153-174, 1987. A random sample of edges on the */ +/* boundary of the triangulation are maintained in a splay tree for the */ +/* purpose of point location. Splay trees are described by Daniel */ +/* Dominic Sleator and Robert Endre Tarjan, "Self-Adjusting Binary Search */ +/* Trees," Journal of the ACM 32(3):652-686, July 1985. */ +/* */ +/* The algorithms for exact computation of the signs of determinants are */ +/* described in Jonathan Richard Shewchuk, "Adaptive Precision Floating- */ +/* Point Arithmetic and Fast Robust Geometric Predicates," Discrete & */ +/* Computational Geometry 18(3):305-363, October 1997. (Also available */ +/* as Technical Report CMU-CS-96-140, School of Computer Science, */ +/* Carnegie Mellon University, Pittsburgh, Pennsylvania, May 1996.) [*] */ +/* An abbreviated version appears as Jonathan Richard Shewchuk, "Robust */ +/* Adaptive Floating-Point Geometric Predicates," Proceedings of the */ +/* Twelfth Annual Symposium on Computational Geometry, ACM, May 1996. [*] */ +/* Many of the ideas for my exact arithmetic routines originate with */ +/* Douglas M. Priest, "Algorithms for Arbitrary Precision Floating Point */ +/* Arithmetic," Tenth Symposium on Computer Arithmetic, pp. 132-143, IEEE */ +/* Computer Society Press, 1991. [*] Many of the ideas for the correct */ +/* evaluation of the signs of determinants are taken from Steven Fortune */ +/* and Christopher J. Van Wyk, "Efficient Exact Arithmetic for Computa- */ +/* tional Geometry," Proceedings of the Ninth Annual Symposium on */ +/* Computational Geometry, ACM, pp. 163-172, May 1993, and from Steven */ +/* Fortune, "Numerical Stability of Algorithms for 2D Delaunay Triangu- */ +/* lations," International Journal of Computational Geometry & Applica- */ +/* tions 5(1-2):193-213, March-June 1995. */ +/* */ +/* The method of inserting new vertices off-center (not precisely at the */ +/* circumcenter of every poor-quality triangle) is from Alper Ungor, */ +/* "Off-centers: A New Type of Steiner Points for Computing Size-Optimal */ +/* quality-guaranteed Delaunay triangulations," Proceedings of LATIN */ +/* 2004 (Buenos Aires, Argentina), April 2004. */ +/* */ +/* For definitions of and results involving Delaunay triangulations, */ +/* constrained and conforming versions thereof, and other aspects of */ +/* triangular mesh generation, see the excellent survey by Marshall Bern */ +/* and David Eppstein, "Mesh Generation and Optimal Triangulation," in */ +/* Computing and Euclidean Geometry, Ding-Zhu Du and Frank Hwang, */ +/* editors, World Scientific, Singapore, pp. 23-90, 1992. [*] */ +/* */ +/* The time for incrementally adding PSLG (planar straight line graph) */ +/* segments to create a constrained Delaunay triangulation is probably */ +/* O(t^2) per segment in the worst case and O(t) per segment in the */ +/* common case, where t is the number of triangles that intersect the */ +/* segment before it is inserted. This doesn't count point location, */ +/* which can be much more expensive. I could improve this to O(d log d) */ +/* time, but d is usually quite small, so it's not worth the bother. */ +/* (This note does not apply to conforming Delaunay triangulations, for */ +/* which a different method is used to insert segments.) */ +/* */ +/* The time for adding segments to a conforming Delaunay triangulation is */ +/* not clear, but does not depend upon t alone. In some cases, very */ +/* small features (like a vertex lying next to a segment) can cause a */ +/* single segment to be split an arbitrary number of times. Of course, */ +/* floating-point precision is a practical barrier to how much this can */ +/* happen. */ +/* */ +/* The time for deleting a vertex from a Delaunay triangulation is O(d^2) */ +/* in the worst case and O(d) in the common case, where d is the degree */ +/* of the vertex being deleted. I could improve this to O(d log d) time, */ +/* but d is usually quite small, so it's not worth the bother. */ +/* */ +/* Ruppert's Delaunay refinement algorithm typically generates triangles */ +/* at a linear rate (constant time per triangle) after the initial */ +/* triangulation is formed. There may be pathological cases where */ +/* quadratic time is required, but these never arise in practice. */ +/* */ +/* The geometric predicates (circumcenter calculations, segment */ +/* intersection formulae, etc.) appear in my "Lecture Notes on Geometric */ +/* Robustness" at http://www.cs.berkeley.edu/~jrs/mesh.html . */ +/* */ +/* If you make any improvements to this code, please please please let me */ +/* know, so that I may obtain the improvements. Even if you don't change */ +/* the code, I'd still love to hear what it's being used for. */ +/* */ +/* Disclaimer: Neither I nor Carnegie Mellon warrant this code in any way */ +/* whatsoever. This code is provided "as-is". Use at your own risk. */ +/* */ +/*****************************************************************************/ + +/* For single precision (which will save some memory and reduce paging), */ +/* define the symbol SINGLE by using the -DSINGLE compiler switch or by */ +/* writing "#define SINGLE" below. */ +/* */ +/* For double precision (which will allow you to refine meshes to a smaller */ +/* edge length), leave SINGLE undefined. */ +/* */ +/* Double precision uses more memory, but improves the resolution of the */ +/* meshes you can generate with Triangle. It also reduces the likelihood */ +/* of a floating exception due to overflow. Finally, it is much faster */ +/* than single precision on 64-bit architectures like the DEC Alpha. I */ +/* recommend double precision unless you want to generate a mesh for which */ +/* you do not have enough memory. */ + +/* #define SINGLE */ + +#ifdef SINGLE +#define REAL float +#else /* not SINGLE */ +#define REAL double +#endif /* not SINGLE */ + +/* If yours is not a Unix system, define the NO_TIMER compiler switch to */ +/* remove the Unix-specific timing code. */ + +/* #define NO_TIMER */ + +/* To insert lots of self-checks for internal errors, define the SELF_CHECK */ +/* symbol. This will slow down the program significantly. It is best to */ +/* define the symbol using the -DSELF_CHECK compiler switch, but you could */ +/* write "#define SELF_CHECK" below. If you are modifying this code, I */ +/* recommend you turn self-checks on until your work is debugged. */ + +/* #define SELF_CHECK */ + +/* To compile Triangle as a callable object library (triangle.o), define the */ +/* TRILIBRARY symbol. Read the file triangle.h for details on how to call */ +/* the procedure triangulate() that results. */ + +/* #define TRILIBRARY */ + +/* It is possible to generate a smaller version of Triangle using one or */ +/* both of the following symbols. Define the REDUCED symbol to eliminate */ +/* all features that are primarily of research interest; specifically, the */ +/* -i, -F, -s, and -C switches. Define the CDT_ONLY symbol to eliminate */ +/* all meshing algorithms above and beyond constrained Delaunay */ +/* triangulation; specifically, the -r, -q, -a, -S, and -s switches. */ +/* These reductions are most likely to be useful when generating an object */ +/* library (triangle.o) by defining the TRILIBRARY symbol. */ + +/* #define REDUCED */ +/* #define CDT_ONLY */ + +/* On some machines, my exact arithmetic routines might be defeated by the */ +/* use of internal extended precision floating-point registers. The best */ +/* way to solve this problem is to set the floating-point registers to use */ +/* single or double precision internally. On 80x86 processors, this may */ +/* be accomplished by setting the CPU86 symbol for the Microsoft C */ +/* compiler, or the LINUX symbol for the gcc compiler running on Linux. */ +/* */ +/* An inferior solution is to declare certain values as `volatile', thus */ +/* forcing them to be stored to memory and rounded off. Unfortunately, */ +/* this solution might slow Triangle down quite a bit. To use volatile */ +/* values, write "#define INEXACT volatile" below. Normally, however, */ +/* INEXACT should be defined to be nothing. ("#define INEXACT".) */ +/* */ +/* For more discussion, see http://www.cs.cmu.edu/~quake/robust.pc.html . */ +/* For yet more discussion, see Section 5 of my paper, "Adaptive Precision */ +/* Floating-Point Arithmetic and Fast Robust Geometric Predicates" (also */ +/* available as Section 6.6 of my dissertation). */ + +/* #define CPU86 */ +/* #define LINUX */ + +#define INEXACT /* Nothing */ +/* #define INEXACT volatile */ + +/* Maximum number of characters in a file name (including the null). */ + +#define FILENAMESIZE 512 + +/* Maximum number of characters in a line read from a file (including the */ +/* null). */ + +#define INPUTLINESIZE 512 + +/* For efficiency, a variety of data structures are allocated in bulk. The */ +/* following constants determine how many of each structure is allocated */ +/* at once. */ + +#define TRIPERBLOCK 4092 /* Number of triangles allocated at once. */ +#define SUBSEGPERBLOCK 508 /* Number of subsegments allocated at once. */ +#define VERTEXPERBLOCK 4092 /* Number of vertices allocated at once. */ +#define VIRUSPERBLOCK 1020 /* Number of virus triangles allocated at once. */ +/* Number of encroached subsegments allocated at once. */ +#define BADSUBSEGPERBLOCK 252 +/* Number of skinny triangles allocated at once. */ +#define BADTRIPERBLOCK 4092 +/* Number of flipped triangles allocated at once. */ +#define FLIPSTACKERPERBLOCK 252 +/* Number of splay tree nodes allocated at once. */ +#define SPLAYNODEPERBLOCK 508 + +/* The vertex types. A DEADVERTEX has been deleted entirely. An */ +/* UNDEADVERTEX is not part of the mesh, but is written to the output */ +/* .node file and affects the node indexing in the other output files. */ + +#define INPUTVERTEX 0 +#define SEGMENTVERTEX 1 +#define FREEVERTEX 2 +#define DEADVERTEX -32768 +#define UNDEADVERTEX -32767 + +/* The next line is used to outsmart some very stupid compilers. If your */ +/* compiler is smarter, feel free to replace the "int" with "void". */ +/* Not that it matters. */ + +#define VOID int + +/* Two constants for algorithms based on random sampling. Both constants */ +/* have been chosen empirically to optimize their respective algorithms. */ + +/* Used for the point location scheme of Mucke, Saias, and Zhu, to decide */ +/* how large a random sample of triangles to inspect. */ + +#define SAMPLEFACTOR 11 + +/* Used in Fortune's sweepline Delaunay algorithm to determine what fraction */ +/* of boundary edges should be maintained in the splay tree for point */ +/* location on the front. */ + +#define SAMPLERATE 10 + +/* A number that speaks for itself, every kissable digit. */ + +#define PI 3.141592653589793238462643383279502884197169399375105820974944592308 + +/* Another fave. */ + +#define SQUAREROOTTWO 1.4142135623730950488016887242096980785696718753769480732 + +/* And here's one for those of you who are intimidated by math. */ + +#define ONETHIRD 0.333333333333333333333333333333333333333333333333333333333333 + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <math.h> +#ifndef NO_TIMER +#include <sys/time.h> +#endif /* not NO_TIMER */ +#ifdef CPU86 +#include <float.h> +#endif /* CPU86 */ +#ifdef LINUX +#include <fpu_control.h> +#endif /* LINUX */ +#ifdef TRILIBRARY +#include "triangle.h" +#endif /* TRILIBRARY */ + +/* A few forward declarations. */ + +#ifndef TRILIBRARY +char *readline(); +char *findfield(); +#endif /* not TRILIBRARY */ + +/* Labels that signify whether a record consists primarily of pointers or of */ +/* floating-point words. Used to make decisions about data alignment. */ + +enum wordtype {POINTER, FLOATINGPOINT}; + +/* Labels that signify the result of point location. The result of a */ +/* search indicates that the point falls in the interior of a triangle, on */ +/* an edge, on a vertex, or outside the mesh. */ + +enum locateresult {INTRIANGLE, ONEDGE, ONVERTEX, OUTSIDE}; + +/* Labels that signify the result of vertex insertion. The result indicates */ +/* that the vertex was inserted with complete success, was inserted but */ +/* encroaches upon a subsegment, was not inserted because it lies on a */ +/* segment, or was not inserted because another vertex occupies the same */ +/* location. */ + +enum insertvertexresult {SUCCESSFULVERTEX, ENCROACHINGVERTEX, VIOLATINGVERTEX, + DUPLICATEVERTEX}; + +/* Labels that signify the result of direction finding. The result */ +/* indicates that a segment connecting the two query points falls within */ +/* the direction triangle, along the left edge of the direction triangle, */ +/* or along the right edge of the direction triangle. */ + +enum finddirectionresult {WITHIN, LEFTCOLLINEAR, RIGHTCOLLINEAR}; + +/*****************************************************************************/ +/* */ +/* The basic mesh data structures */ +/* */ +/* There are three: vertices, triangles, and subsegments (abbreviated */ +/* `subseg'). These three data structures, linked by pointers, comprise */ +/* the mesh. A vertex simply represents a mesh vertex and its properties. */ +/* A triangle is a triangle. A subsegment is a special data structure used */ +/* to represent an impenetrable edge of the mesh (perhaps on the outer */ +/* boundary, on the boundary of a hole, or part of an internal boundary */ +/* separating two triangulated regions). Subsegments represent boundaries, */ +/* defined by the user, that triangles may not lie across. */ +/* */ +/* A triangle consists of a list of three vertices, a list of three */ +/* adjoining triangles, a list of three adjoining subsegments (when */ +/* segments exist), an arbitrary number of optional user-defined */ +/* floating-point attributes, and an optional area constraint. The latter */ +/* is an upper bound on the permissible area of each triangle in a region, */ +/* used for mesh refinement. */ +/* */ +/* For a triangle on a boundary of the mesh, some or all of the neighboring */ +/* triangles may not be present. For a triangle in the interior of the */ +/* mesh, often no neighboring subsegments are present. Such absent */ +/* triangles and subsegments are never represented by NULL pointers; they */ +/* are represented by two special records: `dummytri', the triangle that */ +/* fills "outer space", and `dummysub', the omnipresent subsegment. */ +/* `dummytri' and `dummysub' are used for several reasons; for instance, */ +/* they can be dereferenced and their contents examined without violating */ +/* protected memory. */ +/* */ +/* However, it is important to understand that a triangle includes other */ +/* information as well. The pointers to adjoining vertices, triangles, and */ +/* subsegments are ordered in a way that indicates their geometric relation */ +/* to each other. Furthermore, each of these pointers contains orientation */ +/* information. Each pointer to an adjoining triangle indicates which face */ +/* of that triangle is contacted. Similarly, each pointer to an adjoining */ +/* subsegment indicates which side of that subsegment is contacted, and how */ +/* the subsegment is oriented relative to the triangle. */ +/* */ +/* The data structure representing a subsegment may be thought to be */ +/* abutting the edge of one or two triangle data structures: either */ +/* sandwiched between two triangles, or resting against one triangle on an */ +/* exterior boundary or hole boundary. */ +/* */ +/* A subsegment consists of a list of two vertices, a list of two */ +/* adjoining subsegments, and a list of two adjoining triangles. One of */ +/* the two adjoining triangles may not be present (though there should */ +/* always be one), and neighboring subsegments might not be present. */ +/* Subsegments also store a user-defined integer "boundary marker". */ +/* Typically, this integer is used to indicate what boundary conditions are */ +/* to be applied at that location in a finite element simulation. */ +/* */ +/* Like triangles, subsegments maintain information about the relative */ +/* orientation of neighboring objects. */ +/* */ +/* Vertices are relatively simple. A vertex is a list of floating-point */ +/* numbers, starting with the x, and y coordinates, followed by an */ +/* arbitrary number of optional user-defined floating-point attributes, */ +/* followed by an integer boundary marker. During the segment insertion */ +/* phase, there is also a pointer from each vertex to a triangle that may */ +/* contain it. Each pointer is not always correct, but when one is, it */ +/* speeds up segment insertion. These pointers are assigned values once */ +/* at the beginning of the segment insertion phase, and are not used or */ +/* updated except during this phase. Edge flipping during segment */ +/* insertion will render some of them incorrect. Hence, don't rely upon */ +/* them for anything. */ +/* */ +/* Other than the exception mentioned above, vertices have no information */ +/* about what triangles, subfacets, or subsegments they are linked to. */ +/* */ +/*****************************************************************************/ + +/*****************************************************************************/ +/* */ +/* Handles */ +/* */ +/* The oriented triangle (`otri') and oriented subsegment (`osub') data */ +/* structures defined below do not themselves store any part of the mesh. */ +/* The mesh itself is made of `triangle's, `subseg's, and `vertex's. */ +/* */ +/* Oriented triangles and oriented subsegments will usually be referred to */ +/* as "handles." A handle is essentially a pointer into the mesh; it */ +/* allows you to "hold" one particular part of the mesh. Handles are used */ +/* to specify the regions in which one is traversing and modifying the mesh.*/ +/* A single `triangle' may be held by many handles, or none at all. (The */ +/* latter case is not a memory leak, because the triangle is still */ +/* connected to other triangles in the mesh.) */ +/* */ +/* An `otri' is a handle that holds a triangle. It holds a specific edge */ +/* of the triangle. An `osub' is a handle that holds a subsegment. It */ +/* holds either the left or right side of the subsegment. */ +/* */ +/* Navigation about the mesh is accomplished through a set of mesh */ +/* manipulation primitives, further below. Many of these primitives take */ +/* a handle and produce a new handle that holds the mesh near the first */ +/* handle. Other primitives take two handles and glue the corresponding */ +/* parts of the mesh together. The orientation of the handles is */ +/* important. For instance, when two triangles are glued together by the */ +/* bond() primitive, they are glued at the edges on which the handles lie. */ +/* */ +/* Because vertices have no information about which triangles they are */ +/* attached to, I commonly represent a vertex by use of a handle whose */ +/* origin is the vertex. A single handle can simultaneously represent a */ +/* triangle, an edge, and a vertex. */ +/* */ +/*****************************************************************************/ + +/* The triangle data structure. Each triangle contains three pointers to */ +/* adjoining triangles, plus three pointers to vertices, plus three */ +/* pointers to subsegments (declared below; these pointers are usually */ +/* `dummysub'). It may or may not also contain user-defined attributes */ +/* and/or a floating-point "area constraint." It may also contain extra */ +/* pointers for nodes, when the user asks for high-order elements. */ +/* Because the size and structure of a `triangle' is not decided until */ +/* runtime, I haven't simply declared the type `triangle' as a struct. */ + +typedef REAL **triangle; /* Really: typedef triangle *triangle */ + +/* An oriented triangle: includes a pointer to a triangle and orientation. */ +/* The orientation denotes an edge of the triangle. Hence, there are */ +/* three possible orientations. By convention, each edge always points */ +/* counterclockwise about the corresponding triangle. */ + +struct otri { + triangle *tri; + int orient; /* Ranges from 0 to 2. */ +}; + +/* The subsegment data structure. Each subsegment contains two pointers to */ +/* adjoining subsegments, plus two pointers to vertices, plus two pointers */ +/* to adjoining triangles, plus one boundary marker. */ + +typedef REAL **subseg; /* Really: typedef subseg *subseg */ + +/* An oriented subsegment: includes a pointer to a subsegment and an */ +/* orientation. The orientation denotes a side of the edge. Hence, there */ +/* are two possible orientations. By convention, the edge is always */ +/* directed so that the "side" denoted is the right side of the edge. */ + +struct osub { + subseg *ss; + int ssorient; /* Ranges from 0 to 1. */ +}; + +/* The vertex data structure. Each vertex is actually an array of REALs. */ +/* The number of REALs is unknown until runtime. An integer boundary */ +/* marker, and sometimes a pointer to a triangle, is appended after the */ +/* REALs. */ + +typedef REAL *vertex; + +/* A queue used to store encroached subsegments. Each subsegment's vertices */ +/* are stored so that we can check whether a subsegment is still the same. */ + +struct badsubseg { + subseg encsubseg; /* An encroached subsegment. */ + vertex subsegorg, subsegdest; /* Its two vertices. */ +}; + +/* A queue used to store bad triangles. The key is the square of the cosine */ +/* of the smallest angle of the triangle. Each triangle's vertices are */ +/* stored so that one can check whether a triangle is still the same. */ + +struct badtriang { + triangle poortri; /* A skinny or too-large triangle. */ + REAL key; /* cos^2 of smallest (apical) angle. */ + vertex triangorg, triangdest, triangapex; /* Its three vertices. */ + struct badtriang *nexttriang; /* Pointer to next bad triangle. */ +}; + +/* A stack of triangles flipped during the most recent vertex insertion. */ +/* The stack is used to undo the vertex insertion if the vertex encroaches */ +/* upon a subsegment. */ + +struct flipstacker { + triangle flippedtri; /* A recently flipped triangle. */ + struct flipstacker *prevflip; /* Previous flip in the stack. */ +}; + +/* A node in a heap used to store events for the sweepline Delaunay */ +/* algorithm. Nodes do not point directly to their parents or children in */ +/* the heap. Instead, each node knows its position in the heap, and can */ +/* look up its parent and children in a separate array. The `eventptr' */ +/* points either to a `vertex' or to a triangle (in encoded format, so */ +/* that an orientation is included). In the latter case, the origin of */ +/* the oriented triangle is the apex of a "circle event" of the sweepline */ +/* algorithm. To distinguish site events from circle events, all circle */ +/* events are given an invalid (smaller than `xmin') x-coordinate `xkey'. */ + +struct event { + REAL xkey, ykey; /* Coordinates of the event. */ + VOID *eventptr; /* Can be a vertex or the location of a circle event. */ + int heapposition; /* Marks this event's position in the heap. */ +}; + +/* A node in the splay tree. Each node holds an oriented ghost triangle */ +/* that represents a boundary edge of the growing triangulation. When a */ +/* circle event covers two boundary edges with a triangle, so that they */ +/* are no longer boundary edges, those edges are not immediately deleted */ +/* from the tree; rather, they are lazily deleted when they are next */ +/* encountered. (Since only a random sample of boundary edges are kept */ +/* in the tree, lazy deletion is faster.) `keydest' is used to verify */ +/* that a triangle is still the same as when it entered the splay tree; if */ +/* it has been rotated (due to a circle event), it no longer represents a */ +/* boundary edge and should be deleted. */ + +struct splaynode { + struct otri keyedge; /* Lprev of an edge on the front. */ + vertex keydest; /* Used to verify that splay node is still live. */ + struct splaynode *lchild, *rchild; /* Children in splay tree. */ +}; + +/* A type used to allocate memory. firstblock is the first block of items. */ +/* nowblock is the block from which items are currently being allocated. */ +/* nextitem points to the next slab of free memory for an item. */ +/* deaditemstack is the head of a linked list (stack) of deallocated items */ +/* that can be recycled. unallocateditems is the number of items that */ +/* remain to be allocated from nowblock. */ +/* */ +/* Traversal is the process of walking through the entire list of items, and */ +/* is separate from allocation. Note that a traversal will visit items on */ +/* the "deaditemstack" stack as well as live items. pathblock points to */ +/* the block currently being traversed. pathitem points to the next item */ +/* to be traversed. pathitemsleft is the number of items that remain to */ +/* be traversed in pathblock. */ +/* */ +/* itemwordtype is set to POINTER or FLOATINGPOINT, and is used to suggest */ +/* what sort of word the record is primarily made up of. alignbytes */ +/* determines how new records should be aligned in memory. itembytes and */ +/* itemwords are the length of a record in bytes (after rounding up) and */ +/* words. itemsperblock is the number of items allocated at once in a */ +/* single block. itemsfirstblock is the number of items in the first */ +/* block, which can vary from the others. items is the number of */ +/* currently allocated items. maxitems is the maximum number of items */ +/* that have been allocated at once; it is the current number of items */ +/* plus the number of records kept on deaditemstack. */ + +struct memorypool { + VOID **firstblock, **nowblock; + VOID *nextitem; + VOID *deaditemstack; + VOID **pathblock; + VOID *pathitem; + enum wordtype itemwordtype; + int alignbytes; + int itembytes, itemwords; + int itemsperblock; + int itemsfirstblock; + long items, maxitems; + int unallocateditems; + int pathitemsleft; +}; + + +/* Global constants. */ + +REAL splitter; /* Used to split REAL factors for exact multiplication. */ +REAL epsilon; /* Floating-point machine epsilon. */ +REAL resulterrbound; +REAL ccwerrboundA, ccwerrboundB, ccwerrboundC; +REAL iccerrboundA, iccerrboundB, iccerrboundC; +REAL o3derrboundA, o3derrboundB, o3derrboundC; + +/* Random number seed is not constant, but I've made it global anyway. */ + +unsigned long randomseed; /* Current random number seed. */ + + +/* Mesh data structure. Triangle operates on only one mesh, but the mesh */ +/* structure is used (instead of global variables) to allow reentrancy. */ + +struct mesh { + +/* Variables used to allocate memory for triangles, subsegments, vertices, */ +/* viri (triangles being eaten), encroached segments, bad (skinny or too */ +/* large) triangles, and splay tree nodes. */ + + struct memorypool triangles; + struct memorypool subsegs; + struct memorypool vertices; + struct memorypool viri; + struct memorypool badsubsegs; + struct memorypool badtriangles; + struct memorypool flipstackers; + struct memorypool splaynodes; + +/* Variables that maintain the bad triangle queues. The queues are */ +/* ordered from 63 (highest priority) to 0 (lowest priority). */ + + struct badtriang *queuefront[64]; + struct badtriang *queuetail[64]; + int nextnonemptyq[64]; + int firstnonemptyq; + +/* Variable that maintains the stack of recently flipped triangles. */ + + struct flipstacker *lastflip; + +/* Other variables. */ + + REAL xmin, xmax, ymin, ymax; /* x and y bounds. */ + REAL xminextreme; /* Nonexistent x value used as a flag in sweepline. */ + int invertices; /* Number of input vertices. */ + int inelements; /* Number of input triangles. */ + int insegments; /* Number of input segments. */ + int holes; /* Number of input holes. */ + int regions; /* Number of input regions. */ + int undeads; /* Number of input vertices that don't appear in the mesh. */ + long edges; /* Number of output edges. */ + int mesh_dim; /* Dimension (ought to be 2). */ + int nextras; /* Number of attributes per vertex. */ + int eextras; /* Number of attributes per triangle. */ + long hullsize; /* Number of edges in convex hull. */ + int steinerleft; /* Number of Steiner points not yet used. */ + int vertexmarkindex; /* Index to find boundary marker of a vertex. */ + int vertex2triindex; /* Index to find a triangle adjacent to a vertex. */ + int highorderindex; /* Index to find extra nodes for high-order elements. */ + int elemattribindex; /* Index to find attributes of a triangle. */ + int areaboundindex; /* Index to find area bound of a triangle. */ + int checksegments; /* Are there segments in the triangulation yet? */ + int checkquality; /* Has quality triangulation begun yet? */ + int readnodefile; /* Has a .node file been read? */ + long samples; /* Number of random samples for point location. */ + + long incirclecount; /* Number of incircle tests performed. */ + long counterclockcount; /* Number of counterclockwise tests performed. */ + long orient3dcount; /* Number of 3D orientation tests performed. */ + long hyperbolacount; /* Number of right-of-hyperbola tests performed. */ + long circumcentercount; /* Number of circumcenter calculations performed. */ + long circletopcount; /* Number of circle top calculations performed. */ + +/* Triangular bounding box vertices. */ + + vertex infvertex1, infvertex2, infvertex3; + +/* Pointer to the `triangle' that occupies all of "outer space." */ + + triangle *dummytri; + triangle *dummytribase; /* Keep base address so we can free() it later. */ + +/* Pointer to the omnipresent subsegment. Referenced by any triangle or */ +/* subsegment that isn't really connected to a subsegment at that */ +/* location. */ + + subseg *dummysub; + subseg *dummysubbase; /* Keep base address so we can free() it later. */ + +/* Pointer to a recently visited triangle. Improves point location if */ +/* proximate vertices are inserted sequentially. */ + + struct otri recenttri; + +}; /* End of `struct mesh'. */ + + +/* Data structure for command line switches and file names. This structure */ +/* is used (instead of global variables) to allow reentrancy. */ + +struct behavior { + +/* Switches for the triangulator. */ +/* poly: -p switch. refine: -r switch. */ +/* quality: -q switch. */ +/* minangle: minimum angle bound, specified after -q switch. */ +/* goodangle: cosine squared of minangle. */ +/* offconstant: constant used to place off-center Steiner points. */ +/* vararea: -a switch without number. */ +/* fixedarea: -a switch with number. */ +/* maxarea: maximum area bound, specified after -a switch. */ +/* usertest: -u switch. */ +/* regionattrib: -A switch. convex: -c switch. */ +/* weighted: 1 for -w switch, 2 for -W switch. jettison: -j switch */ +/* firstnumber: inverse of -z switch. All items are numbered starting */ +/* from `firstnumber'. */ +/* edgesout: -e switch. voronoi: -v switch. */ +/* neighbors: -n switch. geomview: -g switch. */ +/* nobound: -B switch. nopolywritten: -P switch. */ +/* nonodewritten: -N switch. noelewritten: -E switch. */ +/* noiterationnum: -I switch. noholes: -O switch. */ +/* noexact: -X switch. */ +/* order: element order, specified after -o switch. */ +/* nobisect: count of how often -Y switch is selected. */ +/* steiner: maximum number of Steiner points, specified after -S switch. */ +/* incremental: -i switch. sweepline: -F switch. */ +/* dwyer: inverse of -l switch. */ +/* splitseg: -s switch. */ +/* nolenses: -L switch. docheck: -C switch. */ +/* quiet: -Q switch. verbose: count of how often -V switch is selected. */ +/* usesegments: -p, -r, -q, or -c switch; determines whether segments are */ +/* used at all. */ +/* */ +/* Read the instructions to find out the meaning of these switches. */ + + int poly, refine, quality, vararea, fixedarea, usertest; + int regionattrib, convex, weighted, jettison; + int firstnumber; + int edgesout, voronoi, neighbors, geomview; + int nobound, nopolywritten, nonodewritten, noelewritten, noiterationnum; + int noholes, noexact, nolenses; + int incremental, sweepline, dwyer; + int splitseg; + int docheck; + int quiet, verbose; + int usesegments; + int order; + int nobisect; + int steiner; + REAL minangle, goodangle, offconstant; + REAL maxarea; + +/* Variables for file names. */ + +#ifndef TRILIBRARY + char innodefilename[FILENAMESIZE]; + char inelefilename[FILENAMESIZE]; + char inpolyfilename[FILENAMESIZE]; + char areafilename[FILENAMESIZE]; + char outnodefilename[FILENAMESIZE]; + char outelefilename[FILENAMESIZE]; + char outpolyfilename[FILENAMESIZE]; + char edgefilename[FILENAMESIZE]; + char vnodefilename[FILENAMESIZE]; + char vedgefilename[FILENAMESIZE]; + char neighborfilename[FILENAMESIZE]; + char offfilename[FILENAMESIZE]; +#endif /* not TRILIBRARY */ + +}; /* End of `struct behavior'. */ + + +/*****************************************************************************/ +/* */ +/* Mesh manipulation primitives. Each triangle contains three pointers to */ +/* other triangles, with orientations. Each pointer points not to the */ +/* first byte of a triangle, but to one of the first three bytes of a */ +/* triangle. It is necessary to extract both the triangle itself and the */ +/* orientation. To save memory, I keep both pieces of information in one */ +/* pointer. To make this possible, I assume that all triangles are aligned */ +/* to four-byte boundaries. The decode() routine below decodes a pointer, */ +/* extracting an orientation (in the range 0 to 2) and a pointer to the */ +/* beginning of a triangle. The encode() routine compresses a pointer to a */ +/* triangle and an orientation into a single pointer. My assumptions that */ +/* triangles are four-byte-aligned and that the `unsigned long' type is */ +/* long enough to hold a pointer are two of the few kludges in this program.*/ +/* */ +/* Subsegments are manipulated similarly. A pointer to a subsegment */ +/* carries both an address and an orientation in the range 0 to 1. */ +/* */ +/* The other primitives take an oriented triangle or oriented subsegment, */ +/* and return an oriented triangle or oriented subsegment or vertex; or */ +/* they change the connections in the data structure. */ +/* */ +/* Below, triangles and subsegments are denoted by their vertices. The */ +/* triangle abc has origin (org) a, destination (dest) b, and apex (apex) */ +/* c. These vertices occur in counterclockwise order about the triangle. */ +/* The handle abc may simultaneously denote vertex a, edge ab, and triangle */ +/* abc. */ +/* */ +/* Similarly, the subsegment ab has origin (sorg) a and destination (sdest) */ +/* b. If ab is thought to be directed upward (with b directly above a), */ +/* then the handle ab is thought to grasp the right side of ab, and may */ +/* simultaneously denote vertex a and edge ab. */ +/* */ +/* An asterisk (*) denotes a vertex whose identity is unknown. */ +/* */ +/* Given this notation, a partial list of mesh manipulation primitives */ +/* follows. */ +/* */ +/* */ +/* For triangles: */ +/* */ +/* sym: Find the abutting triangle; same edge. */ +/* sym(abc) -> ba* */ +/* */ +/* lnext: Find the next edge (counterclockwise) of a triangle. */ +/* lnext(abc) -> bca */ +/* */ +/* lprev: Find the previous edge (clockwise) of a triangle. */ +/* lprev(abc) -> cab */ +/* */ +/* onext: Find the next edge counterclockwise with the same origin. */ +/* onext(abc) -> ac* */ +/* */ +/* oprev: Find the next edge clockwise with the same origin. */ +/* oprev(abc) -> a*b */ +/* */ +/* dnext: Find the next edge counterclockwise with the same destination. */ +/* dnext(abc) -> *ba */ +/* */ +/* dprev: Find the next edge clockwise with the same destination. */ +/* dprev(abc) -> cb* */ +/* */ +/* rnext: Find the next edge (counterclockwise) of the adjacent triangle. */ +/* rnext(abc) -> *a* */ +/* */ +/* rprev: Find the previous edge (clockwise) of the adjacent triangle. */ +/* rprev(abc) -> b** */ +/* */ +/* org: Origin dest: Destination apex: Apex */ +/* org(abc) -> a dest(abc) -> b apex(abc) -> c */ +/* */ +/* bond: Bond two triangles together at the resepective handles. */ +/* bond(abc, bad) */ +/* */ +/* */ +/* For subsegments: */ +/* */ +/* ssym: Reverse the orientation of a subsegment. */ +/* ssym(ab) -> ba */ +/* */ +/* spivot: Find adjoining subsegment with the same origin. */ +/* spivot(ab) -> a* */ +/* */ +/* snext: Find next subsegment in sequence. */ +/* snext(ab) -> b* */ +/* */ +/* sorg: Origin sdest: Destination */ +/* sorg(ab) -> a sdest(ab) -> b */ +/* */ +/* sbond: Bond two subsegments together at the respective origins. */ +/* sbond(ab, ac) */ +/* */ +/* */ +/* For interacting tetrahedra and subfacets: */ +/* */ +/* tspivot: Find a subsegment abutting a triangle. */ +/* tspivot(abc) -> ba */ +/* */ +/* stpivot: Find a triangle abutting a subsegment. */ +/* stpivot(ab) -> ba* */ +/* */ +/* tsbond: Bond a triangle to a subsegment. */ +/* tsbond(abc, ba) */ +/* */ +/*****************************************************************************/ + +/********* Mesh manipulation primitives begin here *********/ +/** **/ +/** **/ + +/* Fast lookup arrays to speed some of the mesh manipulation primitives. */ + +int plus1mod3[3] = {1, 2, 0}; +int minus1mod3[3] = {2, 0, 1}; + +/********* Primitives for triangles *********/ +/* */ +/* */ + +/* decode() converts a pointer to an oriented triangle. The orientation is */ +/* extracted from the two least significant bits of the pointer. */ + +#define decode(ptr, otri) \ + (otri).orient = (int) ((unsigned long) (ptr) & (unsigned long) 3l); \ + (otri).tri = (triangle *) \ + ((unsigned long) (ptr) ^ (unsigned long) (otri).orient) + +/* encode() compresses an oriented triangle into a single pointer. It */ +/* relies on the assumption that all triangles are aligned to four-byte */ +/* boundaries, so the two least significant bits of (otri).tri are zero. */ + +#define encode(otri) \ + (triangle) ((unsigned long) (otri).tri | (unsigned long) (otri).orient) + +/* The following handle manipulation primitives are all described by Guibas */ +/* and Stolfi. However, Guibas and Stolfi use an edge-based data */ +/* structure, whereas I use a triangle-based data structure. */ + +/* sym() finds the abutting triangle, on the same edge. Note that the edge */ +/* direction is necessarily reversed, because the handle specified by an */ +/* oriented triangle is directed counterclockwise around the triangle. */ + +#define sym(otri1, otri2) \ + ptr = (otri1).tri[(otri1).orient]; \ + decode(ptr, otri2); + +#define symself(otri) \ + ptr = (otri).tri[(otri).orient]; \ + decode(ptr, otri); + +/* lnext() finds the next edge (counterclockwise) of a triangle. */ + +#define lnext(otri1, otri2) \ + (otri2).tri = (otri1).tri; \ + (otri2).orient = plus1mod3[(otri1).orient] + +#define lnextself(otri) \ + (otri).orient = plus1mod3[(otri).orient] + +/* lprev() finds the previous edge (clockwise) of a triangle. */ + +#define lprev(otri1, otri2) \ + (otri2).tri = (otri1).tri; \ + (otri2).orient = minus1mod3[(otri1).orient] + +#define lprevself(otri) \ + (otri).orient = minus1mod3[(otri).orient] + +/* onext() spins counterclockwise around a vertex; that is, it finds the */ +/* next edge with the same origin in the counterclockwise direction. This */ +/* edge is part of a different triangle. */ + +#define onext(otri1, otri2) \ + lprev(otri1, otri2); \ + symself(otri2); + +#define onextself(otri) \ + lprevself(otri); \ + symself(otri); + +/* oprev() spins clockwise around a vertex; that is, it finds the next edge */ +/* with the same origin in the clockwise direction. This edge is part of */ +/* a different triangle. */ + +#define oprev(otri1, otri2) \ + sym(otri1, otri2); \ + lnextself(otri2); + +#define oprevself(otri) \ + symself(otri); \ + lnextself(otri); + +/* dnext() spins counterclockwise around a vertex; that is, it finds the */ +/* next edge with the same destination in the counterclockwise direction. */ +/* This edge is part of a different triangle. */ + +#define dnext(otri1, otri2) \ + sym(otri1, otri2); \ + lprevself(otri2); + +#define dnextself(otri) \ + symself(otri); \ + lprevself(otri); + +/* dprev() spins clockwise around a vertex; that is, it finds the next edge */ +/* with the same destination in the clockwise direction. This edge is */ +/* part of a different triangle. */ + +#define dprev(otri1, otri2) \ + lnext(otri1, otri2); \ + symself(otri2); + +#define dprevself(otri) \ + lnextself(otri); \ + symself(otri); + +/* rnext() moves one edge counterclockwise about the adjacent triangle. */ +/* (It's best understood by reading Guibas and Stolfi. It involves */ +/* changing triangles twice.) */ + +#define rnext(otri1, otri2) \ + sym(otri1, otri2); \ + lnextself(otri2); \ + symself(otri2); + +#define rnextself(otri) \ + symself(otri); \ + lnextself(otri); \ + symself(otri); + +/* rprev() moves one edge clockwise about the adjacent triangle. */ +/* (It's best understood by reading Guibas and Stolfi. It involves */ +/* changing triangles twice.) */ + +#define rprev(otri1, otri2) \ + sym(otri1, otri2); \ + lprevself(otri2); \ + symself(otri2); + +#define rprevself(otri) \ + symself(otri); \ + lprevself(otri); \ + symself(otri); + +/* These primitives determine or set the origin, destination, or apex of a */ +/* triangle. */ + +#define org(otri, vertexptr) \ + vertexptr = (vertex) (otri).tri[plus1mod3[(otri).orient] + 3] + +#define dest(otri, vertexptr) \ + vertexptr = (vertex) (otri).tri[minus1mod3[(otri).orient] + 3] + +#define apex(otri, vertexptr) \ + vertexptr = (vertex) (otri).tri[(otri).orient + 3] + +#define setorg(otri, vertexptr) \ + (otri).tri[plus1mod3[(otri).orient] + 3] = (triangle) vertexptr + +#define setdest(otri, vertexptr) \ + (otri).tri[minus1mod3[(otri).orient] + 3] = (triangle) vertexptr + +#define setapex(otri, vertexptr) \ + (otri).tri[(otri).orient + 3] = (triangle) vertexptr + +/* Bond two triangles together. */ + +#define bond(otri1, otri2) \ + (otri1).tri[(otri1).orient] = encode(otri2); \ + (otri2).tri[(otri2).orient] = encode(otri1) + +/* Dissolve a bond (from one side). Note that the other triangle will still */ +/* think it's connected to this triangle. Usually, however, the other */ +/* triangle is being deleted entirely, or bonded to another triangle, so */ +/* it doesn't matter. */ + +#define dissolve(otri) \ + (otri).tri[(otri).orient] = (triangle) m->dummytri + +/* Copy an oriented triangle. */ + +#define otricopy(otri1, otri2) \ + (otri2).tri = (otri1).tri; \ + (otri2).orient = (otri1).orient + +/* Test for equality of oriented triangles. */ + +#define otriequal(otri1, otri2) \ + (((otri1).tri == (otri2).tri) && \ + ((otri1).orient == (otri2).orient)) + +/* Primitives to infect or cure a triangle with the virus. These rely on */ +/* the assumption that all subsegments are aligned to four-byte boundaries.*/ + +#define infect(otri) \ + (otri).tri[6] = (triangle) \ + ((unsigned long) (otri).tri[6] | (unsigned long) 2l) + +#define uninfect(otri) \ + (otri).tri[6] = (triangle) \ + ((unsigned long) (otri).tri[6] & ~ (unsigned long) 2l) + +/* Test a triangle for viral infection. */ + +#define infected(otri) \ + (((unsigned long) (otri).tri[6] & (unsigned long) 2l) != 0l) + +/* Check or set a triangle's attributes. */ + +#define elemattribute(otri, attnum) \ + ((REAL *) (otri).tri)[m->elemattribindex + (attnum)] + +#define setelemattribute(otri, attnum, value) \ + ((REAL *) (otri).tri)[m->elemattribindex + (attnum)] = value + +/* Check or set a triangle's maximum area bound. */ + +#define areabound(otri) ((REAL *) (otri).tri)[m->areaboundindex] + +#define setareabound(otri, value) \ + ((REAL *) (otri).tri)[m->areaboundindex] = value + +/* Check or set a triangle's deallocation. Its second pointer is set to */ +/* NULL to indicate that it is not allocated. (Its first pointer is used */ +/* for the stack of dead items.) Its fourth pointer (its first vertex) */ +/* is set to NULL in case a `badtriang' structure points to it. */ + +#define deadtri(tria) ((tria)[1] == (triangle) NULL) + +#define killtri(tria) \ + (tria)[1] = (triangle) NULL; \ + (tria)[3] = (triangle) NULL + +/********* Primitives for subsegments *********/ +/* */ +/* */ + +/* sdecode() converts a pointer to an oriented subsegment. The orientation */ +/* is extracted from the least significant bit of the pointer. The two */ +/* least significant bits (one for orientation, one for viral infection) */ +/* are masked out to produce the real pointer. */ + +#define sdecode(sptr, osub) \ + (osub).ssorient = (int) ((unsigned long) (sptr) & (unsigned long) 1l); \ + (osub).ss = (subseg *) \ + ((unsigned long) (sptr) & ~ (unsigned long) 3l) + +/* sencode() compresses an oriented subsegment into a single pointer. It */ +/* relies on the assumption that all subsegments are aligned to two-byte */ +/* boundaries, so the least significant bit of (osub).ss is zero. */ + +#define sencode(osub) \ + (subseg) ((unsigned long) (osub).ss | (unsigned long) (osub).ssorient) + +/* ssym() toggles the orientation of a subsegment. */ + +#define ssym(osub1, osub2) \ + (osub2).ss = (osub1).ss; \ + (osub2).ssorient = 1 - (osub1).ssorient + +#define ssymself(osub) \ + (osub).ssorient = 1 - (osub).ssorient + +/* spivot() finds the other subsegment (from the same segment) that shares */ +/* the same origin. */ + +#define spivot(osub1, osub2) \ + sptr = (osub1).ss[(osub1).ssorient]; \ + sdecode(sptr, osub2) + +#define spivotself(osub) \ + sptr = (osub).ss[(osub).ssorient]; \ + sdecode(sptr, osub) + +/* snext() finds the next subsegment (from the same segment) in sequence; */ +/* one whose origin is the input subsegment's destination. */ + +#define snext(osub1, osub2) \ + sptr = (osub1).ss[1 - (osub1).ssorient]; \ + sdecode(sptr, osub2) + +#define snextself(osub) \ + sptr = (osub).ss[1 - (osub).ssorient]; \ + sdecode(sptr, osub) + +/* These primitives determine or set the origin or destination of a */ +/* subsegment. */ + +#define sorg(osub, vertexptr) \ + vertexptr = (vertex) (osub).ss[2 + (osub).ssorient] + +#define sdest(osub, vertexptr) \ + vertexptr = (vertex) (osub).ss[3 - (osub).ssorient] + +#define setsorg(osub, vertexptr) \ + (osub).ss[2 + (osub).ssorient] = (subseg) vertexptr + +#define setsdest(osub, vertexptr) \ + (osub).ss[3 - (osub).ssorient] = (subseg) vertexptr + +/* These primitives read or set a boundary marker. Boundary markers are */ +/* used to hold user-defined tags for setting boundary conditions in */ +/* finite element solvers. */ + +#define mark(osub) (* (int *) ((osub).ss + 6)) + +#define setmark(osub, value) \ + * (int *) ((osub).ss + 6) = value + +/* Bond two subsegments together. */ + +#define sbond(osub1, osub2) \ + (osub1).ss[(osub1).ssorient] = sencode(osub2); \ + (osub2).ss[(osub2).ssorient] = sencode(osub1) + +/* Dissolve a subsegment bond (from one side). Note that the other */ +/* subsegment will still think it's connected to this subsegment. */ + +#define sdissolve(osub) \ + (osub).ss[(osub).ssorient] = (subseg) m->dummysub + +/* Copy a subsegment. */ + +#define subsegcopy(osub1, osub2) \ + (osub2).ss = (osub1).ss; \ + (osub2).ssorient = (osub1).ssorient + +/* Test for equality of subsegments. */ + +#define subsegequal(osub1, osub2) \ + (((osub1).ss == (osub2).ss) && \ + ((osub1).ssorient == (osub2).ssorient)) + +/* Check or set a subsegment's deallocation. Its second pointer is set to */ +/* NULL to indicate that it is not allocated. (Its first pointer is used */ +/* for the stack of dead items.) Its third pointer (its first vertex) */ +/* is set to NULL in case a `badsubseg' structure points to it. */ + +#define deadsubseg(sub) ((sub)[1] == (subseg) NULL) + +#define killsubseg(sub) \ + (sub)[1] = (subseg) NULL; \ + (sub)[2] = (subseg) NULL + +/********* Primitives for interacting triangles and subsegments *********/ +/* */ +/* */ + +/* tspivot() finds a subsegment abutting a triangle. */ + +#define tspivot(otri, osub) \ + sptr = (subseg) (otri).tri[6 + (otri).orient]; \ + sdecode(sptr, osub) + +/* stpivot() finds a triangle abutting a subsegment. It requires that the */ +/* variable `ptr' of type `triangle' be defined. */ + +#define stpivot(osub, otri) \ + ptr = (triangle) (osub).ss[4 + (osub).ssorient]; \ + decode(ptr, otri) + +/* Bond a triangle to a subsegment. */ + +#define tsbond(otri, osub) \ + (otri).tri[6 + (otri).orient] = (triangle) sencode(osub); \ + (osub).ss[4 + (osub).ssorient] = (subseg) encode(otri) + +/* Dissolve a bond (from the triangle side). */ + +#define tsdissolve(otri) \ + (otri).tri[6 + (otri).orient] = (triangle) m->dummysub + +/* Dissolve a bond (from the subsegment side). */ + +#define stdissolve(osub) \ + (osub).ss[4 + (osub).ssorient] = (subseg) m->dummytri + +/********* Primitives for vertices *********/ +/* */ +/* */ + +#define vertexmark(vx) ((int *) (vx))[m->vertexmarkindex] + +#define setvertexmark(vx, value) \ + ((int *) (vx))[m->vertexmarkindex] = value + +#define vertextype(vx) ((int *) (vx))[m->vertexmarkindex + 1] + +#define setvertextype(vx, value) \ + ((int *) (vx))[m->vertexmarkindex + 1] = value + +#define vertex2tri(vx) ((triangle *) (vx))[m->vertex2triindex] + +#define setvertex2tri(vx, value) \ + ((triangle *) (vx))[m->vertex2triindex] = value + +/** **/ +/** **/ +/********* Mesh manipulation primitives end here *********/ + +/********* User-defined triangle evaluation routine begins here *********/ +/** **/ +/** **/ + +/*****************************************************************************/ +/* */ +/* triunsuitable() Determine if a triangle is unsuitable, and thus must */ +/* be further refined. */ +/* */ +/* You may write your own procedure that decides whether or not a selected */ +/* triangle is too big (and needs to be refined). There are two ways to do */ +/* this. */ +/* */ +/* (1) Modify the procedure `triunsuitable' below, then recompile */ +/* Triangle. */ +/* */ +/* (2) Define the symbol EXTERNAL_TEST (either by adding the definition */ +/* to this file, or by using the appropriate compiler switch). This way, */ +/* you can compile triangle.c separately from your test. Write your own */ +/* `triunsuitable' procedure in a separate C file (using the same prototype */ +/* as below). Compile it and link the object code with triangle.o. */ +/* */ +/* This procedure returns 1 if the triangle is too large and should be */ +/* refined; 0 otherwise. */ +/* */ +/*****************************************************************************/ + +#ifdef EXTERNAL_TEST + +int triunsuitable(); + +#else /* not EXTERNAL_TEST */ + +int triunsuitable(triorg, tridest, triapex, area) +vertex triorg; /* The triangle's origin vertex. */ +vertex tridest; /* The triangle's destination vertex. */ +vertex triapex; /* The triangle's apex vertex. */ +REAL area; /* The area of the triangle. */ +{ + REAL dxoa, dxda, dxod; + REAL dyoa, dyda, dyod; + REAL oalen, dalen, odlen; + REAL maxlen; + + dxoa = triorg[0] - triapex[0]; + dyoa = triorg[1] - triapex[1]; + dxda = tridest[0] - triapex[0]; + dyda = tridest[1] - triapex[1]; + dxod = triorg[0] - tridest[0]; + dyod = triorg[1] - tridest[1]; + /* Find the squares of the lengths of the triangle's three edges. */ + oalen = dxoa * dxoa + dyoa * dyoa; + dalen = dxda * dxda + dyda * dyda; + odlen = dxod * dxod + dyod * dyod; + /* Find the square of the length of the longest edge. */ + maxlen = (dalen > oalen) ? dalen : oalen; + maxlen = (odlen > maxlen) ? odlen : maxlen; + + if (maxlen > 0.05 * (triorg[0] * triorg[0] + triorg[1] * triorg[1]) + 0.02) { + return 1; + } else { + return 0; + } +} + +#endif /* not EXTERNAL_TEST */ + +/** **/ +/** **/ +/********* User-defined triangle evaluation routine ends here *********/ + +/********* Memory allocation wrappers begin here *********/ +/** **/ +/** **/ + +#ifdef ANSI_DECLARATORS +VOID *trimalloc(int size) +#else /* not ANSI_DECLARATORS */ +VOID *trimalloc(size) +int size; +#endif /* not ANSI_DECLARATORS */ + +{ + VOID *memptr; + + memptr = malloc((unsigned int) size); + if (memptr == (VOID *) NULL) { + printf("Error: Out of memory.\n"); + exit(1); + } + return(memptr); +} + +#ifdef ANSI_DECLARATORS +void trifree(VOID *memptr) +#else /* not ANSI_DECLARATORS */ +void trifree(memptr) +VOID *memptr; +#endif /* not ANSI_DECLARATORS */ + +{ + free(memptr); +} + +/** **/ +/** **/ +/********* Memory allocation wrappers end here *********/ + +/********* User interaction routines begin here *********/ +/** **/ +/** **/ + +/*****************************************************************************/ +/* */ +/* syntax() Print list of command line switches. */ +/* */ +/*****************************************************************************/ + +#ifndef TRILIBRARY + +void syntax() +{ +#ifdef CDT_ONLY +#ifdef REDUCED + printf("triangle [-pAcjevngBPNEIOXzo_lQVh] input_file\n"); +#else /* not REDUCED */ + printf("triangle [-pAcjevngBPNEIOXzo_iFlCQVh] input_file\n"); +#endif /* not REDUCED */ +#else /* not CDT_ONLY */ +#ifdef REDUCED + printf("triangle [-prq__a__uAcjevngBPNEIOXzo_YS__LlQVh] input_file\n"); +#else /* not REDUCED */ + printf("triangle [-prq__a__uAcjevngBPNEIOXzo_YS__LiFlsCQVh] input_file\n"); +#endif /* not REDUCED */ +#endif /* not CDT_ONLY */ + + printf(" -p Triangulates a Planar Straight Line Graph (.poly file).\n"); +#ifndef CDT_ONLY + printf(" -r Refines a previously generated mesh.\n"); + printf( + " -q Quality mesh generation. A minimum angle may be specified.\n"); + printf(" -a Applies a maximum triangle area constraint.\n"); + printf(" -u Applies a user-defined triangle constraint.\n"); +#endif /* not CDT_ONLY */ + printf( + " -A Applies attributes to identify triangles in certain regions.\n"); + printf(" -c Encloses the convex hull with segments.\n"); + printf(" -w Weighted Delaunay triangulation.\n"); + printf(" -W Regular triangulation (lower hull of a height field).\n"); + printf(" -j Jettison unused vertices from output .node file.\n"); + printf(" -e Generates an edge list.\n"); + printf(" -v Generates a Voronoi diagram.\n"); + printf(" -n Generates a list of triangle neighbors.\n"); + printf(" -g Generates an .off file for Geomview.\n"); + printf(" -B Suppresses output of boundary information.\n"); + printf(" -P Suppresses output of .poly file.\n"); + printf(" -N Suppresses output of .node file.\n"); + printf(" -E Suppresses output of .ele file.\n"); + printf(" -I Suppresses mesh iteration numbers.\n"); + printf(" -O Ignores holes in .poly file.\n"); + printf(" -X Suppresses use of exact arithmetic.\n"); + printf(" -z Numbers all items starting from zero (rather than one).\n"); + printf(" -o2 Generates second-order subparametric elements.\n"); +#ifndef CDT_ONLY + printf(" -Y Suppresses boundary segment splitting.\n"); + printf(" -S Specifies maximum number of added Steiner points.\n"); + printf(" -L Uses equatorial circles, not equatorial lenses.\n"); +#endif /* not CDT_ONLY */ +#ifndef REDUCED + printf(" -i Uses incremental method, rather than divide-and-conquer.\n"); + printf(" -F Uses Fortune's sweepline algorithm, rather than d-and-c.\n"); +#endif /* not REDUCED */ + printf(" -l Uses vertical cuts only, rather than alternating cuts.\n"); +#ifndef REDUCED +#ifndef CDT_ONLY + printf( + " -s Force segments into mesh by splitting (instead of using CDT).\n"); + printf(" -L Uses Ruppert's diametral spheres, not diametral lenses.\n"); +#endif /* not CDT_ONLY */ + printf(" -C Check consistency of final mesh.\n"); +#endif /* not REDUCED */ + printf(" -Q Quiet: No terminal output except errors.\n"); + printf(" -V Verbose: Detailed information on what I'm doing.\n"); + printf(" -h Help: Detailed instructions for Triangle.\n"); + exit(0); +} + +#endif /* not TRILIBRARY */ + +/*****************************************************************************/ +/* */ +/* info() Print out complete instructions. */ +/* */ +/*****************************************************************************/ + +#ifndef TRILIBRARY + +void info() +{ + printf("Triangle\n"); + printf( +"A Two-Dimensional Quality Mesh Generator and Delaunay Triangulator.\n"); + printf("Version 1.5\n\n"); + printf( +"Copyright 1993, 1995, 1997, 1998, 2002, 2004 Jonathan Richard Shewchuk\n"); + printf("2360 Woolsey #H / Berkeley, California 94705-1927\n"); + printf("Bugs/comments to jrs@cs.berkeley.edu\n"); + printf( +"Created as part of the Archimedes project (tools for parallel FEM).\n"); + printf( +"Supported in part by NSF Grant CMS-9318163 and an NSERC 1967 Scholarship.\n"); + printf("There is no warranty whatsoever. Use at your own risk.\n"); +#ifdef SINGLE + printf("This executable is compiled for single precision arithmetic.\n\n\n"); +#else /* not SINGLE */ + printf("This executable is compiled for double precision arithmetic.\n\n\n"); +#endif /* not SINGLE */ + printf( +"Triangle generates exact Delaunay triangulations, constrained Delaunay\n"); + printf( +"triangulations, Voronoi diagrams, and quality conforming Delaunay\n"); + printf( +"triangulations. The latter can be generated with no small angles, and are\n" +); + printf( +"thus suitable for finite element analysis. If no command line switches are\n" +); + printf( +"specified, your .node input file is read, and the Delaunay triangulation is\n" +); + printf("returned in .node and .ele output files. The command syntax is:\n"); + printf("\n"); + printf("triangle [-prq__a__uAcjevngBPNEIOXzo_YS__LiFlsCQVh] input_file\n"); + printf("\n"); + printf( +"Underscores indicate that numbers may optionally follow certain switches.\n"); + printf( +"Do not leave any space between a switch and its numeric parameter.\n"); + printf( +"input_file must be a file with extension .node, or extension .poly if the\n"); + printf( +"-p switch is used. If -r is used, you must supply .node and .ele files,\n"); + printf( +"and possibly a .poly file and an .area file as well. The formats of these\n" +); + printf("files are described below.\n\n"); + printf("Command Line Switches:\n\n"); + printf( +" -p Reads a Planar Straight Line Graph (.poly file), which can specify\n" +); + printf(" vertices, segments, holes, regional attributes, and area\n"); + printf( +" constraints. Generates a constrained Delaunay triangulation (CDT)\n" +); + printf( +" fitting the input; or, if -s, -q, -a, or -u is used, a conforming\n"); + printf( +" constrained Delaunay triangulation (CCDT). If -p is not used,\n"); + printf(" Triangle reads a .node file by default.\n"); + printf( +" -r Refines a previously generated mesh. The mesh is read from a .node\n" +); + printf( +" file and an .ele file. If -p is also used, a .poly file is read\n"); + printf( +" and used to constrain segments in the mesh. If -a is also used\n"); + printf( +" (with no number following), an .area file is read and used to\n"); + printf( +" impose area constraints on the mesh. Further details on refinement\n" +); + printf(" are given below.\n"); + printf( +" -q Quality mesh generation by my variant of Jim Ruppert's Delaunay\n"); + printf( +" refinement algorithm. Adds vertices to the mesh to ensure that no\n" +); + printf( +" angles smaller than 20 degrees occur. An alternative minimum angle\n" +); + printf( +" may be specified after the `q'. If the minimum angle is 20.7\n"); + printf( +" degrees or smaller, the triangulation algorithm is mathematically\n"); + printf( +" guaranteed to terminate (assuming infinite precision arithmetic--\n"); + printf( +" Triangle may fail to terminate if you run out of precision). In\n"); + printf( +" practice, the algorithm often succeeds for minimum angles up to\n"); + printf( +" 33.8 degrees. For some meshes, however, it may be necessary to\n"); + printf( +" reduce the minimum angle to avoid problems associated with\n"); + printf( +" insufficient floating-point precision. The specified angle may\n"); + printf(" include a decimal point.\n"); + printf( +" -a Imposes a maximum triangle area. If a number follows the `a', no\n"); + printf( +" triangle is generated whose area is larger than that number. If no\n" +); + printf( +" number is specified, an .area file (if -r is used) or .poly file\n"); + printf( +" (if -r is not used) specifies a set of maximum area constraints.\n"); + printf( +" An .area file contains a separate area constraint for each\n"); + printf( +" triangle, and is useful for refining a finite element mesh based on\n" +); + printf( +" a posteriori error estimates. A .poly file can optionally contain\n" +); + printf( +" an area constraint for each segment-bounded region, thereby\n"); + printf( +" controlling triangle densities in a first triangulation of a PSLG.\n" +); + printf( +" You can impose both a fixed area constraint and a varying area\n"); + printf( +" constraint by invoking the -a switch twice, once with and once\n"); + printf( +" without a number following. Each area specified may include a\n"); + printf(" decimal point.\n"); + printf( +" -u Imposes a user-defined constraint on triangle size. There are two\n" +); + printf( +" ways to use this feature. One is to edit the triunsuitable()\n"); + printf( +" procedure in triangle.c to encode any constraint you like, then\n"); + printf( +" recompile Triangle. The other is to compile triangle.c with the\n"); + printf( +" EXTERNAL_TEST symbol set (compiler switch -DEXTERNAL_TEST), then\n"); + printf( +" link Triangle against a separate object file that implements\n"); + printf( +" triunsuitable(). In either case, the -u switch causes the user-\n"); + printf(" defined test to be applied to every triangle.\n"); + printf( +" -A Assigns an additional attribute to each triangle that identifies\n"); + printf( +" what segment-bounded region each triangle belongs to. Attributes\n"); + printf( +" are assigned to regions by the .poly file. If a region is not\n"); + printf( +" explicitly marked by the .poly file, triangles in that region are\n"); + printf( +" assigned an attribute of zero. The -A switch has an effect only\n"); + printf(" when the -p switch is used and the -r switch is not.\n"); + printf( +" -c Creates segments on the convex hull of the triangulation. If you\n"); + printf( +" are triangulating a vertex set, this switch causes a .poly file to\n" +); + printf( +" be written, containing all edges in the convex hull. If you are\n"); + printf( +" triangulating a PSLG, this switch specifies that the whole convex\n"); + printf( +" hull of the PSLG should be triangulated, regardless of what\n"); + printf( +" segments the PSLG has. If you do not use this switch when\n"); + printf( +" triangulating a PSLG, it is assumed that you have identified the\n"); + printf( +" region to be triangulated by surrounding it with segments of the\n"); + printf( +" input PSLG. Beware: if you are not careful, this switch can cause\n" +); + printf( +" the introduction of an extremely thin angle between a PSLG segment\n" +); + printf( +" and a convex hull segment, which can cause overrefinement (and\n"); + printf( +" possibly failure if Triangle runs out of precision). If you are\n"); + printf( +" refining a mesh, the -c switch works differently; it generates the\n" +); + printf( +" set of boundary edges of the mesh (useful if no .poly file was\n"); + printf(" read).\n"); + printf( +" -j Jettisons vertices that are not part of the final triangulation\n"); + printf( +" from the output .node file. By default, Triangle copies all\n"); + printf( +" vertices in the input .node file to the output .node file, in the\n"); + printf( +" same order, so their indices do not change. The -j switch prevents\n" +); + printf( +" duplicated input vertices from appearing in the output .node file;\n" +); + printf( +" hence, if two input vertices have exactly the same coordinates,\n"); + printf( +" only the first appears in the output. If any vertices are\n"); + printf( +" jettisoned, the vertex numbering in the output .node file differs\n"); + printf(" from that of the input .node file.\n"); + printf( +" -e Outputs (to an .edge file) a list of edges of the triangulation.\n"); + printf( +" -v Outputs the Voronoi diagram associated with the triangulation.\n"); + printf( +" Does not attempt to detect degeneracies, so some Voronoi vertices\n"); + printf( +" may be duplicated. See the discussion of Voronoi diagrams below.\n"); + printf( +" -n Outputs (to a .neigh file) a list of triangles neighboring each\n"); + printf(" triangle.\n"); + printf( +" -g Outputs the mesh to an Object File Format (.off) file, suitable for\n" +); + printf(" viewing with the Geometry Center's Geomview package.\n"); + printf( +" -B No boundary markers in the output .node, .poly, and .edge output\n"); + printf( +" files. See the detailed discussion of boundary markers below.\n"); + printf( +" -P No output .poly file. Saves disk space, but you lose the ability\n"); + printf( +" to maintain constraining segments on later refinements of the mesh.\n" +); + printf(" -N No output .node file.\n"); + printf(" -E No output .ele file.\n"); + printf( +" -I No iteration numbers. Suppresses the output of .node and .poly\n"); + printf( +" files, so your input files won't be overwritten. (If your input is\n" +); + printf( +" a .poly file only, a .node file is written.) Cannot be used with\n"); + printf( +" the -r switch, because that would overwrite your input .ele file.\n"); + printf( +" Shouldn't be used with the -q, -a, -u, or -s switch if you are\n"); + printf( +" using a .node file for input, because no .node file is written, so\n" +); + printf(" there is no record of any added Steiner points.\n"); + printf(" -O No holes. Ignores the holes in the .poly file.\n"); + printf( +" -X No exact arithmetic. Normally, Triangle uses exact floating-point\n" +); + printf( +" arithmetic for certain tests if it thinks the inexact tests are not\n" +); + printf( +" accurate enough. Exact arithmetic ensures the robustness of the\n"); + printf( +" triangulation algorithms, despite floating-point roundoff error.\n"); + printf( +" Disabling exact arithmetic with the -X switch causes a small\n"); + printf( +" improvement in speed and creates the possibility (albeit small)\n"); + printf( +" that Triangle will fail to produce a valid mesh. Not recommended.\n" +); + printf( +" -z Numbers all items starting from zero (rather than one). Note that\n" +); + printf( +" this switch is normally overrided by the value used to number the\n"); + printf( +" first vertex of the input .node or .poly file. However, this\n"); + printf( +" switch is useful when calling Triangle from another program.\n"); + printf( +" -o2 Generates second-order subparametric elements with six nodes each.\n" +); + printf( +" -Y No new vertices on the boundary. This switch is useful when the\n"); + printf( +" mesh boundary must be preserved so that it conforms to some\n"); + printf( +" adjacent mesh. Be forewarned that you will probably sacrifice some\n" +); + printf( +" of the quality of the mesh; Triangle will try, but the resulting\n"); + printf( +" mesh may contain triangles of poor aspect ratio. Works well if all\n" +); + printf( +" the boundary vertices are closely spaced. Specify this switch\n"); + printf( +" twice (`-YY') to prevent all segment splitting, including internal\n" +); + printf(" boundaries.\n"); + printf( +" -S Specifies the maximum number of Steiner points (vertices that are\n"); + printf( +" not in the input, but are added to meet the constraints on minimum\n" +); + printf( +" angle and maximum area). The default is to allow an unlimited\n"); + printf( +" number. If you specify this switch with no number after it,\n"); + printf( +" the limit is set to zero. Triangle always adds vertices at segment\n" +); + printf( +" intersections, even if it needs to use more vertices than the limit\n" +); + printf( +" you set. When Triangle inserts segments by splitting (-s), it\n"); + printf( +" always adds enough vertices to ensure that all the segments of the\n" +); + printf(" PLSG are recovered, ignoring the limit if necessary.\n"); + printf( +" -L Do not use diametral lenses to determine whether subsegments are\n"); + printf( +" encroached; use diametral circles instead (as in Ruppert's\n"); + printf( +" algorithm). Use this switch if you want all triangles in the mesh\n" +); + printf( +" to be Delaunay, and not just constrained Delaunay; or if you want\n"); + printf( +" to ensure that all Voronoi vertices lie within the triangulation.\n"); + printf( +" (Applications such as some finite volume methods may have this\n"); + printf( +" requirement.) This switch may increase the number of vertices in\n"); + printf(" the mesh to meet these constraints.\n"); + printf( +" -i Uses an incremental rather than divide-and-conquer algorithm to\n"); + printf( +" form a Delaunay triangulation. Try it if the divide-and-conquer\n"); + printf(" algorithm fails.\n"); + printf( +" -F Uses Steven Fortune's sweepline algorithm to form a Delaunay\n"); + printf( +" triangulation. Warning: does not use exact arithmetic for all\n"); + printf(" calculations. An exact result is not guaranteed.\n"); + printf( +" -l Uses only vertical cuts in the divide-and-conquer algorithm. By\n"); + printf( +" default, Triangle uses alternating vertical and horizontal cuts,\n"); + printf( +" which usually improve the speed except with vertex sets that are\n"); + printf( +" small or short and wide. This switch is primarily of theoretical\n"); + printf(" interest.\n"); + printf( +" -s Specifies that segments should be forced into the triangulation by\n" +); + printf( +" recursively splitting them at their midpoints, rather than by\n"); + printf( +" generating a constrained Delaunay triangulation. Segment splitting\n" +); + printf( +" is true to Ruppert's original algorithm, but can create needlessly\n" +); + printf( +" small triangles. This switch is primarily of theoretical interest.\n" +); + printf( +" -C Check the consistency of the final mesh. Uses exact arithmetic for\n" +); + printf( +" checking, even if the -X switch is used. Useful if you suspect\n"); + printf(" Triangle is buggy.\n"); + printf( +" -Q Quiet: Suppresses all explanation of what Triangle is doing,\n"); + printf(" unless an error occurs.\n"); + printf( +" -V Verbose: Gives detailed information about what Triangle is doing.\n" +); + printf( +" Add more `V's for increasing amount of detail. `-V' gives\n"); + printf( +" information on algorithmic progress and more detailed statistics.\n"); + printf( +" `-VV' gives vertex-by-vertex details, and prints so much that\n"); + printf( +" Triangle runs much more slowly. `-VVVV' gives information only\n"); + printf(" a debugger could love.\n"); + printf(" -h Help: Displays these instructions.\n"); + printf("\n"); + printf("Definitions:\n"); + printf("\n"); + printf( +" A Delaunay triangulation of a vertex set is a triangulation whose\n"); + printf( +" vertices are the vertex set, wherein no vertex in the vertex set falls in\n" +); + printf( +" the interior of the circumcircle (circle that passes through all three\n"); + printf(" vertices) of any triangle in the triangulation.\n\n"); + printf( +" A Voronoi diagram of a vertex set is a subdivision of the plane into\n"); + printf( +" polygonal regions (some of which may be infinite), where each region is\n"); + printf( +" the set of points in the plane that are closer to some input vertex than\n" +); + printf( +" to any other input vertex. (The Voronoi diagram is the geometric dual of\n" +); + printf(" the Delaunay triangulation.)\n\n"); + printf( +" A Planar Straight Line Graph (PSLG) is a set of vertices and segments.\n"); + printf( +" Segments are simply edges, whose endpoints are vertices in the PSLG.\n"); + printf( +" Segments may intersect each other only at their endpoints. The file\n"); + printf(" format for PSLGs (.poly files) is described below.\n\n"); + printf( +" A constrained Delaunay triangulation (CDT) of a PSLG is similar to a\n"); + printf( +" Delaunay triangulation, but each PSLG segment is present as a single edge\n" +); + printf( +" in the triangulation. (A constrained Delaunay triangulation is not truly\n" +); + printf( +" a Delaunay triangulation.) By definition, a CDT does not have any\n"); + printf(" vertices other than those specified in the input PSLG.\n\n"); + printf( +" A conforming Delaunay triangulation of a PSLG is a true Delaunay\n"); + printf( +" triangulation in which each PSLG segment is represented by a linear\n"); + printf( +" contiguous sequence of edges in the triangulation. Each input segment\n"); + printf( +" may have been subdivided into shorter subsegments by the insertion of\n"); + printf( +" additional vertices. These inserted vertices are necessary to maintain\n"); + printf( +" the Delaunay property while ensuring that every segment is represented.\n"); + printf("\n"); + printf("File Formats:\n"); + printf("\n"); + printf( +" All files may contain comments prefixed by the character '#'. Vertices,\n" +); + printf( +" triangles, edges, holes, and maximum area constraints must be numbered\n"); + printf( +" consecutively, starting from either 1 or 0. Whichever you choose, all\n"); + printf( +" input files must be consistent; if the vertices are numbered from 1, so\n"); + printf( +" must be all other objects. Triangle automatically detects your choice\n"); + printf( +" while reading the .node (or .poly) file. (When calling Triangle from\n"); + printf( +" another program, use the -z switch if you wish to number objects from\n"); + printf(" zero.) Examples of these file formats are given below.\n\n"); + printf(" .node files:\n"); + printf( +" First line: <# of vertices> <dimension (must be 2)> <# of attributes>\n" +); + printf( +" <# of boundary markers (0 or 1)>\n" +); + printf( +" Remaining lines: <vertex #> <x> <y> [attributes] [boundary marker]\n"); + printf("\n"); + printf( +" The attributes, which are typically floating-point values of physical\n"); + printf( +" quantities (such as mass or conductivity) associated with the nodes of\n" +); + printf( +" a finite element mesh, are copied unchanged to the output mesh. If -q,\n" +); + printf( +" -a, -u, or -s is selected, each new Steiner point added to the mesh\n"); + printf(" has attributes assigned to it by linear interpolation.\n\n"); + printf( +" If the fourth entry of the first line is `1', the last column of the\n"); + printf( +" remainder of the file is assumed to contain boundary markers. Boundary\n" +); + printf( +" markers are used to identify boundary vertices and vertices resting on\n" +); + printf( +" PSLG segments; a complete description appears in a section below. The\n" +); + printf( +" .node file produced by Triangle contains boundary markers in the last\n"); + printf(" column unless they are suppressed by the -B switch.\n\n"); + printf(" .ele files:\n"); + printf( +" First line: <# of triangles> <nodes per triangle> <# of attributes>\n"); + printf( +" Remaining lines: <triangle #> <node> <node> <node> ... [attributes]\n"); + printf("\n"); + printf( +" Nodes are indices into the corresponding .node file. The first three\n"); + printf( +" nodes are the corner vertices, and are listed in counterclockwise order\n" +); + printf( +" around each triangle. (The remaining nodes, if any, depend on the type\n" +); + printf(" of finite element used.)\n\n"); + printf( +" The attributes are just like those of .node files. Because there is no\n" +); + printf( +" simple mapping from input to output triangles, an attempt is made to\n"); + printf( +" interpolate attributes, which may result in a good deal of diffusion of\n" +); + printf( +" attributes among nearby triangles as the triangulation is refined.\n"); + printf( +" Attributes do not diffuse across segments, so attributes used to\n"); + printf(" identify segment-bounded regions remain intact.\n\n"); + printf( +" In .ele files produced by Triangle, each triangular element has three\n"); + printf( +" nodes (vertices) unless the -o2 switch is used, in which case\n"); + printf( +" subparametric quadratic elements with six nodes each are generated.\n"); + printf( +" The first three nodes are the corners in counterclockwise order, and\n"); + printf( +" the fourth, fifth, and sixth nodes lie on the midpoints of the edges\n"); + printf( +" opposite the first, second, and third vertices, respectively.\n"); + printf("\n"); + printf(" .poly files:\n"); + printf( +" First line: <# of vertices> <dimension (must be 2)> <# of attributes>\n" +); + printf( +" <# of boundary markers (0 or 1)>\n" +); + printf( +" Following lines: <vertex #> <x> <y> [attributes] [boundary marker]\n"); + printf(" One line: <# of segments> <# of boundary markers (0 or 1)>\n"); + printf( +" Following lines: <segment #> <endpoint> <endpoint> [boundary marker]\n"); + printf(" One line: <# of holes>\n"); + printf(" Following lines: <hole #> <x> <y>\n"); + printf( +" Optional line: <# of regional attributes and/or area constraints>\n"); + printf( +" Optional following lines: <region #> <x> <y> <attribute> <max area>\n"); + printf("\n"); + printf( +" A .poly file represents a PSLG, as well as some additional information.\n" +); + printf( +" The first section lists all the vertices, and is identical to the\n"); + printf( +" format of .node files. <# of vertices> may be set to zero to indicate\n" +); + printf( +" that the vertices are listed in a separate .node file; .poly files\n"); + printf( +" produced by Triangle always have this format. A vertex set represented\n" +); + printf( +" this way has the advantage that it may easily be triangulated with or\n"); + printf( +" without segments (depending on whether the .poly or .node file is\n"); + printf(" read).\n\n"); + printf( +" The second section lists the segments. Segments are edges whose\n"); + printf( +" presence in the triangulation is enforced (although each segment may be\n" +); + printf( +" subdivided into smaller edges). Each segment is specified by listing\n"); + printf( +" the indices of its two endpoints. This means that you must include its\n" +); + printf( +" endpoints in the vertex list. Each segment, like each point, may have\n" +); + printf(" a boundary marker.\n\n"); + printf( +" If -q, -a, -u, and -s are not selected, Triangle produces a constrained\n" +); + printf( +" Delaunay triangulation (CDT), in which each segment appears as a single\n" +); + printf( +" edge in the triangulation. If -q, -a, -u, or -s is selected, Triangle\n" +); + printf( +" produces a conforming constrained Delaunay triangulation (CCDT), in\n"); + printf( +" which segments may be subdivided into smaller edges. If -L is selected\n" +); + printf( +" as well, Triangle produces a conforming Delaunay triangulation, so\n"); + printf( +" every triangle is Delaunay, and not just constrained Delaunay.\n"); + printf("\n"); + printf( +" The third section lists holes (and concavities, if -c is selected) in\n"); + printf( +" the triangulation. Holes are specified by identifying a point inside\n"); + printf( +" each hole. After the triangulation is formed, Triangle creates holes\n"); + printf( +" by eating triangles, spreading out from each hole point until its\n"); + printf( +" progress is blocked by PSLG segments; you must be careful to enclose\n"); + printf( +" each hole in segments, or your whole triangulation might be eaten away.\n" +); + printf( +" If the two triangles abutting a segment are eaten, the segment itself\n"); + printf( +" is also eaten. Do not place a hole directly on a segment; if you do,\n"); + printf(" Triangle chooses one side of the segment arbitrarily.\n\n"); + printf( +" The optional fourth section lists regional attributes (to be assigned\n"); + printf( +" to all triangles in a region) and regional constraints on the maximum\n"); + printf( +" triangle area. Triangle reads this section only if the -A switch is\n"); + printf( +" used or the -a switch is used without a number following it, and the -r\n" +); + printf( +" switch is not used. Regional attributes and area constraints are\n"); + printf( +" propagated in the same manner as holes; you specify a point for each\n"); + printf( +" attribute and/or constraint, and the attribute and/or constraint\n"); + printf( +" affects the whole region (bounded by segments) containing the point.\n"); + printf( +" If two values are written on a line after the x and y coordinate, the\n"); + printf( +" first such value is assumed to be a regional attribute (but is only\n"); + printf( +" applied if the -A switch is selected), and the second value is assumed\n" +); + printf( +" to be a regional area constraint (but is only applied if the -a switch\n" +); + printf( +" is selected). You may specify just one value after the coordinates,\n"); + printf( +" which can serve as both an attribute and an area constraint, depending\n" +); + printf( +" on the choice of switches. If you are using the -A and -a switches\n"); + printf( +" simultaneously and wish to assign an attribute to some region without\n"); + printf(" imposing an area constraint, use a negative maximum area.\n\n"); + printf( +" When a triangulation is created from a .poly file, you must either\n"); + printf( +" enclose the entire region to be triangulated in PSLG segments, or\n"); + printf( +" use the -c switch, which encloses the convex hull of the input vertex\n"); + printf( +" set. If you do not use the -c switch, Triangle eats all triangles that\n" +); + printf( +" are not enclosed by segments; if you are not careful, your whole\n"); + printf( +" triangulation may be eaten away. If you do use the -c switch, you can\n" +); + printf( +" still produce concavities by the appropriate placement of holes just\n"); + printf(" within the convex hull.\n\n"); + printf( +" An ideal PSLG has no intersecting segments, nor any vertices that lie\n"); + printf( +" upon segments (except, of course, the endpoints of each segment.) You\n" +); + printf( +" aren't required to make your .poly files ideal, but you should be aware\n" +); + printf( +" of what can go wrong. Segment intersections are relatively safe--\n"); + printf( +" Triangle calculates the intersection points for you and adds them to\n"); + printf( +" the triangulation--as long as your machine's floating-point precision\n"); + printf( +" doesn't become a problem. You are tempting the fates if you have three\n" +); + printf( +" segments that cross at the same location, and expect Triangle to figure\n" +); + printf( +" out where the intersection point is. Thanks to floating-point roundoff\n" +); + printf( +" error, Triangle will probably decide that the three segments intersect\n" +); + printf( +" at three different points, and you will find a minuscule triangle in\n"); + printf( +" your output--unless Triangle tries to refine the tiny triangle, uses\n"); + printf( +" up the last bit of machine precision, and fails to terminate at all.\n"); + printf( +" You're better off putting the intersection point in the input files,\n"); + printf( +" and manually breaking up each segment into two. Similarly, if you\n"); + printf( +" place a vertex at the middle of a segment, and hope that Triangle will\n" +); + printf( +" break up the segment at that vertex, you might get lucky. On the other\n" +); + printf( +" hand, Triangle might decide that the vertex doesn't lie precisely on\n"); + printf( +" the segment, and you'll have a needle-sharp triangle in your output--or\n" +); + printf(" a lot of tiny triangles if you're generating a quality mesh.\n"); + printf("\n"); + printf( +" When Triangle reads a .poly file, it also writes a .poly file, which\n"); + printf( +" includes all edges that are parts of input segments. If the -c switch\n" +); + printf( +" is used, the output .poly file also includes all of the edges on the\n"); + printf( +" convex hull. Hence, the output .poly file is useful for finding edges\n" +); + printf( +" associated with input segments and for setting boundary conditions in\n"); + printf( +" finite element simulations. Moreover, you will need it if you plan to\n" +); + printf( +" refine the output mesh, and don't want segments to be missing in later\n" +); + printf(" triangulations.\n\n"); + printf(" .area files:\n"); + printf(" First line: <# of triangles>\n"); + printf(" Following lines: <triangle #> <maximum area>\n\n"); + printf( +" An .area file associates with each triangle a maximum area that is used\n" +); + printf( +" for mesh refinement. As with other file formats, every triangle must\n"); + printf( +" be represented, and they must be numbered consecutively. A triangle\n"); + printf( +" may be left unconstrained by assigning it a negative maximum area.\n"); + printf("\n"); + printf(" .edge files:\n"); + printf(" First line: <# of edges> <# of boundary markers (0 or 1)>\n"); + printf( +" Following lines: <edge #> <endpoint> <endpoint> [boundary marker]\n"); + printf("\n"); + printf( +" Endpoints are indices into the corresponding .node file. Triangle can\n" +); + printf( +" produce .edge files (use the -e switch), but cannot read them. The\n"); + printf( +" optional column of boundary markers is suppressed by the -B switch.\n"); + printf("\n"); + printf( +" In Voronoi diagrams, one also finds a special kind of edge that is an\n"); + printf( +" infinite ray with only one endpoint. For these edges, a different\n"); + printf(" format is used:\n\n"); + printf(" <edge #> <endpoint> -1 <direction x> <direction y>\n\n"); + printf( +" The `direction' is a floating-point vector that indicates the direction\n" +); + printf(" of the infinite ray.\n\n"); + printf(" .neigh files:\n"); + printf( +" First line: <# of triangles> <# of neighbors per triangle (always 3)>\n" +); + printf( +" Following lines: <triangle #> <neighbor> <neighbor> <neighbor>\n"); + printf("\n"); + printf( +" Neighbors are indices into the corresponding .ele file. An index of -1\n" +); + printf( +" indicates no neighbor (because the triangle is on an exterior\n"); + printf( +" boundary). The first neighbor of triangle i is opposite the first\n"); + printf(" corner of triangle i, and so on.\n\n"); + printf( +" Triangle can produce .neigh files (use the -n switch), but cannot read\n" +); + printf(" them.\n\n"); + printf("Boundary Markers:\n\n"); + printf( +" Boundary markers are tags used mainly to identify which output vertices\n"); + printf( +" and edges are associated with which PSLG segment, and to identify which\n"); + printf( +" vertices and edges occur on a boundary of the triangulation. A common\n"); + printf( +" use is to determine where boundary conditions should be applied to a\n"); + printf( +" finite element mesh. You can prevent boundary markers from being written\n" +); + printf(" into files produced by Triangle by using the -B switch.\n\n"); + printf( +" The boundary marker associated with each segment in an output .poly file\n" +); + printf(" and each edge in an output .edge file is chosen as follows:\n"); + printf( +" - If an output edge is part or all of a PSLG segment with a nonzero\n"); + printf( +" boundary marker, then the edge is assigned the same marker.\n"); + printf( +" - Otherwise, if the edge occurs on a boundary of the triangulation\n"); + printf( +" (including boundaries of holes), then the edge is assigned the marker\n" +); + printf(" one (1).\n"); + printf(" - Otherwise, the edge is assigned the marker zero (0).\n"); + printf( +" The boundary marker associated with each vertex in an output .node file\n"); + printf(" is chosen as follows:\n"); + printf( +" - If a vertex is assigned a nonzero boundary marker in the input file,\n" +); + printf( +" then it is assigned the same marker in the output .node file.\n"); + printf( +" - Otherwise, if the vertex lies on a PSLG segment (including the\n"); + printf( +" segment's endpoints) with a nonzero boundary marker, then the vertex\n" +); + printf( +" is assigned the same marker. If the vertex lies on several such\n"); + printf(" segments, one of the markers is chosen arbitrarily.\n"); + printf( +" - Otherwise, if the vertex occurs on a boundary of the triangulation,\n"); + printf(" then the vertex is assigned the marker one (1).\n"); + printf(" - Otherwise, the vertex is assigned the marker zero (0).\n"); + printf("\n"); + printf( +" If you want Triangle to determine for you which vertices and edges are on\n" +); + printf( +" the boundary, assign them the boundary marker zero (or use no markers at\n" +); + printf( +" all) in your input files. In the output files, all boundary vertices,\n"); + printf(" edges, and segments are assigned the value one.\n\n"); + printf("Triangulation Iteration Numbers:\n\n"); + printf( +" Because Triangle can read and refine its own triangulations, input\n"); + printf( +" and output files have iteration numbers. For instance, Triangle might\n"); + printf( +" read the files mesh.3.node, mesh.3.ele, and mesh.3.poly, refine the\n"); + printf( +" triangulation, and output the files mesh.4.node, mesh.4.ele, and\n"); + printf(" mesh.4.poly. Files with no iteration number are treated as if\n"); + printf( +" their iteration number is zero; hence, Triangle might read the file\n"); + printf( +" points.node, triangulate it, and produce the files points.1.node and\n"); + printf(" points.1.ele.\n\n"); + printf( +" Iteration numbers allow you to create a sequence of successively finer\n"); + printf( +" meshes suitable for multigrid methods. They also allow you to produce a\n" +); + printf( +" sequence of meshes using error estimate-driven mesh refinement.\n"); + printf("\n"); + printf( +" If you're not using refinement or quality meshing, and you don't like\n"); + printf( +" iteration numbers, use the -I switch to disable them. This switch also\n"); + printf( +" disables output of .node and .poly files to prevent your input files from\n" +); + printf( +" being overwritten. (If the input is a .poly file that contains its own\n"); + printf(" points, a .node file is written.)\n\n"); + printf("Examples of How to Use Triangle:\n\n"); + printf( +" `triangle dots' reads vertices from dots.node, and writes their Delaunay\n" +); + printf( +" triangulation to dots.1.node and dots.1.ele. (dots.1.node is identical\n"); + printf( +" to dots.node.) `triangle -I dots' writes the triangulation to dots.ele\n"); + printf( +" instead. (No additional .node file is needed, so none is written.)\n"); + printf("\n"); + printf( +" `triangle -pe object.1' reads a PSLG from object.1.poly (and possibly\n"); + printf( +" object.1.node, if the vertices are omitted from object.1.poly) and writes\n" +); + printf( +" its constrained Delaunay triangulation to object.2.node and object.2.ele.\n" +); + printf( +" The segments are copied to object.2.poly, and all edges are written to\n"); + printf(" object.2.edge.\n\n"); + printf( +" `triangle -pq31.5a.1 object' reads a PSLG from object.poly (and possibly\n" +); + printf( +" object.node), generates a mesh whose angles are all 31.5 degrees or\n"); + printf( +" greater and whose triangles all have areas of 0.1 or less, and writes the\n" +); + printf( +" mesh to object.1.node and object.1.ele. Each segment may be broken up\n"); + printf(" into multiple subsegments; these are written to object.1.poly.\n"); + printf("\n"); + printf( +" Here is a sample file `box.poly' describing a square with a square hole:\n" +); + printf("\n"); + printf( +" # A box with eight vertices in 2D, no attributes, one boundary marker.\n" +); + printf(" 8 2 0 1\n"); + printf(" # Outer box has these vertices:\n"); + printf(" 1 0 0 0\n"); + printf(" 2 0 3 0\n"); + printf(" 3 3 0 0\n"); + printf(" 4 3 3 33 # A special marker for this vertex.\n"); + printf(" # Inner square has these vertices:\n"); + printf(" 5 1 1 0\n"); + printf(" 6 1 2 0\n"); + printf(" 7 2 1 0\n"); + printf(" 8 2 2 0\n"); + printf(" # Five segments with boundary markers.\n"); + printf(" 5 1\n"); + printf(" 1 1 2 5 # Left side of outer box.\n"); + printf(" # Square hole has these segments:\n"); + printf(" 2 5 7 0\n"); + printf(" 3 7 8 0\n"); + printf(" 4 8 6 10\n"); + printf(" 5 6 5 0\n"); + printf(" # One hole in the middle of the inner square.\n"); + printf(" 1\n"); + printf(" 1 1.5 1.5\n"); + printf("\n"); + printf( +" Note that some segments are missing from the outer square, so one must\n"); + printf( +" use the `-c' switch. After `triangle -pqc box.poly', here is the output\n" +); + printf( +" file `box.1.node', with twelve vertices. The last four vertices were\n"); + printf( +" added to meet the angle constraint. Vertices 1, 2, and 9 have markers\n"); + printf( +" from segment 1. Vertices 6 and 8 have markers from segment 4. All the\n"); + printf( +" other vertices but 4 have been marked to indicate that they lie on a\n"); + printf(" boundary.\n\n"); + printf(" 12 2 0 1\n"); + printf(" 1 0 0 5\n"); + printf(" 2 0 3 5\n"); + printf(" 3 3 0 1\n"); + printf(" 4 3 3 33\n"); + printf(" 5 1 1 1\n"); + printf(" 6 1 2 10\n"); + printf(" 7 2 1 1\n"); + printf(" 8 2 2 10\n"); + printf(" 9 0 1.5 5\n"); + printf(" 10 1.5 0 1\n"); + printf(" 11 3 1.5 1\n"); + printf(" 12 1.5 3 1\n"); + printf(" # Generated by triangle -pqc box.poly\n"); + printf("\n"); + printf(" Here is the output file `box.1.ele', with twelve triangles.\n"); + printf("\n"); + printf(" 12 3 0\n"); + printf(" 1 5 6 9\n"); + printf(" 2 10 3 7\n"); + printf(" 3 6 8 12\n"); + printf(" 4 9 1 5\n"); + printf(" 5 6 2 9\n"); + printf(" 6 7 3 11\n"); + printf(" 7 11 4 8\n"); + printf(" 8 7 5 10\n"); + printf(" 9 12 2 6\n"); + printf(" 10 8 7 11\n"); + printf(" 11 5 1 10\n"); + printf(" 12 8 4 12\n"); + printf(" # Generated by triangle -pqc box.poly\n\n"); + printf( +" Here is the output file `box.1.poly'. Note that segments have been added\n" +); + printf( +" to represent the convex hull, and some segments have been split by newly\n" +); + printf( +" added vertices. Note also that <# of vertices> is set to zero to\n"); + printf(" indicate that the vertices should be read from the .node file.\n"); + printf("\n"); + printf(" 0 2 0 1\n"); + printf(" 12 1\n"); + printf(" 1 1 9 5\n"); + printf(" 2 5 7 1\n"); + printf(" 3 8 7 1\n"); + printf(" 4 6 8 10\n"); + printf(" 5 5 6 1\n"); + printf(" 6 3 10 1\n"); + printf(" 7 4 11 1\n"); + printf(" 8 2 12 1\n"); + printf(" 9 9 2 5\n"); + printf(" 10 10 1 1\n"); + printf(" 11 11 3 1\n"); + printf(" 12 12 4 1\n"); + printf(" 1\n"); + printf(" 1 1.5 1.5\n"); + printf(" # Generated by triangle -pqc box.poly\n"); + printf("\n"); + printf("Refinement and Area Constraints:\n"); + printf("\n"); + printf( +" The -r switch causes a mesh (.node and .ele files) to be read and\n"); + printf( +" refined. If the -p switch is also used, a .poly file is read and used to\n" +); + printf( +" specify edges that are constrained and cannot be eliminated (although\n"); + printf( +" they can be divided into smaller edges) by the refinement process.\n"); + printf("\n"); + printf( +" When you refine a mesh, you generally want to impose tighter quality\n"); + printf( +" constraints. One way to accomplish this is to use -q with a larger\n"); + printf( +" angle, or -a followed by a smaller area than you used to generate the\n"); + printf( +" mesh you are refining. Another way to do this is to create an .area\n"); + printf( +" file, which specifies a maximum area for each triangle, and use the -a\n"); + printf( +" switch (without a number following). Each triangle's area constraint is\n" +); + printf( +" applied to that triangle. Area constraints tend to diffuse as the mesh\n"); + printf( +" is refined, so if there are large variations in area constraint between\n"); + printf(" adjacent triangles, you may not get the results you want.\n\n"); + printf( +" If you are refining a mesh composed of linear (three-node) elements, the\n" +); + printf( +" output mesh contains all the nodes present in the input mesh, in the same\n" +); + printf( +" order, with new nodes added at the end of the .node file. However, the\n"); + printf( +" refinement is not hierarchical: there is no guarantee that each output\n"); + printf( +" element is contained in a single input element. Often, output elements\n"); + printf( +" overlap two input elements, and some input edges are not present in the\n"); + printf( +" output mesh. Hence, a sequence of refined meshes forms a hierarchy of\n"); + printf( +" nodes, but not a hierarchy of elements. If you refine a mesh of higher-\n" +); + printf( +" order elements, the hierarchical property applies only to the nodes at\n"); + printf( +" the corners of an element; other nodes may not be present in the refined\n" +); + printf(" mesh.\n\n"); + printf( +" Maximum area constraints in .poly files operate differently from those in\n" +); + printf( +" .area files. A maximum area in a .poly file applies to the whole\n"); + printf( +" (segment-bounded) region in which a point falls, whereas a maximum area\n"); + printf( +" in an .area file applies to only one triangle. Area constraints in .poly\n" +); + printf( +" files are used only when a mesh is first generated, whereas area\n"); + printf( +" constraints in .area files are used only to refine an existing mesh, and\n" +); + printf( +" are typically based on a posteriori error estimates resulting from a\n"); + printf(" finite element simulation on that mesh.\n\n"); + printf( +" `triangle -rq25 object.1' reads object.1.node and object.1.ele, then\n"); + printf( +" refines the triangulation to enforce a 25 degree minimum angle, and then\n" +); + printf( +" writes the refined triangulation to object.2.node and object.2.ele.\n"); + printf("\n"); + printf( +" `triangle -rpaa6.2 z.3' reads z.3.node, z.3.ele, z.3.poly, and z.3.area.\n" +); + printf( +" After reconstructing the mesh and its subsegments, Triangle refines the\n"); + printf( +" mesh so that no triangle has area greater than 6.2, and furthermore the\n"); + printf( +" triangles satisfy the maximum area constraints in z.3.area. No angle\n"); + printf( +" bound is imposed at all. The output is written to z.4.node, z.4.ele, and\n" +); + printf(" z.4.poly.\n\n"); + printf( +" The sequence `triangle -qa1 x', `triangle -rqa.3 x.1', `triangle -rqa.1\n"); + printf( +" x.2' creates a sequence of successively finer meshes x.1, x.2, and x.3,\n"); + printf(" suitable for multigrid.\n\n"); + printf("Convex Hulls and Mesh Boundaries:\n\n"); + printf( +" If the input is a vertex set (rather than a PSLG), Triangle produces its\n" +); + printf( +" convex hull as a by-product in the output .poly file if you use the -c\n"); + printf( +" switch. There are faster algorithms for finding a two-dimensional convex\n" +); + printf( +" hull than triangulation, of course, but this one comes for free.\n"); + printf("\n"); + printf( +" If the input is an unconstrained mesh (you are using the -r switch but\n"); + printf( +" not the -p switch), Triangle produces a list of its boundary edges\n"); + printf( +" (including hole boundaries) as a by-product when you use the -c switch.\n"); + printf( +" If you also use the -p switch, the output .poly file contains all the\n"); + printf(" segments from the input .poly file as well.\n\n"); + printf("Voronoi Diagrams:\n\n"); + printf( +" The -v switch produces a Voronoi diagram, in files suffixed .v.node and\n"); + printf( +" .v.edge. For example, `triangle -v points' reads points.node, produces\n"); + printf( +" its Delaunay triangulation in points.1.node and points.1.ele, and\n"); + printf( +" produces its Voronoi diagram in points.1.v.node and points.1.v.edge. The\n" +); + printf( +" .v.node file contains a list of all Voronoi vertices, and the .v.edge\n"); + printf( +" file contains a list of all Voronoi edges, some of which may be infinite\n" +); + printf( +" rays. (The choice of filenames makes it easy to run the set of Voronoi\n"); + printf(" vertices through Triangle, if so desired.)\n\n"); + printf( +" This implementation does not use exact arithmetic to compute the Voronoi\n" +); + printf( +" vertices, and does not check whether neighboring vertices are identical.\n" +); + printf( +" Be forewarned that if the Delaunay triangulation is degenerate or\n"); + printf( +" near-degenerate, the Voronoi diagram may have duplicate vertices,\n"); + printf( +" crossing edges, or infinite rays whose direction vector is zero.\n"); + printf("\n"); + printf( +" The result is a valid Voronoi diagram only if Triangle's output is a true\n" +); + printf( +" Delaunay triangulation. The Voronoi output is usually meaningless (and\n"); + printf( +" may contain crossing edges and other pathology) if the output is a CDT or\n" +); + printf( +" CCDT, or if it has holes or concavities. If the triangulation is convex\n" +); + printf( +" and has no holes, this can be fixed by using the -L switch to ensure a\n"); + printf(" conforming Delaunay triangulation is constructed.\n\n"); + printf("Mesh Topology:\n\n"); + printf( +" You may wish to know which triangles are adjacent to a certain Delaunay\n"); + printf( +" edge in an .edge file, which Voronoi regions are adjacent to a certain\n"); + printf( +" Voronoi edge in a .v.edge file, or which Voronoi regions are adjacent to\n" +); + printf( +" each other. All of this information can be found by cross-referencing\n"); + printf( +" output files with the recollection that the Delaunay triangulation and\n"); + printf(" the Voronoi diagram are planar duals.\n\n"); + printf( +" Specifically, edge i of an .edge file is the dual of Voronoi edge i of\n"); + printf( +" the corresponding .v.edge file, and is rotated 90 degrees counterclock-\n"); + printf( +" wise from the Voronoi edge. Triangle j of an .ele file is the dual of\n"); + printf( +" vertex j of the corresponding .v.node file. Voronoi region k is the dual\n" +); + printf(" of vertex k of the corresponding .node file.\n\n"); + printf( +" Hence, to find the triangles adjacent to a Delaunay edge, look at the\n"); + printf( +" vertices of the corresponding Voronoi edge. If the endpoints of a\n"); + printf( +" Voronoi edge are Voronoi vertices 2 and 6 respectively, then triangles 2\n" +); + printf( +" and 6 adjoin the left and right sides of the corresponding Delaunay edge,\n" +); + printf( +" respectively. To find the Voronoi regions adjacent to a Voronoi edge,\n"); + printf( +" look at the endpoints of the corresponding Delaunay edge. If the\n"); + printf( +" endpoints of a Delaunay edge are input vertices 7 and 12, then Voronoi\n"); + printf( +" regions 7 and 12 adjoin the right and left sides of the corresponding\n"); + printf( +" Voronoi edge, respectively. To find which Voronoi regions are adjacent\n"); + printf(" to each other, just read the list of Delaunay edges.\n\n"); + printf( +" Triangle does not write a list of Voronoi regions, but one can be\n"); + printf( +" reconstructed straightforwardly. For instance, to find all the edges of\n" +); + printf( +" Voronoi region 1, search the output .edge file for every edge that has\n"); + printf( +" input vertex 1 as an endpoint. The corresponding dual edges in the\n"); + printf(" output .v.edge file form the boundary of Voronoi region 1.\n\n"); + printf("Quadratic Elements:\n\n"); + printf( +" Triangle generates meshes with subparametric quadratic elements if the\n"); + printf( +" -o2 switch is specified. Quadratic elements have six nodes per element,\n" +); + printf( +" rather than three. `Subparametric' means that the edges of the triangles\n" +); + printf( +" are always straight, so that subparametric quadratic elements are\n"); + printf( +" geometrically identical to linear elements, even though they can be used\n" +); + printf( +" with quadratic interpolating functions. The three extra nodes of an\n"); + printf( +" element fall at the midpoints of the three edges, with the fourth, fifth,\n" +); + printf( +" and sixth nodes appearing opposite the first, second, and third corners\n"); + printf(" respectively.\n\n"); + printf("Statistics:\n\n"); + printf( +" After generating a mesh, Triangle prints a count of the number of\n"); + printf( +" vertices, triangles, edges, exterior boundary edges (including hole\n"); + printf( +" boundaries), interior boundary edges, and segments in the output mesh.\n"); + printf( +" If you've forgotten the statistics for an existing mesh, run Triangle on\n" +); + printf( +" that mesh with the -rNEP switches to read the mesh and print the\n"); + printf( +" statistics without writing any files. Use -rpNEP if you've got a .poly\n"); + printf(" file for the mesh.\n\n"); + printf( +" The -V switch produces extended statistics, including a rough estimate\n"); + printf( +" of memory use, the number of calls to geometric predicates, and\n"); + printf(" histograms of triangle aspect ratios and angles in the mesh.\n\n"); + printf("Exact Arithmetic:\n\n"); + printf( +" Triangle uses adaptive exact arithmetic to perform what computational\n"); + printf( +" geometers call the `orientation' and `incircle' tests. If the floating-\n" +); + printf( +" point arithmetic of your machine conforms to the IEEE 754 standard (as\n"); + printf( +" most workstations do), and does not use extended precision internal\n"); + printf( +" floating-point registers, then your output is guaranteed to be an\n"); + printf( +" absolutely true Delaunay or constrained Delaunay triangulation, roundoff\n" +); + printf( +" error notwithstanding. The word `adaptive' implies that these arithmetic\n" +); + printf( +" routines compute the result only to the precision necessary to guarantee\n" +); + printf( +" correctness, so they are usually nearly as fast as their approximate\n"); + printf(" counterparts.\n\n"); + printf( +" Pentiums have extended precision floating-point registers. These must be\n" +); + printf( +" reconfigured so their precision is reduced to memory precision. Triangle\n" +); + printf( +" does this if it is compiled correctly. See the makefile for details.\n"); + printf("\n"); + printf( +" The exact tests can be disabled with the -X switch. On most inputs, this\n" +); + printf( +" switch reduces the computation time by about eight percent--it's not\n"); + printf( +" worth the risk. There are rare difficult inputs (having many collinear\n"); + printf( +" and cocircular vertices), however, for which the difference in speed\n"); + printf( +" could be a factor of two. Be forewarned that these are precisely the\n"); + printf( +" inputs most likely to cause errors if you use the -X switch. Hence, the\n" +); + printf(" -X switch is not recommended.\n\n"); + printf( +" Unfortunately, the exact tests don't solve every numerical problem.\n"); + printf( +" Exact arithmetic is not used to compute the positions of new vertices,\n"); + printf( +" because the bit complexity of vertex coordinates would grow without\n"); + printf( +" bound. Hence, segment intersections aren't computed exactly; in very\n"); + printf( +" unusual cases, roundoff error in computing an intersection point might\n"); + printf( +" actually lead to an inverted triangle and an invalid triangulation.\n"); + printf( +" (This is one reason to compute your own intersection points in your .poly\n" +); + printf( +" files.) Similarly, exact arithmetic is not used to compute the vertices\n" +); + printf(" of the Voronoi diagram.\n\n"); + printf( +" Another pair of problems not solved by the exact arithmetic routines is\n"); + printf( +" underflow and overflow. If Triangle is compiled for double precision\n"); + printf( +" arithmetic, I believe that Triangle's geometric predicates work correctly\n" +); + printf( +" if the exponent of every input coordinate falls in the range [-148, 201].\n" +); + printf( +" Underflow can silently prevent the orientation and incircle tests from\n"); + printf( +" being performed exactly, while overflow typically causes a floating\n"); + printf(" exception.\n\n"); + printf("Calling Triangle from Another Program:\n\n"); + printf(" Read the file triangle.h for details.\n\n"); + printf("Troubleshooting:\n\n"); + printf(" Please read this section before mailing me bugs.\n\n"); + printf(" `My output mesh has no triangles!'\n\n"); + printf( +" If you're using a PSLG, you've probably failed to specify a proper set\n" +); + printf( +" of bounding segments, or forgotten to use the -c switch. Or you may\n"); + printf( +" have placed a hole badly, thereby eating all your triangles. To test\n"); + printf(" these possibilities, try again with the -c and -O switches.\n"); + printf( +" Alternatively, all your input vertices may be collinear, in which case\n" +); + printf(" you can hardly expect to triangulate them.\n\n"); + printf(" `Triangle doesn't terminate, or just crashes.'\n\n"); + printf( +" Bad things can happen when triangles get so small that the distance\n"); + printf( +" between their vertices isn't much larger than the precision of your\n"); + printf( +" machine's arithmetic. If you've compiled Triangle for single-precision\n" +); + printf( +" arithmetic, you might do better by recompiling it for double-precision.\n" +); + printf( +" Then again, you might just have to settle for more lenient constraints\n" +); + printf( +" on the minimum angle and the maximum area than you had planned.\n"); + printf("\n"); + printf( +" You can minimize precision problems by ensuring that the origin lies\n"); + printf( +" inside your vertex set, or even inside the densest part of your\n"); + printf( +" mesh. If you're triangulating an object whose x coordinates all fall\n"); + printf( +" between 6247133 and 6247134, you're not leaving much floating-point\n"); + printf(" precision for Triangle to work with.\n\n"); + printf( +" Precision problems can occur covertly if the input PSLG contains two\n"); + printf( +" segments that meet (or intersect) at an extremely small angle, or if\n"); + printf( +" such an angle is introduced by the -c switch. If you don't realize\n"); + printf( +" that a tiny angle is being formed, you might never discover why\n"); + printf( +" Triangle is crashing. To check for this possibility, use the -S switch\n" +); + printf( +" (with an appropriate limit on the number of Steiner points, found by\n"); + printf( +" trial-and-error) to stop Triangle early, and view the output .poly file\n" +); + printf( +" with Show Me (described below). Look carefully for regions where dense\n" +); + printf( +" clusters of vertices are forming and for small angles between segments.\n" +); + printf( +" Zoom in closely, as such segments might look like a single segment from\n" +); + printf(" a distance.\n\n"); + printf( +" If some of the input values are too large, Triangle may suffer a\n"); + printf( +" floating exception due to overflow when attempting to perform an\n"); + printf( +" orientation or incircle test. (Read the section on exact arithmetic\n"); + printf( +" above.) Again, I recommend compiling Triangle for double (rather\n"); + printf(" than single) precision arithmetic.\n\n"); + printf( +" Unexpected problems can arise if you use quality meshing (-q, -a, or\n"); + printf( +" -u) with an input that is not segment-bounded--that is, if your input\n"); + printf( +" is a vertex set, or you're using the -c switch. If the convex hull of\n" +); + printf( +" your input vertices has collinear vertices on its boundary, an input\n"); + printf( +" vertex that you think lies on the convex hull might actually lie just\n"); + printf( +" inside the convex hull. If so, an extremely thin triangle is formed by\n" +); + printf( +" the vertex and the convex hull edge beside it. When Triangle tries to\n" +); + printf( +" refine the mesh to enforce angle and area constraints, extremely tiny\n"); + printf( +" triangles may be formed, or Triangle may fail because of insufficient\n"); + printf(" floating-point precision.\n\n"); + printf( +" `The numbering of the output vertices doesn't match the input vertices.'\n" +); + printf("\n"); + printf( +" You may have had duplicate input vertices, or you may have eaten some\n"); + printf( +" of your input vertices with a hole, or by placing them outside the area\n" +); + printf( +" enclosed by segments. In any case, you can solve the problem by not\n"); + printf(" using the -j switch.\n\n"); + printf( +" `Triangle executes without incident, but when I look at the resulting\n"); + printf( +" mesh, it has overlapping triangles or other geometric inconsistencies.'\n"); + printf("\n"); + printf( +" If you select the -X switch, Triangle occasionally makes mistakes due\n"); + printf( +" to floating-point roundoff error. Although these errors are rare,\n"); + printf( +" don't use the -X switch. If you still have problems, please report the\n" +); + printf(" bug.\n\n"); + printf( +" Strange things can happen if you've taken liberties with your PSLG. Do\n"); + printf( +" you have a vertex lying in the middle of a segment? Triangle sometimes\n"); + printf( +" copes poorly with that sort of thing. Do you want to lay out a collinear\n" +); + printf( +" row of evenly spaced, segment-connected vertices? Have you simply\n"); + printf( +" defined one long segment connecting the leftmost vertex to the rightmost\n" +); + printf( +" vertex, and a bunch of vertices lying along it? This method occasionally\n" +); + printf( +" works, especially with horizontal and vertical lines, but often it\n"); + printf( +" doesn't, and you'll have to connect each adjacent pair of vertices with a\n" +); + printf(" separate segment. If you don't like it, tough.\n\n"); + printf( +" Furthermore, if you have segments that intersect other than at their\n"); + printf( +" endpoints, try not to let the intersections fall extremely close to PSLG\n" +); + printf(" vertices or each other.\n\n"); + printf( +" If you have problems refining a triangulation not produced by Triangle:\n"); + printf( +" Are you sure the triangulation is geometrically valid? Is it formatted\n"); + printf( +" correctly for Triangle? Are the triangles all listed so the first three\n" +); + printf( +" vertices are their corners in counterclockwise order? Are all of the\n"); + printf( +" triangles constrained Delaunay? Triangle's Delaunay refinement algorithm\n" +); + printf(" assumes that it starts with a CDT.\n\n"); + printf("Show Me:\n\n"); + printf( +" Triangle comes with a separate program named `Show Me', whose primary\n"); + printf( +" purpose is to draw meshes on your screen or in PostScript. Its secondary\n" +); + printf( +" purpose is to check the validity of your input files, and do so more\n"); + printf( +" thoroughly than Triangle does. Unlike Triangle, Show Me requires that\n"); + printf(" you have the X Windows system.\n\n"); + printf("Triangle on the Web:\n\n"); + printf( +" To see an illustrated, updated version of these instructions, check out\n"); + printf("\n"); + printf(" http://www.cs.cmu.edu/~quake/triangle.html\n"); + printf("\n"); + printf("A Brief Plea:\n"); + printf("\n"); + printf( +" If you use Triangle, and especially if you use it to accomplish real\n"); + printf( +" work, I would like very much to hear from you. A short letter or email\n"); + printf( +" (to jrs@cs.berkeley.edu) describing how you use Triangle will mean a lot\n" +); + printf( +" to me. The more people I know are using this program, the more easily I\n" +); + printf( +" can justify spending time on improvements, which in turn will benefit\n"); + printf( +" you. Also, I can put you on a list to receive email whenever a new\n"); + printf(" version of Triangle is available.\n\n"); + printf( +" If you use a mesh generated by Triangle in a publication, please include\n" +); + printf(" an acknowledgment as well.\n\n"); + printf("Research credit:\n\n"); + printf( +" Of course, I can take credit for only a fraction of the ideas that made\n"); + printf( +" this mesh generator possible. Triangle owes its existence to the efforts\n" +); + printf( +" of many fine computational geometers and other researchers, including\n"); + printf( +" Marshall Bern, L. Paul Chew, Boris Delaunay, Rex A. Dwyer, David\n"); + printf( +" Eppstein, Steven Fortune, Leonidas J. Guibas, Donald E. Knuth, Charles L.\n" +); + printf( +" Lawson, Der-Tsai Lee, Ernst P. Mucke, Douglas M. Priest, Jim Ruppert,\n"); + printf( +" Isaac Saias, Bruce J. Schachter, Micha Sharir, Daniel D. Sleator, Jorge\n"); + printf( +" Stolfi, Robert E. Tarjan, Alper Ungor, Christopher J. Van Wyk, and Binhai\n" +); + printf(" Zhu. See the comments at the beginning of the source code for\n"); + printf(" references.\n\n"); + exit(0); +} + +#endif /* not TRILIBRARY */ + +/*****************************************************************************/ +/* */ +/* internalerror() Ask the user to send me the defective product. Exit. */ +/* */ +/*****************************************************************************/ + +void internalerror() +{ + printf(" Please report this bug to jrs@cs.berkeley.edu\n"); + printf(" Include the message above, your input data set, and the exact\n"); + printf(" command line you used to run Triangle.\n"); + exit(1); +} + +/*****************************************************************************/ +/* */ +/* parsecommandline() Read the command line, identify switches, and set */ +/* up options and file names. */ +/* */ +/*****************************************************************************/ + +#ifdef ANSI_DECLARATORS +void parsecommandline(int argc, char **argv, struct behavior *b) +#else /* not ANSI_DECLARATORS */ +void parsecommandline(argc, argv, b) +int argc; +char **argv; +struct behavior *b; +#endif /* not ANSI_DECLARATORS */ + +{ +#ifdef TRILIBRARY +#define STARTINDEX 0 +#else /* not TRILIBRARY */ +#define STARTINDEX 1 + int increment; + int meshnumber; +#endif /* not TRILIBRARY */ + int i, j, k; + char workstring[FILENAMESIZE]; + + b->poly = b->refine = b->quality = 0; + b->vararea = b->fixedarea = b->usertest = 0; + b->regionattrib = b->convex = b->weighted = b->jettison = 0; + b->firstnumber = 1; + b->edgesout = b->voronoi = b->neighbors = b->geomview = 0; + b->nobound = b->nopolywritten = b->nonodewritten = b->noelewritten = 0; + b->noiterationnum = 0; + b->noholes = b->noexact = 0; + b->incremental = b->sweepline = 0; + b->dwyer = 1; + b->splitseg = 0; + b->docheck = 0; + b->nobisect = 0; + b->nolenses = 0; + b->steiner = -1; + b->order = 1; + b->minangle = 0.0; + b->maxarea = -1.0; + b->quiet = b->verbose = 0; +#ifndef TRILIBRARY + b->innodefilename[0] = '\0'; +#endif /* not TRILIBRARY */ + + for (i = STARTINDEX; i < argc; i++) { +#ifndef TRILIBRARY + if (argv[i][0] == '-') { +#endif /* not TRILIBRARY */ + for (j = STARTINDEX; argv[i][j] != '\0'; j++) { + if (argv[i][j] == 'p') { + b->poly = 1; + } +#ifndef CDT_ONLY + if (argv[i][j] == 'r') { + b->refine = 1; + } + if (argv[i][j] == 'q') { + b->quality = 1; + if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) || + (argv[i][j + 1] == '.')) { + k = 0; + while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) || + (argv[i][j + 1] == '.')) { + j++; + workstring[k] = argv[i][j]; + k++; + } + workstring[k] = '\0'; + b->minangle = (REAL) strtod(workstring, (char **) NULL); + } else { + b->minangle = 20.0; + } + } + if (argv[i][j] == 'a') { + b->quality = 1; + if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) || + (argv[i][j + 1] == '.')) { + b->fixedarea = 1; + k = 0; + while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) || + (argv[i][j + 1] == '.')) { + j++; + workstring[k] = argv[i][j]; + k++; + } + workstring[k] = '\0'; + b->maxarea = (REAL) strtod(workstring, (char **) NULL); + if (b->maxarea <= 0.0) { + printf("Error: Maximum area must be greater than zero.\n"); + exit(1); + } + } else { + b->vararea = 1; + } + } + if (argv[i][j] == 'u') { + b->quality = 1; + b->usertest = 1; + } +#endif /* not CDT_ONLY */ + if (argv[i][j] == 'A') { + b->regionattrib = 1; + } + if (argv[i][j] == 'c') { + b->convex = 1; + } + if (argv[i][j] == 'w') { + b->weighted = 1; + } + if (argv[i][j] == 'W') { + b->weighted = 2; + } + if (argv[i][j] == 'j') { + b->jettison = 1; + } + if (argv[i][j] == 'z') { + b->firstnumber = 0; + } + if (argv[i][j] == 'e') { + b->edgesout = 1; + } + if (argv[i][j] == 'v') { + b->voronoi = 1; + } + if (argv[i][j] == 'n') { + b->neighbors = 1; + } + if (argv[i][j] == 'g') { + b->geomview = 1; + } + if (argv[i][j] == 'B') { + b->nobound = 1; + } + if (argv[i][j] == 'P') { + b->nopolywritten = 1; + } + if (argv[i][j] == 'N') { + b->nonodewritten = 1; + } + if (argv[i][j] == 'E') { + b->noelewritten = 1; + } +#ifndef TRILIBRARY + if (argv[i][j] == 'I') { + b->noiterationnum = 1; + } +#endif /* not TRILIBRARY */ + if (argv[i][j] == 'O') { + b->noholes = 1; + } + if (argv[i][j] == 'X') { + b->noexact = 1; + } + if (argv[i][j] == 'o') { + if (argv[i][j + 1] == '2') { + j++; + b->order = 2; + } + } +#ifndef CDT_ONLY + if (argv[i][j] == 'Y') { + b->nobisect++; + } + if (argv[i][j] == 'S') { + b->steiner = 0; + while ((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) { + j++; + b->steiner = b->steiner * 10 + (int) (argv[i][j] - '0'); + } + } +#endif /* not CDT_ONLY */ +#ifndef REDUCED + if (argv[i][j] == 'i') { + b->incremental = 1; + } + if (argv[i][j] == 'F') { + b->sweepline = 1; + } +#endif /* not REDUCED */ + if (argv[i][j] == 'l') { + b->dwyer = 0; + } +#ifndef REDUCED +#ifndef CDT_ONLY + if (argv[i][j] == 's') { + b->splitseg = 1; + } + if (argv[i][j] == 'L') { + b->nolenses = 1; + } +#endif /* not CDT_ONLY */ + if (argv[i][j] == 'C') { + b->docheck = 1; + } +#endif /* not REDUCED */ + if (argv[i][j] == 'Q') { + b->quiet = 1; + } + if (argv[i][j] == 'V') { + b->verbose++; + } +#ifndef TRILIBRARY + if ((argv[i][j] == 'h') || (argv[i][j] == 'H') || + (argv[i][j] == '?')) { + info(); + } +#endif /* not TRILIBRARY */ + } +#ifndef TRILIBRARY + } else { + strncpy(b->innodefilename, argv[i], FILENAMESIZE - 1); + b->innodefilename[FILENAMESIZE - 1] = '\0'; + } +#endif /* not TRILIBRARY */ + } +#ifndef TRILIBRARY + if (b->innodefilename[0] == '\0') { + syntax(); + } + if (!strcmp(&b->innodefilename[strlen(b->innodefilename) - 5], ".node")) { + b->innodefilename[strlen(b->innodefilename) - 5] = '\0'; + } + if (!strcmp(&b->innodefilename[strlen(b->innodefilename) - 5], ".poly")) { + b->innodefilename[strlen(b->innodefilename) - 5] = '\0'; + b->poly = 1; + } +#ifndef CDT_ONLY + if (!strcmp(&b->innodefilename[strlen(b->innodefilename) - 4], ".ele")) { + b->innodefilename[strlen(b->innodefilename) - 4] = '\0'; + b->refine = 1; + } + if (!strcmp(&b->innodefilename[strlen(b->innodefilename) - 5], ".area")) { + b->innodefilename[strlen(b->innodefilename) - 5] = '\0'; + b->refine = 1; + b->quality = 1; + b->vararea = 1; + } +#endif /* not CDT_ONLY */ +#endif /* not TRILIBRARY */ + b->usesegments = b->poly || b->refine || b->quality || b->convex; + b->goodangle = cos(b->minangle * PI / 180.0); + if (b->goodangle == 1.0) { + b->offconstant = 0.0; + } else { + b->offconstant = 0.475 * sqrt((1.0 + b->goodangle) / (1.0 - b->goodangle)); + } + b->goodangle *= b->goodangle; + if (b->refine && b->noiterationnum) { + printf( + "Error: You cannot use the -I switch when refining a triangulation.\n"); + exit(1); + } + /* Be careful not to allocate space for element area constraints that */ + /* will never be assigned any value (other than the default -1.0). */ + if (!b->refine && !b->poly) { + b->vararea = 0; + } + /* Be careful not to add an extra attribute to each element unless the */ + /* input supports it (PSLG in, but not refining a preexisting mesh). */ + if (b->refine || !b->poly) { + b->regionattrib = 0; + } + /* Regular/weighted triangulations are incompatible with PSLGs */ + /* and meshing. */ + if (b->weighted && (b->poly || b->quality)) { + b->weighted = 0; + if (!b->quiet) { + printf("Warning: weighted triangulations (-w, -W) are incompatible\n"); + printf(" with PSLGs (-p) and meshing (-q, -a, -u). Weights ignored.\n" + ); + } + } + if (b->jettison && b->nonodewritten && !b->quiet) { + printf("Warning: -j and -N switches are somewhat incompatible.\n"); + printf(" If any vertices are jettisoned, you will need the output\n"); + printf(" .node file to reconstruct the new node indices."); + } + +#ifndef TRILIBRARY + strcpy(b->inpolyfilename, b->innodefilename); + strcpy(b->inelefilename, b->innodefilename); + strcpy(b->areafilename, b->innodefilename); + increment = 0; + strcpy(workstring, b->innodefilename); + j = 1; + while (workstring[j] != '\0') { + if ((workstring[j] == '.') && (workstring[j + 1] != '\0')) { + increment = j + 1; + } + j++; + } + meshnumber = 0; + if (increment > 0) { + j = increment; + do { + if ((workstring[j] >= '0') && (workstring[j] <= '9')) { + meshnumber = meshnumber * 10 + (int) (workstring[j] - '0'); + } else { + increment = 0; + } + j++; + } while (workstring[j] != '\0'); + } + if (b->noiterationnum) { + strcpy(b->outnodefilename, b->innodefilename); + strcpy(b->outelefilename, b->innodefilename); + strcpy(b->edgefilename, b->innodefilename); + strcpy(b->vnodefilename, b->innodefilename); + strcpy(b->vedgefilename, b->innodefilename); + strcpy(b->neighborfilename, b->innodefilename); + strcpy(b->offfilename, b->innodefilename); + strcat(b->outnodefilename, ".node"); + strcat(b->outelefilename, ".ele"); + strcat(b->edgefilename, ".edge"); + strcat(b->vnodefilename, ".v.node"); + strcat(b->vedgefilename, ".v.edge"); + strcat(b->neighborfilename, ".neigh"); + strcat(b->offfilename, ".off"); + } else if (increment == 0) { + strcpy(b->outnodefilename, b->innodefilename); + strcpy(b->outpolyfilename, b->innodefilename); + strcpy(b->outelefilename, b->innodefilename); + strcpy(b->edgefilename, b->innodefilename); + strcpy(b->vnodefilename, b->innodefilename); + strcpy(b->vedgefilename, b->innodefilename); + strcpy(b->neighborfilename, b->innodefilename); + strcpy(b->offfilename, b->innodefilename); + strcat(b->outnodefilename, ".1.node"); + strcat(b->outpolyfilename, ".1.poly"); + strcat(b->outelefilename, ".1.ele"); + strcat(b->edgefilename, ".1.edge"); + strcat(b->vnodefilename, ".1.v.node"); + strcat(b->vedgefilename, ".1.v.edge"); + strcat(b->neighborfilename, ".1.neigh"); + strcat(b->offfilename, ".1.off"); + } else { + workstring[increment] = '%'; + workstring[increment + 1] = 'd'; + workstring[increment + 2] = '\0'; + sprintf(b->outnodefilename, workstring, meshnumber + 1); + strcpy(b->outpolyfilename, b->outnodefilename); + strcpy(b->outelefilename, b->outnodefilename); + strcpy(b->edgefilename, b->outnodefilename); + strcpy(b->vnodefilename, b->outnodefilename); + strcpy(b->vedgefilename, b->outnodefilename); + strcpy(b->neighborfilename, b->outnodefilename); + strcpy(b->offfilename, b->outnodefilename); + strcat(b->outnodefilename, ".node"); + strcat(b->outpolyfilename, ".poly"); + strcat(b->outelefilename, ".ele"); + strcat(b->edgefilename, ".edge"); + strcat(b->vnodefilename, ".v.node"); + strcat(b->vedgefilename, ".v.edge"); + strcat(b->neighborfilename, ".neigh"); + strcat(b->offfilename, ".off"); + } + strcat(b->innodefilename, ".node"); + strcat(b->inpolyfilename, ".poly"); + strcat(b->inelefilename, ".ele"); + strcat(b->areafilename, ".area"); +#endif /* not TRILIBRARY */ +} + +/** **/ +/** **/ +/********* User interaction routines begin here *********/ + +/********* Debugging routines begin here *********/ +/** **/ +/** **/ + +/*****************************************************************************/ +/* */ +/* printtriangle() Print out the details of an oriented triangle. */ +/* */ +/* I originally wrote this procedure to simplify debugging; it can be */ +/* called directly from the debugger, and presents information about an */ +/* oriented triangle in digestible form. It's also used when the */ +/* highest level of verbosity (`-VVV') is specified. */ +/* */ +/*****************************************************************************/ + +#ifdef ANSI_DECLARATORS +void printtriangle(struct mesh *m, struct behavior *b, struct otri *t) +#else /* not ANSI_DECLARATORS */ +void printtriangle(m, b, t) +struct mesh *m; +struct behavior *b; +struct otri *t; +#endif /* not ANSI_DECLARATORS */ + +{ + struct otri printtri; + struct osub printsh; + vertex printvertex; + + printf("triangle x%lx with orientation %d:\n", (unsigned long) t->tri, + t->orient); + decode(t->tri[0], printtri); + if (printtri.tri == m->dummytri) { + printf(" [0] = Outer space\n"); + } else { + printf(" [0] = x%lx %d\n", (unsigned long) printtri.tri, + printtri.orient); + } + decode(t->tri[1], printtri); + if (printtri.tri == m->dummytri) { + printf(" [1] = Outer space\n"); + } else { + printf(" [1] = x%lx %d\n", (unsigned long) printtri.tri, + printtri.orient); + } + decode(t->tri[2], printtri); + if (printtri.tri == m->dummytri) { + printf(" [2] = Outer space\n"); + } else { + printf(" [2] = x%lx %d\n", (unsigned long) printtri.tri, + printtri.orient); + } + + org(*t, printvertex); + if (printvertex == (vertex) NULL) + printf(" Origin[%d] = NULL\n", (t->orient + 1) % 3 + 3); + else + printf(" Origin[%d] = x%lx (%.12g, %.12g)\n", + (t->orient + 1) % 3 + 3, (unsigned long) printvertex, + printvertex[0], printvertex[1]); + dest(*t, printvertex); + if (printvertex == (vertex) NULL) + printf(" Dest [%d] = NULL\n", (t->orient + 2) % 3 + 3); + else + printf(" Dest [%d] = x%lx (%.12g, %.12g)\n", + (t->orient + 2) % 3 + 3, (unsigned long) printvertex, + printvertex[0], printvertex[1]); + apex(*t, printvertex); + if (printvertex == (vertex) NULL) + printf(" Apex [%d] = NULL\n", t->orient + 3); + else + printf(" Apex [%d] = x%lx (%.12g, %.12g)\n", + t->orient + 3, (unsigned long) printvertex, + printvertex[0], printvertex[1]); + + if (b->usesegments) { + sdecode(t->tri[6], printsh); + if (printsh.ss != m->dummysub) { + printf(" [6] = x%lx %d\n", (unsigned long) printsh.ss, + printsh.ssorient); + } + sdecode(t->tri[7], printsh); + if (printsh.ss != m->dummysub) { + printf(" [7] = x%lx %d\n", (unsigned long) printsh.ss, + printsh.ssorient); + } + sdecode(t->tri[8], printsh); + if (printsh.ss != m->dummysub) { + printf(" [8] = x%lx %d\n", (unsigned long) printsh.ss, + printsh.ssorient); + } + } + + if (b->vararea) { + printf(" Area constraint: %.4g\n", areabound(*t)); + } +} + +/*****************************************************************************/ +/* */ +/* printsubseg() Print out the details of an oriented subsegment. */ +/* */ +/* I originally wrote this procedure to simplify debugging; it can be */ +/* called directly from the debugger, and presents information about an */ +/* oriented subsegment in digestible form. It's also used when the highest */ +/* level of verbosity (`-VVV') is specified. */ +/* */ +/*****************************************************************************/ + +#ifdef ANSI_DECLARATORS +void printsubseg(struct mesh *m, struct behavior *b, struct osub *s) +#else /* not ANSI_DECLARATORS */ +void printsubseg(m, b, s) +struct mesh *m; +struct behavior *b; +struct osub *s; +#endif /* not ANSI_DECLARATORS */ + +{ + struct osub printsh; + struct otri printtri; + vertex printvertex; + + printf("subsegment x%lx with orientation %d and mark %d:\n", + (unsigned long) s->ss, s->ssorient, mark(*s)); + sdecode(s->ss[0], printsh); + if (printsh.ss == m->dummysub) { + printf(" [0] = No subsegment\n"); + } else { + printf(" [0] = x%lx %d\n", (unsigned long) printsh.ss, + printsh.ssorient); + } + sdecode(s->ss[1], printsh); + if (printsh.ss == m->dummysub) { + printf(" [1] = No subsegment\n"); + } else { + printf(" [1] = x%lx %d\n", (unsigned long) printsh.ss, + printsh.ssorient); + } + + sorg(*s, printvertex); + if (printvertex == (vertex) NULL) + printf(" Origin[%d] = NULL\n", 2 + s->ssorient); + else + printf(" Origin[%d] = x%lx (%.12g, %.12g)\n", + 2 + s->ssorient, (unsigned long) printvertex, + printvertex[0], printvertex[1]); + sdest(*s, printvertex); + if (printvertex == (vertex) NULL) + printf(" Dest [%d] = NULL\n", 3 - s->ssorient); + else + printf(" Dest [%d] = x%lx (%.12g, %.12g)\n", + 3 - s->ssorient, (unsigned long) printvertex, + printvertex[0], printvertex[1]); + + decode(s->ss[4], printtri); + if (printtri.tri == m->dummytri) { + printf(" [4] = Outer space\n"); + } else { + printf(" [4] = x%lx %d\n", (unsigned long) printtri.tri, + printtri.orient); + } + decode(s->ss[5], printtri); + if (printtri.tri == m->dummytri) { + printf(" [5] = Outer space\n"); + } else { + printf(" [5] = x%lx %d\n", (unsigned long) printtri.tri, + printtri.orient); + } +} + +/** **/ +/** **/ +/********* Debugging routines end here *********/ + +/********* Memory management routines begin here *********/ +/** **/ +/** **/ + +/*****************************************************************************/ +/* */ +/* poolrestart() Deallocate all items in a pool. */ +/* */ +/* The pool is returned to its starting state, except that no memory is */ +/* freed to the operating system. Rather, the previously allocated blocks */ +/* are ready to be reused. */ +/* */ +/*****************************************************************************/ + +#ifdef ANSI_DECLARATORS +void poolrestart(struct memorypool *pool) +#else /* not ANSI_DECLARATORS */ +void poolrestart(pool) +struct memorypool *pool; +#endif /* not ANSI_DECLARATORS */ + +{ + unsigned long alignptr; + + pool->items = 0; + pool->maxitems = 0; + + /* Set the currently active block. */ + pool->nowblock = pool->firstblock; + /* Find the first item in the pool. Increment by the size of (VOID *). */ + alignptr = (unsigned long) (pool->nowblock + 1); + /* Align the item on an `alignbytes'-byte boundary. */ + pool->nextitem = (VOID *) + (alignptr + (unsigned long) pool->alignbytes - + (alignptr % (unsigned long) pool->alignbytes)); + /* There are lots of unallocated items left in this block. */ + pool->unallocateditems = pool->itemsfirstblock; + /* The stack of deallocated items is empty. */ + pool->deaditemstack = (VOID *) NULL; +} + +/*****************************************************************************/ +/* */ +/* poolinit() Initialize a pool of memory for allocation of items. */ +/* */ +/* This routine initializes the machinery for allocating items. A `pool' */ +/* is created whose records have size at least `bytecount'. Items will be */ +/* allocated in `itemcount'-item blocks. Each item is assumed to be a */ +/* collection of words, and either pointers or floating-point values are */ +/* assumed to be the "primary" word type. (The "primary" word type is used */ +/* to determine alignment of items.) If `alignment' isn't zero, all items */ +/* will be `alignment'-byte aligned in memory. `alignment' must be either */ +/* a multiple or a factor of the primary word size; powers of two are safe. */ +/* `alignment' is normally used to create a few unused bits at the bottom */ +/* of each item's pointer, in which information may be stored. */ +/* */ +/* Don't change this routine unless you understand it. */ +/* */ +/*****************************************************************************/ + +#ifdef ANSI_DECLARATORS +void poolinit(struct memorypool *pool, int bytecount, int itemcount, + int firstitemcount, enum wordtype wtype, int alignment) +#else /* not ANSI_DECLARATORS */ +void poolinit(pool, bytecount, itemcount, firstitemcount, wtype, alignment) +struct memorypool *pool; +int bytecount; +int itemcount; +int firstitemcount; +enum wordtype wtype; +int alignment; +#endif /* not ANSI_DECLARATORS */ + +{ + int wordsize; + + /* Initialize values in the pool. */ + pool->itemwordtype = wtype; + wordsize = (pool->itemwordtype == POINTER) ? sizeof(VOID *) : sizeof(REAL); + /* Find the proper alignment, which must be at least as large as: */ + /* - The parameter `alignment'. */ + /* - The primary word type, to avoid unaligned accesses. */ + /* - sizeof(VOID *), so the stack of dead items can be maintained */ + /* without unaligned accesses. */ + if (alignment > wordsize) { + pool->alignbytes = alignment; + } else { + pool->alignbytes = wordsize; + } + if (sizeof(VOID *) > pool->alignbytes) { + pool->alignbytes = sizeof(VOID *); + } + pool->itemwords = ((bytecount + pool->alignbytes - 1) / pool->alignbytes) + * (pool->alignbytes / wordsize); + pool->itembytes = pool->itemwords * wordsize; + pool->itemsperblock = itemcount; + if (firstitemcount == 0) { + pool->itemsfirstblock = itemcount; + } else { + pool->itemsfirstblock = firstitemcount; + } + + /* Allocate a block of items. Space for `itemsfirstblock' items and one */ + /* pointer (to point to the next block) are allocated, as well as space */ + /* to ensure alignment of the items. */ + pool->firstblock = (VOID **) + trimalloc(pool->itemsfirstblock * pool->itembytes + (int) sizeof(VOID *) + + pool->alignbytes); + /* Set the next block pointer to NULL. */ + *(pool->firstblock) = (VOID *) NULL; + poolrestart(pool); +} + +/*****************************************************************************/ +/* */ +/* pooldeinit() Free to the operating system all memory taken by a pool. */ +/* */ +/*****************************************************************************/ + +#ifdef ANSI_DECLARATORS +void pooldeinit(struct memorypool *pool) +#else /* not ANSI_DECLARATORS */ +void pooldeinit(pool) +struct memorypool *pool; +#endif /* not ANSI_DECLARATORS */ + +{ + while (pool->firstblock != (VOID **) NULL) { + pool->nowblock = (VOID **) *(pool->firstblock); + trifree((VOID *) pool->firstblock); + pool->firstblock = pool->nowblock; + } +} + +/*****************************************************************************/ +/* */ +/* poolalloc() Allocate space for an item. */ +/* */ +/*****************************************************************************/ + +#ifdef ANSI_DECLARATORS +VOID *poolalloc(struct memorypool *pool) +#else /* not ANSI_DECLARATORS */ +VOID *poolalloc(pool) +struct memorypool *pool; +#endif /* not ANSI_DECLARATORS */ + +{ + VOID *newitem; + VOID **newblock; + unsigned long alignptr; + + /* First check the linked list of dead items. If the list is not */ + /* empty, allocate an item from the list rather than a fresh one. */ + if (pool->deaditemstack != (VOID *) NULL) { + newitem = pool->deaditemstack; /* Take first item in list. */ + pool->deaditemstack = * (VOID **) pool->deaditemstack; + } else { + /* Check if there are any free items left in the current block. */ + if (pool->unallocateditems == 0) { + /* Check if another block must be allocated. */ + if (*(pool->nowblock) == (VOID *) NULL) { + /* Allocate a new block of items, pointed to by the previous block. */ + newblock = (VOID **) trimalloc(pool->itemsperblock * pool->itembytes + + (int) sizeof(VOID *) + + pool->alignbytes); + *(pool->nowblock) = (VOID *) newblock; + /* The next block pointer is NULL. */ + *newblock = (VOID *) NULL; + } + + /* Move to the new block. */ + pool->nowblock = (VOID **) *(pool->nowblock); + /* Find the first item in the block. */ + /* Increment by the size of (VOID *). */ + alignptr = (unsigned long) (pool->nowblock + 1); + /* Align the item on an `alignbytes'-byte boundary. */ + pool->nextitem = (VOID *) + (alignptr + (unsigned long) pool->alignbytes - + (alignptr % (unsigned long) pool->alignbytes)); + /* There are lots of unallocated items left in this block. */ + pool->unallocateditems = pool->itemsperblock; + } + + /* Allocate a new item. */ + newitem = pool->nextitem; + /* Advance `nextitem' pointer to next free item in block. */ + if (pool->itemwordtype == POINTER) { + pool->nextitem = (VOID *) ((VOID **) pool->nextitem + pool->itemwords); + } else { + pool->nextitem = (VOID *) ((REAL *) pool->nextitem + pool->itemwords); + } + pool->unallocateditems--; + pool->maxitems++; + } + pool->items++; + return newitem; +} + +/*****************************************************************************/ +/* */ +/* pooldealloc() Deallocate space for an item. */ +/* */ +/* The deallocated space is stored in a queue for later reuse. */ +/* */ +/*****************************************************************************/ + +#ifdef ANSI_DECLARATORS +void pooldealloc(struct memorypool *pool, VOID *dyingitem) +#else /* not ANSI_DECLARATORS */ +void pooldealloc(pool, dyingitem) +struct memorypool *pool; +VOID *dyingitem; +#endif /* not ANSI_DECLARATORS */ + +{ + /* Push freshly killed item onto stack. */ + *((VOID **) dyingitem) = pool->deaditemstack; + pool->deaditemstack = dyingitem; + pool->items--; +} + +/*****************************************************************************/ +/* */ +/* traversalinit() Prepare to traverse the entire list of items. */ +/* */ +/* This routine is used in conjunction with traverse(). */ +/* */ +/*****************************************************************************/ + +#ifdef ANSI_DECLARATORS +void traversalinit(struct memorypool *pool) +#else /* not ANSI_DECLARATORS */ +void traversalinit(pool) +struct memorypool *pool; +#endif /* not ANSI_DECLARATORS */ + +{ + unsigned long alignptr; + + /* Begin the traversal in the first block. */ + pool->pathblock = pool->firstblock; + /* Find the first item in the block. Increment by the size of (VOID *). */ + alignptr = (unsigned long) (pool->pathblock + 1); + /* Align with item on an `alignbytes'-byte boundary. */ + pool->pathitem = (VOID *) + (alignptr + (unsigned long) pool->alignbytes - + (alignptr % (unsigned long) pool->alignbytes)); + /* Set the number of items left in the current block. */ + pool->pathitemsleft = pool->itemsfirstblock; +} + +/*****************************************************************************/ +/* */ +/* traverse() Find the next item in the list. */ +/* */ +/* This routine is used in conjunction with traversalinit(). Be forewarned */ +/* that this routine successively returns all items in the list, including */ +/* deallocated ones on the deaditemqueue. It's up to you to figure out */ +/* which ones are actually dead. Why? I don't want to allocate extra */ +/* space just to demarcate dead items. It can usually be done more */ +/* space-efficiently by a routine that knows something about the structure */ +/* of the item. */ +/* */ +/*****************************************************************************/ + +#ifdef ANSI_DECLARATORS +VOID *traverse(struct memorypool *pool) +#else /* not ANSI_DECLARATORS */ +VOID *traverse(pool) +struct memorypool *pool; +#endif /* not ANSI_DECLARATORS */ + +{ + VOID *newitem; + unsigned long alignptr; + + /* Stop upon exhausting the list of items. */ + if (pool->pathitem == pool->nextitem) { + return (VOID *) NULL; + } + + /* Check whether any untraversed items remain in the current block. */ + if (pool->pathitemsleft == 0) { + /* Find the next block. */ + pool->pathblock = (VOID **) *(pool->pathblock); + /* Find the first item in the block. Increment by the size of (VOID *). */ + alignptr = (unsigned long) (pool->pathblock + 1); + /* Align with item on an `alignbytes'-byte boundary. */ + pool->pathitem = (VOID *) + (alignptr + (unsigned long) pool->alignbytes - + (alignptr % (unsigned long) pool->alignbytes)); + /* Set the number of items left in the current block. */ + pool->pathitemsleft = pool->itemsperblock; + } + + newitem = pool->pathitem; + /* Find the next item in the block. */ + if (pool->itemwordtype == POINTER) { + pool->pathitem = (VOID *) ((VOID **) pool->pathitem + pool->itemwords); + } else { + pool->pathitem = (VOID *) ((REAL *) pool->pathitem + pool->itemwords); + } + pool->pathitemsleft--; + return newitem; +} + +/*****************************************************************************/ +/* */ +/* dummyinit() Initialize the triangle that fills "outer space" and the */ +/* omnipresent subsegment. */ +/* */ +/* The triangle that fills "outer space," called `dummytri', is pointed to */ +/* by every triangle and subsegment on a boundary (be it outer or inner) of */ +/* the triangulation. Also, `dummytri' points to one of the triangles on */ +/* the convex hull (until the holes and concavities are carved), making it */ +/* possible to find a starting triangle for point location. */ +/* */ +/* The omnipresent subsegment, `dummysub', is pointed to by every triangle */ +/* or subsegment that doesn't have a full complement of real subsegments */ +/* to point to. */ +/* */ +/* `dummytri' and `dummysub' are generally required to fulfill only a few */ +/* invariants: their vertices must remain NULL and `dummytri' must always */ +/* be bonded (at offset zero) to some triangle on the convex hull of the */ +/* mesh, via a boundary edge. Otherwise, the connections of `dummytri' and */ +/* `dummysub' may change willy-nilly. This makes it possible to avoid */ +/* writing a good deal of special-case code (in the edge flip, for example) */ +/* for dealing with the boundary of the mesh, places where no subsegment is */ +/* present, and so forth. Other entities are frequently bonded to */ +/* `dummytri' and `dummysub' as if they were real mesh entities, with no */ +/* harm done. */ +/* */ +/*****************************************************************************/ + +#ifdef ANSI_DECLARATORS +void dummyinit(struct mesh *m, struct behavior *b, int trianglewords, + int subsegwords) +#else /* not ANSI_DECLARATORS */ +void dummyinit(m, b, trianglewords, subsegwords) +struct mesh *m; +struct behavior *b; +int trianglewords; +int subsegwords; +#endif /* not ANSI_DECLARATORS */ + +{ + unsigned long alignptr; + + /* Set up `dummytri', the `triangle' that occupies "outer space." */ + m->dummytribase = (triangle *) + trimalloc(trianglewords * (int) sizeof(triangle) + + m->triangles.alignbytes); + /* Align `dummytri' on a `triangles.alignbytes'-byte boundary. */ + alignptr = (unsigned long) m->dummytribase; + m->dummytri = (triangle *) + (alignptr + (unsigned long) m->triangles.alignbytes - + (alignptr % (unsigned long) m->triangles.alignbytes)); + /* Initialize the three adjoining triangles to be "outer space." These */ + /* will eventually be changed by various bonding operations, but their */ + /* values don't really matter, as long as they can legally be */ + /* dereferenced. */ + m->dummytri[0] = (triangle) m->dummytri; + m->dummytri[1] = (triangle) m->dummytri; + m->dummytri[2] = (triangle) m->dummytri; + /* Three NULL vertices. */ + m->dummytri[3] = (triangle) NULL; + m->dummytri[4] = (triangle) NULL; + m->dummytri[5] = (triangle) NULL; + + if (b->usesegments) { + /* Set up `dummysub', the omnipresent subsegment pointed to by any */ + /* triangle side or subsegment end that isn't attached to a real */ + /* subsegment. */ + m->dummysubbase = (subseg *) trimalloc(subsegwords * (int) sizeof(subseg) + + m->subsegs.alignbytes); + /* Align `dummysub' on a `subsegs.alignbytes'-byte boundary. */ + alignptr = (unsigned long) m->dummysubbase; + m->dummysub = (subseg *) + (alignptr + (unsigned long) m->subsegs.alignbytes - + (alignptr % (unsigned long) m->subsegs.alignbytes)); + /* Initialize the two adjoining subsegments to be the omnipresent */ + /* subsegment. These will eventually be changed by various bonding */ + /* operations, but their values don't really matter, as long as they */ + /* can legally be dereferenced. */ + m->dummysub[0] = (subseg) m->dummysub; + m->dummysub[1] = (subseg) m->dummysub; + /* Two NULL vertices. */ + m->dummysub[2] = (subseg) NULL; + m->dummysub[3] = (subseg) NULL; + /* Initialize the two adjoining triangles to be "outer space." */ + m->dummysub[4] = (subseg) m->dummytri; + m->dummysub[5] = (subseg) m->dummytri; + /* Set the boundary marker to zero. */ + * (int *) (m->dummysub + 6) = 0; + + /* Initialize the three adjoining subsegments of `dummytri' to be */ + /* the omnipresent subsegment. */ + m->dummytri[6] = (triangle) m->dummysub; + m->dummytri[7] = (triangle) m->dummysub; + m->dummytri[8] = (triangle) m->dummysub; + } +} + +/*****************************************************************************/ +/* */ +/* initializevertexpool() Calculate the size of the vertex data structure */ +/* and initialize its memory pool. */ +/* */ +/* This routine also computes the `vertexmarkindex' and `vertex2triindex' */ +/* indices used to find values within each vertex. */ +/* */ +/*****************************************************************************/ + +#ifdef ANSI_DECLARATORS +void initializevertexpool(struct mesh *m, struct behavior *b) +#else /* not ANSI_DECLARATORS */ +void initializevertexpool(m, b) +struct mesh *m; +struct behavior *b; +#endif /* not ANSI_DECLARATORS */ + +{ + int vertexsize; + + /* The index within each vertex at which the boundary marker is found, */ + /* followed by the vertex type. Ensure the vertex marker is aligned to */ + /* a sizeof(int)-byte address. */ + m->vertexmarkindex = ((m->mesh_dim + m->nextras) * sizeof(REAL) + + sizeof(int) - 1) / + sizeof(int); + vertexsize = (m->vertexmarkindex + 2) * sizeof(int); + if (b->poly) { + /* The index within each vertex at which a triangle pointer is found. */ + /* Ensure the pointer is aligned to a sizeof(triangle)-byte address. */ + m->vertex2triindex = (vertexsize + sizeof(triangle) - 1) / + sizeof(triangle); + vertexsize = (m->vertex2triindex + 1) * sizeof(triangle); + } + + /* Initialize the pool of vertices. */ + poolinit(&m->vertices, vertexsize, VERTEXPERBLOCK, + m->invertices > VERTEXPERBLOCK ? m->invertices : VERTEXPERBLOCK, + (sizeof(REAL) >= sizeof(triangle)) ? FLOATINGPOINT : POINTER, 0); +} + +/*****************************************************************************/ +/* */ +/* initializetrisubpools() Calculate the sizes of the triangle and */ +/* subsegment data structures and initialize */ +/* their memory pools. */ +/* */ +/* This routine also computes the `highorderindex', `elemattribindex', and */ +/* `areaboundindex' indices used to find values within each triangle. */ +/* */ +/*****************************************************************************/ + +#ifdef ANSI_DECLARATORS +void initializetrisubpools(struct mesh *m, struct behavior *b) +#else /* not ANSI_DECLARATORS */ +void initializetrisubpools(m, b) +struct mesh *m; +struct behavior *b; +#endif /* not ANSI_DECLARATORS */ + +{ + int trisize; + + /* The index within each triangle at which the extra nodes (above three) */ + /* associated with high order elements are found. There are three */ + /* pointers to other triangles, three pointers to corners, and possibly */ + /* three pointers to subsegments before the extra nodes. */ + m->highorderindex = 6 + (b->usesegments * 3); + /* The number of bytes occupied by a triangle. */ + trisize = ((b->order + 1) * (b->order + 2) / 2 + (m->highorderindex - 3)) * + sizeof(triangle); + /* The index within each triangle at which its attributes are found, */ + /* where the index is measured in REALs. */ + m->elemattribindex = (trisize + sizeof(REAL) - 1) / sizeof(REAL); + /* The index within each triangle at which the maximum area constraint */ + /* is found, where the index is measured in REALs. Note that if the */ + /* `regionattrib' flag is set, an additional attribute will be added. */ + m->areaboundindex = m->elemattribindex + m->eextras + b->regionattrib; + /* If triangle attributes or an area bound are needed, increase the number */ + /* of bytes occupied by a triangle. */ + if (b->vararea) { + trisize = (m->areaboundindex + 1) * sizeof(REAL); + } else if (m->eextras + b->regionattrib > 0) { + trisize = m->areaboundindex * sizeof(REAL); + } + /* If a Voronoi diagram or triangle neighbor graph is requested, make */ + /* sure there's room to store an integer index in each triangle. This */ + /* integer index can occupy the same space as the subsegment pointers */ + /* or attributes or area constraint or extra nodes. */ + if ((b->voronoi || b->neighbors) && + (trisize < 6 * sizeof(triangle) + sizeof(int))) { + trisize = 6 * sizeof(triangle) + sizeof(int); + } + + /* Having determined the memory size of a triangle, initialize the pool. */ + poolinit(&m->triangles, trisize, TRIPERBLOCK, + (2 * m->invertices - 2) > TRIPERBLOCK ? (2 * m->invertices - 2) : + TRIPERBLOCK, POINTER, 4); + + if (b->usesegments) { + /* Initialize the pool of subsegments. Take into account all six */ + /* pointers and one boundary marker. */ + poolinit(&m->subsegs, 6 * sizeof(triangle) + sizeof(int), SUBSEGPERBLOCK, + SUBSEGPERBLOCK, POINTER, 4); + + /* Initialize the "outer space" triangle and omnipresent subsegment. */ + dummyinit(m, b, m->triangles.itemwords, m->subsegs.itemwords); + } else { + /* Initialize the "outer space" triangle. */ + dummyinit(m, b, m->triangles.itemwords, 0); + } +} + +/*****************************************************************************/ +/* */ +/* triangledealloc() Deallocate space for a triangle, marking it dead. */ +/* */ +/*****************************************************************************/ + +#ifdef ANSI_DECLARATORS +void triangledealloc(struct mesh *m, triangle *dyingtriangle) +#else /* not ANSI_DECLARATORS */ +void triangledealloc(m, dyingtriangle) +struct mesh *m; +triangle *dyingtriangle; +#endif /* not ANSI_DECLARATORS */ + +{ + /* Mark the triangle as dead. This makes it possible to detect dead */ + /* triangles when traversing the list of all triangles. */ + killtri(dyingtriangle); + pooldealloc(&m->triangles, (VOID *) dyingtriangle); +} + +/*****************************************************************************/ +/* */ +/* triangletraverse() Traverse the triangles, skipping dead ones. */ +/* */ +/*****************************************************************************/ + +#ifdef ANSI_DECLARATORS +triangle *triangletraverse(struct mesh *m) +#else /* not ANSI_DECLARATORS */ +triangle *triangletraverse(m) +struct mesh *m; +#endif /* not ANSI_DECLARATORS */ + +{ + triangle *newtriangle; + + do { + newtriangle = (triangle *) traverse(&m->triangles); + if (newtriangle == (triangle *) NULL) { + return (triangle *) NULL; + } + } while (deadtri(newtriangle)); /* Skip dead ones. */ + return newtriangle; +} + +/*****************************************************************************/ +/* */ +/* subsegdealloc() Deallocate space for a subsegment, marking it dead. */ +/* */ +/*****************************************************************************/ + +#ifdef ANSI_DECLARATORS +void subsegdealloc(struct mesh *m, subseg *dyingsubseg) +#else /* not ANSI_DECLARATORS */ +void subsegdealloc(m, dyingsubseg) +struct mesh *m; +subseg *dyingsubseg; +#endif /* not ANSI_DECLARATORS */ + +{ + /* Mark the subsegment as dead. This makes it possible to detect dead */ + /* subsegments when traversing the list of all subsegments. */ + killsubseg(dyingsubseg); + pooldealloc(&m->subsegs, (VOID *) dyingsubseg); +} + +/*****************************************************************************/ +/* */ +/* subsegtraverse() Traverse the subsegments, skipping dead ones. */ +/* */ +/*****************************************************************************/ + +#ifdef ANSI_DECLARATORS +subseg *subsegtraverse(struct mesh *m) +#else /* not ANSI_DECLARATORS */ +subseg *subsegtraverse(m) +struct mesh *m; +#endif /* not ANSI_DECLARATORS */ + +{ + subseg *newsubseg; + + do { + newsubseg = (subseg *) traverse(&m->subsegs); + if (newsubseg == (subseg *) NULL) { + return (subseg *) NULL; + } + } while (deadsubseg(newsubseg)); /* Skip dead ones. */ + return newsubseg; +} + +/*****************************************************************************/ +/* */ +/* vertexdealloc() Deallocate space for a vertex, marking it dead. */ +/* */ +/*****************************************************************************/ + +#ifdef ANSI_DECLARATORS +void vertexdealloc(struct mesh *m, vertex dyingvertex) +#else /* not ANSI_DECLARATORS */ +void vertexdealloc(m, dyingvertex) +struct mesh *m; +vertex dyingvertex; +#endif /* not ANSI_DECLARATORS */ + +{ + /* Mark the vertex as dead. This makes it possible to detect dead */ + /* vertices when traversing the list of all vertices. */ + setvertextype(dyingvertex, DEADVERTEX); + pooldealloc(&m->vertices, (VOID *) dyingvertex); +} + +/*****************************************************************************/ +/* */ +/* vertextraverse() Traverse the vertices, skipping dead ones. */ +/* */ +/*****************************************************************************/ + +#ifdef ANSI_DECLARATORS +vertex vertextraverse(struct mesh *m) +#else /* not ANSI_DECLARATORS */ +vertex vertextraverse(m) +struct mesh *m; +#endif /* not ANSI_DECLARATORS */ + +{ + vertex newvertex; + + do { + newvertex = (vertex) traverse(&m->vertices); + if (newvertex == (vertex) NULL) { + return (vertex) NULL; + } + } while (vertextype(newvertex) == DEADVERTEX); /* Skip dead ones. */ + return newvertex; +} + +/*****************************************************************************/ +/* */ +/* badsubsegdealloc() Deallocate space for a bad subsegment, marking it */ +/* dead. */ +/* */ +/*****************************************************************************/ + +#ifndef CDT_ONLY + +#ifdef ANSI_DECLARATORS +void badsubsegdealloc(struct mesh *m, struct badsubseg *dyingseg) +#else /* not ANSI_DECLARATORS */ +void badsubsegdealloc(m, dyingseg) +struct mesh *m; +struct badsubseg *dyingseg; +#endif /* not ANSI_DECLARATORS */ + +{ + /* Set subsegment's origin to NULL. This makes it possible to detect dead */ + /* subsegments when traversing the list of all encroached subsegments. */ + dyingseg->subsegorg = (vertex) NULL; + pooldealloc(&m->badsubsegs, (VOID *) dyingseg); +} + +#endif /* not CDT_ONLY */ + +/*****************************************************************************/ +/* */ +/* badsubsegtraverse() Traverse the bad subsegments, skipping dead ones. */ +/* */ +/*****************************************************************************/ + +#ifndef CDT_ONLY + +#ifdef ANSI_DECLARATORS +struct badsubseg *badsubsegtraverse(struct mesh *m) +#else /* not ANSI_DECLARATORS */ +struct badsubseg *badsubsegtraverse(m) +struct mesh *m; +#endif /* not ANSI_DECLARATORS */ + +{ + struct badsubseg *newseg; + + do { + newseg = (struct badsubseg *) traverse(&m->badsubsegs); + if (newseg == (struct badsubseg *) NULL) { + return (struct badsubseg *) NULL; + } + } while (newseg->subsegorg == (vertex) NULL); /* Skip dead ones. */ + return newseg; +} + +#endif /* not CDT_ONLY */ + +/*****************************************************************************/ +/* */ +/* getvertex() Get a specific vertex, by number, from the list. */ +/* */ +/* The first vertex is number 'firstnumber'. */ +/* */ +/* Note that this takes O(n) time (with a small constant, if VERTEXPERBLOCK */ +/* is large). I don't care to take the trouble to make it work in constant */ +/* time. */ +/* */ +/*****************************************************************************/ + +#ifdef ANSI_DECLARATORS +vertex getvertex(struct mesh *m, struct behavior *b, int number) +#else /* not ANSI_DECLARATORS */ +vertex getvertex(m, b, number) +struct mesh *m; +struct behavior *b; +int number; +#endif /* not ANSI_DECLARATORS */ + +{ + VOID **getblock; + vertex foundvertex; + unsigned long alignptr; + int current; + + getblock = m->vertices.firstblock; + current = b->firstnumber; + + /* Find the right block. */ + if (current + m->vertices.itemsfirstblock <= number) { + getblock = (VOID **) *getblock; + current += m->vertices.itemsfirstblock; + while (current + m->vertices.itemsperblock <= number) { + getblock = (VOID **) *getblock; + current += m->vertices.itemsperblock; + } + } + + /* Now find the right vertex. */ + alignptr = (unsigned long) (getblock + 1); + foundvertex = (vertex) (alignptr + (unsigned long) m->vertices.alignbytes - + (alignptr % (unsigned long) m->vertices.alignbytes)); + while (current < number) { + foundvertex += m->vertices.itemwords; + current++; + } + return foundvertex; +} + +/*****************************************************************************/ +/* */ +/* triangledeinit() Free all remaining allocated memory. */ +/* */ +/*****************************************************************************/ + +#ifdef ANSI_DECLARATORS +void triangledeinit(struct mesh *m, struct behavior *b) +#else /* not ANSI_DECLARATORS */ +void triangledeinit(m, b) +struct mesh *m; +struct behavior *b; +#endif /* not ANSI_DECLARATORS */ + +{ + pooldeinit(&m->triangles); + trifree((VOID *) m->dummytribase); + if (b->usesegments) { + pooldeinit(&m->subsegs); + trifree((VOID *) m->dummysubbase); + } + pooldeinit(&m->vertices); +#ifndef CDT_ONLY + if (b->quality) { + pooldeinit(&m->badsubsegs); + if ((b->minangle > 0.0) || b->vararea || b->fixedarea || b->usertest) { + pooldeinit(&m->badtriangles); + pooldeinit(&m->flipstackers); + } + } +#endif /* not CDT_ONLY */ +} + +/** **/ +/** **/ +/********* Memory management routines end here *********/ + +/********* Constructors begin here *********/ +/** **/ +/** **/ + +/*****************************************************************************/ +/* */ +/* maketriangle() Create a new triangle with orientation zero. */ +/* */ +/*****************************************************************************/ + +#ifdef ANSI_DECLARATORS +void maketriangle(struct mesh *m, struct behavior *b, struct otri *newotri) +#else /* not ANSI_DECLARATORS */ +void maketriangle(m, b, newotri) +struct mesh *m; +struct behavior *b; +struct otri *newotri; +#endif /* not ANSI_DECLARATORS */ + +{ + int i; + + newotri->tri = (triangle *) poolalloc(&m->triangles); + /* Initialize the three adjoining triangles to be "outer space". */ + newotri->tri[0] = (triangle) m->dummytri; + newotri->tri[1] = (triangle) m->dummytri; + newotri->tri[2] = (triangle) m->dummytri; + /* Three NULL vertices. */ + newotri->tri[3] = (triangle) NULL; + newotri->tri[4] = (triangle) NULL; + newotri->tri[5] = (triangle) NULL; + if (b->usesegments) { + /* Initialize the three adjoining subsegments to be the omnipresent */ + /* subsegment. */ + newotri->tri[6] = (triangle) m->dummysub; + newotri->tri[7] = (triangle) m->dummysub; + newotri->tri[8] = (triangle) m->dummysub; + } + for (i = 0; i < m->eextras; i++) { + setelemattribute(*newotri, i, 0.0); + } + if (b->vararea) { + setareabound(*newotri, -1.0); + } + + newotri->orient = 0; +} + +/*****************************************************************************/ +/* */ +/* makesubseg() Create a new subsegment with orientation zero. */ +/* */ +/*****************************************************************************/ + +#ifdef ANSI_DECLARATORS +void makesubseg(struct mesh *m, struct osub *newsubseg) +#else /* not ANSI_DECLARATORS */ +void makesubseg(m, newsubseg) +struct mesh *m; +struct osub *newsubseg; +#endif /* not ANSI_DECLARATORS */ + +{ + newsubseg->ss = (subseg *) poolalloc(&m->subsegs); + /* Initialize the two adjoining subsegments to be the omnipresent */ + /* subsegment. */ + newsubseg->ss[0] = (subseg) m->dummysub; + newsubseg->ss[1] = (subseg) m->dummysub; + /* Two NULL vertices. */ + newsubseg->ss[2] = (subseg) NULL; + newsubseg->ss[3] = (subseg) NULL; + /* Initialize the two adjoining triangles to be "outer space." */ + newsubseg->ss[4] = (subseg) m->dummytri; + newsubseg->ss[5] = (subseg) m->dummytri; + /* Set the boundary marker to zero. */ + setmark(*newsubseg, 0); + + newsubseg->ssorient = 0; +} + +/** **/ +/** **/ +/********* Constructors end here *********/ + +/********* Geometric primitives begin here *********/ +/** **/ +/** **/ + +/* The adaptive exact arithmetic geometric predicates implemented herein are */ +/* described in detail in my paper, "Adaptive Precision Floating-Point */ +/* Arithmetic and Fast Robust Geometric Predicates." See the header for a */ +/* full citation. */ + +/* Which of the following two methods of finding the absolute values is */ +/* fastest is compiler-dependent. A few compilers can inline and optimize */ +/* the fabs() call; but most will incur the overhead of a function call, */ +/* which is disastrously slow. A faster way on IEEE machines might be to */ +/* mask the appropriate bit, but that's difficult to do in C without */ +/* forcing the value to be stored to memory (rather than be kept in the */ +/* register to which the optimizer assigned it). */ + +#define Absolute(a) ((a) >= 0.0 ? (a) : -(a)) +/* #define Absolute(a) fabs(a) */ + +/* Many of the operations are broken up into two pieces, a main part that */ +/* performs an approximate operation, and a "tail" that computes the */ +/* roundoff error of that operation. */ +/* */ +/* The operations Fast_Two_Sum(), Fast_Two_Diff(), Two_Sum(), Two_Diff(), */ +/* Split(), and Two_Product() are all implemented as described in the */ +/* reference. Each of these macros requires certain variables to be */ +/* defined in the calling routine. The variables `bvirt', `c', `abig', */ +/* `_i', `_j', `_k', `_l', `_m', and `_n' are declared `INEXACT' because */ +/* they store the result of an operation that may incur roundoff error. */ +/* The input parameter `x' (or the highest numbered `x_' parameter) must */ +/* also be declared `INEXACT'. */ + +#define Fast_Two_Sum_Tail(a, b, x, y) \ + bvirt = x - a; \ + y = b - bvirt + +#define Fast_Two_Sum(a, b, x, y) \ + x = (REAL) (a + b); \ + Fast_Two_Sum_Tail(a, b, x, y) + +#define Two_Sum_Tail(a, b, x, y) \ + bvirt = (REAL) (x - a); \ + avirt = x - bvirt; \ + bround = b - bvirt; \ + around = a - avirt; \ + y = around + bround + +#define Two_Sum(a, b, x, y) \ + x = (REAL) (a + b); \ + Two_Sum_Tail(a, b, x, y) + +#define Two_Diff_Tail(a, b, x, y) \ + bvirt = (REAL) (a - x); \ + avirt = x + bvirt; \ + bround = bvirt - b; \ + around = a - avirt; \ + y = around + bround + +#define Two_Diff(a, b, x, y) \ + x = (REAL) (a - b); \ + Two_Diff_Tail(a, b, x, y) + +#define Split(a, ahi, alo) \ + c = (REAL) (splitter * a); \ + abig = (REAL) (c - a); \ + ahi = c - abig; \ + alo = a - ahi + +#define Two_Product_Tail(a, b, x, y) \ + Split(a, ahi, alo); \ + Split(b, bhi, blo); \ + err1 = x - (ahi * bhi); \ + err2 = err1 - (alo * bhi); \ + err3 = err2 - (ahi * blo); \ + y = (alo * blo) - err3 + +#define Two_Product(a, b, x, y) \ + x = (REAL) (a * b); \ + Two_Product_Tail(a, b, x, y) + +/* Two_Product_Presplit() is Two_Product() where one of the inputs has */ +/* already been split. Avoids redundant splitting. */ + +#define Two_Product_Presplit(a, b, bhi, blo, x, y) \ + x = (REAL) (a * b); \ + Split(a, ahi, alo); \ + err1 = x - (ahi * bhi); \ + err2 = err1 - (alo * bhi); \ + err3 = err2 - (ahi * blo); \ + y = (alo * blo) - err3 + +/* Square() can be done more quickly than Two_Product(). */ + +#define Square_Tail(a, x, y) \ + Split(a, ahi, alo); \ + err1 = x - (ahi * ahi); \ + err3 = err1 - ((ahi + ahi) * alo); \ + y = (alo * alo) - err3 + +#define Square(a, x, y) \ + x = (REAL) (a * a); \ + Square_Tail(a, x, y) + +/* Macros for summing expansions of various fixed lengths. These are all */ +/* unrolled versions of Expansion_Sum(). */ + +#define Two_One_Sum(a1, a0, b, x2, x1, x0) \ + Two_Sum(a0, b , _i, x0); \ + Two_Sum(a1, _i, x2, x1) + +#define Two_One_Diff(a1, a0, b, x2, x1, x0) \ + Two_Diff(a0, b , _i, x0); \ + Two_Sum( a1, _i, x2, x1) + +#define Two_Two_Sum(a1, a0, b1, b0, x3, x2, x1, x0) \ + Two_One_Sum(a1, a0, b0, _j, _0, x0); \ + Two_One_Sum(_j, _0, b1, x3, x2, x1) + +#define Two_Two_Diff(a1, a0, b1, b0, x3, x2, x1, x0) \ + Two_One_Diff(a1, a0, b0, _j, _0, x0); \ + Two_One_Diff(_j, _0, b1, x3, x2, x1) + +/* Macro for multiplying a two-component expansion by a single component. */ + +#define Two_One_Product(a1, a0, b, x3, x2, x1, x0) \ + Split(b, bhi, blo); \ + Two_Product_Presplit(a0, b, bhi, blo, _i, x0); \ + Two_Product_Presplit(a1, b, bhi, blo, _j, _0); \ + Two_Sum(_i, _0, _k, x1); \ + Fast_Two_Sum(_j, _k, x3, x2) + +/*****************************************************************************/ +/* */ +/* exactinit() Initialize the variables used for exact arithmetic. */ +/* */ +/* `epsilon' is the largest power of two such that 1.0 + epsilon = 1.0 in */ +/* floating-point arithmetic. `epsilon' bounds the relative roundoff */ +/* error. It is used for floating-point error analysis. */ +/* */ +/* `splitter' is used to split floating-point numbers into two half- */ +/* length significands for exact multiplication. */ +/* */ +/* I imagine that a highly optimizing compiler might be too smart for its */ +/* own good, and somehow cause this routine to fail, if it pretends that */ +/* floating-point arithmetic is too much like real arithmetic. */ +/* */ +/* Don't change this routine unless you fully understand it. */ +/* */ +/*****************************************************************************/ + +void exactinit() +{ + REAL half; + REAL check, lastcheck; + int every_other; +#ifdef LINUX + int cword; +#endif /* LINUX */ + +#ifdef CPU86 +#ifdef SINGLE + _control87(_PC_24, _MCW_PC); /* Set FPU control word for single precision. */ +#else /* not SINGLE */ + _control87(_PC_53, _MCW_PC); /* Set FPU control word for double precision. */ +#endif /* not SINGLE */ +#endif /* CPU86 */ +#ifdef LINUX +#ifdef SINGLE + /* cword = 4223; */ + cword = 4210; /* set FPU control word for single precision */ +#else /* not SINGLE */ + /* cword = 4735; */ + cword = 4722; /* set FPU control word for double precision */ +#endif /* not SINGLE */ + _FPU_SETCW(cword); +#endif /* LINUX */ + + every_other = 1; + half = 0.5; + epsilon = 1.0; + splitter = 1.0; + check = 1.0; + /* Repeatedly divide `epsilon' by two until it is too small to add to */ + /* one without causing roundoff. (Also check if the sum is equal to */ + /* the previous sum, for machines that round up instead of using exact */ + /* rounding. Not that these routines will work on such machines.) */ + do { + lastcheck = check; + epsilon *= half; + if (every_other) { + splitter *= 2.0; + } + every_other = !every_other; + check = 1.0 + epsilon; + } while ((check != 1.0) && (check != lastcheck)); + splitter += 1.0; + /* Error bounds for orientation and incircle tests. */ + resulterrbound = (3.0 + 8.0 * epsilon) * epsilon; + ccwerrboundA = (3.0 + 16.0 * epsilon) * epsilon; + ccwerrboundB = (2.0 + 12.0 * epsilon) * epsilon; + ccwerrboundC = (9.0 + 64.0 * epsilon) * epsilon * epsilon; + iccerrboundA = (10.0 + 96.0 * epsilon) * epsilon; + iccerrboundB = (4.0 + 48.0 * epsilon) * epsilon; + iccerrboundC = (44.0 + 576.0 * epsilon) * epsilon * epsilon; + o3derrboundA = (7.0 + 56.0 * epsilon) * epsilon; + o3derrboundB = (3.0 + 28.0 * epsilon) * epsilon; + o3derrboundC = (26.0 + 288.0 * epsilon) * epsilon * epsilon; +} + +/*****************************************************************************/ +/* */ +/* fast_expansion_sum_zeroelim() Sum two expansions, eliminating zero */ +/* components from the output expansion. */ +/* */ +/* Sets h = e + f. See my Robust Predicates paper for details. */ +/* */ +/* If round-to-even is used (as with IEEE 754), maintains the strongly */ +/* nonoverlapping property. (That is, if e is strongly nonoverlapping, h */ +/* will be also.) Does NOT maintain the nonoverlapping or nonadjacent */ +/* properties. */ +/* */ +/*****************************************************************************/ + +#ifdef ANSI_DECLARATORS +int fast_expansion_sum_zeroelim(int elen, REAL *e, int flen, REAL *f, REAL *h) +#else /* not ANSI_DECLARATORS */ +int fast_expansion_sum_zeroelim(elen, e, flen, f, h) /* h cannot be e or f. */ +int elen; +REAL *e; +int flen; +REAL *f; +REAL *h; +#endif /* not ANSI_DECLARATORS */ + +{ + REAL Q; + INEXACT REAL Qnew; + INEXACT REAL hh; + INEXACT REAL bvirt; + REAL avirt, bround, around; + int eindex, findex, hindex; + REAL enow, fnow; + + enow = e[0]; + fnow = f[0]; + eindex = findex = 0; + if ((fnow > enow) == (fnow > -enow)) { + Q = enow; + enow = e[++eindex]; + } else { + Q = fnow; + fnow = f[++findex]; + } + hindex = 0; + if ((eindex < elen) && (findex < flen)) { + if ((fnow > enow) == (fnow > -enow)) { + Fast_Two_Sum(enow, Q, Qnew, hh); + enow = e[++eindex]; + } else { + Fast_Two_Sum(fnow, Q, Qnew, hh); + fnow = f[++findex]; + } + Q = Qnew; + if (hh != 0.0) { + h[hindex++] = hh; + } + while ((eindex < elen) && (findex < flen)) { + if ((fnow > enow) == (fnow > -enow)) { + Two_Sum(Q, enow, Qnew, hh); + enow = e[++eindex]; + } else { + Two_Sum(Q, fnow, Qnew, hh); + fnow = f[++findex]; + } + Q = Qnew; + if (hh != 0.0) { + h[hindex++] = hh; + } + } + } + while (eindex < elen) { + Two_Sum(Q, enow, Qnew, hh); + enow = e[++eindex]; + Q = Qnew; + if (hh != 0.0) { + h[hindex++] = hh; + } + } + while (findex < flen) { + Two_Sum(Q, fnow, Qnew, hh); + fnow = f[++findex]; + Q = Qnew; + if (hh != 0.0) { + h[hindex++] = hh; + } + } + if ((Q != 0.0) || (hindex == 0)) { + h[hindex++] = Q; + } + return hindex; +} + +/*****************************************************************************/ +/* */ +/* scale_expansion_zeroelim() Multiply an expansion by a scalar, */ +/* eliminating zero components from the */ +/* output expansion. */ +/* */ +/* Sets h = be. See my Robust Predicates paper for details. */ +/* */ +/* Maintains the nonoverlapping property. If round-to-even is used (as */ +/* with IEEE 754), maintains the strongly nonoverlapping and nonadjacent */ +/* properties as well. (That is, if e has one of these properties, so */ +/* will h.) */ +/* */ +/*****************************************************************************/ + +#ifdef ANSI_DECLARATORS +int scale_expansion_zeroelim(int elen, REAL *e, REAL b, REAL *h) +#else /* not ANSI_DECLARATORS */ +int scale_expansion_zeroelim(elen, e, b, h) /* e and h cannot be the same. */ +int elen; +REAL *e; +REAL b; +REAL *h; +#endif /* not ANSI_DECLARATORS */ + +{ + INEXACT REAL Q, sum; + REAL hh; + INEXACT REAL product1; + REAL product0; + int eindex, hindex; + REAL enow; + INEXACT REAL bvirt; + REAL avirt, bround, around; + INEXACT REAL c; + INEXACT REAL abig; + REAL ahi, alo, bhi, blo; + REAL err1, err2, err3; + + Split(b, bhi, blo); + Two_Product_Presplit(e[0], b, bhi, blo, Q, hh); + hindex = 0; + if (hh != 0) { + h[hindex++] = hh; + } + for (eindex = 1; eindex < elen; eindex++) { + enow = e[eindex]; + Two_Product_Presplit(enow, b, bhi, blo, product1, product0); + Two_Sum(Q, product0, sum, hh); + if (hh != 0) { + h[hindex++] = hh; + } + Fast_Two_Sum(product1, sum, Q, hh); + if (hh != 0) { + h[hindex++] = hh; + } + } + if ((Q != 0.0) || (hindex == 0)) { + h[hindex++] = Q; + } + return hindex; +} + +/*****************************************************************************/ +/* */ +/* estimate() Produce a one-word estimate of an expansion's value. */ +/* */ +/* See my Robust Predicates paper for details. */ +/* */ +/*****************************************************************************/ + +#ifdef ANSI_DECLARATORS +REAL estimate(int elen, REAL *e) +#else /* not ANSI_DECLARATORS */ +REAL estimate(elen, e) +int elen; +REAL *e; +#endif /* not ANSI_DECLARATORS */ + +{ + REAL Q; + int eindex; + + Q = e[0]; + for (eindex = 1; eindex < elen; eindex++) { + Q += e[eindex]; + } + return Q; +} + +/*****************************************************************************/ +/* */ +/* counterclockwise() Return a positive value if the points pa, pb, and */ +/* pc occur in counterclockwise order; a negative */ +/* value if they occur in clockwise order; and zero */ +/* if they are collinear. The result is also a rough */ +/* approximation of twice the signed area of the */ +/* triangle defined by the three points. */ +/* */ +/* Uses exact arithmetic if necessary to ensure a correct answer. The */ +/* result returned is the determinant of a matrix. This determinant is */ +/* computed adaptively, in the sense that exact arithmetic is used only to */ +/* the degree it is needed to ensure that the returned value has the */ +/* correct sign. Hence, this function is usually quite fast, but will run */ +/* more slowly when the input points are collinear or nearly so. */ +/* */ +/* See my Robust Predicates paper for details. */ +/* */ +/*****************************************************************************/ + +#ifdef ANSI_DECLARATORS +REAL counterclockwiseadapt(vertex pa, vertex pb, vertex pc, REAL detsum) +#else /* not ANSI_DECLARATORS */ +REAL counterclockwiseadapt(pa, pb, pc, detsum) +vertex pa; +vertex pb; +vertex pc; +REAL detsum; +#endif /* not ANSI_DECLARATORS */ + +{ + INEXACT REAL acx, acy, bcx, bcy; + REAL acxtail, acytail, bcxtail, bcytail; + INEXACT REAL detleft, detright; + REAL detlefttail, detrighttail; + REAL det, errbound; + REAL B[4], C1[8], C2[12], D[16]; + INEXACT REAL B3; + int C1length, C2length, Dlength; + REAL u[4]; + INEXACT REAL u3; + INEXACT REAL s1, t1; + REAL s0, t0; + + INEXACT REAL bvirt; + REAL avirt, bround, around; + INEXACT REAL c; + INEXACT REAL abig; + REAL ahi, alo, bhi, blo; + REAL err1, err2, err3; + INEXACT REAL _i, _j; + REAL _0; + + acx = (REAL) (pa[0] - pc[0]); + bcx = (REAL) (pb[0] - pc[0]); + acy = (REAL) (pa[1] - pc[1]); + bcy = (REAL) (pb[1] - pc[1]); + + Two_Product(acx, bcy, detleft, detlefttail); + Two_Product(acy, bcx, detright, detrighttail); + + Two_Two_Diff(detleft, detlefttail, detright, detrighttail, + B3, B[2], B[1], B[0]); + B[3] = B3; + + det = estimate(4, B); + errbound = ccwerrboundB * detsum; + if ((det >= errbound) || (-det >= errbound)) { + return det; + } + + Two_Diff_Tail(pa[0], pc[0], acx, acxtail); + Two_Diff_Tail(pb[0], pc[0], bcx, bcxtail); + Two_Diff_Tail(pa[1], pc[1], acy, acytail); + Two_Diff_Tail(pb[1], pc[1], bcy, bcytail); + + if ((acxtail == 0.0) && (acytail == 0.0) + && (bcxtail == 0.0) && (bcytail == 0.0)) { + return det; + } + + errbound = ccwerrboundC * detsum + resulterrbound * Absolute(det); + det += (acx * bcytail + bcy * acxtail) + - (acy * bcxtail + bcx * acytail); + if ((det >= errbound) || (-det >= errbound)) { + return det; + } + + Two_Product(acxtail, bcy, s1, s0); + Two_Product(acytail, bcx, t1, t0); + Two_Two_Diff(s1, s0, t1, t0, u3, u[2], u[1], u[0]); + u[3] = u3; + C1length = fast_expansion_sum_zeroelim(4, B, 4, u, C1); + + Two_Product(acx, bcytail, s1, s0); + Two_Product(acy, bcxtail, t1, t0); + Two_Two_Diff(s1, s0, t1, t0, u3, u[2], u[1], u[0]); + u[3] = u3; + C2length = fast_expansion_sum_zeroelim(C1length, C1, 4, u, C2); + + Two_Product(acxtail, bcytail, s1, s0); + Two_Product(acytail, bcxtail, t1, t0); + Two_Two_Diff(s1, s0, t1, t0, u3, u[2], u[1], u[0]); + u[3] = u3; + Dlength = fast_expansion_sum_zeroelim(C2length, C2, 4, u, D); + + return(D[Dlength - 1]); +} + +#ifdef ANSI_DECLARATORS +REAL counterclockwise(struct mesh *m, struct behavior *b, + vertex pa, vertex pb, vertex pc) +#else /* not ANSI_DECLARATORS */ +REAL counterclockwise(m, b, pa, pb, pc) +struct mesh *m; +struct behavior *b; +vertex pa; +vertex pb; +vertex pc; +#endif /* not ANSI_DECLARATORS */ + +{ + REAL detleft, detright, det; + REAL detsum, errbound; + + m->counterclockcount++; + + detleft = (pa[0] - pc[0]) * (pb[1] - pc[1]); + detright = (pa[1] - pc[1]) * (pb[0] - pc[0]); + det = detleft - detright; + + if (b->noexact) { + return det; + } + + if (detleft > 0.0) { + if (detright <= 0.0) { + return det; + } else { + detsum = detleft + detright; + } + } else if (detleft < 0.0) { + if (detright >= 0.0) { + return det; + } else { + detsum = -detleft - detright; + } + } else { + return det; + } + + errbound = ccwerrboundA * detsum; + if ((det >= errbound) || (-det >= errbound)) { + return det; + } + + return counterclockwiseadapt(pa, pb, pc, detsum); +} + +/*****************************************************************************/ +/* */ +/* incircle() Return a positive value if the point pd lies inside the */ +/* circle passing through pa, pb, and pc; a negative value if */ +/* it lies outside; and zero if the four points are cocircular.*/ +/* The points pa, pb, and pc must be in counterclockwise */ +/* order, or the sign of the result will be reversed. */ +/* */ +/* Uses exact arithmetic if necessary to ensure a correct answer. The */ +/* result returned is the determinant of a matrix. This determinant is */ +/* computed adaptively, in the sense that exact arithmetic is used only to */ +/* the degree it is needed to ensure that the returned value has the */ +/* correct sign. Hence, this function is usually quite fast, but will run */ +/* more slowly when the input points are cocircular or nearly so. */ +/* */ +/* See my Robust Predicates paper for details. */ +/* */ +/*****************************************************************************/ + +#ifdef ANSI_DECLARATORS +REAL incircleadapt(vertex pa, vertex pb, vertex pc, vertex pd, REAL permanent) +#else /* not ANSI_DECLARATORS */ +REAL incircleadapt(pa, pb, pc, pd, permanent) +vertex pa; +vertex pb; +vertex pc; +vertex pd; +REAL permanent; +#endif /* not ANSI_DECLARATORS */ + +{ + INEXACT REAL adx, bdx, cdx, ady, bdy, cdy; + REAL det, errbound; + + INEXACT REAL bdxcdy1, cdxbdy1, cdxady1, adxcdy1, adxbdy1, bdxady1; + REAL bdxcdy0, cdxbdy0, cdxady0, adxcdy0, adxbdy0, bdxady0; + REAL bc[4], ca[4], ab[4]; + INEXACT REAL bc3, ca3, ab3; + REAL axbc[8], axxbc[16], aybc[8], ayybc[16], adet[32]; + int axbclen, axxbclen, aybclen, ayybclen, alen; + REAL bxca[8], bxxca[16], byca[8], byyca[16], bdet[32]; + int bxcalen, bxxcalen, bycalen, byycalen, blen; + REAL cxab[8], cxxab[16], cyab[8], cyyab[16], cdet[32]; + int cxablen, cxxablen, cyablen, cyyablen, clen; + REAL abdet[64]; + int ablen; + REAL fin1[1152], fin2[1152]; + REAL *finnow, *finother, *finswap; + int finlength; + + REAL adxtail, bdxtail, cdxtail, adytail, bdytail, cdytail; + INEXACT REAL adxadx1, adyady1, bdxbdx1, bdybdy1, cdxcdx1, cdycdy1; + REAL adxadx0, adyady0, bdxbdx0, bdybdy0, cdxcdx0, cdycdy0; + REAL aa[4], bb[4], cc[4]; + INEXACT REAL aa3, bb3, cc3; + INEXACT REAL ti1, tj1; + REAL ti0, tj0; + REAL u[4], v[4]; + INEXACT REAL u3, v3; + REAL temp8[8], temp16a[16], temp16b[16], temp16c[16]; + REAL temp32a[32], temp32b[32], temp48[48], temp64[64]; + int temp8len, temp16alen, temp16blen, temp16clen; + int temp32alen, temp32blen, temp48len, temp64len; + REAL axtbb[8], axtcc[8], aytbb[8], aytcc[8]; + int axtbblen, axtcclen, aytbblen, aytcclen; + REAL bxtaa[8], bxtcc[8], bytaa[8], bytcc[8]; + int bxtaalen, bxtcclen, bytaalen, bytcclen; + REAL cxtaa[8], cxtbb[8], cytaa[8], cytbb[8]; + int cxtaalen, cxtbblen, cytaalen, cytbblen; + REAL axtbc[8], aytbc[8], bxtca[8], bytca[8], cxtab[8], cytab[8]; + int axtbclen, aytbclen, bxtcalen, bytcalen, cxtablen, cytablen; + REAL axtbct[16], aytbct[16], bxtcat[16], bytcat[16], cxtabt[16], cytabt[16]; + int axtbctlen, aytbctlen, bxtcatlen, bytcatlen, cxtabtlen, cytabtlen; + REAL axtbctt[8], aytbctt[8], bxtcatt[8]; + REAL bytcatt[8], cxtabtt[8], cytabtt[8]; + int axtbcttlen, aytbcttlen, bxtcattlen, bytcattlen, cxtabttlen, cytabttlen; + REAL abt[8], bct[8], cat[8]; + int abtlen, bctlen, catlen; + REAL abtt[4], bctt[4], catt[4]; + int abttlen, bcttlen, cattlen; + INEXACT REAL abtt3, bctt3, catt3; + REAL negate; + + INEXACT REAL bvirt; + REAL avirt, bround, around; + INEXACT REAL c; + INEXACT REAL abig; + REAL ahi, alo, bhi, blo; + REAL err1, err2, err3; + INEXACT REAL _i, _j; + REAL _0; + + adx = (REAL) (pa[0] - pd[0]); + bdx = (REAL) (pb[0] - pd[0]); + cdx = (REAL) (pc[0] - pd[0]); + ady = (REAL) (pa[1] - pd[1]); + bdy = (REAL) (pb[1] - pd[1]); + cdy = (REAL) (pc[1] - pd[1]); + + Two_Product(bdx, cdy, bdxcdy1, bdxcdy0); + Two_Product(cdx, bdy, cdxbdy1, cdxbdy0); + Two_Two_Diff(bdxcdy1, bdxcdy0, cdxbdy1, cdxbdy0, bc3, bc[2], bc[1], bc[0]); + bc[3] = bc3; + axbclen = scale_expansion_zeroelim(4, bc, adx, axbc); + axxbclen = scale_expansion_zeroelim(axbclen, axbc, adx, axxbc); + aybclen = scale_expansion_zeroelim(4, bc, ady, aybc); + ayybclen = scale_expansion_zeroelim(aybclen, aybc, ady, ayybc); + alen = fast_expansion_sum_zeroelim(axxbclen, axxbc, ayybclen, ayybc, adet); + + Two_Product(cdx, ady, cdxady1, cdxady0); + Two_Product(adx, cdy, adxcdy1, adxcdy0); + Two_Two_Diff(cdxady1, cdxady0, adxcdy1, adxcdy0, ca3, ca[2], ca[1], ca[0]); + ca[3] = ca3; + bxcalen = scale_expansion_zeroelim(4, ca, bdx, bxca); + bxxcalen = scale_expansion_zeroelim(bxcalen, bxca, bdx, bxxca); + bycalen = scale_expansion_zeroelim(4, ca, bdy, byca); + byycalen = scale_expansion_zeroelim(bycalen, byca, bdy, byyca); + blen = fast_expansion_sum_zeroelim(bxxcalen, bxxca, byycalen, byyca, bdet); + + Two_Product(adx, bdy, adxbdy1, adxbdy0); + Two_Product(bdx, ady, bdxady1, bdxady0); + Two_Two_Diff(adxbdy1, adxbdy0, bdxady1, bdxady0, ab3, ab[2], ab[1], ab[0]); + ab[3] = ab3; + cxablen = scale_expansion_zeroelim(4, ab, cdx, cxab); + cxxablen = scale_expansion_zeroelim(cxablen, cxab, cdx, cxxab); + cyablen = scale_expansion_zeroelim(4, ab, cdy, cyab); + cyyablen = scale_expansion_zeroelim(cyablen, cyab, cdy, cyyab); + clen = fast_expansion_sum_zeroelim(cxxablen, cxxab, cyyablen, cyyab, cdet); + + ablen = fast_expansion_sum_zeroelim(alen, adet, blen, bdet, abdet); + finlength = fast_expansion_sum_zeroelim(ablen, abdet, clen, cdet, fin1); + + det = estimate(finlength, fin1); + errbound = iccerrboundB * permanent; + if ((det >= errbound) || (-det >= errbound)) { + return det; + } + + Two_Diff_Tail(pa[0], pd[0], adx, adxtail); + Two_Diff_Tail(pa[1], pd[1], ady, adytail); + Two_Diff_Tail(pb[0], pd[0], bdx, bdxtail); + Two_Diff_Tail(pb[1], pd[1], bdy, bdytail); + Two_Diff_Tail(pc[0], pd[0], cdx, cdxtail); + Two_Diff_Tail(pc[1], pd[1], cdy, cdytail); + if ((adxtail == 0.0) && (bdxtail == 0.0) && (cdxtail == 0.0) + && (adytail == 0.0) && (bdytail == 0.0) && (cdytail == 0.0)) { + return det; + } + + errbound = iccerrboundC * permanent + resulterrbound * Absolute(det); + det += ((adx * adx + ady * ady) * ((bdx * cdytail + cdy * bdxtail) + - (bdy * cdxtail + cdx * bdytail)) + + 2.0 * (adx * adxtail + ady * adytail) * (bdx * cdy - bdy * cdx)) + + ((bdx * bdx + bdy * bdy) * ((cdx * adytail + ady * cdxtail) + - (cdy * adxtail + adx * cdytail)) + + 2.0 * (bdx * bdxtail + bdy * bdytail) * (cdx * ady - cdy * adx)) + + ((cdx * cdx + cdy * cdy) * ((adx * bdytail + bdy * adxtail) + - (ady * bdxtail + bdx * adytail)) + + 2.0 * (cdx * cdxtail + cdy * cdytail) * (adx * bdy - ady * bdx)); + if ((det >= errbound) || (-det >= errbound)) { + return det; + } + + finnow = fin1; + finother = fin2; + + if ((bdxtail != 0.0) || (bdytail != 0.0) + || (cdxtail != 0.0) || (cdytail != 0.0)) { + Square(adx, adxadx1, adxadx0); + Square(ady, adyady1, adyady0); + Two_Two_Sum(adxadx1, adxadx0, adyady1, adyady0, aa3, aa[2], aa[1], aa[0]); + aa[3] = aa3; + } + if ((cdxtail != 0.0) || (cdytail != 0.0) + || (adxtail != 0.0) || (adytail != 0.0)) { + Square(bdx, bdxbdx1, bdxbdx0); + Square(bdy, bdybdy1, bdybdy0); + Two_Two_Sum(bdxbdx1, bdxbdx0, bdybdy1, bdybdy0, bb3, bb[2], bb[1], bb[0]); + bb[3] = bb3; + } + if ((adxtail != 0.0) || (adytail != 0.0) + || (bdxtail != 0.0) || (bdytail != 0.0)) { + Square(cdx, cdxcdx1, cdxcdx0); + Square(cdy, cdycdy1, cdycdy0); + Two_Two_Sum(cdxcdx1, cdxcdx0, cdycdy1, cdycdy0, cc3, cc[2], cc[1], cc[0]); + cc[3] = cc3; + } + + if (adxtail != 0.0) { + axtbclen = scale_expansion_zeroelim(4, bc, adxtail, axtbc); + temp16alen = scale_expansion_zeroelim(axtbclen, axtbc, 2.0 * adx, + temp16a); + + axtcclen = scale_expansion_zeroelim(4, cc, adxtail, axtcc); + temp16blen = scale_expansion_zeroelim(axtcclen, axtcc, bdy, temp16b); + + axtbblen = scale_expansion_zeroelim(4, bb, adxtail, axtbb); + temp16clen = scale_expansion_zeroelim(axtbblen, axtbb, -cdy, temp16c); + + temp32alen = fast_expansion_sum_zeroelim(temp16alen, temp16a, + temp16blen, temp16b, temp32a); + temp48len = fast_expansion_sum_zeroelim(temp16clen, temp16c, + temp32alen, temp32a, temp48); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, + temp48, finother); + finswap = finnow; finnow = finother; finother = finswap; + } + if (adytail != 0.0) { + aytbclen = scale_expansion_zeroelim(4, bc, adytail, aytbc); + temp16alen = scale_expansion_zeroelim(aytbclen, aytbc, 2.0 * ady, + temp16a); + + aytbblen = scale_expansion_zeroelim(4, bb, adytail, aytbb); + temp16blen = scale_expansion_zeroelim(aytbblen, aytbb, cdx, temp16b); + + aytcclen = scale_expansion_zeroelim(4, cc, adytail, aytcc); + temp16clen = scale_expansion_zeroelim(aytcclen, aytcc, -bdx, temp16c); + + temp32alen = fast_expansion_sum_zeroelim(temp16alen, temp16a, + temp16blen, temp16b, temp32a); + temp48len = fast_expansion_sum_zeroelim(temp16clen, temp16c, + temp32alen, temp32a, temp48); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, + temp48, finother); + finswap = finnow; finnow = finother; finother = finswap; + } + if (bdxtail != 0.0) { + bxtcalen = scale_expansion_zeroelim(4, ca, bdxtail, bxtca); + temp16alen = scale_expansion_zeroelim(bxtcalen, bxtca, 2.0 * bdx, + temp16a); + + bxtaalen = scale_expansion_zeroelim(4, aa, bdxtail, bxtaa); + temp16blen = scale_expansion_zeroelim(bxtaalen, bxtaa, cdy, temp16b); + + bxtcclen = scale_expansion_zeroelim(4, cc, bdxtail, bxtcc); + temp16clen = scale_expansion_zeroelim(bxtcclen, bxtcc, -ady, temp16c); + + temp32alen = fast_expansion_sum_zeroelim(temp16alen, temp16a, + temp16blen, temp16b, temp32a); + temp48len = fast_expansion_sum_zeroelim(temp16clen, temp16c, + temp32alen, temp32a, temp48); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, + temp48, finother); + finswap = finnow; finnow = finother; finother = finswap; + } + if (bdytail != 0.0) { + bytcalen = scale_expansion_zeroelim(4, ca, bdytail, bytca); + temp16alen = scale_expansion_zeroelim(bytcalen, bytca, 2.0 * bdy, + temp16a); + + bytcclen = scale_expansion_zeroelim(4, cc, bdytail, bytcc); + temp16blen = scale_expansion_zeroelim(bytcclen, bytcc, adx, temp16b); + + bytaalen = scale_expansion_zeroelim(4, aa, bdytail, bytaa); + temp16clen = scale_expansion_zeroelim(bytaalen, bytaa, -cdx, temp16c); + + temp32alen = fast_expansion_sum_zeroelim(temp16alen, temp16a, + temp16blen, temp16b, temp32a); + temp48len = fast_expansion_sum_zeroelim(temp16clen, temp16c, + temp32alen, temp32a, temp48); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, + temp48, finother); + finswap = finnow; finnow = finother; finother = finswap; + } + if (cdxtail != 0.0) { + cxtablen = scale_expansion_zeroelim(4, ab, cdxtail, cxtab); + temp16alen = scale_expansion_zeroelim(cxtablen, cxtab, 2.0 * cdx, + temp16a); + + cxtbblen = scale_expansion_zeroelim(4, bb, cdxtail, cxtbb); + temp16blen = scale_expansion_zeroelim(cxtbblen, cxtbb, ady, temp16b); + + cxtaalen = scale_expansion_zeroelim(4, aa, cdxtail, cxtaa); + temp16clen = scale_expansion_zeroelim(cxtaalen, cxtaa, -bdy, temp16c); + + temp32alen = fast_expansion_sum_zeroelim(temp16alen, temp16a, + temp16blen, temp16b, temp32a); + temp48len = fast_expansion_sum_zeroelim(temp16clen, temp16c, + temp32alen, temp32a, temp48); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, + temp48, finother); + finswap = finnow; finnow = finother; finother = finswap; + } + if (cdytail != 0.0) { + cytablen = scale_expansion_zeroelim(4, ab, cdytail, cytab); + temp16alen = scale_expansion_zeroelim(cytablen, cytab, 2.0 * cdy, + temp16a); + + cytaalen = scale_expansion_zeroelim(4, aa, cdytail, cytaa); + temp16blen = scale_expansion_zeroelim(cytaalen, cytaa, bdx, temp16b); + + cytbblen = scale_expansion_zeroelim(4, bb, cdytail, cytbb); + temp16clen = scale_expansion_zeroelim(cytbblen, cytbb, -adx, temp16c); + + temp32alen = fast_expansion_sum_zeroelim(temp16alen, temp16a, + temp16blen, temp16b, temp32a); + temp48len = fast_expansion_sum_zeroelim(temp16clen, temp16c, + temp32alen, temp32a, temp48); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, + temp48, finother); + finswap = finnow; finnow = finother; finother = finswap; + } + + if ((adxtail != 0.0) || (adytail != 0.0)) { + if ((bdxtail != 0.0) || (bdytail != 0.0) + || (cdxtail != 0.0) || (cdytail != 0.0)) { + Two_Product(bdxtail, cdy, ti1, ti0); + Two_Product(bdx, cdytail, tj1, tj0); + Two_Two_Sum(ti1, ti0, tj1, tj0, u3, u[2], u[1], u[0]); + u[3] = u3; + negate = -bdy; + Two_Product(cdxtail, negate, ti1, ti0); + negate = -bdytail; + Two_Product(cdx, negate, tj1, tj0); + Two_Two_Sum(ti1, ti0, tj1, tj0, v3, v[2], v[1], v[0]); + v[3] = v3; + bctlen = fast_expansion_sum_zeroelim(4, u, 4, v, bct); + + Two_Product(bdxtail, cdytail, ti1, ti0); + Two_Product(cdxtail, bdytail, tj1, tj0); + Two_Two_Diff(ti1, ti0, tj1, tj0, bctt3, bctt[2], bctt[1], bctt[0]); + bctt[3] = bctt3; + bcttlen = 4; + } else { + bct[0] = 0.0; + bctlen = 1; + bctt[0] = 0.0; + bcttlen = 1; + } + + if (adxtail != 0.0) { + temp16alen = scale_expansion_zeroelim(axtbclen, axtbc, adxtail, temp16a); + axtbctlen = scale_expansion_zeroelim(bctlen, bct, adxtail, axtbct); + temp32alen = scale_expansion_zeroelim(axtbctlen, axtbct, 2.0 * adx, + temp32a); + temp48len = fast_expansion_sum_zeroelim(temp16alen, temp16a, + temp32alen, temp32a, temp48); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, + temp48, finother); + finswap = finnow; finnow = finother; finother = finswap; + if (bdytail != 0.0) { + temp8len = scale_expansion_zeroelim(4, cc, adxtail, temp8); + temp16alen = scale_expansion_zeroelim(temp8len, temp8, bdytail, + temp16a); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp16alen, + temp16a, finother); + finswap = finnow; finnow = finother; finother = finswap; + } + if (cdytail != 0.0) { + temp8len = scale_expansion_zeroelim(4, bb, -adxtail, temp8); + temp16alen = scale_expansion_zeroelim(temp8len, temp8, cdytail, + temp16a); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp16alen, + temp16a, finother); + finswap = finnow; finnow = finother; finother = finswap; + } + + temp32alen = scale_expansion_zeroelim(axtbctlen, axtbct, adxtail, + temp32a); + axtbcttlen = scale_expansion_zeroelim(bcttlen, bctt, adxtail, axtbctt); + temp16alen = scale_expansion_zeroelim(axtbcttlen, axtbctt, 2.0 * adx, + temp16a); + temp16blen = scale_expansion_zeroelim(axtbcttlen, axtbctt, adxtail, + temp16b); + temp32blen = fast_expansion_sum_zeroelim(temp16alen, temp16a, + temp16blen, temp16b, temp32b); + temp64len = fast_expansion_sum_zeroelim(temp32alen, temp32a, + temp32blen, temp32b, temp64); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp64len, + temp64, finother); + finswap = finnow; finnow = finother; finother = finswap; + } + if (adytail != 0.0) { + temp16alen = scale_expansion_zeroelim(aytbclen, aytbc, adytail, temp16a); + aytbctlen = scale_expansion_zeroelim(bctlen, bct, adytail, aytbct); + temp32alen = scale_expansion_zeroelim(aytbctlen, aytbct, 2.0 * ady, + temp32a); + temp48len = fast_expansion_sum_zeroelim(temp16alen, temp16a, + temp32alen, temp32a, temp48); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, + temp48, finother); + finswap = finnow; finnow = finother; finother = finswap; + + + temp32alen = scale_expansion_zeroelim(aytbctlen, aytbct, adytail, + temp32a); + aytbcttlen = scale_expansion_zeroelim(bcttlen, bctt, adytail, aytbctt); + temp16alen = scale_expansion_zeroelim(aytbcttlen, aytbctt, 2.0 * ady, + temp16a); + temp16blen = scale_expansion_zeroelim(aytbcttlen, aytbctt, adytail, + temp16b); + temp32blen = fast_expansion_sum_zeroelim(temp16alen, temp16a, + temp16blen, temp16b, temp32b); + temp64len = fast_expansion_sum_zeroelim(temp32alen, temp32a, + temp32blen, temp32b, temp64); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp64len, + temp64, finother); + finswap = finnow; finnow = finother; finother = finswap; + } + } + if ((bdxtail != 0.0) || (bdytail != 0.0)) { + if ((cdxtail != 0.0) || (cdytail != 0.0) + || (adxtail != 0.0) || (adytail != 0.0)) { + Two_Product(cdxtail, ady, ti1, ti0); + Two_Product(cdx, adytail, tj1, tj0); + Two_Two_Sum(ti1, ti0, tj1, tj0, u3, u[2], u[1], u[0]); + u[3] = u3; + negate = -cdy; + Two_Product(adxtail, negate, ti1, ti0); + negate = -cdytail; + Two_Product(adx, negate, tj1, tj0); + Two_Two_Sum(ti1, ti0, tj1, tj0, v3, v[2], v[1], v[0]); + v[3] = v3; + catlen = fast_expansion_sum_zeroelim(4, u, 4, v, cat); + + Two_Product(cdxtail, adytail, ti1, ti0); + Two_Product(adxtail, cdytail, tj1, tj0); + Two_Two_Diff(ti1, ti0, tj1, tj0, catt3, catt[2], catt[1], catt[0]); + catt[3] = catt3; + cattlen = 4; + } else { + cat[0] = 0.0; + catlen = 1; + catt[0] = 0.0; + cattlen = 1; + } + + if (bdxtail != 0.0) { + temp16alen = scale_expansion_zeroelim(bxtcalen, bxtca, bdxtail, temp16a); + bxtcatlen = scale_expansion_zeroelim(catlen, cat, bdxtail, bxtcat); + temp32alen = scale_expansion_zeroelim(bxtcatlen, bxtcat, 2.0 * bdx, + temp32a); + temp48len = fast_expansion_sum_zeroelim(temp16alen, temp16a, + temp32alen, temp32a, temp48); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, + temp48, finother); + finswap = finnow; finnow = finother; finother = finswap; + if (cdytail != 0.0) { + temp8len = scale_expansion_zeroelim(4, aa, bdxtail, temp8); + temp16alen = scale_expansion_zeroelim(temp8len, temp8, cdytail, + temp16a); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp16alen, + temp16a, finother); + finswap = finnow; finnow = finother; finother = finswap; + } + if (adytail != 0.0) { + temp8len = scale_expansion_zeroelim(4, cc, -bdxtail, temp8); + temp16alen = scale_expansion_zeroelim(temp8len, temp8, adytail, + temp16a); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp16alen, + temp16a, finother); + finswap = finnow; finnow = finother; finother = finswap; + } + + temp32alen = scale_expansion_zeroelim(bxtcatlen, bxtcat, bdxtail, + temp32a); + bxtcattlen = scale_expansion_zeroelim(cattlen, catt, bdxtail, bxtcatt); + temp16alen = scale_expansion_zeroelim(bxtcattlen, bxtcatt, 2.0 * bdx, + temp16a); + temp16blen = scale_expansion_zeroelim(bxtcattlen, bxtcatt, bdxtail, + temp16b); + temp32blen = fast_expansion_sum_zeroelim(temp16alen, temp16a, + temp16blen, temp16b, temp32b); + temp64len = fast_expansion_sum_zeroelim(temp32alen, temp32a, + temp32blen, temp32b, temp64); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp64len, + temp64, finother); + finswap = finnow; finnow = finother; finother = finswap; + } + if (bdytail != 0.0) { + temp16alen = scale_expansion_zeroelim(bytcalen, bytca, bdytail, temp16a); + bytcatlen = scale_expansion_zeroelim(catlen, cat, bdytail, bytcat); + temp32alen = scale_expansion_zeroelim(bytcatlen, bytcat, 2.0 * bdy, + temp32a); + temp48len = fast_expansion_sum_zeroelim(temp16alen, temp16a, + temp32alen, temp32a, temp48); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, + temp48, finother); + finswap = finnow; finnow = finother; finother = finswap; + + + temp32alen = scale_expansion_zeroelim(bytcatlen, bytcat, bdytail, + temp32a); + bytcattlen = scale_expansion_zeroelim(cattlen, catt, bdytail, bytcatt); + temp16alen = scale_expansion_zeroelim(bytcattlen, bytcatt, 2.0 * bdy, + temp16a); + temp16blen = scale_expansion_zeroelim(bytcattlen, bytcatt, bdytail, + temp16b); + temp32blen = fast_expansion_sum_zeroelim(temp16alen, temp16a, + temp16blen, temp16b, temp32b); + temp64len = fast_expansion_sum_zeroelim(temp32alen, temp32a, + temp32blen, temp32b, temp64); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp64len, + temp64, finother); + finswap = finnow; finnow = finother; finother = finswap; + } + } + if ((cdxtail != 0.0) || (cdytail != 0.0)) { + if ((adxtail != 0.0) || (adytail != 0.0) + || (bdxtail != 0.0) || (bdytail != 0.0)) { + Two_Product(adxtail, bdy, ti1, ti0); + Two_Product(adx, bdytail, tj1, tj0); + Two_Two_Sum(ti1, ti0, tj1, tj0, u3, u[2], u[1], u[0]); + u[3] = u3; + negate = -ady; + Two_Product(bdxtail, negate, ti1, ti0); + negate = -adytail; + Two_Product(bdx, negate, tj1, tj0); + Two_Two_Sum(ti1, ti0, tj1, tj0, v3, v[2], v[1], v[0]); + v[3] = v3; + abtlen = fast_expansion_sum_zeroelim(4, u, 4, v, abt); + + Two_Product(adxtail, bdytail, ti1, ti0); + Two_Product(bdxtail, adytail, tj1, tj0); + Two_Two_Diff(ti1, ti0, tj1, tj0, abtt3, abtt[2], abtt[1], abtt[0]); + abtt[3] = abtt3; + abttlen = 4; + } else { + abt[0] = 0.0; + abtlen = 1; + abtt[0] = 0.0; + abttlen = 1; + } + + if (cdxtail != 0.0) { + temp16alen = scale_expansion_zeroelim(cxtablen, cxtab, cdxtail, temp16a); + cxtabtlen = scale_expansion_zeroelim(abtlen, abt, cdxtail, cxtabt); + temp32alen = scale_expansion_zeroelim(cxtabtlen, cxtabt, 2.0 * cdx, + temp32a); + temp48len = fast_expansion_sum_zeroelim(temp16alen, temp16a, + temp32alen, temp32a, temp48); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, + temp48, finother); + finswap = finnow; finnow = finother; finother = finswap; + if (adytail != 0.0) { + temp8len = scale_expansion_zeroelim(4, bb, cdxtail, temp8); + temp16alen = scale_expansion_zeroelim(temp8len, temp8, adytail, + temp16a); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp16alen, + temp16a, finother); + finswap = finnow; finnow = finother; finother = finswap; + } + if (bdytail != 0.0) { + temp8len = scale_expansion_zeroelim(4, aa, -cdxtail, temp8); + temp16alen = scale_expansion_zeroelim(temp8len, temp8, bdytail, + temp16a); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp16alen, + temp16a, finother); + finswap = finnow; finnow = finother; finother = finswap; + } + + temp32alen = scale_expansion_zeroelim(cxtabtlen, cxtabt, cdxtail, + temp32a); + cxtabttlen = scale_expansion_zeroelim(abttlen, abtt, cdxtail, cxtabtt); + temp16alen = scale_expansion_zeroelim(cxtabttlen, cxtabtt, 2.0 * cdx, + temp16a); + temp16blen = scale_expansion_zeroelim(cxtabttlen, cxtabtt, cdxtail, + temp16b); + temp32blen = fast_expansion_sum_zeroelim(temp16alen, temp16a, + temp16blen, temp16b, temp32b); + temp64len = fast_expansion_sum_zeroelim(temp32alen, temp32a, + temp32blen, temp32b, temp64); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp64len, + temp64, finother); + finswap = finnow; finnow = finother; finother = finswap; + } + if (cdytail != 0.0) { + temp16alen = scale_expansion_zeroelim(cytablen, cytab, cdytail, temp16a); + cytabtlen = scale_expansion_zeroelim(abtlen, abt, cdytail, cytabt); + temp32alen = scale_expansion_zeroelim(cytabtlen, cytabt, 2.0 * cdy, + temp32a); + temp48len = fast_expansion_sum_zeroelim(temp16alen, temp16a, + temp32alen, temp32a, temp48); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, + temp48, finother); + finswap = finnow; finnow = finother; finother = finswap; + + + temp32alen = scale_expansion_zeroelim(cytabtlen, cytabt, cdytail, + temp32a); + cytabttlen = scale_expansion_zeroelim(abttlen, abtt, cdytail, cytabtt); + temp16alen = scale_expansion_zeroelim(cytabttlen, cytabtt, 2.0 * cdy, + temp16a); + temp16blen = scale_expansion_zeroelim(cytabttlen, cytabtt, cdytail, + temp16b); + temp32blen = fast_expansion_sum_zeroelim(temp16alen, temp16a, + temp16blen, temp16b, temp32b); + temp64len = fast_expansion_sum_zeroelim(temp32alen, temp32a, + temp32blen, temp32b, temp64); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp64len, + temp64, finother); + finswap = finnow; finnow = finother; finother = finswap; + } + } + + return finnow[finlength - 1]; +} + +#ifdef ANSI_DECLARATORS +REAL incircle(struct mesh *m, struct behavior *b, + vertex pa, vertex pb, vertex pc, vertex pd) +#else /* not ANSI_DECLARATORS */ +REAL incircle(m, b, pa, pb, pc, pd) +struct mesh *m; +struct behavior *b; +vertex pa; +vertex pb; +vertex pc; +vertex pd; +#endif /* not ANSI_DECLARATORS */ + +{ + REAL adx, bdx, cdx, ady, bdy, cdy; + REAL bdxcdy, cdxbdy, cdxady, adxcdy, adxbdy, bdxady; + REAL alift, blift, clift; + REAL det; + REAL permanent, errbound; + + m->incirclecount++; + + adx = pa[0] - pd[0]; + bdx = pb[0] - pd[0]; + cdx = pc[0] - pd[0]; + ady = pa[1] - pd[1]; + bdy = pb[1] - pd[1]; + cdy = pc[1] - pd[1]; + + bdxcdy = bdx * cdy; + cdxbdy = cdx * bdy; + alift = adx * adx + ady * ady; + + cdxady = cdx * ady; + adxcdy = adx * cdy; + blift = bdx * bdx + bdy * bdy; + + adxbdy = adx * bdy; + bdxady = bdx * ady; + clift = cdx * cdx + cdy * cdy; + + det = alift * (bdxcdy - cdxbdy) + + blift * (cdxady - adxcdy) + + clift * (adxbdy - bdxady); + + if (b->noexact) { + return det; + } + + permanent = (Absolute(bdxcdy) + Absolute(cdxbdy)) * alift + + (Absolute(cdxady) + Absolute(adxcdy)) * blift + + (Absolute(adxbdy) + Absolute(bdxady)) * clift; + errbound = iccerrboundA * permanent; + if ((det > errbound) || (-det > errbound)) { + return det; + } + + return incircleadapt(pa, pb, pc, pd, permanent); +} + +/*****************************************************************************/ +/* */ +/* orient3d() Return a positive value if the point pd lies below the */ +/* plane passing through pa, pb, and pc; "below" is defined so */ +/* that pa, pb, and pc appear in counterclockwise order when */ +/* viewed from above the plane. Returns a negative value if */ +/* pd lies above the plane. Returns zero if the points are */ +/* coplanar. The result is also a rough approximation of six */ +/* times the signed volume of the tetrahedron defined by the */ +/* four points. */ +/* */ +/* Uses exact arithmetic if necessary to ensure a correct answer. The */ +/* result returned is the determinant of a matrix. This determinant is */ +/* computed adaptively, in the sense that exact arithmetic is used only to */ +/* the degree it is needed to ensure that the returned value has the */ +/* correct sign. Hence, this function is usually quite fast, but will run */ +/* more slowly when the input points are coplanar or nearly so. */ +/* */ +/* See my Robust Predicates paper for details. */ +/* */ +/*****************************************************************************/ + +#ifdef ANSI_DECLARATORS +REAL orient3dadapt(vertex pa, vertex pb, vertex pc, vertex pd, + REAL aheight, REAL bheight, REAL cheight, REAL dheight, + REAL permanent) +#else /* not ANSI_DECLARATORS */ +REAL orient3dadapt(pa, pb, pc, pd, + aheight, bheight, cheight, dheight, permanent) +vertex pa; +vertex pb; +vertex pc; +vertex pd; +REAL aheight; +REAL bheight; +REAL cheight; +REAL dheight; +REAL permanent; +#endif /* not ANSI_DECLARATORS */ + +{ + INEXACT REAL adx, bdx, cdx, ady, bdy, cdy, adheight, bdheight, cdheight; + REAL det, errbound; + + INEXACT REAL bdxcdy1, cdxbdy1, cdxady1, adxcdy1, adxbdy1, bdxady1; + REAL bdxcdy0, cdxbdy0, cdxady0, adxcdy0, adxbdy0, bdxady0; + REAL bc[4], ca[4], ab[4]; + INEXACT REAL bc3, ca3, ab3; + REAL adet[8], bdet[8], cdet[8]; + int alen, blen, clen; + REAL abdet[16]; + int ablen; + REAL *finnow, *finother, *finswap; + REAL fin1[192], fin2[192]; + int finlength; + + REAL adxtail, bdxtail, cdxtail; + REAL adytail, bdytail, cdytail; + REAL adheighttail, bdheighttail, cdheighttail; + INEXACT REAL at_blarge, at_clarge; + INEXACT REAL bt_clarge, bt_alarge; + INEXACT REAL ct_alarge, ct_blarge; + REAL at_b[4], at_c[4], bt_c[4], bt_a[4], ct_a[4], ct_b[4]; + int at_blen, at_clen, bt_clen, bt_alen, ct_alen, ct_blen; + INEXACT REAL bdxt_cdy1, cdxt_bdy1, cdxt_ady1; + INEXACT REAL adxt_cdy1, adxt_bdy1, bdxt_ady1; + REAL bdxt_cdy0, cdxt_bdy0, cdxt_ady0; + REAL adxt_cdy0, adxt_bdy0, bdxt_ady0; + INEXACT REAL bdyt_cdx1, cdyt_bdx1, cdyt_adx1; + INEXACT REAL adyt_cdx1, adyt_bdx1, bdyt_adx1; + REAL bdyt_cdx0, cdyt_bdx0, cdyt_adx0; + REAL adyt_cdx0, adyt_bdx0, bdyt_adx0; + REAL bct[8], cat[8], abt[8]; + int bctlen, catlen, abtlen; + INEXACT REAL bdxt_cdyt1, cdxt_bdyt1, cdxt_adyt1; + INEXACT REAL adxt_cdyt1, adxt_bdyt1, bdxt_adyt1; + REAL bdxt_cdyt0, cdxt_bdyt0, cdxt_adyt0; + REAL adxt_cdyt0, adxt_bdyt0, bdxt_adyt0; + REAL u[4], v[12], w[16]; + INEXACT REAL u3; + int vlength, wlength; + REAL negate; + + INEXACT REAL bvirt; + REAL avirt, bround, around; + INEXACT REAL c; + INEXACT REAL abig; + REAL ahi, alo, bhi, blo; + REAL err1, err2, err3; + INEXACT REAL _i, _j, _k; + REAL _0; + + adx = (REAL) (pa[0] - pd[0]); + bdx = (REAL) (pb[0] - pd[0]); + cdx = (REAL) (pc[0] - pd[0]); + ady = (REAL) (pa[1] - pd[1]); + bdy = (REAL) (pb[1] - pd[1]); + cdy = (REAL) (pc[1] - pd[1]); + adheight = (REAL) (aheight - dheight); + bdheight = (REAL) (bheight - dheight); + cdheight = (REAL) (cheight - dheight); + + Two_Product(bdx, cdy, bdxcdy1, bdxcdy0); + Two_Product(cdx, bdy, cdxbdy1, cdxbdy0); + Two_Two_Diff(bdxcdy1, bdxcdy0, cdxbdy1, cdxbdy0, bc3, bc[2], bc[1], bc[0]); + bc[3] = bc3; + alen = scale_expansion_zeroelim(4, bc, adheight, adet); + + Two_Product(cdx, ady, cdxady1, cdxady0); + Two_Product(adx, cdy, adxcdy1, adxcdy0); + Two_Two_Diff(cdxady1, cdxady0, adxcdy1, adxcdy0, ca3, ca[2], ca[1], ca[0]); + ca[3] = ca3; + blen = scale_expansion_zeroelim(4, ca, bdheight, bdet); + + Two_Product(adx, bdy, adxbdy1, adxbdy0); + Two_Product(bdx, ady, bdxady1, bdxady0); + Two_Two_Diff(adxbdy1, adxbdy0, bdxady1, bdxady0, ab3, ab[2], ab[1], ab[0]); + ab[3] = ab3; + clen = scale_expansion_zeroelim(4, ab, cdheight, cdet); + + ablen = fast_expansion_sum_zeroelim(alen, adet, blen, bdet, abdet); + finlength = fast_expansion_sum_zeroelim(ablen, abdet, clen, cdet, fin1); + + det = estimate(finlength, fin1); + errbound = o3derrboundB * permanent; + if ((det >= errbound) || (-det >= errbound)) { + return det; + } + + Two_Diff_Tail(pa[0], pd[0], adx, adxtail); + Two_Diff_Tail(pb[0], pd[0], bdx, bdxtail); + Two_Diff_Tail(pc[0], pd[0], cdx, cdxtail); + Two_Diff_Tail(pa[1], pd[1], ady, adytail); + Two_Diff_Tail(pb[1], pd[1], bdy, bdytail); + Two_Diff_Tail(pc[1], pd[1], cdy, cdytail); + Two_Diff_Tail(aheight, dheight, adheight, adheighttail); + Two_Diff_Tail(bheight, dheight, bdheight, bdheighttail); + Two_Diff_Tail(cheight, dheight, cdheight, cdheighttail); + + if ((adxtail == 0.0) && (bdxtail == 0.0) && (cdxtail == 0.0) && + (adytail == 0.0) && (bdytail == 0.0) && (cdytail == 0.0) && + (adheighttail == 0.0) && + (bdheighttail == 0.0) && + (cdheighttail == 0.0)) { + return det; + } + + errbound = o3derrboundC * permanent + resulterrbound * Absolute(det); + det += (adheight * ((bdx * cdytail + cdy * bdxtail) - + (bdy * cdxtail + cdx * bdytail)) + + adheighttail * (bdx * cdy - bdy * cdx)) + + (bdheight * ((cdx * adytail + ady * cdxtail) - + (cdy * adxtail + adx * cdytail)) + + bdheighttail * (cdx * ady - cdy * adx)) + + (cdheight * ((adx * bdytail + bdy * adxtail) - + (ady * bdxtail + bdx * adytail)) + + cdheighttail * (adx * bdy - ady * bdx)); + if ((det >= errbound) || (-det >= errbound)) { + return det; + } + + finnow = fin1; + finother = fin2; + + if (adxtail == 0.0) { + if (adytail == 0.0) { + at_b[0] = 0.0; + at_blen = 1; + at_c[0] = 0.0; + at_clen = 1; + } else { + negate = -adytail; + Two_Product(negate, bdx, at_blarge, at_b[0]); + at_b[1] = at_blarge; + at_blen = 2; + Two_Product(adytail, cdx, at_clarge, at_c[0]); + at_c[1] = at_clarge; + at_clen = 2; + } + } else { + if (adytail == 0.0) { + Two_Product(adxtail, bdy, at_blarge, at_b[0]); + at_b[1] = at_blarge; + at_blen = 2; + negate = -adxtail; + Two_Product(negate, cdy, at_clarge, at_c[0]); + at_c[1] = at_clarge; + at_clen = 2; + } else { + Two_Product(adxtail, bdy, adxt_bdy1, adxt_bdy0); + Two_Product(adytail, bdx, adyt_bdx1, adyt_bdx0); + Two_Two_Diff(adxt_bdy1, adxt_bdy0, adyt_bdx1, adyt_bdx0, + at_blarge, at_b[2], at_b[1], at_b[0]); + at_b[3] = at_blarge; + at_blen = 4; + Two_Product(adytail, cdx, adyt_cdx1, adyt_cdx0); + Two_Product(adxtail, cdy, adxt_cdy1, adxt_cdy0); + Two_Two_Diff(adyt_cdx1, adyt_cdx0, adxt_cdy1, adxt_cdy0, + at_clarge, at_c[2], at_c[1], at_c[0]); + at_c[3] = at_clarge; + at_clen = 4; + } + } + if (bdxtail == 0.0) { + if (bdytail == 0.0) { + bt_c[0] = 0.0; + bt_clen = 1; + bt_a[0] = 0.0; + bt_alen = 1; + } else { + negate = -bdytail; + Two_Product(negate, cdx, bt_clarge, bt_c[0]); + bt_c[1] = bt_clarge; + bt_clen = 2; + Two_Product(bdytail, adx, bt_alarge, bt_a[0]); + bt_a[1] = bt_alarge; + bt_alen = 2; + } + } else { + if (bdytail == 0.0) { + Two_Product(bdxtail, cdy, bt_clarge, bt_c[0]); + bt_c[1] = bt_clarge; + bt_clen = 2; + negate = -bdxtail; + Two_Product(negate, ady, bt_alarge, bt_a[0]); + bt_a[1] = bt_alarge; + bt_alen = 2; + } else { + Two_Product(bdxtail, cdy, bdxt_cdy1, bdxt_cdy0); + Two_Product(bdytail, cdx, bdyt_cdx1, bdyt_cdx0); + Two_Two_Diff(bdxt_cdy1, bdxt_cdy0, bdyt_cdx1, bdyt_cdx0, + bt_clarge, bt_c[2], bt_c[1], bt_c[0]); + bt_c[3] = bt_clarge; + bt_clen = 4; + Two_Product(bdytail, adx, bdyt_adx1, bdyt_adx0); + Two_Product(bdxtail, ady, bdxt_ady1, bdxt_ady0); + Two_Two_Diff(bdyt_adx1, bdyt_adx0, bdxt_ady1, bdxt_ady0, + bt_alarge, bt_a[2], bt_a[1], bt_a[0]); + bt_a[3] = bt_alarge; + bt_alen = 4; + } + } + if (cdxtail == 0.0) { + if (cdytail == 0.0) { + ct_a[0] = 0.0; + ct_alen = 1; + ct_b[0] = 0.0; + ct_blen = 1; + } else { + negate = -cdytail; + Two_Product(negate, adx, ct_alarge, ct_a[0]); + ct_a[1] = ct_alarge; + ct_alen = 2; + Two_Product(cdytail, bdx, ct_blarge, ct_b[0]); + ct_b[1] = ct_blarge; + ct_blen = 2; + } + } else { + if (cdytail == 0.0) { + Two_Product(cdxtail, ady, ct_alarge, ct_a[0]); + ct_a[1] = ct_alarge; + ct_alen = 2; + negate = -cdxtail; + Two_Product(negate, bdy, ct_blarge, ct_b[0]); + ct_b[1] = ct_blarge; + ct_blen = 2; + } else { + Two_Product(cdxtail, ady, cdxt_ady1, cdxt_ady0); + Two_Product(cdytail, adx, cdyt_adx1, cdyt_adx0); + Two_Two_Diff(cdxt_ady1, cdxt_ady0, cdyt_adx1, cdyt_adx0, + ct_alarge, ct_a[2], ct_a[1], ct_a[0]); + ct_a[3] = ct_alarge; + ct_alen = 4; + Two_Product(cdytail, bdx, cdyt_bdx1, cdyt_bdx0); + Two_Product(cdxtail, bdy, cdxt_bdy1, cdxt_bdy0); + Two_Two_Diff(cdyt_bdx1, cdyt_bdx0, cdxt_bdy1, cdxt_bdy0, + ct_blarge, ct_b[2], ct_b[1], ct_b[0]); + ct_b[3] = ct_blarge; + ct_blen = 4; + } + } + + bctlen = fast_expansion_sum_zeroelim(bt_clen, bt_c, ct_blen, ct_b, bct); + wlength = scale_expansion_zeroelim(bctlen, bct, adheight, w); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, wlength, w, + finother); + finswap = finnow; finnow = finother; finother = finswap; + + catlen = fast_expansion_sum_zeroelim(ct_alen, ct_a, at_clen, at_c, cat); + wlength = scale_expansion_zeroelim(catlen, cat, bdheight, w); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, wlength, w, + finother); + finswap = finnow; finnow = finother; finother = finswap; + + abtlen = fast_expansion_sum_zeroelim(at_blen, at_b, bt_alen, bt_a, abt); + wlength = scale_expansion_zeroelim(abtlen, abt, cdheight, w); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, wlength, w, + finother); + finswap = finnow; finnow = finother; finother = finswap; + + if (adheighttail != 0.0) { + vlength = scale_expansion_zeroelim(4, bc, adheighttail, v); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, vlength, v, + finother); + finswap = finnow; finnow = finother; finother = finswap; + } + if (bdheighttail != 0.0) { + vlength = scale_expansion_zeroelim(4, ca, bdheighttail, v); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, vlength, v, + finother); + finswap = finnow; finnow = finother; finother = finswap; + } + if (cdheighttail != 0.0) { + vlength = scale_expansion_zeroelim(4, ab, cdheighttail, v); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, vlength, v, + finother); + finswap = finnow; finnow = finother; finother = finswap; + } + + if (adxtail != 0.0) { + if (bdytail != 0.0) { + Two_Product(adxtail, bdytail, adxt_bdyt1, adxt_bdyt0); + Two_One_Product(adxt_bdyt1, adxt_bdyt0, cdheight, u3, u[2], u[1], u[0]); + u[3] = u3; + finlength = fast_expansion_sum_zeroelim(finlength, finnow, 4, u, + finother); + finswap = finnow; finnow = finother; finother = finswap; + if (cdheighttail != 0.0) { + Two_One_Product(adxt_bdyt1, adxt_bdyt0, cdheighttail, + u3, u[2], u[1], u[0]); + u[3] = u3; + finlength = fast_expansion_sum_zeroelim(finlength, finnow, 4, u, + finother); + finswap = finnow; finnow = finother; finother = finswap; + } + } + if (cdytail != 0.0) { + negate = -adxtail; + Two_Product(negate, cdytail, adxt_cdyt1, adxt_cdyt0); + Two_One_Product(adxt_cdyt1, adxt_cdyt0, bdheight, u3, u[2], u[1], u[0]); + u[3] = u3; + finlength = fast_expansion_sum_zeroelim(finlength, finnow, 4, u, + finother); + finswap = finnow; finnow = finother; finother = finswap; + if (bdheighttail != 0.0) { + Two_One_Product(adxt_cdyt1, adxt_cdyt0, bdheighttail, + u3, u[2], u[1], u[0]); + u[3] = u3; + finlength = fast_expansion_sum_zeroelim(finlength, finnow, 4, u, + finother); + finswap = finnow; finnow = finother; finother = finswap; + } + } + } + if (bdxtail != 0.0) { + if (cdytail != 0.0) { + Two_Product(bdxtail, cdytail, bdxt_cdyt1, bdxt_cdyt0); + Two_One_Product(bdxt_cdyt1, bdxt_cdyt0, adheight, u3, u[2], u[1], u[0]); + u[3] = u3; + finlength = fast_expansion_sum_zeroelim(finlength, finnow, 4, u, + finother); + finswap = finnow; finnow = finother; finother = finswap; + if (adheighttail != 0.0) { + Two_One_Product(bdxt_cdyt1, bdxt_cdyt0, adheighttail, + u3, u[2], u[1], u[0]); + u[3] = u3; + finlength = fast_expansion_sum_zeroelim(finlength, finnow, 4, u, + finother); + finswap = finnow; finnow = finother; finother = finswap; + } + } + if (adytail != 0.0) { + negate = -bdxtail; + Two_Product(negate, adytail, bdxt_adyt1, bdxt_adyt0); + Two_One_Product(bdxt_adyt1, bdxt_adyt0, cdheight, u3, u[2], u[1], u[0]); + u[3] = u3; + finlength = fast_expansion_sum_zeroelim(finlength, finnow, 4, u, + finother); + finswap = finnow; finnow = finother; finother = finswap; + if (cdheighttail != 0.0) { + Two_One_Product(bdxt_adyt1, bdxt_adyt0, cdheighttail, + u3, u[2], u[1], u[0]); + u[3] = u3; + finlength = fast_expansion_sum_zeroelim(finlength, finnow, 4, u, + finother); + finswap = finnow; finnow = finother; finother = finswap; + } + } + } + if (cdxtail != 0.0) { + if (adytail != 0.0) { + Two_Product(cdxtail, adytail, cdxt_adyt1, cdxt_adyt0); + Two_One_Product(cdxt_adyt1, cdxt_adyt0, bdheight, u3, u[2], u[1], u[0]); + u[3] = u3; + finlength = fast_expansion_sum_zeroelim(finlength, finnow, 4, u, + finother); + finswap = finnow; finnow = finother; finother = finswap; + if (bdheighttail != 0.0) { + Two_One_Product(cdxt_adyt1, cdxt_adyt0, bdheighttail, + u3, u[2], u[1], u[0]); + u[3] = u3; + finlength = fast_expansion_sum_zeroelim(finlength, finnow, 4, u, + finother); + finswap = finnow; finnow = finother; finother = finswap; + } + } + if (bdytail != 0.0) { + negate = -cdxtail; + Two_Product(negate, bdytail, cdxt_bdyt1, cdxt_bdyt0); + Two_One_Product(cdxt_bdyt1, cdxt_bdyt0, adheight, u3, u[2], u[1], u[0]); + u[3] = u3; + finlength = fast_expansion_sum_zeroelim(finlength, finnow, 4, u, + finother); + finswap = finnow; finnow = finother; finother = finswap; + if (adheighttail != 0.0) { + Two_One_Product(cdxt_bdyt1, cdxt_bdyt0, adheighttail, + u3, u[2], u[1], u[0]); + u[3] = u3; + finlength = fast_expansion_sum_zeroelim(finlength, finnow, 4, u, + finother); + finswap = finnow; finnow = finother; finother = finswap; + } + } + } + + if (adheighttail != 0.0) { + wlength = scale_expansion_zeroelim(bctlen, bct, adheighttail, w); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, wlength, w, + finother); + finswap = finnow; finnow = finother; finother = finswap; + } + if (bdheighttail != 0.0) { + wlength = scale_expansion_zeroelim(catlen, cat, bdheighttail, w); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, wlength, w, + finother); + finswap = finnow; finnow = finother; finother = finswap; + } + if (cdheighttail != 0.0) { + wlength = scale_expansion_zeroelim(abtlen, abt, cdheighttail, w); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, wlength, w, + finother); + finswap = finnow; finnow = finother; finother = finswap; + } + + return finnow[finlength - 1]; +} + +#ifdef ANSI_DECLARATORS +REAL orient3d(struct mesh *m, struct behavior *b, + vertex pa, vertex pb, vertex pc, vertex pd, + REAL aheight, REAL bheight, REAL cheight, REAL dheight) +#else /* not ANSI_DECLARATORS */ +REAL orient3d(m, b, pa, pb, pc, pd, aheight, bheight, cheight, dheight) +struct mesh *m; +struct behavior *b; +vertex pa; +vertex pb; +vertex pc; +vertex pd; +REAL aheight; +REAL bheight; +REAL cheight; +REAL dheight; +#endif /* not ANSI_DECLARATORS */ + +{ + REAL adx, bdx, cdx, ady, bdy, cdy, adheight, bdheight, cdheight; + REAL bdxcdy, cdxbdy, cdxady, adxcdy, adxbdy, bdxady; + REAL det; + REAL permanent, errbound; + + m->orient3dcount++; + + adx = pa[0] - pd[0]; + bdx = pb[0] - pd[0]; + cdx = pc[0] - pd[0]; + ady = pa[1] - pd[1]; + bdy = pb[1] - pd[1]; + cdy = pc[1] - pd[1]; + adheight = aheight - dheight; + bdheight = bheight - dheight; + cdheight = cheight - dheight; + + bdxcdy = bdx * cdy; + cdxbdy = cdx * bdy; + + cdxady = cdx * ady; + adxcdy = adx * cdy; + + adxbdy = adx * bdy; + bdxady = bdx * ady; + + det = adheight * (bdxcdy - cdxbdy) + + bdheight * (cdxady - adxcdy) + + cdheight * (adxbdy - bdxady); + + if (b->noexact) { + return det; + } + + permanent = (Absolute(bdxcdy) + Absolute(cdxbdy)) * Absolute(adheight) + + (Absolute(cdxady) + Absolute(adxcdy)) * Absolute(bdheight) + + (Absolute(adxbdy) + Absolute(bdxady)) * Absolute(cdheight); + errbound = o3derrboundA * permanent; + if ((det > errbound) || (-det > errbound)) { + return det; + } + + return orient3dadapt(pa, pb, pc, pd, aheight, bheight, cheight, dheight, + permanent); +} + +/*****************************************************************************/ +/* */ +/* nonregular() Return a positive value if the point pd is incompatible */ +/* with the circle or plane passing through pa, pb, and pc */ +/* (meaning that pd is inside the circle or below the */ +/* plane); a negative value if it is compatible; and zero if */ +/* the four points are cocircular/coplanar. The points pa, */ +/* pb, and pc must be in counterclockwise order, or the sign */ +/* of the result will be reversed. */ +/* */ +/* If the -w switch is used, the points are lifted onto the parabolic */ +/* lifting map, then they are dropped according to their weights, then the */ +/* 3D orientation test is applied. If the -W switch is used, the points' */ +/* heights are already provided, so the 3D orientation test is applied */ +/* directly. If neither switch is used, the incircle test is applied. */ +/* */ +/*****************************************************************************/ + +#ifdef ANSI_DECLARATORS +REAL nonregular(struct mesh *m, struct behavior *b, + vertex pa, vertex pb, vertex pc, vertex pd) +#else /* not ANSI_DECLARATORS */ +REAL nonregular(m, b, pa, pb, pc, pd) +struct mesh *m; +struct behavior *b; +vertex pa; +vertex pb; +vertex pc; +vertex pd; +#endif /* not ANSI_DECLARATORS */ + +{ + if (b->weighted == 0) { + return incircle(m, b, pa, pb, pc, pd); + } else if (b->weighted == 1) { + return orient3d(m, b, pa, pb, pc, pd, + pa[0] * pa[0] + pa[1] * pa[1] - pa[2], + pb[0] * pb[0] + pb[1] * pb[1] - pb[2], + pc[0] * pc[0] + pc[1] * pc[1] - pc[2], + pd[0] * pd[0] + pd[1] * pd[1] - pd[2]); + } else { + return orient3d(m, b, pa, pb, pc, pd, pa[2], pb[2], pc[2], pd[2]); + } +} + +/*****************************************************************************/ +/* */ +/* findcircumcenter() Find the circumcenter of a triangle. */ +/* */ +/* The result is returned both in terms of x-y coordinates and xi-eta */ +/* (barycentric) coordinates. The xi-eta coordinate system is defined in */ +/* terms of the triangle: the origin of the triangle is the origin of the */ +/* coordinate system; the destination of the triangle is one unit along the */ +/* xi axis; and the apex of the triangle is one unit along the eta axis. */ +/* This procedure also returns the square of the length of the triangle's */ +/* shortest edge. */ +/* */ +/*****************************************************************************/ + +#ifdef ANSI_DECLARATORS +void findcircumcenter(struct mesh *m, struct behavior *b, + vertex torg, vertex tdest, vertex tapex, + vertex circumcenter, REAL *xi, REAL *eta, REAL *minedge, + int offcenter) +#else /* not ANSI_DECLARATORS */ +void findcircumcenter(m, b, torg, tdest, tapex, circumcenter, xi, eta, minedge, + offcenter) +struct mesh *m; +struct behavior *b; +vertex torg; +vertex tdest; +vertex tapex; +vertex circumcenter; +REAL *xi; +REAL *eta; +REAL *minedge; +int offcenter; +#endif /* not ANSI_DECLARATORS */ + +{ + REAL xdo, ydo, xao, yao; + REAL dodist, aodist, dadist; + REAL denominator; + REAL dx, dy, dxoff, dyoff; + + m->circumcentercount++; + + /* Compute the circumcenter of the triangle. */ + xdo = tdest[0] - torg[0]; + ydo = tdest[1] - torg[1]; + xao = tapex[0] - torg[0]; + yao = tapex[1] - torg[1]; + dodist = xdo * xdo + ydo * ydo; + aodist = xao * xao + yao * yao; + dadist = (tdest[0] - tapex[0]) * (tdest[0] - tapex[0]) + + (tdest[1] - tapex[1]) * (tdest[1] - tapex[1]); + if (b->noexact) { + denominator = 0.5 / (xdo * yao - xao * ydo); + } else { + /* Use the counterclockwise() routine to ensure a positive (and */ + /* reasonably accurate) result, avoiding any possibility of */ + /* division by zero. */ + denominator = 0.5 / counterclockwise(m, b, tdest, tapex, torg); + /* Don't count the above as an orientation test. */ + m->counterclockcount--; + } + dx = (yao * dodist - ydo * aodist) * denominator; + dy = (xdo * aodist - xao * dodist) * denominator; + + /* Find the (squared) length of the triangle's shortest edge. This */ + /* serves as a conservative estimate of the insertion radius of the */ + /* circumcenter's parent. The estimate is used to ensure that */ + /* the algorithm terminates even if very small angles appear in */ + /* the input PSLG. */ + if ((dodist < aodist) && (dodist < dadist)) { + *minedge = dodist; + if (offcenter && (b->offconstant > 0.0)) { + /* Find the position of the off-center, as described by Alper Ungor. */ + dxoff = 0.5 * xdo - b->offconstant * ydo; + dyoff = 0.5 * ydo + b->offconstant * xdo; + /* If the off-center is closer to the origin than the */ + /* circumcenter, use the off-center instead. */ + if (dxoff * dxoff + dyoff * dyoff < dx * dx + dy * dy) { + dx = dxoff; + dy = dyoff; + } + } + } else if (aodist < dadist) { + *minedge = aodist; + if (offcenter && (b->offconstant > 0.0)) { + dxoff = 0.5 * xao + b->offconstant * yao; + dyoff = 0.5 * yao - b->offconstant * xao; + /* If the off-center is closer to the origin than the */ + /* circumcenter, use the off-center instead. */ + if (dxoff * dxoff + dyoff * dyoff < dx * dx + dy * dy) { + dx = dxoff; + dy = dyoff; + } + } + } else { + *minedge = dadist; + if (offcenter && (b->offconstant > 0.0)) { + dxoff = 0.5 * (tapex[0] - tdest[0]) - + b->offconstant * (tapex[1] - tdest[1]); + dyoff = 0.5 * (tapex[1] - tdest[1]) + + b->offconstant * (tapex[0] - tdest[0]); + /* If the off-center is closer to the destination than the */ + /* circumcenter, use the off-center instead. */ + if (dxoff * dxoff + dyoff * dyoff < + (dx - xdo) * (dx - xdo) + (dy - ydo) * (dy - ydo)) { + dx = xdo + dxoff; + dy = ydo + dyoff; + } + } + } + + circumcenter[0] = torg[0] + dx; + circumcenter[1] = torg[1] + dy; + + /* To interpolate vertex attributes for the new vertex inserted at */ + /* the circumcenter, define a coordinate system with a xi-axis, */ + /* directed from the triangle's origin to its destination, and */ + /* an eta-axis, directed from its origin to its apex. */ + /* Calculate the xi and eta coordinates of the circumcenter. */ + *xi = (yao * dx - xao * dy) * (2.0 * denominator); + *eta = (xdo * dy - ydo * dx) * (2.0 * denominator); +} + +/** **/ +/** **/ +/********* Geometric primitives end here *********/ + +/*****************************************************************************/ +/* */ +/* triangleinit() Initialize some variables. */ +/* */ +/*****************************************************************************/ + +#ifdef ANSI_DECLARATORS +void triangleinit(struct mesh *m) +#else /* not ANSI_DECLARATORS */ +void triangleinit(m) +struct mesh *m; +#endif /* not ANSI_DECLARATORS */ + +{ + m->vertices.maxitems = m->triangles.maxitems = m->subsegs.maxitems = + m->viri.maxitems = m->badsubsegs.maxitems = m->badtriangles.maxitems = + m->flipstackers.maxitems = m->splaynodes.maxitems = 0l; + m->vertices.itembytes = m->triangles.itembytes = m->subsegs.itembytes = + m->viri.itembytes = m->badsubsegs.itembytes = m->badtriangles.itembytes = + m->flipstackers.itembytes = m->splaynodes.itembytes = 0; + m->recenttri.tri = (triangle *) NULL; /* No triangle has been visited yet. */ + m->undeads = 0; /* No eliminated input vertices yet. */ + m->samples = 1; /* Point location should take at least one sample. */ + m->checksegments = 0; /* There are no segments in the triangulation yet. */ + m->checkquality = 0; /* The quality triangulation stage has not begun. */ + m->incirclecount = m->counterclockcount = m->orient3dcount = 0; + m->hyperbolacount = m->circletopcount = m->circumcentercount = 0; + randomseed = 1; + + exactinit(); /* Initialize exact arithmetic constants. */ +} + +/*****************************************************************************/ +/* */ +/* randomnation() Generate a random number between 0 and `choices' - 1. */ +/* */ +/* This is a simple linear congruential random number generator. Hence, it */ +/* is a bad random number generator, but good enough for most randomized */ +/* geometric algorithms. */ +/* */ +/*****************************************************************************/ + +#ifdef ANSI_DECLARATORS +unsigned long randomnation(unsigned int choices) +#else /* not ANSI_DECLARATORS */ +unsigned long randomnation(choices) +unsigned int choices; +#endif /* not ANSI_DECLARATORS */ + +{ + randomseed = (randomseed * 1366l + 150889l) % 714025l; + return randomseed / (714025l / choices + 1); +} + +/********* Mesh quality testing routines begin here *********/ +/** **/ +/** **/ + +/*****************************************************************************/ +/* */ +/* checkmesh() Test the mesh for topological consistency. */ +/* */ +/*****************************************************************************/ + +#ifndef REDUCED + +#ifdef ANSI_DECLARATORS +void checkmesh(struct mesh *m, struct behavior *b) +#else /* not ANSI_DECLARATORS */ +void checkmesh(m, b) +struct mesh *m; +struct behavior *b; +#endif /* not ANSI_DECLARATORS */ + +{ + struct otri triangleloop; + struct otri oppotri, oppooppotri; + vertex triorg, tridest, triapex; + vertex oppoorg, oppodest; + int horrors; + int saveexact; + triangle ptr; /* Temporary variable used by sym(). */ + + /* Temporarily turn on exact arithmetic if it's off. */ + saveexact = b->noexact; + b->noexact = 0; + if (!b->quiet) { + printf(" Checking consistency of mesh...\n"); + } + horrors = 0; + /* Run through the list of triangles, checking each one. */ + traversalinit(&m->triangles); + triangleloop.tri = triangletraverse(m); + while (triangleloop.tri != (triangle *) NULL) { + /* Check all three edges of the triangle. */ + for (triangleloop.orient = 0; triangleloop.orient < 3; + triangleloop.orient++) { + org(triangleloop, triorg); + dest(triangleloop, tridest); + if (triangleloop.orient == 0) { /* Only test for inversion once. */ + /* Test if the triangle is flat or inverted. */ + apex(triangleloop, triapex); + if (counterclockwise(m, b, triorg, tridest, triapex) <= 0.0) { + printf(" !! !! Inverted "); + printtriangle(m, b, &triangleloop); + horrors++; + } + } + /* Find the neighboring triangle on this edge. */ + sym(triangleloop, oppotri); + if (oppotri.tri != m->dummytri) { + /* Check that the triangle's neighbor knows it's a neighbor. */ + sym(oppotri, oppooppotri); + if ((triangleloop.tri != oppooppotri.tri) + || (triangleloop.orient != oppooppotri.orient)) { + printf(" !! !! Asymmetric triangle-triangle bond:\n"); + if (triangleloop.tri == oppooppotri.tri) { + printf(" (Right triangle, wrong orientation)\n"); + } + printf(" First "); + printtriangle(m, b, &triangleloop); + printf(" Second (nonreciprocating) "); + printtriangle(m, b, &oppotri); + horrors++; + } + /* Check that both triangles agree on the identities */ + /* of their shared vertices. */ + org(oppotri, oppoorg); + dest(oppotri, oppodest); + if ((triorg != oppodest) || (tridest != oppoorg)) { + printf(" !! !! Mismatched edge coordinates between two triangles:\n" + ); + printf(" First mismatched "); + printtriangle(m, b, &triangleloop); + printf(" Second mismatched "); + printtriangle(m, b, &oppotri); + horrors++; + } + } + } + triangleloop.tri = triangletraverse(m); + } + if (horrors == 0) { + if (!b->quiet) { + printf(" In my studied opinion, the mesh appears to be consistent.\n"); + } + } else if (horrors == 1) { + printf(" !! !! !! !! Precisely one festering wound discovered.\n"); + } else { + printf(" !! !! !! !! %d abominations witnessed.\n", horrors); + } + /* Restore the status of exact arithmetic. */ + b->noexact = saveexact; +} + +#endif /* not REDUCED */ + +/*****************************************************************************/ +/* */ +/* checkdelaunay() Ensure that the mesh is (constrained) Delaunay. */ +/* */ +/*****************************************************************************/ + +#ifndef REDUCED + +#ifdef ANSI_DECLARATORS +void checkdelaunay(struct mesh *m, struct behavior *b) +#else /* not ANSI_DECLARATORS */ +void checkdelaunay(m, b) +struct mesh *m; +struct behavior *b; +#endif /* not ANSI_DECLARATORS */ + +{ + struct otri triangleloop; + struct otri oppotri; + struct osub opposubseg; + vertex triorg, tridest, triapex; + vertex oppoapex; + int shouldbedelaunay; + int horrors; + int saveexact; + triangle ptr; /* Temporary variable used by sym(). */ + subseg sptr; /* Temporary variable used by tspivot(). */ + + /* Temporarily turn on exact arithmetic if it's off. */ + saveexact = b->noexact; + b->noexact = 0; + if (!b->quiet) { + printf(" Checking Delaunay property of mesh...\n"); + } + horrors = 0; + /* Run through the list of triangles, checking each one. */ + traversalinit(&m->triangles); + triangleloop.tri = triangletraverse(m); + while (triangleloop.tri != (triangle *) NULL) { + /* Check all three edges of the triangle. */ + for (triangleloop.orient = 0; triangleloop.orient < 3; + triangleloop.orient++) { + org(triangleloop, triorg); + dest(triangleloop, tridest); + apex(triangleloop, triapex); + sym(triangleloop, oppotri); + apex(oppotri, oppoapex); + /* Only test that the edge is locally Delaunay if there is an */ + /* adjoining triangle whose pointer is larger (to ensure that */ + /* each pair isn't tested twice). */ + shouldbedelaunay = (oppotri.tri != m->dummytri) && + !deadtri(oppotri.tri) && (triangleloop.tri < oppotri.tri) && + (triorg != m->infvertex1) && (triorg != m->infvertex2) && + (triorg != m->infvertex3) && + (tridest != m->infvertex1) && (tridest != m->infvertex2) && + (tridest != m->infvertex3) && + (triapex != m->infvertex1) && (triapex != m->infvertex2) && + (triapex != m->infvertex3) && + (oppoapex != m->infvertex1) && (oppoapex != m->infvertex2) && + (oppoapex != m->infvertex3); + if (m->checksegments && shouldbedelaunay) { + /* If a subsegment separates the triangles, then the edge is */ + /* constrained, so no local Delaunay test should be done. */ + tspivot(triangleloop, opposubseg); + if (opposubseg.ss != m->dummysub){ + shouldbedelaunay = 0; + } + } + if (shouldbedelaunay) { + if (nonregular(m, b, triorg, tridest, triapex, oppoapex) > 0.0) { + if (!b->weighted) { + printf(" !! !! Non-Delaunay pair of triangles:\n"); + printf(" First non-Delaunay "); + printtriangle(m, b, &triangleloop); + printf(" Second non-Delaunay "); + } else { + printf(" !! !! Non-regular pair of triangles:\n"); + printf(" First non-regular "); + printtriangle(m, b, &triangleloop); + printf(" Second non-regular "); + } + printtriangle(m, b, &oppotri); + horrors++; + } + } + } + triangleloop.tri = triangletraverse(m); + } + if (horrors == 0) { + if (!b->quiet) { + printf( + " By virtue of my perceptive intelligence, I declare the mesh Delaunay.\n"); + } + } else if (horrors == 1) { + printf( + " !! !! !! !! Precisely one terrifying transgression identified.\n"); + } else { + printf(" !! !! !! !! %d obscenities viewed with horror.\n", horrors); + } + /* Restore the status of exact arithmetic. */ + b->noexact = saveexact; +} + +#endif /* not REDUCED */ + +/*****************************************************************************/ +/* */ +/* enqueuebadtriang() Add a bad triangle data structure to the end of a */ +/* queue. */ +/* */ +/* The queue is actually a set of 64 queues. I use multiple queues to give */ +/* priority to smaller angles. I originally implemented a heap, but the */ +/* queues are faster by a larger margin than I'd suspected. */ +/* */ +/*****************************************************************************/ + +#ifndef CDT_ONLY + +#ifdef ANSI_DECLARATORS +void enqueuebadtriang(struct mesh *m, struct behavior *b, + struct badtriang *badtri) +#else /* not ANSI_DECLARATORS */ +void enqueuebadtriang(m, b, badtri) +struct mesh *m; +struct behavior *b; +struct badtriang *badtri; +#endif /* not ANSI_DECLARATORS */ + +{ + int queuenumber; + int i; + + if (b->verbose > 2) { + printf(" Queueing bad triangle:\n"); + printf(" (%.12g, %.12g) (%.12g, %.12g) (%.12g, %.12g)\n", + badtri->triangorg[0], badtri->triangorg[1], + badtri->triangdest[0], badtri->triangdest[1], + badtri->triangapex[0], badtri->triangapex[1]); + } + /* Determine the appropriate queue to put the bad triangle into. */ + if (badtri->key > 0.6) { + queuenumber = (int) (160.0 * (badtri->key - 0.6)); + if (queuenumber > 63) { + queuenumber = 63; + } + } else { + /* It's not a bad angle; put the triangle in the lowest-priority queue. */ + queuenumber = 0; + } + + /* Are we inserting into an empty queue? */ + if (m->queuefront[queuenumber] == (struct badtriang *) NULL) { + /* Yes, we are inserting into an empty queue. */ + /* Will this become the highest-priority queue? */ + if (queuenumber > m->firstnonemptyq) { + /* Yes, this is the highest-priority queue. */ + m->nextnonemptyq[queuenumber] = m->firstnonemptyq; + m->firstnonemptyq = queuenumber; + } else { + /* No, this is not the highest-priority queue. */ + /* Find the queue with next higher priority. */ + i = queuenumber + 1; + while (m->queuefront[i] == (struct badtriang *) NULL) { + i++; + } + /* Mark the newly nonempty queue as following a higher-priority queue. */ + m->nextnonemptyq[queuenumber] = m->nextnonemptyq[i]; + m->nextnonemptyq[i] = queuenumber; + } + /* Put the bad triangle at the beginning of the (empty) queue. */ + m->queuefront[queuenumber] = badtri; + } else { + /* Add the bad triangle to the end of an already nonempty queue. */ + m->queuetail[queuenumber]->nexttriang = badtri; + } + /* Maintain a pointer to the last triangle of the queue. */ + m->queuetail[queuenumber] = badtri; + /* Newly enqueued bad triangle has no successor in the queue. */ + badtri->nexttriang = (struct badtriang *) NULL; +} + +#endif /* not CDT_ONLY */ + +/*****************************************************************************/ +/* */ +/* enqueuebadtri() Add a bad triangle to the end of a queue. */ +/* */ +/* Allocates a badtriang data structure for the triangle, then passes it to */ +/* enqueuebadtriang(). */ +/* */ +/*****************************************************************************/ + +#ifndef CDT_ONLY + +#ifdef ANSI_DECLARATORS +void enqueuebadtri(struct mesh *m, struct behavior *b, struct otri *enqtri, + REAL angle, vertex enqapex, vertex enqorg, vertex enqdest) +#else /* not ANSI_DECLARATORS */ +void enqueuebadtri(m, b, enqtri, angle, enqapex, enqorg, enqdest) +struct mesh *m; +struct behavior *b; +struct otri *enqtri; +REAL angle; +vertex enqapex; +vertex enqorg; +vertex enqdest; +#endif /* not ANSI_DECLARATORS */ + +{ + struct badtriang *newbad; + + /* Allocate space for the bad triangle. */ + newbad = (struct badtriang *) poolalloc(&m->badtriangles); + newbad->poortri = encode(*enqtri); + newbad->key = angle; + newbad->triangapex = enqapex; + newbad->triangorg = enqorg; + newbad->triangdest = enqdest; + enqueuebadtriang(m, b, newbad); +} + +#endif /* not CDT_ONLY */ + +/*****************************************************************************/ +/* */ +/* dequeuebadtriang() Remove a triangle from the front of the queue. */ +/* */ +/*****************************************************************************/ + +#ifndef CDT_ONLY + +#ifdef ANSI_DECLARATORS +struct badtriang *dequeuebadtriang(struct mesh *m) +#else /* not ANSI_DECLARATORS */ +struct badtriang *dequeuebadtriang(m) +struct mesh *m; +#endif /* not ANSI_DECLARATORS */ + +{ + struct badtriang *result; + + /* If no queues are nonempty, return NULL. */ + if (m->firstnonemptyq < 0) { + return (struct badtriang *) NULL; + } + /* Find the first triangle of the highest-priority queue. */ + result = m->queuefront[m->firstnonemptyq]; + /* Remove the triangle from the queue. */ + m->queuefront[m->firstnonemptyq] = result->nexttriang; + /* If this queue is now empty, note the new highest-priority */ + /* nonempty queue. */ + if (result == m->queuetail[m->firstnonemptyq]) { + m->firstnonemptyq = m->nextnonemptyq[m->firstnonemptyq]; + } + return result; +} + +#endif /* not CDT_ONLY */ + +/*****************************************************************************/ +/* */ +/* under60degrees() Return 1 if the two incident input segments are */ +/* separated by an angle less than 60 degrees; */ +/* 0 otherwise. */ +/* */ +/* The two input segments MUST have the same origin. */ +/* */ +/*****************************************************************************/ + +#ifndef CDT_ONLY + +int under60degrees(struct osub *sub1, struct osub *sub2) { + vertex segmentapex, v1, v2; + REAL dotprod; + + sorg(*sub1, segmentapex); + sdest(*sub1, v1); + sdest(*sub2, v2); + dotprod = (v2[0] - segmentapex[0]) * (v1[0] - segmentapex[0]) + + (v2[1] - segmentapex[1]) * (v1[1] - segmentapex[1]); + return (dotprod > 0.0) && + (4.0 * dotprod * dotprod > + ((v1[0] - segmentapex[0]) * (v1[0] - segmentapex[0]) + + (v1[1] - segmentapex[1]) * (v1[1] - segmentapex[1])) * + ((v2[0] - segmentapex[0]) * (v2[0] - segmentapex[0]) + + (v2[1] - segmentapex[1]) * (v2[1] - segmentapex[1]))); +} + +#endif /* not CDT_ONLY */ + +/*****************************************************************************/ +/* */ +/* clockwiseseg() Find the next segment clockwise from `thissub' having */ +/* the same origin and return it as `nextsub' if the */ +/* intervening region is inside the domain. */ +/* */ +/* Returns 1 if the next segment is separated from `thissub' by less than */ +/* 60 degrees, and the intervening region is inside the domain. */ +/* */ +/*****************************************************************************/ + +#ifndef CDT_ONLY + +int clockwiseseg(struct mesh *m, struct osub *thissub, struct osub *nextsub) { + struct otri neighbortri; + triangle ptr; /* Temporary variable used by sym() and stpivot(). */ + subseg sptr; /* Temporary variable used by tspivot(). */ + + stpivot(*thissub, neighbortri); + if (neighbortri.tri == m->dummytri) { + return 0; + } else { + lnextself(neighbortri); + tspivot(neighbortri, *nextsub); + while (nextsub->ss == m->dummysub) { + symself(neighbortri); + lnextself(neighbortri); + tspivot(neighbortri, *nextsub); + } + ssymself(*nextsub); + return under60degrees(thissub, nextsub); + } +} + +#endif /* not CDT_ONLY */ + +/*****************************************************************************/ +/* */ +/* counterclockwiseseg() Find the next segment counterclockwise from */ +/* `thissub' having the same origin and return it */ +/* as `nextsub' if the intervening region is inside */ +/* the domain. */ +/* */ +/* Returns 1 if the next segment is separated from `thissub' by less than */ +/* 60 degrees, and the intervening region is inside the domain. */ +/* */ +/*****************************************************************************/ + +#ifndef CDT_ONLY + +int counterclockwiseseg(struct mesh *m, struct osub *thissub, + struct osub *nextsub) { + struct otri neighbortri; + struct osub subsym; + triangle ptr; /* Temporary variable used by sym() and stpivot(). */ + subseg sptr; /* Temporary variable used by tspivot(). */ + + ssym(*thissub, subsym); + stpivot(subsym, neighbortri); + if (neighbortri.tri == m->dummytri) { + return 0; + } else { + lprevself(neighbortri); + tspivot(neighbortri, *nextsub); + while (nextsub->ss == m->dummysub) { + symself(neighbortri); + lprevself(neighbortri); + tspivot(neighbortri, *nextsub); + } + return under60degrees(thissub, nextsub); + } +} + +#endif /* not CDT_ONLY */ + +#ifndef CDT_ONLY + +/*****************************************************************************/ +/* */ +/* splitpermitted() Return 1 if `testsubseg' is part of a subsegment */ +/* cluster that is eligible for splitting. */ +/* */ +/* The term "subsegment cluster" is formally defined in my paper "Mesh */ +/* Generation for Domains with Small Angles." The algorithm that uses this */ +/* procedure is also described there. */ +/* */ +/* A subsegment cluster is eligible for splitting if (1) it includes a */ +/* subsegment whose length is not a power of two, (2) its subsegments are */ +/* not all the same length, or (3) no new edge that will be created by */ +/* splitting all the subsegments in the cluster has a length shorter than */ +/* the insertion radius of the encroaching vertex, whose square is given */ +/* as the parameter `iradius'. Note that the shortest edges created by */ +/* splitting a cluster are those whose endpoints are both subsegment */ +/* midpoints introduced when the cluster is split. */ +/* */ +/* `testsubseg' is also eligible for splitting (and a 1 will be returned) */ +/* if it is part of two subsegment clusters; one at its origin and one at */ +/* its destination. */ +/* */ +/*****************************************************************************/ + +int splitpermitted(struct mesh *m, struct osub *testsubseg, REAL iradius) { + struct osub cwsubseg, ccwsubseg, cwsubseg2, ccwsubseg2; + struct osub testsym; + struct osub startsubseg, nowsubseg; + vertex suborg, dest1, dest2; + REAL nearestpoweroffour, seglength, prevseglength, edgelength; + int cwsmall, ccwsmall, cwsmall2, ccwsmall2; + int orgcluster, destcluster; + int toosmall; + + /* Find the square of the subsegment's length, and the nearest power of */ + /* four (which is the square of the nearest power of two to the */ + /* subsegment's length). */ + sorg(*testsubseg, suborg); + sdest(*testsubseg, dest1); + seglength = (dest1[0] - suborg[0]) * (dest1[0] - suborg[0]) + + (dest1[1] - suborg[1]) * (dest1[1] - suborg[1]); + nearestpoweroffour = 1.0; + while (seglength > 2.0 * nearestpoweroffour) { + nearestpoweroffour *= 4.0; + } + while (seglength < 0.5 * nearestpoweroffour) { + nearestpoweroffour *= 0.25; + } + /* If the segment's length is not a power of two, the segment */ + /* is eligible for splitting. */ + if ((nearestpoweroffour > 1.001 * seglength) || + (nearestpoweroffour < 0.999 * seglength)) { + return 1; + } + + /* Is `testsubseg' part of a subsegment cluster at its origin? */ + cwsmall = clockwiseseg(m, testsubseg, &cwsubseg); + ccwsmall = cwsmall ? 0 : counterclockwiseseg(m, testsubseg, &ccwsubseg); + orgcluster = cwsmall || ccwsmall; + + /* Is `testsubseg' part of a subsegment cluster at its destination? */ + ssym(*testsubseg, testsym); + cwsmall2 = clockwiseseg(m, &testsym, &cwsubseg2); + ccwsmall2 = cwsmall2 ? 0 : counterclockwiseseg(m, &testsym, &ccwsubseg2); + destcluster = cwsmall2 || ccwsmall2; + + if (orgcluster == destcluster) { + /* `testsubseg' is part of two clusters or none, */ + /* and thus should be split. */ + return 1; + } else if (orgcluster) { + /* `testsubseg' is part of a cluster at its origin. */ + subsegcopy(*testsubseg, startsubseg); + } else { + /* `testsubseg' is part of a cluster at its destination; switch to */ + /* the symmetric case, so we can use the same code to handle it. */ + subsegcopy(testsym, startsubseg); + subsegcopy(cwsubseg2, cwsubseg); + subsegcopy(ccwsubseg2, ccwsubseg); + cwsmall = cwsmall2; + ccwsmall = ccwsmall2; + } + + toosmall = 0; + if (cwsmall) { + /* Check the subsegment(s) clockwise from `testsubseg'. */ + subsegcopy(startsubseg, nowsubseg); + sorg(nowsubseg, suborg); + sdest(nowsubseg, dest1); + prevseglength = nearestpoweroffour; + do { + /* Is the next subsegment shorter than `startsubseg'? */ + sdest(cwsubseg, dest2); + seglength = (dest2[0] - suborg[0]) * (dest2[0] - suborg[0]) + + (dest2[1] - suborg[1]) * (dest2[1] - suborg[1]); + if (nearestpoweroffour > 1.001 * seglength) { + /* It's shorter; it's safe to split `startsubseg'. */ + return 1; + } + /* If the current and previous subsegments are split to a length */ + /* half that of `startsubseg' (which is a likely consequence if */ + /* `startsubseg' is split), what will be (the square of) the */ + /* length of the free edge between the splitting vertices? */ + edgelength = 0.5 * nearestpoweroffour * + (1 - (((dest1[0] - suborg[0]) * (dest2[0] - suborg[0]) + + (dest1[1] - suborg[1]) * (dest2[1] - suborg[1])) / + sqrt(prevseglength * seglength))); + if (edgelength < iradius) { + /* If this cluster is split, the new edge dest1-dest2 will be */ + /* smaller than the insertion radius of the encroaching vertex. */ + /* Hence, we'd prefer to avoid splitting it if possible. */ + toosmall = 1; + } + if (cwsubseg.ss == startsubseg.ss) { + /* We've gone all the way around the vertex. Split the cluster */ + /* if no edges will be too short. */ + return !toosmall; + } + + /* Find the next subsegment clockwise around the vertex. */ + subsegcopy(cwsubseg, nowsubseg); + dest1 = dest2; + prevseglength = seglength; + cwsmall = clockwiseseg(m, &nowsubseg, &cwsubseg); + } while (cwsmall); + + /* Prepare to start searching counterclockwise from */ + /* the starting subsegment. */ + ccwsmall = counterclockwiseseg(m, &startsubseg, &ccwsubseg); + } + + if (ccwsmall) { + /* Check the subsegment(s) counterclockwise from `testsubseg'. */ + subsegcopy(startsubseg, nowsubseg); + sorg(nowsubseg, suborg); + sdest(nowsubseg, dest1); + prevseglength = nearestpoweroffour; + do { + /* Is the next subsegment shorter than `startsubseg'? */ + sdest(ccwsubseg, dest2); + seglength = (dest2[0] - suborg[0]) * (dest2[0] - suborg[0]) + + (dest2[1] - suborg[1]) * (dest2[1] - suborg[1]); + if (nearestpoweroffour > 1.001 * seglength) { + /* It's shorter; it's safe to split `startsubseg'. */ + return 1; + } + /* half that of `startsubseg' (which is a likely consequence if */ + /* `startsubseg' is split), what will be (the square of) the */ + /* length of the free edge between the splitting vertices? */ + edgelength = 0.5 * nearestpoweroffour * + (1 - (((dest1[0] - suborg[0]) * (dest2[0] - suborg[0]) + + (dest1[1] - suborg[1]) * (dest2[1] - suborg[1])) / + sqrt(prevseglength * seglength))); + if (edgelength < iradius) { + /* If this cluster is split, the new edge dest1-dest2 will be */ + /* smaller than the insertion radius of the encroaching vertex. */ + /* Hence, we'd prefer to avoid splitting it if possible. */ + toosmall = 1; + } + if (ccwsubseg.ss == startsubseg.ss) { + /* We've gone all the way around the vertex. Split the cluster */ + /* if no edges will be too short. */ + return !toosmall; + } + + /* Find the next subsegment counterclockwise around the vertex. */ + subsegcopy(ccwsubseg, nowsubseg); + dest1 = dest2; + prevseglength = seglength; + ccwsmall = counterclockwiseseg(m, &nowsubseg, &ccwsubseg); + } while (ccwsmall); + } + + /* We've found every subsegment in the cluster. Split the cluster */ + /* if no edges will be too short. */ + return !toosmall; +} + +#endif /* not CDT_ONLY */ + +/*****************************************************************************/ +/* */ +/* checkseg4encroach() Check a subsegment to see if it is encroached; add */ +/* it to the list if it is. */ +/* */ +/* A subsegment is encroached if there is a vertex in its diametral circle */ +/* (that is, the subsegment faces an angle greater than 90 degrees). This */ +/* definition is due to Ruppert. */ +/* */ +/* Returns a nonzero value if the subsegment is encroached. */ +/* */ +/*****************************************************************************/ + +#ifndef CDT_ONLY + +#ifdef ANSI_DECLARATORS +int checkseg4encroach(struct mesh *m, struct behavior *b, + struct osub *testsubseg, REAL iradius) +#else /* not ANSI_DECLARATORS */ +int checkseg4encroach(m, b, testsubseg, iradius) +struct mesh *m; +struct behavior *b; +struct osub *testsubseg; +REAL iradius; +#endif /* not ANSI_DECLARATORS */ + +{ + struct otri neighbortri; + struct osub testsym; + struct badsubseg *encroachedseg; + REAL dotproduct; + int encroached; + int sides; + int enq; + vertex eorg, edest, eapex; + triangle ptr; /* Temporary variable used by stpivot(). */ + + encroached = 0; + sides = 0; + + sorg(*testsubseg, eorg); + sdest(*testsubseg, edest); + /* Check one neighbor of the subsegment. */ + stpivot(*testsubseg, neighbortri); + /* Does the neighbor exist, or is this a boundary edge? */ + if (neighbortri.tri != m->dummytri) { + sides++; + /* Find a vertex opposite this subsegment. */ + apex(neighbortri, eapex); + /* Check whether the apex is in the diametral lens of the subsegment */ + /* (or the diametral circle, if `nolenses' is set). A dot product */ + /* of two sides of the triangle is used to check whether the angle */ + /* at the apex is greater than 120 degrees (for lenses; 90 degrees */ + /* for diametral circles). */ + dotproduct = (eorg[0] - eapex[0]) * (edest[0] - eapex[0]) + + (eorg[1] - eapex[1]) * (edest[1] - eapex[1]); + if (dotproduct < 0.0) { + if (b->nolenses || + (dotproduct * dotproduct >= + 0.25 * ((eorg[0] - eapex[0]) * (eorg[0] - eapex[0]) + + (eorg[1] - eapex[1]) * (eorg[1] - eapex[1])) * + ((edest[0] - eapex[0]) * (edest[0] - eapex[0]) + + (edest[1] - eapex[1]) * (edest[1] - eapex[1])))) { + encroached = 1; + } + } + } + /* Check the other neighbor of the subsegment. */ + ssym(*testsubseg, testsym); + stpivot(testsym, neighbortri); + /* Does the neighbor exist, or is this a boundary edge? */ + if (neighbortri.tri != m->dummytri) { + sides++; + /* Find the other vertex opposite this subsegment. */ + apex(neighbortri, eapex); + /* Check whether the apex is in the diametral lens of the subsegment */ + /* (or the diametral circle, if `nolenses' is set). */ + dotproduct = (eorg[0] - eapex[0]) * (edest[0] - eapex[0]) + + (eorg[1] - eapex[1]) * (edest[1] - eapex[1]); + if (dotproduct < 0.0) { + if (b->nolenses || + (dotproduct * dotproduct >= + 0.25 * ((eorg[0] - eapex[0]) * (eorg[0] - eapex[0]) + + (eorg[1] - eapex[1]) * (eorg[1] - eapex[1])) * + ((edest[0] - eapex[0]) * (edest[0] - eapex[0]) + + (edest[1] - eapex[1]) * (edest[1] - eapex[1])))) { + encroached += 2; + } + } + } + + if (encroached && (!b->nobisect || ((b->nobisect == 1) && (sides == 2)))) { + /* Decide whether `testsubseg' should be split. */ + if (iradius > 0.0) { + /* The encroaching vertex is a triangle circumcenter, which will be */ + /* rejected. Hence, `testsubseg' probably should be split, unless */ + /* it is part of a subsegment cluster which, according to the rules */ + /* described in my paper "Mesh Generation for Domains with Small */ + /* Angles," should not be split. */ + enq = splitpermitted(m, testsubseg, iradius); + } else { + /* The encroaching vertex is an input vertex or was inserted in a */ + /* subsegment, so the encroached subsegment must be split. */ + enq = 1; + } + if (enq) { + if (b->verbose > 2) { + printf( + " Queueing encroached subsegment (%.12g, %.12g) (%.12g, %.12g).\n", + eorg[0], eorg[1], edest[0], edest[1]); + } + /* Add the subsegment to the list of encroached subsegments. */ + /* Be sure to get the orientation right. */ + encroachedseg = (struct badsubseg *) poolalloc(&m->badsubsegs); + if (encroached == 1) { + encroachedseg->encsubseg = sencode(*testsubseg); + encroachedseg->subsegorg = eorg; + encroachedseg->subsegdest = edest; + } else { + encroachedseg->encsubseg = sencode(testsym); + encroachedseg->subsegorg = edest; + encroachedseg->subsegdest = eorg; + } + } + } + + return encroached; +} + +#endif /* not CDT_ONLY */ + +/*****************************************************************************/ +/* */ +/* testtriangle() Test a face for quality measures. */ +/* */ +/* Tests a triangle to see if it satisfies the minimum angle condition and */ +/* the maximum area condition. Triangles that aren't up to spec are added */ +/* to the bad triangle queue. */ +/* */ +/*****************************************************************************/ + +#ifndef CDT_ONLY + +#ifdef ANSI_DECLARATORS +void testtriangle(struct mesh *m, struct behavior *b, struct otri *testtri) +#else /* not ANSI_DECLARATORS */ +void testtriangle(m, b, testtri) +struct mesh *m; +struct behavior *b; +struct otri *testtri; +#endif /* not ANSI_DECLARATORS */ + +{ + struct otri sametesttri; + struct osub subseg1, subseg2; + vertex torg, tdest, tapex; + vertex anglevertex; + REAL dxod, dyod, dxda, dyda, dxao, dyao; + REAL dxod2, dyod2, dxda2, dyda2, dxao2, dyao2; + REAL apexlen, orglen, destlen; + REAL angle; + REAL area; + subseg sptr; /* Temporary variable used by tspivot(). */ + + org(*testtri, torg); + dest(*testtri, tdest); + apex(*testtri, tapex); + dxod = torg[0] - tdest[0]; + dyod = torg[1] - tdest[1]; + dxda = tdest[0] - tapex[0]; + dyda = tdest[1] - tapex[1]; + dxao = tapex[0] - torg[0]; + dyao = tapex[1] - torg[1]; + dxod2 = dxod * dxod; + dyod2 = dyod * dyod; + dxda2 = dxda * dxda; + dyda2 = dyda * dyda; + dxao2 = dxao * dxao; + dyao2 = dyao * dyao; + /* Find the lengths of the triangle's three edges. */ + apexlen = dxod2 + dyod2; + orglen = dxda2 + dyda2; + destlen = dxao2 + dyao2; + if ((apexlen < orglen) && (apexlen < destlen)) { + /* The edge opposite the apex is shortest. */ + /* Find the square of the cosine of the angle at the apex. */ + angle = dxda * dxao + dyda * dyao; + angle = angle * angle / (orglen * destlen); + anglevertex = tapex; + lnext(*testtri, sametesttri); + tspivot(sametesttri, subseg1); + lnextself(sametesttri); + tspivot(sametesttri, subseg2); + } else if (orglen < destlen) { + /* The edge opposite the origin is shortest. */ + /* Find the square of the cosine of the angle at the origin. */ + angle = dxod * dxao + dyod * dyao; + angle = angle * angle / (apexlen * destlen); + anglevertex = torg; + tspivot(*testtri, subseg1); + lprev(*testtri, sametesttri); + tspivot(sametesttri, subseg2); + } else { + /* The edge opposite the destination is shortest. */ + /* Find the square of the cosine of the angle at the destination. */ + angle = dxod * dxda + dyod * dyda; + angle = angle * angle / (apexlen * orglen); + anglevertex = tdest; + tspivot(*testtri, subseg1); + lnext(*testtri, sametesttri); + tspivot(sametesttri, subseg2); + } + + /* Check if both edges that form the angle are segments. */ + if ((subseg1.ss != m->dummysub) && (subseg2.ss != m->dummysub)) { + /* The angle is a segment intersection. Don't add this bad triangle to */ + /* the list; there's nothing that can be done about a small angle */ + /* between two segments. */ + angle = 0.0; + } + + /* Check whether the angle is smaller than permitted. */ + if (angle > b->goodangle) { + /* Add this triangle to the list of bad triangles. */ + enqueuebadtri(m, b, testtri, angle, tapex, torg, tdest); + return; + } + + if (b->vararea || b->fixedarea || b->usertest) { + /* Check whether the area is larger than permitted. */ + area = 0.5 * (dxod * dyda - dyod * dxda); + if (b->fixedarea && (area > b->maxarea)) { + /* Add this triangle to the list of bad triangles. */ + enqueuebadtri(m, b, testtri, angle, tapex, torg, tdest); + return; + } + + /* Nonpositive area constraints are treated as unconstrained. */ + if ((b->vararea) && (area > areabound(*testtri)) && + (areabound(*testtri) > 0.0)) { + /* Add this triangle to the list of bad triangles. */ + enqueuebadtri(m, b, testtri, angle, tapex, torg, tdest); + return; + } + + if (b->usertest) { + /* Check whether the user thinks this triangle is too large. */ + if (triunsuitable(torg, tdest, tapex, area)) { + enqueuebadtri(m, b, testtri, angle, tapex, torg, tdest); + return; + } + } + } +} + +#endif /* not CDT_ONLY */ + +/** **/ +/** **/ +/********* Mesh quality testing routines end here *********/ + +/********* Point location routines begin here *********/ +/** **/ +/** **/ + +/*****************************************************************************/ +/* */ +/* makevertexmap() Construct a mapping from vertices to triangles to */ +/* improve the speed of point location for segment */ +/* insertion. */ +/* */ +/* Traverses all the triangles, and provides each corner of each triangle */ +/* with a pointer to that triangle. Of course, pointers will be */ +/* overwritten by other pointers because (almost) each vertex is a corner */ +/* of several triangles, but in the end every vertex will point to some */ +/* triangle that contains it. */ +/* */ +/*****************************************************************************/ + +#ifdef ANSI_DECLARATORS +void makevertexmap(struct mesh *m, struct behavior *b) +#else /* not ANSI_DECLARATORS */ +void makevertexmap(m, b) +struct mesh *m; +struct behavior *b; +#endif /* not ANSI_DECLARATORS */ + +{ + struct otri triangleloop; + vertex triorg; + + if (b->verbose) { + printf(" Constructing mapping from vertices to triangles.\n"); + } + traversalinit(&m->triangles); + triangleloop.tri = triangletraverse(m); + while (triangleloop.tri != (triangle *) NULL) { + /* Check all three vertices of the triangle. */ + for (triangleloop.orient = 0; triangleloop.orient < 3; + triangleloop.orient++) { + org(triangleloop, triorg); + setvertex2tri(triorg, encode(triangleloop)); + } + triangleloop.tri = triangletraverse(m); + } +} + +/*****************************************************************************/ +/* */ +/* preciselocate() Find a triangle or edge containing a given point. */ +/* */ +/* Begins its search from `searchtri'. It is important that `searchtri' */ +/* be a handle with the property that `searchpoint' is strictly to the left */ +/* of the edge denoted by `searchtri', or is collinear with that edge and */ +/* does not intersect that edge. (In particular, `searchpoint' should not */ +/* be the origin or destination of that edge.) */ +/* */ +/* These conditions are imposed because preciselocate() is normally used in */ +/* one of two situations: */ +/* */ +/* (1) To try to find the location to insert a new point. Normally, we */ +/* know an edge that the point is strictly to the left of. In the */ +/* incremental Delaunay algorithm, that edge is a bounding box edge. */ +/* In Ruppert's Delaunay refinement algorithm for quality meshing, */ +/* that edge is the shortest edge of the triangle whose circumcenter */ +/* is being inserted. */ +/* */ +/* (2) To try to find an existing point. In this case, any edge on the */ +/* convex hull is a good starting edge. You must screen out the */ +/* possibility that the vertex sought is an endpoint of the starting */ +/* edge before you call preciselocate(). */ +/* */ +/* On completion, `searchtri' is a triangle that contains `searchpoint'. */ +/* */ +/* This implementation differs from that given by Guibas and Stolfi. It */ +/* walks from triangle to triangle, crossing an edge only if `searchpoint' */ +/* is on the other side of the line containing that edge. After entering */ +/* a triangle, there are two edges by which one can leave that triangle. */ +/* If both edges are valid (`searchpoint' is on the other side of both */ +/* edges), one of the two is chosen by drawing a line perpendicular to */ +/* the entry edge (whose endpoints are `forg' and `fdest') passing through */ +/* `fapex'. Depending on which side of this perpendicular `searchpoint' */ +/* falls on, an exit edge is chosen. */ +/* */ +/* This implementation is empirically faster than the Guibas and Stolfi */ +/* point location routine (which I originally used), which tends to spiral */ +/* in toward its target. */ +/* */ +/* Returns ONVERTEX if the point lies on an existing vertex. `searchtri' */ +/* is a handle whose origin is the existing vertex. */ +/* */ +/* Returns ONEDGE if the point lies on a mesh edge. `searchtri' is a */ +/* handle whose primary edge is the edge on which the point lies. */ +/* */ +/* Returns INTRIANGLE if the point lies strictly within a triangle. */ +/* `searchtri' is a handle on the triangle that contains the point. */ +/* */ +/* Returns OUTSIDE if the point lies outside the mesh. `searchtri' is a */ +/* handle whose primary edge the point is to the right of. This might */ +/* occur when the circumcenter of a triangle falls just slightly outside */ +/* the mesh due to floating-point roundoff error. It also occurs when */ +/* seeking a hole or region point that a foolish user has placed outside */ +/* the mesh. */ +/* */ +/* If `stopatsubsegment' is nonzero, the search will stop if it tries to */ +/* walk through a subsegment, and will return OUTSIDE. */ +/* */ +/* WARNING: This routine is designed for convex triangulations, and will */ +/* not generally work after the holes and concavities have been carved. */ +/* However, it can still be used to find the circumcenter of a triangle, as */ +/* long as the search is begun from the triangle in question. */ +/* */ +/*****************************************************************************/ + +#ifdef ANSI_DECLARATORS +enum locateresult preciselocate(struct mesh *m, struct behavior *b, + vertex searchpoint, struct otri *searchtri, + int stopatsubsegment) +#else /* not ANSI_DECLARATORS */ +enum locateresult preciselocate(m, b, searchpoint, searchtri, stopatsubsegment) +struct mesh *m; +struct behavior *b; +vertex searchpoint; +struct otri *searchtri; +int stopatsubsegment; +#endif /* not ANSI_DECLARATORS */ + +{ + struct otri backtracktri; + struct osub checkedge; + vertex forg, fdest, fapex; + REAL orgorient, destorient; + int moveleft; + triangle ptr; /* Temporary variable used by sym(). */ + subseg sptr; /* Temporary variable used by tspivot(). */ + + if (b->verbose > 2) { + printf(" Searching for point (%.12g, %.12g).\n", + searchpoint[0], searchpoint[1]); + } + /* Where are we? */ + org(*searchtri, forg); + dest(*searchtri, fdest); + apex(*searchtri, fapex); + while (1) { + if (b->verbose > 2) { + printf(" At (%.12g, %.12g) (%.12g, %.12g) (%.12g, %.12g)\n", + forg[0], forg[1], fdest[0], fdest[1], fapex[0], fapex[1]); + } + /* Check whether the apex is the point we seek. */ + if ((fapex[0] == searchpoint[0]) && (fapex[1] == searchpoint[1])) { + lprevself(*searchtri); + return ONVERTEX; + } + /* Does the point lie on the other side of the line defined by the */ + /* triangle edge opposite the triangle's destination? */ + destorient = counterclockwise(m, b, forg, fapex, searchpoint); + /* Does the point lie on the other side of the line defined by the */ + /* triangle edge opposite the triangle's origin? */ + orgorient = counterclockwise(m, b, fapex, fdest, searchpoint); + if (destorient > 0.0) { + if (orgorient > 0.0) { + /* Move left if the inner product of (fapex - searchpoint) and */ + /* (fdest - forg) is positive. This is equivalent to drawing */ + /* a line perpendicular to the line (forg, fdest) and passing */ + /* through `fapex', and determining which side of this line */ + /* `searchpoint' falls on. */ + moveleft = (fapex[0] - searchpoint[0]) * (fdest[0] - forg[0]) + + (fapex[1] - searchpoint[1]) * (fdest[1] - forg[1]) > 0.0; + } else { + moveleft = 1; + } + } else { + if (orgorient > 0.0) { + moveleft = 0; + } else { + /* The point we seek must be on the boundary of or inside this */ + /* triangle. */ + if (destorient == 0.0) { + lprevself(*searchtri); + return ONEDGE; + } + if (orgorient == 0.0) { + lnextself(*searchtri); + return ONEDGE; + } + return INTRIANGLE; + } + } + + /* Move to another triangle. Leave a trace `backtracktri' in case */ + /* floating-point roundoff or some such bogey causes us to walk */ + /* off a boundary of the triangulation. */ + if (moveleft) { + lprev(*searchtri, backtracktri); + fdest = fapex; + } else { + lnext(*searchtri, backtracktri); + forg = fapex; + } + sym(backtracktri, *searchtri); + + if (m->checksegments && stopatsubsegment) { + /* Check for walking through a subsegment. */ + tspivot(backtracktri, checkedge); + if (checkedge.ss != m->dummysub) { + /* Go back to the last triangle. */ + otricopy(backtracktri, *searchtri); + return OUTSIDE; + } + } + /* Check for walking right out of the triangulation. */ + if (searchtri->tri == m->dummytri) { + /* Go back to the last triangle. */ + otricopy(backtracktri, *searchtri); + return OUTSIDE; + } + + apex(*searchtri, fapex); + } +} + +/*****************************************************************************/ +/* */ +/* locate() Find a triangle or edge containing a given point. */ +/* */ +/* Searching begins from one of: the input `searchtri', a recently */ +/* encountered triangle `recenttri', or from a triangle chosen from a */ +/* random sample. The choice is made by determining which triangle's */ +/* origin is closest to the point we are searching for. Normally, */ +/* `searchtri' should be a handle on the convex hull of the triangulation. */ +/* */ +/* Details on the random sampling method can be found in the Mucke, Saias, */ +/* and Zhu paper cited in the header of this code. */ +/* */ +/* On completion, `searchtri' is a triangle that contains `searchpoint'. */ +/* */ +/* Returns ONVERTEX if the point lies on an existing vertex. `searchtri' */ +/* is a handle whose origin is the existing vertex. */ +/* */ +/* Returns ONEDGE if the point lies on a mesh edge. `searchtri' is a */ +/* handle whose primary edge is the edge on which the point lies. */ +/* */ +/* Returns INTRIANGLE if the point lies strictly within a triangle. */ +/* `searchtri' is a handle on the triangle that contains the point. */ +/* */ +/* Returns OUTSIDE if the point lies outside the mesh. `searchtri' is a */ +/* handle whose primary edge the point is to the right of. This might */ +/* occur when the circumcenter of a triangle falls just slightly outside */ +/* the mesh due to floating-point roundoff error. It also occurs when */ +/* seeking a hole or region point that a foolish user has placed outside */ +/* the mesh. */ +/* */ +/* WARNING: This routine is designed for convex triangulations, and will */ +/* not generally work after the holes and concavities have been carved. */ +/* */ +/*****************************************************************************/ + +#ifdef ANSI_DECLARATORS +enum locateresult locate(struct mesh *m, struct behavior *b, + vertex searchpoint, struct otri *searchtri) +#else /* not ANSI_DECLARATORS */ +enum locateresult locate(m, b, searchpoint, searchtri) +struct mesh *m; +struct behavior *b; +vertex searchpoint; +struct otri *searchtri; +#endif /* not ANSI_DECLARATORS */ + +{ + VOID **sampleblock; + triangle *firsttri; + struct otri sampletri; + vertex torg, tdest; + unsigned long alignptr; + REAL searchdist, dist; + REAL ahead; + long sampleblocks, samplesperblock, samplenum; + long triblocks; + long i, j; + triangle ptr; /* Temporary variable used by sym(). */ + + if (b->verbose > 2) { + printf(" Randomly sampling for a triangle near point (%.12g, %.12g).\n", + searchpoint[0], searchpoint[1]); + } + /* Record the distance from the suggested starting triangle to the */ + /* point we seek. */ + org(*searchtri, torg); + searchdist = (searchpoint[0] - torg[0]) * (searchpoint[0] - torg[0]) + + (searchpoint[1] - torg[1]) * (searchpoint[1] - torg[1]); + if (b->verbose > 2) { + printf(" Boundary triangle has origin (%.12g, %.12g).\n", + torg[0], torg[1]); + } + + /* If a recently encountered triangle has been recorded and has not been */ + /* deallocated, test it as a good starting point. */ + if (m->recenttri.tri != (triangle *) NULL) { + if (!deadtri(m->recenttri.tri)) { + org(m->recenttri, torg); + if ((torg[0] == searchpoint[0]) && (torg[1] == searchpoint[1])) { + otricopy(m->recenttri, *searchtri); + return ONVERTEX; + } + dist = (searchpoint[0] - torg[0]) * (searchpoint[0] - torg[0]) + + (searchpoint[1] - torg[1]) * (searchpoint[1] - torg[1]); + if (dist < searchdist) { + otricopy(m->recenttri, *searchtri); + searchdist = dist; + if (b->verbose > 2) { + printf(" Choosing recent triangle with origin (%.12g, %.12g).\n", + torg[0], torg[1]); + } + } + } + } + + /* The number of random samples taken is proportional to the cube root of */ + /* the number of triangles in the mesh. The next bit of code assumes */ + /* that the number of triangles increases monotonically. */ + while (SAMPLEFACTOR * m->samples * m->samples * m->samples < + m->triangles.items) { + m->samples++; + } + triblocks = (m->triangles.maxitems + TRIPERBLOCK - 1) / TRIPERBLOCK; + samplesperblock = (m->samples + triblocks - 1) / triblocks; + sampleblocks = m->samples / samplesperblock; + sampleblock = m->triangles.firstblock; + sampletri.orient = 0; + for (i = 0; i < sampleblocks; i++) { + alignptr = (unsigned long) (sampleblock + 1); + firsttri = (triangle *) (alignptr + (unsigned long) m->triangles.alignbytes + - (alignptr % (unsigned long) m->triangles.alignbytes)); + for (j = 0; j < samplesperblock; j++) { + if (i == triblocks - 1) { + samplenum = randomnation((unsigned int) + (m->triangles.maxitems - (i * TRIPERBLOCK))); + } else { + samplenum = randomnation(TRIPERBLOCK); + } + sampletri.tri = (triangle *) + (firsttri + (samplenum * m->triangles.itemwords)); + if (!deadtri(sampletri.tri)) { + org(sampletri, torg); + dist = (searchpoint[0] - torg[0]) * (searchpoint[0] - torg[0]) + + (searchpoint[1] - torg[1]) * (searchpoint[1] - torg[1]); + if (dist < searchdist) { + otricopy(sampletri, *searchtri); + searchdist = dist; + if (b->verbose > 2) { + printf(" Choosing triangle with origin (%.12g, %.12g).\n", + torg[0], torg[1]); + } + } + } + } + sampleblock = (VOID **) *sampleblock; + } + + /* Where are we? */ + org(*searchtri, torg); + dest(*searchtri, tdest); + /* Check the starting triangle's vertices. */ + if ((torg[0] == searchpoint[0]) && (torg[1] == searchpoint[1])) { + return ONVERTEX; + } + if ((tdest[0] == searchpoint[0]) && (tdest[1] == searchpoint[1])) { + lnextself(*searchtri); + return ONVERTEX; + } + /* Orient `searchtri' to fit the preconditions of calling preciselocate(). */ + ahead = counterclockwise(m, b, torg, tdest, searchpoint); + if (ahead < 0.0) { + /* Turn around so that `searchpoint' is to the left of the */ + /* edge specified by `searchtri'. */ + symself(*searchtri); + } else if (ahead == 0.0) { + /* Check if `searchpoint' is between `torg' and `tdest'. */ + if (((torg[0] < searchpoint[0]) == (searchpoint[0] < tdest[0])) && + ((torg[1] < searchpoint[1]) == (searchpoint[1] < tdest[1]))) { + return ONEDGE; + } + } + return preciselocate(m, b, searchpoint, searchtri, 0); +} + +/** **/ +/** **/ +/********* Point location routines end here *********/ + +/********* Mesh transformation routines begin here *********/ +/** **/ +/** **/ + +/*****************************************************************************/ +/* */ +/* insertsubseg() Create a new subsegment and insert it between two */ +/* triangles. */ +/* */ +/* The new subsegment is inserted at the edge described by the handle */ +/* `tri'. Its vertices are properly initialized. The marker `subsegmark' */ +/* is applied to the subsegment and, if appropriate, its vertices. */ +/* */ +/*****************************************************************************/ + +#ifdef ANSI_DECLARATORS +void insertsubseg(struct mesh *m, struct behavior *b, struct otri *tri, + int subsegmark) +#else /* not ANSI_DECLARATORS */ +void insertsubseg(m, b, tri, subsegmark) +struct mesh *m; +struct behavior *b; +struct otri *tri; /* Edge at which to insert the new subsegment. */ +int subsegmark; /* Marker for the new subsegment. */ +#endif /* not ANSI_DECLARATORS */ + +{ + struct otri oppotri; + struct osub newsubseg; + vertex triorg, tridest; + triangle ptr; /* Temporary variable used by sym(). */ + subseg sptr; /* Temporary variable used by tspivot(). */ + + org(*tri, triorg); + dest(*tri, tridest); + /* Mark vertices if possible. */ + if (vertexmark(triorg) == 0) { + setvertexmark(triorg, subsegmark); + } + if (vertexmark(tridest) == 0) { + setvertexmark(tridest, subsegmark); + } + /* Check if there's already a subsegment here. */ + tspivot(*tri, newsubseg); + if (newsubseg.ss == m->dummysub) { + /* Make new subsegment and initialize its vertices. */ + makesubseg(m, &newsubseg); + setsorg(newsubseg, tridest); + setsdest(newsubseg, triorg); + /* Bond new subsegment to the two triangles it is sandwiched between. */ + /* Note that the facing triangle `oppotri' might be equal to */ + /* `dummytri' (outer space), but the new subsegment is bonded to it */ + /* all the same. */ + tsbond(*tri, newsubseg); + sym(*tri, oppotri); + ssymself(newsubseg); + tsbond(oppotri, newsubseg); + setmark(newsubseg, subsegmark); + if (b->verbose > 2) { + printf(" Inserting new "); + printsubseg(m, b, &newsubseg); + } + } else { + if (mark(newsubseg) == 0) { + setmark(newsubseg, subsegmark); + } + } +} + +/*****************************************************************************/ +/* */ +/* Terminology */ +/* */ +/* A "local transformation" replaces a small set of triangles with another */ +/* set of triangles. This may or may not involve inserting or deleting a */ +/* vertex. */ +/* */ +/* The term "casing" is used to describe the set of triangles that are */ +/* attached to the triangles being transformed, but are not transformed */ +/* themselves. Think of the casing as a fixed hollow structure inside */ +/* which all the action happens. A "casing" is only defined relative to */ +/* a single transformation; each occurrence of a transformation will */ +/* involve a different casing. */ +/* */ +/*****************************************************************************/ + +/*****************************************************************************/ +/* */ +/* flip() Transform two triangles to two different triangles by flipping */ +/* an edge counterclockwise within a quadrilateral. */ +/* */ +/* Imagine the original triangles, abc and bad, oriented so that the */ +/* shared edge ab lies in a horizontal plane, with the vertex b on the left */ +/* and the vertex a on the right. The vertex c lies below the edge, and */ +/* the vertex d lies above the edge. The `flipedge' handle holds the edge */ +/* ab of triangle abc, and is directed left, from vertex a to vertex b. */ +/* */ +/* The triangles abc and bad are deleted and replaced by the triangles cdb */ +/* and dca. The triangles that represent abc and bad are NOT deallocated; */ +/* they are reused for dca and cdb, respectively. Hence, any handles that */ +/* may have held the original triangles are still valid, although not */ +/* directed as they were before. */ +/* */ +/* Upon completion of this routine, the `flipedge' handle holds the edge */ +/* dc of triangle dca, and is directed down, from vertex d to vertex c. */ +/* (Hence, the two triangles have rotated counterclockwise.) */ +/* */ +/* WARNING: This transformation is geometrically valid only if the */ +/* quadrilateral adbc is convex. Furthermore, this transformation is */ +/* valid only if there is not a subsegment between the triangles abc and */ +/* bad. This routine does not check either of these preconditions, and */ +/* it is the responsibility of the calling routine to ensure that they are */ +/* met. If they are not, the streets shall be filled with wailing and */ +/* gnashing of teeth. */ +/* */ +/*****************************************************************************/ + +#ifdef ANSI_DECLARATORS +void flip(struct mesh *m, struct behavior *b, struct otri *flipedge) +#else /* not ANSI_DECLARATORS */ +void flip(m, b, flipedge) +struct mesh *m; +struct behavior *b; +struct otri *flipedge; /* Handle for the triangle abc. */ +#endif /* not ANSI_DECLARATORS */ + +{ + struct otri botleft, botright; + struct otri topleft, topright; + struct otri top; + struct otri botlcasing, botrcasing; + struct otri toplcasing, toprcasing; + struct osub botlsubseg, botrsubseg; + struct osub toplsubseg, toprsubseg; + vertex leftvertex, rightvertex, botvertex; + vertex farvertex; + triangle ptr; /* Temporary variable used by sym(). */ + subseg sptr; /* Temporary variable used by tspivot(). */ + + /* Identify the vertices of the quadrilateral. */ + org(*flipedge, rightvertex); + dest(*flipedge, leftvertex); + apex(*flipedge, botvertex); + sym(*flipedge, top); +#ifdef SELF_CHECK + if (top.tri == m->dummytri) { + printf("Internal error in flip(): Attempt to flip on boundary.\n"); + lnextself(*flipedge); + return; + } + if (m->checksegments) { + tspivot(*flipedge, toplsubseg); + if (toplsubseg.ss != m->dummysub) { + printf("Internal error in flip(): Attempt to flip a segment.\n"); + lnextself(*flipedge); + return; + } + } +#endif /* SELF_CHECK */ + apex(top, farvertex); + + /* Identify the casing of the quadrilateral. */ + lprev(top, topleft); + sym(topleft, toplcasing); + lnext(top, topright); + sym(topright, toprcasing); + lnext(*flipedge, botleft); + sym(botleft, botlcasing); + lprev(*flipedge, botright); + sym(botright, botrcasing); + /* Rotate the quadrilateral one-quarter turn counterclockwise. */ + bond(topleft, botlcasing); + bond(botleft, botrcasing); + bond(botright, toprcasing); + bond(topright, toplcasing); + + if (m->checksegments) { + /* Check for subsegments and rebond them to the quadrilateral. */ + tspivot(topleft, toplsubseg); + tspivot(botleft, botlsubseg); + tspivot(botright, botrsubseg); + tspivot(topright, toprsubseg); + if (toplsubseg.ss == m->dummysub) { + tsdissolve(topright); + } else { + tsbond(topright, toplsubseg); + } + if (botlsubseg.ss == m->dummysub) { + tsdissolve(topleft); + } else { + tsbond(topleft, botlsubseg); + } + if (botrsubseg.ss == m->dummysub) { + tsdissolve(botleft); + } else { + tsbond(botleft, botrsubseg); + } + if (toprsubseg.ss == m->dummysub) { + tsdissolve(botright); + } else { + tsbond(botright, toprsubseg); + } + } + + /* New vertex assignments for the rotated quadrilateral. */ + setorg(*flipedge, farvertex); + setdest(*flipedge, botvertex); + setapex(*flipedge, rightvertex); + setorg(top, botvertex); + setdest(top, farvertex); + setapex(top, leftvertex); + if (b->verbose > 2) { + printf(" Edge flip results in left "); + printtriangle(m, b, &top); + printf(" and right "); + printtriangle(m, b, flipedge); + } +} + +/*****************************************************************************/ +/* */ +/* unflip() Transform two triangles to two different triangles by */ +/* flipping an edge clockwise within a quadrilateral. Reverses */ +/* the flip() operation so that the data structures representing */ +/* the triangles are back where they were before the flip(). */ +/* */ +/* Imagine the original triangles, abc and bad, oriented so that the */ +/* shared edge ab lies in a horizontal plane, with the vertex b on the left */ +/* and the vertex a on the right. The vertex c lies below the edge, and */ +/* the vertex d lies above the edge. The `flipedge' handle holds the edge */ +/* ab of triangle abc, and is directed left, from vertex a to vertex b. */ +/* */ +/* The triangles abc and bad are deleted and replaced by the triangles cdb */ +/* and dca. The triangles that represent abc and bad are NOT deallocated; */ +/* they are reused for cdb and dca, respectively. Hence, any handles that */ +/* may have held the original triangles are still valid, although not */ +/* directed as they were before. */ +/* */ +/* Upon completion of this routine, the `flipedge' handle holds the edge */ +/* cd of triangle cdb, and is directed up, from vertex c to vertex d. */ +/* (Hence, the two triangles have rotated clockwise.) */ +/* */ +/* WARNING: This transformation is geometrically valid only if the */ +/* quadrilateral adbc is convex. Furthermore, this transformation is */ +/* valid only if there is not a subsegment between the triangles abc and */ +/* bad. This routine does not check either of these preconditions, and */ +/* it is the responsibility of the calling routine to ensure that they are */ +/* met. If they are not, the streets shall be filled with wailing and */ +/* gnashing of teeth. */ +/* */ +/*****************************************************************************/ + +#ifdef ANSI_DECLARATORS +void unflip(struct mesh *m, struct behavior *b, struct otri *flipedge) +#else /* not ANSI_DECLARATORS */ +void unflip(m, b, flipedge) +struct mesh *m; +struct behavior *b; +struct otri *flipedge; /* Handle for the triangle abc. */ +#endif /* not ANSI_DECLARATORS */ + +{ + struct otri botleft, botright; + struct otri topleft, topright; + struct otri top; + struct otri botlcasing, botrcasing; + struct otri toplcasing, toprcasing; + struct osub botlsubseg, botrsubseg; + struct osub toplsubseg, toprsubseg; + vertex leftvertex, rightvertex, botvertex; + vertex farvertex; + triangle ptr; /* Temporary variable used by sym(). */ + subseg sptr; /* Temporary variable used by tspivot(). */ + + /* Identify the vertices of the quadrilateral. */ + org(*flipedge, rightvertex); + dest(*flipedge, leftvertex); + apex(*flipedge, botvertex); + sym(*flipedge, top); +#ifdef SELF_CHECK + if (top.tri == m->dummytri) { + printf("Internal error in unflip(): Attempt to flip on boundary.\n"); + lnextself(*flipedge); + return; + } + if (m->checksegments) { + tspivot(*flipedge, toplsubseg); + if (toplsubseg.ss != m->dummysub) { + printf("Internal error in unflip(): Attempt to flip a subsegment.\n"); + lnextself(*flipedge); + return; + } + } +#endif /* SELF_CHECK */ + apex(top, farvertex); + + /* Identify the casing of the quadrilateral. */ + lprev(top, topleft); + sym(topleft, toplcasing); + lnext(top, topright); + sym(topright, toprcasing); + lnext(*flipedge, botleft); + sym(botleft, botlcasing); + lprev(*flipedge, botright); + sym(botright, botrcasing); + /* Rotate the quadrilateral one-quarter turn clockwise. */ + bond(topleft, toprcasing); + bond(botleft, toplcasing); + bond(botright, botlcasing); + bond(topright, botrcasing); + + if (m->checksegments) { + /* Check for subsegments and rebond them to the quadrilateral. */ + tspivot(topleft, toplsubseg); + tspivot(botleft, botlsubseg); + tspivot(botright, botrsubseg); + tspivot(topright, toprsubseg); + if (toplsubseg.ss == m->dummysub) { + tsdissolve(botleft); + } else { + tsbond(botleft, toplsubseg); + } + if (botlsubseg.ss == m->dummysub) { + tsdissolve(botright); + } else { + tsbond(botright, botlsubseg); + } + if (botrsubseg.ss == m->dummysub) { + tsdissolve(topright); + } else { + tsbond(topright, botrsubseg); + } + if (toprsubseg.ss == m->dummysub) { + tsdissolve(topleft); + } else { + tsbond(topleft, toprsubseg); + } + } + + /* New vertex assignments for the rotated quadrilateral. */ + setorg(*flipedge, botvertex); + setdest(*flipedge, farvertex); + setapex(*flipedge, leftvertex); + setorg(top, farvertex); + setdest(top, botvertex); + setapex(top, rightvertex); + if (b->verbose > 2) { + printf(" Edge unflip results in left "); + printtriangle(m, b, flipedge); + printf(" and right "); + printtriangle(m, b, &top); + } +} + +/*****************************************************************************/ +/* */ +/* insertvertex() Insert a vertex into a Delaunay triangulation, */ +/* performing flips as necessary to maintain the Delaunay */ +/* property. */ +/* */ +/* The point `insertvertex' is located. If `searchtri.tri' is not NULL, */ +/* the search for the containing triangle begins from `searchtri'. If */ +/* `searchtri.tri' is NULL, a full point location procedure is called. */ +/* If `insertvertex' is found inside a triangle, the triangle is split into */ +/* three; if `insertvertex' lies on an edge, the edge is split in two, */ +/* thereby splitting the two adjacent triangles into four. Edge flips are */ +/* used to restore the Delaunay property. If `insertvertex' lies on an */ +/* existing vertex, no action is taken, and the value DUPLICATEVERTEX is */ +/* returned. On return, `searchtri' is set to a handle whose origin is the */ +/* existing vertex. */ +/* */ +/* Normally, the parameter `splitseg' is set to NULL, implying that no */ +/* subsegment should be split. In this case, if `insertvertex' is found to */ +/* lie on a segment, no action is taken, and the value VIOLATINGVERTEX is */ +/* returned. On return, `searchtri' is set to a handle whose primary edge */ +/* is the violated subsegment. */ +/* */ +/* If the calling routine wishes to split a subsegment by inserting a */ +/* vertex in it, the parameter `splitseg' should be that subsegment. In */ +/* this case, `searchtri' MUST be the triangle handle reached by pivoting */ +/* from that subsegment; no point location is done. */ +/* */ +/* `segmentflaws' and `triflaws' are flags that indicate whether or not */ +/* there should be checks for the creation of encroached subsegments or bad */ +/* quality triangles. If a newly inserted vertex encroaches upon */ +/* subsegments, these subsegments are added to the list of subsegments to */ +/* be split if `segmentflaws' is set. If bad triangles are created, these */ +/* are added to the queue if `triflaws' is set. */ +/* */ +/* If a duplicate vertex or violated segment does not prevent the vertex */ +/* from being inserted, the return value will be ENCROACHINGVERTEX if the */ +/* vertex encroaches upon a subsegment (and checking is enabled), or */ +/* SUCCESSFULVERTEX otherwise. In either case, `searchtri' is set to a */ +/* handle whose origin is the newly inserted vertex. */ +/* */ +/* insertvertex() does not use flip() for reasons of speed; some */ +/* information can be reused from edge flip to edge flip, like the */ +/* locations of subsegments. */ +/* */ +/*****************************************************************************/ + +#ifdef ANSI_DECLARATORS +enum insertvertexresult insertvertex(struct mesh *m, struct behavior *b, + vertex newvertex, struct otri *searchtri, + struct osub *splitseg, + int segmentflaws, int triflaws, + REAL iradius) +#else /* not ANSI_DECLARATORS */ +enum insertvertexresult insertvertex(m, b, newvertex, searchtri, splitseg, + segmentflaws, triflaws, iradius) +struct mesh *m; +struct behavior *b; +vertex newvertex; +struct otri *searchtri; +struct osub *splitseg; +int segmentflaws; +int triflaws; +REAL iradius; +#endif /* not ANSI_DECLARATORS */ + +{ + struct otri horiz; + struct otri top; + struct otri botleft, botright; + struct otri topleft, topright; + struct otri newbotleft, newbotright; + struct otri newtopright; + struct otri botlcasing, botrcasing; + struct otri toplcasing, toprcasing; + struct otri testtri; + struct osub botlsubseg, botrsubseg; + struct osub toplsubseg, toprsubseg; + struct osub brokensubseg; + struct osub checksubseg; + struct osub rightsubseg; + struct osub newsubseg; + struct badsubseg *encroached; + struct flipstacker *newflip; + vertex first; + vertex leftvertex, rightvertex, botvertex, topvertex, farvertex; + REAL attrib; + REAL area; + enum insertvertexresult success; + enum locateresult intersect; + int doflip; + int mirrorflag; + int enq; + int i; + triangle ptr; /* Temporary variable used by sym(). */ + subseg sptr; /* Temporary variable used by spivot() and tspivot(). */ + + if (b->verbose > 1) { + printf(" Inserting (%.12g, %.12g).\n", newvertex[0], newvertex[1]); + } + + if (splitseg == (struct osub *) NULL) { + /* Find the location of the vertex to be inserted. Check if a good */ + /* starting triangle has already been provided by the caller. */ + if (searchtri->tri == m->dummytri) { + /* Find a boundary triangle. */ + horiz.tri = m->dummytri; + horiz.orient = 0; + symself(horiz); + /* Search for a triangle containing `newvertex'. */ + intersect = locate(m, b, newvertex, &horiz); + } else { + /* Start searching from the triangle provided by the caller. */ + otricopy(*searchtri, horiz); + intersect = preciselocate(m, b, newvertex, &horiz, 1); + } + } else { + /* The calling routine provides the subsegment in which */ + /* the vertex is inserted. */ + otricopy(*searchtri, horiz); + intersect = ONEDGE; + } + if (intersect == ONVERTEX) { + /* There's already a vertex there. Return in `searchtri' a triangle */ + /* whose origin is the existing vertex. */ + otricopy(horiz, *searchtri); + otricopy(horiz, m->recenttri); + return DUPLICATEVERTEX; + } + if ((intersect == ONEDGE) || (intersect == OUTSIDE)) { + /* The vertex falls on an edge or boundary. */ + if (m->checksegments && (splitseg == (struct osub *) NULL)) { + /* Check whether the vertex falls on a subsegment. */ + tspivot(horiz, brokensubseg); + if (brokensubseg.ss != m->dummysub) { + /* The vertex falls on a subsegment, and hence will not be inserted. */ + if (segmentflaws) { + if (b->nobisect == 2) { + enq = 0; +#ifndef CDT_ONLY + } else if (iradius > 0.0) { + enq = splitpermitted(m, &brokensubseg, iradius); +#endif /* not CDT_ONLY */ + } else { + enq = 1; + } + if (enq && (b->nobisect == 1)) { + /* This subsegment may be split only if it is an */ + /* internal boundary. */ + sym(horiz, testtri); + enq = testtri.tri != m->dummytri; + } + if (enq) { + /* Add the subsegment to the list of encroached subsegments. */ + encroached = (struct badsubseg *) poolalloc(&m->badsubsegs); + encroached->encsubseg = sencode(brokensubseg); + sorg(brokensubseg, encroached->subsegorg); + sdest(brokensubseg, encroached->subsegdest); + if (b->verbose > 2) { + printf( + " Queueing encroached subsegment (%.12g, %.12g) (%.12g, %.12g).\n", + encroached->subsegorg[0], encroached->subsegorg[1], + encroached->subsegdest[0], encroached->subsegdest[1]); + } + } + } + /* Return a handle whose primary edge contains the vertex, */ + /* which has not been inserted. */ + otricopy(horiz, *searchtri); + otricopy(horiz, m->recenttri); + return VIOLATINGVERTEX; + } + } + + /* Insert the vertex on an edge, dividing one triangle into two (if */ + /* the edge lies on a boundary) or two triangles into four. */ + lprev(horiz, botright); + sym(botright, botrcasing); + sym(horiz, topright); + /* Is there a second triangle? (Or does this edge lie on a boundary?) */ + mirrorflag = topright.tri != m->dummytri; + if (mirrorflag) { + lnextself(topright); + sym(topright, toprcasing); + maketriangle(m, b, &newtopright); + } else { + /* Splitting a boundary edge increases the number of boundary edges. */ + m->hullsize++; + } + maketriangle(m, b, &newbotright); + + /* Set the vertices of changed and new triangles. */ + org(horiz, rightvertex); + dest(horiz, leftvertex); + apex(horiz, botvertex); + setorg(newbotright, botvertex); + setdest(newbotright, rightvertex); + setapex(newbotright, newvertex); + setorg(horiz, newvertex); + for (i = 0; i < m->eextras; i++) { + /* Set the element attributes of a new triangle. */ + setelemattribute(newbotright, i, elemattribute(botright, i)); + } + if (b->vararea) { + /* Set the area constraint of a new triangle. */ + setareabound(newbotright, areabound(botright)); + } + if (mirrorflag) { + dest(topright, topvertex); + setorg(newtopright, rightvertex); + setdest(newtopright, topvertex); + setapex(newtopright, newvertex); + setorg(topright, newvertex); + for (i = 0; i < m->eextras; i++) { + /* Set the element attributes of another new triangle. */ + setelemattribute(newtopright, i, elemattribute(topright, i)); + } + if (b->vararea) { + /* Set the area constraint of another new triangle. */ + setareabound(newtopright, areabound(topright)); + } + } + + /* There may be subsegments that need to be bonded */ + /* to the new triangle(s). */ + if (m->checksegments) { + tspivot(botright, botrsubseg); + if (botrsubseg.ss != m->dummysub) { + tsdissolve(botright); + tsbond(newbotright, botrsubseg); + } + if (mirrorflag) { + tspivot(topright, toprsubseg); + if (toprsubseg.ss != m->dummysub) { + tsdissolve(topright); + tsbond(newtopright, toprsubseg); + } + } + } + + /* Bond the new triangle(s) to the surrounding triangles. */ + bond(newbotright, botrcasing); + lprevself(newbotright); + bond(newbotright, botright); + lprevself(newbotright); + if (mirrorflag) { + bond(newtopright, toprcasing); + lnextself(newtopright); + bond(newtopright, topright); + lnextself(newtopright); + bond(newtopright, newbotright); + } + + if (splitseg != (struct osub *) NULL) { + /* Split the subsegment into two. */ + setsdest(*splitseg, newvertex); + ssymself(*splitseg); + spivot(*splitseg, rightsubseg); + insertsubseg(m, b, &newbotright, mark(*splitseg)); + tspivot(newbotright, newsubseg); + sbond(*splitseg, newsubseg); + ssymself(newsubseg); + sbond(newsubseg, rightsubseg); + ssymself(*splitseg); + /* Transfer the subsegment's boundary marker to the vertex */ + /* if required. */ + if (vertexmark(newvertex) == 0) { + setvertexmark(newvertex, mark(*splitseg)); + } + } + + if (m->checkquality) { + poolrestart(&m->flipstackers); + m->lastflip = (struct flipstacker *) poolalloc(&m->flipstackers); + m->lastflip->flippedtri = encode(horiz); + m->lastflip->prevflip = (struct flipstacker *) &insertvertex; + } + +#ifdef SELF_CHECK + if (counterclockwise(m, b, rightvertex, leftvertex, botvertex) < 0.0) { + printf("Internal error in insertvertex():\n"); + printf( + " Clockwise triangle prior to edge vertex insertion (bottom).\n"); + } + if (mirrorflag) { + if (counterclockwise(m, b, leftvertex, rightvertex, topvertex) < 0.0) { + printf("Internal error in insertvertex():\n"); + printf(" Clockwise triangle prior to edge vertex insertion (top).\n"); + } + if (counterclockwise(m, b, rightvertex, topvertex, newvertex) < 0.0) { + printf("Internal error in insertvertex():\n"); + printf( + " Clockwise triangle after edge vertex insertion (top right).\n"); + } + if (counterclockwise(m, b, topvertex, leftvertex, newvertex) < 0.0) { + printf("Internal error in insertvertex():\n"); + printf( + " Clockwise triangle after edge vertex insertion (top left).\n"); + } + } + if (counterclockwise(m, b, leftvertex, botvertex, newvertex) < 0.0) { + printf("Internal error in insertvertex():\n"); + printf( + " Clockwise triangle after edge vertex insertion (bottom left).\n"); + } + if (counterclockwise(m, b, botvertex, rightvertex, newvertex) < 0.0) { + printf("Internal error in insertvertex():\n"); + printf( + " Clockwise triangle after edge vertex insertion (bottom right).\n"); + } +#endif /* SELF_CHECK */ + if (b->verbose > 2) { + printf(" Updating bottom left "); + printtriangle(m, b, &botright); + if (mirrorflag) { + printf(" Updating top left "); + printtriangle(m, b, &topright); + printf(" Creating top right "); + printtriangle(m, b, &newtopright); + } + printf(" Creating bottom right "); + printtriangle(m, b, &newbotright); + } + + /* Position `horiz' on the first edge to check for */ + /* the Delaunay property. */ + lnextself(horiz); + } else { + /* Insert the vertex in a triangle, splitting it into three. */ + lnext(horiz, botleft); + lprev(horiz, botright); + sym(botleft, botlcasing); + sym(botright, botrcasing); + maketriangle(m, b, &newbotleft); + maketriangle(m, b, &newbotright); + + /* Set the vertices of changed and new triangles. */ + org(horiz, rightvertex); + dest(horiz, leftvertex); + apex(horiz, botvertex); + setorg(newbotleft, leftvertex); + setdest(newbotleft, botvertex); + setapex(newbotleft, newvertex); + setorg(newbotright, botvertex); + setdest(newbotright, rightvertex); + setapex(newbotright, newvertex); + setapex(horiz, newvertex); + for (i = 0; i < m->eextras; i++) { + /* Set the element attributes of the new triangles. */ + attrib = elemattribute(horiz, i); + setelemattribute(newbotleft, i, attrib); + setelemattribute(newbotright, i, attrib); + } + if (b->vararea) { + /* Set the area constraint of the new triangles. */ + area = areabound(horiz); + setareabound(newbotleft, area); + setareabound(newbotright, area); + } + + /* There may be subsegments that need to be bonded */ + /* to the new triangles. */ + if (m->checksegments) { + tspivot(botleft, botlsubseg); + if (botlsubseg.ss != m->dummysub) { + tsdissolve(botleft); + tsbond(newbotleft, botlsubseg); + } + tspivot(botright, botrsubseg); + if (botrsubseg.ss != m->dummysub) { + tsdissolve(botright); + tsbond(newbotright, botrsubseg); + } + } + + /* Bond the new triangles to the surrounding triangles. */ + bond(newbotleft, botlcasing); + bond(newbotright, botrcasing); + lnextself(newbotleft); + lprevself(newbotright); + bond(newbotleft, newbotright); + lnextself(newbotleft); + bond(botleft, newbotleft); + lprevself(newbotright); + bond(botright, newbotright); + + if (m->checkquality) { + poolrestart(&m->flipstackers); + m->lastflip = (struct flipstacker *) poolalloc(&m->flipstackers); + m->lastflip->flippedtri = encode(horiz); + m->lastflip->prevflip = (struct flipstacker *) NULL; + } + +#ifdef SELF_CHECK + if (counterclockwise(m, b, rightvertex, leftvertex, botvertex) < 0.0) { + printf("Internal error in insertvertex():\n"); + printf(" Clockwise triangle prior to vertex insertion.\n"); + } + if (counterclockwise(m, b, rightvertex, leftvertex, newvertex) < 0.0) { + printf("Internal error in insertvertex():\n"); + printf(" Clockwise triangle after vertex insertion (top).\n"); + } + if (counterclockwise(m, b, leftvertex, botvertex, newvertex) < 0.0) { + printf("Internal error in insertvertex():\n"); + printf(" Clockwise triangle after vertex insertion (left).\n"); + } + if (counterclockwise(m, b, botvertex, rightvertex, newvertex) < 0.0) { + printf("Internal error in insertvertex():\n"); + printf(" Clockwise triangle after vertex insertion (right).\n"); + } +#endif /* SELF_CHECK */ + if (b->verbose > 2) { + printf(" Updating top "); + printtriangle(m, b, &horiz); + printf(" Creating left "); + printtriangle(m, b, &newbotleft); + printf(" Creating right "); + printtriangle(m, b, &newbotright); + } + } + + /* The insertion is successful by default, unless an encroached */ + /* subsegment is found. */ + success = SUCCESSFULVERTEX; + /* Circle around the newly inserted vertex, checking each edge opposite */ + /* it for the Delaunay property. Non-Delaunay edges are flipped. */ + /* `horiz' is always the edge being checked. `first' marks where to */ + /* stop circling. */ + org(horiz, first); + rightvertex = first; + dest(horiz, leftvertex); + /* Circle until finished. */ + while (1) { + /* By default, the edge will be flipped. */ + doflip = 1; + + if (m->checksegments) { + /* Check for a subsegment, which cannot be flipped. */ + tspivot(horiz, checksubseg); + if (checksubseg.ss != m->dummysub) { + /* The edge is a subsegment and cannot be flipped. */ + doflip = 0; +#ifndef CDT_ONLY + if (segmentflaws) { + /* Does the new vertex encroach upon this subsegment? */ + if (checkseg4encroach(m, b, &checksubseg, iradius)) { + success = ENCROACHINGVERTEX; + } + } +#endif /* not CDT_ONLY */ + } + } + + if (doflip) { + /* Check if the edge is a boundary edge. */ + sym(horiz, top); + if (top.tri == m->dummytri) { + /* The edge is a boundary edge and cannot be flipped. */ + doflip = 0; + } else { + /* Find the vertex on the other side of the edge. */ + apex(top, farvertex); + /* In the incremental Delaunay triangulation algorithm, any of */ + /* `leftvertex', `rightvertex', and `farvertex' could be vertices */ + /* of the triangular bounding box. These vertices must be */ + /* treated as if they are infinitely distant, even though their */ + /* "coordinates" are not. */ + if ((leftvertex == m->infvertex1) || (leftvertex == m->infvertex2) || + (leftvertex == m->infvertex3)) { + /* `leftvertex' is infinitely distant. Check the convexity of */ + /* the boundary of the triangulation. 'farvertex' might be */ + /* infinite as well, but trust me, this same condition should */ + /* be applied. */ + doflip = counterclockwise(m, b, newvertex, rightvertex, farvertex) + > 0.0; + } else if ((rightvertex == m->infvertex1) || + (rightvertex == m->infvertex2) || + (rightvertex == m->infvertex3)) { + /* `rightvertex' is infinitely distant. Check the convexity of */ + /* the boundary of the triangulation. 'farvertex' might be */ + /* infinite as well, but trust me, this same condition should */ + /* be applied. */ + doflip = counterclockwise(m, b, farvertex, leftvertex, newvertex) + > 0.0; + } else if ((farvertex == m->infvertex1) || + (farvertex == m->infvertex2) || + (farvertex == m->infvertex3)) { + /* `farvertex' is infinitely distant and cannot be inside */ + /* the circumcircle of the triangle `horiz'. */ + doflip = 0; + } else { + /* Test whether the edge is locally Delaunay. */ + doflip = incircle(m, b, leftvertex, newvertex, rightvertex, + farvertex) > 0.0; + } + if (doflip) { + /* We made it! Flip the edge `horiz' by rotating its containing */ + /* quadrilateral (the two triangles adjacent to `horiz'). */ + /* Identify the casing of the quadrilateral. */ + lprev(top, topleft); + sym(topleft, toplcasing); + lnext(top, topright); + sym(topright, toprcasing); + lnext(horiz, botleft); + sym(botleft, botlcasing); + lprev(horiz, botright); + sym(botright, botrcasing); + /* Rotate the quadrilateral one-quarter turn counterclockwise. */ + bond(topleft, botlcasing); + bond(botleft, botrcasing); + bond(botright, toprcasing); + bond(topright, toplcasing); + if (m->checksegments) { + /* Check for subsegments and rebond them to the quadrilateral. */ + tspivot(topleft, toplsubseg); + tspivot(botleft, botlsubseg); + tspivot(botright, botrsubseg); + tspivot(topright, toprsubseg); + if (toplsubseg.ss == m->dummysub) { + tsdissolve(topright); + } else { + tsbond(topright, toplsubseg); + } + if (botlsubseg.ss == m->dummysub) { + tsdissolve(topleft); + } else { + tsbond(topleft, botlsubseg); + } + if (botrsubseg.ss == m->dummysub) { + tsdissolve(botleft); + } else { + tsbond(botleft, botrsubseg); + } + if (toprsubseg.ss == m->dummysub) { + tsdissolve(botright); + } else { + tsbond(botright, toprsubseg); + } + } + /* New vertex assignments for the rotated quadrilateral. */ + setorg(horiz, farvertex); + setdest(horiz, newvertex); + setapex(horiz, rightvertex); + setorg(top, newvertex); + setdest(top, farvertex); + setapex(top, leftvertex); + for (i = 0; i < m->eextras; i++) { + /* Take the average of the two triangles' attributes. */ + attrib = 0.5 * (elemattribute(top, i) + elemattribute(horiz, i)); + setelemattribute(top, i, attrib); + setelemattribute(horiz, i, attrib); + } + if (b->vararea) { + if ((areabound(top) <= 0.0) || (areabound(horiz) <= 0.0)) { + area = -1.0; + } else { + /* Take the average of the two triangles' area constraints. */ + /* This prevents small area constraints from migrating a */ + /* long, long way from their original location due to flips. */ + area = 0.5 * (areabound(top) + areabound(horiz)); + } + setareabound(top, area); + setareabound(horiz, area); + } + + if (m->checkquality) { + newflip = (struct flipstacker *) poolalloc(&m->flipstackers); + newflip->flippedtri = encode(horiz); + newflip->prevflip = m->lastflip; + m->lastflip = newflip; + } + +#ifdef SELF_CHECK + if (newvertex != (vertex) NULL) { + if (counterclockwise(m, b, leftvertex, newvertex, rightvertex) < + 0.0) { + printf("Internal error in insertvertex():\n"); + printf(" Clockwise triangle prior to edge flip (bottom).\n"); + } + /* The following test has been removed because constrainededge() */ + /* sometimes generates inverted triangles that insertvertex() */ + /* removes. */ +/* + if (counterclockwise(m, b, rightvertex, farvertex, leftvertex) < + 0.0) { + printf("Internal error in insertvertex():\n"); + printf(" Clockwise triangle prior to edge flip (top).\n"); + } +*/ + if (counterclockwise(m, b, farvertex, leftvertex, newvertex) < + 0.0) { + printf("Internal error in insertvertex():\n"); + printf(" Clockwise triangle after edge flip (left).\n"); + } + if (counterclockwise(m, b, newvertex, rightvertex, farvertex) < + 0.0) { + printf("Internal error in insertvertex():\n"); + printf(" Clockwise triangle after edge flip (right).\n"); + } + } +#endif /* SELF_CHECK */ + if (b->verbose > 2) { + printf(" Edge flip results in left "); + lnextself(topleft); + printtriangle(m, b, &topleft); + printf(" and right "); + printtriangle(m, b, &horiz); + } + /* On the next iterations, consider the two edges that were */ + /* exposed (this is, are now visible to the newly inserted */ + /* vertex) by the edge flip. */ + lprevself(horiz); + leftvertex = farvertex; + } + } + } + if (!doflip) { + /* The handle `horiz' is accepted as locally Delaunay. */ +#ifndef CDT_ONLY + if (triflaws) { + /* Check the triangle `horiz' for quality. */ + testtriangle(m, b, &horiz); + } +#endif /* not CDT_ONLY */ + /* Look for the next edge around the newly inserted vertex. */ + lnextself(horiz); + sym(horiz, testtri); + /* Check for finishing a complete revolution about the new vertex, or */ + /* falling outside of the triangulation. The latter will happen */ + /* when a vertex is inserted at a boundary. */ + if ((leftvertex == first) || (testtri.tri == m->dummytri)) { + /* We're done. Return a triangle whose origin is the new vertex. */ + lnext(horiz, *searchtri); + lnext(horiz, m->recenttri); + return success; + } + /* Finish finding the next edge around the newly inserted vertex. */ + lnext(testtri, horiz); + rightvertex = leftvertex; + dest(horiz, leftvertex); + } + } +} + +/*****************************************************************************/ +/* */ +/* triangulatepolygon() Find the Delaunay triangulation of a polygon that */ +/* has a certain "nice" shape. This includes the */ +/* polygons that result from deletion of a vertex or */ +/* insertion of a segment. */ +/* */ +/* This is a conceptually difficult routine. The starting assumption is */ +/* that we have a polygon with n sides. n - 1 of these sides are currently */ +/* represented as edges in the mesh. One side, called the "base", need not */ +/* be. */ +/* */ +/* Inside the polygon is a structure I call a "fan", consisting of n - 1 */ +/* triangles that share a common origin. For each of these triangles, the */ +/* edge opposite the origin is one of the sides of the polygon. The */ +/* primary edge of each triangle is the edge directed from the origin to */ +/* the destination; note that this is not the same edge that is a side of */ +/* the polygon. `firstedge' is the primary edge of the first triangle. */ +/* From there, the triangles follow in counterclockwise order about the */ +/* polygon, until `lastedge', the primary edge of the last triangle. */ +/* `firstedge' and `lastedge' are probably connected to other triangles */ +/* beyond the extremes of the fan, but their identity is not important, as */ +/* long as the fan remains connected to them. */ +/* */ +/* Imagine the polygon oriented so that its base is at the bottom. This */ +/* puts `firstedge' on the far right, and `lastedge' on the far left. */ +/* The right vertex of the base is the destination of `firstedge', and the */ +/* left vertex of the base is the apex of `lastedge'. */ +/* */ +/* The challenge now is to find the right sequence of edge flips to */ +/* transform the fan into a Delaunay triangulation of the polygon. Each */ +/* edge flip effectively removes one triangle from the fan, committing it */ +/* to the polygon. The resulting polygon has one fewer edge. If `doflip' */ +/* is set, the final flip will be performed, resulting in a fan of one */ +/* (useless?) triangle. If `doflip' is not set, the final flip is not */ +/* performed, resulting in a fan of two triangles, and an unfinished */ +/* triangular polygon that is not yet filled out with a single triangle. */ +/* On completion of the routine, `lastedge' is the last remaining triangle, */ +/* or the leftmost of the last two. */ +/* */ +/* Although the flips are performed in the order described above, the */ +/* decisions about what flips to perform are made in precisely the reverse */ +/* order. The recursive triangulatepolygon() procedure makes a decision, */ +/* uses up to two recursive calls to triangulate the "subproblems" */ +/* (polygons with fewer edges), and then performs an edge flip. */ +/* */ +/* The "decision" it makes is which vertex of the polygon should be */ +/* connected to the base. This decision is made by testing every possible */ +/* vertex. Once the best vertex is found, the two edges that connect this */ +/* vertex to the base become the bases for two smaller polygons. These */ +/* are triangulated recursively. Unfortunately, this approach can take */ +/* O(n^2) time not only in the worst case, but in many common cases. It's */ +/* rarely a big deal for vertex deletion, where n is rarely larger than */ +/* ten, but it could be a big deal for segment insertion, especially if */ +/* there's a lot of long segments that each cut many triangles. I ought to */ +/* code a faster algorithm some day. */ +/* */ +/* The `edgecount' parameter is the number of sides of the polygon, */ +/* including its base. `triflaws' is a flag that determines whether the */ +/* new triangles should be tested for quality, and enqueued if they are */ +/* bad. */ +/* */ +/*****************************************************************************/ + +#ifdef ANSI_DECLARATORS +void triangulatepolygon(struct mesh *m, struct behavior *b, + struct otri *firstedge, struct otri *lastedge, + int edgecount, int doflip, int triflaws) +#else /* not ANSI_DECLARATORS */ +void triangulatepolygon(m, b, firstedge, lastedge, edgecount, doflip, triflaws) +struct mesh *m; +struct behavior *b; +struct otri *firstedge; +struct otri *lastedge; +int edgecount; +int doflip; +int triflaws; +#endif /* not ANSI_DECLARATORS */ + +{ + struct otri testtri; + struct otri besttri; + struct otri tempedge; + vertex leftbasevertex, rightbasevertex; + vertex testvertex; + vertex bestvertex; + int bestnumber; + int i; + triangle ptr; /* Temporary variable used by sym(), onext(), and oprev(). */ + + /* Identify the base vertices. */ + apex(*lastedge, leftbasevertex); + dest(*firstedge, rightbasevertex); + if (b->verbose > 2) { + printf(" Triangulating interior polygon at edge\n"); + printf(" (%.12g, %.12g) (%.12g, %.12g)\n", leftbasevertex[0], + leftbasevertex[1], rightbasevertex[0], rightbasevertex[1]); + } + /* Find the best vertex to connect the base to. */ + onext(*firstedge, besttri); + dest(besttri, bestvertex); + otricopy(besttri, testtri); + bestnumber = 1; + for (i = 2; i <= edgecount - 2; i++) { + onextself(testtri); + dest(testtri, testvertex); + /* Is this a better vertex? */ + if (incircle(m, b, leftbasevertex, rightbasevertex, bestvertex, + testvertex) > 0.0) { + otricopy(testtri, besttri); + bestvertex = testvertex; + bestnumber = i; + } + } + if (b->verbose > 2) { + printf(" Connecting edge to (%.12g, %.12g)\n", bestvertex[0], + bestvertex[1]); + } + if (bestnumber > 1) { + /* Recursively triangulate the smaller polygon on the right. */ + oprev(besttri, tempedge); + triangulatepolygon(m, b, firstedge, &tempedge, bestnumber + 1, 1, + triflaws); + } + if (bestnumber < edgecount - 2) { + /* Recursively triangulate the smaller polygon on the left. */ + sym(besttri, tempedge); + triangulatepolygon(m, b, &besttri, lastedge, edgecount - bestnumber, 1, + triflaws); + /* Find `besttri' again; it may have been lost to edge flips. */ + sym(tempedge, besttri); + } + if (doflip) { + /* Do one final edge flip. */ + flip(m, b, &besttri); +#ifndef CDT_ONLY + if (triflaws) { + /* Check the quality of the newly committed triangle. */ + sym(besttri, testtri); + testtriangle(m, b, &testtri); + } +#endif /* not CDT_ONLY */ + } + /* Return the base triangle. */ + otricopy(besttri, *lastedge); +} + +/*****************************************************************************/ +/* */ +/* deletevertex() Delete a vertex from a Delaunay triangulation, ensuring */ +/* that the triangulation remains Delaunay. */ +/* */ +/* The origin of `deltri' is deleted. The union of the triangles adjacent */ +/* to this vertex is a polygon, for which the Delaunay triangulation is */ +/* found. Two triangles are removed from the mesh. */ +/* */ +/* Only interior vertices that do not lie on segments or boundaries may be */ +/* deleted. */ +/* */ +/*****************************************************************************/ + +#ifndef CDT_ONLY + +#ifdef ANSI_DECLARATORS +void deletevertex(struct mesh *m, struct behavior *b, struct otri *deltri) +#else /* not ANSI_DECLARATORS */ +void deletevertex(m, b, deltri) +struct mesh *m; +struct behavior *b; +struct otri *deltri; +#endif /* not ANSI_DECLARATORS */ + +{ + struct otri countingtri; + struct otri firstedge, lastedge; + struct otri deltriright; + struct otri lefttri, righttri; + struct otri leftcasing, rightcasing; + struct osub leftsubseg, rightsubseg; + vertex delvertex; + vertex neworg; + int edgecount; + triangle ptr; /* Temporary variable used by sym(), onext(), and oprev(). */ + subseg sptr; /* Temporary variable used by tspivot(). */ + + org(*deltri, delvertex); + if (b->verbose > 1) { + printf(" Deleting (%.12g, %.12g).\n", delvertex[0], delvertex[1]); + } + vertexdealloc(m, delvertex); + + /* Count the degree of the vertex being deleted. */ + onext(*deltri, countingtri); + edgecount = 1; + while (!otriequal(*deltri, countingtri)) { +#ifdef SELF_CHECK + if (countingtri.tri == m->dummytri) { + printf("Internal error in deletevertex():\n"); + printf(" Attempt to delete boundary vertex.\n"); + internalerror(); + } +#endif /* SELF_CHECK */ + edgecount++; + onextself(countingtri); + } + +#ifdef SELF_CHECK + if (edgecount < 3) { + printf("Internal error in deletevertex():\n Vertex has degree %d.\n", + edgecount); + internalerror(); + } +#endif /* SELF_CHECK */ + if (edgecount > 3) { + /* Triangulate the polygon defined by the union of all triangles */ + /* adjacent to the vertex being deleted. Check the quality of */ + /* the resulting triangles. */ + onext(*deltri, firstedge); + oprev(*deltri, lastedge); + triangulatepolygon(m, b, &firstedge, &lastedge, edgecount, 0, + !b->nobisect); + } + /* Splice out two triangles. */ + lprev(*deltri, deltriright); + dnext(*deltri, lefttri); + sym(lefttri, leftcasing); + oprev(deltriright, righttri); + sym(righttri, rightcasing); + bond(*deltri, leftcasing); + bond(deltriright, rightcasing); + tspivot(lefttri, leftsubseg); + if (leftsubseg.ss != m->dummysub) { + tsbond(*deltri, leftsubseg); + } + tspivot(righttri, rightsubseg); + if (rightsubseg.ss != m->dummysub) { + tsbond(deltriright, rightsubseg); + } + + /* Set the new origin of `deltri' and check its quality. */ + org(lefttri, neworg); + setorg(*deltri, neworg); + if (!b->nobisect) { + testtriangle(m, b, deltri); + } + + /* Delete the two spliced-out triangles. */ + triangledealloc(m, lefttri.tri); + triangledealloc(m, righttri.tri); +} + +#endif /* not CDT_ONLY */ + +/*****************************************************************************/ +/* */ +/* undovertex() Undo the most recent vertex insertion. */ +/* */ +/* Walks through the list of transformations (flips and a vertex insertion) */ +/* in the reverse of the order in which they were done, and undoes them. */ +/* The inserted vertex is removed from the triangulation and deallocated. */ +/* Two triangles (possibly just one) are also deallocated. */ +/* */ +/*****************************************************************************/ + +#ifndef CDT_ONLY + +#ifdef ANSI_DECLARATORS +void undovertex(struct mesh *m, struct behavior *b) +#else /* not ANSI_DECLARATORS */ +void undovertex(m, b) +struct mesh *m; +struct behavior *b; +#endif /* not ANSI_DECLARATORS */ + +{ + struct otri fliptri; + struct otri botleft, botright, topright; + struct otri botlcasing, botrcasing, toprcasing; + struct otri gluetri; + struct osub botlsubseg, botrsubseg, toprsubseg; + vertex botvertex, rightvertex; + triangle ptr; /* Temporary variable used by sym(). */ + subseg sptr; /* Temporary variable used by tspivot(). */ + + /* Walk through the list of transformations (flips and a vertex insertion) */ + /* in the reverse of the order in which they were done, and undo them. */ + while (m->lastflip != (struct flipstacker *) NULL) { + /* Find a triangle involved in the last unreversed transformation. */ + decode(m->lastflip->flippedtri, fliptri); + + /* We are reversing one of three transformations: a trisection of one */ + /* triangle into three (by inserting a vertex in the triangle), a */ + /* bisection of two triangles into four (by inserting a vertex in an */ + /* edge), or an edge flip. */ + if (m->lastflip->prevflip == (struct flipstacker *) NULL) { + /* Restore a triangle that was split into three triangles, */ + /* so it is again one triangle. */ + dprev(fliptri, botleft); + lnextself(botleft); + onext(fliptri, botright); + lprevself(botright); + sym(botleft, botlcasing); + sym(botright, botrcasing); + dest(botleft, botvertex); + + setapex(fliptri, botvertex); + lnextself(fliptri); + bond(fliptri, botlcasing); + tspivot(botleft, botlsubseg); + tsbond(fliptri, botlsubseg); + lnextself(fliptri); + bond(fliptri, botrcasing); + tspivot(botright, botrsubseg); + tsbond(fliptri, botrsubseg); + + /* Delete the two spliced-out triangles. */ + triangledealloc(m, botleft.tri); + triangledealloc(m, botright.tri); + } else if (m->lastflip->prevflip == (struct flipstacker *) &insertvertex) { + /* Restore two triangles that were split into four triangles, */ + /* so they are again two triangles. */ + lprev(fliptri, gluetri); + sym(gluetri, botright); + lnextself(botright); + sym(botright, botrcasing); + dest(botright, rightvertex); + + setorg(fliptri, rightvertex); + bond(gluetri, botrcasing); + tspivot(botright, botrsubseg); + tsbond(gluetri, botrsubseg); + + /* Delete the spliced-out triangle. */ + triangledealloc(m, botright.tri); + + sym(fliptri, gluetri); + if (gluetri.tri != m->dummytri) { + lnextself(gluetri); + dnext(gluetri, topright); + sym(topright, toprcasing); + + setorg(gluetri, rightvertex); + bond(gluetri, toprcasing); + tspivot(topright, toprsubseg); + tsbond(gluetri, toprsubseg); + + /* Delete the spliced-out triangle. */ + triangledealloc(m, topright.tri); + } + + /* This is the end of the list, sneakily encoded. */ + m->lastflip->prevflip = (struct flipstacker *) NULL; + } else { + /* Undo an edge flip. */ + unflip(m, b, &fliptri); + } + + /* Go on and process the next transformation. */ + m->lastflip = m->lastflip->prevflip; + } +} + +#endif /* not CDT_ONLY */ + +/** **/ +/** **/ +/********* Mesh transformation routines end here *********/ + +/********* Divide-and-conquer Delaunay triangulation begins here *********/ +/** **/ +/** **/ + +/*****************************************************************************/ +/* */ +/* The divide-and-conquer bounding box */ +/* */ +/* I originally implemented the divide-and-conquer and incremental Delaunay */ +/* triangulations using the edge-based data structure presented by Guibas */ +/* and Stolfi. Switching to a triangle-based data structure doubled the */ +/* speed. However, I had to think of a few extra tricks to maintain the */ +/* elegance of the original algorithms. */ +/* */ +/* The "bounding box" used by my variant of the divide-and-conquer */ +/* algorithm uses one triangle for each edge of the convex hull of the */ +/* triangulation. These bounding triangles all share a common apical */ +/* vertex, which is represented by NULL and which represents nothing. */ +/* The bounding triangles are linked in a circular fan about this NULL */ +/* vertex, and the edges on the convex hull of the triangulation appear */ +/* opposite the NULL vertex. You might find it easiest to imagine that */ +/* the NULL vertex is a point in 3D space behind the center of the */ +/* triangulation, and that the bounding triangles form a sort of cone. */ +/* */ +/* This bounding box makes it easy to represent degenerate cases. For */ +/* instance, the triangulation of two vertices is a single edge. This edge */ +/* is represented by two bounding box triangles, one on each "side" of the */ +/* edge. These triangles are also linked together in a fan about the NULL */ +/* vertex. */ +/* */ +/* The bounding box also makes it easy to traverse the convex hull, as the */ +/* divide-and-conquer algorithm needs to do. */ +/* */ +/*****************************************************************************/ + +/*****************************************************************************/ +/* */ +/* vertexsort() Sort an array of vertices by x-coordinate, using the */ +/* y-coordinate as a secondary key. */ +/* */ +/* Uses quicksort. Randomized O(n log n) time. No, I did not make any of */ +/* the usual quicksort mistakes. */ +/* */ +/*****************************************************************************/ + +#ifdef ANSI_DECLARATORS +void vertexsort(vertex *sortarray, int arraysize) +#else /* not ANSI_DECLARATORS */ +void vertexsort(sortarray, arraysize) +vertex *sortarray; +int arraysize; +#endif /* not ANSI_DECLARATORS */ + +{ + int left, right; + int pivot; + REAL pivotx, pivoty; + vertex temp; + + if (arraysize == 2) { + /* Recursive base case. */ + if ((sortarray[0][0] > sortarray[1][0]) || + ((sortarray[0][0] == sortarray[1][0]) && + (sortarray[0][1] > sortarray[1][1]))) { + temp = sortarray[1]; + sortarray[1] = sortarray[0]; + sortarray[0] = temp; + } + return; + } + /* Choose a random pivot to split the array. */ + pivot = (int) randomnation((unsigned int) arraysize); + pivotx = sortarray[pivot][0]; + pivoty = sortarray[pivot][1]; + /* Split the array. */ + left = -1; + right = arraysize; + while (left < right) { + /* Search for a vertex whose x-coordinate is too large for the left. */ + do { + left++; + } while ((left <= right) && ((sortarray[left][0] < pivotx) || + ((sortarray[left][0] == pivotx) && + (sortarray[left][1] < pivoty)))); + /* Search for a vertex whose x-coordinate is too small for the right. */ + do { + right--; + } while ((left <= right) && ((sortarray[right][0] > pivotx) || + ((sortarray[right][0] == pivotx) && + (sortarray[right][1] > pivoty)))); + if (left < right) { + /* Swap the left and right vertices. */ + temp = sortarray[left]; + sortarray[left] = sortarray[right]; + sortarray[right] = temp; + } + } + if (left > 1) { + /* Recursively sort the left subset. */ + vertexsort(sortarray, left); + } + if (right < arraysize - 2) { + /* Recursively sort the right subset. */ + vertexsort(&sortarray[right + 1], arraysize - right - 1); + } +} + +/*****************************************************************************/ +/* */ +/* vertexmedian() An order statistic algorithm, almost. Shuffles an */ +/* array of vertices so that the first `median' vertices */ +/* occur lexicographically before the remaining vertices. */ +/* */ +/* Uses the x-coordinate as the primary key if axis == 0; the y-coordinate */ +/* if axis == 1. Very similar to the vertexsort() procedure, but runs in */ +/* randomized linear time. */ +/* */ +/*****************************************************************************/ + +#ifdef ANSI_DECLARATORS +void vertexmedian(vertex *sortarray, int arraysize, int median, int axis) +#else /* not ANSI_DECLARATORS */ +void vertexmedian(sortarray, arraysize, median, axis) +vertex *sortarray; +int arraysize; +int median; +int axis; +#endif /* not ANSI_DECLARATORS */ + +{ + int left, right; + int pivot; + REAL pivot1, pivot2; + vertex temp; + + if (arraysize == 2) { + /* Recursive base case. */ + if ((sortarray[0][axis] > sortarray[1][axis]) || + ((sortarray[0][axis] == sortarray[1][axis]) && + (sortarray[0][1 - axis] > sortarray[1][1 - axis]))) { + temp = sortarray[1]; + sortarray[1] = sortarray[0]; + sortarray[0] = temp; + } + return; + } + /* Choose a random pivot to split the array. */ + pivot = (int) randomnation((unsigned int) arraysize); + pivot1 = sortarray[pivot][axis]; + pivot2 = sortarray[pivot][1 - axis]; + /* Split the array. */ + left = -1; + right = arraysize; + while (left < right) { + /* Search for a vertex whose x-coordinate is too large for the left. */ + do { + left++; + } while ((left <= right) && ((sortarray[left][axis] < pivot1) || + ((sortarray[left][axis] == pivot1) && + (sortarray[left][1 - axis] < pivot2)))); + /* Search for a vertex whose x-coordinate is too small for the right. */ + do { + right--; + } while ((left <= right) && ((sortarray[right][axis] > pivot1) || + ((sortarray[right][axis] == pivot1) && + (sortarray[right][1 - axis] > pivot2)))); + if (left < right) { + /* Swap the left and right vertices. */ + temp = sortarray[left]; + sortarray[left] = sortarray[right]; + sortarray[right] = temp; + } + } + /* Unlike in vertexsort(), at most one of the following */ + /* conditionals is true. */ + if (left > median) { + /* Recursively shuffle the left subset. */ + vertexmedian(sortarray, left, median, axis); + } + if (right < median - 1) { + /* Recursively shuffle the right subset. */ + vertexmedian(&sortarray[right + 1], arraysize - right - 1, + median - right - 1, axis); + } +} + +/*****************************************************************************/ +/* */ +/* alternateaxes() Sorts the vertices as appropriate for the divide-and- */ +/* conquer algorithm with alternating cuts. */ +/* */ +/* Partitions by x-coordinate if axis == 0; by y-coordinate if axis == 1. */ +/* For the base case, subsets containing only two or three vertices are */ +/* always sorted by x-coordinate. */ +/* */ +/*****************************************************************************/ + +#ifdef ANSI_DECLARATORS +void alternateaxes(vertex *sortarray, int arraysize, int axis) +#else /* not ANSI_DECLARATORS */ +void alternateaxes(sortarray, arraysize, axis) +vertex *sortarray; +int arraysize; +int axis; +#endif /* not ANSI_DECLARATORS */ + +{ + int divider; + + divider = arraysize >> 1; + if (arraysize <= 3) { + /* Recursive base case: subsets of two or three vertices will be */ + /* handled specially, and should always be sorted by x-coordinate. */ + axis = 0; + } + /* Partition with a horizontal or vertical cut. */ + vertexmedian(sortarray, arraysize, divider, axis); + /* Recursively partition the subsets with a cross cut. */ + if (arraysize - divider >= 2) { + if (divider >= 2) { + alternateaxes(sortarray, divider, 1 - axis); + } + alternateaxes(&sortarray[divider], arraysize - divider, 1 - axis); + } +} + +/*****************************************************************************/ +/* */ +/* mergehulls() Merge two adjacent Delaunay triangulations into a */ +/* single Delaunay triangulation. */ +/* */ +/* This is similar to the algorithm given by Guibas and Stolfi, but uses */ +/* a triangle-based, rather than edge-based, data structure. */ +/* */ +/* The algorithm walks up the gap between the two triangulations, knitting */ +/* them together. As they are merged, some of their bounding triangles */ +/* are converted into real triangles of the triangulation. The procedure */ +/* pulls each hull's bounding triangles apart, then knits them together */ +/* like the teeth of two gears. The Delaunay property determines, at each */ +/* step, whether the next "tooth" is a bounding triangle of the left hull */ +/* or the right. When a bounding triangle becomes real, its apex is */ +/* changed from NULL to a real vertex. */ +/* */ +/* Only two new triangles need to be allocated. These become new bounding */ +/* triangles at the top and bottom of the seam. They are used to connect */ +/* the remaining bounding triangles (those that have not been converted */ +/* into real triangles) into a single fan. */ +/* */ +/* On entry, `farleft' and `innerleft' are bounding triangles of the left */ +/* triangulation. The origin of `farleft' is the leftmost vertex, and */ +/* the destination of `innerleft' is the rightmost vertex of the */ +/* triangulation. Similarly, `innerright' and `farright' are bounding */ +/* triangles of the right triangulation. The origin of `innerright' and */ +/* destination of `farright' are the leftmost and rightmost vertices. */ +/* */ +/* On completion, the origin of `farleft' is the leftmost vertex of the */ +/* merged triangulation, and the destination of `farright' is the rightmost */ +/* vertex. */ +/* */ +/*****************************************************************************/ + +#ifdef ANSI_DECLARATORS +void mergehulls(struct mesh *m, struct behavior *b, struct otri *farleft, + struct otri *innerleft, struct otri *innerright, + struct otri *farright, int axis) +#else /* not ANSI_DECLARATORS */ +void mergehulls(m, b, farleft, innerleft, innerright, farright, axis) +struct mesh *m; +struct behavior *b; +struct otri *farleft; +struct otri *innerleft; +struct otri *innerright; +struct otri *farright; +int axis; +#endif /* not ANSI_DECLARATORS */ + +{ + struct otri leftcand, rightcand; + struct otri baseedge; + struct otri nextedge; + struct otri sidecasing, topcasing, outercasing; + struct otri checkedge; + vertex innerleftdest; + vertex innerrightorg; + vertex innerleftapex, innerrightapex; + vertex farleftpt, farrightpt; + vertex farleftapex, farrightapex; + vertex lowerleft, lowerright; + vertex upperleft, upperright; + vertex nextapex; + vertex checkvertex; + int changemade; + int badedge; + int leftfinished, rightfinished; + triangle ptr; /* Temporary variable used by sym(). */ + + dest(*innerleft, innerleftdest); + apex(*innerleft, innerleftapex); + org(*innerright, innerrightorg); + apex(*innerright, innerrightapex); + /* Special treatment for horizontal cuts. */ + if (b->dwyer && (axis == 1)) { + org(*farleft, farleftpt); + apex(*farleft, farleftapex); + dest(*farright, farrightpt); + apex(*farright, farrightapex); + /* The pointers to the extremal vertices are shifted to point to the */ + /* topmost and bottommost vertex of each hull, rather than the */ + /* leftmost and rightmost vertices. */ + while (farleftapex[1] < farleftpt[1]) { + lnextself(*farleft); + symself(*farleft); + farleftpt = farleftapex; + apex(*farleft, farleftapex); + } + sym(*innerleft, checkedge); + apex(checkedge, checkvertex); + while (checkvertex[1] > innerleftdest[1]) { + lnext(checkedge, *innerleft); + innerleftapex = innerleftdest; + innerleftdest = checkvertex; + sym(*innerleft, checkedge); + apex(checkedge, checkvertex); + } + while (innerrightapex[1] < innerrightorg[1]) { + lnextself(*innerright); + symself(*innerright); + innerrightorg = innerrightapex; + apex(*innerright, innerrightapex); + } + sym(*farright, checkedge); + apex(checkedge, checkvertex); + while (checkvertex[1] > farrightpt[1]) { + lnext(checkedge, *farright); + farrightapex = farrightpt; + farrightpt = checkvertex; + sym(*farright, checkedge); + apex(checkedge, checkvertex); + } + } + /* Find a line tangent to and below both hulls. */ + do { + changemade = 0; + /* Make innerleftdest the "bottommost" vertex of the left hull. */ + if (counterclockwise(m, b, innerleftdest, innerleftapex, innerrightorg) > + 0.0) { + lprevself(*innerleft); + symself(*innerleft); + innerleftdest = innerleftapex; + apex(*innerleft, innerleftapex); + changemade = 1; + } + /* Make innerrightorg the "bottommost" vertex of the right hull. */ + if (counterclockwise(m, b, innerrightapex, innerrightorg, innerleftdest) > + 0.0) { + lnextself(*innerright); + symself(*innerright); + innerrightorg = innerrightapex; + apex(*innerright, innerrightapex); + changemade = 1; + } + } while (changemade); + /* Find the two candidates to be the next "gear tooth." */ + sym(*innerleft, leftcand); + sym(*innerright, rightcand); + /* Create the bottom new bounding triangle. */ + maketriangle(m, b, &baseedge); + /* Connect it to the bounding boxes of the left and right triangulations. */ + bond(baseedge, *innerleft); + lnextself(baseedge); + bond(baseedge, *innerright); + lnextself(baseedge); + setorg(baseedge, innerrightorg); + setdest(baseedge, innerleftdest); + /* Apex is intentionally left NULL. */ + if (b->verbose > 2) { + printf(" Creating base bounding "); + printtriangle(m, b, &baseedge); + } + /* Fix the extreme triangles if necessary. */ + org(*farleft, farleftpt); + if (innerleftdest == farleftpt) { + lnext(baseedge, *farleft); + } + dest(*farright, farrightpt); + if (innerrightorg == farrightpt) { + lprev(baseedge, *farright); + } + /* The vertices of the current knitting edge. */ + lowerleft = innerleftdest; + lowerright = innerrightorg; + /* The candidate vertices for knitting. */ + apex(leftcand, upperleft); + apex(rightcand, upperright); + /* Walk up the gap between the two triangulations, knitting them together. */ + while (1) { + /* Have we reached the top? (This isn't quite the right question, */ + /* because even though the left triangulation might seem finished now, */ + /* moving up on the right triangulation might reveal a new vertex of */ + /* the left triangulation. And vice-versa.) */ + leftfinished = counterclockwise(m, b, upperleft, lowerleft, lowerright) <= + 0.0; + rightfinished = counterclockwise(m, b, upperright, lowerleft, lowerright) + <= 0.0; + if (leftfinished && rightfinished) { + /* Create the top new bounding triangle. */ + maketriangle(m, b, &nextedge); + setorg(nextedge, lowerleft); + setdest(nextedge, lowerright); + /* Apex is intentionally left NULL. */ + /* Connect it to the bounding boxes of the two triangulations. */ + bond(nextedge, baseedge); + lnextself(nextedge); + bond(nextedge, rightcand); + lnextself(nextedge); + bond(nextedge, leftcand); + if (b->verbose > 2) { + printf(" Creating top bounding "); + printtriangle(m, b, &nextedge); + } + /* Special treatment for horizontal cuts. */ + if (b->dwyer && (axis == 1)) { + org(*farleft, farleftpt); + apex(*farleft, farleftapex); + dest(*farright, farrightpt); + apex(*farright, farrightapex); + sym(*farleft, checkedge); + apex(checkedge, checkvertex); + /* The pointers to the extremal vertices are restored to the */ + /* leftmost and rightmost vertices (rather than topmost and */ + /* bottommost). */ + while (checkvertex[0] < farleftpt[0]) { + lprev(checkedge, *farleft); + farleftapex = farleftpt; + farleftpt = checkvertex; + sym(*farleft, checkedge); + apex(checkedge, checkvertex); + } + while (farrightapex[0] > farrightpt[0]) { + lprevself(*farright); + symself(*farright); + farrightpt = farrightapex; + apex(*farright, farrightapex); + } + } + return; + } + /* Consider eliminating edges from the left triangulation. */ + if (!leftfinished) { + /* What vertex would be exposed if an edge were deleted? */ + lprev(leftcand, nextedge); + symself(nextedge); + apex(nextedge, nextapex); + /* If nextapex is NULL, then no vertex would be exposed; the */ + /* triangulation would have been eaten right through. */ + if (nextapex != (vertex) NULL) { + /* Check whether the edge is Delaunay. */ + badedge = incircle(m, b, lowerleft, lowerright, upperleft, nextapex) > + 0.0; + while (badedge) { + /* Eliminate the edge with an edge flip. As a result, the */ + /* left triangulation will have one more boundary triangle. */ + lnextself(nextedge); + sym(nextedge, topcasing); + lnextself(nextedge); + sym(nextedge, sidecasing); + bond(nextedge, topcasing); + bond(leftcand, sidecasing); + lnextself(leftcand); + sym(leftcand, outercasing); + lprevself(nextedge); + bond(nextedge, outercasing); + /* Correct the vertices to reflect the edge flip. */ + setorg(leftcand, lowerleft); + setdest(leftcand, NULL); + setapex(leftcand, nextapex); + setorg(nextedge, NULL); + setdest(nextedge, upperleft); + setapex(nextedge, nextapex); + /* Consider the newly exposed vertex. */ + upperleft = nextapex; + /* What vertex would be exposed if another edge were deleted? */ + otricopy(sidecasing, nextedge); + apex(nextedge, nextapex); + if (nextapex != (vertex) NULL) { + /* Check whether the edge is Delaunay. */ + badedge = incircle(m, b, lowerleft, lowerright, upperleft, + nextapex) > 0.0; + } else { + /* Avoid eating right through the triangulation. */ + badedge = 0; + } + } + } + } + /* Consider eliminating edges from the right triangulation. */ + if (!rightfinished) { + /* What vertex would be exposed if an edge were deleted? */ + lnext(rightcand, nextedge); + symself(nextedge); + apex(nextedge, nextapex); + /* If nextapex is NULL, then no vertex would be exposed; the */ + /* triangulation would have been eaten right through. */ + if (nextapex != (vertex) NULL) { + /* Check whether the edge is Delaunay. */ + badedge = incircle(m, b, lowerleft, lowerright, upperright, nextapex) > + 0.0; + while (badedge) { + /* Eliminate the edge with an edge flip. As a result, the */ + /* right triangulation will have one more boundary triangle. */ + lprevself(nextedge); + sym(nextedge, topcasing); + lprevself(nextedge); + sym(nextedge, sidecasing); + bond(nextedge, topcasing); + bond(rightcand, sidecasing); + lprevself(rightcand); + sym(rightcand, outercasing); + lnextself(nextedge); + bond(nextedge, outercasing); + /* Correct the vertices to reflect the edge flip. */ + setorg(rightcand, NULL); + setdest(rightcand, lowerright); + setapex(rightcand, nextapex); + setorg(nextedge, upperright); + setdest(nextedge, NULL); + setapex(nextedge, nextapex); + /* Consider the newly exposed vertex. */ + upperright = nextapex; + /* What vertex would be exposed if another edge were deleted? */ + otricopy(sidecasing, nextedge); + apex(nextedge, nextapex); + if (nextapex != (vertex) NULL) { + /* Check whether the edge is Delaunay. */ + badedge = incircle(m, b, lowerleft, lowerright, upperright, + nextapex) > 0.0; + } else { + /* Avoid eating right through the triangulation. */ + badedge = 0; + } + } + } + } + if (leftfinished || (!rightfinished && + (incircle(m, b, upperleft, lowerleft, lowerright, upperright) > + 0.0))) { + /* Knit the triangulations, adding an edge from `lowerleft' */ + /* to `upperright'. */ + bond(baseedge, rightcand); + lprev(rightcand, baseedge); + setdest(baseedge, lowerleft); + lowerright = upperright; + sym(baseedge, rightcand); + apex(rightcand, upperright); + } else { + /* Knit the triangulations, adding an edge from `upperleft' */ + /* to `lowerright'. */ + bond(baseedge, leftcand); + lnext(leftcand, baseedge); + setorg(baseedge, lowerright); + lowerleft = upperleft; + sym(baseedge, leftcand); + apex(leftcand, upperleft); + } + if (b->verbose > 2) { + printf(" Connecting "); + printtriangle(m, b, &baseedge); + } + } +} + +/*****************************************************************************/ +/* */ +/* divconqrecurse() Recursively form a Delaunay triangulation by the */ +/* divide-and-conquer method. */ +/* */ +/* Recursively breaks down the problem into smaller pieces, which are */ +/* knitted together by mergehulls(). The base cases (problems of two or */ +/* three vertices) are handled specially here. */ +/* */ +/* On completion, `farleft' and `farright' are bounding triangles such that */ +/* the origin of `farleft' is the leftmost vertex (breaking ties by */ +/* choosing the highest leftmost vertex), and the destination of */ +/* `farright' is the rightmost vertex (breaking ties by choosing the */ +/* lowest rightmost vertex). */ +/* */ +/*****************************************************************************/ + +#ifdef ANSI_DECLARATORS +void divconqrecurse(struct mesh *m, struct behavior *b, vertex *sortarray, + int vertices, int axis, + struct otri *farleft, struct otri *farright) +#else /* not ANSI_DECLARATORS */ +void divconqrecurse(m, b, sortarray, vertices, axis, farleft, farright) +struct mesh *m; +struct behavior *b; +vertex *sortarray; +int vertices; +int axis; +struct otri *farleft; +struct otri *farright; +#endif /* not ANSI_DECLARATORS */ + +{ + struct otri midtri, tri1, tri2, tri3; + struct otri innerleft, innerright; + REAL area; + int divider; + + if (b->verbose > 2) { + printf(" Triangulating %d vertices.\n", vertices); + } + if (vertices == 2) { + /* The triangulation of two vertices is an edge. An edge is */ + /* represented by two bounding triangles. */ + maketriangle(m, b, farleft); + setorg(*farleft, sortarray[0]); + setdest(*farleft, sortarray[1]); + /* The apex is intentionally left NULL. */ + maketriangle(m, b, farright); + setorg(*farright, sortarray[1]); + setdest(*farright, sortarray[0]); + /* The apex is intentionally left NULL. */ + bond(*farleft, *farright); + lprevself(*farleft); + lnextself(*farright); + bond(*farleft, *farright); + lprevself(*farleft); + lnextself(*farright); + bond(*farleft, *farright); + if (b->verbose > 2) { + printf(" Creating "); + printtriangle(m, b, farleft); + printf(" Creating "); + printtriangle(m, b, farright); + } + /* Ensure that the origin of `farleft' is sortarray[0]. */ + lprev(*farright, *farleft); + return; + } else if (vertices == 3) { + /* The triangulation of three vertices is either a triangle (with */ + /* three bounding triangles) or two edges (with four bounding */ + /* triangles). In either case, four triangles are created. */ + maketriangle(m, b, &midtri); + maketriangle(m, b, &tri1); + maketriangle(m, b, &tri2); + maketriangle(m, b, &tri3); + area = counterclockwise(m, b, sortarray[0], sortarray[1], sortarray[2]); + if (area == 0.0) { + /* Three collinear vertices; the triangulation is two edges. */ + setorg(midtri, sortarray[0]); + setdest(midtri, sortarray[1]); + setorg(tri1, sortarray[1]); + setdest(tri1, sortarray[0]); + setorg(tri2, sortarray[2]); + setdest(tri2, sortarray[1]); + setorg(tri3, sortarray[1]); + setdest(tri3, sortarray[2]); + /* All apices are intentionally left NULL. */ + bond(midtri, tri1); + bond(tri2, tri3); + lnextself(midtri); + lprevself(tri1); + lnextself(tri2); + lprevself(tri3); + bond(midtri, tri3); + bond(tri1, tri2); + lnextself(midtri); + lprevself(tri1); + lnextself(tri2); + lprevself(tri3); + bond(midtri, tri1); + bond(tri2, tri3); + /* Ensure that the origin of `farleft' is sortarray[0]. */ + otricopy(tri1, *farleft); + /* Ensure that the destination of `farright' is sortarray[2]. */ + otricopy(tri2, *farright); + } else { + /* The three vertices are not collinear; the triangulation is one */ + /* triangle, namely `midtri'. */ + setorg(midtri, sortarray[0]); + setdest(tri1, sortarray[0]); + setorg(tri3, sortarray[0]); + /* Apices of tri1, tri2, and tri3 are left NULL. */ + if (area > 0.0) { + /* The vertices are in counterclockwise order. */ + setdest(midtri, sortarray[1]); + setorg(tri1, sortarray[1]); + setdest(tri2, sortarray[1]); + setapex(midtri, sortarray[2]); + setorg(tri2, sortarray[2]); + setdest(tri3, sortarray[2]); + } else { + /* The vertices are in clockwise order. */ + setdest(midtri, sortarray[2]); + setorg(tri1, sortarray[2]); + setdest(tri2, sortarray[2]); + setapex(midtri, sortarray[1]); + setorg(tri2, sortarray[1]); + setdest(tri3, sortarray[1]); + } + /* The topology does not depend on how the vertices are ordered. */ + bond(midtri, tri1); + lnextself(midtri); + bond(midtri, tri2); + lnextself(midtri); + bond(midtri, tri3); + lprevself(tri1); + lnextself(tri2); + bond(tri1, tri2); + lprevself(tri1); + lprevself(tri3); + bond(tri1, tri3); + lnextself(tri2); + lprevself(tri3); + bond(tri2, tri3); + /* Ensure that the origin of `farleft' is sortarray[0]. */ + otricopy(tri1, *farleft); + /* Ensure that the destination of `farright' is sortarray[2]. */ + if (area > 0.0) { + otricopy(tri2, *farright); + } else { + lnext(*farleft, *farright); + } + } + if (b->verbose > 2) { + printf(" Creating "); + printtriangle(m, b, &midtri); + printf(" Creating "); + printtriangle(m, b, &tri1); + printf(" Creating "); + printtriangle(m, b, &tri2); + printf(" Creating "); + printtriangle(m, b, &tri3); + } + return; + } else { + /* Split the vertices in half. */ + divider = vertices >> 1; + /* Recursively triangulate each half. */ + divconqrecurse(m, b, sortarray, divider, 1 - axis, farleft, &innerleft); + divconqrecurse(m, b, &sortarray[divider], vertices - divider, 1 - axis, + &innerright, farright); + if (b->verbose > 1) { + printf(" Joining triangulations with %d and %d vertices.\n", divider, + vertices - divider); + } + /* Merge the two triangulations into one. */ + mergehulls(m, b, farleft, &innerleft, &innerright, farright, axis); + } +} + +#ifdef ANSI_DECLARATORS +long removeghosts(struct mesh *m, struct behavior *b, struct otri *startghost) +#else /* not ANSI_DECLARATORS */ +long removeghosts(m, b, startghost) +struct mesh *m; +struct behavior *b; +struct otri *startghost; +#endif /* not ANSI_DECLARATORS */ + +{ + struct otri searchedge; + struct otri dissolveedge; + struct otri deadtriangle; + vertex markorg; + long hullsize; + triangle ptr; /* Temporary variable used by sym(). */ + + if (b->verbose) { + printf(" Removing ghost triangles.\n"); + } + /* Find an edge on the convex hull to start point location from. */ + lprev(*startghost, searchedge); + symself(searchedge); + m->dummytri[0] = encode(searchedge); + /* Remove the bounding box and count the convex hull edges. */ + otricopy(*startghost, dissolveedge); + hullsize = 0; + do { + hullsize++; + lnext(dissolveedge, deadtriangle); + lprevself(dissolveedge); + symself(dissolveedge); + /* If no PSLG is involved, set the boundary markers of all the vertices */ + /* on the convex hull. If a PSLG is used, this step is done later. */ + if (!b->poly) { + /* Watch out for the case where all the input vertices are collinear. */ + if (dissolveedge.tri != m->dummytri) { + org(dissolveedge, markorg); + if (vertexmark(markorg) == 0) { + setvertexmark(markorg, 1); + } + } + } + /* Remove a bounding triangle from a convex hull triangle. */ + dissolve(dissolveedge); + /* Find the next bounding triangle. */ + sym(deadtriangle, dissolveedge); + /* Delete the bounding triangle. */ + triangledealloc(m, deadtriangle.tri); + } while (!otriequal(dissolveedge, *startghost)); + return hullsize; +} + +/*****************************************************************************/ +/* */ +/* divconqdelaunay() Form a Delaunay triangulation by the divide-and- */ +/* conquer method. */ +/* */ +/* Sorts the vertices, calls a recursive procedure to triangulate them, and */ +/* removes the bounding box, setting boundary markers as appropriate. */ +/* */ +/*****************************************************************************/ + +#ifdef ANSI_DECLARATORS +long divconqdelaunay(struct mesh *m, struct behavior *b) +#else /* not ANSI_DECLARATORS */ +long divconqdelaunay(m, b) +struct mesh *m; +struct behavior *b; +#endif /* not ANSI_DECLARATORS */ + +{ + vertex *sortarray; + struct otri hullleft, hullright; + int divider; + int i, j; + + if (b->verbose) { + printf(" Sorting vertices.\n"); + } + + /* Allocate an array of pointers to vertices for sorting. */ + sortarray = (vertex *) trimalloc(m->invertices * (int) sizeof(vertex)); + traversalinit(&m->vertices); + for (i = 0; i < m->invertices; i++) { + sortarray[i] = vertextraverse(m); + } + /* Sort the vertices. */ + vertexsort(sortarray, m->invertices); + /* Discard duplicate vertices, which can really mess up the algorithm. */ + i = 0; + for (j = 1; j < m->invertices; j++) { + if ((sortarray[i][0] == sortarray[j][0]) + && (sortarray[i][1] == sortarray[j][1])) { + if (!b->quiet) { + printf( +"Warning: A duplicate vertex at (%.12g, %.12g) appeared and was ignored.\n", + sortarray[j][0], sortarray[j][1]); + } + setvertextype(sortarray[j], UNDEADVERTEX); + m->undeads++; + } else { + i++; + sortarray[i] = sortarray[j]; + } + } + i++; + if (b->dwyer) { + /* Re-sort the array of vertices to accommodate alternating cuts. */ + divider = i >> 1; + if (i - divider >= 2) { + if (divider >= 2) { + alternateaxes(sortarray, divider, 1); + } + alternateaxes(&sortarray[divider], i - divider, 1); + } + } + + if (b->verbose) { + printf(" Forming triangulation.\n"); + } + + /* Form the Delaunay triangulation. */ + divconqrecurse(m, b, sortarray, i, 0, &hullleft, &hullright); + trifree((VOID *) sortarray); + + return removeghosts(m, b, &hullleft); +} + +/** **/ +/** **/ +/********* Divide-and-conquer Delaunay triangulation ends here *********/ + +/********* Incremental Delaunay triangulation begins here *********/ +/** **/ +/** **/ + +/*****************************************************************************/ +/* */ +/* boundingbox() Form an "infinite" bounding triangle to insert vertices */ +/* into. */ +/* */ +/* The vertices at "infinity" are assigned finite coordinates, which are */ +/* used by the point location routines, but (mostly) ignored by the */ +/* Delaunay edge flip routines. */ +/* */ +/*****************************************************************************/ + +#ifndef REDUCED + +#ifdef ANSI_DECLARATORS +void boundingbox(struct mesh *m, struct behavior *b) +#else /* not ANSI_DECLARATORS */ +void boundingbox(m, b) +struct mesh *m; +struct behavior *b; +#endif /* not ANSI_DECLARATORS */ + +{ + struct otri inftri; /* Handle for the triangular bounding box. */ + REAL width; + + if (b->verbose) { + printf(" Creating triangular bounding box.\n"); + } + /* Find the width (or height, whichever is larger) of the triangulation. */ + width = m->xmax - m->xmin; + if (m->ymax - m->ymin > width) { + width = m->ymax - m->ymin; + } + if (width == 0.0) { + width = 1.0; + } + /* Create the vertices of the bounding box. */ + m->infvertex1 = (vertex) trimalloc(m->vertices.itembytes); + m->infvertex2 = (vertex) trimalloc(m->vertices.itembytes); + m->infvertex3 = (vertex) trimalloc(m->vertices.itembytes); + m->infvertex1[0] = m->xmin - 50.0 * width; + m->infvertex1[1] = m->ymin - 40.0 * width; + m->infvertex2[0] = m->xmax + 50.0 * width; + m->infvertex2[1] = m->ymin - 40.0 * width; + m->infvertex3[0] = 0.5 * (m->xmin + m->xmax); + m->infvertex3[1] = m->ymax + 60.0 * width; + + /* Create the bounding box. */ + maketriangle(m, b, &inftri); + setorg(inftri, m->infvertex1); + setdest(inftri, m->infvertex2); + setapex(inftri, m->infvertex3); + /* Link dummytri to the bounding box so we can always find an */ + /* edge to begin searching (point location) from. */ + m->dummytri[0] = (triangle) inftri.tri; + if (b->verbose > 2) { + printf(" Creating "); + printtriangle(m, b, &inftri); + } +} + +#endif /* not REDUCED */ + +/*****************************************************************************/ +/* */ +/* removebox() Remove the "infinite" bounding triangle, setting boundary */ +/* markers as appropriate. */ +/* */ +/* The triangular bounding box has three boundary triangles (one for each */ +/* side of the bounding box), and a bunch of triangles fanning out from */ +/* the three bounding box vertices (one triangle for each edge of the */ +/* convex hull of the inner mesh). This routine removes these triangles. */ +/* */ +/* Returns the number of edges on the convex hull of the triangulation. */ +/* */ +/*****************************************************************************/ + +#ifndef REDUCED + +#ifdef ANSI_DECLARATORS +long removebox(struct mesh *m, struct behavior *b) +#else /* not ANSI_DECLARATORS */ +long removebox(m, b) +struct mesh *m; +struct behavior *b; +#endif /* not ANSI_DECLARATORS */ + +{ + struct otri deadtriangle; + struct otri searchedge; + struct otri checkedge; + struct otri nextedge, finaledge, dissolveedge; + vertex markorg; + long hullsize; + triangle ptr; /* Temporary variable used by sym(). */ + + if (b->verbose) { + printf(" Removing triangular bounding box.\n"); + } + /* Find a boundary triangle. */ + nextedge.tri = m->dummytri; + nextedge.orient = 0; + symself(nextedge); + /* Mark a place to stop. */ + lprev(nextedge, finaledge); + lnextself(nextedge); + symself(nextedge); + /* Find a triangle (on the boundary of the vertex set) that isn't */ + /* a bounding box triangle. */ + lprev(nextedge, searchedge); + symself(searchedge); + /* Check whether nextedge is another boundary triangle */ + /* adjacent to the first one. */ + lnext(nextedge, checkedge); + symself(checkedge); + if (checkedge.tri == m->dummytri) { + /* Go on to the next triangle. There are only three boundary */ + /* triangles, and this next triangle cannot be the third one, */ + /* so it's safe to stop here. */ + lprevself(searchedge); + symself(searchedge); + } + /* Find a new boundary edge to search from, as the current search */ + /* edge lies on a bounding box triangle and will be deleted. */ + m->dummytri[0] = encode(searchedge); + hullsize = -2l; + while (!otriequal(nextedge, finaledge)) { + hullsize++; + lprev(nextedge, dissolveedge); + symself(dissolveedge); + /* If not using a PSLG, the vertices should be marked now. */ + /* (If using a PSLG, markhull() will do the job.) */ + if (!b->poly) { + /* Be careful! One must check for the case where all the input */ + /* vertices are collinear, and thus all the triangles are part of */ + /* the bounding box. Otherwise, the setvertexmark() call below */ + /* will cause a bad pointer reference. */ + if (dissolveedge.tri != m->dummytri) { + org(dissolveedge, markorg); + if (vertexmark(markorg) == 0) { + setvertexmark(markorg, 1); + } + } + } + /* Disconnect the bounding box triangle from the mesh triangle. */ + dissolve(dissolveedge); + lnext(nextedge, deadtriangle); + sym(deadtriangle, nextedge); + /* Get rid of the bounding box triangle. */ + triangledealloc(m, deadtriangle.tri); + /* Do we need to turn the corner? */ + if (nextedge.tri == m->dummytri) { + /* Turn the corner. */ + otricopy(dissolveedge, nextedge); + } + } + triangledealloc(m, finaledge.tri); + + trifree((VOID *) m->infvertex1); /* Deallocate the bounding box vertices. */ + trifree((VOID *) m->infvertex2); + trifree((VOID *) m->infvertex3); + + return hullsize; +} + +#endif /* not REDUCED */ + +/*****************************************************************************/ +/* */ +/* incrementaldelaunay() Form a Delaunay triangulation by incrementally */ +/* inserting vertices. */ +/* */ +/* Returns the number of edges on the convex hull of the triangulation. */ +/* */ +/*****************************************************************************/ + +#ifndef REDUCED + +#ifdef ANSI_DECLARATORS +long incrementaldelaunay(struct mesh *m, struct behavior *b) +#else /* not ANSI_DECLARATORS */ +long incrementaldelaunay(m, b) +struct mesh *m; +struct behavior *b; +#endif /* not ANSI_DECLARATORS */ + +{ + struct otri starttri; + vertex vertexloop; + + /* Create a triangular bounding box. */ + boundingbox(m, b); + if (b->verbose) { + printf(" Incrementally inserting vertices.\n"); + } + traversalinit(&m->vertices); + vertexloop = vertextraverse(m); + while (vertexloop != (vertex) NULL) { + starttri.tri = m->dummytri; + if (insertvertex(m, b, vertexloop, &starttri, (struct osub *) NULL, 0, 0, + 0.0) == DUPLICATEVERTEX) { + if (!b->quiet) { + printf( +"Warning: A duplicate vertex at (%.12g, %.12g) appeared and was ignored.\n", + vertexloop[0], vertexloop[1]); + } + setvertextype(vertexloop, UNDEADVERTEX); + m->undeads++; + } + vertexloop = vertextraverse(m); + } + /* Remove the bounding box. */ + return removebox(m, b); +} + +#endif /* not REDUCED */ + +/** **/ +/** **/ +/********* Incremental Delaunay triangulation ends here *********/ + +/********* Sweepline Delaunay triangulation begins here *********/ +/** **/ +/** **/ + +#ifndef REDUCED + +#ifdef ANSI_DECLARATORS +void eventheapinsert(struct event **heap, int heapsize, struct event *newevent) +#else /* not ANSI_DECLARATORS */ +void eventheapinsert(heap, heapsize, newevent) +struct event **heap; +int heapsize; +struct event *newevent; +#endif /* not ANSI_DECLARATORS */ + +{ + REAL eventx, eventy; + int eventnum; + int parent; + int notdone; + + eventx = newevent->xkey; + eventy = newevent->ykey; + eventnum = heapsize; + notdone = eventnum > 0; + while (notdone) { + parent = (eventnum - 1) >> 1; + if ((heap[parent]->ykey < eventy) || + ((heap[parent]->ykey == eventy) + && (heap[parent]->xkey <= eventx))) { + notdone = 0; + } else { + heap[eventnum] = heap[parent]; + heap[eventnum]->heapposition = eventnum; + + eventnum = parent; + notdone = eventnum > 0; + } + } + heap[eventnum] = newevent; + newevent->heapposition = eventnum; +} + +#endif /* not REDUCED */ + +#ifndef REDUCED + +#ifdef ANSI_DECLARATORS +void eventheapify(struct event **heap, int heapsize, int eventnum) +#else /* not ANSI_DECLARATORS */ +void eventheapify(heap, heapsize, eventnum) +struct event **heap; +int heapsize; +int eventnum; +#endif /* not ANSI_DECLARATORS */ + +{ + struct event *thisevent; + REAL eventx, eventy; + int leftchild, rightchild; + int smallest; + int notdone; + + thisevent = heap[eventnum]; + eventx = thisevent->xkey; + eventy = thisevent->ykey; + leftchild = 2 * eventnum + 1; + notdone = leftchild < heapsize; + while (notdone) { + if ((heap[leftchild]->ykey < eventy) || + ((heap[leftchild]->ykey == eventy) + && (heap[leftchild]->xkey < eventx))) { + smallest = leftchild; + } else { + smallest = eventnum; + } + rightchild = leftchild + 1; + if (rightchild < heapsize) { + if ((heap[rightchild]->ykey < heap[smallest]->ykey) || + ((heap[rightchild]->ykey == heap[smallest]->ykey) + && (heap[rightchild]->xkey < heap[smallest]->xkey))) { + smallest = rightchild; + } + } + if (smallest == eventnum) { + notdone = 0; + } else { + heap[eventnum] = heap[smallest]; + heap[eventnum]->heapposition = eventnum; + heap[smallest] = thisevent; + thisevent->heapposition = smallest; + + eventnum = smallest; + leftchild = 2 * eventnum + 1; + notdone = leftchild < heapsize; + } + } +} + +#endif /* not REDUCED */ + +#ifndef REDUCED + +#ifdef ANSI_DECLARATORS +void eventheapdelete(struct event **heap, int heapsize, int eventnum) +#else /* not ANSI_DECLARATORS */ +void eventheapdelete(heap, heapsize, eventnum) +struct event **heap; +int heapsize; +int eventnum; +#endif /* not ANSI_DECLARATORS */ + +{ + struct event *moveevent; + REAL eventx, eventy; + int parent; + int notdone; + + moveevent = heap[heapsize - 1]; + if (eventnum > 0) { + eventx = moveevent->xkey; + eventy = moveevent->ykey; + do { + parent = (eventnum - 1) >> 1; + if ((heap[parent]->ykey < eventy) || + ((heap[parent]->ykey == eventy) + && (heap[parent]->xkey <= eventx))) { + notdone = 0; + } else { + heap[eventnum] = heap[parent]; + heap[eventnum]->heapposition = eventnum; + + eventnum = parent; + notdone = eventnum > 0; + } + } while (notdone); + } + heap[eventnum] = moveevent; + moveevent->heapposition = eventnum; + eventheapify(heap, heapsize - 1, eventnum); +} + +#endif /* not REDUCED */ + +#ifndef REDUCED + +#ifdef ANSI_DECLARATORS +void createeventheap(struct mesh *m, struct event ***eventheap, + struct event **events, struct event **freeevents) +#else /* not ANSI_DECLARATORS */ +void createeventheap(m, eventheap, events, freeevents) +struct mesh *m; +struct event ***eventheap; +struct event **events; +struct event **freeevents; +#endif /* not ANSI_DECLARATORS */ + +{ + vertex thisvertex; + int maxevents; + int i; + + maxevents = (3 * m->invertices) / 2; + *eventheap = (struct event **) + trimalloc(maxevents * (int) sizeof(struct event *)); + *events = (struct event *) trimalloc(maxevents * (int) sizeof(struct event)); + traversalinit(&m->vertices); + for (i = 0; i < m->invertices; i++) { + thisvertex = vertextraverse(m); + (*events)[i].eventptr = (VOID *) thisvertex; + (*events)[i].xkey = thisvertex[0]; + (*events)[i].ykey = thisvertex[1]; + eventheapinsert(*eventheap, i, *events + i); + } + *freeevents = (struct event *) NULL; + for (i = maxevents - 1; i >= m->invertices; i--) { + (*events)[i].eventptr = (VOID *) *freeevents; + *freeevents = *events + i; + } +} + +#endif /* not REDUCED */ + +#ifndef REDUCED + +#ifdef ANSI_DECLARATORS +int rightofhyperbola(struct mesh *m, struct otri *fronttri, vertex newsite) +#else /* not ANSI_DECLARATORS */ +int rightofhyperbola(m, fronttri, newsite) +struct mesh *m; +struct otri *fronttri; +vertex newsite; +#endif /* not ANSI_DECLARATORS */ + +{ + vertex leftvertex, rightvertex; + REAL dxa, dya, dxb, dyb; + + m->hyperbolacount++; + + dest(*fronttri, leftvertex); + apex(*fronttri, rightvertex); + if ((leftvertex[1] < rightvertex[1]) || + ((leftvertex[1] == rightvertex[1]) && + (leftvertex[0] < rightvertex[0]))) { + if (newsite[0] >= rightvertex[0]) { + return 1; + } + } else { + if (newsite[0] <= leftvertex[0]) { + return 0; + } + } + dxa = leftvertex[0] - newsite[0]; + dya = leftvertex[1] - newsite[1]; + dxb = rightvertex[0] - newsite[0]; + dyb = rightvertex[1] - newsite[1]; + return dya * (dxb * dxb + dyb * dyb) > dyb * (dxa * dxa + dya * dya); +} + +#endif /* not REDUCED */ + +#ifndef REDUCED + +#ifdef ANSI_DECLARATORS +REAL circletop(struct mesh *m, vertex pa, vertex pb, vertex pc, REAL ccwabc) +#else /* not ANSI_DECLARATORS */ +REAL circletop(m, pa, pb, pc, ccwabc) +struct mesh *m; +vertex pa; +vertex pb; +vertex pc; +REAL ccwabc; +#endif /* not ANSI_DECLARATORS */ + +{ + REAL xac, yac, xbc, ybc, xab, yab; + REAL aclen2, bclen2, ablen2; + + m->circletopcount++; + + xac = pa[0] - pc[0]; + yac = pa[1] - pc[1]; + xbc = pb[0] - pc[0]; + ybc = pb[1] - pc[1]; + xab = pa[0] - pb[0]; + yab = pa[1] - pb[1]; + aclen2 = xac * xac + yac * yac; + bclen2 = xbc * xbc + ybc * ybc; + ablen2 = xab * xab + yab * yab; + return pc[1] + (xac * bclen2 - xbc * aclen2 + sqrt(aclen2 * bclen2 * ablen2)) + / (2.0 * ccwabc); +} + +#endif /* not REDUCED */ + +#ifndef REDUCED + +#ifdef ANSI_DECLARATORS +void check4deadevent(struct otri *checktri, struct event **freeevents, + struct event **eventheap, int *heapsize) +#else /* not ANSI_DECLARATORS */ +void check4deadevent(checktri, freeevents, eventheap, heapsize) +struct otri *checktri; +struct event **freeevents; +struct event **eventheap; +int *heapsize; +#endif /* not ANSI_DECLARATORS */ + +{ + struct event *deadevent; + vertex eventvertex; + int eventnum; + + org(*checktri, eventvertex); + if (eventvertex != (vertex) NULL) { + deadevent = (struct event *) eventvertex; + eventnum = deadevent->heapposition; + deadevent->eventptr = (VOID *) *freeevents; + *freeevents = deadevent; + eventheapdelete(eventheap, *heapsize, eventnum); + (*heapsize)--; + setorg(*checktri, NULL); + } +} + +#endif /* not REDUCED */ + +#ifndef REDUCED + +#ifdef ANSI_DECLARATORS +struct splaynode *splay(struct mesh *m, struct splaynode *splaytree, + vertex searchpoint, struct otri *searchtri) +#else /* not ANSI_DECLARATORS */ +struct splaynode *splay(m, splaytree, searchpoint, searchtri) +struct mesh *m; +struct splaynode *splaytree; +vertex searchpoint; +struct otri *searchtri; +#endif /* not ANSI_DECLARATORS */ + +{ + struct splaynode *child, *grandchild; + struct splaynode *lefttree, *righttree; + struct splaynode *leftright; + vertex checkvertex; + int rightofroot, rightofchild; + + if (splaytree == (struct splaynode *) NULL) { + return (struct splaynode *) NULL; + } + dest(splaytree->keyedge, checkvertex); + if (checkvertex == splaytree->keydest) { + rightofroot = rightofhyperbola(m, &splaytree->keyedge, searchpoint); + if (rightofroot) { + otricopy(splaytree->keyedge, *searchtri); + child = splaytree->rchild; + } else { + child = splaytree->lchild; + } + if (child == (struct splaynode *) NULL) { + return splaytree; + } + dest(child->keyedge, checkvertex); + if (checkvertex != child->keydest) { + child = splay(m, child, searchpoint, searchtri); + if (child == (struct splaynode *) NULL) { + if (rightofroot) { + splaytree->rchild = (struct splaynode *) NULL; + } else { + splaytree->lchild = (struct splaynode *) NULL; + } + return splaytree; + } + } + rightofchild = rightofhyperbola(m, &child->keyedge, searchpoint); + if (rightofchild) { + otricopy(child->keyedge, *searchtri); + grandchild = splay(m, child->rchild, searchpoint, searchtri); + child->rchild = grandchild; + } else { + grandchild = splay(m, child->lchild, searchpoint, searchtri); + child->lchild = grandchild; + } + if (grandchild == (struct splaynode *) NULL) { + if (rightofroot) { + splaytree->rchild = child->lchild; + child->lchild = splaytree; + } else { + splaytree->lchild = child->rchild; + child->rchild = splaytree; + } + return child; + } + if (rightofchild) { + if (rightofroot) { + splaytree->rchild = child->lchild; + child->lchild = splaytree; + } else { + splaytree->lchild = grandchild->rchild; + grandchild->rchild = splaytree; + } + child->rchild = grandchild->lchild; + grandchild->lchild = child; + } else { + if (rightofroot) { + splaytree->rchild = grandchild->lchild; + grandchild->lchild = splaytree; + } else { + splaytree->lchild = child->rchild; + child->rchild = splaytree; + } + child->lchild = grandchild->rchild; + grandchild->rchild = child; + } + return grandchild; + } else { + lefttree = splay(m, splaytree->lchild, searchpoint, searchtri); + righttree = splay(m, splaytree->rchild, searchpoint, searchtri); + + pooldealloc(&m->splaynodes, (VOID *) splaytree); + if (lefttree == (struct splaynode *) NULL) { + return righttree; + } else if (righttree == (struct splaynode *) NULL) { + return lefttree; + } else if (lefttree->rchild == (struct splaynode *) NULL) { + lefttree->rchild = righttree->lchild; + righttree->lchild = lefttree; + return righttree; + } else if (righttree->lchild == (struct splaynode *) NULL) { + righttree->lchild = lefttree->rchild; + lefttree->rchild = righttree; + return lefttree; + } else { +/* printf("Holy Toledo!!!\n"); */ + leftright = lefttree->rchild; + while (leftright->rchild != (struct splaynode *) NULL) { + leftright = leftright->rchild; + } + leftright->rchild = righttree; + return lefttree; + } + } +} + +#endif /* not REDUCED */ + +#ifndef REDUCED + +#ifdef ANSI_DECLARATORS +struct splaynode *splayinsert(struct mesh *m, struct splaynode *splayroot, + struct otri *newkey, vertex searchpoint) +#else /* not ANSI_DECLARATORS */ +struct splaynode *splayinsert(m, splayroot, newkey, searchpoint) +struct mesh *m; +struct splaynode *splayroot; +struct otri *newkey; +vertex searchpoint; +#endif /* not ANSI_DECLARATORS */ + +{ + struct splaynode *newsplaynode; + + newsplaynode = (struct splaynode *) poolalloc(&m->splaynodes); + otricopy(*newkey, newsplaynode->keyedge); + dest(*newkey, newsplaynode->keydest); + if (splayroot == (struct splaynode *) NULL) { + newsplaynode->lchild = (struct splaynode *) NULL; + newsplaynode->rchild = (struct splaynode *) NULL; + } else if (rightofhyperbola(m, &splayroot->keyedge, searchpoint)) { + newsplaynode->lchild = splayroot; + newsplaynode->rchild = splayroot->rchild; + splayroot->rchild = (struct splaynode *) NULL; + } else { + newsplaynode->lchild = splayroot->lchild; + newsplaynode->rchild = splayroot; + splayroot->lchild = (struct splaynode *) NULL; + } + return newsplaynode; +} + +#endif /* not REDUCED */ + +#ifndef REDUCED + +#ifdef ANSI_DECLARATORS +struct splaynode *circletopinsert(struct mesh *m, struct behavior *b, + struct splaynode *splayroot, + struct otri *newkey, + vertex pa, vertex pb, vertex pc, REAL topy) +#else /* not ANSI_DECLARATORS */ +struct splaynode *circletopinsert(m, b, splayroot, newkey, pa, pb, pc, topy) +struct mesh *m; +struct behavior *b; +struct splaynode *splayroot; +struct otri *newkey; +vertex pa; +vertex pb; +vertex pc; +REAL topy; +#endif /* not ANSI_DECLARATORS */ + +{ + REAL ccwabc; + REAL xac, yac, xbc, ybc; + REAL aclen2, bclen2; + REAL searchpoint[2]; + struct otri dummytri; + + ccwabc = counterclockwise(m, b, pa, pb, pc); + xac = pa[0] - pc[0]; + yac = pa[1] - pc[1]; + xbc = pb[0] - pc[0]; + ybc = pb[1] - pc[1]; + aclen2 = xac * xac + yac * yac; + bclen2 = xbc * xbc + ybc * ybc; + searchpoint[0] = pc[0] - (yac * bclen2 - ybc * aclen2) / (2.0 * ccwabc); + searchpoint[1] = topy; + return splayinsert(m, splay(m, splayroot, (vertex) searchpoint, &dummytri), + newkey, (vertex) searchpoint); +} + +#endif /* not REDUCED */ + +#ifndef REDUCED + +#ifdef ANSI_DECLARATORS +struct splaynode *frontlocate(struct mesh *m, struct splaynode *splayroot, + struct otri *bottommost, vertex searchvertex, + struct otri *searchtri, int *farright) +#else /* not ANSI_DECLARATORS */ +struct splaynode *frontlocate(m, splayroot, bottommost, searchvertex, + searchtri, farright) +struct mesh *m; +struct splaynode *splayroot; +struct otri *bottommost; +vertex searchvertex; +struct otri *searchtri; +int *farright; +#endif /* not ANSI_DECLARATORS */ + +{ + int farrightflag; + triangle ptr; /* Temporary variable used by onext(). */ + + otricopy(*bottommost, *searchtri); + splayroot = splay(m, splayroot, searchvertex, searchtri); + + farrightflag = 0; + while (!farrightflag && rightofhyperbola(m, searchtri, searchvertex)) { + onextself(*searchtri); + farrightflag = otriequal(*searchtri, *bottommost); + } + *farright = farrightflag; + return splayroot; +} + +#endif /* not REDUCED */ + +#ifndef REDUCED + +#ifdef ANSI_DECLARATORS +long sweeplinedelaunay(struct mesh *m, struct behavior *b) +#else /* not ANSI_DECLARATORS */ +long sweeplinedelaunay(m, b) +struct mesh *m; +struct behavior *b; +#endif /* not ANSI_DECLARATORS */ + +{ + struct event **eventheap; + struct event *events; + struct event *freeevents; + struct event *nextevent; + struct event *newevent; + struct splaynode *splayroot; + struct otri bottommost; + struct otri searchtri; + struct otri fliptri; + struct otri lefttri, righttri, farlefttri, farrighttri; + struct otri inserttri; + vertex firstvertex, secondvertex; + vertex nextvertex, lastvertex; + vertex connectvertex; + vertex leftvertex, midvertex, rightvertex; + REAL lefttest, righttest; + int heapsize; + int check4events, farrightflag; + triangle ptr; /* Temporary variable used by sym(), onext(), and oprev(). */ + + poolinit(&m->splaynodes, sizeof(struct splaynode), SPLAYNODEPERBLOCK, + SPLAYNODEPERBLOCK, POINTER, 0); + splayroot = (struct splaynode *) NULL; + + if (b->verbose) { + printf(" Placing vertices in event heap.\n"); + } + createeventheap(m, &eventheap, &events, &freeevents); + heapsize = m->invertices; + + if (b->verbose) { + printf(" Forming triangulation.\n"); + } + maketriangle(m, b, &lefttri); + maketriangle(m, b, &righttri); + bond(lefttri, righttri); + lnextself(lefttri); + lprevself(righttri); + bond(lefttri, righttri); + lnextself(lefttri); + lprevself(righttri); + bond(lefttri, righttri); + firstvertex = (vertex) eventheap[0]->eventptr; + eventheap[0]->eventptr = (VOID *) freeevents; + freeevents = eventheap[0]; + eventheapdelete(eventheap, heapsize, 0); + heapsize--; + do { + if (heapsize == 0) { + printf("Error: Input vertices are all identical.\n"); + exit(1); + } + secondvertex = (vertex) eventheap[0]->eventptr; + eventheap[0]->eventptr = (VOID *) freeevents; + freeevents = eventheap[0]; + eventheapdelete(eventheap, heapsize, 0); + heapsize--; + if ((firstvertex[0] == secondvertex[0]) && + (firstvertex[1] == secondvertex[1])) { + if (!b->quiet) { + printf( +"Warning: A duplicate vertex at (%.12g, %.12g) appeared and was ignored.\n", + secondvertex[0], secondvertex[1]); + } + setvertextype(secondvertex, UNDEADVERTEX); + m->undeads++; + } + } while ((firstvertex[0] == secondvertex[0]) && + (firstvertex[1] == secondvertex[1])); + setorg(lefttri, firstvertex); + setdest(lefttri, secondvertex); + setorg(righttri, secondvertex); + setdest(righttri, firstvertex); + lprev(lefttri, bottommost); + lastvertex = secondvertex; + while (heapsize > 0) { + nextevent = eventheap[0]; + eventheapdelete(eventheap, heapsize, 0); + heapsize--; + check4events = 1; + if (nextevent->xkey < m->xmin) { + decode(nextevent->eventptr, fliptri); + oprev(fliptri, farlefttri); + check4deadevent(&farlefttri, &freeevents, eventheap, &heapsize); + onext(fliptri, farrighttri); + check4deadevent(&farrighttri, &freeevents, eventheap, &heapsize); + + if (otriequal(farlefttri, bottommost)) { + lprev(fliptri, bottommost); + } + flip(m, b, &fliptri); + setapex(fliptri, NULL); + lprev(fliptri, lefttri); + lnext(fliptri, righttri); + sym(lefttri, farlefttri); + + if (randomnation(SAMPLERATE) == 0) { + symself(fliptri); + dest(fliptri, leftvertex); + apex(fliptri, midvertex); + org(fliptri, rightvertex); + splayroot = circletopinsert(m, b, splayroot, &lefttri, leftvertex, + midvertex, rightvertex, nextevent->ykey); + } + } else { + nextvertex = (vertex) nextevent->eventptr; + if ((nextvertex[0] == lastvertex[0]) && + (nextvertex[1] == lastvertex[1])) { + if (!b->quiet) { + printf( +"Warning: A duplicate vertex at (%.12g, %.12g) appeared and was ignored.\n", + nextvertex[0], nextvertex[1]); + } + setvertextype(nextvertex, UNDEADVERTEX); + m->undeads++; + check4events = 0; + } else { + lastvertex = nextvertex; + + splayroot = frontlocate(m, splayroot, &bottommost, nextvertex, + &searchtri, &farrightflag); +/* + otricopy(bottommost, searchtri); + farrightflag = 0; + while (!farrightflag && rightofhyperbola(m, &searchtri, nextvertex)) { + onextself(searchtri); + farrightflag = otriequal(searchtri, bottommost); + } +*/ + + check4deadevent(&searchtri, &freeevents, eventheap, &heapsize); + + otricopy(searchtri, farrighttri); + sym(searchtri, farlefttri); + maketriangle(m, b, &lefttri); + maketriangle(m, b, &righttri); + dest(farrighttri, connectvertex); + setorg(lefttri, connectvertex); + setdest(lefttri, nextvertex); + setorg(righttri, nextvertex); + setdest(righttri, connectvertex); + bond(lefttri, righttri); + lnextself(lefttri); + lprevself(righttri); + bond(lefttri, righttri); + lnextself(lefttri); + lprevself(righttri); + bond(lefttri, farlefttri); + bond(righttri, farrighttri); + if (!farrightflag && otriequal(farrighttri, bottommost)) { + otricopy(lefttri, bottommost); + } + + if (randomnation(SAMPLERATE) == 0) { + splayroot = splayinsert(m, splayroot, &lefttri, nextvertex); + } else if (randomnation(SAMPLERATE) == 0) { + lnext(righttri, inserttri); + splayroot = splayinsert(m, splayroot, &inserttri, nextvertex); + } + } + } + nextevent->eventptr = (VOID *) freeevents; + freeevents = nextevent; + + if (check4events) { + apex(farlefttri, leftvertex); + dest(lefttri, midvertex); + apex(lefttri, rightvertex); + lefttest = counterclockwise(m, b, leftvertex, midvertex, rightvertex); + if (lefttest > 0.0) { + newevent = freeevents; + freeevents = (struct event *) freeevents->eventptr; + newevent->xkey = m->xminextreme; + newevent->ykey = circletop(m, leftvertex, midvertex, rightvertex, + lefttest); + newevent->eventptr = (VOID *) encode(lefttri); + eventheapinsert(eventheap, heapsize, newevent); + heapsize++; + setorg(lefttri, newevent); + } + apex(righttri, leftvertex); + org(righttri, midvertex); + apex(farrighttri, rightvertex); + righttest = counterclockwise(m, b, leftvertex, midvertex, rightvertex); + if (righttest > 0.0) { + newevent = freeevents; + freeevents = (struct event *) freeevents->eventptr; + newevent->xkey = m->xminextreme; + newevent->ykey = circletop(m, leftvertex, midvertex, rightvertex, + righttest); + newevent->eventptr = (VOID *) encode(farrighttri); + eventheapinsert(eventheap, heapsize, newevent); + heapsize++; + setorg(farrighttri, newevent); + } + } + } + + pooldeinit(&m->splaynodes); + lprevself(bottommost); + return removeghosts(m, b, &bottommost); +} + +#endif /* not REDUCED */ + +/** **/ +/** **/ +/********* Sweepline Delaunay triangulation ends here *********/ + +/********* General mesh construction routines begin here *********/ +/** **/ +/** **/ + +/*****************************************************************************/ +/* */ +/* delaunay() Form a Delaunay triangulation. */ +/* */ +/*****************************************************************************/ + +#ifdef ANSI_DECLARATORS +long delaunay(struct mesh *m, struct behavior *b) +#else /* not ANSI_DECLARATORS */ +long delaunay(m, b) +struct mesh *m; +struct behavior *b; +#endif /* not ANSI_DECLARATORS */ + +{ + long hulledges; + + m->eextras = 0; + initializetrisubpools(m, b); + +#ifdef REDUCED + if (!b->quiet) { + printf( + "Constructing Delaunay triangulation by divide-and-conquer method.\n"); + } + hulledges = divconqdelaunay(m, b); +#else /* not REDUCED */ + if (!b->quiet) { + printf("Constructing Delaunay triangulation "); + if (b->incremental) { + printf("by incremental method.\n"); + } else if (b->sweepline) { + printf("by sweepline method.\n"); + } else { + printf("by divide-and-conquer method.\n"); + } + } + if (b->incremental) { + hulledges = incrementaldelaunay(m, b); + } else if (b->sweepline) { + hulledges = sweeplinedelaunay(m, b); + } else { + hulledges = divconqdelaunay(m, b); + } +#endif /* not REDUCED */ + + if (m->triangles.items == 0) { + /* The input vertices were all collinear, so there are no triangles. */ + return 0l; + } else { + return hulledges; + } +} + +/*****************************************************************************/ +/* */ +/* reconstruct() Reconstruct a triangulation from its .ele (and possibly */ +/* .poly) file. Used when the -r switch is used. */ +/* */ +/* Reads an .ele file and reconstructs the original mesh. If the -p switch */ +/* is used, this procedure will also read a .poly file and reconstruct the */ +/* subsegments of the original mesh. If the -a switch is used, this */ +/* procedure will also read an .area file and set a maximum area constraint */ +/* on each triangle. */ +/* */ +/* Vertices that are not corners of triangles, such as nodes on edges of */ +/* subparametric elements, are discarded. */ +/* */ +/* This routine finds the adjacencies between triangles (and subsegments) */ +/* by forming one stack of triangles for each vertex. Each triangle is on */ +/* three different stacks simultaneously. Each triangle's subsegment */ +/* pointers are used to link the items in each stack. This memory-saving */ +/* feature makes the code harder to read. The most important thing to keep */ +/* in mind is that each triangle is removed from a stack precisely when */ +/* the corresponding pointer is adjusted to refer to a subsegment rather */ +/* than the next triangle of the stack. */ +/* */ +/*****************************************************************************/ + +#ifndef CDT_ONLY + +#ifdef TRILIBRARY + +#ifdef ANSI_DECLARATORS +int reconstruct(struct mesh *m, struct behavior *b, int *trianglelist, + REAL *triangleattriblist, REAL *trianglearealist, + int elements, int corners, int attribs, + int *segmentlist,int *segmentmarkerlist, int numberofsegments) +#else /* not ANSI_DECLARATORS */ +int reconstruct(m, b, trianglelist, triangleattriblist, trianglearealist, + elements, corners, attribs, segmentlist, segmentmarkerlist, + numberofsegments) +struct mesh *m; +struct behavior *b; +int *trianglelist; +REAL *triangleattriblist; +REAL *trianglearealist; +int elements; +int corners; +int attribs; +int *segmentlist; +int *segmentmarkerlist; +int numberofsegments; +#endif /* not ANSI_DECLARATORS */ + +#else /* not TRILIBRARY */ + +#ifdef ANSI_DECLARATORS +long reconstruct(struct mesh *m, struct behavior *b, char *elefilename, + char *areafilename, char *polyfilename, FILE *polyfile) +#else /* not ANSI_DECLARATORS */ +long reconstruct(m, b, elefilename, areafilename, polyfilename, polyfile) +struct mesh *m; +struct behavior *b; +char *elefilename; +char *areafilename; +char *polyfilename; +FILE *polyfile; +#endif /* not ANSI_DECLARATORS */ + +#endif /* not TRILIBRARY */ + +{ +#ifdef TRILIBRARY + int vertexindex; + int attribindex; +#else /* not TRILIBRARY */ + FILE *elefile; + FILE *areafile; + char inputline[INPUTLINESIZE]; + char *stringptr; + int areaelements; +#endif /* not TRILIBRARY */ + struct otri triangleloop; + struct otri triangleleft; + struct otri checktri; + struct otri checkleft; + struct otri checkneighbor; + struct osub subsegloop; + triangle *vertexarray; + triangle *prevlink; + triangle nexttri; + vertex tdest, tapex; + vertex checkdest, checkapex; + vertex shorg; + vertex killvertex; + REAL area; + int corner[3]; + int end[2]; + int killvertexindex; + int incorners; + int segmentmarkers; + int boundmarker; + int aroundvertex; + long hullsize; + int notfound; + long elementnumber, segmentnumber; + int i, j; + triangle ptr; /* Temporary variable used by sym(). */ + +#ifdef TRILIBRARY + m->inelements = elements; + incorners = corners; + if (incorners < 3) { + printf("Error: Triangles must have at least 3 vertices.\n"); + exit(1); + } + m->eextras = attribs; +#else /* not TRILIBRARY */ + /* Read the triangles from an .ele file. */ + if (!b->quiet) { + printf("Opening %s.\n", elefilename); + } + elefile = fopen(elefilename, "r"); + if (elefile == (FILE *) NULL) { + printf(" Error: Cannot access file %s.\n", elefilename); + exit(1); + } + /* Read number of triangles, number of vertices per triangle, and */ + /* number of triangle attributes from .ele file. */ + stringptr = readline(inputline, elefile, elefilename); + m->inelements = (int) strtol(stringptr, &stringptr, 0); + stringptr = findfield(stringptr); + if (*stringptr == '\0') { + incorners = 3; + } else { + incorners = (int) strtol(stringptr, &stringptr, 0); + if (incorners < 3) { + printf("Error: Triangles in %s must have at least 3 vertices.\n", + elefilename); + exit(1); + } + } + stringptr = findfield(stringptr); + if (*stringptr == '\0') { + m->eextras = 0; + } else { + m->eextras = (int) strtol(stringptr, &stringptr, 0); + } +#endif /* not TRILIBRARY */ + + initializetrisubpools(m, b); + + /* Create the triangles. */ + for (elementnumber = 1; elementnumber <= m->inelements; elementnumber++) { + maketriangle(m, b, &triangleloop); + /* Mark the triangle as living. */ + triangleloop.tri[3] = (triangle) triangleloop.tri; + } + + if (b->poly) { +#ifdef TRILIBRARY + m->insegments = numberofsegments; + segmentmarkers = segmentmarkerlist != (int *) NULL; +#else /* not TRILIBRARY */ + /* Read number of segments and number of segment */ + /* boundary markers from .poly file. */ + stringptr = readline(inputline, polyfile, b->inpolyfilename); + m->insegments = (int) strtol(stringptr, &stringptr, 0); + stringptr = findfield(stringptr); + if (*stringptr == '\0') { + segmentmarkers = 0; + } else { + segmentmarkers = (int) strtol(stringptr, &stringptr, 0); + } +#endif /* not TRILIBRARY */ + + /* Create the subsegments. */ + for (segmentnumber = 1; segmentnumber <= m->insegments; segmentnumber++) { + makesubseg(m, &subsegloop); + /* Mark the subsegment as living. */ + subsegloop.ss[2] = (subseg) subsegloop.ss; + } + } + +#ifdef TRILIBRARY + vertexindex = 0; + attribindex = 0; +#else /* not TRILIBRARY */ + if (b->vararea) { + /* Open an .area file, check for consistency with the .ele file. */ + if (!b->quiet) { + printf("Opening %s.\n", areafilename); + } + areafile = fopen(areafilename, "r"); + if (areafile == (FILE *) NULL) { + printf(" Error: Cannot access file %s.\n", areafilename); + exit(1); + } + stringptr = readline(inputline, areafile, areafilename); + areaelements = (int) strtol(stringptr, &stringptr, 0); + if (areaelements != m->inelements) { + printf("Error: %s and %s disagree on number of triangles.\n", + elefilename, areafilename); + exit(1); + } + } +#endif /* not TRILIBRARY */ + + if (!b->quiet) { + printf("Reconstructing mesh.\n"); + } + /* Allocate a temporary array that maps each vertex to some adjacent */ + /* triangle. I took care to allocate all the permanent memory for */ + /* triangles and subsegments first. */ + vertexarray = (triangle *) + trimalloc(m->vertices.items * (int) sizeof(triangle)); + /* Each vertex is initially unrepresented. */ + for (i = 0; i < m->vertices.items; i++) { + vertexarray[i] = (triangle) m->dummytri; + } + + if (b->verbose) { + printf(" Assembling triangles.\n"); + } + /* Read the triangles from the .ele file, and link */ + /* together those that share an edge. */ + traversalinit(&m->triangles); + triangleloop.tri = triangletraverse(m); + elementnumber = b->firstnumber; + while (triangleloop.tri != (triangle *) NULL) { +#ifdef TRILIBRARY + /* Copy the triangle's three corners. */ + for (j = 0; j < 3; j++) { + corner[j] = trianglelist[vertexindex++]; + if ((corner[j] < b->firstnumber) || + (corner[j] >= b->firstnumber + m->invertices)) { + printf("Error: Triangle %ld has an invalid vertex index.\n", + elementnumber); + exit(1); + } + } +#else /* not TRILIBRARY */ + /* Read triangle number and the triangle's three corners. */ + stringptr = readline(inputline, elefile, elefilename); + for (j = 0; j < 3; j++) { + stringptr = findfield(stringptr); + if (*stringptr == '\0') { + printf("Error: Triangle %ld is missing vertex %d in %s.\n", + elementnumber, j + 1, elefilename); + exit(1); + } else { + corner[j] = (int) strtol(stringptr, &stringptr, 0); + if ((corner[j] < b->firstnumber) || + (corner[j] >= b->firstnumber + m->invertices)) { + printf("Error: Triangle %ld has an invalid vertex index.\n", + elementnumber); + exit(1); + } + } + } +#endif /* not TRILIBRARY */ + + /* Find out about (and throw away) extra nodes. */ + for (j = 3; j < incorners; j++) { +#ifdef TRILIBRARY + killvertexindex = trianglelist[vertexindex++]; +#else /* not TRILIBRARY */ + stringptr = findfield(stringptr); + if (*stringptr != '\0') { + killvertexindex = (int) strtol(stringptr, &stringptr, 0); +#endif /* not TRILIBRARY */ + if ((killvertexindex >= b->firstnumber) && + (killvertexindex < b->firstnumber + m->invertices)) { + /* Delete the non-corner vertex if it's not already deleted. */ + killvertex = getvertex(m, b, killvertexindex); + if (vertextype(killvertex) != DEADVERTEX) { + vertexdealloc(m, killvertex); + } + } +#ifndef TRILIBRARY + } +#endif /* not TRILIBRARY */ + } + + /* Read the triangle's attributes. */ + for (j = 0; j < m->eextras; j++) { +#ifdef TRILIBRARY + setelemattribute(triangleloop, j, triangleattriblist[attribindex++]); +#else /* not TRILIBRARY */ + stringptr = findfield(stringptr); + if (*stringptr == '\0') { + setelemattribute(triangleloop, j, 0); + } else { + setelemattribute(triangleloop, j, + (REAL) strtod(stringptr, &stringptr)); + } +#endif /* not TRILIBRARY */ + } + + if (b->vararea) { +#ifdef TRILIBRARY + area = trianglearealist[elementnumber - b->firstnumber]; +#else /* not TRILIBRARY */ + /* Read an area constraint from the .area file. */ + stringptr = readline(inputline, areafile, areafilename); + stringptr = findfield(stringptr); + if (*stringptr == '\0') { + area = -1.0; /* No constraint on this triangle. */ + } else { + area = (REAL) strtod(stringptr, &stringptr); + } +#endif /* not TRILIBRARY */ + setareabound(triangleloop, area); + } + + /* Set the triangle's vertices. */ + triangleloop.orient = 0; + setorg(triangleloop, getvertex(m, b, corner[0])); + setdest(triangleloop, getvertex(m, b, corner[1])); + setapex(triangleloop, getvertex(m, b, corner[2])); + /* Try linking the triangle to others that share these vertices. */ + for (triangleloop.orient = 0; triangleloop.orient < 3; + triangleloop.orient++) { + /* Take the number for the origin of triangleloop. */ + aroundvertex = corner[triangleloop.orient]; + /* Look for other triangles having this vertex. */ + nexttri = vertexarray[aroundvertex - b->firstnumber]; + /* Link the current triangle to the next one in the stack. */ + triangleloop.tri[6 + triangleloop.orient] = nexttri; + /* Push the current triangle onto the stack. */ + vertexarray[aroundvertex - b->firstnumber] = encode(triangleloop); + decode(nexttri, checktri); + if (checktri.tri != m->dummytri) { + dest(triangleloop, tdest); + apex(triangleloop, tapex); + /* Look for other triangles that share an edge. */ + do { + dest(checktri, checkdest); + apex(checktri, checkapex); + if (tapex == checkdest) { + /* The two triangles share an edge; bond them together. */ + lprev(triangleloop, triangleleft); + bond(triangleleft, checktri); + } + if (tdest == checkapex) { + /* The two triangles share an edge; bond them together. */ + lprev(checktri, checkleft); + bond(triangleloop, checkleft); + } + /* Find the next triangle in the stack. */ + nexttri = checktri.tri[6 + checktri.orient]; + decode(nexttri, checktri); + } while (checktri.tri != m->dummytri); + } + } + triangleloop.tri = triangletraverse(m); + elementnumber++; + } + +#ifdef TRILIBRARY + vertexindex = 0; +#else /* not TRILIBRARY */ + fclose(elefile); + if (b->vararea) { + fclose(areafile); + } +#endif /* not TRILIBRARY */ + + hullsize = 0; /* Prepare to count the boundary edges. */ + if (b->poly) { + if (b->verbose) { + printf(" Marking segments in triangulation.\n"); + } + /* Read the segments from the .poly file, and link them */ + /* to their neighboring triangles. */ + boundmarker = 0; + traversalinit(&m->subsegs); + subsegloop.ss = subsegtraverse(m); + segmentnumber = b->firstnumber; + while (subsegloop.ss != (subseg *) NULL) { +#ifdef TRILIBRARY + end[0] = segmentlist[vertexindex++]; + end[1] = segmentlist[vertexindex++]; + if (segmentmarkers) { + boundmarker = segmentmarkerlist[segmentnumber - b->firstnumber]; + } +#else /* not TRILIBRARY */ + /* Read the endpoints of each segment, and possibly a boundary marker. */ + stringptr = readline(inputline, polyfile, b->inpolyfilename); + /* Skip the first (segment number) field. */ + stringptr = findfield(stringptr); + if (*stringptr == '\0') { + printf("Error: Segment %ld has no endpoints in %s.\n", segmentnumber, + polyfilename); + exit(1); + } else { + end[0] = (int) strtol(stringptr, &stringptr, 0); + } + stringptr = findfield(stringptr); + if (*stringptr == '\0') { + printf("Error: Segment %ld is missing its second endpoint in %s.\n", + segmentnumber, polyfilename); + exit(1); + } else { + end[1] = (int) strtol(stringptr, &stringptr, 0); + } + if (segmentmarkers) { + stringptr = findfield(stringptr); + if (*stringptr == '\0') { + boundmarker = 0; + } else { + boundmarker = (int) strtol(stringptr, &stringptr, 0); + } + } +#endif /* not TRILIBRARY */ + for (j = 0; j < 2; j++) { + if ((end[j] < b->firstnumber) || + (end[j] >= b->firstnumber + m->invertices)) { + printf("Error: Segment %ld has an invalid vertex index.\n", + segmentnumber); + exit(1); + } + } + + /* set the subsegment's vertices. */ + subsegloop.ssorient = 0; + setsorg(subsegloop, getvertex(m, b, end[0])); + setsdest(subsegloop, getvertex(m, b, end[1])); + setmark(subsegloop, boundmarker); + /* Try linking the subsegment to triangles that share these vertices. */ + for (subsegloop.ssorient = 0; subsegloop.ssorient < 2; + subsegloop.ssorient++) { + /* Take the number for the destination of subsegloop. */ + aroundvertex = end[1 - subsegloop.ssorient]; + /* Look for triangles having this vertex. */ + prevlink = &vertexarray[aroundvertex - b->firstnumber]; + nexttri = vertexarray[aroundvertex - b->firstnumber]; + decode(nexttri, checktri); + sorg(subsegloop, shorg); + notfound = 1; + /* Look for triangles having this edge. Note that I'm only */ + /* comparing each triangle's destination with the subsegment; */ + /* each triangle's apex is handled through a different vertex. */ + /* Because each triangle appears on three vertices' lists, each */ + /* occurrence of a triangle on a list can (and does) represent */ + /* an edge. In this way, most edges are represented twice, and */ + /* every triangle-subsegment bond is represented once. */ + while (notfound && (checktri.tri != m->dummytri)) { + dest(checktri, checkdest); + if (shorg == checkdest) { + /* We have a match. Remove this triangle from the list. */ + *prevlink = checktri.tri[6 + checktri.orient]; + /* Bond the subsegment to the triangle. */ + tsbond(checktri, subsegloop); + /* Check if this is a boundary edge. */ + sym(checktri, checkneighbor); + if (checkneighbor.tri == m->dummytri) { + /* The next line doesn't insert a subsegment (because there's */ + /* already one there), but it sets the boundary markers of */ + /* the existing subsegment and its vertices. */ + insertsubseg(m, b, &checktri, 1); + hullsize++; + } + notfound = 0; + } + /* Find the next triangle in the stack. */ + prevlink = &checktri.tri[6 + checktri.orient]; + nexttri = checktri.tri[6 + checktri.orient]; + decode(nexttri, checktri); + } + } + subsegloop.ss = subsegtraverse(m); + segmentnumber++; + } + } + + /* Mark the remaining edges as not being attached to any subsegment. */ + /* Also, count the (yet uncounted) boundary edges. */ + for (i = 0; i < m->vertices.items; i++) { + /* Search the stack of triangles adjacent to a vertex. */ + nexttri = vertexarray[i]; + decode(nexttri, checktri); + while (checktri.tri != m->dummytri) { + /* Find the next triangle in the stack before this */ + /* information gets overwritten. */ + nexttri = checktri.tri[6 + checktri.orient]; + /* No adjacent subsegment. (This overwrites the stack info.) */ + tsdissolve(checktri); + sym(checktri, checkneighbor); + if (checkneighbor.tri == m->dummytri) { + insertsubseg(m, b, &checktri, 1); + hullsize++; + } + decode(nexttri, checktri); + } + } + + trifree((VOID *) vertexarray); + return hullsize; +} + +#endif /* not CDT_ONLY */ + +/** **/ +/** **/ +/********* General mesh construction routines end here *********/ + +/********* Segment insertion begins here *********/ +/** **/ +/** **/ + +/*****************************************************************************/ +/* */ +/* finddirection() Find the first triangle on the path from one point */ +/* to another. */ +/* */ +/* Finds the triangle that intersects a line segment drawn from the */ +/* origin of `searchtri' to the point `searchpoint', and returns the result */ +/* in `searchtri'. The origin of `searchtri' does not change, even though */ +/* the triangle returned may differ from the one passed in. This routine */ +/* is used to find the direction to move in to get from one point to */ +/* another. */ +/* */ +/* The return value notes whether the destination or apex of the found */ +/* triangle is collinear with the two points in question. */ +/* */ +/*****************************************************************************/ + +#ifdef ANSI_DECLARATORS +enum finddirectionresult finddirection(struct mesh *m, struct behavior *b, + struct otri *searchtri, + vertex searchpoint) +#else /* not ANSI_DECLARATORS */ +enum finddirectionresult finddirection(m, b, searchtri, searchpoint) +struct mesh *m; +struct behavior *b; +struct otri *searchtri; +vertex searchpoint; +#endif /* not ANSI_DECLARATORS */ + +{ + struct otri checktri; + vertex startvertex; + vertex leftvertex, rightvertex; + REAL leftccw, rightccw; + int leftflag, rightflag; + triangle ptr; /* Temporary variable used by onext() and oprev(). */ + + org(*searchtri, startvertex); + dest(*searchtri, rightvertex); + apex(*searchtri, leftvertex); + /* Is `searchpoint' to the left? */ + leftccw = counterclockwise(m, b, searchpoint, startvertex, leftvertex); + leftflag = leftccw > 0.0; + /* Is `searchpoint' to the right? */ + rightccw = counterclockwise(m, b, startvertex, searchpoint, rightvertex); + rightflag = rightccw > 0.0; + if (leftflag && rightflag) { + /* `searchtri' faces directly away from `searchpoint'. We could go left */ + /* or right. Ask whether it's a triangle or a boundary on the left. */ + onext(*searchtri, checktri); + if (checktri.tri == m->dummytri) { + leftflag = 0; + } else { + rightflag = 0; + } + } + while (leftflag) { + /* Turn left until satisfied. */ + onextself(*searchtri); + if (searchtri->tri == m->dummytri) { + printf("Internal error in finddirection(): Unable to find a\n"); + printf(" triangle leading from (%.12g, %.12g) to", startvertex[0], + startvertex[1]); + printf(" (%.12g, %.12g).\n", searchpoint[0], searchpoint[1]); + internalerror(); + } + apex(*searchtri, leftvertex); + rightccw = leftccw; + leftccw = counterclockwise(m, b, searchpoint, startvertex, leftvertex); + leftflag = leftccw > 0.0; + } + while (rightflag) { + /* Turn right until satisfied. */ + oprevself(*searchtri); + if (searchtri->tri == m->dummytri) { + printf("Internal error in finddirection(): Unable to find a\n"); + printf(" triangle leading from (%.12g, %.12g) to", startvertex[0], + startvertex[1]); + printf(" (%.12g, %.12g).\n", searchpoint[0], searchpoint[1]); + internalerror(); + } + dest(*searchtri, rightvertex); + leftccw = rightccw; + rightccw = counterclockwise(m, b, startvertex, searchpoint, rightvertex); + rightflag = rightccw > 0.0; + } + if (leftccw == 0.0) { + return LEFTCOLLINEAR; + } else if (rightccw == 0.0) { + return RIGHTCOLLINEAR; + } else { + return WITHIN; + } +} + +/*****************************************************************************/ +/* */ +/* segmentintersection() Find the intersection of an existing segment */ +/* and a segment that is being inserted. Insert */ +/* a vertex at the intersection, splitting an */ +/* existing subsegment. */ +/* */ +/* The segment being inserted connects the apex of splittri to endpoint2. */ +/* splitsubseg is the subsegment being split, and MUST adjoin splittri. */ +/* Hence, endpoints of the subsegment being split are the origin and */ +/* destination of splittri. */ +/* */ +/* On completion, splittri is a handle having the newly inserted */ +/* intersection point as its origin, and endpoint1 as its destination. */ +/* */ +/*****************************************************************************/ + +#ifdef ANSI_DECLARATORS +void segmentintersection(struct mesh *m, struct behavior *b, + struct otri *splittri, struct osub *splitsubseg, + vertex endpoint2) +#else /* not ANSI_DECLARATORS */ +void segmentintersection(m, b, splittri, splitsubseg, endpoint2) +struct mesh *m; +struct behavior *b; +struct otri *splittri; +struct osub *splitsubseg; +vertex endpoint2; +#endif /* not ANSI_DECLARATORS */ + +{ + vertex endpoint1; + vertex torg, tdest; + vertex leftvertex, rightvertex; + vertex newvertex; + enum insertvertexresult success; + enum finddirectionresult collinear; + REAL ex, ey; + REAL tx, ty; + REAL etx, ety; + REAL split, denom; + int i; + triangle ptr; /* Temporary variable used by onext(). */ + + /* Find the other three segment endpoints. */ + apex(*splittri, endpoint1); + org(*splittri, torg); + dest(*splittri, tdest); + /* Segment intersection formulae; see the Antonio reference. */ + tx = tdest[0] - torg[0]; + ty = tdest[1] - torg[1]; + ex = endpoint2[0] - endpoint1[0]; + ey = endpoint2[1] - endpoint1[1]; + etx = torg[0] - endpoint2[0]; + ety = torg[1] - endpoint2[1]; + denom = ty * ex - tx * ey; + if (denom == 0.0) { + printf("Internal error in segmentintersection():"); + printf(" Attempt to find intersection of parallel segments.\n"); + internalerror(); + } + split = (ey * etx - ex * ety) / denom; + /* Create the new vertex. */ + newvertex = (vertex) poolalloc(&m->vertices); + /* Interpolate its coordinate and attributes. */ + for (i = 0; i < 2 + m->nextras; i++) { + newvertex[i] = torg[i] + split * (tdest[i] - torg[i]); + } + setvertexmark(newvertex, mark(*splitsubseg)); + setvertextype(newvertex, INPUTVERTEX); + if (b->verbose > 1) { + printf( + " Splitting subsegment (%.12g, %.12g) (%.12g, %.12g) at (%.12g, %.12g).\n", + torg[0], torg[1], tdest[0], tdest[1], newvertex[0], newvertex[1]); + } + /* Insert the intersection vertex. This should always succeed. */ + success = insertvertex(m, b, newvertex, splittri, splitsubseg, 0, 0, 0.0); + if (success != SUCCESSFULVERTEX) { + printf("Internal error in segmentintersection():\n"); + printf(" Failure to split a segment.\n"); + internalerror(); + } + if (m->steinerleft > 0) { + m->steinerleft--; + } + /* Inserting the vertex may have caused edge flips. We wish to rediscover */ + /* the edge connecting endpoint1 to the new intersection vertex. */ + collinear = finddirection(m, b, splittri, endpoint1); + dest(*splittri, rightvertex); + apex(*splittri, leftvertex); + if ((leftvertex[0] == endpoint1[0]) && (leftvertex[1] == endpoint1[1])) { + onextself(*splittri); + } else if ((rightvertex[0] != endpoint1[0]) || + (rightvertex[1] != endpoint1[1])) { + printf("Internal error in segmentintersection():\n"); + printf(" Topological inconsistency after splitting a segment.\n"); + internalerror(); + } + /* `splittri' should have destination endpoint1. */ +} + +/*****************************************************************************/ +/* */ +/* scoutsegment() Scout the first triangle on the path from one endpoint */ +/* to another, and check for completion (reaching the */ +/* second endpoint), a collinear vertex, or the */ +/* intersection of two segments. */ +/* */ +/* Returns one if the entire segment is successfully inserted, and zero if */ +/* the job must be finished by conformingedge() or constrainededge(). */ +/* */ +/* If the first triangle on the path has the second endpoint as its */ +/* destination or apex, a subsegment is inserted and the job is done. */ +/* */ +/* If the first triangle on the path has a destination or apex that lies on */ +/* the segment, a subsegment is inserted connecting the first endpoint to */ +/* the collinear vertex, and the search is continued from the collinear */ +/* vertex. */ +/* */ +/* If the first triangle on the path has a subsegment opposite its origin, */ +/* then there is a segment that intersects the segment being inserted. */ +/* Their intersection vertex is inserted, splitting the subsegment. */ +/* */ +/*****************************************************************************/ + +#ifdef ANSI_DECLARATORS +int scoutsegment(struct mesh *m, struct behavior *b, struct otri *searchtri, + vertex endpoint2, int newmark) +#else /* not ANSI_DECLARATORS */ +int scoutsegment(m, b, searchtri, endpoint2, newmark) +struct mesh *m; +struct behavior *b; +struct otri *searchtri; +vertex endpoint2; +int newmark; +#endif /* not ANSI_DECLARATORS */ + +{ + struct otri crosstri; + struct osub crosssubseg; + vertex leftvertex, rightvertex; + enum finddirectionresult collinear; + subseg sptr; /* Temporary variable used by tspivot(). */ + + collinear = finddirection(m, b, searchtri, endpoint2); + dest(*searchtri, rightvertex); + apex(*searchtri, leftvertex); + if (((leftvertex[0] == endpoint2[0]) && (leftvertex[1] == endpoint2[1])) || + ((rightvertex[0] == endpoint2[0]) && (rightvertex[1] == endpoint2[1]))) { + /* The segment is already an edge in the mesh. */ + if ((leftvertex[0] == endpoint2[0]) && (leftvertex[1] == endpoint2[1])) { + lprevself(*searchtri); + } + /* Insert a subsegment, if there isn't already one there. */ + insertsubseg(m, b, searchtri, newmark); + return 1; + } else if (collinear == LEFTCOLLINEAR) { + /* We've collided with a vertex between the segment's endpoints. */ + /* Make the collinear vertex be the triangle's origin. */ + lprevself(*searchtri); + insertsubseg(m, b, searchtri, newmark); + /* Insert the remainder of the segment. */ + return scoutsegment(m, b, searchtri, endpoint2, newmark); + } else if (collinear == RIGHTCOLLINEAR) { + /* We've collided with a vertex between the segment's endpoints. */ + insertsubseg(m, b, searchtri, newmark); + /* Make the collinear vertex be the triangle's origin. */ + lnextself(*searchtri); + /* Insert the remainder of the segment. */ + return scoutsegment(m, b, searchtri, endpoint2, newmark); + } else { + lnext(*searchtri, crosstri); + tspivot(crosstri, crosssubseg); + /* Check for a crossing segment. */ + if (crosssubseg.ss == m->dummysub) { + return 0; + } else { + /* Insert a vertex at the intersection. */ + segmentintersection(m, b, &crosstri, &crosssubseg, endpoint2); + otricopy(crosstri, *searchtri); + insertsubseg(m, b, searchtri, newmark); + /* Insert the remainder of the segment. */ + return scoutsegment(m, b, searchtri, endpoint2, newmark); + } + } +} + +/*****************************************************************************/ +/* */ +/* conformingedge() Force a segment into a conforming Delaunay */ +/* triangulation by inserting a vertex at its midpoint, */ +/* and recursively forcing in the two half-segments if */ +/* necessary. */ +/* */ +/* Generates a sequence of subsegments connecting `endpoint1' to */ +/* `endpoint2'. `newmark' is the boundary marker of the segment, assigned */ +/* to each new splitting vertex and subsegment. */ +/* */ +/* Note that conformingedge() does not always maintain the conforming */ +/* Delaunay property. Once inserted, segments are locked into place; */ +/* vertices inserted later (to force other segments in) may render these */ +/* fixed segments non-Delaunay. The conforming Delaunay property will be */ +/* restored by enforcequality() by splitting encroached subsegments. */ +/* */ +/*****************************************************************************/ + +#ifndef REDUCED +#ifndef CDT_ONLY + +#ifdef ANSI_DECLARATORS +void conformingedge(struct mesh *m, struct behavior *b, + vertex endpoint1, vertex endpoint2, int newmark) +#else /* not ANSI_DECLARATORS */ +void conformingedge(m, b, endpoint1, endpoint2, newmark) +struct mesh *m; +struct behavior *b; +vertex endpoint1; +vertex endpoint2; +int newmark; +#endif /* not ANSI_DECLARATORS */ + +{ + struct otri searchtri1, searchtri2; + struct osub brokensubseg; + vertex newvertex; + vertex midvertex1, midvertex2; + enum insertvertexresult success; + int i; + subseg sptr; /* Temporary variable used by tspivot(). */ + + if (b->verbose > 2) { + printf("Forcing segment into triangulation by recursive splitting:\n"); + printf(" (%.12g, %.12g) (%.12g, %.12g)\n", endpoint1[0], endpoint1[1], + endpoint2[0], endpoint2[1]); + } + /* Create a new vertex to insert in the middle of the segment. */ + newvertex = (vertex) poolalloc(&m->vertices); + /* Interpolate coordinates and attributes. */ + for (i = 0; i < 2 + m->nextras; i++) { + newvertex[i] = 0.5 * (endpoint1[i] + endpoint2[i]); + } + setvertexmark(newvertex, newmark); + setvertextype(newvertex, SEGMENTVERTEX); + /* No known triangle to search from. */ + searchtri1.tri = m->dummytri; + /* Attempt to insert the new vertex. */ + success = insertvertex(m, b, newvertex, &searchtri1, (struct osub *) NULL, + 0, 0, 0.0); + if (success == DUPLICATEVERTEX) { + if (b->verbose > 2) { + printf(" Segment intersects existing vertex (%.12g, %.12g).\n", + newvertex[0], newvertex[1]); + } + /* Use the vertex that's already there. */ + vertexdealloc(m, newvertex); + org(searchtri1, newvertex); + } else { + if (success == VIOLATINGVERTEX) { + if (b->verbose > 2) { + printf(" Two segments intersect at (%.12g, %.12g).\n", + newvertex[0], newvertex[1]); + } + /* By fluke, we've landed right on another segment. Split it. */ + tspivot(searchtri1, brokensubseg); + success = insertvertex(m, b, newvertex, &searchtri1, &brokensubseg, + 0, 0, 0.0); + if (success != SUCCESSFULVERTEX) { + printf("Internal error in conformingedge():\n"); + printf(" Failure to split a segment.\n"); + internalerror(); + } + } + /* The vertex has been inserted successfully. */ + if (m->steinerleft > 0) { + m->steinerleft--; + } + } + otricopy(searchtri1, searchtri2); + /* `searchtri1' and `searchtri2' are fastened at their origins to */ + /* `newvertex', and will be directed toward `endpoint1' and `endpoint2' */ + /* respectively. First, we must get `searchtri2' out of the way so it */ + /* won't be invalidated during the insertion of the first half of the */ + /* segment. */ + finddirection(m, b, &searchtri2, endpoint2); + if (!scoutsegment(m, b, &searchtri1, endpoint1, newmark)) { + /* The origin of searchtri1 may have changed if a collision with an */ + /* intervening vertex on the segment occurred. */ + org(searchtri1, midvertex1); + conformingedge(m, b, midvertex1, endpoint1, newmark); + } + if (!scoutsegment(m, b, &searchtri2, endpoint2, newmark)) { + /* The origin of searchtri2 may have changed if a collision with an */ + /* intervening vertex on the segment occurred. */ + org(searchtri2, midvertex2); + conformingedge(m, b, midvertex2, endpoint2, newmark); + } +} + +#endif /* not CDT_ONLY */ +#endif /* not REDUCED */ + +/*****************************************************************************/ +/* */ +/* delaunayfixup() Enforce the Delaunay condition at an edge, fanning out */ +/* recursively from an existing vertex. Pay special */ +/* attention to stacking inverted triangles. */ +/* */ +/* This is a support routine for inserting segments into a constrained */ +/* Delaunay triangulation. */ +/* */ +/* The origin of fixuptri is treated as if it has just been inserted, and */ +/* the local Delaunay condition needs to be enforced. It is only enforced */ +/* in one sector, however, that being the angular range defined by */ +/* fixuptri. */ +/* */ +/* This routine also needs to make decisions regarding the "stacking" of */ +/* triangles. (Read the description of constrainededge() below before */ +/* reading on here, so you understand the algorithm.) If the position of */ +/* the new vertex (the origin of fixuptri) indicates that the vertex before */ +/* it on the polygon is a reflex vertex, then "stack" the triangle by */ +/* doing nothing. (fixuptri is an inverted triangle, which is how stacked */ +/* triangles are identified.) */ +/* */ +/* Otherwise, check whether the vertex before that was a reflex vertex. */ +/* If so, perform an edge flip, thereby eliminating an inverted triangle */ +/* (popping it off the stack). The edge flip may result in the creation */ +/* of a new inverted triangle, depending on whether or not the new vertex */ +/* is visible to the vertex three edges behind on the polygon. */ +/* */ +/* If neither of the two vertices behind the new vertex are reflex */ +/* vertices, fixuptri and fartri, the triangle opposite it, are not */ +/* inverted; hence, ensure that the edge between them is locally Delaunay. */ +/* */ +/* `leftside' indicates whether or not fixuptri is to the left of the */ +/* segment being inserted. (Imagine that the segment is pointing up from */ +/* endpoint1 to endpoint2.) */ +/* */ +/*****************************************************************************/ + +#ifdef ANSI_DECLARATORS +void delaunayfixup(struct mesh *m, struct behavior *b, + struct otri *fixuptri, int leftside) +#else /* not ANSI_DECLARATORS */ +void delaunayfixup(m, b, fixuptri, leftside) +struct mesh *m; +struct behavior *b; +struct otri *fixuptri; +int leftside; +#endif /* not ANSI_DECLARATORS */ + +{ + struct otri neartri; + struct otri fartri; + struct osub faredge; + vertex nearvertex, leftvertex, rightvertex, farvertex; + triangle ptr; /* Temporary variable used by sym(). */ + subseg sptr; /* Temporary variable used by tspivot(). */ + + lnext(*fixuptri, neartri); + sym(neartri, fartri); + /* Check if the edge opposite the origin of fixuptri can be flipped. */ + if (fartri.tri == m->dummytri) { + return; + } + tspivot(neartri, faredge); + if (faredge.ss != m->dummysub) { + return; + } + /* Find all the relevant vertices. */ + apex(neartri, nearvertex); + org(neartri, leftvertex); + dest(neartri, rightvertex); + apex(fartri, farvertex); + /* Check whether the previous polygon vertex is a reflex vertex. */ + if (leftside) { + if (counterclockwise(m, b, nearvertex, leftvertex, farvertex) <= 0.0) { + /* leftvertex is a reflex vertex too. Nothing can */ + /* be done until a convex section is found. */ + return; + } + } else { + if (counterclockwise(m, b, farvertex, rightvertex, nearvertex) <= 0.0) { + /* rightvertex is a reflex vertex too. Nothing can */ + /* be done until a convex section is found. */ + return; + } + } + if (counterclockwise(m, b, rightvertex, leftvertex, farvertex) > 0.0) { + /* fartri is not an inverted triangle, and farvertex is not a reflex */ + /* vertex. As there are no reflex vertices, fixuptri isn't an */ + /* inverted triangle, either. Hence, test the edge between the */ + /* triangles to ensure it is locally Delaunay. */ + if (incircle(m, b, leftvertex, farvertex, rightvertex, nearvertex) <= + 0.0) { + return; + } + /* Not locally Delaunay; go on to an edge flip. */ + } /* else fartri is inverted; remove it from the stack by flipping. */ + flip(m, b, &neartri); + lprevself(*fixuptri); /* Restore the origin of fixuptri after the flip. */ + /* Recursively process the two triangles that result from the flip. */ + delaunayfixup(m, b, fixuptri, leftside); + delaunayfixup(m, b, &fartri, leftside); +} + +/*****************************************************************************/ +/* */ +/* constrainededge() Force a segment into a constrained Delaunay */ +/* triangulation by deleting the triangles it */ +/* intersects, and triangulating the polygons that */ +/* form on each side of it. */ +/* */ +/* Generates a single subsegment connecting `endpoint1' to `endpoint2'. */ +/* The triangle `starttri' has `endpoint1' as its origin. `newmark' is the */ +/* boundary marker of the segment. */ +/* */ +/* To insert a segment, every triangle whose interior intersects the */ +/* segment is deleted. The union of these deleted triangles is a polygon */ +/* (which is not necessarily monotone, but is close enough), which is */ +/* divided into two polygons by the new segment. This routine's task is */ +/* to generate the Delaunay triangulation of these two polygons. */ +/* */ +/* You might think of this routine's behavior as a two-step process. The */ +/* first step is to walk from endpoint1 to endpoint2, flipping each edge */ +/* encountered. This step creates a fan of edges connected to endpoint1, */ +/* including the desired edge to endpoint2. The second step enforces the */ +/* Delaunay condition on each side of the segment in an incremental manner: */ +/* proceeding along the polygon from endpoint1 to endpoint2 (this is done */ +/* independently on each side of the segment), each vertex is "enforced" */ +/* as if it had just been inserted, but affecting only the previous */ +/* vertices. The result is the same as if the vertices had been inserted */ +/* in the order they appear on the polygon, so the result is Delaunay. */ +/* */ +/* In truth, constrainededge() interleaves these two steps. The procedure */ +/* walks from endpoint1 to endpoint2, and each time an edge is encountered */ +/* and flipped, the newly exposed vertex (at the far end of the flipped */ +/* edge) is "enforced" upon the previously flipped edges, usually affecting */ +/* only one side of the polygon (depending upon which side of the segment */ +/* the vertex falls on). */ +/* */ +/* The algorithm is complicated by the need to handle polygons that are not */ +/* convex. Although the polygon is not necessarily monotone, it can be */ +/* triangulated in a manner similar to the stack-based algorithms for */ +/* monotone polygons. For each reflex vertex (local concavity) of the */ +/* polygon, there will be an inverted triangle formed by one of the edge */ +/* flips. (An inverted triangle is one with negative area - that is, its */ +/* vertices are arranged in clockwise order - and is best thought of as a */ +/* wrinkle in the fabric of the mesh.) Each inverted triangle can be */ +/* thought of as a reflex vertex pushed on the stack, waiting to be fixed */ +/* later. */ +/* */ +/* A reflex vertex is popped from the stack when a vertex is inserted that */ +/* is visible to the reflex vertex. (However, if the vertex behind the */ +/* reflex vertex is not visible to the reflex vertex, a new inverted */ +/* triangle will take its place on the stack.) These details are handled */ +/* by the delaunayfixup() routine above. */ +/* */ +/*****************************************************************************/ + +#ifdef ANSI_DECLARATORS +void constrainededge(struct mesh *m, struct behavior *b, + struct otri *starttri, vertex endpoint2, int newmark) +#else /* not ANSI_DECLARATORS */ +void constrainededge(m, b, starttri, endpoint2, newmark) +struct mesh *m; +struct behavior *b; +struct otri *starttri; +vertex endpoint2; +int newmark; +#endif /* not ANSI_DECLARATORS */ + +{ + struct otri fixuptri, fixuptri2; + struct osub crosssubseg; + vertex endpoint1; + vertex farvertex; + REAL area; + int collision; + int done; + triangle ptr; /* Temporary variable used by sym() and oprev(). */ + subseg sptr; /* Temporary variable used by tspivot(). */ + + org(*starttri, endpoint1); + lnext(*starttri, fixuptri); + flip(m, b, &fixuptri); + /* `collision' indicates whether we have found a vertex directly */ + /* between endpoint1 and endpoint2. */ + collision = 0; + done = 0; + do { + org(fixuptri, farvertex); + /* `farvertex' is the extreme point of the polygon we are "digging" */ + /* to get from endpoint1 to endpoint2. */ + if ((farvertex[0] == endpoint2[0]) && (farvertex[1] == endpoint2[1])) { + oprev(fixuptri, fixuptri2); + /* Enforce the Delaunay condition around endpoint2. */ + delaunayfixup(m, b, &fixuptri, 0); + delaunayfixup(m, b, &fixuptri2, 1); + done = 1; + } else { + /* Check whether farvertex is to the left or right of the segment */ + /* being inserted, to decide which edge of fixuptri to dig */ + /* through next. */ + area = counterclockwise(m, b, endpoint1, endpoint2, farvertex); + if (area == 0.0) { + /* We've collided with a vertex between endpoint1 and endpoint2. */ + collision = 1; + oprev(fixuptri, fixuptri2); + /* Enforce the Delaunay condition around farvertex. */ + delaunayfixup(m, b, &fixuptri, 0); + delaunayfixup(m, b, &fixuptri2, 1); + done = 1; + } else { + if (area > 0.0) { /* farvertex is to the left of the segment. */ + oprev(fixuptri, fixuptri2); + /* Enforce the Delaunay condition around farvertex, on the */ + /* left side of the segment only. */ + delaunayfixup(m, b, &fixuptri2, 1); + /* Flip the edge that crosses the segment. After the edge is */ + /* flipped, one of its endpoints is the fan vertex, and the */ + /* destination of fixuptri is the fan vertex. */ + lprevself(fixuptri); + } else { /* farvertex is to the right of the segment. */ + delaunayfixup(m, b, &fixuptri, 0); + /* Flip the edge that crosses the segment. After the edge is */ + /* flipped, one of its endpoints is the fan vertex, and the */ + /* destination of fixuptri is the fan vertex. */ + oprevself(fixuptri); + } + /* Check for two intersecting segments. */ + tspivot(fixuptri, crosssubseg); + if (crosssubseg.ss == m->dummysub) { + flip(m, b, &fixuptri); /* May create inverted triangle at left. */ + } else { + /* We've collided with a segment between endpoint1 and endpoint2. */ + collision = 1; + /* Insert a vertex at the intersection. */ + segmentintersection(m, b, &fixuptri, &crosssubseg, endpoint2); + done = 1; + } + } + } + } while (!done); + /* Insert a subsegment to make the segment permanent. */ + insertsubseg(m, b, &fixuptri, newmark); + /* If there was a collision with an interceding vertex, install another */ + /* segment connecting that vertex with endpoint2. */ + if (collision) { + /* Insert the remainder of the segment. */ + if (!scoutsegment(m, b, &fixuptri, endpoint2, newmark)) { + constrainededge(m, b, &fixuptri, endpoint2, newmark); + } + } +} + +/*****************************************************************************/ +/* */ +/* insertsegment() Insert a PSLG segment into a triangulation. */ +/* */ +/*****************************************************************************/ + +#ifdef ANSI_DECLARATORS +void insertsegment(struct mesh *m, struct behavior *b, + vertex endpoint1, vertex endpoint2, int newmark) +#else /* not ANSI_DECLARATORS */ +void insertsegment(m, b, endpoint1, endpoint2, newmark) +struct mesh *m; +struct behavior *b; +vertex endpoint1; +vertex endpoint2; +int newmark; +#endif /* not ANSI_DECLARATORS */ + +{ + struct otri searchtri1, searchtri2; + triangle encodedtri; + vertex checkvertex; + triangle ptr; /* Temporary variable used by sym(). */ + + if (b->verbose > 1) { + printf(" Connecting (%.12g, %.12g) to (%.12g, %.12g).\n", + endpoint1[0], endpoint1[1], endpoint2[0], endpoint2[1]); + } + + /* Find a triangle whose origin is the segment's first endpoint. */ + checkvertex = (vertex) NULL; + encodedtri = vertex2tri(endpoint1); + if (encodedtri != (triangle) NULL) { + decode(encodedtri, searchtri1); + org(searchtri1, checkvertex); + } + if (checkvertex != endpoint1) { + /* Find a boundary triangle to search from. */ + searchtri1.tri = m->dummytri; + searchtri1.orient = 0; + symself(searchtri1); + /* Search for the segment's first endpoint by point location. */ + if (locate(m, b, endpoint1, &searchtri1) != ONVERTEX) { + printf( + "Internal error in insertsegment(): Unable to locate PSLG vertex\n"); + printf(" (%.12g, %.12g) in triangulation.\n", + endpoint1[0], endpoint1[1]); + internalerror(); + } + } + /* Remember this triangle to improve subsequent point location. */ + otricopy(searchtri1, m->recenttri); + /* Scout the beginnings of a path from the first endpoint */ + /* toward the second. */ + if (scoutsegment(m, b, &searchtri1, endpoint2, newmark)) { + /* The segment was easily inserted. */ + return; + } + /* The first endpoint may have changed if a collision with an intervening */ + /* vertex on the segment occurred. */ + org(searchtri1, endpoint1); + + /* Find a triangle whose origin is the segment's second endpoint. */ + checkvertex = (vertex) NULL; + encodedtri = vertex2tri(endpoint2); + if (encodedtri != (triangle) NULL) { + decode(encodedtri, searchtri2); + org(searchtri2, checkvertex); + } + if (checkvertex != endpoint2) { + /* Find a boundary triangle to search from. */ + searchtri2.tri = m->dummytri; + searchtri2.orient = 0; + symself(searchtri2); + /* Search for the segment's second endpoint by point location. */ + if (locate(m, b, endpoint2, &searchtri2) != ONVERTEX) { + printf( + "Internal error in insertsegment(): Unable to locate PSLG vertex\n"); + printf(" (%.12g, %.12g) in triangulation.\n", + endpoint2[0], endpoint2[1]); + internalerror(); + } + } + /* Remember this triangle to improve subsequent point location. */ + otricopy(searchtri2, m->recenttri); + /* Scout the beginnings of a path from the second endpoint */ + /* toward the first. */ + if (scoutsegment(m, b, &searchtri2, endpoint1, newmark)) { + /* The segment was easily inserted. */ + return; + } + /* The second endpoint may have changed if a collision with an intervening */ + /* vertex on the segment occurred. */ + org(searchtri2, endpoint2); + +#ifndef REDUCED +#ifndef CDT_ONLY + if (b->splitseg) { + /* Insert vertices to force the segment into the triangulation. */ + conformingedge(m, b, endpoint1, endpoint2, newmark); + } else { +#endif /* not CDT_ONLY */ +#endif /* not REDUCED */ + /* Insert the segment directly into the triangulation. */ + constrainededge(m, b, &searchtri1, endpoint2, newmark); +#ifndef REDUCED +#ifndef CDT_ONLY + } +#endif /* not CDT_ONLY */ +#endif /* not REDUCED */ +} + +/*****************************************************************************/ +/* */ +/* markhull() Cover the convex hull of a triangulation with subsegments. */ +/* */ +/*****************************************************************************/ + +#ifdef ANSI_DECLARATORS +void markhull(struct mesh *m, struct behavior *b) +#else /* not ANSI_DECLARATORS */ +void markhull(m, b) +struct mesh *m; +struct behavior *b; +#endif /* not ANSI_DECLARATORS */ + +{ + struct otri hulltri; + struct otri nexttri; + struct otri starttri; + triangle ptr; /* Temporary variable used by sym() and oprev(). */ + + /* Find a triangle handle on the hull. */ + hulltri.tri = m->dummytri; + hulltri.orient = 0; + symself(hulltri); + /* Remember where we started so we know when to stop. */ + otricopy(hulltri, starttri); + /* Go once counterclockwise around the convex hull. */ + do { + /* Create a subsegment if there isn't already one here. */ + insertsubseg(m, b, &hulltri, 1); + /* To find the next hull edge, go clockwise around the next vertex. */ + lnextself(hulltri); + oprev(hulltri, nexttri); + while (nexttri.tri != m->dummytri) { + otricopy(nexttri, hulltri); + oprev(hulltri, nexttri); + } + } while (!otriequal(hulltri, starttri)); +} + +/*****************************************************************************/ +/* */ +/* formskeleton() Create the segments of a triangulation, including PSLG */ +/* segments and edges on the convex hull. */ +/* */ +/* The PSLG segments are read from a .poly file. The return value is the */ +/* number of segments in the file. */ +/* */ +/*****************************************************************************/ + +#ifdef TRILIBRARY + +#ifdef ANSI_DECLARATORS +void formskeleton(struct mesh *m, struct behavior *b, int *segmentlist, + int *segmentmarkerlist, int numberofsegments) +#else /* not ANSI_DECLARATORS */ +void formskeleton(m, b, segmentlist, segmentmarkerlist, numberofsegments) +struct mesh *m; +struct behavior *b; +int *segmentlist; +int *segmentmarkerlist; +int numberofsegments; +#endif /* not ANSI_DECLARATORS */ + +#else /* not TRILIBRARY */ + +#ifdef ANSI_DECLARATORS +void formskeleton(struct mesh *m, struct behavior *b, + FILE *polyfile, char *polyfilename) +#else /* not ANSI_DECLARATORS */ +void formskeleton(m, b, polyfile, polyfilename) +struct mesh *m; +struct behavior *b; +FILE *polyfile; +char *polyfilename; +#endif /* not ANSI_DECLARATORS */ + +#endif /* not TRILIBRARY */ + +{ +#ifdef TRILIBRARY + char polyfilename[6]; + int index; +#else /* not TRILIBRARY */ + char inputline[INPUTLINESIZE]; + char *stringptr; +#endif /* not TRILIBRARY */ + vertex endpoint1, endpoint2; + int segmentmarkers; + int end1, end2; + int boundmarker; + int i; + + if (b->poly) { + if (!b->quiet) { + printf("Recovering segments in Delaunay triangulation.\n"); + } +#ifdef TRILIBRARY + strcpy(polyfilename, "input"); + m->insegments = numberofsegments; + segmentmarkers = segmentmarkerlist != (int *) NULL; + index = 0; +#else /* not TRILIBRARY */ + /* Read the segments from a .poly file. */ + /* Read number of segments and number of boundary markers. */ + stringptr = readline(inputline, polyfile, polyfilename); + m->insegments = (int) strtol(stringptr, &stringptr, 0); + stringptr = findfield(stringptr); + if (*stringptr == '\0') { + segmentmarkers = 0; + } else { + segmentmarkers = (int) strtol(stringptr, &stringptr, 0); + } +#endif /* not TRILIBRARY */ + /* If the input vertices are collinear, there is no triangulation, */ + /* so don't try to insert segments. */ + if (m->triangles.items == 0) { + return; + } + + /* If segments are to be inserted, compute a mapping */ + /* from vertices to triangles. */ + if (m->insegments > 0) { + makevertexmap(m, b); + if (b->verbose) { + printf(" Recovering PSLG segments.\n"); + } + } + + boundmarker = 0; + /* Read and insert the segments. */ + for (i = 0; i < m->insegments; i++) { +#ifdef TRILIBRARY + end1 = segmentlist[index++]; + end2 = segmentlist[index++]; + if (segmentmarkers) { + boundmarker = segmentmarkerlist[i]; + } +#else /* not TRILIBRARY */ + stringptr = readline(inputline, polyfile, b->inpolyfilename); + stringptr = findfield(stringptr); + if (*stringptr == '\0') { + printf("Error: Segment %d has no endpoints in %s.\n", + b->firstnumber + i, polyfilename); + exit(1); + } else { + end1 = (int) strtol(stringptr, &stringptr, 0); + } + stringptr = findfield(stringptr); + if (*stringptr == '\0') { + printf("Error: Segment %d is missing its second endpoint in %s.\n", + b->firstnumber + i, polyfilename); + exit(1); + } else { + end2 = (int) strtol(stringptr, &stringptr, 0); + } + if (segmentmarkers) { + stringptr = findfield(stringptr); + if (*stringptr == '\0') { + boundmarker = 0; + } else { + boundmarker = (int) strtol(stringptr, &stringptr, 0); + } + } +#endif /* not TRILIBRARY */ + if ((end1 < b->firstnumber) || + (end1 >= b->firstnumber + m->invertices)) { + if (!b->quiet) { + printf("Warning: Invalid first endpoint of segment %d in %s.\n", + b->firstnumber + i, polyfilename); + } + } else if ((end2 < b->firstnumber) || + (end2 >= b->firstnumber + m->invertices)) { + if (!b->quiet) { + printf("Warning: Invalid second endpoint of segment %d in %s.\n", + b->firstnumber + i, polyfilename); + } + } else { + endpoint1 = getvertex(m, b, end1); + endpoint2 = getvertex(m, b, end2); + if ((endpoint1[0] == endpoint2[0]) && (endpoint1[1] == endpoint2[1])) { + if (!b->quiet) { + printf("Warning: Endpoints of segment %d are coincident in %s.\n", + b->firstnumber + i, polyfilename); + } + } else { + insertsegment(m, b, endpoint1, endpoint2, boundmarker); + } + } + } + } else { + m->insegments = 0; + } + if (b->convex || !b->poly) { + /* Enclose the convex hull with subsegments. */ + if (b->verbose) { + printf(" Enclosing convex hull with segments.\n"); + } + markhull(m, b); + } +} + +/** **/ +/** **/ +/********* Segment insertion ends here *********/ + +/********* Carving out holes and concavities begins here *********/ +/** **/ +/** **/ + +/*****************************************************************************/ +/* */ +/* infecthull() Virally infect all of the triangles of the convex hull */ +/* that are not protected by subsegments. Where there are */ +/* subsegments, set boundary markers as appropriate. */ +/* */ +/*****************************************************************************/ + +#ifdef ANSI_DECLARATORS +void infecthull(struct mesh *m, struct behavior *b) +#else /* not ANSI_DECLARATORS */ +void infecthull(m, b) +struct mesh *m; +struct behavior *b; +#endif /* not ANSI_DECLARATORS */ + +{ + struct otri hulltri; + struct otri nexttri; + struct otri starttri; + struct osub hullsubseg; + triangle **deadtriangle; + vertex horg, hdest; + triangle ptr; /* Temporary variable used by sym(). */ + subseg sptr; /* Temporary variable used by tspivot(). */ + + if (b->verbose) { + printf(" Marking concavities (external triangles) for elimination.\n"); + } + /* Find a triangle handle on the hull. */ + hulltri.tri = m->dummytri; + hulltri.orient = 0; + symself(hulltri); + /* Remember where we started so we know when to stop. */ + otricopy(hulltri, starttri); + /* Go once counterclockwise around the convex hull. */ + do { + /* Ignore triangles that are already infected. */ + if (!infected(hulltri)) { + /* Is the triangle protected by a subsegment? */ + tspivot(hulltri, hullsubseg); + if (hullsubseg.ss == m->dummysub) { + /* The triangle is not protected; infect it. */ + if (!infected(hulltri)) { + infect(hulltri); + deadtriangle = (triangle **) poolalloc(&m->viri); + *deadtriangle = hulltri.tri; + } + } else { + /* The triangle is protected; set boundary markers if appropriate. */ + if (mark(hullsubseg) == 0) { + setmark(hullsubseg, 1); + org(hulltri, horg); + dest(hulltri, hdest); + if (vertexmark(horg) == 0) { + setvertexmark(horg, 1); + } + if (vertexmark(hdest) == 0) { + setvertexmark(hdest, 1); + } + } + } + } + /* To find the next hull edge, go clockwise around the next vertex. */ + lnextself(hulltri); + oprev(hulltri, nexttri); + while (nexttri.tri != m->dummytri) { + otricopy(nexttri, hulltri); + oprev(hulltri, nexttri); + } + } while (!otriequal(hulltri, starttri)); +} + +/*****************************************************************************/ +/* */ +/* plague() Spread the virus from all infected triangles to any neighbors */ +/* not protected by subsegments. Delete all infected triangles. */ +/* */ +/* This is the procedure that actually creates holes and concavities. */ +/* */ +/* This procedure operates in two phases. The first phase identifies all */ +/* the triangles that will die, and marks them as infected. They are */ +/* marked to ensure that each triangle is added to the virus pool only */ +/* once, so the procedure will terminate. */ +/* */ +/* The second phase actually eliminates the infected triangles. It also */ +/* eliminates orphaned vertices. */ +/* */ +/*****************************************************************************/ + +#ifdef ANSI_DECLARATORS +void plague(struct mesh *m, struct behavior *b) +#else /* not ANSI_DECLARATORS */ +void plague(m, b) +struct mesh *m; +struct behavior *b; +#endif /* not ANSI_DECLARATORS */ + +{ + struct otri testtri; + struct otri neighbor; + triangle **virusloop; + triangle **deadtriangle; + struct osub neighborsubseg; + vertex testvertex; + vertex norg, ndest; + vertex deadorg, deaddest, deadapex; + int killorg; + triangle ptr; /* Temporary variable used by sym() and onext(). */ + subseg sptr; /* Temporary variable used by tspivot(). */ + + if (b->verbose) { + printf(" Marking neighbors of marked triangles.\n"); + } + /* Loop through all the infected triangles, spreading the virus to */ + /* their neighbors, then to their neighbors' neighbors. */ + traversalinit(&m->viri); + virusloop = (triangle **) traverse(&m->viri); + while (virusloop != (triangle **) NULL) { + testtri.tri = *virusloop; + /* A triangle is marked as infected by messing with one of its pointers */ + /* to subsegments, setting it to an illegal value. Hence, we have to */ + /* temporarily uninfect this triangle so that we can examine its */ + /* adjacent subsegments. */ + uninfect(testtri); + if (b->verbose > 2) { + /* Assign the triangle an orientation for convenience in */ + /* checking its vertices. */ + testtri.orient = 0; + org(testtri, deadorg); + dest(testtri, deaddest); + apex(testtri, deadapex); + printf(" Checking (%.12g, %.12g) (%.12g, %.12g) (%.12g, %.12g)\n", + deadorg[0], deadorg[1], deaddest[0], deaddest[1], + deadapex[0], deadapex[1]); + } + /* Check each of the triangle's three neighbors. */ + for (testtri.orient = 0; testtri.orient < 3; testtri.orient++) { + /* Find the neighbor. */ + sym(testtri, neighbor); + /* Check for a subsegment between the triangle and its neighbor. */ + tspivot(testtri, neighborsubseg); + /* Check if the neighbor is nonexistent or already infected. */ + if ((neighbor.tri == m->dummytri) || infected(neighbor)) { + if (neighborsubseg.ss != m->dummysub) { + /* There is a subsegment separating the triangle from its */ + /* neighbor, but both triangles are dying, so the subsegment */ + /* dies too. */ + subsegdealloc(m, neighborsubseg.ss); + if (neighbor.tri != m->dummytri) { + /* Make sure the subsegment doesn't get deallocated again */ + /* later when the infected neighbor is visited. */ + uninfect(neighbor); + tsdissolve(neighbor); + infect(neighbor); + } + } + } else { /* The neighbor exists and is not infected. */ + if (neighborsubseg.ss == m->dummysub) { + /* There is no subsegment protecting the neighbor, so */ + /* the neighbor becomes infected. */ + if (b->verbose > 2) { + org(neighbor, deadorg); + dest(neighbor, deaddest); + apex(neighbor, deadapex); + printf( + " Marking (%.12g, %.12g) (%.12g, %.12g) (%.12g, %.12g)\n", + deadorg[0], deadorg[1], deaddest[0], deaddest[1], + deadapex[0], deadapex[1]); + } + infect(neighbor); + /* Ensure that the neighbor's neighbors will be infected. */ + deadtriangle = (triangle **) poolalloc(&m->viri); + *deadtriangle = neighbor.tri; + } else { /* The neighbor is protected by a subsegment. */ + /* Remove this triangle from the subsegment. */ + stdissolve(neighborsubseg); + /* The subsegment becomes a boundary. Set markers accordingly. */ + if (mark(neighborsubseg) == 0) { + setmark(neighborsubseg, 1); + } + org(neighbor, norg); + dest(neighbor, ndest); + if (vertexmark(norg) == 0) { + setvertexmark(norg, 1); + } + if (vertexmark(ndest) == 0) { + setvertexmark(ndest, 1); + } + } + } + } + /* Remark the triangle as infected, so it doesn't get added to the */ + /* virus pool again. */ + infect(testtri); + virusloop = (triangle **) traverse(&m->viri); + } + + if (b->verbose) { + printf(" Deleting marked triangles.\n"); + } + + traversalinit(&m->viri); + virusloop = (triangle **) traverse(&m->viri); + while (virusloop != (triangle **) NULL) { + testtri.tri = *virusloop; + + /* Check each of the three corners of the triangle for elimination. */ + /* This is done by walking around each vertex, checking if it is */ + /* still connected to at least one live triangle. */ + for (testtri.orient = 0; testtri.orient < 3; testtri.orient++) { + org(testtri, testvertex); + /* Check if the vertex has already been tested. */ + if (testvertex != (vertex) NULL) { + killorg = 1; + /* Mark the corner of the triangle as having been tested. */ + setorg(testtri, NULL); + /* Walk counterclockwise about the vertex. */ + onext(testtri, neighbor); + /* Stop upon reaching a boundary or the starting triangle. */ + while ((neighbor.tri != m->dummytri) && + (!otriequal(neighbor, testtri))) { + if (infected(neighbor)) { + /* Mark the corner of this triangle as having been tested. */ + setorg(neighbor, NULL); + } else { + /* A live triangle. The vertex survives. */ + killorg = 0; + } + /* Walk counterclockwise about the vertex. */ + onextself(neighbor); + } + /* If we reached a boundary, we must walk clockwise as well. */ + if (neighbor.tri == m->dummytri) { + /* Walk clockwise about the vertex. */ + oprev(testtri, neighbor); + /* Stop upon reaching a boundary. */ + while (neighbor.tri != m->dummytri) { + if (infected(neighbor)) { + /* Mark the corner of this triangle as having been tested. */ + setorg(neighbor, NULL); + } else { + /* A live triangle. The vertex survives. */ + killorg = 0; + } + /* Walk clockwise about the vertex. */ + oprevself(neighbor); + } + } + if (killorg) { + if (b->verbose > 1) { + printf(" Deleting vertex (%.12g, %.12g)\n", + testvertex[0], testvertex[1]); + } + setvertextype(testvertex, UNDEADVERTEX); + m->undeads++; + } + } + } + + /* Record changes in the number of boundary edges, and disconnect */ + /* dead triangles from their neighbors. */ + for (testtri.orient = 0; testtri.orient < 3; testtri.orient++) { + sym(testtri, neighbor); + if (neighbor.tri == m->dummytri) { + /* There is no neighboring triangle on this edge, so this edge */ + /* is a boundary edge. This triangle is being deleted, so this */ + /* boundary edge is deleted. */ + m->hullsize--; + } else { + /* Disconnect the triangle from its neighbor. */ + dissolve(neighbor); + /* There is a neighboring triangle on this edge, so this edge */ + /* becomes a boundary edge when this triangle is deleted. */ + m->hullsize++; + } + } + /* Return the dead triangle to the pool of triangles. */ + triangledealloc(m, testtri.tri); + virusloop = (triangle **) traverse(&m->viri); + } + /* Empty the virus pool. */ + poolrestart(&m->viri); +} + +/*****************************************************************************/ +/* */ +/* regionplague() Spread regional attributes and/or area constraints */ +/* (from a .poly file) throughout the mesh. */ +/* */ +/* This procedure operates in two phases. The first phase spreads an */ +/* attribute and/or an area constraint through a (segment-bounded) region. */ +/* The triangles are marked to ensure that each triangle is added to the */ +/* virus pool only once, so the procedure will terminate. */ +/* */ +/* The second phase uninfects all infected triangles, returning them to */ +/* normal. */ +/* */ +/*****************************************************************************/ + +#ifdef ANSI_DECLARATORS +void regionplague(struct mesh *m, struct behavior *b, + REAL attribute, REAL area) +#else /* not ANSI_DECLARATORS */ +void regionplague(m, b, attribute, area) +struct mesh *m; +struct behavior *b; +REAL attribute; +REAL area; +#endif /* not ANSI_DECLARATORS */ + +{ + struct otri testtri; + struct otri neighbor; + triangle **virusloop; + triangle **regiontri; + struct osub neighborsubseg; + vertex regionorg, regiondest, regionapex; + triangle ptr; /* Temporary variable used by sym() and onext(). */ + subseg sptr; /* Temporary variable used by tspivot(). */ + + if (b->verbose > 1) { + printf(" Marking neighbors of marked triangles.\n"); + } + /* Loop through all the infected triangles, spreading the attribute */ + /* and/or area constraint to their neighbors, then to their neighbors' */ + /* neighbors. */ + traversalinit(&m->viri); + virusloop = (triangle **) traverse(&m->viri); + while (virusloop != (triangle **) NULL) { + testtri.tri = *virusloop; + /* A triangle is marked as infected by messing with one of its pointers */ + /* to subsegments, setting it to an illegal value. Hence, we have to */ + /* temporarily uninfect this triangle so that we can examine its */ + /* adjacent subsegments. */ + uninfect(testtri); + if (b->regionattrib) { + /* Set an attribute. */ + setelemattribute(testtri, m->eextras, attribute); + } + if (b->vararea) { + /* Set an area constraint. */ + setareabound(testtri, area); + } + if (b->verbose > 2) { + /* Assign the triangle an orientation for convenience in */ + /* checking its vertices. */ + testtri.orient = 0; + org(testtri, regionorg); + dest(testtri, regiondest); + apex(testtri, regionapex); + printf(" Checking (%.12g, %.12g) (%.12g, %.12g) (%.12g, %.12g)\n", + regionorg[0], regionorg[1], regiondest[0], regiondest[1], + regionapex[0], regionapex[1]); + } + /* Check each of the triangle's three neighbors. */ + for (testtri.orient = 0; testtri.orient < 3; testtri.orient++) { + /* Find the neighbor. */ + sym(testtri, neighbor); + /* Check for a subsegment between the triangle and its neighbor. */ + tspivot(testtri, neighborsubseg); + /* Make sure the neighbor exists, is not already infected, and */ + /* isn't protected by a subsegment. */ + if ((neighbor.tri != m->dummytri) && !infected(neighbor) + && (neighborsubseg.ss == m->dummysub)) { + if (b->verbose > 2) { + org(neighbor, regionorg); + dest(neighbor, regiondest); + apex(neighbor, regionapex); + printf(" Marking (%.12g, %.12g) (%.12g, %.12g) (%.12g, %.12g)\n", + regionorg[0], regionorg[1], regiondest[0], regiondest[1], + regionapex[0], regionapex[1]); + } + /* Infect the neighbor. */ + infect(neighbor); + /* Ensure that the neighbor's neighbors will be infected. */ + regiontri = (triangle **) poolalloc(&m->viri); + *regiontri = neighbor.tri; + } + } + /* Remark the triangle as infected, so it doesn't get added to the */ + /* virus pool again. */ + infect(testtri); + virusloop = (triangle **) traverse(&m->viri); + } + + /* Uninfect all triangles. */ + if (b->verbose > 1) { + printf(" Unmarking marked triangles.\n"); + } + traversalinit(&m->viri); + virusloop = (triangle **) traverse(&m->viri); + while (virusloop != (triangle **) NULL) { + testtri.tri = *virusloop; + uninfect(testtri); + virusloop = (triangle **) traverse(&m->viri); + } + /* Empty the virus pool. */ + poolrestart(&m->viri); +} + +/*****************************************************************************/ +/* */ +/* carveholes() Find the holes and infect them. Find the area */ +/* constraints and infect them. Infect the convex hull. */ +/* Spread the infection and kill triangles. Spread the */ +/* area constraints. */ +/* */ +/* This routine mainly calls other routines to carry out all these */ +/* functions. */ +/* */ +/*****************************************************************************/ + +#ifdef ANSI_DECLARATORS +void carveholes(struct mesh *m, struct behavior *b, REAL *holelist, int holes, + REAL *regionlist, int regions) +#else /* not ANSI_DECLARATORS */ +void carveholes(m, b, holelist, holes, regionlist, regions) +struct mesh *m; +struct behavior *b; +REAL *holelist; +int holes; +REAL *regionlist; +int regions; +#endif /* not ANSI_DECLARATORS */ + +{ + struct otri searchtri; + struct otri triangleloop; + struct otri *regiontris; + triangle **holetri; + triangle **regiontri; + vertex searchorg, searchdest; + enum locateresult intersect; + int i; + triangle ptr; /* Temporary variable used by sym(). */ + + if (!(b->quiet || (b->noholes && b->convex))) { + printf("Removing unwanted triangles.\n"); + if (b->verbose && (holes > 0)) { + printf(" Marking holes for elimination.\n"); + } + } + + if (regions > 0) { + /* Allocate storage for the triangles in which region points fall. */ + regiontris = (struct otri *) + trimalloc(regions * (int) sizeof(struct otri)); + } + + if (((holes > 0) && !b->noholes) || !b->convex || (regions > 0)) { + /* Initialize a pool of viri to be used for holes, concavities, */ + /* regional attributes, and/or regional area constraints. */ + poolinit(&m->viri, sizeof(triangle *), VIRUSPERBLOCK, VIRUSPERBLOCK, + POINTER, 0); + } + + if (!b->convex) { + /* Mark as infected any unprotected triangles on the boundary. */ + /* This is one way by which concavities are created. */ + infecthull(m, b); + } + + if ((holes > 0) && !b->noholes) { + /* Infect each triangle in which a hole lies. */ + for (i = 0; i < 2 * holes; i += 2) { + /* Ignore holes that aren't within the bounds of the mesh. */ + if ((holelist[i] >= m->xmin) && (holelist[i] <= m->xmax) + && (holelist[i + 1] >= m->ymin) && (holelist[i + 1] <= m->ymax)) { + /* Start searching from some triangle on the outer boundary. */ + searchtri.tri = m->dummytri; + searchtri.orient = 0; + symself(searchtri); + /* Ensure that the hole is to the left of this boundary edge; */ + /* otherwise, locate() will falsely report that the hole */ + /* falls within the starting triangle. */ + org(searchtri, searchorg); + dest(searchtri, searchdest); + if (counterclockwise(m, b, searchorg, searchdest, &holelist[i]) > + 0.0) { + /* Find a triangle that contains the hole. */ + intersect = locate(m, b, &holelist[i], &searchtri); + if ((intersect != OUTSIDE) && (!infected(searchtri))) { + /* Infect the triangle. This is done by marking the triangle */ + /* as infected and including the triangle in the virus pool. */ + infect(searchtri); + holetri = (triangle **) poolalloc(&m->viri); + *holetri = searchtri.tri; + } + } + } + } + } + + /* Now, we have to find all the regions BEFORE we carve the holes, because */ + /* locate() won't work when the triangulation is no longer convex. */ + /* (Incidentally, this is the reason why regional attributes and area */ + /* constraints can't be used when refining a preexisting mesh, which */ + /* might not be convex; they can only be used with a freshly */ + /* triangulated PSLG.) */ + if (regions > 0) { + /* Find the starting triangle for each region. */ + for (i = 0; i < regions; i++) { + regiontris[i].tri = m->dummytri; + /* Ignore region points that aren't within the bounds of the mesh. */ + if ((regionlist[4 * i] >= m->xmin) && (regionlist[4 * i] <= m->xmax) && + (regionlist[4 * i + 1] >= m->ymin) && + (regionlist[4 * i + 1] <= m->ymax)) { + /* Start searching from some triangle on the outer boundary. */ + searchtri.tri = m->dummytri; + searchtri.orient = 0; + symself(searchtri); + /* Ensure that the region point is to the left of this boundary */ + /* edge; otherwise, locate() will falsely report that the */ + /* region point falls within the starting triangle. */ + org(searchtri, searchorg); + dest(searchtri, searchdest); + if (counterclockwise(m, b, searchorg, searchdest, ®ionlist[4 * i]) > + 0.0) { + /* Find a triangle that contains the region point. */ + intersect = locate(m, b, ®ionlist[4 * i], &searchtri); + if ((intersect != OUTSIDE) && (!infected(searchtri))) { + /* Record the triangle for processing after the */ + /* holes have been carved. */ + otricopy(searchtri, regiontris[i]); + } + } + } + } + } + + if (m->viri.items > 0) { + /* Carve the holes and concavities. */ + plague(m, b); + } + /* The virus pool should be empty now. */ + + if (regions > 0) { + if (!b->quiet) { + if (b->regionattrib) { + if (b->vararea) { + printf("Spreading regional attributes and area constraints.\n"); + } else { + printf("Spreading regional attributes.\n"); + } + } else { + printf("Spreading regional area constraints.\n"); + } + } + if (b->regionattrib && !b->refine) { + /* Assign every triangle a regional attribute of zero. */ + traversalinit(&m->triangles); + triangleloop.orient = 0; + triangleloop.tri = triangletraverse(m); + while (triangleloop.tri != (triangle *) NULL) { + setelemattribute(triangleloop, m->eextras, 0.0); + triangleloop.tri = triangletraverse(m); + } + } + for (i = 0; i < regions; i++) { + if (regiontris[i].tri != m->dummytri) { + /* Make sure the triangle under consideration still exists. */ + /* It may have been eaten by the virus. */ + if (!deadtri(regiontris[i].tri)) { + /* Put one triangle in the virus pool. */ + infect(regiontris[i]); + regiontri = (triangle **) poolalloc(&m->viri); + *regiontri = regiontris[i].tri; + /* Apply one region's attribute and/or area constraint. */ + regionplague(m, b, regionlist[4 * i + 2], regionlist[4 * i + 3]); + /* The virus pool should be empty now. */ + } + } + } + if (b->regionattrib && !b->refine) { + /* Note the fact that each triangle has an additional attribute. */ + m->eextras++; + } + } + + /* Free up memory. */ + if (((holes > 0) && !b->noholes) || !b->convex || (regions > 0)) { + pooldeinit(&m->viri); + } + if (regions > 0) { + trifree((VOID *) regiontris); + } +} + +/** **/ +/** **/ +/********* Carving out holes and concavities ends here *********/ + +/********* Mesh quality maintenance begins here *********/ +/** **/ +/** **/ + +/*****************************************************************************/ +/* */ +/* tallyencs() Traverse the entire list of subsegments, and check each */ +/* to see if it is encroached. If so, add it to the list. */ +/* */ +/*****************************************************************************/ + +#ifndef CDT_ONLY + +#ifdef ANSI_DECLARATORS +void tallyencs(struct mesh *m, struct behavior *b) +#else /* not ANSI_DECLARATORS */ +void tallyencs(m, b) +struct mesh *m; +struct behavior *b; +#endif /* not ANSI_DECLARATORS */ + +{ + struct osub subsegloop; + int dummy; + + traversalinit(&m->subsegs); + subsegloop.ssorient = 0; + subsegloop.ss = subsegtraverse(m); + while (subsegloop.ss != (subseg *) NULL) { + /* If the segment is encroached, add it to the list. */ + dummy = checkseg4encroach(m, b, &subsegloop, 0.0); + subsegloop.ss = subsegtraverse(m); + } +} + +#endif /* not CDT_ONLY */ + +/*****************************************************************************/ +/* */ +/* precisionerror() Print an error message for precision problems. */ +/* */ +/*****************************************************************************/ + +#ifndef CDT_ONLY + +void precisionerror() +{ + printf("Try increasing the area criterion and/or reducing the minimum\n"); + printf(" allowable angle so that tiny triangles are not created.\n"); +#ifdef SINGLE + printf("Alternatively, try recompiling me with double precision\n"); + printf(" arithmetic (by removing \"#define SINGLE\" from the\n"); + printf(" source file or \"-DSINGLE\" from the makefile).\n"); +#endif /* SINGLE */ +} + +#endif /* not CDT_ONLY */ + +/*****************************************************************************/ +/* */ +/* splitencsegs() Split all the encroached subsegments. */ +/* */ +/* Each encroached subsegment is repaired by splitting it - inserting a */ +/* vertex at or near its midpoint. Newly inserted vertices may encroach */ +/* upon other subsegments; these are also repaired. */ +/* */ +/* `triflaws' is a flag that specifies whether one should take note of new */ +/* bad triangles that result from inserting vertices to repair encroached */ +/* subsegments. */ +/* */ +/*****************************************************************************/ + +#ifndef CDT_ONLY + +#ifdef ANSI_DECLARATORS +void splitencsegs(struct mesh *m, struct behavior *b, int triflaws) +#else /* not ANSI_DECLARATORS */ +void splitencsegs(m, b, triflaws) +struct mesh *m; +struct behavior *b; +int triflaws; +#endif /* not ANSI_DECLARATORS */ + +{ + struct otri enctri; + struct otri testtri; + struct osub testsh; + struct osub currentenc; + struct badsubseg *encloop; + vertex eorg, edest, eapex; + vertex newvertex; + enum insertvertexresult success; + REAL segmentlength, nearestpoweroftwo; + REAL split; + REAL multiplier, divisor; + int acuteorg, acuteorg2, acutedest, acutedest2; + int dummy; + int i; + triangle ptr; /* Temporary variable used by stpivot(). */ + subseg sptr; /* Temporary variable used by snext(). */ + + /* Note that steinerleft == -1 if an unlimited number */ + /* of Steiner points is allowed. */ + while ((m->badsubsegs.items > 0) && (m->steinerleft != 0)) { + traversalinit(&m->badsubsegs); + encloop = badsubsegtraverse(m); + while ((encloop != (struct badsubseg *) NULL) && (m->steinerleft != 0)) { + sdecode(encloop->encsubseg, currentenc); + sorg(currentenc, eorg); + sdest(currentenc, edest); + /* Make sure that this segment is still the same segment it was */ + /* when it was determined to be encroached. If the segment was */ + /* enqueued multiple times (because several newly inserted */ + /* vertices encroached it), it may have already been split. */ + if (!deadsubseg(currentenc.ss) && + (eorg == encloop->subsegorg) && (edest == encloop->subsegdest)) { + /* To decide where to split a segment, we need to know if the */ + /* segment shares an endpoint with an adjacent segment. */ + /* The concern is that, if we simply split every encroached */ + /* segment in its center, two adjacent segments with a small */ + /* angle between them might lead to an infinite loop; each */ + /* vertex added to split one segment will encroach upon the */ + /* other segment, which must then be split with a vertex that */ + /* will encroach upon the first segment, and so on forever. */ + /* To avoid this, imagine a set of concentric circles, whose */ + /* radii are powers of two, about each segment endpoint. */ + /* These concentric circles determine where the segment is */ + /* split. (If both endpoints are shared with adjacent */ + /* segments, split the segment in the middle, and apply the */ + /* concentric circles for later splittings.) */ + + /* Is the origin shared with another segment? */ + stpivot(currentenc, enctri); + lnext(enctri, testtri); + tspivot(testtri, testsh); + acuteorg = testsh.ss != m->dummysub; + /* Is the destination shared with another segment? */ + lnextself(testtri); + tspivot(testtri, testsh); + acutedest = testsh.ss != m->dummysub; + + /* If we're using diametral lenses (rather than diametral circles) */ + /* to define encroachment, delete free vertices from the */ + /* subsegment's diametral circle. */ + if (!b->nolenses && !acuteorg && !acutedest) { + apex(enctri, eapex); + while ((vertextype(eapex) == FREEVERTEX) && + ((eorg[0] - eapex[0]) * (edest[0] - eapex[0]) + + (eorg[1] - eapex[1]) * (edest[1] - eapex[1]) < 0.0)) { + deletevertex(m, b, &testtri); + stpivot(currentenc, enctri); + apex(enctri, eapex); + lprev(enctri, testtri); + } + } + + /* Now, check the other side of the segment, if there's a triangle */ + /* there. */ + sym(enctri, testtri); + if (testtri.tri != m->dummytri) { + /* Is the destination shared with another segment? */ + lnextself(testtri); + tspivot(testtri, testsh); + acutedest2 = testsh.ss != m->dummysub; + acutedest = acutedest || acutedest2; + /* Is the origin shared with another segment? */ + lnextself(testtri); + tspivot(testtri, testsh); + acuteorg2 = testsh.ss != m->dummysub; + acuteorg = acuteorg || acuteorg2; + + /* Delete free vertices from the subsegment's diametral circle. */ + if (!b->nolenses && !acuteorg2 && !acutedest2) { + org(testtri, eapex); + while ((vertextype(eapex) == FREEVERTEX) && + ((eorg[0] - eapex[0]) * (edest[0] - eapex[0]) + + (eorg[1] - eapex[1]) * (edest[1] - eapex[1]) < 0.0)) { + deletevertex(m, b, &testtri); + sym(enctri, testtri); + apex(testtri, eapex); + lprevself(testtri); + } + } + } + + /* Use the concentric circles if exactly one endpoint is shared */ + /* with another adjacent segment. */ + if (acuteorg || acutedest) { + segmentlength = sqrt((edest[0] - eorg[0]) * (edest[0] - eorg[0]) + + (edest[1] - eorg[1]) * (edest[1] - eorg[1])); + /* Find the power of two that most evenly splits the segment. */ + /* The worst case is a 2:1 ratio between subsegment lengths. */ + nearestpoweroftwo = 1.0; + while (segmentlength > 3.0 * nearestpoweroftwo) { + nearestpoweroftwo *= 2.0; + } + while (segmentlength < 1.5 * nearestpoweroftwo) { + nearestpoweroftwo *= 0.5; + } + /* Where do we split the segment? */ + split = nearestpoweroftwo / segmentlength; + if (acutedest) { + split = 1.0 - split; + } + } else { + /* If we're not worried about adjacent segments, split */ + /* this segment in the middle. */ + split = 0.5; + } + + /* Create the new vertex. */ + newvertex = (vertex) poolalloc(&m->vertices); + /* Interpolate its coordinate and attributes. */ + for (i = 0; i < 2 + m->nextras; i++) { + newvertex[i] = eorg[i] + split * (edest[i] - eorg[i]); + } + + if (!b->noexact) { + /* Roundoff in the above calculation may yield a `newvertex' */ + /* that is not precisely collinear with `eorg' and `edest'. */ + /* Improve collinearity by one step of iterative refinement. */ + multiplier = counterclockwise(m, b, eorg, edest, newvertex); + divisor = ((eorg[0] - edest[0]) * (eorg[0] - edest[0]) + + (eorg[1] - edest[1]) * (eorg[1] - edest[1])); + if ((multiplier != 0.0) && (divisor != 0.0)) { + multiplier = multiplier / divisor; + /* Watch out for NANs. */ + if (multiplier == multiplier) { + newvertex[0] += multiplier * (edest[1] - eorg[1]); + newvertex[1] += multiplier * (eorg[0] - edest[0]); + } + } + } + + setvertexmark(newvertex, mark(currentenc)); + setvertextype(newvertex, SEGMENTVERTEX); + if (b->verbose > 1) { + printf( + " Splitting subsegment (%.12g, %.12g) (%.12g, %.12g) at (%.12g, %.12g).\n", + eorg[0], eorg[1], edest[0], edest[1], + newvertex[0], newvertex[1]); + } + /* Check whether the new vertex lies on an endpoint. */ + if (((newvertex[0] == eorg[0]) && (newvertex[1] == eorg[1])) || + ((newvertex[0] == edest[0]) && (newvertex[1] == edest[1]))) { + printf("Error: Ran out of precision at (%.12g, %.12g).\n", + newvertex[0], newvertex[1]); + printf("I attempted to split a segment to a smaller size than\n"); + printf(" can be accommodated by the finite precision of\n"); + printf(" floating point arithmetic.\n"); + precisionerror(); + exit(1); + } + /* Insert the splitting vertex. This should always succeed. */ + success = insertvertex(m, b, newvertex, &enctri, ¤tenc, + 1, triflaws, 0.0); + if ((success != SUCCESSFULVERTEX) && (success != ENCROACHINGVERTEX)) { + printf("Internal error in splitencsegs():\n"); + printf(" Failure to split a segment.\n"); + internalerror(); + } + if (m->steinerleft > 0) { + m->steinerleft--; + } + /* Check the two new subsegments to see if they're encroached. */ + dummy = checkseg4encroach(m, b, ¤tenc, 0.0); + snextself(currentenc); + dummy = checkseg4encroach(m, b, ¤tenc, 0.0); + } + + badsubsegdealloc(m, encloop); + encloop = badsubsegtraverse(m); + } + } +} + +#endif /* not CDT_ONLY */ + +/*****************************************************************************/ +/* */ +/* tallyfaces() Test every triangle in the mesh for quality measures. */ +/* */ +/*****************************************************************************/ + +#ifndef CDT_ONLY + +#ifdef ANSI_DECLARATORS +void tallyfaces(struct mesh *m, struct behavior *b) +#else /* not ANSI_DECLARATORS */ +void tallyfaces(m, b) +struct mesh *m; +struct behavior *b; +#endif /* not ANSI_DECLARATORS */ + +{ + struct otri triangleloop; + + if (b->verbose) { + printf(" Making a list of bad triangles.\n"); + } + traversalinit(&m->triangles); + triangleloop.orient = 0; + triangleloop.tri = triangletraverse(m); + while (triangleloop.tri != (triangle *) NULL) { + /* If the triangle is bad, enqueue it. */ + testtriangle(m, b, &triangleloop); + triangleloop.tri = triangletraverse(m); + } +} + +#endif /* not CDT_ONLY */ + +/*****************************************************************************/ +/* */ +/* splittriangle() Inserts a vertex at the circumcenter of a triangle. */ +/* Deletes the newly inserted vertex if it encroaches */ +/* upon a segment. */ +/* */ +/*****************************************************************************/ + +#ifndef CDT_ONLY + +#ifdef ANSI_DECLARATORS +void splittriangle(struct mesh *m, struct behavior *b, + struct badtriang *badtri) +#else /* not ANSI_DECLARATORS */ +void splittriangle(m, b, badtri) +struct mesh *m; +struct behavior *b; +struct badtriang *badtri; +#endif /* not ANSI_DECLARATORS */ + +{ + struct otri badotri; + vertex borg, bdest, bapex; + vertex newvertex; + REAL xi, eta; + REAL minedge; + enum insertvertexresult success; + int errorflag; + int i; + + decode(badtri->poortri, badotri); + org(badotri, borg); + dest(badotri, bdest); + apex(badotri, bapex); + /* Make sure that this triangle is still the same triangle it was */ + /* when it was tested and determined to be of bad quality. */ + /* Subsequent transformations may have made it a different triangle. */ + if (!deadtri(badotri.tri) && (borg == badtri->triangorg) && + (bdest == badtri->triangdest) && (bapex == badtri->triangapex)) { + if (b->verbose > 1) { + printf(" Splitting this triangle at its circumcenter:\n"); + printf(" (%.12g, %.12g) (%.12g, %.12g) (%.12g, %.12g)\n", borg[0], + borg[1], bdest[0], bdest[1], bapex[0], bapex[1]); + } + + errorflag = 0; + /* Create a new vertex at the triangle's circumcenter. */ + newvertex = (vertex) poolalloc(&m->vertices); + findcircumcenter(m, b, borg, bdest, bapex, newvertex, &xi, &eta, &minedge, + 1); + + /* Check whether the new vertex lies on a triangle vertex. */ + if (((newvertex[0] == borg[0]) && (newvertex[1] == borg[1])) || + ((newvertex[0] == bdest[0]) && (newvertex[1] == bdest[1])) || + ((newvertex[0] == bapex[0]) && (newvertex[1] == bapex[1]))) { + if (!b->quiet) { + printf( + "Warning: New vertex (%.12g, %.12g) falls on existing vertex.\n", + newvertex[0], newvertex[1]); + errorflag = 1; + } + vertexdealloc(m, newvertex); + } else { + for (i = 2; i < 2 + m->nextras; i++) { + /* Interpolate the vertex attributes at the circumcenter. */ + newvertex[i] = borg[i] + xi * (bdest[i] - borg[i]) + + eta * (bapex[i] - borg[i]); + } + /* The new vertex must be in the interior, and therefore is a */ + /* free vertex with a marker of zero. */ + setvertexmark(newvertex, 0); + setvertextype(newvertex, FREEVERTEX); + + /* Ensure that the handle `badotri' does not represent the longest */ + /* edge of the triangle. This ensures that the circumcenter must */ + /* fall to the left of this edge, so point location will work. */ + /* (If the angle org-apex-dest exceeds 90 degrees, then the */ + /* circumcenter lies outside the org-dest edge, and eta is */ + /* negative. Roundoff error might prevent eta from being */ + /* negative when it should be, so I test eta against xi.) */ + if (eta < xi) { + lprevself(badotri); + } + + /* Insert the circumcenter, searching from the edge of the triangle, */ + /* and maintain the Delaunay property of the triangulation. */ + success = insertvertex(m, b, newvertex, &badotri, (struct osub *) NULL, + 1, 1, minedge); + if (success == SUCCESSFULVERTEX) { + if (m->steinerleft > 0) { + m->steinerleft--; + } + } else if (success == ENCROACHINGVERTEX) { + /* If the newly inserted vertex encroaches upon a subsegment, */ + /* delete the new vertex. */ + undovertex(m, b); + if (b->verbose > 1) { + printf(" Rejecting (%.12g, %.12g).\n", newvertex[0], newvertex[1]); + } + vertexdealloc(m, newvertex); + } else if (success == VIOLATINGVERTEX) { + /* Failed to insert the new vertex, but some subsegment was */ + /* marked as being encroached. */ + vertexdealloc(m, newvertex); + } else { /* success == DUPLICATEVERTEX */ + /* Couldn't insert the new vertex because a vertex is already there. */ + if (!b->quiet) { + printf( + "Warning: New vertex (%.12g, %.12g) falls on existing vertex.\n", + newvertex[0], newvertex[1]); + errorflag = 1; + } + vertexdealloc(m, newvertex); + } + } + if (errorflag) { + if (b->verbose) { + printf(" The new vertex is at the circumcenter of triangle\n"); + printf(" (%.12g, %.12g) (%.12g, %.12g) (%.12g, %.12g)\n", + borg[0], borg[1], bdest[0], bdest[1], bapex[0], bapex[1]); + } + printf("This probably means that I am trying to refine triangles\n"); + printf(" to a smaller size than can be accommodated by the finite\n"); + printf(" precision of floating point arithmetic. (You can be\n"); + printf(" sure of this if I fail to terminate.)\n"); + precisionerror(); + } + } +} + +#endif /* not CDT_ONLY */ + +/*****************************************************************************/ +/* */ +/* enforcequality() Remove all the encroached subsegments and bad */ +/* triangles from the triangulation. */ +/* */ +/*****************************************************************************/ + +#ifndef CDT_ONLY + +#ifdef ANSI_DECLARATORS +void enforcequality(struct mesh *m, struct behavior *b) +#else /* not ANSI_DECLARATORS */ +void enforcequality(m, b) +struct mesh *m; +struct behavior *b; +#endif /* not ANSI_DECLARATORS */ + +{ + struct badtriang *badtri; + int i; + + if (!b->quiet) { + printf("Adding Steiner points to enforce quality.\n"); + } + /* Initialize the pool of encroached subsegments. */ + poolinit(&m->badsubsegs, sizeof(struct badsubseg), BADSUBSEGPERBLOCK, + BADSUBSEGPERBLOCK, POINTER, 0); + if (b->verbose) { + printf(" Looking for encroached subsegments.\n"); + } + /* Test all segments to see if they're encroached. */ + tallyencs(m, b); + if (b->verbose && (m->badsubsegs.items > 0)) { + printf(" Splitting encroached subsegments.\n"); + } + /* Fix encroached subsegments without noting bad triangles. */ + splitencsegs(m, b, 0); + /* At this point, if we haven't run out of Steiner points, the */ + /* triangulation should be (conforming) Delaunay. */ + + /* Next, we worry about enforcing triangle quality. */ + if ((b->minangle > 0.0) || b->vararea || b->fixedarea || b->usertest) { + /* Initialize the pool of bad triangles. */ + poolinit(&m->badtriangles, sizeof(struct badtriang), BADTRIPERBLOCK, + BADTRIPERBLOCK, POINTER, 0); + /* Initialize the queues of bad triangles. */ + for (i = 0; i < 64; i++) { + m->queuefront[i] = (struct badtriang *) NULL; + } + m->firstnonemptyq = -1; + /* Test all triangles to see if they're bad. */ + tallyfaces(m, b); + /* Initialize the pool of recently flipped triangles. */ + poolinit(&m->flipstackers, sizeof(struct flipstacker), FLIPSTACKERPERBLOCK, + FLIPSTACKERPERBLOCK, POINTER, 0); + m->checkquality = 1; + if (b->verbose) { + printf(" Splitting bad triangles.\n"); + } + while ((m->badtriangles.items > 0) && (m->steinerleft != 0)) { + /* Fix one bad triangle by inserting a vertex at its circumcenter. */ + badtri = dequeuebadtriang(m); + splittriangle(m, b, badtri); + if (m->badsubsegs.items > 0) { + /* Put bad triangle back in queue for another try later. */ + enqueuebadtriang(m, b, badtri); + /* Fix any encroached subsegments that resulted. */ + /* Record any new bad triangles that result. */ + splitencsegs(m, b, 1); + } else { + /* Return the bad triangle to the pool. */ + pooldealloc(&m->badtriangles, (VOID *) badtri); + } + } + } + /* At this point, if we haven't run out of Steiner points, the */ + /* triangulation should be (conforming) Delaunay and have no */ + /* low-quality triangles. */ + + /* Might we have run out of Steiner points too soon? */ + if (!b->quiet && (m->badsubsegs.items > 0) && (m->steinerleft == 0)) { + printf("\nWarning: I ran out of Steiner points, but the mesh has\n"); + if (m->badsubsegs.items == 1) { + printf(" an encroached subsegment, and therefore might not be truly\n"); + } else { + printf(" %ld encroached subsegments, and therefore might not be truly\n" + , m->badsubsegs.items); + } + printf(" Delaunay. If the Delaunay property is important to you,\n"); + printf(" try increasing the number of Steiner points (controlled by\n"); + printf(" the -S switch) slightly and try again.\n\n"); + } +} + +#endif /* not CDT_ONLY */ + +/** **/ +/** **/ +/********* Mesh quality maintenance ends here *********/ + +/*****************************************************************************/ +/* */ +/* highorder() Create extra nodes for quadratic subparametric elements. */ +/* */ +/*****************************************************************************/ + +#ifdef ANSI_DECLARATORS +void highorder(struct mesh *m, struct behavior *b) +#else /* not ANSI_DECLARATORS */ +void highorder(m, b) +struct mesh *m; +struct behavior *b; +#endif /* not ANSI_DECLARATORS */ + +{ + struct otri triangleloop, trisym; + struct osub checkmark; + vertex newvertex; + vertex torg, tdest; + int i; + triangle ptr; /* Temporary variable used by sym(). */ + subseg sptr; /* Temporary variable used by tspivot(). */ + + if (!b->quiet) { + printf("Adding vertices for second-order triangles.\n"); + } + /* The following line ensures that dead items in the pool of nodes */ + /* cannot be allocated for the extra nodes associated with high */ + /* order elements. This ensures that the primary nodes (at the */ + /* corners of elements) will occur earlier in the output files, and */ + /* have lower indices, than the extra nodes. */ + m->vertices.deaditemstack = (VOID *) NULL; + + traversalinit(&m->triangles); + triangleloop.tri = triangletraverse(m); + /* To loop over the set of edges, loop over all triangles, and look at */ + /* the three edges of each triangle. If there isn't another triangle */ + /* adjacent to the edge, operate on the edge. If there is another */ + /* adjacent triangle, operate on the edge only if the current triangle */ + /* has a smaller pointer than its neighbor. This way, each edge is */ + /* considered only once. */ + while (triangleloop.tri != (triangle *) NULL) { + for (triangleloop.orient = 0; triangleloop.orient < 3; + triangleloop.orient++) { + sym(triangleloop, trisym); + if ((triangleloop.tri < trisym.tri) || (trisym.tri == m->dummytri)) { + org(triangleloop, torg); + dest(triangleloop, tdest); + /* Create a new node in the middle of the edge. Interpolate */ + /* its attributes. */ + newvertex = (vertex) poolalloc(&m->vertices); + for (i = 0; i < 2 + m->nextras; i++) { + newvertex[i] = 0.5 * (torg[i] + tdest[i]); + } + /* Set the new node's marker to zero or one, depending on */ + /* whether it lies on a boundary. */ + setvertexmark(newvertex, trisym.tri == m->dummytri); + setvertextype(newvertex, + trisym.tri == m->dummytri ? FREEVERTEX : SEGMENTVERTEX); + if (b->usesegments) { + tspivot(triangleloop, checkmark); + /* If this edge is a segment, transfer the marker to the new node. */ + if (checkmark.ss != m->dummysub) { + setvertexmark(newvertex, mark(checkmark)); + setvertextype(newvertex, SEGMENTVERTEX); + } + } + if (b->verbose > 1) { + printf(" Creating (%.12g, %.12g).\n", newvertex[0], newvertex[1]); + } + /* Record the new node in the (one or two) adjacent elements. */ + triangleloop.tri[m->highorderindex + triangleloop.orient] = + (triangle) newvertex; + if (trisym.tri != m->dummytri) { + trisym.tri[m->highorderindex + trisym.orient] = (triangle) newvertex; + } + } + } + triangleloop.tri = triangletraverse(m); + } +} + +/********* File I/O routines begin here *********/ +/** **/ +/** **/ + +/*****************************************************************************/ +/* */ +/* readline() Read a nonempty line from a file. */ +/* */ +/* A line is considered "nonempty" if it contains something that looks like */ +/* a number. Comments (prefaced by `#') are ignored. */ +/* */ +/*****************************************************************************/ + +#ifndef TRILIBRARY + +#ifdef ANSI_DECLARATORS +char *readline(char *string, FILE *infile, char *infilename) +#else /* not ANSI_DECLARATORS */ +char *readline(string, infile, infilename) +char *string; +FILE *infile; +char *infilename; +#endif /* not ANSI_DECLARATORS */ + +{ + char *result; + + /* Search for something that looks like a number. */ + do { + result = fgets(string, INPUTLINESIZE, infile); + if (result == (char *) NULL) { + printf(" Error: Unexpected end of file in %s.\n", infilename); + exit(1); + } + /* Skip anything that doesn't look like a number, a comment, */ + /* or the end of a line. */ + while ((*result != '\0') && (*result != '#') + && (*result != '.') && (*result != '+') && (*result != '-') + && ((*result < '0') || (*result > '9'))) { + result++; + } + /* If it's a comment or end of line, read another line and try again. */ + } while ((*result == '#') || (*result == '\0')); + return result; +} + +#endif /* not TRILIBRARY */ + +/*****************************************************************************/ +/* */ +/* findfield() Find the next field of a string. */ +/* */ +/* Jumps past the current field by searching for whitespace, then jumps */ +/* past the whitespace to find the next field. */ +/* */ +/*****************************************************************************/ + +#ifndef TRILIBRARY + +#ifdef ANSI_DECLARATORS +char *findfield(char *string) +#else /* not ANSI_DECLARATORS */ +char *findfield(string) +char *string; +#endif /* not ANSI_DECLARATORS */ + +{ + char *result; + + result = string; + /* Skip the current field. Stop upon reaching whitespace. */ + while ((*result != '\0') && (*result != '#') + && (*result != ' ') && (*result != '\t')) { + result++; + } + /* Now skip the whitespace and anything else that doesn't look like a */ + /* number, a comment, or the end of a line. */ + while ((*result != '\0') && (*result != '#') + && (*result != '.') && (*result != '+') && (*result != '-') + && ((*result < '0') || (*result > '9'))) { + result++; + } + /* Check for a comment (prefixed with `#'). */ + if (*result == '#') { + *result = '\0'; + } + return result; +} + +#endif /* not TRILIBRARY */ + +/*****************************************************************************/ +/* */ +/* readnodes() Read the vertices from a file, which may be a .node or */ +/* .poly file. */ +/* */ +/*****************************************************************************/ + +#ifndef TRILIBRARY + +#ifdef ANSI_DECLARATORS +void readnodes(struct mesh *m, struct behavior *b, char *nodefilename, + char *polyfilename, FILE **polyfile) +#else /* not ANSI_DECLARATORS */ +void readnodes(m, b, nodefilename, polyfilename, polyfile) +struct mesh *m; +struct behavior *b; +char *nodefilename; +char *polyfilename; +FILE **polyfile; +#endif /* not ANSI_DECLARATORS */ + +{ + FILE *infile; + vertex vertexloop; + char inputline[INPUTLINESIZE]; + char *stringptr; + char *infilename; + REAL x, y; + int firstnode; + int nodemarkers; + int currentmarker; + int i, j; + + if (b->poly) { + /* Read the vertices from a .poly file. */ + if (!b->quiet) { + printf("Opening %s.\n", polyfilename); + } + *polyfile = fopen(polyfilename, "r"); + if (*polyfile == (FILE *) NULL) { + printf(" Error: Cannot access file %s.\n", polyfilename); + exit(1); + } + /* Read number of vertices, number of dimensions, number of vertex */ + /* attributes, and number of boundary markers. */ + stringptr = readline(inputline, *polyfile, polyfilename); + m->invertices = (int) strtol(stringptr, &stringptr, 0); + stringptr = findfield(stringptr); + if (*stringptr == '\0') { + m->mesh_dim = 2; + } else { + m->mesh_dim = (int) strtol(stringptr, &stringptr, 0); + } + stringptr = findfield(stringptr); + if (*stringptr == '\0') { + m->nextras = 0; + } else { + m->nextras = (int) strtol(stringptr, &stringptr, 0); + } + stringptr = findfield(stringptr); + if (*stringptr == '\0') { + nodemarkers = 0; + } else { + nodemarkers = (int) strtol(stringptr, &stringptr, 0); + } + if (m->invertices > 0) { + infile = *polyfile; + infilename = polyfilename; + m->readnodefile = 0; + } else { + /* If the .poly file claims there are zero vertices, that means that */ + /* the vertices should be read from a separate .node file. */ + m->readnodefile = 1; + infilename = nodefilename; + } + } else { + m->readnodefile = 1; + infilename = nodefilename; + *polyfile = (FILE *) NULL; + } + + if (m->readnodefile) { + /* Read the vertices from a .node file. */ + if (!b->quiet) { + printf("Opening %s.\n", nodefilename); + } + infile = fopen(nodefilename, "r"); + if (infile == (FILE *) NULL) { + printf(" Error: Cannot access file %s.\n", nodefilename); + exit(1); + } + /* Read number of vertices, number of dimensions, number of vertex */ + /* attributes, and number of boundary markers. */ + stringptr = readline(inputline, infile, nodefilename); + m->invertices = (int) strtol(stringptr, &stringptr, 0); + stringptr = findfield(stringptr); + if (*stringptr == '\0') { + m->mesh_dim = 2; + } else { + m->mesh_dim = (int) strtol(stringptr, &stringptr, 0); + } + stringptr = findfield(stringptr); + if (*stringptr == '\0') { + m->nextras = 0; + } else { + m->nextras = (int) strtol(stringptr, &stringptr, 0); + } + stringptr = findfield(stringptr); + if (*stringptr == '\0') { + nodemarkers = 0; + } else { + nodemarkers = (int) strtol(stringptr, &stringptr, 0); + } + } + + if (m->invertices < 3) { + printf("Error: Input must have at least three input vertices.\n"); + exit(1); + } + if (m->mesh_dim != 2) { + printf("Error: Triangle only works with two-dimensional meshes.\n"); + exit(1); + } + if (m->nextras == 0) { + b->weighted = 0; + } + + initializevertexpool(m, b); + + /* Read the vertices. */ + for (i = 0; i < m->invertices; i++) { + vertexloop = (vertex) poolalloc(&m->vertices); + stringptr = readline(inputline, infile, infilename); + if (i == 0) { + firstnode = (int) strtol(stringptr, &stringptr, 0); + if ((firstnode == 0) || (firstnode == 1)) { + b->firstnumber = firstnode; + } + } + stringptr = findfield(stringptr); + if (*stringptr == '\0') { + printf("Error: Vertex %d has no x coordinate.\n", b->firstnumber + i); + exit(1); + } + x = (REAL) strtod(stringptr, &stringptr); + stringptr = findfield(stringptr); + if (*stringptr == '\0') { + printf("Error: Vertex %d has no y coordinate.\n", b->firstnumber + i); + exit(1); + } + y = (REAL) strtod(stringptr, &stringptr); + vertexloop[0] = x; + vertexloop[1] = y; + /* Read the vertex attributes. */ + for (j = 2; j < 2 + m->nextras; j++) { + stringptr = findfield(stringptr); + if (*stringptr == '\0') { + vertexloop[j] = 0.0; + } else { + vertexloop[j] = (REAL) strtod(stringptr, &stringptr); + } + } + if (nodemarkers) { + /* Read a vertex marker. */ + stringptr = findfield(stringptr); + if (*stringptr == '\0') { + setvertexmark(vertexloop, 0); + } else { + currentmarker = (int) strtol(stringptr, &stringptr, 0); + setvertexmark(vertexloop, currentmarker); + } + } else { + /* If no markers are specified in the file, they default to zero. */ + setvertexmark(vertexloop, 0); + } + setvertextype(vertexloop, INPUTVERTEX); + /* Determine the smallest and largest x and y coordinates. */ + if (i == 0) { + m->xmin = m->xmax = x; + m->ymin = m->ymax = y; + } else { + m->xmin = (x < m->xmin) ? x : m->xmin; + m->xmax = (x > m->xmax) ? x : m->xmax; + m->ymin = (y < m->ymin) ? y : m->ymin; + m->ymax = (y > m->ymax) ? y : m->ymax; + } + } + if (m->readnodefile) { + fclose(infile); + } + + /* Nonexistent x value used as a flag to mark circle events in sweepline */ + /* Delaunay algorithm. */ + m->xminextreme = 10 * m->xmin - 9 * m->xmax; +} + +#endif /* not TRILIBRARY */ + +/*****************************************************************************/ +/* */ +/* transfernodes() Read the vertices from memory. */ +/* */ +/*****************************************************************************/ + +#ifdef TRILIBRARY + +#ifdef ANSI_DECLARATORS +void transfernodes(struct mesh *m, struct behavior *b, REAL *pointlist, + REAL *pointattriblist, int *pointmarkerlist, + int numberofpoints, int numberofpointattribs) +#else /* not ANSI_DECLARATORS */ +void transfernodes(m, b, pointlist, pointattriblist, pointmarkerlist, + numberofpoints, numberofpointattribs) +struct mesh *m; +struct behavior *b; +REAL *pointlist; +REAL *pointattriblist; +int *pointmarkerlist; +int numberofpoints; +int numberofpointattribs; +#endif /* not ANSI_DECLARATORS */ + +{ + vertex vertexloop; + REAL x, y; + int i, j; + int coordindex; + int attribindex; + + m->invertices = numberofpoints; + m->mesh_dim = 2; + m->nextras = numberofpointattribs; + m->readnodefile = 0; + if (m->invertices < 3) { + printf("Error: Input must have at least three input vertices.\n"); + exit(1); + } + if (m->nextras == 0) { + b->weighted = 0; + } + + initializevertexpool(m, b); + + /* Read the vertices. */ + coordindex = 0; + attribindex = 0; + for (i = 0; i < m->invertices; i++) { + vertexloop = (vertex) poolalloc(&m->vertices); + /* Read the vertex coordinates. */ + x = vertexloop[0] = pointlist[coordindex++]; + y = vertexloop[1] = pointlist[coordindex++]; + /* Read the vertex attributes. */ + for (j = 0; j < numberofpointattribs; j++) { + vertexloop[2 + j] = pointattriblist[attribindex++]; + } + if (pointmarkerlist != (int *) NULL) { + /* Read a vertex marker. */ + setvertexmark(vertexloop, pointmarkerlist[i]); + } else { + /* If no markers are specified, they default to zero. */ + setvertexmark(vertexloop, 0); + } + setvertextype(vertexloop, INPUTVERTEX); + /* Determine the smallest and largest x and y coordinates. */ + if (i == 0) { + m->xmin = m->xmax = x; + m->ymin = m->ymax = y; + } else { + m->xmin = (x < m->xmin) ? x : m->xmin; + m->xmax = (x > m->xmax) ? x : m->xmax; + m->ymin = (y < m->ymin) ? y : m->ymin; + m->ymax = (y > m->ymax) ? y : m->ymax; + } + } + + /* Nonexistent x value used as a flag to mark circle events in sweepline */ + /* Delaunay algorithm. */ + m->xminextreme = 10 * m->xmin - 9 * m->xmax; +} + +#endif /* TRILIBRARY */ + +/*****************************************************************************/ +/* */ +/* readholes() Read the holes, and possibly regional attributes and area */ +/* constraints, from a .poly file. */ +/* */ +/*****************************************************************************/ + +#ifndef TRILIBRARY + +#ifdef ANSI_DECLARATORS +void readholes(struct mesh *m, struct behavior *b, + FILE *polyfile, char *polyfilename, REAL **hlist, int *holes, + REAL **rlist, int *regions) +#else /* not ANSI_DECLARATORS */ +void readholes(m, b, polyfile, polyfilename, hlist, holes, rlist, regions) +struct mesh *m; +struct behavior *b; +FILE *polyfile; +char *polyfilename; +REAL **hlist; +int *holes; +REAL **rlist; +int *regions; +#endif /* not ANSI_DECLARATORS */ + +{ + REAL *holelist; + REAL *regionlist; + char inputline[INPUTLINESIZE]; + char *stringptr; + int index; + int i; + + /* Read the holes. */ + stringptr = readline(inputline, polyfile, polyfilename); + *holes = (int) strtol(stringptr, &stringptr, 0); + if (*holes > 0) { + holelist = (REAL *) trimalloc(2 * *holes * (int) sizeof(REAL)); + *hlist = holelist; + for (i = 0; i < 2 * *holes; i += 2) { + stringptr = readline(inputline, polyfile, polyfilename); + stringptr = findfield(stringptr); + if (*stringptr == '\0') { + printf("Error: Hole %d has no x coordinate.\n", + b->firstnumber + (i >> 1)); + exit(1); + } else { + holelist[i] = (REAL) strtod(stringptr, &stringptr); + } + stringptr = findfield(stringptr); + if (*stringptr == '\0') { + printf("Error: Hole %d has no y coordinate.\n", + b->firstnumber + (i >> 1)); + exit(1); + } else { + holelist[i + 1] = (REAL) strtod(stringptr, &stringptr); + } + } + } else { + *hlist = (REAL *) NULL; + } + +#ifndef CDT_ONLY + if ((b->regionattrib || b->vararea) && !b->refine) { + /* Read the area constraints. */ + stringptr = readline(inputline, polyfile, polyfilename); + *regions = (int) strtol(stringptr, &stringptr, 0); + if (*regions > 0) { + regionlist = (REAL *) trimalloc(4 * *regions * (int) sizeof(REAL)); + *rlist = regionlist; + index = 0; + for (i = 0; i < *regions; i++) { + stringptr = readline(inputline, polyfile, polyfilename); + stringptr = findfield(stringptr); + if (*stringptr == '\0') { + printf("Error: Region %d has no x coordinate.\n", + b->firstnumber + i); + exit(1); + } else { + regionlist[index++] = (REAL) strtod(stringptr, &stringptr); + } + stringptr = findfield(stringptr); + if (*stringptr == '\0') { + printf("Error: Region %d has no y coordinate.\n", + b->firstnumber + i); + exit(1); + } else { + regionlist[index++] = (REAL) strtod(stringptr, &stringptr); + } + stringptr = findfield(stringptr); + if (*stringptr == '\0') { + printf( + "Error: Region %d has no region attribute or area constraint.\n", + b->firstnumber + i); + exit(1); + } else { + regionlist[index++] = (REAL) strtod(stringptr, &stringptr); + } + stringptr = findfield(stringptr); + if (*stringptr == '\0') { + regionlist[index] = regionlist[index - 1]; + } else { + regionlist[index] = (REAL) strtod(stringptr, &stringptr); + } + index++; + } + } + } else { + /* Set `*regions' to zero to avoid an accidental free() later. */ + *regions = 0; + *rlist = (REAL *) NULL; + } +#endif /* not CDT_ONLY */ + + fclose(polyfile); +} + +#endif /* not TRILIBRARY */ + +/*****************************************************************************/ +/* */ +/* finishfile() Write the command line to the output file so the user */ +/* can remember how the file was generated. Close the file. */ +/* */ +/*****************************************************************************/ + +#ifndef TRILIBRARY + +#ifdef ANSI_DECLARATORS +void finishfile(FILE *outfile, int argc, char **argv) +#else /* not ANSI_DECLARATORS */ +void finishfile(outfile, argc, argv) +FILE *outfile; +int argc; +char **argv; +#endif /* not ANSI_DECLARATORS */ + +{ + int i; + + fprintf(outfile, "# Generated by"); + for (i = 0; i < argc; i++) { + fprintf(outfile, " "); + fputs(argv[i], outfile); + } + fprintf(outfile, "\n"); + fclose(outfile); +} + +#endif /* not TRILIBRARY */ + +/*****************************************************************************/ +/* */ +/* writenodes() Number the vertices and write them to a .node file. */ +/* */ +/* To save memory, the vertex numbers are written over the boundary markers */ +/* after the vertices are written to a file. */ +/* */ +/*****************************************************************************/ + +#ifdef TRILIBRARY + +#ifdef ANSI_DECLARATORS +void writenodes(struct mesh *m, struct behavior *b, REAL **pointlist, + REAL **pointattriblist, int **pointmarkerlist) +#else /* not ANSI_DECLARATORS */ +void writenodes(m, b, pointlist, pointattriblist, pointmarkerlist) +struct mesh *m; +struct behavior *b; +REAL **pointlist; +REAL **pointattriblist; +int **pointmarkerlist; +#endif /* not ANSI_DECLARATORS */ + +#else /* not TRILIBRARY */ + +#ifdef ANSI_DECLARATORS +void writenodes(struct mesh *m, struct behavior *b, char *nodefilename, + int argc, char **argv) +#else /* not ANSI_DECLARATORS */ +void writenodes(m, b, nodefilename, argc, argv) +struct mesh *m; +struct behavior *b; +char *nodefilename; +int argc; +char **argv; +#endif /* not ANSI_DECLARATORS */ + +#endif /* not TRILIBRARY */ + +{ +#ifdef TRILIBRARY + REAL *plist; + REAL *palist; + int *pmlist; + int coordindex; + int attribindex; +#else /* not TRILIBRARY */ + FILE *outfile; +#endif /* not TRILIBRARY */ + vertex vertexloop; + long outvertices; + int vertexnumber; + int i; + + if (b->jettison) { + outvertices = m->vertices.items - m->undeads; + } else { + outvertices = m->vertices.items; + } + +#ifdef TRILIBRARY + if (!b->quiet) { + printf("Writing vertices.\n"); + } + /* Allocate memory for output vertices if necessary. */ + if (*pointlist == (REAL *) NULL) { + *pointlist = (REAL *) trimalloc(outvertices * 2 * sizeof(REAL)); + } + /* Allocate memory for output vertex attributes if necessary. */ + if ((m->nextras > 0) && (*pointattriblist == (REAL *) NULL)) { + *pointattriblist = (REAL *) trimalloc(outvertices * m->nextras * + sizeof(REAL)); + } + /* Allocate memory for output vertex markers if necessary. */ + if (!b->nobound && (*pointmarkerlist == (int *) NULL)) { + *pointmarkerlist = (int *) trimalloc(outvertices * sizeof(int)); + } + plist = *pointlist; + palist = *pointattriblist; + pmlist = *pointmarkerlist; + coordindex = 0; + attribindex = 0; +#else /* not TRILIBRARY */ + if (!b->quiet) { + printf("Writing %s.\n", nodefilename); + } + outfile = fopen(nodefilename, "w"); + if (outfile == (FILE *) NULL) { + printf(" Error: Cannot create file %s.\n", nodefilename); + exit(1); + } + /* Number of vertices, number of dimensions, number of vertex attributes, */ + /* and number of boundary markers (zero or one). */ + fprintf(outfile, "%ld %d %d %d\n", outvertices, m->mesh_dim, + m->nextras, 1 - b->nobound); +#endif /* not TRILIBRARY */ + + traversalinit(&m->vertices); + vertexnumber = b->firstnumber; + vertexloop = vertextraverse(m); + while (vertexloop != (vertex) NULL) { + if (!b->jettison || (vertextype(vertexloop) != UNDEADVERTEX)) { +#ifdef TRILIBRARY + /* X and y coordinates. */ + plist[coordindex++] = vertexloop[0]; + plist[coordindex++] = vertexloop[1]; + /* Vertex attributes. */ + for (i = 0; i < m->nextras; i++) { + palist[attribindex++] = vertexloop[2 + i]; + } + if (!b->nobound) { + /* Copy the boundary marker. */ + pmlist[vertexnumber - b->firstnumber] = vertexmark(vertexloop); + } +#else /* not TRILIBRARY */ + /* Vertex number, x and y coordinates. */ + fprintf(outfile, "%4d %.17g %.17g", vertexnumber, vertexloop[0], + vertexloop[1]); + for (i = 0; i < m->nextras; i++) { + /* Write an attribute. */ + fprintf(outfile, " %.17g", vertexloop[i + 2]); + } + if (b->nobound) { + fprintf(outfile, "\n"); + } else { + /* Write the boundary marker. */ + fprintf(outfile, " %d\n", vertexmark(vertexloop)); + } +#endif /* not TRILIBRARY */ + + setvertexmark(vertexloop, vertexnumber); + vertexnumber++; + } + vertexloop = vertextraverse(m); + } + +#ifndef TRILIBRARY + finishfile(outfile, argc, argv); +#endif /* not TRILIBRARY */ +} + +/*****************************************************************************/ +/* */ +/* numbernodes() Number the vertices. */ +/* */ +/* Each vertex is assigned a marker equal to its number. */ +/* */ +/* Used when writenodes() is not called because no .node file is written. */ +/* */ +/*****************************************************************************/ + +#ifdef ANSI_DECLARATORS +void numbernodes(struct mesh *m, struct behavior *b) +#else /* not ANSI_DECLARATORS */ +void numbernodes(m, b) +struct mesh *m; +struct behavior *b; +#endif /* not ANSI_DECLARATORS */ + +{ + vertex vertexloop; + int vertexnumber; + + traversalinit(&m->vertices); + vertexnumber = b->firstnumber; + vertexloop = vertextraverse(m); + while (vertexloop != (vertex) NULL) { + setvertexmark(vertexloop, vertexnumber); + if (!b->jettison || (vertextype(vertexloop) != UNDEADVERTEX)) { + vertexnumber++; + } + vertexloop = vertextraverse(m); + } +} + +/*****************************************************************************/ +/* */ +/* writeelements() Write the triangles to an .ele file. */ +/* */ +/*****************************************************************************/ + +#ifdef TRILIBRARY + +#ifdef ANSI_DECLARATORS +void writeelements(struct mesh *m, struct behavior *b, + int **trianglelist, REAL **triangleattriblist) +#else /* not ANSI_DECLARATORS */ +void writeelements(m, b, trianglelist, triangleattriblist) +struct mesh *m; +struct behavior *b; +int **trianglelist; +REAL **triangleattriblist; +#endif /* not ANSI_DECLARATORS */ + +#else /* not TRILIBRARY */ + +#ifdef ANSI_DECLARATORS +void writeelements(struct mesh *m, struct behavior *b, char *elefilename, + int argc, char **argv) +#else /* not ANSI_DECLARATORS */ +void writeelements(m, b, elefilename, argc, argv) +struct mesh *m; +struct behavior *b; +char *elefilename; +int argc; +char **argv; +#endif /* not ANSI_DECLARATORS */ + +#endif /* not TRILIBRARY */ + +{ +#ifdef TRILIBRARY + int *tlist; + REAL *talist; + int vertexindex; + int attribindex; +#else /* not TRILIBRARY */ + FILE *outfile; +#endif /* not TRILIBRARY */ + struct otri triangleloop; + vertex p1, p2, p3; + vertex mid1, mid2, mid3; + long elementnumber; + int i; + +#ifdef TRILIBRARY + if (!b->quiet) { + printf("Writing triangles.\n"); + } + /* Allocate memory for output triangles if necessary. */ + if (*trianglelist == (int *) NULL) { + *trianglelist = (int *) trimalloc(m->triangles.items * + ((b->order + 1) * (b->order + 2) / 2) * + sizeof(int)); + } + /* Allocate memory for output triangle attributes if necessary. */ + if ((m->eextras > 0) && (*triangleattriblist == (REAL *) NULL)) { + *triangleattriblist = (REAL *) trimalloc(m->triangles.items * m->eextras * + sizeof(REAL)); + } + tlist = *trianglelist; + talist = *triangleattriblist; + vertexindex = 0; + attribindex = 0; +#else /* not TRILIBRARY */ + if (!b->quiet) { + printf("Writing %s.\n", elefilename); + } + outfile = fopen(elefilename, "w"); + if (outfile == (FILE *) NULL) { + printf(" Error: Cannot create file %s.\n", elefilename); + exit(1); + } + /* Number of triangles, vertices per triangle, attributes per triangle. */ + fprintf(outfile, "%ld %d %d\n", m->triangles.items, + (b->order + 1) * (b->order + 2) / 2, m->eextras); +#endif /* not TRILIBRARY */ + + traversalinit(&m->triangles); + triangleloop.tri = triangletraverse(m); + triangleloop.orient = 0; + elementnumber = b->firstnumber; + while (triangleloop.tri != (triangle *) NULL) { + org(triangleloop, p1); + dest(triangleloop, p2); + apex(triangleloop, p3); + if (b->order == 1) { +#ifdef TRILIBRARY + tlist[vertexindex++] = vertexmark(p1); + tlist[vertexindex++] = vertexmark(p2); + tlist[vertexindex++] = vertexmark(p3); +#else /* not TRILIBRARY */ + /* Triangle number, indices for three vertices. */ + fprintf(outfile, "%4ld %4d %4d %4d", elementnumber, + vertexmark(p1), vertexmark(p2), vertexmark(p3)); +#endif /* not TRILIBRARY */ + } else { + mid1 = (vertex) triangleloop.tri[m->highorderindex + 1]; + mid2 = (vertex) triangleloop.tri[m->highorderindex + 2]; + mid3 = (vertex) triangleloop.tri[m->highorderindex]; +#ifdef TRILIBRARY + tlist[vertexindex++] = vertexmark(p1); + tlist[vertexindex++] = vertexmark(p2); + tlist[vertexindex++] = vertexmark(p3); + tlist[vertexindex++] = vertexmark(mid1); + tlist[vertexindex++] = vertexmark(mid2); + tlist[vertexindex++] = vertexmark(mid3); +#else /* not TRILIBRARY */ + /* Triangle number, indices for six vertices. */ + fprintf(outfile, "%4ld %4d %4d %4d %4d %4d %4d", elementnumber, + vertexmark(p1), vertexmark(p2), vertexmark(p3), vertexmark(mid1), + vertexmark(mid2), vertexmark(mid3)); +#endif /* not TRILIBRARY */ + } + +#ifdef TRILIBRARY + for (i = 0; i < m->eextras; i++) { + talist[attribindex++] = elemattribute(triangleloop, i); + } +#else /* not TRILIBRARY */ + for (i = 0; i < m->eextras; i++) { + fprintf(outfile, " %.17g", elemattribute(triangleloop, i)); + } + fprintf(outfile, "\n"); +#endif /* not TRILIBRARY */ + + triangleloop.tri = triangletraverse(m); + elementnumber++; + } + +#ifndef TRILIBRARY + finishfile(outfile, argc, argv); +#endif /* not TRILIBRARY */ +} + +/*****************************************************************************/ +/* */ +/* writepoly() Write the segments and holes to a .poly file. */ +/* */ +/*****************************************************************************/ + +#ifdef TRILIBRARY + +#ifdef ANSI_DECLARATORS +void writepoly(struct mesh *m, struct behavior *b, + int **segmentlist, int **segmentmarkerlist) +#else /* not ANSI_DECLARATORS */ +void writepoly(m, b, segmentlist, segmentmarkerlist) +struct mesh *m; +struct behavior *b; +int **segmentlist; +int **segmentmarkerlist; +#endif /* not ANSI_DECLARATORS */ + +#else /* not TRILIBRARY */ + +#ifdef ANSI_DECLARATORS +void writepoly(struct mesh *m, struct behavior *b, char *polyfilename, + REAL *holelist, int holes, REAL *regionlist, int regions, + int argc, char **argv) +#else /* not ANSI_DECLARATORS */ +void writepoly(m, b, polyfilename, holelist, holes, regionlist, regions, + argc, argv) +struct mesh *m; +struct behavior *b; +char *polyfilename; +REAL *holelist; +int holes; +REAL *regionlist; +int regions; +int argc; +char **argv; +#endif /* not ANSI_DECLARATORS */ + +#endif /* not TRILIBRARY */ + +{ +#ifdef TRILIBRARY + int *slist; + int *smlist; + int index; +#else /* not TRILIBRARY */ + FILE *outfile; + long holenumber, regionnumber; +#endif /* not TRILIBRARY */ + struct osub subsegloop; + vertex endpoint1, endpoint2; + long subsegnumber; + +#ifdef TRILIBRARY + if (!b->quiet) { + printf("Writing segments.\n"); + } + /* Allocate memory for output segments if necessary. */ + if (*segmentlist == (int *) NULL) { + *segmentlist = (int *) trimalloc(m->subsegs.items * 2 * sizeof(int)); + } + /* Allocate memory for output segment markers if necessary. */ + if (!b->nobound && (*segmentmarkerlist == (int *) NULL)) { + *segmentmarkerlist = (int *) trimalloc(m->subsegs.items * sizeof(int)); + } + slist = *segmentlist; + smlist = *segmentmarkerlist; + index = 0; +#else /* not TRILIBRARY */ + if (!b->quiet) { + printf("Writing %s.\n", polyfilename); + } + outfile = fopen(polyfilename, "w"); + if (outfile == (FILE *) NULL) { + printf(" Error: Cannot create file %s.\n", polyfilename); + exit(1); + } + /* The zero indicates that the vertices are in a separate .node file. */ + /* Followed by number of dimensions, number of vertex attributes, */ + /* and number of boundary markers (zero or one). */ + fprintf(outfile, "%d %d %d %d\n", 0, m->mesh_dim, m->nextras, + 1 - b->nobound); + /* Number of segments, number of boundary markers (zero or one). */ + fprintf(outfile, "%ld %d\n", m->subsegs.items, 1 - b->nobound); +#endif /* not TRILIBRARY */ + + traversalinit(&m->subsegs); + subsegloop.ss = subsegtraverse(m); + subsegloop.ssorient = 0; + subsegnumber = b->firstnumber; + while (subsegloop.ss != (subseg *) NULL) { + sorg(subsegloop, endpoint1); + sdest(subsegloop, endpoint2); +#ifdef TRILIBRARY + /* Copy indices of the segment's two endpoints. */ + slist[index++] = vertexmark(endpoint1); + slist[index++] = vertexmark(endpoint2); + if (!b->nobound) { + /* Copy the boundary marker. */ + smlist[subsegnumber - b->firstnumber] = mark(subsegloop); + } +#else /* not TRILIBRARY */ + /* Segment number, indices of its two endpoints, and possibly a marker. */ + if (b->nobound) { + fprintf(outfile, "%4ld %4d %4d\n", subsegnumber, + vertexmark(endpoint1), vertexmark(endpoint2)); + } else { + fprintf(outfile, "%4ld %4d %4d %4d\n", subsegnumber, + vertexmark(endpoint1), vertexmark(endpoint2), mark(subsegloop)); + } +#endif /* not TRILIBRARY */ + + subsegloop.ss = subsegtraverse(m); + subsegnumber++; + } + +#ifndef TRILIBRARY +#ifndef CDT_ONLY + fprintf(outfile, "%d\n", holes); + if (holes > 0) { + for (holenumber = 0; holenumber < holes; holenumber++) { + /* Hole number, x and y coordinates. */ + fprintf(outfile, "%4ld %.17g %.17g\n", b->firstnumber + holenumber, + holelist[2 * holenumber], holelist[2 * holenumber + 1]); + } + } + if (regions > 0) { + fprintf(outfile, "%d\n", regions); + for (regionnumber = 0; regionnumber < regions; regionnumber++) { + /* Region number, x and y coordinates, attribute, maximum area. */ + fprintf(outfile, "%4ld %.17g %.17g %.17g %.17g\n", + b->firstnumber + regionnumber, + regionlist[4 * regionnumber], regionlist[4 * regionnumber + 1], + regionlist[4 * regionnumber + 2], + regionlist[4 * regionnumber + 3]); + } + } +#endif /* not CDT_ONLY */ + + finishfile(outfile, argc, argv); +#endif /* not TRILIBRARY */ +} + +/*****************************************************************************/ +/* */ +/* writeedges() Write the edges to an .edge file. */ +/* */ +/*****************************************************************************/ + +#ifdef TRILIBRARY + +#ifdef ANSI_DECLARATORS +void writeedges(struct mesh *m, struct behavior *b, + int **edgelist, int **edgemarkerlist) +#else /* not ANSI_DECLARATORS */ +void writeedges(m, b, edgelist, edgemarkerlist) +struct mesh *m; +struct behavior *b; +int **edgelist; +int **edgemarkerlist; +#endif /* not ANSI_DECLARATORS */ + +#else /* not TRILIBRARY */ + +#ifdef ANSI_DECLARATORS +void writeedges(struct mesh *m, struct behavior *b, char *edgefilename, + int argc, char **argv) +#else /* not ANSI_DECLARATORS */ +void writeedges(m, b, edgefilename, argc, argv) +struct mesh *m; +struct behavior *b; +char *edgefilename; +int argc; +char **argv; +#endif /* not ANSI_DECLARATORS */ + +#endif /* not TRILIBRARY */ + +{ +#ifdef TRILIBRARY + int *elist; + int *emlist; + int index; +#else /* not TRILIBRARY */ + FILE *outfile; +#endif /* not TRILIBRARY */ + struct otri triangleloop, trisym; + struct osub checkmark; + vertex p1, p2; + long edgenumber; + triangle ptr; /* Temporary variable used by sym(). */ + subseg sptr; /* Temporary variable used by tspivot(). */ + +#ifdef TRILIBRARY + if (!b->quiet) { + printf("Writing edges.\n"); + } + /* Allocate memory for edges if necessary. */ + if (*edgelist == (int *) NULL) { + *edgelist = (int *) trimalloc(m->edges * 2 * sizeof(int)); + } + /* Allocate memory for edge markers if necessary. */ + if (!b->nobound && (*edgemarkerlist == (int *) NULL)) { + *edgemarkerlist = (int *) trimalloc(m->edges * sizeof(int)); + } + elist = *edgelist; + emlist = *edgemarkerlist; + index = 0; +#else /* not TRILIBRARY */ + if (!b->quiet) { + printf("Writing %s.\n", edgefilename); + } + outfile = fopen(edgefilename, "w"); + if (outfile == (FILE *) NULL) { + printf(" Error: Cannot create file %s.\n", edgefilename); + exit(1); + } + /* Number of edges, number of boundary markers (zero or one). */ + fprintf(outfile, "%ld %d\n", m->edges, 1 - b->nobound); +#endif /* not TRILIBRARY */ + + traversalinit(&m->triangles); + triangleloop.tri = triangletraverse(m); + edgenumber = b->firstnumber; + /* To loop over the set of edges, loop over all triangles, and look at */ + /* the three edges of each triangle. If there isn't another triangle */ + /* adjacent to the edge, operate on the edge. If there is another */ + /* adjacent triangle, operate on the edge only if the current triangle */ + /* has a smaller pointer than its neighbor. This way, each edge is */ + /* considered only once. */ + while (triangleloop.tri != (triangle *) NULL) { + for (triangleloop.orient = 0; triangleloop.orient < 3; + triangleloop.orient++) { + sym(triangleloop, trisym); + if ((triangleloop.tri < trisym.tri) || (trisym.tri == m->dummytri)) { + org(triangleloop, p1); + dest(triangleloop, p2); +#ifdef TRILIBRARY + elist[index++] = vertexmark(p1); + elist[index++] = vertexmark(p2); +#endif /* TRILIBRARY */ + if (b->nobound) { +#ifndef TRILIBRARY + /* Edge number, indices of two endpoints. */ + fprintf(outfile, "%4ld %d %d\n", edgenumber, + vertexmark(p1), vertexmark(p2)); +#endif /* not TRILIBRARY */ + } else { + /* Edge number, indices of two endpoints, and a boundary marker. */ + /* If there's no subsegment, the boundary marker is zero. */ + if (b->usesegments) { + tspivot(triangleloop, checkmark); + if (checkmark.ss == m->dummysub) { +#ifdef TRILIBRARY + emlist[edgenumber - b->firstnumber] = 0; +#else /* not TRILIBRARY */ + fprintf(outfile, "%4ld %d %d %d\n", edgenumber, + vertexmark(p1), vertexmark(p2), 0); +#endif /* not TRILIBRARY */ + } else { +#ifdef TRILIBRARY + emlist[edgenumber - b->firstnumber] = mark(checkmark); +#else /* not TRILIBRARY */ + fprintf(outfile, "%4ld %d %d %d\n", edgenumber, + vertexmark(p1), vertexmark(p2), mark(checkmark)); +#endif /* not TRILIBRARY */ + } + } else { +#ifdef TRILIBRARY + emlist[edgenumber - b->firstnumber] = trisym.tri == m->dummytri; +#else /* not TRILIBRARY */ + fprintf(outfile, "%4ld %d %d %d\n", edgenumber, + vertexmark(p1), vertexmark(p2), trisym.tri == m->dummytri); +#endif /* not TRILIBRARY */ + } + } + edgenumber++; + } + } + triangleloop.tri = triangletraverse(m); + } + +#ifndef TRILIBRARY + finishfile(outfile, argc, argv); +#endif /* not TRILIBRARY */ +} + +/*****************************************************************************/ +/* */ +/* writevoronoi() Write the Voronoi diagram to a .v.node and .v.edge */ +/* file. */ +/* */ +/* The Voronoi diagram is the geometric dual of the Delaunay triangulation. */ +/* Hence, the Voronoi vertices are listed by traversing the Delaunay */ +/* triangles, and the Voronoi edges are listed by traversing the Delaunay */ +/* edges. */ +/* */ +/* WARNING: In order to assign numbers to the Voronoi vertices, this */ +/* procedure messes up the subsegments or the extra nodes of every */ +/* element. Hence, you should call this procedure last. */ +/* */ +/*****************************************************************************/ + +#ifdef TRILIBRARY + +#ifdef ANSI_DECLARATORS +void writevoronoi(struct mesh *m, struct behavior *b, REAL **vpointlist, + REAL **vpointattriblist, int **vpointmarkerlist, + int **vedgelist, int **vedgemarkerlist, REAL **vnormlist) +#else /* not ANSI_DECLARATORS */ +void writevoronoi(m, b, vpointlist, vpointattriblist, vpointmarkerlist, + vedgelist, vedgemarkerlist, vnormlist) +struct mesh *m; +struct behavior *b; +REAL **vpointlist; +REAL **vpointattriblist; +int **vpointmarkerlist; +int **vedgelist; +int **vedgemarkerlist; +REAL **vnormlist; +#endif /* not ANSI_DECLARATORS */ + +#else /* not TRILIBRARY */ + +#ifdef ANSI_DECLARATORS +void writevoronoi(struct mesh *m, struct behavior *b, char *vnodefilename, + char *vedgefilename, int argc, char **argv) +#else /* not ANSI_DECLARATORS */ +void writevoronoi(m, b, vnodefilename, vedgefilename, argc, argv) +struct mesh *m; +struct behavior *b; +char *vnodefilename; +char *vedgefilename; +int argc; +char **argv; +#endif /* not ANSI_DECLARATORS */ + +#endif /* not TRILIBRARY */ + +{ +#ifdef TRILIBRARY + REAL *plist; + REAL *palist; + int *elist; + REAL *normlist; + int coordindex; + int attribindex; +#else /* not TRILIBRARY */ + FILE *outfile; +#endif /* not TRILIBRARY */ + struct otri triangleloop, trisym; + vertex torg, tdest, tapex; + REAL circumcenter[2]; + REAL xi, eta; + REAL dum; + long vnodenumber, vedgenumber; + int p1, p2; + int i; + triangle ptr; /* Temporary variable used by sym(). */ + +#ifdef TRILIBRARY + if (!b->quiet) { + printf("Writing Voronoi vertices.\n"); + } + /* Allocate memory for Voronoi vertices if necessary. */ + if (*vpointlist == (REAL *) NULL) { + *vpointlist = (REAL *) trimalloc(m->triangles.items * 2 * sizeof(REAL)); + } + /* Allocate memory for Voronoi vertex attributes if necessary. */ + if (*vpointattriblist == (REAL *) NULL) { + *vpointattriblist = (REAL *) trimalloc(m->triangles.items * m->nextras * + sizeof(REAL)); + } + *vpointmarkerlist = (int *) NULL; + plist = *vpointlist; + palist = *vpointattriblist; + coordindex = 0; + attribindex = 0; +#else /* not TRILIBRARY */ + if (!b->quiet) { + printf("Writing %s.\n", vnodefilename); + } + outfile = fopen(vnodefilename, "w"); + if (outfile == (FILE *) NULL) { + printf(" Error: Cannot create file %s.\n", vnodefilename); + exit(1); + } + /* Number of triangles, two dimensions, number of vertex attributes, */ + /* no markers. */ + fprintf(outfile, "%ld %d %d %d\n", m->triangles.items, 2, m->nextras, 0); +#endif /* not TRILIBRARY */ + + traversalinit(&m->triangles); + triangleloop.tri = triangletraverse(m); + triangleloop.orient = 0; + vnodenumber = b->firstnumber; + while (triangleloop.tri != (triangle *) NULL) { + org(triangleloop, torg); + dest(triangleloop, tdest); + apex(triangleloop, tapex); + findcircumcenter(m, b, torg, tdest, tapex, circumcenter, &xi, &eta, &dum, + 0); +#ifdef TRILIBRARY + /* X and y coordinates. */ + plist[coordindex++] = circumcenter[0]; + plist[coordindex++] = circumcenter[1]; + for (i = 2; i < 2 + m->nextras; i++) { + /* Interpolate the vertex attributes at the circumcenter. */ + palist[attribindex++] = torg[i] + xi * (tdest[i] - torg[i]) + + eta * (tapex[i] - torg[i]); + } +#else /* not TRILIBRARY */ + /* Voronoi vertex number, x and y coordinates. */ + fprintf(outfile, "%4ld %.17g %.17g", vnodenumber, circumcenter[0], + circumcenter[1]); + for (i = 2; i < 2 + m->nextras; i++) { + /* Interpolate the vertex attributes at the circumcenter. */ + fprintf(outfile, " %.17g", torg[i] + xi * (tdest[i] - torg[i]) + + eta * (tapex[i] - torg[i])); + } + fprintf(outfile, "\n"); +#endif /* not TRILIBRARY */ + + * (int *) (triangleloop.tri + 6) = (int) vnodenumber; + triangleloop.tri = triangletraverse(m); + vnodenumber++; + } + +#ifndef TRILIBRARY + finishfile(outfile, argc, argv); +#endif /* not TRILIBRARY */ + +#ifdef TRILIBRARY + if (!b->quiet) { + printf("Writing Voronoi edges.\n"); + } + /* Allocate memory for output Voronoi edges if necessary. */ + if (*vedgelist == (int *) NULL) { + *vedgelist = (int *) trimalloc(m->edges * 2 * sizeof(int)); + } + *vedgemarkerlist = (int *) NULL; + /* Allocate memory for output Voronoi norms if necessary. */ + if (*vnormlist == (REAL *) NULL) { + *vnormlist = (REAL *) trimalloc(m->edges * 2 * sizeof(REAL)); + } + elist = *vedgelist; + normlist = *vnormlist; + coordindex = 0; +#else /* not TRILIBRARY */ + if (!b->quiet) { + printf("Writing %s.\n", vedgefilename); + } + outfile = fopen(vedgefilename, "w"); + if (outfile == (FILE *) NULL) { + printf(" Error: Cannot create file %s.\n", vedgefilename); + exit(1); + } + /* Number of edges, zero boundary markers. */ + fprintf(outfile, "%ld %d\n", m->edges, 0); +#endif /* not TRILIBRARY */ + + traversalinit(&m->triangles); + triangleloop.tri = triangletraverse(m); + vedgenumber = b->firstnumber; + /* To loop over the set of edges, loop over all triangles, and look at */ + /* the three edges of each triangle. If there isn't another triangle */ + /* adjacent to the edge, operate on the edge. If there is another */ + /* adjacent triangle, operate on the edge only if the current triangle */ + /* has a smaller pointer than its neighbor. This way, each edge is */ + /* considered only once. */ + while (triangleloop.tri != (triangle *) NULL) { + for (triangleloop.orient = 0; triangleloop.orient < 3; + triangleloop.orient++) { + sym(triangleloop, trisym); + if ((triangleloop.tri < trisym.tri) || (trisym.tri == m->dummytri)) { + /* Find the number of this triangle (and Voronoi vertex). */ + p1 = * (int *) (triangleloop.tri + 6); + if (trisym.tri == m->dummytri) { + org(triangleloop, torg); + dest(triangleloop, tdest); +#ifdef TRILIBRARY + /* Copy an infinite ray. Index of one endpoint, and -1. */ + elist[coordindex] = p1; + normlist[coordindex++] = tdest[1] - torg[1]; + elist[coordindex] = -1; + normlist[coordindex++] = torg[0] - tdest[0]; +#else /* not TRILIBRARY */ + /* Write an infinite ray. Edge number, index of one endpoint, -1, */ + /* and x and y coordinates of a vector representing the */ + /* direction of the ray. */ + fprintf(outfile, "%4ld %d %d %.17g %.17g\n", vedgenumber, + p1, -1, tdest[1] - torg[1], torg[0] - tdest[0]); +#endif /* not TRILIBRARY */ + } else { + /* Find the number of the adjacent triangle (and Voronoi vertex). */ + p2 = * (int *) (trisym.tri + 6); + /* Finite edge. Write indices of two endpoints. */ +#ifdef TRILIBRARY + elist[coordindex] = p1; + normlist[coordindex++] = 0.0; + elist[coordindex] = p2; + normlist[coordindex++] = 0.0; +#else /* not TRILIBRARY */ + fprintf(outfile, "%4ld %d %d\n", vedgenumber, p1, p2); +#endif /* not TRILIBRARY */ + } + vedgenumber++; + } + } + triangleloop.tri = triangletraverse(m); + } + +#ifndef TRILIBRARY + finishfile(outfile, argc, argv); +#endif /* not TRILIBRARY */ +} + +#ifdef TRILIBRARY + +#ifdef ANSI_DECLARATORS +void writeneighbors(struct mesh *m, struct behavior *b, int **neighborlist) +#else /* not ANSI_DECLARATORS */ +void writeneighbors(m, b, neighborlist) +struct mesh *m; +struct behavior *b; +int **neighborlist; +#endif /* not ANSI_DECLARATORS */ + +#else /* not TRILIBRARY */ + +#ifdef ANSI_DECLARATORS +void writeneighbors(struct mesh *m, struct behavior *b, char *neighborfilename, + int argc, char **argv) +#else /* not ANSI_DECLARATORS */ +void writeneighbors(m, b, neighborfilename, argc, argv) +struct mesh *m; +struct behavior *b; +char *neighborfilename; +int argc; +char **argv; +#endif /* not ANSI_DECLARATORS */ + +#endif /* not TRILIBRARY */ + +{ +#ifdef TRILIBRARY + int *nlist; + int index; +#else /* not TRILIBRARY */ + FILE *outfile; +#endif /* not TRILIBRARY */ + struct otri triangleloop, trisym; + long elementnumber; + int neighbor1, neighbor2, neighbor3; + triangle ptr; /* Temporary variable used by sym(). */ + +#ifdef TRILIBRARY + if (!b->quiet) { + printf("Writing neighbors.\n"); + } + /* Allocate memory for neighbors if necessary. */ + if (*neighborlist == (int *) NULL) { + *neighborlist = (int *) trimalloc(m->triangles.items * 3 * sizeof(int)); + } + nlist = *neighborlist; + index = 0; +#else /* not TRILIBRARY */ + if (!b->quiet) { + printf("Writing %s.\n", neighborfilename); + } + outfile = fopen(neighborfilename, "w"); + if (outfile == (FILE *) NULL) { + printf(" Error: Cannot create file %s.\n", neighborfilename); + exit(1); + } + /* Number of triangles, three neighbors per triangle. */ + fprintf(outfile, "%ld %d\n", m->triangles.items, 3); +#endif /* not TRILIBRARY */ + + traversalinit(&m->triangles); + triangleloop.tri = triangletraverse(m); + triangleloop.orient = 0; + elementnumber = b->firstnumber; + while (triangleloop.tri != (triangle *) NULL) { + * (int *) (triangleloop.tri + 6) = (int) elementnumber; + triangleloop.tri = triangletraverse(m); + elementnumber++; + } + * (int *) (m->dummytri + 6) = -1; + + traversalinit(&m->triangles); + triangleloop.tri = triangletraverse(m); + elementnumber = b->firstnumber; + while (triangleloop.tri != (triangle *) NULL) { + triangleloop.orient = 1; + sym(triangleloop, trisym); + neighbor1 = * (int *) (trisym.tri + 6); + triangleloop.orient = 2; + sym(triangleloop, trisym); + neighbor2 = * (int *) (trisym.tri + 6); + triangleloop.orient = 0; + sym(triangleloop, trisym); + neighbor3 = * (int *) (trisym.tri + 6); +#ifdef TRILIBRARY + nlist[index++] = neighbor1; + nlist[index++] = neighbor2; + nlist[index++] = neighbor3; +#else /* not TRILIBRARY */ + /* Triangle number, neighboring triangle numbers. */ + fprintf(outfile, "%4ld %d %d %d\n", elementnumber, + neighbor1, neighbor2, neighbor3); +#endif /* not TRILIBRARY */ + + triangleloop.tri = triangletraverse(m); + elementnumber++; + } + +#ifndef TRILIBRARY + finishfile(outfile, argc, argv); +#endif /* not TRILIBRARY */ +} + +/*****************************************************************************/ +/* */ +/* writeoff() Write the triangulation to an .off file. */ +/* */ +/* OFF stands for the Object File Format, a format used by the Geometry */ +/* Center's Geomview package. */ +/* */ +/*****************************************************************************/ + +#ifndef TRILIBRARY + +#ifdef ANSI_DECLARATORS +void writeoff(struct mesh *m, struct behavior *b, char *offfilename, + int argc, char **argv) +#else /* not ANSI_DECLARATORS */ +void writeoff(m, b, offfilename, argc, argv) +struct mesh *m; +struct behavior *b; +char *offfilename; +int argc; +char **argv; +#endif /* not ANSI_DECLARATORS */ + +{ + FILE *outfile; + struct otri triangleloop; + vertex vertexloop; + vertex p1, p2, p3; + long outvertices; + + if (!b->quiet) { + printf("Writing %s.\n", offfilename); + } + + if (b->jettison) { + outvertices = m->vertices.items - m->undeads; + } else { + outvertices = m->vertices.items; + } + + outfile = fopen(offfilename, "w"); + if (outfile == (FILE *) NULL) { + printf(" Error: Cannot create file %s.\n", offfilename); + exit(1); + } + /* Number of vertices, triangles, and edges. */ + fprintf(outfile, "OFF\n%ld %ld %ld\n", outvertices, m->triangles.items, + m->edges); + + /* Write the vertices. */ + traversalinit(&m->vertices); + vertexloop = vertextraverse(m); + while (vertexloop != (vertex) NULL) { + if (!b->jettison || (vertextype(vertexloop) != UNDEADVERTEX)) { + /* The "0.0" is here because the OFF format uses 3D coordinates. */ + fprintf(outfile, " %.17g %.17g %.17g\n", vertexloop[0], vertexloop[1], + 0.0); + } + vertexloop = vertextraverse(m); + } + + /* Write the triangles. */ + traversalinit(&m->triangles); + triangleloop.tri = triangletraverse(m); + triangleloop.orient = 0; + while (triangleloop.tri != (triangle *) NULL) { + org(triangleloop, p1); + dest(triangleloop, p2); + apex(triangleloop, p3); + /* The "3" means a three-vertex polygon. */ + fprintf(outfile, " 3 %4d %4d %4d\n", vertexmark(p1) - 1, + vertexmark(p2) - 1, vertexmark(p3) - 1); + triangleloop.tri = triangletraverse(m); + } + finishfile(outfile, argc, argv); +} + +#endif /* not TRILIBRARY */ + +/** **/ +/** **/ +/********* File I/O routines end here *********/ + +/*****************************************************************************/ +/* */ +/* quality_statistics() Print statistics about the quality of the mesh. */ +/* */ +/*****************************************************************************/ + +#ifdef ANSI_DECLARATORS +void quality_statistics(struct mesh *m, struct behavior *b) +#else /* not ANSI_DECLARATORS */ +void quality_statistics(m, b) +struct mesh *m; +struct behavior *b; +#endif /* not ANSI_DECLARATORS */ + +{ + struct otri triangleloop; + vertex p[3]; + REAL cossquaretable[8]; + REAL ratiotable[16]; + REAL dx[3], dy[3]; + REAL edgelength[3]; + REAL dotproduct; + REAL cossquare; + REAL triarea; + REAL shortest, longest; + REAL trilongest2; + REAL smallestarea, biggestarea; + REAL triminaltitude2; + REAL minaltitude; + REAL triaspect2; + REAL worstaspect; + REAL smallestangle, biggestangle; + REAL radconst, degconst; + int angletable[18]; + int aspecttable[16]; + int aspectindex; + int tendegree; + int acutebiggest; + int i, ii, j, k; + + printf("Mesh quality statistics:\n\n"); + radconst = PI / 18.0; + degconst = 180.0 / PI; + for (i = 0; i < 8; i++) { + cossquaretable[i] = cos(radconst * (REAL) (i + 1)); + cossquaretable[i] = cossquaretable[i] * cossquaretable[i]; + } + for (i = 0; i < 18; i++) { + angletable[i] = 0; + } + + ratiotable[0] = 1.5; ratiotable[1] = 2.0; + ratiotable[2] = 2.5; ratiotable[3] = 3.0; + ratiotable[4] = 4.0; ratiotable[5] = 6.0; + ratiotable[6] = 10.0; ratiotable[7] = 15.0; + ratiotable[8] = 25.0; ratiotable[9] = 50.0; + ratiotable[10] = 100.0; ratiotable[11] = 300.0; + ratiotable[12] = 1000.0; ratiotable[13] = 10000.0; + ratiotable[14] = 100000.0; ratiotable[15] = 0.0; + for (i = 0; i < 16; i++) { + aspecttable[i] = 0; + } + + worstaspect = 0.0; + minaltitude = m->xmax - m->xmin + m->ymax - m->ymin; + minaltitude = minaltitude * minaltitude; + shortest = minaltitude; + longest = 0.0; + smallestarea = minaltitude; + biggestarea = 0.0; + worstaspect = 0.0; + smallestangle = 0.0; + biggestangle = 2.0; + acutebiggest = 1; + + traversalinit(&m->triangles); + triangleloop.tri = triangletraverse(m); + triangleloop.orient = 0; + while (triangleloop.tri != (triangle *) NULL) { + org(triangleloop, p[0]); + dest(triangleloop, p[1]); + apex(triangleloop, p[2]); + trilongest2 = 0.0; + + for (i = 0; i < 3; i++) { + j = plus1mod3[i]; + k = minus1mod3[i]; + dx[i] = p[j][0] - p[k][0]; + dy[i] = p[j][1] - p[k][1]; + edgelength[i] = dx[i] * dx[i] + dy[i] * dy[i]; + if (edgelength[i] > trilongest2) { + trilongest2 = edgelength[i]; + } + if (edgelength[i] > longest) { + longest = edgelength[i]; + } + if (edgelength[i] < shortest) { + shortest = edgelength[i]; + } + } + + triarea = counterclockwise(m, b, p[0], p[1], p[2]); + if (triarea < smallestarea) { + smallestarea = triarea; + } + if (triarea > biggestarea) { + biggestarea = triarea; + } + triminaltitude2 = triarea * triarea / trilongest2; + if (triminaltitude2 < minaltitude) { + minaltitude = triminaltitude2; + } + triaspect2 = trilongest2 / triminaltitude2; + if (triaspect2 > worstaspect) { + worstaspect = triaspect2; + } + aspectindex = 0; + while ((triaspect2 > ratiotable[aspectindex] * ratiotable[aspectindex]) + && (aspectindex < 15)) { + aspectindex++; + } + aspecttable[aspectindex]++; + + for (i = 0; i < 3; i++) { + j = plus1mod3[i]; + k = minus1mod3[i]; + dotproduct = dx[j] * dx[k] + dy[j] * dy[k]; + cossquare = dotproduct * dotproduct / (edgelength[j] * edgelength[k]); + tendegree = 8; + for (ii = 7; ii >= 0; ii--) { + if (cossquare > cossquaretable[ii]) { + tendegree = ii; + } + } + if (dotproduct <= 0.0) { + angletable[tendegree]++; + if (cossquare > smallestangle) { + smallestangle = cossquare; + } + if (acutebiggest && (cossquare < biggestangle)) { + biggestangle = cossquare; + } + } else { + angletable[17 - tendegree]++; + if (acutebiggest || (cossquare > biggestangle)) { + biggestangle = cossquare; + acutebiggest = 0; + } + } + } + triangleloop.tri = triangletraverse(m); + } + + shortest = sqrt(shortest); + longest = sqrt(longest); + minaltitude = sqrt(minaltitude); + worstaspect = sqrt(worstaspect); + smallestarea *= 0.5; + biggestarea *= 0.5; + if (smallestangle >= 1.0) { + smallestangle = 0.0; + } else { + smallestangle = degconst * acos(sqrt(smallestangle)); + } + if (biggestangle >= 1.0) { + biggestangle = 180.0; + } else { + if (acutebiggest) { + biggestangle = degconst * acos(sqrt(biggestangle)); + } else { + biggestangle = 180.0 - degconst * acos(sqrt(biggestangle)); + } + } + + printf(" Smallest area: %16.5g | Largest area: %16.5g\n", + smallestarea, biggestarea); + printf(" Shortest edge: %16.5g | Longest edge: %16.5g\n", + shortest, longest); + printf(" Shortest altitude: %12.5g | Largest aspect ratio: %8.5g\n\n", + minaltitude, worstaspect); + + printf(" Triangle aspect ratio histogram:\n"); + printf(" 1.1547 - %-6.6g : %8d | %6.6g - %-6.6g : %8d\n", + ratiotable[0], aspecttable[0], ratiotable[7], ratiotable[8], + aspecttable[8]); + for (i = 1; i < 7; i++) { + printf(" %6.6g - %-6.6g : %8d | %6.6g - %-6.6g : %8d\n", + ratiotable[i - 1], ratiotable[i], aspecttable[i], + ratiotable[i + 7], ratiotable[i + 8], aspecttable[i + 8]); + } + printf(" %6.6g - %-6.6g : %8d | %6.6g - : %8d\n", + ratiotable[6], ratiotable[7], aspecttable[7], ratiotable[14], + aspecttable[15]); + printf(" (Aspect ratio is longest edge divided by shortest altitude)\n\n"); + + printf(" Smallest angle: %15.5g | Largest angle: %15.5g\n\n", + smallestangle, biggestangle); + + printf(" Angle histogram:\n"); + for (i = 0; i < 9; i++) { + printf(" %3d - %3d degrees: %8d | %3d - %3d degrees: %8d\n", + i * 10, i * 10 + 10, angletable[i], + i * 10 + 90, i * 10 + 100, angletable[i + 9]); + } + printf("\n"); +} + +/*****************************************************************************/ +/* */ +/* statistics() Print all sorts of cool facts. */ +/* */ +/*****************************************************************************/ + +#ifdef ANSI_DECLARATORS +void statistics(struct mesh *m, struct behavior *b) +#else /* not ANSI_DECLARATORS */ +void statistics(m, b) +struct mesh *m; +struct behavior *b; +#endif /* not ANSI_DECLARATORS */ + +{ + printf("\nStatistics:\n\n"); + printf(" Input vertices: %d\n", m->invertices); + if (b->refine) { + printf(" Input triangles: %d\n", m->inelements); + } + if (b->poly) { + printf(" Input segments: %d\n", m->insegments); + if (!b->refine) { + printf(" Input holes: %d\n", m->holes); + } + } + + printf("\n Mesh vertices: %ld\n", m->vertices.items - m->undeads); + printf(" Mesh triangles: %ld\n", m->triangles.items); + printf(" Mesh edges: %ld\n", m->edges); + printf(" Mesh exterior boundary edges: %ld\n", m->hullsize); + if (b->poly || b->refine) { + printf(" Mesh interior boundary edges: %ld\n", + m->subsegs.items - m->hullsize); + printf(" Mesh subsegments (constrained edges): %ld\n", + m->subsegs.items); + } + printf("\n"); + + if (b->verbose) { + quality_statistics(m, b); + printf("Memory allocation statistics:\n\n"); + printf(" Maximum number of vertices: %ld\n", m->vertices.maxitems); + printf(" Maximum number of triangles: %ld\n", m->triangles.maxitems); + if (m->subsegs.maxitems > 0) { + printf(" Maximum number of subsegments: %ld\n", m->subsegs.maxitems); + } + if (m->viri.maxitems > 0) { + printf(" Maximum number of viri: %ld\n", m->viri.maxitems); + } + if (m->badsubsegs.maxitems > 0) { + printf(" Maximum number of encroached subsegments: %ld\n", + m->badsubsegs.maxitems); + } + if (m->badtriangles.maxitems > 0) { + printf(" Maximum number of bad triangles: %ld\n", + m->badtriangles.maxitems); + } + if (m->flipstackers.maxitems > 0) { + printf(" Maximum number of stacked triangle flips: %ld\n", + m->flipstackers.maxitems); + } + if (m->splaynodes.maxitems > 0) { + printf(" Maximum number of splay tree nodes: %ld\n", + m->splaynodes.maxitems); + } + printf(" Approximate heap memory use (bytes): %ld\n\n", + m->vertices.maxitems * m->vertices.itembytes + + m->triangles.maxitems * m->triangles.itembytes + + m->subsegs.maxitems * m->subsegs.itembytes + + m->viri.maxitems * m->viri.itembytes + + m->badsubsegs.maxitems * m->badsubsegs.itembytes + + m->badtriangles.maxitems * m->badtriangles.itembytes + + m->flipstackers.maxitems * m->flipstackers.itembytes + + m->splaynodes.maxitems * m->splaynodes.itembytes); + + printf("Algorithmic statistics:\n\n"); + if (!b->weighted) { + printf(" Number of incircle tests: %ld\n", m->incirclecount); + } else { + printf(" Number of 3D orientation tests: %ld\n", m->orient3dcount); + } + printf(" Number of 2D orientation tests: %ld\n", m->counterclockcount); + if (m->hyperbolacount > 0) { + printf(" Number of right-of-hyperbola tests: %ld\n", + m->hyperbolacount); + } + if (m->circletopcount > 0) { + printf(" Number of circle top computations: %ld\n", + m->circletopcount); + } + if (m->circumcentercount > 0) { + printf(" Number of triangle circumcenter computations: %ld\n", + m->circumcentercount); + } + printf("\n"); + } +} + +/*****************************************************************************/ +/* */ +/* main() or triangulate() Gosh, do everything. */ +/* */ +/* The sequence is roughly as follows. Many of these steps can be skipped, */ +/* depending on the command line switches. */ +/* */ +/* - Initialize constants and parse the command line. */ +/* - Read the vertices from a file and either */ +/* - triangulate them (no -r), or */ +/* - read an old mesh from files and reconstruct it (-r). */ +/* - Insert the PSLG segments (-p), and possibly segments on the convex */ +/* hull (-c). */ +/* - Read the holes (-p), regional attributes (-pA), and regional area */ +/* constraints (-pa). Carve the holes and concavities, and spread the */ +/* regional attributes and area constraints. */ +/* - Enforce the constraints on minimum angle (-q) and maximum area (-a). */ +/* Also enforce the conforming Delaunay property (-q and -a). */ +/* - Compute the number of edges in the resulting mesh. */ +/* - Promote the mesh's linear triangles to higher order elements (-o). */ +/* - Write the output files and print the statistics. */ +/* - Check the consistency and Delaunay property of the mesh (-C). */ +/* */ +/*****************************************************************************/ + +#ifdef TRILIBRARY + +#ifdef ANSI_DECLARATORS +void triangulate(char *triswitches, struct triangulateio *in, + struct triangulateio *out, struct triangulateio *vorout) +#else /* not ANSI_DECLARATORS */ +void triangulate(triswitches, in, out, vorout) +char *triswitches; +struct triangulateio *in; +struct triangulateio *out; +struct triangulateio *vorout; +#endif /* not ANSI_DECLARATORS */ + +#else /* not TRILIBRARY */ + +#ifdef ANSI_DECLARATORS +int main(int argc, char **argv) +#else /* not ANSI_DECLARATORS */ +int main(argc, argv) +int argc; +char **argv; +#endif /* not ANSI_DECLARATORS */ + +#endif /* not TRILIBRARY */ + +{ + struct mesh m; + struct behavior b; + REAL *holearray; /* Array of holes. */ + REAL *regionarray; /* Array of regional attributes and area constraints. */ +#ifndef TRILIBRARY + FILE *polyfile; +#endif /* not TRILIBRARY */ +#ifndef NO_TIMER + /* Variables for timing the performance of Triangle. The types are */ + /* defined in sys/time.h. */ + struct timeval tv0, tv1, tv2, tv3, tv4, tv5, tv6; + struct timezone tz; +#endif /* not NO_TIMER */ + +#ifndef NO_TIMER + gettimeofday(&tv0, &tz); +#endif /* not NO_TIMER */ + + triangleinit(&m); +#ifdef TRILIBRARY + parsecommandline(1, &triswitches, &b); +#else /* not TRILIBRARY */ + parsecommandline(argc, argv, &b); +#endif /* not TRILIBRARY */ + m.steinerleft = b.steiner; + +#ifdef TRILIBRARY + transfernodes(&m, &b, in->pointlist, in->pointattributelist, + in->pointmarkerlist, in->numberofpoints, + in->numberofpointattributes); +#else /* not TRILIBRARY */ + readnodes(&m, &b, b.innodefilename, b.inpolyfilename, &polyfile); +#endif /* not TRILIBRARY */ + +#ifndef NO_TIMER + if (!b.quiet) { + gettimeofday(&tv1, &tz); + } +#endif /* not NO_TIMER */ + +#ifdef CDT_ONLY + m.hullsize = delaunay(&m, &b); /* Triangulate the vertices. */ +#else /* not CDT_ONLY */ + if (b.refine) { + /* Read and reconstruct a mesh. */ +#ifdef TRILIBRARY + m.hullsize = reconstruct(&m, &b, in->trianglelist, + in->triangleattributelist, in->trianglearealist, + in->numberoftriangles, in->numberofcorners, + in->numberoftriangleattributes, + in->segmentlist, in->segmentmarkerlist, + in->numberofsegments); +#else /* not TRILIBRARY */ + m.hullsize = reconstruct(&m, &b, b.inelefilename, b.areafilename, + b.inpolyfilename, polyfile); +#endif /* not TRILIBRARY */ + } else { + m.hullsize = delaunay(&m, &b); /* Triangulate the vertices. */ + } +#endif /* not CDT_ONLY */ + +#ifndef NO_TIMER + if (!b.quiet) { + gettimeofday(&tv2, &tz); + if (b.refine) { + printf("Mesh reconstruction"); + } else { + printf("Delaunay"); + } + printf(" milliseconds: %ld\n", 1000l * (tv2.tv_sec - tv1.tv_sec) + + (tv2.tv_usec - tv1.tv_usec) / 1000l); + } +#endif /* not NO_TIMER */ + + /* Ensure that no vertex can be mistaken for a triangular bounding */ + /* box vertex in insertvertex(). */ + m.infvertex1 = (vertex) NULL; + m.infvertex2 = (vertex) NULL; + m.infvertex3 = (vertex) NULL; + + if (b.usesegments) { + m.checksegments = 1; /* Segments will be introduced next. */ + if (!b.refine) { + /* Insert PSLG segments and/or convex hull segments. */ +#ifdef TRILIBRARY + formskeleton(&m, &b, in->segmentlist, + in->segmentmarkerlist, in->numberofsegments); +#else /* not TRILIBRARY */ + formskeleton(&m, &b, polyfile, b.inpolyfilename); +#endif /* not TRILIBRARY */ + } + } + +#ifndef NO_TIMER + if (!b.quiet) { + gettimeofday(&tv3, &tz); + if (b.usesegments && !b.refine) { + printf("Segment milliseconds: %ld\n", + 1000l * (tv3.tv_sec - tv2.tv_sec) + + (tv3.tv_usec - tv2.tv_usec) / 1000l); + } + } +#endif /* not NO_TIMER */ + + if (b.poly && (m.triangles.items > 0)) { +#ifdef TRILIBRARY + holearray = in->holelist; + m.holes = in->numberofholes; + regionarray = in->regionlist; + m.regions = in->numberofregions; +#else /* not TRILIBRARY */ + readholes(&m, &b, polyfile, b.inpolyfilename, &holearray, &m.holes, + ®ionarray, &m.regions); +#endif /* not TRILIBRARY */ + if (!b.refine) { + /* Carve out holes and concavities. */ + carveholes(&m, &b, holearray, m.holes, regionarray, m.regions); + } + } else { + /* Without a PSLG, there can be no holes or regional attributes */ + /* or area constraints. The following are set to zero to avoid */ + /* an accidental free() later. */ + m.holes = 0; + m.regions = 0; + } + +#ifndef NO_TIMER + if (!b.quiet) { + gettimeofday(&tv4, &tz); + if (b.poly && !b.refine) { + printf("Hole milliseconds: %ld\n", 1000l * (tv4.tv_sec - tv3.tv_sec) + + (tv4.tv_usec - tv3.tv_usec) / 1000l); + } + } +#endif /* not NO_TIMER */ + +#ifndef CDT_ONLY + if (b.quality && (m.triangles.items > 0)) { + enforcequality(&m, &b); /* Enforce angle and area constraints. */ + } +#endif /* not CDT_ONLY */ + +#ifndef NO_TIMER + if (!b.quiet) { + gettimeofday(&tv5, &tz); +#ifndef CDT_ONLY + if (b.quality) { + printf("Quality milliseconds: %ld\n", + 1000l * (tv5.tv_sec - tv4.tv_sec) + + (tv5.tv_usec - tv4.tv_usec) / 1000l); + } +#endif /* not CDT_ONLY */ + } +#endif /* not NO_TIMER */ + + /* Calculate the number of edges. */ + m.edges = (3l * m.triangles.items + m.hullsize) / 2l; + + if (b.order > 1) { + highorder(&m, &b); /* Promote elements to higher polynomial order. */ + } + if (!b.quiet) { + printf("\n"); + } + +#ifdef TRILIBRARY + out->numberofpoints = m.vertices.items; + out->numberofpointattributes = m.nextras; + out->numberoftriangles = m.triangles.items; + out->numberofcorners = (b.order + 1) * (b.order + 2) / 2; + out->numberoftriangleattributes = m.eextras; + out->numberofedges = m.edges; + if (b.usesegments) { + out->numberofsegments = m.subsegs.items; + } else { + out->numberofsegments = m.hullsize; + } + if (vorout != (struct triangulateio *) NULL) { + vorout->numberofpoints = m.triangles.items; + vorout->numberofpointattributes = m.nextras; + vorout->numberofedges = m.edges; + } +#endif /* TRILIBRARY */ + /* If not using iteration numbers, don't write a .node file if one was */ + /* read, because the original one would be overwritten! */ + if (b.nonodewritten || (b.noiterationnum && m.readnodefile)) { + if (!b.quiet) { +#ifdef TRILIBRARY + printf("NOT writing vertices.\n"); +#else /* not TRILIBRARY */ + printf("NOT writing a .node file.\n"); +#endif /* not TRILIBRARY */ + } + numbernodes(&m, &b); /* We must remember to number the vertices. */ + } else { + /* writenodes() numbers the vertices too. */ +#ifdef TRILIBRARY + writenodes(&m, &b, &out->pointlist, &out->pointattributelist, + &out->pointmarkerlist); +#else /* not TRILIBRARY */ + writenodes(&m, &b, b.outnodefilename, argc, argv); +#endif /* TRILIBRARY */ + } + if (b.noelewritten) { + if (!b.quiet) { +#ifdef TRILIBRARY + printf("NOT writing triangles.\n"); +#else /* not TRILIBRARY */ + printf("NOT writing an .ele file.\n"); +#endif /* not TRILIBRARY */ + } + } else { +#ifdef TRILIBRARY + writeelements(&m, &b, &out->trianglelist, &out->triangleattributelist); +#else /* not TRILIBRARY */ + writeelements(&m, &b, b.outelefilename, argc, argv); +#endif /* not TRILIBRARY */ + } + /* The -c switch (convex switch) causes a PSLG to be written */ + /* even if none was read. */ + if (b.poly || b.convex) { + /* If not using iteration numbers, don't overwrite the .poly file. */ + if (b.nopolywritten || b.noiterationnum) { + if (!b.quiet) { +#ifdef TRILIBRARY + printf("NOT writing segments.\n"); +#else /* not TRILIBRARY */ + printf("NOT writing a .poly file.\n"); +#endif /* not TRILIBRARY */ + } + } else { +#ifdef TRILIBRARY + writepoly(&m, &b, &out->segmentlist, &out->segmentmarkerlist); + out->numberofholes = m.holes; + out->numberofregions = m.regions; + if (b.poly) { + out->holelist = in->holelist; + out->regionlist = in->regionlist; + } else { + out->holelist = (REAL *) NULL; + out->regionlist = (REAL *) NULL; + } +#else /* not TRILIBRARY */ + writepoly(&m, &b, b.outpolyfilename, holearray, m.holes, regionarray, + m.regions, argc, argv); +#endif /* not TRILIBRARY */ + } + } +#ifndef TRILIBRARY +#ifndef CDT_ONLY + if (m.regions > 0) { + trifree((VOID *) regionarray); + } +#endif /* not CDT_ONLY */ + if (m.holes > 0) { + trifree((VOID *) holearray); + } + if (b.geomview) { + writeoff(&m, &b, b.offfilename, argc, argv); + } +#endif /* not TRILIBRARY */ + if (b.edgesout) { +#ifdef TRILIBRARY + writeedges(&m, &b, &out->edgelist, &out->edgemarkerlist); +#else /* not TRILIBRARY */ + writeedges(&m, &b, b.edgefilename, argc, argv); +#endif /* not TRILIBRARY */ + } + if (b.voronoi) { +#ifdef TRILIBRARY + writevoronoi(&m, &b, &vorout->pointlist, &vorout->pointattributelist, + &vorout->pointmarkerlist, &vorout->edgelist, + &vorout->edgemarkerlist, &vorout->normlist); +#else /* not TRILIBRARY */ + writevoronoi(&m, &b, b.vnodefilename, b.vedgefilename, argc, argv); +#endif /* not TRILIBRARY */ + } + if (b.neighbors) { +#ifdef TRILIBRARY + writeneighbors(&m, &b, &out->neighborlist); +#else /* not TRILIBRARY */ + writeneighbors(&m, &b, b.neighborfilename, argc, argv); +#endif /* not TRILIBRARY */ + } + + if (!b.quiet) { +#ifndef NO_TIMER + gettimeofday(&tv6, &tz); + printf("\nOutput milliseconds: %ld\n", + 1000l * (tv6.tv_sec - tv5.tv_sec) + + (tv6.tv_usec - tv5.tv_usec) / 1000l); + printf("Total running milliseconds: %ld\n", + 1000l * (tv6.tv_sec - tv0.tv_sec) + + (tv6.tv_usec - tv0.tv_usec) / 1000l); +#endif /* not NO_TIMER */ + + statistics(&m, &b); + } + +#ifndef REDUCED + if (b.docheck) { + checkmesh(&m, &b); + checkdelaunay(&m, &b); + } +#endif /* not REDUCED */ + + triangledeinit(&m, &b); +#ifndef TRILIBRARY + return 0; +#endif /* not TRILIBRARY */ +} diff --git a/contrib/Triangle/triangle.h b/contrib/Triangle/triangle.h new file mode 100644 index 0000000000..5b2c5995af --- /dev/null +++ b/contrib/Triangle/triangle.h @@ -0,0 +1,282 @@ +/*****************************************************************************/ +/* */ +/* (triangle.h) */ +/* */ +/* Include file for programs that call Triangle. */ +/* */ +/* Accompanies Triangle Versions 1.3 and 1.4 */ +/* July 19, 1996 */ +/* */ +/* Copyright 1996 */ +/* Jonathan Richard Shewchuk */ +/* 2360 Woolsey #H */ +/* Berkeley, California 94705-1927 */ +/* jrs@cs.berkeley.edu */ +/* */ +/*****************************************************************************/ + +/*****************************************************************************/ +/* */ +/* How to call Triangle from another program */ +/* */ +/* */ +/* If you haven't read Triangle's instructions (run "triangle -h" to read */ +/* them), you won't understand what follows. */ +/* */ +/* Triangle must be compiled into an object file (triangle.o) with the */ +/* TRILIBRARY symbol defined (preferably by using the -DTRILIBRARY compiler */ +/* switch). The makefile included with Triangle will do this for you if */ +/* you run "make trilibrary". The resulting object file can be called via */ +/* the procedure triangulate(). */ +/* */ +/* If the size of the object file is important to you, you may wish to */ +/* generate a reduced version of triangle.o. The REDUCED symbol gets rid */ +/* of all features that are primarily of research interest. Specifically, */ +/* the -DREDUCED switch eliminates Triangle's -i, -F, -s, and -C switches. */ +/* The CDT_ONLY symbol gets rid of all meshing algorithms above and beyond */ +/* constrained Delaunay triangulation. Specifically, the -DCDT_ONLY switch */ +/* eliminates Triangle's -r, -q, -a, -S, and -s switches. */ +/* */ +/* IMPORTANT: These definitions (TRILIBRARY, REDUCED, CDT_ONLY) must be */ +/* made in the makefile or in triangle.c itself. Putting these definitions */ +/* in this file will not create the desired effect. */ +/* */ +/* */ +/* The calling convention for triangulate() follows. */ +/* */ +/* void triangulate(triswitches, in, out, vorout) */ +/* char *triswitches; */ +/* struct triangulateio *in; */ +/* struct triangulateio *out; */ +/* struct triangulateio *vorout; */ +/* */ +/* `triswitches' is a string containing the command line switches you wish */ +/* to invoke. No initial dash is required. Some suggestions: */ +/* */ +/* - You'll probably find it convenient to use the `z' switch so that */ +/* points (and other items) are numbered from zero. This simplifies */ +/* indexing, because the first item of any type always starts at index */ +/* [0] of the corresponding array, whether that item's number is zero or */ +/* one. */ +/* - You'll probably want to use the `Q' (quiet) switch in your final code, */ +/* but you can take advantage of Triangle's printed output (including the */ +/* `V' switch) while debugging. */ +/* - If you are not using the `q' or `a' switches, then the output points */ +/* will be identical to the input points, except possibly for the */ +/* boundary markers. If you don't need the boundary markers, you should */ +/* use the `N' (no nodes output) switch to save memory. (If you do need */ +/* boundary markers, but need to save memory, a good nasty trick is to */ +/* set out->pointlist equal to in->pointlist before calling triangulate(),*/ +/* so that Triangle overwrites the input points with identical copies.) */ +/* - The `I' (no iteration numbers) and `g' (.off file output) switches */ +/* have no effect when Triangle is compiled with TRILIBRARY defined. */ +/* */ +/* `in', `out', and `vorout' are descriptions of the input, the output, */ +/* and the Voronoi output. If the `v' (Voronoi output) switch is not used, */ +/* `vorout' may be NULL. `in' and `out' may never be NULL. */ +/* */ +/* Certain fields of the input and output structures must be initialized, */ +/* as described below. */ +/* */ +/*****************************************************************************/ + +/*****************************************************************************/ +/* */ +/* The `triangulateio' structure. */ +/* */ +/* Used to pass data into and out of the triangulate() procedure. */ +/* */ +/* */ +/* Arrays are used to store points, triangles, markers, and so forth. In */ +/* all cases, the first item in any array is stored starting at index [0]. */ +/* However, that item is item number `1' unless the `z' switch is used, in */ +/* which case it is item number `0'. Hence, you may find it easier to */ +/* index points (and triangles in the neighbor list) if you use the `z' */ +/* switch. Unless, of course, you're calling Triangle from a Fortran */ +/* program. */ +/* */ +/* Description of fields (except the `numberof' fields, which are obvious): */ +/* */ +/* `pointlist': An array of point coordinates. The first point's x */ +/* coordinate is at index [0] and its y coordinate at index [1], followed */ +/* by the coordinates of the remaining points. Each point occupies two */ +/* REALs. */ +/* `pointattributelist': An array of point attributes. Each point's */ +/* attributes occupy `numberofpointattributes' REALs. */ +/* `pointmarkerlist': An array of point markers; one int per point. */ +/* */ +/* `trianglelist': An array of triangle corners. The first triangle's */ +/* first corner is at index [0], followed by its other two corners in */ +/* counterclockwise order, followed by any other nodes if the triangle */ +/* represents a nonlinear element. Each triangle occupies */ +/* `numberofcorners' ints. */ +/* `triangleattributelist': An array of triangle attributes. Each */ +/* triangle's attributes occupy `numberoftriangleattributes' REALs. */ +/* `trianglearealist': An array of triangle area constraints; one REAL per */ +/* triangle. Input only. */ +/* `neighborlist': An array of triangle neighbors; three ints per */ +/* triangle. Output only. */ +/* */ +/* `segmentlist': An array of segment endpoints. The first segment's */ +/* endpoints are at indices [0] and [1], followed by the remaining */ +/* segments. Two ints per segment. */ +/* `segmentmarkerlist': An array of segment markers; one int per segment. */ +/* */ +/* `holelist': An array of holes. The first hole's x and y coordinates */ +/* are at indices [0] and [1], followed by the remaining holes. Two */ +/* REALs per hole. Input only, although the pointer is copied to the */ +/* output structure for your convenience. */ +/* */ +/* `regionlist': An array of regional attributes and area constraints. */ +/* The first constraint's x and y coordinates are at indices [0] and [1], */ +/* followed by the regional attribute and index [2], followed by the */ +/* maximum area at index [3], followed by the remaining area constraints. */ +/* Four REALs per area constraint. Note that each regional attribute is */ +/* used only if you select the `A' switch, and each area constraint is */ +/* used only if you select the `a' switch (with no number following), but */ +/* omitting one of these switches does not change the memory layout. */ +/* Input only, although the pointer is copied to the output structure for */ +/* your convenience. */ +/* */ +/* `edgelist': An array of edge endpoints. The first edge's endpoints are */ +/* at indices [0] and [1], followed by the remaining edges. Two ints per */ +/* edge. Output only. */ +/* `edgemarkerlist': An array of edge markers; one int per edge. Output */ +/* only. */ +/* `normlist': An array of normal vectors, used for infinite rays in */ +/* Voronoi diagrams. The first normal vector's x and y magnitudes are */ +/* at indices [0] and [1], followed by the remaining vectors. For each */ +/* finite edge in a Voronoi diagram, the normal vector written is the */ +/* zero vector. Two REALs per edge. Output only. */ +/* */ +/* */ +/* Any input fields that Triangle will examine must be initialized. */ +/* Furthermore, for each output array that Triangle will write to, you */ +/* must either provide space by setting the appropriate pointer to point */ +/* to the space you want the data written to, or you must initialize the */ +/* pointer to NULL, which tells Triangle to allocate space for the results. */ +/* The latter option is preferable, because Triangle always knows exactly */ +/* how much space to allocate. The former option is provided mainly for */ +/* people who need to call Triangle from Fortran code, though it also makes */ +/* possible some nasty space-saving tricks, like writing the output to the */ +/* same arrays as the input. */ +/* */ +/* Triangle will not free() any input or output arrays, including those it */ +/* allocates itself; that's up to you. */ +/* */ +/* Here's a guide to help you decide which fields you must initialize */ +/* before you call triangulate(). */ +/* */ +/* `in': */ +/* */ +/* - `pointlist' must always point to a list of points; `numberofpoints' */ +/* and `numberofpointattributes' must be properly set. */ +/* `pointmarkerlist' must either be set to NULL (in which case all */ +/* markers default to zero), or must point to a list of markers. If */ +/* `numberofpointattributes' is not zero, `pointattributelist' must */ +/* point to a list of point attributes. */ +/* - If the `r' switch is used, `trianglelist' must point to a list of */ +/* triangles, and `numberoftriangles', `numberofcorners', and */ +/* `numberoftriangleattributes' must be properly set. If */ +/* `numberoftriangleattributes' is not zero, `triangleattributelist' */ +/* must point to a list of triangle attributes. If the `a' switch is */ +/* used (with no number following), `trianglearealist' must point to a */ +/* list of triangle area constraints. `neighborlist' may be ignored. */ +/* - If the `p' switch is used, `segmentlist' must point to a list of */ +/* segments, `numberofsegments' must be properly set, and */ +/* `segmentmarkerlist' must either be set to NULL (in which case all */ +/* markers default to zero), or must point to a list of markers. */ +/* - If the `p' switch is used without the `r' switch, then */ +/* `numberofholes' and `numberofregions' must be properly set. If */ +/* `numberofholes' is not zero, `holelist' must point to a list of */ +/* holes. If `numberofregions' is not zero, `regionlist' must point to */ +/* a list of region constraints. */ +/* - If the `p' switch is used, `holelist', `numberofholes', */ +/* `regionlist', and `numberofregions' is copied to `out'. (You can */ +/* nonetheless get away with not initializing them if the `r' switch is */ +/* used.) */ +/* - `edgelist', `edgemarkerlist', `normlist', and `numberofedges' may be */ +/* ignored. */ +/* */ +/* `out': */ +/* */ +/* - `pointlist' must be initialized (NULL or pointing to memory) unless */ +/* the `N' switch is used. `pointmarkerlist' must be initialized */ +/* unless the `N' or `B' switch is used. If `N' is not used and */ +/* `in->numberofpointattributes' is not zero, `pointattributelist' must */ +/* be initialized. */ +/* - `trianglelist' must be initialized unless the `E' switch is used. */ +/* `neighborlist' must be initialized if the `n' switch is used. If */ +/* the `E' switch is not used and (`in->numberofelementattributes' is */ +/* not zero or the `A' switch is used), `elementattributelist' must be */ +/* initialized. `trianglearealist' may be ignored. */ +/* - `segmentlist' must be initialized if the `p' or `c' switch is used, */ +/* and the `P' switch is not used. `segmentmarkerlist' must also be */ +/* initialized under these circumstances unless the `B' switch is used. */ +/* - `edgelist' must be initialized if the `e' switch is used. */ +/* `edgemarkerlist' must be initialized if the `e' switch is used and */ +/* the `B' switch is not. */ +/* - `holelist', `regionlist', `normlist', and all scalars may be ignored.*/ +/* */ +/* `vorout' (only needed if `v' switch is used): */ +/* */ +/* - `pointlist' must be initialized. If `in->numberofpointattributes' */ +/* is not zero, `pointattributelist' must be initialized. */ +/* `pointmarkerlist' may be ignored. */ +/* - `edgelist' and `normlist' must both be initialized. */ +/* `edgemarkerlist' may be ignored. */ +/* - Everything else may be ignored. */ +/* */ +/* After a call to triangulate(), the valid fields of `out' and `vorout' */ +/* will depend, in an obvious way, on the choice of switches used. Note */ +/* that when the `p' switch is used, the pointers `holelist' and */ +/* `regionlist' are copied from `in' to `out', but no new space is */ +/* allocated; be careful that you don't free() the same array twice. On */ +/* the other hand, Triangle will never copy the `pointlist' pointer (or any */ +/* others); new space is allocated for `out->pointlist', or if the `N' */ +/* switch is used, `out->pointlist' remains uninitialized. */ +/* */ +/* All of the meaningful `numberof' fields will be properly set; for */ +/* instance, `numberofedges' will represent the number of edges in the */ +/* triangulation whether or not the edges were written. If segments are */ +/* not used, `numberofsegments' will indicate the number of boundary edges. */ +/* */ +/*****************************************************************************/ + +struct triangulateio { + REAL *pointlist; /* In / out */ + REAL *pointattributelist; /* In / out */ + int *pointmarkerlist; /* In / out */ + int numberofpoints; /* In / out */ + int numberofpointattributes; /* In / out */ + + int *trianglelist; /* In / out */ + REAL *triangleattributelist; /* In / out */ + REAL *trianglearealist; /* In only */ + int *neighborlist; /* Out only */ + int numberoftriangles; /* In / out */ + int numberofcorners; /* In / out */ + int numberoftriangleattributes; /* In / out */ + + int *segmentlist; /* In / out */ + int *segmentmarkerlist; /* In / out */ + int numberofsegments; /* In / out */ + + REAL *holelist; /* In / pointer to array copied out */ + int numberofholes; /* In / copied out */ + + REAL *regionlist; /* In / pointer to array copied out */ + int numberofregions; /* In / copied out */ + + int *edgelist; /* Out only */ + int *edgemarkerlist; /* Not used with Voronoi diagram; out only */ + REAL *normlist; /* Used only with Voronoi diagram; out only */ + int numberofedges; /* Out only */ +}; + +#ifdef ANSI_DECLARATORS +void triangulate(char *, struct triangulateio *, struct triangulateio *, + struct triangulateio *); +#else /* not ANSI_DECLARATORS */ +void triangulate(); +#endif /* not ANSI_DECLARATORS */ -- GitLab