├── AQP_RepImage.png ├── data ├── jacobson_boy.mat └── paper_deformation_2d_gecko_wConstraints.mat ├── mex ├── projectRotationMex.mexw64 ├── projectRotationMexFast.mexw64 ├── computeFunctionalIsoDistMex.mexw64 ├── computeInjectiveStepSizeMex.mexw64 ├── computeMeshTranformationCoeffsMex.mexw64 ├── mexHelpers.cpp ├── projectRotationMex.cpp ├── projectRotationMexFast.cpp ├── computeFunctionalIsoDistMex.cpp ├── computeMeshTranformationCoeffsMex.cpp └── computeInjectiveStepSizeMex.cpp ├── toolbox ├── toolbox_graph │ ├── read_off.m │ ├── progressbar.m │ └── read_obj.m └── LargeScaleBD │ ├── projectBDMex.mexw64 │ ├── computeMeshTranformationCoeffsMex.mexw64 │ ├── SolverProjectorModeEnum.m │ ├── SolverProjectorBD.m │ └── SolverProjector.m ├── .gitignore ├── code ├── meshHelpers │ ├── getDistortionColormap.m │ ├── indCoordsToLinearSystem.m │ ├── computeTutte.m │ ├── boundaryFaces.m │ └── computeInjectiveStepSize.m ├── mathHelpers │ ├── colStack.m │ ├── spdiag.m │ ├── solveConstrainedLS.m │ ├── getTensorTranspose.m │ └── SparseLU.m ├── OptimProblem.m ├── OptimSolver.m ├── OptimProblemArap.m ├── OptimSolverIterative.m ├── visualizeSolversForExamples.m ├── OptimSolverAcclQuadProx.m └── OptimProblemIsoDist.m ├── .gitattributes ├── initialize.m ├── license.txt ├── compileAllMex.m ├── example_deformation_3d_boy_ARAP.m ├── example_deformation_2d_gecko_IsoDist.m ├── example_parameterization_cow_IsoDist.m ├── README.md ├── example_deformation_2d_bar_ARAP.m └── replicability_instructions.htm /AQP_RepImage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shaharkov/AcceleratedQuadraticProxy/HEAD/AQP_RepImage.png -------------------------------------------------------------------------------- /data/jacobson_boy.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shaharkov/AcceleratedQuadraticProxy/HEAD/data/jacobson_boy.mat -------------------------------------------------------------------------------- /mex/projectRotationMex.mexw64: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shaharkov/AcceleratedQuadraticProxy/HEAD/mex/projectRotationMex.mexw64 -------------------------------------------------------------------------------- /mex/projectRotationMexFast.mexw64: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shaharkov/AcceleratedQuadraticProxy/HEAD/mex/projectRotationMexFast.mexw64 -------------------------------------------------------------------------------- /toolbox/toolbox_graph/read_off.m: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shaharkov/AcceleratedQuadraticProxy/HEAD/toolbox/toolbox_graph/read_off.m -------------------------------------------------------------------------------- /toolbox/toolbox_graph/progressbar.m: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shaharkov/AcceleratedQuadraticProxy/HEAD/toolbox/toolbox_graph/progressbar.m -------------------------------------------------------------------------------- /mex/computeFunctionalIsoDistMex.mexw64: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shaharkov/AcceleratedQuadraticProxy/HEAD/mex/computeFunctionalIsoDistMex.mexw64 -------------------------------------------------------------------------------- /mex/computeInjectiveStepSizeMex.mexw64: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shaharkov/AcceleratedQuadraticProxy/HEAD/mex/computeInjectiveStepSizeMex.mexw64 -------------------------------------------------------------------------------- /toolbox/LargeScaleBD/projectBDMex.mexw64: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shaharkov/AcceleratedQuadraticProxy/HEAD/toolbox/LargeScaleBD/projectBDMex.mexw64 -------------------------------------------------------------------------------- /mex/computeMeshTranformationCoeffsMex.mexw64: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shaharkov/AcceleratedQuadraticProxy/HEAD/mex/computeMeshTranformationCoeffsMex.mexw64 -------------------------------------------------------------------------------- /data/paper_deformation_2d_gecko_wConstraints.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shaharkov/AcceleratedQuadraticProxy/HEAD/data/paper_deformation_2d_gecko_wConstraints.mat -------------------------------------------------------------------------------- /toolbox/LargeScaleBD/computeMeshTranformationCoeffsMex.mexw64: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shaharkov/AcceleratedQuadraticProxy/HEAD/toolbox/LargeScaleBD/computeMeshTranformationCoeffsMex.mexw64 -------------------------------------------------------------------------------- /toolbox/LargeScaleBD/SolverProjectorModeEnum.m: -------------------------------------------------------------------------------- 1 | classdef SolverProjectorModeEnum1) =1; 11 | caxis([1 10]); 12 | end 13 | 14 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | *.sln merge=union 7 | *.csproj merge=union 8 | *.vbproj merge=union 9 | *.fsproj merge=union 10 | *.dbproj merge=union 11 | 12 | # Standard to msysgit 13 | *.doc diff=astextplain 14 | *.DOC diff=astextplain 15 | *.docx diff=astextplain 16 | *.DOCX diff=astextplain 17 | *.dot diff=astextplain 18 | *.DOT diff=astextplain 19 | *.pdf diff=astextplain 20 | *.PDF diff=astextplain 21 | *.rtf diff=astextplain 22 | *.RTF diff=astextplain 23 | -------------------------------------------------------------------------------- /code/mathHelpers/colStack.m: -------------------------------------------------------------------------------- 1 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2 | % Code implementing the paper "Accelerated Quadratic Proxy for Geometric Optimization", SIGGRAPH 2016. 3 | % Disclaimer: The code is provided as-is for academic use only and without any guarantees. 4 | % Please contact the author to report any bugs. 5 | % Written by Shahar Kovalsky (http://www.wisdom.weizmann.ac.il/~shaharko/) 6 | % Meirav Galun (http://www.wisdom.weizmann.ac.il/~/meirav/) 7 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 8 | 9 | function y = colStack(x) 10 | 11 | y = x(:); -------------------------------------------------------------------------------- /code/mathHelpers/spdiag.m: -------------------------------------------------------------------------------- 1 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2 | % Code implementing the paper "Accelerated Quadratic Proxy for Geometric Optimization", SIGGRAPH 2016. 3 | % Disclaimer: The code is provided as-is for academic use only and without any guarantees. 4 | % Please contact the author to report any bugs. 5 | % Written by Shahar Kovalsky (http://www.wisdom.weizmann.ac.il/~shaharko/) 6 | % Meirav Galun (http://www.wisdom.weizmann.ac.il/~/meirav/) 7 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 8 | 9 | function D = spdiag(d) 10 | 11 | n = length(d); 12 | D = sparse(1:n, 1:n, d, n, n); -------------------------------------------------------------------------------- /code/mathHelpers/solveConstrainedLS.m: -------------------------------------------------------------------------------- 1 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2 | % Code implementing the paper "Accelerated Quadratic Proxy for Geometric Optimization", SIGGRAPH 2016. 3 | % Disclaimer: The code is provided as-is for academic use only and without any guarantees. 4 | % Please contact the author to report any bugs. 5 | % Written by Shahar Kovalsky (http://www.wisdom.weizmann.ac.il/~shaharko/) 6 | % Meirav Galun (http://www.wisdom.weizmann.ac.il/~/meirav/) 7 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 8 | 9 | function x = solveConstrainedLS(C, d, A, b) 10 | % minimize ||Cx-d|| s.t. Ax=b 11 | 12 | n_vars = size(A,2); 13 | n_eq = size(A,1); 14 | x_lambda = [C'*C A'; A sparse(n_eq,n_eq)] \ [C'*d; b]; 15 | x = x_lambda(1:n_vars); -------------------------------------------------------------------------------- /code/meshHelpers/indCoordsToLinearSystem.m: -------------------------------------------------------------------------------- 1 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2 | % Code implementing the paper "Accelerated Quadratic Proxy for Geometric Optimization", SIGGRAPH 2016. 3 | % Disclaimer: The code is provided as-is for academic use only and without any guarantees. 4 | % Please contact the author to report any bugs. 5 | % Written by Shahar Kovalsky (http://www.wisdom.weizmann.ac.il/~shaharko/) 6 | % Meirav Galun (http://www.wisdom.weizmann.ac.il/~/meirav/) 7 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 8 | 9 | function [eq_lhs,eq_rhs] = indCoordsToLinearSystem(X,ind,coords) 10 | 11 | eq_lhs_temp = sparse(1:length(ind), ind, 1, length(ind), size(X,1)); 12 | eq_lhs = kron(eq_lhs_temp,eye(size(X,2)))*getTensorTranspose(size(X,1),size(X,2)); 13 | eq_rhs = colStack(coords'); 14 | -------------------------------------------------------------------------------- /code/mathHelpers/getTensorTranspose.m: -------------------------------------------------------------------------------- 1 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2 | % Code implementing the paper "Accelerated Quadratic Proxy for Geometric Optimization", SIGGRAPH 2016. 3 | % Disclaimer: The code is provided as-is for academic use only and without any guarantees. 4 | % Please contact the author to report any bugs. 5 | % Written by Shahar Kovalsky (http://www.wisdom.weizmann.ac.il/~shaharko/) 6 | % Meirav Galun (http://www.wisdom.weizmann.ac.il/~/meirav/) 7 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 8 | 9 | function T = getTensorTranspose(n,m) 10 | % Returns a matrix T such that vec(X')=T*vec(X) for any nxm matrix X. 11 | % 12 | % Example: 13 | % n = 3; 14 | % m = 4; 15 | % X = zeros(n,m); 16 | % X(:)=1:numel(X); 17 | % T = getTensorTranspose(n,m); 18 | % vec(X') 19 | % T*vec(X) 20 | 21 | [i,j] = meshgrid(1:n,1:m); 22 | T = sparse(sub2ind([m n],j,i),sub2ind([n m],i,j),1); -------------------------------------------------------------------------------- /initialize.m: -------------------------------------------------------------------------------- 1 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2 | % Code implementing the paper "Accelerated Quadratic Proxy for Geometric Optimization", SIGGRAPH 2016. 3 | % Disclaimer: The code is provided as-is for academic use only and without any guarantees. 4 | % Please contact the author to report any bugs. 5 | % Written by Shahar Kovalsky (http://www.wisdom.weizmann.ac.il/~shaharko/) 6 | % Meirav Galun (http://www.wisdom.weizmann.ac.il/~/meirav/) 7 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 8 | 9 | function initialize 10 | 11 | % reset timer; 12 | tic; dummy = toc; 13 | 14 | % set paths 15 | if isempty(whos('global','path_def')), 16 | fprintf('- Adding toolbox paths\n'); 17 | 18 | % common path 19 | addpath(genpath('toolbox')); 20 | addpath(genpath('code')); 21 | addpath(genpath('mex')); 22 | 23 | if isunix, 24 | opengl neverselect % disable opengl 25 | set(0, 'DefaultFigureRenderer', 'zbuffer'); 26 | end 27 | 28 | global path_def 29 | end; 30 | -------------------------------------------------------------------------------- /license.txt: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 Shahar Kovalsky 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /code/mathHelpers/SparseLU.m: -------------------------------------------------------------------------------- 1 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2 | % Code implementing the paper "Accelerated Quadratic Proxy for Geometric Optimization", SIGGRAPH 2016. 3 | % Disclaimer: The code is provided as-is for academic use only and without any guarantees. 4 | % Please contact the author to report any bugs. 5 | % Written by Shahar Kovalsky (http://www.wisdom.weizmann.ac.il/~shaharko/) 6 | % Meirav Galun (http://www.wisdom.weizmann.ac.il/~/meirav/) 7 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 8 | 9 | classdef SparseLU < handle 10 | properties 11 | LHS; 12 | L; 13 | U; 14 | p; 15 | q; 16 | end 17 | methods 18 | function obj = SparseLU(LHS) 19 | if ~issparse(LHS) 20 | error('Argument must be a sparse matrix') 21 | end 22 | obj.LHS = LHS; 23 | [obj.L,obj.U, obj.p, obj.q] = lu(LHS, 'vector'); 24 | end 25 | function x = solve(obj,RHS) 26 | x(obj.q,:) = obj.U\(obj.L\(RHS(obj.p,:))); 27 | end 28 | end 29 | 30 | end 31 | 32 | -------------------------------------------------------------------------------- /compileAllMex.m: -------------------------------------------------------------------------------- 1 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2 | % Code implementing the paper "Accelerated Quadratic Proxy for Geometric Optimization", SIGGRAPH 2016. 3 | % Disclaimer: The code is provided as-is for academic use only and without any guarantees. 4 | % Please contact the author to report any bugs. 5 | % Written by Shahar Kovalsky (http://www.wisdom.weizmann.ac.il/~shaharko/) 6 | % Meirav Galun (http://www.wisdom.weizmann.ac.il/~/meirav/) 7 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 8 | 9 | %% 10 | cd mex 11 | 12 | 13 | %% compile all 14 | eigenFolder = 'eigen-eigen-b30b87236a1b'; 15 | 16 | mex('-largeArrayDims',['-I',eigenFolder],'computeMeshTranformationCoeffsMex.cpp'); 17 | mex('-largeArrayDims',['-I',eigenFolder],'computeInjectiveStepSizeMex.cpp'); 18 | mex('-largeArrayDims',['-I',eigenFolder],'projectRotationMex.cpp'); 19 | mex('-largeArrayDims',['-I',eigenFolder],'computeFunctionalIsoDistMex.cpp'); 20 | 21 | 22 | %% fast routines (require libigl) 23 | libiglFolder = 'libigl-master\include\igl'; 24 | 25 | mex('-largeArrayDims',['-I',eigenFolder],['-I',libiglFolder],'projectRotationMexFast.cpp'); 26 | 27 | 28 | %% 29 | cd .. -------------------------------------------------------------------------------- /example_deformation_3d_boy_ARAP.m: -------------------------------------------------------------------------------- 1 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2 | % Code implementing the paper "Accelerated Quadratic Proxy for Geometric Optimization", SIGGRAPH 2016. 3 | % Disclaimer: The code is provided as-is for academic use only and without any guarantees. 4 | % Please contact the author to report any bugs. 5 | % Written by Shahar Kovalsky (http://www.wisdom.weizmann.ac.il/~shaharko/) 6 | % Meirav Galun (http://www.wisdom.weizmann.ac.il/~/meirav/) 7 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 8 | 9 | %% init 10 | rng(1) 11 | clear 12 | initialize 13 | close all 14 | 15 | 16 | %% parameters 17 | num_iter = 100; 18 | visualizeIterations = true; 19 | TolX = 1e-10; 20 | TolFun = 1e-6; 21 | 22 | 23 | %% load problem 24 | load('data\jacobson_boy.mat'); 25 | 26 | 27 | %% setup optimization problem 28 | optimProblem = OptimProblemArap(V, F, eq_lhs, eq_rhs, []); 29 | 30 | 31 | %% setup solver 32 | solver{1} = OptimSolverAcclQuadProx('AQP', optimProblem, true, true, false); solver{1}.setKappa(100); % no need for line search in ARAP 33 | n_solvers = length(solver); 34 | 35 | 36 | %% solve 37 | for ii = 1:n_solvers 38 | logs{ii} = solver{ii}.solveTol(TolX, TolFun ,num_iter); 39 | end 40 | 41 | 42 | %% visualize 43 | visualizeSolversForExamples; 44 | -------------------------------------------------------------------------------- /example_deformation_2d_gecko_IsoDist.m: -------------------------------------------------------------------------------- 1 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2 | % Code implementing the paper "Accelerated Quadratic Proxy for Geometric Optimization", SIGGRAPH 2016. 3 | % Disclaimer: The code is provided as-is for academic use only and without any guarantees. 4 | % Please contact the author to report any bugs. 5 | % Written by Shahar Kovalsky (http://www.wisdom.weizmann.ac.il/~shaharko/) 6 | % Meirav Galun (http://www.wisdom.weizmann.ac.il/~/meirav/) 7 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 8 | 9 | %% init 10 | rng(1) 11 | clear 12 | initialize 13 | close all 14 | 15 | 16 | %% parameters 17 | num_iter = 2500; 18 | visualizeIterations = true; 19 | TolX = 1e-10; 20 | TolFun = 1e-6; 21 | 22 | 23 | %% load problem 24 | load 'data\paper_deformation_2d_gecko_wConstraints.mat'; 25 | 26 | 27 | %% setup optimization problem 28 | optimProblem = OptimProblemIsoDist(V, F, eq_lhs, eq_rhs, [], 25); 29 | 30 | 31 | %% setup solver 32 | solver{1} = OptimSolverAcclQuadProx('AQP', optimProblem, true, true, true); solver{1}.setKappa(1000); 33 | n_solvers = length(solver); 34 | 35 | 36 | %% solve 37 | for ii = 1:n_solvers 38 | logs{ii} = solver{ii}.solveTol(TolX, TolFun ,num_iter); 39 | end 40 | 41 | 42 | %% visualize 43 | visualizeSolversForExamples; 44 | 45 | -------------------------------------------------------------------------------- /code/meshHelpers/computeTutte.m: -------------------------------------------------------------------------------- 1 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2 | % Code implementing the paper "Accelerated Quadratic Proxy for Geometric Optimization", SIGGRAPH 2016. 3 | % Disclaimer: The code is provided as-is for academic use only and without any guarantees. 4 | % Please contact the author to report any bugs. 5 | % Written by Shahar Kovalsky (http://www.wisdom.weizmann.ac.il/~shaharko/) 6 | % Meirav Galun (http://www.wisdom.weizmann.ac.il/~/meirav/) 7 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 8 | 9 | function [V0, inds_bF] = computeTutte(F,V,scale) 10 | 11 | % compute mesh gradient 12 | [T,areas] = computeMeshTranformationCoeffsMex(F, V); 13 | 14 | % constrain boundary to the circle 15 | TR = triangulation(F, V); 16 | temp = freeBoundary(TR); 17 | inds_bF = temp(:,1); %boundary vertices indices 18 | bn_vert = length(inds_bF); %number of boundary verts 19 | tet = 0: (2*pi / bn_vert) : 2*pi; 20 | tet(end)=[]; 21 | tet = tet'; 22 | [eq_lhs,eq_rhs] = indCoordsToLinearSystem(V(:,1:2), inds_bF, 1*[cos(tet) sin(tet)] ); 23 | 24 | % compute tutte 25 | wT = spdiag(kron(sqrt(areas), ones(4,1)))*T; 26 | V0 = reshape(solveConstrainedLS(wT,zeros(size(T,1),1),eq_lhs,eq_rhs),[],2); 27 | 28 | % global scale (isometric as possible) 29 | if scale 30 | V0 = ((T*V0(:))\colStack(repmat(eye(2),[1 1 size(F,1)]))) * V0; 31 | end 32 | 33 | -------------------------------------------------------------------------------- /mex/mexHelpers.cpp: -------------------------------------------------------------------------------- 1 | //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2 | //% Code implementing the paper "Accelerated Quadratic Proxy for Geometric Optimization", SIGGRAPH 2016. 3 | //% Disclaimer: The code is provided as-is for academic use only and without any guarantees. 4 | //% Please contact the author to report any bugs. 5 | //% Written by Shahar Kovalsky (http://www.wisdom.weizmann.ac.il/~shaharko/) 6 | //% Meirav Galun (http://www.wisdom.weizmann.ac.il/~/meirav/) 7 | //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 8 | 9 | #include "mex.h" 10 | #include 11 | #include 12 | 13 | using namespace Eigen; 14 | 15 | void mapSparseMatrixToMex(const SparseMatrix& mat, mxArray **out) 16 | { 17 | *out = mxCreateSparse(mat.rows(), mat.cols(), mat.nonZeros(), mxREAL); 18 | 19 | mwIndex *Ir, *Jc; 20 | double *Pr; 21 | Ir = mxGetIr(*out); 22 | Jc = mxGetJc(*out); 23 | Pr = mxGetPr(*out); 24 | 25 | for (int k = 0; k < mat.nonZeros(); k++) 26 | { 27 | Pr[k] = (mat.valuePtr())[k]; 28 | Ir[k] = (mat.innerIndexPtr())[k]; 29 | } 30 | for (int k = 0; k <= mat.cols(); k++) 31 | { 32 | Jc[k] = (mat.outerIndexPtr())[k]; 33 | } 34 | } 35 | 36 | void mapDenseMatrixToMex(const MatrixXd& mat, mxArray **out) 37 | { 38 | *out = mxCreateDoubleMatrix(mat.rows(), mat.cols(), mxREAL); 39 | Map temp(mxGetPr(*out), mat.rows(), mat.cols()); 40 | temp = mat; // copy 41 | } -------------------------------------------------------------------------------- /toolbox/toolbox_graph/read_obj.m: -------------------------------------------------------------------------------- 1 | function [vertex,faces,normal] = read_obj(filename) 2 | 3 | % read_obj - load a .obj file. 4 | % 5 | % [vertex,face,normal] = read_obj(filename); 6 | % 7 | % faces : list of facesangle elements 8 | % vertex : node vertexinatates 9 | % normal : normal vector list 10 | % 11 | % Copyright (c) 2008 Gabriel Peyre 12 | 13 | fid = fopen(filename); 14 | if fid<0 15 | error(['Cannot open ' filename '.']); 16 | end 17 | 18 | frewind(fid); 19 | a = fscanf(fid,'%c',1); 20 | if strcmp(a, 'P') 21 | % This is the montreal neurological institute (MNI) specific ASCII facesangular mesh data structure. 22 | % For FreeSurfer software, a slightly different data input coding is 23 | % needed. It will be provided upon request. 24 | fscanf(fid,'%f',5); 25 | n_points=fscanf(fid,'%i',1); 26 | vertex=fscanf(fid,'%f',[3,n_points]); 27 | normal=fscanf(fid,'%f',[3,n_points]); 28 | n_faces=fscanf(fid,'%i',1); 29 | fscanf(fid,'%i',5+n_faces); 30 | faces=fscanf(fid,'%i',[3,n_faces])'+1; 31 | fclose(fid); 32 | return; 33 | end 34 | 35 | frewind(fid); 36 | vertex = []; 37 | faces = []; 38 | while 1 39 | s = fgetl(fid); 40 | if ~ischar(s), 41 | break; 42 | end 43 | if ~isempty(s) && strcmp(s(1), 'f') 44 | % face 45 | faces(:,end+1) = sscanf(s(3:end), '%d %d %d'); 46 | end 47 | if ~isempty(s) && strcmp(s(1), 'v') 48 | % vertex 49 | vertex(:,end+1) = sscanf(s(3:end), '%f %f %f'); 50 | end 51 | end 52 | fclose(fid); 53 | 54 | -------------------------------------------------------------------------------- /example_parameterization_cow_IsoDist.m: -------------------------------------------------------------------------------- 1 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2 | % Code implementing the paper "Accelerated Quadratic Proxy for Geometric Optimization", SIGGRAPH 2016. 3 | % Disclaimer: The code is provided as-is for academic use only and without any guarantees. 4 | % Please contact the author to report any bugs. 5 | % Written by Shahar Kovalsky (http://www.wisdom.weizmann.ac.il/~shaharko/) 6 | % Meirav Galun (http://www.wisdom.weizmann.ac.il/~/meirav/) 7 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 8 | 9 | %% init 10 | rng(1) 11 | clear 12 | initialize 13 | close all 14 | 15 | 16 | %% parameters 17 | num_iter = 3000; 18 | visualizeIterations = true; 19 | TolX = 1e-10; 20 | TolFun = 1e-6; 21 | 22 | 23 | %% generate problem 24 | % load mesh 25 | [V, F] = read_off('data\schaeffer_cow.off'); 26 | V=V'; F=F'; F = F(:,[1 3 2]); 27 | % initialize with tutte 28 | [V0, inds_bF] = computeTutte(F,V,true); % global scale to be as ismetric as possible 29 | % constrain the centroid 30 | eq_lhs_centroid = kron(eye(2),sparse(1,inds_bF,1,1,size(V,1))); 31 | eq_rhs_centroid = [0;0]; 32 | 33 | 34 | %% setup optimization problem 35 | optimProblem = OptimProblemIsoDist(V, F, eq_lhs_centroid, eq_rhs_centroid, V0); 36 | 37 | 38 | %% setup solver 39 | solver{1} = OptimSolverAcclQuadProx('AQP', optimProblem, true, true, true); solver{1}.setKappa(1000); 40 | n_solvers = length(solver); 41 | 42 | 43 | %% solve 44 | for ii = 1:n_solvers 45 | logs{ii} = solver{ii}.solveTol(TolX, TolFun ,num_iter); 46 | end 47 | 48 | 49 | %% visualize 50 | visualizeSolversForExamples; 51 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Accelerated Quadratic Proxy for Geometric Optimization 2 | ==== 3 | 4 | A Matlab implementation of the paper ["Accelerated Quadratic Proxy for Geometric Optimization"](https://shaharkov.github.io/AcceleratedQuadraticProxy.html). 5 | 6 | ---- 7 | The class `OptimSolverAcclQuadProx.m` implements the accelerated quadratic proxy optimization algorithm described in the paper for the minimization of geometric energies. 8 | 9 | This package includes a few examples: 10 | - `example_deformation_2d_gecko_IsoDist.m` demonstrates the minimization of the Isometric Distortion energy for shape deformation (Figure 1 in the paper). 11 | - `example_parameterization_cow_IsoDist.m` demonstrates the minimization of the Isometric Distortion energy for parameterization (the cow of Figure 12 in the paper). 12 | - `example_deformation_2d_bar_ARAP.m` and `example_deformation_3d_boy_ARAP.m` demonstrate the minimization of the As-Rigid-As-Possible energy for shape deformation (see https://goo.gl/skatVH and https://goo.gl/iYXJaP for video clips). 13 | 14 | **Compatibility and dependencies:** The code was tested with Matlab (2015a). The code depends on a few MEX functions. Windows (x64) binaries are included; they are compiled with Intel C++ Composer XE 2016 with Microsoft Visual Studio 2013; compilation requires [Eigen](http://eigen.tuxfamily.org/); fast implementation of As-Rigid-As-Possible also relies on [libigl](https://github.com/libigl/libigl). The source code is provided under the `mex/` folder; run `compileAllMex.m` to compile all mex files (only tested under windows). 15 | 16 | **Disclaimer:** 17 | The code is provided as-is for academic use only and without any guarantees. Please contact the authors to report any bugs. 18 | Written by [Shahar Kovalsky](https://shaharkov.github.io/) and [Meirav Galun](http://www.wisdom.weizmann.ac.il/~/meirav/). 19 | -------------------------------------------------------------------------------- /mex/projectRotationMex.cpp: -------------------------------------------------------------------------------- 1 | //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2 | //% Code implementing the paper "Accelerated Quadratic Proxy for Geometric Optimization", SIGGRAPH 2016. 3 | //% Disclaimer: The code is provided as-is for academic use only and without any guarantees. 4 | //% Please contact the author to report any bugs. 5 | //% Written by Shahar Kovalsky (http://www.wisdom.weizmann.ac.il/~shaharko/) 6 | //% Meirav Galun (http://www.wisdom.weizmann.ac.il/~/meirav/) 7 | //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 8 | 9 | #include "mex.h" 10 | #include 11 | #include 12 | #include "mexHelpers.cpp" 13 | 14 | using namespace Eigen; 15 | 16 | void projBlockRotation(VectorXd &pA, int dim) 17 | { 18 | int block_size = dim*dim; 19 | int num_blocks = pA.size() / block_size; 20 | JacobiSVD svdA(dim, dim, (ComputeFullU | ComputeFullV)); 21 | bool flipped; 22 | MatrixXd U, V; 23 | Map currA(pA.data(), dim, dim); 24 | 25 | // project 26 | for (int ii = 0; ii < num_blocks; ii++) 27 | { 28 | // get current block 29 | new (&currA) Map(pA.data() + ii*block_size, dim, dim); 30 | // sign of determinant 31 | flipped = (currA.determinant() < 0); 32 | // svd 33 | svdA.compute(currA); 34 | // compute frames 35 | U = svdA.matrixU(); 36 | V = svdA.matrixV(); 37 | // ssvd 38 | if (flipped) 39 | { 40 | U.col(dim - 1) = -U.col(dim - 1); 41 | } 42 | // project block 43 | currA = U*V.transpose(); 44 | } 45 | } 46 | 47 | void mexFunction(int nlhs, mxArray *plhs[], 48 | int nrhs, const mxArray*prhs[]) 49 | 50 | { 51 | // assign input 52 | int A_rows = mxGetM(prhs[0]); // # rows of A 53 | int A_cols = mxGetN(prhs[0]); // # cols of A 54 | double *dim; 55 | const Map A(mxGetPr(prhs[0]), A_rows, A_cols); 56 | dim = mxGetPr(prhs[1]); 57 | 58 | // init output 59 | VectorXd pA(A_rows); 60 | pA = A; 61 | 62 | // project 63 | projBlockRotation(pA, *dim); 64 | 65 | // assign outputs 66 | mapDenseMatrixToMex(pA, &(plhs[0])); 67 | 68 | } -------------------------------------------------------------------------------- /code/OptimProblem.m: -------------------------------------------------------------------------------- 1 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2 | % Code implementing the paper "Accelerated Quadratic Proxy for Geometric Optimization", SIGGRAPH 2016. 3 | % Disclaimer: The code is provided as-is for academic use only and without any guarantees. 4 | % Please contact the author to report any bugs. 5 | % Written by Shahar Kovalsky (http://www.wisdom.weizmann.ac.il/~shaharko/) 6 | % Meirav Galun (http://www.wisdom.weizmann.ac.il/~/meirav/) 7 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 8 | 9 | classdef (Abstract) OptimProblem < handle 10 | properties 11 | % problem 12 | T; 13 | eq_lhs; 14 | eq_rhs; 15 | x0; 16 | n_vars; 17 | n_eq; 18 | H; 19 | 20 | % parameters 21 | verbose = 2; 22 | end 23 | 24 | methods (Abstract) 25 | evaluateFunctional(obj, x, doVal, doGrad, doHess) 26 | setQuadraticProxy(obj) 27 | getMaxStep(obj, x, p) 28 | end 29 | 30 | methods 31 | function obj = OptimProblem 32 | end 33 | 34 | function initProblem(obj) 35 | obj.n_vars = size(obj.T,2); 36 | obj.n_eq = size(obj.eq_lhs,1); 37 | end 38 | 39 | function f = evaluateValue(obj, x) 40 | f = evaluateFunctional(obj, x, true, false, false); 41 | end 42 | function f_grad = evaluateGrad(obj, x) 43 | f_grad = evaluateFunctional(obj, x, false, true, false); 44 | end 45 | function [f, f_grad] = evaluateValueGrad(obj, x) 46 | [f, f_grad] = evaluateFunctional(obj, x, true, true, false); 47 | end 48 | 49 | function [estH,err] = estimateHessian(obj, x) 50 | [estH,err] = hessian(@(x) obj.evaluateFunctional(x, true, false, false) ,x); 51 | end 52 | 53 | function report(obj,verbosity,varargin) 54 | if verbosity<=obj.verbose 55 | fprintf(varargin{:}); 56 | end 57 | end 58 | end 59 | 60 | end -------------------------------------------------------------------------------- /code/meshHelpers/boundaryFaces.m: -------------------------------------------------------------------------------- 1 | % Code implementing the paper "Injective and Bounded Mappings in 3D". 2 | % Disclaimer: The code is provided as-is and without any guarantees. Please contact the author to report any bugs. 3 | % Written by Noam Aigerman, http://www.wisdom.weizmann.ac.il/~noamaig/ 4 | 5 | function [F,inds] = boundaryFaces(T,keep) 6 | %compute the boundary faces F of the given tetrahedral mesh 7 | % keep is an optional boolean vector that forces to keep all faces of 8 | % any tet that its cooresponding entry in "keep" is non-zero 9 | %returns: 10 | %F: n x 3 array of all faces from T that are boundary or belong to a tet 11 | % that is marked as 1 in "keep". 12 | %inds(i)==k iff the the boundary face F(i,:) belongs to the tetrahedron 13 | %T(k,:) 14 | 15 | %alec jacobson's code with slight modification 16 | 17 | if isempty(T) || (nargin>1 && isempty(keep)); 18 | F=[]; 19 | inds=[]; 20 | return; 21 | end 22 | if nargin==1 23 | keep=zeros(size(T,1),1); 24 | end 25 | % BOUNDARY_FACES 26 | % F = boundary_faces(T) 27 | % Determine boundary faces of tetrahedra stored in T 28 | % 29 | % Input: 30 | % T tetrahedron index list, m by 4, where m is the number of tetrahedra 31 | % 32 | % Output: 33 | % F list of boundary faces, n by 3, where n is the number of boundary faces 34 | % 35 | 36 | % get all faces 37 | allF = [ ... 38 | T(:,1) T(:,2) T(:,3); ... 39 | T(:,1) T(:,3) T(:,4); ... 40 | T(:,1) T(:,4) T(:,2); ... 41 | T(:,2) T(:,4) T(:,3)]; 42 | keep=[keep;keep;keep;keep]~=0; 43 | % sort rows so that faces are reorder in ascending order of indices 44 | sortedF = sort(allF,2); 45 | % determine uniqueness of faces 46 | [u,~,n] = unique(sortedF,'rows'); 47 | % determine counts for each unique face 48 | counts = accumarray(n(:), 1); 49 | % extract faces that only occurred once 50 | sorted_exteriorF = u(counts == 1,:); 51 | % find in original faces so that ordering of indices is correct 52 | use=ismember(sortedF,sorted_exteriorF,'rows')|keep; 53 | F = allF(use,:); 54 | 55 | if nargout>1 56 | inds=1:size(T,1); 57 | inds=[inds inds inds inds]'; 58 | 59 | inds=inds(use); 60 | end 61 | end 62 | -------------------------------------------------------------------------------- /code/OptimSolver.m: -------------------------------------------------------------------------------- 1 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2 | % Code implementing the paper "Accelerated Quadratic Proxy for Geometric Optimization", SIGGRAPH 2016. 3 | % Disclaimer: The code is provided as-is for academic use only and without any guarantees. 4 | % Please contact the author to report any bugs. 5 | % Written by Shahar Kovalsky (http://www.wisdom.weizmann.ac.il/~shaharko/) 6 | % Meirav Galun (http://www.wisdom.weizmann.ac.il/~/meirav/) 7 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 8 | 9 | classdef (Abstract) OptimSolver < handle 10 | properties 11 | % solver vars 12 | optimProblem; 13 | x; 14 | 15 | % solver parameters 16 | 17 | % log 18 | tag = ''; 19 | verbose = 2; 20 | 21 | % default solver parameters 22 | default_max_iter = 500; 23 | default_TolX = 1e-10; 24 | default_TolFun = 1e-6; 25 | end 26 | 27 | properties (Dependent) 28 | X; 29 | end 30 | 31 | methods (Abstract) 32 | solveTol(obj, TolX, TolFun, max_iter) 33 | end 34 | 35 | methods 36 | function obj = OptimSolver 37 | 38 | end 39 | 40 | function value = get.X(obj) 41 | value = reshape(obj.x,size(obj.optimProblem.x0)); 42 | end 43 | 44 | function initSolver(obj, tag, optimProblem) 45 | % copy 46 | obj.tag = tag; 47 | obj.optimProblem = optimProblem; 48 | obj.x = obj.optimProblem.x0(:); 49 | % report 50 | obj.report(1,'Constructing %s::%s (#var: %d)\n', obj.tag, class(obj), obj.optimProblem.n_vars); 51 | end 52 | 53 | function log = solveN(obj,num_iter) 54 | log = obj.solveTol(0, 0, num_iter); 55 | end 56 | 57 | function log = solveDefault(obj) 58 | log = obj.solveTol(obj.default_TolX, obj.default_TolFun, obj.default_max_iter); 59 | end 60 | 61 | function report(obj,verbosity,varargin) 62 | if verbosity<=obj.verbose 63 | fprintf(varargin{:}); 64 | end 65 | end 66 | end 67 | end -------------------------------------------------------------------------------- /example_deformation_2d_bar_ARAP.m: -------------------------------------------------------------------------------- 1 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2 | % Code implementing the paper "Accelerated Quadratic Proxy for Geometric Optimization", SIGGRAPH 2016. 3 | % Disclaimer: The code is provided as-is for academic use only and without any guarantees. 4 | % Please contact the author to report any bugs. 5 | % Written by Shahar Kovalsky (http://www.wisdom.weizmann.ac.il/~shaharko/) 6 | % Meirav Galun (http://www.wisdom.weizmann.ac.il/~/meirav/) 7 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 8 | 9 | %% init 10 | rng(1) 11 | clear 12 | initialize 13 | close all 14 | 15 | 16 | %% parameters 17 | num_iter = 500; 18 | visualizeIterations = false; 19 | TolX = 1e-10; 20 | TolFun = 1e-6; 21 | 22 | 23 | %% generate problem 24 | n=500; 25 | theta = 170; 26 | 27 | n_x = n; 28 | n_y = ceil(n/20.0); 29 | 30 | [x, y] = meshgrid(1:n_x, 1:n_y); 31 | x = x(:); y = y(:); 32 | V = [x, y]; 33 | F = delaunay(V); 34 | 35 | anchors_fix = find(x<2); 36 | anchor_fix_coords = V(anchors_fix,:); 37 | anchors_move = find(x==n_x); 38 | 39 | ctr = mean(V); 40 | theta = theta *pi/180; 41 | rot = [cos(theta) sin(theta); -sin(theta) cos(theta)]; 42 | anchor_move_coords = bsxfun(@plus,bsxfun(@minus,V(anchors_move,:),ctr)*rot,ctr); 43 | 44 | % compute corresponding linear system 45 | [eq_lhs_fix,eq_rhs_fix] = indCoordsToLinearSystem(V,anchors_fix,anchor_fix_coords); 46 | [eq_lhs_move,eq_rhs_move] = indCoordsToLinearSystem(V,anchors_move,anchor_move_coords); 47 | 48 | 49 | eq_lhs = [eq_lhs_fix; eq_lhs_move]; 50 | eq_rhs = [eq_rhs_fix; eq_rhs_move]; 51 | 52 | 53 | %% init - poisson 54 | T = computeMeshTranformationCoeffsMex(F, V); 55 | V0 = reshape(solveConstrainedLS(T, zeros(size(T,1),1), eq_lhs, eq_rhs),[],2); 56 | 57 | 58 | %% setup optimization problem 59 | optimProblem = OptimProblemArap(V, F, eq_lhs, eq_rhs, V0); % actually start with V0 60 | 61 | 62 | %% setup solver 63 | solver{1} = OptimSolverAcclQuadProx('AQP', optimProblem, true, true, false); solver{1}.setKappa(100); 64 | solver{2} = OptimSolverAcclQuadProx('Global-Local', optimProblem, false, true, false); % AQP without acceleration reduces to global-local (see Appendix B) 65 | n_solvers = length(solver); 66 | 67 | 68 | %% solve 69 | for ii = 1:n_solvers 70 | logs{ii} = solver{ii}.solveTol(TolX, TolFun ,num_iter); 71 | end 72 | 73 | 74 | %% visualize 75 | visualizeSolversForExamples -------------------------------------------------------------------------------- /mex/projectRotationMexFast.cpp: -------------------------------------------------------------------------------- 1 | //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2 | //% Code implementing the paper "Accelerated Quadratic Proxy for Geometric Optimization", SIGGRAPH 2016. 3 | //% Disclaimer: The code is provided as-is for academic use only and without any guarantees. 4 | //% Please contact the author to report any bugs. 5 | //% Written by Shahar Kovalsky (http://www.wisdom.weizmann.ac.il/~shaharko/) 6 | //% Meirav Galun (http://www.wisdom.weizmann.ac.il/~/meirav/) 7 | //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 8 | 9 | #include "mex.h" 10 | #include 11 | #include 12 | #include "mexHelpers.cpp" 13 | #include 14 | 15 | using namespace Eigen; 16 | using namespace igl; 17 | 18 | void projBlockRotation2x2(VectorXd &pA, int dim) 19 | { 20 | int block_size = dim*dim; 21 | int num_blocks = pA.size() / block_size; 22 | Map currA(pA.data(), dim, dim); 23 | Vector2d b; 24 | 25 | // project 26 | for (int ii = 0; ii < num_blocks; ii++) 27 | { 28 | // get current block 29 | new (&currA) Map(pA.data() + ii*block_size, dim, dim); 30 | // closest similarity 31 | b << 0.5*(currA(0, 0) + currA(1, 1)), 0.5*(currA(0, 1) - currA(1, 0)); // first row of B 32 | // closest rotation 33 | b = b / b.norm(); 34 | currA << b(0), b(1), -b(1), b(0); 35 | } 36 | } 37 | 38 | void projBlockRotation3x3(VectorXd &pA, int dim) 39 | { 40 | int block_size = dim*dim; 41 | int num_blocks = pA.size() / block_size; 42 | 43 | Matrix3f currAf, R; 44 | Matrix3f U, V; 45 | Vector3f s; 46 | Map currA(pA.data()); 47 | 48 | // project 49 | for (int ii = 0; ii < num_blocks; ii++) 50 | { 51 | // get current block 52 | new (&currA) Map(pA.data() + ii*block_size, dim, dim); 53 | // 54 | currAf = currA.cast(); // double -> single 55 | svd3x3(currAf, U, s, V); // svd 56 | R = U * V.transpose(); // polar 57 | currA = R.cast(); 58 | } 59 | } 60 | 61 | void mexFunction(int nlhs, mxArray *plhs[], 62 | int nrhs, const mxArray*prhs[]) 63 | 64 | { 65 | // assign input 66 | int A_rows = mxGetM(prhs[0]); // # rows of A 67 | int A_cols = mxGetN(prhs[0]); // # cols of A 68 | double *dim; 69 | const Map A(mxGetPr(prhs[0]), A_rows, A_cols); 70 | dim = mxGetPr(prhs[1]); 71 | 72 | // init output 73 | VectorXd pA(A_rows); 74 | pA = A; 75 | 76 | // project 77 | if (*dim == 2) 78 | projBlockRotation2x2(pA, *dim); 79 | else if (*dim == 3) 80 | projBlockRotation3x3(pA, *dim); 81 | else 82 | mexErrMsgIdAndTxt("MATLAB:wrong_dimension", "dim must be either 2 or 3"); 83 | 84 | // assign outputs 85 | mapDenseMatrixToMex(pA, &(plhs[0])); 86 | 87 | } -------------------------------------------------------------------------------- /toolbox/LargeScaleBD/SolverProjectorBD.m: -------------------------------------------------------------------------------- 1 | classdef SolverProjectorBD < SolverProjector 2 | 3 | properties 4 | K; 5 | lb; 6 | ub; 7 | dim; 8 | distortions; 9 | flips; 10 | minsv; 11 | maxsv; 12 | end 13 | 14 | methods 15 | function obj = SolverProjectorBD(F, V, eqLHS, eqRHS, K, lb, ub, x0, mode) 16 | t_start = tic; 17 | obj.eqLHS = eqLHS; 18 | obj.eqRHS = eqRHS; 19 | obj.x0 = x0; 20 | obj.mode = mode; 21 | obj.K = K; 22 | obj.lb = lb; 23 | obj.ub = ub; 24 | obj.dim = size(F,2)-1; 25 | [obj.T,areas] = computeMeshTranformationCoeffsMex(F, V); 26 | weights = kron(sqrt(areas),ones(obj.dim^2,1)); 27 | obj.W = sparse(1:length(weights),1:length(weights),weights); 28 | %obj.W = 1; 29 | obj.initSolver(); 30 | obj.report(1,'SolverProjectorBD is ready (%.3g secs)\n', toc(t_start)); 31 | end 32 | 33 | function projectD_(obj) 34 | [obj.pTx, obj.distortions, obj.flips, obj.minsv, obj.maxsv] = projectBDMex(obj.Tx, obj.dim, obj.K, obj.lb, obj.ub); 35 | end 36 | 37 | function solve(obj, iter_max, tol_err, verbose) 38 | 39 | fprintf('-----------------------------------------------------------------\n'); 40 | fprintf('BD PROJECTION (K=%g):\n', obj.K); 41 | fprintf('-----------------------------------------------------------------\n'); 42 | fprintf('initial max dist %g, flips %d, infeasible %d\n', max(obj.distortions), nnz(obj.flips), nnz((obj.distortions>obj.K)|obj.flips)); 43 | fprintf('(min sv %g, max sv %d)\n', min(abs(obj.minsv)), max(obj.maxsv)); 44 | fprintf('-----------------------------------------------------------------\n'); 45 | for iter = 1:iter_max 46 | obj.iterate(); 47 | err = mse(obj.tanNormal); 48 | if verbose 49 | fprintf('iter %d -- err: %g dist: %g flips: %g time: %g sec (pD:%d%%, pL:%d%%)\n',iter,err,max(obj.distortions),nnz(obj.flips),obj.t_iter,round(100*obj.t_projectD/obj.t_iter), round(100*obj.t_projectLinear/obj.t_iter)); 50 | end 51 | if (err stopping...\n'); 53 | break; 54 | end 55 | end 56 | fprintf('-----------------------------------------------------------------\n'); 57 | fprintf('final max dist %g, flips %d, infeasible %d\n', max(obj.distortions), nnz(obj.flips), nnz((obj.distortions>obj.K)|obj.flips)); 58 | fprintf('-----------------------------------------------------------------\n'); 59 | 60 | 61 | end 62 | end 63 | 64 | end 65 | 66 | -------------------------------------------------------------------------------- /mex/computeFunctionalIsoDistMex.cpp: -------------------------------------------------------------------------------- 1 | //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2 | //% Code implementing the paper "Accelerated Quadratic Proxy for Geometric Optimization", SIGGRAPH 2016. 3 | //% Disclaimer: The code is provided as-is for academic use only and without any guarantees. 4 | //% Please contact the author to report any bugs. 5 | //% Written by Shahar Kovalsky (http://www.wisdom.weizmann.ac.il/~shaharko/) 6 | //% Meirav Galun (http://www.wisdom.weizmann.ac.il/~/meirav/) 7 | //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 8 | 9 | #include "mex.h" 10 | #include 11 | #include 12 | #include "mexHelpers.cpp" 13 | 14 | using namespace Eigen; 15 | 16 | void helperFcuntionalIsoDist2x2(VectorXd &pA, const VectorXd &areas, int dim, double& val, bool& flips) 17 | { 18 | int block_size = dim*dim; 19 | int num_blocks = pA.size() / block_size; 20 | Map currA(pA.data(), dim, dim); 21 | Matrix2d currA_inv; 22 | 23 | // project 24 | val = 0; 25 | flips = 0; 26 | for (int ii = 0; ii < num_blocks; ii++) 27 | { 28 | // get current block 29 | new (&currA) Map(pA.data() + ii*block_size, dim, dim); 30 | // check inverse 31 | flips = flips || (currA.determinant() < 0); 32 | // compute inverse 33 | currA_inv = currA.inverse(); 34 | val = val + areas(ii) * (currA.squaredNorm() + currA_inv.squaredNorm()); 35 | // compute Tx_grad 36 | currA = 2 * areas(ii) * (currA - currA_inv.transpose()*currA_inv*currA_inv.transpose()); 37 | } 38 | } 39 | 40 | void helperFcuntionalIsoDist3x3(VectorXd &pA, const VectorXd &areas, int dim, double& val, bool& flips) 41 | { 42 | int block_size = dim*dim; 43 | int num_blocks = pA.size() / block_size; 44 | Map currA(pA.data(), dim, dim); 45 | Matrix3d currA_inv; 46 | 47 | // project 48 | val = 0; 49 | flips = 0; 50 | for (int ii = 0; ii < num_blocks; ii++) 51 | { 52 | // get current block 53 | new (&currA) Map(pA.data() + ii*block_size, dim, dim); 54 | // check inverse 55 | flips = flips || (currA.determinant() < 0); 56 | // compute inverse 57 | currA_inv = currA.inverse(); 58 | val = val + areas(ii) * (currA.squaredNorm() + currA_inv.squaredNorm()); 59 | // compute Tx_grad 60 | currA = 2 * areas(ii) * (currA - currA_inv.transpose()*currA_inv*currA_inv.transpose()); 61 | } 62 | } 63 | 64 | void mexFunction(int nlhs, mxArray *plhs[], 65 | int nrhs, const mxArray*prhs[]) 66 | { 67 | // assign input 68 | int A_rows = mxGetM(prhs[0]); // # rows of A 69 | int A_cols = mxGetN(prhs[0]); // # cols of A 70 | int areas_rows = mxGetM(prhs[1]); // # rows of A 71 | int areas_cols = mxGetN(prhs[1]); // # cols of A 72 | double *dim; 73 | double val; 74 | bool flips; 75 | const Map A(mxGetPr(prhs[0]), A_rows, A_cols); 76 | const Map areas(mxGetPr(prhs[1]), areas_rows, areas_cols); 77 | dim = mxGetPr(prhs[2]); 78 | 79 | if (A_cols!=1) 80 | mexErrMsgIdAndTxt("MATLAB:wrong_input", "first argument must be a column vector"); 81 | if (areas_cols != 1) 82 | mexErrMsgIdAndTxt("MATLAB:wrong_input", "second argument must be a column vector"); 83 | 84 | // copy 85 | VectorXd pA(A_rows); 86 | pA = A; 87 | 88 | // compute 89 | if (*dim == 2) 90 | helperFcuntionalIsoDist2x2(pA, areas, *dim, val, flips); 91 | else if (*dim == 3) 92 | helperFcuntionalIsoDist3x3(pA, areas, *dim, val, flips); 93 | else 94 | mexErrMsgIdAndTxt("MATLAB:wrong_dimension", "dim must be either 2 or 3"); 95 | 96 | // output 97 | plhs[0] = mxCreateDoubleScalar(val); // functional value 98 | mapDenseMatrixToMex(pA, &(plhs[1])); // return Tx_grad 99 | plhs[2] = mxCreateLogicalScalar(flips); // were there any flips 100 | } -------------------------------------------------------------------------------- /code/OptimProblemArap.m: -------------------------------------------------------------------------------- 1 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2 | % Code implementing the paper "Accelerated Quadratic Proxy for Geometric Optimization", SIGGRAPH 2016. 3 | % Disclaimer: The code is provided as-is for academic use only and without any guarantees. 4 | % Please contact the author to report any bugs. 5 | % Written by Shahar Kovalsky (http://www.wisdom.weizmann.ac.il/~shaharko/) 6 | % Meirav Galun (http://www.wisdom.weizmann.ac.il/~/meirav/) 7 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 8 | 9 | classdef OptimProblemArap < OptimProblem 10 | properties 11 | % mesh (keep here?) 12 | V; 13 | F; 14 | dim; 15 | n_vert; 16 | n_tri; 17 | areas; 18 | w; 19 | 20 | % internal variables 21 | Tx; 22 | R; 23 | wTxMinusR; 24 | end 25 | 26 | methods 27 | function obj = OptimProblemArap(V, F, eq_lhs, eq_rhs, V0) 28 | % copy 29 | obj.V = V; 30 | obj.F = F; 31 | obj.eq_lhs = eq_lhs; 32 | obj.eq_rhs = eq_rhs; 33 | obj.dim = size(F,2)-1; 34 | obj.n_vert = size(V,1); 35 | obj.n_tri = size(F,1); 36 | % report 37 | obj.report(1,'Constructing %s (dim: %d #vert: %d #elem: %d)\n', class(obj), obj.dim, obj.n_vert, obj.n_tri); 38 | % compute transformations 39 | [obj.T,obj.areas] = computeMeshTranformationCoeffsMex(F, V); 40 | % set weights 41 | obj.w = kron(sqrt(obj.areas), ones(obj.dim^2,1)); 42 | % set initial configuration 43 | obj.x0 = obj.initVertices(V0); 44 | % set quadratic proxy 45 | obj.H = obj.setQuadraticProxy(); 46 | % finish construction 47 | obj.initProblem(); 48 | end 49 | 50 | function x0 = initVertices(obj, V0) 51 | % feasible initialization -- provide input or a single local-global step 52 | if ~isempty(V0) 53 | x0 = V0; 54 | else 55 | obj.Tx = obj.T*obj.V(:); 56 | obj.R = projectRotationMexFast(obj.Tx, obj.dim); 57 | x0 = solveConstrainedLS(obj.T, obj.R, obj.eq_lhs, obj.eq_rhs); 58 | x0 = reshape(x0, obj.n_vert, obj.dim); 59 | end 60 | end 61 | 62 | function [varargout] = evaluateFunctional(obj, x, doVal, doGrad, doHess) 63 | assert(~doHess, 'Hessian computation is not implementated for this functional'); 64 | % evaluate 65 | obj.Tx = obj.T*x; 66 | obj.R = projectRotationMexFast(obj.Tx, obj.dim); 67 | obj.wTxMinusR = obj.w.*(obj.Tx-obj.R); 68 | n_arg = 0; 69 | if doVal 70 | n_arg = n_arg + 1; 71 | varargout{n_arg} = sum(obj.wTxMinusR.^2); 72 | end 73 | if doGrad 74 | n_arg = n_arg + 1; 75 | varargout{n_arg} = 2*((obj.w.*obj.wTxMinusR)'*obj.T)'; 76 | end 77 | end 78 | 79 | function H = setQuadraticProxy(obj) 80 | wT = spdiag(obj.w)*obj.T; 81 | H = 2*(wT'*wT); 82 | end 83 | 84 | function t_max = getMaxStep(obj, x, p) 85 | t_max = inf; % do not enforce a t_max constraint for this functional 86 | end 87 | 88 | function e = evaluatePerElementEnergy(obj, x) 89 | % evaluate 90 | obj.Tx = obj.T*x; 91 | obj.R = projectRotationMexFast(obj.Tx, obj.dim); 92 | TxMinusR = reshape(obj.Tx-obj.R, obj.dim^2, []); 93 | e = sqrt(sum(TxMinusR.^2,1))'; 94 | end 95 | end 96 | 97 | end 98 | 99 | 100 | -------------------------------------------------------------------------------- /code/OptimSolverIterative.m: -------------------------------------------------------------------------------- 1 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2 | % Code implementing the paper "Accelerated Quadratic Proxy for Geometric Optimization", SIGGRAPH 2016. 3 | % Disclaimer: The code is provided as-is for academic use only and without any guarantees. 4 | % Please contact the author to report any bugs. 5 | % Written by Shahar Kovalsky (http://www.wisdom.weizmann.ac.il/~shaharko/) 6 | % Meirav Galun (http://www.wisdom.weizmann.ac.il/~/meirav/) 7 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 8 | 9 | classdef (Abstract) OptimSolverIterative < OptimSolver 10 | properties 11 | % solver vars 12 | t = nan; 13 | 14 | % 15 | stopCntAccept = 5; 16 | tolXCnt = 0; 17 | tolFunCnt = 0; 18 | 19 | end 20 | 21 | properties (Dependent) 22 | end 23 | 24 | methods (Abstract) 25 | iterate(obj) 26 | end 27 | 28 | methods 29 | function obj = OptimSolverIterative 30 | end 31 | 32 | function log = solveTol(obj, TolX, TolFun, max_iter) 33 | obj.report(1,'Solving %s::%s (TolX: %f TolFun: %f #max iter: %d) ', obj.tag, class(obj), TolX, TolFun, max_iter); 34 | logInit; 35 | logState; 36 | % run num_iter iteration 37 | for iter = 1:max_iter 38 | t_iter_start = tic; 39 | obj.iterate(); 40 | t_iter = toc(t_iter_start); 41 | % log 42 | logState; 43 | progBar; 44 | stop = stopCriteria; 45 | if stop 46 | break; 47 | end 48 | end 49 | % truncate log 50 | log.iter = log.iter(1:iter+1); 51 | log.t_iter = log.t_iter(1:iter+1); 52 | log.f_count = log.f_count(1:iter+1); 53 | log.f = log.f(1:iter+1); 54 | log.t = log.t(1:iter+1); 55 | log.X = log.X(:,:,1:iter+1); 56 | 57 | function logInit 58 | iter = 0; 59 | t_iter = 0; 60 | log.tag = obj.tag; 61 | log.iter = nan(1, max_iter+1); 62 | log.t_iter = nan(1, max_iter+1); 63 | log.f_count = nan(1, max_iter+1); 64 | log.f = nan(1, max_iter+1); 65 | log.t = nan(1, max_iter+1); 66 | log.X = nan([size(obj.X), max_iter+1]); 67 | log.exitflag = 'MaxIter'; 68 | end 69 | function logState 70 | log.iter(iter+1) = iter; 71 | log.t_iter(iter+1) = t_iter; 72 | log.f_count(iter+1) = obj.f_count; 73 | log.f(iter+1) = obj.optimProblem.evaluateValue(obj.x); % do not count, for logging only 74 | log.t(iter+1) = obj.t; 75 | log.X(:,:,iter+1) = obj.X; 76 | end 77 | function progBar 78 | if obj.verbose>=1 79 | progressbar(iter, max_iter, 40); 80 | end 81 | end 82 | function stop = stopCriteria 83 | stop = false; 84 | if iter>1 85 | % TolX 86 | if norm(log.X(:,:,iter)-log.X(:,:,iter+1),'fro')=obj.stopCntAccept 92 | obj.report(2,' - stopped after %d iterations (TolX)\n', iter); 93 | log.exitflag = 'TolX'; 94 | stop = true; 95 | end 96 | % TolFun 97 | if abs(log.f(iter)-log.f(iter+1))=obj.stopCntAccept 103 | obj.report(2,' - stopped after %d iterations (TolFun)\n', iter); 104 | log.exitflag = 'TolFun'; 105 | stop = true; 106 | end 107 | end 108 | end 109 | end 110 | 111 | end 112 | 113 | end -------------------------------------------------------------------------------- /code/visualizeSolversForExamples.m: -------------------------------------------------------------------------------- 1 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2 | % Code implementing the paper "Accelerated Quadratic Proxy for Geometric Optimization", SIGGRAPH 2016. 3 | % Disclaimer: The code is provided as-is for academic use only and without any guarantees. 4 | % Please contact the author to report any bugs. 5 | % Written by Shahar Kovalsky (http://www.wisdom.weizmann.ac.il/~shaharko/) 6 | % Meirav Galun (http://www.wisdom.weizmann.ac.il/~/meirav/) 7 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 8 | 9 | 10 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 11 | %%% This script visualizes the results of the examples provided in this 12 | %%% code package. 13 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 14 | 15 | %% init stuff 16 | solver_colors = {'b','m','c','r','k','g','y'}; 17 | switch size(F,2) 18 | case 3 19 | visF = F; 20 | case 4 21 | visF = boundaryFaces(F); 22 | end 23 | 24 | 25 | %% print summary 26 | for ii = 1:n_solvers 27 | fprintf('%s - %g sec\n', logs{ii}.tag, sum(logs{ii}.t_iter)); 28 | end 29 | 30 | 31 | %% visualize init state 32 | figure(100); clf; 33 | clear hP; 34 | for ii = 1:n_solvers 35 | hP{ii} = patch('vertices', optimProblem.x0, 'faces', visF, 'FaceColor', solver_colors{ii}, 'FaceAlpha', 0.4); 36 | end 37 | axis equal; 38 | legend(cellfun(@(x) x.tag, logs, 'UniformOutput', false)); 39 | if optimProblem.dim==3 40 | cameratoolbar; 41 | cameratoolbar('SetCoordSys','y'); 42 | end 43 | 44 | 45 | %% go through iterations 46 | figure(100); 47 | if visualizeIterations 48 | iterVec = 1:max(cellfun(@(x) length(x.iter), logs)); 49 | else 50 | iterVec = num_iter; 51 | end 52 | for iter = iterVec 53 | % update solvers 54 | for ii = 1:n_solvers 55 | try 56 | hP{ii}.Vertices = logs{ii}.X(:,:,min(iter, end)); 57 | catch 58 | warning('solver %d failed to draw', ii); 59 | end 60 | end 61 | title(iter); 62 | drawnow; 63 | pause(0.001); 64 | end 65 | 66 | 67 | %% plot some other information 68 | figure(101); clf; 69 | for ii = 1:n_solvers 70 | semilogy(logs{ii}.f, solver_colors{ii}); 71 | hold on; 72 | end 73 | ylabel('functional value'); 74 | xlabel('iteration #'); 75 | legend(cellfun(@(x) x.tag, logs, 'UniformOutput', false)); 76 | 77 | figure(102); clf; 78 | for ii = 1:n_solvers 79 | semilogy(logs{ii}.t, solver_colors{ii}); 80 | hold on; 81 | end 82 | ylabel('step size (t)'); 83 | xlabel('iteration #'); 84 | legend(cellfun(@(x) x.tag, logs, 'UniformOutput', false)); 85 | 86 | figure(103); clf; 87 | for ii = 1:n_solvers 88 | semilogy(cumsum([0; colStack(logs{ii}.t_iter(2:end))]), logs{ii}.f(1:end), solver_colors{ii}); 89 | hold on; 90 | end 91 | ylabel('functional value'); 92 | xlabel('time [sec]'); 93 | legend(cellfun(@(x) x.tag, logs, 'UniformOutput', false)); 94 | 95 | figure(104); clf; 96 | for ii = 1:n_solvers 97 | plot( abs(diff(logs{ii}.f))./(1+abs(logs{ii}.f(1:end-1))), solver_colors{ii}); 98 | hold on; 99 | end 100 | ylabel('relative functional error') 101 | xlabel('iteration #'); 102 | legend(cellfun(@(x) x.tag, logs, 'UniformOutput', false)); 103 | 104 | 105 | %% show per element energies (2d target domains only) 106 | if optimProblem.dim==2 107 | % compute per element energies 108 | clear e; 109 | for ii = 1:n_solvers 110 | try 111 | e{ii} = optimProblem.evaluatePerElementEnergy(solver{ii}.x); 112 | catch 113 | warning('solver %d failed to draw', ii); 114 | end 115 | end 116 | c_min = min(cellfun(@(x) min(x), e)); 117 | c_max = min(cellfun(@(x) max(x), e)); 118 | 119 | % compute boundary 120 | temp.TR = triangulation(optimProblem.F, optimProblem.x0); 121 | temp.indB = temp.TR.freeBoundary(); 122 | temp.indB = [temp.indB(:,1); temp.indB(1,1)]; 123 | if ~exist('boundary_line_width','var') 124 | boundary_line_width = 1; 125 | end 126 | 127 | for ii = 1:n_solvers 128 | try 129 | figure(400+ii); clf; 130 | patch('faces',optimProblem.F,'vertices',logs{ii}.X(:,:,end),'FaceVertexCData',e{ii},'facecolor','flat','EdgeAlpha',0.03); 131 | title(sprintf('%s\nmean energy: %g\nmedian energy: %g\nmax energy: %g',logs{ii}.tag, mean(e{ii}), median(e{ii}), max(e{ii}))); 132 | axis off; 133 | axis equal; 134 | colorbar; 135 | colormap(getDistortionColormap()); 136 | caxis([c_min c_max]); 137 | % boundary 138 | line(logs{ii}.X(temp.indB,1,end), logs{ii}.X(temp.indB,2,end),... 139 | 'color', solver_colors{ii}, 'linewidth', boundary_line_width); 140 | catch 141 | warning('solver %d failed to draw', ii); 142 | end 143 | end 144 | end -------------------------------------------------------------------------------- /code/OptimSolverAcclQuadProx.m: -------------------------------------------------------------------------------- 1 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2 | % Code implementing the paper "Accelerated Quadratic Proxy for Geometric Optimization", SIGGRAPH 2016. 3 | % Disclaimer: The code is provided as-is for academic use only and without any guarantees. 4 | % Please contact the author to report any bugs. 5 | % Written by Shahar Kovalsky (http://www.wisdom.weizmann.ac.il/~shaharko/) 6 | % Meirav Galun (http://www.wisdom.weizmann.ac.il/~/meirav/) 7 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 8 | 9 | classdef OptimSolverAcclQuadProx < OptimSolverIterative 10 | properties 11 | % internal variables 12 | x_prev; 13 | y; 14 | p; 15 | KKT; 16 | KKT_rhs; 17 | p_lambda; 18 | y_f; 19 | y_fgrad; 20 | t_start; 21 | t_init; % store intialization time 22 | f_count = 0; % store function evaluation count 23 | 24 | % solver parameters 25 | useAccelaration; 26 | useQuadProxy; 27 | useLineSearch; 28 | theta = []; 29 | 30 | % step size limiting 31 | useAccelarationStepSizeLimit = true; 32 | accelarationStepSizeLimitFactor = 0.5; 33 | accelarationStepSize; 34 | useLineSearchStepSizeLimit = true; 35 | lineSearchStepSizeLimitFactor = 0.5; %0.99; 36 | useLineSearchStepSizeMemory = true; 37 | lineSearchStepSizeMemoryFactor = 2^5.5; 38 | 39 | % line search parameters 40 | ls_alpha = 0.2; 41 | ls_beta = 0.5; 42 | end 43 | 44 | methods 45 | function obj = OptimSolverAcclQuadProx(tag, optimProblem, useAccelaration, useQuadProxy, useLineSearch) 46 | t_init_start = tic; 47 | % copy 48 | obj.useAccelaration = useAccelaration; 49 | obj.useQuadProxy = useQuadProxy; 50 | obj.useLineSearch = useLineSearch; 51 | % init solver 52 | obj.initSolver(tag, optimProblem); 53 | % precomputaions 54 | if obj.useQuadProxy 55 | KKT_mat = [obj.optimProblem.H obj.optimProblem.eq_lhs'; obj.optimProblem.eq_lhs sparse(obj.optimProblem.n_eq,obj.optimProblem.n_eq)]; 56 | else 57 | KKT_mat = [speye(size(optimProblem.H)) obj.optimProblem.eq_lhs'; obj.optimProblem.eq_lhs sparse(obj.optimProblem.n_eq,obj.optimProblem.n_eq)]; 58 | end 59 | obj.KKT = SparseLU(KKT_mat); 60 | % init internal variables 61 | obj.KKT_rhs = zeros(obj.optimProblem.n_vars+obj.optimProblem.n_eq,1); 62 | obj.x_prev = obj.x; 63 | obj.t = 1/obj.lineSearchStepSizeMemoryFactor; 64 | % store init time 65 | obj.t_init = toc(t_init_start); 66 | end 67 | 68 | function iterate(obj) 69 | % acceleration 70 | if obj.useAccelaration 71 | if obj.useAccelarationStepSizeLimit 72 | obj.accelarationStepSize = min(obj.theta, obj.accelarationStepSizeLimitFactor*obj.optimProblem.getMaxStep(obj.x, (obj.x-obj.x_prev))); 73 | else 74 | obj.accelarationStepSize = obj.theta; 75 | end 76 | %obj.y = (1+obj.theta)*obj.x + obj.theta*obj.x_prev; 77 | obj.y = obj.x + obj.accelarationStepSize*(obj.x-obj.x_prev); 78 | else 79 | obj.y = obj.x; 80 | end 81 | 82 | % quadratic proxy minimization 83 | if obj.useLineSearch 84 | [obj.y_f, obj.y_fgrad] = obj.optimProblem.evaluateValueGrad(obj.y); 85 | obj.f_count = obj.f_count + 1; 86 | else 87 | obj.y_fgrad = obj.optimProblem.evaluateGrad(obj.y); 88 | obj.f_count = obj.f_count + 1; 89 | end 90 | obj.KKT_rhs(1:obj.optimProblem.n_vars) = -obj.y_fgrad; 91 | obj.p_lambda = obj.KKT.solve(obj.KKT_rhs); 92 | obj.p = obj.p_lambda(1:obj.optimProblem.n_vars); 93 | 94 | % initialize step size 95 | if obj.useLineSearchStepSizeMemory 96 | obj.t_start = min(obj.t * obj.lineSearchStepSizeMemoryFactor, 1); 97 | else 98 | obj.t_start = 1; 99 | end 100 | if obj.useLineSearchStepSizeLimit 101 | obj.t = min(obj.t_start, obj.lineSearchStepSizeLimitFactor*obj.optimProblem.getMaxStep(obj.y, obj.p)); 102 | else 103 | obj.t = obj.t_start; 104 | end 105 | 106 | % line search 107 | if obj.useLineSearch 108 | [linesearch_cond_lhs, linesearch_cond_rhs] = computeLineSearchCond; 109 | while linesearch_cond_lhs>linesearch_cond_rhs 110 | obj.t = obj.ls_beta*obj.t; 111 | [linesearch_cond_lhs, linesearch_cond_rhs] = computeLineSearchCond; 112 | end 113 | end 114 | % fprintf('%e %e %e\n',obj.t_start,obj.lineSearchStepSizeLimitFactor*obj.optimProblem.getMaxStep(obj.y, obj.p),obj.t) 115 | 116 | % update 117 | obj.x_prev = obj.x; 118 | obj.x = obj.y + obj.t*obj.p; 119 | 120 | function [linesearch_cond_lhs, linesearch_cond_rhs] = computeLineSearchCond 121 | linesearch_cond_lhs = obj.optimProblem.evaluateValue(obj.y + obj.t*obj.p); 122 | obj.f_count = obj.f_count + 1; 123 | linesearch_cond_rhs = obj.y_f + obj.ls_alpha*obj.t*obj.y_fgrad'*obj.p; 124 | end 125 | end 126 | 127 | function setKappa(obj, kappa) 128 | obj.theta = (1-sqrt(1/kappa))/(1+sqrt(1/kappa)); 129 | end 130 | 131 | end 132 | 133 | end -------------------------------------------------------------------------------- /code/OptimProblemIsoDist.m: -------------------------------------------------------------------------------- 1 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2 | % Code implementing the paper "Accelerated Quadratic Proxy for Geometric Optimization", SIGGRAPH 2016. 3 | % Disclaimer: The code is provided as-is for academic use only and without any guarantees. 4 | % Please contact the author to report any bugs. 5 | % Written by Shahar Kovalsky (http://www.wisdom.weizmann.ac.il/~shaharko/) 6 | % Meirav Galun (http://www.wisdom.weizmann.ac.il/~/meirav/) 7 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 8 | 9 | classdef OptimProblemIsoDist < OptimProblem 10 | properties 11 | % mesh (keep here?) 12 | V; 13 | F; 14 | dim; 15 | n_vert; 16 | n_tri; 17 | areas; 18 | 19 | % internal variables 20 | Tx; 21 | R; 22 | f_val; 23 | Tx_grad; 24 | flips; 25 | localHess; 26 | 27 | % parameters 28 | maxStepTol = 1e-8; 29 | initArapIter; 30 | 31 | % bd projection parameters (for initialization) 32 | proj_bd_K = 10; % bounded distortion constant 33 | proj_bd_lb = -1; % lower bound on SVs (-1 = disabled) 34 | proj_bd_ub = -1; % upper bound on SVs (-1 = disabled) 35 | proj_bd_iter_max = 1000; % maximal number of BD projection iterations 36 | proj_bd_tol_err = 1e-10; % tolerance for stopping BD projection iterations 37 | proj_bd_verbose = true; % flag to showing iteration statistics 38 | end 39 | 40 | methods 41 | function obj = OptimProblemIsoDist(V, F, eq_lhs, eq_rhs, V0, initArapIter) 42 | % copy 43 | obj.V = V; 44 | obj.F = F; 45 | obj.eq_lhs = eq_lhs; 46 | obj.eq_rhs = eq_rhs; 47 | obj.dim = size(F,2)-1; 48 | obj.n_vert = size(V,1); 49 | obj.n_tri = size(F,1); 50 | if exist('initArapIter','var') 51 | obj.initArapIter = initArapIter; 52 | else 53 | obj.initArapIter = 1; 54 | end 55 | % report 56 | obj.report(1,'Constructing %s (dim: %d #vert: %d #elem: %d)\n', class(obj), obj.dim, obj.n_vert, obj.n_tri); 57 | % compute transformations 58 | [obj.T,obj.areas] = computeMeshTranformationCoeffsMex(F, V); 59 | % set initial configuration 60 | obj.x0 = obj.initVertices(V0); 61 | % set quadratic proxy 62 | obj.H = obj.setQuadraticProxy(); 63 | % finish construction 64 | obj.initProblem(); 65 | end 66 | 67 | function x0 = initVertices(obj, V0) 68 | % feasible initialization -- provide input or a single local-global step 69 | if ~isempty(V0) 70 | x0 = V0; 71 | else 72 | x0 = obj.V(:); 73 | obj.report(2,'Init with %d ARAP iterations ', obj.initArapIter); 74 | for arapIter = 1:obj.initArapIter 75 | obj.Tx = obj.T*x0; 76 | obj.R = projectRotationMexFast(obj.Tx, obj.dim); 77 | x0 = solveConstrainedLS(obj.T, obj.R, obj.eq_lhs, obj.eq_rhs); 78 | progBar; 79 | end 80 | obj.report(2,'\n'); 81 | x0 = reshape(x0, obj.n_vert, obj.dim); 82 | end 83 | % check if solution is orientation preserving 84 | obj.Tx = obj.T*x0(:); 85 | [~, ~, obj.flips] = computeFunctionalIsoDistMex(obj.Tx, obj.areas, obj.dim); 86 | % fix if there are flips 87 | if obj.flips 88 | warning('Initialization is not orientation preserving -- projecting on BD') 89 | % project onto BD 90 | solver_bd = SolverProjectorBD(obj.F, obj.V, obj.eq_lhs, obj.eq_rhs, obj.proj_bd_K, obj.proj_bd_lb, obj.proj_bd_ub, x0, SolverProjectorModeEnum.Tangent); % setup BD solver 91 | solver_bd.solve(obj.proj_bd_iter_max, obj.proj_bd_tol_err, obj.proj_bd_verbose); % solve BD projection 92 | assert(nnz(solver_bd.flips)==0, 'BD projector output has flipped elements'); 93 | x0 = solver_bd.y; % reassign x0 94 | end 95 | 96 | function progBar 97 | if obj.verbose>=1 98 | progressbar(arapIter, obj.initArapIter , 40); 99 | end 100 | end 101 | end 102 | 103 | function [varargout] = evaluateFunctional(obj, x, doVal, doGrad, doHess) 104 | % evaluate 105 | obj.Tx = obj.T*x; 106 | if doVal||doGrad 107 | % call mex helps 108 | [obj.f_val, obj.Tx_grad, obj.flips] = computeFunctionalIsoDistMex(obj.Tx, obj.areas, obj.dim); 109 | if obj.flips 110 | warning('negative det'); 111 | obj.f_val = inf; 112 | end 113 | end 114 | % return 115 | n_arg = 0; 116 | if doVal 117 | n_arg = n_arg + 1; 118 | varargout{n_arg} = obj.f_val; 119 | end 120 | if doGrad 121 | n_arg = n_arg + 1; 122 | varargout{n_arg} = (obj.Tx_grad'*obj.T)'; 123 | end 124 | if doHess 125 | n_arg = n_arg + 1; 126 | obj.localHess = computeHessianIsoDistMex(obj.Tx, obj.areas, obj.dim); 127 | varargout{n_arg} = obj.T'*obj.localHess*obj.T; 128 | end 129 | end 130 | 131 | function H = setQuadraticProxy(obj) 132 | wT = spdiag(kron(sqrt(obj.areas), ones(obj.dim^2,1)))*obj.T; 133 | H = 2*(wT'*wT); 134 | end 135 | 136 | function t_max = getMaxStep(obj, x, p) 137 | t_max = computeInjectiveStepSizeMex(obj.F,x,p,obj.maxStepTol); 138 | end 139 | 140 | function e = evaluatePerElementEnergy(obj, x) 141 | % evaluate 142 | obj.Tx = obj.T*x; 143 | A = reshape(obj.Tx, obj.dim, obj.dim, []); 144 | e = nan(obj.n_tri,1); 145 | for ii = 1:obj.n_tri 146 | e(ii) = sqrt( sum(sum(A(:,:,ii).^2)) + sum(sum(inv(A(:,:,ii)).^2)) )/sqrt(2*obj.dim); 147 | end 148 | end 149 | end 150 | 151 | end 152 | 153 | 154 | -------------------------------------------------------------------------------- /mex/computeMeshTranformationCoeffsMex.cpp: -------------------------------------------------------------------------------- 1 | //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2 | //% Code implementing the paper "Accelerated Quadratic Proxy for Geometric Optimization", SIGGRAPH 2016. 3 | //% Disclaimer: The code is provided as-is for academic use only and without any guarantees. 4 | //% Please contact the author to report any bugs. 5 | //% Written by Shahar Kovalsky (http://www.wisdom.weizmann.ac.il/~shaharko/) 6 | //% Meirav Galun (http://www.wisdom.weizmann.ac.il/~/meirav/) 7 | //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 8 | 9 | #include "mex.h" 10 | #include 11 | #include 12 | #include "mexHelpers.cpp" 13 | 14 | using namespace Eigen; 15 | 16 | void computeMeshTranformationCoeffsFullDim(const MatrixXd& F, const MatrixXd& V, SparseMatrix &T, VectorXd& areas) 17 | { 18 | // init 19 | int n_tri = F.rows(); 20 | int d_simplex = F.cols(); 21 | int n_vert = V.rows(); 22 | int dim = V.cols(); 23 | int T_rows = n_tri*dim*dim; 24 | int T_cols = n_vert*dim; 25 | int T_nnz = n_tri*dim*dim*d_simplex; 26 | 27 | 28 | // prepare centering matrix 29 | MatrixXd B = MatrixXd::Identity(d_simplex, d_simplex); 30 | B = B.array() - (1.0 / d_simplex); 31 | 32 | // prepare output matrix 33 | T.resize(T_cols, T_rows); 34 | T.reserve(VectorXi::Constant(T_rows, d_simplex)); 35 | areas.resize(n_tri); 36 | 37 | // calculate differential coefficients for each element 38 | MatrixXd currV(d_simplex, dim); 39 | MatrixXd currT(dim, d_simplex); 40 | int curr_row = 0; 41 | for (int ii = 0; ii < n_tri; ii++) 42 | { 43 | // calculate current element 44 | for (int jj = 0; jj < d_simplex; jj++) 45 | { 46 | currV.row(jj) = V.row(F(ii, jj)); 47 | } 48 | currV = B*currV; // center 49 | currT = currV.fullPivLu().solve(B); // solver 50 | 51 | // fill into the correct places of T 52 | for (int cd = 0; cd < dim; cd++) 53 | for (int cr = 0; cr < dim; cr++) 54 | { 55 | for (int cc = 0; cc < d_simplex; cc++) 56 | T.insert(F(ii, cc) + (cd*n_vert), curr_row) = currT(cr, cc); 57 | curr_row += 1; 58 | } 59 | 60 | // calculate area 61 | areas(ii) = (currV.bottomRows(dim).rowwise() - currV.row(0)).determinant() / 2; 62 | } 63 | 64 | // compress 65 | T.makeCompressed(); 66 | T = T.transpose(); 67 | } 68 | 69 | 70 | void orth(const MatrixXd &A, MatrixXd &Q) 71 | { 72 | 73 | //perform svd on A = U*S*V' (V is not computed and only the thin U is computed) 74 | Eigen::JacobiSVD svd(A, Eigen::ComputeThinU); 75 | Eigen::MatrixXd U = svd.matrixU(); 76 | const Eigen::VectorXd S = svd.singularValues(); 77 | 78 | //get rank of A 79 | int m = A.rows(); 80 | int n = A.cols(); 81 | double tol = std::max(m, n) * S.maxCoeff() * 2.2204e-16; 82 | int r = 0; 83 | for (int i = 0; i < S.rows(); ++r, ++i) 84 | { 85 | if (S[i] < tol) 86 | break; 87 | } 88 | 89 | //keep r first columns of U 90 | Q = U.block(0, 0, U.rows(), r); 91 | } 92 | 93 | void compute2dEmbedding(const MatrixXd& V, MatrixXd& A) 94 | { 95 | // given a nXn matrix whose columns are the vertices of a (n-1)-D simplex, 96 | // returns the transformation A, s.t A*V gives embedding in (n-1)-D 97 | 98 | MatrixXd ctrV(V.rows() - 1, V.cols()); 99 | ctrV = -V.bottomRows(V.rows() - 1); 100 | ctrV.rowwise() += V.row(0); 101 | ctrV.transpose(); 102 | orth(ctrV, A); 103 | //if (((ctrV*A).determinant()) < 0) 104 | // A.col(0).swap(A.col(1)); 105 | A.transpose(); 106 | } 107 | 108 | void embedTriangle(const MatrixXd& V, MatrixXd& flatV, double& area) 109 | { 110 | VectorXd v1 = V.row(1) - V.row(0); 111 | VectorXd v2 = V.row(2) - V.row(0); 112 | 113 | double norm_v1 = v1.norm(); 114 | double norm_v2 = v2.norm(); 115 | double cos_theta = v1.dot(v2) / (norm_v1*norm_v2); 116 | double sin_theta = sqrt(1 - cos_theta*cos_theta); 117 | 118 | flatV << 0, 0, 119 | norm_v1, 0, 120 | norm_v2*cos_theta, norm_v2*sin_theta; 121 | 122 | area = norm_v1*norm_v2*sin_theta / 2; 123 | } 124 | 125 | void computeMeshTranformationCoeffsFlatenning(const MatrixXd& F, const MatrixXd& V, SparseMatrix &T, VectorXd& areas) 126 | { 127 | // init 128 | int n_tri = F.rows(); 129 | int d_simplex = F.cols(); 130 | int n_vert = V.rows(); 131 | int dim = V.cols(); 132 | int d_diff = dim - 1; 133 | int T_rows = n_tri*d_diff*d_diff; 134 | int T_cols = n_vert*d_diff; 135 | int T_nnz = n_tri*d_diff*d_diff*d_simplex; 136 | 137 | assert(d_simplex == 3 && dim == 3); 138 | 139 | // prepare centering matrix 140 | MatrixXd B = MatrixXd::Identity(d_simplex, d_simplex); 141 | B = B.array() - (1.0 / d_simplex); 142 | 143 | // prepare output matrix 144 | T.resize(T_cols, T_rows); 145 | T.reserve(VectorXi::Constant(T_rows, d_simplex)); 146 | areas.resize(n_tri); 147 | 148 | // calculate differential coefficients for each element 149 | MatrixXd currV(d_simplex, dim); 150 | MatrixXd currT(dim, d_simplex); 151 | MatrixXd RFlat(dim, d_diff); 152 | MatrixXd currVFlat(d_simplex, d_diff); 153 | int curr_row = 0; 154 | for (int ii = 0; ii < n_tri; ii++) 155 | { 156 | // calculate current element 157 | for (int jj = 0; jj < d_simplex; jj++) 158 | { 159 | currV.row(jj) = V.row(F(ii, jj)); 160 | } 161 | // transform to plane 162 | embedTriangle(currV, currVFlat, areas(ii)); // this only works for triangles 163 | // compute 164 | currVFlat = B*currVFlat; // center 165 | currT = currVFlat.fullPivLu().solve(B); // solver 166 | 167 | // fill into the correct places of T 168 | for (int cd = 0; cd < d_diff; cd++) 169 | for (int cr = 0; cr < d_diff; cr++) 170 | { 171 | for (int cc = 0; cc < d_simplex; cc++) 172 | T.insert(F(ii, cc) + (cd*n_vert), curr_row) = currT(cr, cc); 173 | curr_row += 1; 174 | } 175 | } 176 | 177 | // compress 178 | T.makeCompressed(); 179 | T = T.transpose(); 180 | } 181 | 182 | void mexFunction(int nlhs, mxArray *plhs[], 183 | int nrhs, const mxArray*prhs[]) 184 | { 185 | // assign input 186 | int n_tri = mxGetM(prhs[0]); // # rows of F 187 | int d_simplex = mxGetN(prhs[0]); // # cols of F 188 | int n_vert = mxGetM(prhs[1]); // # rows of V 189 | int dim = mxGetN(prhs[1]); // # cols of V 190 | const Map Fmatlab(mxGetPr(prhs[0]), n_tri, d_simplex); 191 | const Map V(mxGetPr(prhs[1]), n_vert, dim); 192 | 193 | // update index numbers to 0-base 194 | MatrixXd F (Fmatlab); 195 | F = F.array() - 1; 196 | 197 | // compute 198 | SparseMatrix T; 199 | VectorXd areas; 200 | if (d_simplex == 3 && dim == 2) 201 | { 202 | // Planar triangulation 203 | computeMeshTranformationCoeffsFullDim(F, V, T, areas); 204 | } 205 | else if (d_simplex == 4 && dim == 3) 206 | { 207 | // Tet mesh 208 | computeMeshTranformationCoeffsFullDim(F, V, T, areas); 209 | } 210 | else if (d_simplex == 3 && dim == 3) 211 | { 212 | // 3D surface 213 | computeMeshTranformationCoeffsFlatenning(F, V, T, areas); 214 | } 215 | else 216 | mexErrMsgIdAndTxt("MATLAB:invalidInputs", "Invalid input dimensions or mesh type not supported"); 217 | 218 | 219 | // assign outputs 220 | mapSparseMatrixToMex(T, &(plhs[0])); 221 | mapDenseMatrixToMex(areas, &(plhs[1])); 222 | } -------------------------------------------------------------------------------- /toolbox/LargeScaleBD/SolverProjector.m: -------------------------------------------------------------------------------- 1 | classdef (Abstract) SolverProjector < handle 2 | 3 | properties 4 | % problem 5 | T; % lift operator 6 | W; % norm weights 7 | eqLHS; 8 | eqRHS; 9 | x0; 10 | % solver 11 | mode; 12 | usePreFactorization = true; 13 | nVars; 14 | nEq; 15 | x; 16 | Tx; 17 | pTx; 18 | tanNormal; 19 | tanLHS; 20 | tanRHS; 21 | preFactorization; 22 | TWW; % T'*W'*W 23 | TWWT; % T'*W'*W*T 24 | % temporaries 25 | % ? 26 | % log 27 | % ? 28 | % display / log 29 | verbose = 4; 30 | t_iter; 31 | t_projectD; 32 | t_projectLinear; 33 | t_factorization; 34 | % aux 35 | lambdaMultiTangent = 10; 36 | end 37 | 38 | properties (Dependent) 39 | y; 40 | end 41 | 42 | methods (Abstract) 43 | projectD_(obj) 44 | end 45 | 46 | methods 47 | function obj = SolverProjector 48 | % empty constructor 49 | end 50 | 51 | function value = get.y(obj) 52 | value = reshape(obj.x,size(obj.x0)); 53 | end 54 | 55 | function initSolver(obj) 56 | obj.nVars = numel(obj.x0); 57 | obj.nEq = size(obj.eqLHS,1); 58 | obj.x = colStack(obj.x0); 59 | obj.Tx = obj.T*obj.x; 60 | obj.projectD(); 61 | obj.tanNormal = zeros(obj.nVars,1); 62 | obj.tanLHS = zeros(obj.nVars,1); 63 | obj.tanRHS = 0; 64 | obj.updateProblem(); 65 | end 66 | 67 | function updateProblem(obj) 68 | t_start = tic; 69 | obj.TWW = obj.T'*obj.W'*obj.W; 70 | obj.TWWT = obj.TWW*obj.T; 71 | if (obj.usePreFactorization) 72 | obj.factorize(); 73 | end 74 | obj.t_factorization = toc(t_start); 75 | obj.report(2,'Prectorization took (%.3g secs)\n', obj.t_factorization); 76 | end 77 | 78 | function factorize(obj) 79 | % construct KKT matrix 80 | LHS = [obj.TWWT, obj.eqLHS'; obj.eqLHS, sparse(obj.nEq,obj.nEq)]; 81 | % factorize 82 | obj.preFactorization = SparseLU(LHS); 83 | end 84 | 85 | function projectD(obj) 86 | t_start = tic; 87 | obj.projectD_(); 88 | obj.t_projectD = toc(t_start); 89 | end 90 | 91 | function projectLinear(obj) 92 | t_start = tic; 93 | switch obj.mode 94 | case SolverProjectorModeEnum.AltProj 95 | temp_RHS = [obj.TWW*obj.pTx; obj.eqRHS]; 96 | if (obj.usePreFactorization) 97 | temp_x_lambda = obj.preFactorization.solve(temp_RHS); 98 | else 99 | temp_LHS = [obj.TWWT, obj.eqLHS'; obj.eqLHS, sparse(obj.nEq,obj.nEq)]; 100 | temp_x_lambda = temp_LHS\temp_RHS; 101 | end 102 | obj.x = temp_x_lambda(1:obj.nVars); 103 | 104 | case SolverProjectorModeEnum.Tangent 105 | if any(obj.tanNormal) % avoid solving linear system if projecting on D didn't do anything 106 | obj.tanLHS = obj.tanNormal'*obj.T; 107 | obj.tanRHS = obj.tanNormal'*obj.pTx; 108 | if (obj.usePreFactorization) 109 | temp_rhs = [obj.TWW*obj.pTx; obj.eqRHS]; 110 | temp_Au = [obj.tanLHS'; zeros(obj.nEq,1)]; 111 | % % compute lambda update 112 | % temp_inv_LHS_RHS = obj.preFactorization.solve(temp_rhs); 113 | % temp_inv_LHS_AuT = obj.preFactorization.solve(temp_Au); 114 | % temp_lambda_u = (temp_Au'*temp_inv_LHS_RHS - obj.tanRHS) / (temp_Au'*temp_inv_LHS_AuT); 115 | % % compute x_lambda 116 | % temp_x_lambda_RHS = temp_rhs - temp_lambda_u*temp_Au; 117 | % temp_x_lambda = obj.preFactorization.solve(temp_x_lambda_RHS); 118 | Fm_c = obj.preFactorization.solve(temp_rhs); 119 | Fm_n = obj.preFactorization.solve(temp_Au); 120 | temp_x_lambda = Fm_c - (temp_Au'*Fm_c - obj.tanRHS)/(temp_Au'*Fm_n)*Fm_n; 121 | else 122 | error('Not implemented yet') 123 | end 124 | else % if tanNormal=0 125 | temp_RHS = [obj.TWW*obj.pTx; obj.eqRHS]; 126 | if (obj.usePreFactorization) 127 | temp_x_lambda = obj.preFactorization.solve(temp_RHS); 128 | else 129 | temp_LHS = [obj.TWWT, obj.eqLHS'; obj.eqLHS, sparse(obj.nEq,obj.nEq)]; 130 | temp_x_lambda = temp_LHS\temp_RHS; 131 | end 132 | end 133 | obj.x = temp_x_lambda(1:obj.nVars); 134 | 135 | case SolverProjectorModeEnum.MultiTangent 136 | if isa(obj,'SolverProjectorBD') 137 | % split normals 138 | manyTanNormals = sparse(1:length(obj.tanNormal), kron(1:(length(obj.tanNormal)/(obj.dim^2)),ones(1,obj.dim^2)), obj.tanNormal); 139 | % remove inactive tangents 140 | manyTanNormals = manyTanNormals(:,any(manyTanNormals)); 141 | % normalize 142 | norms = sqrt(sum(manyTanNormals.^2)); 143 | invNorms = sparse(1:length(norms),1:length(norms),1./norms); 144 | manyTanNormals = manyTanNormals*invNorms; 145 | % tangents 146 | obj.tanLHS = manyTanNormals'*obj.T; 147 | obj.tanRHS = manyTanNormals'*obj.pTx; 148 | % solve 149 | obj.x = solveConstrainedLS([obj.W*obj.T; sqrt(obj.lambdaMultiTangent)*obj.tanLHS],... 150 | [obj.W*obj.pTx; sqrt(obj.lambdaMultiTangent)*obj.tanRHS], obj.eqLHS, obj.eqRHS); 151 | %fprintf('# active constraints for multitangents: %d\n',size(obj.tanLHS,1)); 152 | else 153 | error('Problem type not supported'); 154 | end 155 | 156 | otherwise 157 | error('invalid mode'); 158 | end 159 | obj.t_projectLinear = toc(t_start); 160 | end 161 | 162 | function iterate(obj) 163 | t_start = tic; 164 | % lift 165 | obj.Tx = obj.T*obj.x; 166 | % project onto D 167 | obj.projectD(); 168 | % compute normal (=error) 169 | obj.tanNormal = obj.Tx - obj.pTx; 170 | % project onto linear constraints 171 | obj.projectLinear(); 172 | obj.t_iter = toc(t_start); 173 | end 174 | 175 | function iterateN(obj,n) 176 | for ii = 1:n 177 | obj.iterate(); 178 | end 179 | end 180 | 181 | function solve(obj) 182 | error('Not implemented yet') 183 | end 184 | 185 | function report(obj,verbosity,varargin) 186 | if verbosity<=obj.verbose 187 | fprintf(varargin{:}); 188 | end 189 | end 190 | end 191 | end 192 | 193 | -------------------------------------------------------------------------------- /mex/computeInjectiveStepSizeMex.cpp: -------------------------------------------------------------------------------- 1 | //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2 | //% Code implementing the paper "Accelerated Quadratic Proxy for Geometric Optimization", SIGGRAPH 2016. 3 | //% Disclaimer: The code is provided as-is for academic use only and without any guarantees. 4 | //% Please contact the author to report any bugs. 5 | //% Written by Shahar Kovalsky (http://www.wisdom.weizmann.ac.il/~shaharko/) 6 | //% Meirav Galun (http://www.wisdom.weizmann.ac.il/~/meirav/) 7 | //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 8 | 9 | #include "mex.h" 10 | #include 11 | #include 12 | #include 13 | #include "mexHelpers.cpp" 14 | 15 | using namespace Eigen; 16 | using namespace std; 17 | 18 | double getSmallestPositiveRealQuadRoot(double a, double b, double c, double tol) 19 | { 20 | // return negative value if no positive real root is found 21 | double t; 22 | 23 | if (abs(a) <= tol) 24 | t = -c / b; 25 | else 26 | { 27 | double desc = b*b - 4 * a*c; 28 | if (desc > 0) 29 | { 30 | t = (-b - sqrt(desc)) / (2 * a); 31 | if (t < 0) 32 | t = (-b + sqrt(desc)) / (2 * a); 33 | } 34 | else // desv<0 ==> imag 35 | t = -1; 36 | } 37 | return t; 38 | } 39 | 40 | 41 | void computeInjectiveStepSize_2d(const MatrixXd& F, const MatrixXd& x, const MatrixXd& p, double tol, double& t_max) 42 | { 43 | int n_tri = F.rows(); 44 | double x1, x2, x3, y1, y2, y3; 45 | double p1, p2, p3, q1, q2, q3; 46 | double a, b, c, t; 47 | 48 | t_max = -1; 49 | for (int ii = 0; ii < n_tri; ii++) 50 | { 51 | x1 = x(F(ii, 0), 0); 52 | x2 = x(F(ii, 1), 0); 53 | x3 = x(F(ii, 2), 0); 54 | 55 | y1 = x(F(ii, 0), 1); 56 | y2 = x(F(ii, 1), 1); 57 | y3 = x(F(ii, 2), 1); 58 | 59 | p1 = p(F(ii, 0), 0); 60 | p2 = p(F(ii, 1), 0); 61 | p3 = p(F(ii, 2), 0); 62 | 63 | q1 = p(F(ii, 0), 1); 64 | q2 = p(F(ii, 1), 1); 65 | q3 = p(F(ii, 2), 1); 66 | 67 | a = p1*q2 - p2*q1 - p1*q3 + p3*q1 + p2*q3 - p3*q2; 68 | b = p1*y2 - p2*y1 - q1*x2 + q2*x1 - p1*y3 + p3*y1 + q1*x3 - q3*x1 + p2*y3 - p3*y2 - q2*x3 + q3*x2; 69 | c = x1*y2 - x2*y1 - x1*y3 + x3*y1 + x2*y3 - x3*y2; 70 | 71 | t = getSmallestPositiveRealQuadRoot(a, b, c, tol); 72 | if (t >= 0) 73 | if ((t_max < 0) | (t_max>t)) 74 | t_max = t; 75 | } 76 | } 77 | 78 | 79 | double getSmallestPositiveRealCubicRoot(double a, double b, double c, double d, double tol) 80 | { 81 | // return negative value if no positive real root is found 82 | double t = -1; 83 | 84 | if (abs(a) <= tol) 85 | t = getSmallestPositiveRealQuadRoot(b, c, d, tol); 86 | else 87 | { 88 | complex i(0, 1); 89 | complex delta0(b*b - 3 * a*c, 0); 90 | complex delta1(2 * b*b*b - 9 * a*b*c + 27 * a*a*d, 0); 91 | complex C = pow((delta1 + sqrt(delta1*delta1 - 4.0 * delta0*delta0*delta0)) / 2.0, 1.0 / 3.0); 92 | 93 | complex u2 = (-1.0 + sqrt(3.0)*i) / 2.0; 94 | complex u3 = (-1.0 - sqrt(3.0)*i) / 2.0; 95 | 96 | complex t1 = (b + C + delta0 / C) / (-3.0*a); 97 | complex t2 = (b + u2*C + delta0 / (u2*C)) / (-3.0*a); 98 | complex t3 = (b + u3*C + delta0 / (u3*C)) / (-3.0*a); 99 | 100 | if ((abs(imag(t1))0)) 101 | t = real(t1); 102 | if ((abs(imag(t2))0) && ((real(t2) < t) || (t < 0))) 103 | t = real(t2); 104 | if ((abs(imag(t3))0) && ((real(t3) < t) || (t < 0))) 105 | t = real(t3); 106 | } 107 | return t; 108 | } 109 | 110 | 111 | void computeInjectiveStepSize_3d(const MatrixXd& F, const MatrixXd& x, const MatrixXd& p, double tol, double& t_max) 112 | { 113 | int n_tri = F.rows(); 114 | double x1, x2, x3, x4, y1, y2, y3, y4, z1, z2, z3, z4; 115 | double p1, p2, p3, p4, q1, q2, q3, q4, r1, r2, r3, r4; 116 | double a, b, c, d, t; 117 | 118 | t_max = -1; 119 | for (int ii = 0; ii < n_tri; ii++) 120 | { 121 | x1 = x(F(ii, 0), 0); 122 | x2 = x(F(ii, 1), 0); 123 | x3 = x(F(ii, 2), 0); 124 | x4 = x(F(ii, 3), 0); 125 | 126 | y1 = x(F(ii, 0), 1); 127 | y2 = x(F(ii, 1), 1); 128 | y3 = x(F(ii, 2), 1); 129 | y4 = x(F(ii, 3), 1); 130 | 131 | z1 = x(F(ii, 0), 2); 132 | z2 = x(F(ii, 1), 2); 133 | z3 = x(F(ii, 2), 2); 134 | z4 = x(F(ii, 3), 2); 135 | 136 | p1 = p(F(ii, 0), 0); 137 | p2 = p(F(ii, 1), 0); 138 | p3 = p(F(ii, 2), 0); 139 | p4 = p(F(ii, 3), 0); 140 | 141 | q1 = p(F(ii, 0), 1); 142 | q2 = p(F(ii, 1), 1); 143 | q3 = p(F(ii, 2), 1); 144 | q4 = p(F(ii, 3), 1); 145 | 146 | r1 = p(F(ii, 0), 2); 147 | r2 = p(F(ii, 1), 2); 148 | r3 = p(F(ii, 2), 2); 149 | r4 = p(F(ii, 3), 2); 150 | 151 | a = -p1*q2*r3 + p1*r2*q3 + q1*p2*r3 - q1*r2*p3 - r1*p2*q3 + r1*q2*p3 + p1*q2*r4 - p1*r2*q4 - q1*p2*r4 + q1*r2*p4 + r1*p2*q4 - r1*q2*p4 - p1*q3*r4 + p1*r3*q4 + q1*p3*r4 - q1*r3*p4 - r1*p3*q4 + r1*q3*p4 + p2*q3*r4 - p2*r3*q4 - q2*p3*r4 + q2*r3*p4 + r2*p3*q4 - r2*q3*p4; 152 | b = -x1*q2*r3 + x1*r2*q3 + y1*p2*r3 - y1*r2*p3 - z1*p2*q3 + z1*q2*p3 + x2*q1*r3 - x2*r1*q3 - y2*p1*r3 + y2*r1*p3 + z2*p1*q3 - z2*q1*p3 - x3*q1*r2 + x3*r1*q2 + y3*p1*r2 - y3*r1*p2 - z3*p1*q2 + z3*q1*p2 + x1*q2*r4 - x1*r2*q4 - y1*p2*r4 + y1*r2*p4 + z1*p2*q4 - z1*q2*p4 - x2*q1*r4 + x2*r1*q4 + y2*p1*r4 - y2*r1*p4 - z2*p1*q4 + z2*q1*p4 + x4*q1*r2 - x4*r1*q2 - y4*p1*r2 + y4*r1*p2 + z4*p1*q2 - z4*q1*p2 - x1*q3*r4 + x1*r3*q4 + y1*p3*r4 - y1*r3*p4 - z1*p3*q4 + z1*q3*p4 + x3*q1*r4 - x3*r1*q4 - y3*p1*r4 + y3*r1*p4 + z3*p1*q4 - z3*q1*p4 - x4*q1*r3 + x4*r1*q3 + y4*p1*r3 - y4*r1*p3 - z4*p1*q3 + z4*q1*p3 + x2*q3*r4 - x2*r3*q4 - y2*p3*r4 + y2*r3*p4 + z2*p3*q4 - z2*q3*p4 - x3*q2*r4 + x3*r2*q4 + y3*p2*r4 - y3*r2*p4 - z3*p2*q4 + z3*q2*p4 + x4*q2*r3 - x4*r2*q3 - y4*p2*r3 + y4*r2*p3 + z4*p2*q3 - z4*q2*p3; 153 | c = -x1*y2*r3 + x1*z2*q3 + x1*y3*r2 - x1*z3*q2 + y1*x2*r3 - y1*z2*p3 - y1*x3*r2 + y1*z3*p2 - z1*x2*q3 + z1*y2*p3 + z1*x3*q2 - z1*y3*p2 - x2*y3*r1 + x2*z3*q1 + y2*x3*r1 - y2*z3*p1 - z2*x3*q1 + z2*y3*p1 + x1*y2*r4 - x1*z2*q4 - x1*y4*r2 + x1*z4*q2 - y1*x2*r4 + y1*z2*p4 + y1*x4*r2 - y1*z4*p2 + z1*x2*q4 - z1*y2*p4 - z1*x4*q2 + z1*y4*p2 + x2*y4*r1 - x2*z4*q1 - y2*x4*r1 + y2*z4*p1 + z2*x4*q1 - z2*y4*p1 - x1*y3*r4 + x1*z3*q4 + x1*y4*r3 - x1*z4*q3 + y1*x3*r4 - y1*z3*p4 - y1*x4*r3 + y1*z4*p3 - z1*x3*q4 + z1*y3*p4 + z1*x4*q3 - z1*y4*p3 - x3*y4*r1 + x3*z4*q1 + y3*x4*r1 - y3*z4*p1 - z3*x4*q1 + z3*y4*p1 + x2*y3*r4 - x2*z3*q4 - x2*y4*r3 + x2*z4*q3 - y2*x3*r4 + y2*z3*p4 + y2*x4*r3 - y2*z4*p3 + z2*x3*q4 - z2*y3*p4 - z2*x4*q3 + z2*y4*p3 + x3*y4*r2 - x3*z4*q2 - y3*x4*r2 + y3*z4*p2 + z3*x4*q2 - z3*y4*p2; 154 | d = x1*z2*y3 - x1*y2*z3 + y1*x2*z3 - y1*z2*x3 - z1*x2*y3 + z1*y2*x3 + x1*y2*z4 - x1*z2*y4 - y1*x2*z4 + y1*z2*x4 + z1*x2*y4 - z1*y2*x4 - x1*y3*z4 + x1*z3*y4 + y1*x3*z4 - y1*z3*x4 - z1*x3*y4 + z1*y3*x4 + x2*y3*z4 - x2*z3*y4 - y2*x3*z4 + y2*z3*x4 + z2*x3*y4 - z2*y3*x4; 155 | 156 | 157 | t = getSmallestPositiveRealCubicRoot(a, b, c, d, tol); 158 | if (t >= 0) 159 | if ((t_max < 0) | (t_max>t)) 160 | t_max = t; 161 | } 162 | } 163 | 164 | void mexFunction(int nlhs, mxArray *plhs[], 165 | int nrhs, const mxArray*prhs[]) 166 | { 167 | // assign input 168 | int n_tri = mxGetM(prhs[0]); // # rows of F 169 | int d_simplex = mxGetN(prhs[0]); // # cols of F 170 | int dim = d_simplex - 1; 171 | int n_vars = mxGetM(prhs[1]); // # rows of x/p 172 | int n_vert = n_vars / dim; 173 | const Map Fmatlab(mxGetPr(prhs[0]), n_tri, d_simplex); 174 | const Map x(mxGetPr(prhs[1]), n_vert, dim); 175 | const Map p(mxGetPr(prhs[2]), n_vert, dim); 176 | double *tol; 177 | tol = mxGetPr(prhs[3]); 178 | 179 | // update index numbers to 0-base 180 | MatrixXd F (Fmatlab); 181 | F = F.array() - 1; 182 | 183 | // compute 184 | double t_max; 185 | 186 | // compute 187 | if (dim == 2) 188 | computeInjectiveStepSize_2d(F, x, p, *tol, t_max); 189 | else if (dim == 3) 190 | computeInjectiveStepSize_3d(F, x, p, *tol, t_max); 191 | else 192 | mexErrMsgIdAndTxt("MATLAB:wrong_dimension", "dim must be either 2 or 3"); 193 | 194 | 195 | // assign outputs 196 | if (t_max < 0) 197 | t_max = mxGetInf(); 198 | plhs[0] = mxCreateDoubleScalar(t_max); // functional value 199 | 200 | } -------------------------------------------------------------------------------- /code/meshHelpers/computeInjectiveStepSize.m: -------------------------------------------------------------------------------- 1 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2 | % Code implementing the paper "Accelerated Quadratic Proxy for Geometric Optimization", SIGGRAPH 2016. 3 | % Disclaimer: The code is provided as-is for academic use only and without any guarantees. 4 | % Please contact the author to report any bugs. 5 | % Written by Shahar Kovalsky (http://www.wisdom.weizmann.ac.il/~shaharko/) 6 | % Meirav Galun (http://www.wisdom.weizmann.ac.il/~/meirav/) 7 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 8 | 9 | function tmax = computeInjectiveStepSize(F,x,p,tol) 10 | 11 | % init 12 | % tmax = inf; 13 | dim = size(F,2)-1; 14 | 15 | switch dim 16 | case 2 17 | xy = reshape(x,[],dim); 18 | pq = reshape(p,[],dim); 19 | x = xy(:,1); x = x(F); 20 | y = xy(:,2); y = y(F); 21 | p = pq(:,1); p = p(F); 22 | q = pq(:,2); q = q(F); 23 | 24 | a = p(:,1).*q(:,2) - p(:,2).*q(:,1) - p(:,1).*q(:,3) + p(:,3).*q(:,1) + p(:,2).*q(:,3) - p(:,3).*q(:,2); 25 | b = p(:,1).*y(:,2) - p(:,2).*y(:,1) - q(:,1).*x(:,2) + q(:,2).*x(:,1) - p(:,1).*y(:,3) + p(:,3).*y(:,1) + q(:,1).*x(:,3) - q(:,3).*x(:,1) + p(:,2).*y(:,3) - p(:,3).*y(:,2) - q(:,2).*x(:,3) + q(:,3).*x(:,2); 26 | c = x(:,1).*y(:,2) - x(:,2).*y(:,1) - x(:,1).*y(:,3) + x(:,3).*y(:,1) + x(:,2).*y(:,3) - x(:,3).*y(:,2); 27 | 28 | % regular cae 29 | ti1 = (-b+sqrt(b.^2-4*a.*c))/2./a; 30 | ti2 = (-b-sqrt(b.^2-4*a.*c))/2./a; 31 | % linear equation 32 | ff = (abs(a)<=tol); 33 | ti1(ff) = -c(ff)./b(ff); 34 | ti2(ff) = ti1(ff); 35 | % deal with pseudo complex roots 36 | ff=(abs(imag(ti1))<=tol); 37 | ti1(ff) = real(ti1(ff)); 38 | % 39 | ff=(abs(imag(ti2))<=tol); 40 | ti2(ff) = real(ti2(ff)); 41 | % get rid of negatives/imaginaries 42 | ti1(ti1<0 | imag(ti1)~=0) = inf; 43 | ti2(ti2<0 | imag(ti2)~=0) = inf; 44 | % take minimal value 45 | tmax = min(min(ti1),min(ti2)); 46 | 47 | case 3 48 | xyz = reshape(x,[],dim); 49 | pqr = reshape(p,[],dim); 50 | % 51 | x = xyz(:,1); x = x(F); 52 | y = xyz(:,2); y = y(F); 53 | z = xyz(:,3); z = z(F); 54 | % 55 | p = pqr(:,1); p = p(F); 56 | q = pqr(:,2); q = q(F); 57 | r = pqr(:,3); r = r(F); 58 | 59 | a = -p(:,1).*q(:,2).*r(:,3) + p(:,1).*r(:,2).*q(:,3) + q(:,1).*p(:,2).*r(:,3) - q(:,1).*r(:,2).*p(:,3) - r(:,1).*p(:,2).*q(:,3) + r(:,1).*q(:,2).*p(:,3) + p(:,1).*q(:,2).*r(:,4) - p(:,1).*r(:,2).*q(:,4) - q(:,1).*p(:,2).*r(:,4) + q(:,1).*r(:,2).*p(:,4) + r(:,1).*p(:,2).*q(:,4) - r(:,1).*q(:,2).*p(:,4) - p(:,1).*q(:,3).*r(:,4) + p(:,1).*r(:,3).*q(:,4) + q(:,1).*p(:,3).*r(:,4) - q(:,1).*r(:,3).*p(:,4) - r(:,1).*p(:,3).*q(:,4) + r(:,1).*q(:,3).*p(:,4) + p(:,2).*q(:,3).*r(:,4) - p(:,2).*r(:,3).*q(:,4) - q(:,2).*p(:,3).*r(:,4) + q(:,2).*r(:,3).*p(:,4) + r(:,2).*p(:,3).*q(:,4) - r(:,2).*q(:,3).*p(:,4); 60 | b = -x(:,1).*q(:,2).*r(:,3) + x(:,1).*r(:,2).*q(:,3) + y(:,1).*p(:,2).*r(:,3) - y(:,1).*r(:,2).*p(:,3) - z(:,1).*p(:,2).*q(:,3) + z(:,1).*q(:,2).*p(:,3) + x(:,2).*q(:,1).*r(:,3) - x(:,2).*r(:,1).*q(:,3) - y(:,2).*p(:,1).*r(:,3) + y(:,2).*r(:,1).*p(:,3) + z(:,2).*p(:,1).*q(:,3) - z(:,2).*q(:,1).*p(:,3) - x(:,3).*q(:,1).*r(:,2) + x(:,3).*r(:,1).*q(:,2) + y(:,3).*p(:,1).*r(:,2) - y(:,3).*r(:,1).*p(:,2) - z(:,3).*p(:,1).*q(:,2) + z(:,3).*q(:,1).*p(:,2) + x(:,1).*q(:,2).*r(:,4) - x(:,1).*r(:,2).*q(:,4) - y(:,1).*p(:,2).*r(:,4) + y(:,1).*r(:,2).*p(:,4) + z(:,1).*p(:,2).*q(:,4) - z(:,1).*q(:,2).*p(:,4) - x(:,2).*q(:,1).*r(:,4) + x(:,2).*r(:,1).*q(:,4) + y(:,2).*p(:,1).*r(:,4) - y(:,2).*r(:,1).*p(:,4) - z(:,2).*p(:,1).*q(:,4) + z(:,2).*q(:,1).*p(:,4) + x(:,4).*q(:,1).*r(:,2) - x(:,4).*r(:,1).*q(:,2) - y(:,4).*p(:,1).*r(:,2) + y(:,4).*r(:,1).*p(:,2) + z(:,4).*p(:,1).*q(:,2) - z(:,4).*q(:,1).*p(:,2) - x(:,1).*q(:,3).*r(:,4) + x(:,1).*r(:,3).*q(:,4) + y(:,1).*p(:,3).*r(:,4) - y(:,1).*r(:,3).*p(:,4) - z(:,1).*p(:,3).*q(:,4) + z(:,1).*q(:,3).*p(:,4) + x(:,3).*q(:,1).*r(:,4) - x(:,3).*r(:,1).*q(:,4) - y(:,3).*p(:,1).*r(:,4) + y(:,3).*r(:,1).*p(:,4) + z(:,3).*p(:,1).*q(:,4) - z(:,3).*q(:,1).*p(:,4) - x(:,4).*q(:,1).*r(:,3) + x(:,4).*r(:,1).*q(:,3) + y(:,4).*p(:,1).*r(:,3) - y(:,4).*r(:,1).*p(:,3) - z(:,4).*p(:,1).*q(:,3) + z(:,4).*q(:,1).*p(:,3) + x(:,2).*q(:,3).*r(:,4) - x(:,2).*r(:,3).*q(:,4) - y(:,2).*p(:,3).*r(:,4) + y(:,2).*r(:,3).*p(:,4) + z(:,2).*p(:,3).*q(:,4) - z(:,2).*q(:,3).*p(:,4) - x(:,3).*q(:,2).*r(:,4) + x(:,3).*r(:,2).*q(:,4) + y(:,3).*p(:,2).*r(:,4) - y(:,3).*r(:,2).*p(:,4) - z(:,3).*p(:,2).*q(:,4) + z(:,3).*q(:,2).*p(:,4) + x(:,4).*q(:,2).*r(:,3) - x(:,4).*r(:,2).*q(:,3) - y(:,4).*p(:,2).*r(:,3) + y(:,4).*r(:,2).*p(:,3) + z(:,4).*p(:,2).*q(:,3) - z(:,4).*q(:,2).*p(:,3); 61 | c = -x(:,1).*y(:,2).*r(:,3) + x(:,1).*z(:,2).*q(:,3) + x(:,1).*y(:,3).*r(:,2) - x(:,1).*z(:,3).*q(:,2) + y(:,1).*x(:,2).*r(:,3) - y(:,1).*z(:,2).*p(:,3) - y(:,1).*x(:,3).*r(:,2) + y(:,1).*z(:,3).*p(:,2) - z(:,1).*x(:,2).*q(:,3) + z(:,1).*y(:,2).*p(:,3) + z(:,1).*x(:,3).*q(:,2) - z(:,1).*y(:,3).*p(:,2) - x(:,2).*y(:,3).*r(:,1) + x(:,2).*z(:,3).*q(:,1) + y(:,2).*x(:,3).*r(:,1) - y(:,2).*z(:,3).*p(:,1) - z(:,2).*x(:,3).*q(:,1) + z(:,2).*y(:,3).*p(:,1) + x(:,1).*y(:,2).*r(:,4) - x(:,1).*z(:,2).*q(:,4) - x(:,1).*y(:,4).*r(:,2) + x(:,1).*z(:,4).*q(:,2) - y(:,1).*x(:,2).*r(:,4) + y(:,1).*z(:,2).*p(:,4) + y(:,1).*x(:,4).*r(:,2) - y(:,1).*z(:,4).*p(:,2) + z(:,1).*x(:,2).*q(:,4) - z(:,1).*y(:,2).*p(:,4) - z(:,1).*x(:,4).*q(:,2) + z(:,1).*y(:,4).*p(:,2) + x(:,2).*y(:,4).*r(:,1) - x(:,2).*z(:,4).*q(:,1) - y(:,2).*x(:,4).*r(:,1) + y(:,2).*z(:,4).*p(:,1) + z(:,2).*x(:,4).*q(:,1) - z(:,2).*y(:,4).*p(:,1) - x(:,1).*y(:,3).*r(:,4) + x(:,1).*z(:,3).*q(:,4) + x(:,1).*y(:,4).*r(:,3) - x(:,1).*z(:,4).*q(:,3) + y(:,1).*x(:,3).*r(:,4) - y(:,1).*z(:,3).*p(:,4) - y(:,1).*x(:,4).*r(:,3) + y(:,1).*z(:,4).*p(:,3) - z(:,1).*x(:,3).*q(:,4) + z(:,1).*y(:,3).*p(:,4) + z(:,1).*x(:,4).*q(:,3) - z(:,1).*y(:,4).*p(:,3) - x(:,3).*y(:,4).*r(:,1) + x(:,3).*z(:,4).*q(:,1) + y(:,3).*x(:,4).*r(:,1) - y(:,3).*z(:,4).*p(:,1) - z(:,3).*x(:,4).*q(:,1) + z(:,3).*y(:,4).*p(:,1) + x(:,2).*y(:,3).*r(:,4) - x(:,2).*z(:,3).*q(:,4) - x(:,2).*y(:,4).*r(:,3) + x(:,2).*z(:,4).*q(:,3) - y(:,2).*x(:,3).*r(:,4) + y(:,2).*z(:,3).*p(:,4) + y(:,2).*x(:,4).*r(:,3) - y(:,2).*z(:,4).*p(:,3) + z(:,2).*x(:,3).*q(:,4) - z(:,2).*y(:,3).*p(:,4) - z(:,2).*x(:,4).*q(:,3) + z(:,2).*y(:,4).*p(:,3) + x(:,3).*y(:,4).*r(:,2) - x(:,3).*z(:,4).*q(:,2) - y(:,3).*x(:,4).*r(:,2) + y(:,3).*z(:,4).*p(:,2) + z(:,3).*x(:,4).*q(:,2) - z(:,3).*y(:,4).*p(:,2); 62 | d = x(:,1).*z(:,2).*y(:,3) - x(:,1).*y(:,2).*z(:,3) + y(:,1).*x(:,2).*z(:,3) - y(:,1).*z(:,2).*x(:,3) - z(:,1).*x(:,2).*y(:,3) + z(:,1).*y(:,2).*x(:,3) + x(:,1).*y(:,2).*z(:,4) - x(:,1).*z(:,2).*y(:,4) - y(:,1).*x(:,2).*z(:,4) + y(:,1).*z(:,2).*x(:,4) + z(:,1).*x(:,2).*y(:,4) - z(:,1).*y(:,2).*x(:,4) - x(:,1).*y(:,3).*z(:,4) + x(:,1).*z(:,3).*y(:,4) + y(:,1).*x(:,3).*z(:,4) - y(:,1).*z(:,3).*x(:,4) - z(:,1).*x(:,3).*y(:,4) + z(:,1).*y(:,3).*x(:,4) + x(:,2).*y(:,3).*z(:,4) - x(:,2).*z(:,3).*y(:,4) - y(:,2).*x(:,3).*z(:,4) + y(:,2).*z(:,3).*x(:,4) + z(:,2).*x(:,3).*y(:,4) - z(:,2).*y(:,3).*x(:,4); 63 | 64 | %regular case - cubic equation 65 | delta0 = b.^2-3.*a.*c; 66 | delta1 = 2.*b.^3 - 9.*a.*b.*c + 27.*a.^2.*d; 67 | C=((delta1+sqrt(delta1.^2-4*delta0.^3))/2).^(1/3); 68 | u1 = 1; 69 | u2 = ((-1+sqrt(3)*sqrt(-1))/2); 70 | u3 = ((-1-sqrt(3)*sqrt(-1))/2); 71 | % 72 | ti1 = -(b+u1*C+delta0./(u1*C))./(3*a); 73 | ti2 = -(b+u2*C+delta0./(u2*C))./(3*a); 74 | ti3 = -(b+u3*C+delta0./(u3*C))./(3*a); 75 | % quadratic equation 76 | ff = (abs(a)<=tol); 77 | ti1(ff) = (-c(ff)+sqrt(c(ff).^2-4*b(ff).*d(ff)))/2./b(ff); 78 | ti2(ff) = (-c(ff)-sqrt(c(ff).^2-4*b(ff).*d(ff)))/2./b(ff); 79 | ti3(ff) = ti2(ff); 80 | % linear equation 81 | ff = (abs(a)<=tol & abs(b)<=tol); 82 | ti1(ff) = -d(ff)./c(ff); 83 | ti2(ff) = ti1(ff); 84 | ti3(ff) = ti1(ff); 85 | % deal with pseudo complex roots 86 | ff=(abs(imag(ti1))<=tol); 87 | ti1(ff) = real(ti1(ff)); 88 | % 89 | ff=(abs(imag(ti2))<=tol); 90 | ti2(ff) = real(ti2(ff)); 91 | % 92 | ff=(abs(imag(ti3))<=tol); 93 | ti3(ff) = real(ti3(ff)); 94 | % get rid of negatives/imaginaries 95 | ti1(ti1<0 | imag(ti1)~=0) = inf; 96 | ti2(ti2<0 | imag(ti2)~=0) = inf; 97 | ti3(ti3<0 | imag(ti3)~=0) = inf; 98 | % take minimal value 99 | tmax = min(min(min(ti1),min(ti2)),min(ti3)); 100 | 101 | otherwise 102 | error('invalid dimension') 103 | end -------------------------------------------------------------------------------- /replicability_instructions.htm: -------------------------------------------------------------------------------- 1 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 33 | 34 | 36 | 649 | 1117 | 1147 | 1148 | 1149 | 1150 | 1151 |
1152 | 1153 |

