1

1 C++类的知识

因为CGAL是用C++实现的,所以需要先了解一下C++编程。C++是面向对象的编程,这也是C++对C语言改进的最重要的部分。C++也被叫做是"带类的 C"。简单讲一下类的构成,成员函数以及对象的定义和使用。

1.1 C++类的构成

首先从C的结构体说起。C中的结构体我想大家已经熟悉了,不熟悉的朋友可以先了解一下,这将对你认识“类”有很好的帮助。C中的结构体存在缺点:1.main 函数中的任意赋值语句都可以访问结构体中的成员,但在实际应用中我们想保护自己的私密数据不被访问,因此C语言中的结构体的数据是不安全的;2.结构体中的数据和对该数据的操作是分离的,并不是一个被封装起来的整体,因此使程序难以重用,影响了软件生产效率。于是C++中引入了类的概念。

C++中类的一般格式为:

   class Kid
   {
      private:
      int age;    //私有成员
      char *name;
      char *sex;
      public:      //公有成员
      void setKid(int age,char *name,char *sex);
      void showKid();
   };

C++中规定如果没有对类的成员加私有private,保护protected,公有public,则默认为私有的。而对于 C++的结构体来说,成员可以是私有的,保护的或公有的,但默认为公有的;还有要注意的是不能在类的声明中给数据成员赋值。

一般情况下,一个类的数据成员应该声明为私有的,成员函数声明为共有的。这样,内部的数据隐藏在类中,在类的外部无法访问直接访问,使数据得到有效的保护。而公有的成员函数就成为一种与类外部沟通的接口。

1.2 C++中的成员函数

1) 普通的成员函数。
要注意几点:1.类名和函数名之间应加上作用域运算符::,用于声明这个成员函数是属于哪一个类的,如果在函数名前没有类名,或既无类名又无作用域运算符::,那么这个函数不属于任何类,不是成员函数,而是普通函数;2.在类的声明中,成员函数原型的参数表中可以不说明参数的名字,而只说明它的类型,但在类外定义时必须既要说明参数类型又要说明参数名;
2) 内联成员函数,它又分显式声明和隐式声明。

1.3 C++中的成员函数

类与对象的关系可以用数据类型int和整形变量i之间的关系来类比。int类型和类类型代表一种抽象的概念,而整形变量和类的对象代表具体的东西。C++把类的变量称为类的对象,对象也被称为类的实例;类的对象可以是: class Kid{...}kid1,kid2;也可以是声明了类后,使用时在定义对象: Kid kid1,kid2;(声明一个类后,它并不接受和存储具体的值,只作为生成具体对象的一种样板,只有定义了对象后,系统才为对象分配存储空间,以存放对象中的成员);

对对象中的成员的访问可以是:
1) 对象名.数据成员名/对象名.成员函数名(参数),比如

kid1.setKid(10,"rookie_j","男");

2) 指针访问对象中成员,比如:

class Kid{public: int age;}; 
Kid kid,*ptr; 
ptr=&kid;
cout << ptr->age //cout<<(*ptr).age;

3) 可以通过引用来访问对象中的成员

class Kid{public: int age;};
Kid kid;
Kid &ptr=kid;
cout << ptr.age   //cout<<kid.age;

因为接下来要讲解的运用CGAL库编写凸包的程序,其程序运用以上的 C++的知识就可以理解了,所以只讲解以上的 C++ 的知识,具体想了解 C++的话,推荐(注意了解某种语言,不在于你看了多少书,而是去尝试编写)

1.《C++ Primer中文版》(第4版)
    【原书名】 C++ Primer (4th Edition)
    【原出版社】 Addison Wesley/Pearson
    【作者】 (美)Stanley B.Lippman,Josée LaJoie,Barbara E.Moo
    【译者】 李师贤
    【丛书名】 图灵计算机科学丛书
    【出版社】人民邮电出版社
2.《C++ Primer Plus》(第四版)中文版
    【原书名】 C++ Primer Plus,Fourth Edition
    【原出版社】 Sams
    【作者】 (美)Stephen Prata
    【译者】 孙建春 韦强
    【丛书名】 Primer Plus 系列
    【出版社】 人民邮电出版社

2 CGAL库的应用

2.1 CGAL 中的 Kernel 和眼花缭乱的 typedef

