function [hdr,be] = read_hdr_raw(fname)
% Read a NIFTI-1 hdr file
% FORMAT [hdr,be] = read_hdr_raw(fname)
% fname - filename of image
% hdr   - a structure containing hdr info
% be    - whether big-endian or not
% _______________________________________________________________________
% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging

%
% $Id: read_hdr_raw.m 1143 2008-02-07 19:33:33Z spm $

hdr = [];
be  = [];
ok  = true;

% Name of header file
[pth,nam,ext] = fileparts(fname);
switch ext
case {'.img','.hdr'}
    hname = fullfile(pth,[nam '.hdr']);
case {'.nii'}
    hname = fullfile(pth,[nam '.nii']);
otherwise
    hname = fullfile(pth,[nam '.hdr']);
end;

% Open it if possible
fp  = fopen(hname,'r','native');
if fp==-1
    hdr = [];
    return;
end;

% Sort out endian issues of header
[unused,unused,mach] = fopen(fp);
if strcmp(mach,'ieee-be') || strcmp(mach,'ieee-be.l64')
    be = true;
else
    be = false;
end;
fseek(fp,0,'bof');
fseek(fp,40,'bof');
nd = fread(fp,1,'int16')';
if isempty(nd),
    fclose(fp);
    hdr = [];
    return;
elseif nd<1 || nd>7
    be = ~be;
    fclose(fp);
    if be, mach = 'ieee-be';
    else   mach = 'ieee-le';
    end;
    fp = fopen(hname,'r',mach);
    if fp==-1
        hdr = [];
        return;
    end;
end;

