Browse Source

first-commit

master
cailean 4 hours ago
commit
0e4ec7b7b1
  1. 91
      .gitignore
  2. 194
      .vscode/c_cpp_properties.json
  3. 72
      .vscode/launch.json
  4. 133
      .vscode/tasks.json
  5. 13
      Makefile
  6. 4
      addons.make
  7. BIN
      bin/image-to-mesh
  8. BIN
      bin/image-to-mesh_debug
  9. BIN
      bin/libfmod.so
  10. 142
      config.make
  11. 107
      image-to-mesh.code-workspace
  12. 71
      image-to-mesh.qbs
  13. 267
      src/Bullet.cpp
  14. 128
      src/Bullet.h
  15. 151
      src/MeshGenerator.cpp
  16. 11
      src/MeshGenerator.h
  17. 31
      src/VP.cpp
  18. 14
      src/VP.h
  19. 346
      src/VpTree.hpp
  20. 18
      src/main.cpp
  21. 184
      src/ofApp.cpp
  22. 43
      src/ofApp.h

91
.gitignore

@ -0,0 +1,91 @@
#.gitignore is a file which makes git ignore files which should
# not go into version control in the first place
# Questions? See
# http://git-scm.com/book/en/v2/Git-Basics-Recording-Changes-to-the-Repository#Ignoring-Files
# http://git-scm.com/docs/gitignore
###########################
# ignore generated binaries
# but not the data folder
###########################
/bin/data/images
/bin/data/recordings
#########
# general
#########
[Bb]uild/
[Oo]bj/
*.o
[Dd]ebug*/
[Rr]elease*/
*.mode*
*.app/
*.pyc
.svn/
*.log
########################
# IDE files which should
# be ignored
########################
# XCode
*.pbxuser
*.perspective
*.perspectivev3
*.mode1v3
*.mode2v3
# XCode 4
*.xccheckout
xcuserdata/
# Visual Studio
*.sdf
*.opensdf
*.suo
*.pdb
*.ilk
*.aps
ipch/
# Eclipse
.metadata
local.properties
.externalToolBuilders
# Android Studio
.gradle
/local.properties
/.idea/workspace.xml
/.idea/libraries
##################
# operating system
##################
# Linux
*~
# KDE
.directory
.AppleDouble
# OSX
.DS_Store
*.swp
*~.nib
# Thumbnails
._*
# Windows
# Image file caches
Thumbs.db
# Folder config file
Desktop.ini
# Android
.csettings
/bin/data/

194
.vscode/c_cpp_properties.json

@ -0,0 +1,194 @@
{
"configurations": [
{
"name": "Mac",
"includePath": [
"/usr/include",
"/usr/local/include",
"/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/",
"/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/c++/4.2.1",
"${workspaceRoot}/../../../libs/openFrameworks",
"${workspaceRoot}/../../../libs/openFrameworks/3d",
"${workspaceRoot}/../../../libs/openFrameworks/app",
"${workspaceRoot}/../../../libs/openFrameworks/communication",
"${workspaceRoot}/../../../libs/openFrameworks/events",
"${workspaceRoot}/../../../libs/openFrameworks/gl",
"${workspaceRoot}/../../../libs/openFrameworks/graphics",
"${workspaceRoot}/../../../libs/openFrameworks/math",
"${workspaceRoot}/../../../libs/openFrameworks/sound",
"${workspaceRoot}/../../../libs/openFrameworks/types",
"${workspaceRoot}/../../../libs/openFrameworks/utils",
"${workspaceRoot}/../../../libs/openFrameworks/video",
"${workspaceRoot}/../../../libs/boost/include",
"${workspaceRoot}/../../../libs/cairo/include",
"${workspaceRoot}/../../../libs/curl/include",
"${workspaceRoot}/../../../libs/fmod/include",
"${workspaceRoot}/../../../libs/FreeImage/include",
"${workspaceRoot}/../../../libs/freetype/include",
"${workspaceRoot}/../../../libs/glew/include",
"${workspaceRoot}/../../../libs/glfw/include",
"${workspaceRoot}/../../../libs/glm/include",
"${workspaceRoot}/../../../libs/json/include",
"${workspaceRoot}/../../../libs/pugixml/include",
"${workspaceRoot}/../../../libs/rtAudio/include",
"${workspaceRoot}/../../../libs/tess2/include",
"${workspaceRoot}/../../../libs/uriparser/include",
"${workspaceRoot}/../../../libs/utf8/include"
],
"browse": {
"limitSymbolsToIncludedHeaders": true,
"databaseFilename": "${workspaceRoot}/.vscode/browse.db",
"path": [
"/usr/include",
"/usr/local/include",
"/System/Library/Frameworks",
"/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/",
"${workspaceRoot}/../../../libs",
"${workspaceRoot}/../../../addons",
"${workspaceRoot}/../../../libs/openFrameworks"
]
},
"intelliSenseMode": "clang-x64",
"macFrameworkPath": [
"/System/Library/Frameworks",
"/Library/Frameworks"
],
"compilerPath": "/usr/local/bin/gcc-8",
"cStandard": "c11",
"cppStandard": "c++17"
},
{
"name": "Linux",
"includePath": [
"/usr/include",
"/usr/local/include",
"/usr/include/c++/5",
"/usr/include/c++/5/backward",
"/usr/lib/gcc/x86_64-linux-gnu/5/include",
"/usr/lib/x86_64-linux-gnu/glib-2.0/include",
"/usr/lib/x86_64-linux-gnu/gstreamer-1.0/include",
"/usr/local/include",
"/usr/lib/gcc/x86_64-linux-gnu/5/include-fixed",
"/usr/include/x86_64-linux-gnu",
"${workspaceRoot}/../../../libs/openFrameworks",
"${workspaceRoot}/../../../libs/openFrameworks/3d",
"${workspaceRoot}/../../../libs/openFrameworks/app",
"${workspaceRoot}/../../../libs/openFrameworks/communication",
"${workspaceRoot}/../../../libs/openFrameworks/events",
"${workspaceRoot}/../../../libs/openFrameworks/gl",
"${workspaceRoot}/../../../libs/openFrameworks/graphics",
"${workspaceRoot}/../../../libs/openFrameworks/math",
"${workspaceRoot}/../../../libs/openFrameworks/sound",
"${workspaceRoot}/../../../libs/openFrameworks/types",
"${workspaceRoot}/../../../libs/openFrameworks/utils",
"${workspaceRoot}/../../../libs/openFrameworks/video",
"${workspaceRoot}/../../../libs/boost/include",
"${workspaceRoot}/../../../libs/cairo/include",
"${workspaceRoot}/../../../libs/curl/include",
"${workspaceRoot}/../../../libs/fmod/include",
"${workspaceRoot}/../../../libs/FreeImage/include",
"${workspaceRoot}/../../../libs/freetype/include",
"${workspaceRoot}/../../../libs/glew/include",
"${workspaceRoot}/../../../libs/glfw/include",
"${workspaceRoot}/../../../libs/glm/include",
"${workspaceRoot}/../../../libs/json/include",
"${workspaceRoot}/../../../libs/pugixml/include",
"${workspaceRoot}/../../../libs/rtAudio/include",
"${workspaceRoot}/../../../libs/tess2/include",
"${workspaceRoot}/../../../libs/uriparser/include",
"${workspaceRoot}/../../../libs/utf8/include",
"${workspaceRoot}/../../../libs/poco/include",
"${workspaceRoot}/../../../libs/kiss/include",
"/usr/include/x86_64-linux-gnu/c++/5",
"/usr/include/pulse",
"/usr/include/cairo",
"/usr/include/gstreamer-1.0",
"/usr/include/glib-2.0",
"${workspaceRoot}",
"/home/cailean/Desktop/openframeworks/of_v0.12.0_linux64gcc6_release/addons/ofxOpenCv/libs/opencv/include/opencv4",
"/home/cailean/Desktop/openframeworks/of_v0.12.0_linux64gcc6_release/addons/ofxOpenCv/src",
"/home/cailean/Desktop/openframeworks/of_v0.12.0_linux64gcc6_release/addons/ofxBox2d/src",
"/home/cailean/Desktop/openframeworks/of_v0.12.0_linux64gcc6_release/addons/ofxBox2d/libs/Box2D",
"/home/cailean/Desktop/openframeworks/of_v0.12.0_linux64gcc6_release/addons/ofxBox2d/libs",
"/home/cailean/Desktop/openframeworks/of_v0.12.0_linux64gcc6_release/addons/ofxBullet/libs",
"/home/cailean/Desktop/openframeworks/of_v0.12.0_linux64gcc6_release/addons/ofxBullet/src",
"/home/cailean/Desktop/openframeworks/of_v0.12.0_linux64gcc6_release/addons/ofxBullet/src/shapes",
"/home/cailean/Desktop/openframeworks/of_v0.12.0_linux64gcc6_release/addons/ofxBullet/src/events",
"/home/cailean/Desktop/openframeworks/of_v0.12.0_linux64gcc6_release/addons/ofxBullet/src/render",
"/home/cailean/Desktop/openframeworks/of_v0.12.0_linux64gcc6_release/addons/ofxBullet/libs/bullet2.8.2/include/BulletCollision/CollisionShapes",
"/home/cailean/Desktop/openframeworks/of_v0.12.0_linux64gcc6_release/addons/ofxBullet/libs/bullet2.8.2/include",
"/home/cailean/Desktop/openframeworks/of_v0.12.0_linux64gcc6_release/addons/ofxBullet/src/joints",
"/home/cailean/Desktop/openframeworks/of_v0.12.0_linux64gcc6_release/addons/ofxFFmpeg/src",
"/home/cailean/Desktop/openframeworks/of_v0.12.0_linux64gcc6_release/addons/ofxVideoRecorder/src"
],
"browse": {
"limitSymbolsToIncludedHeaders": true,
"databaseFilename": "",
"path": [
"/usr/include",
"/usr/local/include",
"${workspaceRoot}/../../../libs",
"${workspaceRoot}/../../../addons",
"${workspaceRoot}/../../../libs/openFrameworks",
"/home/cailean/Desktop/openframeworks/of_v0.12.0_linux64gcc6_release/addons/ofxOpenCv/src",
"/home/cailean/Desktop/openframeworks/of_v0.12.0_linux64gcc6_release/addons/ofxBox2d/src",
"/home/cailean/Desktop/openframeworks/of_v0.12.0_linux64gcc6_release/addons/ofxBullet/src"
]
},
"intelliSenseMode": "clang-x64",
"compilerPath": "/usr/bin/gcc",
"cStandard": "c17",
"cppStandard": "c++17"
},
{
"name": "Win32",
"includePath": [
"C:/msys64/mingw32/include/c++/7.4.0",
"C:/msys64/mingw32/i686-w64-mingw32/include",
"${workspaceRoot}/../../../libs",
"${workspaceRoot}/../../../addons",
"${workspaceRoot}/../../../libs/openFrameworks",
"${workspaceRoot}/../../../libs/openFrameworks/3d",
"${workspaceRoot}/../../../libs/openFrameworks/app",
"${workspaceRoot}/../../../libs/openFrameworks/communication",
"${workspaceRoot}/../../../libs/openFrameworks/events",
"${workspaceRoot}/../../../libs/openFrameworks/gl",
"${workspaceRoot}/../../../libs/openFrameworks/graphics",
"${workspaceRoot}/../../../libs/openFrameworks/math",
"${workspaceRoot}/../../../libs/openFrameworks/sound",
"${workspaceRoot}/../../../libs/openFrameworks/types",
"${workspaceRoot}/../../../libs/openFrameworks/utils",
"${workspaceRoot}/../../../libs/openFrameworks/video",
"${workspaceRoot}/../../../libs/boost/include",
"${workspaceRoot}/../../../libs/cairo/include",
"${workspaceRoot}/../../../libs/curl/include",
"${workspaceRoot}/../../../libs/fmod/include",
"${workspaceRoot}/../../../libs/FreeImage/include",
"${workspaceRoot}/../../../libs/freetype/include",
"${workspaceRoot}/../../../libs/glew/include",
"${workspaceRoot}/../../../libs/glfw/include",
"${workspaceRoot}/../../../libs/glm/include",
"${workspaceRoot}/../../../libs/json/include",
"${workspaceRoot}/../../../libs/pugixml/include",
"${workspaceRoot}/../../../libs/rtAudio/include",
"${workspaceRoot}/../../../libs/tess2/include",
"${workspaceRoot}/../../../libs/uriparser/include",
"${workspaceRoot}/../../../libs/utf8/include"
],
"browse": {
"limitSymbolsToIncludedHeaders": true,
"databaseFilename": "",
"path": [
"${workspaceRoot}/../../../libs",
"${workspaceRoot}/../../../addons",
"${workspaceRoot}/../../../libs/openFrameworks"
]
},
"intelliSenseMode": "clang-x64",
"compilerPath": "C:/msys64/mingw32/bin/g++.exe",
"cStandard": "c11",
"cppStandard": "c++17"
}
],
"version": 4
}

