├── ProjectSettings ├── ProjectVersion.txt ├── TagManager.asset ├── TimeManager.asset ├── AudioManager.asset ├── InputManager.asset ├── NavMeshAreas.asset ├── DynamicsManager.asset ├── EditorSettings.asset ├── GraphicsSettings.asset ├── NetworkManager.asset ├── ProjectSettings.asset ├── QualitySettings.asset ├── UnityAdsSettings.asset ├── Physics2DSettings.asset ├── ClusterInputManager.asset ├── EditorBuildSettings.asset └── UnityConnectSettings.asset ├── (2001) Procedural Modeling of Cities.pdf ├── Assets ├── RoadGen │ ├── Scenes │ │ ├── Materials │ │ │ ├── Gray.mat │ │ │ ├── Red.mat │ │ │ ├── Gray.mat.meta │ │ │ └── Red.mat.meta │ │ ├── RoadNetworkDebug.unity │ │ ├── RoadNetworkDebug.unity.meta │ │ └── Materials.meta │ ├── Scripts │ │ ├── IOrderedScript.cs │ │ ├── IPrototypeAdapter.cs │ │ ├── ICollidable.cs │ │ ├── IHeightmap.cs │ │ ├── Interpolation.cs │ │ ├── IAllotmentBuilder.cs │ │ ├── ITerrain.cs │ │ ├── Eppy.meta │ │ ├── Mischel.meta │ │ ├── Mischel │ │ │ ├── Collections.meta │ │ │ └── Collections │ │ │ │ ├── PriorityQueue.cs.meta │ │ │ │ └── PriorityQueue.cs │ │ ├── AABB.cs.meta │ │ ├── Collider.cs.meta │ │ ├── Config.cs.meta │ │ ├── IMap.cs.meta │ │ ├── ITerrain.cs.meta │ │ ├── MousePan.cs.meta │ │ ├── Perlin.cs.meta │ │ ├── Quadtree.cs.meta │ │ ├── Segment.cs.meta │ │ ├── Allotment.cs.meta │ │ ├── BitOpsHelper.cs.meta │ │ ├── Collision.cs.meta │ │ ├── ColorGradient.cs.meta │ │ ├── EasingHelper.cs.meta │ │ ├── Eppy │ │ │ ├── Tuple.cs.meta │ │ │ ├── Tuple2.cs.meta │ │ │ ├── Tuple3.cs.meta │ │ │ ├── Tuple4.cs.meta │ │ │ ├── Tuple2.cs │ │ │ ├── Tuple3.cs │ │ │ ├── Tuple4.cs │ │ │ └── Tuple.cs │ │ ├── FilterHelper.cs.meta │ │ ├── GlobalSeeder.cs.meta │ │ ├── ICollidable.cs.meta │ │ ├── IHeightmap.cs.meta │ │ ├── Interpolation.cs.meta │ │ ├── MapMesh.cs.meta │ │ ├── MockAllotment.cs.meta │ │ ├── MockTerrain.cs.meta │ │ ├── RoadNetwork.cs.meta │ │ ├── IAllotmentBuilder.cs.meta │ │ ├── IOrderedScript.cs.meta │ │ ├── IPrototypeAdapter.cs.meta │ │ ├── MouseWheelZoom.cs.meta │ │ ├── RoadDensityMap.cs.meta │ │ ├── RoadNetworkMesh.cs.meta │ │ ├── SettlementSpawner.cs.meta │ │ ├── StandardGeometry.cs.meta │ │ ├── UnityEngineHelper.cs.meta │ │ ├── DummyAllotmentBuilder.cs.meta │ │ ├── IRoadNetworkGeometry.cs.meta │ │ ├── MockTerrain.cs │ │ ├── PopulationDensityMap.cs.meta │ │ ├── RoadNetworkCollisionMap.cs.meta │ │ ├── RoadNetworkGenerator.cs.meta │ │ ├── RoadNetworkTraversal.cs.meta │ │ ├── InteractiveCityRenderer2D.cs.meta │ │ ├── InteractiveCityRenderer3D.cs.meta │ │ ├── PopulationDensityMapAdapter.cs.meta │ │ ├── RandomSettlementsSpawner.cs.meta │ │ ├── RoadNetworkGeometryBuilder.cs.meta │ │ ├── IMap.cs │ │ ├── RoadDensityBasedSettlementSpawner.cs.meta │ │ ├── IRoadNetworkGeometry.cs │ │ ├── AABB.cs │ │ ├── EasingHelper.cs │ │ ├── DummyAllotmentBuilder.cs │ │ ├── GlobalSeeder.cs │ │ ├── MousePan.cs │ │ ├── MouseWheelZoom.cs │ │ ├── PopulationDensityMapAdapter.cs │ │ ├── UnityEngineHelper.cs │ │ ├── BitOpsHelper.cs │ │ ├── FilterHelper.cs │ │ ├── PopulationDensityMap.cs │ │ ├── MockAllotment.cs │ │ ├── ColorGradient.cs │ │ ├── SettlementSpawner.cs │ │ ├── Config.cs │ │ ├── RoadNetworkMesh.cs │ │ ├── Allotment.cs │ │ ├── RoadDensityMap.cs │ │ ├── RandomSettlementsSpawner.cs │ │ ├── MapMesh.cs │ │ ├── StandardGeometry.cs │ │ ├── RoadNetworkTraversal.cs │ │ ├── RoadNetwork.cs │ │ ├── Quadtree.cs │ │ ├── Perlin.cs │ │ ├── InteractiveCityRenderer3D.cs │ │ ├── InteractiveCityRenderer2D.cs │ │ ├── Collider.cs │ │ ├── Segment.cs │ │ ├── Collision.cs │ │ ├── RoadNetworkCollisionMap.cs │ │ └── RoadDensityBasedSettlementSpawner.cs │ ├── Editor.meta │ ├── Scenes.meta │ ├── Scripts.meta │ └── Editor │ │ ├── UnitTests.meta │ │ ├── PerformanceTests.meta │ │ ├── UnitTests │ │ ├── RoadGen.meta │ │ ├── Assert.cs.meta │ │ ├── BitOpsHelperTests.cs.meta │ │ ├── RoadGen │ │ │ ├── CollisionTests.cs.meta │ │ │ └── CollisionTests.cs │ │ ├── BitOpsHelperTests.cs │ │ └── Assert.cs │ │ └── PerformanceTests │ │ ├── BitOpsHelperPerformanceTests.cs.meta │ │ └── BitOpsHelperPerformanceTests.cs └── RoadGen.meta ├── .gitignore ├── LICENSE └── README.md /ProjectSettings/ProjectVersion.txt: -------------------------------------------------------------------------------- 1 | m_EditorVersion: 5.3.5f1 2 | m_StandardAssetsVersion: 0 3 | -------------------------------------------------------------------------------- /ProjectSettings/TagManager.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pboechat/roadgen/HEAD/ProjectSettings/TagManager.asset -------------------------------------------------------------------------------- /ProjectSettings/TimeManager.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pboechat/roadgen/HEAD/ProjectSettings/TimeManager.asset -------------------------------------------------------------------------------- /ProjectSettings/AudioManager.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pboechat/roadgen/HEAD/ProjectSettings/AudioManager.asset -------------------------------------------------------------------------------- /ProjectSettings/InputManager.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pboechat/roadgen/HEAD/ProjectSettings/InputManager.asset -------------------------------------------------------------------------------- /ProjectSettings/NavMeshAreas.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pboechat/roadgen/HEAD/ProjectSettings/NavMeshAreas.asset -------------------------------------------------------------------------------- /ProjectSettings/DynamicsManager.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pboechat/roadgen/HEAD/ProjectSettings/DynamicsManager.asset -------------------------------------------------------------------------------- /ProjectSettings/EditorSettings.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pboechat/roadgen/HEAD/ProjectSettings/EditorSettings.asset -------------------------------------------------------------------------------- /ProjectSettings/GraphicsSettings.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pboechat/roadgen/HEAD/ProjectSettings/GraphicsSettings.asset -------------------------------------------------------------------------------- /ProjectSettings/NetworkManager.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pboechat/roadgen/HEAD/ProjectSettings/NetworkManager.asset -------------------------------------------------------------------------------- /ProjectSettings/ProjectSettings.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pboechat/roadgen/HEAD/ProjectSettings/ProjectSettings.asset -------------------------------------------------------------------------------- /ProjectSettings/QualitySettings.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pboechat/roadgen/HEAD/ProjectSettings/QualitySettings.asset -------------------------------------------------------------------------------- /ProjectSettings/UnityAdsSettings.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pboechat/roadgen/HEAD/ProjectSettings/UnityAdsSettings.asset -------------------------------------------------------------------------------- /(2001) Procedural Modeling of Cities.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pboechat/roadgen/HEAD/(2001) Procedural Modeling of Cities.pdf -------------------------------------------------------------------------------- /Assets/RoadGen/Scenes/Materials/Gray.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pboechat/roadgen/HEAD/Assets/RoadGen/Scenes/Materials/Gray.mat -------------------------------------------------------------------------------- /Assets/RoadGen/Scenes/Materials/Red.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pboechat/roadgen/HEAD/Assets/RoadGen/Scenes/Materials/Red.mat -------------------------------------------------------------------------------- /ProjectSettings/Physics2DSettings.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pboechat/roadgen/HEAD/ProjectSettings/Physics2DSettings.asset -------------------------------------------------------------------------------- /ProjectSettings/ClusterInputManager.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pboechat/roadgen/HEAD/ProjectSettings/ClusterInputManager.asset -------------------------------------------------------------------------------- /ProjectSettings/EditorBuildSettings.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pboechat/roadgen/HEAD/ProjectSettings/EditorBuildSettings.asset -------------------------------------------------------------------------------- /ProjectSettings/UnityConnectSettings.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pboechat/roadgen/HEAD/ProjectSettings/UnityConnectSettings.asset -------------------------------------------------------------------------------- /Assets/RoadGen/Scenes/RoadNetworkDebug.unity: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pboechat/roadgen/HEAD/Assets/RoadGen/Scenes/RoadNetworkDebug.unity -------------------------------------------------------------------------------- /Assets/RoadGen/Scripts/IOrderedScript.cs: -------------------------------------------------------------------------------- 1 | namespace RoadGen 2 | { 3 | public interface IOrderedScript 4 | { 5 | bool Finished(); 6 | 7 | } 8 | 9 | } -------------------------------------------------------------------------------- /Assets/RoadGen/Scripts/IPrototypeAdapter.cs: -------------------------------------------------------------------------------- 1 | namespace RoadGen 2 | { 3 | public interface IPrototypeAdapter 4 | { 5 | T Convert(); 6 | 7 | } 8 | 9 | } -------------------------------------------------------------------------------- /Assets/RoadGen/Scripts/ICollidable.cs: -------------------------------------------------------------------------------- 1 | namespace RoadGen 2 | { 3 | public interface ICollidable 4 | { 5 | Collider GetCollider(); 6 | 7 | } 8 | 9 | } 10 | -------------------------------------------------------------------------------- /Assets/RoadGen/Scripts/IHeightmap.cs: -------------------------------------------------------------------------------- 1 | namespace RoadGen 2 | { 3 | public interface IHeightmap : IOrderedScript 4 | { 5 | float GetHeight(float x, float y); 6 | 7 | } 8 | 9 | } -------------------------------------------------------------------------------- /Assets/RoadGen/Scripts/Interpolation.cs: -------------------------------------------------------------------------------- 1 | namespace RoadGen 2 | { 3 | public enum Interpolation 4 | { 5 | LINEAR, 6 | SMOOTHSTEP, 7 | SMOOTHERSTEP 8 | 9 | } 10 | 11 | } -------------------------------------------------------------------------------- /Assets/RoadGen.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 32914f21646c68f4e9f6b6f7c7d33ad6 3 | folderAsset: yes 4 | timeCreated: 1470338509 5 | licenseType: Free 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Assets/RoadGen/Scenes/Materials/Gray.mat.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 6bd6a1bac126f074e8b9706b8fc342f6 3 | timeCreated: 1463071855 4 | licenseType: Free 5 | NativeFormatImporter: 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Assets/RoadGen/Scenes/Materials/Red.mat.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 4c337380f10f8374a95b6e61a7b1b3d9 3 | timeCreated: 1463070123 4 | licenseType: Free 5 | NativeFormatImporter: 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Assets/RoadGen/Scenes/RoadNetworkDebug.unity.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: d126fb6ca3874b244bc6e49c64b7b638 3 | timeCreated: 1460117868 4 | licenseType: Free 5 | DefaultImporter: 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Assets/RoadGen/Scripts/IAllotmentBuilder.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | 3 | namespace RoadGen 4 | { 5 | public interface IAllotmentBuilder 6 | { 7 | GameObject Build(Allotment allotment, IHeightmap heightmap); 8 | 9 | } 10 | 11 | } -------------------------------------------------------------------------------- /Assets/RoadGen/Scripts/ITerrain.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | 3 | namespace RoadGen 4 | { 5 | public interface ITerrain : IHeightmap 6 | { 7 | int GetHeightmapDownscale(); 8 | TerrainData GetData(); 9 | 10 | } 11 | 12 | } -------------------------------------------------------------------------------- /Assets/RoadGen/Editor.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 6f91cc3cdd82ca545889b2ad25030cbd 3 | folderAsset: yes 4 | timeCreated: 1470338509 5 | licenseType: Free 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Assets/RoadGen/Scenes.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 4e3cc2f11f7878641b8e7dc0e0a502c6 3 | folderAsset: yes 4 | timeCreated: 1470338509 5 | licenseType: Free 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Assets/RoadGen/Scripts.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 19a0bc4b8272e934a8b0c63c488443b6 3 | folderAsset: yes 4 | timeCreated: 1470570729 5 | licenseType: Free 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Assets/RoadGen/Scripts/Eppy.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 3236ae819e9e5b8499c048657d14dec0 3 | folderAsset: yes 4 | timeCreated: 1470338509 5 | licenseType: Free 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Assets/RoadGen/Scripts/Mischel.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 6acc11c235f81c843892714fb9941e19 3 | folderAsset: yes 4 | timeCreated: 1470338509 5 | licenseType: Free 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Assets/RoadGen/Editor/UnitTests.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 042d47558e5160748905800a9c5e526b 3 | folderAsset: yes 4 | timeCreated: 1470338509 5 | licenseType: Free 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Assets/RoadGen/Scenes/Materials.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 96945c732ccecb64497820301e4e34f8 3 | folderAsset: yes 4 | timeCreated: 1470338509 5 | licenseType: Free 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Assets/RoadGen/Editor/PerformanceTests.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 175f7e37bdf7d3a449d52117b9a89dbd 3 | folderAsset: yes 4 | timeCreated: 1470338509 5 | licenseType: Free 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Assets/RoadGen/Editor/UnitTests/RoadGen.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: c0b66e3d364e96e41bea33863b447ecf 3 | folderAsset: yes 4 | timeCreated: 1470338509 5 | licenseType: Free 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Assets/RoadGen/Scripts/Mischel/Collections.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 63bec150f86062d41814ba3000e95895 3 | folderAsset: yes 4 | timeCreated: 1470338509 5 | licenseType: Free 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Assets/RoadGen/Scripts/AABB.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 7a54caea09adcc944879ed3508fe8c84 3 | timeCreated: 1459777898 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Assets/RoadGen/Scripts/Collider.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 5e23548bfbcacd04582ff098bfcb4122 3 | timeCreated: 1459764196 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Assets/RoadGen/Scripts/Config.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 1fa1b9d2b46b94f42ab692d283c0edba 3 | timeCreated: 1459760094 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Assets/RoadGen/Scripts/IMap.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: cab9417303a94774d944ce6891e35d25 3 | timeCreated: 1463736577 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Assets/RoadGen/Scripts/ITerrain.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: a11823ce7fd01f6469e76576967338c5 3 | timeCreated: 1470414953 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Assets/RoadGen/Scripts/MousePan.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 05ae212fee70a69409469bf030a29d15 3 | timeCreated: 1460146882 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Assets/RoadGen/Scripts/Perlin.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: cb8d8b009a536aa45a54886fc4e5cf3a 3 | timeCreated: 1459777898 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Assets/RoadGen/Scripts/Quadtree.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 0dd006beb881f5e4299086e33d36c1a1 3 | timeCreated: 1459777898 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Assets/RoadGen/Scripts/Segment.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: f34cf52202c815a4587e746124f54e27 3 | timeCreated: 1459760094 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Assets/RoadGen/Scripts/Allotment.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 3203b0ba678727c419cca13330dbb194 3 | timeCreated: 1459847583 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Assets/RoadGen/Scripts/BitOpsHelper.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: f61364135fabe834c9811e357982c06f 3 | timeCreated: 1462810383 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Assets/RoadGen/Scripts/Collision.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 722dcbf50ea59dc4e872fbefa545aaea 3 | timeCreated: 1459806689 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Assets/RoadGen/Scripts/ColorGradient.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 41a02505f3f7eba45b545d5aef974269 3 | timeCreated: 1459781258 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Assets/RoadGen/Scripts/EasingHelper.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 6f7a26dee1ad4f7479c435df73914897 3 | timeCreated: 1470414913 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Assets/RoadGen/Scripts/Eppy/Tuple.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: cb2b440ceefe09f4a88475959dbd81d6 3 | timeCreated: 1457601660 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Assets/RoadGen/Scripts/Eppy/Tuple2.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 1d2e2f57ad03088429d9682980433f96 3 | timeCreated: 1457601658 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Assets/RoadGen/Scripts/Eppy/Tuple3.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 77ee684018bc0d640a38140bb6e1b4e1 3 | timeCreated: 1457601658 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Assets/RoadGen/Scripts/Eppy/Tuple4.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: c467dac308c79ee42b436c3c25721f27 3 | timeCreated: 1457601658 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Assets/RoadGen/Scripts/FilterHelper.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 34282e0c128a075408f83f858748ce5c 3 | timeCreated: 1464014762 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Assets/RoadGen/Scripts/GlobalSeeder.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: ede2dacfcc860094680c03cdbe94d4c5 3 | timeCreated: 1470568813 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 1 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Assets/RoadGen/Scripts/ICollidable.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 916e6e8bab7bd5c4f87ac0da6734ef7b 3 | timeCreated: 1459850228 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Assets/RoadGen/Scripts/IHeightmap.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: f561abc1e41cd0d4b81803d7f6f2a68e 3 | timeCreated: 1470414953 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Assets/RoadGen/Scripts/Interpolation.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: e743aaba0c6c1c4438161732334cbbd7 3 | timeCreated: 1464171700 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Assets/RoadGen/Scripts/MapMesh.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 7341a36f8c633e548a0671d08a2b6e15 3 | timeCreated: 1470568796 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 600 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Assets/RoadGen/Scripts/MockAllotment.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 7d66c367b675cd041a1c6b9d02f90e19 3 | timeCreated: 1462802483 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Assets/RoadGen/Scripts/MockTerrain.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 9365df594c8d1fc49bd6837b3ed4b762 3 | timeCreated: 1470414953 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Assets/RoadGen/Scripts/RoadNetwork.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 371ce48921690e647a63ca2461e679e1 3 | timeCreated: 1470568813 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 2 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Assets/RoadGen/Editor/UnitTests/Assert.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: cb93a973bee5f5a4090fbe2c43971342 3 | timeCreated: 1459934130 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Assets/RoadGen/Scripts/IAllotmentBuilder.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 46af9974c6956b0489414a975184d9e1 3 | timeCreated: 1462785748 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Assets/RoadGen/Scripts/IOrderedScript.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 73dcaa7bc0cfd9d4a93a14c3ab3f51ed 3 | timeCreated: 1463735025 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Assets/RoadGen/Scripts/IPrototypeAdapter.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 560cbbb7b761d794e85dd4dfc1c1ce6f 3 | timeCreated: 1462377518 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Assets/RoadGen/Scripts/MouseWheelZoom.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 1f46b514317777345b0f918d9bd89c89 3 | timeCreated: 1460146258 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Assets/RoadGen/Scripts/RoadDensityMap.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: f818ab087f071b94bbc093ae4ab37f7a 3 | timeCreated: 1470568813 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 3 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Assets/RoadGen/Scripts/RoadNetworkMesh.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 1535e6fa34fb3db41959a55fc063fcdf 3 | timeCreated: 1470568813 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 5 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Assets/RoadGen/Scripts/SettlementSpawner.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: b2a7e569da518ce4899108d5d3cfe773 3 | timeCreated: 1461840006 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Assets/RoadGen/Scripts/StandardGeometry.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 28c8ab6915259164d833dde040165d36 3 | timeCreated: 1461841076 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Assets/RoadGen/Scripts/UnityEngineHelper.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: fca65a1f30a458049bc85bda11be52ca 3 | timeCreated: 1462804233 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Assets/RoadGen/Scripts/DummyAllotmentBuilder.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: f595b9313ec327b40864717b3d6c84f6 3 | timeCreated: 1462796056 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Assets/RoadGen/Scripts/IRoadNetworkGeometry.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 32a5f2c5babb2374181e072fd00cf25b 3 | timeCreated: 1460640198 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Assets/RoadGen/Scripts/MockTerrain.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using RoadGen; 3 | 4 | public class MockTerrain : MonoBehaviour, IHeightmap 5 | { 6 | public float z; 7 | 8 | public float GetHeight(float x, float y) 9 | { 10 | return z; 11 | } 12 | 13 | public bool Finished() 14 | { 15 | return true; 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /Assets/RoadGen/Scripts/PopulationDensityMap.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: d81e7de41ea2ffd4ab56d2dc5b6fbe9a 3 | timeCreated: 1459778535 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Assets/RoadGen/Scripts/RoadNetworkCollisionMap.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 85a9dbe8e4d891b4183753c5f8122fe8 3 | timeCreated: 1462356252 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Assets/RoadGen/Scripts/RoadNetworkGenerator.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 0432524861f1183469bcd95d7706c6d2 3 | timeCreated: 1459758655 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Assets/RoadGen/Scripts/RoadNetworkTraversal.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 9ffaaec4846844b468e14611d1691b21 3 | timeCreated: 1459864784 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Assets/RoadGen/Editor/UnitTests/BitOpsHelperTests.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 8e2f670fb92a0704b9025ab6cfbcd980 3 | timeCreated: 1462812948 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Assets/RoadGen/Scripts/InteractiveCityRenderer2D.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: d27166b45a798f64198b745739b976e9 3 | timeCreated: 1460102567 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Assets/RoadGen/Scripts/InteractiveCityRenderer3D.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 66298d210ee1e7e41bf62297b24d625d 3 | timeCreated: 1460115439 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Assets/RoadGen/Scripts/PopulationDensityMapAdapter.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 75d09cfaa5bbae6419ba2503f23123bf 3 | timeCreated: 1463736577 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Assets/RoadGen/Scripts/RandomSettlementsSpawner.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 09b447764f5d2ed469edcf8ab50ad84a 3 | timeCreated: 1470414808 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Assets/RoadGen/Scripts/RoadNetworkGeometryBuilder.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 14772b7fb6227d94a97a378b0b3dab4c 3 | timeCreated: 1460143792 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Assets/RoadGen/Editor/UnitTests/RoadGen/CollisionTests.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 824f0b78c52299b4386719fddf9940d0 3 | timeCreated: 1459929366 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Assets/RoadGen/Scripts/IMap.cs: -------------------------------------------------------------------------------- 1 | namespace RoadGen 2 | { 3 | public interface IMap : IOrderedScript 4 | { 5 | float GetWidth(); 6 | float GetHeight(); 7 | float GetMinX(); 8 | float GetMaxX(); 9 | float GetMinY(); 10 | float GetMaxY(); 11 | float GetNormalizedValue(float x, float y); 12 | 13 | } 14 | 15 | } -------------------------------------------------------------------------------- /Assets/RoadGen/Scripts/Mischel/Collections/PriorityQueue.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 26f9a969cab509b4fb30bad3c0bcf485 3 | timeCreated: 1459809339 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Assets/RoadGen/Scripts/RoadDensityBasedSettlementSpawner.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: cebfe005ff2c8c84a9df02a9b28007c9 3 | timeCreated: 1470568813 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 4 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Assets/RoadGen/Editor/PerformanceTests/BitOpsHelperPerformanceTests.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: bc06ae48af7408e43b85d557d8f98c6b 3 | timeCreated: 1462957742 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Assets/RoadGen/Scripts/IRoadNetworkGeometry.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System.Collections.Generic; 3 | 4 | namespace RoadGen 5 | { 6 | public interface IRoadNetworkGeometry 7 | { 8 | List GetCrossingPositions(); 9 | List GetCrossingUvs(); 10 | List GetCrossingIndices(); 11 | List GetSegmentPositions(); 12 | List GetSegmentUvs(); 13 | List GetSegmentIndices(); 14 | 15 | } 16 | 17 | } -------------------------------------------------------------------------------- /Assets/RoadGen/Scripts/AABB.cs: -------------------------------------------------------------------------------- 1 | namespace RoadGen 2 | { 3 | public class AABB 4 | { 5 | public float x; 6 | public float y; 7 | public float width; 8 | public float height; 9 | public object reference; 10 | 11 | public AABB(float x, float y, float width, float height, object reference) 12 | { 13 | this.x = x; this.y = y; this.width = width; this.height = height; this.reference = reference; 14 | } 15 | 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /[Ll]ibrary/ 2 | /[Tt]emp/ 3 | /[Oo]bj/ 4 | /[Bb]uild/ 5 | /[Bb]uilds/ 6 | /Assets/AssetStoreTools* 7 | /.git/ 8 | /.vs/ 9 | 10 | # Autogenerated VS/MD solution and project files 11 | ExportedObj/ 12 | *.csproj 13 | *.unityproj 14 | *.sln 15 | *.suo 16 | *.tmp 17 | *.user 18 | *.userprefs 19 | *.pidb 20 | *.booproj 21 | *.svd 22 | 23 | 24 | # Unity3D generated meta files 25 | *.pidb.meta 26 | 27 | # Unity3D Generated File On Crash Reports 28 | sysinfo.txt 29 | 30 | # Builds 31 | *.apk 32 | *.unitypackage 33 | -------------------------------------------------------------------------------- /Assets/RoadGen/Scripts/EasingHelper.cs: -------------------------------------------------------------------------------- 1 | namespace RoadGen 2 | { 3 | /// 4 | /// source: http://gizma.com/easing/ 5 | /// 6 | public static class EasingHelper 7 | { 8 | public static float EaseInCubic(float t, float b, float c, float d) 9 | { 10 | t /= d; 11 | return c * t * t * t + b; 12 | } 13 | 14 | public static float EaseOutCubic(float t, float b, float c, float d) 15 | { 16 | t /= d; 17 | t--; 18 | return c * (t * t * t + 1) + b; 19 | } 20 | 21 | } 22 | 23 | } -------------------------------------------------------------------------------- /Assets/RoadGen/Editor/UnitTests/BitOpsHelperTests.cs: -------------------------------------------------------------------------------- 1 | using NUnit.Framework; 2 | using RoadGen; 3 | 4 | [TestFixture] 5 | public class BitOpsHelperTests 6 | { 7 | public void test_bfind() 8 | { 9 | // 11 = 1011, so the third flipped bit is in index 3 10 | Assert.AreEqual(3, BitOpsHelper.BFind(11, 3)); 11 | // 3 = 11, so there's no third flipped bit and BFind returns 32 12 | Assert.AreEqual(32, BitOpsHelper.BFind(3, 3)); 13 | // searching for the 0th flipped bit always causes BFind to return 32 14 | Assert.AreEqual(32, BitOpsHelper.BFind(1, 0)); 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /Assets/RoadGen/Scripts/DummyAllotmentBuilder.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using RoadGen; 3 | 4 | public class DummyAllotmentBuilder : MonoBehaviour, IAllotmentBuilder 5 | { 6 | public float height = 12; 7 | public Material material; 8 | 9 | public GameObject Build(Allotment allotment, IHeightmap heightmap) 10 | { 11 | GameObject allotmentGO = new GameObject("Allotment"); 12 | float z = heightmap.GetHeight(allotment.Center.x, allotment.Center.y); 13 | allotmentGO.AddComponent().mesh = StandardGeometry.CreateCubeMesh(allotment.Corners, height, z); 14 | allotmentGO.AddComponent().material = material; 15 | return allotmentGO; 16 | } 17 | 18 | } -------------------------------------------------------------------------------- /Assets/RoadGen/Scripts/GlobalSeeder.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System; 3 | 4 | public class GlobalSeeder : MonoBehaviour 5 | { 6 | public bool useTimeAsSeed = true; 7 | public int seed = 0; 8 | 9 | static int GetSecondsSinceEpoch() 10 | { 11 | var seconds = DateTime.Now.Subtract(new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)).TotalSeconds; 12 | if (seconds > (double)int.MaxValue) 13 | throw new Exception(); 14 | return (int)seconds; 15 | } 16 | 17 | void Start() 18 | { 19 | seed = (useTimeAsSeed) ? GetSecondsSinceEpoch() : seed; 20 | UnityEngine.Random.seed = seed; 21 | RoadGen.Perlin.Seed(seed); 22 | Debug.Log("Seed: " + seed); 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /Assets/RoadGen/Editor/UnitTests/RoadGen/CollisionTests.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System.Collections; 3 | using NUnit.Framework; 4 | 5 | namespace RoadGen 6 | { 7 | [TestFixture] 8 | public class CollisionTests 9 | { 10 | [Test] 11 | public void test_arm_points() 12 | { 13 | Vector2 p0 = new Vector2(2, 2); 14 | Vector2 p1 = new Vector2(0, 0); 15 | Vector2 p2 = new Vector2(-2, 2); 16 | float width = Mathf.Sqrt(2); 17 | 18 | // --- 19 | 20 | Vector2 elbow, joint; 21 | Collision.ArmPoints(p0, p1, p2, width, out elbow, out joint); 22 | 23 | // --- 24 | 25 | Assert.AreEqual(new Vector2(0, -1), elbow); 26 | Assert.AreEqual(new Vector2(0, 1), joint); 27 | } 28 | 29 | } 30 | 31 | } -------------------------------------------------------------------------------- /Assets/RoadGen/Scripts/MousePan.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | 3 | ////////////////////////////////////////////////////////////////////////////////////////// 4 | // source: http://answers.unity3d.com/questions/614174/pan-orthographic-camera.html 5 | ////////////////////////////////////////////////////////////////////////////////////////// 6 | public class MousePan : MonoBehaviour 7 | { 8 | public int button = 2; 9 | public float sensitivityX = 0.5f; 10 | public float sensitivityY = 0.5f; 11 | 12 | void Update() 13 | { 14 | if (!Input.GetMouseButton(button)) 15 | return; 16 | float y = Input.GetAxis("Mouse Y"), x = Input.GetAxis("Mouse X"); 17 | if (x != 0) 18 | Camera.main.transform.Translate(Vector3.left * (x * sensitivityX)); 19 | if (y != 0) 20 | Camera.main.transform.Translate(Vector3.down * (y * sensitivityY)); 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /Assets/RoadGen/Scripts/MouseWheelZoom.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System.Collections; 3 | 4 | ////////////////////////////////////////////////////////////////////////////////////////// 5 | // source: http://answers.unity3d.com/questions/20228/mouse-wheel-zoom.html 6 | ////////////////////////////////////////////////////////////////////////////////////////// 7 | public class MouseWheelZoom : MonoBehaviour 8 | { 9 | public float orthographicSizeMin = 1; 10 | public float orthographicSizeMax = 6; 11 | public float sensitivity = 1; 12 | 13 | void Update() 14 | { 15 | float mouseWheel = Input.GetAxis("Mouse ScrollWheel"); 16 | if (mouseWheel < 0) // forward 17 | Camera.main.orthographicSize -= mouseWheel * sensitivity; 18 | else if (mouseWheel > 0) // back 19 | Camera.main.orthographicSize -= mouseWheel * sensitivity; 20 | Camera.main.orthographicSize = Mathf.Clamp(Camera.main.orthographicSize, orthographicSizeMin, orthographicSizeMax); 21 | } 22 | 23 | } -------------------------------------------------------------------------------- /Assets/RoadGen/Scripts/PopulationDensityMapAdapter.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using RoadGen; 3 | 4 | public class PopulationDensityMapAdapter : MonoBehaviour, IMap 5 | { 6 | public float GetWidth() 7 | { 8 | return RoadGen.Config.QuadtreeParams.width; 9 | } 10 | 11 | public float GetHeight() 12 | { 13 | return RoadGen.Config.QuadtreeParams.height; 14 | } 15 | 16 | public float GetMinX() 17 | { 18 | return RoadGen.Config.QuadtreeParams.xMin; 19 | } 20 | 21 | public float GetMaxX() 22 | { 23 | return RoadGen.Config.QuadtreeParams.xMax; 24 | } 25 | 26 | public float GetMinY() 27 | { 28 | return RoadGen.Config.QuadtreeParams.yMin; 29 | } 30 | 31 | public float GetMaxY() 32 | { 33 | return RoadGen.Config.QuadtreeParams.yMax; 34 | } 35 | 36 | public float GetNormalizedValue(float x, float y) 37 | { 38 | return RoadGen.PopulationDensityMap.DensityAt(x, y); 39 | } 40 | 41 | public bool Finished() 42 | { 43 | return true; 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 Pedro Boechat 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Assets/RoadGen/Scripts/UnityEngineHelper.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System.Collections.Generic; 3 | 4 | namespace RoadGen 5 | { 6 | public static class UnityEngineHelper 7 | { 8 | public static List GetInterfaces(GameObject gameObject) where T : class 9 | { 10 | UnityEngine.Component[] components = gameObject.GetComponents(typeof(T)); 11 | if (components.Length == 0) 12 | return null; 13 | List interfaces = new List(); 14 | foreach (var component in components) 15 | interfaces.Add((component as T)); 16 | return interfaces; 17 | } 18 | 19 | public static T GetInterface(GameObject gameObject) where T : class 20 | { 21 | UnityEngine.Component[] components = gameObject.GetComponents(typeof(T)); 22 | if (components.Length == 0) 23 | return null; 24 | foreach (var component in components) 25 | return (component as T); 26 | return null; 27 | } 28 | 29 | public static Bounds GetRenderingBounds(GameObject gameObject) 30 | { 31 | var meshRenderer = gameObject.GetComponentInChildren(); 32 | return meshRenderer.bounds; 33 | } 34 | 35 | } 36 | 37 | } -------------------------------------------------------------------------------- /Assets/RoadGen/Scripts/BitOpsHelper.cs: -------------------------------------------------------------------------------- 1 | namespace RoadGen 2 | { 3 | public static class BitOpsHelper 4 | { 5 | public static int PopCount(int bitmask) 6 | { 7 | bitmask = bitmask - ((bitmask >> 1) & 0x55555555); 8 | bitmask = (bitmask & 0x33333333) + ((bitmask >> 2) & 0x33333333); 9 | return (((bitmask + (bitmask >> 4)) & 0x0F0F0F0F) * 0x01010101) >> 24; 10 | } 11 | 12 | public static int RandomBit(int bitmask) 13 | { 14 | return UnityEngine.Random.Range(0, PopCount(bitmask)); 15 | } 16 | 17 | public static int RemoveRandomBit(ref int bitmask) 18 | { 19 | var randomBitIndex = UnityEngine.Random.Range(0, PopCount(bitmask)); 20 | var actualBitIndex = BitOpsHelper.BFind(bitmask, randomBitIndex + 1); 21 | bitmask &= ~(1 << actualBitIndex); 22 | return actualBitIndex; 23 | } 24 | 25 | public static int Clz(int bitmask) 26 | { 27 | int i = 0; 28 | while ((bitmask & (1 << i)) == 0 && i < 32) 29 | i++; 30 | return i; 31 | } 32 | 33 | public static int BFind(int bitmask, int count) 34 | { 35 | int c = 0, i = 0; 36 | do 37 | { 38 | c += (bitmask & (1 << i)) >> i; 39 | } while (c != count && ++i < 32); 40 | return i; 41 | } 42 | 43 | } 44 | 45 | } -------------------------------------------------------------------------------- /Assets/RoadGen/Editor/PerformanceTests/BitOpsHelperPerformanceTests.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics; 2 | using System.Collections.Generic; 3 | using NUnit.Framework; 4 | using RoadGen; 5 | 6 | [TestFixture] 7 | public class BitOpsHelperPerformanceTests 8 | { 9 | [Test] 10 | public void test_remove_random_bit_vs_hashset_performance() 11 | { 12 | HashSet hashSet = new HashSet { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 13 | 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 14 | 21, 22, 23, 24, 25, 26, 27, 28, 29, 30 }; 15 | int bitmask = 2147483647; 16 | Stopwatch stopWatch = new Stopwatch(); 17 | 18 | int[] selection0 = new int[31]; 19 | int[] selection1 = new int[31]; 20 | 21 | 22 | // --- 23 | 24 | UnityEngine.Random.seed = 0; 25 | int c = 0; 26 | stopWatch.Start(); 27 | while (bitmask != 0) 28 | selection0[c++] = BitOpsHelper.RemoveRandomBit(ref bitmask); 29 | stopWatch.Stop(); 30 | var t0 = stopWatch.ElapsedTicks; 31 | 32 | UnityEngine.Random.seed = 0; 33 | c = 0; 34 | stopWatch.Start(); 35 | while (hashSet.Count > 0) 36 | { 37 | int i = UnityEngine.Random.Range(0, hashSet.Count); 38 | var e = hashSet.GetEnumerator(); 39 | while (i-- >= 0) 40 | e.MoveNext(); 41 | hashSet.Remove(selection1[c++] = e.Current); 42 | } 43 | stopWatch.Stop(); 44 | var t1 = stopWatch.ElapsedTicks; 45 | 46 | // --- 47 | 48 | //UnityEngine.Debug.Log("t0: " + t0); 49 | //UnityEngine.Debug.Log("t1: " + t1); 50 | //string str0 = "", str1 = ""; 51 | //for (int i = 0; i < 31; i++) 52 | //{ 53 | // str0 += selection0[i] + ", "; 54 | // str1 += selection1[i] + ", "; 55 | //} 56 | //UnityEngine.Debug.Log("selection0: " + str0); 57 | //UnityEngine.Debug.Log("selection1: " + str1); 58 | 59 | Assert.AreIdenticalSets(selection0, selection1, (a, b) => a == b); 60 | Assert.IsTrue(t0 < t1); 61 | } 62 | 63 | } 64 | -------------------------------------------------------------------------------- /Assets/RoadGen/Scripts/FilterHelper.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | 3 | namespace RoadGen 4 | { 5 | public static class FilterHelper 6 | { 7 | public static float[,] CreateGaussianKernel(int size, float weight) 8 | { 9 | float[,] kernel = new float[size, size]; 10 | float calculatedEuler = 1.0f / (2.0f * Mathf.PI * Mathf.Pow(weight, 2)); 11 | int radius = size / 2; 12 | float distance = 0; 13 | float sum = 0; 14 | for (int fY = -radius; fY <= radius; fY++) 15 | { 16 | for (int fX = -radius; fX <= radius; fX++) 17 | { 18 | distance = ((fX * fX) + (fY * fY)) / (2 * (weight * weight)); 19 | kernel[fX + radius, fY + radius] = calculatedEuler * Mathf.Exp(-distance); 20 | sum += kernel[fX + radius, fY + radius]; 21 | } 22 | } 23 | for (int y = 0; y < size; y++) 24 | { 25 | for (int x = 0; x < size; x++) 26 | { 27 | kernel[x, y] = kernel[x, y] * (1.0f / sum); 28 | } 29 | } 30 | return kernel; 31 | } 32 | 33 | public static void Convolute(float[,] src, float[,] dst, float[,] filter, int w, int h, int kernelSize, int x0 = 0, int x1 = -1, int y0 = 0, int y1 = -1) 34 | { 35 | if (x1 < 0) 36 | x1 = w - 1; 37 | if (y1 < 0) 38 | y1 = h - 1; 39 | int hKernelSize = kernelSize / 2; 40 | for (int gY = y0; gY <= y1; gY++) 41 | { 42 | for (int gX = x0; gX <= x1; gX++) 43 | { 44 | dst[gX, gY] = src[gX, gY]; 45 | float pixel = 0; 46 | int minFY = Mathf.Max(0, gY - hKernelSize), 47 | maxFY = Mathf.Min(h - 1, gY + hKernelSize); 48 | int minFX = Mathf.Max(0, gX - hKernelSize), 49 | maxFX = Mathf.Min(w - 1, gX + hKernelSize); 50 | for (int y = 0, fY = minFY; fY <= maxFY; y++, fY++) 51 | for (int x = 0, fX = minFX; fX <= maxFX; x++, fX++) 52 | pixel += filter[x, y] * src[fX, fY]; 53 | dst[gX, gY] = pixel; 54 | } 55 | } 56 | } 57 | 58 | } 59 | 60 | } -------------------------------------------------------------------------------- /Assets/RoadGen/Scripts/PopulationDensityMap.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | 3 | namespace RoadGen 4 | { 5 | public static class PopulationDensityMap 6 | { 7 | private static float width = -1; 8 | private static float height = -1; 9 | private static float offset = -1; 10 | private static float twoOffset = -1; 11 | 12 | private static float Width 13 | { 14 | get 15 | { 16 | if (width == -1) 17 | { 18 | // NOTE: downscale of 4 19 | width = Config.QuadtreeParams.width * 0.25f; 20 | } 21 | return width; 22 | } 23 | } 24 | 25 | private static float Height 26 | { 27 | get 28 | { 29 | if (height == -1) 30 | { 31 | // NOTE: downscale of 4 32 | height = Config.QuadtreeParams.height * 0.25f; 33 | } 34 | return height; 35 | } 36 | } 37 | 38 | private static float Offset 39 | { 40 | get 41 | { 42 | if (offset == -1) 43 | offset = Width * 0.025f; 44 | return offset; 45 | } 46 | } 47 | 48 | private static float TwoOffset 49 | { 50 | get 51 | { 52 | if (twoOffset == -1) 53 | twoOffset = Offset * 2; 54 | return twoOffset; 55 | } 56 | } 57 | 58 | public static void ResetCache() 59 | { 60 | width = height = offset = twoOffset = -1; 61 | } 62 | 63 | public static float DensityOnRoad(Segment segment) 64 | { 65 | return (DensityAt(segment.Start.x, segment.Start.y) + DensityAt(segment.End.x, segment.End.y)) / 2; 66 | } 67 | 68 | public static float DensityAt(float x, float y) 69 | { 70 | float value1, value2, value3; 71 | value1 = (Perlin.Simplex2(x / (Width * 0.5f), y / (Height * 0.5f)) + 1) * 0.5f; 72 | value2 = (Perlin.Simplex2(x / Width + Offset, y / Height + Offset) + 1) * 0.5f; 73 | value3 = (Perlin.Simplex2(x / Width + TwoOffset, y / height + TwoOffset) + 1) * 0.5f; 74 | return Mathf.Pow((value1 * value2 + value3) * 0.5f, 2); 75 | } 76 | 77 | }; 78 | } 79 | -------------------------------------------------------------------------------- /Assets/RoadGen/Scripts/MockAllotment.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System.Collections.Generic; 3 | using RoadGen; 4 | 5 | public class MockAllotment : MonoBehaviour 6 | { 7 | public GameObject allotmentBuilderGameObject; 8 | public GameObject heightmapGameObject; 9 | private IHeightmap heightmap; 10 | private List allotmentBuilders = null; 11 | private List allotments = new List(); 12 | 13 | void Generate() 14 | { 15 | foreach (GameObject allotmentGO in allotments) 16 | Destroy(allotmentGO); 17 | allotments.Clear(); 18 | var allotment = new Allotment(default(Vector2), 19 | 0, 20 | UnityEngine.Random.Range(Config.allotmentMinHalfDiagonal, Config.allotmentMaxHalfDiagonal), 21 | UnityEngine.Random.Range(Config.allotmentMinAspect, Config.allotmentMaxAspect)); 22 | foreach (var allotmentBuilder in allotmentBuilders) 23 | { 24 | GameObject allotmentGO = allotmentBuilder.Build(allotment, heightmap); 25 | Vector3 position = allotmentGO.transform.position; 26 | allotmentGO.transform.position = position; 27 | allotments.Add(allotmentGO); 28 | } 29 | } 30 | 31 | void Start() 32 | { 33 | if (heightmapGameObject != null) 34 | heightmap = UnityEngineHelper.GetInterface(heightmapGameObject); 35 | 36 | if (heightmap == null) 37 | { 38 | Debug.LogError("MockAllotment needs a reference to a game object containing at least one component that implements IHeightmap"); 39 | return; 40 | } 41 | 42 | if (!heightmap.Finished()) 43 | { 44 | Debug.LogError("MockAllotment script can only execute after the components that implements IHeightmap (Configure execution order that in Edit > Project Settings > Script Execution Order)"); 45 | return; 46 | } 47 | 48 | if (allotmentBuilderGameObject != null) 49 | allotmentBuilders = UnityEngineHelper.GetInterfaces(allotmentBuilderGameObject); 50 | if (allotmentBuilders == null) 51 | { 52 | Debug.LogError("MockAllotment needs a reference to a game object containing at least one component that implements IAllotmentBuilder"); 53 | return; 54 | } 55 | 56 | Generate(); 57 | } 58 | 59 | void OnGUI() 60 | { 61 | if (GUI.Button(new Rect(10, 10, 140, 40), "Generate")) 62 | Generate(); 63 | } 64 | 65 | } 66 | -------------------------------------------------------------------------------- /Assets/RoadGen/Scripts/ColorGradient.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | 5 | namespace RoadGen 6 | { 7 | public class ColorGradient 8 | { 9 | List colors = new List(); 10 | 11 | public ColorGradient() 12 | { 13 | } 14 | 15 | public ColorGradient(IList colors) 16 | { 17 | float step = 1 / (colors.Count - 1.0f); 18 | for (int i = 0; i < colors.Count; i++) 19 | AddColor(colors[i], step * i); 20 | } 21 | 22 | public void AddColor(Color color, float value) 23 | { 24 | for (int i = 0; i < colors.Count; i++) 25 | { 26 | if (value < colors[i].a) 27 | { 28 | colors.Insert(i, new Color(color.r, color.g, color.b, value)); 29 | return; 30 | } 31 | } 32 | colors.Add(new Color(color.r, color.g, color.b, value)); 33 | } 34 | 35 | public void ClearGradient() 36 | { 37 | colors.Clear(); 38 | } 39 | 40 | public static ColorGradient CreateDefaultHeatMapGradient() 41 | { 42 | return new ColorGradient(new Color[] { 43 | new Color(0, 0, 1, 0), // Blue. 44 | new Color(0, 1, 1, 0), // Cyan. 45 | new Color(0, 1, 0, 0), // Green. 46 | new Color(1, 1, 0, 0), // Yellow. 47 | new Color(1, 0, 0, 0) // Red. 48 | }); 49 | } 50 | 51 | public void GetColorAtValue(float value, ref Color color) 52 | { 53 | if (colors.Count == 0) 54 | return; 55 | 56 | for (int i = 0; i < colors.Count; i++) 57 | { 58 | Color currColor = colors[i]; 59 | if (value < currColor.a) 60 | { 61 | Color prevColor = colors[Mathf.Max(0, i - 1)]; 62 | float valueDiff = (prevColor.a - currColor.a); 63 | float fractBetween = (valueDiff == 0) ? 0 : (value - currColor.a) / valueDiff; 64 | color.r = (prevColor.r - currColor.r) * fractBetween + currColor.r; 65 | color.g = (prevColor.g - currColor.g) * fractBetween + currColor.g; 66 | color.b = (prevColor.b - currColor.b) * fractBetween + currColor.b; 67 | return; 68 | } 69 | } 70 | color.r = colors.Last().r; 71 | color.g = colors.Last().g; 72 | color.b = colors.Last().b; 73 | return; 74 | } 75 | 76 | } 77 | 78 | } -------------------------------------------------------------------------------- /Assets/RoadGen/Scripts/SettlementSpawner.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System.Collections.Generic; 3 | 4 | namespace RoadGen 5 | { 6 | public static class SettlementSpawner 7 | { 8 | static bool SpawnBuilding(Vector2 center, float direction, Quadtree quadtree, out Allotment allotment, List allotments) 9 | { 10 | allotment = new Allotment(default(Vector2), 11 | 0, 12 | UnityEngine.Random.Range(Config.allotmentMinHalfDiagonal, Config.allotmentMaxHalfDiagonal), 13 | UnityEngine.Random.Range(Config.allotmentMinAspect, Config.allotmentMaxAspect)); 14 | allotment.UpdateCenterAndDirection(center, direction); 15 | bool allow = false; 16 | for (int j = 0; j < Config.allotmentPlacementLoopLimit; j++) 17 | { 18 | int c = 0; 19 | Vector2 offset; 20 | var colliders = quadtree.Retrieve(allotment.GetCollider().GetAABB()); 21 | for (int k = 0; k < colliders.Count && (c == 0 || j < Config.allotmentPlacementLoopLimit - 1); k++) 22 | { 23 | if (allotment.GetCollider().Collide(((ICollidable)colliders[k].reference).GetCollider(), out offset)) 24 | { 25 | c++; 26 | allotment.Center = (allotment.Center + offset); 27 | } 28 | } 29 | for (int k = 0; k < allotments.Count && (c == 0 || j < Config.allotmentPlacementLoopLimit - 1); k++) 30 | { 31 | if (allotment.GetCollider().Collide(allotments[k].GetCollider(), out offset)) 32 | { 33 | c++; 34 | allotment.Center = (allotment.Center + offset); 35 | } 36 | } 37 | if (c == 0) 38 | { 39 | allow = true; 40 | break; 41 | } 42 | } 43 | return allow; 44 | } 45 | 46 | public static void Spawn(Segment segment, int density, float radius, Quadtree quadtree, ref List newAllotments) 47 | { 48 | Vector2 segmentCenter = (segment.End + segment.Start) * 0.5f; 49 | for (int i = 0; i < density; i++) 50 | { 51 | float randomAngle = UnityEngine.Random.value * 2.0f * Mathf.PI; 52 | float randomRadius = UnityEngine.Random.value * radius; 53 | Vector2 center = new Vector2( 54 | segmentCenter.x + randomRadius * Mathf.Sin(randomAngle), 55 | segmentCenter.y + randomRadius * Mathf.Cos(randomAngle) 56 | ); 57 | Allotment newAllotment; 58 | if (SpawnBuilding(center, segment.Direction, quadtree, out newAllotment, newAllotments)) 59 | newAllotments.Add(newAllotment); 60 | } 61 | } 62 | 63 | } 64 | 65 | } -------------------------------------------------------------------------------- /Assets/RoadGen/Scripts/Config.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System; 3 | 4 | namespace RoadGen 5 | { 6 | public class Config 7 | { 8 | private readonly static float BRANCH_ANGLE_DEVIATION = 3; 9 | private readonly static float FORWARD_ANGLE_DEVIATION = 15; 10 | 11 | private static float RandomAngle(float limit) 12 | { 13 | float nonUniformNorm, value; 14 | nonUniformNorm = Mathf.Pow(Math.Abs(limit), 3); 15 | value = 0; 16 | while (value == 0 || UnityEngine.Random.value < Math.Pow(Math.Abs(value), 3) / nonUniformNorm) 17 | value = UnityEngine.Random.Range(-limit, +limit); 18 | return value; 19 | } 20 | 21 | private static Rect quadtreeParams = new Rect(-20000, -20000, 40000, 40000); 22 | 23 | public static Rect QuadtreeParams 24 | { 25 | get 26 | { 27 | return quadtreeParams; 28 | } 29 | set 30 | { 31 | quadtreeParams = value; 32 | PopulationDensityMap.ResetCache(); 33 | } 34 | } 35 | 36 | public static int quadtreeMaxObjects = 10; 37 | public static int quadtreeMaxLevels = 10; 38 | public static float streetSegmentLength = 300; 39 | public static float highwaySegmentLength = 400; 40 | public static float streetSegmentWidth = 6; 41 | public static float highwaySegmentWidth = 16; 42 | public static int derivationStepLimit = 10000; 43 | public static float streetBranchProbability = 0.4f; 44 | public static float highwayBranchProbability = 0.05f; 45 | public static float streetBranchPopulationThreshold = 0.1f; 46 | public static float highwayBranchPopulationThreshold = 0.1f; 47 | public static int highwayDelay = 1; 48 | public static int streetBranchDelayFromHighway = 5; 49 | public static float minIntersectionDeviation = 30; 50 | public static int segmentCountLimit = 500; 51 | public static float snapDistance = 50; 52 | public static int settlementSpawnDelay = 10; 53 | public static int settlementDensity = 10; 54 | public static float allotmentMinHalfDiagonal = 40.0f; 55 | public static float allotmentMaxHalfDiagonal = 60.0f; 56 | public static float allotmentMinAspect = 1.15f; 57 | public static float allotmentMaxAspect = 1.5f; 58 | public static int allotmentPlacementLoopLimit = 3; 59 | public static float settlementRadius = 400.0f; 60 | public static float settlementInCrossingProbability = 0.9f; 61 | public static float settlementInHighwayProbability = 0.1f; 62 | 63 | public static float RandomBranchAngle() 64 | { 65 | return RandomAngle(BRANCH_ANGLE_DEVIATION); 66 | } 67 | 68 | public static float RandomStraightAngle() 69 | { 70 | return RandomAngle(FORWARD_ANGLE_DEVIATION); 71 | } 72 | 73 | } 74 | 75 | } 76 | -------------------------------------------------------------------------------- /Assets/RoadGen/Editor/UnitTests/Assert.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System; 3 | using System.Collections.Generic; 4 | using NUnit.Framework; 5 | 6 | public class Assert : NUnit.Framework.Assert 7 | { 8 | public static void AreApproximatelyEqual(float expected, float actual) 9 | { 10 | if (!Mathf.Approximately(expected, actual)) 11 | Assert.Fail("Expected: " + expected + "\nBut was: " + actual); 12 | } 13 | 14 | public static void AreApproximatelyEqual(Vector2 expected, Vector2 actual) 15 | { 16 | if (!Mathf.Approximately(expected.x, actual.x) || !Mathf.Approximately(expected.y, actual.y)) 17 | Assert.Fail("Expected: " + expected + "\nBut was: " + actual); 18 | } 19 | 20 | private static bool FloatCompare(float a, float b, int precision = -1) 21 | { 22 | if (precision < 0) 23 | return Mathf.Approximately(a, b); 24 | else 25 | { 26 | float multiplier = Mathf.Pow(10, precision); 27 | return Mathf.RoundToInt(a * multiplier) == Mathf.RoundToInt(b * multiplier); 28 | } 29 | } 30 | 31 | public static void AreIdenticalSets(IEnumerable A, IEnumerable B, Func comparison) 32 | { 33 | IEnumerator e0 = A.GetEnumerator(); 34 | IEnumerator e1 = B.GetEnumerator(); 35 | int i = 0; 36 | do 37 | { 38 | bool c1 = e0.MoveNext(), c2 = e1.MoveNext(); 39 | if (c1 ^ c2) 40 | Assert.Fail("sets don't have the same size"); 41 | if (!c1) 42 | break; 43 | if (!comparison(e0.Current, e1.Current)) 44 | Assert.Fail("B[" + i + "]\n\tExpected: " + e0.Current + "\n\tBut was: " + e1.Current); 45 | } 46 | while (++i > 0); 47 | } 48 | 49 | public static void AreIdenticalSets(IEnumerable A, IEnumerable B, Func comparison) 50 | { 51 | IEnumerator e0 = A.GetEnumerator(); 52 | IEnumerator e1 = B.GetEnumerator(); 53 | int i = 0; 54 | do 55 | { 56 | bool c1 = e0.MoveNext(), c2 = e1.MoveNext(); 57 | if (c1 ^ c2) 58 | Assert.Fail("sets don't have the same size"); 59 | if (!c1) 60 | break; 61 | var a = e0.Current; 62 | var b = e1.Current; 63 | if (a.Length != b.Length) 64 | Assert.Fail("sets don't have the same size"); 65 | for (int j = 0; j < a.Length; j++) 66 | if (!comparison(a[j], b[j])) 67 | Assert.Fail("B[" + i + "][" + j + "]\n\tExpected: " + a[j] + "\n\tBut was: " + b[j]); 68 | } 69 | while (++i > 0); 70 | } 71 | 72 | public static void AreIdenticalFloatSets(IEnumerable A, IEnumerable B, int precision = -1) 73 | { 74 | AreIdenticalSets(A, B, (a, b) => FloatCompare(a, b, precision)); 75 | } 76 | 77 | public static void AreIdenticalFloatSets(IEnumerable A, IEnumerable B, int precision = -1) 78 | { 79 | AreIdenticalSets(A, B, (a, b) => FloatCompare(a, b, precision)); 80 | } 81 | 82 | } 83 | -------------------------------------------------------------------------------- /Assets/RoadGen/Scripts/Eppy/Tuple2.cs: -------------------------------------------------------------------------------- 1 | // ---------------------------------------------------------------------------- 2 | // Tuple structs for use in .NET Not-Quite-3.5 (e.g. Unity3D). 3 | // 4 | // Used Chapter 3 in http://functional-programming.net/ as a starting point. 5 | // 6 | // Note: .NET 4.0 Tuples are immutable classes so they're *slightly* different. 7 | // ---------------------------------------------------------------------------- 8 | 9 | using System; 10 | 11 | namespace RoadGen.Eppy 12 | { 13 | /// 14 | /// Represents a functional tuple that can be used to store 15 | /// two values of different types inside one object. 16 | /// 17 | /// The type of the first element 18 | /// The type of the second element 19 | public sealed class Tuple 20 | { 21 | private readonly T1 item1; 22 | private readonly T2 item2; 23 | 24 | /// 25 | /// Retyurns the first element of the tuple 26 | /// 27 | public T1 Item1 28 | { 29 | get { return item1; } 30 | } 31 | 32 | /// 33 | /// Returns the second element of the tuple 34 | /// 35 | public T2 Item2 36 | { 37 | get { return item2; } 38 | } 39 | 40 | /// 41 | /// Create a new tuple value 42 | /// 43 | /// First element of the tuple 44 | /// Second element of the tuple 45 | public Tuple(T1 item1, T2 item2) 46 | { 47 | this.item1 = item1; 48 | this.item2 = item2; 49 | } 50 | 51 | public override string ToString() 52 | { 53 | return string.Format("Tuple({0}, {1})", Item1, Item2); 54 | } 55 | 56 | public override int GetHashCode() 57 | { 58 | int hash = 17; 59 | hash = hash * 23 + (item1 == null ? 0 : item1.GetHashCode()); 60 | hash = hash * 23 + (item2 == null ? 0 : item2.GetHashCode()); 61 | return hash; 62 | } 63 | 64 | public override bool Equals(object o) 65 | { 66 | if (!(o is Tuple)) { 67 | return false; 68 | } 69 | 70 | var other = (Tuple) o; 71 | 72 | return this == other; 73 | } 74 | 75 | public bool Equals(Tuple other) 76 | { 77 | return this == other; 78 | } 79 | 80 | public static bool operator==(Tuple a, Tuple b) 81 | { 82 | if (object.ReferenceEquals(a, null)) 83 | { 84 | return object.ReferenceEquals(b, null); 85 | } 86 | if (object.ReferenceEquals(b, null)) 87 | { 88 | return false; 89 | } 90 | if (a.item1 == null && b.item1 != null) return false; 91 | if (a.item1 == null && b.item1 == null) return true; 92 | if (a.item2 == null && b.item2 != null) return false; 93 | if (a.item2 == null && b.item2 == null) return true; 94 | return 95 | a.item1.Equals(b.item1) && 96 | a.item2.Equals(b.item2); 97 | } 98 | 99 | public static bool operator!=(Tuple a, Tuple b) 100 | { 101 | return !(a == b); 102 | } 103 | 104 | public void Unpack(Action unpackerDelegate) 105 | { 106 | unpackerDelegate(Item1, Item2); 107 | } 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /Assets/RoadGen/Scripts/RoadNetworkMesh.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using UnityEngine.Rendering; 3 | using System.Collections.Generic; 4 | using RoadGen; 5 | 6 | public class RoadNetworkMesh : MonoBehaviour 7 | { 8 | public float zOffset = 1; 9 | public float lengthStep = 10; 10 | public Material roadSegmentsMaterial; 11 | public Material roadCrossingsMaterial; 12 | public RoadNetwork roadNetwork; 13 | public GameObject heightmapGameObject; 14 | 15 | void Start() 16 | { 17 | if (roadNetwork == null) 18 | { 19 | Debug.LogError("RoadNetworkMesh needs a reference to a RoadNetwork"); 20 | return; 21 | } 22 | 23 | if (!roadNetwork.Finished) 24 | { 25 | Debug.LogError("RoadNetworkMesh script can only execute after RoadNetwork (Configure execution order that in Edit > Project Settings > Script Execution Order)"); 26 | return; 27 | } 28 | 29 | IHeightmap heightmap = null; 30 | if (heightmapGameObject != null) 31 | heightmap = UnityEngineHelper.GetInterface(heightmapGameObject); 32 | 33 | if (heightmap == null) 34 | { 35 | Debug.LogError("RoadNetworkMesh needs a reference to a game object containing at least one component that implements IHeightmap"); 36 | return; 37 | } 38 | 39 | if (!heightmap.Finished()) 40 | { 41 | Debug.LogError("RoadNetworkMesh script can only execute after the components that implements IHeightmap (Configure execution order that in Edit > Project Settings > Script Execution Order)"); 42 | return; 43 | } 44 | 45 | var geometry = RoadNetworkGeometryBuilder.Build( 46 | 1.0f, 47 | Config.highwaySegmentWidth, 48 | Config.streetSegmentWidth, 49 | lengthStep, 50 | roadNetwork.Segments, 51 | roadNetwork.Mask 52 | ); 53 | 54 | GameObject roadGO = new GameObject("Road"); 55 | List vertices = new List(); 56 | geometry.GetSegmentPositions().ForEach((p) => 57 | { 58 | vertices.Add(new Vector3(p.x, heightmap.GetHeight(p.x, p.y) + zOffset, p.y)); 59 | }); 60 | Mesh mesh = new Mesh(); 61 | mesh.vertices = vertices.ToArray(); 62 | mesh.triangles = geometry.GetSegmentIndices().ToArray(); 63 | mesh.uv = geometry.GetSegmentUvs().ToArray(); 64 | mesh.RecalculateNormals(); 65 | GameObject segmentsGO = new GameObject("Segments"); 66 | segmentsGO.AddComponent().mesh = mesh; 67 | var meshRenderer = segmentsGO.AddComponent(); 68 | meshRenderer.material = roadSegmentsMaterial; 69 | meshRenderer.shadowCastingMode = ShadowCastingMode.Off; 70 | segmentsGO.transform.parent = roadGO.transform; 71 | vertices = new List(); 72 | geometry.GetCrossingPositions().ForEach((p) => 73 | { 74 | vertices.Add(new Vector3(p.x, heightmap.GetHeight(p.x, p.y) + zOffset, p.y)); 75 | }); 76 | mesh = new Mesh(); 77 | mesh.vertices = vertices.ToArray(); 78 | mesh.triangles = geometry.GetCrossingIndices().ToArray(); 79 | mesh.uv = geometry.GetCrossingUvs().ToArray(); 80 | mesh.RecalculateNormals(); 81 | GameObject crossingsGO = new GameObject("Crossings"); 82 | crossingsGO.AddComponent().mesh = mesh; 83 | meshRenderer = crossingsGO.AddComponent(); 84 | meshRenderer.material = roadCrossingsMaterial; 85 | meshRenderer.shadowCastingMode = ShadowCastingMode.Off; 86 | crossingsGO.transform.parent = roadGO.transform; 87 | roadGO.transform.parent = transform; 88 | } 89 | 90 | } 91 | -------------------------------------------------------------------------------- /Assets/RoadGen/Scripts/Allotment.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | 7 | namespace RoadGen 8 | { 9 | public class Allotment : ICollidable 10 | { 11 | private Vector2 center; 12 | private float direction; // in radians 13 | private float halfDiagonal; 14 | private float width; 15 | private float height; 16 | private float aspectRatio; 17 | private float aspectAngle; // in radians 18 | private RectangleCollider collider; 19 | 20 | public Allotment(Vector2 center, float direction /* in degrees */, float halfDiagonal, float aspectRatio = 1) 21 | { 22 | this.center = center; 23 | this.direction = direction * Mathf.Deg2Rad; 24 | this.halfDiagonal = halfDiagonal; 25 | aspectAngle = Mathf.Atan(aspectRatio); 26 | height = GetHeight(halfDiagonal, aspectRatio); 27 | width = height * aspectRatio; 28 | this.aspectRatio = aspectRatio; 29 | collider = new RectangleCollider(this, new Vector2[4]); 30 | UpdateCorners(); 31 | } 32 | 33 | public static float GetHeight(float halfDiagonal, float aspectRatio) 34 | { 35 | return halfDiagonal * 2.0f / Mathf.Sqrt(1.0f + aspectRatio * aspectRatio); 36 | } 37 | 38 | public static float GetWidth(float halfDiagonal, float aspectRatio) 39 | { 40 | return GetHeight(halfDiagonal, aspectRatio) * aspectRatio; 41 | } 42 | 43 | public float Width 44 | { 45 | get 46 | { 47 | return width; 48 | } 49 | } 50 | 51 | public float Height 52 | { 53 | get 54 | { 55 | return height; 56 | } 57 | } 58 | 59 | public float HalfDiagonal 60 | { 61 | get 62 | { 63 | return halfDiagonal; 64 | } 65 | } 66 | 67 | public float AspectRatio 68 | { 69 | get 70 | { 71 | return aspectRatio; 72 | } 73 | } 74 | 75 | private void UpdateCorners() 76 | { 77 | var corners = collider.Corners; 78 | RoadGen.Collision.SetCorners(corners, center, direction, halfDiagonal, aspectAngle); 79 | collider.Corners = corners; 80 | } 81 | 82 | public Collider GetCollider() 83 | { 84 | return collider; 85 | } 86 | 87 | public Vector2 Center 88 | { 89 | get 90 | { 91 | return center; 92 | } 93 | set 94 | { 95 | center = value; 96 | UpdateCorners(); 97 | } 98 | } 99 | 100 | public void UpdateCenterAndDirection(Vector2 center, float direction /* in degrees */) 101 | { 102 | this.center = center; 103 | this.direction = direction * Mathf.Deg2Rad; 104 | UpdateCorners(); 105 | } 106 | 107 | public void UpdateWidthAndHeight(float width, float height) 108 | { 109 | this.width = width; 110 | this.height = height; 111 | halfDiagonal = Mathf.Sqrt(width * width + height * height) * 0.5f; 112 | UpdateCorners(); 113 | } 114 | 115 | public Vector2[] Corners 116 | { 117 | get 118 | { 119 | return collider.Corners; 120 | } 121 | } 122 | 123 | public float Direction 124 | { 125 | get 126 | { 127 | return direction; 128 | } 129 | } 130 | 131 | } 132 | 133 | } 134 | -------------------------------------------------------------------------------- /Assets/RoadGen/Scripts/Eppy/Tuple3.cs: -------------------------------------------------------------------------------- 1 | // ---------------------------------------------------------------------------- 2 | // Tuple structs for use in .NET Not-Quite-3.5 (e.g. Unity3D). 3 | // 4 | // Used Chapter 3 in http://functional-programming.net/ as a starting point. 5 | // 6 | // Note: .NET 4.0 Tuples are immutable classes so they're *slightly* different. 7 | // ---------------------------------------------------------------------------- 8 | 9 | using System; 10 | 11 | namespace RoadGen.Eppy 12 | { 13 | /// 14 | /// Represents a functional tuple that can be used to store 15 | /// two values of different types inside one object. 16 | /// 17 | /// The type of the first element 18 | /// The type of the second element 19 | /// The type of the third element 20 | public sealed class Tuple 21 | { 22 | private readonly T1 item1; 23 | private readonly T2 item2; 24 | private readonly T3 item3; 25 | 26 | /// 27 | /// Retyurns the first element of the tuple 28 | /// 29 | public T1 Item1 30 | { 31 | get { return item1; } 32 | } 33 | 34 | /// 35 | /// Returns the second element of the tuple 36 | /// 37 | public T2 Item2 38 | { 39 | get { return item2; } 40 | } 41 | 42 | /// 43 | /// Returns the second element of the tuple 44 | /// 45 | public T3 Item3 46 | { 47 | get { return item3; } 48 | } 49 | 50 | /// 51 | /// Create a new tuple value 52 | /// 53 | /// First element of the tuple 54 | /// Second element of the tuple 55 | /// Third element of the tuple 56 | public Tuple(T1 item1, T2 item2, T3 item3) 57 | { 58 | this.item1 = item1; 59 | this.item2 = item2; 60 | this.item3 = item3; 61 | } 62 | 63 | public override string ToString() 64 | { 65 | return string.Format("Tuple({0}, {1}, {2})", Item1, Item2, Item3); 66 | } 67 | 68 | public override int GetHashCode() 69 | { 70 | int hash = 17; 71 | hash = hash * 23 + (item1 == null ? 0 : item1.GetHashCode()); 72 | hash = hash * 23 + (item2 == null ? 0 : item2.GetHashCode()); 73 | hash = hash * 23 + (item3 == null ? 0 : item3.GetHashCode()); 74 | return hash; 75 | } 76 | 77 | public override bool Equals(object o) 78 | { 79 | if (!(o is Tuple)) { 80 | return false; 81 | } 82 | 83 | var other = (Tuple)o; 84 | 85 | return this == other; 86 | } 87 | 88 | public static bool operator==(Tuple a, Tuple b) 89 | { 90 | if (object.ReferenceEquals(a, null)) { 91 | return object.ReferenceEquals(b, null); 92 | } 93 | if (a.item1 == null && b.item1 != null) return false; 94 | if (a.item2 == null && b.item2 != null) return false; 95 | if (a.item3 == null && b.item3 != null) return false; 96 | return 97 | a.item1.Equals(b.item1) && 98 | a.item2.Equals(b.item2) && 99 | a.item3.Equals(b.item3); 100 | } 101 | 102 | public static bool operator!=(Tuple a, Tuple b) 103 | { 104 | return !(a == b); 105 | } 106 | 107 | public void Unpack(Action unpackerDelegate) 108 | { 109 | unpackerDelegate(Item1, Item2, Item3); 110 | } 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /Assets/RoadGen/Scripts/RoadDensityMap.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using RoadGen; 3 | 4 | public class RoadDensityMap : MonoBehaviour, IMap 5 | { 6 | public float samplingStep = 10.0f; 7 | public int collisionMapDownscale = 5; 8 | public int collisionStrokeSize = 60; 9 | public int kernelSize = 9; 10 | public float gaussianWeight = 16; 11 | public RoadNetwork roadNetwork; 12 | public bool saveMapToFile = false; 13 | private int bbMinWX; 14 | private int bbMinWY; 15 | private int bbMaxWX; 16 | private int bbMaxWY; 17 | private int bbWidth; 18 | private int bbHeight; 19 | private int dScale; 20 | private int w2GX; 21 | private int w2GY; 22 | private float[,] roadDensityMap; 23 | private bool finished = false; 24 | 25 | bool WorldToMapCoords(float wX, float wY, out int mX, out int mY) 26 | { 27 | mX = Mathf.RoundToInt((w2GX + wX) / dScale); 28 | mY = Mathf.RoundToInt((w2GY + wY) / dScale); 29 | return true; 30 | } 31 | 32 | void Start() 33 | { 34 | if (roadNetwork == null) 35 | { 36 | Debug.LogError("RoadDensityMap needs a reference to a RoadNetwork"); 37 | return; 38 | } 39 | 40 | if (!roadNetwork.Finished) 41 | { 42 | Debug.LogError("RoadDensityMap script can only execute after RoadNetwork (Configure execution order that in Edit > Project Settings > Script Execution Order)"); 43 | return; 44 | } 45 | 46 | bbMinWX = Mathf.FloorToInt(roadNetwork.BoundingBox.xMin); 47 | bbMinWY = Mathf.FloorToInt(roadNetwork.BoundingBox.yMin); 48 | bbMaxWX = Mathf.CeilToInt(roadNetwork.BoundingBox.xMax); 49 | bbMaxWY = Mathf.CeilToInt(roadNetwork.BoundingBox.yMax); 50 | bbWidth = bbMaxWX - bbMinWX; 51 | bbHeight = bbMaxWY - bbMinWY; 52 | int cWX = bbMinWX + Mathf.CeilToInt(bbWidth * 0.5f); 53 | int cWY = bbMinWY + Mathf.CeilToInt(bbHeight * 0.5f); 54 | 55 | dScale = (int)Mathf.Pow(2, collisionMapDownscale); 56 | int gSide = Mathf.NextPowerOfTwo(Mathf.CeilToInt(Mathf.Max(bbWidth, bbHeight))) / dScale + 1; 57 | int hGSide = gSide / 2 + 1; 58 | w2GX = hGSide * dScale - cWX; 59 | w2GY = hGSide * dScale - cWY; 60 | 61 | roadDensityMap = new float[gSide, gSide]; 62 | RoadNetworkCollisionMap.Build(roadNetwork.Segments, 63 | roadNetwork.Mask, 64 | samplingStep, 65 | collisionStrokeSize, 66 | RoadNetworkCollisionMap.SquaredSmoothCircleBrush, 67 | gSide, 68 | WorldToMapCoords, 69 | roadDensityMap); 70 | 71 | RoadNetworkCollisionMap.Normalize(gSide, roadDensityMap); 72 | 73 | if (kernelSize > 0) 74 | { 75 | var gaussian = FilterHelper.CreateGaussianKernel(kernelSize, gaussianWeight); 76 | var dst = new float[gSide, gSide]; 77 | FilterHelper.Convolute(roadDensityMap, dst, gaussian, gSide, gSide, kernelSize); 78 | roadDensityMap = dst; 79 | } 80 | 81 | if (saveMapToFile) 82 | RoadNetworkCollisionMap.SaveMapToFile("road_density_map.png", roadDensityMap); 83 | 84 | finished = true; 85 | } 86 | 87 | public float GetNormalizedValue(float x, float y) 88 | { 89 | int mX, mY; 90 | if (!WorldToMapCoords(x, y, out mX, out mY)) 91 | return -1; 92 | return roadDensityMap[mX, mY]; 93 | } 94 | 95 | public float GetWidth() 96 | { 97 | return (float)bbWidth; 98 | } 99 | 100 | public float GetHeight() 101 | { 102 | return (float)bbHeight; 103 | } 104 | 105 | public float GetMinX() 106 | { 107 | return (float)bbMinWX; 108 | } 109 | 110 | public float GetMaxX() 111 | { 112 | return (float)bbMaxWX; 113 | } 114 | 115 | public float GetMinY() 116 | { 117 | return (float)bbMinWY; 118 | } 119 | 120 | public float GetMaxY() 121 | { 122 | return (float)bbMaxWY; 123 | } 124 | public bool Finished() 125 | { 126 | return finished; 127 | } 128 | 129 | } 130 | -------------------------------------------------------------------------------- /Assets/RoadGen/Scripts/RandomSettlementsSpawner.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System.Collections.Generic; 3 | using RoadGen; 4 | 5 | public class RandomSettlementsSpawner : MonoBehaviour 6 | { 7 | public RoadNetwork roadNetwork; 8 | public GameObject heightmapGameObject; 9 | public GameObject allotmentBuilderGameObject; 10 | private IHeightmap heightmap; 11 | 12 | public class Context 13 | { 14 | public List allotments; 15 | public Quadtree quadtree; 16 | 17 | public Context(Quadtree quadtree) 18 | { 19 | allotments = new List(); 20 | this.quadtree = quadtree; 21 | } 22 | 23 | } 24 | 25 | static bool SegmentVisitor(Segment s0, ref Context context, int counter, out int o_counter) 26 | { 27 | if (counter >= 0 && counter < Config.settlementSpawnDelay) 28 | { 29 | o_counter = counter + 1; 30 | return true; 31 | } 32 | float settlementProbability = (s0.Destinations.Count > 1) ? Config.settlementInCrossingProbability : Config.settlementInHighwayProbability; 33 | if (UnityEngine.Random.value >= settlementProbability) 34 | { 35 | o_counter = counter + 1; 36 | return true; 37 | } 38 | List newBuildings = new List(); 39 | SettlementSpawner.Spawn(s0, Config.settlementDensity, Config.settlementRadius, context.quadtree, ref newBuildings); 40 | foreach (var newBuilding in newBuildings) 41 | context.quadtree.Insert(newBuilding); 42 | context.allotments.AddRange(newBuildings); 43 | o_counter = 0; 44 | return true; 45 | } 46 | 47 | void Start() 48 | { 49 | if (roadNetwork == null) 50 | { 51 | Debug.LogError("RandomSettlementsSpawner needs a reference to a RoadNetwork"); 52 | return; 53 | } 54 | 55 | if (!roadNetwork.Finished) 56 | { 57 | Debug.LogError("RandomSettlementsSpawner script can only execute after RoadNetwork (Configure execution order that in Edit > Project Settings > Script Execution Order)"); 58 | return; 59 | } 60 | 61 | if (heightmapGameObject != null) 62 | heightmap = UnityEngineHelper.GetInterface(heightmapGameObject); 63 | 64 | if (heightmap == null) 65 | { 66 | Debug.LogError("RandomSettlementsSpawner needs a reference to a game object containing at least one component that implements IHeightmap"); 67 | return; 68 | } 69 | 70 | if (!heightmap.Finished()) 71 | { 72 | Debug.LogError("RandomSettlementsSpawner script can only execute after the components that implements IHeightmap (Configure execution order that in Edit > Project Settings > Script Execution Order)"); 73 | return; 74 | } 75 | 76 | List allotmentBuilders = null; 77 | if (allotmentBuilderGameObject != null) 78 | allotmentBuilders = UnityEngineHelper.GetInterfaces(allotmentBuilderGameObject); 79 | if (allotmentBuilders == null) 80 | { 81 | Debug.LogError("RoadDensitySettlementSpawner needs a reference to a game object containing at least one component that implements IAllotmentBuilder"); 82 | return; 83 | } 84 | 85 | Context context = new Context(roadNetwork.Quadtree); 86 | HashSet visited = new HashSet(); 87 | foreach (var segment in roadNetwork.Segments) 88 | RoadNetworkTraversal.PreOrder(segment, ref context, -1, SegmentVisitor, roadNetwork.Mask, ref visited); 89 | GameObject allotmentsGO = new GameObject("Allotments"); 90 | allotmentsGO.transform.parent = transform; 91 | foreach (var allotment in context.allotments) 92 | { 93 | foreach (var allotmentBuilder in allotmentBuilders) 94 | { 95 | GameObject allotmentGO = allotmentBuilder.Build(allotment, heightmap); 96 | allotmentGO.transform.parent = allotmentsGO.transform; 97 | } 98 | } 99 | Debug.Log(context.allotments.Count + " allotments spawned"); 100 | } 101 | 102 | } 103 | -------------------------------------------------------------------------------- /Assets/RoadGen/Scripts/MapMesh.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System; 3 | using RoadGen; 4 | 5 | public class MapMesh : MonoBehaviour 6 | { 7 | public float samplingScale = 0.01f; 8 | public float z = 0; 9 | public bool invertY = false; 10 | public bool invertX = false; 11 | public GameObject mapGameObject; 12 | // NOTE: heat map 13 | public Color[] colors = new Color[] { 14 | new Color(0, 0, 1, 0), // Blue. 15 | new Color(0, 1, 1, 0), // Cyan. 16 | new Color(0, 1, 0, 0), // Green. 17 | new Color(1, 1, 0, 0), // Yellow. 18 | new Color(1, 0, 0, 0) // Red. 19 | }; 20 | 21 | void Start() 22 | { 23 | IMap map = null; 24 | if (mapGameObject != null) 25 | map = UnityEngineHelper.GetInterface(mapGameObject); 26 | 27 | if (map == null) 28 | { 29 | Debug.LogError("MapMesh needs a reference to a game object containing at least one component that implements IMap"); 30 | return; 31 | } 32 | 33 | if (!map.Finished()) 34 | { 35 | Debug.LogError("MapMesh script can only execute after the component that implements IMap (Configure execution order that in Edit > Project Settings > Script Execution Order)"); 36 | return; 37 | } 38 | 39 | int width = Mathf.CeilToInt(map.GetWidth() * samplingScale), 40 | height = Mathf.CeilToInt(map.GetHeight() * samplingScale); 41 | Texture2D mapTexture = new Texture2D(width, height, TextureFormat.RGB24, true); 42 | Color[] pixels = new Color[width * height]; 43 | ColorGradient gradient = new ColorGradient(colors); 44 | int y = (invertY) ? height - 1 : 0; 45 | Func yCompare, xCompare; 46 | Func yMove, xMove; 47 | if (invertY) 48 | { 49 | yCompare = (a) => a >= 0; 50 | yMove = (a) => a - 1; 51 | } 52 | else 53 | { 54 | yCompare = (a) => a < height; 55 | yMove = (a) => a + 1; 56 | } 57 | if (invertX) 58 | { 59 | xCompare = (a) => a >= 0; 60 | xMove = (a) => a - 1; 61 | } 62 | else 63 | { 64 | xCompare = (a) => a < width; 65 | xMove = (a) => a + 1; 66 | } 67 | for (int p = 0; yCompare(y); y = yMove(y)) 68 | { 69 | float wY = y / samplingScale + map.GetMinY(); 70 | int x = (invertX) ? width - 1 : 0; 71 | for (; xCompare(x); x = xMove(x), p++) 72 | { 73 | float wX = x / samplingScale + map.GetMinX(); 74 | Color pixel = new Color(); 75 | gradient.GetColorAtValue(map.GetNormalizedValue(wX, wY), ref pixel); 76 | pixels[p] = pixel; 77 | } 78 | } 79 | mapTexture.SetPixels(pixels); 80 | mapTexture.Apply(true); 81 | GameObject mapGO = new GameObject("Map"); 82 | Mesh mesh = new Mesh(); 83 | mesh.vertices = new Vector3[] 84 | { 85 | new Vector3(map.GetMinX(), map.GetMaxY(), z), 86 | new Vector3(map.GetMaxX(), map.GetMaxY(), z), 87 | new Vector3(map.GetMaxX(), map.GetMinY(), z), 88 | new Vector3(map.GetMinX(), map.GetMinY(), z) 89 | }; 90 | mesh.triangles = new int[] 91 | { 92 | 0, 1, 2, 93 | 0, 2, 3 94 | }; 95 | mesh.uv = new Vector2[] 96 | { 97 | new Vector2(1, 1), 98 | new Vector2(0, 1), 99 | new Vector2(0, 0), 100 | new Vector2(1, 0) 101 | }; 102 | mesh.normals = new Vector3[] 103 | { 104 | Vector3.back, 105 | Vector3.back, 106 | Vector3.back, 107 | Vector3.back 108 | }; 109 | mapGO.AddComponent().mesh = mesh; 110 | Material material = new Material(Shader.Find("Unlit/Texture")); 111 | material.SetTexture("_MainTex", mapTexture); 112 | mapGO.AddComponent().material = material; 113 | mapGO.transform.parent = transform; 114 | mapGO.transform.localRotation = Quaternion.identity; 115 | } 116 | 117 | } 118 | -------------------------------------------------------------------------------- /Assets/RoadGen/Scripts/StandardGeometry.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | 3 | namespace RoadGen 4 | { 5 | public static class StandardGeometry 6 | { 7 | public static Mesh CreateCubeMesh(Vector2[] corners, float height = 1, float z = 0) 8 | { 9 | Mesh mesh = new Mesh(); 10 | mesh.vertices = new Vector3[] 11 | { 12 | // back 13 | new Vector3(corners[3].x, z + height, corners[3].y), 14 | new Vector3(corners[0].x, z + height, corners[0].y), 15 | new Vector3(corners[0].x, z, corners[0].y), 16 | new Vector3(corners[3].x, z, corners[3].y), 17 | 18 | // right 19 | new Vector3(corners[0].x, z + height, corners[0].y), 20 | new Vector3(corners[1].x, z + height, corners[1].y), 21 | new Vector3(corners[1].x, z, corners[1].y), 22 | new Vector3(corners[0].x, z, corners[0].y), 23 | 24 | // forward 25 | new Vector3(corners[1].x, z + height, corners[1].y), 26 | new Vector3(corners[2].x, z + height, corners[2].y), 27 | new Vector3(corners[2].x, z, corners[2].y), 28 | new Vector3(corners[1].x, z, corners[1].y), 29 | 30 | // left 31 | new Vector3(corners[2].x, z + height, corners[2].y), 32 | new Vector3(corners[3].x, z + height, corners[3].y), 33 | new Vector3(corners[3].x, z, corners[3].y), 34 | new Vector3(corners[2].x, z, corners[2].y), 35 | 36 | // up 37 | new Vector3(corners[2].x, z + height, corners[2].y), 38 | new Vector3(corners[1].x, z + height, corners[1].y), 39 | new Vector3(corners[0].x, z + height, corners[0].y), 40 | new Vector3(corners[3].x, z + height, corners[3].y), 41 | 42 | // down 43 | new Vector3(corners[1].x, z, corners[1].y), 44 | new Vector3(corners[2].x, z, corners[2].y), 45 | new Vector3(corners[3].x, z, corners[3].y), 46 | new Vector3(corners[0].x, z, corners[0].y) 47 | 48 | }; 49 | mesh.triangles = new int[] 50 | { 51 | 0, 1, 2, 52 | 0, 2, 3, 53 | 54 | 4, 5, 6, 55 | 4, 6, 7, 56 | 57 | 8, 9, 10, 58 | 8, 10, 11, 59 | 60 | 12, 13, 14, 61 | 12, 14, 15, 62 | 63 | 16, 17, 18, 64 | 16, 18, 19, 65 | 66 | 20, 21, 22, 67 | 20, 22, 23, 68 | 69 | }; 70 | mesh.uv = new Vector2[] 71 | { 72 | new Vector2(1, 1), 73 | new Vector2(0, 1), 74 | new Vector2(0, 0), 75 | new Vector2(1, 0), 76 | 77 | new Vector2(1, 1), 78 | new Vector2(0, 1), 79 | new Vector2(0, 0), 80 | new Vector2(1, 0), 81 | 82 | new Vector2(1, 1), 83 | new Vector2(0, 1), 84 | new Vector2(0, 0), 85 | new Vector2(1, 0), 86 | 87 | new Vector2(1, 1), 88 | new Vector2(0, 1), 89 | new Vector2(0, 0), 90 | new Vector2(1, 0), 91 | 92 | new Vector2(1, 1), 93 | new Vector2(0, 1), 94 | new Vector2(0, 0), 95 | new Vector2(1, 0), 96 | 97 | new Vector2(1, 1), 98 | new Vector2(0, 1), 99 | new Vector2(0, 0), 100 | new Vector2(1, 0) 101 | 102 | }; 103 | 104 | mesh.normals = new Vector3[] 105 | { 106 | Vector3.back, 107 | Vector3.back, 108 | Vector3.back, 109 | Vector3.back, 110 | 111 | Vector3.right, 112 | Vector3.right, 113 | Vector3.right, 114 | Vector3.right, 115 | 116 | Vector3.forward, 117 | Vector3.forward, 118 | Vector3.forward, 119 | Vector3.forward, 120 | 121 | Vector3.left, 122 | Vector3.left, 123 | Vector3.left, 124 | Vector3.left, 125 | 126 | Vector3.up, 127 | Vector3.up, 128 | Vector3.up, 129 | Vector3.up, 130 | 131 | Vector3.down, 132 | Vector3.down, 133 | Vector3.down, 134 | Vector3.down 135 | 136 | }; 137 | return mesh; 138 | } 139 | 140 | } 141 | 142 | } -------------------------------------------------------------------------------- /Assets/RoadGen/Scripts/Eppy/Tuple4.cs: -------------------------------------------------------------------------------- 1 | // ---------------------------------------------------------------------------- 2 | // Tuple structs for use in .NET Not-Quite-3.5 (e.g. Unity3D). 3 | // 4 | // Used Chapter 3 in http://functional-programming.net/ as a starting point. 5 | // 6 | // Note: .NET 4.0 Tuples are immutable classes so they're *slightly* different. 7 | // ---------------------------------------------------------------------------- 8 | 9 | using System; 10 | 11 | namespace RoadGen.Eppy 12 | { 13 | /// 14 | /// Represents a functional tuple that can be used to store 15 | /// two values of different types inside one object. 16 | /// 17 | /// The type of the first element 18 | /// The type of the second element 19 | /// The type of the third element 20 | /// The type of the fourth element 21 | public sealed class Tuple 22 | { 23 | private readonly T1 item1; 24 | private readonly T2 item2; 25 | private readonly T3 item3; 26 | private readonly T4 item4; 27 | 28 | /// 29 | /// Retyurns the first element of the tuple 30 | /// 31 | public T1 Item1 32 | { 33 | get { return item1; } 34 | } 35 | 36 | /// 37 | /// Returns the second element of the tuple 38 | /// 39 | public T2 Item2 40 | { 41 | get { return item2; } 42 | } 43 | 44 | /// 45 | /// Returns the second element of the tuple 46 | /// 47 | public T3 Item3 48 | { 49 | get { return item3; } 50 | } 51 | 52 | /// 53 | /// Returns the second element of the tuple 54 | /// 55 | public T4 Item4 56 | { 57 | get { return item4; } 58 | } 59 | 60 | /// 61 | /// Create a new tuple value 62 | /// 63 | /// First element of the tuple 64 | /// Second element of the tuple 65 | /// Third element of the tuple 66 | /// Fourth element of the tuple 67 | public Tuple(T1 item1, T2 item2, T3 item3, T4 item4) 68 | { 69 | this.item1 = item1; 70 | this.item2 = item2; 71 | this.item3 = item3; 72 | this.item4 = item4; 73 | } 74 | 75 | public override int GetHashCode() 76 | { 77 | int hash = 17; 78 | hash = hash * 23 + (item1 == null ? 0 : item1.GetHashCode()); 79 | hash = hash * 23 + (item2 == null ? 0 : item2.GetHashCode()); 80 | hash = hash * 23 + (item3 == null ? 0 : item3.GetHashCode()); 81 | hash = hash * 23 + (item4 == null ? 0 : item4.GetHashCode()); 82 | return hash; 83 | } 84 | 85 | public override bool Equals(object o) 86 | { 87 | if (o.GetType() != typeof(Tuple)) { 88 | return false; 89 | } 90 | 91 | var other = (Tuple)o; 92 | 93 | return this == other; 94 | } 95 | 96 | public static bool operator==(Tuple a, Tuple b) 97 | { 98 | if (object.ReferenceEquals(a, null)) { 99 | return object.ReferenceEquals(b, null); 100 | } 101 | if (a.item1 == null && b.item1 != null) return false; 102 | if (a.item2 == null && b.item2 != null) return false; 103 | if (a.item3 == null && b.item3 != null) return false; 104 | if (a.item4 == null && b.item4 != null) return false; 105 | return 106 | a.item1.Equals(b.item1) && 107 | a.item2.Equals(b.item2) && 108 | a.item3.Equals(b.item3) && 109 | a.item4.Equals(b.item4); 110 | } 111 | 112 | public static bool operator!=(Tuple a, Tuple b) 113 | { 114 | return !(a == b); 115 | } 116 | 117 | public void Unpack(Action unpackerDelegate) 118 | { 119 | unpackerDelegate(Item1, Item2, Item3, Item4); 120 | } 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /Assets/RoadGen/Scripts/RoadNetworkTraversal.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace RoadGen 4 | { 5 | public class RoadNetworkTraversal 6 | { 7 | public const int HIGHWAYS_MASK = 1; 8 | public const int STREETS_MASK = 2; 9 | 10 | public delegate bool Visitor0(Segment s0); 11 | public delegate bool Visitor1(Segment s0, Segment s1); 12 | public delegate bool Visitor2(Segment s0, ref T context); 13 | public delegate bool Visitor3(Segment s0, ref T context, U inData, out U outData); 14 | public delegate bool Visitor4(Segment s0, Segment s1, ref T context, U inData, out U outData); 15 | 16 | public static void PreOrder(Segment s0, Visitor0 visitor, int mask, ref HashSet visited) 17 | { 18 | if (s0.Highway && (mask & HIGHWAYS_MASK) == 0 || !s0.Highway && (mask & STREETS_MASK) == 0) 19 | return; 20 | if (visited.Contains(s0)) 21 | return; 22 | visited.Add(s0); 23 | if (!visitor(s0)) 24 | return; 25 | foreach (var destination in s0.Destinations) 26 | PreOrder(destination, visitor, mask, ref visited); 27 | } 28 | 29 | public static void PreOrder(Segment s0, Visitor1 visitor, int mask, ref HashSet visited) 30 | { 31 | PreOrder(null, s0, visitor, mask, ref visited); 32 | } 33 | 34 | public static void PreOrder(Segment s0, Segment s1, Visitor1 visitor, int mask, ref HashSet visited) 35 | { 36 | if (s1.Highway && (mask & HIGHWAYS_MASK) == 0 || !s1.Highway && (mask & STREETS_MASK) == 0) 37 | return; 38 | if (visited.Contains(s1)) 39 | return; 40 | visited.Add(s1); 41 | if (s1.Destinations.Count == 0) 42 | { 43 | if (!visitor(s1, null)) 44 | return; 45 | } 46 | else 47 | { 48 | if (!visitor(s0, s1)) 49 | return; 50 | foreach (var s2 in s1.Destinations) 51 | PreOrder(s1, s2, visitor, mask, ref visited); 52 | } 53 | } 54 | 55 | public static void PreOrder(Segment s0, ref T context, Visitor2 visitor, int mask, ref HashSet visited) 56 | { 57 | if (s0.Highway && (mask & HIGHWAYS_MASK) == 0 || !s0.Highway && (mask & STREETS_MASK) == 0) 58 | return; 59 | if (visited.Contains(s0)) 60 | return; 61 | visited.Add(s0); 62 | if (!visitor(s0, ref context)) 63 | return; 64 | foreach (var destination in s0.Destinations) 65 | PreOrder(destination, ref context, visitor, mask, ref visited); 66 | } 67 | 68 | public static void PreOrder(Segment s0, ref T context, U inData, Visitor3 visitor, int mask, ref HashSet visited) 69 | { 70 | if (s0.Highway && (mask & HIGHWAYS_MASK) == 0 || !s0.Highway && (mask & STREETS_MASK) == 0) 71 | return; 72 | if (visited.Contains(s0)) 73 | return; 74 | visited.Add(s0); 75 | U outData; 76 | if (!visitor(s0, ref context, inData, out outData)) 77 | return; 78 | foreach (var destination in s0.Destinations) 79 | PreOrder(destination, ref context, outData, visitor, mask, ref visited); 80 | } 81 | 82 | public static void PreOrder(Segment s0, ref T context, U inData, Visitor4 visitor, int mask, ref HashSet visited) 83 | { 84 | PreOrder(null, s0, ref context, inData, visitor, mask, ref visited); 85 | } 86 | 87 | public static void PreOrder(Segment s0, Segment s1, ref T context, U inData, Visitor4 visitor, int mask, ref HashSet visited) 88 | { 89 | if (s1.Highway && (mask & HIGHWAYS_MASK) == 0 || !s1.Highway && (mask & STREETS_MASK) == 0) 90 | return; 91 | if (visited.Contains(s1)) 92 | return; 93 | visited.Add(s1); 94 | U outData; 95 | if (s1.Destinations.Count == 0) 96 | { 97 | if (!visitor(s1, null, ref context, inData, out outData)) 98 | return; 99 | } 100 | else 101 | { 102 | if (!visitor(s0, s1, ref context, inData, out outData)) 103 | return; 104 | foreach (var s2 in s1.Destinations) 105 | PreOrder(s1, s2, ref context, outData, visitor, mask, ref visited); 106 | } 107 | } 108 | 109 | } 110 | 111 | } -------------------------------------------------------------------------------- /Assets/RoadGen/Scripts/Eppy/Tuple.cs: -------------------------------------------------------------------------------- 1 | // ---------------------------------------------------------------------------- 2 | // Tuple structs for use in .NET Not-Quite-3.5 (e.g. Unity3D). 3 | // 4 | // Used Chapter 3 in http://functional-programming.net/ as a starting point. 5 | // 6 | // Note: .NET 4.0 Tuples are immutable classes so they're *slightly* different. 7 | // ---------------------------------------------------------------------------- 8 | 9 | namespace RoadGen.Eppy 10 | { 11 | /// 12 | /// Utility class that simplifies cration of tuples by using 13 | /// method calls instead of constructor calls 14 | /// 15 | public static class Tuple 16 | { 17 | /// 18 | /// Creates a new tuple value with the specified elements. The method 19 | /// can be used without specifying the generic parameters, because C# 20 | /// compiler can usually infer the actual types. 21 | /// 22 | /// First element of the tuple 23 | /// Second element of the tuple 24 | /// A newly created tuple 25 | public static Tuple Create(T1 item1, T2 second) 26 | { 27 | return new Tuple(item1, second); 28 | } 29 | 30 | /// 31 | /// Creates a new tuple value with the specified elements. The method 32 | /// can be used without specifying the generic parameters, because C# 33 | /// compiler can usually infer the actual types. 34 | /// 35 | /// First element of the tuple 36 | /// Second element of the tuple 37 | /// Third element of the tuple 38 | /// A newly created tuple 39 | public static Tuple Create(T1 item1, T2 second, T3 third) 40 | { 41 | return new Tuple(item1, second, third); 42 | } 43 | 44 | /// 45 | /// Creates a new tuple value with the specified elements. The method 46 | /// can be used without specifying the generic parameters, because C# 47 | /// compiler can usually infer the actual types. 48 | /// 49 | /// First element of the tuple 50 | /// Second element of the tuple 51 | /// Third element of the tuple 52 | /// Fourth element of the tuple 53 | /// A newly created tuple 54 | public static Tuple Create(T1 item1, T2 second, T3 third, T4 fourth) 55 | { 56 | return new Tuple(item1, second, third, fourth); 57 | } 58 | 59 | 60 | /// 61 | /// Extension method that provides a concise utility for unpacking 62 | /// tuple components into specific out parameters. 63 | /// 64 | /// the tuple to unpack from 65 | /// the out parameter that will be assigned tuple.Item1 66 | /// the out parameter that will be assigned tuple.Item2 67 | public static void Unpack(this Tuple tuple, out T1 ref1, out T2 ref2) 68 | { 69 | ref1 = tuple.Item1; 70 | ref2 = tuple.Item2; 71 | } 72 | 73 | /// 74 | /// Extension method that provides a concise utility for unpacking 75 | /// tuple components into specific out parameters. 76 | /// 77 | /// the tuple to unpack from 78 | /// the out parameter that will be assigned tuple.Item1 79 | /// the out parameter that will be assigned tuple.Item2 80 | /// the out parameter that will be assigned tuple.Item3 81 | public static void Unpack(this Tuple tuple, out T1 ref1, out T2 ref2, T3 ref3) 82 | { 83 | ref1 = tuple.Item1; 84 | ref2 = tuple.Item2; 85 | ref3 = tuple.Item3; 86 | } 87 | 88 | /// 89 | /// Extension method that provides a concise utility for unpacking 90 | /// tuple components into specific out parameters. 91 | /// 92 | /// the tuple to unpack from 93 | /// the out parameter that will be assigned tuple.Item1 94 | /// the out parameter that will be assigned tuple.Item2 95 | /// the out parameter that will be assigned tuple.Item3 96 | /// the out parameter that will be assigned tuple.Item4 97 | public static void Unpack(this Tuple tuple, out T1 ref1, out T2 ref2, T3 ref3, T4 ref4) 98 | { 99 | ref1 = tuple.Item1; 100 | ref2 = tuple.Item2; 101 | ref3 = tuple.Item3; 102 | ref4 = tuple.Item4; 103 | } 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /Assets/RoadGen/Scripts/RoadNetwork.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System.Collections.Generic; 3 | using RoadGen; 4 | 5 | public class RoadNetwork : MonoBehaviour 6 | { 7 | // Config 8 | public Rect quadtreeParams = new Rect(-25000, -25000, 50000, 50000); 9 | public int quadtreeMaxObjects = 10; 10 | public int quadtreeMaxLevels = 10; 11 | public int segmentCountLimit = 400; 12 | public int derivationStepLimit = 400; 13 | public float streetSegmentLength = 50; 14 | public float highwaySegmentLength = 120; 15 | public float streetSegmentWidth = 30; 16 | public float highwaySegmentWidth = 30; 17 | public float streetBranchProbability = 0.1f; 18 | public float highwayBranchProbability = 0.025f; 19 | public float streetBranchPopulationThreshold = 0.1f; 20 | public float highwayBranchPopulationThreshold = 0.15f; 21 | public int streetBranchTimeDelayFromHighway = 5; 22 | public float minimumIntersectionDeviation = 30; 23 | public float snapDistance = 30; 24 | public float allotmentMinHalfDiagonal = 60; 25 | public float allotmentMaxHalfDiagonal = 80; 26 | public float allotmentMinAspect = 1; 27 | public float allotmentMaxAspect = 1.45f; 28 | public int allotmentPlacementLoopLimit = 3; 29 | public int settlementSpawnDelay = 10; 30 | public int settlementDensity = 40; 31 | public float settlementRadius = 400.0f; 32 | public float settlementInCrossingProbability = 0.9f; 33 | public float settlementInHighwayProbability = 0.1f; 34 | // Road network 35 | public bool generateHighways = true; 36 | public bool generateStreets = true; 37 | private List segments; 38 | private RoadGen.Quadtree quadtree; 39 | private int mask = 0; 40 | private bool finished = false; 41 | private Rect boundingBox; 42 | 43 | 44 | public List Segments 45 | { 46 | get 47 | { 48 | return segments; 49 | } 50 | } 51 | 52 | public RoadGen.Quadtree Quadtree 53 | { 54 | get 55 | { 56 | return quadtree; 57 | } 58 | } 59 | 60 | public Rect BoundingBox 61 | { 62 | get 63 | { 64 | return boundingBox; 65 | } 66 | } 67 | 68 | public int Mask 69 | { 70 | get 71 | { 72 | return mask; 73 | } 74 | } 75 | 76 | public bool Finished 77 | { 78 | get 79 | { 80 | return finished; 81 | } 82 | } 83 | 84 | void SetupConfig() 85 | { 86 | Config.QuadtreeParams = quadtreeParams; 87 | Config.quadtreeMaxObjects = quadtreeMaxObjects; 88 | Config.quadtreeMaxLevels = quadtreeMaxLevels; 89 | Config.segmentCountLimit = segmentCountLimit; 90 | Config.derivationStepLimit = derivationStepLimit; 91 | Config.streetSegmentLength = streetSegmentLength; 92 | Config.highwaySegmentLength = highwaySegmentLength; 93 | Config.streetSegmentWidth = streetSegmentWidth; 94 | Config.highwaySegmentWidth = highwaySegmentWidth; 95 | Config.streetBranchProbability = streetBranchProbability; 96 | Config.highwayBranchProbability = highwayBranchProbability; 97 | Config.streetBranchPopulationThreshold = streetBranchPopulationThreshold; 98 | Config.streetBranchDelayFromHighway = streetBranchTimeDelayFromHighway; 99 | Config.minIntersectionDeviation = minimumIntersectionDeviation; 100 | Config.snapDistance = snapDistance; 101 | Config.allotmentMinHalfDiagonal = allotmentMinHalfDiagonal; 102 | Config.allotmentMaxHalfDiagonal = allotmentMaxHalfDiagonal; 103 | Config.allotmentMinAspect = allotmentMinAspect; 104 | Config.allotmentMaxAspect = allotmentMaxAspect; 105 | Config.allotmentPlacementLoopLimit = allotmentPlacementLoopLimit; 106 | Config.settlementSpawnDelay = settlementSpawnDelay; 107 | Config.settlementDensity = settlementDensity; 108 | Config.settlementRadius = settlementRadius; 109 | Config.settlementInCrossingProbability = settlementInCrossingProbability; 110 | Config.settlementInHighwayProbability = settlementInHighwayProbability; 111 | } 112 | 113 | void Start() 114 | { 115 | SetupConfig(); 116 | 117 | // --- 118 | 119 | RoadNetworkGenerator.DebugData debugData; 120 | RoadNetworkGenerator.Generate(out segments, out quadtree, out debugData); 121 | 122 | Debug.Log(segments.Count + " segments"); 123 | 124 | // --- 125 | 126 | mask = ((generateHighways) ? RoadNetworkTraversal.HIGHWAYS_MASK : 0) | ((generateStreets) ? RoadNetworkTraversal.STREETS_MASK : 0); 127 | 128 | float minX = float.MaxValue, 129 | maxX = -float.MaxValue, 130 | minY = float.MaxValue, 131 | maxY = -float.MaxValue; 132 | HashSet visited = new HashSet(); 133 | foreach (var segment in segments) 134 | { 135 | RoadNetworkTraversal.PreOrder(segment, (a) => 136 | { 137 | minX = Mathf.Min(Mathf.Min(a.Start.x, a.End.x), minX); 138 | minY = Mathf.Min(Mathf.Min(a.Start.y, a.End.y), minY); 139 | maxX = Mathf.Max(Mathf.Max(a.Start.x, a.End.x), maxX); 140 | maxY = Mathf.Max(Mathf.Max(a.Start.y, a.End.y), maxY); 141 | return true; 142 | }, mask, ref visited); 143 | } 144 | Vector2 size = new Vector2(maxX - minX, maxY - minY); 145 | Vector2 center = new Vector2(minX, minY); 146 | boundingBox = new Rect(center, size); 147 | 148 | finished = true; 149 | } 150 | 151 | } 152 | -------------------------------------------------------------------------------- /Assets/RoadGen/Scripts/Quadtree.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System.Collections.Generic; 3 | 4 | namespace RoadGen 5 | { 6 | public class Quadtree 7 | { 8 | int maxObjects; 9 | int maxLevels; 10 | int level; 11 | Rect bounds; 12 | List objects; 13 | List nodes; 14 | 15 | public Quadtree(Rect bounds, int maxObjects = 10, int maxLevels = 4, int level = 0) 16 | { 17 | this.maxObjects = maxObjects; 18 | this.maxLevels = maxLevels; 19 | this.level = level; 20 | this.bounds = bounds; 21 | objects = new List(); 22 | nodes = new List(); 23 | } 24 | 25 | public void Split() 26 | { 27 | int nextLevel = level + 1, 28 | subWidth = Mathf.RoundToInt(bounds.width / 2), 29 | subHeight = Mathf.RoundToInt(bounds.height / 2), 30 | x = Mathf.RoundToInt(bounds.x), 31 | y = Mathf.RoundToInt(bounds.y); 32 | 33 | //top right node 34 | nodes.Add(new Quadtree(new Rect( 35 | x + subWidth, 36 | y, 37 | subWidth, 38 | subHeight), maxObjects, maxLevels, nextLevel)); 39 | 40 | //top left node 41 | nodes.Add(new Quadtree(new Rect( 42 | x, 43 | y, 44 | subWidth, 45 | subHeight), maxObjects, maxLevels, nextLevel)); 46 | 47 | //bottom left node 48 | nodes.Add(new Quadtree(new Rect( 49 | x, 50 | y + subHeight, 51 | subWidth, 52 | subHeight), maxObjects, maxLevels, nextLevel)); 53 | 54 | //bottom right node 55 | nodes.Add(new Quadtree(new Rect( 56 | x + subWidth, 57 | y + subHeight, 58 | subWidth, 59 | subHeight), maxObjects, maxLevels, nextLevel)); 60 | } 61 | 62 | public int GetIndex(AABB obj) 63 | { 64 | int index = -1; 65 | float verticalMidpoint = bounds.x + (bounds.width * 0.5f); 66 | float horizontalMidpoint = bounds.y + (bounds.height * 0.5f); 67 | // obj can completely fit within the top quadrants 68 | bool topQuadrant = (obj.y < horizontalMidpoint && obj.y + obj.height < horizontalMidpoint); 69 | // obj can completely fit within the bottom quadrants 70 | bool bottomQuadrant = (obj.y > horizontalMidpoint); 71 | // obj can completely fit within the left quadrants 72 | if (obj.x < verticalMidpoint && obj.x + obj.width < verticalMidpoint) 73 | { 74 | if (topQuadrant) 75 | index = 1; 76 | else if (bottomQuadrant) 77 | index = 2; 78 | } 79 | //obj can completely fit within the right quadrants 80 | else if (obj.x > verticalMidpoint) 81 | { 82 | if (topQuadrant) 83 | index = 0; 84 | else if (bottomQuadrant) 85 | index = 3; 86 | } 87 | return index; 88 | } 89 | 90 | public void Insert(ICollidable collidable) 91 | { 92 | Insert(collidable.GetCollider().GetAABB()); 93 | } 94 | 95 | public void Insert(AABB obj) 96 | { 97 | int i = 0, index; 98 | 99 | // if we have sub nodes, find in which to insert obj 100 | if (nodes.Count > 0) 101 | { 102 | index = GetIndex(obj); 103 | if (index != -1) 104 | { 105 | nodes[index].Insert(obj); 106 | return; 107 | } 108 | } 109 | 110 | objects.Add(obj); 111 | 112 | if (objects.Count > maxObjects && level < maxLevels) 113 | { 114 | // split if we don't already have sub nodes 115 | if (nodes.Count == 0) 116 | Split(); 117 | 118 | // add all objects to there corresponding sub nodes 119 | while (i < objects.Count) 120 | { 121 | index = GetIndex(objects[i]); 122 | if (index != -1) 123 | nodes[index].Insert(objects.Splice(i, 1)[0]); 124 | else 125 | i++; 126 | } 127 | } 128 | } 129 | 130 | public List Retrieve(ICollidable collidable) 131 | { 132 | return Retrieve(collidable.GetCollider().GetAABB()); 133 | } 134 | 135 | public List Retrieve(AABB obj) 136 | { 137 | int index = GetIndex(obj); 138 | List returnObjects = new List(objects); 139 | //if we have sub nodes... 140 | if (nodes.Count > 0) 141 | { 142 | // if obj fits into a sub node... 143 | if (index != -1) 144 | { 145 | returnObjects.AddRange(nodes[index].Retrieve(obj)); 146 | } 147 | // if obj does not fit into a sub node, check it against all sub nodes 148 | else 149 | { 150 | for (var i = 0; i < nodes.Count; i++) 151 | returnObjects.AddRange(nodes[i].Retrieve(obj)); 152 | } 153 | } 154 | return returnObjects; 155 | } 156 | 157 | public void Clear() 158 | { 159 | objects = new List(); 160 | for (var i = 0; i < nodes.Count; i++) 161 | { 162 | nodes[i].Clear(); 163 | } 164 | nodes = new List(); 165 | } 166 | 167 | } 168 | 169 | } 170 | 171 | -------------------------------------------------------------------------------- /Assets/RoadGen/Scripts/Perlin.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | 3 | namespace RoadGen 4 | { 5 | public class Perlin 6 | { 7 | private static readonly int[] p = { 151, 160, 137, 91, 90, 15, 8 | 131, 13, 201, 95, 96, 53, 194, 233, 7, 225, 140, 36, 103, 30, 69, 142, 8, 99, 37, 240, 21, 10, 23, 9 | 190, 6, 148, 247, 120, 234, 75, 0, 26, 197, 62, 94, 252, 219, 203, 117, 35, 11, 32, 57, 177, 33, 10 | 88, 237, 149, 56, 87, 174, 20, 125, 136, 171, 168, 68, 175, 74, 165, 71, 134, 139, 48, 27, 166, 11 | 77, 146, 158, 231, 83, 111, 229, 122, 60, 211, 133, 230, 220, 105, 92, 41, 55, 46, 245, 40, 244, 12 | 102, 143, 54, 65, 25, 63, 161, 1, 216, 80, 73, 209, 76, 132, 187, 208, 89, 18, 169, 200, 196, 13 | 135, 130, 116, 188, 159, 86, 164, 100, 109, 198, 173, 186, 3, 64, 52, 217, 226, 250, 124, 123, 14 | 5, 202, 38, 147, 118, 126, 255, 82, 85, 212, 207, 206, 59, 227, 47, 16, 58, 17, 182, 189, 28, 42, 15 | 223, 183, 170, 213, 119, 248, 152, 2, 44, 154, 163, 70, 221, 153, 101, 155, 167, 43, 172, 9, 16 | 129, 22, 39, 253, 19, 98, 108, 110, 79, 113, 224, 232, 178, 185, 112, 104, 218, 246, 97, 228, 17 | 251, 34, 242, 193, 238, 210, 144, 12, 191, 179, 162, 241, 81, 51, 145, 235, 249, 14, 239, 107, 18 | 49, 192, 214, 31, 181, 199, 106, 157, 184, 84, 204, 176, 115, 121, 50, 45, 127, 4, 150, 254, 19 | 138, 236, 205, 93, 222, 114, 67, 29, 24, 72, 243, 141, 128, 195, 78, 66, 215, 61, 156, 180 }; 20 | 21 | private static int[] perm = { 22 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 23 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 24 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 25 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 26 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 27 | 0,0,0,0,0,0,0,0,0,0,0,0 28 | }; 29 | 30 | private static Vector3[] gradP = new Vector3[512]; 31 | 32 | 33 | private static readonly Vector3[] grad3 = { new Vector3(1, 1, 0), new Vector3(-1, 1, 0), new Vector3(1, -1, 0), new Vector3(-1, -1, 0), 34 | new Vector3(1, 0, 1), new Vector3(-1, 0, 1), new Vector3(1, 0, -1), new Vector3(-1, 0, -1), 35 | new Vector3(0, 1, 1), new Vector3(0, -1, 1), new Vector3(0, 1, -1), new Vector3(0, -1, -1) }; 36 | 37 | // Skewing and unskewing factors for 2, 3, and 4 dimensions 38 | private static readonly float F2 = 0.5f * (Mathf.Sqrt(3) - 1); 39 | private static readonly float G2 = (3 - Mathf.Sqrt(3)) / 6.0f; 40 | 41 | public static void Seed(int seed) 42 | { 43 | if (seed > 0 && seed < 1) 44 | { 45 | // Scale the seed out 46 | seed *= 65536; 47 | } 48 | 49 | if (seed < 256) 50 | { 51 | seed |= seed << 8; 52 | } 53 | 54 | for (int i = 0; i < 256; i++) 55 | { 56 | int v; 57 | if ((i & 1) != 0) 58 | { 59 | v = p[i] ^ (seed & 255); 60 | } 61 | else { 62 | v = p[i] ^ ((seed >> 8) & 255); 63 | } 64 | 65 | perm[i] = perm[i + 256] = v; 66 | gradP[i] = gradP[i + 256] = grad3[v % 12]; 67 | } 68 | } 69 | 70 | public static float Simplex2(float xin, float yin) 71 | { 72 | float n0, n1, n2; // Noise contributions from the three corners 73 | // Skew the input space to determine which simplex cell we're in 74 | var s = (xin + yin) * F2; // Hairy factor for 2D 75 | var i = Mathf.FloorToInt(xin + s); 76 | var j = Mathf.FloorToInt(yin + s); 77 | var t = (i + j) * G2; 78 | var x0 = xin - i + t; // The x,y distances from the cell origin, unskewed. 79 | var y0 = yin - j + t; 80 | // For the 2D case, the simplex shape is an equilateral triangle. 81 | // Determine which simplex we are in. 82 | int i1, j1; // Offsets for second (middle) corner of simplex in (i,j) coords 83 | if (x0 > y0) 84 | { // lower triangle, XY order: (0,0)->(1,0)->(1,1) 85 | i1 = 1; j1 = 0; 86 | } 87 | else { // upper triangle, YX order: (0,0)->(0,1)->(1,1) 88 | i1 = 0; j1 = 1; 89 | } 90 | // A step of (1,0) in (i,j) means a step of (1-c,-c) in (x,y), and 91 | // a step of (0,1) in (i,j) means a step of (-c,1-c) in (x,y), where 92 | // c = (3-sqrt(3))/6 93 | var x1 = x0 - i1 + G2; // Offsets for middle corner in (x,y) unskewed coords 94 | var y1 = y0 - j1 + G2; 95 | var x2 = x0 - 1 + 2 * G2; // Offsets for last corner in (x,y) unskewed coords 96 | var y2 = y0 - 1 + 2 * G2; 97 | // Work out the hashed gradient indices of the three simplex corners 98 | i &= 255; 99 | j &= 255; 100 | var gi0 = gradP[i + perm[j]]; 101 | var gi1 = gradP[i + i1 + perm[j + j1]]; 102 | var gi2 = gradP[i + 1 + perm[j + 1]]; 103 | // Calculate the contribution from the three corners 104 | var t0 = 0.5f - x0 * x0 - y0 * y0; 105 | if (t0 < 0) 106 | { 107 | n0 = 0; 108 | } 109 | else { 110 | t0 *= t0; 111 | n0 = t0 * t0 * Vector3.Dot(gi0, new Vector3(x0, y0, 0)); // (x,y) of grad3 used for 2D gradient 112 | } 113 | var t1 = 0.5f - x1 * x1 - y1 * y1; 114 | if (t1 < 0) 115 | { 116 | n1 = 0; 117 | } 118 | else { 119 | t1 *= t1; 120 | n1 = t1 * t1 * Vector3.Dot(gi1, new Vector3(x1, y1, 0)); 121 | } 122 | var t2 = 0.5f - x2 * x2 - y2 * y2; 123 | if (t2 < 0) 124 | { 125 | n2 = 0; 126 | } 127 | else { 128 | t2 *= t2; 129 | n2 = t2 * t2 * Vector3.Dot(gi2, new Vector3(x2, y2, 0)); 130 | } 131 | // Add contributions from each corner to get the final noise value. 132 | // The result is scaled to return values in the interval [-1,1]. 133 | return 70 * (n0 + n1 + n2); 134 | } 135 | 136 | } 137 | 138 | } 139 | -------------------------------------------------------------------------------- /Assets/RoadGen/Scripts/InteractiveCityRenderer3D.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System.Collections.Generic; 3 | using RoadGen; 4 | 5 | public class InteractiveCityRenderer3D : MonoBehaviour 6 | { 7 | public float scale = 0.001f; 8 | public float z = 1; 9 | public float lengthStep = 1; 10 | public bool displayBuildings = true; 11 | public bool displayHighways = true; 12 | public bool displayStreets = true; 13 | public Material roadSegmentsMaterial; 14 | public Material roadCrossingsMaterial; 15 | public float iconSize = 0.333f; 16 | public Texture2D intersectionIcon; 17 | public Texture2D snapIcon; 18 | public Texture2D intersectionRadiusIcon; 19 | RoadNetworkGenerator.InteractiveGenerationContext context; 20 | List iconGOs; 21 | GameObject roadGO; 22 | int action; 23 | bool step; 24 | bool end; 25 | int speed; 26 | 27 | void CreateRoadMesh(IRoadNetworkGeometry roadGeometry) 28 | { 29 | Destroy(roadGO); 30 | roadGO = new GameObject("Road"); 31 | List vertices = new List(); 32 | roadGeometry.GetSegmentPositions().ForEach((p) => 33 | { 34 | vertices.Add(new Vector3(p.x, p.y, z)); 35 | }); 36 | Mesh mesh = new Mesh(); 37 | mesh.vertices = vertices.ToArray(); 38 | mesh.triangles = roadGeometry.GetSegmentIndices().ToArray(); 39 | mesh.uv = roadGeometry.GetSegmentUvs().ToArray(); 40 | mesh.RecalculateNormals(); 41 | GameObject segmentsGO = new GameObject("Segments"); 42 | segmentsGO.AddComponent().mesh = mesh; 43 | segmentsGO.AddComponent().material = roadSegmentsMaterial; 44 | segmentsGO.transform.parent = roadGO.transform; 45 | vertices = new List(); 46 | roadGeometry.GetCrossingPositions().ForEach((p) => 47 | { 48 | vertices.Add(new Vector3(p.x, p.y, z)); 49 | }); 50 | mesh = new Mesh(); 51 | mesh.vertices = vertices.ToArray(); 52 | mesh.triangles = roadGeometry.GetCrossingIndices().ToArray(); 53 | mesh.uv = roadGeometry.GetCrossingUvs().ToArray(); 54 | mesh.RecalculateNormals(); 55 | GameObject crossingsGO = new GameObject("Crossings"); 56 | crossingsGO.AddComponent().mesh = mesh; 57 | crossingsGO.AddComponent().material = roadCrossingsMaterial; 58 | crossingsGO.transform.parent = roadGO.transform; 59 | } 60 | 61 | void RemoveIcons() 62 | { 63 | foreach (var gameObject in iconGOs) 64 | Destroy(gameObject); 65 | iconGOs.Clear(); 66 | } 67 | 68 | static GameObject CreateIcon(Vector2 intersection, float iconSize, float scale, float z, Texture2D icon) 69 | { 70 | GameObject gameObject = new GameObject("Icon"); 71 | gameObject.AddComponent().mesh = CreateQuadMesh(intersection * scale, iconSize, iconSize, z - 1); 72 | Material material = new Material(Shader.Find("Unlit/Transparent")); 73 | material.SetTexture("_MainTex", icon); 74 | gameObject.AddComponent().material = material; 75 | return gameObject; 76 | } 77 | 78 | static Mesh CreateQuadMesh(Vector2 center, float width, float height, float z) 79 | { 80 | Mesh mesh = new Mesh(); 81 | float halfWidth = width * 0.5f, halfHeight = height * 0.5f; 82 | mesh.vertices = new Vector3[] 83 | { 84 | new Vector3(center.x - halfWidth, center.y - halfHeight, z), 85 | new Vector3(center.x - halfWidth, center.y + halfHeight, z), 86 | new Vector3(center.x + halfWidth, center.y + halfHeight, z), 87 | new Vector3(center.x + halfWidth, center.y - halfHeight, z) 88 | }; 89 | mesh.normals = new Vector3[] { Vector3.back, Vector3.back, Vector3.back, Vector3.back }; 90 | mesh.uv = new Vector2[] 91 | { 92 | new Vector2(0,0), 93 | new Vector2(0,1), 94 | new Vector2(1,1), 95 | new Vector2(1,0) 96 | }; 97 | mesh.triangles = new int[] { 0, 1, 2, 0, 2, 3 }; 98 | return mesh; 99 | } 100 | 101 | void Start() 102 | { 103 | context = RoadNetworkGenerator.BeginInteractiveGeneration(); 104 | iconGOs = new List(); 105 | action = 1; 106 | } 107 | 108 | void Update() 109 | { 110 | if (action == 0) 111 | return; 112 | 113 | if (action == 1) 114 | { 115 | if (!end) 116 | end = Input.GetKeyDown(KeyCode.F5); 117 | 118 | if (!step) 119 | step = Input.GetKeyDown(KeyCode.F10); 120 | 121 | if (!step && !end) 122 | return; 123 | 124 | if (end) 125 | { 126 | RoadNetworkGenerator.EndInteractiveGeneration(ref context); 127 | action = 0; 128 | } 129 | else 130 | { 131 | if (!RoadNetworkGenerator.InteractiveGenerationStep(speed, ref context)) 132 | action = 0; 133 | } 134 | 135 | // --- 136 | 137 | var roadGeometry = RoadNetworkGeometryBuilder.Build( 138 | scale, 139 | Config.highwaySegmentWidth * scale, 140 | Config.streetSegmentWidth * scale, 141 | lengthStep, 142 | context.segments, 143 | ((displayHighways) ? RoadNetworkTraversal.HIGHWAYS_MASK : 0) | ((displayStreets) ? RoadNetworkTraversal.STREETS_MASK : 0) 144 | ); 145 | CreateRoadMesh(roadGeometry); 146 | 147 | // --- 148 | 149 | RemoveIcons(); 150 | if (context.debugData.intersections.Count > 0 || 151 | context.debugData.snaps.Count > 0 || 152 | context.debugData.intersectionsRadius.Count > 0) 153 | { 154 | foreach (Vector2 intersection in context.debugData.intersections) 155 | iconGOs.Add(CreateIcon(intersection, iconSize, scale, z, intersectionIcon)); 156 | foreach (Vector2 snap in context.debugData.snaps) 157 | iconGOs.Add(CreateIcon(snap, iconSize, scale, z, snapIcon)); 158 | foreach (Vector2 intersectionRadius in context.debugData.intersectionsRadius) 159 | iconGOs.Add(CreateIcon(intersectionRadius, iconSize, scale, z, intersectionRadiusIcon)); 160 | context.debugData.intersections.Clear(); 161 | context.debugData.snaps.Clear(); 162 | context.debugData.intersectionsRadius.Clear(); 163 | } 164 | 165 | step = false; 166 | } 167 | } 168 | 169 | void OnGUI() 170 | { 171 | GUI.Label(new Rect(10, 10, 40, 20), "Speed"); 172 | if (!int.TryParse(GUI.TextField(new Rect(50, 10, 40, 20), speed + ""), out speed)) 173 | speed = 1; 174 | else 175 | speed = (int)Mathf.Max(1, speed); 176 | step = GUI.Button(new Rect(10, 40, 100, 20), "Step"); 177 | end = GUI.Button(new Rect(10, 70, 100, 20), "End"); 178 | GUI.Label(new Rect(10, 100, 200, 20), "Global Derivation Step: " + context.globalDerivationStep); 179 | if (GUI.Button(new Rect(10, 130, 140, 20), "Remove Icons")) 180 | RemoveIcons(); 181 | } 182 | 183 | } 184 | -------------------------------------------------------------------------------- /Assets/RoadGen/Scripts/InteractiveCityRenderer2D.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System.Collections.Generic; 3 | using RoadGen; 4 | 5 | public class InteractiveCityRenderer2D : MonoBehaviour 6 | { 7 | public Color highwayStartColor = Color.red; 8 | public Color highwayEndColor = Color.red; 9 | public Color streetStartColor = Color.gray; 10 | public Color streetEndColor = Color.gray; 11 | public Texture2D intersectionIcon; 12 | public Texture2D snapIcon; 13 | public Texture2D intersectionRadiusIcon; 14 | public float iconSize = 0.333f; 15 | public float highwayWidth = 0.05f; 16 | public float streetWidth = 0.025f; 17 | public float downscaleFactor = 1000.0f; 18 | public float z = 1; 19 | public bool displayBuildings = true; 20 | public bool displayHighways = true; 21 | public bool displayStreets = true; 22 | RoadNetworkGenerator.InteractiveGenerationContext context; 23 | HashSet visited; 24 | List segmentsGOs; 25 | List iconGOs; 26 | int mask; 27 | int action; 28 | bool step; 29 | bool end; 30 | int speed; 31 | 32 | bool Visitor(Segment segment) 33 | { 34 | GameObject segmentGO = new GameObject("Segment " + segment.Index); 35 | segmentGO.AddComponent().mesh = CreateLineMesh( 36 | segment.Start / downscaleFactor, 37 | segment.End / downscaleFactor, 38 | z, 39 | segment.Highway ? highwayStartColor : streetStartColor, 40 | segment.Highway ? highwayEndColor : streetEndColor, 41 | segment.Highway ? highwayWidth : streetWidth); 42 | segmentGO.AddComponent().material = new Material(Shader.Find("Custom/VertexColor")); 43 | segmentsGOs.Add(segmentGO); 44 | return true; 45 | } 46 | 47 | void Start() 48 | { 49 | context = RoadNetworkGenerator.BeginInteractiveGeneration(); 50 | visited = new HashSet(); 51 | mask = ((displayHighways) ? RoadNetworkTraversal.HIGHWAYS_MASK : 0) | ((displayStreets) ? RoadNetworkTraversal.STREETS_MASK : 0); 52 | segmentsGOs = new List(); 53 | iconGOs = new List(); 54 | action = 1; 55 | } 56 | 57 | void Update() 58 | { 59 | if (action == 0) 60 | return; 61 | 62 | if (action == 1) 63 | { 64 | if (!end) 65 | end = Input.GetKeyDown(KeyCode.F5); 66 | 67 | if (!step) 68 | step = Input.GetKeyDown(KeyCode.F10); 69 | 70 | if (!step && !end) 71 | return; 72 | 73 | if (end) 74 | { 75 | RoadNetworkGenerator.EndInteractiveGeneration(ref context); 76 | action = 0; 77 | } 78 | else 79 | { 80 | if (!RoadNetworkGenerator.InteractiveGenerationStep(speed, ref context)) 81 | action = 0; 82 | } 83 | 84 | foreach (Segment segment in context.segments) 85 | RoadNetworkTraversal.PreOrder(segment, Visitor, mask, ref visited); 86 | 87 | RemoveIcons(); 88 | if (context.debugData.intersections.Count > 0 || 89 | context.debugData.snaps.Count > 0 || 90 | context.debugData.intersectionsRadius.Count > 0) 91 | { 92 | foreach (Vector2 intersection in context.debugData.intersections) 93 | iconGOs.Add(CreateIcon(intersection, iconSize, downscaleFactor, z, intersectionIcon)); 94 | foreach (Vector2 snap in context.debugData.snaps) 95 | iconGOs.Add(CreateIcon(snap, iconSize, downscaleFactor, z, snapIcon)); 96 | foreach (Vector2 intersectionRadius in context.debugData.intersectionsRadius) 97 | iconGOs.Add(CreateIcon(intersectionRadius, iconSize, downscaleFactor, z, intersectionRadiusIcon)); 98 | context.debugData.intersections.Clear(); 99 | context.debugData.snaps.Clear(); 100 | context.debugData.intersectionsRadius.Clear(); 101 | } 102 | 103 | step = false; 104 | } 105 | } 106 | 107 | void OnGUI() 108 | { 109 | GUI.Label(new Rect(10, 10, 40, 20), "Speed"); 110 | if (!int.TryParse(GUI.TextField(new Rect(50, 10, 40, 20), speed + ""), out speed)) 111 | speed = 1; 112 | else 113 | speed = (int)Mathf.Max(1, speed); 114 | step = GUI.Button(new Rect(10, 40, 100, 20), "Step"); 115 | end = GUI.Button(new Rect(10, 70, 100, 20), "End"); 116 | GUI.Label(new Rect(10, 100, 200, 20), "Global Derivation Step: " + context.globalDerivationStep); 117 | if (GUI.Button(new Rect(10, 130, 140, 20), "Remove Icons")) 118 | RemoveIcons(); 119 | } 120 | 121 | static Mesh CreateLineMesh(Vector2 start, Vector2 end, float z, Color startColor, Color endColor, float width) 122 | { 123 | float halfWidth = width * 0.5f; 124 | Vector2 direction = end - start; 125 | Vector2 side = new Vector2(direction.y, -direction.x); 126 | side.Normalize(); 127 | side *= halfWidth; 128 | Vector2[] positions = new Vector2[4]; 129 | positions[0] = start - side; 130 | positions[1] = end - side; 131 | positions[2] = end + side; 132 | positions[3] = start + side; 133 | Mesh mesh = new Mesh(); 134 | Vector3[] vertices = new Vector3[4]; 135 | for (int i = 0; i < 4; i++) 136 | vertices[i] = new Vector3(positions[i].x, positions[i].y, z); 137 | mesh.vertices = vertices; 138 | mesh.normals = new Vector3[] { Vector3.back, Vector3.back, Vector3.back, Vector3.back }; 139 | mesh.colors = new Color[] { startColor, endColor, endColor, startColor }; 140 | mesh.triangles = new int[] { 0, 1, 2, 0, 2, 3 }; 141 | return mesh; 142 | } 143 | 144 | static Mesh CreateQuadMesh(Vector2 center, float width, float height, float z) 145 | { 146 | Mesh mesh = new Mesh(); 147 | float halfWidth = width * 0.5f, halfHeight = height * 0.5f; 148 | mesh.vertices = new Vector3[] 149 | { 150 | new Vector3(center.x - halfWidth, center.y - halfHeight, z), 151 | new Vector3(center.x - halfWidth, center.y + halfHeight, z), 152 | new Vector3(center.x + halfWidth, center.y + halfHeight, z), 153 | new Vector3(center.x + halfWidth, center.y - halfHeight, z) 154 | }; 155 | mesh.normals = new Vector3[] { Vector3.back, Vector3.back, Vector3.back, Vector3.back }; 156 | mesh.uv = new Vector2[] 157 | { 158 | new Vector2(0,0), 159 | new Vector2(0,1), 160 | new Vector2(1,1), 161 | new Vector2(1,0) 162 | }; 163 | mesh.triangles = new int[] { 0, 1, 2, 0, 2, 3 }; 164 | return mesh; 165 | } 166 | 167 | void RemoveIcons() 168 | { 169 | foreach (var gameObject in iconGOs) 170 | Destroy(gameObject); 171 | iconGOs.Clear(); 172 | } 173 | 174 | static GameObject CreateIcon(Vector2 intersection, float iconSize, float downscaleFactor, float z, Texture2D icon) 175 | { 176 | GameObject gameObject = new GameObject("Icon"); 177 | gameObject.AddComponent().mesh = CreateQuadMesh(intersection / downscaleFactor, iconSize, iconSize, z - 1); 178 | Material material = new Material(Shader.Find("Unlit/Transparent")); 179 | material.SetTexture("_MainTex", icon); 180 | gameObject.AddComponent().material = material; 181 | return gameObject; 182 | } 183 | 184 | } 185 | -------------------------------------------------------------------------------- /Assets/RoadGen/Scripts/Collider.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System.Linq; 3 | using System; 4 | 5 | namespace RoadGen 6 | { 7 | public abstract class Collider 8 | { 9 | protected int colliderRevision; 10 | private int aabbRevision; 11 | private AABB cachedAABB; 12 | protected object reference; 13 | 14 | protected Collider(object reference) 15 | { 16 | colliderRevision = 0; 17 | aabbRevision = -1; 18 | cachedAABB = null; 19 | this.reference = reference; 20 | } 21 | 22 | protected abstract AABB CreateAABB(); 23 | 24 | public AABB GetAABB() 25 | { 26 | if (aabbRevision != colliderRevision) 27 | { 28 | aabbRevision = colliderRevision; 29 | cachedAABB = CreateAABB(); 30 | } 31 | return cachedAABB; 32 | } 33 | 34 | public abstract bool Collide(Collider other, out Vector2 offset); 35 | 36 | } 37 | 38 | public class RectangleCollider : Collider 39 | { 40 | private Vector2[] corners; 41 | 42 | public RectangleCollider(object reference, Vector2[] corners) : base(reference) 43 | { 44 | this.corners = corners; 45 | } 46 | 47 | public Vector2[] Corners 48 | { 49 | get 50 | { 51 | return corners; 52 | } 53 | set 54 | { 55 | corners = value; 56 | colliderRevision++; 57 | } 58 | } 59 | 60 | protected override AABB CreateAABB() 61 | { 62 | float minX = corners.Min((c) => 63 | { 64 | return c.x; 65 | }); 66 | float minY = corners.Min((c) => 67 | { 68 | return c.y; 69 | }); 70 | return new AABB( 71 | minX, 72 | minY, 73 | corners.Max((c) => 74 | { 75 | return c.x - minX; 76 | }), 77 | corners.Max((c) => 78 | { 79 | return c.y - minY; 80 | }), 81 | reference 82 | ); 83 | } 84 | 85 | public override bool Collide(Collider other, out Vector2 offset) 86 | { 87 | offset = default(Vector2); 88 | 89 | if (other == null) 90 | return false; 91 | 92 | if (other is RectangleCollider) 93 | return Collision.RectangleRectangleIntersection(corners, ((RectangleCollider)other).corners, out offset); 94 | else if (other is LineCollider) 95 | { 96 | var lineCollider = (LineCollider)other; 97 | return Collision.RectangleRectangleIntersection(corners, Collision.GetCorners(lineCollider.Start, lineCollider.End, lineCollider.Width), out offset); 98 | } 99 | else if (other is CircleCollider) 100 | { 101 | var circleCollider = (CircleCollider)other; 102 | return Collision.RectangleCircleIntersection(corners, circleCollider.Center, circleCollider.Radius); 103 | } 104 | else 105 | throw new NotImplementedException(); 106 | } 107 | 108 | } 109 | 110 | public class LineCollider : Collider 111 | { 112 | private Vector2 start; 113 | private Vector2 end; 114 | private float width; 115 | 116 | public LineCollider(object reference, Vector2 start, Vector2 end, float width) : base(reference) 117 | { 118 | this.start = start; 119 | this.end = end; 120 | this.width = width; 121 | } 122 | 123 | public Vector2 Start 124 | { 125 | get 126 | { 127 | return start; 128 | } 129 | set 130 | { 131 | start = value; 132 | colliderRevision++; 133 | } 134 | } 135 | 136 | public Vector2 End 137 | { 138 | get 139 | { 140 | return end; 141 | } 142 | set 143 | { 144 | end = value; 145 | colliderRevision++; 146 | } 147 | } 148 | 149 | public float Width 150 | { 151 | get 152 | { 153 | return width; 154 | } 155 | set 156 | { 157 | width = value; 158 | colliderRevision++; 159 | } 160 | } 161 | 162 | protected override AABB CreateAABB() 163 | { 164 | return new AABB( 165 | Mathf.Min(start.x, end.x), 166 | Mathf.Min(start.y, end.y), 167 | Mathf.Abs(start.x - end.x), 168 | Mathf.Abs(start.y - end.y), 169 | reference 170 | ); 171 | } 172 | 173 | public override bool Collide(Collider other, out Vector2 offset) 174 | { 175 | offset = default(Vector2); 176 | 177 | if (other == null) 178 | return false; 179 | 180 | if (other is RectangleCollider) 181 | return Collision.RectangleRectangleIntersection(Collision.GetCorners(start, end, width), ((RectangleCollider)other).Corners, out offset); 182 | else if (other is LineCollider) 183 | { 184 | var lineCollider = (LineCollider)other; 185 | return Collision.RectangleRectangleIntersection(Collision.GetCorners(start, end, width), Collision.GetCorners(lineCollider.start, lineCollider.end, lineCollider.width), out offset); 186 | } 187 | else 188 | throw new NotImplementedException(); 189 | } 190 | 191 | } 192 | 193 | public class CircleCollider : Collider 194 | { 195 | private Vector2 center; 196 | private float radius; 197 | 198 | public CircleCollider(object reference, Vector2 center, float radius) : base(reference) 199 | { 200 | this.center = center; 201 | this.radius = radius; 202 | } 203 | 204 | public Vector2 Center 205 | { 206 | get 207 | { 208 | return center; 209 | } 210 | set 211 | { 212 | center = value; 213 | colliderRevision++; 214 | } 215 | } 216 | 217 | public float Radius 218 | { 219 | get 220 | { 221 | return radius; 222 | } 223 | set 224 | { 225 | radius = value; 226 | colliderRevision++; 227 | } 228 | } 229 | 230 | protected override AABB CreateAABB() 231 | { 232 | return new AABB( 233 | center.x - radius, 234 | center.y - radius, 235 | radius * 2, 236 | radius * 2, 237 | reference 238 | ); 239 | } 240 | 241 | public override bool Collide(Collider other, out Vector2 offset) 242 | { 243 | offset = default(Vector2); 244 | 245 | if (other == null) 246 | return false; 247 | 248 | if (other is RectangleCollider) 249 | return Collision.RectangleCircleIntersection(((RectangleCollider)other).Corners, center, radius); 250 | else 251 | throw new NotImplementedException(); 252 | } 253 | 254 | } 255 | 256 | } 257 | -------------------------------------------------------------------------------- /Assets/RoadGen/Scripts/Segment.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System; 3 | using System.Collections.Generic; 4 | 5 | namespace RoadGen 6 | { 7 | public class Segment : ICollidable 8 | { 9 | private int index; 10 | private int roadRevision; 11 | private int directionRevision; 12 | private int lengthRevision; 13 | private LineCollider collider; 14 | private float cachedDirection; 15 | private float cachedLength; 16 | private bool highway; 17 | private bool severed; 18 | private List sources; 19 | private List destinations; 20 | private List branches; 21 | private List forwards; 22 | private Action setupBranchLinksCallback; 23 | 24 | public Segment(Vector2 start, Vector2 end, bool highway = false, bool severed = false) 25 | { 26 | index = -1; 27 | roadRevision = 0; 28 | directionRevision = -1; 29 | lengthRevision = -1; 30 | cachedDirection = -1; 31 | cachedLength = -1; 32 | float width = highway ? Config.highwaySegmentWidth : Config.streetSegmentWidth; 33 | collider = new LineCollider(this, start, end, width); 34 | sources = new List(); 35 | destinations = new List(); 36 | branches = new List(); 37 | forwards = new List(); 38 | setupBranchLinksCallback = null; 39 | this.highway = highway; 40 | this.severed = severed; 41 | } 42 | 43 | private static Vector2 ComputeEnd(Vector2 start, float direction, float length) 44 | { 45 | return new Vector2( 46 | start.x + length * Mathf.Sin(direction * Mathf.Deg2Rad), 47 | start.y + length * Mathf.Cos(direction * Mathf.Deg2Rad) 48 | ); 49 | } 50 | 51 | public Segment(Segment other) : this(other.Start, other.End, other.highway, other.severed) 52 | { 53 | } 54 | 55 | public Segment(Vector2 start, float direction, float length, bool highway, bool severed) : this(start, ComputeEnd(start, direction, length), highway, severed) 56 | { 57 | } 58 | 59 | public int Index 60 | { 61 | get 62 | { 63 | return index; 64 | } 65 | set 66 | { 67 | index = value; 68 | } 69 | } 70 | 71 | public Vector2 Start 72 | { 73 | get 74 | { 75 | return collider.Start; 76 | } 77 | set 78 | { 79 | collider.Start = value; 80 | roadRevision++; 81 | } 82 | } 83 | 84 | public Vector2 End 85 | { 86 | get 87 | { 88 | return collider.End; 89 | } 90 | set 91 | { 92 | collider.End = value; 93 | roadRevision++; 94 | } 95 | } 96 | 97 | public float Width 98 | { 99 | get 100 | { 101 | return collider.Width; 102 | } 103 | set 104 | { 105 | collider.Width = value; 106 | roadRevision++; 107 | } 108 | } 109 | 110 | public Action SetupBranchLinksCallback 111 | { 112 | set 113 | { 114 | setupBranchLinksCallback = value; 115 | } 116 | } 117 | 118 | public List Sources 119 | { 120 | get 121 | { 122 | return sources; 123 | } 124 | set 125 | { 126 | sources = value; 127 | } 128 | } 129 | 130 | public List Destinations 131 | { 132 | get 133 | { 134 | return destinations; 135 | } 136 | set 137 | { 138 | destinations = value; 139 | } 140 | } 141 | 142 | public List Branches 143 | { 144 | get 145 | { 146 | return branches; 147 | } 148 | set 149 | { 150 | branches = value; 151 | } 152 | } 153 | 154 | public List Forwards 155 | { 156 | get 157 | { 158 | return forwards; 159 | } 160 | set 161 | { 162 | forwards = value; 163 | } 164 | } 165 | 166 | public bool Highway 167 | { 168 | get 169 | { 170 | return highway; 171 | } 172 | } 173 | 174 | public bool Severed 175 | { 176 | get 177 | { 178 | return severed; 179 | } 180 | set 181 | { 182 | severed = value; 183 | } 184 | } 185 | 186 | public float Direction 187 | { 188 | get 189 | { 190 | Vector2 direction; 191 | if (directionRevision != roadRevision) 192 | { 193 | directionRevision = roadRevision; 194 | direction = (End - Start); 195 | if (Length == 0) 196 | cachedDirection = 0; 197 | else 198 | cachedDirection = Mathf.Sign(direction.x) * Mathf.Acos(direction.y / Length) * Mathf.Rad2Deg; 199 | } 200 | return cachedDirection; 201 | } 202 | } 203 | 204 | public float Length 205 | { 206 | get 207 | { 208 | if (lengthRevision != roadRevision) 209 | { 210 | lengthRevision = roadRevision; 211 | cachedLength = (End - Start).magnitude; 212 | } 213 | return cachedLength; 214 | } 215 | } 216 | 217 | public void SetupBranchLinks() 218 | { 219 | if (setupBranchLinksCallback != null) 220 | setupBranchLinksCallback(); 221 | } 222 | 223 | public List LinksForEndContaining(Segment segment) 224 | { 225 | if (branches.IndexOf(segment) != -1) 226 | return branches; 227 | else if (forwards.IndexOf(segment) != -1) 228 | return forwards; 229 | else 230 | return null; 231 | } 232 | 233 | public bool StartIsBackwards() 234 | { 235 | if (branches.Count > 0) 236 | return (branches[0].Start == Start) || (branches[0].Start == End); 237 | else if (forwards.Count > 0) 238 | return (forwards[0].Start == End) || (forwards[0].End == End); 239 | else 240 | return false; 241 | } 242 | 243 | public bool Intersect(Segment other, out Vector2 intersection, out float t) 244 | { 245 | return Collision.LineSegmentLineSegmentIntersection(Start, End, other.Start, other.End, out intersection, out t); 246 | } 247 | 248 | public Collider GetCollider() 249 | { 250 | return collider; 251 | } 252 | 253 | public override int GetHashCode() 254 | { 255 | return index.GetHashCode(); 256 | } 257 | 258 | public override bool Equals(object obj) 259 | { 260 | if (obj != null && obj is Segment) 261 | return index == ((Segment)obj).index; 262 | return false; 263 | } 264 | 265 | } 266 | 267 | } 268 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | roadgen 2 | ======= 3 | 4 | This is a road network generation tool based on [Müller et al.](https://github.com/pboechat/roadgen/blob/master/%282001%29%20Procedural%20Modeling%20of%20Cities.pdf). The basic idea is to extend L-Systems to support intersection and snapping (self-sensitivity) and be guided by image maps (population density). 5 | 6 | It features: 7 | 8 | - road network generation/manipulation 9 | - basic road network geometry construction 10 | - basic building allotment distribution 11 | 12 | 13 | ---------- 14 | #### Getting Started 15 | 16 | 1. Add RoadNetwork to a game object in your scene an set generation parameters (e.g., street segment length) 17 | 2. Add MockTerrain (or your own ITerrain implementation) 18 | 3. [Optional] Add DummyAllotmentBuilder and RoadDensityMap. RoadDensityMap requires that you reference RoadNetwork. 19 | 5. Add RoadDensityBasedSettlementSpawner (or your own settlement spawner implementation) and reference DummyAllotmentBuilder (or your own IAllotmentBuilder implementation) and RoadDensityMap 20 | 6. Add RoadNetworkMesh and set materials (road segments and crossing), mesh detail (e.g., length step) and reference to RoadNetwork and terrain 21 | 22 | ![Example](http://pedroboechat.com/images/roadgen.png) 23 | 24 | ##### Generation Parameters 25 | 26 | ![Generation Parameters](http://pedroboechat.com/images/roadgen-RoadNetwork.png) 27 | 28 | - _Quadtree Params_: The min. coordinates and size of the quatree (in world units) in which the road segments are put to optimize collision detections. 29 | 30 | - _Quadtree Max Objects/Levels_: Some other control parameters for the quadtree (max. number of items per quadrant and max. number of quadtree levels). 31 | 32 | - _Segment Count Limit_: Each road segment expands forward or spawns child road segments (branch) at each derivation step. This parameter controls the maximum amount of expansions a road segment can have. 33 | 34 | - _Derivation Step Limit_: Each derivation step is an opportunity for an existing road segments to expand or branch. This parameter controls the number of derivation steps. 35 | 36 | - _Street/Highway Segment Length/Width_: Road segments can be streets or highways. This parameter controls their width/length (in world units). 37 | 38 | - _Street/Highway Branch Probability_: This parameter is the normalized (0-1) probability of a road segment spawning another road segment. 39 | 40 | - _Street/Highway Branch Population_: **TODO** 41 | 42 | - _Street Branch Time Delay_: Number of derivation steps until the probability for streets to branch is evaluated. 43 | 44 | - _Minimum Intersection_ = **TODO** 45 | 46 | - _Snap Distance_: Road segments "snap" to each other in order to form network-like structures. This is the maximum distance (in world units) that a road segment can have from another until it's snapped. 47 | 48 | - _Allotment Min/Max Half Diagonal_: Building allotments are placed alongside road segments at a certain derivation interval. This is the min./max. diagonal size (in world units) of an allotment. 49 | 50 | - _Allotment Min/Max Aspect_: Once the diagonal size is sorted, the aspect length is sorted too. With the diagonal and aspect, we can define width and height. This controls the aspect (width / height) of the allotments. 51 | 52 | - _Allotment Placement Loop_: **TODO** 53 | 54 | - _Settlement Spawn Delay_: A settlement is a region where building allotments are placed. This parameter controls how many derivation steps needs to pass until a settlement can be randomly sorted. 55 | 56 | - _Settlement Radius_: This parameter controls the size of settlement from the point they started (in world units). 57 | 58 | - _Settlement Crossing/Highway Probabilities_: This parameter is the normalized (0-1) probability of a road segment that is either a highway or is in a crossing (i.e., has 2 orthogonal road segments connected to it) spawning a settlement. 59 | 60 | - _Generate Highways/Streets_: Enable/disable the generation of highways/streets. 61 | 62 | 63 | ##### Script Execution Order 64 | 65 | ![Script Execution Order](http://pedroboechat.com/images/roadgen-ScriptExecutionOrder.png) 66 | 67 | ##### (Pseudo-)Randomness 68 | 69 | Add GlobalSeeder to a game object in your scene to control pseudo-random number generation. 70 | 71 | ![Global Seeder](http://pedroboechat.com/images/roadgen-GlobalSeeder.png) 72 | 73 | 74 | ---------- 75 | #### Advanced Usage 76 | 77 | ##### Road Network Generation 78 | 79 | using System.Collections.Generic; 80 | using RoadGen; 81 | 82 | (...) 83 | 84 | List segments; 85 | Quadtree quadtree; 86 | RoadNetworkGenerator.DebugData debugData; 87 | 88 | RoadNetworkGenerator.Generate(out segments, out quadtree, out debugData); 89 | 90 | ##### Road Network Traversal 91 | 92 | ###### Standard segment visitor 93 | 94 | using System.Collections.Generic; 95 | using RoadGen; 96 | 97 | (...) 98 | 99 | HashSet visited = new HashSet(); 100 | foreach (var segment in segments) 101 | { 102 | RoadNetworkTraversal.PreOrder(segment, (a) => 103 | { 104 | // my visitation logic 105 | return true; 106 | }, 107 | mask, 108 | ref visited); 109 | } 110 | 111 | ###### Segment visitor w/ per-traversal parameter (Context) 112 | 113 | using System.Collections.Generic; 114 | using RoadGen; 115 | 116 | (...) 117 | 118 | struct MyContext 119 | { 120 | // my data 121 | } 122 | 123 | (...) 124 | 125 | bool MyVisitor(Segment segment, ref MyContext myContext) 126 | { 127 | // my visitation logic 128 | return true; 129 | } 130 | 131 | (...) 132 | 133 | HashSet visited = new HashSet(); 134 | MyContext myContext; 135 | foreach (var segment in roadNetwork.Segments) 136 | { 137 | RoadNetworkTraversal.PreOrder(segment, 138 | ref myContext, 139 | MyVisitor, 140 | RoadNetworkTraversal.HIGHWAYS_MASK | RoadNetworkTraversal.STREETS_MASK, 141 | ref visited); 142 | } 143 | 144 | ###### Segment visitor w/ per-segment parameter (User Data) 145 | 146 | using System.Collections.Generic; 147 | using RoadGen; 148 | 149 | (...) 150 | 151 | struct MyContext 152 | { 153 | // my context data 154 | } 155 | 156 | struct MyUserData 157 | { 158 | // my user data 159 | } 160 | 161 | (...) 162 | 163 | bool MyVisitor(Segment segment, ref MyContext myContext, MyUserData i_myUserData, out MyUserData o_myUserData) 164 | { 165 | o_myUserData = new MyUserData(); 166 | // my visitation logic 167 | return true; 168 | } 169 | 170 | (...) 171 | 172 | HashSet visited = new HashSet(); 173 | MyContext myContext; 174 | MyUserData myUserData; 175 | foreach (var segment in roadNetwork.Segments) 176 | { 177 | RoadNetworkTraversal.PreOrder(segment, 178 | ref myContext, 179 | myUserData, 180 | MyVisitor, 181 | RoadNetworkTraversal.HIGHWAYS_MASK | RoadNetworkTraversal.STREETS_MASK, 182 | ref visited); 183 | } 184 | 185 | ##### Road Network Geometry Construction 186 | 187 | using UnityEngine; 188 | using System.Collections.Generic; 189 | using System.Linq; 190 | using RoadGen; 191 | 192 | (...) 193 | 194 | var geometry = RoadNetworkGeometryBuilder.Build( 195 | scale, 196 | Config.highwaySegmentWidth, 197 | Config.streetSegmentWidth, 198 | lengthStep, 199 | segments, 200 | RoadNetworkTraversal.HIGHWAYS_MASK | RoadNetworkTraversal.STREETS_MASK 201 | ); 202 | 203 | List vertices = new List(); 204 | geometry.GetSegmentPositions().ForEach((p) => 205 | { 206 | vertices.Add(new Vector3(p.x, heightmap.GetHeight(p.x, p.y), p.y)); 207 | }); 208 | 209 | geometry.GetCrossingPositions().ForEach((p) => 210 | { 211 | vertices.Add(new Vector3(p.x, heightmap.GetHeight(p.x, p.y), p.y)); 212 | }); 213 | 214 | Mesh mesh = new Mesh(); 215 | mesh.vertices = vertices.ToArray(); 216 | mesh.triangles = geometry.GetCrossingIndices().ToArray(); 217 | mesh.uv = geometry.GetCrossingUvs().ToArray(); 218 | mesh.RecalculateNormals(); 219 | 220 | ##### Custom Heightmap 221 | 222 | Extend RoadGen.IHeightmap and implement: 223 | 224 | float GetHeight(float x, float y); 225 | 226 | bool Finished(); 227 | 228 | ##### Custom Allotment Builder 229 | 230 | Extend RoadGen.IAllotmentBuilder and implement: 231 | 232 | GameObject Build(Allotment allotment, IHeightmap heightmap); 233 | -------------------------------------------------------------------------------- /Assets/RoadGen/Scripts/Collision.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System.Collections.Generic; 3 | 4 | namespace RoadGen 5 | { 6 | public static class Collision 7 | { 8 | public static readonly float EPSILON = 0.001f; 9 | 10 | public static void ArmPoints(Vector2 a, Vector2 b, Vector2 c, float width, out Vector2 elbow, out Vector2 joint) 11 | { 12 | var a0 = (a - b).normalized; 13 | var a1 = (c - b).normalized; 14 | float r = 0.5f * width; 15 | float dot = Vector2.Dot(a0, a1); 16 | if (Mathf.Abs(dot) < (1.0f - RoadGen.Collision.EPSILON)) 17 | { 18 | Vector2 i; 19 | LineLineIntersection(new Vector3(-a0.y, a0.x, r), new Vector3(-a1.y, a1.x, -r), out i); 20 | elbow = (b + i); // left 21 | LineLineIntersection(new Vector3(-a0.y, a0.x, -r), new Vector3(-a1.y, a1.x, r), out i); 22 | joint = (b + i); // right 23 | } 24 | else 25 | { 26 | Vector2 n; 27 | if (dot > RoadGen.Collision.EPSILON) 28 | { 29 | n = (new Vector2(-a0.y - a1.y, a0.x + a1.x)).normalized; 30 | elbow = (b + (-r * n)); // left 31 | joint = (b + (r * n)); // right 32 | } 33 | else 34 | { 35 | n = (new Vector2(-a0.y + a1.y, a0.x - a1.x)).normalized; 36 | elbow = (b + (-r * n)); // left 37 | joint = (b + (r * n)); // right 38 | } 39 | } 40 | } 41 | 42 | public static bool RectangleCircleIntersection(Vector2[] corners, Vector2 center, float radius) 43 | { 44 | float r2 = radius * radius; 45 | for (int i = 0; i < corners.Length; i++) 46 | { 47 | if (Vector2.SqrMagnitude(center - corners[i]) <= (r2)) 48 | return true; 49 | } 50 | Vector2 e0, e1, p0; 51 | for (int i = 0; i < corners.Length; i++) 52 | { 53 | Vector2 start = corners[i]; 54 | Vector2 end = corners[(i + 1) % corners.Length]; 55 | e0 = (center - start); 56 | e1 = (end - start); 57 | p0 = Vector3.Project(e0, e1); 58 | float d2 = Vector2.SqrMagnitude(center - (start + p0)); 59 | float pl0 = Mathf.Sign(Vector3.Dot(e0, e1)) * Vector2.SqrMagnitude(p0); 60 | float l2 = Vector2.SqrMagnitude(e1); 61 | if (pl0 > 0 && pl0 < l2 && d2 <= r2) 62 | return true; 63 | } 64 | Vector2 a0 = corners[3] - corners[0], 65 | a1 = corners[3] - corners[2]; 66 | e0 = center - corners[0]; 67 | e1 = center - corners[2]; 68 | p0 = Vector3.Project(e0, a0); 69 | Vector2 p1 = Vector3.Project(e1, a1); 70 | if (Vector2.Dot(e0, a0) < 0 || 71 | Vector2.SqrMagnitude(p0) > Vector2.SqrMagnitude(a0) || 72 | Vector2.Dot(e1, a1) < 0 || 73 | Vector2.SqrMagnitude(p1) > Vector2.SqrMagnitude(a1)) 74 | return false; 75 | return true; 76 | } 77 | 78 | public static Vector2[] GetCorners(Vector2 start, Vector2 end, float width) 79 | { 80 | Vector2 direction = (end - start); 81 | Vector2 perpDir = new Vector2( 82 | -direction.y, 83 | direction.x 84 | ); 85 | Vector2 halfWidthPerpDir = perpDir * (0.5f * width / perpDir.magnitude); 86 | return new Vector2[] 87 | { 88 | (start + halfWidthPerpDir), 89 | (start - halfWidthPerpDir), 90 | (end - halfWidthPerpDir), 91 | (end + halfWidthPerpDir) 92 | }; 93 | } 94 | 95 | public static void SetCorners(Vector2[] corners, Vector2 center, float direction /* in radians */, float halfDiagonal, float aspectAngle = 0.785398163f /* in radians */) 96 | { 97 | float a0 = (aspectAngle + direction), 98 | a1 = (direction - aspectAngle); 99 | corners[0].x = center.x + halfDiagonal * Mathf.Sin(a0); 100 | corners[0].y = center.y + halfDiagonal * Mathf.Cos(a0); 101 | corners[1].x = center.x + halfDiagonal * Mathf.Sin(a1); 102 | corners[1].y = center.y + halfDiagonal * Mathf.Cos(a1); 103 | corners[2].x = center.x + halfDiagonal * Mathf.Sin(Mathf.PI + a0); 104 | corners[2].y = center.y + halfDiagonal * Mathf.Cos(Mathf.PI + a0); 105 | corners[3].x = center.x + halfDiagonal * Mathf.Sin(Mathf.PI + a1); 106 | corners[3].y = center.y + halfDiagonal * Mathf.Cos(Mathf.PI + a1); 107 | } 108 | 109 | 110 | public static bool RectangleRectangleIntersection(Vector2[] corners0, Vector2[] corners1, out Vector2 offset) 111 | { 112 | Vector2[] axes = new Vector2[] { (corners0[3] - corners0[0]), 113 | (corners0[3] - corners0[2]), 114 | (corners1[0] - corners1[1]), 115 | (corners1[0] - corners1[3]) }; 116 | List axisOverlaps = new List(4); 117 | offset = default(Vector2); 118 | int i; 119 | for (i = 0; i < 4; i++) 120 | { 121 | Vector2 axis = axes[i]; 122 | List projectedVectorsA = new List(4); 123 | List projectedVectorsB = new List(4); 124 | foreach (var corner in corners0) 125 | projectedVectorsA.Add(Vector3.Project(corner, axis)); 126 | foreach (var corner in corners1) 127 | projectedVectorsB.Add(Vector3.Project(corner, axis)); 128 | List positionsOnAxisA = new List(); 129 | List positionsOnAxisB = new List(); 130 | foreach (var v in projectedVectorsA) 131 | positionsOnAxisA.Add(Vector2.Dot(v, axis)); 132 | foreach (var v in projectedVectorsB) 133 | positionsOnAxisB.Add(Vector2.Dot(v, axis)); 134 | float maxA = -float.MaxValue, minA = float.MaxValue, maxB = -float.MaxValue, minB = float.MaxValue; 135 | int maxA_j = -1, minA_j = -1, maxB_j = -1, minB_j = -1; 136 | for (int j = 0; j < positionsOnAxisA.Count; j++) 137 | { 138 | var a = positionsOnAxisA[j]; 139 | if (a > maxA) 140 | { 141 | maxA = a; 142 | maxA_j = j; 143 | } 144 | if (a < minA) 145 | { 146 | minA = a; 147 | minA_j = j; 148 | } 149 | } 150 | for (int j = 0; j < positionsOnAxisB.Count; j++) 151 | { 152 | var b = positionsOnAxisB[j]; 153 | if (b > maxB) 154 | { 155 | maxB = b; 156 | maxB_j = j; 157 | } 158 | if (b < minB) 159 | { 160 | minB = b; 161 | minB_j = j; 162 | } 163 | } 164 | if (maxA < minB || maxB < minA) 165 | { 166 | return false; 167 | } 168 | else 169 | { 170 | Vector2 diff1 = (projectedVectorsA[maxA_j] - projectedVectorsB[minB_j]); 171 | Vector2 diff2 = (projectedVectorsB[maxB_j] - projectedVectorsA[minA_j]); 172 | if (diff1.SqrMagnitude() < diff2.SqrMagnitude()) 173 | axisOverlaps.Add(diff1); 174 | else 175 | axisOverlaps.Add((diff2 * -1)); 176 | } 177 | } 178 | 179 | if (axisOverlaps.Count == 0) 180 | return false; 181 | 182 | float minLength2 = float.MaxValue; 183 | i = -1; 184 | for (int j = 0; j < axisOverlaps.Count; j++) 185 | { 186 | var length2 = axisOverlaps[j].SqrMagnitude(); 187 | if (length2 < minLength2) 188 | { 189 | minLength2 = length2; 190 | i = j; 191 | } 192 | } 193 | offset = (axisOverlaps[i] * -1.0f); 194 | return true; 195 | } 196 | 197 | public static bool LineLineIntersection(Vector3 l1, Vector3 l2, out Vector2 intersection) 198 | { 199 | float det = l2.x * l1.y - l1.x * l2.y; 200 | if (Mathf.Abs(det) != 0.0) 201 | { 202 | intersection = 1.0f / det * new Vector2(l2.y * l1.z - l1.y * l2.z, l1.x * l2.z - l2.x * l1.z); 203 | return true; 204 | } 205 | intersection = default(Vector2); 206 | return false; 207 | } 208 | 209 | public static bool LineSegmentLineSegmentIntersection(Vector2 p1, Vector2 p2, Vector2 q1, Vector2 q2, out Vector2 intersection, out float t) 210 | { 211 | var r = (p2 - p1); 212 | var s = (q2 - q1); 213 | var num = Vector3.Cross((q1 - p1), r).z; 214 | var den = Vector3.Cross(r, s).z; 215 | if (num == 0 && den == 0) 216 | { 217 | // lines are collinear, so do they overlap? 218 | // return ((q1.x - p1.x < 0) != (q1.x - p2.x < 0) != (q2.x - p1.x < 0) != (q2.x - p2.x < 0)) || 219 | // ((q1.y - p1.y < 0) != (q1.y - p2.y < 0) != (q2.y - p1.y < 0) != (q2.y - p2.y < 0)); 220 | intersection = default(Vector2); 221 | t = -1; 222 | return false; 223 | } 224 | if (den == 0) 225 | { 226 | // lines are parallel 227 | intersection = default(Vector2); 228 | t = -1; 229 | return false; 230 | } 231 | var u = num / den; 232 | t = Vector3.Cross((q1 - p1), s).z / den; 233 | bool a = (t > EPSILON) && (t < 1.0f - EPSILON) && (u > EPSILON) && (u < 1.0f - EPSILON); 234 | if (a) 235 | { 236 | intersection = new Vector2(p1.x + t * r.x, p1.y + t * r.y); 237 | return true; 238 | } 239 | intersection = default(Vector2); 240 | return a; 241 | } 242 | 243 | } 244 | 245 | } 246 | -------------------------------------------------------------------------------- /Assets/RoadGen/Scripts/RoadNetworkCollisionMap.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | 5 | namespace RoadGen 6 | { 7 | public static class RoadNetworkCollisionMap 8 | { 9 | public class Stroke 10 | { 11 | public class Pixel 12 | { 13 | public int x, y; 14 | public float distanceToCenter; 15 | public float sqrDistanceToCenter; 16 | internal Stroke source; 17 | 18 | public float GetNormalizedDistanceToCenter() 19 | { 20 | return distanceToCenter / source.halfSize; 21 | } 22 | 23 | public int GetMapX() 24 | { 25 | return source.x + x; 26 | } 27 | 28 | public int GetMapY() 29 | { 30 | return source.y + y; 31 | } 32 | 33 | } 34 | 35 | public int size; 36 | public int halfSize; 37 | public int halfSize2; 38 | public int x, y; 39 | public Segment segment; 40 | public Vector2 segmentCoords; 41 | public Vector2 segmentDirection; 42 | public float segmentStep; 43 | private Pixel currentPixel; 44 | 45 | public Stroke() 46 | { 47 | currentPixel = new Pixel(); 48 | currentPixel.source = this; 49 | } 50 | 51 | public Pixel CurrentPixel 52 | { 53 | get 54 | { 55 | return currentPixel; 56 | } 57 | } 58 | 59 | } 60 | 61 | public delegate bool WorldToMapCoords(float wX, float wY, out int mX, out int mY); 62 | public delegate void BrushFunction(Stroke stroke, int mapSize, T[,] map); 63 | public delegate T DrawFunction(Stroke stroke, T currentValue); 64 | 65 | private static void FindStrokePixelBoundaries(Stroke stroke, int mapSize, out int minY, out int maxY, out int minX, out int maxX) 66 | { 67 | if (stroke.y < stroke.halfSize) 68 | minY = -stroke.y; 69 | else 70 | minY = -stroke.halfSize; 71 | if (stroke.y + stroke.halfSize > mapSize - 1) 72 | maxY = mapSize - 1 - stroke.y; 73 | else 74 | maxY = stroke.halfSize; 75 | if (stroke.x < stroke.halfSize) 76 | minX = -stroke.x; 77 | else 78 | minX = -stroke.halfSize; 79 | if (stroke.x + stroke.halfSize > mapSize - 1) 80 | maxX = mapSize - 1 - stroke.x; 81 | else 82 | maxX = stroke.halfSize; 83 | } 84 | 85 | public static void CircleBrush(Stroke stroke, int mapSize, T[,] map, DrawFunction drawFunction) 86 | { 87 | int minSPY, maxSPY, minSPX, maxSPX; 88 | FindStrokePixelBoundaries(stroke, mapSize, out minSPY, out maxSPY, out minSPX, out maxSPX); 89 | for (stroke.CurrentPixel.y = minSPY; stroke.CurrentPixel.y <= maxSPY; stroke.CurrentPixel.y++) 90 | { 91 | int sY2 = stroke.CurrentPixel.y * stroke.CurrentPixel.y; 92 | for (stroke.CurrentPixel.x = minSPX; stroke.CurrentPixel.x <= maxSPX; stroke.CurrentPixel.x++) 93 | { 94 | stroke.CurrentPixel.distanceToCenter = Mathf.Sqrt(stroke.CurrentPixel.x * stroke.CurrentPixel.x + sY2); 95 | if (stroke.CurrentPixel.distanceToCenter <= stroke.halfSize) 96 | { 97 | int mX = stroke.CurrentPixel.GetMapX(), 98 | mY = stroke.CurrentPixel.GetMapY(); 99 | map[mX, mY] = drawFunction(stroke, map[mX, mY]); 100 | } 101 | } 102 | } 103 | } 104 | 105 | public static void SquaredCircleBrush(Stroke stroke, int mapSize, T[,] map, DrawFunction drawFunction) 106 | { 107 | int minSPY, maxSPY, minSPX, maxSPX; 108 | FindStrokePixelBoundaries(stroke, mapSize, out minSPY, out maxSPY, out minSPX, out maxSPX); 109 | for (stroke.CurrentPixel.y = minSPY; stroke.CurrentPixel.y <= maxSPY; stroke.CurrentPixel.y++) 110 | { 111 | int sY2 = stroke.CurrentPixel.y * stroke.CurrentPixel.y; 112 | for (stroke.CurrentPixel.x = minSPX; stroke.CurrentPixel.x <= maxSPX; stroke.CurrentPixel.x++) 113 | { 114 | stroke.CurrentPixel.sqrDistanceToCenter = stroke.CurrentPixel.x * stroke.CurrentPixel.x + sY2; 115 | if (stroke.CurrentPixel.sqrDistanceToCenter <= stroke.halfSize2) 116 | { 117 | int mX = stroke.CurrentPixel.GetMapX(), 118 | mY = stroke.CurrentPixel.GetMapY(); 119 | map[mX, mY] = drawFunction(stroke, map[mX, mY]); 120 | } 121 | } 122 | } 123 | } 124 | 125 | public static void SolidCircleBrush(Stroke stroke, int mapSize, float[,] map) 126 | { 127 | int minSPY, maxSPY, minSPX, maxSPX; 128 | FindStrokePixelBoundaries(stroke, mapSize, out minSPY, out maxSPY, out minSPX, out maxSPX); 129 | for (int sPY = minSPY; sPY <= maxSPY; sPY++) 130 | { 131 | int sY2 = sPY * sPY; 132 | for (int sPX = minSPX; sPX <= maxSPX; sPX++) 133 | if (sPX * sPX + sY2 <= stroke.halfSize2) 134 | map[stroke.x + sPX, stroke.y + sPY] = 1; 135 | } 136 | } 137 | 138 | public static void SmoothCircleBrush(Stroke stroke0, int mapSize, float[,] map) 139 | { 140 | CircleBrush(stroke0, mapSize, map, (stroke1, currentValue) => currentValue + Mathf.Lerp(1, 0, stroke1.CurrentPixel.GetNormalizedDistanceToCenter())); 141 | } 142 | 143 | public static void CubicEaseOutCircleBrush(Stroke stroke0, int mapSize, float[,] map) 144 | { 145 | CircleBrush(stroke0, mapSize, map, (stroke1, currentValue) => currentValue + EasingHelper.EaseOutCubic(1, 0, stroke1.CurrentPixel.GetNormalizedDistanceToCenter(), 1)); 146 | } 147 | 148 | public static void CubicEaseInCircleBrush(Stroke stroke0, int mapSize, float[,] map) 149 | { 150 | CircleBrush(stroke0, mapSize, map, (stroke1, currentValue) => currentValue + EasingHelper.EaseInCubic(1, 0, stroke1.CurrentPixel.GetNormalizedDistanceToCenter(), 1)); 151 | } 152 | 153 | public static void SquaredSmoothCircleBrush(Stroke stroke0, int mapSize, float[,] map) 154 | { 155 | SquaredCircleBrush(stroke0, mapSize, map, (stroke1, currentValue) => currentValue + Mathf.Lerp(1, 0, stroke1.CurrentPixel.GetNormalizedDistanceToCenter())); 156 | } 157 | 158 | public static void Build(List segments, int mask, float samplingStep, int strokeSize, BrushFunction brushFunction, int mapSize, WorldToMapCoords worldToMapCoords, T[,] map) 159 | { 160 | Stroke stroke = new Stroke(); 161 | stroke.halfSize = Mathf.CeilToInt(strokeSize * 0.5f); 162 | stroke.halfSize2 = stroke.halfSize * stroke.halfSize; 163 | HashSet visited = new HashSet(); 164 | foreach (var segment in segments) 165 | { 166 | RoadNetworkTraversal.PreOrder(segment, (s0) => 167 | { 168 | stroke.segment = s0; 169 | stroke.segmentDirection = (s0.End - s0.Start) / s0.Length; 170 | int numSteps = Mathf.CeilToInt(s0.Length / samplingStep); 171 | var segmentStep = 1.0f / numSteps; 172 | var positionIncrement = s0.Length / numSteps * stroke.segmentDirection; 173 | stroke.segmentStep = 0; 174 | stroke.segmentCoords = s0.Start; 175 | int x, y; 176 | for (int step = 0; step < numSteps; step++, stroke.segmentCoords += positionIncrement, stroke.segmentStep += segmentStep) 177 | { 178 | if (!worldToMapCoords(stroke.segmentCoords.x, stroke.segmentCoords.y, out x, out y)) 179 | break; 180 | stroke.x = x; 181 | stroke.y = y; 182 | brushFunction(stroke, mapSize, map); 183 | } 184 | return true; 185 | }, mask, ref visited); 186 | } 187 | } 188 | 189 | public static void Normalize(int mapSize, float[,] map) 190 | { 191 | float maxValue = -float.MaxValue; 192 | for (int y = 0; y < mapSize; y++) 193 | for (int x = 0; x < mapSize; x++) 194 | { 195 | float value = map[x, y]; 196 | if (value > maxValue) 197 | maxValue = value; 198 | } 199 | for (int y = 0; y < mapSize; y++) 200 | for (int x = 0; x < mapSize; x++) 201 | map[x, y] /= maxValue; 202 | } 203 | 204 | public static void SaveMapToFile(string fileName, float[,] map, bool invert = true, bool normalize = false) 205 | { 206 | int width = map.GetLength(0), height = map.GetLength(1); 207 | float maxValue = 0; 208 | if (normalize) 209 | { 210 | maxValue = -float.MaxValue; 211 | for (int y = 0; y < height; y++) 212 | for (int x = 0; x < width; x++) 213 | { 214 | float value = map[x, y]; 215 | if (value > maxValue) 216 | maxValue = value; 217 | } 218 | } 219 | Texture2D texture = new Texture2D(width, height, TextureFormat.RGB24, false); 220 | Color[] pixels = new Color[width * height]; 221 | for (int y = 0, i = 0; y < height; y++) 222 | for (int x = 0; x < width; x++, i++) 223 | { 224 | float value = map[x, y]; 225 | if (normalize) 226 | value = value / maxValue; 227 | if (invert) 228 | value = 1 - value; 229 | pixels[i] = new Color(value, value, value, 1.0f); 230 | } 231 | texture.SetPixels(pixels); 232 | texture.Apply(); 233 | var bytes = texture.EncodeToPNG(); 234 | var fileStream = File.Open(Application.dataPath + "/" + fileName, FileMode.Create); 235 | var binary = new BinaryWriter(fileStream); 236 | binary.Write(bytes); 237 | fileStream.Close(); 238 | } 239 | 240 | } 241 | 242 | } -------------------------------------------------------------------------------- /Assets/RoadGen/Scripts/RoadDensityBasedSettlementSpawner.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System; 3 | using System.Collections.Generic; 4 | using RoadGen; 5 | using RoadGen.Eppy; 6 | 7 | public class RoadDensityBasedSettlementSpawner : MonoBehaviour 8 | { 9 | [Serializable] 10 | public struct DensityTier 11 | { 12 | public float offset; 13 | public float multiplier; 14 | public float threshold; 15 | public Interpolation interpolation; 16 | 17 | } 18 | 19 | public DensityTier[] densityTiers; 20 | public float distanceFromRoad = 1.0f; 21 | public RoadNetwork roadNetwork; 22 | public RoadDensityMap roadDensityMap; 23 | public GameObject heightmapGameObject; 24 | public GameObject allotmentBuilderGameObject; 25 | public int maxNumAllotments = 1000; 26 | private IHeightmap heightmap; 27 | private List> allotments; 28 | private float minAllotmentWidth; 29 | 30 | bool TryToAddSideBuilding(Allotment newAllotment, Vector2 position, Vector2 side, float direction, float halfRoadWidth, float density) 31 | { 32 | Vector2 center = position + side * (newAllotment.Height * 0.5f + distanceFromRoad + halfRoadWidth); 33 | newAllotment.UpdateCenterAndDirection(center, direction); 34 | bool addBuilding = false; 35 | for (int i = 0; i < Config.allotmentPlacementLoopLimit; i++) 36 | { 37 | int c = 0; 38 | Vector2 offset; 39 | var colliders = roadNetwork.Quadtree.Retrieve(newAllotment.GetCollider().GetAABB()); 40 | for (int j = 0; j < colliders.Count && (c == 0 || i < Config.allotmentPlacementLoopLimit - 1); j++) 41 | { 42 | if (newAllotment.GetCollider().Collide(((ICollidable)colliders[j].reference).GetCollider(), out offset)) 43 | { 44 | c++; 45 | newAllotment.Center = (newAllotment.Center + offset); 46 | } 47 | } 48 | if (c == 0) 49 | { 50 | addBuilding = true; 51 | break; 52 | } 53 | } 54 | if (!addBuilding) 55 | return false; 56 | allotments.Add(Tuple.Create(density, newAllotment)); 57 | roadNetwork.Quadtree.Insert(newAllotment); 58 | return true; 59 | } 60 | 61 | float Apply(float value, float edge0, float edge1, Interpolation interpolation) 62 | { 63 | float x = (value - edge0) / (edge1 - edge0); 64 | x = (interpolation == Interpolation.SMOOTHERSTEP) ? x * x * x * (x * (x * 6 - 15) + 10) : (interpolation == Interpolation.SMOOTHSTEP) ? x * x * (3 - 2 * x) : x; 65 | return x; 66 | } 67 | 68 | int FindDensityTierIndex(float density) 69 | { 70 | int i = 0; 71 | for (; i < densityTiers.Length - 1; i++) 72 | { 73 | if (density >= densityTiers[i].threshold && density < densityTiers[i + 1].threshold) 74 | return i; 75 | } 76 | if (density >= densityTiers[i].threshold) 77 | return i; 78 | return -1; 79 | } 80 | 81 | float GetProbability(float density) 82 | { 83 | var i = FindDensityTierIndex(density); 84 | if (i == -1) 85 | return 0; 86 | var currDensityTier = densityTiers[i]; 87 | return Mathf.Clamp01(Apply(density, currDensityTier.threshold, (i == densityTiers.Length - 1) ? 1 : densityTiers[i + 1].threshold, currDensityTier.interpolation) 88 | * currDensityTier.multiplier + currDensityTier.offset); 89 | } 90 | 91 | static Allotment CreateAllotment() 92 | { 93 | return new Allotment(default(Vector2), 94 | 0, 95 | UnityEngine.Random.Range(Config.allotmentMinHalfDiagonal, Config.allotmentMaxHalfDiagonal), 96 | UnityEngine.Random.Range(Config.allotmentMinAspect, Config.allotmentMaxAspect)); 97 | } 98 | 99 | bool SegmentVisitor(Segment s0) 100 | { 101 | var dir = (s0.End - s0.Start) / s0.Length; 102 | Vector2 leftDir = new Vector2(-dir.y, dir.x), 103 | rightDir = new Vector2(dir.y, -dir.x); 104 | float lengthLeft = 0, lengthRight = 0; 105 | Vector2 positionLeft = s0.Start, positionRight = s0.Start; 106 | float halfRoadWith = s0.Width * 0.5f; 107 | bool hasLeft = true, hasRight = true; 108 | do 109 | { 110 | var allotment = CreateAllotment(); 111 | var step = allotment.Width; 112 | if (hasLeft) 113 | { 114 | var remainingLength = s0.Length - lengthLeft; 115 | bool forceFit = remainingLength < step && remainingLength >= minAllotmentWidth; 116 | if (remainingLength >= step || forceFit) 117 | { 118 | if (forceFit) 119 | { 120 | var height = remainingLength / allotment.AspectRatio; 121 | allotment.UpdateWidthAndHeight(remainingLength, height); 122 | step = remainingLength; 123 | } 124 | var halfStep = step * 0.5f * dir; 125 | var newPosition = positionLeft + halfStep; 126 | var roadDensity = roadDensityMap.GetNormalizedValue(newPosition.x, newPosition.y); 127 | if (UnityEngine.Random.value < GetProbability(roadDensity)) 128 | TryToAddSideBuilding(allotment, newPosition, leftDir, s0.Direction - 90, halfRoadWith, roadDensity); 129 | positionLeft = newPosition + halfStep; 130 | lengthLeft += step; 131 | } 132 | else 133 | hasLeft = false; 134 | } 135 | allotment = CreateAllotment(); 136 | step = allotment.Width; 137 | if (hasRight) 138 | { 139 | var remainingLength = s0.Length - lengthRight; 140 | bool forceFit = remainingLength < step && remainingLength >= minAllotmentWidth; 141 | if (remainingLength >= step || forceFit) 142 | { 143 | if (forceFit) 144 | { 145 | var height = remainingLength / allotment.AspectRatio; 146 | allotment.UpdateWidthAndHeight(remainingLength, height); 147 | step = remainingLength; 148 | } 149 | var halfStep = step * 0.5f * dir; 150 | var newPosition = positionRight + halfStep; 151 | var roadDensity = roadDensityMap.GetNormalizedValue(newPosition.x, newPosition.y); 152 | if (UnityEngine.Random.value < GetProbability(roadDensity)) 153 | TryToAddSideBuilding(allotment, newPosition, rightDir, s0.Direction + 90, halfRoadWith, roadDensity); 154 | positionRight = newPosition + halfStep; 155 | lengthRight += step; 156 | } 157 | else 158 | hasRight = false; 159 | } 160 | } while (hasLeft || hasRight); 161 | return true; 162 | } 163 | 164 | void Start() 165 | { 166 | if (roadNetwork == null) 167 | { 168 | Debug.LogError("RoadDensityBasedSettlementSpawner needs a reference to a RoadNetwork"); 169 | return; 170 | } 171 | 172 | if (!roadNetwork.Finished) 173 | { 174 | Debug.LogError("RoadDensityBasedSettlementSpawner script can only execute after RoadNetwork (Configure execution order that in Edit > Project Settings > Script Execution Order)"); 175 | return; 176 | } 177 | 178 | if (roadDensityMap == null) 179 | { 180 | Debug.LogError("RoadDensityBasedSettlementSpawner needs a reference to a RoadDensityMap"); 181 | return; 182 | } 183 | 184 | if (!roadDensityMap.Finished()) 185 | { 186 | Debug.LogError("RoadDensityBasedSettlementSpawner script can only execute after RoadDensityMap (Configure execution order that in Edit > Project Settings > Script Execution Order)"); 187 | return; 188 | } 189 | 190 | if (heightmapGameObject != null) 191 | heightmap = UnityEngineHelper.GetInterface(heightmapGameObject); 192 | 193 | if (heightmap == null) 194 | { 195 | Debug.LogError("RoadDensityBasedSettlementSpawner needs a reference to a game object containing at least one component that implements IHeightmap"); 196 | return; 197 | } 198 | 199 | if (!heightmap.Finished()) 200 | { 201 | Debug.LogError("RoadDensityBasedSettlementSpawner script can only execute after the components that implements IHeightmap (Configure execution order that in Edit > Project Settings > Script Execution Order)"); 202 | return; 203 | } 204 | 205 | List allotmentBuilders = null; 206 | if (allotmentBuilderGameObject != null) 207 | allotmentBuilders = UnityEngineHelper.GetInterfaces(allotmentBuilderGameObject); 208 | if (allotmentBuilders == null) 209 | { 210 | Debug.LogError("RoadDensityBasedSettlementSpawner needs a reference to a game object containing at least one component that implements IAllotmentBuilder"); 211 | return; 212 | } 213 | 214 | { 215 | float minThreshold = -float.MaxValue; 216 | foreach (var densityTier in densityTiers) 217 | { 218 | if (densityTier.threshold < minThreshold) 219 | { 220 | Debug.LogError("Density tier has a threshold smaller than it's predecessor"); 221 | return; 222 | } 223 | minThreshold = densityTier.threshold; 224 | } 225 | } 226 | 227 | minAllotmentWidth = Allotment.GetWidth(Config.allotmentMinHalfDiagonal, Config.allotmentMinAspect); 228 | 229 | allotments = new List>(); 230 | HashSet visited = new HashSet(); 231 | foreach (var segment in roadNetwork.Segments) 232 | RoadNetworkTraversal.PreOrder(segment, SegmentVisitor, roadNetwork.Mask, ref visited); 233 | if (maxNumAllotments > 0 && allotments.Count > maxNumAllotments) 234 | { 235 | allotments.Sort((a, b) => b.Item1.CompareTo(a.Item1)); 236 | allotments = allotments.GetRange(0, maxNumAllotments); 237 | } 238 | GameObject allotmentsGO = new GameObject("Allotments"); 239 | allotmentsGO.transform.parent = transform; 240 | { 241 | foreach (var allotment in allotments) 242 | { 243 | foreach (var allotmentBuilder in allotmentBuilders) 244 | { 245 | GameObject allotmentGO = allotmentBuilder.Build(allotment.Item2, heightmap); 246 | allotmentGO.transform.parent = allotmentsGO.transform; 247 | } 248 | } 249 | } 250 | Debug.Log(allotments.Count + " allotments spawned"); 251 | } 252 | 253 | } 254 | -------------------------------------------------------------------------------- /Assets/RoadGen/Scripts/Mischel/Collections/PriorityQueue.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | 5 | namespace RoadGen.Mischel.Collections 6 | { 7 | [Serializable] 8 | public struct PriorityQueueItem 9 | { 10 | private TValue _value; 11 | public TValue Value 12 | { 13 | get { return _value; } 14 | } 15 | 16 | private TPriority _priority; 17 | public TPriority Priority 18 | { 19 | get { return _priority; } 20 | } 21 | 22 | internal PriorityQueueItem(TValue val, TPriority pri) 23 | { 24 | this._value = val; 25 | this._priority = pri; 26 | } 27 | } 28 | 29 | [Serializable] 30 | public class PriorityQueue : ICollection, 31 | IEnumerable> 32 | { 33 | private PriorityQueueItem[] items; 34 | 35 | private const Int32 DefaultCapacity = 16; 36 | private Int32 capacity; 37 | private Int32 numItems; 38 | 39 | private Comparison compareFunc; 40 | 41 | public PriorityQueue() 42 | : this(DefaultCapacity, Comparer.Default) 43 | { 44 | } 45 | 46 | public PriorityQueue(Int32 initialCapacity) 47 | : this(initialCapacity, Comparer.Default) 48 | { 49 | } 50 | 51 | public PriorityQueue(IComparer comparer) 52 | : this(DefaultCapacity, comparer) 53 | { 54 | } 55 | 56 | public PriorityQueue(int initialCapacity, IComparer comparer) 57 | { 58 | Init(initialCapacity, new Comparison(comparer.Compare)); 59 | } 60 | 61 | public PriorityQueue(Comparison comparison) 62 | : this(DefaultCapacity, comparison) 63 | { 64 | } 65 | 66 | public PriorityQueue(int initialCapacity, Comparison comparison) 67 | { 68 | Init(initialCapacity, comparison); 69 | } 70 | 71 | private void Init(int initialCapacity, Comparison comparison) 72 | { 73 | numItems = 0; 74 | compareFunc = comparison; 75 | SetCapacity(initialCapacity); 76 | } 77 | 78 | public int Count 79 | { 80 | get { return numItems; } 81 | } 82 | 83 | public int Capacity 84 | { 85 | get { return items.Length; } 86 | set { SetCapacity(value); } 87 | } 88 | 89 | private void SetCapacity(int newCapacity) 90 | { 91 | int newCap = newCapacity; 92 | if (newCap < DefaultCapacity) 93 | newCap = DefaultCapacity; 94 | 95 | // throw exception if newCapacity < NumItems 96 | if (newCap < numItems) 97 | throw new ArgumentOutOfRangeException("newCapacity", "New capacity is less than Count"); 98 | 99 | this.capacity = newCap; 100 | if (items == null) 101 | { 102 | items = new PriorityQueueItem[newCap]; 103 | return; 104 | } 105 | 106 | // Resize the array. 107 | Array.Resize>(ref items, newCap); 108 | } 109 | 110 | public void Enqueue(PriorityQueueItem newItem) 111 | { 112 | if (numItems == capacity) 113 | { 114 | // need to increase capacity 115 | // grow by 50 percent 116 | SetCapacity((3 * Capacity) / 2); 117 | } 118 | 119 | int i = numItems; 120 | ++numItems; 121 | while ((i > 0) && (compareFunc(items[(i - 1) / 2].Priority, newItem.Priority) < 0)) 122 | { 123 | items[i] = items[(i - 1) / 2]; 124 | i = (i - 1) / 2; 125 | } 126 | items[i] = newItem; 127 | //if (!VerifyQueue()) 128 | //{ 129 | // Console.WriteLine("ERROR: Queue out of order!"); 130 | //} 131 | } 132 | 133 | public void Enqueue(TValue value, TPriority priority) 134 | { 135 | Enqueue(new PriorityQueueItem(value, priority)); 136 | } 137 | 138 | private PriorityQueueItem RemoveAt(Int32 index) 139 | { 140 | PriorityQueueItem o = items[index]; 141 | --numItems; 142 | // move the last item to fill the hole 143 | PriorityQueueItem tmp = items[numItems]; 144 | // If you forget to clear this, you have a potential memory leak. 145 | items[numItems] = default(PriorityQueueItem); 146 | if (numItems > 0 && index != numItems) 147 | { 148 | // If the new item is greater than its parent, bubble up. 149 | int i = index; 150 | int parent = (i - 1) / 2; 151 | while (compareFunc(tmp.Priority, items[parent].Priority) > 0) 152 | { 153 | items[i] = items[parent]; 154 | i = parent; 155 | parent = (i - 1) / 2; 156 | } 157 | 158 | // if i == index, then we didn't move the item up 159 | if (i == index) 160 | { 161 | // bubble down ... 162 | while (i < (numItems) / 2) 163 | { 164 | int j = (2 * i) + 1; 165 | if ((j < numItems - 1) && (compareFunc(items[j].Priority, items[j + 1].Priority) < 0)) 166 | { 167 | ++j; 168 | } 169 | if (compareFunc(items[j].Priority, tmp.Priority) <= 0) 170 | { 171 | break; 172 | } 173 | items[i] = items[j]; 174 | i = j; 175 | } 176 | } 177 | // Be sure to store the item in its place. 178 | items[i] = tmp; 179 | } 180 | //if (!VerifyQueue()) 181 | //{ 182 | // Console.WriteLine("ERROR: Queue out of order!"); 183 | //} 184 | return o; 185 | } 186 | 187 | // Function to check that the queue is coherent. 188 | public bool VerifyQueue() 189 | { 190 | int i = 0; 191 | while (i < numItems / 2) 192 | { 193 | int leftChild = (2 * i) + 1; 194 | int rightChild = leftChild + 1; 195 | if (compareFunc(items[i].Priority, items[leftChild].Priority) < 0) 196 | { 197 | return false; 198 | } 199 | if (rightChild < numItems && compareFunc(items[i].Priority, items[rightChild].Priority) < 0) 200 | { 201 | return false; 202 | } 203 | ++i; 204 | } 205 | return true; 206 | } 207 | 208 | public PriorityQueueItem Dequeue() 209 | { 210 | if (Count == 0) 211 | throw new InvalidOperationException("The queue is empty"); 212 | return RemoveAt(0); 213 | } 214 | 215 | public void Remove(TValue item, IEqualityComparer comparer) 216 | { 217 | // need to find the PriorityQueueItem that has the Data value of o 218 | for (int index = 0; index < numItems; ++index) 219 | { 220 | if (comparer.Equals(item, items[index].Value)) 221 | { 222 | RemoveAt(index); 223 | return; 224 | } 225 | } 226 | throw new ApplicationException("The specified itemm is not in the queue."); 227 | } 228 | 229 | public void Remove(TValue item) 230 | { 231 | Remove(item, EqualityComparer.Default); 232 | } 233 | 234 | public PriorityQueueItem Peek() 235 | { 236 | if (Count == 0) 237 | throw new InvalidOperationException("The queue is empty"); 238 | return items[0]; 239 | } 240 | 241 | public void Clear() 242 | { 243 | for (int i = 0; i < numItems; ++i) 244 | { 245 | items[i] = default(PriorityQueueItem); 246 | } 247 | numItems = 0; 248 | TrimExcess(); 249 | } 250 | 251 | public void TrimExcess() 252 | { 253 | if (numItems < (float)0.9 * capacity) 254 | { 255 | SetCapacity(numItems); 256 | } 257 | } 258 | 259 | // Contains 260 | public bool Contains(TValue o) 261 | { 262 | foreach (PriorityQueueItem x in items) 263 | { 264 | if (x.Value.Equals(o)) 265 | return true; 266 | } 267 | return false; 268 | } 269 | 270 | public void CopyTo(PriorityQueueItem[] array, int arrayIndex) 271 | { 272 | if (array == null) 273 | throw new ArgumentNullException("array"); 274 | if (arrayIndex < 0) 275 | throw new ArgumentOutOfRangeException("arrayIndex", "arrayIndex is less than 0."); 276 | if (array.Rank > 1) 277 | throw new ArgumentException("array is multidimensional."); 278 | if (numItems == 0) 279 | return; 280 | if (arrayIndex >= array.Length) 281 | throw new ArgumentException("arrayIndex is equal to or greater than the length of the array."); 282 | if (numItems > (array.Length - arrayIndex)) 283 | throw new ArgumentException("The number of elements in the source ICollection is greater than the available space from arrayIndex to the end of the destination array."); 284 | 285 | for (int i = 0; i < numItems; i++) 286 | { 287 | array[arrayIndex + i] = items[i]; 288 | } 289 | } 290 | 291 | #region ICollection Members 292 | 293 | public void CopyTo(Array array, int index) 294 | { 295 | this.CopyTo((PriorityQueueItem[])array, index); 296 | } 297 | 298 | public bool IsSynchronized 299 | { 300 | get { return false; } 301 | } 302 | 303 | public object SyncRoot 304 | { 305 | get { return items.SyncRoot; } 306 | } 307 | 308 | #endregion 309 | 310 | #region IEnumerable> Members 311 | 312 | public IEnumerator> GetEnumerator() 313 | { 314 | for (int i = 0; i < numItems; i++) 315 | { 316 | yield return items[i]; 317 | } 318 | } 319 | 320 | #endregion 321 | 322 | #region IEnumerable Members 323 | 324 | IEnumerator IEnumerable.GetEnumerator() 325 | { 326 | return GetEnumerator(); 327 | } 328 | 329 | #endregion 330 | } 331 | } 332 | --------------------------------------------------------------------------------