├── .appveyor.yml ├── .clang-format ├── .gitignore ├── .gitmodules ├── .travis.yml ├── 3rdparty └── CMakeLists.txt ├── CMakeLists.txt ├── LICENSE ├── README.md ├── data ├── building_blocks_fig1.svg ├── building_blocks_fig1.xml ├── building_blocks_fig11.xml ├── building_blocks_fig6a.svg ├── building_blocks_fig6a.xml ├── building_blocks_fig6b.svg ├── building_blocks_fig6b.xml ├── building_blocks_fig6c.svg ├── building_blocks_fig6c.xml ├── building_blocks_fig6d.svg ├── building_blocks_fig6d.xml ├── config.txt ├── planar_graph_fig1.svg ├── planar_graph_fig1.xml ├── planar_graph_fig10_floor1.svg ├── planar_graph_fig10_floor1.xml ├── planar_graph_fig10_floor2.svg ├── planar_graph_fig10_floor2.xml ├── planar_graph_fig10_floor3.svg ├── planar_graph_fig10_floor3.xml ├── planar_graph_fig11.svg ├── planar_graph_fig11.xml ├── planar_graph_fig7_bottom.svg ├── planar_graph_fig7_bottom.xml ├── planar_graph_fig7_top.svg ├── planar_graph_fig7_top.xml ├── planar_graph_fig8.svg ├── planar_graph_fig8.xml ├── planar_graph_fig9.svg └── planar_graph_fig9.xml └── src ├── CMakeLists.txt ├── ConfigSpace.cpp ├── ConfigSpace.h ├── GraphChain.h ├── GraphEdge.h ├── GraphFace.h ├── GraphNode.h ├── LevelConfig.cpp ├── LevelConfig.h ├── LevelMath.cpp ├── LevelMath.h ├── LevelSynth.cpp ├── LevelSynth.h ├── LevelTimer.h ├── LineBase.h ├── PlanarGraph.cpp ├── PlanarGraph.h ├── Room.cpp ├── Room.h ├── RoomEdge.h ├── RoomLayout.cpp ├── RoomLayout.h ├── RoomTemplates.cpp ├── RoomTemplates.h ├── clipperWrapper.cpp ├── clipperWrapper.h ├── levels.cpp ├── util.h └── vec.h /.appveyor.yml: -------------------------------------------------------------------------------- 1 | version: "{build}" 2 | 3 | os: Visual Studio 2015 4 | 5 | platform: 6 | - Win32 7 | #- x64 8 | 9 | environment: 10 | MSVC_DEFAULT_OPTIONS: ON 11 | BOOST_ROOT: C:\Libraries\boost_1_69_0 12 | BOOST_LIBRARYDIR: C:\Libraries\boost_1_69_0\lib32-msvc-14.0 13 | 14 | configuration: 15 | #- Debug 16 | - Release 17 | 18 | clone_folder: C:\projects\LevelSyn 19 | 20 | branches: 21 | only: 22 | - master 23 | 24 | install: 25 | - git submodule update --init --recursive 26 | 27 | build_script: 28 | - cd C:\projects\LevelSyn 29 | - md build 30 | - cd build 31 | - if "%platform%"=="Win32" set CMAKE_GENERATOR_NAME=Visual Studio 14 2015 32 | - if "%platform%"=="x64" set CMAKE_GENERATOR_NAME=Visual Studio 14 2015 Win64 33 | - cmake -G "%CMAKE_GENERATOR_NAME%" -DCMAKE_BUILD_TYPE=%configuration% -DBOOST_ROOT="%BOOST_ROOT%" -DBOOST_LIBRARYDIR="%BOOST_LIBRARYDIR%" -DBoost_USE_STATIC_LIBS="ON" ../ 34 | - msbuild %MSBuildOptions% LevelSyn.sln 35 | - cd ..\bin 36 | - levels.exe ..\data\planar_graph_fig1.xml ..\data\building_blocks_fig1.xml ..\data\config.txt 10 37 | -------------------------------------------------------------------------------- /.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | Language: Cpp 3 | BasedOnStyle: LLVM 4 | AccessModifierOffset: -4 5 | #AlignAfterOpenBracket: Align 6 | AlignConsecutiveAssignments: false 7 | AlignConsecutiveDeclarations: false 8 | AlignEscapedNewlines: Left 9 | AlignOperands: false 10 | AlignTrailingComments: true 11 | AllowAllParametersOfDeclarationOnNextLine: true 12 | AllowShortBlocksOnASingleLine: Empty 13 | AllowShortCaseLabelsOnASingleLine: false 14 | AllowShortFunctionsOnASingleLine: InlineOnly 15 | AllowShortIfStatementsOnASingleLine: WithoutElse 16 | AllowShortLoopsOnASingleLine: false 17 | AlwaysBreakAfterDefinitionReturnType: None 18 | AlwaysBreakAfterReturnType: None 19 | AlwaysBreakBeforeMultilineStrings: false 20 | AlwaysBreakTemplateDeclarations: MultiLine 21 | BinPackArguments: true 22 | BinPackParameters: true 23 | BreakBeforeBraces: Custom 24 | BraceWrapping: 25 | AfterClass: true 26 | AfterControlStatement: Always 27 | AfterEnum: true 28 | AfterFunction: true 29 | AfterNamespace: true 30 | AfterObjCDeclaration: true 31 | AfterStruct: true 32 | AfterUnion: true 33 | AfterExternBlock: true 34 | BeforeCatch: true 35 | BeforeElse: true 36 | IndentBraces: false 37 | SplitEmptyFunction: false 38 | SplitEmptyRecord: false 39 | SplitEmptyNamespace: false 40 | BreakBeforeBinaryOperators: None 41 | BreakInheritanceList: AfterColon 42 | BreakBeforeTernaryOperators: false 43 | BreakConstructorInitializers: AfterColon 44 | BreakAfterJavaFieldAnnotations: true 45 | BreakStringLiterals: false 46 | ColumnLimit: 0 47 | CommentPragmas: '^ IWYU pragma:' 48 | CompactNamespaces: false 49 | ConstructorInitializerAllOnOneLineOrOnePerLine: true 50 | ConstructorInitializerIndentWidth: 4 51 | ContinuationIndentWidth: 4 52 | Cpp11BracedListStyle: false 53 | DerivePointerAlignment: false 54 | DisableFormat: false 55 | ExperimentalAutoDetectBinPacking: false 56 | FixNamespaceComments: true 57 | ForEachMacros: 58 | - foreach 59 | - Q_FOREACH 60 | - BOOST_FOREACH 61 | IncludeBlocks: Regroup 62 | IncludeCategories: 63 | - Regex: '^"(llvm|llvm-c|clang|clang-c)/' 64 | Priority: 2 65 | - Regex: '^(<|"(gtest|gmock|isl|json)/)' 66 | Priority: 3 67 | - Regex: '.*' 68 | Priority: 1 69 | #IncludeIsMainRegex: '(Test)?$' 70 | IndentCaseLabels: false 71 | IndentPPDirectives: BeforeHash 72 | IndentWidth: 4 73 | IndentWrappedFunctionNames: true 74 | JavaScriptQuotes: Leave 75 | JavaScriptWrapImports: true 76 | KeepEmptyLinesAtTheStartOfBlocks: false 77 | #MacroBlockBegin: '' 78 | #MacroBlockEnd: '' 79 | MaxEmptyLinesToKeep: 1 80 | NamespaceIndentation: None 81 | PenaltyBreakAssignment: 4 82 | PenaltyBreakBeforeFirstCallParameter: 19 83 | PenaltyBreakComment: 300 84 | PenaltyBreakFirstLessLess: 120 85 | PenaltyBreakString: 1000 86 | PenaltyBreakTemplateDeclaration: 10 87 | PenaltyExcessCharacter: 1000000 88 | PenaltyReturnTypeOnItsOwnLine: 60 89 | PointerAlignment: Left 90 | ReflowComments: false 91 | SortIncludes: true 92 | SortUsingDeclarations: true 93 | SpaceAfterCStyleCast: false 94 | SpaceAfterTemplateKeyword: true 95 | SpaceBeforeAssignmentOperators: true 96 | SpaceBeforeCpp11BracedList: false 97 | SpaceBeforeCtorInitializerColon: true 98 | SpaceBeforeInheritanceColon: true 99 | SpaceBeforeParens: ControlStatements 100 | SpaceBeforeRangeBasedForLoopColon: true 101 | SpaceInEmptyParentheses: false 102 | SpacesBeforeTrailingComments: 1 103 | SpacesInAngles: false 104 | SpacesInContainerLiterals: true 105 | SpacesInCStyleCastParentheses: false 106 | SpacesInParentheses: false 107 | SpacesInSquareBrackets: false 108 | Standard: c++17 109 | StatementMacros: 110 | - Q_UNUSED 111 | - QT_REQUIRE_VERSION 112 | TabWidth: 4 113 | UseTab: Never 114 | ... 115 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files 2 | *.slo 3 | *.lo 4 | *.o 5 | *.obj 6 | 7 | # Precompiled Headers 8 | *.gch 9 | *.pch 10 | 11 | # Compiled Dynamic libraries 12 | *.so 13 | *.dylib 14 | *.dll 15 | 16 | # Fortran module files 17 | *.mod 18 | 19 | # Compiled Static libraries 20 | *.lai 21 | *.la 22 | *.a 23 | *.lib 24 | 25 | # Executables 26 | *.exe 27 | *.out 28 | *.app 29 | 30 | build 31 | bin 32 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "3rdparty/clipper"] 2 | path = 3rdparty/clipper 3 | url = https://github.com/skyrpex/clipper.git 4 | [submodule "3rdparty/tinyxml2"] 5 | path = 3rdparty/tinyxml2 6 | url = https://github.com/leethomason/tinyxml2.git 7 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: cpp 2 | dist: trusty 3 | 4 | os: 5 | - linux 6 | - osx 7 | 8 | compiler: 9 | - gcc 10 | - clang 11 | 12 | before_script: 13 | - if [ "$TRAVIS_OS_NAME" == "linux" ]; then sudo apt-get install cmake; fi 14 | - if [ "$TRAVIS_OS_NAME" == "linux" ]; then sudo apt-get install libboost-all-dev; fi 15 | - mkdir build 16 | - cd build 17 | - cmake .. 18 | 19 | script: 20 | - make 21 | - cd ../bin 22 | - ./levels ../data/planar_graph_fig1.xml ../data/building_blocks_fig1.xml ../data/config.txt 10 23 | -------------------------------------------------------------------------------- /3rdparty/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | ADD_LIBRARY(polyclipping STATIC clipper/cpp/clipper.cpp clipper/cpp/clipper.hpp) 2 | ADD_LIBRARY(tinyxml2 STATIC tinyxml2/tinyxml2.cpp tinyxml2/tinyxml2.h) 3 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | CMAKE_MINIMUM_REQUIRED(VERSION 2.8.12) 2 | PROJECT(LevelSyn) 3 | 4 | include(CheckCXXCompilerFlag) 5 | CHECK_CXX_COMPILER_FLAG("-std=c++11" COMPILER_SUPPORTS_CXX11) 6 | if(COMPILER_SUPPORTS_CXX11) 7 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") 8 | else() 9 | message(STATUS "The compiler ${CMAKE_CXX_COMPILER} has no C++11 support. Please use a different C++ compiler.") 10 | endif() 11 | 12 | ADD_SUBDIRECTORY(3rdparty) 13 | ADD_SUBDIRECTORY(src) 14 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2016, the LevelSyn authors 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | * Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | * Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | * Neither the name of the copyright holder nor the names of its 17 | contributors may be used to endorse or promote products derived from 18 | this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | LevelSyn 2 | ======== 3 | 4 | [![Build Status](https://app.travis-ci.com/chongyangma/LevelSyn.svg?token=28YCkBfgbR7Sd67ewr9H&branch=master)](https://app.travis-ci.com/chongyangma/LevelSyn) [![Build status](https://ci.appveyor.com/api/projects/status/rppyp7wpf1un5dse?svg=true)](https://ci.appveyor.com/project/chongyangma/levelsyn) 5 | 6 | This repository contains the source code and example data of the following publication: 7 | 8 | > Game Level Layout from Design Specification 9 | > 10 | > [Chongyang Ma](http://chongyangma.com/), [Nicholas Vining](http://www.cs.ubc.ca/~nvining/), [Sylvain Lefebvre](https://www.antexel.com/sylefeb-research/), [Alla Sheffer](http://www.cs.ubc.ca/~sheffa/) 11 | > 12 | > In _Computer Graphics Forum (Proceedings of Eurographics 2014)_ 13 | > 14 | > [Project page](http://chongyangma.com/publications/gl/index.html), 15 | > [Paper](http://chongyangma.com/publications/gl/2014_gl_preprint.pdf), 16 | > [Slides](http://chongyangma.com/publications/gl/2014_gl_slides.pdf), 17 | > [BibTex](http://chongyangma.com/publications/gl/2014_gl_bib.txt) 18 | 19 | Requirements 20 | ------------ 21 | 22 | The code is cross-platform and has been tested under Windows (MSVC), Linux and Mac OS X. Compiling from scratch requires the installation of [CMake](https://cmake.org/) and [Boost C++ Libraries](http://www.boost.org/). Additional third-party dependencies (included in this repo as submodules) are: 23 | * [Clipper 6.4.2](https://github.com/skyrpex/clipper) for polygon intersection computation 24 | * [TinyXML-2](https://github.com/leethomason/tinyxml2) for loading/saving xml files 25 | 26 | Usage 27 | ----- 28 | 29 | Launching the compiled application from command line without any argument will print the usage information (MSVC version): 30 | 31 | ```bash 32 | levels.exe graph.xml templates.xml config.txt [target_solution_number] 33 | ``` 34 | 35 | Contact information 36 | ------------------- 37 | 38 | Questions? Bug reports? Please send email to Chongyang Ma chongyangm@gmail.com . 39 | -------------------------------------------------------------------------------- /data/building_blocks_fig1.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 19 | 21 | 22 | 24 | image/svg+xml 25 | 27 | 28 | 29 | 30 | 32 | 56 | 61 | 66 | 71 | 76 | 81 | 86 | 91 | 96 | 101 | 106 | 117 | 128 | 139 | 150 | 161 | 172 | 183 | 194 | 205 | 216 | 227 | 238 | 249 | 260 | 271 | 282 | 293 | 304 | 315 | 326 | 337 | 348 | 359 | 370 | 381 | 392 | 403 | 414 | 415 | -------------------------------------------------------------------------------- /data/building_blocks_fig1.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /data/building_blocks_fig11.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /data/building_blocks_fig6a.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 19 | 21 | 22 | 24 | image/svg+xml 25 | 27 | 28 | 29 | 30 | 32 | 56 | 61 | 66 | 71 | 76 | 81 | 86 | 97 | 108 | 119 | 130 | 141 | 152 | 163 | 174 | 185 | 196 | 207 | 218 | 219 | -------------------------------------------------------------------------------- /data/building_blocks_fig6a.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /data/building_blocks_fig6b.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 19 | 21 | 22 | 24 | image/svg+xml 25 | 27 | 28 | 29 | 30 | 32 | 56 | 61 | 66 | 71 | 76 | 81 | 86 | 97 | 108 | 119 | 130 | 141 | 152 | 163 | 174 | 185 | 196 | 207 | 218 | 229 | 240 | 251 | 262 | 273 | 284 | 295 | 306 | 307 | -------------------------------------------------------------------------------- /data/building_blocks_fig6b.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /data/building_blocks_fig6c.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /data/building_blocks_fig6c.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /data/building_blocks_fig6d.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /data/building_blocks_fig6d.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /data/config.txt: -------------------------------------------------------------------------------- 1 | FLAG_RANDOMNESS 0 2 | FLAG_ENABLE_TYPE_CHANGE 1 3 | FLAG_ENRICH_TEMPLATES 1 4 | FLAG_EQUAL_PICK_PROBABILITY 1 5 | FLAG_DISCRETE_CONNECTIVITY_FUNCTION 0 6 | FLAG_RANDOM_PICK 0 7 | FLAG_NON_OVERLAP_CONTACT 1 8 | FLAG_SMALL_FACE_FIRST 1 9 | FLAG_USE_ILS 0 10 | FLAG_RANDOM_WALK 0 11 | NUMBER_OF_SOLUTIONS_TO_TRACK 15 12 | SYNTHESIS_METHOD 0 13 | SA_NUM_OF_CYCLES 50 14 | SA_NUM_OF_TRIALS 500 15 | SA_PROB_0 0.010000 16 | SA_PROB_1 0.200000 17 | DELTA_E_SCALING 35.000000 18 | SIGMA_COLLIDE 5.000000 19 | SIGMA_CONTACT 0.000000 20 | SIGMA_CONNECTIVITY 5.000000 21 | GRAPH_SCALING 1.500000 22 | ROOM_SCALING 0.970000 23 | STATE_DIFFERENCE_THRESHOLD 0.010000 24 | ROOM_CONTACT_THRESHOLD 0.100000 25 | OUTPUT_PREFIX level_syn_output01\ 26 | -------------------------------------------------------------------------------- /data/planar_graph_fig1.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 0 42 | 1 43 | 2 44 | 3 45 | 4 46 | 5 47 | 6 48 | 7 49 | 8 50 | 9 51 | 10 52 | 11 53 | 12 54 | 13 55 | 14 56 | 15 57 | 16 58 | 59 | -------------------------------------------------------------------------------- /data/planar_graph_fig1.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | -------------------------------------------------------------------------------- /data/planar_graph_fig10_floor1.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 19 | 21 | 22 | 24 | image/svg+xml 25 | 27 | 28 | 29 | 30 | 32 | 56 | 61 | 66 | 71 | 76 | 81 | 86 | 91 | 96 | 101 | 106 | 111 | 116 | 127 | 138 | 149 | 160 | 171 | 182 | 193 | 204 | 215 | 0 221 | 1 227 | 2 233 | 3 239 | 4 245 | 5 251 | 6 257 | 7 263 | 8 269 | 270 | -------------------------------------------------------------------------------- /data/planar_graph_fig10_floor1.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /data/planar_graph_fig10_floor2.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 19 | 21 | 22 | 24 | image/svg+xml 25 | 27 | 28 | 29 | 30 | 32 | 56 | 61 | 66 | 71 | 76 | 81 | 86 | 91 | 96 | 101 | 106 | 111 | 116 | 121 | 126 | 131 | 142 | 153 | 164 | 175 | 186 | 197 | 208 | 219 | 230 | 241 | 252 | 0 258 | 1 264 | 2 270 | 3 276 | 4 282 | 5 288 | 6 294 | 7 300 | 8 306 | 9 312 | 10 318 | 319 | -------------------------------------------------------------------------------- /data/planar_graph_fig10_floor2.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /data/planar_graph_fig10_floor3.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 19 | 21 | 22 | 24 | image/svg+xml 25 | 27 | 28 | 29 | 30 | 32 | 56 | 61 | 66 | 71 | 76 | 81 | 86 | 91 | 96 | 101 | 106 | 111 | 116 | 121 | 126 | 137 | 148 | 159 | 170 | 181 | 192 | 203 | 214 | 225 | 236 | 247 | 258 | 269 | 0 275 | 1 281 | 2 287 | 3 293 | 4 299 | 5 305 | 6 311 | 7 317 | 8 323 | 9 329 | 10 335 | 11 341 | 12 347 | 348 | -------------------------------------------------------------------------------- /data/planar_graph_fig10_floor3.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /data/planar_graph_fig11.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 19 | 21 | 22 | 24 | image/svg+xml 25 | 27 | 28 | 29 | 30 | 32 | 56 | 61 | 66 | 71 | 76 | 81 | 86 | 91 | 96 | 101 | 106 | 111 | 116 | 121 | 126 | 137 | 148 | 159 | 170 | 181 | 192 | 203 | 214 | 225 | 236 | 247 | 258 | 269 | 0 275 | 1 281 | 2 287 | 3 293 | 4 299 | 5 305 | 6 311 | 7 317 | 8 323 | 9 329 | 10 335 | 11 341 | 12 347 | 348 | -------------------------------------------------------------------------------- /data/planar_graph_fig11.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /data/planar_graph_fig7_bottom.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 0 42 | 1 43 | 2 44 | 3 45 | 4 46 | 5 47 | 6 48 | 7 49 | 8 50 | 9 51 | 10 52 | 11 53 | 12 54 | 13 55 | 14 56 | 15 57 | 16 58 | 59 | -------------------------------------------------------------------------------- /data/planar_graph_fig7_bottom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /data/planar_graph_fig7_top.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 0 25 | 1 26 | 2 27 | 3 28 | 4 29 | 5 30 | 6 31 | 7 32 | 8 33 | 34 | -------------------------------------------------------------------------------- /data/planar_graph_fig7_top.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /data/planar_graph_fig8.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 0 88 | 1 89 | 2 90 | 3 91 | 4 92 | 5 93 | 6 94 | 7 95 | 8 96 | 9 97 | 10 98 | 11 99 | 12 100 | 13 101 | 14 102 | 15 103 | 16 104 | 17 105 | 18 106 | 19 107 | 20 108 | 21 109 | 22 110 | 23 111 | 24 112 | 25 113 | 26 114 | 27 115 | 28 116 | 29 117 | 30 118 | 31 119 | 32 120 | 33 121 | 34 122 | 35 123 | 36 124 | 37 125 | 38 126 | 39 127 | 40 128 | 129 | -------------------------------------------------------------------------------- /data/planar_graph_fig8.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | -------------------------------------------------------------------------------- /data/planar_graph_fig9.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 0 34 | 1 35 | 2 36 | 3 37 | 4 38 | 5 39 | 6 40 | 7 41 | 8 42 | 9 43 | 10 44 | 11 45 | 12 46 | 13 47 | 14 48 | 49 | -------------------------------------------------------------------------------- /data/planar_graph_fig9.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | CMAKE_MINIMUM_REQUIRED(VERSION 2.8.12) 2 | PROJECT(LevenSyn) 3 | 4 | IF(MSVC) 5 | # set( BOOST_ROOT "C:/Program Files/boost/boost_1_54_0") 6 | # set( BOOST_LIBRARYDIR "C:/Program Files/boost/boost_1_54_0/lib64-msvc-10.0" ) 7 | ENDIF() 8 | 9 | SET(Boost_USE_STATIC_LIBS TRUE) 10 | FIND_PACKAGE(Boost COMPONENTS thread REQUIRED) 11 | LINK_DIRECTORIES (${Boost_LIBRARY_DIRS}) 12 | INCLUDE_DIRECTORIES (${Boost_INCLUDE_DIRS}) 13 | 14 | IF(APPLE) 15 | FIND_LIBRARY(coreFoundation CoreFoundation) 16 | ENDIF() 17 | 18 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY $<1:${CMAKE_SOURCE_DIR}/bin>) 19 | 20 | FILE(GLOB LEVEL_SYN_SOURCES "*.cpp") 21 | FILE(GLOB LEVEL_SYN_HEADERS "*.h") 22 | 23 | INCLUDE_DIRECTORIES(../3rdparty/clipper/cpp) 24 | INCLUDE_DIRECTORIES(../3rdparty/tinyxml2) 25 | 26 | ADD_EXECUTABLE(levels ${LEVEL_SYN_SOURCES} ${LEVEL_SYN_HEADERS}) 27 | TARGET_LINK_LIBRARIES(levels tinyxml2 polyclipping ${Boost_LIBRARIES} ${Boost_THREAD_LIBRARY}) 28 | 29 | if(APPLE) 30 | TARGET_LINK_LIBRARIES(levels ${coreFoundation}) 31 | endif() 32 | -------------------------------------------------------------------------------- /src/ConfigSpace.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) www.chongyangma.com 2 | // 3 | // author: Chongyang Ma - 2013-07-15 4 | // email: chongyangm@gmail.com 5 | // info: class declaration of a configuration space 6 | // -------------------------------------------------------------- 7 | 8 | #ifndef CONFIGSPACE_H 9 | #define CONFIGSPACE_H 10 | 11 | #include "LevelMath.h" 12 | #include "Room.h" 13 | #include "clipperWrapper.h" 14 | 15 | using namespace level_math; 16 | 17 | class CConfigLine : public CLineBase 18 | { 19 | public: 20 | CConfigLine(v2f pos1, v2f pos2) : 21 | CLineBase(pos1, pos2) {} 22 | 23 | CConfigLine(v2f pos) : 24 | CLineBase(pos) {} 25 | 26 | v2f RandomlySampleConfigLine(); 27 | 28 | v2f RandomlySampleConfigLineDiscrete(); 29 | 30 | float GetConfigLineLength() const; 31 | 32 | float GetConfigLineSqLength() const; 33 | 34 | void PrintConfigLine(); 35 | 36 | void TranslateConfigLine(v2f trans); 37 | }; 38 | 39 | class CConfigSpace 40 | { 41 | public: 42 | CConfigSpace() {} 43 | 44 | // The configuration space to put room2 around room1... 45 | CConfigSpace(const CRoom& room1, const CRoom& room2); 46 | 47 | CConfigSpace(const std::vector& vecConfigLines); 48 | 49 | void AddConfigLine(const CConfigLine& line) { m_vecConfigLine.push_back(line); } 50 | 51 | v2f RandomlySampleConfigSpace(); 52 | 53 | v2f RandomlySampleConfigSpaceContinuous(); 54 | 55 | v2f RandomlySampleConfigSpaceDiscrete(); 56 | 57 | std::vector SmartlySampleConfigSpace(); 58 | 59 | int GetNumOfLines() { return int(m_vecConfigLine.size()); } 60 | 61 | bool IsEmpty() { return m_vecConfigLine.empty(); } 62 | 63 | void SetConfigLines(const std::vector& vecConfigLine) { m_vecConfigLine = vecConfigLine; } 64 | 65 | std::vector& GetConfigLines() { return m_vecConfigLine; } 66 | 67 | CConfigLine& GetConfigLine(int idx) { return m_vecConfigLine[idx]; } 68 | 69 | static CConfigSpace FindIntersection(CConfigSpace& configSpace1, CConfigSpace& configSpace2); 70 | 71 | static CConfigSpace FindUnion(CConfigSpace& configSpace, CConfigLine& configLine); 72 | 73 | void SelfMerge(); 74 | 75 | float GetConfigSpaceSize(); 76 | 77 | void PrintConfigSpace(); 78 | 79 | void TranslateConfigSpace(v2f trans); 80 | 81 | static bool CompareConfigLineLength(const CConfigLine& line1, const CConfigLine& line2); 82 | 83 | static void PrecomputeTable(const std::vector& vecRooms); 84 | 85 | static std::vector> m_precomputedTable; 86 | 87 | static bool m_flagPrecomputed; 88 | 89 | private: 90 | std::vector m_vecConfigLine; 91 | }; 92 | 93 | #endif // CONFIGSPACE_H 94 | -------------------------------------------------------------------------------- /src/GraphChain.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) www.chongyangma.com 2 | // 3 | // author: Chongyang Ma - 2013-08-17 4 | // email: chongyangm@gmail.com 5 | // info: class declaration of a graph chain 6 | // -------------------------------------------------------------- 7 | 8 | #ifndef GRAPHCHAIN_H 9 | #define GRAPHCHAIN_H 10 | 11 | #include 12 | #include 13 | 14 | class CGraphChain 15 | { 16 | public: 17 | CGraphChain() {} 18 | 19 | CGraphChain(std::vector& indices, bool flag) 20 | { 21 | m_indices = indices; 22 | m_flagCyclic = flag; 23 | } 24 | 25 | std::vector& GetIndices() { return m_indices; } 26 | 27 | void AddIndex(int idx) { m_indices.push_back(idx); } 28 | 29 | void ClearIndices() { m_indices.clear(); } 30 | 31 | int GetChainSize() { return int(m_indices.size()); } 32 | 33 | bool IsEmpty() { return m_indices.empty(); } 34 | 35 | bool GetFlagCyclic() { return m_flagCyclic; } 36 | 37 | void SetFlagCyclic(bool flag) { m_flagCyclic = flag; } 38 | 39 | private: 40 | std::vector m_indices; // graph nodes that form a chain 41 | bool m_flagCyclic; 42 | }; 43 | 44 | #endif // GRAPHCHAIN_H 45 | -------------------------------------------------------------------------------- /src/GraphEdge.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) www.chongyangma.com 2 | // 3 | // author: Chongyang Ma - 2013-06-06 4 | // email: chongyangm@gmail.com 5 | // info: class declaration of a graph edge 6 | // -------------------------------------------------------------- 7 | 8 | #ifndef GRAPHEDGE_H 9 | #define GRAPHEDGE_H 10 | 11 | #include 12 | #include 13 | 14 | class CGraphEdge 15 | { 16 | public: 17 | CGraphEdge(int idx0, int idx1) 18 | { 19 | m_indices.resize(2); 20 | m_indices[0] = idx0; 21 | m_indices[1] = idx1; 22 | } 23 | 24 | std::vector& GetIndices() { return m_indices; } 25 | 26 | int GetIdx0() const { return m_indices[0]; } 27 | int GetIdx1() const { return m_indices[1]; } 28 | 29 | void SetIdx0(int idx0) { m_indices[0] = idx0; } 30 | void SetIdx1(int idx1) { m_indices[1] = idx1; } 31 | 32 | private: 33 | std::vector m_indices; 34 | }; 35 | 36 | #endif // GRAPHEDGE_H 37 | -------------------------------------------------------------------------------- /src/GraphFace.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) www.chongyangma.com 2 | // 3 | // author: Chongyang Ma - 2013-06-06 4 | // email: chongyangm@gmail.com 5 | // info: class declaration of a graph face 6 | // -------------------------------------------------------------- 7 | 8 | #ifndef GRAPHFACE_H 9 | #define GRAPHFACE_H 10 | 11 | #include 12 | #include 13 | 14 | class CGraphFace 15 | { 16 | public: 17 | CGraphFace() {} 18 | 19 | CGraphFace(std::vector& indices) 20 | { 21 | m_indices = indices; 22 | } 23 | 24 | std::vector& GetIndices() { return m_indices; } 25 | 26 | void AddIndex(int idx) { m_indices.push_back(idx); } 27 | 28 | void ClearIndices() { m_indices.clear(); } 29 | 30 | int GetFaceSize() { return int(m_indices.size()); } 31 | 32 | bool IsEmpty() { return m_indices.empty(); } 33 | 34 | private: 35 | std::vector m_indices; // graph nodes that form a face 36 | }; 37 | 38 | #endif // GRAPHFACE_H 39 | -------------------------------------------------------------------------------- /src/GraphNode.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) www.chongyangma.com 2 | // 3 | // author: Chongyang Ma - 2013-06-06 4 | // email: chongyangm@gmail.com 5 | // info: class declaration of a graph node 6 | // -------------------------------------------------------------- 7 | 8 | #ifndef GRAPHNODE_H 9 | #define GRAPHNODE_H 10 | 11 | #include "vec.h" 12 | 13 | #include 14 | #include 15 | #include 16 | 17 | class CGraphNode 18 | { 19 | public: 20 | CGraphNode() 21 | { 22 | RandomlyInitPos(); 23 | m_flagVisited = false; 24 | m_flagFixed = false; 25 | m_type = 0; 26 | m_boundaryType = 0; 27 | } 28 | 29 | CGraphNode(std::string name) 30 | { 31 | m_name = name; 32 | RandomlyInitPos(); 33 | } 34 | 35 | std::string GetName() { return m_name; } 36 | void SetName(std::string name) { m_name = name; } 37 | 38 | void RandomlyInitPos() 39 | { 40 | for (int i = 0; i < 2; i++) 41 | { 42 | float p = rand() / float(RAND_MAX); 43 | p -= 0.5f; 44 | p *= 1.5f; 45 | m_pos[i] = p; 46 | } 47 | } 48 | 49 | v2f GetPos() { return m_pos; } 50 | void SetPos(v2f pos) { m_pos = pos; } 51 | void SetPos(float px, float py) 52 | { 53 | m_pos[0] = px; 54 | m_pos[1] = py; 55 | } 56 | 57 | void ClearNeighbors() { m_neighbors.clear(); } 58 | void AddNeighbor(int idx) { m_neighbors.push_back(idx); } 59 | std::vector& GetNeighbors() { return m_neighbors; } 60 | bool IsNeighbor(int idx) 61 | { 62 | for (int i = 0; i < int(m_neighbors.size()); i++) 63 | { 64 | if (m_neighbors[i] == idx) 65 | { 66 | return true; 67 | } 68 | } 69 | return false; 70 | } 71 | 72 | bool GetFlagVisited() { return m_flagVisited; } 73 | void SetFlagVisited(bool flagVisited) { m_flagVisited = flagVisited; } 74 | 75 | bool GetFlagFixed() const { return m_flagFixed; } 76 | void SetFlagFixed(bool flagFixed) { m_flagFixed = flagFixed; } 77 | 78 | int GetType() { return m_type; } 79 | void SetType(int type) { m_type = type; } 80 | 81 | int GetBoundaryType() const { return m_boundaryType; } 82 | void SetBoundaryType(int type) { m_boundaryType = type; } 83 | 84 | private: 85 | std::string m_name; 86 | v2f m_pos; 87 | std::vector m_neighbors; 88 | bool m_flagVisited; 89 | bool m_flagFixed; 90 | int m_type; // index of the room template 91 | int m_boundaryType; 92 | }; 93 | 94 | #endif // GRAPHNODE_H 95 | -------------------------------------------------------------------------------- /src/LevelConfig.cpp: -------------------------------------------------------------------------------- 1 | #include "LevelConfig.h" 2 | 3 | #ifndef WIN32 4 | #define MAX_PATH 260 5 | #endif 6 | 7 | bool CLevelConfig::m_flagRandomness = false; 8 | bool CLevelConfig::m_flagEnableTypeChange = true; 9 | bool CLevelConfig::m_flagEnrichTemplates = false; 10 | bool CLevelConfig::m_flagEqualPickProb = true; 11 | bool CLevelConfig::m_flagDiscreteConnectFunc = true; 12 | bool CLevelConfig::m_flagRandomPick = true; 13 | bool CLevelConfig::m_flagNonOverlapContact = false; 14 | bool CLevelConfig::m_flagSmallFaceFirst = false; 15 | bool CLevelConfig::m_flagUseILS = false; 16 | bool CLevelConfig::m_flagRandomWalk = false; 17 | int CLevelConfig::m_numOfSolutionsToTrack = 10; 18 | int CLevelConfig::m_synMethod = 0; 19 | int CLevelConfig::m_saNumOfCycles = 1000; 20 | int CLevelConfig::m_saNumOfTrials = 1000; 21 | int CLevelConfig::m_targetNumOfSolutions = 100; 22 | float CLevelConfig::m_saProb0 = 0.001f; 23 | float CLevelConfig::m_saProb1 = 0.7f; 24 | float CLevelConfig::m_deltaEscaling = 1.0f; 25 | float CLevelConfig::m_sigmaCollide = 50.f; 26 | float CLevelConfig::m_sigmaContact = 1.f; 27 | float CLevelConfig::m_sigmaConnectivity = 2.f; 28 | float CLevelConfig::m_graphScaling = 1.f; 29 | float CLevelConfig::m_roomScaling = 0.9f; 30 | float CLevelConfig::m_stateDiffThresh = 0.f; 31 | float CLevelConfig::m_roomContactThresh = 1e-6f; 32 | std::string CLevelConfig::m_outputPrefix; 33 | 34 | CLevelConfig::CLevelConfig() 35 | { 36 | } 37 | 38 | bool CLevelConfig::LoadFromSynConfig(std::string fileName, bool resetFlag /* = true */) 39 | { 40 | std::ifstream fin(fileName.c_str()); 41 | if (fin.fail() == true) 42 | { 43 | std::cout << "Failed to load config parameters from config file " << fileName << "!\n"; 44 | return false; 45 | } 46 | std::string param; 47 | while (fin >> param) 48 | { 49 | if (param == std::string("FLAG_RANDOMNESS")) 50 | { 51 | fin >> m_flagRandomness; 52 | } 53 | else if (param == std::string("FLAG_ENABLE_TYPE_CHANGE")) 54 | { 55 | fin >> m_flagEnableTypeChange; 56 | } 57 | else if (param == std::string("FLAG_ENRICH_TEMPLATES")) 58 | { 59 | fin >> m_flagEnrichTemplates; 60 | } 61 | else if (param == std::string("FLAG_EQUAL_PICK_PROBABILITY")) 62 | { 63 | fin >> m_flagEqualPickProb; 64 | } 65 | else if (param == std::string("FLAG_DISCRETE_CONNECTIVITY_FUNCTION")) 66 | { 67 | fin >> m_flagDiscreteConnectFunc; 68 | } 69 | else if (param == std::string("FLAG_RANDOM_PICK")) 70 | { 71 | fin >> m_flagRandomPick; 72 | } 73 | else if (param == std::string("FLAG_NON_OVERLAP_CONTACT")) 74 | { 75 | fin >> m_flagNonOverlapContact; 76 | } 77 | else if (param == std::string("FLAG_SMALL_FACE_FIRST")) 78 | { 79 | fin >> m_flagSmallFaceFirst; 80 | } 81 | else if (param == std::string("FLAG_USE_ILS")) 82 | { 83 | fin >> m_flagUseILS; 84 | } 85 | else if (param == std::string("FLAG_RANDOM_WALK")) 86 | { 87 | fin >> m_flagRandomWalk; 88 | } 89 | else if (param == std::string("NUMBER_OF_SOLUTIONS_TO_TRACK")) 90 | { 91 | fin >> m_numOfSolutionsToTrack; 92 | } 93 | else if (param == std::string("SYNTHESIS_METHOD")) 94 | { 95 | fin >> m_synMethod; 96 | } 97 | else if (param == std::string("SA_NUM_OF_CYCLES")) 98 | { 99 | fin >> m_saNumOfCycles; 100 | } 101 | else if (param == std::string("SA_NUM_OF_TRIALS")) 102 | { 103 | fin >> m_saNumOfTrials; 104 | } 105 | else if (param == std::string("SA_PROB_0")) 106 | { 107 | fin >> m_saProb0; 108 | } 109 | else if (param == std::string("SA_PROB_1")) 110 | { 111 | fin >> m_saProb1; 112 | } 113 | else if (param == std::string("DELTA_E_SCALING")) 114 | { 115 | fin >> m_deltaEscaling; 116 | } 117 | else if (param == std::string("SIGMA_COLLIDE")) 118 | { 119 | fin >> m_sigmaCollide; 120 | } 121 | else if (param == std::string("SIGMA_CONTACT")) 122 | { 123 | fin >> m_sigmaContact; 124 | } 125 | else if (param == std::string("SIGMA_CONNECTIVITY")) 126 | { 127 | fin >> m_sigmaConnectivity; 128 | } 129 | else if (param == std::string("GRAPH_SCALING")) 130 | { 131 | fin >> m_graphScaling; 132 | } 133 | else if (param == std::string("ROOM_SCALING")) 134 | { 135 | fin >> m_roomScaling; 136 | } 137 | else if (param == std::string("STATE_DIFFERENCE_THRESHOLD")) 138 | { 139 | fin >> m_stateDiffThresh; 140 | } 141 | else if (param == std::string("ROOM_CONTACT_THRESHOLD")) 142 | { 143 | fin >> m_roomContactThresh; 144 | } 145 | else if (param == std::string("OUTPUT_PREFIX")) 146 | { 147 | fin >> m_outputPrefix; 148 | } 149 | } 150 | if (resetFlag == false) 151 | { 152 | return true; 153 | } 154 | ResetConfig(); 155 | 156 | return true; 157 | } 158 | 159 | std::string CLevelConfig::AddOutputPrefix(std::string str) 160 | { 161 | if (m_outputPrefix.empty() == true) 162 | { 163 | return str; 164 | } 165 | std::ostringstream oss; 166 | oss << m_outputPrefix << str; 167 | std::string strNew = oss.str(); 168 | return strNew; 169 | } 170 | 171 | void CLevelConfig::ResetConfig() 172 | { 173 | if (m_flagRandomness == true) 174 | { 175 | srand((unsigned int)time(0)); 176 | } 177 | if (m_outputPrefix.empty() == false) 178 | { 179 | UpdateOutputPrefix(); 180 | } 181 | DumpToSynConfig(); 182 | } 183 | 184 | bool CLevelConfig::DumpToSynConfig() 185 | { 186 | std::ostringstream oss; 187 | oss << m_outputPrefix << "SynConfig.txt"; 188 | std::string fileName = oss.str(); 189 | FILE* file; 190 | file = fopen(fileName.c_str(), "w"); 191 | if (!file) 192 | { 193 | std::cout << "Failed to dump parameters into config file " << fileName << "!\n"; 194 | return false; 195 | } 196 | DumpTimeAndDate(file); 197 | DumpParameters(file); 198 | fclose(file); 199 | 200 | return true; 201 | } 202 | 203 | void CLevelConfig::DumpTimeAndDate(FILE* file) 204 | { 205 | time_t myTime = time(NULL); 206 | tm* ptrTime = localtime(&myTime); 207 | fprintf(file, "%02d:%02d:%02d ", ptrTime->tm_hour, ptrTime->tm_min, ptrTime->tm_sec); 208 | fprintf(file, "%02d/%02d/%04d\n\n", ptrTime->tm_mon + 1, ptrTime->tm_mday, ptrTime->tm_year + 1900); 209 | } 210 | 211 | void CLevelConfig::DumpTimeAndDate(std::ofstream& fout) 212 | { 213 | time_t myTime = time(NULL); 214 | tm* ptrTime = localtime(&myTime); 215 | char str[1000]; 216 | sprintf(str, "%02d:%02d:%02d ", ptrTime->tm_hour, ptrTime->tm_min, ptrTime->tm_sec); 217 | fout << str; 218 | sprintf(str, "%02d/%02d/%04d", ptrTime->tm_mon + 1, ptrTime->tm_mday, ptrTime->tm_year + 1900); 219 | fout << str << std::endl; 220 | } 221 | 222 | void CLevelConfig::DumpParameters(FILE* file) 223 | { 224 | fprintf(file, "%s\t%d\n", "FLAG_RANDOMNESS", m_flagRandomness); 225 | fprintf(file, "%s\t%d\n", "FLAG_ENABLE_TYPE_CHANGE", m_flagEnableTypeChange); 226 | fprintf(file, "%s\t%d\n", "FLAG_ENRICH_TEMPLATES", m_flagEnrichTemplates); 227 | fprintf(file, "%s\t%d\n", "FLAG_EQUAL_PICK_PROBABILITY", m_flagEqualPickProb); 228 | fprintf(file, "%s\t%d\n", "FLAG_DISCRETE_CONNECTIVITY_FUNCTION", m_flagDiscreteConnectFunc); 229 | fprintf(file, "%s\t%d\n", "FLAG_RANDOM_PICK", m_flagRandomPick); 230 | fprintf(file, "%s\t%d\n", "FLAG_NON_OVERLAP_CONTACT", m_flagNonOverlapContact); 231 | fprintf(file, "%s\t%d\n", "FLAG_SMALL_FACE_FIRST", m_flagSmallFaceFirst); 232 | fprintf(file, "%s\t%d\n", "FLAG_USE_ILS", m_flagUseILS); 233 | fprintf(file, "%s\t%d\n", "FLAG_RANDOM_WALK", m_flagRandomWalk); 234 | fprintf(file, "%s\t%d\n", "NUMBER_OF_SOLUTIONS_TO_TRACK", m_numOfSolutionsToTrack); 235 | fprintf(file, "%s\t%d\n", "SYNTHESIS_METHOD", m_synMethod); 236 | fprintf(file, "%s\t%d\n", "SA_NUM_OF_CYCLES", m_saNumOfCycles); 237 | fprintf(file, "%s\t%d\n", "SA_NUM_OF_TRIALS", m_saNumOfTrials); 238 | fprintf(file, "%s\t%f\n", "SA_PROB_0", m_saProb0); 239 | fprintf(file, "%s\t%f\n", "SA_PROB_1", m_saProb1); 240 | fprintf(file, "%s\t%f\n", "DELTA_E_SCALING", m_deltaEscaling); 241 | fprintf(file, "%s\t%f\n", "SIGMA_COLLIDE", m_sigmaCollide); 242 | fprintf(file, "%s\t%f\n", "SIGMA_CONTACT", m_sigmaContact); 243 | fprintf(file, "%s\t%f\n", "SIGMA_CONNECTIVITY", m_sigmaConnectivity); 244 | fprintf(file, "%s\t%f\n", "GRAPH_SCALING", m_graphScaling); 245 | fprintf(file, "%s\t%f\n", "ROOM_SCALING", m_roomScaling); 246 | fprintf(file, "%s\t%f\n", "STATE_DIFFERENCE_THRESHOLD", m_stateDiffThresh); 247 | fprintf(file, "%s\t%f\n", "ROOM_CONTACT_THRESHOLD", m_roomContactThresh); 248 | DumpStringParam(file, "OUTPUT_PREFIX", m_outputPrefix); 249 | } 250 | 251 | void CLevelConfig::UpdateOutputPrefix() 252 | { 253 | #ifdef WIN32 254 | if (m_outputPrefix[m_outputPrefix.size() - 1] != '\\') 255 | { 256 | m_outputPrefix = m_outputPrefix + std::string("\\"); 257 | } 258 | #else 259 | while (m_outputPrefix.empty() == false && isdigit(m_outputPrefix[m_outputPrefix.size() - 1]) == 0) 260 | { 261 | m_outputPrefix = m_outputPrefix.substr(0, m_outputPrefix.size() - 1); 262 | } 263 | if (m_outputPrefix[m_outputPrefix.size() - 1] != '/') 264 | { 265 | m_outputPrefix = m_outputPrefix + std::string("/"); 266 | } 267 | #endif 268 | std::ostringstream oss; 269 | #ifdef WIN32 270 | bool flag = CreateDirectoryA(m_outputPrefix.c_str(), NULL); 271 | const int numLength = 2; 272 | while (flag == false && m_outputPrefix.size() >= 2) 273 | { 274 | std::string subStr = m_outputPrefix.substr(m_outputPrefix.length() - numLength - 1, 2); 275 | int num = atoi(subStr.c_str()) + 1; 276 | char numChar[MAX_PATH]; 277 | sprintf_s(numChar, "%02d", num); 278 | std::ostringstream oss; 279 | oss << m_outputPrefix.substr(0, m_outputPrefix.length() - numLength - 1) << numChar << "\\"; 280 | m_outputPrefix = oss.str(); 281 | flag = CreateDirectoryA(m_outputPrefix.c_str(), NULL); 282 | } 283 | #else 284 | std::string outputFolder = m_outputPrefix.substr(0, m_outputPrefix.size() - 1); 285 | int flag = mkdir(outputFolder.c_str(), 0777); 286 | const int numLength = 2; 287 | while (flag == -1 && m_outputPrefix.size() >= 2) 288 | { 289 | std::string subStr = m_outputPrefix.substr(m_outputPrefix.length() - numLength - 1, 2); 290 | int num = atoi(subStr.c_str()) + 1; 291 | char numChar[MAX_PATH]; 292 | sprintf(numChar, "%02d", num); 293 | std::ostringstream oss; 294 | oss << m_outputPrefix.substr(0, m_outputPrefix.length() - numLength - 1) << numChar << "/"; 295 | m_outputPrefix = oss.str(); 296 | outputFolder = m_outputPrefix.substr(0, m_outputPrefix.size() - 1); 297 | flag = mkdir(outputFolder.c_str(), 0777); 298 | } 299 | #endif 300 | std::cout << "Generating results into the directory: " << m_outputPrefix.c_str() << "...\n"; 301 | } 302 | 303 | void CLevelConfig::DumpStringParam(FILE* file, const char* param, const std::string& str) 304 | { 305 | if (str.empty() != true) 306 | { 307 | fprintf(file, "%s\t%s\n", param, str.c_str()); 308 | } 309 | else 310 | { 311 | //fprintf(file, "%s\t%s\n", param, "NULL"); 312 | } 313 | } 314 | -------------------------------------------------------------------------------- /src/LevelConfig.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) www.chongyangma.com 2 | // 3 | // author: Chongyang Ma - 2013-06-13 4 | // email: chongyangm@gmail.com 5 | // info: class declaration of config file for level synthesis 6 | // -------------------------------------------------------------- 7 | 8 | #ifndef LEVELCONFIG_H 9 | #define LEVELCONFIG_H 10 | 11 | #ifdef WIN32 12 | #include 13 | #else 14 | #include 15 | #endif 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | class CLevelConfig 26 | { 27 | public: 28 | CLevelConfig(); 29 | 30 | bool LoadFromSynConfig(std::string fileName, bool resetFlag = true); 31 | 32 | static std::string AddOutputPrefix(std::string str); 33 | 34 | static bool m_flagRandomness; 35 | static bool m_flagEnableTypeChange; 36 | static bool m_flagEnrichTemplates; 37 | static bool m_flagEqualPickProb; 38 | static bool m_flagDiscreteConnectFunc; 39 | static bool m_flagRandomPick; 40 | static bool m_flagNonOverlapContact; 41 | static bool m_flagSmallFaceFirst; 42 | static bool m_flagUseILS; 43 | static bool m_flagRandomWalk; 44 | static int m_numOfSolutionsToTrack; 45 | static int m_synMethod; 46 | static int m_targetNumOfSolutions; 47 | // For simulated annealing... 48 | static int m_saNumOfCycles; 49 | static int m_saNumOfTrials; 50 | static float m_saProb0; 51 | static float m_saProb1; 52 | static float m_deltaEscaling; 53 | // For layout energy calculation... 54 | static float m_sigmaCollide; 55 | static float m_sigmaContact; 56 | static float m_sigmaConnectivity; 57 | static float m_graphScaling; // For initialization 58 | static float m_roomScaling; // For rendering only 59 | static float m_stateDiffThresh; 60 | static float m_roomContactThresh; 61 | static std::string m_outputPrefix; 62 | 63 | static void DumpTimeAndDate(FILE* file); 64 | 65 | static void DumpTimeAndDate(std::ofstream& fout); 66 | 67 | protected: 68 | virtual void ResetConfig(); 69 | 70 | bool DumpToSynConfig(); 71 | 72 | virtual void DumpParameters(FILE* file); 73 | 74 | virtual void UpdateOutputPrefix(); 75 | 76 | void DumpStringParam(FILE* file, const char* param, const std::string& str); 77 | }; 78 | 79 | #endif //LEVELCONFIG_H 80 | -------------------------------------------------------------------------------- /src/LevelMath.cpp: -------------------------------------------------------------------------------- 1 | #include "LevelMath.h" 2 | 3 | namespace level_math 4 | { 5 | float PointToSegmentSqDistance(const v2f& pt, const CLineBase& line) 6 | { 7 | if (line.GetSqLength() < g_numericalTolerance * g_numericalTolerance) 8 | { 9 | return mag2(pt - line.GetPos1()); 10 | } 11 | float d1 = mag2(pt - line.GetPos1()); 12 | float d2 = mag2(pt - line.GetPos2()); 13 | v2f pe = line.GetPos2() - line.GetPos1(); 14 | v2f pd = pt - line.GetPos1(); 15 | float dp = dot(pe, pd); 16 | float r = dp / mag2(pe); 17 | float d; 18 | if (r >= 1.f) 19 | { 20 | d = d2; 21 | } 22 | else if (r <= 0.f) 23 | { 24 | d = d1; 25 | } 26 | else 27 | { 28 | v2f peNew = v2f(pe[1], -pe[0]); 29 | d = std::abs(dot(pd, peNew) / mag(peNew)); 30 | d = d * d; 31 | } 32 | return d; 33 | } 34 | 35 | float PointToLineSqDistance(const v2f& pt, const CLineBase& line) 36 | { 37 | return PointToLineSqDistance(pt, line.GetPos2(), line.GetPos1()); 38 | } 39 | 40 | float PointToLineSqDistance(const v2f& pt, const v2f& p1, const v2f& p2) 41 | { 42 | v2f pe = p2 - p1; 43 | v2f peNorm = normalize(pe); 44 | v2f pr = pt - p1; 45 | v3f peNew = v3f(peNorm[0], peNorm[1], 0.f); 46 | v3f prNew = v3f(pr[0], pr[1], 0.f); 47 | v3f cp = cross(peNew, prNew); 48 | float d = mag2(cp); 49 | return d; 50 | } 51 | 52 | float RoomPerimeter(const CRoom& room1) 53 | { 54 | float contactArea = 0.f; 55 | for (int i = 0; i < room1.GetNumOfEdges(); i++) 56 | { 57 | CRoomEdge edge1 = room1.GetEdge(i); 58 | contactArea += edge1.GetLength(); 59 | } 60 | 61 | return contactArea; 62 | } 63 | 64 | float RoomContact(const CRoom& room1, const CRoom& room2) 65 | { 66 | float contactArea = 0.f; 67 | for (int i = 0; i < room1.GetNumOfEdges(); i++) 68 | { 69 | CRoomEdge edge1 = room1.GetEdge(i); 70 | for (int j = 0; j < room2.GetNumOfEdges(); j++) 71 | { 72 | CRoomEdge edge2 = room2.GetEdge(j); 73 | if (edge1.GetDoorFlag() == false || edge2.GetDoorFlag() == false) 74 | { 75 | continue; 76 | } 77 | float contactAreaTmp = EdgeContact(edge1, edge2); 78 | contactArea += contactAreaTmp; 79 | } 80 | } 81 | 82 | return contactArea; 83 | } 84 | 85 | float RoomContact(const CRoom& room1, const CRoom& room2, int& edgeIdx1, int& edgeIdx2) 86 | { 87 | float contactAreaMax = 0.f; 88 | for (int i = 0; i < room1.GetNumOfEdges(); i++) 89 | { 90 | CRoomEdge edge1 = room1.GetEdge(i); 91 | for (int j = 0; j < room2.GetNumOfEdges(); j++) 92 | { 93 | CRoomEdge edge2 = room2.GetEdge(j); 94 | if (edge1.GetDoorFlag() == false || edge2.GetDoorFlag() == false) 95 | { 96 | continue; 97 | } 98 | float contactAreaTmp = EdgeContact(edge1, edge2); 99 | if (contactAreaTmp > contactAreaMax) 100 | { 101 | contactAreaMax = contactAreaTmp; 102 | edgeIdx1 = i; 103 | edgeIdx2 = j; 104 | } 105 | } 106 | } 107 | 108 | return contactAreaMax; 109 | } 110 | 111 | float EdgeContact(const CLineBase& line1, const CLineBase& line2) 112 | { 113 | const float numericalTolerance = g_numericalTolerance * 100.f; 114 | const float numericalToleranceSq = numericalTolerance * numericalTolerance; 115 | v2f pr1 = line1.GetPos2() - line1.GetPos1(); 116 | v2f pr2 = line2.GetPos2() - line2.GetPos1(); 117 | v3f pe1 = v3f(pr1[0], pr1[1], 0.f); 118 | v3f pe2 = v3f(pr2[0], pr2[1], 0.f); 119 | v3f cp = cross(pe1, pe2); 120 | if (mag2(cp) > numericalTolerance) 121 | { 122 | return 0.f; 123 | } 124 | v2f posMin1 = min_union(line1.GetPos1(), line1.GetPos2()); 125 | v2f posMax1 = max_union(line1.GetPos1(), line1.GetPos2()); 126 | v2f posMin2 = min_union(line2.GetPos1(), line2.GetPos2()); 127 | v2f posMax2 = max_union(line2.GetPos1(), line2.GetPos2()); 128 | for (int j = 0; j < 2; j++) 129 | { 130 | if (posMax1[j] < posMin2[j] - numericalTolerance || posMin1[j] > posMax2[j] + numericalTolerance) 131 | { 132 | return 0.f; 133 | } 134 | } 135 | float d1 = PointToLineSqDistance(line2.GetPos1(), line1); 136 | float d2 = PointToLineSqDistance(line2.GetPos2(), line1); 137 | if (d1 > numericalToleranceSq || d2 > numericalToleranceSq) 138 | { 139 | return 0.f; 140 | } 141 | // Now the two edges should in the same line anyway... 142 | float len1 = mag(pe1); 143 | float len2 = mag(pe2); 144 | float d11 = mag2(line1.GetPos1() - line2.GetPos1()); 145 | float d21 = mag2(line1.GetPos2() - line2.GetPos1()); 146 | float d12 = mag2(line1.GetPos1() - line2.GetPos2()); 147 | float d22 = mag2(line1.GetPos2() - line2.GetPos2()); 148 | float dMax = sqrt(max(max(d11, d21), max(d12, d22))); 149 | dMax = max(dMax, max(len1, len2)); 150 | float contactArea = len1 + len2 - dMax; 151 | contactArea = max(contactArea, 0.f); 152 | return contactArea; 153 | } 154 | 155 | float RoomDistance(const CRoom& room1, const CRoom& room2) 156 | { 157 | float d = 1e10; 158 | for (int i = 0; i < room1.GetNumOfVertices(); i++) 159 | { 160 | v2f pt = room1.GetVertex(i); 161 | for (int j = 0; j < room2.GetNumOfEdges(); j++) 162 | { 163 | CRoomEdge edge = room2.GetEdge(j); 164 | float dTmp = PointToSegmentSqDistance(pt, edge); 165 | d = min(d, dTmp); 166 | } 167 | } 168 | d = sqrt(d); 169 | return d; 170 | } 171 | 172 | bool SegmentIntersection(v2f pa, v2f pb, v2f pc, v2f pd, v2f& pi) 173 | { 174 | return SegmentIntersection(pa[0], pa[1], pb[0], pb[1], pc[0], pc[1], pd[0], pd[1], pi[0], pi[1]); 175 | } 176 | 177 | // Based on the example under http://stackoverflow.com/questions/563198/how-do-you-detect-where-two-line-segments-intersect 178 | bool SegmentIntersection(float Ax, float Ay, float Bx, float By, float Cx, float Cy, float Dx, float Dy, float& Ix, float& Iy) 179 | { 180 | float Rx = Bx - Ax; 181 | float Ry = By - Ay; 182 | float Sx = Dx - Cx; 183 | float Sy = Dy - Cy; 184 | float QPx = Cx - Ax; 185 | float QPy = Cy - Ay; 186 | float rs = Rx * Sy - Ry * Sx; 187 | if (rs == 0.f) 188 | { 189 | return false; 190 | } 191 | float t = (QPx * Sy - QPy * Sx) / rs; 192 | float u = (QPx * Ry - QPy * Rx) / rs; 193 | if (t >= 0.f && t <= 1.f && u >= 0.f && u <= 1.f) 194 | { 195 | Ix = Ax + t * Rx; 196 | Iy = Ay + t * Ry; 197 | return true; 198 | } 199 | else 200 | { 201 | return false; 202 | } 203 | } 204 | 205 | bool LineIntersection(v2f pa, v2f pb, v2f pc, v2f pd, v2f& pi) 206 | { 207 | return LineIntersection(pa[0], pa[1], pb[0], pb[1], pc[0], pc[1], pd[0], pd[1], pi[0], pi[1]); 208 | } 209 | 210 | bool LineIntersection(float Ax, float Ay, float Bx, float By, float Cx, float Cy, float Dx, float Dy, float& Ix, float& Iy) 211 | { 212 | float Rx = Bx - Ax; 213 | float Ry = By - Ay; 214 | float Sx = Dx - Cx; 215 | float Sy = Dy - Cy; 216 | float QPx = Cx - Ax; 217 | float QPy = Cy - Ay; 218 | float rs = Rx * Sy - Ry * Sx; 219 | if (rs == 0.f) 220 | { 221 | return false; 222 | } 223 | float t = (QPx * Sy - QPy * Sx) / rs; 224 | Ix = Ax + t * Rx; 225 | Iy = Ay + t * Ry; 226 | return true; 227 | } 228 | 229 | bool ComparePrSmallerFirst(const PrSort& pr1, const PrSort& pr2) 230 | { 231 | return (pr1.m_dp < pr2.m_dp); 232 | } 233 | 234 | void SortVecPr(std::vector& vecPr) 235 | { 236 | if (vecPr.size() < 2) 237 | { 238 | return; 239 | } 240 | v2f pd = vecPr[1] - vecPr[0]; 241 | std::vector vecPrSort(vecPr.size()); 242 | for (int i = 0; i < int(vecPrSort.size()); i++) 243 | { 244 | vecPrSort[i].m_pr = vecPr[i]; 245 | vecPrSort[i].m_dp = dot(pd, vecPr[i] - vecPr[0]); 246 | } 247 | sort(vecPrSort.begin(), vecPrSort.end(), ComparePrSmallerFirst); 248 | for (int i = 0; i < int(vecPrSort.size()); i++) 249 | { 250 | vecPr[i] = vecPrSort[i].m_pr; 251 | } 252 | } 253 | 254 | v3f randomColorFromIndex(int idx) 255 | { 256 | static std::vector clrs; 257 | if (clrs.empty()) 258 | { 259 | clrs.resize(256); 260 | for (int c = 0; c < clrs.size(); c++) 261 | { 262 | clrs[c] = v3f(rand(), rand(), rand()); 263 | clrs[c] = clrs[c] / max(clrs[c]); 264 | } 265 | } 266 | return (clrs[idx & 255]); 267 | } 268 | } // namespace level_math 269 | -------------------------------------------------------------------------------- /src/LevelMath.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) www.chongyangma.com 2 | // 3 | // author: Chongyang Ma - 2013-06-15 4 | // email: chongyangm@gmail.com 5 | // info: wrapper for basic math operations 6 | // -------------------------------------------------------------- 7 | 8 | #ifndef LEVELMATH_H 9 | #define LEVELMATH_H 10 | 11 | #include "Room.h" 12 | 13 | namespace level_math 14 | { 15 | typedef struct PrSort 16 | { 17 | v2f m_pr; 18 | float m_dp; // dot product 19 | } PrSort; 20 | 21 | const float g_numericalTolerance = 1e-4f; //1e-6; 22 | 23 | const float g_numericalToleranceSq = g_numericalTolerance * g_numericalTolerance; 24 | 25 | float PointToSegmentSqDistance(const v2f& pt, const CLineBase& line); 26 | 27 | float PointToLineSqDistance(const v2f& pt, const CLineBase& line); 28 | 29 | float PointToLineSqDistance(const v2f& pt, const v2f& p1, const v2f& p2); 30 | 31 | float RoomPerimeter(const CRoom& room1); 32 | 33 | float RoomContact(const CRoom& room1, const CRoom& room2); 34 | 35 | float RoomContact(const CRoom& room1, const CRoom& room2, int& edgeIdx1, int& edgeIdx2); 36 | 37 | float EdgeContact(const CLineBase& line1, const CLineBase& line2); 38 | 39 | float RoomDistance(const CRoom& room1, const CRoom& room2); 40 | 41 | bool SegmentIntersection(v2f pa, v2f pb, v2f pc, v2f pd, v2f& pi); 42 | 43 | bool SegmentIntersection(float Ax, float Ay, float Bx, float By, float Cx, float Cy, float Dx, float Dy, float& Ix, float& Iy); 44 | 45 | bool LineIntersection(v2f pa, v2f pb, v2f pc, v2f pd, v2f& pi); 46 | 47 | bool LineIntersection(float Ax, float Ay, float Bx, float By, float Cx, float Cy, float Dx, float Dy, float& Ix, float& Iy); 48 | 49 | bool ComparePrSmallerFirst(const PrSort& pr1, const PrSort& pr2); 50 | 51 | void SortVecPr(std::vector& vecPr); 52 | 53 | v3f randomColorFromIndex(int idx); 54 | } // namespace level_math 55 | 56 | #endif // LEVELMATH_H 57 | -------------------------------------------------------------------------------- /src/LevelSynth.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) www.chongyangma.com 2 | // 3 | // author: Chongyang Ma - 2013-03-07 4 | // email: chongyangm@gmail.com 5 | // info: class declaration of the level synthesis algorithm 6 | // -------------------------------------------------------------- 7 | 8 | #ifndef LEVELSYNTH_H 9 | #define LEVELSYNTH_H 10 | 11 | #include "ConfigSpace.h" 12 | #include "LevelConfig.h" 13 | #include "PlanarGraph.h" 14 | #include "RoomLayout.h" 15 | #include "RoomTemplates.h" 16 | #include "clipperWrapper.h" 17 | 18 | #include 19 | #include 20 | 21 | #ifdef __linux__ 22 | #include 23 | #endif 24 | 25 | //#define PRINT_OUT_DEBUG_INFO 26 | 27 | // Use to track current solution state 28 | class CurrentState 29 | { 30 | public: 31 | CPlanarGraph m_stateGraph; 32 | std::vector m_stateRoomPositions; 33 | std::vector myIndices; 34 | 35 | float m_stateEnergy; 36 | 37 | void MoveRoomsToSceneCenter(CPlanarGraph* ptrGraph); 38 | 39 | void Move1DchainToSceneCenter(std::vector& indices); 40 | 41 | float GetStateDifference(CurrentState& otherState, CPlanarGraph* ptrGraph); 42 | 43 | bool InsertToNewStates(std::vector& newStates, CPlanarGraph* ptrGraph); 44 | }; 45 | 46 | class CLevelSynth 47 | { 48 | public: 49 | CLevelSynth(); 50 | 51 | CLevelSynth(CPlanarGraph* ptrGraph, CRoomTemplates* ptrTemplates); 52 | 53 | void SetGraphAndTemplates(CPlanarGraph* ptrGraph, CRoomTemplates* ptrTemplates); 54 | 55 | void SetGraph(CPlanarGraph* ptrGraph); 56 | 57 | bool MovePickedGraphNode(float& dx, float& dy); 58 | 59 | bool AdjustPickedRoom(float& dx, float& dy); 60 | 61 | void InitScene(); 62 | 63 | CRoomLayout GetLayout(CPlanarGraph* ptrGraph, std::vector& roomPositions); 64 | 65 | void SynthesizeScene(); 66 | 67 | void UpdateGraphFromLayout(); 68 | 69 | bool PostProcessing(CRoomLayout& layout, CPlanarGraph* ptrGraph); 70 | 71 | bool OpenDoors(CRoomLayout& layout, CPlanarGraph* ptrGraph, bool flagPartial = false); 72 | 73 | bool OpenDoor(CRoom& room, RoomDoor& door, float width = -1.f); 74 | 75 | bool OpenDoors(CRoomLayout& layout, CRoomLayout& layoutShrinked, CPlanarGraph* ptrGraph, float thrinkDist); 76 | 77 | void ShrinkRooms(CRoomLayout& layout, float dist); 78 | 79 | void ShrinkRoom(CRoom& room, float dist); 80 | 81 | bool SaveGraphAsSVG(const char* fileName, CPlanarGraph* ptrGraph, int wd = 800, int ht = 800, float labelRad = 0.25f); 82 | 83 | static bool CompareStateEnergySmallerFirst(const CurrentState& state1, const CurrentState& state2); 84 | 85 | int GetSolutionCount() { return m_solutionCount; } 86 | 87 | void ResetSolutionCount() { m_solutionCount = 0; } 88 | 89 | void ResetIterationCount() 90 | { 91 | m_chainCount = 0; 92 | } 93 | 94 | inline std::string sprint(const char* fmt, ...) 95 | { 96 | int size = 512; 97 | char* buffer = 0; 98 | buffer = new char[size]; 99 | va_list vl; 100 | va_start(vl, fmt); 101 | int nsize = vsnprintf(buffer, size, fmt, vl); 102 | if (size <= nsize) 103 | { 104 | //fail delete buffer and try again 105 | delete[] buffer; 106 | buffer = 0; 107 | buffer = new char[nsize + 1]; //+1 for /0 108 | nsize = vsnprintf(buffer, size, fmt, vl); 109 | } 110 | std::string ret(buffer); 111 | va_end(vl); 112 | delete[] buffer; 113 | return ret; 114 | } 115 | 116 | private: 117 | void SynthesizeSceneViaMainLoop(); 118 | 119 | bool Solve1Dchain(std::vector& indices, std::vector* tmpIndices, CurrentState& oldState, std::vector& newStates); 120 | 121 | bool Solve1DchainILS(std::vector& indices, CurrentState& oldState, std::vector& newStates); 122 | 123 | void SetCurrentState(CurrentState& s); 124 | 125 | void SetSequenceAs1Dchain(const std::vector& indices, CPlanarGraph* ptrGraph); 126 | 127 | void SetVisitedNeighbors(const std::vector& indices); 128 | 129 | void DumpSolutionIntoXML(); 130 | 131 | int RandomlyPickOneRoom(CRoomLayout& layout); 132 | 133 | int RandomlyPickOneRoom(std::vector& indices, std::vector* weightedIndices = NULL); 134 | 135 | int RandomlyPickOneRoom(CRoomLayout& layout, std::vector& indices, std::vector* weightedIndices); 136 | 137 | int RandomlyPickAnotherRoom(CRoomLayout& layout, int pickedIndex); 138 | 139 | std::vector GetConnectedIndices(CPlanarGraph* ptrGraph, int pickedIndex, bool flagVisitedOnly = true); 140 | 141 | int RandomlyAdjustOneRoom(CRoomLayout& layout, CPlanarGraph* ptrGraph, std::vector& indices, std::vector* weightedIndices); 142 | 143 | void RandomlyAdjustOneRoom01(CRoomLayout& layout, CPlanarGraph* ptrGraph, std::vector& indices); 144 | 145 | void RandomlyAdjustOneRoom02(CRoomLayout& layout, CPlanarGraph* ptrGraph, std::vector& indices); 146 | 147 | int RandomlyAdjustOneRoom03(CRoomLayout& layout, CPlanarGraph* ptrGraph, std::vector& indices, std::vector* weightedIndices); 148 | 149 | void SampleConfigSpaceForPickedRoom(CRoomLayout& layout, CPlanarGraph* ptrGraph, std::vector& indices, int pickedRoomIndex); 150 | 151 | int RandomlyAdjustOneRoom04(CRoomLayout& layout, CPlanarGraph* ptrGraph, std::vector& indices, std::vector* weightedIndices); 152 | 153 | int GradientDescentOneRoom(CRoomLayout& layout, CPlanarGraph* ptrGraph, std::vector& indices); 154 | 155 | float GetLayoutEnergy(CRoomLayout& layout, CPlanarGraph* ptrGraph, float& collideArea, float& connectivity, int roomThatMoved = -1, bool doContact = false, std::vector* indicesForContact = NULL); 156 | 157 | bool GetLayoutEnergyEarlyOut(CRoomLayout& layout, CPlanarGraph* ptrGraph, float& collideArea, float& connectivity, int roomThatMoved = -1, float* energyTmp = NULL, float energyCurrent = 0.0f); 158 | 159 | float CheckRoomConnectivity(CRoomLayout& layout, CPlanarGraph* ptrGraph, bool flagVisitedOnly = false, int roomThatMoved = -1); 160 | 161 | float LayoutCollide(CRoomLayout& layout, CPlanarGraph* ptrGraph, bool flagVisitedOnly = false, int roomThatMoved = -1); 162 | 163 | float LayoutCollide(CRoomLayout& layout); 164 | 165 | float RoomCollides(CRoom& room1, CRoom& room2); 166 | 167 | float BoundingBoxCollidesArea(AABB2f& bb1, AABB2f& bb2); // not-in-use 168 | 169 | bool TestBoundingBoxCollides(AABB2f& bb1, AABB2f& bb2); 170 | 171 | float LayoutContact(CRoomLayout& layout, CPlanarGraph* ptrGraph, bool flagVisitedOnly = false, bool flagNonOverlap = false, std::vector* indices = NULL, int roomThatMoved = -1); 172 | 173 | v2f ComputeLabelPosition(int idx, CPlanarGraph* ptrGraph, float labelRad); 174 | 175 | std::vector m_sequence; // 1D chain of instantiated room templates 176 | 177 | CPlanarGraph* m_ptrGraph; 178 | CRoomTemplates* m_ptrTemplates; 179 | CRoomLayout m_layout; 180 | 181 | int m_solutionCount; 182 | std::vector m_roomPositions; 183 | std::vector> m_visitedNeighbors; 184 | int m_bestSolCount = 0; 185 | 186 | bool m_flagVisitedNoNode; 187 | 188 | int m_chainCount; 189 | 190 | int m_backTrackCount; 191 | int m_backTrackLevel; 192 | }; 193 | 194 | #endif // LEVELSYNTH_H 195 | -------------------------------------------------------------------------------- /src/LevelTimer.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) www.chongyangma.com 2 | // 3 | // author: Chongyang Ma - 2013-08-28 4 | // email: chongyangm@gmail.com 5 | // info: class declaration of CLevelTimer for performance measurement 6 | // ------------------------------------------------------------------- 7 | 8 | #ifndef LEVELTIMER_H 9 | #define LEVELTIMER_H 10 | 11 | #ifdef __APPLE__ 12 | 13 | #include 14 | 15 | class CLevelTimer 16 | { 17 | public: 18 | CLevelTimer() {} 19 | 20 | double GetTime() 21 | { 22 | double time = CFAbsoluteTimeGetCurrent(); 23 | return time; 24 | } 25 | 26 | double GetElapsedTime(double old_time) 27 | { 28 | double time = CFAbsoluteTimeGetCurrent(); 29 | return (time - old_time); 30 | } 31 | }; 32 | 33 | #endif 34 | 35 | #ifdef WIN32 36 | 37 | #include 38 | typedef __int64 i64; 39 | 40 | class CLevelTimer 41 | { 42 | public: 43 | CLevelTimer(); 44 | double GetTime(); 45 | double GetElapsedTime(double old_time); 46 | 47 | private: 48 | i64 m_freq; 49 | i64 m_clocks; 50 | }; 51 | 52 | CLevelTimer::CLevelTimer() : 53 | m_clocks(0) 54 | { 55 | QueryPerformanceFrequency((LARGE_INTEGER*)&m_freq); 56 | } 57 | 58 | double CLevelTimer::GetTime() 59 | { 60 | QueryPerformanceCounter((LARGE_INTEGER*)&m_clocks); 61 | return (double)m_clocks / (double)m_freq; 62 | } 63 | 64 | double CLevelTimer::GetElapsedTime(double old_time) 65 | { 66 | QueryPerformanceCounter((LARGE_INTEGER*)&m_clocks); 67 | return ((double)m_clocks / (double)m_freq - old_time); 68 | } 69 | 70 | #endif 71 | 72 | #ifdef __linux__ 73 | 74 | #include 75 | 76 | class CLevelTimer 77 | { 78 | public: 79 | CLevelTimer() {} 80 | 81 | double GetTime() 82 | { 83 | double time_res = (double)time(NULL); 84 | return time_res; 85 | } 86 | 87 | double GetElapsedTime(double old_time) 88 | { 89 | double time_res = time(NULL); 90 | return (time_res - old_time); 91 | } 92 | }; 93 | 94 | #endif 95 | 96 | #endif // LEVELTIMER_H 97 | -------------------------------------------------------------------------------- /src/LineBase.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) www.chongyangma.com 2 | // 3 | // author: Chongyang Ma - 2013-08-22 4 | // email: chongyangm@gmail.com 5 | // info: base class declaration of a line-shaped object 6 | // -------------------------------------------------------------- 7 | 8 | #ifndef LINEBASE_H 9 | #define LINEBASE_H 10 | 11 | #include "vec.h" 12 | 13 | class CLineBase 14 | { 15 | public: 16 | CLineBase() 17 | { 18 | m_pos1 = v2f(0.f); 19 | m_pos2 = v2f(0.f); 20 | } 21 | 22 | CLineBase(v2f pos) : 23 | m_pos1(pos), m_pos2(pos) 24 | { 25 | } 26 | 27 | CLineBase(v2f pos1, v2f pos2) : 28 | m_pos1(pos1), m_pos2(pos2) 29 | { 30 | } 31 | 32 | float GetLength() const { return mag(m_pos2 - m_pos1); } 33 | 34 | float GetSqLength() const { return mag2(m_pos2 - m_pos1); } 35 | 36 | v2f GetPos1() const { return m_pos1; } 37 | v2f GetPos2() const { return m_pos2; } 38 | 39 | void SetPos1(v2f pos1) { m_pos1 = pos1; } 40 | void SetPos2(v2f pos2) { m_pos2 = pos2; } 41 | 42 | protected: 43 | v2f m_pos1; 44 | v2f m_pos2; 45 | }; 46 | 47 | #endif // LINEBASE_H 48 | -------------------------------------------------------------------------------- /src/PlanarGraph.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) www.chongyangma.com 2 | // 3 | // author: Chongyang Ma - 2013-02-28 4 | // email: chongyangm@gmail.com 5 | // info: class declaration of a planar graph 6 | // -------------------------------------------------------------- 7 | 8 | #ifndef PLANARGRAPH_H 9 | #define PLANARGRAPH_H 10 | 11 | #include "tinyxml2.h" 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | using namespace boost; 28 | 29 | #include "GraphChain.h" 30 | #include "GraphEdge.h" 31 | #include "GraphFace.h" 32 | #include "GraphNode.h" 33 | #include "vec.h" 34 | 35 | class CPlanarGraph 36 | { 37 | public: 38 | typedef adjacency_list, 42 | property> 43 | Graph; 44 | 45 | typedef graph_traits::vertex_descriptor VertexDescriptor; 46 | typedef graph_traits::vertex_iterator VertexIterator; 47 | typedef graph_traits::edge_descriptor EdgeDescriptor; 48 | typedef graph_traits::out_edge_iterator OutEdgeIterator; 49 | 50 | CPlanarGraph(); 51 | 52 | void ClearGraph(); 53 | 54 | void PrintGraph(); 55 | 56 | bool LoadGraphFromXML(const char* fileName, bool flagDetectFaces = true, bool flagIgnoreIndiv = true); 57 | 58 | bool SaveGraphAsXML(const char* fileName); 59 | 60 | void AddGraphNode(CGraphNode& node) { m_nodes.push_back(node); } 61 | //void AddGraphEdge(CGraphEdge& edge) { m_edges.push_back(edge); } 62 | bool AddGraphEdge(const CGraphEdge& edge); 63 | 64 | bool CheckDuplicatedEdge(const CGraphEdge& edge); 65 | 66 | void AddGraphNodes(int numOfNodes, int parent = -1); 67 | 68 | void SetNodeNeighbors(); 69 | 70 | bool FindLineIntersect(v2f p1, v2f p2, v2f p3, v2f p4) 71 | { 72 | return FindLineIntersect(p1[0], p1[1], p2[0], p2[1], p3[0], p3[1], p4[0], p4[1]); 73 | } 74 | 75 | bool FindLineIntersect(float x1, float y1, float x2, float y2, float x3, float y3, float x4, float y4) 76 | { 77 | float s1 = (y1 - y2) * (x3 - x4) - (x1 - x2) * (y3 - y4); 78 | float s0 = (x1 - x2) * (y4 - y2) - (y1 - y2) * (x4 - x2); 79 | float t1 = (y3 - y4) * (x1 - x2) - (x3 - x4) * (y1 - y2); 80 | float t0 = (x3 - x4) * (y2 - y4) - (y3 - y4) * (x2 - x4); 81 | if (std::abs(s1) > 0.f && std::abs(t1) > 0.f) 82 | { 83 | float s = s0 / s1; 84 | float t = t0 / t1; 85 | if (s > 0.f && s < 1.f && t > 0.f && t < 1.f) 86 | { 87 | return true; 88 | } 89 | } 90 | 91 | return false; 92 | } 93 | 94 | void PickClosestNode(float px, float py); 95 | 96 | void MovePickedNode(float dx, float dy); 97 | 98 | void MovePickedNode(v2f dp) { MovePickedNode(dp[0], dp[1]); } 99 | 100 | void UnpickNode() { m_pickedNodeIndex = -1; } 101 | 102 | int GetPickedNodeIndex() { return m_pickedNodeIndex; } 103 | 104 | int GetNumOfNodes() { return int(m_nodes.size()); } 105 | 106 | int GetNumOfEdges() { return int(m_edges.size()); } 107 | 108 | int GetNumOfFaces() { return int(m_faces.size()); } 109 | 110 | v2f GetNodePos(int idx) { return m_nodes[idx].GetPos(); } 111 | 112 | void RandomInitGraph(); 113 | 114 | void RandomInitPositions(); 115 | 116 | void RandomInitTypes(); 117 | 118 | void DetectFaces(); 119 | 120 | void SortAdjacentVertices(const Graph& g, VertexDescriptor vert, std::vector& adjacentEdges); 121 | 122 | bool CompareEdgeDirections(const v2f& edgePr1, const v2f& edgePr2, const v2f& edgeRef); 123 | 124 | void RemoveTheOutsideFace(); 125 | 126 | CGraphNode& GetNode(int idx) { return m_nodes[idx]; } 127 | CGraphEdge& GetEdge(int idx) { return m_edges[idx]; } 128 | CGraphFace& GetFace(int idx) { return m_faces[idx]; } 129 | CGraphChain& GetChain(int idx) { return m_chains[idx]; } 130 | 131 | bool VisitedAllNodes(); 132 | 133 | bool VisitedNoNode(); 134 | 135 | bool HasFixedNode(); 136 | 137 | std::vector GetFixedNodes(); 138 | 139 | std::vector GetUnfixedNodes(); 140 | 141 | // Step 3: Extract the 'deepest' face or chain not yet inserted (the most included one) 142 | std::vector ExtractDeepestFaceOrChain(bool& flagCyclic, bool flagSmallFaceFirst); 143 | 144 | std::vector ExtractDeepestFaceOrChainOld(bool& flagCyclic, bool flagSmallFaceFirst); 145 | 146 | // Extract the 'deepest' face not yet inserted 147 | std::vector ExtractDeepestFace(bool flagSmallFaceFirst); 148 | 149 | // Extract the 'deepest' chain not yet inserted 150 | std::vector ExtractDeepestChainNew(); 151 | 152 | std::vector ExtractDeepestChain(); 153 | 154 | int CountConstraints(std::vector& indices); 155 | 156 | void SetNumOfTypes(int numOfTypes) { m_numOfTypes = numOfTypes; } 157 | 158 | void GetGraphBoundingBox(v2f& posMin, v2f& posMax); 159 | 160 | void MoveGraphToSceneCenter(); 161 | 162 | void ScaleGraphNodePositions(float scaling); 163 | 164 | bool LoadChainsFromTXT(const char* fileName); 165 | 166 | int FindNodeAccordingToName(const char* str); 167 | 168 | void RemoveIndividualNodes(); 169 | 170 | private: 171 | inline int Random2(int max) 172 | { 173 | if (max < 1 || max >= RAND_MAX) 174 | return 0; 175 | else 176 | return (int)rand() / (RAND_MAX / max + 1); 177 | } 178 | 179 | inline bool OneChanceIn(int a_million) 180 | { 181 | return (Random2(a_million) == 0); 182 | } 183 | 184 | inline bool CoinFlip() 185 | { 186 | return OneChanceIn(2); 187 | } 188 | 189 | std::vector m_nodes; 190 | std::vector m_edges; 191 | int m_pickedNodeIndex; 192 | 193 | static CGraphFace m_faceTmp; 194 | static std::vector m_faces; 195 | 196 | std::vector m_chains; 197 | 198 | int m_numOfTypes; // number of node types 199 | 200 | // Some planar face traversal visitors that will 201 | // print the vertices and edges on the faces 202 | struct output_visitor : public planar_face_traversal_visitor 203 | { 204 | void begin_face() 205 | { 206 | m_faceTmp.ClearIndices(); 207 | std::cout << "New face: "; 208 | } 209 | 210 | void end_face() 211 | { 212 | std::cout << std::endl; 213 | if (m_faceTmp.IsEmpty() == false) 214 | { 215 | m_faces.push_back(m_faceTmp); 216 | } 217 | } 218 | }; 219 | 220 | struct vertex_output_visitor : public output_visitor 221 | { 222 | template 223 | void next_vertex(Vertex v) 224 | { 225 | std::cout << v << " "; 226 | m_faceTmp.AddIndex(int(v)); 227 | } 228 | }; 229 | 230 | struct edge_output_visitor : public output_visitor 231 | { 232 | template 233 | void next_edge(Edge e) 234 | { 235 | std::cout << e << " "; 236 | } 237 | }; 238 | }; 239 | 240 | #endif // PLANARGRAPH_H 241 | -------------------------------------------------------------------------------- /src/Room.cpp: -------------------------------------------------------------------------------- 1 | #include "Room.h" 2 | 3 | #include "LevelConfig.h" 4 | 5 | CRoom::CRoom() 6 | { 7 | m_templateType = -1; 8 | m_flagFixed = false; 9 | m_boundaryType = 0; 10 | ResetEnergy(); 11 | } 12 | 13 | CRoomEdge CRoom::GetEdge(int idx) const 14 | { 15 | int idx1 = idx; 16 | int idx2 = (idx + 1) % GetNumOfVertices(); 17 | CRoomEdge edge; 18 | edge.SetPos1(GetVertex(idx1)); 19 | edge.SetPos2(GetVertex(idx2)); 20 | edge.SetIdx1(idx1); 21 | edge.SetIdx2(idx2); 22 | edge.SetDoorFlag(GetDoorFlag(idx)); 23 | return edge; 24 | } 25 | 26 | v2f CRoom::GetRoomCenter() const 27 | { 28 | v2f center(0.f); 29 | if (GetNumOfVertices() == 0) 30 | { 31 | return center; 32 | } 33 | v2f posMin(1e10); 34 | v2f posMax(-1e10); 35 | for (int i = 0; i < GetNumOfVertices(); i++) 36 | { 37 | v2f pi = m_vertices[i]; 38 | for (int j = 0; j < 2; j++) 39 | { 40 | posMin[j] = min(posMin[j], pi[j]); 41 | posMax[j] = max(posMax[j], pi[j]); 42 | } 43 | } 44 | center = (posMin + posMax) * 0.5f; 45 | return center; 46 | } 47 | 48 | v2f CRoom::GetShiftedRoomCenter() 49 | { 50 | v2f center = GetRoomCenter() + m_centerShift; 51 | return center; 52 | } 53 | 54 | void CRoom::TranslateRoom(v2f trans) 55 | { 56 | for (int i = 0; i < GetNumOfVertices(); i++) 57 | { 58 | m_vertices[i] = m_vertices[i] + trans; 59 | } 60 | } 61 | 62 | void CRoom::RotateRoom(float rad) 63 | { 64 | float cv = cos(rad); 65 | float sv = sin(rad); 66 | for (int i = 0; i < GetNumOfVertices(); i++) 67 | { 68 | float p0 = m_vertices[i][0]; 69 | float p1 = m_vertices[i][1]; 70 | m_vertices[i][0] = p0 * cv + p1 * sv; 71 | m_vertices[i][1] = -p0 * sv + p1 * cv; 72 | } 73 | float p0 = m_centerShift[0]; 74 | float p1 = m_centerShift[1]; 75 | m_centerShift[0] = p0 * cv + p1 * sv; 76 | m_centerShift[1] = -p0 * sv + p1 * cv; 77 | } 78 | 79 | void CRoom::ScaleRoom(float scaling) 80 | { 81 | v2f center = GetRoomCenter(); 82 | for (int i = 0; i < GetNumOfVertices(); i++) 83 | { 84 | v2f pi = m_vertices[i] - center; 85 | m_vertices[i] = center + pi * scaling; 86 | } 87 | m_centerShift = m_centerShift * scaling; 88 | } 89 | 90 | void CRoom::ScaleRoom(v2f scaling) 91 | { 92 | v2f center = GetRoomCenter(); 93 | for (int i = 0; i < GetNumOfVertices(); i++) 94 | { 95 | v2f pi = m_vertices[i] - center; 96 | pi[0] *= scaling[0]; 97 | pi[1] *= scaling[1]; 98 | m_vertices[i] = center + pi; 99 | } 100 | m_centerShift[0] *= scaling[0]; 101 | m_centerShift[1] *= scaling[1]; 102 | } 103 | 104 | void CRoom::GetRoomBoundingBox(v2f& posMin, v2f& posMax) 105 | { 106 | v2f pMin(1e10); 107 | v2f pMax(-1e10); 108 | for (int i = 0; i < GetNumOfVertices(); i++) 109 | { 110 | v2f pi = m_vertices[i]; 111 | for (int j = 0; j < 2; j++) 112 | { 113 | pMin[j] = min(pMin[j], pi[j]); 114 | pMax[j] = max(pMax[j], pi[j]); 115 | } 116 | } 117 | posMin = pMin; 118 | posMax = pMax; 119 | } 120 | 121 | void CRoom::GetRoomBoundingBox(AABB2f& boundingBox) 122 | { 123 | v2f posMin, posMax; 124 | GetRoomBoundingBox(posMin, posMax); 125 | boundingBox.m_posMin = posMin; 126 | boundingBox.m_posMax = posMax; 127 | } 128 | 129 | void CRoom::PrintRoom() 130 | { 131 | std::cout << "A room with " << GetNumOfVertices() << " vertices...\n"; 132 | for (int i = 0; i < GetNumOfVertices(); i++) 133 | { 134 | std::cout << i << "th vertex: " << GetVertex(i) << std::endl; 135 | } 136 | } 137 | 138 | void CRoom::InitWalls() 139 | { 140 | m_walls.clear(); 141 | for (int i = 0; i < GetNumOfVertices(); i++) 142 | { 143 | int idx1 = i; 144 | int idx2 = (i + 1) % GetNumOfVertices(); 145 | v2f pos1 = GetVertex(idx1); 146 | v2f pos2 = GetVertex(idx2); 147 | RoomWall wall(pos1, pos2); 148 | m_walls.push_back(wall); 149 | } 150 | } 151 | 152 | bool CRoom::EraseWall(int idx) 153 | { 154 | if (idx >= GetNumOfWalls()) 155 | { 156 | return false; 157 | } 158 | m_walls.erase(m_walls.begin() + idx); 159 | return true; 160 | } 161 | 162 | void CRoom::ResetDoorFlags() 163 | { 164 | if (m_doorFlags.empty() == false) 165 | { 166 | return; 167 | } 168 | m_doorFlags.resize(GetNumOfEdges(), false); 169 | } 170 | 171 | void CRoom::SetDoorFlag(int edgeIdx, bool doorFlag) 172 | { 173 | if (edgeIdx < 0 || edgeIdx >= int(m_doorFlags.size())) 174 | { 175 | return; 176 | } 177 | m_doorFlags[edgeIdx] = doorFlag; 178 | } 179 | 180 | bool CRoom::GetDoorFlag(int edgeIdx) const 181 | { 182 | if (edgeIdx < 0 || edgeIdx >= int(m_doorFlags.size())) 183 | { 184 | return true; 185 | } 186 | return m_doorFlags[edgeIdx]; 187 | } 188 | 189 | std::vector CRoom::GetDoorFlags() const 190 | { 191 | return m_doorFlags; 192 | } 193 | 194 | bool CRoom::HasRestrictedDoorPosition() const 195 | { 196 | for (int i = 0; i < int(m_doorFlags.size()); i++) 197 | { 198 | if (m_doorFlags[i] == false) 199 | { 200 | return true; 201 | } 202 | } 203 | return false; 204 | } 205 | -------------------------------------------------------------------------------- /src/Room.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) www.chongyangma.com 2 | // 3 | // author: Chongyang Ma - 2013-03-07 4 | // email: chongyangm@gmail.com 5 | // info: class declaration of a single room 6 | // -------------------------------------------------------------- 7 | 8 | #ifndef ROOM_H 9 | #define ROOM_H 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | #include "tinyxml2.h" 18 | 19 | #include "vec.h" 20 | #include "RoomEdge.h" 21 | 22 | typedef struct AABB2f 23 | { 24 | v2f m_posMin; 25 | v2f m_posMax; 26 | } AABB2f; 27 | 28 | typedef CLineBase RoomWall; 29 | typedef CLineBase RoomDoor; 30 | 31 | class CRoom 32 | { 33 | public: 34 | CRoom(); 35 | 36 | std::vector& GetVertices() { return m_vertices; } 37 | 38 | void SetVertices(std::vector& vertices) { m_vertices = vertices; } 39 | 40 | void SetVertex(v2f& pos, int idx) { m_vertices[idx] = pos; } 41 | 42 | void SetCenterShift(v2f& shift) { m_centerShift = shift; } 43 | 44 | v2f GetCenterShift() const { return m_centerShift; } 45 | 46 | v2f GetVertex(int idx) const { return m_vertices[idx]; } 47 | 48 | CRoomEdge GetEdge(int idx) const; 49 | 50 | int GetNumOfVertices() const { return int(m_vertices.size()); } 51 | 52 | int GetNumOfEdges() const { return int(m_vertices.size()); } 53 | 54 | v2f GetRoomCenter() const; 55 | 56 | v2f GetShiftedRoomCenter(); 57 | 58 | void TranslateRoom(v2f trans); 59 | 60 | void RotateRoom(float rad); 61 | 62 | void ScaleRoom(float scaling); 63 | 64 | void ScaleRoom(v2f scaling); 65 | 66 | void GetRoomBoundingBox(v2f& posMin, v2f& posMax); 67 | 68 | void GetRoomBoundingBox(AABB2f& boundingBox); 69 | 70 | v3f GetColor() { return m_color; } 71 | void SetColor(v3f color) { m_color = color; } 72 | 73 | float GetEnergy() { return m_energy; } 74 | void SetEnergy(float energy) { m_energy = energy; } 75 | void ResetEnergy() { SetEnergy(1.f); } 76 | void UpdateEnergy(float factor) { m_energy *= factor; } 77 | 78 | void PrintRoom(); 79 | 80 | bool HasWalls() const { return (m_walls.empty() == false); } 81 | 82 | void InitWalls(); 83 | 84 | bool EraseWall(int idx); 85 | 86 | void InsertWall(RoomWall& wall) { m_walls.push_back(wall); } 87 | 88 | int GetNumOfWalls() const { return int(m_walls.size()); } 89 | 90 | RoomWall& GetWall(int idx) { return m_walls[idx]; } 91 | 92 | int GetTemplateType() const { return m_templateType; } 93 | void SetTemplateType(int type) { m_templateType = type; } 94 | 95 | int GetBoundaryType() const { return m_boundaryType; } 96 | void SetBoundaryType(int type) { m_boundaryType = type; } 97 | 98 | bool GetFlagFixed() const { return m_flagFixed; } 99 | void SetFlagFixed(bool flagFixed) { m_flagFixed = flagFixed; } 100 | 101 | void ResetDoorFlags(); 102 | void SetDoorFlag(int edgeIdx, bool doorFlag); 103 | bool GetDoorFlag(int edgeIdx) const; 104 | std::vector GetDoorFlags() const; 105 | bool HasRestrictedDoorPosition() const; 106 | 107 | private: 108 | std::vector m_vertices; 109 | v2f m_centerShift = v2f(0.f, 0.f);; 110 | std::vector m_walls; 111 | v3f m_color = v3f(0.5f, 0.5f, 0.5f); 112 | float m_energy; 113 | int m_templateType; 114 | bool m_flagFixed; 115 | int m_boundaryType; 116 | std::vector m_doorFlags; 117 | }; 118 | 119 | #endif // ROOM_H 120 | -------------------------------------------------------------------------------- /src/RoomEdge.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) www.chongyangma.com 2 | // 3 | // author: Chongyang Ma - 2013-08-22 4 | // email: chongyangm@gmail.com 5 | // info: class declaration of a room edge 6 | // -------------------------------------------------------------- 7 | 8 | #ifndef ROOMEDGE_H 9 | #define ROOMEDGE_H 10 | 11 | #include "LineBase.h" 12 | 13 | class CRoomEdge : public CLineBase 14 | { 15 | public: 16 | CRoomEdge() 17 | { 18 | m_idx1 = -1; 19 | m_idx2 = -1; 20 | m_doorFlag = true; 21 | } 22 | 23 | CRoomEdge(v2f pos1, v2f pos2) : CLineBase(pos1, pos2) 24 | { 25 | m_idx1 = -1; 26 | m_idx2 = -1; 27 | m_doorFlag = true; 28 | } 29 | 30 | CRoomEdge(v2f pos1, v2f pos2, int idx1, int idx2) : CLineBase(pos1, pos2), m_idx1(idx1), m_idx2(idx2) 31 | { 32 | m_doorFlag = true; 33 | } 34 | 35 | v2f GetDirection() { return (m_pos2 - m_pos1); } 36 | 37 | v3f GetDirection3D() { return v3f(GetDirection()[0], GetDirection()[1], 0.f); } 38 | 39 | int GetIdx1() const { return m_idx1; } 40 | int GetIdx2() const { return m_idx2; } 41 | 42 | void SetIdx1(int idx1) { m_idx1 = idx1; } 43 | void SetIdx2(int idx2) { m_idx2 = idx2; } 44 | 45 | void SetDoorFlag(bool flag) { m_doorFlag = flag; } 46 | bool GetDoorFlag() { return m_doorFlag; } 47 | 48 | private: 49 | int m_idx1; 50 | int m_idx2; 51 | 52 | bool m_doorFlag; 53 | }; 54 | 55 | #endif // ROOMEDGE_H 56 | -------------------------------------------------------------------------------- /src/RoomLayout.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) www.chongyangma.com 2 | // 3 | // author: Chongyang Ma - 2013-03-07 4 | // email: chongyangm@gmail.com 5 | // info: class declaration of a room layout, i.e. a set of rooms 6 | // -------------------------------------------------------------- 7 | 8 | #ifndef ROOMLAYOUT_H 9 | #define ROOMLAYOUT_H 10 | 11 | //#define DUMP_INTERMEDIATE_OUTPUT 12 | //#define DUMP_PARTIAL_SOLUTION 13 | #define PERFORMANCE_TEST 1 14 | 15 | #include "Room.h" 16 | 17 | #include 18 | 19 | typedef CLineBase CorridorWall; 20 | 21 | class CRoomLayout 22 | { 23 | public: 24 | void ClearLayout() { m_rooms.clear(); } 25 | 26 | void AddRoom(CRoom& room) { m_rooms.push_back(room); } 27 | 28 | int GetNumOfRooms() { return int(m_rooms.size()); } 29 | 30 | int GetNumOfVertices(); 31 | 32 | int GetNumOfEdges(); 33 | 34 | CRoom& GetRoom(int idx) { return m_rooms[idx]; } 35 | 36 | v2i GetNearestEdgePair(int roomIdx0, int roomIdx1); 37 | 38 | void GetLayoutBoundingBox(v2f& posMin, v2f& posMax); 39 | 40 | void MoveToSceneCenter(); 41 | 42 | std::vector GetRoomPositions(); 43 | 44 | void ResetRoomEnergies(); 45 | 46 | void PrintLayout(); 47 | 48 | bool SaveLayoutAsSVG(const char* fileName, int wd = 400, int ht = 400, bool writeOnlyVisited = false, class CPlanarGraph* graphBest = NULL, bool labelFlag = true); 49 | 50 | static int ConvertPos(float p, float pMin, float pMax, int sz); 51 | 52 | static int ConvertPosX(float p, float pMin, float pMax, int sz); 53 | 54 | static int ConvertPosY(float p, float pMin, float pMax, int sz); 55 | 56 | void InsertCorridorWall(CorridorWall& wall) { m_corridorWalls.push_back(wall); } 57 | 58 | int GetNumOfCorridorWalls() const { return int(m_corridorWalls.size()); } 59 | 60 | RoomWall& GetCorridorWall(int idx) { return m_corridorWalls[idx]; } 61 | 62 | std::map, float> cachedCollisionEnergies; 63 | std::map, float> cachedConnectivities; 64 | std::map, float> cachedContacts; 65 | 66 | private: 67 | std::vector m_rooms; 68 | std::vector m_corridorWalls; 69 | }; 70 | 71 | #endif // ROOMLAYOUT_H 72 | -------------------------------------------------------------------------------- /src/RoomTemplates.cpp: -------------------------------------------------------------------------------- 1 | #include "RoomTemplates.h" 2 | 3 | #include 4 | 5 | void CRoomTemplates::PrintTemplates() 6 | { 7 | std::cout << "There are " << m_rooms.size() << " room templates!\n"; 8 | for (int i = 0; i < int(m_rooms.size()); i++) 9 | { 10 | std::vector vertices = m_rooms[i].GetVertices(); 11 | std::cout << "Room " << i << " with " << vertices.size() << " vertices:\n"; 12 | for (int j = 0; j < int(vertices.size()); j++) 13 | { 14 | std::cout << vertices[j] << " "; 15 | } 16 | std::cout << std::endl; 17 | } 18 | } 19 | 20 | bool CRoomTemplates::LoadTemplatesFromXML(const char* fileName) 21 | { 22 | // Clear the current templates... 23 | ClearTemplates(); 24 | 25 | tinyxml2::XMLDocument doc; 26 | if (doc.LoadFile(fileName) != tinyxml2::XML_SUCCESS) 27 | { 28 | std::cout << "Failed to load templates from " << fileName << "!\n"; 29 | return false; 30 | } 31 | //doc.Print(); 32 | 33 | tinyxml2::XMLElement* xmlRoot = doc.RootElement(); 34 | assert(xmlRoot); 35 | 36 | tinyxml2::XMLNode* xmlNode = xmlRoot->FirstChild(); 37 | while (xmlNode != 0) 38 | { 39 | if (strcmp(xmlNode->Value(), "Room") == 0) 40 | { 41 | std::vector doorPositions; 42 | // Parse a room... 43 | CRoom room; 44 | std::vector vertices; 45 | tinyxml2::XMLNode* xmlChildNode = xmlNode->FirstChild(); 46 | while (xmlChildNode != 0) 47 | { 48 | if (strcmp(xmlChildNode->Value(), "Vertex") == 0) 49 | { 50 | // Parse a vertex... 51 | float px, py; 52 | int rx = xmlChildNode->ToElement()->QueryFloatAttribute("px", &px); 53 | int ry = xmlChildNode->ToElement()->QueryFloatAttribute("py", &py); 54 | if (rx == tinyxml2::XML_SUCCESS && ry == tinyxml2::XML_SUCCESS) 55 | { 56 | v2f pos; 57 | pos[0] = px; 58 | pos[1] = py; 59 | vertices.push_back(pos); 60 | } 61 | } 62 | else if (strcmp(xmlChildNode->Value(), "Shift") == 0) 63 | { 64 | float px, py; 65 | int rx = xmlChildNode->ToElement()->QueryFloatAttribute("px", &px); 66 | int ry = xmlChildNode->ToElement()->QueryFloatAttribute("py", &py); 67 | if (rx == tinyxml2::XML_SUCCESS && ry == tinyxml2::XML_SUCCESS) 68 | { 69 | v2f pos; 70 | pos[0] = px; 71 | pos[1] = py; 72 | room.SetCenterShift(pos); 73 | } 74 | } 75 | else if (strcmp(xmlChildNode->Value(), "Boundary") == 0) 76 | { 77 | int type; 78 | int r = xmlChildNode->ToElement()->QueryIntAttribute("type", &type); 79 | if (r == tinyxml2::XML_SUCCESS) 80 | { 81 | room.SetBoundaryType(type); 82 | } 83 | } 84 | else if (strcmp(xmlChildNode->Value(), "Door") == 0) 85 | { 86 | int idx; 87 | int r = xmlChildNode->ToElement()->QueryIntAttribute("edgeIndex", &idx); 88 | if (r == tinyxml2::XML_SUCCESS) 89 | { 90 | doorPositions.push_back(idx); 91 | } 92 | } 93 | xmlChildNode = xmlChildNode->NextSibling(); 94 | } 95 | room.SetVertices(vertices); 96 | if (doorPositions.empty() == false) 97 | { 98 | room.ResetDoorFlags(); 99 | for (int i = 0; i < int(doorPositions.size()); i++) 100 | { 101 | room.SetDoorFlag(doorPositions[i], true); 102 | } 103 | } 104 | AddTemplate(room); 105 | } 106 | 107 | // Move to the next sibling... 108 | xmlNode = xmlNode->NextSibling(); 109 | } 110 | 111 | SetRoomTypes(); 112 | //PrintTemplates(); 113 | return true; 114 | } 115 | 116 | bool CRoomTemplates::SaveTemplatesAsXML(const char* fileName) 117 | { 118 | const char* str = "\t\n" 119 | "\n" 120 | "\n" 121 | "\n"; 122 | tinyxml2::XMLDocument doc; 123 | doc.Parse(str); 124 | tinyxml2::XMLElement* root = doc.RootElement(); 125 | // Dump nodes... 126 | for (int i = 0; i < GetNumOfTemplates(); i++) 127 | { 128 | tinyxml2::XMLElement* roomElement = doc.NewElement("Room"); 129 | for (int j = 0; j < GetRoom(i).GetNumOfVertices(); j++) 130 | { 131 | tinyxml2::XMLElement* vertexElement = doc.NewElement("Vertex"); 132 | v2f pj = GetRoom(i).GetVertex(j); 133 | std::ostringstream oss0; 134 | std::ostringstream oss1; 135 | oss0 << pj[0]; 136 | oss1 << pj[1]; 137 | vertexElement->SetAttribute("px", oss0.str().c_str()); 138 | vertexElement->SetAttribute("py", oss1.str().c_str()); 139 | roomElement->InsertEndChild(vertexElement); 140 | } 141 | // Dump center shift... 142 | tinyxml2::XMLElement* shiftElement = doc.NewElement("Shift"); 143 | v2f shift = GetRoom(i).GetCenterShift(); 144 | std::ostringstream oss0; 145 | std::ostringstream oss1; 146 | oss0 << shift[0]; 147 | oss1 << shift[1]; 148 | shiftElement->SetAttribute("px", oss0.str().c_str()); 149 | shiftElement->SetAttribute("py", oss1.str().c_str()); 150 | roomElement->InsertEndChild(shiftElement); 151 | // Dump boundary type... 152 | if (GetRoom(i).GetBoundaryType() != 0) 153 | { 154 | tinyxml2::XMLElement* boundaryElement = doc.NewElement("Boundary"); 155 | boundaryElement->SetAttribute("type", GetRoom(i).GetBoundaryType()); 156 | roomElement->InsertEndChild(boundaryElement); 157 | } 158 | // Dump door positions... 159 | if (GetRoom(i).HasRestrictedDoorPosition() == true) 160 | { 161 | std::vector doorFlags = GetRoom(i).GetDoorFlags(); 162 | for (int j = 0; j < int(doorFlags.size()); j++) 163 | { 164 | if (doorFlags[j] == false) 165 | { 166 | continue; 167 | } 168 | tinyxml2::XMLElement* doorElement = doc.NewElement("Door"); 169 | doorElement->SetAttribute("edgeIndex", j); 170 | roomElement->InsertEndChild(doorElement); 171 | } 172 | } 173 | // Add room... 174 | root->InsertEndChild(roomElement); 175 | } 176 | 177 | bool saveFlag = doc.SaveFile(fileName); 178 | return saveFlag; 179 | } 180 | 181 | void CRoomTemplates::EnrichByRotating180Degrees() 182 | { 183 | int numOfTemplatesOld = GetNumOfTemplates(); 184 | for (int i = 0; i < numOfTemplatesOld; i++) 185 | { 186 | CRoom roomNew = GetRoom(i); 187 | roomNew.RotateRoom(atan(1.f) * 4.f); 188 | AddTemplate(roomNew); 189 | } 190 | SetRoomTypes(); 191 | } 192 | 193 | void CRoomTemplates::EnrichByIntroducingSizeVariation() 194 | { 195 | int numOfTemplatesOld = GetNumOfTemplates(); 196 | for (int n = 0; n < 3; n++) 197 | { 198 | for (int i = 0; i < numOfTemplatesOld; i++) 199 | { 200 | CRoom roomNew = GetRoom(i); 201 | float rx = 1.f + rand() / float(RAND_MAX); 202 | float ry = 1.f + rand() / float(RAND_MAX); 203 | roomNew.ScaleRoom(v2f(rx, ry)); 204 | AddTemplate(roomNew); 205 | } 206 | } 207 | SetRoomTypes(); 208 | } 209 | 210 | void CRoomTemplates::SetRoomTypes() 211 | { 212 | for (int i = 0; i < GetNumOfTemplates(); i++) 213 | { 214 | m_rooms[i].SetTemplateType(i); 215 | } 216 | } 217 | -------------------------------------------------------------------------------- /src/RoomTemplates.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) www.chongyangma.com 2 | // 3 | // author: Chongyang Ma - 2013-03-04 4 | // email: chongyangm@gmail.com 5 | // info: class declaration of room templates 6 | // -------------------------------------------------------------- 7 | 8 | #ifndef ROOMTEMPLATES_H 9 | #define ROOMTEMPLATES_H 10 | 11 | #include "Room.h" 12 | 13 | class CRoomTemplates 14 | { 15 | public: 16 | void ClearTemplates() { m_rooms.clear(); } 17 | 18 | void PrintTemplates(); 19 | 20 | void AddTemplate(CRoom& room) { m_rooms.push_back(room); } 21 | 22 | bool LoadTemplatesFromXML(const char* fileName); 23 | 24 | bool SaveTemplatesAsXML(const char* fileName); 25 | 26 | int GetNumOfTemplates() { return int(m_rooms.size()); } 27 | 28 | CRoom& GetRoom(int idx) { return m_rooms[idx]; } 29 | 30 | const std::vector& GetRooms() const { return m_rooms; } 31 | 32 | void EnrichByRotating180Degrees(); 33 | 34 | void EnrichByIntroducingSizeVariation(); 35 | 36 | void SetRoomTypes(); 37 | 38 | private: 39 | std::vector m_rooms; 40 | }; 41 | 42 | #endif // ROOMTEMPLATES_H 43 | -------------------------------------------------------------------------------- /src/clipperWrapper.cpp: -------------------------------------------------------------------------------- 1 | #include "clipperWrapper.h" 2 | 3 | float CClipperWrapper::m_scalingFactor = 1e10; 4 | 5 | Paths CClipperWrapper::FindIntersection(const CRoom& room1, const CRoom& room2) 6 | { 7 | Path p1, p2; 8 | p1.resize(room1.GetNumOfVertices()); 9 | p2.resize(room2.GetNumOfVertices()); 10 | 11 | for (int i = 0; i < room1.GetNumOfVertices(); i++) 12 | { 13 | v2f pi = room1.GetVertex(i); 14 | p1[i].X = ConvertFloatToLong64(pi[0]); 15 | p1[i].Y = ConvertFloatToLong64(pi[1]); 16 | } 17 | for (int i = 0; i < room2.GetNumOfVertices(); i++) 18 | { 19 | v2f pi = room2.GetVertex(i); 20 | p2[i].X = ConvertFloatToLong64(pi[0]); 21 | p2[i].Y = ConvertFloatToLong64(pi[1]); 22 | } 23 | 24 | ClipType ct = ctIntersection; 25 | PolyFillType pft = pftNonZero; 26 | Paths sub, clp, sol; 27 | 28 | Clipper c; 29 | c.AddPath(p1, ptSubject, true); 30 | c.AddPath(p2, ptClip, true); 31 | c.Execute(ct, sol, pft, pft); 32 | 33 | return sol; 34 | } 35 | 36 | float CClipperWrapper::ComputeCollideArea(const CRoom& room1, const CRoom& room2) 37 | { 38 | Paths sol = FindIntersection(room1, room2); 39 | float collideArea = 0.f; 40 | for (int i = 0; i < int(sol.size()); i++) 41 | { 42 | double a = Area(sol[i]); 43 | collideArea += std::abs(ConvertDoubleAreaToFloat(a)); 44 | } 45 | if (collideArea < 10e-4) 46 | { 47 | collideArea = 0; 48 | } 49 | return collideArea; 50 | } 51 | 52 | float CClipperWrapper::ComputeRoomArea(const CRoom& room) 53 | { 54 | return ComputeCollideArea(room, room); 55 | } 56 | 57 | long64 CClipperWrapper::ConvertFloatToLong64(float f) 58 | { 59 | long64 i = long64(f * m_scalingFactor + 0.5f); 60 | return i; 61 | } 62 | 63 | float CClipperWrapper::ConvertLong64ToFloat(long64 i) 64 | { 65 | float f = float(i) / m_scalingFactor; 66 | return f; 67 | } 68 | 69 | float CClipperWrapper::ConvertDoubleAreaToFloat(double a) 70 | { 71 | a = a / double(m_scalingFactor * m_scalingFactor); 72 | float f = float(a); 73 | return f; 74 | } 75 | -------------------------------------------------------------------------------- /src/clipperWrapper.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) www.chongyangma.com 2 | // 3 | // author: Chongyang Ma - 2013-06-24 4 | // email: chongyangm@gmail.com 5 | // info: wrapper of the Clipper library 6 | // -------------------------------------------------------------- 7 | 8 | #ifndef CLIPPERWRAPPER_H 9 | #define CLIPPERWRAPPER_H 10 | 11 | #include "clipper.hpp" 12 | using namespace ClipperLib; 13 | 14 | #include "LevelMath.h" 15 | #include "RoomLayout.h" 16 | using namespace level_math; 17 | 18 | class CClipperWrapper 19 | { 20 | public: 21 | Paths FindIntersection(const CRoom& room1, const CRoom& room2); 22 | 23 | float ComputeCollideArea(const CRoom& room1, const CRoom& room2); 24 | 25 | float ComputeRoomArea(const CRoom& room); 26 | 27 | static float m_scalingFactor; 28 | 29 | private: 30 | long64 ConvertFloatToLong64(float f); 31 | 32 | float ConvertLong64ToFloat(long64 i); 33 | 34 | float ConvertDoubleAreaToFloat(double a); 35 | }; 36 | 37 | #endif //CLIPPERWRAPPER_H 38 | -------------------------------------------------------------------------------- /src/levels.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) www.chongyangma.com 2 | // 3 | // author: Chongyang Ma - 2013-02-28 4 | // email: chongyangm@gmail.com 5 | // info: main function of command line tool for level synthesis 6 | // -------------------------------------------------------------- 7 | 8 | #include "LevelSynth.h" 9 | #include "LevelTimer.h" 10 | #include "PlanarGraph.h" 11 | #include "RoomTemplates.h" 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | void usage(char* argv[]) 20 | { 21 | std::cout << "Usage: " << argv[0] << " graph.xml templates.xml config.txt [target_solution_number]\n"; 22 | } 23 | 24 | int main(int argc, char** argv) 25 | { 26 | if (argc < 4) 27 | { 28 | usage(argv); 29 | return -1; 30 | } 31 | 32 | CPlanarGraph planar_graph; 33 | CRoomTemplates room_templates; 34 | CLevelConfig level_config; 35 | CLevelSynth level_synthesizer; 36 | std::string input_graph_name = argv[1]; 37 | std::string input_template_name = argv[2]; 38 | level_config.LoadFromSynConfig(argv[3]); 39 | if (argc > 4) 40 | { 41 | CLevelConfig::m_targetNumOfSolutions = atoi(argv[4]); 42 | } 43 | 44 | planar_graph.LoadGraphFromXML(input_graph_name.c_str()); 45 | planar_graph.SaveGraphAsXML(CLevelConfig::AddOutputPrefix(input_graph_name).c_str()); 46 | room_templates.LoadTemplatesFromXML(input_template_name.c_str()); 47 | room_templates.SaveTemplatesAsXML(CLevelConfig::AddOutputPrefix(input_template_name).c_str()); 48 | 49 | if (CLevelConfig::m_flagRandomness) 50 | { 51 | srand((unsigned int)time(0)); 52 | } 53 | if (CLevelConfig::m_flagEnrichTemplates == true) 54 | { 55 | room_templates.EnrichByRotating180Degrees(); 56 | } 57 | CConfigSpace::PrecomputeTable(room_templates.GetRooms()); 58 | 59 | CLevelTimer timer; 60 | double oldTime = timer.GetTime(); 61 | level_synthesizer.SetGraphAndTemplates(&planar_graph, &room_templates); 62 | double elapseTime = timer.GetElapsedTime(oldTime); 63 | 64 | std::ofstream fout; 65 | fout.open("log.txt", std::ios_base::app); 66 | CLevelConfig::DumpTimeAndDate(fout); 67 | fout << "Have found " << level_synthesizer.GetSolutionCount() << " solution(s) within " << elapseTime << " seconds.\n"; 68 | std::cout << "Have found " << level_synthesizer.GetSolutionCount() << " solution(s) within " << elapseTime << " seconds.\n"; 69 | 70 | return (0); 71 | } 72 | -------------------------------------------------------------------------------- /src/util.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) www.chongyangma.com 2 | // 3 | // author: Chongyang Ma - 2013-03-22 4 | // email: chongyangm@gmail.com 5 | // info: math utilities for the template class of a vector 6 | // -------------------------------------------------------------- 7 | 8 | #ifndef UTIL_H 9 | #define UTIL_H 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #ifdef WIN32 17 | #undef min 18 | #undef max 19 | #endif 20 | 21 | using std::max; 22 | using std::min; 23 | using std::swap; 24 | 25 | template 26 | inline T sqr(const T& x) 27 | { 28 | return x * x; 29 | } 30 | 31 | template 32 | inline T min(T a1, T a2, T a3) 33 | { 34 | return min(a1, min(a2, a3)); 35 | } 36 | 37 | template 38 | inline T min(T a1, T a2, T a3, T a4) 39 | { 40 | return min(min(a1, a2), min(a3, a4)); 41 | } 42 | 43 | template 44 | inline T min(T a1, T a2, T a3, T a4, T a5) 45 | { 46 | return min(min(a1, a2), min(a3, a4), a5); 47 | } 48 | 49 | template 50 | inline T min(T a1, T a2, T a3, T a4, T a5, T a6) 51 | { 52 | return min(min(a1, a2), min(a3, a4), min(a5, a6)); 53 | } 54 | 55 | template 56 | inline T max(T a1, T a2, T a3) 57 | { 58 | return max(a1, max(a2, a3)); 59 | } 60 | 61 | template 62 | inline T max(T a1, T a2, T a3, T a4) 63 | { 64 | return max(max(a1, a2), max(a3, a4)); 65 | } 66 | 67 | template 68 | inline T max(T a1, T a2, T a3, T a4, T a5) 69 | { 70 | return max(max(a1, a2), max(a3, a4), a5); 71 | } 72 | 73 | template 74 | inline T max(T a1, T a2, T a3, T a4, T a5, T a6) 75 | { 76 | return max(max(a1, a2), max(a3, a4), max(a5, a6)); 77 | } 78 | 79 | template 80 | inline T clamp(T a, T lower, T upper) 81 | { 82 | if (a < lower) 83 | return lower; 84 | else if (a > upper) 85 | return upper; 86 | else 87 | return a; 88 | } 89 | 90 | #ifdef WIN32 91 | // there may be some fancy bit-trickery that's faster... 92 | inline long lround(double x) 93 | { 94 | if (x > 0) 95 | return (x - floor(x) < 0.5) ? (long)floor(x) : (long)ceil(x); 96 | else 97 | return (x - floor(x) <= 0.5) ? (long)floor(x) : (long)ceil(x); 98 | } 99 | #endif //WIN32 100 | 101 | inline unsigned int round_up_to_power_of_two(unsigned int n) 102 | { 103 | int exponent = 0; 104 | --n; 105 | while (n) 106 | { 107 | ++exponent; 108 | n >>= 1; 109 | } 110 | return 1 << exponent; 111 | } 112 | 113 | inline unsigned int round_down_to_power_of_two(unsigned int n) 114 | { 115 | int exponent = 0; 116 | while (n > 1) 117 | { 118 | ++exponent; 119 | n >>= 1; 120 | } 121 | return 1 << exponent; 122 | } 123 | 124 | inline int intlog2(int x) 125 | { 126 | int exp = -1; 127 | while (x) 128 | { 129 | x >>= 1; 130 | ++exp; 131 | } 132 | return exp; 133 | } 134 | 135 | template 136 | void set_zero(std::vector& v) 137 | { 138 | for (int i = (int)v.size() - 1; i >= 0; --i) 139 | v[i] = 0; 140 | } 141 | 142 | template 143 | T abs_max(const std::vector& v) 144 | { 145 | T m = 0; 146 | for (int i = (int)v.size() - 1; i >= 0; --i) 147 | { 148 | if (std::fabs(v[i]) > m) 149 | m = std::fabs(v[i]); 150 | } 151 | return m; 152 | } 153 | 154 | template 155 | bool contains(const std::vector& a, T e) 156 | { 157 | for (unsigned int i = 0; i < a.size(); ++i) 158 | if (a[i] == e) return true; 159 | return false; 160 | } 161 | 162 | #endif // UTIL_H 163 | -------------------------------------------------------------------------------- /src/vec.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) www.chongyangma.com 2 | // 3 | // author: Chongyang Ma - 2013-03-22 4 | // email: chongyangm@gmail.com 5 | // info: template class declaration of a vector 6 | // -------------------------------------------------------------- 7 | 8 | #ifndef VEC_H 9 | #define VEC_H 10 | 11 | #include "util.h" 12 | 13 | #include 14 | #include 15 | #include 16 | 17 | template 18 | struct Vec 19 | { 20 | T v[N]; 21 | 22 | Vec(void) 23 | {} 24 | 25 | Vec(T value_for_all) 26 | { 27 | for (unsigned int i = 0; i < N; ++i) 28 | v[i] = value_for_all; 29 | } 30 | 31 | template 32 | Vec(const S* source) 33 | { 34 | for (unsigned int i = 0; i < N; ++i) 35 | v[i] = (T)source[i]; 36 | } 37 | 38 | Vec(T v0, T v1) 39 | { 40 | assert(N == 2); 41 | v[0] = v0; 42 | v[1] = v1; 43 | } 44 | 45 | Vec(T v0, T v1, T v2) 46 | { 47 | assert(N == 3); 48 | v[0] = v0; 49 | v[1] = v1; 50 | v[2] = v2; 51 | } 52 | 53 | Vec(T v0, T v1, T v2, T v3) 54 | { 55 | assert(N == 4); 56 | v[0] = v0; 57 | v[1] = v1; 58 | v[2] = v2; 59 | v[3] = v3; 60 | } 61 | 62 | Vec(T v0, T v1, T v2, T v3, T v4) 63 | { 64 | assert(N == 5); 65 | v[0] = v0; 66 | v[1] = v1; 67 | v[2] = v2; 68 | v[3] = v3; 69 | v[4] = v4; 70 | } 71 | 72 | Vec(T v0, T v1, T v2, T v3, T v4, T v5) 73 | { 74 | assert(N == 6); 75 | v[0] = v0; 76 | v[1] = v1; 77 | v[2] = v2; 78 | v[3] = v3; 79 | v[4] = v4; 80 | v[5] = v5; 81 | } 82 | 83 | T& operator[](int index) 84 | { 85 | assert(0 <= index && (unsigned int)index < N); 86 | return v[index]; 87 | } 88 | 89 | const T& operator[](int index) const 90 | { 91 | assert(0 <= index && (unsigned int)index < N); 92 | return v[index]; 93 | } 94 | 95 | Vec operator+=(const Vec& w) 96 | { 97 | for (unsigned int i = 0; i < N; ++i) 98 | v[i] += w[i]; 99 | return *this; 100 | } 101 | 102 | Vec operator+(const Vec& w) const 103 | { 104 | Vec sum(*this); 105 | sum += w; 106 | return sum; 107 | } 108 | 109 | Vec operator-=(const Vec& w) 110 | { 111 | for (unsigned int i = 0; i < N; ++i) 112 | v[i] -= w[i]; 113 | return *this; 114 | } 115 | 116 | Vec operator-(void) const // unary minus 117 | { 118 | Vec negative; 119 | for (unsigned int i = 0; i < N; ++i) 120 | negative.v[i] = -v[i]; 121 | return negative; 122 | } 123 | 124 | Vec operator-(const Vec& w) const // (binary) subtraction 125 | { 126 | Vec diff(*this); 127 | diff -= w; 128 | return diff; 129 | } 130 | 131 | Vec operator*=(T a) 132 | { 133 | for (unsigned int i = 0; i < N; ++i) 134 | v[i] *= a; 135 | return *this; 136 | } 137 | 138 | Vec operator*(T a) const 139 | { 140 | Vec w(*this); 141 | w *= a; 142 | return w; 143 | } 144 | 145 | Vec operator*(const Vec& w) const 146 | { 147 | Vec componentwise_product; 148 | for (unsigned int i = 0; i < N; ++i) 149 | componentwise_product[i] = v[i] * w.v[i]; 150 | return componentwise_product; 151 | } 152 | 153 | Vec operator/=(T a) 154 | { 155 | for (unsigned int i = 0; i < N; ++i) 156 | v[i] /= a; 157 | return *this; 158 | } 159 | 160 | Vec operator/(T a) const 161 | { 162 | Vec w(*this); 163 | w /= a; 164 | return w; 165 | } 166 | }; 167 | 168 | typedef Vec<2, double> Vec2d; 169 | typedef Vec<2, float> Vec2f; 170 | typedef Vec<2, float> v2f; 171 | typedef Vec<2, int> Vec2i; 172 | typedef Vec<2, int> v2i; 173 | typedef Vec<2, unsigned int> Vec2ui; 174 | typedef Vec<2, short> Vec2s; 175 | typedef Vec<2, unsigned short> Vec2us; 176 | typedef Vec<2, char> Vec2c; 177 | typedef Vec<2, unsigned char> Vec2uc; 178 | 179 | typedef Vec<3, double> Vec3d; 180 | typedef Vec<3, float> Vec3f; 181 | typedef Vec<3, float> v3f; 182 | typedef Vec<3, int> Vec3i; 183 | typedef Vec<3, unsigned int> Vec3ui; 184 | typedef Vec<3, short> Vec3s; 185 | typedef Vec<3, unsigned short> Vec3us; 186 | typedef Vec<3, char> Vec3c; 187 | typedef Vec<3, unsigned char> Vec3uc; 188 | 189 | typedef Vec<4, double> Vec4d; 190 | typedef Vec<4, float> Vec4f; 191 | typedef Vec<4, int> Vec4i; 192 | typedef Vec<4, unsigned int> Vec4ui; 193 | typedef Vec<4, short> Vec4s; 194 | typedef Vec<4, unsigned short> Vec4us; 195 | typedef Vec<4, char> Vec4c; 196 | typedef Vec<4, unsigned char> Vec4uc; 197 | 198 | typedef Vec<6, double> Vec6d; 199 | typedef Vec<6, float> Vec6f; 200 | typedef Vec<6, unsigned int> Vec6ui; 201 | typedef Vec<6, int> Vec6i; 202 | typedef Vec<6, short> Vec6s; 203 | typedef Vec<6, unsigned short> Vec6us; 204 | typedef Vec<6, char> Vec6c; 205 | typedef Vec<6, unsigned char> Vec6uc; 206 | 207 | template 208 | T mag2(const Vec& a) 209 | { 210 | T l = sqr(a.v[0]); 211 | for (unsigned int i = 1; i < N; ++i) 212 | l += sqr(a.v[i]); 213 | return l; 214 | } 215 | 216 | template 217 | T mag(const Vec& a) 218 | { 219 | return sqrt(mag2(a)); 220 | } 221 | 222 | template 223 | T mag1(const Vec& a) 224 | { 225 | T l = abs(a.v[0]); 226 | for (unsigned int i = 1; i < N; ++i) 227 | l += abs(a.v[i]); 228 | return l; 229 | } 230 | 231 | template 232 | inline T dist2(const Vec& a, const Vec& b) 233 | { 234 | T d = sqr(a.v[0] - b.v[0]); 235 | for (unsigned int i = 1; i < N; ++i) 236 | d += sqr(a.v[i] - b.v[i]); 237 | return d; 238 | } 239 | 240 | template 241 | inline T dist(const Vec& a, const Vec& b) 242 | { 243 | return std::sqrt(dist2(a, b)); 244 | } 245 | 246 | template 247 | inline Vec normalize(Vec& a) 248 | { 249 | return a / mag(a); 250 | } 251 | 252 | template 253 | inline T normalized(const Vec& a) 254 | { 255 | T leng = mag(a); 256 | a /= leng; 257 | return leng; 258 | } 259 | 260 | template 261 | inline T infnorm(const Vec& a) 262 | { 263 | T d = std::fabs(a.v[0]); 264 | for (unsigned int i = 1; i < N; ++i) 265 | d = max(std::fabs(a.v[i]), d); 266 | return d; 267 | } 268 | 269 | template 270 | std::ostream& operator<<(std::ostream& out, const Vec& v) 271 | { 272 | out << v.v[0]; 273 | for (unsigned int i = 1; i < N; ++i) 274 | out << ' ' << v.v[i]; 275 | return out; 276 | } 277 | 278 | template 279 | std::istream& operator>>(std::istream& in, Vec& v) 280 | { 281 | in >> v.v[0]; 282 | for (unsigned int i = 1; i < N; ++i) 283 | in >> v.v[i]; 284 | return in; 285 | } 286 | 287 | template 288 | inline bool operator==(const Vec& a, const Vec& b) 289 | { 290 | bool t = (a.v[0] == b.v[0]); 291 | unsigned int i = 1; 292 | while (i < N && t) 293 | { 294 | t = t && (a.v[i] == b.v[i]); 295 | ++i; 296 | } 297 | return t; 298 | } 299 | 300 | template 301 | inline bool operator!=(const Vec& a, const Vec& b) 302 | { 303 | bool t = (a.v[0] != b.v[0]); 304 | unsigned int i = 1; 305 | while (i < N && !t) 306 | { 307 | t = t || (a.v[i] != b.v[i]); 308 | ++i; 309 | } 310 | return t; 311 | } 312 | 313 | template 314 | inline Vec operator*(T a, const Vec& v) 315 | { 316 | Vec w(v); 317 | w *= a; 318 | return w; 319 | } 320 | 321 | template 322 | inline T min(const Vec& a) 323 | { 324 | T m = a.v[0]; 325 | for (unsigned int i = 1; i < N; ++i) 326 | if (a.v[i] < m) m = a.v[i]; 327 | return m; 328 | } 329 | 330 | template 331 | inline T max(const Vec& a) 332 | { 333 | T m = a.v[0]; 334 | for (unsigned int i = 1; i < N; ++i) 335 | if (a.v[i] > m) m = a.v[i]; 336 | return m; 337 | } 338 | 339 | template 340 | inline Vec min_union(const Vec& a, const Vec& b) 341 | { 342 | Vec m; 343 | for (unsigned int i = 0; i < N; ++i) 344 | (a.v[i] < b.v[i]) ? m.v[i] = a.v[i] : m.v[i] = b.v[i]; 345 | return m; 346 | } 347 | 348 | template 349 | inline Vec max_union(const Vec& a, const Vec& b) 350 | { 351 | Vec m; 352 | for (unsigned int i = 0; i < N; ++i) 353 | (a.v[i] > b.v[i]) ? m.v[i] = a.v[i] : m.v[i] = b.v[i]; 354 | return m; 355 | } 356 | 357 | template 358 | inline T dot(const Vec& a, const Vec& b) 359 | { 360 | T d = a.v[0] * b.v[0]; 361 | for (unsigned int i = 1; i < N; ++i) 362 | d += a.v[i] * b.v[i]; 363 | return d; 364 | } 365 | 366 | template 367 | inline T cross(const Vec<2, T>& a, const Vec<2, T>& b) 368 | { 369 | return a.v[0] * b.v[1] - a.v[1] * b.v[0]; 370 | } 371 | 372 | template 373 | inline Vec<3, T> cross(const Vec<3, T>& a, const Vec<3, T>& b) 374 | { 375 | return Vec<3, T>(a.v[1] * b.v[2] - a.v[2] * b.v[1], a.v[2] * b.v[0] - a.v[0] * b.v[2], a.v[0] * b.v[1] - a.v[1] * b.v[0]); 376 | } 377 | 378 | template 379 | inline T triple(const Vec<3, T>& a, const Vec<3, T>& b, const Vec<3, T>& c) 380 | { 381 | return a.v[0] * (b.v[1] * c.v[2] - b.v[2] * c.v[1]) + a.v[1] * (b.v[2] * c.v[0] - b.v[0] * c.v[2]) + a.v[2] * (b.v[0] * c.v[1] - b.v[1] * c.v[0]); 382 | } 383 | 384 | template 385 | inline void assign(const Vec& a, T& a0, T& a1) 386 | { 387 | assert(N == 2); 388 | a0 = a.v[0]; 389 | a1 = a.v[1]; 390 | } 391 | 392 | template 393 | inline void assign(const Vec& a, T& a0, T& a1, T& a2) 394 | { 395 | assert(N == 3); 396 | a0 = a.v[0]; 397 | a1 = a.v[1]; 398 | a2 = a.v[2]; 399 | } 400 | 401 | template 402 | inline void assign(const Vec& a, T& a0, T& a1, T& a2, T& a3) 403 | { 404 | assert(N == 4); 405 | a0 = a.v[0]; 406 | a1 = a.v[1]; 407 | a2 = a.v[2]; 408 | a3 = a.v[3]; 409 | } 410 | 411 | template 412 | inline void assign(const Vec& a, T& a0, T& a1, T& a2, T& a3, T& a4, T& a5) 413 | { 414 | assert(N == 6); 415 | a0 = a.v[0]; 416 | a1 = a.v[1]; 417 | a2 = a.v[2]; 418 | a3 = a.v[3]; 419 | a4 = a.v[4]; 420 | a5 = a.v[5]; 421 | } 422 | 423 | template 424 | inline Vec round(const Vec& a) 425 | { 426 | Vec rounded; 427 | for (unsigned int i = 0; i < N; ++i) 428 | rounded.v[i] = lround(a.v[i]); 429 | return rounded; 430 | } 431 | 432 | template 433 | inline Vec floor(const Vec& a) 434 | { 435 | Vec rounded; 436 | for (unsigned int i = 0; i < N; ++i) 437 | rounded.v[i] = (T)floor(a.v[i]); 438 | return rounded; 439 | } 440 | 441 | template 442 | inline Vec ceil(const Vec& a) 443 | { 444 | Vec rounded; 445 | for (unsigned int i = 0; i < N; ++i) 446 | rounded.v[i] = (T)ceil(a.v[i]); 447 | return rounded; 448 | } 449 | 450 | template 451 | inline Vec clamp(const Vec& a, const Vec& lower, const Vec& upper) 452 | { 453 | Vec clamped; 454 | for (unsigned int i = 0; i < N; ++i) 455 | clamped.v[i] = clamp(a.v[i], lower.v[i], upper.v[i]); 456 | return clamped; 457 | } 458 | 459 | #endif // VEC_H 460 | --------------------------------------------------------------------------------