Search Unity

Find anchoredPosition of a RectTransform relative to another RectTransform

Discussion in 'UGUI & TextMesh Pro' started by Demigiant, Jun 3, 2015.

  1. Demigiant

    Demigiant

    Joined:
    Jan 27, 2011
    Posts:
    3,242
    Hello,

    The thread title might look confusing, so let me make an example.

    EXAMPLE
    I have two RectTransforms, A and B. A has its anchor set to the top-left of the screen, B to the center. Now, I would like to move B to the same exact position as A, eye-wise, so that they overlap, but without changing its original anchor offset etc: just by giving it a new anchoredPosition.

    So the question is, how would I calculate the correct anchoredPosition for an object, so that it perfectly overlaps another object, even if they have different offsets, anchors, and maybe even parents?

    Thanks,
    Daniele
     
    _TheFuture_ likes this.
  2. SimonDarksideJ

    SimonDarksideJ

    Joined:
    Jul 3, 2012
    Posts:
    1,689
    One thing you have to remember is that the anchors position is relative to the RectTransform's pivot point.
    So in that scenario you might be better trying to align them based on their pivot point and the RectTransforms dimensions / size delta
     
  3. Demigiant

    Demigiant

    Joined:
    Jan 27, 2011
    Posts:
    3,242
    @SimonDarksideJ I know, but I really need to be able to align them only by changing the anchoredPosition, and still can't find the right way to do that. Any help there?
     
  4. Zinov

    Zinov

    Joined:
    Jul 20, 2015
    Posts:
    38
    I would like to know that as well. I need to visually align 2 ui elements but they have different parents. What equations should I use?
     
  5. Demigiant

    Demigiant

    Joined:
    Jan 27, 2011
    Posts:
    3,242
    After many trials and errors, I managed to create a method just for that:
    Code (csharp):
    1.  
    2. /// <summary>
    3. /// Converts the anchoredPosition of the first RectTransform to the second RectTransform,
    4. /// taking into consideration offset, anchors and pivot, and returns the new anchoredPosition
    5. /// </summary>
    6. public static Vector2 SwitchToRectTransform(RectTransform from, RectTransform to)
    7. {
    8.    Vector2 localPoint;
    9.    Vector2 fromPivotDerivedOffset = new Vector2(from.rect.width * 0.5f + from.rect.xMin, from.rect.height * 0.5f + from.rect.yMin);
    10.    Vector2 screenP = RectTransformUtility.WorldToScreenPoint(null, from.position);
    11.    screenP += fromPivotDerivedOffset;
    12.    RectTransformUtility.ScreenPointToLocalPointInRectangle(to, screenP, null, out localPoint);
    13.    Vector2 pivotDerivedOffset = new Vector2(to.rect.width * 0.5f + to.rect.xMin, to.rect.height * 0.5f + to.rect.yMin);
    14.    return to.anchoredPosition + localPoint - pivotDerivedOffset;
    15. }
     
  6. Brave-Michael

    Brave-Michael

    Joined:
    Jul 2, 2015
    Posts:
    5
    Thanks, worked like a charm.

    Just a small change to make it return coordinates which respect the pivots of the two RectTransforms:

    Code (csharp):
    1.  
    2. private Vector2 switchToRectTransform(RectTransform from, RectTransform to)
    3.   {
    4.   Vector2 localPoint;
    5.   Vector2 fromPivotDerivedOffset = new Vector2(from.rect.width * from.pivot.x + from.rect.xMin, from.rect.height * from.pivot.y + from.rect.yMin);
    6.   Vector2 screenP = RectTransformUtility.WorldToScreenPoint(null, from.position);
    7.   screenP += fromPivotDerivedOffset;
    8.   RectTransformUtility.ScreenPointToLocalPointInRectangle(to, screenP, null, out localPoint);
    9.   Vector2 pivotDerivedOffset = new Vector2(to.rect.width * to.pivot.x + to.rect.xMin, to.rect.height * to.pivot.y + to.rect.yMin);
    10.   return to.anchoredPosition + localPoint - pivotDerivedOffset;
    11.   }
    12.  
     
  7. SimonDarksideJ

    SimonDarksideJ

    Joined:
    Jul 3, 2012
    Posts:
    1,689
    Great stuff, will see about adding these functions to the UI Extensions project, with a few variations
     
    PrimalCoder and Demigiant like this.
  8. Demigiant

    Demigiant

    Joined:
    Jan 27, 2011
    Posts:
    3,242
    Highfive to you for the addition, @Brave Michael! And woah, didn't know the UI Extensions project. Cool!
     
    twobob and SimonDarksideJ like this.
  9. fermmmm

    fermmmm

    Joined:
    Oct 18, 2013
    Posts:
    129
    tomtominc likes this.
  10. casimps1

    casimps1

    Joined:
    Jul 28, 2012
    Posts:
    254
    FYI - I don't think the pivot offset above is actually necessary for this. From what I can tell, Transform.position is already going to give you exactly where the pivot is in world space (regardless of whether the pivot is in the center of the Rect or not). So, I think it's enough to just do this:

    Code (CSharp):
    1. Vector2 localPoint;
    2. Vector2 screenP = RectTransformUtility.WorldToScreenPoint( null, from.position )
    3. RectTransformUtility.ScreenPointToLocalPointInRectangle( to, screenP, null, out localPoint );
    4.  
     
  11. IronHelmet

    IronHelmet

    Joined:
    May 2, 2017
    Posts:
    85
    How come WorldToScreenPoint is not documented in RectTransformUtility. Am I reading the docs wrong?
     
  12. CPULL

    CPULL

    Joined:
    Aug 1, 2019
    Posts:
    5
    It is a script utility.
    It is documented in the script part of the documentation, it does not have a page in the "manual" section of the Unity documents.
     
  13. azevedco

    azevedco

    Joined:
    Mar 2, 2014
    Posts:
    34
    For my particular scenario, I had a position relative to a certain RectTransform Anchored space and had to convert it to another RectTransform's space. So I updated the function provided above to take in a position and convert it from it's current RectTransform space into a target RectTransform space.

    Code (CSharp):
    1. private Vector2 ConvertPosToTargetPivotSpace(Vector2 fromAnchoredPos, RectTransform fromPivotSpace, RectTransform toPivotSpace)
    2. {
    3.     Vector2 convertedPos;
    4.  
    5.     Vector2 fromPivotDerivedOffset = new Vector2(fromPivotSpace.rect.width * fromPivotSpace.pivot.x + fromPivotSpace.rect.xMin, fromPivotSpace.rect.height * fromPivotSpace.pivot.y + fromPivotSpace.rect.yMin);
    6.  
    7.     Vector3 fromWorldSpace = fromPivotSpace.TransformPoint(fromAnchoredPos);
    8.     Vector2 screenP = RectTransformUtility.WorldToScreenPoint(null, fromWorldSpace);
    9.     screenP += fromPivotDerivedOffset;
    10.  
    11.     RectTransformUtility.ScreenPointToLocalPointInRectangle(toPivotSpace, screenP, null, out convertedPos);
    12.     Vector2 pivotDerivedOffset = new Vector2(toPivotSpace.rect.width * toPivotSpace.pivot.x + toPivotSpace.rect.xMin, toPivotSpace.rect.height * toPivotSpace.pivot.y + toPivotSpace.rect.yMin);
    13.  
    14.     return toPivotSpace.anchoredPosition + convertedPos - pivotDerivedOffset;
    15. }
    Hope this helps anyone else who was seeking this type of solution, or even myself if I run into the same issue in the future.

    Be sure that you're providing the CORRECT fromPivotSpace RectTransform, initial tests, I was not and thought I was going down the wrong direction.

    Goodluck!
     
    Braza likes this.
  14. Tortuap

    Tortuap

    Joined:
    Dec 4, 2013
    Posts:
    137
    Code (CSharp):
    1. Vector2 fromPivotDerivedOffset = new Vector2(fromPivotSpace.rect.width * fromPivotSpace.pivot.x + fromPivotSpace.rect.xMin, fromPivotSpace.rect.height * fromPivotSpace.pivot.y + fromPivotSpace.rect.yMin);
    Pretty sure adding this directly to a world position is wrong.
    Aren't you forgetting to take scaling or rotation into account there ?
     
  15. Tortuap

    Tortuap

    Joined:
    Dec 4, 2013
    Posts:
    137
    Well it's not working at all guys.
     
  16. a436t4ataf

    a436t4ataf

    Joined:
    May 19, 2013
    Posts:
    1,933
    I think what @IronHelmet means is ... in the Unity scripting docs this method you used DOES NOT EXIST - https://docs.unity3d.com/ScriptReference/RectTransformUtility.html

    (I came here in the hope that someone else had implemented the obvious missing API call. I was a bit stunned to find the API call isn't missing, just some muppet at Unity deleted it from the docs - it's a public method in the class, no reason for it to be absent)