著者 Dmitry Anisimov, David Bommes, Kai Hormann, and Pierre Alliez
The package 2D Generalized Barycentric Coordinatesは、単純な2次元ポリゴンのために定義した2次元閉形式の一般化バリセント座標の効率的かつ堅牢な実装を提供します。 多角形ではなく多変量に散らばった点に関する座標が必要な場合は、パッケージ 2D の自然近傍座標と表面関数補間を参照してください。
特に、このパッケージには Wachspress、平均値、離散調和座標の実装と、セグメント (segment coordinates) と三角形 (triangle coordinates) に関してバリセントリック座標を計算するいくつかの追加関数があります。 Theory of 2D Generalized Barycentric Coordinates のセクションでは、バリセントリック座標のトピックについて簡単に紹介しています。
バリセントリック座標を計算する各クラスは、trait クラスによってパラメータ化されています。 このtraitクラスは、計算で使用される型と幾何学的プリミティブを指定し、概念BarycentricTraits_2
のモデルでなければならない。
コンポーネントへの主なエントリポイントは、多角形の頂点上の入力イテレータである。 多角形の頂点は時計回りまたは反時計回りの順序に従う必要があり、任意の型を持つことができる。 しかし、内部的にはクラスはCGAL::Point_2
型を使用しており、ユーザーの型をCGAL::Point_2
に変換する適切なtraitクラスが提供されなければならないのはそのためです。
平均値座標は、入力として任意の単純な多角形を許容するため、このパッケージの中で最も汎用的な座標です。 Wachspressと離散調和座標は、定義上、厳密に凸の多角形に限定されます。 セグメント座標は任意の非縮退セグメントを入力とし、三角形座標は任意の非縮退三角形を入力とします。
セグメントおよび三角形座標は、グローバル関数を使用するか、対応するクラスを作成することによって計算できます。 他のすべての一般化された座標は、概念 BarycentricCoordinates_2
のモデルでなければならない適切な座標タイプによってパラメータ化されたクラス CGAL::Barycentric_coordinates::Generalized_barycentric_coordinates_2
のインスタンスを作成することによって計算することができます。 しかし、多角形の閉じた部分の外側にある問合せ点でWachspressや離散調和座標を使うことはお勧めしません。
一度ある多角形のためにインスタンス化すると、与えられた多角形のすべての頂点に関して、異なる問合せ点に対して座標を複数回計算することができます。
計算の出力は、ポリゴンのすべての頂点を基準とした現在のクエリー点での座標値のセットである。 この出力は、適切な出力イテレータを提供する任意のコンテナに格納することができる。 さらに、すべてのクラスは最後に格納された要素へのポインタと、計算の状態(ブール値の真偽)を返す。
セグメント座標
これはグローバル関数 CGAL::Barycentric_coordinates::compute_segment_coordinates_2() の使用を示す単純な例である。 この例では、区間( \)に沿った緑の3点と、区間外だが補助線に沿った青の2点の座標を計算します。 正確なカーネルを使用し、座標を2つの値の配列として返します。 ここでも問い合わせ点の対称性によって、計算中に生じたかもしれないエラーを認識することができる。
図 96.1 例の点パターン。
File Barycentric_coordinates_2/Segment_coordinates_example.cpp
#include <CGAL/Exact_predicates_exact_constructions_kernel.CGAL_Exact_constructions_kernel.h>
#include <CGAL/Barycentric_coordinates_2/Segment_coordinates_2.h>
// 名前空間の別名。
名前空間 BC = CGAL::Barycentric_coordinates;
// いくつかの便利な typedefs があります。
typedef CGAL::Exact_predicates_exact_constructions_kernel Kernel;
typedef Kernel::FT Scalar;
typedef Kernel::Point_2 Point;
typedef std.Kernel; typeef Kernel::FT scalar;
typeef CGAL::Exact_predicates_exact_constructions_kernel:array<Scalar,2> Pair;
using std::cout; using std::endl; using std::string;
int main()
{
// セグメントを構築する。
const Point first_vertex(0, Scalar(2)/Scalar(5));
const Point second_vertex(2, Scalar(2)/Scalar(5));
// 内部3点、外部2点のクエリをインスタンス化します。
const Point query_points = { Point(Scalar(2) /Scalar(5), Scalar(2)/Scalar(5)), // 内部の問い合わせ点
Point(1 , Scalar(2)/Scalar(5)),
Point(Scalar(8) /Scalar(5)).Scalar(5), Scalar(2)/Scalar(5)),
Point(Scalar(-1)/Scalar(5), Scalar(2)/Scalar(5)), // 外部クエリーポイント
Point(Scalar(11)/Scalar(5), Scalar(2)/Scalar(5))
};
// 定義されたすべての点のセグメント座標を計算する。
// グローバル関数を使用し、std::array<FT,2>型の配列に格納されたセグメント座標を返します。
cout << endl << “Computed segment coordinates: ” << endl << endl;
for(int i = 0; i < 5; ++i) {
const Pair pair = BC::compute_segment_coordinates_2(first_vertex, second_vertex, query_points, Kernel());
// それぞれの点に対して両方の座標を出力します。
cout << “座標のペア # ” << i + 1 << ” = (” << pair << “, ” << pair <“).Pair of coordinates # “, ” << pair # “).Pair of coordinates # “, ” ” << pair < < < “);” << endl;
}
cout << endl;
return EXIT_SUCCESS;
}
Triangle Coordinates
この例では、クラス CGAL::Barycentric_coordinates::Triangle_coordinates_2
と double 型用の Simple_cartesian
カーネルを使用する方法を示しています。 内部(緑)、境界(赤)、外部(青)の3つの点のセットの座標を計算します。 なお、外側の点の座標値のいくつかは負である。
図96.2 例の点のパターン。
File Barycentric_coordinates_2/Triangle_coordinates_example.cpp
#include <CGAL/Simple_cartesian.h>
#include <CGAL/Barycentric_coordinates_2/Triangle_coordinates_2.h>
// いくつかの便利な typedefs があります。
typedef CGAL::Simple_cartesian<double> Kernel;
typedef Kernel::FT Scalar;
typedef Kernel.Kernel::FT Scalar;
typedef CGAL::Simple_cartesian<double > typedef Kernel:Kernel::Point_2 Point;
typedef std::vector<Scalar> Scalar_vector;
typedef CGAL.Scalar_vector;
typedef CGAL::Barycentric_coordinates::Triangle_coordinates_2<Kernel> Triangle_coordinates;
using std::cout; using std::endl; using std::string;
int main()
{
// 三角形を構成します。
const Point first_vertex(0.0f, 0.0f);
const Point second_vertex(2.0f, 0.5f);
const Point third_vertex(1.0f, 2.0f);
//座標格納用に std::vector を作成する。
Scalar_vector coordinates;
// 上記で定義した三角形に対してTriangle_coordinates_2クラスをインスタンス化します。
Triangle_coordinates triangle_coordinates(first_vertex, second_vertex, third_vertex);
// 三角形と座標に関するいくつかの情報を表示します。
triangle_coordinates.print_information();
// 座標を計算するための内部、境界、外部のクエリーポイントをいくつかインスタンス化します。
const int number_of_query_points = 18;
const Point query_points = { Point(0.5f , 0.5f ), Point(1.0f, 0.5f ), Point(1.0f , 0.75f), Point(1.0f , 1.5f ), Point(1.5f , 0.5f ).0f), // 内部クエリ点
Point(1.0f , 1.25f), Point(1.0f, 1.5f ), Point(0.75f, 1.0f ), Point(1.25f, 1.0f), Point(1.5f, 0.75f),
Point(1.5f , 1.0f , 0.25f), Point(0.5f, 1.0f ), Point(1.5f , 1.25f), Point(1.0f , 2.0f), Point(2.0f, 0.5f ), // 境界問い合わせ点
Point(0.25f, 1.0f ), Point(0.5f, 1.75f), Point(1.5f , 1.75f), Point(1.75f, 1.5f) // 外部問い合わせ点
};
// 18点の問い合わせ点に対する三角座標を格納するメモリを確保します。
coordinates.reserve(number_of_query_points * 3);
// これらの点に対する三角座標を計算する。
cout << endl << “計算された三角形の座標。 ” << endl << endl;
for(int i = 0; i < number_of_query_points; ++i) {
triangle_coordinates(query_points, std::inserter(coordinates, coordinates.end()));
// 各点に対する座標を出力します。
cout << “点” << i + 1 << “.点” << i + 1 << “: “;
for(int j = 0; j < 3; ++j)
cout << “coordinate ” << j + 1 << ” = ” << coordinates < “.座標”;<< <<座標”;
cout << endl << endl;
}
return EXIT_SUCCESS;
}
Wachspress座標
以下の例では、1000個のランダムな点を作成し、この点の集合の凸包をポリゴンとして、定義したすべての点でのWachspress座標を計算します。 traitsクラスとしてdouble型のSimple_cartesian
カーネルを使用し、得られた座標値をstd::vector
型のコンテナに格納する。 出力イテレータはstd::back_insert_iterator
です。
ファイル Barycentric_coordinates_2/Wachspress_coordinates_example.cpp
#include <CGAL/convex_hull_2.Wachspress_coordinates_example.cpp #9623 #9623 #6590> #9623 #9623 #9623 #9623 #9623 #9623 #9623 #9623
#include <CGAL/Simple_cartesian.h>
#include <CGAL/point_generators_2.h>
#include <CGAL/point_generators_2.h>
#include <CGAL/Barycentric_coordinates_2/Wachspress_2.h>
#include <CGAL/Barycentric_coordinates_2/Generalized_barycentric_coordinates_2.h>
// いくつかの便利な typedef を追加しました。
typedef CGAL::Simple_cartesian<double> Kernel;
typedef Kernel::FT Scalar;
typedef Kernel::Point_2 Point;
typedef std:.Scala;
typedef Kernel::FT Scala;
typedef Kernel::Point_2 Point;
typedef std::vector<Point> Point_vector;
typedef CGAL::Creator_uniform_2<double, Point> Creator;
typedef CGAL.Scalar_vector;
typedef CGAL.Creator_uniform_2<double, Point> Creator;
typeedef CGAL.Scalar_vector;
typedef CGAL::Barycentric_coordinates::Generalized_barycentric_coordinates_2<Wachspress,Kernel> Wachspress_coordinates;
using std.Wachspress;
typeef CGAL::Barycentric_contordinates:Wachspress_2 Wachspress;
int main()
{
// 何個のランダムポイントを生成したいか選択します。
const int number_of_points = 1000;
// 生成された点と凸多角形の頂点を格納するベクトルを作成する。
Point_vector points, vertices;
// ランダムな点の集合を生成する。
CGAL::Random_points_in_square_2<Point,Creator> point_generator(1.0);
std::copy_n(point_generator, number_of_points, std::back_inserter(points));
//生成した点の集まりから凸包を求める。
// この凸包は、生成されたすべての点を含む凸多角形の頂点を与える。
CGAL::convex_hull_2(points.begin(), points.end(), std::back_inserter(vertices));
const size_t number_of_vertices = vertices.size();
// 上に定義した凸多角形に対するWachspress座標でクラスのインスタンス化を行います。
Wachspress_coordinates wachspress_coordinates(vertices.begin(), vertices.end());
// ポリゴンと座標に関する情報を表示します。
wachspress_coordinates.print_information();
// ランダムに定義されたすべての点に対してWachspress座標を計算する。
cout << endl << “Computed Wachspress coordinates: ” << endl << endl;
for(int i = 0; i < number_of_points; ++i) {
// 座標計算を行う。
Scalar_vector coordinates;
coordinates.reserve(number_of_vertices);
wachspress_coordinates(points, std::back_inserter(coordinates));
// 計算された座標を出力する。
cout << “点” << i + 1 << “: ” << endl;
for(int j = 0; j < int(number_of_vertices); ++j) cout << “座標” << j + 1 << ” = ” << coordinates << “; ” << endl;
cout << endl.For (int j = 0; j ) {3152>< <の座標は、” <<<<<となります。
}
return EXIT_SUCCESS;
}
Discrete Harmonic Coordinates
この例では、単位正方形を基準に緑点(内部)、赤点(境界)、青点(外部)の集合に対して離散調和座標を計算します。 また、追加の関数パラメータを使用して問い合わせ点の位置を指定する方法を示す。 使用するカーネルは厳密であり、std::vector
型の出力コンテナを使用する。 すべての点は対称であるので、得られた座標値の正しさをデバッグすることは容易である。 出力イテレータは std::back_insert_iterator
.
図96.3 例の点のパターン。
File Barycentric_coordinates_2/Discrete_harmonic_coordinates_example.cpp
#include <CGAL/Exact_predicates_exact_constructions_kernel.CGAL_Exact_constructions.Co.h>
#include <CGAL/Barycentric_coordinates_2/Discrete_harmonic_2.h>
#include <CGAL/Barycentric_coordinates_2/Generalized_barycentric_coordinates_2.h>
// いくつかの便利な typedef を紹介します。
typedef CGAL::Exact_predicates_exact_constructions_kernel Kernel;
typedef Kernel::FT Scalar;
typedef Kernel::Point_2 Point;
typedef std:.Scala;
typeedef Kernel::FT Scalar;
typeedef Kernel::FT Scalar;
typedef Kernel::FT Scalarvector<Scalar> Scalar_vector;
typedef std::vector<Point> Point_vector;
typedef std::back_insert_iterator<Scalar_vector> Vector_insert_iterator;
typedef boost::optional<Vector_insert_iterator> Output_type;
typedef CGAL::Barycentric_coordinates::Discrete_harmonic_2<Kernel> Discrete_harmonic;
typedef CGAL:.Discrete_harmonic_2<Kernel> Discrete_harmonic; typeedef CGAL::Barycentric_coordinates::Generalized_barycentric_coordinates_2<Discrete_harmonic, Kernel> Discrete_harmonic_coordinates;
using std::cout; using std::endl; using std::string.Barycentric_coordinates_2<Discrete_harmonic,Kernel> Discrete_harmonic;
<6589> typef CGAL::BareCentric.BareCentric_coordinates
int main()
{
// 単位正方形を構成します。
const int number_of_vertices = 4;
Point_vector vertices(number_of_vertices);
vertices = Point(0, 0); vertices = Point(1, 0); vertices = Point(1, 1); vertices = Point(0, 1);
//座標格納用に std::vector を作成する。
Scalar_vector coordinates;
// 上で定義した単位正方形の離散調和座標を持つクラスのインスタンスを作成する。
Discrete_harmonic_coordinates discrete_harmonic_coordinates(vertices.begin(), vertices.end());
// ポリゴンと座標に関する情報を表示する。
discrete_harmonic_coordinates.print_information();
// 単位正方形の中心点をインスタンス化する。
const Point center(Scalar(1)/Scalar(2), Scalar(1)/Scalar(2));
// 中心点の離散調和座標を算出する。
// query_point_location = CGAL::Barycentric_coordinates::ON_BOUNDED_SIDE パラメータを使用します。
Output_type result = discrete_harmonic_coordinates(center, std::back_inserter(coordinates), CGAL::Barycentric_coordinates::ON_BOUNDED_SIDE);
// 他の4つの内部点をインスタンス化します。
const int number_of_interior_points = 4;
const Point interior_points = { Point(Scalar(1)/Scalar(5), Scalar(1)/Scalar(5)) ,
Point(Scalar(4)/Scalar(5)).Scalar(5)/Scalar(5), Scalar(1)/Scalar(5)) ,
Point(Scalar(4)/Scalar(5), Scalar(4)/Scalar(5)) ,
Point(Scalar(1)/Scalar(5), Scalar(4)/Scalar(5))) };
// これらの点に対して離散調和座標を計算し、前と同じベクトル「座標」に格納する。
for(int i = 0; i < number_of_interior_points; ++i)
result = discrete_harmonic_coordinates(interior_points, std::back_inserter(coordinates), CGAL::Barycentric_coordinates::ON_BOUNDED_SIDE);
// 2辺と最後の辺に境界点2点を設定する。
const Point second_edge(1, Scalar(4)/Scalar(5));
const Point last_edge(0, Scalar(4)/Scalar(5));
// この2点に対して離散調和座標を算出する。
// query_point_location = CGAL::Barycentric_coordinates::ON_BOUNDARY パラメータを使用します。
result = discrete_harmonic_coordinates(second_edge, std::back_inserter(coordinates), CGAL::Barycentric_coordinates::ON_BOUNDARY);
result = discrete_harmonic_coordinates(last_edge , std.BOUNDARY)::back_inserter(coordinates), CGAL::Barycentric_coordinates::ON_BOUNDARY);
// 第1、第3エッジに他の境界点2点をインスタンス化します。
const Point first_edge(Scalar(1)/Scalar(2), 0);
const Point third_edge(Scalar(1)/Scalar(2), 1);
// 任意のエッジのインデックスを用いて離散調和座標を算出する。
// インデックスのカウントが0から始まることを忘れないように。
result = discrete_harmonic_coordinates.compute_on_edge(first_edge, 0, std::back_inserter(coordinates));
result = discrete_harmonic_coordinates.compute_on_edge(third_edge, 2, std::back_inserter(coordinates));
// 単位正方形の第1頂点と第3頂点にある点に対する離散調和座標を計算する。
result = discrete_harmonic_coordinates.compute_on_vertex(0, std::back_inserter(coordinates));
result = discrete_harmonic_coordinates.compute_on_vertex(2, std::back_inserter(coordinates));
// ユニットスクエア2番目と4番目の頂点での点のインスタンスを作成します。
const Point second_vertex(1, 0);
const Point fourth_vertex(0, 1);
// これらの点に対して離散調和座標を計算する。
// query_point_location = CGAL::Barycentric_coordinates::ON_VERTEX パラメータを使用します。
result = discrete_harmonic_coordinates(second_vertex, std::back_inserter(coordinates), CGAL::Barycentric_coordinates::ON_VERTEX);
result = discrete_harmonic_coordinates(fourth_vertex, std.BERCENTIC_CORDINES::ON_CORDINES)::back_inserter(coordinates), CGAL::Barycentric_coordinates::ON_VERTEX);
// 単位正方形の外側に2点、左と右から1点ずつインスタンス化します。
const Point left_most(Scalar(-1)/Scalar(2), Scalar(1)/Scalar(2));
const Point right_most(Scalar(3)/Scalar(2), Scalar(1)/Scalar(2));
// この2点に対して離散調和座標を計算する。
// query_point_location = CGAL::Barycentric_coordinates::ON_UNBOUNDED_SIDE パラメータを使用します。
result = discrete_harmonic_coordinates(left_most , std::back_inserter(coordinates), CGAL::Barycentric_coordinates::ON_UNBOUNDED_SIDE);
result = discrete_harmonic_coordinates(right_most, std.C:B:B:B:C);
result = descrete_harmonic_contordinates(left_most , std::B:B:C):back_inserter(coordinates), CGAL::Barycentric_coordinates::ON_UNBOUNDED_SIDE);
// 計算された座標値を出力します。
cout << endl << “定義されたすべての点に対する正確な離散調和座標値です。 ” << endl << endl;
const size_t number_of_query_points = coordinates.size();
for(int index = 0; index < int(number_of_query_points); ++index) {
cout << “Coordinate ” << index % number_of_vertices + 1 << ” = ” << coordinates << “.座標の値” << “.座標”
cout << “;
if((index + 1) % number_of_vertices == 0) cout << endl;
if((index + 13) % (4 * number_of_vertices) == 0) cout << endl;
}
// 最後の計算の状態を返せます。
const string status = (result ? “SUCCESS.” : “FAILURE.”);
cout << endl << “Status of the last computation. “最後の計算のステータス。 ” << status << endl << endl;
return EXIT_SUCCESS;
}
平均値座標
星形ポリゴンにある緑の点の集合に対して平均値座標を計算する例である。 この種の座標はこのような凹型の多角形に対してよく定義されているが、Wachspressや離散調和座標はそうではないことに注意されたい。 しかし、ポリゴンのカーネルの外側の点(赤で示す)には負の座標値を与える可能性がある。 非正確なデータ型、std::vector
型の出力コンテナ、std::back_insert_iterator型の出力イテレータを用いて、結果の座標値の計算、アクセス、保存を行う。 また、一般化バリセントリック座標を計算するために異なるアルゴリズムを選択する方法を示す(一方はより正確で、他方はより速い)。
図 96.4 例のポイントパターン。
File Barycentric_coordinates_2/Mean_value_coordinates_example.cpp
#include <CGAL/Barycentric_coordinates_2/Mean_value_2.X.X.X.X.X.X.X.
File File Barycentric_coordinates_2-Mean_value_2.h>
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include <CGAL/Barycentric_coordinates_2/Generalized_barycentric_coordinates_2.h>
// いくつかの都合の良い typedefs があります。
typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel;
typedef Kernel::FT Scalar;
typedef Kernel::Point_2 Point;
typedef std:.Scala;Kernel::FT Scalar; typedef Std:.Scalar.Kernel;
typedef STD:.Scalar.Kernel;
typedef std::vector<Point> Point_vector;
typedef std::back_insert_iterator<Scalar_vector> Vector_insert_iterator;
typedef boost:.BOOST:DATA;
typeef std::DATA;
typedef std::DATA;
typedef std::DATA;
typedef CGAL::Barycentric_coordinates::Mean_value_2<Kernel> Mean_value;
typedef CGAL::Barycentric_coordinates::Generalized_barycentric_coordinates_2<Mean_value, Kernel> Mean_value_coordinates;
using std::cout; using std::endl; using std::string;
int main()
{
// 星型のポリゴンを構築します。
const int number_of_vertices = 10;
Point_vector vertices(number_of_vertices);
vertices = Point(0.0, 0.0); vertices = Point(0.1, -0.8); vertices = Point(0.3, 0.0); vertices = Point(0.6, -0.5); vertices = Point(0.6 , 0.1);
vertices = Point(1.1, 0.6); vertices = Point(0.3, 0.2); vertices = Point(0.1, 0.8); vertices = Point(0.1, 0.2); vertices = Point(-0.7, 0.0);
//座標を格納する std::vector を生成します。
Scalar_vector coordinates;
// 上で定義した多角形の平均値座標を持つクラスをインスタンス化します。
Mean_value_coordinates mean_value_coordinates(vertices.begin(), vertices.end());
// ポリゴンや座標に関する情報を表示する。
mean_value_coordinates.print_information();
// ポリゴンの内部点をいくつかインスタンス化する。
const int number_of_interior_points = 8;
const Point interior_points = { Point(0.12, -0.45), Point(0.55, -0.3), Point(0.9 , 0.45),
Point(0.15, 0.35), Point(-0.4, 0.04),Point(0.11, 0.45).11),
Point(0.28, 0.12), // 星型ポリゴンのカーネル内の唯一の点
Point(0.55, 0.11)
};
// すべての定義済み内部点に対する平均値座標を計算する。
// CGAL::Barycentric_coordinates::FAST パラメータで呼び出される O(n) アルゴリズムを用いて計算を高速化する。
// デフォルトはCGAL::Barycentric_coordinates::PRECISEです。
const CGAL::Barycentric_coordinates::Type_of_algorithm type_of_algorithm = CGAL::Barycentric_coordinates::FAST;
// query_point_location = CGAL::Barycentric_coordinates::ON_BOUNDED_SIDE というパラメータも使って計算を高速化する.
const CGAL::Barycentric_coordinates::Query_point_location query_point_location = CGAL::Barycentric_coordinates:.BOUNDED_SIDE:ON_BOUNDED_SIDE;
for(int i = 0; i < number_of_interior_points; ++i) {
const Output_type result = mean_value_coordinates(interior_points, std::back_inserter(coordinates), query_point_location, type_of_algorithm);
// それぞれの点における座標を出力する。
const string status = (result ? “SUCCESS.” : “FAILURE.”);
cout << endl << “For the point ” << i + 1 << “status of the computation: ” << status << endl;
for(int j = 0; j < number_of_vertices; ++j)
cout << “Coordinate ” << j + 1 << ” = “<< coordinates << endl;
}
// ある点の非正規化重みだけが必要な場合(最後の点を取り上げる)、次のように計算することができます。
// 重みを格納するためにstd::vectorをインスタンス化する。
Scalar_vector weights;
// 平均値の重みを計算する。
const int last_point_index = number_of_interior_points – 1;
const Output_type result = mean_value_coordinates.compute_weights(interior_points, std::back_inserter(weights));
// その合計を計算する。
Scalar mv_denominator = Scalar(0);
for(int j = 0; j < number_of_vertices; ++j) mv_denominator += weights;
// この合計を反転させる。
const Scalar mv_inverted_denominator = Scalar(1) / mv_denominator;
// 平均値の重みを出力する。
const string status = (result ? “SUCCESS.” : “FAILURE.”);
cout << endl << “点に対する重みの計算の状況” << last_point_index + 1 << “.NET” << “: ” << status << endl;
for(int j = 0; j < number_of_vertices; ++j)
cout << “Weight ” << j + 1 << ” = ” << weights << endl;
// ここで、重みを正規化すると、先ほど計算した最後の点の平均値座標の値が復元されます。
cout << endl << “After normalization, for the point ” << last_point_index + 1 << “mean value coordinates are ” << endl;
for(int j = 0; j < number_of_vertices; ++j)
cout << “Coordinate ” << j + 1 << ” = ” << weights * mv_inverted_denominator << endl; < << “平均値座標は” <<とする。
cout << endl;
return EXIT_SUCCESS;
}
地形モデリングにおける高度補間
この例は、地形モデリングに適用して一般化バリセントリック座標による高度補間を示す上級者向けのもので、高さ補間には、一般化バリセントリック座標を使用します。 また、Kernel
traits クラスの代わりに、デフォルトでない traits クラスをパッケージで使用する方法も示しています。 例えば、3次元の頂点を持つ多角形として表現される3次元の地形の境界が分かっているとします。 課題は、境界上の既知の標本点からポリゴン内部へ高さを伝播させることである。
図96.5 凸部と凹部を持つ地形の一部を表す50頂点の2次元多角形。 高さは表示していない。
この例では、クラスCGAL::Projection_traits_xy_3
を使って3次元ポリゴンを2次元平面に直交投影し、クラスCGAL::Delaunay_mesher_2
を使ってその内部を三角測量し、得られたすべての点のポリゴン全頂点に対する平均値座標を算出します。 最後に、計算された座標とパッケージ2D and Surface Function Interpolationのグローバル補間関数を用いて、ポリゴンの境界からその内部に高さデータを補間する。
File Barycentric_coordinates_2/Terrain_height_modeling.cpp
#include <CGAL/Delaunay_mesher_2.h>
#include <CGAL/Interpolation_traits_2.h>
#include <CGAL/Projection_traits_xy_3.h >
#Interpression <CGAL/Projection_traits_3.h>
#include <CGAL/interpolation_functions.h>
#include <CGAL/Delaunay_mesh_face_base_2.h>
#include <CGAL/Delaunay_mesh_size_criteria_2.h>
#include <CGAL/Constrained_Delaunay_triangulation_2.h>
#include <CGAL/Barycentric_coordinates_2/Mean_value_2.h>
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#Include <CGAL/Binary_coordinates_2/Mean_value_2.h>
typedef CGAL::Projection_traits_xy_3<Kernel> Projection;
typedef Projection::FT Scalar;
typedef Projection:.Projection_traits_3<Kernel> Projection;
typedef Projection:.Projection_TitlePoint_2 Point;
typedef std::vector<Scalar> Scalar_vector;
typedef std::vector<Point> Point_vector;
// 座標関連。
typedef CGAL::Barycentric_coordinates::Mean_value_2<Projection> Mean_value;
typedef CGAL::Barycentric_coordinates::Generalized_barycentric_coordinates_2<Mean-value, Projection> Mean_value_coordinates;
// 三角測量に関するものです。
typedef CGAL::Delaunay_mesh_face_base_2<Projection> Face_base;
typedef CGAL::Triangulation_vertex_base_2<Projection> Vertex_base;
typedef CGAL::Triangulation_data_structure_2<Vertex_base, Face_base> TDS;
typedef CGAL:.Triangulation_Datas_Base_3<Projection>Vertex_base;
Typedef CGAL::Constrained_Delaunay_triangulation_2<Projection, TDS> CDT;
typedef CGAL::Delaunay_mesh_size_criteria_2<CDT> Criteria;
typedef CGAL:.Delta_Triangulation_2<Projection, TDS> CDT;
typeef:.Delaunay_mesh_size_CriteriaDelaunay_mesher_2<CDT, Criteria> Mesher;
typedef CDT::Finite_vertices_iterator Vertex_iterator;
typedef CDT::Vertex_handle Vertex_handle;
// 内挿関係。
typedef CGAL::Interpolation_traits_2<Projection> Interpolation_traits;
typedef CGAL::Data_access< std::map<Point, Scalar, Projection::Less_xy_2 > Value_access;
// STD.
using std::cout; using std::endl; using std::string;
int main()
{
// 三次元地形の一部を囲むポリゴンを構築します。
// 各頂点のz座標は高さ関数を表すことに注意。
// 2次元での投影はProjection traitsクラスが自動的に行う。
const int number_of_vertices = 50;
Point_vector vertices(number_of_vertices);
vertices = Point(0.0);
vertices = Point(0.03, 0.05, 0.000); vertices = Point(0.07, 0.04, 10.00); vertices = Point(0.10, 0.04, 20.00);
vertices = Point(0.14, 0.04, 30.00);
vertices = Point(0.14, 0.05, 30.00); vertices = Point(0.17, 0.07, 40.00); vertices = Point(0.19, 0.09, 50.00);
vertices = Point(0.22, 0.11, 60.00);
vertices = Point(0.17, 0.07, 30.00); vertices = Point(0.17, 0.00, 40.00)00); vertices = Point(0.25, 0.11, 70.00); vertices = Point(0.27, 0.10, 80.00);
vertices = Point(0.30, 0.07, 90.00); vertices = Point(0.31, 0.04, 100.0); vertices = Point(0.34, 0.03, 110.0);
vertices = Point(0.37, 0.02, 120.0); vertices = Point(0.40, 0.00);
vertices = Point(0.31, 0.04, 100.0); vertices = Point(0.03, 130.0); vertices = Point(0.42, 0.04, 140.0);
vertices = Point(0.44, 0.07, 150.0); vertices = Point(0.45, 0.10, 160.0).0); vertices = Point(0.46, 0.13, 170.0);
vertices = Point(0.46, 0.19, 180.0); vertices = Point(0.47, 0.26, 190.0); vertices = Point(0.47, 0.26, 160.47, 0.31, 200.0);
vertices = Point(0.47, 0.35, 210.0); vertices = Point(0.45, 0.37, 220.0); vertices = Point(0.41, 0.38, 230.0);
vertices = Point(0.38, 0.37, 240.0); vertices = Point(0.35, 0.36, 250.0); vertices = Point(0.32, 0.35, 260.0); vertices = Point(0.35, 0.35, 260.0);
vertices = Point(0.30, 0.37, 270.0); vertices = Point(0.28, 0.39, 280.0); vertices = Point(0.25, 0.40, 290.0);
vertices = Point(0.30, 0.37, 270.0); vertices = Point(0.30, 0.37, 260.0);
vertices = Point(0.23, 0.39, 300.0); vertices = Point(0.21, 0.37, 310.0); vertices = Point(0.21, 0.34, 320.0);
vertices = Point(0.23, 0.32, 330.0);
vertices = Point(0.21, 0.37, 330.0); vertices = Point(0.24, 0.29, 340.0); vertices = Point(0.27, 0.24, 350.0);
vertices = Point(0.29, 0.21, 360.0); vertices = Point(0.29, 0.18, 370.0); vertices = Point(0.26, 0.16, 380.0);
vertices = Point(0.24, 0.17, 390.0); vertices = Point(0.23, 0.19, 400.0);
vertices = Point(0.24, 0.17, 370.0);
vertices = Point(0.27, 0.18, 370.0)0); vertices = Point(0.24, 0.22, 410.0);
vertices = Point(0.24, 0.25, 420.0); vertices = Point(0.21, 0.26, 430.0); vertices = Point(0.21, 0.26, 0.0);
vertices = Point(0.17, 0.26, 440.0);
vertices = Point(0.12, 0.24, 450.0); vertices = Point(0.07, 0.20, 460.0); vertices = Point(0.03, 0.25, 440.0); vertices = Point(0.15, 470.0);
vertices = Point(0.01, 0.10, 480.0); vertices = Point(0.02, 0.07, 490.0);
// このポリゴンをメッシュ化します。
// 制約付きドロネー三角形分割を作成します。
CDT cdt;
std::vector<Vertex_handle> vertex_handle(number_of_vertices);
// 初期点セットとしてポリゴンの頂点を挿入する。
for(int i = 0; i < number_of_vertices; ++i) vertex_handle = cdt.insert(vertices);
// ポリゴン内部のみをメッシュするために、ポリゴンの辺である拘束を挿入する。
for(int i = 0; i < number_of_vertices; ++i) cdt.insert_constraint(vertex_handle, vertex_handle);
Mesher mesher(cdt);
// どうメッシュを作るかの基準を設定する。
mesher.set_criteria(Criteria(0.01, 0.01));
// ポリゴンにメッシュをかける。
mesher.refine_mesh();
// 平均値座標を計算し、ポリゴンの境界から内部へのデータの補間に利用する。
// 各点に対応する関数値と座標を関連付けます。
std::map<Point, Scalar, Projection::Less_xy_2> point_function_value;
std::vector< std:.Border< // 各点に対応する関数と座標を関連付ける。pair<Point, Scalar> point_coordinates(number_of_vertices);
for(int i = 0; i < number_of_vertices; ++i)
point_function_value.POINT_FUNCTION_VALUE.POINT_FUNCTION_VALUE.insert(std::make_pair(vertices, vertices.z()));
// 平均値座標を持つクラスのインスタンスを作成する。
Mean_value_coordinates mean_value_coordinates(vertices.begin(), vertices.end());
// ここに補間データを持つ新しい内点をすべて格納する。
std::vector<Point> points(cdt.number_of_vertices());
cout << endl << “Result of the height interpolation.”「高さの補間の結果です」。 ” << endl << endl;
// 座標を計算し、ポリゴン内部への境界データを補間します。
int index = 0;
for(Vertex_iterator vertex_iterator = cdt.finite_vertices_begin(); vertex_iterator != cdt.int index = 0;
for(Vertex_iterator vertex_iterator = cdt.finite_vertices_begin(); vertex_iterator !finite_vertices_end(); ++vertex_iterator) {
Scalar_vector coordinates;
const Point &point = vertex_iterator->point();
mean_value_coordinates(point, std:.NET) { const Point &point = vertex_iterator->point();
mean_value_coordinates(point, std::back_inserter(coordinates));
for(int j = 0; j < number_of_vertices; ++j)
point_coordinates = std::make_pair(vertices, coordinates);
Scalar f = CGAL::linear_interpolation(point_coordinates.VERITES);
for(string = 0; j < number_of_vertices; +*j)begin(), point_coordinates.end(), Scalar(1), Value_access(point_function_value));
points = Point(point.x(), point.x(), point.y(), f);
cout << ” index << ” で補間した高さは ” << f << “;” << endl;
++ index.F << << <<で補った。
}
cout << endl;
return EXIT_SUCCESS;
}
結果として、ポリゴン内部に地形に近似した滑らかな関数が得られます。
図96.6 補間されたデータ。 カラーバーが対応する高さを表している。
Degeneracies and Special Cases
Segment Coordinates
セグメント座標は正確なデータ型を選択すれば正確に計算できる。 座標を計算するセグメント自体は非変性でなければなりません。 この2つの条件が満たされていれば、計算が失敗することはありません。 しかし、座標を計算するためには、問い合わせた点が線分を支持する線分(line \(L)) 上に正確に存在することを確認する必要がある。
Figure 96.7 The orthogonal projection \(p’\) of the vector \(p) (green) onto the vector \(q) (red).
ある問合せ点Ⓐが直線Ⓐ上に正確に存在せず、上図のようにある程度の距離Ⓐにあったとします。 また、頂点の位置からセグメントのバリセントリック座標を計算したい場合、まずベクトル(p)の直交投影(p’δ)を(q)の長さで正規化します。
Warning: この機能を悪用すると、正しいセグメントバリエントリック座標が得られなくなります。 また、線分 \(L) 上にない点(v)のセグメントバリエントリック座標は存在しません。 しかし、距離(d)が0でないのは、点(v)の位置を計算するときに数値が不安定になるなどして、その点が線上に正確にない場合、最終的なセグメント座標は少なくとも近似的に正しいものになるのです。
不正確なデータ型では、結果の座標値は選択したデータ型の精度まで正しくなります。
三角座標
平面上の任意の問い合わせ点および縮退しない三角形に対して、正確なデータ型を選択すればこれらの座標は正確に計算されます。 特別なケースは処理されません。 計算は常に正しい結果を与える。 正確さの概念は、使用されるデータ型の精度に依存します。
Wachspress座標
Wachspress座標は、任意の厳密な凸多角形の閉路においてよく定義されるものである。 したがって、正確なデータ型を持つポリゴンのクロージャからの任意のクエリー点に対して、これらの座標は正確に計算され、誤った結果は期待されない。 不正確なデータ型の場合、計算の精度は、関連するアルゴリズムと選択されたデータ型に起因します。 次の段落では、Wachspress座標を計算するための2つの利用可能なアルゴリズムについて説明します。 その一つはCGAL::Barycentric_coordinates::PRECISE
で、もう一つはCGAL::Barycentric_coordinates::FAST
です。
図 96.8 Wachspress座標の表記法。
Wachspress重みの計算には、式
\(w_i = \frac{C_i}{A_{i-1}A_i})
ただし、 \(i = 1dots n) はポリゴン頂点の数である。 座標を計算するために、これらの重みを正規化し、
\(b_i = \frac{w_i}{W^{wp}}) with \qquad W^{wp} = \sum_{j=1}^n w_j.\(但し、この式は多角形の境界に近づくと不安定になる)。 この問題を解決するために、重みの値を \(\bar{w}_i = C_iprod_{j}not=i-1,i} A_j}).
上記のように正規化すると、Wachspress座標を計算する精密アルゴリズムが得られるのですが、性能はたったの⑷(O^2 )⑸でしかないのです。 この高速なアルゴリズムでは、標準的な重さ(w_i)が使用されます。
厳密に凸な多角形では、Wachspress座標の分母のゼロ集合( \(W^{wp} = 0~Н))は曲線で、(多くの場合)多角形からかなり離れたところにあることが知られています。 正確には、ポリゴンの辺の連続の交点を補間している。 したがって、多角形の外側のWachspress座標はこの曲線に属さない点でしか計算できない。
図 96.9 非正規六角形のWachspress座標の分母のゼロセット(赤) \(W^{wp})
警告:外接点に対してWachspress座標を使うことはお勧めしません!
Discrete Harmonic Coordinates
離散調和座標はWachspress座標と同じ要件を持っています。 それらは、任意の厳密な凸多角形の閉包においてよく定義され、厳密なデータ型が選ばれるなら、それらは正確に計算される。 しかし、Wachspress基底関数とは異なり、これらの座標は必ずしも正であるとは限らない。 特に、重さ(w_i)が正であるのは、 \(alpha+beta < \pi) のときだけです(表記は下図を参照してください)。 非正確なデータ型の場合、計算の精度は関係するアルゴリズムと選択されたデータ型に起因する。 図96.10 離散調和座標の表記法。
離散調和重みを計算するために。 w_i = \frac{r_{i+1}^2A_{i-1}-r_i^2B_i+r_{i-1}^2A_i}{A_{i-1}A_i})
with \(i = 1}dots n} (ここで[n}はポリゴン頂点の数)の式に従って使用します。 座標を計算するために、これらの重みを正規化し、
\(b_i = \frac{w_i}{W^{dh}}) with \qquad W^{dh} = ⤵um{j=1}^n w_j.\を満たす場合、この式は不安定になり、多角形の境界(ⒶⒶ)に近づきます。 この問題を解決するために、前節と同様に、重みの値を \(\bar{w}_i = (r_{i+1}^2A_{i-1}-r_i^2B_i+r_{i-1}^2A_i)\prod_{j}not=i-1,i} として変更する。 A_j この高速なアルゴリズムは、標準的な重さ(w_i)を使用します。
警告: Wachspress座標については、曲線 \(W^{dh} = 0}) が複数の成分を持ち、そのうちの1つがポリゴンの頂点を補間するため、外点に対する離散調和座標の使用はお勧めしません。
平均値座標
平均値座標は先の座標と異なり、平方根演算が不可避であるため、正確に計算することはできない。 しかし、正確なデータ型が使用される場合、計算のデフォルトの精度は、2つのCGAL関数にのみ依存します。 CGAL::to_double()
と CGAL::sqrt()
の2つのCGAL関数に依存する。 一方、平均値座標は、どんな単純な多角形であっても、平面上のどこでもよく定義されています。 さらに,もしtraitクラスが平方根関数のより正確なバージョンを提供するならば,正確なデータ型による計算の最終的な精度はその関数の精度だけに依存することになります。
図 96.11 平均値座標の表記法
これらの座標に対して、我々はまた2つのアルゴリズムを持っています:1つは正確で、もう1つは速いです。 最初のものは平面上のどこでも動作し、計算の精度は上の備考を含め、選択したデータ型にのみ依存します。 このアルゴリズムは、
の以下の重み式に基づき、 \(w_i = \sigma_i\bar{w}_i}qquad_i = (r_{i-1}r_{i+1}-d_{i-1}d_{i+1})^{1/2}prod_{j not= i-1,i}(r_jr_{j+1} + d_jd_{j+1})^{1/2} ³) where \qquad r_i = \|d_i|.\(bar{w}_i}) は常に正なので、これに符号付き平均値重みの適切な符号(Σ)を付加する必要がありますが、これは効率的に求めることができます(下図参照)。 基本的に、この重みは赤い区分線形曲線の左側では常に正で、反時計回りに右側では負になる。
図 96.12 平均値重み₍凸多角形₍(﹡)と凹多角₍₍ (P’)﹡に領域による記号の違い。
After the normalization of these weights as before
\(b_i = \frac{w_i}{W^{mv}}) with \qquad W^{mv} = \sum_{j=1}^n w_janthus)
we get the precise \(O(n^2)\) algorithm. 高速なO(n)アルゴリズムは、ここにある擬似コードを用いて、重さ(w_i)㎤を計算します。 この重みは
\(w_i = \frac{t_{i-1} + t_i}{r_i} ³)with \qquad t_i = \frac{text{det}(d_i, d_{i+1})}{r_ir_{i+1} ³)で計算されます。 + d_id_{i+1}})
も正規化される。 Wachspressや離散調和座標と同様に、問い合わせ点がポリゴンの境界線に \ よりも近い場合、不安定になることに注意してください。
Performance
Barycentric座標に最も重要な要件は、できるだけ正確であることの他に、できるだけ速く評価することが非常に重要です。 これらの座標は、何百万ものポイントについて計算しなければならない多くのアプリケーションで使用されており、したがって、座標の実時間使用は非常に重要です。
すべての関数について実行したスピードテストの構造は、あるポリゴン(または三角形、またはセグメント)に関して、>= 100 万個の厳密に内側の点における座標値(または重み)を計算することである。 ループの各反復において、クエリーポイントを作成し、それを関数に渡し、関連するすべての座標を計算します。 このループを 10 回連続で実行し、セクションの最後にある対数スケールプロットに示される時間は、すべての試行の算術平均です。
クエリーポイントの数が少ない三角形座標に対するこの性能テストの典型的な例を以下に示します。 この例では、イテレータを構築し、それをクラスに渡す方法も説明しています。 この例では、固定サイズの標準 C++ 配列内の前のポイントの座標値の上に新しいクエリーポイントの座標値を書き込むイテレータを作成し、メモリが 1 回だけ割り当てられるようにします。
File Barycentric_coordinates_2/Triangle_coordinates_speed_test.cpp
#include <CGAL/Real_timer.h>
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include <CGAL/Barycentric_coordinates_2/Triangle_coordinates_2.H
#Instrument <CGAL/Barycentric_coordinates_2/Triangle_cordinates_3.h>
// 現在のデータ型と標準 C++ 配列の最初の要素へのポインタを入力とするイテレータを構築します。
template<typename Scalar>
class overwrite_iterator
{
private:
Scalar* pointer;
public.Scalar
explicit overwrite_iterator(Scalar* new_pointer) : pointer(new_pointer) { }
// Triangle_coordinates_2 クラスを使用するためにオーバーロードする必要がある操作は2つだけです。
// この操作は、現在の座標値を返すためのものです。
inline Scalar& operator* () { return *pointer; }
// この操作は、座標のインデックスを増加させるためのものである。
inline void operator++ () { ++pointer; }
};
// いくつかの便利な typedef があります。
typedef CGAL::Real_timer Timer;
typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel;
typedef Kernel:.Kernel_Constructions_Kernel;
typedef CGAL::Real_timer Timer;
typedef CGAL::Real_timer TimerFT Scalar;
typedef Kernel::Point_2 Point;
typedef overwrite_iterator<Scalar> Overwrite_iterator;
typedef CGAL.FT Scalar;
typedef Kernel::Point_2 Point;
typeef オーバーライト_イテレータ<スカラー;
using std::cout; using std::endl; using std::string;
int main()
{
// x、y座標を合わせた数が点の数となる。
const int number_of_x_coordinates = 100000;
const int number_of_y_coordinates = 1000;
// 時間の算術平均を計算するための実行数です。
const int number_of_runs = 10;
// 座標を変更するためのx、y方向に沿った一様なステップサイズを計算する。
const Scalar zero = Scalar(0);
const Scalar one = Scalar(1);
const Scalar two = Scalar(2);
const Scalar x_step = one / Scalar(number_of_x_coordinates).Scalar(0);
const Scalar x_step = 1 / Scalar(0);
const Scalar x_scalar = 1 / Scalar(2)
const Scalar y_step = one / Scalar(number_of_y_coordinates);
// ゼロから少しずれた直角三角形を作成する。
const Point first_vertex(zero – x_step, zero – x_step);
const Point second_vertex(two + y_step, zero – x_step);
const Point third_vertex(zero – x_step, two + y_step);
// 上の定義で使用する、正しい三角形に対するクラス Triangle_coordinates_2 をインスタンス化します。
Triangle_coordinates triangle_coordinates(first_vertex, second_vertex, third_vertex);
// 座標を格納する標準 C++ 配列のインスタンスを作成する。
// 固定サイズ = 3 = 頂点の数である。
Scalar coordinates = {0, 0, 0};
// 配列の最初の要素に座標を上書きするためにポインタを渡します。
Overwrite_iterator it( &(coordinates) );
// タイマーを作成する。
タイマー time_to_compute;
double time = 0.0;
for(int i = 0; i < number_of_runs; ++i) { // 実行回数
time_to_compute.Time_to_compute.Timer = 0.0;
time_to_compute.Time_out_runs; ++i { // 実行回数
for(Scalar x = zero; x <= one; x += x_step) {
for(Scalar y = zero; y <= one.X_Step); // スタートクロック
for(Scalar x = zero; y <= one; y += y_step)
triangle_coordinates(Point(x, y), it); // 生成された各点に対して3つの座標値を計算
}
time_to_compute.stop(); // 時計を止める
time += time_to_compute.time(); // 全体の時間に現在のランの時間を加える
time_to_compute.reset(); // 時間をリセット
}
// すべてのランの算術平均を計算する。
const double mean_time = time / number_of_runs;
// 結果の時間を出力する。
cout.precision(10);
cout << endl << “CPU time to compute triangle coordinates for ”
<< number_of_x_coordinates * number_of_y_coordinates << “points = ” << mean_time << ” seconds. “の三角座標を求めるCPU時間。”;
cout << endl << endl;
return EXIT_SUCCESS;
}
座標計算時間はメモリ割り当て、入力カーネル、出力容器、点数など多くの要素によって変化します。 我々のテストでは、最小限のメモリ割り当てで、最も標準的なC++とCGALの機能を使用しました。 したがって、最終的に提示された時間は、深い最適化なしでも、効率的なメモリ割り当てで予想される平均時間である。
すべてのテストでは、2 GHz Intel Core i7 プロセッサー (2 コア) および 8 GB 1333 MHz DDR3 メモリーを搭載した MacBook Pro 2011 を使用しました。 インストールされているオペレーティング システムは、OS X 10.9 Maverick です。 スピードテストスイートのコンパイルには、Clang 5.0 64bitコンパイラーを使用しました。 9623>
図96.13 100万点の頂点があるポリゴンに対して、Wachspress座標(青)、離散調和座標(赤)、平均値座標(緑)について、fast \(O(n)\) algorithms(破線)とslow \(0(n^2)\) algorithms(実線)で、 \(n) coordinate values compute the time in seconds.を計算しています。
上の図から、頂点の数が少ない多角形であれば㊙(O(n^2)㊙)アルゴリズムと同じくらい速いことが容易に分かります。 しかし、頂点の数が増えてくると、予想通り線形アルゴリズムが2乗アルゴリズムに勝ります。 この動作の理由の1つは、頂点数が少ない場合、Fast \(O(n)\) algorithm (dashed) と Slow \(O(n^2)\) algorithm (solid) の内部で行う \(n-2)elements の乗算は、対応するdivision in the \(O(n)\) algorithmとほとんど同じ時間がかかるからである。 9623>
Implementation Details
The generic design of the package was developed in 2013 by Dmitry Anisimov and David Bommes with many useful comments by Kai Hormann and Pierre Alliez. パッケージは、6つのクラス、2つの列挙、および1つの名前空間から構成されています。 適切なイテレータは、データへの効率的なアクセスを提供し、座標計算のための汎用アルゴリズムの1つにデータを渡すために使用されます。 一旦、多角形(三角形、セグメント)のインスタンスを作成すると、与えられた多角形(三角形、セグメント)のすべての頂点に対して、異なるクエリーポイントの座標を複数回計算することができる。 すべてのクラスは完全にテンプレート化されており、シンプルで類似したデザインになっています。 特に、すべての関数について、同じ命名規則に従っている。
座標計算の実装アルゴリズムは特定のカーネルに依存せず、平均値座標を除けば、正確なカーネルを用いればすべての座標が正確に計算できる。 後者の座標は平方根演算を伴い、浮動小数点型に一時的に変換されるため、正確なデータ型では精度が若干悪くなります。
注目すべきは、クラス CGAL::Barycentric_coordinates::Segment_coordinates_2
がポリゴンの境界に沿って一般化されたバリセントリック座標を計算するために使用されていることである。 したがって、ある点がポリゴンの境界上に正確に存在しなければならないと確信しているが、いくつかの数値的不安定性のために存在しない場合、「縮退と特殊ケース」のセグメント座標のトリックを使うことができる。
このパッケージは、後で必要に応じて、他の2次元一般化バリセントリック座標をこのパッケージに容易に追加できる方法で実装されている。
Theory of 2D Generalized Barycentric Coordinates
1827年にドイツの数学者、理論天文学者のAugust Ferdinand Möbius (1790-1868) が、平面上の点の座標を三角形の頂点に対して求める方法を提唱しました。 この座標は三角バリセントリック座標(面積座標の場合もある)と呼ばれ、様々な用途に広く用いられている。 その応用例として、三角形上の線形補間や三角形包含検査などがある。 前者はいわゆるシェーディングに使われ、後者はベクターグラフィックス形式の画像をラスター画像に変換する必要があるときにラスタライズステップで生じる。
三角バリセントリック座標は、定数と線形精度、ラグランジェ特性、三角形内部の正値など多くの重要な特性を持っている。 これらの特性により、これらの座標は多くの科学的分野でユニークなツールとなっている。 三角形の座標を三角形の辺の1つとその補助線に限定すると、セグメントに関するバリセントリック座標が得られ、セグメント座標と呼ばれます。
以上の座標について、いくつかのプロットを示しましょう。 線分座標をプロットするには、直線(y=0.4)を取り、その上に線分(second)を定義する。 そして、この線分をサンプルし、すべてのサンプル点に対して線分座標を計算します。 定義されたすべての点でのセグメント座標関数を頂点 Ⓐに対してプロットすると、下図のような青線が得られる。 図96.14 頂点(v_1 = (2.0,♪0.4)♪ に対するすべての定義点(緑)のセグメント座標(青)。
三角形の座標をプロットしたい場合も、同じような方法をとります。 平面上の三角形Ⓐをとり、その内部と境界を何点かサンプリングするのです。 このサンプリングができたら、三角形の座標関数の1つを(ここでは三角形の3番目の頂点を基準にして)定義されたサンプル点すべてでプロットします。 同様に、1番目または2番目の頂点を基準にして座標関数をプロットすることもできる。 その結果得られる関数は、最初の辺に沿ったゼロから、選択された頂点であるⒶ(v_2) で1に成長する線形(下図)です。
図 96.15 Triangle coordinates with respect to \(v_2 = (1.0,\ 2.0)\). カラーバーは選択された座標の値の範囲を示す。
多くのアプリケーションでは、セグメントや三角形よりも複雑な平面幾何形状を扱う必要があるので、任意の多角形に関して三角形座標の一般化版を調査するのは自然なことだと思われます。 最初の試みは1975年にE. L. Wachspressによってなされ、その結果得られた一般化バリセントリック座標は、現在Wachspress座標と呼ばれています。 この座標は、任意の厳密な凸多角形に対してよく定義され、三角形座標のすべての特性を備えています。
前述と同様に、ワッハスプレス座標をプロットして、それがどのように見えるか見てみましょう。 非正規の六角形を選び、それを少し回転させ、その頂点の1つを隣接する2つを通る線に向かって移動させることにしよう。 この多角形の内部と境界を先ほどと同じようにサンプルし、すべてのサンプル点で動かした頂点を基準にした座標関数をプロットしてみます。 カラーバーが示すように、すべての辺に沿った線形で、0から1に成長する滑らかな関数が得られることがわかる。
図96.16 示された頂点を基準としたWachspress座標関数で、カラーバーが示すように0から1までの値を持つ。
一般化されたバリセントリック座標のもう一つのタイプは、1993年のPinkallとPolthier、1995年のEckらの三角メッシュのパラメータ化の文脈にさかのぼります。 これらは離散調和座標と呼ばれます。 これらの座標は、Wachspress座標と同様に、任意の厳密な凸多角形に対してよく定義され、多角形の内部で正の値をとることを除けば、三角形座標のすべての特性を受け継いでいます(ある多角形では負の値をとりうるからです)。
離散調和座標をプロットするために、Wachspress座標と同じ多角形をとり、同じ頂点に関して座標関数をプロットする。 ここでも滑らかな関数が得られ、それはすべての辺に沿った線形で、0から1へ成長する。 プロット中の孤立線は、選ばれたポリゴンと頂点に対する離散調和座標とWachspress座標の差を示す。
図 96.17 カラーバーが示すようにゼロから1までの値を持つ、示された頂点に対する離散調和座標関数。
最後に述べる一般化バリセントリック座標は、M.Floaterが2003年に提案した平均値座標である。 平均値の定理に基づくこの座標は、Wachspressや離散調和座標とは異なり、任意の単純多角形に対してよく定義され、任意の凸多角形に対して三角形座標のすべての特性を継承し、一般の凹多角形に対しては正値性だけが欠落している。 HormannとFloaterは、これらの座標が星型多角形のカーネル内部で正であることを証明した。 また、任意の四角形の閉じた部分でも正である。 平均値重みは離散調和重みと同様、三角形メッシュのパラメタリゼーションによく用いられる。
平均値座標の特殊な振る舞いを凹多角形に適用して示すために、10頂点の星型多角形(heterpic)を取り、その内部と境界をサンプルし、第4頂点の座標関数をプロットする(v_3c)[注1]。 カラーバーが示すように、得られた関数は選ばれた頂点でわずかに負の値から1まで成長する。 また、多角形の内部は滑らかで、すべての辺に沿った線形である。
図 96.18 平均値座標と(v_3 ×)に関する座標。 カラーバーは選択した座標関数の値域を示す。
Interesting fact: all the coordinates discussed in this section and implemented in the package comes from one and the same family of generalized barycentric coordinates named 3-point family of coordinates .
Acknowledgments