看CGAL中演化缭乱的Kernel对我这个C++入门级的人来说是件痛苦的事。倘若有时间,我会认真去看看模板类,类模板什么的再去好好理解这些东西,但是我想大部分人在学习新的东西的时候是没有兴趣去看那么的多参考书。所以摸着石头过河时最好最有效的方法。以下说说这Kernel是个什么东西,为什么要有那么多的typedef

CGAL的开发人员力图让这个程序包有较强的扩展性,要有扩展性,同时又要有一定的规则层次。这个层次的底层是代数结构,其上谈number type,再往上就是基本几何对象(线,面,点,射线,线段)和定义在基本几何对象上的基本算法,在往上就是各种复杂的几何算法(包围盒,搜索,网格化等),如下图所示。
CGAL层次图
<img src="htt://cgal_use.com/1.png" width="400" height="100">

所谓的Kernel就是Layer2的内容。CGAL将Layer2按照基本几何对象的表达方式(用欧式坐标表达还是其次坐标表达)进一步分成CartesianHomogeneous两种。简单的说,我们用Cartesian开始编程,以后的对象操作什么的都是用x , y , z三个坐标去表示点,线,面。

因为各个layer的东西在CGAL里都是以类模板的形式定义。CGAL的一开始,会有一大堆typedef,其实就是给这些类模板起一个简单而又好记的名字。看一例:

   typedef CGAL:: Exact_predicates_exact_constructions_kernel K;
   typedef K::Ray_3 Ray;
   typedef K::Line_3 Line;
   typedef K::Point_3 Point;
   typedef K::Triangle_3 Triangle;
   typedef std::list<Triangle>::iterator Iterator;
   typedef CGAL::AABB_triangle_primitive<K,Iterator> Primitive;

CGAL给出了一些预定义的东西,也就是把上面那个不断typedef的最初一部分给隐藏掉:

   Exact_predicates_exact_constructions_kernel;
   Exact_predicates_exact_constructions_kernel_with_sqrt;
   Exact_predicates_inexact_constructions_kernel;

这些预定义的东西默认使用Cartesian,数据类型支持double,还包括能实现精确的几何判断(exact predicate ),原来的代码可以写成:

   typedef CGAL:: Cartesian<double> K;// 使用Cartesian坐标描述几何体,坐标的数值时double型,以后用到 ray , line等几何体的时候都按照Cartesian方式给出double型坐标。
   typedef K::Ray_3 Ray;
   typedef K::Line_3 Line;
   typedef K::Point_3 Point;
   typedef K::Triangle_3 Triangle;
   typedef std::list<Triangle>::iterator Iterator;
   typedef CGAL::AABB_triangle_primitive<K,Iterator> Primitive;//这句话表示使用高级计算几何算法AABB时,所有的几何对象都是Cartesian表示的,坐标的数值都是double。

2.2 CGAL中某种算法的运用流程

点击http://doc.cgal.org/latest/Manual/packages.html| 66c998fe1f511ede5c7483b24fcc88ca4 |进入CGAL手册,出现各种算法库Arithmetic and AlgebraCombinatorial AlgorithmsGeometry KernelsPolygons、Arrangements等等。
假如我们想找有关3d凸包的算法,则找到如下图所示的算法,
3D凸包手册

点击reference manual,就会看到该算法库中的ConceptsTraits ClassesConvex Hull FunctionsConvexity Checking Function,如下图:
图片描述

点击convex_hull_3函数,就会看见该函数的使用规则和实例,如下图
图片描述

每个算法库中都会带有示例程序,点击左侧列表中example->convex_hull_3/quickhull_3.cpp,就会看到如下示例程序:

