ObjectPlacementBoxStack.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322
  1. #if UNITY_EDITOR
  2. using UnityEngine;
  3. using System.Collections.Generic;
  4. namespace O3DWB
  5. {
  6. public class ObjectPlacementBoxStack
  7. {
  8. #region Private Variables
  9. private Vector3 _growDirection;
  10. private bool _isGrowingDownwards = false;
  11. private Vector3 _basePosition = Vector3.zero;
  12. private Quaternion _rotation = Quaternion.identity;
  13. private TransformMatrix _rotationMatrix = TransformMatrix.GetIdentity();
  14. private float _paddingAlongGrowDirection = 0.0f;
  15. private ObjectPlacementBoxStackOverlapData _overlapData = new ObjectPlacementBoxStackOverlapData();
  16. private Vector3 _boxSize = Vector3.one;
  17. private List<ObjectPlacementBox> _boxes = new List<ObjectPlacementBox>();
  18. #endregion
  19. #region Public Properties
  20. public int NumberOfBoxes { get { return _boxes.Count; } }
  21. public Vector3 BasePosition { get { return _basePosition; } }
  22. public Quaternion Rotation { get { return _rotation; } }
  23. public bool IsOverlappedByAnotherStack { get { return _overlapData.IsOverlappedByAnotherStack; ; } set { _overlapData.IsOverlappedByAnotherStack = value; } }
  24. public TransformMatrix RotationMatrix { get { return _rotationMatrix; } }
  25. public Vector3 UpAxis { get { return _rotationMatrix.GetNormalizedUpAxis(); } }
  26. public Vector3 GrowDirection { get { return IsGrowingUpwards ? _growDirection : -_growDirection; } }
  27. public float PaddingAlongGrowDirection { get { return _paddingAlongGrowDirection; } }
  28. public bool IsGrowingUpwards { get { return !_isGrowingDownwards; } }
  29. public bool IsGrowingDownwards { get { return _isGrowingDownwards; } }
  30. public int Height { get { return NumberOfBoxes * (IsGrowingUpwards ? 1 : -1); } }
  31. public Vector3 BoxSize { get { return _boxSize; } }
  32. #endregion
  33. #region Constructors
  34. public ObjectPlacementBoxStack()
  35. {
  36. _growDirection = UpAxis;
  37. }
  38. #endregion
  39. #region Public Methods
  40. public List<OrientedBox> GetAllOrientedBoxes()
  41. {
  42. var allOrientedBoxes = new List<OrientedBox>();
  43. foreach (var box in _boxes) allOrientedBoxes.Add(box.OrientedBox);
  44. return allOrientedBoxes;
  45. }
  46. public ObjectPlacementBox GetBoxByIndex(int boxIndex)
  47. {
  48. return _boxes[boxIndex];
  49. }
  50. public Plane GetBasePlane()
  51. {
  52. Vector3 growDirection = GrowDirection;
  53. Vector3 pointOnPlane = BasePosition - growDirection * GetBoxSizeAlongNormalizedDirection(growDirection) * 0.5f;
  54. return new Plane(growDirection, pointOnPlane);
  55. }
  56. public float GetBoxSizeAlongNormalizedDirection(Vector3 direction)
  57. {
  58. Vector3 transformedBoxSizeVector = RotationMatrix.MultiplyVector(_boxSize);
  59. return direction.GetAbsDot(transformedBoxSizeVector);
  60. }
  61. public void PlaceOnPlane(Plane plane)
  62. {
  63. Vector3 upAxis = UpAxis;
  64. if (plane.normal.IsAlignedWith(upAxis))
  65. {
  66. Vector3 projectedBasePosition = plane.ProjectPoint(BasePosition);
  67. Vector3 desiredBasePosition = projectedBasePosition + upAxis * GetBoxSizeAlongNormalizedDirection(upAxis) * 0.5f;
  68. SetBasePosition(desiredBasePosition);
  69. }
  70. }
  71. // Note: This method will reset any hide flags assigned to the placement boxes.
  72. public void SetGrowDirection(Vector3 growDirection)
  73. {
  74. _growDirection = growDirection;
  75. int numberOfBoxes = NumberOfBoxes;
  76. RemoveAllBoxes();
  77. if (_isGrowingDownwards) GrowDownwards(numberOfBoxes);
  78. else GrowUpwards(numberOfBoxes);
  79. }
  80. public void SetBoxSize(Vector3 boxSize)
  81. {
  82. _boxSize = boxSize;
  83. if(NumberOfBoxes != 0)
  84. {
  85. for (int boxIndex = 0; boxIndex < NumberOfBoxes; ++boxIndex)
  86. {
  87. ObjectPlacementBox box = _boxes[boxIndex];
  88. box.ModelSpaceSize = boxSize;
  89. if(boxIndex > 0) box.Center = CalculateBoxCenterToSitRightAfterBox(_boxes[boxIndex - 1]);
  90. }
  91. }
  92. }
  93. public void SetRotation(Quaternion rotation)
  94. {
  95. Quaternion relativeRotation = _rotation.GetRelativeRotation(rotation);
  96. _growDirection = relativeRotation * _growDirection;
  97. _rotation = rotation;
  98. _rotationMatrix = new TransformMatrix(Vector3.zero, _rotation, Vector3.one);
  99. foreach (ObjectPlacementBox box in _boxes)
  100. {
  101. Vector3 newBoxCenter = box.Center - _basePosition;
  102. newBoxCenter = relativeRotation * newBoxCenter;
  103. newBoxCenter += _basePosition;
  104. box.Center = newBoxCenter;
  105. box.Rotation = _rotation;
  106. }
  107. }
  108. // Note: This method will reset any hide flags assigned to the placement boxes.
  109. public void SetHeight(int height)
  110. {
  111. RemoveAllBoxes();
  112. if (height == 0) return;
  113. float boxSizeAlongGrow = GetBoxSizeAlongNormalizedDirection(GrowDirection);
  114. if (boxSizeAlongGrow < GetMinAllowedBoxSizeForGrow())
  115. {
  116. float sign = Mathf.Sign(height);
  117. height = (int)(1.0f * sign);
  118. }
  119. _isGrowingDownwards = height < 0;
  120. if (IsGrowingUpwards) GrowUpwards(height);
  121. else GrowDownwards(Mathf.Abs(height));
  122. }
  123. public void SetBasePosition(Vector3 basePosition)
  124. {
  125. Vector3 boxMoveOffset = basePosition - _basePosition;
  126. _basePosition = basePosition;
  127. OffsetBoxes(boxMoveOffset);
  128. }
  129. public void SetPaddingAlongGrowDirection(float paddingAlongGrowDirection)
  130. {
  131. if (paddingAlongGrowDirection == _paddingAlongGrowDirection) return;
  132. _paddingAlongGrowDirection = paddingAlongGrowDirection;
  133. for (int boxIndex = 1; boxIndex < NumberOfBoxes; ++boxIndex)
  134. {
  135. _boxes[boxIndex].Center = CalculateBoxCenterToSitRightAfterBox(_boxes[boxIndex - 1]);
  136. }
  137. }
  138. public void MoveBasePosition(Vector3 moveVector)
  139. {
  140. SetBasePosition(_basePosition + moveVector);
  141. }
  142. public void RemoveAllBoxes()
  143. {
  144. _boxes.Clear();
  145. }
  146. public void GrowUpwards(int amount)
  147. {
  148. if (amount <= 0) return;
  149. if (IsHeightRestrictedToOne() && Height == 1) return;
  150. if (!IsGrowingUpwards)
  151. {
  152. int numberOfRemovedBoxes = RemoveBoxesFromTopOfStack(amount);
  153. if (numberOfRemovedBoxes < amount)
  154. {
  155. _isGrowingDownwards = false;
  156. int remainingBoxes = amount - numberOfRemovedBoxes;
  157. CreateNewBoxesOnTopOfStack(remainingBoxes);
  158. }
  159. }
  160. else CreateNewBoxesOnTopOfStack(amount);
  161. }
  162. public void GrowDownwards(int amount)
  163. {
  164. if (amount <= 0) return;
  165. if (IsHeightRestrictedToOne() && Height == 1) return;
  166. if (!IsGrowingDownwards)
  167. {
  168. int numberOfRemovedBoxes = RemoveBoxesFromTopOfStack(amount);
  169. if (numberOfRemovedBoxes < amount)
  170. {
  171. _isGrowingDownwards = true;
  172. int remainingBoxes = amount - numberOfRemovedBoxes;
  173. CreateNewBoxesOnTopOfStack(remainingBoxes);
  174. }
  175. }
  176. else CreateNewBoxesOnTopOfStack(amount);
  177. }
  178. public Vector3 GetBasePositionConnectionVectorTo(ObjectPlacementBoxStack stack)
  179. {
  180. Plane basePlane = GetBasePlane();
  181. Vector3 projectedThisBasePos = basePlane.ProjectPoint(BasePosition);
  182. Vector3 projectedStackBasePos = basePlane.ProjectPoint(stack.BasePosition);
  183. return projectedStackBasePos - projectedThisBasePos;
  184. }
  185. public Vector3 GetNormalizedBasePositionConnectionVectorTo(ObjectPlacementBoxStack stack)
  186. {
  187. Vector3 connectionVector = GetBasePositionConnectionVectorTo(stack);
  188. connectionVector.Normalize();
  189. return connectionVector;
  190. }
  191. public void ClearHideFlagForAllBoxes(ObjectPlacementBoxHideFlags hideFlag)
  192. {
  193. foreach(ObjectPlacementBox box in _boxes)
  194. {
  195. box.ClearHideFlag(hideFlag);
  196. }
  197. }
  198. public void SetHideFlagForAllBoxes(ObjectPlacementBoxHideFlags hideFlag)
  199. {
  200. foreach (ObjectPlacementBox box in _boxes)
  201. {
  202. box.SetHideFlag(hideFlag);
  203. }
  204. }
  205. #endregion
  206. #region Private Methods
  207. private void OffsetBoxes(Vector3 offset)
  208. {
  209. foreach(ObjectPlacementBox box in _boxes)
  210. {
  211. box.Center = box.Center + offset;
  212. }
  213. }
  214. private void CreateNewBoxesOnTopOfStack(int numberOfBoxes)
  215. {
  216. for (int boxIndex = 0; boxIndex < numberOfBoxes; ++boxIndex)
  217. {
  218. CreateNewBoxOnTopOfStack();
  219. }
  220. }
  221. private void CreateNewBoxOnTopOfStack()
  222. {
  223. var newBox = new ObjectPlacementBox();
  224. newBox.Rotation = _rotation;
  225. newBox.ModelSpaceSize = _boxSize;
  226. newBox.Center = CalculateNewBoxCenterToSitOnTopOfStack();
  227. _boxes.Add(newBox);
  228. }
  229. private Vector3 CalculateNewBoxCenterToSitOnTopOfStack()
  230. {
  231. if (NumberOfBoxes == 0) return _basePosition;
  232. return CalculateBoxCenterToSitRightAfterBox(_boxes[NumberOfBoxes - 1]);
  233. }
  234. private Vector3 CalculateBoxCenterToSitRightAfterBox(ObjectPlacementBox afterBox)
  235. {
  236. return afterBox.Center + GrowDirection * (GetBoxSizeAlongNormalizedDirection(GrowDirection) + _paddingAlongGrowDirection);
  237. }
  238. private int RemoveBoxesFromTopOfStack(int numberOfBoxes)
  239. {
  240. int numberOfRemovedBoxes = 0;
  241. for (int boxIndex = 0; boxIndex < numberOfBoxes; ++boxIndex)
  242. {
  243. if (RemoveBoxFromTopOfStack()) ++numberOfRemovedBoxes;
  244. }
  245. return numberOfRemovedBoxes;
  246. }
  247. private bool RemoveBoxFromTopOfStack()
  248. {
  249. if (NumberOfBoxes > 0)
  250. {
  251. _boxes.RemoveAt(NumberOfBoxes - 1);
  252. return true;
  253. }
  254. return false;
  255. }
  256. private bool IsHeightRestrictedToOne()
  257. {
  258. return GetBoxSizeAlongNormalizedDirection(GrowDirection) >= GetMinAllowedBoxSizeForGrow();
  259. }
  260. private float GetMinAllowedBoxSizeForGrow()
  261. {
  262. return 1e-4f;
  263. }
  264. #endregion
  265. }
  266. }
  267. #endif