72
.vscode/launch.json

@ -0,0 +1,72 @@
{
"version": "0.2.0",
"configurations": [
{
"name": "C++ Launch",
"type": "cppdbg",
"request": "launch",
"args": [],
"stopAtEntry": false,
"cwd": "${workspaceRoot}",
"environment": [],
"externalConsole": false,
"linux": {
"MIMode": "gdb",
"setupCommands": [
{
"description": "Enable pretty-printing for gdb",
"text": "-enable-pretty-printing",
"ignoreFailures": true
}
],
"program": "${workspaceRoot}/bin/${workspaceFolderBasename}_debug"
},
"osx": {
"MIMode": "lldb",
"program": "${workspaceRoot}/bin/${workspaceFolderBasename}_debug.app/Contents/MacOS/${workspaceFolderBasename}_debug"
},
"windows": {
"MIMode": "gdb",
"miDebuggerPath": "gdb.exe",
"setupCommands": [
{
"description": "Enable pretty-printing for gdb",
"text": "-enable-pretty-printing",
"ignoreFailures": true
}
],
"program": "${workspaceRoot}/bin/${workspaceFolderBasename}_debug"
}
},
{
"name": "C++ Attach",
"type": "cppdbg",
"request": "attach",
"program": "enter program name, for example ${workspaceRoot}/a.out",
"processId": "${command:pickProcess}",
"linux": {
"MIMode": "gdb",
"setupCommands": [
{
"description": "Enable pretty-printing for gdb",
"text": "-enable-pretty-printing",
"ignoreFailures": true
}
]
},
"osx": {
"MIMode": "lldb"
},
"windows": {
"MIMode": "gdb",
"setupCommands": [
{
"description": "Enable pretty-printing for gdb",
"text": "-enable-pretty-printing",
"ignoreFailures": true
}
]
}
}
]
}

133
.vscode/tasks.json

@ -0,0 +1,133 @@
{
"version": "2.0.0",
"shell":{
"task": true
},
"tasks": [
{
"type": "shell",
"label": "Build RELEASE",
"presentation": {
"reveal": "always",
"panel": "shared"
},
"command": "make -j -s 2>&1 && make RunRelease",
"group": {
"kind": "build",
"isDefault": true
},
"problemMatcher": {
"owner": "cpp",
"fileLocation": ["relative", "${workspaceFolder}"],
"pattern": {
"regexp": "^(.*):(\\d+):(\\d+):\\s+(warning|error):\\s+(.*)$",
"file": 1,
"line": 2,
"column": 3,
"severity": 4,
"message": 5
}
}
},
{
"type": "shell",
"label": "Build DEBUG",
"presentation": {
"reveal": "always",
"panel": "shared"
},
"command": "make Debug -j -s 2>&1 || exit 1",
"group": {
"kind": "build",
"isDefault": true
},
"problemMatcher": {
"owner": "cpp",
"fileLocation": ["relative", "${workspaceFolder}"],
"pattern": {
"regexp": "^(.*):(\\d+):(\\d+):\\s+(warning|error):\\s+(.*)$",
"file": 1,
"line": 2,
"column": 3,
"severity": 4,
"message": 5
}
}
},
{
"type": "shell",
"label": "Clean DEBUG",
"presentation": {
"reveal": "always",
"panel": "shared"
},
"command": "make CleanDebug",
"group": {
"kind": "build",
"isDefault": true
},
"problemMatcher": {
"owner": "cpp",
"fileLocation": ["relative", "${workspaceFolder}"],
"pattern": {
"regexp": "^(.*):(\\d+):(\\d+):\\s+(warning|error):\\s+(.*)$",
"file": 1,
"line": 2,
"column": 3,
"severity": 4,
"message": 5
}
}
},
{
"type": "shell",
"label": "Clean RELEASE",
"presentation": {
"reveal": "always",
"panel": "shared"
},
"command": "make CleanRelease",
"group": {
"kind": "build",
"isDefault": true
},
"problemMatcher": {
"owner": "cpp",
"fileLocation": ["relative", "${workspaceFolder}"],
"pattern": {
"regexp": "^(.*):(\\d+):(\\d+):\\s+(warning|error):\\s+(.*)$",
"file": 1,
"line": 2,
"column": 3,
"severity": 4,
"message": 5
}
}
},
{
"type": "shell",
"label": "Clean ALL",
"presentation": {
"reveal": "always",
"panel": "shared"
},
"command": "make clean",
"group": {
"kind": "build",
"isDefault": true
},
"problemMatcher": {
"owner": "cpp",
"fileLocation": ["relative", "${workspaceFolder}"],
"pattern": {
"regexp": "^(.*):(\\d+):(\\d+):\\s+(warning|error):\\s+(.*)$",
"file": 1,
"line": 2,
"column": 3,
"severity": 4,
"message": 5
}
}
}
]
}