% Is it NIFTI or not
fseek(fp,0,'bof');
fseek(fp,344,'bof');
mgc = deblank(char(fread(fp,4,'uint8')'));
switch mgc
case {'ni1','n+1'}
    org = niftistruc;
otherwise
    org = mayostruc;
end;
fseek(fp,0,'bof');
% Read the fields
for i=1:length(org)
    tmp = fread(fp,org(i).len,['*' org(i).dtype.prec])';
    if length(tmp) ~= org(i).len
disp([length(tmp) org(i).len]);
        tmp = org(i).def;
        ok  = false;
    end;
    tmp = feval(org(i).dtype.conv,tmp);
    hdr.(org(i).label) = tmp;
end;

fclose(fp);
if ~ok,
     fprintf('There was a problem reading the header of\n');
     fprintf('"%s".\n', fname);
     fprintf('It may be corrupted in some way.');
end;
return;


function [node,elem]=meshresample(v,f,keepratio)
%
% [node,elem]=meshresample(v,f,keepratio)
%
% resample mesh using CGAL mesh simplification utility
%
% author: Qianqian Fang, <q.fang at neu.edu>
% date: 2007/11/12
%
% input:
%    v: list of nodes
%    f: list of surface elements (each row for each triangle)
%    keepratio: decimation rate, a number less than 1, as the percentage
%               of the elements after the sampling
%
% output:
%    node: the node coordinates of the sampled surface mesh
%    elem: the element list of the sampled surface mesh
%
% -- this function is part of iso2mesh toolbox (http://iso2mesh.sf.net)
%

[node,elem]=domeshsimplify(v,f,keepratio);

if(length(node)==0)
    warning(['Your input mesh contains topological defects, and the ',...
           'mesh resampling utility aborted during processing. Now iso2mesh ',...
           'is trying to repair your mesh with meshcheckrepair. ',...
           'You can also call this manually before passing your mesh to meshresample.'] );
    [vnew,fnew]=meshcheckrepair(v,f);
    [node,elem]=domeshsimplify(vnew,fnew,keepratio);
end
[node,I,J]=unique(node,'rows');
elem=J(elem);
saveoff(node,elem,mwpath('post_remesh.off'));

end

% function to perform the actual resampling
function [node,elem]=domeshsimplify(v,f,keepratio)
  exesuff=getexeext;
  exesuff=fallbackexeext(exesuff,'cgalsimp2');

  saveoff(v,f,mwpath('pre_remesh.off'));
  deletemeshfile(mwpath('post_remesh.off'));
  system([' "' mcpath('cgalsimp2') exesuff '" "' mwpath('pre_remesh.off') '" ' num2str(keepratio) ' "' mwpath('post_remesh.off') '"']);
  [node,elem]=readoff(mwpath('post_remesh.off'));
end


function [edges]=renumberEdges(edges)

% create mapping to points
idx = unique(edges(:));
for i = 1 : length(idx)
    map(idx(i),1) = i;
end

% renumber bnde to correspond with pfix
for i = 1 : size(edges,1)
    edges(i,1) = map(edges(i,1));
    edges(i,2) = map(edges(i,2));
end

end


classdef ThermalComputer < handle

    properties (Access = public)
        computation
    end

    properties (Access = private)
        testName
    end

    methods (Access = public)
        function obj = ThermalComputer(cParams)
            obj.testName = cParams.testName;
        end

        function compute(obj)
            s = obj.createFEMparameters();
            obj.computation = FEM.create(s);
            obj.computation.solve();
        end
    end

    methods (Access = private)

        function s = createFEMparameters(obj)
            gidParams = obj.createGiDparameters();
            s.dim       = gidParams.pdim;
            s.type      = gidParams.ptype;
            s.scale     = gidParams.scale;
            s.mesh      = gidParams.mesh;
            s.dirichlet = gidParams.dirichlet;
            s.pointload = gidParams.pointload;
        end

        function gidParams = createGiDparameters(obj)
            file = obj.testName;
            gidReader = FemInputReader_GiD();
            gidParams = gidReader.read(file);
        end

    end
end


%   AUTHORSHIP
%   Primary Developer: Stephen Meehan <swmeehan@stanford.edu>
%   Math Lead & Secondary Developer:  Connor Meehan <connor.gw.meehan@gmail.com>
%   Bioinformatics Lead:  Wayne Moore <wmoore@stanford.edu>
%   Provided by the Herzenberg Lab at Stanford University
%   License: BSD 3 clause
%
function ok=initJava
ok=false;
try
    edu.stanford.facs.swing.StochasticGradientDescent.EPOCH_REPORTS;
catch
    jar=fullfile(fileparts(mfilename('fullpath')), 'umap.jar');
    javaaddpath(jar);
end
try
    edu.stanford.facs.swing.StochasticGradientDescent.EPOCH_REPORTS;
    ok=true;
catch
end


% setdiff_bc - setdiff backward compatible with Matlab versions prior to 2013a

% Copyright (C) 2013 Arnaud Delorme
%
% This file is part of EEGLAB, see http://www.eeglab.org
% for the documentation and details.
%
% Redistribution and use in source and binary forms, with or without
% modification, are permitted provided that the following conditions are met:
%
% 1. Redistributions of source code must retain the above copyright notice,
% this list of conditions and the following disclaimer.
%
% 2. Redistributions in binary form must reproduce the above copyright notice,
% this list of conditions and the following disclaimer in the documentation
% and/or other materials provided with the distribution.
%
% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
% THE POSSIBILITY OF SUCH DAMAGE.

function [C,IA] = setdiff_bc(A,B,varargin)

errorFlag = error_bc;

v = version;
indp = find(v == '.');
v = str2num(v(1:indp(2)-1));
if v > 7.19, v = floor(v) + rem(v,1)/10; end

if nargin > 2
    ind = strmatch('legacy', varargin);
    if ~isempty(ind)
        varargin(ind) = [];
    end
end

if v >= 7.14
    [C,IA] = setdiff(A,B,varargin{:},'legacy');
    if errorFlag
        [C2,IA2] = setdiff(A,B,varargin{:});
        if (~isequal(C, C2) || ~isequal(IA, IA2))
            warning('backward compatibility issue with call to setdiff function');
        end
    end
else
    [C,IA] = setdiff(A,B,varargin{:});
end


file = 'PnP_mex.cpp';

INCLUDE = {'/usr/local/include' , '/usr/include/glog', '/usr/include/eigen3',...
	   '/home/htaira/Desktop/zips/ceres-solver/build/config/'};

LIBFOLDER = {'/home/htaira/Desktop/zips/ceres-solver/build/lib/', '/usr/lib/x86_64-linux-gnu/'};

LIBNAME = {'ceres', 'ceres', 'glog', 'gflags', 'suitesparseconfig',...
	   'cholmod', 'lapack', 'blas', 'spqr', 'gomp', 'cxsparse'};

include = strjoin(strcat('-I', INCLUDE));
libfolder = strjoin(strcat('-L', LIBFOLDER));
libname = strjoin(strcat('-l', LIBNAME));

eval(['mex' ' ' file ' ' include ' '  libfolder ' ' libname]);


function res = is_symbol(x)
% check whether an expression is a symbol
res = isequal(exp_head(x),@Symbol);


%   AUTHORSHIP
%   Primary Developer: Stephen Meehan <swmeehan@stanford.edu>
%   Math Lead & Secondary Developer:  Connor Meehan <connor.gw.meehan@gmail.com>
%   Bioinformatics Lead:  Wayne Moore <wmoore@stanford.edu>
%   Provided by the Herzenberg Lab at Stanford University
%   License: BSD 3 clause
%

classdef StringArray < handle
    properties(SetAccess=private)
        strings;
        N;
    end

    methods
        function this=StringArray(strings)
            this.strings=strings;
            this.N=length(strings);
        end
        function idx=lastIndexOf(this, search)
            idx=0;
            for i=this.N:-1:1
                if strcmp(this.strings{i}, search)
                    idx=i;
                    break;
                end
            end
        end

        function ok=contains(this,search)
            ok=this.indexOf(search)>0;
        end

        function idx=indexOf(this, search)
            idx=0;
            for i=1:this.N
                if strcmp(this.strings{i}, search)
                    idx=i;
                    break;
                end
            end
        end

        function idx=endsWith(this, with)
            idx=0;
            for i=1:this.N
                if endsWith(this.strings{i}, with)
                    idx=i;
                    break;
                end
            end
        end

        function indices=indicesOf(this, search)
            indices=[];
            for i=1:this.N
                if strcmp(this.strings{i}, search)
                    indices(end+1)=i;
                end
            end
        end

        function idx=indexOfI(this, search)
            idx=0;
            for i=1:this.N
                if strcmpi(this.strings{i}, search)
                    idx=i;
                    break;
                end
            end
        end

    end

    methods(Static)
        function ok=IsOk(x)
            ok=true;
            if iscell(x)
                N=length(x);
                for i=1:N
                    if ~ischar(x{i})
                        ok=false;
                        break;
                    end
                end
            elseif ischar(x)
            else
                ok=false;
                warning('Expecting string or string array');
            end
        end

        function strs=Trim(strs, limit)
            if length(strs)>limit
                strs{limit}=[num2str(length(strs)-limit) ' more...'];
                strs(limit+1:end)=[];
            end
        end
        function c=Num2Str(nums, prefix)
            if nargin<2
                prefix='#';
            end
            N_=length(nums);
            c=cell(1, N_);
            for i_=1:N_
                c{i_}=[prefix num2str(nums(i_))];
            end
        end

        function out=Intersection(left, right)
            if isempty(left)
                out=right;
            elseif isempty(right)
                out=left;
            else
                out={};
                r=StringArray.Set(right);
                N=length(left);
                for i=1:N
                    try
                        if r.contains(java.lang.String(left{i}))
                            out{end+1}=left{i};
                        end
                    catch ex
                    end
                end
            end
        end

        function out=Sort(in, canon)
            if nargin==1
                out=StringArray.Cell(StringArray.Set(in));
            else
                N=length(in);
                this=StringArray(canon);
                map=java.util.TreeMap;
                for i=1:N
                    str=in{i};
                    idx=this.indexOf(str);
                    if idx>0
                        map.put(idx, str);
                    else
                        map.put(N+i, str);
                    end
                end
                out=StringArray.Cell(map.values);
            end
        end

        function c=Cell(javaCollection)
            N=javaCollection.size;
            c=cell(1,N);
            it=javaCollection.iterator;
            for i=1:N
                c{i}=it.next;
            end
        end

        function out=JavaString2Chars(in)
            N=length(in);
            out=cell(1,N);
            for i=1:N
                out{i}=char(in{i});
            end
        end

        function c=JavaArrayToCell(javaArr)
            if iscell(javaArr)
                c=javaArr;
            else
                N=length(javaArr);
                c=cell(1,N);
                for i=1:N
                    c{i}=char(javaArr(i));
                end
            end
        end

        function lst=List(strs)
            lst=java.util.ArrayList;
            N=length(strs);
            for i=1:N
                lst.add(strs{i});
            end
        end

        function lst=Vector(strs)
            lst=java.util.Vector;
            N=length(strs);
            for i=1:N
                lst.add(strs{i});
            end
        end

        function lst=ListFromJavaArray(strs)
            lst=java.util.ArrayList;
            N=length(strs);
            for i=1:N
                lst.add(strs(i));
            end
        end
        function set=Set(strs, set)
            if nargin<2
                set=java.util.TreeSet;
            end
            N=length(strs);
            for i=1:N
                if ~isempty(strs{i})
                    set.add(java.lang.String(strs{i}));
                end
            end
        end

        function out=RemoveDuplicates(strs, set)
            if nargin<2
                set=StringArray.Set(strs);
            else
                set=StringArray.Set(strs, set);
            end
            N_=set.size;
            out=cell(1,N_);
            it=set.iterator;
            for i=1:N_
                out{i}=it.next;
            end
        end

        function [out, dupCnt]=ForceUnique(strs, prefix, suffix)
            dupCnt=0;
            map=java.util.HashMap;
            N_=length(strs);
            out=cell(1,N_);
            for i=1:N_
                if map.containsKey(strs{i})
                    cnt=map.get(strs{i})+1;
                else
                    cnt=1;
                end
                map.put(strs{i}, cnt);
                if cnt>1
                    out{i}=[strs{i} prefix num2str(cnt) suffix];
                    dupCnt=dupCnt+1;
                else
                    out{i}=strs{i};
                end
            end
        end

        function ok=Contains(searchedStrings, search)
            sa=StringArray(searchedStrings);
            ok=sa.indexOf(search)>0;
        end
        function idx=IndexOf(searchedStrings, search)
            sa=StringArray(searchedStrings);
            idx=sa.indexOf(search);
        end

        function idxs=IndexOfEmpties(searchedStrings)
            N=length(searchedStrings);
            idxs=[];
            for i=1:N
                if isempty(searchedStrings{i})
                    idxs(end+1)=i;
                end
            end
        end

        function idx=IndexOfIgnoreCase(searchedStrings, search)
            sa=StringArray(searchedStrings);
            idx=sa.indexOfI(search);
        end

        function idxs=FirstListIndexes(searched, searches)
            N=length(searches);
            idxs=zeros(1,N);
            for i=1:N
                idxs(i)=searched.indexOf(searches{i});
            end
            idxs=idxs+1;
        end

        function [idxs, foundAll]=EndsWith(searchedStrings, searches)
            idxs=[];
            sa=StringArray(searchedStrings);
            N=length(searches);
            for i=1:N
                idx=sa.endsWith(searches{i});
                if idx>0
                    idxs=[idxs idx+1];
                else
                    disp('huh');
                end
            end
            foundAll=length(idxs)>=length(searchedStrings);
        end

        %Not sure if a faster search than this is available at
        %https://www.mathworks.com/matlabcentral/answers/335930-most-efficient-way-to-search-in-text-arrays
        %I think that the the problem with find(strcmp(a,s),1) is that
        %strcmp does not STOP after its first successful strcmp
        %the Containers.map approach WILL ... but has a high startup
        %cost for under 1000 strings
        function idxs=IndexesOf(searchedStrings, searches)
            idxs=[];
            sa=StringArray.List(searchedStrings);
            N=length(searches);
            for i=1:N
                idx=sa.indexOf(searches{i});
                if idx>=0
                    idxs=[idxs idx+1];
                else
                    disp('huh');
                end
            end
        end

        function idxs=IndexesOf2(searchedStrings, searches)
            sa=StringArray.List(searchedStrings);
            N=length(searches);
            idxs=zeros(1,N);
            for i=1:N
                idxs(i)=sa.indexOf(searches{i})+1;
            end
        end

        function idxs=NotFound(searchedStrings, searches)
            idxs=[];
            sa=StringArray.List(searchedStrings);
            N=length(searches);
            for i=1:N
                idx=sa.indexOf(searches{i});
                if idx<0
                    idxs=[idxs i];
                end
            end
        end

        function [ok, sameButReordered]=AreSameOrEmpty(d1, d2)
            ok=isequal(d1, d2);
            sameButReordered=false;
            if ~ok
                if length(d1)==length(d2)
                    nf=StringArray.NotFound(d2, d1);
                    if isempty(nf)
                        sameButReordered=true;
                    elseif length(nf)==1
                        % is FMO?
                        if isempty(d1{nf}) || isempty(d2{nf})
                            d1_=d1;
                            d2_=d2;
                            d1_{nf}='dummy';
                            d2_{nf}='dummy';
                            ok=isequal(d1_,d2_);
                        end
                    end
                end
            end
        end

        function [allFound, idxs]=Find(d1, d2, allowOneEmptyLikeFMO)
            if nargin<3
                allowOneEmptyLikeFMO=false;
            end
            allFound=true;
            N=length(d1);
            idxs=zeros(1,N);

            sa2=StringArray(d2);
            for i=1:N
                ii=sa2.indexOf(d1{i});
                if ii<1
                    if allowOneEmptyLikeFMO
                        allowOneEmptyLikeFMO=false;
                        [emptyCount, ii]=StringArray.GetEmpties(d2);
                        if emptyCount ~= 1
                            [emptyCount, i2]=StringArray.GetEmpties(d1);
                            if emptyCount ~= 1
                                allFound=false;
                                ii=0;
                            else
                                ii=0;
                                if i2==i
                                    sa1=StringArray(d1);
                                    N2=length(d2);
                                    for j=1:N2
                                        jj=sa1.indexOf(d2{j});
                                        if jj<1
                                            ii=j;
                                            break;
                                        end
                                    end
                                end
                                if ii<1
                                    allFound=false;
                                end
                            end
                        end
                    else
                        allFound=false;
                    end
                end
                if ~isempty(ii)
                    idxs(i)=ii(1);
                end
            end
        end

        function str=toString(stringArray, delimiter, useQuotes)
            if nargin<3
                useQuotes=false;
                if nargin<2
                    delimiter=', ';
                end
            end
            N=length(stringArray);
            str='';
            for i=1:N
                v=stringArray{i};
                if ~ischar(v)
                    v=String.toString(v);
                end
                if useQuotes
                    v=['"' v '"'];
                end
                if (i>1)
                    str=[str delimiter v];
                else
                    str=v;
                end
            end
        end

        function ok=isEqual(stringArray1, stringArray2)
            N1=length(stringArray1);
            N2=length(stringArray2);
            ok=false;
            if N1==N2
                ok=true;
                for i=1:N1
                    if ~strcmp(stringArray1{i}, stringArray2{i})
                        ok=false;
                        break;
                    end
                end
            end
        end

        function a=Join(a, a2)
            N=length(a2);
            for i=1:N
                a{end+1}=a2{i};
            end
        end

        function stringArray=Subset(strings, idxs)
            stringArray=StringArray( strings(idxs) );
        end

        function [searchResultIdxs, unSearchedStrings, unFoundStrings]=...
                SearchSubset(searchedStrings, subsettingIndices, searchStrings)
            N=length(searchStrings);
            unFoundStrings={};
            searchResultIdxs=1:N;
            subset=StringArray.Subset(searchedStrings, subsettingIndices);
            unSearchedStrings=subset.strings;
            for i=N:-1:1
                idx=subset.indexOf(searchStrings{i});
                searchResultIdxs(i)=idx;
                if idx>0
                    %remove found string
                    unSearchedStrings(idx)=[];
                else
                    unFoundStrings{end+1}=searchStrings{i};
                end
            end
        end

        function [searchResultIdxs, unsearchedStrings, unFoundStrings]=...
                Search2Subsets(searchedStrings1, searchedStrings2,...
                subsettingIndices, searchStrings)
            N=length(searchStrings);

            unFoundStrings={};
            searchResultIdxs=1:N;
            subset1=StringArray.Subset(searchedStrings1, subsettingIndices);
            subset2=StringArray.Subset(searchedStrings2, subsettingIndices);
            temp=subset1.strings;
            for i=N:-1:1
                searchString=searchStrings{i};
                idx=subset1.indexOf(searchString);
                if idx==0
                    idx=subset2.indexOf(searchString);

                end
                searchResultIdxs(i)=idx;
                if idx>0
                    %remove found string
                    temp{idx}='';
                else
                    unFoundStrings{end+1}=searchString;
                end
            end
            unsearchedStrings={};
            for i=1:length(temp)
                if ~isempty(temp{i})
                    unsearchedStrings{end+1}=temp{i};
                end
            end
        end

         function[files]=getField(handles, fileField)
             files={};
             if isfield(handles, fileField)
                 temp=getfield(handles,fileField);
                 if ~strcmp('cell', class(temp))
                     files={temp};
                 else
                     files=temp;
                 end
             end
         end

         function array=toArray(something)
             if ~strcmp('cell', class(something))
                 array={something};
             else
                 array=something;
             end
         end

         function s=encodeCell(c, quotes)
             if nargin==1
                 quotes=false;
             end
             N=length(c);
             s='';
             for i=1:N
                 if i>1
                     s=[s ', '];
                 end
                 if quotes
                     s=[s '''' c{i} ''''];
                 else
                     s=[s c{i}];
                 end
             end
             if quotes
                 s=['{' s '}'];
             end
         end

         function c=decodeCell(s)
             if String.StartsWith(s, '{''')
                 c=eval(s);
             else
                 c=regexp(s, '[^,\s]*', 'match');
             end
         end

         function idxs=StartsWith(sa, str)
             idxs=[];
             N=length(sa);
             for i=1:N
                 if startsWith(str, sa{i})
                     idxs(end+1)=i;
                 end
             end
         end

         function ok=EqualsIndexed(these, those, idxs)
             try
                 N_=length(idxs);
                 N2=length(these);
                 N3=length(those);
                 ok=true;
                 for i=1:N_
                     idx=idxs(i);
                     if idx>N2 || idx>N3
                         continue;
                     end
                     if ~strcmp(these{idx}, those{idx})
                         ok=false;
                         break;
                     end
                 end
             catch exception
                 warning(exception.message);
                 ok=false;
             end
         end

         function ok=Equals(these, those)
             N1=length(these);
             N2=length(those);
             if N1 ~= N2
                 ok=false;
             else
                 ok=StringArray.EqualsIndexed(these, those, [1:N1]);
             end
         end

         function found=HasAny(superSet, subSet, superSetValues)
             found=false;
             for i=1:length(subSet)
                 idx=StringArray.IndexOf(superSet, subSet{i});
                 if idx>0
                     if nargin<2 || ~isempty(superSetValues{idx})
                         found=true;
                         break;
                     end
                 end
             end
         end

         function found=HasAll(superSet, subSet, superSetValues)
             found=true;
             for i=1:length(subSet)
                 idx=StringArray.IndexOf(superSet, subSet{i});
                 if idx>0
                     if nargin>1 && isempty(superSetValues{idx})
                         found=false;
                         break;
                     end
                 else
                     found=false;
                     break;
                 end
             end
         end

         function [arrayOfArrayIdx, arrayIdx]=FindAofA(arrayOfArrays, searchValue)
             arrayOfArrayIdx=0;
             arrayIdx=0;
             N=length(arrayOfArrays);
             for i=1:N
                 j=StringArray.IndexOf(arrayOfArrays{i}, searchValue);
                 if j>0
                     arrayIdx=j;
                     arrayOfArrayIdx=i;
                     return;
                 end
             end
         end

         function ok=ContainsInAofA(arrayOfArrays, arrayIdx)
             ok=false;
             N=length(arrayOfArrays);
             if N>=arrayIdx
                 j=StringArray.IndexOf(arrayOfArrays{arrayIdx}, searchValue);
                 if j>0
                   ok=true;
                 end
             end
         end

         function [lbl, sz]=GetLongest(strs)
             N=length(strs);
             sz=0;
             lbl=[];
             for i=1:N
                 ln=length(strs{i});
                 if ln>sz
                     sz=ln;
                     lbl=strs{i};
                 end
             end
         end

         function out=ToLower(strs)
             N=length(strs);
             out=cell(1,N);
             for i=1:N
                 out{i}=lower(strs{i});
             end
         end

         function [cnt, idxs]=GetEmpties(strs)
             cnt=0;
             idxs=[];
             N=length(strs);
             for i=1:N
                 if isempty(strs{i})
                     cnt=cnt+1;
                     idxs(end+1)=i;
                 end
             end
         end

         function ok=IsValid(in)
             if iscell(in)
                 ok=true;
                 N=length(in);
                 for i=1:N
                     if ~ischar(in{i})
                         ok=false;
                         break;
                     end
                 end
             else
                 ok=false;
             end

         end
    end
end


function ply_to_tri_surface_test ( )

%*****************************************************************************80
%
%% PLY_TO_TRI_SURFACE_TEST tests the PLY_TO_TRI_SURFACE library.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    28 September 2008
%
%  Author:
%
%    John Burkardt
%
  timestamp ( );
  fprintf ( 1, '\n' );
  fprintf ( 1, 'PLY_TO_TRI_SURFACE_TEST\n' );
  fprintf ( 1, '  MATLAB version:\n' );
  fprintf ( 1, '  Test the PLY_TO_TRI_SURFACE library.\n' );

  ply_file_name = 'sphere.ply';

  ply_to_tri_surface_test01 ( ply_file_name );

  ply_file_name = 'cube.ply';

  ply_to_tri_surface_test02 ( ply_file_name );
%
%  Terminate.
%
  fprintf ( 1, '\n' );
  fprintf ( 1, 'PLY_TO_TRI_SURFACE_TEST:\n' );
  fprintf ( 1, '  Normal end of execution.\n' );
  fprintf ( 1, '\n' );
  timestamp ( );

  return
end


function result = isNaNgeneral(x)
% Determine if x contains a NaN value
%
% function result = isNaNgeneral(x)
%
% Returns a logical value which indicates whether or not the input x
% contains a NaN value. The input x can be defined recursively by arrays,
% structs and cells.
%
% See also:

% This file is part of Manopt: www.manopt.org.
% Original author: Xiaowen Jiang, Aug. 31, 2021.
% Contributors: Nicolas Boumal
% Change log:

    if ~isstruct(x) && ~iscell(x) && ~isnumeric(x)
        up = MException('manopt:isNaNgeneral', ...
                    'isNaNgeneral should only accept structs, cells or arrays.');
        throw(up);
    end

    % recursively find NaN for each part of x
    if isstruct(x)
        result = isNaN_struct(x);
        if result > 0
            result = true;
        end
    elseif iscell(x)
        result = isNaN_cell(x);
        if result > 0
            result = true;
        end
    else
        result = any(isnan(x(:)));
    end

    % when x is a struct
    function result = isNaN_struct(x)
        elems = fieldnames(x);
        nelems = numel(elems);
        result = false;
        for ii = 1:nelems
            if isstruct(x.(elems{ii}))
                result = result + isNaN_struct(x.(elems{ii}));
            elseif iscell(x.(elems{ii}))
                result = result + isNaN_cell(x.(elems{ii}));
            else
                result = result + any(isnan(x.(elems{ii})(:)));
            end
        end
    end

    % when x is a cell
    function result = isNaN_cell(x)
        ncell = length(x);
        result = false;
        for ii = 1:ncell
            if isstruct(x{ii})
                result = result + isNaN_struct(x{ii});
            elseif iscell(x{ii})
                result = result + isNaN_cell(x{ii});
            else
                result = result + any(isnan(x{ii}(:)));
            end
        end
    end
end


function F = stoploop(str)
% STOPLOOP - creates stop button to have a user interrupt a loop
%
%  FS = STOPLOOP creates a message box window and returns a structure FS that
%  holds two functions, called FS.Stop and FS.Clear. The function FS.Stop()
%  will return true, if the OK button has been clicked (or the message box
%  has been removed), so that a loop can be interrupted.
%  The function FS.Clear() can be used to remove the message box, if a loop
%  has ended without user interruption.
%
%  FS = STOPLOOP(STR) uses the string STR to display instead of the default
%  'Stop the Loop'.
%
%  Example:
%    tic ;         % We will measure elapsed time in a loop
%                  % Set up the stop box:
%    FS = stoploop({'Stop me before', '5 seconds have elapsed'}) ;
%                  % Display elapsed time
%    fprintf('\nSTOPLOOP: elapsed time (s): %5.2f\n',toc)
%                  % start the loop
%    while(~FS.Stop() && toc < 5),       % Check if the loop has to be stopped
%        fprintf('%c',repmat(8,6,1)) ;   % clear up previous time
%        fprintf('%5.2f\n',toc) ;        % display elapsed time
%    end
%    FS.Clear() ;  % Clear up the box
%    clear FS ;    % this structure has no use anymore
%
%  Notes:
%  - The function call F.Stop() issues a drawnow command.
%  - The function call F.Clear() does nothing when the message box already
%    has been cleared.
%
%  See also MSGBOX, KEYBOARD, DBSTOP, WHILE, FOR
%           GETKEYNOW, GETKEYWAIT, GETKEY (on the File Exchange)

% for Matlab R14+
% version 1.0 (jun 2008)
% (c) Jos van der Geest
% email: jos@jasen.nl

% History:
% 1.0 (jun 2008) Inspired by several requests over the years on CSSM

error(nargoutchk(1,1,nargout)) ;

if nargin,
    if ~ischar(str) && ~iscellstr(str),
        error([mfilename ':InputString'],...
            'Input should be a string, or a cell array of strings.') ;
    end
else
    % default message string
    str = 'Stop the Loop' ;
end

% create a msgbox displaying the string
H = msgbox(str,'STOPLOOP') ;

% create the two anonymous functions
F.Stop = @() stopfun(H) ; % false if message box still exists
F.Clear = @() clearfun(H) ; % delete message box

function r = stopfun(H)
drawnow ;          % ensure that button presses are recorded
r = ~ishandle(H) ; % false if message box still exists

function clearfun(H)
% clear the message box if it still exists
if ishandle(H),
    delete(H) ;
end


%DETECTMARKERS  Basic ArUco marker detection
%
%     [corners, ids] = cv.detectMarkers(img, dictionary)
%     [corners, ids, rejectedImgPoints] = cv.detectMarkers(img, dictionary)
%     [...] = cv.detectMarkers(..., 'OptionName',optionValue, ...)
%
% ## Input
% * __img__ input image (8-bit grayscale or color).
% * __dictionary__ indicates the type of markers that will be searched. You
%   can specify the dictionary as a cell-array that starts with the type name
%   followed by option arguments `{Type, ...}`. There are three types of
%   dictionaries available:
%   * __Predefined__ `{'Predefined', name}` or simply as a string `name`.
%     Returns one of the predefined dictionaries.
%   * __Custom__ `{'Custom', nMarkers, markerSize, 'BaseDictionary',baseDict}`.
%     Generates a new customizable marker dictionary. This creates a new
%     dictionary composed by `nMarkers` markers and each markers composed by
%     `markerSize*markerSize` bits. If `BaseDictionary` is provided, its
%     markers are directly included and the rest are generated based on them.
%     If the size of `baseDict` is higher than `nMarkers`, only the first
%     `nMarkers` in `baseDict` are taken and no new marker is added.
%   * __Manual__ `{'Manual', bytesList, markerSize, maxCorrectionBits}`.
%     Creates a dictionary/set of markers manually. It contains the inner
%     codification.
%
% ## Output
% * __corners__ cell array of detected marker corners. For each marker, its
%   four corners are provided `{{[x1,y1],[x2,y2],[x3,y3],[x4,y4]}, ..}`. The
%   order of the corners is clockwise.
% * __ids__ vector of identifiers of the detected markers. The identifier is
%   of integer type (0-based). For N detected markers, the size of ids is also
%   N. The identifiers have the same order than the markers in the `corners`
%   array.
% * __rejectedImgPoints__ contains the `corners` of those squares whose inner
%   code has not a correct codification. Useful for debugging purposes.
%
% ## Options
% * __DetectorParameters__ marker detection parameters. A struct of parameters
%   for the detection process, with the following fields:
%   * __adaptiveThreshWinSizeMin__ minimum window size for adaptive
%     thresholding before finding contours (default 3).
%   * __adaptiveThreshWinSizeMax__ maximum window size for adaptive
%     thresholding before finding contours (default 23).
%   * __adaptiveThreshWinSizeStep__ increments from `AdaptiveThreshWinSizeMin`
%     to `AdaptiveThreshWinSizeMax` during the thresholding (default 10).
%   * __adaptiveThreshConstant__ constant for adaptive thresholding before
%     finding contours (default 7)
%   * __minMarkerPerimeterRate__ determine minimum perimeter for marker
%     contour to be detected. This is defined as a rate respect to the maximum
%     dimension of the input image (default 0.03).
%   * __maxMarkerPerimeterRate__ determine maximum perimeter for marker
%     contour to be detected. This is defined as a rate respect to the maximum
%     dimension of the input image (default 4.0).
%   * __polygonalApproxAccuracyRate__ minimum accuracy during the polygonal
%     approximation process to determine which contours are squares
%     (default 0.03).
%   * __minCornerDistanceRate__ minimum distance between corners for detected
%     markers relative to its perimeter (default 0.05)
%   * __minDistanceToBorder__ minimum distance of any corner to the image
%     border for detected markers (in pixels) (default 3)
%   * __minMarkerDistanceRate__ minimum mean distance beetween two marker
%     corners to be considered similar, so that the smaller one is removed.
%     The rate is relative to the smaller perimeter of the two markers
%     (default 0.05).
%   * __cornerRefinementMethod__ corner refinement method, one of:
%     * __None__ (default) no refinement.
%     * __Subpix__ do subpixel refinement (cv.cornerSubPix).
%     * __Contour__ refine the corners using the contour-points.
%   * __cornerRefinementWinSize__ window size for the corner refinement
%     process (in pixels) (default 5).
%   * __cornerRefinementMaxIterations__ maximum number of iterations for stop
%     criteria of the corner refinement process (default 30).
%   * __cornerRefinementMinAccuracy__ minimum error for the stop cristeria of
%     the corner refinement process (default 0.1)
%   * __markerBorderBits__ number of bits of the marker border, i.e. marker
%     border width (default 1).
%   * __perpectiveRemovePixelPerCell__ number of bits (per dimension) for each
%     cell of the marker when removing the perspective (default 4).
%   * __perspectiveRemoveIgnoredMarginPerCell__ width of the margin of pixels
%     on each cell not considered for the determination of the cell bit.
%     Represents the rate respect to the total size of the cell, i.e.
%     `PerpectiveRemovePixelPerCell` (default 0.13)
%   * __maxErroneousBitsInBorderRate__ maximum number of accepted erroneous
%     bits in the border (i.e. number of allowed white bits in the border).
%     Represented as a rate respect to the total number of bits per marker
%     (default 0.35).
%   * __minOtsuStdDev__ minimun standard deviation in pixels values during the
%     decodification step to apply Otsu thresholding (otherwise, all the bits
%     are set to 0 or 1 depending on mean higher than 128 or not) (default 5.0)
%   * __errorCorrectionRate__ error correction rate respect to the maximum
%     error correction capability for each dictionary. (default 0.6).
% * __CameraMatrix__ Optional 3x3 camera calibration matrix
%   `A = [fx 0 cx; 0 fy cy; 0 0 1]`.
% * __DistCoeffs__ Optional vector of camera distortion coefficients
%   `[k1,k2,p1,p2,k3,k4,k5,k6,s1,s2,s3,s4]` of 4, 5, 8 or 12 elements.
%
% ## Inputs for Predefined Dictionary
% * __name__ name of predefined markers dictionaries/sets. Each dictionary
%   indicates the number of bits and the number of markers contained:
%   * `4x4_50`, `4x4_100`, `4x4_250`, `4x4_1000`: 4x4 bits with
%     (50|100|250|1000) markers.
%   * `5x5_50`, `5x5_100`, `5x5_250`, `5x5_1000`: 5x5 bits with
%     (50|100|250|1000) markers.
%   * `6x6_50`, `6x6_100`, `6x6_250`, `6x6_1000`: 6x6 bits with
%     (50|100|250|1000) markers.
%   * `7x7_50`, `7x7_100`, `7x7_250`, `7x7_1000`: 7x7 bits with
%     (50|100|250|1000) markers.
%   * `ArucoOriginal`: standard ArUco Library Markers. 1024 markers, 5x5 bits,
%     0 minimum distance.
%
% ## Inputs for Custom Dictionary
% * __nMarkers__ number of markers in the dictionary.
% * __markerSize__ number of bits per dimension of each markers.
% * __baseDict__ (Optional) include the markers in this dictionary at the
%   beginning. It is specified in the same format as the parent dictionary
%   (i.e. a cell-array `{Type, ...}`).
%
% ## Inputs for Manual Dictionary
% * __bytesList__ marker code information. Note that the `bytesList` is given
%   in the form of a matrix of bits which is then converted to list of bytes
%   in the 4 rotations using `Dictionary::getByteListFromBits`. It contains
%   the marker codewords where:
%   * the number of rows is the dictionary size
%   * each marker is encoded using `nbytes = ceil(markerSize*markerSize/8)`
%   * each row contains all 4 rotations of the marker, so its length is
%     `4*nbytes`
%   * `bytesList(i,k*nbytes+j)` is then the j-th byte of i-th marker, in its
%     k-th rotation.
% * __markerSize__ number of bits per dimension.
% * __maxCorrectionBits__ maximum number of bits that can be corrected.
%
% The cv.detectMarkers function performs marker detection in the input image.
% Only markers included in the specific dictionary are searched. For each
% detected marker, it returns the 2D position of its corner in the image and
% its corresponding identifier. Note that this function does not perform pose
% estimation.
%
% # ArUco Marker Detection
%
% This module is dedicated to square fiducial markers (also known as Augmented
% Reality Markers). These markers are useful for easy, fast and robust camera
% pose estimation.
%
% The main functionalities are:
%
% - Detection of markers in a image
% - Pose estimation from a single marker or from a board/set of markers
% - Detection of ChArUco board for high subpixel accuracy
% - Camera calibration from both, ArUco boards and ChArUco boards.
% - Detection of ChArUco diamond markers
%
% The implementation is based on the ArUco Library [2] by [1].
%
% This module has been originally developed by Sergio Garrido-Jurado as a
% project for Google Summer of Code 2015 (GSoC 15).
%
% ### ArUco
%
% ArUco markers are easy to detect pattern grids that yield up to 1024
% different patterns. They were built for augmented reality and later used for
% camera calibration. Since the grid uniquely orients the square, the
% detection algorithm can determing the pose of the grid.
%
% ### ChArUco
%
% ArUco markers were improved by interspersing them inside a checkerboard
% called ChArUco. Checkerboard corner intersectionsa provide more stable
% corners because the edge location bias on one square is countered by the
% opposite edge orientation in the connecting square. By interspersing ArUco
% markers inside the checkerboard, each checkerboard corner gets a label which
% enables it to be used in complex calibration or pose scenarios where you
% cannot see all the corners of the checkerboard.
%
% The smallest ChArUco board is 5 checkers and 4 markers called a
% "Diamond Marker".
%
% ## References
% [1]:
% > S. Garrido-Jurado, R. Munoz-Salinas, F. J. Madrid-Cuevas, and
% > M. J. Marin-Jimenez. 2014. "Automatic generation and detection of highly
% > reliable fiducial markers under occlusion". Pattern Recogn. 47, 6
% > (June 2014), 2280-2292. DOI=10.1016/j.patcog.2014.01.005
%
% [2]:
% > ArUco: a minimal library for Augmented Reality applications
% > based on OpenCV, [ArUco](http://www.uco.es/investiga/grupos/ava/node/26)
%
% See also: cv.estimatePoseSingleMarkers, cv.estimatePoseBoard,
%  cv.refineDetectedMarkers, cv.drawDetectedMarkers, cv.adaptiveThreshold,
%  cv.threshold, cv.findContours, cv.cornerSubPix
%


function [varargout]=coarsepatch(F,V,f)

% function [F,V,Eb]=coarsepatch(F,V,f)
%-------------------------------------------------------------------------
%
%
%
% Change log:
% 2019/06/25 Added variable output handling as well as outputting of
% boundary edges
%-------------------------------------------------------------------------
%%
% Run reducepatch
[F,V] = reducepatch(F,V,f,'fast');

%%
% Avoid/fix reducepatch bugs
[F,V]=mergeVertices(F,V); %Merge vertices
F=patchRemoveCollapsed(F); %remove collapsed (edges)
[F,V]=triSurfRemoveThreeConnect(F,V);
[F,V]=patchCleanUnused(F,V); %Remove unused points
F=uniqueIntegerRow(F); %Removing double faces

%%

varargout{1}=F;
varargout{2}=V;

if nargout==3
    %Also compute boundary
    varargout{3}=patchBoundary(F,V);
end

%%
% _*GIBBON footer text*_
%
% License: <https://github.com/gibbonCode/GIBBON/blob/master/LICENSE>
%
% GIBBON: The Geometry and Image-based Bioengineering add-On. A toolbox for
% image segmentation, image-based modeling, meshing, and finite element
% analysis.
%
% Copyright (C) 2006-2022 Kevin Mattheus Moerman and the GIBBON contributors
%
% This program is free software: you can redistribute it and/or modify
% it under the terms of the GNU General Public License as published by
% the Free Software Foundation, either version 3 of the License, or
% (at your option) any later version.
%
% This program is distributed in the hope that it will be useful,
% but WITHOUT ANY WARRANTY; without even the implied warranty of
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
% GNU General Public License for more details.
%
% You should have received a copy of the GNU General Public License
% along with this program.  If not, see <http://www.gnu.org/licenses/>.