├── .gitignore ├── Example.png ├── LICENSE ├── Overview.png ├── Primatte ├── Makefile ├── Primatte.pro ├── Primatte.pro.user ├── algorithmprimatte.cpp ├── algorithmprimatte.h ├── alphalocator.cpp ├── alphalocator.h ├── application.cpp ├── application.h ├── averagebackgroundcolourlocators.cpp ├── averagebackgroundcolourlocators.h ├── boundingpolyhedron.cpp ├── boundingpolyhedron.h ├── coloursegmenters.cpp ├── coloursegmenters.h ├── fittingalgorithms.cpp ├── fittingalgorithms.h ├── ialgorithm.h ├── ialphalocator.h ├── iaveragebackgroundcolourlocator.h ├── icoloursegmenter.h ├── ifittingalgorithm.h ├── inputassembler.cpp ├── inputassembler.h ├── io.cpp ├── io.h ├── main.cpp ├── matrixd.cpp ├── matrixd.h ├── spherepolyhedron.cpp └── spherepolyhedron.h └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | Primatte-build-* 2 | 3 | # Compiled Object files 4 | *.slo 5 | *.lo 6 | *.o 7 | *.obj 8 | 9 | # Precompiled Headers 10 | *.gch 11 | *.pch 12 | 13 | # Compiled Dynamic libraries 14 | *.so 15 | *.dylib 16 | *.dll 17 | 18 | # Fortran module files 19 | *.mod 20 | 21 | # Compiled Static libraries 22 | *.lai 23 | *.la 24 | *.a 25 | *.lib 26 | 27 | # Executables 28 | *.exe 29 | *.out 30 | *.app 31 | -------------------------------------------------------------------------------- /Example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DreamingInfraviolet/EstimateImageMatting/6a80089dfa9b956e9a5baaac66789b3af26adec9/Example.png -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Anima 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 | 23 | -------------------------------------------------------------------------------- /Overview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DreamingInfraviolet/EstimateImageMatting/6a80089dfa9b956e9a5baaac66789b3af26adec9/Overview.png -------------------------------------------------------------------------------- /Primatte/Makefile: -------------------------------------------------------------------------------- 1 | ############################################################################# 2 | # Makefile for building: Part2 3 | # Generated by qmake (2.01a) (Qt 4.8.1) on: Mon Aug 24 13:43:33 2015 4 | # Project: Primatte.pro 5 | # Template: app 6 | # Command: /usr/bin/qmake-qt4 -spec /usr/share/qt4/mkspecs/linux-g++ CONFIG+=debug CONFIG+=declarative_debug -o Makefile Primatte.pro 7 | ############################################################################# 8 | 9 | ####### Compiler, tools and options 10 | 11 | CC = gcc 12 | CXX = g++ 13 | DEFINES = -DQT_WEBKIT -DQT_XML_LIB -DQT_OPENGL_LIB -DQT_GUI_LIB -DQT_CORE_LIB -DQT_SHARED 14 | CFLAGS = -pipe -g -Wall -W -D_REENTRANT $(DEFINES) 15 | CXXFLAGS = -pipe -std=c++11 -Wall -g -Wall -W -D_REENTRANT $(DEFINES) 16 | INCPATH = -I/usr/share/qt4/mkspecs/linux-g++ -I. -I/usr/include/qt4/QtCore -I/usr/include/qt4/QtGui -I/usr/include/qt4/QtOpenGL -I/usr/include/qt4/QtXml -I/usr/include/qt4 -I/usr/include -I/usr/include/opencv -I/usr/X11R6/include -I. 17 | LINK = g++ 18 | LFLAGS = 19 | LIBS = $(SUBLIBS) -L/usr/lib/x86_64-linux-gnu -L/usr/X11R6/lib -L/usr/lib -lqglviewer-qt4 -lGLU -lopencv_core -lopencv_imgproc -lopencv_highgui -lopencv_ml -lopencv_video -lopencv_features2d -lopencv_calib3d -lopencv_objdetect -lopencv_contrib -lopencv_legacy -lopencv_flann -lQtXml -lQtOpenGL -lQtGui -lQtCore -lGL -lpthread 20 | AR = ar cqs 21 | RANLIB = 22 | QMAKE = /usr/bin/qmake-qt4 23 | TAR = tar -cf 24 | COMPRESS = gzip -9f 25 | COPY = cp -f 26 | SED = sed 27 | COPY_FILE = $(COPY) 28 | COPY_DIR = $(COPY) -r 29 | STRIP = strip 30 | INSTALL_FILE = install -m 644 -p 31 | INSTALL_DIR = $(COPY_DIR) 32 | INSTALL_PROGRAM = install -m 755 -p 33 | DEL_FILE = rm -f 34 | SYMLINK = ln -f -s 35 | DEL_DIR = rmdir 36 | MOVE = mv -f 37 | CHK_DIR_EXISTS= test -d 38 | MKDIR = mkdir -p 39 | 40 | ####### Output directory 41 | 42 | OBJECTS_DIR = ./ 43 | 44 | ####### Files 45 | 46 | SOURCES = main.cpp \ 47 | io.cpp \ 48 | application.cpp \ 49 | matrixd.cpp \ 50 | boundingpolyhedron.cpp \ 51 | coloursegmenters.cpp \ 52 | inputassembler.cpp \ 53 | algorithmprimatte.cpp \ 54 | alphalocator.cpp \ 55 | inputprocessing.cpp \ 56 | fittingalgorithms.cpp \ 57 | spherepolyhedron.cpp 58 | OBJECTS = main.o \ 59 | io.o \ 60 | application.o \ 61 | matrixd.o \ 62 | boundingpolyhedron.o \ 63 | coloursegmenters.o \ 64 | inputassembler.o \ 65 | algorithmprimatte.o \ 66 | alphalocator.o \ 67 | inputprocessing.o \ 68 | fittingalgorithms.o \ 69 | spherepolyhedron.o 70 | DIST = /usr/share/qt4/mkspecs/common/unix.conf \ 71 | /usr/share/qt4/mkspecs/common/linux.conf \ 72 | /usr/share/qt4/mkspecs/common/gcc-base.conf \ 73 | /usr/share/qt4/mkspecs/common/gcc-base-unix.conf \ 74 | /usr/share/qt4/mkspecs/common/g++-base.conf \ 75 | /usr/share/qt4/mkspecs/common/g++-unix.conf \ 76 | /usr/share/qt4/mkspecs/qconfig.pri \ 77 | /usr/share/qt4/mkspecs/modules/qt_webkit_version.pri \ 78 | /usr/share/qt4/mkspecs/features/qt_functions.prf \ 79 | /usr/share/qt4/mkspecs/features/qt_config.prf \ 80 | /usr/share/qt4/mkspecs/features/exclusive_builds.prf \ 81 | /usr/share/qt4/mkspecs/features/default_pre.prf \ 82 | /usr/share/qt4/mkspecs/features/debug.prf \ 83 | /usr/share/qt4/mkspecs/features/default_post.prf \ 84 | /usr/share/qt4/mkspecs/features/link_pkgconfig.prf \ 85 | /usr/share/qt4/mkspecs/features/declarative_debug.prf \ 86 | /usr/share/qt4/mkspecs/features/unix/gdb_dwarf_index.prf \ 87 | /usr/share/qt4/mkspecs/features/warn_on.prf \ 88 | /usr/share/qt4/mkspecs/features/qt.prf \ 89 | /usr/share/qt4/mkspecs/features/unix/opengl.prf \ 90 | /usr/share/qt4/mkspecs/features/unix/thread.prf \ 91 | /usr/share/qt4/mkspecs/features/moc.prf \ 92 | /usr/share/qt4/mkspecs/features/resources.prf \ 93 | /usr/share/qt4/mkspecs/features/uic.prf \ 94 | /usr/share/qt4/mkspecs/features/yacc.prf \ 95 | /usr/share/qt4/mkspecs/features/lex.prf \ 96 | /usr/share/qt4/mkspecs/features/include_source_dir.prf \ 97 | Primatte.pro 98 | QMAKE_TARGET = Part2 99 | DESTDIR = 100 | TARGET = Part2 101 | 102 | first: all 103 | ####### Implicit rules 104 | 105 | .SUFFIXES: .o .c .cpp .cc .cxx .C 106 | 107 | .cpp.o: 108 | $(CXX) -c $(CXXFLAGS) $(INCPATH) -o "$@" "$<" 109 | 110 | .cc.o: 111 | $(CXX) -c $(CXXFLAGS) $(INCPATH) -o "$@" "$<" 112 | 113 | .cxx.o: 114 | $(CXX) -c $(CXXFLAGS) $(INCPATH) -o "$@" "$<" 115 | 116 | .C.o: 117 | $(CXX) -c $(CXXFLAGS) $(INCPATH) -o "$@" "$<" 118 | 119 | .c.o: 120 | $(CC) -c $(CFLAGS) $(INCPATH) -o "$@" "$<" 121 | 122 | ####### Build rules 123 | 124 | all: Makefile $(TARGET) 125 | 126 | $(TARGET): $(OBJECTS) 127 | $(LINK) $(LFLAGS) -o $(TARGET) $(OBJECTS) $(OBJCOMP) $(LIBS) 128 | { test -n "$(DESTDIR)" && DESTDIR="$(DESTDIR)" || DESTDIR=.; } && test $$(gdb --version | sed -e 's,[^0-9]\+\([0-9]\)\.\([0-9]\).*,\1\2,;q') -gt 72 && gdb --nx --batch --quiet -ex 'set confirm off' -ex "save gdb-index $$DESTDIR" -ex quit '$(TARGET)' && test -f $(TARGET).gdb-index && objcopy --add-section '.gdb_index=$(TARGET).gdb-index' --set-section-flags '.gdb_index=readonly' '$(TARGET)' '$(TARGET)' && rm -f $(TARGET).gdb-index || true 129 | 130 | Makefile: Primatte.pro /usr/share/qt4/mkspecs/linux-g++/qmake.conf /usr/share/qt4/mkspecs/common/unix.conf \ 131 | /usr/share/qt4/mkspecs/common/linux.conf \ 132 | /usr/share/qt4/mkspecs/common/gcc-base.conf \ 133 | /usr/share/qt4/mkspecs/common/gcc-base-unix.conf \ 134 | /usr/share/qt4/mkspecs/common/g++-base.conf \ 135 | /usr/share/qt4/mkspecs/common/g++-unix.conf \ 136 | /usr/share/qt4/mkspecs/qconfig.pri \ 137 | /usr/share/qt4/mkspecs/modules/qt_webkit_version.pri \ 138 | /usr/share/qt4/mkspecs/features/qt_functions.prf \ 139 | /usr/share/qt4/mkspecs/features/qt_config.prf \ 140 | /usr/share/qt4/mkspecs/features/exclusive_builds.prf \ 141 | /usr/share/qt4/mkspecs/features/default_pre.prf \ 142 | /usr/share/qt4/mkspecs/features/debug.prf \ 143 | /usr/share/qt4/mkspecs/features/default_post.prf \ 144 | /usr/share/qt4/mkspecs/features/link_pkgconfig.prf \ 145 | /usr/share/qt4/mkspecs/features/declarative_debug.prf \ 146 | /usr/share/qt4/mkspecs/features/unix/gdb_dwarf_index.prf \ 147 | /usr/share/qt4/mkspecs/features/warn_on.prf \ 148 | /usr/share/qt4/mkspecs/features/qt.prf \ 149 | /usr/share/qt4/mkspecs/features/unix/opengl.prf \ 150 | /usr/share/qt4/mkspecs/features/unix/thread.prf \ 151 | /usr/share/qt4/mkspecs/features/moc.prf \ 152 | /usr/share/qt4/mkspecs/features/resources.prf \ 153 | /usr/share/qt4/mkspecs/features/uic.prf \ 154 | /usr/share/qt4/mkspecs/features/yacc.prf \ 155 | /usr/share/qt4/mkspecs/features/lex.prf \ 156 | /usr/share/qt4/mkspecs/features/include_source_dir.prf \ 157 | /usr/lib/x86_64-linux-gnu/libqglviewer-qt4.prl \ 158 | /usr/lib/x86_64-linux-gnu/libQtXml.prl \ 159 | /usr/lib/x86_64-linux-gnu/libQtOpenGL.prl \ 160 | /usr/lib/x86_64-linux-gnu/libQtGui.prl \ 161 | /usr/lib/x86_64-linux-gnu/libQtCore.prl 162 | $(QMAKE) -spec /usr/share/qt4/mkspecs/linux-g++ CONFIG+=debug CONFIG+=declarative_debug -o Makefile Primatte.pro 163 | /usr/share/qt4/mkspecs/common/unix.conf: 164 | /usr/share/qt4/mkspecs/common/linux.conf: 165 | /usr/share/qt4/mkspecs/common/gcc-base.conf: 166 | /usr/share/qt4/mkspecs/common/gcc-base-unix.conf: 167 | /usr/share/qt4/mkspecs/common/g++-base.conf: 168 | /usr/share/qt4/mkspecs/common/g++-unix.conf: 169 | /usr/share/qt4/mkspecs/qconfig.pri: 170 | /usr/share/qt4/mkspecs/modules/qt_webkit_version.pri: 171 | /usr/share/qt4/mkspecs/features/qt_functions.prf: 172 | /usr/share/qt4/mkspecs/features/qt_config.prf: 173 | /usr/share/qt4/mkspecs/features/exclusive_builds.prf: 174 | /usr/share/qt4/mkspecs/features/default_pre.prf: 175 | /usr/share/qt4/mkspecs/features/debug.prf: 176 | /usr/share/qt4/mkspecs/features/default_post.prf: 177 | /usr/share/qt4/mkspecs/features/link_pkgconfig.prf: 178 | /usr/share/qt4/mkspecs/features/declarative_debug.prf: 179 | /usr/share/qt4/mkspecs/features/unix/gdb_dwarf_index.prf: 180 | /usr/share/qt4/mkspecs/features/warn_on.prf: 181 | /usr/share/qt4/mkspecs/features/qt.prf: 182 | /usr/share/qt4/mkspecs/features/unix/opengl.prf: 183 | /usr/share/qt4/mkspecs/features/unix/thread.prf: 184 | /usr/share/qt4/mkspecs/features/moc.prf: 185 | /usr/share/qt4/mkspecs/features/resources.prf: 186 | /usr/share/qt4/mkspecs/features/uic.prf: 187 | /usr/share/qt4/mkspecs/features/yacc.prf: 188 | /usr/share/qt4/mkspecs/features/lex.prf: 189 | /usr/share/qt4/mkspecs/features/include_source_dir.prf: 190 | /usr/lib/x86_64-linux-gnu/libqglviewer-qt4.prl: 191 | /usr/lib/x86_64-linux-gnu/libQtXml.prl: 192 | /usr/lib/x86_64-linux-gnu/libQtOpenGL.prl: 193 | /usr/lib/x86_64-linux-gnu/libQtGui.prl: 194 | /usr/lib/x86_64-linux-gnu/libQtCore.prl: 195 | qmake: FORCE 196 | @$(QMAKE) -spec /usr/share/qt4/mkspecs/linux-g++ CONFIG+=debug CONFIG+=declarative_debug -o Makefile Primatte.pro 197 | 198 | dist: 199 | @$(CHK_DIR_EXISTS) .tmp/Part21.0.0 || $(MKDIR) .tmp/Part21.0.0 200 | $(COPY_FILE) --parents $(SOURCES) $(DIST) .tmp/Part21.0.0/ && $(COPY_FILE) --parents io.h application.h matrixd.h boundingpolyhedron.h icoloursegmenter.h ifittingalgorithm.h coloursegmenters.h inputassembler.h IAlgorithm.h algorithmprimatte.h ialphalocator.h alphalocator.h inputprocessing.h fittingalgorithms.h spherepolyhedron.h .tmp/Part21.0.0/ && $(COPY_FILE) --parents main.cpp io.cpp application.cpp matrixd.cpp boundingpolyhedron.cpp coloursegmenters.cpp inputassembler.cpp algorithmprimatte.cpp alphalocator.cpp inputprocessing.cpp fittingalgorithms.cpp spherepolyhedron.cpp .tmp/Part21.0.0/ && (cd `dirname .tmp/Part21.0.0` && $(TAR) Part21.0.0.tar Part21.0.0 && $(COMPRESS) Part21.0.0.tar) && $(MOVE) `dirname .tmp/Part21.0.0`/Part21.0.0.tar.gz . && $(DEL_FILE) -r .tmp/Part21.0.0 201 | 202 | 203 | clean:compiler_clean 204 | -$(DEL_FILE) $(OBJECTS) 205 | -$(DEL_FILE) *~ core *.core 206 | 207 | 208 | ####### Sub-libraries 209 | 210 | distclean: clean 211 | -$(DEL_FILE) $(TARGET) 212 | -$(DEL_FILE) Makefile 213 | 214 | 215 | check: first 216 | 217 | mocclean: compiler_moc_header_clean compiler_moc_source_clean 218 | 219 | mocables: compiler_moc_header_make_all compiler_moc_source_make_all 220 | 221 | compiler_moc_header_make_all: 222 | compiler_moc_header_clean: 223 | compiler_rcc_make_all: 224 | compiler_rcc_clean: 225 | compiler_image_collection_make_all: qmake_image_collection.cpp 226 | compiler_image_collection_clean: 227 | -$(DEL_FILE) qmake_image_collection.cpp 228 | compiler_moc_source_make_all: 229 | compiler_moc_source_clean: 230 | compiler_uic_make_all: 231 | compiler_uic_clean: 232 | compiler_yacc_decl_make_all: 233 | compiler_yacc_decl_clean: 234 | compiler_yacc_impl_make_all: 235 | compiler_yacc_impl_clean: 236 | compiler_lex_make_all: 237 | compiler_lex_clean: 238 | compiler_clean: 239 | 240 | ####### Compile 241 | 242 | main.o: main.cpp application.h \ 243 | inputassembler.h \ 244 | inputprocessing.h \ 245 | matrixd.h 246 | $(CXX) -c $(CXXFLAGS) $(INCPATH) -o main.o main.cpp 247 | 248 | io.o: io.cpp io.h 249 | $(CXX) -c $(CXXFLAGS) $(INCPATH) -o io.o io.cpp 250 | 251 | application.o: application.cpp application.h \ 252 | inputassembler.h \ 253 | inputprocessing.h \ 254 | matrixd.h \ 255 | fittingalgorithms.h \ 256 | ifittingalgorithm.h \ 257 | spherepolyhedron.h \ 258 | io.h \ 259 | coloursegmenters.h \ 260 | icoloursegmenter.h \ 261 | boundingpolyhedron.h \ 262 | alphalocator.h \ 263 | ialphalocator.h \ 264 | algorithmprimatte.h \ 265 | IAlgorithm.h 266 | $(CXX) -c $(CXXFLAGS) $(INCPATH) -o application.o application.cpp 267 | 268 | matrixd.o: matrixd.cpp matrixd.h 269 | $(CXX) -c $(CXXFLAGS) $(INCPATH) -o matrixd.o matrixd.cpp 270 | 271 | boundingpolyhedron.o: boundingpolyhedron.cpp boundingpolyhedron.h \ 272 | matrixd.h \ 273 | ifittingalgorithm.h \ 274 | spherepolyhedron.h \ 275 | application.h \ 276 | inputassembler.h \ 277 | inputprocessing.h \ 278 | io.h 279 | $(CXX) -c $(CXXFLAGS) $(INCPATH) -o boundingpolyhedron.o boundingpolyhedron.cpp 280 | 281 | coloursegmenters.o: coloursegmenters.cpp coloursegmenters.h \ 282 | icoloursegmenter.h \ 283 | matrixd.h 284 | $(CXX) -c $(CXXFLAGS) $(INCPATH) -o coloursegmenters.o coloursegmenters.cpp 285 | 286 | inputassembler.o: inputassembler.cpp inputassembler.h \ 287 | inputprocessing.h \ 288 | matrixd.h \ 289 | io.h 290 | $(CXX) -c $(CXXFLAGS) $(INCPATH) -o inputassembler.o inputassembler.cpp 291 | 292 | algorithmprimatte.o: algorithmprimatte.cpp algorithmprimatte.h \ 293 | IAlgorithm.h \ 294 | inputassembler.h \ 295 | inputprocessing.h \ 296 | matrixd.h \ 297 | boundingpolyhedron.h \ 298 | ifittingalgorithm.h \ 299 | spherepolyhedron.h \ 300 | application.h \ 301 | ialphalocator.h \ 302 | icoloursegmenter.h 303 | $(CXX) -c $(CXXFLAGS) $(INCPATH) -o algorithmprimatte.o algorithmprimatte.cpp 304 | 305 | alphalocator.o: alphalocator.cpp alphalocator.h \ 306 | ialphalocator.h \ 307 | boundingpolyhedron.h \ 308 | matrixd.h \ 309 | ifittingalgorithm.h \ 310 | spherepolyhedron.h \ 311 | application.h \ 312 | inputassembler.h \ 313 | inputprocessing.h \ 314 | io.h 315 | $(CXX) -c $(CXXFLAGS) $(INCPATH) -o alphalocator.o alphalocator.cpp 316 | 317 | inputprocessing.o: inputprocessing.cpp inputprocessing.h \ 318 | matrixd.h \ 319 | io.h 320 | $(CXX) -c $(CXXFLAGS) $(INCPATH) -o inputprocessing.o inputprocessing.cpp 321 | 322 | fittingalgorithms.o: fittingalgorithms.cpp fittingalgorithms.h \ 323 | ifittingalgorithm.h \ 324 | spherepolyhedron.h \ 325 | matrixd.h \ 326 | application.h \ 327 | inputassembler.h \ 328 | inputprocessing.h \ 329 | io.h 330 | $(CXX) -c $(CXXFLAGS) $(INCPATH) -o fittingalgorithms.o fittingalgorithms.cpp 331 | 332 | spherepolyhedron.o: spherepolyhedron.cpp spherepolyhedron.h \ 333 | matrixd.h \ 334 | application.h \ 335 | inputassembler.h \ 336 | inputprocessing.h \ 337 | io.h 338 | $(CXX) -c $(CXXFLAGS) $(INCPATH) -o spherepolyhedron.o spherepolyhedron.cpp 339 | 340 | ####### Install 341 | 342 | install: FORCE 343 | 344 | uninstall: FORCE 345 | 346 | FORCE: 347 | 348 | -------------------------------------------------------------------------------- /Primatte/Primatte.pro: -------------------------------------------------------------------------------- 1 | TEMPLATE = app 2 | CONFIG += console 3 | QT += opengl xml glviewer 4 | 5 | QT_CONFIG -= no-pkg-config 6 | CONFIG += link_pkgconfig 7 | PKGCONFIG += opencv 8 | 9 | QMAKE_CXXFLAGS += -std=c++0x -Wall 10 | INCLUDEPATH += /usr/include 11 | LIBS += -L/usr/lib 12 | LIBS += -lqglviewer-qt4 -lGLU 13 | 14 | greaterThan(QT_MAJOR_VERSION, 4): QT += widgets 15 | 16 | TARGET = Part2 17 | TEMPLATE = app 18 | 19 | 20 | SOURCES += main.cpp \ 21 | io.cpp \ 22 | application.cpp \ 23 | matrixd.cpp \ 24 | boundingpolyhedron.cpp \ 25 | coloursegmenters.cpp \ 26 | inputassembler.cpp \ 27 | algorithmprimatte.cpp \ 28 | alphalocator.cpp \ 29 | fittingalgorithms.cpp \ 30 | spherepolyhedron.cpp \ 31 | averagebackgroundcolourlocators.cpp 32 | 33 | HEADERS += \ 34 | io.h \ 35 | application.h \ 36 | matrixd.h \ 37 | icoloursegmenter.h \ 38 | ifittingalgorithm.h \ 39 | coloursegmenters.h \ 40 | inputassembler.h \ 41 | algorithmprimatte.h \ 42 | ialphalocator.h \ 43 | alphalocator.h \ 44 | fittingalgorithms.h \ 45 | spherepolyhedron.h \ 46 | boundingpolyhedron.h \ 47 | ialgorithm.h \ 48 | averagebackgroundcolourlocators.h \ 49 | iaveragebackgroundcolourlocator.h 50 | 51 | 52 | -------------------------------------------------------------------------------- /Primatte/Primatte.pro.user: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | ProjectExplorer.Project.ActiveTarget 7 | 0 8 | 9 | 10 | ProjectExplorer.Project.EditorSettings 11 | 12 | true 13 | false 14 | 15 | Cpp 16 | 17 | CppGlobal 18 | 19 | 20 | 21 | QmlJS 22 | 23 | QmlJSGlobal 24 | 25 | 26 | 2 27 | System 28 | false 29 | 4 30 | true 31 | 1 32 | true 33 | 0 34 | true 35 | 0 36 | 8 37 | true 38 | 1 39 | true 40 | true 41 | true 42 | false 43 | 44 | 45 | 46 | ProjectExplorer.Project.PluginSettings 47 | 48 | 49 | 50 | ProjectExplorer.Project.Target.0 51 | 52 | Desktop 53 | Desktop 54 | Qt4ProjectManager.Target.DesktopTarget 55 | 1 56 | 0 57 | 0 58 | 59 | ProjectExplorer.ToolChain.Gcc:/usr/bin/g++.x86-linux-generic-elf-64bit./usr/bin/gdb 60 | 61 | 62 | qmake 63 | 64 | QtProjectManager.QMakeBuildStep 65 | false 66 | true 67 | 68 | false 69 | 70 | 71 | Make 72 | 73 | Qt4ProjectManager.MakeStep 74 | false 75 | 76 | 77 | 78 | 2 79 | Build 80 | 81 | ProjectExplorer.BuildSteps.Build 82 | 83 | 84 | 85 | Make 86 | 87 | Qt4ProjectManager.MakeStep 88 | true 89 | clean 90 | 91 | 92 | 1 93 | Clean 94 | 95 | ProjectExplorer.BuildSteps.Clean 96 | 97 | 2 98 | false 99 | 100 | Qt 4.8.1 in PATH (System) Release 101 | 102 | Qt4ProjectManager.Qt4BuildConfiguration 103 | 0 104 | /lhome/vsereda/Linux/Primatte/Primatte-build-desktop-Qt_4_8_1_in_PATH__System__Release 105 | 1 106 | true 107 | 108 | 109 | ProjectExplorer.ToolChain.Gcc:/usr/bin/g++.x86-linux-generic-elf-64bit./usr/bin/gdb 110 | 111 | 112 | qmake 113 | 114 | QtProjectManager.QMakeBuildStep 115 | false 116 | true 117 | 118 | false 119 | 120 | 121 | Make 122 | 123 | Qt4ProjectManager.MakeStep 124 | false 125 | 126 | 127 | 128 | 2 129 | Build 130 | 131 | ProjectExplorer.BuildSteps.Build 132 | 133 | 134 | 135 | Make 136 | 137 | Qt4ProjectManager.MakeStep 138 | true 139 | clean 140 | 141 | 142 | 1 143 | Clean 144 | 145 | ProjectExplorer.BuildSteps.Clean 146 | 147 | 2 148 | false 149 | 150 | Qt 4.8.1 in PATH (System) Debug 151 | 152 | Qt4ProjectManager.Qt4BuildConfiguration 153 | 2 154 | /lhome/vsereda/Linux/Primatte/Primatte-build-desktop-Qt_4_8_1_in_PATH__System__Debug 155 | 1 156 | true 157 | 158 | 2 159 | 160 | 161 | 0 162 | Deploy 163 | 164 | ProjectExplorer.BuildSteps.Deploy 165 | 166 | 1 167 | No deployment 168 | 169 | ProjectExplorer.DefaultDeployConfiguration 170 | 171 | 1 172 | 173 | true 174 | true 175 | 176 | 177 | false 178 | false 179 | false 180 | false 181 | false 182 | false 183 | false 184 | false 185 | true 186 | true 187 | 0.01 188 | 0.01 189 | 10 190 | 10 191 | true 192 | true 193 | 25 194 | 25 195 | 196 | 197 | true 198 | true 199 | valgrind 200 | valgrind 201 | 202 | 0 203 | 1 204 | 2 205 | 3 206 | 4 207 | 5 208 | 6 209 | 7 210 | 8 211 | 9 212 | 10 213 | 11 214 | 12 215 | 13 216 | 14 217 | 218 | 219 | 0 220 | 1 221 | 2 222 | 3 223 | 4 224 | 5 225 | 6 226 | 7 227 | 8 228 | 9 229 | 10 230 | 11 231 | 12 232 | 13 233 | 14 234 | 235 | Primatte 236 | 237 | Qt4ProjectManager.Qt4RunConfiguration 238 | 2 239 | 240 | Primatte.pro 241 | false 242 | true 243 | 244 | 245 | 3768 246 | true 247 | false 248 | false 249 | 250 | 1 251 | 252 | 253 | 254 | ProjectExplorer.Project.TargetCount 255 | 1 256 | 257 | 258 | ProjectExplorer.Project.Updater.EnvironmentId 259 | {2527a1f2-1af4-40d9-a3dc-20297efa4de9} 260 | 261 | 262 | ProjectExplorer.Project.Updater.FileVersion 263 | 10 264 | 265 | 266 | -------------------------------------------------------------------------------- /Primatte/algorithmprimatte.cpp: -------------------------------------------------------------------------------- 1 | #include "algorithmprimatte.h" 2 | #include "ialphalocator.h" 3 | #include "icoloursegmenter.h" 4 | #include "ifittingalgorithm.h" 5 | #include "inputassembler.h" 6 | #include 7 | #include "io.h" 8 | 9 | 10 | namespace anima 11 | { 12 | namespace alg 13 | { 14 | namespace primatte 15 | { 16 | AlgorithmPrimatte::AlgorithmPrimatte(AlgorithmPrimatteDesc desc) 17 | : mAnalysed(false) 18 | { 19 | //Validate desc 20 | if(!desc.segmenter) 21 | throw std::runtime_error("Null segmenter"); 22 | 23 | if(!desc.alphaLocator) 24 | throw std::runtime_error("Null alpha locator"); 25 | 26 | if(desc.innerPostShrinkingMultiplier < 0 || 27 | desc.innerShrinkingMinDistance < 0 || 28 | desc.innerShrinkingThreshold < 0 || 29 | desc.outerExpandDelta < 0 || 30 | desc.outerExpansionStartThreshold < 0 || 31 | desc.outerScaleParameter <0) 32 | throw std::runtime_error("Algorithm parameter out of range"); 33 | 34 | //Try constructing a bounding polyhedron to validate its descriptor 35 | BoundingPolyhedron(desc.boundingPolyhedronDesc); 36 | 37 | //Set desc 38 | mDesc = desc; 39 | } 40 | 41 | void AlgorithmPrimatte::analyse() 42 | { 43 | if(!mInput) 44 | throw std::runtime_error("Using algorithm with null input."); 45 | 46 | //Set up unit polyhedron 47 | BoundingPolyhedron unitPoly (mDesc.boundingPolyhedronDesc); 48 | mPolys[POLY_INNER] = unitPoly; 49 | mPolys[POLY_OUTER] = unitPoly; 50 | 51 | //Fit inner polyhedron around the background points 52 | mPolys[POLY_INNER].fitter()->shrink( 53 | mPolys[POLY_INNER], 54 | mDesc.segmenter->segment( 55 | mInput->backgroundPoints(), 56 | mInput->background(), 57 | mDesc.innerShrinkingThreshold).inner, 58 | mInput->background(), 59 | mDesc.innerShrinkingMinDistance); 60 | 61 | //Scale the inner polyhedron 62 | mPolys[POLY_INNER] = mPolys[POLY_INNER]*mDesc.innerPostShrinkingMultiplier; 63 | 64 | //Ensure that it is greater than the inner polyhedron 65 | float innerPolyhedronMaxSize = mPolys[POLY_INNER].findLargestRadius(); 66 | float startRadius = std::max(innerPolyhedronMaxSize, mDesc.outerExpansionStartThreshold); 67 | 68 | //Expand the sphere from the starting radius towards startingRadius+expandDelta 69 | mPolys[POLY_OUTER].fitter()->expand(mPolys[POLY_OUTER], 70 | mInput->points(), 71 | mDesc.segmenter, 72 | mInput->background(), 73 | startRadius, 74 | startRadius+mDesc.outerExpandDelta); 75 | 76 | 77 | //Scale outer if wanted 78 | float maxInnerRadius = mPolys[POLY_INNER].findLargestRadius(); 79 | float scale = mPolys[POLY_OUTER].radius() + 80 | (maxInnerRadius-mPolys[POLY_OUTER].radius())* 81 | (1.f-mDesc.outerScaleParameter); 82 | mPolys[POLY_OUTER] = mPolys[POLY_OUTER]*(scale/mPolys[POLY_OUTER].radius()); 83 | 84 | mAnalysed = true; 85 | } 86 | 87 | cv::Mat AlgorithmPrimatte::computeAlphas() const 88 | { 89 | if(!mAnalysed) 90 | throw std::runtime_error("Trying to compute alphas with algorithm before input analysis."); 91 | return mDesc.alphaLocator->findAlphas(mPolys, POLY_COUNT, *mInput); 92 | } 93 | 94 | void AlgorithmPrimatte::debugDraw() const 95 | { 96 | for(int i = 0; i < POLY_COUNT; ++i) 97 | mPolys[i].debugDraw(math::vec3((float)((i+2)%4==0), (float)((i+2)%3==0), 0.f)); 98 | } 99 | } 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /Primatte/algorithmprimatte.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "ialgorithm.h" 3 | #include "boundingpolyhedron.h" 4 | #include "inputassembler.h" 5 | 6 | /** This class implements an algorithm inspired by primatte. 7 | Its main purpose is to combine all the other algorithms in the 8 | primatte namespace and provide a single interface. 9 | In it's current form, it's potentially a little unstable as I did not have the time 10 | (or the images) to test it fully. But it seems to work! */ 11 | namespace anima 12 | { 13 | //Forward declaration. 14 | namespace ia 15 | { 16 | class InputAssembler; 17 | } 18 | 19 | namespace alg 20 | { 21 | namespace primatte 22 | { 23 | //Forward declaration. 24 | class IFittingAlgorithm; 25 | class IColourSegmenter; 26 | class IAlphaLocator; 27 | 28 | /** The algorithm descriptor to use when creating the algorithm. 29 | You must fill this in entirely and pass it to the constructor. */ 30 | struct AlgorithmPrimatteDesc 31 | { 32 | //The following specify sub-algorithms to be used. 33 | 34 | /* The algorithm to use to group clusters of points together. */ 35 | IColourSegmenter* segmenter; 36 | 37 | /* The locator used for alpha generation. */ 38 | IAlphaLocator* alphaLocator; 39 | 40 | /* The bounding polyhedron descriptor. */ 41 | BoundingPolyhedronDescriptor boundingPolyhedronDesc; 42 | 43 | //The following values specify the parameters used by the algorithm. 44 | 45 | //The parameter passed to the colour segmenter when segmenting the background 46 | //points for the inner polyhedron. The segmenter splits the points into Inner 47 | //and Outer, and the Inner points are wrapped around. Should be the approximate 48 | //radius of the sphere inside which the points should be marked as Inner, 49 | //but may be different if you use your own segmenter. 50 | float innerShrinkingThreshold; 51 | 52 | //The minimum size of the inner polyhedron after shrinking. 53 | //Values that are too low may yield in parts of the background being visible. 54 | float innerShrinkingMinDistance; 55 | 56 | //After shrinking, the inner polyhedron is scaled by this amount. 57 | float innerPostShrinkingMultiplier; 58 | 59 | //The foreground pixels are then segmented based on this parameter, 60 | //And the outer polyhedron is positioned around them before expansion. 61 | float outerExpansionStartThreshold; 62 | 63 | //The approximate amount the outer sphere should try to expand. 64 | float outerExpandDelta; 65 | 66 | //The amount the outer sphere should be scaled after expansion relative to 67 | //the inner sphere. It is made so that it never collides with the inner polyhedron, 68 | //such that a value of 0 = as close as possible to inner. A value of 1 = minimal scaling. 69 | //Note that it is relative to the final size of the inner polyhedron. 70 | float outerScaleParameter; 71 | 72 | }; 73 | 74 | /** The primatte-inspired algorithm. */ 75 | class AlgorithmPrimatte : public IAlgorithm 76 | { 77 | /* The internal sphere ennumerations. 78 | * Warning: Must be in inner->outer order. 79 | * When improving the algorithm, one may wish to use more spheres. */ 80 | enum PolyId {POLY_INNER, POLY_OUTER, POLY_COUNT}; 81 | 82 | /* The polyhedron objects in inner->outer order. */ 83 | BoundingPolyhedron mPolys[POLY_COUNT]; 84 | 85 | /* The algorithm descriptor. */ 86 | AlgorithmPrimatteDesc mDesc; 87 | 88 | bool mAnalysed; 89 | 90 | public: 91 | 92 | /** Initialises the class, throwing an exception upon failure 93 | * (most commonly std::runtime_error) */ 94 | AlgorithmPrimatte(AlgorithmPrimatteDesc desc); 95 | 96 | /** Prepares alpha computation for the given data set by analysing the input. */ 97 | virtual void analyse(); 98 | 99 | /** Computes the alphas for the given set of points in relation to the 100 | * previously supplied inputs. */ 101 | virtual cv::Mat computeAlphas() const; 102 | 103 | /** Uses OpenGL to draw a representation of the internal polyhedrons. */ 104 | virtual void debugDraw() const; 105 | }; 106 | } 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /Primatte/alphalocator.cpp: -------------------------------------------------------------------------------- 1 | #include "alphalocator.h" 2 | #include "io.h" 3 | #include "matrixd.h" 4 | 5 | using namespace anima::alg; 6 | 7 | 8 | 9 | namespace anima 10 | { 11 | namespace alg 12 | { 13 | namespace primatte 14 | { 15 | cv::Mat AlphaRayLocator::findAlphas( 16 | const BoundingPolyhedron* polyhedrons, 17 | const size_t polyhedronCount, 18 | const ia::InputAssembler& input) const 19 | { 20 | assert(polyhedronCount>1); 21 | START_TIMER(AlphaLocator); 22 | 23 | const cv::Mat& mat = input.mat(); 24 | const unsigned r = input.mat().rows, c = input.mat().cols; 25 | const math::vec3 background = input.background(); 26 | 27 | cv::Mat out; 28 | out.create(r, c, CV_32FC1); 29 | 30 | const SpherePolyhedron& outerPoly = polyhedrons[1]; 31 | const SpherePolyhedron& innerPoly = polyhedrons[0]; 32 | 33 | //For each point, send rays 34 | for (unsigned i = 0; i < r; ++i) 35 | { 36 | float* data = (float*)(mat.data + mat.step*i); 37 | float* dataOut = (float*)(out.data + out.step*i); 38 | for(unsigned j = 0; j < c; ++j) 39 | { 40 | math::vec3& point = *((math::vec3*)(data + j*3)); 41 | float alpha; 42 | 43 | //If right in the middle 44 | if(background==point) 45 | alpha = 0; 46 | else 47 | { 48 | //Prepare vector 49 | const math::vec3 vector = point - background; 50 | const float vectorLen = vector.length(); 51 | const math::vec3 vectorNorm = vector/vectorLen; 52 | const float distanceToPoint = point.distance(background); 53 | 54 | const float distanceToOuterPoly = outerPoly.findDistanceToPolyhedron(vectorNorm); 55 | 56 | //If inside outer poly, alpha < 1 57 | if(distanceToPoint < distanceToOuterPoly) 58 | { 59 | float distanceToInnerPoly = innerPoly.findDistanceToPolyhedron(vectorNorm); 60 | 61 | //If does not intersect with inner, fully inside 62 | if(distanceToPoint < distanceToInnerPoly) 63 | alpha = 0; 64 | else //interpolate between inner and outer 65 | alpha = (vectorLen - distanceToInnerPoly) / 66 | (distanceToOuterPoly - distanceToInnerPoly); 67 | 68 | } 69 | else //If intersects with middle, it's outside. Alpha = 1. 70 | alpha = 1; 71 | } 72 | 73 | *(dataOut+j) = alpha; 74 | } 75 | } 76 | 77 | END_TIMER(AlphaLocator); 78 | 79 | return out; 80 | } 81 | } 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /Primatte/alphalocator.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "ialphalocator.h" 3 | 4 | namespace anima 5 | { 6 | namespace alg 7 | { 8 | namespace primatte 9 | { 10 | /** Sends out rays to determine the alpha, interpolating between the two 11 | * spheres. It is done so that: 12 | * If outside outer sphere, alpha = 1 13 | * If inside inner sphere, alpha = 0 14 | * If in the middle, interpolate. 15 | * It expects that the bounding polyhedrons are sorted in 16 | * increasing order so that any ray sent is guaranteed that the inner 17 | * intersection is closer than the outer. 18 | * This particular algorithm requires at least two polyhedrons. 19 | * */ 20 | class AlphaRayLocator : public IAlphaLocator 21 | { 22 | public: 23 | virtual cv::Mat findAlphas( 24 | const BoundingPolyhedron* polyhedrons, 25 | const size_t polyhedronCount, 26 | const ia::InputAssembler &input) const; 27 | }; 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Primatte/application.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "application.h" 4 | #include "matrixd.h" 5 | #include "algorithmprimatte.h" 6 | #include "fittingalgorithms.h" 7 | #include "averagebackgroundcolourlocators.h" 8 | #include "coloursegmenters.h" 9 | #include "alphalocator.h" 10 | #include "io.h" 11 | 12 | 13 | Application::Application() : 14 | mInputAssembler(nullptr), 15 | mAlgorithm(nullptr), 16 | mFitter(nullptr), 17 | mSegmenter(nullptr), 18 | mAlphaLocator(nullptr), 19 | mBackgroundLocator(nullptr) {} 20 | 21 | Application::~Application() 22 | { 23 | delete mBackgroundLocator; 24 | delete mAlphaLocator; 25 | delete mSegmenter; 26 | delete mFitter; 27 | delete mAlgorithm; 28 | delete mInputAssembler; 29 | } 30 | 31 | void Application::timerEvent(QTimerEvent*) 32 | { 33 | update(); 34 | } 35 | 36 | void Application::init() 37 | { 38 | try 39 | { 40 | using namespace anima::ia; 41 | using namespace anima::alg::primatte; 42 | 43 | //Restore QGLPreviewer state from last run, such as camera position, etc. 44 | restoreStateFromFile(); 45 | 46 | //A scene radius of 1 has some clipping. 47 | this->setSceneRadius(1.5); 48 | 49 | //This makes things difficult to see and interferes with the pixel colours. 50 | glDisable(GL_LIGHTING); 51 | 52 | //Set fps (update every n milliseconds). 16.66... ~ 60fps 53 | mBasicTimer.start(16.66666666, this); 54 | 55 | 56 | Inform("Processing input"); 57 | 58 | cv::Mat imageMat = cv::imread("test.jpg"); 59 | cv::Mat backgroundMat = cv::imread("test_background.jpg"); 60 | if(imageMat.data==nullptr || backgroundMat.data == nullptr) 61 | throw std::runtime_error("Could not load images"); 62 | 63 | 64 | START_TIMER(WholeProgramTimer); 65 | 66 | //////////////////////////////////////////////////////////////////////////// 67 | ////////////////////////////// Input Stage ///////////////////////////////// 68 | //////////////////////////////////////////////////////////////////////////// 69 | 70 | /* Locates the dominant background colour from the input background image mat. */ 71 | mBackgroundLocator = new anima::ia::ABCL_BarycentreBased(); 72 | 73 | //This descriptor is used to initialise the input assembler. 74 | InputAssemblerDescriptor iaDesc; 75 | 76 | //Set the background colour locator 77 | iaDesc.backgroundLocator = mBackgroundLocator; 78 | 79 | //Set the image source to be copied from. 80 | //The source mat is converted into floating point values. 81 | //8-bit, 16-bit and floating point formats are supported. 82 | //Expects a 3-component image. 83 | iaDesc.foregroundSource = &imageMat; 84 | 85 | //The background image. 86 | iaDesc.backgroundSource = &backgroundMat; 87 | 88 | //The 3D grid segment count to use for cleaning up duplicate input 89 | //points. Lower values require less memory and filter more aggressively. 90 | iaDesc.ipd.gridSize = 400; 91 | 92 | //The target colour space to convert to. 93 | //Currently can either be RGB, HSV or LAB. 94 | //HSV is unsuitable for blue due to wrap-around! 95 | iaDesc.targetColourspace = InputAssemblerDescriptor::ETCS_RGB; 96 | 97 | //Remove % of points randomly after cleanup to speed up computation. 98 | iaDesc.ipd.randomSimplify = false; 99 | iaDesc.ipd.randomSimplifyPercentage = 30.0; 100 | 101 | //Create the assembler object, load, and process the input. 102 | //An exception will be thrown in case of an error, most likely 103 | //a std::runtime_error. 104 | mInputAssembler = new InputAssembler(iaDesc); 105 | 106 | //////////////////////////////////////////////////////////////////////////// 107 | //////////////////////////// Algorithm Stage /////////////////////////////// 108 | //////////////////////////////////////////////////////////////////////////// 109 | Inform("Creating primatte algorithm"); 110 | 111 | //Choose your algorithms: 112 | 113 | /* The fitting algorithm to use. The input is the number of binary iterations 114 | to perform, akin to a binary search algorithm iteration. 115 | 2 is a good number, as it's both accurate and doesn't fit TOO closely, which 116 | can lead to errors due to the sample points being simplified. */ 117 | mFitter = new StableFitting(2); 118 | 119 | /* The segmenter algorithm to use. It splits the data points in two based on the parameters. 120 | The distance segmenter splits the input based on whether a point is inside/outside a sphere. */ 121 | mSegmenter = new DistanceColourSegmenter(); 122 | 123 | /* The alpha interpolation algorithm to use. It is used to compute the alpha for each pixel. */ 124 | mAlphaLocator = new AlphaRayLocator(); 125 | 126 | //Fill in the algorithm descriptor. 127 | AlgorithmPrimatteDesc algDesc; 128 | 129 | //The fitter algorithm to use. 130 | algDesc.boundingPolyhedronDesc.fitter = mFitter; 131 | 132 | //The number of phi and theta faces for the generated sphere. 133 | //Optimally, there is a ration of 2:1. 16*8 is a 128-faced sphere. 134 | algDesc.boundingPolyhedronDesc.phiFaces = 16; 135 | algDesc.boundingPolyhedronDesc.thetaFaces = 8; 136 | 137 | //The sphere is multiplied by this amount after creation to ensure no 138 | //accidental intersection with the points due to low mesh resolution. 139 | algDesc.boundingPolyhedronDesc.scaleMultiplier = 1.2f; 140 | 141 | //The segmenter splits the points into outer and inner points. 142 | algDesc.segmenter = mSegmenter; 143 | 144 | //The alpha locator is responsible for interpolating and generating the alpha. 145 | algDesc.alphaLocator = mAlphaLocator; 146 | 147 | //The parameter passed to the colour segmenter. 148 | //The inner background points returned are wrapped around. 149 | algDesc.innerShrinkingThreshold = 0.6f; 150 | 151 | //The distance of a shrunken inner vertex from the centre. 152 | algDesc.innerShrinkingMinDistance = 0.001f; 153 | 154 | //After shrinking the inner polyhedron is multiplied by this amount. 155 | algDesc.innerPostShrinkingMultiplier = 1.1f; 156 | 157 | //Passed to the segmenter when positioning outer sphere around inner points before expanding. 158 | //Essentially the start radius of the outer sphere. 159 | algDesc.outerExpansionStartThreshold = 0.15f; 160 | 161 | //The approximate amount the outer sphere should try to expand. 162 | algDesc.outerExpandDelta = 0.075f; 163 | 164 | //The amount the outer sphere should be scaled after expansion relative to 165 | //the inner sphere. It is made so that it never collides with the inner polyhedron, 166 | //such that a value of 0 = as close as possible to inner. A value of 1 = minimal scaling. 167 | //Note that it is relative to the final size of the inner polyhedron. 168 | algDesc.outerScaleParameter = 1.f; 169 | 170 | mAlgorithm = new AlgorithmPrimatte(algDesc); 171 | 172 | Inform("Analysing input"); 173 | //Set the new input to be used. 174 | mAlgorithm->setInput(mInputAssembler); 175 | 176 | //Analyse the input. This is a performance-intensive operation. 177 | //In primatte this corresponds to polyhedron deformation. 178 | mAlgorithm->analyse(); 179 | 180 | 181 | //////////////////////////////////////////////////////////////////////////// 182 | ///////////////////////// Get and preview result /////////////////////////// 183 | //////////////////////////////////////////////////////////////////////////// 184 | 185 | 186 | Inform("Applying results"); 187 | //Apply the polyhedrae to the input image, and save the alpha to result. 188 | cv::Mat result = mAlgorithm->computeAlphas(); 189 | 190 | END_TIMER(WholeProgramTimer); 191 | 192 | //Note: This is not part of the algorithm. It's just to preview the result. 193 | 194 | //Display the alpha image 195 | cv::namedWindow("Alpha", cv::WINDOW_AUTOSIZE); 196 | cv::imshow("Alpha", result); 197 | 198 | //Apply the alpha to the original image in order to preview it. 199 | cv::Mat af = imageMat.clone(); 200 | 201 | //The background colour to blend with in BGR format. 202 | cv::Vec3f backgroundBlendColour(0,0,1); 203 | cv::Vec3f backgroundInImage(mInputAssembler->background().x, 204 | mInputAssembler->background().y, 205 | mInputAssembler->background().z); 206 | 207 | for(int r = 0; r < af.rows; ++r) 208 | for(int c = 0; c < af.cols; ++c) 209 | { 210 | cv::Vec3b& original = af.at(r,c); 211 | float alpha = result.at(r,c); 212 | cv::Vec3f originalf = original; 213 | originalf *= 1/255.f; 214 | 215 | //Cancel out original background colour from guessed alpha 216 | cv::Vec3f foreground = (originalf - backgroundInImage*(1 - alpha))*(alpha); 217 | 218 | original = (foreground*alpha + backgroundBlendColour*(1.f-alpha))*255; 219 | } 220 | 221 | cv::namedWindow( "AF", cv::WINDOW_AUTOSIZE ); 222 | cv::imshow( "AF", af ); 223 | } 224 | catch(std::runtime_error err) 225 | { 226 | //If a known error has occured: 227 | Error(err.what()); 228 | this->hide(); 229 | this->close(); 230 | } 231 | catch(...) 232 | { 233 | //If an unknown exception happened: 234 | Error("Something happened"); 235 | this->hide(); 236 | this->close(); 237 | } 238 | } 239 | 240 | ////////////////////////////////////////////////////////////////////////////// 241 | /////////////////Below this, it's just for 3D previewing. //////////////////// 242 | ////////////////////////////////////////////////////////////////////////////// 243 | 244 | /** This function takes in a normalised colour in linear colourspace and 245 | calls glColour3f with its gamma-corrected version. */ 246 | void glColor3fSRGB(float x, float y, float z) 247 | { 248 | glColor3f(pow(x,2.2f),pow(y,2.2f),pow(z,2.2f)); 249 | } 250 | 251 | void Application::draw() 252 | { 253 | if(this->isHidden()) 254 | return; 255 | 256 | drawBackground(); 257 | 258 | //Draw points 259 | glPointSize(5.0); 260 | glLineWidth(2); 261 | glBegin(GL_POINTS); 262 | 263 | //Background points 264 | for(auto it = mInputAssembler->backgroundPoints().begin(); it!=mInputAssembler->backgroundPoints().end(); ++it) 265 | { 266 | glColor3f(1,0,0); 267 | glVertex3f(it->x, it->y, it->z); 268 | } 269 | 270 | //Foreground points 271 | for(auto it = mInputAssembler->points().begin(); it!=mInputAssembler->points().end(); ++it) 272 | { 273 | auto c = mInputAssembler->debugGetPointColour(*it); 274 | 275 | //Swap components because the internal image is in BGR 276 | glColor3fSRGB(c.x,c.y,c.z); 277 | 278 | glVertex3f(it->x, it->y, it->z); 279 | } 280 | glEnd(); 281 | 282 | //Draw background point 283 | if(mInputAssembler) 284 | { 285 | glColor3fSRGB(1,0,0); 286 | glPointSize(10.0); 287 | glBegin(GL_POINTS); 288 | auto b = mInputAssembler->background(); 289 | glVertex3f(b.x,b.y,b.z); 290 | glEnd(); 291 | } 292 | 293 | //Draw algorithm 294 | glPolygonMode( GL_FRONT_AND_BACK, GL_LINE ); 295 | if(mAlgorithm) 296 | mAlgorithm->debugDraw(); 297 | glPolygonMode( GL_FRONT_AND_BACK, GL_FILL ); 298 | 299 | glPointSize(5.0); 300 | } 301 | 302 | void Application::drawBackground() 303 | { 304 | float c1r = 0.95, c1g = 0.95, c1b = 0.95; 305 | float c2r = 0.4, c2g = 0.6, c2b = 0.4; 306 | 307 | //Push 308 | glMatrixMode(GL_PROJECTION); 309 | glPushMatrix(); 310 | glLoadIdentity(); 311 | glMatrixMode(GL_MODELVIEW); 312 | glPushMatrix(); 313 | glLoadIdentity(); 314 | 315 | //Draw 316 | glBegin(GL_QUADS); 317 | //c1 318 | glColor3fSRGB(c1r,c1g,c1b); 319 | glVertex2f(1.0, 1.0); 320 | glVertex2f(-1.0,1.0); 321 | //c2 322 | glColor3fSRGB(c2r,c2g,c2b); 323 | glVertex2f(-1.0,-1.0); 324 | glVertex2f(1.0, -1.0); 325 | glEnd(); 326 | 327 | //Pop 328 | glPopMatrix(); 329 | glMatrixMode(GL_MODELVIEW); 330 | glPopMatrix(); 331 | glMatrixMode(GL_PROJECTION); 332 | glPopMatrix(); 333 | glClear(GL_DEPTH_BUFFER_BIT); 334 | } 335 | 336 | QString Application::helpString() const 337 | { 338 | QString text("

