├── .clang-format
├── .gitignore
├── CMakeLists.txt
├── LICENSE
├── README.md
├── docs
├── Report.pdf
├── Slides.pdf
└── SoftwareDemo.mp4
├── experiment
├── BoundaryFree
│ ├── bunny_disk.obj
│ ├── cube.mark
│ └── cube.obj
├── ConeParameterization
│ ├── david.obj
│ ├── david1.mark
│ ├── david2.mark
│ ├── max.mark
│ └── max.obj
├── EuclideanOrbifold
│ ├── david.obj
│ ├── david_orbifold1.mark
│ ├── david_orbifold2.mark
│ └── david_orbifold3.mark
├── HyperbolicOrbifold
│ ├── bunny_sphere.mark
│ └── bunny_sphere.obj
├── Polygon
│ ├── bunny_disk.mark
│ ├── bunny_disk.obj
│ ├── half_sphere.mark
│ └── half_sphere.obj
├── Texture
│ ├── checker_1k.bmp
│ └── circles_1.bmp
└── bin
│ └── Viewer.exe
├── images
├── bunny_free_emb.png
├── bunny_free_texture.png
├── bunny_hyper.png
├── bunny_hyper_cover.png
├── bunny_hyper_emb.png
├── bunny_hyper_texture.png
├── bunny_polygon.png
├── bunny_polygon_emb.png
├── bunny_polygon_texture.png
├── cone.png
├── david_euc.png
├── david_euc_cover.png
├── david_euc_emb.png
├── david_euc_texture.png
├── david_global.png
├── david_global_emb.png
├── david_global_emb_hilbert.png
├── david_global_texture.png
├── euc_orbifold.png
├── four_euc_orbifolds.png
├── gui.png
├── halfedge.png
├── halfshpere_polygon.png
├── halfshpere_polygon_texture.png
├── halfsphere_polygon_emb.png
├── hyperbolic.png
├── locally.png
├── loop.png
├── max_global.png
├── max_global_emb.png
├── max_global_texture.png
├── parameterizations.png
├── q-fold.png
├── q-folds.png
├── spherical.png
└── torus.png
└── src
├── BoundaryFirstFlattening
├── BFF.cpp
├── BFF.h
├── BFFInitializer.cpp
└── BFFInitializer.h
├── CMakeLists.txt
├── Mesh
├── MeshDefinition.cpp
└── MeshDefinition.h
├── OrbifoldEmbedding
├── EuclideanOrbifoldSolver.cpp
├── EuclideanOrbifoldSolver.h
├── HyperbolicOrbifoldSolver.cpp
├── HyperbolicOrbifoldSolver.h
├── OrbifoldInitializer.cpp
└── OrbifoldInitializer.h
├── Utilities
├── Circle.cpp
├── Circle.h
├── Dijkstra.cpp
├── Dijkstra.h
├── EuclideanCoveringSpace.cpp
├── EuclideanCoveringSpace.h
├── EuclideanGeometry2D.cpp
├── EuclideanGeometry2D.h
├── HyperbolicCoveringSpace.cpp
├── HyperbolicCoveringSpace.h
├── HyperbolicGeometry.cpp
├── HyperbolicGeometry.h
├── LineCylinder.cpp
├── LineCylinder.h
├── MeshFormConverter.cpp
├── MeshFormConverter.h
├── MeshMarker.cpp
├── MeshMarker.h
├── MeshMerger.cpp
├── MeshMerger.h
├── MeshSlicer.cpp
├── MeshSlicer.h
├── PointSphere.cpp
├── PointSphere.h
├── StringParser.cpp
└── StringParser.h
└── Viewer
├── GUIViewer.cpp
├── GUIViewer.h
└── main.cpp
/.clang-format:
--------------------------------------------------------------------------------
1 | BasedOnStyle: LLVM
2 | IndentWidth: 4
3 | UseTab: Never
4 | AlwaysBreakTemplateDeclarations: true
5 | ColumnLimit: 160
6 | Language: Cpp
7 | Standard: Cpp11
8 | BinPackParameters: false
9 | BreakBeforeBraces: Allman
10 | ### you may add more rules to fit your own taste
11 | #PointerBindsToType: true
12 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | build
2 | install
3 | .DS_Store
4 |
--------------------------------------------------------------------------------
/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 3.0)
2 |
3 | project(Parameterization)
4 |
5 | set(CMAKE_CXX_STANDARD 14)
6 |
7 | if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
8 | set(CMAKE_INSTALL_PREFIX ${CMAKE_SOURCE_DIR}/install CACHE PATH "cmake install prefix" FORCE)
9 | endif(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
10 |
11 | if(MSVC)
12 | set(CMAKE_DEBUG_POSTFIX "d")
13 | else()
14 | set(CMAKE_DEBUG_POSTFIX "")
15 | endif()
16 |
17 | # if there are some customized FindXXX modules
18 | set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_LIST_DIR}/cmake" CACHE STRING "Modules for CMake" FORCE)
19 |
20 | ###################### user-selected option ####################
21 | option(WITH_OPENMP "Enable OpenMP support?" ON)
22 | if(WITH_OPENMP)
23 | find_package(OpenMP REQUIRED)
24 | if(OPENMP_FOUND)
25 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}")
26 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}")
27 | endif()
28 | add_definitions(-DWITH_OPENMP)
29 | endif()
30 |
31 | ####################### eigen ###################
32 |
33 | include(FetchContent)
34 | FetchContent_Declare(
35 | eigen
36 | URL https://gitlab.com/libeigen/eigen/-/archive/3.3.7/eigen-3.3.7.tar.bz2
37 | URL_MD5 b9e98a200d2455f06db9c661c5610496
38 | )
39 | FetchContent_GetProperties(eigen)
40 | FetchContent_Populate(eigen)
41 | include_directories(${eigen_SOURCE_DIR})
42 |
43 |
44 | ####################### lbfgs ###################
45 |
46 | FetchContent_Declare(
47 | lbfgs
48 | GIT_REPOSITORY https://github.com/yixuan/LBFGSpp.git
49 | GIT_TAG 7fea82aab31607fc51c2ffd751a21c031b9a1061
50 | )
51 | FetchContent_GetProperties(lbfgs)
52 | FetchContent_Populate(lbfgs)
53 | include_directories(${lbfgs_SOURCE_DIR}/include)
54 |
55 | ############### libigl #######################
56 |
57 | option(LIBIGL_WITH_OPENGL "Use OpenGL" ON)
58 | option(LIBIGL_WITH_GLFW "Use GLFW" ON)
59 | option(LIBIGL_WITH_IMGUI "Use ImGui" ON)
60 | option(LIBIGL_WITH_PNG "Use PNG" ON)
61 |
62 | include(FetchContent)
63 | FetchContent_Declare(
64 | libigl
65 | GIT_REPOSITORY https://github.com/libigl/libigl.git
66 | GIT_TAG 237ffa20b1e2fd92e0be7862e9246c3774e4fc14
67 | )
68 | FetchContent_MakeAvailable(libigl)
69 |
70 |
71 | ############## OpenMesh #################
72 |
73 | FetchContent_Declare(
74 | openmesh
75 | GIT_REPOSITORY https://gitlab.vci.rwth-aachen.de:9000/OpenMesh/OpenMesh.git
76 | GIT_TAG d50cad4640d6d3657c4d0188fbf27ff38e4bfdca
77 | )
78 | FetchContent_MakeAvailable(openmesh)
79 | include_directories(${openmesh_SOURCE_DIR}/src)
80 |
81 |
82 | # ####################### precompiled dependencies ####################
83 |
84 | # find_package(OpenMesh REQUIRED)
85 | # include_directories(${OpenMesh_INCLUDE_DIRS})
86 | ##################### import files ##################
87 | add_definitions(-D_USE_MATH_DEFINES)
88 | add_subdirectory(src)
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017 Xuan Li
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # [Project for CSE528 On Surface Parameterization](https://github.com/xuan-li/GraphicsProject)
2 |
3 | 
4 |
5 | ## Project Overview
6 |
7 | In this project, I explore two kinds of parameterization algorithms. The first kind is from the view of Tutte embedding called Orbifold Tutte embedding (OTE). The other kind is from the view of differential geometry called boundary first flattening (BFF).
8 |
9 | [Full report on this project.](https://github.com/xuan-li/GraphicsProject/blob/master/docs/Report.pdf)
10 |
11 | [Software Demo](https://github.com/xuan-li/GraphicsProject/blob/master/docs/SoftwareDemo.mp4)
12 |
13 |
14 | ## References
15 |
16 | - Aigerman, N. and Lipman, Y. (2015). Orbifold tutte embeddings. ACM Trans. Graph., 34(6):190:1–190:12.
17 |
18 | - Aigerman, N. and Lipman, Y. (2016). Hyperbolic orbifold tutte embeddings. ACM Trans. Graph., 35(6):217:1–217:14.
19 |
20 | - Sawhney, R. and Crane, K. (2017). Boundary first flattening. https://arxiv.org/abs/1704.06873.
21 |
22 |
37 |
38 | ## Compile and Run (Ubuntu)
39 | ```
40 | sudo apt-get install freeglut3-dev libxrandr-dev libxinerama-dev libxcursor-dev libxi-dev
41 | mkidir build
42 | cmake -DCMAKE_BUILD_TYPE=Release ..
43 | make -j12
44 | src/Viewer
45 | ```
46 |
47 |
48 | ## How To Use
49 |
50 | ### Folder structure
51 |
52 | Released .exe file is in experiment/bin/
53 |
54 | Test data are included in experiment/.
55 |
56 | There are seven folders in experiment/:
57 |
58 | - bin: released exe file
59 |
60 | - Texture: some textures to show texture mappings.
61 |
62 | - Euclidean Orbifold / Hyperbolic Orbifold: test data for OTE
63 |
64 | - BoundaryFree / Polygon / ConeParameterization: test data for BFF
65 |
66 |
67 | ### Viewer Options
68 |
69 | Show Option:
70 |
71 | - Original: show loaded model.
72 |
73 | - Sliced: show model after cut, which is a disk.
74 |
75 | - Embedding: show results of algorithms
76 |
77 | - Covering Space: show tiled plane for orbifolds. (Only enabled in orbifold embeddings).
78 |
79 | Show Slices and Cones: whether to show added cones and slices.
80 |
81 |
82 |
83 | ### Vertex Selection and Cutting System
84 |
85 | Both algorithm needs to cut mesh and set angle sum for some vertices.
86 |
87 | The loaded mesh is shown in "Original" mode. In this mode, you can select vertices while pressing down 'S'. Input cone angle sum in the unit of
. Select one vertex to add a cone and select two vertices to add a slice.
88 |
89 | Current marker can be saved and loaded. There's a .mark file associated with each model file.
90 |
91 |
92 | ### Orbifold Tutte Embedding
93 |
94 | Only sphere-type Euclidean orbifolds with three cones supported:
95 |
,
96 |
,
97 |
98 |
99 |
100 | Only sphere-type hyperbolic orbifolds with cone angles all
supported. The number of cones for this kind should be larger than 4.
101 |
102 | Needed .mark file is included for test.
103 |
104 | Use Covering Space flag to see tiled plane: part of Euclidean plane and part of Poincare disk.
105 |
106 |
107 | ### Boundary First Flattening
108 |
109 | Three settings: free boundary (Harmonic/Hilbert BFF with free B), polygonal boundary (Harmonic/Hilbert BFF with K), cone parameterization (Harmonic/Hilbert BFF with Cones).
110 |
111 | Needed .mark file is included for test.
112 |
113 |
114 | ### Texture Mapping
115 |
116 | After computation, load a texture. Choose "Show texture" flag. See it in "Sliced" mode.
117 |
118 | ## Build From Source
119 |
120 | All codes are included in Code/.
121 |
122 | Open .sln file in VS2017 and build. Only x64 mode supported. Needed libraries' path are set in relative mode, you needn't modify them.
123 |
124 | ## License
125 |
126 | MIT
127 |
--------------------------------------------------------------------------------
/docs/Report.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xuan-li/Surface-Parameterization-Algorithms/c92997447447791bd1db2900717ce91d12a2203a/docs/Report.pdf
--------------------------------------------------------------------------------
/docs/Slides.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xuan-li/Surface-Parameterization-Algorithms/c92997447447791bd1db2900717ce91d12a2203a/docs/Slides.pdf
--------------------------------------------------------------------------------
/docs/SoftwareDemo.mp4:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xuan-li/Surface-Parameterization-Algorithms/c92997447447791bd1db2900717ce91d12a2203a/docs/SoftwareDemo.mp4
--------------------------------------------------------------------------------
/experiment/BoundaryFree/cube.mark:
--------------------------------------------------------------------------------
1 | e 8
2 | e 9
3 | e 13
4 | e 73
5 | e 111
6 | e 118
7 | e 165
8 | e 180
9 | e 240
10 | e 300
11 | e 310
12 | e 324
13 | e 327
14 | e 353
15 | e 362
16 | e 417
17 | e 493
18 | e 506
19 | e 522
20 | e 618
21 | e 707
22 | e 713
23 | e 722
24 | e 804
25 | e 848
26 | e 1014
27 | e 1068
28 | e 1092
29 | e 1132
30 | e 1155
31 |
--------------------------------------------------------------------------------
/experiment/ConeParameterization/david1.mark:
--------------------------------------------------------------------------------
1 | v 14611 1.57079627
2 | v 25291 3.14159254
3 | v 25414 1.57079627
4 | e 376
5 | e 1634
6 | e 1783
7 | e 3022
8 | e 3047
9 | e 4207
10 | e 4867
11 | e 8189
12 | e 9639
13 | e 10226
14 | e 10887
15 | e 11394
16 | e 11437
17 | e 11635
18 | e 11807
19 | e 13065
20 | e 13245
21 | e 13361
22 | e 14614
23 | e 14803
24 | e 15676
25 | e 15966
26 | e 16084
27 | e 16153
28 | e 16751
29 | e 16763
30 | e 17245
31 | e 18242
32 | e 18435
33 | e 18628
34 | e 20016
35 | e 20659
36 | e 20696
37 | e 20900
38 | e 21356
39 | e 22564
40 | e 22750
41 | e 22814
42 | e 22883
43 | e 23856
44 | e 24119
45 | e 24161
46 | e 24997
47 | e 25768
48 | e 26882
49 | e 27027
50 | e 28091
51 | e 28096
52 | e 30437
53 | e 30698
54 | e 31046
55 | e 32507
56 | e 32774
57 | e 32778
58 | e 32972
59 | e 33803
60 | e 35571
61 | e 35679
62 | e 37517
63 | e 38413
64 | e 40037
65 | e 40847
66 | e 40925
67 | e 42352
68 | e 42871
69 | e 43090
70 | e 43453
71 | e 44612
72 | e 46187
73 | e 46953
74 | e 47738
75 | e 49971
76 | e 49983
77 | e 50605
78 | e 51792
79 | e 51812
80 | e 52083
81 | e 52106
82 | e 55430
83 | e 56413
84 | e 56459
85 | e 57181
86 | e 58835
87 | e 59172
88 | e 59973
89 | e 62198
90 | e 62930
91 | e 63510
92 | e 63870
93 | e 65540
94 | e 66303
95 | e 67137
96 | e 67140
97 | e 67239
98 | e 67612
99 | e 68447
100 |
--------------------------------------------------------------------------------
/experiment/ConeParameterization/david2.mark:
--------------------------------------------------------------------------------
1 | v 14611 3.14159254
2 | v 17336 3.14159254
3 | v 18396 3.14159254
4 | v 25414 3.14159254
5 | e 376
6 | e 1634
7 | e 1783
8 | e 3022
9 | e 3047
10 | e 4207
11 | e 4867
12 | e 8189
13 | e 9639
14 | e 10226
15 | e 10887
16 | e 11394
17 | e 11437
18 | e 11635
19 | e 11807
20 | e 13065
21 | e 13245
22 | e 13361
23 | e 14614
24 | e 14803
25 | e 15676
26 | e 15966
27 | e 16084
28 | e 16153
29 | e 16751
30 | e 16763
31 | e 17245
32 | e 18242
33 | e 18435
34 | e 18628
35 | e 20016
36 | e 20659
37 | e 20696
38 | e 20900
39 | e 21356
40 | e 22564
41 | e 22750
42 | e 22814
43 | e 22883
44 | e 23856
45 | e 24119
46 | e 24161
47 | e 24997
48 | e 25768
49 | e 26882
50 | e 27027
51 | e 28091
52 | e 28096
53 | e 30437
54 | e 30698
55 | e 31046
56 | e 32507
57 | e 32774
58 | e 32778
59 | e 32972
60 | e 33803
61 | e 35571
62 | e 35679
63 | e 37517
64 | e 38413
65 | e 40037
66 | e 40847
67 | e 40925
68 | e 42352
69 | e 42871
70 | e 43090
71 | e 43453
72 | e 44612
73 | e 46187
74 | e 46953
75 | e 47738
76 | e 49971
77 | e 49983
78 | e 50605
79 | e 51792
80 | e 51812
81 | e 52083
82 | e 52106
83 | e 55430
84 | e 56413
85 | e 56459
86 | e 57181
87 | e 58835
88 | e 59172
89 | e 59973
90 | e 62198
91 | e 62930
92 | e 63510
93 | e 63870
94 | e 65540
95 | e 66303
96 | e 67137
97 | e 67140
98 | e 67239
99 | e 67612
100 | e 68447
101 |
--------------------------------------------------------------------------------
/experiment/ConeParameterization/max.mark:
--------------------------------------------------------------------------------
1 | v 3374 4.71238881
2 | v 3693 4.71238881
3 | v 6274 4.71238881
4 | v 6308 4.71238881
5 | e 74
6 | e 102
7 | e 433
8 | e 520
9 | e 779
10 | e 935
11 | e 1273
12 | e 1425
13 | e 1514
14 | e 1907
15 | e 2138
16 | e 2227
17 | e 2275
18 | e 2326
19 | e 2637
20 | e 2969
21 | e 2977
22 | e 3423
23 | e 3468
24 | e 3481
25 | e 3851
26 | e 4486
27 | e 4560
28 | e 4582
29 | e 4662
30 | e 4884
31 | e 4957
32 | e 5470
33 | e 5737
34 | e 5824
35 | e 5995
36 | e 6169
37 | e 7066
38 | e 7230
39 | e 7532
40 | e 7801
41 | e 8022
42 | e 8372
43 | e 8420
44 | e 8776
45 | e 8859
46 | e 9443
47 | e 9582
48 | e 9865
49 | e 9868
50 | e 10332
51 | e 10701
52 | e 11051
53 | e 11267
54 | e 11565
55 | e 11811
56 | e 12455
57 | e 12580
58 | e 12627
59 | e 12774
60 | e 12996
61 | e 13163
62 | e 13313
63 | e 13852
64 | e 13880
65 | e 14151
66 | e 14310
67 | e 14427
68 | e 14549
69 | e 14984
70 | e 15002
71 | e 15121
72 | e 15392
73 | e 15829
74 | e 16066
75 | e 16335
76 | e 16416
77 | e 16465
78 | e 16688
79 | e 16953
80 | e 16985
81 | e 17274
82 | e 17586
83 | e 17670
84 | e 17688
85 | e 17985
86 | e 18490
87 | e 18526
88 | e 18545
89 | e 19002
90 | e 19026
91 | e 19254
92 | e 19259
93 | e 19461
94 | e 19768
95 | e 19911
96 | e 19929
97 | e 20053
98 | e 20120
99 | e 20634
100 | e 20970
101 | e 21067
102 | e 21118
103 | e 21646
104 | e 21670
105 | e 21719
106 | e 21960
107 | e 22369
108 | e 22666
109 | e 22733
110 | e 22783
111 | e 23053
112 | e 23289
113 | e 23309
114 | e 23325
115 | e 23538
116 | e 23912
117 | e 24092
118 | e 24104
119 | e 24275
120 | e 24427
121 | e 24592
122 | e 24606
123 | e 24778
124 | e 25004
125 | e 25068
126 | e 25091
127 | e 25646
128 | e 25655
129 | e 25726
130 | e 26344
131 |
--------------------------------------------------------------------------------
/experiment/EuclideanOrbifold/david_orbifold1.mark:
--------------------------------------------------------------------------------
1 | v 14611 1.57079627
2 | v 25291 3.14159254
3 | v 25414 1.57079627
4 | e 376
5 | e 1634
6 | e 1783
7 | e 3022
8 | e 3047
9 | e 4207
10 | e 4867
11 | e 8189
12 | e 9639
13 | e 10226
14 | e 10887
15 | e 11394
16 | e 11437
17 | e 11635
18 | e 11807
19 | e 13065
20 | e 13245
21 | e 13361
22 | e 14614
23 | e 14803
24 | e 15676
25 | e 15966
26 | e 16084
27 | e 16153
28 | e 16751
29 | e 16763
30 | e 17245
31 | e 18242
32 | e 18435
33 | e 18628
34 | e 20016
35 | e 20659
36 | e 20696
37 | e 20900
38 | e 21356
39 | e 22564
40 | e 22750
41 | e 22814
42 | e 22883
43 | e 23856
44 | e 24119
45 | e 24161
46 | e 24997
47 | e 25768
48 | e 26882
49 | e 27027
50 | e 28091
51 | e 28096
52 | e 30437
53 | e 30698
54 | e 31046
55 | e 32507
56 | e 32774
57 | e 32778
58 | e 32972
59 | e 33803
60 | e 35571
61 | e 35679
62 | e 37517
63 | e 38413
64 | e 40037
65 | e 40847
66 | e 40925
67 | e 42352
68 | e 42871
69 | e 43090
70 | e 43453
71 | e 44612
72 | e 46187
73 | e 46953
74 | e 47738
75 | e 49971
76 | e 49983
77 | e 50605
78 | e 51792
79 | e 51812
80 | e 52083
81 | e 52106
82 | e 55430
83 | e 56413
84 | e 56459
85 | e 57181
86 | e 58835
87 | e 59172
88 | e 59973
89 | e 62198
90 | e 62930
91 | e 63510
92 | e 63870
93 | e 65540
94 | e 66303
95 | e 67137
96 | e 67140
97 | e 67239
98 | e 67612
99 | e 68447
100 |
--------------------------------------------------------------------------------
/experiment/EuclideanOrbifold/david_orbifold2.mark:
--------------------------------------------------------------------------------
1 | v 14611 2.09439510
2 | v 25291 2.09439510
3 | v 25414 2.09439510
4 | e 376
5 | e 1634
6 | e 1783
7 | e 3022
8 | e 3047
9 | e 4207
10 | e 4867
11 | e 8189
12 | e 9639
13 | e 10226
14 | e 10887
15 | e 11394
16 | e 11437
17 | e 11635
18 | e 11807
19 | e 13065
20 | e 13245
21 | e 13361
22 | e 14614
23 | e 14803
24 | e 15676
25 | e 15966
26 | e 16084
27 | e 16153
28 | e 16751
29 | e 16763
30 | e 17245
31 | e 18242
32 | e 18435
33 | e 18628
34 | e 20016
35 | e 20659
36 | e 20696
37 | e 20900
38 | e 21356
39 | e 22564
40 | e 22750
41 | e 22814
42 | e 22883
43 | e 23856
44 | e 24119
45 | e 24161
46 | e 24997
47 | e 25768
48 | e 26882
49 | e 27027
50 | e 28091
51 | e 28096
52 | e 30437
53 | e 30698
54 | e 31046
55 | e 32507
56 | e 32774
57 | e 32778
58 | e 32972
59 | e 33803
60 | e 35571
61 | e 35679
62 | e 37517
63 | e 38413
64 | e 40037
65 | e 40847
66 | e 40925
67 | e 42352
68 | e 42871
69 | e 43090
70 | e 43453
71 | e 44612
72 | e 46187
73 | e 46953
74 | e 47738
75 | e 49971
76 | e 49983
77 | e 50605
78 | e 51792
79 | e 51812
80 | e 52083
81 | e 52106
82 | e 55430
83 | e 56413
84 | e 56459
85 | e 57181
86 | e 58835
87 | e 59172
88 | e 59973
89 | e 62198
90 | e 62930
91 | e 63510
92 | e 63870
93 | e 65540
94 | e 66303
95 | e 67137
96 | e 67140
97 | e 67239
98 | e 67612
99 | e 68447
100 |
--------------------------------------------------------------------------------
/experiment/EuclideanOrbifold/david_orbifold3.mark:
--------------------------------------------------------------------------------
1 | v 14611 1.04719755
2 | v 25291 2.09439510
3 | v 25414 3.14159254
4 | e 376
5 | e 1634
6 | e 1783
7 | e 3022
8 | e 3047
9 | e 4207
10 | e 4867
11 | e 8189
12 | e 9639
13 | e 10226
14 | e 10887
15 | e 11394
16 | e 11437
17 | e 11635
18 | e 11807
19 | e 13065
20 | e 13245
21 | e 13361
22 | e 14614
23 | e 14803
24 | e 15676
25 | e 15966
26 | e 16084
27 | e 16153
28 | e 16751
29 | e 16763
30 | e 17245
31 | e 18242
32 | e 18435
33 | e 18628
34 | e 20016
35 | e 20659
36 | e 20696
37 | e 20900
38 | e 21356
39 | e 22564
40 | e 22750
41 | e 22814
42 | e 22883
43 | e 23856
44 | e 24119
45 | e 24161
46 | e 24997
47 | e 25768
48 | e 26882
49 | e 27027
50 | e 28091
51 | e 28096
52 | e 30437
53 | e 30698
54 | e 31046
55 | e 32507
56 | e 32774
57 | e 32778
58 | e 32972
59 | e 33803
60 | e 35571
61 | e 35679
62 | e 37517
63 | e 38413
64 | e 40037
65 | e 40847
66 | e 40925
67 | e 42352
68 | e 42871
69 | e 43090
70 | e 43453
71 | e 44612
72 | e 46187
73 | e 46953
74 | e 47738
75 | e 49971
76 | e 49983
77 | e 50605
78 | e 51792
79 | e 51812
80 | e 52083
81 | e 52106
82 | e 55430
83 | e 56413
84 | e 56459
85 | e 57181
86 | e 58835
87 | e 59172
88 | e 59973
89 | e 62198
90 | e 62930
91 | e 63510
92 | e 63870
93 | e 65540
94 | e 66303
95 | e 67137
96 | e 67140
97 | e 67239
98 | e 67612
99 | e 68447
100 |
--------------------------------------------------------------------------------
/experiment/HyperbolicOrbifold/bunny_sphere.mark:
--------------------------------------------------------------------------------
1 | v 22 3.14159254
2 | v 3141 3.14159254
3 | v 5956 3.14159254
4 | v 6211 3.14159254
5 | v 6266 3.14159254
6 | v 7107 3.14159254
7 | v 8038 3.14159254
8 | e 1109
9 | e 1340
10 | e 1352
11 | e 1504
12 | e 1753
13 | e 1823
14 | e 1932
15 | e 2040
16 | e 2158
17 | e 2214
18 | e 2233
19 | e 2469
20 | e 2866
21 | e 2966
22 | e 3105
23 | e 3478
24 | e 3559
25 | e 3627
26 | e 3667
27 | e 4336
28 | e 4355
29 | e 4502
30 | e 4570
31 | e 4814
32 | e 5437
33 | e 5999
34 | e 6014
35 | e 6035
36 | e 6050
37 | e 6273
38 | e 6330
39 | e 6779
40 | e 7025
41 | e 7104
42 | e 7243
43 | e 7413
44 | e 7433
45 | e 7499
46 | e 7662
47 | e 7833
48 | e 7852
49 | e 8591
50 | e 8612
51 | e 8761
52 | e 9086
53 | e 9980
54 | e 10591
55 | e 10598
56 | e 10938
57 | e 11018
58 | e 11348
59 | e 11684
60 | e 11923
61 | e 12346
62 | e 13332
63 | e 13502
64 | e 13778
65 | e 14101
66 | e 14964
67 | e 15279
68 | e 15304
69 | e 16035
70 | e 16178
71 | e 17581
72 | e 17592
73 | e 17610
74 | e 17846
75 | e 17998
76 | e 18001
77 | e 18054
78 | e 18425
79 | e 18479
80 | e 18664
81 | e 18728
82 | e 19193
83 | e 19304
84 | e 19529
85 | e 19812
86 | e 19829
87 | e 20080
88 | e 20313
89 | e 20867
90 | e 20870
91 | e 21626
92 | e 21753
93 | e 21789
94 | e 21809
95 | e 22053
96 | e 23035
97 | e 23060
98 | e 23385
99 | e 23482
100 | e 23529
101 | e 23557
102 | e 23655
103 | e 23735
104 | e 23812
105 | e 23846
106 | e 24237
107 | e 24438
108 | e 24870
109 | e 25434
110 | e 25549
111 | e 25812
112 | e 25873
113 | e 25901
114 | e 25984
115 | e 26011
116 | e 26151
117 | e 26564
118 | e 26658
119 | e 26736
120 | e 26740
121 | e 26831
122 | e 26999
123 | e 27591
124 | e 27746
125 | e 27907
126 | e 28123
127 | e 28249
128 | e 28408
129 | e 28743
130 | e 28892
131 | e 28907
132 | e 28951
133 | e 28961
134 | e 29253
135 | e 29392
136 | e 30456
137 | e 30943
138 | e 31578
139 | e 31751
140 | e 31841
141 | e 31973
142 | e 32596
143 | e 32944
144 | e 33266
145 | e 33268
146 | e 33316
147 | e 33408
148 | e 33491
149 |
--------------------------------------------------------------------------------
/experiment/Polygon/bunny_disk.mark:
--------------------------------------------------------------------------------
1 | v 2210 1.57079627
2 | v 2255 1.57079627
3 | v 2275 1.57079627
4 | v 2415 1.57079627
5 |
--------------------------------------------------------------------------------
/experiment/Polygon/half_sphere.mark:
--------------------------------------------------------------------------------
1 | v 199 1.57079627
2 | v 352 1.57079627
3 | v 400 1.57079627
4 | v 757 1.57079627
5 | v 1613 1.57079627
6 | v 1835 4.71238881
7 |
--------------------------------------------------------------------------------
/experiment/Texture/checker_1k.bmp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xuan-li/Surface-Parameterization-Algorithms/c92997447447791bd1db2900717ce91d12a2203a/experiment/Texture/checker_1k.bmp
--------------------------------------------------------------------------------
/experiment/Texture/circles_1.bmp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xuan-li/Surface-Parameterization-Algorithms/c92997447447791bd1db2900717ce91d12a2203a/experiment/Texture/circles_1.bmp
--------------------------------------------------------------------------------
/experiment/bin/Viewer.exe:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xuan-li/Surface-Parameterization-Algorithms/c92997447447791bd1db2900717ce91d12a2203a/experiment/bin/Viewer.exe
--------------------------------------------------------------------------------
/images/bunny_free_emb.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xuan-li/Surface-Parameterization-Algorithms/c92997447447791bd1db2900717ce91d12a2203a/images/bunny_free_emb.png
--------------------------------------------------------------------------------
/images/bunny_free_texture.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xuan-li/Surface-Parameterization-Algorithms/c92997447447791bd1db2900717ce91d12a2203a/images/bunny_free_texture.png
--------------------------------------------------------------------------------
/images/bunny_hyper.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xuan-li/Surface-Parameterization-Algorithms/c92997447447791bd1db2900717ce91d12a2203a/images/bunny_hyper.png
--------------------------------------------------------------------------------
/images/bunny_hyper_cover.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xuan-li/Surface-Parameterization-Algorithms/c92997447447791bd1db2900717ce91d12a2203a/images/bunny_hyper_cover.png
--------------------------------------------------------------------------------
/images/bunny_hyper_emb.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xuan-li/Surface-Parameterization-Algorithms/c92997447447791bd1db2900717ce91d12a2203a/images/bunny_hyper_emb.png
--------------------------------------------------------------------------------
/images/bunny_hyper_texture.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xuan-li/Surface-Parameterization-Algorithms/c92997447447791bd1db2900717ce91d12a2203a/images/bunny_hyper_texture.png
--------------------------------------------------------------------------------
/images/bunny_polygon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xuan-li/Surface-Parameterization-Algorithms/c92997447447791bd1db2900717ce91d12a2203a/images/bunny_polygon.png
--------------------------------------------------------------------------------
/images/bunny_polygon_emb.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xuan-li/Surface-Parameterization-Algorithms/c92997447447791bd1db2900717ce91d12a2203a/images/bunny_polygon_emb.png
--------------------------------------------------------------------------------
/images/bunny_polygon_texture.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xuan-li/Surface-Parameterization-Algorithms/c92997447447791bd1db2900717ce91d12a2203a/images/bunny_polygon_texture.png
--------------------------------------------------------------------------------
/images/cone.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xuan-li/Surface-Parameterization-Algorithms/c92997447447791bd1db2900717ce91d12a2203a/images/cone.png
--------------------------------------------------------------------------------
/images/david_euc.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xuan-li/Surface-Parameterization-Algorithms/c92997447447791bd1db2900717ce91d12a2203a/images/david_euc.png
--------------------------------------------------------------------------------
/images/david_euc_cover.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xuan-li/Surface-Parameterization-Algorithms/c92997447447791bd1db2900717ce91d12a2203a/images/david_euc_cover.png
--------------------------------------------------------------------------------
/images/david_euc_emb.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xuan-li/Surface-Parameterization-Algorithms/c92997447447791bd1db2900717ce91d12a2203a/images/david_euc_emb.png
--------------------------------------------------------------------------------
/images/david_euc_texture.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xuan-li/Surface-Parameterization-Algorithms/c92997447447791bd1db2900717ce91d12a2203a/images/david_euc_texture.png
--------------------------------------------------------------------------------
/images/david_global.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xuan-li/Surface-Parameterization-Algorithms/c92997447447791bd1db2900717ce91d12a2203a/images/david_global.png
--------------------------------------------------------------------------------
/images/david_global_emb.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xuan-li/Surface-Parameterization-Algorithms/c92997447447791bd1db2900717ce91d12a2203a/images/david_global_emb.png
--------------------------------------------------------------------------------
/images/david_global_emb_hilbert.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xuan-li/Surface-Parameterization-Algorithms/c92997447447791bd1db2900717ce91d12a2203a/images/david_global_emb_hilbert.png
--------------------------------------------------------------------------------
/images/david_global_texture.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xuan-li/Surface-Parameterization-Algorithms/c92997447447791bd1db2900717ce91d12a2203a/images/david_global_texture.png
--------------------------------------------------------------------------------
/images/euc_orbifold.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xuan-li/Surface-Parameterization-Algorithms/c92997447447791bd1db2900717ce91d12a2203a/images/euc_orbifold.png
--------------------------------------------------------------------------------
/images/four_euc_orbifolds.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xuan-li/Surface-Parameterization-Algorithms/c92997447447791bd1db2900717ce91d12a2203a/images/four_euc_orbifolds.png
--------------------------------------------------------------------------------
/images/gui.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xuan-li/Surface-Parameterization-Algorithms/c92997447447791bd1db2900717ce91d12a2203a/images/gui.png
--------------------------------------------------------------------------------
/images/halfedge.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xuan-li/Surface-Parameterization-Algorithms/c92997447447791bd1db2900717ce91d12a2203a/images/halfedge.png
--------------------------------------------------------------------------------
/images/halfshpere_polygon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xuan-li/Surface-Parameterization-Algorithms/c92997447447791bd1db2900717ce91d12a2203a/images/halfshpere_polygon.png
--------------------------------------------------------------------------------
/images/halfshpere_polygon_texture.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xuan-li/Surface-Parameterization-Algorithms/c92997447447791bd1db2900717ce91d12a2203a/images/halfshpere_polygon_texture.png
--------------------------------------------------------------------------------
/images/halfsphere_polygon_emb.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xuan-li/Surface-Parameterization-Algorithms/c92997447447791bd1db2900717ce91d12a2203a/images/halfsphere_polygon_emb.png
--------------------------------------------------------------------------------
/images/hyperbolic.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xuan-li/Surface-Parameterization-Algorithms/c92997447447791bd1db2900717ce91d12a2203a/images/hyperbolic.png
--------------------------------------------------------------------------------
/images/locally.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xuan-li/Surface-Parameterization-Algorithms/c92997447447791bd1db2900717ce91d12a2203a/images/locally.png
--------------------------------------------------------------------------------
/images/loop.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xuan-li/Surface-Parameterization-Algorithms/c92997447447791bd1db2900717ce91d12a2203a/images/loop.png
--------------------------------------------------------------------------------
/images/max_global.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xuan-li/Surface-Parameterization-Algorithms/c92997447447791bd1db2900717ce91d12a2203a/images/max_global.png
--------------------------------------------------------------------------------
/images/max_global_emb.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xuan-li/Surface-Parameterization-Algorithms/c92997447447791bd1db2900717ce91d12a2203a/images/max_global_emb.png
--------------------------------------------------------------------------------
/images/max_global_texture.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xuan-li/Surface-Parameterization-Algorithms/c92997447447791bd1db2900717ce91d12a2203a/images/max_global_texture.png
--------------------------------------------------------------------------------
/images/parameterizations.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xuan-li/Surface-Parameterization-Algorithms/c92997447447791bd1db2900717ce91d12a2203a/images/parameterizations.png
--------------------------------------------------------------------------------
/images/q-fold.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xuan-li/Surface-Parameterization-Algorithms/c92997447447791bd1db2900717ce91d12a2203a/images/q-fold.png
--------------------------------------------------------------------------------
/images/q-folds.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xuan-li/Surface-Parameterization-Algorithms/c92997447447791bd1db2900717ce91d12a2203a/images/q-folds.png
--------------------------------------------------------------------------------
/images/spherical.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xuan-li/Surface-Parameterization-Algorithms/c92997447447791bd1db2900717ce91d12a2203a/images/spherical.png
--------------------------------------------------------------------------------
/images/torus.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xuan-li/Surface-Parameterization-Algorithms/c92997447447791bd1db2900717ce91d12a2203a/images/torus.png
--------------------------------------------------------------------------------
/src/BoundaryFirstFlattening/BFF.cpp:
--------------------------------------------------------------------------------
1 | #include "BFF.h"
2 |
3 | BFFSolver::BFFSolver(SurfaceMesh & mesh, OpenMesh::VPropHandleT cone_flag, OpenMesh::VPropHandleT cone_angle, OpenMesh::EPropHandleT slice_flag)
4 | :mesh_(mesh), cone_flag_(cone_flag), cone_angle_(cone_angle), slice_flag_(slice_flag)
5 | {
6 |
7 | }
8 |
9 |
10 | SurfaceMesh BFFSolver::Compute(int mode)
11 | {
12 | /*
13 | mode 0: BFF known k with hilbert extension
14 | mode 1: BFF known k with harmonic extension
15 | mode 2: BFF free boundary with hilbert extension
16 | mode 3: BFF free boundary with harmonic extension
17 | mode 4: BFF cone parameterization with hilbert extension
18 | mode 5: BFF cone parameterization with harmonic extension
19 | */
20 |
21 | Init();
22 |
23 | ComputeVertexCurvatures(sliced_mesh_);
24 |
25 | if (mode == 2 || mode == 3)
26 | FreeBoundary();
27 | else if (mode == 0 || mode == 1)
28 | BoundaryTargetKKnown();
29 | else if (mode == 4 || mode == 5)
30 | GlobalParameterization();
31 |
32 | IntegrateBoundaryCurve();
33 |
34 | if(mode == 0 || mode == 2 || mode == 4)
35 | ExtendToInteriorHilbert();
36 | else
37 | ExtendToInteriorHarmonic();
38 |
39 | NormalizeUV();
40 |
41 | return sliced_mesh_;
42 | }
43 |
44 | void BFFSolver::Init()
45 | {
46 | BFFInitializer initializer(mesh_);
47 | initializer.Initiate(sliced_mesh_, cone_flag_, cone_angle_, slice_flag_);
48 | cone_vts_ = initializer.GetConeVertices();
49 | split_to_ = initializer.split_to();
50 | }
51 |
52 | double BFFSolver::CosineLaw(double a, double b, double c)
53 | {
54 | double cs = (a * a + b * b - c * c) / (2 * a * b);
55 | if (-1 > cs)
56 | return PI;
57 | else if (cs > 1)
58 | return 0;
59 | else
60 | return acos(cs);
61 | }
62 |
63 | void BFFSolver::ComputeCornerAngles(SurfaceMesh &mesh, Eigen::VectorXd L)
64 | {
65 | using namespace OpenMesh;
66 | bool with_length = false;
67 | if (L.size() == mesh.n_edges())
68 | with_length = true;
69 | for (auto fiter = mesh.faces_begin(); fiter != mesh.faces_end(); ++fiter) {
70 | FaceHandle f = *fiter;
71 | std::vector he;
72 |
73 | for (auto fhiter = mesh.fh_iter(f); fhiter.is_valid(); ++fhiter) {
74 | he.push_back(*fhiter);
75 | }
76 | double l[3];
77 | if (with_length) {
78 | l[0] = L(mesh.edge_handle(he[0]).idx());
79 | l[1] = L(mesh.edge_handle(he[1]).idx());
80 | l[2] = L(mesh.edge_handle(he[2]).idx());
81 | }
82 | else {
83 | l[0] = mesh.calc_edge_length(mesh.edge_handle(he[0]));
84 | l[1] = mesh.calc_edge_length(mesh.edge_handle(he[1]));
85 | l[2] = mesh.calc_edge_length(mesh.edge_handle(he[2]));
86 | }
87 | for (int i = 0; i < 3; ++i) {
88 | double cs = CosineLaw(l[i], l[(i + 1) % 3], l[(i + 2) % 3]);
89 | mesh.data(he[i]).set_angle(cs);
90 | }
91 | }
92 | }
93 |
94 | void BFFSolver::ComputeVertexCurvatures(SurfaceMesh &mesh, Eigen::VectorXd L)
95 | {
96 | using namespace OpenMesh;
97 | ComputeCornerAngles(mesh, L);
98 | double sum = 0.0;
99 | for (auto viter = mesh.vertices_begin(); viter != mesh.vertices_end(); ++viter) {
100 | VertexHandle v = *viter;
101 | double angle_sum = 0.0;
102 | for (auto vihiter = mesh.vih_iter(v); vihiter.is_valid(); ++vihiter) {
103 | HalfedgeHandle h = *vihiter;
104 | if (mesh.is_boundary(h)) continue;
105 | angle_sum += mesh.data(h).angle();
106 | }
107 | if(!mesh.is_boundary(v))
108 | mesh.data(v).set_curvature(2 * PI - angle_sum);
109 | else
110 | mesh.data(v).set_curvature(PI - angle_sum);
111 | sum += mesh.data(v).curvature();
112 | }
113 | std::cout << "Total Curvature: " << sum/ PI << " pi."<< std::endl;
114 | }
115 |
116 | void BFFSolver::ComputeLaplacian(SurfaceMesh & mesh, bool mode)
117 | {
118 | using namespace OpenMesh;
119 | using namespace Eigen;
120 |
121 | ReindexVertices(mesh);
122 | ComputeHalfedgeWeights(mesh);
123 |
124 | Delta_.resize(mesh.n_vertices(), mesh.n_vertices());
125 | Delta_.setZero();
126 | std::vector> A_coefficients;
127 | for (auto viter = mesh.vertices_begin(); viter != mesh.vertices_end(); ++viter) {
128 | VertexHandle v = *viter;
129 | if (mode && (viter == mesh.vertices_begin())){
130 | for (auto viter1 = mesh.vertices_begin(); viter1 != mesh.vertices_end(); ++viter1) {
131 | VertexHandle v1 = *viter1;
132 | A_coefficients.push_back(Eigen::Triplet(mesh.data(v).reindex(), mesh.data(v1).reindex(), 1.));
133 | }
134 | continue;
135 | }
136 | double s_w = 0;
137 | for (SurfaceMesh::VertexVertexIter vviter = mesh.vv_iter(v); vviter.is_valid(); ++vviter) {
138 | VertexHandle neighbor = *vviter;
139 | HalfedgeHandle h = mesh.find_halfedge(v, neighbor);
140 | double n_w = mesh.data(h).weight();
141 |
142 | s_w += n_w;
143 | A_coefficients.push_back(Eigen::Triplet(mesh.data(v).reindex(), mesh.data(neighbor).reindex(), -n_w));
144 | }
145 | A_coefficients.push_back(Eigen::Triplet(mesh.data(v).reindex(), mesh.data(v).reindex(), s_w));
146 | }
147 | Delta_.setFromTriplets(A_coefficients.begin(), A_coefficients.end());
148 | }
149 |
150 |
151 | void BFFSolver::ComputeHalfedgeWeights(SurfaceMesh &mesh)
152 | {
153 | using namespace OpenMesh;
154 | ComputeCornerAngles(mesh);
155 | for (auto eiter = mesh.edges_begin(); eiter != mesh.edges_end(); ++eiter) {
156 | EdgeHandle e = *eiter;
157 | HalfedgeHandle h0 = mesh.halfedge_handle(e, 0);
158 | HalfedgeHandle h1 = mesh.halfedge_handle(e, 1);
159 | HalfedgeHandle h0_next;
160 | if (!mesh.is_boundary(h0))
161 | h0_next = mesh.next_halfedge_handle(h0);
162 | HalfedgeHandle h1_next;
163 | if (!mesh.is_boundary(h1))
164 | h1_next = mesh.next_halfedge_handle(h1);
165 |
166 | double weight = 0.;
167 |
168 | if (h0_next.is_valid())
169 | weight += 1. / tan(mesh.data(h0_next).angle());
170 | if (h1_next.is_valid())
171 | weight += 1. / tan(mesh.data(h1_next).angle());
172 | weight *= 0.5;
173 | //if (weight < 0)
174 | //weight = 0.01;
175 | mesh.data(h0).set_weight(weight);
176 | mesh.data(h1).set_weight(weight);
177 | }
178 | }
179 |
180 | void BFFSolver::ReindexVertices(SurfaceMesh & mesh)
181 | {
182 | using namespace OpenMesh;
183 | int n_interior = 0;
184 | int n_boundary = 0;
185 |
186 | for (auto viter = mesh.vertices_begin(); viter != mesh.vertices_end(); ++viter) {
187 | VertexHandle v = *viter;
188 | if (!mesh.is_boundary(v)) {
189 | mesh.data(v).set_reindex(n_interior);
190 | ++n_interior;
191 | }
192 | }
193 |
194 | mesh.RequestBoundary();
195 | if (mesh.GetBoundaries().size() == 0) return;
196 | auto boundary = mesh.GetBoundaries().front();
197 | std::list boundary_list(boundary.begin(), boundary.end());
198 | for (auto it = boundary_list.begin(); it != boundary_list.end(); ++it) {
199 | if (!mesh.data(mesh.from_vertex_handle(*it)).equivalent_vertex().is_valid()) {
200 | boundary_list.insert(boundary_list.end(), boundary_list.begin(), it);
201 | boundary_list.erase(boundary_list.begin(), it);
202 | break;
203 | }
204 | }
205 |
206 | for (auto it = boundary_list.begin(); it != boundary_list.end(); ++it) {
207 | mesh.data(mesh.from_vertex_handle(*it)).set_reindex(n_interior+n_boundary);
208 | ++n_boundary;
209 | }
210 |
211 |
212 |
213 | n_boundary_ = n_boundary;
214 | n_interior_ = n_interior;
215 | }
216 |
217 | void BFFSolver::BoundaryTargetKKnown()
218 | {
219 | using namespace Eigen;
220 | using namespace OpenMesh;
221 | SurfaceMesh &mesh = sliced_mesh_;
222 | VectorXd target_k(mesh.n_vertices());
223 | target_k.setZero();
224 |
225 | ReindexVertices(mesh);
226 |
227 | std::cout << "Singularities' curvature:" << std::endl;
228 | for (auto viter = mesh.vertices_begin(); viter != mesh.vertices_end(); ++viter) {
229 | VertexHandle v = *viter;
230 | if (mesh.data(v).is_singularity()) {
231 | target_k(mesh.data(v).reindex()) = mesh.data(v).target_curvature();
232 | std::cout << mesh.data(v).target_curvature() / PI << "pi" << std::endl;
233 | }
234 | }
235 | VectorXd k_B = target_k.segment(n_interior_, n_boundary_);
236 | VectorXd u = BoundaryTargetKToU(k_B);
237 |
238 | mesh.RequestBoundary();
239 | auto boundary = mesh.GetBoundaries().front();
240 | for (auto it = boundary.begin(); it != boundary.end(); ++it) {
241 | VertexHandle v = mesh.to_vertex_handle(*it);
242 | mesh.data(v).set_u(u(mesh.data(v).reindex() - n_interior_));
243 | }
244 |
245 | }
246 |
247 |
248 |
249 | void BFFSolver::FreeBoundary()
250 | {
251 | using namespace Eigen;
252 | using namespace OpenMesh;
253 | SurfaceMesh &mesh = sliced_mesh_;
254 |
255 | VectorXd u(mesh.n_vertices());
256 | ReindexVertices(mesh);
257 |
258 | u.setZero();
259 |
260 | Eigen::VectorXd u_B = u.segment(n_interior_, n_boundary_);
261 |
262 | Eigen::VectorXd target_k = BoundaryUToTargetK(u_B);
263 |
264 | auto boundary = sliced_mesh_.GetBoundaries().front();
265 | for (auto it = boundary.begin(); it != boundary.end(); ++it) {
266 | VertexHandle v = sliced_mesh_.to_vertex_handle(*it);
267 | mesh.data(v).set_target_curvature(target_k(mesh.data(v).reindex() - n_interior_));
268 | mesh.data(v).set_u(0);
269 | }
270 |
271 | std::cout << "Singularities' curvature:" << std::endl;
272 | for (auto it = cone_vts_.begin(); it != cone_vts_.end(); ++it) {
273 | VertexHandle v = *it;
274 | std::cout << mesh.data(v).target_curvature() / PI << "pi" << std::endl;
275 | }
276 |
277 | for (auto viter = mesh.vertices_begin(); viter != mesh.vertices_end(); ++viter) {
278 | VertexHandle v = *viter;
279 | mesh.data(v).reindex();
280 | }
281 |
282 |
283 | }
284 |
285 | void BFFSolver::GlobalParameterization()
286 | {
287 | using namespace Eigen;
288 | SurfaceMesh &mesh = mesh_;
289 | using namespace OpenMesh;
290 | // Using Cherrier Formula
291 | // Construct Sparse system;
292 | ComputeLaplacian(mesh, true);
293 | ComputeVertexCurvatures(mesh);
294 | Eigen::VectorXd b(mesh.n_vertices());
295 |
296 | for (auto viter = mesh.vertices_begin(); viter != mesh.vertices_end(); ++viter) {
297 | VertexHandle v = *viter;
298 | if (!mesh.property(cone_flag_, v)) {
299 | b(mesh.data(v).reindex()) = mesh.data(v).curvature();
300 | }
301 | else {
302 | if (mesh.is_boundary(v))
303 | b(mesh.data(v).reindex()) = mesh.data(v).curvature() - (PI - mesh.property(cone_angle_, v));
304 | else
305 | b(mesh.data(v).reindex()) = mesh.data(v).curvature() - (2 * PI - mesh.property(cone_angle_, v));
306 | }
307 | }
308 |
309 | b(mesh.data(*mesh.vertices_begin()).reindex()) = 0;
310 |
311 | SparseLU, COLAMDOrdering> solver;
312 | solver.compute(Delta_);
313 | if (solver.info() != Eigen::Success){
314 | std::cerr << "Waring: Eigen decomposition failed" << std::endl;
315 | }
316 | Eigen::VectorXd u = solver.solve(b);
317 |
318 | for (auto viter = mesh.vertices_begin(); viter != mesh.vertices_end(); ++viter) {
319 | VertexHandle v = *viter;
320 | mesh.data(v).set_u(u(mesh.data(v).reindex()));
321 | }
322 |
323 | ReindexVertices(sliced_mesh_);
324 | u.resize(sliced_mesh_.n_vertices());
325 | for (auto viter = mesh.vertices_begin(); viter != mesh.vertices_end(); ++viter) {
326 | VertexHandle v = *viter;
327 | auto verts = mesh.property(split_to_, v);
328 | for (auto it = verts.begin(); it != verts.end(); ++it) {
329 | sliced_mesh_.data(*it).set_u(mesh.data(v).u());
330 | u(sliced_mesh_.data(*it).reindex()) = mesh.data(v).u();
331 | }
332 | }
333 |
334 |
335 | // Convert u to k
336 | VectorXd uB = u.segment(n_interior_, n_boundary_);
337 | Eigen::VectorXd target_k = BoundaryUToTargetK(uB);
338 | auto boundary = sliced_mesh_.GetBoundaries().front();
339 | for (auto it = boundary.begin(); it != boundary.end(); ++it) {
340 | VertexHandle v = sliced_mesh_.to_vertex_handle(*it);
341 | sliced_mesh_.data(v).set_target_curvature(target_k(sliced_mesh_.data(v).reindex() - n_interior_));
342 | }
343 |
344 | std::cout << "Singularities' curvature:" << std::endl;
345 | for (auto it = cone_vts_.begin(); it != cone_vts_.end(); ++it) {
346 | VertexHandle v = *it;
347 | std::cout << sliced_mesh_.data(v).target_curvature() / PI << "pi" << std::endl;
348 | }
349 |
350 | }
351 |
352 |
353 | Eigen::VectorXd BFFSolver::BoundaryUToTargetK(Eigen::VectorXd & u)
354 | {
355 | using namespace Eigen;
356 | using namespace OpenMesh;
357 |
358 | SurfaceMesh &mesh = sliced_mesh_;
359 |
360 | ComputeLaplacian(mesh);
361 | VectorXd omega(mesh.n_vertices());
362 | VectorXd k(n_boundary_);
363 |
364 | for (auto viter = mesh.vertices_begin(); viter != mesh.vertices_end(); ++viter) {
365 | VertexHandle v = *viter;
366 | omega(mesh.data(v).reindex()) = mesh.data(v).curvature();
367 | }
368 |
369 | k = omega.segment(n_interior_, n_boundary_);
370 | SparseLU> solver;
371 | solver.compute(Delta_.block(0, 0, n_interior_, n_interior_));
372 | if (solver.info() != Eigen::Success)
373 | {
374 | std::cerr << "Waring: Eigen decomposition failed" << std::endl;
375 | }
376 |
377 | Eigen::SparseMatrix A_IB = Delta_.block(0, n_interior_, n_interior_, n_boundary_);
378 | Eigen::SparseMatrix A_BB = Delta_.block(n_interior_, n_interior_, n_boundary_, n_boundary_);
379 | Eigen::SparseMatrix A_BI = Delta_.block(n_interior_, 0, n_boundary_, n_interior_);
380 | VectorXd omega_I = omega.segment(0, n_interior_);
381 | Eigen::VectorXd to_inverse = omega_I - A_IB * u;
382 | Eigen::VectorXd inverse = solver.solve(to_inverse);
383 | assert((Delta_.block(0, 0, n_interior_, n_interior_) * inverse - to_inverse).norm() < 1e-7);
384 | Eigen::VectorXd h = A_BI * inverse + A_BB * u;
385 |
386 | Eigen::VectorXd target_k = k - h;
387 |
388 | std::cout << "Sum of target total curvature:" << target_k.sum() / PI << " pi" << std::endl;
389 |
390 | return target_k;
391 |
392 | }
393 |
394 | Eigen::VectorXd BFFSolver::BoundaryTargetKToU(Eigen::VectorXd & target_k)
395 | {
396 | using namespace Eigen;
397 | using namespace OpenMesh;
398 |
399 | SurfaceMesh &mesh = sliced_mesh_;
400 | ComputeLaplacian(mesh, true);
401 |
402 | VectorXd omega(mesh.n_vertices());
403 | VectorXd h(mesh.n_vertices());
404 |
405 | for (auto viter = mesh.vertices_begin(); viter != mesh.vertices_end(); ++viter) {
406 | VertexHandle v = *viter;
407 | if (!mesh.is_boundary(v)) {
408 | omega(mesh.data(v).reindex()) = mesh.data(v).curvature();
409 | h(mesh.data(v).reindex()) = 0.;
410 | }
411 | else {
412 | omega(mesh.data(v).reindex()) = 0;
413 | h(mesh.data(v).reindex()) = (mesh.data(v).curvature() - target_k(mesh.data(v).reindex() - n_interior_));
414 | }
415 |
416 | }
417 |
418 | omega(mesh.data(*mesh.vertices_begin()).reindex()) = 0;
419 |
420 |
421 | SparseLU> solver;
422 | solver.compute(Delta_);
423 | if (solver.info() != Eigen::Success)
424 | {
425 | std::cerr << "Waring: Eigen decomposition failed" << std::endl;
426 | }
427 |
428 | Eigen::VectorXd u = solver.solve(omega + h);
429 |
430 | return u.segment(n_interior_, n_boundary_);
431 |
432 |
433 | }
434 |
435 | void BFFSolver::IntegrateBoundaryCurve()
436 | {
437 | using namespace OpenMesh;
438 | using namespace Eigen;
439 | SurfaceMesh &mesh = sliced_mesh_;
440 |
441 | VPropHandleT cumulative_angle;
442 | VPropHandleT tangent;
443 | mesh.add_property(cumulative_angle);
444 | mesh.add_property(tangent);
445 |
446 | Eigen::MatrixXd T(2, n_boundary_); // Tangent vector
447 |
448 | T.setZero();
449 |
450 | Eigen::VectorXd L_star(n_boundary_); // edge length after conformal map
451 | Eigen::VectorXd L(n_boundary_); // mesh euclidean length.
452 | auto boundary = mesh.GetBoundaries().front();
453 | mesh.property(cumulative_angle, mesh.from_vertex_handle(boundary.front())) = mesh.data(mesh.from_vertex_handle(boundary.front())).target_curvature();
454 | int i = 0;
455 | for (auto it = boundary.begin(); it != boundary.end(); ++it, ++i) {
456 | VertexHandle v0 = mesh.from_vertex_handle(*it);
457 | VertexHandle v1 = mesh.to_vertex_handle(*it);
458 | EdgeHandle e = mesh.edge_handle(*it);
459 | double u0 = mesh.data(v0).u();
460 | double u1 = mesh.data(v1).u();
461 | double l = mesh.calc_edge_length(e);
462 | double l_star = exp(0.5 * (u0 + u1)) * l;
463 | double angle = mesh.property(cumulative_angle, v0);
464 | mesh.property(cumulative_angle, v1) = angle + mesh.data(v1).target_curvature();
465 | mesh.property(tangent, v0) = Vec2d(cos(angle), sin(angle));
466 |
467 | T(0, i) = cos(angle);
468 | T(1, i) = sin(angle);
469 | L_star(i) = l_star;
470 | L(i) = l;
471 | }
472 |
473 | // Reindex boundary halfedges
474 | HPropHandleT reindex;
475 | mesh.add_property(reindex);
476 |
477 | int index = 0;
478 | for (auto it = boundary.begin(); it != boundary.end(); ++it, ++index) {
479 | HalfedgeHandle h = *it;
480 | mesh.property(reindex, h) = index;
481 | }
482 |
483 | // Equivalent edges produced by cut should be of the same length.
484 | std::vector oppo_relation(boundary.size());
485 |
486 | for (auto it = boundary.begin(); it != boundary.end(); ++it) {
487 | HalfedgeHandle h = *it;
488 | HalfedgeHandle oppo_inner = mesh.data(mesh.opposite_halfedge_handle(h)).original_opposition();
489 | if (oppo_inner.is_valid()) {
490 | HalfedgeHandle oppo = mesh.opposite_halfedge_handle(oppo_inner);
491 | oppo_relation[mesh.property(reindex, h)] = mesh.property(reindex, oppo);
492 | oppo_relation[mesh.property(reindex, oppo)] = mesh.property(reindex, h);
493 | }
494 | else {
495 | oppo_relation[mesh.property(reindex, h)] = -1;
496 | }
497 | }
498 |
499 | std::vector valid_halfedges;
500 | for (int i = 0; i < oppo_relation.size(); ++i) {
501 | if (i > oppo_relation[i] && oppo_relation[i] != -1) continue;
502 | valid_halfedges.push_back(boundary[i]);
503 | }
504 |
505 |
506 | int n_valid_h = valid_halfedges.size();
507 |
508 | Eigen::MatrixXd N(n_valid_h, n_valid_h);
509 | N.setZero();
510 | for (int i = 1; i < n_valid_h; ++i) {
511 | HalfedgeHandle h = valid_halfedges[i];
512 | int index = mesh.property(reindex, h);
513 | int oppo_index = oppo_relation[index];
514 | N(i, i) = L_star(index);
515 | if (oppo_index >= 0) {
516 | N(i, i) *= 2;
517 | }
518 | }
519 |
520 | Eigen::MatrixXd newT(T.rows(), n_valid_h);
521 | Eigen::VectorXd L_star_valid(n_valid_h);
522 |
523 | for (int i = 0; i < n_valid_h; ++i) {
524 | HalfedgeHandle h = valid_halfedges[i];
525 | int index = mesh.property(reindex, h);
526 | int oppo_index = oppo_relation[index];
527 | newT.col(i) = T.col(index);
528 | if (oppo_index >= 0)
529 | newT.col(i) += T.col(oppo_index);
530 | L_star_valid(i) = L_star(index);
531 | }
532 |
533 | // Use quadratic programming to get optimal solutions.
534 | Eigen::SparseMatrix Q = (0.5 * N * N).sparseView();
535 | Eigen::VectorXd B = - N.diagonal();
536 |
537 | Eigen::SparseMatrix A_eq(2, Q.rows());
538 | A_eq = newT.sparseView();
539 | Eigen::VectorXd B_eq(2); B_eq.setZero();
540 |
541 | Eigen::SparseMatrix A_ieq = (-Eigen::MatrixXd::Identity(Q.rows(), Q.cols())).sparseView();
542 | Eigen::VectorXd B_ieq = -Eigen::VectorXd::Constant(A_ieq.rows(), -1e-3);
543 |
544 | Eigen::VectorXd lx = Eigen::VectorXd::Constant(Q.cols(), -1000);
545 | Eigen::VectorXd ux = Eigen::VectorXd::Constant(Q.cols(), 1000);
546 |
547 | Eigen::VectorXd L_normalized_valid(L_star_valid.size());
548 | L_normalized_valid = L_star_valid;
549 | igl::active_set_params as;
550 | igl::active_set(Q, B, Eigen::VectorXi(), Eigen::VectorXd(), A_eq, B_eq, A_ieq, B_ieq, lx, ux, as, L_normalized_valid);
551 | Eigen::VectorXd L_normalized(L_star.size());
552 |
553 |
554 | for (int i = 0; i < n_valid_h; ++i) {
555 | HalfedgeHandle h = valid_halfedges[i];
556 | int index = mesh.property(reindex, h);
557 | int oppo_index = oppo_relation[index];
558 | L_normalized(index) = L_normalized_valid[i];
559 | if (oppo_index >= 0)
560 | L_normalized(oppo_index) = L_normalized_valid(i);
561 | }
562 |
563 | i = 0;
564 | mesh.set_texcoord2D(mesh.from_vertex_handle(boundary.front()), Vec2d(0, 0));
565 | for (auto it = boundary.begin(); it != boundary.end(); ++it, ++i) {
566 | VertexHandle v0 = mesh.from_vertex_handle(*it);
567 | VertexHandle v1 = mesh.to_vertex_handle(*it);
568 | Vec2d coord = mesh.texcoord2D(v0) + mesh.property(tangent, v0) * L_normalized(i);
569 | mesh.set_texcoord2D(v1, coord);
570 | }
571 |
572 | }
573 |
574 | void BFFSolver::ExtendToInteriorHilbert()
575 | {
576 | using namespace Eigen;
577 | using namespace OpenMesh;
578 | SurfaceMesh &mesh = sliced_mesh_;
579 | ComputeHarmonicMatrix();
580 |
581 | Eigen::VectorXd a_boundary(mesh.n_vertices());
582 | a_boundary.setZero();
583 |
584 | auto boundary = mesh.GetBoundaries().front();
585 | for (int i = 0; i < boundary.size(); ++i) {
586 | VertexHandle v = mesh.to_vertex_handle(boundary[i]);
587 | Vec2d coord = mesh.texcoord2D(v);
588 | a_boundary(v.idx()) = coord[0];
589 | }
590 |
591 | SparseLU> solver;
592 | solver.compute(Delta_);
593 | if (solver.info() != Eigen::Success)
594 | {
595 | std::cerr << "Waring: Eigen decomposition failed" << std::endl;
596 | }
597 | Eigen::VectorXd a = solver.solve(a_boundary);
598 |
599 | ComputeLaplacian(mesh);
600 | Eigen::VectorXd h(mesh.n_vertices());
601 | h.setZero();
602 | for (int i = 0; i < boundary.size(); ++i) {
603 | VertexHandle v = mesh.to_vertex_handle(boundary[i]);
604 | VertexHandle v_prev = mesh.from_vertex_handle(boundary[i]);
605 | VertexHandle v_next = mesh.to_vertex_handle(boundary[(i + 1) % boundary.size()]);
606 | h(mesh.data(v).reindex()) = -0.5 * (a(v_next.idx()) - a(v_prev.idx()));
607 | }
608 |
609 | solver.compute(Delta_);
610 | if (solver.info() != Eigen::Success)
611 | {
612 | std::cerr << "Waring: Eigen decomposition failed" << std::endl;
613 | }
614 | Eigen::VectorXd b = solver.solve(h);
615 |
616 | for (auto viter = mesh.vertices_begin(); viter != mesh.vertices_end(); ++viter) {
617 | VertexHandle v = *viter;
618 | mesh.set_texcoord2D(v, Vec2d(a(v.idx()), b(mesh.data(v).reindex())));
619 | }
620 | }
621 |
622 | void BFFSolver::ExtendToInteriorHarmonic()
623 | {
624 | using namespace Eigen;
625 | using namespace OpenMesh;
626 | SurfaceMesh &mesh = sliced_mesh_;
627 | ComputeHarmonicMatrix();
628 |
629 | Eigen::MatrixXd uv_boundary(mesh.n_vertices(), 2);
630 | uv_boundary.setZero();
631 |
632 | auto boundary = mesh.GetBoundaries().front();
633 | for (int i = 0; i < boundary.size(); ++i) {
634 | VertexHandle v = mesh.to_vertex_handle(boundary[i]);
635 | Vec2d coord = mesh.texcoord2D(v);
636 | uv_boundary(v.idx(), 0) = coord[0];
637 | uv_boundary(v.idx(), 1) = coord[1];
638 | }
639 |
640 | SparseLU> solver;
641 | solver.compute(Delta_);
642 | if (solver.info() != Eigen::Success)
643 | {
644 | std::cerr << "Waring: Eigen decomposition failed" << std::endl;
645 | }
646 | Eigen::MatrixXd uv = solver.solve(uv_boundary);
647 |
648 | for (auto viter = mesh.vertices_begin(); viter != mesh.vertices_end(); ++viter) {
649 | VertexHandle v = *viter;
650 | mesh.set_texcoord2D(v, Vec2d(uv(v.idx(), 0), uv(v.idx(), 1)));
651 | }
652 | }
653 |
654 | void BFFSolver::ComputeHarmonicMatrix()
655 | {
656 | using namespace OpenMesh;
657 | using namespace Eigen;
658 | SurfaceMesh &mesh = sliced_mesh_;
659 |
660 | Delta_.resize(mesh.n_vertices(), mesh.n_vertices());
661 | Delta_.setZero();
662 | std::vector> A_coefficients;
663 | for (auto viter = mesh.vertices_begin(); viter != mesh.vertices_end(); ++viter) {
664 | VertexHandle v = *viter;
665 | if (mesh.is_boundary(v)) {
666 | A_coefficients.push_back(Eigen::Triplet(v.idx(), v.idx(), 1.));
667 | continue;
668 | }
669 | double s_w = 0;
670 | for (SurfaceMesh::VertexVertexIter vviter = mesh.vv_iter(v); vviter.is_valid(); ++vviter) {
671 | VertexHandle neighbor = *vviter;
672 | HalfedgeHandle h = mesh.find_halfedge(v, neighbor);
673 | double n_w = mesh.data(h).weight();
674 | s_w += n_w;
675 | A_coefficients.push_back(Eigen::Triplet(v.idx(), neighbor.idx(), -n_w));
676 | }
677 | A_coefficients.push_back(Eigen::Triplet(v.idx(), v.idx(), s_w));
678 | }
679 | Delta_.setFromTriplets(A_coefficients.begin(), A_coefficients.end());
680 | }
681 |
682 | void BFFSolver::NormalizeUV()
683 | {
684 | using namespace OpenMesh;
685 | SurfaceMesh &mesh = sliced_mesh_;
686 | Vec2d s(0, 0);
687 | for (SurfaceMesh::VertexIter viter = mesh.vertices_begin(); viter != mesh.vertices_end(); ++viter) {
688 | VertexHandle v = *viter;
689 | s += mesh.texcoord2D(v);
690 | }
691 | s /= mesh.n_vertices();
692 | for (SurfaceMesh::VertexIter viter = mesh.vertices_begin(); viter != mesh.vertices_end(); ++viter) {
693 | VertexHandle v = *viter;
694 | mesh.set_texcoord2D(v, mesh.texcoord2D(v) -s);
695 | }
696 |
697 | double scale = 0;
698 | for (SurfaceMesh::VertexIter viter = mesh.vertices_begin(); viter != mesh.vertices_end(); ++viter) {
699 | VertexHandle v = *viter;
700 | scale = mesh.texcoord2D(v).norm() > scale ? mesh.texcoord2D(v).norm() : scale;
701 | }
702 | for (SurfaceMesh::VertexIter viter = mesh.vertices_begin(); viter != mesh.vertices_end(); ++viter) {
703 | VertexHandle v = *viter;
704 | mesh.set_texcoord2D(v, mesh.texcoord2D(v) / scale);
705 | }
706 | }
707 |
708 |
709 |
--------------------------------------------------------------------------------
/src/BoundaryFirstFlattening/BFF.h:
--------------------------------------------------------------------------------
1 | #ifndef BOUNDARY_FIRST_FLATTENING
2 | #define BOUNDARY_FIRST_FLATTENING
3 |
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include "BFFInitializer.h"
10 |
11 | #include
12 |
13 | #ifndef PI
14 | #define PI 3.141592653
15 | #endif
16 |
17 | // This class is the implementation of paper Boundary First Flattening.
18 | //
19 | // BFF algorithm parameterize the surface according to boundary data.
20 | // We need one of two kinds of boundary as input: conformal factors or target geodesic curvature.
21 | // These two kinds of data can be converted to each other.
22 | // Known boundary data is determined by user and processed in the initializer for BFF.
23 | class BFFSolver {
24 | public:
25 | BFFSolver(SurfaceMesh &mesh, OpenMesh::VPropHandleT cone_flag, OpenMesh::VPropHandleT cone_angle, OpenMesh::EPropHandleT slice_flag);
26 | SurfaceMesh Compute(int mode = 0);
27 | std::vector ConeVertices() { return cone_vts_; }
28 |
29 | protected:
30 | SurfaceMesh &mesh_;
31 | SurfaceMesh sliced_mesh_;
32 |
33 | std::vector cone_vts_;
34 |
35 | OpenMesh::VPropHandleT cone_flag_;
36 | OpenMesh::VPropHandleT cone_angle_;
37 | OpenMesh::EPropHandleT slice_flag_;
38 |
39 | OpenMesh::VPropHandleT> split_to_;
40 |
41 | Eigen::SparseMatrix Delta_;
42 |
43 | int n_boundary_;
44 | int n_interior_;
45 | int n_cones_;
46 |
47 | protected:
48 |
49 | // Cut the mesh into disk, and set all kinds of data and flags.
50 | void Init();
51 |
52 | double CosineLaw(double a, double b, double c);
53 |
54 | // Compute mesh data
55 | void ComputeCornerAngles(SurfaceMesh &mesh, Eigen::VectorXd l = Eigen::VectorXd());
56 | void ComputeHalfedgeWeights(SurfaceMesh &mesh);
57 | void ComputeVertexCurvatures(SurfaceMesh &mesh, Eigen::VectorXd l = Eigen::VectorXd());
58 |
59 | // Compute cotangent Laplacian operator.
60 | void ComputeLaplacian(SurfaceMesh &mesh, bool mode = false);
61 |
62 | // Seperate inner vertices and boundary vertices.
63 | void ReindexVertices(SurfaceMesh &mesh);
64 |
65 | // Convert boundary target geodesic curvature into conformal factors.
66 | void BoundaryTargetKKnown();
67 |
68 | // To minimize area distorsion, we preserve the length of boundary, i.e. u_B = 0.
69 | // And then we convert conformal factors u_B to target curvature.
70 | void FreeBoundary();
71 |
72 | // To compute a global parameterization with fixed cone angles.
73 | void GlobalParameterization();
74 |
75 |
76 | // The operator that convert boundary conformal factors to target curvatures.
77 | Eigen::VectorXd BoundaryUToTargetK(Eigen::VectorXd &u);
78 |
79 | // The operator that convert boundary target curvatures to conformal factors.
80 | Eigen::VectorXd BoundaryTargetKToU(Eigen::VectorXd &k);
81 |
82 | // Integrate boundary data into a closed loop.
83 | void IntegrateBoundaryCurve();
84 |
85 | // Given boundary's embedding, we use harmonic map to get one component.
86 | // And minimize conformal energy use hilbert transform over the other component.
87 | void ExtendToInteriorHilbert();
88 |
89 | // Use harmonic map on both components.
90 | void ExtendToInteriorHarmonic();
91 |
92 | void ComputeHarmonicMatrix();
93 |
94 | // Normalize uvs s.t. they all fall in unit circle.
95 | void NormalizeUV();
96 | };
97 |
98 | #endif // !BOUNDARY_FIRST_FLATTENING
99 |
--------------------------------------------------------------------------------
/src/BoundaryFirstFlattening/BFFInitializer.cpp:
--------------------------------------------------------------------------------
1 | #include "BFFInitializer.h"
2 |
3 | BFFInitializer::BFFInitializer(SurfaceMesh & mesh)
4 | : mesh_(mesh)
5 | {
6 |
7 | }
8 |
9 | void BFFInitializer::Initiate(SurfaceMesh & sliced_mesh, OpenMesh::VPropHandleT cone_flag, OpenMesh::VPropHandleT cone_angle, OpenMesh::EPropHandleT slice_flag)
10 | {
11 | cone_flag_ = cone_flag;
12 | cone_angle_ = cone_angle;
13 | slice_flag_ = slice_flag;
14 | CutMesh(sliced_mesh);
15 | }
16 |
17 | void BFFInitializer::CutMesh(SurfaceMesh & sliced_mesh)
18 | {
19 | using namespace OpenMesh;
20 | SurfaceMesh &mesh = mesh_;
21 |
22 | MeshSlicer slicer(mesh);
23 | slicer.ResetFlags();
24 | for (auto eiter = mesh.edges_begin(); eiter != mesh.edges_end(); ++eiter) {
25 | EdgeHandle e = *eiter;
26 | if (mesh.property(slice_flag_, e)) {
27 | slicer.AddOnCutEdge(e);
28 | }
29 | }
30 |
31 | slicer.ConstructWedge();
32 | slicer.SliceAccordingToWedge(sliced_mesh);
33 |
34 | for (auto eiter = mesh.edges_begin(); eiter != mesh.edges_end(); ++eiter) {
35 | EdgeHandle e = *eiter;
36 | if (mesh.is_boundary(e)) continue;
37 | HalfedgeHandle h0 = mesh.halfedge_handle(e, 0);
38 | HalfedgeHandle h1 = mesh.halfedge_handle(e, 1);
39 | HalfedgeHandle h0_to = slicer.ConvertTo(h0);
40 | HalfedgeHandle h1_to = slicer.ConvertTo(h1);
41 | sliced_mesh.data(h0_to).set_original_opposition(h1_to);
42 | sliced_mesh.data(h1_to).set_original_opposition(h0_to);
43 | }
44 |
45 | for (auto viter = mesh.vertices_begin(); viter != mesh.vertices_end(); ++viter) {
46 | VertexHandle v = *viter;
47 |
48 | auto verts = slicer.SplitTo(v);
49 |
50 | for (auto it = verts.begin(); it != verts.end(); ++it) {
51 | VertexHandle sv = *it;
52 | sliced_mesh.data(sv).set_target_curvature(0);
53 | if (mesh.property(cone_flag_, v)) {
54 | double angle = mesh_.property(cone_angle_, v) / verts.size();
55 | sliced_mesh.data(sv).set_singularity(true);
56 | if (sliced_mesh.is_boundary(sv))
57 | sliced_mesh.data(sv).set_target_curvature(PI - angle);
58 | else
59 | sliced_mesh.data(sv).set_target_curvature(2 * PI - angle);
60 | }
61 | }
62 |
63 | }
64 |
65 |
66 | split_to_ = slicer.split_to();
67 |
68 | sliced_mesh.RequestBoundary();
69 | auto boundary = sliced_mesh.GetBoundaries().front();
70 | for (auto it = boundary.begin(); it != boundary.end(); ++it) {
71 | HalfedgeHandle h = *it;
72 | if (sliced_mesh.data(sliced_mesh.from_vertex_handle(h)).is_singularity()) {
73 | cone_vertices_.push_back(sliced_mesh.from_vertex_handle(h));
74 | }
75 | }
76 |
77 | }
78 |
79 |
--------------------------------------------------------------------------------
/src/BoundaryFirstFlattening/BFFInitializer.h:
--------------------------------------------------------------------------------
1 | #ifndef BFF_INITIALIZER_H_
2 | #define BFF_INITIALIZER_H_
3 |
4 | #include
5 | #include
6 | #include
7 | #include