Files
ZeroVR/ZeroPacientVR/Assets/Octave3D World Builder/Scripts/Objects/Object Placement/Path/ObjectPlacementPathManualConstructionSession.cs
T
2022-04-18 19:17:20 +03:00

650 lines
36 KiB
C#

#if UNITY_EDITOR
using UnityEngine;
using UnityEditor;
using System.Collections.Generic;
namespace O3DWB
{
public class ObjectPlacementPathManualConstructionSession
{
#region Private Variables
private ObjectPlacementPath _path;
private ObjectPlacementPathSettings _pathSettings;
private ObjectPlacementPathTileConnectionSettings _tileConnectionSettings;
private List<ObjectPlacementPathTileConnectionGridCell> _tileConnectionGridCells;
private ObjectPlacementPathManualConstructionSettings _manualConstructionSettings;
private ObjectPlacementPathHeightAdjustmentSettings _heightAdjustmentSettings;
private ObjectPlacementPathPaddingSettings _paddingSettings;
private ObjectPlacementPathBorderSettings _borderSettings;
private List<ObjectPlacementBoxStackSegment> _pathSegments;
private ObjectPlacementExtensionPlane _pathExtensionPlane;
private GameObject _startObject;
private OrientedBox _startObjectHierarchyWorldOrientedBox;
private float _tileConnectionXZSize;
private ObjectPlacementPathManualHeightAdjuster _manualHeightAdjuster = new ObjectPlacementPathManualHeightAdjuster();
private int _currentManualPathHeight = 1;
private ObjectPlacementPathAutomaticRandomHeightAdjuster _automaticRandomHeightAdjuster = new ObjectPlacementPathAutomaticRandomHeightAdjuster();
private ObjectPlacementPathAutomaticPatternHeightAdjuster _automaticPatternHeightAdjuster = new ObjectPlacementPathAutomaticPatternHeightAdjuster();
private ObjectPlacementPathBorderApplyOperation _borderApplyOperation = new ObjectPlacementPathBorderApplyOperation();
private ObjectPlacementPathTileConnectionDetector _tileConnectionDetector = new ObjectPlacementPathTileConnectionDetector();
private PathNoTileConnectionsObjectPlacementDataCaculator _pathNoTileConnectionsObjectPlacementDataCalculator = new PathNoTileConnectionsObjectPlacementDataCaculator();
private PathWithTileConnectionsObjectPlacementDataCalculator _pathWithTileConnectionsObjectPlacementDataCalculator = new PathWithTileConnectionsObjectPlacementDataCalculator();
private bool _isActive = false;
#endregion
#region Private Properties
private ObjectPlacementBoxStackSegment LastSegment { get { return _pathSegments.Count != 0 ? _pathSegments[_pathSegments.Count - 1] : null; } }
private ObjectPlacementBoxStackSegment PenultimateSegment { get { return _pathSegments.Count > 1 ? _pathSegments[_pathSegments.Count - 2] : null; } }
#endregion
#region Public Properties
public bool IsActive { get { return _isActive; } }
#endregion
#region Public Methods
public void SetData(ObjectPlacementPathManualConstructionSessionData sessionData)
{
if(!_isActive)
{
_path = sessionData.Path;
_pathSegments = sessionData.PathSegments;
_pathExtensionPlane = sessionData.PathExtensionPlane;
_tileConnectionGridCells = sessionData.TileConnectionGridCells;
_startObject = sessionData.StartObject;
_startObjectHierarchyWorldOrientedBox = _startObject.GetHierarchyWorldOrientedBox();
_pathSettings = _path.Settings;
_tileConnectionSettings = _pathSettings.TileConnectionSettings;
_manualConstructionSettings = _pathSettings.ManualConstructionSettings;
_heightAdjustmentSettings = _manualConstructionSettings.HeightAdjustmentSettings;
_paddingSettings = _manualConstructionSettings.PaddingSettings;
_borderSettings = _manualConstructionSettings.BorderSettings;
_pathNoTileConnectionsObjectPlacementDataCalculator.Path = _path;
_pathWithTileConnectionsObjectPlacementDataCalculator.Path = _path;
}
}
public void Begin()
{
if (CanBegin())
{
_isActive = true;
_currentManualPathHeight = 1;
_pathSegments.Clear();
if (_tileConnectionSettings.UseTileConnections) EstablshTileConnectionXZSize();
CreateFirst2Segments();
}
}
public List<ObjectPlacementData> End()
{
if(_isActive)
{
_isActive = false;
RemoveSegmentsWithNoStacks();
if (_tileConnectionSettings.UseTileConnections) return _pathWithTileConnectionsObjectPlacementDataCalculator.Calculate();
else return _pathNoTileConnectionsObjectPlacementDataCalculator.Calculate();
}
return new List<ObjectPlacementData>();
}
public void Cancel()
{
_isActive = false;
}
public void ManualRaisePath()
{
if (CanManualRaiseOrLowerPath())
{
_currentManualPathHeight = _manualHeightAdjuster.Raise(_path, _currentManualPathHeight);
if (_borderSettings.UseBorders) _borderApplyOperation.ApplyBordersToAllPathSegments(_pathSegments, _borderSettings);
}
}
public void ManualLowerPath()
{
if (CanManualRaiseOrLowerPath())
{
_currentManualPathHeight = _manualHeightAdjuster.Lower(_path, _currentManualPathHeight);
if (_borderSettings.UseBorders) _borderApplyOperation.ApplyBordersToAllPathSegments(_pathSegments, _borderSettings);
}
}
public void UpdateForMouseMoveEvent()
{
if (_isActive) ExtendOrShrinkPathAlongExtensionPlane();
}
public void Attach2NewSegments()
{
if(_isActive)
{
RemoveSegmentsWithNoStacks();
// First create the 2 new segments which will replace the current penultimate and last segments
ObjectPlacementBoxStackSegment oldLastSegment = LastSegment;
ObjectPlacementBoxStackSegment newPenultimateSegment = CreateNewSegment();
CreateNewSegment();
// We will want the first stack in the new penultimate segment to replace the last stack in 'LastSegment'.
// Otherwise, when this function is called, an additional box will suddenly appear in the scene apparently
// out of nowhere and it doesn't look very good. Not to mention that it can be quite confusing :).
oldLastSegment.Shrink(1);
newPenultimateSegment.Extend(1);
newPenultimateSegment.SetExtensionDirection(oldLastSegment.ExtensionDirection);
if (CanRotateObjectsToFollowPath())
{
newPenultimateSegment.SetRotationForAllStacks(oldLastSegment.StackRotation);
MakeSegmentFollowPath(LastSegment);
}
newPenultimateSegment.ConnectFirstStackToLastStackInSegment(oldLastSegment, CalculateSegmentConnectionOffset(newPenultimateSegment, oldLastSegment));
AdjustHeightForEntireSegment(PenultimateSegment);
UpdateStackOverlapDataForLast2Segments();
if (_borderSettings.UseBorders) _borderApplyOperation.ApplyBordersToAllPathSegments(_pathSegments, _borderSettings);
if (_tileConnectionSettings.UseTileConnections) UpdateTileConnectionInformation();
}
}
public void RemoveLast2Segments()
{
if(_isActive)
{
_pathSegments.RemoveLast();
_pathSegments.RemoveLast();
if (_pathSegments.Count == 0) End();
}
}
public void OnExcludeCornersSettingsChanged()
{
if (_isActive && !_tileConnectionSettings.UseTileConnections)
{
ReconnectAllSegments();
HandleStackOverlapForAllStacksInAllSegments();
if (_borderSettings.UseBorders) _borderApplyOperation.ApplyBordersToAllPathSegments(_pathSegments, _borderSettings);
SceneView.RepaintAll();
}
}
public void OnRotateObjectsToFollowPathSettingsChanged()
{
if (_isActive && !_tileConnectionSettings.UseTileConnections)
{
AdjustRotationForAllSegments();
ReconnectAllSegments();
HandleStackOverlapForAllStacksInAllSegments();
if (_borderSettings.UseBorders) _borderApplyOperation.ApplyBordersToAllPathSegments(_pathSegments, _borderSettings);
SceneView.RepaintAll();
}
}
public void OnPaddingSettingsChanged()
{
if (_isActive && !_tileConnectionSettings.UseTileConnections)
{
ObjectPlacementBoxStackSegmentActions.SetPaddingForSegments(_pathSegments, _paddingSettings.PaddingAlongExtensionPlane, _paddingSettings.PaddingAlongGrowDirection);
ReconnectAllSegments();
HandleStackOverlapForAllStacksInAllSegments();
if (_borderSettings.UseBorders) _borderApplyOperation.ApplyBordersToAllPathSegments(_pathSegments, _borderSettings);
SceneView.RepaintAll();
}
}
public void OnBorderSettingsChanged()
{
if (_isActive)
{
if (_borderSettings.UseBorders) _borderApplyOperation.ApplyBordersToAllPathSegments(_pathSegments, _borderSettings);
else ObjectPlacementBoxStackSegmentActions.ClearHideFlagsForAllStacksInSegments(_pathSegments, ObjectPlacementBoxHideFlags.PathApplyBorders);
SceneView.RepaintAll();
}
}
public void OnHeightAdjustmentModeChanged()
{
if (_isActive)
{
AdjustHeightForAllStacksInPath();
if (_borderSettings.UseBorders) _borderApplyOperation.ApplyBordersToAllPathSegments(_pathSegments, _borderSettings);
SceneView.RepaintAll();
}
}
public void OnAutomaticRandomHeightAdjustmentSettingsChanged()
{
if (_isActive)
{
AdjustHeightForAllStacksInPath();
if (_borderSettings.UseBorders) _borderApplyOperation.ApplyBordersToAllPathSegments(_pathSegments, _borderSettings);
SceneView.RepaintAll();
}
}
public void OnAutomaticPatternHeightAdjustmentSettingsChanged()
{
if (_isActive)
{
AdjustHeightForAllStacksInPath();
if (_borderSettings.UseBorders) _borderApplyOperation.ApplyBordersToAllPathSegments(_pathSegments, _borderSettings);
SceneView.RepaintAll();
}
}
public void OnHeightPatternRemoved()
{
if(_isActive && _heightAdjustmentSettings.HeightAdjustmentMode == ObjectPlacementPathHeightAdjustmentMode.AutomaticPattern)
{
ObjectPlacementPathHeightPattern activePattern = ObjectPlacementPathHeightPatternDatabase.Get().ActivePattern;
if (activePattern != null)
{
AdjustHeightForAllStacksInPath();
if (_borderSettings.UseBorders) _borderApplyOperation.ApplyBordersToAllPathSegments(_pathSegments, _borderSettings);
}
else
{
Debug.LogWarning("There is no height pattern currently available. Path construction was cancelled.");
End();
}
SceneView.RepaintAll();
}
}
public void OnNewHeightPatternWasActivated()
{
if (_isActive && _heightAdjustmentSettings.HeightAdjustmentMode == ObjectPlacementPathHeightAdjustmentMode.AutomaticPattern)
{
AdjustHeightForAllStacksInPath();
if (_borderSettings.UseBorders) _borderApplyOperation.ApplyBordersToAllPathSegments(_pathSegments, _borderSettings);
SceneView.RepaintAll();
}
}
#endregion
#region Private Methods
private bool CanBegin()
{
return !_isActive && IsSessionDataReady();
}
private bool CanRotateObjectsToFollowPath()
{
return _manualConstructionSettings.RotateObjectsToFollowPath && !_tileConnectionSettings.UseTileConnections;
}
private bool CanUsePadding()
{
return !_tileConnectionSettings.UseTileConnections;
}
private bool CanExcludeCorners()
{
return _manualConstructionSettings.ExcludeCorners && !_tileConnectionSettings.UseTileConnections;
}
private bool CanManualRaiseOrLowerPath()
{
return _isActive && _heightAdjustmentSettings.HeightAdjustmentMode == ObjectPlacementPathHeightAdjustmentMode.Manual;
}
private void EstablshTileConnectionXZSize()
{
if(_pathSettings.TileConnectionSettings.UsesSprites())
{
Vector3 scaledSize = _startObjectHierarchyWorldOrientedBox.ScaledSize;
_tileConnectionXZSize = (scaledSize.x + scaledSize.y) * 0.5f;
_pathWithTileConnectionsObjectPlacementDataCalculator.TileConnectionXZSize = _tileConnectionXZSize;
}
else
{
Vector3 scaledSize = _startObjectHierarchyWorldOrientedBox.ScaledSize;
_tileConnectionXZSize = (scaledSize.x + scaledSize.z) * 0.5f;
_pathWithTileConnectionsObjectPlacementDataCalculator.TileConnectionXZSize = _tileConnectionXZSize;
}
}
private bool IsSessionDataReady()
{
bool isReady = (_path != null && _pathSegments != null && _startObject != null && _pathExtensionPlane != null);
if (!isReady) return false;
if (_heightAdjustmentSettings.HeightAdjustmentMode == ObjectPlacementPathHeightAdjustmentMode.AutomaticPattern &&
ObjectPlacementPathHeightPatternDatabase.Get().ActivePattern == null)
{
Debug.LogWarning("Can not begin path construction because the automatic pattern height adjustment mode is selected but there is no active pattern.");
isReady = false;
}
if (_tileConnectionSettings.UseTileConnections && !_tileConnectionSettings.DoAllTileConnectionsHavePrefabAssociated(true))
{
Debug.LogWarning("You are using tile connections, but not all tiles have an associated prefab. Please associate a prefab with each tile in order to being path construction.");
isReady = false;
}
OrientedBox hierarchyWorldOrientedBox = _startObject.GetHierarchyWorldOrientedBox();
float absSizeRight = hierarchyWorldOrientedBox.GetRotatedAndScaledSizeAlongDirection(_pathExtensionPlane.RightAxis);
float absSizeLook = hierarchyWorldOrientedBox.GetRotatedAndScaledSizeAlongDirection(_pathExtensionPlane.LookAxis);
if(absSizeRight < 1e-4f || absSizeLook < 1e-4f)
{
Debug.LogWarning("Can not begin path construction because the object has a 0 size component along the extention plane axes.");
isReady = false;
}
return isReady;
}
private void RemoveSegmentsWithNoStacks()
{
_pathSegments.RemoveAll(item => item.NumberOfStacks == 0);
}
private void CreateFirst2Segments()
{
CreateNewSegment();
CreateNewSegment();
Vector3 camLookAxis = SceneViewCamera.Camera.transform.forward;
Vector3 penultimateSegmentDir = _pathExtensionPlane.LookAxis;
if(Mathf.Abs(Vector3.Dot(camLookAxis, _pathExtensionPlane.LookAxis)) <
Mathf.Abs(Vector3.Dot(camLookAxis, _pathExtensionPlane.RightAxis)))
{
penultimateSegmentDir = _pathExtensionPlane.RightAxis;
}
PenultimateSegment.SetFirstStackBasePosition(_startObjectHierarchyWorldOrientedBox.Center);
PenultimateSegment.SetExtensionDirection(penultimateSegmentDir);
PenultimateSegment.Extend(1);
AdjustHeightForEntireSegment(PenultimateSegment);
}
private ObjectPlacementBoxStackSegment CreateNewSegment()
{
var newSegment = new ObjectPlacementBoxStackSegment();
newSegment.SetRotationForAllStacks(_startObjectHierarchyWorldOrientedBox.Rotation);
newSegment.SetBoxSizeForAllStacks(GetSegmentBoxSize());
newSegment.SetExtensionDirection(_pathExtensionPlane.LookAxis);
newSegment.SetGrowAxis(_pathExtensionPlane.UpAxis);
if (CanUsePadding())
{
newSegment.SetPaddingAlongStackGrowDirection(_paddingSettings.PaddingAlongGrowDirection);
newSegment.SetPaddingAlongExtensionDirection(_paddingSettings.PaddingAlongExtensionPlane);
}
_pathSegments.Add(newSegment);
return newSegment;
}
private Vector3 GetSegmentBoxSize()
{
if (_tileConnectionSettings.UseTileConnections)
{
if (_pathSettings.TileConnectionSettings.UsesSprites()) return new Vector3(_tileConnectionXZSize, _tileConnectionXZSize, _startObjectHierarchyWorldOrientedBox.ScaledSize.z);
return new Vector3(_tileConnectionXZSize, _startObjectHierarchyWorldOrientedBox.ScaledSize.y, _tileConnectionXZSize);
}
else return _startObjectHierarchyWorldOrientedBox.ScaledSize;
}
private void ExtendOrShrinkPathAlongExtensionPlane()
{
// Construct a new extension plane in order to take into account the block's Y offset. Otherwise,
// it becomes harder to control the block extension.
Plane extensionPlane = _pathExtensionPlane.Plane;
Vector3 pointOnBlockExtensionPlane = _pathExtensionPlane.PlaneQuad.Center;
pointOnBlockExtensionPlane += extensionPlane.normal * _manualConstructionSettings.OffsetAlongGrowDirection;
extensionPlane = new Plane(extensionPlane.normal, pointOnBlockExtensionPlane);
// We will need to adjust the last 2 segments using the intersection point between the mouse cursor
// and the extension plane, so the first thing that we will do is find this intersection point. This
// intersection point will essentially help us visualize a triangle whose adjacent sides represent the
// extension directions of the 2 segments. The hypotenuse represents the vector which goes from the
// first stack in the penultimate segment to the last stack in the last segment.
Vector3 extensionPlaneIntersectionPoint;
if (MouseCursor.Instance.IntersectsPlane(extensionPlane, out extensionPlaneIntersectionPoint))
{
// We will need to adjust the number of stacks in each segment based on the length of the triangle's
// adjacent sides. We will start with the penultimate segment and construct a vector which goes from
// the first stack in the penultimate segment to the intersection point with the plane. Projecting this
// vector on the extension direction of the penultimate segment will give us the length of the adjacent
// side. This length is then used to calculate the number of stacks in the penultimate segment.
Vector3 toIntersectionPoint = extensionPlaneIntersectionPoint - _pathExtensionPlane.Plane.ProjectPoint(PenultimateSegment.FirstStackBasePosition);
if (_pathSegments.Count == 2 && PenultimateSegment.NumberOfStacks == 1 && !_pathSettings.TileConnectionSettings.UseTileConnections)
{
var extensionPlaneAxes = new List<Vector3> { _pathExtensionPlane.RightAxis, -_pathExtensionPlane.RightAxis, _pathExtensionPlane.LookAxis, -_pathExtensionPlane.LookAxis };
int mostAlignedVector = toIntersectionPoint.GetIndexOfMostAlignedVector(extensionPlaneAxes);
if (mostAlignedVector >= 0)
{
PenultimateSegment.SetExtensionDirection(extensionPlaneAxes[mostAlignedVector]);
}
}
else if (!PenultimateSegment.ExtensionDirection.IsPointingInSameGeneralDirection(toIntersectionPoint)) PenultimateSegment.ReverseExtensionDirection();
// Calculate the number of stacks in the penultimate segment
float adjacentSideLength = PenultimateSegment.ExtensionDirection.GetAbsDot(toIntersectionPoint);
float numberOfStacks = adjacentSideLength / (PenultimateSegment.GetBoxSizeAlongNormalizedDirection(PenultimateSegment.ExtensionDirection) + _paddingSettings.PaddingAlongExtensionPlane);
int integerNumberOfStacks = (int)numberOfStacks + 1;
int currentNumberOfStacks = PenultimateSegment.NumberOfStacks;
int deltaNumberOfStacks = integerNumberOfStacks - currentNumberOfStacks;
if (deltaNumberOfStacks > 0 || (deltaNumberOfStacks == 0 && _heightAdjustmentSettings.HeightAdjustmentMode == ObjectPlacementPathHeightAdjustmentMode.AutomaticPattern))
{
PenultimateSegment.Extend(deltaNumberOfStacks);
AdjustHeightForStackRangeInSegment(PenultimateSegment, currentNumberOfStacks);
}
else PenultimateSegment.Shrink(Mathf.Abs(deltaNumberOfStacks));
// We will have to do the same thing for the last segment. However, this time we will first detect its extension direction. The extension direction
// is one of the extension plane's axes (right or look). The one we choose has to be the one which is not aligned with the penultimate segment's
// extension direction (i.e. it has to be perpendicular to it).
toIntersectionPoint = extensionPlaneIntersectionPoint - _pathExtensionPlane.Plane.ProjectPoint(PenultimateSegment.LastStackBasePosition);
Vector3 extensionPlaneRight = _pathExtensionPlane.RightAxis;
Vector3 extensionPlaneLook = _pathExtensionPlane.LookAxis;
Vector3 lastSegmentExtensionDirection = extensionPlaneRight;
if (lastSegmentExtensionDirection.IsAlignedWith(PenultimateSegment.ExtensionDirection)) lastSegmentExtensionDirection = extensionPlaneLook;
if (!lastSegmentExtensionDirection.IsPointingInSameGeneralDirection(toIntersectionPoint)) lastSegmentExtensionDirection *= -1.0f;
LastSegment.SetExtensionDirection(lastSegmentExtensionDirection);
// Calculate the number of stacks in the segment.
// Note: We no longer add 1 to the integer number of stacks because that stack is actually the last stack in the penultimate segment
numberOfStacks = toIntersectionPoint.magnitude / (LastSegment.GetBoxSizeAlongNormalizedDirection(LastSegment.ExtensionDirection) + _paddingSettings.PaddingAlongExtensionPlane);
integerNumberOfStacks = (int)numberOfStacks;
currentNumberOfStacks = LastSegment.NumberOfStacks;
deltaNumberOfStacks = integerNumberOfStacks - currentNumberOfStacks;
if (deltaNumberOfStacks > 0 || (deltaNumberOfStacks == 0 && _heightAdjustmentSettings.HeightAdjustmentMode == ObjectPlacementPathHeightAdjustmentMode.AutomaticPattern))
{
LastSegment.Extend(deltaNumberOfStacks);
AdjustHeightForStackRangeInSegment(LastSegment, currentNumberOfStacks);
}
else LastSegment.Shrink(Mathf.Abs(deltaNumberOfStacks));
if (CanRotateObjectsToFollowPath()) MakeSegmentFollowPath(LastSegment);
LastSegment.ConnectFirstStackToLastStackInSegment(PenultimateSegment, CalculateSegmentConnectionOffset(LastSegment, PenultimateSegment));
UpdateStackOverlapDataForLast2Segments();
if (_borderSettings.UseBorders) _borderApplyOperation.ApplyBordersToAllPathSegments(_pathSegments, _borderSettings);
if (_tileConnectionSettings.UseTileConnections) UpdateTileConnectionInformation();
SceneView.RepaintAll();
}
}
private void MakeSegmentFollowPath(ObjectPlacementBoxStackSegment segment)
{
float angleFromFirstSegment = Vector3.Angle(_pathSegments[0].ExtensionDirection, segment.ExtensionDirection);
Quaternion rotation = Quaternion.AngleAxis(angleFromFirstSegment, _pathExtensionPlane.Plane.normal);
segment.SetRotationForAllStacks(rotation * _startObjectHierarchyWorldOrientedBox.Rotation);
}
private Vector3 CalculateSegmentConnectionOffset(ObjectPlacementBoxStackSegment sourceSegment, ObjectPlacementBoxStackSegment destinationSegment)
{
if (!CanExcludeCorners()) return CalculateSegmentConnectionOffsetForNoCornerExclusion(sourceSegment, destinationSegment);
else
{
// Note: Corner exclusion is applied only if the 2 segments are perpendicular.
if (sourceSegment.ExtensionDirection.IsPerpendicularTo(destinationSegment.ExtensionDirection)) return CalculateSegmentConnectionOffsetForCornerExclusion(sourceSegment, destinationSegment);
else return CalculateSegmentConnectionOffsetForNoCornerExclusion(sourceSegment, destinationSegment);
}
}
private Vector3 CalculateSegmentConnectionOffsetForNoCornerExclusion(ObjectPlacementBoxStackSegment sourceSegment, ObjectPlacementBoxStackSegment destinationSegment)
{
// No offset if the destination segment doesn't have any stacks
if (destinationSegment.NumberOfStacks == 0) return Vector3.zero;
bool srcPointsInSameDirAsDestination;
bool srcExtensionDirAlignedWithDestDir = sourceSegment.ExtensionDirection.IsAlignedWith(destinationSegment.ExtensionDirection, out srcPointsInSameDirAsDestination);
float multiplicationSign = 1.0f;
if(srcExtensionDirAlignedWithDestDir)
{
if (!srcPointsInSameDirAsDestination) multiplicationSign *= -1.0f;
}
float destBoxSizeAlongDestExtensionDir = destinationSegment.GetBoxSizeAlongNormalizedDirection(destinationSegment.ExtensionDirection);
float srcBoxSizeAlongDestExtensionDir = sourceSegment.GetBoxSizeAlongNormalizedDirection(destinationSegment.ExtensionDirection);
Vector3 offsetAlongDestExtensionDir = destinationSegment.ExtensionDirection * (destBoxSizeAlongDestExtensionDir - srcBoxSizeAlongDestExtensionDir) * 0.5f;
float destBoxSizeAlongSrcExtensionDir = destinationSegment.GetBoxSizeAlongNormalizedDirection(sourceSegment.ExtensionDirection);
float srcBoxSizeAlongSrcExtensionDir = sourceSegment.GetBoxSizeAlongNormalizedDirection(sourceSegment.ExtensionDirection);
Vector3 offsetAlongSourceExtensionDir = multiplicationSign * sourceSegment.ExtensionDirection * ((srcBoxSizeAlongSrcExtensionDir + destBoxSizeAlongSrcExtensionDir) * 0.5f + _paddingSettings.PaddingAlongExtensionPlane);
return offsetAlongDestExtensionDir + offsetAlongSourceExtensionDir;
}
private Vector3 CalculateSegmentConnectionOffsetForCornerExclusion(ObjectPlacementBoxStackSegment sourceSegment, ObjectPlacementBoxStackSegment destinationSegment)
{
bool srcPointsInSameDirAsDestination;
bool srcExtensionDirAlignedWithDestDir = sourceSegment.ExtensionDirection.IsAlignedWith(destinationSegment.ExtensionDirection, out srcPointsInSameDirAsDestination);
float multiplicationSign = 1.0f;
if (srcExtensionDirAlignedWithDestDir)
{
if (!srcPointsInSameDirAsDestination) multiplicationSign *= -1.0f;
}
float destBoxSizeAlongDestExtensionDir = destinationSegment.GetBoxSizeAlongNormalizedDirection(destinationSegment.ExtensionDirection);
float srcBoxSizeAlongDestExtensionDir = sourceSegment.GetBoxSizeAlongNormalizedDirection(destinationSegment.ExtensionDirection);
Vector3 offsetAlongDestExtensionDir = destinationSegment.ExtensionDirection * Mathf.Abs((destBoxSizeAlongDestExtensionDir + srcBoxSizeAlongDestExtensionDir) * 0.5f);
float destBoxSizeAlongSrcExtensionDir = destinationSegment.GetBoxSizeAlongNormalizedDirection(sourceSegment.ExtensionDirection);
float srcBoxSizeAlongSrcExtensionDir = sourceSegment.GetBoxSizeAlongNormalizedDirection(sourceSegment.ExtensionDirection);
Vector3 offsetAlongSourceExtensionDir = multiplicationSign * sourceSegment.ExtensionDirection * (srcBoxSizeAlongSrcExtensionDir + destBoxSizeAlongSrcExtensionDir) * 0.5f;
return offsetAlongDestExtensionDir + offsetAlongSourceExtensionDir;
}
private void AdjustHeightForEntireSegment(ObjectPlacementBoxStackSegment segment)
{
ObjectPlacementPathHeightAdjustmentMode heightAdjustmentMode = _heightAdjustmentSettings.HeightAdjustmentMode;
if (heightAdjustmentMode == ObjectPlacementPathHeightAdjustmentMode.Manual) _manualHeightAdjuster.AdjustSegmentHeight(segment, _currentManualPathHeight);
else if (heightAdjustmentMode == ObjectPlacementPathHeightAdjustmentMode.AutomaticRandom) _automaticRandomHeightAdjuster.AdjustSegmentHeight(segment, _heightAdjustmentSettings.AutomaticRandomHeightAdjustmentSettings);
else _automaticPatternHeightAdjuster.AdjustSegmentHeight(segment, _pathSegments, _heightAdjustmentSettings.AutomaticPatternHeightAdjustmentSettings, ObjectPlacementPathHeightPatternDatabase.Get().ActivePattern);
}
private void AdjustHeightForStackRangeInSegment(ObjectPlacementBoxStackSegment segment, int indexOfFirstStackToAdjust)
{
ObjectPlacementPathHeightAdjustmentMode heightAdjustmentMode = _heightAdjustmentSettings.HeightAdjustmentMode;
if (heightAdjustmentMode == ObjectPlacementPathHeightAdjustmentMode.Manual) _manualHeightAdjuster.AdjustSegmentHeight(segment, indexOfFirstStackToAdjust, _currentManualPathHeight);
else if (heightAdjustmentMode == ObjectPlacementPathHeightAdjustmentMode.AutomaticRandom) _automaticRandomHeightAdjuster.AdjustSegmentHeight(segment, indexOfFirstStackToAdjust, _heightAdjustmentSettings.AutomaticRandomHeightAdjustmentSettings);
else _automaticPatternHeightAdjuster.AdjustSegmentHeight(segment, _pathSegments, _heightAdjustmentSettings.AutomaticPatternHeightAdjustmentSettings, ObjectPlacementPathHeightPatternDatabase.Get().ActivePattern);
}
private void ReconnectAllSegments()
{
for(int segmentIndex = 1; segmentIndex < _pathSegments.Count; ++segmentIndex)
{
ObjectPlacementBoxStackSegment currentSegment = _pathSegments[segmentIndex];
ObjectPlacementBoxStackSegment previousSegment = _pathSegments[segmentIndex - 1];
currentSegment.ConnectFirstStackToLastStackInSegment(previousSegment, CalculateSegmentConnectionOffset(currentSegment, previousSegment));
}
}
private void HandleStackOverlapForAllStacksInAllSegments()
{
for (int segmentIndex = 0; segmentIndex < _pathSegments.Count; ++segmentIndex)
{
_pathSegments[segmentIndex].MarkAllStacksAsNotOverlapped();
ObjectPlacementBoxStackActions.MarkStacksAsOverlapped(ObjectPlacementPathOverlappedStackDetection.GetOverlappedStacksInSegment(segmentIndex, _pathSegments));
}
}
private void AdjustRotationForAllSegments()
{
foreach(ObjectPlacementBoxStackSegment segment in _pathSegments)
{
if (_manualConstructionSettings.RotateObjectsToFollowPath)
{
if (_pathSegments.Count >= 2 && segment == _pathSegments[0] && segment.NumberOfStacks == 1 && _pathSegments[1].NumberOfStacks >= 1)
{
segment.LookStacksAlongDirection(_pathSegments[1].ExtensionDirection);
}
else segment.LookStacksAlongExtensionDirection();
}
else segment.LookStacksAlongDirection(_pathSegments[0].ExtensionDirection);
}
}
private void AdjustHeightForAllStacksInPath()
{
if (_heightAdjustmentSettings.HeightAdjustmentMode == ObjectPlacementPathHeightAdjustmentMode.Manual) _manualHeightAdjuster.AdjustHeightForSegments(_pathSegments, _currentManualPathHeight);
else if (_heightAdjustmentSettings.HeightAdjustmentMode == ObjectPlacementPathHeightAdjustmentMode.AutomaticRandom) _automaticRandomHeightAdjuster.AdjustHeightForSegments(_pathSegments, _heightAdjustmentSettings.AutomaticRandomHeightAdjustmentSettings);
else _automaticPatternHeightAdjuster.AdjustHeightForAllSegmentsInPath(_pathSegments, _heightAdjustmentSettings.AutomaticPatternHeightAdjustmentSettings, ObjectPlacementPathHeightPatternDatabase.Get().ActivePattern);
}
private void UpdateTileConnectionInformation()
{
List<ObjectPlacementPathTileConnectionGridCell> tileConnectionGridCells = _tileConnectionDetector.Detect(_path, _tileConnectionXZSize);
if (tileConnectionGridCells.Count == 0) return;
_tileConnectionGridCells.Clear();
_tileConnectionGridCells.AddRange(tileConnectionGridCells);
bool usingSprites = _pathSettings.TileConnectionSettings.UsesSprites();
List<OrientedBox> tileConnectionPrefabWorldOrientedBoxesExceptAutofill = PrefabQueries.GetHierarchyWorldOrientedBoxesForAllPrefabs(_tileConnectionSettings.GetAllTileConnectionPrefabs(true));
foreach (ObjectPlacementPathTileConnectionGridCell tileConnectionGridCell in _tileConnectionGridCells)
{
ObjectPlacementPathTileConnectionTypeSettings tileConnectionTypeSettings = _tileConnectionSettings.GetSettingsForTileConnectionType(tileConnectionGridCell.TileConnectionType);
tileConnectionGridCell.TileConnectionStack.SetBoxSize(GetTileConnectionSize(tileConnectionPrefabWorldOrientedBoxesExceptAutofill[(int)tileConnectionTypeSettings.TileConnectionType], usingSprites));
tileConnectionGridCell.TileConnectionStack.PlaceOnPlane(_pathExtensionPlane.Plane);
}
}
private Vector3 GetTileConnectionSize(OrientedBox tilePrefabOOBB, bool usingSprites)
{
Vector3 boxSize = GetSegmentBoxSize();
if (usingSprites) boxSize.z = 0.0f;
else boxSize.y = tilePrefabOOBB.ScaledSize.y;
return boxSize;
}
private void UpdateStackOverlapDataForLast2Segments()
{
PenultimateSegment.MarkAllStacksAsNotOverlapped();
LastSegment.MarkAllStacksAsNotOverlapped();
ObjectPlacementBoxStackActions.MarkStacksAsOverlapped(ObjectPlacementPathOverlappedStackDetection.GetOverlappedStacksInSegment(_pathSegments.Count - 2, _pathSegments));
ObjectPlacementBoxStackActions.MarkStacksAsOverlapped(ObjectPlacementPathOverlappedStackDetection.GetOverlappedStacksInSegment(_pathSegments.Count - 1, _pathSegments));
}
#endregion
}
}
#endif