S i m p l e V i e w e r

"); 339 | text += "Use the mouse to move the camera around the object. "; 340 | text += "You can respectively revolve around, zoom and translate with the three mouse buttons. "; 341 | text += "Left and middle buttons pressed together rotate around the camera view direction axis

"; 342 | text += "Pressing Alt and one of the function keys (F1..F12) defines a camera keyFrame. "; 343 | text += "Simply press the function key again to restore it. Several keyFrames define a "; 344 | text += "camera path. Paths are saved when you quit the application and restored at next start.

"; 345 | text += "Press F to display the frame rate, A for the world axis, "; 346 | text += "Alt+Return for full screen mode and Control+S to save a snapshot. "; 347 | text += "See the Keyboard tab in this window for a complete shortcut list.

"; 348 | text += "Double clicks automates single click actions: A left button double click aligns the closer axis with the camera (if close enough). "; 349 | text += "A middle button double click fits the zoom of the camera and the right button re-centers the scene.

"; 350 | text += "A left button double click while holding right button pressed defines the camera Revolve Around Point. "; 351 | text += "See the Mouse tab and the documentation web pages for details.

"; 352 | text += "Press Escape to exit the Application."; 353 | return text; 354 | } 355 | -------------------------------------------------------------------------------- /Primatte/application.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | 5 | //Forward declarations 6 | namespace anima 7 | { 8 | namespace alg 9 | { 10 | class IAlgorithm; 11 | 12 | namespace primatte 13 | { 14 | class IColourSegmenter; 15 | class IFittingAlgorithm; 16 | class IAlphaLocator; 17 | } 18 | } 19 | namespace ia 20 | { 21 | class InputAssembler; 22 | class IAverageBackgroundColourLocator; 23 | } 24 | } 25 | 26 | /** The main application class. It is to be replaced in the future by a proper 27 | * driver. Currently it reads the input from a file called "test.bmp" and 28 | * supplies it to the algorithm, which in itself is a general system. 29 | */ 30 | class Application: public QGLViewer 31 | { 32 | public: 33 | /** Initialises variables to null. */ 34 | Application(); 35 | 36 | /** Deletes internal pointers. */ 37 | ~Application(); 38 | 39 | /** Draws a preview of the scene. */ 40 | virtual void draw(); 41 | 42 | /** Draws the background plane. Used by draw(). */ 43 | void drawBackground(); 44 | 45 | /** Gathers input and runs the algorithm. */ 46 | virtual void init(); 47 | 48 | /** Used by qglviewer to provide a help string during preview. */ 49 | virtual QString helpString() const; 50 | 51 | /* The input data structure. */ 52 | anima::ia::InputAssembler* mInputAssembler; 53 | 54 | /* The currently used algorithm (only primatte available). */ 55 | anima::alg::IAlgorithm* mAlgorithm; 56 | 57 | //Subalgorithms: 58 | 59 | /* The fitting algorithm to use. */ 60 | anima::alg::primatte::IFittingAlgorithm* mFitter; 61 | 62 | /* The segmenter algorithm to use. */ 63 | anima::alg::primatte::IColourSegmenter* mSegmenter; 64 | 65 | /* The alpha interpolation algorithm to use. */ 66 | anima::alg::primatte::IAlphaLocator* mAlphaLocator; 67 | 68 | /* Finds the dominant background colour. */ 69 | anima::ia::IAverageBackgroundColourLocator* mBackgroundLocator; 70 | 71 | /* Handles debug preview fps. */ 72 | QBasicTimer mBasicTimer; 73 | 74 | /** Called on every timer tick: updates the frame. */ 75 | void timerEvent(QTimerEvent*); 76 | 77 | }; 78 | -------------------------------------------------------------------------------- /Primatte/averagebackgroundcolourlocators.cpp: -------------------------------------------------------------------------------- 1 | #include "averagebackgroundcolourlocators.h" 2 | #include "io.h" 3 | 4 | namespace anima 5 | { 6 | namespace ia 7 | { 8 | math::vec3 ABCL_BarycentreBased::findColour(const cv::Mat& mat) const 9 | { 10 | int r = mat.rows, c = mat.cols, s = mat.step; 11 | 12 | math::vec3 background; 13 | 14 | for (int i = 0; i < r; ++i) 15 | { 16 | float* data = (float*)(mat.data + s*i); 17 | 18 | for(int j = 0; j < c; ++j) 19 | { 20 | math::vec3& v = *((math::vec3*)(data + j*3)); 21 | background+=v; 22 | } 23 | } 24 | 25 | background/=r*c; 26 | return background; 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Primatte/averagebackgroundcolourlocators.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "iaveragebackgroundcolourlocator.h" 3 | 4 | namespace anima 5 | { 6 | namespace ia 7 | { 8 | /** Chooses the average background colour as the barycentre of all points. */ 9 | class ABCL_BarycentreBased : public IAverageBackgroundColourLocator 10 | { 11 | public: 12 | virtual math::vec3 findColour(const cv::Mat& mat) const; 13 | 14 | }; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Primatte/boundingpolyhedron.cpp: -------------------------------------------------------------------------------- 1 | #include "boundingpolyhedron.h" 2 | #include "io.h" 3 | #include "stdlib.h" 4 | #include 5 | #include 6 | #include "ifittingalgorithm.h" 7 | 8 | namespace anima 9 | { 10 | namespace alg 11 | { 12 | namespace primatte 13 | { 14 | BoundingPolyhedron::BoundingPolyhedron(BoundingPolyhedronDescriptor desc) 15 | : SpherePolyhedron(desc.phiFaces, desc.thetaFaces) 16 | { 17 | if(desc.fitter==nullptr) 18 | throw std::runtime_error("Null fitter"); 19 | 20 | if(desc.scaleMultiplier < 0) 21 | throw std::runtime_error("Negative bounding polyhedron scale multiplier"); 22 | 23 | mDesc = desc; 24 | 25 | mInitialised = true; 26 | } 27 | 28 | //Adapted from http://stackoverflow.com/a/24818473 29 | std::pair calculateBoundSphere(const std::vector& vertices) 30 | { 31 | math::vec3 center = vertices[0]; 32 | float radius = 0.0001f; 33 | float len, alpha, alphaSq; 34 | 35 | for (int i = 0; i < 2; i++) 36 | { 37 | for (auto it = vertices.begin(); it != vertices.end(); it++) 38 | { 39 | math::vec3 pos = *it; 40 | math::vec3 diff = pos - center; 41 | len = diff.length(); 42 | if (len > radius) 43 | { 44 | alpha = len / radius; 45 | alphaSq = alpha * alpha; 46 | radius = 0.5f * (alpha + 1 / alpha) * radius; 47 | center =(center * (1 + 1 / alphaSq)+ pos*(1 - 1 / alphaSq)) * 0.5f; 48 | } 49 | } 50 | } 51 | 52 | for (auto it = vertices.begin(); it != vertices.end(); it++) 53 | { 54 | math::vec3 diff = *it - center; 55 | len = diff.length(); 56 | if (len > radius) 57 | { 58 | radius = (radius + len) / 2.0f; 59 | center = center + diff * ((len - radius) / len); 60 | } 61 | } 62 | 63 | return std::make_pair(center, radius); 64 | } 65 | 66 | 67 | void BoundingPolyhedron::positionAround(const math::vec3 desiredCentre, const std::vector& points) 68 | { 69 | if(!mInitialised) 70 | throw::std::runtime_error("Using uninitialised bounding polyhedron"); 71 | 72 | if(points.size()==0) 73 | return; 74 | 75 | auto bounding = calculateBoundSphere(points); 76 | 77 | float radius = (bounding.second + desiredCentre.distance(bounding.first))*mDesc.scaleMultiplier; 78 | setCentreAndRadius(desiredCentre, radius); 79 | } 80 | 81 | BoundingPolyhedron BoundingPolyhedron::operator * (const float scale) 82 | { 83 | BoundingPolyhedron out = *this; 84 | for(auto it = out.mVertices.begin(); it!=out.mVertices.end(); ++it) 85 | *it = (*it-mCentre)*scale+mCentre; 86 | out.mRadius *= scale; 87 | return out; 88 | } 89 | 90 | } 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /Primatte/boundingpolyhedron.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "matrixd.h" 3 | #include "spherepolyhedron.h" 4 | 5 | /** A polyhedron object that's capable of wrapping itself around a set of points. */ 6 | namespace anima 7 | { 8 | namespace alg 9 | { 10 | namespace primatte 11 | { 12 | class IFittingAlgorithm; 13 | 14 | /** The descriptor used to create the polyhedron. */ 15 | struct BoundingPolyhedronDescriptor 16 | { 17 | /* Number of faces around the up axis to have. Must be > 3 */ 18 | int phiFaces; 19 | 20 | /* The number of horizontal faces to have. Must be > 2 */ 21 | int thetaFaces; 22 | 23 | /* The polyhedron is scaled by this factor after being positioned. Must be positive. */ 24 | float scaleMultiplier; 25 | 26 | /* The fitting algorithm to use to fit the polyhedron around the points. */ 27 | IFittingAlgorithm* fitter; 28 | }; 29 | 30 | class BoundingPolyhedron : public SpherePolyhedron 31 | { 32 | private: 33 | /* The descriptor object. */ 34 | BoundingPolyhedronDescriptor mDesc; 35 | 36 | /* Indicates whether the polyhedron is initialised. 37 | * Only initialised polyhedrons may be used after creation. */ 38 | bool mInitialised; 39 | 40 | public: 41 | /** Constructs an uninitialised object. */ 42 | BoundingPolyhedron() : mInitialised(false) {} 43 | 44 | /** Constructs the object from the descriptor. */ 45 | BoundingPolyhedron(BoundingPolyhedronDescriptor desc); 46 | 47 | /** Positions the polyhedral sphere around the points, 48 | * only using linear transformations. 49 | * @param points The points around which to position the 50 | polyhedron. 51 | */ 52 | void positionAround(const math::vec3 desiredCentre, const std::vector& points); 53 | 54 | IFittingAlgorithm* fitter() { return mDesc.fitter; } 55 | 56 | /** Returns a copy of the polyhedron scaled around the centre */ 57 | BoundingPolyhedron operator * (const float scale); 58 | }; 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /Primatte/coloursegmenters.cpp: -------------------------------------------------------------------------------- 1 | #include "coloursegmenters.h" 2 | #include "io.h" 3 | namespace anima 4 | { 5 | namespace alg 6 | { 7 | namespace primatte 8 | { 9 | SegmenterResult DistanceColourSegmenter::segment(const std::vector &points, 10 | const math::vec3 reference, 11 | float approximateRadius) const 12 | { 13 | SegmenterResult out; 14 | 15 | float radiusSquared = approximateRadius*approximateRadius; 16 | 17 | for(auto it = points.begin(); it!=points.end(); ++it) 18 | { 19 | if(reference.distanceSquared(*it) <= radiusSquared) 20 | out.inner.push_back(*it); 21 | else 22 | out.outer.push_back(*it); 23 | } 24 | return out; 25 | } 26 | 27 | 28 | // std::pair,std::vector > 29 | // DistanceColourSegmenter::segment(const std::vector& points, 30 | // const math::vec3 background, 31 | // float approximateRadius) const 32 | // { 33 | // std::vector outer, inner; 34 | 35 | // float radiusSquared = approximateRadius*approximateRadius; 36 | 37 | // for(auto it = points.begin(); it!=points.end(); ++it) 38 | // { 39 | // if(background.distanceSquared(*it) <= radiusSquared) 40 | // inner.push_back(*it); 41 | // else 42 | // outer.push_back(*it); 43 | // } 44 | // return std::make_pair(outer, inner); 45 | // } 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /Primatte/coloursegmenters.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "icoloursegmenter.h" 3 | 4 | /* A series of classes implementing the IColourSegmenter interface. */ 5 | 6 | namespace anima 7 | { 8 | namespace alg 9 | { 10 | namespace primatte 11 | { 12 | /** This class segments colours according to distance, 13 | * cutting off the points that are too far away. */ 14 | class DistanceColourSegmenter : public IColourSegmenter 15 | { 16 | public: 17 | virtual SegmenterResult segment(const std::vector& points, 18 | const math::vec3 reference, 19 | float approximateRadius) const; 20 | }; 21 | 22 | // class DistanceColourSegmenter : public IColourSegmenter 23 | // { 24 | // virtual std::pair,std::vector > 25 | // segment(const std::vector& points, 26 | // const math::vec3 background, 27 | // float approximateRadius) const; 28 | // }; 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /Primatte/fittingalgorithms.cpp: -------------------------------------------------------------------------------- 1 | #include "fittingalgorithms.h" 2 | #include "io.h" 3 | #include "icoloursegmenter.h" 4 | 5 | namespace anima 6 | { 7 | namespace alg 8 | { 9 | namespace primatte 10 | { 11 | unsigned StableFitting::countPointsInside(const std::vector& points, BoundingPolyhedron& poly) 12 | { 13 | int pointsInside = 0; 14 | for(auto itPoint = points.begin(); itPoint != points.end(); ++itPoint) 15 | { 16 | //If intersects 17 | math::vec3 vector = *itPoint - poly.centre(); 18 | float vectorLen = vector.length(); 19 | math::vec3 vectorNorm = vector/vectorLen; 20 | 21 | if(poly.findDistanceToPolyhedron(vectorNorm) >= vectorLen) 22 | ++pointsInside; 23 | } 24 | return pointsInside; 25 | } 26 | 27 | void StableFitting::shrink(BoundingPolyhedron& poly, 28 | const std::vector& points, 29 | math::vec3 backgroundPoint, 30 | float minimumDistance) const 31 | { 32 | START_TIMER(Shrinking); 33 | 34 | poly.positionAround(backgroundPoint, points); 35 | 36 | float step = poly.radius()/2.f; 37 | 38 | float minDistanceSquared = minimumDistance*minimumDistance; 39 | 40 | int originalPointsInside = countPointsInside(points, poly); 41 | 42 | for(int iIteration = 0; iIteration < mNoOfIterations; ++iIteration) 43 | { 44 | float stepSquared = step*step; 45 | 46 | for(auto vertex = poly.mVertices.rbegin(); vertex!=poly.mVertices.rend(); ++vertex) 47 | { 48 | //If too close, or move distance too great 49 | const float distanceCentreToVertex = poly.centre().distanceSquared(*vertex); 50 | if(distanceCentreToVertex < minDistanceSquared || distanceCentreToVertex < stepSquared) 51 | continue; 52 | 53 | math::vec3 moveNormal = (poly.centre() - *vertex).normalize(); 54 | const math::vec3 vec = moveNormal*step; 55 | 56 | //Move 57 | *vertex += vec; 58 | 59 | int newPointsInside = countPointsInside(points, poly); 60 | 61 | //Move back if movement violates rule 62 | if(newPointsInside& points, IColourSegmenter* segmenter, 74 | math::vec3 backgroundPoint, float startRadius, float endRadius) const 75 | { 76 | 77 | START_TIMER(Expanding); 78 | 79 | auto innerouter = segmenter->segment(points, backgroundPoint, startRadius); 80 | 81 | //Indicates whether a vertex was unable to move at least once due to outer points. 82 | std::vector didVertexEncounterResistance; 83 | didVertexEncounterResistance.resize(poly.mVertices.size(), false); 84 | 85 | //Position the polygon around the inner points. 86 | poly.positionAround(backgroundPoint, innerouter.inner); 87 | 88 | //Make a copy that is to be scaled. 89 | //We need a copy to deal with the case where no resistance is met. 90 | BoundingPolyhedron newPoly = poly; 91 | 92 | //The starting step is set to be half way between the start and end distance. 93 | float step = (endRadius-startRadius)/2.f; 94 | 95 | //Count number of points outside for later reference. 96 | int originalPointsOutside = innerouter.outer.size()-countPointsInside(innerouter.outer, newPoly); 97 | 98 | //Iterate... 99 | for(int iIteration = 0; iIteration < mNoOfIterations; ++iIteration) 100 | { 101 | //Try moving each vertex outwards 102 | for(size_t iVertex = 0; iVertex < newPoly.mVertices.size(); ++iVertex) 103 | { 104 | //Find movement vector 105 | math::vec3 moveNormal = (newPoly.mVertices[iVertex]-newPoly.centre()).normalize(); 106 | const math::vec3 vec = moveNormal*step; 107 | 108 | //Move 109 | newPoly.mVertices[iVertex] += vec; 110 | 111 | //Find the number of points now outside after movement. 112 | int newPointsOutside = innerouter.outer.size()-countPointsInside(innerouter.outer, newPoly); 113 | 114 | //If there are now less points outside, we have gone through something. Move back and mark resistance. 115 | if(newPointsOutside < originalPointsOutside) 116 | { 117 | newPoly.mVertices[iVertex] -= vec; 118 | didVertexEncounterResistance[iVertex] = true; 119 | } 120 | } 121 | 122 | //halve the step and try again. 123 | step *= 0.5f; 124 | } 125 | 126 | //The idea here is that if a vertex did not encounter any resistance while moving, 127 | //Move it by the maximin movement of the vertices that _did_ encounter resistance. 128 | 129 | //You might try replacing maximum with mode, etc. (mean gave really low deltas) 130 | 131 | //Find max movement of vertices that found resistance: 132 | float maxMovement = poly.mVertices[0].distance(newPoly.mVertices[0]); 133 | for(size_t i = 1; i < didVertexEncounterResistance.size(); ++i) 134 | maxMovement = std::max(maxMovement, 135 | poly.mVertices[i].distance(newPoly.mVertices[i])); 136 | 137 | 138 | 139 | //If a vertex found resistance, keep it. Otherwise, restore it and move by the average. 140 | for(size_t i = 0; i < didVertexEncounterResistance.size(); ++i) 141 | if(didVertexEncounterResistance[i]) 142 | poly.mVertices[i] = newPoly.mVertices[i]; 143 | else 144 | poly.mVertices[i] = poly.mVertices[i]+(newPoly.mVertices[i]-poly.mVertices[i]).normalize()*maxMovement; 145 | 146 | END_TIMER(Expanding); 147 | } 148 | } 149 | } 150 | } 151 | -------------------------------------------------------------------------------- /Primatte/fittingalgorithms.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "ifittingalgorithm.h" 3 | 4 | /* 5 | * Various polyhedron fitting algorithms implementing the IFittingAlgorithm interface. 6 | */ 7 | namespace anima 8 | { 9 | namespace alg 10 | { 11 | namespace primatte 12 | { 13 | /** Use exact fitting by trying to move points inside/outside while possible. 14 | Points are guaranteed to not go through the polyhedron. 15 | An alternative to try out might be to allow for a certain number of points to be ignored, 16 | reducing outlier effect. */ 17 | class StableFitting : public IFittingAlgorithm 18 | { 19 | //Number of iterations to perform. 20 | int mNoOfIterations; 21 | 22 | /** Counts the number of points from the points vector that are inside the bounding polyhedron. */ 23 | static unsigned countPointsInside(const std::vector& points, BoundingPolyhedron& poly); 24 | 25 | public: 26 | 27 | StableFitting(int numberOfIterations) : mNoOfIterations(numberOfIterations){} 28 | 29 | virtual void shrink(BoundingPolyhedron& poly, const std::vector& points, math::vec3 backgroundPoint, float minimumDistance) const; 30 | virtual void expand(BoundingPolyhedron& poly, const std::vector& points, IColourSegmenter* segmenter, math::vec3 backgroundPoint, float startingRadius, float maximumRadius) const; 31 | }; //End of class 32 | 33 | /** Does nothing */ 34 | class NoFitting : public IFittingAlgorithm 35 | { 36 | public: 37 | virtual void shrink(BoundingPolyhedron&, const std::vector&, math::vec3, float) const {} 38 | virtual void expand(BoundingPolyhedron&, const std::vector&, IColourSegmenter*, math::vec3, float, float) const {} 39 | }; //End of class 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /Primatte/ialgorithm.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include "inputassembler.h" 5 | 6 | namespace anima 7 | { 8 | namespace alg 9 | { 10 | /** An abstract class that defines the basic functionality required by an algorithm. 11 | * Deviates towards an abstract class by implementing basic functionality for convenience. */ 12 | class IAlgorithm 13 | { 14 | protected: 15 | 16 | const ia::InputAssembler* mInput; 17 | public: 18 | 19 | /** Trivial virtual destructor */ 20 | virtual ~IAlgorithm() {} 21 | 22 | /** Sets the current input. */ 23 | virtual void setInput(const ia::InputAssembler* input) 24 | { 25 | mInput = input; 26 | } 27 | 28 | /** Prepares alpha computation for the given data set. Needed for debug draw. 29 | * Example activity might be collapsing polyhedrons around the input points. 30 | Must set mPrepared=when done. */ 31 | virtual void analyse() = 0; 32 | 33 | /** Computes the alpha for the internal input.*/ 34 | virtual cv::Mat computeAlphas() const = 0; 35 | 36 | /** Draws a 3D representation of the algorithm. */ 37 | virtual void debugDraw() const = 0; 38 | }; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /Primatte/ialphalocator.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "boundingpolyhedron.h" 3 | #include 4 | #include 5 | #include "inputassembler.h" 6 | 7 | /** 8 | * Given n polyhedrons, a background centre point and a list of points, 9 | * return a vector of alphas corresponding to the list of points 10 | * in relation to the background point. 11 | */ 12 | 13 | namespace anima 14 | { 15 | namespace alg 16 | { 17 | namespace primatte 18 | { 19 | class IAlphaLocator 20 | { 21 | public: 22 | 23 | virtual ~IAlphaLocator(){} 24 | 25 | /** Calculates the alpha for a set of points. 26 | * @param polyhedrons The polyhedrons usd by primatte 27 | ordered from inner to outer. 28 | * @param polyhedronCount The number of polyhedrons. 29 | * @param input The initialised input structure. 30 | */ 31 | virtual cv::Mat findAlphas( 32 | const BoundingPolyhedron* polyhedrons, 33 | const size_t polyhedronCount, 34 | const ia::InputAssembler &input) const = 0; 35 | }; 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Primatte/iaveragebackgroundcolourlocator.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include "matrixd.h" 4 | /** Given an F32 mat of background colours, this class must calculate 5 | * the most dominant colour and return it. 6 | */ 7 | 8 | namespace anima 9 | { 10 | namespace ia 11 | { 12 | class IAverageBackgroundColourLocator 13 | { 14 | public: 15 | virtual ~IAverageBackgroundColourLocator(){} 16 | virtual math::vec3 findColour(const cv::Mat& mat) const = 0; 17 | }; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /Primatte/icoloursegmenter.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "matrixd.h" 3 | #include 4 | /** 5 | * Given a vector of points, this class must return a subset of those points. 6 | * based on their distance from a background point. 7 | * It essentially choose the points against which the polyhedrons must be fitted. 8 | */ 9 | 10 | namespace anima 11 | { 12 | namespace alg 13 | { 14 | namespace primatte 15 | { 16 | struct SegmenterResult 17 | { 18 | //The points chosen to be outside. 19 | std::vector outer; 20 | 21 | //The points chosen to be inside. 22 | std::vector inner; 23 | 24 | //The union of these two constitutes the input points to the segmenter. 25 | }; 26 | 27 | 28 | class IColourSegmenter 29 | { 30 | public: 31 | 32 | virtual ~IColourSegmenter(){} 33 | 34 | /** Computes the subset. 35 | * @param points The points the subset of which is to be found. 36 | * @param background The point around which to find the subset. 37 | * @param approximateRadius Loosely-defined cut-off point. 38 | */ 39 | virtual SegmenterResult segment(const std::vector& points, 40 | const math::vec3 background, 41 | float approximateRadius) const = 0; 42 | }; 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /Primatte/ifittingalgorithm.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "boundingpolyhedron.h" 3 | #include "matrixd.h" 4 | 5 | /** An interface defining the functionality needed by an algorithm that 6 | * fits a polyhedron (that's assumed to be around the points) tightly 7 | * around some points. 8 | * IMPORTANT: The algorithm must guarantee that any vertex moved is moved 9 | * on a line between it and the centre of the polyhedron. 10 | * This is the requirement for fast triangle-ray intersections. 11 | */ 12 | namespace anima 13 | { 14 | namespace alg 15 | { 16 | namespace primatte 17 | { 18 | class IColourSegmenter; 19 | 20 | class IFittingAlgorithm 21 | { 22 | public: 23 | virtual ~IFittingAlgorithm(){} 24 | 25 | /** Fits the polyhedron around the points. 26 | * @param poly The polyhedron to be shrunk. 27 | * @param points The points around which to shrink. 28 | * @param minimumDistance The minimum distance of a vertex to the centre. 29 | */ 30 | virtual void shrink(BoundingPolyhedron& poly, const std::vector& points, math::vec3 backgroundPoint, 31 | float minimumDistance) const = 0; 32 | 33 | /** Fits the polyhedron around the points. 34 | * @param poly The polyhedron to be expanded. 35 | * @param points The points inside which to expand. 36 | * @param segmenter The segmenter to use when determining inner/outer points before expansion. 37 | * @param maximumDistance The maximum distance of a vertex from the centre. 38 | */ 39 | virtual void expand(BoundingPolyhedron& poly, const std::vector& points, IColourSegmenter* segmenter, 40 | math::vec3 backgroundPoint, float startingRadius, float maximumRadius) const = 0; 41 | }; 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /Primatte/inputassembler.cpp: -------------------------------------------------------------------------------- 1 | #include "inputassembler.h" 2 | #include "matrixd.h" 3 | #include "io.h" 4 | #include 5 | #include 6 | #include "iaveragebackgroundcolourlocator.h" 7 | 8 | namespace anima 9 | { 10 | namespace ia 11 | { 12 | std::vector RemoveDuplicatesWithGrid(const cv::Mat& mat, unsigned gridSize) 13 | { 14 | START_TIMER(CleaningWithGrid); 15 | 16 | assert(mat.type() == CV_32FC3); 17 | const unsigned r = mat.rows, c = mat.cols; 18 | 19 | std::vector points; 20 | points.reserve(r*c/50); 21 | 22 | const unsigned gridCubed = gridSize*gridSize*gridSize; 23 | const unsigned gridSizeMinusOne = gridSize-1; 24 | 25 | bool* grid = new(std::nothrow) bool[gridCubed](); 26 | 27 | if(!grid) 28 | throw std::runtime_error("Unable to allocate 3D grid for input processing"); 29 | 30 | for (unsigned i = 0; i < r; ++i) 31 | { 32 | float* data = (float*)(mat.data + mat.step*i); 33 | for(unsigned j = 0; j < c; ++j) 34 | { 35 | math::vec3& p = *((math::vec3*)(data + j*3)); 36 | math::vec3i pi(p.x*gridSize,p.y*gridSize,p.z*gridSize); 37 | if(unsigned(pi.x) >= gridSize) 38 | pi.x = gridSizeMinusOne; 39 | if(unsigned(pi.y) >= gridSize) 40 | pi.y = gridSizeMinusOne; 41 | if(unsigned(pi.z) >= gridSize) 42 | pi.z = gridSizeMinusOne; 43 | 44 | bool& b = grid[pi.x + gridSize*(pi.y + gridSize*pi.z)]; 45 | if (!b) 46 | { 47 | b = true; 48 | points.push_back(p); 49 | } 50 | } 51 | } 52 | 53 | delete[] grid; 54 | 55 | END_TIMER(CleaningWithGrid); 56 | 57 | return points; 58 | } 59 | 60 | void RandomSimplify(std::vector* points, float percentageToRemove) 61 | { 62 | START_TIMER(RandomSimplifying); 63 | size_t initialSize = points->size(); 64 | 65 | std::random_device rd; 66 | std::mt19937 random(rd()); 67 | std::shuffle(points->begin(), points->end(), random); 68 | 69 | points->erase(points->begin()+(int)(points->size()*(1.f-percentageToRemove/100.f)), points->end()); 70 | 71 | Inform("" + ToString(points->size()/float(initialSize)*100) + "% of points remain (" + 72 | ToString(points->size()) + "/" + ToString(initialSize)+")"); 73 | 74 | END_TIMER(RandomSimplifying); 75 | } 76 | 77 | float InputAssembler::normalisationMultiplier(int cvCode) 78 | { 79 | switch(cvCode) 80 | { 81 | case CV_8UC3: 82 | return 1.0/255.0; 83 | case CV_16UC3: 84 | return 1.0/65535.0; 85 | case CV_32FC3: 86 | return 1.0; 87 | default: 88 | throw std::runtime_error("Unknown format in input assember at line " + ToString(__LINE__)); 89 | } 90 | assert(0); 91 | } 92 | 93 | InputAssembler::InputAssembler(InputAssemblerDescriptor& desc) 94 | { 95 | START_TIMER(ProcessingInput); 96 | //Convert the input into 3 component float mat. 97 | if(desc.foregroundSource == nullptr) 98 | throw std::runtime_error("Null source foreground Mat"); 99 | 100 | if(desc.backgroundSource == nullptr) 101 | throw std::runtime_error("Null source background mat"); 102 | 103 | if(desc.backgroundLocator == nullptr) 104 | throw std::runtime_error("Null background colour locator"); 105 | 106 | if(!desc.ipd.validate()) 107 | throw std::runtime_error("Could not validate input processor."); 108 | 109 | if(desc.foregroundSource->cols*desc.foregroundSource->rows==0) 110 | throw std::runtime_error("Empty foreground source."); 111 | 112 | if(desc.backgroundSource->cols*desc.backgroundSource->rows==0) 113 | throw std::runtime_error("Empty background source."); 114 | 115 | 116 | desc.foregroundSource->convertTo(mForegroundF, CV_32FC3, 117 | normalisationMultiplier(desc.foregroundSource->type())); 118 | desc.backgroundSource->convertTo(mBackgroundF, CV_32FC3, 119 | normalisationMultiplier(desc.backgroundSource->type())); 120 | 121 | //Convert everything to the appropriate colour space: 122 | mColourSpace = desc.targetColourspace; 123 | 124 | switch(desc.targetColourspace) 125 | { 126 | case InputAssemblerDescriptor::ETCS_RGB: 127 | break; 128 | case InputAssemblerDescriptor::ETCS_HSV: 129 | cv::cvtColor(mForegroundF, mForegroundF, CV_RGB2HSV); 130 | cv::cvtColor(mBackgroundF, mBackgroundF, CV_RGB2HSV); 131 | 132 | //Normalise hue: 133 | for (int i = 0; i < mForegroundF.rows; ++i) 134 | { 135 | float* data = (float*)(mForegroundF.data + mForegroundF.step*i); 136 | for(int j = 0; j < mForegroundF.cols; ++j) 137 | *(data + j*3)/=360.f; 138 | } 139 | for (int i = 0; i < mBackgroundF.rows; ++i) 140 | { 141 | float* data = (float*)(mBackgroundF.data + mBackgroundF.step*i); 142 | for(int j = 0; j < mBackgroundF.cols; ++j) 143 | *(data + j*3)/=360.f; 144 | } 145 | break; 146 | case InputAssemblerDescriptor::ETCS_LAB: 147 | cv::cvtColor(mForegroundF, mForegroundF, CV_RGB2Lab); 148 | cv::cvtColor(mBackgroundF, mBackgroundF, CV_RGB2Lab); 149 | 150 | //Get into proper range 151 | for (int i = 0; i < mForegroundF.rows; ++i) 152 | { 153 | float* data = (float*)(mForegroundF.data + mForegroundF.step*i); 154 | for(int j = 0; j < mForegroundF.cols; ++j) 155 | { 156 | math::vec3& p = *((math::vec3*)(data + j*3)); 157 | p = math::vec3(p.x, (p.y+127.f), (p.z+127.f))/254.f; 158 | } 159 | } 160 | for (int i = 0; i < mBackgroundF.rows; ++i) 161 | { 162 | float* data = (float*)(mBackgroundF.data + mBackgroundF.step*i); 163 | for(int j = 0; j < mBackgroundF.cols; ++j) 164 | { 165 | math::vec3& p = *((math::vec3*)(data + j*3)); 166 | p = math::vec3(p.x, (p.y+127.f), (p.z+127.f))/254.f; 167 | } 168 | } 169 | break; 170 | } 171 | 172 | //Convert mat to vector, and clean: 173 | mPoints = RemoveDuplicatesWithGrid(mForegroundF, desc.ipd.gridSize); 174 | mBackgroundPoints = RemoveDuplicatesWithGrid(mBackgroundF, desc.ipd.gridSize); 175 | 176 | //Find dominant background colour: 177 | mBackground = desc.backgroundLocator->findColour(mBackgroundF); 178 | 179 | //Simplify randomly if needed: 180 | if(desc.ipd.randomSimplify) 181 | { 182 | RandomSimplify(&mPoints, desc.ipd.randomSimplifyPercentage); 183 | RandomSimplify(&mBackgroundPoints, desc.ipd.randomSimplifyPercentage); 184 | } 185 | 186 | END_TIMER(ProcessingInput); 187 | } 188 | 189 | cv::Point3f InputAssembler::debugGetPointColour(math::vec3 p) const 190 | { 191 | switch(mColourSpace) 192 | { 193 | case InputAssemblerDescriptor::ETCS_RGB: 194 | break; 195 | case InputAssemblerDescriptor::ETCS_HSV: 196 | { 197 | p.x *= 360.f; 198 | cv::Mat mat(1,1,CV_32FC3, &p.x); 199 | cv::cvtColor(mat, mat, CV_HSV2BGR); 200 | } 201 | break; 202 | case InputAssemblerDescriptor::ETCS_LAB: 203 | { 204 | p = math::vec3(p.x*254.f, 205 | p.y*254.f - 127.f, 206 | p.z*254.f - 127.f); 207 | 208 | cv::Mat mat(1,1,CV_32FC3, &p.x); 209 | cv::cvtColor(mat, mat, CV_Lab2BGR); 210 | } 211 | break; 212 | default: 213 | assert(0); 214 | } 215 | 216 | return cv::Point3f(p.z,p.y,p.x); 217 | } 218 | 219 | const std::vector& InputAssembler::backgroundPoints() const 220 | { 221 | return mBackgroundPoints; 222 | } 223 | 224 | const std::vector& InputAssembler::points() const 225 | { 226 | return mPoints; 227 | } 228 | 229 | const cv::Mat& InputAssembler::mat() const 230 | { 231 | return mForegroundF; 232 | } 233 | 234 | math::vec3 InputAssembler::background() const 235 | { 236 | return mBackground; 237 | } 238 | } 239 | } 240 | -------------------------------------------------------------------------------- /Primatte/inputassembler.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include "matrixd.h" 6 | 7 | /** 8 | * This class is responsible for taking an InputAssemblerDescriptor object, 9 | * and load+store the corresponding data. 10 | * */ 11 | 12 | namespace anima 13 | { 14 | namespace ia 15 | { 16 | class IAverageBackgroundColourLocator; 17 | 18 | /** The descriptor of the input data/source. */ 19 | struct InputAssemblerDescriptor 20 | { 21 | enum TargetColourspace {ETCS_RGB, ETCS_HSV, ETCS_LAB}; 22 | 23 | /** The colour space to which the input will be converted. */ 24 | TargetColourspace targetColourspace; 25 | 26 | IAverageBackgroundColourLocator* backgroundLocator; 27 | 28 | /** Set the image source to be copied from. 29 | The source mat is converted into floating point rgb values. 30 | 8-bit, 16-bit and floating point formats are supported. 31 | Expects a 3-component image. */ 32 | const cv::Mat* foregroundSource; 33 | 34 | const cv::Mat* backgroundSource; 35 | 36 | /** The input processing descriptor, setting out pixel cleaning options. */ 37 | struct InputCleanupDescriptor 38 | { 39 | /** Wheter to remove points at random. */ 40 | bool randomSimplify; 41 | 42 | /** Percentage of points to remove randomly. */ 43 | float randomSimplifyPercentage; 44 | 45 | /** Used for early stage pre-processing where only one point is kept per 3D grid box. */ 46 | unsigned gridSize; 47 | 48 | bool validate() 49 | { 50 | if(randomSimplifyPercentage < 0 || 51 | randomSimplifyPercentage > 100) 52 | return false; 53 | else 54 | return true; 55 | } 56 | } ipd; 57 | 58 | InputAssemblerDescriptor() 59 | { 60 | memset(this, 0, sizeof(*this)); 61 | } 62 | }; 63 | 64 | /** The input assembler class. */ 65 | class InputAssembler 66 | { 67 | cv::Mat mForegroundF, mBackgroundF; 68 | std::vector mPoints, mBackgroundPoints; 69 | math::vec3 mBackground; 70 | InputAssemblerDescriptor::TargetColourspace mColourSpace; 71 | 72 | /** Returns the normalisation multiplier for a CV code 73 | CV_8UC3, CV_UC16C3 and CV_32FC3 supported.*/ 74 | static float normalisationMultiplier(int cvCode); 75 | public: 76 | 77 | /** Initialises the input, throwing an exception if failed. */ 78 | InputAssembler(InputAssemblerDescriptor& desc); 79 | 80 | /** Returns the internal points. */ 81 | const std::vector& points() const; 82 | 83 | /** Returns the background points. */ 84 | const std::vector& backgroundPoints() const; 85 | 86 | /** Returns the internal floating point image. */ 87 | const cv::Mat& mat() const; 88 | 89 | /** Returns the most dominant background point in the correct colour space. */ 90 | math::vec3 background() const; 91 | 92 | //Converts from internal colour space to rgb 93 | cv::Point3f debugGetPointColour(math::vec3 p) const; 94 | }; 95 | 96 | 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /Primatte/io.cpp: -------------------------------------------------------------------------------- 1 | #include "io.h" 2 | #include 3 | 4 | void Error(const std::string& msg) 5 | { 6 | std::cerr << "ERROR: " << msg << "\n"; 7 | } 8 | 9 | void Warning(const std::string& msg) 10 | { 11 | std::cout << "Warning: " << msg << "\n"; 12 | } 13 | 14 | void Inform(const std::string& msg) 15 | { 16 | std::cout << ":- " << msg << "\n"; 17 | } 18 | -------------------------------------------------------------------------------- /Primatte/io.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | 5 | /** 6 | * A series of function to help with basic input and output. 7 | * */ 8 | 9 | /** Prints the given error message */ 10 | void Error(const std::string& msg); 11 | 12 | /** Prints the given warning message. */ 13 | void Warning(const std::string& msg); 14 | 15 | /** Prints the given information message. */ 16 | void Inform(const std::string& msg); 17 | 18 | /** Converts the input to a string. */ 19 | template 20 | std::string ToString(const T t) 21 | { 22 | std::ostringstream ss; 23 | ss << t; 24 | return ss.str(); 25 | } 26 | 27 | /* Timer macros. Usage: 28 | * ''' 29 | * START_TIMER(myFunkyTimer); 30 | * doHeavyCode(); 31 | * END_TIMER(myFunkyTimer); 32 | * ''' 33 | */ 34 | 35 | #include 36 | 37 | #define START_TIMER(t) auto t = std::chrono::system_clock::now(); 38 | 39 | #define END_TIMER(t) {Inform("Stopping timer: "#t + std::string(" : ") + \ 40 | ToString(std::chrono::duration_cast(std::chrono::system_clock::now() - t).count()));} 41 | -------------------------------------------------------------------------------- /Primatte/main.cpp: -------------------------------------------------------------------------------- 1 | #include "application.h" 2 | #include 3 | 4 | int main(int argc, char** argv) 5 | { 6 | // Read command lines arguments. 7 | QApplication application(argc,argv); 8 | 9 | // Instantiate the viewer. 10 | Application viewer; 11 | 12 | viewer.setWindowTitle("Preview"); 13 | 14 | // Make the viewer window visible on screen. 15 | viewer.show(); 16 | 17 | // Run main loop. 18 | return application.exec(); 19 | } 20 | -------------------------------------------------------------------------------- /Primatte/matrixd.cpp: -------------------------------------------------------------------------------- 1 | #include "matrixd.h" 2 | #include 3 | 4 | namespace math 5 | { 6 | template T dot(const tmp::_vec2& v1, const tmp::_vec2& v2) 7 | { 8 | return v1.x*v2.x + v1.y*v2.y; 9 | } 10 | 11 | template T dot(const tmp::_vec3& v1, const tmp::_vec3& v2) 12 | { 13 | return v1.x*v2.x + v1.y*v2.y + v1.z*v2.z; 14 | } 15 | 16 | template T dot(const tmp::_vec4& v1, const tmp::_vec4& v2) 17 | { 18 | return v1.x*v2.x + v1.y*v2.y + v1.z*v2.z + v1.w*v2.w; 19 | } 20 | 21 | template tmp::_vec3 cross(const tmp::_vec3& v1, const tmp::_vec3& v2) 22 | { 23 | return tmp::_vec3(v1.y*v2.z - v1.z*v2.y, 24 | v1.z*v2.x - v1.x*v2.z, 25 | v1.x*v2.y - v1.y*v2.x); 26 | } 27 | 28 | namespace tmp 29 | { 30 | static const matReal matScalarOne(1); 31 | static const matReal matScalarNull(0); 32 | static const matReal matScalarTwo(2); 33 | 34 | template _vec2::_vec2() 35 | { 36 | reset(); 37 | } 38 | 39 | template _vec2::_vec2(const T x_, const T y_) 40 | { 41 | x = x_; 42 | y = y_; 43 | } 44 | 45 | template _vec2::_vec2(const T n) 46 | { 47 | x = n; 48 | y = n; 49 | } 50 | 51 | template matReal _vec2::angle() const 52 | { 53 | return matReal(std::atan2(y, x)); 54 | } 55 | 56 | template T _vec2::lengthSquared() const 57 | { 58 | return x*x + y*y; 59 | } 60 | 61 | template matReal _vec2::length() const 62 | { 63 | return matReal(std::sqrt(x*x + y*y)); 64 | } 65 | 66 | template matReal _vec2::proj(const _vec2& v) const 67 | { 68 | return math::dot(*this, v/v.length()); 69 | } 70 | 71 | template matReal _vec2::distance(const _vec2& v) const 72 | { 73 | return matReal(std::sqrt((x - v.x)*(x - v.x) + (y - v.y)*(y - v.y))); 74 | } 75 | 76 | template T _vec2::distanceSquared(const _vec2& v) const 77 | { 78 | return (x - v.x)*(x - v.x) + (y - v.y)*(y - v.y); 79 | } 80 | 81 | template _vec2 _vec2::operator * (const T n) const 82 | { 83 | return _vec2(x*n, y*n); 84 | } 85 | 86 | template _vec2 _vec2::operator / (const T n) const 87 | { 88 | return _vec2(x / n, y / n); 89 | } 90 | 91 | template _vec2 _vec2::operator + (const T n) const 92 | { 93 | return _vec2(x + n, y + n); 94 | } 95 | 96 | template _vec2 _vec2::operator - (const T n) const 97 | { 98 | return _vec2(x - n, y - n); 99 | } 100 | 101 | template void _vec2::operator *= (const T n) 102 | { 103 | x *= n; 104 | y *= n; 105 | } 106 | 107 | template void _vec2::operator /= (const T n) 108 | { 109 | x /= n; 110 | y /= n; 111 | } 112 | 113 | template void _vec2::operator += (const T n) 114 | { 115 | x += n; 116 | y += n; 117 | } 118 | 119 | template void _vec2::operator -= (const T n) 120 | { 121 | x -= n; 122 | y -= n; 123 | } 124 | 125 | template bool _vec2::operator == (const _vec2& vec) const 126 | { 127 | return x == vec.x && y == vec.y; 128 | } 129 | 130 | template bool _vec2::operator == (T f) const 131 | { 132 | return x == f && y == f; 133 | } 134 | 135 | template bool _vec2::operator != (const _vec2& vec) const 136 | { 137 | return x != vec.x || y != vec.y; 138 | } 139 | 140 | template bool _vec2::operator != (T f) const 141 | { 142 | return x != f || y != f; 143 | } 144 | 145 | template _vec2& _vec2::normalize() 146 | { 147 | const matReal len = length(); 148 | if(len==0) 149 | *this = _vec2(0); 150 | else 151 | { 152 | const matReal lenDivisor = matScalarOne / len; 153 | x = T(x * lenDivisor); 154 | y = T(y * lenDivisor); 155 | } 156 | return *this; 157 | } 158 | 159 | template _vec2 _vec2::operator + (const _vec2& vec) const 160 | { 161 | return _vec2(x + vec.x, y + vec.y); 162 | } 163 | 164 | template _vec2 _vec2::operator - (const _vec2& vec) const 165 | { 166 | return _vec2(x - vec.x, y - vec.y); 167 | } 168 | 169 | template _vec2 _vec2::operator * (const _vec2& vec) const 170 | { 171 | return _vec2(x*vec.x, y*vec.y); 172 | } 173 | 174 | template _vec2 _vec2::operator / (const _vec2& vec) const 175 | { 176 | return _vec2(x / vec.x, y / vec.y); 177 | } 178 | 179 | template void _vec2::operator += (const _vec2& vec) 180 | { 181 | x += vec.x; 182 | y += vec.y; 183 | } 184 | 185 | template void _vec2::operator -= (const _vec2& vec) 186 | { 187 | x -= vec.x; 188 | y -= vec.y; 189 | } 190 | 191 | template void _vec2::operator *= (const _vec2& vec) 192 | { 193 | x *= vec.x; 194 | y *= vec.y; 195 | } 196 | 197 | template void _vec2::operator /= (const _vec2& vec) 198 | { 199 | x /= vec.x; 200 | y /= vec.y; 201 | } 202 | 203 | template _vec2 _vec2::xy() const { return _vec2(x, y); } 204 | template _vec2 _vec2::yx() const { return _vec2(y, x); } 205 | 206 | template void _vec2::reset() 207 | { 208 | x = 0; 209 | y = 0; 210 | } 211 | 212 | template bool _vec2::operator < (const _vec2& vec) const 213 | { 214 | if (x==vec.x) 215 | return y bool _vec2::operator <= (const _vec2& vec) const 221 | { 222 | return *this < vec || *this==vec; 223 | } 224 | 225 | template bool _vec2::operator > (const _vec2& vec) const 226 | { 227 | if (x==vec.x) 228 | return y>vec.y; 229 | else 230 | return x > vec.x; 231 | } 232 | 233 | template bool _vec2::operator >= (const _vec2& vec) const 234 | { 235 | return *this > vec || *this==vec; 236 | } 237 | 238 | template _vec2 _vec2::operator % (const T n) const 239 | { 240 | return _vec2(x%n, y%n); 241 | } 242 | 243 | template void _vec2::operator %= (const T n) 244 | { 245 | x%=n; 246 | y%=n; 247 | } 248 | 249 | template _vec2 _vec2::operator % (const _vec2& vec) const 250 | { 251 | return _vec2(x%vec.x, y%vec.y); 252 | } 253 | 254 | template void _vec2::operator %= (const _vec2& vec) 255 | { 256 | x%=vec.x; 257 | y%=vec.y; 258 | } 259 | 260 | 261 | template<> _vec2 _vec2::operator % (const float n) const 262 | { 263 | return _vec2((float)fmod(x,n),(float)fmod(y,n)); 264 | } 265 | 266 | template<> void _vec2::operator %= (const float n) 267 | { 268 | x = (float)fmod(x,n); 269 | y = (float)fmod(y,n); 270 | } 271 | 272 | template<> _vec2 _vec2::operator % (const _vec2& vec) const 273 | { 274 | return _vec2((float)fmod(x,vec.x), (float)fmod(y,vec.y)); 275 | } 276 | 277 | template<> void _vec2::operator %= (const _vec2& vec) 278 | { 279 | x = (float)fmod(x,vec.x); 280 | y = (float)fmod(y,vec.y); 281 | } 282 | 283 | 284 | template<> _vec2 _vec2::operator % (const double n) const 285 | { 286 | return _vec2((double)fmod(x,n),(double)fmod(y,n)); 287 | } 288 | 289 | template<> void _vec2::operator %= (const double n) 290 | { 291 | x = (double)fmod(x,n); 292 | y = (double)fmod(y,n); 293 | } 294 | 295 | template<> _vec2 _vec2::operator % (const _vec2& vec) const 296 | { 297 | return _vec2((double)fmod(x,vec.x), (double)fmod(y,vec.y)); 298 | } 299 | 300 | template<> void _vec2::operator %= (const _vec2& vec) 301 | { 302 | x = (double)fmod(x,vec.x); 303 | y = (double)fmod(y,vec.y); 304 | } 305 | 306 | 307 | template _vec3::_vec3() 308 | { 309 | reset(); 310 | } 311 | 312 | template _vec3::_vec3(const T x_, const T y_, const T z_) 313 | { 314 | x = x_; 315 | y = y_; 316 | z = z_; 317 | } 318 | 319 | template _vec3::_vec3(const _vec2& v, const T f) 320 | { 321 | x = v.x; 322 | y = v.y; 323 | z = f; 324 | } 325 | 326 | template _vec3::_vec3(const T f, const _vec2& v) 327 | { 328 | x = f; 329 | y = v.x; 330 | z = v.y; 331 | } 332 | 333 | template _vec3::_vec3(const T f) 334 | { 335 | x = f; 336 | y = f; 337 | z = f; 338 | } 339 | 340 | template T _vec3::lengthSquared() const 341 | { 342 | return x*x + y*y + z*z; 343 | } 344 | 345 | template matReal _vec3::length() const 346 | { 347 | return matReal(std::sqrt(x*x + y*y + z*z)); 348 | } 349 | 350 | template matReal _vec3::distance(const _vec3& v) const 351 | { 352 | return matReal(std::sqrt((x - v.x)*(x - v.x) + (y - v.y)*(y - v.y) + (z - v.z)*(z - v.z))); 353 | } 354 | 355 | template T _vec3::distanceSquared(const _vec3& v) const 356 | { 357 | return (x - v.x)*(x - v.x) + (y - v.y)*(y - v.y) + (z - v.z)*(z - v.z); 358 | } 359 | 360 | template matReal _vec3::proj(const _vec3& v) const 361 | { 362 | return math::dot(*this, v/v.length()); 363 | } 364 | 365 | template _vec3 _vec3::operator * (const T n) const 366 | { 367 | return _vec3(x*n, y*n, z*n); 368 | } 369 | 370 | template _vec3 _vec3::operator / (const T n) const 371 | { 372 | return _vec3(x / n, y / n, z / n); 373 | } 374 | 375 | template _vec3 _vec3::operator + (const T n) const 376 | { 377 | return _vec3(x + n, y + n, z + n); 378 | } 379 | 380 | template _vec3 _vec3::operator - (const T n) const 381 | { 382 | return _vec3(x - n, y - n, z - n); 383 | } 384 | 385 | template void _vec3::operator *= (const T n) 386 | { 387 | x *= n; 388 | y *= n; 389 | z *= n; 390 | } 391 | 392 | template void _vec3::operator /= (const T n) 393 | { 394 | x /= n; 395 | y /= n; 396 | z /= n; 397 | } 398 | 399 | template void _vec3::operator += (const T n) 400 | { 401 | x += n; 402 | y += n; 403 | z += n; 404 | } 405 | 406 | template void _vec3::operator -= (const T n) 407 | { 408 | x -= n; 409 | y -= n; 410 | z -= n; 411 | } 412 | 413 | template 414 | bool _vec3::operator == (const _vec3& vec) const 415 | { 416 | return x == vec.x && y == vec.y && z == vec.z; 417 | } 418 | 419 | template bool _vec3::operator == (T f) const 420 | { 421 | return x == f && y == f && z == f; 422 | } 423 | 424 | template bool _vec3::operator != (const _vec3& vec) const 425 | { 426 | return x != vec.x || y != vec.y || z != vec.z; 427 | } 428 | 429 | template bool _vec3::operator != (T f) const 430 | { 431 | return x != f || y != f || z != f; 432 | } 433 | 434 | template _vec3& _vec3::normalize() 435 | { 436 | const matReal len = length(); 437 | if(len==0) 438 | *this = _vec3(T(0)); 439 | else 440 | { 441 | const matReal lenDivisor = matScalarOne / len; 442 | x = T(x * lenDivisor); 443 | y = T(y * lenDivisor); 444 | z = T(z * lenDivisor); 445 | } 446 | return *this; 447 | } 448 | 449 | template _vec3 _vec3::operator + (const _vec3& vec) const 450 | { 451 | return _vec3(x + vec.x, y + vec.y, z + vec.z); 452 | } 453 | 454 | template _vec3 _vec3::operator - (const _vec3& vec) const 455 | { 456 | return _vec3(x - vec.x, y - vec.y, z - vec.z); 457 | } 458 | 459 | template _vec3 _vec3::operator * (const _vec3& vec) const 460 | { 461 | return _vec3(x*vec.x, y*vec.y, z*vec.z); 462 | } 463 | 464 | template _vec3 _vec3::operator / (const _vec3& vec) const 465 | { 466 | return _vec3(x / vec.x, y / vec.y, z / vec.z); 467 | } 468 | 469 | template void _vec3::operator += (const _vec3& vec) 470 | { 471 | x += vec.x; 472 | y += vec.y; 473 | z += vec.z; 474 | } 475 | 476 | template void _vec3::operator -= (const _vec3& vec) 477 | { 478 | x -= vec.x; 479 | y -= vec.y; 480 | z -= vec.z; 481 | } 482 | 483 | template void _vec3::operator *= (const _vec3& vec) 484 | { 485 | x *= vec.x; 486 | y *= vec.y; 487 | z *= vec.z; 488 | } 489 | 490 | template void _vec3::operator /= (const _vec3& vec) 491 | { 492 | x /= vec.x; 493 | y /= vec.y; 494 | z /= vec.z; 495 | } 496 | 497 | template _vec3& _vec3::rotate(const matReal angle, const _vec3& axis) 498 | { 499 | mat4 rotationmat; 500 | rotationmat.initRotation(angle, axis); 501 | 502 | *this = (rotationmat*_vec4(*this, 1)).xyz(); 503 | return *this; 504 | } 505 | 506 | template void _vec3::reset() 507 | { 508 | x = 0; 509 | y = 0; 510 | z = 0; 511 | } 512 | 513 | template _vec3 _vec3::xyz() const { return _vec3(x, y, z); } 514 | template _vec3 _vec3::xzy() const { return _vec3(x, z, y); } 515 | template _vec3 _vec3::yxz() const { return _vec3(y, x, z); } 516 | template _vec3 _vec3::yzx() const { return _vec3(y, z, x); } 517 | template _vec3 _vec3::zxy() const { return _vec3(z, x, y); } 518 | template _vec3 _vec3::zyx() const { return _vec3(z, y, x); } 519 | 520 | template _vec2 _vec3::xy() const { return _vec2(x, y); } 521 | template _vec2 _vec3::yx() const { return _vec2(y, x); } 522 | template _vec2 _vec3::xz() const { return _vec2(x, z); } 523 | template _vec2 _vec3::zx() const { return _vec2(z, x); } 524 | template _vec2 _vec3::yz() const { return _vec2(y, z); } 525 | template _vec2 _vec3::zy() const { return _vec2(z, y); } 526 | 527 | 528 | template bool _vec3::operator < (const _vec3& vec) const 529 | { 530 | if (x==vec.x) 531 | if(y==vec.y) 532 | return z bool _vec3::operator <= (const _vec3& vec) const 540 | { 541 | return *this < vec || *this==vec; 542 | } 543 | 544 | template bool _vec3::operator > (const _vec3& vec) const 545 | { 546 | if (x==vec.x) 547 | if(y==vec.y) 548 | return z>vec.z; 549 | else 550 | return y>vec.y; 551 | else 552 | return x > vec.x; 553 | } 554 | 555 | template bool _vec3::operator >= (const _vec3& vec) const 556 | { 557 | return *this > vec || *this==vec; 558 | } 559 | 560 | template _vec3 _vec3::operator % (const T n) const 561 | { 562 | return _vec3(x%n, y%n, z%n); 563 | } 564 | 565 | template void _vec3::operator %= (const T n) 566 | { 567 | x%=n; 568 | y%=n; 569 | z%=n; 570 | } 571 | 572 | template _vec3 _vec3::operator % (const _vec3& vec) const 573 | { 574 | return _vec3(x%vec.x, y%vec.y, z%vec.z); 575 | } 576 | 577 | template void _vec3::operator %= (const _vec3& vec) 578 | { 579 | x%=vec.x; 580 | y%=vec.y; 581 | z%=vec.z; 582 | } 583 | 584 | 585 | template<> _vec3 _vec3::operator % (const float n) const 586 | { 587 | return _vec3((float)fmod(x,n),(float)fmod(y,n),(float)fmod(z,n)); 588 | } 589 | 590 | template<> void _vec3::operator %= (const float n) 591 | { 592 | x = (float)fmod(x,n); 593 | y = (float)fmod(y,n); 594 | z = (float)fmod(z,n); 595 | } 596 | 597 | template<> _vec3 _vec3::operator % (const _vec3& vec) const 598 | { 599 | return _vec3((float)fmod(x,vec.x), (float)fmod(y,vec.y), (float)fmod(z,vec.z)); 600 | } 601 | 602 | template<> void _vec3::operator %= (const _vec3& vec) 603 | { 604 | x = (float)fmod(x,vec.x); 605 | y = (float)fmod(y,vec.y); 606 | z = (float)fmod(z,vec.z); 607 | } 608 | 609 | 610 | template<> _vec3 _vec3::operator % (const double n) const 611 | { 612 | return _vec3((double)fmod(x,n),(double)fmod(y,n),(double)fmod(z,n)); 613 | } 614 | 615 | template<> void _vec3::operator %= (const double n) 616 | { 617 | x = (double)fmod(x,n); 618 | y = (double)fmod(y,n); 619 | z = (double)fmod(z,n); 620 | } 621 | 622 | template<> _vec3 _vec3::operator % (const _vec3& vec) const 623 | { 624 | return _vec3((double)fmod(x,vec.x), (double)fmod(y,vec.y), (double)fmod(z,vec.z)); 625 | } 626 | 627 | template<> void _vec3::operator %= (const _vec3& vec) 628 | { 629 | x = (double)fmod(x,vec.x); 630 | y = (double)fmod(y,vec.y); 631 | z = (double)fmod(z,vec.z); 632 | } 633 | 634 | 635 | 636 | 637 | 638 | template _vec4::_vec4() 639 | { 640 | reset(); 641 | } 642 | 643 | template _vec4::_vec4(const T x_, const T y_, const T z_, const T w_) 644 | { 645 | x = x_; 646 | y = y_; 647 | z = z_; 648 | w = w_; 649 | } 650 | 651 | template _vec4::_vec4(const _vec2& v1, const _vec2& v2) 652 | { 653 | x = v1.x; 654 | y = v1.y; 655 | z = v2.x; 656 | w = v2.y; 657 | } 658 | 659 | template _vec4::_vec4(const T f1, const T f2, const _vec2& v) 660 | { 661 | x = f1; 662 | y = f2; 663 | z = v.x; 664 | w = v.y; 665 | } 666 | 667 | template _vec4::_vec4(const _vec2& v, const T f1, const T f2) 668 | { 669 | x = v.x; 670 | y = v.y; 671 | z = f1; 672 | w = f2; 673 | } 674 | 675 | template _vec4::_vec4(const T f1, const _vec2& v, const T f2) 676 | { 677 | x = f1; 678 | y = v.x; 679 | z = v.y; 680 | w = f2; 681 | } 682 | 683 | template _vec4::_vec4(const _vec3& v, const T f) 684 | { 685 | x = v.x; 686 | y = v.y; 687 | z = v.z; 688 | w = f; 689 | } 690 | 691 | template _vec4::_vec4(const T f, const _vec3& v) 692 | { 693 | x = f; 694 | y = v.x; 695 | z = v.y; 696 | w = v.z; 697 | } 698 | 699 | template _vec4::_vec4(const T f) 700 | { 701 | x = f; 702 | y = f; 703 | z = f; 704 | w = f; 705 | } 706 | 707 | template T _vec4::lengthSquared() const 708 | { 709 | return x*x + y*y + z*z + w*w; 710 | } 711 | 712 | template matReal _vec4::length() const 713 | { 714 | return matReal(std::sqrt(x*x + y*y + z*z + w*w)); 715 | } 716 | 717 | template 718 | matReal _vec4::distance(const _vec4& v) const 719 | { 720 | return matReal(sqrt((x - v.x)*(x - v.x) + (y - v.y)*(y - v.y) + (z - v.z)*(z - v.z) + (w - v.w)*(w - v.w))); 721 | } 722 | 723 | template T _vec4::distanceSquared(const _vec4& v) const 724 | { 725 | return (x - v.x)*(x - v.x) + (y - v.y)*(y - v.y) + (z - v.z)*(z - v.z) + (w - v.w)*(w - v.w); 726 | } 727 | 728 | template matReal _vec4::proj(const _vec4& v) const 729 | { 730 | return math::dot(*this, v/v.length()); 731 | } 732 | 733 | template _vec4 _vec4::operator * (const T n) const 734 | { 735 | return _vec4(x*n, y*n, z*n, w*n); 736 | } 737 | 738 | template _vec4 _vec4::operator / (const T n) const 739 | { 740 | return _vec4(x / n, y / n, z / n, w / n); 741 | } 742 | 743 | template _vec4 _vec4::operator + (const T n) const 744 | { 745 | return _vec4(x + n, y + n, z + n, w + n); 746 | } 747 | 748 | template _vec4 _vec4::operator - (const T n) const 749 | { 750 | return _vec4(x - n, y - n, z - n, w - n); 751 | } 752 | 753 | template void _vec4::operator *= (const T n) 754 | { 755 | x *= n; 756 | y *= n; 757 | z *= n; 758 | w *= n; 759 | } 760 | 761 | template void _vec4::operator /= (const T n) 762 | { 763 | x /= n; 764 | y /= n; 765 | z /= n; 766 | w /= n; 767 | } 768 | 769 | template void _vec4::operator += (const T n) 770 | { 771 | x += n; 772 | y += n; 773 | z += n; 774 | w += n; 775 | } 776 | 777 | template void _vec4::operator -= (const T n) 778 | { 779 | x -= n; 780 | y -= n; 781 | z -= n; 782 | w -= n; 783 | } 784 | 785 | template bool _vec4::operator == (const _vec4& vec) const 786 | { 787 | return x == vec.x && y == vec.y && z == vec.z && w == vec.w; 788 | } 789 | 790 | template bool _vec4::operator == (T f) const 791 | { 792 | return x == f && y == f &&z == f && w == f; 793 | } 794 | 795 | template bool _vec4::operator != (const _vec4& vec) const 796 | { 797 | return x != vec.x || y != vec.y || z != vec.z || w != vec.w; 798 | } 799 | 800 | template bool _vec4::operator != (T f) const 801 | { 802 | return x != f || y != f || z != f || w != f; 803 | } 804 | 805 | template _vec4& _vec4::normalize() 806 | { 807 | const matReal len = length(); 808 | if(len==0) 809 | *this = _vec4(0); 810 | else 811 | { 812 | const matReal lenDivisor = matScalarOne / len; 813 | x = T(x * lenDivisor); 814 | y = T(y * lenDivisor); 815 | z = T(z * lenDivisor); 816 | w = T(w * lenDivisor); 817 | } 818 | return *this; 819 | } 820 | 821 | template _vec4 _vec4::operator + (const _vec4& vec) const 822 | { 823 | return _vec4(x + vec.x, y + vec.y, z + vec.z, w + vec.w); 824 | } 825 | 826 | template _vec4 _vec4::operator - (const _vec4& vec) const 827 | { 828 | return _vec4(x - vec.x, y - vec.y, z - vec.z, w - vec.w); 829 | } 830 | 831 | template 832 | _vec4 _vec4::operator * (const _vec4& vec) const 833 | { 834 | return _vec4(x*vec.x, y*vec.y, z*vec.z, w*vec.w); 835 | } 836 | 837 | template _vec4 _vec4::operator / (const _vec4& vec) const 838 | { 839 | return _vec4(x / vec.x, y / vec.y, z / vec.z, w / vec.w); 840 | } 841 | 842 | template void _vec4::operator += (const _vec4& vec) 843 | { 844 | x += vec.x; 845 | y += vec.y; 846 | z += vec.z; 847 | w += vec.w; 848 | } 849 | template void _vec4::operator -= (const _vec4& vec) 850 | { 851 | x -= vec.x; 852 | y -= vec.y; 853 | z -= vec.z; 854 | w -= vec.w; 855 | } 856 | 857 | template void _vec4::operator *= (const _vec4& vec) 858 | { 859 | x *= vec.x; 860 | y *= vec.y; 861 | z *= vec.z; 862 | w *= vec.w; 863 | } 864 | 865 | template void _vec4::operator /= (const _vec4& vec) 866 | { 867 | x /= vec.x; 868 | y /= vec.y; 869 | z /= vec.z; 870 | w /= vec.w; 871 | } 872 | 873 | template void _vec4::reset() 874 | { 875 | x = 0; 876 | y = 0; 877 | z = 0; 878 | w = 0; 879 | } 880 | 881 | template _vec4 _vec4::operator % (const T n) const 882 | { 883 | return _vec4(x%n, y%n, z%n, w%n); 884 | } 885 | 886 | template void _vec4::operator %= (const T n) 887 | { 888 | x%=n; 889 | y%=n; 890 | z%=n; 891 | w%=n; 892 | } 893 | 894 | template _vec4 _vec4::operator % (const _vec4& vec) const 895 | { 896 | return _vec4(x%vec.x, y%vec.y, z%vec.z, w%vec.w); 897 | } 898 | 899 | template void _vec4::operator %= (const _vec4& vec) 900 | { 901 | x%=vec.x; 902 | y%=vec.y; 903 | z%=vec.z; 904 | w%=vec.w; 905 | } 906 | 907 | 908 | 909 | template<> _vec4 _vec4::operator % (const float n) const 910 | { 911 | return _vec4((float)fmod(x,n),(float)fmod(y,n),(float)fmod(z,n),(float)fmod(w,n)); 912 | } 913 | 914 | template<> void _vec4::operator %= (const float n) 915 | { 916 | x = (float)fmod(x,n); 917 | y = (float)fmod(y,n); 918 | z = (float)fmod(z,n); 919 | w = (float)fmod(w,n); 920 | } 921 | 922 | template<> _vec4 _vec4::operator % (const _vec4& vec) const 923 | { 924 | return _vec4((float)fmod(x,vec.x), (float)fmod(y,vec.y), (float)fmod(z,vec.z),(float)fmod(w,vec.w)); 925 | } 926 | 927 | template<> void _vec4::operator %= (const _vec4& vec) 928 | { 929 | x = (float)fmod(x,vec.x); 930 | y = (float)fmod(y,vec.y); 931 | z = (float)fmod(z,vec.z); 932 | w = (float)fmod(w,vec.w); 933 | } 934 | 935 | 936 | template<> _vec4 _vec4::operator % (const double n) const 937 | { 938 | return _vec4((double)fmod(x,n),(double)fmod(y,n),(double)fmod(z,n),(double)fmod(w,n)); 939 | } 940 | 941 | template<> void _vec4::operator %= (const double n) 942 | { 943 | x = (double)fmod(x,n); 944 | y = (double)fmod(y,n); 945 | z = (double)fmod(z,n); 946 | w = (double)fmod(w,n); 947 | } 948 | 949 | template<> _vec4 _vec4::operator % (const _vec4& vec) const 950 | { 951 | return _vec4((double)fmod(x,vec.x), (double)fmod(y,vec.y), (double)fmod(z,vec.z),(double)fmod(w,vec.w)); 952 | } 953 | 954 | template<> void _vec4::operator %= (const _vec4& vec) 955 | { 956 | x = (double)fmod(x,vec.x); 957 | y = (double)fmod(y,vec.y); 958 | z = (double)fmod(z,vec.z); 959 | w = (double)fmod(w,vec.w); 960 | } 961 | 962 | 963 | 964 | 965 | 966 | template _vec4 _vec4::xyzw() const { return _vec4(x, y, z, w); } 967 | template _vec4 _vec4::xywz() const { return _vec4(x, y, w, z); } 968 | template _vec4 _vec4::xzwy() const { return _vec4(x, z, w, y); } 969 | template _vec4 _vec4::xzyw() const { return _vec4(x, z, y, w); } 970 | template _vec4 _vec4::xwzy() const { return _vec4(x, w, z, y); } 971 | template _vec4 _vec4::xwyz() const { return _vec4(x, w, y, z); } 972 | template _vec4 _vec4::yxzw() const { return _vec4(y, x, z, w); } 973 | template _vec4 _vec4::yxwz() const { return _vec4(y, x, w, z); } 974 | template _vec4 _vec4::yzwx() const { return _vec4(y, z, w, x); } 975 | template _vec4 _vec4::yzxw() const { return _vec4(y, z, x, w); } 976 | template _vec4 _vec4::ywzx() const { return _vec4(y, w, z, x); } 977 | template _vec4 _vec4::ywxz() const { return _vec4(y, w, x, z); } 978 | template _vec4 _vec4::zyxw() const { return _vec4(z, y, x, w); } 979 | template _vec4 _vec4::zywx() const { return _vec4(z, y, w, x); } 980 | template _vec4 _vec4::zxwy() const { return _vec4(z, x, w, y); } 981 | template _vec4 _vec4::zxyw() const { return _vec4(z, x, y, w); } 982 | template _vec4 _vec4::zwxy() const { return _vec4(z, w, x, y); } 983 | template _vec4 _vec4::zwyx() const { return _vec4(z, w, y, x); } 984 | template _vec4 _vec4::wyzx() const { return _vec4(w, y, z, x); } 985 | template _vec4 _vec4::wyxz() const { return _vec4(w, y, x, z); } 986 | template _vec4 _vec4::wzxy() const { return _vec4(w, z, x, y); } 987 | template _vec4 _vec4::wzyx() const { return _vec4(w, z, y, x); } 988 | template _vec4 _vec4::wxzy() const { return _vec4(w, x, z, y); } 989 | template _vec4 _vec4::wxyz() const { return _vec4(w, x, y, z); } 990 | 991 | template _vec3 _vec4::xyz() const { return _vec3(x, y, z); } 992 | template _vec3 _vec4::xzy() const { return _vec3(x, z, y); } 993 | template _vec3 _vec4::yxz() const { return _vec3(y, x, z); } 994 | template _vec3 _vec4::yzx() const { return _vec3(y, z, x); } 995 | template _vec3 _vec4::zxy() const { return _vec3(z, x, y); } 996 | template _vec3 _vec4::zyx() const { return _vec3(z, y, x); } 997 | template _vec3 _vec4::wyz() const { return _vec3(w, y, z); } 998 | template _vec3 _vec4::wzy() const { return _vec3(w, z, y); } 999 | template _vec3 _vec4::ywz() const { return _vec3(y, w, z); } 1000 | template _vec3 _vec4::yzw() const { return _vec3(y, z, w); } 1001 | template _vec3 _vec4::zwy() const { return _vec3(z, w, y); } 1002 | template _vec3 _vec4::zyw() const { return _vec3(z, y, w); } 1003 | template _vec3 _vec4::xyw() const { return _vec3(x, y, w); } 1004 | template _vec3 _vec4::xwy() const { return _vec3(x, w, y); } 1005 | template _vec3 _vec4::yxw() const { return _vec3(y, x, w); } 1006 | template _vec3 _vec4::ywx() const { return _vec3(y, w, x); } 1007 | template _vec3 _vec4::wxy() const { return _vec3(w, x, y); } 1008 | template _vec3 _vec4::wyx() const { return _vec3(w, y, x); } 1009 | template _vec3 _vec4::xwz() const { return _vec3(x, w, z); } 1010 | template _vec3 _vec4::xzw() const { return _vec3(x, z, w); } 1011 | template _vec3 _vec4::wxz() const { return _vec3(w, x, z); } 1012 | template _vec3 _vec4::wzx() const { return _vec3(w, z, x); } 1013 | template _vec3 _vec4::zxw() const { return _vec3(z, x, w); } 1014 | template _vec3 _vec4::zwx() const { return _vec3(z, w, x); } 1015 | 1016 | template _vec2 _vec4::xy() const { return _vec2(x, y); } 1017 | template _vec2 _vec4::yx() const { return _vec2(y, x); } 1018 | template _vec2 _vec4::xz() const { return _vec2(x, z); } 1019 | template _vec2 _vec4::zx() const { return _vec2(z, x); } 1020 | template _vec2 _vec4::xw() const { return _vec2(x, w); } 1021 | template _vec2 _vec4::wx() const { return _vec2(w, x); } 1022 | template _vec2 _vec4::yz() const { return _vec2(y, z); } 1023 | template _vec2 _vec4::zy() const { return _vec2(z, y); } 1024 | template _vec2 _vec4::wz() const { return _vec2(w, z); } 1025 | template _vec2 _vec4::zw() const { return _vec2(z, w); } 1026 | 1027 | 1028 | template bool _vec4::operator < (const _vec4& vec) const 1029 | { 1030 | if (x==vec.x) 1031 | if(y==vec.y) 1032 | if(z==vec.z) 1033 | return w bool _vec4::operator <= (const _vec4& vec) const 1043 | { 1044 | return *this < vec || *this==vec; 1045 | } 1046 | 1047 | template bool _vec4::operator > (const _vec4& vec) const 1048 | { 1049 | if (x==vec.x) 1050 | if(y==vec.y) 1051 | if(z==vec.z) 1052 | return w bool _vec4::operator >= (const _vec4& vec) const 1062 | { 1063 | return *this > vec || *this==vec; 1064 | } 1065 | 1066 | 1067 | _mat4::_mat4() 1068 | { 1069 | reset(); 1070 | } 1071 | 1072 | _mat4::_mat4(const matReal n) 1073 | { 1074 | reset(); 1075 | m[0][0] = n; m[1][1] = n; 1076 | m[2][2] = n; m[3][3] = n; 1077 | } 1078 | 1079 | _mat4::_mat4(const matReal m00, const matReal m10, const matReal m20, const matReal m30, 1080 | const matReal m01, const matReal m11, const matReal m21, const matReal m31, 1081 | const matReal m02, const matReal m12, const matReal m22, const matReal m32, 1082 | const matReal m03, const matReal m13, const matReal m23, const matReal m33) 1083 | { 1084 | m[0][0] = m00; m[0][1] = m01; m[0][2] = m02; m[0][3] = m03; 1085 | m[1][0] = m10; m[1][1] = m11; m[1][2] = m12; m[1][3] = m13; 1086 | m[2][0] = m20; m[2][1] = m21; m[2][2] = m22; m[2][3] = m23; 1087 | m[3][0] = m30; m[3][1] = m31; m[3][2] = m32; m[3][3] = m33; 1088 | } 1089 | 1090 | void _mat4::reset() 1091 | { 1092 | m[0][0] = 1; m[0][1] = 0; m[0][2] = 0; m[0][3] = 0; 1093 | m[1][0] = 0; m[1][1] = 1; m[1][2] = 0; m[1][3] = 0; 1094 | m[2][0] = 0; m[2][1] = 0; m[2][2] = 1; m[2][3] = 0; 1095 | m[3][0] = 0; m[3][1] = 0; m[3][2] = 0; m[3][3] = 1; 1096 | } 1097 | 1098 | _mat4 _mat4::operator * (const _mat4& p) const 1099 | { 1100 | return _mat4( 1101 | m[0][0] * p.m[0][0] + m[1][0] * p.m[0][1] + m[2][0] * p.m[0][2] + m[3][0] * p.m[0][3], 1102 | m[0][0] * p.m[1][0] + m[1][0] * p.m[1][1] + m[2][0] * p.m[1][2] + m[3][0] * p.m[1][3], 1103 | m[0][0] * p.m[2][0] + m[1][0] * p.m[2][1] + m[2][0] * p.m[2][2] + m[3][0] * p.m[2][3], 1104 | m[0][0] * p.m[3][0] + m[1][0] * p.m[3][1] + m[2][0] * p.m[3][2] + m[3][0] * p.m[3][3], 1105 | m[0][1] * p.m[0][0] + m[1][1] * p.m[0][1] + m[2][1] * p.m[0][2] + m[3][1] * p.m[0][3], 1106 | m[0][1] * p.m[1][0] + m[1][1] * p.m[1][1] + m[2][1] * p.m[1][2] + m[3][1] * p.m[1][3], 1107 | m[0][1] * p.m[2][0] + m[1][1] * p.m[2][1] + m[2][1] * p.m[2][2] + m[3][1] * p.m[2][3], 1108 | m[0][1] * p.m[3][0] + m[1][1] * p.m[3][1] + m[2][1] * p.m[3][2] + m[3][1] * p.m[3][3], 1109 | m[0][2] * p.m[0][0] + m[1][2] * p.m[0][1] + m[2][2] * p.m[0][2] + m[3][2] * p.m[0][3], 1110 | m[0][2] * p.m[1][0] + m[1][2] * p.m[1][1] + m[2][2] * p.m[1][2] + m[3][2] * p.m[1][3], 1111 | m[0][2] * p.m[2][0] + m[1][2] * p.m[2][1] + m[2][2] * p.m[2][2] + m[3][2] * p.m[2][3], 1112 | m[0][2] * p.m[3][0] + m[1][2] * p.m[3][1] + m[2][2] * p.m[3][2] + m[3][2] * p.m[3][3], 1113 | m[0][3] * p.m[0][0] + m[1][3] * p.m[0][1] + m[2][3] * p.m[0][2] + m[3][3] * p.m[0][3], 1114 | m[0][3] * p.m[1][0] + m[1][3] * p.m[1][1] + m[2][3] * p.m[1][2] + m[3][3] * p.m[1][3], 1115 | m[0][3] * p.m[2][0] + m[1][3] * p.m[2][1] + m[2][3] * p.m[2][2] + m[3][3] * p.m[2][3], 1116 | m[0][3] * p.m[3][0] + m[1][3] * p.m[3][1] + m[2][3] * p.m[3][2] + m[3][3] * p.m[3][3]); 1117 | } 1118 | 1119 | template 1120 | _vec4 _mat4::operator* (const _vec4& vec) const 1121 | { 1122 | return _vec4( 1123 | T(m[0][0] * vec.x + m[1][0] * vec.y + m[2][0] * vec.z + m[3][0] * vec.w), 1124 | T(m[0][1] * vec.x + m[1][1] * vec.y + m[2][1] * vec.z + m[3][1] * vec.w), 1125 | T(m[0][2] * vec.x + m[1][2] * vec.y + m[2][2] * vec.z + m[3][2] * vec.w), 1126 | T(m[0][3] * vec.x + m[1][3] * vec.y + m[2][3] * vec.z + m[3][3] * vec.w)); 1127 | } 1128 | 1129 | _mat4 _mat4::operator* (const matReal n) const 1130 | { 1131 | return _mat4( 1132 | m[0][0] * n, m[0][1] * n, m[0][2] * n, m[0][3] * n, 1133 | m[1][0] * n, m[1][1] * n, m[1][2] * n, m[1][3] * n, 1134 | m[2][0] * n, m[2][1] * n, m[2][2] * n, m[2][3] * n, 1135 | m[3][0] * n, m[3][1] * n, m[3][2] * n, m[3][3] * n); 1136 | } 1137 | 1138 | _mat4 _mat4::operator+ (const mat4& p) const 1139 | { 1140 | return _mat4( 1141 | m[0][0] + p.m[0][0], m[0][1] + p.m[0][1], 1142 | m[0][2] + p.m[0][2], m[0][3] + p.m[0][3], 1143 | m[1][0] + p.m[1][0], m[1][1] + p.m[1][1], 1144 | m[1][2] + p.m[1][2], m[1][3] + p.m[1][3], 1145 | m[2][0] + p.m[2][0], m[2][1] + p.m[2][1], 1146 | m[2][2] + p.m[2][2], m[2][3] + p.m[2][3], 1147 | m[3][0] + p.m[3][0], m[3][1] + p.m[3][1], 1148 | m[3][2] + p.m[3][2], m[3][3] + p.m[3][3]); 1149 | } 1150 | 1151 | _mat4 _mat4::operator- (const mat4& p) const 1152 | { 1153 | return _mat4( 1154 | m[0][0] - p.m[0][0], m[0][1] - p.m[0][1], 1155 | m[0][2] - p.m[0][2], m[0][3] - p.m[0][3], 1156 | m[1][0] - p.m[1][0], m[1][1] - p.m[1][1], 1157 | m[1][2] - p.m[1][2], m[1][3] - p.m[1][3], 1158 | m[2][0] - p.m[2][0], m[2][1] - p.m[2][1], 1159 | m[2][2] - p.m[2][2], m[2][3] - p.m[2][3], 1160 | m[3][0] - p.m[3][0], m[3][1] - p.m[3][1], 1161 | m[3][2] - p.m[3][2], m[3][3] - p.m[3][3]); 1162 | } 1163 | 1164 | _mat4 _mat4::operator / (const matReal n) const 1165 | { 1166 | return _mat4( 1167 | m[0][0] / n, m[0][1] / n, m[0][2] / n, m[0][3] / n, 1168 | m[1][0] / n, m[1][1] / n, m[1][2] / n, m[1][3] / n, 1169 | m[2][0] / n, m[2][1] / n, m[2][2] / n, m[2][3] / n, 1170 | m[3][0] / n, m[3][1] / n, m[3][2] / n, m[3][3] / n); 1171 | } 1172 | 1173 | _mat4 _mat4::operator+ (const matReal n) const 1174 | { 1175 | return _mat4( 1176 | m[0][0] + n, m[0][1] + n, m[0][2] + n, m[0][3] + n, 1177 | m[1][0] + n, m[1][1] + n, m[1][2] + n, m[1][3] + n, 1178 | m[2][0] + n, m[2][1] + n, m[2][2] + n, m[2][3] + n, 1179 | m[3][0] + n, m[3][1] + n, m[3][2] + n, m[3][3] + n); 1180 | } 1181 | 1182 | _mat4 _mat4::operator- (const matReal n) const 1183 | { 1184 | return _mat4( 1185 | m[0][0] - n, m[0][1] - n, m[0][2] - n, m[0][3] - n, 1186 | m[1][0] - n, m[1][1] - n, m[1][2] - n, m[1][3] - n, 1187 | m[2][0] - n, m[2][1] - n, m[2][2] - n, m[2][3] - n, 1188 | m[3][0] - n, m[3][1] - n, m[3][2] - n, m[3][3] - n); 1189 | } 1190 | 1191 | void _mat4::operator *= (const _mat4& p) 1192 | { 1193 | matReal t1, t2, t3, t4; 1194 | t1 = m[0][0] * p.m[0][0] + m[1][0] * p.m[0][1] + m[2][0] * p.m[0][2] + m[3][0] * p.m[0][3]; 1195 | t2 = m[0][0] * p.m[1][0] + m[1][0] * p.m[1][1] + m[2][0] * p.m[1][2] + m[3][0] * p.m[1][3]; 1196 | t3 = m[0][0] * p.m[2][0] + m[1][0] * p.m[2][1] + m[2][0] * p.m[2][2] + m[3][0] * p.m[2][3]; 1197 | t4 = m[0][0] * p.m[3][0] + m[1][0] * p.m[3][1] + m[2][0] * p.m[3][2] + m[3][0] * p.m[3][3]; 1198 | m[0][0] = t1; m[1][0] = t2; m[2][0] = t3; m[3][0] = t4; 1199 | t1 = m[0][1] * p.m[0][0] + m[1][1] * p.m[0][1] + m[2][1] * p.m[0][2] + m[3][1] * p.m[0][3]; 1200 | t2 = m[0][1] * p.m[1][0] + m[1][1] * p.m[1][1] + m[2][1] * p.m[1][2] + m[3][1] * p.m[1][3]; 1201 | t3 = m[0][1] * p.m[2][0] + m[1][1] * p.m[2][1] + m[2][1] * p.m[2][2] + m[3][1] * p.m[2][3]; 1202 | t4 = m[0][1] * p.m[3][0] + m[1][1] * p.m[3][1] + m[2][1] * p.m[3][2] + m[3][1] * p.m[3][3]; 1203 | m[0][1] = t1; m[1][1] = t2; m[2][1] = t3; m[3][1] = t4; 1204 | t1 = m[0][2] * p.m[0][0] + m[1][2] * p.m[0][1] + m[2][2] * p.m[0][2] + m[3][2] * p.m[0][3]; 1205 | t2 = m[0][2] * p.m[1][0] + m[1][2] * p.m[1][1] + m[2][2] * p.m[1][2] + m[3][2] * p.m[1][3]; 1206 | t3 = m[0][2] * p.m[2][0] + m[1][2] * p.m[2][1] + m[2][2] * p.m[2][2] + m[3][2] * p.m[2][3]; 1207 | t4 = m[0][2] * p.m[3][0] + m[1][2] * p.m[3][1] + m[2][2] * p.m[3][2] + m[3][2] * p.m[3][3]; 1208 | m[0][2] = t1; m[1][2] = t2; m[2][2] = t3; m[3][2] = t4; 1209 | t1 = m[0][3] * p.m[0][0] + m[1][3] * p.m[0][1] + m[2][3] * p.m[0][2] + m[3][3] * p.m[0][3]; 1210 | t2 = m[0][3] * p.m[1][0] + m[1][3] * p.m[1][1] + m[2][3] * p.m[1][2] + m[3][3] * p.m[1][3]; 1211 | t3 = m[0][3] * p.m[2][0] + m[1][3] * p.m[2][1] + m[2][3] * p.m[2][2] + m[3][3] * p.m[2][3]; 1212 | t4 = m[0][3] * p.m[3][0] + m[1][3] * p.m[3][1] + m[2][3] * p.m[3][2] + m[3][3] * p.m[3][3]; 1213 | m[0][3] = t1; m[1][3] = t2; m[2][3] = t3; m[3][3] = t4; 1214 | } 1215 | 1216 | void _mat4::operator *= (const matReal n) 1217 | { 1218 | m[0][0] *= n; m[0][1] *= n; m[0][2] *= n; m[0][3] *= n; 1219 | m[1][0] *= n; m[1][1] *= n; m[1][2] *= n; m[1][3] *= n; 1220 | m[2][0] *= n; m[2][1] *= n; m[2][2] *= n; m[2][3] *= n; 1221 | m[3][0] *= n; m[3][1] *= n; m[3][2] *= n; m[3][3] *= n; 1222 | } 1223 | 1224 | void _mat4::operator /= (const matReal n) 1225 | { 1226 | m[0][0] /= n; m[0][1] /= n; m[0][2] /= n; m[0][3] /= n; 1227 | m[1][0] /= n; m[1][1] /= n; m[1][2] /= n; m[1][3] /= n; 1228 | m[2][0] /= n; m[2][1] /= n; m[2][2] /= n; m[2][3] /= n; 1229 | m[3][0] /= n; m[3][1] /= n; m[3][2] /= n; m[3][3] /= n; 1230 | } 1231 | 1232 | void _mat4::operator += (const _mat4& p) 1233 | { 1234 | m[0][0] += p.m[0][0]; m[0][1] += p.m[0][1]; 1235 | m[0][2] += p.m[0][2]; m[0][3] += p.m[0][3]; 1236 | m[1][0] += p.m[1][0]; m[1][1] += p.m[1][1]; 1237 | m[1][2] += p.m[1][2]; m[1][3] += p.m[1][3]; 1238 | m[2][0] += p.m[2][0]; m[2][1] += p.m[2][1]; 1239 | m[2][2] += p.m[2][2]; m[2][3] += p.m[2][3]; 1240 | m[3][0] += p.m[3][0]; m[3][1] += p.m[3][1]; 1241 | m[3][2] += p.m[3][2]; m[3][3] += p.m[3][3]; 1242 | } 1243 | 1244 | void _mat4::operator += (const matReal n) 1245 | { 1246 | m[0][0] += n; m[0][1] += n; m[0][2] += n; m[0][3] += n; 1247 | m[1][0] += n; m[1][1] += n; m[1][2] += n; m[1][3] += n; 1248 | m[2][0] += n; m[2][1] += n; m[2][2] += n; m[2][3] += n; 1249 | m[3][0] += n; m[3][1] += n; m[3][2] += n; m[3][3] += n; 1250 | } 1251 | 1252 | void _mat4::operator -= (const _mat4& p) 1253 | { 1254 | m[0][0] -= p.m[0][0]; m[0][1] -= p.m[0][1]; 1255 | m[0][2] -= p.m[0][2]; m[0][3] -= p.m[0][3]; 1256 | m[1][0] -= p.m[1][0]; m[1][1] -= p.m[1][1]; 1257 | m[1][2] -= p.m[1][2]; m[1][3] -= p.m[1][3]; 1258 | m[2][0] -= p.m[2][0]; m[2][1] -= p.m[2][1]; 1259 | m[2][2] -= p.m[2][2]; m[2][3] -= p.m[2][3]; 1260 | m[3][0] -= p.m[3][0]; m[3][1] -= p.m[3][1]; 1261 | m[3][2] -= p.m[3][2]; m[3][3] -= p.m[3][3]; 1262 | } 1263 | 1264 | void _mat4::operator -= (const matReal n) 1265 | { 1266 | m[0][0] -= n; m[0][1] -= n; m[0][2] -= n; m[0][3] -= n; 1267 | m[1][0] -= n; m[1][1] -= n; m[1][2] -= n; m[1][3] -= n; 1268 | m[2][0] -= n; m[2][1] -= n; m[2][2] -= n; m[2][3] -= n; 1269 | m[3][0] -= n; m[3][1] -= n; m[3][2] -= n; m[3][3] -= n; 1270 | } 1271 | 1272 | _mat4& _mat4::initRotation(const matReal angle, const matReal x, 1273 | const matReal y, const matReal z) 1274 | { 1275 | matReal c = cos(angle); 1276 | matReal s = sin(angle); 1277 | matReal iC = matScalarOne - c; 1278 | 1279 | m[0][0] = x*x + (matScalarOne - x*x)*c; 1280 | m[0][1] = iC*x*y + z*s; 1281 | m[0][2] = iC*x*z - y*s; 1282 | m[0][3] = matScalarNull; 1283 | m[1][0] = iC*x*y - z*s; 1284 | m[1][1] = y*y + (matScalarOne - y*y)*c; 1285 | m[1][2] = iC*y*z + x*s; 1286 | m[1][3] = matScalarNull; 1287 | m[2][0] = iC*x*z + y*s; 1288 | m[2][1] = iC*y*z - x*s; 1289 | m[2][2] = z*z + (matScalarOne - z*z)*c; 1290 | m[2][3] = matScalarNull; 1291 | m[3][0] = matScalarNull; 1292 | m[3][1] = matScalarNull; 1293 | m[3][2] = matScalarNull; 1294 | m[3][3] = matScalarOne; 1295 | 1296 | return *this; 1297 | } 1298 | 1299 | bool _mat4::operator == (const _mat4& p) const 1300 | { 1301 | return 1302 | m[0][0] == p.m[0][0] && m[0][1] == p.m[0][1] && 1303 | m[0][2] == p.m[0][2] && m[0][3] == p.m[0][3] && 1304 | m[1][0] == p.m[1][0] && m[1][1] == p.m[1][1] && 1305 | m[1][2] == p.m[1][2] && m[1][3] == p.m[1][3] && 1306 | m[2][0] == p.m[2][0] && m[2][1] == p.m[2][1] && 1307 | m[2][2] == p.m[2][2] && m[2][3] == p.m[2][3] && 1308 | m[3][0] == p.m[3][0] && m[3][1] == p.m[3][1] && 1309 | m[3][2] == p.m[3][2] && m[3][3] == p.m[3][3]; 1310 | } 1311 | 1312 | bool _mat4::operator != (const _mat4& p) const 1313 | { 1314 | return 1315 | m[0][0] != p.m[0][0] || m[0][1] != p.m[0][1] || 1316 | m[0][2] != p.m[0][2] || m[0][3] != p.m[0][3] || 1317 | m[1][0] != p.m[1][0] || m[1][1] != p.m[1][1] || 1318 | m[1][2] != p.m[1][2] || m[1][3] != p.m[1][3] || 1319 | m[2][0] != p.m[2][0] || m[2][1] != p.m[2][1] || 1320 | m[2][2] != p.m[2][2] || m[2][3] != p.m[2][3] || 1321 | m[3][0] != p.m[3][0] || m[3][1] != p.m[3][1] || 1322 | m[3][2] != p.m[3][2] || m[3][3] != p.m[3][3]; 1323 | } 1324 | 1325 | _mat4& _mat4::initTranslation(const matReal x, const matReal y, const matReal z) 1326 | { 1327 | reset(); 1328 | m[3][0] = x; 1329 | m[3][1] = y; 1330 | m[3][2] = z; 1331 | return *this; 1332 | } 1333 | 1334 | _mat4& _mat4::initScale(const matReal x, const matReal y, const matReal z) 1335 | { 1336 | reset(); 1337 | m[0][0] = x; 1338 | m[1][1] = y; 1339 | m[2][2] = z; 1340 | return *this; 1341 | } 1342 | 1343 | inline _mat4& mat4::initRotation(matReal angle, const vec3& axis) 1344 | { 1345 | return initRotation(angle, axis.x, axis.y, axis.z); 1346 | } 1347 | 1348 | inline _mat4& _mat4::initTranslation(vec3& trans) 1349 | { 1350 | return initTranslation(trans.x, trans.y, trans.z); 1351 | } 1352 | 1353 | inline _mat4& _mat4::initScale(vec3& scale) 1354 | { 1355 | return initScale(scale.x, scale.y, scale.z); 1356 | } 1357 | 1358 | _mat4& _mat4::initProjection(const matReal fov, const matReal width, 1359 | const matReal height, const matReal znear, const matReal zfar) 1360 | { 1361 | reset(); 1362 | 1363 | matReal tanHalfFOV = tan(fov / matScalarTwo); 1364 | m[1][1] = matScalarOne / tanHalfFOV; 1365 | m[0][0] = -m[1][1] / (width / height); //negative? 1366 | m[2][2] = zfar*(matScalarOne / (zfar - znear)); 1367 | m[3][2] = (-zfar*znear)*(matScalarOne / (zfar - znear)); 1368 | m[2][3] = matScalarOne; 1369 | m[3][3] = matScalarNull; 1370 | return *this; 1371 | } 1372 | 1373 | _mat4& _mat4::initOrthoProjection(const matReal left_, const matReal right_, 1374 | const matReal bottom_, const matReal top_, const matReal near_, const matReal far_) 1375 | { 1376 | reset(); 1377 | m[0][0] = matScalarTwo / (right_ - left_); 1378 | m[1][1] = matScalarTwo / (top_ - bottom_); 1379 | m[2][2] = -matScalarTwo / (far_ - near_); 1380 | m[3][0] = -((right_ + left_) / (right_ - left_)); 1381 | m[3][1] = -((top_ + bottom_) / (top_ - bottom_)); 1382 | m[3][2] = (far_ + near_) / (far_ - near_); 1383 | return *this; 1384 | } 1385 | 1386 | _mat4 _mat4::getTranspose() 1387 | { 1388 | return _mat4(m[0][0], m[0][1], m[0][2], m[0][3], 1389 | m[1][0], m[1][1], m[1][2], m[1][3], 1390 | m[2][0], m[2][1], m[2][2], m[2][3], 1391 | m[3][0], m[3][1], m[3][2], m[3][3]); 1392 | } 1393 | 1394 | _mat3::_mat3() 1395 | { 1396 | reset(); 1397 | } 1398 | 1399 | _mat3::_mat3(const matReal n) 1400 | { 1401 | reset(); 1402 | m[0][0] = n; 1403 | m[1][1] = n; 1404 | m[2][2] = n; 1405 | } 1406 | 1407 | _mat3::_mat3(const matReal m00, const matReal m10, const matReal m20, 1408 | const matReal m01, const matReal m11, const matReal m21, 1409 | const matReal m02, const matReal m12, const matReal m22) 1410 | { 1411 | m[0][0] = m00; m[0][1] = m01; m[0][2] = m02; 1412 | m[1][0] = m10; m[1][1] = m11; m[1][2] = m12; 1413 | m[2][0] = m20; m[2][1] = m21; m[2][2] = m22; 1414 | } 1415 | 1416 | void _mat3::reset() 1417 | { 1418 | m[0][0] = 1; m[0][1] = 0; m[0][2] = 0; 1419 | m[1][0] = 0; m[1][1] = 1; m[1][2] = 0; 1420 | m[2][0] = 0; m[2][1] = 0; m[2][2] = 1; 1421 | } 1422 | 1423 | _mat3 _mat3::operator * (const _mat3& p) const 1424 | { 1425 | return _mat3( 1426 | m[0][0] * p.m[0][0] + m[1][0] * p.m[0][1] + m[2][0] * p.m[0][2], 1427 | m[0][0] * p.m[1][0] + m[1][0] * p.m[1][1] + m[2][0] * p.m[1][2], 1428 | m[0][0] * p.m[2][0] + m[1][0] * p.m[2][1] + m[2][0] * p.m[2][2], 1429 | 1430 | m[0][1] * p.m[0][0] + m[1][1] * p.m[0][1] + m[2][1] * p.m[0][2], 1431 | m[0][1] * p.m[1][0] + m[1][1] * p.m[1][1] + m[2][1] * p.m[1][2], 1432 | m[0][1] * p.m[2][0] + m[1][1] * p.m[2][1] + m[2][1] * p.m[2][2], 1433 | 1434 | m[0][2] * p.m[0][0] + m[1][2] * p.m[0][1] + m[2][2] * p.m[0][2], 1435 | m[0][2] * p.m[1][0] + m[1][2] * p.m[1][1] + m[2][2] * p.m[1][2], 1436 | m[0][2] * p.m[2][0] + m[1][2] * p.m[2][1] + m[2][2] * p.m[2][2]); 1437 | } 1438 | 1439 | vec3 _mat3::operator* (const vec3& vec) const 1440 | { 1441 | return vec3( 1442 | m[0][0] * vec.x + m[1][0] * vec.y + m[2][0] * vec.z, 1443 | m[0][1] * vec.x + m[1][1] * vec.y + m[2][1] * vec.z, 1444 | m[0][2] * vec.x + m[1][2] * vec.y + m[2][2] * vec.z); 1445 | } 1446 | 1447 | _mat3 _mat3::operator* (const matReal n) const 1448 | { 1449 | return _mat3( 1450 | m[0][0] * n, m[0][1] * n, m[0][2] * n, 1451 | m[1][0] * n, m[1][1] * n, m[1][2] * n, 1452 | m[2][0] * n, m[2][1] * n, m[2][2] * n); 1453 | } 1454 | 1455 | _mat3 _mat3::operator+ (const _mat3& p) const 1456 | { 1457 | return _mat3( 1458 | m[0][0] + p.m[0][0], m[0][1] + p.m[0][1], m[0][2] + p.m[0][2], 1459 | m[1][1] + p.m[1][1], m[1][0] + p.m[1][0], m[1][2] + p.m[1][2], 1460 | m[2][0] + p.m[2][0], m[2][1] + p.m[2][1], m[2][2] + p.m[2][2]); 1461 | } 1462 | 1463 | _mat3 _mat3::operator- (const _mat3& p) const 1464 | { 1465 | return _mat3( 1466 | m[0][0] - p.m[0][0], m[0][1] - p.m[0][1], m[0][2] - p.m[0][2], 1467 | m[1][1] - p.m[1][1], m[1][0] - p.m[1][0], m[1][2] - p.m[1][2], 1468 | m[2][0] - p.m[2][0], m[2][1] - p.m[2][1], m[2][2] - p.m[2][2]); 1469 | } 1470 | 1471 | _mat3 _mat3::operator / (const matReal n) const 1472 | { 1473 | return _mat3( 1474 | m[0][0] / n, m[0][1] / n, m[0][2] / n, 1475 | m[1][0] / n, m[1][1] / n, m[1][2] / n, 1476 | m[2][0] / n, m[2][1] / n, m[2][2] / n); 1477 | } 1478 | 1479 | _mat3 _mat3::operator+ (const matReal n) const 1480 | { 1481 | return _mat3( 1482 | m[0][0] + n, m[0][1] + n, m[0][2] + n, 1483 | m[1][0] + n, m[1][1] + n, m[1][2] + n, 1484 | m[2][0] + n, m[2][1] + n, m[2][2] + n); 1485 | } 1486 | 1487 | _mat3 _mat3::operator- (const matReal n) const 1488 | { 1489 | return _mat3( 1490 | m[0][0] - n, m[0][1] - n, m[0][2] - n, 1491 | m[1][0] - n, m[1][1] - n, m[1][2] - n, 1492 | m[2][0] - n, m[2][1] - n, m[2][2] - n); 1493 | } 1494 | 1495 | void _mat3::operator *= (const _mat3& p) 1496 | { 1497 | matReal t1, t2, t3; 1498 | t1 = m[0][0] * p.m[0][0] + m[1][0] * p.m[0][1] + m[2][0] * p.m[0][2]; 1499 | t2 = m[0][0] * p.m[1][0] + m[1][0] * p.m[1][1] + m[2][0] * p.m[1][2]; 1500 | t3 = m[0][0] * p.m[2][0] + m[1][0] * p.m[2][1] + m[2][0] * p.m[2][2]; 1501 | m[0][0] = t1; m[1][0] = t2; m[2][0] = t3; 1502 | t1 = m[0][1] * p.m[0][0] + m[1][1] * p.m[0][1] + m[2][1] * p.m[0][2]; 1503 | t2 = m[0][1] * p.m[1][0] + m[1][1] * p.m[1][1] + m[2][1] * p.m[1][2]; 1504 | t3 = m[0][1] * p.m[2][0] + m[1][1] * p.m[2][1] + m[2][1] * p.m[2][2]; 1505 | m[0][1] = t1; m[1][1] = t2; m[2][1] = t3; 1506 | t1 = m[0][2] * p.m[0][0] + m[1][2] * p.m[0][1] + m[2][2] * p.m[0][2]; 1507 | t2 = m[0][2] * p.m[1][0] + m[1][2] * p.m[1][1] + m[2][2] * p.m[1][2]; 1508 | t3 = m[0][2] * p.m[2][0] + m[1][2] * p.m[2][1] + m[2][2] * p.m[2][2]; 1509 | m[0][2] = t1; m[1][2] = t2; m[2][2] = t3; 1510 | } 1511 | 1512 | void _mat3::operator *= (const matReal n) 1513 | { 1514 | m[0][0] *= n; m[0][1] *= n; m[0][2] *= n; 1515 | m[1][0] *= n; m[1][1] *= n; m[1][2] *= n; 1516 | m[2][0] *= n; m[2][1] *= n; m[2][2] *= n; 1517 | } 1518 | 1519 | void _mat3::operator /= (const matReal n) 1520 | { 1521 | m[0][0] /= n; m[0][1] /= n; m[0][2] /= n; 1522 | m[1][0] /= n; m[1][1] /= n; m[1][2] /= n; 1523 | m[2][0] /= n; m[2][1] /= n; m[2][2] /= n; 1524 | } 1525 | 1526 | void _mat3::operator += (const _mat3& p) 1527 | { 1528 | m[0][0] += p.m[0][0]; m[0][1] += p.m[0][1]; m[0][2] += p.m[0][2]; 1529 | m[1][0] += p.m[1][0]; m[1][1] += p.m[1][1]; m[1][2] += p.m[1][2]; 1530 | m[2][0] += p.m[2][0]; m[2][1] += p.m[2][1]; m[2][2] += p.m[2][2]; 1531 | } 1532 | 1533 | void _mat3::operator += (const matReal n) 1534 | { 1535 | m[0][0] += n; m[0][1] += n; m[0][2] += n; 1536 | m[1][0] += n; m[1][1] += n; m[1][2] += n; 1537 | m[2][0] += n; m[2][1] += n; m[2][2] += n; 1538 | } 1539 | 1540 | void _mat3::operator -= (const _mat3& p) 1541 | { 1542 | m[0][0] -= p.m[0][0]; m[0][1] -= p.m[0][1]; m[0][2] -= p.m[0][2]; 1543 | m[1][0] -= p.m[1][0]; m[1][1] -= p.m[1][1]; m[1][2] -= p.m[1][2]; 1544 | m[2][0] -= p.m[2][0]; m[2][1] -= p.m[2][1]; m[2][2] -= p.m[2][2]; 1545 | } 1546 | 1547 | void _mat3::operator -= (const matReal n) 1548 | { 1549 | m[0][0] -= n; m[0][1] -= n; m[0][2] -= n; 1550 | m[1][0] -= n; m[1][1] -= n; m[1][2] -= n; 1551 | m[2][0] -= n; m[2][1] -= n; m[2][2] -= n; 1552 | } 1553 | 1554 | bool _mat3::operator == (const _mat3& p) const 1555 | { 1556 | return 1557 | m[0][0] == p.m[0][0] && m[0][1] == p.m[0][1] && m[0][2] == p.m[0][2] && 1558 | m[1][0] == p.m[1][0] && m[1][1] == p.m[1][1] && m[1][2] == p.m[1][2] && 1559 | m[2][0] == p.m[2][0] && m[2][1] == p.m[2][1] && m[2][2] == p.m[2][2]; 1560 | } 1561 | 1562 | bool _mat3::operator != (const _mat3& p) const 1563 | { 1564 | return 1565 | m[0][0] != p.m[0][0] || m[0][1] != p.m[0][1] || m[0][2] != p.m[0][2] || 1566 | m[1][0] != p.m[1][0] || m[1][1] != p.m[1][1] || m[1][2] != p.m[1][2] || 1567 | m[2][0] != p.m[2][0] || m[2][1] != p.m[2][1] || m[2][2] != p.m[2][2]; 1568 | } 1569 | 1570 | _mat3 _mat3::getTranspose() const 1571 | { 1572 | return _mat3(m[0][0], m[0][1], m[0][2], 1573 | m[1][0], m[1][1], m[1][2], 1574 | m[2][0], m[2][1], m[2][2]); 1575 | } 1576 | 1577 | matReal _mat3::det() const 1578 | { 1579 | return (m[0][0]*m[1][1]*m[2][2] + m[1][0]*m[2][1]*m[0][2] + m[2][0]*m[0][1]*m[1][2])- 1580 | (m[2][0]*m[1][1]*m[0][2] + m[0][0]*m[2][1]*m[1][2] + m[1][0]*m[0][1]*m[2][2]); 1581 | } 1582 | 1583 | _mat3 _mat3::getInverse() const 1584 | { 1585 | matReal determinent = det(); 1586 | if(determinent==0) 1587 | return _mat3(); 1588 | 1589 | matReal a = m[0][0]; 1590 | matReal b = m[1][0]; 1591 | matReal c = m[2][0]; 1592 | matReal d = m[0][1]; 1593 | matReal e = m[1][1]; 1594 | matReal f = m[2][1]; 1595 | matReal g = m[0][2]; 1596 | matReal h = m[1][2]; 1597 | matReal i = m[2][2]; 1598 | 1599 | return _mat3(e*i-f*h,f*g-d*i,d*h-e*g, 1600 | c*h-b*i,a*i-c*g,b*g-a*h, 1601 | b*f-c*e,c*d-a*f,a*e-b*d)*(1/determinent); 1602 | } 1603 | 1604 | _mat2::_mat2() 1605 | { 1606 | reset(); 1607 | } 1608 | 1609 | _mat2::_mat2(const matReal n) 1610 | { 1611 | reset(); 1612 | m[0][0] = n; m[1][1] = n; 1613 | } 1614 | 1615 | _mat2::_mat2(const matReal m00, const matReal m10, 1616 | const matReal m01, const matReal m11) 1617 | { 1618 | m[0][0] = m00; m[0][1] = m01; 1619 | m[1][0] = m10; m[1][1] = m11; 1620 | } 1621 | 1622 | void _mat2::reset() 1623 | { 1624 | m[0][0] = 1; m[0][1] = 0; 1625 | m[1][0] = 0; m[1][1] = 1; 1626 | } 1627 | 1628 | _mat2 _mat2::operator * (const _mat2& p) const 1629 | { 1630 | return _mat2( 1631 | m[0][0] * p.m[0][0] + m[1][0] * p.m[0][1], 1632 | m[0][0] * p.m[1][0] + m[1][0] * p.m[1][1], 1633 | m[0][1] * p.m[0][0] + m[1][1] * p.m[0][1], 1634 | m[0][1] * p.m[1][0] + m[1][1] * p.m[1][1]); 1635 | } 1636 | 1637 | vec2 _mat2::operator* (const vec2& vec) const 1638 | { 1639 | return vec2( 1640 | m[0][0] * vec.x + m[1][0] * vec.y, 1641 | m[0][1] * vec.x + m[1][1] * vec.y); 1642 | } 1643 | 1644 | _mat2 _mat2::operator* (const matReal n) const 1645 | { 1646 | return _mat2( 1647 | m[0][0] * n, m[0][1] * n, 1648 | m[1][0] * n, m[1][1] * n); 1649 | } 1650 | 1651 | _mat2 _mat2::operator+ (const _mat2& p) const 1652 | { 1653 | return _mat2( 1654 | m[0][0] + p.m[0][0], m[0][1] + p.m[0][1], 1655 | m[1][0] + p.m[1][0], m[1][1] + p.m[1][1]); 1656 | } 1657 | 1658 | _mat2 _mat2::operator- (const _mat2& p) const 1659 | { 1660 | return _mat2( 1661 | m[0][0] - p.m[0][0], m[0][1] - p.m[0][1], 1662 | m[1][0] - p.m[1][0], m[1][1] - p.m[1][1]); 1663 | } 1664 | 1665 | _mat2 _mat2::operator / (const matReal n) const 1666 | { 1667 | return _mat2( 1668 | m[0][0] / n, m[0][1] / n, 1669 | m[1][0] / n, m[1][1] / n); 1670 | } 1671 | 1672 | _mat2 _mat2::operator+ (const matReal n) const 1673 | { 1674 | return _mat2( 1675 | m[0][0] + n, m[0][1] + n, 1676 | m[1][0] + n, m[1][1] + n); 1677 | } 1678 | 1679 | _mat2 _mat2::operator- (const matReal n) const 1680 | { 1681 | return _mat2( 1682 | m[0][0] - n, m[0][1] - n, 1683 | m[1][0] - n, m[1][1] - n); 1684 | } 1685 | 1686 | void _mat2::operator *= (const _mat2& p) 1687 | { 1688 | matReal t1, t2; 1689 | t1 = m[0][0] * p.m[0][0] + m[1][0] * p.m[0][1]; 1690 | t2 = m[0][0] * p.m[1][0] + m[1][0] * p.m[1][1]; 1691 | m[0][0] = t1; m[1][0] = t2; 1692 | t1 = m[0][1] * p.m[0][0] + m[1][1] * p.m[0][1]; 1693 | t2 = m[0][1] * p.m[1][0] + m[1][1] * p.m[1][1]; 1694 | m[0][1] = t1; m[1][1] = t2; 1695 | } 1696 | 1697 | void _mat2::operator *= (const matReal n) 1698 | { 1699 | m[0][0] *= n; m[0][1] *= n; 1700 | m[1][0] *= n; m[1][1] *= n; 1701 | } 1702 | 1703 | void _mat2::operator /= (const matReal n) 1704 | { 1705 | m[0][0] /= n; m[0][1] /= n; 1706 | m[1][0] /= n; m[1][1] /= n; 1707 | } 1708 | 1709 | void _mat2::operator += (const _mat2& p) 1710 | { 1711 | m[0][0] += p.m[0][0]; m[0][1] += p.m[0][1]; 1712 | m[1][0] += p.m[1][0]; m[1][1] += p.m[1][1]; 1713 | } 1714 | 1715 | void _mat2::operator += (const matReal n) 1716 | { 1717 | m[0][0] += n; m[0][1] += n; 1718 | m[1][0] += n; m[1][1] += n; 1719 | } 1720 | 1721 | void _mat2::operator -= (const _mat2& p) 1722 | { 1723 | m[0][0] -= p.m[0][0]; m[0][1] -= p.m[0][1]; 1724 | m[1][0] -= p.m[1][0]; m[1][1] -= p.m[1][1]; 1725 | } 1726 | 1727 | void _mat2::operator -= (const matReal n) 1728 | { 1729 | m[0][0] -= n; m[0][1] -= n; 1730 | m[1][0] -= n; m[1][1] -= n; 1731 | } 1732 | 1733 | bool _mat2::operator == (const _mat2& p) const 1734 | { 1735 | return 1736 | m[0][0] == p.m[0][0] && m[0][1] == p.m[0][1] && 1737 | m[1][0] == p.m[1][0] && m[1][1] == p.m[1][1]; 1738 | } 1739 | 1740 | bool _mat2::operator != (const _mat2& p) const 1741 | { 1742 | return 1743 | m[0][0] != p.m[0][0] || m[0][1] != p.m[0][1] || 1744 | m[1][0] != p.m[1][0] || m[1][1] != p.m[1][1]; 1745 | } 1746 | 1747 | _mat2 _mat2::getTranspose() 1748 | { 1749 | return _mat2(m[0][0], m[0][1], 1750 | m[1][0], m[1][1]); 1751 | } 1752 | 1753 | } 1754 | 1755 | //Force vector instantiatios for types: 1756 | 1757 | #define FORCE_VEC_INST(type) \ 1758 | template class tmp::_vec2; \ 1759 | template class tmp::_vec3; \ 1760 | template class tmp::_vec4; \ 1761 | template type dot(const tmp::_vec2&, const tmp::_vec2&); \ 1762 | template type dot(const tmp::_vec3&, const tmp::_vec3&); \ 1763 | template type dot(const tmp::_vec4&, const tmp::_vec4&); \ 1764 | template tmp::_vec3 cross(const tmp::_vec3&, const tmp::_vec3&); \ 1765 | 1766 | FORCE_VEC_INST(float) 1767 | FORCE_VEC_INST(int) 1768 | FORCE_VEC_INST(double) 1769 | FORCE_VEC_INST(long long) 1770 | FORCE_VEC_INST(short) 1771 | 1772 | 1773 | #undef FORCE_VEC_INST 1774 | 1775 | } 1776 | -------------------------------------------------------------------------------- /Primatte/matrixd.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | /* 4 | * A series of vec3{2,3,4} and mat{2,3,4} classes. 5 | * @author Anima. 6 | */ 7 | 8 | namespace math 9 | { 10 | //Affects vecX and matX 11 | 12 | #ifdef MATRIX_D_DOUBLE 13 | typedef double matReal; 14 | #else 15 | typedef float matReal; 16 | #endif 17 | 18 | #ifdef MATRIX_D_LONG 19 | typedef long long matInt; 20 | #else 21 | typedef int matInt; 22 | #endif 23 | 24 | namespace tmp 25 | { 26 | template 27 | class _vec2 28 | { 29 | public: 30 | T x, y; 31 | 32 | _vec2(); 33 | _vec2(const T x_, const T y_); 34 | explicit _vec2(const T n); 35 | matReal angle() const; 36 | T lengthSquared() const; 37 | matReal length() const; 38 | matReal distance(const _vec2& v) const; 39 | matReal proj(const _vec2& v) const; 40 | T distanceSquared(const _vec2& v) const; 41 | _vec2 operator * (const T n) const; 42 | _vec2 operator / (const T n) const; 43 | _vec2 operator + (const T n) const; 44 | _vec2 operator - (const T n) const; 45 | _vec2 operator + (const _vec2& vec) const; 46 | _vec2 operator - (const _vec2& vec) const; 47 | _vec2 operator * (const _vec2& vec) const; 48 | _vec2 operator / (const _vec2& vec) const; 49 | void operator *= (const T f); 50 | void operator /= (const T f); 51 | void operator += (const T f); 52 | void operator -= (const T f); 53 | void operator += (const _vec2& vec); 54 | void operator -= (const _vec2& vec); 55 | void operator *= (const _vec2& vec); 56 | void operator /= (const _vec2& vec); 57 | bool operator == (const _vec2& vec) const; 58 | bool operator == (T f) const; 59 | bool operator != (const _vec2& vec) const; 60 | bool operator != (T f) const; 61 | bool operator < (const _vec2& vec) const; 62 | bool operator <= (const _vec2& vec) const; 63 | bool operator > (const _vec2& vec) const; 64 | bool operator >= (const _vec2& vec) const; 65 | 66 | _vec2& normalize(); 67 | void reset(); 68 | 69 | _vec2 operator % (const T n) const; 70 | void operator %= (const T n); 71 | _vec2 operator % (const _vec2& vec) const; 72 | void operator %= (const _vec2& vec); 73 | 74 | 75 | _vec2 xy() const; _vec2 yx() const; 76 | }; 77 | 78 | template 79 | class _vec3 80 | { 81 | public: 82 | T x, y, z; 83 | 84 | _vec3(); 85 | _vec3(const T x_, const T y_, const T z_); 86 | _vec3(const _vec2& v, const T f); 87 | _vec3(const T f, const _vec2& v); 88 | explicit _vec3(const T f); 89 | T lengthSquared() const; 90 | matReal length() const; 91 | matReal distance(const _vec3& v) const; 92 | T distanceSquared(const _vec3& v) const; 93 | matReal proj(const _vec3& v) const; 94 | _vec3 operator * (const T n) const; 95 | _vec3 operator / (const T n) const; 96 | _vec3 operator + (const T n) const; 97 | _vec3 operator - (const T n) const; 98 | _vec3 operator + (const _vec3& vec) const; 99 | _vec3 operator - (const _vec3& vec) const; 100 | _vec3 operator * (const _vec3& vec) const; 101 | _vec3 operator / (const _vec3& vec) const; 102 | void operator *= (const T n); 103 | void operator /= (const T n); 104 | void operator += (const T n); 105 | void operator -= (const T n); 106 | void operator += (const _vec3& vec); 107 | void operator -= (const _vec3& vec); 108 | void operator *= (const _vec3& vec); 109 | void operator /= (const _vec3& vec); 110 | bool operator == (const _vec3& vec) const; 111 | bool operator == (T f) const; 112 | bool operator != (const _vec3& vec) const; 113 | bool operator != (T f) const; 114 | bool operator < (const _vec3& vec) const; 115 | bool operator <= (const _vec3& vec) const; 116 | bool operator > (const _vec3& vec) const; 117 | bool operator >= (const _vec3& vec) const; 118 | _vec3& normalize(); 119 | 120 | _vec3& rotate(const matReal angle, const _vec3& axis); 121 | 122 | _vec3 operator % (const T n) const; 123 | void operator %= (const T n); 124 | _vec3 operator % (const _vec3& vec) const; 125 | void operator %= (const _vec3& vec); 126 | 127 | 128 | void reset(); 129 | 130 | _vec3 xyz() const; _vec3 xzy() const; _vec3 yxz() const; 131 | _vec3 yzx() const; _vec3 zxy() const; _vec3 zyx() const; 132 | _vec2 xy() const; _vec2 yx() const; _vec2 xz() const; 133 | _vec2 zx() const; _vec2 yz() const; _vec2 zy() const; 134 | }; 135 | 136 | template 137 | class _vec4 138 | { 139 | public: 140 | T x, y, z, w; 141 | 142 | _vec4(); 143 | _vec4(const T x_, const T y_, const T z_, const T w_); 144 | _vec4(const _vec2& v1, const _vec2& v2); 145 | _vec4(const T f1, const T f2, const _vec2& v); 146 | _vec4(const _vec2& v, const T f1, const T f2); 147 | _vec4(const T f1, const _vec2& v, const T f2); 148 | _vec4(const _vec3& v, const T f); 149 | _vec4(const T f, const _vec3& v); 150 | explicit _vec4(const T f); 151 | 152 | matReal length() const; 153 | T lengthSquared() const; 154 | matReal distance(const _vec4& v) const; 155 | T distanceSquared(const _vec4& v) const; 156 | matReal proj(const _vec4& v) const; 157 | _vec4 operator * (const T n) const; 158 | _vec4 operator / (const T n) const; 159 | _vec4 operator + (const T n) const; 160 | _vec4 operator - (const T n) const; 161 | _vec4 operator + (const _vec4& vec) const; 162 | _vec4 operator - (const _vec4& vec) const; 163 | _vec4 operator * (const _vec4& vec) const; 164 | _vec4 operator / (const _vec4& vec) const; 165 | void operator *= (const T n); 166 | void operator /= (const T n); 167 | void operator += (const T n); 168 | void operator -= (const T n); 169 | void operator += (const _vec4& vec); 170 | void operator -= (const _vec4& vec); 171 | void operator *= (const _vec4& vec); 172 | void operator /= (const _vec4& vec); 173 | bool operator == (const _vec4& vec) const; 174 | bool operator == (T f) const; 175 | bool operator != (const _vec4& vec) const; 176 | bool operator != (T f) const; 177 | bool operator < (const _vec4& vec) const; 178 | bool operator <= (const _vec4& vec) const; 179 | bool operator > (const _vec4& vec) const; 180 | bool operator >= (const _vec4& vec) const; 181 | 182 | _vec4 operator % (const T n) const; 183 | void operator %= (const T n); 184 | _vec4 operator % (const _vec4& vec) const; 185 | void operator %= (const _vec4& vec); 186 | 187 | _vec4& normalize(); 188 | 189 | void reset(); 190 | 191 | _vec4 xyzw() const; _vec4 xywz() const; _vec4 xzwy() const; 192 | _vec4 xzyw() const; _vec4 xwzy() const; _vec4 xwyz() const; 193 | _vec4 yxzw() const; _vec4 yxwz() const; _vec4 yzwx() const; 194 | _vec4 yzxw() const; _vec4 ywzx() const; _vec4 ywxz() const; 195 | _vec4 zyxw() const; _vec4 zywx() const; _vec4 zxwy() const; 196 | _vec4 zxyw() const; _vec4 zwxy() const; _vec4 zwyx() const; 197 | _vec4 wyzx() const; _vec4 wyxz() const; _vec4 wzxy() const; 198 | _vec4 wzyx() const; _vec4 wxzy() const; _vec4 wxyz() const; 199 | _vec3 xyz() const; _vec3 xzy() const; _vec3 yxz() const; 200 | _vec3 yzx() const; _vec3 zxy() const; _vec3 zyx() const; 201 | _vec3 wyz() const; _vec3 wzy() const; _vec3 ywz() const; 202 | _vec3 yzw() const; _vec3 zwy() const; _vec3 zyw() const; 203 | _vec3 xyw() const; _vec3 xwy() const; _vec3 yxw() const; 204 | _vec3 ywx() const; _vec3 wxy() const; _vec3 wyx() const; 205 | _vec3 xwz() const; _vec3 xzw() const; _vec3 wxz() const; 206 | _vec3 wzx() const; _vec3 zxw() const; _vec3 zwx() const; 207 | _vec2 xy() const; _vec2 yx() const; _vec2 xz() const; 208 | _vec2 zx() const; _vec2 xw() const; _vec2 wx() const; 209 | _vec2 yz() const; _vec2 zy() const; _vec2 wz() const; 210 | _vec2 zw() const; 211 | }; 212 | 213 | class _mat4 214 | { 215 | public: 216 | matReal m[4][4]; 217 | 218 | _mat4(); 219 | explicit _mat4(const matReal n); 220 | _mat4(const matReal m00, const matReal m01, const matReal m02, const matReal m03, 221 | const matReal m10, const matReal m11, const matReal m12, const matReal m13, 222 | const matReal m20, const matReal m21, const matReal m22, const matReal m23, 223 | const matReal m30, const matReal m31, const matReal m32, const matReal m33); 224 | void reset(); 225 | _mat4 operator * (const _mat4& p) const; 226 | template 227 | _vec4 operator* (const _vec4& vec) const; 228 | _mat4 operator+ (const _mat4& p) const; 229 | _mat4 operator- (const _mat4& p) const; 230 | _mat4 operator* (const matReal n) const; 231 | _mat4 operator / (const matReal n) const; 232 | _mat4 operator+ (const matReal n) const; 233 | _mat4 operator- (const matReal n) const; 234 | void operator *= (const _mat4& p); 235 | void operator *= (const matReal n); 236 | void operator /= (const matReal n); 237 | void operator += (const _mat4& p); 238 | void operator += (const matReal n); 239 | void operator -= (const _mat4& p); 240 | void operator -= (const matReal n); 241 | bool operator == (const _mat4& p) const; 242 | bool operator != (const _mat4& p) const; 243 | 244 | inline _mat4& initRotation(matReal angle, const _vec3& axis); 245 | inline _mat4& initTranslation(_vec3& trans); 246 | inline _mat4& initScale(_vec3& scale); 247 | 248 | _mat4& initRotation(matReal angle, const matReal x, 249 | const matReal y, const matReal z); 250 | _mat4& initTranslation(const matReal x, const matReal y, const matReal z); 251 | _mat4& initScale(const matReal x, const matReal y, const matReal z); 252 | 253 | _mat4& initProjection(const matReal fov, const matReal width, 254 | const matReal height, const matReal znear, const matReal zfar); 255 | _mat4& initOrthoProjection(const matReal left_, const matReal right_, 256 | const matReal bottom_, const matReal top_, const matReal near_, 257 | const matReal far_); 258 | 259 | _mat4 getTranspose(); 260 | }; 261 | 262 | class _mat3 263 | { 264 | public: 265 | matReal m[3][3]; 266 | 267 | _mat3(); 268 | explicit _mat3(const matReal n); 269 | _mat3(const matReal m00, const matReal m01, const matReal m02, 270 | const matReal m10, const matReal m11, const matReal m12, 271 | const matReal m20, const matReal m21, const matReal m22); 272 | void reset(); 273 | _mat3 operator * (const _mat3& p) const; 274 | _vec3 operator* (const _vec3& vec) const; 275 | _mat3 operator* (const matReal n) const; 276 | _mat3 operator+ (const _mat3& p) const; 277 | _mat3 operator- (const _mat3& p) const; 278 | _mat3 operator / (const matReal n) const; 279 | _mat3 operator+ (const matReal n) const; 280 | _mat3 operator- (const matReal n) const; 281 | void operator *= (const _mat3& p); 282 | void operator *= (const matReal n); 283 | void operator /= (const matReal n); 284 | void operator += (const _mat3& p); 285 | void operator += (const matReal n); 286 | void operator -= (const _mat3& p); 287 | void operator -= (const matReal n); 288 | bool operator == (const _mat3& p) const; 289 | bool operator != (const _mat3& p) const; 290 | 291 | _mat3 getTranspose() const; 292 | matReal det() const; 293 | _mat3 getInverse() const; 294 | }; 295 | 296 | class _mat2 297 | { 298 | public: 299 | matReal m[2][2]; 300 | 301 | _mat2(); 302 | explicit _mat2(const matReal n); 303 | _mat2(const matReal m00, const matReal m01, 304 | const matReal m10, const matReal m11); 305 | void reset(); 306 | _mat2 operator * (const _mat2& p) const; 307 | _vec2 operator* (const _vec2& vec) const; 308 | _mat2 operator* (const matReal n) const; 309 | _mat2 operator+ (const _mat2& p) const; 310 | _mat2 operator- (const _mat2& p) const; 311 | _mat2 operator / (const matReal n) const; 312 | _mat2 operator+ (const matReal n) const; 313 | _mat2 operator- (const matReal n) const; 314 | void operator *= (const _mat2& p); 315 | void operator *= (const matReal n); 316 | void operator /= (const matReal n); 317 | void operator += (const _mat2& p); 318 | void operator += (const matReal n); 319 | void operator -= (const _mat2& p); 320 | void operator -= (const matReal n); 321 | bool operator == (const _mat2& p) const; 322 | bool operator != (const _mat2& p) const; 323 | 324 | _mat2 getTranspose(); 325 | }; 326 | 327 | } 328 | 329 | //Type determined through typedefs: 330 | typedef tmp::_vec2 vec2; 331 | typedef tmp::_vec3 vec3; 332 | typedef tmp::_vec4 vec4; 333 | typedef tmp::_vec2 vec2i; 334 | typedef tmp::_vec3 vec3i; 335 | typedef tmp::_vec4 vec4i; 336 | 337 | typedef tmp::_vec2 vec2f; 338 | typedef tmp::_vec3 vec3f; 339 | typedef tmp::_vec4 vec4f; 340 | typedef tmp::_vec2 vec2d; 341 | typedef tmp::_vec3 vec3d; 342 | typedef tmp::_vec4 vec4d; 343 | 344 | typedef tmp::_vec2 vec2ii; 345 | typedef tmp::_vec3 vec3ii; 346 | typedef tmp::_vec4 vec4ii; 347 | typedef tmp::_vec2 vec2l; 348 | typedef tmp::_vec3 vec3l; 349 | typedef tmp::_vec4 vec4l; 350 | 351 | typedef tmp::_vec2 vec2s; 352 | typedef tmp::_vec3 vec3s; 353 | typedef tmp::_vec4 vec4s; 354 | 355 | typedef tmp::_mat2 mat2; 356 | typedef tmp::_mat3 mat3; 357 | typedef tmp::_mat4 mat4; 358 | 359 | typedef vec2 Vector2f; 360 | typedef vec3 Vector3f; 361 | typedef vec4 Vector4f; 362 | typedef vec2i Vector2i; 363 | typedef vec3i Vector3i; 364 | typedef vec4i Vector4i; 365 | typedef mat2 Matrix2x2; 366 | typedef mat3 Matrix3x3; 367 | typedef mat4 Matrix4x4; 368 | 369 | template T dot(const tmp::_vec2& v1, const tmp::_vec2& v2); 370 | template T dot(const tmp::_vec3& v1, const tmp::_vec3& v2); 371 | template T dot(const tmp::_vec4& v1, const tmp::_vec4& v2); 372 | template tmp::_vec3 cross(const tmp::_vec3& v1, const tmp::_vec3& v2); 373 | } 374 | -------------------------------------------------------------------------------- /Primatte/spherepolyhedron.cpp: -------------------------------------------------------------------------------- 1 | #include "spherepolyhedron.h" 2 | #include "math.h" 3 | #include 4 | #include 5 | #include "io.h" 6 | #include "QGLViewer/qglviewer.h" 7 | 8 | namespace anima 9 | { 10 | const float PI = acos(-1); 11 | const float PI2 = PI*2; 12 | const float PIo2 = PI/2; 13 | 14 | //Phi = around up axis. 15 | //Theta = up/down. 16 | 17 | //Should replace atan and asin with lookup tables for performance. 18 | 19 | //Bottleneck 20 | math::vec2 SpherePolyhedron::cartesianToSpherical(const math::vec3& cartesian) 21 | { 22 | return math::vec2(atan2(cartesian.x, cartesian.y), asin(cartesian.z)); 23 | } 24 | 25 | //Only used for sphere generation, so it's fine if it's slower. 26 | math::vec3 SpherePolyhedron::sphericalToCartesian(const math::vec2& spherical) 27 | { 28 | const float sinPhi = sin(spherical.x); 29 | const float cosPhi = cos(spherical.x); 30 | const float sinTheta = sin(spherical.y); 31 | const float cosTheta = cos(spherical.y); 32 | 33 | return math::vec3(sinPhi*cosTheta, cosTheta*cosPhi, sinTheta); 34 | } 35 | 36 | math::vec3 SpherePolyhedron::getPointAtIndex(int phi, int theta) const 37 | { 38 | return mVertices[phi*mVerticesThetaCount+theta]; 39 | } 40 | 41 | float SpherePolyhedron::findDistanceToPolyhedron(const math::vec3& normalisedVector) const 42 | { 43 | //Get spherical coordinates of vector 44 | math::vec2 spherical = cartesianToSpherical(normalisedVector); 45 | 46 | //As the phi component can be negative, move it into the [0,2 Pi] range. 47 | spherical.x = fmod(spherical.x+PI2, PI2); 48 | 49 | //Get theta into into the [0, PI] range 50 | float thetaWithOffset = spherical.y + PIo2; 51 | 52 | //Vertices to be found: 53 | math::vec3 v1, v2, v3; 54 | 55 | //If pointing near the poles 56 | const float piMinusThetaAngle = PI-mThetaAngle; 57 | 58 | //If too high or low to be in the grid: 59 | if(thetaWithOffset < mThetaAngle || thetaWithOffset > piMinusThetaAngle) 60 | { 61 | const int phiIndexi = (int) (spherical.x/mPhiAngle); 62 | 63 | //If north 64 | if(thetaWithOffset > piMinusThetaAngle) 65 | { 66 | v1 = getPointAtIndex(phiIndexi, mVerticesThetaCount-1); 67 | v2 = getPointAtIndex((phiIndexi+1) % mVerticesPhiCount, mVerticesThetaCount-1); 68 | v3 = mVertices[mVertices.size()-2]; 69 | } 70 | else //if south 71 | { 72 | v1 = getPointAtIndex(phiIndexi, 0); 73 | v2 = getPointAtIndex((phiIndexi+1) % mVerticesPhiCount, 0); 74 | v3 = mVertices[mVertices.size()-1]; 75 | } 76 | } 77 | else //If pointing at a normal quad 78 | { 79 | //Get a quad index from the spherical coordinates. 80 | const math::vec2f indexf(spherical.x/mPhiAngle, thetaWithOffset/mThetaAngle); 81 | const math::vec2i indexi(indexf.x, indexf.y); 82 | 83 | //Get vertices common to both triangles 84 | v1 = getPointAtIndex((indexi.x+1) % mVerticesPhiCount, indexi.y); 85 | v2 = getPointAtIndex(indexi.x, (indexi.y + mVerticesThetaCount-1) % mVerticesThetaCount); 86 | 87 | //Upper triangle 88 | if((indexf.y-indexi.y) / mPhiAngle > (indexf.x-indexi.x) / mPhiAngle) 89 | v3 = getPointAtIndex(indexi.x, indexi.y); 90 | //Lower triange 91 | else 92 | v3 = getPointAtIndex((indexi.x+1) % mVerticesPhiCount, (indexi.y + mVerticesThetaCount-1) % mVerticesThetaCount); 93 | } 94 | 95 | //v1,v2,v3 are now filled out. 96 | 97 | //Find distance to triangle 98 | math::vec3 normal = math::cross(v2-v1,v3-v1); 99 | float vn = math::dot(normalisedVector, normal); 100 | 101 | //Assert that the angles are not perpendicular, which only happens in error. 102 | assert(vn!=0); 103 | 104 | float distance = (math::dot(v1-mCentre, normal)/vn); 105 | 106 | return distance; 107 | } 108 | 109 | void SpherePolyhedron::constructMesh() 110 | { 111 | using namespace math; 112 | 113 | //Unique vertices 114 | mVerticesPhiCount = mPhiFaces; 115 | mVerticesThetaCount = mThetaFaces - 1; 116 | 117 | //Fill out grid 118 | for(unsigned iPhi = 0; iPhi < mPhiFaces; ++iPhi) 119 | for(unsigned iTheta = 1; iTheta < mThetaFaces; ++iTheta) 120 | mVertices.push_back(sphericalToCartesian(vec2(iPhi*mPhiAngle, iTheta*mThetaAngle-PIo2))); 121 | 122 | //Add in poles 123 | //North 124 | mVertices.push_back(math::vec3(0,0,1)); 125 | //South 126 | mVertices.push_back(math::vec3(0,0,-1)); 127 | 128 | } 129 | 130 | SpherePolyhedron::SpherePolyhedron() {} 131 | 132 | SpherePolyhedron::SpherePolyhedron(unsigned phiFaces, unsigned thetaFaces) 133 | : mPhiFaces(phiFaces), mThetaFaces(thetaFaces), 134 | mPhiAngle(PI2/phiFaces), mThetaAngle(PI/thetaFaces), mRadius(1) 135 | { 136 | assert(phiFaces > 3 && thetaFaces > 2); 137 | constructMesh(); 138 | } 139 | 140 | void SpherePolyhedron::setCentreAndRadius(const math::vec3 centre, float radius) 141 | { 142 | for(auto it = mVertices.begin(); it!=mVertices.end(); ++it) 143 | *it = ((*it-mCentre)/mRadius)*radius + centre; 144 | 145 | mRadius = radius; 146 | mCentre = centre; 147 | } 148 | 149 | 150 | void SpherePolyhedron::debugDraw(math::vec3 colour) const 151 | { 152 | if(mVertices.size()==0) 153 | return; 154 | 155 | //Iterate over the quads 156 | glColor3f(colour.x,colour.y,colour.z); 157 | glPointSize(5.f); 158 | for(unsigned iPhi = 0; iPhi < mVerticesPhiCount; ++iPhi) 159 | for(unsigned iTheta = 0; iTheta < mVerticesThetaCount-1; ++iTheta) 160 | { 161 | //Get points 162 | glBegin(GL_POINTS); 163 | auto v1 = getPointAtIndex(iPhi, iTheta); 164 | auto v2 = getPointAtIndex(iPhi, iTheta+1); 165 | auto v3 = getPointAtIndex(((iPhi+1) % mVerticesPhiCount), iTheta+1); 166 | auto v4 = getPointAtIndex(((iPhi+1) % mVerticesPhiCount), iTheta); 167 | glEnd(); 168 | 169 | //Draw triangles 170 | glBegin(GL_LINES); 171 | glVertex3f(v1.x,v1.y,v1.z); 172 | glVertex3f(v3.x,v3.y,v3.z); 173 | glVertex3f(v1.x,v1.y,v1.z); 174 | glVertex3f(v2.x,v2.y,v2.z); 175 | glVertex3f(v2.x,v2.y,v2.z); 176 | glVertex3f(v3.x,v3.y,v3.z); 177 | glVertex3f(v4.x,v4.y,v4.z); 178 | glVertex3f(v1.x,v1.y,v1.z); 179 | glEnd(); 180 | } 181 | 182 | //Draw poles 183 | math::vec3 north = mVertices[mVertices.size()-2]; 184 | math::vec3 south = mVertices[mVertices.size()-1]; 185 | 186 | glBegin(GL_LINES); 187 | for(unsigned iPhi = 0; iPhi < mPhiFaces; ++iPhi) 188 | { 189 | auto edgePointTop11 = getPointAtIndex(iPhi, mVerticesThetaCount-1); 190 | auto edgePointTop21 = getPointAtIndex((iPhi+1) % (mVerticesPhiCount), mVerticesThetaCount-1); 191 | glVertex3f(north.x,north.y,north.z); 192 | glVertex3f(edgePointTop11.x,edgePointTop11.y,edgePointTop11.z); 193 | glVertex3f(north.x,north.y,north.z); 194 | glVertex3f(edgePointTop21.x,edgePointTop21.y,edgePointTop21.z); 195 | glVertex3f(edgePointTop11.x,edgePointTop11.y,edgePointTop11.z); 196 | glVertex3f(edgePointTop21.x,edgePointTop21.y,edgePointTop21.z); 197 | 198 | auto edgePointTop12 = getPointAtIndex(iPhi, 0); 199 | auto edgePointTop22 = getPointAtIndex((iPhi+1) % (mVerticesPhiCount), 0); 200 | glVertex3f(south.x,south.y,south.z); 201 | glVertex3f(edgePointTop12.x,edgePointTop12.y,edgePointTop12.z); 202 | glVertex3f(south.x,south.y,south.z); 203 | glVertex3f(edgePointTop22.x,edgePointTop22.y,edgePointTop22.z); 204 | glVertex3f(edgePointTop12.x,edgePointTop12.y,edgePointTop12.z); 205 | glVertex3f(edgePointTop22.x,edgePointTop22.y,edgePointTop22.z); 206 | } 207 | glEnd(); 208 | } 209 | 210 | float SpherePolyhedron::findLargestRadius() const 211 | { 212 | float maxRadiusSquared = 0; 213 | for(size_t i = 0; i < mVertices.size(); ++i) 214 | maxRadiusSquared = std::max(maxRadiusSquared, mVertices[i].distanceSquared(mCentre)); 215 | return sqrt(maxRadiusSquared); 216 | } 217 | 218 | 219 | float SpherePolyhedron::findSmallestRadius() const 220 | { 221 | float minRadiusSquared = mVertices.front().distanceSquared(mCentre); 222 | for(size_t i = 1; i < mVertices.size(); ++i) 223 | minRadiusSquared = std::min(minRadiusSquared, mVertices[i].distanceSquared(mCentre)); 224 | return sqrt(minRadiusSquared); 225 | } 226 | 227 | } 228 | -------------------------------------------------------------------------------- /Primatte/spherepolyhedron.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "matrixd.h" 3 | #include 4 | #include 5 | 6 | /** 7 | * This class constructs, stores and manages a carefully-constructed 3D spherical 8 | * polyhedron. Here is how it works: 9 | * Construction: 10 | * If the top and bottom triangle rings are ignored, then the polyhedron 11 | * can be represented as a 2D grid of vertices indexed by angles. This makes 12 | * face lookup really fast. The top/bottom areas can then be treated as edge cases. 13 | * Thus, first the 2D grid is constructed, and then the two poles are inserted. 14 | * Adjacent vertices may be found quickly by storing the vertices in a grid order. 15 | * Triangle inersection: 16 | * The appropriate quad is first selected. A quad is made from two triangles: 17 | * the equation of the line is used to determine which trinagle a ray falls into. 18 | * The triangle is then chosen, and the distance to the plane lying on the triangle is found. 19 | * One limitation is that the ray origin must be the sphere origin, and the sphere vertices 20 | * may not be moved as to violate the angle between them and the origin. 21 | */ 22 | 23 | 24 | namespace anima 25 | { 26 | 27 | //There is a potential minor innacuracy in the theta angle. 28 | //Debug preview shows strange jumps when finding distance, yet I can't see anything wrong. 29 | 30 | class SpherePolyhedron 31 | { 32 | protected: 33 | //The centre of the sphere. 34 | math::vec3 mCentre; 35 | 36 | //The number of quads. 37 | unsigned mPhiFaces, mThetaFaces; 38 | 39 | //The angles taken up by each quads. 40 | float mPhiAngle, mThetaAngle; 41 | 42 | //The radius. 43 | float mRadius; 44 | 45 | //The number of vertices in each direction, excluding the poles. 46 | unsigned mVerticesPhiCount, mVerticesThetaCount; 47 | 48 | /** Constructs the mesh according to the internal parameters without 49 | * scaling or positioning it. */ 50 | void constructMesh(); 51 | 52 | 53 | /** Returns the vertex at the index phi,theta of the vertex grid. 54 | * Can not return poles unless in error. */ 55 | math::vec3 getPointAtIndex(int phi, int theta) const; 56 | 57 | public: 58 | 59 | /** 60 | * Converts cartesian coordinates to spherical coordinaes. 61 | * @param cartesian A cartesian coordinate normalised around the origin. 62 | * @return The spherical coordinates where x = phi and y = theta. 63 | */ 64 | static math::vec2 cartesianToSpherical(const math::vec3& cartesian); 65 | 66 | /** 67 | * Converts spherical coordinates to cartesian normalised around the origin. 68 | * @param spherical The spherical coordinates to be converted. 69 | * @return The corresponding cartesian coordinates. 70 | */ 71 | static math::vec3 sphericalToCartesian(const math::vec2& spherical); 72 | 73 | 74 | //The inner vertices, made public as both read/write access is required. 75 | //Vertices must only be moved towards or from the origin. 76 | std::vector mVertices; 77 | 78 | /** Draws the polyhedron with the given colour. */ 79 | void debugDraw(math::vec3 colour) const; 80 | 81 | /** Creates an uninitialised polyhedron. */ 82 | SpherePolyhedron(); 83 | 84 | /** Constructs and initialises the polyhedron. 85 | * @param phiFaces the number of faces around the up axis. 86 | * @param thetaFaces the number of vertical faces. */ 87 | SpherePolyhedron(unsigned phiFaces, unsigned thetaFaces); 88 | 89 | /** 90 | * Finds and returns the distance of a vector to the polyhedron. 91 | * @param normalisedVector The vector from the centre of the sphere that is to be tested. 92 | * @return The distance to the triangle from the centre in the direction of the vector. 93 | */ 94 | float findDistanceToPolyhedron(const math::vec3& normalisedVector) const; 95 | 96 | /** Transforms the polyhedron towards the given centre and radius. 97 | * @param centre The new centre. 98 | * @param radius The new radius. */ 99 | void setCentreAndRadius(const math::vec3 centre, float radius); 100 | 101 | /** Returns the centre of the object. */ 102 | math::vec3 centre() const { return mCentre; } 103 | 104 | /** Returns the symbolic radius of the sphere. Not that fitting might make it wrong. */ 105 | float radius() const {return mRadius; } 106 | 107 | /** Finds the distance to furthest vertex from the centre. */ 108 | float findLargestRadius() const; 109 | 110 | /** Finds the distance to the closest certex from the centre. */ 111 | float findSmallestRadius() const; 112 | }; 113 | 114 | } 115 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![Example](Example.png) 2 | 3 | The second part of my 2015 summer internship, this algorithm removes 4 | the background of an image using a Primatte-inspired algorithm. 5 | 6 | Dependencies: 7 | * QGlViewer is needed for previewing the 3D data. 8 | * OpenCV is used for image handling and processing. 9 | 10 | It was designed to be easy to use and adapt, with many of the sub 11 | algorithms being replacable. The Overview.png image describes visually 12 | in some detail how it works, but a greater understanding will be achieved 13 | through reviewing the code and comments. 14 | 15 | The usage interface was inspired by the DirectX model, where a descriptor 16 | must first be created and filled out before being passed to an object. 17 | In this case, the user must create an InputAssembler to load the input, 18 | and an Algorithm to use it. 19 | 20 | An example usage is shown in application.cpp, in the init() method. 21 | It is heavily commented and should serve as a good starting point! 22 | 23 | Description of the files: 24 | * io - The IO file contains debug output functions and macros, such as timer helpers. 25 | * algorithmprimatte - This is the main core of the primatte-inspired algorithm. 26 | * alphalocator - This contains classes that implement the ialphalocator interface. 27 | * application - The application driver and 3D previewer. 28 | * averagebackgroundcolourlocators - Classes that implement the iaveragebackgroundcolourlocator interface. 29 | * boundingpolyhedron - A class that inherits from spherepolyhedron, adding fitting functionality. 30 | * coloursegmenters - Classes that implement the icoloursegmenter interface. 31 | * ialgorithm - The algorithm interface. Currently only algorithmprimatte is available. 32 | * ialphalocator - A class implementing this is reponsible for generating the alpha image given the polyhedra. 33 | * iaveragebackgroundcolourlocator - Must find the dominant background point given an image in any colour space. 34 | * icoloursegmenter - Must split the points into Inner and Outer according to a centre point and a distance parameter. 35 | * ifittingalgorithm - Must be able to shrink and expand a polyhedron around points. 36 | * inputassembler - Loads and stores the input. 37 | * matrixd - Linear algebra code. Only the vectors are used throughout the program. 38 | * spherepolyhedron - A carefully constructed UV Sphere polyhedron that allows fast ray-triangle intersection. 39 | 40 | Known issues: 41 | * There is a really small inaccuracy in ray-triangle intersection if the ray is close to a horizontal edge. 42 | 43 | Possible optimisations: 44 | * Much of alpha interpolation code could be moved to the GPU, yielding a substantial performance gain. 45 | * Changing the system to use 8-bit images could speed up the input processing stage. 46 | * Currently, the system attempts to find the alpha for each pixel, even if some pixels are not unique. Changing this could 47 | result in optimisations ranging from the alpha interpolation having to be invoked for less pixels, to colourspace conversion 48 | being needed for only the unique pixels. 49 | 50 | Supported colourspaces: 51 | * RGB - This is the fastest, as it requires least conversion. It's more suitable for compressed images as well. 52 | * HSV - Not really suitable for anything. Just left there for completeness . . . . The hue wraps around, which isn't good for distance comparisons. 53 | * LAB - The optimal choice for uncompressed images. 54 | --------------------------------------------------------------------------------