This code was evaluated for replicability by an independent 1161 | team of experts (see https://replicability.graphics/ ).

1163 | 1164 |

The remainder of this file contains the evaluation report, along with suggestions to successfully 1171 | compile and run the code.

1172 | 1173 |

Information

1175 | 1176 |
    1180 |
  • Paper topic: Geometry
  • 1187 |
  • Software type: 1192 | Code
  • 1193 |
  • Able to run a replicability test: True
  • 1199 |
  • Replicability score: 5
  • 1206 |
  • Software language: 1211 | Matlab / Mathematica / ..
  • 1213 |
  • License: unspecified
  • 1218 |
  • Build mechanism: Not applicable (python, Matlab..)
  • 1227 |
  • Dependencies: matlab 1232 | / eigen / libigl
  • 1233 |
  • Documentation score {0,1,2}: 1
  • 1240 |
  • Reviewer: Julie Digne 1245 | <julie.digne@liris.cnrs.fr>
  • 1246 |
  • Time spent for the test (build->first 1251 | run, timeout at 100min): 1253 | 20min
  • 1254 |
1255 | 1256 |

Source code 1260 | information

1261 | 1262 | 1282 | 1283 |

Comments

1286 | 1287 |
To compile it under linux: in compileAllMex.m set up the right paths for Eigen and libigl. Then to run the examples change the path formating to be linux-compatible: replace 'data\paper_deformation_2d_gecko_wConstraints.mat' by 'data/paper_deformation_2d_gecko_wConstraints.mat' for example (similar changes for all example scripts. Up to proper mesh visualization, the results are similar to the ones in the paper in both 2D and 3D.
1305 | 1306 |

 

1307 | 1308 |
1309 | 1310 | 1311 | 1312 | 1313 | --------------------------------------------------------------------------------