static Vector2 GetMaxPos(Rect rect, SnapReference reference) { switch (reference) { case SnapReference.LeftEdge: return(new Vector2(rect.x, rect.yMax)); case SnapReference.HorizontalCenter: return(new Vector2(rect.center.x, rect.yMax)); case SnapReference.RightEdge: return(new Vector2(rect.xMax, rect.yMax)); case SnapReference.TopEdge: return(new Vector2(rect.xMax, rect.y)); case SnapReference.VerticalCenter: return(new Vector2(rect.xMax, rect.center.y)); case SnapReference.BottomEdge: return(new Vector2(rect.xMax, rect.yMax)); default: return(Vector2.zero); } }
void ComputeSpacingPositions(ReferenceRects referenceRects, Rect sourceRect) { SnapReference startReference = referenceRects.Orientation == Orientation.Vertical ? SnapReference.TopEdge : SnapReference.LeftEdge; SnapReference endReference = referenceRects.Orientation == Orientation.Vertical ? SnapReference.BottomEdge : SnapReference.RightEdge; for (int i = 0; i < referenceRects.Rects.Count; ++i) { Rect firstRect = referenceRects.Rects[i]; int nextRectIndex = i + 1; // After rect i is done, we don't consider it anymore for the next iterations for (int j = nextRectIndex; j < referenceRects.Rects.Count; ++j) { Rect secondRect = referenceRects.Rects[j]; // For each rect i, we find the 3 spacing positions: (examples are for horizontal orientation) // - 1. position before rect i // +-----+ +-----+ +-----+ // | pos | | i | | j | // +-----+ +-----+ +-----+ // - 2. position between rect i and rect j // +-----+ +-----+ +-----+ // | i | | pos | | j | // +-----+ +-----+ +-----+ // - 3. position after rect j // +-----+ +-----+ +-----+ // | i | | j | | pos | // +-----+ +-----+ +-----+ List <float> spacingPositions = GetSpacingPositions(sourceRect, firstRect, secondRect, startReference, endReference, referenceRects.Orientation); AddSpacingPositions(spacingPositions, sourceRect, firstRect, secondRect, referenceRects.Orientation); } } }
Line2 GetSnapLine(Rect r1, SnapReference reference1, Rect r2, SnapReference reference2) { bool horizontal = reference1 <= SnapReference.RightEdge; Line2 line1 = GetSnapLine(r1, reference1); Line2 line2 = GetSnapLine(r2, reference2); Vector2 p11 = line1.start , p12 = line1.end , p21 = line2.start , p22 = line2.end , start = Vector2.zero , end = Vector2.zero; if (horizontal) { float x = p21.x; float yMin = Math.Min(p22.y, Math.Min(p21.y, Math.Min(p11.y, p12.y))); float yMax = Math.Max(p22.y, Math.Max(p21.y, Math.Max(p11.y, p12.y))); start = new Vector2(x, yMin); end = new Vector2(x, yMax); } else { float y = p22.y; float xMin = Math.Min(p22.x, Math.Min(p21.x, Math.Min(p11.x, p12.x))); float xMax = Math.Max(p22.x, Math.Max(p21.x, Math.Max(p11.x, p12.x))); start = new Vector2(xMin, y); end = new Vector2(xMax, y); } return(new Line2(start, end)); }
internal static float GetPos(Rect rect, SnapReference reference) { switch (reference) { case SnapReference.LeftEdge: return(rect.x); case SnapReference.HorizontalCenter: return(rect.center.x); case SnapReference.RightEdge: return(rect.xMax); case SnapReference.TopEdge: return(rect.y); case SnapReference.VerticalCenter: return(rect.center.y); case SnapReference.BottomEdge: return(rect.yMax); default: return(0); } }
List <SnapResult> GetClosestSnapElements(Rect sourceRect, Orientation orientation) { SnapReference startReference = orientation == Orientation.Horizontal ? SnapReference.LeftEdge : SnapReference.TopEdge; SnapReference centerReference = orientation == Orientation.Horizontal ? SnapReference.HorizontalCenter : SnapReference.VerticalCenter; SnapReference endReference = orientation == Orientation.Horizontal ? SnapReference.RightEdge : SnapReference.BottomEdge; List <SnapResult> results = new List <SnapResult>(3); SnapResult result = GetClosestSnapElement(sourceRect, startReference, startReference, centerReference, endReference); if (result != null) { results.Add(result); } result = GetClosestSnapElement(sourceRect, centerReference, startReference, centerReference, endReference); if (result != null) { results.Add(result); } result = GetClosestSnapElement(sourceRect, endReference, startReference, centerReference, endReference); if (result != null) { results.Add(result); } // Look for the minimum if (results.Count > 0) { results.Sort((a, b) => a.distance.CompareTo(b.distance)); float minDistance = results[0].distance; results.RemoveAll(r => Math.Abs(r.distance - minDistance) > 0.01f); } return(results); }
SnapResult GetClosestSnapElement(Rect sourceRect, SnapReference sourceRef, Rect snappableRect, SnapReference startReference, SnapReference centerReference, SnapReference endReference) { float sourcePos = GetPos(sourceRect, sourceRef); float offsetStart = sourcePos - GetPos(snappableRect, startReference); float offsetEnd = sourcePos - GetPos(snappableRect, endReference); float minOffset = offsetStart; SnapReference minSnappableReference = startReference; if (Math.Abs(minOffset) > Math.Abs(offsetEnd)) { minOffset = offsetEnd; minSnappableReference = endReference; } SnapResult minResult = new SnapResult { sourceRect = sourceRect, sourceReference = sourceRef, snappableRect = snappableRect, snappableReference = minSnappableReference, offset = minOffset }; if (minResult.distance <= snapDistance * 1 / m_CurrentScale) { return(minResult); } else { return(null); } }
float GetClosestGridLine(Rect rect, SnapReference reference) { switch (reference) { case SnapReference.LeftEdge: return(GetClosestGridLine(rect.xMin)); case SnapReference.HorizontalCenter: return(GetClosestGridLine(rect.center.x)); case SnapReference.RightEdge: return(GetClosestGridLine(rect.xMax)); case SnapReference.TopEdge: return(GetClosestGridLine(rect.yMin)); case SnapReference.VerticalCenter: return(GetClosestGridLine(rect.center.y)); case SnapReference.BottomEdge: return(GetClosestGridLine(rect.yMax)); default: return(0); } }
float GetPositionWithBorder(Rect rect, SnapReference reference) { // We need to take account of the selected element's content container's border width to snap on it switch (reference) { case SnapReference.LeftEdge: return(rect.x - m_BorderWidth.Left); case SnapReference.HorizontalCenter: return(rect.center.x); case SnapReference.RightEdge: return(rect.xMax + m_BorderWidth.Right); case SnapReference.TopEdge: return(rect.y - m_BorderWidth.Top); case SnapReference.VerticalCenter: return(rect.center.y); case SnapReference.BottomEdge: return(rect.yMax + m_BorderWidth.Bottom); default: return(0); } }
SnapResult GetClosestSnapElement(Rect sourceRect, SnapReference sourceRef, SnapReference startReference, SnapReference centerReference, SnapReference endReference) { SnapResult minResult = null; float minDistance = float.MaxValue; foreach (Rect snappableRect in m_SnappableRects) { SnapResult result = GetClosestSnapElement(sourceRect, sourceRef, snappableRect, startReference, centerReference, endReference); if (result != null && minDistance > result.distance) { minDistance = result.distance; minResult = result; } } return(minResult); }
List <SpacingLine> GetSpacingLines(List <Rect> rects, Orientation orientation) { SnapReference startReference = orientation == Orientation.Vertical ? SnapReference.BottomEdge : SnapReference.RightEdge; SnapReference endReference = orientation == Orientation.Vertical ? SnapReference.TopEdge : SnapReference.LeftEdge; float maxCoordinate = rects.Max(rect => orientation == Orientation.Vertical ? rect.xMax : rect.yMax) + SpacingLine.DefaultSpacingLineSideLength; float spacingLineSideLength = SpacingLine.DefaultSpacingLineSideLength / m_CurrentScale; Vector2 firstSidePos = GetMaxPos(rects[0], startReference); Vector2 secondSidePos = GetMaxPos(rects[1], endReference); Vector2 thirdSidePos = GetMaxPos(rects[1], startReference); Vector2 fourthSidePos = GetMaxPos(rects[2], endReference); return(new List <SpacingLine> { GetSpacingLine(maxCoordinate, spacingLineSideLength, firstSidePos, secondSidePos, orientation), GetSpacingLine(maxCoordinate, spacingLineSideLength, thirdSidePos, fourthSidePos, orientation) }); }
Line2 GetSnapLine(Rect r, SnapReference reference) { Vector2 start = Vector2.zero, end = Vector2.zero; switch (reference) { case SnapReference.LeftEdge: start = r.position; end = new Vector2(r.x, r.yMax); break; case SnapReference.HorizontalCenter: start = r.center; end = start; break; case SnapReference.RightEdge: start = new Vector2(r.xMax, r.yMin); end = new Vector2(r.xMax, r.yMax); break; case SnapReference.TopEdge: start = r.position; end = new Vector2(r.xMax, r.yMin); break; case SnapReference.VerticalCenter: start = r.center; end = start; break; default: // case SnapReference.BottomEdge: start = new Vector2(r.x, r.yMax); end = new Vector2(r.xMax, r.yMax); break; } return(new Line2(start, end)); }
SnapToGridResult GetClosestGridLine(Rect sourceRect, SnapReference sourceRef, SnapReference startReference, SnapReference endReference) { float sourcePos = GetPositionWithBorder(sourceRect, sourceRef); float offsetStart = sourcePos - GetClosestGridLine(sourceRect, startReference); float offsetEnd = sourcePos - GetClosestGridLine(sourceRect, endReference); float minOffset = offsetStart; SnapReference minSnappableReference = startReference; if (Math.Abs(minOffset) > Math.Abs(offsetEnd)) { minOffset = offsetEnd; minSnappableReference = endReference; } SnapToGridResult minResult = new SnapToGridResult() { SnappableReference = minSnappableReference, Offset = minOffset }; return(minResult.Distance <= SnapDistance * 1 / m_CurrentScale ? minResult : null); }
static List <float> GetSpacingPositions(Rect sourceRect, Rect firstRect, Rect secondRect, SnapReference startReference, SnapReference endReference, Orientation orientation) { if (AreElementsSuperposed(firstRect, secondRect, orientation)) { return(null); } Vector2 firstRectStartPos = GetMaxPos(firstRect, startReference); Vector2 firstRectEndPos = GetMaxPos(firstRect, endReference); Vector2 secondRectStartPos = GetMaxPos(secondRect, startReference); Vector2 secondRectEndPos = GetMaxPos(secondRect, endReference); List <float> positions = orientation == Orientation.Vertical ? ComputeSpacingPositions(firstRectStartPos.y, firstRectEndPos.y, secondRectStartPos.y, secondRectEndPos.y, sourceRect.height * 0.5f) : ComputeSpacingPositions(firstRectStartPos.x, firstRectEndPos.x, secondRectStartPos.x, secondRectEndPos.x, sourceRect.width * 0.5f); return(positions); }