#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include <CGAL/point_generators_3.h>
#include <CGAL/algorithm.h>
#include <CGAL/Polyhedron_3.h>
#include <CGAL/convex_hull_3.h>
#include <vector>
typedef CGAL::Exact_predicates_inexact_constructions_kernel  K;
typedef CGAL::Polyhedron_3<K>                     Polyhedron_3;
typedef K::Segment_3                              Segment_3;
// define point creator
typedef K::Point_3                                Point_3;
typedef CGAL::Creator_uniform_3<double, Point_3>  PointCreator;
//a functor computing the plane containing a triangular facet
struct Plane_from_facet {
  Polyhedron_3::Plane_3 operator()(Polyhedron_3::Facet& f) {
      Polyhedron_3::Halfedge_handle h = f.halfedge();
      return Polyhedron_3::Plane_3( h->vertex()->point(),
                                    h->next()->vertex()->point(),
                                    h->opposite()->vertex()->point());
  }
};
int main()
{
  CGAL::Random_points_in_sphere_3<Point_3, PointCreator> gen(100.0);
  // generate 250 points randomly on a sphere of radius 100.0
  // and copy them to a vector
  std::vector<Point_3> points;
  CGAL::cpp11::copy_n( gen, 250, std::back_inserter(points) );
  // define polyhedron to hold convex hull
  Polyhedron_3 poly;
  
  // compute convex hull of non-collinear points
  CGAL::convex_hull_3(points.begin(), points.end(), poly);
  std::cout << "The convex hull contains " << poly.size_of_vertices() << " vertices" << std::endl;
  
  // assign a plane equation to each polyhedron facet using functor Plane_from_facet
  std::transform( poly.facets_begin(), poly.facets_end(), poly.planes_begin(),Plane_from_facet());
  return 0;
}

3、CGAL程序的编译

3.1 Cmake

对于用CGAL所编写的程序(因为基于C++)可利用Cmake来进行编译安装。CMake是一个跨平台的安装(编译)工具,可以用简单的语句来描述所有平台的安装(编译过程)。他能够输出各种各样的makefile或者project文件,能测试编译器所支持的C++特性,类似UNIX下的automake。只是 CMake 的组态档取名为 CmakeLists.txt。Cmake 并不直接建构出最终的软件,而是产生标准的建构档(如 Unix 的 Makefile 或 Windows Visual C++ 的 projects/workspaces),然后再依一般的建构方式使用。这使得熟悉某个集成开发环境(IDE)的开发者可以用标准的方式建构他的软件,这种可以使用各平台的原生建构系统的能力是 CMake 和 SCons 等其他类似系统的区别之处。
建议去了解一下CMake方面的知识。
linux-gentoo下cmake的安装

$ sudo emerge -avt cmake

3.2 CGAL示例程序编译

1) 创建一个工程目录quickhull3,并将上面的示例程序quickhull_3.cpp放入该目录中

$ mkdir quickhull3
$ ls
quickhull_3.cpp

2) 编写CMakeLists.txt文件,鉴于许多朋友不会编写CMakeLists.txt文件,因此这里给出一个可自动生成CMakeLists.txt文件的shell脚本文件create_cmakelists.sh,该脚本仅运用于基于CGAL算法库编写的项目,将此脚本放在工程主目录中,其内容如下:

#!/bin/bash

# Copyright (c) 1999,2000,2002-2007,2009,2011,2012
# Utrecht University (The Netherlands),
# ETH Zurich (Switzerland),
# INRIA Sophia-Antipolis (France),
# Max-Planck-Institute for Informatics Saarbruecken (Germany), 
# and Tel-Aviv University (Israel).  All rights reserved.
#
# This file is part of CGAL (www.cgal.org); 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.
#
# Licensees holding a valid commercial license may use this file in
# accordance with the commercial license agreement provided with the software.
#
# This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
# WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
#
# $URL: svn+ssh://fcacciola@scm.gforge.inria.fr/svn/cgal/trunk/Scripts/scripts/cgal_create_makefile $
# $Id: cgal_create_makefile 36976 2007-03-09 22:53:24Z reichel $
#
# Author(s)     : various

# This script creates a CGAL cmake script with entries for .C and .cpp
# files in the current directory - some options can be given or specified in a file


#LEDA
#GMP
#GMPXX
#MPFR
#MPFI
#RS
#TAUCS
#BLAS
#LAPACK
#OPENNL
#QGLViewer (or implied by Qt4?)
#ESBTL
#NTL

#Core (implies GMP+GMPXX)
#Qt3 (implies QT3)
#Qt4 (implies QT4)
#ImageIO

#not (yet) supported
#F2C (comes with BLAS/LAPACK - something like that)
#IPE (ask Laurent)
#MKL (ask Andreas)

