最終更新日: 2022/05/12 作成日: 2022/05/11
このページの概要

C++のライブラリであるCGAL(The Computational Geometry Algorithms Library)を使うための準備について

tags: #CGAL

CGALとは

CGAL (The Computational Geometry Algorithms Library) は,Wikipediaによると「計算幾何学分野におけるアルゴリズムに効果的で信頼性があり、かつ簡易なアクセスを提供することを目的としたソフトウェア」とのこと. 具体的には,2次元や3次元の三角分割 とか,表面再構成 とかやってくれる. また「オリジナルはC++言語で書かれているが、Python言語のバインディングも利用可能」らしいが,ここではC++の場合について書く.

2022年5月時点ではCGALは5.4が最新の安定版である.

CGALを使うための準備(Linux/macOSのみ)

  1. C++のライブラリBoost C++ Library が必要である.

    Ubuntuで管理者権限がある場合,

    bash
    1
    
    $ sudo apt install libboost-dev

    CentOSだと管理者権限があれば,

    bash
    1
    
    $ sudo yum install -y boost-devel

    macOSだと,Homebrew を入れていれば,

    bash
    1
    
    $ brew install boost

    で簡単に入れられる.

    UbuntuやCentOSで管理者権限がない場合は,ホームディレクトリ以下に適当にディレクトリを作って,そこにダウンロードして適当にゴニョゴニョすればよい. (https://www.boost.org/doc/libs/1_79_0/more/getting_started/unix-variants.html を見れば最新版について記されているはず.) 以下では具体的には,~/.sh/boost/という隠しディレクトリにBoost 1.79.0を入れる例を記す.

    bash
    1
    2
    3
    4
    5
    6
    7
    8
    
    $ mkdir -p ~/.sh/boost/
    $ cd ~/.sh/boost/
    $ wget https://boostorg.jfrog.io/artifactory/main/release/1.79.0/source/boost_1_79_0.tar.gz
    $ tar zxvf boost_1_79_0.tar.gz
    $ cd boost_1_79_0
    $ bootstrap.sh
    $ ./b2 headers
    $ echo 'export LD_LIBRARY_PATH=$HOME/.sh/boost/boost_1_79_0/:$LD_LIBRARY_PATH' >> ~/.bash_profile

    留意1:zshの場合は最後のecho~/.bash_profileのところを書き換えないといけないはず. 留意2:Boost もだいたいが header-only ライブラリとして使えるので今回はコンパイルはしなくてよい.

  2. CGALが依存するライブラリを入れる. GNU Multiple Precision Arithmetic (GMP)GNU Multiple Precision Floating-Point Reliably (MPFR) Libraries のこと.GMPはUbuntuで管理者権限があると

    bash
    1
    
    $ sudo apt-get install libgmp3-dev libmpfr-dev

    で入る.CentOSでは

    bash
    1
    
    $ sudo yum install gmp-devel mpfr

    で入る. macOSの場合は,

    bash
    1
    
    $ brew install gmp mpfr

    でよい.

  3. CGALを持ってくる.これも実はUbuntuで管理者権限があれば簡単で

    bash
    1
    
    $ sudo apt-get install libcgal-dev

    とすればよい.またmacOSでは

    bash
    1
    
    $ brew install cgal

    で準備が整う. 管理者権限がない場合は,https://github.com/CGAL/cgal/releases からCGALの最新版を,たとえば~/.sh/cgal/にダウンロードする.以下はその例.

    bash
    1
    2
    3
    4
    5
    
    $ mkdir -p ~/.sh/cgal/
    $ cd ~/.sh/cgal/
    $ wget https://github.com/CGAL/cgal/releases/download/v5.4/CGAL-5.4.tar.xz
    $ tar xvf CGAL-5.4.tar.xz
    $ echo 'export LD_LIBRARY_PATH=$HOME/.sh/cgal/CGAL-5.4/:$LD_LIBRARY_PATH' >> ~/.bash_profile

    留意:zshの場合は最後のecho~/.bash_profileのところを書き換えないといけないはず.

  4. CMakeLists.txtを用意する. CMakeについては,CMakeの使い方(その1) などで速習できる. CMake(やg++)のバージョンが古いとCGALがコンパイルできないという問題もあるが,以下ではそれらの問題はクリアされているとする.

    基本的に自分でCMakeLists.txtを書かないで,C++のコードが~/Work/C++/test/にある場合,

    bash
    1
    2
    
    $ cd ~/Work/C++/test/
    $ cgal_create_CMakeLists -s main

    とするとCMakeLists.txtが自動で作成される.-s testのtestは適当に変更してよいはず. 管理者権限がなくて,yumとかaptでCGALを準備できなかった場合は,cgal_create_CMakeListsがないと言われるので,~/.sh/cgal/にCGALを入れた上の例の場合では

    bash
    1
    
    $ ~/.sh/cgal/CGAL-5.4/scripts/cgal_create_CMakeLists -s main

    CMakeLists.txtを生成してくれるはず.

上記の準備でだいたいCGALが使えるようになっているはず.

CGALを使う

とりあえずサンプルソースコードがコンパイルできて実行できるか確かめる. https://doc.cgal.org/latest/Periodic_3_mesh_3/Periodic_3_mesh_3_2mesh_implicit_shape_with_subdomains_8cpp-example.html にある3D Periodic Mesh Generationを実行できるか試してみる. ~/Work/C++/test/に上のソースコードを貼り付けるなりしてtest.cppを作成する.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
#include <CGAL/Periodic_3_mesh_3/config.h>
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include <CGAL/Implicit_to_labeled_subdomains_function_wrapper.h>
#include <CGAL/make_periodic_3_mesh_3.h>
#include <CGAL/Periodic_3_mesh_3/IO/File_medit.h>
#include <CGAL/Periodic_3_mesh_triangulation_3.h>
#include <CGAL/Labeled_mesh_domain_3.h>
#include <CGAL/Mesh_criteria_3.h>
#include <CGAL/Mesh_complex_3_in_triangulation_3.h>
#include <CGAL/Mesh_constant_domain_field_3.h>
#include <CGAL/number_type_config.h> // CGAL_PI
#include <cmath>
#include <fstream>
// Kernel
typedef CGAL::Exact_predicates_inexact_constructions_kernel K;
typedef K::FT                                               FT;
typedef K::Point_3                                          Point;
typedef K::Iso_cuboid_3                                     Iso_cuboid;
// Domain
typedef FT (Function)(const Point&);
typedef CGAL::Implicit_to_labeled_subdomains_function_wrapper<Function, K> Function_wrapper;
typedef CGAL::Labeled_mesh_domain_3<K>                                     Periodic_mesh_domain;
// Triangulation
typedef CGAL::Periodic_3_mesh_triangulation_3<Periodic_mesh_domain>::type Tr;
typedef CGAL::Mesh_complex_3_in_triangulation_3<Tr>                       C3t3;
// Criteria
typedef CGAL::Mesh_criteria_3<Tr> Periodic_mesh_criteria;
// To avoid verbose function and named parameters call
using namespace CGAL::parameters;
// Function
FT schwarz_p(const Point& p)
{
  const FT x2 = std::cos( p.x() * 2 * CGAL_PI ),
           y2 = std::cos( p.y() * 2 * CGAL_PI ),
           z2 = std::cos( p.z() * 2 * CGAL_PI );
  return x2 + y2 + z2;
}
// This example uses a cell sizing field that depends on the subdomain index
typedef CGAL::Mesh_constant_domain_field_3<Periodic_mesh_domain::R,
                                           Periodic_mesh_domain::Index> Field;
int main(int argc, char** argv)
{
  int number_of_copies_in_output = (argc > 1) ? atoi(argv[1]) : 4; // can be 1, 2, 4, or 8
  Iso_cuboid canonical_cube(0, 0, 0, 1, 1, 1);
  Function_wrapper wrapper(schwarz_p);
  Periodic_mesh_domain domain(wrapper, canonical_cube);
  // Write the two different sizing fields for cells
  int volume_dimension = 3;
  Field size(2);
  size.set_size(0.1, volume_dimension, domain.index_from_subdomain_index(2)); // exterior
  size.set_size(0.03, volume_dimension, domain.index_from_subdomain_index(1)); // interior
  Periodic_mesh_criteria criteria(facet_angle = 30.,
                                  facet_size = 0.05,
                                  facet_distance = 0.025,
                                  cell_radius_edge_ratio = 2.,
                                  cell_size = size);
  // Mesh generation
  C3t3 c3t3 = CGAL::make_periodic_3_mesh_3<C3t3>(domain, criteria);
  // Output
  std::ofstream medit_file("output_implicit_with_subdomains.mesh");
  CGAL::output_periodic_mesh_to_medit(medit_file, c3t3, number_of_copies_in_output);
  std::cout << "EXIT SUCCESS" << std::endl;
  return 0;
}

ちなみに,最後から4行目のCGAL::IO::output_periodic_mesh_to_meditはのバージョン5.4ではIO::が不要だった.(コンパイルしたらコンパイラに怒られた.)

ソースコードを用意して,上の「CMakeLists.txtを用意する」の箇所に従ってCMakeLists.txtを生成してもらい,UbuntuとmacOSでは

bash
1
2
$ cmake -S . -B build
$ cmake --build build

と打てば,コンパイルしてくれる. CentOSでは,

bash
1
2
3
$ mkdir build
$ cmake -S . -B build
$ cmake --build build

mkdirが必要な模様. ここまでうまくいけば,あとは./build/mainで実行できるか確かめるのみ. コンパイルはできるけど,うまく実行されない場合,ライブラリが足りない可能性がある. Linuxの場合は$ ldd ./build/mainで確かめてみるとよいかもしれない.macOSの場合は$ otool -L ./build/mainで同様のことができる.