#if UNITY_EDITOR using UnityEngine; using System; using System.Linq; using System.Collections.Generic; namespace O3DWB { [Serializable] public class ProjectedBoxFacePivotPoints { #region Private Variables [SerializeField] private PivotPointCollection _pivotPointCollection = new PivotPointCollection(); [SerializeField] private List _unprojectedPivotPoints = new List { Vector3.zero }; [SerializeField] private Plane _pointsPlane = new Plane(); [SerializeField] private float _area = 0.0f; #endregion #region Public Static Properties public static int NumberOfBoundarySegments { get { return 4; } } public static int IndexOfPointInCenter { get { return 0; } } #endregion #region Public Properties public int NumberOfPoints { get { return _pivotPointCollection.NumberOfPoints; } } public Vector3 ActivePoint { get { return _pivotPointCollection.ActivePoint; } } public Vector3 CenterPoint { get { return _pivotPointCollection.GetPointByIndex(IndexOfPointInCenter); } } public int IndexOfActivePoint { get { return _pivotPointCollection.IndexOfActivePoint; } } public List AllPoints { get { return _pivotPointCollection.AllPoints; } } public Plane PointsPlane { get { return _pointsPlane; } } public float Area { get { return _area; } } #endregion #region Public Methods public ProjectedBoxFacePivotPoints TakeSnapshot() { var projectedBoxFacePivotPoints = new ProjectedBoxFacePivotPoints(); projectedBoxFacePivotPoints._pivotPointCollection = _pivotPointCollection.TakeSnapshot(); projectedBoxFacePivotPoints._unprojectedPivotPoints = GetUnprojectedPivotPoints(); projectedBoxFacePivotPoints._pointsPlane = PointsPlane; return projectedBoxFacePivotPoints; } public void FromOrientedBoxAndSnapSurface(OrientedBox orientedBox, SnapSurface objectSnapSurface) { if (!objectSnapSurface.IsValid) return; Vector3 surfacePlaneNormal = objectSnapSurface.Plane.normal; if (AllShortcutCombos.Instance.PlaceGuideBehindSurfacePlane.IsActive()) surfacePlaneNormal *= -1.0f; BoxFace boxFaceMostAlignedWithSurface = orientedBox.GetBoxFaceWhichFacesNormal(surfacePlaneNormal); List cornerPointsOfFaceMostAlignedWithSurface = orientedBox.GetBoxFaceCornerPoints(boxFaceMostAlignedWithSurface); CalculatePointsPlane(orientedBox, objectSnapSurface); StoreObjectPivotPoints(_pointsPlane.ProjectAllPoints(cornerPointsOfFaceMostAlignedWithSurface)); StoreUnprojectedPivotPoints(cornerPointsOfFaceMostAlignedWithSurface); CalculateArea(); } public void FromOrientedBoxAndDecorStrokeSurface(OrientedBox orientedBox, DecorPaintStrokeSurface decorPaintStrokeSurface) { if (!decorPaintStrokeSurface.IsValid) return; Vector3 surfacePlaneNormal = decorPaintStrokeSurface.Plane.normal; if (AllShortcutCombos.Instance.PlaceGuideBehindSurfacePlane.IsActive()) surfacePlaneNormal *= -1.0f; BoxFace boxFaceMostAlignedWithSurface = orientedBox.GetBoxFaceWhichFacesNormal(surfacePlaneNormal); List cornerPointsOfFaceMostAlignedWithSurface = orientedBox.GetBoxFaceCornerPoints(boxFaceMostAlignedWithSurface); CalculatePointsPlane(orientedBox, decorPaintStrokeSurface); StoreObjectPivotPoints(_pointsPlane.ProjectAllPoints(cornerPointsOfFaceMostAlignedWithSurface)); StoreUnprojectedPivotPoints(cornerPointsOfFaceMostAlignedWithSurface); CalculateArea(); } public List GetAllPointsExcludingCenter() { List pivotPoints = AllPoints; if (pivotPoints.Count == 0) return pivotPoints; pivotPoints.RemoveAt(IndexOfPointInCenter); return pivotPoints; } public int GetIndexOfPointClosestToPoint(Vector3 point) { return Vector3Extensions.GetIndexOfPointClosestToPoint(AllPoints, point); } public List GetUnprojectedPivotPoints() { return new List(_unprojectedPivotPoints); } public void ActivatePoint(int pointIndex) { _pivotPointCollection.ActivatePoint(pointIndex); } public void ActivateNextPivotPoint() { _pivotPointCollection.ActivateNextPoint(); } public Vector3 GetPointByIndex(int pointIndex) { return _pivotPointCollection.GetPointByIndex(pointIndex); } public List GetAllBoundarySegments() { List allPointsNoCenter = GetAllPointsExcludingCenter(); return Vector3Extensions.GetSegmentsBetweenPoints(allPointsNoCenter, true); } public List GetAllBoundarySegmentPlanes() { List allBoundarySegments = GetAllBoundarySegments(); var allBoundarySegmentPlanes = new List(allBoundarySegments.Count); for(int segmentIndex = 0; segmentIndex < allBoundarySegments.Count; ++segmentIndex) { allBoundarySegmentPlanes.Add(GetBoundarySegmentPlane(segmentIndex)); } return allBoundarySegmentPlanes; } public Segment3D GetBoundarySegment(int segmentIndex) { segmentIndex %= NumberOfBoundarySegments; List allPointsNoCenter = GetAllPointsExcludingCenter(); return new Segment3D(allPointsNoCenter[segmentIndex], allPointsNoCenter[(segmentIndex + 1) % NumberOfBoundarySegments]); } public Plane GetBoundarySegmentPlane(int segmentIndex) { Segment3D boundarySegment = GetBoundarySegment(segmentIndex); Vector3 centerPivotPoint = GetPointByIndex(IndexOfPointInCenter); Vector3 centerPivotPointProjectedOnSegment = centerPivotPoint.CalculateProjectionPointOnSegment(boundarySegment.StartPoint, boundarySegment.EndPoint); Vector3 planeNormal = centerPivotPointProjectedOnSegment - centerPivotPoint; planeNormal.Normalize(); return new Plane(planeNormal, boundarySegment.StartPoint); } public void MovePoints(Vector3 moveVector) { _unprojectedPivotPoints = Vector3Extensions.ApplyOffsetToPoints(_unprojectedPivotPoints, moveVector); _pivotPointCollection.MovePoints(moveVector); _pointsPlane = new Plane(_pointsPlane.normal, _pivotPointCollection.GetPointByIndex(0)); } #endregion #region Private Methods private void StoreUnprojectedPivotPoints(List cornerPointsOfFaceMostAlignedWithSurface) { _unprojectedPivotPoints = new List(cornerPointsOfFaceMostAlignedWithSurface); _unprojectedPivotPoints.Insert(IndexOfPointInCenter, Vector3Extensions.GetAveragePoint(cornerPointsOfFaceMostAlignedWithSurface)); } private void CalculatePointsPlane(OrientedBox orientedBox, SnapSurface objectSnapSurface) { // Note: It is necessary to ensure that all projected points sit right below the oriented box in order // to avoid situations in which the object hierarchy floats in the air or becomes embedded // inside other objects. In order to do this, we adjust the surface plane such that the box // sits right in front of it (or behind) depending on the settings. _pointsPlane = objectSnapSurface.Plane; if (AllShortcutCombos.Instance.PlaceGuideBehindSurfacePlane.IsActive()) _pointsPlane = _pointsPlane.AdjustSoBoxSitsBehind(orientedBox); else _pointsPlane = _pointsPlane.AdjustSoBoxSitsInFront(orientedBox); } private void CalculatePointsPlane(OrientedBox orientedBox, DecorPaintStrokeSurface decorPaintSurface) { _pointsPlane = decorPaintSurface.Plane; if (AllShortcutCombos.Instance.PlaceGuideBehindSurfacePlane.IsActive()) _pointsPlane = _pointsPlane.AdjustSoBoxSitsBehind(orientedBox); else _pointsPlane = _pointsPlane.AdjustSoBoxSitsInFront(orientedBox); } private void StoreObjectPivotPoints(List projectedFacePoints) { List projectedPointsAndCenter = new List(projectedFacePoints); projectedPointsAndCenter.Insert(IndexOfPointInCenter, Vector3Extensions.GetAveragePoint(projectedFacePoints)); _pivotPointCollection.SetPivotPoints(projectedPointsAndCenter, _pivotPointCollection.IndexOfActivePoint); } private void CalculateArea() { List boundarySegments = GetAllBoundarySegments(); for(int segmentIndex = 0; segmentIndex < boundarySegments.Count; ++segmentIndex) { Segment3D currentSegment = boundarySegments[segmentIndex]; for(int perpSegmentIndex = segmentIndex + 1; perpSegmentIndex < boundarySegments.Count; ++perpSegmentIndex) { Segment3D perpSegment = boundarySegments[perpSegmentIndex]; if(perpSegment.IsPerpendicualrTo(currentSegment)) { Vector3 cross = Vector3.Cross(perpSegment.Direction, currentSegment.Direction); _area = cross.magnitude; return; } } } } #endregion } } #endif