create_cmake_script_with_options()
{
  qt3='n'
  qt4='n'

  # parse options file
  if [ -e "$OPTIONS_FILE" ]; then

    OLDIFS="$IFS"
    IFS=$'\n'
    for LINE in `cat $OPTIONS_FILE`; do 

      # CGAL components
      if [ -z "$CGAL_COMPONENTS_GIVEN" ]; then # read file only if not given!
        next_cgal_component=`echo $LINE | grep -v "#" | grep CGAL_COMPONENT`
        if [ ! -z "$next_cgal_component" ]; then
          next_cgal_component=${next_cgal_component/CGAL_COMPONENT /}
          if [ -z "$CGAL_COMPONENTS" ]; then 
            CGAL_COMPONENTS=$next_cgal_component
          else
            CGAL_COMPONENTS=$CGAL_COMPONENTS":"$next_cgal_component
          fi
        fi
      fi

      # Boost components
      if [ -z "$BOOST_COMPONENTS_GIVEN" ]; then # read file only if not given!
        next_boost_component=`echo $LINE | grep -v "#" | grep BOOST_COMPONENT`
        if [ ! -z "$next_boost_component" ]; then
          next_boost_component=${next_boost_component/BOOST_COMPONENT /}
          if [ -z "$BOOST_COMPONENTS" ]; then 
            BOOST_COMPONENTS=$next_boost_component
          else
            BOOST_COMPONENTS=$BOOST_COMPONENTS":"$next_boost_component
          fi
        fi
      fi

    done
    IFS="$OLDIFS"
  fi


  # print makefile header
  #vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
  cat << 'EOF'
# Created by the script cgal_create_cmake_script_with_options
# This is the CMake script for compiling a set of CGAL applications.

EOF
  #---------------------------------------------------------------------------
  if [ "$SINGLE_SOURCE" = "n" ]; then
    echo "project( ${PROJECT} )"
  else 
    echo "project( ${SOURCE} )"
  fi

  #vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
  cat << 'EOF'


cmake_minimum_required(VERSION 2.6.2)
if("${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}" VERSION_GREATER 2.6)
  if("${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}.${CMAKE_PATCH_VERSION}" VERSION_GREATER 2.8.3)
    cmake_policy(VERSION 2.8.4)
  else()
    cmake_policy(VERSION 2.6)
  endif()
endif()

set( CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS true )
 
if ( COMMAND cmake_policy )

  cmake_policy( SET CMP0003 NEW )  

endif()

# CGAL and its components
EOF
if [ -n "$ENABLE_CTEST" ]; then
  echo "enable_testing()"
fi
  #---------------------------------------------------------------------------
  # echo "CGAL_COMPONENTS: $CGAL_COMPONENTS"
  # echo "CGAL_PRECONFIGURED_LIBS: $CGAL_PRECONFIGURED_LIBS"
  if [ ! -z "$CGAL_COMPONENTS" ]; then
    # ensure capitalization

    # CGAL: Core, Qt3, Qt4, PDB, ImageIO
    CGAL_COMPONENTS=${CGAL_COMPONENTS//[c|C][o|O][r|R][e|E]/Core}
    CGAL_COMPONENTS=${CGAL_COMPONENTS//[q|Q][t|T]3/Qt3}
    CGAL_COMPONENTS=${CGAL_COMPONENTS//[q|Q][t|T]4/Qt4}
    CGAL_COMPONENTS=${CGAL_COMPONENTS//[i|I][m|M][a|A][g|G][e|E][i|I][o|O]/ImageIO}
  
    # external libs

    CGAL_COMPONENTS=${CGAL_COMPONENTS//[g|G][m|M][p|P]/GMP}
    CGAL_COMPONENTS=${CGAL_COMPONENTS//[g|G][m|M][p|P][x|X][x|X]/GMPXX}

    CGAL_COMPONENTS=${CGAL_COMPONENTS//[m|M][p|P][f|F][r|R]/MPFR}
    CGAL_COMPONENTS=${CGAL_COMPONENTS//[l|L][e|E][d|D][a|A]/LEDA}
    CGAL_COMPONENTS=${CGAL_COMPONENTS//[m|M][p|P][f|F][i|I]/MPFI}
    CGAL_COMPONENTS=${CGAL_COMPONENTS//[r|R][s|S]/RS}

    CGAL_COMPONENTS=${CGAL_COMPONENTS//[o|O][p|P][e|E][n|N][n|N][l|L]/OpenNL}
    CGAL_COMPONENTS=${CGAL_COMPONENTS//[t|T][a|A][u|U][c|C][s|S]/TAUCS}
    CGAL_COMPONENTS=${CGAL_COMPONENTS//[b|B][l|L][a|A][s|S]/BLAS}
    CGAL_COMPONENTS=${CGAL_COMPONENTS//[l|L][a|A][p|P][a|A][c|C][k|K]/LAPACK}

    CGAL_COMPONENTS=${CGAL_COMPONENTS//[q|Q][g|G][l|L][v|V][i|I][e|E][w|W][e|E][r|R]/QGLViewer}

    CGAL_COMPONENTS=${CGAL_COMPONENTS//[z|Z][l|L][i|I][b|B]/zlib}

    CGAL_COMPONENTS=${CGAL_COMPONENTS//[e|E][s|S][b|B][t|T][l|L]/ESBTL}

    CGAL_COMPONENTS=${CGAL_COMPONENTS//[n|N][t|T][l|L]/NTL}

    CGAL_COMPONENTS=${CGAL_COMPONENTS//[o|O][p|P][e|E][n|N][g|G][l|L]/OpenGL}


#F2C?
#IPE?
#MKL?

    OLDIFS="$IFS"
    IFS=':'
    for cgal_component in $CGAL_COMPONENTS; do
      COMPONENT=`echo $cgal_component | tr '[:upper:]' '[:lower:]'`

      # for qtmoc
      if [ "$COMPONENT" = "qt3" ]; then
        qt3='y'
      fi
      if [ "$COMPONENT" = "qt4" ]; then
        qt4='y'
      fi

    done
    IFS=$OLDIFS

  fi

  if [ "$CGAL_PRECONFIGURED_LIBS" = "y" ]; then
    CGAL_COMPONENTS=${CGAL_COMPONENTS}" ALL_PRECONFIGURED_LIBS"
  fi

  echo "find_package( CGAL QUIET COMPONENTS ${CGAL_COMPONENTS//:/ } )"

  #vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
  cat << 'EOF'

if ( NOT CGAL_FOUND )

  message(STATUS "This project requires the CGAL library, and will not be compiled.")
  return()  

endif()

# include helper file
include( ${CGAL_USE_FILE} )

EOF
  #---------------------------------------------------------------------------

  #vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
  cat << 'EOF'

# Boost and its components
EOF
  #---------------------------------------------------------------------------

  if [ ! -z "$BOOST_COMPONENTS" ]; then

    echo "find_package( Boost REQUIRED COMPONENTS ${BOOST_COMPONENTS//:/ } )"

  else

    echo "find_package( Boost REQUIRED )"

  fi # additional Boost components

  #vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
  cat << 'EOF'

if ( NOT Boost_FOUND )

  message(STATUS "This project requires the Boost library, and will not be compiled.")

  return()  

endif()
EOF
  #---------------------------------------------------------------------------


  #vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
  cat << 'EOF'

# include for local directory
EOF
  #---------------------------------------------------------------------------

  if [ -d include ] ; then
    echo 'include_directories( BEFORE include )'
  fi        

  #vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
  cat << 'EOF'

# include for local package
EOF
  #---------------------------------------------------------------------------

  # includes for local package
  if [ -d ../../include ] ; then
    echo 'include_directories( BEFORE ../../include )'
  fi
  if [ -d ../include ] ; then
    echo 'include_directories( BEFORE ../include )'
  fi

  if [ ! -z "$PACKAGES" ]; then
    #vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
    cat << 'EOF'

# include of additional packages
EOF
    #-------------------------------------------------------------------------
  fi

  # Qt3 or Qt4
  if [ "$qt3" = "y" ]; then

    #vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
    cat << 'EOF'

# Qt3
# FindQt3-patched.cmake is FindQt3.cmake patched by CGAL developers, so
# that it can be used together with FindQt4: all its variables are prefixed
# by "QT3_" instead of "QT_".
find_package(Qt3-patched QUIET )

if ( NOT QT3_FOUND )

  message(STATUS "This project requires the Qt3 library, and will not be compiled.")
  return()  

endif()

if ( CGAL_Qt3_FOUND )
  
  include( Qt3Macros-patched )

endif()
EOF
    #-------------------------------------------------------------------------
  fi # qt3

  if [ "$qt4" = "y" ]; then

    #vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
    cat << 'EOF'

# Qt4
set( QT_USE_QTXML     true )
set( QT_USE_QTMAIN    true )
set( QT_USE_QTSCRIPT  true )
set( QT_USE_QTOPENGL  true )

find_package(Qt4)  

if ( NOT QT_FOUND )

  message(STATUS "This project requires the Qt4 library, and will not be compiled.")
  return()  

endif()
EOF
    #-------------------------------------------------------------------------

  fi #qt4

  if [ ! -z "$BOOST_COMPONENTS" ]; then
    #vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
    cat << 'EOF'

# Boost linking
EOF
    #-------------------------------------------------------------------------

    OLDIFS="$IFS"
    IFS=':'
    for boost_component in $BOOST_COMPONENTS; do
      BOOST_COMPONENT=`echo $boost_component | tr '[:lower:]' '[:upper:]'`
      echo "add_definitions( \"-DCGAL_USE_BOOST_${BOOST_COMPONENT}\" )"
      echo "list(APPEND CGAL_3RD_PARTY_LIBRARIES \${Boost_${BOOST_COMPONENT}_LIBRARY} )"
    done
    IFS=$OLDIFS

  fi # additional Boost components


  # All Files or Single Source

  if [ "$SINGLE_SOURCE" = "n" ]; then #=======================================

    ###############
    # ALL SOURCES #
    ###############

    #vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
    cat << 'EOF'


# Creating entries for all .cpp/.C files with "main" routine
# ##########################################################

EOF
    #-------------------------------------------------------------------------


    if [ "$qt4" = "y" ]; then

      echo "include( CGAL_CreateSingleSourceCGALProgramQt4 )"

    else
 
      echo "include( CGAL_CreateSingleSourceCGALProgram )"

    fi
    # add a new line
    echo

    # Qt3
    if [ "$qt3" = "y" ]; then
      #vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
      cat << 'EOF'
if ( CGAL_Qt3_FOUND AND QT3_FOUND )

EOF
      #-----------------------------------------------------------------------

      for file in `ls *.C *.cpp 2> /dev/null | sort` ; do
        # Create an executable for each cpp that  contains a function "main()"
        BASE=`basename $file .C`
        BASE=`basename $BASE .cpp`
        egrep '\bmain[ \t]*\(' $file >/dev/null 2>&1
        if [ $? -eq 0 ]; then
          echo "qt3_automoc( ${file} )"
        fi
      done

      #vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
      cat << 'EOF'

  # Make sure the compiler can find generated .moc files
  include_directories( BEFORE ${CMAKE_CURRENT_BINARY_DIR} )
  
  include_directories( ${QT3_INCLUDE_DIR} )

  list(APPEND CGAL_3RD_PARTY_LIBRARIES ${QT3_LIBRARIES} )

endif()

EOF
      #-----------------------------------------------------------------------

    fi # qt3

    # Qt4
    if [ "$qt4" = "y" ]; then
      #vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
      cat << 'EOF'

if ( CGAL_Qt4_FOUND AND QT_FOUND )

  include( ${QT_USE_FILE} )
  include_directories( ${QT_INCLUDE_DIR} )  

endif()

EOF
      #-----------------------------------------------------------------------
    fi # qt4

    for file in `ls *.C *.cpp 2> /dev/null | sort`; do
      # Create an executable for each cpp that  contains a function "main()"
      BASE=`basename $file .C`
      BASE=`basename $BASE .cpp`
      egrep '\bmain[ \t]*\(' $file >/dev/null 2>&1
      if [ $? -eq 0 ]; then
        if [ "$qt4" = "y" ]; then
          echo "create_single_source_cgal_program_qt4( \"$file\" )"
        else
          echo "create_single_source_cgal_program( \"$file\" )"
        fi
        if [ -n "$ENABLE_CTEST" ]; then 
          if [ -f "$BASE.cin" ] ; then
            CIN=" < $BASE.cin"
          else
            CIN=
          fi
          cat <<EOF
add_test( "$BASE" \${CMAKE_CTEST_COMMAND}
  --build-and-test "\${CMAKE_CURRENT_SOURCE_DIR}"
                   "\${CMAKE_CURRENT_BINARY_DIR}"
  --build-generator "\${CMAKE_GENERATOR}"
  --build-makeprogram "\${CMAKE_MAKE_PROGRAM}"
  --build-target $BASE
  --build-no-clean
  --build-run-dir "\${CMAKE_CURRENT_SOURCE_DIR}"
  --test-command sh -c "\${CMAKE_CURRENT_BINARY_DIR}/$BASE$CIN" )
EOF
        fi
      fi
      #add a new line
      echo 
    done
    
  else #======================================================================

    #################
    # SINGLE_SOURCE #
    #################

    target_name=$SOURCE

    echo
    echo
    echo "# Creating entries for target: $target_name"
    #vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
    cat << 'EOF'
# ############################
EOF
    #-------------------------------------------------------------------------

    for file in `ls *.C *.cpp 2> /dev/null | sort`; do
      all="$all $file"
    done

    # Qt3
    if [ "$qt3" = "y" ]; then
      #vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
      cat << 'EOF'

if ( CGAL_Qt3_FOUND AND QT3_FOUND )

EOF
      #-----------------------------------------------------------------------

      echo "qt3_automoc( ${all} )"

      #vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
      cat << 'EOF'

  # Make sure the compiler can find generated .moc files
  include_directories( BEFORE ${CMAKE_CURRENT_BINARY_DIR} )
 
  include_directories( ${QT3_INCLUDE_DIR} )

endif()
EOF
      #-----------------------------------------------------------------------
    fi # qt3

    # Qt4
    if [ "$qt4" = "y" ]; then
      #vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
      cat << 'EOF'

if ( CGAL_Qt4_FOUND AND QT_FOUND )

  include( ${QT_USE_FILE} )
  include_directories( ${QT_INCLUDE_DIR} )  

EOF
      #-----------------------------------------------------------------------

      echo "  # UI files (Qt Designer files)"
      for file in `ls *.ui 2> /dev/null | sort`; do
        echo "  qt4_wrap_ui( DT_UI_FILES $file )"
      done
      echo
      echo "  # qrc files (resources files, that contain icons, at least)"
      for file in `ls *.qrc 2> /dev/null | sort`; do
        echo "  qt4_add_resources ( DT_RESOURCE_FILES ./$file )"
      done
      echo
      MOC_FILES=""
      echo "  # use the Qt MOC preprocessor on classes that derives from QObject"
      for file in `ls include/*.h 2> /dev/null | sort`; do
        BASE=`basename $file .h`
        egrep 'Q_OBJECT' $file >/dev/null 2>&1
        if [ $? -eq 0 ]; then
          echo "  qt4_generate_moc( include/${BASE}.h ${BASE}.moc )"
          MOC_FILES="${BASE}.moc $MOC_FILES"
        fi
      done
      for file in `ls *.h 2> /dev/null | sort`; do
        BASE=`basename $file .h`
        egrep 'Q_OBJECT' $file >/dev/null 2>&1
        if [ $? -eq 0 ]; then
          echo "  qt4_generate_moc( ${BASE}.h ${BASE}.moc )"
          MOC_FILES="${BASE}.moc $MOC_FILES"
        fi
      done
      for file in `ls *.cpp 2> /dev/null | sort`; do
        BASE=`basename $file .cpp`
        egrep 'Q_OBJECT' $file >/dev/null 2>&1
        if [ $? -eq 0 ]; then
          echo "  qt4_generate_moc( ${BASE}.cpp ${BASE}.moc )"
          MOC_FILES="${BASE}.moc $MOC_FILES"
        fi
      done

      #vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
      cat << 'EOF'

endif()
EOF
      #-----------------------------------------------------------------------

      all="${all} ${MOC_FILES} \${DT_UI_FILES} \${DT_RESOURCE_FILES}"

    fi # qt4

    # no 'cat' here, as variable substitution required
    echo
    echo "add_executable( ${target_name} ${all} )"
    echo
    echo "add_to_cached_list( CGAL_EXECUTABLE_TARGETS ${target_name} )"
    echo
    echo "# Link the executable to CGAL and third-party libraries"
    LIBS=""
    if [ "$qt3" = "y" ]; then
      LIBS="\${QT3_LIBRARIES}"
    fi
    if [ "$qt4" = "y" ]; then
      LIBS="\${QT_LIBRARIES}" 
    fi
    LIBS=$LIBS" \${CGAL_LIBRARIES} \${CGAL_3RD_PARTY_LIBRARIES}"
    echo "target_link_libraries(${target_name}  $LIBS )"

  fi # single source or all files #===========================================

  #vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
  cat << 'EOF'
EOF
  #---------------------------------------------------------------------------

echo

}

usage()
{
  echo "Usage: `basename $0` [-s source] [-c cgal-component1:cgal-component2:...] [-b boost-component1:boost-component2:...] [-p] [-o options_file='`pwd`/cgal_cmake_options:$HOME/.cgal_cmake_options_rc'] [-v] [-h]" >&2
  echo >&2
  echo "  -s source If this parameter is given the script will create one single executable for 'source' with all source files; otherwise it creates one executable for each main'ed source." >&2
  echo "  cgal_componentX - must be a valid cgal component, examples are 'Core','ImageIO','Qt3','Qt4' ('benchmark', 'symbolic')." >&2
  echo "  boost_componentX - must be a valid boost component, like 'filesystem', 'program_options'." >&2
  echo "  -p use all of CGAL's preconfigured libraries" >&2
  echo "  -o options_file - file with PACKAGE, DIRECTORY, CGAL_COMPONENT, and BOOST_COMPONENT directives" >&2
  echo "  -v the version" >&2
  echo "  -h this info screen" >&2
  echo  >&2
}


SINGLE_SOURCE='n'
SOURCE=""

CGAL_COMPONENTS_GIVEN=""
CGAL_COMPONENTS=""

CGAL_PRECONFIGURED_LIBS='n'

BOOST_COMPONENTS_GIVEN=""
BOOST_COMPONENTS=""

OPTIONS_FILE=`pwd`"/cgal_cmake_options"

if [ ! -e "$OPTIONS_FILE" ]; then
  OPTIONS_FILE="${HOME}/.cgal_cmake_options_rc"
fi

# parse command line arguments
while getopts s:c:b:o:phvt OPT; do
  case "$OPT" in
    s)  SINGLE_SOURCE='y'
        SOURCE=$OPTARG
        if [ "${SOURCE:(-4)}" = ".cpp" ]; then
           echo "Error: Source must not end with '.cpp'!" >&2
           echo
           usage
           exit 2
        fi
        if [ "${SOURCE:(-2)}" = ".C" ]; then
           echo "Error: Source must not end with '.C'!" >&2
           echo
           usage
           exit 2
        fi

        ;;

    c)  CGAL_COMPONENTS_GIVEN='y'
        CGAL_COMPONENTS=$OPTARG
        ;;
    b)  BOOST_COMPONENTS_GIVEN='y'
        BOOST_COMPONENTS=$OPTARG
        ;;

    o)  OPTIONS_FILE=$OPTARG
        if [ ! -e "$OPTIONS_FILE" ]; then
          echo "Options-file '$OPTIONS_FILE' does not exist." >&2
          exit 1
        fi
        ;;
    p)  CGAL_PRECONFIGURED_LIBS='y'
        ;;
    t)  ENABLE_CTEST='y'
        ;;
    h)  usage
        exit 0
        ;;
    v)  echo "`basename $0` version 0.1"
        exit 0
        ;;
    \?) # getopts issues an error message
        usage
        exit 1
        ;;
  esac
done

shift `expr $OPTIND - 1`

#echo "FILE: $OPTIONS_FILE"
#echo "BOOST_COMPONENTS: $BOOST_COMPONENTS"
echo "CGAL_COMPONENTS: $CGAL_COMPONENTS"
#echo "SINGLE_SOURCE: $SINGLE_SOURCE"
#echo "SOURCE: $SOURCE"

OUTPUTFILE=CMakeLists.txt
PROJECT=`basename $PWD`

if [ -f ${OUTPUTFILE} ] ; then
  echo "moving $OUTPUTFILE to ${OUTPUTFILE}.bak ..."
  echo
  mv -f $OUTPUTFILE ${OUTPUTFILE}.bak
fi

create_cmake_script_with_options | tee $OUTPUTFILE

echo
echo "created $OUTPUTFILE in $PWD ..."
$ ./create_cmakelists.sh 
$ ls 
CMakeLists.txt quickhull_3.cpp

3) 为了保持代码目录的整洁,建议采用外部编译,即新建一个build目录,在该目录下配置编译,其过程如下:

$ mkdir build && cd build
$ cmake ..
$ make 
$ ./quickhull_3.cpp
The convex hull contains 89 vertices

vslam
137 声望15 粉丝

debug forever