13
Makefile

@ -0,0 +1,13 @@
# Attempt to load a config.make file.
# If none is found, project defaults in config.project.make will be used.
ifneq ($(wildcard config.make),)
include config.make
endif
# make sure the the OF_ROOT location is defined
ifndef OF_ROOT
OF_ROOT=$(realpath ../../..)
endif
# call the project makefile!
include $(OF_ROOT)/libs/openFrameworksCompiled/project/makefileCommon/compile.project.mk

4
addons.make

@ -0,0 +1,4 @@
ofxOpenCv
ofxOpenCv
ofxBullet
ofxBullet

BIN
bin/image-to-mesh

Binary file not shown.

BIN
bin/image-to-mesh_debug

Binary file not shown.

BIN
bin/libfmod.so

Binary file not shown.

142
config.make

@ -0,0 +1,142 @@
################################################################################
# CONFIGURE PROJECT MAKEFILE (optional)
# This file is where we make project specific configurations.
################################################################################
################################################################################
# OF ROOT
# The location of your root openFrameworks installation
# (default) OF_ROOT = ../../..
################################################################################
OF_ROOT = ../../..
################################################################################
# PROJECT ROOT
# The location of the project - a starting place for searching for files
# (default) PROJECT_ROOT = . (this directory)
#
################################################################################
# PROJECT_ROOT = .
################################################################################
# PROJECT SPECIFIC CHECKS
# This is a project defined section to create internal makefile flags to
# conditionally enable or disable the addition of various features within
# this makefile. For instance, if you want to make changes based on whether
# GTK is installed, one might test that here and create a variable to check.
################################################################################
# None
################################################################################
# PROJECT EXTERNAL SOURCE PATHS
# These are fully qualified paths that are not within the PROJECT_ROOT folder.
# Like source folders in the PROJECT_ROOT, these paths are subject to
# exlclusion via the PROJECT_EXLCUSIONS list.
#
# (default) PROJECT_EXTERNAL_SOURCE_PATHS = (blank)
#
# Note: Leave a leading space when adding list items with the += operator
################################################################################
# PROJECT_EXTERNAL_SOURCE_PATHS =
################################################################################
# PROJECT EXCLUSIONS
# These makefiles assume that all folders in your current project directory
# and any listed in the PROJECT_EXTERNAL_SOURCH_PATHS are are valid locations
# to look for source code. The any folders or files that match any of the
# items in the PROJECT_EXCLUSIONS list below will be ignored.
#
# Each item in the PROJECT_EXCLUSIONS list will be treated as a complete
# string unless teh user adds a wildcard (%) operator to match subdirectories.
# GNU make only allows one wildcard for matching. The second wildcard (%) is
# treated literally.
#
# (default) PROJECT_EXCLUSIONS = (blank)
#
# Will automatically exclude the following:
#
# $(PROJECT_ROOT)/bin%
# $(PROJECT_ROOT)/obj%
# $(PROJECT_ROOT)/%.xcodeproj
#
# Note: Leave a leading space when adding list items with the += operator
################################################################################
# PROJECT_EXCLUSIONS =
################################################################################
# PROJECT LINKER FLAGS
# These flags will be sent to the linker when compiling the executable.
#
# (default) PROJECT_LDFLAGS = -Wl,-rpath=./libs
#
# Note: Leave a leading space when adding list items with the += operator
################################################################################
# Currently, shared libraries that are needed are copied to the
# $(PROJECT_ROOT)/bin/libs directory. The following LDFLAGS tell the linker to
# add a runtime path to search for those shared libraries, since they aren't
# incorporated directly into the final executable application binary.
# TODO: should this be a default setting?
# PROJECT_LDFLAGS=-Wl,-rpath=./libs
################################################################################
# PROJECT DEFINES
# Create a space-delimited list of DEFINES. The list will be converted into
# CFLAGS with the "-D" flag later in the makefile.
#
# (default) PROJECT_DEFINES = (blank)
#
# Note: Leave a leading space when adding list items with the += operator
################################################################################
# PROJECT_DEFINES =
################################################################################
# PROJECT CFLAGS
# This is a list of fully qualified CFLAGS required when compiling for this
# project. These CFLAGS will be used IN ADDITION TO the PLATFORM_CFLAGS
# defined in your platform specific core configuration files. These flags are
# presented to the compiler BEFORE the PROJECT_OPTIMIZATION_CFLAGS below.
#
# (default) PROJECT_CFLAGS = (blank)
#
# Note: Before adding PROJECT_CFLAGS, note that the PLATFORM_CFLAGS defined in
# your platform specific configuration file will be applied by default and
# further flags here may not be needed.
#
# Note: Leave a leading space when adding list items with the += operator
################################################################################
# PROJECT_CFLAGS =
################################################################################
# PROJECT OPTIMIZATION CFLAGS
# These are lists of CFLAGS that are target-specific. While any flags could
# be conditionally added, they are usually limited to optimization flags.
# These flags are added BEFORE the PROJECT_CFLAGS.
#
# PROJECT_OPTIMIZATION_CFLAGS_RELEASE flags are only applied to RELEASE targets.
#
# (default) PROJECT_OPTIMIZATION_CFLAGS_RELEASE = (blank)
#
# PROJECT_OPTIMIZATION_CFLAGS_DEBUG flags are only applied to DEBUG targets.
#
# (default) PROJECT_OPTIMIZATION_CFLAGS_DEBUG = (blank)
#
# Note: Before adding PROJECT_OPTIMIZATION_CFLAGS, please note that the
# PLATFORM_OPTIMIZATION_CFLAGS defined in your platform specific configuration
# file will be applied by default and further optimization flags here may not
# be needed.
#
# Note: Leave a leading space when adding list items with the += operator
################################################################################
# PROJECT_OPTIMIZATION_CFLAGS_RELEASE =
# PROJECT_OPTIMIZATION_CFLAGS_DEBUG =
################################################################################
# PROJECT COMPILERS
# Custom compilers can be set for CC and CXX
# (default) PROJECT_CXX = (blank)
# (default) PROJECT_CC = (blank)
# Note: Leave a leading space when adding list items with the += operator
################################################################################
# PROJECT_CXX =
# PROJECT_CC =

107
image-to-mesh.code-workspace

