mirror of
https://github.com/Xevion/Rebirth.git
synced 2025-12-08 10:08:10 -06:00
Bobbing, KDTree implementation
This commit is contained in:
@@ -49,7 +49,7 @@ MonoBehaviour:
|
|||||||
m_Script: {fileID: 11500000, guid: 5e5a2958b00708d4bacd5703ef7b2b50, type: 3}
|
m_Script: {fileID: 11500000, guid: 5e5a2958b00708d4bacd5703ef7b2b50, type: 3}
|
||||||
m_Name:
|
m_Name:
|
||||||
m_EditorClassIdentifier:
|
m_EditorClassIdentifier:
|
||||||
Size: 139
|
Size: 143
|
||||||
Bulbs: 1
|
Bulbs: 1
|
||||||
edgeColor: {r: 0.4811321, g: 0.4811321, b: 0.4811321, a: 1}
|
edgeColor: {r: 0.4811321, g: 0.4811321, b: 0.4811321, a: 1}
|
||||||
fillColor: {r: 0.1509434, g: 0.1509434, b: 0.1509434, a: 1}
|
fillColor: {r: 0.1509434, g: 0.1509434, b: 0.1509434, a: 1}
|
||||||
@@ -97,115 +97,117 @@ LineRenderer:
|
|||||||
m_SortingLayer: 0
|
m_SortingLayer: 0
|
||||||
m_SortingOrder: 0
|
m_SortingOrder: 0
|
||||||
m_Positions:
|
m_Positions:
|
||||||
- {x: 1.39, y: 0, z: 0}
|
- {x: 1.43, y: 0, z: 0}
|
||||||
- {x: 1.3876913, y: 0.08008066, z: 0}
|
- {x: 1.4277096, y: 0.08090232, z: 0}
|
||||||
- {x: 1.3807727, y: 0.1598953, z: 0}
|
- {x: 1.4208459, y: 0.16154549, z: 0}
|
||||||
- {x: 1.3692675, y: 0.23917878, z: 0}
|
- {x: 1.4094307, y: 0.24167116, z: 0}
|
||||||
- {x: 1.3532137, y: 0.31766775, z: 0}
|
- {x: 1.3935007, y: 0.32102272, z: 0}
|
||||||
- {x: 1.3326646, y: 0.39510143, z: 0}
|
- {x: 1.373107, y: 0.3993459, z: 0}
|
||||||
- {x: 1.3076885, y: 0.47122264, z: 0}
|
- {x: 1.3483148, y: 0.4763899, z: 0}
|
||||||
- {x: 1.2783685, y: 0.5457785, z: 0}
|
- {x: 1.3192034, y: 0.5519079, z: 0}
|
||||||
- {x: 1.2448018, y: 0.61852133, z: 0}
|
- {x: 1.2858663, y: 0.6256579, z: 0}
|
||||||
- {x: 1.2070999, y: 0.6892095, z: 0}
|
- {x: 1.2484101, y: 0.6974037, z: 0}
|
||||||
- {x: 1.1653882, y: 0.7576082, z: 0}
|
- {x: 1.206955, y: 0.7669156, z: 0}
|
||||||
- {x: 1.1198053, y: 0.8234901, z: 0}
|
- {x: 1.1616336, y: 0.83397084, z: 0}
|
||||||
- {x: 1.0705024, y: 0.88663656, z: 0}
|
- {x: 1.1125911, y: 0.8983546, z: 0}
|
||||||
- {x: 1.0176436, y: 0.9468377, z: 0}
|
- {x: 1.0599846, y: 0.9598606, z: 0}
|
||||||
- {x: 0.9614041, y: 1.0038935, z: 0}
|
- {x: 1.0039828, y: 1.018292, z: 0}
|
||||||
- {x: 0.9019709, y: 1.0576144, z: 0}
|
- {x: 0.9447648, y: 1.0734614, z: 0}
|
||||||
- {x: 0.8395415, y: 1.1078222, z: 0}
|
- {x: 0.8825205, y: 1.1251922, z: 0}
|
||||||
- {x: 0.7743233, y: 1.1543498, z: 0}
|
- {x: 0.8174492, y: 1.1733186, z: 0}
|
||||||
- {x: 0.7065328, y: 1.1970428, z: 0}
|
- {x: 0.74975944, y: 1.2176867, z: 0}
|
||||||
- {x: 0.6363952, y: 1.2357593, z: 0}
|
- {x: 0.6796678, y: 1.258154, z: 0}
|
||||||
- {x: 0.5641437, y: 1.2703707, z: 0}
|
- {x: 0.6073991, y: 1.2945911, z: 0}
|
||||||
- {x: 0.4900181, y: 1.3007622, z: 0}
|
- {x: 0.53318465, y: 1.3268813, z: 0}
|
||||||
- {x: 0.41426474, y: 1.3268325, z: 0}
|
- {x: 0.45726237, y: 1.354921, z: 0}
|
||||||
- {x: 0.33713508, y: 1.3484954, z: 0}
|
- {x: 0.37987518, y: 1.3786206, z: 0}
|
||||||
- {x: 0.25888562, y: 1.3656787, z: 0}
|
- {x: 0.3012713, y: 1.397904, z: 0}
|
||||||
- {x: 0.17977619, y: 1.3783252, z: 0}
|
- {x: 0.22170235, y: 1.4127095, z: 0}
|
||||||
- {x: 0.10006955, y: 1.3863932, z: 0}
|
- {x: 0.14142308, y: 1.4229896, z: 0}
|
||||||
- {x: 0.020030497, y: 1.3898556, z: 0}
|
- {x: 0.060690925, y: 1.4287114, z: 0}
|
||||||
- {x: -0.060075097, y: 1.3887011, z: 0}
|
- {x: -0.020235796, y: 1.4298568, z: 0}
|
||||||
- {x: -0.13998112, y: 1.3829336, z: 0}
|
- {x: -0.10109753, y: 1.4264218, z: 0}
|
||||||
- {x: -0.21942216, y: 1.372572, z: 0}
|
- {x: -0.18163557, y: 1.4184176, z: 0}
|
||||||
- {x: -0.2981343, y: 1.3576509, z: 0}
|
- {x: -0.2615916, y: 1.4058697, z: 0}
|
||||||
- {x: -0.37585622, y: 1.3382198, z: 0}
|
- {x: -0.3407099, y: 1.3888184, z: 0}
|
||||||
- {x: -0.4523294, y: 1.3143432, z: 0}
|
- {x: -0.4187366, y: 1.3673184, z: 0}
|
||||||
- {x: -0.5273, y: 1.2861005, z: 0}
|
- {x: -0.49542212, y: 1.3414383, z: 0}
|
||||||
- {x: -0.600519, y: 1.2535856, z: 0}
|
- {x: -0.57052046, y: 1.3112613, z: 0}
|
||||||
- {x: -0.6717431, y: 1.2169064, z: 0}
|
- {x: -0.6437913, y: 1.276884, z: 0}
|
||||||
- {x: -0.74073577, y: 1.1761848, z: 0}
|
- {x: -0.71500003, y: 1.2384163, z: 0}
|
||||||
- {x: -0.8072677, y: 1.1315559, z: 0}
|
- {x: -0.7839184, y: 1.1959815, z: 0}
|
||||||
- {x: -0.8711181, y: 1.0831681, z: 0}
|
- {x: -0.8503254, y: 1.1497159, z: 0}
|
||||||
- {x: -0.93207467, y: 1.0311822, z: 0}
|
- {x: -0.9140087, y: 1.0997672, z: 0}
|
||||||
- {x: -0.9899349, y: 0.97577083, z: 0}
|
- {x: -0.9747643, y: 1.0462956, z: 0}
|
||||||
- {x: -1.0445068, y: 0.917118, z: 0}
|
- {x: -1.0323973, y: 0.9894724, z: 0}
|
||||||
- {x: -1.095609, y: 0.8554186, z: 0}
|
- {x: -1.0867231, y: 0.9294799, z: 0}
|
||||||
- {x: -1.1430715, y: 0.7908776, z: 0}
|
- {x: -1.1375679, y: 0.8665097, z: 0}
|
||||||
- {x: -1.186737, y: 0.7237094, z: 0}
|
- {x: -1.1847688, y: 0.8007637, z: 0}
|
||||||
- {x: -1.2264603, y: 0.65413684, z: 0}
|
- {x: -1.2281746, y: 0.7324528, z: 0}
|
||||||
- {x: -1.2621094, y: 0.58239156, z: 0}
|
- {x: -1.2676458, y: 0.66179585, z: 0}
|
||||||
- {x: -1.2935658, y: 0.50871164, z: 0}
|
- {x: -1.3030567, y: 0.58901864, z: 0}
|
||||||
- {x: -1.3207252, y: 0.4333418, z: 0}
|
- {x: -1.3342935, y: 0.5143547, z: 0}
|
||||||
- {x: -1.3434972, y: 0.35653248, z: 0}
|
- {x: -1.361256, y: 0.4380434, z: 0}
|
||||||
- {x: -1.3618063, y: 0.27853876, z: 0}
|
- {x: -1.3838581, y: 0.36032858, z: 0}
|
||||||
- {x: -1.3755915, y: 0.19961978, z: 0}
|
- {x: -1.4020272, y: 0.2814595, z: 0}
|
||||||
- {x: -1.3848071, y: 0.12003768, z: 0}
|
- {x: -1.4157052, y: 0.20168887, z: 0}
|
||||||
- {x: -1.3894227, y: 0.040056836, z: 0}
|
- {x: -1.4248483, y: 0.12127248, z: 0}
|
||||||
- {x: -1.3894227, y: -0.040057078, z: 0}
|
- {x: -1.4294273, y: 0.04046729, z: 0}
|
||||||
- {x: -1.3848071, y: -0.12003792, z: 0}
|
- {x: -1.4294273, y: -0.040467538, z: 0}
|
||||||
- {x: -1.3755915, y: -0.19962001, z: 0}
|
- {x: -1.4248483, y: -0.12127273, z: 0}
|
||||||
- {x: -1.3618062, y: -0.278539, z: 0}
|
- {x: -1.4157052, y: -0.20168911, z: 0}
|
||||||
- {x: -1.3434972, y: -0.3565327, z: 0}
|
- {x: -1.4020272, y: -0.28145975, z: 0}
|
||||||
- {x: -1.3207251, y: -0.433342, z: 0}
|
- {x: -1.383858, y: -0.3603288, z: 0}
|
||||||
- {x: -1.2935658, y: -0.5087119, z: 0}
|
- {x: -1.3612559, y: -0.43804362, z: 0}
|
||||||
- {x: -1.2621093, y: -0.58239174, z: 0}
|
- {x: -1.3342934, y: -0.5143549, z: 0}
|
||||||
- {x: -1.2264602, y: -0.6541371, z: 0}
|
- {x: -1.3030566, y: -0.58901894, z: 0}
|
||||||
- {x: -1.1867368, y: -0.72370964, z: 0}
|
- {x: -1.2676457, y: -0.6617961, z: 0}
|
||||||
- {x: -1.1430714, y: -0.7908779, z: 0}
|
- {x: -1.2281744, y: -0.73245305, z: 0}
|
||||||
- {x: -1.0956088, y: -0.85541886, z: 0}
|
- {x: -1.1847687, y: -0.800764, z: 0}
|
||||||
- {x: -1.0445067, y: -0.9171182, z: 0}
|
- {x: -1.1375679, y: -0.86650985, z: 0}
|
||||||
- {x: -0.98993474, y: -0.975771, z: 0}
|
- {x: -1.0867229, y: -0.9294801, z: 0}
|
||||||
- {x: -0.9320745, y: -1.0311824, z: 0}
|
- {x: -1.0323972, y: -0.98947257, z: 0}
|
||||||
- {x: -0.87111783, y: -1.0831683, z: 0}
|
- {x: -0.97476405, y: -1.0462958, z: 0}
|
||||||
- {x: -0.8072676, y: -1.131556, z: 0}
|
- {x: -0.9140088, y: -1.0997671, z: 0}
|
||||||
- {x: -0.74073553, y: -1.1761848, z: 0}
|
- {x: -0.8503254, y: -1.1497158, z: 0}
|
||||||
- {x: -0.67174286, y: -1.2169065, z: 0}
|
- {x: -0.7839182, y: -1.1959817, z: 0}
|
||||||
- {x: -0.60051876, y: -1.2535857, z: 0}
|
- {x: -0.71499985, y: -1.2384163, z: 0}
|
||||||
- {x: -0.52729976, y: -1.2861006, z: 0}
|
- {x: -0.6437911, y: -1.276884, z: 0}
|
||||||
- {x: -0.4523292, y: -1.3143432, z: 0}
|
- {x: -0.5705201, y: -1.3112614, z: 0}
|
||||||
- {x: -0.37585598, y: -1.3382198, z: 0}
|
- {x: -0.49542156, y: -1.3414385, z: 0}
|
||||||
- {x: -0.2981342, y: -1.3576509, z: 0}
|
- {x: -0.4187367, y: -1.3673183, z: 0}
|
||||||
- {x: -0.21942207, y: -1.372572, z: 0}
|
- {x: -0.3407098, y: -1.3888184, z: 0}
|
||||||
- {x: -0.13998105, y: -1.3829336, z: 0}
|
- {x: -0.26159155, y: -1.4058697, z: 0}
|
||||||
- {x: -0.060075022, y: -1.3887011, z: 0}
|
- {x: -0.18163534, y: -1.4184176, z: 0}
|
||||||
- {x: 0.020030575, y: -1.3898556, z: 0}
|
- {x: -0.10109727, y: -1.4264218, z: 0}
|
||||||
- {x: 0.10006963, y: -1.3863932, z: 0}
|
- {x: -0.020235375, y: -1.4298568, z: 0}
|
||||||
- {x: 0.17977627, y: -1.3783252, z: 0}
|
- {x: 0.060691345, y: -1.4287114, z: 0}
|
||||||
- {x: 0.2588857, y: -1.3656787, z: 0}
|
- {x: 0.14142366, y: -1.4229896, z: 0}
|
||||||
- {x: 0.33713514, y: -1.3484954, z: 0}
|
- {x: 0.22170226, y: -1.4127095, z: 0}
|
||||||
- {x: 0.41426465, y: -1.3268325, z: 0}
|
- {x: 0.30127138, y: -1.3979039, z: 0}
|
||||||
- {x: 0.490018, y: -1.3007622, z: 0}
|
- {x: 0.3798754, y: -1.3786205, z: 0}
|
||||||
- {x: 0.5641436, y: -1.2703708, z: 0}
|
- {x: 0.4572626, y: -1.354921, z: 0}
|
||||||
- {x: 0.63639516, y: -1.2357594, z: 0}
|
- {x: 0.533185, y: -1.3268812, z: 0}
|
||||||
- {x: 0.70653325, y: -1.1970425, z: 0}
|
- {x: 0.6073995, y: -1.294591, z: 0}
|
||||||
- {x: 0.77432376, y: -1.1543496, z: 0}
|
- {x: 0.6796683, y: -1.2581538, z: 0}
|
||||||
- {x: 0.839542, y: -1.1078218, z: 0}
|
- {x: 0.7497593, y: -1.2176867, z: 0}
|
||||||
- {x: 0.9019713, y: -1.0576142, z: 0}
|
- {x: 0.8174492, y: -1.1733186, z: 0}
|
||||||
- {x: 0.9614044, y: -1.0038931, z: 0}
|
- {x: 0.88252056, y: -1.125192, z: 0}
|
||||||
- {x: 1.0176438, y: -0.94683737, z: 0}
|
- {x: 0.944765, y: -1.0734613, z: 0}
|
||||||
- {x: 1.0705028, y: -0.88663626, z: 0}
|
- {x: 1.003983, y: -1.0182917, z: 0}
|
||||||
- {x: 1.1198056, y: -0.8234898, z: 0}
|
- {x: 1.0599849, y: -0.9598603, z: 0}
|
||||||
- {x: 1.1653885, y: -0.7576078, z: 0}
|
- {x: 1.1125914, y: -0.8983542, z: 0}
|
||||||
- {x: 1.2071002, y: -0.6892091, z: 0}
|
- {x: 1.1616335, y: -0.8339709, z: 0}
|
||||||
- {x: 1.2448019, y: -0.618521, z: 0}
|
- {x: 1.206955, y: -0.7669156, z: 0}
|
||||||
- {x: 1.2783685, y: -0.54577816, z: 0}
|
- {x: 1.2484102, y: -0.69740367, z: 0}
|
||||||
- {x: 1.3076886, y: -0.4712223, z: 0}
|
- {x: 1.2858664, y: -0.6256577, z: 0}
|
||||||
- {x: 1.3326646, y: -0.3951011, z: 0}
|
- {x: 1.3192035, y: -0.5519076, z: 0}
|
||||||
- {x: 1.3532137, y: -0.31766742, z: 0}
|
- {x: 1.3483148, y: -0.47638956, z: 0}
|
||||||
- {x: 1.3692676, y: -0.2391785, z: 0}
|
- {x: 1.3731071, y: -0.39934546, z: 0}
|
||||||
- {x: 1.3807728, y: -0.15989502, z: 0}
|
- {x: 1.3935008, y: -0.32102215, z: 0}
|
||||||
- {x: 1.3876913, y: -0.0800804, z: 0}
|
- {x: 1.4094307, y: -0.2416712, z: 0}
|
||||||
|
- {x: 1.4208459, y: -0.16154543, z: 0}
|
||||||
|
- {x: 1.4277096, y: -0.08090216, z: 0}
|
||||||
m_Parameters:
|
m_Parameters:
|
||||||
serializedVersion: 3
|
serializedVersion: 3
|
||||||
widthMultiplier: 0.0466
|
widthMultiplier: 0.0466
|
||||||
@@ -262,7 +264,7 @@ LineRenderer:
|
|||||||
shadowBias: 0.5
|
shadowBias: 0.5
|
||||||
generateLightingData: 0
|
generateLightingData: 0
|
||||||
m_MaskInteraction: 0
|
m_MaskInteraction: 0
|
||||||
m_UseWorldSpace: 1
|
m_UseWorldSpace: 0
|
||||||
m_Loop: 1
|
m_Loop: 1
|
||||||
m_ApplyActiveColorSpace: 1
|
m_ApplyActiveColorSpace: 1
|
||||||
--- !u!33 &-945589377389130640
|
--- !u!33 &-945589377389130640
|
||||||
@@ -349,7 +351,7 @@ CircleCollider2D:
|
|||||||
m_UsedByComposite: 0
|
m_UsedByComposite: 0
|
||||||
m_Offset: {x: 0.001685977, y: 0}
|
m_Offset: {x: 0.001685977, y: 0}
|
||||||
serializedVersion: 2
|
serializedVersion: 2
|
||||||
m_Radius: 1.39
|
m_Radius: 1.43
|
||||||
--- !u!114 &1236946940358429026
|
--- !u!114 &1236946940358429026
|
||||||
MonoBehaviour:
|
MonoBehaviour:
|
||||||
m_ObjectHideFlags: 0
|
m_ObjectHideFlags: 0
|
||||||
@@ -367,7 +369,7 @@ MonoBehaviour:
|
|||||||
m_BlendStyleIndex: 0
|
m_BlendStyleIndex: 0
|
||||||
m_FalloffIntensity: 0.159
|
m_FalloffIntensity: 0.159
|
||||||
m_Color: {r: 1, g: 1, b: 1, a: 1}
|
m_Color: {r: 1, g: 1, b: 1, a: 1}
|
||||||
m_Intensity: 1.57
|
m_Intensity: 24.54
|
||||||
m_LightVolumeIntensity: 1
|
m_LightVolumeIntensity: 1
|
||||||
m_LightVolumeIntensityEnabled: 0
|
m_LightVolumeIntensityEnabled: 0
|
||||||
m_ApplyToSortingLayers:
|
m_ApplyToSortingLayers:
|
||||||
@@ -388,8 +390,8 @@ MonoBehaviour:
|
|||||||
m_Extent: {x: 0.9985302, y: 0.99853027, z: 0}
|
m_Extent: {x: 0.9985302, y: 0.99853027, z: 0}
|
||||||
m_PointLightInnerAngle: 360
|
m_PointLightInnerAngle: 360
|
||||||
m_PointLightOuterAngle: 360
|
m_PointLightOuterAngle: 360
|
||||||
m_PointLightInnerRadius: 0
|
m_PointLightInnerRadius: 1
|
||||||
m_PointLightOuterRadius: 1
|
m_PointLightOuterRadius: 2
|
||||||
m_ShapeLightParametricSides: 5
|
m_ShapeLightParametricSides: 5
|
||||||
m_ShapeLightParametricAngleOffset: 0
|
m_ShapeLightParametricAngleOffset: 0
|
||||||
m_ShapeLightParametricRadius: 1
|
m_ShapeLightParametricRadius: 1
|
||||||
|
|||||||
8
Assets/Datastructures.meta
Normal file
8
Assets/Datastructures.meta
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: fd0fb2105300f73429e78907962749e2
|
||||||
|
folderAsset: yes
|
||||||
|
DefaultImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
8
Assets/Datastructures/Heap.meta
Normal file
8
Assets/Datastructures/Heap.meta
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 5643fe3e36c9cef4cb65fd43995792a4
|
||||||
|
folderAsset: yes
|
||||||
|
DefaultImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
211
Assets/Datastructures/Heap/BaseHeap.cs
Normal file
211
Assets/Datastructures/Heap/BaseHeap.cs
Normal file
@@ -0,0 +1,211 @@
|
|||||||
|
/*MIT License
|
||||||
|
|
||||||
|
Copyright(c) 2018 Vili Volčini / viliwonka
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace DataStructures.ViliWonka.Heap {
|
||||||
|
|
||||||
|
// array start at index 1, optimisation reason
|
||||||
|
public abstract class BaseHeap {
|
||||||
|
|
||||||
|
protected int nodesCount;
|
||||||
|
protected int maxSize;
|
||||||
|
|
||||||
|
protected float[] heap;
|
||||||
|
|
||||||
|
protected BaseHeap(int initialSize) {
|
||||||
|
|
||||||
|
maxSize = initialSize;
|
||||||
|
heap = new float[initialSize + 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
public int Count { get { return nodesCount; } }
|
||||||
|
|
||||||
|
public float HeadValue { get { return heap[1]; } }
|
||||||
|
|
||||||
|
public void Clear() {
|
||||||
|
nodesCount = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected int Parent(int index) { return (index >> 1); }
|
||||||
|
protected int Left (int index) { return (index << 1); }
|
||||||
|
protected int Right (int index) { return (index << 1) | 1; }
|
||||||
|
|
||||||
|
// bubble down, MaxHeap version
|
||||||
|
protected void BubbleDownMax(int index) {
|
||||||
|
|
||||||
|
int L = Left(index);
|
||||||
|
int R = Right(index);
|
||||||
|
|
||||||
|
// bubbling down, 2 kids
|
||||||
|
while (R <= nodesCount) {
|
||||||
|
|
||||||
|
// if heap property is violated between index and Left child
|
||||||
|
if(heap[index] < heap[L]) {
|
||||||
|
|
||||||
|
if (heap[L] < heap[R]) {
|
||||||
|
|
||||||
|
Swap(index, R); // left has bigger priority
|
||||||
|
index = R;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
|
||||||
|
Swap(index, L); // right has bigger priority
|
||||||
|
index = L;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// if heap property is violated between index and R
|
||||||
|
if (heap[index] < heap[R]) {
|
||||||
|
|
||||||
|
Swap(index, R);
|
||||||
|
index = R;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
|
||||||
|
index = L;
|
||||||
|
L = Left(index);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
L = Left(index);
|
||||||
|
R = Right(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
// only left & last children available to test and swap
|
||||||
|
if (L <= nodesCount && heap[index] < heap[L]) {
|
||||||
|
Swap(index, L);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// bubble up, MaxHeap version
|
||||||
|
protected void BubbleUpMax(int index) {
|
||||||
|
|
||||||
|
int P = Parent(index);
|
||||||
|
|
||||||
|
//swap, until Heap property isn't violated anymore
|
||||||
|
while (P > 0 && heap[P] < heap[index]) {
|
||||||
|
|
||||||
|
Swap(P, index);
|
||||||
|
|
||||||
|
index = P;
|
||||||
|
P = Parent(index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// bubble down, MinHeap version
|
||||||
|
protected void BubbleDownMin(int index) {
|
||||||
|
|
||||||
|
int L = Left(index);
|
||||||
|
int R = Right(index);
|
||||||
|
|
||||||
|
// bubbling down, 2 kids
|
||||||
|
while(R <= nodesCount) {
|
||||||
|
|
||||||
|
// if heap property is violated between index and Left child
|
||||||
|
if(heap[index] > heap[L]) {
|
||||||
|
|
||||||
|
if(heap[L] > heap[R]) {
|
||||||
|
|
||||||
|
Swap(index, R); // right has smaller priority
|
||||||
|
index = R;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
|
||||||
|
Swap(index, L); // left has smaller priority
|
||||||
|
index = L;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// if heap property is violated between index and R
|
||||||
|
if(heap[index] > heap[R]) {
|
||||||
|
|
||||||
|
Swap(index, R);
|
||||||
|
index = R;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
|
||||||
|
index = L;
|
||||||
|
L = Left(index);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
L = Left(index);
|
||||||
|
R = Right(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
// only left & last children available to test and swap
|
||||||
|
if(L <= nodesCount && heap[index] > heap[L]) {
|
||||||
|
Swap(index, L);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// bubble up, MinHeap version
|
||||||
|
protected void BubbleUpMin(int index) {
|
||||||
|
|
||||||
|
int P = Parent(index);
|
||||||
|
|
||||||
|
//swap, until Heap property isn't violated anymore
|
||||||
|
while(P > 0 && heap[P] > heap[index]) {
|
||||||
|
|
||||||
|
Swap(P, index);
|
||||||
|
|
||||||
|
index = P;
|
||||||
|
P = Parent(index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected float tempHeap;
|
||||||
|
protected virtual void Swap(int A, int B) {
|
||||||
|
|
||||||
|
tempHeap = heap[A];
|
||||||
|
heap[A] = heap[B];
|
||||||
|
heap[B] = tempHeap;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual void UpsizeHeap() {
|
||||||
|
|
||||||
|
maxSize *= 2;
|
||||||
|
System.Array.Resize(ref heap, maxSize + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual void PushValue(float h) {
|
||||||
|
throw new System.NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual float PopValue() {
|
||||||
|
throw new System.NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void FlushHeapResult(List<float> heapList) {
|
||||||
|
|
||||||
|
for(int i = 1; i < Count; i++) {
|
||||||
|
heapList.Add(heap[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
11
Assets/Datastructures/Heap/BaseHeap.cs.meta
Normal file
11
Assets/Datastructures/Heap/BaseHeap.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: f79974e0b20985b47a168ebcb1f3e74b
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
229
Assets/Datastructures/Heap/KSmallest.cs
Normal file
229
Assets/Datastructures/Heap/KSmallest.cs
Normal file
@@ -0,0 +1,229 @@
|
|||||||
|
/*MIT License
|
||||||
|
|
||||||
|
Copyright(c) 2018 Vili Volčini / viliwonka
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace DataStructures.ViliWonka.Heap {
|
||||||
|
|
||||||
|
public class KSmallestHeap : BaseHeap {
|
||||||
|
|
||||||
|
public KSmallestHeap(int maxEntries) : base(maxEntries) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Full {
|
||||||
|
get {
|
||||||
|
return maxSize == nodesCount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// in lots of cases, max head gets removed
|
||||||
|
public override void PushValue(float h) {
|
||||||
|
|
||||||
|
// if heap full
|
||||||
|
if(nodesCount == maxSize) {
|
||||||
|
|
||||||
|
// if Heads priority is smaller than input priority, then ignore that item
|
||||||
|
if(HeadValue < h) {
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
|
||||||
|
heap[1] = h; // remove top element
|
||||||
|
BubbleDownMax(1); // bubble it down
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
|
||||||
|
nodesCount++;
|
||||||
|
heap[nodesCount] = h;
|
||||||
|
BubbleUpMax(nodesCount);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override float PopValue() {
|
||||||
|
|
||||||
|
if(nodesCount == 0)
|
||||||
|
throw new System.ArgumentException("Heap is empty!");
|
||||||
|
|
||||||
|
float result = heap[1];
|
||||||
|
|
||||||
|
heap[1] = heap[nodesCount];
|
||||||
|
nodesCount--;
|
||||||
|
BubbleDownMax(1);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Print() {
|
||||||
|
|
||||||
|
UnityEngine.Debug.Log("HeapPropertyHolds? " + HeapPropertyHolds(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
//should remove
|
||||||
|
public bool HeapPropertyHolds(int index, int depth = 0) {
|
||||||
|
|
||||||
|
if (index > nodesCount)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
UnityEngine.Debug.Log(heap[index]);
|
||||||
|
|
||||||
|
int L = Left(index);
|
||||||
|
int R = Right(index);
|
||||||
|
|
||||||
|
bool bothHold = true;
|
||||||
|
|
||||||
|
if(L <= nodesCount) {
|
||||||
|
|
||||||
|
UnityEngine.Debug.Log(heap[index] + " => " + heap[L]);
|
||||||
|
|
||||||
|
if (heap[index] < heap[L])
|
||||||
|
bothHold = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if L <= nodesCount, then R <= nodesCount can also happen
|
||||||
|
if (R <= nodesCount) {
|
||||||
|
|
||||||
|
UnityEngine.Debug.Log(heap[index] + " => " + heap[R]);
|
||||||
|
|
||||||
|
if (bothHold && heap[index] < heap[R])
|
||||||
|
bothHold = false;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return bothHold & HeapPropertyHolds(L, depth + 1) & HeapPropertyHolds(R, depth + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// array start at index 1
|
||||||
|
// generic version
|
||||||
|
public class KSmallestHeap<T> : KSmallestHeap {
|
||||||
|
|
||||||
|
T[] objs; //objects
|
||||||
|
|
||||||
|
public KSmallestHeap(int maxEntries) : base(maxEntries) {
|
||||||
|
objs = new T[maxEntries + 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
public T HeadHeapObject { get { return objs[1]; } }
|
||||||
|
|
||||||
|
T tempObjs;
|
||||||
|
protected override void Swap(int A, int B) {
|
||||||
|
|
||||||
|
tempHeap = heap[A];
|
||||||
|
tempObjs = objs[A];
|
||||||
|
|
||||||
|
heap[A] = heap[B];
|
||||||
|
objs[A] = objs[B];
|
||||||
|
|
||||||
|
heap[B] = tempHeap;
|
||||||
|
objs[B] = tempObjs;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void PushValue(float h) {
|
||||||
|
throw new System.ArgumentException("Use Push(T, float)!");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void PushObj(T obj, float h) {
|
||||||
|
|
||||||
|
// if heap full
|
||||||
|
if(nodesCount == maxSize) {
|
||||||
|
|
||||||
|
// if Heads priority is smaller than input priority, then ignore that item
|
||||||
|
if(HeadValue < h) {
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
|
||||||
|
heap[1] = h; // remove top element
|
||||||
|
objs[1] = obj;
|
||||||
|
BubbleDownMax(1); // bubble it down
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
|
||||||
|
nodesCount++;
|
||||||
|
heap[nodesCount] = h;
|
||||||
|
objs[nodesCount] = obj;
|
||||||
|
BubbleUpMax(nodesCount);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override float PopValue() {
|
||||||
|
throw new System.ArgumentException("Use PopObj()!");
|
||||||
|
}
|
||||||
|
|
||||||
|
public T PopObj() {
|
||||||
|
|
||||||
|
if(nodesCount == 0)
|
||||||
|
throw new System.ArgumentException("Heap is empty!");
|
||||||
|
|
||||||
|
T result = objs[1];
|
||||||
|
|
||||||
|
heap[1] = heap[nodesCount];
|
||||||
|
objs[1] = objs[nodesCount];
|
||||||
|
|
||||||
|
nodesCount--;
|
||||||
|
BubbleDownMax(1);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public T PopObj(ref float heapValue) {
|
||||||
|
|
||||||
|
if(nodesCount == 0)
|
||||||
|
throw new System.ArgumentException("Heap is empty!");
|
||||||
|
|
||||||
|
heapValue = heap[1];
|
||||||
|
T result = PopObj();
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
//flush internal results, returns ordered data
|
||||||
|
public void FlushResult(List<T> resultList, List<float> heapList = null) {
|
||||||
|
|
||||||
|
int count = nodesCount + 1;
|
||||||
|
|
||||||
|
|
||||||
|
if(heapList == null) {
|
||||||
|
|
||||||
|
for(int i = 1; i < count; i++) {
|
||||||
|
resultList.Add(PopObj());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
|
||||||
|
float h = 0f;
|
||||||
|
|
||||||
|
for(int i = 1; i < count; i++) {
|
||||||
|
resultList.Add(PopObj(ref h));
|
||||||
|
heapList.Add(h);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
11
Assets/Datastructures/Heap/KSmallest.cs.meta
Normal file
11
Assets/Datastructures/Heap/KSmallest.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 616a0666a4955ed4bbe7fcac27b32ae7
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
168
Assets/Datastructures/Heap/MaxHeap.cs
Normal file
168
Assets/Datastructures/Heap/MaxHeap.cs
Normal file
@@ -0,0 +1,168 @@
|
|||||||
|
/*MIT License
|
||||||
|
|
||||||
|
Copyright(c) 2018 Vili Volčini / viliwonka
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace DataStructures.ViliWonka.Heap {
|
||||||
|
|
||||||
|
public class MaxHeap : BaseHeap {
|
||||||
|
|
||||||
|
public MaxHeap(int initialSize = 2048) : base(initialSize) {
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void PushValue(float h) {
|
||||||
|
|
||||||
|
// if heap array is full
|
||||||
|
if(nodesCount == maxSize) {
|
||||||
|
|
||||||
|
UpsizeHeap();
|
||||||
|
}
|
||||||
|
|
||||||
|
nodesCount++;
|
||||||
|
heap[nodesCount] = h;
|
||||||
|
BubbleUpMax(nodesCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override float PopValue() {
|
||||||
|
|
||||||
|
if(nodesCount == 0)
|
||||||
|
throw new System.ArgumentException("Heap is empty!");
|
||||||
|
|
||||||
|
float result = heap[1];
|
||||||
|
|
||||||
|
heap[1] = heap[nodesCount];
|
||||||
|
nodesCount--;
|
||||||
|
BubbleDownMax(1);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// generic version
|
||||||
|
public class MaxHeap<T> : MaxHeap {
|
||||||
|
|
||||||
|
T[] objs; // objects
|
||||||
|
|
||||||
|
public MaxHeap(int maxNodes) : base(maxNodes) {
|
||||||
|
objs = new T[maxNodes + 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
public T HeadHeapObject { get { return objs[1]; } }
|
||||||
|
|
||||||
|
T tempObjs;
|
||||||
|
protected override void Swap(int A, int B) {
|
||||||
|
|
||||||
|
tempHeap = heap[A];
|
||||||
|
tempObjs = objs[A];
|
||||||
|
|
||||||
|
heap[A] = heap[B];
|
||||||
|
objs[A] = objs[B];
|
||||||
|
|
||||||
|
heap[B] = tempHeap;
|
||||||
|
objs[B] = tempObjs;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void PushValue(float h) {
|
||||||
|
throw new System.ArgumentException("Use PushObj(T, float)!");
|
||||||
|
}
|
||||||
|
|
||||||
|
public override float PopValue() {
|
||||||
|
throw new System.ArgumentException("Use Push(T, float)!");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void PushObj(T obj, float h) {
|
||||||
|
|
||||||
|
// if heap array is full
|
||||||
|
if(nodesCount == maxSize) {
|
||||||
|
UpsizeHeap();
|
||||||
|
}
|
||||||
|
|
||||||
|
nodesCount++;
|
||||||
|
heap[nodesCount] = h;
|
||||||
|
objs[nodesCount] = obj;
|
||||||
|
|
||||||
|
BubbleUpMin(nodesCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
public T PopObj() {
|
||||||
|
|
||||||
|
if(nodesCount == 0)
|
||||||
|
throw new System.ArgumentException("Heap is empty!");
|
||||||
|
|
||||||
|
T result = objs[1];
|
||||||
|
|
||||||
|
heap[1] = heap[nodesCount];
|
||||||
|
objs[1] = objs[nodesCount];
|
||||||
|
|
||||||
|
objs[nodesCount] = default(T);
|
||||||
|
|
||||||
|
nodesCount--;
|
||||||
|
BubbleDownMin(1);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public T PopObj(ref float heapValue) {
|
||||||
|
|
||||||
|
if(nodesCount == 0)
|
||||||
|
throw new System.ArgumentException("Heap is empty!");
|
||||||
|
|
||||||
|
heapValue = heap[1];
|
||||||
|
T result = PopObj();
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void UpsizeHeap() {
|
||||||
|
|
||||||
|
maxSize *= 2;
|
||||||
|
System.Array.Resize(ref heap, maxSize + 1);
|
||||||
|
System.Array.Resize(ref objs, maxSize + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
//flush internal results, returns ordered data
|
||||||
|
public void FlushResult(List<T> resultList, List<float> heapList = null) {
|
||||||
|
|
||||||
|
int count = nodesCount + 1;
|
||||||
|
|
||||||
|
if(heapList == null) {
|
||||||
|
|
||||||
|
for(int i = 1; i < count; i++) {
|
||||||
|
resultList.Add(PopObj());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
|
||||||
|
float h = 0f;
|
||||||
|
|
||||||
|
for(int i = 1; i < count; i++) {
|
||||||
|
resultList.Add(PopObj(ref h));
|
||||||
|
heapList.Add(h);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
11
Assets/Datastructures/Heap/MaxHeap.cs.meta
Normal file
11
Assets/Datastructures/Heap/MaxHeap.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 6c07f133f8057584fadbaf01edc5fd3a
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
171
Assets/Datastructures/Heap/MinHeap.cs
Normal file
171
Assets/Datastructures/Heap/MinHeap.cs
Normal file
@@ -0,0 +1,171 @@
|
|||||||
|
/*MIT License
|
||||||
|
|
||||||
|
Copyright(c) 2018 Vili Volčini / viliwonka
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace DataStructures.ViliWonka.Heap {
|
||||||
|
|
||||||
|
public class MinHeap : BaseHeap {
|
||||||
|
|
||||||
|
public MinHeap(int initialSize = 2048) : base(initialSize) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void PushValue(float h) {
|
||||||
|
|
||||||
|
// if heap array is full
|
||||||
|
if(nodesCount == maxSize) {
|
||||||
|
|
||||||
|
UpsizeHeap();
|
||||||
|
}
|
||||||
|
|
||||||
|
nodesCount++;
|
||||||
|
heap[nodesCount] = h;
|
||||||
|
BubbleUpMin(nodesCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override float PopValue() {
|
||||||
|
|
||||||
|
if(nodesCount == 0)
|
||||||
|
throw new System.ArgumentException("Heap is empty!");
|
||||||
|
|
||||||
|
float result = heap[1];
|
||||||
|
|
||||||
|
heap[1] = heap[nodesCount];
|
||||||
|
|
||||||
|
nodesCount--;
|
||||||
|
|
||||||
|
if(nodesCount != 0)
|
||||||
|
BubbleDownMin(1);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// generic version
|
||||||
|
public class MinHeap<T> : MinHeap {
|
||||||
|
|
||||||
|
T[] objs; // objects
|
||||||
|
|
||||||
|
public MinHeap(int maxNodes = 2048) : base(maxNodes) {
|
||||||
|
objs = new T[maxNodes + 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
public T HeadHeapObject { get { return objs[1]; } }
|
||||||
|
|
||||||
|
T tempObjs;
|
||||||
|
protected override void Swap(int A, int B) {
|
||||||
|
|
||||||
|
tempHeap = heap[A];
|
||||||
|
tempObjs = objs[A];
|
||||||
|
|
||||||
|
heap[A] = heap[B];
|
||||||
|
objs[A] = objs[B];
|
||||||
|
|
||||||
|
heap[B] = tempHeap;
|
||||||
|
objs[B] = tempObjs;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void PushValue(float h) {
|
||||||
|
throw new System.ArgumentException("Use Push(T, float)!");
|
||||||
|
}
|
||||||
|
|
||||||
|
public override float PopValue() {
|
||||||
|
throw new System.ArgumentException("Use Push(T, float)!");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void PushObj(T obj, float h) {
|
||||||
|
|
||||||
|
// if heap array is full
|
||||||
|
if(nodesCount == maxSize) {
|
||||||
|
UpsizeHeap();
|
||||||
|
}
|
||||||
|
|
||||||
|
nodesCount++;
|
||||||
|
heap[nodesCount] = h;
|
||||||
|
objs[nodesCount] = obj;
|
||||||
|
|
||||||
|
BubbleUpMin(nodesCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
public T PopObj() {
|
||||||
|
|
||||||
|
if(nodesCount == 0)
|
||||||
|
throw new System.ArgumentException("Heap is empty!");
|
||||||
|
|
||||||
|
T result = objs[1];
|
||||||
|
|
||||||
|
heap[1] = heap[nodesCount];
|
||||||
|
objs[1] = objs[nodesCount];
|
||||||
|
|
||||||
|
objs[nodesCount] = default(T);
|
||||||
|
|
||||||
|
nodesCount--;
|
||||||
|
|
||||||
|
if(nodesCount != 0)
|
||||||
|
BubbleDownMin(1);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public T PopObj(ref float heapValue) {
|
||||||
|
|
||||||
|
if(nodesCount == 0)
|
||||||
|
throw new System.ArgumentException("Heap is empty!");
|
||||||
|
|
||||||
|
heapValue = heap[1];
|
||||||
|
T result = PopObj();
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void UpsizeHeap() {
|
||||||
|
|
||||||
|
maxSize *= 2;
|
||||||
|
System.Array.Resize(ref heap, maxSize + 1);
|
||||||
|
System.Array.Resize(ref objs, maxSize + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
//flush internal array, returns ordered data
|
||||||
|
public void FlushResult(List<T> resultList, List<float> heapList = null) {
|
||||||
|
|
||||||
|
int count = nodesCount + 1;
|
||||||
|
|
||||||
|
if(heapList == null) {
|
||||||
|
|
||||||
|
for(int i = 1; i < count; i++) {
|
||||||
|
resultList.Add(PopObj());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
|
||||||
|
float h = 0f;
|
||||||
|
|
||||||
|
for(int i = 1; i < count; i++) {
|
||||||
|
resultList.Add(PopObj(ref h));
|
||||||
|
heapList.Add(h);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
11
Assets/Datastructures/Heap/MinHeap.cs.meta
Normal file
11
Assets/Datastructures/Heap/MinHeap.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 354799470fae8d74d8f977dd8db040cf
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
298
Assets/Datastructures/Heap/heapTestScene.unity
Normal file
298
Assets/Datastructures/Heap/heapTestScene.unity
Normal file
@@ -0,0 +1,298 @@
|
|||||||
|
%YAML 1.1
|
||||||
|
%TAG !u! tag:unity3d.com,2011:
|
||||||
|
--- !u!29 &1
|
||||||
|
OcclusionCullingSettings:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
serializedVersion: 2
|
||||||
|
m_OcclusionBakeSettings:
|
||||||
|
smallestOccluder: 5
|
||||||
|
smallestHole: 0.25
|
||||||
|
backfaceThreshold: 100
|
||||||
|
m_SceneGUID: 00000000000000000000000000000000
|
||||||
|
m_OcclusionCullingData: {fileID: 0}
|
||||||
|
--- !u!104 &2
|
||||||
|
RenderSettings:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
serializedVersion: 9
|
||||||
|
m_Fog: 0
|
||||||
|
m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1}
|
||||||
|
m_FogMode: 3
|
||||||
|
m_FogDensity: 0.01
|
||||||
|
m_LinearFogStart: 0
|
||||||
|
m_LinearFogEnd: 300
|
||||||
|
m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1}
|
||||||
|
m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1}
|
||||||
|
m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1}
|
||||||
|
m_AmbientIntensity: 1
|
||||||
|
m_AmbientMode: 0
|
||||||
|
m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1}
|
||||||
|
m_SkyboxMaterial: {fileID: 10304, guid: 0000000000000000f000000000000000, type: 0}
|
||||||
|
m_HaloStrength: 0.5
|
||||||
|
m_FlareStrength: 1
|
||||||
|
m_FlareFadeSpeed: 3
|
||||||
|
m_HaloTexture: {fileID: 0}
|
||||||
|
m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0}
|
||||||
|
m_DefaultReflectionMode: 0
|
||||||
|
m_DefaultReflectionResolution: 128
|
||||||
|
m_ReflectionBounces: 1
|
||||||
|
m_ReflectionIntensity: 1
|
||||||
|
m_CustomReflection: {fileID: 0}
|
||||||
|
m_Sun: {fileID: 0}
|
||||||
|
m_IndirectSpecularColor: {r: 0.44657898, g: 0.4964133, b: 0.5748178, a: 1}
|
||||||
|
m_UseRadianceAmbientProbe: 0
|
||||||
|
--- !u!157 &3
|
||||||
|
LightmapSettings:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
serializedVersion: 11
|
||||||
|
m_GIWorkflowMode: 0
|
||||||
|
m_GISettings:
|
||||||
|
serializedVersion: 2
|
||||||
|
m_BounceScale: 1
|
||||||
|
m_IndirectOutputScale: 1
|
||||||
|
m_AlbedoBoost: 1
|
||||||
|
m_TemporalCoherenceThreshold: 1
|
||||||
|
m_EnvironmentLightingMode: 0
|
||||||
|
m_EnableBakedLightmaps: 1
|
||||||
|
m_EnableRealtimeLightmaps: 1
|
||||||
|
m_LightmapEditorSettings:
|
||||||
|
serializedVersion: 10
|
||||||
|
m_Resolution: 2
|
||||||
|
m_BakeResolution: 40
|
||||||
|
m_AtlasSize: 1024
|
||||||
|
m_AO: 0
|
||||||
|
m_AOMaxDistance: 1
|
||||||
|
m_CompAOExponent: 1
|
||||||
|
m_CompAOExponentDirect: 0
|
||||||
|
m_Padding: 2
|
||||||
|
m_LightmapParameters: {fileID: 0}
|
||||||
|
m_LightmapsBakeMode: 1
|
||||||
|
m_TextureCompression: 1
|
||||||
|
m_FinalGather: 0
|
||||||
|
m_FinalGatherFiltering: 1
|
||||||
|
m_FinalGatherRayCount: 256
|
||||||
|
m_ReflectionCompression: 2
|
||||||
|
m_MixedBakeMode: 2
|
||||||
|
m_BakeBackend: 1
|
||||||
|
m_PVRSampling: 1
|
||||||
|
m_PVRDirectSampleCount: 32
|
||||||
|
m_PVRSampleCount: 500
|
||||||
|
m_PVRBounces: 2
|
||||||
|
m_PVRFilterTypeDirect: 0
|
||||||
|
m_PVRFilterTypeIndirect: 0
|
||||||
|
m_PVRFilterTypeAO: 0
|
||||||
|
m_PVRFilteringMode: 1
|
||||||
|
m_PVRCulling: 1
|
||||||
|
m_PVRFilteringGaussRadiusDirect: 1
|
||||||
|
m_PVRFilteringGaussRadiusIndirect: 5
|
||||||
|
m_PVRFilteringGaussRadiusAO: 2
|
||||||
|
m_PVRFilteringAtrousPositionSigmaDirect: 0.5
|
||||||
|
m_PVRFilteringAtrousPositionSigmaIndirect: 2
|
||||||
|
m_PVRFilteringAtrousPositionSigmaAO: 1
|
||||||
|
m_ShowResolutionOverlay: 1
|
||||||
|
m_LightingDataAsset: {fileID: 0}
|
||||||
|
m_UseShadowmask: 1
|
||||||
|
--- !u!196 &4
|
||||||
|
NavMeshSettings:
|
||||||
|
serializedVersion: 2
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_BuildSettings:
|
||||||
|
serializedVersion: 2
|
||||||
|
agentTypeID: 0
|
||||||
|
agentRadius: 0.5
|
||||||
|
agentHeight: 2
|
||||||
|
agentSlope: 45
|
||||||
|
agentClimb: 0.4
|
||||||
|
ledgeDropHeight: 0
|
||||||
|
maxJumpAcrossDistance: 0
|
||||||
|
minRegionArea: 2
|
||||||
|
manualCellSize: 0
|
||||||
|
cellSize: 0.16666667
|
||||||
|
manualTileSize: 0
|
||||||
|
tileSize: 256
|
||||||
|
accuratePlacement: 0
|
||||||
|
debug:
|
||||||
|
m_Flags: 0
|
||||||
|
m_NavMeshData: {fileID: 0}
|
||||||
|
--- !u!1 &653832527
|
||||||
|
GameObject:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInternal: {fileID: 0}
|
||||||
|
serializedVersion: 6
|
||||||
|
m_Component:
|
||||||
|
- component: {fileID: 653832530}
|
||||||
|
- component: {fileID: 653832529}
|
||||||
|
- component: {fileID: 653832528}
|
||||||
|
m_Layer: 0
|
||||||
|
m_Name: Main Camera
|
||||||
|
m_TagString: MainCamera
|
||||||
|
m_Icon: {fileID: 0}
|
||||||
|
m_NavMeshLayer: 0
|
||||||
|
m_StaticEditorFlags: 0
|
||||||
|
m_IsActive: 1
|
||||||
|
--- !u!81 &653832528
|
||||||
|
AudioListener:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInternal: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 653832527}
|
||||||
|
m_Enabled: 1
|
||||||
|
--- !u!20 &653832529
|
||||||
|
Camera:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInternal: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 653832527}
|
||||||
|
m_Enabled: 1
|
||||||
|
serializedVersion: 2
|
||||||
|
m_ClearFlags: 1
|
||||||
|
m_BackGroundColor: {r: 0.19215687, g: 0.3019608, b: 0.4745098, a: 0}
|
||||||
|
m_projectionMatrixMode: 1
|
||||||
|
m_SensorSize: {x: 36, y: 24}
|
||||||
|
m_LensShift: {x: 0, y: 0}
|
||||||
|
m_FocalLength: 50
|
||||||
|
m_NormalizedViewPortRect:
|
||||||
|
serializedVersion: 2
|
||||||
|
x: 0
|
||||||
|
y: 0
|
||||||
|
width: 1
|
||||||
|
height: 1
|
||||||
|
near clip plane: 0.3
|
||||||
|
far clip plane: 1000
|
||||||
|
field of view: 60
|
||||||
|
orthographic: 0
|
||||||
|
orthographic size: 5
|
||||||
|
m_Depth: -1
|
||||||
|
m_CullingMask:
|
||||||
|
serializedVersion: 2
|
||||||
|
m_Bits: 4294967295
|
||||||
|
m_RenderingPath: -1
|
||||||
|
m_TargetTexture: {fileID: 0}
|
||||||
|
m_TargetDisplay: 0
|
||||||
|
m_TargetEye: 3
|
||||||
|
m_HDR: 1
|
||||||
|
m_AllowMSAA: 1
|
||||||
|
m_AllowDynamicResolution: 0
|
||||||
|
m_ForceIntoRT: 0
|
||||||
|
m_OcclusionCulling: 1
|
||||||
|
m_StereoConvergence: 10
|
||||||
|
m_StereoSeparation: 0.022
|
||||||
|
--- !u!4 &653832530
|
||||||
|
Transform:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInternal: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 653832527}
|
||||||
|
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||||
|
m_LocalPosition: {x: 0, y: 1, z: -10}
|
||||||
|
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||||
|
m_Children: []
|
||||||
|
m_Father: {fileID: 0}
|
||||||
|
m_RootOrder: 0
|
||||||
|
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||||
|
--- !u!1 &1730864583
|
||||||
|
GameObject:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInternal: {fileID: 0}
|
||||||
|
serializedVersion: 6
|
||||||
|
m_Component:
|
||||||
|
- component: {fileID: 1730864585}
|
||||||
|
- component: {fileID: 1730864584}
|
||||||
|
m_Layer: 0
|
||||||
|
m_Name: Directional Light
|
||||||
|
m_TagString: Untagged
|
||||||
|
m_Icon: {fileID: 0}
|
||||||
|
m_NavMeshLayer: 0
|
||||||
|
m_StaticEditorFlags: 0
|
||||||
|
m_IsActive: 1
|
||||||
|
--- !u!108 &1730864584
|
||||||
|
Light:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInternal: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 1730864583}
|
||||||
|
m_Enabled: 1
|
||||||
|
serializedVersion: 8
|
||||||
|
m_Type: 1
|
||||||
|
m_Color: {r: 1, g: 0.95686275, b: 0.8392157, a: 1}
|
||||||
|
m_Intensity: 1
|
||||||
|
m_Range: 10
|
||||||
|
m_SpotAngle: 30
|
||||||
|
m_CookieSize: 10
|
||||||
|
m_Shadows:
|
||||||
|
m_Type: 2
|
||||||
|
m_Resolution: -1
|
||||||
|
m_CustomResolution: -1
|
||||||
|
m_Strength: 1
|
||||||
|
m_Bias: 0.05
|
||||||
|
m_NormalBias: 0.4
|
||||||
|
m_NearPlane: 0.2
|
||||||
|
m_Cookie: {fileID: 0}
|
||||||
|
m_DrawHalo: 0
|
||||||
|
m_Flare: {fileID: 0}
|
||||||
|
m_RenderMode: 0
|
||||||
|
m_CullingMask:
|
||||||
|
serializedVersion: 2
|
||||||
|
m_Bits: 4294967295
|
||||||
|
m_Lightmapping: 4
|
||||||
|
m_LightShadowCasterMode: 0
|
||||||
|
m_AreaSize: {x: 1, y: 1}
|
||||||
|
m_BounceIntensity: 1
|
||||||
|
m_ColorTemperature: 6570
|
||||||
|
m_UseColorTemperature: 0
|
||||||
|
m_ShadowRadius: 0
|
||||||
|
m_ShadowAngle: 0
|
||||||
|
--- !u!4 &1730864585
|
||||||
|
Transform:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInternal: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 1730864583}
|
||||||
|
m_LocalRotation: {x: 0.40821788, y: -0.23456968, z: 0.10938163, w: 0.8754261}
|
||||||
|
m_LocalPosition: {x: 0, y: 3, z: 0}
|
||||||
|
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||||
|
m_Children: []
|
||||||
|
m_Father: {fileID: 0}
|
||||||
|
m_RootOrder: 1
|
||||||
|
m_LocalEulerAnglesHint: {x: 50, y: -30, z: 0}
|
||||||
|
--- !u!1 &1883466098
|
||||||
|
GameObject:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInternal: {fileID: 0}
|
||||||
|
serializedVersion: 6
|
||||||
|
m_Component:
|
||||||
|
- component: {fileID: 1883466100}
|
||||||
|
- component: {fileID: 1883466099}
|
||||||
|
m_Layer: 0
|
||||||
|
m_Name: GameObject
|
||||||
|
m_TagString: Untagged
|
||||||
|
m_Icon: {fileID: 0}
|
||||||
|
m_NavMeshLayer: 0
|
||||||
|
m_StaticEditorFlags: 0
|
||||||
|
m_IsActive: 1
|
||||||
|
--- !u!114 &1883466099
|
||||||
|
MonoBehaviour:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInternal: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 1883466098}
|
||||||
|
m_Enabled: 1
|
||||||
|
m_EditorHideFlags: 0
|
||||||
|
m_Script: {fileID: 11500000, guid: e3f22e25c6d555d45b86d62ecaaf8895, type: 3}
|
||||||
|
m_Name:
|
||||||
|
m_EditorClassIdentifier:
|
||||||
|
--- !u!4 &1883466100
|
||||||
|
Transform:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInternal: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 1883466098}
|
||||||
|
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||||
|
m_LocalPosition: {x: 1.6106011, y: 0.41596547, z: 1.608385}
|
||||||
|
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||||
|
m_Children: []
|
||||||
|
m_Father: {fileID: 0}
|
||||||
|
m_RootOrder: 2
|
||||||
|
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||||
7
Assets/Datastructures/Heap/heapTestScene.unity.meta
Normal file
7
Assets/Datastructures/Heap/heapTestScene.unity.meta
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 3bd0cd1e56a2ce749a627974769aee70
|
||||||
|
DefaultImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
8
Assets/Datastructures/KDTree.meta
Normal file
8
Assets/Datastructures/KDTree.meta
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 1d2e5a2e752b9204f8375596c35adb7c
|
||||||
|
folderAsset: yes
|
||||||
|
DefaultImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
73
Assets/Datastructures/KDTree/KDBounds.cs
Normal file
73
Assets/Datastructures/KDTree/KDBounds.cs
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
/*MIT License
|
||||||
|
|
||||||
|
Copyright(c) 2018 Vili Volčini / viliwonka
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
using UnityEngine;
|
||||||
|
using UnityEditor;
|
||||||
|
|
||||||
|
namespace DataStructures.ViliWonka.KDTree {
|
||||||
|
|
||||||
|
public struct KDBounds {
|
||||||
|
|
||||||
|
public Vector3 min;
|
||||||
|
public Vector3 max;
|
||||||
|
|
||||||
|
public Vector3 size {
|
||||||
|
|
||||||
|
get {
|
||||||
|
return max - min;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// returns unity bounds
|
||||||
|
public Bounds Bounds {
|
||||||
|
|
||||||
|
get {
|
||||||
|
return new Bounds(
|
||||||
|
(min + max) / 2,
|
||||||
|
(max - min)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public Vector3 ClosestPoint(Vector3 point) {
|
||||||
|
|
||||||
|
// X axis
|
||||||
|
if(point.x < min.x) point.x = min.x;
|
||||||
|
else
|
||||||
|
if(point.x > max.x) point.x = max.x;
|
||||||
|
|
||||||
|
// Y axis
|
||||||
|
if(point.y < min.y) point.y = min.y;
|
||||||
|
else
|
||||||
|
if(point.y > max.y) point.y = max.y;
|
||||||
|
|
||||||
|
// Z axis
|
||||||
|
if(point.z < min.z) point.z = min.z;
|
||||||
|
else
|
||||||
|
if(point.z > max.z) point.z = max.z;
|
||||||
|
|
||||||
|
return point;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
13
Assets/Datastructures/KDTree/KDBounds.cs.meta
Normal file
13
Assets/Datastructures/KDTree/KDBounds.cs.meta
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 1b92db3ff3e67ee43a15eda23aea87a3
|
||||||
|
timeCreated: 1521907406
|
||||||
|
licenseType: Free
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
49
Assets/Datastructures/KDTree/KDNode.cs
Normal file
49
Assets/Datastructures/KDTree/KDNode.cs
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
/*MIT License
|
||||||
|
|
||||||
|
Copyright(c) 2018 Vili Volčini / viliwonka
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace DataStructures.ViliWonka.KDTree {
|
||||||
|
|
||||||
|
public class KDNode {
|
||||||
|
|
||||||
|
public float partitionCoordinate;
|
||||||
|
public int partitionAxis = -1;
|
||||||
|
|
||||||
|
public KDNode negativeChild;
|
||||||
|
public KDNode positiveChild;
|
||||||
|
|
||||||
|
public int start;
|
||||||
|
public int end;
|
||||||
|
|
||||||
|
public int Count { get { return end - start; } }
|
||||||
|
|
||||||
|
public bool Leaf { get { return partitionAxis == -1; } }
|
||||||
|
|
||||||
|
public KDBounds bounds;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
13
Assets/Datastructures/KDTree/KDNode.cs.meta
Normal file
13
Assets/Datastructures/KDTree/KDNode.cs.meta
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: c4440ff733ae6bc488c26393873a5950
|
||||||
|
timeCreated: 1520605573
|
||||||
|
licenseType: Free
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
8
Assets/Datastructures/KDTree/KDQuery.meta
Normal file
8
Assets/Datastructures/KDTree/KDQuery.meta
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: e3161368cf6450547b9d21f82757ed69
|
||||||
|
folderAsset: yes
|
||||||
|
DefaultImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
136
Assets/Datastructures/KDTree/KDQuery/Base.cs
Normal file
136
Assets/Datastructures/KDTree/KDQuery/Base.cs
Normal file
@@ -0,0 +1,136 @@
|
|||||||
|
/*MIT License
|
||||||
|
|
||||||
|
Copyright(c) 2018 Vili Volčini / viliwonka
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
The object used for querying. This object should be persistent - re-used for querying.
|
||||||
|
Contains internal array for pooling, so that it doesn't generate (too much) garbage.
|
||||||
|
The array never down-sizes, only up-sizes, so the more you use this object, less garbage will it make over time.
|
||||||
|
|
||||||
|
Should be used only by 1 thread,
|
||||||
|
which means each thread should have it's own KDQuery object in order for querying to be thread safe.
|
||||||
|
|
||||||
|
KDQuery can query different KDTrees.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using UnityEngine;
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace DataStructures.ViliWonka.KDTree {
|
||||||
|
|
||||||
|
public partial class KDQuery {
|
||||||
|
|
||||||
|
protected KDQueryNode[] queueArray; // queue array
|
||||||
|
protected Heap.MinHeap<KDQueryNode> minHeap; //heap for k-nearest
|
||||||
|
protected int count = 0; // size of queue
|
||||||
|
protected int queryIndex = 0; // current index at stack
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns initialized node from stack that also acts as a pool
|
||||||
|
/// The returned reference to node stays in stack
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>Reference to pooled node</returns>
|
||||||
|
private KDQueryNode PushGetQueue() {
|
||||||
|
|
||||||
|
KDQueryNode node = null;
|
||||||
|
|
||||||
|
if (count < queueArray.Length) {
|
||||||
|
|
||||||
|
if (queueArray[count] == null)
|
||||||
|
queueArray[count] = node = new KDQueryNode();
|
||||||
|
else
|
||||||
|
node = queueArray[count];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
|
||||||
|
// automatic resize of pool
|
||||||
|
Array.Resize(ref queueArray, queueArray.Length * 2);
|
||||||
|
node = queueArray[count] = new KDQueryNode();
|
||||||
|
}
|
||||||
|
|
||||||
|
count++;
|
||||||
|
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void PushToQueue(KDNode node, Vector3 tempClosestPoint) {
|
||||||
|
|
||||||
|
var queryNode = PushGetQueue();
|
||||||
|
queryNode.node = node;
|
||||||
|
queryNode.tempClosestPoint = tempClosestPoint;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void PushToHeap(KDNode node, Vector3 tempClosestPoint, Vector3 queryPosition) {
|
||||||
|
|
||||||
|
var queryNode = PushGetQueue();
|
||||||
|
queryNode.node = node;
|
||||||
|
queryNode.tempClosestPoint = tempClosestPoint;
|
||||||
|
|
||||||
|
float sqrDist = Vector3.SqrMagnitude(tempClosestPoint - queryPosition);
|
||||||
|
queryNode.distance = sqrDist;
|
||||||
|
minHeap.PushObj(queryNode, sqrDist);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected int LeftToProcess {
|
||||||
|
|
||||||
|
get {
|
||||||
|
return count - queryIndex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// just gets unprocessed node from stack
|
||||||
|
// increases queryIndex
|
||||||
|
protected KDQueryNode PopFromQueue() {
|
||||||
|
|
||||||
|
var node = queueArray[queryIndex];
|
||||||
|
queryIndex++;
|
||||||
|
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected KDQueryNode PopFromHeap() {
|
||||||
|
|
||||||
|
KDQueryNode heapNode = minHeap.PopObj();
|
||||||
|
|
||||||
|
queueArray[queryIndex]= heapNode;
|
||||||
|
queryIndex++;
|
||||||
|
|
||||||
|
return heapNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void Reset() {
|
||||||
|
|
||||||
|
count = 0;
|
||||||
|
queryIndex = 0;
|
||||||
|
minHeap.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
public KDQuery(int queryNodesContainersInitialSize = 2048) {
|
||||||
|
queueArray = new KDQueryNode[queryNodesContainersInitialSize];
|
||||||
|
minHeap = new Heap.MinHeap<KDQueryNode>(queryNodesContainersInitialSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
13
Assets/Datastructures/KDTree/KDQuery/Base.cs.meta
Normal file
13
Assets/Datastructures/KDTree/KDQuery/Base.cs.meta
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 57b0c8c3d7b727847b235e82d2fbead0
|
||||||
|
timeCreated: 1521924674
|
||||||
|
licenseType: Free
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
56
Assets/Datastructures/KDTree/KDQuery/Debug.cs
Normal file
56
Assets/Datastructures/KDTree/KDQuery/Debug.cs
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
/*MIT License
|
||||||
|
|
||||||
|
Copyright(c) 2018 Vili Volčini / viliwonka
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define KDTREE_VISUAL_DEBUG
|
||||||
|
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using UnityEngine;
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace DataStructures.ViliWonka.KDTree {
|
||||||
|
|
||||||
|
public partial class KDQuery {
|
||||||
|
|
||||||
|
// uses gizmos
|
||||||
|
public void DrawLastQuery() {
|
||||||
|
|
||||||
|
Color start = Color.red;
|
||||||
|
Color end = Color.green;
|
||||||
|
|
||||||
|
start.a = 0.25f;
|
||||||
|
end.a = 0.25f;
|
||||||
|
|
||||||
|
for(int i = 0; i < queryIndex; i++) {
|
||||||
|
|
||||||
|
float val = i / (float)queryIndex;
|
||||||
|
|
||||||
|
Gizmos.color = Color.Lerp(end, start, val);
|
||||||
|
|
||||||
|
Bounds b = queueArray[i].node.bounds.Bounds;
|
||||||
|
|
||||||
|
Gizmos.DrawWireCube(b.center, b.size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
11
Assets/Datastructures/KDTree/KDQuery/Debug.cs.meta
Normal file
11
Assets/Datastructures/KDTree/KDQuery/Debug.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 4aac471bf6e30fd49afa5fff399421c0
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
45
Assets/Datastructures/KDTree/KDQuery/KDQueryNode.cs
Normal file
45
Assets/Datastructures/KDTree/KDQuery/KDQueryNode.cs
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
/*MIT License
|
||||||
|
|
||||||
|
Copyright(c) 2018 Vili Volčini / viliwonka
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
using UnityEngine;
|
||||||
|
using UnityEditor;
|
||||||
|
|
||||||
|
namespace DataStructures.ViliWonka.KDTree {
|
||||||
|
|
||||||
|
public class KDQueryNode {
|
||||||
|
|
||||||
|
public KDNode node;
|
||||||
|
public Vector3 tempClosestPoint;
|
||||||
|
public float distance;
|
||||||
|
|
||||||
|
public KDQueryNode() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public KDQueryNode(KDNode node, Vector3 tempClosestPoint) {
|
||||||
|
this.node = node;
|
||||||
|
this.tempClosestPoint = tempClosestPoint;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
13
Assets/Datastructures/KDTree/KDQuery/KDQueryNode.cs.meta
Normal file
13
Assets/Datastructures/KDTree/KDQuery/KDQueryNode.cs.meta
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: cbe8b45a46d50254494605e93da9d3ed
|
||||||
|
timeCreated: 1521907406
|
||||||
|
licenseType: Free
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
144
Assets/Datastructures/KDTree/KDQuery/QueryClosest.cs
Normal file
144
Assets/Datastructures/KDTree/KDQuery/QueryClosest.cs
Normal file
@@ -0,0 +1,144 @@
|
|||||||
|
/*MIT License
|
||||||
|
|
||||||
|
Copyright(c) 2018 Vili Volčini / viliwonka
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using UnityEngine;
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace DataStructures.ViliWonka.KDTree {
|
||||||
|
|
||||||
|
using Heap;
|
||||||
|
|
||||||
|
public partial class KDQuery {
|
||||||
|
|
||||||
|
public void ClosestPoint(KDTree tree, Vector3 queryPosition, List<int> resultIndices, List<float> resultDistances = null) {
|
||||||
|
|
||||||
|
Reset();
|
||||||
|
|
||||||
|
Vector3[] points = tree.Points;
|
||||||
|
int[] permutation = tree.Permutation;
|
||||||
|
|
||||||
|
if (points.Length == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int smallestIndex = 0;
|
||||||
|
/// Smallest Squared Radius
|
||||||
|
float SSR = Single.PositiveInfinity;
|
||||||
|
|
||||||
|
|
||||||
|
var rootNode = tree.RootNode;
|
||||||
|
|
||||||
|
Vector3 rootClosestPoint = rootNode.bounds.ClosestPoint(queryPosition);
|
||||||
|
|
||||||
|
PushToHeap(rootNode, rootClosestPoint, queryPosition);
|
||||||
|
|
||||||
|
KDQueryNode queryNode = null;
|
||||||
|
KDNode node = null;
|
||||||
|
|
||||||
|
int partitionAxis;
|
||||||
|
float partitionCoord;
|
||||||
|
|
||||||
|
Vector3 tempClosestPoint;
|
||||||
|
|
||||||
|
// searching
|
||||||
|
while(minHeap.Count > 0) {
|
||||||
|
|
||||||
|
queryNode = PopFromHeap();
|
||||||
|
|
||||||
|
if(queryNode.distance > SSR)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
node = queryNode.node;
|
||||||
|
|
||||||
|
if(!node.Leaf) {
|
||||||
|
|
||||||
|
partitionAxis = node.partitionAxis;
|
||||||
|
partitionCoord = node.partitionCoordinate;
|
||||||
|
|
||||||
|
tempClosestPoint = queryNode.tempClosestPoint;
|
||||||
|
|
||||||
|
if((tempClosestPoint[partitionAxis] - partitionCoord) < 0) {
|
||||||
|
|
||||||
|
// we already know we are on the side of negative bound/node,
|
||||||
|
// so we don't need to test for distance
|
||||||
|
// push to stack for later querying
|
||||||
|
|
||||||
|
PushToHeap(node.negativeChild, tempClosestPoint, queryPosition);
|
||||||
|
// project the tempClosestPoint to other bound
|
||||||
|
tempClosestPoint[partitionAxis] = partitionCoord;
|
||||||
|
|
||||||
|
if(node.positiveChild.Count != 0) {
|
||||||
|
|
||||||
|
PushToHeap(node.positiveChild, tempClosestPoint, queryPosition);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
|
||||||
|
// we already know we are on the side of positive bound/node,
|
||||||
|
// so we don't need to test for distance
|
||||||
|
// push to stack for later querying
|
||||||
|
|
||||||
|
PushToHeap(node.positiveChild, tempClosestPoint, queryPosition);
|
||||||
|
// project the tempClosestPoint to other bound
|
||||||
|
tempClosestPoint[partitionAxis] = partitionCoord;
|
||||||
|
|
||||||
|
if(node.positiveChild.Count != 0) {
|
||||||
|
|
||||||
|
PushToHeap(node.negativeChild, tempClosestPoint, queryPosition);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
|
||||||
|
float sqrDist;
|
||||||
|
// LEAF
|
||||||
|
for(int i = node.start; i < node.end; i++) {
|
||||||
|
|
||||||
|
int index = permutation[i];
|
||||||
|
|
||||||
|
sqrDist = Vector3.SqrMagnitude(points[index] - queryPosition);
|
||||||
|
|
||||||
|
if(sqrDist <= SSR) {
|
||||||
|
|
||||||
|
SSR = sqrDist;
|
||||||
|
smallestIndex = index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resultIndices.Add(smallestIndex);
|
||||||
|
|
||||||
|
if(resultDistances != null) {
|
||||||
|
resultDistances.Add(SSR);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
11
Assets/Datastructures/KDTree/KDQuery/QueryClosest.cs.meta
Normal file
11
Assets/Datastructures/KDTree/KDQuery/QueryClosest.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: a226a270de4df034986ad64328da4cc2
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
151
Assets/Datastructures/KDTree/KDQuery/QueryInterval.cs
Normal file
151
Assets/Datastructures/KDTree/KDQuery/QueryInterval.cs
Normal file
@@ -0,0 +1,151 @@
|
|||||||
|
/*MIT License
|
||||||
|
|
||||||
|
Copyright(c) 2018 Vili Volčini / viliwonka
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using UnityEngine;
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace DataStructures.ViliWonka.KDTree {
|
||||||
|
|
||||||
|
public partial class KDQuery {
|
||||||
|
|
||||||
|
public void Interval(KDTree tree, Vector3 min, Vector3 max, List<int> resultIndices) {
|
||||||
|
|
||||||
|
Reset();
|
||||||
|
|
||||||
|
Vector3[] points = tree.Points;
|
||||||
|
int[] permutation = tree.Permutation;
|
||||||
|
|
||||||
|
var rootNode = tree.RootNode;
|
||||||
|
|
||||||
|
PushToQueue(
|
||||||
|
|
||||||
|
rootNode,
|
||||||
|
rootNode.bounds.ClosestPoint((min + max) / 2)
|
||||||
|
);
|
||||||
|
|
||||||
|
KDQueryNode queryNode = null;
|
||||||
|
KDNode node = null;
|
||||||
|
|
||||||
|
|
||||||
|
// KD search with pruning (don't visit areas which distance is more away than range)
|
||||||
|
// Recursion done on Stack
|
||||||
|
while(LeftToProcess > 0) {
|
||||||
|
|
||||||
|
queryNode = PopFromQueue();
|
||||||
|
node = queryNode.node;
|
||||||
|
|
||||||
|
if(!node.Leaf) {
|
||||||
|
|
||||||
|
int partitionAxis = node.partitionAxis;
|
||||||
|
float partitionCoord = node.partitionCoordinate;
|
||||||
|
|
||||||
|
Vector3 tempClosestPoint = queryNode.tempClosestPoint;
|
||||||
|
|
||||||
|
if((tempClosestPoint[partitionAxis] - partitionCoord) < 0) {
|
||||||
|
|
||||||
|
// we already know we are inside negative bound/node,
|
||||||
|
// so we don't need to test for distance
|
||||||
|
// push to stack for later querying
|
||||||
|
|
||||||
|
// tempClosestPoint is inside negative side
|
||||||
|
// assign it to negativeChild
|
||||||
|
PushToQueue(node.negativeChild, tempClosestPoint);
|
||||||
|
|
||||||
|
tempClosestPoint[partitionAxis] = partitionCoord;
|
||||||
|
|
||||||
|
// testing other side
|
||||||
|
if(node.positiveChild.Count != 0
|
||||||
|
&& tempClosestPoint[partitionAxis] <= max[partitionAxis]) {
|
||||||
|
|
||||||
|
PushToQueue(node.positiveChild, tempClosestPoint);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
|
||||||
|
// we already know we are inside positive bound/node,
|
||||||
|
// so we don't need to test for distance
|
||||||
|
// push to stack for later querying
|
||||||
|
|
||||||
|
// tempClosestPoint is inside positive side
|
||||||
|
// assign it to positiveChild
|
||||||
|
PushToQueue(node.positiveChild, tempClosestPoint);
|
||||||
|
|
||||||
|
// project the tempClosestPoint to other bound
|
||||||
|
tempClosestPoint[partitionAxis] = partitionCoord;
|
||||||
|
|
||||||
|
// testing other side
|
||||||
|
if(node.negativeChild.Count != 0
|
||||||
|
&& tempClosestPoint[partitionAxis] >= min[partitionAxis]) {
|
||||||
|
|
||||||
|
PushToQueue(node.negativeChild, tempClosestPoint);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
|
||||||
|
// LEAF
|
||||||
|
|
||||||
|
// testing if node bounds are inside the query interval
|
||||||
|
if(node.bounds.min[0] >= min[0]
|
||||||
|
&& node.bounds.min[1] >= min[1]
|
||||||
|
&& node.bounds.min[2] >= min[2]
|
||||||
|
|
||||||
|
&& node.bounds.max[0] <= max[0]
|
||||||
|
&& node.bounds.max[1] <= max[1]
|
||||||
|
&& node.bounds.max[2] <= max[2]) {
|
||||||
|
|
||||||
|
for(int i = node.start; i < node.end; i++) {
|
||||||
|
|
||||||
|
resultIndices.Add(permutation[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
// node is not inside query interval, need to do test on each point separately
|
||||||
|
else {
|
||||||
|
|
||||||
|
for(int i = node.start; i < node.end; i++) {
|
||||||
|
|
||||||
|
int index = permutation[i];
|
||||||
|
|
||||||
|
Vector3 v = points[index];
|
||||||
|
|
||||||
|
if(v[0] >= min[0]
|
||||||
|
&& v[1] >= min[1]
|
||||||
|
&& v[2] >= min[2]
|
||||||
|
|
||||||
|
&& v[0] <= max[0]
|
||||||
|
&& v[1] <= max[1]
|
||||||
|
&& v[2] <= max[2]) {
|
||||||
|
|
||||||
|
resultIndices.Add(index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
11
Assets/Datastructures/KDTree/KDQuery/QueryInterval.cs.meta
Normal file
11
Assets/Datastructures/KDTree/KDQuery/QueryInterval.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: ea62a128d2f9e7848ae1c116012e36e1
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
160
Assets/Datastructures/KDTree/KDQuery/QueryKNearest.cs
Normal file
160
Assets/Datastructures/KDTree/KDQuery/QueryKNearest.cs
Normal file
@@ -0,0 +1,160 @@
|
|||||||
|
/*MIT License
|
||||||
|
|
||||||
|
Copyright(c) 2018 Vili Volčini / viliwonka
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define KDTREE_VISUAL_DEBUG
|
||||||
|
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using UnityEngine;
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace DataStructures.ViliWonka.KDTree {
|
||||||
|
|
||||||
|
using Heap;
|
||||||
|
|
||||||
|
public partial class KDQuery {
|
||||||
|
|
||||||
|
SortedList<int, KSmallestHeap<int>> _heaps = new SortedList<int, KSmallestHeap<int>>();
|
||||||
|
/// <summary>
|
||||||
|
/// Returns indices to k closest points, and optionaly can return distances
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="tree">Tree to do search on</param>
|
||||||
|
/// <param name="queryPosition">Position</param>
|
||||||
|
/// <param name="k">Max number of points</param>
|
||||||
|
/// <param name="resultIndices">List where resulting indices will be stored</param>
|
||||||
|
/// <param name="resultDistances">Optional list where resulting distances will be stored</param>
|
||||||
|
public void KNearest(KDTree tree, Vector3 queryPosition, int k, List<int> resultIndices, List<float> resultDistances = null) {
|
||||||
|
|
||||||
|
// pooled heap arrays
|
||||||
|
KSmallestHeap<int> kHeap;
|
||||||
|
|
||||||
|
_heaps.TryGetValue(k, out kHeap);
|
||||||
|
|
||||||
|
if(kHeap == null) {
|
||||||
|
|
||||||
|
kHeap = new KSmallestHeap<int>(k);
|
||||||
|
_heaps.Add(k, kHeap);
|
||||||
|
}
|
||||||
|
|
||||||
|
kHeap.Clear();
|
||||||
|
Reset();
|
||||||
|
|
||||||
|
Vector3[] points = tree.Points;
|
||||||
|
int[] permutation = tree.Permutation;
|
||||||
|
|
||||||
|
///Biggest Smallest Squared Radius
|
||||||
|
float BSSR = Single.PositiveInfinity;
|
||||||
|
|
||||||
|
var rootNode = tree.RootNode;
|
||||||
|
|
||||||
|
Vector3 rootClosestPoint = rootNode.bounds.ClosestPoint(queryPosition);
|
||||||
|
|
||||||
|
PushToHeap(rootNode, rootClosestPoint, queryPosition);
|
||||||
|
|
||||||
|
KDQueryNode queryNode = null;
|
||||||
|
KDNode node = null;
|
||||||
|
|
||||||
|
int partitionAxis;
|
||||||
|
float partitionCoord;
|
||||||
|
|
||||||
|
Vector3 tempClosestPoint;
|
||||||
|
|
||||||
|
// searching
|
||||||
|
while(minHeap.Count > 0) {
|
||||||
|
|
||||||
|
queryNode = PopFromHeap();
|
||||||
|
|
||||||
|
if(queryNode.distance > BSSR)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
node = queryNode.node;
|
||||||
|
|
||||||
|
if(!node.Leaf) {
|
||||||
|
|
||||||
|
partitionAxis = node.partitionAxis;
|
||||||
|
partitionCoord = node.partitionCoordinate;
|
||||||
|
|
||||||
|
tempClosestPoint = queryNode.tempClosestPoint;
|
||||||
|
|
||||||
|
if((tempClosestPoint[partitionAxis] - partitionCoord) < 0) {
|
||||||
|
|
||||||
|
// we already know we are on the side of negative bound/node,
|
||||||
|
// so we don't need to test for distance
|
||||||
|
// push to stack for later querying
|
||||||
|
|
||||||
|
PushToHeap(node.negativeChild, tempClosestPoint, queryPosition);
|
||||||
|
// project the tempClosestPoint to other bound
|
||||||
|
tempClosestPoint[partitionAxis] = partitionCoord;
|
||||||
|
|
||||||
|
if(node.positiveChild.Count != 0) {
|
||||||
|
|
||||||
|
PushToHeap(node.positiveChild, tempClosestPoint, queryPosition);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
|
||||||
|
// we already know we are on the side of positive bound/node,
|
||||||
|
// so we don't need to test for distance
|
||||||
|
// push to stack for later querying
|
||||||
|
|
||||||
|
PushToHeap(node.positiveChild, tempClosestPoint, queryPosition);
|
||||||
|
// project the tempClosestPoint to other bound
|
||||||
|
tempClosestPoint[partitionAxis] = partitionCoord;
|
||||||
|
|
||||||
|
if(node.positiveChild.Count != 0) {
|
||||||
|
|
||||||
|
PushToHeap(node.negativeChild, tempClosestPoint, queryPosition);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
|
||||||
|
float sqrDist;
|
||||||
|
// LEAF
|
||||||
|
for(int i = node.start; i < node.end; i++) {
|
||||||
|
|
||||||
|
int index = permutation[i];
|
||||||
|
|
||||||
|
sqrDist = Vector3.SqrMagnitude(points[index] - queryPosition);
|
||||||
|
|
||||||
|
if(sqrDist <= BSSR) {
|
||||||
|
|
||||||
|
kHeap.PushObj(index, sqrDist);
|
||||||
|
|
||||||
|
if(kHeap.Full) {
|
||||||
|
BSSR = kHeap.HeadValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
kHeap.FlushResult(resultIndices, resultDistances);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
11
Assets/Datastructures/KDTree/KDQuery/QueryKNearest.cs.meta
Normal file
11
Assets/Datastructures/KDTree/KDQuery/QueryKNearest.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: ded2e8ab341672849898f46a7719a7a0
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
131
Assets/Datastructures/KDTree/KDQuery/QueryRadius.cs
Normal file
131
Assets/Datastructures/KDTree/KDQuery/QueryRadius.cs
Normal file
@@ -0,0 +1,131 @@
|
|||||||
|
/*MIT License
|
||||||
|
|
||||||
|
Copyright(c) 2018 Vili Volčini / viliwonka
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using UnityEngine;
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace DataStructures.ViliWonka.KDTree {
|
||||||
|
|
||||||
|
public partial class KDQuery {
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Search by radius method.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="tree">Tree to do search on</param>
|
||||||
|
/// <param name="queryPosition">Position</param>
|
||||||
|
/// <param name="queryRadius">Radius</param>
|
||||||
|
/// <param name="resultIndices">Initialized list, cleared.</param>
|
||||||
|
public void Radius(KDTree tree, Vector3 queryPosition, float queryRadius, List<int> resultIndices) {
|
||||||
|
|
||||||
|
Reset();
|
||||||
|
|
||||||
|
Vector3[] points = tree.Points;
|
||||||
|
int[] permutation = tree.Permutation;
|
||||||
|
|
||||||
|
float squaredRadius = queryRadius * queryRadius;
|
||||||
|
|
||||||
|
var rootNode = tree.RootNode;
|
||||||
|
|
||||||
|
PushToQueue(rootNode, rootNode.bounds.ClosestPoint(queryPosition));
|
||||||
|
|
||||||
|
KDQueryNode queryNode = null;
|
||||||
|
KDNode node = null;
|
||||||
|
|
||||||
|
// KD search with pruning (don't visit areas which distance is more away than range)
|
||||||
|
// Recursion done on Stack
|
||||||
|
while(LeftToProcess > 0) {
|
||||||
|
|
||||||
|
queryNode = PopFromQueue();
|
||||||
|
node = queryNode.node;
|
||||||
|
|
||||||
|
if(!node.Leaf) {
|
||||||
|
|
||||||
|
int partitionAxis = node.partitionAxis;
|
||||||
|
float partitionCoord = node.partitionCoordinate;
|
||||||
|
|
||||||
|
Vector3 tempClosestPoint = queryNode.tempClosestPoint;
|
||||||
|
|
||||||
|
if((tempClosestPoint[partitionAxis] - partitionCoord) < 0) {
|
||||||
|
|
||||||
|
// we already know we are inside negative bound/node,
|
||||||
|
// so we don't need to test for distance
|
||||||
|
// push to stack for later querying
|
||||||
|
|
||||||
|
// tempClosestPoint is inside negative side
|
||||||
|
// assign it to negativeChild
|
||||||
|
PushToQueue(node.negativeChild, tempClosestPoint);
|
||||||
|
|
||||||
|
tempClosestPoint[partitionAxis] = partitionCoord;
|
||||||
|
|
||||||
|
float sqrDist = Vector3.SqrMagnitude(tempClosestPoint - queryPosition);
|
||||||
|
|
||||||
|
// testing other side
|
||||||
|
if(node.positiveChild.Count != 0
|
||||||
|
&& sqrDist <= squaredRadius) {
|
||||||
|
|
||||||
|
PushToQueue(node.positiveChild, tempClosestPoint);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
|
||||||
|
// we already know we are inside positive bound/node,
|
||||||
|
// so we don't need to test for distance
|
||||||
|
// push to stack for later querying
|
||||||
|
|
||||||
|
// tempClosestPoint is inside positive side
|
||||||
|
// assign it to positiveChild
|
||||||
|
PushToQueue(node.positiveChild, tempClosestPoint);
|
||||||
|
|
||||||
|
// project the tempClosestPoint to other bound
|
||||||
|
tempClosestPoint[partitionAxis] = partitionCoord;
|
||||||
|
|
||||||
|
float sqrDist = Vector3.SqrMagnitude(tempClosestPoint - queryPosition);
|
||||||
|
|
||||||
|
// testing other side
|
||||||
|
if(node.negativeChild.Count != 0
|
||||||
|
&& sqrDist <= squaredRadius) {
|
||||||
|
|
||||||
|
PushToQueue(node.negativeChild, tempClosestPoint);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
|
||||||
|
// LEAF
|
||||||
|
for(int i = node.start; i < node.end; i++) {
|
||||||
|
|
||||||
|
int index = permutation[i];
|
||||||
|
|
||||||
|
if(Vector3.SqrMagnitude(points[index] - queryPosition) <= squaredRadius) {
|
||||||
|
|
||||||
|
resultIndices.Add(index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
11
Assets/Datastructures/KDTree/KDQuery/QueryRadius.cs.meta
Normal file
11
Assets/Datastructures/KDTree/KDQuery/QueryRadius.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 17086d61d13921a4ba22e206ef32e74f
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
459
Assets/Datastructures/KDTree/KDTree.cs
Normal file
459
Assets/Datastructures/KDTree/KDTree.cs
Normal file
@@ -0,0 +1,459 @@
|
|||||||
|
/*MIT License
|
||||||
|
|
||||||
|
Copyright(c) 2018 Vili Volčini / viliwonka
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// change to !KDTREE_DUPLICATES
|
||||||
|
// if you know for sure you will not use duplicate coordinates (all unique)
|
||||||
|
#define KDTREE_DUPLICATES
|
||||||
|
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace DataStructures.ViliWonka.KDTree {
|
||||||
|
|
||||||
|
public class KDTree {
|
||||||
|
|
||||||
|
public KDNode RootNode { get; private set; }
|
||||||
|
|
||||||
|
public Vector3[] Points { get { return points; } } // points on which kd-tree will build on. This array will stay unchanged when re/building kdtree!
|
||||||
|
private Vector3[] points;
|
||||||
|
|
||||||
|
public int[] Permutation { get { return permutation; } } // index aray, that will be permuted
|
||||||
|
private int[] permutation;
|
||||||
|
|
||||||
|
public int Count { get; private set; }
|
||||||
|
|
||||||
|
private int maxPointsPerLeafNode = 32;
|
||||||
|
|
||||||
|
private KDNode[] kdNodesStack;
|
||||||
|
private int kdNodesCount = 0;
|
||||||
|
|
||||||
|
public KDTree(int maxPointsPerLeafNode = 32) {
|
||||||
|
|
||||||
|
Count = 0;
|
||||||
|
points = new Vector3[0];
|
||||||
|
permutation = new int[0];
|
||||||
|
|
||||||
|
kdNodesStack = new KDNode[64];
|
||||||
|
|
||||||
|
this.maxPointsPerLeafNode = maxPointsPerLeafNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public KDTree(Vector3[] points, int maxPointsPerLeafNode = 32) {
|
||||||
|
|
||||||
|
this.points = points;
|
||||||
|
this.permutation = new int[points.Length];
|
||||||
|
|
||||||
|
Count = points.Length;
|
||||||
|
kdNodesStack = new KDNode[64];
|
||||||
|
|
||||||
|
this.maxPointsPerLeafNode = maxPointsPerLeafNode;
|
||||||
|
|
||||||
|
Rebuild();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Build(Vector3[] newPoints, int maxPointsPerLeafNode = -1) {
|
||||||
|
|
||||||
|
SetCount(newPoints.Length);
|
||||||
|
|
||||||
|
for(int i = 0; i < Count; i++) {
|
||||||
|
points[i] = newPoints[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
Rebuild(maxPointsPerLeafNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Build(List<Vector3> newPoints, int maxPointsPerLeafNode = -1) {
|
||||||
|
|
||||||
|
SetCount(newPoints.Count);
|
||||||
|
|
||||||
|
for(int i = 0; i < Count; i++) {
|
||||||
|
points[i] = newPoints[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
Rebuild(maxPointsPerLeafNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Rebuild(int maxPointsPerLeafNode = -1) {
|
||||||
|
|
||||||
|
for(int i = 0; i < Count; i++) {
|
||||||
|
permutation[i] = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(maxPointsPerLeafNode > 0) {
|
||||||
|
this.maxPointsPerLeafNode = maxPointsPerLeafNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
BuildTree();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetCount(int newSize) {
|
||||||
|
|
||||||
|
Count = newSize;
|
||||||
|
// upsize internal arrays
|
||||||
|
if(Count > points.Length) {
|
||||||
|
|
||||||
|
Array.Resize(ref points, Count);
|
||||||
|
Array.Resize(ref permutation, Count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void BuildTree() {
|
||||||
|
|
||||||
|
ResetKDNodeStack();
|
||||||
|
|
||||||
|
RootNode = GetKDNode();
|
||||||
|
RootNode.bounds = MakeBounds();
|
||||||
|
RootNode.start = 0;
|
||||||
|
RootNode.end = Count;
|
||||||
|
|
||||||
|
SplitNode(RootNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
KDNode GetKDNode() {
|
||||||
|
|
||||||
|
KDNode node = null;
|
||||||
|
|
||||||
|
if(kdNodesCount < kdNodesStack.Length) {
|
||||||
|
|
||||||
|
if(kdNodesStack[kdNodesCount] == null) {
|
||||||
|
kdNodesStack[kdNodesCount] = node = new KDNode();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
node = kdNodesStack[kdNodesCount];
|
||||||
|
node.partitionAxis = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
|
||||||
|
// automatic resize of KDNode pool array
|
||||||
|
Array.Resize(ref kdNodesStack, kdNodesStack.Length * 2);
|
||||||
|
node = kdNodesStack[kdNodesCount] = new KDNode();
|
||||||
|
}
|
||||||
|
|
||||||
|
kdNodesCount++;
|
||||||
|
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ResetKDNodeStack() {
|
||||||
|
kdNodesCount = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// For calculating root node bounds
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>Boundary of all Vector3 points</returns>
|
||||||
|
KDBounds MakeBounds() {
|
||||||
|
|
||||||
|
Vector3 max = new Vector3(float.MinValue, float.MinValue, float.MinValue);
|
||||||
|
Vector3 min = new Vector3(float.MaxValue, float.MaxValue, float.MaxValue);
|
||||||
|
|
||||||
|
int even = Count & ~1; // calculate even Length
|
||||||
|
|
||||||
|
// min, max calculations
|
||||||
|
// 3n/2 calculations instead of 2n
|
||||||
|
for (int i0 = 0; i0 < even; i0 += 2) {
|
||||||
|
|
||||||
|
int i1 = i0 + 1;
|
||||||
|
|
||||||
|
// X Coords
|
||||||
|
if (points[i0].x > points[i1].x) {
|
||||||
|
// i0 is bigger, i1 is smaller
|
||||||
|
if (points[i1].x < min.x)
|
||||||
|
min.x = points[i1].x;
|
||||||
|
|
||||||
|
if (points[i0].x > max.x)
|
||||||
|
max.x = points[i0].x;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// i1 is smaller, i0 is bigger
|
||||||
|
if (points[i0].x < min.x)
|
||||||
|
min.x = points[i0].x;
|
||||||
|
|
||||||
|
if (points[i1].x > max.x)
|
||||||
|
max.x = points[i1].x;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Y Coords
|
||||||
|
if (points[i0].y > points[i1].y) {
|
||||||
|
// i0 is bigger, i1 is smaller
|
||||||
|
if (points[i1].y < min.y)
|
||||||
|
min.y = points[i1].y;
|
||||||
|
|
||||||
|
if (points[i0].y > max.y)
|
||||||
|
max.y = points[i0].y;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// i1 is smaller, i0 is bigger
|
||||||
|
if (points[i0].y < min.y)
|
||||||
|
min.y = points[i0].y;
|
||||||
|
|
||||||
|
if (points[i1].y > max.y)
|
||||||
|
max.y = points[i1].y;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Z Coords
|
||||||
|
if (points[i0].z > points[i1].z) {
|
||||||
|
// i0 is bigger, i1 is smaller
|
||||||
|
if (points[i1].z < min.z)
|
||||||
|
min.z = points[i1].z;
|
||||||
|
|
||||||
|
if (points[i0].z > max.z)
|
||||||
|
max.z = points[i0].z;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// i1 is smaller, i0 is bigger
|
||||||
|
if (points[i0].z < min.z)
|
||||||
|
min.z = points[i0].z;
|
||||||
|
|
||||||
|
if (points[i1].z > max.z)
|
||||||
|
max.z = points[i1].z;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// if array was odd, calculate also min/max for the last element
|
||||||
|
if(even != Count) {
|
||||||
|
// X
|
||||||
|
if (min.x > points[even].x)
|
||||||
|
min.x = points[even].x;
|
||||||
|
|
||||||
|
if (max.x < points[even].x)
|
||||||
|
max.x = points[even].x;
|
||||||
|
// Y
|
||||||
|
if (min.y > points[even].y)
|
||||||
|
min.y = points[even].y;
|
||||||
|
|
||||||
|
if (max.y < points[even].y)
|
||||||
|
max.y = points[even].y;
|
||||||
|
// Z
|
||||||
|
if (min.z > points[even].z)
|
||||||
|
min.z = points[even].z;
|
||||||
|
|
||||||
|
if (max.z < points[even].z)
|
||||||
|
max.z = points[even].z;
|
||||||
|
}
|
||||||
|
|
||||||
|
KDBounds b = new KDBounds();
|
||||||
|
b.min = min;
|
||||||
|
b.max = max;
|
||||||
|
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Recursive splitting procedure
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="parent">This is where root node goes</param>
|
||||||
|
/// <param name="depth"></param>
|
||||||
|
///
|
||||||
|
void SplitNode(KDNode parent) {
|
||||||
|
|
||||||
|
// center of bounding box
|
||||||
|
KDBounds parentBounds = parent.bounds;
|
||||||
|
Vector3 parentBoundsSize = parentBounds.size;
|
||||||
|
|
||||||
|
// Find axis where bounds are largest
|
||||||
|
int splitAxis = 0;
|
||||||
|
float axisSize = parentBoundsSize.x;
|
||||||
|
|
||||||
|
if (axisSize < parentBoundsSize.y) {
|
||||||
|
splitAxis = 1;
|
||||||
|
axisSize = parentBoundsSize.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (axisSize < parentBoundsSize.z) {
|
||||||
|
splitAxis = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Our axis min-max bounds
|
||||||
|
float boundsStart = parentBounds.min[splitAxis];
|
||||||
|
float boundsEnd = parentBounds.max[splitAxis];
|
||||||
|
|
||||||
|
// Calculate the spliting coords
|
||||||
|
float splitPivot = CalculatePivot(parent.start, parent.end, boundsStart, boundsEnd, splitAxis);
|
||||||
|
|
||||||
|
parent.partitionAxis = splitAxis;
|
||||||
|
parent.partitionCoordinate = splitPivot;
|
||||||
|
|
||||||
|
// 'Spliting' array to two subarrays
|
||||||
|
int splittingIndex = Partition(parent.start, parent.end, splitPivot, splitAxis);
|
||||||
|
|
||||||
|
// Negative / Left node
|
||||||
|
Vector3 negMax = parentBounds.max;
|
||||||
|
negMax[splitAxis] = splitPivot;
|
||||||
|
|
||||||
|
KDNode negNode = GetKDNode();
|
||||||
|
negNode.bounds = parentBounds;
|
||||||
|
negNode.bounds.max = negMax;
|
||||||
|
negNode.start = parent.start;
|
||||||
|
negNode.end = splittingIndex;
|
||||||
|
parent.negativeChild = negNode;
|
||||||
|
|
||||||
|
// Positive / Right node
|
||||||
|
Vector3 posMin = parentBounds.min;
|
||||||
|
posMin[splitAxis] = splitPivot;
|
||||||
|
|
||||||
|
KDNode posNode = GetKDNode();
|
||||||
|
posNode.bounds = parentBounds;
|
||||||
|
posNode.bounds.min = posMin;
|
||||||
|
posNode.start = splittingIndex;
|
||||||
|
posNode.end = parent.end;
|
||||||
|
parent.positiveChild = posNode;
|
||||||
|
|
||||||
|
// check if we are actually splitting it anything
|
||||||
|
// this if check enables duplicate coordinates, but makes construction a bit slower
|
||||||
|
#if KDTREE_DUPLICATES
|
||||||
|
if(negNode.Count != 0 && posNode.Count != 0) {
|
||||||
|
#endif
|
||||||
|
// Constraint function deciding if split should be continued
|
||||||
|
if(ContinueSplit(negNode))
|
||||||
|
SplitNode(negNode);
|
||||||
|
|
||||||
|
|
||||||
|
if(ContinueSplit(posNode))
|
||||||
|
SplitNode(posNode);
|
||||||
|
|
||||||
|
#if KDTREE_DUPLICATES
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sliding midpoint splitting pivot calculation
|
||||||
|
/// 1. First splits node to two equal parts (midPoint)
|
||||||
|
/// 2. Checks if elements are in both sides of splitted bounds
|
||||||
|
/// 3a. If they are, just return midPoint
|
||||||
|
/// 3b. If they are not, then points are only on left or right bound.
|
||||||
|
/// 4. Move the splitting pivot so that it shrinks part with points completely (calculate min or max dependent) and return.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="start"></param>
|
||||||
|
/// <param name="end"></param>
|
||||||
|
/// <param name="boundsStart"></param>
|
||||||
|
/// <param name="boundsEnd"></param>
|
||||||
|
/// <param name="axis"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
float CalculatePivot(int start, int end, float boundsStart, float boundsEnd, int axis) {
|
||||||
|
|
||||||
|
//! sliding midpoint rule
|
||||||
|
float midPoint = (boundsStart + boundsEnd) / 2f;
|
||||||
|
|
||||||
|
bool negative = false;
|
||||||
|
bool positive = false;
|
||||||
|
|
||||||
|
float negMax = Single.MinValue;
|
||||||
|
float posMin = Single.MaxValue;
|
||||||
|
|
||||||
|
// this for loop section is used both for sorted and unsorted data
|
||||||
|
for (int i = start; i < end; i++) {
|
||||||
|
|
||||||
|
if (points[permutation[i]][axis] < midPoint)
|
||||||
|
negative = true;
|
||||||
|
else
|
||||||
|
positive = true;
|
||||||
|
|
||||||
|
if (negative == true && positive == true)
|
||||||
|
return midPoint;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (negative) {
|
||||||
|
|
||||||
|
for (int i = start; i < end; i++)
|
||||||
|
if (negMax < points[permutation[i]][axis])
|
||||||
|
negMax = points[permutation[i]][axis];
|
||||||
|
|
||||||
|
return negMax;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
|
||||||
|
for (int i = start; i < end; i++)
|
||||||
|
if (posMin > points[permutation[i]][axis])
|
||||||
|
posMin = points[permutation[i]][axis];
|
||||||
|
|
||||||
|
return posMin;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Similar to Hoare partitioning algorithm (used in Quick Sort)
|
||||||
|
/// Modification: pivot is not left-most element but is instead argument of function
|
||||||
|
/// Calculates splitting index and partially sorts elements (swaps them until they are on correct side - depending on pivot)
|
||||||
|
/// Complexity: O(n)
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="start">Start index</param>
|
||||||
|
/// <param name="end">End index</param>
|
||||||
|
/// <param name="partitionPivot">Pivot that decides boundary between left and right</param>
|
||||||
|
/// <param name="axis">Axis of this pivoting</param>
|
||||||
|
/// <returns>
|
||||||
|
/// Returns splitting index that subdivides array into 2 smaller arrays
|
||||||
|
/// left = [start, pivot),
|
||||||
|
/// right = [pivot, end)
|
||||||
|
/// </returns>
|
||||||
|
int Partition(int start, int end, float partitionPivot, int axis) {
|
||||||
|
|
||||||
|
// note: increasing right pointer is actually decreasing!
|
||||||
|
int LP = start - 1; // left pointer (negative side)
|
||||||
|
int RP = end; // right pointer (positive side)
|
||||||
|
|
||||||
|
int temp; // temporary var for swapping permutation indexes
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
|
||||||
|
do {
|
||||||
|
// move from left to the right until "out of bounds" value is found
|
||||||
|
LP++;
|
||||||
|
}
|
||||||
|
while (LP < RP && points[permutation[LP]][axis] < partitionPivot);
|
||||||
|
|
||||||
|
do {
|
||||||
|
// move from right to the left until "out of bounds" value found
|
||||||
|
RP--;
|
||||||
|
}
|
||||||
|
while (LP < RP && points[permutation[RP]][axis] >= partitionPivot);
|
||||||
|
|
||||||
|
if (LP < RP) {
|
||||||
|
// swap
|
||||||
|
temp = permutation[LP];
|
||||||
|
permutation[LP] = permutation[RP];
|
||||||
|
permutation[RP] = temp;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
|
||||||
|
return LP;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Constraint function. You can add custom constraints here - if you have some other data/classes binded to Vector3 points
|
||||||
|
/// Can hardcode it into
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="node"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
bool ContinueSplit(KDNode node) {
|
||||||
|
|
||||||
|
return (node.Count > maxPointsPerLeafNode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
13
Assets/Datastructures/KDTree/KDTree.cs.meta
Normal file
13
Assets/Datastructures/KDTree/KDTree.cs.meta
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 437ce4903d14e2f4182fad0f2ac92678
|
||||||
|
timeCreated: 1520696434
|
||||||
|
licenseType: Free
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -1,6 +1,9 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
using DataStructures.ViliWonka.KDTree;
|
||||||
|
using System;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
public class Planet : MonoBehaviour
|
public class Planet : MonoBehaviour
|
||||||
{
|
{
|
||||||
@@ -8,7 +11,10 @@ public class Planet : MonoBehaviour
|
|||||||
private LineRenderer _lineRenderer;
|
private LineRenderer _lineRenderer;
|
||||||
private CircleCollider2D _circleCollider;
|
private CircleCollider2D _circleCollider;
|
||||||
private Network _network;
|
private Network _network;
|
||||||
private HashSet<Unit> _units;
|
private KDQuery _query;
|
||||||
|
public KDTree Tree => _tree;
|
||||||
|
private KDTree _tree;
|
||||||
|
private List<Unit> _units;
|
||||||
|
|
||||||
[SerializeField] public HashSet<Planet> neighbors;
|
[SerializeField] public HashSet<Planet> neighbors;
|
||||||
|
|
||||||
@@ -22,11 +28,14 @@ public class Planet : MonoBehaviour
|
|||||||
{
|
{
|
||||||
_lineRenderer = gameObject.GetComponent<LineRenderer>();
|
_lineRenderer = gameObject.GetComponent<LineRenderer>();
|
||||||
_network = FindObjectOfType<Network>();
|
_network = FindObjectOfType<Network>();
|
||||||
_units = new HashSet<Unit>();
|
_units = new List<Unit>();
|
||||||
}
|
_query = new KDQuery();
|
||||||
|
_tree = new KDTree();
|
||||||
|
|
||||||
void OnEnable()
|
while (_units.Count < 10)
|
||||||
{
|
SpawnUnit();
|
||||||
|
|
||||||
|
InvokeRepeating("ChangeUnits", 0.0f, 1f);
|
||||||
}
|
}
|
||||||
|
|
||||||
void OnMouseDown()
|
void OnMouseDown()
|
||||||
@@ -41,15 +50,74 @@ public class Planet : MonoBehaviour
|
|||||||
return new Vector2(Mathf.Cos(theta), Mathf.Sin(theta)) * radius;
|
return new Vector2(Mathf.Cos(theta), Mathf.Sin(theta)) * radius;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public float GetUnitAngle(Unit unit)
|
||||||
|
{
|
||||||
|
var angle = Mathf.Atan2(unit.transform.position.y, unit.transform.position.x) * Mathf.Rad2Deg;
|
||||||
|
return angle < 0 ? angle + 360 : angle;
|
||||||
|
}
|
||||||
|
|
||||||
void SpawnUnit()
|
void SpawnUnit()
|
||||||
{
|
{
|
||||||
var unitPrefab = Resources.Load<GameObject>("BaseUnit");
|
var unitPrefab = Resources.Load<GameObject>("BaseUnit");
|
||||||
var unitObject = Instantiate(unitPrefab);
|
var unitObject = Instantiate(unitPrefab);
|
||||||
unitObject.transform.position = transform.position;
|
unitObject.transform.position = transform.position;
|
||||||
unitObject.transform.parent = transform;
|
unitObject.transform.parent = transform;
|
||||||
_units.Add(unitObject.GetComponent<Unit>());
|
var unit = unitObject.GetComponent<Unit>();
|
||||||
Debug.Log("Spawned unit " + unitObject.GetComponent<Unit>().GetHashCode());
|
_units.Add(unit);
|
||||||
unitObject.name = "Unit " + _units.Count;
|
unitObject.name = "Unit " + _units.Count;
|
||||||
|
|
||||||
|
|
||||||
|
_tree.SetCount(_tree.Count + 1);
|
||||||
|
var index = _tree.Count - 1;
|
||||||
|
unit.TreeIndex = index;
|
||||||
|
|
||||||
|
_tree.Points[index] = new Vector2(unitObject.transform.position.x, unitObject.transform.position.y);
|
||||||
|
_tree.Rebuild();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void FixedUpdate()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void ChangeUnits()
|
||||||
|
{
|
||||||
|
// Delete 3 units
|
||||||
|
for (int i = 0; i < 3; i++)
|
||||||
|
{
|
||||||
|
if (_units.Count == 0) break;
|
||||||
|
var unit = _units[0];
|
||||||
|
Destroy(unit.gameObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add 4 units
|
||||||
|
for (int i = 0; i < 4; i++)
|
||||||
|
{
|
||||||
|
SpawnUnit();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void OnDrawGizmos()
|
||||||
|
{
|
||||||
|
if (_units.Count == 0) return;
|
||||||
|
|
||||||
|
var origin = _units[0];
|
||||||
|
// Draw sphere on first unit
|
||||||
|
Gizmos.color = Color.red;
|
||||||
|
Gizmos.DrawSphere(origin.transform.position, 0.1f);
|
||||||
|
|
||||||
|
var results = new List<int>();
|
||||||
|
var resultDistances = new List<float>();
|
||||||
|
_query.KNearest(_tree, origin.transform.position, 2, results, resultDistances);
|
||||||
|
|
||||||
|
if (results.Count < 2) return;
|
||||||
|
|
||||||
|
var closestUnit = results[0];
|
||||||
|
|
||||||
|
// Draw line to closest unit
|
||||||
|
Gizmos.color = Color.green;
|
||||||
|
Gizmos.DrawLine(origin.transform.position, _tree.Points[closestUnit]);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsConnected(Planet other)
|
bool IsConnected(Planet other)
|
||||||
@@ -64,6 +132,7 @@ public class Planet : MonoBehaviour
|
|||||||
|
|
||||||
public void UnitDestroyed(Unit unit)
|
public void UnitDestroyed(Unit unit)
|
||||||
{
|
{
|
||||||
|
_tree.Points[unit.TreeIndex] = new Vector2(float.MaxValue, float.MaxValue);
|
||||||
_units.Remove(unit);
|
_units.Remove(unit);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -53,6 +53,7 @@ MonoBehaviour:
|
|||||||
fillColor: {r: 0.509434, g: 0.509434, b: 0.509434, a: 1}
|
fillColor: {r: 0.509434, g: 0.509434, b: 0.509434, a: 1}
|
||||||
edgeColor: {r: 0.1792453, g: 0.1792453, b: 0.1792453, a: 1}
|
edgeColor: {r: 0.1792453, g: 0.1792453, b: 0.1792453, a: 1}
|
||||||
Size: 16
|
Size: 16
|
||||||
|
TreeIndex: 0
|
||||||
--- !u!33 &6421509436193620488
|
--- !u!33 &6421509436193620488
|
||||||
MeshFilter:
|
MeshFilter:
|
||||||
m_ObjectHideFlags: 0
|
m_ObjectHideFlags: 0
|
||||||
@@ -246,7 +247,7 @@ MonoBehaviour:
|
|||||||
m_BlendStyleIndex: 0
|
m_BlendStyleIndex: 0
|
||||||
m_FalloffIntensity: 0.5
|
m_FalloffIntensity: 0.5
|
||||||
m_Color: {r: 1, g: 1, b: 1, a: 1}
|
m_Color: {r: 1, g: 1, b: 1, a: 1}
|
||||||
m_Intensity: 26.48
|
m_Intensity: 30
|
||||||
m_LightVolumeIntensity: 1
|
m_LightVolumeIntensity: 1
|
||||||
m_LightVolumeIntensityEnabled: 0
|
m_LightVolumeIntensityEnabled: 0
|
||||||
m_ApplyToSortingLayers:
|
m_ApplyToSortingLayers:
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
using Random = UnityEngine.Random;
|
||||||
|
|
||||||
public class Unit : MonoBehaviour
|
public class Unit : MonoBehaviour
|
||||||
{
|
{
|
||||||
@@ -9,6 +11,9 @@ public class Unit : MonoBehaviour
|
|||||||
public Color fillColor = Color.white;
|
public Color fillColor = Color.white;
|
||||||
public Color edgeColor = Color.white;
|
public Color edgeColor = Color.white;
|
||||||
public float Size;
|
public float Size;
|
||||||
|
public int TreeIndex;
|
||||||
|
private float RotationSpeed;
|
||||||
|
private float BobbingOffset;
|
||||||
|
|
||||||
void Start()
|
void Start()
|
||||||
{
|
{
|
||||||
@@ -19,15 +24,28 @@ public class Unit : MonoBehaviour
|
|||||||
{
|
{
|
||||||
x = (Random.value > 0.5f ? 1 : -1) * 32 * Random.Range(0.8f, 1.2f),
|
x = (Random.value > 0.5f ? 1 : -1) * 32 * Random.Range(0.8f, 1.2f),
|
||||||
};
|
};
|
||||||
|
RotationSpeed = Random.value > 0.5f ? 1 : -1 * Random.Range(0.8f, 1.2f) * 4f;
|
||||||
|
BobbingOffset = Random.Range(0, (float)(2 * Math.PI));
|
||||||
|
|
||||||
transform.position = planet.GetSurfacePosition(Random.Range(0, 360), 0.4f);
|
transform.position = planet.GetSurfacePosition(Random.Range(0, 360), 0.3f);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Update()
|
void Update()
|
||||||
{
|
{
|
||||||
|
// Rotate itself slightly
|
||||||
|
transform.Rotate(new Vector3(0, 0, Time.deltaTime * RotationSpeed));
|
||||||
transform.RotateAround(planet.transform.position, Vector3.forward, planetaryVelocity.x * Time.deltaTime);
|
transform.RotateAround(planet.transform.position, Vector3.forward, planetaryVelocity.x * Time.deltaTime);
|
||||||
transform.position = Vector2.MoveTowards(transform.position, planet.transform.position, planetaryVelocity.y * Time.deltaTime);
|
|
||||||
|
// Bobbing motion
|
||||||
|
var unitAngle = planet.GetUnitAngle(this);
|
||||||
|
var targetDistance = (Mathf.Sin(BobbingOffset + Time.time) + 1) / 2;
|
||||||
|
targetDistance = Mathf.Lerp(0.35f, 0.8f, targetDistance);
|
||||||
|
if (TreeIndex == 0)
|
||||||
|
Debug.Log(targetDistance);
|
||||||
|
transform.position = planet.GetSurfacePosition(unitAngle, targetDistance);
|
||||||
|
|
||||||
|
planet.Tree.Points[TreeIndex] = transform.position;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnDestroy()
|
private void OnDestroy()
|
||||||
|
|||||||
Reference in New Issue
Block a user