Import mshr_2019.2.0~git20200924.c27eb18+dfsg1.orig.tar.bz2
authorDrew Parsons <dparsons@debian.org>
Sun, 4 Oct 2020 16:15:24 +0000 (00:15 +0800)
committerDrew Parsons <dparsons@debian.org>
Sun, 4 Oct 2020 16:15:24 +0000 (00:15 +0800)
[dgit import orig mshr_2019.2.0~git20200924.c27eb18+dfsg1.orig.tar.bz2]

100 files changed:
.gitignore [new file with mode: 0644]
3rdparty/CMakeLists.txt [new file with mode: 0644]
3rdparty/cgal-version.txt [new file with mode: 0644]
3rdparty/cgal.patch [new file with mode: 0644]
CMakeLists.txt [new file with mode: 0644]
COPYING [new file with mode: 0644]
ChangeLog.rst [new file with mode: 0644]
README.rst [new file with mode: 0644]
app/mshrable.cpp [new file with mode: 0644]
cmake/FindTetGen.cmake [new file with mode: 0644]
demo/python/classic.py [new file with mode: 0644]
demo/python/csg-subdomains-2D.py [new file with mode: 0644]
demo/python/deathstar.py [new file with mode: 0644]
demo/python/extrude.py [new file with mode: 0644]
demo/python/icecream.py [new file with mode: 0644]
demo/python/materials.py [new file with mode: 0644]
demo/python/propeller.py [new file with mode: 0644]
demo/python/remove_degenerate.py [new file with mode: 0644]
demo/python/simple-csg-3D.py [new file with mode: 0644]
doc/Doxyfile [new file with mode: 0644]
doc/generate_rst.py [new file with mode: 0644]
doc/sphinx/Makefile [new file with mode: 0644]
doc/sphinx/README [new file with mode: 0644]
doc/sphinx/source/ChangeLog.rst [new symlink]
doc/sphinx/source/conf.py [new file with mode: 0644]
doc/sphinx/source/index.rst [new file with mode: 0644]
fenics-dev-install.sh [new file with mode: 0755]
include/mshr.h [new file with mode: 0644]
include/mshr/ASCFileReader.h [new file with mode: 0755]
include/mshr/CSGCGALDomain2D.h [new file with mode: 0644]
include/mshr/CSGCGALDomain3D.h [new file with mode: 0644]
include/mshr/CSGCGALMeshGenerator2D.h [new file with mode: 0644]
include/mshr/CSGCGALMeshGenerator3D.h [new file with mode: 0644]
include/mshr/CSGGeometries3D.h [new file with mode: 0644]
include/mshr/CSGGeometry.h [new file with mode: 0644]
include/mshr/CSGOperators.h [new file with mode: 0644]
include/mshr/CSGPrimitive.h [new file with mode: 0644]
include/mshr/CSGPrimitives2D.h [new file with mode: 0644]
include/mshr/CSGPrimitives3D.h [new file with mode: 0644]
include/mshr/DolfinMeshUtils.h [new file with mode: 0644]
include/mshr/GlobalInitializer.h [new file with mode: 0644]
include/mshr/MeshGenerator.h [new file with mode: 0644]
include/mshr/Meshes.h [new file with mode: 0644]
include/mshr/OFFFileReader.h [new file with mode: 0644]
include/mshr/STLFileReader.h [new file with mode: 0644]
include/mshr/SurfaceConsistency.h [new file with mode: 0644]
include/mshr/SurfaceReconstruction.h [new file with mode: 0644]
include/mshr/TetgenMeshGenerator3D.h [new file with mode: 0644]
mshr-config.cmake.in [new file with mode: 0644]
mshrConfig.cmake.in [new file with mode: 0644]
python/CMakeLists.txt [new file with mode: 0644]
python/cmake/Findmshr.cmake [new file with mode: 0644]
python/config.json.in [new file with mode: 0644]
python/mshr/__init__.py [new file with mode: 0644]
python/setup.py [new file with mode: 0644]
python/src/mshr.cpp [new file with mode: 0644]
release.conf [new file with mode: 0644]
src/ASCFileReader.cpp [new file with mode: 0755]
src/CSGCGALDomain2D.cpp [new file with mode: 0644]
src/CSGCGALDomain3D.cpp [new file with mode: 0644]
src/CSGCGALMeshGenerator2D.cpp [new file with mode: 0644]
src/CSGCGALMeshGenerator3D.cpp [new file with mode: 0644]
src/CSGGeometries3D.cpp [new file with mode: 0644]
src/CSGGeometry.cpp [new file with mode: 0644]
src/CSGOperators.cpp [new file with mode: 0644]
src/CSGPrimitives2D.cpp [new file with mode: 0644]
src/CSGPrimitives3D.cpp [new file with mode: 0644]
src/DolfinMeshUtils.cpp [new file with mode: 0644]
src/FuzzyPointLocator.h [new file with mode: 0644]
src/GlobalInitializer.cpp [new file with mode: 0644]
src/MeshGenerator.cpp [new file with mode: 0644]
src/Meshes.cpp [new file with mode: 0644]
src/OFFFileReader.cpp [new file with mode: 0644]
src/Polygon_utils.h [new file with mode: 0644]
src/Polyhedral_multicomponent_mesh_domain_with_features_3.h [new file with mode: 0644]
src/Polyhedron_utils.h [new file with mode: 0644]
src/STLFileReader.cpp [new file with mode: 0644]
src/SurfaceConsistency.cpp [new file with mode: 0644]
src/SurfaceReconstruction.cpp [new file with mode: 0644]
src/TetgenMeshGenerator3D.cpp [new file with mode: 0644]
src/make_multicomponent_mesh_3.h [new file with mode: 0644]
src/meshclean.h [new file with mode: 0644]
src/smoothing.h [new file with mode: 0644]
src/triangulation_refinement.h [new file with mode: 0644]
test/CMakeLists.txt [new file with mode: 0644]
test/degenerate_removal.py [new file with mode: 0644]
test/dummy.py [new file with mode: 0644]
test/test-ASCFileReader.py [new file with mode: 0644]
test/test-csg-predicates.py [new file with mode: 0644]
test/test-csg-primitives-2d.py [new file with mode: 0644]
test/test-csg.py [new file with mode: 0644]
test/test-csggeometries.cpp [new file with mode: 0644]
test/test-fuzzypointmap.py [new file with mode: 0644]
test/test-mesh-generation.py [new file with mode: 0644]
test/test-meshes.py [new file with mode: 0644]
test/test-num-segments-2d.py [new file with mode: 0644]
test/test.cpp [new file with mode: 0644]
test/test2.cpp [new file with mode: 0644]
test/test3D.cpp [new file with mode: 0644]
use-mshr.cmake [new file with mode: 0644]

diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..1720df4
--- /dev/null
@@ -0,0 +1,4 @@
+build/
+build.*/
+release/
+__pycache__
diff --git a/3rdparty/CMakeLists.txt b/3rdparty/CMakeLists.txt
new file mode 100644 (file)
index 0000000..97d1547
--- /dev/null
@@ -0,0 +1,78 @@
+if (NOT USE_SYSTEM_CGAL)
+  # Enable ExternalProject CMake module
+  include(ExternalProject)
+  
+  # Set default ExternalProject root directory
+  set_directory_properties(PROPERTIES EP_PREFIX ${CMAKE_BINARY_DIR}/3rdparty)
+
+  message(STATUS "Building CGAL")
+  
+  message(STATUS "Current source dir: ${CMAKE_CURRENT_SOURCE_DIR}")
+  message(STATUS "Binary dir: ${CMAKE_BINARY_DIR}")
+  
+  set(CGAL_INSTALL_DIR ${CMAKE_BINARY_DIR}/CGAL-installdir)
+  
+  if ( CMAKE_BUILD_TYPE )
+    set(CGAL_BUILD_TYPE ${CMAKE_BUILD_TYPE})
+  else()
+    set(CGAL_BUILD_TYPE Debug)
+  endif()
+  
+  # CGAL doesn't allow Developer, RelWithDebInfo and MinSizeRel as build type.
+  if ( "${CMAKE_BUILD_TYPE}" STREQUAL "Developer" )
+    set(CGAL_BUILD_TYPE "Debug")
+  endif()
+  if ( "${CMAKE_BUILD_TYPE}" STREQUAL "MinSizeRel"
+      OR "${CMAKE_BUILD_TYPE}" STREQUAL "RelWithDebInfo" )
+    set(CGAL_BUILD_TYPE "Release")
+  endif()
+  
+  message(STATUS "CGAL build type: ${CGAL_BUILD_TYPE}")
+  
+  # Note: Need to add fPIC in order to be able to link staticly with CGAL
+  # FIXME: The CMAKE_CXX_FLAGS=-std=c++11 is a hack to remove CGAL's dependency on boost.thread (see setup_Boost.cmake)
+  # This should be removed when CGAL's boost dependency is eventually removed.
+  ExternalProject_Add(CGAL
+    SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/CGAL
+    INSTALL_DIR ${CGAL_INSTALL_DIR}
+    CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH=${CGAL_INSTALL_DIR} -DCMAKE_BUILD_TYPE=${CGAL_BUILD_TYPE} -DCMAKE_C_COMPILER=${CMAKE_C_COMPILER} -DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER} -DCMAKE_CXX_FLAGS=-std=c++11 -DCGAL_CXX_FLAGS=-fPIC -DWITH_CGAL_Core:BOOL=OFF -DWITH_CGAL_ImageIO:BOOL=OFF -DWITH_CGAL_Qt5:BOOL=OFF -DWITH_demos:BOOL=OFF -DWITH_examples:BOOL=OFF -DWITH_LEDA:BOOL=OFF -DWITH_GMP:BOOL=ON -DWITH_MPFR:BOOL=ON -DWITH_Eigen3:BOOL=ON -DBUILD_SHARED_LIBS:BOOL=OFF -DBOOST_ROOT=${BOOST_ROOT} -DGMP_INCLUDE_DIR=${GMP_INCLUDE_DIR} -DGMP_LIBRARIES=${GMP_LIBRARIES} -DMPFR_INCLUDE_DIR=${MPFR_INCLUDE_DIR} -DMPFR_LIBRARIES=${MPFR_LIBRARIES} -DEIGEN3_INCLUDE_DIR=${EIGEN3_INCLUDE_DIR} -DCGAL_HEADER_ONLY:BOOL=${CGAL_HEADER_ONLY}
+    
+    # -DWITH_ESBTL:BOOL=OFF        \
+    # -DWITH_GMPXX:BOOL=OFF        \
+    # -DWITH_IPE:BOOL=OFF          \
+    # -DWITH_LAPACK:BOOL=OFF       \
+    # -DWITH_LEDA:BOOL=OFF         \
+    # -DWITH_MPFI:BOOL=OFF         \
+    # -DWITH_NTL:BOOL=OFF          \
+    # -DWITH_OpenGL:BOOL=OFF       \
+    # -DWITH_OpenNL:BOOL=OFF       \
+    # -DWITH_QGLViewer:BOOL=OFF    \
+    # -DWITH_RS:BOOL=OFF           \
+    # -DWITH_RS3:BOOL=OFF          \
+    # -DWITH_TAUCS:BOOL=OFF        \
+    # -DWITH_ZLIB:BOOL=OFF         \
+    
+    UPDATE_COMMAND ""
+    )
+  
+  set(CGAL_INCLUDE_DIR ${CGAL_INSTALL_DIR}/include PARENT_SCOPE)
+  set(CGAL_LIB_DIR ${CGAL_INSTALL_DIR}/lib PARENT_SCOPE)
+  
+  # LINK_DIRECTORIES( ${CGAL_INSTALL_DIR}/lib )
+  
+  # ADD_LIBRARY(CGAL STATIC IMPORTED)
+  # SET_TARGET_PROPERTIES(TARGET cgal PROPERTY
+  #     IMPORTED_LOCATION ${CGAL_INSTALL_DIR}/lib/libCGAL.a)
+  
+  # ADD_LIBRARY(CGAL_Core STATIC IMPORTED)
+  # SET_TARGET_PROPERTIES(TARGET cgal PROPERTY
+  #     IMPORTED_LOCATION ${CGAL_INSTALL_DIR}/lib/libCGAL_Core.a)
+endif()
+
+if (NOT USE_SYSTEM_TETGEN)
+  add_subdirectory( tetgen1.5.0 )
+endif()
+
+set(EXTERNAL_INCLUDE_DIRS "${CGAL_INSTALL_DIR}/include;${TETGEN_INCLUDE_DIR}" PARENT_SCOPE)
+set(EXTERNAL_LIBS "tet" PARENT_SCOPE)
+set(EXTERNAL_DEFINITIONS "${TETGEN_DEFINITIONS}" PARENT_SCOPE)
diff --git a/3rdparty/cgal-version.txt b/3rdparty/cgal-version.txt
new file mode 100644 (file)
index 0000000..f588584
--- /dev/null
@@ -0,0 +1 @@
+4.12
diff --git a/3rdparty/cgal.patch b/3rdparty/cgal.patch
new file mode 100644 (file)
index 0000000..c004510
--- /dev/null
@@ -0,0 +1,15 @@
+diff --git a/3rdparty/CGAL/CMakeLists.txt b/3rdparty/CGAL/CMakeLists.txt
+index d5173fd..0ae9026 100644
+--- a/3rdparty/CGAL/CMakeLists.txt
++++ b/3rdparty/CGAL/CMakeLists.txt
+@@ -890,7 +890,9 @@ foreach (dir ${CGAL_CONFIGURED_PACKAGES})
+     install(DIRECTORY ${dir}/include/CGAL              DESTINATION ${CGAL_INSTALL_INC_DIR} PATTERN ".svn" EXCLUDE)
+   endif()
+ endforeach()
+-install(DIRECTORY ${CMAKE_BINARY_DIR}/include/CGAL     DESTINATION ${CGAL_INSTALL_INC_DIR} PATTERN ".svn" EXCLUDE)
++if(EXISTS ${CMAKE_BINARY_DIR}/include/CGAL)
++  install(DIRECTORY ${CMAKE_BINARY_DIR}/include/CGAL     DESTINATION ${CGAL_INSTALL_INC_DIR} PATTERN ".svn" EXCLUDE)
++endif()
+ file(GLOB scripts "scripts/*")
+ list(SORT scripts)
diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644 (file)
index 0000000..78fee4a
--- /dev/null
@@ -0,0 +1,233 @@
+# Require CMake 3.5
+cmake_minimum_required(VERSION 3.5)
+
+project( MSHR )
+set(MSHR_VERSION_RELEASE 0)
+set(MSHR_VERSION_MAJOR "2019")
+set(MSHR_VERSION_MINOR "2")
+set(MSHR_VERSION_MICRO "0")
+set(MSHR_VERSION "${MSHR_VERSION_MAJOR}.${MSHR_VERSION_MINOR}.${MSHR_VERSION_MICRO}")
+if (NOT MSHR_VERSION_RELEASE)
+  set(MSHR_VERSION "${MSHR_VERSION}.dev0")
+endif()
+
+# CGAL setup
+option(USE_SYSTEM_CGAL "Do not build CGAL, but use an existing build instead." OFF)
+if (USE_SYSTEM_CGAL)
+  find_package(CGAL 4.12 CONFIG REQUIRED)
+endif()
+
+# Borrow some cmake modules from cgal
+if (USE_SYSTEM_CGAL)
+  set(CMAKE_MODULE_PATH "${CGAL_MODULES_DIR}")
+else()
+  set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/3rdparty/CGAL/cmake/modules")
+endif()
+
+# Add cmake directory to module path
+list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake")
+
+option(USE_SYSTEM_TETGEN "Do not build tetgen, but use an existing build instead." OFF)
+if (USE_SYSTEM_TETGEN)
+  find_package(TetGen)
+endif()
+
+# Helper macro for testing if particular value is contained in list
+# Taken from http://www.cmake.org/Wiki/CMakeMacroListOperations#LIST_CONTAINS
+MACRO(LIST_CONTAINS var value)
+  SET(${var})
+  FOREACH (value2 ${ARGN})
+    IF (${value} STREQUAL ${value2})
+      SET(${var} TRUE)
+    ENDIF (${value} STREQUAL ${value2})
+  ENDFOREACH (value2)
+ENDMACRO(LIST_CONTAINS)
+
+# Use C++11
+SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x -Wall")
+
+# Boost
+# This is workaround to avoid that find_package(Boost)
+# picks up th ewrong boost when a hint is given
+set(BOOST_ROOT $ENV{BOOST_DIR} $ENV{BOOST_HOME})
+if (BOOST_ROOT)
+  set(Boost_NO_SYSTEM_PATHS on)
+endif()
+
+# Prevent FindBoost.cmake from looking for system Boost{foo}.cmake files
+set(Boost_NO_BOOST_CMAKE true)
+find_package( Boost REQUIRED system filesystem program_options )
+# Save this because it will be overwritten by find_package(DOLFIN)
+set(Boost_MSHR_LIBRARIES ${Boost_LIBRARIES})
+include_directories("${Boost_INCLUDE_DIRS}")
+
+#  GMP_INCLUDE_DIR       - the GMP include directory
+#  GMP_LIBRARIES_DIR     - directory where the GMP libraries are located
+#  GMP_LIBRARIES         - Link these to use GMP
+find_package(GMP REQUIRED)
+include_directories("${GMP_INCLUDE_DIR}")
+
+# Try to find the MPFR libraries
+# MPFR_FOUND - system has MPFR lib
+# MPFR_INCLUDE_DIR - the MPFR include directory
+# MPFR_LIBRARIES_DIR - Directory where the MPFR libraries are located
+# MPFR_LIBRARIES - the MPFR libraries
+# MPFR_IN_CGAL_AUXILIARY - TRUE if the MPFR found is the one distributed with CGAL in the auxiliary folder
+find_package(MPFR REQUIRED)
+include_directories("${MPFR_INCLUDE_DIR}")
+
+find_package(Eigen3 REQUIRED)
+include_directories("${EIGEN3_INCLUDE_DIR}")
+
+# use CGAL in header-only mode
+option (CGAL_HEADER_ONLY "Use CGAL in header-only mode" ON)
+if (CGAL_HEADER_ONLY)
+  add_definitions( -DCGAL_HEADER_ONLY )
+endif()
+
+add_subdirectory(3rdparty)
+#include_directories(BEFORE ${CGAL_INCLUDE_DIR})
+include_directories(BEFORE ${EXTERNAL_INCLUDE_DIRS})
+add_definitions("${EXTERNAL_DEFINITIONS}")
+
+find_package(DOLFIN REQUIRED)
+include(${DOLFIN_USE_FILE})
+
+# Set installation directories
+set(INSTALL_LIB_DIR lib CACHE PATH "Installation directory for libraries")
+set(INSTALL_BIN_DIR bin CACHE PATH "Installation directory for executables")
+set(INSTALL_INCLUDE_DIR include CACHE PATH "Installation directory for header files")
+set(SHARE_DIR "share/mshr" CACHE PATH "Shared data installation directory.")
+
+# Make relative paths absolute (needed later on)
+foreach(p LIB BIN INCLUDE CMAKE)
+  set(var INSTALL_${p}_DIR)
+  if(NOT IS_ABSOLUTE "${${var}}")
+    set(${var} "${CMAKE_INSTALL_PREFIX}/${${var}}")
+  endif()
+endforeach()
+
+
+# include for local header directory
+include_directories( BEFORE include )
+
+file( GLOB_RECURSE SOURCES src/*.cpp )
+
+add_library(mshr SHARED ${SOURCES})
+if (NOT USE_SYSTEM_CGAL)
+  add_dependencies( mshr CGAL )
+endif()
+
+# Append the library version information to the library target properties
+option(MSHR_WITH_LIBRARY_VERSION "Build with library version information." ON)
+if (MSHR_WITH_LIBRARY_VERSION)
+  string(REPLACE "+" "" MSHR_LIBRARY_VERSION ${MSHR_VERSION})
+  # This setting of SOVERSION assumes that any API change
+  # will increment either the minor or major version number.
+  set(MSHR_LIBRARY_PROPERTIES ${MSHR_LIBRARY_PROPERTIES}
+    VERSION ${MSHR_LIBRARY_VERSION}
+    SOVERSION ${MSHR_VERSION_MAJOR}.${MSHR_VERSION_MINOR}
+  )
+endif()
+set_target_properties(mshr PROPERTIES ${MSHR_LIBRARY_PROPERTIES})
+
+# Link the executable to (static) CGAL libraries
+target_link_libraries( mshr ${GMP_LIBRARIES}
+                            ${MPFR_LIBRARIES}
+                            tet
+                     )
+
+# Fix CGAL's random generator (usefull to reproduce bugs)
+option(INIT_CGAL_RANDOM "Use fixed seed for CGAL's pseudo random generator" OFF)
+if (INIT_CGAL_RANDOM)
+  add_definitions( -DINIT_RANDOM_GENERATOR=0 )
+endif()
+
+#
+option(ENABLE_EXPERIMENTAL "Enable experimental code" OFF)
+if(ENABLE_EXPERIMENTAL)
+  message(STATUS "Enabling experimental code")
+  add_definitions( -DMSHR_ENABLE_EXPERIMENTAL )
+endif()
+
+
+export(PACKAGE mshr)
+
+target_link_libraries( mshr
+  dolfin
+  ${Boost_MSHR_LIBRARIES}
+  )
+
+# install library
+install(TARGETS mshr
+  RUNTIME DESTINATION ${INSTALL_BIN_DIR}
+  LIBRARY DESTINATION ${INSTALL_LIB_DIR}
+  ARCHIVE DESTINATION ${INSTALL_LIB_DIR}
+  )
+
+option(ENABLE_MSHRABLE "Enable building the command line client, mshrable" OFF)
+if (ENABLE_MSHRABLE)
+  add_executable( mshrable app/mshrable.cpp )
+
+  target_link_libraries( mshrable
+    mshr
+    dolfin
+    ${Boost_MSHR_LIBRARIES}
+    )
+
+  # install app
+  install(TARGETS mshrable
+    RUNTIME DESTINATION ${INSTALL_BIN_DIR}
+    LIBRARY DESTINATION ${INSTALL_LIB_DIR}
+    ARCHIVE DESTINATION ${INSTALL_LIB_DIR}
+    )
+else()
+    message(STATUS "Disabling building command line client mshrable")
+endif()
+
+# install header files
+install(DIRECTORY include/ DESTINATION ${INSTALL_INCLUDE_DIR})
+
+file(RELATIVE_PATH REL_INCLUDE_DIR "${INSTALL_CMAKE_DIR}" "${INSTALL_INCLUDE_DIR}")
+
+### add cmake configuration file ###
+
+# common for both config files
+set(CONF_EXTERNAL_INCLUDE_DIRS "${DOLFIN_INCLUDE_DIRS};${DOLFIN_3RD_PARTY_INCLUDE_DIRS}")
+set(CONF_EXTERNAL_LIBRARIES "${DOLFIN_LIBRARIES};${DOLFIN_3RD_PARTY_LIBRARIES}")
+set(CONF_CXX_DEFINITIONS "${DOLFIN_CXX_DEFINITIONS}")
+string(REPLACE "\"" "\\\"" CONF_CXX_DEFINITIONS "${CONF_CXX_DEFINITIONS}")
+set(CONF_CXX_FLAGS "${DOLFIN_CXX_FLAGS}")
+
+# for the build tree
+set(CONF_INCLUDE_DIRS "${PROJECT_SOURCE_DIR}/include")
+set(CONF_LIBRARIES_DIRS "${PROJECT_BINARY_DIR}")
+
+configure_file(mshrConfig.cmake.in "${PROJECT_BINARY_DIR}/mshrConfig.cmake" @ONLY)
+configure_file(mshr-config.cmake.in "${PROJECT_BINARY_DIR}/mshr-config.cmake" @ONLY)
+
+# ... and for the install tree
+set(CONF_INCLUDE_DIRS "${INSTALL_INCLUDE_DIR}")
+set(CONF_LIBRARIES_DIRS "${INSTALL_LIB_DIR}")
+configure_file(mshrConfig.cmake.in
+  "${PROJECT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/mshrConfig.cmake" @ONLY)
+configure_file(mshr-config.cmake.in
+  "${PROJECT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/mshr-config.cmake" @ONLY)
+
+# Install the FooBarConfig.cmake and FooBarConfigVersion.cmake
+install(FILES "${PROJECT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/mshrConfig.cmake" DESTINATION "${INSTALL_LIB_DIR}/cmake/mshr" COMPONENT dev)
+install(FILES "${PROJECT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/mshr-config.cmake" DESTINATION "${INSTALL_LIB_DIR}/cmake/mshr" COMPONENT dev)
+#install(FILES "Use-mshr.cmake" DESTINATION "${INSTALL_CMAKE_DIR}" COMPONENT dev)
+
+
+
+
+
+option(ENABLE_TESTS "Enable testing" OFF)
+
+if(ENABLE_TESTS)
+  enable_testing()
+  add_subdirectory(test)
+else()
+  message(STATUS "Testing disabled")
+endif()
diff --git a/COPYING b/COPYING
new file mode 100644 (file)
index 0000000..94a9ed0
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,674 @@
+                    GNU GENERAL PUBLIC LICENSE
+                       Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                            Preamble
+
+  The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+  The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works.  By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users.  We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors.  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, 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
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+  To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights.  Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received.  You must make sure that they, too, receive
+or can get the source code.  And you must show them these terms so they
+know their rights.
+
+  Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+  For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software.  For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+  Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so.  This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software.  The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable.  Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products.  If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+  Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary.  To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                       TERMS AND CONDITIONS
+
+  0. Definitions.
+
+  "This License" refers to version 3 of the GNU General Public License.
+
+  "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+  "The Program" refers to any copyrightable work licensed under this
+License.  Each licensee is addressed as "you".  "Licensees" and
+"recipients" may be individuals or organizations.
+
+  To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy.  The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+  A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+  To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy.  Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+  To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies.  Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+  An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License.  If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+  1. Source Code.
+
+  The "source code" for a work means the preferred form of the work
+for making modifications to it.  "Object code" means any non-source
+form of a work.
+
+  A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+  The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form.  A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+  The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities.  However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work.  For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+  The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+  The Corresponding Source for a work in source code form is that
+same work.
+
+  2. Basic Permissions.
+
+  All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met.  This License explicitly affirms your unlimited
+permission to run the unmodified Program.  The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work.  This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+  You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force.  You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright.  Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+  Conveying under any other circumstances is permitted solely under
+the conditions stated below.  Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+  3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+  No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+  When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+  4. Conveying Verbatim Copies.
+
+  You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+  You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+  5. Conveying Modified Source Versions.
+
+  You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+    a) The work must carry prominent notices stating that you modified
+    it, and giving a relevant date.
+
+    b) The work must carry prominent notices stating that it is
+    released under this License and any conditions added under section
+    7.  This requirement modifies the requirement in section 4 to
+    "keep intact all notices".
+
+    c) You must license the entire work, as a whole, under this
+    License to anyone who comes into possession of a copy.  This
+    License will therefore apply, along with any applicable section 7
+    additional terms, to the whole of the work, and all its parts,
+    regardless of how they are packaged.  This License gives no
+    permission to license the work in any other way, but it does not
+    invalidate such permission if you have separately received it.
+
+    d) If the work has interactive user interfaces, each must display
+    Appropriate Legal Notices; however, if the Program has interactive
+    interfaces that do not display Appropriate Legal Notices, your
+    work need not make them do so.
+
+  A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit.  Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+  6. Conveying Non-Source Forms.
+
+  You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+    a) Convey the object code in, or embodied in, a physical product
+    (including a physical distribution medium), accompanied by the
+    Corresponding Source fixed on a durable physical medium
+    customarily used for software interchange.
+
+    b) Convey the object code in, or embodied in, a physical product
+    (including a physical distribution medium), accompanied by a
+    written offer, valid for at least three years and valid for as
+    long as you offer spare parts or customer support for that product
+    model, to give anyone who possesses the object code either (1) a
+    copy of the Corresponding Source for all the software in the
+    product that is covered by this License, on a durable physical
+    medium customarily used for software interchange, for a price no
+    more than your reasonable cost of physically performing this
+    conveying of source, or (2) access to copy the
+    Corresponding Source from a network server at no charge.
+
+    c) Convey individual copies of the object code with a copy of the
+    written offer to provide the Corresponding Source.  This
+    alternative is allowed only occasionally and noncommercially, and
+    only if you received the object code with such an offer, in accord
+    with subsection 6b.
+
+    d) Convey the object code by offering access from a designated
+    place (gratis or for a charge), and offer equivalent access to the
+    Corresponding Source in the same way through the same place at no
+    further charge.  You need not require recipients to copy the
+    Corresponding Source along with the object code.  If the place to
+    copy the object code is a network server, the Corresponding Source
+    may be on a different server (operated by you or a third party)
+    that supports equivalent copying facilities, provided you maintain
+    clear directions next to the object code saying where to find the
+    Corresponding Source.  Regardless of what server hosts the
+    Corresponding Source, you remain obligated to ensure that it is
+    available for as long as needed to satisfy these requirements.
+
+    e) Convey the object code using peer-to-peer transmission, provided
+    you inform other peers where the object code and Corresponding
+    Source of the work are being offered to the general public at no
+    charge under subsection 6d.
+
+  A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+  A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling.  In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage.  For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product.  A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+  "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source.  The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+  If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information.  But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+  The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed.  Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+  Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+  7. Additional Terms.
+
+  "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law.  If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+  When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it.  (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.)  You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+  Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+    a) Disclaiming warranty or limiting liability differently from the
+    terms of sections 15 and 16 of this License; or
+
+    b) Requiring preservation of specified reasonable legal notices or
+    author attributions in that material or in the Appropriate Legal
+    Notices displayed by works containing it; or
+
+    c) Prohibiting misrepresentation of the origin of that material, or
+    requiring that modified versions of such material be marked in
+    reasonable ways as different from the original version; or
+
+    d) Limiting the use for publicity purposes of names of licensors or
+    authors of the material; or
+
+    e) Declining to grant rights under trademark law for use of some
+    trade names, trademarks, or service marks; or
+
+    f) Requiring indemnification of licensors and authors of that
+    material by anyone who conveys the material (or modified versions of
+    it) with contractual assumptions of liability to the recipient, for
+    any liability that these contractual assumptions directly impose on
+    those licensors and authors.
+
+  All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10.  If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term.  If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+  If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+  Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+  8. Termination.
+
+  You may not propagate or modify a covered work except as expressly
+provided under this License.  Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+  However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+  Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+  Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License.  If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+  9. Acceptance Not Required for Having Copies.
+
+  You are not required to accept this License in order to receive or
+run a copy of the Program.  Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance.  However,
+nothing other than this License grants you permission to propagate or
+modify any covered work.  These actions infringe copyright if you do
+not accept this License.  Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+  10. Automatic Licensing of Downstream Recipients.
+
+  Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License.  You are not responsible
+for enforcing compliance by third parties with this License.
+
+  An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations.  If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+  You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License.  For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+  11. Patents.
+
+  A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based.  The
+work thus licensed is called the contributor's "contributor version".
+
+  A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version.  For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+  Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+  In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement).  To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+  If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients.  "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+  If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+  A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License.  You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+  Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+  12. No Surrender of Others' Freedom.
+
+  If 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 convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all.  For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+  13. Use with the GNU Affero General Public License.
+
+  Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work.  The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+  14. Revised Versions of this License.
+
+  The Free Software Foundation may publish revised and/or new versions of
+the GNU 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
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation.  If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+  If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+  Later license versions may give you additional or different
+permissions.  However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+  15. Disclaimer of Warranty.
+
+  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "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 PROGRAM
+IS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. Limitation of Liability.
+
+  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM 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 PROGRAM (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 PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+  17. Interpretation of Sections 15 and 16.
+
+  If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+                     END OF TERMS AND CONDITIONS
+
+            How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+state 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 program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    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 3 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+  If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+    <program>  Copyright (C) <year>  <name of author>
+    This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+  You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+<http://www.gnu.org/licenses/>.
+
+  The GNU General Public License does not permit incorporating your program
+into proprietary programs.  If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications with
+the library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.  But first, please read
+<http://www.gnu.org/philosophy/why-not-lgpl.html>.
diff --git a/ChangeLog.rst b/ChangeLog.rst
new file mode 100644 (file)
index 0000000..8418d2d
--- /dev/null
@@ -0,0 +1,53 @@
+Changelog
+=========
+
+2019.2.0.dev0
+-------------
+
+- No changes yet.
+
+2019.1.0 (2019-04-17)
+---------------------
+
+- No changes.
+
+2018.1.0 (2018-06-14)
+--------------
+
+- Drop python2 support.
+- Switch to pybind11 bindings from SWIG.
+
+2017.2.0 (2017-12-05)
+---------------------
+
+- Nothing changed yet
+
+2017.1.0 (2017-05-11)
+---------------------
+
+- Bugfixes
+
+2016.2.0 (2016-11-30)
+---------------------
+
+- Improvements and bugfixes
+- Upgrade to CGAL 4.9 and use CGAL as header only library
+
+2016.1.0 (2016-06-23)
+---------------------
+
+- Major improvements, in particular boundary conditions
+
+1.6.0 (2015-07-28)
+------------------
+
+- Upgrade to CGAL 4.6
+- Add more demos
+- Faster and more memory efficient implementation of csg operations
+  with -DENABLE_EXPERIMENTAL=True
+- Bugfixes and cleanups
+
+1.5.0 (2015-02-04)
+------------------
+
+- Initial release of mshr.
diff --git a/README.rst b/README.rst
new file mode 100644 (file)
index 0000000..b9b9be4
--- /dev/null
@@ -0,0 +1,81 @@
+====\r
+mshr\r
+====\r
+\r
+mshr is the mesh generation component of `FEniCS\r
+<http://fenicsproject.org/>`_. It generates simplicial `DOLFIN\r
+<https://bitbucket.org/fenics-project/dolfin>`_ meshes in 2D and 3D\r
+from geometries described by Constructive Solid Geometry (CSG) or from\r
+surface files, utilizing CGAL and Tetgen as mesh generation backends.\r
+\r
+Authors:\r
+  | Benjamin Kehlet <benjamik@simula.no>\r
+\r
+Contributors:\r
+  | Anders Logg     <logg@chalmers.se>\r
+  | Johannes Ring   <johannr@simula.no>\r
+  | Garth N. Wells  <gnw20@cam.ac.uk>\r
+\r
+Documentation\r
+=============\r
+\r
+The documentation is currently being prepared here: \r
+`https://bitbucket.org/fenics-project/mshr/wiki <https://bitbucket.org/fenics-project/mshr/wiki>`_\r
+\r
+Installation\r
+============\r
+For Debian and Ubuntu users, installing mshr is as easy as::\r
+\r
+  sudo apt-get install fenics\r
+\r
+To get a recent version of, enable the FEniCS PPA first. See `Installation instructions for Ubuntu <http://fenicsproject.org/download/ubuntu_details.html>`_\r
+\r
+To build mshr from source, run::\r
+\r
+  cmake <path to mshr source tree>\r
+  make\r
+  make install\r
+\r
+mshr's build script will also build CGAL and Tetgen from source and\r
+include them in the binary.\r
+\r
+Dependencies\r
+============\r
+\r
+mshr needs `DOLFIN <https://bitbucket.org/fenics-project/dolfin>`_\r
+with Python support (pyDolfin). `CGAL <http://www.cgal.org/>`_ and\r
+`Tetgen <http://www.tetgen.org>`_ are shipped with mshr and built from\r
+source automatically. CGAL needs `Gnu GMP <https://gmplib.org/>`_ and\r
+`Gnu MPFR <http://www.mpfr.org/>`_.\r
+\r
+License\r
+=======\r
+\r
+mshr is licensed under GPL version 3 or (at your option) any later\r
+version.\r
+\r
+Contact\r
+=======\r
+\r
+mshr is hosted at https://bitbucket.org/fenics-project/mshr/\r
+\r
+For comments and requests, send an email to the FEniCS mailing list::\r
+\r
+ fenics@fenicsproject.org\r
+\r
+For bug reports and feature requests, visit mshr's issue tracker at BitBucket::\r
+\r
+ https://bitbucket.org/fenics-project/mshr/issues\r
+\r
+Contributions\r
+=============\r
+\r
+Contributions are welcome!\r
+\r
+Please read about contributing to FEniCS here:\r
+http://fenicsproject.org/contributing/\r
+\r
+If you plan to implement a new feature, please discuss it at the\r
+FEniCS mailing list beforehand. Smaller patches and bugfixes are\r
+easiest submitted as `pull request on Bitbucket\r
+<https://confluence.atlassian.com/display/BITBUCKET/Work+with+pull+requests>`_.
\ No newline at end of file
diff --git a/app/mshrable.cpp b/app/mshrable.cpp
new file mode 100644 (file)
index 0000000..c486a7c
--- /dev/null
@@ -0,0 +1,172 @@
+// Copyright (C) 2014 Benjamin Kehlet
+//
+// This file is part of mshr.
+//
+// mshr 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 3 of the License, or
+// (at your option) any later version.
+// 
+// mshr 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 mshr.  If not, see <http://www.gnu.org/licenses/>.
+//
+
+#include <mshr.h>
+#include <dolfin.h>
+
+#include <boost/program_options/options_description.hpp>
+#include <boost/program_options/variables_map.hpp>
+#include <boost/program_options/parsers.hpp>
+#include <boost/filesystem.hpp>
+
+#include <string>
+#include <iostream>
+
+namespace po = boost::program_options;
+
+// This program reads in a surface from file and generates mesh
+
+
+namespace
+{
+void print_mesh_statistics(const dolfin::Mesh& m)
+{
+  std::cout << "Dolfin mesh of topological dimension " << m.topology().dim() << std::endl;
+  std::cout << "  " << m.num_vertices() << " vertices" << std::endl;
+  std::cout << "  " << m.num_cells() << " cells" << std::endl;
+
+  const std::pair<double, double> volume_min_max = mshr::DolfinMeshUtils::cell_volume_min_max(m);
+  std::cout << "Min cell volume: " << volume_min_max.first << std::endl;
+  std::cout << "Max cell volume: " << volume_min_max.second << std::endl;
+  const std::pair<double, double> radii_ratio = dolfin::MeshQuality::radius_ratio_min_max(m);
+  std::cout << "Minimum cell radii ratio: " << radii_ratio.first  << std::endl;
+  std::cout << "Maximum cell radii ratio: " << radii_ratio.second << std::endl;
+}
+//-----------------------------------------------------------------------------
+// Define options and parse command line
+void handle_commandline(int argc, char** argv, po::variables_map &vm)
+{
+  // Command line options
+  po::options_description visible("Generate mesh from surface file");
+  visible.add_options()
+    ("outfile,o",    po::value<std::string>(), "Filename of generated Dolfin mesh")
+    ("resolution,r", po::value<double>()->default_value(15.0), "Resolution of result mesh")
+    ("stats,s", "Write some statistics of the mesh to stdout")
+    ("polyout", po::value<std::string>(), "Write the polyhedron to a .off file (and do not create a mesh)")
+    ("polystats", "Write statistics of polyhedron (and do not create a mesh")
+    ("backend,b", po::value<std::string>()->default_value("cgal"), "Use 3D mesh generation backend [tetgen|cgal]")
+    ("degenerate_tolerance", po::value<double>()->default_value(1e-12), "Tolerance for considering a facet as degenerate. Set to 0 to not remove degenerate facets")
+    ("check-mesh", "Check consistency of output mesh (most for debugging/testing")
+    ("verbose,v", "Output more information about what is going on")
+    ("help,h",   "write help message");
+
+  // Options not shown to the user
+  po::options_description hidden("Hidden options");
+  hidden.add_options()
+    ("input-file", po::value<std::string>(), "Input file")
+    ;
+
+  po::options_description cmdline("Generate mesh from surface file");
+  cmdline.add(visible).add(hidden);
+
+  //Command line positional arguments
+  po::positional_options_description p;
+  p.add("input-file", 1);
+
+  // parse command line
+  po::store(po::command_line_parser(argc, argv)
+            .options(cmdline)
+            .positional(p).run(), vm);
+
+  // Print help message if requested 
+  // (before notify to avoid error messages if only --help is given)
+  if (vm.count("help"))
+  {
+    std::cout << visible << std::endl;
+    exit(EXIT_SUCCESS);
+  }
+
+  po::notify(vm);
+
+}
+} //end anonymous namespace
+//-----------------------------------------------------------------------------
+int main(int argc, char** argv)
+{
+  // Ensure Dolfin initializes MPI correctly.
+  #ifdef HAS_MPI
+  dolfin::SubSystemsManager::init_mpi();
+  #endif
+
+  po::variables_map vm;
+  handle_commandline(argc, argv, vm);
+
+  if (vm.count("verbose"))
+    dolfin::set_log_level(dolfin::TRACE);
+
+  // Read the infile
+  if (!boost::filesystem::exists(vm["input-file"].as<std::string>()))
+  {
+    std::cerr << "File " << vm["input-file"].as<std::string>() << "does not exist" << std::endl;
+    exit(1);
+  }
+
+
+  std::shared_ptr<mshr::Surface3D> surf(new mshr::Surface3D(vm["input-file"].as<std::string>()));
+  surf->degenerate_tolerance = vm["degenerate_tolerance"].as<double>();
+
+  // Operations that disable mesh generation
+  if (vm.count("polyout") || vm.count("polystats"))
+  {
+    mshr::CSGCGALDomain3D domain(surf);
+
+    if (vm.count("polyout"))
+    {
+      std::string extension = boost::filesystem::extension(vm["polyout"].as<std::string>());
+
+      if (extension != ".off")
+      {
+        std::cerr << "Unknown file type: " << extension << std::endl;
+        exit(1);
+      }
+
+      domain.save_off(vm["polyout"].as<std::string>());
+    }
+
+    if (vm.count("polystats"))
+      std::cout << domain.str(true) << std::endl;
+
+    exit(EXIT_SUCCESS);
+  }
+
+  // Generate the mesh
+  std::shared_ptr<dolfin::Mesh> m = mshr::generate_mesh(surf,
+                                                        vm["resolution"].as<double>(),
+                                                        vm["backend"].as<std::string>());
+
+  // Output mesh if requested
+  if (vm.count("outfile"))
+  {
+    dolfin::File f(vm["outfile"].as<std::string>());
+    f << *m;
+  }
+    
+  if (vm.count("stats"))
+    print_mesh_statistics(*m);
+
+  if (vm.count("check-mesh"))
+  {
+    if (!mshr::DolfinMeshUtils::check_mesh(*m))
+    {
+      std::cout << "  Error: Mesh check failed" << std::endl;
+      return EXIT_FAILURE;
+    }
+  }
+
+  return EXIT_SUCCESS;
+}
diff --git a/cmake/FindTetGen.cmake b/cmake/FindTetGen.cmake
new file mode 100644 (file)
index 0000000..db5e6e6
--- /dev/null
@@ -0,0 +1,42 @@
+#.rst:
+# FindTetGen
+# --------
+#
+# Find TetGen library
+#
+# Find the TetGen includes and library This module defines
+#
+# ::
+#
+#   TETGEN_INCLUDE_DIRS, where to find triangle.h.
+#   TETGEN_LIBRARIES, libraries to link against to use triangle.
+#   TETGEN_FOUND, If false, do not try to use TETGEN.
+#
+#
+#
+#
+#
+#=============================================================================
+
+find_path(TETGEN_INCLUDE_DIR tetgen.h
+          DOC "The TetGen include directory")
+
+set(TETGEN_NAMES ${TETGEN_NAMES} libtetgen tetgen tet)
+find_library(TETGEN_LIBRARY NAMES ${TETGEN_NAMES}
+            DOC "The TetGen library")
+
+# handle the QUIETLY and REQUIRED arguments and set TETGEN_FOUND to TRUE if
+# all listed variables are TRUE
+include(FindPackageHandleStandardArgs)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(TETGEN
+                                  REQUIRED_VARS TETGEN_LIBRARY
+                                                TETGEN_INCLUDE_DIR
+                                  VERSION_VAR TETGEN_VERSION_STRING)
+
+if(TETGEN_FOUND)
+  set( TETGEN_LIBRARIES ${TETGEN_LIBRARY} )
+  set( TETGEN_INCLUDE_DIRS ${TETGEN_INCLUDE_DIR} )
+  add_definitions(-DTETLIBRARY)
+endif()
+
+mark_as_advanced(TETGEN_INCLUDE_DIR TETGEN_LIBRARY)
diff --git a/demo/python/classic.py b/demo/python/classic.py
new file mode 100644 (file)
index 0000000..2419563
--- /dev/null
@@ -0,0 +1,39 @@
+# Copyright (C) 2015 Anders Logg
+#
+# This file is part of mshr.
+#
+# mshr 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 3 of the License, or
+# (at your option) any later version.
+#
+# mshr 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 mshr.  If not, see <http://www.gnu.org/licenses/>.
+
+from dolfin import *
+from mshr import *
+
+# Create geometry
+s1 = Sphere(Point(0, 0, 0), 1.4)
+b1 = Box(Point(-1, -1, -1), Point(1, 1, 1))
+c1 = Cylinder(Point(-2, 0, 0), Point(2, 0, 0), 0.8, 0.8)
+c2 = Cylinder(Point(0, -2, 0), Point(0, 2, 0), 0.8, 0.8)
+c3 = Cylinder(Point(0, 0, -2), Point(0, 0, 2), 0.8, 0.8)
+
+geometry = s1*b1 - (c1 + c2 + c3)
+
+# Create mesh
+mesh = generate_mesh(geometry, 64)
+
+# Save to file and plot
+File("classic.pvd") << mesh
+
+plot(mesh)
+
+# import matplotlib.pyplot as plt
+# plt.show()
diff --git a/demo/python/csg-subdomains-2D.py b/demo/python/csg-subdomains-2D.py
new file mode 100644 (file)
index 0000000..636f412
--- /dev/null
@@ -0,0 +1,45 @@
+# Copyright (C) 2012-2014 Benjamin Kehlet
+#
+# This file is part of mshr.
+#
+# mshr 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 3 of the License, or
+# (at your option) any later version.
+# 
+# mshr 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 mshr.  If not, see <http://www.gnu.org/licenses/>.
+
+import dolfin
+from mshr import *
+
+#dolfin.set_log_level(dolfin.TRACE)
+
+# Define 2D geometry
+domain =   Rectangle(dolfin.Point(0., 0.), dolfin.Point(5., 5.)) \
+         - Rectangle(dolfin.Point(2., 1.25), dolfin.Point(3., 1.75)) \
+         - Circle(dolfin.Point(1, 4), .25) \
+         - Circle(dolfin.Point(4, 4), .25)
+domain.set_subdomain(1, Rectangle(dolfin.Point(1., 1.), dolfin.Point(4., 3.)))
+domain.set_subdomain(2, Rectangle(dolfin.Point(2., 2.), dolfin.Point(3., 4.)))
+
+print("Verbose output of 2D geometry:")
+dolfin.info(domain, True)
+
+# Generate and plot mesh
+mesh2d = generate_mesh(domain, 45)
+print(mesh2d)
+
+dolfin.plot(mesh2d, "2D mesh")
+
+# Convert subdomains to mesh function for plotting
+mf = dolfin.MeshFunction("size_t", mesh2d, 2, mesh2d.domains())
+dolfin.plot(mf, "Subdomains")
+
+# import matplotlib.pyplot as plt
+# plt.show()
diff --git a/demo/python/deathstar.py b/demo/python/deathstar.py
new file mode 100644 (file)
index 0000000..dbbf520
--- /dev/null
@@ -0,0 +1,45 @@
+# Copyright (C) 2015 Anders Logg
+#
+# This file is part of mshr.
+#
+# mshr 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 3 of the License, or
+# (at your option) any later version.
+#
+# mshr 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 mshr.  If not, see <http://www.gnu.org/licenses/>.
+
+from dolfin import *
+from mshr import *
+from math import pi, sin, cos, sqrt
+
+# Parameters
+R = 1.02
+r = 0.4
+t = 10
+x = R*cos(float(t) / 180 * pi)
+y = 0
+z = R*sin(t)
+
+# Create geometry
+s1 = Sphere(Point(0, 0, 0), 1)
+s2 = Sphere(Point(x, y, z), r)
+b1 = Box(Point(-2, -2, -0.03), Point(2, 2, 0.03))
+geometry = s1 - s2 - b1
+
+# Create mesh
+mesh = generate_mesh(geometry, 32)
+
+# Save to file and plot
+File("deathstar.pvd") << mesh
+
+plot(mesh)
+
+# import matplotlib.pyplot as plt
+# plt.show()
diff --git a/demo/python/extrude.py b/demo/python/extrude.py
new file mode 100644 (file)
index 0000000..f63d69f
--- /dev/null
@@ -0,0 +1,30 @@
+# Copyright (C) 2015 Benjamin Kehlet
+#
+# This file is part of mshr.
+#
+# mshr 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 3 of the License, or
+# (at your option) any later version.
+# 
+# mshr 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 mshr.  If not, see <http://www.gnu.org/licenses/>.
+
+# This demo illustrates how a 2D geometry can be extruded to 3D.
+
+from dolfin import *
+import mshr
+
+g2d = mshr.Circle(Point(0,0), 1.2) + mshr.Circle(Point(0, 1.2), 1.2)
+
+# Any simple 2D geometry can be extruded to 3D
+g3d = mshr.Extrude2D(g2d, 
+                     .2) # The z "thickness"
+
+m = mshr.generate_mesh(g3d, 15)
+plot(m)
diff --git a/demo/python/icecream.py b/demo/python/icecream.py
new file mode 100644 (file)
index 0000000..b9031a2
--- /dev/null
@@ -0,0 +1,48 @@
+# Copyright (C) 2014 Benjamin Kehlet
+#
+# This file is part of mshr.
+#
+# mshr 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 3 of the License, or
+# (at your option) any later version.
+#
+# mshr 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 mshr. If not, see <http://www.gnu.org/licenses/>.
+#
+
+import dolfin
+from mshr import *
+
+# Define 3D geometry
+sphere = Sphere(dolfin.Point(0, 0, 0), 0.5)
+cone = Cylinder(dolfin.Point(0, 0, 0), dolfin.Point(0, 0, -1), .35, .1)
+
+geometry = cone + sphere
+
+# Geometry surfaces can be saved to off files
+# which can be viewed by eg. MeshLab
+meshing_domain = CSGCGALDomain3D(geometry)
+meshing_domain.remove_degenerate_facets(1e-12)
+meshing_domain.save("icecream.off")
+
+# Test printing
+dolfin.info("\nCompact output of 3D geometry:")
+dolfin.info(geometry)
+dolfin.info("\nVerbose output of 3D geometry:")
+dolfin.info(geometry, True)
+
+# Generate and plot mesh
+m = generate_mesh(geometry, 16, "cgal")
+print(m)
+
+dolfin.plot(m, "3D mesh")
+
+# import matplotlib.pyplot as plt
+# plt.show()
+
diff --git a/demo/python/materials.py b/demo/python/materials.py
new file mode 100644 (file)
index 0000000..1a64718
--- /dev/null
@@ -0,0 +1,41 @@
+# Copyright (C) 2014 Benjamin Kehlet
+#
+#
+# This file is part of mshr.
+#
+# mshr 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 3 of the License, or
+# (at your option) any later version.
+# 
+# mshr 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 mshr.  If not, see <http://www.gnu.org/licenses/>.
+
+import dolfin
+from mshr import *
+
+#dolfin.set_log_level(dolfin.TRACE)
+
+# Define 2D geometry
+domain = Rectangle(dolfin.Point(0., 0.), dolfin.Point(1., 1.)) - Circle(dolfin.Point(0.0, 0.0), .35)
+domain.set_subdomain(1, Rectangle(dolfin.Point(.05, .05), dolfin.Point(.95, .95)))
+domain.set_subdomain(2, Circle(dolfin.Point(0, 0), .45))
+domain.set_subdomain(3, Circle(dolfin.Point(0,0), .6))
+
+# Generate and plot mesh
+mesh2d = generate_mesh(domain, 45)
+dolfin.plot(mesh2d, "2D mesh")
+
+# Convert subdomains to mesh function for plotting
+mf = dolfin.MeshFunction("size_t", mesh2d, 2, mesh2d.domains())
+
+dolfin.plot(mf, "Subdomains")
+
+# import matplotlib.pyplot as plt
+# plt.show()
+
diff --git a/demo/python/propeller.py b/demo/python/propeller.py
new file mode 100644 (file)
index 0000000..6dd34c7
--- /dev/null
@@ -0,0 +1,86 @@
+# Copyright (C) 2014 Anders Logg
+#
+# This file is part of mshr.
+#
+# mshr 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 3 of the License, or
+# (at your option) any later version.
+#
+# mshr 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 mshr.  If not, see <http://www.gnu.org/licenses/>.
+
+from __future__ import print_function
+from mshr import *
+from dolfin import *
+
+# Set parameters
+r = 0.125
+R = 0.5
+w = 0.3
+h = 0.025
+rotate_blades = True
+include_tip = False
+extra_rotation = True # only applied to inner mesh
+resolution = 4
+
+# Define geometries
+sphere = Sphere(Point(0, 0, 0), 2*R)
+geometry_inside = CSGGeometries.propeller(r, R, w, h, rotate_blades, include_tip)
+geometry_outside = sphere - geometry_inside
+
+# Generate meshes
+mesh_inside = generate_mesh(geometry_inside, resolution)
+mesh_outside = generate_mesh(geometry_outside, resolution)
+
+# Rotate blades
+if extra_rotation:
+    print("Rotating blades...")
+    c = mesh_inside.coordinates()
+    for i, (x, y, z) in enumerate(c):
+
+        # Compute distance to axis
+        _r = sqrt(x**2 + y**2)
+
+        # Compute rotation angle
+        v = -2*max(0, _r - r)
+
+        # Rotate blades
+        xx = x; yy = y; zz = z;
+        if x > 0 and abs(y) < 5*h:
+            yy = cos(v)*y - sin(v)*z
+            zz = sin(v)*y + cos(v)*z
+        elif x < 0 and abs(y) < 5*h:
+            yy = cos(v)*y + sin(v)*z
+            zz = -sin(v)*y + cos(v)*z
+        elif y > 0 and abs(x) < 5*h:
+            xx = cos(v)*x + sin(v)*z
+            zz = -sin(v)*x + cos(v)*z
+        elif y < 0 and abs(x) < 5*h:
+            xx = cos(v)*x - sin(v)*z
+            zz = sin(v)*x + cos(v)*z
+
+        # Store coordinates
+        c[i][0] = xx
+        c[i][1] = yy
+        c[i][2] = zz
+
+# Report size of meshes
+print("Mesh of propeller inside:  %d cells" % mesh_inside.num_cells())
+print("Mesh of propeller outside: %d cells" % mesh_outside.num_cells())
+
+# Save meshes to file
+File("propeller_inside.xml.gz") << mesh_inside
+File("propeller_outside.xml.gz") << mesh_outside
+
+# Plot mesh
+plot(mesh_inside)
+plot(mesh_outside)
+
+# import matplotlib.pyplot as plt
+# plt.show()
diff --git a/demo/python/remove_degenerate.py b/demo/python/remove_degenerate.py
new file mode 100644 (file)
index 0000000..76b4d81
--- /dev/null
@@ -0,0 +1,18 @@
+from __future__ import print_function
+import mshr
+import dolfin
+
+TOLERANCE = 1e-10
+
+# This geometry generates a lot of degenerate facets
+cone = mshr.Cylinder(dolfin.Point(-1.0, 1.0, 1.0), dolfin.Point(1.0, -1.0, -1.0), .5, .5)
+cyl = mshr.Cone(dolfin.Point(1.0, -1.0, 1.0), dolfin.Point(-1.0, 1.0, -1.0), .5)
+geometry = cone + cyl;
+
+polyhedral_domain = mshr.CSGCGALDomain3D(geometry)
+
+print("Degenerate facets after boolean operation: {0}".format(polyhedral_domain.num_degenerate_facets(TOLERANCE)))
+polyhedral_domain.remove_degenerate_facets(TOLERANCE)
+
+dolfin.info(polyhedral_domain, True)
+
diff --git a/demo/python/simple-csg-3D.py b/demo/python/simple-csg-3D.py
new file mode 100644 (file)
index 0000000..62b2a89
--- /dev/null
@@ -0,0 +1,47 @@
+# Copyright (C) 2012-2014 Benjamin Kehlet
+#
+# This file is part of mshr.
+#
+# mshr 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 3 of the License, or
+# (at your option) any later version.
+# 
+# mshr 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 mshr.  If not, see <http://www.gnu.org/licenses/>.
+
+import dolfin
+from mshr import *
+
+# Define 3D geometry
+box = Box(dolfin.Point(0, 0, 0), dolfin.Point(1, 1, 1))
+sphere = Sphere(dolfin.Point(0, 0, 0), 0.3)
+cylinder = Cylinder(dolfin.Point(0, 0, -1), dolfin.Point(0, 0, 1), 1., .5)
+
+domain = box + cylinder - sphere
+
+# Test printing
+dolfin.info("\nCompact output of 3D geometry:")
+dolfin.info(domain)
+dolfin.info("\nVerbose output of 3D geometry:")
+dolfin.info(domain, True)
+
+# Creating a mesh generator object gives access to parameters of the
+# meshing backend
+generator = CSGCGALMeshGenerator3D()
+generator.parameters["edge_size"] = 0.025
+generator.parameters["facet_angle"] = 25.0
+generator.parameters["facet_size"] = 0.05
+
+# Invoke the mesh generator
+mesh = generator.generate(CSGCGALDomain3D(domain))
+
+dolfin.plot(mesh, "3D mesh")
+
+# import matplotlib.pyplot as plt
+# plt.show()
diff --git a/doc/Doxyfile b/doc/Doxyfile
new file mode 100644 (file)
index 0000000..b2bd620
--- /dev/null
@@ -0,0 +1,1890 @@
+# Doxyfile 1.8.4
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project.
+#
+# All text after a double hash (##) is considered a comment and is placed
+# in front of the TAG it is preceding .
+# All text after a hash (#) is considered a comment and will be ignored.
+# The format is:
+#       TAG = value [value, ...]
+# For lists items can also be appended using:
+#       TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (" ").
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the config file
+# that follow. The default is UTF-8 which is also the encoding used for all
+# text before the first occurrence of this tag. Doxygen uses libiconv (or the
+# iconv built into libc) for the transcoding. See
+# http://www.gnu.org/software/libiconv for the list of possible encodings.
+
+DOXYFILE_ENCODING      = UTF-8
+
+# The PROJECT_NAME tag is a single word (or sequence of words) that should
+# identify the project. Note that if you do not use Doxywizard you need
+# to put quotes around the project name if it contains spaces.
+
+PROJECT_NAME           = "mshr"
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number.
+# This could be handy for archiving the generated documentation or
+# if some version control system is used.
+
+PROJECT_NUMBER         = 1.4
+
+# Using the PROJECT_BRIEF tag one can provide an optional one line description
+# for a project that appears at the top of each page and should give viewer
+# a quick idea about the purpose of the project. Keep the description short.
+
+PROJECT_BRIEF          = "Mesh generation in FEniCS"
+
+# With the PROJECT_LOGO tag one can specify an logo or icon that is
+# included in the documentation. The maximum height of the logo should not
+# exceed 55 pixels and the maximum width should not exceed 200 pixels.
+# Doxygen will copy the logo to the output directory.
+
+PROJECT_LOGO           =
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
+# base path where the generated documentation will be put.
+# If a relative path is entered, it will be relative to the location
+# where doxygen was started. If left blank the current directory will be used.
+
+OUTPUT_DIRECTORY       =
+
+# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create
+# 4096 sub-directories (in 2 levels) under the output directory of each output
+# format and will distribute the generated files over these directories.
+# Enabling this option can be useful when feeding doxygen a huge amount of
+# source files, where putting all generated files in the same directory would
+# otherwise cause performance problems for the file system.
+
+CREATE_SUBDIRS         = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# The default language is English, other supported languages are:
+# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional,
+# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German,
+# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English
+# messages), Korean, Korean-en, Latvian, Lithuanian, Norwegian, Macedonian,
+# Persian, Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrillic,
+# Slovak, Slovene, Spanish, Swedish, Ukrainian, and Vietnamese.
+
+OUTPUT_LANGUAGE        = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will
+# include brief member descriptions after the members that are listed in
+# the file and class documentation (similar to JavaDoc).
+# Set to NO to disable this.
+
+BRIEF_MEMBER_DESC      = YES
+
+# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend
+# the brief description of a member or function before the detailed description.
+# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+
+REPEAT_BRIEF           = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator
+# that is used to form the text in various listings. Each string
+# in this list, if found as the leading text of the brief description, will be
+# stripped from the text and the result after processing the whole list, is
+# used as the annotated text. Otherwise, the brief description is used as-is.
+# If left blank, the following values are used ("$name" is automatically
+# replaced with the name of the entity): "The $name class" "The $name widget"
+# "The $name file" "is" "provides" "specifies" "contains"
+# "represents" "a" "an" "the"
+
+ABBREVIATE_BRIEF       =
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# Doxygen will generate a detailed section even if there is only a brief
+# description.
+
+ALWAYS_DETAILED_SEC    = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+
+INLINE_INHERITED_MEMB  = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full
+# path before files name in the file list and in the header files. If set
+# to NO the shortest path that makes the file name unique will be used.
+
+FULL_PATH_NAMES        = YES
+
+# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag
+# can be used to strip a user-defined part of the path. Stripping is
+# only done if one of the specified strings matches the left-hand part of
+# the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the
+# path to strip. Note that you specify absolute paths here, but also
+# relative paths, which will be relative from the directory where doxygen is
+# started.
+
+STRIP_FROM_PATH        =
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of
+# the path mentioned in the documentation of a class, which tells
+# the reader which header file to include in order to use a class.
+# If left blank only the name of the header file containing the class
+# definition is used. Otherwise one should specify the include paths that
+# are normally passed to the compiler using the -I flag.
+
+STRIP_FROM_INC_PATH    =
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter
+# (but less readable) file names. This can be useful if your file system
+# doesn't support long names like on DOS, Mac, or CD-ROM.
+
+SHORT_NAMES            = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen
+# will interpret the first line (until the first dot) of a JavaDoc-style
+# comment as the brief description. If set to NO, the JavaDoc
+# comments will behave just like regular Qt-style comments
+# (thus requiring an explicit @brief command for a brief description.)
+
+JAVADOC_AUTOBRIEF      = NO
+
+# If the QT_AUTOBRIEF tag is set to YES then Doxygen will
+# interpret the first line (until the first dot) of a Qt-style
+# comment as the brief description. If set to NO, the comments
+# will behave just like regular Qt-style comments (thus requiring
+# an explicit \brief command for a brief description.)
+
+QT_AUTOBRIEF           = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen
+# treat a multi-line C++ special comment block (i.e. a block of //! or ///
+# comments) as a brief description. This used to be the default behaviour.
+# The new default is to treat a multi-line C++ comment block as a detailed
+# description. Set this tag to YES if you prefer the old behaviour instead.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented
+# member inherits the documentation from any documented member that it
+# re-implements.
+
+INHERIT_DOCS           = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce
+# a new page for each member. If set to NO, the documentation of a member will
+# be part of the file/class/namespace that contains it.
+
+SEPARATE_MEMBER_PAGES  = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab.
+# Doxygen uses this value to replace tabs by spaces in code fragments.
+
+TAB_SIZE               = 4
+
+# This tag can be used to specify a number of aliases that acts
+# as commands in the documentation. An alias has the form "name=value".
+# For example adding "sideeffect=\par Side Effects:\n" will allow you to
+# put the command \sideeffect (or @sideeffect) in the documentation, which
+# will result in a user-defined paragraph with heading "Side Effects:".
+# You can put \n's in the value part of an alias to insert newlines.
+
+ALIASES                =
+
+# This tag can be used to specify a number of word-keyword mappings (TCL only).
+# A mapping has the form "name=value". For example adding
+# "class=itcl::class" will allow you to use the command class in the
+# itcl::class meaning.
+
+TCL_SUBST              =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C
+# sources only. Doxygen will then generate output that is more tailored for C.
+# For instance, some of the names that are used will be different. The list
+# of all members will be omitted, etc.
+
+OPTIMIZE_OUTPUT_FOR_C  = NO
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java
+# sources only. Doxygen will then generate output that is more tailored for
+# Java. For instance, namespaces will be presented as packages, qualified
+# scopes will look different, etc.
+
+OPTIMIZE_OUTPUT_JAVA   = NO
+
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
+# sources only. Doxygen will then generate output that is more tailored for
+# Fortran.
+
+OPTIMIZE_FOR_FORTRAN   = NO
+
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
+# sources. Doxygen will then generate output that is tailored for
+# VHDL.
+
+OPTIMIZE_OUTPUT_VHDL   = NO
+
+# Doxygen selects the parser to use depending on the extension of the files it
+# parses. With this tag you can assign which parser to use for a given
+# extension. Doxygen has a built-in mapping, but you can override or extend it
+# using this tag. The format is ext=language, where ext is a file extension,
+# and language is one of the parsers supported by doxygen: IDL, Java,
+# Javascript, CSharp, C, C++, D, PHP, Objective-C, Python, Fortran, VHDL, C,
+# C++. For instance to make doxygen treat .inc files as Fortran files (default
+# is PHP), and .f files as C (default is Fortran), use: inc=Fortran f=C. Note
+# that for custom extensions you also need to set FILE_PATTERNS otherwise the
+# files are not read by doxygen.
+
+EXTENSION_MAPPING      =
+
+# If MARKDOWN_SUPPORT is enabled (the default) then doxygen pre-processes all
+# comments according to the Markdown format, which allows for more readable
+# documentation. See http://daringfireball.net/projects/markdown/ for details.
+# The output of markdown processing is further processed by doxygen, so you
+# can mix doxygen, HTML, and XML commands with Markdown formatting.
+# Disable only in case of backward compatibilities issues.
+
+MARKDOWN_SUPPORT       = YES
+
+# When enabled doxygen tries to link words that correspond to documented
+# classes, or namespaces to their corresponding documentation. Such a link can
+# be prevented in individual cases by by putting a % sign in front of the word
+# or globally by setting AUTOLINK_SUPPORT to NO.
+
+AUTOLINK_SUPPORT       = YES
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
+# to include (a tag file for) the STL sources as input, then you should
+# set this tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string); v.s.
+# func(std::string) {}). This also makes the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+
+BUILTIN_STL_SUPPORT    = NO
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+
+CPP_CLI_SUPPORT        = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only.
+# Doxygen will parse them like normal C++ but will assume all classes use public
+# instead of private inheritance when no explicit protection keyword is present.
+
+SIP_SUPPORT            = NO
+
+# For Microsoft's IDL there are propget and propput attributes to indicate
+# getter and setter methods for a property. Setting this option to YES (the
+# default) will make doxygen replace the get and set methods by a property in
+# the documentation. This will only work if the methods are indeed getting or
+# setting a simple type. If this is not the case, or you want to show the
+# methods anyway, you should set this option to NO.
+
+IDL_PROPERTY_SUPPORT   = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES, then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+
+DISTRIBUTE_GROUP_DOC   = NO
+
+# Set the SUBGROUPING tag to YES (the default) to allow class member groups of
+# the same type (for instance a group of public functions) to be put as a
+# subgroup of that type (e.g. under the Public Functions section). Set it to
+# NO to prevent subgrouping. Alternatively, this can be done per class using
+# the \nosubgrouping command.
+
+SUBGROUPING            = YES
+
+# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and
+# unions are shown inside the group in which they are included (e.g. using
+# @ingroup) instead of on a separate page (for HTML and Man pages) or
+# section (for LaTeX and RTF).
+
+INLINE_GROUPED_CLASSES = NO
+
+# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and
+# unions with only public data fields or simple typedef fields will be shown
+# inline in the documentation of the scope in which they are defined (i.e. file,
+# namespace, or group documentation), provided this scope is documented. If set
+# to NO (the default), structs, classes, and unions are shown on a separate
+# page (for HTML and Man pages) or section (for LaTeX and RTF).
+
+INLINE_SIMPLE_STRUCTS  = NO
+
+# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum
+# is documented as struct, union, or enum with the name of the typedef. So
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
+# with name TypeT. When disabled the typedef will appear as a member of a file,
+# namespace, or class. And the struct will be named TypeS. This can typically
+# be useful for C code in case the coding convention dictates that all compound
+# types are typedef'ed and only the typedef is referenced, never the tag name.
+
+TYPEDEF_HIDES_STRUCT   = NO
+
+# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This
+# cache is used to resolve symbols given their name and scope. Since this can
+# be an expensive process and often the same symbol appear multiple times in
+# the code, doxygen keeps a cache of pre-resolved symbols. If the cache is too
+# small doxygen will become slower. If the cache is too large, memory is wasted.
+# The cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid
+# range is 0..9, the default is 0, corresponding to a cache size of 2^16 = 65536
+# symbols.
+
+LOOKUP_CACHE_SIZE      = 0
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
+# documentation are documented, even if no documentation was available.
+# Private class members and static file members will be hidden unless
+# the EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES
+
+EXTRACT_ALL            = NO
+
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class
+# will be included in the documentation.
+
+EXTRACT_PRIVATE        = NO
+
+# If the EXTRACT_PACKAGE tag is set to YES all members with package or internal
+# scope will be included in the documentation.
+
+EXTRACT_PACKAGE        = NO
+
+# If the EXTRACT_STATIC tag is set to YES all static members of a file
+# will be included in the documentation.
+
+EXTRACT_STATIC         = NO
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs)
+# defined locally in source files will be included in the documentation.
+# If set to NO only classes defined in header files are included.
+
+EXTRACT_LOCAL_CLASSES  = YES
+
+# This flag is only useful for Objective-C code. When set to YES local
+# methods, which are defined in the implementation section but not in
+# the interface are included in the documentation.
+# If set to NO (the default) only methods in the interface are included.
+
+EXTRACT_LOCAL_METHODS  = NO
+
+# If this flag is set to YES, the members of anonymous namespaces will be
+# extracted and appear in the documentation as a namespace called
+# 'anonymous_namespace{file}', where file will be replaced with the base
+# name of the file that contains the anonymous namespace. By default
+# anonymous namespaces are hidden.
+
+EXTRACT_ANON_NSPACES   = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all
+# undocumented members of documented classes, files or namespaces.
+# If set to NO (the default) these members will be included in the
+# various overviews, but no documentation section is generated.
+# This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_MEMBERS     = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy.
+# If set to NO (the default) these classes will be included in the various
+# overviews. This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_CLASSES     = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all
+# friend (class|struct|union) declarations.
+# If set to NO (the default) these declarations will be included in the
+# documentation.
+
+HIDE_FRIEND_COMPOUNDS  = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any
+# documentation blocks found inside the body of a function.
+# If set to NO (the default) these blocks will be appended to the
+# function's detailed documentation block.
+
+HIDE_IN_BODY_DOCS      = NO
+
+# The INTERNAL_DOCS tag determines if documentation
+# that is typed after a \internal command is included. If the tag is set
+# to NO (the default) then the documentation will be excluded.
+# Set it to YES to include the internal documentation.
+
+INTERNAL_DOCS          = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate
+# file names in lower-case letters. If set to YES upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# and Mac users are advised to set this option to NO.
+
+CASE_SENSE_NAMES       = YES
+
+# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen
+# will show members with their full class and namespace scopes in the
+# documentation. If set to YES the scope will be hidden.
+
+HIDE_SCOPE_NAMES       = NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen
+# will put a list of the files that are included by a file in the documentation
+# of that file.
+
+SHOW_INCLUDE_FILES     = YES
+
+# If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen
+# will list include files with double quotes in the documentation
+# rather than with sharp brackets.
+
+FORCE_LOCAL_INCLUDES   = NO
+
+# If the INLINE_INFO tag is set to YES (the default) then a tag [inline]
+# is inserted in the documentation for inline members.
+
+INLINE_INFO            = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen
+# will sort the (detailed) documentation of file and class members
+# alphabetically by member name. If set to NO the members will appear in
+# declaration order.
+
+SORT_MEMBER_DOCS       = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the
+# brief documentation of file, namespace and class members alphabetically
+# by member name. If set to NO (the default) the members will appear in
+# declaration order.
+
+SORT_BRIEF_DOCS        = NO
+
+# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen
+# will sort the (brief and detailed) documentation of class members so that
+# constructors and destructors are listed first. If set to NO (the default)
+# the constructors will appear in the respective orders defined by
+# SORT_MEMBER_DOCS and SORT_BRIEF_DOCS.
+# This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO
+# and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO.
+
+SORT_MEMBERS_CTORS_1ST = NO
+
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the
+# hierarchy of group names into alphabetical order. If set to NO (the default)
+# the group names will appear in their defined order.
+
+SORT_GROUP_NAMES       = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be
+# sorted by fully-qualified names, including namespaces. If set to
+# NO (the default), the class list will be sorted only by class name,
+# not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the
+# alphabetical list.
+
+SORT_BY_SCOPE_NAME     = NO
+
+# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to
+# do proper type resolution of all parameters of a function it will reject a
+# match between the prototype and the implementation of a member function even
+# if there is only one candidate or it is obvious which candidate to choose
+# by doing a simple string match. By disabling STRICT_PROTO_MATCHING doxygen
+# will still accept a match between prototype and implementation in such cases.
+
+STRICT_PROTO_MATCHING  = NO
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or
+# disable (NO) the todo list. This list is created by putting \todo
+# commands in the documentation.
+
+GENERATE_TODOLIST      = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or
+# disable (NO) the test list. This list is created by putting \test
+# commands in the documentation.
+
+GENERATE_TESTLIST      = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or
+# disable (NO) the bug list. This list is created by putting \bug
+# commands in the documentation.
+
+GENERATE_BUGLIST       = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or
+# disable (NO) the deprecated list. This list is created by putting
+# \deprecated commands in the documentation.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional
+# documentation sections, marked by \if section-label ... \endif
+# and \cond section-label ... \endcond blocks.
+
+ENABLED_SECTIONS       =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines
+# the initial value of a variable or macro consists of for it to appear in
+# the documentation. If the initializer consists of more lines than specified
+# here it will be hidden. Use a value of 0 to hide initializers completely.
+# The appearance of the initializer of individual variables and macros in the
+# documentation can be controlled using \showinitializer or \hideinitializer
+# command in the documentation regardless of this setting.
+
+MAX_INITIALIZER_LINES  = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated
+# at the bottom of the documentation of classes and structs. If set to YES the
+# list will mention the files that were used to generate the documentation.
+
+SHOW_USED_FILES        = YES
+
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page.
+# This will remove the Files entry from the Quick Index and from the
+# Folder Tree View (if specified). The default is YES.
+
+SHOW_FILES             = YES
+
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the
+# Namespaces page.
+# This will remove the Namespaces entry from the Quick Index
+# and from the Folder Tree View (if specified). The default is YES.
+
+SHOW_NAMESPACES        = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from
+# the version control system). Doxygen will invoke the program by executing (via
+# popen()) the command <command> <input-file>, where <command> is the value of
+# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file
+# provided by doxygen. Whatever the program writes to standard output
+# is used as the file version. See the manual for examples.
+
+FILE_VERSION_FILTER    =
+
+# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed
+# by doxygen. The layout file controls the global structure of the generated
+# output files in an output format independent way. To create the layout file
+# that represents doxygen's defaults, run doxygen with the -l option.
+# You can optionally specify a file name after the option, if omitted
+# DoxygenLayout.xml will be used as the name of the layout file.
+
+LAYOUT_FILE            =
+
+# The CITE_BIB_FILES tag can be used to specify one or more bib files
+# containing the references data. This must be a list of .bib files. The
+# .bib extension is automatically appended if omitted. Using this command
+# requires the bibtex tool to be installed. See also
+# http://en.wikipedia.org/wiki/BibTeX for more info. For LaTeX the style
+# of the bibliography can be controlled using LATEX_BIB_STYLE. To use this
+# feature you need bibtex and perl available in the search path. Do not use
+# file names with spaces, bibtex cannot handle them.
+
+CITE_BIB_FILES         =
+
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated
+# by doxygen. Possible values are YES and NO. If left blank NO is used.
+
+QUIET                  = NO
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated by doxygen. Possible values are YES and NO. If left blank
+# NO is used.
+
+WARNINGS               = YES
+
+# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings
+# for undocumented members. If EXTRACT_ALL is set to YES then this flag will
+# automatically be disabled.
+
+WARN_IF_UNDOCUMENTED   = YES
+
+# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some
+# parameters in a documented function, or documenting parameters that
+# don't exist or using markup commands wrongly.
+
+WARN_IF_DOC_ERROR      = YES
+
+# The WARN_NO_PARAMDOC option can be enabled to get warnings for
+# functions that are documented, but have no documentation for their parameters
+# or return value. If set to NO (the default) doxygen will only warn about
+# wrong or incomplete parameter documentation, but not about the absence of
+# documentation.
+
+WARN_NO_PARAMDOC       = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that
+# doxygen can produce. The string should contain the $file, $line, and $text
+# tags, which will be replaced by the file and line number from which the
+# warning originated and the warning text. Optionally the format may contain
+# $version, which will be replaced by the version of the file (if it could
+# be obtained via FILE_VERSION_FILTER)
+
+WARN_FORMAT            = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning
+# and error messages should be written. If left blank the output is written
+# to stderr.
+
+WARN_LOGFILE           =
+
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag can be used to specify the files and/or directories that contain
+# documented source files. You may enter file names like "myfile.cpp" or
+# directories like "/usr/src/myproject". Separate the files or directories
+# with spaces.
+
+INPUT                  = ../include/mshr
+
+# This tag can be used to specify the character encoding of the source files
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is
+# also the default input encoding. Doxygen uses libiconv (or the iconv built
+# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for
+# the list of possible encodings.
+
+INPUT_ENCODING         = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank the following patterns are tested:
+# *.c *.cc *.cxx *.cpp *.c++ *.d *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh
+# *.hxx *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.dox *.py
+# *.f90 *.f *.for *.vhd *.vhdl
+
+FILE_PATTERNS          = *.h
+
+# The RECURSIVE tag can be used to turn specify whether or not subdirectories
+# should be searched for input files as well. Possible values are YES and NO.
+# If left blank NO is used.
+
+RECURSIVE              = NO
+
+# The EXCLUDE tag can be used to specify files and/or directories that should be
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+# Note that relative paths are relative to the directory from which doxygen is
+# run.
+
+EXCLUDE                =
+
+# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
+# directories that are symbolic links (a Unix file system feature) are excluded
+# from the input.
+
+EXCLUDE_SYMLINKS       = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories. Note that the wildcards are matched
+# against the file with absolute path, so to exclude all test directories
+# for example use the pattern */test/*
+
+EXCLUDE_PATTERNS       =
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
+# (namespaces, classes, functions, etc.) that should be excluded from the
+# output. The symbol name can be a fully qualified name, a word, or if the
+# wildcard * is used, a substring. Examples: ANamespace, AClass,
+# AClass::ANamespace, ANamespace::*Test
+
+EXCLUDE_SYMBOLS        =
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or
+# directories that contain example code fragments that are included (see
+# the \include command).
+
+EXAMPLE_PATH           =
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank all files are included.
+
+EXAMPLE_PATTERNS       =
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude
+# commands irrespective of the value of the RECURSIVE tag.
+# Possible values are YES and NO. If left blank NO is used.
+
+EXAMPLE_RECURSIVE      = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or
+# directories that contain image that are included in the documentation (see
+# the \image command).
+
+IMAGE_PATH             =
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command <filter> <input-file>, where <filter>
+# is the value of the INPUT_FILTER tag, and <input-file> is the name of an
+# input file. Doxygen will then use the output that the filter program writes
+# to standard output.
+# If FILTER_PATTERNS is specified, this tag will be ignored.
+# Note that the filter must not add or remove lines; it is applied before the
+# code is scanned, but not when the output code is generated. If lines are added
+# or removed, the anchors will not be placed correctly.
+
+INPUT_FILTER           =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis.
+# Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match.
+# The filters are a list of the form:
+# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further
+# info on how filters are used. If FILTER_PATTERNS is empty or if
+# non of the patterns match the file name, INPUT_FILTER is applied.
+
+FILTER_PATTERNS        =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER) will be used to filter the input files when producing source
+# files to browse (i.e. when SOURCE_BROWSER is set to YES).
+
+FILTER_SOURCE_FILES    = NO
+
+# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file
+# pattern. A pattern will override the setting for FILTER_PATTERN (if any)
+# and it is also possible to disable source filtering for a specific pattern
+# using *.ext= (so without naming a filter). This option only has effect when
+# FILTER_SOURCE_FILES is enabled.
+
+FILTER_SOURCE_PATTERNS =
+
+# If the USE_MD_FILE_AS_MAINPAGE tag refers to the name of a markdown file that
+# is part of the input, its contents will be placed on the main page
+# (index.html). This can be useful if you have a project on for instance GitHub
+# and want reuse the introduction page also for the doxygen output.
+
+USE_MDFILE_AS_MAINPAGE =
+
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will
+# be generated. Documented entities will be cross-referenced with these sources.
+# Note: To get rid of all source code in the generated output, make sure also
+# VERBATIM_HEADERS is set to NO.
+
+SOURCE_BROWSER         = NO
+
+# Setting the INLINE_SOURCES tag to YES will include the body
+# of functions and classes directly in the documentation.
+
+INLINE_SOURCES         = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct
+# doxygen to hide any special comment blocks from generated source code
+# fragments. Normal C, C++ and Fortran comments will always remain visible.
+
+STRIP_CODE_COMMENTS    = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES
+# then for each documented function all documented
+# functions referencing it will be listed.
+
+REFERENCED_BY_RELATION = NO
+
+# If the REFERENCES_RELATION tag is set to YES
+# then for each documented function all documented entities
+# called/used by that function will be listed.
+
+REFERENCES_RELATION    = NO
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES (the default)
+# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from
+# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will
+# link to the source code.
+# Otherwise they will link to the documentation.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code
+# will point to the HTML generated by the htags(1) tool instead of doxygen
+# built-in source browser. The htags tool is part of GNU's global source
+# tagging system (see http://www.gnu.org/software/global/global.html). You
+# will need version 4.8.6 or higher.
+
+USE_HTAGS              = NO
+
+# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen
+# will generate a verbatim copy of the header file for each class for
+# which an include is specified. Set to NO to disable this.
+
+VERBATIM_HEADERS       = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index
+# of all compounds will be generated. Enable this if the project
+# contains a lot of classes, structs, unions or interfaces.
+
+ALPHABETICAL_INDEX     = YES
+
+# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then
+# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns
+# in which this list will be split (can be a number in the range [1..20])
+
+COLS_IN_ALPHA_INDEX    = 5
+
+# In case all classes in a project start with a common prefix, all
+# classes will be put under the same header in the alphabetical index.
+# The IGNORE_PREFIX tag can be used to specify one or more prefixes that
+# should be ignored while generating the index headers.
+
+IGNORE_PREFIX          =
+
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES (the default) Doxygen will
+# generate HTML output.
+
+GENERATE_HTML          = NO
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `html' will be used as the default path.
+
+HTML_OUTPUT            = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for
+# each generated HTML page (for example: .htm,.php,.asp). If it is left blank
+# doxygen will generate files with .html extension.
+
+HTML_FILE_EXTENSION    = .html
+
+# The HTML_HEADER tag can be used to specify a personal HTML header for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard header. Note that when using a custom header you are responsible
+#  for the proper inclusion of any scripts and style sheets that doxygen
+# needs, which is dependent on the configuration options used.
+# It is advised to generate a default header using "doxygen -w html
+# header.html footer.html stylesheet.css YourConfigFile" and then modify
+# that header. Note that the header is subject to change so you typically
+# have to redo this when upgrading to a newer version of doxygen or when
+# changing the value of configuration settings such as GENERATE_TREEVIEW!
+
+HTML_HEADER            =
+
+# The HTML_FOOTER tag can be used to specify a personal HTML footer for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard footer.
+
+HTML_FOOTER            =
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading
+# style sheet that is used by each HTML page. It can be used to
+# fine-tune the look of the HTML output. If left blank doxygen will
+# generate a default style sheet. Note that it is recommended to use
+# HTML_EXTRA_STYLESHEET instead of this one, as it is more robust and this
+# tag will in the future become obsolete.
+
+HTML_STYLESHEET        =
+
+# The HTML_EXTRA_STYLESHEET tag can be used to specify an additional
+# user-defined cascading style sheet that is included after the standard
+# style sheets created by doxygen. Using this option one can overrule
+# certain style aspects. This is preferred over using HTML_STYLESHEET
+# since it does not replace the standard style sheet and is therefor more
+# robust against future updates. Doxygen will copy the style sheet file to
+# the output directory.
+
+HTML_EXTRA_STYLESHEET  =
+
+# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the HTML output directory. Note
+# that these files will be copied to the base HTML output directory. Use the
+# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these
+# files. In the HTML_STYLESHEET file, use the file name only. Also note that
+# the files will be copied as-is; there are no commands or markers available.
+
+HTML_EXTRA_FILES       =
+
+# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output.
+# Doxygen will adjust the colors in the style sheet and background images
+# according to this color. Hue is specified as an angle on a colorwheel,
+# see http://en.wikipedia.org/wiki/Hue for more information.
+# For instance the value 0 represents red, 60 is yellow, 120 is green,
+# 180 is cyan, 240 is blue, 300 purple, and 360 is red again.
+# The allowed range is 0 to 359.
+
+HTML_COLORSTYLE_HUE    = 220
+
+# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of
+# the colors in the HTML output. For a value of 0 the output will use
+# grayscales only. A value of 255 will produce the most vivid colors.
+
+HTML_COLORSTYLE_SAT    = 100
+
+# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to
+# the luminance component of the colors in the HTML output. Values below
+# 100 gradually make the output lighter, whereas values above 100 make
+# the output darker. The value divided by 100 is the actual gamma applied,
+# so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2,
+# and 100 does not change the gamma.
+
+HTML_COLORSTYLE_GAMMA  = 80
+
+# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
+# page will contain the date and time when the page was generated. Setting
+# this to NO can help when comparing the output of multiple runs.
+
+HTML_TIMESTAMP         = YES
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
+# documentation will contain sections that can be hidden and shown after the
+# page has loaded.
+
+HTML_DYNAMIC_SECTIONS  = NO
+
+# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of
+# entries shown in the various tree structured indices initially; the user
+# can expand and collapse entries dynamically later on. Doxygen will expand
+# the tree to such a level that at most the specified number of entries are
+# visible (unless a fully collapsed tree already exceeds this amount).
+# So setting the number of entries 1 will produce a full collapsed tree by
+# default. 0 is a special value representing an infinite number of entries
+# and will result in a full expanded tree by default.
+
+HTML_INDEX_NUM_ENTRIES = 100
+
+# If the GENERATE_DOCSET tag is set to YES, additional index files
+# will be generated that can be used as input for Apple's Xcode 3
+# integrated development environment, introduced with OSX 10.5 (Leopard).
+# To create a documentation set, doxygen will generate a Makefile in the
+# HTML output directory. Running make will produce the docset in that
+# directory and running "make install" will install the docset in
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find
+# it at startup.
+# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html
+# for more information.
+
+GENERATE_DOCSET        = NO
+
+# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the
+# feed. A documentation feed provides an umbrella under which multiple
+# documentation sets from a single provider (such as a company or product suite)
+# can be grouped.
+
+DOCSET_FEEDNAME        = "Doxygen generated docs"
+
+# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that
+# should uniquely identify the documentation set bundle. This should be a
+# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen
+# will append .docset to the name.
+
+DOCSET_BUNDLE_ID       = org.doxygen.Project
+
+# When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely
+# identify the documentation publisher. This should be a reverse domain-name
+# style string, e.g. com.mycompany.MyDocSet.documentation.
+
+DOCSET_PUBLISHER_ID    = org.doxygen.Publisher
+
+# The GENERATE_PUBLISHER_NAME tag identifies the documentation publisher.
+
+DOCSET_PUBLISHER_NAME  = Publisher
+
+# If the GENERATE_HTMLHELP tag is set to YES, additional index files
+# will be generated that can be used as input for tools like the
+# Microsoft HTML help workshop to generate a compiled HTML help file (.chm)
+# of the generated HTML documentation.
+
+GENERATE_HTMLHELP      = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can
+# be used to specify the file name of the resulting .chm file. You
+# can add a path in front of the file if the result should not be
+# written to the html output directory.
+
+CHM_FILE               =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can
+# be used to specify the location (absolute path including file name) of
+# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run
+# the HTML help compiler on the generated index.hhp.
+
+HHC_LOCATION           =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag
+# controls if a separate .chi index file is generated (YES) or that
+# it should be included in the master .chm file (NO).
+
+GENERATE_CHI           = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING
+# is used to encode HtmlHelp index (hhk), content (hhc) and project file
+# content.
+
+CHM_INDEX_ENCODING     =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag
+# controls whether a binary table of contents is generated (YES) or a
+# normal table of contents (NO) in the .chm file.
+
+BINARY_TOC             = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members
+# to the contents of the HTML help documentation and to the tree view.
+
+TOC_EXPAND             = NO
+
+# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
+# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated
+# that can be used as input for Qt's qhelpgenerator to generate a
+# Qt Compressed Help (.qch) of the generated HTML documentation.
+
+GENERATE_QHP           = NO
+
+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can
+# be used to specify the file name of the resulting .qch file.
+# The path specified is relative to the HTML output folder.
+
+QCH_FILE               =
+
+# The QHP_NAMESPACE tag specifies the namespace to use when generating
+# Qt Help Project output. For more information please see
+# http://doc.trolltech.com/qthelpproject.html#namespace
+
+QHP_NAMESPACE          = org.doxygen.Project
+
+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating
+# Qt Help Project output. For more information please see
+# http://doc.trolltech.com/qthelpproject.html#virtual-folders
+
+QHP_VIRTUAL_FOLDER     = doc
+
+# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to
+# add. For more information please see
+# http://doc.trolltech.com/qthelpproject.html#custom-filters
+
+QHP_CUST_FILTER_NAME   =
+
+# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the
+# custom filter to add. For more information please see
+# <a href="http://doc.trolltech.com/qthelpproject.html#custom-filters">
+# Qt Help Project / Custom Filters</a>.
+
+QHP_CUST_FILTER_ATTRS  =
+
+# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
+# project's
+# filter section matches.
+# <a href="http://doc.trolltech.com/qthelpproject.html#filter-attributes">
+# Qt Help Project / Filter Attributes</a>.
+
+QHP_SECT_FILTER_ATTRS  =
+
+# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can
+# be used to specify the location of Qt's qhelpgenerator.
+# If non-empty doxygen will try to run qhelpgenerator on the generated
+# .qhp file.
+
+QHG_LOCATION           =
+
+# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files
+#  will be generated, which together with the HTML files, form an Eclipse help
+# plugin. To install this plugin and make it available under the help contents
+# menu in Eclipse, the contents of the directory containing the HTML and XML
+# files needs to be copied into the plugins directory of eclipse. The name of
+# the directory within the plugins directory should be the same as
+# the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before
+# the help appears.
+
+GENERATE_ECLIPSEHELP   = NO
+
+# A unique identifier for the eclipse help plugin. When installing the plugin
+# the directory name containing the HTML and XML files should also have
+# this name.
+
+ECLIPSE_DOC_ID         = org.doxygen.Project
+
+# The DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs)
+# at top of each HTML page. The value NO (the default) enables the index and
+# the value YES disables it. Since the tabs have the same information as the
+# navigation tree you can set this option to NO if you already set
+# GENERATE_TREEVIEW to YES.
+
+DISABLE_INDEX          = NO
+
+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
+# structure should be generated to display hierarchical information.
+# If the tag value is set to YES, a side panel will be generated
+# containing a tree-like index structure (just like the one that
+# is generated for HTML Help). For this to work a browser that supports
+# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser).
+# Windows users are probably better off using the HTML help feature.
+# Since the tree basically has the same information as the tab index you
+# could consider to set DISABLE_INDEX to NO when enabling this option.
+
+GENERATE_TREEVIEW      = NO
+
+# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values
+# (range [0,1..20]) that doxygen will group on one line in the generated HTML
+# documentation. Note that a value of 0 will completely suppress the enum
+# values from appearing in the overview section.
+
+ENUM_VALUES_PER_LINE   = 4
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be
+# used to set the initial width (in pixels) of the frame in which the tree
+# is shown.
+
+TREEVIEW_WIDTH         = 250
+
+# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open
+# links to external symbols imported via tag files in a separate window.
+
+EXT_LINKS_IN_WINDOW    = NO
+
+# Use this tag to change the font size of Latex formulas included
+# as images in the HTML documentation. The default is 10. Note that
+# when you change the font size after a successful doxygen run you need
+# to manually remove any form_*.png images from the HTML output directory
+# to force them to be regenerated.
+
+FORMULA_FONTSIZE       = 10
+
+# Use the FORMULA_TRANPARENT tag to determine whether or not the images
+# generated for formulas are transparent PNGs. Transparent PNGs are
+# not supported properly for IE 6.0, but are supported on all modern browsers.
+# Note that when changing this option you need to delete any form_*.png files
+# in the HTML output before the changes have effect.
+
+FORMULA_TRANSPARENT    = YES
+
+# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax
+# (see http://www.mathjax.org) which uses client side Javascript for the
+# rendering instead of using prerendered bitmaps. Use this if you do not
+# have LaTeX installed or if you want to formulas look prettier in the HTML
+# output. When enabled you may also need to install MathJax separately and
+# configure the path to it using the MATHJAX_RELPATH option.
+
+USE_MATHJAX            = NO
+
+# When MathJax is enabled you can set the default output format to be used for
+# the MathJax output. Supported types are HTML-CSS, NativeMML (i.e. MathML) and
+# SVG. The default value is HTML-CSS, which is slower, but has the best
+# compatibility.
+
+MATHJAX_FORMAT         = HTML-CSS
+
+# When MathJax is enabled you need to specify the location relative to the
+# HTML output directory using the MATHJAX_RELPATH option. The destination
+# directory should contain the MathJax.js script. For instance, if the mathjax
+# directory is located at the same level as the HTML output directory, then
+# MATHJAX_RELPATH should be ../mathjax. The default value points to
+# the MathJax Content Delivery Network so you can quickly see the result without
+# installing MathJax.
+# However, it is strongly recommended to install a local
+# copy of MathJax from http://www.mathjax.org before deployment.
+
+MATHJAX_RELPATH        = http://cdn.mathjax.org/mathjax/latest
+
+# The MATHJAX_EXTENSIONS tag can be used to specify one or MathJax extension
+# names that should be enabled during MathJax rendering.
+
+MATHJAX_EXTENSIONS     =
+
+# The MATHJAX_CODEFILE tag can be used to specify a file with javascript
+# pieces of code that will be used on startup of the MathJax code.
+
+MATHJAX_CODEFILE       =
+
+# When the SEARCHENGINE tag is enabled doxygen will generate a search box
+# for the HTML output. The underlying search engine uses javascript
+# and DHTML and should work on any modern browser. Note that when using
+# HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets
+# (GENERATE_DOCSET) there is already a search function so this one should
+# typically be disabled. For large projects the javascript based search engine
+# can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution.
+
+SEARCHENGINE           = YES
+
+# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
+# implemented using a web server instead of a web client using Javascript.
+# There are two flavours of web server based search depending on the
+# EXTERNAL_SEARCH setting. When disabled, doxygen will generate a PHP script for
+# searching and an index file used by the script. When EXTERNAL_SEARCH is
+# enabled the indexing and searching needs to be provided by external tools.
+# See the manual for details.
+
+SERVER_BASED_SEARCH    = NO
+
+# When EXTERNAL_SEARCH is enabled doxygen will no longer generate the PHP
+# script for searching. Instead the search results are written to an XML file
+# which needs to be processed by an external indexer. Doxygen will invoke an
+# external search engine pointed to by the SEARCHENGINE_URL option to obtain
+# the search results. Doxygen ships with an example indexer (doxyindexer) and
+# search engine (doxysearch.cgi) which are based on the open source search
+# engine library Xapian. See the manual for configuration details.
+
+EXTERNAL_SEARCH        = NO
+
+# The SEARCHENGINE_URL should point to a search engine hosted by a web server
+# which will returned the search results when EXTERNAL_SEARCH is enabled.
+# Doxygen ships with an example search engine (doxysearch) which is based on
+# the open source search engine library Xapian. See the manual for configuration
+# details.
+
+SEARCHENGINE_URL       =
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed
+# search data is written to a file for indexing by an external tool. With the
+# SEARCHDATA_FILE tag the name of this file can be specified.
+
+SEARCHDATA_FILE        = searchdata.xml
+
+# When SERVER_BASED_SEARCH AND EXTERNAL_SEARCH are both enabled the
+# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is
+# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple
+# projects and redirect the results back to the right project.
+
+EXTERNAL_SEARCH_ID     =
+
+# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen
+# projects other than the one defined by this configuration file, but that are
+# all added to the same external search index. Each project needs to have a
+# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id
+# of to a relative location where the documentation can be found.
+# The format is: EXTRA_SEARCH_MAPPINGS = id1=loc1 id2=loc2 ...
+
+EXTRA_SEARCH_MAPPINGS  =
+
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will
+# generate Latex output.
+
+GENERATE_LATEX         = NO
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `latex' will be used as the default path.
+
+LATEX_OUTPUT           = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked. If left blank `latex' will be used as the default command name.
+# Note that when enabling USE_PDFLATEX this option is only used for
+# generating bitmaps for formulas in the HTML output, but not in the
+# Makefile that is written to the output directory.
+
+LATEX_CMD_NAME         = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to
+# generate index for LaTeX. If left blank `makeindex' will be used as the
+# default command name.
+
+MAKEINDEX_CMD_NAME     = makeindex
+
+# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact
+# LaTeX documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_LATEX          = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used
+# by the printer. Possible values are: a4, letter, legal and
+# executive. If left blank a4 will be used.
+
+PAPER_TYPE             = a4
+
+# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX
+# packages that should be included in the LaTeX output.
+
+EXTRA_PACKAGES         =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for
+# the generated latex document. The header should contain everything until
+# the first chapter. If it is left blank doxygen will generate a
+# standard header. Notice: only use this tag if you know what you are doing!
+
+LATEX_HEADER           =
+
+# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for
+# the generated latex document. The footer should contain everything after
+# the last chapter. If it is left blank doxygen will generate a
+# standard footer. Notice: only use this tag if you know what you are doing!
+
+LATEX_FOOTER           =
+
+# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images
+# or other source files which should be copied to the LaTeX output directory.
+# Note that the files will be copied as-is; there are no commands or markers
+# available.
+
+LATEX_EXTRA_FILES      =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated
+# is prepared for conversion to pdf (using ps2pdf). The pdf file will
+# contain links (just like the HTML output) instead of page references
+# This makes the output suitable for online browsing using a pdf viewer.
+
+PDF_HYPERLINKS         = YES
+
+# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of
+# plain latex in the generated Makefile. Set this option to YES to get a
+# higher quality PDF documentation.
+
+USE_PDFLATEX           = YES
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode.
+# command to the generated LaTeX files. This will instruct LaTeX to keep
+# running if errors occur, instead of asking the user for help.
+# This option is also used when generating formulas in HTML.
+
+LATEX_BATCHMODE        = NO
+
+# If LATEX_HIDE_INDICES is set to YES then doxygen will not
+# include the index chapters (such as File Index, Compound Index, etc.)
+# in the output.
+
+LATEX_HIDE_INDICES     = NO
+
+# If LATEX_SOURCE_CODE is set to YES then doxygen will include
+# source code with syntax highlighting in the LaTeX output.
+# Note that which sources are shown also depends on other settings
+# such as SOURCE_BROWSER.
+
+LATEX_SOURCE_CODE      = NO
+
+# The LATEX_BIB_STYLE tag can be used to specify the style to use for the
+# bibliography, e.g. plainnat, or ieeetr. The default style is "plain". See
+# http://en.wikipedia.org/wiki/BibTeX for more info.
+
+LATEX_BIB_STYLE        = plain
+
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output
+# The RTF output is optimized for Word 97 and may not look very pretty with
+# other RTF readers or editors.
+
+GENERATE_RTF           = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `rtf' will be used as the default path.
+
+RTF_OUTPUT             = rtf
+
+# If the COMPACT_RTF tag is set to YES Doxygen generates more compact
+# RTF documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_RTF            = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated
+# will contain hyperlink fields. The RTF file will
+# contain links (just like the HTML output) instead of page references.
+# This makes the output suitable for online browsing using WORD or other
+# programs which support those fields.
+# Note: wordpad (write) and others do not support links.
+
+RTF_HYPERLINKS         = NO
+
+# Load style sheet definitions from file. Syntax is similar to doxygen's
+# config file, i.e. a series of assignments. You only have to provide
+# replacements, missing definitions are set to their default value.
+
+RTF_STYLESHEET_FILE    =
+
+# Set optional variables used in the generation of an rtf document.
+# Syntax is similar to doxygen's config file.
+
+RTF_EXTENSIONS_FILE    =
+
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES (the default) Doxygen will
+# generate man pages
+
+GENERATE_MAN           = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `man' will be used as the default path.
+
+MAN_OUTPUT             = man
+
+# The MAN_EXTENSION tag determines the extension that is added to
+# the generated man pages (default is the subroutine's section .3)
+
+MAN_EXTENSION          = .3
+
+# If the MAN_LINKS tag is set to YES and Doxygen generates man output,
+# then it will generate one additional man file for each entity
+# documented in the real man page(s). These additional files
+# only source the real man page, but without them the man command
+# would be unable to find the correct page. The default is NO.
+
+MAN_LINKS              = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES Doxygen will
+# generate an XML file that captures the structure of
+# the code including all documentation.
+
+GENERATE_XML           = YES
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `xml' will be used as the default path.
+
+XML_OUTPUT             = xml
+
+# The XML_SCHEMA tag can be used to specify an XML schema,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_SCHEMA             =
+
+# The XML_DTD tag can be used to specify an XML DTD,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_DTD                =
+
+# If the XML_PROGRAMLISTING tag is set to YES Doxygen will
+# dump the program listings (including syntax highlighting
+# and cross-referencing information) to the XML output. Note that
+# enabling this will significantly increase the size of the XML output.
+
+XML_PROGRAMLISTING     = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the DOCBOOK output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_DOCBOOK tag is set to YES Doxygen will generate DOCBOOK files
+# that can be used to generate PDF.
+
+GENERATE_DOCBOOK       = NO
+
+# The DOCBOOK_OUTPUT tag is used to specify where the DOCBOOK pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be put in
+# front of it. If left blank docbook will be used as the default path.
+
+DOCBOOK_OUTPUT         = docbook
+
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will
+# generate an AutoGen Definitions (see autogen.sf.net) file
+# that captures the structure of the code including all
+# documentation. Note that this feature is still experimental
+# and incomplete at the moment.
+
+GENERATE_AUTOGEN_DEF   = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES Doxygen will
+# generate a Perl module file that captures the structure of
+# the code including all documentation. Note that this
+# feature is still experimental and incomplete at the
+# moment.
+
+GENERATE_PERLMOD       = NO
+
+# If the PERLMOD_LATEX tag is set to YES Doxygen will generate
+# the necessary Makefile rules, Perl scripts and LaTeX code to be able
+# to generate PDF and DVI output from the Perl module output.
+
+PERLMOD_LATEX          = NO
+
+# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be
+# nicely formatted so it can be parsed by a human reader.
+# This is useful
+# if you want to understand what is going on.
+# On the other hand, if this
+# tag is set to NO the size of the Perl module output will be much smaller
+# and Perl will parse it just the same.
+
+PERLMOD_PRETTY         = YES
+
+# The names of the make variables in the generated doxyrules.make file
+# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX.
+# This is useful so different doxyrules.make files included by the same
+# Makefile don't overwrite each other's variables.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will
+# evaluate all C-preprocessor directives found in the sources and include
+# files.
+
+ENABLE_PREPROCESSING   = YES
+
+# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro
+# names in the source code. If set to NO (the default) only conditional
+# compilation will be performed. Macro expansion can be done in a controlled
+# way by setting EXPAND_ONLY_PREDEF to YES.
+
+MACRO_EXPANSION        = NO
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES
+# then the macro expansion is limited to the macros specified with the
+# PREDEFINED and EXPAND_AS_DEFINED tags.
+
+EXPAND_ONLY_PREDEF     = NO
+
+# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files
+# pointed to by INCLUDE_PATH will be searched when a #include is found.
+
+SEARCH_INCLUDES        = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by
+# the preprocessor.
+
+INCLUDE_PATH           =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will
+# be used.
+
+INCLUDE_FILE_PATTERNS  =
+
+# The PREDEFINED tag can be used to specify one or more macro names that
+# are defined before the preprocessor is started (similar to the -D option of
+# gcc). The argument of the tag is a list of macros of the form: name
+# or name=definition (no spaces). If the definition and the = are
+# omitted =1 is assumed. To prevent a macro definition from being
+# undefined via #undef or recursively expanded use the := operator
+# instead of the = operator.
+
+PREDEFINED             =
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
+# this tag can be used to specify a list of macro names that should be expanded.
+# The macro definition that is found in the sources will be used.
+# Use the PREDEFINED tag if you want to use a different macro definition that
+# overrules the definition found in the source code.
+
+EXPAND_AS_DEFINED      =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then
+# doxygen's preprocessor will remove all references to function-like macros
+# that are alone on a line, have an all uppercase name, and do not end with a
+# semicolon, because these will confuse the parser if not removed.
+
+SKIP_FUNCTION_MACROS   = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES option can be used to specify one or more tagfiles. For each
+# tag file the location of the external documentation should be added. The
+# format of a tag file without this location is as follows:
+#
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+#
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where "loc1" and "loc2" can be relative or absolute paths
+# or URLs. Note that each tag file must have a unique name (where the name does
+# NOT include the path). If a tag file is not located in the directory in which
+# doxygen is run, you must also specify the path to the tagfile here.
+
+TAGFILES               =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create
+# a tag file that is based on the input files it reads.
+
+GENERATE_TAGFILE       =
+
+# If the ALLEXTERNALS tag is set to YES all external classes will be listed
+# in the class index. If set to NO only the inherited external classes
+# will be listed.
+
+ALLEXTERNALS           = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will
+# be listed.
+
+EXTERNAL_GROUPS        = YES
+
+# If the EXTERNAL_PAGES tag is set to YES all external pages will be listed
+# in the related pages index. If set to NO, only the current project's
+# pages will be listed.
+
+EXTERNAL_PAGES         = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of `which perl').
+
+PERL_PATH              = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will
+# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base
+# or super classes. Setting the tag to NO turns the diagrams off. Note that
+# this option also works with HAVE_DOT disabled, but it is recommended to
+# install and use dot, since it yields more powerful graphs.
+
+CLASS_DIAGRAMS         = YES
+
+# You can define message sequence charts within doxygen comments using the \msc
+# command. Doxygen will then run the mscgen tool (see
+# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the
+# documentation. The MSCGEN_PATH tag allows you to specify the directory where
+# the mscgen tool resides. If left empty the tool is assumed to be found in the
+# default search path.
+
+MSCGEN_PATH            =
+
+# If set to YES, the inheritance and collaboration graphs will hide
+# inheritance and usage relations if the target is undocumented
+# or is not a class.
+
+HIDE_UNDOC_RELATIONS   = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz, a graph visualization
+# toolkit from AT&T and Lucent Bell Labs. The other options in this section
+# have no effect if this option is set to NO (the default)
+
+HAVE_DOT               = NO
+
+# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is
+# allowed to run in parallel. When set to 0 (the default) doxygen will
+# base this on the number of processors available in the system. You can set it
+# explicitly to a value larger than 0 to get control over the balance
+# between CPU load and processing speed.
+
+DOT_NUM_THREADS        = 0
+
+# By default doxygen will use the Helvetica font for all dot files that
+# doxygen generates. When you want a differently looking font you can specify
+# the font name using DOT_FONTNAME. You need to make sure dot is able to find
+# the font, which can be done by putting it in a standard location or by setting
+# the DOTFONTPATH environment variable or by setting DOT_FONTPATH to the
+# directory containing the font.
+
+DOT_FONTNAME           = Helvetica
+
+# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs.
+# The default size is 10pt.
+
+DOT_FONTSIZE           = 10
+
+# By default doxygen will tell dot to use the Helvetica font.
+# If you specify a different font using DOT_FONTNAME you can use DOT_FONTPATH to
+# set the path where dot can find it.
+
+DOT_FONTPATH           =
+
+# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect inheritance relations. Setting this tag to YES will force the
+# CLASS_DIAGRAMS tag to NO.
+
+CLASS_GRAPH            = YES
+
+# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect implementation dependencies (inheritance, containment, and
+# class references variables) of the class with other documented classes.
+
+COLLABORATION_GRAPH    = YES
+
+# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for groups, showing the direct groups dependencies
+
+GROUP_GRAPHS           = YES
+
+# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+
+UML_LOOK               = NO
+
+# If the UML_LOOK tag is enabled, the fields and methods are shown inside
+# the class node. If there are many fields or methods and many nodes the
+# graph may become too big to be useful. The UML_LIMIT_NUM_FIELDS
+# threshold limits the number of items for each type to make the size more
+# manageable. Set this to 0 for no limit. Note that the threshold may be
+# exceeded by 50% before the limit is enforced.
+
+UML_LIMIT_NUM_FIELDS   = 10
+
+# If set to YES, the inheritance and collaboration graphs will show the
+# relations between templates and their instances.
+
+TEMPLATE_RELATIONS     = NO
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT
+# tags are set to YES then doxygen will generate a graph for each documented
+# file showing the direct and indirect include dependencies of the file with
+# other documented files.
+
+INCLUDE_GRAPH          = YES
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and
+# HAVE_DOT tags are set to YES then doxygen will generate a graph for each
+# documented header file showing the documented files that directly or
+# indirectly include this file.
+
+INCLUDED_BY_GRAPH      = YES
+
+# If the CALL_GRAPH and HAVE_DOT options are set to YES then
+# doxygen will generate a call dependency graph for every global function
+# or class method. Note that enabling this option will significantly increase
+# the time of a run. So in most cases it will be better to enable call graphs
+# for selected functions only using the \callgraph command.
+
+CALL_GRAPH             = NO
+
+# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then
+# doxygen will generate a caller dependency graph for every global function
+# or class method. Note that enabling this option will significantly increase
+# the time of a run. So in most cases it will be better to enable caller
+# graphs for selected functions only using the \callergraph command.
+
+CALLER_GRAPH           = NO
+
+# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen
+# will generate a graphical hierarchy of all classes instead of a textual one.
+
+GRAPHICAL_HIERARCHY    = YES
+
+# If the DIRECTORY_GRAPH and HAVE_DOT tags are set to YES
+# then doxygen will show the dependencies a directory has on other directories
+# in a graphical way. The dependency relations are determined by the #include
+# relations between the files in the directories.
+
+DIRECTORY_GRAPH        = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot. Possible values are svg, png, jpg, or gif.
+# If left blank png will be used. If you choose svg you need to set
+# HTML_FILE_EXTENSION to xhtml in order to make the SVG files
+# visible in IE 9+ (other browsers do not have this requirement).
+
+DOT_IMAGE_FORMAT       = png
+
+# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to
+# enable generation of interactive SVG images that allow zooming and panning.
+# Note that this requires a modern browser other than Internet Explorer.
+# Tested and working are Firefox, Chrome, Safari, and Opera. For IE 9+ you
+# need to set HTML_FILE_EXTENSION to xhtml in order to make the SVG files
+# visible. Older versions of IE do not have SVG support.
+
+INTERACTIVE_SVG        = NO
+
+# The tag DOT_PATH can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+
+DOT_PATH               =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the
+# \dotfile command).
+
+DOTFILE_DIRS           =
+
+# The MSCFILE_DIRS tag can be used to specify one or more directories that
+# contain msc files that are included in the documentation (see the
+# \mscfile command).
+
+MSCFILE_DIRS           =
+
+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of
+# nodes that will be shown in the graph. If the number of nodes in a graph
+# becomes larger than this value, doxygen will truncate the graph, which is
+# visualized by representing a node as a red box. Note that doxygen if the
+# number of direct children of the root node in a graph is already larger than
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note
+# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+
+DOT_GRAPH_MAX_NODES    = 50
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the
+# graphs generated by dot. A depth value of 3 means that only nodes reachable
+# from the root by following a path via at most 3 edges will be shown. Nodes
+# that lay further from the root node will be omitted. Note that setting this
+# option to 1 or 2 may greatly reduce the computation time needed for large
+# code bases. Also note that the size of a graph can be further restricted by
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+
+MAX_DOT_GRAPH_DEPTH    = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, because dot on Windows does not
+# seem to support this out of the box. Warning: Depending on the platform used,
+# enabling this option may lead to badly anti-aliased labels on the edges of
+# a graph (i.e. they become hard to read).
+
+DOT_TRANSPARENT        = NO
+
+# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10)
+# support this, this feature is disabled by default.
+
+DOT_MULTI_TARGETS      = YES
+
+# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will
+# generate a legend page explaining the meaning of the various boxes and
+# arrows in the dot generated graphs.
+
+GENERATE_LEGEND        = YES
+
+# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will
+# remove the intermediate dot files that are used to generate
+# the various graphs.
+
+DOT_CLEANUP            = YES
diff --git a/doc/generate_rst.py b/doc/generate_rst.py
new file mode 100644 (file)
index 0000000..d9c55c6
--- /dev/null
@@ -0,0 +1,312 @@
+# This script generates a set of .md (MarkDown) files
+# from xml files generated by doxygen.
+
+# The script does two sweeps. 
+# First all xml are parsed and stored in dictionaries
+# with their id as key.
+# The second sweep generates one page (a markdown file) pr class
+# and collects the information for main page which is generated
+# at the end.
+
+import sys, os
+from xml.etree import ElementTree
+import subprocess
+
+input_dir = os.path.abspath(sys.argv[1])
+output_dir = os.path.abspath(sys.argv[2])
+
+if not os.path.exists(output_dir) :
+    os.mkdir(output_dir)
+
+if not os.path.exists(os.path.join(output_dir, "API")) :
+    os.mkdir(os.path.join(output_dir, "API"))
+
+
+# searches through the detaileddescription section
+# for parameter documentation with the same name
+# and returns it
+def get_parameter_documentation(functiondefinition, declname) :
+    details = functiondefinition.find("detaileddescription")
+    para = details.find("para")
+    if para is not None :
+        paralist = para.find("parameterlist")
+        if paralist is not None :
+            items = paralist.findall("parameteritem")
+            for parameteritem in items :
+                name = parameteritem.find("parameternamelist").find("parametername").text.strip()
+
+                if name == declname.strip() :
+                    # We got the right parameter
+                    description = parameteritem.find("parameterdescription")
+                    if description is not None :
+                        para = description.find("para")
+                        if para is not None and para.text is not None:
+                            return para.text.strip()
+                        else :
+                            return ""
+    return ""
+
+def get_extra_data(classdefinition) :
+    details = classdefinition.find("detaileddescription")
+    paragraphs = details.findall("para")
+    for para in paragraphs :
+        text = para.text.strip()
+        if text.startswith("{") and text.endswith("}") :
+            return eval(text)
+    return {}
+
+print("Reading files from %s" % input_dir)
+
+# save all the classes as dictionary with doxygens id as key.
+cls = {}
+
+# First sweep
+for filename in os.listdir(input_dir) :
+    if not os.path.isfile(os.path.join(input_dir, filename)) :
+        continue
+
+    if not filename.endswith(".xml") :
+        continue
+
+    # Only classes are documented now
+    if not filename.startswith("class") :
+        continue
+
+    # print("Processing %s" % filename)
+
+    root = ElementTree.parse(os.path.join(input_dir, filename)).getroot()
+    assert root.tag == "doxygen"
+    assert len(root) == 1
+
+    class_def = root.find("compounddef")
+    assert not cls.has_key(class_def.attrib["id"])
+
+    class_name = class_def.find("compoundname").text
+    outfilename_base = class_name if not class_name.startswith("mshr::") else class_name[6:]
+    briefdescription = class_def.find("briefdescription")
+    # Description should at most one paragraph
+    assert (len(briefdescription) <= 1) 
+    briefdescription = briefdescription.find("para").text if briefdescription.find("para") is not None else ""
+    
+    data = {'filename'    : outfilename_base,
+            'description' : briefdescription.strip() }
+
+    extra_data = get_extra_data(class_def)
+    data.update(extra_data)
+
+    cls[class_def.attrib["id"]] = (class_def, data)
+
+longest_class_name  = max([ len(c[0].find("compoundname").text) for k, c in cls.iteritems()])
+longest_description = max([ len(c[1]["description"]) for k, c in cls.iteritems()])
+
+primitives2d = []
+primitives3d = []
+operators    = []
+others       = []
+
+
+# Second sweep
+for k,c in cls.iteritems() :
+    theclass = c[0]
+    classname = theclass.find("compoundname").text
+    classid = theclass.attrib["id"]
+    print "Processing "+classname
+
+    classpage = []
+    category = others
+
+    # inheritance
+    # also decides which category the class belong to
+    inheritance = theclass.find("inheritancegraph")
+    if inheritance is not None :
+        inheritancenodes = {}
+        nodes = inheritance.findall("node")
+
+        # collect all inheritance nodes in a dictionary with the refid (which is not the same
+        # as the class id as key
+        myid = False
+        for x in nodes : 
+            inheritancenodes[x.attrib["id"]] = x
+            link = x.find("link")
+            
+            # save the refid to self
+            if link is not None and link.attrib["refid"] == classid :
+                myid = x.attrib["id"]
+
+        # traverse the tree from self through all super classes
+        current = inheritancenodes[myid]
+        current = inheritancenodes[current.find("childnode").attrib["refid"]]
+        inheritance_list = []
+        while current is not None :
+            label = current.find("label").text
+            if label == "mshr::CSGPrimitive2D"   : category = primitives2d
+            elif label == "mshr::CSGPrimitive3D" : category = primitives3d
+            elif label == "mshr::CSGOperator"    : category = operators
+
+            ref = current.find("link")
+
+            if ref is not None and cls.has_key(ref.attrib["refid"]) :
+                inheritance_list.append("[%s](%s)" % (current.find("label").text.strip(),
+                                                      cls[ref.attrib["refid"]][1]["filename"]))
+            else :
+                inheritance_list.append(x.find("label").text.strip())
+
+            child = current.find("childnode")
+            if child is not None :
+                current = inheritancenodes[child.attrib["refid"]]
+            else :
+                current = None
+
+
+        inheritance_list.reverse()
+        classpage.append("_" + " > ".join(inheritance_list) + "_")
+        classpage.append("\n\n")
+
+    icon_txt = " |"
+    if c[1].has_key("small-icon") :
+        icon_txt = "![%s icon](icons/%s)|" % (classname, c[1]["small-icon"])
+
+    print "Appending to category"
+    category.append("%s[%s](API/%s)|%s|\n" % (icon_txt,
+                                              classname.ljust(longest_class_name),
+                                              c[1]["filename"],
+                                              c[1]["description"].ljust(longest_description)))
+
+
+
+    classpage.append("# %s\n\n" % (classname))
+    classpage.append("_%s_\n\n" % c[1]["description"])
+
+    classpage.append("#### Public functions\n\n")
+    for member in c[0].findall("sectiondef") :
+
+        # Only public functions are considered part of the public API for now
+        if member.attrib["kind"] != "public-func" :
+            continue
+
+        for definition in member.findall("memberdef") :
+            membername = definition.find("name").text
+
+            argsstr    = definition.find("argsstring").text
+            description = definition.find("briefdescription").find("para")
+            description = description.text.strip() if description is not None else ""
+
+            returntype = definition.find("type").text
+            if returntype is not None and len(returntype) > 0 :
+                returntype = returntype+" "
+            if returntype is None :
+                returntype = ""
+
+            # name
+            classpage.append("%s**%s**%s\n" % (returntype, membername, argsstr))
+
+            # description
+            if description :
+                classpage.append("> _%s_\n" % description)
+
+            classpage.append("\n")
+
+            param_table = []
+
+            # table of parameters
+            for param in definition.findall("param") :
+                declname = param.find("declname").text
+                paramtype = param.find("type").text
+                if paramtype is None :
+                    paramtype = ""
+
+                desc = get_parameter_documentation(definition, declname)
+                param_table.append( (declname, paramtype, desc) )
+                
+            if len(param_table) > 0 :
+                longest_param_name = max([len(x[0]) for x in param_table])
+                longest_param_type = max([len(x[1]) for x in param_table])
+                longest_param_desc = max([len(x[2]) for x in param_table])
+
+                longest_param_name = max(longest_param_name, len("Parameters"))
+
+                classpage.append("> %s|%s|%s\n" % ("Parameters".ljust(longest_param_name),
+                                                   " "*longest_param_type,
+                                                   " "*longest_param_desc))
+                classpage.append("> %s|%s|%s\n" % ("-"*longest_param_name,
+                                                   "-"*longest_param_type,
+                                                   "-"*longest_param_desc))
+
+                for p in param_table :
+                    classpage.append("> %s|%s|%s\n" % (p[0].ljust(longest_param_name),
+                                                       p[1].ljust(longest_param_type),
+                                                       p[2].ljust(longest_param_desc)))
+
+                classpage.append("\n")
+                
+
+    with open(os.path.join(output_dir, "API", c[1]["filename"]+".md"), "w") as f:
+        f.write("".join(classpage))
+        f.close()
+
+
+
+# Create the main page for 
+mainpage = ["""
+
+# API reference
+
+"""]
+
+mainpage.append("- |%s|%s|\n" % ("2D primitives".ljust(longest_class_name),
+                                "Description".ljust(longest_description)))
+
+mainpage.append("--|%s|%s|\n" % ( ":".ljust(longest_class_name, "-"),
+                                 ":".ljust(longest_description, "-")))
+
+
+################# Append 2D primitives
+#mainpage.append("%s|%s|\n" % ("**2D primitives**".ljust(longest_class_name),
+#                              "".ljust(longest_description)))
+
+# mainpage.append("%s|%s|\n" % ( ":".ljust(longest_class_name, "-"),
+#                                ":".ljust(longest_description, "-")))
+
+mainpage.append("".join(primitives2d))
+#mainpage.append("\n\n")
+
+################ Append 3D primitives
+mainpage.append("- |%s|%s|\n" % ("**3D primitives**".ljust(longest_class_name),
+                              " "*longest_description))
+
+# mainpage.append("%s|%s|\n" % ( ":".ljust(longest_class_name, "-"),
+#                                ":".ljust(longest_description, "-")))
+
+mainpage.append("".join(primitives3d))
+#mainpage.append("\n\n")
+
+############### Append operators
+mainpage.append("- |%s|%s|\n" % ("**Operators**".ljust(longest_class_name),
+                              " "*longest_description))
+
+# mainpage.append("%s|%s|\n" % ( ":".ljust(longest_class_name, "-"),
+#                               ":".ljust(longest_description, "-")))
+
+mainpage.append("".join(operators))
+# mainpage.append("\n\n")
+
+############### Append other classes
+mainpage.append("- |%s|%s|\n" % ("**Other classes**".ljust(longest_class_name),
+                              " "*longest_description))
+
+# mainpage.append("%s|%s|\n" % ( ":".ljust(longest_class_name, "-"),
+#                               ":".ljust(longest_description, "-")))
+
+mainpage.append("".join(others))
+mainpage.append("\n\n")
+
+# Read the current revision from git
+revision_info = subprocess.check_output(["git", "log", "--pretty=format:'%ad %H'", "-1"]).strip("'")
+mainpage.append("_Generated from revision: {}. Please don't edit these files manually._\n".format(revision_info))
+
+
+
+with open(os.path.join(output_dir, "API.md"), "w") as f:
+    f.write("".join(mainpage))
+    f.close()
+
diff --git a/doc/sphinx/Makefile b/doc/sphinx/Makefile
new file mode 100644 (file)
index 0000000..06a261d
--- /dev/null
@@ -0,0 +1,216 @@
+# Makefile for Sphinx documentation
+#
+
+# You can set these variables from the command line.
+SPHINXOPTS    =
+SPHINXBUILD   = sphinx-build
+PAPER         =
+BUILDDIR      = build
+
+# User-friendly check for sphinx-build
+ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1)
+$(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/)
+endif
+
+# Internal variables.
+PAPEROPT_a4     = -D latex_paper_size=a4
+PAPEROPT_letter = -D latex_paper_size=letter
+ALLSPHINXOPTS   = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source
+# the i18n builder cannot share the environment and doctrees with the others
+I18NSPHINXOPTS  = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source
+
+.PHONY: help
+help:
+       @echo "Please use \`make <target>' where <target> is one of"
+       @echo "  html       to make standalone HTML files"
+       @echo "  dirhtml    to make HTML files named index.html in directories"
+       @echo "  singlehtml to make a single large HTML file"
+       @echo "  pickle     to make pickle files"
+       @echo "  json       to make JSON files"
+       @echo "  htmlhelp   to make HTML files and a HTML help project"
+       @echo "  qthelp     to make HTML files and a qthelp project"
+       @echo "  applehelp  to make an Apple Help Book"
+       @echo "  devhelp    to make HTML files and a Devhelp project"
+       @echo "  epub       to make an epub"
+       @echo "  latex      to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
+       @echo "  latexpdf   to make LaTeX files and run them through pdflatex"
+       @echo "  latexpdfja to make LaTeX files and run them through platex/dvipdfmx"
+       @echo "  text       to make text files"
+       @echo "  man        to make manual pages"
+       @echo "  texinfo    to make Texinfo files"
+       @echo "  info       to make Texinfo files and run them through makeinfo"
+       @echo "  gettext    to make PO message catalogs"
+       @echo "  changes    to make an overview of all changed/added/deprecated items"
+       @echo "  xml        to make Docutils-native XML files"
+       @echo "  pseudoxml  to make pseudoxml-XML files for display purposes"
+       @echo "  linkcheck  to check all external links for integrity"
+       @echo "  doctest    to run all doctests embedded in the documentation (if enabled)"
+       @echo "  coverage   to run coverage check of the documentation (if enabled)"
+
+.PHONY: clean
+clean:
+       rm -rf $(BUILDDIR)/*
+
+.PHONY: html
+html:
+       $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
+       @echo
+       @echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
+
+.PHONY: dirhtml
+dirhtml:
+       $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
+       @echo
+       @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
+
+.PHONY: singlehtml
+singlehtml:
+       $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
+       @echo
+       @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
+
+.PHONY: pickle
+pickle:
+       $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
+       @echo
+       @echo "Build finished; now you can process the pickle files."
+
+.PHONY: json
+json:
+       $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
+       @echo
+       @echo "Build finished; now you can process the JSON files."
+
+.PHONY: htmlhelp
+htmlhelp:
+       $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
+       @echo
+       @echo "Build finished; now you can run HTML Help Workshop with the" \
+             ".hhp project file in $(BUILDDIR)/htmlhelp."
+
+.PHONY: qthelp
+qthelp:
+       $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
+       @echo
+       @echo "Build finished; now you can run "qcollectiongenerator" with the" \
+             ".qhcp project file in $(BUILDDIR)/qthelp, like this:"
+       @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/mshr.qhcp"
+       @echo "To view the help file:"
+       @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/mshr.qhc"
+
+.PHONY: applehelp
+applehelp:
+       $(SPHINXBUILD) -b applehelp $(ALLSPHINXOPTS) $(BUILDDIR)/applehelp
+       @echo
+       @echo "Build finished. The help book is in $(BUILDDIR)/applehelp."
+       @echo "N.B. You won't be able to view it unless you put it in" \
+             "~/Library/Documentation/Help or install it in your application" \
+             "bundle."
+
+.PHONY: devhelp
+devhelp:
+       $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
+       @echo
+       @echo "Build finished."
+       @echo "To view the help file:"
+       @echo "# mkdir -p $$HOME/.local/share/devhelp/mshr"
+       @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/mshr"
+       @echo "# devhelp"
+
+.PHONY: epub
+epub:
+       $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
+       @echo
+       @echo "Build finished. The epub file is in $(BUILDDIR)/epub."
+
+.PHONY: latex
+latex:
+       $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
+       @echo
+       @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
+       @echo "Run \`make' in that directory to run these through (pdf)latex" \
+             "(use \`make latexpdf' here to do that automatically)."
+
+.PHONY: latexpdf
+latexpdf:
+       $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
+       @echo "Running LaTeX files through pdflatex..."
+       $(MAKE) -C $(BUILDDIR)/latex all-pdf
+       @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
+
+.PHONY: latexpdfja
+latexpdfja:
+       $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
+       @echo "Running LaTeX files through platex and dvipdfmx..."
+       $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja
+       @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
+
+.PHONY: text
+text:
+       $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
+       @echo
+       @echo "Build finished. The text files are in $(BUILDDIR)/text."
+
+.PHONY: man
+man:
+       $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
+       @echo
+       @echo "Build finished. The manual pages are in $(BUILDDIR)/man."
+
+.PHONY: texinfo
+texinfo:
+       $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
+       @echo
+       @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
+       @echo "Run \`make' in that directory to run these through makeinfo" \
+             "(use \`make info' here to do that automatically)."
+
+.PHONY: info
+info:
+       $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
+       @echo "Running Texinfo files through makeinfo..."
+       make -C $(BUILDDIR)/texinfo info
+       @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
+
+.PHONY: gettext
+gettext:
+       $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
+       @echo
+       @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
+
+.PHONY: changes
+changes:
+       $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
+       @echo
+       @echo "The overview file is in $(BUILDDIR)/changes."
+
+.PHONY: linkcheck
+linkcheck:
+       $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
+       @echo
+       @echo "Link check complete; look for any errors in the above output " \
+             "or in $(BUILDDIR)/linkcheck/output.txt."
+
+.PHONY: doctest
+doctest:
+       $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
+       @echo "Testing of doctests in the sources finished, look at the " \
+             "results in $(BUILDDIR)/doctest/output.txt."
+
+.PHONY: coverage
+coverage:
+       $(SPHINXBUILD) -b coverage $(ALLSPHINXOPTS) $(BUILDDIR)/coverage
+       @echo "Testing of coverage in the sources finished, look at the " \
+             "results in $(BUILDDIR)/coverage/python.txt."
+
+.PHONY: xml
+xml:
+       $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml
+       @echo
+       @echo "Build finished. The XML files are in $(BUILDDIR)/xml."
+
+.PHONY: pseudoxml
+pseudoxml:
+       $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml
+       @echo
+       @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml."
diff --git a/doc/sphinx/README b/doc/sphinx/README
new file mode 100644 (file)
index 0000000..049ff11
--- /dev/null
@@ -0,0 +1,20 @@
+====================
+Sphinx documentation
+====================
+
+mshr is documented using Sphinx and reStructured text. The
+documentation is hosted at http://fenics-mshr.readthedocs.org/. The
+online documentation is automatically updated upon pushes to the mshr
+master branch.
+
+
+Building the documentation locally
+==================================
+
+The HTML documentation can be built locally using::
+
+    make html
+
+In order for changes in the docstring to be propagated to the html
+pages, mshr must be installed anew. In other words, sphinx reads the
+docstrings from the installed code, not the source code.
diff --git a/doc/sphinx/source/ChangeLog.rst b/doc/sphinx/source/ChangeLog.rst
new file mode 120000 (symlink)
index 0000000..6b0be0e
--- /dev/null
@@ -0,0 +1 @@
+../../../ChangeLog.rst
\ No newline at end of file
diff --git a/doc/sphinx/source/conf.py b/doc/sphinx/source/conf.py
new file mode 100644 (file)
index 0000000..8b50642
--- /dev/null
@@ -0,0 +1,342 @@
+# -*- coding: utf-8 -*-
+#
+# mshr documentation build configuration file, created by
+# sphinx-quickstart on Thu Aug 11 13:48:10 2016.
+#
+# This file is execfile()d with the current directory set to its
+# containing dir.
+#
+# Note that not all possible configuration values are present in this
+# autogenerated file.
+#
+# All configuration values have a default; values that are commented out
+# serve to show the default.
+
+from __future__ import print_function
+import sys
+import os
+
+
+def grep_ver(verstr, lines):
+    """Based on a loose criterion find a string of type::
+
+        set(MSHR_VERSION_verstr number)
+
+    or::
+
+        set(MSHR_VERSION_verstr "number")
+
+    in provided iterable of strings and return `number`."""
+
+    left = "set(MSHR_VERSION_{}".format(verstr)
+    right = ")"
+
+    line, = [l for l in lines if left in l]
+    line = line.strip()  # strip whitespace
+
+    begin, sep, end = line.partition(left)
+    assert len(begin) == 0 and sep == left
+    line = end
+
+    begin, sep, end = line.partition(right)
+    assert len(end) == 0 and sep == right
+    line = begin
+
+    line = line.strip(' \'"')  # strip whitespace and quotes
+    int(line)  # check integer
+
+    return line
+
+
+def get_mshr_version():
+    "Parse `CMakeLists.txt` for mshr version and return as string"
+    filepath = os.path.join(os.path.pardir, os.path.pardir, os.path.pardir,
+                            "CMakeLists.txt")
+    with open(filepath, "r") as f:
+        lines = f.readlines()
+    major = grep_ver("MAJOR", lines)
+    minor = grep_ver("MINOR", lines)
+    micro = grep_ver("MICRO", lines)
+    release = grep_ver("RELEASE", lines)
+    if release == "1":
+        ver_str = ".".join((major, minor, micro))
+    else:
+        assert release == "0"
+        ver_str = ".".join((major, minor, micro, "dev0"))
+    print("Detected mshr version '{}'".format(ver_str))
+    return ver_str
+
+
+# If extensions (or modules to document with autodoc) are in another directory,
+# add these directories to sys.path here. If the directory is relative to the
+# documentation root, use os.path.abspath to make it absolute, like shown here.
+#sys.path.insert(0, os.path.abspath('.'))
+
+# -- General configuration ------------------------------------------------
+
+# If your documentation needs a minimal Sphinx version, state it here.
+#needs_sphinx = '1.0'
+
+# Add any Sphinx extension module names here, as strings. They can be
+# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
+# ones.
+extensions = [
+    'sphinx.ext.autodoc',
+    'sphinx.ext.doctest',
+    'sphinx.ext.coverage',
+    'sphinx.ext.mathjax',
+    'sphinx.ext.viewcode',
+]
+
+# Add any paths that contain templates here, relative to this directory.
+templates_path = ['_templates']
+
+# The suffix(es) of source filenames.
+# You can specify multiple suffix as a list of string:
+# source_suffix = ['.rst', '.md']
+source_suffix = '.rst'
+
+# The encoding of source files.
+#source_encoding = 'utf-8-sig'
+
+# The master toctree document.
+master_doc = 'index'
+
+# General information about the project.
+project = u'mshr'
+copyright = u'2016, FEniCS Project'
+author = u'FEniCS Project'
+
+# The version info for the project you're documenting, acts as replacement for
+# |version| and |release|, also used in various other places throughout the
+# built documents.
+#
+mshr_version = get_mshr_version()
+# The short X.Y version.
+version = mshr_version
+# The full version, including alpha/beta/rc tags.
+release = mshr_version
+
+# The language for content autogenerated by Sphinx. Refer to documentation
+# for a list of supported languages.
+#
+# This is also used if you do content translation via gettext catalogs.
+# Usually you set "language" from the command line for these cases.
+language = None
+
+# There are two options for replacing |today|: either, you set today to some
+# non-false value, then it is used:
+#today = ''
+# Else, today_fmt is used as the format for a strftime call.
+#today_fmt = '%B %d, %Y'
+
+# List of patterns, relative to source directory, that match files and
+# directories to ignore when looking for source files.
+exclude_patterns = []
+
+# The reST default role (used for this markup: `text`) to use for all
+# documents.
+#default_role = None
+
+# If true, '()' will be appended to :func: etc. cross-reference text.
+#add_function_parentheses = True
+
+# If true, the current module name will be prepended to all description
+# unit titles (such as .. function::).
+#add_module_names = True
+
+# If true, sectionauthor and moduleauthor directives will be shown in the
+# output. They are ignored by default.
+#show_authors = False
+
+# The name of the Pygments (syntax highlighting) style to use.
+pygments_style = 'sphinx'
+
+# A list of ignored prefixes for module index sorting.
+#modindex_common_prefix = []
+
+# If true, keep warnings as "system message" paragraphs in the built documents.
+#keep_warnings = False
+
+# If true, `todo` and `todoList` produce output, else they produce nothing.
+todo_include_todos = False
+
+
+# -- Options for HTML output ----------------------------------------------
+
+# The theme to use for HTML and HTML Help pages.  See the documentation for
+# a list of builtin themes.
+#html_theme = 'alabaster'
+
+# Theme options are theme-specific and customize the look and feel of a theme
+# further.  For a list of options available for each theme, see the
+# documentation.
+#html_theme_options = {}
+
+# Add any paths that contain custom themes here, relative to this directory.
+#html_theme_path = []
+
+# The name for this set of Sphinx documents.  If None, it defaults to
+# "<project> v<release> documentation".
+#html_title = None
+
+# A shorter title for the navigation bar.  Default is the same as html_title.
+#html_short_title = None
+
+# The name of an image file (relative to this directory) to place at the top
+# of the sidebar.
+#html_logo = None
+
+# The name of an image file (relative to this directory) to use as a favicon of
+# the docs.  This file should be a Windows icon file (.ico) being 16x16 or 32x32
+# pixels large.
+#html_favicon = None
+
+# Add any paths that contain custom static files (such as style sheets) here,
+# relative to this directory. They are copied after the builtin static files,
+# so a file named "default.css" will overwrite the builtin "default.css".
+html_static_path = ['_static']
+
+# Add any extra paths that contain custom files (such as robots.txt or
+# .htaccess) here, relative to this directory. These files are copied
+# directly to the root of the documentation.
+#html_extra_path = []
+
+# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
+# using the given strftime format.
+#html_last_updated_fmt = '%b %d, %Y'
+
+# If true, SmartyPants will be used to convert quotes and dashes to
+# typographically correct entities.
+#html_use_smartypants = True
+
+# Custom sidebar templates, maps document names to template names.
+#html_sidebars = {}
+
+# Additional templates that should be rendered to pages, maps page names to
+# template names.
+#html_additional_pages = {}
+
+# If false, no module index is generated.
+#html_domain_indices = True
+
+# If false, no index is generated.
+#html_use_index = True
+
+# If true, the index is split into individual pages for each letter.
+#html_split_index = False
+
+# If true, links to the reST sources are added to the pages.
+#html_show_sourcelink = True
+
+# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
+#html_show_sphinx = True
+
+# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
+#html_show_copyright = True
+
+# If true, an OpenSearch description file will be output, and all pages will
+# contain a <link> tag referring to it.  The value of this option must be the
+# base URL from which the finished HTML is served.
+#html_use_opensearch = ''
+
+# This is the file name suffix for HTML files (e.g. ".xhtml").
+#html_file_suffix = None
+
+# Language to be used for generating the HTML full-text search index.
+# Sphinx supports the following languages:
+#   'da', 'de', 'en', 'es', 'fi', 'fr', 'hu', 'it', 'ja'
+#   'nl', 'no', 'pt', 'ro', 'ru', 'sv', 'tr'
+#html_search_language = 'en'
+
+# A dictionary with options for the search language support, empty by default.
+# Now only 'ja' uses this config value
+#html_search_options = {'type': 'default'}
+
+# The name of a javascript file (relative to the configuration directory) that
+# implements a search results scorer. If empty, the default will be used.
+#html_search_scorer = 'scorer.js'
+
+# Output file base name for HTML help builder.
+htmlhelp_basename = 'mshrdoc'
+
+# -- Options for LaTeX output ---------------------------------------------
+
+latex_elements = {
+# The paper size ('letterpaper' or 'a4paper').
+#'papersize': 'letterpaper',
+
+# The font size ('10pt', '11pt' or '12pt').
+#'pointsize': '10pt',
+
+# Additional stuff for the LaTeX preamble.
+#'preamble': '',
+
+# Latex figure (float) alignment
+#'figure_align': 'htbp',
+}
+
+# Grouping the document tree into LaTeX files. List of tuples
+# (source start file, target name, title,
+#  author, documentclass [howto, manual, or own class]).
+latex_documents = [
+    (master_doc, 'mshr.tex', u'mshr Documentation',
+     u'FEniCS Project', 'manual'),
+]
+
+# The name of an image file (relative to this directory) to place at the top of
+# the title page.
+#latex_logo = None
+
+# For "manual" documents, if this is true, then toplevel headings are parts,
+# not chapters.
+#latex_use_parts = False
+
+# If true, show page references after internal links.
+#latex_show_pagerefs = False
+
+# If true, show URL addresses after external links.
+#latex_show_urls = False
+
+# Documents to append as an appendix to all manuals.
+#latex_appendices = []
+
+# If false, no module index is generated.
+#latex_domain_indices = True
+
+
+# -- Options for manual page output ---------------------------------------
+
+# One entry per manual page. List of tuples
+# (source start file, name, description, authors, manual section).
+man_pages = [
+    (master_doc, 'mshr', u'mshr Documentation',
+     [author], 1)
+]
+
+# If true, show URL addresses after external links.
+#man_show_urls = False
+
+
+# -- Options for Texinfo output -------------------------------------------
+
+# Grouping the document tree into Texinfo files. List of tuples
+# (source start file, target name, title, author,
+#  dir menu entry, description, category)
+texinfo_documents = [
+    (master_doc, 'mshr', u'mshr Documentation',
+     author, 'mshr', 'One line description of project.',
+     'Miscellaneous'),
+]
+
+# Documents to append as an appendix to all manuals.
+#texinfo_appendices = []
+
+# If false, no module index is generated.
+#texinfo_domain_indices = True
+
+# How to display URL addresses: 'footnote', 'no', or 'inline'.
+#texinfo_show_urls = 'footnote'
+
+# If true, do not generate a @detailmenu in the "Top" node's menu.
+#texinfo_no_detailmenu = False
diff --git a/doc/sphinx/source/index.rst b/doc/sphinx/source/index.rst
new file mode 100644 (file)
index 0000000..3355e9b
--- /dev/null
@@ -0,0 +1,28 @@
+mshr documentation
+==================
+
+Mshr manual is located on `Bitbucket wiki
+<https://bitbucket.org/fenics-project/mshr/wiki/Home>`_.
+It is waiting for porting to Read the Docs. Contributions
+are welcome and first best discussed on `FEniCS Slack
+#documentation channel
+<https://fenicsproject.slack.com/messages/C1AGB4402/>`_,
+see `instruction for joining <https://fenicsproject.org/community/>`_.
+
+Automatically generated API documentation is not available yet.
+The approach from DOLFIN could possibly be ported to mshr too.
+Again, contributions are welcome.
+
+Contents:
+
+.. toctree::
+   :maxdepth: 1
+
+   ChangeLog
+
+Indices and tables
+==================
+
+* :ref:`genindex`
+* :ref:`modindex`
+* :ref:`search`
diff --git a/fenics-dev-install.sh b/fenics-dev-install.sh
new file mode 100755 (executable)
index 0000000..b045aab
--- /dev/null
@@ -0,0 +1,117 @@
+#!/usr/bin/env bash
+#
+# Developer script for configure + build + rebuild.
+#
+# Notes:
+#
+# - This script is what most developers use to build/rebuild this package.
+# - This script works for both CMake and distutils based packages.
+# - If this script is updated in one package, please propagate to the others!
+#
+# Environment variables:
+#
+# - $PROCS                    : controls number of processes to use for build
+#                             : defaults to 6
+# - $FENICS_PYTHON_EXECUTABLE : name of python executable
+#                             : defaults to "python"
+# - $FENICS_INSTALL_PREFIX    : path to FEniCS installation prefix
+#                             : defaults to "${HOME}/opt/<branchname>"
+
+# Exit on first error
+set -e
+
+# Get branch name
+BRANCH=`(git symbolic-ref --short HEAD 2> /dev/null || git describe HEAD) | sed s:/:.:g`
+echo "On branch '${BRANCH}'."
+
+# Get installation prefix
+: ${FENICS_INSTALL_PREFIX:="${HOME}/opt/fenics/${BRANCH}"}
+echo "Installation prefix set to '${FENICS_INSTALL_PREFIX}'."
+
+# Get Python executable and version
+: ${FENICS_PYTHON_EXECUTABLE:=python}
+FENICS_PYTHON_VERSION=$(${FENICS_PYTHON_EXECUTABLE} -c 'import sys; print(".".join(map(str, sys.version_info[:2])))')
+echo "Python executable and version set to '${FENICS_PYTHON_EXECUTABLE} ${FENICS_PYTHON_VERSION}'."
+
+# Get number of processes to use for build
+: ${PROCS:=6}
+
+
+# Build and install distutils based FEniCS package
+if [ -e setup.py ]; then
+    ${FENICS_PYTHON_EXECUTABLE} setup.py build
+    ${FENICS_PYTHON_EXECUTABLE} setup.py install --prefix=${FENICS_INSTALL_PREFIX}
+fi
+
+
+# Build and install dolfin
+if [ -e CMakeLists.txt ]; then
+    # Set build directory
+    if [ "${BRANCH}" = "master" ]; then
+        BUILD_DIR=build.${BRANCH}
+    elif [ "${BRANCH}" = "next" ]; then
+        BUILD_DIR=build.${BRANCH}
+    else
+        BUILD_DIR="build.wip" # use for all other branches to save disk space
+    fi
+
+    # Configure
+    CMAKE_EXTRA_ARGS=$@
+    mkdir -p ${BUILD_DIR}
+    cd ${BUILD_DIR}
+    time cmake -DCMAKE_INSTALL_PREFIX=${FENICS_INSTALL_PREFIX} \
+               -DDOLFIN_ENABLE_TESTING=true \
+               -DDOLFIN_ENABLE_BENCHMARKS=true \
+               -DCMAKE_BUILD_TYPE=Developer \
+               -DDOLFIN_DEPRECATION_ERROR=false \
+               ${CMAKE_EXTRA_ARGS} \
+               ..
+
+    # Build and install
+    time make -j ${PROCS} -k && make install -j ${PROCS}
+fi
+
+
+# Write config file
+CONFIG_FILE="${FENICS_INSTALL_PREFIX}/fenics.conf"
+rm -f ${CONFIG_FILE}
+cat << EOF > ${CONFIG_FILE}
+# FEniCS configuration file created by fenics-dev-install.sh on $(date)
+export FENICS_INSTALL_PREFIX=${FENICS_INSTALL_PREFIX}
+export FENICS_PYTHON_EXECUTABLE=${FENICS_PYTHON_EXECUTABLE}
+export FENICS_PYTHON_VERSION=${FENICS_PYTHON_VERSION}
+
+# Source FEniCS dependencies if found
+FENICS_DEPS_CONF=\${HOME}/opt/fenics/fenics.deps
+if [ -e \${FENICS_DEPS_CONF} ]; then
+    source \${FENICS_DEPS_CONF}
+fi
+
+# Common Unix variables
+export LD_LIBRARY_PATH=\${FENICS_INSTALL_PREFIX}/lib:\${LD_LIBRARY_PATH}
+export PATH=\${FENICS_INSTALL_PREFIX}/bin:\${PATH}
+export PKG_CONFIG_PATH=\${FENICS_INSTALL_PREFIX}/pkgconfig:\${PKG_CONFIG_PATH}
+export PYTHONPATH=\${FENICS_INSTALL_PREFIX}/lib/python${FENICS_PYTHON_VERSION}/site-packages:\${PYTHONPATH}
+export MANPATH=\${FENICS_INSTALL_PREFIX}/share/man:\${MANPATH}
+
+# Set Instant cache modules separately for each install
+export INSTANT_CACHE_DIR=\${FENICS_INSTALL_PREFIX}/cache/instant
+
+# CMake search path
+export CMAKE_PREFIX_PATH=\${FENICS_INSTALL_PREFIX}:\${CMAKE_PREFIX_PATH}
+EOF
+if [ $(uname) = "Darwin" ]; then
+    cat << EOF >> $CONFIG_FILE
+
+# Mac specific path
+export DYLD_FALLBACK_LIBRARY_PATH=\${FENICS_INSTALL_PREFIX}/lib:\${DYLD_FALLBACK_LIBRARY_PATH}
+EOF
+fi
+
+# Print information
+echo
+echo "- Installed branch '${BRANCH}' to ${FENICS_INSTALL_PREFIX}."
+echo
+echo "- Config file written to ${CONFIG_FILE}"
+echo "  (source this file)."
+echo
diff --git a/include/mshr.h b/include/mshr.h
new file mode 100644 (file)
index 0000000..e7b4441
--- /dev/null
@@ -0,0 +1,11 @@
+#include <mshr/MeshGenerator.h>
+#include <mshr/CSGOperators.h>
+#include <mshr/CSGPrimitives2D.h>
+#include <mshr/CSGPrimitives3D.h>
+#include <mshr/CSGCGALMeshGenerator2D.h>
+#include <mshr/CSGCGALMeshGenerator3D.h>
+#include <mshr/CSGCGALDomain3D.h>
+#include <mshr/CSGGeometries3D.h>
+#include <mshr/CSGGeometry.h>
+#include <mshr/CSGPrimitive.h>
+#include <mshr/DolfinMeshUtils.h>
diff --git a/include/mshr/ASCFileReader.h b/include/mshr/ASCFileReader.h
new file mode 100755 (executable)
index 0000000..6643955
--- /dev/null
@@ -0,0 +1,47 @@
+// Copyright (C) 2016 Lars Magnus Valnes
+//
+// This file is part of mshr.
+//
+// mshr 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 3 of the License, or
+// (at your option) any later version.
+// 
+// mshr 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 mshr.  If not, see <http://www.gnu.org/licenses/>.
+//
+
+#ifndef __ASC_FILE_READER_H // ??
+#define __ASC_FILE_READER_H // ?? 
+
+#include <string>
+#include <vector>
+#include <array>
+
+namespace mshr
+{
+
+class ASCFileReader
+{
+ public:
+  /// @brief Read and parse a triangular 3d surface off file
+  /// @param filename The file to read
+  /// @param vertices A vector of points to be read into
+  /// @param facets A vector of facets given as indices to the vertex array.
+  static void read(const std::string filename, 
+                   std::vector<std::array<double, 3> >& vertices,
+                   std::vector<std::array<std::size_t, 3> >& facets);
+
+  static void write(const std::string filename,
+                    const std::vector<std::array<double, 3> >& vertices,
+                    const std::vector<std::array<std::size_t, 3> >& facets);
+
+};
+
+}
+#endif
diff --git a/include/mshr/CSGCGALDomain2D.h b/include/mshr/CSGCGALDomain2D.h
new file mode 100644 (file)
index 0000000..35bca27
--- /dev/null
@@ -0,0 +1,98 @@
+// Copyright (C) 2013-2017 Benjamin Kehlet
+//
+// This file is part of mshr.
+//
+// mshr 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 3 of the License, or
+// (at your option) any later version.
+//
+// mshr 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 mshr.  If not, see <http://www.gnu.org/licenses/>.
+
+#ifndef __MSHR_CSGCGAL_DOMAIN2D_H
+#define __MSHR_CSGCGAL_DOMAIN2D_H
+
+#include <mshr/CSGGeometry.h>
+
+#include <dolfin/geometry/Point.h>
+#include <memory>
+
+
+namespace mshr
+{
+// Forward declaration
+struct CSGCGALDomain2DImpl;
+
+/// @brief Polygonal meshing domain
+///
+/// Represents the polygonal meshing domain to be sent to the mesh
+/// generator. It uses CGAL's Polygon_2 as backend and utilizied CGAL's
+/// 2D Regularized Boolean Set-Operations package.
+class CSGCGALDomain2D : public dolfin::Variable
+{
+ public:
+  /// @brief Create empty polygon
+  CSGCGALDomain2D();
+
+  /// @brief Construct polygon from Dolfin CSG geometry
+  CSGCGALDomain2D(
+      std::shared_ptr<const CSGGeometry> geometry,
+      double segment_granularity
+      );
+
+  /// @brief Destructor
+  ~CSGCGALDomain2D();
+
+  /// @brief Copy constructor
+  CSGCGALDomain2D(const CSGCGALDomain2D &other);
+
+  /// @brief Assignment operator
+  CSGCGALDomain2D &operator=(const CSGCGALDomain2D &other);
+
+  /// @brief Boolean join
+  void join_inplace(const CSGCGALDomain2D& other);
+
+  /// @brief Boolean intersection
+  void intersect_inplace(const CSGCGALDomain2D& other,
+                         double truncate_tolerance=-1.);
+
+  /// @brief Boolean difference
+  void difference_inplace(const CSGCGALDomain2D& other);
+
+  /// @brief Determine if point is inside the polygon.
+  bool point_in_domain(dolfin::Point p) const;
+
+  /// @brief Compute the radius of the minimum bounding circle.
+  double compute_boundingcircle_radius() const;
+
+  std::size_t num_polygons() const;
+  double shortest_edge() const;
+
+  std::vector<dolfin::Point> get_outer_polygon(std::size_t i) const;
+
+  /// @brief get one point per hole, strictly inside the hole.
+  /// @param holes the returned points
+  void get_points_in_holes(std::vector<dolfin::Point>& holes) const;
+
+  /// @brief Informal string representation
+  /// @param verbose Verbosity level
+  std::string str(bool verbose) const;
+
+  static
+    std::pair<std::vector<dolfin::Point>,
+              std::vector<std::pair<std::size_t, std::size_t>>>
+    compute_pslg(const std::vector<std::pair<std::size_t, CSGCGALDomain2D>>& domains);
+
+ private:
+  std::unique_ptr<CSGCGALDomain2DImpl> impl;
+};
+
+}
+
+#endif
diff --git a/include/mshr/CSGCGALDomain3D.h b/include/mshr/CSGCGALDomain3D.h
new file mode 100644 (file)
index 0000000..0557b59
--- /dev/null
@@ -0,0 +1,214 @@
+// Copyright (C) 2013-2015 Benjamin Kehlet
+//
+// This file is part of mshr.
+//
+// mshr 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 3 of the License, or
+// (at your option) any later version.
+//
+// mshr 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 mshr.  If not, see <http://www.gnu.org/licenses/>.
+
+#ifndef __MSHR_CSGCGAL_DOMAIN3D_H
+#define __MSHR_CSGCGAL_DOMAIN3D_H
+
+#include <mshr/CSGPrimitives3D.h>
+#include <dolfin/geometry/Point.h>
+
+#include <memory>
+#include <array>
+
+namespace mshr
+{
+
+  // Forward declaration
+  struct CSGCGALDomain3DImpl;
+  struct CSGCGALDomain3DQueryStructureImpl;
+
+class CSGCGALDomain3DQueryStructure
+{
+ public:
+  CSGCGALDomain3DQueryStructure(std::unique_ptr<CSGCGALDomain3DQueryStructureImpl> impl);
+  ~CSGCGALDomain3DQueryStructure();
+
+  std::unique_ptr<CSGCGALDomain3DQueryStructureImpl> impl;
+};
+
+/// @brief A polyhedron meshing domain.
+///
+/// This class represents a polyhedral meshing domain which implements boolean
+/// operations. It uses CGAL Polyhedron_3 as backend and utilizes CGAL
+//  Nef_polyhedron for boolean operations.
+class CSGCGALDomain3D : public CSGPrimitive3D
+{
+ public:
+  /// @brief Create empty polyhedron
+  CSGCGALDomain3D();
+
+  /// @brief Construct polyhedron from CSG geometry
+  CSGCGALDomain3D(std::shared_ptr<const mshr::CSGGeometry> csg);
+
+  CSGCGALDomain3D(const std::vector<std::array<double, 3>>& vertices,
+                  const std::vector<std::array<std::size_t, 3>>& facets);
+
+  /// @brief Destructor
+  ~CSGCGALDomain3D();
+
+  Type getType() const
+  { return CSGGeometry::TriPolyhedron; }
+
+  /// @brief Insert polyhedron into this object
+  /// Inserted polyhedron should not intersect
+  void insert(const CSGCGALDomain3D& p);
+
+  /// @brief Number of vertices in polyhedron
+  std::size_t num_vertices() const;
+
+  /// @brief Number of facets in polyhedron
+  std::size_t num_facets() const;
+
+  /// @brief Number of halfedges in polyhedron
+  std::size_t num_halfedges() const;
+
+  /// @brief Volume of polyhedron (experimental, use with care)
+  double volume() const;
+
+  /// @brief Is polyhedron  (experimental, use with care)
+  bool is_insideout() const;
+
+  /// @brief Count the number of degenerate facets wrt. the given tolerance
+  std::size_t num_degenerate_facets(double threshold) const;
+
+  std::pair<double, double> facet_area_minmax() const;
+
+  /// @brief get length of shortest edge
+  std::pair<double, double> edge_length_range() const;
+
+  /// @brief count edges with squared length shorter than tolerance
+  std::size_t num_short_edges(double tolerance) const;
+
+  /// @brief Test if any facets intersects
+  bool is_selfintersecting(bool verbose=false) const;
+
+  std::size_t remove_selfintersections();
+
+  void normalize();
+
+  /// @brief Save polyhedron to off file
+  /// @param filename Filename to write to
+  void save_off(std::string filename) const;
+
+  void save(std::string filename) const;
+
+  // TODO: Define iterators to be more memory friendly
+
+  /// @brief Output vertices in double precision
+  /// This outputs as a flattened array
+  std::unique_ptr<std::vector<double>> get_vertices() const;
+
+  /// @brief Output facets as indices to the vertices array
+  std::unique_ptr<std::vector<std::size_t>> get_facets() const;
+
+  /// @brief get one point per hole, strictly inside the hole.
+  /// @param holes the returned points
+  /// @param q a query structure returned from get_query_structure()
+  void get_points_in_holes(std::vector<dolfin::Point>& holes,
+                           std::shared_ptr<CSGCGALDomain3DQueryStructure> q=std::shared_ptr<CSGCGALDomain3DQueryStructure>()) const;
+
+  /// @brief Attempt to remove degenerate facets.
+  void remove_degenerate_facets(double tolerance);
+
+  /// @brief Attempts to ensure that the preconditions
+  /// for successfull meshing generation are fullfilled.
+  void ensure_meshing_preconditions();
+
+  /// @brief Return data structure that allows fast queries,
+  /// essentially a wrapper for a CGAL AABB tree of the polyhedron triangles.
+  /// When performing queries, the user is responsible for the query structure
+  /// being in sync with the CSGCGALDomain3D object.
+  std::shared_ptr<CSGCGALDomain3DQueryStructure> get_query_structure() const;
+
+  /// Default parameter values
+  static dolfin::Parameters default_parameters()
+  {
+    dolfin::Parameters p("csg_cgal_domain_3d");
+    p.add("remove_degenerate", true);
+    p.add("degenerate_tolerance", 1e-10);
+
+    return p;
+  }
+
+  /// @brief Informal string representation
+  /// @param verbose The verbosity level
+  std::string str(bool verbose) const;
+
+  /// @brief Remove facets, starting from the facets closest to to the given
+  /// point
+  void filter_facets(dolfin::Point start,
+                     double threshold,
+                     std::shared_ptr<CSGCGALDomain3DQueryStructure> q=std::shared_ptr<CSGCGALDomain3DQueryStructure>());
+
+  void inside_out();
+
+  /// A hole is a connected sequence of boundary edges
+  std::size_t num_holes() const;
+
+  ///  Disconnected components are parts of the polyhedron that can not be
+  ///  reached through adjacent entities.
+  std::size_t num_disconnected_components() const;
+
+  /// Keep only the n largest disconnected components. Returns the number of
+  /// components removed.
+  std::size_t keep_largest_components(std::size_t n);
+
+  /// get the axis aligned bounding box of the polyhedron, represented as min and
+  /// max points
+  std::pair<dolfin::Point, dolfin::Point> get_aabb() const;
+
+  /// @brief Close and triangulate all holes. Experimental.
+  void close_holes();
+
+  /// @brief Close and triangulate hole. Experimental.
+  bool close_hole(std::size_t hole, std::string method="auto");
+
+  void list_hole(std::size_t hole) const;
+
+  double sharpest_edge() const;
+  std::size_t num_sharp_edges(double tolerance) const;
+
+  void smooth_taubin(std::size_t iterations=3);
+  void smooth_laplacian(double c=1.0);
+
+  /// Do a simple center vertex refinement
+  /// Note: This decreases the triangle quality
+  void refine_center_vertex();
+
+  /// Refine by splitting all edges
+  void refine_edge_split();
+
+  // @brief Reconstruct surface from point set. Experimental
+  std::shared_ptr<CSGCGALDomain3D> reconstruct_surface(double expansion=0.0) const;
+
+  // @brief Isotropic remeshing. Experimental
+  std::shared_ptr<CSGCGALDomain3D> remesh_surface(double edge_length,
+                                                  double sharp_edge_tolerance=60) const;
+
+  /// @brief Return convex hull of vertices as CSGCGALDomain3D object. Experimental
+  std::shared_ptr<CSGCGALDomain3D> convex_hull() const;
+
+  static std::shared_ptr<CSGCGALDomain3D>
+    convex_hull(const std::vector<std::array<double, 3>>& point_set);
+
+  // FIXME: Make this private again
+  // private :
+  std::unique_ptr<CSGCGALDomain3DImpl> impl;
+};
+
+}
+#endif
diff --git a/include/mshr/CSGCGALMeshGenerator2D.h b/include/mshr/CSGCGALMeshGenerator2D.h
new file mode 100644 (file)
index 0000000..c867f48
--- /dev/null
@@ -0,0 +1,80 @@
+// Copyright (C) 2012-2016 Benjamin Kehlet
+//
+// This file is part of mshr.
+//
+// mshr 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 3 of the License, or
+// (at your option) any later version.
+//
+// mshr 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 mshr.  If not, see <http://www.gnu.org/licenses/>.
+//
+// Modified by Johannes Ring, 2012
+
+#ifndef __MSHR_CGAL_MESH_GENERATOR2D_H
+#define __MSHR_CGAL_MESH_GENERATOR2D_H
+
+#include <dolfin/common/Variable.h>
+
+#include <vector>
+#include <memory>
+
+// Forward declaration
+namespace dolfin{ class Mesh; }
+
+namespace mshr
+{
+
+  // Forward declaration
+  class CSGCGALDomain2D;
+
+  /// @brief Mesh generator for Constructive Solid Geometry (CSG)
+  /// utilizing CGALs 2D Regularized Boolean Set-Operations
+  class CSGCGALMeshGenerator2D : public dolfin::Variable
+  {
+  public :
+
+    /// @brief Create mesh generator
+    CSGCGALMeshGenerator2D();
+
+    /// @brief Destructor
+    ~CSGCGALMeshGenerator2D();
+
+    /// @brief Generate mesh
+    /// @param geometry The geometry to be meshed
+    /// @param mesh The Dolfin mesh object to be returned. Will ble cleared.
+    /// @param partition (experimental) If true then generate mesh on process 0 and partition and distribute
+    ///   it. If false, then a full mesh is generated on all processes.(only
+    ///   relevant when running in parallel)
+    std::shared_ptr<dolfin::Mesh> generate(std::shared_ptr<const CSGCGALDomain2D> domain,
+                                           const std::vector<std::pair<std::size_t, std::shared_ptr<const CSGCGALDomain2D>>>& subdomains
+                                           = std::vector<std::pair<std::size_t, std::shared_ptr<const CSGCGALDomain2D>>>());
+
+    /// Default parameter values
+    static dolfin::Parameters default_parameters()
+    {
+      dolfin::Parameters p("csg_cgal_meshgenerator");
+
+      // DEPRECATED! Use cell size
+      p.add("mesh_resolution", 64.0);
+      p.add("triangle_shape_bound", 0.125);
+      p.add("cell_size", 0.25);
+      p.add("lloyd_optimize", false);
+
+      // shorter edges in the domain will be collapsed before meshing
+      p.add("edge_truncate_tolerance", 1e-16);
+      p.add("partition", true);
+
+      return p;
+    }
+  };
+
+}
+
+#endif
diff --git a/include/mshr/CSGCGALMeshGenerator3D.h b/include/mshr/CSGCGALMeshGenerator3D.h
new file mode 100644 (file)
index 0000000..4eacd1d
--- /dev/null
@@ -0,0 +1,79 @@
+// Copyright (C) 2012 Benjamin Kehlet
+//
+// This file is part of mshr.
+//
+// mshr 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 3 of the License, or
+// (at your option) any later version.
+// 
+// mshr 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 mshr.  If not, see <http://www.gnu.org/licenses/>.
+
+#ifndef __MSHR_CGAL_MESH_GENERATOR3D_H
+#define __MSHR_CGAL_MESH_GENERATOR3D_H
+
+#include <mshr/CSGCGALDomain3D.h>
+
+#include <dolfin/common/Variable.h>
+#include <memory>
+
+namespace dolfin{ class Mesh; }
+
+namespace mshr
+{
+
+  // Forward declaration
+  class CSGGeometry;
+
+  /// @brief Mesh generator for Constructive Solid Geometry (CSG)
+  /// utilizing CGALs 3D Mesh generation package.
+  ///
+  /// This class gives access to the backend specific meshing
+  /// criterias throught the parameter system.
+  class CSGCGALMeshGenerator3D : public dolfin::Variable
+  {
+  public :
+
+    /// @brief Create mesh generator
+    CSGCGALMeshGenerator3D();
+
+    /// @brief Destructor
+    ~CSGCGALMeshGenerator3D();
+
+    /// @brief Generate Dolfin mesh
+    /// @param domain The polyhedral domain to be meshed
+    std::shared_ptr<dolfin::Mesh> generate(std::shared_ptr<const CSGCGALDomain3D> domain) const;
+
+    /// @brief Default parameter values
+    static dolfin::Parameters default_parameters()
+    {
+      dolfin::Parameters p("csg_cgal_meshgenerator");
+      p.add("mesh_resolution", 64.0);
+      p.add("perturb_optimize", false);
+      p.add("exude_optimize", false);
+      p.add("lloyd_optimize", false);
+      p.add("odt_optimize", false);
+      p.add("edge_size", 0.025);
+      p.add("facet_angle", 25.0);
+      p.add("facet_size", 0.05);
+      p.add("facet_distance", 0.005);
+      p.add("cell_radius_edge_ratio", 3.0);
+      p.add("cell_size", 0.05);
+      p.add("detect_sharp_features", true);
+      p.add("feature_threshold", 70.);
+
+      return p;
+    }
+  private:
+    void generate(std::shared_ptr<const CSGCGALDomain3D> domain, dolfin::Mesh& mesh) const;
+  };
+
+}
+
+#endif
diff --git a/include/mshr/CSGGeometries3D.h b/include/mshr/CSGGeometries3D.h
new file mode 100644 (file)
index 0000000..dd3fe8c
--- /dev/null
@@ -0,0 +1,61 @@
+// Copyright (C) 2012-2017 Benjamin Kehlet
+//
+// This file is part of mshr.
+//
+// mshr 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 3 of the License, or
+// (at your option) any later version.
+//
+// mshr 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 mshr.  If not, see <http://www.gnu.org/licenses/>.
+//
+// Modified by Johannes Ring, 2012
+
+#ifndef __MSHR_GEOMETRIES_H
+#define __MSHR_GEOMETRIES_H
+
+#include "CSGGeometry.h"
+#include <dolfin/geometry/Point.h>
+
+#include <memory>
+
+namespace dolfin
+{
+  class Mesh;
+}
+
+namespace mshr
+{
+  class CSGGeometries
+  {
+  public:
+
+    // A standard LEGO brick starting at the point x with (n0, n1)
+    // knobs and height n2. The height should be 1 for a thin brick or 3
+    // for a regular brick.
+    static std::shared_ptr<CSGGeometry> lego(std::size_t n0,
+                                             std::size_t n1,
+                                             std::size_t n2,
+                                             dolfin::Point x = dolfin::Point(0,0,0));
+
+    // A simple propeller with parameters r - radius of center body, R - length of blades,
+    // w - width of blades and h - thicknes of blades
+    static std::shared_ptr<CSGGeometry> propeller(double r=0.125,
+                                                  double R=0.5,
+                                                  double w=0.3,
+                                                  double h=0.025,
+                                                  bool rotate_blades=true,
+                                                  bool include_tip=false);
+
+    // Import boundary of mesh as CSG geometry
+    static std::shared_ptr<CSGGeometry> import_mesh(std::shared_ptr<dolfin::Mesh> mesh);
+  };
+}
+
+#endif
diff --git a/include/mshr/CSGGeometry.h b/include/mshr/CSGGeometry.h
new file mode 100644 (file)
index 0000000..f032946
--- /dev/null
@@ -0,0 +1,109 @@
+// Copyright (C) 2012 Anders Logg and 2013-2017 Benjamin Kehlet
+//
+// This file is part of mshr.
+//
+// mshr 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 3 of the License, or
+// (at your option) any later version.
+//
+// mshr 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 mshr.  If not, see <http://www.gnu.org/licenses/>.
+//
+// Modified by Johannes Ring, 2012
+
+
+#ifndef __MSHR_GEOMETRY_H
+#define __MSHR_GEOMETRY_H
+
+#include <memory>
+#include <cstddef>
+#include <vector>
+#include <list>
+
+#include <dolfin/common/Variable.h>
+#include <dolfin/geometry/Point.h>
+
+namespace mshr
+{
+
+  /// Geometry described by Constructive Solid Geometry (CSG)
+  class CSGGeometry : public dolfin::Variable
+  {
+   protected:
+    /// Constructor
+    CSGGeometry();
+
+   public:
+    /// Destructor
+    virtual ~CSGGeometry();
+
+    /// Return dimension of geometry
+    virtual std::size_t dim() const = 0;
+
+    /// Informal string representation
+    virtual std::string str(bool verbose) const = 0;
+
+    /// Define subdomain. This feature is 2D only.
+    /// The subdomain is itself a CSGGeometry and the corresponding
+    /// cells in the resulting will be marked with i
+    /// If subdomains overlap, the latest added will take precedence.
+    void set_subdomain(std::size_t i, std::shared_ptr<CSGGeometry> s);
+
+    /// Define subdomain. This feature is 2D only.
+    /// The subdomain is itself a CSGGeometry and the corresponding
+    /// cells in the resulting will be marked with i
+    /// If subdomains overlap, the latest added will take precedence.
+    void set_subdomain(std::size_t i, CSGGeometry& s);
+
+    /// @brief Has subdomains been set
+    bool has_subdomains() const;
+
+    /// @brief Return const list of subdomain geometries
+    const std::list<std::pair<std::size_t, std::shared_ptr<const CSGGeometry>>>& get_subdomains() const { return subdomains; }
+
+    // These functions are (for now) implemented for 2D only.
+    std::pair<dolfin::Point, double> estimate_bounding_sphere(std::size_t numSamples=100) const;
+
+    // Compute axis aligned box that is guaranteed to bound the geometry. May overshoot.
+    virtual std::pair<dolfin::Point, dolfin::Point> bounding_box() const = 0;
+
+    // Test if given point is inside geometry. 2D only (for now)
+    virtual bool inside(dolfin::Point p) const = 0;
+
+    // Test if line segment is entirely inside geometry. 2D only (for now)
+    virtual bool inside(dolfin::Point p1, dolfin::Point p2) const;
+
+    enum Type { Box,
+                Sphere,
+                Cylinder,
+                Tetrahedron,
+                Ellipsoid,
+                Surface3D,
+                Extrude2D,
+                Circle,
+                Ellipse,
+                Rectangle,
+                Polygon,
+                Union,
+                Intersection,
+                Difference,
+                Translation,
+                Scaling,
+                Rotation,
+                TriPolyhedron };
+
+    virtual Type getType() const = 0;
+    virtual bool is_operator() const = 0;
+
+   private :
+    std::list<std::pair<std::size_t, std::shared_ptr<const CSGGeometry> > > subdomains;
+  };
+}
+
+#endif
diff --git a/include/mshr/CSGOperators.h b/include/mshr/CSGOperators.h
new file mode 100644 (file)
index 0000000..35a58ac
--- /dev/null
@@ -0,0 +1,325 @@
+// Copyright (C) 2012 Anders Logg, 2012-2017 Benjamin Kehlet
+//
+// This file is part of mshr.
+//
+// mshr 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 3 of the License, or
+// (at your option) any later version.
+//
+// mshr 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 mshr.  If not, see <http://www.gnu.org/licenses/>.
+//
+
+#ifndef __MSHR_OPERATORS_H
+#define __MSHR_OPERATORS_H
+
+#include "CSGGeometry.h"
+#include <dolfin/geometry/Point.h>
+#include <dolfin/common/NoDeleter.h>
+
+#include <memory>
+
+namespace mshr
+{
+
+  /// @brief Base class for csg operators
+  /// CSGOperator object are internal (non-leaf) nodes in the CSG tree.
+  class CSGOperator : public CSGGeometry
+  {
+   protected:
+    CSGOperator();
+   public:
+    virtual bool is_operator() const { return true; }
+    std::size_t dim() const { return dim_;}
+
+   protected :
+    std::size_t dim_;
+  };
+
+  /// @brief Union of CSG geometries
+  class CSGUnion : public CSGOperator
+  {
+  public:
+
+    /// @brief Create union of two geometries
+    /// @param g0 a CSG geometry
+    /// @param g1 a CSG geometry
+    CSGUnion(std::shared_ptr<CSGGeometry> g0,
+             std::shared_ptr<CSGGeometry> g1);
+
+    /// @brief get informal string representation
+    /// @param verbose vervosity level
+    std::string str(bool verbose) const;
+
+    std::pair<dolfin::Point, dolfin::Point> bounding_box() const;
+    bool inside(dolfin::Point p) const;
+
+    Type getType() const { return CSGGeometry::Union; }
+
+    const std::shared_ptr<CSGGeometry> _g0;
+    const std::shared_ptr<CSGGeometry> _g1;
+  };
+
+  /// @brief Difference of CSG geometries
+  class CSGDifference : public CSGOperator
+  {
+  public:
+
+    /// @brief Create union of two geometries
+    /// @param g0 a CSG geometry
+    /// @param g1 a CSG CSG geometry
+    CSGDifference(std::shared_ptr<CSGGeometry> g0,
+                  std::shared_ptr<CSGGeometry> g1);
+
+    /// @brief get informal string representation
+    std::string str(bool verbose) const;
+
+    std::pair<dolfin::Point, dolfin::Point> bounding_box() const;
+    bool inside(dolfin::Point p) const;
+
+    Type getType() const { return CSGGeometry::Difference; }
+
+    const std::shared_ptr<CSGGeometry> _g0;
+    const std::shared_ptr<CSGGeometry> _g1;
+  };
+
+
+  /// @brief Intersection of CSG geometries
+  class CSGIntersection : public CSGOperator
+  {
+  public:
+
+    /// @brief Create intersection of two geometries
+    /// @param g0 a CSG geometry
+    /// @param g1 a CSG geometry
+    CSGIntersection(std::shared_ptr<CSGGeometry> g0,
+                    std::shared_ptr<CSGGeometry> g1);
+
+    /// @brief get informal string representation
+    std::string str(bool verbose) const;
+
+    std::pair<dolfin::Point, dolfin::Point> bounding_box() const;
+    bool inside(dolfin::Point p) const;
+
+    Type getType() const { return CSGGeometry::Intersection; }
+
+    const std::shared_ptr<CSGGeometry> _g0;
+    const std::shared_ptr<CSGGeometry> _g1;
+
+  };
+
+  /// @brief Translate CSG geometry by vector
+  ///
+  /// { 'small-icon' : 'translation-small.png' }
+  class CSGTranslation : public CSGOperator
+  {
+    public:
+
+    /// @brief create translation
+    /// @param g a CSG geometry
+    /// @param t the translation vector
+    CSGTranslation(std::shared_ptr<CSGGeometry> g,
+                   dolfin::Point t);
+
+    /// @brief get informal string representation
+    std::string str(bool verbose) const;
+
+    std::pair<dolfin::Point, dolfin::Point> bounding_box() const;
+    bool inside(dolfin::Point p) const;
+
+    Type getType() const { return CSGGeometry::Translation; }
+
+    const std::shared_ptr<CSGGeometry> g;
+    const dolfin::Point t;
+  };
+
+  /// @brief Scale CSG geometry
+  ///
+  /// { 'small-icon' : 'scaling-small.png' }
+  class CSGScaling : public CSGOperator
+  {
+   public:
+
+    /// @brief Create scaling
+    /// @param g a CSG geometry
+    /// @param scale_factor
+    CSGScaling(std::shared_ptr<CSGGeometry> g,
+               double scale_factor);
+
+    /// @brief Scale (translated) geometry. Geometry will be translated, scaled and translated back
+    /// @param g a CSG geometry
+    /// @param c translation
+    /// @param scale_factor the scale factor
+    CSGScaling(std::shared_ptr<CSGGeometry> g,
+               dolfin::Point c,
+               double scale_factor);
+
+    std::string str(bool verbose) const;
+
+    std::pair<dolfin::Point, dolfin::Point> bounding_box() const;
+    bool inside(dolfin::Point p) const;
+
+    Type getType() const { return CSGGeometry::Scaling; }
+
+    const std::shared_ptr<CSGGeometry> g;
+    const dolfin::Point c;
+    const double s;
+    const bool translate;
+  };
+
+  /// @brief Rotate CSG geometry
+  ///
+  /// { 'small-icon' : 'rotation-small.png' }
+  class CSGRotation : public CSGOperator
+  {
+   public:
+    /// @brief Create 2D rotation (2D only)
+    /// @param g A CSG geometry
+    /// @param theta Rotate by theta
+    CSGRotation(std::shared_ptr<CSGGeometry> g,
+                             double theta);
+
+    /// @brief Create rotation
+    /// @param g A CSG geometry
+    /// @param v In 2D: the rotation center. In 3D: the rotation axis.
+    /// @param theta Radians to rotate.
+    CSGRotation(std::shared_ptr<CSGGeometry> g,
+                dolfin::Point v,
+                double theta);
+
+    /// @brief create 3D rotation
+    /// @param g A CSG geometry
+    /// @param rot_axis The rotation axis
+    /// @param rot_center The rotation center
+    /// @param theta Radians to rotate
+    CSGRotation(std::shared_ptr<CSGGeometry> g,
+                dolfin::Point rot_axis,
+                dolfin::Point rot_center,
+                double theta);
+    Type getType() const { return CSGGeometry::Rotation; }
+    std::string str(bool verbose) const;
+
+    std::pair<dolfin::Point, dolfin::Point> bounding_box() const;
+    bool inside(dolfin::Point p) const;
+
+    const std::shared_ptr<CSGGeometry> g;
+    const dolfin::Point rot_axis;
+    const dolfin::Point c;
+    const double theta;
+    const bool translate;
+  };
+
+  //--- Union operators ---
+
+  /// Create union of two geometries
+  inline std::shared_ptr<CSGUnion> operator+(std::shared_ptr<CSGGeometry> g0,
+                                             std::shared_ptr<CSGGeometry> g1)
+  {
+    return std::shared_ptr<CSGUnion>(new CSGUnion(g0, g1));
+  }
+
+  /// Create union of two geometries
+  inline std::shared_ptr<CSGUnion> operator+(CSGGeometry& g0,
+                                             std::shared_ptr<CSGGeometry> g1)
+  {
+    return reference_to_no_delete_pointer(g0) + g1;
+  }
+
+  /// Create union of two geometries
+  inline std::shared_ptr<CSGUnion> operator+(std::shared_ptr<CSGGeometry> g0,
+                                             CSGGeometry& g1)
+  {
+    return g0 + reference_to_no_delete_pointer(g1);
+  }
+
+  /// Create union of two geometries
+  inline std::shared_ptr<CSGUnion> operator+(CSGGeometry& g0,
+                                             CSGGeometry& g1)
+  {
+    return reference_to_no_delete_pointer(g0) + reference_to_no_delete_pointer(g1);
+  }
+
+  //--- Difference operators ---
+
+  /// Create difference of two geometries
+  inline  std::shared_ptr<CSGDifference> operator-(std::shared_ptr<CSGGeometry> g0,
+                                            std::shared_ptr<CSGGeometry> g1)
+  {
+    return std::shared_ptr<CSGDifference>(new CSGDifference(g0, g1));
+  }
+
+  /// Create difference of two geometries
+  inline std::shared_ptr<CSGDifference> operator-(CSGGeometry& g0,
+                                            std::shared_ptr<CSGGeometry> g1)
+  {
+    return reference_to_no_delete_pointer(g0) - g1;
+  }
+
+  /// Create union of two geometries
+  inline std::shared_ptr<CSGDifference> operator-(std::shared_ptr<CSGGeometry> g0,
+                                            CSGGeometry& g1)
+  {
+    return g0 - reference_to_no_delete_pointer(g1);
+  }
+
+  /// Create difference of two geometries
+  inline std::shared_ptr<CSGDifference> operator-(CSGGeometry& g0,
+                                            CSGGeometry& g1)
+  {
+    return reference_to_no_delete_pointer(g0) - reference_to_no_delete_pointer(g1);
+  }
+
+
+  //--- Intersection operators ---
+
+  /// Create intersection  of two geometries
+  inline std::shared_ptr<CSGIntersection> operator*(std::shared_ptr<CSGGeometry> g0,
+                                                    std::shared_ptr<CSGGeometry> g1)
+  {
+    return std::shared_ptr<CSGIntersection>(new CSGIntersection(g0, g1));
+  }
+
+  /// Create intersection of two geometries
+  inline std::shared_ptr<CSGIntersection> operator*(CSGGeometry& g0,
+                                                    std::shared_ptr<CSGGeometry> g1)
+  {
+    return reference_to_no_delete_pointer(g0) * g1;
+  }
+
+  /// Create intersection of two geometries
+  inline std::shared_ptr<CSGIntersection> operator*(std::shared_ptr<CSGGeometry> g0,
+                                                    CSGGeometry& g1)
+  {
+    return g0 * reference_to_no_delete_pointer(g1);
+  }
+
+  /// Create intersection of two geometries
+  inline std::shared_ptr<CSGIntersection> operator*(CSGGeometry& g0,
+                                                    CSGGeometry& g1)
+  {
+    return reference_to_no_delete_pointer(g0) * reference_to_no_delete_pointer(g1);
+  }
+
+  //--- Translation operators ---
+  inline std::shared_ptr<CSGTranslation> operator+(std::shared_ptr<CSGGeometry> g,
+                                                   dolfin::Point t)
+  {
+    return std::shared_ptr<CSGTranslation>(new CSGTranslation(g, t));
+  }
+
+  //--- Scaling operators ---
+  inline std::shared_ptr<CSGScaling> operator*(std::shared_ptr<CSGGeometry> g,
+                                               double s)
+  {
+    return std::shared_ptr<CSGScaling>(new CSGScaling(g, s));
+  }
+
+}
+
+#endif
diff --git a/include/mshr/CSGPrimitive.h b/include/mshr/CSGPrimitive.h
new file mode 100644 (file)
index 0000000..018f55a
--- /dev/null
@@ -0,0 +1,38 @@
+// Copyright (C) 2012 Anders Logg
+//
+// This file is part of mshr.
+//
+// mshr 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 3 of the License, or
+// (at your option) any later version.
+// 
+// mshr 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 mshr.  If not, see <http://www.gnu.org/licenses/>.
+//
+// Modified by Benjamin Kehlet, 2012-2013
+
+#ifndef __MSHR_PRIMITIVE_H
+#define __MSHR_PRIMITIVE_H
+
+#include "CSGGeometry.h"
+
+namespace mshr
+{
+
+  /// Base class for Constructive Solid Geometry (CSG) primitives.
+  class CSGPrimitive : public CSGGeometry
+  {
+  public:
+    virtual bool is_operator() const { return false; }
+    virtual std::size_t dim() const = 0;
+  };
+
+}
+
+#endif
diff --git a/include/mshr/CSGPrimitives2D.h b/include/mshr/CSGPrimitives2D.h
new file mode 100644 (file)
index 0000000..d726d14
--- /dev/null
@@ -0,0 +1,191 @@
+// Copyright (C) 2012 Anders Logg, 2012-2017 Benjamin Kehlet
+//
+// This file is part of mshr.
+//
+// mshr 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 3 of the License, or
+// (at your option) any later version.
+//
+// mshr 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 mshr.  If not, see <http://www.gnu.org/licenses/>.
+//
+// Modified by Johannes Ring, 2012
+
+
+#ifndef __MSHR_PRIMITIVES_2D_H
+#define __MSHR_PRIMITIVES_2D_H
+
+#include "CSGPrimitive.h"
+
+#include <dolfin/geometry/Point.h>
+#include <vector>
+
+
+namespace mshr
+{
+
+  /// @brief Base class for 2D primitives
+  class CSGPrimitive2D : public CSGPrimitive
+  {
+  protected:
+    CSGPrimitive2D();
+
+  public:
+
+    /// @brief get the dimension of the geometry (2)
+    std::size_t dim() const { return 2; }
+  };
+
+  /// @brief A 2D circle
+  ///
+  /// { "small-icon" : "circle-small.png" }
+  class Circle : public CSGPrimitive2D
+  {
+  public:
+
+    /// @brief Create circle centered at x with radius r.
+    ///
+    /// @param c center.
+    /// @param r radius.
+    /// @param segments number of segments when computing the polygonal approximation
+    Circle(dolfin::Point c, double r, std::size_t segments=0);
+
+    /// @brief get informal string representation
+    /// @param verbose  Verbosity level
+    std::string str(bool verbose) const;
+
+    Type getType() const { return CSGGeometry::Circle; }
+
+    /// @brief get center of circle
+    dolfin::Point center() const { return c; }
+
+    /// @brief get radius of circle
+    double radius() const { return _r; }
+
+    /// @brief get number of segments used when computing polygonal approximation
+    std::size_t segments() const { return _segments; }
+
+    std::pair<dolfin::Point, dolfin::Point> bounding_box() const;
+    bool inside(dolfin::Point p) const;
+
+  private:
+    dolfin::Point c;
+    double _r;
+    const std::size_t _segments;
+  };
+
+  /// @brief A 2D ellipse
+  ///
+  /// { "small-icon" : "ellipse-small.png" }
+  class Ellipse : public CSGPrimitive2D
+  {
+  public:
+
+    /// @brief Create ellipse centered at c with horizontal semi-axis a and
+    /// vertical semi-axis b.
+    ///
+    /// @param c        the center
+    /// @param a        the horizontal semi-axis
+    /// @param b        the vertical semi-axis
+    /// @param segments the resolution when computing polygonal approximation
+    Ellipse(dolfin::Point c, double a, double b, std::size_t segments=0);
+
+    /// @brief get informal string representation
+    /// @param verbose  Verbosity level
+    std::string str(bool verbose) const;
+
+    Type getType() const { return CSGGeometry::Ellipse; }
+
+    /// @brief get center of ellipse
+    dolfin::Point center() const { return c; }
+
+    /// @brief get horizontal semi-axis
+    double a() const { return _a; }
+
+    /// @brief get vertical semi-axis
+    double b() const { return _b; }
+
+    /// @brief get resolution when computing polygonal approximation
+    std::size_t segments() const { return _segments; }
+
+    std::pair<dolfin::Point, dolfin::Point> bounding_box() const;
+    bool inside(dolfin::Point p) const;
+
+
+  private:
+    dolfin::Point c;
+    double _a, _b;
+    const std::size_t _segments;
+  };
+
+  /// @brief A 2D axis aligned rectangle
+  ///
+  /// { "small-icon" : "rectangle-small.png" }
+  class Rectangle : public CSGPrimitive2D
+  {
+  public:
+
+    /// @brief Create rectangle defined by two opposite corners
+    ///
+    /// @param a first corner.
+    /// @param b second corner.
+    Rectangle(dolfin::Point a, dolfin::Point b);
+
+    /// @brief get informal string representation
+    /// @param verbose  Verbosity level
+    std::string str(bool verbose) const;
+
+    Type getType() const { return CSGGeometry::Rectangle; }
+
+    /// @brief get first corner
+    dolfin::Point first_corner() const { return a; }
+
+    /// @brief get second corner
+    dolfin::Point second_corner() const { return b; }
+
+    std::pair<dolfin::Point, dolfin::Point> bounding_box() const;
+    bool inside(dolfin::Point p) const;
+
+  private:
+    const dolfin::Point a, b;
+  };
+
+  /// @brief A 2D polygon
+  ///
+  /// { 'large-icon' : 'polygon-large.png', 'small-icon' : 'polygon-small.png' }
+  class Polygon : public CSGPrimitive2D
+  {
+  public:
+
+    /// @brief Create polygon defined by the given vertices. Vertices must be in counter-clockwise order and free of self-intersections.
+    ///
+    /// @param vertices A vector of dolfin::Points. Vertices are copied into the object.
+    Polygon(const std::vector<dolfin::Point>& vertices);
+
+    /// @brief get informal string representation
+    /// @param verbose  Verbosity level
+    std::string str(bool verbose) const;
+
+    Type getType() const { return CSGGeometry::Polygon; }
+
+    /// @brief check if vertices are counter clockwise oriented.
+    bool ccw() const;
+
+    /// @brief get vertices in polygon.
+    const std::vector<dolfin::Point>& vertices() const { return _vertices; }
+
+    std::pair<dolfin::Point, dolfin::Point> bounding_box() const;
+    bool inside(dolfin::Point p) const;
+
+  private:
+    const std::vector<dolfin::Point> _vertices;
+  };
+}
+
+#endif
diff --git a/include/mshr/CSGPrimitives3D.h b/include/mshr/CSGPrimitives3D.h
new file mode 100644 (file)
index 0000000..433957a
--- /dev/null
@@ -0,0 +1,270 @@
+// Copyright (C) 2012 Anders Logg, 2012-2017 Benjamin Kehlet
+//
+// This file is part of mshr.
+//
+// mshr 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 3 of the License, or
+// (at your option) any later version.
+//
+// mshr 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 mshr.  If not, see <http://www.gnu.org/licenses/>.
+//
+// Modified by Johannes Ring 2012
+
+#ifndef __MSHR_PRIMITIVES_3D_H
+#define __MSHR_PRIMITIVES_3D_H
+
+#include "CSGPrimitive.h"
+#include "CSGPrimitives2D.h"
+#include <dolfin/mesh/Mesh.h>
+#include <dolfin/geometry/Point.h>
+#include <cstddef>
+
+namespace mshr
+{
+
+  /// @brief Base class for 3D primitives
+  class CSGPrimitive3D : public CSGPrimitive
+  {
+  protected:
+    CSGPrimitive3D();
+
+  public:
+    /// @return get dimension of geometry
+    std::size_t dim() const { return 3; }
+
+    // Compute axis aligned box that is guaranteed to bound the geometry. May overshoot.
+    std::pair<dolfin::Point, dolfin::Point> bounding_box() const;
+
+    // Test if given point is inside geometry. 2D only (for now)
+    bool inside(dolfin::Point p) const;
+
+
+  };
+
+  // TODO: Make sphere a special case of ellipsoid.
+  /// @brief A 3D sphere
+  ///
+  /// { "small-icon" : "sphere-small.png" }
+  class Sphere : public CSGPrimitive3D
+  {
+  public:
+
+    /// @brief Create sphere at c with radius r.
+    ///
+    /// @param center center of sphere
+    /// @param radius radius of sphere
+    /// @param segments resolution when generating a polyhedral appoximation
+    Sphere(dolfin::Point center, double radius, std::size_t segments=10);
+
+    /// @brief Informal string representation
+    /// @param verbose  Verbosity level
+    std::string str(bool verbose) const;
+
+    Type getType() const { return CSGGeometry::Sphere; }
+
+    const dolfin::Point c;
+    const double r;
+    const std::size_t _segments;
+  };
+
+  /// @brief A 3D axis aligned box
+  ///
+  /// { "small-icon" : "box-small.png" }
+  class Box : public CSGPrimitive3D
+  {
+  public:
+
+    /// @brief Create box defined by two opposite corners
+    ///
+    /// @param a The first corner
+    /// @param b The second corner
+    Box(dolfin::Point a, dolfin::Point b);
+
+    /// @brief Informal string representation
+    std::string str(bool verbose) const;
+
+    Type getType() const { return CSGGeometry::Box; }
+
+    const dolfin::Point a, b;
+  };
+
+  /// @brief A 3D cylinder
+  ///
+  /// { "small-icon" : "cylinder-small.png" }
+  class Cylinder : public CSGPrimitive3D
+  {
+  public:
+
+    /// @brief Create cylinder defined by upper and lower center
+    /// and radius respectively.
+    ///
+    /// @param top           Center at top of cylinder.
+    /// @param bottom        Center at bottom of cylinder.
+    /// @param top_radius    Radius top of cylinder.
+    /// @param bottom_radius Radius at botoom of cylinder.
+    /// @param segments      number of faces on the side when generating a polyhedral approximation.
+    Cylinder(dolfin::Point top,
+             dolfin::Point bottom,
+             double top_radius,
+             double bottom_radius,
+             std::size_t segments=32);
+
+    /// @brief  Informal string representation
+    /// @param  verbose Verbosity level
+    /// @return The description string
+    std::string str(bool verbose) const;
+
+    Type getType() const
+    { return CSGGeometry::Cylinder; }
+
+    const dolfin::Point _top, _bottom;
+    const double _top_radius, _bottom_radius;
+    const std::size_t _segments;
+  };
+
+  /// @brief A 3D cone.
+  /// A cone is here just a special case of a cylinder.
+  ///
+  /// { "small-icon" : "cone-small.png" }
+  class Cone : public Cylinder
+  {
+  public:
+
+    /// @brief Create cone defined by upper and lower center and bottom radius respectively.
+    /// @param top      Center at top of cone.
+    /// @param bottom   Center at top of cone.
+    /// @param r        bottom radius of cone.
+    /// @param segments number of faces on the side when generating a polyhedral approximation.
+    Cone(dolfin::Point top, dolfin::Point bottom, double r, std::size_t segments=32)
+      : Cylinder(top, bottom, r, 0, segments) {}
+  };
+
+  /// @brief A 3D tetrahedron
+  ///
+  /// { "small-icon" : "tetrahedron-small.png" }
+  class Tetrahedron : public CSGPrimitive3D
+  {
+  public:
+    /// @brief Create tetrahedron defined by four corner points.
+    ///
+    /// @param a Point
+    /// @param b Point
+    /// @param c Point
+    /// @param d Point
+    Tetrahedron(dolfin::Point a,
+                dolfin::Point b,
+                dolfin::Point c,
+                dolfin::Point d);
+
+    /// @brief Informal string representation
+    /// @return The description string
+    std::string str(bool verbose) const;
+
+    Type getType() const
+    { return CSGGeometry::Tetrahedron; }
+
+    const dolfin::Point a, b, c, d;
+  };
+
+  /// @brief A triangular 3D surface read from file.
+  ///
+  /// { "small-icon" : "disk-small.png" }
+  class Surface3D : public CSGPrimitive3D
+  {
+  public:
+    Surface3D(std::string filename);
+
+    // Create triangulated polyhedron from surface of mesh
+    Surface3D(std::shared_ptr<const dolfin::Mesh> mesh);
+
+    // Create triangulate polyhedron on surface of subdomain of mesh
+    Surface3D(std::shared_ptr<const dolfin::Mesh> mesh, std::size_t cell_domain);
+
+    /// @brief Informal string representation
+    /// @return The description string
+    std::string str(bool verbose) const;
+
+    Type getType() const
+    { return CSGGeometry::Surface3D; }
+
+    const std::string _filename;
+    std::shared_ptr<const dolfin::Mesh> mesh;
+
+    /// @brief Tolerance when merging close vertices
+    double vertex_tolerance;
+
+    /// @brief Tolerance when removing degenerate facets
+    double degenerate_tolerance;
+
+    /// @brief Attempt to repair if surface is not topologically valid
+    bool repair;
+    
+    // @brief Read only one connected_component. Only relevant if repair==true
+    bool single_connected_component;
+
+    int sharp_features_filter;
+    
+    /// @brief First facet, when reading only one connect component.
+    std::size_t first_facet;
+
+    /// @brief Flip all facets
+    bool flip_facets;
+
+    /// Dump read triangles and edges to off file (usefull for debugging)
+    std::string debug_dump;
+
+    std::size_t cell_domain;
+    bool use_cell_domain;
+  };
+
+  /// @brief An axis-aligned ellipsoid
+  class Ellipsoid : public CSGPrimitive3D
+  {
+   public:
+    /// @brief Create axis aligned ellipsoid
+    ///
+    /// @param center center of ellipsoid
+    /// @param a semi-principal axis in x direction
+    /// @param b semi-principal axis in y direction
+    /// @param c semi-principal axis in z direction
+    /// @param segments resolution when generating a polyhedral appoximation
+    Ellipsoid(dolfin::Point center, double a, double b, double c, std::size_t segments=17);
+
+    /// @brief Informal string representation
+    /// @return The description string
+    std::string str(bool verbose) const;
+
+    Type getType() const
+    { return CSGGeometry::Ellipsoid; }
+
+    const dolfin::Point center;
+    const double a, b, c;
+    const std::size_t _segments;
+  };
+
+  /// @brief A 2D polygon extruded along the z axis to 3D
+  class Extrude2D : public CSGPrimitive3D
+  {
+   public :
+    Extrude2D(std::shared_ptr<CSGGeometry>, double z);
+
+    /// @brief Informal string representation
+    /// @return The description string
+    std::string str(bool verbose) const;
+
+    Type getType() const
+    { return CSGGeometry::Extrude2D; }
+
+    std::shared_ptr<CSGGeometry> geometry_2d;
+    const double z;
+  };
+}
+
+#endif
diff --git a/include/mshr/DolfinMeshUtils.h b/include/mshr/DolfinMeshUtils.h
new file mode 100644 (file)
index 0000000..0029841
--- /dev/null
@@ -0,0 +1,66 @@
+// Copyright (C) 2014-2016 Benjamin Kehlet
+//
+// This file is part of mshr.
+//
+// mshr 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 3 of the License, or
+// (at your option) any later version.
+// 
+// mshr 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 mshr.  If not, see <http://www.gnu.org/licenses/>.
+//
+
+#ifndef __MSHR_DOLFIN_MESH_UTILS_H
+#define __MSHR_DOLFIN_MESH_UTILS_H
+
+#include <utility>
+#include <memory>
+
+namespace dolfin { class Mesh; }
+
+namespace mshr
+{
+
+class DolfinMeshUtils
+{
+ public:
+  /// Compute the smallest and largest cell wrt. volume.
+  /// @param m The mesh
+  static std::pair<double, double> cell_volume_min_max(const dolfin::Mesh& m);
+
+  /// Check that all vertices has at least one incident cell
+  /// @param m The mesh
+  static bool has_isolated_vertices(const dolfin::Mesh& m);
+
+  /// Run all implemented checks mesh consistency
+  /// @param m The mesh
+  static bool check_mesh(const dolfin::Mesh& m);
+
+  static std::shared_ptr<dolfin::Mesh>
+    extract_subdomain(std::shared_ptr<const dolfin::Mesh>,
+                      std::size_t cell_domain);
+
+  /// @brief Glue together two meshes by matching boundary vertices.
+  /// @param m1 Mesh 1 to merge
+  /// @param m2 Mesh 2 to merge
+  /// @param m1_boundary_marker Mark boundary facets the belongs to m1. A value < 0 disables marking.
+  /// @param m1_boundary_marker Mark boundary facets the belongs to m2. A value < 0 disables marking.
+  /// @param m1_boundary_marker Mark boundary facets the belongs to the interface between m1 an m2. A value < 0 disables marking.
+  static std::shared_ptr<dolfin::Mesh>
+    merge_meshes(std::shared_ptr<dolfin::Mesh> m1,
+                 std::shared_ptr<dolfin::Mesh> m2,
+                 int m1_marker=1,
+                 int m2_marker=2,
+                 int m1_boundary_marker=1,
+                 int m2_boundary_marker=2,
+                 int interface_marker=3);
+};
+
+}
+#endif
diff --git a/include/mshr/GlobalInitializer.h b/include/mshr/GlobalInitializer.h
new file mode 100644 (file)
index 0000000..ad57445
--- /dev/null
@@ -0,0 +1,31 @@
+// Copyright (C) 2014 Benjamin Kehlet
+//
+// This file is part of mshr.
+//
+// mshr 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 3 of the License, or
+// (at your option) any later version.
+// 
+// mshr 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 mshr.  If not, see <http://www.gnu.org/licenses/>.
+
+#ifndef __MSHR_GLOBALINITIALIZER_H
+#define __MSHR_GLOBALINITIALIZER_H
+
+class GlobalInitializer
+{
+ public:
+  GlobalInitializer();
+  ~GlobalInitializer();
+
+  /// The singleton instance of the GlobalInitializer.
+  static GlobalInitializer& instance();
+};
+
+#endif
diff --git a/include/mshr/MeshGenerator.h b/include/mshr/MeshGenerator.h
new file mode 100644 (file)
index 0000000..7cf3c87
--- /dev/null
@@ -0,0 +1,41 @@
+// Copyright (C) 2012 Anders Logg and 2012-2014 Benjamin Kehlet
+//
+// This file is part of mshr.
+//
+// mshr 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 3 of the License, or
+// (at your option) any later version.
+// 
+// mshr 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 mshr. If not, see <http://www.gnu.org/licenses/>.
+//
+
+
+#ifndef __MSHR_MESH_GENERATOR_H
+#define __MSHR_MESH_GENERATOR_H
+
+#include "CSGGeometry.h"
+
+namespace dolfin
+{
+  // Forward declarations
+  class Mesh;
+}
+
+namespace mshr
+{
+
+  /// Generate mesh from CSG geometry
+  std::shared_ptr<dolfin::Mesh>
+    generate_mesh(std::shared_ptr<const CSGGeometry> geometry,
+                  double resolution,
+                  std::string backend="cgal");
+}
+
+#endif
diff --git a/include/mshr/Meshes.h b/include/mshr/Meshes.h
new file mode 100644 (file)
index 0000000..1bd0695
--- /dev/null
@@ -0,0 +1,27 @@
+// Copyright (C) -2014 Benjamin Kehlet
+//
+// This file is part of mshr.
+//
+// mshr 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 3 of the License, or
+// (at your option) any later version.
+// 
+// mshr 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 mshr. If not, see <http://www.gnu.org/licenses/>.
+
+#include <dolfin/mesh/Mesh.h>
+
+namespace mshr
+{
+  class UnitSphereMesh : public dolfin::Mesh
+  {
+   public:
+    UnitSphereMesh(std::size_t resolution);
+  };
+}
diff --git a/include/mshr/OFFFileReader.h b/include/mshr/OFFFileReader.h
new file mode 100644 (file)
index 0000000..6b985b7
--- /dev/null
@@ -0,0 +1,47 @@
+// Copyright (C) 2015 Benjamin Kehlet
+//
+// This file is part of mshr.
+//
+// mshr 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 3 of the License, or
+// (at your option) any later version.
+// 
+// mshr 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 mshr.  If not, see <http://www.gnu.org/licenses/>.
+//
+
+#ifndef __OFF_FILE_READER_H
+#define __OFF_FILE_READER_H
+
+#include <string>
+#include <vector>
+#include <array>
+
+namespace mshr
+{
+
+class OFFFileReader
+{
+ public:
+  /// @brief Read and parse a triangular 3d surface off file
+  /// @param filename The file to read
+  /// @param vertices A vector of points to be read into
+  /// @param facets A vector of facets given as indices to the vertex array.
+  static void read(const std::string filename, 
+                   std::vector<std::array<double, 3> >& vertices,
+                   std::vector<std::array<std::size_t, 3> >& facets);
+
+  static void write(const std::string filename,
+                    const std::vector<std::array<double, 3> >& vertices,
+                    const std::vector<std::array<std::size_t, 3> >& facets);
+
+};
+
+}
+#endif
diff --git a/include/mshr/STLFileReader.h b/include/mshr/STLFileReader.h
new file mode 100644 (file)
index 0000000..0a00ee5
--- /dev/null
@@ -0,0 +1,48 @@
+// Copyright (C) 2014 Benjamin Kehlet & 2016 Lars Magnus Valnes
+//
+// This file is part of mshr.
+//
+// mshr 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 3 of the License, or
+// (at your option) any later version.
+// 
+// mshr 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 mshr.  If not, see <http://www.gnu.org/licenses/>.
+//
+
+#ifndef __STL_FILE_READER_H
+#define __STL_FILE_READER_H
+
+#include <string>
+#include <vector>
+#include <array>
+
+#include <boost/tuple/tuple.hpp>
+
+namespace mshr
+{
+
+class STLFileReader
+{
+public:
+
+  /// @brief Parse STL file.
+  /// @param filename The file to be read
+  /// @param vertices array to return vertices in
+  /// @param facets array to return facets in as indices to the vertex array
+  static void read(const std::string filename, 
+                   std::vector<std::array<double, 3> >& vertices,
+                   std::vector<std::array<std::size_t, 3> >& facets);
+  static void write(const std::string filename, 
+                   std::vector<std::array<double, 3> >& vertices,
+                   std::vector<std::array<std::size_t, 3> >& facets);
+};
+
+}
+#endif
diff --git a/include/mshr/SurfaceConsistency.h b/include/mshr/SurfaceConsistency.h
new file mode 100644 (file)
index 0000000..285a153
--- /dev/null
@@ -0,0 +1,64 @@
+ // Copyright (C) 2014 Benjamin Kehlet
+ //
+ // This file is part of mshr.
+ //
+ // mshr 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 3 of the License, or
+ // (at your option) any later version.
+ //
+ // mshr 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 mshr.  If not, see <http://www.gnu.org/licenses/>.
+
+ // OBS! Experimental
+
+ #ifndef _SURFACE_CONSISTENCY_H
+ #define _SURFACE_CONSISTENCY_H
+
+ #include <vector>
+ #include <set>
+ #include <array>
+ #include <memory>
+
+ namespace mshr
+ {
+
+ class SurfaceConsistency
+ {
+  public:
+
+   /// Check that the connectivity of the facet is consistent, ie. all edges are
+   /// shared by exactly two facets.
+   /// If error is set to True, then an error will be thrown when a duplicated
+   /// halfedges is encountered. Otherwise, the index of one of the facets will
+   /// be stored in the set.
+   static void checkConnectivity(std::vector<std::array<std::size_t, 3> >& facets,
+                                 std::set<std::size_t>& duplicating,
+                                 bool error);
+
+   static void filterFacets(const std::vector<std::array<std::size_t, 3> >& facets,
+                            const std::vector<std::array<double, 3> >& vertices,
+                            std::size_t start, std::set<std::size_t>& skip);
+
+   static std::pair<std::unique_ptr<std::vector<std::array<double, 3> > >,
+                    std::unique_ptr<std::vector<std::array<std::size_t, 3> > > >
+     merge_close_vertices(const std::vector<std::array<std::size_t, 3> >& facets,
+                          const std::vector<std::array<double, 3> >& vertices,
+                          double tolerance);
+
+   static std::size_t remove_null_facets(std::vector<std::array<std::size_t, 3>>& facets);
+
+   static std::size_t remove_isolated_vertices(std::vector<std::array<double, 3>>& vertices,
+                                               std::vector<std::array<std::size_t, 3>>& facets);
+
+   static void orient_component(std::vector<std::array<std::size_t, 3> >& facets,
+                                std::size_t start);
+};
+
+}
+#endif
diff --git a/include/mshr/SurfaceReconstruction.h b/include/mshr/SurfaceReconstruction.h
new file mode 100644 (file)
index 0000000..4837a0a
--- /dev/null
@@ -0,0 +1,46 @@
+// Copyright (C) 2015 Benjamin Kehlet
+//
+// This file is part of mshr.
+//
+// mshr 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 3 of the License, or
+// (at your option) any later version.
+//
+// mshr 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 mshr.  If not, see <http://www.gnu.org/licenses/>.
+//
+
+#ifndef __MSHR_SURFACERECONSTRUCTION_H
+#define __MSHR_SURFACERECONSTRUCTION_H
+
+#include <vector>
+#include <array>
+
+namespace mshr
+{
+  class SurfaceReconstruction
+  {
+   public:
+    static void reconstruct(const std::vector<double>& vertices,
+                            const std::vector<std::size_t>& facets,
+                            std::vector<std::array<double, 3>>& reconstructed_vertices,
+                            std::vector<std::array<std::size_t, 3>>& reconstruct_facets,
+                            double expansion);
+
+    static void remesh(double edge_length,
+                       double sharp_edge_tolerance,
+                       const std::vector<double>& vertices,
+                       const std::vector<std::size_t>& facets,
+                       std::vector<std::array<double, 3>>& remeshed_vertices,
+                       std::vector<std::array<std::size_t, 3>>& remeshed_facets);
+  };
+
+}
+
+#endif
diff --git a/include/mshr/TetgenMeshGenerator3D.h b/include/mshr/TetgenMeshGenerator3D.h
new file mode 100644 (file)
index 0000000..84bcda6
--- /dev/null
@@ -0,0 +1,61 @@
+// Copyright (C) 2012-2015 Benjamin Kehlet
+//
+// This file is part of mshr.
+//
+// mshr 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 3 of the License, or
+// (at your option) any later version.
+// 
+// mshr 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 mshr.  If not, see <http://www.gnu.org/licenses/>.
+
+#ifndef __MSHR_TETGEN_MESH_GENERATOR3D_H
+#define __MSHR_TETGEN_MESH_GENERATOR3D_H
+
+#include <mshr/CSGCGALDomain3D.h>
+
+#include <dolfin/common/Variable.h>
+#include <memory>
+
+namespace dolfin{ class Mesh; }
+
+namespace mshr
+{
+
+  // Forward declaration
+  class CSGGeometry;
+
+  class TetgenMeshGenerator3D : public dolfin::Variable
+  {
+  public :
+    TetgenMeshGenerator3D();
+    ~TetgenMeshGenerator3D();
+
+    std::shared_ptr<dolfin::Mesh> generate(std::shared_ptr<const CSGCGALDomain3D> domain) const;
+
+    /// Default parameter values
+    static dolfin::Parameters default_parameters()
+    {
+      dolfin::Parameters p("tetgen_meshgenerator");
+      p.add("mesh_resolution", 64.0);
+
+      p.add("disable_quality_improvement", false);
+      p.add("preserve_surface", false);
+      p.add("max_radius_edge_ratio", 2.);
+      p.add("min_dihedral_angle", 12.);
+
+      // If set to a positive value, this will override "mesh_resolution"
+      p.add("max_tet_volume", -1.0);
+
+      return p;
+    }
+  };
+}
+
+#endif
diff --git a/mshr-config.cmake.in b/mshr-config.cmake.in
new file mode 100644 (file)
index 0000000..7935ef0
--- /dev/null
@@ -0,0 +1,17 @@
+# - Config file for the mshr package
+# It defines the following variables
+#  MSHR_INCLUDE_DIRS  - include directories for mshr
+#  MSHR_LIBRARIES_DIR - directory where the mshr library is located
+#  MSHR_LIBRARIES     - libraries to link against
+# Compute paths
+get_filename_component(MSHR_CMAKE_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH)
+set(MSHR_INCLUDE_DIRS "@CONF_INCLUDE_DIRS@")
+set(MSHR_EXTERNAL_INCLUDE_DIRS "@CONF_EXTERNAL_INCLUDE_DIRS@")
+set(MSHR_LIBRARIES_DIRS "@CONF_LIBRARIES_DIRS@")
+set(MSHR_EXTERNAL_LIBRARIES "@CONF_EXTERNAL_LIBRARIES@")
+set(MSHR_CXX_DEFINITIONS "@CONF_CXX_DEFINITIONS@")
+set(MSHR_CXX_FLAGS "@CONF_CXX_FLAGS@")
+set(MSHR_LIBRARIES mshr)
+
+set(MSHR_USE_FILE "${MSHR_CMAKE_DIR}/use-mshr.cmake")
\ No newline at end of file
diff --git a/mshrConfig.cmake.in b/mshrConfig.cmake.in
new file mode 100644 (file)
index 0000000..9d27c51
--- /dev/null
@@ -0,0 +1,15 @@
+# - Config file for the mshr package
+# It defines the following variables
+#  MSHR_INCLUDE_DIRS  - include directories for mshr
+#  MSHR_LIBRARIES_DIR - directory where the mshr library is located
+#  MSHR_LIBRARIES     - libraries to link against
+
+# Compute paths
+get_filename_component(MSHR_CMAKE_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH)
+set(mshr_INCLUDE_DIRS "@CONF_INCLUDE_DIRS@")
+set(mshr_EXTERNAL_INCLUDE_DIRS "@CONF_EXTERNAL_INCLUDE_DIRS@")
+set(mshr_LIBRARIES_DIRS "@CONF_LIBRARIES_DIRS@")
+set(mshr_EXTERNAL_LIBRARIES "@CONF_EXTERNAL_LIBRARIES@")
+set(mshr_CXX_DEFINITIONS "@CONF_CXX_DEFINITIONS@")
+set(mshr_CXX_FLAGS "@CONF_CXX_FLAGS@")
+set(mshr_LIBRARIES mshr)
diff --git a/python/CMakeLists.txt b/python/CMakeLists.txt
new file mode 100644 (file)
index 0000000..4edf566
--- /dev/null
@@ -0,0 +1,32 @@
+cmake_minimum_required(VERSION 3.5.0)
+
+
+# This script is used solely for getting the paths to the dependencies
+# of the bindings (ie. pybind11, dolfin and mshr).
+# This is written to a json file which is read from setup.py.
+
+PROJECT(mshr_pybind11_config)
+
+# Add cmake directory to mshr module path
+list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake")
+
+#   pybind11_FOUND - true if pybind11 and all required components found on the system
+#   pybind11_VERSION - pybind11 version in format Major.Minor.Release
+#   pybind11_INCLUDE_DIRS - Directories where pybind11 and python headers are located.
+#   pybind11_INCLUDE_DIR - Directory where pybind11 headers are located.
+#   pybind11_DEFINITIONS - Definitions necessary to use pybind11, namely USING_pybind11.
+#   pybind11_LIBRARIES - compile flags and python libraries (as needed) to link against.
+#   pybind11_LIBRARY - empty.
+#   CMAKE_MODULE_PATH - appends location of accompanying FindPythonLibsNew.cmake and
+#                       pybind11Tools.cmake modules.
+find_package(pybind11 CONFIG HINTS ${PYBIND11_DIR} ${PYBIND11_ROOT}
+  $ENV{PYBIND11_DIR} $ENV{PYBIND11_ROOT})
+
+
+find_package(DOLFIN)
+
+find_package(mshr MODULE)
+
+configure_file("config.json.in" "config.json")
+
+
diff --git a/python/cmake/Findmshr.cmake b/python/cmake/Findmshr.cmake
new file mode 100644 (file)
index 0000000..21737fd
--- /dev/null
@@ -0,0 +1,51 @@
+#.rst:
+# Findmshr
+# --------
+#
+# Find mshr library
+#
+# Find the mshr includes and library. This module defines
+#
+# ::
+#
+#   mshr_INCLUDE_DIRS, where to find mshr.h.
+#   mshr_LIBRARIES, libraries to link against to use mshr
+#   mshr_FOUND, If false (0), do not try to use mshr.
+#
+#
+#
+#
+#
+#=============================================================================
+find_path(mshr_INCLUDE_DIR mshr.h
+          DOC "The mshr include directory")
+
+set(mshr_NAMES ${mshr_NAMES} libmshr mshr)
+find_library(mshr_LIBRARY NAMES ${mshr_NAMES}
+            DOC "The mshr library")
+
+# handle the QUIETLY and REQUIRED arguments and set mshr_FOUND to TRUE if
+# all listed variables are TRUE
+include(FindPackageHandleStandardArgs)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(mshr
+                                  REQUIRED_VARS mshr_LIBRARY
+                                                mshr_INCLUDE_DIR
+                                  VERSION_VAR mshr_VERSION_STRING)
+
+if(mshr_FOUND)
+  # FIND_PACKAGE_HANDLE_STANDARD_ARGS sets mshr_FOUND to TRUE not 1
+  # which interferes with the json in config.json (must be true not TRUE)
+  # So set to 1 (following find_package(DOLFIN) )
+  set( mshr_FOUND 1 )
+  # use by setuptools.Extension, mshr_LIBRARIES must be in a form that appends to -l
+  # i.e. mshr not libmshr.so
+  set( mshr_LIBRARIES "mshr" )
+  get_filename_component( mshr_LIBRARIES_DIRS ${mshr_LIBRARY} DIRECTORY )
+  set( mshr_INCLUDE_DIRS ${mshr_INCLUDE_DIR} )
+else()
+  set( mshr_FOUND 0)
+  set( mshr_LIBRARIES_DIRS "." )
+  set( mshr_INCLUDE_DIRS "." )
+endif()
+
+mark_as_advanced(mshr_INCLUDE_DIR mshr_LIBRARY)
diff --git a/python/config.json.in b/python/config.json.in
new file mode 100644 (file)
index 0000000..b12229b
--- /dev/null
@@ -0,0 +1,16 @@
+{
+    "pybind11" : { "found"        : ${pybind11_FOUND},
+                  "version"      : "${pybind11_VERSION}",
+                  "include_dir"  : "${pybind11_INCLUDE_DIRS}",
+                  "include_dirs" : "${pybind11_INCLUDE_DIR}",
+                  "definitions"  : "${pybind11_DEFINITIONS}"
+                 },
+    "dolfin"   : { "found"        : ${DOLFIN_FOUND},
+                  "include_dirs" : "${DOLFIN_INCLUDE_DIRS}"
+                },
+    "mshr"     : { "found"        : ${mshr_FOUND},
+                  "include_dirs" : "${mshr_INCLUDE_DIRS}",
+                  "lib_dirs"     : "${mshr_LIBRARIES_DIRS}",
+                  "libs"         : "${mshr_LIBRARIES}"
+                }
+}
diff --git a/python/mshr/__init__.py b/python/mshr/__init__.py
new file mode 100644 (file)
index 0000000..33a2b68
--- /dev/null
@@ -0,0 +1,56 @@
+# -*- coding: utf-8 -*-
+"""mshr package"""
+
+# Copyright (C) 2017 Benjamin Kehlet
+
+# This file is part of mshr.
+#
+# mshr 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 3 of the License, or
+# (at your option) any later version.
+#
+# mshr 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 mshr.  If not, see <http:#www.gnu.org/licenses/>.
+#
+
+import dolfin
+
+from .cpp import Circle
+from .cpp import Ellipse
+from .cpp import Rectangle
+from .cpp import Polygon
+from .cpp import Sphere
+from .cpp import Box
+from .cpp import Cylinder
+from .cpp import Cone
+from .cpp import Tetrahedron
+from .cpp import Surface3D
+from .cpp import Ellipsoid
+from .cpp import Rectangle
+from .cpp import Extrude2D
+from .cpp import CSGCGALDomain3D
+
+from .cpp import CSGIntersection
+from .cpp import CSGDifference
+from .cpp import CSGUnion
+from .cpp import CSGScaling
+from .cpp import CSGTranslation
+from .cpp import CSGRotation
+
+from .cpp import CSGGeometries
+from .cpp import UnitSphereMesh
+
+from .cpp import CSGCGALMeshGenerator3D
+from .cpp import TetgenMeshGenerator3D
+
+from .cpp import CSGCGALDomain2D
+from .cpp import CSGCGALMeshGenerator2D
+
+
+from .cpp import generate_mesh
diff --git a/python/setup.py b/python/setup.py
new file mode 100644 (file)
index 0000000..2ead3e7
--- /dev/null
@@ -0,0 +1,43 @@
+import os, sys
+import subprocess
+import json
+
+from setuptools import setup, Extension
+
+
+# Call cmake to generate json file with include and link information about dolfin and pybind11
+if not os.path.isfile(os.path.join("build", "config.json")) :
+    if not os.path.exists("build") :
+        os.mkdir("build")
+    cmake_command=["cmake", os.getcwd()]
+    if os.environ.get('CMAKE_PREFIX_PATH'):
+        cmake_command.extend(['-DCMAKE_PREFIX_PATH={}'.format(os.environ['CMAKE_PREFIX_PATH'])])
+    subprocess.check_call(cmake_command, cwd=os.path.abspath("build"))
+
+with open(os.path.join("build", "config.json"), 'r') as infile :
+    config = json.load(infile)
+
+include_dirs = config["pybind11"]["include_dirs"].split(";") + \
+               config["dolfin"]["include_dirs"].split(";")   + \
+               config["mshr"]["include_dirs"].split(";")
+
+
+mshr_ext = Extension('mshr.cpp',
+                     ['src/mshr.cpp'],
+                     include_dirs=include_dirs,
+                     library_dirs=config['mshr']['lib_dirs'].split(";"),
+                     libraries=config['mshr']['libs'].split(";"),
+                     extra_compile_args=['-std=c++11'],
+                     language='c++11')
+
+
+setup(name             = 'mshr',
+      version          = '2019.2.0.dev0',
+      author           = 'FEniCS Project',
+      description      = 'mshr python interface (via pybind11)',
+      long_description = '',
+      packages         = ["mshr",],
+      ext_modules      = [mshr_ext],
+      install_requires = ["numpy", "fenics-dolfin"]
+      #zip_safe         = False)
+      )
diff --git a/python/src/mshr.cpp b/python/src/mshr.cpp
new file mode 100644 (file)
index 0000000..1bb24c2
--- /dev/null
@@ -0,0 +1,214 @@
+#include <pybind11/pybind11.h>
+#include <pybind11/operators.h>
+#include <pybind11/stl.h>
+
+#include <mshr/CSGGeometry.h>
+#include <mshr/CSGPrimitives2D.h>
+#include <mshr/CSGPrimitives3D.h>
+#include <mshr/CSGCGALDomain2D.h>
+#include <mshr/CSGCGALDomain3D.h>
+#include <mshr/CSGOperators.h>
+#include <mshr/MeshGenerator.h>
+#include <mshr/CSGGeometries3D.h>
+#include <mshr/CSGCGALMeshGenerator3D.h>
+#include <mshr/CSGCGALMeshGenerator2D.h>
+#include <mshr/TetgenMeshGenerator3D.h>
+#include <mshr/Meshes.h>
+
+namespace py = pybind11;
+
+
+PYBIND11_MODULE(cpp, m)
+{
+  // Create module for C++ wrappers
+  m.doc() ="mshr python interface";
+
+  // CSGGeometry
+  py::class_<mshr::CSGGeometry, dolfin::Variable,
+             std::shared_ptr<mshr::CSGGeometry>> (m, "CSGGeometry")
+    .def("dim", &mshr::CSGGeometry::dim)
+    .def("set_subdomain",
+         static_cast<void(mshr::CSGGeometry::*)(std::size_t i,
+                                                std::shared_ptr<mshr::CSGGeometry> s)>(&mshr::CSGGeometry::set_subdomain))
+    .def("has_subdomains", &mshr::CSGGeometry::has_subdomains)
+    .def("inside", static_cast<bool (mshr::CSGGeometry::*)(dolfin::Point) const>(&mshr::CSGGeometry::inside))
+    .def("__mul__",
+         static_cast<std::shared_ptr<mshr::CSGIntersection>(*)(std::shared_ptr<mshr::CSGGeometry>,
+                                                               std::shared_ptr<mshr::CSGGeometry>)>(&mshr::operator*),
+         py::is_operator())
+
+    .def("__mul__",
+         static_cast<std::shared_ptr<mshr::CSGScaling>(*)(std::shared_ptr<mshr::CSGGeometry>,
+                                                          double)>(&mshr::operator*),
+         py::is_operator())
+
+    .def("__add__",
+         static_cast<std::shared_ptr<mshr::CSGUnion>(*)(std::shared_ptr<mshr::CSGGeometry>,
+                                                        std::shared_ptr<mshr::CSGGeometry>)>(&mshr::operator+),
+         py::is_operator())
+
+    .def("__sub__",
+         static_cast<std::shared_ptr<mshr::CSGDifference>(*)(std::shared_ptr<mshr::CSGGeometry>,
+                                                             std::shared_ptr<mshr::CSGGeometry>)>(&mshr::operator-),
+         py::is_operator());
+
+
+  py::class_<mshr::CSGUnion, mshr::CSGGeometry,
+             std::shared_ptr<mshr::CSGUnion>>(m, "CSGUnion");
+
+  py::class_<mshr::CSGIntersection, mshr::CSGGeometry,
+             std::shared_ptr<mshr::CSGIntersection>>(m, "CSGIntersection");
+
+  py::class_<mshr::CSGDifference, mshr::CSGGeometry,
+             std::shared_ptr<mshr::CSGDifference>>(m, "CSGDifference");
+
+  py::class_<mshr::CSGScaling, mshr::CSGGeometry,
+             std::shared_ptr<mshr::CSGScaling>>(m, "CSGScaling")
+    .def(py::init<std::shared_ptr<mshr::CSGGeometry>, double>());
+
+  py::class_<mshr::CSGTranslation, mshr::CSGGeometry,
+             std::shared_ptr<mshr::CSGTranslation>>(m, "CSGTranslation")
+    .def(py::init<std::shared_ptr<mshr::CSGGeometry>, dolfin::Point>());
+
+  py::class_<mshr::CSGRotation, mshr::CSGGeometry,
+             std::shared_ptr<mshr::CSGRotation>>(m, "CSGRotation")
+    .def(py::init<std::shared_ptr<mshr::CSGGeometry>, dolfin::Point, double>())
+   .def(py::init<std::shared_ptr<mshr::CSGGeometry>, double>());
+
+
+
+  // Circle
+  py::class_<mshr::Circle, mshr::CSGGeometry,
+    std::shared_ptr<mshr::Circle>>(m, "Circle")
+    .def(py::init<dolfin::Point, double, std::size_t>(),
+         py::arg("c"), py::arg("r"), py::arg("segments")=0)
+    .def("center", &mshr::Circle::center)
+    .def("radius", &mshr::Circle::radius);
+
+  // Ellipse
+  py::class_<mshr::Ellipse, mshr::CSGGeometry,
+             std::shared_ptr<mshr::Ellipse>>(m, "Ellipse")
+    .def(py::init<dolfin::Point, double, double, std::size_t>(),
+         py::arg("c"), py::arg("a"), py::arg("b"), py::arg("segments")=0)
+    .def("center", &mshr::Ellipse::center)
+    .def("a", &mshr::Ellipse::a)
+    .def("b", &mshr::Ellipse::b);
+
+  // Rectangle
+  py::class_<mshr::Rectangle, mshr::CSGGeometry,
+             std::shared_ptr<mshr::Rectangle>> (m, "Rectangle")
+    .def(py::init<dolfin::Point, dolfin::Point>())
+    .def("first_corner", &mshr::Rectangle::first_corner)
+    .def("second_corne", &mshr::Rectangle::second_corner);
+
+  // Polygon
+  py::class_<mshr::Polygon, mshr::CSGGeometry,
+             std::shared_ptr<mshr::Polygon>>(m, "Polygon")
+    .def(py::init<std::vector<dolfin::Point>&>())
+    .def("ccw", &mshr::Polygon::ccw)
+    .def("vertices", &mshr::Polygon::vertices);
+
+  // Sphere
+  py::class_<mshr::Sphere, mshr::CSGGeometry,
+             std::shared_ptr<mshr::Sphere>>(m, "Sphere")
+    .def(py::init<dolfin::Point, double, std::size_t>(),
+         py::arg("center"), py::arg("radius"), py::arg("segments")=10);
+
+  // Box
+  py::class_<mshr::Box, mshr::CSGGeometry,
+             std::shared_ptr<mshr::Box>>(m, "Box")
+    .def(py::init<dolfin::Point, dolfin::Point>());
+
+  // Cylinder
+  py::class_<mshr::Cylinder, mshr::CSGGeometry,
+             std::shared_ptr<mshr::Cylinder>>(m, "Cylinder")
+    .def(py::init<dolfin::Point, dolfin::Point, double, double, std::size_t>(),
+         py::arg("top"),
+         py::arg("bottom"),
+         py::arg("top_radius"),
+         py::arg("bottom_radius"),
+         py::arg("segments")=32);
+
+  // Cone
+  py::class_<mshr::Cone, mshr::Cylinder,
+             std::shared_ptr<mshr::Cone>>(m, "Cone")
+    .def(py::init<dolfin::Point, dolfin::Point, double, std::size_t>(),
+         py::arg("top"), py::arg("bottom"), py::arg("r"), py::arg("segments")=32);
+
+  // Tetrahedron
+  py::class_<mshr::Tetrahedron, mshr::CSGGeometry,
+             std::shared_ptr<mshr::Tetrahedron>>(m, "Tetrahedron")
+    .def(py::init<dolfin::Point, dolfin::Point, dolfin::Point, dolfin::Point>());
+
+  // Surface3D (deprecated, use CSGCGALDomain3D)
+  py::class_<mshr::Surface3D, mshr::CSGGeometry,
+             std::shared_ptr<mshr::Surface3D>>(m, "Surface3D")
+    .def(py::init<std::string>());
+
+  // Ellipsoid
+  py::class_<mshr::Ellipsoid, mshr::CSGGeometry,
+             std::shared_ptr<mshr::Ellipsoid>>(m, "Ellipsoid")
+    .def(py::init<dolfin::Point, double, double, double, std::size_t>(),
+         py::arg("center"),
+         py::arg("a"), py::arg("b"), py::arg("c"), py::arg("segments")=15);
+
+  // Extrude2D
+  py::class_<mshr::Extrude2D, mshr::CSGGeometry,
+             std::shared_ptr<mshr::Extrude2D>>(m, "Extrude2D")
+    .def(py::init<std::shared_ptr<mshr::CSGGeometry>, double>());
+
+  // CSGCGALDomain3D
+  py::class_<mshr::CSGCGALDomain3D, mshr::CSGGeometry,
+             std::shared_ptr<mshr::CSGCGALDomain3D>>(m, "CSGCGALDomain3D")
+    .def(py::init<std::shared_ptr<const mshr::CSGGeometry>>())
+    .def("num_vertices", &mshr::CSGCGALDomain3D::num_vertices)
+    .def("num_facets", &mshr::CSGCGALDomain3D::num_facets)
+    .def("num_halfedges", &mshr::CSGCGALDomain3D::num_halfedges)
+    .def("num_degenerate_facets", &mshr::CSGCGALDomain3D::num_degenerate_facets)
+    .def("facet_area_minmax", &mshr::CSGCGALDomain3D::facet_area_minmax)
+    .def("edge_length_minmax", &mshr::CSGCGALDomain3D::edge_length_range)
+    .def("num_short_edges", &mshr::CSGCGALDomain3D::num_short_edges)
+    .def("volume", &mshr::CSGCGALDomain3D::volume)
+    .def("ensure_meshing_preconditions", &mshr::CSGCGALDomain3D::ensure_meshing_preconditions)
+    .def("is_selfintersecting", &mshr::CSGCGALDomain3D::is_selfintersecting)
+    .def("remove_selfintersectione", &mshr::CSGCGALDomain3D::remove_selfintersections)
+    .def("save", &mshr::CSGCGALDomain3D::save)
+    .def("num_disconnected_components", &mshr::CSGCGALDomain3D::num_disconnected_components)
+    .def("num_holes", &mshr::CSGCGALDomain3D::num_holes)
+    .def("remesh_surface", &mshr::CSGCGALDomain3D::remesh_surface)
+    .def("remove_degenerate_facets", &mshr::CSGCGALDomain3D::remove_degenerate_facets)
+    .def("convex_hull", static_cast<std::shared_ptr<mshr::CSGCGALDomain3D>(mshr::CSGCGALDomain3D::*)() const>(&mshr::CSGCGALDomain3D::convex_hull))
+    ;
+
+  py::class_<mshr::CSGGeometries>(m, "CSGGeometries")
+    .def_static("lego", &mshr::CSGGeometries::lego)
+    .def_static("propeller", &mshr::CSGGeometries::propeller);
+
+  py::class_<mshr::UnitSphereMesh>(m, "UnitSphereMesh")
+    .def(py::init<std::size_t>());
+
+  py::class_<mshr::CSGCGALMeshGenerator3D, dolfin::Variable,
+            std::shared_ptr<mshr::CSGCGALMeshGenerator3D>>(m, "CSGCGALMeshGenerator3D")
+    .def(py::init<>())
+    .def("generate", static_cast<std::shared_ptr<dolfin::Mesh>(mshr::CSGCGALMeshGenerator3D::*)(std::shared_ptr<const mshr::CSGCGALDomain3D>) const>(&mshr::CSGCGALMeshGenerator3D::generate));
+
+  py::class_<mshr::CSGCGALDomain2D, dolfin::Variable,
+            std::shared_ptr<mshr::CSGCGALDomain2D>>(m, "CSGCGALDomain2D")
+    .def(py::init<std::shared_ptr<const mshr::CSGGeometry>, double>());
+
+  py::class_<mshr::CSGCGALMeshGenerator2D, dolfin::Variable,
+            std::shared_ptr<mshr::CSGCGALMeshGenerator2D>>(m, "CSGCGALMeshGenerator2D")
+    .def(py::init<>())
+    .def("generate", &mshr::CSGCGALMeshGenerator2D::generate);
+
+
+  py::class_<mshr::TetgenMeshGenerator3D, dolfin::Variable,
+            std::shared_ptr<mshr::TetgenMeshGenerator3D>>(m, "TetgenMeshGenerator3D")
+    .def(py::init<>())
+    .def("generate", &mshr::TetgenMeshGenerator3D::generate);
+
+  // generate_mesh
+  m.def("generate_mesh",
+       &mshr::generate_mesh,
+       py::arg("geoemtry"), py::arg("resolution"), py::arg("backend")="cgal");
+}
diff --git a/release.conf b/release.conf
new file mode 100644 (file)
index 0000000..309f558
--- /dev/null
@@ -0,0 +1,5 @@
+# Configuration file for fenics-release
+
+PACKAGE="mshr"
+BRANCH="master"
+FILES="ChangeLog.rst CMakeLists.txt"
diff --git a/src/ASCFileReader.cpp b/src/ASCFileReader.cpp
new file mode 100755 (executable)
index 0000000..a1e16b8
--- /dev/null
@@ -0,0 +1,173 @@
+// Copyright (C) 2016 Lars Magnus Valnes
+//
+// This file is part of mshr.
+//
+// mshr 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 3 of the License, or
+// (at your option) any later version.
+//
+// mshr 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 mshr.  If not, see <http://www.gnu.org/licenses/>.
+//
+
+#include <mshr/ASCFileReader.h>
+
+#include <dolfin/geometry/Point.h>
+#include <dolfin/common/constants.h>
+#include <dolfin/log/LogStream.h>
+#include <dolfin/log/log.h>
+
+#define BOOST_FILESYSTEM_NO_DEPRECATED
+#include <boost/filesystem.hpp>
+#include <boost/tokenizer.hpp>
+#include <boost/algorithm/string.hpp>
+
+#include <fstream>
+#include <iostream>
+#include <sstream>
+#include <string>
+#include <algorithm>
+#include <string>
+#include <map>
+
+namespace
+{
+template<typename T>
+inline double convert_string(const std::string& s)
+{
+  std::istringstream is(s);
+  T val;
+  is >> val;
+
+  return val;
+}
+
+// get next line of file and trim away whitespace
+inline void get_next_line(std::ifstream& file, std::string& line, std::size_t &lineno)
+{
+  do
+  {
+    std::getline(file, line);
+    boost::algorithm::trim(line);
+    lineno++;
+  } while ( !file.eof() && line == "");
+}
+} // end anonymous namespace
+//-----------------------------------------------------------------------------
+namespace mshr
+{
+
+void ASCFileReader::read(const std::string filename,
+                         std::vector<std::array<double, 3> >& vertices,
+                         std::vector<std::array<std::size_t, 3> >& facets)
+{
+  dolfin::log(dolfin:: TRACE, "Reading surface from %s ", filename.c_str());
+
+  vertices.clear();
+  facets.clear();
+  typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
+
+  std::ifstream file(filename.c_str());
+  if (!file.is_open())
+  {
+    dolfin::dolfin_error("ASCFileReader.cpp",
+                         "open .asc file to read 3D surface",
+                         "Failed to open file");
+  }
+
+  std::string line;
+  std::size_t lineno = 0;
+  const boost::char_separator<char> sep(" ");
+  const boost::char_separator<char> sep2("  ");
+  
+  get_next_line(file, line, lineno);  
+  // First line is not important
+  get_next_line(file, line, lineno);
+  tokenizer tokens(line, sep); 
+  tokenizer::iterator tok_iter = tokens.begin();
+  const std::size_t num_vertices = convert_string<std::size_t>(*tok_iter);
+  tok_iter++;
+  const std::size_t num_facets   = convert_string<std::size_t>(*tok_iter);
+  tok_iter++;
+  dolfin_assert(tok_iter == tokens.end());
+
+  vertices.reserve(num_vertices);
+  facets.reserve(num_facets);
+
+  get_next_line(file, line, lineno);   
+  for (std::size_t i = 0; i < num_vertices; i++)
+  {
+    tokenizer tokens(line, sep2);
+    tokenizer::iterator tok_iter = tokens.begin();
+
+    std::array<double, 3> vertex;
+    vertex[0] = convert_string<double>(*tok_iter);
+    tok_iter++;
+    vertex[1] = convert_string<double>(*tok_iter);
+    tok_iter++;
+    vertex[2] = convert_string<double>(*tok_iter);
+    tok_iter++;
+
+    tok_iter++;
+
+    dolfin_assert(tok_iter == tokens.end());
+    vertices.push_back(vertex);
+    get_next_line(file, line, lineno);
+  }
+  for (std::size_t i = 0; i < num_facets; i++)
+  {
+    tokenizer tokens(line, sep);
+    tokenizer::iterator tok_iter = tokens.begin();
+
+    std::array<std::size_t, 3> facet;
+    facet[0] = convert_string<std::size_t>(*tok_iter);
+    tok_iter++;
+    facet[1] = convert_string<std::size_t>(*tok_iter);
+    tok_iter++;
+    facet[2] = convert_string<std::size_t>(*tok_iter);
+    tok_iter++;
+    tok_iter++;
+
+    dolfin_assert(tok_iter == tokens.end());
+
+    facets.push_back(facet);
+    get_next_line(file, line, lineno); 
+
+  }
+  
+}
+//-----------------------------------------------------------------------------
+void ASCFileReader::write(const std::string filename,
+                          const std::vector<std::array<double, 3> >& vertices,
+                          const std::vector<std::array<std::size_t, 3> >& facets)
+{
+  std::ofstream file(filename);
+  file.precision(6);
+
+  if (!file.is_open())
+  {
+    dolfin::dolfin_error("ASCFileReader.cpp",
+                         "open file to write asc data",
+                         "Failed to open file");
+  }
+
+  file << "#!" <<  std::endl;
+  file << vertices.size() << " " << facets.size() << std::endl;
+       // Orded vertices
+  for (const std::array<double, 3>& v : vertices)
+  {
+    file << v[0] << "  " << v[1] << "  " << v[2] << "  " << 0 << std::endl;
+  }
+
+  for (const std::array<std::size_t, 3>& f : facets)
+  {
+    file << f[0] << " " << f[1] << " " << f[2] << " " << 0 <<  std::endl;
+  }
+}
+}
diff --git a/src/CSGCGALDomain2D.cpp b/src/CSGCGALDomain2D.cpp
new file mode 100644 (file)
index 0000000..b4af626
--- /dev/null
@@ -0,0 +1,881 @@
+// Copyright (C) 2013-2017 Benjamin Kehlet
+//
+// This file is part of mshr.
+//
+// mshr 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 3 of the License, or
+// (at your option) any later version.
+//
+// mshr 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 mshr.  If not, see <http://www.gnu.org/licenses/>.
+
+// This file must be included to get the compiler flags
+// They should ideally have been added via the command line,
+// but since CGAL configure time is at mshr compile time, we don't
+// have access to CGALConfig.cmake at configure time...
+#ifndef CGAL_HEADER_ONLY
+#include <CGAL/compiler_config.h>
+#endif
+#include <CGAL/Cartesian.h>
+#include <CGAL/Quotient.h>
+#include <CGAL/MP_Float.h>
+
+#include <mshr/CSGCGALDomain2D.h>
+#include <mshr/CSGPrimitives2D.h>
+#include <mshr/CSGOperators.h>
+
+#include <dolfin/common/constants.h>
+#include <dolfin/log/LogStream.h>
+
+#include <CGAL/basic.h>
+#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
+#include <CGAL/Boolean_set_operations_2.h>
+#include <CGAL/Polygon_set_2.h>
+
+#include <CGAL/Min_circle_2.h>
+#include <CGAL/Min_circle_2_traits_2.h>
+
+// Polygon typedefs
+//typedef CGAL::Exact_predicates_exact_constructions_kernel Exact_Kernel;
+typedef CGAL::Quotient<CGAL::MP_Float>                    FT;
+typedef CGAL::Cartesian<FT>                               Exact_Kernel;
+
+typedef Exact_Kernel::Point_2                             Point_2;
+typedef Exact_Kernel::Vector_2                            Vector_2;
+typedef Exact_Kernel::Segment_2                           Segment_2;
+typedef Exact_Kernel::Ray_2                               Ray_2;
+typedef Exact_Kernel::Direction_2                         Direction_2;
+typedef Exact_Kernel::Aff_transformation_2                Aff_transformation_2;
+typedef CGAL::Polygon_2<Exact_Kernel>                     Polygon_2;
+typedef Polygon_2::Vertex_const_iterator                  Vertex_const_iterator;
+typedef CGAL::Polygon_with_holes_2<Exact_Kernel>          Polygon_with_holes_2;
+typedef Polygon_with_holes_2::Hole_const_iterator         Hole_const_iterator;
+typedef CGAL::Polygon_set_2<Exact_Kernel>                 Polygon_set_2;
+
+// Min enclosing circle typedefs
+typedef CGAL::Min_circle_2_traits_2<Exact_Kernel>  Min_Circle_Traits;
+typedef CGAL::Min_circle_2<Min_Circle_Traits>      Min_circle;
+typedef CGAL::Circle_2<Exact_Kernel> CGAL_Circle;
+
+
+namespace
+{
+FT get_shortest_edge(const Polygon_set_2& polygon_set)
+{
+  FT shortest_edge = std::numeric_limits<double>::max();
+
+  std::list<Polygon_with_holes_2> polygon_list;
+  polygon_set.polygons_with_holes(std::back_inserter(polygon_list));
+
+  // FIXME: For now it looks only at the outer boundary.
+  // Should take holes into account as well
+  for (const Polygon_with_holes_2& p : polygon_list)
+  {
+    const Polygon_2& bdr = p.outer_boundary();
+    Point_2 prev = bdr.container().back();
+    for (Polygon_2::Vertex_const_iterator vit = bdr.vertices_begin();
+         vit != bdr.vertices_end(); vit++)
+    {
+      shortest_edge = std::min(shortest_edge, (*vit-prev).squared_length());
+      prev = *vit;
+    }
+  }
+  return shortest_edge;
+}
+//-----------------------------------------------------------------------------
+Point_2 point_in_polygon(const Polygon_2& p)
+{
+  // Take the midpoint, s,  of a segment, then do a ray shooting in the inwards
+  // normal direction and return the midpoint between s and the closest ray hit.
+
+  Polygon_2::Edge_const_iterator eit = p.edges_begin();
+  const Point_2 source = CGAL::midpoint(eit->source(), eit->target());
+  const Aff_transformation_2 tr = Aff_transformation_2(CGAL::ROTATION,
+                                                       p.orientation() == CGAL::COUNTERCLOCKWISE ? 1 : -1, 0);
+
+  const Ray_2 r(source, tr(Direction_2(*eit)));
+  Point_2 closest;
+  FT min_squared_distance = std::numeric_limits<double>::max();
+
+  eit++;
+  for (; eit != p.edges_end(); eit++)
+  {
+    auto ii = CGAL::intersection(r, *eit);
+    if (ii)
+    {
+      if (const Point_2* p = boost::get<Point_2>(&*ii))
+      {
+        const FT squared_distance = CGAL::squared_distance(source, *p);
+        if (squared_distance < min_squared_distance)
+        {
+          closest = *p;
+          min_squared_distance = squared_distance;
+        }
+      }
+      else if (const Segment_2* s = boost::get<Segment_2>(&*ii))
+      {
+        // If the intersection is a segment, an edge in the polygon is paralell
+        // to the ray. Simply check both the source and the target point of the
+        // segment.
+
+        {
+          const FT squared_distance = CGAL::squared_distance(source, s->source());
+          if (squared_distance < min_squared_distance)
+          {
+            closest = *p;
+            min_squared_distance = squared_distance;
+          }
+        }
+
+        {
+          const FT squared_distance = CGAL::squared_distance(source, s->target());
+          if (squared_distance < min_squared_distance)
+          {
+            closest = *p;
+            min_squared_distance = squared_distance;
+          }
+        }
+      } // end intersection is Segment_2
+    }
+  }
+  return CGAL::midpoint(source, closest);
+}
+//-----------------------------------------------------------------------------
+void truncate_short_edges(Polygon_set_2& polygon_set,
+                          FT tolerance,
+                          const std::set<Point_2> & collapsable_vertices = std::set<Point_2>())
+{
+  const FT tolerance_squared = tolerance*tolerance;
+
+  Polygon_set_2 truncated_set;
+  std::list<Polygon_with_holes_2> polygon_list;
+  polygon_set.polygons_with_holes(std::back_inserter(polygon_list));
+
+  // FIXME: For now it looks only at the outer boundary.
+  // Should take holes into account as well
+  for (const Polygon_with_holes_2& p : polygon_list)
+  {
+    Polygon_2 bdr = p.outer_boundary();
+
+    bool changed = true;
+    while(changed)
+    {
+      changed = false;
+
+      Polygon_2::Vertex_iterator prev = bdr.vertices_end()-1;
+
+      for (Polygon_2::Vertex_iterator vit = bdr.vertices_begin();
+           vit != bdr.vertices_end(); vit++)
+      {
+        if ( (*vit-*prev).squared_length() < tolerance_squared)
+        {
+          if (collapsable_vertices.size() == 0 || collapsable_vertices.find(*vit) != collapsable_vertices.end())
+          {
+            bdr.erase(vit);
+            changed = true;
+            break;
+          }
+          else if (collapsable_vertices.size() == 0 || collapsable_vertices.find(*prev) != collapsable_vertices.end())
+          {
+            bdr.erase(prev);
+            changed = true;
+            break;
+          }
+          else
+          {
+            // std::cout << "Couldn't erase vertex" << std::endl;
+          }
+        } // end if short edge
+        prev = vit;
+      } // end vertex iteration
+    } // end while(changed)
+
+    Polygon_with_holes_2 pwh(bdr);
+    for (Hole_const_iterator hit = p.holes_begin(); hit != p.holes_end(); ++hit)
+    {
+      pwh.add_hole(*hit);
+    }
+    truncated_set.insert(pwh);
+  }
+  polygon_set = truncated_set;
+}
+} // end anonymous namespace
+//-----------------------------------------------------------------------------
+namespace mshr
+{
+
+struct CSGCGALDomain2DImpl
+{
+  Polygon_set_2 polygon_set;
+
+  CSGCGALDomain2DImpl(){}
+  explicit CSGCGALDomain2DImpl(const Polygon_set_2& p)
+    : polygon_set(p) {}
+};
+//-----------------------------------------------------------------------------
+Polygon_2 make_circle(
+    const Circle* c,
+    const double segment_granularity
+    )
+{
+  unsigned int num_segments = 0;
+  if (c->segments() > 0)
+  {
+    num_segments = c->segments();
+  } else {
+    dolfin_assert(segment_granularity > 0.0);
+
+    num_segments = std::round(
+        (2 * DOLFIN_PI * c->radius()) / segment_granularity
+        );
+  }
+
+  // Set the minimum number of segments to 5 (to be a bit circle-like)
+  // (A polygon with less than 3 segments is degenerate)
+  num_segments = std::max(num_segments, 5u);
+
+  std::vector<Point_2> pts;
+  pts.reserve(num_segments);
+
+  for (std::size_t i = 0; i < num_segments; i++)
+  {
+    const double phi = (2*DOLFIN_PI*i) / num_segments;
+    const double x = c->center().x() + c->radius()*cos(phi);
+    const double y = c->center().y() + c->radius()*sin(phi);
+    pts.push_back(Point_2(x, y));
+  }
+
+  return Polygon_2(pts.begin(), pts.end());
+}
+//-----------------------------------------------------------------------------
+Polygon_2 make_ellipse(const Ellipse* e,
+                       const double segment_granularity)
+{
+  unsigned int num_segments = 0;
+  if (e->segments() > 0) {
+    num_segments = e->segments();
+  }
+  else
+  {
+    dolfin_assert(segment_granularity > 0.0);
+    // https://en.wikipedia.org/wiki/Ellipse#Circumference
+    const double a_min_b = e->a() - e->b();
+    const double a_plus_b = e->a() + e->b();
+    const double h = (a_min_b*a_min_b) / (a_plus_b*a_plus_b);
+    const double arc_length_ellipse_approx = DOLFIN_PI * a_plus_b * (
+        1.0 + 3.0*h / (10 + sqrt(4.0 - 3.0*h))
+        );
+    num_segments = std::round(arc_length_ellipse_approx / segment_granularity);
+  }
+
+  // A polygon with less segments than 3 is degenerate
+  // FIXME: Should this result in an empty polygon?
+  num_segments = std::max(num_segments, 3u);
+
+  std::vector<Point_2> pts;
+  pts.reserve(num_segments);
+
+  for (std::size_t i = 0; i < num_segments; i++)
+  {
+    const double phi = (2*DOLFIN_PI*i) / num_segments;
+    const double x = e->center().x() + e->a()*cos(phi);
+    const double y = e->center().y() + e->b()*sin(phi);
+    pts.push_back(Point_2(x, y));
+  }
+
+  return Polygon_2(pts.begin(), pts.end());
+}
+//-----------------------------------------------------------------------------
+Polygon_2 make_rectangle(const Rectangle* r)
+{
+  const double x0 = std::min(r->first_corner().x(), r->second_corner().x());
+  const double y0 = std::min(r->first_corner().y(), r->second_corner().y());
+
+  const double x1 = std::max(r->first_corner().x(), r->second_corner().x());
+  const double y1 = std::max(r->first_corner().y(), r->second_corner().y());
+
+  std::vector<Point_2> pts;
+  pts.push_back(Point_2(x0, y0));
+  pts.push_back(Point_2(x1, y0));
+  pts.push_back(Point_2(x1, y1));
+  pts.push_back(Point_2(x0, y1));
+
+  Polygon_2 p(pts.begin(), pts.end());
+
+  return p;
+}
+//-----------------------------------------------------------------------------
+Polygon_2 make_polygon(const Polygon* p)
+{
+  std::vector<Point_2> pts;
+  std::vector<dolfin::Point>::const_iterator v;
+  for (v = p->vertices().begin(); v != p->vertices().end(); ++v)
+    pts.push_back(Point_2(v->x(), v->y()));
+
+  return Polygon_2(pts.begin(), pts.end());
+}
+//-----------------------------------------------------------------------------
+std::unique_ptr<CSGCGALDomain2DImpl> do_transformation(const Polygon_set_2& p, Exact_Kernel::Aff_transformation_2 t)
+{
+  std::unique_ptr<CSGCGALDomain2DImpl> result(new CSGCGALDomain2DImpl);
+
+  std::list<Polygon_with_holes_2> polygon_list;
+  p.polygons_with_holes(std::back_inserter(polygon_list));
+
+  std::list<Polygon_with_holes_2>::const_iterator pit;
+  for (pit = polygon_list.begin(); pit != polygon_list.end(); ++pit)
+  {
+    const Polygon_with_holes_2& pwh = *pit;
+
+    // Transform outer boundary
+    Polygon_with_holes_2 transformed(CGAL::transform(t, pwh.outer_boundary()));
+
+    // Transform holes
+    for (Hole_const_iterator hit = pwh.holes_begin(); hit != pwh.holes_end(); hit++)
+    {
+      transformed.add_hole(CGAL::transform(t, *hit));
+    }
+
+    result->polygon_set.insert(transformed);
+  }
+
+  return result;
+}
+//-----------------------------------------------------------------------------
+CSGCGALDomain2D::CSGCGALDomain2D()
+  : impl(new CSGCGALDomain2DImpl)
+{
+
+}
+//-----------------------------------------------------------------------------
+CSGCGALDomain2D::~CSGCGALDomain2D()
+{
+}
+//-----------------------------------------------------------------------------
+CSGCGALDomain2D::CSGCGALDomain2D(std::shared_ptr<const CSGGeometry> geometry,
+                                 double segment_granularity)
+ : impl(new CSGCGALDomain2DImpl)
+{
+  if (geometry->dim() != 2)
+    dolfin::dolfin_error("CSGCGALDomain2D.cpp",
+                         "Creating polygonal domain",
+                         "Geometry has dimension %d, expected 2", geometry->dim());
+
+
+  switch (geometry->getType())
+  {
+    case CSGGeometry::Union:
+    {
+      std::shared_ptr<const CSGUnion> u = std::dynamic_pointer_cast<const CSGUnion, const CSGGeometry>(geometry);
+      dolfin_assert(u);
+
+      CSGCGALDomain2D a(u->_g0, segment_granularity);
+      CSGCGALDomain2D b(u->_g1, segment_granularity);
+
+      impl.swap(a.impl);
+      impl->polygon_set.join(b.impl->polygon_set);
+      break;
+    }
+    case CSGGeometry::Intersection:
+    {
+      auto  u = std::dynamic_pointer_cast<const CSGIntersection, const CSGGeometry>(geometry);
+      dolfin_assert(u);
+
+      CSGCGALDomain2D a(u->_g0, segment_granularity);
+      CSGCGALDomain2D b(u->_g1, segment_granularity);
+
+      impl.swap(a.impl);
+      impl->polygon_set.intersection(b.impl->polygon_set);
+      break;
+    }
+    case CSGGeometry::Difference:
+    {
+      auto u = std::dynamic_pointer_cast<const CSGDifference, const CSGGeometry>(geometry);
+      dolfin_assert(u);
+      CSGCGALDomain2D a(u->_g0, segment_granularity);
+      CSGCGALDomain2D b(u->_g1, segment_granularity);
+
+      impl.swap(a.impl);
+      impl->polygon_set.difference(b.impl->polygon_set);
+      break;
+    }
+    case CSGGeometry::Translation :
+    {
+      auto t = std::dynamic_pointer_cast<const CSGTranslation, const CSGGeometry>(geometry);
+      dolfin_assert(t);
+      CSGCGALDomain2D a(t->g, segment_granularity);
+      Exact_Kernel::Aff_transformation_2 translation(CGAL::TRANSLATION, Vector_2(t->t.x(), t->t.y()));
+      std::unique_ptr<CSGCGALDomain2DImpl> transformed = do_transformation(a.impl->polygon_set, translation);
+      impl.swap(transformed);
+      break;
+    }
+    case CSGGeometry::Scaling :
+    {
+      auto t = std::dynamic_pointer_cast<const CSGScaling, const CSGGeometry>(geometry);
+      dolfin_assert(t);
+      CSGCGALDomain2D a(t->g, segment_granularity);
+      Exact_Kernel::Aff_transformation_2 tr(CGAL::IDENTITY);
+
+      // Translate if requested
+      if (t->translate)
+        tr = Exact_Kernel::Aff_transformation_2 (CGAL::TRANSLATION,
+                                                 Vector_2(-t->c.x(), -t->c.y())) * tr;
+
+      // Do the scaling
+      tr = Exact_Kernel::Aff_transformation_2(CGAL::SCALING, t->s) * tr;
+
+      if (t->translate)
+        tr = Exact_Kernel::Aff_transformation_2(CGAL::TRANSLATION,
+                                                Vector_2(t->c.x(), t->c.y())) * tr;
+
+      std::unique_ptr<CSGCGALDomain2DImpl> transformed = do_transformation(a.impl->polygon_set,
+                                                                           tr);
+      impl.swap(transformed);
+      break;
+    }
+    case CSGGeometry::Rotation :
+    {
+      auto t = std::dynamic_pointer_cast<const CSGRotation, const CSGGeometry>(geometry);
+      dolfin_assert(t);
+      CSGCGALDomain2D a(t->g, segment_granularity);
+      Exact_Kernel::Aff_transformation_2 tr(CGAL::IDENTITY);
+
+      // Translate if requested
+      if (t->translate)
+        tr = Exact_Kernel::Aff_transformation_2 (CGAL::TRANSLATION,
+                                                 Vector_2(-t->c.x(), -t->c.y())) * tr;
+
+      // Do the rotation
+      tr = Exact_Kernel::Aff_transformation_2(CGAL::ROTATION, sin(t->theta), cos(t->theta)) * tr;
+
+      if (t->translate)
+        tr = Exact_Kernel::Aff_transformation_2(CGAL::TRANSLATION,
+                                                Vector_2(t->c.x(), t->c.y())) * tr;
+
+      std::unique_ptr<CSGCGALDomain2DImpl> transformed = do_transformation(a.impl->polygon_set,
+                                                                           tr);
+      impl.swap(transformed);
+      break;
+    }
+    case CSGGeometry::Circle:
+    {
+      auto c = std::dynamic_pointer_cast<const Circle, const CSGGeometry>(geometry);
+      dolfin_assert(c);
+      impl->polygon_set.insert(make_circle(c.get(), segment_granularity));
+      break;
+    }
+    case CSGGeometry::Ellipse:
+    {
+      auto c = std::dynamic_pointer_cast<const Ellipse, const CSGGeometry>(geometry);
+      dolfin_assert(c);
+      impl->polygon_set.insert(make_ellipse(c.get(), segment_granularity));
+      break;
+    }
+    case CSGGeometry::Rectangle:
+    {
+      auto r = std::dynamic_pointer_cast<const Rectangle, const CSGGeometry>(geometry);
+      dolfin_assert(r);
+      impl->polygon_set.insert(make_rectangle(r.get()));
+      break;
+    }
+    case CSGGeometry::Polygon:
+    {
+      auto p = std::dynamic_pointer_cast<const Polygon, const CSGGeometry>(geometry);
+      dolfin_assert(p);
+      impl->polygon_set.insert(make_polygon(p.get()));
+      break;
+    }
+    default:
+      dolfin::dolfin_error("CSGCGALMeshGenerator2D.cpp",
+                           "converting geometry to cgal polyhedron",
+                           "Unhandled primitive type");
+  }
+
+  // Truncate short edges
+  // std::cout << "Creating domain, shortest edge: " << CGAL::to_double(get_shortest_edge(impl->polygon_set)) << std::endl;
+
+  truncate_short_edges(impl->polygon_set, 1e-15);
+  // std::cout << "Truncated, shortest edge: " << CGAL::to_double(get_shortest_edge(impl->polygon_set)) << std::endl;
+}
+//-----------------------------------------------------------------------------
+CSGCGALDomain2D::CSGCGALDomain2D(const CSGCGALDomain2D &other)
+ : impl(new CSGCGALDomain2DImpl(other.impl->polygon_set))
+{
+}
+//-----------------------------------------------------------------------------
+CSGCGALDomain2D &CSGCGALDomain2D::operator=(const CSGCGALDomain2D &other)
+{
+  std::unique_ptr<CSGCGALDomain2DImpl> tmp(new CSGCGALDomain2DImpl(other.impl->polygon_set));
+
+  impl.swap(tmp);
+
+  return *this;
+}
+//-----------------------------------------------------------------------------
+double CSGCGALDomain2D::compute_boundingcircle_radius() const
+{
+  std::list<Polygon_with_holes_2> polygon_list;
+  impl->polygon_set.polygons_with_holes(std::back_inserter(polygon_list));
+
+  std::vector<Point_2> points;
+
+  for (std::list<Polygon_with_holes_2>::const_iterator pit = polygon_list.begin();
+       pit != polygon_list.end(); ++pit)
+    for (Polygon_2::Vertex_const_iterator vit = pit->outer_boundary().vertices_begin();
+         vit != pit->outer_boundary().vertices_end(); ++vit)
+      points.push_back(*vit);
+
+  Min_circle min_circle (points.begin(),
+                         points.end(),
+                         true); //randomize point order
+
+  return sqrt(CGAL::to_double(min_circle.circle().squared_radius()));
+}
+//-----------------------------------------------------------------------------
+std::size_t CSGCGALDomain2D::num_polygons() const
+{
+  return impl->polygon_set.number_of_polygons_with_holes();
+}
+//-----------------------------------------------------------------------------
+std::vector<dolfin::Point> CSGCGALDomain2D::get_outer_polygon(std::size_t i) const
+{
+  std::vector<Polygon_with_holes_2> polygon_list;
+  impl->polygon_set.polygons_with_holes(std::back_inserter(polygon_list));
+
+  const Polygon_2& polygon = polygon_list[i].outer_boundary();
+
+  std::vector<dolfin::Point> res;
+  res.reserve(polygon.size());
+  for (std::size_t j = 0; j < polygon.size(); j++)
+  {
+    const Point_2& p = polygon.vertex(j);
+    res.push_back(dolfin::Point(CGAL::to_double(p.x()), CGAL::to_double(p.y())));
+  }
+
+  return res;
+}
+//-----------------------------------------------------------------------------
+void CSGCGALDomain2D::join_inplace(const CSGCGALDomain2D& other)
+{
+  impl->polygon_set.join(other.impl->polygon_set);
+}
+//-----------------------------------------------------------------------------
+void CSGCGALDomain2D::difference_inplace(const CSGCGALDomain2D& other)
+{
+  impl->polygon_set.difference(other.impl->polygon_set);
+}
+//-----------------------------------------------------------------------------
+void CSGCGALDomain2D::intersect_inplace(const CSGCGALDomain2D &other,
+                                        double truncate_tolerance)
+{
+  if (truncate_tolerance > 0)
+  {
+    // store
+    std::set<Point_2> original_vertices;
+    {
+      std::list<Polygon_with_holes_2> polygon_list;
+      impl->polygon_set.polygons_with_holes(std::back_inserter(polygon_list));
+
+      // FIXME: For now it looks only at the outer boundary.
+      // Should take holes into account as well
+      for (const Polygon_with_holes_2& p : polygon_list)
+      {
+        const Polygon_2& bdr = p.outer_boundary();
+        for (Polygon_2::Vertex_const_iterator vit = bdr.vertices_begin();
+             vit != bdr.vertices_end(); vit++)
+        {
+          original_vertices.insert(*vit);
+        }
+
+      }
+    }
+    // Do the actual intersection
+    impl->polygon_set.intersection(other.impl->polygon_set);
+
+    const FT shortest_edge = get_shortest_edge(impl->polygon_set);
+    const FT tolerance_squared = truncate_tolerance*truncate_tolerance;
+    if (shortest_edge < tolerance_squared)
+    {
+      truncate_short_edges(impl->polygon_set,
+                           truncate_tolerance,
+                           original_vertices);
+    } // end
+  }
+  else
+  {
+    impl->polygon_set.intersection(other.impl->polygon_set);
+  }
+}
+//-----------------------------------------------------------------------------
+bool CSGCGALDomain2D::point_in_domain(dolfin::Point p) const
+{
+  const Point_2 p_(p.x(), p.y());
+  return impl->polygon_set.oriented_side(p_) == CGAL::ON_POSITIVE_SIDE;
+}
+//-----------------------------------------------------------------------------
+std::string CSGCGALDomain2D::str(bool verbose) const
+{
+  std::stringstream ss;
+  const std::size_t num_polygons = impl->polygon_set.number_of_polygons_with_holes();
+  ss << "<Polygonal domain with " << num_polygons
+     << " outer polygon" << (num_polygons != 1 ? "s" : "") << std::endl;
+
+  if (verbose)
+  {
+    std::list<Polygon_with_holes_2> polygon_list;
+    impl->polygon_set.polygons_with_holes(std::back_inserter(polygon_list));
+    for (const Polygon_with_holes_2& p : polygon_list)
+    {
+      ss << "  Polygon ";
+      const Polygon_2& bdr = p.outer_boundary();
+      // ss << "[" << bdr.size() << "] Vertices: ";
+
+      for (Polygon_2::Vertex_const_iterator vit = bdr.vertices_begin();
+           vit != bdr.vertices_end(); vit++)
+      {
+        ss << CGAL::to_double(vit->x()) << " " << CGAL::to_double(vit->y()) << ", ";
+      }
+      ss << std::endl;
+
+      Point_2 prev = bdr.container().back();
+      ss << "Edge lengths:";
+      for (Polygon_2::Vertex_const_iterator vit = bdr.vertices_begin();
+           vit != bdr.vertices_end(); vit++)
+      {
+        ss << " "  << sqrt(CGAL::to_double((*vit-prev).squared_length()));
+        prev = *vit;
+      }
+      ss << std::endl;
+
+
+
+      ss << "[" << p.number_of_holes() << " holes]" << std::endl;
+    }
+  }
+
+  ss << ">";
+  return ss.str();
+}
+//-----------------------------------------------------------------------------
+typedef std::map<Point_2, std::size_t>::iterator VertexMapIterator;
+typedef std::set<std::pair<std::size_t, std::size_t>>::iterator SegmentIterator;
+//-----------------------------------------------------------------------------
+VertexMapIterator pslg_split_edge(SegmentIterator si,
+                                  Point_2 p,
+                                  std::map<Point_2, std::size_t>& vertex_map,
+                                  std::vector<Point_2>& vertices,
+                                  std::set<std::pair<std::size_t, std::size_t>>& segments)
+{
+  dolfin_assert(CGAL::do_intersect(Segment_2(vertices[si->first], vertices[si->second]), p));
+  dolfin_assert(p != vertices[si->first]);
+  dolfin_assert(p != vertices[si->second]);
+
+  vertices.push_back(p);
+  const std::size_t new_vertex_index = vertex_map.size();
+  std::pair<VertexMapIterator, bool> result =
+    vertex_map.insert(std::make_pair(p, new_vertex_index));
+  dolfin_assert(result.second);
+
+  const std::size_t source_vertex_index = si->first;
+  const std::size_t target_vertex_index = si->second;
+
+  segments.erase(si);
+  segments.insert(std::make_pair(new_vertex_index, target_vertex_index));
+  segments.insert(std::make_pair(source_vertex_index, new_vertex_index));
+  return result.first;
+}
+//-----------------------------------------------------------------------------
+
+// Check if point intersects any edge in the interior
+static inline SegmentIterator
+pslg_segment_intersection(Point_2 p,
+                          const std::vector<Point_2>& vertices,
+                          const std::set<std::pair<std::size_t, std::size_t>>& segments)
+{
+  for (SegmentIterator it = segments.begin(); it != segments.end(); ++it)
+  {
+    const Segment_2 current(vertices[it->first], vertices[it->second]);
+    if (CGAL::do_intersect(p, current))
+      return it;
+  }
+  return segments.end();
+}
+
+//-----------------------------------------------------------------------------
+static inline void pslg_add_simple_polygon(std::map<Point_2, std::size_t>& vertex_map,
+                                           std::vector<Point_2>& vertices,
+                                           std::set<std::pair<std::size_t, std::size_t>>& segments,
+                                           const Polygon_2& p)
+{
+  // Note that this function assumes that all edges are sufficiently long. Short
+  // edges should be filtered out when preparing the domain (and subdomain)
+  // polygon_set_2s.
+
+  Point_2 prev = p.vertex(p.size()-1);
+
+  for (std::size_t i = 0; i < p.size(); i++)
+  {
+    const Point_2 current = p.vertex(i);
+    const Segment_2 s(prev, current);
+
+    VertexMapIterator sit = vertex_map.find(s.source());
+    if (sit == vertex_map.end())
+    {
+      // Did not find vertex
+      SegmentIterator si = pslg_segment_intersection(s.source(), vertices, segments);
+      if (si != segments.end())
+      {
+        sit = pslg_split_edge(si,
+                              s.source(),
+                              vertex_map,
+                              vertices,
+                              segments);
+      }
+      else
+      {
+        std::pair<VertexMapIterator, bool> i = vertex_map.insert(std::make_pair(s.source(), vertex_map.size()));
+        vertices.push_back(s.source());
+        dolfin_assert(i.second);
+        sit = i.first;
+      }
+    }
+
+    VertexMapIterator tit = vertex_map.find(s.target());
+    if (tit == vertex_map.end())
+    {
+      SegmentIterator si = pslg_segment_intersection(s.target(), vertices, segments);
+      if (si != segments.end())
+      {
+        tit = pslg_split_edge(si,
+                              s.target(),
+                              vertex_map,
+                              vertices,
+                              segments);
+      }
+      else
+      {
+        std::pair<VertexMapIterator, bool> i = vertex_map.insert(std::make_pair(s.target(), vertex_map.size()));
+        vertices.push_back(s.target());
+        dolfin_assert(i.second);
+        tit = i.first;
+      }
+    }
+
+    if (segments.count(std::make_pair(tit->second, sit->second)) == 0)
+      segments.insert(std::make_pair(sit->second, tit->second));
+
+    prev = current;
+  }
+}
+//-----------------------------------------------------------------------------
+std::pair<std::vector<dolfin::Point>, std::vector<std::pair<std::size_t, std::size_t>>>
+  CSGCGALDomain2D::compute_pslg(const std::vector<std::pair<std::size_t, CSGCGALDomain2D>>& domains)
+{
+  std::vector<Point_2> vertices;
+  std::map<Point_2, std::size_t> vertex_map;
+  std::set<std::pair<std::size_t, std::size_t>> segments;
+  // std::vector<Segment_2> inserted_segments;
+
+  for (const std::pair<std::size_t, CSGCGALDomain2D>& domain : domains)
+  {
+    const Polygon_set_2& p = domain.second.impl->polygon_set;
+
+    std::list<Polygon_with_holes_2> polygon_list;
+    p.polygons_with_holes(std::back_inserter(polygon_list));
+
+    for (const Polygon_with_holes_2& pwh : polygon_list)
+    {
+      pslg_add_simple_polygon(vertex_map,
+                              vertices,
+                              segments,
+                              pwh.outer_boundary());
+
+      // Add holes
+      Hole_const_iterator hit;
+      for (hit = pwh.holes_begin(); hit != pwh.holes_end(); ++hit)
+      {
+        pslg_add_simple_polygon(vertex_map,
+                                vertices,
+                                segments,
+                                *hit);
+      }
+    }
+  }
+
+  std::vector<dolfin::Point> v(vertices.size());
+  for (const std::pair<Point_2, std::size_t>& vertex : vertex_map)
+  {
+    v[vertex.second] = dolfin::Point(CGAL::to_double(vertex.first.x()), CGAL::to_double(vertex.first.y()));
+  }
+
+  std::vector<std::pair<std::size_t, std::size_t>> s(segments.begin(), segments.end());
+
+  {
+    double shortest_segment = std::numeric_limits<double>::max();
+    for (std::pair<std::size_t, std::size_t> segment : s)
+    {
+      shortest_segment = std::min(shortest_segment, (v[segment.first]-v[segment.second]).norm());
+    }
+
+    double closest_points = std::numeric_limits<double>::max();
+    for (auto i = v.begin(); i != v.end(); i++)
+    {
+      for (auto j = i+1; j != v.end(); j++)
+      {
+        closest_points = std::min(closest_points, (*i-*j).norm());
+      }
+    }
+
+    // std::cout << "Num vertices: " << v.size() << ", num edges: " << s.size() << std::endl;
+    // std::cout << "Shortest edge: " << shortest_segment << ", closest: " << closest_points << std::endl;
+  }
+
+  return std::make_pair(std::move(v), std::move(s));
+}
+//-----------------------------------------------------------------------------
+double CSGCGALDomain2D::shortest_edge() const
+{
+  FT shortest_edge = std::numeric_limits<double>::max();
+
+  std::list<Polygon_with_holes_2> polygon_list;
+  impl->polygon_set.polygons_with_holes(std::back_inserter(polygon_list));
+
+  // FIXME: For now it looks only at the outer boundary.
+  // Should take holes into account as well
+  for (const Polygon_with_holes_2& p : polygon_list)
+  {
+    const Polygon_2& bdr = p.outer_boundary();
+    Point_2 prev = bdr.container().back();
+    for (Polygon_2::Vertex_const_iterator vit = bdr.vertices_begin();
+         vit != bdr.vertices_end(); vit++)
+    {
+      shortest_edge = std::min(shortest_edge, (*vit-prev).squared_length());
+      prev = *vit;
+    }
+  }
+
+  return sqrt(CGAL::to_double(shortest_edge));
+}
+//-----------------------------------------------------------------------------
+void CSGCGALDomain2D::get_points_in_holes(std::vector<dolfin::Point>& holes) const
+{
+  std::list<Polygon_with_holes_2> polygon_list;
+  impl->polygon_set.polygons_with_holes(std::back_inserter(polygon_list));
+
+  for (const Polygon_with_holes_2& pwh : polygon_list)
+  {
+    Hole_const_iterator hit;
+    for (hit = pwh.holes_begin(); hit != pwh.holes_end(); ++hit)
+    {
+      const Point_2 p = point_in_polygon(*hit);
+      holes.push_back(dolfin::Point(CGAL::to_double(p.x()), CGAL::to_double(p.y())));
+    }
+  }
+}
+}
diff --git a/src/CSGCGALDomain3D.cpp b/src/CSGCGALDomain3D.cpp
new file mode 100644 (file)
index 0000000..a07a1d6
--- /dev/null
@@ -0,0 +1,2336 @@
+// Copyright (C) 2012-2015 Benjamin Kehlet
+//
+// This file is part of mshr.
+//
+// mshr 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 3 of the License, or
+// (at your option) any later version.
+//
+// mshr 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 mshr.  If not, see <http://www.gnu.org/licenses/>.
+
+#include <mshr/CSGCGALDomain3D.h>
+#include <mshr/CSGGeometry.h>
+#include <mshr/CSGOperators.h>
+#include <mshr/CSGPrimitives3D.h>
+#include <mshr/STLFileReader.h>
+#include <mshr/OFFFileReader.h>
+#include <mshr/ASCFileReader.h>
+#include <mshr/SurfaceConsistency.h>
+#include <mshr/CSGCGALDomain2D.h>
+#include <mshr/CSGCGALMeshGenerator2D.h>
+#include <mshr/DolfinMeshUtils.h>
+#include <mshr/SurfaceReconstruction.h>
+
+#include "meshclean.h"
+#include "triangulation_refinement.h"
+#include "Polyhedron_utils.h"
+#include "smoothing.h"
+
+#include <dolfin/geometry/Point.h>
+#include <dolfin/math/basic.h>
+#include <dolfin/log/log.h>
+#include <dolfin/log/LogStream.h>
+#include <dolfin/mesh/BoundaryMesh.h>
+#include <dolfin/mesh/Vertex.h>
+#include <dolfin/mesh/Cell.h>
+
+#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
+#include <CGAL/Polyhedron_incremental_builder_3.h>
+#ifndef MSHR_ENABLE_EXPERIMENTAL
+  #include <CGAL/Nef_polyhedron_3.h>
+#else
+  #include <CGAL/corefinement_operations.h>
+#endif
+#include <CGAL/IO/Polyhedron_iostream.h>
+#include <CGAL/Origin.h>
+//#include <CGAL/Self_intersection_polyhedron_3.h>
+#include <CGAL/Polygon_mesh_processing/self_intersections.h>
+
+#include <CGAL/AABB_tree.h>
+#include <CGAL/AABB_traits.h>
+#include <CGAL/boost/graph/graph_traits_Polyhedron_3.h>
+#include <CGAL/AABB_face_graph_triangle_primitive.h>
+
+#include <CGAL/convex_hull_3.h>
+
+#define BOOST_FILESYSTEM_NO_DEPRECATED
+#include <boost/filesystem.hpp>
+
+#include <vector>
+#include <iterator>
+#include <fstream>
+#include <iomanip>
+#include <set>
+#include <cmath>
+#include <memory>
+
+namespace
+{
+  typedef CGAL::Exact_predicates_exact_constructions_kernel  Exact_Kernel;
+  typedef Exact_Kernel::Triangle_3               Exact_Triangle_3;
+  typedef Exact_Kernel::Triangle_2               Exact_Triangle_2;
+  typedef Exact_Kernel::Vector_3                 Exact_Vector_3;
+  typedef CGAL::Polyhedron_3<Exact_Kernel>       Exact_Polyhedron_3;
+  typedef Exact_Polyhedron_3::HalfedgeDS         Exact_HalfedgeDS;
+  typedef Exact_Kernel::Point_3                  Exact_Point_3;
+  typedef Exact_Kernel::Point_2                  Exact_Point_2;
+  typedef Exact_Kernel::Vector_3                 Vector_3;
+  typedef Exact_Kernel::Ray_3                    Ray_3;
+  typedef Exact_Kernel::Aff_transformation_3     Aff_transformation_3;
+
+#ifndef MSHR_ENABLE_EXPERIMENTAL
+  typedef CGAL::Nef_polyhedron_3<Exact_Kernel>   Nef_polyhedron_3;
+#endif
+
+// AABB tree primitives
+  typedef CGAL::AABB_face_graph_triangle_primitive<Exact_Polyhedron_3> Primitive;
+  typedef CGAL::AABB_traits<Exact_Kernel, Primitive> Traits;
+  typedef CGAL::AABB_tree<Traits> AABB_Tree;
+}
+
+namespace mshr
+{
+  struct CSGCGALDomain3DImpl
+  {
+    Exact_Polyhedron_3 p;
+  };
+}
+
+namespace
+{
+  //-----------------------------------------------------------------------------
+  // Convenience routine to make debugging easier. Remove before releasing.
+  template<typename Builder>
+  inline void add_triangular_facet(Builder& builder,
+                                   int v0, int v1, int v2)
+  {
+    builder.begin_facet();
+    builder.add_vertex_to_facet(v0);
+    builder.add_vertex_to_facet(v1);
+    builder.add_vertex_to_facet(v2);
+    builder.end_facet();
+  }
+  //-----------------------------------------------------------------------------
+  template<typename Builder>
+  inline void add_vertex(Builder& builder,
+                         const Exact_Point_3& point)
+  {
+    builder.add_vertex(point);
+  }
+  //-----------------------------------------------------------------------------
+  // Sphere
+  //-----------------------------------------------------------------------------
+  class Build_sphere : public CGAL::Modifier_base<Exact_HalfedgeDS>
+  {
+  public:
+    Build_sphere(const mshr::Sphere& sphere) : _sphere(sphere) {}
+
+    void operator()( Exact_HalfedgeDS& hds )
+    {
+      std::vector<dolfin::Point> initial_vertices { dolfin::Point( 0.0, 0.0, 1.0 ),
+          dolfin::Point( 1.0, 0.0, 0.0 ),
+          dolfin::Point( 0.0,-1.0, 0.0 ),
+          dolfin::Point(-1.0, 0.0, 0.0 ),
+          dolfin::Point( 0.0, 1.0, 0.0 ),
+          dolfin::Point( 0.0, 0.0,-1.0 )};
+
+      // Note: Some older compilers (eg. gcc on Ubuntu Precise) require std::array<std::size_t, 3> to be
+      // given explicitly in the initializer list.
+      std::vector<std::array<std::size_t, 3> > initial_triangles { std::array<std::size_t, 3>{{0, 2, 1 }},
+                                                                   std::array<std::size_t, 3>{{0, 3, 2 }},
+                                                                   std::array<std::size_t, 3>{{0, 4, 3 }},
+                                                                   std::array<std::size_t, 3>{{0, 1, 4 }},
+                                                                   std::array<std::size_t, 3>{{5, 4, 1 }},
+                                                                   std::array<std::size_t, 3>{{5, 1, 2 }},
+                                                                   std::array<std::size_t, 3>{{5, 2, 3 }},
+                                                                   std::array<std::size_t, 3>{{5, 3, 4 }} };
+
+      std::vector<dolfin::Point> vertices;
+      std::vector<std::array<std::size_t, 3> > triangles;
+      if (_sphere._segments > 1 )
+      {
+        refine_triangulation(initial_vertices,
+                             initial_triangles,
+                             _sphere._segments,
+                             vertices,
+                             triangles);
+      }
+      else
+      {
+        vertices.reserve(initial_vertices.size());
+        std::copy(initial_vertices.begin(), initial_vertices.end(), std::back_inserter(vertices));
+
+        triangles.reserve(initial_triangles.size());
+        std::copy(initial_triangles.begin(), initial_triangles.end(), std::back_inserter(triangles));
+      }
+
+      CGAL::Polyhedron_incremental_builder_3<Exact_HalfedgeDS> builder( hds, true );
+      builder.begin_surface(vertices.size(), triangles.size());
+
+      dolfin::Point center = _sphere.c;
+      for (const dolfin::Point& p : vertices)
+      {
+        const double scaling = _sphere.r/std::sqrt(p.x()*p.x() + p.y()*p.y() + p.z()*p.z());
+        add_vertex(builder, Exact_Point_3(center.x() + p.x()*scaling,
+                                          center.y() + p.y()*scaling,
+                                          center.z() + p.z()*scaling));
+      }
+
+      for (const std::array<std::size_t, 3>& t : triangles)
+      {
+        add_triangular_facet(builder, t[0], t[1], t[2]);
+      }
+
+      builder.end_surface();
+    }
+
+  private:
+    const mshr::Sphere& _sphere;
+  };
+  //-----------------------------------------------------------------------------
+  void make_sphere(const mshr::Sphere* s, Exact_Polyhedron_3& P)
+  {
+    Build_sphere builder(*s);
+    P.delegate(builder);
+    dolfin_assert(P.is_valid());
+    dolfin_assert(P.is_closed());
+  }
+  //-----------------------------------------------------------------------------
+  class Build_box : public CGAL::Modifier_base<Exact_HalfedgeDS>
+  {
+  public:
+    Build_box(const mshr::Box* box) : _box(box) {}
+
+    void operator()( Exact_HalfedgeDS& hds )
+    {
+      CGAL::Polyhedron_incremental_builder_3<Exact_HalfedgeDS> builder(hds, true);
+
+      builder.begin_surface(8, 12);
+
+      const double x0 = std::min(_box->a.x(), _box->b.x());
+      const double y0 = std::max(_box->a.x(), _box->b.x());
+
+      const double x1 = std::min(_box->a.y(), _box->b.y());
+      const double y1 = std::max(_box->a.y(), _box->b.y());
+
+      const double x2 = std::min(_box->a.z(), _box->b.z());
+      const double y2 = std::max(_box->a.z(), _box->b.z());
+
+      add_vertex(builder, Exact_Point_3(y0, x1, x2));
+      add_vertex(builder, Exact_Point_3(x0, x1, y2));
+      add_vertex(builder, Exact_Point_3(x0, x1, x2));
+      add_vertex(builder, Exact_Point_3(x0, y1, x2));
+      add_vertex(builder, Exact_Point_3(y0, x1, y2));
+      add_vertex(builder, Exact_Point_3(x0, y1, y2));
+      add_vertex(builder, Exact_Point_3(y0, y1, x2));
+      add_vertex(builder, Exact_Point_3(y0, y1, y2));
+
+      add_triangular_facet(builder, 1, 3, 2);
+      add_triangular_facet(builder, 1, 5, 3);
+      add_triangular_facet(builder, 1, 4, 5);
+      add_triangular_facet(builder, 4, 7, 5);
+      add_triangular_facet(builder, 4, 0, 7);
+      add_triangular_facet(builder, 0, 6, 7);
+      add_triangular_facet(builder, 0, 2, 6);
+      add_triangular_facet(builder, 2, 3, 6);
+      add_triangular_facet(builder, 7, 6, 5);
+      add_triangular_facet(builder, 6, 3, 5);
+      add_triangular_facet(builder, 1, 2, 4);
+      add_triangular_facet(builder, 2, 0, 4);
+
+      builder.end_surface();
+    }
+
+    const mshr::Box* _box;
+  };
+  //-----------------------------------------------------------------------------
+  void make_box(const mshr::Box* b, Exact_Polyhedron_3& P)
+  {
+    Build_box builder(b);
+    P.delegate(builder);
+    dolfin_assert(P.is_closed());
+    dolfin_assert(P.is_valid());
+  }
+  //-----------------------------------------------------------------------------
+  void make_tetrahedron(const mshr::Tetrahedron* b, Exact_Polyhedron_3& P)
+  {
+    P.make_tetrahedron(Exact_Point_3(b->a.x(), b->a.y(), b->a.z()),
+                       Exact_Point_3(b->b.x(), b->b.y(), b->b.z()),
+                       Exact_Point_3(b->c.x(), b->c.y(), b->c.z()),
+                       Exact_Point_3(b->d.x(), b->d.y(), b->d.z()));
+  }
+  //-----------------------------------------------------------------------------
+  // Return some unit vector orthogonal to a
+  dolfin::Point generate_orthogonal(const dolfin::Point& a)
+  {
+    const dolfin::Point b(0, 1, 0);
+    const dolfin::Point c(0, 0, 1);
+
+    // Find a vector not parallel to a.
+    const dolfin::Point d = (fabs(a.dot(b)) < fabs(a.dot(c))) ? b : c;
+    const dolfin::Point orthogonal = a.cross(d);
+    return orthogonal/orthogonal.norm();
+  }
+  //-----------------------------------------------------------------------------
+  class Build_cylinder : public CGAL::Modifier_base<Exact_HalfedgeDS>
+  {
+  public:
+    Build_cylinder(const mshr::Cylinder* cylinder) : _cylinder(cylinder) {}
+
+    void operator()(Exact_HalfedgeDS& hds)
+    {
+      const dolfin::Point axis = (_cylinder->_top - _cylinder->_bottom)/(_cylinder->_top - _cylinder->_bottom).norm();
+      dolfin::Point initial = generate_orthogonal(axis);
+      dolfin_assert(dolfin::near(initial.norm(), 1.0));
+
+      CGAL::Polyhedron_incremental_builder_3<Exact_HalfedgeDS> builder(hds, true);
+
+      const int num_sides = _cylinder->_segments;
+      const bool top_degenerate = dolfin::near(_cylinder->_top_radius, 0.0);
+      const bool bottom_degenerate = dolfin::near(_cylinder->_bottom_radius, 0.0);
+
+      const int num_vertices = (top_degenerate || bottom_degenerate) ? num_sides+2 : num_sides*2+2;
+
+      builder.begin_surface(num_vertices, num_sides*4);
+
+      const double delta_theta = 2.0 * DOLFIN_PI / num_sides;
+      for (int i = 0; i < num_sides; ++i)
+      {
+        const double theta = i*delta_theta;
+        const dolfin::Point rotated = initial.rotate(axis, theta);
+        if (!bottom_degenerate)
+        {
+          const dolfin::Point p = _cylinder->_bottom + rotated*_cylinder->_bottom_radius;
+          const Exact_Point_3 p_(p.x(), p.y(), p.z());
+          add_vertex(builder, p_);
+        }
+        if (!top_degenerate)
+        {
+          const dolfin::Point p = _cylinder->_top + rotated*_cylinder->_top_radius;
+          const Exact_Point_3 p_(p.x(), p.y(), p.z());
+          add_vertex(builder, p_);
+        }
+      }
+
+      // The top and bottom vertices
+      add_vertex(builder, Exact_Point_3(_cylinder->_bottom.x(), _cylinder->_bottom.y(),
+                                        _cylinder->_bottom.z()));
+      add_vertex(builder, Exact_Point_3(_cylinder->_top.x(), _cylinder->_top.y(),
+                                        _cylinder->_top.z()));
+
+      // bottom vertex has index num_vertices-2, top vertex has index num_vertices-1
+
+      // Construct the facets on the side.
+      // Vertices must be sorted counter clockwise seen from inside.
+      for (int i = 0; i < num_sides; ++i)
+      {
+        if (top_degenerate)
+        {
+          add_triangular_facet(builder, (i + 1)%num_sides, num_vertices - 1, i);
+        }
+        else if (bottom_degenerate)
+        {
+          add_triangular_facet(builder, i, num_vertices - 1, (i + 1) % num_sides);
+        }
+        else
+        {
+          //Draw the sides as triangles.
+          const int vertex_offset = i*2;
+
+          // First triangle
+          add_triangular_facet(builder, vertex_offset, (vertex_offset + 2) % (num_sides*2), vertex_offset + 1);
+
+          // Second triangle
+          add_triangular_facet(builder, (vertex_offset + 3) % (num_sides*2), vertex_offset + 1,
+                               (vertex_offset + 2) % (num_sides*2));
+        }
+      }
+
+      // Construct the bottom facet.
+      if (!bottom_degenerate)
+      {
+        for (int i = num_sides-1; i >= 0; i -= 1)
+        {
+          if (!top_degenerate)
+          {
+            add_triangular_facet(builder, num_vertices-2,( (i+1)*2) % (num_sides*2), i*2);
+          }
+          else
+          {
+            add_triangular_facet(builder, num_vertices-2, (i+1)%num_sides, i);
+          }
+        }
+      }
+
+      // Construct the the top facet
+      if (!top_degenerate)
+      {
+        for (int i = 0; i < num_sides; i++)
+        {
+          if (!bottom_degenerate)
+          {
+            add_triangular_facet(builder, num_vertices-1, i*2 + 1, ( (i+1)*2)%(num_sides*2) +1);
+          }
+          else
+          {
+            add_triangular_facet(builder, num_vertices-2, i, (i+1)%num_sides);
+          }
+        }
+      }
+
+      builder.end_surface();
+    }
+  private:
+    const mshr::Cylinder* _cylinder;
+  };
+  //-----------------------------------------------------------------------------
+  void make_cylinder(const mshr::Cylinder* c, Exact_Polyhedron_3& P)
+  {
+    Build_cylinder builder(c);
+    P.delegate(builder);
+    dolfin_assert(P.is_closed());
+    dolfin_assert(P.is_valid());
+  }
+  //-----------------------------------------------------------------------------
+  class Build_ellipsoid : public CGAL::Modifier_base<Exact_HalfedgeDS>
+  {
+  public:
+    Build_ellipsoid(const mshr::Ellipsoid& ellipsoid) : _ellipsoid(ellipsoid) {}
+
+    void operator()(Exact_HalfedgeDS& hds)
+    {
+      std::vector<dolfin::Point> initial_vertices { dolfin::Point( 0.0, 0.0, 1.0 ),
+          dolfin::Point( 1.0, 0.0, 0.0 ),
+          dolfin::Point( 0.0,-1.0, 0.0 ),
+          dolfin::Point(-1.0, 0.0, 0.0 ),
+          dolfin::Point( 0.0, 1.0, 0.0 ),
+          dolfin::Point( 0.0, 0.0,-1.0 )};
+
+      // Note: Some older compilers (eg. gcc on Ubuntu Precise) require std::array<std::size_t, 3> to be
+      // given explicitly in the initializer list.
+      std::vector<std::array<std::size_t, 3> > initial_triangles { std::array<std::size_t, 3>{{0, 2, 1 }},
+          std::array<std::size_t, 3>{{0, 3, 2 }},
+            std::array<std::size_t, 3>{{0, 4, 3 }},
+              std::array<std::size_t, 3>{{0, 1, 4 }},
+                std::array<std::size_t, 3>{{5, 4, 1 }},
+                  std::array<std::size_t, 3>{{5, 1, 2 }},
+                    std::array<std::size_t, 3>{{5, 2, 3 }},
+                      std::array<std::size_t, 3>{{5, 3, 4 }} };
+
+      std::vector<dolfin::Point> vertices;
+      std::vector<std::array<std::size_t, 3> > triangles;
+      if (_ellipsoid._segments > 1 )
+      {
+        refine_triangulation(initial_vertices,
+                             initial_triangles,
+                             _ellipsoid._segments,
+                             vertices,
+                             triangles);
+      }
+      else
+      {
+        vertices.reserve(initial_vertices.size());
+        std::copy(initial_vertices.begin(), initial_vertices.end(), std::back_inserter(vertices));
+
+        triangles.reserve(initial_triangles.size());
+        std::copy(initial_triangles.begin(), initial_triangles.end(), std::back_inserter(triangles));
+      }
+
+      CGAL::Polyhedron_incremental_builder_3<Exact_HalfedgeDS> builder( hds, true );
+      builder.begin_surface(vertices.size(), triangles.size());
+
+      dolfin::Point center = _ellipsoid.center;
+      const double a = _ellipsoid.a, b = _ellipsoid.b, c = _ellipsoid.c;
+      for (const dolfin::Point& p : vertices)
+      {
+        const double scaling = 1.0/std::sqrt( (p.x()*p.x())/(a*a) +
+                                              (p.y()*p.y())/(b*b) +
+                                              (p.z()*p.z())/(c*c) );
+        add_vertex(builder, Exact_Point_3(center.x() + p.x()*scaling,
+                                          center.y() + p.y()*scaling,
+                                          center.z() + p.z()*scaling));
+      }
+
+      for (const std::array<std::size_t, 3>& t : triangles)
+      {
+        add_triangular_facet(builder, t[0], t[1], t[2]);
+      }
+
+      builder.end_surface();
+    }
+
+    const mshr::Ellipsoid& _ellipsoid;
+  };
+  //-----------------------------------------------------------------------------
+  void make_ellipsoid(const mshr::Ellipsoid* e, Exact_Polyhedron_3& P)
+  {
+    Build_ellipsoid builder(*e);
+    P.delegate(builder);
+    dolfin_assert(P.is_closed());
+    dolfin_assert(P.is_valid());
+  }
+  //-----------------------------------------------------------------------------
+  template <class HDS>
+  class BuildFromFacetList : public CGAL::Modifier_base<HDS>
+  {
+  public:
+    BuildFromFacetList(const std::vector<std::array<double, 3> >& vertices,
+                       const std::vector<std::array<std::size_t, 3> >& facets,
+                       const std::set<std::size_t>& facets_to_be_skipped)
+      : vertices(vertices), facets(facets), facets_to_be_skipped(facets_to_be_skipped){}
+    void operator()(HDS& hds)
+    {
+      std::set<std::size_t> isolated_vertices;
+      if (facets_to_be_skipped.size() > 0)
+      {
+        for (std::size_t i = 0; i < vertices.size(); i++)
+          isolated_vertices.insert(i);
+
+        for (std::size_t j = 0; j < facets.size(); j++)
+        {
+          if (facets_to_be_skipped.count(j) == 0)
+          {
+            for (auto it2 = facets[j].begin(); it2 != facets[j].end(); it2++)
+              isolated_vertices.erase(*it2);
+          }
+        }
+      }
+
+      // std::cout << "Isolated vertices: " << isolated_vertices.size() << std::endl;
+
+      CGAL::Polyhedron_incremental_builder_3<HDS> builder(hds, true);
+
+      builder.begin_surface(vertices.size(), facets.size());
+
+      for (std::size_t i = 0; i < vertices.size(); i++)
+      {
+        if (isolated_vertices.count(i) == 0)
+          builder.add_vertex(Exact_Point_3( vertices[i][0], vertices[i][1], vertices[i][2]) );
+      }
+
+      const bool has_isolated_vertices = isolated_vertices.size() > 0;
+      std::vector<std::size_t> iv(isolated_vertices.begin(), isolated_vertices.end());
+      std::sort(iv.begin(), iv.end());
+      for (std::size_t i = 0; i < facets.size(); i++)
+      {
+        if (facets_to_be_skipped.count(i) == 0)
+        {
+          if (has_isolated_vertices)
+          {
+            std::vector<std::size_t> f;
+            f.reserve(facets[i].size());
+            for (auto it = facets[i].begin(); it != facets[i].end(); it++)
+            {
+              f.push_back(*it - std::distance(iv.begin(), std::lower_bound(iv.begin(), iv.end(), *it)));
+            }
+            builder.add_facet(f.begin(), f.end());
+          }
+          else
+            builder.add_facet(facets[i].begin(), facets[i].end());
+
+          if (builder.error())
+          {
+            dolfin::dolfin_error("CSGCGALDomain3D.cpp",
+                                 "read surface from file",
+                                 "error in polyhedron builder");
+          }
+        }
+        else
+        {
+          // std::cout << "Skipping" << std::endl;
+        }
+      }
+
+      builder.end_surface();
+
+    }
+    const std::vector<std::array<double, 3> >& vertices;
+    const std::vector<std::array<std::size_t, 3> >& facets;
+    const std::set<std::size_t>& facets_to_be_skipped;
+  };
+  //-----------------------------------------------------------------------------
+  void make_surface3D(const mshr::Surface3D* s, Exact_Polyhedron_3& P)
+  {
+    dolfin_assert(s);
+
+    std::vector<std::array<double, 3> > vertices;
+    std::vector<std::array<std::size_t, 3> > facets;
+    std::set<std::size_t> skip;
+
+    if (s->_filename == "")
+    {
+      dolfin_assert(s->mesh);
+
+      std::unique_ptr<dolfin::BoundaryMesh> b;
+
+      if (s->use_cell_domain)
+      {
+        std::shared_ptr<dolfin::Mesh> m = mshr::DolfinMeshUtils::extract_subdomain(s->mesh, s->cell_domain);
+        b.reset(new dolfin::BoundaryMesh(*m, "exterior", false));
+      }
+      else
+      {
+        // Extract global boundary of mesh, order with outward pointing normals
+        b.reset(new dolfin::BoundaryMesh(*(s->mesh), "exterior", false));
+      }
+
+      for (dolfin::VertexIterator v(*b); !v.end(); ++v)
+      {
+        const dolfin::Point& p = v->point();
+        vertices.push_back(std::array<double, 3>{{p[0], p[1], p[2]}});
+      }
+
+      for (dolfin::CellIterator c(*b); !c.end(); ++c)
+      {
+        const unsigned int* vertices = c->entities(0);
+        facets.push_back(std::array<std::size_t, 3>{{vertices[0], vertices[1], vertices[2]}});
+      }
+    }
+    else
+    {
+      boost::filesystem::path fpath(s->_filename);
+      if (fpath.extension() == ".off")
+      {
+        mshr::OFFFileReader::read(s->_filename, vertices, facets);
+      }
+      else
+      {
+        if (fpath.extension() == ".stl")
+        {
+          mshr::STLFileReader::read(s->_filename, vertices, facets);
+        }
+       else if (fpath.extension() == ".asc") // ADDED
+       {
+       mshr::ASCFileReader::read(s->_filename, vertices, facets);
+       }
+        else
+        {
+          dolfin::dolfin_error("CSGCGALDomain3D.cpp",
+                               "open file to read 3D surface",
+                               "Unknown file type");
+        }
+
+        log(dolfin::TRACE, "Done reading file");
+      }
+
+      if (s->flip_facets)
+      {
+        log(dolfin::TRACE, "Flipping facets");
+        for (std::vector<std::array<std::size_t, 3> >::iterator it = facets.begin();
+             it != facets.end(); it++)
+        {
+          std::array<std::size_t, 3>& t = *it;
+          std::swap(t[1], t[2]);
+        }
+      }
+
+      // std::pair<std::unique_ptr<std::vector<std::array<double, 3> > >,
+      //           std::unique_ptr<std::vector<std::array<std::size_t, 3> > > > filtered =
+      //   SurfaceConsistency::merge_close_vertices(facets, vertices);
+
+      // log(dolfin::TRACE, "Checking connectivity");
+
+      //mshr::closest_vertices(vertices);
+
+      if (s->repair)
+      {
+        {
+          const std::size_t removed = mshr::SurfaceConsistency::remove_null_facets(facets);
+          if (removed > 0)
+            log(dolfin::TRACE, "Removed %u degenerate facets", removed);
+        }
+
+        {
+          const std::size_t removed = mshr::SurfaceConsistency::remove_isolated_vertices(vertices, facets);
+          if (removed > 0)
+            log(dolfin::TRACE, "Removed %u isolated vertices", removed);
+        }
+
+
+        // TODO: Orient all components
+        mshr::SurfaceConsistency::orient_component(facets, 0);
+        // std::size_t start_facet = s->first_facet;
+
+        std::set<std::size_t> duplicating;
+        mshr::SurfaceConsistency::checkConnectivity(facets, duplicating, false);
+        log(dolfin::TRACE, "%u facets filtered out", duplicating.size());
+        skip.insert(duplicating.begin(), duplicating.end());
+
+
+        // SurfaceConsistency::filterFacets(facets,
+        // vertices,
+        // start_facet,
+        // skip);
+
+        // std::vector<std::array<std::size_t, 3> > filtered_facets;
+        // filtered_facets.reserve(facets.size()-skip.size());
+        // for (std::size_t i = 0; i < facets.size(); i++)
+        // {
+        //   if (skip.count(i) == 0)
+        //     filtered_facets.push_back(facets[i]);
+        // }
+      }
+
+      // std::cout << "Duplicating: " << duplicating.size() << std::endl;
+      // for (auto it = duplicating.begin(); it != duplicating.end(); it++)
+      //   std::cout << *it << " ";
+      // std::cout << std::endl;
+
+    } // end read from file
+
+    if (s->debug_dump != "")
+    {
+      log(dolfin::TRACE, "Dumping to file '%s'", s->debug_dump.c_str());
+      mshr::OFFFileReader::write(s->debug_dump,
+                                 vertices,
+                                 facets);
+    }
+
+
+    // Create the polyhedron
+    BuildFromFacetList<Exact_HalfedgeDS> builder(vertices, facets, skip);
+    P.delegate(builder);
+    log(dolfin::TRACE, "Done creating polyhedron");
+
+    if (!P.is_valid())
+    {
+      dolfin::dolfin_error("CSGCGALDomain3D.cpp",
+                           "read surface from file",
+                           "Polyhedron is not valid. If you are sure your file is valid, please file a bug report");
+    }
+
+    P.normalize_border();
+
+    // {
+    //   std::size_t num_vertices = P.size_of_vertices();
+    //   std::list<typename Exact_Polyhedron_3::Vertex_const_handle> components;
+    //   mshr::PolyhedronUtils::get_disconnected_components(P, std::back_inserter(components));
+    //   std::cout << "Number of components: " << components.size() << std::endl;
+    //   const unsigned int deleted = P.keep_largest_connected_components(1);
+    //   std::cout << "Deleted " << deleted << " disconnected components with " << num_vertices-P.size_of_vertices() << " vertices" << std::endl;
+    //   std::cout << "Min vertex degree before closing: " << mshr::PolyhedronUtils::min_vertex_degree(P) << std::endl;
+    //   std::cout << "Is pure triangular: " << (P.is_pure_triangle() ? "True" : "False") << std::endl;
+    //   int tmp;
+    //   std::cin >> tmp;
+    // }
+
+    // Triangulate polyhedron
+    //mshr::PolyhedronUtils::triangulate_polyhedron(P);
+    dolfin_assert (P.is_pure_triangle());
+
+    // remove self-intersecting facets
+    if (s->repair)
+    {
+      if (s->sharp_features_filter >= 0)
+      {
+        mshr::PolyhedronUtils::filter_sharp_features(P,
+                                                     s->sharp_features_filter,
+                                                     DOLFIN_PI/6.0);
+      }
+
+      // FIXME: Should this be enabled?
+      // mshr::PolyhedronUtils::remove_self_intersections(P);
+      // mshr::PolyhedronUtils::close_holes(P);
+    }
+
+    // mshr::PolyhedronUtils::list_self_intersections(P);
+
+    // if (s->degenerate_tolerance > 0)
+    // {
+    //   if (remove_degenerate(P, s->degenerate_tolerance))
+    //     log(dolfin::TRACE, "Removed degenerate facets from '%s'",
+    //         s->_filename.c_str());
+    // }
+
+    // if (!P.is_closed())
+    // {
+    //   if (s->repair)
+    //   {
+    //     mshr::PolyhedronUtils::cut_holes(P);
+
+    //     dolfin_assert(P.is_closed());
+    //     dolfin_assert(P.is_pure_triangle());
+    //     remove_degenerate(P, s->degenerate_tolerance);
+    //   }
+    //   else
+    //   {
+    //     dolfin::dolfin_error("CSGCGALDomain3D.cpp",
+    //                          "read surface from file",
+    //                          "Surface is not closed.");
+    //   }
+    // }
+  }
+//-----------------------------------------------------------------------------
+  template <class Polyhedron>
+  struct Insert_polyhedron_to
+    : public CGAL::Modifier_base<typename Polyhedron::HalfedgeDS>
+  {
+    Insert_polyhedron_to(const Polyhedron& in_poly)
+      : _in_poly(in_poly) {}
+
+    void operator()(typename Polyhedron::HalfedgeDS& hds)
+    {
+      typedef typename Polyhedron::HalfedgeDS HDS;
+
+      CGAL::Polyhedron_incremental_builder_3<HDS> builder(hds);
+
+      typedef typename Polyhedron::Vertex_const_iterator Vertex_const_iterator;
+      typedef typename Polyhedron::Facet_const_iterator  Facet_const_iterator;
+      typedef typename Polyhedron::Halfedge_around_facet_const_circulator HFCC;
+
+      builder.begin_surface(_in_poly.size_of_vertices(),
+                            _in_poly.size_of_facets(),
+                            _in_poly.size_of_halfedges());
+
+      for(Vertex_const_iterator
+            vi = _in_poly.vertices_begin(), end = _in_poly.vertices_end();
+          vi != end ; ++vi)
+      {
+        builder.add_vertex(vi->point());
+      }
+
+      typedef CGAL::Inverse_index<Vertex_const_iterator> Index;
+      Index index(_in_poly.vertices_begin(), _in_poly.vertices_end());
+
+      for(Facet_const_iterator
+            fi = _in_poly.facets_begin(), end = _in_poly.facets_end();
+          fi != end; ++fi)
+      {
+        HFCC hc = fi->facet_begin();
+        HFCC hc_end = hc;
+        //     std::size_t n = circulator_size( hc);
+        //     CGAL_assertion( n >= 3);
+        builder.begin_facet ();
+        do
+        {
+          builder.add_vertex_to_facet(index[hc->vertex()]);
+          ++hc;
+        } while( hc != hc_end);
+        builder.end_facet();
+      }
+      builder.end_surface();
+    } // end operator()(..)
+  private:
+    const Polyhedron& _in_poly;
+  }; // end Copy_polyhedron_to<>
+//-----------------------------------------------------------------------------
+  template <class HDS>
+  class BuildExtrude2D : public CGAL::Modifier_base<HDS>
+  {
+  public:
+    BuildExtrude2D(const mshr::CSGGeometry& polygon, double z)
+      : polygon(polygon), z(z){}
+    void operator()(HDS& hds)
+    {
+      // Let the 2d mesh generator triangulate the polygon
+      std::shared_ptr<dolfin::Mesh> mesh2d(new dolfin::Mesh());
+      {
+        mshr::CSGCGALMeshGenerator2D generator;
+        generator.parameters["mesh_resolution"] = 2.0;
+        generator.parameters["partition"] = false;
+
+        const std::pair<dolfin::Point, double> bounding_circle = polygon.estimate_bounding_sphere();
+
+        // Generate 2D mesh (on all nodes if in parallel)
+        std::shared_ptr<mshr::CSGCGALDomain2D>
+          d2(new mshr::CSGCGALDomain2D(dolfin::reference_to_no_delete_pointer(polygon),
+                                       bounding_circle.second/6.));
+
+        mesh2d = generator.generate(d2);
+      }
+
+      CGAL::Polyhedron_incremental_builder_3<HDS> builder(hds, true);
+
+      builder.begin_surface(0, 0);
+
+      const double min_z = std::min(0., z);
+      const double max_z = std::max(0., z);
+
+      // Copy vertices to the new 3d polyhedron
+      const std::vector<double>& vertices = mesh2d->coordinates();
+      for (std::size_t i = 0; i < vertices.size()/2; i++)
+      {
+        builder.add_vertex(Exact_Point_3(vertices[2*i], vertices[2*i+1], min_z));
+        builder.add_vertex(Exact_Point_3(vertices[2*i], vertices[2*i+1], max_z));
+      }
+
+      // Add the triangles from the 2d mesh at z=0 and z=z
+      for (dolfin::CellIterator c(*mesh2d); !c.end(); ++c)
+      {
+        const unsigned int* v_indices = c->entities(0);
+        const bool flip = Exact_Triangle_2(Exact_Point_2(vertices[2*v_indices[0]], vertices[2*v_indices[0]+1]),
+                                           Exact_Point_2(vertices[2*v_indices[1]], vertices[2*v_indices[1]+1]),
+                                           Exact_Point_2(vertices[2*v_indices[2]], vertices[2*v_indices[2]+1])).orientation() == CGAL::POSITIVE;
+        builder.begin_facet();
+        builder.add_vertex_to_facet(2*v_indices[0]);
+        if (flip)
+        {
+          builder.add_vertex_to_facet(2*v_indices[2]);
+          builder.add_vertex_to_facet(2*v_indices[1]);
+        }
+        else
+        {
+          builder.add_vertex_to_facet(2*v_indices[1]);
+          builder.add_vertex_to_facet(2*v_indices[2]);
+        }
+
+        builder.end_facet();
+
+        builder.begin_facet();
+        builder.add_vertex_to_facet(2*v_indices[0]+1);
+        if (!flip)
+        {
+          builder.add_vertex_to_facet(2*v_indices[2]+1);
+          builder.add_vertex_to_facet(2*v_indices[1]+1);
+        }
+        else
+        {
+          builder.add_vertex_to_facet(2*v_indices[1]+1);
+          builder.add_vertex_to_facet(2*v_indices[2]+1);
+        }
+        builder.end_facet();
+      }
+
+      // Connect the two polygons
+      dolfin::BoundaryMesh bdr(*mesh2d, "exterior", false);
+      const dolfin::MeshFunction<std::size_t>& vertex_map = bdr.entity_map(0);
+      for (dolfin::CellIterator cell(bdr); !cell.end(); ++cell)
+      {
+        const unsigned int* v_indices = cell->entities(0);
+        builder.begin_facet();
+        builder.add_vertex_to_facet(2*vertex_map[v_indices[0]]);
+        builder.add_vertex_to_facet(2*vertex_map[v_indices[1]]);
+        builder.add_vertex_to_facet(2*vertex_map[v_indices[0]]+1);
+        builder.end_facet();
+
+        builder.begin_facet();
+        builder.add_vertex_to_facet(2*vertex_map[v_indices[1]]);
+        builder.add_vertex_to_facet(2*vertex_map[v_indices[1]]+1);
+        builder.add_vertex_to_facet(2*vertex_map[v_indices[0]]+1);
+        builder.end_facet();
+
+      }
+
+      builder.end_surface();
+    }
+
+    const mshr::CSGGeometry& polygon;
+    const double z;
+  };
+// ----
+  void make_extrude2D(const mshr::Extrude2D* e, Exact_Polyhedron_3& P)
+  {
+    dolfin_assert(e);
+
+    //CSGCGALDomain2D polygon(e->geometry_2d.get());
+    BuildExtrude2D<Exact_HalfedgeDS> builder(*e->geometry_2d, e->z);
+    P.delegate(builder);
+  }
+//-----------------------------------------------------------------------------
+  Aff_transformation_3 get_scaling(const mshr::CSGScaling& s)
+  {
+    Aff_transformation_3 transformation(CGAL::IDENTITY);
+    if (s.translate)
+    {
+      Aff_transformation_3 translation(CGAL::TRANSLATION,
+                                       Vector_3(-s.c.x(),
+                                                -s.c.y(),
+                                                -s.c.z()));
+      transformation = translation * transformation;
+    }
+
+    Aff_transformation_3 scaling(CGAL::SCALING, s.s);
+    transformation = scaling * transformation;
+
+    if (s.translate)
+    {
+      Aff_transformation_3 translation(CGAL::TRANSLATION,
+                                       Vector_3(s.c.x(),
+                                                s.c.y(),
+                                                s.c.z()));
+      transformation = translation * transformation;
+    }
+
+    return transformation;
+  }
+//-----------------------------------------------------------------------------
+  Aff_transformation_3 get_rotation(const mshr::CSGRotation& r)
+  {
+    // Normalize rotation axis vector
+    dolfin::Point axis = r.rot_axis/(r.rot_axis.norm());
+    dolfin_assert(dolfin::near(axis.norm(), 1.0));
+
+    Aff_transformation_3 transformation(CGAL::IDENTITY);
+    if (r.translate)
+    {
+      Aff_transformation_3 translation(CGAL::TRANSLATION,
+                                       Vector_3(-r.c.x(),
+                                                -r.c.y(),
+                                                -r.c.z()));
+      transformation = translation * transformation;
+    }
+
+    // The Euler-Rodrigues formula
+    const double a = cos(r.theta/2);
+    const double b = -axis.x()*sin(r.theta/2);
+    const double c = -axis.y()*sin(r.theta/2);
+    const double d = -axis.z()*sin(r.theta/2);
+
+    Aff_transformation_3 rotation(a*a+b*b-c*c-d*d,
+                                  2*(b*c-a*d),
+                                  2*(b*d+a*c),
+                                  2*(b*c+a*d),
+                                  a*a+c*c-b*b-d*d,
+                                  2*(c*d-a*b),
+                                  2*(b*d-a*c),
+                                  2*(c*d+a*b),
+                                  a*a+d*d-b*b-c*c);
+    transformation = rotation * transformation;
+
+    if (r.translate)
+    {
+      Aff_transformation_3 translation(CGAL::TRANSLATION,
+                                       Vector_3(r.c.x(),
+                                                r.c.y(),
+                                                r.c.z()));
+      transformation = translation * transformation;
+    }
+
+    return transformation;
+  }
+//-----------------------------------------------------------------------------
+#ifdef MSHR_ENABLE_EXPERIMENTAL
+  bool polyline_is_degenerate(const std::vector<Exact_Point_3>& polyline, double tol)
+  {
+    double length = 0;
+    std::vector<Exact_Point_3>::const_iterator it = polyline.begin();
+    Exact_Point_3 prev = *it;
+    it++;
+    for (;it != polyline.end(); it++)
+    {
+      length += CGAL::to_double((*it-prev).squared_length());
+    }
+    length += CGAL::to_double((polyline.back()-polyline.front()).squared_length());
+
+    return length < tol;
+  }
+
+
+  typedef CGAL::Polyhedron_corefinement<Exact_Polyhedron_3> CGALCSGOperator;
+
+  void convertSubTree(const mshr::CSGGeometry* geometry, Exact_Polyhedron_3& P)
+  {
+    switch (geometry->getType())
+    {
+    case mshr::CSGGeometry::Union :
+    {
+      const mshr::CSGUnion* u = dynamic_cast<const mshr::CSGUnion*>(geometry);
+      dolfin_assert(u);
+      convertSubTree(u->_g0.get(), P);
+      Exact_Polyhedron_3 P2;
+      convertSubTree(u->_g1.get(), P2);
+
+      std::list<std::vector<Exact_Point_3> > intersection_polylines;
+      CGALCSGOperator op;
+      op(P, P2, std::back_inserter(intersection_polylines), CGALCSGOperator::Join_tag);
+
+      // Check that intersection is not degenerate
+      for (std::list<std::vector<Exact_Point_3> >::iterator it=intersection_polylines.begin();
+           it != intersection_polylines.end(); it++)
+      {
+       if (polyline_is_degenerate(*it, DOLFIN_EPS))
+       {
+         dolfin::dolfin_error("CSGCGALDomain3D.cpp",
+                              "union of csg geometries",
+                              "degenerate intersection polyline (geometries meet in a single point?)");
+       }
+      }
+      break;
+    }
+    case mshr::CSGGeometry::Intersection :
+    {
+      const mshr::CSGIntersection* u = dynamic_cast<const mshr::CSGIntersection*>(geometry);
+      dolfin_assert(u);
+      convertSubTree(u->_g0.get(), P);
+      Exact_Polyhedron_3 P2;
+      convertSubTree(u->_g1.get(), P2);
+
+      std::list<std::vector<Exact_Point_3> > intersection_polylines;
+      CGALCSGOperator op;
+      op(P, P2, std::back_inserter(intersection_polylines), CGALCSGOperator::Intersection_tag);
+
+      // Check that intersection is not degenerate
+      for (std::list<std::vector<Exact_Point_3> >::iterator it=intersection_polylines.begin();
+           it != intersection_polylines.end(); it++)
+      {
+       if (polyline_is_degenerate(*it, DOLFIN_EPS))
+       {
+         dolfin::dolfin_error("CSGCGALDomain3D.cpp",
+                              "intersection of csg geometries",
+                              "degenerate intersection polyline (geometries meet in a single point?)");
+       }
+      }
+
+      break;
+    }
+    case mshr::CSGGeometry::Difference :
+    {
+      std::cout << "Difference operator" << std::endl;
+      const mshr::CSGDifference* u = dynamic_cast<const mshr::CSGDifference*>(geometry);
+      dolfin_assert(u);
+      convertSubTree(u->_g0.get(), P);
+      Exact_Polyhedron_3 P2;
+      convertSubTree(u->_g1.get(), P2);
+
+      std::list<std::vector<Exact_Point_3> > intersection_polylines;
+      CGALCSGOperator op;
+      op(P, P2, std::back_inserter(intersection_polylines), CGALCSGOperator::P_minus_Q_tag);
+
+      std::cout << "Checking polyline" << std::endl;
+      // Check that intersection is not degenerate
+      for (std::list<std::vector<Exact_Point_3> >::iterator it=intersection_polylines.begin();
+           it != intersection_polylines.end(); it++)
+      {
+       if (polyline_is_degenerate(*it, DOLFIN_EPS))
+       {
+         dolfin::dolfin_error("CSGCGALDomain3D.cpp",
+                              "difference of csg geometries",
+                              "degenerate intersection polyline (geometries meet in a single point?)");
+       }
+      }
+
+      break;
+    }
+    case mshr::CSGGeometry::Translation :
+    {
+      const mshr::CSGTranslation* t = dynamic_cast<const mshr::CSGTranslation*>(geometry);
+      dolfin_assert(t);
+      convertSubTree(t->g.get(), P);
+      Aff_transformation_3 translation(CGAL::TRANSLATION, Vector_3(t->t.x(), t->t.y(), t->t.z()));
+      std::transform(P.points_begin(), P.points_end(), P.points_begin(), translation);
+      break;
+    }
+    case mshr::CSGGeometry::Scaling :
+    {
+      const mshr::CSGScaling* t = dynamic_cast<const mshr::CSGScaling*>(geometry);
+      dolfin_assert(t);
+      convertSubTree(t->g.get(), P);
+
+      Aff_transformation_3 scaling = get_scaling(*t);
+      std::transform(P.points_begin(), P.points_end(), P.points_begin(), scaling);
+      break;
+    }
+    case mshr::CSGGeometry::Rotation :
+    {
+      const mshr::CSGRotation* t = dynamic_cast<const mshr::CSGRotation*>(geometry);
+      dolfin_assert(t);
+
+      convertSubTree(t->g.get(), P);
+      Aff_transformation_3 rotation = get_rotation(*t);
+      std::transform(P.points_begin(), P.points_end(), P.points_begin(), rotation);
+      break;
+    }
+    case mshr::CSGGeometry::Cylinder :
+    {
+      const mshr::Cylinder* c = dynamic_cast<const mshr::Cylinder*>(geometry);
+      dolfin_assert(c);
+      make_cylinder(c, P);
+      break;
+    }
+    case mshr::CSGGeometry::Sphere :
+    {
+      const mshr::Sphere* s = dynamic_cast<const mshr::Sphere*>(geometry);
+      dolfin_assert(s);
+      make_sphere(s, P);
+      break;
+    }
+    case mshr::CSGGeometry::Box :
+    {
+      const mshr::Box* b = dynamic_cast<const mshr::Box*>(geometry);
+      dolfin_assert(b);
+      make_box(b, P);
+      break;
+    }
+    case mshr::CSGGeometry::Tetrahedron :
+    {
+      const mshr::Tetrahedron* b = dynamic_cast<const mshr::Tetrahedron*>(geometry);
+      dolfin_assert(b);
+      make_tetrahedron(b, P);
+      break;
+    }
+    case mshr::CSGGeometry::Ellipsoid :
+    {
+      const mshr::Ellipsoid* b = dynamic_cast<const mshr::Ellipsoid*>(geometry);
+      dolfin_assert(b);
+      make_ellipsoid(b, P);
+      break;
+    }
+    case mshr::CSGGeometry::Surface3D :
+    {
+      const mshr::Surface3D* b = dynamic_cast<const mshr::Surface3D*>(geometry);
+      dolfin_assert(b);
+      make_surface3D(b, P);
+      break;
+    }
+    case mshr::CSGGeometry::TriPolyhedron :
+    {
+      const mshr::CSGCGALDomain3D* b = dynamic_cast<const mshr::CSGCGALDomain3D*>(geometry);
+      dolfin_assert(b);
+      Insert_polyhedron_to<Exact_Polyhedron_3> inserter(b->impl->p);
+      P.delegate(inserter);
+      dolfin_assert(P.is_valid());
+      break;
+    }
+    case mshr::CSGGeometry::Extrude2D :
+    {
+      const mshr::Extrude2D* e = dynamic_cast<const mshr::Extrude2D*>(geometry);
+      dolfin_assert(e);
+      make_extrude2D(e, P);
+      break;
+    }
+    default:
+      dolfin::dolfin_error("CSGCGALDomain.cpp",
+                           "converting geometry to cgal polyhedron",
+                           "Unhandled primitive type");
+    }
+    }
+#else
+    std::shared_ptr<Nef_polyhedron_3>
+      convertSubTree(const mshr::CSGGeometry *geometry)
+    {
+      switch (geometry->getType())
+      {
+      case mshr::CSGGeometry::Union :
+      {
+        const mshr::CSGUnion* u = dynamic_cast<const mshr::CSGUnion*>(geometry);
+        dolfin_assert(u);
+        std::shared_ptr<Nef_polyhedron_3> g0 = convertSubTree(u->_g0.get());
+        std::shared_ptr<Nef_polyhedron_3> g1 = convertSubTree(u->_g1.get());
+        (*g0) += (*g1);
+        return g0;
+
+        break;
+      }
+      case mshr::CSGGeometry::Intersection :
+      {
+        const mshr::CSGIntersection* u = dynamic_cast<const mshr::CSGIntersection*>(geometry);
+        dolfin_assert(u);
+        std::shared_ptr<Nef_polyhedron_3> g0 = convertSubTree(u->_g0.get());
+        std::shared_ptr<Nef_polyhedron_3> g1 = convertSubTree(u->_g1.get());
+        (*g0) *= (*g1);
+        return g0;
+        break;
+      }
+      case mshr::CSGGeometry::Difference :
+      {
+        const mshr::CSGDifference* u = dynamic_cast<const mshr::CSGDifference*>(geometry);
+        dolfin_assert(u);
+        std::shared_ptr<Nef_polyhedron_3> g0 = convertSubTree(u->_g0.get());
+        std::shared_ptr<Nef_polyhedron_3> g1 = convertSubTree(u->_g1.get());
+        (*g0) -= (*g1);
+        return g0;
+        break;
+      }
+      case mshr::CSGGeometry::Translation :
+      {
+        const mshr::CSGTranslation* t = dynamic_cast<const mshr::CSGTranslation*>(geometry);
+        dolfin_assert(t);
+        std::shared_ptr<Nef_polyhedron_3> g = convertSubTree(t->g.get());
+        Aff_transformation_3 translation(CGAL::TRANSLATION, Vector_3(t->t.x(), t->t.y(), t->t.z()));
+        g->transform(translation);
+        return g;
+        break;
+      }
+      case mshr::CSGGeometry::Scaling :
+      {
+        const mshr::CSGScaling* t = dynamic_cast<const mshr::CSGScaling*>(geometry);
+        dolfin_assert(t);
+        std::shared_ptr<Nef_polyhedron_3> g = convertSubTree(t->g.get());
+        Aff_transformation_3 scaling = get_scaling(*t);
+        g->transform(scaling);
+        return g;
+        break;
+      }
+      case mshr::CSGGeometry::Rotation :
+      {
+        const mshr::CSGRotation* t = dynamic_cast<const mshr::CSGRotation*>(geometry);
+        dolfin_assert(t);
+
+        std::shared_ptr<Nef_polyhedron_3> g = convertSubTree(t->g.get());
+        Aff_transformation_3 rotation = get_rotation(*t);
+        g->transform(rotation);
+        return g;
+        break;
+      }
+      case mshr::CSGGeometry::Cylinder :
+      {
+        const mshr::Cylinder* c = dynamic_cast<const mshr::Cylinder*>(geometry);
+        dolfin_assert(c);
+        Exact_Polyhedron_3 P;
+        make_cylinder(c, P);
+        return std::shared_ptr<Nef_polyhedron_3>(new Nef_polyhedron_3(P));
+        break;
+      }
+      case mshr::CSGGeometry::Sphere :
+      {
+        const mshr::Sphere* s = dynamic_cast<const mshr::Sphere*>(geometry);
+        dolfin_assert(s);
+        Exact_Polyhedron_3 P;
+        make_sphere(s, P);
+        return std::shared_ptr<Nef_polyhedron_3>(new Nef_polyhedron_3(P));
+        break;
+      }
+      case mshr::CSGGeometry::Box :
+      {
+        const mshr::Box* b = dynamic_cast<const mshr::Box*>(geometry);
+        dolfin_assert(b);
+        Exact_Polyhedron_3 P;
+        make_box(b, P);
+        return std::shared_ptr<Nef_polyhedron_3>(new Nef_polyhedron_3(P));
+        break;
+      }
+      case mshr::CSGGeometry::Tetrahedron :
+      {
+        const mshr::Tetrahedron* b = dynamic_cast<const mshr::Tetrahedron*>(geometry);
+        dolfin_assert(b);
+        Exact_Polyhedron_3 P;
+        make_tetrahedron(b, P);
+        return std::shared_ptr<Nef_polyhedron_3>(new Nef_polyhedron_3(P));
+        break;
+      }
+      case mshr::CSGGeometry::Ellipsoid :
+      {
+        const mshr::Ellipsoid* b = dynamic_cast<const mshr::Ellipsoid*>(geometry);
+        dolfin_assert(b);
+        Exact_Polyhedron_3 P;
+        make_ellipsoid(b, P);
+        return std::shared_ptr<Nef_polyhedron_3>(new Nef_polyhedron_3(P));
+        break;
+      }
+      case mshr::CSGGeometry::Surface3D :
+      {
+        const mshr::Surface3D* b = dynamic_cast<const mshr::Surface3D*>(geometry);
+        dolfin_assert(b);
+        Exact_Polyhedron_3 P;
+        make_surface3D(b, P);
+        return std::shared_ptr<Nef_polyhedron_3>(new Nef_polyhedron_3(P));
+        break;
+      }
+      case mshr::CSGGeometry::TriPolyhedron :
+      {
+        const mshr::CSGCGALDomain3D* b = dynamic_cast<const mshr::CSGCGALDomain3D*>(geometry);
+        dolfin_assert(b);
+        return std::shared_ptr<Nef_polyhedron_3>(new Nef_polyhedron_3(b->impl->p));
+        break;
+      }
+      case mshr::CSGGeometry::Extrude2D :
+      {
+        const mshr::Extrude2D* e = dynamic_cast<const mshr::Extrude2D*>(geometry);
+        dolfin_assert(e);
+        Exact_Polyhedron_3 P;
+        make_extrude2D(e, P);
+        return std::shared_ptr<Nef_polyhedron_3>(new Nef_polyhedron_3(P));
+        break;
+      }
+      default:
+        dolfin::dolfin_error("CSGCGALDomain.cpp",
+                             "converting geometry to cgal polyhedron",
+                             "Unhandled primitive type");
+      }
+      // Make compiler happy.
+      return std::shared_ptr<Nef_polyhedron_3>(new Nef_polyhedron_3);
+    }
+#endif
+//-----------------------------------------------------------------------------
+    void convert(const mshr::CSGGeometry& geometry,
+                 Exact_Polyhedron_3 &P)
+    {
+      // If the tree has only one node, we don't have to convert to Nef
+      // polyhedrons for csg manipulations
+      if (!geometry.is_operator())
+      {
+        switch (geometry.getType())
+        {
+
+        case mshr::CSGGeometry::Cylinder :
+        {
+          const mshr::Cylinder* c = dynamic_cast<const mshr::Cylinder*>(&geometry);
+          dolfin_assert(c);
+          make_cylinder(c, P);
+          break;
+        }
+        case mshr::CSGGeometry::Sphere :
+        {
+          const mshr::Sphere* s = dynamic_cast<const mshr::Sphere*>(&geometry);
+          dolfin_assert(s);
+          make_sphere(s, P);
+          break;
+        }
+        case mshr::CSGGeometry::Box :
+        {
+          const mshr::Box* b = dynamic_cast<const mshr::Box*>(&geometry);
+          dolfin_assert(b);
+          make_box(b, P);
+          break;
+        }
+
+        case mshr::CSGGeometry::Tetrahedron :
+        {
+          const mshr::Tetrahedron* b = dynamic_cast<const mshr::Tetrahedron*>(&geometry);
+          dolfin_assert(b);
+          make_tetrahedron(b, P);
+          break;
+        }
+        case mshr::CSGGeometry::Ellipsoid :
+        {
+          const mshr::Ellipsoid* b = dynamic_cast<const mshr::Ellipsoid*>(&geometry);
+          dolfin_assert(b);
+          make_ellipsoid(b, P);
+          break;
+        }
+        case mshr::CSGGeometry::TriPolyhedron :
+        {
+          const mshr::CSGCGALDomain3D* p = dynamic_cast<const mshr::CSGCGALDomain3D*>(&geometry);
+          dolfin_assert(p);
+          Insert_polyhedron_to<Exact_Polyhedron_3> inserter(p->impl->p);
+          P.delegate(inserter);
+          dolfin_assert(P.is_valid());
+          break;
+        }
+        case mshr::CSGGeometry::Surface3D :
+        {
+          const mshr::Surface3D* b = dynamic_cast<const mshr::Surface3D*>(&geometry);
+          dolfin_assert(b);
+          make_surface3D(b, P);
+          break;
+        }
+        case mshr::CSGGeometry::Extrude2D :
+        {
+          const mshr::Extrude2D* e = dynamic_cast<const mshr::Extrude2D*>(&geometry);
+          dolfin_assert(e);
+          make_extrude2D(e, P);
+          break;
+        }
+
+        default:
+          dolfin::dolfin_error("CSGCGALDomain3D.cpp",
+                               "converting geometry to cgal polyhedron",
+                               "Unhandled primitive type");
+        }
+      }
+      else
+      {
+#ifdef MSHR_ENABLE_EXPERIMENTAL
+        convertSubTree(&geometry, P);
+#else
+        log(dolfin::TRACE, "Convert to nef polyhedron");
+        std::shared_ptr<Nef_polyhedron_3> cgal_geometry
+          = convertSubTree(&geometry);
+        dolfin_assert(cgal_geometry->is_valid());
+        dolfin_assert(cgal_geometry->is_simple());
+        cgal_geometry->convert_to_polyhedron(P);
+#endif
+      }
+
+      if (P.size_of_facets() == 0)
+      {
+        dolfin::dolfin_error("CSGCGALDomain3D.cpp",
+                             "Convert geometry to polyhedron",
+                             "Geometry contains no facet");
+      }
+
+      log(dolfin::TRACE, "Number of vertices: %d",  P.size_of_vertices());
+      log(dolfin::TRACE, "Number of facets: %d", P.size_of_facets());
+    }
+  } //end unnamed namespace
+
+
+  namespace mshr
+  {
+    //-----------------------------------------------------------------------------
+    struct CSGCGALDomain3DQueryStructureImpl
+    {
+      template <typename A>
+      CSGCGALDomain3DQueryStructureImpl(A start, A end, const Exact_Polyhedron_3& p)
+        : aabb_tree(start, end, p){}
+
+      AABB_Tree aabb_tree;
+    };
+    //-----------------------------------------------------------------------------
+    CSGCGALDomain3DQueryStructure::CSGCGALDomain3DQueryStructure(std::unique_ptr<CSGCGALDomain3DQueryStructureImpl> impl)
+      : impl(std::move(impl))
+    {
+      // Do nothing
+    }
+    //-----------------------------------------------------------------------------
+    CSGCGALDomain3DQueryStructure::~CSGCGALDomain3DQueryStructure()
+    {
+      // Do nothing
+    }
+    //-----------------------------------------------------------------------------
+    CSGCGALDomain3D::CSGCGALDomain3D() : impl(new CSGCGALDomain3DImpl)
+    {
+      parameters = default_parameters();
+    }
+    //-----------------------------------------------------------------------------
+  CSGCGALDomain3D::CSGCGALDomain3D(std::shared_ptr<const mshr::CSGGeometry> csg)
+      : impl(new CSGCGALDomain3DImpl)
+    {
+      parameters = default_parameters();
+
+      if (csg->dim() != 3)
+      {
+        dolfin::dolfin_error("CSGCGALDomain3D.cpp",
+                             "Creating polyhedral domain",
+                             "Geometry has dimension %d, expected 3", csg->dim());
+      }
+
+      convert(*csg, impl->p);
+
+    }
+    //-----------------------------------------------------------------------------
+    CSGCGALDomain3D::CSGCGALDomain3D(const std::vector<std::array<double, 3>>& vertices,
+                                     const std::vector<std::array<std::size_t, 3>>& facets)
+     : impl(new CSGCGALDomain3DImpl)
+    {
+      parameters = default_parameters();
+
+      // Create the polyhedron
+      BuildFromFacetList<Exact_HalfedgeDS> builder(vertices, facets, std::set<std::size_t>{});
+      impl->p.delegate(builder);
+    }
+    //-----------------------------------------------------------------------------
+    CSGCGALDomain3D::~CSGCGALDomain3D(){}
+    //-----------------------------------------------------------------------------
+    void CSGCGALDomain3D::insert(const CSGCGALDomain3D& p)
+    {
+      Insert_polyhedron_to<Exact_Polyhedron_3> inserter(p.impl->p);
+      impl->p.delegate(inserter);
+      CGAL_assertion(impl->p.is_valid());
+    }
+//-----------------------------------------------------------------------------
+    std::size_t CSGCGALDomain3D::num_vertices() const
+    { return impl->p.size_of_vertices(); }
+//-----------------------------------------------------------------------------
+    std::size_t CSGCGALDomain3D::num_facets() const
+    { return impl->p.size_of_facets(); }
+//-----------------------------------------------------------------------------
+    std::size_t CSGCGALDomain3D::num_halfedges() const
+    { return impl->p.size_of_halfedges(); }
+//-----------------------------------------------------------------------------
+    double CSGCGALDomain3D::volume() const
+    {
+      double volume = .0;
+      for (Exact_Polyhedron_3::Facet_const_iterator it = impl->p.facets_begin();
+           it != impl->p.facets_end(); it++)
+      {
+        const Exact_Polyhedron_3::Halfedge_const_handle h = it->halfedge();
+        const Vector_3 V0 = h->vertex()->point()-CGAL::ORIGIN;
+        const Vector_3 V1 = h->next()->vertex()->point()-CGAL::ORIGIN;
+        const Vector_3 V2 = h->next()->next()->vertex()->point()-CGAL::ORIGIN;
+
+        volume += CGAL::to_double(V0*CGAL::cross_product(V1, V2));
+      }
+
+      return volume/6.0;
+    }
+//-----------------------------------------------------------------------------
+  std::unique_ptr<std::vector<double>> CSGCGALDomain3D::get_vertices() const
+    {
+      typedef typename Exact_Polyhedron_3::Vertex_const_iterator Vertex_const_iterator;
+
+      std::unique_ptr<std::vector<double>> vertices(new std::vector<double>());
+      vertices->reserve(impl->p.size_of_vertices());
+
+      for(Vertex_const_iterator
+            vi = impl->p.vertices_begin(), end = impl->p.vertices_end();
+          vi != end ; ++vi)
+      {
+        vertices->push_back(::CGAL::to_double( vi->point().x()));
+        vertices->push_back(::CGAL::to_double( vi->point().y()));
+        vertices->push_back(::CGAL::to_double( vi->point().z()));
+      }
+
+      return vertices;
+    }
+//-----------------------------------------------------------------------------
+  std::unique_ptr<std::vector<std::size_t>> CSGCGALDomain3D::get_facets() const
+    {
+      typedef typename Exact_Polyhedron_3::Vertex_const_iterator Vertex_const_iterator;
+      typedef typename Exact_Polyhedron_3::Facet_const_iterator  Facet_const_iterator;
+      typedef typename Exact_Polyhedron_3::Halfedge_around_facet_const_circulator HFCC;
+
+      typedef CGAL::Inverse_index<Vertex_const_iterator> Index;
+      Index index(impl->p.vertices_begin(), impl->p.vertices_end());
+
+      std::unique_ptr<std::vector<std::size_t>> facets(new std::vector<std::size_t>());
+      facets->reserve(impl->p.size_of_facets());
+
+      for(Facet_const_iterator
+            fi = impl->p.facets_begin(), end = impl->p.facets_end();
+          fi != end; ++fi)
+      {
+        HFCC hc = fi->facet_begin();
+        facets->push_back(index[hc->vertex()]);
+        hc++;
+        facets->push_back(index[hc->vertex()]);
+        hc++;
+        facets->push_back(index[hc->vertex()]);
+      }
+
+      return facets;
+    }
+//-----------------------------------------------------------------------------
+    void CSGCGALDomain3D::get_points_in_holes(std::vector<dolfin::Point>& holes,
+                                              std::shared_ptr<CSGCGALDomain3DQueryStructure> q) const
+    {
+      std::vector<typename Exact_Polyhedron_3::Vertex_const_handle> parts;
+      mshr::PolyhedronUtils::get_disconnected_components(impl->p,std::back_inserter(parts));
+
+      if (parts.size() > 1)
+      {
+        if (!q)
+          q = get_query_structure();
+
+        for (std::vector<typename Exact_Polyhedron_3::Vertex_const_handle>::const_iterator it = parts.begin();
+             it != parts.end(); it++)
+        {
+          typename Exact_Polyhedron_3::Halfedge_const_handle h = (*it)->halfedge();
+          const Exact_Point_3 x1 = h->vertex()->point();
+          const Exact_Point_3 x2 = h->next()->vertex()->point();
+          const Exact_Point_3 x3 = h->next()->next()->vertex()->point();
+          const Exact_Point_3 origin( (x1.x()+x2.x()+x3.x())/3,
+                                      (x1.y()+x2.y()+x3.y())/3,
+                                      (x1.z()+x2.z()+x3.z())/3);
+
+          Vector_3 n = CGAL::cross_product(x3-x1, x2-x1);
+
+          // shoot a ray from the facet and count the number of hits
+          Ray_3 ray(origin, n);
+
+          std::list<AABB_Tree::Object_and_primitive_id> intersections;
+          q->impl->aabb_tree.all_intersections(ray, std::back_inserter(intersections));
+          // std::cout << "Number of intersections: " << intersections.size() << std::endl;
+
+          // Collect unique intersection points not including the origin point
+          std::set<Exact_Point_3> intersection_points;
+          for (std::list<AABB_Tree::Object_and_primitive_id>::const_iterator
+                 iit = intersections.begin();
+               iit != intersections.end(); iit++)
+          {
+            if (const Exact_Point_3* p = CGAL::object_cast<Exact_Point_3>(&(iit->first)))
+            {
+              if (*p != origin)
+                intersection_points.insert(*p);
+            }
+          }
+
+          // std::cout << "Number of unique point intersections: " << intersection_points.size() << std::endl;
+          if (intersection_points.size() % 2 == 0)
+          {
+            // This is a hole
+            // Find a point strictly inside it
+
+            std::set<Exact_Point_3>::const_iterator pit = intersection_points.begin();
+            Exact_Point_3 closest_point = *pit;
+            Exact_Kernel::FT distance_to_closest = (closest_point-origin).squared_length();
+            pit++;
+
+            for (;pit != intersection_points.end(); pit++)
+            {
+              Exact_Kernel::FT d = (*pit-origin).squared_length();
+              if (d < distance_to_closest)
+              {
+                distance_to_closest = d;
+                closest_point = *pit;
+              }
+            }
+
+            const dolfin::Point h_point( (CGAL::to_double(origin.x())+CGAL::to_double(closest_point.x()))/2,
+                                         (CGAL::to_double(origin.y())+CGAL::to_double(closest_point.y()))/2,
+                                         (CGAL::to_double(origin.z())+CGAL::to_double(closest_point.z()))/2 );
+            // std::cout << "Point in hole: " << h_point << std::endl;
+            holes.push_back(h_point);
+          }
+        }
+      }
+    }
+//-----------------------------------------------------------------------------
+    void CSGCGALDomain3D::remove_degenerate_facets(double tolerance)
+    {
+      remove_degenerate(impl->p, tolerance);
+    }
+//-----------------------------------------------------------------------------
+    void CSGCGALDomain3D::ensure_meshing_preconditions()
+    {
+      if (!impl->p.is_valid())
+        dolfin::dolfin_error("CSGCGDomain3D.cpp",
+                             "Checking meshing preconditions",
+                             "Polyhedron is not valid");
+
+      if (parameters["remove_degenerate"])
+        remove_degenerate_facets(parameters["degenerate_tolerance"]);
+    }
+//-----------------------------------------------------------------------------
+    std::shared_ptr<CSGCGALDomain3DQueryStructure> CSGCGALDomain3D::get_query_structure() const
+    {
+      std::unique_ptr<CSGCGALDomain3DQueryStructureImpl> i(new CSGCGALDomain3DQueryStructureImpl(faces(impl->p).first,
+                                                                                                 faces(impl->p).second,
+                                                                                                 impl->p));
+      return std::shared_ptr<CSGCGALDomain3DQueryStructure>(new CSGCGALDomain3DQueryStructure(std::move(i)));
+    }
+//-----------------------------------------------------------------------------
+    bool CSGCGALDomain3D::is_insideout() const
+    {
+      typedef Exact_Kernel::Ray_3 Exact_Ray_3;
+
+      // Pick a point on a facet a. Shoot in the direction of the normal and count
+      // the number of distinct hits (if the ray hit an edge, the same intersection
+      // point will hit sevel facets). Excluding the hit on facet a the number
+      // should be even for the polyhedron to be bounded.
+      // TODO: Take QueryStructure argument.
+      Exact_Polyhedron_3::Facet_iterator f = impl->p.facets_begin();
+
+      Exact_Ray_3 ray;
+
+      {
+        Exact_Polyhedron_3::Halfedge_handle h = f->halfedge();
+        Exact_Triangle_3 t(h->vertex()->point(),
+                           h->next()->vertex()->point(),
+                           h->next()->next()->vertex()->point());
+        f++;
+
+        //Compute the ray
+        Exact_Vector_3 normal = CGAL::normal(t.vertex(0), t.vertex(1), t.vertex(2));
+        Exact_Point_3  mid    = CGAL::centroid(t);
+
+        ray = Exact_Ray_3(mid, normal);
+      }
+
+      // Collect the points to avoid double hits on facets.
+      std::set<Exact_Point_3> points;
+      for (; f != impl->p.facets_end(); ++f)
+      {
+        Exact_Polyhedron_3::Halfedge_handle h = f->halfedge();
+        Exact_Triangle_3 t(h->vertex()->point(),
+                           h->next()->vertex()->point(),
+                           h->next()->next()->vertex()->point());
+
+
+        auto result = intersection(t, ray);
+        if(result)
+        {
+          if (const Exact_Point_3* p = boost::get<Exact_Point_3>(&*result))
+          {
+            points.insert(*p);
+          }
+        }
+      }
+
+      // std::cout << "Number of intersections: " << points.size() << std::endl;
+      return points.size() % 2 != 0;
+    }
+//-----------------------------------------------------------------------------
+    bool CSGCGALDomain3D::is_selfintersecting(bool verbose) const
+    {
+      if (verbose)
+      {
+        const std::string s = PolyhedronUtils::list_self_intersections(impl->p);
+        if (s != "")
+        {
+          dolfin::cout << s;
+          return true;
+        }
+        else
+        {
+          return false;
+        }
+      }
+      else
+      {
+        return CGAL::Polygon_mesh_processing::does_self_intersect(impl->p);
+      }
+    }
+//-----------------------------------------------------------------------------
+    std::size_t CSGCGALDomain3D::num_degenerate_facets(double threshold) const
+    {
+      return number_of_degenerate_facets(impl->p, threshold);
+    }
+//-----------------------------------------------------------------------------
+    std::pair<double, double> CSGCGALDomain3D::facet_area_minmax() const
+    {
+      double smallest_triangle = std::numeric_limits<double>::max();
+      double largest_triangle = 0.;
+      for (auto f = impl->p.facets_begin(); f != impl->p.facets_end(); f++)
+      {
+        auto h = f->halfedge();
+        if (f->is_triangle())
+        {
+          const Exact_Triangle_3 t(h->vertex()->point(),
+                                   h->next()->vertex()->point(),
+                                   h->next()->next()->vertex()->point());
+          const double squared_area = CGAL::to_double(t.squared_area());
+          smallest_triangle = std::min(smallest_triangle,
+                                       squared_area);
+          largest_triangle = std::max(largest_triangle,
+                                      squared_area);
+        }
+      }
+      return std::make_pair(sqrt(smallest_triangle),
+                            sqrt(largest_triangle));
+    }
+  //-----------------------------------------------------------------------------
+    void CSGCGALDomain3D::save_off(std::string filename) const
+    {
+      {
+        std::string message = "Writing to file: "+filename;
+        log(dolfin::TRACE, message);
+      }
+
+      std::ofstream outfile(filename.c_str());
+      outfile << std::setprecision(16);
+
+      outfile << impl->p;
+
+      // std::map<Exact_Polyhedron_3::Vertex_const_handle, std::size_t> vertex_map;
+      // std::size_t vertex_counter = 0;
+
+      // // Write header
+      // outfile << "OFF " << std::endl << impl->p.size_of_vertices() << " " << impl->p.size_of_facets() << " 0" << std::endl << std::endl;
+
+      // // Write vertices
+      // for (Exact_Polyhedron_3::Vertex_const_iterator vit = impl->p.vertices_begin(); vit != impl->p.vertices_end(); vit++)
+      // {
+      //   vertex_map[vit] = vertex_counter;
+      //   outfile << std::fixed << std::setprecision(16) << CGAL::to_double(vit->point().x()) << " "
+      //           << CGAL::to_double(vit->point().y()) << " "
+      //           << CGAL::to_double(vit->point().z()) << std::endl;
+      //   vertex_counter++;
+      // }
+
+      // for (Exact_Polyhedron_3::Facet_const_iterator fit = impl->p.facets_begin(); fit != impl->p.facets_end(); fit++)
+      // {
+      //   Exact_Polyhedron_3::Halfedge_const_iterator h = fit->halfedge();
+      //   outfile << "3";
+      //   outfile << vertex_map[h->vertex()] << " "
+      //           << vertex_map[h->next()->vertex()] << " "
+      //           << vertex_map[h->next()->next()->vertex()] << std::endl;
+      // }
+
+      outfile.close();
+    }
+//-----------------------------------------------------------------------------
+void CSGCGALDomain3D::save(std::string filename) const
+     { 
+     boost::filesystem::path fpath(filename);
+     if (fpath.extension() == ".off") 
+     {
+       save_off(filename);
+     } 
+     else if  (fpath.extension() == ".asc") 
+     {
+       std::vector<std::array<double, 3>> new_vertices;
+       std::vector<std::array<std::size_t, 3>> new_facets;    
+       std::vector<double> vertices = *get_vertices(); 
+       std::vector<std::size_t> facets = *get_facets();
+       for (std::size_t i = 0; i < vertices.size(); i += 3)
+       {
+         std::array<double, 3> vertex; 
+         vertex[0] = vertices[i];
+         vertex[1] =vertices[i+1];
+         vertex[2] = vertices[i+2];
+         new_vertices.push_back(vertex);
+       }
+       for (std::size_t i = 0; i < facets.size(); i += 3)
+       {
+         std::array<std::size_t, 3> facet;
+         facet[0] = facets[i];
+         facet[1] = facets[i+1];
+         facet[2] = facets[i+2];
+         new_facets.push_back(facet);
+       }
+       mshr::ASCFileReader::write(filename,new_vertices,new_facets);
+     }
+     else if (fpath.extension() == ".stl")
+     {
+       std::vector<std::array<double, 3>> new_vertices;
+       std::vector<std::array<std::size_t, 3>> new_facets;    
+       std::vector<double> vertices = *get_vertices(); 
+       std::vector<std::size_t> facets = *get_facets();
+       for (std::size_t i = 0; i < vertices.size(); i += 3)
+       {
+         std::array<double, 3> vertex; 
+         vertex[0] = vertices[i];
+         vertex[1] =vertices[i+1];
+         vertex[2] = vertices[i+2];
+         new_vertices.push_back(vertex);
+       }
+       for (std::size_t i = 0; i < facets.size(); i += 3)
+       {
+         std::array<std::size_t, 3> facet;
+         facet[0] = facets[i];
+         facet[1] = facets[i+1];
+         facet[2] = facets[i+2];
+         new_facets.push_back(facet);
+       }
+       mshr::STLFileReader::write(filename,new_vertices,new_facets);
+     } 
+     else
+     {
+     dolfin::dolfin_error("CSGCGALDomain3D",
+                         "extension to file is not known",
+                         "Failed write file");
+     } 
+    }
+//-----------------------------------------------------------------------------
+  std::pair<double, double> CSGCGALDomain3D::edge_length_range() const
+  {
+      Exact_Polyhedron_3::Edge_const_iterator it = impl->p.edges_begin();
+      double shortest = CGAL::to_double((it->vertex()->point() - it->opposite()->vertex()->point()).squared_length());
+      double longest = shortest;
+      it++;
+
+      for (; it != impl->p.edges_end(); it++)
+      {
+        const double l = CGAL::to_double((it->vertex()->point() - it->opposite()->vertex()->point()).squared_length());
+        shortest = std::min(shortest, l);
+        longest = std::max(longest, l);
+      }
+
+      return std::make_pair(sqrt(shortest), sqrt(longest));
+    }
+//-----------------------------------------------------------------------------
+    std::size_t CSGCGALDomain3D::num_short_edges(double tolerance) const
+    {
+      std::size_t count = 0;
+      for (Exact_Polyhedron_3::Edge_const_iterator it = impl->p.edges_begin(); it != impl->p.edges_end(); it++)
+      {
+        const Exact_Kernel::FT l = (it->vertex()->point() - it->opposite()->vertex()->point()).squared_length();
+        if (l < tolerance)
+          count++;
+      }
+
+      return count;
+    }
+//-----------------------------------------------------------------------------
+    std::string CSGCGALDomain3D::str(bool verbose) const
+    {
+      std::stringstream ss;
+      ss << "Triangular polyhedron with" << std::endl;
+      ss << "  " << num_vertices() << " vertices," << std::endl;
+      ss << "  " << num_facets() << " facets," << std::endl;
+      ss << "  " << num_halfedges() << " halfedges." << std::endl;
+
+      if (verbose)
+      {
+        ss << "Volume: " << volume() << std::endl;
+        const std::pair<double, double> edge_lengths = edge_length_range();
+        ss << "Edge length range: (" << edge_lengths.first << ", " << edge_lengths.second << ")" << std::endl;
+        ss << "Degenerate facets: " << num_degenerate_facets(1e-12) << std::endl;
+        ss << "Is inside out:        " << (is_insideout() ? "Yes" : "No") << std::endl;
+        ss << "Is self-intersecting: " << (is_selfintersecting() ? "Yes" : "No") << std::endl;
+        ss << "Is closed:            " << (num_holes() > 0 ? "Yes" : "No");
+      }
+
+      return ss.str();
+    }
+//-----------------------------------------------------------------------------
+    std::shared_ptr<CSGCGALDomain3D> CSGCGALDomain3D::convex_hull() const
+    {
+      std::shared_ptr<CSGCGALDomain3D> res(new CSGCGALDomain3D);
+      CGAL::convex_hull_3(impl->p.points_begin(), impl->p.points_end(), res->impl->p);
+
+      return res;
+    }
+  //-----------------------------------------------------------------------------
+    std::shared_ptr<CSGCGALDomain3D> CSGCGALDomain3D::convex_hull(const std::vector<std::array<double, 3>>& point_set)
+    {
+      std::vector<Exact_Point_3> points;
+      points.reserve(point_set.size());
+      for (const std::array<double,3>& p : point_set)
+        points.push_back(Exact_Point_3(p[0], p[1], p[2]));
+
+      std::shared_ptr<CSGCGALDomain3D> res(new CSGCGALDomain3D);
+      CGAL::convex_hull_3(points.begin(),
+                          points.end(),
+                          res->impl->p);
+
+      return res;
+    }
+//-----------------------------------------------------------------------------
+    void CSGCGALDomain3D::filter_facets(dolfin::Point start,
+                                        double threshold,
+                                        std::shared_ptr<CSGCGALDomain3DQueryStructure> q)
+    {
+      std::cout << "Filtering facets" << std::endl;
+
+      if (!q)
+        q = get_query_structure();
+
+      typedef AABB_Tree::Point_and_primitive_id Point_and_primitive_id;
+      typedef Exact_Polyhedron_3::Face_handle Face_handle;
+      typedef Exact_Polyhedron_3::Halfedge_handle Halfedge_handle;
+      Exact_Point_3 query_point(start[0], start[1], start[2]);
+      Point_and_primitive_id pp = q->impl->aabb_tree.closest_point_and_primitive(query_point);
+      dolfin::log(dolfin::TRACE, "Closest point: (%f, %f, %f)",
+                  CGAL::to_double(pp.first.x()),
+                  CGAL::to_double(pp.first.y()),
+                  CGAL::to_double(pp.first.z()));
+
+      const double cos_threshold = cos(threshold);
+
+      std::set<Face_handle> to_be_removed;
+      {
+        std::deque<Face_handle> queue;
+        queue.push_back(pp.second);
+
+        while (!queue.empty())
+        {
+          Face_handle f = queue.front();
+          queue.pop_front();
+
+          if (to_be_removed.count(f) > 0)
+            continue;
+
+          to_be_removed.insert(f);
+
+          const Halfedge_handle start = f->halfedge();
+          Halfedge_handle c = start;
+          const Exact_Triangle_3 f_triangle = PolyhedronUtils::get_facet_triangle<Exact_Polyhedron_3>(f->halfedge());
+          do
+          {
+            Halfedge_handle current = c;
+            c = c->next();
+
+            if (current->is_border_edge())
+              continue;
+
+            Face_handle f2 = current->opposite()->facet();
+            if (PolyhedronUtils::get_triangle_cos_angle<Exact_Triangle_3>(f_triangle,
+                                                                          PolyhedronUtils::get_facet_triangle<Exact_Polyhedron_3>(f2->halfedge())) > cos_threshold &&
+                to_be_removed.count(f2) == 0)
+            {
+              queue.push_back(f2);
+            }
+
+          } while (c != start);
+        }
+      }
+
+      dolfin::log(dolfin::TRACE, "Removing %d facets", to_be_removed.size());
+
+      for (auto fit = to_be_removed.begin(); fit != to_be_removed.end(); fit++)
+      {
+        impl->p.erase_facet((*fit)->halfedge());
+      }
+
+      dolfin_assert(impl->p.is_valid());
+    }
+//-----------------------------------------------------------------------------
+    // std::shared_ptr<CSGCGALDomain3D> get_component(dolfin::Point p,
+    //                                                std::shared_ptr<CSGCGALDomain3DQueryStructure> qs)
+    // {
+    //   if (!qs)
+    //     qs = get_query_structure();
+
+
+    //   typedef AABB_Tree::Point_and_primitive_id Point_and_primitive_id;
+    //   typedef Exact_Polyhedron_3::Face_handle Face_handle;
+    //   typedef Exact_Polyhedron_3::Halfedge_handle Halfedge_handle;
+    //   Exact_Point_3 query_point(start[0], start[1], start[2]);
+    //   Point_and_primitive_id pp = q->impl->aabb_tree.closest_point_and_primitive(query_point);
+    //   dolfin::log(dolfin::TRACE, "Closest point: %s", dolfin::Point(CGAL::double(pp.first[0])),
+    //                                                   dolfin::Point(CGAL::to_double(pp.first[1])),
+    //                                                   dolfin::Point(CGAL::to_double(pp.first[2])));
+
+    //   const double cos_threshold = cos(threshold);
+
+    //   std::set<Face_handle> to_be_removed;
+    //   {
+    //     std::deque<Face_handle> queue;
+    //     queue.push_back(pp.second);
+
+    //     while (!queue.empty())
+    //     {
+    //       Face_handle f = queue.front();
+    //       queue.pop_front();
+
+    //       if (to_be_removed.count(f) > 0)
+    //         continue;
+
+    //       to_be_removed.insert(f);
+
+    //       const Halfedge_handle start = f->halfedge();
+    //       Halfedge_handle c = start;
+    //       const Exact_Triangle_3 f_triangle = PolyhedronUtils::get_facet_triangle<Exact_Polyhedron_3>(f->halfedge());
+    //       do
+    //       {
+    //         Halfedge_handle current = c;
+    //         c = c->next();
+
+    //         if (current->is_border_edge())
+    //           continue;
+
+    //         Face_handle f2 = current->opposite()->facet();
+    //         if (PolyhedronUtils::get_triangle_cos_angle<Exact_Triangle_3>(f_triangle,
+    //                                                                       PolyhedronUtils::get_facet_triangle<Exact_Polyhedron_3>(f2->halfedge())) > cos_threshold &&
+    //             to_be_removed.count(f2) == 0)
+    //         {
+    //           queue.push_back(f2);
+    //         }
+
+    //       } while (c != start);
+    //     }
+    //   }
+
+    //   std::cout << "Removing " << to_be_removed.size() << " facets" << std::endl;
+
+    //   for (auto fit = to_be_removed.begin(); fit != to_be_removed.end(); fit++)
+    //   {
+    //     impl->p.erase_facet((*fit)->halfedge());
+    //   }
+
+    //   dolfin_assert(impl->p.is_valid());
+
+    // }
+//-----------------------------------------------------------------------------
+    void CSGCGALDomain3D::inside_out()
+    {
+      dolfin_assert(impl->p.is_valid());
+      impl->p.inside_out();
+    }
+//-----------------------------------------------------------------------------
+    std::size_t CSGCGALDomain3D::num_holes() const
+    {
+      impl->p.normalize_border();
+
+      dolfin_assert(impl->p.is_valid(false, 0));
+
+      const std::vector<Exact_Polyhedron_3::Halfedge_handle> holes = PolyhedronUtils::get_holes(impl->p);
+      return holes.size();
+    }
+    //-----------------------------------------------------------------------------
+    bool CSGCGALDomain3D::close_hole(std::size_t hole, std::string method)
+    {
+      dolfin::warning("Hole closing is an experimental feature");
+      dolfin_assert(impl->p.is_valid(false, 0));
+      impl->p.normalize_border();
+
+      const std::vector<Exact_Polyhedron_3::Halfedge_handle> holes = PolyhedronUtils::get_holes(impl->p);
+
+      if (method == "auto")
+        PolyhedronUtils::close_hole(impl->p,
+                                    holes[hole]);
+      else if (method == "planar")
+      {
+        const bool res = PolyhedronUtils::triangulate_polygon_3d(impl->p,
+                                                                 holes[hole],
+                                                                 false);
+
+        dolfin_assert(impl->p.is_valid(false, 0));
+        //dolfin_assert(impl->p.is_pure_triangle());
+        impl->p.normalize_border();
+        return res;
+      }
+      else if (method == "split")
+      {
+        const bool res = PolyhedronUtils::split_hole_planar(impl->p, holes[hole]);
+        dolfin_assert(impl->p.is_valid(false, 0));
+        //dolfin_assert(impl->p.is_pure_triangle());
+        impl->p.normalize_border();
+        return res;
+      }
+      else
+      {
+        dolfin::dolfin_error("CSGCGALDomain3D.cpp",
+                             "triangulate hole",
+                             "Unknown hole closing method");
+        return false;
+      }
+      return true;
+    }
+    //-----------------------------------------------------------------------------
+  void CSGCGALDomain3D::list_hole(std::size_t hole) const
+  {
+      const std::vector<Exact_Polyhedron_3::Halfedge_handle> holes = PolyhedronUtils::get_holes(impl->p);
+      PolyhedronUtils::list_hole<Exact_Polyhedron_3>(holes[hole]);
+  }
+  //-----------------------------------------------------------------------------
+    void CSGCGALDomain3D::close_holes()
+    {
+      dolfin::warning("Hole closing is an experimental feature");
+
+      const std::vector<Exact_Polyhedron_3::Halfedge_handle> holes = PolyhedronUtils::get_holes(impl->p);
+
+      std::size_t counter = 0;
+      for (const Exact_Polyhedron_3::Halfedge_handle h : holes)
+      {
+        // save_off("not_intersecting.off");
+        PolyhedronUtils::close_hole(impl->p, h);
+
+        counter++;
+
+        dolfin_assert(impl->p.is_valid(false, 0));
+        dolfin_assert(impl->p.is_pure_triangle());
+      }
+
+      dolfin_assert(impl->p.is_closed());
+    }
+  //-----------------------------------------------------------------------------
+  std::shared_ptr<CSGCGALDomain3D> CSGCGALDomain3D::reconstruct_surface(double expansion) const
+  {
+    std::vector<std::array<double, 3>> new_vertices;
+    std::vector<std::array<std::size_t, 3>> new_facets;
+
+    {
+      std::unique_ptr<const std::vector<double>> vertices = get_vertices();
+      std::unique_ptr<const std::vector<std::size_t>> facets = get_facets();
+
+      SurfaceReconstruction::reconstruct(*vertices,
+                                         *facets,
+                                         new_vertices,
+                                         new_facets,
+                                         expansion);
+    }
+
+    return std::shared_ptr<CSGCGALDomain3D>(new CSGCGALDomain3D(new_vertices,
+                                                                new_facets));
+  }
+  //-----------------------------------------------------------------------------
+  std::shared_ptr<CSGCGALDomain3D> CSGCGALDomain3D::remesh_surface(double edge_length,
+                                                                   double sharp_edge_tolerance) const
+  {
+    std::vector<std::array<double, 3>> remeshed_vertices;
+    std::vector<std::array<std::size_t, 3>> remeshed_facets;
+
+    std::unique_ptr<std::vector<double>> vertices = get_vertices();
+    std::unique_ptr<std::vector<std::size_t>> facets = get_facets();
+
+    SurfaceReconstruction::remesh(edge_length,
+                                  sharp_edge_tolerance,
+                                  *vertices,
+                                  *facets,
+                                  remeshed_vertices,
+                                  remeshed_facets);
+    return std::shared_ptr<CSGCGALDomain3D>(new CSGCGALDomain3D(remeshed_vertices,
+                                                                remeshed_facets));
+  }
+  //-----------------------------------------------------------------------------
+  std::size_t CSGCGALDomain3D::remove_selfintersections()
+  {
+    return PolyhedronUtils::remove_self_intersections(impl->p);
+  }
+  //-----------------------------------------------------------------------------
+  void CSGCGALDomain3D::normalize()
+  {
+    typedef typename Exact_Polyhedron_3::Vertex_iterator Vertex_iterator;
+    typedef typename Exact_Kernel::Aff_transformation_3 Aff_transformation_3;
+
+    if (impl->p.size_of_vertices() > 0)
+    {
+      Vertex_iterator v = impl->p.vertices_begin();
+      const Vertex_iterator end = impl->p.vertices_end();
+      CGAL::Bbox_3 bbox = v->point().bbox();
+      v++;
+
+      for (; v != end; v++)
+      {
+        bbox += v->point().bbox();
+      }
+
+      std::cout << "Bounding box: " << bbox << std::endl;
+      const Exact_Point_3 mid((bbox.xmax()+bbox.xmin())/2,
+                              (bbox.ymax()+bbox.ymin())/2,
+                              (bbox.zmax()+bbox.zmin())/2);
+      std::cout << "Mid point: " << mid << std::endl;
+      const Exact_Vector_3 translation = CGAL::ORIGIN-mid;
+      const Exact_Kernel::RT scaling = std::max(std::max(bbox.xmax()-bbox.xmin(),
+                                                         bbox.ymax()-bbox.ymin()),
+                                                bbox.zmax()-bbox.zmin());
+
+      std::cout << "Scaling: " << scaling << std::endl;
+
+      const Aff_transformation_3 t(CGAL::Translation(), translation);
+      const Aff_transformation_3 s(CGAL::Scaling(), 2/scaling);
+      const Aff_transformation_3 transform = s*t;
+
+      CGAL::Bbox_3 new_bbox = Exact_Point_3(0,0,0).bbox();
+
+      for (Vertex_iterator v = impl->p.vertices_begin(); v != end; v++)
+      {
+        //v->point() = v->point() + translation;
+        v->point() = transform.transform(v->point());
+        new_bbox += v->point().bbox();
+      }
+
+      std::cout << "New bbox: " << new_bbox << std::endl;
+    }
+  }
+  //-----------------------------------------------------------------------------
+  void CSGCGALDomain3D::smooth_taubin(std::size_t iterations)
+  {
+    for (std::size_t i = 0; i < iterations; i++)
+    {
+      LaplacianSmoothing::smooth(impl->p, .8);
+      LaplacianSmoothing::smooth(impl->p, -.805);
+    }
+  }
+  //-----------------------------------------------------------------------------
+  void CSGCGALDomain3D::smooth_laplacian(double c)
+  {
+    LaplacianSmoothing::smooth(impl->p, c);
+  }
+  //-----------------------------------------------------------------------------
+  double CSGCGALDomain3D::sharpest_edge() const
+  {
+    return PolyhedronUtils::sharpest_edge(impl->p);
+  }
+  //-----------------------------------------------------------------------------
+  std::size_t CSGCGALDomain3D::num_sharp_edges(double tolerance) const
+  {
+    return 0;
+  }
+  //-----------------------------------------------------------------------------
+  std::size_t CSGCGALDomain3D::num_disconnected_components() const
+  {
+    std::vector<typename Exact_Polyhedron_3::Vertex_const_handle> parts;
+    mshr::PolyhedronUtils::get_disconnected_components(impl->p, std::back_inserter(parts));
+    return parts.size();
+  }
+  //-----------------------------------------------------------------------------
+  std::size_t CSGCGALDomain3D::keep_largest_components(std::size_t n)
+  {
+    return impl->p.keep_largest_connected_components(static_cast<unsigned int>(n));
+  }
+  //-----------------------------------------------------------------------------
+  std::pair<dolfin::Point, dolfin::Point> CSGCGALDomain3D::get_aabb() const
+  {
+    std::pair<Exact_Point_3, Exact_Point_3> aabb = PolyhedronUtils::get_aabb(impl->p);
+    auto res = std::make_pair(dolfin::Point(CGAL::to_double(aabb.first[0]),
+                                            CGAL::to_double(aabb.first[1]),
+                                            CGAL::to_double(aabb.first[2])),
+                              dolfin::Point(CGAL::to_double(aabb.second[0]),
+                                            CGAL::to_double(aabb.second[1]),
+                                            CGAL::to_double(aabb.second[2])));
+    return res;
+  }
+  //-----------------------------------------------------------------------------
+  void CSGCGALDomain3D::refine_center_vertex()
+  {
+    PolyhedronUtils::center_vertex_refinement(impl->p);
+  }
+  //-----------------------------------------------------------------------------
+  void CSGCGALDomain3D::refine_edge_split()
+  {
+    PolyhedronUtils::split_edge_refinement(impl->p);
+  }
+  //-----------------------------------------------------------------------------
+} // end namespace mshr
+
diff --git a/src/CSGCGALMeshGenerator2D.cpp b/src/CSGCGALMeshGenerator2D.cpp
new file mode 100644 (file)
index 0000000..6851520
--- /dev/null
@@ -0,0 +1,408 @@
+// Copyright (C) 2012 Johannes Ring, 2012-2017 Benjamin Kehlet
+//
+// This file is part of mshr.
+//
+// mshr 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 3 of the License, or
+// (at your option) any later version.
+//
+// mshr 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 mshr.  If not, see <http://www.gnu.org/licenses/>.
+
+
+#include <vector>
+#include <cmath>
+#include <limits>
+#include <fstream>
+
+#ifndef CGAL_HEADER_ONLY
+#include <CGAL/compiler_config.h>
+#endif
+#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
+#include <CGAL/Triangulation_vertex_base_with_info_2.h>
+#include <CGAL/Constrained_Delaunay_triangulation_2.h>
+#include <CGAL/Triangulation_face_base_with_info_2.h>
+#include <CGAL/Delaunay_mesher_2.h>
+#include <CGAL/Delaunay_mesh_face_base_2.h>
+#include <CGAL/Delaunay_mesh_vertex_base_2.h>
+#include <CGAL/Delaunay_mesh_size_criteria_2.h>
+#include <CGAL/lloyd_optimize_mesh_2.h>
+
+#include <dolfin/common/constants.h>
+#include <dolfin/common/MPI.h>
+#include <dolfin/math/basic.h>
+#include <dolfin/mesh/Mesh.h>
+#include <dolfin/mesh/MeshEditor.h>
+#include <dolfin/mesh/CellType.h>
+#include <dolfin/mesh/MeshFunction.h>
+#include <dolfin/mesh/MeshDomains.h>
+#include <dolfin/mesh/MeshValueCollection.h>
+#include <dolfin/mesh/MeshPartitioning.h>
+#include <dolfin/log/log.h>
+
+#include <mshr/CSGCGALMeshGenerator2D.h>
+#include <mshr/CSGGeometry.h>
+#include <mshr/CSGOperators.h>
+#include <mshr/CSGPrimitives2D.h>
+#include <mshr/CSGCGALDomain2D.h>
+
+
+typedef CGAL::Exact_predicates_inexact_constructions_kernel             Inexact_Kernel;
+typedef CGAL::Delaunay_mesh_vertex_base_2<Inexact_Kernel>               Vertex_base;
+typedef CGAL::Delaunay_mesh_face_base_2<Inexact_Kernel>                 Face_base;
+typedef CGAL::Triangulation_data_structure_2<Vertex_base, Face_base>    TDS;
+typedef CGAL::Constrained_Delaunay_triangulation_2<Inexact_Kernel, TDS> CDT;
+typedef CGAL::Delaunay_mesh_size_criteria_2<CDT>                        Mesh_criteria_2;
+typedef CGAL::Delaunay_mesher_2<CDT, Mesh_criteria_2>                   CGAL_Mesher_2;
+
+typedef CDT::Vertex_handle Vertex_handle;
+typedef CDT::Face_handle Face_handle;
+typedef Inexact_Kernel::Point_2 Point_2;
+
+namespace mshr
+{
+
+//-----------------------------------------------------------------------------
+CSGCGALMeshGenerator2D::CSGCGALMeshGenerator2D()
+{
+  parameters = default_parameters();
+}
+//-----------------------------------------------------------------------------
+CSGCGALMeshGenerator2D::~CSGCGALMeshGenerator2D() {}
+//-----------------------------------------------------------------------------
+void explore_subdomain(const CDT& cdt,
+                       Face_handle f,
+                       std::size_t marker,
+                       std::map<Face_handle, unsigned int>& subdomain_map,
+                       std::set<Face_handle>& not_visited)
+{
+  std::deque<Face_handle> queue;
+  queue.push_back(f);
+
+  while (!queue.empty())
+  {
+    CDT::Face_handle face = queue.front();
+    queue.pop_front();
+
+    std::set<Face_handle>::iterator face_not_visited = not_visited.find(face);
+    if (face_not_visited != not_visited.end())
+    {
+      dolfin_assert(subdomain_map.find(face) == subdomain_map.end());
+      not_visited.erase(face_not_visited);
+      subdomain_map[face] = marker;
+
+      for(int i = 0; i < 3; i++)
+      {
+        const CDT::Edge e(face,i);
+        if (!cdt.is_constrained(e))
+          queue.push_back(face->neighbor(i));
+      }
+    }
+  }
+}
+//-----------------------------------------------------------------------------
+// Set the member in_domain and counter for all faces in the cdt
+std::map<Face_handle, unsigned int>
+  explore_subdomains(const CDT& cdt,
+                     const CSGCGALDomain2D& total_domain,
+                     const std::vector<std::pair<std::size_t, CSGCGALDomain2D>>&
+                       subdomain_geometries)
+{
+  std::set<Face_handle> not_visited;
+
+  for(CDT::Finite_faces_iterator fit = cdt.finite_faces_begin();
+        fit != cdt.finite_faces_end(); ++fit)
+  {
+    if (fit->is_in_domain())
+      not_visited.insert(fit);
+  }
+
+  std::map<Face_handle, unsigned int> subdomain_map;
+
+  std::list<CDT::Face_handle> queue;
+  queue.push_back(*not_visited.begin());
+
+  while (!not_visited.empty())
+  {
+    const Face_handle f = *not_visited.begin();
+
+    // set to default domain (0)
+    unsigned int marker = 0;
+
+    const Point_2 p0 = f->vertex(0)->point();
+    const Point_2 p1 = f->vertex(1)->point();
+    const Point_2 p2 = f->vertex(2)->point();
+
+    const dolfin::Point p( (p0[0] + p1[0] + p2[0]) / 3.0,
+                           (p0[1] + p1[1] + p2[1]) / 3.0 );
+
+    for (const std::pair<std::size_t, CSGCGALDomain2D> subdomain : subdomain_geometries)
+    {
+      if (subdomain.second.point_in_domain(p))
+      {
+        marker = subdomain.first;
+        break;
+      }
+    }
+
+    explore_subdomain(cdt,
+                      f,
+                      marker,
+                      subdomain_map,
+                      not_visited);
+  }
+
+  return subdomain_map;
+}
+//-----------------------------------------------------------------------------
+double shortest_constrained_edge(const CDT &cdt)
+{
+  double min_length = std::numeric_limits<double>::max();
+  for (CDT::Finite_edges_iterator it = cdt.finite_edges_begin();
+       it != cdt.finite_edges_end();
+       it++)
+  {
+    if (!cdt.is_constrained(*it))
+      continue;
+
+    // An edge is an std::pair<Face_handle, int>
+    // see CGAL/Triangulation_data_structure_2.h
+    CDT::Face_handle f = it->first;
+    const int i = it->second;
+
+    CDT::Point p1 = f->vertex( (i+1)%3 )->point();
+    CDT::Point p2 = f->vertex( (i+2)%3 )->point();
+
+    min_length = std::min(CGAL::to_double((p1-p2).squared_length()),
+                          min_length);
+  }
+
+  return min_length;
+}
+//-----------------------------------------------------------------------------
+std::shared_ptr<dolfin::Mesh> CSGCGALMeshGenerator2D::generate(const std::shared_ptr<const CSGCGALDomain2D> total_domain,
+                                                               const std::vector<std::pair<std::size_t,
+                                                                                           std::shared_ptr<const CSGCGALDomain2D>>>& subdomains)
+{
+  const bool partition = parameters["partition"];
+
+  std::shared_ptr<dolfin::Mesh> mesh(new dolfin::Mesh);
+
+  // Note that if not in parallel (ie. size() == 0)
+  // then both receiver and broadcaster will return false
+  // If not partition, then generate the mesh on all processes
+  if (!partition || !dolfin::MPI::is_receiver(mesh->mpi_comm()))
+  {
+    double cell_size;
+    {
+      const double mesh_resolution = parameters["mesh_resolution"];
+      if (mesh_resolution > 0)
+      {
+        const double min_radius = total_domain->compute_boundingcircle_radius();
+        cell_size = 2.0*min_radius/mesh_resolution;
+      }
+      else
+        cell_size = parameters["cell_size"];
+    }
+
+    std::vector<std::pair<std::size_t, CSGCGALDomain2D> >
+      subdomain_geometries;
+
+    log(dolfin::TRACE, "Converting geometry to CGAL polygon");
+
+    // Empty polygon, will be populated when traversing the subdomains
+    CSGCGALDomain2D overlaying;
+
+    if (!subdomains.empty())
+      log(dolfin::TRACE, "Processing subdomains");
+
+    // Add the subdomains to the PSLG. Traverse in reverse order to get the latest
+    // added subdomain on top
+    for (auto rit = subdomains.rbegin(); rit != subdomains.rend(); rit++)
+    {
+      const std::size_t current_index = rit->first;
+      CSGCGALDomain2D cgal_geometry(*(rit->second));
+
+      // Only the part inside the total domain
+      cgal_geometry.intersect_inplace(*total_domain, 1e-15);
+
+      // Only the part outside overlaying subdomains
+      cgal_geometry.difference_inplace(overlaying);
+
+      subdomain_geometries.push_back(std::make_pair(current_index,
+                                                    cgal_geometry));
+
+      overlaying.join_inplace(cgal_geometry);
+    }
+
+    CSGCGALDomain2D remaining(*total_domain);
+    remaining.difference_inplace(overlaying);
+
+    subdomain_geometries.push_back(std::make_pair(0, remaining));
+
+    const auto pslg = CSGCGALDomain2D::compute_pslg(subdomain_geometries);
+
+
+    // for (dolfin::Point p : pslg.first)
+    // {
+    //   std::cout << "\"Point " << p.x() << " " << p.y() << "\" ";
+    // }
+    // std::cout << std::endl;
+
+    // for (std::pair<std::size_t, std::size_t> s : pslg.second)
+    // {
+    //   dolfin::Point p0 = pslg.first[s.first];
+    //   dolfin::Point p1 = pslg.first[s.second];
+    //   std::cout << "\"Segment " << p0.x() << " " << p0.y() << ", " << p1.x() << " " << p1.y() << "\" ";
+    // }
+    // std::cout << std::endl;
+
+    // Create empty CGAL triangulation and copy data from the PSLG
+    CDT cdt;
+
+    {
+      std::vector<CDT::Vertex_handle> vertices;
+      {
+        // Insert the vertices into the triangulation
+        vertices.reserve(pslg.first.size());
+        for (const dolfin::Point& vertex : pslg.first)
+        {
+          const Point_2 p(vertex.x(), vertex.y());
+          vertices.push_back(cdt.insert(p));
+        }
+      }
+
+      // Insert the edges as constraints
+      for (const std::pair<std::size_t, size_t>& edge : pslg.second)
+      {
+        cdt.insert_constraint(vertices[edge.first], vertices[edge.second]);
+      }
+    }
+
+    log(dolfin::TRACE, "Initializing mesh refinement");
+
+    // Create mesher
+    CGAL_Mesher_2 mesher(cdt);
+
+    // Add seeds for all faces in the total domain
+    std::vector<dolfin::Point> hole_points;
+    total_domain->get_points_in_holes(hole_points);
+    std::vector<Point_2> seed_points;
+    for (dolfin::Point p : hole_points)
+      seed_points.push_back(Point_2(p.x(), p.y()));
+
+    log(dolfin::TRACE, "Added %d seed points", seed_points.size());
+    mesher.set_seeds(seed_points.begin(), seed_points.end(), false);
+
+    // Set shape and size criteria
+    const double shape_bound = parameters["triangle_shape_bound"];
+    mesher.set_criteria(Mesh_criteria_2(shape_bound, cell_size));
+
+    // Refine CGAL mesh/triangulation
+    mesher.refine_mesh();
+
+    // Lloyd optimization
+    if (parameters["lloyd_optimize"]) {
+      log(dolfin::TRACE, "Optimizing mesh by Lloyd smoothing");
+      CGAL::lloyd_optimize_mesh_2(cdt);
+    }
+
+    // Make sure triangulation is valid
+    dolfin_assert(cdt.is_valid());
+
+    // Mark the subdomains
+    log(dolfin::TRACE, "Exploring subdomains in mesh");
+
+    std::map<Face_handle, unsigned int> subdomain_map =
+      explore_subdomains(cdt, *total_domain, subdomain_geometries);
+
+    // Clear mesh
+    // This function has been removed from dolfin.
+    // mesh.clear();
+
+    const std::size_t num_vertices = cdt.number_of_vertices();
+
+    // Count valid cells
+    std::size_t num_cells = 0;
+    for (CDT::Finite_faces_iterator cgal_cell = cdt.finite_faces_begin();
+         cgal_cell != cdt.finite_faces_end(); ++cgal_cell)
+    {
+      // Add cell if it is in the domain
+      if (cgal_cell->is_in_domain())
+      {
+        num_cells++;
+      }
+    }
+
+    log(dolfin::DBG, "Mesh with %d vertices and %d cells created", num_vertices, num_cells);
+
+    // Create a MeshEditor and open
+    dolfin::MeshEditor mesh_editor;
+    mesh_editor.open(*mesh, dolfin::CellType::Type::triangle, 2, 2);
+    mesh_editor.init_vertices(num_vertices);
+    mesh_editor.init_cells(num_cells);
+
+    // Add vertices to mesh
+    unsigned int vertex_index = 0;
+    std::map<Vertex_handle, unsigned int> vertex_map;
+    for (CDT::Finite_vertices_iterator cgal_vertex = cdt.finite_vertices_begin();
+         cgal_vertex != cdt.finite_vertices_end(); ++cgal_vertex)
+    {
+      // Get vertex coordinates and add vertex to the mesh
+      dolfin::Point p;
+      p[0] = cgal_vertex->point()[0];
+      p[1] = cgal_vertex->point()[1];
+
+      // Add mesh vertex
+      mesh_editor.add_vertex(vertex_index, p);
+
+      // Attach index to vertex and increment
+      vertex_map[cgal_vertex] = vertex_index;
+      vertex_index++;
+    }
+
+    dolfin_assert(vertex_index == num_vertices);
+
+    // Add cells to mesh and build domain marker mesh function
+    dolfin::MeshDomains &domain_markers = mesh->domains();
+    std::size_t cell_index = 0;
+    const bool mark_cells = !subdomains.empty();
+    for (CDT::Finite_faces_iterator cgal_cell = cdt.finite_faces_begin();
+         cgal_cell != cdt.finite_faces_end(); ++cgal_cell)
+    {
+      // Add cell if it is in the domain
+      if (cgal_cell->is_in_domain())
+      {
+        mesh_editor.add_cell(cell_index,
+                             vertex_map[cgal_cell->vertex(0)],
+                             vertex_map[cgal_cell->vertex(1)],
+                             vertex_map[cgal_cell->vertex(2)]);
+
+        if (mark_cells)
+        {
+          domain_markers.set_marker(std::make_pair(cell_index,
+                                                   subdomain_map[cgal_cell]), 2);
+        }
+        ++cell_index;
+      }
+    }
+    dolfin_assert(cell_index == num_cells);
+
+    // Close mesh editor
+    mesh_editor.close();
+  }
+
+  // Distribute the mesh (if in parallel)
+  if (partition)
+    dolfin::MeshPartitioning::build_distributed_mesh(*mesh);
+
+  return mesh;
+}
+}
+//-----------------------------------------------------------------------------
diff --git a/src/CSGCGALMeshGenerator3D.cpp b/src/CSGCGALMeshGenerator3D.cpp
new file mode 100644 (file)
index 0000000..c2d7e90
--- /dev/null
@@ -0,0 +1,386 @@
+// Copyright (C) 2012-2014 Benjamin Kehlet
+//
+// This file is part of mshr.
+//
+// mshr 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 3 of the License, or
+// (at your option) any later version.
+//
+// mshr 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 mshr.  If not, see <http://www.gnu.org/licenses/>.
+
+
+#include <mshr/CSGCGALMeshGenerator3D.h>
+#include <mshr/CSGGeometry.h>
+#include <mshr/CSGCGALDomain3D.h>
+
+#include <dolfin/common/MPI.h>
+#include <dolfin/log/LogStream.h>
+#include <dolfin/mesh/BoundaryMesh.h>
+#include <dolfin/mesh/CellType.h>
+#include <dolfin/mesh/MeshEditor.h>
+#include <dolfin/mesh/MeshPartitioning.h>
+
+#include <chrono>
+#include <thread>
+#include <memory>
+
+#define CGAL_NO_DEPRECATED_CODE
+#define CGAL_MESH_3_NO_DEPRECATED_SURFACE_INDEX
+#define CGAL_MESH_3_NO_DEPRECATED_C3T3_ITERATORS
+
+#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
+#include <CGAL/Mesh_triangulation_3.h>
+#include <CGAL/Mesh_complex_3_in_triangulation_3.h>
+#include <CGAL/Mesh_criteria_3.h>
+#include "Polyhedral_multicomponent_mesh_domain_with_features_3.h"
+#include "make_multicomponent_mesh_3.h"
+
+// Bounding sphere computation
+#include <CGAL/Min_sphere_of_spheres_d.h>
+#include <CGAL/Min_sphere_of_spheres_d_traits_3.h>
+
+//#define NO_MULTICOMPONENT_DOMAIN
+
+// Domain
+typedef CGAL::Exact_predicates_inexact_constructions_kernel K;
+typedef CGAL::Mesh_polyhedron_3<K>::type MeshPolyhedron_3;
+typedef K::Point_3 Point_3;
+typedef K::Vector_3 Vector_3;
+typedef K::Triangle_3 Triangle_3;
+
+#ifdef NO_MULTICOMPONENT_DOMAIN
+typedef CGAL::Polyhedral_mesh_domain_with_features_3<K> PolyhedralMeshDomain;
+#else
+typedef Polyhedral_multicomponent_mesh_domain_with_features_3<K> PolyhedralMeshDomain;
+#endif
+
+// Triangulation
+typedef CGAL::Mesh_triangulation_3<PolyhedralMeshDomain>::type Tr;
+// typedef CGAL::Mesh_complex_3_in_triangulation_3<
+//  Tr,PolyhedralMeshDomain::Corner_index,PolyhedralMeshDomain::Curve_segment_index> C3t3;
+
+typedef CGAL::Mesh_complex_3_in_triangulation_3<Tr> C3t3;
+
+// Criteria
+typedef CGAL::Mesh_criteria_3<Tr> Mesh_criteria;
+
+namespace
+{
+//-----------------------------------------------------------------------------
+// Repeatedly output some data from the triangulation. Return when the mutex is
+// released.
+void output_num_vertices(Tr& triangulation, std::timed_mutex& mutex)
+{
+  std::chrono::seconds timeout(1);
+
+  while (!mutex.try_lock_for(timeout))
+  {
+    // Be carefull to only call functions which are thread safe.
+    // Inspecting the triangulation data structure reveals that both
+    // Tr::number_of_vertices() and Tr::number_of_cells() just reads an
+    // int. Both Tr::number_of_finite_cells and
+    // Tr::number_of_finite_vertices() count by iterating through the data
+    // (which creates a race condition).
+    dolfin::log(dolfin::PROGRESS,
+                "Generating mesh: Currently approx. %ld vertices and %ld cells",
+                triangulation.number_of_vertices(),
+                triangulation.number_of_cells());
+  }
+}
+//-----------------------------------------------------------------------------
+void build_dolfin_mesh(const C3t3& c3t3, dolfin::Mesh& mesh)
+{
+  typedef C3t3::Triangulation Triangulation;
+  typedef Triangulation::Vertex_handle Vertex_handle;
+
+  // Collect the vertices that are part of the complex
+  std::map<Vertex_handle, std::size_t> vertex_id_map;
+  for(C3t3::Cells_in_complex_iterator cit = c3t3.cells_in_complex_begin();
+      cit != c3t3.cells_in_complex_end();
+      ++cit)
+  {
+    for (std::size_t i = 0; i < 4; i++)
+    {
+      if (!vertex_id_map.count(cit->vertex(i)))
+      {
+        const std::size_t vertex_index = vertex_id_map.size();
+        vertex_id_map[cit->vertex(i)] = vertex_index;
+      }
+    }
+  }
+
+  // Create and initialize mesh editor
+
+  // dolfin::Mesh::clear has been removed
+  // mesh.clear();
+
+  dolfin::MeshEditor mesh_editor;
+  mesh_editor.open(mesh, dolfin::CellType::Type::tetrahedron, 3, 3);
+  mesh_editor.init_vertices(vertex_id_map.size());
+  mesh_editor.init_cells(c3t3.number_of_cells_in_complex());
+
+  // Add vertices to mesh
+  for (std::map<Vertex_handle, std::size_t>::const_iterator it = vertex_id_map.cbegin();
+       it != vertex_id_map.cend(); it++)
+  {
+    // Get vertex coordinates and add vertex to the mesh
+    dolfin::Point p(it->first->point()[0], it->first->point()[1], it->first->point()[2]);
+    mesh_editor.add_vertex(it->second, p);
+  }
+
+  // Add cells to mesh
+  std::size_t cell_index = 0;
+  for(C3t3::Cells_in_complex_iterator cit = c3t3.cells_in_complex_begin();
+      cit != c3t3.cells_in_complex_end();
+      ++cit)
+  {
+    mesh_editor.add_cell(cell_index,
+                         vertex_id_map[cit->vertex(0)],
+                         vertex_id_map[cit->vertex(1)],
+                         vertex_id_map[cit->vertex(2)],
+                         vertex_id_map[cit->vertex(3)]);
+
+    ++cell_index;
+  }
+
+  // Close mesh editor
+  mesh_editor.close();
+}
+//-----------------------------------------------------------------------------
+struct Copy_polyhedron_to
+  : public CGAL::Modifier_base<typename MeshPolyhedron_3::HalfedgeDS>
+{
+  Copy_polyhedron_to(const mshr::CSGCGALDomain3D& in_poly, bool flip)
+    : _in_poly(in_poly), flip(flip) {}
+
+  void operator()(typename MeshPolyhedron_3::HalfedgeDS& out_hds)
+  {
+    typedef typename MeshPolyhedron_3::HalfedgeDS Output_HDS;
+    CGAL::Polyhedron_incremental_builder_3<Output_HDS> builder(out_hds);
+
+    builder.begin_surface(_in_poly.num_vertices(),
+                          _in_poly.num_facets(),
+                          _in_poly.num_halfedges());
+
+    {
+      std::unique_ptr<std::vector<double>> v = _in_poly.get_vertices();
+
+      for (std::size_t i = 0; i < v->size(); i += 3)
+      {
+        typename MeshPolyhedron_3::Point_3 p( (*v)[i], (*v)[i+1], (*v)[i+2] );
+        builder.add_vertex(p);
+      }
+    }
+
+    {
+      std::unique_ptr<const std::vector<std::size_t>> f = _in_poly.get_facets();
+
+      for (std::size_t i = 0; i < f->size(); i += 3)
+      {
+        builder.begin_facet();
+        builder.add_vertex_to_facet( (*f)[i] );
+        if (flip)
+        {
+          builder.add_vertex_to_facet( (*f)[i+2] );
+          builder.add_vertex_to_facet( (*f)[i+1] );
+        }
+        else
+        {
+          builder.add_vertex_to_facet( (*f)[i+1] );
+          builder.add_vertex_to_facet( (*f)[i+2] );
+        }
+
+        builder.end_facet();
+      }
+    }
+    builder.end_surface();
+  }
+private:
+  const mshr::CSGCGALDomain3D& _in_poly;
+  const bool flip;
+};
+
+static void convert_to_inexact(const mshr::CSGCGALDomain3D &exact_domain,
+                               MeshPolyhedron_3 &inexact_domain,
+                               bool flip)
+{
+  Copy_polyhedron_to modifier(exact_domain, flip);
+  inexact_domain.delegate(modifier);
+  CGAL_assertion(inexact_domain.is_valid());
+}
+//-----------------------------------------------------------------------------
+double get_bounding_sphere_radius(const MeshPolyhedron_3& polyhedron)
+{
+  typedef CGAL::Min_sphere_of_spheres_d_traits_3<K, K::FT> MinSphereTraits;
+  typedef CGAL::Min_sphere_of_spheres_d<MinSphereTraits> Min_sphere;
+  typedef MinSphereTraits::Sphere Sphere;
+
+  std::vector<Sphere> S;
+
+  for (MeshPolyhedron_3::Vertex_const_iterator it=polyhedron.vertices_begin();
+       it != polyhedron.vertices_end(); ++it)
+  {
+    S.push_back(Sphere(it->point(), 0.0));
+  }
+
+  Min_sphere ms(S.begin(), S.end());
+  CGAL_assertion(ms.is_valid());
+
+  return CGAL::to_double(ms.radius());
+}
+} //end anonymous namespace
+//-----------------------------------------------------------------------------
+namespace mshr
+{
+CSGCGALMeshGenerator3D::CSGCGALMeshGenerator3D()
+{
+  parameters = default_parameters();
+}
+//-----------------------------------------------------------------------------
+CSGCGALMeshGenerator3D::~CSGCGALMeshGenerator3D() {}
+//-----------------------------------------------------------------------------
+void CSGCGALMeshGenerator3D::generate(std::shared_ptr<const CSGCGALDomain3D> csgdomain,
+                                      dolfin::Mesh& mesh) const
+{
+
+  // Note that if not in parallel (ie. size() == 0)
+  // then both receiver and broadcaster will return false
+  if (!dolfin::MPI::is_receiver(mesh.mpi_comm()))
+  {
+    // Create CGAL mesh domain
+    MeshPolyhedron_3 p;
+    convert_to_inexact(*csgdomain, p, !csgdomain->is_insideout());
+
+    // Reset the (memory consuming exact arithmetic) domain object
+    // will be deleted if the pointer has been moved to the function
+    csgdomain.reset();
+
+    // Workaround, cgal segfaulted when assigning new mesh criterias
+    // within the if-else blocks.
+    std::unique_ptr<Mesh_criteria> criteria;
+    double edge_size;
+
+    const bool criteria_changed = parameters["edge_size"].change_count() > 0
+      || parameters["facet_angle"].change_count() > 0
+      || parameters["facet_size"].change_count() > 0
+      || parameters["facet_distance"].change_count() > 0
+      || parameters["cell_radius_edge_ratio"].change_count() > 0
+      || parameters["cell_size"].change_count() > 0;
+
+    if (parameters["mesh_resolution"].change_count() > 0 && criteria_changed)
+      dolfin::warning("Attempt to set both mesh_resolution and other meshing criterias which are mutually exclusive");
+
+    if (criteria_changed)
+    {
+      log(dolfin::TRACE, "Using user specified meshing criterias");
+
+      // Mesh criteria
+      criteria.reset(new Mesh_criteria(CGAL::parameters::edge_size = parameters["edge_size"],
+                                       CGAL::parameters::facet_angle = parameters["facet_angle"],
+                                       CGAL::parameters::facet_size = parameters["facet_size"], //  <-----------
+                                       CGAL::parameters::facet_distance = parameters["facet_distance"],
+                                       CGAL::parameters::cell_radius_edge_ratio = parameters["cell_radius_edge_ratio"],
+                                       CGAL::parameters::cell_size = parameters["cell_size"])); // <--------------
+      edge_size = parameters["edge_size"];
+    }
+    else
+    {
+      // Try to compute reasonable parameters
+      const double mesh_resolution = parameters["mesh_resolution"];
+      const double r = get_bounding_sphere_radius(p);
+      const double cell_size = r/mesh_resolution*2.0;
+      log(dolfin::TRACE, "Computing meshing criterias. Chose cell size %f", cell_size);
+
+      criteria.reset(new Mesh_criteria(CGAL::parameters::edge_size = cell_size,
+                                       CGAL::parameters::facet_angle = 30.0,
+                                       CGAL::parameters::facet_size = cell_size,
+                                       CGAL::parameters::facet_distance = cell_size/10.0, // ???
+                                       CGAL::parameters::cell_radius_edge_ratio = 3.0,
+                                       CGAL::parameters::cell_size = cell_size));
+      edge_size = cell_size;
+    }
+
+    #ifdef NO_MULTICOMPONENT_DOMAIN
+    PolyhedralMeshDomain domain(p);
+    #else
+    PolyhedralMeshDomain domain(p, edge_size);
+    #endif
+
+    if (parameters["detect_sharp_features"])
+    {
+      log(dolfin::TRACE, "Detecting sharp features");
+
+      const double feature_threshold = parameters["feature_threshold"];
+      domain.detect_features(feature_threshold);
+    }
+
+    // Mesh generation
+    log(dolfin::TRACE, "Generating mesh");
+    C3t3 c3t3;
+    {
+      std::timed_mutex mutex;
+      mutex.lock();
+      std::thread output_thread(output_num_vertices,
+                                std::ref(c3t3.triangulation()), std::ref(mutex));
+      dolfin::begin("Generating mesh with CGAL 3D mesh generator");
+      make_multicomponent_mesh_3_impl<C3t3>(c3t3,
+                                            domain,
+                                            *criteria,
+                                            CGAL::parameters::no_exude(),
+                                            CGAL::parameters::no_perturb(),
+                                            CGAL::parameters::no_odt(),
+                                            CGAL::parameters::no_lloyd(),
+                                            true);
+      mutex.unlock();
+      output_thread.join();
+      dolfin::end();
+    }
+
+    log(dolfin::TRACE, "Done");
+    if (parameters["odt_optimize"])
+    {
+      log(dolfin::TRACE, "Optimizing mesh by odt optimization");
+      odt_optimize_mesh_3(c3t3, domain);
+    }
+
+    if (parameters["lloyd_optimize"])
+    {
+      log(dolfin::TRACE, "Optimizing mesh by lloyd optimization");
+      lloyd_optimize_mesh_3(c3t3, domain);
+    }
+
+    if (parameters["perturb_optimize"])
+    {
+      log(dolfin::TRACE, "Optimizing mesh by perturbation");
+      // TODO: Set time limit
+      CGAL::perturb_mesh_3(c3t3, domain);
+    }
+
+    if (parameters["exude_optimize"])
+    {
+      log(dolfin::TRACE, "Optimizing mesh by sliver exudation");
+      exude_mesh_3(c3t3);
+    }
+
+    build_dolfin_mesh(c3t3, mesh);
+  }
+
+  // Distribute the mesh (if in parallel)
+  dolfin::MeshPartitioning::build_distributed_mesh(mesh);
+}
+//-----------------------------------------------------------------------------
+std::shared_ptr<dolfin::Mesh>
+CSGCGALMeshGenerator3D::generate(std::shared_ptr<const CSGCGALDomain3D> csgdomain) const
+{
+  std::shared_ptr<dolfin::Mesh> mesh(new dolfin::Mesh());
+  generate(csgdomain, *mesh);
+  return mesh;
+}
+}
diff --git a/src/CSGGeometries3D.cpp b/src/CSGGeometries3D.cpp
new file mode 100644 (file)
index 0000000..43b4d99
--- /dev/null
@@ -0,0 +1,262 @@
+// Copyright (C) 2012-2014 Benjamin Kehlet
+//
+// This file is part of mshr.
+//
+// mshr 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 3 of the License, or
+// (at your option) any later version.
+//
+// mshr 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 mshr.  If not, see <http://www.gnu.org/licenses/>.
+//
+// Modified by Johannes Ring 2014
+// Modified by Anders Logg 2014
+
+#include <mshr/CSGGeometries3D.h>
+#include <mshr/CSGGeometry.h>
+#include <mshr/CSGPrimitives3D.h>
+#include <mshr/CSGOperators.h>
+
+#include <dolfin/mesh/Mesh.h>
+#include <dolfin/mesh/BoundaryMesh.h>
+#include <dolfin/mesh/Edge.h>
+
+#include <algorithm>
+#include <cmath>
+
+#include "Polygon_utils.h"
+
+namespace mshr
+{
+
+// FIXME: Move somewhere else
+// Convenience function for rotation
+std::shared_ptr<CSGGeometry> rotate(std::shared_ptr<CSGGeometry> geometry,
+                                     dolfin::Point rot_axis,
+                                     dolfin::Point rot_center,
+                                     double theta)
+{
+  return std::shared_ptr<CSGGeometry>(new CSGRotation(geometry,
+                                                      rot_axis,
+                                                      rot_center,
+                                                      theta));
+}
+
+//-----------------------------------------------------------------------------
+std::shared_ptr<CSGGeometry> CSGGeometries::lego(std::size_t n0,
+                                                 std::size_t n1,
+                                                 std::size_t n2,
+                                                 dolfin::Point x)
+{
+  // Standard dimensions for LEGO bricks / m
+  const double P = 8.0 * 0.001;
+  const double h = 3.2 * 0.001;
+  const double D = 5.0 * 0.001;
+  const double b = 1.7 * 0.001;
+  const double d = 0.2 * 0.001;
+
+  // Create brick
+  std::shared_ptr<CSGGeometry>
+    lego(new Box(x + dolfin::Point(0.5*d, 0.5*d, 0),
+                 x + dolfin::Point(n0*P - 0.5*d, n1*P - 0.5*d, n2*h)));
+
+  // Add knobs
+  for (std::size_t i = 0; i < n0; i++)
+  {
+    for (std::size_t j = 0; j < n1; j++)
+    {
+      const dolfin::Point knop_bottom = x + dolfin::Point( (i + 0.5)*P,
+                                                           (j + 0.5)*P,
+                                                           0);
+
+      std::shared_ptr<CSGGeometry>
+        knob(new Cylinder(knop_bottom,
+                          knop_bottom + dolfin::Point(0, 0, n2*h + b),
+                          0.5*D,
+                          0.5*D));
+
+      lego = lego + knob;
+    }
+  }
+
+  return lego;
+}
+//-----------------------------------------------------------------------------
+std::shared_ptr<CSGGeometry> CSGGeometries::propeller(double r,
+                                                      double R,
+                                                      double w,
+                                                      double h,
+                                                      bool rotate_blades,
+                                                      bool include_tip)
+{
+  // Parameters
+  const double v = 0.3;     // rotation of blades
+  const double l = 0.8*w;  // length of cone
+
+  // // Create blades
+  std::shared_ptr<CSGGeometry>
+    blade_0(new Box(dolfin::Point(0.8*r, -0.5*h, -0.5*w),
+                    dolfin::Point(    R,  0.5*h,  0.5*w)));
+  std::shared_ptr<CSGGeometry>
+    blade_1(new Box(dolfin::Point(    -R, -0.5*h, -0.5*w),
+                    dolfin::Point(-0.8*r,  0.5*h,  0.5*w)));
+  std::shared_ptr<CSGGeometry>
+    blade_2(new Box(dolfin::Point(-0.5*h, 0.8*r, -0.5*w),
+                    dolfin::Point( 0.5*h,     R,  0.5*w)));
+  std::shared_ptr<CSGGeometry>
+    blade_3(new Box(dolfin::Point(-0.5*h,     -R, -0.5*w),
+                    dolfin::Point( 0.5*h, -0.8*r,  0.5*w)));
+
+  // Rotate blades
+  if (rotate_blades)
+  {
+    blade_0 = rotate(blade_0, dolfin::Point(1, 0, 0), dolfin::Point(0, 0, 0), v);
+    blade_1 = rotate(blade_1, dolfin::Point(1, 0, 0), dolfin::Point(0, 0, 0), -v);
+    blade_2 = rotate(blade_2, dolfin::Point(0, 1, 0), dolfin::Point(0, 0, 0), v);
+    blade_3 = rotate(blade_3, dolfin::Point(0, 1, 0), dolfin::Point(0, 0, 0), -v);
+  }
+
+  // Create blade tips
+  std::shared_ptr<CSGGeometry>
+    blade_tip_0(new Cylinder(dolfin::Point( R, -0.5*h, 0),
+                             dolfin::Point( R,  0.5*h, 0), 0.5*w, 0.5*w));
+  std::shared_ptr<CSGGeometry>
+    blade_tip_1(new Cylinder(dolfin::Point(-R, -0.5*h, 0),
+                             dolfin::Point(-R,  0.5*h, 0), 0.5*w, 0.5*w));
+  std::shared_ptr<CSGGeometry>
+    blade_tip_2(new Cylinder(dolfin::Point(-0.5*h,  R, 0),
+                             dolfin::Point( 0.5*h,  R, 0), 0.5*w, 0.5*w));
+  std::shared_ptr<CSGGeometry>
+    blade_tip_3(new Cylinder(dolfin::Point(-0.5*h, -R, 0),
+                             dolfin::Point( 0.5*h, -R, 0), 0.5*w, 0.5*w));
+
+  // Rotate blades
+  if (rotate_blades)
+  {
+    blade_tip_0 = rotate(blade_tip_0, dolfin::Point(1, 0, 0), dolfin::Point(0, 0, 0), v);
+    blade_tip_1 = rotate(blade_tip_1, dolfin::Point(1, 0, 0), dolfin::Point(0, 0, 0), -v);
+    blade_tip_2 = rotate(blade_tip_2, dolfin::Point(0, 1, 0), dolfin::Point(0, 0, 0), v);
+    blade_tip_3 = rotate(blade_tip_3, dolfin::Point(0, 1, 0), dolfin::Point(0, 0, 0), -v);
+  }
+
+  // Add blade tips
+  blade_0 = blade_0 + blade_tip_0;
+  blade_1 = blade_1 + blade_tip_1;
+  blade_2 = blade_2 + blade_tip_2;
+  blade_3 = blade_3 + blade_tip_3;
+
+  // // Add blades
+  std::shared_ptr<CSGGeometry>
+    blades = blade_0 + blade_1 + blade_2 + blade_3;
+
+  // Create outer cylinder
+  std::shared_ptr<CSGGeometry>
+    cylinder_outer(new Cylinder(dolfin::Point(0, 0, -0.5*w),
+                                dolfin::Point(0, 0, 0.5*w),
+                                r, r));
+
+  // Create inner cylinder
+  std::shared_ptr<CSGGeometry>
+    cylinder_inner(new Cylinder(dolfin::Point(0, 0, -0.5*w),
+                                dolfin::Point(0, 0, 0.5*w),
+                                0.5*r, 0.5*r));
+
+  // Create center cone
+  std::shared_ptr<CSGGeometry>
+    cone(new Cylinder(dolfin::Point(0, 0, -0.5*w),
+                      dolfin::Point(0, 0, -0.5*w - l), r, h));
+
+  // Create sphere for tip of cone
+  const double k = (r - h) / l;
+  const double rc = h*sqrt(1 + k*k);
+  const double xc = k*h;
+  std::shared_ptr<CSGGeometry>
+    tip(new Sphere(dolfin::Point(0, 0, -0.5*w - l + xc), rc));
+
+  // Build propeller from parts
+  if (include_tip)
+    return cylinder_outer - cylinder_inner + blades + cone + tip;
+  else
+    return cylinder_outer - cylinder_inner + blades + cone;
+}
+//-----------------------------------------------------------------------------
+std::shared_ptr<CSGGeometry> CSGGeometries::import_mesh(std::shared_ptr<dolfin::Mesh> mesh)
+{
+  std::shared_ptr<CSGGeometry> g;
+  if (mesh->geometry().dim() == 2)
+  {
+    // Import and right hand orient boundary entities (not UFC orientation)
+    dolfin::BoundaryMesh bnd(*mesh, "exterior", false);
+    const std::vector<double>& coordinates = bnd.coordinates();
+
+    std::vector<std::vector<dolfin::Point>> polygons;
+    std::vector<std::vector<dolfin::Point>> holes;
+
+    std::map<std::size_t, std::size_t> edges;
+    for (dolfin::EdgeIterator e(bnd); !e.end(); ++e)
+    {
+      const unsigned int* vertices = e->entities(0);
+      edges.emplace(std::make_pair(vertices[0], vertices[1]));
+    }
+
+    while (edges.size() > 0)
+    {
+      std::vector<dolfin::Point> polygon_vertices;
+      std::map<std::size_t, std::size_t>::iterator current = edges.begin();
+      std::size_t start = current->first;
+      std::size_t next;
+      do
+      {
+       polygon_vertices.push_back(dolfin::Point(coordinates[2*current->second], coordinates[2*current->second+1]));
+       next = current->second;
+       edges.erase(current);
+       current = edges.find(next);
+      }        while(next != start);
+
+      if (PolygonUtils::ccw(polygon_vertices))
+       polygons.push_back(polygon_vertices);
+      else
+      {
+       std::reverse(polygon_vertices.begin(), polygon_vertices.end());
+       holes.push_back(polygon_vertices);
+      }
+    }
+
+    {
+      std::vector<std::vector<dolfin::Point>>::iterator it = polygons.begin();
+      g = std::make_shared<Polygon>(*it);
+      it++;
+
+      for(; it != polygons.end(); it++)
+      {
+       std::shared_ptr<CSGGeometry> h = std::make_shared<Polygon>(*it);
+       g = std::make_shared<CSGUnion>(g, h);
+      }
+    }
+
+    for (std::vector<std::vector<dolfin::Point>>::iterator it = holes.begin();
+        it != holes.end();
+        it++)
+    {
+      std::shared_ptr<CSGGeometry> h = std::make_shared<Polygon>(*it);
+      g = std::make_shared<CSGDifference>(g, h);
+    }
+  }
+  else
+  {
+    dolfin::dolfin_error("CSGGeometries.cpp",
+                        "importing 3D mesh",
+                        "use mshr::Surface3D for now");
+  }
+
+  return g;
+}
+
+
+}
diff --git a/src/CSGGeometry.cpp b/src/CSGGeometry.cpp
new file mode 100644 (file)
index 0000000..17d522b
--- /dev/null
@@ -0,0 +1,137 @@
+// Copyright (C) 2012 Anders Logg, Benjamin Kehlet 2013-2017
+//
+// This file is part of mshr.
+//
+// mshr 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 3 of the License, or
+// (at your option) any later version.
+//
+// mshr 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 mshr.  If not, see <http://www.gnu.org/licenses/>.
+//
+
+#include <dolfin/common/NoDeleter.h>
+#include <dolfin/log/LogStream.h>
+#include <mshr/CSGGeometry.h>
+
+// Bounding sphere computation
+#include <CGAL/Cartesian.h>
+#include <CGAL/Min_sphere_of_spheres_d.h>
+#include <CGAL/Min_sphere_of_spheres_d_traits_3.h>
+
+namespace mshr
+{
+
+//-----------------------------------------------------------------------------
+CSGGeometry::CSGGeometry()
+{
+  // Do nothing
+}
+//-----------------------------------------------------------------------------
+CSGGeometry::~CSGGeometry()
+{
+  // Do nothing
+}
+//-----------------------------------------------------------------------------
+void CSGGeometry::set_subdomain(std::size_t i, std::shared_ptr<CSGGeometry> s)
+{
+  if (dim() != 2)
+    dolfin::dolfin_error("CSGGeometry.cpp",
+                 "setting subdomain",
+                 "Subdomains are currently supported only in 2D");
+
+  if (s->dim() != dim())
+    dolfin::dolfin_error("CSGGeometry.cpp",
+                 "setting subdomain",
+                 "Subdomain and domain must be of same dimension. Domain was dimension %d and subdomain was %d", dim(), s->dim());
+
+  if (i == 0)
+  {
+    dolfin::dolfin_error("CSGGeometry.cpp",
+                         "Setting reserved CSG subdomain (0)",
+                         " Subdomain 0 is reserved and cannot be set by user");
+  }
+
+  // Check if i already used
+  std::list<std::pair<std::size_t, std::shared_ptr<const CSGGeometry> > >::iterator it = subdomains.begin();
+  while (it != subdomains.end())
+  {
+    if (it->first == i)
+    {
+      dolfin::warning("Double declaration of CSG subdomain with index %u.", i);
+
+       // Remove existing declaration
+       it = subdomains.erase(it);
+    }
+    else
+      ++it;
+  }
+
+  subdomains.push_back(std::make_pair(i, s));
+}
+//-----------------------------------------------------------------------------
+void CSGGeometry::set_subdomain(std::size_t i, CSGGeometry& s)
+{
+  set_subdomain(i, reference_to_no_delete_pointer(s));
+}
+//-----------------------------------------------------------------------------
+bool CSGGeometry::has_subdomains() const
+{
+  return subdomains.size() > 0;
+}
+//-----------------------------------------------------------------------------
+bool CSGGeometry::inside(dolfin::Point p1, dolfin::Point p2) const
+{
+  dolfin_not_implemented();
+  return false;
+}
+//-----------------------------------------------------------------------------
+std::pair<dolfin::Point, double> CSGGeometry::estimate_bounding_sphere(std::size_t numSamples) const
+{
+  std::pair<dolfin::Point, dolfin::Point> aabb = bounding_box();
+  const dolfin::Point min = aabb.first;
+  const dolfin::Point max = aabb.second;
+
+  //typedef CGAL::Exact_predicates_exact_constructions_kernel K;
+  typedef CGAL::Cartesian<double> K;
+  typedef K::Point_2                      Point_2;
+  typedef CGAL::Min_sphere_of_spheres_d_traits_2<K, K::FT> MinSphereTraits;
+  typedef CGAL::Min_sphere_of_spheres_d<MinSphereTraits> Min_sphere;
+  typedef MinSphereTraits::Sphere Sphere;
+
+  std::vector<Sphere> S;
+  S.reserve(numSamples);
+  const std::size_t N = static_cast<std::size_t>(std::sqrt(static_cast<double>(numSamples)+.5));
+  const double dX = (max.x()-min.x())/N;
+  const double dY = (max.y()-min.y())/N;
+  // const double dTheta = 2*DOLFIN_PI/N;
+  for (std::size_t i = 0; i < N; i++)
+  {
+    for (std::size_t j = 0; j < N; j++)
+    {
+      const dolfin::Point p(min.x() + i*dX, min.y() + j*dY);
+      if (inside(p))
+        S.push_back(Sphere(Point_2(p.x(), p.y()), 0.0));
+    }
+  }
+
+  Min_sphere ms(S.begin(), S.end());
+  CGAL_assertion(ms.is_valid());
+
+  auto it = ms.center_cartesian_begin();
+  const double center_x = CGAL::to_double(*it);
+  it++;
+  const double center_y = CGAL::to_double(*it);
+  const double radius = CGAL::to_double(ms.radius());
+
+  return std::make_pair(dolfin::Point(center_x, center_y),
+                        radius);
+}
+
+}
diff --git a/src/CSGOperators.cpp b/src/CSGOperators.cpp
new file mode 100644 (file)
index 0000000..a01e48e
--- /dev/null
@@ -0,0 +1,444 @@
+// Copyright (C) 2012 Anders Logg, Benjamin Kehlet 2013-2017
+//
+// This file is part of mshr.
+//
+// mshr 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 3 of the License, or
+// (at your option) any later version.
+//
+// mshr 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 mshr.  If not, see <http://www.gnu.org/licenses/>.
+//
+// Modified by Johannes Ring, 2012
+
+#include <mshr/CSGOperators.h>
+
+#include <dolfin/common/utils.h>
+#include <dolfin/log/log.h>
+#include <dolfin/common/constants.h>
+
+#include <sstream>
+
+namespace mshr
+{
+
+//-----------------------------------------------------------------------------
+// CSGUnion
+//-----------------------------------------------------------------------------
+CSGOperator::CSGOperator()
+{}
+
+//-----------------------------------------------------------------------------
+// CSGUnion
+//-----------------------------------------------------------------------------
+CSGUnion::CSGUnion(std::shared_ptr<CSGGeometry> g0,
+                   std::shared_ptr<CSGGeometry> g1)
+  : _g0(g0), _g1(g1)
+{
+  assert(g0);
+  assert(g1);
+
+  // Check dimensions
+  if (g0->dim() != g1->dim())
+  {
+    dolfin::dolfin_error("CSGOperators.cpp",
+                         "create union of CSG geometries",
+                         "Dimensions of geometries don't match (%d vs %d)",
+                         g0->dim(), g1->dim());
+  }
+
+  dim_ = g0->dim();
+}
+//-----------------------------------------------------------------------------
+std::string CSGUnion::str(bool verbose) const
+{
+  assert(_g0);
+  assert(_g1);
+
+  std::stringstream s;
+
+  if (verbose)
+  {
+    s << "<Union>\n"
+      << "{\n"
+      << dolfin::indent(_g0->str(true))
+      << "\n"
+      << dolfin::indent(_g1->str(true))
+      << "\n}";
+  }
+  else
+  {
+    s << "(" << _g0->str(false) << " + " << _g1->str(false) << ")";
+  }
+
+  return s.str();
+}
+//-----------------------------------------------------------------------------
+std::pair<dolfin::Point, dolfin::Point> CSGUnion::bounding_box() const
+{
+  std::pair<dolfin::Point, dolfin::Point> a = _g0->bounding_box();
+  std::pair<dolfin::Point, dolfin::Point> b = _g1->bounding_box();
+
+  return std::make_pair(dolfin::Point(std::min(a.first.x(), b.first.x()),
+                                      std::min(a.first.y(), b.first.y()),
+                                      std::min(a.first.z(), b.first.z())),
+                        dolfin::Point(std::max(a.second.x(), b.second.x()),
+                                      std::max(a.second.y(), b.second.y()),
+                                      std::max(a.second.z(), b.second.z())));
+}
+//-----------------------------------------------------------------------------
+bool CSGUnion::inside(dolfin::Point p) const
+{
+  return _g0->inside(p) || _g1->inside(p);
+}
+
+//-----------------------------------------------------------------------------
+// CSGDifference
+//-----------------------------------------------------------------------------
+CSGDifference::CSGDifference(std::shared_ptr<CSGGeometry> g0,
+                            std::shared_ptr<CSGGeometry> g1)
+  : _g0(g0), _g1(g1)
+{
+  assert(g0);
+  assert(g1);
+
+  // Check dimensions
+  if (g0->dim() != g1->dim())
+  {
+    dolfin::dolfin_error("CSGOperators.cpp",
+                         "create difference of CSG geometries",
+                         "Dimensions of geomestries don't match (%d vs %d)",
+                         g0->dim(), g1->dim());
+  }
+
+  dim_ = g0->dim();
+}
+//-----------------------------------------------------------------------------
+std::string CSGDifference::str(bool verbose) const
+{
+  assert(_g0);
+  assert(_g1);
+
+  std::stringstream s;
+
+  if (verbose)
+  {
+    s << "<Difference>\n"
+      << "{\n"
+      << dolfin::indent(_g0->str(true))
+      << "\n"
+      << dolfin::indent(_g1->str(true))
+      << "\n}";
+  }
+  else
+  {
+    s << "(" << _g0->str(false) << " - " << _g1->str(false) << ")";
+  }
+
+  return s.str();
+}
+//-----------------------------------------------------------------------------
+std::pair<dolfin::Point, dolfin::Point> CSGDifference::bounding_box() const
+{
+  // FIXME: This is where the bounding_box implementation may overshoot
+  return _g0->bounding_box();
+}
+//-----------------------------------------------------------------------------
+bool CSGDifference::inside(dolfin::Point p) const
+{
+  return _g0->inside(p) && !_g1->inside(p);
+}
+
+//-----------------------------------------------------------------------------
+// CSGIntersection
+//-----------------------------------------------------------------------------
+CSGIntersection::CSGIntersection(std::shared_ptr<CSGGeometry> g0,
+                                 std::shared_ptr<CSGGeometry> g1)
+  : _g0(g0), _g1(g1)
+{
+  assert(g0);
+  assert(g1);
+
+  // Check dimensions
+  if (g0->dim() != g1->dim())
+  {
+    dolfin::dolfin_error("CSGOperators.cpp",
+                         "create intersection of CSG geometries",
+                         "Dimensions of geomestries don't match (%d vs %d)",
+                         g0->dim(), g1->dim());
+  }
+
+  dim_ = g0->dim();
+}
+//-----------------------------------------------------------------------------
+std::string CSGIntersection::str(bool verbose) const
+{
+  assert(_g0);
+  assert(_g1);
+
+  std::stringstream s;
+
+  if (verbose)
+  {
+    s << "<Intersection>\n"
+      << "{\n"
+      << dolfin::indent(_g0->str(true))
+      << "\n"
+      << dolfin::indent(_g1->str(true))
+      << "\n}";
+  }
+  else
+  {
+    s << "(" << _g0->str(false) << " * " << _g1->str(false) << ")";
+  }
+
+  return s.str();
+}
+//-----------------------------------------------------------------------------
+std::pair<dolfin::Point, dolfin::Point> CSGIntersection::bounding_box() const
+{
+  std::pair<dolfin::Point, dolfin::Point> a = _g0->bounding_box();
+  std::pair<dolfin::Point, dolfin::Point> b = _g1->bounding_box();
+
+  return std::make_pair(dolfin::Point(std::min(a.first.x(), b.first.x()),
+                                      std::min(a.first.y(), b.first.y()),
+                                      std::min(a.first.z(), b.first.z())),
+                        dolfin::Point(std::max(a.second.x(), b.second.x()),
+                                      std::max(a.second.y(), b.second.y()),
+                                      std::max(a.second.z(), b.second.z())));
+}
+//-----------------------------------------------------------------------------
+bool CSGIntersection::inside(dolfin::Point p) const
+{
+  return _g0->inside(p) && _g1->inside(p);
+}
+
+//-----------------------------------------------------------------------------
+// CSGTranslation
+//-----------------------------------------------------------------------------
+CSGTranslation::CSGTranslation(std::shared_ptr<CSGGeometry> g,
+                               dolfin::Point t)
+  : g(g), t(t)
+{
+  assert(g);
+
+  dim_ = g->dim();
+}
+//-----------------------------------------------------------------------------
+std::string CSGTranslation::str(bool verbose) const
+{
+  std::stringstream s;
+
+  if (verbose)
+  {
+    s << "<Translation>\n"
+      << "{\n"
+      << dolfin::indent(g->str(true) + "\nby\n" + t.str(true))
+      << "\n}";
+  }
+  else
+  {
+    s << "(" << g->str(false) << " + " << t.str(false) << ")";
+  }
+
+  return s.str();
+}
+//-----------------------------------------------------------------------------
+std::pair<dolfin::Point, dolfin::Point> CSGTranslation::bounding_box() const
+{
+  std::pair<dolfin::Point, dolfin::Point> aabb = g->bounding_box();
+
+  return std::make_pair(aabb.first+t, aabb.second+t);
+}
+//-----------------------------------------------------------------------------
+bool CSGTranslation::inside(dolfin::Point p) const
+{
+  return g->inside(p-t);
+}
+
+//-----------------------------------------------------------------------------
+// CSGScaling
+//-----------------------------------------------------------------------------
+CSGScaling::CSGScaling(std::shared_ptr<CSGGeometry> g,
+                       dolfin::Point c,
+                       double s)
+  : g(g), c(c), s(s), translate(true)
+{
+  assert(g);
+
+  dim_ = g->dim();
+}
+//-----------------------------------------------------------------------------
+CSGScaling::CSGScaling(std::shared_ptr<CSGGeometry> g,
+                       double s)
+  : g(g), c(0,0,0), s(s), translate(false)
+{
+  assert(g);
+
+  dim_ = g->dim();
+}
+//-----------------------------------------------------------------------------
+std::string CSGScaling::str(bool verbose) const
+{
+  std::stringstream ss;
+
+  if (verbose)
+  {
+    ss << "<Scaling>\n"
+      << "{\n"
+      << dolfin::indent(g->str(true) + "\nby\n" + std::to_string(s));
+
+      if (translate)
+        ss << "\naround " << c.str(true);
+
+      ss << "\n}";
+  }
+  else
+  {
+    ss << "(" << g->str(false) << " * " << std::to_string(s);
+    if (translate)
+      ss << "(" << c.str(true) << ")";
+    ss << ")";
+  }
+
+  return ss.str();
+}
+//-----------------------------------------------------------------------------
+std::pair<dolfin::Point, dolfin::Point> CSGScaling::bounding_box() const
+{
+  std::pair<dolfin::Point, dolfin::Point> aabb = g->bounding_box();
+
+  const dolfin::Point scaled_c = (translate ? (1-s)*c : dolfin::Point(0,0,0));
+
+  if (translate)
+    return std::make_pair((aabb.first-c)*s + c, (aabb.second-c)*s + c);
+  else
+    return std::make_pair(aabb.first*s, aabb.second*s);
+
+}
+//-----------------------------------------------------------------------------
+bool CSGScaling::inside(dolfin::Point p) const
+{
+  const dolfin::Point p_scaled = (translate ? (p-c)*s + c : p*s);
+  return g->inside(p_scaled);
+}
+
+//-----------------------------------------------------------------------------
+// CSGRotation
+//-----------------------------------------------------------------------------
+CSGRotation::CSGRotation(std::shared_ptr<CSGGeometry> g,
+                         double theta)
+  : g(g), rot_axis(.0,.0), c(.0,.0), theta(theta), translate(false)
+{
+
+  dim_ = g->dim();
+
+  if (dim_ > 2)
+    dolfin::dolfin_error("CSGOperators.cpp",
+                         "Constructing CSG rotation",
+                         "Rotation axis must be given in 3D");
+}
+//-----------------------------------------------------------------------------
+CSGRotation::CSGRotation(std::shared_ptr<CSGGeometry> g,
+                         dolfin::Point v,
+                         double theta)
+  : g(g),
+    rot_axis(v),
+    c(v),
+    theta(theta),
+    translate(g->dim() == 2 ? true : false)
+{
+  assert(g);
+
+  dim_ = g->dim();
+
+  // if (dim_ == 2)
+  //   translate = true;
+  // else
+  //   translate = false;
+}
+//-----------------------------------------------------------------------------
+CSGRotation::CSGRotation(std::shared_ptr<CSGGeometry> g,
+                         dolfin::Point rot_axis,
+                         dolfin::Point rot_center,
+                         double theta)
+  : g(g),
+    rot_axis(rot_axis),
+    c(rot_center),
+    theta(theta),
+    translate(true)
+{
+  assert(g);
+
+  dim_ = g->dim();
+
+  if (dim_ < 3)
+    dolfin::dolfin_error("CSGOperators.cpp",
+                         "Constructing CSG rotation",
+                         "Can't give rotation axis for dimension < 3");
+}
+//-----------------------------------------------------------------------------
+std::string CSGRotation::str(bool verbose) const
+{
+  std::stringstream ss;
+
+  if (verbose)
+  {
+    ss << "<Rotation>\n"
+      << "{\n"
+      << dolfin::indent(g->str(true)
+                        + (translate ? "\naround "+rot_axis.str(true) : "")
+                        + "\nby " + std::to_string(theta/DOLFIN_PI) + " PI");
+
+      ss << "\n}";
+  }
+  else
+  {
+    ss << "rotate(" << g->str(false)
+       << ", " << std::to_string(theta/DOLFIN_PI) << " PI";
+
+    if (translate)
+      ss << ", " << rot_axis.str(true);
+
+    ss << ")";
+  }
+
+  return ss.str();
+}
+//-----------------------------------------------------------------------------
+std::pair<dolfin::Point, dolfin::Point> CSGRotation::bounding_box() const
+{
+  if (dim() != 2)
+  {
+    dolfin_not_implemented();
+  }
+
+  const std::pair<dolfin::Point, dolfin::Point> aabb = g->bounding_box();
+  const dolfin::Point axis(0,0,1);
+
+  // Rotate all corners
+  const dolfin::Point a = aabb.first.rotate(axis, theta);
+  const dolfin::Point b = dolfin::Point(aabb.first.x(), aabb.second.y()).rotate(axis, theta);
+  const dolfin::Point c = dolfin::Point(aabb.second.x(), aabb.first.y()).rotate(axis, theta);
+  const dolfin::Point d = aabb.second.rotate(axis, theta);
+
+  return std::make_pair(dolfin::Point(std::min(a.x(), std::min(b.x(), std::min(c.x(), d.x()))),
+                                      std::min(a.y(), std::min(b.y(), std::min(c.y(), d.y())))),
+                        dolfin::Point(std::max(a.x(), std::max(b.x(), std::max(c.x(), d.x()))),
+                                      std::max(a.y(), std::max(b.y(), std::max(c.y(), d.y())))));
+
+}
+//-----------------------------------------------------------------------------
+bool CSGRotation::inside(dolfin::Point p) const
+{
+  const dolfin::Point p_rotated = translate ? (p-c).rotate(dolfin::Point(0,0,1), -theta) + c  : p.rotate(dolfin::Point(0,0,1), -theta);
+  return g->inside(p_rotated);
+}
+
+}
diff --git a/src/CSGPrimitives2D.cpp b/src/CSGPrimitives2D.cpp
new file mode 100644 (file)
index 0000000..c91829e
--- /dev/null
@@ -0,0 +1,285 @@
+// Copyright (C) 2012 Anders Logg, 2014-2017 Benjamin Kehlet
+//
+// This file is part of mshr.
+//
+// mshr 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 3 of the License, or
+// (at your option) any later version.
+//
+// mshr 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 mshr.  If not, see <http://www.gnu.org/licenses/>.
+//
+// Modified by Johannes Ring, 2012
+
+#include <mshr/CSGPrimitives2D.h>
+#include <dolfin/math/basic.h>
+#include <dolfin/log/LogStream.h>
+
+#include <sstream>
+#include <limits>
+#include <algorithm>
+
+#include <CGAL/Cartesian.h>
+#include <CGAL/Polygon_2.h>
+
+namespace mshr
+{
+//-----------------------------------------------------------------------------
+CSGPrimitive2D::CSGPrimitive2D()
+{}
+//-----------------------------------------------------------------------------
+
+
+//-----------------------------------------------------------------------------
+// Circle
+//-----------------------------------------------------------------------------
+Circle::Circle(dolfin::Point(c), double r, std::size_t segments)
+  : c(c), _r(r), _segments(segments)
+{
+  if (_r < DOLFIN_EPS)
+  {
+    std::stringstream s;
+    s << "Circle with center " << c.str() << " has zero or negative radius";
+    dolfin::dolfin_error("CSGPrimitives2D.cpp",
+                         "create circle",
+                         s.str());
+  }
+
+  if (0 < _segments && _segments < 3)
+  {
+    dolfin::dolfin_error("CSGPrimitives2D.cpp",
+                         "create circle",
+                         "Unable to create circle with fewer than 3 segments");
+  }
+}
+//-----------------------------------------------------------------------------
+std::string Circle::str(bool verbose) const
+{
+  std::stringstream s;
+
+  if (verbose)
+  {
+    s << "<Circle at (" << c.str() << ") with radius " << _r << ">";
+  }
+  else
+  {
+    s << "Circle(" << c.str() << ", " << _r << ")";
+  }
+
+  return s.str();
+}
+//-----------------------------------------------------------------------------
+std::pair<dolfin::Point, dolfin::Point> Circle::bounding_box() const
+{
+  return std::make_pair(dolfin::Point(c.x()-radius(), c.y()-radius()),
+                        dolfin::Point(c.x()+radius(), c.y()+radius()));
+}
+//-----------------------------------------------------------------------------
+bool Circle::inside(dolfin::Point p) const
+{
+  // dolfin::cout << "Inside: " << c << " r=" << _r << " ::: " << p << "(" << ((p-c).squared_norm() <= _r*_r ? "Inside" : "Outside") << dolfin::endl;
+  return (p-c).squared_norm() <= _r*_r;
+}
+
+
+//-----------------------------------------------------------------------------
+// Ellipse
+//-----------------------------------------------------------------------------
+Ellipse::Ellipse(dolfin::Point c, double a, double b,
+                 std::size_t segments)
+  : c(c), _a(a), _b(b), _segments(segments)
+{
+  if (_a < DOLFIN_EPS || _b < DOLFIN_EPS)
+  {
+    std::stringstream s;
+    s << "Ellipse with center " << c.str() << " has invalid semi-axis";
+    dolfin::dolfin_error("CSGPrimitives2D.cpp",
+                         "create ellipse",
+                         s.str());
+  }
+
+  if (0 < _segments && _segments < 3)
+  {
+    dolfin::dolfin_error("CSGPrimitives2D.cpp",
+                 "create ellipse",
+                 "Unable to create ellipse with fewer than 3 segments");
+  }
+}
+//-----------------------------------------------------------------------------
+std::string Ellipse::str(bool verbose) const
+{
+  std::stringstream s;
+
+  if (verbose)
+  {
+    s << "<Ellipse centered at (" << c.str() << ") with horizontal semi-axis "
+      << _a << " and vertical semi-axis " << _b << ">";
+  }
+  else
+  {
+    s << "Ellipse(" << c.str() << ", " << _a << ", " << _b << ")";
+  }
+
+  return s.str();
+}
+//-----------------------------------------------------------------------------
+std::pair<dolfin::Point, dolfin::Point> Ellipse::bounding_box() const
+{
+  return std::make_pair(dolfin::Point(c.x()-a(), c.y()-b()),
+                        dolfin::Point(c.x()+a(), c.y()+b()));
+}
+//-----------------------------------------------------------------------------
+bool Ellipse::inside(dolfin::Point p) const
+{
+  const double x = (c.x()-p.x())/_a;
+  const double y = (c.y()-p.y())/_b;
+  return x*x + y*y <= 1;
+}
+
+//-----------------------------------------------------------------------------
+// Rectangle
+//-----------------------------------------------------------------------------
+Rectangle::Rectangle(dolfin::Point a_, dolfin::Point b_)
+  : a(dolfin::Point(std::min(a_.x(), b_.x()), std::min(a_.y(), b_.y()))),
+    b(dolfin::Point(std::max(a_.x(), b_.x()), std::max(a_.y(), b_.y())))
+{
+  if (dolfin::near(a.x(), b.x()) || dolfin::near( a.y(), b.y()))
+  {
+    std::stringstream s;
+    s << "Rectangle with corner " << a.str() << " and " << b.str() << " degenerated";
+    dolfin::dolfin_error("CSGPrimitives2D.cpp",
+                 "create rectangle",
+                         s.str());
+  }
+}
+//-----------------------------------------------------------------------------
+std::string Rectangle::str(bool verbose) const
+{
+  std::stringstream s;
+
+  if (verbose)
+  {
+    s << "<Rectangle with first corner at (" << a.str() << ") "
+      << "and second corner at (" << b.str() << ")>";
+  }
+  else
+  {
+    s << "Rectangle( (" << a.str() << "), (" << b.str() << ") )";
+  }
+
+  return s.str();
+}
+//-----------------------------------------------------------------------------
+std::pair<dolfin::Point, dolfin::Point> Rectangle::bounding_box() const
+{
+  return std::make_pair(a, b);
+}
+//-----------------------------------------------------------------------------
+bool Rectangle::inside(dolfin::Point p) const
+{
+  return p.x() >= a.x() && p.x() <= b.x() && p.y() >= a.y() && p.y() <= b.y();
+}
+
+
+//-----------------------------------------------------------------------------
+// Polygon
+//-----------------------------------------------------------------------------
+Polygon::Polygon(const std::vector<dolfin::Point>& vertices)
+  : _vertices(vertices.begin(), vertices.end())
+{
+  if (_vertices.size() < 3)
+  {
+    dolfin::dolfin_error("CSGPrimitives2D.cpp",
+                 "create polygon",
+                 "Polygon should have at least three vertices");
+  }
+
+  if (!ccw())
+    dolfin::dolfin_error("CSGPrimitives2D.cpp",
+                 "create polygon",
+                 "Polygon vertices must be given in counter clockwise order");
+}
+//-----------------------------------------------------------------------------
+std::string Polygon::str(bool verbose) const
+{
+  std::stringstream s;
+
+  if (verbose)
+  {
+    s << "<Polygon with vertices ";
+    std::vector<dolfin::Point>::const_iterator p;
+    for (p = _vertices.begin(); p != _vertices.end(); ++p)
+    {
+      s << "(" << p->x() << ", " << p->y() << ")";
+      if ((p != _vertices.end()) && (p + 1 != _vertices.end()))
+        s << ", ";
+    }
+    s << ">";
+  }
+  else
+  {
+    s << "Polygon (" << _vertices.size() << " vertices)";
+  }
+
+  return s.str();
+}
+//-----------------------------------------------------------------------------
+bool Polygon::ccw() const
+{
+  double signed_area = 0.0;
+
+  dolfin::Point prev = _vertices.back();
+  for (std::vector<dolfin::Point>::const_iterator it = _vertices.begin(),
+        v_end = _vertices.end();
+       it != v_end;
+       ++it)
+  {
+    signed_area += (prev.x()*it->y())-(it->x()*prev.y());
+    prev = *it;
+  }
+
+  return signed_area > 0;
+}
+//-----------------------------------------------------------------------------
+std::pair<dolfin::Point, dolfin::Point> Polygon::bounding_box() const
+{
+  std::vector<dolfin::Point>::const_iterator it = _vertices.begin();
+  dolfin::Point min = *it;
+  dolfin::Point max = *it;
+  it++;
+
+  for (; it != _vertices.end(); it++)
+  {
+    const dolfin::Point& p = *it;
+    min[0] = std::min(min[0], p[0]);
+    min[1] = std::min(min[1], p[1]);
+    min[2] = std::min(min[2], p[2]);
+
+    max[0] = std::max(max[0], p[0]);
+    max[1] = std::max(max[1], p[1]);
+    max[2] = std::max(max[2], p[2]);
+  }
+
+  return std::make_pair(min, max);
+}
+//-----------------------------------------------------------------------------
+bool Polygon::inside(dolfin::Point p) const
+{
+  typedef CGAL::Cartesian<double> K;
+  typedef CGAL::Point_2<K> Point_2;
+  typedef CGAL::Polygon_2<K> Polygon_2;
+
+  Polygon_2 polygon;
+  for (const dolfin::Point& vertex : _vertices)
+    polygon.push_back(Point_2(vertex.x(), vertex.y()));
+
+  return polygon.has_on_bounded_side(Point_2(p.x(), p.y()));
+}
+
+}
diff --git a/src/CSGPrimitives3D.cpp b/src/CSGPrimitives3D.cpp
new file mode 100644 (file)
index 0000000..aa68614
--- /dev/null
@@ -0,0 +1,289 @@
+// Copyright (C) 2012 Anders Logg and 2012, 2014-2017 Benjamin Kehlet
+//
+// This file is part of mshr.
+//
+// mshr 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 3 of the License, or
+// (at your option) any later version.
+// 
+// mshr 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 mshr.  If not, see <http://www.gnu.org/licenses/>.
+//
+
+#include <mshr/CSGPrimitives3D.h>
+
+#include <dolfin/math/basic.h>
+#include <dolfin/log/LogStream.h>
+#include <sstream>
+
+namespace mshr
+{
+//-----------------------------------------------------------------------------
+CSGPrimitive3D::CSGPrimitive3D()
+{}
+//-----------------------------------------------------------------------------
+std::pair<dolfin::Point, dolfin::Point> CSGPrimitive3D::bounding_box() const
+{
+  dolfin_not_implemented();
+  return std::make_pair(dolfin::Point(0., 0., 0.), dolfin::Point(0., 0., 0.));
+}
+//-----------------------------------------------------------------------------
+bool CSGPrimitive3D::inside(dolfin::Point p) const
+{
+  dolfin_not_implemented();
+  return false;
+}
+
+
+
+//-----------------------------------------------------------------------------
+// Sphere
+//-----------------------------------------------------------------------------
+Sphere::Sphere(dolfin::Point center, double radius, std::size_t segments)
+  : c(center), r(radius), _segments(segments)
+{
+  if (r < DOLFIN_EPS)
+  {
+    dolfin::dolfin_error("CSGPrimitives3D.cpp",
+                         "Create sphere",
+                         "Sphere with center (%f, %f, %f) has zero or negative radius", c.x(), c.y(), c.z());
+  }
+
+  if (segments < 1)
+  {
+    dolfin::dolfin_error("CSGPrimitives3D.cpp",
+                "Create sphere",
+                "Can't create sphere with zero segments");
+  }
+}
+//-----------------------------------------------------------------------------
+std::string Sphere::str(bool verbose) const
+{
+  std::stringstream s;
+
+  if (verbose)
+  {
+    s << "<Sphere with center at " << c << " "
+      << "and radius " << r << ">";
+  }
+  else
+    s << "Sphere(" << c << ", " << r << ")";
+
+  return s.str();
+}
+//-----------------------------------------------------------------------------
+// Box
+//-----------------------------------------------------------------------------
+Box::Box(dolfin::Point a_, dolfin::Point b_)
+  : a(dolfin::Point(std::min(a_.x(), b_.x()), std::min(a_.y(), b_.y()), std::min(a_.z(), b_.z()))),
+    b(dolfin::Point(std::max(a_.x(), b_.x()), std::max(a_.y(), b_.y()), std::max(a_.z(), b_.z())))
+{
+  if (dolfin::near(a.x(), b.x()) || dolfin::near(a.y(), b.y()) || dolfin::near(a.z(), b.z()))
+  {
+    std::stringstream s;
+    s << "Box with corner " << a_.str() << " and " << b_.str() << "is degenerate";
+
+    dolfin::dolfin_error("CSGPrimitives3D.cpp",
+                         "Create axis aligned box",
+                         s.str());
+  }
+}
+//-----------------------------------------------------------------------------
+std::string Box::str(bool verbose) const
+{
+  std::stringstream s;
+
+  if (verbose)
+  {
+    s << "<Box with first corner at (" << a.str(true) << ") "
+      << "and second corner at (" << b.str(true) << ")>";
+  }
+  else
+  {
+    s << "Box(" << a.str(false) << ", " << b.str(false) << ")";
+  }
+
+  return s.str();
+}
+//-----------------------------------------------------------------------------
+// Cone
+//-----------------------------------------------------------------------------
+Cylinder::Cylinder(dolfin::Point top, 
+                   dolfin::Point bottom, 
+                   double top_radius, 
+                   double bottom_radius,
+                   std::size_t segments)
+  : _top(top), _bottom(bottom), _top_radius(top_radius),
+    _bottom_radius(bottom_radius), _segments(segments)
+{
+  if (dolfin::near(top_radius, 0.0) && dolfin::near(bottom_radius, 0.0))
+  {
+    dolfin::dolfin_error("CSGPrimitives3D.cpp",
+                         "Create cylinder",
+                         "Cylinder with zero thickness");
+  }
+
+  if (top.distance(bottom) < DOLFIN_EPS)
+  {
+    dolfin::dolfin_error("CSGPrimitives3D.cpp",
+                         "Create cylinder",
+                         "Cylinder with zero length");
+  }
+}
+//-----------------------------------------------------------------------------
+std::string Cylinder::str(bool verbose) const
+{
+  std::stringstream s;
+  if (verbose)
+  {
+    s << "<Cylinder with top at " << _top << ", top radius " << _top_radius
+      << " and bottom at " << _bottom << ", bottom radius "
+      << _bottom_radius << ", with " << _segments << " segments>";
+  }
+  else
+  {
+    s << "Cylinder( " << _top << ", " << _bottom << ", " << _top_radius
+      << ", " << _bottom_radius << " )";
+  }
+
+  return s.str();
+}
+//-----------------------------------------------------------------------------
+Tetrahedron::Tetrahedron(dolfin::Point a,
+                         dolfin::Point b, 
+                         dolfin::Point c, 
+                         dolfin::Point d)
+  : a(a), b(b), c(c), d(d)
+{
+  // TODO: Check validity of coordinates
+}
+//-----------------------------------------------------------------------------
+/// Informal string representation
+std::string Tetrahedron::str(bool verbose) const
+{
+  std::stringstream s;
+  if (verbose)
+  {
+    s << "<Tetrahedron with points at " << a << ", " << b << ", "
+      << c << ", " << d << ">";
+  }
+  else
+  {
+    s << "Tetrahedron( " << a << ", " << b << ", " << c << ", "
+      << d << ")";
+  }
+  return s.str();
+}
+//-----------------------------------------------------------------------------
+Surface3D::Surface3D(std::string filename)
+ : _filename(filename),
+   mesh(NULL),
+   vertex_tolerance(.0),
+   degenerate_tolerance(1e-12),
+   repair(false),
+   single_connected_component(false),
+   sharp_features_filter(-1),
+   first_facet(0),
+   flip_facets(false),
+   debug_dump("")
+{
+  // Do nothing
+}
+//-----------------------------------------------------------------------------
+Surface3D::Surface3D(std::shared_ptr<const dolfin::Mesh> m)
+ : _filename(""),
+   mesh(m),
+   vertex_tolerance(.0),
+   degenerate_tolerance(1e-12),
+   repair(false),
+   single_connected_component(false),
+   sharp_features_filter(-1),
+   first_facet(0),
+   cell_domain(0),
+   use_cell_domain(false)
+{}
+//-----------------------------------------------------------------------------
+Surface3D::Surface3D(std::shared_ptr<const dolfin::Mesh> m,
+                     std::size_t cell_domain)
+ : _filename(""),
+   mesh(m),
+   vertex_tolerance(.0),
+   degenerate_tolerance(1e-12),
+   repair(false),
+   single_connected_component(false),
+   sharp_features_filter(-1),
+   first_facet(0),
+   cell_domain(cell_domain),
+   use_cell_domain(true)
+{}
+//-----------------------------------------------------------------------------
+std::string Surface3D::str(bool verbose) const
+{
+  return std::string("Surface3D from file ") + _filename;
+}
+//-----------------------------------------------------------------------------
+Ellipsoid::Ellipsoid(dolfin::Point center, double a, double b, double c, std::size_t segments)
+  : center(center), a(a), b(b), c(c), _segments(segments)
+{
+  if (a < DOLFIN_EPS || b < DOLFIN_EPS || c < DOLFIN_EPS)
+  {
+    dolfin::dolfin_error("CSGPrimitives3D.cpp",
+                         "Create ellipsoid",
+                         "Ellipsoid with zero or negative semi-principal axis");
+  }
+
+  if (segments < 1)
+  {
+    dolfin::dolfin_error("CSGPrimitives3D.cpp",
+                         "Create ellipsoid",
+                         "Can't create ellipsoid with zero segments");
+  }
+}
+//-----------------------------------------------------------------------------
+std::string Ellipsoid::str(bool verbose) const
+{
+  std::stringstream ss;
+  if (verbose)
+  {
+    ss << "Ellipsoid centered at " << center.str() << " with semi-principal axes of lengths ";
+    ss << a  << ", " << b << " and " << c;
+  }
+  else
+  {
+    ss << "Ellipsoid(" << center.str() << ", " << a << ", " << b << ", " << c << ")";
+  }
+  return ss.str();
+}
+//-----------------------------------------------------------------------------
+Extrude2D::Extrude2D(std::shared_ptr<CSGGeometry> geometry_2d, double z)
+  : geometry_2d(geometry_2d), z(z)
+{
+  if (geometry_2d->dim() != 2)
+  {
+    std::stringstream ss;
+    ss << "Expected geometry of dimension 2, got ";
+    ss << geometry_2d->dim();
+    dolfin::dolfin_error("CSGPrimitives3D.cpp",
+                         "Extrude 2D geometry",
+                         ss.str());
+}
+}
+//-----------------------------------------------------------------------------
+std::string Extrude2D::str(bool verbose) const
+{
+  std::stringstream ss;
+  ss << "Extruded 2D polygon, z = " << z;
+  if (verbose)
+  {
+    ss << geometry_2d->str(true);
+  }
+
+  return ss.str();
+}
+}
diff --git a/src/DolfinMeshUtils.cpp b/src/DolfinMeshUtils.cpp
new file mode 100644 (file)
index 0000000..1519a5c
--- /dev/null
@@ -0,0 +1,298 @@
+// Copyright (C) 2014-2016 Benjamin Kehlet
+//
+// This file is part of mshr.
+//
+// mshr 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 3 of the License, or
+// (at your option) any later version.
+//
+// mshr 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 mshr.  If not, see <http://www.gnu.org/licenses/>.
+//
+
+#include <mshr/DolfinMeshUtils.h>
+#include "FuzzyPointLocator.h"
+
+#include <dolfin/mesh/Cell.h>
+#include <dolfin/mesh/Vertex.h>
+#include <dolfin/mesh/Facet.h>
+#include <dolfin/mesh/MeshEditor.h>
+#include <dolfin/math/basic.h>
+
+#include <limits>
+
+namespace mshr
+{
+
+std::pair<double, double> DolfinMeshUtils::cell_volume_min_max(const dolfin::Mesh& m)
+{
+  std::pair<double, double> res(std::numeric_limits<double>::max(), 0.0);
+
+  for (dolfin::CellIterator cell(m); !cell.end(); ++cell)
+  {
+    const double v = cell->volume();
+    res.first = std::min(res.first, v);
+    res.second = std::max(res.second, v);
+  }
+
+  return res;
+}
+//-----------------------------------------------------------------------------
+bool DolfinMeshUtils::has_isolated_vertices(const dolfin::Mesh& m)
+{
+  std::set<std::size_t> vertices;
+  for (dolfin::CellIterator cit(m); !cit.end(); ++cit)
+  {
+    const unsigned int* v = cit->entities(0);
+    for (std::size_t i = 0; i < cit->num_global_entities(0); i++)
+    {
+      vertices.insert(v[i]);
+    }
+  }
+
+  bool isolated_vertices = false;
+  for (std::size_t i = 0; i < m.num_vertices(); i++)
+  {
+    if (vertices.count(i) < 1)
+    {
+      log(dolfin::DBG, "Vertex %u has no incident cells", i);
+      isolated_vertices = true;
+    }
+  }
+
+  return isolated_vertices;
+}
+//-----------------------------------------------------------------------------
+bool DolfinMeshUtils::check_mesh(const dolfin::Mesh& m)
+{
+  return !has_isolated_vertices(m);
+}
+//-----------------------------------------------------------------------------
+std::shared_ptr<dolfin::Mesh>
+   DolfinMeshUtils::extract_subdomain(std::shared_ptr<const dolfin::Mesh> mesh,
+                                      std::size_t cell_domain)
+{
+  dolfin_assert(mesh->geometry().dim() == 3);
+  dolfin_assert(mesh->topology().dim() == 3);
+
+  // Collect all vertices incident to all marked cells
+  std::map<std::size_t, std::size_t> collected_vertices;
+  std::size_t num_cells = 0;
+  for (const std::pair<std::size_t, std::size_t>& marker : mesh->domains().markers(3))
+  {
+    if (marker.second == cell_domain)
+    {
+      num_cells++;
+      dolfin::Cell c(*mesh, marker.second);
+      for (std::size_t i = 0; i < 4; i++)
+      {
+        const std::size_t s = collected_vertices.size();
+        collected_vertices.insert(std::make_pair(c.entities(0)[i], s));
+      }
+    }
+  }
+
+  std::shared_ptr<dolfin::Mesh> outmesh(new dolfin::Mesh);
+  dolfin::MeshEditor editor;
+  editor.open(*outmesh, dolfin::CellType::Type::tetrahedron, 3,3);
+
+  editor.init_vertices(collected_vertices.size());
+  for (std::pair<std::size_t, std::size_t> v : collected_vertices)
+  {
+    dolfin::Vertex existing_vertex(*mesh, v.first);
+    editor.add_vertex(v.second, existing_vertex.point());
+  }
+
+  editor.init_cells(num_cells);
+  std::size_t cell_counter = 0;
+  for (const std::pair<std::size_t, std::size_t>& marker : mesh->domains().markers(3))
+  {
+    if (marker.second == cell_domain)
+    {
+      const dolfin::Cell c(*mesh, marker.second);
+      const unsigned int* vertices = c.entities(0);
+      editor.add_cell(cell_counter,
+                      collected_vertices[vertices[0]],
+                      collected_vertices[vertices[1]],
+                      collected_vertices[vertices[2]],
+                      collected_vertices[vertices[3]]);
+
+    }
+  }
+
+  editor.close();
+  return outmesh;
+}
+
+
+//-----------------------------------------------------------------------------
+std::shared_ptr<dolfin::Mesh>
+DolfinMeshUtils::merge_meshes(std::shared_ptr<dolfin::Mesh> m1,
+                              std::shared_ptr<dolfin::Mesh> m2,
+                              int m1_marker,
+                              int m2_marker,
+                              int m1_boundary_marker,
+                              int m2_boundary_marker,
+                              int interface_marker)
+{
+  log(dolfin::TRACE, "Merge meshes");
+
+  if (m1->topology().dim() != m2->topology().dim() || m1->geometry().dim() != m2->geometry().dim())
+    dolfin::dolfin_error("DolfinMeshUtils.cpp",
+                        "merging meshes",
+                        "Meshes dimensions must match");
+
+  const std::size_t tdim = m1->topology().dim();
+
+  // Map vertex (geometric) points to index for m1
+  FuzzyPointMap vertex_map_inner(1e-14);
+  std::vector<std::size_t> map_to_mesh_index(m1->num_vertices());;
+
+  for (dolfin::VertexIterator v(*m1); !v.end(); ++v)
+  {
+    dolfin_assert(!vertex_map_inner.contains(v->point()));
+    const std::size_t map_index = vertex_map_inner.insert_point(v->point());
+    map_to_mesh_index[map_index] = v->global_index();
+  }
+
+  dolfin_assert(m1->num_vertices() == vertex_map_inner.size());
+
+  // Count number of shared vertices
+  // (We need this to initialize the mesh editor)
+  // TOOO: Store these to avoid another lookup?
+  std::size_t shared_vertices = 0;
+  for (dolfin::VertexIterator v(*m2); !v.end(); ++v)
+  {
+    if (vertex_map_inner.contains(v->point()))
+      shared_vertices++;
+  }
+
+  log(dolfin::TRACE, "Located %u shared vertices.", shared_vertices);
+
+  std::shared_ptr<dolfin::Mesh> outmesh(new dolfin::Mesh);
+  dolfin::MeshEditor editor;
+  editor.open(*outmesh, m1->type().cell_type(), tdim, tdim);
+  editor.init_vertices(m1->num_vertices() + m2->num_vertices() - shared_vertices);
+
+  // Add vertices from m1
+  for (dolfin::VertexIterator v(*m1); !v.end(); ++v)
+  {
+    editor.add_vertex(v->global_index(), v->point());
+  }
+
+  // Add vertices from m2
+  std::vector<std::size_t> m2_vertex_map(m2->num_vertices());
+
+  std::size_t m2_vertex_counter = m1->num_vertices();
+  for (dolfin::VertexIterator v(*m2); !v.end(); ++v)
+  {
+    std::size_t index;
+    if (vertex_map_inner.contains(v->point()))
+    {
+      const std::size_t map_index = vertex_map_inner.get_index(v->point());
+      index = map_to_mesh_index[map_index];
+    }
+    else
+    {
+      index = m2_vertex_counter;
+      editor.add_vertex(index, v->point());
+
+      m2_vertex_counter++;
+    }
+
+    m2_vertex_map[v->global_index()] = index;
+  }
+
+  editor.init_cells(m1->num_cells() + m2->num_cells());
+
+  std::size_t cell_counter = 0;
+
+  std::vector<std::size_t> vertices(tdim+1);
+
+  // Add cells from m1
+  for (dolfin::CellIterator c(*m1); !c.end(); ++c)
+  {
+    for (std::size_t i = 0; i < tdim+1; i++)
+      vertices[i] = c->entities(0)[i];
+
+    editor.add_cell(cell_counter,vertices);
+    cell_counter++;
+  }
+
+  for (dolfin::CellIterator c(*m2); !c.end(); ++c)
+  {
+    for (std::size_t i = 0; i < tdim+1; i++)
+      vertices[i] = m2_vertex_map[c->entities(0)[i]];
+
+    editor.add_cell(cell_counter,vertices);
+    cell_counter++;
+  }
+  editor.close();
+
+  return outmesh;
+
+  // Mark cells from
+  dolfin::MeshDomains &domain_markers = outmesh->domains();
+  domain_markers.init(tdim-1);
+  domain_markers.init(tdim);
+
+  for (std::size_t i = 0; i < outmesh->num_cells(); ++i)
+  {
+    if (m1->num_cells())
+    {
+      if (m1_marker >= 0)
+        domain_markers.set_marker(std::make_pair(i, m1_marker), tdim);
+    }
+    else
+    {
+      if (m2_marker >= 0)
+        domain_markers.set_marker(std::make_pair(i, m2_marker), tdim);
+    }
+  }
+
+  // Mark facets
+  // Boundary facets are marked with 1 or 2 depending on the source meshes the
+  // origined from. Facets shared by the two source meshes will be marked with
+  // 3.
+
+  // Compute facet - cell connectivity
+
+  outmesh->init(tdim-1, tdim);
+  for (dolfin::FacetIterator f(*outmesh); !f.end(); ++f)
+  {
+    if (f->exterior())
+    {
+      if (f->entities(tdim)[0] < m1->num_cells())
+      {
+        if (m1_boundary_marker >= 0)
+          domain_markers.set_marker(std::make_pair(f->index(), m1_boundary_marker), tdim-1);
+      }
+      else
+      {
+        if (m2_boundary_marker >= 0)
+          domain_markers.set_marker(std::make_pair(f->index(), m2_boundary_marker), tdim-1);
+      }
+    }
+    else
+    {
+      if (interface_marker >= 0)
+      {
+        const std::size_t cell1 = f->entities(tdim)[0];
+        const std::size_t cell2 = f->entities(tdim)[1];
+        if ( (cell1 < m1->num_cells() && cell2 >= m1->num_cells()) ||
+             (cell1 >= m1->num_cells() && cell2 < m1->num_cells()))
+          domain_markers.set_marker(std::make_pair(f->index(), interface_marker), tdim-1);
+      }
+    }
+  }
+
+  return outmesh;
+}
+
+}
diff --git a/src/FuzzyPointLocator.h b/src/FuzzyPointLocator.h
new file mode 100644 (file)
index 0000000..12e2991
--- /dev/null
@@ -0,0 +1,145 @@
+// Copyright (C) 2016 Benjamin Kehlet
+//
+// This file is part of mshr.
+//
+// mshr 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 3 of the License, or
+// (at your option) any later version.
+//
+// mshr 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 mshr.  If not, see <http://www.gnu.org/licenses/>.
+//
+// Modified by Anders Logg 2016
+
+#ifndef FUZZY_POINT_SET_H
+#define FUZZY_POINT_SET_H
+
+#include <utility> // defines less operator for std::pair
+#include <map>
+#include <set>
+#include <algorithm>
+#include <iostream>
+#include <vector>
+#include <array>
+
+// TODO: Template over dimension.
+//template <std::size_t dim>
+class FuzzyPointMap
+{
+ public:
+  FuzzyPointMap(double tolerance)
+    : tolerance(tolerance)
+  {}
+  //-----------------------------------------------------------------------------
+  template <typename Point>
+  std::size_t insert_point(const Point& p)
+  //-----------------------------------------------------------------------------
+  {
+    const std::size_t index = get_index(p);
+    if (index == points.size())
+    {
+      // insert the points
+      points.push_back(std::array<double, 3>{{p[0], p[1], p[2]}});
+      maps[0].insert(std::make_pair(p[0], index));
+      maps[1].insert(std::make_pair(p[1], index));
+      maps[2].insert(std::make_pair(p[2], index));
+    }
+
+    return index;
+  }
+  //-----------------------------------------------------------------------------
+  template <typename Point>
+  std::size_t forced_insert_point(const Point& p)
+  //-----------------------------------------------------------------------------
+  {
+    const std::size_t index = points.size();
+
+    points.push_back(std::array<double, 3>{{p[0], p[1], p[2]}});
+    maps[0].insert(std::make_pair(p[0], index));
+    maps[1].insert(std::make_pair(p[1], index));
+    maps[2].insert(std::make_pair(p[2], index));
+
+    return index;
+  }
+  //-----------------------------------------------------------------------------
+  template<typename Point>
+  bool contains(const Point& p)
+  //-----------------------------------------------------------------------------
+  {
+    const std::size_t index = get_index(p);
+    return index < points.size();
+  }
+  //-----------------------------------------------------------------------------
+  const std::array<double, 3>& operator[](std::size_t i) const
+  //-----------------------------------------------------------------------------
+  {
+    return points[i];
+  }
+  //-----------------------------------------------------------------------------
+  const std::vector<std::array<double, 3>>& get_points() const
+  //-----------------------------------------------------------------------------
+  {
+    return points;
+  }
+  //-----------------------------------------------------------------------------
+  std::size_t size() const
+  //-----------------------------------------------------------------------------
+  {
+    return points.size();
+  }
+  //-----------------------------------------------------------------------------
+  template<typename Point>
+  std::size_t get_index(const Point& p)
+  //-----------------------------------------------------------------------------
+  {
+    typedef std::multimap<double, std::size_t>::iterator iterator;
+
+    // Check if a nearby point exists
+    std::array<std::set<std::size_t>, 3> matches;
+    for (int i = 0; i < 3; i++)
+    {
+      iterator lb = maps[i].lower_bound(p[i]-tolerance);
+      iterator ub = maps[i].upper_bound(p[i]+tolerance);
+
+      if (lb != maps[i].end())
+      {
+        iterator it = lb;
+        while (it != ub)
+        {
+          matches[i].insert(it->second);
+          it++;
+        }
+      }
+    }
+
+    std::set<std::size_t> x_y_intersections;
+    std::set_intersection(matches[0].begin(), matches[0].end(),
+                          matches[1].begin(), matches[1].end(),
+                          std::inserter(x_y_intersections, x_y_intersections.begin()));
+
+    std::set<std::size_t> x_y_z_intersections;
+    std::set_intersection(matches[2].begin(), matches[2].end(),
+                          x_y_intersections.begin(), x_y_intersections.end(),
+                          std::inserter(x_y_z_intersections, x_y_z_intersections.begin()));
+
+    if (x_y_z_intersections.size() > 0)
+      return *x_y_z_intersections.begin();
+    else
+      return points.size();
+  }
+
+ private:
+  const double tolerance;
+
+  // Map from component of point to index
+  std::array<std::multimap<double, std::size_t>, 3> maps;
+  std::vector<std::array<double, 3> > points;
+};
+
+#endif
diff --git a/src/GlobalInitializer.cpp b/src/GlobalInitializer.cpp
new file mode 100644 (file)
index 0000000..5999806
--- /dev/null
@@ -0,0 +1,43 @@
+// Copyright (C) 2014 Benjamin Kehlet
+//
+// This file is part of mshr.
+//
+// mshr 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 3 of the License, or
+// (at your option) any later version.
+// 
+// mshr 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 mshr.  If not, see <http://www.gnu.org/licenses/>.
+
+#include <mshr/GlobalInitializer.h>
+
+#include <CGAL/Random.h>
+
+#include <iostream>
+
+GlobalInitializer::GlobalInitializer()
+{
+  // std::cout << "Initializing globals" << std::endl;
+  #ifdef INIT_RANDOM_GENERATOR
+    // std::cout << "Using fixed random generator generator (seed=" << INIT_RANDOM_GENERATOR << ")" << std::endl;
+    CGAL::default_random = CGAL::Random( INIT_RANDOM_GENERATOR );
+  #endif
+
+}
+//-----------------------------------------------------------------------------
+GlobalInitializer::~GlobalInitializer()
+{
+
+}
+//-----------------------------------------------------------------------------
+GlobalInitializer _the_singleton;
+GlobalInitializer& GlobalInitializer::instance()
+{
+  return _the_singleton;
+}
diff --git a/src/MeshGenerator.cpp b/src/MeshGenerator.cpp
new file mode 100644 (file)
index 0000000..8a6d896
--- /dev/null
@@ -0,0 +1,112 @@
+// Copyright (C) 2012 Anders Logg, Johannes Ring, 2012-2016 Benjamin Kehlet
+//
+// This file is part of mshr.
+//
+// mshr 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 3 of the License, or
+// (at your option) any later version.
+//
+// mshr 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 mshr.  If not, see <http://www.gnu.org/licenses/>.
+
+#include <mshr/MeshGenerator.h>
+#include <mshr/CSGGeometry.h>
+#include <mshr/CSGCGALMeshGenerator2D.h>
+#include <mshr/CSGCGALMeshGenerator3D.h>
+#include <mshr/TetgenMeshGenerator3D.h>
+
+#include <mshr/CSGCGALDomain2D.h>
+
+#include <dolfin/log/log.h>
+#include <dolfin/mesh/BoundaryMesh.h>
+
+
+namespace mshr
+{
+
+//-----------------------------------------------------------------------------
+std::shared_ptr<dolfin::Mesh> generate_mesh(std::shared_ptr<const CSGGeometry> geometry,
+                                            double resolution,
+                                            std::string backend)
+{
+  if (resolution <= 0)
+  {
+    dolfin::dolfin_error("MeshGenerator.cpp",
+                         "generate from CSG geometry",
+                         "Resolution argument must be positive");
+  }
+
+
+  if (geometry->dim() == 2)
+  {
+    if (backend != "cgal")
+    {
+      const std::string e = "Unknown mesh generator backend: " + backend + ". The only supported 2D backend is cgal.";
+      dolfin::dolfin_error("MeshGenerator.cpp",
+                           "generate mesh of 2D geometry",
+                           e);
+    }
+
+    CSGCGALMeshGenerator2D generator;
+
+    // Estimate the bounding circle radius from the geometry
+    const std::pair<dolfin::Point, double> bounding_circle = geometry->estimate_bounding_sphere();
+    const double segment_granularity = 2*bounding_circle.second/resolution;
+    const double cell_size = 2.0*bounding_circle.second/resolution;
+
+    // Calculate surface representation
+    log(dolfin::TRACE, "Request cell size: %f", cell_size);
+    generator.parameters["mesh_resolution"] = -1.0;
+    generator.parameters["cell_size"] = cell_size;
+
+    std::shared_ptr<CSGCGALDomain2D> total_domain(new CSGCGALDomain2D(geometry, segment_granularity));
+    std::vector<std::pair<std::size_t, std::shared_ptr<const CSGCGALDomain2D>>> subdomain_geometries;
+    for (const std::pair<std::size_t, std::shared_ptr<const CSGGeometry>>& subdomain : geometry->get_subdomains())
+    {
+      subdomain_geometries.push_back(std::make_pair(subdomain.first,
+                                                    std::shared_ptr<CSGCGALDomain2D>(new CSGCGALDomain2D(subdomain.second, segment_granularity))));
+    }
+    return generator.generate(total_domain, subdomain_geometries);
+  }
+  else if (geometry->dim() == 3)
+  {
+    std::shared_ptr<CSGCGALDomain3D> domain(new CSGCGALDomain3D(geometry));
+    domain->ensure_meshing_preconditions();
+
+    if (backend == "cgal")
+    {
+      CSGCGALMeshGenerator3D generator;
+      generator.parameters["mesh_resolution"] = resolution;
+      return generator.generate(std::move(domain));
+    }
+    else if (backend == "tetgen")
+    {
+      TetgenMeshGenerator3D generator;
+      generator.parameters["mesh_resolution"] = resolution;
+      return generator.generate(std::move(domain));
+    }
+    else
+    {
+      std::string e = "Unknown mesh generator backend: " + backend;
+      dolfin::dolfin_error("MeshGenerator.cpp",
+                           "Generator mesh of 3D geometry",
+                           e);
+      return std::shared_ptr<dolfin::Mesh>();
+    }
+  }
+  else
+  {
+    dolfin::dolfin_error("MeshGenerator.cpp",
+                         "create mesh from CSG geometry",
+                         "Unhandled geometry dimension %d", geometry->dim());
+    return std::shared_ptr<dolfin::Mesh>();
+  }
+}
+
+}
diff --git a/src/Meshes.cpp b/src/Meshes.cpp
new file mode 100644 (file)
index 0000000..f5687cb
--- /dev/null
@@ -0,0 +1,59 @@
+// Copyright (C) -2014 Benjamin Kehlet
+//
+// This file is part of mshr.
+//
+// mshr 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 3 of the License, or
+// (at your option) any later version.
+// 
+// mshr 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 mshr. If not, see <http://www.gnu.org/licenses/>.
+
+#include <mshr/Meshes.h>
+#include <mshr/TetgenMeshGenerator3D.h>
+#include <mshr/CSGPrimitives3D.h>
+
+#include <dolfin/mesh/MeshPartitioning.h>
+
+namespace mshr
+{
+  UnitSphereMesh::UnitSphereMesh(std::size_t resolution)
+    : dolfin::Mesh()
+  {
+    // Receive mesh according to parallel policy
+    if (dolfin::MPI::is_receiver(this->mpi_comm()))
+    {
+      dolfin::MeshPartitioning::build_distributed_mesh(*this);
+      return;
+    }
+
+    std::shared_ptr<Sphere> s(new Sphere(dolfin::Point(0,0,0), 1.0, resolution));
+    std::shared_ptr<CSGCGALDomain3D> polyhedral_domain(new CSGCGALDomain3D(s));
+
+    TetgenMeshGenerator3D generator;
+    const double facet_area = 4.*DOLFIN_PI/polyhedral_domain->num_facets();
+    // compute edge length assuming perfect regular tetrahedrons
+    const double edge_length = 1.51967*std::sqrt(facet_area);
+    const double max_cell_volume = std::sqrt(2.)/12.*edge_length*edge_length*edge_length;
+    generator.parameters["max_tet_volume"] = max_cell_volume;
+    generator.parameters["preserve_surface"] = true;
+
+    std::shared_ptr<dolfin::Mesh> mesh = generator.generate(polyhedral_domain);
+    // dolfin::Mesh* m = static_cast<dolfin::Mesh>(this);
+    // *m = *mesh
+    dolfin::Mesh::operator=(*mesh);
+
+    // Broadcast mesh according to parallel policy
+    if (dolfin::MPI::is_broadcaster(this->mpi_comm()))
+    {
+      dolfin::MeshPartitioning::build_distributed_mesh(*this);
+      return;
+    }
+  }
+}
diff --git a/src/OFFFileReader.cpp b/src/OFFFileReader.cpp
new file mode 100644 (file)
index 0000000..87760fc
--- /dev/null
@@ -0,0 +1,188 @@
+// Copyright (C) 2015 Benjamin Kehlet
+//
+// This file is part of mshr.
+//
+// mshr 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 3 of the License, or
+// (at your option) any later version.
+//
+// mshr 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 mshr.  If not, see <http://www.gnu.org/licenses/>.
+//
+
+#include <mshr/OFFFileReader.h>
+
+#include <dolfin/geometry/Point.h>
+#include <dolfin/common/constants.h>
+#include <dolfin/log/LogStream.h>
+#include <dolfin/log/log.h>
+
+#define BOOST_FILESYSTEM_NO_DEPRECATED
+#include <boost/filesystem.hpp>
+#include <boost/tokenizer.hpp>
+#include <boost/algorithm/string.hpp>
+
+#include <fstream>
+#include <iostream>
+#include <sstream>
+#include <string>
+#include <algorithm>
+#include <string>
+#include <map>
+
+namespace
+{
+template<typename T>
+inline double convert_string(const std::string& s)
+{
+  std::istringstream is(s);
+  T val;
+  is >> val;
+
+  return val;
+}
+
+// get next line of file and trim away whitespace
+inline void get_next_line(std::ifstream& file, std::string& line, std::size_t &lineno)
+{
+  do
+  {
+    std::getline(file, line);
+    boost::algorithm::trim(line);
+    lineno++;
+  } while ( !file.eof() && line == "");
+}
+} // end anonymous namespace
+//-----------------------------------------------------------------------------
+namespace mshr
+{
+
+void OFFFileReader::read(const std::string filename,
+                         std::vector<std::array<double, 3> >& vertices,
+                         std::vector<std::array<std::size_t, 3> >& facets)
+{
+
+  dolfin::log(dolfin:: TRACE, "Reading surface from %s ", filename.c_str());
+
+  vertices.clear();
+  facets.clear();
+
+  typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
+
+  std::ifstream file(filename.c_str());
+  if (!file.is_open())
+  {
+    dolfin::dolfin_error("OFFFileReader.cpp",
+                         "open .off file to read 3D surface",
+                         "Failed to open file");
+  }
+
+  std::string line;
+  std::size_t lineno = 0;
+  const boost::char_separator<char> sep(" ");
+
+  // Read the first line and trim away whitespaces
+  get_next_line(file, line, lineno);
+
+  if (line != "OFF")
+  {
+    dolfin::dolfin_error("OFFFileReader.cpp",
+                         "open .off file to read 3D surface",
+                         "File does not start with \"OFF\" (line %u", lineno);
+  }
+
+  get_next_line(file, line, lineno);
+
+  // Read number of vertices and facets  
+  tokenizer tokens(line, sep);
+  tokenizer::iterator tok_iter = tokens.begin();
+
+  const std::size_t num_vertices = convert_string<std::size_t>(*tok_iter);
+  tok_iter++;
+  const std::size_t num_facets   = convert_string<std::size_t>(*tok_iter);
+
+  vertices.reserve(num_vertices);
+  facets.reserve(num_facets);
+  
+  get_next_line(file, line, lineno);
+
+  // Reader vertices
+  for (std::size_t i = 0; i < num_vertices; i++)
+  {
+    tokenizer tokens(line, sep);
+    tokenizer::iterator tok_iter = tokens.begin();
+
+    std::array<double, 3> vertex;
+    vertex[0] = convert_string<double>(*tok_iter);
+    tok_iter++;
+    vertex[1] = convert_string<double>(*tok_iter);
+    tok_iter++;
+    vertex[2] = convert_string<double>(*tok_iter);
+    tok_iter++;
+    
+    dolfin_assert(tok_iter == tokens.end());
+
+    vertices.push_back(vertex);
+    get_next_line(file, line, lineno);
+  }
+
+  // Read facets
+  for (std::size_t i = 0; i < num_facets; i++)
+  {
+    tokenizer tokens(line, sep);
+    tokenizer::iterator tok_iter = tokens.begin();
+
+    const std::size_t v = convert_string<std::size_t>(*tok_iter);
+    if (v != 3)
+      dolfin::dolfin_error("OFFFileReader.cpp",
+                           "reading off file",
+                           "facet is not triangular");
+    tok_iter++;
+    
+    std::array<std::size_t, 3> facet;
+    facet[0] = convert_string<std::size_t>(*tok_iter);
+    tok_iter++;
+    facet[1] = convert_string<std::size_t>(*tok_iter);
+    tok_iter++;
+    facet[2] = convert_string<std::size_t>(*tok_iter);
+    tok_iter++;
+    
+    dolfin_assert(tok_iter == tokens.end());
+
+    facets.push_back(facet);
+    get_next_line(file, line, lineno);
+  }
+}
+//-----------------------------------------------------------------------------
+void OFFFileReader::write(const std::string filename,
+                          const std::vector<std::array<double, 3> >& vertices,
+                          const std::vector<std::array<std::size_t, 3> >& facets)
+{
+  std::ofstream file(filename);
+  file.precision(6);
+
+  if (!file.is_open())
+  {
+    dolfin::dolfin_error("OFFFileReader.cpp",
+                         "open file to write off data",
+                         "Failed to open file");
+  }
+
+  file << "OFF " << vertices.size() << " " << facets.size() << " 0" << std::endl << std::endl;
+  for (const std::array<double, 3>& v : vertices)
+  {
+    file << v[0] << " " << v[1] << " " << v[2] << std::endl;
+  }
+
+  for (const std::array<std::size_t, 3>& f : facets)
+  {
+    file << "3 " << f[0] << " " << f[1] << " " << f[2] << std::endl;
+  }
+}
+}
diff --git a/src/Polygon_utils.h b/src/Polygon_utils.h
new file mode 100644 (file)
index 0000000..3b0cfd8
--- /dev/null
@@ -0,0 +1,46 @@
+// Copyright (C) 2017 Benjamin Kehlet
+//
+// This file is part of mshr.
+//
+// mshr 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 3 of the License, or
+// (at your option) any later version.
+//
+// mshr 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 mshr.  If not, see <http://www.gnu.org/licenses/>.
+
+
+#ifndef POLYGON_UTILS_H__
+#define POLYGON_UTILS_H__
+
+class PolygonUtils
+{
+ public:
+
+  // Computes the orientation, assuming that it is well defined
+  static bool ccw(const std::vector<dolfin::Point>& vertices)
+  {
+    double signed_area = 0.0;
+
+    dolfin::Point prev = vertices.back();
+    for (std::vector<dolfin::Point>::const_iterator it = vertices.begin(),
+          v_end = vertices.end();
+        it != v_end;
+        ++it)
+    {
+      signed_area += (prev.x()*it->y())-(it->x()*prev.y());
+      prev = *it;
+    }
+
+    return signed_area > 0; 
+  }
+};
+
+
+#endif
diff --git a/src/Polyhedral_multicomponent_mesh_domain_with_features_3.h b/src/Polyhedral_multicomponent_mesh_domain_with_features_3.h
new file mode 100644 (file)
index 0000000..618a951
--- /dev/null
@@ -0,0 +1,163 @@
+// Copyright (C) 2014 Benjamin Kehlet
+//
+// This file is part of mshr.
+//
+// mshr 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 3 of the License, or
+// (at your option) any later version.
+//
+// mshr 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 mshr.  If not, see <http://www.gnu.org/licenses/>.
+
+
+#ifndef POLYHEDRAL_MULTICOMPONENT_MESH_DOMAIN_WITH_FEATURES_3_H
+#define POLYHEDRAL_MULTICOMPONENT_MESH_DOMAIN_WITH_FEATURES_3_H
+
+#include "FuzzyPointLocator.h"
+#include "Polyhedron_utils.h"
+#include <CGAL/Polyhedral_mesh_domain_with_features_3.h>
+
+#include <dolfin/log/log.h>
+//-----------------------------------------------------------------------------
+// This class reimplements Construct_initial_points (from Polyhedral_mesh_domain)
+// in order to make sure that all disconnected parts of the polyhedron are
+// sufficiently covered. Otherwise the meshing algorithm may miss them entirely.
+template< typename IGT_ >
+class Polyhedral_multicomponent_mesh_domain_with_features_3
+  : public CGAL::Polyhedral_mesh_domain_with_features_3< IGT_ >
+{
+ public:
+  typedef typename CGAL::Polyhedral_mesh_domain_with_features_3< IGT_ > Base;
+  typedef typename Base::Polyhedron Polyhedron;
+
+  // Passing the edge size with the constructor is a workaround. Ideally CGAL should pass it
+  // when calling construct_initial_points
+  Polyhedral_multicomponent_mesh_domain_with_features_3(const Polyhedron& p, double edge_size)
+   : Base(p), edge_size(edge_size)
+  {}
+
+  ~Polyhedral_multicomponent_mesh_domain_with_features_3(){}
+
+  struct Construct_initial_points
+  {
+    Construct_initial_points(const Polyhedral_multicomponent_mesh_domain_with_features_3& domain,
+                             double edge_size)
+     : r_domain_(domain), edge_size(edge_size) {}
+
+    template<class OutputIterator>
+    OutputIterator operator()(OutputIterator pts, const int n = 8) const;
+
+   private:
+    const Polyhedral_multicomponent_mesh_domain_with_features_3& r_domain_;
+    const double edge_size;
+  };
+
+  Construct_initial_points construct_initial_points_object() const
+  {
+    return Construct_initial_points(*this, edge_size);
+  }
+
+ private :
+  const double edge_size;
+};
+//-----------------------------------------------------------------------------
+template<typename Set, typename Polyhedron>
+  void recursive_insert(Set& set,
+                        std::set<typename Polyhedron::Vertex_const_handle>& visited,
+                        typename Polyhedron::Vertex_const_handle v,
+                        std::size_t n)
+{
+  std::pair<typename std::set<typename Polyhedron::Vertex_const_handle>::iterator, bool> v_insert = visited.insert(v);
+
+  // If vertex is already visited, then return
+  if (!v_insert.second)
+  {
+    return;
+  }
+
+  // Add point to set.
+  set.insert_point(v->point());
+
+  typename Polyhedron::Halfedge_around_vertex_const_circulator start = v->vertex_begin(), current = start;
+  do
+  {
+    if ( set.size() >= n )
+      break;
+
+    recursive_insert<Set, Polyhedron>(set, visited, current->opposite()->vertex(), n);
+
+    current++;
+  } while (current != start);
+}
+
+//-----------------------------------------------------------------------------
+template<typename IGT_>
+template<class OutputIterator>
+OutputIterator
+Polyhedral_multicomponent_mesh_domain_with_features_3<IGT_>::
+Construct_initial_points::operator()(OutputIterator pts, const int n) const
+{
+  typedef typename Polyhedral_multicomponent_mesh_domain_with_features_3::Polyhedron Polyhedron;
+  typedef typename Polyhedron::Point_3 Point_3;
+  typedef typename Polyhedron::Vertex_const_handle Vertex_const_handle;
+
+  const std::vector<Polyhedron>& poly_ = r_domain_.polyhedra();
+  if (poly_.size() != 1)
+  {
+    dolfin::dolfin_error("Polyhedral_multicomponent_mesh_domain_with_features_3.h",
+                        "Accessing polyhedra for domain",
+                        "Unexpected number of polyhedrons! (%f)", poly_.size());
+  }
+  const Polyhedron& P  = poly_[0];
+  std::list<Vertex_const_handle> components;
+  mshr::PolyhedronUtils::get_disconnected_components(P, std::back_inserter(components));
+
+  // Collect inserted points in a set with a fuzzy comparison operator
+  // to ensure no points closer than the tolerance are inserted.
+  std::set<Vertex_const_handle> visited;
+
+  // TODO: Tune this parameter
+  const double tolerance = edge_size*3;
+  FuzzyPointMap inserted_points(tolerance);
+
+  std::size_t current_index;
+  {
+    // get corners
+    std::vector<std::pair<int, Point_3> > corners;
+    r_domain_.get_corners(std::back_inserter(corners));
+    current_index = corners.size();
+    current_index++;
+    for (const std::pair<int, Point_3>& c : corners)
+    {
+      inserted_points.forced_insert_point(c.second);
+    }
+  }
+
+  // Insert n surface points from each disconnected component
+  for (Vertex_const_handle v : components)
+  {
+    recursive_insert<FuzzyPointMap, Polyhedron>(inserted_points,
+                                                visited,
+                                                v,
+                                                n+inserted_points.size());
+  }
+
+  // for (auto it = inserted_points.begin(); it != inserted_points.end(); it++)
+  for (const std::array<double, 3>& p : inserted_points.get_points())
+  {
+
+    *pts = std::make_pair(Point_3(p[0], p[1], p[2]), current_index);
+    pts++;
+    current_index++;
+  }
+
+  return pts;
+}
+//-----------------------------------------------------------------------------
+#endif
diff --git a/src/Polyhedron_utils.h b/src/Polyhedron_utils.h
new file mode 100644 (file)
index 0000000..e7e834a
--- /dev/null
@@ -0,0 +1,2975 @@
+// Copyright (C) 2014-2015 Benjamin Kehlet
+//
+// This file is part of mshr.
+//
+// mshr 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 3 of the License, or
+// (at your option) any later version.
+//
+// mshr 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 mshr.  If not, see <http://www.gnu.org/licenses/>.
+
+
+#ifndef POLYHEDRON_UTILS_H__
+#define POLYHEDRON_UTILS_H__
+
+#include <dolfin/math/basic.h>
+
+#include <CGAL/basic.h>
+#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
+#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
+#include <CGAL/Simple_cartesian.h>
+#include <CGAL/Polyhedron_3.h>
+#include <CGAL/boost/graph/graph_traits_Polyhedron_3.h>
+//#include <CGAL/Self_intersection_polyhedron_3.h>
+#include <CGAL/linear_least_squares_fitting_3.h>
+#include <CGAL/Constrained_Delaunay_triangulation_2.h>
+#include <CGAL/Triangulation_vertex_base_with_info_2.h>
+#include <CGAL/Polyhedron_incremental_builder_3.h>
+#include <CGAL/convex_hull_3.h>
+#include <CGAL/version.h>
+#if CGAL_VERSION_NR >= 1041401000
+#include <CGAL/Polygon_mesh_processing/corefinement.h>
+#else
+#include <CGAL/corefinement_operations.h>
+#endif
+#include <CGAL/Aff_transformation_3.h>
+#include <CGAL/Delaunay_mesher_no_edge_refinement_2.h>
+#include <CGAL/Delaunay_mesh_face_base_2.h>
+#include <CGAL/Delaunay_mesh_size_criteria_2.h>
+
+#include <cmath>
+#include <deque>
+#include <fstream>
+
+namespace mshr
+{
+
+class PolyhedronUtils
+{
+ public:
+
+  //-----------------------------------------------------------------------------
+  template<typename CDT>
+  static void dump_2D_triangulation(const CDT& cdt, std::string filename)
+  {
+    std::cout << "Dumping 2D triangulation" << std::endl;
+
+    // Count valid cells and connected vertices
+    std::size_t num_cells = 0;
+    std::map<typename CDT::Vertex_handle, std::size_t> vertex_map;
+
+    for (typename CDT::Finite_faces_iterator cgal_cell = cdt.finite_faces_begin();
+         cgal_cell != cdt.finite_faces_end(); ++cgal_cell)
+    {
+      if (cgal_cell->is_in_domain())
+      {
+        num_cells++;
+
+        for (std::size_t i = 0; i < 3; i++)
+        {
+          const typename CDT::Vertex_handle v = cgal_cell->vertex(i);
+          if (vertex_map.count(v) == 0)
+          {
+            const std::size_t s = vertex_map.size();
+            vertex_map[v] = s;
+          }
+        }
+      }
+    }
+
+    std::cout << "Adding " << vertex_map.size() << " vertices and " << num_cells << " cells" << std::endl;
+
+    std::ofstream outfile(filename);
+    outfile << std::setprecision(16);
+    outfile << "OFF" << std::endl;
+    outfile << vertex_map.size() << " " << num_cells << " 0" << std::endl;
+    outfile << std::endl;
+
+    std::vector<typename CDT::Vertex_handle> vertices(vertex_map.size());
+    for (const std::pair<typename CDT::Vertex_handle, std::size_t>& vertex : vertex_map)
+      vertices[vertex.second] = vertex.first;
+
+    for (const typename CDT::Vertex_handle v : vertices)
+    {
+      outfile << v->point()[0] << " "
+              << v->point()[1] << " 0 " << std::endl;
+    }
+
+    for (typename CDT::Finite_faces_iterator cgal_cell = cdt.finite_faces_begin();
+         cgal_cell != cdt.finite_faces_end(); ++cgal_cell)
+    {
+      // Add cell if it is in the domain
+      if (cgal_cell->is_in_domain())
+      {
+        outfile << "3 "
+                << vertex_map[cgal_cell->vertex(0)] << " "
+                << vertex_map[cgal_cell->vertex(1)] << " "
+                << vertex_map[cgal_cell->vertex(2)] << std::endl;
+      }
+    }
+  }
+  //-----------------------------------------------------------------------------
+  // Scans the vertices of the polyhedron the polyhedron and returns a
+  // Polyhedron::Vertex_const_handle for each disconnected component.
+  template <typename Polyhedron, typename OutputIterator>
+  static void get_disconnected_components(const Polyhedron& p, OutputIterator it)
+  {
+    //typedef Polyhedron Polyhedron_t;
+    typedef typename Polyhedron::Halfedge_around_vertex_const_circulator HV_const_circulator;
+    typedef typename Polyhedron::Vertex_const_handle Vertex_const_handle;
+
+    // store all vertices in a set
+    std::set<Vertex_const_handle> v;
+    for (typename Polyhedron::Vertex_const_iterator vit = p.vertices_begin();
+         vit != p.vertices_end(); vit++)
+      v.insert(vit);
+
+    while (!v.empty())
+    {
+      // Add the component to the output
+      typename std::set<Vertex_const_handle>::iterator start_it = v.begin();
+      Vertex_const_handle start = *start_it;
+
+      *it = start;
+      it++;
+
+      // Remove all vertices belonging to component from v
+      std::deque<Vertex_const_handle> queue;
+      queue.push_back(start);
+      while (!queue.empty())
+      {
+        const Vertex_const_handle current = queue.front();
+        queue.pop_front();
+
+        if (v.count(current) > 0)
+        {
+          v.erase(current);
+
+          const HV_const_circulator h_start = current->vertex_begin();
+          HV_const_circulator h_current = h_start;
+          do
+          {
+            queue.push_back(h_current->opposite()->vertex());
+            h_current++;
+          } while (h_current != h_start);
+        }
+      }
+    }
+  }
+  //-----------------------------------------------------------------------------
+  template<typename Polyhedron>
+  static std::vector<typename Polyhedron::Halfedge_handle>
+  get_holes(Polyhedron& P)
+  {
+    typedef typename Polyhedron::Halfedge_handle Halfedge_handle;
+
+    P.normalize_border();
+
+    std::set<Halfedge_handle> border_edges;
+    for (typename Polyhedron::Halfedge_iterator hit = P.border_halfedges_begin(); hit != P.halfedges_end(); hit++)
+    {
+      Halfedge_handle b = hit;
+      dolfin_assert(b->is_border_edge());
+      if (b->is_border())
+        border_edges.insert(b);
+      else if (b->opposite()->is_border())
+        border_edges.insert(b->opposite());
+      else
+        dolfin_assert(false);
+    }
+
+    std::vector<Halfedge_handle> border_begins;
+    while (!border_edges.empty())
+    {
+      Halfedge_handle current = *(border_edges.begin());
+      border_begins.push_back(current);
+
+      std::size_t counter = 0;
+      const Halfedge_handle start = current;
+      do
+      {
+        dolfin_assert(border_edges.count(current) == 1);
+        border_edges.erase(current);
+        counter++;
+        current = current->next();
+      } while (current != start);
+    }
+
+    return std::move(border_begins);
+  }
+  //-----------------------------------------------------------------------------
+  // Count the number of edges in a facet or along a hole
+  template<typename Halfedge_handle>
+  static std::size_t edge_count(Halfedge_handle h)
+  {
+    Halfedge_handle current;
+    std::size_t counter = 0;
+    do
+    {
+      counter++;
+      current = current->next();
+    } while (current != h);
+
+    return counter;
+  }
+  //-----------------------------------------------------------------------------
+  template<typename Polyhedron>
+  static typename Polyhedron::Traits::Triangle_3 get_facet_triangle(typename Polyhedron::Halfedge_handle h)
+  {
+    typedef typename Polyhedron::Traits::Triangle_3 Triangle_3;
+
+    dolfin_assert(h->facet()->is_triangle());
+
+    return Triangle_3(h->vertex()->point(),
+                      h->next()->vertex()->point(),
+                      h->next()->next()->vertex()->point());
+  }
+  //-----------------------------------------------------------------------------
+  template<typename Polyhedron>
+    static double cos_min_angle(typename Polyhedron::Traits::Vector_3 v,
+                                typename Polyhedron::Halfedge_handle h1,
+                                typename Polyhedron::Halfedge_handle h2)
+  {
+    v /= v.squared_length();
+
+    double max = 0;
+    typename Polyhedron::Halfedge_handle current = h1;
+    do
+    {
+      typename Polyhedron::Traits::Vector_3 w(current->vertex()->point(),
+                                              current->next()->vertex()->point());
+      w /= std::sqrt(CGAL::to_double(w.squared_length()));
+      max = std::max(std::abs(CGAL::to_double(w*v)));
+    } while (current != h2);
+
+    return max;
+  }
+  //-----------------------------------------------------------------------------
+  // Given a facet and a vertex (assumed to be incident to the facet), find the
+  // corresponding halfedge
+  template<typename Polyhedron>
+  static typename Polyhedron::Halfedge_handle
+  find_edge(typename Polyhedron::Vertex_handle v,
+            typename Polyhedron::Face_handle f)
+  {
+    dolfin_assert(v != typename Polyhedron::Vertex_handle());
+    dolfin_assert(f != typename Polyhedron::Face_handle());
+
+    typename Polyhedron::Halfedge_around_vertex_circulator start = v->vertex_begin();
+    typename Polyhedron::Halfedge_around_vertex_circulator current = start;
+
+    do
+    {
+      if (current->facet() == f)
+      {
+        dolfin_assert(current->vertex() == v && current->facet()  == f);
+        return current;
+      }
+
+      current++;
+    } while(current != start);
+
+    dolfin_assert(false);
+    return typename Polyhedron::Halfedge_handle();
+  }
+  //-----------------------------------------------------------------------------
+  template<typename Polyhedron>
+  static typename Polyhedron::Facet_handle
+  find_common_facet(typename Polyhedron::Vertex_handle v0,
+                    typename Polyhedron::Vertex_handle v1,
+                    typename Polyhedron::Vertex_handle v2)
+  {
+    typedef typename Polyhedron::Halfedge_around_vertex_circulator He_circulator;
+    std::set<typename Polyhedron::Facet_handle> facets0;
+    {
+      He_circulator start = v0->vertex_begin();
+      He_circulator current = start;
+      do
+      {
+        if (!current->is_border())
+          facets0.insert(current->facet());
+
+        current++;
+      } while (current != start);
+    }
+
+    std::set<typename Polyhedron::Facet_handle> facets1;
+    {
+      He_circulator start = v1->vertex_begin();
+      He_circulator current = start;
+      do
+      {
+        if (!current->is_border() && facets0.count(current->facet()) > 0)
+          facets1.insert(current->facet());
+
+        current++;
+      } while (current != start);
+    }
+
+    std::set<typename Polyhedron::Facet_handle> facets2;
+    {
+      He_circulator start = v2->vertex_begin();
+      He_circulator current = start;
+      do
+      {
+        if (!current->is_border() && facets1.count(current->facet()) > 0)
+          facets2.insert(current->facet());
+
+        current++;
+      } while (current != start);
+    }
+
+    dolfin_assert(facets2.size() < 2);
+    dolfin_assert(facets2.size() > 0);
+
+    return *(facets2.begin());
+  }
+  //-----------------------------------------------------------------------------
+  template<typename Polyhedron>
+  static void insert_edge(Polyhedron& P,
+                          typename Polyhedron::Vertex_handle h,
+                          typename Polyhedron::Vertex_handle g,
+                          typename Polyhedron::Facet_handle f)
+  {
+    //std::pair<typename Polyhedron::Halfedge_handle, typename Polyhedron::Halfedge_handle>
+    //edges = find_edges(h_edge, g_edge);
+    typedef typename Polyhedron::Halfedge_handle Halfedge_handle;
+
+    Halfedge_handle h_edge, g_edge;
+    const Halfedge_handle start = g->halfedge();
+    Halfedge_handle current = start;
+    do
+    {
+      if (current->vertex() == h)
+        h_edge = current;
+      else if(current->vertex() == g)
+        g_edge == current;
+    } while (current != start);
+
+    dolfin_assert(h_edge != Halfedge_handle() && g_edge != Halfedge_handle());
+    P.split_facet(h_edge, g_edge);
+    dolfin_assert(P.is_valid());
+  }
+  //-----------------------------------------------------------------------------
+  template<typename Triangle_3>
+  static double get_triangle_cos_angle(Triangle_3 t1,
+                                       Triangle_3 t2)
+  {
+    typedef typename CGAL::Kernel_traits<Triangle_3>::Kernel::Vector_3 Vector_3;
+
+    const Vector_3 v1 = t1.supporting_plane().orthogonal_vector();
+    const Vector_3 v2 = t2.supporting_plane().orthogonal_vector();
+
+    return CGAL::to_double((v1*v2)/std::sqrt(CGAL::to_double(v1.squared_length()*v2.squared_length())));
+  }
+  //-----------------------------------------------------------------------------
+  template<typename Polyhedron>
+    static double get_edge_cos_angle(typename Polyhedron::Halfedge_handle h)
+  {
+    typedef typename Polyhedron::Traits::Vector_3 Vector_3;
+
+    // std::cout << "get edge cos theta" << std::endl;
+
+    Vector_3 h1_vec(h->vertex()->point(), h->prev()->vertex()->point());
+    h1_vec = h1_vec/std::sqrt(CGAL::to_double(h1_vec.squared_length()));
+
+    // std::cout << "h1_vec_normalized: " << h1_vec << std::endl;
+    Vector_3 h2_vec(h->vertex()->point(), h->next()->vertex()->point());
+    h2_vec = h2_vec/std::sqrt(CGAL::to_double(h2_vec.squared_length()));
+    // std::cout << "h2_vec_normalized: " << h2_vec << std::endl;
+    const double cos_theta = CGAL::to_double(h1_vec*h2_vec);
+    // std::cout << "Cos theta: " << cos_theta << std::endl;
+    return cos_theta;
+  }
+  //-----------------------------------------------------------------------------
+  // Compute the plane fit quality of the vertices from h1 to h2 both included
+  // Return fitting quality, max projection distance, max cos angle
+  template<typename Polyhedron>
+  static std::array<double, 3>
+  get_plane_fit(const typename Polyhedron::Halfedge_handle h1,
+                const typename Polyhedron::Halfedge_handle h2)
+  {
+    typedef typename Polyhedron::Halfedge_handle Halfedge_handle;
+    typedef typename Polyhedron::Traits::Plane_3 Plane_3;
+    typedef typename Polyhedron::Traits::Point_3 Point_3;
+    typedef typename Polyhedron::Traits::Vector_3 Vector_3;
+    typedef typename Polyhedron::Traits::FT FT;
+    typedef CGAL::Exact_predicates_inexact_constructions_kernel InexactKernel;
+    typedef typename InexactKernel::Plane_3 InexactPlane_3;
+    typedef typename InexactKernel::Point_3 InexactPoint_3;
+    //typedef typename InexactKernel::Segment_3 InexactSegment_3;
+    //typedef typename InexactKernel::Vector_3 InexactVector_3;
+    typedef typename Polyhedron::Traits::Point_3 Point_3;
+
+    // std::cout << "Get plane fit" << std::endl;
+
+    // std::cout << "Polygon ";
+    std::vector<InexactPoint_3> points;
+    //std::vector<InexactSegment_3> segments;
+    Halfedge_handle current = h1;
+    do
+    {
+      const Point_3& p = current->vertex()->point();
+      // std::cout << ", " << p;
+      points.push_back(InexactPoint_3(CGAL::to_double(p[0]),
+                                      CGAL::to_double(p[1]),
+                                      CGAL::to_double(p[2])));
+      current = current->next();
+    } while (current != h2);
+
+    {
+      const Point_3& p = h2->vertex()->point();
+      // std::cout << ", " << p;
+      points.push_back(InexactPoint_3(CGAL::to_double(p[0]),
+                                      CGAL::to_double(p[1]),
+                                      CGAL::to_double(p[2])));
+    }
+
+    dolfin_assert(points.size() > 2);
+    // std::cout << "Size: " << points.size() << std::endl;
+    //std::cout << std::endl;
+    InexactPlane_3 fitting_plane_inexact;
+    const double fit_quality = CGAL::linear_least_squares_fitting_3(points.begin(),
+                                                                    points.end(),
+                                                                    fitting_plane_inexact,
+                                                                    CGAL::Dimension_tag<0>());
+    Plane_3 fitting_plane(fitting_plane_inexact.a(),
+                          fitting_plane_inexact.b(),
+                          fitting_plane_inexact.c(),
+                          fitting_plane_inexact.d());
+    // std::cout << "Plane: " << fitting_plane << std::endl;
+    // std::cout << "Length of normal: " << fitting_plane.orthogonal_vector().squared_length() << std::endl;
+    const Vector_3 normal = fitting_plane.orthogonal_vector()/std::sqrt(CGAL::to_double(fitting_plane.orthogonal_vector().squared_length()));
+
+    FT max_distance = (h1->vertex()->point()-fitting_plane.projection(h1->vertex()->point())).squared_length();
+    FT max_angle = 0;
+
+    Halfedge_handle prev = h1;
+    current = h1->next();
+    do
+    {
+      const Vector_3 v = current->vertex()->point()-prev->vertex()->point();
+      const FT cos_angle = v/std::sqrt(CGAL::to_double(v.squared_length())) * normal;
+      const Point_3 projection = fitting_plane.projection(current->vertex()->point());
+      max_angle = std::max(max_angle, cos_angle);
+      max_distance = std::max(max_distance, (current->vertex()->point()-projection).squared_length());
+
+      prev = current;
+      current = current->next();
+    } while (prev != h2);
+
+    // std::cout << "Fit quality: " << fit_quality << ", max distance: " << max_distance << ", cos_angle: " << max_angle << std::endl;
+    return std::array<double, 3>{fit_quality, CGAL::to_double(max_distance), CGAL::to_double(max_angle)};
+    // return -max_distance;
+    //return CGAL::to_double(fit_quality - max_angle);
+  }
+  //-----------------------------------------------------------------------------
+  // Compute the fit quality heuristic of the vertices from h1 to h2 both
+  // included.
+
+  // Some experiences:
+  // * The plane fit quality as returned from
+  // CGAL::linear_least_squares_fitting_3() is not suitable here. It measures
+  // how distinct the best fitting plane is, rather than the actual quality of
+  // the fit.
+  // * The max angle between the segments and the normal work good is the hole
+  // has no more than one "kink".
+  // * The max distance from the points to their projection is also a pretty
+  // good measure, but needs to be normalized in some clever way if not used
+  // solely.
+  template<typename Polyhedron>
+  static double evaluate_hole_subdivision(const typename Polyhedron::Halfedge_handle h1,
+                                          const typename Polyhedron::Halfedge_handle h2)
+  {
+    typedef typename Polyhedron::Halfedge_handle Halfedge_handle;
+    typedef typename Polyhedron::Traits::Point_3 Point_3;
+    typedef CGAL::Simple_cartesian<double> InexactKernel;
+    //typedef CGAL::Exact_predicates_inexact_constructions_kernel InexactKernel;
+    typedef typename InexactKernel::Plane_3 InexactPlane_3;
+    typedef typename InexactKernel::Point_3 InexactPoint_3;
+    typedef typename InexactKernel::Segment_3 InexactSegment_3;
+    typedef typename InexactKernel::Vector_3 InexactVector_3;
+
+    // double plane1fit;
+    double max_angle1 = 0;
+    InexactPlane_3 fitting_plane1;
+    double avg_distance_squared1 = 0;
+    {
+      std::vector<InexactSegment_3> segments;
+      Halfedge_handle current = h1;
+      do
+      {
+        const Point_3& p = current->vertex()->point();
+        const Point_3& next = current->next()->vertex()->point();
+        segments.push_back(InexactSegment_3(InexactPoint_3(CGAL::to_double(p[0]), CGAL::to_double(p[1]), CGAL::to_double(p[2])),
+                                            InexactPoint_3(CGAL::to_double(next[0]), CGAL::to_double(next[1]), CGAL::to_double(next[2]))));
+        current = current->next();
+      } while (current != h2);
+
+      {
+        const Point_3& p = h2->vertex()->point();
+        const Point_3& next = h1->vertex()->point();
+        segments.push_back(InexactSegment_3(InexactPoint_3(CGAL::to_double(p[0]), CGAL::to_double(p[1]), CGAL::to_double(p[2])),
+                                            InexactPoint_3(CGAL::to_double(next[0]), CGAL::to_double(next[1]), CGAL::to_double(next[2]))));
+      }
+
+      dolfin_assert(segments.size() > 2);
+
+      /* plane1fit = */ CGAL::linear_least_squares_fitting_3(segments.begin(),
+                                                             segments.end(),
+                                                             fitting_plane1,
+                                                             CGAL::Dimension_tag<1>());
+
+      // std::cout << "  Plane 1: " << fitting_plane1 << ", " << plane1fit << std::endl;
+
+      // Compute max angle between segment and fitting plane
+      const InexactVector_3 normal = fitting_plane1.orthogonal_vector();
+      // std::cout << "Length: " << normal.squared_length() << std::endl;
+      dolfin_assert(dolfin::near(normal.squared_length(), 1, DOLFIN_EPS_LARGE));
+      for (auto sit = segments.begin(); sit != segments.end(); sit++)
+      {
+        const InexactVector_3 v = InexactVector_3(*sit) / std::sqrt(sit->squared_length());
+        // std::cout << "Length: " << (v.squared_length()-1) << std::endl;
+        dolfin_assert(dolfin::near(v.squared_length(), 1, DOLFIN_EPS_LARGE));
+        max_angle1 = std::max(max_angle1, std::abs(v*normal));
+        // max_distance_squared1 = std::max(max_distance_squared1,
+        avg_distance_squared1 += InexactVector_3(sit->source(), fitting_plane1.projection(sit->source())).squared_length();
+      }
+      avg_distance_squared1 /= segments.size();
+    }
+
+    /* double plane2fit; */
+    InexactPlane_3 fitting_plane2;
+    double max_angle2 = 0;
+    //double max_distance_squared2 = 0;
+    double avg_distance_squared2 = 0;
+    {
+      std::vector<InexactSegment_3> segments;
+      Halfedge_handle current = h2;
+      do
+      {
+        const Point_3& p = current->vertex()->point();
+        const Point_3& next = current->next()->vertex()->point();
+        segments.push_back(InexactSegment_3(InexactPoint_3(CGAL::to_double(p[0]), CGAL::to_double(p[1]), CGAL::to_double(p[2])),
+                                            InexactPoint_3(CGAL::to_double(next[0]), CGAL::to_double(next[1]), CGAL::to_double(next[2]))));
+        current = current->next();
+      } while (current != h1);
+
+      const Point_3& p = h1->vertex()->point();
+      const Point_3& next = h2->vertex()->point();
+
+      segments.push_back(InexactSegment_3(InexactPoint_3(CGAL::to_double(p[0]), CGAL::to_double(p[1]), CGAL::to_double(p[2])),
+                                          InexactPoint_3(CGAL::to_double(next[0]), CGAL::to_double(next[1]), CGAL::to_double(next[2]))));
+
+      dolfin_assert(segments.size() > 2);
+      // std::cout << "  Size: " << segments.size() << std::endl;
+
+      /* plane2fit = */ CGAL::linear_least_squares_fitting_3(segments.begin(),
+                                                             segments.end(),
+                                                             fitting_plane2,
+                                                             CGAL::Dimension_tag<1>());
+
+      // std::cout << "  Plane 1: " << fitting_plane1 << ", " << plane1fit << std::endl;
+
+      // Compute max angle between plane and segments
+      const InexactVector_3 normal = fitting_plane2.orthogonal_vector();
+      dolfin_assert(dolfin::near(normal.squared_length(), 1, DOLFIN_EPS_LARGE));
+      for (auto sit = segments.begin(); sit != segments.end(); sit++)
+      {
+        const InexactVector_3 v = InexactVector_3(*sit) / std::sqrt(sit->squared_length());
+        dolfin_assert(dolfin::near(v.squared_length(), 1, DOLFIN_EPS_LARGE));
+        max_angle2 = std::max(max_angle2, std::abs(v*normal));
+        /* max_distance_squared2 = std::max(max_distance_squared2, */
+        /*                                  InexactVector_3(sit->source(), fitting_plane2.projection(sit->source())).squared_length()); */
+        avg_distance_squared2 += InexactVector_3(sit->source(), fitting_plane2.projection(sit->source())).squared_length();
+      }
+      avg_distance_squared2 /= segments.size();
+    }
+
+    // const double cos_angle = fitting_plane1.orthogonal_vector()*fitting_plane2.orthogonal_vector();
+    // std::cout << "  Angle: " << cos_angle << "(" << acos(cos_angle)/(2*DOLFIN_PI)*360 << ")" << std::endl;
+    // std::cout << "Max angles: " << max_angle1 << "(" << acos(max_angle1)/(2*DOLFIN_PI)*360 << "), " << max_angle2 << " (" << acos(max_angle2)/(2*DOLFIN_PI)*360 << ")" << std::endl;
+    // return std::min(plane1fit, plane2fit); // - .04*cos_angle - .05*max_angle1 - .05*max_angle2;// + triangulation_extra;
+
+    //return (-avg_distance_squared1 - avg_distance_squared2)/std::max(max_angle1, max_angle2); ///std::min(plane1fit, plane2fit);
+    return -std::max(max_angle1, max_angle2);
+  }
+
+  //-----------------------------------------------------------------------------
+  // Compute the transformation that rotates a given vector (assumed to be of
+  // unit length) into (0,0,1)
+  template<typename Vector_3>
+  static CGAL::Aff_transformation_3<typename CGAL::Kernel_traits<Vector_3>::Kernel>
+    rotate_to_xy(Vector_3 a)
+  {
+    typedef typename CGAL::Kernel_traits<Vector_3>::Kernel::RT RT;
+    typedef typename CGAL::Aff_transformation_3<typename CGAL::Kernel_traits<Vector_3>::Kernel> Aff_transformation_3;
+
+    // Inner product of a and target vector (0,0,1)
+    const RT cos_theta = a[2];
+
+    // Cross product of a and target vector (0,0,1)
+    // const RT sine_theta = CGAL::sqrt(a[1]*a[1] + a[0]*a[0]);
+    const RT sine_theta = sqrt(CGAL::to_double(a[1]*a[1] + a[0]*a[0]));
+
+    const RT ux = a[1]/sine_theta;;
+    const RT uy = -a[0]/sine_theta;
+    const RT uz = 0;
+    dolfin_assert(CGAL::abs(ux*ux + uy*uy + uz*uz) - 1 < DOLFIN_EPS);
+
+    return Aff_transformation_3(
+      cos_theta+ux*ux*(1-cos_theta),     ux*uy*(1-cos_theta)-uz*sine_theta, ux*uz*(1-cos_theta)+uy*sine_theta,
+      uy*ux*(1-cos_theta)+uz*sine_theta, cos_theta+uy*uy*(1-cos_theta),     uy*uz*(1-cos_theta)-ux*sine_theta,
+      uz*ux*(1-cos_theta)-uy*sine_theta, uz*uy*(1-cos_theta)+ux*sine_theta, cos_theta+uz*uz*(1-cos_theta));
+  }
+  //-----------------------------------------------------------------------------
+  template <typename HDS, typename CDT>
+  class Add2DTriangulation : public CGAL::Modifier_base<HDS>
+  {
+  public:
+ Add2DTriangulation(const CDT& cdt,
+                    const typename HDS::Traits::Aff_transformation_3& from_xy,
+                    const typename CDT::Vertex_handle v0,
+                    const typename CDT::Vertex_handle v1,
+                    const typename HDS::Traits::Vector_3 displacement=typename HDS::Traits::Vector_3(CGAL::Null_vector()))
+   : cdt(cdt),
+      rotate_from_xy(from_xy),
+      displacement(displacement),
+      v0_2d(v0),
+      v1_2d(v1),
+      v0_initialized(false),
+      v1_initialized(false)
+    { }
+
+    void operator()(HDS& hds)
+    {
+      CGAL::Polyhedron_incremental_builder_3<HDS> builder(hds, true);
+
+      for (typename CDT::Finite_vertices_iterator cgal_vertex = cdt.finite_vertices_begin();
+           cgal_vertex != cdt.finite_vertices_end(); ++cgal_vertex)
+      {
+        cgal_vertex->info() = std::make_pair(typename HDS::Vertex_handle(),
+                                             std::numeric_limits<std::size_t>::max());
+      }
+
+      // Find the face incident to both v0 and v1
+      // We will use this to check the orientation of the faces when they are
+      // inserted into the 3D polyhedron
+      typename CDT::Face_handle f;
+
+      // Count valid cells and connected vertices
+      std::size_t num_cells = 0;
+      std::size_t num_vertices = 0;
+      for (typename CDT::Finite_faces_iterator cgal_cell = cdt.finite_faces_begin();
+           cgal_cell != cdt.finite_faces_end(); ++cgal_cell)
+      {
+        if (cgal_cell->is_in_domain())
+        {
+          num_cells++;
+
+          for (std::size_t i = 0; i < 3; i++)
+          {
+            typename CDT::Vertex_handle v = cgal_cell->vertex(i);
+            if (v->info().second == std::numeric_limits<std::size_t>::max())
+            {
+              v->info().second = num_vertices;
+              num_vertices++;
+            }
+          }
+
+          if (cgal_cell->has_vertex(v0_2d) && cgal_cell->has_vertex(v1_2d))
+          {
+            std::cout << "!!!! Found the face!!!" << std::endl;
+            std::cout << cgal_cell->index(v0_2d) << " " << cgal_cell->index(v1_2d) << std::endl;
+            f = cgal_cell;
+          }
+        }
+      }
+
+      // Check the orientation of the facets
+      const bool flip = ((f->index(v1_2d)+1)%3 == f->index(v0_2d));
+
+      const typename HDS::Traits::Vector_3 displacement_flipped = flip ? -displacement : displacement;
+
+      builder.begin_surface(num_vertices, num_cells);
+
+      std::cout << "Adding " << num_vertices << " vertices and " << num_cells << " cells" << std::endl;
+
+      // Add vertices
+      std::size_t vertex_index = 0;
+      for (typename CDT::Finite_vertices_iterator cgal_vertex = cdt.finite_vertices_begin();
+           cgal_vertex != cdt.finite_vertices_end(); ++cgal_vertex)
+      {
+        const typename CDT::Vertex_handle current = cgal_vertex;
+
+        // Transform point from xy plane to where it belongs in the polyhendron (2D point is EPICK)
+        typename HDS::Traits::Point_3 p = rotate_from_xy(typename HDS::Traits::Point_3(cgal_vertex->point()[0],
+                                                                                       cgal_vertex->point()[1],
+                                                                                       0))+displacement;
+
+        /* std::cout << "  2D point: " << cgal_vertex->point() << " (" << z << ")" << std::endl; */
+        /* std::cout << "  Rotated:  " << p << std::endl; */
+        /* std::cout << "  Index: " << vertex_index << std::endl; */
+// FRom remove-null-facets
+          /* // std::cout << "Now creating face" << std::endl; */
+
+          /* // This typedef for some reason gives a "unused local typedef" warning */
+          /* //from clang (...?) --> write out the typename in the statements */
+          /* //below. */
+          /* // typedef typename Halfedge::Base HBase; */
+          /* edges[0]->Halfedge::Base::set_next(edges[1]); */
+          /* decorator.set_prev(edges[1], edges[0]); */
+          /* edges[1]->Halfedge::Base::set_next(edges[2]); */
+          /* decorator.set_prev(edges[2], edges[1]); */
+          /* edges[2]->Halfedge::Base::set_next(edges[0]); */
+          /* decorator.set_prev(edges[0], edges[2]); */
+// end remove-null-facets
+
+        // Add vertex (convert point to EPECK)
+        typename HDS::Vertex_handle h = builder.add_vertex(p);
+        if (current == v0_2d)
+        {
+          v0 = h;
+          v0_initialized = true;
+        }
+        else if (current == v1_2d)
+        {
+          v1 = h;
+          v1_initialized = true;
+        }
+
+        // Attach index to vertex and increment
+        cgal_vertex->info().second = vertex_index++;
+      }
+
+      // Add cells to mesh and build domain marker mesh function
+      // std::size_t cell_index = 0;
+      for (typename CDT::Finite_faces_iterator cgal_cell = cdt.finite_faces_begin();
+           cgal_cell != cdt.finite_faces_end(); ++cgal_cell)
+      {
+        // Add cell if it is in the domain
+        if (cgal_cell->is_in_domain())
+        {
+          const typename CDT::Geom_traits::Triangle_2 t_2d(cgal_cell->vertex(0)->point(),
+                                                           cgal_cell->vertex(1)->point(),
+                                                           cgal_cell->vertex(2)->point());
+
+          // Transform point from xy plane to where it belongs in the polyhendron (2D point is EPICK)
+          typename HDS::Traits::Point_3 p0 = rotate_from_xy(typename HDS::Traits::Point_3(cgal_cell->vertex(0)->point()[0],
+                                                                                          cgal_cell->vertex(0)->point()[1],
+                                                                                          0));
+
+          typename HDS::Traits::Point_3 p1 = rotate_from_xy(typename HDS::Traits::Point_3(cgal_cell->vertex(1)->point()[0],
+                                                                                          cgal_cell->vertex(1)->point()[1],
+                                                                                          0));
+
+          typename HDS::Traits::Point_3 p2 = rotate_from_xy(typename HDS::Traits::Point_3(cgal_cell->vertex(2)->point()[0],
+                                                                                          cgal_cell->vertex(2)->point()[1],
+                                                                                          0));
+
+          typename HDS::Traits::Triangle_3 t_3d(p0, p1, p2);
+
+          const double diff = sqrt(CGAL::to_double(t_3d.squared_area()))-CGAL::to_double(CGAL::abs(t_2d.area()));
+          if (std::abs(diff) > 1e-10)
+            std::cout << "Rotated triangle differs: " << diff << std::endl;
+
+
+
+          builder.begin_facet();
+          builder.add_vertex_to_facet(cgal_cell->vertex(0)->info().second);
+          if (flip)
+          {
+            builder.add_vertex_to_facet(cgal_cell->vertex(2)->info().second);
+            builder.add_vertex_to_facet(cgal_cell->vertex(1)->info().second);
+            /* std::cout << "  Adding vertex: (" << cgal_cell->vertex(0)->info().second */
+            /*           << ", " << cgal_cell->vertex(2)->info().second */
+            /*           << ", " << cgal_cell->vertex(1)->info().second << std::endl; */
+          }
+          else
+          {
+            builder.add_vertex_to_facet(cgal_cell->vertex(1)->info().second);
+            builder.add_vertex_to_facet(cgal_cell->vertex(2)->info().second);
+            /* std::cout << "  Adding vertex: (" << cgal_cell->vertex(0)->info().second */
+            /*           << ", " << cgal_cell->vertex(1)->info().second */
+            /*           << ", " << cgal_cell->vertex(2)->info().second << std::endl; */
+
+          }
+          new_facets.insert(builder.end_facet());
+        }
+      }
+
+      builder.end_surface();
+
+      dolfin_assert(v0_initialized);
+      dolfin_assert(v1_initialized);
+    }
+    const CDT& cdt;
+    const typename HDS::Traits::Aff_transformation_3 rotate_from_xy;
+    const typename HDS::Traits::Vector_3 displacement;
+    const typename CDT::Vertex_handle v0_2d, v1_2d;
+    typename HDS::Vertex_handle v0, v1;
+    bool v0_initialized, v1_initialized;
+    std::set<typename HDS::Halfedge_handle> new_facets;
+  };
+
+  /// Attempts to triangulate a polygon in 3d by projecting vertices into the
+  /// best fitting plane and triangulating in 2d.
+  /// Return the new added edges.
+  /// If the triangulation is not possible (the boundary self intersects in this 2d plane) then
+  /// the return vector is empty
+  template <typename Polyhedron>
+  static bool triangulate_polygon_3d(Polyhedron& P,
+                                     const typename Polyhedron::Halfedge_handle h,
+                                     bool check_for_intersections = true,
+                                     bool refine = true)
+  {
+    typedef typename Polyhedron::Halfedge_handle Halfedge_handle;
+    typedef typename Polyhedron::Vertex_handle Vertex_handle;
+    // typedef typename Polyhedron::Facet_handle Facet_handle;
+    typedef typename Polyhedron::Traits::FT FT;
+    typedef typename Polyhedron::Traits::Point_3 Point_3;
+    typedef typename Polyhedron::Traits::Segment_3 Segment_3;
+    typedef typename Polyhedron::Traits::Vector_3 Vector_3;
+    typedef CGAL::Aff_transformation_3<typename Polyhedron::Traits> Aff_transformation_3;
+
+
+    typedef CGAL::Exact_predicates_inexact_constructions_kernel InexactKernel;
+    typedef typename InexactKernel::Plane_3 InexactPlane_3;
+    typedef typename InexactKernel::Point_3 InexactPoint_3;
+    typedef typename InexactKernel::Vector_3 InexactVector_3;
+    typedef typename InexactKernel::Point_2 InexactPoint_2;
+    // typedef typename InexactKernel::Segment_2 InexactSegment_2;
+    typedef typename InexactKernel::Segment_3 InexactSegment_3;
+    typedef typename InexactKernel::Triangle_2 InexactTriangle_2;
+
+    typedef CGAL::Triangulation_vertex_base_with_info_2<std::pair<Vertex_handle, std::size_t>, InexactKernel> Vb;
+    typedef CGAL::Delaunay_mesh_face_base_2<InexactKernel> Fb;
+    typedef CGAL::Triangulation_data_structure_2<Vb,Fb> TDS;
+    typedef CGAL::No_intersection_tag Itag;
+    typedef CGAL::Constrained_Delaunay_triangulation_2<InexactKernel, TDS, Itag> CDT;
+    typedef CGAL::Delaunay_mesh_size_criteria_2<CDT> Mesh_criteria_2;
+    typedef CGAL::Delaunay_mesher_no_edge_refinement_2<CDT, Mesh_criteria_2>  CGAL_Mesher_2;
+
+    std::cout << "Triangulating hole as 2d polygon" << std::endl;
+    dolfin_assert(P.is_valid());
+
+    {
+      std::cout << "Polygon ";
+      typename Polyhedron::Halfedge_handle current = h;
+      do
+      {
+        std::cout << current->vertex()->point() << ", ";
+        current = current->next();
+      } while (current != h);
+
+       std::cout << std::endl;
+    }
+
+    Aff_transformation_3 to_xy;
+    Vector_3 plane_normal;
+    {
+      // Compute the best fitting plane of the points of the hole
+      InexactPlane_3 fitting_plane;
+
+
+      std::vector<InexactSegment_3> boundary;
+      Halfedge_handle current = h;
+      do
+      {
+        const Point_3& p = current->vertex()->point();
+        const Point_3& next = current->next()->vertex()->point();
+        boundary.push_back(InexactSegment_3(InexactPoint_3(CGAL::to_double(p[0]), CGAL::to_double(p[1]), CGAL::to_double(p[2])),
+                                            InexactPoint_3(CGAL::to_double(next[0]), CGAL::to_double(next[1]), CGAL::to_double(next[2]))));
+
+        current = current->next();
+      } while (current != h);
+
+      /* const double fit_quality = */
+      CGAL::linear_least_squares_fitting_3(boundary.begin(),
+                                           boundary.end(),
+                                           fitting_plane,
+                                           CGAL::Dimension_tag<1>());
+
+      // Compute rotation that will rotate the fitting plane to the xy plane
+      const InexactVector_3 orthogonal = fitting_plane.orthogonal_vector();
+      const Vector_3 orthogonal_exact(orthogonal[0], orthogonal[1], orthogonal[2]);
+      // std::cout << "Orthogonal vector: " << orthogonal << ", " << orthogonal.squared_length() << std::endl;
+      const Aff_transformation_3 rotation = rotate_to_xy(orthogonal_exact);
+      // std::cout << "Rotation: " << rotation << std::endl;
+      std::cout << "Rotated: " << rotation.transform(orthogonal_exact) << std::endl;
+      const InexactPoint_3 point_on_plane = fitting_plane.point();
+      const FT z = rotation.transform(Point_3(point_on_plane[0],
+                                              point_on_plane[1],
+                                              point_on_plane[2]))[2];
+
+      const Aff_transformation_3 zero_z(CGAL::Translation(), Vector_3(0,0,-z));
+
+      double max_cos_normal_angle = 0;
+      const InexactVector_3 normal = fitting_plane.orthogonal_vector();
+      std::cout << "Normal: " << plane_normal << std::endl;
+      plane_normal = Vector_3(normal.x(), normal.y(), normal.z());
+
+      double max_squared_distance = 0;
+      dolfin_assert(dolfin::near(normal.squared_length(), 1, DOLFIN_EPS_LARGE));
+
+      // Compute 2D bounding box
+      std::vector<InexactPoint_2> points_2D;
+      for (const InexactSegment_3& s : boundary)
+      {
+        const Point_3 current_exact(s.source()[0], s.source()[1], s.source()[2]);
+        const Point_3 rotated = rotation.transform(current_exact);
+        points_2D.push_back(InexactPoint_2(CGAL::to_double(rotated[0]),
+                                           CGAL::to_double(rotated[1])));
+      }
+      CGAL::Bbox_2 bbox = CGAL::bbox_2(points_2D.begin(), points_2D.end());
+      std::cout << "Bounding box: " << bbox << std::endl;
+
+      // InexactVector_3 prev = InexactVector_3(boundary[boundary.size()-1]) / std::sqrt(boundary[boundary.size()-1].squared_length());
+      for (const InexactSegment_3& s : boundary)
+      {
+        InexactVector_3 current = InexactVector_3(s) / std::sqrt(s.squared_length());
+        max_squared_distance = std::max(max_squared_distance, (s.source()-fitting_plane.projection(s.source())).squared_length());
+
+        // std::cout << "Length: " << sit->squared_length() << ", " << current.squared_length() << ", " << (current*normal) << std::endl;
+        dolfin_assert(dolfin::near(current.squared_length(), 1, DOLFIN_EPS_LARGE));
+        max_cos_normal_angle = std::max(max_cos_normal_angle, CGAL::abs(current*normal));
+        // prev = current;
+
+        const Point_3 current_exact(s.source()[0], s.source()[1], s.source()[2]);
+        const Point_3 rotated = rotation.transform(current_exact);
+        // bbox += InexactPoint_2(CGAL::to_double(rotated[0]), CGAL::to_double(rotated[1])).bbox();
+        // std::cout << "  " << bbox << std::endl;
+      }
+
+      std::cout << "Max abs cos normal angle: " << max_cos_normal_angle << std::endl;
+      // std::cout << "Plane quality: " << fit_quality << std::endl;
+      std::cout << "Max distance: " << std::sqrt(max_squared_distance) << std::endl;
+
+      if (max_cos_normal_angle > .2)
+      {
+        std::cout << "ERROR: Rejecting 2d triangulating, max_cos_normal_angle: " << max_cos_normal_angle << std::endl;
+        return false;
+      }
+      if (max_squared_distance > 1e-8)
+      {
+        std::cout << "ERROR: Rejecting 2d triangulating, max squared_distance: " << max_squared_distance << std::endl;
+        return false;
+      }
+
+      const Aff_transformation_3 normalization(CGAL::Translation(), Vector_3(-(bbox.xmax()+bbox.xmin())/2,
+                                                                             -(bbox.ymax()+bbox.ymin())/2,
+                                                                             0));
+
+      to_xy = normalization*zero_z*rotation;
+    }
+
+
+    // std::cout << "Rotate normal: " << rotation.transform(fitting_plane.orthogonal_vector()) << std::endl;
+    // dolfin_assert(dolfin::near(fitting_plane.orthogonal_vector().squared_length(), 1, DOLFIN_EPS_LARGE));
+    double max_z = 0.;
+
+    CDT cdt;
+
+    std::cout << "Projected polygon" << std::endl;
+    std::cout << "Polygon";
+
+    // Insert vertices into 2D triangulation
+    std::vector<typename CDT::Vertex_handle> vertices;
+    double max_squared_edge_length = 0;
+    double min_squared_edge_length = std::numeric_limits<double>::max();
+
+    {
+      Halfedge_handle current = h;
+      Point_3 prev = current->prev()->vertex()->point();
+      std::stringstream ss;
+      ss << "Polygon ";
+      do
+      {
+
+        const Point_3& p = current->vertex()->point();
+        // InexactPoint_3 p_inexact(CGAL::to_double(p[0]),
+//                                  CGAL::to_double(p[1]),
+        //                               CGAL::to_double(p[2]));
+        // InexactPoint_3 p_projected = fitting_plane.projection(p_inexact);
+        // std::cout << " " << p_projected << ", ";
+
+        const double length_current = CGAL::to_double(Segment_3(prev, p).squared_length());
+        max_squared_edge_length = std::max(max_squared_edge_length, length_current);
+        min_squared_edge_length = std::min(min_squared_edge_length, length_current);
+        const Point_3 rotated = to_xy.transform(p);
+
+        max_z = std::max(max_z, CGAL::to_double(CGAL::abs(rotated.z())));
+        ss << " " << rotated << ", ";
+
+        const InexactPoint_2 p_2d(CGAL::to_double(rotated[0]), CGAL::to_double(rotated[1]));
+
+        // std::cout << " " << p_2d << ", ";
+
+        vertices.push_back(cdt.insert(p_2d));
+        vertices.back()->info().first = current->vertex();
+
+        prev = p;
+        current = current->next();
+      } while (current != h);
+
+      // std::cout << std::endl;
+      std::cout << std::endl;
+      std::cout << ss.str() << std::endl;
+    }
+
+    std::cout << "Size of points: " << vertices.size() << std::endl;
+    // std::cout << "z = " << z << std::endl;
+    std::cout << "Max z : " << max_z << std::endl;
+    std::cout << "Longest edge:  " << max_squared_edge_length << std::endl;
+    std::cout << "Shortest edge: " << min_squared_edge_length << std::endl;
+
+
+    // Check if any of the edges intersect (before actually adding the
+    // constrained edges to the triangulation)
+#if 0
+    if (check_for_intersections)
+    {
+      for (std::size_t i = 0; i < vertices.size()-1; i++)
+      {
+        const Point_3& a = vertices[i]->info().first->point(), b = vertices[+1]->info().first->point();
+        const InexactSegment_2 s(vertices[i]->point(), vertices[i+1]->point());
+        const Segment_3 original(a, b);
+
+        const InexactSegment_3 s2(fitting_plane.projection(InexactPoint_3(CGAL::to_double(a[0]),
+                                                                          CGAL::to_double(a[1]),
+                                                                          CGAL::to_double(a[2]))),
+                                  fitting_plane.projection(InexactPoint_3(CGAL::to_double(b[0]),
+                                                                          CGAL::to_double(b[1]),
+                                                                          CGAL::to_double(b[2]))));
+
+        for (std::size_t j = i+1; j < vertices.size(); j++)
+        {
+          InexactSegment_2 s2(vertices[j]->point(), vertices[(j+1)%vertices.size()]->point());
+
+          const auto intersection = CGAL::intersection(s, s2);
+
+          if (intersection)
+          {
+            if (boost::get<InexactPoint_2>(&*intersection))
+            {
+              if (j != i+1 && i != (j+1)%vertices.size())
+              {
+                std::cout << "Non-neighbors (" << i << ", " << j << ")/" << vertices.size()
+                          << " intersect in single point" << std::endl;
+
+                return false;
+              }
+            }
+            else if (boost::get<InexactSegment_2>(&*intersection))
+            {
+              std::cout << "Intersects in segment" << std::endl;
+              return false;
+            }
+            else
+            {
+              dolfin_assert(false);
+              return false;
+            }
+          } // end if intersection
+        } // end inner loop
+      } // end outer loop
+
+      // No edges intersect, so we can safely insert then as constraints to the
+      // triangulation
+    }
+#endif
+
+    // Insert the edges around the facet as constraints to the triangulation
+    for (std::size_t i = 0; i < vertices.size(); i++)
+    {
+      // std::cout << "Insert constraint: (" << i << ") " << vertices[i]->point() << ", (" << (i+1)%vertices.size() << ") " << vertices[(i+1)%vertices.size()]->point() << std::endl;
+      cdt.insert_constraint(vertices[i], vertices[(i+1)%vertices.size()]);
+    }
+
+    // std::cout << "Done triangulating" << std::endl;
+    // std::cout << "Num vertices: " << cdt.number_of_vertices() << std::endl;
+
+    if (refine)
+    {
+      // Create mesher
+      CGAL_Mesher_2 mesher(cdt);
+
+      // Set shape and size criteria
+      mesher.set_criteria(Mesh_criteria_2(.125, 2*std::sqrt(max_squared_edge_length)));
+
+      // No size criteria, only shape
+      //mesher.set_criteria(Mesh_criteria_2());
+
+      std::cout << "Max edge length: " << 2*std::sqrt(max_squared_edge_length) << std::endl;
+
+      // Refine CGAL mesh/triangulation
+      std::cout << "Refining 2D mesh" << std::endl;
+      mesher.refine_mesh();
+    }
+    else
+    {
+      for (auto f = cdt.finite_faces_begin(); f != cdt.finite_faces_end(); f++)
+      {
+        f->set_in_domain(true);
+      }
+    }
+
+    std::cout << "Done meshing. Num vertices: " << cdt.number_of_vertices() << std::endl;
+
+    {
+      double shortest_edge = std::numeric_limits<double>::max();
+      double smallest_triangle = std::numeric_limits<double>::max();
+      for (auto f = cdt.finite_faces_begin(); f != cdt.finite_faces_end(); f++)
+      {
+        if (f->is_in_domain())
+        {
+          for (int i = 0; i < 3; i++)
+            shortest_edge = std::min(shortest_edge,
+                                     CGAL::to_double((f->vertex(i)->point()-f->vertex((i+1)%3)->point()).squared_length()));
+          InexactTriangle_2 t(f->vertex(0)->point(),
+                              f->vertex(1)->point(),
+                              f->vertex(2)->point());
+          smallest_triangle = std::min(smallest_triangle, CGAL::to_double(CGAL::abs(t.area())));
+        }
+      }
+
+      std::cout << "Shortest edge in 2D triangulation: " << shortest_edge << std::endl;
+      std::cout << "Smallest triangle in 2D triangulation: " << smallest_triangle << std::endl;
+    }
+
+    //P.normalize_border();
+    // dolfin_assert(P.is_valid(false, 1));
+
+    // add the triangulation to the polyhedron
+
+    dump_2D_triangulation(cdt, "triangulation2D.off");
+
+    Add2DTriangulation<typename Polyhedron::HalfedgeDS, CDT> builder(cdt,
+                                                                     to_xy.inverse(),
+                                                                     vertices[0],
+                                                                     vertices[1],
+                                                                     plane_normal*.001);
+    P.delegate(builder);
+
+    std::cout << "Inserted: " << builder.new_facets.size() << " new facets" << std::endl;
+
+    // Find the border edge incident to "inserted h"
+    const typename Polyhedron::Halfedge_around_vertex_circulator start = builder.v0->vertex_begin();
+    typename Polyhedron::Halfedge_around_vertex_circulator current = start;
+
+    do
+    {
+      if (current->opposite()->vertex() == builder.v1)
+      {
+        std::cout << "Found the edge" << std::endl;
+        break;
+      }
+      std::cout << "Advancing" << std::endl;
+      current++;
+    } while (current != start);
+
+    const typename Polyhedron::Halfedge_handle h_new = current->is_border() ? current : current->opposite();
+
+    if (!h_new->is_border())
+    {
+      std::cout << "Is border edge: " << h_new->is_border_edge() << std::endl;
+      dolfin::dolfin_error("Polyhedron_utils.h",
+                           "Locating border edge",
+                           "locating border edge");
+    }
+
+    std::cout << "2D: " << vertices[0]->point() << std::endl;
+    std::cout << "Original: " << h->vertex()->point() << std::endl;
+    std::cout << "Original Next: " << h->next()->vertex()->point() << std::endl;
+    std::cout << "Original prev: " << h->prev()->vertex()->point() << std::endl;
+    std::cout << "Inserted: " << h_new->vertex()->point() << std::endl;
+    std::cout << "Inserted next: " << h_new->next()->vertex()->point() << std::endl;
+    std::cout << "Inserted prev: " << h_new->prev()->vertex()->point() << std::endl;
+    std::cout << "Vertex degree: " << h_new->vertex()->vertex_degree() << std::endl;
+
+
+    std::cout << "Joining loop" << std::endl;
+
+    {
+      Halfedge_handle a = h_new;
+      Halfedge_handle b = h;
+      double max_distance = 0.;
+      do
+      {
+        max_distance = std::max(max_distance, CGAL::to_double((a->vertex()->point()-b->vertex()->point()).squared_length()));
+
+        a = a->next();
+        b = b->prev();
+      } while (a != h_new);
+      std::cout << "Max distance between merged vertices: " << max_distance << std::endl;
+    }
+
+    {
+      double shortest_edge = std::numeric_limits<double>::max();
+      for (auto e = P.halfedges_begin(); e != P.halfedges_end(); e++)
+      {
+        shortest_edge = std::min(shortest_edge, CGAL::to_double((e->vertex()->point()-e->opposite()->vertex()->point()).squared_length()));
+      }
+
+      std::cout << "Shortest edge: " << shortest_edge << std::endl;
+    }
+
+    {
+      double smallest_triangle = std::numeric_limits<double>::max();;
+      for (auto f = P.facets_begin(); f != P.facets_end(); f++)
+      {
+        auto h = f->halfedge();
+        if (f->is_triangle())
+        {
+          typename Polyhedron::Traits::Triangle_3 t(h->vertex()->point(),
+                                                    h->next()->vertex()->point(),
+                                                    h->next()->next()->vertex()->point());
+          smallest_triangle = std::min(smallest_triangle,
+                                      CGAL::to_double(t.squared_area()));
+        }
+      }
+      std::cout << "Smallest triangle before join: " << smallest_triangle << std::endl;
+    }
+
+
+    //
+    P.join_loop(h, h_new);
+
+    {
+      double shortest_edge = std::numeric_limits<double>::max();
+      for (auto e = P.halfedges_begin(); e != P.halfedges_end(); e++)
+      {
+        shortest_edge = std::min(shortest_edge, CGAL::to_double((e->vertex()->point()-e->opposite()->vertex()->point()).squared_length()));
+      }
+
+      std::cout << "Shortest edge after merge: " << shortest_edge << std::endl;
+    }
+
+    {
+      double smallest_triangle = std::numeric_limits<double>::max();;
+      for (auto f = P.facets_begin(); f != P.facets_end(); f++)
+      {
+        auto h = f->halfedge();
+        if (f->is_triangle())
+        {
+          typename Polyhedron::Traits::Triangle_3 t(h->vertex()->point(),
+                                                    h->next()->vertex()->point(),
+                                                    h->next()->next()->vertex()->point());
+          smallest_triangle = std::min(smallest_triangle,
+                                      CGAL::to_double(t.squared_area()));
+        }
+      }
+      std::cout << "Smallest triangle: " << smallest_triangle << std::endl;
+    }
+
+
+
+    std::cout << "H degree: " << h->facet()->facet_degree() << std::endl;
+    std::cout << "Hole: " << (h->is_border_edge() ? "Yes" : "No") << std::endl;
+
+    return true;
+  }
+  //-----------------------------------------------------------------------------
+  template <typename Polyhedron>
+  static std::pair<double, double> evaluate_planarity(const typename Polyhedron::Halfedge_handle from,
+                                                      const typename Polyhedron::Halfedge_handle to)
+  {
+    typedef typename Polyhedron::Halfedge_handle Halfedge_handle;
+    typedef CGAL::Exact_predicates_inexact_constructions_kernel InexactKernel;
+    typedef typename InexactKernel::Plane_3 InexactPlane_3;
+    typedef typename InexactKernel::Segment_3 InexactSegment_3;
+    typedef typename InexactKernel::Vector_3 InexactVector_3;
+    typedef typename InexactKernel::Point_3 InexactPoint_3;
+    typedef typename Polyhedron::Traits::Point_3 Point_3;
+
+    std::vector<InexactSegment_3> segments;
+    Halfedge_handle current = from;
+    while (current != to)
+    {
+      const Point_3& s1 = current->vertex()->point();
+      const Point_3& s2 = current->next()->vertex()->point();
+      segments.push_back(InexactSegment_3(InexactPoint_3(CGAL::to_double(s1[0]),
+                                                         CGAL::to_double(s1[1]),
+                                                         CGAL::to_double(s1[2])),
+                                          InexactPoint_3(CGAL::to_double(s2[0]),
+                                                         CGAL::to_double(s2[1]),
+                                                         CGAL::to_double(s2[2]))));
+      current = current->next();
+    }
+
+    InexactPlane_3 fitting_plane;
+    CGAL::linear_least_squares_fitting_3(segments.begin(),
+                                         segments.end(),
+                                         fitting_plane,
+                                         CGAL::Dimension_tag<1>());
+
+    const InexactVector_3 orthogonal_vector = fitting_plane.orthogonal_vector()/sqrt(CGAL::to_double(fitting_plane.orthogonal_vector().squared_length()));
+
+    dolfin_assert(dolfin::near(orthogonal_vector.squared_length(), 1., DOLFIN_EPS_LARGE));
+
+    double max_distance = 0.;
+    double min_cos_angle = 1.;
+
+    current = from;;
+    while (current != to)
+    {
+      const Point_3& p1 = current->vertex()->point();
+      const InexactPoint_3 p1_inexact(CGAL::to_double(p1[0]),
+                                      CGAL::to_double(p1[1]),
+                                      CGAL::to_double(p1[2]));
+
+      const Point_3& next = current->next()->vertex()->point();
+      const InexactPoint_3 next_inexact(CGAL::to_double(next[0]),
+                                        CGAL::to_double(next[1]),
+                                        CGAL::to_double(next[2]));
+
+      const InexactVector_3 current_vector = (p1_inexact-next_inexact)/sqrt(CGAL::to_double((p1_inexact-next_inexact).squared_length()));
+      dolfin_assert(dolfin::near(current_vector.squared_length(), 1., DOLFIN_EPS_LARGE));
+
+      // Check if the angle between this vector and the fitting plane is acceptable
+      min_cos_angle = std::min(min_cos_angle,
+                               CGAL::abs(current_vector*orthogonal_vector));
+
+      max_distance = std::max(max_distance,
+                              sqrt((p1_inexact-fitting_plane.projection(p1_inexact)).squared_length()));
+
+      current = current->next();
+    }
+
+    return std::make_pair(max_distance, min_cos_angle);
+  }
+  //-----------------------------------------------------------------------------
+  template <typename Polyhedron>
+  static std::pair<typename Polyhedron::Halfedge_handle, typename Polyhedron::Halfedge_handle>
+  find_best_cut (Polyhedron& P,
+                 const typename Polyhedron::Halfedge_handle h,
+                 double cos_angle_tolerance)
+  {
+    typedef typename Polyhedron::Halfedge_handle Halfedge_handle;
+    typedef typename Polyhedron::Traits::Point_3 Point_3;
+    typedef CGAL::Exact_predicates_inexact_constructions_kernel InexactKernel;
+    typedef typename InexactKernel::Plane_3 InexactPlane_3;
+    typedef typename InexactKernel::Point_3 InexactPoint_3;
+    typedef typename InexactKernel::Vector_3 InexactVector_3;
+    typedef typename InexactKernel::Segment_3 InexactSegment_3;
+
+    Halfedge_handle h1_distance, h2_distance;
+    double min_distance = std::numeric_limits<double>::max();
+
+    Halfedge_handle h1_angle, h2_angle;
+    double min_cos_normal = std::numeric_limits<double>::max();
+
+    Halfedge_handle current1 = h->next()->next();
+    const Halfedge_handle current1_end = h->prev()->prev();
+    do
+    {
+      // std::cout << "Current1 " << current1->vertex()->point() << std::endl;
+      Halfedge_handle current2 = current1->next()->next();
+      const Halfedge_handle current2_end = current1->prev();
+      do
+      {
+        /* std::cout << "  Current 2" << std::endl; */
+        /* std::cout << "Segment " << current1->vertex()->point() << ", " << current2->vertex()->point() << std::endl; */
+
+        double max_distance_local = 0.;
+        double max_cos_normal_local = 0;
+
+        // Compute fitting plane of segments from current1 to current2
+        // std::cout << "Compute fit plane 1" << std::endl;
+        {
+          InexactPlane_3 fitting_plane;
+          std::vector<InexactSegment_3> segments;
+          Halfedge_handle current3 = current1;
+          while (current3 != current2)
+          {
+            const Point_3& s1 = current3->vertex()->point();
+            const Point_3& s2 = current3->next()->vertex()->point();
+            segments.push_back(InexactSegment_3(InexactPoint_3(CGAL::to_double(s1[0]),
+                                                               CGAL::to_double(s1[1]),
+                                                               CGAL::to_double(s1[2])),
+                                                InexactPoint_3(CGAL::to_double(s2[0]),
+                                                               CGAL::to_double(s2[1]),
+                                                               CGAL::to_double(s2[2]))));
+            current3 = current3->next();
+          }
+
+          /* const double fit_quality = */
+          CGAL::linear_least_squares_fitting_3(segments.begin(),
+                                               segments.end(),
+                                               fitting_plane,
+                                               CGAL::Dimension_tag<1>());
+          const InexactVector_3 orthogonal_vector = fitting_plane.orthogonal_vector()/sqrt(CGAL::to_double(fitting_plane.orthogonal_vector().squared_length()));
+
+          // std::cout << "Plane vector length: " << (CGAL::abs(orthogonal_vector.squared_length())-1) << std::endl;
+          dolfin_assert(dolfin::near(orthogonal_vector.squared_length(), 1., DOLFIN_EPS_LARGE));
+
+          current3 = current1;
+          while (current3 != current2)
+          {
+            const Point_3& p1 = current3->vertex()->point();
+            const InexactPoint_3 p1_inexact(CGAL::to_double(p1[0]),
+                                            CGAL::to_double(p1[1]),
+                                            CGAL::to_double(p1[2]));
+
+            const Point_3& next = current3->next()->vertex()->point();
+            const InexactPoint_3 next_inexact(CGAL::to_double(next[0]),
+                                              CGAL::to_double(next[1]),
+                                              CGAL::to_double(next[2]));
+
+            const InexactVector_3 current_vector = (p1_inexact-next_inexact)/sqrt(CGAL::to_double((p1_inexact-next_inexact).squared_length()));
+            dolfin_assert(dolfin::near(current_vector.squared_length(), 1., DOLFIN_EPS_LARGE));
+
+            // Check if angle between this vector and the fitting plane is acceptable
+            max_cos_normal_local = std::max(max_cos_normal_local, CGAL::abs(current_vector*orthogonal_vector));
+
+            max_distance_local = std::max(max_distance_local,
+                                          CGAL::to_double((p1_inexact-fitting_plane.projection(p1_inexact)).squared_length()));
+
+            current3 = current3->next();
+          }
+        }
+
+        // std::cout << "Done evaluating candidate: " << std::endl;
+
+        // Compute fitting plane of segments from current2 to current1
+        {
+          InexactPlane_3 fitting_plane;
+          std::vector<InexactSegment_3> segments;
+          Halfedge_handle current3 = current2;
+          while (current3 != current1)
+          {
+            const Point_3& s1 = current3->vertex()->point();
+            const Point_3& s2 = current3->next()->vertex()->point();
+            segments.push_back(InexactSegment_3(InexactPoint_3(CGAL::to_double(s1[0]),
+                                                               CGAL::to_double(s1[1]),
+                                                               CGAL::to_double(s1[2])),
+                                                InexactPoint_3(CGAL::to_double(s2[0]),
+                                                               CGAL::to_double(s2[1]),
+                                                               CGAL::to_double(s2[2]))));
+            current3 = current3->next();
+          }
+
+          /* const double fit_quality = */ CGAL::linear_least_squares_fitting_3(segments.begin(),
+                                                                          segments.end(),
+                                                                          fitting_plane,
+                                                                          CGAL::Dimension_tag<1>());
+
+          const InexactVector_3 orthogonal_vector = fitting_plane.orthogonal_vector()/sqrt(CGAL::to_double(fitting_plane.orthogonal_vector().squared_length()));
+          // const double angle_tolerance = .5;
+          // std::cout << "Plane vector length: " << (CGAL::abs(orthogonal_vector.squared_length())-1) << std::endl;
+          dolfin_assert(dolfin::near(CGAL::to_double(orthogonal_vector.squared_length()), 1., DOLFIN_EPS_LARGE));
+
+          current3 = current2;
+          while (current3 != current1)
+          {
+            const Point_3& p1 = current3->vertex()->point();
+            const InexactPoint_3 p1_inexact(CGAL::to_double(p1[0]),
+                                            CGAL::to_double(p1[1]),
+                                            CGAL::to_double(p1[2]));
+
+            const Point_3& next = current3->next()->vertex()->point();
+            const InexactPoint_3 next_inexact(CGAL::to_double(next[0]),
+                                              CGAL::to_double(next[1]),
+                                              CGAL::to_double(next[2]));
+
+            const InexactVector_3 current_vector = (p1_inexact-next_inexact)/sqrt(CGAL::to_double((p1_inexact-next_inexact).squared_length()));
+            dolfin_assert(dolfin::near(CGAL::to_double(current_vector.squared_length()), 1., DOLFIN_EPS_LARGE));
+
+            // Check if the angle between this vector and the fitting plane is acceptable
+            max_cos_normal_local = std::max(max_cos_normal_local, CGAL::abs(current_vector*orthogonal_vector));
+
+            max_distance_local = std::max(max_distance_local,
+                                          CGAL::to_double((p1_inexact-fitting_plane.projection(p1_inexact)).squared_length()));
+
+            current3 = current3->next();
+          }
+        }
+
+        // std::cout << "Done evaluating other half: " << std::endl;
+
+        if (max_distance_local < min_distance)
+        {
+          // std::cout << "New min split" << std::endl;
+          min_distance = max_distance_local;
+          h1_distance = current1;
+          h2_distance = current2;
+        }
+
+        if (max_cos_normal_local < min_cos_normal)
+        {
+          min_cos_normal = max_cos_normal_local;
+          h1_angle = current1;
+          h2_angle = current2;
+        }
+
+        current2 = current2->next();
+      } while (current2 != current2_end);
+
+      current1 = current1->next();
+    } while (current1 != current1_end);
+
+    std::cout << "Best cut, distance=" << min_distance << " : Segment " << h1_distance->vertex()->point() << ", " << h2_distance->vertex()->point() << std::endl;
+    std::cout << "Best cut, angle=" << min_cos_normal << " : Segment " << h1_angle->vertex()->point() << ", " << h2_angle->vertex()->point() << std::endl;
+
+
+    return std::make_pair(h1_angle, h2_angle);
+  }
+  //-----------------------------------------------------------------------------
+  template <typename Polyhedron>
+  static bool split_hole_planar(Polyhedron& P,
+                                typename Polyhedron::Halfedge_handle h)
+  {
+    typedef typename Polyhedron::Halfedge_handle Halfedge_handle;
+    typedef typename Polyhedron::Traits::Vector_3 Vector_3;
+
+    std::cout << "Split hole" << std::endl;
+
+    const std::pair<Halfedge_handle, Halfedge_handle> best_cut = find_best_cut(P, h, .3);
+
+    std::cout << "Found best cut" << std::endl;
+    if (best_cut.first == Halfedge_handle() || best_cut.second == Halfedge_handle())
+      return false;
+
+
+    const std::pair<double, double> planarity1 = evaluate_planarity<Polyhedron>(best_cut.first, best_cut.second);
+    const std::pair<double, double> planarity2 = evaluate_planarity<Polyhedron>(best_cut.second, best_cut.first);
+
+    std::cout << "Planarity: " << planarity1.first << " vs " << planarity2.first << std::endl;
+
+    const Halfedge_handle start = planarity1.first < planarity2.first ? best_cut.first : best_cut.second;
+    const Halfedge_handle end   = planarity1.first < planarity2.first ? best_cut.second : best_cut.first;
+
+    // Compute average edge length
+    double length = 0.;
+    int num_edges = 0;
+    Halfedge_handle current = best_cut.first;
+    do
+    {
+      length += sqrt(CGAL::to_double((current->vertex()->point()-current->next()->vertex()->point()).squared_length()));
+      num_edges++;
+    } while (current != best_cut.first);
+
+    length /= num_edges;
+
+    const Vector_3 cut = start->vertex()->point() - end->vertex()->point();
+    const double cut_length = sqrt(CGAL::to_double(cut.squared_length()));
+    const int num_new_edges = static_cast<int>(cut_length/length);
+
+    P.fill_hole(h);
+
+    Halfedge_handle new_diagonal = P.split_facet(end, start);
+    // Now new_diagonal is on the facet to be
+
+    std::cout << "Inserting " << num_new_edges << " vertices from " << start->vertex()->point() << " to " << end->vertex()->point() << std::endl;
+    for (int i = 1; i < num_new_edges; i++)
+    {
+      Halfedge_handle hnew = P.split_edge(new_diagonal);
+      hnew->vertex()->point() = end->vertex()->point() + cut*i/num_new_edges;
+      // std::cout << "  " << i << ": " << hnew->vertex()->point() << (hnew->vertex()->point()-hnew->opposite()->vertex()->point()).squared_length() << std::endl;
+    }
+
+    /* Halfedge_handle c = new_diagonal; */
+    /* do */
+    /* { */
+    /*   std::cout << "Edge: " << c->vertex()->point() << " <--> " << c->opposite()->vertex()->point() << " : " << (c->vertex()->point()-c->opposite()->vertex()->point()).squared_length() << std::endl; */
+    /*   c = c->next(); */
+    /* } while (c != new_diagonal); */
+
+
+    const Halfedge_handle opposite = new_diagonal->opposite();
+    P.make_hole(new_diagonal);
+    const bool success = triangulate_polygon_3d(P, new_diagonal);
+    //dolfin_assert(success);
+
+    P.make_hole(opposite);
+    if (!success)
+      return false;
+
+    return true;
+  }
+  //-----------------------------------------------------------------------------
+
+  /* template <typename Polyhedron> */
+  /* void min_vertex_degree(const Polyhedron& p) */
+  /* { */
+  /*   std::size_t min_degree = std::numeric_limits<std::size_t>::max(); */
+  /*   std::size_t min_degree_non_border = min_degree; */
+
+  /*   for (typename Polyhedron::Vertex_const_iterator vit = p.vertices_begin(); */
+  /*        vit != p.vertices_end(); vit++) */
+  /*   { */
+  /*     min_degree = std::min(min_degree, vit->vertex_degree); */
+
+  /*   } */
+
+  /*   std::cout << "Min vertex_degree: " << min_degree << std::endl; */
+  /* } */
+  //-----------------------------------------------------------------------------
+  template<typename Polyhedron>
+  static void list_hole(const typename Polyhedron::Halfedge_handle h)
+  {
+    std::size_t counter = 0;
+    std::cout << "Polygon";
+
+    {
+      typename Polyhedron::Halfedge_handle current = h;
+      do
+      {
+        counter++;
+        current = current->next();
+      } while(current != h);
+    }
+
+    // if (counter < 250)
+    // {
+      typename Polyhedron::Halfedge_handle current = h;
+      do
+      {
+        std::cout << " " << current->vertex()->point() << ",";
+
+        current = current->next();
+      } while(current != h);
+      // }
+      std::cout << std::endl;
+
+      // std::cout << " size: " << counter << std::endl;
+  }
+  //-----------------------------------------------------------------------------
+  template<typename Polyhedron>
+  static std::string print_triangle(typename Polyhedron::Halfedge_handle h)
+  {
+    std::stringstream ss;
+    ss << "Triangle "
+              << h->prev()->vertex()->point() << ", "
+              << h->vertex()->point() << ", "
+              << h->next()->vertex()->point() << std::endl;
+    ss << "Area: " << triangle_area<Polyhedron>(h) << std::endl;
+    return ss.str();
+  }
+  //-----------------------------------------------------------------------------
+  template<typename Polyhedron>
+  static double triangle_area(typename Polyhedron::Halfedge_handle h)
+  {
+    typedef typename Polyhedron::Traits::Triangle_3 Triangle_3;
+
+    Triangle_3 t(h->prev()->vertex()->point(),
+                 h->vertex()->point(),
+                 h->next()->vertex()->point());
+
+    return CGAL::to_double(t.squared_area());
+  }
+  //-----------------------------------------------------------------------------
+  template<typename Polyhedron>
+  static typename Polyhedron::Vertex_handle get_common_vertex(typename Polyhedron::Facet_handle f1,
+                                                              typename Polyhedron::Facet_handle f2)
+  {
+    typedef typename Polyhedron::Halfedge_handle Halfedge_handle;
+    typedef typename Polyhedron::Vertex_handle Vertex_handle;
+
+    // Find common vertex
+    Halfedge_handle h1 = f1->halfedge();
+    Halfedge_handle current1 = h1;
+    do
+    {
+      Halfedge_handle h2 = f2->halfedge();
+      Halfedge_handle current2 = h2;
+      do
+      {
+        if (current2->vertex() == current1->vertex())
+          return current2->vertex();
+
+        current2 = current2->next();
+      } while (h2 != current2);
+
+      current1 = current1->next();
+    } while (h1 != current1);
+
+    return Vertex_handle();
+  }
+  //-----------------------------------------------------------------------------
+  template <typename Polyhedron>
+  static double facet_angle(typename Polyhedron::Halfedge_handle h)
+  {
+    dolfin_assert(h->is_border());
+    dolfin_assert(h->next()->is_border());
+
+    typedef typename Polyhedron::Traits::Line_3 Line_3;
+    typedef typename Polyhedron::Traits::Vector_3 Vector_3;
+    typedef typename Polyhedron::Traits::Point_3 Point_3;
+
+    const Line_3 l(h->prev()->vertex()->point(),
+                   h->vertex()->point());
+
+    const Point_3& p11 = h->next()->vertex()->point();
+    const Point_3  p12 = l.projection(p11);
+    const Vector_3 v1(p12, p11);
+
+    dolfin_assert(h->opposite()->facet()->is_triangle());
+
+    const Point_3& p21 = h->opposite()->next()->vertex()->point();
+    const Point_3  p22 = l.projection(p21);
+    const Vector_3 v2(p22, p21);
+
+    return CGAL::to_double((v1*v2)/std::sqrt(CGAL::to_double(v1.squared_length()*v2.squared_length())));
+  }
+  //-----------------------------------------------------------------------------
+  template<typename Segment_3>
+  static bool segment_intersects_triangle(const Segment_3& s,
+                                          const typename CGAL::Kernel_traits<Segment_3>::Kernel::Triangle_3& t)
+  {
+    typedef typename CGAL::Kernel_traits<Segment_3>::Kernel::Point_3 Point_3;
+
+    auto result = CGAL::intersection(s, t);
+    if (!result)
+      return false;
+
+    if (const Point_3* p = boost::get<Point_3>(&*result))
+    {
+      if (*p == t[0] || *p == t[1] || *p == t[2])
+        return false;
+      else
+        return true;
+    }
+    else if (const Segment_3* s_ = boost::get<Segment_3>(&*result))
+    {
+      if ( (s.source() == t[0] || s.source() == t[1] || s.source() == t[2]) &&
+           (s.target() == t[0] || s.target() == t[1] || s.target() == t[2]) )
+        return false;
+      else
+        return true;
+    }
+
+    dolfin_assert(false);
+    return false;
+  }
+  //-----------------------------------------------------------------------------
+  // Check if two triangles intersect.
+  // Neighbor triangles (share a vertice or an edge) do not intersect
+  // if t1 == t2 (geometrically), the triangles do not intersect
+  template<typename Triangle_3>
+  static bool triangles_intersect(const Triangle_3& t1, const Triangle_3& t2)
+  {
+    typedef typename CGAL::Kernel_traits<Triangle_3>::Kernel::Point_3 Point_3;
+    typedef typename CGAL::Kernel_traits<Triangle_3>::Kernel::Segment_3 Segment_3;
+
+    if ( (t1[0] == t2[0] || t1[0] == t2[1] || t1[0] == t2[2]) &&
+         (t1[1] == t2[0] || t1[1] == t2[1] || t1[1] == t2[2]) &&
+         (t1[2] == t2[0] || t1[2] == t2[1] || t1[2] == t2[2]))
+      return false;
+
+    auto result = CGAL::intersection(t1, t2);
+
+    if (!result)
+      return false;
+
+    if (const Point_3* p = boost::get<Point_3>(&*result))
+    {
+      if (t1[0] == t2[0] || t1[0] == t2[1] || t1[0] == t2[2] ||
+          t1[1] == t2[0] || t1[1] == t2[1] || t1[1] == t2[2] ||
+          t1[2] == t2[0] || t1[2] == t2[1] || t1[2] == t2[2])
+        return false;
+      else
+        return true;
+    }
+    else if (const Segment_3* s = boost::get<Segment_3>(&*result))
+    {
+      std::size_t common_vertices = 0;
+      if (t1[0] == t2[0] || t1[0] == t2[1] || t1[0] == t2[2])
+        common_vertices++;
+
+      if (t1[1] == t2[0] || t1[1] == t2[1] || t1[1] == t2[2])
+        common_vertices++;
+
+      if (t1[2] == t2[0] || t1[2] == t2[1] || t1[2] == t2[2])
+        common_vertices++;
+
+      if (common_vertices > 1)
+        return false;
+      else
+        return true;
+    }
+    else if (const Triangle_3* t = boost::get<Triangle_3>(&*result))
+      return true;
+    else if (const std::vector<Point_3>* v = boost::get<std::vector<Point_3> >(&*result))
+      return true;
+
+    dolfin_assert(false);
+    return false;
+  }
+  //-----------------------------------------------------------------------------
+  template<typename Triangle_3>
+  static bool triangle_set_intersects(const std::vector<Triangle_3>& t)
+  {
+    for (std::size_t i = 0; i < t.size(); i++)
+    {
+      for (std::size_t j = i+1; j < t.size(); j++)
+      {
+        if (triangles_intersect<Triangle_3>(t[i], t[j]))
+          return true;
+      }
+    }
+    return false;
+  }
+  //-----------------------------------------------------------------------------
+  template<typename Halfedge_handle>
+  static std::size_t vertex_count_halfedges(Halfedge_handle h)
+  {
+    std::size_t count = 0;
+    Halfedge_handle current = h;
+    do
+    {
+      ++count;
+      current = current->next()->opposite();
+    } while (current != h);
+
+    dolfin_assert(count > 0);
+    return count;
+  }
+  //-----------------------------------------------------------------------------
+  template<typename Polyhedron>
+    static std::size_t total_vertex_count_halfedges(const Polyhedron& P, std::map<typename Polyhedron::Vertex_const_handle, std::size_t>& m)
+  {
+    std::size_t total_count = 0;
+    for (typename Polyhedron::Vertex_const_iterator it = P.vertices_begin(); it != P.vertices_end(); it++)
+    {
+      const std::size_t c = vertex_count_halfedges(it->halfedge());
+      m[it] = c;
+      // std::cout << " Halfedge count: " << c << std::endl;
+      if (c == 0)
+      {int tmp; std::cin >> tmp; }
+      total_count += c;
+    }
+    return total_count;
+  }
+  //-----------------------------------------------------------------------------
+  template<typename Polyhedron>
+  static bool halfedge_is_in_polyhedron(const Polyhedron& P,
+                                        typename Polyhedron::Halfedge_const_handle h)
+  {
+    for (auto hit = P.halfedges_begin(); hit != P.halfedges_end(); hit++)
+    {
+      if (hit == h)
+        return true;
+    }
+    return false;
+  }
+  //-----------------------------------------------------------------------------
+  template<typename Polyhedron>
+  static bool vertex_is_in_polyhedron(const Polyhedron& P,
+                                      typename Polyhedron::Vertex_const_handle v)
+  {
+    for (auto vit = P.vertices_begin(); vit != P.vertices_end(); ++vit)
+    {
+      if (vit == v)
+        return true;
+    }
+
+    return false;
+  }
+  //-----------------------------------------------------------------------------
+  template<typename Polyhedron>
+    static bool check_vertex_consistency(const Polyhedron& P)
+  {
+    // std::cout << "Checking vertex consistency" << std::endl;
+    std::size_t counter = 0;
+
+    // Build a set of the list of vertices for faster lookup
+    std::set<typename Polyhedron::Vertex_const_handle> vertex_set;
+    for (auto vit = P.vertices_begin(); vit != P.vertices_end(); ++vit)
+    {
+      dolfin_assert(vertex_set.count(vit) == 0);
+      vertex_set.insert(vit);
+    }
+
+    std::deque<typename Polyhedron::Halfedge_const_handle> queue;
+    std::set<typename Polyhedron::Halfedge_const_handle> visited;
+
+    queue.push_back(P.halfedges_begin());
+    while (!queue.empty())
+    {
+      typename Polyhedron::Halfedge_const_handle current = queue.back();
+      queue.pop_back();
+      if (visited.count(current) == 0)
+      {
+        counter++;
+        typename Polyhedron::Halfedge_const_handle start = current;
+        visited.insert(current);
+
+        // Walk around the facet (or hole). Check halfedges and queue opposites
+        do
+        {
+          if (vertex_set.count(current->vertex()) == 0)
+          {
+            // std::cout << "Vertex not in vertex list: " << current->vertex()->point() << std::endl;
+            return false;
+          }
+
+          // TODO: Add the opposite check: All vertices should be reachable via halfedges
+          queue.push_back(current->opposite());
+          current = current->next();
+        } while(current != start);
+      }
+    }
+
+    // std::cout << "  Checked " << counter << " halfedges" << std::endl;
+    return true;
+  }
+  //-----------------------------------------------------------------------------
+  template<typename Triangle_3>
+  static bool triangle_set_intersect_triangle(Triangle_3 t,
+                                              const std::vector<Triangle_3>& triangle_set)
+  {
+    for (auto tit = triangle_set.begin(); tit != triangle_set.end(); tit++)
+    {
+      if (triangles_intersect(*tit, t))
+        return true;
+    }
+    return false;
+  }
+  //-----------------------------------------------------------------------------
+  template<typename Segment_3>
+    static bool segment_intersects_triangle_set(const Segment_3& s,
+                                                const std::vector<typename CGAL::Kernel_traits<Segment_3>::Kernel::Triangle_3>& triangle_set)
+  {
+    for (auto tit = triangle_set.begin(); tit != triangle_set.end(); tit++)
+    {
+      if (segment_intersects_triangle(s, *tit))
+        return true;
+    }
+    return false;
+  }
+  //-----------------------------------------------------------------------------
+  template<typename Polyhedron>
+  static bool center_vertex_triangulation(Polyhedron& P,
+                                          const typename Polyhedron::Halfedge_handle h)
+  {
+    typedef typename Polyhedron::Traits::Point_3 Point_3;
+    typedef typename Polyhedron::Traits::Triangle_3 Triangle_3;
+    typedef typename Polyhedron::Halfedge_handle Halfedge_handle;
+
+    // check if the triangulation with a center vertex intersects any of the
+    // neighbor triangles
+    // std::cout << "Attempting center vertex triangulation" << std::endl;
+    dolfin_assert(P.is_valid(false, 0));
+    dolfin_assert(halfedge_is_in_polyhedron(P, h));
+    dolfin_assert(vertex_is_in_polyhedron(P, h->vertex()));
+
+    const std::array<double, 3> plane_fit = get_plane_fit<Polyhedron>(h, h->prev());
+    if (plane_fit[0] < .85)
+    {
+      // std::cout << "  Rejected. Not sufficiently planar: " << plane_fit[0] << std::endl;
+      return false;
+    }
+
+    // Collect set of neighbor triangles and compute centroid
+    std::vector<Triangle_3> triangles;
+    Point_3 centroid = CGAL::ORIGIN;
+    std::size_t counter = 0;
+    {
+      Halfedge_handle current = h;
+      do
+      {
+        if (!current->opposite()->is_border() && current->opposite()->facet()->facet_degree() == 3)
+        {
+          triangles.push_back(get_facet_triangle<Polyhedron>(current->opposite()));
+        }
+        centroid = centroid + (current->vertex()->point()-CGAL::ORIGIN);
+        counter++;
+
+        current = current->next();
+      } while (current != h);
+    }
+    // std::cout << "Number of triangles: " << triangles.size() << std::endl;
+    centroid = CGAL::ORIGIN + (centroid-CGAL::ORIGIN)/counter;
+    // std::cout << "Centroid: " << centroid << std::endl;
+
+    Halfedge_handle current = h;
+    do
+    {
+      Triangle_3 current_triangle(current->vertex()->point(), current->next()->vertex()->point(), centroid);
+      for (auto tit = triangles.begin(); tit != triangles.end(); tit++)
+      {
+        if (triangles_intersect(current_triangle, *tit))
+        {
+          // std::cout << "No: Triangle " << current_triangle[0] << " " << current_triangle[1] << " " << current_triangle[2] << std::endl;
+          // std::cout << "Triangle " << (*tit)[0] << " " << (*tit)[1] << " " << (*tit)[2] << std::endl;
+          return false;
+        }
+      }
+
+      triangles.push_back(current_triangle);
+
+      current = current->next();
+    } while (current != h);
+
+    // std::cout << "Facet degree before center vertex: " << h->facet()->facet_degree() << std::endl;
+
+    P.normalize_border();
+    dolfin_assert(P.is_valid(false, 1));
+    dolfin_assert(!h->is_border_edge());
+    dolfin_assert(h->facet()->facet_degree() > 3);
+
+    Halfedge_handle center = P.create_center_vertex(h);
+    /* Halfedge_handle g = h->next()->next(); */
+    /* dolfin_assert(check_vertex_consistency(P)); */
+    /* dolfin_assert(halfedge_is_in_polyhedron(P, h)); */
+    /* dolfin_assert(vertex_is_in_polyhedron(P, h->vertex())); */
+    /* dolfin_assert(vertex_is_in_polyhedron(P, g->vertex())); */
+    /* std::cout << "Splitting: Segment " << h->vertex()->point() << ", " << g->vertex()->point() << std::endl; */
+    /* std::cout << "Vertex degrees: " << h->vertex()->vertex_degree() << ", " << g->vertex()->vertex_degree() << std::endl; */
+    /* std::cout << "My count: " << vertex_count_halfedges(h) << ", " << vertex_count_halfedges(g) << std::endl; */
+
+    /* std::cout << "Facet degree: " << h->facet()->facet_degree() << std::endl; */
+    /* std::cout << "Opposite facet degree: " << h->opposite()->facet()->facet_degree() << std::endl; */
+    /* std::cout << "Num halfedges: " << P.size_of_halfedges() << std::endl; */
+    /* std::map<typename Polyhedron::Vertex_const_handle, std::size_t> vertex_degrees; */
+    /* std::cout << "My total count: " << total_vertex_count_halfedges(P, vertex_degrees); */
+    /* std::cout << "Mapped: " << vertex_degrees.at(h->vertex()) << ", " << vertex_degrees.at(g->vertex()) << std::endl; */
+    /* std::cout << "Size of map: " << vertex_degrees.size() << std::endl; */
+    /* std::cout << "-- Splitting facet --" << std::endl; */
+
+    /* Halfedge_handle diagonal = P.split_facet(h, g); */
+
+    /* std::cout << "Vertex degrees: " << h->vertex()->vertex_degree() << ", " << g->vertex()->vertex_degree() << std::endl; */
+    /* std::cout << "My count: " << vertex_count_halfedges(h) << ", " << vertex_count_halfedges(g) << std::endl; */
+    /* std::map<typename Polyhedron::Vertex_const_handle, std::size_t> vertex_degrees_after; */
+    /* std::cout << "My total count: " << total_vertex_count_halfedges(P, vertex_degrees_after) << std::endl; */
+    /* std::cout << "Size of map: " << vertex_degrees_after.size() << std::endl; */
+    /* std::cout << "Num halfedges: " << P.size_of_halfedges() << std::endl; */
+    /* std::cout << "Mapped: " << vertex_degrees_after.at(h->vertex()) << ", " << vertex_degrees_after.at(g->vertex()) << std::endl; */
+    /* for (auto it = vertex_degrees_after.begin(); it != vertex_degrees_after.end(); ++it) */
+    /* { */
+    /*   if (vertex_degrees.at(it->first) != it->second) */
+    /*   { */
+    /*     std::cout << "DIFF!!!" << vertex_degrees[it->first] << " " << it->second << std::endl; */
+    /*   } */
+
+    /*   if (vertex_degrees.at(it->first) == 0 || it->second == 0) */
+    /*   { */
+    /*     std::cout << "zero degree " << it->first->point() << std::endl; */
+    /*   } */
+    /* } */
+    /* dolfin_assert(P.is_valid(false)); */
+    /* Halfedge_handle c = diagonal->vertex()->halfedge(); */
+    /* Halfedge_handle start = c; */
+    /* do */
+    /* { */
+    /*   if (c->opposite()->vertex() == diagonal->opposite()->vertex()) */
+    /*     std::cout << "Yes!!!" << std::endl; */
+    /*   c = c->opposite()->next(); */
+    /* } while (c != start); */
+    /* dolfin_assert(P.is_valid(false, 0)); */
+    /* std::cout << "Splitting edge: Segment " << diagonal->opposite()->vertex()->point() << ", " << diagonal->vertex()->point() << std::endl; */
+    /* Halfedge_handle center = P.split_edge(diagonal); */
+    center->vertex()->point() = centroid;
+    dolfin_assert(P.is_valid(false, 0));
+
+    /* std::cout << "Splitting facet: " << diagonal->opposite()->vertex()->point() << ", " << diagonal->opposite()->prev()->prev()->vertex()->point() << std::endl; */
+    /* P.split_facet(diagonal->opposite(), diagonal->opposite()->prev()->prev()); */
+
+    /* do */
+    /* { */
+    /*   dolfin_assert(P.is_valid(false, 0)); */
+    /*   std::cout << "adding diagonal: " << diagonal->next()->vertex()->point() << ", " << center->vertex()->point() << std::endl; */
+    /*   diagonal = P.split_facet(diagonal->next(), center); */
+    /*   diagonal = diagonal->opposite(); */
+
+    /* } while (diagonal->next()->next() != center); */
+    /* std::cout << "Center vertex degree: " << center->vertex()->vertex_degree() << std::endl; */
+    /* //P.normalize_border(); */
+    /* { */
+    /*   std::ofstream ofile("center-vertex.off"); */
+    /*   ofile << P; */
+    /* } */
+
+    /* dolfin_assert(P.is_valid()); */
+
+    return true;
+  }
+  //-----------------------------------------------------------------------------
+  template<typename Polyhedron>
+  static void close_hole(Polyhedron& P,
+                         typename Polyhedron::Halfedge_handle h)
+  {
+    //typedef typename Polyhedron::Traits::Point_3 Point_3;
+    typedef typename Polyhedron::Halfedge_handle Halfedge_handle;
+
+    dolfin_assert(P.is_valid(false, 0));
+    dolfin_assert(P.is_pure_triangle());
+    dolfin_assert(h->is_border());
+
+    P.fill_hole(h);
+    P.normalize_border();
+
+    dolfin_assert(h->facet()->facet_degree() > 2);
+
+    // Since the facet may be split, we push the facets to a fifo queue.
+    // Neighbor facets are now not guaranteed to be triangles.
+    std::deque<Halfedge_handle> queue;
+    queue.push_back(h);
+
+    while (!queue.empty())
+    {
+      // std::cout << "--- Popping facet from queue (" << queue.size() << ")" << std::endl;
+      const Halfedge_handle current = queue.front();
+      queue.pop_front();
+
+      // list_hole<Polyhedron>(current);
+
+      dolfin_assert(P.is_valid(false, 0));
+      dolfin_assert(halfedge_is_in_polyhedron(P, current));
+
+      if (current->facet()->facet_degree() == 3)
+      {
+        //P.fill_hole(h);
+        dolfin_assert(current->opposite()->facet()->facet_degree() != 3  ||
+                      !triangles_intersect(get_facet_triangle<Polyhedron>(current),
+                                           get_facet_triangle<Polyhedron>(current->opposite())));
+        dolfin_assert(current->next()->opposite()->facet()->facet_degree() != 3  ||
+                      !triangles_intersect(get_facet_triangle<Polyhedron>(current),
+                                           get_facet_triangle<Polyhedron>(current->next()->opposite())));
+        dolfin_assert(current->prev()->opposite()->facet()->facet_degree() != 3  ||
+                      !triangles_intersect(get_facet_triangle<Polyhedron>(current),
+                                           get_facet_triangle<Polyhedron>(current->prev()->opposite())));
+      }
+      else
+      {
+        // std::cout << "Attempting to triangulate in 2D" << std::endl;
+        dolfin_assert(halfedge_is_in_polyhedron(P, current));
+        if (!triangulate_polygon_3d(P, current, false))
+        {
+          dolfin_assert(halfedge_is_in_polyhedron(P, current));
+
+          Halfedge_handle facet = subdivide_facet(P, current);
+
+          queue.push_back(facet->opposite());
+          queue.push_back(facet);
+        }
+      }
+    }
+  }
+  //-----------------------------------------------------------------------------
+  template<typename Polyhedron>
+  static typename Polyhedron::Halfedge_handle
+  subdivide_facet(Polyhedron& P, typename Polyhedron::Halfedge_handle h)
+  {
+    typedef typename Polyhedron::Halfedge_handle Halfedge_handle;
+    typedef typename Polyhedron::Traits::Triangle_3 Triangle_3;
+    typedef typename Polyhedron::Traits::Point_3 Point_3;
+    typedef typename Polyhedron::Traits::Segment_3 Segment_3;
+    typedef typename Polyhedron::Traits::Vector_3 Vector_3;
+
+    // Search for segments that divide the hole, such that the dividing segment
+    // does not intersect triangles next to the hole and the facets on each side
+    // of the split is as planar as possible.
+
+    // Store all triangles around the hole and compute max edge length
+    std::vector<Triangle_3> border_triangles;
+    double max_squared_edge_length = 0;
+    {
+      Halfedge_handle current = h;
+      do
+      {
+        max_squared_edge_length = std::max(max_squared_edge_length,
+                                           CGAL::to_double(Segment_3(current->prev()->vertex()->point(),
+                                                                     current->vertex()->point()).squared_length()));
+        if (current->opposite()->facet()->facet_degree() == 3)
+        {
+          border_triangles.push_back(get_facet_triangle<Polyhedron>(current->opposite()));
+        }
+
+        current = current->next();
+      } while (current != h);
+    }
+
+    dolfin_assert(border_triangles.size() > 4);
+
+    // Search for the best dividing segment
+    double best_quality = -1000;
+    Halfedge_handle best_outer;
+    Halfedge_handle best_inner;
+
+    Halfedge_handle current_outer = h;
+
+    // FIXME: This loop should run to h->prev()->prev(), but need
+    // handle the specially
+    const Halfedge_handle outer_end = h->prev()->prev();
+    do
+    {
+      Halfedge_handle current_inner = current_outer->next()->next();
+      const Halfedge_handle inner_end = h;
+      do
+      {
+        if (current_inner->next() != current_outer &&
+            current_inner->prev() != current_outer)
+        {
+
+          Segment_3 current_segment(current_outer->vertex()->point(),
+                                    current_inner->vertex()->point());
+
+          // Check that this does not introduce an intersection
+          if (!segment_intersects_triangle_set(current_segment, border_triangles))
+          {
+            const double candidate_quality = evaluate_hole_subdivision<Polyhedron>(current_inner, current_outer);
+
+            if (candidate_quality > best_quality)
+            {
+              best_outer = current_outer;
+              best_inner = current_inner;
+              best_quality = candidate_quality;
+            }
+          }
+        }
+
+        current_inner = current_inner->next();
+      } while (current_inner != inner_end);
+
+      current_outer = current_outer->next();
+    } while (current_outer != outer_end);
+
+    dolfin_assert(best_outer != Halfedge_handle());
+    dolfin_assert(best_inner != Halfedge_handle());
+
+    // std::cout << "Found best subdivision: " << std::endl;
+
+    // list_hole<Polyhedron>(best_outer);
+    // std::cout << "Segment " << best_outer->vertex()->point()
+    //           << ", " << best_inner->vertex()->point() << std::endl;
+    // std::cout << "Quality: " << best_quality << std::endl;
+
+    dolfin_assert(P.is_valid(false, 0));
+    const Halfedge_handle new_diagonal = P.split_facet(best_inner, best_outer);
+    const Point_3& p = new_diagonal->opposite()->vertex()->point();
+
+    const Vector_3 new_edge(new_diagonal->opposite()->vertex()->point(),
+                            new_diagonal->vertex()->point());
+
+    const int num_segments = static_cast<int>(sqrt(CGAL::to_double(new_edge.squared_length())/max_squared_edge_length)+.5);
+
+    // Note: Don't use std::size_t as 0-1 becomes very large...
+    for (int i = 1; i < num_segments; i++)
+    {
+      //std::cout << "Splitting segment" << std::endl;
+      Halfedge_handle new_segment = P.split_edge(new_diagonal);
+      new_segment->vertex()->point() = p + static_cast<double>(i)/num_segments * new_edge;
+    }
+
+    P.normalize_border();
+    dolfin_assert(P.is_valid(false, 0));
+
+    return new_diagonal;
+  }
+  //-----------------------------------------------------------------------------
+  /* template<typename Polyhedron> */
+  /* static double evaluate_heuristic(const Polyhedron& P, */
+  /*                                  typename Polyhedron::Halfedge_handle h, */
+  /*                                  double plane_fit) */
+  /* { */
+  /*   typedef typename Polyhedron::Traits::Triangle_3 Triangle_3; */
+  /*   typedef typename Polyhedron::Traits::Vector_3 Vector_3; */
+  /*   typedef CGAL::Exact_predicates_inexact_constructions_kernel InexactKernel; */
+  /*   typedef typename InexactKernel::Plane_3 InexactPlane_3; */
+
+
+  /*   // const double distance_to_plane_weight = 1.0; */
+  /*   const double planarity_weight = 1.0; */
+  /*   const double dihedral_weight  = 1.0; */
+  /*   const double ear_angle_weight = 1.0; */
+
+  /*   // Compute the planarity of the points excluding the current point */
+  /*   InexactPlane_3 p; */
+  /*   const double plane_fit_quality = get_plane_fit<Polyhedron>(h->next(), */
+  /*                                                              h->prev(), */
+  /*                                                              &p); */
+  /*   // Compute the maximum of the dihedral angle to the neighbors */
+  /*   const Triangle_3 candidate_triangle(h->prev()->vertex()->point(), */
+  /*                                       h->vertex()->point(), */
+  /*                                       h->next()->vertex()->point()); */
+  /*   const double cos_dihedral = (std::min(get_triangle_cos_angle(candidate_triangle, */
+  /*                                                                get_facet_triangle<Polyhedron>(h->opposite())), */
+  /*                                         get_triangle_cos_angle(candidate_triangle, */
+  /*                                                                get_facet_triangle<Polyhedron>(h->next()->opposite())))+1)/2; */
+
+  /*   // Compute the angle of the cutted ear */
+  /*   const Vector_3 v1(h->vertex()->point(), */
+  /*                     h->prev()->vertex()->point()); */
+  /*   const Vector_3 v2(h->vertex()->point(), */
+  /*                     h->next()->vertex()->point()); */
+
+  /*   const double cos_ear_angle = (CGAL::to_double((v1*v2)/std::sqrt(CGAL::to_double(v1.squared_length()*v2.squared_length())))+1)/2.0; */
+  /*   const double ear_angle_quality = cos_ear_angle; */
+
+  /*   std::cout << "Triangle " << candidate_triangle[0] */
+  /*             << ", " << candidate_triangle[1]  */
+  /*             << "," << candidate_triangle[2] << std::endl; */
+
+  /*   std::cout << "Evaluate: planarity: " << (plane_fit_quality/plane_fit) */
+  /*             << ", dihedral: " << cos_dihedral */
+  /*             << ", ear angle: " << ear_angle_quality << std::endl; */
+
+  /*   return planarity_weight*plane_fit_quality + dihedral_weight*cos_dihedral + ear_angle_quality*ear_angle_weight; */
+
+  /*   /\* return planarity_weight*plane_fit_quality/plane_fit + *\/ */
+  /*   /\*   dihedral_weight*cos_dihedral + *\/ */
+  /*   /\*   (1-std::exp(-ear_angle_weight*cos_ear_angle))*cos_dihedral; *\/ */
+  /* } */
+  //-----------------------------------------------------------------------------
+  template<typename Polyhedron>
+  static bool vertex_is_border(typename Polyhedron::Vertex_const_handle v)
+  {
+    //typename Polyhedron::Vertex::Halfedge_around_vertex_circulator h_start = v->vertex_begin();
+    auto h_start = v->vertex_begin();
+    auto h_current = h_start;
+    do
+    {
+      if (h_current->is_border_edge())
+        return true;
+      h_current++;
+    } while(h_current != h_start);
+
+    return false;
+  }
+  //-----------------------------------------------------------------------------
+  template<typename Polyhedron>
+  static bool facets_are_neighbors(typename Polyhedron::Facet_handle f1,
+                                   typename Polyhedron::Facet_handle f2)
+  {
+    typename Polyhedron::Halfedge_handle h1 = f1->halfedge();
+    typename Polyhedron::Halfedge_handle start1 = h1;
+    do
+    {
+      typename Polyhedron::Halfedge_handle h2 = f2->halfedge();
+      typename Polyhedron::Halfedge_handle start2 = h2;
+      do
+      {
+        if (h2->vertex() == h1->vertex())
+          return true;
+
+        h2 = h2->next();
+      } while (h2 != start2);
+
+      h1 = h1->next();
+    } while (h1 != start1);
+
+    return false;
+  }
+  //-----------------------------------------------------------------------------
+  template<typename Polyhedron>
+  static bool segment_intersects_facets(typename Polyhedron::Vertex_handle v1,
+                                        typename Polyhedron::Vertex_handle v2)
+  {
+    typedef typename Polyhedron::Halfedge_around_vertex_circulator Vertex_circulator;
+    typedef typename Polyhedron::Traits::Segment_3 Segment_3;
+    typedef typename Polyhedron::Traits::Triangle_3 Triangle_3;
+        typedef typename Polyhedron::Traits::Point_3 Point_3;
+
+    Segment_3 s(v1->point(), v2->point());
+
+    Vertex_circulator start = v1->vertex_begin();
+    Vertex_circulator current = start;
+    do
+    {
+      if (!current->is_border() && current->facet()->is_triangle())
+      {
+        Triangle_3 t = get_facet_triangle<Polyhedron>(current);
+        auto result = CGAL::intersection(t, s);
+        dolfin_assert(result);
+
+        if (const Point_3* p = boost::get<Point_3>(&*result))
+        {
+          dolfin_assert(*p == s.source() || *p == s.target());
+        }
+        else if (const Segment_3* s = boost::get<Segment_3>(&*result))
+        {
+          return true;
+        }
+        else
+        {
+          dolfin_assert(false);
+        }
+      }
+
+      current++;
+    } while (start != current);
+
+    return false;
+  }
+  //-----------------------------------------------------------------------------
+  template<typename Polyhedron>
+  static std::string list_self_intersections(Polyhedron& p)
+  {
+    typedef typename Polyhedron::Facet_handle Facet_handle;
+    typedef typename Polyhedron::Halfedge_handle Halfedge_handle;
+    typedef typename Polyhedron::Traits Polyhedron_traits;
+    typedef typename Polyhedron_traits::Triangle_3 Triangle_3;
+    typedef typename Polyhedron_traits::Point_3 Point_3;
+    typedef typename Polyhedron_traits::Segment_3 Segment_3;
+
+    std::stringstream ss;
+
+    std::vector<std::pair<Facet_handle, Facet_handle> > intersections;
+    CGAL::Polygon_mesh_processing::self_intersections(p, std::back_inserter(intersections));
+
+    for (const std::pair<Facet_handle, Facet_handle>& iit : intersections)
+    {
+      ss << "Intersection (neighbors: " << (facets_are_neighbors<Polyhedron>(iit.first, iit.second) ? "Yes" : "No") << ")" << std::endl;
+      const Halfedge_handle h1 = iit.first->halfedge();
+      const Halfedge_handle h2 = iit.second->halfedge();
+      print_triangle<Polyhedron>(h1);
+      print_triangle<Polyhedron>(h2);
+
+      // Compute intersection
+
+      const Triangle_3 t1(h1->vertex()->point(),
+                          h1->next()->vertex()->point(),
+                          h1->next()->next()->vertex()->point());
+
+      const Triangle_3 t2(h2->vertex()->point(),
+                          h2->next()->vertex()->point(),
+                          h2->next()->next()->vertex()->point());
+
+      const auto result = CGAL::intersection(t1, t2);
+
+      dolfin_assert(result);
+      if (const Segment_3* s = boost::get<Segment_3>(&*result))
+      {
+        ss << "Segment: " << *s << std::endl;
+      }
+      else if (const Point_3* p = boost::get<Point_3>(&*result))
+      {
+        ss << "Point: " << *p << std::endl;
+      }
+      else if (const Triangle_3* t = boost::get<Triangle_3>(&*result))
+      {
+        ss << "Triangle: " << *t << std::endl;
+      }
+      else
+      {
+        ss << "Polygon" << std::endl;
+      }
+    }
+
+    return ss.str();
+  }
+  //-----------------------------------------------------------------------------
+  template<typename Polyhedron>
+  static double closest_vertices(const Polyhedron& p)
+  {
+    // TODO: Use a better optimal algorithm for closest pair problem
+    std::cout << "Computing closest vertices" << std::endl;
+    double min_distance = std::numeric_limits<double>::max();
+
+    std::size_t counter = 0;
+    std::cout << "Vertices: " << p.size_of_vertices() << std::endl;
+    for (typename Polyhedron::Vertex_const_iterator v1 = p.vertices_begin();
+         v1 != p.vertices_end(); v1++)
+    {
+      if (counter % 1000 == 0)
+        std::cout << counter << std::endl;
+
+      typename Polyhedron::Vertex_const_handle v2 = v1;
+      v2++;
+      std::size_t counter2 = 0;
+      for (;v2 != p.vertices_end(); v2++)
+      {
+        min_distance = std::min(min_distance,
+                                CGAL::to_double(CGAL::squared_distance(v1->point(), v2->point())));
+
+        if (min_distance == 0)
+          return 0.0;
+
+        counter2++;
+      }
+
+      counter++;
+    }
+
+    std::cout << "  Done computing closest" << std::endl;
+    return min_distance;
+  }
+  //-----------------------------------------------------------------------------
+  template<typename Polyhedron>
+  static std::size_t min_vertex_degree(const Polyhedron& p)
+  {
+    std::size_t min_degree = std::numeric_limits<std::size_t>::max();
+    for (typename Polyhedron::Vertex_const_iterator it = p.vertices_begin();
+         it != p.vertices_end(); it++)
+    {
+      if (!vertex_is_border<Polyhedron>(it))
+      {
+        min_degree = std::min(min_degree, it->vertex_degree());
+      }
+    }
+    return min_degree;
+  }
+  //-----------------------------------------------------------------------------
+  template<typename Polyhedron>
+  static void remove_vertex(Polyhedron& P, typename Polyhedron::Vertex_handle v)
+  {
+    typedef typename Polyhedron::Halfedge_around_vertex_circulator Vertex_circulator;
+    typedef typename Polyhedron::Halfedge_handle Halfedge_handle;
+
+    // std::cout << "Removing vertex" << std::endl;
+
+    Vertex_circulator h = v->vertex_begin();
+    Vertex_circulator start = h;
+
+    std::vector<Halfedge_handle> to_be_removed;
+
+    do
+    {
+      if (!h->is_border())
+        to_be_removed.push_back(h);
+
+      h++;
+    } while (h != start);
+
+
+    // std::cout << "Removing " << to_be_removed.size() << " halfedges" << std::endl;
+    for (auto it = to_be_removed.begin(); it != to_be_removed.end(); it++)
+    {
+      P.erase_facet(*it);
+    }
+
+    // std::cout << "  done removing vertex" << std::endl;
+  }
+  //-----------------------------------------------------------------------------
+  template<typename Polyhedron>
+  static std::size_t remove_self_intersections(Polyhedron& P)
+  {
+    std::size_t removed = 0;
+
+    // typedef typename Polyhedron::Traits Polyhedron_traits;
+    typedef typename Polyhedron::Facet_handle Facet_handle;
+    typedef typename Polyhedron::Halfedge_handle Halfedge_handle;
+    std::vector<std::pair<Facet_handle, Facet_handle> > intersections;
+    CGAL::Polygon_mesh_processing::self_intersections(P, std::back_inserter(intersections));
+
+    while (intersections.size() > 0)
+    {
+      std::cout << "Removing self intersection (" << intersections.size() << ")" << std::endl;
+      const typename Polyhedron::Facet_handle f1 = intersections.front().first;
+      const typename Polyhedron::Facet_handle f2 = intersections.front().second;
+
+      std::deque<Facet_handle> queue1;
+      queue1.push_back(f1);
+
+      std::deque<Facet_handle> queue2;
+      queue2.push_back(f2);
+
+      std::set<Facet_handle> to_be_removed1;
+      to_be_removed1.insert(f1);
+
+      std::set<Facet_handle> to_be_removed2;
+      to_be_removed2.insert(f2);
+
+      bool f1_done = false;
+
+      while (!f1_done)
+      {
+        // Pop from queue 1
+        if (queue1.size() > 0)
+        {
+          to_be_removed1.insert(queue1.front());
+          Halfedge_handle start = queue1.front()->halfedge();
+
+          queue1.pop_front();
+          Halfedge_handle current = start;
+
+          do
+          {
+            std::cout << "Spreading out 1" << std::endl;
+            if (!current->is_border_edge())
+            {
+              //if (to_be_removed2.count(current->opposite()->facet()) > 0)
+              if (current->opposite()->facet() == f2)
+              {
+                f1_done = true;
+                break;
+              }
+              else
+              {
+                queue1.push_back(current->opposite()->facet());
+              }
+            }
+            current = current->next();
+          } while (current != start);
+        }
+        else
+        {
+          f1_done = true;
+        }
+      }
+
+      bool f2_done = false;
+
+      while (!f2_done)
+      {
+        // Pop from queue 2
+        if (queue2.size() > 0)
+        {
+          to_be_removed2.insert(queue2.front());
+          Halfedge_handle start = queue2.front()->halfedge();
+          queue2.pop_front();
+          Halfedge_handle current = start;
+
+          do
+          {
+            std::cout << "Spreading out 2" << std::endl;
+            if (!current->is_border_edge())
+            {
+              // if (to_be_removed1.count(current->opposite()->facet()) > 0)
+              if (current->opposite()->facet() == f1)
+              {
+                f2_done = true;
+                break;
+              }
+              else
+              {
+                queue2.push_back(current->opposite()->facet());
+              }
+            }
+            current = current->next();
+          } while (current != start);
+        }
+        else
+        {
+          f2_done = true;
+        }
+      }
+
+      std::cout << "To be removed 1: " << to_be_removed1.size() << std::endl;
+      std::cout << "To be removed 2: " << to_be_removed2.size() << std::endl;
+
+      to_be_removed1.insert(to_be_removed2.begin(),
+                            to_be_removed2.end());
+
+      for (typename Polyhedron::Face_handle f : to_be_removed1)
+      {
+        P.erase_facet(f->halfedge());
+        dolfin_assert(P.is_valid());
+        removed++;
+      }
+
+
+      /* for (typename Polyhedron::Face_handle f : to_be_removed2) */
+      /* { */
+      /*   P.erase_facet(f->halfedge()); */
+      /*   dolfin_assert(P.is_valid()); */
+      /*   removed++; */
+      /* } */
+
+      dolfin_assert(P.is_valid());
+
+      intersections.clear();
+      CGAL::Polygon_mesh_processing::self_intersections(P, std::back_inserter(intersections));
+
+      break;
+    }
+
+    return removed;
+  }
+  //-----------------------------------------------------------------------------
+  template<typename Polyhedron>
+  static void filter_sharp_features(Polyhedron& P, int start_facet, double tolerance)
+  {
+    typedef typename Polyhedron::Facet_iterator Facet_iterator;
+    typedef typename Polyhedron::Facet_handle Facet_handle;
+    typedef typename Polyhedron::Halfedge_handle Halfedge_handle;
+    typedef typename Polyhedron::Traits::Triangle_3 Triangle_3;
+
+    /* { */
+    /*   std::ofstream outfile("before_filtering.off"); */
+    /*   outfile << P; */
+    /* } */
+
+    /* std::cout << "Filter sharp features" << std::endl; */
+
+    const double cos_tolerance = std::cos(tolerance);
+    // std::cout << "tolerance: " << cos_tolerance << std::endl;
+    Facet_iterator fit = P.facets_begin();
+    for (int i = 0; i < start_facet; i++)
+      fit++;
+
+    std::deque<Facet_handle> queue;
+    {
+      Halfedge_handle h = fit->halfedge();
+      // std::cout << "Starting facet: Triangle " << h->vertex()->point() << ", ";
+      h = h->next();
+      // std::cout << h->vertex()->point() << ", ";
+      h = h->next();
+      // std::cout << h->vertex()->point() << std::endl;
+    }
+
+    std::set<Facet_handle> visited;
+    std::set<Facet_handle> to_be_removed;
+    for (Facet_iterator fit = P.facets_begin(); fit != P.facets_end(); fit++)
+      to_be_removed.insert(fit);
+
+    // std::cout << "Number of facets: " << P.size_of_facets() << std::endl;
+
+    queue.push_back(fit);
+    while (!queue.empty())
+    {
+      // std::cout << "In queue" << std::endl;
+      Facet_handle f = queue.front();
+      queue.pop_front();
+
+      if (visited.count(f) > 0)
+      {
+        // std::cout << "Already handled" << std::endl;
+        continue;
+      }
+
+      visited.insert(f);
+      to_be_removed.erase(f);
+
+      const Halfedge_handle start = f->halfedge();
+      Halfedge_handle current = start;
+      do
+      {
+        // std::cout << "Exploring neighbor" << std::endl;
+        if (!current->opposite()->is_border())
+        {
+
+          Triangle_3 t1 = get_facet_triangle<Polyhedron>(current);
+          Triangle_3 t2 = get_facet_triangle<Polyhedron>(current->opposite());
+          if (get_triangle_cos_angle(t1, t2) > cos_tolerance)
+          {
+            queue.push_back(current->opposite()->facet());
+          }
+        }
+
+        current = current->next();
+      } while (current != start);
+    }
+
+    // std::cout << "Remove " << to_be_removed.size() << " facets" << std::endl;
+
+    for (auto fit = to_be_removed.begin(); fit != to_be_removed.end(); fit++)
+    {
+      P.erase_facet( (*fit)->halfedge() );
+    }
+
+    /* { */
+    /*   std::ofstream outfile("after_filtering.off"); */
+    /*   outfile << P; */
+    /* } */
+  }
+
+//-----------------------------------------------------------------------------
+  template <typename Polyhedron>
+  static std::pair<typename Polyhedron::Traits::Point_3, typename Polyhedron::Traits::Point_3>
+  get_aabb(const Polyhedron& P)
+  {
+    typedef typename Polyhedron::Vertex_const_iterator Vertex_const_iterator;
+    typedef typename Polyhedron::Traits::Point_3 Point_3;
+    typedef typename Polyhedron::Traits::FT FT;
+    Vertex_const_iterator it = P.vertices_begin();
+
+    FT x_min = it->point().x();
+    FT y_min = it->point().y();;
+    FT z_min = it->point().z();
+    FT x_max = x_min;
+    FT y_max = y_min;
+    FT z_max = z_min;
+    it++;
+
+    for (;it != P.vertices_end(); it++)
+    {
+      const Point_3& current = it->point();
+      x_min = std::min(x_min, current.x());
+      y_min = std::min(y_min, current.y());
+      z_min = std::min(z_min, current.z());
+
+      x_max = std::max(x_max, current.x());
+      y_max = std::max(y_max, current.y());
+      z_max = std::max(z_max, current.z());
+    }
+
+    return std::make_pair(Point_3(x_min, y_min, z_min),
+                          Point_3(x_max, y_max, z_max));
+  }
+  //-----------------------------------------------------------------------------
+  template<typename Polyhedron>
+  static double sharpest_edge(const Polyhedron& P)
+  {
+    typedef typename Polyhedron::Traits Kernel;
+    typedef typename Polyhedron::Edge_const_iterator Edge_const_iterator;
+    typedef typename Kernel::Vector_3 Vector_3;
+
+    double min_cos = 1.0;
+    for (Edge_const_iterator it = P.edges_begin(); it != P.edges_end(); it++)
+    {
+      //const Point_3 a = it->vertex()->point();
+      const Vector_3 n1 = CGAL::normal<Kernel>(it->vertex()->point(),
+                                               it->next()->vertex()->point(),
+                                               it->next()->next()->vertex()->point());
+      const Vector_3 n2 = CGAL::normal<Kernel>(it->opposite()->vertex()->point(),
+                                               it->opposite()->next()->vertex()->point(),
+                                               it->opposite()->next()->next()->vertex()->point());
+      min_cos = std::min(min_cos,
+                         CGAL::to_double(n1*n2)/sqrt(CGAL::to_double(n1.squared_length()*n2.squared_length())));
+    }
+
+    return acos(min_cos);
+  }
+  //-----------------------------------------------------------------------------
+  template<typename Polyhedron>
+  static void center_vertex_refinement(Polyhedron& P)
+  {
+    // Precollect facet handles since we are adding facets within the loop
+    std::vector<typename Polyhedron::Facet_handle> facets;
+    facets.reserve(P.size_of_facets());
+    for (typename Polyhedron::Facet_iterator fit = P.facets_begin();
+         fit != P.facets_end();
+         fit++)
+    {
+      facets.push_back(fit);
+    }
+
+    for (typename Polyhedron::Facet_handle f : facets)
+    {
+      typename Polyhedron::Halfedge_handle h = f->halfedge();
+      typename Polyhedron::Traits::Point_3 c = CGAL::centroid(h->vertex()->point(),
+                                                              h->next()->vertex()->point(),
+                                                              h->next()->next()->vertex()->point());
+      c.exact();
+      typename Polyhedron::Halfedge_handle h_new = P.create_center_vertex(h);
+      h_new->vertex()->point() = c;
+    }
+  }
+  //-----------------------------------------------------------------------------
+  template<typename Polyhedron>
+  static void split_edge_refinement(Polyhedron& P)
+  {
+    typedef typename Polyhedron::Halfedge_handle Halfedge_handle;
+    typedef typename Polyhedron::Traits::Point_3 Point_3;
+
+    // Collect vertices from the original
+    std::set<Halfedge_handle> facets;
+    // facets.reserve(P.size_of_facets());
+    for (typename Polyhedron::Facet_iterator fit = P.facets_begin();
+         fit != P.facets_end();
+         fit++)
+    {
+      const Halfedge_handle h = fit->halfedge();
+      facets.insert(h);
+    }
+
+    // Split all edges
+    {
+      std::vector<Halfedge_handle> edges;
+      for (typename Polyhedron::Edge_iterator eit = P.edges_begin();
+           eit != P.edges_end(); eit++)
+      {
+        edges.push_back(eit);
+      }
+
+      for (Halfedge_handle h : edges)
+      {
+        const Point_3 p = CGAL::midpoint(h->vertex()->point(),
+                                         h->opposite()->vertex()->point());
+        Halfedge_handle opposite = h->opposite();
+        Halfedge_handle h_new = P.split_edge(h);
+        h_new->vertex()->point() = p;
+
+        // This is suboptimal, but split_edge(h) changes h->opposite() to point
+        // to the newly inserted vertex, so we have to check and update if
+        // h->opposite() is stored in facets
+        if (facets.erase(opposite))
+        {
+          facets.insert(h_new->opposite());
+        }
+      }
+    }
+
+    for (Halfedge_handle h : facets)
+    {
+      Halfedge_handle h2 = h->next()->next();
+      Halfedge_handle h3 = h2->next()->next();
+      P.split_facet(h->next(), h->prev());
+      P.split_facet(h2->next(), h2->prev());
+      P.split_facet(h3->next(), h3->prev());
+    }
+  }
+};
+  //-----------------------------------------------------------------------------
+// Taken from demo/Polyhedron/Scene_nef_polyhedron_item.cpp in the
+// CGAL source tree.
+// Quick hacks to convert polyhedra from exact to inexact and
+// vice-versa
+template <class Polyhedron_input, class Polyhedron_output>
+struct Copy_polyhedron_to
+  : public CGAL::Modifier_base<typename Polyhedron_output::HalfedgeDS>
+{
+  Copy_polyhedron_to(const Polyhedron_input& in_poly)
+    : _in_poly(in_poly) {}
+
+  void operator()(typename Polyhedron_output::HalfedgeDS& out_hds)
+  {
+    typedef typename Polyhedron_output::HalfedgeDS Output_HDS;
+    //typedef typename Polyhedron_input::HalfedgeDS Input_HDS;
+
+    CGAL::Polyhedron_incremental_builder_3<Output_HDS> builder(out_hds);
+
+    typedef typename Polyhedron_input::Vertex_const_iterator Vertex_const_iterator;
+    typedef typename Polyhedron_input::Facet_const_iterator  Facet_const_iterator;
+    typedef typename Polyhedron_input::Halfedge_around_facet_const_circulator HFCC;
+
+    builder.begin_surface(_in_poly.size_of_vertices(),
+      _in_poly.size_of_facets(),
+      _in_poly.size_of_halfedges());
+
+    for(Vertex_const_iterator
+      vi = _in_poly.vertices_begin(), end = _in_poly.vertices_end();
+      vi != end ; ++vi)
+    {
+      typename Polyhedron_output::Point_3 p(::CGAL::to_double( vi->point().x()),
+       ::CGAL::to_double( vi->point().y()),
+       ::CGAL::to_double( vi->point().z()));
+      builder.add_vertex(p);
+    }
+
+    typedef CGAL::Inverse_index<Vertex_const_iterator> Index;
+    Index index(_in_poly.vertices_begin(), _in_poly.vertices_end());
+
+    for(Facet_const_iterator
+      fi = _in_poly.facets_begin(), end = _in_poly.facets_end();
+      fi != end; ++fi)
+    {
+      HFCC hc = fi->facet_begin();
+      HFCC hc_end = hc;
+      //     std::size_t n = circulator_size( hc);
+      //     CGAL_assertion( n >= 3);
+      builder.begin_facet ();
+      do
+      {
+        builder.add_vertex_to_facet(index[hc->vertex()]);
+        ++hc;
+      } while( hc != hc_end);
+      builder.end_facet();
+    }
+    builder.end_surface();
+  } // end operator()(..)
+private:
+  const Polyhedron_input& _in_poly;
+}; // end Copy_polyhedron_to<>
+
+template <class Poly_A, class Poly_B>
+void copy_to(const Poly_A& poly_a, Poly_B& poly_b)
+{
+  Copy_polyhedron_to<Poly_A, Poly_B> modifier(poly_a);
+  poly_b.delegate(modifier);
+  // CGAL_assertion(poly_b.is_valid());
+}
+}
+
+#endif
diff --git a/src/STLFileReader.cpp b/src/STLFileReader.cpp
new file mode 100644 (file)
index 0000000..3e124da
--- /dev/null
@@ -0,0 +1,335 @@
+// Copyright (C) 2014 Benjamin Kehlet
+//
+// This file is part of mshr.
+//
+// mshr 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 3 of the License, or
+// (at your option) any later version.
+//
+// mshr 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 mshr.  If not, see <http://www.gnu.org/licenses/>.
+//
+
+#include <mshr/STLFileReader.h>
+#include "FuzzyPointLocator.h"
+
+#include <dolfin/geometry/Point.h>
+#include <dolfin/common/constants.h>
+#include <dolfin/log/LogStream.h>
+#include <dolfin/log/log.h>
+
+#define BOOST_FILESYSTEM_NO_DEPRECATED
+#include <boost/filesystem.hpp>
+#include <boost/tokenizer.hpp>
+#include <boost/algorithm/string.hpp>
+
+#include <fstream>
+#include <iostream>
+#include <sstream>
+#include <string>
+#include <algorithm>
+#include <string>
+#include <map>
+#include <math.h> 
+namespace
+{
+inline double strToDouble(const std::string& s)
+{
+  std::istringstream is(s);
+  double val;
+  is >> val;
+
+  return val;
+}
+
+// get next line of file and trim away whitespace
+inline void get_next_line(std::ifstream& file, std::string& line, std::size_t &lineno)
+{
+  // Skip white
+  do
+  {
+    std::getline(file, line);
+    boost::algorithm::trim(line);
+    lineno++;
+  } while (file.good() && line.size() == 0);
+}
+
+} // end anonymous namespace
+//-----------------------------------------------------------------------------
+namespace mshr
+{
+
+void STLFileReader::read(const std::string filename,
+                         std::vector<std::array<double, 3> >& vertices,
+                         std::vector<std::array<std::size_t, 3> >& facets)
+{
+
+  dolfin::log(dolfin:: TRACE, "Reading surface from %s ", filename.c_str());
+
+  // vertices.clear();
+  facets.clear();
+
+  typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
+
+  std::ifstream file(filename.c_str());
+  if (!file.is_open())
+  {
+    dolfin::dolfin_error("STLFileReader.cpp",
+                         "open .stl file to read 3D surface",
+                         "Failed to open file");
+  }
+
+  FuzzyPointMap vertex_map(1e-10);
+
+  std::string line;
+  std::size_t lineno = 0;
+  const boost::char_separator<char> sep(" ");
+
+  // Read the first line and trim away whitespaces
+  get_next_line(file, line, lineno);
+
+  if (line.substr(0, 5) != "solid")
+  {
+    dolfin::dolfin_error("STLFileReader.cpp",
+                         "open .stl file to read 3D surface",
+                         "File does not start with \"solid\" (line %u", lineno);
+  }
+
+  // TODO: Read name of solid
+
+  do
+  {
+    // Some files contain color information before the vertex information
+    get_next_line(file, line, lineno);
+  } while (line.substr(0, 5) != "facet");
+
+  while (file.good())
+  {
+    bool has_normal = false;
+    dolfin::Point normal;
+
+    // Read the line "facet normal n1 n2 n3"
+    {
+      tokenizer tokens(line, sep);
+      tokenizer::iterator tok_iter = tokens.begin();
+
+      if (*tok_iter != "facet")
+        dolfin::dolfin_error("STLFileReader.cpp",
+                             "open .stl file to read 3D surface",
+                             "Expected keyword \"facet\" (line %u)", lineno);
+      ++tok_iter;
+
+      // Check if a normal different from zero is given
+      if (tok_iter != tokens.end())
+      {
+        if  (*tok_iter != "normal")
+          dolfin::dolfin_error("STLFileReader.cpp",
+                               "open .stl file to read 3D surface",
+                               "Expected keyword \"normal\"(line %u)", lineno);
+        ++tok_iter;
+
+        //dolfin::cout << "Read line: " << line << dolfin::endl;
+
+        for (std::size_t i = 0; i < 3; ++i)
+        {
+          normal[i] = strToDouble(*tok_iter);
+          ++tok_iter;
+        }
+
+        if (normal.norm() > DOLFIN_EPS)
+          has_normal = true;
+
+        if (tok_iter != tokens.end())
+          dolfin::dolfin_error("STLFileReader.cpp",
+                               "open .stl file to read 3D surface",
+                               "Expected end of line (line %u)", lineno);
+      }
+    }
+
+    // if (has_normal)
+    // {
+    //   dolfin::cout << "Has normal" << dolfin::endl;
+    //   dolfin::cout << normal << dolfin::endl;
+    // }
+
+    // Read "outer loop" line
+    get_next_line(file, line, lineno);
+
+    if (line != "outer loop")
+      dolfin::dolfin_error("STLFileReader.cpp",
+                           "open .stl file to read 3D surface",
+                           "Expected keyword 'outer loop' (line %u)", lineno);
+
+    std::array<std::size_t, 3> v_indices;
+
+    get_next_line(file, line, lineno);
+
+    tokenizer tokens(line, sep);
+    tokenizer::iterator tok_iter = tokens.begin();
+
+    if (*tok_iter != "vertex")
+    {
+      dolfin::dolfin_error("STLFileReader.cpp",
+                           "open .stl file to read 3D surface",
+                           "Expected keyword vertex (line %u)", lineno);
+    }
+
+    int counter = 0;
+
+    // Read lines with vertices
+    do
+    {
+      // Only support for triangulated surfaces for now
+      dolfin_assert(counter < 3);
+
+      // Advance to next
+      ++tok_iter;
+
+      const double x = strToDouble(*tok_iter); ++tok_iter;
+      const double y = strToDouble(*tok_iter); ++tok_iter;
+      const double z = strToDouble(*tok_iter); ++tok_iter;
+
+      const std::array<double, 3> vertex = {{x, y, z}};
+
+      // Insert point and get index. vertex_map takes care of merging close
+      // vertices
+      v_indices[counter] = vertex_map.insert_point(vertex);
+
+      // Get next line
+      get_next_line(file, line, lineno);
+
+      tokens = tokenizer(line, sep);
+      tok_iter = tokens.begin();
+
+      counter++;
+    } while (*tok_iter == "vertex");
+
+    // Read 'endloop' line
+    if (line != "endloop")
+    {
+      dolfin::dolfin_error("STLFileReader.cpp",
+                           "open .stl file to read 3D surface",
+                           "Expected keyword endloop (line %u)", lineno);
+    }
+
+    get_next_line(file, line, lineno);
+    if (line != "endfacet")
+    {
+      dolfin::dolfin_error("STLFileReader.cpp",
+                           "open .stl file to read 3D surface",
+                           "Expected keyword endfacet (line %u)", lineno);
+    }
+
+    // Add facet to output
+    facets.push_back(v_indices);
+
+    // Get orientation right if normal is given
+    if (has_normal)
+    {
+      // Compute normal
+      const dolfin::Point v1(3, vertex_map[v_indices[0]].data());
+      const dolfin::Point v2(3, vertex_map[v_indices[1]].data());
+      const dolfin::Point v3(3, vertex_map[v_indices[2]].data());
+
+      const dolfin::Point a = v2-v1;
+      const dolfin::Point b = v3-v1;
+
+      dolfin::Point n = a.cross(b);
+      n /= n.norm();
+
+      // dolfin::cout << "Normal: " << n << dolfin::endl;
+      // if ( (n - normal).norm() > 1e-5 )
+      //   dolfin::cout << "Diff: " << (n - normal).norm() << dolfin::endl;
+    }
+
+    // Get next line
+    // either start of next facet or endsolid
+    get_next_line(file, line, lineno);
+
+    if (line.substr(0, 5) != "facet")
+      break;
+  }
+
+  // Read the 'endsolid' line
+  tokenizer tokens(line, sep);
+  tokenizer::iterator tok_iter = tokens.begin();
+
+  if (*tok_iter != "endsolid")
+  {
+    dolfin::dolfin_error("STLFileReader.cpp",
+                         "open .stl file to read 3D surface",
+                         "Expected keyword endsolid at line %u", lineno);
+  }
+  ++tok_iter;
+
+  vertices = vertex_map.get_points();
+
+  // TODO: Check name of solid
+  dolfin::log(dolfin::TRACE, "Done reading surface");
+
+  // closest_vertices(vertex_map);
+}
+void STLFileReader::write(const std::string filename,
+                         std::vector<std::array<double, 3> >& vertices,
+                         std::vector<std::array<std::size_t, 3> >& facets)
+{
+
+    std::ofstream file(filename);
+    file.precision(6);
+
+    if (!file.is_open())
+    {
+       dolfin::dolfin_error("STLFileReader.cpp",
+                         "open file to write stl data",
+                         "Failed to open file");
+    }
+
+    file << "solid "<< filename << std::endl;
+    
+
+    
+    
+    for (const std::array<std::size_t, 3>& f : facets)
+    {
+
+       std::array<double,3> n;
+       float vec1x,vec1y,vec1z;
+       float vec2x,vec2y,vec2z;
+       float size;
+      
+       std::array<double, 3>& v0 = vertices[f[0]];
+       std::array<double, 3>& v1 = vertices[f[1]];
+       std::array<double, 3>& v2 = vertices[f[2]];
+       
+       vec1x = v1[0] - v0[0];
+       vec1y = v1[1] - v0[1];
+       vec1z = v1[2] - v0[2];
+
+       vec2x = v2[0] - v0[0];
+       vec2y = v2[1] - v0[1];
+       vec2z = v2[2] - v0[2];
+       
+       n[0] = vec1y*vec2z-vec1z*vec2y;
+       n[1] = vec1z*vec2x-vec1x*vec2z;
+       n[2] = vec1x*vec2y-vec1y*vec2x;                 
+       size = sqrt(n[0]*n[0]+n[1]*n[1]+n[2]*n[2]);
+
+       file << "facet normal " << n[0]/size << " " << n[1]/size  << " " << n[2]/size <<std::endl;
+       file << "outer loop"<< std::endl;
+       file << "\t" << "vertex " << v0[0] << " " << v0[1]<< " " << v0[2] << std::endl;
+       file << "\t" << "vertex " << v1[0] << " " << v1[1]<< " " << v1[2] << std::endl;
+       file << "\t" << "vertex " << v2[0] << " " << v2[1]<< " " << v2[2] << std::endl;
+       file <<"endloop" << std::endl;
+       file <<"endfacet"<< std::endl;
+    }
+    file << "endsolid"  << std::endl;
+
+}
+
+}
diff --git a/src/SurfaceConsistency.cpp b/src/SurfaceConsistency.cpp
new file mode 100644 (file)
index 0000000..4eb6974
--- /dev/null
@@ -0,0 +1,363 @@
+// Copyright (C) 2014-2016 Benjamin Kehlet
+//
+// This file is part of mshr.
+//
+// mshr 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 3 of the License, or
+// (at your option) any later version.
+//
+// mshr 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 mshr.  If not, see <http://www.gnu.org/licenses/>.
+
+// OBS! Experimental code
+
+#include <mshr/SurfaceConsistency.h>
+#include "FuzzyPointLocator.h"
+
+#include <dolfin/log/log.h>
+#include <vector>
+#include <map>
+#include <deque>
+#include <iostream>
+#include <limits>
+
+// #include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
+// typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel;
+// typedef Kernel::Point_3 Point_3;
+// typedef Kernel::Triangle_3 Triangle_3;
+
+// namespace
+// {
+// inline bool triangles_intersect(const std::vector<std::array<double, 3> >& vertices,
+//                                 const std::vector<std::array<std::size_t, 3> >& facets,
+//                                 std::size_t a,
+//                                 std::size_t b)
+// {
+//   const std::array<std::size_t, 3>& ta = facets[a];
+//   const std::array<std::size_t, 3>& tb = facets[b];
+
+//   std::cout << "  Intersection test: " << std::endl;
+//   std::cout << "    Facet " << a << ": (" << ta[0] << ", " << ta[1] << ", " << ta[2] << ")" << std::endl;
+//   std::cout << "    Facet " << b << ": (" << tb[0] << ", " << tb[1] << ", " << tb[2] << ")" << std::endl;
+
+//   for (std::size_t i = 0; i < 3; i++)
+//   {
+//     for (std::size_t j = 0; j < 3; j++)
+//     {
+//       if (ta[i] == tb[j] || (ta[i] == tb[(j+1)%3] && ta[(i+1)%3] == tb[j]))
+//       {
+//         std::cout << "    Neighbor" << std::endl;
+//         return false;
+//       }
+//     }
+//   }
+
+//   Triangle_3 t1(Point_3(vertices[ta[0]][0], vertices[ta[0]][1], vertices[ta[0]][2]),
+//                 Point_3(vertices[ta[1]][0], vertices[ta[1]][1], vertices[ta[1]][2]),
+//                 Point_3(vertices[ta[2]][0], vertices[ta[2]][1], vertices[ta[2]][2]));
+
+//   Triangle_3 t2(Point_3(vertices[tb[0]][0], vertices[tb[0]][1], vertices[tb[0]][2]),
+//                 Point_3(vertices[tb[1]][0], vertices[tb[1]][1], vertices[tb[1]][2]),
+//                 Point_3(vertices[tb[2]][0], vertices[tb[2]][1], vertices[tb[2]][2]));
+
+//   const bool i = CGAL::do_intersect(t1, t2);
+//   std::cout << "    Result: " << (i ? "True" : "False") << std::endl;
+//   return i;
+// }
+// }
+
+namespace mshr
+{
+
+void SurfaceConsistency::checkConnectivity(std::vector<std::array<std::size_t, 3> >& facets,
+                                           std::set<std::size_t>& duplicating,
+                                           bool error)
+{
+  log(dolfin::TRACE, "Checking connectivity");
+
+  // Store halfedges
+  std::map<std::pair<std::size_t, std::size_t>, std::size_t> halfedges;
+
+  for (std::size_t facet_no = 0; facet_no < facets.size(); facet_no++)
+  {
+    std::array<std::size_t, 3>& f = facets[facet_no];
+    // Check for (topologically) degenerate facets
+    if ( f[0] == f[1] || f[0] == f[2] || f[1] == f[2] )
+      dolfin::dolfin_error("SurfaceConsistency.cpp",
+                           "confirm surface connectivity",
+                           "Facet %d is topologically degenerate", facet_no);
+
+    if (halfedges.count(std::make_pair(f[0], f[1])) > 0 ||
+        halfedges.count(std::make_pair(f[1], f[2])) > 0 ||
+        halfedges.count(std::make_pair(f[2], f[0])) > 0)
+    {
+      duplicating.insert(facet_no);
+    }
+    else
+    {
+      halfedges[std::make_pair(f[0], f[1])] = facet_no;
+      halfedges[std::make_pair(f[1], f[2])] = facet_no;
+      halfedges[std::make_pair(f[2], f[0])] = facet_no;
+    }
+  }
+}
+//-----------------------------------------------------------------------------
+void SurfaceConsistency::filterFacets(const std::vector<std::array<std::size_t, 3> >& facets,
+                                      const std::vector<std::array<double, 3> >& vertices,
+                                      std::size_t start, std::set<std::size_t>& skip)
+{
+  // Map egdes (ordered pairs of vertices) to facets
+  std::map<std::pair<std::size_t, std::size_t>, std::size_t> edge_map;
+
+  for (std::size_t i = 0; i < facets.size(); i++)
+  {
+    const std::array<std::size_t, 3>& facet = facets[i];
+    std::size_t prev = facet[facet.size()-1];
+    for (auto vit = facet.begin(); vit != facet.end(); vit++)
+    {
+      const std::pair<std::size_t, std::size_t> e(prev, *vit);
+      edge_map[e] = i;
+      prev = *vit;
+    }
+
+    skip.insert(i);
+  }
+
+  // const std::size_t global_max = skip.size();
+
+  std::set<std::size_t> visited;
+  //std::vector<std::size_t> included;
+  std::deque<std::size_t> queue;
+  if (skip.count(start) > 0)
+    queue.push_front(start);
+  // else
+  //   std::cout << "  Already added" << std::endl;
+
+  std::size_t global_count = 0;
+  while (!queue.empty())
+  {
+    // dolfin_assert(global_count <= global_max);
+
+    std::size_t current = queue.front();
+    queue.pop_front();
+
+    const std::array<size_t, 3>& current_facet = facets[current];
+    // std::cout << "-- Processing " << current << ", vertices: " << current_facet[0] << ", " << current_facet[1] << ", " << current_facet[2] << std::endl;
+
+    visited.insert(current);
+
+    // don't skip this facet
+    if (skip.count(current) > 0)
+    {
+      // bool intersects = false;
+      // for (auto it = included.begin(); it != included.end(); it++)
+      // {
+      //   if (triangles_intersect(vertices, facets, current, *it))
+      //   {
+      //     intersects = true;
+      //     break;
+      //   }
+      // }
+
+      // if (intersects)
+      // {
+      //   std::cout << " SKIPPING" << std::endl;
+      //   {int tmp; std::cin >> tmp;}
+      //   continue;
+      // }
+
+      skip.erase(current);
+      //included.push_back(current);
+
+      std::size_t prev = current_facet[2];
+      for (auto fit = current_facet.begin(); fit != current_facet.end(); fit++)
+      {
+        const std::pair<std::size_t, std::size_t> opposite(*fit, prev);
+        // std::cout << "  opposite: " << opposite.first << " " << opposite.second << std::endl;
+        if (edge_map.count(opposite) > 0)
+        {
+          std::size_t opposite_facet = edge_map[opposite];
+          if (visited.count(opposite_facet) == 0)
+          {
+            queue.push_back(opposite_facet);
+            //std::cout << "  pushing: " << edge_map[opposite] << std::endl;
+          }
+        }
+        prev = *fit;
+      }
+
+      // std::cout << "Size of skip: " << skip.size() << ", size of queue: " << queue.size() << ", current: " << current << std::endl;
+      // {int tmp; std::cin >> tmp;}
+      global_count++;
+    }
+  }
+}
+//-----------------------------------------------------------------------------
+std::pair<std::unique_ptr<std::vector<std::array<double, 3> > >,
+          std::unique_ptr<std::vector<std::array<std::size_t, 3> > > >
+SurfaceConsistency::merge_close_vertices(const std::vector<std::array<std::size_t, 3> >& facets,
+                                         const std::vector<std::array<double, 3> >& vertices,
+                                         double tolerance)
+{
+  FuzzyPointMap point_map(tolerance);
+  std::vector<std::size_t> vertex_mapping;
+  vertex_mapping.reserve(vertices.size());
+
+
+  for (std::size_t i = 0; i < vertices.size(); i++)
+  {
+    const std::array<double, 3>& v = vertices[i];
+    const std::size_t new_index = point_map.insert_point(v);
+    vertex_mapping.push_back(new_index);
+  }
+
+  // std::cout << "Distinct vertices: " << point_map.size() << std::endl;
+
+  std::unique_ptr<std::vector<std::array<double, 3> > > new_vertices(new std::vector<std::array<double, 3> >(point_map.get_points()));
+  std::unique_ptr<std::vector<std::array<std::size_t, 3> > > new_facets(new std::vector<std::array<std::size_t, 3> >);
+  for (const std::array<std::size_t, 3>& t : facets)
+  {
+    new_facets->push_back({ {vertex_mapping[t[0]], vertex_mapping[t[1]], vertex_mapping[t[2]]} });
+  }
+
+  return std::make_pair(std::move(new_vertices), std::move(new_facets));
+}
+//-----------------------------------------------------------------------------
+void SurfaceConsistency::orient_component(std::vector<std::array<std::size_t, 3> >& facets,
+                                          std::size_t start)
+{
+  log(dolfin::TRACE, "Checking facet orientation");
+
+  // Map from edge (pair of vertices) to two triangles
+  std::map<std::pair<std::size_t, std::size_t>, std::pair<std::size_t, std::size_t> > edge_map;
+  for (std::size_t i = 0; i < facets.size(); i++)
+  {
+    const std::array<std::size_t, 3>& f = facets[i];
+    for (std::size_t j = 0; j < 3; j++)
+    {
+      auto edge = std::make_pair(std::min(f[j], f[(j+1)%3]), std::max(f[j], f[(j+1)%3]));
+      if (edge_map.count(edge) > 0)
+        edge_map[edge].second = i;
+      else
+        edge_map[edge] = std::make_pair(i, std::numeric_limits<std::size_t>::max());
+    }
+  }
+
+  std::deque<std::size_t> queue;
+  std::set<std::size_t> visited;
+  queue.push_back(start);
+
+  std::size_t counter = 0;
+  std::size_t flipped = 0;
+  while (!queue.empty())
+  {
+    std::size_t current = queue.front();
+    const std::array<std::size_t, 3>& current_facet = facets[current];
+    queue.pop_front();
+
+    if (visited.count(current) == 0)
+    {
+      counter++;
+      visited.insert(current);
+
+      for (std::size_t j = 0; j < 3; j++)
+      {
+        auto edge = std::make_pair(std::min(current_facet[j], current_facet[(j+1)%3]), std::max(current_facet[j], current_facet[(j+1)%3]));
+        dolfin_assert(edge_map.count(edge) > 0);
+
+        auto facet_pair = edge_map[edge];
+        const std::size_t opposite = facet_pair.first == current ? facet_pair.second : facet_pair.first;
+
+        if (opposite != std::numeric_limits<std::size_t>::max() && visited.count(opposite) == 0)
+        {
+          dolfin_assert(opposite != current);
+
+          std::array<std::size_t, 3>& opposite_facet = facets[opposite];
+          for (std::size_t k = 0; k < 3; k++)
+          {
+            const std::size_t a = opposite_facet[k];
+            const std::size_t b = opposite_facet[(k+1)%3];
+            if ( (a == current_facet[0] && b == current_facet[1]) ||
+                 (a == current_facet[1] && b == current_facet[2]) ||
+                 (a == current_facet[2] && b == current_facet[0]))
+            {
+              flipped++;
+              std::swap(opposite_facet[0], opposite_facet[1]);
+              break;
+            }
+          }
+          queue.push_back(opposite);
+        }
+      }
+    }
+  }
+  log(dolfin::TRACE, "Flipped %u triangles", flipped);
+}
+
+std::size_t SurfaceConsistency::remove_null_facets(std::vector<std::array<std::size_t, 3>>& facets)
+{
+  std::size_t counter = 0;
+
+  std::vector<std::array<std::size_t, 3>>::iterator it = facets.begin();
+
+  while (it != facets.end())
+  {
+    const std::array<std::size_t, 3>& f = *it;
+    if (f[0] == f[1] || f[0] == f[2] || f[1] == f[2])
+    {
+      *it = facets.back();
+      facets.pop_back();
+      counter++;
+    }
+    else
+      it++;
+  }
+
+  return counter;
+}
+
+std::size_t SurfaceConsistency::remove_isolated_vertices(std::vector<std::array<double, 3>>& vertices,
+                                                         std::vector<std::array<std::size_t, 3>>& facets)
+{
+  std::size_t counter = 0;
+  std::vector<bool> is_connected(vertices.size());
+  std::fill(is_connected.begin(), is_connected.end(), false);
+  for (const std::array<std::size_t, 3>& f : facets)
+  {
+    is_connected[f[0]] = true;
+    is_connected[f[1]] = true;
+    is_connected[f[2]] = true;
+  }
+
+  for (std::size_t i_ = 0; i_ < is_connected.size(); i_++)
+  {
+    // Need to do this in reverse order, so the vertices with higher index is
+    // processed first to avoid invalidating the
+    const std::size_t i = is_connected.size()-i_-1;
+
+    if (!is_connected[i])
+    {
+      vertices.erase(vertices.begin()+i);
+
+      for (std::array<std::size_t, 3>& f : facets)
+      {
+        if (f[0] > i) f[0]--;
+        if (f[1] > i) f[1]--;
+        if (f[2] > i) f[2]--;
+      }
+
+      counter++;
+    }
+  }
+
+  return counter;
+}
+
+
+}
diff --git a/src/SurfaceReconstruction.cpp b/src/SurfaceReconstruction.cpp
new file mode 100644 (file)
index 0000000..6d4fbd7
--- /dev/null
@@ -0,0 +1,370 @@
+// Copyright (C) 2015-2016 Benjamin Kehlet
+//
+// This file is part of mshr.
+//
+// mshr 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 3 of the License, or
+// (at your option) any later version.
+//
+// mshr 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 mshr.  If not, see <http://www.gnu.org/licenses/>.
+//
+
+#include <mshr/SurfaceReconstruction.h>
+#include <dolfin/log/log.h>
+#include <dolfin/common/constants.h>
+
+#define CGAL_EIGEN3_ENABLED true
+#include <CGAL/trace.h>
+#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
+#include <CGAL/Surface_mesh_default_triangulation_3.h>
+#include <CGAL/make_surface_mesh.h>
+#include <CGAL/Implicit_surface_3.h>
+#include <CGAL/Poisson_reconstruction_function.h>
+#include <CGAL/Point_with_normal_3.h>
+#include <CGAL/property_map.h>
+#include <CGAL/compute_average_spacing.h>
+
+#include <CGAL/Surface_mesh.h>
+#include <CGAL/Polygon_mesh_processing/remesh.h>
+
+// Based on CGAL/Surface_reconstruction_points_3/poisson_reconstruction_example.cpp
+typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel;
+typedef Kernel::FT FT;
+typedef Kernel::Point_3 Point;
+typedef Kernel::Vector_3 Vector;
+typedef CGAL::Point_with_normal_3<Kernel> Point_with_normal;
+typedef Kernel::Sphere_3 Sphere;
+typedef std::vector<Point_with_normal> PointList;
+typedef CGAL::Poisson_reconstruction_function<Kernel> Poisson_reconstruction_function;
+typedef CGAL::Surface_mesh_default_triangulation_3 STr;
+typedef CGAL::Surface_mesh_complex_2_in_triangulation_3<STr> C2t3;
+typedef CGAL::Implicit_surface_3<Kernel, Poisson_reconstruction_function> Surface_3;
+typedef typename C2t3::Triangulation Tr;
+typedef typename Tr::Vertex_handle Vertex_handle;
+typedef typename Tr::Edge Edge;
+typedef typename Tr::Facet Facet;
+typedef typename Tr::Finite_facets_iterator Finite_facets_iterator;
+
+
+namespace
+{
+
+template <class Vertex_handle>
+std::size_t get_vertex_index(std::vector<std::array<double, 3>>& vertices,
+                             Vertex_handle vh,
+                             std::map<Vertex_handle, std::size_t>& V,
+                             std::size_t& inum)
+{
+  typedef typename std::map<Vertex_handle, std::size_t>::iterator map_iterator;
+  std::pair<map_iterator,bool> insert_res = V.insert( std::make_pair(vh,inum) );
+  if ( insert_res.second )
+  {
+    typename Tr::Point p = static_cast<typename Tr::Point>(vh->point());
+    vertices.push_back({ {CGAL::to_double(p[0]),
+                          CGAL::to_double(p[1]),
+                          CGAL::to_double(p[2])} });
+    ++inum;
+  }
+  return insert_res.first->second;
+}
+//-----------------------------------------------------------------------------
+void export_triangulation(const C2t3& c2t3,
+                          std::vector<std::array<double, 3>>& vertices,
+                          std::vector<std::array<std::size_t, 3>>& facets)
+{
+  const Tr& tr = c2t3.triangulation();
+  const typename Tr::size_type number_of_facets = c2t3.number_of_facets();
+
+  vertices.reserve(tr.number_of_vertices());
+  facets.reserve(number_of_facets);
+
+  // Finite vertices coordinates.
+  Finite_facets_iterator fit = tr.finite_facets_begin();
+  std::set<Facet> oriented_set;
+  std::stack<Facet> stack;
+
+  //CGAL_assertion_code(typename Tr::size_type nb_facets = 0; )
+
+  while (oriented_set.size() != number_of_facets)
+  {
+    while ( fit->first->is_facet_on_surface(fit->second) == false ||
+            oriented_set.find(*fit) != oriented_set.end() ||
+            oriented_set.find(c2t3.opposite_facet(*fit)) != oriented_set.end() )
+    {
+      ++fit;
+    }
+    oriented_set.insert(*fit);
+    stack.push(*fit);
+    while(! stack.empty() )
+    {
+      Facet f = stack.top();
+      stack.pop();
+      for(int ih = 0 ; ih < 3 ; ++ih)
+      {
+        const int i1  = tr.vertex_triple_index(f.second, tr. cw(ih));
+        const int i2  = tr.vertex_triple_index(f.second, tr.ccw(ih));
+        if( c2t3.face_status(Edge(f.first, i1, i2)) == C2t3::REGULAR )
+        {
+          Facet fn = c2t3.neighbor(f, ih);
+          if (oriented_set.find(fn) == oriented_set.end() &&
+              oriented_set.find(c2t3.opposite_facet(fn)) == oriented_set.end())
+          {
+            oriented_set.insert(fn);
+            stack.push(fn);
+          }
+        } // end "if the edge is regular"
+      } // end "for each neighbor of f"
+    } // end "stack non empty"
+  } // end "oriented_set not full"
+
+  // Orients the whole mesh towards outside:
+  // - find the facet with max z
+  typename std::set<Facet>::const_iterator top_facet = oriented_set.begin();
+  for(typename std::set<Facet>::const_iterator fit = oriented_set.begin();
+      fit != oriented_set.end();
+      ++fit)
+  {
+    double top_z =
+      (top_facet->first->vertex(tr.vertex_triple_index(top_facet->second, 0))->point().z()
+       + top_facet->first->vertex(tr.vertex_triple_index(top_facet->second, 1))->point().z()
+       + top_facet->first->vertex(tr.vertex_triple_index(top_facet->second, 2))->point().z())/3.;
+    double z =
+      (fit->first->vertex(tr.vertex_triple_index(fit->second, 0))->point().z()
+       + fit->first->vertex(tr.vertex_triple_index(fit->second, 1))->point().z()
+       + fit->first->vertex(tr.vertex_triple_index(fit->second, 2))->point().z())/3.;
+    if (top_z < z)
+      top_facet = fit;
+  }
+
+  // - orient the facet with max z towards +Z axis
+  Vertex_handle v0 = top_facet->first->vertex(tr.vertex_triple_index(top_facet->second, 0));
+  Vertex_handle v1 = top_facet->first->vertex(tr.vertex_triple_index(top_facet->second, 1));
+  Vertex_handle v2 = top_facet->first->vertex(tr.vertex_triple_index(top_facet->second, 2));
+  Vector normal = cross_product(v1->point()-v0->point(), v2->point()-v1->point());
+  const Vector Z(0, 0, 1);
+  bool regular_orientation = (Z * normal >= 0);
+
+  // used to set indices of vertices
+  std::map<Vertex_handle, std::size_t> V;
+  std::size_t inum = 0;
+
+  for(typename std::set<Facet>::const_iterator fit =
+        oriented_set.begin();
+      fit != oriented_set.end();
+      ++fit)
+  {
+    std::size_t indices[3];
+    std::size_t index = 0;
+    for (std::size_t i = 0; i<3; i++)
+    {
+      indices[index++] = get_vertex_index(vertices,
+                                          fit->first->vertex(tr.vertex_triple_index(fit->second, i)),
+                                          V,
+                                          inum);
+    }
+
+    facets.push_back({ {indices[0],
+                       regular_orientation ? indices[1] : indices[2],
+                       regular_orientation ? indices[2] : indices[1]} });
+  }
+}
+}
+
+namespace mshr
+{
+//-----------------------------------------------------------------------------
+void mshr::SurfaceReconstruction::reconstruct(const std::vector<double>& vertices,
+                                              const std::vector<std::size_t>& facets,
+                                              std::vector<std::array<double, 3>>& reconstructed_vertices,
+                                              std::vector<std::array<std::size_t, 3>>& reconstructed_facets,
+                                              double expansion)
+{
+  // Poisson options
+  FT sm_angle = 20.0; // Min triangle angle in degrees.
+  FT sm_radius = 10; // Max triangle size w.r.t. point set average spacing.
+  FT sm_distance = 0.10; // Surface Approximation error w.r.t. point set average spacing.
+
+  // Reads the point set file in points[].
+  // Note: read_xyz_points_and_normals() requires an iterator over points
+  // + property maps to access each point's position and normal.
+  // The position property map can be omitted here as we use iterators over Point_3 elements.
+  PointList points;
+  for (std::size_t i = 0; i < facets.size(); i += 3)
+  {
+    const Point a(vertices[facets[i]*3],   vertices[facets[i]*3+1],   vertices[facets[i]*3+2]);
+    const Point b(vertices[facets[i+1]*3], vertices[facets[i+1]*3+1], vertices[facets[i+1]*3+2]);
+    const Point c(vertices[facets[i+2]*3], vertices[facets[i+2]*3+1], vertices[facets[i+2]*3+2]);
+
+    // compute normal
+    const Vector normal = CGAL::cross_product(b-a, c-a);
+    const Point centroid = CGAL::ORIGIN + ((a-CGAL::ORIGIN)+(b-CGAL::ORIGIN)+(c-CGAL::ORIGIN))/3.0;
+    const Vector normal_normalized = normal/std::sqrt(normal.squared_length());
+    Point_with_normal pm( centroid + normal_normalized*expansion,
+                          normal_normalized );
+
+    points.push_back(pm);
+  }
+
+  // Creates implicit function from the read points using the default solver.
+  // Note: this method requires an iterator over points
+  // + property maps to access each point's position and normal.
+  // The position property map can be omitted here as we use iterators over Point_3 elements.
+  log(dolfin::TRACE, "Construct implicit function");
+  Poisson_reconstruction_function function(points.begin(), points.end(),
+                                           CGAL::make_normal_of_point_with_normal_map(PointList::value_type()) );
+  log(dolfin::TRACE, "Compute Poisson indicator function");
+  // Computes the Poisson indicator function f()
+  // at each vertex of the triangulation.
+  if ( ! function.compute_implicit_function() )
+  {
+    dolfin::dolfin_error("SurfaceReconstruction.cpp",
+                         "reconstruct surface",
+                         "couldn't compute implicit function");
+  }
+  // Computes average spacing
+  log(dolfin::TRACE, "Compute average spacing");
+  FT average_spacing = CGAL::compute_average_spacing<CGAL::Sequential_tag>(points.begin(), points.end(),
+                                                     6 /* knn = 1 ring */);
+  // Gets one point inside the implicit surface
+  // and computes implicit function bounding sphere radius.
+  Point inner_point = function.get_inner_point();
+  Sphere bsphere = function.bounding_sphere();
+  FT radius = std::sqrt(bsphere.squared_radius());
+  // Defines the implicit surface: requires defining a
+  // conservative bounding sphere centered at inner point.
+  FT sm_sphere_radius = 5.0 * radius;
+  FT sm_dichotomy_error = sm_distance*average_spacing/1000.0; // Dichotomy error must be << sm_distance
+  Surface_3 surface(function,
+                    Sphere(inner_point,sm_sphere_radius*sm_sphere_radius),
+                    sm_dichotomy_error/sm_sphere_radius);
+
+  // Defines surface mesh generation criteria
+  CGAL::Surface_mesh_default_criteria_3<STr> criteria(sm_angle,  // Min triangle angle (degrees)
+                                                      sm_radius*average_spacing,  // Max triangle size
+                                                      sm_distance*average_spacing); // Approximation error
+  // Generates surface mesh with manifold option
+  log(dolfin::TRACE, "Invoke surface mesher");
+  STr tr; // 3D Delaunay triangulation for surface mesh generation
+  C2t3 c2t3(tr); // 2D complex in 3D Delaunay triangulation
+  CGAL::make_surface_mesh(c2t3,                                 // reconstructed mesh
+                          surface,                              // implicit surface
+                          criteria,                             // meshing criteria
+                          CGAL::Manifold_with_boundary_tag());  // require manifold mesh
+  if(tr.number_of_vertices() == 0)
+    dolfin::dolfin_error("SurfaceReconstruction.cpp",
+                         "reconstruct surface from point set",
+                         "Couldn't reconstruct surface");
+
+  export_triangulation(c2t3,
+                       reconstructed_vertices,
+                       reconstructed_facets);
+}
+  //-----------------------------------------------------------------------------
+void SurfaceReconstruction::remesh(double edge_length,
+                                   double sharp_edge_tolerance,
+                                   const std::vector<double>& vertices,
+                                   const std::vector<std::size_t>& facets,
+                                   std::vector<std::array<double, 3>>& remeshed_vertices,
+                                   std::vector<std::array<std::size_t, 3>>& remeshed_facets)
+{
+  typedef CGAL::Surface_mesh<Point> Surface_mesh;
+  typedef Surface_mesh::Vertex_index Vertex_index;
+  typedef Surface_mesh::Face_index Face_index;
+  typedef Surface_mesh::Edge_index Edge_index;
+  typedef Surface_mesh::Halfedge_index Halfedge_index;
+  typedef boost::graph_traits<Surface_mesh>::face_descriptor face_descriptor;
+  typedef boost::graph_traits<Surface_mesh>::edge_descriptor edge_descriptor;
+
+  namespace Parameters = CGAL::Polygon_mesh_processing::parameters;
+
+  Surface_mesh m;
+  std::vector<Vertex_index> v_index_mapping;
+  v_index_mapping.reserve(vertices.size());
+  for (std::size_t i = 0; i < vertices.size(); i += 3)
+  {
+    v_index_mapping.push_back(m.add_vertex(Point(vertices[i], vertices[i+1], vertices[i+2])));
+  }
+
+  for (std::size_t i = 0; i < facets.size(); i += 3)
+  {
+    m.add_face(v_index_mapping[facets[i]],
+               v_index_mapping[facets[i+1]],
+               v_index_mapping[facets[i+2]]);
+  }
+
+  // Collect edges that should be protected during remeshing
+  const double cos_tolerance = cos(2*DOLFIN_PI*sharp_edge_tolerance/360);
+
+  Surface_mesh::Property_map<edge_descriptor, bool> edge_constrained_map =
+    m.add_property_map<edge_descriptor, bool>("e:is_constrained", false).first;
+
+  std::size_t num_protected = 0;
+  if (sharp_edge_tolerance > 0)
+  {
+    Surface_mesh::Property_map<face_descriptor, Vector> fnormals =
+      m.add_property_map<face_descriptor, Vector>("f:normals", CGAL::NULL_VECTOR).first;
+
+    CGAL::Polygon_mesh_processing::compute_face_normals(m, fnormals);
+
+    for (Edge_index e : m.edges())
+    {
+      Halfedge_index h = e.halfedge();
+      Face_index f1 = m.face(h);
+      Face_index f2 = m.face(m.opposite(h));
+      const Vector& n1 = fnormals[f1];
+      const Vector& n2 = fnormals[f2];
+
+      if (n1*n2 < cos_tolerance)
+      {
+        edge_constrained_map[e] = true;
+        num_protected++;
+      }
+    }
+
+    m.remove_property_map(fnormals);
+
+    dolfin::log(dolfin::TRACE,
+                "Number of protected edges: %u", num_protected);
+  }
+
+  // Remeshing
+  CGAL::Polygon_mesh_processing::isotropic_remeshing(faces(m),
+                                                     edge_length,
+                                                     m,
+                                                     Parameters::edge_is_constrained_map(edge_constrained_map)
+    );
+
+  remeshed_vertices.clear();
+  remeshed_facets.clear();
+
+  std::vector<std::size_t> vertex_index_mapping;
+  vertex_index_mapping.resize(m.num_vertices());
+  int i = 0;
+  for(Vertex_index vd : m.vertices())
+  {
+    const Point& p = m.point(vd);
+    remeshed_vertices.push_back({{CGAL::to_double(p[0]), CGAL::to_double(p[1]), CGAL::to_double(p[2])}});
+    vertex_index_mapping[vd] = i;
+    i++;
+  }
+
+  for (Face_index f : m.faces())
+  {
+    const Halfedge_index h = m.halfedge(f);
+    const Halfedge_index h_next = m.next(h);
+    const Halfedge_index h_next_next = m.next(h_next);
+
+    remeshed_facets.push_back({{vertex_index_mapping[m.source(h)],
+                                vertex_index_mapping[m.source(h_next)],
+                                vertex_index_mapping[m.source(h_next_next)]}});
+  }
+}
+
+} // end namespace mshr
diff --git a/src/TetgenMeshGenerator3D.cpp b/src/TetgenMeshGenerator3D.cpp
new file mode 100644 (file)
index 0000000..a21625d
--- /dev/null
@@ -0,0 +1,248 @@
+// Copyright (C) 2014 Benjamin Kehlet
+//
+// This file is part of mshr.
+//
+// mshr 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 3 of the License, or
+// (at your option) any later version.
+//
+// mshr 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 mshr.  If not, see <http://www.gnu.org/licenses/>.
+//
+
+#include <mshr/TetgenMeshGenerator3D.h>
+
+#include <dolfin/mesh/Mesh.h>
+#include <dolfin/mesh/CellType.h>
+#include <dolfin/mesh/MeshEditor.h>
+#include <dolfin/mesh/MeshPartitioning.h>
+#include <dolfin/log/log.h>
+
+#include <tetgen.h>
+
+// Bounding sphere computation
+#include <CGAL/Cartesian.h>
+#include <CGAL/Min_sphere_of_spheres_d.h>
+#include <CGAL/Min_sphere_of_spheres_d_traits_3.h>
+
+#include <vector>
+#include <array>
+
+namespace
+{
+//-----------------------------------------------------------------------------
+void build_dolfin_mesh(const tetgenio& tetgenmesh, dolfin::Mesh& dolfinmesh)
+{
+  // Clear mesh
+  // dolfin::Mesh::clear has been removed
+  // dolfinmesh.clear();
+
+  // Create and initialize mesh editor
+  dolfin::MeshEditor mesh_editor;
+  mesh_editor.open(dolfinmesh, dolfin::CellType::Type::tetrahedron, 3, 3);
+  mesh_editor.init_vertices(tetgenmesh.numberofpoints);
+
+  const int offset = tetgenmesh.firstnumber;
+
+  for (int i = 0; i < tetgenmesh.numberofpoints; i++)
+  {
+
+    dolfin::Point p(tetgenmesh.pointlist[i * 3],
+                    tetgenmesh.pointlist[i * 3 + 1],
+                    tetgenmesh.pointlist[i * 3 + 2]);
+    mesh_editor.add_vertex(i, p);
+  }
+
+
+  mesh_editor.init_cells(tetgenmesh.numberoftetrahedra);
+  dolfin_assert(tetgenmesh.numberofcorners == 4);
+
+  for (int i = 0; i < tetgenmesh.numberoftetrahedra; i++)
+  {
+    mesh_editor.add_cell(i,
+                         tetgenmesh.tetrahedronlist[i*4 + 0]-offset,
+                         tetgenmesh.tetrahedronlist[i*4 + 1]-offset,
+                         tetgenmesh.tetrahedronlist[i*4 + 2]-offset,
+                         tetgenmesh.tetrahedronlist[i*4 + 3]-offset);
+  }
+
+  // Close mesh editor
+  mesh_editor.close();
+}
+//-----------------------------------------------------------------------------
+double bounding_sphere_radius(const std::vector<double>& vertices)
+{
+  typedef double FT;
+  typedef CGAL::Cartesian<FT> K;
+  typedef CGAL::Min_sphere_of_spheres_d_traits_3<K, FT> MinSphereTraits;
+  typedef CGAL::Min_sphere_of_spheres_d<MinSphereTraits> Min_sphere;
+  typedef MinSphereTraits::Sphere Sphere;
+
+  std::vector<Sphere> S;
+
+  for (std::size_t i = 0; i < vertices.size(); i += 3)
+  {
+    S.push_back(Sphere(K::Point_3( vertices[i],
+                                   vertices[i+1],
+                                   vertices[i+2]), 0.0));
+  }
+
+  Min_sphere ms(S.begin(), S.end());
+  dolfin_assert(ms.is_valid());
+
+  return ms.radius();
+}
+
+} // end anonymous namespace
+//-----------------------------------------------------------------------------
+namespace mshr
+{
+
+TetgenMeshGenerator3D::TetgenMeshGenerator3D()
+{
+  parameters = default_parameters();
+}
+//-----------------------------------------------------------------------------
+TetgenMeshGenerator3D::~TetgenMeshGenerator3D()
+{
+}
+//-----------------------------------------------------------------------------
+std::shared_ptr<dolfin::Mesh>
+TetgenMeshGenerator3D::generate(std::shared_ptr<const CSGCGALDomain3D> domain) const
+{
+  tetgenio in;
+
+  double r;
+  {
+    // Copy the vertices to the tetgen structure
+    dolfin::log(dolfin::TRACE, "Copying vertices");
+    std::unique_ptr<const std::vector<double>> vertices = domain->get_vertices();
+    r = bounding_sphere_radius(*vertices);
+
+    in.numberofpoints = vertices->size()/3;
+    in.pointlist = new REAL[in.numberofpoints * 3];
+
+    for (std::size_t i = 0; i < vertices->size(); i++)
+    {
+      in.pointlist[i] = (*vertices)[i];
+    }
+  }
+
+  // Copy the facets to the tetgen structure
+  {
+    dolfin::log(dolfin::TRACE, "Copying facets");
+    std::unique_ptr<const std::vector<std::size_t>> facets = domain->get_facets();
+
+    in.numberoffacets = facets->size()/3;
+    in.facetlist = new tetgenio::facet[in.numberoffacets];
+    //in.facetmarkerlist = new int[in.numberoffacets];
+
+    for (std::size_t i = 0; i*3 < facets->size(); i++)
+    {
+      tetgenio::facet& f = in.facetlist[i];
+      f.numberofpolygons = 1;
+      f.polygonlist = new tetgenio::polygon[f.numberofpolygons];
+      f.numberofholes = 0;
+      f.holelist = NULL;
+      tetgenio::polygon& p = f.polygonlist[0];
+      p.numberofvertices = 3;
+      p.vertexlist = new int[p.numberofvertices];
+      p.vertexlist[0] = (*facets)[i*3];
+      p.vertexlist[1] = (*facets)[i*3+1];
+      p.vertexlist[2] = (*facets)[i*3+2];
+    }
+  }
+
+  // Mark holes in the domain
+  {
+    dolfin::log(dolfin::TRACE, "Marking holes");
+    std::vector<dolfin::Point> holes;
+    domain->get_points_in_holes(holes);
+
+    in.numberofholes = holes.size();
+    in.holelist = new REAL[in.numberofholes*3];
+    std::size_t i = 0;
+    for (std::vector<dolfin::Point>::const_iterator it = holes.begin();
+         it != holes.end(); it++)
+    {
+      in.holelist[i*3]     = it->x();
+      in.holelist[i*3 + 1] = it->y();
+      in.holelist[i*3 + 2] = it->z();
+    }
+
+    i++;
+  }
+
+  // Release domain object, possibly deleting it
+  domain.reset();
+
+  // set tetgen parameters
+  std::stringstream tetgenparams;
+  tetgenparams << std::fixed << std::setprecision(16);
+
+  // tetrahedralize a plc
+  tetgenparams << "p";
+
+  if (!parameters["disable_quality_improvement"])
+  {
+    // set quality constraints
+    const double ratio = parameters["max_radius_edge_ratio"];
+    const double angle = parameters["min_dihedral_angle"];
+    tetgenparams << "q" << ratio << "/" << angle;
+
+    tetgenparams << "a";
+    if (double(parameters["max_tet_volume"]) > 0)
+    {
+      // set maximum cell volume
+      tetgenparams << double(parameters["max_tet_volume"]);
+    }
+    else
+    {
+      const double resolution = parameters["mesh_resolution"];
+
+      // try to compute reasonable parameters
+      //const double r = bounding_sphere_radius(vertices);
+      const double cell_size = r/static_cast<double>(resolution)*2.0;
+      tetgenparams << cell_size;
+    }
+
+    if (parameters["preserve_surface"])
+    {
+      tetgenparams << "Y";
+    }
+  }
+
+  if (dolfin::get_log_level() > dolfin::DBG)
+  {
+    // set verbosity level
+    tetgenparams << "Q";
+  }
+
+  dolfin::log(dolfin::TRACE, "Calling tetgen with parameters: " + tetgenparams.str());
+
+  // Tetgen requires a char[] (as opposed to a const char[])
+  // so we need to copy of from the string
+  const std::string str = tetgenparams.str();
+  std::unique_ptr<char> writable(new char[str.size() + 1]);
+  std::copy(str.begin(), str.end(), writable.get());
+  writable.get()[str.size()] = '\0'; // terminating 0
+
+  tetgenio out;
+  tetrahedralize(writable.get(), &in, &out);
+
+  std::shared_ptr<dolfin::Mesh> mesh(new dolfin::Mesh());
+  build_dolfin_mesh(out, *mesh);
+
+  // Distribute the mesh (if in parallel)
+  dolfin::MeshPartitioning::build_distributed_mesh(*mesh);
+
+  return mesh;
+}
+//-----------------------------------------------------------------------------
+} // end namespace mshr
diff --git a/src/make_multicomponent_mesh_3.h b/src/make_multicomponent_mesh_3.h
new file mode 100644 (file)
index 0000000..0d6a2db
--- /dev/null
@@ -0,0 +1,61 @@
+// Copyright (C) 2014 Benjamin Kehlet
+//
+// This file is part of mshr.
+//
+// mshr 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 3 of the License, or
+// (at your option) any later version.
+//
+// mshr 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 mshr.  If not, see <http://www.gnu.org/licenses/>.
+
+#ifndef __MSHR_MAKE_MULTICOMPONENT_MESH_3_H
+#define __MSHR_MAKE_MULTICOMPONENT_MESH_3_H
+
+#include <CGAL/make_mesh_3.h>
+#include <CGAL/refine_mesh_3.h>
+
+
+template<class C3T3, class MeshDomain, class MeshCriteria>
+void make_multicomponent_mesh_3_impl(C3T3& c3t3,
+                                     const MeshDomain&   domain,
+                                     const MeshCriteria& criteria,
+                                     const CGAL::parameters::internal::Exude_options& exude,
+                                     const CGAL::parameters::internal::Perturb_options& perturb,
+                                     const CGAL::parameters::internal::Odt_options& odt,
+                                     const CGAL::parameters::internal::Lloyd_options& lloyd,
+                                     const bool with_features,
+                                     const CGAL::parameters::internal::Mesh_3_options& 
+                                     mesh_options = CGAL::parameters::internal::Mesh_3_options())
+{
+  //std::cout << "Number of vertices initially: " << c3t3.triangulation().number_of_vertices() << std::endl;
+
+  // Initialize c3t3 with points from the special features
+  CGAL::internal::Mesh_3::C3t3_initializer< 
+    C3T3,
+    MeshDomain,
+    MeshCriteria,
+    CGAL::internal::Mesh_3::has_Has_features<MeshDomain>::value > () (c3t3,
+                                                                      domain,
+                                                                      criteria,
+                                                                      with_features);
+
+  // std::cout << "Number of vertices after features: " << c3t3.triangulation().number_of_vertices() << std::endl;
+  
+  // Inserts points from all connected components to the mesh
+  CGAL::internal::Mesh_3::init_c3t3(c3t3, domain, criteria, 0);
+  // std::cout << "Number of vertices before meshing: " << c3t3.triangulation().number_of_vertices() << std::endl;
+  
+  // Build mesher and launch refinement process
+  // Don't reset c3t3 as we just created it
+  refine_mesh_3(c3t3, domain, criteria,
+                exude, perturb, odt, lloyd, CGAL::parameters::no_reset_c3t3(), mesh_options);
+}
+
+#endif
diff --git a/src/meshclean.h b/src/meshclean.h
new file mode 100644 (file)
index 0000000..7ca75e3
--- /dev/null
@@ -0,0 +1,562 @@
+// Copyright (C) 2014-2015 Benjamin Kehlet
+//
+// This file is part of mshr.
+//
+// mshr 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 3 of the License, or
+// (at your option) any later version.
+// 
+// mshr 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 mshr. If not, see <http://www.gnu.org/licenses/>.
+//
+
+#ifndef __MESH_CLEAN_H
+#define __MESH_CLEAN_H
+
+#include <CGAL/basic.h>
+#include <CGAL/Kernel/global_functions.h>
+#include <CGAL/Triangle_3.h>
+
+//-----------------------------------------------------------------------------
+// Get squared edge length
+template<typename Polyhedron>
+inline double
+get_edge_length(typename Polyhedron::Halfedge_const_handle halfedge)
+{
+  return CGAL::to_double((halfedge->vertex()->point() -
+    halfedge->opposite()->vertex()->point()).squared_length());
+}
+//-----------------------------------------------------------------------------
+template <typename Polyhedron>
+inline double get_triangle_area(typename Polyhedron::Facet_handle facet)
+{
+  typedef typename Polyhedron::Traits::Triangle_3 Triangle;
+  typename Polyhedron::Halfedge_const_handle h = facet->halfedge();
+  Triangle t(h->vertex()->point(),
+             h->next()->vertex()->point(),
+             h->next()->next()->vertex()->point());
+  return CGAL::to_double(t.squared_area());
+}
+//-----------------------------------------------------------------------------
+template <typename Polyhedron>
+inline typename Polyhedron::Halfedge_handle
+  get_longest_edge(typename Polyhedron::Facet_handle facet)
+{
+  typename Polyhedron::Halfedge_handle current = facet->halfedge();
+  typename Polyhedron::Halfedge_handle longest = current;
+  double length = get_edge_length<Polyhedron>(current);
+
+  current = current->next();
+  if (get_edge_length<Polyhedron>(current) > length)
+  {
+    length = get_edge_length<Polyhedron>(current);
+    longest = current;
+  }
+
+  current = current->next();
+  if (get_edge_length<Polyhedron>(current) > length)
+  {
+    length = get_edge_length<Polyhedron>(current);
+    longest = current;
+  }
+
+  return longest;
+}
+//-----------------------------------------------------------------------------
+template <typename Polyhedron>
+inline typename Polyhedron::Halfedge_const_handle
+  get_longest_const_edge(typename Polyhedron::Facet_const_handle facet)
+{
+  typename Polyhedron::Halfedge_const_handle current = facet->halfedge();
+  typename Polyhedron::Halfedge_const_handle longest = current;
+  double length = get_edge_length<Polyhedron>(current);
+
+  current = current->next();
+  if (get_edge_length<Polyhedron>(current) > length)
+  {
+    length = get_edge_length<Polyhedron>(current);
+    longest = current;
+  }
+
+  current = current->next();
+  if (get_edge_length<Polyhedron>(current) > length)
+  {
+    length = get_edge_length<Polyhedron>(current);
+    longest = current;
+  }
+
+  return longest;
+}
+//-----------------------------------------------------------------------------
+// Compute the distance from the longest edge to the opposite vertex
+template<typename Polyhedron>
+inline double triangle_projection(typename Polyhedron::Facet_const_handle f)
+{
+  typename Polyhedron::Halfedge_const_handle longest = get_longest_const_edge<Polyhedron>(f);
+  typename Polyhedron::Traits::Line_3 l(longest->vertex()->point(), longest->opposite()->vertex()->point());
+  return CGAL::to_double( (l.projection(longest->next()->vertex()->point()) - longest->next()->vertex()->point()).squared_length());
+}
+//-----------------------------------------------------------------------------
+template<typename Polyhedron>
+inline double
+get_min_edge_length(typename Polyhedron::Facet_const_handle facet)
+{
+  typename Polyhedron::Facet::Halfedge_around_facet_const_circulator half_edge
+    = facet->facet_begin();
+  double min_length = CGAL::to_double((half_edge->vertex()->point()
+      - half_edge->opposite()->vertex()->point()).squared_length());
+
+  half_edge++;
+  min_length = std::min(min_length, get_edge_length<Polyhedron>(half_edge));
+
+  half_edge++;
+  min_length = std::min(min_length, get_edge_length<Polyhedron>(half_edge));
+
+  return min_length;
+}
+//-----------------------------------------------------------------------------
+template<typename Polyhedron>
+inline double
+get_max_edge_length(typename Polyhedron::Facet_const_handle facet)
+{
+  typename Polyhedron::Facet::Halfedge_around_facet_const_circulator h = facet->facet_begin();
+  double max_length = get_edge_length<Polyhedron>(h);
+
+  h++;
+  max_length = std::max(max_length, get_edge_length<Polyhedron>(h));
+
+  h++;
+  max_length = std::max(max_length, get_edge_length<Polyhedron>(h));
+
+  return max_length;
+}
+//-----------------------------------------------------------------------------
+template<typename Polyhedron>
+std::size_t get_vertex_id(const Polyhedron& p, typename Polyhedron::Vertex_const_handle v)
+{
+  return std::distance(p.vertices_begin(), v);
+}
+//-----------------------------------------------------------------------------
+template<typename Polyhedron>
+void print_vertex(const Polyhedron& p, typename Polyhedron::Halfedge_const_handle h)
+{
+  typename Polyhedron::Halfedge_const_handle current = h;
+  do
+  {
+    dolfin_assert(current->vertex() == h->vertex());
+    std::cout << get_vertex_id(p, current->opposite()->vertex()) << std::endl;
+
+    current = current->opposite()->prev();
+  } while(current != h);
+}
+
+//-----------------------------------------------------------------------------
+template<typename Polyhedron>
+void print_edge(const Polyhedron& p, typename Polyhedron::Halfedge_const_handle h)
+{
+  std::cout << "(" << get_vertex_id(p, h->opposite()->vertex()) << ": " << h->opposite()->vertex()->point() << ", "
+           << get_vertex_id(p, h->vertex()) << ": " << h->vertex()->point() << ")" << std::endl;
+}
+//-----------------------------------------------------------------------------
+// Print some info about a facet
+// Meant for debugging
+template<typename Polyhedron>
+void print_facet(const Polyhedron& p, typename Polyhedron::Halfedge_const_handle h, bool verbose=true)
+{
+  std::cout << "Vertices: " << std::endl;
+  typename Polyhedron::Halfedge_const_handle current = h;
+  do
+  {
+    std::cout << "  " << get_vertex_id<Polyhedron>(p, current->vertex()) << ": (" << current->vertex()->point() << ") " << std::endl;
+    current = current ->next();
+  } while (current != h);
+  
+  if (verbose)
+  {
+    std::cout << "Edge lengths (squared):" << std::endl;
+    current = h;
+    do
+    {
+      std::cout << "  " << (current->vertex()->point() - current->next()->vertex()->point()).squared_length() << std::endl;
+      current = current->next();
+    } while (current != h);
+  
+    typename Polyhedron::Traits::Triangle_3 t(h->vertex()->point(),
+                                             h->next()->vertex()->point(),
+                                             h->next()->next()->vertex()->point());
+    std::cout << "Area (if triangle): " << t.squared_area() << std::endl;
+  
+    typename Polyhedron::Halfedge_const_handle longest = get_longest_const_edge<Polyhedron>(h->facet());
+    typename Polyhedron::Traits::Line_3 l(longest->vertex()->point(), longest->opposite()->vertex()->point());
+    std::cout << "Colinearity (if triangle): " << triangle_projection<Polyhedron>(h->facet()) << std::endl;
+  }
+}
+//-----------------------------------------------------------------------------
+template<typename Polyhedron>
+inline bool facet_is_degenerate(typename Polyhedron::Facet_const_handle facet,
+                                typename Polyhedron::Traits::FT tol_sq)
+{
+  dolfin_assert(facet->is_triangle());
+
+  return get_min_edge_length<Polyhedron>(facet) < tol_sq
+    || triangle_projection<Polyhedron>(facet) < tol_sq;
+}
+//-----------------------------------------------------------------------------
+template <typename Polyhedron>
+inline double shortest_edge(Polyhedron& p)
+{
+  double shortest = std::numeric_limits<double>::max();
+  for (typename Polyhedron::Halfedge_iterator halfedge = p.halfedges_begin();
+       halfedge != p.halfedges_end(); halfedge++)
+  {
+    const double length = get_edge_length<Polyhedron>(halfedge);
+    shortest = std::min(shortest, length);
+  }
+
+  return shortest;
+}
+//-----------------------------------------------------------------------------
+template<typename Polyhedron>
+int number_of_degenerate_facets(const Polyhedron& p, const double tolerance)
+{
+  int count = 0;
+  for (typename Polyhedron::Facet_const_iterator facet = p.facets_begin();
+       facet != p.facets_end(); facet++)
+  {
+    dolfin_assert(facet->is_triangle());
+    if ( facet_is_degenerate<Polyhedron>(facet, tolerance) )
+      count++;
+  }
+  return count;
+}
+//-----------------------------------------------------------------------------
+template <typename Polyhedron>
+inline bool has_slivers(const Polyhedron& p)
+{
+  for (typename Polyhedron::Vertex_const_iterator vit = p.vertices_begin(); vit != p.vertices_end(); vit++)
+  {
+    if (vit->vertex_degree() < 3)
+    {
+      // Check that this is not on a border (we can have borders eg. when
+      // reading files that must be repaired
+      const typename Polyhedron::Halfedge_around_vertex_const_circulator first = vit->vertex_begin();
+      typename Polyhedron::Halfedge_around_vertex_const_circulator current = first;
+      
+      bool is_border = false;
+
+      do
+      {
+        if ( !current->is_border() )
+          is_border = true;
+
+        current++;
+      } while (current != first);
+
+      if (!is_border)
+        return true;
+    }
+  }
+
+  /* for (typename Polyhedron::Halfedge_const_iterator it = p.halfedges_begin(); */
+  /*      it != p.halfedges_end(); it++) */
+  /* { */
+  /*   if (it->next()->vertex() == it->opposite()->next()->vertex()) */
+  /*   { */
+  /*     return true; */
+  /*   } */
+  /* }   */
+  return false;
+}
+//-----------------------------------------------------------------------------
+template<typename Polyhedron>
+inline bool has_degree3_neighbors(const Polyhedron& p)
+{
+  for (typename Polyhedron::Halfedge_const_iterator it = p.halfedges_begin();
+       it != p.halfedges_end(); it++)
+  {
+    if (it->vertex()->vertex_degree() < 4 &&
+        it->opposite()->vertex()->vertex_degree() < 4)
+      return true;
+  }
+
+  return false;
+}
+//-----------------------------------------------------------------------------
+template<typename Polyhedron>
+inline std::size_t min_vertex_degree(const Polyhedron& p)
+{
+  typename Polyhedron::Vertex_const_iterator vit = p.vertices_begin();
+  std::size_t min_degree = vit->vertex_degree();
+  vit++;
+
+  for (; vit != p.vertices_end(); vit++)
+    min_degree = std::min(min_degree, vit->vertex_degree());
+
+  return min_degree;
+}
+//-----------------------------------------------------------------------------
+#define ASSERT_GOOD_STATE(p) do             \
+{                                           \
+  dolfin_assert(p.is_valid());              \
+  dolfin_assert(p.is_pure_triangle());      \
+  dolfin_assert(!has_slivers(p));           \
+  dolfin_assert(p.is_closed());             \
+  dolfin_assert(min_vertex_degree(p) > 2);  \
+  dolfin_assert(p.size_of_vertices() < 5 || !has_degree3_neighbors(p)); \
+} while(false);
+//-----------------------------------------------------------------------------
+template <typename Polyhedron>
+inline void remove_degree3_center_vertex(Polyhedron& p,
+                                         typename Polyhedron::Halfedge_handle h)
+{
+  // Remove center vertex, but assure the degree of the vertex is 3 and that at least
+  // one of the sides of the incident triangles is short
+  dolfin_assert(h->vertex()->vertex_degree() == 3);
+
+  p.erase_center_vertex(h);
+}
+//-----------------------------------------------------------------------------
+template<typename Polyhedron>
+inline bool remove_degree3_with_short_edges(Polyhedron& p,
+                                            typename Polyhedron::Traits::FT tol_sq)
+{
+  bool removed = false;
+
+  typename Polyhedron::Vertex_iterator vit = p.vertices_begin();
+  typename Polyhedron::Vertex_iterator vertex_end = p.vertices_end();
+  while (vit != vertex_end)
+  {
+    // iterator is invalid if we remove the vertex, so copy and advance now
+    typename Polyhedron::Vertex_handle v = vit;
+    vit++;
+
+    if (v->vertex_degree() < 3)
+      log(dolfin::DBG, "Vertex with degree less than 3 detected");
+
+    if (v->is_trivalent())
+    {
+      typename Polyhedron::Halfedge_handle h = v->halfedge();
+      if (get_edge_length<Polyhedron>(h) < tol_sq ||
+          get_edge_length<Polyhedron>(h->next()) < tol_sq ||
+          get_edge_length<Polyhedron>(h->prev()) < tol_sq)
+      {
+        p.erase_center_vertex(h);
+        removed = true;
+      }
+    }
+  }
+  return removed;
+}
+//-----------------------------------------------------------------------------
+template <typename Polyhedron>
+inline void collapse_edge(Polyhedron& p,
+                          typename Polyhedron::Halfedge_handle edge)
+{
+  ASSERT_GOOD_STATE(p);
+
+  if (edge->vertex()->is_trivalent())
+  {
+    p.erase_center_vertex(edge);
+    ASSERT_GOOD_STATE(p);
+  }
+  else if (edge->opposite()->vertex()->is_trivalent())
+  {
+    p.erase_center_vertex(edge->opposite());
+    ASSERT_GOOD_STATE(p);
+  }
+  else
+  {
+    // Join small triangles with neighbor facets
+
+    // Make sure we don't introduce slivers
+    // (ie. vertices of degree 2)
+    while (edge->next()->vertex()->is_trivalent())
+    {
+      remove_degree3_center_vertex(p, edge->next());
+      ASSERT_GOOD_STATE(p);
+    }
+
+    while (edge->opposite()->next()->vertex()->is_trivalent())
+    {
+      remove_degree3_center_vertex(p, edge->opposite()->next());
+      ASSERT_GOOD_STATE(p);
+    }
+
+    if (edge->vertex()->is_trivalent())
+    {
+      p.erase_center_vertex(edge);
+    }
+    else if (edge->opposite()->vertex()->is_trivalent())
+    {
+      p.erase_center_vertex(edge->opposite());
+    }
+
+    ASSERT_GOOD_STATE(p);
+    dolfin_assert(edge->vertex()->vertex_degree() > 3);
+    
+    edge = p.join_facet(edge->next());
+    dolfin_assert(p.is_valid());
+    dolfin_assert(!has_slivers(p));
+
+    p.join_facet(edge->opposite()->prev());
+    dolfin_assert(p.is_valid());
+
+    dolfin_assert(edge->vertex() != edge->opposite()->vertex());
+    
+    // We can possibly have a sliver now
+
+    // The joined facets are now quads
+    // Join the two close vertices
+    p.join_vertex(edge);
+    ASSERT_GOOD_STATE(p);
+  }
+}
+//-----------------------------------------------------------------------------
+// FIXME: Return the number of edges collapsed
+template <typename Polyhedron>
+bool collapse_short_edges(Polyhedron& p,
+                          typename Polyhedron::Traits::FT tol_sq)
+{
+  // Degree 3 vertices with short incident edges causes problems when collapsing
+  // short edges. The very ad hoc solution that has shown to work is to remove
+  // these center vertices (and by that the short edges)  before collapsing short
+  // edges.
+
+  bool edges_removed = remove_degree3_with_short_edges(p, tol_sq);
+
+  bool removed;
+
+  do
+  {
+    removed = false;
+
+    for (typename Polyhedron::Halfedge_iterator halfedge = p.halfedges_begin();
+        halfedge != p.halfedges_end(); halfedge++)
+    {
+      if (get_edge_length<Polyhedron>(halfedge) < tol_sq)
+      {
+       collapse_edge<Polyhedron>(p, halfedge);
+        ASSERT_GOOD_STATE(p);
+        remove_degree3_with_short_edges(p, tol_sq);
+        removed = true;
+        edges_removed = true;
+       break;
+      }
+    }
+  } while (removed);
+
+  return edges_removed;
+}
+//-----------------------------------------------------------------------------
+template<typename Polyhedron>
+bool flip_edges(Polyhedron& p,
+                typename Polyhedron::Traits::FT tol_sq)
+{
+  typedef typename Polyhedron::Traits::Line_3 Line_3;
+  typedef typename Polyhedron::Traits::Point_3 Point_3;
+  typedef typename Polyhedron::Halfedge_handle Halfedge_handle;
+
+  bool edge_flipped = false;
+  bool done;
+
+  do
+  {
+    done = true;
+
+    for (typename Polyhedron::Facet_iterator facet = p.facets_begin();
+         facet != p.facets_end(); facet++)
+    {
+      dolfin_assert(facet->is_triangle());
+      if (triangle_projection<Polyhedron>(facet) < tol_sq)
+      {
+        dolfin_assert(p.is_pure_triangle());
+        dolfin_assert(p.is_closed());
+
+        typename Polyhedron::Halfedge_handle longest 
+          = get_longest_edge<Polyhedron>(facet);
+
+        if (longest->vertex()->is_trivalent())
+          remove_degree3_center_vertex(p, longest);
+        else if (longest->opposite()->vertex()->is_trivalent())
+          remove_degree3_center_vertex(p, longest->opposite());
+        else
+        {
+        
+          Line_3 l(longest->vertex()->point(),
+                   longest->opposite()->vertex()->point());
+          Point_3 newpoint = l.projection(longest->next()->vertex()->point());
+          Halfedge_handle flipped = p.flip_edge(longest);
+          flipped->vertex()->point() = newpoint;
+
+          ASSERT_GOOD_STATE(p);
+
+          // TODO: Check length of newly created edge and
+          // collapse if necessary.
+          collapse_short_edges(p, tol_sq);
+          done = false;
+          edge_flipped = true;
+        }
+      }
+    }
+  } while (!done);
+
+  return edge_flipped;
+}
+//-----------------------------------------------------------------------------
+template<typename Polyhedron>
+bool has_degenerate_facets(const Polyhedron& p,
+                           typename Polyhedron::Traits::FT tol_sq)
+{
+  for (typename Polyhedron::Facet_const_iterator facet = p.facets_begin();
+       facet != p.facets_end(); facet++)
+  {
+    dolfin_assert(facet->is_triangle());
+    if (facet_is_degenerate<Polyhedron>(facet, tol_sq))
+      return true;
+  }
+  return false;
+}
+//-----------------------------------------------------------------------------
+// Remove degenerate facets of a triangular polyhedron by
+// 1) Collapse edges with squared length less than tolerance
+// 2) Remove (almost) colinear facets by flipping the longest edge of the 
+//    colinear facet. Colinearity defined as the (squared) distance from a
+//    vertex to the opposite edge being less than tolerance
+template<typename Polyhedron>
+bool remove_degenerate(Polyhedron &p, double tolerance)
+{
+  log(dolfin::TRACE, "Cleaning degenerate facets");
+  dolfin_assert(p.is_pure_triangle());
+
+  // Compute squared tolerance
+  typename Polyhedron::Traits::FT tol_sq(tolerance);
+  tol_sq *= tol_sq;
+
+  const bool edges_removed = remove_degree3_with_short_edges(p, tol_sq);
+  if (edges_removed)
+    log(dolfin::TRACE, "Remove degree 3 vertices");
+
+  ASSERT_GOOD_STATE(p);
+
+
+  log(dolfin::TRACE, "  Collapsing short edges");
+  const bool collapsed = collapse_short_edges(p, tol_sq);
+  ASSERT_GOOD_STATE(p);
+
+  // log(dolfin::TRACE, "Shortest edge: %f", shortest_edge());
+  log(dolfin::TRACE, "  Removing colinear facets by edge flipping");
+  const bool flipped = flip_edges(p, tol_sq);
+  ASSERT_GOOD_STATE(p);
+
+  dolfin_assert(!has_degenerate_facets(p, tol_sq));
+
+  return collapsed || flipped;
+}
+
+#endif
diff --git a/src/smoothing.h b/src/smoothing.h
new file mode 100644 (file)
index 0000000..63a89c0
--- /dev/null
@@ -0,0 +1,73 @@
+// Copyright (C) 2016 Benjamin Kehlet
+//
+// This file is part of mshr.
+//
+// mshr 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 3 of the License, or
+// (at your option) any later version.
+//
+// mshr 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 mshr. If not, see <http://www.gnu.org/licenses/>.
+//
+
+#ifndef __SMOOTHING_H
+#define __SMOOTHING_H
+
+namespace mshr
+{
+
+class LaplacianSmoothing
+{
+ public:
+  template<typename Polyhedron>
+  static void smooth(Polyhedron& p, double c=1.0)
+  {
+    typedef typename Polyhedron::Vertex_handle Vertex_handle;
+    typedef typename Polyhedron::Traits::Point_3 Point_3;
+    typedef typename Polyhedron::Traits::Vector_3 Vector_3;
+    typedef typename Polyhedron::Halfedge_around_vertex_const_circulator HV_const_circulator;
+
+    assert(p.is_valid());
+
+    std::vector<std::pair<Vertex_handle, Point_3>> smoothed;
+
+    for (typename Polyhedron::Vertex_iterator vit = p.vertices_begin();
+         vit != p.vertices_end();
+         vit++)
+    {
+      const Point_3 current = vit->point();
+
+      Vector_3 delta;
+
+      const HV_const_circulator h_start = vit->vertex_begin();
+      HV_const_circulator h_current = h_start;
+      do
+      {
+        delta = delta + (h_current->opposite()->vertex()->point()-current);
+        h_current++;
+      } while (h_current != h_start);
+
+      Point_3 p = current + c*delta/vit->vertex_degree();
+
+      // Evaluate exact value to reduce memory usage
+      p.exact();
+
+      smoothed.push_back(std::make_pair(Vertex_handle(vit), p));
+    }
+
+    // Apply the smoothing
+    for (const std::pair<Vertex_handle, Point_3>& s : smoothed)
+    {
+      s.first->point() = s.second;
+    }
+  }
+};
+
+}
+#endif
diff --git a/src/triangulation_refinement.h b/src/triangulation_refinement.h
new file mode 100644 (file)
index 0000000..5c48ec5
--- /dev/null
@@ -0,0 +1,318 @@
+// Copyright (C) 2014 Benjamin Kehlet
+//
+// This file is part of mshr.
+//
+// mshr 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 3 of the License, or
+// (at your option) any later version.
+// 
+// mshr 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 mshr. If not, see <http://www.gnu.org/licenses/>.
+//
+
+#ifndef __TRIANGULATION_REFINEMENT_H
+#define __TRIANGULATION_REFINEMENT_H
+
+#include <dolfin/mesh/MeshEditor.h>
+
+#ifndef DEBUG_TRIANGULATION_REFINEMENT
+  #define DEBUG_TRIANGULATION_REFINEMENT 0
+#endif
+
+namespace 
+{
+  // Simple convenience class for converting from barycentric coordinates wrt to 
+  // a reference triangle.
+  class RefTriangle
+  {
+   public:
+    RefTriangle(dolfin::Point v1, dolfin::Point v2, dolfin::Point v3)
+      : v1(v1), v2(v2), v3(v3) {}
+
+    dolfin::Point barycentric2Point(double l1, double l2, double l3)
+    {
+      const double x = l1*v1.x() + l2*v2.x() + l3*v3.x();
+      const double y = l1*v1.y() + l2*v2.y() + l3*v3.y();
+      const double z = l1*v1.z() + l2*v2.z() + l3*v3.z();
+
+      return dolfin::Point(x, y, z);
+    }
+
+   private:
+    dolfin::Point v1, v2 , v3;
+  };
+  //-----------------------------------------------------------------------------
+  inline dolfin::Point get_edge_point(dolfin::Point a, dolfin::Point b, double f)
+  {
+    // print "Get point {} between {} and {}".format(f, a, b)
+    const dolfin::Point e = b-a;
+    return a + e*f;
+  }
+  //-----------------------------------------------------------------------------
+  inline std::size_t get_edge_vertex(const std::map<std::array<std::size_t,3 >, 
+                                     std::size_t>& edge_vertices, 
+                                     std::size_t a, 
+                                     std::size_t b, 
+                                     std::size_t i, 
+                                     std::size_t N)
+  {
+    const std::array<std::size_t, 3> key{{std::min(a, b), std::max(a, b), a < b ? i : N-i}};
+    std::size_t v = edge_vertices.at(key);
+    // print "getting edge vertex ({}, {}, {}) = {}".format(a, b, i, v)
+    return v;
+  }
+  //-----------------------------------------------------------------------------
+  inline void add_cell(std::vector<std::array<std::size_t, 3> >& triangles, std::array<std::size_t, 3> v)
+  {
+    #if DEBUG_TRIANGULATION_REFINEMENT
+      static std::set<std::pair<std::size_t, std::size_t> > halfedges;
+
+      auto ins = halfedges.insert(std::make_pair(v[0], v[1]));
+      dolfin_assert(ins.second);
+      ins = halfedges.insert(std::make_pair(v[1], v[2]));
+      dolfin_assert(ins.second);
+      ins = halfedges.insert(std::make_pair(v[2], v[0]));
+      dolfin_assert(ins.second);
+    #endif
+
+    triangles.push_back(v);
+  }
+}
+//-----------------------------------------------------------------------------
+// TODO: Use outputiterator to return triangulation instead of vectors to avoid 
+// copying
+void refine_triangulation(const std::vector<dolfin::Point> initial_vertices,
+                          const std::vector<std::array<std::size_t, 3> > initial_triangulation,
+                          std::size_t N,
+                          std::vector<dolfin::Point>& vertices,
+                          std::vector<std::array<std::size_t, 3> >& triangles)
+{
+  const std::size_t num_vertices = initial_vertices.size() + 
+    (N-1)*initial_triangulation.size() + (N+1)*N/2.0;
+  const std::size_t num_triangles = N*N*initial_triangulation.size();
+
+  vertices.clear();
+  triangles.clear();
+  vertices.reserve(num_vertices);
+  triangles.reserve(num_triangles);
+
+  // Add the corner vertices
+  for (const dolfin::Point& p : initial_vertices)
+  {
+    vertices.push_back(p);
+  }
+
+  std::map<std::array<std::size_t, 3>, std::size_t> edge_vertices;
+
+  // Add the "inner" vertices along the edges
+  for (std::size_t i=1; i < N; i++)
+  {
+    for (const std::array<std::size_t, 3>& t : initial_triangulation)
+    {
+      for (std::size_t j = 0; j < 3; j++)
+      {
+        if (t[j] < t[(j+1)%3])
+        {
+          dolfin::Point v = get_edge_point(initial_vertices[t[j]], initial_vertices[t[(j+1)%3]], float(i)/N);
+
+          // NOTE: Some older compilers (eg. gcc on Ubuntu Precise) require the std::array type to be given
+          // explicitly.
+          edge_vertices[std::array<std::size_t,3>{{t[j], t[(j+1)%3], i}}] = vertices.size();
+          vertices.push_back(v/v.norm());
+        }
+      }
+    }
+  }
+
+
+  /***************************** Add the triangles *********************************/
+  std::size_t cell_count = 0;
+  for (const std::array<std::size_t, 3>& triangle : initial_triangulation) 
+  {
+    //std::cout << "Processing triangle (" << triangle[0] << ", " << triangle[1] << ", " << triangle[2] << ")" << std::endl;
+    RefTriangle ref_triangle(initial_vertices[triangle[0]], initial_vertices[triangle[1]], initial_vertices[triangle[2]]);
+    const std::size_t vertex_start = vertices.size();
+
+    for (std::size_t i = 1; i < N; i++)
+    {
+      const double l1 = static_cast<double>(i)/N;
+      for (std::size_t j=1; j < N-i; j++)
+      {
+        // Don't edge along initial vertices
+        if (i+j == N)
+          continue;
+
+        const double l2 = static_cast<double>(j)/N;
+        const double l3 = 1.0 - l1 - l2;
+            
+       dolfin::Point p = ref_triangle.barycentric2Point(l1, l2, l3);
+       p /= p.norm();
+       vertices.push_back(p);
+      }
+    }
+
+    // std::cout << "  Adding corner facets" << std::endl;
+    add_cell(triangles, std::array<std::size_t, 3>{{ triangle[0],
+                          get_edge_vertex(edge_vertices, 
+                                          triangle[0],
+                                          triangle[1], 
+                                          1, N),
+                          get_edge_vertex(edge_vertices,
+                                          triangle[0], triangle[2],
+                                          1, N)}});
+    cell_count += 1;
+
+    add_cell(triangles, std::array<std::size_t, 3>{{triangle[1],
+                         get_edge_vertex(edge_vertices,
+                                         triangle[1], 
+                                         triangle[2],
+                                         1, N),
+                         get_edge_vertex(edge_vertices, 
+                                         triangle[1],
+                                         triangle[0],
+                                         1, N)}});
+    cell_count += 1;
+
+    add_cell(triangles, std::array<std::size_t, 3>{{triangle[2],
+                         get_edge_vertex(edge_vertices,
+                                         triangle[2], 
+                                         triangle[0], 
+                                         1, N),
+                         get_edge_vertex(edge_vertices,
+                                         triangle[2], 
+                                         triangle[1],
+                                         1, N)}});
+    cell_count += 1;
+
+
+    if (N == 2)
+    {
+      // std::cout << "  Refinement level 2: Adding interior cell" << std::endl;
+      add_cell(triangles, std::array<std::size_t, 3>{{get_edge_vertex(edge_vertices, triangle[0], triangle[1], 1, N),
+             get_edge_vertex(edge_vertices, triangle[1], triangle[2], 1, N),
+             get_edge_vertex(edge_vertices, triangle[2], triangle[0], 1, N)}});
+      cell_count += 1;
+    }
+    else
+    {
+      // std::cout << "  Add facets incident to original edges" << std::endl;
+      add_cell(triangles, std::array<std::size_t, 3>{{vertex_start,
+             get_edge_vertex(edge_vertices, triangle[2], triangle[1], 1, N),
+             get_edge_vertex(edge_vertices, triangle[2], triangle[0], 1, N)}});
+      cell_count += 1;
+
+      add_cell(triangles, std::array<std::size_t, 3>{{vertex_start+N-3,
+             get_edge_vertex(edge_vertices, triangle[1], triangle[0], 1, N),
+             get_edge_vertex(edge_vertices, triangle[1], triangle[2], 1, N)}});
+      cell_count += 1;
+
+      add_cell(triangles, std::array<std::size_t, 3>{{ vertices.size() - 1,
+             get_edge_vertex(edge_vertices,triangle[0], triangle[2], 1, N),
+             get_edge_vertex(edge_vertices,triangle[0], triangle[1], 1, N)}});
+      cell_count += 1;
+
+
+      // std::cout << "  Add the facets along the original edges" << std::endl;
+
+      // along edge(triangle[1] <--> triangle[2])
+      add_cell(triangles, std::array<std::size_t, 3>{{vertex_start,
+             get_edge_vertex(edge_vertices,triangle[2], triangle[1], 2, N),
+             get_edge_vertex(edge_vertices,triangle[2], triangle[1], 1, N)}});
+      cell_count += 1;
+
+      for (std::size_t i = 3; i < N; i++)
+      {
+        add_cell(triangles, std::array<std::size_t, 3>{{vertex_start+i-3,
+               vertex_start+i-2,
+               get_edge_vertex(edge_vertices,triangle[2], triangle[1], i-1, N)}});
+        cell_count += 1;
+
+        add_cell(triangles, std::array<std::size_t, 3>{{vertex_start+i-2,
+               get_edge_vertex(edge_vertices,triangle[2], triangle[1], i, N),
+               get_edge_vertex(edge_vertices,triangle[2], triangle[1], i-1, N)}});
+        cell_count += 1;
+      }
+            
+      // along edge(triangle[2], triangle[0])
+      add_cell(triangles, std::array<std::size_t, 3>{{vertex_start,
+             get_edge_vertex(edge_vertices,triangle[2], triangle[0], 1, N),
+             get_edge_vertex(edge_vertices,triangle[2], triangle[0], 2, N)}});
+      cell_count += 1;
+
+      std::size_t current_inner_vertex = 0;
+      for (std::size_t i = 3; i < N; i++)
+      {
+        const std::size_t step = N-2-i+3;
+        add_cell(triangles, std::array<std::size_t, 3>{{vertex_start+current_inner_vertex+step,
+               vertex_start+current_inner_vertex,
+               get_edge_vertex(edge_vertices,triangle[2], triangle[0], i-1, N)}});
+        cell_count += 1;
+
+        add_cell(triangles, std::array<std::size_t, 3>{{get_edge_vertex(edge_vertices,triangle[2], triangle[0], i-1, N),
+               get_edge_vertex(edge_vertices,triangle[2], triangle[0], i, N),
+               vertex_start+current_inner_vertex+step}});
+        cell_count += 1;
+        
+        current_inner_vertex += step;
+      }
+
+      // along edge(triangle[1], triangle[0])
+      add_cell(triangles, std::array<std::size_t, 3>{{vertex_start+N-3,
+             get_edge_vertex(edge_vertices,triangle[1], triangle[0], 2, N),
+             get_edge_vertex(edge_vertices,triangle[1], triangle[0], 1, N)}});
+      cell_count += 1;
+
+      current_inner_vertex = N-3;
+      for (std::size_t i = 3; i < N; i++)
+      {
+        const std::size_t step = N-3-i+3;
+        add_cell(triangles, std::array<std::size_t, 3>{{vertex_start+current_inner_vertex,
+               vertex_start+current_inner_vertex+step,
+               get_edge_vertex(edge_vertices,triangle[1], triangle[0], i-3+2, N)}});
+        cell_count += 1;
+
+        add_cell(triangles, std::array<std::size_t, 3>{{vertex_start+current_inner_vertex+step,
+               get_edge_vertex(edge_vertices,triangle[1], triangle[0], i-3+3, N),
+               get_edge_vertex(edge_vertices,triangle[1], triangle[0], i-3+2, N)}});
+        cell_count += 1;
+            
+        current_inner_vertex += step;
+      }
+    }
+    
+    // std::cout << "  Add the inner facets that don't touch initial edges" << std::endl;
+
+    std::size_t row_offset = 0;
+    for (std::size_t i = 1; i < N-2; i++)
+    {
+      const std::size_t row_length = N-1-i;
+      add_cell(triangles, std::array<std::size_t, 3>{{vertex_start+row_offset,
+             vertex_start+row_offset+row_length,
+             vertex_start+row_offset+1}});
+      cell_count += 1;
+
+      for (std::size_t j = 0; j < N-3-i; j++)
+      {
+        add_cell(triangles,
+                 std::array<std::size_t, 3>{{vertex_start+row_offset+row_length+j,
+                      vertex_start+row_offset+row_length+j+1,
+                      vertex_start+row_offset+j+1}});
+        cell_count += 1;
+
+        add_cell(triangles, std::array<std::size_t, 3>{{vertex_start+row_offset+row_length+j+1,
+               vertex_start+row_offset+j+2,
+               vertex_start+row_offset+j+1}});
+        cell_count += 1;
+      }
+      row_offset += row_length;
+    }
+  }
+}
+
+#endif
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
new file mode 100644 (file)
index 0000000..902248b
--- /dev/null
@@ -0,0 +1,120 @@
+# Copyright (C) 2014 Benjamin Kehlet
+#
+# This file is part of mshr.
+#
+# mshr 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 3 of the License, or
+# (at your option) any later version.
+#
+# mshr 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 mshr.  If not, see <http://www.gnu.org/licenses/>.
+
+# This file defines regression tests. 
+
+# Make sure python finds the mshr module.
+# NOTE: Not sure this is the best way. Is saves the environment at "cmake
+# time" and applies it when running the test. Changing PYTHONPATH
+# later will not have effect. Not sure how to add tp PYTHONPATH at
+# runtime.
+set(PYTHON_ENVIR "$ENV{PYTHONPATH};DOLFIN_NOPLOT=True")
+
+
+############# A python program that just imports dolfin and mshr ##############################
+add_test("Python-DummyImport" "${PYTHON_EXECUTABLE}" "${CMAKE_SOURCE_DIR}/test/dummy.py")
+set_property(TEST "Python-DummyImport" PROPERTY
+    ENVIRONMENT "PYTHONPATH=${PYTHON_ENVIR}"
+)
+
+############# A union which is particularly prone to roundoff errors ##########################
+add_test("Python-DegenerateRemoval" "${PYTHON_EXECUTABLE}" "${CMAKE_SOURCE_DIR}/test/degenerate_removal.py")
+set_property(TEST "Python-DegenerateRemoval" PROPERTY
+    ENVIRONMENT "PYTHONPATH=${PYTHON_ENVIR}"
+)
+
+############# Test the csg operators ##########################################################
+add_test("Python-CSGOperators" "${PYTHON_EXECUTABLE}" "${CMAKE_SOURCE_DIR}/test/test-csg.py")
+set_property(TEST "Python-CSGOperators" PROPERTY
+    ENVIRONMENT "PYTHONPATH=${PYTHON_ENVIR}"
+)
+
+############# Test the fuzzy point map ########################################################
+# This test is disabled since the Surface3D class is about to be removed.
+#add_test("Python-FuzzyPointMap" "${PYTHON_EXECUTABLE}" "${CMAKE_SOURCE_DIR}/test/test-fuzzypointmap.py")
+#set_property(TEST "Python-FuzzyPointMap" PROPERTY
+#    ENVIRONMENT "PYTHONPATH=${PYTHON_ENVIR}"
+#)
+
+############# Test the mesh generation ########################################################
+add_test("Python-MeshGeneration" "${PYTHON_EXECUTABLE}" "${CMAKE_SOURCE_DIR}/test/test-mesh-generation.py")
+set_property(TEST "Python-MeshGeneration" PROPERTY
+    ENVIRONMENT "PYTHONPATH=${PYTHON_ENVIR}"
+)
+
+############# Test the predefined meshes ##########################################################
+add_test("Python-Meshes" "${PYTHON_EXECUTABLE}" "${CMAKE_SOURCE_DIR}/test/test-meshes.py")
+set_property(TEST "Python-Meshes" PROPERTY
+    ENVIRONMENT "PYTHONPATH=${PYTHON_ENVIR}"
+)
+############# Test the ASCFileReader ##########################################################
+add_test("Python-ASCFileReader" "${PYTHON_EXECUTABLE}" "${CMAKE_SOURCE_DIR}/test/test-ASCFileReader.py")
+set_property(TEST "Python-ASCFileReader" PROPERTY
+    ENVIRONMENT "PYTHONPATH=${PYTHON_ENVIR}"
+)
+
+############# Test the ASCFileReader ##########################################################
+add_test("Python-NumSegments2D" "${PYTHON_EXECUTABLE}" "${CMAKE_SOURCE_DIR}/test/test-num-segments-2d.py")
+set_property(TEST "Python-NumSegments2D" PROPERTY
+    ENVIRONMENT "PYTHONPATH=${PYTHON_ENVIR}"
+)
+
+############# Test the CSG predicates (2D) ##########################################################
+add_test("Python-CSGPredicates2D" "${PYTHON_EXECUTABLE}" "${CMAKE_SOURCE_DIR}/test/test-csg-predicates.py")
+set_property(TEST "Python-CSGPredicates2D" PROPERTY
+  ENVIRONMENT "PYTHONPATH=${PYTHON_ENVIR}"
+  )
+
+############# Test CSG primitves (2D) ##########################################################
+add_test("Python-CSGPrimitives2D" "${PYTHON_EXECUTABLE}" "${CMAKE_SOURCE_DIR}/test/test-csg-primitives-2d.py")
+set_property(TEST "Python-CSGPredicates2D" PROPERTY
+  ENVIRONMENT "PYTHONPATH=${PYTHON_ENVIR}"
+)
+
+############# Try meshing some surface files found in the cgal source ########################
+# TODO: Print mesh quality measure from program and check the value
+set(CGAL_DATA_DIR "${CMAKE_SOURCE_DIR}/3rdparty/CGAL/demo/Polyhedron/data")
+
+# Files that should pass
+# Note elephant.off is valid a should passes but takes a very long (so test slave may time out)
+set(TESTFILES_VALID "anchor.off;couplingdown.off;cross.off;cube.off;dragknob.off;ellipsoid.off;handle.off;icosahedron.off;joint.off;knot1.off;knot2.off;pinion.off;pipe.off;rotor.off;sphere.off;spool.off;star.off;translated-cube.off;tripod.off")
+set(TESTFILES_SELFINTERSECTING "bones.off;cow.off;man.off;oblong.ogg")
+set(TESTFILES_NOTCLOSED "cube-ouvert.off;mushroom.off")
+set(TESTFILES_NOTTRIANGULAR "pyramid.off")
+
+foreach(CURRENT_DATA_FILE IN LISTS TESTFILES_VALID)
+  message(STATUS "Adding test: ${CURRENT_DATA_FILE}")
+  add_test(FilePass-cgal-${CURRENT_DATA_FILE} ../mshrable -s -b cgal --check-mesh ${CGAL_DATA_DIR}/${CURRENT_DATA_FILE})
+  add_test(FilePass-tetgen-${CURRENT_DATA_FILE} ../mshrable -s -b tetgen --check-mesh ${CGAL_DATA_DIR}/${CURRENT_DATA_FILE})
+endforeach(CURRENT_DATA_FILE)
+
+
+##############  CPP tests
+add_executable(cppTestCSGGeometries test-csggeometries.cpp)
+target_link_libraries(cppTestCSGGeometries mshr)
+add_test(CPP-CSGGeometries cppTestCSGGeometries)
+
+
+############ Run the demos as regression test ################################################
+file(GLOB PYTHONDEMOS "${CMAKE_SOURCE_DIR}/demo/python/*.py")
+foreach(CURRENT_DEMO IN LISTS PYTHONDEMOS)
+  add_test("PythonDemo-${CURRENT_DEMO}" "${PYTHON_EXECUTABLE}" "${CURRENT_DEMO}")
+  set_property(TEST "PythonDemo-${CURRENT_DEMO}" PROPERTY
+    ENVIRONMENT "PYTHONPATH=${PYTHON_ENVIR}"
+  )
+
+endforeach()
diff --git a/test/degenerate_removal.py b/test/degenerate_removal.py
new file mode 100644 (file)
index 0000000..84eff52
--- /dev/null
@@ -0,0 +1,14 @@
+from mshr import *
+
+# This union of spheres challenges the removal of degenerate facets
+# since the intersection polyline of the two spheres matches lines in
+# the triangulation of the spheres. Because of that roundoff errors
+# introduces a lot of very small triangles when the union is carried
+# out.
+
+a = Sphere(dolfin.Point(0,0,0), .5)
+b = Sphere(dolfin.Point(.5,0,0), .5)
+
+domain = CSGCGALDomain3D(a+b)
+domain.ensure_meshing_preconditions()
+
diff --git a/test/dummy.py b/test/dummy.py
new file mode 100644 (file)
index 0000000..d85bf5a
--- /dev/null
@@ -0,0 +1,5 @@
+import dolfin
+import mshr
+
+
+
diff --git a/test/test-ASCFileReader.py b/test/test-ASCFileReader.py
new file mode 100644 (file)
index 0000000..5d081da
--- /dev/null
@@ -0,0 +1,23 @@
+from dolfin import *
+from mshr import *
+
+import os
+import tempfile
+
+def save_surface(filename) :
+        geometry = Sphere(Point(0.0,0.0,0.0),10.)
+        domain = CSGCGALDomain3D(geometry)
+        domain.save(filename)
+
+def load_surface(filename) :
+        surf  = Surface3D(filename)
+        domain = CSGCGALDomain3D(surf)
+        mesh = generate_mesh(domain, 10)
+
+fd, temp_path = tempfile.mkstemp(suffix='.asc')
+
+save_surface(temp_path)
+load_surface(temp_path)
+
+os.close(fd)
+os.remove(temp_path)
diff --git a/test/test-csg-predicates.py b/test/test-csg-predicates.py
new file mode 100644 (file)
index 0000000..7970161
--- /dev/null
@@ -0,0 +1,38 @@
+from dolfin import *
+import mshr
+import math
+
+
+r = mshr.Rectangle(Point(0,-.5), Point(4,.5))
+
+# Trivial inside outside
+assert r.inside(Point( .5,  .0))
+assert not r.inside(Point(1.5, 1.5))
+
+rotated = mshr.CSGRotation(r, math.pi/2)
+assert not rotated.inside(Point(1.5, 1.5))
+assert rotated.inside(Point(0., 1.5))
+assert not rotated.inside(Point(0., 4.5))
+assert not rotated.inside(Point(0., -.5))
+
+# Translation
+translated = mshr.CSGTranslation(rotated, Point(2, 1))
+assert translated.inside(Point(2, 1.5))
+assert not translated.inside(Point(0, 1.5))
+
+# Circle
+c = mshr.Circle(Point(2, 1), .5)
+assert c.inside(Point(2, 1))
+assert not c.inside(Point(3, 1))
+
+c_rotated = mshr.CSGRotation(c, Point(2,1), math.pi)
+assert c_rotated.inside(Point(2,1))
+assert not c_rotated.inside(Point(3, 1))
+
+c_rotated_2 = mshr.CSGRotation(c_rotated, pi/2)
+assert not c_rotated_2.inside(Point(2,1))
+assert c_rotated_2.inside(Point(-1,2))
+
+# Rectangle and box with the vertices not ordered
+assert mshr.Rectangle(Point(0,0),Point(-1,-1)).inside(Point(-0.5,-0.5))
+#assert mshr.Box(Point(0,0,0),Point(-1,-1,-1)).inside(Point(-0.5,-0.5,-0.5))
diff --git a/test/test-csg-primitives-2d.py b/test/test-csg-primitives-2d.py
new file mode 100644 (file)
index 0000000..bb09da1
--- /dev/null
@@ -0,0 +1,9 @@
+from dolfin import *
+from mshr import *
+
+# Polygon with list of points as argument
+p = Polygon([Point(0, 0), Point(1, 1), Point(0, 1)])
+
+# Polygon with tuple of points as argument
+p = Polygon( (Point(0, 0), Point(1, 1), Point(0, 1)) )
+
diff --git a/test/test-csg.py b/test/test-csg.py
new file mode 100644 (file)
index 0000000..beae7e5
--- /dev/null
@@ -0,0 +1,39 @@
+from mshr import *
+from dolfin import *
+import math
+
+epsilon = 1e-11
+
+def test_volume_exact(g, exact) :
+    domain = CSGCGALDomain3D(g)
+    vol = domain.volume()
+    assert abs(vol-exact) < epsilon, "Computed volume of {} was {}, but expected {}.".format(g.str(False), vol, exact)
+
+def test_volume_bounds(g, lower, upper) :
+    domain = CSGCGALDomain3D(g)
+    vol = domain.volume()
+    assert vol <= upper and vol >= lower, "Computed volume of {} was {}, but expected to be in [{}, {}]".format(g.str(False), vol, lower, upper)
+
+    
+### Test volume of primitives
+# Sphere
+test_volume_bounds(Sphere(Point(1,1,1), 1), 3.8/3.*math.pi, 4./3.0*math.pi)
+
+# TODO: Add primitives
+
+# Test union
+test_volume_exact(Box(Point(0,0,0), Point(2,2,2)) + Box(Point(-1,-1,-1), Point(1,1,1)), 15)
+
+# TODO: Add operators
+
+# Test translation
+c = Cylinder(Point(-1, 1, 2), Point(3.5, -1, 2), 2, 3)
+test_volume_exact(c, CSGCGALDomain3D(CSGTranslation(c, Point(2, 4, -5))).volume())
+
+# Test rotation
+e = Ellipsoid(Point(1,2,3), 2,4,6)
+test_volume_exact(e, CSGCGALDomain3D(CSGRotation(e, Point(1,1,1), math.pi/2.)).volume())
+
+# Test scaling
+s = Sphere(Point(0,0,0), 2)
+test_volume_exact(CSGScaling(s, 2), CSGCGALDomain3D(s).volume()*8)
diff --git a/test/test-csggeometries.cpp b/test/test-csggeometries.cpp
new file mode 100644 (file)
index 0000000..8230400
--- /dev/null
@@ -0,0 +1,30 @@
+// Copyright (C) 2017 Benjamin Kehlet
+//
+// This file 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 3 of the License, or
+// (at your option) any later version.
+//
+// This file 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 DOLFIN. If not, see <http://www.gnu.org/licenses/>.
+//
+
+#include <dolfin/mesh/Mesh.h>
+#include <dolfin/generation/RectangleMesh.h>
+#include <mshr/CSGGeometries3D.h>
+
+int main(int /* argc */, char** /* argv */)
+{
+  std::shared_ptr<dolfin::Mesh> m =
+    std::make_shared<dolfin::RectangleMesh>( dolfin::Point(1., 2.), dolfin::Point(2., 4.),
+                                            5, 6);
+
+  std::shared_ptr<mshr::CSGGeometry> g = mshr::CSGGeometries::import_mesh(m);
+      
+  return 0;
+}
diff --git a/test/test-fuzzypointmap.py b/test/test-fuzzypointmap.py
new file mode 100644 (file)
index 0000000..8067a4f
--- /dev/null
@@ -0,0 +1,108 @@
+import mshr
+import tempfile, os, sys
+
+# A simple unit cube but with some vertices perturbed slightly to test the FuzzyPointMap
+cube = """
+solid ascii
+facet normal 0 0 0
+  outer loop
+    vertex 1e-12 0 1
+    vertex 0 1 0
+    vertex 0 -1e-11 0
+  endloop
+endfacet
+
+facet normal 0 0 0
+outer loop
+  vertex 0 0 1
+  vertex 0 1 1
+  vertex 0 1 1e-13
+endloop
+endfacet
+facet normal 0 0 0
+outer loop
+  vertex 0 0 1
+  vertex 1 0 1
+  vertex 0 1 1
+endloop
+endfacet
+facet normal 0 0 0
+outer loop
+  vertex 1 0 1
+  vertex 1 1 1
+  vertex 0 1 1
+endloop
+endfacet
+facet normal 0 0 0
+outer loop
+  vertex 1 0 1
+  vertex 1 0 0
+  vertex 1 1 1
+endloop
+endfacet
+facet normal 0 0 0
+outer loop
+  vertex 1 0 0
+  vertex 1 1 0
+  vertex 1 1 1
+endloop
+endfacet
+facet normal 0 0 0
+outer loop
+  vertex 1 0 0
+  vertex 0 0 0
+  vertex 1 1 0
+endloop
+endfacet
+facet normal 0 0 0
+outer loop
+  vertex 0 0 0
+  vertex 0 1 0
+  vertex 1 1 0
+endloop
+endfacet
+facet normal 0 0 0
+outer loop
+  vertex 1 1 1
+  vertex 1 1 0
+  vertex 0 1 1
+endloop
+endfacet
+facet normal 0 0 0
+outer loop
+  vertex 1 1 0
+  vertex 0 1 0
+  vertex 0 1 1
+endloop
+endfacet
+facet normal 0 0 0
+outer loop
+  vertex 0 0 1
+  vertex 0 0 0
+  vertex 1 0 1
+endloop
+endfacet
+facet normal 0 0 0
+outer loop
+  vertex 0 0 0
+  vertex 1 0 0
+  vertex 1 0 1
+endloop
+endfacet
+endsolid
+"""
+
+# In python 3 convert the text from unicode to a "classic" str
+if sys.version_info[0] >= 3 :
+    cube = cube.encode("ascii")
+
+fd, filename = tempfile.mkstemp(suffix=".stl")
+os.write(fd, cube)
+os.close(fd)
+
+s = mshr.Surface3D(filename)
+d = mshr.CSGCGALDomain3D(s)
+
+os.remove(filename)
+
+assert d.num_holes() == 0
diff --git a/test/test-mesh-generation.py b/test/test-mesh-generation.py
new file mode 100644 (file)
index 0000000..7c6cfba
--- /dev/null
@@ -0,0 +1,10 @@
+import mshr
+from dolfin import *
+
+# issue 37
+g = mshr.Rectangle(Point(0.0, 0.0), Point(2.2, .41)) - mshr.Circle(Point(.2, .2), .05, 40)
+m = mshr.generate_mesh(g, 50)
+
+# issue 41 (failed only in parallel)
+c = mshr.Extrude2D(mshr.Circle(Point(0, 0, 0), 1), 1)
+m = mshr.generate_mesh(c, 10)
diff --git a/test/test-meshes.py b/test/test-meshes.py
new file mode 100644 (file)
index 0000000..20be703
--- /dev/null
@@ -0,0 +1,6 @@
+from dolfin import *
+import mshr
+
+# Unit sphere mesh
+m = mshr.UnitSphereMesh(4)
+m = mshr.UnitSphereMesh(10) 
diff --git a/test/test-num-segments-2d.py b/test/test-num-segments-2d.py
new file mode 100644 (file)
index 0000000..e1c2273
--- /dev/null
@@ -0,0 +1,13 @@
+from dolfin import *
+import mshr
+
+# The ellipse is completely contained in the circle and will not be
+# visible in the resulting mesh, but it is so small that with
+# mesh_resolution = 10 that when converting it to a polygon the number
+# of segments in the polygon will be 0 (ie. the polygon is degenerate)
+# if not handled correctly.
+c = mshr.Circle(Point(0, 0), 1.5)
+e = mshr.Ellipse(Point(.05, 0), .01, .05)
+
+mesh = mshr.generate_mesh(c+e, 10)
+
diff --git a/test/test.cpp b/test/test.cpp
new file mode 100644 (file)
index 0000000..19d17d1
--- /dev/null
@@ -0,0 +1,142 @@
+// Copyright (C) 2013 Benjamin Kehlet
+//
+// This file 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 3 of the License, or
+// (at your option) any later version.
+//
+// This file 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 DOLFIN. If not, see <http://www.gnu.org/licenses/>.
+//
+// First added:  2013-10-03
+// Last changed: 2013-10-03
+
+#include <intersection_segments.h>
+#include <PolyhedronFactory.h>
+#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
+#include <CGAL/Polyhedron_3.h>
+#include <CGAL/IO/Polyhedron_iostream.h>
+#include <iostream>
+
+typedef CGAL::Exact_predicates_exact_constructions_kernel Kernel;
+typedef Kernel::Point_3 Point;
+typedef Kernel::Triangle_3 Triangle;
+typedef CGAL::Polyhedron_3<Kernel> Polyhedron;
+typedef typename Polyhedron::Facet_handle Facet_handle;
+typedef typename Polyhedron::Halfedge_handle Halfedge_handle;
+typedef typename Kernel::Segment_3 Segment;
+
+void two_tetrahedrons()
+{
+  Polyhedron a;
+
+  make_tetrahedron(a, 
+                   Point(1.0, 0.0, 0.0),
+                   Point(2.0, 0.0, 0.0),
+                   Point(1.5, 1.0, 0.0),
+                   Point(1.5, .5, 10.0));
+
+  Polyhedron b;
+  make_tetrahedron(b,
+                   Point(0.0, 0., .5),
+                   Point(0.0, 0.0, 1.5),
+                   Point(0.0, 1.0, 1.0),
+                   Point(10.0, .5, 1.0));
+
+  if (a.is_pure_triangle())
+    std::cout << "a is pure triangle" << std::endl;
+
+  if (b.is_pure_triangle())
+    std::cout << "b is pure triangle" << std::endl;
+
+  Polyhedron &biggest = a.size_of_facets() > b.size_of_facets() ? a : b;
+  Polyhedron &smallest = a.size_of_facets() > b.size_of_facets() ? b : a;
+
+  std::list<std::list<boost::tuple<Facet_handle, Facet_handle, Segment> > > polylines;
+  {
+    std::list<boost::tuple<Facet_handle, Facet_handle, Segment> > intersections;
+    compute_intersections(biggest, smallest, std::back_inserter(intersections));
+
+    for (std::list<boost::tuple<Facet_handle, Facet_handle, Segment> >::iterator it = intersections.begin();
+         it != intersections.end(); it++)
+    {
+      {
+        Halfedge_handle h = it->get<0>()->halfedge();
+        Triangle t(h->vertex()->point(), h->next()->vertex()->point(), h->next()->next()->vertex()->point());
+        assert(t.has_on(it->get<2>().source()));
+        assert(t.has_on(it->get<2>().target()));
+      }
+      {
+        Halfedge_handle h = it->get<1>()->halfedge();
+        Triangle t(h->vertex()->point(), h->next()->vertex()->point(), h->next()->next()->vertex()->point());
+        assert(t.has_on(it->get<2>().source()));
+        assert(t.has_on(it->get<2>().target()));
+      }
+    }
+    sort_polylines<Polyhedron>(biggest, smallest, intersections, polylines);
+  }
+
+  std::list<std::vector<typename Polyhedron::Halfedge_handle> > intersection_list;
+
+  split_facets<Polyhedron, 0>(biggest,  polylines, intersection_list);
+  //split_facets<Polyhedron, 1>(smallest, polylines);
+
+}
+
+void two_boxes()
+{
+  Polyhedron a;
+  make_box(0,0,0, 4, 5, 2, a);
+
+  Polyhedron b;
+  make_box(1, 1, -1, 2, 2, 1, b);
+
+  if (a.is_pure_triangle())
+    std::cout << "a is pure triangle" << std::endl;
+
+  if (b.is_pure_triangle())
+    std::cout << "b is pure triangle" << std::endl;
+
+  Polyhedron &biggest = a.size_of_facets() > b.size_of_facets() ? a : b;
+  Polyhedron &smallest = a.size_of_facets() > b.size_of_facets() ? b : a;
+
+  std::list<std::list<boost::tuple<Facet_handle, Facet_handle, Segment> > > polylines;
+  {
+    std::list<boost::tuple<Facet_handle, Facet_handle, Segment> > intersections;
+    compute_intersections(biggest, smallest, std::back_inserter(intersections));
+
+    for (std::list<boost::tuple<Facet_handle, Facet_handle, Segment> >::iterator it = intersections.begin();
+         it != intersections.end(); it++)
+    {
+      {
+        Halfedge_handle h = it->get<0>()->halfedge();
+        Triangle t(h->vertex()->point(), h->next()->vertex()->point(), h->next()->next()->vertex()->point());
+        assert(t.has_on(it->get<2>().source()));
+        assert(t.has_on(it->get<2>().target()));
+      }
+      {
+        Halfedge_handle h = it->get<1>()->halfedge();
+        Triangle t(h->vertex()->point(), h->next()->vertex()->point(), h->next()->next()->vertex()->point());
+        assert(t.has_on(it->get<2>().source()));
+        assert(t.has_on(it->get<2>().target()));
+      }
+    }
+    sort_polylines<Polyhedron>(biggest, smallest, intersections, polylines);
+  }
+
+  std::list<std::vector<Halfedge_handle> > a_edges;
+  split_facets<Polyhedron, 0>(biggest, polylines, a_edges);
+  check_splitting<Polyhedron, 0>(biggest, polylines, a_edges);
+  //split_facets<Polyhedron, 1>(smallest, /* smallest, */ polylines);
+}
+
+int main(int argc, char** argv)
+{
+  two_boxes();
+  return 0;
+}
diff --git a/test/test2.cpp b/test/test2.cpp
new file mode 100644 (file)
index 0000000..1c375c4
--- /dev/null
@@ -0,0 +1,54 @@
+// Copyright (C) 2012 Anders Logg
+//
+// This file is part of DOLFIN.
+//
+// DOLFIN 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 3 of the License, or
+// (at your option) any later version.
+//
+// DOLFIN 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 DOLFIN. If not, see <http://www.gnu.org/licenses/>.
+//
+// Modified by Benjamin Kehlet, 2012
+// Modified by Johannes Ring, 2012
+// Modified by Joachim B Haga, 2012
+
+#include <dolfin.h>
+#include <mshr.h>
+
+int main(int argc, char** argv)
+{
+  // Define 3D geometry
+  mshr::Box box(0, 0, 0, 1, 1, 1);
+  mshr::Sphere sphere(dolfin::Point(0, 0, 0), 0.3);
+  mshr::Cone cone(dolfin::Point(0, 0, -1), dolfin::Point(0, 0, 1), .5, .5);
+
+  const boost::shared_ptr<mshr::CSGGeometry> g3d = box + cone - sphere;
+
+  // Test printing
+  dolfin::info("\nCompact output of 3D geometry:");
+  dolfin::info(*g3d);
+  dolfin::info("\nVerbose output of 3D geometry:");
+  dolfin::info(*g3d, true);
+
+  // Plot geometry
+  //dolfin::plot(g3d, "3D geometry (surface)");
+
+  // Generate and plot mesh
+  dolfin::Mesh mesh3d;
+
+  mshr::CSGMeshGenerator::generate(mesh3d, *g3d, 24);
+  dolfin::cout << "Done generating mesh" << dolfin::endl;
+  dolfin::info(mesh3d);
+  dolfin::plot(mesh3d, "3D mesh");
+
+  dolfin::interactive();
+
+  return 0;
+}
diff --git a/test/test3D.cpp b/test/test3D.cpp
new file mode 100644 (file)
index 0000000..5b8f961
--- /dev/null
@@ -0,0 +1,51 @@
+// Copyright (C) 2012 Anders Logg
+//
+// This file is part of mshr.
+//
+// mshr 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 3 of the License, or
+// (at your option) any later version.
+// 
+// mshr 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 mshr.  If not, see <http://www.gnu.org/licenses/>.
+//
+
+#include <dolfin.h>
+#include <mshr.h>
+
+int main(int argc, char** argv)
+{
+  // Define 3D geometry
+  mshr::Box box(0, 0, 0, 1, 1, 1);
+  mshr::Sphere sphere(dolfin::Point(0, 0, 0), 0.3);
+  mshr::Cone cone(dolfin::Point(0, 0, -1), dolfin::Point(0, 0, 1), .5, .5);
+
+  const boost::shared_ptr<mshr::CSGGeometry> g3d = box + cone - sphere;
+
+  // Test printing
+  dolfin::info("\nCompact output of 3D geometry:");
+  dolfin::info(*g3d);
+  dolfin::info("\nVerbose output of 3D geometry:");
+  dolfin::info(*g3d, true);
+
+  // Plot geometry
+  //dolfin::plot(g3d, "3D geometry (surface)");
+
+  // Generate and plot mesh
+  dolfin::Mesh mesh3d;
+
+  mshr::CSGMeshGenerator::generate(mesh3d, *g3d, 24);
+  dolfin::cout << "Done generating mesh" << dolfin::endl;
+  dolfin::info(mesh3d);
+  dolfin::plot(mesh3d, "3D mesh");
+
+  dolfin::interactive();
+
+  return 0;
+}
diff --git a/use-mshr.cmake b/use-mshr.cmake
new file mode 100644 (file)
index 0000000..1062c30
--- /dev/null
@@ -0,0 +1,24 @@
+#
+# This file sets up include directories, link directories, and
+# compiler settings for a project to use mshr. It should not be
+# included directly, but rather through the DOLFIN_USE_FILE setting
+# obtained from mshr-config.cmake.
+#
+
+if (NOT MSHR_USE_FILE_INCLUDED)
+  set(MSHR_USE_FILE_INCLUDED 1)
+
+  # Add compiler definitions needed to use mshr
+  add_definitions(${MSHR_CXX_DEFINITIONS})
+
+  # Add compiler flags needed to use MSHR
+  set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${MSHR_CXX_FLAGS}")
+
+  # Add include directories needed to use MSHR
+  include_directories(${MSHR_INCLUDE_DIRS})
+  include_directories(SYSTEM ${MSHR_EXTERNAL_INCLUDE_DIRS})
+
+  # Add link directories needed to use MSHR
+  message(STATUS "Setting link directories")
+  link_directories(${MSHR_LIBRARIES_DIRS})
+endif()