@ -0,0 +1,107 @@
{
"folders": [
{
"path": "."
},
{
"path": "${workspaceRoot}/../../../../libs/openFrameworks"
},
{
"path": "${workspaceRoot}/../../../../addons"
}
],
"settings": {
"files.associations": {
"ostream": "cpp",
"*.ipp": "cpp",
"functional": "cpp",
"cctype": "cpp",
"clocale": "cpp",
"cmath": "cpp",
"csignal": "cpp",
"cstdarg": "cpp",
"cstddef": "cpp",
"cstdio": "cpp",
"cstdlib": "cpp",
"cstring": "cpp",
"ctime": "cpp",
"cwchar": "cpp",
"cwctype": "cpp",
"any": "cpp",
"array": "cpp",
"atomic": "cpp",
"strstream": "cpp",
"bit": "cpp",
"*.tcc": "cpp",
"bitset": "cpp",
"cfenv": "cpp",
"charconv": "cpp",
"chrono": "cpp",
"codecvt": "cpp",
"compare": "cpp",
"complex": "cpp",
"concepts": "cpp",
"condition_variable": "cpp",
"cstdint": "cpp",
"deque": "cpp",
"forward_list": "cpp",
"list": "cpp",
"map": "cpp",
"set": "cpp",
"string": "cpp",
"unordered_map": "cpp",
"unordered_set": "cpp",
"vector": "cpp",
"exception": "cpp",
"expected": "cpp",
"algorithm": "cpp",
"iterator": "cpp",
"memory": "cpp",
"memory_resource": "cpp",
"numeric": "cpp",
"optional": "cpp",
"random": "cpp",
"ratio": "cpp",
"regex": "cpp",
"source_location": "cpp",
"string_view": "cpp",
"system_error": "cpp",
"tuple": "cpp",
"type_traits": "cpp",
"utility": "cpp",
"fstream": "cpp",
"future": "cpp",
"initializer_list": "cpp",
"iomanip": "cpp",
"iosfwd": "cpp",
"iostream": "cpp",
"istream": "cpp",
"limits": "cpp",
"mutex": "cpp",
"new": "cpp",
"numbers": "cpp",
"ranges": "cpp",
"semaphore": "cpp",
"shared_mutex": "cpp",
"span": "cpp",
"sstream": "cpp",
"stdexcept": "cpp",
"stop_token": "cpp",
"streambuf": "cpp",
"thread": "cpp",
"cinttypes": "cpp",
"typeindex": "cpp",
"typeinfo": "cpp",
"valarray": "cpp",
"variant": "cpp",
"format": "cpp",
"stdfloat": "cpp",
"__nullptr": "cpp",
"__hash_table": "cpp",
"__split_buffer": "cpp",
"__tree": "cpp",
"queue": "cpp",
"stack": "cpp"
}
}
}

71
image-to-mesh.qbs

@ -0,0 +1,71 @@
import qbs
import qbs.Process
import qbs.File
import qbs.FileInfo
import qbs.TextFile
import "../../../libs/openFrameworksCompiled/project/qtcreator/ofApp.qbs" as ofApp
Project{
property string of_root: "../../.."
ofApp {
name: { return FileInfo.baseName(sourceDirectory) }
files: [
'src/main.cpp',
'src/ofApp.cpp',
'src/ofApp.h',
]
of.addons: [
'ofxBox2d',
'ofxBox2d',
'ofxOpenCv',
'ofxOpenCv',
]
// additional flags for the project. the of module sets some
// flags by default to add the core libraries, search paths...
// this flags can be augmented through the following properties:
of.pkgConfigs: [] // list of additional system pkgs to include
of.includePaths: [] // include search paths
of.cFlags: [] // flags passed to the c compiler
of.cxxFlags: [] // flags passed to the c++ compiler
of.linkerFlags: [] // flags passed to the linker
of.defines: [] // defines are passed as -D to the compiler
// and can be checked with #ifdef or #if in the code
of.frameworks: [] // osx only, additional frameworks to link with the project
of.staticLibraries: [] // static libraries
of.dynamicLibraries: [] // dynamic libraries
// other flags can be set through the cpp module: http://doc.qt.io/qbs/cpp-module.html
// eg: this will enable ccache when compiling
//
// cpp.compilerWrapper: 'ccache'
Depends{
name: "cpp"
}
// common rules that parse the include search paths, core libraries...
Depends{
name: "of"
}
// dependency with the OF library
Depends{
name: "openFrameworks"
}
}
property bool makeOF: true // use makfiles to compile the OF library
// will compile OF only once for all your projects
// otherwise compiled per project with qbs
property bool precompileOfMain: false // precompile ofMain.h
// faster to recompile when including ofMain.h
// but might use a lot of space per project
references: [FileInfo.joinPaths(of_root, "/libs/openFrameworksCompiled/project/qtcreator/openFrameworks.qbs")]
}

267
src/Bullet.cpp

