NearPointSearch.cs 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  1. // Magica Cloth.
  2. // Copyright (c) MagicaSoft, 2020-2022.
  3. // https://magicasoft.jp
  4. using System.Collections.Generic;
  5. using Unity.Mathematics;
  6. namespace MagicaCloth
  7. {
  8. /// <summary>
  9. /// ポイントリストからその中で最も距離が近いペアを検索する
  10. /// ※これはエディタ用でランタイムでの用途には設計されていません。
  11. /// </summary>
  12. public class NearPointSearch : GridHash
  13. {
  14. float radius;
  15. Dictionary<int, int> nearDict = new Dictionary<int, int>();
  16. Dictionary<int, float> distDict = new Dictionary<int, float>();
  17. HashSet<uint> lockPairSet = new HashSet<uint>();
  18. /// <summary>
  19. /// 初期化
  20. /// </summary>
  21. /// <param name="positionList">対象となるポイントリスト</param>
  22. /// <param name="radius">各点の検索半径</param>
  23. public void Create(float3[] positionList, float radius)
  24. {
  25. base.Create(radius);
  26. this.radius = radius;
  27. // グリッドにポイントを追加
  28. for (int i = 0; i < positionList.Length; i++)
  29. {
  30. AddPoint(positionList[i], i);
  31. }
  32. }
  33. /// <summary>
  34. /// すべてのポイントの近接インデックスを算出しバッファに格納する
  35. /// </summary>
  36. public void SearchNearPointAll()
  37. {
  38. foreach (var plist in gridMap.Values)
  39. {
  40. foreach (var p in plist)
  41. {
  42. SearchNearPoint(p.id, p.pos);
  43. }
  44. }
  45. }
  46. /// <summary>
  47. /// 指定インデックス1つの近接インデックスを算出しバッファに格納する
  48. /// </summary>
  49. /// <param name="id"></param>
  50. /// <param name="pos"></param>
  51. public void SearchNearPoint(int id, float3 pos)
  52. {
  53. int nearId = -1;
  54. float nearDist = 100000.0f;
  55. // 範囲内のグリッドを走査してもっとも近いポイントを算出する
  56. int3 sgrid = GetGridPos(pos - radius, gridSize);
  57. int3 egrid = GetGridPos(pos + radius, gridSize);
  58. for (int x = sgrid.x; x <= egrid.x; x++)
  59. {
  60. for (int y = sgrid.y; y <= egrid.y; y++)
  61. {
  62. for (int z = sgrid.z; z <= egrid.z; z++)
  63. {
  64. uint hash = GetGridHash(new int3(x, y, z));
  65. // このグリッドを検索する
  66. if (gridMap.ContainsKey(hash))
  67. {
  68. var plist = gridMap[hash];
  69. foreach (var p in plist)
  70. {
  71. // 自身は弾く
  72. if (p.id == id)
  73. continue;
  74. // 距離判定
  75. float dist = math.length(pos - p.pos);
  76. if (dist < nearDist)
  77. {
  78. nearId = p.id;
  79. nearDist = dist;
  80. }
  81. }
  82. }
  83. }
  84. }
  85. }
  86. // 結果格納
  87. if (nearId >= 0)
  88. {
  89. nearDict[id] = nearId;
  90. distDict[id] = nearDist;
  91. }
  92. else
  93. {
  94. if (nearDict.ContainsKey(id))
  95. {
  96. nearDict.Remove(id);
  97. distDict.Remove(id);
  98. }
  99. }
  100. }
  101. /// <summary>
  102. /// 指定範囲の近接頂点を再計算する
  103. /// </summary>
  104. /// <param name="pos"></param>
  105. /// <param name="r"></param>
  106. public void SearchNearPoint(float3 pos, float r)
  107. {
  108. int3 sgrid = GetGridPos(pos - r, gridSize);
  109. int3 egrid = GetGridPos(pos + r, gridSize);
  110. for (int x = sgrid.x; x <= egrid.x; x++)
  111. {
  112. for (int y = sgrid.y; y <= egrid.y; y++)
  113. {
  114. for (int z = sgrid.z; z <= egrid.z; z++)
  115. {
  116. uint hash = GetGridHash(new int3(x, y, z));
  117. if (gridMap.ContainsKey(hash))
  118. {
  119. var plist = gridMap[hash];
  120. foreach (var p in plist)
  121. {
  122. SearchNearPoint(p.id, p.pos);
  123. }
  124. }
  125. }
  126. }
  127. }
  128. }
  129. public override void AddPoint(float3 pos, int id)
  130. {
  131. base.AddPoint(pos, id);
  132. }
  133. public override void Remove(float3 pos, int id)
  134. {
  135. base.Remove(pos, id);
  136. if (nearDict.ContainsKey(id))
  137. {
  138. nearDict.Remove(id);
  139. distDict.Remove(id);
  140. }
  141. }
  142. public void AddLockPair(int id1, int id2)
  143. {
  144. uint pair = DataUtility.PackPair(id1, id2);
  145. lockPairSet.Add(pair);
  146. }
  147. /// <summary>
  148. /// バッファ内の最も近接にあるペアを返す
  149. /// </summary>
  150. /// <param name="id1"></param>
  151. /// <param name="id2"></param>
  152. /// <returns></returns>
  153. public bool GetNearPointPair(out int id1, out int id2)
  154. {
  155. int index = -1;
  156. int nearIndex = -1;
  157. float nearDist = 100000.0f;
  158. foreach (var keyval in nearDict)
  159. {
  160. int id = keyval.Key;
  161. int nearId = keyval.Value;
  162. if (nearId == -1)
  163. continue;
  164. // ロックペアならスルー
  165. uint pair = DataUtility.PackPair(id, nearId);
  166. if (lockPairSet.Contains(pair))
  167. continue;
  168. float dist = distDict[id];
  169. if (dist > radius)
  170. continue;
  171. if (dist < nearDist)
  172. {
  173. index = id;
  174. nearIndex = nearId;
  175. nearDist = dist;
  176. }
  177. }
  178. if (index >= 0 && nearIndex >= 0)
  179. {
  180. id1 = index;
  181. id2 = nearIndex;
  182. return true;
  183. }
  184. else
  185. {
  186. id1 = -1;
  187. id2 = -1;
  188. return false;
  189. }
  190. }
  191. public override string ToString()
  192. {
  193. string str = "";
  194. foreach (var keyval in nearDict)
  195. {
  196. str += string.Format("[{0}] -> {1} {2}\n", keyval.Key, keyval.Value, distDict[keyval.Key]);
  197. }
  198. return str;
  199. }
  200. }
  201. }