diff --git a/Barycentric_coordinates_2/include/CGAL/Barycentric_coordinates_2/Generalized_barycentric_coordinates_2.h b/Barycentric_coordinates_2/include/CGAL/Barycentric_coordinates_2/Generalized_barycentric_coordinates_2.h index 94db271c736c..63c6088ee926 100644 --- a/Barycentric_coordinates_2/include/CGAL/Barycentric_coordinates_2/Generalized_barycentric_coordinates_2.h +++ b/Barycentric_coordinates_2/include/CGAL/Barycentric_coordinates_2/Generalized_barycentric_coordinates_2.h @@ -387,23 +387,18 @@ Generalized_barycentric_coordinates_2 else { // Otherwise, all the coordinates are zero apart from those for the chosen edge with the index = `index`. for(int i = 0; i < index; ++i) { - *output = FT(0); - ++output; + *output++ = FT(0); } // Compute segment coordinates along the chosen edge with the index = `index`. - Segment_coordinates_2 segment_coordinates(vertex[index], vertex[index+1]); - std::optional success = segment_coordinates(query_point, output); - ++output; + output = segment_coordinates_2(vertex[index], vertex[index+1], query_point, output); for(int i = index + 1; i < last; ++i) { - *output = FT(0); - ++output; + *output++ = FT(0); } // Return coordinates. - if(success) return std::optional(output); - else return std::optional(); + return output; } // Pointer cannot be here. Something went wrong. @@ -429,31 +424,24 @@ Generalized_barycentric_coordinates_2 else { // Otherwise, all the coordinates are zeros apart from those for the edge with the query point. int index; - bool status = false; for(index = 0; index < last; ++index) { if(collinear_2(vertex[index], vertex[index+1], query_point) && collinear_are_ordered_along_line_2(vertex[index], query_point, vertex[index+1])) { // Compute segment coordinates along the edge with the query point. - Segment_coordinates_2 segment_coordinates(vertex[index], vertex[index+1]); - std::optional success = segment_coordinates(query_point, output); - if(success) status = true; - ++output; + output = segment_coordinates_2(vertex[index], vertex[index+1], query_point, output); break; } else { - *output = FT(0); - ++output; + *output++ = FT(0); } } for(int i = index + 1; i < last; ++i) { - *output = FT(0); - ++output; + *output++ = FT(0); } // Return coordinates. - if(status == true) return std::optional(output); - else return std::optional(); + return output; } // Pointer cannot be here. Something went wrong. @@ -478,22 +466,18 @@ Generalized_barycentric_coordinates_2 // Compute segment coordinates along the last edge of the polygon. Segment_coordinates_2 segment_coordinates(vertex[last], vertex[0]); - std::optional success = segment_coordinates(query_point, std::back_inserter(coordinate)); + segment_coordinates_2(vertex[last], vertex[0], query_point, std::back_inserter(coordinate)); // Store all the coordinate values. // All the values are zeros apart from those corresponding to the first and the last vertices of the polygon. - *output = coordinate[1]; - ++output; + *output++ = coordinate[1]; for(int i = 1; i < last; ++i) { - *output = FT(0); - ++output; + *output++ = FT(0); } - *output = coordinate[0]; - ++output; + *output++ = coordinate[0]; // Return computed coordinates. - if(success) return std::optional(output); - else return std::optional(); + return output; } // COORDINATES AT VERTEX. diff --git a/Barycentric_coordinates_3/benchmark/Barycentric_coordinates_3/CMakeLists.txt b/Barycentric_coordinates_3/benchmark/Barycentric_coordinates_3/CMakeLists.txt new file mode 100644 index 000000000000..867c102998e3 --- /dev/null +++ b/Barycentric_coordinates_3/benchmark/Barycentric_coordinates_3/CMakeLists.txt @@ -0,0 +1,21 @@ +# Created by the script cgal_create_cmake_script. +# This is the CMake script for compiling a CGAL application. + +project(Barycentric_coordinates_3_Examples) +set(CMAKE_CXX_FLAGS "${CMAXE_CXX_FLAGS} -Wall -Wextra -Werror") + +cmake_minimum_required(VERSION 3.1...3.15) +set(CMAKE_CXX_STANDARD 14) + +find_package(CGAL QUIET COMPONENTS Core) +if(CGAL_FOUND) + + include(${CGAL_USE_FILE}) + include(CGAL_CreateSingleSourceCGALProgram) + + create_single_source_cgal_program("benchmark_tetrahedon_coordinates.cpp") + create_single_source_cgal_program("benchmark_polyhedron_8_vertices.cpp") + +else() + message(WARNING "This program requires the CGAL library, and will not be compiled.") +endif() diff --git a/Barycentric_coordinates_3/benchmark/Barycentric_coordinates_3/benchmark_polyhedron_8_vertices.cpp b/Barycentric_coordinates_3/benchmark/Barycentric_coordinates_3/benchmark_polyhedron_8_vertices.cpp new file mode 100644 index 000000000000..abc1995c9dd5 --- /dev/null +++ b/Barycentric_coordinates_3/benchmark/Barycentric_coordinates_3/benchmark_polyhedron_8_vertices.cpp @@ -0,0 +1,102 @@ +#include +#include +#include +#include +#include + +#include +#include + +#include + +using Kernel = CGAL::Exact_predicates_inexact_constructions_kernel; +using FT = typename Kernel::FT; +using Point_3 = typename Kernel::Point_3; +using Timer = CGAL::Real_timer; +using Vertices = std::vector; +using SM = CGAL::Surface_mesh; + +using WPC3 = CGAL::Barycentric_coordinates::Wachspress_coordinates_3; +using MVC3 = CGAL::Barycentric_coordinates::Mean_value_coordinates_3; +using DHC3 = CGAL::Barycentric_coordinates::Discrete_harmonic_coordinates_3; + +template +double benchmark_overload(const FT scale){ + + const std::size_t number_of_runs = 10; + + // Cube + SM cube; + Vertices cube_coords; + + cube_coords = {Point_3(1.0, 0.0, 0.0), Point_3(1.0, 1.0, 0.0), + Point_3(0.0, 1.0, 0.0), Point_3(0.0, 0.0, 0.0), + Point_3(0.0, 0.0, 1.0), Point_3(1.0, 0.0, 1.0), + Point_3(1.0, 1.0, 1.0), Point_3(0.0, 1.0, 1.0)}; + + CGAL::make_hexahedron(cube_coords[0], cube_coords[1], cube_coords[2], cube_coords[3], + cube_coords[4], cube_coords[5], cube_coords[6], cube_coords[7], cube); + + CGAL::Polygon_mesh_processing::triangulate_faces(cube); + + COORD bar_cube(cube); + + const FT step = FT(1) / scale; + const FT limit = step*scale; + + std::vector bar_coordinates_cube; + bar_coordinates_cube.resize(8); + + Timer timer; + double time = 0.0; + + // Sample interior points + for(std::size_t i = 0; i < number_of_runs; i++){ + + timer.start(); + for(FT x = step; x < limit - step; x += step){ + for(FT y = step; y < limit - step; y += step){ + for(FT z = step; z < limit - step; z += step){ + + const Point_3 query(x, y, z); + bar_cube(query, bar_coordinates_cube.begin()); + } + } + } + timer.stop(); + time += timer.time(); + timer.reset(); + } + + const double mean_time = + time / static_cast(number_of_runs); + + return mean_time; +} + +int main(){ + + std::ofstream wp_file("wp_bench.txt"); + std::ofstream dh_file("dh_bench.txt"); + std::ofstream mv_file("mv_bench.txt"); + + std::ofstream num_file("num_bench.txt"); + + for(std::size_t i = 5; i <= 100; i += 5){ + + wp_file << benchmark_overload(i) << std::endl; + dh_file << benchmark_overload(i) << std::endl; + mv_file << benchmark_overload(i) << std::endl; + + num_file << i << std::endl; + + std::cout << i << "\% complete" << std::endl; + } + + wp_file.close(); + dh_file.close(); + mv_file.close(); + num_file.close(); + + return EXIT_SUCCESS; +} diff --git a/Barycentric_coordinates_3/benchmark/Barycentric_coordinates_3/benchmark_tetrahedon_coordinates.cpp b/Barycentric_coordinates_3/benchmark/Barycentric_coordinates_3/benchmark_tetrahedon_coordinates.cpp new file mode 100644 index 000000000000..797a1890681d --- /dev/null +++ b/Barycentric_coordinates_3/benchmark/Barycentric_coordinates_3/benchmark_tetrahedon_coordinates.cpp @@ -0,0 +1,61 @@ +#include +#include +#include + +using Kernel = CGAL::Exact_predicates_inexact_constructions_kernel; +using FT = typename Kernel::FT; +using Point_3 = typename Kernel::Point_3; +using Timer = CGAL::Real_timer; + +int main() { + + const std::size_t number_of_x_coordinates = 100; + const std::size_t number_of_y_coordinates = 100; + const std::size_t number_of_z_coordinates = 100; + + const std::size_t number_of_runs = 10; + + const FT zero = FT(0); + const FT one = FT(1); + const FT four = FT(4); + + const FT x_step = one / static_cast(number_of_x_coordinates); + const FT y_step = one / static_cast(number_of_y_coordinates); + const FT z_step = one / static_cast(number_of_z_coordinates); + + const Point_3 p0 = Point_3(zero - x_step, zero - y_step, zero - z_step); + const Point_3 p1 = Point_3(four + x_step, zero - y_step, zero - z_step); + const Point_3 p2 = Point_3(zero - x_step, four + y_step, zero - z_step); + const Point_3 p3 = Point_3(zero - x_step, zero - y_step, four + z_step); + + Timer timer; + std::vector coordinates(4); + double time = 0.0; + + for(std::size_t i = 0; i < number_of_runs; i++){ + + timer.start(); + for (FT x = zero; x <= one; x += x_step){ + for (FT y = zero; y <= one; y += y_step){ + for (FT z = zero; z <= one; z += z_step){ + + const Point_3 query(x, y, z); + CGAL::Barycentric_coordinates::tetrahedron_coordinates( + p0, p1, p2, p3, query, coordinates.begin()); + } + } + } + + timer.stop(); + time += timer.time(); + timer.reset(); + } + + const double mean_time = + time / static_cast(number_of_runs); + + std::cout.precision(10); + std::cout << "benchmark_tretrahedron_coordinates (CPU time): " << + mean_time << " seconds" << std::endl; + return EXIT_SUCCESS; +} diff --git a/Barycentric_coordinates_3/benchmark/Barycentric_coordinates_3/scripts/bench_pluto_notebook.jl b/Barycentric_coordinates_3/benchmark/Barycentric_coordinates_3/scripts/bench_pluto_notebook.jl new file mode 100644 index 000000000000..37d42d5ce442 --- /dev/null +++ b/Barycentric_coordinates_3/benchmark/Barycentric_coordinates_3/scripts/bench_pluto_notebook.jl @@ -0,0 +1,858 @@ +### A Pluto.jl notebook ### +# v0.15.1 + +using Markdown +using InteractiveUtils + +# ╔═╡ 5352becc-fc1c-11eb-22d7-c352547689d4 +using Plots + +# ╔═╡ 0034844b-5e15-4db9-ac8b-fdb77df19125 +using DelimitedFiles + +# ╔═╡ d206a52d-b2ab-49ae-96d8-3305888031c5 +samples = readdlm("/home/antonio/Documentos/points.txt", ' ', Float64, '\n') + +# ╔═╡ c27a3346-13b8-4130-87a4-a923652124e4 +interior = scatter(samples[:, 1], samples[:, 2], samples[:, 3], markeralpha = 0.1, ms=1.1, color=RGB(1, 0, 0), title="Bench", label="samples") + +# ╔═╡ 58e01dd7-c7f4-4315-b673-0ec232b02cef +wp_bench = readdlm("/home/antonio/Documentos/gsoc/cgal-public-dev/Barycentric_coordinates_3/benchmark/Barycentric_coordinates_3/build/wp_bench.txt", ' ', Float64, '\n') + + +# ╔═╡ b128fd0d-14e7-45a3-80e3-a76db50dfc7c +dh_bench = readdlm("/home/antonio/Documentos/gsoc/cgal-public-dev/Barycentric_coordinates_3/benchmark/Barycentric_coordinates_3/build/dh_bench.txt", ' ', Float64, '\n') + +# ╔═╡ 832b2e15-7767-4c80-9444-bbc5dfe59ee6 +mv_bench = readdlm("/home/antonio/Documentos/gsoc/cgal-public-dev/Barycentric_coordinates_3/benchmark/Barycentric_coordinates_3/build/mv_bench.txt", ' ', Float64, '\n') + +# ╔═╡ 87f2ae26-3511-47fc-bb35-4c961a57d9ae +num_bench = readdlm("/home/antonio/Documentos/gsoc/cgal-public-dev/Barycentric_coordinates_3/benchmark/Barycentric_coordinates_3/build/num_bench.txt", ' ', Float64, '\n') + +# ╔═╡ 7b3f610a-c4f9-40ff-a904-a3ad7ae81ce1 +plot(num_bench, [wp_bench, dh_bench, mv_bench], label=["WP" "DH" "MV"], xaxis=("n", :log), yaxis=("time (sec)", :log), title="Log-log scale plot") + +# ╔═╡ 00000000-0000-0000-0000-000000000001 +PLUTO_PROJECT_TOML_CONTENTS = """ +[deps] +DelimitedFiles = "8bb1440f-4735-579b-a4ab-409b98df4dab" +Plots = "91a5bcdd-55d7-5caf-9e0b-520d859cae80" + +[compat] +Plots = "~1.20.0" +""" + +# ╔═╡ 00000000-0000-0000-0000-000000000002 +PLUTO_MANIFEST_TOML_CONTENTS = """ +# This file is machine-generated - editing it directly is not advised + +[[Adapt]] +deps = ["LinearAlgebra"] +git-tree-sha1 = "84918055d15b3114ede17ac6a7182f68870c16f7" +uuid = "79e6a3ab-5dfb-504d-930d-738a2a938a0e" +version = "3.3.1" + +[[ArgTools]] +uuid = "0dad84c5-d112-42e6-8d28-ef12dabb789f" + +[[Artifacts]] +uuid = "56f22d72-fd6d-98f1-02f0-08ddc0907c33" + +[[Base64]] +uuid = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f" + +[[Bzip2_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "c3598e525718abcc440f69cc6d5f60dda0a1b61e" +uuid = "6e34b625-4abd-537c-b88f-471c36dfa7a0" +version = "1.0.6+5" + +[[Cairo_jll]] +deps = ["Artifacts", "Bzip2_jll", "Fontconfig_jll", "FreeType2_jll", "Glib_jll", "JLLWrappers", "LZO_jll", "Libdl", "Pixman_jll", "Pkg", "Xorg_libXext_jll", "Xorg_libXrender_jll", "Zlib_jll", "libpng_jll"] +git-tree-sha1 = "e2f47f6d8337369411569fd45ae5753ca10394c6" +uuid = "83423d85-b0ee-5818-9007-b63ccbeb887a" +version = "1.16.0+6" + +[[ColorSchemes]] +deps = ["ColorTypes", "Colors", "FixedPointNumbers", "Random"] +git-tree-sha1 = "9995eb3977fbf67b86d0a0a0508e83017ded03f2" +uuid = "35d6a980-a343-548e-a6ea-1d62b119f2f4" +version = "3.14.0" + +[[ColorTypes]] +deps = ["FixedPointNumbers", "Random"] +git-tree-sha1 = "024fe24d83e4a5bf5fc80501a314ce0d1aa35597" +uuid = "3da002f7-5984-5a60-b8a6-cbb66c0b333f" +version = "0.11.0" + +[[Colors]] +deps = ["ColorTypes", "FixedPointNumbers", "Reexport"] +git-tree-sha1 = "417b0ed7b8b838aa6ca0a87aadf1bb9eb111ce40" +uuid = "5ae59095-9a9b-59fe-a467-6f913c188581" +version = "0.12.8" + +[[Compat]] +deps = ["Base64", "Dates", "DelimitedFiles", "Distributed", "InteractiveUtils", "LibGit2", "Libdl", "LinearAlgebra", "Markdown", "Mmap", "Pkg", "Printf", "REPL", "Random", "SHA", "Serialization", "SharedArrays", "Sockets", "SparseArrays", "Statistics", "Test", "UUIDs", "Unicode"] +git-tree-sha1 = "344f143fa0ec67e47917848795ab19c6a455f32c" +uuid = "34da2185-b29b-5c13-b0c7-acf172513d20" +version = "3.32.0" + +[[CompilerSupportLibraries_jll]] +deps = ["Artifacts", "Libdl"] +uuid = "e66e0078-7015-5450-92f7-15fbd957f2ae" + +[[Contour]] +deps = ["StaticArrays"] +git-tree-sha1 = "9f02045d934dc030edad45944ea80dbd1f0ebea7" +uuid = "d38c429a-6771-53c6-b99e-75d170b6e991" +version = "0.5.7" + +[[DataAPI]] +git-tree-sha1 = "ee400abb2298bd13bfc3df1c412ed228061a2385" +uuid = "9a962f9c-6df0-11e9-0e5d-c546b8b5ee8a" +version = "1.7.0" + +[[DataStructures]] +deps = ["Compat", "InteractiveUtils", "OrderedCollections"] +git-tree-sha1 = "7d9d316f04214f7efdbb6398d545446e246eff02" +uuid = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8" +version = "0.18.10" + +[[DataValueInterfaces]] +git-tree-sha1 = "bfc1187b79289637fa0ef6d4436ebdfe6905cbd6" +uuid = "e2d170a0-9d28-54be-80f0-106bbe20a464" +version = "1.0.0" + +[[Dates]] +deps = ["Printf"] +uuid = "ade2ca70-3891-5945-98fb-dc099432e06a" + +[[DelimitedFiles]] +deps = ["Mmap"] +uuid = "8bb1440f-4735-579b-a4ab-409b98df4dab" + +[[Distributed]] +deps = ["Random", "Serialization", "Sockets"] +uuid = "8ba89e20-285c-5b6f-9357-94700520ee1b" + +[[Downloads]] +deps = ["ArgTools", "LibCURL", "NetworkOptions"] +uuid = "f43a241f-c20a-4ad4-852c-f6b1247861c6" + +[[EarCut_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "92d8f9f208637e8d2d28c664051a00569c01493d" +uuid = "5ae413db-bbd1-5e63-b57d-d24a61df00f5" +version = "2.1.5+1" + +[[Expat_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "b3bfd02e98aedfa5cf885665493c5598c350cd2f" +uuid = "2e619515-83b5-522b-bb60-26c02a35a201" +version = "2.2.10+0" + +[[FFMPEG]] +deps = ["FFMPEG_jll"] +git-tree-sha1 = "b57e3acbe22f8484b4b5ff66a7499717fe1a9cc8" +uuid = "c87230d0-a227-11e9-1b43-d7ebe4e7570a" +version = "0.4.1" + +[[FFMPEG_jll]] +deps = ["Artifacts", "Bzip2_jll", "FreeType2_jll", "FriBidi_jll", "JLLWrappers", "LAME_jll", "LibVPX_jll", "Libdl", "Ogg_jll", "OpenSSL_jll", "Opus_jll", "Pkg", "Zlib_jll", "libass_jll", "libfdk_aac_jll", "libvorbis_jll", "x264_jll", "x265_jll"] +git-tree-sha1 = "3cc57ad0a213808473eafef4845a74766242e05f" +uuid = "b22a6f82-2f65-5046-a5b2-351ab43fb4e5" +version = "4.3.1+4" + +[[FixedPointNumbers]] +deps = ["Statistics"] +git-tree-sha1 = "335bfdceacc84c5cdf16aadc768aa5ddfc5383cc" +uuid = "53c48c17-4a7d-5ca2-90c5-79b7896eea93" +version = "0.8.4" + +[[Fontconfig_jll]] +deps = ["Artifacts", "Bzip2_jll", "Expat_jll", "FreeType2_jll", "JLLWrappers", "Libdl", "Libuuid_jll", "Pkg", "Zlib_jll"] +git-tree-sha1 = "35895cf184ceaab11fd778b4590144034a167a2f" +uuid = "a3f928ae-7b40-5064-980b-68af3947d34b" +version = "2.13.1+14" + +[[Formatting]] +deps = ["Printf"] +git-tree-sha1 = "8339d61043228fdd3eb658d86c926cb282ae72a8" +uuid = "59287772-0a20-5a39-b81b-1366585eb4c0" +version = "0.4.2" + +[[FreeType2_jll]] +deps = ["Artifacts", "Bzip2_jll", "JLLWrappers", "Libdl", "Pkg", "Zlib_jll"] +git-tree-sha1 = "cbd58c9deb1d304f5a245a0b7eb841a2560cfec6" +uuid = "d7e528f0-a631-5988-bf34-fe36492bcfd7" +version = "2.10.1+5" + +[[FriBidi_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "aa31987c2ba8704e23c6c8ba8a4f769d5d7e4f91" +uuid = "559328eb-81f9-559d-9380-de523a88c83c" +version = "1.0.10+0" + +[[GLFW_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Libglvnd_jll", "Pkg", "Xorg_libXcursor_jll", "Xorg_libXi_jll", "Xorg_libXinerama_jll", "Xorg_libXrandr_jll"] +git-tree-sha1 = "dba1e8614e98949abfa60480b13653813d8f0157" +uuid = "0656b61e-2033-5cc2-a64a-77c0f6c09b89" +version = "3.3.5+0" + +[[GR]] +deps = ["Base64", "DelimitedFiles", "GR_jll", "HTTP", "JSON", "Libdl", "LinearAlgebra", "Pkg", "Printf", "Random", "Serialization", "Sockets", "Test", "UUIDs"] +git-tree-sha1 = "182da592436e287758ded5be6e32c406de3a2e47" +uuid = "28b8d3ca-fb5f-59d9-8090-bfdbd6d07a71" +version = "0.58.1" + +[[GR_jll]] +deps = ["Artifacts", "Bzip2_jll", "Cairo_jll", "FFMPEG_jll", "Fontconfig_jll", "GLFW_jll", "JLLWrappers", "JpegTurbo_jll", "Libdl", "Libtiff_jll", "Pixman_jll", "Pkg", "Qt5Base_jll", "Zlib_jll", "libpng_jll"] +git-tree-sha1 = "d59e8320c2747553788e4fc42231489cc602fa50" +uuid = "d2c73de3-f751-5644-a686-071e5b155ba9" +version = "0.58.1+0" + +[[GeometryBasics]] +deps = ["EarCut_jll", "IterTools", "LinearAlgebra", "StaticArrays", "StructArrays", "Tables"] +git-tree-sha1 = "58bcdf5ebc057b085e58d95c138725628dd7453c" +uuid = "5c1252a2-5f33-56bf-86c9-59e7332b4326" +version = "0.4.1" + +[[Gettext_jll]] +deps = ["Artifacts", "CompilerSupportLibraries_jll", "JLLWrappers", "Libdl", "Libiconv_jll", "Pkg", "XML2_jll"] +git-tree-sha1 = "9b02998aba7bf074d14de89f9d37ca24a1a0b046" +uuid = "78b55507-aeef-58d4-861c-77aaff3498b1" +version = "0.21.0+0" + +[[Glib_jll]] +deps = ["Artifacts", "Gettext_jll", "JLLWrappers", "Libdl", "Libffi_jll", "Libiconv_jll", "Libmount_jll", "PCRE_jll", "Pkg", "Zlib_jll"] +git-tree-sha1 = "7bf67e9a481712b3dbe9cb3dac852dc4b1162e02" +uuid = "7746bdde-850d-59dc-9ae8-88ece973131d" +version = "2.68.3+0" + +[[Grisu]] +git-tree-sha1 = "53bb909d1151e57e2484c3d1b53e19552b887fb2" +uuid = "42e2da0e-8278-4e71-bc24-59509adca0fe" +version = "1.0.2" + +[[HTTP]] +deps = ["Base64", "Dates", "IniFile", "Logging", "MbedTLS", "NetworkOptions", "Sockets", "URIs"] +git-tree-sha1 = "44e3b40da000eab4ccb1aecdc4801c040026aeb5" +uuid = "cd3eb016-35fb-5094-929b-558a96fad6f3" +version = "0.9.13" + +[[IniFile]] +deps = ["Test"] +git-tree-sha1 = "098e4d2c533924c921f9f9847274f2ad89e018b8" +uuid = "83e8ac13-25f8-5344-8a64-a9f2b223428f" +version = "0.5.0" + +[[InteractiveUtils]] +deps = ["Markdown"] +uuid = "b77e0a4c-d291-57a0-90e8-8db25a27a240" + +[[IterTools]] +git-tree-sha1 = "05110a2ab1fc5f932622ffea2a003221f4782c18" +uuid = "c8e1da08-722c-5040-9ed9-7db0dc04731e" +version = "1.3.0" + +[[IteratorInterfaceExtensions]] +git-tree-sha1 = "a3f24677c21f5bbe9d2a714f95dcd58337fb2856" +uuid = "82899510-4779-5014-852e-03e436cf321d" +version = "1.0.0" + +[[JLLWrappers]] +deps = ["Preferences"] +git-tree-sha1 = "642a199af8b68253517b80bd3bfd17eb4e84df6e" +uuid = "692b3bcd-3c85-4b1f-b108-f13ce0eb3210" +version = "1.3.0" + +[[JSON]] +deps = ["Dates", "Mmap", "Parsers", "Unicode"] +git-tree-sha1 = "8076680b162ada2a031f707ac7b4953e30667a37" +uuid = "682c06a0-de6a-54ab-a142-c8b1cf79cde6" +version = "0.21.2" + +[[JpegTurbo_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "d735490ac75c5cb9f1b00d8b5509c11984dc6943" +uuid = "aacddb02-875f-59d6-b918-886e6ef4fbf8" +version = "2.1.0+0" + +[[LAME_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "f6250b16881adf048549549fba48b1161acdac8c" +uuid = "c1c5ebd0-6772-5130-a774-d5fcae4a789d" +version = "3.100.1+0" + +[[LZO_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "e5b909bcf985c5e2605737d2ce278ed791b89be6" +uuid = "dd4b983a-f0e5-5f8d-a1b7-129d4a5fb1ac" +version = "2.10.1+0" + +[[LaTeXStrings]] +git-tree-sha1 = "c7f1c695e06c01b95a67f0cd1d34994f3e7db104" +uuid = "b964fa9f-0449-5b57-a5c2-d3ea65f4040f" +version = "1.2.1" + +[[Latexify]] +deps = ["Formatting", "InteractiveUtils", "LaTeXStrings", "MacroTools", "Markdown", "Printf", "Requires"] +git-tree-sha1 = "a4b12a1bd2ebade87891ab7e36fdbce582301a92" +uuid = "23fbe1c1-3f47-55db-b15f-69d7ec21a316" +version = "0.15.6" + +[[LibCURL]] +deps = ["LibCURL_jll", "MozillaCACerts_jll"] +uuid = "b27032c2-a3e7-50c8-80cd-2d36dbcbfd21" + +[[LibCURL_jll]] +deps = ["Artifacts", "LibSSH2_jll", "Libdl", "MbedTLS_jll", "Zlib_jll", "nghttp2_jll"] +uuid = "deac9b47-8bc7-5906-a0fe-35ac56dc84c0" + +[[LibGit2]] +deps = ["Base64", "NetworkOptions", "Printf", "SHA"] +uuid = "76f85450-5226-5b5a-8eaa-529ad045b433" + +[[LibSSH2_jll]] +deps = ["Artifacts", "Libdl", "MbedTLS_jll"] +uuid = "29816b5a-b9ab-546f-933c-edad1886dfa8" + +[[LibVPX_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "12ee7e23fa4d18361e7c2cde8f8337d4c3101bc7" +uuid = "dd192d2f-8180-539f-9fb4-cc70b1dcf69a" +version = "1.10.0+0" + +[[Libdl]] +uuid = "8f399da3-3557-5675-b5ff-fb832c97cbdb" + +[[Libffi_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "761a393aeccd6aa92ec3515e428c26bf99575b3b" +uuid = "e9f186c6-92d2-5b65-8a66-fee21dc1b490" +version = "3.2.2+0" + +[[Libgcrypt_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Libgpg_error_jll", "Pkg"] +git-tree-sha1 = "64613c82a59c120435c067c2b809fc61cf5166ae" +uuid = "d4300ac3-e22c-5743-9152-c294e39db1e4" +version = "1.8.7+0" + +[[Libglvnd_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libX11_jll", "Xorg_libXext_jll"] +git-tree-sha1 = "7739f837d6447403596a75d19ed01fd08d6f56bf" +uuid = "7e76a0d4-f3c7-5321-8279-8d96eeed0f29" +version = "1.3.0+3" + +[[Libgpg_error_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "c333716e46366857753e273ce6a69ee0945a6db9" +uuid = "7add5ba3-2f88-524e-9cd5-f83b8a55f7b8" +version = "1.42.0+0" + +[[Libiconv_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "42b62845d70a619f063a7da093d995ec8e15e778" +uuid = "94ce4f54-9a6c-5748-9c1c-f9c7231a4531" +version = "1.16.1+1" + +[[Libmount_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "9c30530bf0effd46e15e0fdcf2b8636e78cbbd73" +uuid = "4b2f31a3-9ecc-558c-b454-b3730dcb73e9" +version = "2.35.0+0" + +[[Libtiff_jll]] +deps = ["Artifacts", "JLLWrappers", "JpegTurbo_jll", "Libdl", "Pkg", "Zlib_jll", "Zstd_jll"] +git-tree-sha1 = "340e257aada13f95f98ee352d316c3bed37c8ab9" +uuid = "89763e89-9b03-5906-acba-b20f662cd828" +version = "4.3.0+0" + +[[Libuuid_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "7f3efec06033682db852f8b3bc3c1d2b0a0ab066" +uuid = "38a345b3-de98-5d2b-a5d3-14cd9215e700" +version = "2.36.0+0" + +[[LinearAlgebra]] +deps = ["Libdl"] +uuid = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" + +[[Logging]] +uuid = "56ddb016-857b-54e1-b83d-db4d58db5568" + +[[MacroTools]] +deps = ["Markdown", "Random"] +git-tree-sha1 = "0fb723cd8c45858c22169b2e42269e53271a6df7" +uuid = "1914dd2f-81c6-5fcd-8719-6d5c9610ff09" +version = "0.5.7" + +[[Markdown]] +deps = ["Base64"] +uuid = "d6f4376e-aef5-505a-96c1-9c027394607a" + +[[MbedTLS]] +deps = ["Dates", "MbedTLS_jll", "Random", "Sockets"] +git-tree-sha1 = "1c38e51c3d08ef2278062ebceade0e46cefc96fe" +uuid = "739be429-bea8-5141-9913-cc70e7f3736d" +version = "1.0.3" + +[[MbedTLS_jll]] +deps = ["Artifacts", "Libdl"] +uuid = "c8ffd9c3-330d-5841-b78e-0817d7145fa1" + +[[Measures]] +git-tree-sha1 = "e498ddeee6f9fdb4551ce855a46f54dbd900245f" +uuid = "442fdcdd-2543-5da2-b0f3-8c86c306513e" +version = "0.3.1" + +[[Missings]] +deps = ["DataAPI"] +git-tree-sha1 = "4ea90bd5d3985ae1f9a908bd4500ae88921c5ce7" +uuid = "e1d29d7a-bbdc-5cf2-9ac0-f12de2c33e28" +version = "1.0.0" + +[[Mmap]] +uuid = "a63ad114-7e13-5084-954f-fe012c677804" + +[[MozillaCACerts_jll]] +uuid = "14a3606d-f60d-562e-9121-12d972cd8159" + +[[NaNMath]] +git-tree-sha1 = "bfe47e760d60b82b66b61d2d44128b62e3a369fb" +uuid = "77ba4419-2d1f-58cd-9bb1-8ffee604a2e3" +version = "0.3.5" + +[[NetworkOptions]] +uuid = "ca575930-c2e3-43a9-ace4-1e988b2c1908" + +[[Ogg_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "7937eda4681660b4d6aeeecc2f7e1c81c8ee4e2f" +uuid = "e7412a2a-1a6e-54c0-be00-318e2571c051" +version = "1.3.5+0" + +[[OpenSSL_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "15003dcb7d8db3c6c857fda14891a539a8f2705a" +uuid = "458c3c95-2e84-50aa-8efc-19380b2a3a95" +version = "1.1.10+0" + +[[Opus_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "51a08fb14ec28da2ec7a927c4337e4332c2a4720" +uuid = "91d4177d-7536-5919-b921-800302f37372" +version = "1.3.2+0" + +[[OrderedCollections]] +git-tree-sha1 = "85f8e6578bf1f9ee0d11e7bb1b1456435479d47c" +uuid = "bac558e1-5e72-5ebc-8fee-abe8a469f55d" +version = "1.4.1" + +[[PCRE_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "b2a7af664e098055a7529ad1a900ded962bca488" +uuid = "2f80f16e-611a-54ab-bc61-aa92de5b98fc" +version = "8.44.0+0" + +[[Parsers]] +deps = ["Dates"] +git-tree-sha1 = "477bf42b4d1496b454c10cce46645bb5b8a0cf2c" +uuid = "69de0a69-1ddd-5017-9359-2bf0b02dc9f0" +version = "2.0.2" + +[[Pixman_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "b4f5d02549a10e20780a24fce72bea96b6329e29" +uuid = "30392449-352a-5448-841d-b1acce4e97dc" +version = "0.40.1+0" + +[[Pkg]] +deps = ["Artifacts", "Dates", "Downloads", "LibGit2", "Libdl", "Logging", "Markdown", "Printf", "REPL", "Random", "SHA", "Serialization", "TOML", "Tar", "UUIDs", "p7zip_jll"] +uuid = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f" + +[[PlotThemes]] +deps = ["PlotUtils", "Requires", "Statistics"] +git-tree-sha1 = "a3a964ce9dc7898193536002a6dd892b1b5a6f1d" +uuid = "ccf2f8ad-2431-5c83-bf29-c5338b663b6a" +version = "2.0.1" + +[[PlotUtils]] +deps = ["ColorSchemes", "Colors", "Dates", "Printf", "Random", "Reexport", "Statistics"] +git-tree-sha1 = "501c20a63a34ac1d015d5304da0e645f42d91c9f" +uuid = "995b91a9-d308-5afd-9ec6-746e21dbc043" +version = "1.0.11" + +[[Plots]] +deps = ["Base64", "Contour", "Dates", "FFMPEG", "FixedPointNumbers", "GR", "GeometryBasics", "JSON", "Latexify", "LinearAlgebra", "Measures", "NaNMath", "PlotThemes", "PlotUtils", "Printf", "REPL", "Random", "RecipesBase", "RecipesPipeline", "Reexport", "Requires", "Scratch", "Showoff", "SparseArrays", "Statistics", "StatsBase", "UUIDs"] +git-tree-sha1 = "e39bea10478c6aff5495ab522517fae5134b40e3" +uuid = "91a5bcdd-55d7-5caf-9e0b-520d859cae80" +version = "1.20.0" + +[[Preferences]] +deps = ["TOML"] +git-tree-sha1 = "00cfd92944ca9c760982747e9a1d0d5d86ab1e5a" +uuid = "21216c6a-2e73-6563-6e65-726566657250" +version = "1.2.2" + +[[Printf]] +deps = ["Unicode"] +uuid = "de0858da-6303-5e67-8744-51eddeeeb8d7" + +[[Qt5Base_jll]] +deps = ["Artifacts", "CompilerSupportLibraries_jll", "Fontconfig_jll", "Glib_jll", "JLLWrappers", "Libdl", "Libglvnd_jll", "OpenSSL_jll", "Pkg", "Xorg_libXext_jll", "Xorg_libxcb_jll", "Xorg_xcb_util_image_jll", "Xorg_xcb_util_keysyms_jll", "Xorg_xcb_util_renderutil_jll", "Xorg_xcb_util_wm_jll", "Zlib_jll", "xkbcommon_jll"] +git-tree-sha1 = "ad368663a5e20dbb8d6dc2fddeefe4dae0781ae8" +uuid = "ea2cea3b-5b76-57ae-a6ef-0a8af62496e1" +version = "5.15.3+0" + +[[REPL]] +deps = ["InteractiveUtils", "Markdown", "Sockets", "Unicode"] +uuid = "3fa0cd96-eef1-5676-8a61-b3b8758bbffb" + +[[Random]] +deps = ["Serialization"] +uuid = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" + +[[RecipesBase]] +git-tree-sha1 = "b3fb709f3c97bfc6e948be68beeecb55a0b340ae" +uuid = "3cdcf5f2-1ef4-517c-9805-6587b60abb01" +version = "1.1.1" + +[[RecipesPipeline]] +deps = ["Dates", "NaNMath", "PlotUtils", "RecipesBase"] +git-tree-sha1 = "2a7a2469ed5d94a98dea0e85c46fa653d76be0cd" +uuid = "01d81517-befc-4cb6-b9ec-a95719d0359c" +version = "0.3.4" + +[[Reexport]] +git-tree-sha1 = "5f6c21241f0f655da3952fd60aa18477cf96c220" +uuid = "189a3867-3050-52da-a836-e630ba90ab69" +version = "1.1.0" + +[[Requires]] +deps = ["UUIDs"] +git-tree-sha1 = "4036a3bd08ac7e968e27c203d45f5fff15020621" +uuid = "ae029012-a4dd-5104-9daa-d747884805df" +version = "1.1.3" + +[[SHA]] +uuid = "ea8e919c-243c-51af-8825-aaa63cd721ce" + +[[Scratch]] +deps = ["Dates"] +git-tree-sha1 = "0b4b7f1393cff97c33891da2a0bf69c6ed241fda" +uuid = "6c6a2e73-6563-6170-7368-637461726353" +version = "1.1.0" + +[[Serialization]] +uuid = "9e88b42a-f829-5b0c-bbe9-9e923198166b" + +[[SharedArrays]] +deps = ["Distributed", "Mmap", "Random", "Serialization"] +uuid = "1a1011a3-84de-559e-8e89-a11a2f7dc383" + +[[Showoff]] +deps = ["Dates", "Grisu"] +git-tree-sha1 = "91eddf657aca81df9ae6ceb20b959ae5653ad1de" +uuid = "992d4aef-0814-514b-bc4d-f2e9a6c4116f" +version = "1.0.3" + +[[Sockets]] +uuid = "6462fe0b-24de-5631-8697-dd941f90decc" + +[[SortingAlgorithms]] +deps = ["DataStructures"] +git-tree-sha1 = "b3363d7460f7d098ca0912c69b082f75625d7508" +uuid = "a2af1166-a08f-5f64-846c-94a0d3cef48c" +version = "1.0.1" + +[[SparseArrays]] +deps = ["LinearAlgebra", "Random"] +uuid = "2f01184e-e22b-5df5-ae63-d93ebab69eaf" + +[[StaticArrays]] +deps = ["LinearAlgebra", "Random", "Statistics"] +git-tree-sha1 = "3240808c6d463ac46f1c1cd7638375cd22abbccb" +uuid = "90137ffa-7385-5640-81b9-e52037218182" +version = "1.2.12" + +[[Statistics]] +deps = ["LinearAlgebra", "SparseArrays"] +uuid = "10745b16-79ce-11e8-11f9-7d13ad32a3b2" + +[[StatsAPI]] +git-tree-sha1 = "1958272568dc176a1d881acb797beb909c785510" +uuid = "82ae8749-77ed-4fe6-ae5f-f523153014b0" +version = "1.0.0" + +[[StatsBase]] +deps = ["DataAPI", "DataStructures", "LinearAlgebra", "Missings", "Printf", "Random", "SortingAlgorithms", "SparseArrays", "Statistics", "StatsAPI"] +git-tree-sha1 = "fed1ec1e65749c4d96fc20dd13bea72b55457e62" +uuid = "2913bbd2-ae8a-5f71-8c99-4fb6c76f3a91" +version = "0.33.9" + +[[StructArrays]] +deps = ["Adapt", "DataAPI", "StaticArrays", "Tables"] +git-tree-sha1 = "000e168f5cc9aded17b6999a560b7c11dda69095" +uuid = "09ab397b-f2b6-538f-b94a-2f83cf4a842a" +version = "0.6.0" + +[[TOML]] +deps = ["Dates"] +uuid = "fa267f1f-6049-4f14-aa54-33bafae1ed76" + +[[TableTraits]] +deps = ["IteratorInterfaceExtensions"] +git-tree-sha1 = "c06b2f539df1c6efa794486abfb6ed2022561a39" +uuid = "3783bdb8-4a98-5b6b-af9a-565f29a5fe9c" +version = "1.0.1" + +[[Tables]] +deps = ["DataAPI", "DataValueInterfaces", "IteratorInterfaceExtensions", "LinearAlgebra", "TableTraits", "Test"] +git-tree-sha1 = "d0c690d37c73aeb5ca063056283fde5585a41710" +uuid = "bd369af6-aec1-5ad0-b16a-f7cc5008161c" +version = "1.5.0" + +[[Tar]] +deps = ["ArgTools", "SHA"] +uuid = "a4e569a6-e804-4fa4-b0f3-eef7a1d5b13e" + +[[Test]] +deps = ["InteractiveUtils", "Logging", "Random", "Serialization"] +uuid = "8dfed614-e22c-5e08-85e1-65c5234f0b40" + +[[URIs]] +git-tree-sha1 = "97bbe755a53fe859669cd907f2d96aee8d2c1355" +uuid = "5c2747f8-b7ea-4ff2-ba2e-563bfd36b1d4" +version = "1.3.0" + +[[UUIDs]] +deps = ["Random", "SHA"] +uuid = "cf7118a7-6976-5b1a-9a39-7adc72f591a4" + +[[Unicode]] +uuid = "4ec0a83e-493e-50e2-b9ac-8f72acf5a8f5" + +[[Wayland_jll]] +deps = ["Artifacts", "Expat_jll", "JLLWrappers", "Libdl", "Libffi_jll", "Pkg", "XML2_jll"] +git-tree-sha1 = "3e61f0b86f90dacb0bc0e73a0c5a83f6a8636e23" +uuid = "a2964d1f-97da-50d4-b82a-358c7fce9d89" +version = "1.19.0+0" + +[[Wayland_protocols_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Wayland_jll"] +git-tree-sha1 = "2839f1c1296940218e35df0bbb220f2a79686670" +uuid = "2381bf8a-dfd0-557d-9999-79630e7b1b91" +version = "1.18.0+4" + +[[XML2_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Libiconv_jll", "Pkg", "Zlib_jll"] +git-tree-sha1 = "1acf5bdf07aa0907e0a37d3718bb88d4b687b74a" +uuid = "02c8fc9c-b97f-50b9-bbe4-9be30ff0a78a" +version = "2.9.12+0" + +[[XSLT_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Libgcrypt_jll", "Libgpg_error_jll", "Libiconv_jll", "Pkg", "XML2_jll", "Zlib_jll"] +git-tree-sha1 = "91844873c4085240b95e795f692c4cec4d805f8a" +uuid = "aed1982a-8fda-507f-9586-7b0439959a61" +version = "1.1.34+0" + +[[Xorg_libX11_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libxcb_jll", "Xorg_xtrans_jll"] +git-tree-sha1 = "5be649d550f3f4b95308bf0183b82e2582876527" +uuid = "4f6342f7-b3d2-589e-9d20-edeb45f2b2bc" +version = "1.6.9+4" + +[[Xorg_libXau_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "4e490d5c960c314f33885790ed410ff3a94ce67e" +uuid = "0c0b7dd1-d40b-584c-a123-a41640f87eec" +version = "1.0.9+4" + +[[Xorg_libXcursor_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libXfixes_jll", "Xorg_libXrender_jll"] +git-tree-sha1 = "12e0eb3bc634fa2080c1c37fccf56f7c22989afd" +uuid = "935fb764-8cf2-53bf-bb30-45bb1f8bf724" +version = "1.2.0+4" + +[[Xorg_libXdmcp_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "4fe47bd2247248125c428978740e18a681372dd4" +uuid = "a3789734-cfe1-5b06-b2d0-1dd0d9d62d05" +version = "1.1.3+4" + +[[Xorg_libXext_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libX11_jll"] +git-tree-sha1 = "b7c0aa8c376b31e4852b360222848637f481f8c3" +uuid = "1082639a-0dae-5f34-9b06-72781eeb8cb3" +version = "1.3.4+4" + +[[Xorg_libXfixes_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libX11_jll"] +git-tree-sha1 = "0e0dc7431e7a0587559f9294aeec269471c991a4" +uuid = "d091e8ba-531a-589c-9de9-94069b037ed8" +version = "5.0.3+4" + +[[Xorg_libXi_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libXext_jll", "Xorg_libXfixes_jll"] +git-tree-sha1 = "89b52bc2160aadc84d707093930ef0bffa641246" +uuid = "a51aa0fd-4e3c-5386-b890-e753decda492" +version = "1.7.10+4" + +[[Xorg_libXinerama_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libXext_jll"] +git-tree-sha1 = "26be8b1c342929259317d8b9f7b53bf2bb73b123" +uuid = "d1454406-59df-5ea1-beac-c340f2130bc3" +version = "1.1.4+4" + +[[Xorg_libXrandr_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libXext_jll", "Xorg_libXrender_jll"] +git-tree-sha1 = "34cea83cb726fb58f325887bf0612c6b3fb17631" +uuid = "ec84b674-ba8e-5d96-8ba1-2a689ba10484" +version = "1.5.2+4" + +[[Xorg_libXrender_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libX11_jll"] +git-tree-sha1 = "19560f30fd49f4d4efbe7002a1037f8c43d43b96" +uuid = "ea2f1a96-1ddc-540d-b46f-429655e07cfa" +version = "0.9.10+4" + +[[Xorg_libpthread_stubs_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "6783737e45d3c59a4a4c4091f5f88cdcf0908cbb" +uuid = "14d82f49-176c-5ed1-bb49-ad3f5cbd8c74" +version = "0.1.0+3" + +[[Xorg_libxcb_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "XSLT_jll", "Xorg_libXau_jll", "Xorg_libXdmcp_jll", "Xorg_libpthread_stubs_jll"] +git-tree-sha1 = "daf17f441228e7a3833846cd048892861cff16d6" +uuid = "c7cfdc94-dc32-55de-ac96-5a1b8d977c5b" +version = "1.13.0+3" + +[[Xorg_libxkbfile_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libX11_jll"] +git-tree-sha1 = "926af861744212db0eb001d9e40b5d16292080b2" +uuid = "cc61e674-0454-545c-8b26-ed2c68acab7a" +version = "1.1.0+4" + +[[Xorg_xcb_util_image_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_xcb_util_jll"] +git-tree-sha1 = "0fab0a40349ba1cba2c1da699243396ff8e94b97" +uuid = "12413925-8142-5f55-bb0e-6d7ca50bb09b" +version = "0.4.0+1" + +[[Xorg_xcb_util_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libxcb_jll"] +git-tree-sha1 = "e7fd7b2881fa2eaa72717420894d3938177862d1" +uuid = "2def613f-5ad1-5310-b15b-b15d46f528f5" +version = "0.4.0+1" + +[[Xorg_xcb_util_keysyms_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_xcb_util_jll"] +git-tree-sha1 = "d1151e2c45a544f32441a567d1690e701ec89b00" +uuid = "975044d2-76e6-5fbe-bf08-97ce7c6574c7" +version = "0.4.0+1" + +[[Xorg_xcb_util_renderutil_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_xcb_util_jll"] +git-tree-sha1 = "dfd7a8f38d4613b6a575253b3174dd991ca6183e" +uuid = "0d47668e-0667-5a69-a72c-f761630bfb7e" +version = "0.3.9+1" + +[[Xorg_xcb_util_wm_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_xcb_util_jll"] +git-tree-sha1 = "e78d10aab01a4a154142c5006ed44fd9e8e31b67" +uuid = "c22f9ab0-d5fe-5066-847c-f4bb1cd4e361" +version = "0.4.1+1" + +[[Xorg_xkbcomp_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libxkbfile_jll"] +git-tree-sha1 = "4bcbf660f6c2e714f87e960a171b119d06ee163b" +uuid = "35661453-b289-5fab-8a00-3d9160c6a3a4" +version = "1.4.2+4" + +[[Xorg_xkeyboard_config_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_xkbcomp_jll"] +git-tree-sha1 = "5c8424f8a67c3f2209646d4425f3d415fee5931d" +uuid = "33bec58e-1273-512f-9401-5d533626f822" +version = "2.27.0+4" + +[[Xorg_xtrans_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "79c31e7844f6ecf779705fbc12146eb190b7d845" +uuid = "c5fb5394-a638-5e4d-96e5-b29de1b5cf10" +version = "1.4.0+3" + +[[Zlib_jll]] +deps = ["Libdl"] +uuid = "83775a58-1f1d-513f-b197-d71354ab007a" + +[[Zstd_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "cc4bf3fdde8b7e3e9fa0351bdeedba1cf3b7f6e6" +uuid = "3161d3a3-bdf6-5164-811a-617609db77b4" +version = "1.5.0+0" + +[[libass_jll]] +deps = ["Artifacts", "Bzip2_jll", "FreeType2_jll", "FriBidi_jll", "JLLWrappers", "Libdl", "Pkg", "Zlib_jll"] +git-tree-sha1 = "acc685bcf777b2202a904cdcb49ad34c2fa1880c" +uuid = "0ac62f75-1d6f-5e53-bd7c-93b484bb37c0" +version = "0.14.0+4" + +[[libfdk_aac_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "7a5780a0d9c6864184b3a2eeeb833a0c871f00ab" +uuid = "f638f0a6-7fb0-5443-88ba-1cc74229b280" +version = "0.1.6+4" + +[[libpng_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Zlib_jll"] +git-tree-sha1 = "94d180a6d2b5e55e447e2d27a29ed04fe79eb30c" +uuid = "b53b4c65-9356-5827-b1ea-8c7a1a84506f" +version = "1.6.38+0" + +[[libvorbis_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Ogg_jll", "Pkg"] +git-tree-sha1 = "c45f4e40e7aafe9d086379e5578947ec8b95a8fb" +uuid = "f27f6e37-5d2b-51aa-960f-b287f2bc3b7a" +version = "1.3.7+0" + +[[nghttp2_jll]] +deps = ["Artifacts", "Libdl"] +uuid = "8e850ede-7688-5339-a07c-302acd2aaf8d" + +[[p7zip_jll]] +deps = ["Artifacts", "Libdl"] +uuid = "3f19e933-33d8-53b3-aaab-bd5110c3b7a0" + +[[x264_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "d713c1ce4deac133e3334ee12f4adff07f81778f" +uuid = "1270edf5-f2f9-52d2-97e9-ab00b5d0237a" +version = "2020.7.14+2" + +[[x265_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "487da2f8f2f0c8ee0e83f39d13037d6bbf0a45ab" +uuid = "dfaa095f-4041-5dcd-9319-2fabd8486b76" +version = "3.0.0+3" + +[[xkbcommon_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Wayland_jll", "Wayland_protocols_jll", "Xorg_libxcb_jll", "Xorg_xkeyboard_config_jll"] +git-tree-sha1 = "ece2350174195bb31de1a63bea3a41ae1aa593b6" +uuid = "d8fb68d0-12a3-5cfd-a85a-d49703b185fd" +version = "0.9.1+5" +""" + +# ╔═╡ Cell order: +# ╠═5352becc-fc1c-11eb-22d7-c352547689d4 +# ╠═0034844b-5e15-4db9-ac8b-fdb77df19125 +# ╠═d206a52d-b2ab-49ae-96d8-3305888031c5 +# ╠═c27a3346-13b8-4130-87a4-a923652124e4 +# ╠═58e01dd7-c7f4-4315-b673-0ec232b02cef +# ╠═b128fd0d-14e7-45a3-80e3-a76db50dfc7c +# ╠═832b2e15-7767-4c80-9444-bbc5dfe59ee6 +# ╠═87f2ae26-3511-47fc-bb35-4c961a57d9ae +# ╠═7b3f610a-c4f9-40ff-a904-a3ad7ae81ce1 +# ╟─00000000-0000-0000-0000-000000000001 +# ╟─00000000-0000-0000-0000-000000000002 diff --git a/Barycentric_coordinates_3/benchmark/Barycentric_coordinates_3/scripts/bench_raw.jl b/Barycentric_coordinates_3/benchmark/Barycentric_coordinates_3/scripts/bench_raw.jl new file mode 100644 index 000000000000..21ee29982680 --- /dev/null +++ b/Barycentric_coordinates_3/benchmark/Barycentric_coordinates_3/scripts/bench_raw.jl @@ -0,0 +1,13 @@ +using Plots +using DelimitedFiles + +samples = readdlm("/home/antonio/Documentos/points.txt", ' ', Float64, '\n') + +interior = scatter(samples[:, 1], samples[:, 2], samples[:, 3], markeralpha = 0.1, ms=1.1, color=RGB(1, 0, 0), title="Bench", label="samples") + +wp_bench = readdlm("/home/antonio/Documentos/gsoc/cgal-public-dev/Barycentric_coordinates_3/benchmark/Barycentric_coordinates_3/build/wp_bench.txt", ' ', Float64, '\n') +dh_bench = readdlm("/home/antonio/Documentos/gsoc/cgal-public-dev/Barycentric_coordinates_3/benchmark/Barycentric_coordinates_3/build/dh_bench.txt", ' ', Float64, '\n') +mv_bench = readdlm("/home/antonio/Documentos/gsoc/cgal-public-dev/Barycentric_coordinates_3/benchmark/Barycentric_coordinates_3/build/mv_bench.txt", ' ', Float64, '\n') +num_bench = readdlm("/home/antonio/Documentos/gsoc/cgal-public-dev/Barycentric_coordinates_3/benchmark/Barycentric_coordinates_3/build/num_bench.txt", ' ', Float64, '\n') + +plot(num_bench, [wp_bench, dh_bench, mv_bench], label=["WP" "DH" "MV"], xaxis=("n", :log), yaxis=("time (sec)", :log), title="Log-log scale plot") diff --git a/Barycentric_coordinates_3/benchmark/bench.md b/Barycentric_coordinates_3/benchmark/bench.md new file mode 100644 index 000000000000..8cca1dfa7534 --- /dev/null +++ b/Barycentric_coordinates_3/benchmark/bench.md @@ -0,0 +1,9 @@ +Benchmark July 7: + +Here are the results for a triangulated cube, with 1000000 points sampled regularly: +1) Wachspress : benchmark_polyhedron_8_vertices (CPU time): 59.1783669 seconds +2) Discrete Harmonic : benchmark_polyhedron_8_vertices (CPU time): 167.832063 seconds +3) Mean Value : benchmark_polyhedron_8_vertices (CPU time): 199.651994 seconds + + Here is the result for a tetrahedron, with 1000000 points sampled regularly: + 1) Tetrahedron: benchmark_tretrahedron_coordinates (CPU time): 1.612018108 seconds \ No newline at end of file diff --git a/Barycentric_coordinates_3/doc/Barycentric_coordinates_3/Barycentric_coordinates_3.txt b/Barycentric_coordinates_3/doc/Barycentric_coordinates_3/Barycentric_coordinates_3.txt new file mode 100644 index 000000000000..a12bb42aede2 --- /dev/null +++ b/Barycentric_coordinates_3/doc/Barycentric_coordinates_3/Barycentric_coordinates_3.txt @@ -0,0 +1,275 @@ +namespace CGAL { +namespace Barycentric_coordinates { + +/*! +\mainpage User Manual +\anchor Chapter_3D_Generalized_Barycentric_Coordinates +\cgalAutoToc + +\authors Antonio Gomes, Dmitry Anisimov + + +\section gbc_3_introduction Introduction + +Barycentric coordinates are an important tool in computer graphics and geometric modeling. +Originally, these coordinates were used to represent a given point with respect to a simplex but have been later +generalized to more complex shapes. + +The package 3D Generalized Barycentric Coordinates offers an efficient and robust implementation +of three-dimensional closed-form, generalized barycentric coordinates defined for convex simplicial polytopes. + +In particular, this package includes an implementation of Wachspress, discrete harmonic, mean value, and +one extra function to calculate barycentric coordinates with respect to tetrahedra. In this implementation, +we restrict our polyhedra to convex ones with triangular faces, although some of the coordinates may +accept more general shapes. + + +\section gbc_3_interface Software Design + +Wachspress, discrete harmonic, and mean value coordinates are all generalized barycentric coordinates +that can be computed analytically. +All of the three analytic coordinates can be computed either by instantiating a class or through a +free function. Tetrahedron coordinates can be computed only through the free function. + +Similarly to `Barycentric_coordinates::Computation_policy_2` in the 2D package, we can specify a computation +policy Barycentric_coordinates::Computation_policy_3 that can be FAST or +FAST_WITH_EDGE_CASES for each of the three analytical coordinates. The difference between them is that FAST_WITH_EDGE_CASES +treats points near the boundaries by projecting them into the face of the polyhedron and then calculating triangle coordinates. +Note that, different from the 2D package, there is not yet an implementation for a PRECISE algorithm. + +The output of a query point is the coordinate value with respect to each vertex, the number of coordinates + values being the same as the number of vertices, and the ordering is also the same. + +All class and function templates are parameterized by a traits class, which is a model of the concept +BarycentricTraits_3. It provides all necessary geometric primitives, predicates, and constructions, +which are required for the computation. All models of Kernel can be used. A polyhedron is provided as +a model of the concept FaceListGraph with a property map that maps a vertex from the polyhedron to BarycentricTraits_3::Point_3. + + +\section gbc_3_examples Examples + +To facilitate the process of learning this package, we provide various examples +with basic usage of different barycentric components. + + +\subsection tetra_example Tetrahedron Coordinates + +In this example, we use the global function `tetrahedron_coordinates_in_array()`. +We compute coordinates for the tetrahedron whose vertices are the points in the +set {(0,0,0), (1,0,0), (0,1,0), (0,0,1)}. We use points inside, outside and +at the boundary of the tetrahedron. + +\cgalExample{Barycentric_coordinates_3/tetrahedron_coordinates.cpp} + +\subsection wp_3_example Wachspress Coordinates + +In this example, we generate 250 random points inside a unit sphere, +centered at the origin, then we take the convex hull of this set of points +and use this as our polyhedron. Finally, we calculate Wachspress coordinates +for all of these 250 points. + +\cgalExample{Barycentric_coordinates_3/wachspress_coordinates.cpp} + +\subsection dh_3_example Discrete Harmonic Coordinates + +This example is very similar to the one used with tetrahedron coordinates. +We start with a regular icosahedron and for points inside, outside and +at the boundary, we calculate discrete harmonic coordinates. In this example, +we use the fast with edge cases algorithm because it treats points very close +to the boundaries. + +\cgalExample{Barycentric_coordinates_3/discrete_harmonic_coordinates.cpp} + +\subsection mv_3_example Mean Value Coordinates + +This example shows how to compute mean value coordinates for a set of points in a +star-shaped polyhedron. We note that this type of coordinate is well-defined for a +concave polyhedron but it may yield negative coordinate values for points outside +the polyhedron's kernel (shown in blue). + +\cgalFigureBegin{mv_3_example, mv_coords_example_3.png} +Example's point pattern. +\cgalFigureEnd + +\cgalExample{Barycentric_coordinates_3/mean_value_coordinates.cpp} + +\subsection shape_deform_example_3 Shape deformation + +This is an example that shows how to deform a simple smooth sphere into +another shape, topologically equivalent. To achieve this, we enclose the +sphere inside a cube cage, then we calculate the barycentric +coordinate of each vertex with respect to the cube cage. After deforming +the cage, we calculate the linear combination of the points to get the +deformed sphere vertices. + +\cgalFigureBegin{shape_deform_example_3, shape_deform_example_3.png} +The shape on the left is deformed into the shape on the right. +\cgalFigureEnd + +\cgalExample{Barycentric_coordinates_3/shape_deformation.cpp} + +\section gbc_3_degeneracies Edge Cases + +The precision of each coordinate depends on the used `Kernel`. If an inexact kernel +is used and the user is not sure if the points are near the boundaries, `FAST_WITH_EDGE_CASES` +algorithm should be used. +Implementation details are described in \cgalCite{cgal:bc:f-wmvc-14} for Wachspress and mean value +coordinates, and in \cgalCite{cgal:bc:jlw-ggcccsp-07} for discrete harmonic coordinates. + +For each coordinate, it is necessary to make divisions by the signed distance between the query +point and each face. So, if one of these distances is zero or close to zero (query point at the boundary), +it will cause a division by zero error or numerical instability, respectively. +To avoid this, the main purpose of the FAST_WITH_EDGE_CASES algorithm is to extend the region where the analytical +coordinates are well-defined. It adds the guarantee to calculate points near the boundaries. The +way it works is very simple: before calculating any coordinate, the algorithm checks, for each face, +if the distance between the query point and the plane is less than one predetermined tolerance. If so, +instead of calculating the analytical form of the coordinates, it decomposes the query point with +respect to this particular face and then calculates triangle coordinates. However, for Wachspress +coordinates, the 2D version is used because the faces are not necessarily triangular. Note that for +every vertex that does not belong to this face, the coordinate value will be zero. + +\subsection gbc_3_degeneracies_tetrahedron Tetrahedron Coordinates + +To compute tetrahedron coordinates of the query point `q`, we adopt the simple formula: +
+\f$w_i = \frac{V_i}{V}\f$ +
+ +where \f$V_i\f$ is the signed volume of the sub-tetrahedron opposite to the vertex \f$i\f$ and \f$V\f$ +is the total volume of the tetrahedron, that is \f$V = V_0 + V_1 + V_2 + V_3\f$. + +These coordinates can be computed exactly if an exact number type is chosen, for any query point +in the space and with respect to any non-degenerate tetrahedron. No special cases are handled. +The computation always yields the correct result. The notion of correctness depends on the precision +of the used number type. Note that for exterior points some coordinate values will be negative. + +\subsection gbc_3_degeneracies_wachspress Wachspress Coordinates + +For each vertex \f$v\f$, let \f$f_1, f_2, ..., f_k\f$ be the \f$k\f$ faces incident to \f$v\f$. We +are assuming that the faces are taken in counterclockwise order. + +We can define \f${p_f}({q}) = \frac{{n_f}}{h_f({q})}\f$, +and \f$h_f({q}) = ({v} - {q})\cdot {n_f}\f$ as the perpendicular distance of \f$q\f$ to \f$f\f$. +For the face \f$f\f$, let \f${n_f}\f$ denote its unit outward normal. + +So, to compute Wachspress coordinates of the query point `q`, we adopt the simple formula: +
+\f$w_v({q}) = \sum_{i=2}^{k-1}det({p_{f_1}}({q}), {p_{f_i}}({q}), {p_{f_{i+1}}}({q}))\f$ +
+ +In this implementation, Wachspress coordinates are well defined in the closure of any convex +polyhedra. If an exact number type is chosen, they are computed exactly. + +\subsection gbc_3_degeneracies_discrete_harmonic Discrete Harmonic Coordinates + +To compute discrete harmonic coordinates of the query point `q`, we adopt the simple formula: +
+\f$w_i = \sum_{T : v_i \in T} \frac{cot[\theta_i^T]h_i^T}{2}\f$ +
+ +where, within a triangle face T = {v1, v2, v3}, \f$\theta_i^T\f$ is the dihedral angle between T and +triangle {x,\f$v_{i+1}\f$, \f$v_{i−1}\f$}, and \f$h_i^T\f$ is the edge length \f$|v_{i+1} − v_{i−1}|\f$. + +Discrete harmonic coordinates cannot be computed exactly due to a square root operation. +Although, if an exact number type is used, the default precision of the computation depends only on +two CGAL functions: CGAL::to_double() and CGAL::sqrt(). In this implementation, discrete harmonic +coordinates are well defined in the closure of any convex polyhedra with triangular faces. Unlike +Wachspress coordinates, they are not necessarily positive. + +\subsection gbc_3_degeneracies_mean_value Mean Value Coordinates + +To compute mean value coordinates of the query point `q`, we adopt the simple formula: +
+\f$w_i = \frac{1}{2}\sum_{j=1}^3 \beta_j\frac{{m_j}\cdot {m_{i+1}}}{{e_i}\cdot {m_{i+1}}}\f$ +
+ +where a vertex v is projected to the point (unit vector) \f$e_v = \frac{({v} - {q})}{|{v - q}|}\f$, and +\f${m_i} = \frac{{e_i} \times {e_{i+1}}}{|{e_i} \times {e_{i+1}}|}\f$. \f$\beta_j \in (0, \pi)\f$ is the angle +between \f$e_i\f$ and \f$e_{i+1}\f$. + +Like discrete harmonic, mean value coordinates cannot be computed exactly due to a square root +operation. In this implementation, mean value coordinates are well defined everywhere in the space, +but just for polyhedra with triangular faces. Also, they are non-negative in the kernel of a +star-shaped polyhedron. + +\section gbc_3_performance Performance + +Efficiency is really important in this implementation. +These coordinates are used in applications that require +calculations for millions of points, thus developing metrics +to evaluate performance is absolutely necessary. In this section, +we present benchmark results for each algorithm. + +To make the benchmark and evaluate runtimes, for each analytic coordinate, +we regularly sample approximately \f$n^3\f$ (\f$n\f$ varying from 1 to 100) strictly +interior points with respect to a cube with unit length, and then calculate +its coordinate values (see figure below). The results are represented in a log-log +scale plot and are the mean value of 10 loop iterations (see plot below). + +\cgalFigureBegin{bc_coords_bench_structure_3, bc_coords_bench_structure_3.png} +The points shown in red are the sample points used to make the benchmark. +\cgalFigureEnd + +The performance strongly depends on the chosen kernel, +for this test, we choose to use `Simple_cartesian` because is much faster than others. +Also, we can see that time (WP) << time (DH) < time (MV). This happens because wp +implementation has fewer instructions per loop than the other two, so naturally, +the computation time tends to be faster. + +\cgalFigureBegin{bc_coords_bench_3, bc_coords_bench_3.png} +Time in seconds to compute \f$n^3\f$ coordinate values for a cube. Are represented in the graph: +Wachspress (blue), discrete harmonic (orange), and mean value (green). +\cgalFigureEnd + +Tetrahedron coordinates are not shown in the same plot because the test is +slightly different. For this one, we simply show in the table below +the results for some pre-defined quantity of points. The test is done by regularly +sampling strictly interior points with respect to a tetrahedron with +unit sides that lies on the coordinate axis. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Number of points Total time (in seconds)
10000.002662682533
500000.09459688663
1000000.1865084648
5000000.8238497972
10000001.665773582
50000008.359417105
+ +To benchmark each coordinate, we used a 2.6 GHz Intel Core i7 processor (6 cores) +and 16 GB DDR4 2933MHz memory. The installed operating system was Ubuntu 20.04 LTS. + +\section gbc_3_history History + +This package was introduced during GSoC 2021 and implemented by Antonio Gomes +under the supervision of Dmitry Anisimov. + +\section gbc_3_acknowledgments Acknowledgments + + +*/ + +} /* namespace Barycentric_coordinates */ +} /* namespace CGAL */ diff --git a/Barycentric_coordinates_3/doc/Barycentric_coordinates_3/Concepts/BarycentricTraits_3.h b/Barycentric_coordinates_3/doc/Barycentric_coordinates_3/Concepts/BarycentricTraits_3.h new file mode 100644 index 000000000000..83666e14a7f7 --- /dev/null +++ b/Barycentric_coordinates_3/doc/Barycentric_coordinates_3/Concepts/BarycentricTraits_3.h @@ -0,0 +1,117 @@ +namespace CGAL { +namespace Barycentric_coordinates { + +/*! +\ingroup PkgBarycentricCoordinates3RefConcepts +\cgalConcept + +A concept that describes the set of requirements of the template parameter +`GeomTraits` used to parameterize all classes and functions with 3D barycentric +coordinates from the namespace `CGAL::Barycentric_coordinates`. The concept `BarycentricTraits_3` +extends the concept `BarycentricTraits_2` and adds the requirements for 3D objects. +\cgalGeneralizes `BarycentricTraits_2` + +\cgalHasModelsBegin +\cgalHasModelsBare{All models of the \cgal concept `Kernel`} +\cgalHasModelsEnd + +*/ +class BarycentricTraits_3 { + +public: + +/// \name Types +/// @{ + +/*! + A model of `FieldNumberType`. +*/ +typedef unspecified_type FT; + +/// @} + +/// \name 3D Geometric Objects +/// @{ + +/*! + A model of `Kernel::Point_3`. +*/ +typedef unspecified_type Point_3; + +/*! + A model of `Kernel::Vector_3`. +*/ +typedef unspecified_type Vector_3; + +/// @} + +/// \name 3D Generalized Constructions +/// @{ + +/*! + A construction object that must provide the function operator: + + `FT operator(const Point_3& p0, const Point_3& p1, const Point_3& p2, const Point_3& p3)` + + that returns the signed volume of the tetrahedron defined by the four points `p0`, `p1`, `p2`, and `p3`. +*/ +typedef unspecified_type Compute_volume_3; + +/*! + A construction object that must provide the function operator: + + `FT operator(const Vector_3& u, const Vector_3& v)` + + that returns an approximation of the angle between `u` and `v`. + The angle is given in degrees. +*/ +typedef unspecified_type Compute_approximate_angle_3; + +/*! + A construction object that must provide the function operator: + + `FT operator(const Vector_3& v, const Vector_3& w)` + + that returns the scalar (inner) product of the two vectors `v` and `w`. +*/ +typedef unspecified_type Compute_scalar_product_3; + +/*! + A construction object that must provide the function operator: + + `FT operator(const Vector_3& u, const Vector_3& v, const Vector_3& w)` + + that returns the determinant of the three vectors `u`, `v` and `w`. +*/ +typedef unspecified_type Compute_determinant_3; + +/*! + A construction object that must provide the function operator: + + `Vector_3 operator(const Point_3& p, const Point_3& q)` + + that returns the vector `q` - `p`. +*/ +typedef unspecified_type Construct_vector_3; + +/*! + A construction object that must provide the function operator: + + `Vector_3 operator(const Vector_3& u, const Vector_3& v)` + + that returns the cross product between `u` and `v`. +*/ +typedef unspecified_type Construct_cross_product_vector_3; + +/// @} + +/// \name 2D Generalized Predicates +/// @{ + + +/// @} + +}; + +} // namespace Barycentric_coordinates +} // namespace CGAL diff --git a/Barycentric_coordinates_3/doc/Barycentric_coordinates_3/Doxyfile.in b/Barycentric_coordinates_3/doc/Barycentric_coordinates_3/Doxyfile.in new file mode 100644 index 000000000000..0e974af9d661 --- /dev/null +++ b/Barycentric_coordinates_3/doc/Barycentric_coordinates_3/Doxyfile.in @@ -0,0 +1,6 @@ +@INCLUDE = ${CGAL_DOC_PACKAGE_DEFAULTS} +PROJECT_NAME = "CGAL ${CGAL_DOC_VERSION} - 3D Generalized Barycentric Coordinates" +EXTRACT_ALL = false + +HIDE_UNDOC_MEMBERS = true +HIDE_UNDOC_CLASSES = true diff --git a/Barycentric_coordinates_3/doc/Barycentric_coordinates_3/PackageDescription.txt b/Barycentric_coordinates_3/doc/Barycentric_coordinates_3/PackageDescription.txt new file mode 100644 index 000000000000..66cc3e9fe199 --- /dev/null +++ b/Barycentric_coordinates_3/doc/Barycentric_coordinates_3/PackageDescription.txt @@ -0,0 +1,61 @@ +namespace CGAL { +namespace Barycentric_coordinates { + +/*! +\defgroup PkgBarycentricCoordinates3Ref 3D Generalized Barycentric Coordinates Reference + +\defgroup PkgBarycentricCoordinates3RefConcepts Concepts +\ingroup PkgBarycentricCoordinates3Ref + +Generalized barycentric concepts. + +\defgroup PkgBarycentricCoordinates3RefAnalytic Analytic Coordinates +\ingroup PkgBarycentricCoordinates3Ref + +Analytic coordinates and related classes. + +\defgroup PkgBarycentricCoordinates3RefFunctions Free Functions +\ingroup PkgBarycentricCoordinates3Ref + +Free functions to compute barycentric coordinates. + +\addtogroup PkgBarycentricCoordinates3Ref + +\cgalPkgDescriptionBegin{3D Generalized Barycentric Coordinates, PkgBarycentricCoordinates3} +\cgalPkgPicture{barcoord_thumb_3.png} + +\cgalPkgSummaryBegin +\cgalPkgAuthors{Antonio Gomes, Dmitry Anisimov} +\cgalPkgDesc{The package 3D Generalized Barycentric Coordinates offers an efficient and robust +implementation of three-dimensional closed-form generalized barycentric coordinates +defined for convex simplicial polytopes.} +\cgalPkgManuals{Chapter_3D_Generalized_Barycentric_Coordinates, PkgBarycentricCoordinates3Ref} +\cgalPkgSummaryEnd + +\cgalPkgShortInfoBegin +\cgalPkgSince{5.1} +\cgalPkgBib{abha-gbc} +\cgalPkgLicense{\ref licensesGPL "GPL"} +\cgalPkgShortInfoEnd +\cgalPkgDescriptionEnd + +\cgalClassifedRefPages + +## Concepts ## +- `BarycentricTraits_3` + +## Analytic Coordinates ## +- `Wachspress_coordinates_3` +- `Mean_value_coordinates_3` +- `Discrete_harmonic_coordinates_3` + +## Free Functions ## +- `tetrahedron_coordinates()` +- `wachspress_coordinates_3()` +- `mean_value_coordinates_3()` +- `discrete_harmonic_coordinates_3()` +- `boundary_coordinates_3()` +*/ + +} /* namespace Barycentric_coordinates */ +} /* namespace CGAL */ diff --git a/Barycentric_coordinates_3/doc/Barycentric_coordinates_3/dependencies b/Barycentric_coordinates_3/doc/Barycentric_coordinates_3/dependencies new file mode 100644 index 000000000000..79d42fedd85a --- /dev/null +++ b/Barycentric_coordinates_3/doc/Barycentric_coordinates_3/dependencies @@ -0,0 +1,18 @@ +Manual +Mesh_2 +Polygon +BGL +Barycentric_coordinates_2 +Kernel_d +Kernel_23 +Generator +Convex_hull_2 +Number_types +Interpolation +STL_Extension +Triangulation_2 +Algebraic_foundations +Circulator +Stream_support +Property_map +Surface_mesh_parameterization diff --git a/Barycentric_coordinates_3/doc/Barycentric_coordinates_3/examples.txt b/Barycentric_coordinates_3/doc/Barycentric_coordinates_3/examples.txt new file mode 100644 index 000000000000..cf204ddf092d --- /dev/null +++ b/Barycentric_coordinates_3/doc/Barycentric_coordinates_3/examples.txt @@ -0,0 +1,7 @@ +/*! +\example Barycentric_coordinates_3/tetrahedron_coordinates.cpp +\example Barycentric_coordinates_3/wachspress_coordinates.cpp +\example Barycentric_coordinates_3/discrete_harmonic_coordinates.cpp +\example Barycentric_coordinates_3/mean_value_coordinates.cpp +\example Barycentric_coordinates_3/shape_deformation.cpp +*/ diff --git a/Barycentric_coordinates_3/doc/Barycentric_coordinates_3/fig/barcoord_thumb_3.png b/Barycentric_coordinates_3/doc/Barycentric_coordinates_3/fig/barcoord_thumb_3.png new file mode 100644 index 000000000000..3f266461ffb4 Binary files /dev/null and b/Barycentric_coordinates_3/doc/Barycentric_coordinates_3/fig/barcoord_thumb_3.png differ diff --git a/Barycentric_coordinates_3/doc/Barycentric_coordinates_3/fig/bc_coords_bench_3.png b/Barycentric_coordinates_3/doc/Barycentric_coordinates_3/fig/bc_coords_bench_3.png new file mode 100644 index 000000000000..3643b8800f82 Binary files /dev/null and b/Barycentric_coordinates_3/doc/Barycentric_coordinates_3/fig/bc_coords_bench_3.png differ diff --git a/Barycentric_coordinates_3/doc/Barycentric_coordinates_3/fig/bc_coords_bench_structure_3.png b/Barycentric_coordinates_3/doc/Barycentric_coordinates_3/fig/bc_coords_bench_structure_3.png new file mode 100644 index 000000000000..7a528454bc90 Binary files /dev/null and b/Barycentric_coordinates_3/doc/Barycentric_coordinates_3/fig/bc_coords_bench_structure_3.png differ diff --git a/Barycentric_coordinates_3/doc/Barycentric_coordinates_3/fig/mv_coords_example_3.png b/Barycentric_coordinates_3/doc/Barycentric_coordinates_3/fig/mv_coords_example_3.png new file mode 100644 index 000000000000..85846242d19a Binary files /dev/null and b/Barycentric_coordinates_3/doc/Barycentric_coordinates_3/fig/mv_coords_example_3.png differ diff --git a/Barycentric_coordinates_3/doc/Barycentric_coordinates_3/fig/shape_deform_example_3.png b/Barycentric_coordinates_3/doc/Barycentric_coordinates_3/fig/shape_deform_example_3.png new file mode 100644 index 000000000000..ef7ffbd2b0ac Binary files /dev/null and b/Barycentric_coordinates_3/doc/Barycentric_coordinates_3/fig/shape_deform_example_3.png differ diff --git a/Barycentric_coordinates_3/examples/Barycentric_coordinates_3/CMakeLists.txt b/Barycentric_coordinates_3/examples/Barycentric_coordinates_3/CMakeLists.txt new file mode 100644 index 000000000000..2d942fc6ff04 --- /dev/null +++ b/Barycentric_coordinates_3/examples/Barycentric_coordinates_3/CMakeLists.txt @@ -0,0 +1,15 @@ +# Created by the script cgal_create_cmake_script. +# This is the CMake script for compiling a CGAL application. + +cmake_minimum_required(VERSION 3.1...3.23) +project(Barycentric_coordinates_3_Examples) + +find_package(CGAL REQUIRED) + +include(CGAL_CreateSingleSourceCGALProgram) + +create_single_source_cgal_program("tetrahedron_coordinates.cpp") +create_single_source_cgal_program("shape_deformation_3.cpp") +create_single_source_cgal_program("wachspress_coordinates_3.cpp") +create_single_source_cgal_program("discrete_harmonic_coordinates_3.cpp") +create_single_source_cgal_program("mean_value_coordinates_3.cpp") diff --git a/Barycentric_coordinates_3/examples/Barycentric_coordinates_3/discrete_harmonic_coordinates_3.cpp b/Barycentric_coordinates_3/examples/Barycentric_coordinates_3/discrete_harmonic_coordinates_3.cpp new file mode 100644 index 000000000000..929a28009ec7 --- /dev/null +++ b/Barycentric_coordinates_3/examples/Barycentric_coordinates_3/discrete_harmonic_coordinates_3.cpp @@ -0,0 +1,47 @@ +#define PHI 1.6180339887498948482 + +#include +#include +#include +#include + +#include + +using Kernel = CGAL::Exact_predicates_inexact_constructions_kernel; +using FT = Kernel::FT; +using Point_3 = Kernel::Point_3; +using Surface_mesh = CGAL::Surface_mesh; +namespace PMP = CGAL::Polygon_mesh_processing; +using CP3 = CGAL::Barycentric_coordinates::Computation_policy_3; + +int main(){ + + Surface_mesh icosahedron; + CGAL::make_icosahedron(icosahedron, Point_3(0.0, 0.0, 0.0), 2.0); + PMP::triangulate_faces(faces(icosahedron), icosahedron); + + std::vector coords; + std::vector queries{ + Point_3(-1, 1 + PHI, PHI), Point_3(0.5, (1+3*PHI)/2, PHI/2), Point_3(1, 1+PHI, -PHI), //Boundary + Point_3(-1, 1, 1), Point_3(0, 0, 1), Point_3(0, 2, 1), //Interior + Point_3(0, 2*PHI, 4), Point_3(0, 3, 2*PHI), Point_3(4, 0, 0)}; //EXterior + + std::cout << std::endl << "Discrete harmonic coordinates : " << std::endl << std::endl; + + for (const auto& query : queries){ + + coords.clear(); + CGAL::Barycentric_coordinates::discrete_harmonic_coordinates_3( + icosahedron, query, std::back_inserter(coords), CP3::FAST_WITH_EDGE_CASES); + + // Output discrete harmonics coordinates. + for (std::size_t i = 0; i < coords.size() -1; ++i) { + std::cout << coords[i] << ", "; + } + std::cout << coords[coords.size() -1] << std::endl; + } + std::cout << std::endl; + + + return EXIT_SUCCESS; +} diff --git a/Barycentric_coordinates_3/examples/Barycentric_coordinates_3/mean_value_coordinates_3.cpp b/Barycentric_coordinates_3/examples/Barycentric_coordinates_3/mean_value_coordinates_3.cpp new file mode 100644 index 000000000000..c5117d4ea562 --- /dev/null +++ b/Barycentric_coordinates_3/examples/Barycentric_coordinates_3/mean_value_coordinates_3.cpp @@ -0,0 +1,54 @@ +#include +#include +#include + +#include + +using Kernel = CGAL::Exact_predicates_inexact_constructions_kernel; +using FT = Kernel::FT; +using Point_3 = Kernel::Point_3; +using Surface_mesh = CGAL::Surface_mesh; +namespace PMP = CGAL::Polygon_mesh_processing; +using CP3 = CGAL::Barycentric_coordinates::Computation_policy_3; + +int main(){ + + Surface_mesh concave; + + const Point_3 p0(0, 3, 0); + const Point_3 p1(1, 1, 0); + const Point_3 p2(3, 0, 0); + const Point_3 p3(0, 0, 0); + const Point_3 p4(0, 0, 3); + const Point_3 p5(0, 3, 3); + const Point_3 p6(1, 1, 3); + const Point_3 p7(3, 0, 3); + + CGAL::make_hexahedron(p0, p1, p2, p3, p4, p5, p6, p7, concave, + CGAL::parameters::do_not_triangulate_faces(false)); + + std::vector coords; + std::vector queries{ + Point_3(FT(1)/FT(2), FT(1)/FT(2), FT(1)), Point_3(FT(1)/FT(3), FT(1)/FT(3), FT(2)), // Only points in the kernel + Point_3(FT(4)/FT(3), FT(1)/FT(3), FT(1)), Point_3(FT(4)/FT(3), FT(1)/FT(3), FT(2)), + Point_3(FT(1)/FT(3), FT(4)/FT(3), FT(1)), Point_3(FT(1)/FT(3), FT(4)/FT(3), FT(2))}; + + std::cout << std::endl << "Mean value coordinates : " << std::endl << std::endl; + + for (const auto& query : queries){ + + coords.clear(); + CGAL::Barycentric_coordinates::mean_value_coordinates_3( + concave, query, std::back_inserter(coords), CP3::FAST); + + // Output mean value coordinates. + for (std::size_t i = 0; i < coords.size() -1; ++i) { + std::cout << coords[i] << ", "; + } + std::cout << coords[coords.size() -1] << std::endl; + } + std::cout << std::endl; + + + return EXIT_SUCCESS; +} diff --git a/Barycentric_coordinates_3/examples/Barycentric_coordinates_3/shape_deformation_3.cpp b/Barycentric_coordinates_3/examples/Barycentric_coordinates_3/shape_deformation_3.cpp new file mode 100644 index 000000000000..9d4f15db0055 --- /dev/null +++ b/Barycentric_coordinates_3/examples/Barycentric_coordinates_3/shape_deformation_3.cpp @@ -0,0 +1,78 @@ +#include + +#include +#include +#include + +#include +#include + +using Kernel = CGAL::Exact_predicates_inexact_constructions_kernel; + +using Point_3 = Kernel::Point_3; +using FT = Kernel::FT; + +using Surface_mesh = CGAL::Surface_mesh; +namespace PMP = CGAL::Polygon_mesh_processing; + +int main(int argc, char** argv) { + + const std::string filename = (argc > 1) ? argv[1] : CGAL::data_file_path("meshes/sphere.off"); + Surface_mesh sm; + + if(!CGAL::IO::read_polygon_mesh(filename, sm)) + { + std::cerr << "Invalid input: " << filename << std::endl; + return 1; + } + + Surface_mesh deformed; + deformed = sm; + + Surface_mesh quad_cage; + + const Point_3 p0(2, -2, -2), p0_new(5, -5, -5); + const Point_3 p1(2, 2, -2), p1_new(3, 3, -3); + const Point_3 p2(-2, 2, -2), p2_new(-2, 2, -2); + const Point_3 p3(-2, -2, -2), p3_new(-3, -3, -3); + + const Point_3 p4(-2, -2, 2), p4_new(-3, -3, 3); + const Point_3 p5(2, -2, 2), p5_new(4, -4, 4); + const Point_3 p6(2, 2, 2), p6_new(2, 2, 3); + const Point_3 p7(-2, 2, 2), p7_new(-3, 3, 3); + + CGAL::make_hexahedron(p0, p1, p2, p3, p4, p5, p6, p7, quad_cage, + CGAL::parameters::do_not_triangulate_faces(false)); + + CGAL::Barycentric_coordinates::Mean_value_coordinates_3 mv(quad_cage); + auto vertex_to_point_map = get_property_map(CGAL::vertex_point, deformed); + + std::vector coords; + std::vector target_cube{p0_new, p1_new, p2_new, p3_new, + p4_new, p5_new, p6_new, p7_new}; + + for(Surface_mesh::Vertex_index v : vertices(deformed)){ + + const Point_3 vertex_val = get(vertex_to_point_map, v); + coords.clear(); + mv(vertex_val, std::back_inserter(coords)); + + FT x = FT(0), y = FT(0), z = FT(0); + for(std::size_t i = 0; i < 8; i++){ + + x += target_cube[i].x() * coords[i]; + y += target_cube[i].y() * coords[i]; + z += target_cube[i].z() * coords[i]; + } + + put(vertex_to_point_map, v, Point_3(x, y, z)); + } + + std::ofstream out_original("sphere.off"); + out_original << sm << std::endl; + + std::ofstream out_deformed("deformed_sphere.off"); + out_deformed << deformed << std::endl; + + return EXIT_SUCCESS; +} diff --git a/Barycentric_coordinates_3/examples/Barycentric_coordinates_3/tetrahedron_coordinates.cpp b/Barycentric_coordinates_3/examples/Barycentric_coordinates_3/tetrahedron_coordinates.cpp new file mode 100644 index 000000000000..813ea56fb000 --- /dev/null +++ b/Barycentric_coordinates_3/examples/Barycentric_coordinates_3/tetrahedron_coordinates.cpp @@ -0,0 +1,41 @@ +#include +#include + +//Typedefs +using Kernel = CGAL::Simple_cartesian; + +using FT = Kernel::FT; +using Point_3 = Kernel::Point_3; + +int main(){ + + // Construct tetrahedron + const Point_3 p0(0.0, 0.0, 0.0); + const Point_3 p1(1.0, 0.0, 0.0); + const Point_3 p2(0.0, 1.0, 0.0); + const Point_3 p3(0.0, 0.0, 1.0); + + // Instantiate some interior, boundary, and exterior query points for which we compute coordinates. + const std::vector queries = { + Point_3(0.25f , 0.25f, 0.25f), Point_3(0.3f, 0.2f, 0.3f), // interior query points + Point_3(0.1f, 0.1f, 0.1f), Point_3(0.2f, 0.5f, 0.3f), // interior query points + Point_3(0.0f , 0.0f, 0.5f), Point_3(0.4f, 0.4f, 0.0f), // boundary query points + Point_3(0.0f, 0.4f, 0.4f), Point_3(0.4f, 0.0f, 0.4f), // boundary query points + Point_3(0.5f, 0.5f, 0.5f), Point_3(2.0f, 0.0f, 0.0f), // exterior query points + Point_3(-1.0f, -1.0f, 1.0f), Point_3(0.5f, 0.5f, -2.0f)}; // exterior query point + + std::cout << std::endl << "tetrahedra coordinates (all queries): " << std::endl + << std::endl; + + // Get an array of triangle coordinates for all query points + for(std::size_t i = 0; i < queries.size(); i++){ + const auto coords_array = + CGAL::Barycentric_coordinates::tetrahedron_coordinates_in_array(p0, p1, p2, p3, queries[i]); + + std::cout << "tetrahedra coordinates (query " << i << "): " << + coords_array[0] << " " << coords_array[1] << " " << + coords_array[2] << " " << coords_array[3] << std::endl; + } + + return EXIT_SUCCESS; +} diff --git a/Barycentric_coordinates_3/examples/Barycentric_coordinates_3/wachspress_coordinates_3.cpp b/Barycentric_coordinates_3/examples/Barycentric_coordinates_3/wachspress_coordinates_3.cpp new file mode 100644 index 000000000000..7292a984263d --- /dev/null +++ b/Barycentric_coordinates_3/examples/Barycentric_coordinates_3/wachspress_coordinates_3.cpp @@ -0,0 +1,46 @@ +#include +#include +#include +#include +#include + +#include + +using Kernel = CGAL::Exact_predicates_inexact_constructions_kernel; +using FT = Kernel::FT; +using Point_3 = Kernel::Point_3; +using Surface_mesh = CGAL::Surface_mesh; +namespace PMP = CGAL::Polygon_mesh_processing; +using CP3 = CGAL::Barycentric_coordinates::Computation_policy_3; +using WP = CGAL::Barycentric_coordinates::Wachspress_coordinates_3; + +int main() +{ + + CGAL::Random_points_in_sphere_3 gen(1.0); + std::vector points; + + const std::size_t number_of_points = 250; + std::copy_n(gen, number_of_points, std::back_inserter(points)); + + Surface_mesh sm; + CGAL::convex_hull_3(points.begin(), points.end(), sm); + const std::size_t number_of_vertices = num_vertices(sm); + + WP wp(sm, CP3::FAST_WITH_EDGE_CASES); + + std::cout << "Computed Wachspress coordinates: " << std::endl << std::endl; + for(std::size_t i = 0; i < number_of_points; i++){ + + std::vector coordinates; + coordinates.reserve(number_of_vertices); + wp(points[i], std::back_inserter(coordinates)); + + std::cout << "Point " << i + 1 << ": " << std::endl; + for(std::size_t j = 0; j < number_of_vertices; j++) + std::cout << "Coordinate " << j + 1 << " = " << coordinates[j] << "; " << std::endl; + std::cout << std::endl; + } + + return EXIT_SUCCESS; +} diff --git a/Barycentric_coordinates_3/include/CGAL/Barycentric_coordinates_3.h b/Barycentric_coordinates_3/include/CGAL/Barycentric_coordinates_3.h new file mode 100644 index 000000000000..b414f5503d99 --- /dev/null +++ b/Barycentric_coordinates_3/include/CGAL/Barycentric_coordinates_3.h @@ -0,0 +1,32 @@ +// Copyright (c) 2021 GeometryFactory SARL (France). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org). +// +// $URL$ +// $Id$ +// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial +// +// +// Author(s) : Antonio Gomes, Dmitry Anisimov +// + +#ifndef CGAL_BARYCENTRIC_COORDINATES_3_H +#define CGAL_BARYCENTRIC_COORDINATES_3_H + +#include + +/** +* \ingroup PkgBarycentricCoordinates3Ref +* \file CGAL/Barycentric_coordinates_3.h +* A convenience header that includes all free functions and classes for +* 3D barycentric coordinates in closed form. +*/ + +#include +#include +#include +#include +#include + +#endif diff --git a/Barycentric_coordinates_3/include/CGAL/Barycentric_coordinates_3/Discrete_harmonic_coordinates_3.h b/Barycentric_coordinates_3/include/CGAL/Barycentric_coordinates_3/Discrete_harmonic_coordinates_3.h new file mode 100644 index 000000000000..c0c4907d450b --- /dev/null +++ b/Barycentric_coordinates_3/include/CGAL/Barycentric_coordinates_3/Discrete_harmonic_coordinates_3.h @@ -0,0 +1,416 @@ +// Copyright (c) 2021 GeometryFactory SARL (France). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org). +// +// $URL$ +// $Id$ +// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial +// +// +// Author(s) : Antonio Gomes, Dmitry Anisimov +// + +#ifndef CGAL_BARYCENTRIC_DISCRETE_HARMONIC_COORDINATES_3_H +#define CGAL_BARYCENTRIC_DISCRETE_HARMONIC_COORDINATES_3_H + +#include + +// Internal includes. +#include +#include + +namespace CGAL { +namespace Barycentric_coordinates { + + /*! + \ingroup PkgBarycentricCoordinates3RefAnalytic + + \brief 3D discrete harmonic coordinates. + + This class implements 3D discrete harmonic coordinates \cite cgal:bc:jlw-ggcccsp-07, which can be computed + at any point inside a convex polyhedron with triangular faces. + + Discrete harmonic coordinates are well-defined in the closure of a convex polyhedron + with triangular faces but they are not necessarily positive. The coordinates are + computed analytically. + + \tparam TriangleMesh + must be a model of the concept `FaceListGraph`. + + \tparam GeomTraits + a model of `BarycentricTraits_3` + + \tparam VertexToPointMap + a property map with boost::graph_traits::vertex_descriptor as + key type and Point_3 as value type. The default is `property_map_selector`. + */ + template< + typename TriangleMesh, + typename GeomTraits, + typename VertexToPointMap = typename property_map_selector::const_type> + class Discrete_harmonic_coordinates_3 { + + public: + + /// \name Types + /// @{ + + /// \cond SKIP_IN_MANUAL + using Triangle_mesh = TriangleMesh; + using Geom_Traits = GeomTraits; + using Vertex_to_point_map = VertexToPointMap; + + using Construct_vec_3 = typename GeomTraits::Construct_vector_3; + using Cross_3 = typename GeomTraits::Construct_cross_product_vector_3; + using Dot_3 = typename GeomTraits::Compute_scalar_product_3; + using Sqrt = typename internal::Get_sqrt::Sqrt; + /// \endcond + + /// Number type. + typedef typename GeomTraits::FT FT; + + /// Point type. + typedef typename GeomTraits::Point_3 Point_3; + + /// %Vector type. + typedef typename GeomTraits::Vector_3 Vector_3; + + /// @} + + /// \name Initialization + /// @{ + + /*! + \brief initializes all internal data structures. + + This class implements the behavior of discrete harmonic coordinates + for 3D query points. + + \param triangle_mesh + an instance of `TriangleMesh`, which must be a convex simplicial polyhedron + + \param policy + one of the `CGAL::Barycentric_coordinates::Computation_policy_3`; + the default is `Computation_policy_3::FAST_WITH_EDGE_CASES` + + \param traits + a traits class with geometric objects, predicates, and constructions; + the default initialization is provided + + \param vertex_to_point_map + an instance of `VertexToPointMap` that maps a vertex from `triangle_mesh` to `Point_3`; + the default initialization is provided + + \pre num_vertices(triangle_mesh) >= 4. + \pre triangle_mesh is strongly convex. + \pre triangle_mesh is simplicial. + */ + Discrete_harmonic_coordinates_3( + const TriangleMesh& triangle_mesh, + const Computation_policy_3 policy, + const VertexToPointMap vertex_to_point_map, + const GeomTraits traits = GeomTraits()) : + m_triangle_mesh(triangle_mesh), + m_computation_policy(policy), + m_vertex_to_point_map(vertex_to_point_map), + m_traits(traits), + m_construct_vector_3(m_traits.construct_vector_3_object()), + m_cross_3(m_traits.construct_cross_product_vector_3_object()), + m_dot_3(m_traits.compute_scalar_product_3_object()), + sqrt(internal::Get_sqrt::sqrt_object(m_traits)){ + + // Check if polyhedron is strongly convex + CGAL_assertion(is_strongly_convex_3(m_triangle_mesh, m_traits)); + m_weights.resize(vertices(m_triangle_mesh).size()); + } + + /// @} + + Discrete_harmonic_coordinates_3( + const TriangleMesh& triangle_mesh, + const Computation_policy_3 policy = + Computation_policy_3::FAST_WITH_EDGE_CASES, + const GeomTraits traits = GeomTraits()) : + Discrete_harmonic_coordinates_3( + triangle_mesh, + policy, + get_const_property_map(CGAL::vertex_point, triangle_mesh), + traits) { } + + /// \name Access + /// @{ + + + /*! + \brief computes 3D discrete harmonic coordinates. + + This function fills `c_begin` with 3D discrete harmonic coordinates computed + at the `query` point with respect to the vertices of the input polyhedron. + + The number of returned coordinates equals to the number of vertices. + + After the coordinates \f$b_i\f$ with \f$i = 1\dots n\f$ are computed, where + \f$n\f$ is the number of vertices, the query point \f$q\f$ can be obtained + as \f$q = \sum_{i = 1}^{n}b_ip_i\f$, where \f$p_i\f$ are the polyhedron vertices. + + \tparam OutIterator + a model of `OutputIterator` that accepts values of type `FT` + + \param query + a query point + + \param c_begin + the beginning of the destination range with the computed coordinates + + \return an output iterator to the element in the destination range, + one past the last coordinate stored + */ + template + OutIterator operator()(const Point_3& query, OutIterator c_begin) { + return compute(query, c_begin); + } + + /// @} + + private: + const TriangleMesh& m_triangle_mesh; + const Computation_policy_3 m_computation_policy; + const VertexToPointMap m_vertex_to_point_map; // use it to map vertex to Point_3 + const GeomTraits m_traits; + + const Construct_vec_3 m_construct_vector_3; + const Cross_3 m_cross_3; + const Dot_3 m_dot_3; + const Sqrt sqrt; + + std::vector m_weights; + + template + OutputIterator compute( + const Point_3& query, OutputIterator coordinates) { + + switch(m_computation_policy){ + + case Computation_policy_3::FAST:{ + return compute_coords(query, coordinates); + } + + case Computation_policy_3::FAST_WITH_EDGE_CASES:{ + // Calculate query position relative to the polyhedron + const auto edge_case = internal::locate_wrt_polyhedron( + m_vertex_to_point_map, m_triangle_mesh, query, coordinates, m_traits); + + if(edge_case == internal::Edge_case::BOUNDARY) { + return coordinates; + } + if(edge_case == internal::Edge_case::EXTERIOR_BOUNDARY){ + std::cerr << std::endl << + "WARNING: query does not belong to the polygon!" << std::endl; + return coordinates; + } + if(edge_case == internal::Edge_case::EXTERIOR) { + std::cerr << std::endl << + "WARNING: query does not belong to the polygon!" << std::endl; + } + + return compute_coords(query, coordinates); + } + + default:{ + internal::get_default(vertices(m_triangle_mesh).size(), coordinates); + return coordinates; + } + } + return coordinates; + } + + template + OutputIterator compute_coords( + const Point_3& query, OutputIterator coordinates){ + + // Compute weights. + const FT sum = compute_weights(query); + CGAL_assertion(sum != FT(0)); + + // The coordinates must be saved in the same order as vertices in the vertex range. + const auto vd = vertices(m_triangle_mesh); + CGAL_assertion(m_weights.size() == vd.size()); + + for (std::size_t vi = 0; vi < vd.size(); vi++) { + + CGAL_assertion(vi < m_weights.size()); + const FT coordinate = m_weights[vi]/sum; + *(coordinates++) = coordinate; + } + + return coordinates; + } + + FT compute_weights(const Point_3& query) { + + // Sum of weights to normalize them later. + FT sum = FT(0); + + // Vertex index. + std::size_t vi = 0; + const auto vd = vertices(m_triangle_mesh); + + for (const auto& vertex : vd) { + + // Call function to calculate wp coordinates + const FT weight = compute_dh_vertex_query(vertex, query); + + CGAL_assertion(vi < m_weights.size()); + m_weights[vi] = weight; + sum += weight; + ++vi; // update vi + } + + CGAL_assertion(sum != FT(0)); + return sum; + } + + // Compute wp coordinates for a given vertex v and a query q + template + FT compute_dh_vertex_query(const Vertex& vertex, const Point_3& query){ + + const Point_3 vertex_val = get(m_vertex_to_point_map, vertex); + + // Circulator of faces around the vertex + CGAL::Face_around_target_circulator + face_circulator(halfedge(vertex, m_triangle_mesh), m_triangle_mesh); + + CGAL::Face_around_target_circulator + face_done(face_circulator); + + // Compute weight w_v + FT weight = FT(0); + + // Iterate using the circulator + do{ + + //Vertices around face iterator + const auto hedge = halfedge(*face_circulator, m_triangle_mesh); + const auto vertices = vertices_around_face(hedge, m_triangle_mesh); + auto vertex_itr = vertices.begin(); + CGAL_precondition(vertices.size() == 3); + + int vertex_parity = 1; + std::vector points; + points.resize(2); + int point_count = 0; + + for(std::size_t i = 0; i < 3; i++){ + + if(*vertex_itr!=vertex){ + + points[point_count] = get(m_vertex_to_point_map, *vertex_itr); + point_count++; + } + else + vertex_parity *= (i & 1)? -1 : 1; + + vertex_itr++; + } + + const Point_3& point2 = points[0]; + const Point_3& point1 = points[1]; + + const Vector_3 opposite_edge = m_construct_vector_3(point2, point1); + const FT edge_length = sqrt(opposite_edge.squared_length()); + + const Vector_3 normal_query = vertex_parity * m_cross_3(m_construct_vector_3(query, point2), + m_construct_vector_3(query, point1)); + + const Vector_3 face_normal = internal::get_face_normal( + *face_circulator, m_vertex_to_point_map, m_triangle_mesh, m_traits); + + FT cot_dihedral = internal::cot_dihedral_angle( + face_normal, normal_query, m_traits); + + const Vector_3 vertex_query = m_construct_vector_3(vertex_val, query); + + // Treat case when the point is outside + if(m_dot_3(face_normal, vertex_query) > 0) + cot_dihedral *= -1; + + weight += (cot_dihedral * edge_length) / 2; + face_circulator++; + + }while(face_circulator!=face_done); + + return weight; + } + + }; + + /*! + \ingroup PkgBarycentricCoordinates3RefFunctions + + \brief computes 3D discrete harmonic coordinates. + + This function computes 3D discrete harmonic coordinates at a given `query` point + with respect to the vertices of a convex `polyhedron` with triangular faces, that is one + coordinate per vertex. The coordinates are stored in a destination range + beginning at `c_begin`. + + Internally, the class `Discrete_harmonic_coordinates_3` is used. If one wants to process + multiple query points, it is better to use that class. When using the free function, + internal memory is allocated for each query point, while when using the class, + it is allocated only once, which is much more efficient. However, for a few query + points, it is easier to use this function. It can also be used when the processing + time is not a concern. + + \tparam Point_3 + A model of `Kernel::Point_3`. + + \tparam TriangleMesh + must be a model of the concept `FaceListGraph`. + + \tparam OutIterator + a model of `OutputIterator` that accepts values of type `GeomTraits::FT` + + \param triangle_mesh + an instance of `TriangleMesh`, which must be a convex simplicial polyhedron + + \param query + a query point + + \param c_begin + the beginning of the destination range with the computed coordinates + + \param policy + one of the `CGAL::Barycentric_coordinates::Computation_policy_3`; + the default is `Computation_policy_3::FAST_WITH_EDGE_CASES` + + \return an output iterator to the element in the destination range, + one past the last coordinate stored + + \pre num_vertices(triangle_mesh) >= 4. + \pre triangle_mesh is strongly convex. + \pre triangle_mesh is simplicial. + */ + template< + typename Point_3, + typename TriangleMesh, + typename OutIterator> + OutIterator discrete_harmonic_coordinates_3( + const TriangleMesh& triangle_mesh, + const Point_3& query, + OutIterator c_begin, + const Computation_policy_3 policy = + Computation_policy_3::FAST) { + + using Geom_Traits = typename Kernel_traits::Kernel; + + Discrete_harmonic_coordinates_3 discrete_harmonic(triangle_mesh, policy); + return discrete_harmonic(query, c_begin); + } + +} // namespace Barycentric_coordinates +} // namespace CGAL + +#endif // CGAL_BARYCENTRIC_DISCRETE_HARMONIC_COORDINATES_3_H diff --git a/Barycentric_coordinates_3/include/CGAL/Barycentric_coordinates_3/Mean_value_coordinates_3.h b/Barycentric_coordinates_3/include/CGAL/Barycentric_coordinates_3/Mean_value_coordinates_3.h new file mode 100644 index 000000000000..d3beb1926d49 --- /dev/null +++ b/Barycentric_coordinates_3/include/CGAL/Barycentric_coordinates_3/Mean_value_coordinates_3.h @@ -0,0 +1,427 @@ +// Copyright (c) 2021 GeometryFactory SARL (France). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org). +// +// $URL$ +// $Id$ +// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial +// +// +// Author(s) : Antonio Gomes, Dmitry Anisimov +// + +#ifndef CGAL_BARYCENTRIC_MEAN_VALUE_COORDINATES_3_H +#define CGAL_BARYCENTRIC_MEAN_VALUE_COORDINATES_3_H + +#include + +// Internal includes. +#include +#include + +#include + +namespace CGAL { +namespace Barycentric_coordinates { + + /*! + \ingroup PkgBarycentricCoordinates3RefAnalytic + + \brief 3D mean value coordinates. + + This class implements 3D mean value coordinates ( \cite cgal:bc:f-wmvc-14, + \cite cgal:bc:jlw-ggcccsp-07 ), which can be computed at any point in the space. + + Mean value coordinates are well-defined everywhere in the space and are + non-negative in the kernel of a star-shaped polyhedron. The coordinates are + computed analytically. + + \tparam TriangleMesh + must be a model of the concept `FaceListGraph`. + + \tparam GeomTraits + a model of `BarycentricTraits_3` + + \tparam VertexToPointMap + a property map with boost::graph_traits::vertex_descriptor as + key type and Point_3 as value type. The default is `property_map_selector`. + */ + template< + typename TriangleMesh, + typename GeomTraits, + typename VertexToPointMap = typename property_map_selector::const_type> + class Mean_value_coordinates_3 { + + public: + + /// \name Types + /// @{ + + /// \cond SKIP_IN_MANUAL + using Triangle_mesh = TriangleMesh; + using Geom_Traits = GeomTraits; + using Vertex_to_point_map = VertexToPointMap; + + using Construct_vec_3 = typename GeomTraits::Construct_vector_3; + using Cross_3 = typename GeomTraits::Construct_cross_product_vector_3; + using Dot_3 = typename GeomTraits::Compute_scalar_product_3; + using Sqrt = typename internal::Get_sqrt::Sqrt; + using Approximate_angle_3 = typename GeomTraits::Compute_approximate_angle_3; + /// \endcond + + /// Number type. + typedef typename GeomTraits::FT FT; + + /// Point type. + typedef typename GeomTraits::Point_3 Point_3; + + /// %Vector type. + typedef typename GeomTraits::Vector_3 Vector_3; + + /// @} + + /// \name Initialization + /// @{ + + /*! + \brief initializes all internal data structures. + + This class implements the behavior of mean value coordinates + for 3D query points. + + \param triangle_mesh + an instance of `TriangleMesh`, which must be a simplicial polyhedron + + \param policy + one of the `CGAL::Barycentric_coordinates::Computation_policy_3`; + the default is `Computation_policy_3::FAST_WITH_EDGE_CASES` + + \param traits + a traits class with geometric objects, predicates, and constructions; + the default initialization is provided + + \param vertex_to_point_map + an instance of `VertexToPointMap` that maps a vertex from `triangle_mesh` to `Point_3`; + the default initialization is provided + + \pre num_vertices(triangle_mesh) >= 4. + \pre triangle_mesh is simplicial. + */ + Mean_value_coordinates_3( + const TriangleMesh& triangle_mesh, + const Computation_policy_3 policy, + const VertexToPointMap vertex_to_point_map, + const GeomTraits traits = GeomTraits()) : + m_triangle_mesh(triangle_mesh), + m_computation_policy(policy), + m_vertex_to_point_map(vertex_to_point_map), + m_traits(traits), + m_construct_vector_3(m_traits.construct_vector_3_object()), + m_cross_3(m_traits.construct_cross_product_vector_3_object()), + m_dot_3(m_traits.compute_scalar_product_3_object()), + sqrt(internal::Get_sqrt::sqrt_object(m_traits)), + m_approximate_angle_3(m_traits.compute_approximate_angle_3_object()) { + + m_weights.resize(vertices(m_triangle_mesh).size()); + query_vertex_vectors.resize(3); + unit_vectors.resize(3); + m_vectors.resize(3); + angles.resize(3); + } + + /// @} + + Mean_value_coordinates_3( + const TriangleMesh& triangle_mesh, + const Computation_policy_3 policy = + Computation_policy_3::FAST_WITH_EDGE_CASES, + const GeomTraits traits = GeomTraits()) : + Mean_value_coordinates_3( + triangle_mesh, + policy, + get_const_property_map(CGAL::vertex_point, triangle_mesh), + traits) { } + + /// \name Access + /// @{ + + /*! + \brief computes 3D mean value coordinates. + + This function fills `c_begin` with 3D mean value coordinates computed + at the `query` point with respect to the vertices of the input polyhedron. + + The number of returned coordinates equals to the number of vertices. + + After the coordinates \f$b_i\f$ with \f$i = 1\dots n\f$ are computed, where + \f$n\f$ is the number of vertices, the query point \f$q\f$ can be obtained + as \f$q = \sum_{i = 1}^{n}b_ip_i\f$, where \f$p_i\f$ are the polyhedron vertices. + + \tparam OutIterator + a model of `OutputIterator` that accepts values of type `FT` + + \param query + a query point + + \param c_begin + the beginning of the destination range with the computed coordinates + + \return an output iterator to the element in the destination range, + one past the last coordinate stored + */ + template + OutIterator operator()(const Point_3& query, OutIterator c_begin) { + return compute(query, c_begin); + } + + /// @} + + private: + const TriangleMesh& m_triangle_mesh; + const Computation_policy_3 m_computation_policy; + const VertexToPointMap m_vertex_to_point_map; // use it to map vertex to Point_3 + const GeomTraits m_traits; + + const Construct_vec_3 m_construct_vector_3; + const Cross_3 m_cross_3; + const Dot_3 m_dot_3; + const Sqrt sqrt; + const Approximate_angle_3 m_approximate_angle_3; + + // Store useful information + std::vector m_weights; + std::vector query_vertex_vectors; + std::vector unit_vectors; + std::vector m_vectors; + std::vector angles; + + template + OutputIterator compute( + const Point_3& query, OutputIterator coordinates) { + + switch(m_computation_policy){ + + case Computation_policy_3::FAST:{ + return compute_coords(query, coordinates); + } + + case Computation_policy_3::FAST_WITH_EDGE_CASES:{ + // Calculate query position relative to the polyhedron + const auto edge_case = internal::locate_wrt_polyhedron( + m_vertex_to_point_map, m_triangle_mesh, query, coordinates, m_traits); + + if(edge_case == internal::Edge_case::BOUNDARY) { + return coordinates; + } + if(edge_case == internal::Edge_case::EXTERIOR_BOUNDARY){ + std::cerr << std::endl << + "WARNING: query does not belong to the polygon!" << std::endl; + return coordinates; + } + if(edge_case == internal::Edge_case::EXTERIOR) { + std::cerr << std::endl << + "WARNING: query does not belong to the polygon!" << std::endl; + } + + return compute_coords(query, coordinates); + } + + default:{ + internal::get_default(vertices(m_triangle_mesh).size(), coordinates); + return coordinates; + } + } + return coordinates; + } + + template + OutputIterator compute_coords( + const Point_3& query, OutputIterator coordinates){ + + // Compute weights. + const FT sum = compute_weights(query); + CGAL_assertion(sum != FT(0)); + + // The coordinates must be saved in the same order as vertices in the vertex range. + const auto vd = vertices(m_triangle_mesh); + CGAL_assertion(m_weights.size() == vd.size()); + + for (std::size_t vi = 0; vi < vd.size(); vi++) { + + CGAL_assertion(vi < m_weights.size()); + const FT coordinate = m_weights[vi]/sum; + *(coordinates++) = coordinate; + } + + return coordinates; + } + + FT compute_weights(const Point_3& query) { + + // Sum of weights to normalize them later. + FT sum = FT(0); + + // Vertex index. + std::size_t vi = 0; + const auto vd = vertices(m_triangle_mesh); + + for (const auto& vertex : vd) { + + // Call function to calculate wp coordinates + const FT weight = compute_mv_vertex_query(vertex, query); + + CGAL_assertion(vi < m_weights.size()); + m_weights[vi] = weight; + sum += weight; + ++vi; // update vi + } + + CGAL_assertion(sum != FT(0)); + return sum; + } + + // Compute wp coordinates for a given vertex v and a query q + template + FT compute_mv_vertex_query(const Vertex& vertex, const Point_3& query){ + + // Map vertex descriptor to point_3 + const Point_3& vertex_val = get(m_vertex_to_point_map, vertex); + + // Circulator of faces around the vertex + CGAL::Face_around_target_circulator + face_circulator(halfedge(vertex, m_triangle_mesh), m_triangle_mesh); + + CGAL::Face_around_target_circulator + face_done(face_circulator); + + // Compute weight w_v + FT weight = FT(0); + + // Iterate using the circulator + do{ + + // Vertices around face iterator + const auto hedge = halfedge(*face_circulator, m_triangle_mesh); + const auto vertices = vertices_around_face(hedge, m_triangle_mesh); + auto vertex_itr = vertices.begin(); + CGAL_precondition(vertices.size() == 3); + + // Weight of vertex for this particular face + FT partial_weight = FT(0); + int vertex_idx = -1; + + for(std::size_t i = 0; i < 3; i++){ + + if(*vertex_itr == vertex) + vertex_idx = i; + + const Vector_3 p = m_construct_vector_3(query, get(m_vertex_to_point_map, *vertex_itr)); + query_vertex_vectors[i] = p; + vertex_itr++; + } + + // Current vertex should be present in face + assert(vertex_idx != -1); + + for(std::size_t i = 0; i < 3; i++){ + + assert(query_vertex_vectors[i].squared_length() > 0); + unit_vectors[i] = query_vertex_vectors[i]/sqrt(query_vertex_vectors[i].squared_length()); + + m_vectors[i] = m_cross_3(query_vertex_vectors[i], query_vertex_vectors[(i+1)%3]); + assert(m_vectors[i].squared_length() > 0); + m_vectors[i] /= sqrt(m_vectors[i].squared_length()); + + angles[i] = m_approximate_angle_3(query_vertex_vectors[i], query_vertex_vectors[(i+1)%3]); + } + + partial_weight += angles[0] * m_dot_3(m_vectors[0], m_vectors[(vertex_idx+1)%3]); + partial_weight += angles[1] * m_dot_3(m_vectors[1], m_vectors[(vertex_idx+1)%3]); + partial_weight += angles[2] * m_dot_3(m_vectors[2], m_vectors[(vertex_idx+1)%3]); + + const FT dot_unit_m = m_dot_3(unit_vectors[vertex_idx], m_vectors[(vertex_idx+1)%3]); + assert(dot_unit_m != 0); + partial_weight /= dot_unit_m; + + weight += partial_weight; + + face_circulator++; + + }while(face_circulator!=face_done); + + const FT vertex_query_squared_len = m_construct_vector_3(vertex_val, query).squared_length(); + assert(vertex_query_squared_len != 0); + + return weight/sqrt(vertex_query_squared_len); + } + }; + + /*! + \ingroup PkgBarycentricCoordinates3RefFunctions + + \brief computes 3D mean value coordinates. + + This function computes 3D mean value coordinates at a given `query` point + with respect to the vertices of a `polyhedron` with triangular faces, that is one + weight per vertex. The coordinates are stored in a destination range + beginning at `c_begin`. + + Internally, the class `Mean_value_coordinates_3` is used. If one wants to process + multiple query points, it is better to use that class. When using the free function, + internal memory is allocated for each query point, while when using the class, + it is allocated only once, which is much more efficient. However, for a few query + points, it is easier to use this function. It can also be used when the processing + time is not a concern. + + \tparam Point_3 + A model of `Kernel::Point_3`. + + \tparam TriangleMesh + must be a model of the concept `FaceListGraph`. + + \tparam OutIterator + a model of `OutputIterator` that accepts values of type `GeomTraits::FT` + + \param triangle_mesh + an instance of `TriangleMesh`, which must be a simplicial polyhedron + + \param query + a query point + + \param c_begin + the beginning of the destination range with the computed coordinates + + \param policy + one of the `CGAL::Barycentric_coordinates::Computation_policy_3`; + the default is `Computation_policy_3::FAST_WITH_EDGE_CASES` + + \return an output iterator to the element in the destination range, + one past the last coordinates stored + + \pre num_vertices(triangle_mesh) >= 4. + \pre triangle_mesh is simplicial. + */ + template< + typename Point_3, + typename TriangleMesh, + typename OutIterator> + OutIterator mean_value_coordinates_3( + const TriangleMesh& triangle_mesh, + const Point_3& query, + OutIterator c_begin, + const Computation_policy_3 policy = + Computation_policy_3::FAST_WITH_EDGE_CASES) { + + using Geom_Traits = typename Kernel_traits::Kernel; + + Mean_value_coordinates_3 mean_value(triangle_mesh, policy); + return mean_value(query, c_begin); + } + +} // namespace Barycentric_coordinates +} // namespace CGAL + +#endif // CGAL_BARYCENTRIC_MEAN_VALUE_COORDINATES_3_H diff --git a/Barycentric_coordinates_3/include/CGAL/Barycentric_coordinates_3/Wachspress_coordinates_3.h b/Barycentric_coordinates_3/include/CGAL/Barycentric_coordinates_3/Wachspress_coordinates_3.h new file mode 100644 index 000000000000..51adcd143ae5 --- /dev/null +++ b/Barycentric_coordinates_3/include/CGAL/Barycentric_coordinates_3/Wachspress_coordinates_3.h @@ -0,0 +1,389 @@ +// Copyright (c) 2021 GeometryFactory SARL (France). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org). +// +// $URL$ +// $Id$ +// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial +// +// +// Author(s) : Antonio Gomes, Dmitry Anisimov +// + +#ifndef CGAL_BARYCENTRIC_WACHSPRESS_COORDINATES_3_H +#define CGAL_BARYCENTRIC_WACHSPRESS_COORDINATES_3_H + +#include + +// Internal includes. +#include +#include + +namespace CGAL { +namespace Barycentric_coordinates { + + + /*! + \ingroup PkgBarycentricCoordinates3RefAnalytic + + \brief 3D Wachspress coordinates. + + This class implements 3D Wachspress coordinates ( \cite cgal:bc:f-wmvc-14, + \cite cgal:bc:jlw-ggcccsp-07 ), which can be computed at any point inside a convex + polyhedron with triangular faces. + + Wachspress coordinates are well-defined and non-negative in the closure of a convex + polyhedron with triangular faces. The coordinates are computed analytically. + + \tparam PolygonMesh + must be a model of the concept `FaceListGraph`. + + \tparam GeomTraits + a model of `BarycentricTraits_3` + + \tparam VertexToPointMap + a property map with boost::graph_traits::vertex_descriptor as + key type and Point_3 as value type. The default is `property_map_selector`. + */ + template< + typename PolygonMesh, + typename GeomTraits, + typename VertexToPointMap = typename property_map_selector::const_type> + class Wachspress_coordinates_3 { + + public: + + /// \name Types + /// @{ + + /// \cond SKIP_IN_MANUAL + using Polygon_mesh = PolygonMesh; + using Geom_Traits = GeomTraits; + using Vertex_to_point_map = VertexToPointMap; + + using Dot_3 = typename GeomTraits::Compute_scalar_product_3; + using Det_3 = typename GeomTraits::Compute_determinant_3; + using Cross_3 = typename GeomTraits::Construct_cross_product_vector_3; + using Construct_vec_3 = typename GeomTraits::Construct_vector_3; + /// \endcond + + /// Number type. + typedef typename GeomTraits::FT FT; + + /// Point type. + typedef typename GeomTraits::Point_3 Point_3; + + /// %Vector type. + typedef typename GeomTraits::Vector_3 Vector_3; + + /// @} + + /// \name Initialization + /// @{ + + /*! + \brief initializes all internal data structures. + + This class implements the behavior of Wachspress coordinates + for 3D query points. + + \param polygon_mesh + an instance of `PolygonMesh`, which must be a convex simplicial polyhedron + + \param policy + one of the `CGAL::Barycentric_coordinates::Computation_policy_3`; + the default is `Computation_policy_3::FAST_WITH_EDGE_CASES` + + \param traits + a traits class with geometric objects, predicates, and constructions; + the default initialization is provided + + \param vertex_to_point_map + an instance of `VertexToPointMap` that maps a vertex from `polygon_mesh` to `Point_3`; + the default initialization is provided + + \pre num_vertices(polygon_mesh) >= 4. + \pre polygon_mesh is strongly convex. + \pre polygon_mesh is simplicial. + */ + Wachspress_coordinates_3( + const PolygonMesh& polygon_mesh, + const Computation_policy_3 policy, + const VertexToPointMap vertex_to_point_map, + const GeomTraits traits = GeomTraits()) : + m_polygon_mesh(polygon_mesh), + m_computation_policy(policy), + m_vertex_to_point_map(vertex_to_point_map), + m_traits(traits), + m_dot_3(m_traits.compute_scalar_product_3_object()), + m_det_3(m_traits.compute_determinant_3_object()), + m_cross_3(m_traits.construct_cross_product_vector_3_object()), + m_construct_vector_3(m_traits.construct_vector_3_object()){ + + // Check if polyhedron is strongly convex + CGAL_assertion(is_strongly_convex_3(m_polygon_mesh, m_traits)); + m_weights.resize(vertices(m_polygon_mesh).size()); + } + + /// @} + + Wachspress_coordinates_3( + const PolygonMesh& polygon_mesh, + const Computation_policy_3 policy = + Computation_policy_3::FAST_WITH_EDGE_CASES, + const GeomTraits traits = GeomTraits()) : + Wachspress_coordinates_3( + polygon_mesh, + policy, + get_const_property_map(CGAL::vertex_point, polygon_mesh), + traits) { } + + /// \name Access + /// @{ + + /*! + \brief computes 3D Wachspress coordinates. + + This function fills `c_begin` with 3D Wachspress coordinates computed + at the `query` point with respect to the vertices of the input polyhedron. + + The number of returned coordinates equals to the number of vertices. + + After the coordinates \f$b_i\f$ with \f$i = 1\dots n\f$ are computed, where + \f$n\f$ is the number of vertices, the query point \f$q\f$ can be obtained + as \f$q = \sum_{i = 1}^{n}b_ip_i\f$, where \f$p_i\f$ are the polyhedron vertices. + + \tparam OutIterator + a model of `OutputIterator` that accepts values of type `FT` + + \param query + a query point + + \param c_begin + the beginning of the destination range with the computed coordinates + + \return an output iterator to the element in the destination range, + one past the last coordinate stored + */ + template + OutIterator operator()(const Point_3& query, OutIterator c_begin) { + return compute(query, c_begin); + } + + /// @} + + private: + const PolygonMesh& m_polygon_mesh; + const Computation_policy_3 m_computation_policy; + const VertexToPointMap m_vertex_to_point_map; // use it to map vertex to Point_3 + const GeomTraits m_traits; + + const Dot_3 m_dot_3; + const Det_3 m_det_3; + const Cross_3 m_cross_3; + const Construct_vec_3 m_construct_vector_3; + + std::vector m_weights; + + template + OutputIterator compute( + const Point_3& query, OutputIterator coordinates) { + + switch(m_computation_policy){ + + case Computation_policy_3::FAST:{ + return compute_coords(query, coordinates); + } + + case Computation_policy_3::FAST_WITH_EDGE_CASES:{ + // Calculate query position relative to the polyhedron + const auto edge_case = internal::locate_wrt_polyhedron( + m_vertex_to_point_map, m_polygon_mesh, query, coordinates, m_traits, true); + + if(edge_case == internal::Edge_case::BOUNDARY) { + return coordinates; + } + if(edge_case == internal::Edge_case::EXTERIOR_BOUNDARY){ + std::cerr << std::endl << + "WARNING: query does not belong to the polygon!" << std::endl; + return coordinates; + } + if(edge_case == internal::Edge_case::EXTERIOR) { + std::cerr << std::endl << + "WARNING: query does not belong to the polygon!" << std::endl; + } + + return compute_coords(query, coordinates); + } + + default:{ + internal::get_default(vertices(m_polygon_mesh).size(), coordinates); + return coordinates; + } + } + return coordinates; + } + + template + OutputIterator compute_coords( + const Point_3& query, OutputIterator coordinates){ + + // Compute weights. + const FT sum = compute_weights(query); + CGAL_assertion(sum != FT(0)); + + // The coordinates must be saved in the same order as vertices in the vertex range. + const auto vd = vertices(m_polygon_mesh); + CGAL_assertion(m_weights.size() == vd.size()); + + for (std::size_t vi = 0; vi < vd.size(); vi++) { + + CGAL_assertion(vi < m_weights.size()); + const FT coordinate = m_weights[vi]/sum; + *(coordinates++) = coordinate; + } + + return coordinates; + } + + FT compute_weights(const Point_3& query) { + // Sum of weights to normalize them later. + FT sum = FT(0); + + // Vertex index. + std::size_t vi = 0; + for (auto vertex : vertices(m_polygon_mesh)) { + + // Call function to calculate wp coordinates + const FT weight = compute_wp_vertex_query(vertex, query); + + CGAL_assertion(vi < m_weights.size()); + m_weights[vi] = weight; + sum += weight; + ++vi; // update vi + } + + CGAL_assertion(sum != FT(0)); + return sum; + } + + // Compute wp coordinates for a given vertex v and a query q + // cf. Wachspress and mean value coordinates by Michael S. Floater Pages 17~18 + template + FT compute_wp_vertex_query(const Vertex& vertex, const Point_3& query){ + + // Map vertex descriptor to point_3 + const Point_3& vertex_val = get(m_vertex_to_point_map, vertex); + // Vector connecting query point to vertex; + const Vector_3 query_vertex = m_construct_vector_3(query, vertex_val); + + // Loop on the faces the vertex + using halfedge_descriptor = typename boost::graph_traits::halfedge_descriptor; + halfedge_descriptor first_h = halfedge(vertex, m_polygon_mesh); + + auto compute_pf_i = [&](halfedge_descriptor h) + { + const Vector_3 nf = internal::get_face_normal( + face(h, m_polygon_mesh), m_vertex_to_point_map, m_polygon_mesh, m_traits); + const FT hfx = m_dot_3(query_vertex, nf); + CGAL_assertion(hfx != FT(0)); + return nf/hfx; + }; + + // First face. + const Vector_3 pf_1 = compute_pf_i(first_h); + halfedge_descriptor h_i=prev(opposite(first_h, m_polygon_mesh), m_polygon_mesh); + Vector_3 pf_i=compute_pf_i(h_i); + // Compute weight w_v + FT weight = FT(0); + + // Iterate using the circulator + do{ + halfedge_descriptor h_i_p_1=prev(opposite(h_i, m_polygon_mesh), m_polygon_mesh); + if (h_i_p_1==first_h) + break; + const Vector_3 pf_i_p_1=compute_pf_i(h_i_p_1); + + // Sum partial result to weight + weight += m_det_3(pf_1, pf_i, pf_i_p_1); + h_i=h_i_p_1; + pf_i = pf_i_p_1; + }while(true); + + CGAL_assertion(weight > 0); + + return weight; + } + + }; + + /*! + \ingroup PkgBarycentricCoordinates3RefFunctions + + \brief computes 3D Wachspress coordinates. + + This function computes 3D Wachspress coordinates at a given `query` point + with respect to the vertices of a convex `polyhedron` with triangular faces, that is one + coordinate per vertex. The coordinates are stored in a destination range + beginning at `c_begin`. + + Internally, the class `Wachspress_coordinates_3` is used. If one wants to process + multiple query points, it is better to use that class. When using the free function, + internal memory is allocated for each query point, while when using the class, + it is allocated only once, which is much more efficient. However, for a few query + points, it is easier to use this function. It can also be used when the processing + time is not a concern. + + \tparam Point_3 + A model of `Kernel::Point_3`. + + \tparam PolygonMesh + must be a model of the concept `FaceListGraph`. + + \tparam OutIterator + a model of `OutputIterator` that accepts values of type `GeomTraits::FT` + + \param polygon_mesh + an instance of `PolygonMesh`, which must be a convex simplicial polyhedron + + \param query + a query point + + \param c_begin + the beginning of the destination range with the computed coordinates + + \param policy + one of the `CGAL::Barycentric_coordinates::Computation_policy_3`; + the default is `Computation_policy_3::FAST_WITH_EDGE_CASES` + + \return an output iterator to the element in the destination range, + one past the last coordinate stored + + \pre num_vertices(polygon_mesh) >= 4. + \pre polygon_mesh is strongly convex. + \pre polygon_mesh is simplicial. + */ + template< + typename Point_3, + typename PolygonMesh, + typename OutIterator> + OutIterator wachspress_coordinates_3( + const PolygonMesh& polygon_mesh, + const Point_3& query, + OutIterator c_begin, + const Computation_policy_3 policy = + Computation_policy_3::FAST) { + + using Geom_Traits = typename Kernel_traits::Kernel; + + Wachspress_coordinates_3 wachspress(polygon_mesh, policy); + return wachspress(query, c_begin); + } + +} // namespace Barycentric_coordinates +} // namespace CGAL + +#endif // CGAL_BARYCENTRIC_WACHSPRESS_COORDINATES_3_H diff --git a/Barycentric_coordinates_3/include/CGAL/Barycentric_coordinates_3/barycentric_enum_3.h b/Barycentric_coordinates_3/include/CGAL/Barycentric_coordinates_3/barycentric_enum_3.h new file mode 100644 index 000000000000..52803d58e211 --- /dev/null +++ b/Barycentric_coordinates_3/include/CGAL/Barycentric_coordinates_3/barycentric_enum_3.h @@ -0,0 +1,59 @@ +// Copyright (c) 2021 GeometryFactory SARL (France). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org). +// +// $URL$ +// $Id$ +// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial +// +// +// Author(s) : Antonio Gomes, Dmitry Anisimov +// + +#ifndef CGAL_BARYCENTRIC_ENUM_3_H +#define CGAL_BARYCENTRIC_ENUM_3_H + +#include + +namespace CGAL { + +/*! + \ingroup PkgBarycentricCoordinates3Ref + + The namespace `Barycentric_coordinates` contains implementations of all + generalized barycentric coordinates: 2D, 3D, related enumerations, etc. +*/ +namespace Barycentric_coordinates { + +/// \name Computation Policies +/// @{ + +/*! + `Computation_policy_3` provides a way to choose an asymptotic time complexity + of the algorithm and its precision for computing 3D barycentric weights and coordinates. +*/ +enum class Computation_policy_3 { + + /*! + Computation has a linear time complexity with respect to the number of + polygon vertices, but may suffer imprecisions near the polygon boundary. + No extra checks are carried out. + */ + FAST = 0, + + /*! + Computation has a linear time complexity with respect to the number of + polygon vertices, but may suffer imprecisions near the polygon boundary. In + addition, we check a position of the query point with respect to the polygon + and use different computation strategies for different positions. + */ + FAST_WITH_EDGE_CASES = 1 +}; + +/// @} + +} // namespace Barycentric_coordinates +} // namespace CGAL + +#endif // CGAL_BARYCENTRIC_ENUM_3_H diff --git a/Barycentric_coordinates_3/include/CGAL/Barycentric_coordinates_3/boundary_coordinates_3.h b/Barycentric_coordinates_3/include/CGAL/Barycentric_coordinates_3/boundary_coordinates_3.h new file mode 100644 index 000000000000..e5e52acc6d89 --- /dev/null +++ b/Barycentric_coordinates_3/include/CGAL/Barycentric_coordinates_3/boundary_coordinates_3.h @@ -0,0 +1,184 @@ +// Copyright (c) 2021 GeometryFactory SARL (France). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org). +// +// $URL$ +// $Id$ +// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial +// +// +// Author(s) : Antonio Gomes, Dmitry Anisimov +// + +#ifndef CGAL_BARYCENTRIC_BOUNDARY_COORDINATES_3_H +#define CGAL_BARYCENTRIC_BOUNDARY_COORDINATES_3_H + +#include + +#include +#include + +namespace CGAL{ +namespace Barycentric_coordinates{ + + /*! + \ingroup PkgBarycentricCoordinates3RefFunctions + + \brief computes boundary barycentric coordinates. + + This function computes boundary barycentric coordinates at a given `query` point + with respect to the vertices of a simple `polyhedron`, that is one + coordinate per vertex. The coordinates are stored in a destination range + beginning at `c_begin`. + + If `query` is at the vertex, the corresponding coordinate is set to one, while + all other coordinates are zero. If `query` is on the face, the three corresponding + coordinates are triangle coordinates, while all other coordinates are set to zero. + If `query` is not on the boundary, all the coordinates are set to zero. + + \tparam TriangleMesh + must be a model of the concept `FaceListGraph`. + + \tparam GeomTraits + a model of `BarycentricTraits_3` + + \tparam OutIterator + a model of `OutputIterator` that accepts values of type `GeomTraits::FT` + + \tparam VertexToPointMap + a property map with boost::graph_traits::vertex_descriptor as + key type and Point_3 as value type. The default is `property_map_selector`. + + \param triangle_mesh + an instance of `TriangleMesh`, which must be a convex simplicial polyhedron + + \param query + a query point + + \param c_begin + the beginning of the destination range with the computed coordinates + + \param traits + a traits class with geometric objects, predicates, and constructions; + the default initialization is provided + + \param vertex_to_point_map + an instance of `VertexToPointMap` that maps a vertex from `triangle_mesh` to `Point_3`; + the default initialization is provided + + \return an output iterator to the element in the destination range, + one past the last coordinate stored + the flag indicating whether the + query point belongs to the polyhedron boundary + + \pre num_vertices(triangle_mesh) >= 4. + \pre triangle_mesh is simplicial. + */ + template< + typename TriangleMesh, + typename OutIterator, + typename GeomTraits, + typename VertexToPointMap> + std::pair boundary_coordinates_3( + const TriangleMesh& triangle_mesh, + const typename GeomTraits::Point_3& query, + OutIterator c_begin, + const GeomTraits& traits, + const VertexToPointMap vertex_to_point_map) { + + const auto edge_case = internal::locate_wrt_polyhedron( + vertex_to_point_map, triangle_mesh, query, c_begin, traits); + + if(edge_case == internal::Edge_case::BOUNDARY) + return {c_begin, true}; + else{ + internal::get_default(num_vertices(triangle_mesh), c_begin); + return {c_begin, false}; + } + } + + /*! + \ingroup PkgBarycentricCoordinates3RefFunctions + + \brief computes boundary barycentric coordinates. + + This function computes boundary barycentric coordinates at a given `query` point + with respect to the vertices of a simple `polyhedron`, that is one + coordinate per vertex. The coordinates are stored in a destination range + beginning at `c_begin`. + + If `query` is at the vertex, the corresponding coordinate is set to one, while + all other coordinates are zero. If `query` is on the face, the three corresponding + coordinates are triangle coordinates, while all other coordinates are set to zero. + If `query` is not on the boundary, all the coordinates are set to zero. + + \tparam TriangleMesh + must be a model of the concept `FaceListGraph`. + + \tparam Point_3 + a model of `Kernel::Point_3` + + \tparam OutIterator + a model of `OutputIterator` that accepts values of type `GeomTraits::FT` + + \tparam VertexToPointMap + a property map with boost::graph_traits::vertex_descriptor as + key type and Point_3 as value type. The default is `property_map_selector`. + + \param triangle_mesh + an instance of `TriangleMesh`, which must be a convex simplicial polyhedron + + \param query + a query point + + \param c_begin + the beginning of the destination range with the computed coordinates + + \param vertex_to_point_map + an instance of `VertexToPointMap` that maps a vertex from `triangle_mesh` to `Point_3`; + the default initialization is provided + + \return an output iterator to the element in the destination range, + one past the last coordinate stored + the flag indicating whether the + query point belongs to the polyhedron boundary + + \pre num_vertices(triangle_mesh) >= 4. + \pre triangle_mesh is simplicial. + */ + template< + typename TriangleMesh, + typename Point_3, + typename OutIterator, + typename VertexToPointMap = typename property_map_selector::const_type> + std::pair boundary_coordinates_3( + const TriangleMesh& triangle_mesh, + const Point_3& query, + OutIterator c_begin, + const VertexToPointMap vertex_to_point_map){ + + using GeomTraits = typename Kernel_traits::Kernel; + const GeomTraits traits; + + return boundary_coordinates_3(triangle_mesh, query, c_begin, traits, vertex_to_point_map); + } + + template< + typename TriangleMesh, + typename Point_3, + typename OutIterator> + std::pair boundary_coordinates_3( + const TriangleMesh& triangle_mesh, + const Point_3& query, + OutIterator c_begin){ + + return boundary_coordinates_3(triangle_mesh, query, c_begin, + get_const_property_map(CGAL::vertex_point, triangle_mesh)); + } + +} +} + +#endif diff --git a/Barycentric_coordinates_3/include/CGAL/Barycentric_coordinates_3/internal/utils_3.h b/Barycentric_coordinates_3/include/CGAL/Barycentric_coordinates_3/internal/utils_3.h new file mode 100644 index 000000000000..3fb88cdd3536 --- /dev/null +++ b/Barycentric_coordinates_3/include/CGAL/Barycentric_coordinates_3/internal/utils_3.h @@ -0,0 +1,326 @@ +// Copyright (c) 2021 GeometryFactory SARL (France). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org). +// +// $URL$ +// $Id$ +// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial +// +// +// Author(s) : Antonio Gomes, Dmitry Anisimov +// + +#ifndef CGAL_BARYCENTRIC_INTERNAL_UTILS_3_H +#define CGAL_BARYCENTRIC_INTERNAL_UTILS_3_H + +#include + +// STL includes +#include + +// Internal includes +#include +#include +#include +#include +#include +#include + +namespace CGAL{ +namespace Barycentric_coordinates{ +namespace internal{ + +enum class Edge_case { + + EXTERIOR = 0, // exterior part of the polyhedron + INTERIOR = 1, // interior part of the polyhedron + BOUNDARY = 2, // boundary part of the polyhedron + EXTERIOR_BOUNDARY = 3, // extension of the boundary +}; + + template + FT get_tolerance() { + return FT(1) / FT(10000000000); + } + +// Compute barycentric coordinates in the space. + template< + typename OutputIterator, + typename GeomTraits> + OutputIterator tetrahedron_coordinates_impl( + const typename GeomTraits::Point_3& p0, + const typename GeomTraits::Point_3& p1, + const typename GeomTraits::Point_3& p2, + const typename GeomTraits::Point_3& p3, + const typename GeomTraits::Point_3& query, + OutputIterator coordinates, + const GeomTraits& traits) { + + // Number type. + using FT = typename GeomTraits::FT; + + // Functions. + const auto volume_3 = traits.compute_volume_3_object(); + const FT total_volume = volume_3(p0, p1, p2, p3); + + CGAL_precondition(total_volume != FT(0)); + if (total_volume == FT(0)) { + get_default(4, coordinates); + return coordinates; + } + + // Compute some related sub-volumes. + const FT V1 = volume_3(p1, p3, p2, query); + const FT V2 = volume_3(p2, p3, p0, query); + const FT V3 = volume_3(p3, p1, p0, query); + + // Compute the inverted total volume of the tetrahedron. + CGAL_assertion(total_volume != FT(0)); + const FT inverted_total_volume = FT(1) / total_volume; + + // Compute coordinates. + const FT b0 = V1 * inverted_total_volume; + const FT b1 = V2 * inverted_total_volume; + const FT b2 = V3 * inverted_total_volume; + const FT b3 = FT(1) - b0 - b1 - b2; + + // Return coordinates. + *(coordinates++) = b0; + *(coordinates++) = b1; + *(coordinates++) = b2; + *(coordinates++) = b3; + + return coordinates; + } + + // Compute normal vector of the face (not normalized). + template< + typename Face, + typename VertexToPointMap, + typename TriangleMesh, + typename GeomTraits> + typename GeomTraits::Vector_3 get_face_normal( + const Face& face, + const VertexToPointMap& vertex_to_point_map, + const TriangleMesh& triangle_mesh, + const GeomTraits& traits){ + + using Point_3 = typename GeomTraits::Point_3; + using Vector_3 = typename GeomTraits::Vector_3; + const auto cross_3 = traits.construct_cross_product_vector_3_object(); + const auto dot_3 = traits.compute_scalar_product_3_object(); + + const auto hedge = halfedge(face, triangle_mesh); + const auto vertices = vertices_around_face(hedge, triangle_mesh); + CGAL_precondition(vertices.size() >= 3); + + auto vertex = vertices.begin(); + const Point_3& point1 = get(vertex_to_point_map, *vertex); ++vertex; + const Point_3& point2 = get(vertex_to_point_map, *vertex); ++vertex; + const Point_3& point3 = get(vertex_to_point_map, *vertex); + + const Vector_3 u = point2 - point1; + const Vector_3 v = point3 - point1; + Vector_3 face_normal = cross_3(u, v); + face_normal /= approximate_sqrt(dot_3(face_normal, face_normal)); + + return face_normal; + } + + //Compute cotangent of dihedral angle between two faces + template + typename GeomTraits::FT cot_dihedral_angle( + const typename GeomTraits::Vector_3& vec_1, + const typename GeomTraits::Vector_3& vec_2, + const GeomTraits& traits){ + + using FT = typename GeomTraits::FT; + const auto& dot_3 = traits.compute_scalar_product_3_object(); + const auto& cross_3 = traits.construct_cross_product_vector_3_object(); + const auto& sqrt(Get_sqrt::sqrt_object(traits)); + + assert(vec_1.squared_length() != FT(0)); + assert(vec_2.squared_length() != FT(0)); + + const FT approximate_dot_3 = dot_3(vec_1, vec_2); + + const FT approximate_cross_3_length = sqrt(cross_3(vec_1, vec_2).squared_length()); + + assert(approximate_cross_3_length != FT(0)); + + return approximate_dot_3/approximate_cross_3_length; + } + + template + inline bool are_vertices_distinct(VertexRange& vertices_face){ + + // Check if the vertices are distinct + for(auto itr1 = vertices_face.begin(); itr1 != vertices_face.end(); itr1++) + for(auto itr2 = std::next(itr1, 1); itr2 != vertices_face.end(); itr2++) + if(*itr1 == *itr2) return false; + + return true; + } + + template< + typename VertexRange, + typename VertexToPointMap, + typename TriangleMesh, + typename OutIterator, + typename GeomTraits> + OutIterator boundary_coordinates_3( + VertexRange& vertices_face, + const VertexToPointMap& vertex_to_point_map, + const TriangleMesh& triangle_mesh, + const typename GeomTraits::Point_3& query, + OutIterator coordinates, + const GeomTraits& traits, + bool use_wp_flag){ + + using FT = typename GeomTraits::FT; + using Plane_3 = typename GeomTraits::Plane_3; + using Point_2 = typename GeomTraits::Point_2; + + const FT tol = get_tolerance(); + const std::size_t num_sides_face = vertices_face.size(); + + // Check if the vertices are distinct + CGAL_assertion(are_vertices_distinct(vertices_face)); + + // Create plane + auto vertex_itr = vertices_face.begin(); + const auto v0 = *vertex_itr; vertex_itr++; + const auto v1 = *vertex_itr; vertex_itr++; + const auto v2 = *vertex_itr; + const Plane_3 face_plane(get(vertex_to_point_map, v0), + get(vertex_to_point_map, v1), get(vertex_to_point_map, v2)); + + // Store 2d vertices + std::vector polygon; + polygon.reserve(num_sides_face); + auto polygon_itr = std::back_inserter(polygon); + Point_2 query_2 = face_plane.to_2d(query); + for(auto v : vertices_face){ + + *polygon_itr = face_plane.to_2d(get(vertex_to_point_map, v)); + polygon_itr++; + } + + // Check convexity + CGAL_assertion(is_convex_2(polygon.begin(), polygon.end(), traits)); + + // Store 2d barycentric coordinates + std::vector bar_coords_2; + bar_coords_2.reserve(num_sides_face); + + // Use wp_2 or triangle coordinates + if(use_wp_flag){ + wachspress_coordinates_2(polygon, query_2, std::back_inserter(bar_coords_2)); + } + else{ + CGAL_assertion(polygon.size() == 3); + triangle_coordinates_2(polygon[0], polygon[1], polygon[2], query_2, std::back_inserter(bar_coords_2)); + } + + // Fill coordinates + CGAL_assertion(bar_coords_2.size() == num_sides_face); + for(auto vertex_polyhedron : vertices(triangle_mesh)){ + + bool found_vertex = false; + auto bar_coords_itr = bar_coords_2.begin(); + for(auto vertex_face : vertices_face){ + + if(vertex_polyhedron == vertex_face){ + + *coordinates = CGAL::abs(*bar_coords_itr) < tol? FT(0): *bar_coords_itr; + found_vertex = true; + break; + } + bar_coords_itr++; + } + + if(!found_vertex) + *coordinates = FT(0); + + coordinates++; + } + + return coordinates; + } + + // Determine if the query point is on the interior, exterior or boundary + template< + typename VertexToPointMap, + typename PolygonMesh, + typename OutIterator, + typename GeomTraits> + Edge_case locate_wrt_polyhedron( + const VertexToPointMap& vertex_to_point_map, + const PolygonMesh& polygon_mesh, + const typename GeomTraits::Point_3& query, + OutIterator coordinates, + const GeomTraits& traits, + const bool use_wp_flag = false){ + + using Vector_3 = typename GeomTraits::Vector_3; + using FT = typename GeomTraits::FT; + const auto& dot_3 = traits.compute_scalar_product_3_object(); + const auto& construct_vector_3 = traits.construct_vector_3_object(); + const auto& sqrt(Get_sqrt::sqrt_object(traits)); + + // Flags that indicates position of the query point + bool exterior_flag = false; + bool boundary_flag = false; + + const FT tol = get_tolerance(); + auto face_range = faces(polygon_mesh); + + for(auto face : face_range){ + + const auto hedge = halfedge(face, polygon_mesh); + const auto vertices_face = vertices_around_face(hedge, polygon_mesh); + CGAL_precondition(vertices_face.size() >= 3); + + auto vertex = vertices_face.begin(); + const auto vertex_val = get(vertex_to_point_map, *vertex); + + // Vector connecting query point to vertex; + const Vector_3 query_vertex = construct_vector_3(query, vertex_val); + + // Calculate normals of faces + Vector_3 face_normal_i = get_face_normal( + face, vertex_to_point_map, polygon_mesh, traits); + face_normal_i = face_normal_i / sqrt(face_normal_i.squared_length()); + + // Distance of query to face + const FT perp_dist_i = dot_3(query_vertex, face_normal_i); + + // Verify location of query point; + if(CGAL::abs(perp_dist_i) < tol){ + + if(!boundary_flag) + boundary_coordinates_3(vertices_face, vertex_to_point_map, polygon_mesh, + query, coordinates, traits, use_wp_flag); + boundary_flag = true; + } + else if(perp_dist_i < 0) + exterior_flag = true; + } + + // Choose location + if(boundary_flag && exterior_flag) + return Edge_case::EXTERIOR_BOUNDARY; + else if(boundary_flag) + return Edge_case::BOUNDARY; + else if(exterior_flag) + return Edge_case::EXTERIOR; + else + return Edge_case::INTERIOR; + } + +} +} +} + +#endif diff --git a/Barycentric_coordinates_3/include/CGAL/Barycentric_coordinates_3/tetrahedron_coordinates.h b/Barycentric_coordinates_3/include/CGAL/Barycentric_coordinates_3/tetrahedron_coordinates.h new file mode 100644 index 000000000000..4d4be8a297aa --- /dev/null +++ b/Barycentric_coordinates_3/include/CGAL/Barycentric_coordinates_3/tetrahedron_coordinates.h @@ -0,0 +1,181 @@ +// Copyright (c) 2021 GeometryFactory SARL (France). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org). +// +// $URL$ +// $Id$ +// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial +// +// +// Author(s) : Antonio Gomes, Dmitry Anisimov +// + +#ifndef CGAL_BARYCENTRIC_TRIANGLE_COORDINATES_3_H +#define CGAL_BARYCENTRIC_TRIANGLE_COORDINATES_3_H + +#include + +#include + +namespace CGAL{ +namespace Barycentric_coordinates{ + + /*! + \ingroup PkgBarycentricCoordinates3RefFunctions + + \brief computes tetrahedron coordinates. + + This function computes barycentric coordinates at a given `query` point + with respect to the points `p0`, `p1`, `p2`, and `p3`, which form a tetrahedron, that is one + coordinate per point. The coordinates are stored in a destination range + beginning at `c_begin`. + + After the coordinates \f$b_0\f$, \f$b_1\f$, \f$b_2\f$, and \f$b_2\f$ are computed, the query + point \f$q\f$ can be obtained as \f$q = b_0p_0 + b_1p_1 + b_2p_2 + b_3p_3\f$. + + \tparam OutIterator + a model of `OutputIterator` that accepts values of type `GeomTraits::FT` + + \tparam GeomTraits + a model of `BarycentricTraits_3` + + \param p0 + the first vertex of a tetrahedron + + \param p1 + the second vertex of a tetrahedron + + \param p2 + the third vertex of a tetrahedron + + \param p3 + the fourth vertex of a tetrahedron + + \param query + a query point + + \param c_begin + the beginning of the destination range with the computed coordinates + + \param traits + a traits class with geometric objects, predicates, and constructions; + this parameter can be omitted if the traits class can be deduced from the point type + + \return an output iterator to the element in the destination range, + one past the last coordinate stored + + \pre Compute_volume_3(p0, p1, p2, p3) != 0 + */ + template< + typename OutIterator, + typename GeomTraits> + OutIterator tetrahedron_coordinates( + const typename GeomTraits::Point_3& p0, + const typename GeomTraits::Point_3& p1, + const typename GeomTraits::Point_3& p2, + const typename GeomTraits::Point_3& p3, + const typename GeomTraits::Point_3& query, + OutIterator c_begin, + const GeomTraits& traits) { + + return internal::tetrahedron_coordinates_impl( + p0, p1, p2, p3, query, c_begin, traits); + } + + //return iterator(infer from point_3) + template< + typename Point_3, + typename OutIterator> + OutIterator tetrahedron_coordinates( + const Point_3& p0, + const Point_3& p1, + const Point_3& p2, + const Point_3& p3, + const Point_3& query, + OutIterator c_begin) { + + using GeomTraits = typename Kernel_traits::Kernel; + const GeomTraits traits; + return tetrahedron_coordinates( + p0, p1, p2, p3, query, c_begin, traits); + } + + /*! + \ingroup PkgBarycentricCoordinates3RefFunctions + + \brief computes tetrahedron coordinates. + + This function computes barycentric coordinates at a given `query` point + with respect to the points `p0`, `p1`, `p2`, and `p3`, which form a tetrahedron, that is one + coordinate per point. The coordinates are returned in a tuple. + + After the coordinates \f$b_0\f$, \f$b_1\f$, \f$b_2\f$, and \f$b_3\f$ are computed, the query + point \f$q\f$ can be obtained as \f$q = b_0p_0 + b_1p_1 + b_2p_2 + b_3p_3\f$. + + \tparam GeomTraits + a model of `BarycentricTraits_3` + + \param p0 + the first vertex of a tetrahedron + + \param p1 + the second vertex of a tetrahedron + + \param p2 + the third vertex of a tetrahedron + + \param p3 + the fourth vertex of a tetrahedron + + \param query + a query point + + \param traits + a traits class with geometric objects, predicates, and constructions; + this parameter can be omitted if the traits class can be deduced from the point type + + \return a array `std::array` + with the computed coordinates + + \pre Compute_volume_3(p0, p1, p2, p3) != 0 + */ + template + std::array + tetrahedron_coordinates_in_array( + const typename GeomTraits::Point_3& p0, + const typename GeomTraits::Point_3& p1, + const typename GeomTraits::Point_3& p2, + const typename GeomTraits::Point_3& p3, + const typename GeomTraits::Point_3& query, + const GeomTraits& traits) { + + using FT = typename GeomTraits::FT; + std::vector coordinates; + coordinates.reserve(4); + internal::tetrahedron_coordinates_impl( + p0, p1, p2, p3, query, std::back_inserter(coordinates), traits); + CGAL_assertion(coordinates.size() == 4); + return {coordinates[0], coordinates[1], coordinates[2], coordinates[3]}; + } + + //return array (infer from point_3) + template + std::array::Kernel::FT, 4> + tetrahedron_coordinates_in_array( + const Point_3& p0, + const Point_3& p1, + const Point_3& p2, + const Point_3& p3, + const Point_3& query) { + + using GeomTraits = typename Kernel_traits::Kernel; + const GeomTraits traits; + return tetrahedron_coordinates_in_array( + p0, p1, p2, p3, query, traits); + } + +} +} + +#endif diff --git a/Barycentric_coordinates_3/package_info/Barycentric_coordinates_3/copyright b/Barycentric_coordinates_3/package_info/Barycentric_coordinates_3/copyright new file mode 100644 index 000000000000..50ed011a7861 --- /dev/null +++ b/Barycentric_coordinates_3/package_info/Barycentric_coordinates_3/copyright @@ -0,0 +1 @@ +GeometryFactory SARL diff --git a/Barycentric_coordinates_3/package_info/Barycentric_coordinates_3/dependencies b/Barycentric_coordinates_3/package_info/Barycentric_coordinates_3/dependencies new file mode 100644 index 000000000000..527389f7e8a5 --- /dev/null +++ b/Barycentric_coordinates_3/package_info/Barycentric_coordinates_3/dependencies @@ -0,0 +1,9 @@ +Algebraic_foundations +Barycentric_coordinates_2 +Installation +Kernel_23 +Number_types +Polygon +Profiling_tools +STL_Extension +Stream_support diff --git a/Barycentric_coordinates_3/package_info/Barycentric_coordinates_3/description.txt b/Barycentric_coordinates_3/package_info/Barycentric_coordinates_3/description.txt new file mode 100644 index 000000000000..85d1e502d63c --- /dev/null +++ b/Barycentric_coordinates_3/package_info/Barycentric_coordinates_3/description.txt @@ -0,0 +1 @@ +3D Generalized Barycentric Coordinates for convex simplicial polytopes. diff --git a/Barycentric_coordinates_3/package_info/Barycentric_coordinates_3/license.txt b/Barycentric_coordinates_3/package_info/Barycentric_coordinates_3/license.txt new file mode 100644 index 000000000000..8bb8efcb72b0 --- /dev/null +++ b/Barycentric_coordinates_3/package_info/Barycentric_coordinates_3/license.txt @@ -0,0 +1 @@ +GPL (v3 or later) diff --git a/Barycentric_coordinates_3/package_info/Barycentric_coordinates_3/long_description.txt b/Barycentric_coordinates_3/package_info/Barycentric_coordinates_3/long_description.txt new file mode 100644 index 000000000000..a7b8fba2e727 --- /dev/null +++ b/Barycentric_coordinates_3/package_info/Barycentric_coordinates_3/long_description.txt @@ -0,0 +1,3 @@ +The package 3D Generalized Barycentric Coordinates offers an efficient and robust +implementation of three-dimensional closed-form generalized barycentric coordinates +defined for convex simplicial polytopes. diff --git a/Barycentric_coordinates_3/package_info/Barycentric_coordinates_3/maintainer b/Barycentric_coordinates_3/package_info/Barycentric_coordinates_3/maintainer new file mode 100644 index 000000000000..75ec31e4c681 --- /dev/null +++ b/Barycentric_coordinates_3/package_info/Barycentric_coordinates_3/maintainer @@ -0,0 +1,2 @@ +Dmitry Anisimov +Antonio Gomes diff --git a/Barycentric_coordinates_3/test/Barycentric_coordinates_3/CMakeLists.txt b/Barycentric_coordinates_3/test/Barycentric_coordinates_3/CMakeLists.txt new file mode 100644 index 000000000000..22759b826989 --- /dev/null +++ b/Barycentric_coordinates_3/test/Barycentric_coordinates_3/CMakeLists.txt @@ -0,0 +1,18 @@ +# Created by the script cgal_create_cmake_script. +# This is the CMake script for compiling a CGAL application. + +cmake_minimum_required(VERSION 3.1...3.23) +project(Barycentric_coordinates_3_Tests) + +find_package(CGAL REQUIRED) + +include(CGAL_CreateSingleSourceCGALProgram) + +create_single_source_cgal_program("test_tetrahedron_coordinates.cpp") +create_single_source_cgal_program("test_wp_dh_mv_tetrahedron.cpp") +create_single_source_cgal_program("test_wp_weights_3.cpp") +create_single_source_cgal_program("test_dh_weights_3.cpp") +create_single_source_cgal_program("test_mv_weights_3.cpp") +create_single_source_cgal_program("test_edge_cases.cpp") +create_single_source_cgal_program("test_containers.cpp") +create_single_source_cgal_program("test_boundary_coordinates.cpp") diff --git a/Barycentric_coordinates_3/test/Barycentric_coordinates_3/include/utils.h b/Barycentric_coordinates_3/test/Barycentric_coordinates_3/include/utils.h new file mode 100644 index 000000000000..9afe3cc90021 --- /dev/null +++ b/Barycentric_coordinates_3/test/Barycentric_coordinates_3/include/utils.h @@ -0,0 +1,160 @@ +#ifndef CGAL_BARYCENTRIC_TESTS_UTILS_H +#define CGAL_BARYCENTRIC_TESTS_UTILS_H + +// STL includes +#include +#include + +// CGAL includes +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +namespace tests{ + + template + FT get_tolerance() { + return FT(1) / FT(10000000000); + } + + template + std::pair> get_irregular_tetrahedron(){ + + using Point_3 = typename Kernel::Point_3; + + Mesh tetrahedron0; + std::vector coords = {Point_3(0.0, 0.0, 0.0), Point_3(1.0, 0.0, 0.0), + Point_3(0.0, 1.0, 0.0), Point_3(0.0, 0.0, 1.0)}; + + CGAL::make_tetrahedron(coords[0], coords[1], + coords[2], coords[3], tetrahedron0); + + return {tetrahedron0, coords}; + } + + template + std::pair> get_regular_tetrahedron( + typename Kernel::FT scale){ + + using Point_3 = typename Kernel::Point_3; + + Mesh tetrahedron0; + std::vector coords = {Point_3(scale, scale, scale), Point_3(-scale, scale, -scale), + Point_3(scale, -scale, -scale), Point_3(-scale, -scale, scale)}; + + CGAL::make_tetrahedron(coords[0], coords[1], + coords[2], coords[3], tetrahedron0); + + return {tetrahedron0, coords}; + } + + template + std::pair> get_hexahedron(){ + + using Point_3 = typename Kernel::Point_3; + + Mesh hexahedron0; + std::vector coords = {Point_3(1.0, 0.0, 0.0), Point_3(1.0, 1.0, 0.0), + Point_3(0.0, 1.0, 0.0), Point_3(0.0, 0.0, 0.0), + Point_3(0.0, 0.0, 1.0), Point_3(1.0, 0.0, 1.0), + Point_3(1.0, 1.0, 1.0), Point_3(0.0, 1.0, 1.0)}; + + CGAL::make_hexahedron(coords[0], coords[1], coords[2], coords[3], coords[4], coords[5], + coords[6], coords[7], hexahedron0); + + return {hexahedron0, coords}; + } + + template + void test_partition_of_unity(std::vector& coords){ + + using FT = typename Kernel::FT; + + FT tol = get_tolerance(); + + FT sum = FT(0); + for(auto& coord : coords) + sum += coord; + + assert(CGAL::abs(FT(1) - sum) < tol); + } + + template + void test_barycenter(std::vector& coords){ + + using FT = typename Kernel::FT; + + std::size_t num_coords = coords.size(); + assert(num_coords != 0); + + for(auto& coord : coords) + assert(coord == FT(1)/FT(num_coords)); + } + + template + void test_linear_precision( + std::vector& coords, + const std::vector& vertices, + const typename Kernel::Point_3& query){ + + using FT = typename Kernel::FT; + + FT tol = get_tolerance(); + + std::size_t num_coords = coords.size(); + FT x_linear_comb = FT(0); + FT y_linear_comb = FT(0); + FT z_linear_comb = FT(0); + + for(std::size_t i = 0; i < num_coords; i++){ + + x_linear_comb += vertices[i].x() * coords[i]; + y_linear_comb += vertices[i].y() * coords[i]; + z_linear_comb += vertices[i].z() * coords[i]; + } + + assert(CGAL::abs(x_linear_comb - query.x()) < tol && + CGAL::abs(y_linear_comb - query.y()) < tol && + CGAL::abs(z_linear_comb - query.z()) < tol); + } + + template + void test_positivity(std::vector& coords){ + + using FT = typename Kernel::FT; + + for(auto& coord : coords) + assert(coord >= FT(0) && coord <= FT(1)); + } + + template + OutIterator random_points_tetrahedron( + std::vector& coords, + OutIterator out, int n){ + + using Tetrahedron_3 = typename Kernel::Tetrahedron_3; + using Mesh = typename CGAL::Surface_mesh; + + CGAL_assertion(coords.size() == 4); + Tetrahedron_3 tetra_inside(coords[0], coords[1], coords[2], coords[3]); + Mesh tetra_surf; + CGAL::make_tetrahedron(coords[0], coords[1], + coords[2], coords[3], tetra_surf); + + CGAL::Random_points_in_tetrahedron_3 gen_in(tetra_inside); + CGAL::Random_points_in_triangle_mesh_3 gen_surf(tetra_surf); + out = std::copy_n(gen_in, n/2, out); + out = std::copy_n(gen_surf, n/2, out); + + return out; + } +} + +#endif diff --git a/Barycentric_coordinates_3/test/Barycentric_coordinates_3/test_boundary_coordinates.cpp b/Barycentric_coordinates_3/test/Barycentric_coordinates_3/test_boundary_coordinates.cpp new file mode 100644 index 000000000000..cba2074292cb --- /dev/null +++ b/Barycentric_coordinates_3/test/Barycentric_coordinates_3/test_boundary_coordinates.cpp @@ -0,0 +1,74 @@ +#include +#include +#include + +#include +#include + +#include "include/utils.h" + +// Typedefs. +using SCKER = CGAL::Simple_cartesian; +using EPICK = CGAL::Exact_predicates_inexact_constructions_kernel; +using EPECK = CGAL::Exact_predicates_exact_constructions_kernel; + +template +void test_overloads(){ + + using FT = typename Kernel::FT; + using Point_3 = typename Kernel::Point_3; + using Mesh = typename CGAL::Surface_mesh; + + // tetrahedron + Mesh tetrahedron; + std::vector vertices; + std::vector sample_points; + std::vector tetra_coords(4); + + // 500 interior points + 500 surface points + std::tie(tetrahedron, vertices) = tests::get_irregular_tetrahedron(); + tests::random_points_tetrahedron(vertices, std::back_inserter(sample_points), 1000); + + std::size_t num_samples = 0; + for(auto& point : sample_points){ + + const FT x = point.x(), y = point.y(), z = point.z(); + const Point_3 query(x, y, z); + CGAL::Barycentric_coordinates::boundary_coordinates_3(tetrahedron, query, tetra_coords.begin()); + + if(num_samples < 500){ + assert(tetra_coords[0] == FT(0) && + tetra_coords[1] == FT(0) && + tetra_coords[2] == FT(0) && + tetra_coords[3] == FT(0)); + } + else{ + assert(CGAL::abs(1-x-y-z - tetra_coords[0]) == FT(0) && + CGAL::abs(x - tetra_coords[1]) == FT(0) && + CGAL::abs(y - tetra_coords[2]) == FT(0) && + CGAL::abs(z - tetra_coords[3]) == FT(0)); + } + + num_samples++; + } +} + +int main(){ + + // Set cout precision + std::cout.precision(20); + + std::cout << "SCKER test :" << std::endl; + test_overloads(); + std::cout << "SCKER PASSED" << std::endl; + + std::cout << "EPICK test :" << std::endl; + test_overloads(); + std::cout << "EPICK PASSED" << std::endl; + + std::cout << "EPECK test :" << std::endl; + test_overloads(); + std::cout << "EPECK PASSED" << std::endl; + + return EXIT_SUCCESS; +} diff --git a/Barycentric_coordinates_3/test/Barycentric_coordinates_3/test_containers.cpp b/Barycentric_coordinates_3/test/Barycentric_coordinates_3/test_containers.cpp new file mode 100644 index 000000000000..1727abbb0f50 --- /dev/null +++ b/Barycentric_coordinates_3/test/Barycentric_coordinates_3/test_containers.cpp @@ -0,0 +1,95 @@ +#include +#include +#include + +#include +#include +#include +#include + +// Typedefs. +using SCKER = CGAL::Simple_cartesian; +using EPICK = CGAL::Exact_predicates_inexact_constructions_kernel; +using EPECK = CGAL::Exact_predicates_exact_constructions_kernel; + +template +void test_container(const Mesh& mesh, OuputContainer& coordinates) { + + namespace BC = CGAL::Barycentric_coordinates; + using FT = typename Kernel::FT; + using Point_3 = typename Kernel::Point_3; + + const FT h = FT(1) / FT(2); + const Point_3 centroid(h, h, h); + + coordinates.clear(); + BC::Wachspress_coordinates_3 wp(mesh); + wp(centroid, std::back_inserter(coordinates)); + assert(coordinates.front() >= FT(0)); + assert(coordinates.back() >= FT(0)); + + coordinates.clear(); + BC::Discrete_harmonic_coordinates_3 dh(mesh); + dh(centroid, std::back_inserter(coordinates)); + assert(coordinates.front() >= FT(0)); + assert(coordinates.back() >= FT(0)); + + coordinates.clear(); + BC::Mean_value_coordinates_3 mv(mesh); + mv(centroid, std::back_inserter(coordinates)); + assert(coordinates.front() >= FT(0)); + assert(coordinates.back() >= FT(0)); +} + +template +void test_containers() { + + using FT = typename Kernel::FT; + using Point_3 = typename Kernel::Point_3; + + using Polyhedron = CGAL::Polyhedron_3; + using Surface_mesh = CGAL::Surface_mesh; + + using LCoords = std::list; + using VCoords = std::vector; + + Polyhedron polyhedron; + Surface_mesh surface_mesh; + + const Point_3 p0(0, 0, 0); + const Point_3 p1(1, 0, 0); + const Point_3 p2(1, 1, 0); + const Point_3 p3(0, 1, 0); + + const Point_3 p4(0, 1, 1); + const Point_3 p5(0, 0, 1); + const Point_3 p6(1, 0, 1); + const Point_3 p7(1, 1, 1); + + CGAL::make_hexahedron(p0, p1, p2, p3, p4, p5, p6, p7, polyhedron, CGAL::parameters::do_not_triangulate_faces(false)); + CGAL::make_hexahedron(p0, p1, p2, p3, p4, p5, p6, p7, surface_mesh, CGAL::parameters::do_not_triangulate_faces(false)); + + LCoords lcoords; + VCoords vcoords; + + test_container(polyhedron, lcoords); + test_container(polyhedron, vcoords); + + test_container(surface_mesh, lcoords); + test_container(surface_mesh, vcoords); +} + +int main() { + + std::cout << "SCKER test :" << std::endl; + test_containers(); + std::cout << "SCKER PASSED" << std::endl; + + std::cout << "EPICK test :" << std::endl; + test_containers(); + std::cout << "EPICK PASSED" << std::endl; + + std::cout << "EPECK test :" << std::endl; + test_containers(); + std::cout << "EPECK PASSED" << std::endl; +} diff --git a/Barycentric_coordinates_3/test/Barycentric_coordinates_3/test_dh_weights_3.cpp b/Barycentric_coordinates_3/test/Barycentric_coordinates_3/test_dh_weights_3.cpp new file mode 100644 index 000000000000..d179aec776df --- /dev/null +++ b/Barycentric_coordinates_3/test/Barycentric_coordinates_3/test_dh_weights_3.cpp @@ -0,0 +1,78 @@ +#include +#include +#include + +#include +#include + +#include "include/utils.h" + +// Typedefs. +using SCKER = CGAL::Simple_cartesian; +using EPICK = CGAL::Exact_predicates_inexact_constructions_kernel; +using EPECK = CGAL::Exact_predicates_exact_constructions_kernel; + +template +void test_overloads() { + + using FT = typename Kernel::FT; + using Point_3 = typename Kernel::Point_3; + using Mesh = typename CGAL::Surface_mesh; + + // tetrahedron + Mesh tetrahedron; + std::vector tetrahedron_coords; + + std::tie(tetrahedron, tetrahedron_coords) = tests::get_irregular_tetrahedron(); + CGAL::Barycentric_coordinates::Discrete_harmonic_coordinates_3 dh_tetrahedron(tetrahedron); + + const FT step = FT(1) / FT(10); + const FT scale = FT(10); + const FT limit = step*scale; + + std::vector dh_coordinates_tetrahedron; + + //Check for barycenter + dh_tetrahedron(Point_3(FT(1)/FT(4), FT(1)/FT(4), FT(1)/FT(4)), + std::back_inserter(dh_coordinates_tetrahedron)); + tests::test_barycenter(dh_coordinates_tetrahedron); + + // Sample interior points + for(FT x = step; x < limit; x += step){ + for(FT y = step; y < limit; y += step){ + for(FT z = step; z < FT(1) - x - y - step; z+= step){ // Excludes points inside faces + + const Point_3 query(x, y, z); + dh_coordinates_tetrahedron.clear(); + dh_tetrahedron(query, std::back_inserter(dh_coordinates_tetrahedron)); + + tests::test_linear_precision(dh_coordinates_tetrahedron, tetrahedron_coords, query); + tests::test_partition_of_unity(dh_coordinates_tetrahedron); + + dh_coordinates_tetrahedron.clear(); + CGAL::Barycentric_coordinates::discrete_harmonic_coordinates_3( + tetrahedron, query, std::back_inserter(dh_coordinates_tetrahedron)); + } + } + } +} + +int main(){ + + // Set cout precision + std::cout.precision(20); + + std::cout << "SCKER test :" << std::endl; + test_overloads(); + std::cout << "SCKER PASSED" << std::endl; + + std::cout << "EPICK test :" << std::endl; + test_overloads(); + std::cout << "EPICK PASSED" << std::endl; + + std::cout << "EPECK test :" << std::endl; + test_overloads(); + std::cout << "EPECK PASSED" << std::endl; + + return EXIT_SUCCESS; +} diff --git a/Barycentric_coordinates_3/test/Barycentric_coordinates_3/test_edge_cases.cpp b/Barycentric_coordinates_3/test/Barycentric_coordinates_3/test_edge_cases.cpp new file mode 100644 index 000000000000..58077fbdd53a --- /dev/null +++ b/Barycentric_coordinates_3/test/Barycentric_coordinates_3/test_edge_cases.cpp @@ -0,0 +1,123 @@ +#include +#include +#include + +#include +#include + +#include "include/utils.h" + +// Typedefs. +using SCKER = CGAL::Simple_cartesian; +using EPICK = CGAL::Exact_predicates_inexact_constructions_kernel; +using EPECK = CGAL::Exact_predicates_exact_constructions_kernel; +using CP3 = CGAL::Barycentric_coordinates::Computation_policy_3; + +template +void test_coordinate() { + + using FT = typename Kernel::FT; + using Point_3 = typename Kernel::Point_3; + using Mesh = typename CGAL::Surface_mesh; + + // tetrahedron + Mesh tetrahedron; + std::vector tetrahedron_coords; + std::tie(tetrahedron, tetrahedron_coords) = tests::get_regular_tetrahedron(FT(1.0)); + + std::vector sample_points; + std::vector sampled_tetrahedron_coords; + const FT tol = tests::get_tolerance(); + int num_interior_samples = 0; + + for(auto& offset : {FT(0), tol, -tol}){ + + // Sample interior and boundary + std::tie(std::ignore, sampled_tetrahedron_coords) = + tests::get_regular_tetrahedron(FT(1.0) + offset); + + tests::random_points_tetrahedron(sampled_tetrahedron_coords, + std::back_inserter(sample_points), 100); + num_interior_samples += 100; + + // Add points close to vertices + if(offset != tol){ + + for(auto& v : sampled_tetrahedron_coords){ + + sample_points.push_back(v); + num_interior_samples++; + } + } + } + + // Exterior points + std::tie(std::ignore, sampled_tetrahedron_coords) = + tests::get_regular_tetrahedron(FT(2.0)); + + tests::random_points_tetrahedron(sampled_tetrahedron_coords, + std::back_inserter(sample_points), 100); + + // BC coordinates + BC bc_tetrahedron(tetrahedron, CP3::FAST_WITH_EDGE_CASES); + + std::vector bc_coordinates_tetrahedron; + int num_samples = 0; + + for(auto& point : sample_points){ + + const Point_3 query(point.x(), point.y(), point.z()); + bc_coordinates_tetrahedron.clear(); + bc_tetrahedron(query, std::back_inserter(bc_coordinates_tetrahedron)); + + tests::test_linear_precision(bc_coordinates_tetrahedron, tetrahedron_coords, query); + tests::test_partition_of_unity(bc_coordinates_tetrahedron); + + if(num_samples < num_interior_samples) + tests::test_positivity(bc_coordinates_tetrahedron); + + num_samples++; + } +} + +template +void test_overloads(){ + + using Point_3 = typename Kernel::Point_3; + using Mesh = typename CGAL::Surface_mesh; + using WP = CGAL::Barycentric_coordinates::Wachspress_coordinates_3; + using DH = CGAL::Barycentric_coordinates::Discrete_harmonic_coordinates_3; + using MV = CGAL::Barycentric_coordinates::Mean_value_coordinates_3; + + std::cout << "WP test: " << std::endl; + test_coordinate(); + std::cout << "WP passed" << std::endl; + + std::cout << "DH test: " << std::endl; + test_coordinate(); + std::cout << "DH passed" << std::endl; + + std::cout << "MV test: " << std::endl; + test_coordinate(); + std::cout << "MV passed" << std::endl; +} + +int main(){ + + // Set cout precision + std::cout.precision(20); + + std::cout << "SCKER test :" << std::endl; + test_overloads(); + std::cout << "SCKER PASSED" << std::endl; + + std::cout << "EPICK test :" << std::endl; + test_overloads(); + std::cout << "EPICK PASSED" << std::endl; + + std::cout << "EPECK test :" << std::endl; + test_overloads(); + std::cout << "EPECK PASSED" << std::endl; + + return EXIT_SUCCESS; +} diff --git a/Barycentric_coordinates_3/test/Barycentric_coordinates_3/test_mv_weights_3.cpp b/Barycentric_coordinates_3/test/Barycentric_coordinates_3/test_mv_weights_3.cpp new file mode 100644 index 000000000000..eac0646a8cbe --- /dev/null +++ b/Barycentric_coordinates_3/test/Barycentric_coordinates_3/test_mv_weights_3.cpp @@ -0,0 +1,80 @@ +#include +#include +#include + +#include +#include + +#include "include/utils.h" + +// Typedefs. +using SCKER = CGAL::Simple_cartesian; +using EPICK = CGAL::Exact_predicates_inexact_constructions_kernel; +using EPECK = CGAL::Exact_predicates_exact_constructions_kernel; + +template +void test_overloads() { + + using FT = typename Kernel::FT; + using Point_3 = typename Kernel::Point_3; + using Mesh = typename CGAL::Surface_mesh; + + // tetrahedron + Mesh tetrahedron; + std::vector tetrahedron_coords; + std::vector sample_points; + + std::tie(tetrahedron, tetrahedron_coords) = tests::get_irregular_tetrahedron(); + CGAL::Barycentric_coordinates::Mean_value_coordinates_3 mv_tetrahedron(tetrahedron); + tests::random_points_tetrahedron(tetrahedron_coords, std::back_inserter(sample_points), 1000); + + std::vector mv_coordinates_tetrahedron; + + //Check for barycenter + mv_tetrahedron(Point_3(FT(1)/FT(4), FT(1)/FT(4), FT(1)/FT(4)), + std::back_inserter(mv_coordinates_tetrahedron)); + tests::test_barycenter(mv_coordinates_tetrahedron); + + for(auto& point : sample_points){ + + FT x = point.x(); + FT y = point.y(); + FT z = point.z(); + + if(x + y + z == FT(1) || x == FT(0) || y == FT(0) || z == FT(0)) //avoid points inside faces + continue; + + const Point_3 query(x, y, z); + mv_coordinates_tetrahedron.clear(); + mv_tetrahedron(query, std::back_inserter(mv_coordinates_tetrahedron)); + + tests::test_linear_precision(mv_coordinates_tetrahedron, tetrahedron_coords, query); + tests::test_partition_of_unity(mv_coordinates_tetrahedron); + tests::test_positivity(mv_coordinates_tetrahedron); + + mv_coordinates_tetrahedron.clear(); + CGAL::Barycentric_coordinates::mean_value_coordinates_3( + tetrahedron, query, std::back_inserter(mv_coordinates_tetrahedron)); + } + +} + +int main(){ + + // Set cout precision + std::cout.precision(20); + + std::cout << "SCKER test :" << std::endl; + test_overloads(); + std::cout << "SCKER PASSED" << std::endl; + + std::cout << "EPICK test :" << std::endl; + test_overloads(); + std::cout << "EPICK PASSED" << std::endl; + + std::cout << "EPECK test :" << std::endl; + test_overloads(); + std::cout << "EPECK PASSED" << std::endl; + + return EXIT_SUCCESS; +} diff --git a/Barycentric_coordinates_3/test/Barycentric_coordinates_3/test_tetrahedron_coordinates.cpp b/Barycentric_coordinates_3/test/Barycentric_coordinates_3/test_tetrahedron_coordinates.cpp new file mode 100644 index 000000000000..20300f8c7afe --- /dev/null +++ b/Barycentric_coordinates_3/test/Barycentric_coordinates_3/test_tetrahedron_coordinates.cpp @@ -0,0 +1,82 @@ +#include +#include +#include + +#include +#include + +#include "include/utils.h" + +// Typedefs. +using SCKER = CGAL::Simple_cartesian; +using EPICK = CGAL::Exact_predicates_inexact_constructions_kernel; +using EPECK = CGAL::Exact_predicates_exact_constructions_kernel; + +template +void test_overloads(){ + + using FT = typename Kernel::FT; + using Point_3 = typename Kernel::Point_3; + using Mesh = typename CGAL::Surface_mesh; + + // tetrahedron + Mesh tetrahedron; + std::vector vertices; + std::vector sample_points; + std::vector tetra_coords(4); + + //Interior and surface points + std::tie(tetrahedron, vertices) = tests::get_irregular_tetrahedron(); + tests::random_points_tetrahedron(vertices, std::back_inserter(sample_points), 1000); + + //Add vertices + for(auto& v : vertices) + sample_points.push_back(v); + + //Exterior + interior points + std::vector ext_vertices = {Point_3(0.0, 0.0, 0.0), Point_3(5.0, 0.0, 0.0), + Point_3(0.0, 5.0, 0.0), Point_3(0.0, 0.0, 5.0)}; + tests::random_points_tetrahedron(ext_vertices, std::back_inserter(sample_points), 1000); + + for(auto& point : sample_points){ + + const FT x = point.x(), y = point.y(), z = point.z(); + const Point_3 query(x, y, z); + CGAL::Barycentric_coordinates::tetrahedron_coordinates(vertices[0], vertices[1], + vertices[2], vertices[3], query, tetra_coords.begin()); + + const std::array tetra_coords_array = + CGAL::Barycentric_coordinates::tetrahedron_coordinates_in_array(vertices[0], vertices[1], + vertices[2], vertices[3], query); + + assert(CGAL::abs(1-x-y-z - tetra_coords[0]) == FT(0) && + CGAL::abs(x - tetra_coords[1]) == FT(0) && + CGAL::abs(y - tetra_coords[2]) == FT(0) && + CGAL::abs(z - tetra_coords[3]) == FT(0)); + + assert(tetra_coords_array[0] == tetra_coords[0] && + tetra_coords_array[1] == tetra_coords[1] && + tetra_coords_array[2] == tetra_coords[2] && + tetra_coords_array[3] == tetra_coords[3]); + } +} + +int main(){ + + // Set cout precision + std::cout.precision(20); + + std::cout << "SCKER test :" << std::endl; + test_overloads(); + std::cout << "SCKER PASSED" << std::endl; + + std::cout << "EPICK test :" << std::endl; + test_overloads(); + std::cout << "EPICK PASSED" << std::endl; + + std::cout << "EPECK test :" << std::endl; + test_overloads(); + std::cout << "EPECK PASSED" << std::endl; + + return EXIT_SUCCESS; +} diff --git a/Barycentric_coordinates_3/test/Barycentric_coordinates_3/test_wp_dh_mv_tetrahedron.cpp b/Barycentric_coordinates_3/test/Barycentric_coordinates_3/test_wp_dh_mv_tetrahedron.cpp new file mode 100644 index 000000000000..6cac06ef5511 --- /dev/null +++ b/Barycentric_coordinates_3/test/Barycentric_coordinates_3/test_wp_dh_mv_tetrahedron.cpp @@ -0,0 +1,94 @@ +#include + +#include +#include +#include +#include +#include + +#include "include/utils.h" + +//Typedefs +using Kernel = CGAL::Simple_cartesian; + +using FT = typename Kernel::FT; +using Point_3 = typename Kernel::Point_3; +using Mesh = typename CGAL::Surface_mesh; + +using WPC3 = CGAL::Barycentric_coordinates::Wachspress_coordinates_3; +using MVC3 = CGAL::Barycentric_coordinates::Mean_value_coordinates_3; +using DHC3 = CGAL::Barycentric_coordinates::Discrete_harmonic_coordinates_3; + +template +void test_overload(){ + + // Regular tetrahedron + Mesh tetrahedron; + std::vector vertices; + std::tie(tetrahedron, vertices) = tests::get_irregular_tetrahedron(); + + COORD bar(tetrahedron); + + std::vector tetra_coordinates; + std::vector bar_coordinates; + + // Sample points + const FT step = FT(1) / FT(20); + const FT scale = FT(10); + const FT tol = tests::get_tolerance(); + + std::size_t count = 0; + const FT limit = scale * step; + + for(FT x = step; x < limit; x += step){ + for(FT y = step; y < limit; y += step){ + for(FT z = step; z < FT(1) - x - y - step; z+= step){ // Excludes points inside faces + + const Point_3 query = Point_3(x, y, z); + + bar_coordinates.clear(); + tetra_coordinates.clear(); + bar(query, std::back_inserter(bar_coordinates)); + CGAL::Barycentric_coordinates::tetrahedron_coordinates(vertices[0], vertices[1], + vertices[2], vertices[3], query, std::back_inserter(tetra_coordinates)); + + tests::test_positivity(bar_coordinates); + tests::test_positivity(tetra_coordinates); + + tests::test_partition_of_unity(bar_coordinates); + tests::test_partition_of_unity(tetra_coordinates); + + tests::test_linear_precision(bar_coordinates, vertices, query); + tests::test_linear_precision(tetra_coordinates, vertices, query); + + assert( + CGAL::abs(tetra_coordinates[count + 0] - bar_coordinates[count + 0]) < tol && + CGAL::abs(tetra_coordinates[count + 1] - bar_coordinates[count + 1]) < tol && + CGAL::abs(tetra_coordinates[count + 2] - bar_coordinates[count + 2]) < tol && + CGAL::abs(tetra_coordinates[count + 3] - bar_coordinates[count + 3]) < tol); + } + } + } + +} + +int main(){ + + // Set cout precision + std::cout.precision(20); + + std::cout << "Wachspress: " << std::endl; + test_overload(); + std::cout << "Wachspress_tetrahedron PASSED" << std::endl; + + std::cout << "Discrete Harmonic: " << std::endl; + test_overload(); + std::cout << "Discrete_harmonic_tetrahedron PASSED" << std::endl; + + std::cout << "Mean Value: " << std::endl; + test_overload(); + std::cout << "Mean_value_tetrahedron PASSED" << std::endl; + + std::cout << "test_wp_dh_mv_tetrahedron: PASSED" << std::endl; + return EXIT_SUCCESS; +} diff --git a/Barycentric_coordinates_3/test/Barycentric_coordinates_3/test_wp_weights_3.cpp b/Barycentric_coordinates_3/test/Barycentric_coordinates_3/test_wp_weights_3.cpp new file mode 100644 index 000000000000..aa00f8666e9a --- /dev/null +++ b/Barycentric_coordinates_3/test/Barycentric_coordinates_3/test_wp_weights_3.cpp @@ -0,0 +1,83 @@ +#include +#include +#include + +#include +#include +#include + +#include "include/utils.h" + +// Typedefs. +using SCKER = CGAL::Simple_cartesian; +using EPICK = CGAL::Exact_predicates_inexact_constructions_kernel; +using EPECK = CGAL::Exact_predicates_exact_constructions_kernel; +using CP3 = CGAL::Barycentric_coordinates::Computation_policy_3; + +template +void test_overloads() { + + using FT = typename Kernel::FT; + using Point_3 = typename Kernel::Point_3; + using Mesh = CGAL::Surface_mesh; + namespace PMP = CGAL::Polygon_mesh_processing; + + // Cube + Mesh cube; + std::vector cube_coords; + std::tie(cube, cube_coords) = tests::get_hexahedron(); + + CGAL::Barycentric_coordinates::Wachspress_coordinates_3 wp_cube(cube); + + const FT step = FT(1) / FT(10); + const FT scale = FT(10); + const FT limit = step*scale; + + std::vector wp_coordinates_cube; + + // Test cube + //Check for barycenter + wp_cube(Point_3(FT(1)/FT(2), FT(1)/FT(2), FT(1)/FT(2)), std::back_inserter(wp_coordinates_cube)); + tests::test_barycenter(wp_coordinates_cube); + + // Sample interior points + for(FT x = step; x < limit; x += step){ + for(FT y = step; y < limit; y += step){ + for(FT z = step; z < limit; z += step){ + + const Point_3 query(x, y, z); + wp_coordinates_cube.clear(); + wp_cube(query, std::back_inserter(wp_coordinates_cube)); + + tests::test_linear_precision(wp_coordinates_cube, cube_coords, query); + tests::test_partition_of_unity(wp_coordinates_cube); + tests::test_positivity(wp_coordinates_cube); + + wp_coordinates_cube.clear(); + CGAL::Barycentric_coordinates::wachspress_coordinates_3( + cube, query, std::back_inserter(wp_coordinates_cube)); + } + } + } + +} + +int main(){ + + // Set cout precision + std::cout.precision(20); + + std::cout << "SCKER test :" << std::endl; + test_overloads(); + std::cout << "SCKER PASSED" << std::endl; + + std::cout << "EPICK test :" << std::endl; + test_overloads(); + std::cout << "EPICK PASSED" << std::endl; + + std::cout << "EPECK test :" << std::endl; + test_overloads(); + std::cout << "EPECK PASSED" << std::endl; + + return EXIT_SUCCESS; +} diff --git a/Documentation/doc/Documentation/packages.txt b/Documentation/doc/Documentation/packages.txt index 9b1fa73107e4..30f92bba3abb 100644 --- a/Documentation/doc/Documentation/packages.txt +++ b/Documentation/doc/Documentation/packages.txt @@ -152,6 +152,7 @@ \package_listing{Interpolation} \package_listing{Barycentric_coordinates_2} +\package_listing{Barycentric_coordinates_3} \cgalPackageSection{PartSupportLibrary,Support Library} diff --git a/Documentation/doc/biblio/cgal_manual.bib b/Documentation/doc/biblio/cgal_manual.bib index 51dfb1090046..eacb0d699aaf 100644 --- a/Documentation/doc/biblio/cgal_manual.bib +++ b/Documentation/doc/biblio/cgal_manual.bib @@ -3321,6 +3321,16 @@ @techreport{cgal:hssz-gmcabonbc-97 year={1997} } +@article{cgal:bc:jlw-ggcccsp-07, + title={A general geometric construction of coordinates in a convex simplicial polytope}, + volume={24}, + DOI={10.1016/j.cagd.2006.12.001}, + number={3}, + journal={Computer Aided Geometric Design}, + author={Ju, Tao and Liepa, Peter and Warren, Joe}, + year={2007}, + pages={161–178} +} % ---------------------------------------------------------------------------- % END OF BIBFILE % ---------------------------------------------------------------------------- diff --git a/Installation/include/CGAL/license/Barycentric_coordinates_3.h b/Installation/include/CGAL/license/Barycentric_coordinates_3.h new file mode 100644 index 000000000000..dc5a648feedb --- /dev/null +++ b/Installation/include/CGAL/license/Barycentric_coordinates_3.h @@ -0,0 +1,54 @@ +// Copyright (c) 2016 GeometryFactory SARL (France). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org) +// +// $URL$ +// $Id$ +// SPDX-License-Identifier: LGPL-3.0-or-later OR LicenseRef-Commercial +// +// Author(s) : Andreas Fabri +// +// Warning: this file is generated, see include/CGAL/license/README.md + +#ifndef CGAL_LICENSE_BARYCENTRIC_COORDINATES_3_H +#define CGAL_LICENSE_BARYCENTRIC_COORDINATES_3_H + +#include +#include + +#ifdef CGAL_BARYCENTRIC_COORDINATES_3_COMMERCIAL_LICENSE + +# if CGAL_BARYCENTRIC_COORDINATES_3_COMMERCIAL_LICENSE < CGAL_RELEASE_DATE + +# if defined(CGAL_LICENSE_WARNING) + + CGAL_pragma_warning("Your commercial license for CGAL does not cover " + "this release of the 3D Generalized Barycentric Coordinates package.") +# endif + +# ifdef CGAL_LICENSE_ERROR +# error "Your commercial license for CGAL does not cover this release \ + of the 3D Generalized Barycentric Coordinates package. \ + You get this error, as you defined CGAL_LICENSE_ERROR." +# endif // CGAL_LICENSE_ERROR + +# endif // CGAL_BARYCENTRIC_COORDINATES_3_COMMERCIAL_LICENSE < CGAL_RELEASE_DATE + +#else // no CGAL_BARYCENTRIC_COORDINATES_3_COMMERCIAL_LICENSE + +# if defined(CGAL_LICENSE_WARNING) + CGAL_pragma_warning("\nThe macro CGAL_BARYCENTRIC_COORDINATES_3_COMMERCIAL_LICENSE is not defined." + "\nYou use the CGAL 3D Generalized Barycentric Coordinates package under " + "the terms of the GPLv3+.") +# endif // CGAL_LICENSE_WARNING + +# ifdef CGAL_LICENSE_ERROR +# error "The macro CGAL_BARYCENTRIC_COORDINATES_3_COMMERCIAL_LICENSE is not defined.\ + You use the CGAL 3D Generalized Barycentric Coordinates package under the terms of \ + the GPLv3+. You get this error, as you defined CGAL_LICENSE_ERROR." +# endif // CGAL_LICENSE_ERROR + +#endif // no CGAL_BARYCENTRIC_COORDINATES_3_COMMERCIAL_LICENSE + +#endif // CGAL_LICENSE_BARYCENTRIC_COORDINATES_3_H diff --git a/Installation/include/CGAL/license/gpl_package_list.txt b/Installation/include/CGAL/license/gpl_package_list.txt index 75ff9d5c9ed9..1bf86c8c2819 100644 --- a/Installation/include/CGAL/license/gpl_package_list.txt +++ b/Installation/include/CGAL/license/gpl_package_list.txt @@ -6,6 +6,7 @@ Alpha_wrap_3 3D Alpha Wrapping Apollonius_graph_2 2D Apollonius Graphs (Delaunay Graphs of Disks) Arrangement_on_surface_2 2D Arrangements Barycentric_coordinates_2 2D Generalized Barycentric Coordinates +Barycentric_coordinates_3 3D Generalized Barycentric Coordinates Boolean_set_operations_2 2D Regularized Boolean Set-Operations Bounding_volumes Bounding Volumes Box_intersection_d Intersecting Sequences of dD Iso-oriented Boxes