@ -0,0 +1,267 @@
#include "Bullet.h"
void Bullet::setup(){
/* setup camera & world */
camera_start_pos = ofVec3f(0, -3.f, -40.f);
camera_end_position = glm::vec3(ofRandom(-100, 100), ofRandom(-100, 100), ofRandom(0, 0));
camera_move_duration = 10.f;
camera_move_start_time = ofGetElapsedTimef();
is_camera_moving = false;
camera.setPosition(camera_start_pos);
camera.lookAt(ofVec3f(0, 0, 0), ofVec3f(0, -1, 0));
camera.enableOrtho();
camera.setScale(0.01);
camera.setNearClip(-10000);
camera.setFarClip(10000);
world.setup();
world.setCamera(&camera);
world.setGravity( ofVec3f(0, 0, 0) );
for (int i = 0; i < numThreads; ++i) {
workerThreads.emplace_back(&Bullet::workerThreadFunction, this, i);
}
shader.load("vertex_snap");
std::cout << workerThreads.size() << std::endl;
}
void Bullet::update(){
updateRepulsionNode();
cameraBounds = getCameraBounds(camera);
world.update();
if(is_camera_moving){
float t = (ofGetElapsedTimef() - camera_move_start_time) / camera_move_duration;
if (t >= 1.0f){
t = 1.0f;
is_camera_moving = false;
}
float easedT = easeInOutCubic(t);
glm::vec3 new_position = glm::mix(camera_start_pos, camera_end_position, easedT);
camera.setPosition(new_position);
float baseZoom = 0.01f;
float peakZoom = 0.04f;
float zoomT = 1.0f - abs(2.0f * easedT - 1.0f); // Triangle wave using easedT
float easedZoomT = easeInOutCubic(zoomT); // Apply easing to the zoom
float currentZoom = glm::mix(baseZoom, peakZoom, easedZoomT);
camera.setScale(currentZoom);
} else {
//setNewCameraEndpoint();
}
}
void Bullet::draw(){
std::lock_guard<std::mutex> lock(shapeMutex);
float shapes_drawn = 0;
gridSize = calculateGridSize(camera.getScale().x);
camera.begin();
glEnable( GL_DEPTH_TEST );
ofSetLineWidth(10.f);
ofDrawGrid(20, 10, true, false, false, true);
ofNoFill();
ofSetColor(ofColor::yellow);
ofNoFill();
ofSetColor(ofColor::orange);
for(const auto& n : nodes){
if(checkNodeVisibility(n)){
ofPushMatrix();
n.collider->transformGL();
ofScale(n.scale * 1.4);
n.col_mesh.draw();
n.collider->restoreTransformGL();
ofPopMatrix();
}
}
ofSetColor(ofColor::white);
ofFill();
for(const auto& n : nodes){
if(checkNodeVisibility(n)){
ofPushMatrix();
shader.begin();
shader.setUniform1f("gridSize", gridSize);
shader.setUniformTexture("tex0", n.tex, 0);
n.collider->transformGL();
ofScale(n.scale);
n.mesh.draw();
n.collider->restoreTransformGL();
shader.end();
ofPopMatrix();
shapes_drawn++;
}
}
camera.end();
glDisable(GL_DEPTH_TEST);
int totalShapes = nodes.size();
ofVec3f gravity = world.getGravity();
stringstream ss;
ss << "Total Shapes: " << totalShapes << endl;
ss << "FPS: " << ofGetFrameRate() << endl;
ss << "Shapes Drawn: " << shapes_drawn << endl;
ss << "Camera Position: " << camera.getPosition() << std::endl;
ss << "Camera Scale: " << camera.getScale() << std::endl;
ss << "Camera Bounds: " << cameraBounds.z << std::endl;
ofSetColor(255, 255, 255);
ofDrawBitmapString(ss.str().c_str(), 20, 20);
now = false;
}
void Bullet::addMesh(ofMesh _mesh, ofMesh _simple_mesh, ofTexture _tex){
std::lock_guard<std::mutex> lock(shapeMutex);
Node n;
n.tex = _tex;
float rand = ofRandom(0.01, 0.02);
glm::vec3 random_szie(rand, rand, rand);
n.scale = random_szie;
ofQuaternion startRot = ofQuaternion(0., 0., 0., PI);
ofVec3f target_location = ofVec3f( ofRandom(0, 0), ofRandom(0, 0), -5 );
ofVec3f start_location = ofVec3f( ofRandom(-300, 300), ofRandom(-300, 300), -5 );
ofxBulletCustomShape* s = new ofxBulletCustomShape();
s->addMesh(_simple_mesh, n.scale * 1.4, true);
s->create( world.world, start_location, startRot, 3.);
s->add();
s->getRigidBody()->setAngularFactor(btVector3(0, 0, 1));
s->getRigidBody()->setDamping(btScalar(0.001), btScalar(0.05));
s->getRigidBody()->setLinearFactor(btVector3(1, 1, 0));
s->getRigidBody()->setActivationState(DISABLE_DEACTIVATION);
s->getRigidBody()->setRestitution(btScalar(0.5));
s->getRigidBody()->setFriction(btScalar(1.0));
positions.push_back(target_location);
// Set how the col mesh is drawn!
_simple_mesh.setMode(OF_PRIMITIVE_LINES);
n.collider = s;
n.mesh = _mesh;
n.col_mesh = _simple_mesh;
nodes.push_back(n);
}
void Bullet::workerThreadFunction(int threadId) {
while (!shouldTerminate) {
size_t batchSize = shapes.size() / numThreads;
size_t start = threadId * batchSize;
size_t end = (threadId == numThreads - 1) ? nodes.size() : start + batchSize;
updateShapeBatch(start, end);
// Add a small sleep to prevent busy-waiting
std::this_thread::sleep_for(std::chrono::milliseconds(1));
}
}
void Bullet::updateShapeBatch(size_t start, size_t end) {
// for (size_t i = start; i < end; ++i) {
// std::lock_guard<std::mutex> lock(shapeMutex);
// glm::vec3 pos = nodes[i].collider->getPosition();
// glm::vec3 direction = glm::vec3(0, 0, -5) - pos;
// float dist_sq = glm::length(direction);
// glm::vec3 norm_dir = glm::normalize(direction);
// nodes[i].collider->applyCentralForce(1.0 * norm_dir);
// if(now){
// std::lock_guard<std::mutex> lock(shapeMutex);
// nodes[i].collider->applyCentralForce(glm::vec3(ofRandom(-1, 1), ofRandom(-1, 1), ofRandom(-1, 1)));
// }
// if (dist_sq > FORCE_RADIUS_SQ){
// glm::vec3 norm_dir = glm::normalize(direction);
// std::lock_guard<std::mutex> lock(shapeMutex);
// nodes[i].collider->applyCentralForce(0.001 * direction);
// }
// btVector3 vel = nodes[i].collider->getRigidBody()->getLinearVelocity();
// float vel_mag = vel.length();
// if (vel_mag > 1.0f) { // Cap at magnitude 1
// vel.normalize(); // Normalize the velocity
// vel *= 1.0f; // Scale to cap
// nodes[i].collider->getRigidBody()->setLinearVelocity(vel); // Set the capped velocity
// }
//}
for (size_t i = start; i < end; ++i) {
std::lock_guard<std::mutex> lock(shapeMutex);
glm::vec3 pos = nodes[i].collider->getPosition();
glm::vec3 direction = glm::vec3(0, 0, -5) - pos;
float dist_sq = glm::length(direction);
glm::vec3 norm_dir = glm::normalize(direction);
nodes[i].collider->applyCentralForce(1.0f * norm_dir);
// Apply repulsion force if needed
if (shouldApplyRepulsion && i != repulsionNodeIndex) {
const Node& repulsionNode = nodes[repulsionNodeIndex];
glm::vec3 repulsionDir = pos - repulsionNode.collider->getPosition();
float repulsionDist = glm::length(repulsionDir);
if (repulsionDist < repulsionRadius && repulsionDist > 0) {
repulsionDir = glm::normalize(repulsionDir);
float forceMagnitude = repulsionStrength * (1.0f - repulsionDist / repulsionRadius);
glm::vec3 repulsionForce = repulsionDir * forceMagnitude;
nodes[i].collider->applyCentralForce(repulsionForce * 100.0f);
}
}
}
}
float Bullet::easeInOutCubic(float t) {
return t < 0.5 ? 4 * t * t * t : 1 - pow(-2 * t + 2, 3) / 2;
}
float Bullet::calculateGridSize(float zoom){
const float ref_zoom = 0.01;
const float ref_scale = 20;
float new_grid_size = (ref_zoom * ref_scale) / zoom;
if(new_grid_size < 5){
new_grid_size = 5;
}
return new_grid_size;
}
void Bullet::setNewCameraEndpoint(){
camera_move_start_time = ofGetElapsedTimef();
is_camera_moving = true;
camera_start_pos = camera.getPosition();
camera_end_position = glm::vec3(ofRandom(-75, 75), ofRandom(-75, 75), 0.0);
}
glm::vec4 Bullet::getCameraBounds(const ofCamera& cam){
glm::vec3 cam_pos = cam.getPosition();
float cam_scale = cam.getScale().x;
float bounds = ofMap(cam_scale, 0.01, 0.2, 10, 120) + 20;
return glm::vec4(cam_pos.x + bounds, cam_pos.x - bounds, cam_pos.y + bounds, cam_pos.y - bounds);
}
bool Bullet::checkNodeVisibility(const Node& n){
glm::vec3 n_pos = n.collider->getPosition();
if(n_pos.x < cameraBounds.x && n_pos.x > cameraBounds.y && n_pos.y < cameraBounds.z && n_pos.y > cameraBounds.w ){
return true;
} else {
return false;
}
}

128
src/Bullet.h

@ -0,0 +1,128 @@
#pragma once
#include "ofMain.h"
#include "ofxBullet.h"
#include <thread>
#include <mutex>
#include <atomic>
#include <vector>
struct Node {
ofxBulletCustomShape* collider;
ofMesh col_mesh;
ofMesh mesh;
ofImage img;
ofTexture tex;
glm::vec3 scale;
};
class Bullet{
public:
void setup();
void update();
void draw();
void addMesh(ofMesh _mesh, ofMesh _simple_mesh, ofTexture _tex);
float easeInOutCubic(float t);
float calculateGridSize(float zoom);
void setNewCameraEndpoint();
glm::vec4 getCameraBounds(const ofCamera& cam);
bool checkNodeVisibility(const Node& n);
ofxBulletWorldRigid world;
vector <ofxBulletBox*> bounds;
ofxBulletCustomShape* boundsShape;
ofMaterial boundsMat;
ofMaterial shapeMat;
float boundsWidth;
vector<ofxBulletCustomShape*> shapes;
vector<ofxBulletCustomShape*> simplifiedShapes;
vector<glm::vec3> positions;
ofMaterial logoMat;
vector<Node> nodes;
bool bDrawDebug;
ofMesh mesh;
ofMesh simple_mesh;
ofEasyCam camera;
glm::vec3 camera_start_pos;
glm::vec3 camera_end_position;
bool is_camera_moving;
float camera_move_duration;
float camera_move_start_time;
ofLight light;
ofTexture tex;
ofShader shader;
float gridSize = 20.0f;
glm::vec4 cameraBounds;
void updateRepulsionNode() {
static int frameCount = 0;
static const int repulsionInterval = 60; // Apply repulsion every 60 frames
if (frameCount % repulsionInterval == 0 && !nodes.empty()) {
repulsionNodeIndex = ofRandom(nodes.size());
shouldApplyRepulsion = true;
} else if (frameCount % repulsionInterval == repulsionInterval - 1) {
shouldApplyRepulsion = false;
}
frameCount++;
}
ofRectangle calculateMeshBounds(const ofMesh& mesh) {
if (mesh.getVertices().empty()) {
return ofRectangle();
}
ofVec3f min = mesh.getVertices()[0];
ofVec3f max = min;
for (const auto& vertex : mesh.getVertices()) {
min.x = std::min(min.x, vertex.x);
min.y = std::min(min.y, vertex.y);
min.z = std::min(min.z, vertex.z);
max.x = std::max(max.x, vertex.x);
max.y = std::max(max.y, vertex.y);
max.z = std::max(max.z, vertex.z);
}
return ofRectangle(min.x, min.y, max.x - min.x, max.y - min.y);
}
void cleanup() {
shouldTerminate = true;
for (auto& thread : workerThreads) {
if (thread.joinable()) {
thread.join();
}
}
}
~Bullet() {
cleanup();
}
private:
std::vector<std::thread> workerThreads;
std::mutex shapeMutex;
std::atomic<bool> shouldTerminate{false};
std::atomic<size_t> repulsionNodeIndex{0};
std::atomic<bool> shouldApplyRepulsion{false};
const float repulsionRadius = 10.0f;
const float repulsionStrength = 1.0f;
const int numThreads = std::thread::hardware_concurrency();
const float FORCE_RADIUS = 200.0f; // Radius beyond which force is applied
const float FORCE_RADIUS_SQ = FORCE_RADIUS * FORCE_RADIUS; // Squared radius for faster comparisons
const float INNER_RADIUS = 10.0f; // Inner radius where objects are considered "arrived"
const float INNER_RADIUS_SQ = INNER_RADIUS * INNER_RADIUS;
void workerThreadFunction(int threadId);
void updateShapeBatch(size_t start, size_t end);
bool now = true;
};

