├── .gitignore ├── .gitmodules ├── README.md ├── assignment1 ├── .gitignore ├── CMakeLists.txt ├── README.md ├── assignment1.pdf ├── cmake │ └── FindLIBIGL.cmake ├── data │ ├── coffeecup.off │ ├── cube.off │ └── honda.off └── src │ ├── gui_utils.cpp │ ├── gui_utils.h │ └── main.cpp ├── assignment2 ├── .gitignore ├── CMakeLists.txt ├── README.md ├── assignment2.pdf ├── cmake │ └── FindLIBIGL.cmake ├── data │ ├── bunny-1000.off │ ├── bunny-500.off │ ├── cat.off │ ├── horse.off │ ├── hound.off │ ├── luigi.off │ └── sphere.off └── src │ └── main.cpp ├── assignment3 ├── .gitignore ├── CMakeLists.txt ├── README.md ├── assignment3.pdf ├── cmake │ └── FindLIBIGL.cmake ├── data │ ├── Octo_cut2.obj │ ├── bunny.off │ ├── cathead.obj │ ├── cow.obj │ ├── gargoyle_cut.obj │ ├── hemisphere.off │ ├── hemisphere_non_convex_boundary.off │ └── max.off └── src │ └── main.cpp ├── assignment4 ├── .gitignore ├── CMakeLists.txt ├── README.md ├── assignment4.pdf ├── cmake │ └── FindLIBIGL.cmake ├── data │ ├── bar.off │ ├── bumpy_plane.off │ ├── cactus.off │ ├── camel_head.off │ ├── cylinder.off │ ├── hand.off │ ├── woody-hi.off │ └── woody-lo.off └── src │ ├── Colors.cpp │ ├── Colors.h │ ├── Lasso.cpp │ ├── Lasso.h │ └── main.cpp ├── assignment5 ├── CMakeLists.txt ├── README.md ├── assignment5.pdf ├── cmake │ └── FindLIBIGL.cmake └── src │ ├── femLib │ ├── CMakeLists.txt │ ├── Element.h │ ├── FEMElement.h │ ├── FEMElementAnalytic.h │ ├── FEMElementAutoDiff.h │ ├── FEMElementFD.h │ ├── FixedPointElement.h │ ├── SimulationMesh.cpp │ ├── SimulationMesh.h │ ├── Spring.h │ ├── TotalEnergyFunction.cpp │ └── TotalEnergyFunction.h │ ├── gui_utils.cpp │ ├── gui_utils.h │ ├── main.cpp │ ├── optLib │ ├── AutoDiff.h │ ├── CMakeLists.txt │ ├── GradientDescentFunctionMinimizer.h │ ├── MathHelper.h │ ├── NewtonFunctionMinimizer.h │ ├── ObjectiveFunction.h │ └── RosenbrockFunction.h │ └── test_rosenbrock.cpp └── assignment6 ├── CMakeLists.txt ├── README.md ├── assignment6.pdf ├── cmake ├── FindLIBIGL.cmake └── FindOOQP.cmake ├── data ├── woody-hi.off └── woody-lo.off └── src ├── femLib ├── CMakeLists.txt ├── Element.h ├── FEMElement.h ├── FEMElementAnalytic.h ├── FEMElementAutoDiff.h ├── FEMElementFD.h ├── FixedPointElement.h ├── SimulationMesh.cpp ├── SimulationMesh.h ├── Spring.h ├── TotalEnergyFunction.cpp └── TotalEnergyFunction.h ├── gui_utils.cpp ├── gui_utils.h ├── main.cpp ├── optLib ├── AutoDiff.h ├── CMakeLists.txt ├── FunctionConstraints.h ├── GradientDescentFunctionMinimizer.h ├── MathHelper.h ├── NewtonFunctionMinimizer.h ├── ObjectiveFunction.h ├── OoqpEigenInterface.cpp ├── OoqpEigenInterface.h ├── RosenbrockFunction.h ├── SQPFunctionMinimizer.cpp ├── SQPFunctionMinimizer.h ├── ooqpei_assert_macros.h ├── ooqpei_numerical_comparisons.h └── ooqpei_source_file_pos.h └── test_SQP.cpp /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "libigl"] 2 | path = libigl 3 | url = https://github.com/schuellc/libigl.git 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Shape Modeling and Geometry Processing - Course Assignments 2 | 3 | ## Student data 4 | 5 | Name: 'Your real name' 6 | Legi-Nr: 'Your legi number' 7 | 8 | ## News and Changes 9 | 10 | 11 | 20.02.2018 17:30 - Added assignment 1. 12 | 13 | 02.03.2018 12:40 - Added assignment 2. 14 | 15 | 23.03.2018 12:40 - Added assignment 3. 16 | 17 | 13.04.2018 12:40 - Added assignment 4. 18 | 19 | 27.04.2018 09:00 - Added assignment 5. 20 | 21 | 02.05.2018 01:00 - Added AutoDiff code for assignment 5. 22 | 23 | 11.05.2018 03:00 - Added assignment 6. 24 | 25 | Follow the instructions to update your private repository. 26 | 27 | ## Assignments Overview 28 | 29 | [Assignment 1](assignment1/README.md) (Due date: 09.03.2018 09:00) 30 | [Assignment 2](assignment2/README.md) (Due date: 23.03.2018 09:00) 31 | [Assignment 3](assignment3/README.md) (Due date: 13.04.2018 09:00) 32 | [Assignment 4](assignment4/README.md) (Due date: 27.04.2018 09:00) 33 | [Assignment 5](assignment5/README.md) (Due date: .11.05.2018 09:00) 34 | [Assignment 6](assignment6/README.md) (Due date: .25.05.2018 09:00) 35 | 36 | ## General Rules and Instructions 37 | 38 | ### Plagiarism Note and Late Policy 39 | Copying code (either from other students or from external sources) is strictly prohibited! We will be using automatic anti-plagiarism tools, and any violation of this rule will lead to expulsion from the class. Late submissions will generally not be accepted. In case of serious illness or emergency, please notify Roi or Christian and provide a relevant medical certificate. 40 | 41 | ### Provided Libraries 42 | For each assignment, you will use the geometry processing library [libigl](https://github.com/libigl/libigl), which includes implementations of many of the algorithms presented in class. The libigl library includes a set of tutorials, an introduction which can be found [online](http://libigl.github.io/libigl/) or directly in the folder 'libigl/tutorial/tutorial.html'. You are advised to look over the relevant tutorials before starting the implementation for the assignments; you are also encouraged to examine the source code of all the library functions that you use in your code to see how they were implemented. To simplify compilation, we will use libigl as a header-only library (note that, if you prefer, you can compile it into a set of static libraries for faster builds at your own risk (this can be brittle on some platforms). We already included libigl as a git submodule in the course assignment repository [https://github.com/eth-igl/GP2018-Assignments.git](https://github.com/eth-igl/GP2018-Assignments.git) and you don't need to download it yourself. All further dependencies of libigl (like Eigen) are included as submodules in the directory 'libigl/external/' No libraries apart from those are permitted unless stated otherwise. 43 | 44 | ### Installing Git and CMAKE 45 | Before we can begin, you must have Git running, a distributed revision control system which you need to handin your assignments as well as keeping track of your code changes. We refer you to the online [Pro Git book](https://git-scm.com/book/en/v2) for more information. There you will also find [instructions](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git]) on how to to install it. On windows we suggest using [git for windows](https://git-for-windows.github.io/). 46 | 47 | CMake is the system libigl uses for cross-platform builds. If you are using Linux or macOS, I recommend installing it with a package manager instead of the CMake download page. E.g. on Debian/Ubuntu: 48 | ``` 49 | sudo apt-get install cmake 50 | ``` 51 | or with MacPorts on macOS: 52 | ``` 53 | sudo port install cmake. 54 | ``` 55 | On Windows you can download it from: 56 | [https://cmake.org/download/](https://cmake.org/download/) 57 | 58 | ### Cloning the Assignment Repository 59 | Before you are able to clone your private assignment repository, you need to have a active [Github](https://github.com/) account. Then you can create your own private online repository by following this link: https://classroom.github.com/assignment-invitations/845320c79844b27816f22ac903901b45 60 | 61 | In the next step you need to clone it to your local harddrive 62 | ``` 63 | git clone --recursive https://github.com/eth-igl/gp18-'Your_Git_Username'.git 64 | ``` 65 | 'Your_Git_Username' needs to be replaced accordingly. This can take a moment. 66 | 67 | Next, cd into the newly created folder, and add the base assignment repository as a remote: 68 | ``` 69 | cd gp18-'Your_Git_Username' 70 | git remote add base https://github.com/eth-igl/GP2018-Assignments.git 71 | ``` 72 | Now you should have your local clone of the assignment repository ready. Have a look at the new repository folder and open the 'README.md'. It contains the text you are just reading. Please fill in your name and student number at the top of this file and save. Then you need to stage and commit this changed file: 73 | ``` 74 | git add README.md 75 | git commit -m "Adjust README.md" 76 | git push 77 | ``` 78 | You should now be able to see your name online on your private repository: https://github.com/eth-igl/gp18-'Your_Git_Username' 79 | 80 | ### Building Each Assignment 81 | In the assignment repository you will find the different assignment directories 'assignmentX'. For now you only see the first one 'assignment1'. To compile the assignment code we will use the CMake building system. 82 | 83 | Create a directory called build in the assignment directory, e.g.: 84 | ``` 85 | cd assignment1; mkdir build 86 | ``` 87 | Use CMake to generate the Makefiles needed for compilation inside the build/ directory: 88 | ``` 89 | cd build; cmake -DCMAKE_BUILD_TYPE=Release ../ 90 | ``` 91 | On windows use the CMAKE gui with the buttons Configure and Generate. 92 | 93 | Compile and run the executable, e.g.: 94 | ``` 95 | make && ./assignment1 96 | ``` 97 | Or use your favorite IDE. 98 | 99 | If you encounter any problems, please create an issue on the assignments repository on GitHub or ask the assistant in the exercise session. 100 | 101 | ### Workflow 102 | In general, you should use Git to commit your edits as often as possible. This will help you with backtracking bugs and also serve as a backup mechanism. For more information we refer you to the [Pro Git book](https://git-scm.com/book/en/v2/Git-Basics-Recording-Changes-to-the-Repository). 103 | 104 | Every new assignment needs to be pulled from the base repository: 105 | ``` 106 | git pull base master 107 | ``` 108 | 109 | To pull bug fixes or changes you can do the following steps: 110 | ``` 111 | git pull base master 112 | rm -r libigl 113 | git submodule sync 114 | git submodule update --init --recursive 115 | ``` 116 | 117 | Your code should be able to compile and run on our computers as well. Please do not change any of the build files, and only add code for the supplied source files. We generally specify the exact areas for you to add your assignment code. 118 | 119 | ### Solution Submission 120 | In every assignment directory you will find a 'README.md' file in which we will specify the required screenshots and console outputs. You should briefly summarize and report your results and observations, or discuss possible problems. For a quick introduction of the Markdown syntax see: https://guides.github.com/features/mastering-markdown/ 121 | 122 | To submit your final solution of the assignment please add the following commit message: "Solution assignment X". E.g: 123 | ``` 124 | git commit -m "Solution assignment X" 125 | git push 126 | ``` 127 | 128 | **The solutions must be submitted before the corresponding demo session. Late submissions will not be accepted.** -------------------------------------------------------------------------------- /assignment1/.gitignore: -------------------------------------------------------------------------------- 1 | build/assignment1_bin 2 | build/cmake_install.cmake 3 | build/CMakeCache.txt 4 | build/Makefile 5 | build/CMakeFiles/cmake.check_cache 6 | build/CMakeFiles/CMakeDirectoryInformation.cmake 7 | build/CMakeFiles/CMakeOutput.log 8 | build/CMakeFiles/CMakeRuleHashes.txt 9 | build/CMakeFiles/feature_tests.bin 10 | build/CMakeFiles/feature_tests.c 11 | build/CMakeFiles/feature_tests.cxx 12 | build/CMakeFiles/Makefile.cmake 13 | build/CMakeFiles/Makefile2 14 | build/CMakeFiles/progress.marks 15 | build/CMakeFiles/TargetDirectories.txt 16 | build/CMakeFiles/3.7.2/CMakeCCompiler.cmake 17 | build/CMakeFiles/3.7.2/CMakeCXXCompiler.cmake 18 | build/CMakeFiles/3.7.2/CMakeDetermineCompilerABI_C.bin 19 | build/CMakeFiles/3.7.2/CMakeDetermineCompilerABI_CXX.bin 20 | build/CMakeFiles/3.7.2/CMakeSystem.cmake 21 | build/CMakeFiles/3.7.2/CompilerIdC/a.out 22 | build/CMakeFiles/3.7.2/CompilerIdC/CMakeCCompilerId.c 23 | build/CMakeFiles/3.7.2/CompilerIdCXX/a.out 24 | build/CMakeFiles/3.7.2/CompilerIdCXX/CMakeCXXCompilerId.cpp 25 | build/CMakeFiles/assignment1_bin.dir/build.make 26 | build/CMakeFiles/assignment1_bin.dir/cmake_clean.cmake 27 | build/CMakeFiles/assignment1_bin.dir/CXX.includecache 28 | build/CMakeFiles/assignment1_bin.dir/depend.internal 29 | build/CMakeFiles/assignment1_bin.dir/depend.make 30 | build/CMakeFiles/assignment1_bin.dir/DependInfo.cmake 31 | build/CMakeFiles/assignment1_bin.dir/flags.make 32 | build/CMakeFiles/assignment1_bin.dir/link.txt 33 | build/CMakeFiles/assignment1_bin.dir/progress.make 34 | build/CMakeFiles/assignment1_bin.dir/src/main.cpp.o 35 | build/libigl/cmake_install.cmake 36 | build/libigl/Makefile 37 | build/libigl/CMakeFiles/CMakeDirectoryInformation.cmake 38 | build/libigl/CMakeFiles/progress.marks 39 | build/libigl/glfw/cmake_install.cmake 40 | build/libigl/glfw/cmake_uninstall.cmake 41 | build/libigl/glfw/Makefile 42 | build/libigl/glfw/CMakeFiles/CMakeDirectoryInformation.cmake 43 | build/libigl/glfw/CMakeFiles/progress.marks 44 | build/libigl/glfw/CMakeFiles/Export/lib/cmake/glfw3/glfw3Targets-release.cmake 45 | build/libigl/glfw/CMakeFiles/Export/lib/cmake/glfw3/glfw3Targets.cmake 46 | build/libigl/glfw/CMakeFiles/uninstall.dir/build.make 47 | build/libigl/glfw/CMakeFiles/uninstall.dir/cmake_clean.cmake 48 | build/libigl/glfw/CMakeFiles/uninstall.dir/DependInfo.cmake 49 | build/libigl/glfw/CMakeFiles/uninstall.dir/progress.make 50 | build/libigl/glfw/src/cmake_install.cmake 51 | build/libigl/glfw/src/glfw3.pc 52 | build/libigl/glfw/src/glfw3Config.cmake 53 | build/libigl/glfw/src/glfw3ConfigVersion.cmake 54 | build/libigl/glfw/src/glfw_config.h 55 | build/libigl/glfw/src/libglfw3.a 56 | build/libigl/glfw/src/Makefile 57 | build/libigl/glfw/src/CMakeFiles/CMakeDirectoryInformation.cmake 58 | build/libigl/glfw/src/CMakeFiles/progress.marks 59 | build/libigl/glfw/src/CMakeFiles/glfw.dir/build.make 60 | build/libigl/glfw/src/CMakeFiles/glfw.dir/cmake_clean.cmake 61 | build/libigl/glfw/src/CMakeFiles/glfw.dir/cmake_clean_target.cmake 62 | build/libigl/glfw/src/CMakeFiles/glfw.dir/depend.internal 63 | build/libigl/glfw/src/CMakeFiles/glfw.dir/depend.make 64 | build/libigl/glfw/src/CMakeFiles/glfw.dir/DependInfo.cmake 65 | build/libigl/glfw/src/CMakeFiles/glfw.dir/flags.make 66 | build/libigl/glfw/src/CMakeFiles/glfw.dir/link.txt 67 | build/libigl/glfw/src/CMakeFiles/glfw.dir/progress.make 68 | build/libigl/glfw/src/CMakeFiles/glfw_objects.dir/build.make 69 | build/libigl/glfw/src/CMakeFiles/glfw_objects.dir/C.includecache 70 | build/libigl/glfw/src/CMakeFiles/glfw_objects.dir/cmake_clean.cmake 71 | build/libigl/glfw/src/CMakeFiles/glfw_objects.dir/cocoa_init.m.o 72 | build/libigl/glfw/src/CMakeFiles/glfw_objects.dir/cocoa_joystick.m.o 73 | build/libigl/glfw/src/CMakeFiles/glfw_objects.dir/cocoa_monitor.m.o 74 | build/libigl/glfw/src/CMakeFiles/glfw_objects.dir/cocoa_time.c.o 75 | build/libigl/glfw/src/CMakeFiles/glfw_objects.dir/cocoa_window.m.o 76 | build/libigl/glfw/src/CMakeFiles/glfw_objects.dir/context.c.o 77 | build/libigl/glfw/src/CMakeFiles/glfw_objects.dir/depend.internal 78 | build/libigl/glfw/src/CMakeFiles/glfw_objects.dir/depend.make 79 | build/libigl/glfw/src/CMakeFiles/glfw_objects.dir/DependInfo.cmake 80 | build/libigl/glfw/src/CMakeFiles/glfw_objects.dir/flags.make 81 | build/libigl/glfw/src/CMakeFiles/glfw_objects.dir/init.c.o 82 | build/libigl/glfw/src/CMakeFiles/glfw_objects.dir/input.c.o 83 | build/libigl/glfw/src/CMakeFiles/glfw_objects.dir/monitor.c.o 84 | build/libigl/glfw/src/CMakeFiles/glfw_objects.dir/nsgl_context.m.o 85 | build/libigl/glfw/src/CMakeFiles/glfw_objects.dir/posix_tls.c.o 86 | build/libigl/glfw/src/CMakeFiles/glfw_objects.dir/progress.make 87 | build/libigl/glfw/src/CMakeFiles/glfw_objects.dir/vulkan.c.o 88 | build/libigl/glfw/src/CMakeFiles/glfw_objects.dir/window.c.o 89 | -------------------------------------------------------------------------------- /assignment1/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.6) 2 | project(assignment1) 3 | 4 | set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/cmake) 5 | 6 | find_package(LIBIGL QUIET) 7 | 8 | if (NOT LIBIGL_FOUND) 9 | message(FATAL_ERROR "libigl not found --- You can download it using: \n git clone --recursive https://github.com/libigl/libigl.git ${PROJECT_SOURCE_DIR}/../libigl") 10 | endif() 11 | 12 | # Compilation flags: adapt to your needs 13 | if(MSVC) 14 | # Enable parallel compilation 15 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MP /bigobj") 16 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG ${CMAKE_BINARY_DIR} ) 17 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE ${CMAKE_BINARY_DIR} ) 18 | else() 19 | # Libigl requires a modern C++ compiler that supports c++11 20 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") 21 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "." ) 22 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-deprecated-declarations") 23 | endif() 24 | 25 | # libigl options: choose between header only and compiled static library 26 | # Header-only is preferred for small projects. For larger projects the static build 27 | # considerably reduces the compilation times 28 | option(LIBIGL_USE_STATIC_LIBRARY "Use LibIGL as static library" OFF) 29 | 30 | # add a customizable menu bar 31 | option(LIBIGL_VIEWER_WITH_NANOGUI "Use Nanogui menu" ON) 32 | option(LIBIGL_VIEWER_WITH_NANOGUI_IO "Add mesh IO menu" ON) 33 | option(LIBIGL_VIEWER_WITH_NANOGUI_SERIALIZATION "Enable viewer serialization" ON) 34 | 35 | # libigl options: choose your dependencies (by default everything is OFF except opengl) 36 | option(LIBIGL_WITH_VIEWER "Use OpenGL viewer" ON) 37 | option(LIBIGL_WITH_OPENGL "Use OpenGL" ON) 38 | option(LIBIGL_WITH_OPENGL_GLFW "Use GLFW" ON) 39 | option(LIBIGL_WITH_BBW "Use BBW" OFF) 40 | option(LIBIGL_WITH_EMBREE "Use Embree" OFF) 41 | option(LIBIGL_WITH_PNG "Use PNG" OFF) 42 | option(LIBIGL_WITH_TETGEN "Use Tetgen" OFF) 43 | option(LIBIGL_WITH_TRIANGLE "Use Triangle" OFF) 44 | option(LIBIGL_WITH_XML "Use XML" OFF) 45 | option(LIBIGL_WITH_LIM "Use LIM" OFF) 46 | option(LIBIGL_WITH_COMISO "Use CoMiso" OFF) 47 | option(LIBIGL_WITH_MATLAB "Use Matlab" OFF) # This option is not supported yet 48 | option(LIBIGL_WITH_MOSEK "Use MOSEK" OFF) # This option is not supported yet 49 | option(LIBIGL_WITH_CGAL "Use CGAL" OFF) 50 | if(LIBIGL_WITH_CGAL) # Do not remove or move this block, the cgal build system fails without it 51 | find_package(CGAL REQUIRED) 52 | set(CGAL_DONT_OVERRIDE_CMAKE_FLAGS TRUE CACHE BOOL "CGAL's CMAKE Setup is super annoying ") 53 | include(${CGAL_USE_FILE}) 54 | endif() 55 | 56 | # Adding libigl: choose the path to your local copy libigl 57 | # This is going to compile everything you requested 58 | #message(FATAL_ERROR "${PROJECT_SOURCE_DIR}/../libigl/cmake") 59 | add_subdirectory("${LIBIGL_INCLUDE_DIR}/../shared/cmake" "libigl") 60 | 61 | # libigl information 62 | message("libigl includes: ${LIBIGL_INCLUDE_DIRS}") 63 | message("libigl libraries: ${LIBIGL_LIBRARIES}") 64 | message("libigl extra sources: ${LIBIGL_EXTRA_SOURCES}") 65 | message("libigl extra libraries: ${LIBIGL_EXTRA_LIBRARIES}") 66 | message("libigl definitions: ${LIBIGL_DEFINITIONS}") 67 | 68 | # Prepare the build environment 69 | include_directories(${LIBIGL_INCLUDE_DIRS}) 70 | add_definitions(${LIBIGL_DEFINITIONS}) 71 | 72 | # Add your project files 73 | # Note: we need some stubs for building to succeed on TravisCI. 74 | if (TRAVISCI_BUILD) 75 | FILE(GLOB SOURCES src/*.cpp src_travisci/*.cpp) 76 | else (TRAVISCI_BUILD) 77 | FILE(GLOB SOURCES src/*.cpp) 78 | endif (TRAVISCI_BUILD) 79 | 80 | add_executable(${PROJECT_NAME}_bin ${SOURCES} ${LIBIGL_EXTRA_SOURCES}) 81 | target_link_libraries(${PROJECT_NAME}_bin ${LIBIGL_LIBRARIES} ${LIBIGL_EXTRA_LIBRARIES}) 82 | -------------------------------------------------------------------------------- /assignment1/README.md: -------------------------------------------------------------------------------- 1 | # Assignment 1 2 | 3 | Edit this 'README.md' file to report all your results. There is no need to write lengthy reports, just show the requested outputs and screenshots and quickly summarize your observations. 4 | 5 | ## Required results 6 | 7 | ### Tasks 8 | 1) Add a text dump of the content of the two data structures for the provided mesh “plane.off”. 9 | 10 | 2) Show screenshots of the provided meshes with each connected component colored differently. Show the number of connected components and the size of each component (measured in number 11 | of faces) for all the provided models. 12 | 13 | 3) Show screenshots of the subdivided meshes. 14 | 15 | 4) Show screenshots of face extrusion. 16 | 17 | 5) Show a screenshot of a mesh you designed yourself starting from 'cube.off' and using the GUI supplied editing operations, as well as sqrt3 subdivision and face extrusion. Make sure to also save the mesh under the name 'design.off', commit and push it. -------------------------------------------------------------------------------- /assignment1/assignment1.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eth-igl/GP2018-Assignments/895e5e30625089deccfc469c662bdc6093e9e314/assignment1/assignment1.pdf -------------------------------------------------------------------------------- /assignment1/cmake/FindLIBIGL.cmake: -------------------------------------------------------------------------------- 1 | # - Try to find the LIBIGL library 2 | # Once done this will define 3 | # 4 | # LIBIGL_FOUND - system has LIBIGL 5 | # LIBIGL_INCLUDE_DIR - **the** LIBIGL include directory 6 | # LIBIGL_INCLUDE_DIRS - LIBIGL include directories 7 | # LIBIGL_SOURCES - the LIBIGL source files 8 | if(NOT LIBIGL_FOUND) 9 | 10 | FIND_PATH(LIBIGL_INCLUDE_DIR igl/readOBJ.h 11 | ${PROJECT_SOURCE_DIR}/../../include 12 | ${PROJECT_SOURCE_DIR}/../include 13 | ${PROJECT_SOURCE_DIR}/include 14 | ${PROJECT_SOURCE_DIR}/../libigl/include 15 | ${PROJECT_SOURCE_DIR}/../../libigl/include 16 | $ENV{LIBIGL}/include 17 | $ENV{LIBIGLROOT}/include 18 | $ENV{LIBIGL_ROOT}/include 19 | $ENV{LIBIGL_DIR}/include 20 | $ENV{LIBIGL_DIR}/inc 21 | /usr/include 22 | /usr/local/include 23 | /usr/local/igl/libigl/include 24 | ) 25 | 26 | 27 | if(LIBIGL_INCLUDE_DIR) 28 | set(LIBIGL_FOUND TRUE) 29 | set(LIBIGL_INCLUDE_DIRS ${LIBIGL_INCLUDE_DIR}) 30 | #set(LIBIGL_SOURCES 31 | # ${LIBIGL_INCLUDE_DIR}/igl/viewer/Viewer.cpp 32 | #) 33 | endif() 34 | 35 | endif() 36 | -------------------------------------------------------------------------------- /assignment1/data/cube.off: -------------------------------------------------------------------------------- 1 | OFF 2 | 8 12 0 3 | 1 -1 -1 4 | 1 -1 1 5 | -1 -1 1 6 | -1 -1 -1 7 | 1 1 -0.999999 8 | 0.999999 1 1.000001 9 | -1 1 1 10 | -1 1 -1 11 | 3 0 1 2 12 | 3 0 2 3 13 | 3 4 7 6 14 | 3 4 6 5 15 | 3 0 4 5 16 | 3 0 5 1 17 | 3 1 5 6 18 | 3 1 6 2 19 | 3 2 6 7 20 | 3 2 7 3 21 | 3 4 0 3 22 | 3 4 3 7 23 | -------------------------------------------------------------------------------- /assignment1/src/gui_utils.cpp: -------------------------------------------------------------------------------- 1 | #include "gui_utils.h" 2 | 3 | int pick_face(igl::viewer::Viewer& viewer, int mouse_x, int mouse_y, const Eigen::MatrixXd& V, const Eigen::MatrixXi& F) { 4 | // Cast a ray in the view direction starting from the mouse position 5 | double x = mouse_x; 6 | double y = viewer.core.viewport(3) - mouse_y; 7 | 8 | Eigen::RowVector3d pt; 9 | 10 | Eigen::Matrix4f modelview = viewer.core.view * viewer.data.model; 11 | int vi = -1; 12 | 13 | std::vector hits; 14 | 15 | igl::unproject_in_mesh(Eigen::Vector2f(x,y), viewer.core.view * viewer.data.model, 16 | viewer.core.proj, viewer.core.viewport, V, F, pt,hits); 17 | 18 | int fi = -1; 19 | if (hits.size()> 0) { 20 | fi = hits[0].id; 21 | } 22 | return fi; 23 | } 24 | 25 | int pick_vertex(igl::viewer::Viewer& viewer, int mouse_x, int mouse_y, const Eigen::MatrixXd& V, const Eigen::MatrixXi& F) { 26 | // Cast a ray in the view direction starting from the mouse position 27 | double x = mouse_x; 28 | double y = viewer.core.viewport(3) - mouse_y; 29 | 30 | Eigen::RowVector3d pt; 31 | 32 | Eigen::Matrix4f modelview = viewer.core.view * viewer.data.model; 33 | int vi = -1; 34 | 35 | std::vector hits; 36 | /* 37 | igl::unproject_in_mesh(Eigen::Vector2f(x,y), 38 | modelview, 39 | viewer.core.proj, 40 | viewer.core.viewport, 41 | ei,pt,hits); 42 | */ 43 | 44 | igl::unproject_in_mesh(Eigen::Vector2f(x,y), viewer.core.view * viewer.data.model, 45 | viewer.core.proj, viewer.core.viewport, V, F, pt,hits); 46 | 47 | if (hits.size()> 0) { 48 | int fi = hits[0].id; 49 | Eigen::RowVector3d bc; 50 | bc << 1.0-hits[0].u-hits[0].v, hits[0].u, hits[0].v; 51 | bc.maxCoeff(&vi); 52 | vi = F(fi,vi); 53 | } 54 | return vi; 55 | } 56 | 57 | //computes translation for the vertices of the moving handle based on the mouse motion 58 | Eigen::Vector3f computeTranslation (igl::viewer::Viewer& viewer, 59 | int mouse_x, 60 | int from_x, 61 | int mouse_y, 62 | int from_y, 63 | Eigen::RowVector3d pt3D) { 64 | Eigen::Matrix4f modelview = viewer.core.view * viewer.data.model; 65 | //project the given point (typically the handle centroid) to get a screen space depth 66 | Eigen::Vector3f proj = igl::project(pt3D.transpose().cast().eval(), 67 | modelview, 68 | viewer.core.proj, 69 | viewer.core.viewport); 70 | float depth = proj[2]; 71 | 72 | double x, y; 73 | Eigen::Vector3f pos1, pos0; 74 | 75 | //unproject from- and to- points 76 | x = mouse_x; 77 | y = viewer.core.viewport(3) - mouse_y; 78 | pos1 = igl::unproject(Eigen::Vector3f(x,y,depth), 79 | modelview, 80 | viewer.core.proj, 81 | viewer.core.viewport); 82 | 83 | 84 | x = from_x; 85 | y = viewer.core.viewport(3) - from_y; 86 | pos0 = igl::unproject(Eigen::Vector3f(x,y,depth), 87 | modelview, 88 | viewer.core.proj, 89 | viewer.core.viewport); 90 | 91 | //translation is the vector connecting the two 92 | Eigen::Vector3f translation; 93 | translation = pos1 - pos0; 94 | 95 | return translation; 96 | } 97 | 98 | Eigen::Vector4f computeRotation(igl::viewer::Viewer& viewer, 99 | int mouse_x, 100 | int from_x, 101 | int mouse_y, 102 | int from_y, 103 | Eigen::RowVector3d pt3D) { 104 | 105 | Eigen::Vector4f rotation; 106 | rotation.setZero(); 107 | rotation[3] = 1.; 108 | 109 | Eigen::Matrix4f modelview = viewer.core.view * viewer.data.model; 110 | 111 | //initialize a trackball around the handle that is being rotated 112 | //the trackball has (approximately) width w and height h 113 | double w = viewer.core.viewport[2]/8; 114 | double h = viewer.core.viewport[3]/8; 115 | 116 | //the mouse motion has to be expressed with respect to its center of mass 117 | //(i.e. it should approximately fall inside the region of the trackball) 118 | 119 | //project the given point on the handle(centroid) 120 | Eigen::Vector3f proj = igl::project(pt3D.transpose().cast().eval(), 121 | modelview, 122 | viewer.core.proj, 123 | viewer.core.viewport); 124 | proj[1] = viewer.core.viewport[3] - proj[1]; 125 | 126 | //express the mouse points w.r.t the centroid 127 | from_x -= proj[0]; mouse_x -= proj[0]; 128 | from_y -= proj[1]; mouse_y -= proj[1]; 129 | 130 | //shift so that the range is from 0-w and 0-h respectively (similarly to a standard viewport) 131 | from_x += w/2; mouse_x += w/2; 132 | from_y += h/2; mouse_y += h/2; 133 | 134 | //get rotation from trackball 135 | Eigen::Vector4f drot = viewer.core.trackball_angle.coeffs(); 136 | Eigen::Vector4f drot_conj; 137 | igl::quat_conjugate(drot.data(), drot_conj.data()); 138 | igl::trackball(w, h, float(1.), rotation.data(), from_x, from_y, mouse_x, mouse_y, rotation.data()); 139 | 140 | //account for the modelview rotation: prerotate by modelview (place model back to the original 141 | //unrotated frame), postrotate by inverse modelview 142 | Eigen::Vector4f out; 143 | igl::quat_mult(rotation.data(), drot.data(), out.data()); 144 | igl::quat_mult(drot_conj.data(), out.data(), rotation.data()); 145 | return rotation; 146 | } -------------------------------------------------------------------------------- /assignment1/src/gui_utils.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | 9 | int pick_face(igl::viewer::Viewer& viewer, int mouse_x, int mouse_y, const Eigen::MatrixXd& V, const Eigen::MatrixXi& F); 10 | int pick_vertex(igl::viewer::Viewer& viewer, int mouse_x, int mouse_y, const Eigen::MatrixXd& V, const Eigen::MatrixXi& F); 11 | Eigen::Vector3f computeTranslation(igl::viewer::Viewer& viewer,int mouse_x,int from_x,int mouse_y,int from_y,Eigen::RowVector3d pt3D); 12 | Eigen::Vector4f computeRotation(igl::viewer::Viewer& viewer, int mouse_x, int from_x, int mouse_y, int from_y, Eigen::RowVector3d pt3D); 13 | 14 | void update_display(igl::viewer::Viewer& viewer,const Eigen::MatrixXd& V, const Eigen::MatrixXi& F); -------------------------------------------------------------------------------- /assignment2/.gitignore: -------------------------------------------------------------------------------- 1 | build 2 | -------------------------------------------------------------------------------- /assignment2/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.6) 2 | project(assignment2) 3 | 4 | set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/cmake) 5 | 6 | find_package(LIBIGL QUIET) 7 | 8 | if (NOT LIBIGL_FOUND) 9 | message(FATAL_ERROR "libigl not found --- You can download it using: \n git clone --recursive https://github.com/libigl/libigl.git ${PROJECT_SOURCE_DIR}/../libigl") 10 | endif() 11 | 12 | # Compilation flags: adapt to your needs 13 | if(MSVC) 14 | # Enable parallel compilation 15 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MP /bigobj") 16 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG ${CMAKE_BINARY_DIR} ) 17 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE ${CMAKE_BINARY_DIR} ) 18 | else() 19 | # Libigl requires a modern C++ compiler that supports c++11 20 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") 21 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "." ) 22 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-deprecated-declarations") 23 | endif() 24 | 25 | # libigl options: choose between header only and compiled static library 26 | # Header-only is preferred for small projects. For larger projects the static build 27 | # considerably reduces the compilation times 28 | option(LIBIGL_USE_STATIC_LIBRARY "Use LibIGL as static library" OFF) 29 | 30 | # add a customizable menu bar 31 | option(LIBIGL_VIEWER_WITH_NANOGUI "Use Nanogui menu" ON) 32 | option(LIBIGL_VIEWER_WITH_NANOGUI_IO "Add mesh IO menu" ON) 33 | option(LIBIGL_VIEWER_WITH_NANOGUI_SERIALIZATION "Enable viewer serialization" ON) 34 | 35 | # libigl options: choose your dependencies (by default everything is OFF except opengl) 36 | option(LIBIGL_WITH_VIEWER "Use OpenGL viewer" ON) 37 | option(LIBIGL_WITH_OPENGL "Use OpenGL" ON) 38 | option(LIBIGL_WITH_OPENGL_GLFW "Use GLFW" ON) 39 | option(LIBIGL_WITH_BBW "Use BBW" OFF) 40 | option(LIBIGL_WITH_EMBREE "Use Embree" OFF) 41 | option(LIBIGL_WITH_PNG "Use PNG" OFF) 42 | option(LIBIGL_WITH_TETGEN "Use Tetgen" OFF) 43 | option(LIBIGL_WITH_TRIANGLE "Use Triangle" OFF) 44 | option(LIBIGL_WITH_XML "Use XML" OFF) 45 | option(LIBIGL_WITH_LIM "Use LIM" OFF) 46 | option(LIBIGL_WITH_COMISO "Use CoMiso" OFF) 47 | option(LIBIGL_WITH_MATLAB "Use Matlab" OFF) # This option is not supported yet 48 | option(LIBIGL_WITH_MOSEK "Use MOSEK" OFF) # This option is not supported yet 49 | option(LIBIGL_WITH_CGAL "Use CGAL" OFF) 50 | if(LIBIGL_WITH_CGAL) # Do not remove or move this block, the cgal build system fails without it 51 | find_package(CGAL REQUIRED) 52 | set(CGAL_DONT_OVERRIDE_CMAKE_FLAGS TRUE CACHE BOOL "CGAL's CMAKE Setup is super annoying ") 53 | include(${CGAL_USE_FILE}) 54 | endif() 55 | 56 | # Adding libigl: choose the path to your local copy libigl 57 | # This is going to compile everything you requested 58 | #message(FATAL_ERROR "${PROJECT_SOURCE_DIR}/../libigl/cmake") 59 | add_subdirectory("${LIBIGL_INCLUDE_DIR}/../shared/cmake" "libigl") 60 | 61 | # libigl information 62 | message("libigl includes: ${LIBIGL_INCLUDE_DIRS}") 63 | message("libigl libraries: ${LIBIGL_LIBRARIES}") 64 | message("libigl extra sources: ${LIBIGL_EXTRA_SOURCES}") 65 | message("libigl extra libraries: ${LIBIGL_EXTRA_LIBRARIES}") 66 | message("libigl definitions: ${LIBIGL_DEFINITIONS}") 67 | 68 | # Prepare the build environment 69 | include_directories(${LIBIGL_INCLUDE_DIRS}) 70 | add_definitions(${LIBIGL_DEFINITIONS}) 71 | 72 | # Add your project files 73 | # Note: we need some stubs for building to succeed on TravisCI. 74 | if (TRAVISCI_BUILD) 75 | FILE(GLOB SOURCES src/*.cpp src_travisci/*.cpp) 76 | else (TRAVISCI_BUILD) 77 | FILE(GLOB SOURCES src/*.cpp) 78 | endif (TRAVISCI_BUILD) 79 | 80 | add_executable(${PROJECT_NAME}_bin ${SOURCES} ${LIBIGL_EXTRA_SOURCES}) 81 | target_link_libraries(${PROJECT_NAME}_bin ${LIBIGL_LIBRARIES} ${LIBIGL_EXTRA_LIBRARIES}) 82 | -------------------------------------------------------------------------------- /assignment2/README.md: -------------------------------------------------------------------------------- 1 | # Assignment 2 2 | 3 | Edit this 'README.md' file to report all your results. There is no need to write lengthy reports, just show the requested outputs and screenshots and quickly summarize your observations. Please add your additional files or notes in the folder 'assignment2/results' and refer to or directly show them in this page. 4 | 5 | ## Required results 6 | 7 | ### Mandatory Tasks 8 | 1) Show the visualization of the constrained points for the 'cat.off' point cloud. 9 | 10 | 2) Show screenshots of the grid with nodes colored according to their implicit function values (cat.off and luigi.off). 11 | 12 | 3) Show screenshots of the reconstructed surfaces. Experiment with different parameter settings: grid resolution (also anisotropic in the 3 axes), Wendland function radius, polynomial degree. Add all these settings to the GUI to ease experimentation. Briefly summarize your observations and save the reconstructed models in the off format for every point-cloud dataset provided (assignment2/results). 13 | 14 | 4) Theory question: Save your notes to assignment2/results and add a link to this page. 15 | 16 | ### Optional Tasks 17 | 18 | 1) Save your notes and add a link to this page. 19 | 20 | 2) Show screenshots comparing the 'hound.off' of the normal based reconstruction to the point based reconstruction of the mandatory task. 21 | 22 | 3) Compare your MLS reconstruction results to the surfaces obtained with this method, and try to understand the differences. Report your findings. 23 | -------------------------------------------------------------------------------- /assignment2/assignment2.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eth-igl/GP2018-Assignments/895e5e30625089deccfc469c662bdc6093e9e314/assignment2/assignment2.pdf -------------------------------------------------------------------------------- /assignment2/cmake/FindLIBIGL.cmake: -------------------------------------------------------------------------------- 1 | # - Try to find the LIBIGL library 2 | # Once done this will define 3 | # 4 | # LIBIGL_FOUND - system has LIBIGL 5 | # LIBIGL_INCLUDE_DIR - **the** LIBIGL include directory 6 | # LIBIGL_INCLUDE_DIRS - LIBIGL include directories 7 | # LIBIGL_SOURCES - the LIBIGL source files 8 | if(NOT LIBIGL_FOUND) 9 | 10 | FIND_PATH(LIBIGL_INCLUDE_DIR igl/readOBJ.h 11 | ${PROJECT_SOURCE_DIR}/../../include 12 | ${PROJECT_SOURCE_DIR}/../include 13 | ${PROJECT_SOURCE_DIR}/include 14 | ${PROJECT_SOURCE_DIR}/../libigl/include 15 | ${PROJECT_SOURCE_DIR}/../../libigl/include 16 | $ENV{LIBIGL}/include 17 | $ENV{LIBIGLROOT}/include 18 | $ENV{LIBIGL_ROOT}/include 19 | $ENV{LIBIGL_DIR}/include 20 | $ENV{LIBIGL_DIR}/inc 21 | /usr/include 22 | /usr/local/include 23 | /usr/local/igl/libigl/include 24 | ) 25 | 26 | 27 | if(LIBIGL_INCLUDE_DIR) 28 | set(LIBIGL_FOUND TRUE) 29 | set(LIBIGL_INCLUDE_DIRS ${LIBIGL_INCLUDE_DIR}) 30 | #set(LIBIGL_SOURCES 31 | # ${LIBIGL_INCLUDE_DIR}/igl/viewer/Viewer.cpp 32 | #) 33 | endif() 34 | 35 | endif() 36 | -------------------------------------------------------------------------------- /assignment3/.gitignore: -------------------------------------------------------------------------------- 1 | build 2 | -------------------------------------------------------------------------------- /assignment3/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.6) 2 | project(assignment3) 3 | 4 | set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/cmake) 5 | 6 | find_package(LIBIGL QUIET) 7 | 8 | if (NOT LIBIGL_FOUND) 9 | message(FATAL_ERROR "libigl not found --- You can download it using: \n git clone --recursive https://github.com/libigl/libigl.git ${PROJECT_SOURCE_DIR}/../libigl") 10 | endif() 11 | 12 | # Compilation flags: adapt to your needs 13 | if(MSVC) 14 | # Enable parallel compilation 15 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MP /bigobj") 16 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG ${CMAKE_BINARY_DIR} ) 17 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE ${CMAKE_BINARY_DIR} ) 18 | else() 19 | # Libigl requires a modern C++ compiler that supports c++11 20 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") 21 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "." ) 22 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-deprecated-declarations") 23 | endif() 24 | 25 | # libigl options: choose between header only and compiled static library 26 | # Header-only is preferred for small projects. For larger projects the static build 27 | # considerably reduces the compilation times 28 | option(LIBIGL_USE_STATIC_LIBRARY "Use LibIGL as static library" OFF) 29 | 30 | # add a customizable menu bar 31 | option(LIBIGL_VIEWER_WITH_NANOGUI "Use Nanogui menu" ON) 32 | option(LIBIGL_VIEWER_WITH_NANOGUI_IO "Add mesh IO menu" ON) 33 | option(LIBIGL_VIEWER_WITH_NANOGUI_SERIALIZATION "Enable viewer serialization" ON) 34 | 35 | # libigl options: choose your dependencies (by default everything is OFF except opengl) 36 | option(LIBIGL_WITH_VIEWER "Use OpenGL viewer" ON) 37 | option(LIBIGL_WITH_OPENGL "Use OpenGL" ON) 38 | option(LIBIGL_WITH_OPENGL_GLFW "Use GLFW" ON) 39 | option(LIBIGL_WITH_BBW "Use BBW" OFF) 40 | option(LIBIGL_WITH_EMBREE "Use Embree" OFF) 41 | option(LIBIGL_WITH_PNG "Use PNG" OFF) 42 | option(LIBIGL_WITH_TETGEN "Use Tetgen" OFF) 43 | option(LIBIGL_WITH_TRIANGLE "Use Triangle" OFF) 44 | option(LIBIGL_WITH_XML "Use XML" OFF) 45 | option(LIBIGL_WITH_LIM "Use LIM" OFF) 46 | option(LIBIGL_WITH_COMISO "Use CoMiso" OFF) 47 | option(LIBIGL_WITH_MATLAB "Use Matlab" OFF) # This option is not supported yet 48 | option(LIBIGL_WITH_MOSEK "Use MOSEK" OFF) # This option is not supported yet 49 | option(LIBIGL_WITH_CGAL "Use CGAL" OFF) 50 | if(LIBIGL_WITH_CGAL) # Do not remove or move this block, the cgal build system fails without it 51 | find_package(CGAL REQUIRED) 52 | set(CGAL_DONT_OVERRIDE_CMAKE_FLAGS TRUE CACHE BOOL "CGAL's CMAKE Setup is super annoying ") 53 | include(${CGAL_USE_FILE}) 54 | endif() 55 | 56 | # Adding libigl: choose the path to your local copy libigl 57 | # This is going to compile everything you requested 58 | #message(FATAL_ERROR "${PROJECT_SOURCE_DIR}/../libigl/cmake") 59 | add_subdirectory("${LIBIGL_INCLUDE_DIR}/../shared/cmake" "libigl") 60 | 61 | # libigl information 62 | message("libigl includes: ${LIBIGL_INCLUDE_DIRS}") 63 | message("libigl libraries: ${LIBIGL_LIBRARIES}") 64 | message("libigl extra sources: ${LIBIGL_EXTRA_SOURCES}") 65 | message("libigl extra libraries: ${LIBIGL_EXTRA_LIBRARIES}") 66 | message("libigl definitions: ${LIBIGL_DEFINITIONS}") 67 | 68 | # Prepare the build environment 69 | include_directories(${LIBIGL_INCLUDE_DIRS}) 70 | add_definitions(${LIBIGL_DEFINITIONS}) 71 | 72 | # Add your project files 73 | # Note: we need some stubs for building to succeed on TravisCI. 74 | if (TRAVISCI_BUILD) 75 | FILE(GLOB SOURCES src/*.cpp src_travisci/*.cpp) 76 | else (TRAVISCI_BUILD) 77 | FILE(GLOB SOURCES src/*.cpp) 78 | endif (TRAVISCI_BUILD) 79 | 80 | add_executable(${PROJECT_NAME}_bin ${SOURCES} ${LIBIGL_EXTRA_SOURCES}) 81 | target_link_libraries(${PROJECT_NAME}_bin ${LIBIGL_LIBRARIES} ${LIBIGL_EXTRA_LIBRARIES}) 82 | -------------------------------------------------------------------------------- /assignment3/README.md: -------------------------------------------------------------------------------- 1 | # Assignment 4 2 | 3 | Edit this 'README.md' file to report all your results. There is no need to write lengthy reports, just show the requested outputs and screenshots and quickly summarize your observations. Please add your additional files or notes in the folder 'assignment4/results' and refer to or directly show them in this page. 4 | 5 | ## Required results 6 | 7 | * Screenshots of the parameterizations and textured (checkerboard) models for all the implemented methods and boundary conditions (models: cathead.obj, hemisphere.off, hemisphere_non_convex_boundary.off,Octo_cut2.obj) 8 | * Several examples of the distortion visualizations. 9 | -------------------------------------------------------------------------------- /assignment3/assignment3.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eth-igl/GP2018-Assignments/895e5e30625089deccfc469c662bdc6093e9e314/assignment3/assignment3.pdf -------------------------------------------------------------------------------- /assignment3/cmake/FindLIBIGL.cmake: -------------------------------------------------------------------------------- 1 | # - Try to find the LIBIGL library 2 | # Once done this will define 3 | # 4 | # LIBIGL_FOUND - system has LIBIGL 5 | # LIBIGL_INCLUDE_DIR - **the** LIBIGL include directory 6 | # LIBIGL_INCLUDE_DIRS - LIBIGL include directories 7 | # LIBIGL_SOURCES - the LIBIGL source files 8 | if(NOT LIBIGL_FOUND) 9 | 10 | FIND_PATH(LIBIGL_INCLUDE_DIR igl/readOBJ.h 11 | ${PROJECT_SOURCE_DIR}/../../include 12 | ${PROJECT_SOURCE_DIR}/../include 13 | ${PROJECT_SOURCE_DIR}/include 14 | ${PROJECT_SOURCE_DIR}/../libigl/include 15 | ${PROJECT_SOURCE_DIR}/../../libigl/include 16 | $ENV{LIBIGL}/include 17 | $ENV{LIBIGLROOT}/include 18 | $ENV{LIBIGL_ROOT}/include 19 | $ENV{LIBIGL_DIR}/include 20 | $ENV{LIBIGL_DIR}/inc 21 | /usr/include 22 | /usr/local/include 23 | /usr/local/igl/libigl/include 24 | ) 25 | 26 | 27 | if(LIBIGL_INCLUDE_DIR) 28 | set(LIBIGL_FOUND TRUE) 29 | set(LIBIGL_INCLUDE_DIRS ${LIBIGL_INCLUDE_DIR}) 30 | #set(LIBIGL_SOURCES 31 | # ${LIBIGL_INCLUDE_DIR}/igl/viewer/Viewer.cpp 32 | #) 33 | endif() 34 | 35 | endif() 36 | -------------------------------------------------------------------------------- /assignment3/data/cathead.obj: -------------------------------------------------------------------------------- 1 | v -0.206972 0.0740737 0.544664 2 | v -0.398695 -0.0740794 0.501089 3 | v -0.211327 -0.187367 0.588234 4 | v -0.511983 -0.235298 0.400872 5 | v -0.56863 0.0348535 0.405227 6 | v -0.35948 0.178646 0.50545 7 | v -0.525054 0.313721 0.387801 8 | v -0.189545 0.30065 0.544664 9 | v 0.124182 0.0740737 0.509805 10 | v -0.455336 -0.33987 0.544664 11 | v -0.411766 -0.427021 0.671024 12 | v -0.237476 -0.413949 0.745097 13 | v -0.250547 -0.535954 0.797389 14 | v -0.346403 -0.562097 0.758169 15 | v 0.0152491 -0.33116 0.531593 16 | v -0.106755 -0.496734 0.692812 17 | v -0.254903 -0.692812 0.749458 18 | v -0.0631798 -0.601311 0.55338 19 | v -0.14597 -0.666669 0.666669 20 | v -0.250547 -0.727671 0.583879 21 | v -0.198256 -0.714599 0.42266 22 | v 0.0283206 -0.514166 0.383445 23 | v -0.124182 -0.623099 0.196078 24 | v -0.285401 -0.692812 0.413944 25 | v -0.333331 -0.596956 0.226582 26 | v -0.333331 -0.418305 0.413944 27 | v 0.233115 -0.366019 0.313727 28 | v 0.215688 -0.156864 0.457519 29 | v -0.342048 -0.623099 -0.0915061 30 | v -0.708061 -0.431376 0.0697184 31 | v -0.647058 -0.501095 -0.0915061 32 | v -0.716777 -0.318088 0.169935 33 | v -0.699344 -0.143792 0.235292 34 | v -0.747275 0.00871052 0.235292 35 | v -0.747275 0.165574 0.191723 36 | v -0.764708 0.291939 0.12636 37 | v -0.747275 0.461874 0.0130715 38 | v -0.337692 0.535948 0.366013 39 | v -0.472768 0.644881 0.0653574 40 | v -0.272329 0.753814 0.0827899 41 | v -0.294117 0.797383 0.278868 42 | v -0.307188 0.801744 0.435731 43 | v -0.324621 0.779957 0.583879 44 | v -0.355119 0.714594 0.710238 45 | v -0.407405 0.59695 0.692812 46 | v -0.442264 0.505444 0.610022 47 | v -0.477123 0.413944 0.51416 48 | v -0.285401 0.509805 0.666669 49 | v -0.185184 0.605661 0.631809 50 | v -0.0326816 0.518516 0.479301 51 | v -0.198256 0.72331 0.575162 52 | v -0.124182 0.745097 0.278868 53 | v 0.189545 0.479301 0.357297 54 | v -0.0413921 0.675379 0.352942 55 | v -0.843136 -0.0392202 -0.0522859 56 | v -0.764708 -0.33116 0.0348592 57 | v -0.816994 -0.152508 -0.178651 58 | v -0.87364 -0.0522916 -0.187362 59 | v -0.816994 0.108933 -0.204794 60 | v -0.816994 0.25708 -0.00435526 61 | v -0.795206 0.387795 -0.0653574 62 | v -0.764708 0.440087 -0.152503 63 | v -0.642703 0.535948 -0.370368 64 | v -0.516338 0.636165 -0.21351 65 | v -0.856208 0.265791 -0.148147 66 | v -0.816994 0.261435 -0.291939 67 | v -0.847497 0.239648 -0.418299 68 | v -0.82571 0.265791 -0.479301 69 | v -0.912855 -0.0697184 -0.270152 70 | v -0.947714 0.0130715 -0.326799 71 | v -0.938998 0.0740737 -0.392156 72 | v -0.799567 -0.344231 -0.108933 73 | v -0.620916 -0.509805 -0.331154 74 | v -0.764708 -0.287584 -0.244009 75 | v -0.799567 -0.291939 -0.352942 76 | v -0.9085 -0.174296 -0.33987 77 | v -1 -0.0697184 -0.409588 78 | v -0.965141 -0.148153 -0.461874 79 | v -0.95643 -0.0610022 -0.549019 80 | v -0.978212 0.021782 -0.483662 81 | v -0.729848 -0.357302 -0.501089 82 | v -0.921571 -0.230937 -0.544664 83 | v -0.821354 -0.222227 -0.662308 84 | v -0.9085 -0.16558 -0.623093 85 | v -0.342048 -0.557736 -0.383445 86 | v -0.381262 -0.300656 -0.727671 87 | v -0.167757 -0.557736 -0.501089 88 | v -0.599128 -0.252725 -0.692812 89 | v -0.420482 -0.0697184 -0.797389 90 | v -0.14597 -0.610027 -0.631809 91 | v -0.947714 0.0915004 -0.522877 92 | v -0.891067 0.178646 -0.50545 93 | v -0.869279 -0.0697184 -0.705883 94 | v -0.934643 0.0348535 -0.627454 95 | v -0.847497 0.156858 -0.649236 96 | v -0.620916 0.235292 -0.701528 97 | v -0.559913 0.143786 -0.745097 98 | v -0.315905 0.278862 -0.753814 99 | v -0.0196101 0.440087 -0.784312 100 | v -0.211327 0.46623 -0.636165 101 | v -0.381262 0.505444 -0.579523 102 | v -0.647058 0.374724 -0.601305 103 | v -0.355119 0.653591 -0.344225 104 | v -0.0108939 0.644881 -0.313727 105 | v 0.163396 0.64052 0.104578 106 | v 0.433554 0.0697127 0.322443 107 | v 0.516344 -0.318088 0.0435754 108 | v 0.35948 -0.492378 -0.0653574 109 | v 0.185184 -0.535954 0.0305039 110 | v 0.0631798 -0.618738 -0.313727 111 | v 0.328976 -0.618738 -0.296295 112 | v 0.102394 -0.684101 -0.43137 113 | v 0.612199 -0.396517 -0.16558 114 | v 0.307188 0.522877 -0.779957 115 | v 0.163396 0.549019 -0.562091 116 | v 0.468413 0.400872 0.00871623 117 | v 0.599128 0.374724 -0.261435 118 | v 0.721132 0.357297 -0.50545 119 | v 0.843136 0.326793 -0.718955 120 | v 0.124182 -0.801744 -0.562091 121 | v 0.35948 -0.749458 -0.448803 122 | v 0.559913 0.0479307 0.161219 123 | v 0.673201 0.0304982 -0.0566469 124 | v 0.808283 0.0174267 -0.309366 125 | v 0.891067 -0.00871623 -0.483662 126 | v 1 -0.0697184 -0.753814 127 | v 0.355119 0.440087 0.191723 128 | v 0.694989 -0.58824 -0.440087 129 | v 0.886712 -0.230937 -0.457519 130 | v 0.912855 -0.366019 -0.575162 131 | v -0.921571 -0.126365 -0.300656 132 | f 1 2 3 133 | f 4 2 5 134 | f 2 1 5 135 | f 1 6 5 136 | f 6 7 5 137 | f 7 6 8 138 | f 6 1 8 139 | f 9 1 3 140 | f 3 4 10 141 | f 10 11 3 142 | f 11 12 3 143 | f 11 13 12 144 | f 13 11 14 145 | f 12 15 3 146 | f 15 12 16 147 | f 12 13 16 148 | f 13 17 16 149 | f 17 13 14 150 | f 16 18 15 151 | f 18 16 19 152 | f 16 17 19 153 | f 17 20 19 154 | f 20 21 19 155 | f 21 18 19 156 | f 18 21 22 157 | f 21 23 22 158 | f 21 24 23 159 | f 24 21 20 160 | f 24 25 23 161 | f 25 24 26 162 | f 24 20 26 163 | f 20 17 26 164 | f 17 14 26 165 | f 14 11 26 166 | f 11 10 26 167 | f 10 4 26 168 | f 3 15 9 169 | f 15 27 28 170 | f 23 25 29 171 | f 25 30 31 172 | f 30 25 32 173 | f 25 26 32 174 | f 4 33 32 175 | f 18 22 15 176 | f 22 27 15 177 | f 5 34 33 178 | f 34 5 35 179 | f 5 7 35 180 | f 7 36 35 181 | f 36 7 37 182 | f 7 38 37 183 | f 38 39 37 184 | f 39 38 40 185 | f 38 41 40 186 | f 41 38 42 187 | f 38 43 42 188 | f 43 38 44 189 | f 38 45 44 190 | f 45 38 46 191 | f 46 38 47 192 | f 38 7 47 193 | f 7 8 47 194 | f 8 46 47 195 | f 46 8 48 196 | f 8 49 48 197 | f 49 44 48 198 | f 44 45 48 199 | f 49 8 50 200 | f 49 51 44 201 | f 51 43 44 202 | f 43 51 42 203 | f 51 52 42 204 | f 52 41 42 205 | f 41 52 40 206 | f 53 54 50 207 | f 49 54 51 208 | f 54 49 50 209 | f 51 54 52 210 | f 50 9 53 211 | f 9 50 8 212 | f 55 33 34 213 | f 33 55 32 214 | f 55 56 32 215 | f 56 55 57 216 | f 55 58 57 217 | f 58 55 59 218 | f 55 60 59 219 | f 60 55 35 220 | f 55 34 35 221 | f 36 60 35 222 | f 60 36 37 223 | f 37 61 60 224 | f 61 37 62 225 | f 37 63 62 226 | f 63 37 64 227 | f 37 39 64 228 | f 39 40 64 229 | f 62 65 61 230 | f 65 62 66 231 | f 62 67 66 232 | f 67 62 68 233 | f 62 63 68 234 | f 65 59 60 235 | f 59 69 58 236 | f 69 59 70 237 | f 59 71 70 238 | f 71 59 67 239 | f 59 66 67 240 | f 59 65 66 241 | f 56 30 32 242 | f 30 56 31 243 | f 56 72 31 244 | f 72 56 57 245 | f 60 61 65 246 | f 46 48 45 247 | f 31 29 25 248 | f 29 31 73 249 | f 31 74 73 250 | f 74 31 72 251 | f 57 74 72 252 | f 74 57 75 253 | f 57 76 75 254 | f 57 58 69 255 | f 77 78 76 256 | f 78 77 79 257 | f 77 80 79 258 | f 80 77 71 259 | f 77 70 71 260 | f 70 77 69 261 | f 75 73 74 262 | f 73 75 81 263 | f 75 82 81 264 | f 82 75 76 265 | f 82 83 81 266 | f 83 82 84 267 | f 82 79 84 268 | f 79 82 78 269 | f 82 76 78 270 | f 73 85 29 271 | f 85 73 86 272 | f 73 81 86 273 | f 85 87 29 274 | f 87 85 86 275 | f 88 86 81 276 | f 86 88 89 277 | f 88 83 89 278 | f 83 88 81 279 | f 86 90 87 280 | f 71 91 80 281 | f 91 71 92 282 | f 71 67 92 283 | f 67 68 92 284 | f 79 93 84 285 | f 93 79 94 286 | f 79 91 94 287 | f 91 79 80 288 | f 92 95 91 289 | f 92 68 95 290 | f 91 95 94 291 | f 95 93 94 292 | f 93 95 96 293 | f 95 68 96 294 | f 93 83 84 295 | f 83 93 89 296 | f 93 97 89 297 | f 97 93 96 298 | f 89 97 98 299 | f 98 100 99 300 | f 100 98 101 301 | f 98 96 101 302 | f 98 97 96 303 | f 102 68 63 304 | f 68 102 96 305 | f 102 101 96 306 | f 101 102 63 307 | f 64 103 63 308 | f 103 64 40 309 | f 103 101 63 310 | f 101 104 100 311 | f 104 101 103 312 | f 40 104 103 313 | f 40 52 104 314 | f 52 105 104 315 | f 9 106 53 316 | f 106 9 28 317 | f 106 27 107 318 | f 27 106 28 319 | f 27 108 107 320 | f 108 27 22 321 | f 22 109 108 322 | f 109 22 23 323 | f 109 110 108 324 | f 110 109 23 325 | f 23 29 110 326 | f 110 111 108 327 | f 111 110 112 328 | f 110 90 112 329 | f 90 110 87 330 | f 110 29 87 331 | f 108 111 113 332 | f 108 113 107 333 | f 114 99 115 334 | f 99 104 115 335 | f 104 105 115 336 | f 116 117 115 337 | f 117 118 115 338 | f 115 118 114 339 | f 118 119 114 340 | f 120 112 90 341 | f 112 120 111 342 | f 120 121 111 343 | f 99 100 104 344 | f 2 4 3 345 | f 5 33 4 346 | f 116 122 123 347 | f 123 117 116 348 | f 117 123 124 349 | f 117 124 118 350 | f 124 125 118 351 | f 125 119 118 352 | f 119 125 126 353 | f 122 106 107 354 | f 105 116 115 355 | f 54 53 105 356 | f 52 54 105 357 | f 105 127 116 358 | f 122 116 127 359 | f 106 122 127 360 | f 53 127 105 361 | f 121 128 113 362 | f 121 113 111 363 | f 113 128 124 364 | f 128 129 124 365 | f 129 128 130 366 | f 107 113 122 367 | f 113 123 122 368 | f 123 113 124 369 | f 1 9 8 370 | f 9 15 28 371 | f 4 32 26 372 | f 106 127 53 373 | f 57 131 76 374 | f 131 77 76 375 | f 69 131 57 376 | f 131 69 77 377 | f 129 125 124 378 | f 125 130 126 379 | f 130 125 129 380 | -------------------------------------------------------------------------------- /assignment3/data/hemisphere.off: -------------------------------------------------------------------------------- 1 | OFF 2 | 58 100 0 3 | 0.358926 0.0973973 -0.952056 4 | -0.203956 0.101988 -0.982218 5 | 0.923973 0.105098 0.431337 6 | 0.740714 0.374017 0.58483 7 | 0.560486 0.469308 0.697367 8 | 0.647966 0.728626 0.280215 9 | 0.373474 0.713065 0.605006 10 | 0.884792 0.428987 0.236438 11 | 1.001 0.0993867 -0.0694862 12 | 0.420623 0.88295 0.274081 13 | 0.212876 0.0997379 0.985234 14 | 0.549207 0.114287 0.838119 15 | 0.287934 0.430597 0.875048 16 | 0.054638 0.654292 0.769427 17 | 0.772269 0.10752 -0.637625 18 | 0.743399 0.425053 -0.536663 19 | 0.48779 0.602735 -0.641763 20 | 0.216181 0.790049 -0.58336 21 | 0.233383 0.538865 -0.826352 22 | 0.614326 0.701874 -0.380823 23 | 0.0149945 0.310463 -0.962897 24 | 0.589803 0.314957 -0.757677 25 | 0.566575 0.833743 -0.103304 26 | 0.394119 0.854964 -0.36148 27 | 0.153814 1.00173 -0.00350426 28 | 0.943917 0.125462 -0.351265 29 | 0.949653 0.335528 0.0155114 30 | 0.822501 0.572747 -0.148586 31 | -0.923973 0.105098 -0.431337 32 | -0.740714 0.374017 -0.58483 33 | -0.560486 0.469308 -0.697367 34 | -0.658341 0.703666 -0.309987 35 | -0.408824 0.737021 -0.560547 36 | -0.884792 0.428987 -0.236438 37 | -1.001 0.0993867 0.0694862 38 | -0.477974 0.871908 -0.180181 39 | -0.122153 0.786643 -0.623467 40 | 0.0756001 0.953291 -0.345344 41 | -0.229072 0.963108 -0.223331 42 | -0.549207 0.114287 -0.838119 43 | -0.126902 0.587459 -0.816156 44 | -0.267409 0.342379 -0.910924 45 | -0.772269 0.10752 0.637625 46 | -0.743399 0.425053 0.536663 47 | -0.48779 0.602735 0.641763 48 | -0.211089 0.807301 0.562563 49 | -0.23378 0.545041 0.822912 50 | -0.644459 0.771343 0.0959897 51 | -0.614326 0.701874 0.380823 52 | -0.018279 0.318817 0.959425 53 | -0.374701 0.101477 0.94315 54 | -0.589803 0.314957 0.757677 55 | -0.4025 0.881599 0.300982 56 | -0.165166 0.959617 0.252736 57 | 0.0747107 0.910658 0.440988 58 | -0.943917 0.125462 0.351265 59 | -0.949653 0.335528 -0.0155114 60 | -0.822501 0.572747 0.148586 61 | 3 4 5 6 62 | 3 4 3 5 63 | 3 6 5 9 64 | 3 3 11 2 65 | 3 11 4 12 66 | 3 11 3 4 67 | 3 5 3 7 68 | 3 13 12 6 69 | 3 6 54 13 70 | 3 12 4 6 71 | 3 7 2 26 72 | 3 8 26 2 73 | 3 7 26 27 74 | 3 5 7 27 75 | 3 27 22 5 76 | 3 2 7 3 77 | 3 54 6 9 78 | 3 9 5 22 79 | 3 54 9 24 80 | 3 10 11 12 81 | 3 49 10 12 82 | 3 13 49 12 83 | 3 15 16 19 84 | 3 16 15 21 85 | 3 16 21 18 86 | 3 19 16 23 87 | 3 15 14 21 88 | 3 17 16 18 89 | 3 23 16 17 90 | 3 17 18 36 91 | 3 22 27 19 92 | 3 27 15 19 93 | 3 23 22 19 94 | 3 20 18 0 95 | 3 21 0 18 96 | 3 20 0 1 97 | 3 18 20 40 98 | 3 40 36 18 99 | 3 14 0 21 100 | 3 23 37 24 101 | 3 22 23 24 102 | 3 23 17 37 103 | 3 36 37 17 104 | 3 22 24 9 105 | 3 26 25 27 106 | 3 26 8 25 107 | 3 15 25 14 108 | 3 27 25 15 109 | 3 30 31 32 110 | 3 30 29 31 111 | 3 29 39 28 112 | 3 39 30 41 113 | 3 39 29 30 114 | 3 32 31 35 115 | 3 31 29 33 116 | 3 36 40 32 117 | 3 40 30 32 118 | 3 33 28 56 119 | 3 34 56 28 120 | 3 33 56 57 121 | 3 31 33 57 122 | 3 57 47 31 123 | 3 28 33 29 124 | 3 35 38 32 125 | 3 36 32 38 126 | 3 37 36 38 127 | 3 35 31 47 128 | 3 37 38 24 129 | 3 1 39 41 130 | 3 20 1 41 131 | 3 20 41 40 132 | 3 40 41 30 133 | 3 43 44 48 134 | 3 44 43 51 135 | 3 44 51 46 136 | 3 48 44 52 137 | 3 43 42 51 138 | 3 45 44 46 139 | 3 52 44 45 140 | 3 45 46 13 141 | 3 47 57 48 142 | 3 57 43 48 143 | 3 52 47 48 144 | 3 49 46 50 145 | 3 51 50 46 146 | 3 49 50 10 147 | 3 46 49 13 148 | 3 42 50 51 149 | 3 35 47 52 150 | 3 53 45 54 151 | 3 53 52 45 152 | 3 13 54 45 153 | 3 38 53 24 154 | 3 53 38 52 155 | 3 52 38 35 156 | 3 54 24 53 157 | 3 56 55 57 158 | 3 56 34 55 159 | 3 43 55 42 160 | 3 57 55 43 161 | -------------------------------------------------------------------------------- /assignment3/src/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | 11 | /*** insert any necessary libigl headers here ***/ 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | using namespace std; 24 | using namespace Eigen; 25 | using Viewer = igl::viewer::Viewer; 26 | 27 | Viewer viewer; 28 | 29 | // vertex array, #V x3 30 | Eigen::MatrixXd V; 31 | 32 | // face array, #F x3 33 | Eigen::MatrixXi F; 34 | 35 | // UV coordinates, #V x2 36 | Eigen::MatrixXd UV; 37 | 38 | bool showingUV = false; 39 | bool freeBoundary = false; 40 | double TextureResolution = 10; 41 | igl::viewer::ViewerCore temp3D; 42 | igl::viewer::ViewerCore temp2D; 43 | 44 | void Redraw() 45 | { 46 | viewer.data.clear(); 47 | 48 | if (!showingUV) 49 | { 50 | viewer.data.set_mesh(V, F); 51 | viewer.data.set_face_based(false); 52 | 53 | if(UV.size() != 0) 54 | { 55 | viewer.data.set_uv(TextureResolution*UV); 56 | viewer.data.show_texture = true; 57 | } 58 | } 59 | else 60 | { 61 | viewer.data.show_texture = false; 62 | viewer.data.set_mesh(UV, F); 63 | } 64 | } 65 | 66 | bool callback_mouse_move(Viewer &viewer, int mouse_x, int mouse_y) 67 | { 68 | if (showingUV) 69 | viewer.mouse_mode = igl::viewer::Viewer::MouseMode::Translation; 70 | return false; 71 | } 72 | 73 | static void computeSurfaceGradientMatrix(SparseMatrix & D1, SparseMatrix & D2) 74 | { 75 | MatrixXd F1, F2, F3; 76 | SparseMatrix DD, Dx, Dy, Dz; 77 | 78 | igl::local_basis(V, F, F1, F2, F3); 79 | igl::grad(V, F, DD); 80 | 81 | Dx = DD.topLeftCorner(F.rows(), V.rows()); 82 | Dy = DD.block(F.rows(), 0, F.rows(), V.rows()); 83 | Dz = DD.bottomRightCorner(F.rows(), V.rows()); 84 | 85 | D1 = F1.col(0).asDiagonal()*Dx + F1.col(1).asDiagonal()*Dy + F1.col(2).asDiagonal()*Dz; 86 | D2 = F2.col(0).asDiagonal()*Dx + F2.col(1).asDiagonal()*Dy + F2.col(2).asDiagonal()*Dz; 87 | } 88 | static inline void SSVD2x2(const Eigen::Matrix2d& J, Eigen::Matrix2d& U, Eigen::Matrix2d& S, Eigen::Matrix2d& V) 89 | { 90 | double e = (J(0) + J(3))*0.5; 91 | double f = (J(0) - J(3))*0.5; 92 | double g = (J(1) + J(2))*0.5; 93 | double h = (J(1) - J(2))*0.5; 94 | double q = sqrt((e*e) + (h*h)); 95 | double r = sqrt((f*f) + (g*g)); 96 | double a1 = atan2(g, f); 97 | double a2 = atan2(h, e); 98 | double rho = (a2 - a1)*0.5; 99 | double phi = (a2 + a1)*0.5; 100 | 101 | S(0) = q + r; 102 | S(1) = 0; 103 | S(2) = 0; 104 | S(3) = q - r; 105 | 106 | double c = cos(phi); 107 | double s = sin(phi); 108 | U(0) = c; 109 | U(1) = s; 110 | U(2) = -s; 111 | U(3) = c; 112 | 113 | c = cos(rho); 114 | s = sin(rho); 115 | V(0) = c; 116 | V(1) = -s; 117 | V(2) = s; 118 | V(3) = c; 119 | } 120 | 121 | void ConvertConstraintsToMatrixForm(VectorXi indices, MatrixXd positions, Eigen::SparseMatrix &C, VectorXd &d) 122 | { 123 | // Convert the list of fixed indices and their fixed positions to a linear system 124 | // Hint: The matrix C should contain only one non-zero element per row and d should contain the positions in the correct order. 125 | } 126 | 127 | void computeParameterization(int type) 128 | { 129 | VectorXi fixed_UV_indices; 130 | MatrixXd fixed_UV_positions; 131 | 132 | SparseMatrix A; 133 | VectorXd b; 134 | Eigen::SparseMatrix C; 135 | VectorXd d; 136 | // Find the indices of the boundary vertices of the mesh and put them in fixed_UV_indices 137 | if (!freeBoundary) 138 | { 139 | // The boundary vertices should be fixed to positions on the unit disc. Find these position and 140 | // save them in the #V x 2 matrix fixed_UV_position. 141 | } 142 | else 143 | { 144 | // Fix two UV vertices. This should be done in an intelligent way. Hint: The two fixed vertices should be the two most distant one on the mesh. 145 | } 146 | 147 | ConvertConstraintsToMatrixForm(fixed_UV_indices, fixed_UV_positions, C, d); 148 | 149 | // Find the linear system for the parameterization (1- Tutte, 2- Harmonic, 3- LSCM, 4- ARAP) 150 | // and put it in the matrix A. 151 | // The dimensions of A should be 2#V x 2#V. 152 | if (type == '1') { 153 | // Add your code for computing uniform Laplacian for Tutte parameterization 154 | // Hint: use the adjacency matrix of the mesh 155 | } 156 | 157 | if (type == '2') { 158 | // Add your code for computing cotangent Laplacian for Harmonic parameterization 159 | // Use can use a function "cotmatrix" from libIGL, but ~~~~***READ THE DOCUMENTATION***~~~~ 160 | } 161 | 162 | if (type == '3') { 163 | // Add your code for computing the system for LSCM parameterization 164 | // Note that the libIGL implementation is different than what taught in the tutorial! Do not rely on it!! 165 | } 166 | 167 | if (type == '4') { 168 | // Add your code for computing ARAP system and right-hand side 169 | // Implement a function that computes the local step first 170 | // Then construct the matrix with the given rotation matrices 171 | } 172 | 173 | // Solve the linear system. 174 | // Construct the system as discussed in class and the assignment sheet 175 | // Use igl::cat to concatenate matrices 176 | // Use Eigen::SparseLU to solve the system. Refer to tutorial 3 for more detail 177 | 178 | // The solver will output a vector 179 | UV.resize(V.rows(), 2); 180 | //UV.col(0) = 181 | //UV.col(1) = 182 | } 183 | 184 | bool callback_key_pressed(Viewer &viewer, unsigned char key, int modifiers) { 185 | switch (key) { 186 | case '1': 187 | case '2': 188 | case '3': 189 | case '4': 190 | computeParameterization(key); 191 | break; 192 | case '5': 193 | // Add your code for detecting and displaying flipped triangles in the 194 | // UV domain here 195 | break; 196 | case '+': 197 | TextureResolution /= 2; 198 | break; 199 | case '-': 200 | TextureResolution *= 2; 201 | break; 202 | case ' ': // space bar - switches view between mesh and parameterization 203 | if(showingUV) 204 | { 205 | temp2D = viewer.core; 206 | viewer.core = temp3D; 207 | showingUV = false; 208 | } 209 | else 210 | { 211 | if(UV.rows() > 0) 212 | { 213 | temp3D = viewer.core; 214 | viewer.core = temp2D; 215 | showingUV = true; 216 | } 217 | else { std::cout << "ERROR ! No valid parameterization\n"; } 218 | } 219 | break; 220 | } 221 | Redraw(); 222 | return true; 223 | } 224 | 225 | void init_core_states() 226 | { 227 | // save initial viewer core state 228 | temp3D = viewer.core; 229 | temp2D = viewer.core; 230 | temp2D.orthographic = true; 231 | } 232 | 233 | bool load_mesh(string filename) 234 | { 235 | igl::read_triangle_mesh(filename,V,F); 236 | Redraw(); 237 | viewer.core.align_camera_position(V); 238 | showingUV = false; 239 | 240 | return true; 241 | } 242 | 243 | bool callback_load_mesh(Viewer& viewer,string filename) 244 | { 245 | load_mesh(filename); 246 | init_core_states(); 247 | return true; 248 | } 249 | 250 | int main(int argc,char *argv[]) { 251 | if(argc != 2) { 252 | cout << "Usage ex4_bin " << endl; 253 | load_mesh("../data/cathead.obj"); 254 | } 255 | else 256 | { 257 | // Read points and normals 258 | load_mesh(argv[1]); 259 | } 260 | 261 | viewer.callback_init = [&](Viewer &v) { 262 | // Add widgets to the sidebar. 263 | v.ngui->addGroup("Parmaterization"); 264 | v.ngui->addVariable("Free boundary",freeBoundary); 265 | // TODO: Add more parameters to tweak here... 266 | 267 | viewer.screen->performLayout(); 268 | 269 | init_core_states(); 270 | 271 | return false; 272 | }; 273 | 274 | viewer.callback_key_pressed = callback_key_pressed; 275 | viewer.callback_mouse_move = callback_mouse_move; 276 | viewer.callback_load_mesh = callback_load_mesh; 277 | 278 | viewer.launch(); 279 | } 280 | -------------------------------------------------------------------------------- /assignment4/.gitignore: -------------------------------------------------------------------------------- 1 | build 2 | -------------------------------------------------------------------------------- /assignment4/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.6) 2 | project(assignment4) 3 | 4 | set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/cmake) 5 | 6 | find_package(LIBIGL QUIET) 7 | 8 | if (NOT LIBIGL_FOUND) 9 | message(FATAL_ERROR "libigl not found --- You can download it using: \n git clone --recursive https://github.com/libigl/libigl.git ${PROJECT_SOURCE_DIR}/../libigl") 10 | endif() 11 | 12 | # Compilation flags: adapt to your needs 13 | if(MSVC) 14 | # Enable parallel compilation 15 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MP /bigobj") 16 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG ${CMAKE_BINARY_DIR} ) 17 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE ${CMAKE_BINARY_DIR} ) 18 | else() 19 | # Libigl requires a modern C++ compiler that supports c++11 20 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") 21 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "." ) 22 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-deprecated-declarations") 23 | endif() 24 | 25 | # libigl options: choose between header only and compiled static library 26 | # Header-only is preferred for small projects. For larger projects the static build 27 | # considerably reduces the compilation times 28 | option(LIBIGL_USE_STATIC_LIBRARY "Use LibIGL as static library" OFF) 29 | 30 | # add a customizable menu bar 31 | option(LIBIGL_VIEWER_WITH_NANOGUI "Use Nanogui menu" ON) 32 | option(LIBIGL_VIEWER_WITH_NANOGUI_IO "Add mesh IO menu" ON) 33 | option(LIBIGL_VIEWER_WITH_NANOGUI_SERIALIZATION "Enable viewer serialization" ON) 34 | 35 | # libigl options: choose your dependencies (by default everything is OFF except opengl) 36 | option(LIBIGL_WITH_VIEWER "Use OpenGL viewer" ON) 37 | option(LIBIGL_WITH_OPENGL "Use OpenGL" ON) 38 | option(LIBIGL_WITH_OPENGL_GLFW "Use GLFW" ON) 39 | option(LIBIGL_WITH_BBW "Use BBW" OFF) 40 | option(LIBIGL_WITH_EMBREE "Use Embree" OFF) 41 | option(LIBIGL_WITH_PNG "Use PNG" OFF) 42 | option(LIBIGL_WITH_TETGEN "Use Tetgen" OFF) 43 | option(LIBIGL_WITH_TRIANGLE "Use Triangle" OFF) 44 | option(LIBIGL_WITH_XML "Use XML" OFF) 45 | option(LIBIGL_WITH_LIM "Use LIM" OFF) 46 | option(LIBIGL_WITH_COMISO "Use CoMiso" OFF) 47 | option(LIBIGL_WITH_MATLAB "Use Matlab" OFF) # This option is not supported yet 48 | option(LIBIGL_WITH_MOSEK "Use MOSEK" OFF) # This option is not supported yet 49 | option(LIBIGL_WITH_CGAL "Use CGAL" OFF) 50 | if(LIBIGL_WITH_CGAL) # Do not remove or move this block, the cgal build system fails without it 51 | find_package(CGAL REQUIRED) 52 | set(CGAL_DONT_OVERRIDE_CMAKE_FLAGS TRUE CACHE BOOL "CGAL's CMAKE Setup is super annoying ") 53 | include(${CGAL_USE_FILE}) 54 | endif() 55 | 56 | # Adding libigl: choose the path to your local copy libigl 57 | # This is going to compile everything you requested 58 | #message(FATAL_ERROR "${PROJECT_SOURCE_DIR}/../libigl/cmake") 59 | add_subdirectory("${LIBIGL_INCLUDE_DIR}/../shared/cmake" "libigl") 60 | 61 | # libigl information 62 | message("libigl includes: ${LIBIGL_INCLUDE_DIRS}") 63 | message("libigl libraries: ${LIBIGL_LIBRARIES}") 64 | message("libigl extra sources: ${LIBIGL_EXTRA_SOURCES}") 65 | message("libigl extra libraries: ${LIBIGL_EXTRA_LIBRARIES}") 66 | message("libigl definitions: ${LIBIGL_DEFINITIONS}") 67 | 68 | # Prepare the build environment 69 | include_directories(${LIBIGL_INCLUDE_DIRS}) 70 | add_definitions(${LIBIGL_DEFINITIONS}) 71 | 72 | # Add your project files 73 | # Note: we need some stubs for building to succeed on TravisCI. 74 | if (TRAVISCI_BUILD) 75 | FILE(GLOB SOURCES src/*.cpp src_travisci/*.cpp) 76 | else (TRAVISCI_BUILD) 77 | FILE(GLOB SOURCES src/*.cpp) 78 | endif (TRAVISCI_BUILD) 79 | 80 | add_executable(${PROJECT_NAME}_bin ${SOURCES} ${LIBIGL_EXTRA_SOURCES}) 81 | target_link_libraries(${PROJECT_NAME}_bin ${LIBIGL_LIBRARIES} ${LIBIGL_EXTRA_LIBRARIES}) 82 | -------------------------------------------------------------------------------- /assignment4/README.md: -------------------------------------------------------------------------------- 1 | # Assignment 4 2 | 3 | Edit this 'README.md' file to report all your results. There is no need to write lengthy reports, just show the requested outputs and screenshots and quickly summarize your observations. Please add your additional files or notes in the folder 'assignment4/results' and refer to or directly show them in this page. 4 | 5 | ## Required results for assignment 4 6 | 7 | ### Mandatory Tasks 8 | 9 | Provide screenshots for 4 different deformed meshes. For each example, provide a rendering of S, B, B' and S'. 10 | -------------------------------------------------------------------------------- /assignment4/assignment4.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eth-igl/GP2018-Assignments/895e5e30625089deccfc469c662bdc6093e9e314/assignment4/assignment4.pdf -------------------------------------------------------------------------------- /assignment4/cmake/FindLIBIGL.cmake: -------------------------------------------------------------------------------- 1 | # - Try to find the LIBIGL library 2 | # Once done this will define 3 | # 4 | # LIBIGL_FOUND - system has LIBIGL 5 | # LIBIGL_INCLUDE_DIR - **the** LIBIGL include directory 6 | # LIBIGL_INCLUDE_DIRS - LIBIGL include directories 7 | # LIBIGL_SOURCES - the LIBIGL source files 8 | if(NOT LIBIGL_FOUND) 9 | 10 | FIND_PATH(LIBIGL_INCLUDE_DIR igl/readOBJ.h 11 | ${PROJECT_SOURCE_DIR}/../../include 12 | ${PROJECT_SOURCE_DIR}/../include 13 | ${PROJECT_SOURCE_DIR}/include 14 | ${PROJECT_SOURCE_DIR}/../libigl/include 15 | ${PROJECT_SOURCE_DIR}/../../libigl/include 16 | $ENV{LIBIGL}/include 17 | $ENV{LIBIGLROOT}/include 18 | $ENV{LIBIGL_ROOT}/include 19 | $ENV{LIBIGL_DIR}/include 20 | $ENV{LIBIGL_DIR}/inc 21 | /usr/include 22 | /usr/local/include 23 | /usr/local/igl/libigl/include 24 | ) 25 | 26 | 27 | if(LIBIGL_INCLUDE_DIR) 28 | set(LIBIGL_FOUND TRUE) 29 | set(LIBIGL_INCLUDE_DIRS ${LIBIGL_INCLUDE_DIR}) 30 | #set(LIBIGL_SOURCES 31 | # ${LIBIGL_INCLUDE_DIR}/igl/viewer/Viewer.cpp 32 | #) 33 | endif() 34 | 35 | endif() 36 | -------------------------------------------------------------------------------- /assignment4/src/Colors.cpp: -------------------------------------------------------------------------------- 1 | #include "Colors.h" 2 | 3 | double regionColors[MAXNUMREGIONS][3]= { 4 | {0, 0.4470, 0.7410}, 5 | {0.8500, 0.3250, 0.0980}, 6 | {0.9290, 0.6940, 0.1250}, 7 | {0.4940, 0.1840, 0.5560}, 8 | {0.4660, 0.6740, 0.1880}, 9 | {0.3010, 0.7450, 0.9330}, 10 | {0.6350, 0.0780, 0.1840}, 11 | }; 12 | -------------------------------------------------------------------------------- /assignment4/src/Colors.h: -------------------------------------------------------------------------------- 1 | #ifndef ex5_Colors_h 2 | #define ex5_Colors_h 3 | 4 | #define MAXNUMREGIONS 7 5 | extern double regionColors[MAXNUMREGIONS][3]; 6 | 7 | #endif 8 | -------------------------------------------------------------------------------- /assignment4/src/Lasso.cpp: -------------------------------------------------------------------------------- 1 | #include "Lasso.h" 2 | 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include 13 | 14 | using namespace igl; 15 | using namespace std; 16 | 17 | Lasso::Lasso(const Eigen::MatrixXd &V_, 18 | const Eigen::MatrixXi &F_, 19 | const igl::viewer::Viewer &v): 20 | V(V_), 21 | F(F_), 22 | viewer(v) 23 | { 24 | } 25 | 26 | Lasso::~Lasso() 27 | { 28 | } 29 | 30 | int Lasso::pickVertex(int mouse_x, int mouse_y) 31 | { 32 | int vi = -1; 33 | 34 | int fid; 35 | Eigen::Vector3f bc; 36 | // Cast a ray in the view direction starting from the mouse position 37 | double x = viewer.current_mouse_x; 38 | double y = viewer.core.viewport(3) - viewer.current_mouse_y; 39 | if(igl::unproject_onto_mesh(Eigen::Vector2f(x,y), viewer.core.view * viewer.data.model, 40 | viewer.core.proj, viewer.core.viewport, V, F, fid, bc)) 41 | { 42 | // paint hit red 43 | bc.maxCoeff(&vi); 44 | vi = F(fid,vi); 45 | } 46 | return vi; 47 | 48 | } 49 | int Lasso::strokeAdd(int mouse_x, 50 | int mouse_y) 51 | { 52 | // Cast a ray in the view direction starting from the mouse position 53 | double x = mouse_x; 54 | double y = viewer.core.viewport(3) - mouse_y; 55 | 56 | std::vector pt2D; pt2D.push_back(x); pt2D.push_back(y); 57 | stroke2DPoints.push_back(pt2D); 58 | 59 | Eigen::RowVector3d pt(0,0,0); 60 | int fi = -1; 61 | 62 | Eigen::Matrix4f modelview = viewer.core.view * viewer.data.model; 63 | 64 | if (d<0)//first time 65 | { 66 | Eigen::Vector3f bc; 67 | if (igl::unproject_onto_mesh(Eigen::Vector2f(x,y), 68 | modelview, 69 | viewer.core.proj, 70 | viewer.core.viewport, 71 | V, 72 | F, 73 | fi, 74 | bc)) 75 | { 76 | pt = V.row(F(fi,0))*bc(0) + V.row(F(fi,1))*bc(1) + V.row(F(fi,2))*bc(2); 77 | Eigen::Vector3f proj = igl::project(pt.transpose().cast().eval(), modelview, viewer.core.proj,viewer.core.viewport); 78 | d = proj[2]; 79 | } 80 | 81 | } 82 | 83 | // This is lazy, it will find more than just the first hit 84 | pt = igl::unproject(Eigen::Vector3f(x,y,0.95*d), modelview, viewer.core.proj, viewer.core.viewport).transpose().cast(); 85 | 86 | strokePoints.push_back(pt); 87 | 88 | return fi; 89 | 90 | } 91 | 92 | void Lasso::strokeFinish(Eigen::VectorXi &selected_vertices) 93 | { 94 | 95 | Eigen::Matrix4f modelview = viewer.core.view * viewer.data.model; 96 | 97 | //marker for selected vertices 98 | Eigen::VectorXi is_selected; is_selected.setZero(V.rows(),1); 99 | 100 | //project all vertices, check which ones land inside the polyline 101 | for (int vi =0; vi(); 104 | Eigen::Vector3f proj = igl::project(vertex, modelview, viewer.core.proj,viewer.core.viewport); 105 | if (igl::point_in_poly(stroke2DPoints, proj[0], proj[1])) 106 | is_selected[vi] = 1; 107 | 108 | } 109 | 110 | //the selection might consist of front facing and back facing facets. 111 | //we will only select the connected component that is frontmost 112 | 113 | //first, determine faces that have at least one selected vertex 114 | int nf = 0; 115 | Eigen::MatrixXi Fsel(F.rows(), 3); 116 | for (int fi = 0; fi 0) { 128 | //compute their barycenters 129 | Eigen::MatrixXd MFsel; 130 | igl::barycenter(V, Fsel, MFsel); 131 | 132 | //now, find all connected components of selected faces 133 | Eigen::VectorXi cid; 134 | igl::facet_components(Fsel, cid); 135 | 136 | //compute centroids of connected components 137 | int ncomp = cid.maxCoeff()+1; 138 | Eigen::MatrixXd region_centroids; 139 | region_centroids.setZero(ncomp,3); 140 | Eigen::VectorXi total; total.setZero(ncomp,1); 141 | for (long fi = 0; fi(); 156 | Eigen::Vector3f proj = igl::project(t, 157 | modelview, 158 | viewer.core.proj, 159 | viewer.core.viewport); 160 | float depth = proj[2]; 161 | if (mind > depth) 162 | { 163 | r = i; 164 | mind = depth; 165 | } 166 | } 167 | 168 | //all vertices belonging to other components are unmarked 169 | for (long fi = 0; fi 5 | 6 | class Lasso 7 | { 8 | public: 9 | 10 | public: 11 | Lasso(const Eigen::MatrixXd &V_, 12 | const Eigen::MatrixXi &F_, 13 | const igl::viewer::Viewer &v); 14 | ~Lasso(); 15 | 16 | private: 17 | const Eigen::MatrixXd &V; 18 | const Eigen::MatrixXi &F; 19 | const igl::viewer::Viewer &viewer; 20 | 21 | std::vector > stroke2DPoints; 22 | double d = -1; 23 | public: 24 | int strokeAdd(int mouse_x, int mouse_y); 25 | void strokeFinish(Eigen::VectorXi &selected_vertices); 26 | void strokeReset(); 27 | int pickVertex(int mouse_x, int mouse_y); 28 | //the stroke 29 | std::vector< Eigen::Matrix > strokePoints; 30 | }; 31 | 32 | #endif 33 | -------------------------------------------------------------------------------- /assignment5/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.6) 2 | project(assignment5) 3 | 4 | set (CMAKE_CXX_STANDARD 11) 5 | 6 | set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/cmake) 7 | 8 | find_package(LIBIGL QUIET) 9 | 10 | if (NOT LIBIGL_FOUND) 11 | message(FATAL_ERROR "libigl not found --- You can download it using: \n git clone --recursive https://github.com/libigl/libigl.git ${PROJECT_SOURCE_DIR}/../libigl") 12 | endif() 13 | 14 | # Compilation flags: adapt to your needs 15 | if(MSVC) 16 | # Enable parallel compilation 17 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MP /bigobj") 18 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG ${CMAKE_BINARY_DIR} ) 19 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE ${CMAKE_BINARY_DIR} ) 20 | else() 21 | # Libigl requires a modern C++ compiler that supports c++11 22 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") 23 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "." ) 24 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-deprecated-declarations") 25 | endif() 26 | 27 | # libigl options: choose between header only and compiled static library 28 | # Header-only is preferred for small projects. For larger projects the static build 29 | # considerably reduces the compilation times 30 | option(LIBIGL_USE_STATIC_LIBRARY "Use LibIGL as static library" OFF) 31 | 32 | # add a customizable menu bar 33 | option(LIBIGL_VIEWER_WITH_NANOGUI "Use Nanogui menu" ON) 34 | option(LIBIGL_VIEWER_WITH_NANOGUI_IO "Add mesh IO menu" ON) 35 | option(LIBIGL_VIEWER_WITH_NANOGUI_SERIALIZATION "Enable viewer serialization" ON) 36 | 37 | # libigl options: choose your dependencies (by default everything is OFF except opengl) 38 | option(LIBIGL_WITH_VIEWER "Use OpenGL viewer" ON) 39 | option(LIBIGL_WITH_OPENGL "Use OpenGL" ON) 40 | option(LIBIGL_WITH_OPENGL_GLFW "Use GLFW" ON) 41 | option(LIBIGL_WITH_BBW "Use BBW" OFF) 42 | option(LIBIGL_WITH_EMBREE "Use Embree" OFF) 43 | option(LIBIGL_WITH_PNG "Use PNG" OFF) 44 | option(LIBIGL_WITH_TETGEN "Use Tetgen" OFF) 45 | option(LIBIGL_WITH_TRIANGLE "Use Triangle" OFF) 46 | option(LIBIGL_WITH_XML "Use XML" OFF) 47 | option(LIBIGL_WITH_LIM "Use LIM" OFF) 48 | option(LIBIGL_WITH_COMISO "Use CoMiso" OFF) 49 | option(LIBIGL_WITH_MATLAB "Use Matlab" OFF) # This option is not supported yet 50 | option(LIBIGL_WITH_MOSEK "Use MOSEK" OFF) # This option is not supported yet 51 | option(LIBIGL_WITH_CGAL "Use CGAL" OFF) 52 | if(LIBIGL_WITH_CGAL) # Do not remove or move this block, the cgal build system fails without it 53 | find_package(CGAL REQUIRED) 54 | set(CGAL_DONT_OVERRIDE_CMAKE_FLAGS TRUE CACHE BOOL "CGAL's CMAKE Setup is super annoying ") 55 | include(${CGAL_USE_FILE}) 56 | endif() 57 | 58 | # Adding libigl: choose the path to your local copy libigl 59 | # This is going to compile everything you requested 60 | #message(FATAL_ERROR "${PROJECT_SOURCE_DIR}/../libigl/cmake") 61 | add_subdirectory("${LIBIGL_INCLUDE_DIR}/../shared/cmake" "libigl") 62 | 63 | # set(EIGEN3_INCLUDE_DIR "${LIBIGL_INCLUDE_DIR}/../external/nanogui/ext/eigen") 64 | # set(AUTOGEN_BUILD_TESTS FALSE) 65 | # add_subdirectory("../autogen" "autogen") 66 | 67 | # libigl information 68 | message("libigl includes: ${LIBIGL_INCLUDE_DIRS}") 69 | message("libigl libraries: ${LIBIGL_LIBRARIES}") 70 | message("libigl extra sources: ${LIBIGL_EXTRA_SOURCES}") 71 | message("libigl extra libraries: ${LIBIGL_EXTRA_LIBRARIES}") 72 | message("libigl definitions: ${LIBIGL_DEFINITIONS}") 73 | 74 | # Prepare the build environment 75 | include_directories(${LIBIGL_INCLUDE_DIRS}) 76 | add_definitions(${LIBIGL_DEFINITIONS}) 77 | 78 | add_subdirectory(src/femLib) 79 | add_subdirectory(src/optLib) 80 | include_directories(src/optLib) 81 | 82 | FILE(GLOB SOURCES src/main.cpp src/gui_utils.cpp) 83 | add_executable(${PROJECT_NAME}_bin ${SOURCES} ${LIBIGL_EXTRA_SOURCES}) 84 | target_link_libraries(${PROJECT_NAME}_bin ${LIBIGL_LIBRARIES} ${LIBIGL_EXTRA_LIBRARIES} femLib) 85 | 86 | FILE(GLOB SOURCES src/test_rosenbrock.cpp) 87 | add_executable(${PROJECT_NAME}_test_rosenbrock ${SOURCES}) 88 | -------------------------------------------------------------------------------- /assignment5/README.md: -------------------------------------------------------------------------------- 1 | # Assignment 5 2 | 3 | Edit this 'README.md' file to report all your results. There is no need to write lengthy reports, just show the requested outputs and screenshots and quickly summarize your observations. 4 | 5 | ## Required results 6 | 7 | See assignment! -------------------------------------------------------------------------------- /assignment5/assignment5.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eth-igl/GP2018-Assignments/895e5e30625089deccfc469c662bdc6093e9e314/assignment5/assignment5.pdf -------------------------------------------------------------------------------- /assignment5/cmake/FindLIBIGL.cmake: -------------------------------------------------------------------------------- 1 | # - Try to find the LIBIGL library 2 | # Once done this will define 3 | # 4 | # LIBIGL_FOUND - system has LIBIGL 5 | # LIBIGL_INCLUDE_DIR - **the** LIBIGL include directory 6 | # LIBIGL_INCLUDE_DIRS - LIBIGL include directories 7 | # LIBIGL_SOURCES - the LIBIGL source files 8 | if(NOT LIBIGL_FOUND) 9 | 10 | FIND_PATH(LIBIGL_INCLUDE_DIR igl/readOBJ.h 11 | ${PROJECT_SOURCE_DIR}/../../include 12 | ${PROJECT_SOURCE_DIR}/../include 13 | ${PROJECT_SOURCE_DIR}/include 14 | ${PROJECT_SOURCE_DIR}/../libigl/include 15 | ${PROJECT_SOURCE_DIR}/../../libigl/include 16 | $ENV{LIBIGL}/include 17 | $ENV{LIBIGLROOT}/include 18 | $ENV{LIBIGL_ROOT}/include 19 | $ENV{LIBIGL_DIR}/include 20 | $ENV{LIBIGL_DIR}/inc 21 | /usr/include 22 | /usr/local/include 23 | /usr/local/igl/libigl/include 24 | ) 25 | 26 | 27 | if(LIBIGL_INCLUDE_DIR) 28 | set(LIBIGL_FOUND TRUE) 29 | set(LIBIGL_INCLUDE_DIRS ${LIBIGL_INCLUDE_DIR}) 30 | #set(LIBIGL_SOURCES 31 | # ${LIBIGL_INCLUDE_DIR}/igl/viewer/Viewer.cpp 32 | #) 33 | endif() 34 | 35 | endif() 36 | -------------------------------------------------------------------------------- /assignment5/src/femLib/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.6) 2 | 3 | project(femLib CXX) 4 | 5 | set (CMAKE_CXX_STANDARD 11) 6 | FILE(GLOB SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/*.h ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp) 7 | 8 | include_directories(../optLib) 9 | add_library(${PROJECT_NAME} ${SOURCES}) 10 | target_link_libraries(${PROJECT_NAME}) 11 | target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) 12 | -------------------------------------------------------------------------------- /assignment5/src/femLib/Element.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | /** 7 | This class implements the interface for an elementary energy unit. As a function of deformed, undeformed, 8 | and other parameters, such as boundary conditions, each class that extends this one will define a potential energy. 9 | The deformed energy depends on a number of nodes. 10 | */ 11 | class Element{ 12 | 13 | public: 14 | Element() {} 15 | virtual ~Element() {} 16 | 17 | // Returns the number of nodes this unit depends on 18 | virtual int getNumNodes() const = 0; 19 | // Returns the global index of node `i` 20 | virtual int getNodeIndex(int i) const = 0; 21 | 22 | Vector2d getNodePos(int i, const VectorXd &x) const { 23 | return x.segment<2>(2*getNodeIndex(i)); 24 | } 25 | 26 | // Returns the element's mass 27 | virtual double getMass() const = 0; 28 | 29 | // Returns the energy value given deformed `x` and undeformed `X` state 30 | virtual double getEnergy(const VectorXd& x, const VectorXd& X) = 0; 31 | // Adds the gradient to `grad` given deformed `x` and undeformed `X` state 32 | virtual void addEnergyGradientTo(const VectorXd& x, const VectorXd& X, VectorXd& grad) = 0; 33 | // Adds the hessian entries to `hesEntries` given deformed `x` and undeformed `X` state 34 | virtual void addEnergyHessianTo(const VectorXd& x, const VectorXd& X, std::vector& hesEntries) = 0; 35 | 36 | EIGEN_MAKE_ALIGNED_OPERATOR_NEW 37 | }; 38 | -------------------------------------------------------------------------------- /assignment5/src/femLib/FEMElement.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Element.h" 4 | 5 | #include 6 | 7 | enum MaterialModel2D { 8 | MM_LINEAR_ISOTROPIC=0, 9 | MM_STVK, 10 | MM_NEO_HOOKEAN 11 | }; 12 | 13 | /** 14 | This class implements Constant Strain Triangles elements in 2D 15 | */ 16 | class FEMElement : public Element { 17 | public: 18 | FEMElement(const std::array &nodeIndices, const VectorXd &X) 19 | : nodeIndices(nodeIndices) { 20 | 21 | assert(nodeIndices.size() == 3); 22 | 23 | precomputeFromUndeformedState(X); 24 | } 25 | ~FEMElement(){ 26 | } 27 | 28 | virtual int getNumNodes() const { 29 | return 3; 30 | } 31 | virtual int getNodeIndex(int i) const { 32 | return nodeIndices[i]; 33 | } 34 | virtual double getMass() const { 35 | return restShapeArea * massDensity; 36 | } 37 | 38 | protected: 39 | // sets important properties of the rest shape using the set of points passed in as parameters 40 | void precomputeFromUndeformedState(const VectorXd &X){ 41 | //edge vectors 42 | Vector2d v1 = getNodePos(1, X) - getNodePos(0, X); 43 | Vector2d v2 = getNodePos(2, X) - getNodePos(0, X); 44 | 45 | //matrix that holds three edge vectors 46 | Matrix2d dX; 47 | dX << v1[0], v2[0], 48 | v1[1], v2[1]; 49 | 50 | dXInv = dX.inverse(); 51 | 52 | //compute the area of the element... 53 | restShapeArea = 1 / 2.0 * fabs(cross2d(v1, v2)); 54 | } 55 | 56 | // as a deformation measure, we need to compute the deformation gradient F. F maps deformed vectors dx to undeformed coords dX: dx = F*dX. 57 | // for linear basis functions, an easy way to compute it is by looking at the matrix that maps deformed traingle/tet edges to their underformed counterparts (F = dx * inv(dX)). 58 | void computeDeformationGradient(const Vector2d (&x)[3], Matrix2d& dxdX) const { 59 | //edge vectors 60 | Vector2d v1 = x[1] - x[0]; 61 | Vector2d v2 = x[2] - x[0]; 62 | Matrix2d dx; 63 | dx << v1[0], v2[0], 64 | v1[1], v2[1]; 65 | dxdX = dx * dXInv; 66 | } 67 | 68 | protected: 69 | // the collection of nodes that define the triangle element 70 | std::array nodeIndices; 71 | // material parameters 72 | double shearModulus = 50, bulkModulus = 50; 73 | // relates area/volume to the mass of the element 74 | double massDensity = 1; 75 | // precomputed values 76 | double restShapeArea = 0; 77 | Matrix2d dXInv; 78 | }; 79 | -------------------------------------------------------------------------------- /assignment5/src/femLib/FEMElementAnalytic.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "FEMElement.h" 4 | 5 | /** 6 | This class implements Constant Strain Triangles elements in 2D 7 | */ 8 | class FEMElementAnalytic : public FEMElement { 9 | public: 10 | FEMElementAnalytic(const std::array &nodeIndices, const VectorXd &X) 11 | : FEMElement(nodeIndices, X) { 12 | } 13 | ~FEMElementAnalytic(){ 14 | } 15 | 16 | virtual double getEnergy(const VectorXd& x, const VectorXd& X){ 17 | // Ex. 2.3 (same as FEMElementFD 18 | return 0; 19 | } 20 | 21 | virtual void addEnergyGradientTo(const VectorXd& x, const VectorXd& X, VectorXd& grad) { 22 | // Ex. 2.3 23 | } 24 | 25 | virtual void addEnergyHessianTo(const VectorXd& x, const VectorXd& X, std::vector& hesEntries) { 26 | // Ex. 2.3 27 | } 28 | }; 29 | -------------------------------------------------------------------------------- /assignment5/src/femLib/FEMElementAutoDiff.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "FEMElement.h" 4 | 5 | #include 6 | 7 | template using Vector2 = Eigen::Matrix; 8 | template using Matrix2 = Eigen::Matrix; 9 | 10 | typedef AutoDiff AD; 11 | typedef AutoDiff ADD; 12 | 13 | /* This is the code from the tutorial using this AutoDiff implementation: 14 | * 15 | * // df/dx1 16 | AD x1 = M_PI; x1.deriv() = 1; 17 | AD x2 = 3; x2.deriv() = 0; 18 | AD f = sin(x1*x2); 19 | double f_val = f.value(); 20 | double dfdx1 = f.deriv(); 21 | 22 | // ddf/dx1dx2 23 | ADD x1 = M_PI; 24 | x1.value().deriv() = 1; x1.deriv().value() = 0; 25 | ADD x2 = 3; 26 | x2.value().deriv() = 0; x1.deriv().value() = 1; 27 | ADD f = sin(x1*x2); 28 | double f_val = f.value().value(); 29 | double ddfdx1dx2 = f.deriv().deriv(); 30 | 31 | // ddf/dx2dx2 32 | ADD x1 = M_PI; 33 | x1.value().deriv() = 0; x1.deriv().value() = 0; 34 | ADD x2 = 3; 35 | x2.value().deriv() = 1; x1.deriv().value() = 1; 36 | ADD f = sin(x1*x2); 37 | double f_val = f.value().value(); 38 | double ddfdx1dx2 = f.deriv().deriv(); 39 | */ 40 | 41 | /** 42 | This class implements Constant Strain Triangles elements in 2D 43 | */ 44 | class FEMElementAutoDiff : public FEMElement { 45 | public: 46 | FEMElementAutoDiff(const std::array &nodeIndices, const VectorXd &X) 47 | : FEMElement(nodeIndices, X) { 48 | } 49 | ~FEMElementAutoDiff(){ 50 | } 51 | 52 | virtual double getEnergy(const VectorXd& x, const VectorXd& X){ 53 | 54 | // Ex 2.3 55 | 56 | } 57 | 58 | virtual void addEnergyGradientTo(const VectorXd& x, const VectorXd& X, VectorXd& grad) { 59 | 60 | // Ex. 2.3 61 | 62 | } 63 | 64 | virtual void addEnergyHessianTo(const VectorXd& x, const VectorXd& X, std::vector& hesEntries) { 65 | 66 | // Ex. 2.3 67 | 68 | } 69 | 70 | private: 71 | // This is the same function as FEMElement::computeGradient, 72 | // however with a template parameter T. 73 | template 74 | void computeDeformationGradientT(const Vector2 (&x)[3], Matrix2& dxdX) const { 75 | //edge vectors 76 | Vector2 v1 = x[1] - x[0]; 77 | Vector2 v2 = x[2] - x[0]; 78 | Matrix2 dx; 79 | dx << v1[0], v2[0], 80 | v1[1], v2[1]; 81 | Matrix2 dxInvT; 82 | for (int i = 0; i < 4; ++i) 83 | dxInvT.data()[i] = dXInv.data()[i]; 84 | dxdX = dx * dxInvT; 85 | } 86 | }; 87 | -------------------------------------------------------------------------------- /assignment5/src/femLib/FEMElementFD.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "FEMElement.h" 4 | 5 | /** 6 | This class implements Constant Strain Triangles elements in 2D 7 | */ 8 | class FEMElementFD : public FEMElement { 9 | public: 10 | FEMElementFD(const std::array &nodeIndices, const VectorXd &X) 11 | : FEMElement(nodeIndices, X) { 12 | } 13 | ~FEMElementFD(){ 14 | } 15 | 16 | virtual double getEnergy(const VectorXd& x, const VectorXd& X) 17 | { 18 | // Ex 2.1 19 | return 0; 20 | } 21 | virtual void addEnergyGradientTo(const VectorXd& x, const VectorXd& X, VectorXd& grad) 22 | { 23 | // Ex 2.1 24 | } 25 | virtual void addEnergyHessianTo(const VectorXd& x, const VectorXd& X, std::vector& hesEntries) 26 | { 27 | // Ex 2.2 28 | } 29 | 30 | private: 31 | double h = 1e-8; // step size 32 | }; 33 | -------------------------------------------------------------------------------- /assignment5/src/femLib/FixedPointElement.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Element.h" 4 | 5 | // zero rest length spring connected to a target position (could be the mouse, or something else...) 6 | class FixedPointElement : public Element{ 7 | public: 8 | FixedPointElement(int nodeIndex, const Vector2d &targetPosition, double K = 10000) 9 | : nodeIndex(nodeIndex), targetPosition(targetPosition), k(K) { 10 | } 11 | ~FixedPointElement(){ 12 | } 13 | 14 | virtual int getNumNodes() const { 15 | return 1; 16 | } 17 | virtual int getNodeIndex(int i) const { 18 | assert(i == 0); 19 | return nodeIndex; 20 | } 21 | 22 | virtual double getMass() const { 23 | return 0; 24 | } 25 | 26 | virtual double getEnergy(const VectorXd& x, const VectorXd& X){ 27 | Vector2d p = x.segment<2>(2*nodeIndex); 28 | 29 | double v0 = k; 30 | double v3 = 0.500000; 31 | double v4 = v3 * v0; 32 | double v5 = p[0]; 33 | double v6 = targetPosition[0]; 34 | double v7 = v5 - v6; 35 | double v8 = v7 * v7; 36 | double v9 = p[1]; 37 | double v10 = targetPosition[1]; 38 | double v11 = v9 - v10; 39 | double v12 = v11 * v11; 40 | double v13 = v8 + v12; 41 | double v14 = v4 * v13; 42 | return v14; 43 | } 44 | virtual void addEnergyGradientTo(const VectorXd& x, const VectorXd& X, VectorXd& grad) { 45 | Vector2d p = x.segment<2>(2*nodeIndex); 46 | 47 | double v2 = k; 48 | double v3 = p[0]; 49 | double v4 = targetPosition[0]; 50 | double v5 = v3 - v4; 51 | double v6 = v5 + v5; 52 | double v7 = 0.500000; 53 | double v8 = v7 * v2; 54 | double v9 = v6 * v8; 55 | double v10 = p[1]; 56 | double v11 = targetPosition[1]; 57 | double v12 = v10 - v11; 58 | double v13 = v12 + v12; 59 | double v14 = v13 * v8; 60 | grad[2*nodeIndex + 0] += v9; 61 | grad[2*nodeIndex + 1] += v14; 62 | } 63 | virtual void addEnergyHessianTo(const VectorXd& x, const VectorXd& X, std::vector& hesEntries){ 64 | double v0 = k; 65 | double v1 = 2.000000; 66 | double v2 = 0.500000; 67 | double v3 = v2 * v0; 68 | double v4 = v1 * v3; 69 | double v5 = 0.000000; 70 | hesEntries.push_back(Tripletd(2*nodeIndex+0,2*nodeIndex+0,v4)); 71 | hesEntries.push_back(Tripletd(2*nodeIndex+0,2*nodeIndex+1,v5)); 72 | hesEntries.push_back(Tripletd(2*nodeIndex+1,2*nodeIndex+0,v5)); 73 | hesEntries.push_back(Tripletd(2*nodeIndex+1,2*nodeIndex+1,v4)); 74 | } 75 | 76 | void setTargetPosition(const Vector2d &p) { 77 | targetPosition = p; 78 | } 79 | 80 | private: 81 | double k; 82 | int nodeIndex; 83 | Vector2d targetPosition; 84 | }; 85 | -------------------------------------------------------------------------------- /assignment5/src/femLib/SimulationMesh.cpp: -------------------------------------------------------------------------------- 1 | #include "SimulationMesh.h" 2 | 3 | #include 4 | #include 5 | #include "FEMElementAnalytic.h" 6 | #include "FixedPointElement.h" 7 | #include "Spring.h" 8 | 9 | SimulationMesh::SimulationMesh(){ 10 | energyFunction = new TotalEnergyFunction(this); 11 | } 12 | 13 | SimulationMesh::~SimulationMesh(){ 14 | delete energyFunction; 15 | } 16 | 17 | void SimulationMesh::generateSquareTriMesh(SimulationMesh::TriangleMesh &triMesh, double startX, double startY, double dX, double dY, int xSize, int ySize) { 18 | triMesh.v.resize(xSize*ySize); 19 | for (int i=0; ielements.clear(); 58 | for (int i=0; i nodes; 62 | nodes[0] = triangles[i][j]; 63 | int j2 = (j<2) ? j+1 : 0; 64 | nodes[1] = triangles[i][j2]; 65 | Spring* spring = new Spring(nodes, X); 66 | energyFunction->elements.push_back(spring); 67 | } 68 | } 69 | 70 | Vector2d pMin = {HUGE_VAL, HUGE_VAL}; 71 | Vector2d pMax = {-HUGE_VAL, -HUGE_VAL}; 72 | for (int i = 0; i < X.size()/2; ++i) { 73 | for (int j = 0; j < 2; ++j) { 74 | pMin[j] = std::min(pMin[j], X[2*i+j]); 75 | pMax[j] = std::max(pMax[j], X[2*i+j]); 76 | } 77 | } 78 | 79 | m.setZero(); 80 | double massDensity = 1.0; 81 | double totalMass = massDensity*((pMax[0]-pMin[0])*(pMax[1]-pMin[1])); 82 | double massPerNode = totalMass / (X.size()/2); 83 | for (int j=0; jm[j] = massPerNode; 85 | } 86 | 87 | void SimulationMesh::addGravityForces(const Vector2d &g){ 88 | for (size_t i=0;i(); 102 | } 103 | 104 | void SimulationMesh::solveNewtonsMethod() 105 | { 106 | solve_statics(); 107 | } 108 | 109 | void SimulationMesh::testGradient() 110 | { 111 | xSolver = X; 112 | 113 | double functionValue = energyFunction->computeValue(xSolver); 114 | 115 | GradientDescentFunctionMinimizer minimizer(1e5, 1e0); 116 | minimizer.minimize(energyFunction, xSolver); 117 | 118 | x = xSolver; 119 | 120 | VectorXd defEnergyPerNode; 121 | computeDefoEnergyPerNode(defEnergyPerNode); 122 | double maxIndex = defEnergyPerNode.maxCoeff(); 123 | double minIndex = defEnergyPerNode.minCoeff(); 124 | 125 | std::cout << "total energy = " << energyFunction->computeValue(xSolver) << std::endl; 126 | std::cout << "# iterations = " << minimizer.getLastIterations() << std::endl; 127 | std::cout << "min def at = " << minIndex << std::endl; 128 | std::cout << "max def at = " << maxIndex << std::endl; 129 | 130 | } 131 | 132 | void SimulationMesh::testHessian() 133 | { 134 | xSolver = X; 135 | 136 | double functionValue = energyFunction->computeValue(xSolver); 137 | 138 | NewtonFunctionMinimizer minimizer(1e5); 139 | minimizer.minimize(energyFunction, xSolver); 140 | 141 | x = xSolver; 142 | 143 | VectorXd defEnergyPerNode; 144 | computeDefoEnergyPerNode(defEnergyPerNode); 145 | double maxIndex = defEnergyPerNode.maxCoeff(); 146 | double minIndex = defEnergyPerNode.minCoeff(); 147 | 148 | std::cout << "total energy = " << energyFunction->computeValue(xSolver) << std::endl; 149 | std::cout << "# iterations = " << minimizer.getLastIterations() << std::endl; 150 | std::cout << "min def at = " << minIndex << std::endl; 151 | std::cout << "max def at = " << maxIndex << std::endl; 152 | } 153 | 154 | void SimulationMesh::togglePinnedNode(int i) 155 | { 156 | auto it = std::find_if(pinnedNodeElements.begin(), pinnedNodeElements.end(), 157 | [i](Element *e){ 158 | return e->getNodeIndex(0) == i; 159 | }); 160 | if(it == pinnedNodeElements.end()) 161 | setPinnedNode(i, { x[2*i+0], x[2*i+1] }); 162 | else 163 | unpinNode(i); 164 | } 165 | 166 | void SimulationMesh::setPinnedNode(int nodeIndex, const Vector2d &point) 167 | { 168 | for (auto it = pinnedNodeElements.begin(); it != pinnedNodeElements.end(); ++it) { 169 | FixedPointElement* fps = dynamic_cast(*it); 170 | if (fps->getNodeIndex(0) == nodeIndex) { 171 | fps->setTargetPosition(point); 172 | return; 173 | } 174 | } 175 | pinnedNodeElements.push_back(new FixedPointElement(nodeIndex, point)); 176 | } 177 | 178 | void SimulationMesh::unpinNode(int nodeIndex) 179 | { 180 | for (auto it = pinnedNodeElements.begin(); it != pinnedNodeElements.end(); ++it) { 181 | FixedPointElement* fps = dynamic_cast(*it); 182 | if (fps->getNodeIndex(0) == nodeIndex) { 183 | pinnedNodeElements.erase(it); 184 | break; 185 | } 186 | } 187 | } 188 | 189 | void SimulationMesh::computeDefoEnergyPerNode(VectorXd &defEnergyPerNode) 190 | { 191 | defEnergyPerNode.resize(numNodes); 192 | defEnergyPerNode.setZero(); 193 | 194 | for (auto element : energyFunction->elements) { 195 | double energy = element->getEnergy(x, X); 196 | for (int i = 0; i < element->getNumNodes(); ++i) { 197 | defEnergyPerNode[element->getNodeIndex(i)] += energy / (double)element->getNumNodes(); 198 | } 199 | } 200 | } 201 | 202 | void SimulationMesh::clear(){ 203 | numNodes = 0; 204 | energyFunction->elements.clear(); 205 | pinnedNodeElements.clear(); 206 | } 207 | -------------------------------------------------------------------------------- /assignment5/src/femLib/SimulationMesh.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Element.h" 4 | #include "TotalEnergyFunction.h" 5 | 6 | /** 7 | This class implements a generic sim mesh for deformable objects: collection of nodes connected to each other using different types of elements 8 | */ 9 | class SimulationMesh { 10 | 11 | public: 12 | SimulationMesh(); 13 | ~SimulationMesh(); 14 | 15 | // create and load meshes 16 | struct TriangleMesh { 17 | std::vector v; // vertices 18 | std::vector> tri; // triangles 19 | }; 20 | static void generateSquareTriMesh(TriangleMesh &triMesh, double startX=-4.5, double startY=0, double dX=1, double dY=1, int xSize=10, int ySize=10); 21 | void loadTriangleMesh(const TriangleMesh &triMesh); 22 | void createSpringsFromTriangles(); 23 | template void createElementsFromTriangles(); 24 | 25 | // add external forces 26 | void addGravityForces(const Vector2d &g); 27 | void applyForceAt(int i, const Vector2d &force); 28 | 29 | // solve 30 | template void solve_statics(); 31 | void solveGradientDescent(); 32 | void solveNewtonsMethod(); 33 | 34 | // used for the report 35 | void testGradient(); 36 | void testHessian(); 37 | 38 | // pinned nodes 39 | void togglePinnedNode(int i); 40 | void setPinnedNode(int nodeIndex, const Vector2d& point); 41 | void unpinNode(int nodeIndex); 42 | 43 | void computeDefoEnergyPerNode(Eigen::VectorXd &defEnergyPerNode); 44 | 45 | void clear(); 46 | 47 | public: 48 | // number of nodes 49 | int numNodes, numElements; 50 | 51 | // for each node we will store the position and velocity, rest configuration, mass and external forces acting on it 52 | VectorXd x, m, f_ext, X, xSolver; 53 | 54 | // list of elements that connects the nodes to each other 55 | std::vector> triangles; 56 | 57 | // a list of temporary used to pin points to locations that are fixed in space... 58 | std::vector pinnedNodeElements; 59 | 60 | //this is the objective function that we use for simulations... 61 | TotalEnergyFunction* energyFunction; 62 | }; 63 | 64 | 65 | 66 | template 67 | void SimulationMesh::createElementsFromTriangles() 68 | { 69 | energyFunction->elements.clear(); 70 | for (int i=0; ielements.push_back(newElem); 73 | } 74 | 75 | // update mass 76 | m.setZero(); 77 | for(auto e : energyFunction->elements) { 78 | for (int i = 0; i < e->getNumNodes(); ++i) { 79 | for (int j=0; j<2; j++) 80 | this->m[2*e->getNodeIndex(i) + j] += e->getMass() / (double)e->getNumNodes(); 81 | } 82 | } 83 | } 84 | 85 | template 86 | void SimulationMesh::solve_statics(){ 87 | xSolver = x; 88 | 89 | double functionValue = energyFunction->computeValue(xSolver); 90 | 91 | Minimizer minimizer(50); 92 | minimizer.minimize(energyFunction, xSolver); 93 | 94 | x = xSolver; 95 | } 96 | -------------------------------------------------------------------------------- /assignment5/src/femLib/Spring.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Element.h" 4 | 5 | /** 6 | This class implements the interface for an elementary energy unit. As a function of deformed, undeformed, 7 | and other parameters, such as boundary conditions, each class that extends this one will define a potential energy. 8 | The deformed energy depends on a number of nodes. 9 | */ 10 | class Spring : public Element { 11 | 12 | public: 13 | Spring(const std::array &nodeIndices, const VectorXd &X) 14 | : nodeIndices(nodeIndices) { 15 | } 16 | virtual ~Spring() {} 17 | 18 | // Returns the number of nodes this unit depends on 19 | virtual int getNumNodes() const { 20 | return 2; 21 | } 22 | // Returns the global index of node `i` 23 | virtual int getNodeIndex(int i) const { 24 | return nodeIndices[i]; 25 | } 26 | 27 | // Returns the element's mass 28 | virtual double getMass() const { 29 | return 0; 30 | } 31 | 32 | // Returns the energy value given deformed `x` and undeformed `X` state 33 | virtual double getEnergy(const VectorXd& x, const VectorXd& X) { 34 | 35 | // Ex 1.2 36 | // Task: Given `x` and `X`, return the spring energy. 37 | 38 | // Some notes: 39 | // `x` and `X` contain the current and rest positions of all 40 | // nodes. You can extract the position of e.g. node 0 like this: 41 | // Vector2d x1 = getVertex(0, x); 42 | // or to get the rest position of node 0: 43 | // Vector X1 = getVertex(0, X); 44 | // The spring stiffness is stored in the variable `k`. 45 | 46 | return 0; 47 | } 48 | 49 | // Adds the gradient to `grad` given deformed `x` and undeformed `X` state 50 | virtual void addEnergyGradientTo(const VectorXd& x, const VectorXd& X, VectorXd& grad) { 51 | 52 | // Ex 1.2 53 | // Task: Given `x` and `X`, add the gradient of the spring energy to `grad`. 54 | 55 | // Again, you can extract the position of e.g. node 0 like this: 56 | // Vector2d x1 = getVertex(0, x); 57 | // and the spring stiffness is stored in `k`. 58 | 59 | // Remember that `grad` is a vector of size 2*N, where N is the total 60 | // number of nodes in the system. Make sure you are writing to the 61 | // correct location in `grad`. To get the global index of node 0 of 62 | // this spring, use this function: 63 | // int globalIndex0 = getNodeIndex(0); 64 | // or for node 1 65 | // int globalIndex1 = getNodeIndex(1); 66 | } 67 | 68 | // Adds the hessian entries to `hesEntries` given deformed `x` and undeformed `X` state 69 | virtual void addEnergyHessianTo(const VectorXd& x, const VectorXd& X, std::vector& hesEntries) { 70 | 71 | // Ex 1.4 72 | // Task: Given `x` and `X`, add the hessian of the spring energy to `hesEntries`. 73 | 74 | } 75 | 76 | protected: 77 | // the collection of nodes that define the triangle element 78 | std::array nodeIndices; 79 | // spring stiffness 80 | double k = 20.0; 81 | }; 82 | -------------------------------------------------------------------------------- /assignment5/src/femLib/TotalEnergyFunction.cpp: -------------------------------------------------------------------------------- 1 | #include "TotalEnergyFunction.h" 2 | #include "SimulationMesh.h" 3 | 4 | TotalEnergyFunction::TotalEnergyFunction(SimulationMesh *simMesh) 5 | : simMesh(simMesh) { 6 | } 7 | 8 | TotalEnergyFunction::~TotalEnergyFunction(void){ 9 | } 10 | 11 | //The net energy is: 1/2 a'M a + E + x'F, where E is the potential energy stored in the various elements 12 | double TotalEnergyFunction::computeValue(const VectorXd& x){ 13 | double totalEnergy = 0; 14 | 15 | for (size_t i=0;igetEnergy(x, simMesh->X); 17 | 18 | for (size_t i=0;ipinnedNodeElements.size();i++) 19 | totalEnergy += simMesh->pinnedNodeElements[i]->getEnergy(x, simMesh->X); 20 | 21 | totalEnergy -= x.dot(simMesh->f_ext); 22 | 23 | return totalEnergy; 24 | } 25 | 26 | void TotalEnergyFunction::addGradientTo(VectorXd& grad, const VectorXd& x) { 27 | if (grad.size() != x.size()) 28 | resize(grad, x.size()); 29 | 30 | //take into account the gradient of the deformation energy 31 | for (size_t i=0;iaddEnergyGradientTo(x, simMesh->X, grad); 33 | 34 | for (size_t i=0;ipinnedNodeElements.size();i++) 35 | simMesh->pinnedNodeElements[i]->addEnergyGradientTo(x, simMesh->X, grad); 36 | 37 | grad -= simMesh->f_ext; 38 | } 39 | 40 | 41 | void TotalEnergyFunction::addHessianEntriesTo(std::vector& hessianEntries, const VectorXd& x) { 42 | for (size_t i = 0;i < elements.size();i++) 43 | elements[i]->addEnergyHessianTo(x, simMesh->X, hessianEntries); 44 | 45 | for (size_t i = 0;i < simMesh->pinnedNodeElements.size();i++) 46 | simMesh->pinnedNodeElements[i]->addEnergyHessianTo(x, simMesh->X, hessianEntries); 47 | } 48 | -------------------------------------------------------------------------------- /assignment5/src/femLib/TotalEnergyFunction.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "Element.h" 6 | 7 | class SimulationMesh; 8 | 9 | class TotalEnergyFunction : public ObjectiveFunction { 10 | public: 11 | TotalEnergyFunction(SimulationMesh* simMesh); 12 | virtual ~TotalEnergyFunction(void); 13 | 14 | virtual double computeValue(const VectorXd& s); 15 | virtual void addGradientTo(VectorXd& grad, const VectorXd& s); 16 | 17 | virtual void addHessianEntriesTo(std::vector& hessianEntries, const VectorXd& s); 18 | 19 | std::vector elements; 20 | 21 | private: 22 | SimulationMesh* simMesh; 23 | 24 | }; 25 | -------------------------------------------------------------------------------- /assignment5/src/gui_utils.cpp: -------------------------------------------------------------------------------- 1 | #include "gui_utils.h" 2 | 3 | int pick_face(igl::viewer::Viewer& viewer, int mouse_x, int mouse_y, const Eigen::MatrixXd& V, const Eigen::MatrixXi& F) { 4 | // Cast a ray in the view direction starting from the mouse position 5 | double x = mouse_x; 6 | double y = viewer.core.viewport(3) - mouse_y; 7 | 8 | Eigen::RowVector3d pt; 9 | 10 | Eigen::Matrix4f modelview = viewer.core.view * viewer.data.model; 11 | int vi = -1; 12 | 13 | std::vector hits; 14 | 15 | igl::unproject_in_mesh(Eigen::Vector2f(x,y), viewer.core.view * viewer.data.model, 16 | viewer.core.proj, viewer.core.viewport, V, F, pt,hits); 17 | 18 | int fi = -1; 19 | if (hits.size()> 0) { 20 | fi = hits[0].id; 21 | } 22 | return fi; 23 | } 24 | 25 | int pick_vertex(igl::viewer::Viewer& viewer, int mouse_x, int mouse_y, const Eigen::MatrixXd& V, const Eigen::MatrixXi& F) { 26 | // Cast a ray in the view direction starting from the mouse position 27 | double x = mouse_x; 28 | double y = viewer.core.viewport(3) - mouse_y; 29 | 30 | Eigen::RowVector3d pt; 31 | 32 | Eigen::Matrix4f modelview = viewer.core.view * viewer.data.model; 33 | int vi = -1; 34 | 35 | std::vector hits; 36 | /* 37 | igl::unproject_in_mesh(Eigen::Vector2f(x,y), 38 | modelview, 39 | viewer.core.proj, 40 | viewer.core.viewport, 41 | ei,pt,hits); 42 | */ 43 | 44 | igl::unproject_in_mesh(Eigen::Vector2f(x,y), viewer.core.view * viewer.data.model, 45 | viewer.core.proj, viewer.core.viewport, V, F, pt,hits); 46 | 47 | if (hits.size()> 0) { 48 | int fi = hits[0].id; 49 | Eigen::RowVector3d bc; 50 | bc << 1.0-hits[0].u-hits[0].v, hits[0].u, hits[0].v; 51 | bc.maxCoeff(&vi); 52 | vi = F(fi,vi); 53 | } 54 | return vi; 55 | } 56 | 57 | //computes translation for the vertices of the moving handle based on the mouse motion 58 | Eigen::Vector3f computePosition (igl::viewer::Viewer& viewer, 59 | int mouse_x, 60 | int mouse_y, 61 | Eigen::RowVector3d pt3D) { 62 | Eigen::Matrix4f modelview = viewer.core.view * viewer.data.model; 63 | //project the given point (typically the handle centroid) to get a screen space depth 64 | Eigen::Vector3f proj = igl::project(pt3D.transpose().cast().eval(), 65 | modelview, 66 | viewer.core.proj, 67 | viewer.core.viewport); 68 | float depth = proj[2]; 69 | 70 | double x, y; 71 | Eigen::Vector3f pos; 72 | 73 | //unproject from- and to- points 74 | x = mouse_x; 75 | y = viewer.core.viewport(3) - mouse_y; 76 | pos = igl::unproject(Eigen::Vector3f(x,y,depth), 77 | modelview, 78 | viewer.core.proj, 79 | viewer.core.viewport); 80 | 81 | return pos; 82 | } 83 | 84 | //computes translation for the vertices of the moving handle based on the mouse motion 85 | Eigen::Vector3f computeTranslation (igl::viewer::Viewer& viewer, 86 | int mouse_x, 87 | int from_x, 88 | int mouse_y, 89 | int from_y, 90 | Eigen::RowVector3d pt3D) { 91 | Eigen::Matrix4f modelview = viewer.core.view * viewer.data.model; 92 | //project the given point (typically the handle centroid) to get a screen space depth 93 | Eigen::Vector3f proj = igl::project(pt3D.transpose().cast().eval(), 94 | modelview, 95 | viewer.core.proj, 96 | viewer.core.viewport); 97 | float depth = proj[2]; 98 | 99 | double x, y; 100 | Eigen::Vector3f pos1, pos0; 101 | 102 | //unproject from- and to- points 103 | x = mouse_x; 104 | y = viewer.core.viewport(3) - mouse_y; 105 | pos1 = igl::unproject(Eigen::Vector3f(x,y,depth), 106 | modelview, 107 | viewer.core.proj, 108 | viewer.core.viewport); 109 | 110 | 111 | x = from_x; 112 | y = viewer.core.viewport(3) - from_y; 113 | pos0 = igl::unproject(Eigen::Vector3f(x,y,depth), 114 | modelview, 115 | viewer.core.proj, 116 | viewer.core.viewport); 117 | 118 | //translation is the vector connecting the two 119 | Eigen::Vector3f translation; 120 | translation = pos1 - pos0; 121 | 122 | return translation; 123 | } 124 | 125 | Eigen::Vector4f computeRotation(igl::viewer::Viewer& viewer, 126 | int mouse_x, 127 | int from_x, 128 | int mouse_y, 129 | int from_y, 130 | Eigen::RowVector3d pt3D) { 131 | 132 | Eigen::Vector4f rotation; 133 | rotation.setZero(); 134 | rotation[3] = 1.; 135 | 136 | Eigen::Matrix4f modelview = viewer.core.view * viewer.data.model; 137 | 138 | //initialize a trackball around the handle that is being rotated 139 | //the trackball has (approximately) width w and height h 140 | double w = viewer.core.viewport[2]/8; 141 | double h = viewer.core.viewport[3]/8; 142 | 143 | //the mouse motion has to be expressed with respect to its center of mass 144 | //(i.e. it should approximately fall inside the region of the trackball) 145 | 146 | //project the given point on the handle(centroid) 147 | Eigen::Vector3f proj = igl::project(pt3D.transpose().cast().eval(), 148 | modelview, 149 | viewer.core.proj, 150 | viewer.core.viewport); 151 | proj[1] = viewer.core.viewport[3] - proj[1]; 152 | 153 | //express the mouse points w.r.t the centroid 154 | from_x -= proj[0]; mouse_x -= proj[0]; 155 | from_y -= proj[1]; mouse_y -= proj[1]; 156 | 157 | //shift so that the range is from 0-w and 0-h respectively (similarly to a standard viewport) 158 | from_x += w/2; mouse_x += w/2; 159 | from_y += h/2; mouse_y += h/2; 160 | 161 | //get rotation from trackball 162 | Eigen::Vector4f drot = viewer.core.trackball_angle.coeffs(); 163 | Eigen::Vector4f drot_conj; 164 | igl::quat_conjugate(drot.data(), drot_conj.data()); 165 | igl::trackball(w, h, float(1.), rotation.data(), from_x, from_y, mouse_x, mouse_y, rotation.data()); 166 | 167 | //account for the modelview rotation: prerotate by modelview (place model back to the original 168 | //unrotated frame), postrotate by inverse modelview 169 | Eigen::Vector4f out; 170 | igl::quat_mult(rotation.data(), drot.data(), out.data()); 171 | igl::quat_mult(drot_conj.data(), out.data(), rotation.data()); 172 | return rotation; 173 | } 174 | -------------------------------------------------------------------------------- /assignment5/src/gui_utils.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | 9 | int pick_face(igl::viewer::Viewer& viewer, int mouse_x, int mouse_y, const Eigen::MatrixXd& V, const Eigen::MatrixXi& F); 10 | int pick_vertex(igl::viewer::Viewer& viewer, int mouse_x, int mouse_y, const Eigen::MatrixXd& V, const Eigen::MatrixXi& F); 11 | 12 | Eigen::Vector3f computePosition(igl::viewer::Viewer& viewer, int mouse_x, int mouse_y, Eigen::RowVector3d pt3D); 13 | Eigen::Vector3f computeTranslation(igl::viewer::Viewer& viewer,int mouse_x,int from_x,int mouse_y,int from_y,Eigen::RowVector3d pt3D); 14 | Eigen::Vector4f computeRotation(igl::viewer::Viewer& viewer, int mouse_x, int from_x, int mouse_y, int from_y, Eigen::RowVector3d pt3D); 15 | 16 | void update_display(igl::viewer::Viewer& viewer,const Eigen::MatrixXd& V, const Eigen::MatrixXi& F); 17 | -------------------------------------------------------------------------------- /assignment5/src/optLib/AutoDiff.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | template 8 | class AutoDiff 9 | { 10 | public: 11 | AutoDiff() { 12 | } 13 | 14 | template 15 | AutoDiff(const T &c) : m_x((Value)c), m_d((Deriv)0) { 16 | } 17 | 18 | AutoDiff(const Value &x, const Deriv &d) : m_x(x), m_d(d) { 19 | } 20 | 21 | bool operator==(const AutoDiff &other) const { 22 | return other.value() == this->value(); 23 | } 24 | 25 | bool operator!=(const AutoDiff &other) const { 26 | return other.value() != this->value(); 27 | } 28 | 29 | AutoDiff operator+(const AutoDiff &other) const { 30 | return AutoDiff(m_x + other.m_x, m_d + other.m_d); 31 | } 32 | 33 | AutoDiff operator-(const AutoDiff &other) const { 34 | return AutoDiff(m_x - other.m_x, m_d - other.m_d); 35 | } 36 | 37 | AutoDiff operator-() const { 38 | return AutoDiff(-m_x, -m_d); 39 | } 40 | 41 | AutoDiff operator*(const AutoDiff &other) const { 42 | // D(x*y) = x*dy + dx*y 43 | return AutoDiff(m_x * other.m_x, other.m_d * m_x + m_d * other.m_x); 44 | } 45 | 46 | AutoDiff operator/(const AutoDiff &other) const { 47 | // D(x/y) = (dx*y - x*dy) / y*y 48 | Value x2 = other.m_x * other.m_x; 49 | return AutoDiff(m_x / other.m_x, m_d*(other.m_x/x2) - other.m_d*(m_x/x2)); 50 | } 51 | 52 | AutoDiff &operator+=(const AutoDiff &other) { 53 | m_x = m_x + other.m_x; 54 | m_d = m_d + other.m_d; 55 | return *this; 56 | } 57 | 58 | AutoDiff &operator-=(const AutoDiff &other) { 59 | m_x = m_x - other.m_x; 60 | m_d = m_d - other.m_d; 61 | 62 | return *this; 63 | } 64 | 65 | AutoDiff &operator*=(const AutoDiff &other) { 66 | *this = *this * other; 67 | return *this; 68 | } 69 | 70 | AutoDiff &operator/=(const AutoDiff &other) { 71 | *this = *this / other; 72 | return *this; 73 | } 74 | 75 | bool operator>(const AutoDiff &d) const { 76 | return m_x > d.m_x; 77 | } 78 | 79 | bool operator<(const AutoDiff &d) const { 80 | return m_x < d.m_x; 81 | } 82 | 83 | bool operator>=(const AutoDiff &d) const { 84 | return m_x >= d.m_x; 85 | } 86 | 87 | bool operator<=(const AutoDiff &d) const { 88 | return m_x <= d.m_x; 89 | } 90 | 91 | const Value &value() const { return m_x; } 92 | Value &value() { return m_x; } 93 | 94 | const Deriv &deriv() const { return m_d; } 95 | Deriv &deriv() { return m_d; } 96 | 97 | private: 98 | Value m_x; // value 99 | Deriv m_d; // derivative 100 | }; 101 | 102 | template 103 | AutoDiff operator+(const Value &a, const AutoDiff &y) 104 | { 105 | // d(a+y) = dy/dx 106 | return AutoDiff(a + y.value(), y.deriv()); 107 | } 108 | 109 | template 110 | AutoDiff operator-(const Value &a, const AutoDiff &y) 111 | { 112 | // d(a-y) = -dy/dx 113 | return AutoDiff(a - y.value(), -y.deriv()); 114 | } 115 | 116 | template 117 | AutoDiff operator*(const Value &a, const AutoDiff &y) 118 | { 119 | // d(a*y)/dx = a*dy/dx 120 | return AutoDiff(a * y.value(), a * y.deriv()); 121 | } 122 | 123 | // TODO: test this! 124 | template 125 | AutoDiff operator*(const S &a, const AutoDiff &y) 126 | { 127 | // d(a*y)/dx = a*dy/dx 128 | return AutoDiff(a * y.value(), a * y.deriv()); 129 | } 130 | 131 | template 132 | AutoDiff operator/(const Value &a, const AutoDiff &y) 133 | { 134 | // D(a/y) = -a/y^2 * dy/dx 135 | return AutoDiff(a / y.value(), -a / (y.value() * y.value()) * y.deriv()); 136 | } 137 | 138 | template 139 | AutoDiff sin(const AutoDiff &y) 140 | { 141 | // d(sin(y))/dx = cos(y) * dy/dx 142 | return AutoDiff(sin(y.value()), cos(y.value()) * y.deriv()); 143 | } 144 | 145 | template 146 | AutoDiff cos(const AutoDiff &y) 147 | { 148 | // d(cos(y))/dx = -sin(y) * dy/dx 149 | return AutoDiff(cos(y.value()), -sin(y.value()) * y.deriv()); 150 | } 151 | 152 | template 153 | AutoDiff tan(const AutoDiff &y) 154 | { 155 | Value tanValue = tan(y.value()); 156 | 157 | // d(tan(y))/dx = (1 + tan(y)^2) * dy/dx 158 | return AutoDiff(tanValue, ((Value)1 + tanValue*tanValue) * y.deriv()); 159 | } 160 | 161 | template 162 | AutoDiff acos(const AutoDiff &y) 163 | { 164 | // d(acos(x))/dx = -1/sqrt(1-y*y) * dy/dx 165 | return AutoDiff(acos(y.value()), (Value(-1)/sqrt(Value(1)-y.value()*y.value())) * y.deriv()); 166 | } 167 | 168 | template 169 | AutoDiff sqrt(const AutoDiff &y) 170 | { 171 | // d(sqrt(y))/dx = 1/2 * 1/sqrt(y) * dy/dx 172 | return AutoDiff(sqrt(y.value()), Value(1)/Value(2) * Value(1)/sqrt(y.value()) * y.deriv()); 173 | } 174 | 175 | template 176 | AutoDiff log(const AutoDiff &y) 177 | { 178 | // d(log(y))/dx = 1.0 / y * dy/dx 179 | return AutoDiff(log(y.value()), Value(1)/y.value() * y.deriv()); 180 | } 181 | 182 | template 183 | AutoDiff pow(const AutoDiff &y, const double &a) 184 | { 185 | // d(y^a)/dx = a*y^{a-1} * dy/dx 186 | return AutoDiff(pow(y.value(), a), a*pow(y.value(), a-1) * y.deriv()); 187 | } 188 | 189 | template 190 | AutoDiff pow(const AutoDiff &y1, const AutoDiff &y2) 191 | { 192 | // D(y1^y2) = y1^y2 * (dy1/dx*ln(y2) + (y2*dy1/dx)/y1) 193 | return AutoDiff(pow(y1.value(), y2.value()), 194 | pow(y1.value(), y2.value()) * (y2.deriv()*log(y1.value()) + y2.value()*y1.deriv()/y1.value())); 195 | } 196 | 197 | template 198 | AutoDiff fabs(const AutoDiff &s) 199 | { 200 | if(s.value() >= 0) 201 | return s; 202 | else 203 | return -s; 204 | } 205 | 206 | template 207 | std::ostream& operator<<(std::ostream& stream, const AutoDiff &s) { 208 | stream << s.value() << "(" << s.deriv() << ")"; 209 | return stream; 210 | } 211 | -------------------------------------------------------------------------------- /assignment5/src/optLib/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.6) 2 | 3 | project(optLib CXX) 4 | 5 | set (CMAKE_CXX_STANDARD 11) 6 | FILE(GLOB SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/*.h ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp) 7 | 8 | add_library(${PROJECT_NAME} ${SOURCES}) 9 | set_target_properties(${PROJECT_NAME} PROPERTIES LINKER_LANGUAGE CXX) 10 | target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) 11 | -------------------------------------------------------------------------------- /assignment5/src/optLib/GradientDescentFunctionMinimizer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "ObjectiveFunction.h" 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | class GradientDescentFunctionMinimizer{ 11 | public: 12 | GradientDescentFunctionMinimizer(int maxIterations=100, double solveResidual=1e-5, int maxLineSearchIterations=15) 13 | : maxIterations(maxIterations), solveResidual(solveResidual), maxLineSearchIterations(maxLineSearchIterations){ 14 | } 15 | 16 | virtual ~GradientDescentFunctionMinimizer(){} 17 | 18 | int getLastIterations() { return lastIterations; } 19 | 20 | virtual bool minimize(ObjectiveFunction *function, VectorXd &x){ 21 | 22 | //number of parameters... 23 | int N = (int) x.size(); 24 | resize(xi, N); 25 | resize(dx, N); 26 | resize(gradient, N); 27 | 28 | xi = x; 29 | 30 | bool optimizationConverged = false; 31 | 32 | int i=0; 33 | for(; i < maxIterations; i++) { 34 | computeSearchDirection(function, xi, dx); 35 | 36 | if (dx.norm() < solveResidual){ 37 | optimizationConverged = true; 38 | break; 39 | } 40 | 41 | doLineSearch(function, dx, xi); 42 | } 43 | 44 | lastIterations = i; 45 | 46 | //p now holds the parameter values at the start of the iteration... 47 | x = xi; 48 | 49 | //and done! 50 | return optimizationConverged; 51 | } 52 | 53 | protected: 54 | // Since the gradient of a function gives the direction of steepest descent, all one needs to do is go in that direction... 55 | virtual void computeSearchDirection(ObjectiveFunction *function, const VectorXd &x, VectorXd& dx) { 56 | 57 | // Ex. 1.1 58 | 59 | } 60 | 61 | virtual void doLineSearch(ObjectiveFunction *function, const VectorXd& dx, VectorXd& xi) 62 | { 63 | 64 | // Ex. 1.1 65 | 66 | } 67 | 68 | protected: 69 | double solveResidual = 1e-5; 70 | int maxIterations = 100; 71 | int maxLineSearchIterations = 15; 72 | 73 | VectorXd xi, dx, gradient; 74 | 75 | // some stats about the last time `minimize` was called 76 | int lastIterations = -1; 77 | }; 78 | -------------------------------------------------------------------------------- /assignment5/src/optLib/MathHelper.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | //#pragma warning( disable : 4996) 4 | 5 | #define EPSILON 1e-10 6 | #define TINY 0.0000001 7 | #define IS_ZERO(x) (fabs(x) 10 | #include 11 | 12 | using Eigen::VectorXd; 13 | using Eigen::MatrixXd; 14 | typedef Eigen::SparseMatrix SparseMatrixd; 15 | typedef Eigen::Triplet Tripletd; 16 | 17 | #ifdef _DEBUG // DEBUG 18 | typedef Eigen::Matrix Matrix2d; 19 | typedef Eigen::Matrix Vector2d; 20 | #else // RELEASE 21 | using Eigen::Matrix2d; 22 | using Eigen::Vector2d; 23 | #endif // _DEBUG 24 | 25 | inline void resize(SparseMatrixd& sm, int rows, int cols) { 26 | if (sm.rows() != rows || sm.cols() != cols) 27 | sm.resize(rows, cols); 28 | sm.setZero(); 29 | } 30 | 31 | inline void resize(VectorXd& v, int n) { 32 | if (v.size() != n) 33 | v.resize(n); 34 | v.setZero(); 35 | } 36 | 37 | inline void resize(MatrixXd& m, int rows, int cols) { 38 | if (m.rows() != rows || m.cols() != cols) 39 | m.resize(rows, cols); 40 | m.setZero(); 41 | } 42 | 43 | template 44 | void addSparseMatrixDenseBlockToTriplet(std::vector& triplets, int startX, int startY, const MATType& block, bool writeOnlyLowerDiagonalValues = false) { 45 | for (int i = 0; i < block.rows(); i++) 46 | for (int j = 0; j < block.cols(); j++) 47 | if (startX + i >= startY + j || !writeOnlyLowerDiagonalValues) 48 | triplets.push_back(Tripletd(startX + i, startY + j, block(i, j))); 49 | } 50 | 51 | inline double cross2d(const Vector2d &a, const Vector2d &b) { 52 | return a.x()*b.y() - b.x()*a.y(); 53 | } 54 | -------------------------------------------------------------------------------- /assignment5/src/optLib/NewtonFunctionMinimizer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "ObjectiveFunction.h" 4 | #include "GradientDescentFunctionMinimizer.h" 5 | 6 | /** 7 | use Newton's method to optimize a function. p will store the final value that minimizes the function, and its initial value 8 | is used to start the optimization method. 9 | 10 | Task: find p that minimize f(p). This means that df/dp(p) = 0. 11 | df/dp(p+dp) ~ df/dp(p) + d/dp(df/dp) * dp = 0 ==> -df/dp(p) = d/dp(df/dp) * dp 12 | Iterating the above, will hopefully get p that minimizes f. 13 | */ 14 | class NewtonFunctionMinimizer : public GradientDescentFunctionMinimizer { 15 | public: 16 | NewtonFunctionMinimizer(int maxIterations = 100, double solveResidual = 0.0001, int maxLineSearchIterations = 15) 17 | : GradientDescentFunctionMinimizer(maxIterations, solveResidual, maxLineSearchIterations) { } 18 | 19 | virtual ~NewtonFunctionMinimizer() {} 20 | 21 | protected: 22 | // The search direction is given by -Hinv * g 23 | virtual void computeSearchDirection(ObjectiveFunction *function, const VectorXd &x, VectorXd& dx) { 24 | 25 | // Ex 1.3 26 | 27 | } 28 | 29 | public: 30 | SparseMatrixd H; 31 | std::vector hessianEntries; 32 | }; 33 | -------------------------------------------------------------------------------- /assignment5/src/optLib/ObjectiveFunction.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "MathHelper.h" 4 | 5 | class ObjectiveFunction{ 6 | public: 7 | // this should always return the current value of the objective function 8 | virtual double computeValue(const VectorXd& x) = 0; 9 | virtual void addGradientTo(VectorXd& grad, const VectorXd& x) = 0; 10 | virtual void addHessianEntriesTo(std::vector& hessianEntries, const VectorXd& x) = 0; 11 | }; 12 | 13 | -------------------------------------------------------------------------------- /assignment5/src/optLib/RosenbrockFunction.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "ObjectiveFunction.h" 4 | 5 | class RosenbrockFunction : public ObjectiveFunction { 6 | public: 7 | 8 | RosenbrockFunction() { 9 | a = 1; b = 100; 10 | } 11 | 12 | virtual double computeValue(const VectorXd& x) { 13 | 14 | // Ex 1.1 15 | // return f(x) 16 | 17 | } 18 | 19 | virtual void addGradientTo(VectorXd& grad, const VectorXd& x) { 20 | 21 | // Ex 1.1 22 | // write df/dx in `grad` 23 | 24 | } 25 | 26 | virtual void addHessianEntriesTo(std::vector& hessianEntries, const VectorXd& x) { 27 | 28 | // Ex 1.2 29 | // write d^2f/dx^2 in `hessianEntries` 30 | } 31 | 32 | double a, b; 33 | }; 34 | -------------------------------------------------------------------------------- /assignment5/src/test_rosenbrock.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "optLib/GradientDescentFunctionMinimizer.h" 4 | #include "optLib/NewtonFunctionMinimizer.h" 5 | #include "optLib/RosenbrockFunction.h" 6 | 7 | int main(int argc, char *argv[]) { 8 | 9 | RosenbrockFunction function; 10 | 11 | // Ex 1.1: Gradient descent 12 | { 13 | GradientDescentFunctionMinimizer minimizer(10000); 14 | 15 | VectorXd x(2); x << 1.1, 1.1; 16 | bool ok = minimizer.minimize(&function, x); 17 | 18 | std::cout << "---\nGradient descent:" << std::endl; 19 | std::cout << "converged: " << ((ok) ? "yes" : "no") << std::endl; 20 | std::cout << "iterations: " << minimizer.getLastIterations() << std::endl; 21 | std::cout << "min. x: " << x.transpose() << std::endl; 22 | std::cout << "min. value: "<< function.computeValue(x) << std::endl; 23 | } 24 | 25 | // Ex 1.3: Newton's method 26 | #if 0 // set to 1 for Ex 1.3 27 | { 28 | NewtonFunctionMinimizer minimizer; 29 | 30 | VectorXd x(2); x << 1.1, 1.1; 31 | bool ok = minimizer.minimize(&function, x); 32 | 33 | std::cout << "---\nNewton's method:" << std::endl; 34 | std::cout << "converged: " << ((ok) ? "yes" : "no") << std::endl; 35 | std::cout << "iterations: " << minimizer.getLastIterations() << std::endl; 36 | std::cout << "min. x: " << x.transpose() << std::endl; 37 | std::cout << "min. value: "<< function.computeValue(x) << std::endl; 38 | } 39 | #endif 40 | 41 | } 42 | -------------------------------------------------------------------------------- /assignment6/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.6) 2 | project(assignment6) 3 | 4 | set (CMAKE_CXX_STANDARD 11) 5 | 6 | set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/cmake) 7 | 8 | find_package(LIBIGL QUIET) 9 | 10 | if (NOT LIBIGL_FOUND) 11 | message(FATAL_ERROR "libigl not found --- You can download it using: \n git clone --recursive https://github.com/libigl/libigl.git ${PROJECT_SOURCE_DIR}/../libigl") 12 | endif() 13 | 14 | # Compilation flags: adapt to your needs 15 | if(MSVC) 16 | # Enable parallel compilation 17 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MP /bigobj") 18 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG ${CMAKE_BINARY_DIR} ) 19 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE ${CMAKE_BINARY_DIR} ) 20 | else() 21 | # Libigl requires a modern C++ compiler that supports c++11 22 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") 23 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "." ) 24 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-deprecated-declarations") 25 | endif() 26 | 27 | # libigl options: choose between header only and compiled static library 28 | # Header-only is preferred for small projects. For larger projects the static build 29 | # considerably reduces the compilation times 30 | option(LIBIGL_USE_STATIC_LIBRARY "Use LibIGL as static library" OFF) 31 | 32 | # add a customizable menu bar 33 | option(LIBIGL_VIEWER_WITH_NANOGUI "Use Nanogui menu" ON) 34 | option(LIBIGL_VIEWER_WITH_NANOGUI_IO "Add mesh IO menu" ON) 35 | option(LIBIGL_VIEWER_WITH_NANOGUI_SERIALIZATION "Enable viewer serialization" ON) 36 | 37 | # libigl options: choose your dependencies (by default everything is OFF except opengl) 38 | option(LIBIGL_WITH_VIEWER "Use OpenGL viewer" ON) 39 | option(LIBIGL_WITH_OPENGL "Use OpenGL" ON) 40 | option(LIBIGL_WITH_OPENGL_GLFW "Use GLFW" ON) 41 | option(LIBIGL_WITH_BBW "Use BBW" OFF) 42 | option(LIBIGL_WITH_EMBREE "Use Embree" OFF) 43 | option(LIBIGL_WITH_PNG "Use PNG" OFF) 44 | option(LIBIGL_WITH_TETGEN "Use Tetgen" OFF) 45 | option(LIBIGL_WITH_TRIANGLE "Use Triangle" OFF) 46 | option(LIBIGL_WITH_XML "Use XML" OFF) 47 | option(LIBIGL_WITH_LIM "Use LIM" OFF) 48 | option(LIBIGL_WITH_COMISO "Use CoMiso" OFF) 49 | option(LIBIGL_WITH_MATLAB "Use Matlab" OFF) # This option is not supported yet 50 | option(LIBIGL_WITH_MOSEK "Use MOSEK" OFF) # This option is not supported yet 51 | option(LIBIGL_WITH_CGAL "Use CGAL" OFF) 52 | if(LIBIGL_WITH_CGAL) # Do not remove or move this block, the cgal build system fails without it 53 | find_package(CGAL REQUIRED) 54 | set(CGAL_DONT_OVERRIDE_CMAKE_FLAGS TRUE CACHE BOOL "CGAL's CMAKE Setup is super annoying ") 55 | include(${CGAL_USE_FILE}) 56 | endif() 57 | 58 | # Adding libigl: choose the path to your local copy libigl 59 | # This is going to compile everything you requested 60 | #message(FATAL_ERROR "${PROJECT_SOURCE_DIR}/../libigl/cmake") 61 | add_subdirectory("${LIBIGL_INCLUDE_DIR}/../shared/cmake" "libigl") 62 | 63 | # set(EIGEN3_INCLUDE_DIR "${LIBIGL_INCLUDE_DIR}/../external/nanogui/ext/eigen") 64 | # set(AUTOGEN_BUILD_TESTS FALSE) 65 | # add_subdirectory("../autogen" "autogen") 66 | 67 | # libigl information 68 | message("libigl includes: ${LIBIGL_INCLUDE_DIRS}") 69 | message("libigl libraries: ${LIBIGL_LIBRARIES}") 70 | message("libigl extra sources: ${LIBIGL_EXTRA_SOURCES}") 71 | message("libigl extra libraries: ${LIBIGL_EXTRA_LIBRARIES}") 72 | message("libigl definitions: ${LIBIGL_DEFINITIONS}") 73 | 74 | # Prepare the build environment 75 | include_directories(${LIBIGL_INCLUDE_DIRS}) 76 | add_definitions(${LIBIGL_DEFINITIONS}) 77 | 78 | add_subdirectory(src/femLib) 79 | add_subdirectory(src/optLib) 80 | include_directories(src/optLib) 81 | 82 | FILE(GLOB SOURCES src/main.cpp src/gui_utils.cpp) 83 | add_executable(${PROJECT_NAME}_bin ${SOURCES} ${LIBIGL_EXTRA_SOURCES}) 84 | target_link_libraries(${PROJECT_NAME}_bin ${LIBIGL_LIBRARIES} ${LIBIGL_EXTRA_LIBRARIES} femLib optLib) 85 | 86 | FILE(GLOB SOURCES src/test_SQP.cpp) 87 | add_executable(${PROJECT_NAME}_test_SQP ${SOURCES}) 88 | target_link_libraries(${PROJECT_NAME}_test_SQP ${LIBIGL_LIBRARIES} ${LIBIGL_EXTRA_LIBRARIES} femLib optLib) 89 | -------------------------------------------------------------------------------- /assignment6/README.md: -------------------------------------------------------------------------------- 1 | # Assignment 6 2 | 3 | Edit this 'README.md' file to report all your results. There is no need to write lengthy reports, just show the requested outputs and screenshots and quickly summarize your observations. 4 | 5 | ## Required results 6 | 7 | See assignment! -------------------------------------------------------------------------------- /assignment6/assignment6.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eth-igl/GP2018-Assignments/895e5e30625089deccfc469c662bdc6093e9e314/assignment6/assignment6.pdf -------------------------------------------------------------------------------- /assignment6/cmake/FindLIBIGL.cmake: -------------------------------------------------------------------------------- 1 | # - Try to find the LIBIGL library 2 | # Once done this will define 3 | # 4 | # LIBIGL_FOUND - system has LIBIGL 5 | # LIBIGL_INCLUDE_DIR - **the** LIBIGL include directory 6 | # LIBIGL_INCLUDE_DIRS - LIBIGL include directories 7 | # LIBIGL_SOURCES - the LIBIGL source files 8 | if(NOT LIBIGL_FOUND) 9 | 10 | FIND_PATH(LIBIGL_INCLUDE_DIR igl/readOBJ.h 11 | ${PROJECT_SOURCE_DIR}/../../include 12 | ${PROJECT_SOURCE_DIR}/../include 13 | ${PROJECT_SOURCE_DIR}/include 14 | ${PROJECT_SOURCE_DIR}/../libigl/include 15 | ${PROJECT_SOURCE_DIR}/../../libigl/include 16 | $ENV{LIBIGL}/include 17 | $ENV{LIBIGLROOT}/include 18 | $ENV{LIBIGL_ROOT}/include 19 | $ENV{LIBIGL_DIR}/include 20 | $ENV{LIBIGL_DIR}/inc 21 | /usr/include 22 | /usr/local/include 23 | /usr/local/igl/libigl/include 24 | ) 25 | 26 | 27 | if(LIBIGL_INCLUDE_DIR) 28 | set(LIBIGL_FOUND TRUE) 29 | set(LIBIGL_INCLUDE_DIRS ${LIBIGL_INCLUDE_DIR}) 30 | #set(LIBIGL_SOURCES 31 | # ${LIBIGL_INCLUDE_DIR}/igl/viewer/Viewer.cpp 32 | #) 33 | endif() 34 | 35 | endif() 36 | -------------------------------------------------------------------------------- /assignment6/cmake/FindOOQP.cmake: -------------------------------------------------------------------------------- 1 | # TRY TO FIND THE INCLUDE DIRECTORY 2 | find_path(OOQP_INCLUDE_DIR 3 | QpGenData.h 4 | HINTS 5 | ${CMAKE_SOURCE_DIR}/../OOQP/include/ooqp 6 | $ENV{OOQP}/include/ooqp 7 | /usr/local/include/ooqp/ 8 | ${PROJECT_SOURCE_DIR}/../../libs/thirdPartyCode/OOQP/include 9 | ) 10 | 11 | # BLAS 12 | find_library(BLAS_LIBRARIES 13 | NAMES 14 | blas 15 | HINTS 16 | ${CMAKE_SOURCE_DIR}/../OOQP/lib 17 | /usr/lib/x86_64-linux-gnu/ 18 | /usr/local/libs/ 19 | ${CMAKE_SOURCE_DIR}/../libs/thirdPartyCode/CLAPACK/BLAS/Release 20 | ) 21 | if(BLAS_LIBRARIES) 22 | message(STATUS "Found BLAS libraries:" ${BLAS_LIBRARIES}) 23 | else() 24 | message(FATAL_ERROR "Could not find BLAS libraries.") 25 | endif() 26 | 27 | # Dependent packages, BLAS and HSL 28 | # set(OOQP_LIBRARIES) 29 | # find_package(BLAS REQUIRED) 30 | # if(BLAS_FOUND) 31 | # message("BLAS FOUND") 32 | # else() 33 | # message(STATUS "OOQP requires BLAS") 34 | # endif() 35 | 36 | # TODO: do we need these libs on windows? 37 | if (WIN32) 38 | # I77 39 | set(I77_LIB I77) 40 | if(WIN32) 41 | set(I77_LIB lib${I77_LIB}) 42 | endif() 43 | find_library(F2CLIBS_I77 44 | NAMES 45 | ${I77_LIB} 46 | HINTS 47 | ${CMAKE_SOURCE_DIR}/../OOQP/lib 48 | /usr/local/lib/ 49 | /usr/lib/ 50 | /usr/lib/x86_64-linux-gnu/ 51 | ${CMAKE_SOURCE_DIR}/../libs/thirdPartyCode/CLAPACK/F2CLIBS/ReleaseI77 52 | ) 53 | 54 | # I77 55 | set(F77_LIB F77) 56 | if(WIN32) 57 | set(F77_LIB lib${F77_LIB}) 58 | endif() 59 | find_library(F2CLIBS_F77 60 | NAMES 61 | ${F77_LIB} 62 | HINTS 63 | ${CMAKE_SOURCE_DIR}/../OOQP/lib 64 | /usr/local/lib/ 65 | ${CMAKE_SOURCE_DIR}/../libs/thirdPartyCode/CLAPACK/F2CLIBS/ReleaseF77 66 | ) 67 | set(F2CLIBS_LIBRARIES ${F2CLIBS_I77} ${F2CLIBS_F77}) 68 | if(F2CLIBS_LIBRARIES) 69 | message(STATUS "Found F2CLIBS libraries:" ${F2CLIBS_LIBRARIES}) 70 | else() 71 | message(FATAL_ERROR "Could not find F2CLIBS libraries.:" ${F2CLIBS_LIBRARIES}) 72 | endif() 73 | endif(WIN32) 74 | 75 | # CLAPACK 76 | set(CLAPCK_LIB lapack) 77 | if(WIN32) 78 | set(CLAPCK_LIB c${CLAPCK_LIB}) 79 | endif() 80 | find_library(CLAPACK_LIBRARIES 81 | NAMES 82 | ${CLAPCK_LIB} 83 | HINTS 84 | ${CMAKE_SOURCE_DIR}/../OOQP/lib 85 | /usr/lib/x86_64-linux-gnu/ 86 | /usr/local/lib/ 87 | /usr/lib/ 88 | ${CMAKE_SOURCE_DIR}/../libs/thirdPartyCode/CLAPACK/Release 89 | ) 90 | if(CLAPACK_LIBRARIES) 91 | message(STATUS "Found CLAPACK libraries:" ${CLAPACK_LIBRARIES}) 92 | else() 93 | message(FATAL_ERROR "Could not find CLAPACK libraries.") 94 | endif() 95 | 96 | set(OOQP_LIBRARIES ${BLAS_LIBRARIES} ${F2CLIBS_LIBRARIES} ${CLAPACK_LIBRARIES}) 97 | if(WIN32) 98 | set(OOQP_LIBRARIES_DEBUG ${OOQP_LIBRARIES}) 99 | endif(WIN32) 100 | 101 | # find_package(BLAS REQUIRED) 102 | ################################ 103 | 104 | # Dependent packages, BLAS and HSL 105 | # set(OOQP_LIBRARIES) 106 | # find_package(BLAS REQUIRED) 107 | # if(BLAS_FOUND) 108 | # message("BLAS FOUND") 109 | # set(OOQP_LIBRARIES ${OOQP_LIBRARIES} ${BLAS_LIBRARIES}) 110 | # else() 111 | # message(STATUS "OOQP requires BLAS") 112 | # endif() 113 | # find_package(HSL QUIET) 114 | # if(HSL_FOUND) 115 | # set(OOQP_LIBRARIES ${OOQP_LIBRARIES} ${HSL_LIBRARIES}) 116 | # else() 117 | # message(STATUS "OOQP requires HSL") 118 | # endif() 119 | 120 | if(OOQP_INCLUDE_DIR) 121 | set(OOQP_FOUND_INCLUDE TRUE) 122 | set(OOQP_INCLUDE_DIRS 123 | ${OOQP_INCLUDE_DIR}) 124 | message(STATUS "Found OOQP include dirs: ${OOQP_INCLUDE_DIRS}") 125 | else() 126 | message(STATUS "Could not find OOQP include dir") 127 | endif() 128 | 129 | # TRY TO FIND THE LIBRARIES 130 | set(OOQP_LIBS_LIST 131 | ooqpgensparse ooqpsparse ooqpgondzio ooqpbase ma27 132 | ) 133 | 134 | if(APPLE) 135 | set(OOQP_LIBS_LIST 136 | ${OOQP_LIBS_LIST} gfortran quadmath gcc 137 | ) 138 | endif(APPLE) 139 | 140 | set(OOQP_FOUND_LIBS TRUE) 141 | foreach(LIB ${OOQP_LIBS_LIST}) 142 | 143 | if(WIN32) 144 | set(LIB lib${LIB}.lib) 145 | endif() 146 | 147 | find_library(OOQP_LIB_${LIB} 148 | NAMES ${LIB} 149 | HINTS 150 | ${CMAKE_SOURCE_DIR}/../OOQP/lib 151 | /usr/local/libs/ 152 | ${PROJECT_SOURCE_DIR}/../../libs/thirdPartyCode/OOQP/lib/ 153 | ) 154 | if(OOQP_LIB_${LIB}) 155 | set(OOQP_LIBRARIES ${OOQP_LIBRARIES} ${OOQP_LIB_${LIB}}) 156 | else() 157 | message(FATAL_ERROR "Could not find " ${LIB}) 158 | set(OOQP_FOUND_LIBS FALSE) 159 | endif() 160 | 161 | if(WIN32) 162 | find_library(OOQP_LIB_${LIB}_DEBUG NAMES ${LIB} HINTS ${CMAKE_SOURCE_DIR}/../OOQP/lib/Debug) 163 | if(OOQP_LIB_${LIB}_DEBUG) 164 | set(OOQP_LIBRARIES_DEBUG ${OOQP_LIBRARIES_DEBUG} ${OOQP_LIB_${LIB}_DEBUG}) 165 | else() 166 | message(FATAL_ERROR "Could not find Debug version of " ${LIB}) 167 | set(OOQP_FOUND_LIBS FALSE) 168 | endif() 169 | endif(WIN32) 170 | 171 | endforeach() 172 | 173 | # TODO: this is not very clean, use find package 174 | if (UNIX AND NOT APPLE) 175 | set(OOQP_LIBRARIES ${OOQP_LIBRARIES} gfortran blas) 176 | endif (UNIX AND NOT APPLE) 177 | 178 | # also find debug libraries 179 | if(WIN32) 180 | set(OOQP_LIBRARIES_FOR_WIN "") 181 | foreach(lib ${OOQP_LIBRARIES_DEBUG}) 182 | list(APPEND OOQP_LIBRARIES_FOR_WIN debug ${lib}) 183 | endforeach(lib) 184 | foreach(lib ${OOQP_LIBRARIES}) 185 | list(APPEND OOQP_LIBRARIES_FOR_WIN optimized ${lib}) 186 | endforeach(lib) 187 | set(OOQP_LIBRARIES ${OOQP_LIBRARIES_FOR_WIN}) 188 | endif(WIN32) 189 | 190 | # print OOQP_LIBRARIES 191 | if(OOQP_FOUND_LIBS) 192 | message(STATUS "Found OOQP libraries: ${OOQP_LIBRARIES}") 193 | else() 194 | message(STATUS "Cound not find OOQP libraries") 195 | endif() 196 | 197 | # SUCCESS if BOTH THE LIBRARIES AND THE INCLUDE DIRECTORIES WERE FOUND 198 | if(OOQP_FOUND_INCLUDE AND OOQP_FOUND_LIBS AND BLAS_FOUND AND HSL_FOUND) 199 | set(OOQP_FOUND TRUE) 200 | message(STATUS "Found OOQP") 201 | elseif() 202 | message(STATUS "Cound not find OOQP") 203 | endif() 204 | -------------------------------------------------------------------------------- /assignment6/src/femLib/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.6) 2 | 3 | project(femLib CXX) 4 | 5 | set (CMAKE_CXX_STANDARD 11) 6 | FILE(GLOB SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/*.h ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp) 7 | 8 | include_directories(../optLib) 9 | add_library(${PROJECT_NAME} ${SOURCES}) 10 | target_link_libraries(${PROJECT_NAME}) 11 | target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) 12 | -------------------------------------------------------------------------------- /assignment6/src/femLib/Element.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | /** 7 | This class implements the interface for an elementary energy unit. As a function of deformed, undeformed, 8 | and other parameters, such as boundary conditions, each class that extends this one will define a potential energy. 9 | The deformed energy depends on a number of nodes. 10 | */ 11 | class Element{ 12 | 13 | public: 14 | Element() {} 15 | virtual ~Element() {} 16 | 17 | // Returns the number of nodes this unit depends on 18 | virtual int getNumNodes() const = 0; 19 | // Returns the global index of node `i` 20 | virtual int getNodeIndex(int i) const = 0; 21 | 22 | Vector2d getNodePos(int i, const VectorXd &x) const { 23 | return x.segment<2>(2*getNodeIndex(i)); 24 | } 25 | 26 | // Returns the element's mass 27 | virtual double getMass() const = 0; 28 | 29 | // Returns the energy value given deformed `x` and undeformed `X` state 30 | virtual double getEnergy(const VectorXd& x, const VectorXd& X) = 0; 31 | // Adds the gradient to `grad` given deformed `x` and undeformed `X` state 32 | virtual void addEnergyGradientTo(const VectorXd& x, const VectorXd& X, VectorXd& grad) = 0; 33 | // Adds the hessian entries to `hesEntries` given deformed `x` and undeformed `X` state 34 | virtual void addEnergyHessianTo(const VectorXd& x, const VectorXd& X, std::vector& hesEntries) = 0; 35 | 36 | EIGEN_MAKE_ALIGNED_OPERATOR_NEW 37 | }; 38 | -------------------------------------------------------------------------------- /assignment6/src/femLib/FEMElement.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Element.h" 4 | 5 | #include 6 | 7 | enum MaterialModel2D { 8 | MM_LINEAR_ISOTROPIC=0, 9 | MM_STVK, 10 | MM_NEO_HOOKEAN 11 | }; 12 | 13 | /** 14 | This class implements Constant Strain Triangles elements in 2D 15 | */ 16 | class FEMElement : public Element { 17 | public: 18 | FEMElement(const std::array &nodeIndices, const VectorXd &X) 19 | : nodeIndices(nodeIndices) { 20 | 21 | assert(nodeIndices.size() == 3); 22 | 23 | precomputeFromUndeformedState(X); 24 | } 25 | ~FEMElement(){ 26 | } 27 | 28 | virtual int getNumNodes() const { 29 | return 3; 30 | } 31 | virtual int getNodeIndex(int i) const { 32 | return nodeIndices[i]; 33 | } 34 | virtual double getMass() const { 35 | return restShapeArea * massDensity; 36 | } 37 | 38 | protected: 39 | // sets important properties of the rest shape using the set of points passed in as parameters 40 | void precomputeFromUndeformedState(const VectorXd &X){ 41 | //edge vectors 42 | Vector2d v1 = getNodePos(1, X) - getNodePos(0, X); 43 | Vector2d v2 = getNodePos(2, X) - getNodePos(0, X); 44 | 45 | //matrix that holds three edge vectors 46 | Matrix2d dX; 47 | dX << v1[0], v2[0], 48 | v1[1], v2[1]; 49 | 50 | dXInv = dX.inverse(); 51 | 52 | //compute the area of the element... 53 | restShapeArea = 1 / 2.0 * fabs(cross2d(v1, v2)); 54 | } 55 | 56 | // as a deformation measure, we need to compute the deformation gradient F. F maps deformed vectors dx to undeformed coords dX: dx = F*dX. 57 | // for linear basis functions, an easy way to compute it is by looking at the matrix that maps deformed traingle/tet edges to their underformed counterparts (F = dx * inv(dX)). 58 | void computeDeformationGradient(const Vector2d (&x)[3], Matrix2d& dxdX) const { 59 | //edge vectors 60 | Vector2d v1 = x[1] - x[0]; 61 | Vector2d v2 = x[2] - x[0]; 62 | Matrix2d dx; 63 | dx << v1[0], v2[0], 64 | v1[1], v2[1]; 65 | dxdX = dx * dXInv; 66 | } 67 | 68 | //protected: 69 | public: 70 | // the collection of nodes that define the triangle element 71 | std::array nodeIndices; 72 | // material parameters 73 | double shearModulus = 50, bulkModulus = 500; 74 | // relates area/volume to the mass of the element 75 | double massDensity = 1; 76 | // precomputed values 77 | double restShapeArea = 0; 78 | Matrix2d dXInv; 79 | }; 80 | -------------------------------------------------------------------------------- /assignment6/src/femLib/FEMElementAnalytic.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "FEMElement.h" 4 | 5 | /** 6 | This class implements Constant Strain Triangles elements in 2D 7 | */ 8 | class FEMElementAnalytic : public FEMElement { 9 | public: 10 | FEMElementAnalytic(const std::array &nodeIndices, const VectorXd &X) 11 | : FEMElement(nodeIndices, X) { 12 | } 13 | ~FEMElementAnalytic(){ 14 | } 15 | 16 | virtual double getEnergy(const VectorXd& x, const VectorXd& X){ 17 | //compute the deformation gradient 18 | Matrix2d F; 19 | Vector2d x0 = getNodePos(0, x); 20 | Vector2d x1 = getNodePos(1, x); 21 | Vector2d x2 = getNodePos(2, x); 22 | computeDeformationGradient({x0, x1, x2}, F); 23 | 24 | double energyDensity = 0; 25 | 26 | double normF2 = F(0,0)*F(0,0) + F(0,1)*F(0,1) + F(1,0)*F(1,0) + F(1,1)*F(1,1); 27 | double detF = F.determinant(); 28 | energyDensity += shearModulus/2 * (normF2-2) - shearModulus * log(detF) + bulkModulus/2 * log(detF) * log(detF); 29 | 30 | return energyDensity * restShapeArea; 31 | } 32 | 33 | virtual void addEnergyGradientTo(const VectorXd& x, const VectorXd& X, VectorXd& grad) { 34 | Vector2d x0 = getNodePos(0, x); 35 | Vector2d x1 = getNodePos(1, x); 36 | Vector2d x2 = getNodePos(2, x); 37 | 38 | //compute the local gradient, and write it into global gradient 39 | Vector2d dEdx[3]; 40 | computeGradientComponents({x0,x1,x2}, dEdx); 41 | for (int i = 0;i<3;i++) 42 | for (int j = 0;j<2;j++) 43 | grad[2*nodeIndices[i] + j] += dEdx[i][j]; 44 | } 45 | 46 | virtual void addEnergyHessianTo(const VectorXd& x, const VectorXd& X, std::vector& hesEntries) { 47 | Vector2d x0 = getNodePos(0, x); 48 | Vector2d x1 = getNodePos(1, x); 49 | Vector2d x2 = getNodePos(2, x); 50 | 51 | //compute the hessian blocks and write in global hessian 52 | Matrix2d ddEdxdx[3][3]; 53 | computeHessianComponents({x0,x1,x2}, ddEdxdx); 54 | for (int i = 0;i<3;i++) 55 | for (int j = 0;j < 3;j++) 56 | addSparseMatrixDenseBlockToTriplet(hesEntries, 2*nodeIndices[i], 2*nodeIndices[j], ddEdxdx[i][j], true); 57 | } 58 | 59 | private: 60 | void computeGradientComponents(const Vector2d (&x)[3], Vector2d (&dEdx)[3]){ 61 | //compute the gradient of the energy using the chain rule: dE/dx = dE/dF * dF/dx. dE/dF is the first Piola-Kirchoff stress sensor, for which nice expressions exist. 62 | 63 | //compute the deformation gradient 64 | Matrix2d F; 65 | computeDeformationGradient(x, F); 66 | 67 | Matrix2d dEdF; 68 | Matrix2d FinvT = F.inverse().transpose(); 69 | 70 | double normF2 = F(0,0)*F(0,0) + F(0,1)*F(0,1) + F(1,0)*F(1,0) + F(1,1)*F(1,1); 71 | double detF = F.determinant(); 72 | dEdF = F * shearModulus + FinvT * (-shearModulus + bulkModulus*log(detF)); 73 | 74 | //dF/dx is going to be some +/- Xinv terms. The forces on nodes 1,2 can be writen as: dE/dF * XInv', while the force on node 0 is -f1-f2; 75 | dEdx[1] = Vector2d(dEdF(0,0) * dXInv(0,0) + dEdF(0,1) * dXInv(0,1), dEdF(1,0) * dXInv(0,0) + dEdF(1,1) * dXInv(0,1)) * restShapeArea; 76 | dEdx[2] = Vector2d(dEdF(0,0) * dXInv(1,0) + dEdF(0,1) * dXInv(1,1), dEdF(1,0) * dXInv(1,0) + dEdF(1,1) * dXInv(1,1)) * restShapeArea; 77 | dEdx[0] = -dEdx[1]-dEdx[2]; 78 | } 79 | void computeHessianComponents(const Vector2d (&x)[3], Matrix2d (&ddEdxdx)[3][3]) { 80 | 81 | Matrix2d F; 82 | computeDeformationGradient(x, F); 83 | 84 | Matrix2d Finv = F.inverse(); 85 | Matrix2d FinvT = Finv.transpose(); 86 | Matrix2d dF, dP, tmpM, dH; 87 | const double dDs[6][4] = { { -1,-1,0,0 },{ 0,0,-1,-1 },{ 1,0,0,0 },{ 0,0,1,0 },{ 0,1,0,0 },{ 0,0,0,1 } }; 88 | for (int i = 0; i < 6; ++i) 89 | { 90 | for (int x = 0; x < 4; ++x) 91 | dF(x / 2, x % 2) = dDs[i][x]; 92 | dF = dF * dXInv; 93 | dP = shearModulus * dF; 94 | double J = F.determinant(); 95 | dP = dP + (shearModulus - bulkModulus * log(J)) * FinvT * dF.transpose() * FinvT; 96 | tmpM = Finv * dF; 97 | dP = dP + bulkModulus * (tmpM(0, 0) + tmpM(1, 1)) * FinvT; 98 | dH = restShapeArea * dP * dXInv.transpose(); 99 | int row = i / 2, subrow = i % 2; 100 | ddEdxdx[row][1](subrow, 0) = dH(0, 0); ddEdxdx[row][1](subrow, 1) = dH(1, 0); 101 | ddEdxdx[row][2](subrow, 0) = dH(0, 1); ddEdxdx[row][2](subrow, 1) = dH(1, 1); 102 | ddEdxdx[row][0](subrow, 0) = -(dH(0, 0) + dH(0, 1)); 103 | ddEdxdx[row][0](subrow, 1) = -(dH(1, 0) + dH(1, 1)); 104 | } 105 | } 106 | }; 107 | -------------------------------------------------------------------------------- /assignment6/src/femLib/FEMElementAutoDiff.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "FEMElement.h" 4 | 5 | #include 6 | 7 | template using Vector2 = Eigen::Matrix; 8 | template using Matrix2 = Eigen::Matrix; 9 | 10 | typedef AutoDiff AD; 11 | typedef AutoDiff ADD; 12 | 13 | /* This is the code from the tutorial using this AutoDiff implementation: 14 | * 15 | * // df/dx1 16 | AD x1 = M_PI; x1.deriv() = 1; 17 | AD x2 = 3; x2.deriv() = 0; 18 | AD f = sin(x1*x2); 19 | double f_val = f.value(); 20 | double dfdx1 = f.deriv(); 21 | 22 | // ddf/dx1dx2 23 | ADD x1 = M_PI; 24 | x1.value().deriv() = 1; x1.deriv().value() = 0; 25 | ADD x2 = 3; 26 | x2.value().deriv() = 0; x1.deriv().value() = 1; 27 | ADD f = sin(x1*x2); 28 | double f_val = f.value().value(); 29 | double ddfdx1dx2 = f.deriv().deriv(); 30 | 31 | // ddf/dx2dx2 32 | ADD x1 = M_PI; 33 | x1.value().deriv() = 0; x1.deriv().value() = 0; 34 | ADD x2 = 3; 35 | x2.value().deriv() = 1; x1.deriv().value() = 1; 36 | ADD f = sin(x1*x2); 37 | double f_val = f.value().value(); 38 | double ddfdx1dx2 = f.deriv().deriv(); 39 | */ 40 | 41 | /** 42 | This class implements Constant Strain Triangles elements in 2D 43 | */ 44 | class FEMElementAutoDiff : public FEMElement { 45 | public: 46 | FEMElementAutoDiff(const std::array &nodeIndices, const VectorXd &X) 47 | : FEMElement(nodeIndices, X) { 48 | } 49 | ~FEMElementAutoDiff(){ 50 | } 51 | 52 | virtual double getEnergy(const VectorXd& x, const VectorXd& X){ 53 | 54 | // Ex. 2.3 55 | 56 | Vector2d x0 = getNodePos(0, x); 57 | Vector2d x1 = getNodePos(1, x); 58 | Vector2d x2 = getNodePos(2, x); 59 | 60 | return computeEnergyT({x0, x1, x2}); 61 | } 62 | 63 | virtual void addEnergyGradientTo(const VectorXd& x, const VectorXd& X, VectorXd& grad) { 64 | 65 | // Ex. 2.3 66 | 67 | Vector2d x0 = getNodePos(0, x); 68 | Vector2d x1 = getNodePos(1, x); 69 | Vector2d x2 = getNodePos(2, x); 70 | 71 | Vector2 xd[3] = { 72 | {x0[0], x0[1]}, 73 | {x1[0], x1[1]}, 74 | {x2[0], x2[1]} 75 | }; 76 | 77 | for (int i = 0; i < 3; ++i) { 78 | for (int j= 0; j < 2; ++j) { 79 | xd[i][j].deriv() = 1; 80 | grad[2*getNodeIndex(i) + j] += computeEnergyT(xd).deriv(); 81 | xd[i][j].deriv() = 0; 82 | } 83 | } 84 | } 85 | 86 | virtual void addEnergyHessianTo(const VectorXd& x, const VectorXd& X, std::vector& hesEntries) { 87 | 88 | // Ex. 2.3 89 | 90 | Vector2d x0 = getNodePos(0, x); 91 | Vector2d x1 = getNodePos(1, x); 92 | Vector2d x2 = getNodePos(2, x); 93 | 94 | Vector2 xdd[3] = { 95 | {x0[0], x0[1]}, 96 | {x1[0], x1[1]}, 97 | {x2[0], x2[1]} 98 | }; 99 | 100 | for (int i1 = 0; i1 < 3; ++i1) { 101 | for (int j1 = 0; j1 < 2; ++j1) { 102 | xdd[i1][j1].deriv() = 1; 103 | for (int i2 = 0; i2 < 3; ++i2) { 104 | for (int j2 = 0; j2 < 2; ++j2) { 105 | xdd[i2][j2].value().deriv() = 1; 106 | hesEntries.push_back(Tripletd(2*getNodeIndex(i1)+j1, 2*getNodeIndex(i2)+j2, computeEnergyT(xdd).deriv().deriv())); 107 | xdd[i2][j2].value().deriv() = 0; 108 | } 109 | } 110 | xdd[i1][j1].deriv() = 0; 111 | } 112 | } 113 | 114 | } 115 | 116 | private: 117 | // This is the same function as FEMElement::computeGradient, 118 | // however with a template parameter T. 119 | template 120 | void computeDeformationGradientT(const Vector2 (&x)[3], Matrix2& dxdX) const { 121 | //edge vectors 122 | Vector2 v1 = x[1] - x[0]; 123 | Vector2 v2 = x[2] - x[0]; 124 | Matrix2 dx; 125 | dx << v1[0], v2[0], 126 | v1[1], v2[1]; 127 | Matrix2 dxInvT; 128 | for (int i = 0; i < 4; ++i) 129 | dxInvT.data()[i] = dXInv.data()[i]; 130 | dxdX = dx * dxInvT; 131 | } 132 | 133 | template 134 | T computeEnergyT(const Vector2 (&x)[3]) const { 135 | Matrix2 F; 136 | computeDeformationGradientT(x, F); 137 | 138 | T normF2 = F(0,0)*F(0,0) + F(0,1)*F(0,1) + F(1,0)*F(1,0) + F(1,1)*F(1,1); 139 | T detF = F.determinant(); 140 | T energyDensity = shearModulus/2 * (normF2-2) - shearModulus * log(detF) + bulkModulus/2 * log(detF) * log(detF); 141 | 142 | return energyDensity * restShapeArea; 143 | } 144 | }; 145 | -------------------------------------------------------------------------------- /assignment6/src/femLib/FEMElementFD.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "FEMElement.h" 4 | 5 | /** 6 | This class implements Constant Strain Triangles elements in 2D 7 | */ 8 | class FEMElementFD : public FEMElement { 9 | public: 10 | FEMElementFD(const std::array &nodeIndices, const VectorXd &X) 11 | : FEMElement(nodeIndices, X) { 12 | } 13 | ~FEMElementFD(){ 14 | } 15 | 16 | virtual double getEnergy(const VectorXd& x, const VectorXd& X) 17 | { 18 | // Ex 2.1 19 | 20 | Vector2d x0 = getNodePos(0, x); 21 | Vector2d x1 = getNodePos(1, x); 22 | Vector2d x2 = getNodePos(2, x); 23 | 24 | return computeEnergy({x0, x1, x2}); 25 | } 26 | virtual void addEnergyGradientTo(const VectorXd& x, const VectorXd& X, VectorXd& grad) 27 | { 28 | // Ex 2.1 29 | 30 | Vector2d x0 = getNodePos(0, x); 31 | Vector2d x1 = getNodePos(1, x); 32 | Vector2d x2 = getNodePos(2, x); 33 | 34 | Vector2d dEdx[3]; 35 | computeGradientComponents({x0, x1, x2}, dEdx); 36 | 37 | for (int i = 0;i<3;i++) 38 | for (int j = 0;j<2;j++) 39 | grad[2*nodeIndices[i] + j] += dEdx[i][j]; 40 | } 41 | 42 | virtual void addEnergyHessianTo(const VectorXd& x, const VectorXd& X, std::vector& hesEntries) 43 | { 44 | // Ex 2.2 45 | 46 | // get vertices of this element 47 | Vector2d x0 = getNodePos(0, x); 48 | Vector2d x1 = getNodePos(1, x); 49 | Vector2d x2 = getNodePos(2, x); 50 | 51 | //compute the hessian blocks and write in global hessian 52 | Matrix2d ddEdxdx[3][3]; 53 | computeHessianComponents({x0, x1, x2}, ddEdxdx); 54 | for (int i = 0;i<3;i++) 55 | for (int j = 0;j < 3;j++) 56 | addSparseMatrixDenseBlockToTriplet(hesEntries, 2*nodeIndices[i], 2*nodeIndices[j], ddEdxdx[i][j], true); 57 | } 58 | 59 | private: 60 | 61 | double computeEnergy(const Vector2d (&x)[3]) const 62 | { 63 | Matrix2d F; 64 | computeDeformationGradient(x, F); 65 | 66 | double normF2 = F(0,0)*F(0,0) + F(0,1)*F(0,1) + F(1,0)*F(1,0) + F(1,1)*F(1,1); 67 | double detF = F.determinant(); 68 | 69 | double energyDensity = shearModulus/2 * (normF2-2) - shearModulus * log(detF) + bulkModulus/2 * log(detF) * log(detF); 70 | 71 | return energyDensity * restShapeArea; 72 | } 73 | 74 | void computeGradientComponents(const Vector2d (&x)[3], Vector2d (&dEdx)[3]) const 75 | { 76 | // loop over 3 vertices 77 | for (int i = 0; i < 3; ++i) { 78 | // loop over dimensions 79 | for (int j = 0; j < 2; ++j) { 80 | Vector2d xp[3] = {x[0], x[1], x[2]}; 81 | Vector2d xm[3] = {x[0], x[1], x[2]}; 82 | xp[i][j] += h; 83 | xm[i][j] -= h; 84 | double ep = computeEnergy(xp); 85 | double em = computeEnergy(xm); 86 | dEdx[i][j] = (ep-em)/(2*h); 87 | } 88 | } 89 | } 90 | 91 | void computeHessianComponents(const Vector2d (&x)[3], Matrix2d (&ddEdxdx)[3][3]) const 92 | { 93 | // loop over 3 vertices 94 | for (int i = 0; i < 3; ++i) { 95 | 96 | // loop over dimensions 97 | for (int j = 0; j < 2; ++j) { 98 | Vector2d xp[3] = {x[0], x[1], x[2]}; 99 | Vector2d xm[3] = {x[0], x[1], x[2]}; 100 | xp[i][j] += h; 101 | xm[i][j] -= h; 102 | 103 | Vector2d dEdx_p[3]; 104 | computeGradientComponents(xp, dEdx_p); 105 | 106 | Vector2d dEdx_m[3]; 107 | computeGradientComponents(xm, dEdx_m); 108 | 109 | for (int k = 0; k < 3; ++k) { 110 | for (int l = 0; l < 2; ++l) { 111 | ddEdxdx[i][k](j,l) = (dEdx_p[k](l) - dEdx_m[k](l)) / (2*h); 112 | } 113 | } 114 | } 115 | } 116 | } 117 | 118 | private: 119 | double h = 1e-8; // step size 120 | }; 121 | -------------------------------------------------------------------------------- /assignment6/src/femLib/FixedPointElement.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Element.h" 4 | 5 | // zero rest length spring connected to a target position (could be the mouse, or something else...) 6 | class FixedPointElement : public Element{ 7 | public: 8 | FixedPointElement(int nodeIndex, const Vector2d &targetPosition, double K = 10) 9 | : nodeIndex(nodeIndex), targetPosition(targetPosition), k(K) { 10 | } 11 | ~FixedPointElement(){ 12 | } 13 | 14 | virtual int getNumNodes() const { 15 | return 1; 16 | } 17 | virtual int getNodeIndex(int i) const { 18 | assert(i == 0); 19 | return nodeIndex; 20 | } 21 | 22 | virtual double getMass() const { 23 | return 0; 24 | } 25 | 26 | virtual double getEnergy(const VectorXd& x, const VectorXd& X){ 27 | Vector2d p = x.segment<2>(2*nodeIndex); 28 | 29 | double v0 = k; 30 | double v3 = 0.500000; 31 | double v4 = v3 * v0; 32 | double v5 = p[0]; 33 | double v6 = targetPosition[0]; 34 | double v7 = v5 - v6; 35 | double v8 = v7 * v7; 36 | double v9 = p[1]; 37 | double v10 = targetPosition[1]; 38 | double v11 = v9 - v10; 39 | double v12 = v11 * v11; 40 | double v13 = v8 + v12; 41 | double v14 = v4 * v13; 42 | return v14; 43 | } 44 | virtual void addEnergyGradientTo(const VectorXd& x, const VectorXd& X, VectorXd& grad) { 45 | Vector2d p = x.segment<2>(2*nodeIndex); 46 | 47 | double v2 = k; 48 | double v3 = p[0]; 49 | double v4 = targetPosition[0]; 50 | double v5 = v3 - v4; 51 | double v6 = v5 + v5; 52 | double v7 = 0.500000; 53 | double v8 = v7 * v2; 54 | double v9 = v6 * v8; 55 | double v10 = p[1]; 56 | double v11 = targetPosition[1]; 57 | double v12 = v10 - v11; 58 | double v13 = v12 + v12; 59 | double v14 = v13 * v8; 60 | grad[2*nodeIndex + 0] += v9; 61 | grad[2*nodeIndex + 1] += v14; 62 | } 63 | virtual void addEnergyHessianTo(const VectorXd& x, const VectorXd& X, std::vector& hesEntries){ 64 | double v0 = k; 65 | double v1 = 2.000000; 66 | double v2 = 0.500000; 67 | double v3 = v2 * v0; 68 | double v4 = v1 * v3; 69 | double v5 = 0.000000; 70 | hesEntries.push_back(Tripletd(2*nodeIndex+0,2*nodeIndex+0,v4)); 71 | hesEntries.push_back(Tripletd(2*nodeIndex+0,2*nodeIndex+1,v5)); 72 | hesEntries.push_back(Tripletd(2*nodeIndex+1,2*nodeIndex+0,v5)); 73 | hesEntries.push_back(Tripletd(2*nodeIndex+1,2*nodeIndex+1,v4)); 74 | } 75 | 76 | void setTargetPosition(const Vector2d &p) { 77 | targetPosition = p; 78 | } 79 | 80 | Vector2d getTargetPosition() const { 81 | return targetPosition; 82 | } 83 | 84 | private: 85 | double k; 86 | int nodeIndex; 87 | Vector2d targetPosition; 88 | }; 89 | -------------------------------------------------------------------------------- /assignment6/src/femLib/SimulationMesh.cpp: -------------------------------------------------------------------------------- 1 | #include "SimulationMesh.h" 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include "FEMElementAnalytic.h" 8 | #include "Spring.h" 9 | 10 | SimulationMesh::SimulationMesh(){ 11 | energyFunction = new TotalEnergyFunction(this); 12 | } 13 | 14 | SimulationMesh::~SimulationMesh(){ 15 | delete energyFunction; 16 | } 17 | 18 | void SimulationMesh::generateSquareTriMesh(SimulationMesh::TriangleMesh &triMesh, double startX, double startY, double dX, double dY, int xSize, int ySize) { 19 | triMesh.v.resize(xSize*ySize); 20 | for (int i=0; ielements.clear(); 59 | for (int i=0; i nodes; 63 | nodes[0] = triangles[i][j]; 64 | int j2 = (j<2) ? j+1 : 0; 65 | nodes[1] = triangles[i][j2]; 66 | Spring* spring = new Spring(nodes, X); 67 | energyFunction->elements.push_back(spring); 68 | } 69 | } 70 | 71 | Vector2d pMin = {HUGE_VAL, HUGE_VAL}; 72 | Vector2d pMax = {-HUGE_VAL, -HUGE_VAL}; 73 | for (int i = 0; i < X.size()/2; ++i) { 74 | for (int j = 0; j < 2; ++j) { 75 | pMin[j] = std::min(pMin[j], X[2*i+j]); 76 | pMax[j] = std::max(pMax[j], X[2*i+j]); 77 | } 78 | } 79 | 80 | m.setZero(); 81 | double massDensity = 1.0; 82 | double totalMass = massDensity*((pMax[0]-pMin[0])*(pMax[1]-pMin[1])); 83 | double massPerNode = totalMass / (X.size()/2); 84 | for (int j=0; jm[j] = massPerNode; 86 | } 87 | 88 | void SimulationMesh::addGravityForces(const Vector2d &g){ 89 | for (size_t i=0;i(); 108 | } 109 | 110 | void SimulationMesh::solveNewtonsMethod() 111 | { 112 | solve_statics(); 113 | } 114 | 115 | void SimulationMesh::solveShapeOpt(int COMconstraintType) 116 | { 117 | /* Ex 2.1, 2.2: solve shape optimization problem using the SQPFunctionMinimizer 118 | * make sure you use the correct constraint type as set in GUI by using COMconstraintType 119 | */ 120 | } 121 | 122 | void SimulationMesh::togglePinnedNode(int i) 123 | { 124 | auto it = std::find_if(pinnedNodeElements.begin(), pinnedNodeElements.end(), 125 | [i](Element *e){ 126 | return e->getNodeIndex(0) == i; 127 | }); 128 | if(it == pinnedNodeElements.end()) 129 | setPinnedNode(i, { x[2*i+0], x[2*i+1] }); 130 | else 131 | unpinNode(i); 132 | } 133 | 134 | void SimulationMesh::setPinnedNode(int nodeIndex, const Vector2d &point) 135 | { 136 | for (auto it = pinnedNodeElements.begin(); it != pinnedNodeElements.end(); ++it) { 137 | FixedPointElement* fps = dynamic_cast(*it); 138 | if (fps->getNodeIndex(0) == nodeIndex) { 139 | fps->setTargetPosition(point); 140 | return; 141 | } 142 | } 143 | pinnedNodeElements.push_back(new FixedPointElement(nodeIndex, point)); 144 | } 145 | 146 | void SimulationMesh::unpinNode(int nodeIndex) 147 | { 148 | for (auto it = pinnedNodeElements.begin(); it != pinnedNodeElements.end(); ++it) { 149 | FixedPointElement* fps = dynamic_cast(*it); 150 | if (fps->getNodeIndex(0) == nodeIndex) { 151 | pinnedNodeElements.erase(it); 152 | break; 153 | } 154 | } 155 | } 156 | 157 | void SimulationMesh::computeDefoEnergyPerNode(VectorXd &defEnergyPerNode) 158 | { 159 | defEnergyPerNode.resize(numNodes); 160 | defEnergyPerNode.setZero(); 161 | 162 | for (auto element : energyFunction->elements) { 163 | double energy = element->getEnergy(x, X); 164 | for (int i = 0; i < element->getNumNodes(); ++i) { 165 | defEnergyPerNode[element->getNodeIndex(i)] += energy / (double)element->getNumNodes(); 166 | } 167 | } 168 | } 169 | 170 | void SimulationMesh::clear(){ 171 | numNodes = 0; 172 | energyFunction->elements.clear(); 173 | pinnedNodeElements.clear(); 174 | x.resize(0); 175 | 176 | } 177 | -------------------------------------------------------------------------------- /assignment6/src/femLib/SimulationMesh.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Element.h" 4 | #include "TotalEnergyFunction.h" 5 | #include "FixedPointElement.h" 6 | #include 7 | 8 | /** 9 | This class implements a generic sim mesh for deformable objects: collection of nodes connected to each other using different types of elements 10 | */ 11 | class SimulationMesh { 12 | 13 | public: 14 | SimulationMesh(); 15 | ~SimulationMesh(); 16 | 17 | // create and load meshes 18 | struct TriangleMesh { 19 | std::vector v; // vertices 20 | std::vector> tri; // triangles 21 | }; 22 | static void generateSquareTriMesh(TriangleMesh &triMesh, double startX=-4.5, double startY=0, double dX=1, double dY=1, int xSize=10, int ySize=10); 23 | void loadTriangleMesh(const TriangleMesh &triMesh); 24 | void createSpringsFromTriangles(); 25 | template void createElementsFromTriangles(); 26 | 27 | // add external forces 28 | void addGravityForces(const Vector2d &g); 29 | void applyForceAt(int i, const Vector2d &force); 30 | void clearExtForces(); 31 | 32 | // solve 33 | template void solve_statics(); 34 | void solveGradientDescent(); 35 | void solveNewtonsMethod(); 36 | void solveShapeOpt(int COMconstraintType); 37 | 38 | // pinned nodes 39 | void togglePinnedNode(int i); 40 | void setPinnedNode(int nodeIndex, const Vector2d& point); 41 | void unpinNode(int nodeIndex); 42 | 43 | void computeDefoEnergyPerNode(Eigen::VectorXd &defEnergyPerNode); 44 | 45 | void clear(); 46 | 47 | public: 48 | // number of nodes 49 | int numNodes, numElements; 50 | 51 | // for each node we will store the position and velocity, rest configuration, mass and external forces acting on it 52 | VectorXd x, m, f_ext, X, xSolver; 53 | 54 | // list of elements that connects the nodes to each other 55 | std::vector> triangles; 56 | 57 | // a list of temporary used to pin points to locations that are fixed in space... 58 | std::vector pinnedNodeElements; 59 | 60 | // this is the objective function that we use for simulations... 61 | TotalEnergyFunction* energyFunction; 62 | 63 | // this map contains all constrained nodes (support and shaping nodes) 64 | // the `int` is the node index and the `Vector2d` the target position 65 | std::map constraintNodes; 66 | 67 | // this set contains all nodes that belong to the support 68 | std::set supportNodes; 69 | 70 | }; 71 | 72 | 73 | 74 | template 75 | void SimulationMesh::createElementsFromTriangles() 76 | { 77 | energyFunction->elements.clear(); 78 | for (int i=0; ielements.push_back(newElem); 81 | } 82 | 83 | // update mass 84 | m.setZero(); 85 | for(auto e : energyFunction->elements) { 86 | for (int i = 0; i < e->getNumNodes(); ++i) { 87 | for (int j=0; j<2; j++) 88 | this->m[2*e->getNodeIndex(i) + j] += e->getMass() / (double)e->getNumNodes(); 89 | } 90 | } 91 | } 92 | 93 | template 94 | void SimulationMesh::solve_statics(){ 95 | xSolver = x; 96 | 97 | double functionValue = energyFunction->computeValue(xSolver); 98 | 99 | Minimizer minimizer(50); 100 | minimizer.minimize(energyFunction, xSolver); 101 | 102 | x = xSolver; 103 | } 104 | -------------------------------------------------------------------------------- /assignment6/src/femLib/Spring.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Element.h" 4 | 5 | /** 6 | This class implements the interface for an elementary energy unit. As a function of deformed, undeformed, 7 | and other parameters, such as boundary conditions, each class that extends this one will define a potential energy. 8 | The deformed energy depends on a number of nodes. 9 | */ 10 | class Spring : public Element { 11 | 12 | public: 13 | Spring(const std::array &nodeIndices, const VectorXd &X) 14 | : nodeIndices(nodeIndices) { 15 | } 16 | virtual ~Spring() {} 17 | 18 | // Returns the number of nodes this unit depends on 19 | virtual int getNumNodes() const { 20 | return 2; 21 | } 22 | // Returns the global index of node `i` 23 | virtual int getNodeIndex(int i) const { 24 | return nodeIndices[i]; 25 | } 26 | 27 | // Returns the element's mass 28 | virtual double getMass() const { 29 | return 0; 30 | } 31 | 32 | // Returns the energy value given deformed `x` and undeformed `X` state 33 | virtual double getEnergy(const VectorXd& x, const VectorXd& X) { 34 | 35 | // EXERCISE 1.2 36 | 37 | Vector2d V = getNodePos(0, X) - getNodePos(1, X); 38 | Vector2d v = getNodePos(0, x) - getNodePos(1, x); 39 | double l = v.norm(); double L = V.norm(); 40 | 41 | return 0.5 * k * std::pow(l/L-1,2.0)*L; 42 | } 43 | 44 | // Adds the gradient to `grad` given deformed `x` and undeformed `X` state 45 | virtual void addEnergyGradientTo(const VectorXd& x, const VectorXd& X, VectorXd& grad) { 46 | 47 | // EXERCISE 1.2 48 | 49 | Vector2d dEdx[2]; 50 | 51 | Vector2d V = getNodePos(0, X) - getNodePos(1, X); 52 | Vector2d v = getNodePos(0, x) - getNodePos(1, x); 53 | double l = v.norm(); double L = V.norm(); 54 | 55 | Vector2d f = -k*(l/L-1)/l * v; 56 | 57 | dEdx[0] = -f; 58 | dEdx[1] = f; 59 | 60 | // Add the local gradient `dEdx` to the global gradient `grad` 61 | for (int i = 0;i<2;i++) 62 | for (int j = 0;j<2;j++) 63 | grad[2*nodeIndices[i] + j] += dEdx[i][j]; 64 | } 65 | 66 | // Adds the hessian entries to `hesEntries` given deformed `x` and undeformed `X` state 67 | virtual void addEnergyHessianTo(const VectorXd& x, const VectorXd& X, std::vector& hesEntries) { 68 | 69 | // EXERCISE 1.4 70 | 71 | Matrix2d ddEdxdx[2][2]; 72 | 73 | Vector2d V = getNodePos(0, X) - getNodePos(1, X); 74 | Vector2d v = getNodePos(0, x) - getNodePos(1, x); 75 | double l = v.norm(); double L = V.norm(); 76 | 77 | double epsilon = l/L-1; 78 | Matrix2d vv = v*v.transpose()/(v.dot(v)); 79 | Matrix2d dfdx1 = -k*(1/L*vv + epsilon/l*(Matrix2d::Identity()-vv)); 80 | 81 | ddEdxdx[0][0] = -dfdx1; 82 | ddEdxdx[0][1] = dfdx1; 83 | 84 | ddEdxdx[1][0] = dfdx1; 85 | ddEdxdx[1][1] = -dfdx1; 86 | 87 | // Add the local hessians `ddEdxdx` to the global hessian using Eigen::Triplets 88 | for (int i = 0; i<2; i++) 89 | for (int j = 0; j< 2;j++) 90 | addSparseMatrixDenseBlockToTriplet(hesEntries, 2*nodeIndices[i], 2*nodeIndices[j], ddEdxdx[i][j], true); 91 | } 92 | 93 | protected: 94 | // the collection of nodes that define the triangle element 95 | std::array nodeIndices; 96 | // spring stiffness 97 | double k = 20.0; 98 | }; 99 | -------------------------------------------------------------------------------- /assignment6/src/femLib/TotalEnergyFunction.cpp: -------------------------------------------------------------------------------- 1 | #include "TotalEnergyFunction.h" 2 | #include "SimulationMesh.h" 3 | 4 | #include "FixedPointElement.h" 5 | 6 | TotalEnergyFunction::TotalEnergyFunction(SimulationMesh *simMesh) 7 | : simMesh(simMesh) { 8 | 9 | } 10 | 11 | TotalEnergyFunction::~TotalEnergyFunction(void){ 12 | } 13 | 14 | //The net energy is: 1/2 a'M a + E + x'F, where E is the potential energy stored in the various elements 15 | double TotalEnergyFunction::computeValue(const VectorXd& x){ 16 | double totalEnergy = 0; 17 | 18 | for (size_t i=0;igetEnergy(x, simMesh->X); 20 | 21 | for (size_t i=0;ipinnedNodeElements.size();i++) 22 | totalEnergy += simMesh->pinnedNodeElements[i]->getEnergy(x, simMesh->X); 23 | 24 | totalEnergy -= x.dot(simMesh->f_ext); 25 | 26 | return totalEnergy; 27 | } 28 | 29 | void TotalEnergyFunction::addGradientTo(VectorXd& grad, const VectorXd& x) { 30 | if (grad.size() != x.size()) 31 | resize(grad, x.size()); 32 | 33 | //take into account the gradient of the deformation energy 34 | for (size_t i=0;iaddEnergyGradientTo(x, simMesh->X, grad); 36 | 37 | for (size_t i=0;ipinnedNodeElements.size();i++) 38 | simMesh->pinnedNodeElements[i]->addEnergyGradientTo(x, simMesh->X, grad); 39 | 40 | grad -= simMesh->f_ext; 41 | } 42 | 43 | 44 | void TotalEnergyFunction::addHessianEntriesTo(std::vector& hessianEntries, const VectorXd& x) { 45 | for (size_t i = 0;i < elements.size();i++) 46 | elements[i]->addEnergyHessianTo(x, simMesh->X, hessianEntries); 47 | 48 | for (size_t i = 0;i < simMesh->pinnedNodeElements.size();i++) 49 | simMesh->pinnedNodeElements[i]->addEnergyHessianTo(x, simMesh->X, hessianEntries); 50 | } 51 | 52 | //void TotalEnergyFunction::init() 53 | //{ 54 | // Vector2d left = {HUGE_VAL, HUGE_VAL}; 55 | // Vector2d right = {-HUGE_VAL, -HUGE_VAL}; 56 | // for(FixedPointElement* fe : simMesh->pinnedNodeElements) { 57 | // if(fe->getTargetPosition()[0] > right[0]) 58 | // right = fe->getTargetPosition(); 59 | // if(fe->getTargetPosition()[0] < left[0]) 60 | // left = fe->getTargetPosition(); 61 | // } 62 | // comObj.bounds[0] = left; 63 | // comObj.bounds[1] = right; 64 | //} 65 | -------------------------------------------------------------------------------- /assignment6/src/femLib/TotalEnergyFunction.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "Element.h" 6 | 7 | class SimulationMesh; 8 | 9 | class TotalEnergyFunction : public ObjectiveFunction { 10 | public: 11 | TotalEnergyFunction(SimulationMesh* simMesh); 12 | virtual ~TotalEnergyFunction(void); 13 | 14 | virtual double computeValue(const VectorXd& s); 15 | virtual void addGradientTo(VectorXd& grad, const VectorXd& s); 16 | 17 | virtual void addHessianEntriesTo(std::vector& hessianEntries, const VectorXd& s); 18 | 19 | std::vector elements; 20 | 21 | public: 22 | SimulationMesh* simMesh; 23 | }; 24 | -------------------------------------------------------------------------------- /assignment6/src/gui_utils.cpp: -------------------------------------------------------------------------------- 1 | #include "gui_utils.h" 2 | 3 | int pick_face(igl::viewer::Viewer& viewer, int mouse_x, int mouse_y, const Eigen::MatrixXd& V, const Eigen::MatrixXi& F) { 4 | // Cast a ray in the view direction starting from the mouse position 5 | double x = mouse_x; 6 | double y = viewer.core.viewport(3) - mouse_y; 7 | 8 | Eigen::RowVector3d pt; 9 | 10 | Eigen::Matrix4f modelview = viewer.core.view * viewer.data.model; 11 | int vi = -1; 12 | 13 | std::vector hits; 14 | 15 | igl::unproject_in_mesh(Eigen::Vector2f(x,y), viewer.core.view * viewer.data.model, 16 | viewer.core.proj, viewer.core.viewport, V, F, pt,hits); 17 | 18 | int fi = -1; 19 | if (hits.size()> 0) { 20 | fi = hits[0].id; 21 | } 22 | return fi; 23 | } 24 | 25 | int pick_vertex(igl::viewer::Viewer& viewer, int mouse_x, int mouse_y, const Eigen::MatrixXd& V, const Eigen::MatrixXi& F) { 26 | // Cast a ray in the view direction starting from the mouse position 27 | double x = mouse_x; 28 | double y = viewer.core.viewport(3) - mouse_y; 29 | 30 | Eigen::RowVector3d pt; 31 | 32 | Eigen::Matrix4f modelview = viewer.core.view * viewer.data.model; 33 | int vi = -1; 34 | 35 | std::vector hits; 36 | /* 37 | igl::unproject_in_mesh(Eigen::Vector2f(x,y), 38 | modelview, 39 | viewer.core.proj, 40 | viewer.core.viewport, 41 | ei,pt,hits); 42 | */ 43 | 44 | igl::unproject_in_mesh(Eigen::Vector2f(x,y), viewer.core.view * viewer.data.model, 45 | viewer.core.proj, viewer.core.viewport, V, F, pt,hits); 46 | 47 | if (hits.size()> 0) { 48 | int fi = hits[0].id; 49 | Eigen::RowVector3d bc; 50 | bc << 1.0-hits[0].u-hits[0].v, hits[0].u, hits[0].v; 51 | bc.maxCoeff(&vi); 52 | vi = F(fi,vi); 53 | } 54 | return vi; 55 | } 56 | 57 | //computes translation for the vertices of the moving handle based on the mouse motion 58 | Eigen::Vector3f computePosition (igl::viewer::Viewer& viewer, 59 | int mouse_x, 60 | int mouse_y, 61 | Eigen::RowVector3d pt3D) { 62 | Eigen::Matrix4f modelview = viewer.core.view * viewer.data.model; 63 | //project the given point (typically the handle centroid) to get a screen space depth 64 | Eigen::Vector3f proj = igl::project(pt3D.transpose().cast().eval(), 65 | modelview, 66 | viewer.core.proj, 67 | viewer.core.viewport); 68 | float depth = proj[2]; 69 | 70 | double x, y; 71 | Eigen::Vector3f pos; 72 | 73 | //unproject from- and to- points 74 | x = mouse_x; 75 | y = viewer.core.viewport(3) - mouse_y; 76 | pos = igl::unproject(Eigen::Vector3f(x,y,depth), 77 | modelview, 78 | viewer.core.proj, 79 | viewer.core.viewport); 80 | 81 | return pos; 82 | } 83 | 84 | //computes translation for the vertices of the moving handle based on the mouse motion 85 | Eigen::Vector3f computeTranslation (igl::viewer::Viewer& viewer, 86 | int mouse_x, 87 | int from_x, 88 | int mouse_y, 89 | int from_y, 90 | Eigen::RowVector3d pt3D) { 91 | Eigen::Matrix4f modelview = viewer.core.view * viewer.data.model; 92 | //project the given point (typically the handle centroid) to get a screen space depth 93 | Eigen::Vector3f proj = igl::project(pt3D.transpose().cast().eval(), 94 | modelview, 95 | viewer.core.proj, 96 | viewer.core.viewport); 97 | float depth = proj[2]; 98 | 99 | double x, y; 100 | Eigen::Vector3f pos1, pos0; 101 | 102 | //unproject from- and to- points 103 | x = mouse_x; 104 | y = viewer.core.viewport(3) - mouse_y; 105 | pos1 = igl::unproject(Eigen::Vector3f(x,y,depth), 106 | modelview, 107 | viewer.core.proj, 108 | viewer.core.viewport); 109 | 110 | 111 | x = from_x; 112 | y = viewer.core.viewport(3) - from_y; 113 | pos0 = igl::unproject(Eigen::Vector3f(x,y,depth), 114 | modelview, 115 | viewer.core.proj, 116 | viewer.core.viewport); 117 | 118 | //translation is the vector connecting the two 119 | Eigen::Vector3f translation; 120 | translation = pos1 - pos0; 121 | 122 | return translation; 123 | } 124 | 125 | Eigen::Vector4f computeRotation(igl::viewer::Viewer& viewer, 126 | int mouse_x, 127 | int from_x, 128 | int mouse_y, 129 | int from_y, 130 | Eigen::RowVector3d pt3D) { 131 | 132 | Eigen::Vector4f rotation; 133 | rotation.setZero(); 134 | rotation[3] = 1.; 135 | 136 | Eigen::Matrix4f modelview = viewer.core.view * viewer.data.model; 137 | 138 | //initialize a trackball around the handle that is being rotated 139 | //the trackball has (approximately) width w and height h 140 | double w = viewer.core.viewport[2]/8; 141 | double h = viewer.core.viewport[3]/8; 142 | 143 | //the mouse motion has to be expressed with respect to its center of mass 144 | //(i.e. it should approximately fall inside the region of the trackball) 145 | 146 | //project the given point on the handle(centroid) 147 | Eigen::Vector3f proj = igl::project(pt3D.transpose().cast().eval(), 148 | modelview, 149 | viewer.core.proj, 150 | viewer.core.viewport); 151 | proj[1] = viewer.core.viewport[3] - proj[1]; 152 | 153 | //express the mouse points w.r.t the centroid 154 | from_x -= proj[0]; mouse_x -= proj[0]; 155 | from_y -= proj[1]; mouse_y -= proj[1]; 156 | 157 | //shift so that the range is from 0-w and 0-h respectively (similarly to a standard viewport) 158 | from_x += w/2; mouse_x += w/2; 159 | from_y += h/2; mouse_y += h/2; 160 | 161 | //get rotation from trackball 162 | Eigen::Vector4f drot = viewer.core.trackball_angle.coeffs(); 163 | Eigen::Vector4f drot_conj; 164 | igl::quat_conjugate(drot.data(), drot_conj.data()); 165 | igl::trackball(w, h, float(1.), rotation.data(), from_x, from_y, mouse_x, mouse_y, rotation.data()); 166 | 167 | //account for the modelview rotation: prerotate by modelview (place model back to the original 168 | //unrotated frame), postrotate by inverse modelview 169 | Eigen::Vector4f out; 170 | igl::quat_mult(rotation.data(), drot.data(), out.data()); 171 | igl::quat_mult(drot_conj.data(), out.data(), rotation.data()); 172 | return rotation; 173 | } 174 | -------------------------------------------------------------------------------- /assignment6/src/gui_utils.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | 9 | int pick_face(igl::viewer::Viewer& viewer, int mouse_x, int mouse_y, const Eigen::MatrixXd& V, const Eigen::MatrixXi& F); 10 | int pick_vertex(igl::viewer::Viewer& viewer, int mouse_x, int mouse_y, const Eigen::MatrixXd& V, const Eigen::MatrixXi& F); 11 | 12 | Eigen::Vector3f computePosition(igl::viewer::Viewer& viewer, int mouse_x, int mouse_y, Eigen::RowVector3d pt3D); 13 | Eigen::Vector3f computeTranslation(igl::viewer::Viewer& viewer,int mouse_x,int from_x,int mouse_y,int from_y,Eigen::RowVector3d pt3D); 14 | Eigen::Vector4f computeRotation(igl::viewer::Viewer& viewer, int mouse_x, int from_x, int mouse_y, int from_y, Eigen::RowVector3d pt3D); 15 | 16 | void update_display(igl::viewer::Viewer& viewer,const Eigen::MatrixXd& V, const Eigen::MatrixXi& F); 17 | -------------------------------------------------------------------------------- /assignment6/src/optLib/AutoDiff.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | template 8 | class AutoDiff 9 | { 10 | public: 11 | AutoDiff() { 12 | } 13 | 14 | template 15 | AutoDiff(const T &c) : m_x((Value)c), m_d((Deriv)0) { 16 | } 17 | 18 | AutoDiff(const Value &x, const Deriv &d) : m_x(x), m_d(d) { 19 | } 20 | 21 | bool operator==(const AutoDiff &other) const { 22 | return other.value() == this->value(); 23 | } 24 | 25 | bool operator!=(const AutoDiff &other) const { 26 | return other.value() != this->value(); 27 | } 28 | 29 | AutoDiff operator+(const AutoDiff &other) const { 30 | return AutoDiff(m_x + other.m_x, m_d + other.m_d); 31 | } 32 | 33 | AutoDiff operator-(const AutoDiff &other) const { 34 | return AutoDiff(m_x - other.m_x, m_d - other.m_d); 35 | } 36 | 37 | AutoDiff operator-() const { 38 | return AutoDiff(-m_x, -m_d); 39 | } 40 | 41 | AutoDiff operator*(const AutoDiff &other) const { 42 | // D(x*y) = x*dy + dx*y 43 | return AutoDiff(m_x * other.m_x, other.m_d * m_x + m_d * other.m_x); 44 | } 45 | 46 | AutoDiff operator/(const AutoDiff &other) const { 47 | // D(x/y) = (dx*y - x*dy) / y*y 48 | Value x2 = other.m_x * other.m_x; 49 | return AutoDiff(m_x / other.m_x, m_d*(other.m_x/x2) - other.m_d*(m_x/x2)); 50 | } 51 | 52 | AutoDiff &operator+=(const AutoDiff &other) { 53 | m_x = m_x + other.m_x; 54 | m_d = m_d + other.m_d; 55 | return *this; 56 | } 57 | 58 | AutoDiff &operator-=(const AutoDiff &other) { 59 | m_x = m_x - other.m_x; 60 | m_d = m_d - other.m_d; 61 | 62 | return *this; 63 | } 64 | 65 | AutoDiff &operator*=(const AutoDiff &other) { 66 | *this = *this * other; 67 | return *this; 68 | } 69 | 70 | AutoDiff &operator/=(const AutoDiff &other) { 71 | *this = *this / other; 72 | return *this; 73 | } 74 | 75 | bool operator>(const AutoDiff &d) const { 76 | return m_x > d.m_x; 77 | } 78 | 79 | bool operator<(const AutoDiff &d) const { 80 | return m_x < d.m_x; 81 | } 82 | 83 | bool operator>=(const AutoDiff &d) const { 84 | return m_x >= d.m_x; 85 | } 86 | 87 | bool operator<=(const AutoDiff &d) const { 88 | return m_x <= d.m_x; 89 | } 90 | 91 | const Value &value() const { return m_x; } 92 | Value &value() { return m_x; } 93 | 94 | const Deriv &deriv() const { return m_d; } 95 | Deriv &deriv() { return m_d; } 96 | 97 | private: 98 | Value m_x; // value 99 | Deriv m_d; // derivative 100 | }; 101 | 102 | template 103 | AutoDiff operator+(const Value &a, const AutoDiff &y) 104 | { 105 | // d(a+y) = dy/dx 106 | return AutoDiff(a + y.value(), y.deriv()); 107 | } 108 | 109 | template 110 | AutoDiff operator-(const Value &a, const AutoDiff &y) 111 | { 112 | // d(a-y) = -dy/dx 113 | return AutoDiff(a - y.value(), -y.deriv()); 114 | } 115 | 116 | template 117 | AutoDiff operator*(const Value &a, const AutoDiff &y) 118 | { 119 | // d(a*y)/dx = a*dy/dx 120 | return AutoDiff(a * y.value(), a * y.deriv()); 121 | } 122 | 123 | // TODO: test this! 124 | template 125 | AutoDiff operator*(const S &a, const AutoDiff &y) 126 | { 127 | // d(a*y)/dx = a*dy/dx 128 | return AutoDiff(a * y.value(), a * y.deriv()); 129 | } 130 | 131 | template 132 | AutoDiff operator/(const Value &a, const AutoDiff &y) 133 | { 134 | // D(a/y) = -a/y^2 * dy/dx 135 | return AutoDiff(a / y.value(), -a / (y.value() * y.value()) * y.deriv()); 136 | } 137 | 138 | template 139 | AutoDiff sin(const AutoDiff &y) 140 | { 141 | // d(sin(y))/dx = cos(y) * dy/dx 142 | return AutoDiff(sin(y.value()), cos(y.value()) * y.deriv()); 143 | } 144 | 145 | template 146 | AutoDiff cos(const AutoDiff &y) 147 | { 148 | // d(cos(y))/dx = -sin(y) * dy/dx 149 | return AutoDiff(cos(y.value()), -sin(y.value()) * y.deriv()); 150 | } 151 | 152 | template 153 | AutoDiff tan(const AutoDiff &y) 154 | { 155 | Value tanValue = tan(y.value()); 156 | 157 | // d(tan(y))/dx = (1 + tan(y)^2) * dy/dx 158 | return AutoDiff(tanValue, ((Value)1 + tanValue*tanValue) * y.deriv()); 159 | } 160 | 161 | template 162 | AutoDiff acos(const AutoDiff &y) 163 | { 164 | // d(acos(x))/dx = -1/sqrt(1-y*y) * dy/dx 165 | return AutoDiff(acos(y.value()), (Value(-1)/sqrt(Value(1)-y.value()*y.value())) * y.deriv()); 166 | } 167 | 168 | template 169 | AutoDiff sqrt(const AutoDiff &y) 170 | { 171 | // d(sqrt(y))/dx = 1/2 * 1/sqrt(y) * dy/dx 172 | return AutoDiff(sqrt(y.value()), Value(1)/Value(2) * Value(1)/sqrt(y.value()) * y.deriv()); 173 | } 174 | 175 | template 176 | AutoDiff log(const AutoDiff &y) 177 | { 178 | // d(log(y))/dx = 1.0 / y * dy/dx 179 | return AutoDiff(log(y.value()), Value(1)/y.value() * y.deriv()); 180 | } 181 | 182 | template 183 | AutoDiff pow(const AutoDiff &y, const double &a) 184 | { 185 | // d(y^a)/dx = a*y^{a-1} * dy/dx 186 | return AutoDiff(pow(y.value(), a), a*pow(y.value(), a-1) * y.deriv()); 187 | } 188 | 189 | template 190 | AutoDiff pow(const AutoDiff &y1, const AutoDiff &y2) 191 | { 192 | // D(y1^y2) = y1^y2 * (dy1/dx*ln(y2) + (y2*dy1/dx)/y1) 193 | return AutoDiff(pow(y1.value(), y2.value()), 194 | pow(y1.value(), y2.value()) * (y2.deriv()*log(y1.value()) + y2.value()*y1.deriv()/y1.value())); 195 | } 196 | 197 | template 198 | AutoDiff fabs(const AutoDiff &s) 199 | { 200 | if(s.value() >= 0) 201 | return s; 202 | else 203 | return -s; 204 | } 205 | 206 | template 207 | std::ostream& operator<<(std::ostream& stream, const AutoDiff &s) { 208 | stream << s.value() << "(" << s.deriv() << ")"; 209 | return stream; 210 | } 211 | -------------------------------------------------------------------------------- /assignment6/src/optLib/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.6) 2 | 3 | project(optLib CXX) 4 | 5 | set (CMAKE_CXX_STANDARD 11) 6 | 7 | find_package(OOQP REQUIRED) 8 | 9 | include_directories(${OOQP_INCLUDE_DIRS}) 10 | 11 | FILE(GLOB SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/*.h ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp) 12 | 13 | add_library(${PROJECT_NAME} ${SOURCES}) 14 | set_target_properties(${PROJECT_NAME} PROPERTIES LINKER_LANGUAGE CXX) 15 | target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) 16 | target_link_libraries( 17 | ${PROJECT_NAME} 18 | ${OOQP_LIBRARIES} 19 | ) 20 | -------------------------------------------------------------------------------- /assignment6/src/optLib/FunctionConstraints.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include "MathHelper.h" 5 | 6 | /*! 7 | A multi-dimensional function that expresses linear equality and inequality constraints applicable to an objective function: 8 | 9 | Equality constrains: A(p) = b 10 | Inequality constraint: d <= C(p) <= f 11 | Bound constraint: l <= p <= u 12 | */ 13 | class FunctionConstraints { 14 | public: 15 | /*! Constructor 16 | * Fill the constant variables in the constructor of the derived class: 17 | * b, d, f, l, u 18 | */ 19 | FunctionConstraints() {} 20 | 21 | virtual ~FunctionConstraints() {} 22 | 23 | // Returns the number of equality constraints. 24 | virtual int getEqualityConstraintCount() { 25 | return (int)getEqualityConstraintsTargetValues().size(); 26 | } 27 | 28 | // Returns b of A(p) = b. 29 | virtual const VectorXd& getEqualityConstraintsTargetValues() { 30 | return b; 31 | } 32 | 33 | // Returns A(p) of A(p) = b. 34 | // Derive from this to compute A(p). Fill `eqConstraintsVals` and return it. 35 | virtual const VectorXd& getEqualityConstraintValues(const VectorXd& p) { 36 | return eqConstraintVals; 37 | } 38 | 39 | // Computes the Jacobian dA/dp of the equality constraints A. 40 | virtual void addEqualityConstraintsJacobianEntriesTo(std::vector& jacobianEntries, const VectorXd& p) { 41 | 42 | } 43 | 44 | // Returns the number of inequality constraints. 45 | virtual int getInequalityConstraintCount() { 46 | return (int)getInequalityConstraintsMinValues().size(); 47 | } 48 | 49 | // Returns the value of the inequality constraint C(p). 50 | virtual const VectorXd& getInequalityConstraintValues(const VectorXd& p) { 51 | return ineqConstraintVals; 52 | } 53 | 54 | // Returns d of d <= C(p) <= f 55 | virtual const VectorXd& getInequalityConstraintsMinValues() { 56 | return d; 57 | } 58 | 59 | // Returns f of d <= C(p) <= f 60 | virtual const VectorXd& getInequalityConstraintsMaxValues() { 61 | return f; 62 | } 63 | 64 | // Computes the Jacobian dA/dp of the inequality constraints C. 65 | virtual void addInequalityConstraintsJacobianEntriesTo(std::vector& jacobianEntries, const VectorXd& p) { 66 | 67 | } 68 | 69 | // Returns l of constraint l <= p <= u 70 | virtual const VectorXd& getBoundConstraintsMinValues() { 71 | return l; 72 | } 73 | 74 | // Returns u of constraint l <= p <= u 75 | virtual const VectorXd& getBoundConstraintsMaxValues() { 76 | return u; 77 | } 78 | 79 | protected: 80 | VectorXd b; 81 | VectorXd d; 82 | VectorXd f; 83 | VectorXd l; 84 | VectorXd u; 85 | VectorXd eqConstraintVals; // A(p) 86 | VectorXd ineqConstraintVals; // C(p) 87 | }; 88 | -------------------------------------------------------------------------------- /assignment6/src/optLib/GradientDescentFunctionMinimizer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "ObjectiveFunction.h" 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | class GradientDescentFunctionMinimizer{ 11 | public: 12 | GradientDescentFunctionMinimizer(int maxIterations=100, double solveResidual=1e-5, int maxLineSearchIterations=15) 13 | : maxIterations(maxIterations), solveResidual(solveResidual), maxLineSearchIterations(maxLineSearchIterations){ 14 | } 15 | 16 | virtual ~GradientDescentFunctionMinimizer(){} 17 | 18 | int getLastIterations() { return lastIterations; } 19 | 20 | virtual bool minimize(ObjectiveFunction *function, VectorXd &x){ 21 | 22 | //number of parameters... 23 | int N = (int) x.size(); 24 | resize(xi, N); 25 | resize(dx, N); 26 | resize(gradient, N); 27 | 28 | xi = x; 29 | 30 | bool optimizationConverged = false; 31 | 32 | int i=0; 33 | for(; i < maxIterations; i++) { 34 | computeSearchDirection(function, xi, dx); 35 | 36 | if (dx.norm() < solveResidual){ 37 | optimizationConverged = true; 38 | break; 39 | } 40 | 41 | doLineSearch(function, dx, xi); 42 | } 43 | 44 | lastIterations = i; 45 | 46 | //p now holds the parameter values at the start of the iteration... 47 | x = xi; 48 | 49 | //and done! 50 | return optimizationConverged; 51 | } 52 | 53 | protected: 54 | // Since the gradient of a function gives the direction of steepest descent, all one needs to do is go in that direction... 55 | virtual void computeSearchDirection(ObjectiveFunction *function, const VectorXd &x, VectorXd& dx) { 56 | 57 | // Ex. 1.1 58 | 59 | dx.setZero(); 60 | function->addGradientTo(dx, x); 61 | } 62 | 63 | virtual void doLineSearch(ObjectiveFunction *function, const VectorXd& dx, VectorXd& xi) 64 | { 65 | // Ex. 1.1 66 | 67 | // line search now... 68 | double alpha = 1.0; 69 | VectorXd xc(xi); 70 | double initialValue = function->computeValue(xc); 71 | 72 | for(int j = 0; j < maxLineSearchIterations; j++) { 73 | // try a new solution 74 | xi = xc - dx * alpha; 75 | 76 | // now check the new function value at this point... 77 | double newLineSearchValue = function->computeValue(xi); 78 | 79 | if((!std::isfinite(newLineSearchValue) || newLineSearchValue > initialValue) 80 | && j < maxLineSearchIterations -1) 81 | // restore and try again... 82 | alpha /= 2.0; 83 | else 84 | // found a better solution! 85 | return; 86 | } 87 | 88 | // couldn't find a good value. Return what we now have and hope for the best... 89 | std::cout << "line search failed." << std::endl; 90 | } 91 | 92 | protected: 93 | double solveResidual = 1e-5; 94 | int maxIterations = 100; 95 | int maxLineSearchIterations = 15; 96 | 97 | VectorXd xi, dx, gradient; 98 | 99 | // some stats about the last time `minimize` was called 100 | int lastIterations = -1; 101 | }; 102 | -------------------------------------------------------------------------------- /assignment6/src/optLib/MathHelper.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | //#pragma warning( disable : 4996) 4 | 5 | #define EPSILON 1e-10 6 | #define TINY 0.0000001 7 | #define IS_ZERO(x) (fabs(x) 10 | #include 11 | 12 | using Eigen::VectorXd; 13 | using Eigen::MatrixXd; 14 | typedef Eigen::SparseMatrix SparseMatrixd; 15 | typedef Eigen::Triplet Tripletd; 16 | 17 | #ifdef _DEBUG // DEBUG 18 | typedef Eigen::Matrix Matrix2d; 19 | typedef Eigen::Matrix Vector2d; 20 | #else // RELEASE 21 | using Eigen::Matrix2d; 22 | using Eigen::Vector2d; 23 | #endif // _DEBUG 24 | 25 | inline void resize(SparseMatrixd& sm, int rows, int cols) { 26 | if (sm.rows() != rows || sm.cols() != cols) 27 | sm.resize(rows, cols); 28 | sm.setZero(); 29 | } 30 | 31 | inline void resize(VectorXd& v, int n) { 32 | if (v.size() != n) 33 | v.resize(n); 34 | v.setZero(); 35 | } 36 | 37 | inline void resize(MatrixXd& m, int rows, int cols) { 38 | if (m.rows() != rows || m.cols() != cols) 39 | m.resize(rows, cols); 40 | m.setZero(); 41 | } 42 | 43 | template 44 | void addSparseMatrixDenseBlockToTriplet(std::vector& triplets, int startX, int startY, const MATType& block, bool writeOnlyLowerDiagonalValues = false) { 45 | for (int i = 0; i < block.rows(); i++) 46 | for (int j = 0; j < block.cols(); j++) 47 | if (startX + i >= startY + j || !writeOnlyLowerDiagonalValues) 48 | triplets.push_back(Tripletd(startX + i, startY + j, block(i, j))); 49 | } 50 | 51 | inline double cross2d(const Vector2d &a, const Vector2d &b) { 52 | return a.x()*b.y() - b.x()*a.y(); 53 | } 54 | -------------------------------------------------------------------------------- /assignment6/src/optLib/NewtonFunctionMinimizer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "ObjectiveFunction.h" 4 | #include "GradientDescentFunctionMinimizer.h" 5 | 6 | /** 7 | use Newton's method to optimize a function. p will store the final value that minimizes the function, and its initial value 8 | is used to start the optimization method. 9 | 10 | Task: find p that minimize f(p). This means that df/dp(p) = 0. 11 | df/dp(p+dp) ~ df/dp(p) + d/dp(df/dp) * dp = 0 ==> -df/dp(p) = d/dp(df/dp) * dp 12 | Iterating the above, will hopefully get p that minimizes f. 13 | */ 14 | class NewtonFunctionMinimizer : public GradientDescentFunctionMinimizer { 15 | public: 16 | NewtonFunctionMinimizer(int maxIterations = 100, double solveResidual = 0.0001, int maxLineSearchIterations = 15) 17 | : GradientDescentFunctionMinimizer(maxIterations, solveResidual, maxLineSearchIterations) { } 18 | 19 | virtual ~NewtonFunctionMinimizer() {} 20 | 21 | protected: 22 | // The search direction is given by -Hinv * g 23 | virtual void computeSearchDirection(ObjectiveFunction *function, const VectorXd &x, VectorXd& dx) { 24 | 25 | // get hessian 26 | resize(H, x.size(), x.size()); 27 | hessianEntries.clear(); 28 | function->addHessianEntriesTo(hessianEntries, xi); 29 | H.setFromTriplets(hessianEntries.begin(), hessianEntries.end()); 30 | 31 | // get gradient 32 | resize(gradient, x.size()); 33 | function->addGradientTo(gradient, xi); 34 | 35 | //dp = Hes^-1 * grad 36 | Eigen::SimplicialLDLT solver; 37 | solver.compute(H); 38 | dx = solver.solve(gradient); 39 | } 40 | 41 | public: 42 | SparseMatrixd H; 43 | std::vector hessianEntries; 44 | }; 45 | -------------------------------------------------------------------------------- /assignment6/src/optLib/ObjectiveFunction.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "MathHelper.h" 4 | 5 | class ObjectiveFunction{ 6 | public: 7 | // this should always return the current value of the objective function 8 | virtual double computeValue(const VectorXd& x) = 0; 9 | virtual void addGradientTo(VectorXd& grad, const VectorXd& x) = 0; 10 | virtual void addHessianEntriesTo(std::vector& hessianEntries, const VectorXd& x) = 0; 11 | }; 12 | -------------------------------------------------------------------------------- /assignment6/src/optLib/OoqpEigenInterface.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "MathHelper.h" 9 | 10 | namespace ooqpei { 11 | 12 | class OoqpEigenInterface{ 13 | public: 14 | EIGEN_MAKE_ALIGNED_OPERATOR_NEW 15 | 16 | /*! 17 | * Solve min 1/2 x' Q x + c' x, such that A x = b, d <= Cx <= f, and l <= x <= u. 18 | * @param [in] Q a symmetric positive semidefinite matrix (nxn) 19 | * @param [in] c a vector (nx1) 20 | * @param [in] A a (possibly null) matrices (m_axn) 21 | * @param [in] b a vector (m_ax1) 22 | * @param [in] C a (possibly null) matrices (m_cxn) 23 | * @param [in] d a vector (m_cx1) 24 | * @param [in] f a vector (m_cx1) 25 | * @param [in] l a vector (nx1) 26 | * @param [in] u a vector (nx1) 27 | * @param [out] x a vector of variables (nx1) 28 | * @return true if successful 29 | */ 30 | static bool solve(const SparseMatrixd& Q, 31 | const VectorXd& c, 32 | const SparseMatrixd& A, 33 | const VectorXd& b, 34 | const SparseMatrixd& C, 35 | const VectorXd& d, const VectorXd& f, 36 | const VectorXd& l, const VectorXd& u, 37 | VectorXd& x); 38 | 39 | /*! 40 | * Solve min 1/2 x' Q x + c' x, such that A x = b, and d <= Cx <= f 41 | * @param [in] Q a symmetric positive semidefinite matrix (nxn) 42 | * @param [in] c a vector (nx1) 43 | * @param [in] A a (possibly null) matrices (m_axn) 44 | * @param [in] b a vector (m_ax1) 45 | * @param [in] C a (possibly null) matrices (m_cxn) 46 | * @param [in] d a vector (m_cx1) 47 | * @param [in] f a vector (m_cx1) 48 | * @param [out] x a vector of variables (nx1) 49 | * @return true if successful 50 | */ 51 | static bool solve(const SparseMatrixd& Q, 52 | VectorXd& c, 53 | const SparseMatrixd& A, 54 | VectorXd& b, 55 | const SparseMatrixd& C, 56 | VectorXd& d, VectorXd& f, 57 | VectorXd& x); 58 | 59 | /*! 60 | * Solve min 1/2 x' Q x + c' x, such that A x = b, and l <= x <= u. 61 | * @param [in] Q a symmetric positive semidefinite matrix (nxn) 62 | * @param [in] c a vector (nx1) 63 | * @param [in] A a (possibly null) matrices (m_axn) 64 | * @param [in] b a vector (m_ax1) 65 | * @param [in] l a vector (nx1) 66 | * @param [in] u a vector (nx1) 67 | * @param [out] x a vector of variables (nx1) 68 | * @return true if successful 69 | */ 70 | static bool solve(const SparseMatrixd& Q, 71 | VectorXd& c, 72 | const SparseMatrixd& A, 73 | VectorXd& b, 74 | VectorXd& l, VectorXd& u, 75 | VectorXd& x); 76 | 77 | /*! 78 | * Solve min 1/2 x' Q x + c' x, such that Cx <= f 79 | * @param [in] Q a symmetric positive semidefinite matrix (nxn) 80 | * @param [in] c a vector (nx1) 81 | * @param [in] C a (possibly null) matrices (m_cxn) 82 | * @param [in] f a vector (m_cx1) 83 | * @param [out] x a vector of variables (nx1) 84 | * @return true if successful 85 | */ 86 | static bool solve(const SparseMatrixd& Q, 87 | VectorXd& c, 88 | const SparseMatrixd& C, 89 | VectorXd& f, 90 | VectorXd& x); 91 | 92 | /*! 93 | * Solve min 1/2 x' Q x + c' x 94 | * @param [in] Q a symmetric positive semidefinite matrix (nxn) 95 | * @param [in] c a vector (nx1) 96 | * @param [out] x a vector of variables (nx1) 97 | * @return true if successful 98 | */ 99 | static bool solve(const SparseMatrixd& Q, 100 | VectorXd& c, 101 | VectorXd& x); 102 | 103 | /*! 104 | * Change to true to print debug information. 105 | * @return true if in debug mode 106 | */ 107 | static bool isInDebugMode() { return isInDebugMode_; }; 108 | static void setIsInDebugMode(bool isInDebugMode) { 109 | isInDebugMode_ = isInDebugMode; 110 | } 111 | 112 | private: 113 | /*! 114 | * Determine which limits are active and which are not. 115 | * @param [in] l 116 | * @param [in] u 117 | * @param [out] useLowerLimit 118 | * @param [out] useUpperLimit 119 | * @param [out] lowerLimit 120 | * @param [out] upperLimit 121 | */ 122 | static void generateLimits(const VectorXd& l, const VectorXd& u, 123 | Eigen::Matrix& useLowerLimit, 124 | Eigen::Matrix& useUpperLimit, 125 | VectorXd& lowerLimit, VectorXd& upperLimit, bool ignoreEqualLowerAndUpperLimits); 126 | 127 | static void printProblemFormulation( 128 | const SparseMatrixd& Q, const VectorXd& c, 129 | const SparseMatrixd& A, const VectorXd& b, 130 | const SparseMatrixd& C, const VectorXd& d, const VectorXd& f, 131 | const VectorXd& l, const VectorXd& u); 132 | 133 | static void printLimits(Eigen::Matrix& useLowerLimit, 134 | Eigen::Matrix& useUpperLimit, 135 | VectorXd& lowerLimit, 136 | VectorXd& upperLimit); 137 | 138 | static void printSolution(int& status, VectorXd& x); 139 | 140 | private: 141 | static bool isInDebugMode_; 142 | }; 143 | 144 | } /* namespace ooqpei */ 145 | -------------------------------------------------------------------------------- /assignment6/src/optLib/RosenbrockFunction.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "ObjectiveFunction.h" 4 | 5 | class RosenbrockFunction : public ObjectiveFunction { 6 | public: 7 | 8 | RosenbrockFunction() { 9 | a = 1; b = 100; 10 | } 11 | 12 | virtual double computeValue(const VectorXd& x) { 13 | 14 | // Ex 1.1 15 | 16 | const double &x1 = x[0]; 17 | const double &x2 = x[1]; 18 | return std::pow(a-x1,2.0) + b*std::pow(x2-x1*x1, 2.0); 19 | } 20 | 21 | virtual void addGradientTo(VectorXd& grad, const VectorXd& x) { 22 | 23 | // Ex 1.1 24 | 25 | const double &x1 = x[0]; 26 | const double &x2 = x[1]; 27 | grad[0] += -2*(a-x1) - 4*b*(x2-x1*x1)*x1; 28 | grad[1] += 2*b*(x2-x1*x1); 29 | } 30 | 31 | 32 | virtual void addHessianEntriesTo(std::vector& hessianEntries, const VectorXd& x) { 33 | 34 | // Ex 1.2 35 | 36 | const double &x1 = x[0]; 37 | const double &x2 = x[1]; 38 | hessianEntries.push_back(Tripletd(0, 0, 2 + 12*b*x1*x1 - 4*b*x2)); 39 | hessianEntries.push_back(Tripletd(1, 0, -4*b*x1)); 40 | hessianEntries.push_back(Tripletd(1, 1, 2*b)); 41 | } 42 | 43 | double a, b; 44 | }; 45 | -------------------------------------------------------------------------------- /assignment6/src/optLib/SQPFunctionMinimizer.cpp: -------------------------------------------------------------------------------- 1 | #include "SQPFunctionMinimizer.h" 2 | 3 | //TODO: all jacobians and constraints should be represented in terms of the triplets... 4 | //#include "MathHelper.h" 5 | 6 | #include "ObjectiveFunction.h" 7 | 8 | #include "OoqpEigenInterface.h" 9 | #include "ooqpei_assert_macros.h" 10 | 11 | #include 12 | #include 13 | 14 | SQPFunctionMinimizer::SQPFunctionMinimizer(int maxIterations, double solveResidual, int maxLineSearchIterations) 15 | : maxIterations(maxIterations), 16 | solveResidual(solveResidual), 17 | maxLineSearchIterations(maxLineSearchIterations) 18 | { 19 | } 20 | 21 | SQPFunctionMinimizer::~SQPFunctionMinimizer(){ 22 | } 23 | 24 | void SQPFunctionMinimizer::computeGradient(ObjectiveFunction *objective, const VectorXd& pi) { 25 | int nParameters = (int)pi.size(); 26 | resize(gradient, nParameters); 27 | gradient.setZero(); 28 | objective->addGradientTo(gradient, pi); 29 | } 30 | 31 | void SQPFunctionMinimizer::computeHessian(ObjectiveFunction *objective, const VectorXd& pi) { 32 | int nParameters = (int)pi.size(); 33 | resize(H, nParameters, nParameters); 34 | smEntries.clear(); 35 | objective->addHessianEntriesTo(smEntries, pi); 36 | H.setFromTriplets(smEntries.begin(), smEntries.end()); 37 | } 38 | 39 | void SQPFunctionMinimizer::computeConstraintsAndJacobians(FunctionConstraints* constraints, const VectorXd& pi) { 40 | int nParameters = (int)pi.size(); 41 | 42 | smEntries.clear(); 43 | resize(A, constraints->getEqualityConstraintCount(), nParameters); 44 | constraints->addEqualityConstraintsJacobianEntriesTo(smEntries, pi); 45 | A.setFromTriplets(smEntries.begin(), smEntries.end()); 46 | 47 | smEntries.clear(); 48 | resize(C, constraints->getInequalityConstraintCount(), nParameters); 49 | constraints->addInequalityConstraintsJacobianEntriesTo(smEntries, pi); 50 | C.setFromTriplets(smEntries.begin(), smEntries.end()); 51 | 52 | // compute constraints 53 | computeConstraints(constraints, pi, ck); 54 | } 55 | 56 | 57 | /** 58 | min f(p) subject to the constraints... 59 | */ 60 | bool SQPFunctionMinimizer::minimize(ObjectiveFunction *objective, FunctionConstraints* constraints, VectorXd &p){ 61 | 62 | const int nParameters = (int)p.size(); 63 | VectorXd dp = VectorXd::Zero(nParameters); 64 | VectorXd pi = p; 65 | 66 | // Iterate - like Newton 67 | bool optimizationConverged = false; 68 | int i; 69 | for (i=0; igetEqualityConstraintsTargetValues(), 84 | constraints->getInequalityConstraintsMinValues(), 85 | C, 86 | constraints->getInequalityConstraintsMaxValues(), 87 | constraints->getBoundConstraintsMinValues(), 88 | constraints->getBoundConstraintsMaxValues()); 89 | 90 | 91 | if (dp.norm() < solveResidual) { 92 | lastNumberIterations = i; 93 | optimizationConverged = true; 94 | break; 95 | } 96 | 97 | // Do a line search 98 | double alpha = doLineSearch(objective, constraints, pi, dp, maxLineSearchIterations); 99 | 100 | pi += alpha*dp; 101 | } 102 | 103 | lastNumberIterations = i; 104 | p = pi; 105 | return optimizationConverged; 106 | 107 | } 108 | 109 | void SQPFunctionMinimizer::computeSearchDirection(const SparseMatrixd& hessian, 110 | const VectorXd& gradient, 111 | const VectorXd &p, 112 | VectorXd &dp, 113 | const SparseMatrixd& A, 114 | const VectorXd& b, 115 | const VectorXd& d, 116 | const SparseMatrixd& C, 117 | const VectorXd& f, 118 | const VectorXd& l, 119 | const VectorXd& u) { 120 | 121 | /** We want dp to minimize: F(p+dp) ~ F(p) + dp' grad + 1/2 dp' H dp 122 | * while maintaining the constraints A*(p+dp) = b and d <= C*(p+dp) <= f and l <= p+dp <= u. 123 | * re-writing the constraints as 124 | * A*dp = b - A*p 125 | * d-C*p <= C*dp <= f-C*p 126 | * l-p <= dp <= u-p 127 | * we can get a canonical QP form: 128 | * min 1/2 x' Q x + c' x s. t. A x = b, d <= Cx <= f, and l <= x <= u 129 | * where: 130 | * x = dp 131 | * Q = hessian 132 | * c = gradient 133 | * A = A 134 | * b = bMinusAp 135 | * C = C 136 | * d = dMinusCp 137 | * f = fMinusCp 138 | * l = minMinusp 139 | * u = maxMinusp 140 | */ 141 | 142 | int np = p.size(); 143 | 144 | VectorXd fMinusCp; 145 | VectorXd dMinusCp; 146 | 147 | if (C.size() > 0) { 148 | const VectorXd Cp = C*p; 149 | fMinusCp = f - Cp; 150 | dMinusCp = d - Cp; 151 | } 152 | 153 | VectorXd bMinusAp; 154 | if (A.size() > 0) { 155 | bMinusAp = b - A*p; 156 | } 157 | 158 | VectorXd lMinusdp = l - p; 159 | VectorXd uMinusdp = u - p; 160 | 161 | bool success = ooqpei::OoqpEigenInterface::solve(hessian, 162 | gradient, 163 | A, 164 | bMinusAp, 165 | C, 166 | dMinusCp, 167 | fMinusCp, 168 | lMinusdp, 169 | uMinusdp, 170 | dp); 171 | } 172 | 173 | double SQPFunctionMinimizer::doLineSearch(ObjectiveFunction *objective, FunctionConstraints *constraints, VectorXd &p, const VectorXd &dp, int maxSteps){ 174 | 175 | double alpha = 1.0; 176 | const double mu = computeMu(p); 177 | const double initialValue = computeMerritFunction(objective, constraints, p, mu); 178 | VectorXd pc; 179 | 180 | for (int j=0; j= initialValue) { 188 | alpha /= 2.0; 189 | } 190 | else { 191 | return alpha; 192 | } 193 | } 194 | 195 | return alpha; 196 | } 197 | 198 | double SQPFunctionMinimizer::computeMerritFunction(ObjectiveFunction *objective, FunctionConstraints *constraints, const VectorXd &x, double mu) { 199 | double f = objective->computeValue(x); 200 | 201 | VectorXd c_at_x; 202 | computeConstraints(constraints, x, c_at_x); 203 | double c_at_x_norm1 = 0; 204 | for (int i = 0; i < c_at_x.size(); ++i) 205 | c_at_x_norm1 += abs(c_at_x[i]); 206 | 207 | return f + mu*c_at_x_norm1; 208 | } 209 | 210 | double SQPFunctionMinimizer::computeMu(const VectorXd &x) const 211 | { 212 | double ck_norm1 = 0; 213 | for (int i = 0; i < ck.size(); ++i) 214 | ck_norm1 += abs(ck[i]); 215 | 216 | double xTHx = x.transpose()*H*x; 217 | double sigma = (xTHx > 0) ? 1.0 : 0.0; 218 | double rho = 0.1; 219 | double mu_new = (abs(gradient.dot(x) + 0.5*sigma*xTHx)/((1.0-rho)*ck_norm1)); 220 | 221 | mu_new = std::max(mu_max, std::min(mu_min, mu_new)); 222 | 223 | mu_k = std::max(mu_k, mu_new); 224 | 225 | // mu_k = mu_new; 226 | return mu_k; 227 | } 228 | 229 | void SQPFunctionMinimizer::computeConstraints(FunctionConstraints *constraints, const VectorXd &x, VectorXd &c) 230 | { 231 | VectorXd c_ineq = constraints->getInequalityConstraintValues(x); 232 | VectorXd c_min = constraints->getInequalityConstraintsMinValues(); 233 | VectorXd c_max = constraints->getInequalityConstraintsMaxValues(); 234 | 235 | VectorXd c_eq = constraints->getEqualityConstraintValues(x); 236 | VectorXd c_val = constraints->getEqualityConstraintsTargetValues(); 237 | 238 | c.resize(c_ineq.size() + c_eq.size()); 239 | c.setZero(); 240 | for (int i = 0; i < c_ineq.size(); ++i) { 241 | if(c_ineq[i] < c_min[i]) 242 | c[i] = c_min[i]-c_ineq[i]; 243 | if(c_ineq[i] > c_max[i]) 244 | c[i] = c_ineq[i]-c_max[i]; 245 | } 246 | for (int i = 0; i < c_eq.size(); ++i) 247 | c[c_ineq.size()+i] = c_eq[i] - c_val[i]; 248 | } 249 | -------------------------------------------------------------------------------- /assignment6/src/optLib/SQPFunctionMinimizer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "ObjectiveFunction.h" 4 | #include "FunctionConstraints.h" 5 | 6 | /** 7 | Use the Sequential Quadratic Programming method to optimize a function, subject to constraints. 8 | 9 | Task: Find p that minimize f(p), such that Ap = b and d <= Cp <= f 10 | */ 11 | class SQPFunctionMinimizer { 12 | public: 13 | /*! 14 | * 15 | * @param maxIterations maximum number of iterations 16 | * @param solveResidual abortion criterium 17 | * @param maxLineSearchIterations maximum number of line search iterations 18 | */ 19 | SQPFunctionMinimizer(int maxIterations = 10, double solveResidual=0.0001, int maxLineSearchIterations = 20); 20 | virtual ~SQPFunctionMinimizer(); 21 | 22 | /** 23 | min f(p) subject to the constraints... 24 | */ 25 | bool minimize(ObjectiveFunction *objective, FunctionConstraints* constraints, VectorXd &p); 26 | 27 | protected: 28 | virtual void computeGradient(ObjectiveFunction *objective, const VectorXd& pi); 29 | virtual void computeHessian(ObjectiveFunction *objective, const VectorXd& pi); 30 | virtual void computeConstraintsAndJacobians(FunctionConstraints *constraints, const VectorXd& pi); 31 | 32 | private: 33 | 34 | void computeSearchDirection(const SparseMatrixd& hessian, 35 | const VectorXd& gradient, 36 | const VectorXd &p, 37 | VectorXd &dp, 38 | const SparseMatrixd& A, 39 | const VectorXd& b, 40 | const VectorXd& d, 41 | const SparseMatrixd& C, 42 | const VectorXd& f, 43 | const VectorXd& minBounds, 44 | const VectorXd& maxBounds); 45 | 46 | double doLineSearch(ObjectiveFunction *function, FunctionConstraints *constraints, VectorXd &p, const VectorXd &dp, int maxSteps); 47 | 48 | static double computeMerritFunction(ObjectiveFunction *objective, FunctionConstraints *constraints, const Eigen::VectorXd &x, double mu_k); 49 | 50 | double computeMu(const Eigen::VectorXd &x) const; 51 | 52 | static void computeConstraints(FunctionConstraints *constraints, const Eigen::VectorXd &x, VectorXd &ck); 53 | 54 | public: 55 | int maxLineSearchIterations; 56 | int maxIterations; 57 | double solveResidual; 58 | int lastNumberIterations = -1; 59 | 60 | double mu_min = 1e-10; 61 | double mu_max = 1e10; 62 | mutable double mu_k = 1e-10; 63 | 64 | SparseMatrixd H, A, C; 65 | std::vector smEntries; 66 | VectorXd gradient, ck; 67 | }; 68 | 69 | -------------------------------------------------------------------------------- /assignment6/src/optLib/ooqpei_numerical_comparisons.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef OOQPEI_NUMERICALCOMPARISON_HPP_ 3 | #define OOQPEI_NUMERICALCOMPARISON_HPP_ 4 | 5 | #include // std::max 6 | #include // std::numeric_limits 7 | #include // std::abs 8 | #include // std::invalid_argument 9 | #include "ooqpei_assert_macros.h" 10 | 11 | namespace ooqpei { 12 | 13 | /* 14 | * Functions to compare floating point numbers with a relative error (epsilon). 15 | * 16 | * As the precision of floating point numbers are limited and depending on the 17 | * magnitude, we compare two numbers a and b by comparing their difference |a - b| 18 | * to the magnitude of the the bigger number max(|a|, |b|) multiplied with the 19 | * relative error epsilon. Therefore, a and b are approximately equal if it holds 20 | * |a - b| <= max(|a|, |b|) * epsilon. This can be applied analogously to greater 21 | * and less than comparisons. 22 | * 23 | * More information on compare floating point numbers is given in 24 | * - http://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/ 25 | * - The art of computer programming, Volume 2 / Seminumerical Algorithms, Donald E. Knuth (page 218) 26 | */ 27 | 28 | namespace internal { 29 | 30 | /*! 31 | * Takes max(|a|, |b|) and multiplies it with epsilon. 32 | * @param a the first number. 33 | * @param b the second number. 34 | * @param epsilon the precision (epsilon > 0). 35 | * @return the result of max(|a|, |b|) * epsilon. 36 | */ 37 | template 38 | static inline ValueType_ maxTimesEpsilon(const ValueType_ a, const ValueType_ b, const ValueType_ epsilon) 39 | { 40 | OOQPEI_ASSERT_GT_DBG(std::invalid_argument, epsilon, 0.0, "This method is only valid for an epsilon greater than 0."); 41 | return std::max(std::abs(a), std::abs(b)) * epsilon; 42 | } 43 | 44 | } /* namespace internal */ 45 | 46 | /*! 47 | * Checks if two numbers a and b are equal within a relative error. 48 | * @param[in] a the first number to compare. 49 | * @param[in] b the second number to compare. 50 | * @param[in] epsilon the relative error (optional, if not declared the precision of the datatype). 51 | * @return true if a and b are approximately equal, false otherwise. 52 | */ 53 | template 54 | static bool approximatelyEqual(const ValueType_ a, const ValueType_ b, ValueType_ epsilon = std::numeric_limits::epsilon()) 55 | { 56 | return std::abs(a - b) <= internal::maxTimesEpsilon(a, b, epsilon); 57 | } 58 | 59 | /*! 60 | * Checks if a is greater than b (a > b) within a relative error. 61 | * @param a the first number to compare. 62 | * @param b the second number to compare. 63 | * @param epsilon the relative error (optional, if not declared the precision of the datatype). 64 | * @return true if a definitely greater than b, false otherwise. 65 | */ 66 | template 67 | static bool definitelyGreaterThan(const ValueType_ a, const ValueType_ b, ValueType_ epsilon = std::numeric_limits::epsilon()) 68 | { 69 | return (a - b) > internal::maxTimesEpsilon(a, b, epsilon); 70 | } 71 | 72 | /*! 73 | * Checks if a is less than b (a < b) within a relative error. 74 | * @param a the first number to compare. 75 | * @param b the second number to compare. 76 | * @param epsilon the relative error (optional, if not declared the precision of the datatype). 77 | * @return true if a definitely less than b, false otherwise. 78 | */ 79 | template 80 | static bool definitelyLessThan(const ValueType_ a, const ValueType_ b, ValueType_ epsilon = std::numeric_limits::epsilon()) 81 | { 82 | return (b - a) > internal::maxTimesEpsilon(a, b, epsilon); 83 | } 84 | 85 | } /* namespace ooqpei */ 86 | #endif /* OOQPEI_NUMERICALCOMPARISON_HPP_ */ 87 | -------------------------------------------------------------------------------- /assignment6/src/optLib/ooqpei_source_file_pos.h: -------------------------------------------------------------------------------- 1 | // Copied from Paul Furgale's Schweizer-Messer 2 | 3 | #ifndef OOQPEI_SOURCE_FILE_POS_HPP 4 | #define OOQPEI_SOURCE_FILE_POS_HPP 5 | 6 | #include 7 | #include 8 | #include 9 | // A class and macro that gives you the current file position. 10 | 11 | namespace ooqpei { 12 | 13 | class source_file_pos 14 | { 15 | public: 16 | std::string function; 17 | std::string file; 18 | int line; 19 | 20 | source_file_pos(std::string function, std::string file, int line) : 21 | function(function), file(file), line(line) {} 22 | 23 | operator std::string() 24 | { 25 | return toString(); 26 | } 27 | 28 | std::string toString() const 29 | { 30 | std::stringstream s; 31 | s << file << ":" << line << ": " << function << "()"; 32 | return s.str(); 33 | } 34 | 35 | }; 36 | 37 | }// namespace ooqpei 38 | 39 | inline std::ostream & operator<<(std::ostream & out, const ooqpei::source_file_pos & sfp) 40 | { 41 | out << sfp.file << ":" << sfp.line << ": " << sfp.function << "()"; 42 | return out; 43 | } 44 | 45 | 46 | #define OOQPEI_SOURCE_FILE_POS ooqpei::source_file_pos(__FUNCTION__,__FILE__,__LINE__) 47 | 48 | #endif 49 | -------------------------------------------------------------------------------- /assignment6/src/test_SQP.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | 6 | class Ex1Objective : public ObjectiveFunction { 7 | public: 8 | // Ex 1 9 | }; 10 | 11 | class Ex1Constraint : public FunctionConstraints { 12 | public: 13 | // Ex 1 14 | }; 15 | 16 | int main() { 17 | 18 | ObjectiveFunction* objective; 19 | FunctionConstraints* constraints; 20 | 21 | // Ex 1: uncomment these lines 22 | // objective = new Ex1Objective; 23 | // constraints = new Ex1Constraint; 24 | 25 | SQPFunctionMinimizer minimizer; 26 | VectorXd x(2); x << 100, -100; 27 | minimizer.minimize(objective, constraints, x); 28 | 29 | std::cout << "x = " << x.transpose() << std::endl; 30 | std::cout << "f(x) = " << objective->computeValue(x) << std::endl; 31 | std::cout << "c(x) = " << constraints->getEqualityConstraintValues(x) << std::endl; 32 | std::cout << "# iterations = " << minimizer.lastNumberIterations << std::endl; 33 | } 34 | --------------------------------------------------------------------------------