151
src/MeshGenerator.cpp

@ -0,0 +1,151 @@
#include "MeshGenerator.h"
vector<ofMesh> MeshGenerator::generateSimplifiedMesh(ofImage& image) {
ofMesh mesh;
ofMesh simple_mesh;
// Convert ofImage to cv::Mat
cv::Mat imageMat(image.getHeight(), image.getWidth(), CV_8UC4, image.getPixels().getData());
// Split the channels
std::vector<cv::Mat> channels;
cv::split(imageMat, channels);
// Use the alpha channel for processing
cv::Mat alphaMat = channels[3];
// Threshold the alpha channel
cv::Mat binaryMat;
cv::threshold(alphaMat, binaryMat, 1, 255, cv::THRESH_BINARY);
ofImage debugImage;
debugImage.setFromPixels(binaryMat.data, image.getWidth(), image.getHeight(), OF_IMAGE_GRAYSCALE);
debugImage.save("debug_binaryMat.png");
// Find contours
std::vector<std::vector<cv::Point>> contours;
cv::findContours(binaryMat, contours, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE);
// Clear existing mesh
mesh.clear();
simple_mesh.clear();
// Filter and process contours
double minContourArea = 100.0; // Adjust this value as needed
std::vector<std::vector<cv::Point>> filteredContours;
for (const auto& contour : contours) {
double area = cv::contourArea(contour);
if (area > minContourArea) {
filteredContours.push_back(contour);
}
}
// Sort contours by area (largest first)
std::sort(filteredContours.begin(), filteredContours.end(),
[](const std::vector<cv::Point>& c1, const std::vector<cv::Point>& c2) {
return cv::contourArea(c1) > cv::contourArea(c2);
});
// Process only the largest contour (or a few largest if needed)
size_t numContoursToProcess = std::min(size_t(1), filteredContours.size());
// Vector to hold the vertices
std::vector<ofVec3f> vertices;
for (size_t i = 0; i < numContoursToProcess; ++i) {
const auto& contour = filteredContours[i];
std::vector<cv::Point> approxCurve;
// Simplify the contour 0.005 (0.05) -> v simple mesh
double epsilon = 0.005 * cv::arcLength(contour, true);
cv::approxPolyDP(contour, approxCurve, epsilon, true);
// Add vertices and calculate the texture coordinates based on contour points
if (approxCurve.size() > 1) {
for (const auto& point : approxCurve) {
float x = point.x;
float y = point.y;
vertices.emplace_back(x, y, 0);
// Map the texture coordinates to the non-transparent parts directly
float texCoordX = ofMap(x, 0, image.getWidth() - 1, 0, 1); // use image width
float texCoordY = ofMap(y, 0, image.getHeight() - 1, 0, 1); // use image height
mesh.addTexCoord(ofVec2f(texCoordX, texCoordY));
}
}
}
// Calculate the centroid
ofVec3f centroid(0, 0, 0);
for (const auto& vertex : vertices) {
centroid += vertex;
}
centroid /= vertices.size();
// Add vertices to the mesh, adjusting for centroid
for (const auto& vertex : vertices) {
mesh.addVertex(vertex - centroid); // Translate each vertex to center it
}
// Create indices for drawing
for (size_t i = 0; i < vertices.size(); ++i) {
mesh.addIndex(i);
mesh.addIndex((i + 1) % vertices.size());
}
/* simplified mesh */
vertices.clear();
for (size_t i = 0; i < numContoursToProcess; ++i) {
const auto& contour = filteredContours[i];
std::vector<cv::Point> approxCurve;
// Simplify the contour 0.005 (0.05) -> v simple mesh
double epsilon = 0.025 * cv::arcLength(contour, true);
cv::approxPolyDP(contour, approxCurve, epsilon, true);
// Add vertices and calculate the texture coordinates based on contour points
if (approxCurve.size() > 1) {
for (const auto& point : approxCurve) {
float x = point.x;
float y = point.y;
vertices.emplace_back(x, y, 0);
}
}
}
// Calculate the centroid
centroid = glm::vec3(0, 0, 0);
for (const auto& vertex : vertices) {
centroid += vertex;
}
centroid /= vertices.size();
// Add vertices to the mesh, adjusting for centroid
for (const auto& vertex : vertices) {
simple_mesh.addVertex(vertex - centroid); // Translate each vertex to center it
}
// Create indices for drawing
for (size_t i = 0; i < vertices.size(); ++i) {
simple_mesh.addIndex(i);
simple_mesh.addIndex((i + 1) % vertices.size());
}
// Set the primitive mode to triangles to allow proper texture mapping
mesh.setMode(OF_PRIMITIVE_TRIANGLE_FAN);
simple_mesh.setMode(OF_PRIMITIVE_TRIANGLES);
vector<ofMesh> mesh_list;
mesh_list.emplace_back(mesh);
mesh_list.emplace_back(simple_mesh);
return mesh_list;
}

11
src/MeshGenerator.h

@ -0,0 +1,11 @@
#pragma once
#include "ofMain.h"
#include "ofxOpenCv.h"
class MeshGenerator{
public:
vector<ofMesh> generateSimplifiedMesh(ofImage& img);
};

31
src/VP.cpp

@ -0,0 +1,31 @@
#include "VP.h"
// Function to generate random vectors
std::vector<std::vector<double>> VP::generateRandomVectors(int count, int dimension) {
std::vector<std::vector<double>> vectors;
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_real_distribution<> dis(0.0, 1.0);
for (int i = 0; i < count; ++i) {
std::vector<double> vec;
for (int j = 0; j < dimension; ++j) {
vec.push_back(dis(gen));
}
vectors.push_back(vec);
}
return vectors;
}
vpt::VpTree VP::loadTree(std::string path){
return vpt::VpTree::load(path);
}
void VP::saveTree(std::string filename, vpt::VpTree& tree){
tree.save(filename);
}
vpt::VpTree VP::buildTree(std::vector<vpt::Vector> vectors){
vpt::VpTree tree(vectors);
return tree;
}

14
src/VP.h

@ -0,0 +1,14 @@
#pragma once
#include <iostream>
#include <vector>
#include <random>
#include <chrono>
#include "VpTree.hpp"
class VP{
public:
std::vector<std::vector<double>> generateRandomVectors(int count, int dimension);
vpt::VpTree loadTree(std::string path);
void saveTree(std::string filename, vpt::VpTree& tree);
vpt::VpTree buildTree(std::vector<vpt::Vector> vectors);
};

346
src/VpTree.hpp

@ -0,0 +1,346 @@
#pragma once
#include <algorithm>
#include <vector>
#include <queue>
#include <limits>
#include <random>
#include <cmath>
#include <stdexcept>
#include <functional>
#include <optional>
#include <fstream>
#include <iostream>
#include <numeric>
#include "ofFileUtils.h"
namespace vpt {
using Vector = std::vector<double>;
using Metric = std::function<double(const Vector&, const Vector&)>;
using DistancesIndices = std::pair<std::vector<double>, std::vector<int>>;
using BatchDistancesIndices = std::pair<std::vector<std::vector<double>>, std::vector<std::vector<int>>>;
template<class InputIterator>
inline double sum(InputIterator begin, InputIterator end) {
return std::accumulate(begin, end, 0.0);
}
struct EuclideanMetric {
inline double operator()(const Vector& v1, const Vector& v2) const {
Vector diffSquares(v1.size());
std::transform(v1.begin(), v1.end(), v2.begin(), diffSquares.begin(),
[](double lhs, double rhs) { return (lhs - rhs) * (lhs - rhs); });
return std::sqrt(sum(diffSquares.begin(), diffSquares.end()));
}
};
class DimensionMismatch : public std::runtime_error {
public:
inline DimensionMismatch(int expected, int got)
: std::runtime_error("Item dimension doesn't match: expected " + std::to_string(expected) +
", got " + std::to_string(got)) {}
};
class VpTree {
public:
template<typename InputIterator>
inline explicit VpTree(InputIterator start, InputIterator end, Metric metric = EuclideanMetric());
template<typename Container>
inline explicit VpTree(const Container& container, Metric metric = EuclideanMetric());
inline explicit VpTree(std::initializer_list<Vector> list, Metric metric = EuclideanMetric());
inline DistancesIndices getNearestNeighbors(const Vector& target, int neighborsCount) const;
template<typename VectorLike>
inline DistancesIndices getNearestNeighbors(const VectorLike& target, int neighborsCount) const;
inline DistancesIndices getNearestNeighbors(std::initializer_list<double> target, int neighborsCount) const;
template<typename Container>
inline BatchDistancesIndices getNearestNeighborsBatch(const Container& targets, int neighborsCount) const;
inline BatchDistancesIndices getNearestNeighborsBatch(std::initializer_list<Vector> targets, int neighborsCount) const;
// Save the VpTree to a file
inline void save(const std::string& filename) const {
std::ofstream out(filename, std::ios::binary);
if (!out) {
throw std::runtime_error("Cannot open file for writing: " + filename);
}
// Save dimension
out.write(reinterpret_cast<const char*>(&dimension_), sizeof(dimension_));
// Save items
size_t itemsSize = items_.size();
out.write(reinterpret_cast<const char*>(&itemsSize), sizeof(itemsSize));
for (const auto& item : items_) {
size_t vecSize = item.first.size();
out.write(reinterpret_cast<const char*>(&vecSize), sizeof(vecSize));
out.write(reinterpret_cast<const char*>(item.first.data()), vecSize * sizeof(double));
out.write(reinterpret_cast<const char*>(&item.second), sizeof(item.second));
}
// Save nodes
size_t nodesSize = nodes_.size();
out.write(reinterpret_cast<const char*>(&nodesSize), sizeof(nodesSize));
out.write(reinterpret_cast<const char*>(nodes_.data()), nodesSize * sizeof(Node));
if (!out) {
throw std::runtime_error("Error writing to file: " + filename);
}
}
// Load the VpTree from a file
inline static VpTree load(const std::string& filename, Metric metric = EuclideanMetric()) {
std::ifstream in(filename, std::ios::binary);
if (!in) {
throw std::runtime_error("Cannot open file for reading: " + filename);
}
VpTree tree;
tree.distance_ = std::move(metric);
// Load dimension
in.read(reinterpret_cast<char*>(&tree.dimension_), sizeof(tree.dimension_));
// Load items
size_t itemsSize;
in.read(reinterpret_cast<char*>(&itemsSize), sizeof(itemsSize));
tree.items_.resize(itemsSize);
for (auto& item : tree.items_) {
size_t vecSize;
in.read(reinterpret_cast<char*>(&vecSize), sizeof(vecSize));
item.first.resize(vecSize);
in.read(reinterpret_cast<char*>(item.first.data()), vecSize * sizeof(double));
in.read(reinterpret_cast<char*>(&item.second), sizeof(item.second));
}
// Load nodes
size_t nodesSize;
in.read(reinterpret_cast<char*>(&nodesSize), sizeof(nodesSize));
tree.nodes_.resize(nodesSize);
in.read(reinterpret_cast<char*>(tree.nodes_.data()), nodesSize * sizeof(Node));
if (!in) {
throw std::runtime_error("Error reading from file: " + filename);
} else {
std::cout << "Tree loaded from disk." << std::endl;
}
return tree;
}
private:
struct Node {
static constexpr int Leaf = -1;
int item;
double threshold;
int left;
int right;
// Default constructor
Node() : item(Leaf), threshold(0.0), left(Leaf), right(Leaf) {}
Node(int item, double threshold = 0., int left = Leaf, int right = Leaf)
: item(item), threshold(threshold), left(left), right(right) {}
};
using Item = std::pair<Vector, int>;
std::vector<Item> items_;
std::vector<Node> nodes_;
std::mt19937 rng_;
int dimension_;
Metric distance_;
template<typename InputIterator>
inline std::vector<Item> makeItems(InputIterator start, InputIterator end);
inline std::optional<int> makeTree(int lower, int upper);
inline void selectRoot(int lower, int upper);
inline void partitionByDistance(int lower, int pos, int upper);
inline int makeNode(int item);
inline Node root() const { return nodes_[0]; }
// Default constructor for use in load function
inline VpTree() : rng_(std::random_device()()) {}
class Searcher {
public:
inline explicit Searcher(const VpTree* tree, const Vector& target, int neighborsCount);
inline DistancesIndices search();
private:
struct HeapItem {
inline bool operator<(const HeapItem& other) const { return dist < other.dist; }
int item;
double dist;
};
inline void searchInNode(const Node& node);
const VpTree* tree_;
Vector target_;
int neighborsCount_;
double tau_;
std::priority_queue<HeapItem> heap_;
};
friend class Searcher;
};
template<typename InputIterator>
inline VpTree::VpTree(InputIterator start, InputIterator end, Metric metric)
: items_(makeItems(start, end)), nodes_(), rng_(std::random_device()()), distance_(std::move(metric)) {
nodes_.reserve(items_.size());
makeTree(0, items_.size());
}
template<typename Container>
inline VpTree::VpTree(const Container& container, Metric metric)
: VpTree(container.begin(), container.end(), std::move(metric)) {}
inline VpTree::VpTree(std::initializer_list<Vector> list, Metric metric)
: VpTree(list.begin(), list.end(), std::move(metric)) {}
inline std::optional<int> VpTree::makeTree(int lower, int upper) {
if (lower >= upper) {
return std::nullopt;
} else if (lower + 1 == upper) {
return makeNode(lower);
} else {
selectRoot(lower, upper);
int median = (upper + lower) / 2;
partitionByDistance(lower, median, upper);
auto node = makeNode(lower);
nodes_[node].threshold = distance_(items_[lower].first, items_[median].first);
nodes_[node].left = makeTree(lower + 1, median).value_or(Node::Leaf);
nodes_[node].right = makeTree(median, upper).value_or(Node::Leaf);
return node;
}
}
inline void VpTree::selectRoot(int lower, int upper) {
std::uniform_int_distribution<int> uni(lower, upper - 1);
int root = uni(rng_);
std::swap(items_[lower], items_[root]);
}
inline void VpTree::partitionByDistance(int lower, int pos, int upper) {
std::nth_element(
items_.begin() + lower + 1, items_.begin() + pos, items_.begin() + upper,
[this, &lower](const Item& i1, const Item& i2) {
return distance_(items_[lower].first, i1.first) < distance_(items_[lower].first, i2.first);
});
}
inline int VpTree::makeNode(int item) {
nodes_.emplace_back(item);
return static_cast<int>(nodes_.size() - 1);
}
template<typename InputIterator>
inline std::vector<VpTree::Item> VpTree::makeItems(InputIterator begin, InputIterator end) {
if (begin != end) {
dimension_ = begin->size();
} else {
dimension_ = -1;
}
std::vector<Item> res;
for (int i = 0; begin != end; ++begin, ++i) {
res.emplace_back(Vector(begin->begin(), begin->end()), i);
auto lastDimension = res.back().first.size();
if (lastDimension != dimension_) {
throw DimensionMismatch(dimension_, lastDimension);
}
}
return res;
}
template<typename VectorLike>
inline DistancesIndices VpTree::getNearestNeighbors(const VectorLike& target, int neighborsCount) const {
return getNearestNeighbors(Vector(target.begin(), target.end()), neighborsCount);
}
inline DistancesIndices VpTree::getNearestNeighbors(std::initializer_list<double> target, int neighborsCount) const {
return getNearestNeighbors(Vector(target.begin(), target.end()), neighborsCount);
}
inline DistancesIndices VpTree::getNearestNeighbors(const Vector& target, int neighborsCount) const {
auto targetDimension = target.size();
if (targetDimension != dimension_) {
throw DimensionMismatch(dimension_, targetDimension);
}
Searcher searcher(this, target, neighborsCount);
return searcher.search();
}
template<typename Container>
inline BatchDistancesIndices VpTree::getNearestNeighborsBatch(const Container& targets, int neighborsCount) const {
std::vector<std::vector<double>> batchDistances(targets.size());
std::vector<std::vector<int>> batchIndices(targets.size());
#pragma omp parallel for schedule(dynamic)
for (size_t i = 0; i < targets.size(); ++i) {
std::tie(batchDistances[i], batchIndices[i]) = getNearestNeighbors(targets[i], neighborsCount);
}
return {batchDistances, batchIndices};
}
inline BatchDistancesIndices VpTree::getNearestNeighborsBatch(std::initializer_list<Vector> targets, int neighborsCount) const {
return getNearestNeighborsBatch(std::vector<Vector>(targets.begin(), targets.end()), neighborsCount);
}
inline VpTree::Searcher::Searcher(const VpTree* tree, const Vector& target, int neighborsCount)
: tree_(tree), target_(target), neighborsCount_(neighborsCount),
tau_(std::numeric_limits<double>::max()), heap_() {}
inline DistancesIndices VpTree::Searcher::search() {
searchInNode(tree_->root());
DistancesIndices results;
results.first.reserve(heap_.size());
results.second.reserve(heap_.size());
while (!heap_.empty()) {
results.first.push_back(heap_.top().dist);
results.second.push_back(tree_->items_[heap_.top().item].second);
heap_.pop();
}
std::reverse(results.first.begin(), results.first.end());
std::reverse(results.second.begin(), results.second.end());
return results;
}
inline void VpTree::Searcher::searchInNode(const Node& node) {
double dist = tree_->distance_(tree_->items_[node.item].first, target_);
if (dist < tau_) {
if (heap_.size() == neighborsCount_)
heap_.pop();
heap_.push({node.item, dist});
if (heap_.size() == neighborsCount_)
tau_ = heap_.top().dist;
}
if (dist < node.threshold) {
if (node.left != Node::Leaf && dist - tau_ <= node.threshold)
searchInNode(tree_->nodes_[node.left]);
if (node.right != Node::Leaf && dist + tau_ >= node.threshold)
searchInNode(tree_->nodes_[node.right]);
} else {
if (node.right != Node::Leaf && dist + tau_ >= node.threshold)
searchInNode(tree_->nodes_[node.right]);
if (node.left != Node::Leaf && dist - tau_ <= node.threshold)
searchInNode(tree_->nodes_[node.left]);
}
}
} // namespace vpt

18
src/main.cpp

@ -0,0 +1,18 @@
#include "ofMain.h"
#include "ofApp.h"
//========================================================================
int main( ){
//Use ofGLFWWindowSettings for more options like multi-monitor fullscreen
ofGLWindowSettings settings;
settings.setSize(1920, 960);
settings.setGLVersion(3, 2);
settings.windowMode = OF_WINDOW; //can also be OF_FULLSCREEN
auto window = ofCreateWindow(settings);
ofRunApp(window, make_shared<ofApp>());
ofRunMainLoop();
}

184
src/ofApp.cpp

@ -0,0 +1,184 @@
#include "ofApp.h"
//--------------------------------------------------------------
void ofApp::setup(){
const int vectorCount = 10000;
const int dimension = 7;
const int queryCount = 10;
const int k = 5; // Number of nearest neighbors to find
// Generate random vectors
auto vectors = vp_tree.generateRandomVectors(vectorCount, dimension);
vpt::VpTree tree = vp_tree.buildTree(vectors);
vp_tree.saveTree("./data/vp-tree.bin", tree);
// Generate query vectors
auto queries = vp_tree.generateRandomVectors(queryCount, dimension);
for (const auto& query : queries) {
auto [distances, indices] = tree.getNearestNeighbors(query, k);
// Uncomment the following lines to print results for each query
std::cout << "Query: ";
for (double d : query) std::cout << d << " ";
std::cout << "\nNearest neighbors:\n";
for (int i = 0; i < k; ++i) {
std::cout << " Index: " << indices[i] << ", Distance: " << distances[i] << "\n";
}
}
record_fbo.allocate(ofGetWindowWidth(), ofGetWindowHeight(), GL_RGB);
shader_fbo.allocate(ofGetWindowWidth(), ofGetWindowHeight(), GL_RGBA);
out_fbo.allocate(ofGetWindowWidth(), ofGetWindowHeight(), GL_RGBA);
ofSetVerticalSync(true);
ofDisableArbTex();
//ofEnableDepthTest();
ofDisableDepthTest();
ofDisableAntiAliasing();
ofEnableAlphaBlending();
shaders.load("dither");
std::string path = "images";
ofDirectory dir(path);
dir.allowExt("png");
dir.listDir();
ofLoadImage(bayer, "images/bayer.png");
bayer.setTextureWrap(GL_REPEAT, GL_REPEAT);
// Loop through files and load images
for (size_t i = 0; i < dir.size(); i++) {
std::string filePath = dir.getPath(i);
ofImage img;
if (img.load(filePath)) { // Load the image
images.push_back(img); // Add the image to the list
} else {
ofLog() << "Failed to load: " << filePath; // Log if failed to load
}
}
bullet.setup();
vector<ofMesh> mesh_list;
for(auto& img : images){
mesh_list = mesh_generator.generateSimplifiedMesh(img);
bullet.addMesh(mesh_list[0], mesh_list[1], img.getTexture());
mesh_list.clear();
}
}
//--------------------------------------------------------------
void ofApp::update(){
bullet.update();
}
//--------------------------------------------------------------
void ofApp::draw(){
ofPushStyle();
shader_fbo.begin();
ofClear(ofColor::grey);
bullet.draw();
shader_fbo.end();
ofPopStyle();
ofTexture t = shader_fbo.getTexture();
out_fbo.begin();
shaders.begin();
shaders.setUniformTexture("tex0", t, 0);
shaders.setUniformTexture("tex1", bayer, 1);
shaders.setUniform2f("resolution", ofGetWidth(), ofGetHeight());
shaders.setUniform1f("time", ofGetElapsedTimef());
shaders.setUniform1i("frame", ofGetFrameNum());
ofClear(0, 0, 0, 0);
shader_fbo.draw(0,0);
shaders.end();
out_fbo.end();
out_fbo.draw(0,0);
//shader_fbo.draw(0, 0);
// float planeScale = 0.75;
// int planeWidth = ofGetWidth() * planeScale;
// int planeHeight = ofGetHeight() * planeScale;
// int planeGridSize = 20;
// int planeColumns = planeWidth / planeGridSize;
// int planeRows = planeHeight / planeGridSize;
// plane.set(planeWidth, planeHeight, planeColumns, planeRows, OF_PRIMITIVE_TRIANGLES);
// plane.mapTexCoordsFromTexture(t);
// t.bind();
// shaders.begin();
// ofPushMatrix();
// ofTranslate(ofGetWidth()/2, ofGetHeight()/2);
// plane.draw();
// ofPopMatrix();
// shaders.end();
// t.unbind();
//t.draw(ofGetWindowWidth() / 2, 0);
}
//--------------------------------------------------------------
void ofApp::keyPressed(int key){
}
//--------------------------------------------------------------
void ofApp::keyReleased(int key){
}
//--------------------------------------------------------------
void ofApp::mouseMoved(int x, int y ){
}
//--------------------------------------------------------------
void ofApp::mouseDragged(int x, int y, int button){
}
//--------------------------------------------------------------
void ofApp::mousePressed(int x, int y, int button){
}
//--------------------------------------------------------------
void ofApp::mouseReleased(int x, int y, int button){
}
//--------------------------------------------------------------
void ofApp::mouseEntered(int x, int y){
}
//--------------------------------------------------------------
void ofApp::mouseExited(int x, int y){
}
//--------------------------------------------------------------
void ofApp::windowResized(int w, int h){
}
//--------------------------------------------------------------
void ofApp::gotMessage(ofMessage msg){
}
//--------------------------------------------------------------
void ofApp::dragEvent(ofDragInfo dragInfo){
}

43
src/ofApp.h

@ -0,0 +1,43 @@
#pragma once
#include "ofMain.h"
#include "MeshGenerator.h"
#include "Bullet.h"
#include "VP.h"
class ofApp : public ofBaseApp{
public:
void setup();
void update();
void draw();
void keyPressed(int key);
void keyReleased(int key);
void mouseMoved(int x, int y );
void mouseDragged(int x, int y, int button);
void mousePressed(int x, int y, int button);
void mouseReleased(int x, int y, int button);
void mouseEntered(int x, int y);
void mouseExited(int x, int y);
void windowResized(int w, int h);
void dragEvent(ofDragInfo dragInfo);
void gotMessage(ofMessage msg);
ofEasyCam cam;
ofImage img;
ofMesh mesh;
MeshGenerator mesh_generator;
Bullet bullet;
vector<ofImage> images;
ofFbo record_fbo;
ofFbo shader_fbo;
ofFbo out_fbo;
ofShader shaders;
ofPlanePrimitive plane;
ofTexture bayer;
VP vp_tree;
};
Loading…
Cancel
Save