Search code examples
iosunity-game-engine3daugmented-realityvertex

From two interesting lines, Create box and get all 4 corners


I have two lines intersecting each other, How can I put a box upon lines to get 4 corner coordinates.

The image explains the question very well. The red dotted lines(box) are just illusionary, Purpose is to get 4(????) corners of the box.

Lines can be drawn in and direction or shape.

I have got the intersection points of the lines and the middle point of both lines.

enter image description here


Solution

  • So from what I understand is you want a world-XY aligned bounding rectangle. Otherwise there wouldn't be 4 but 8 corners ;)

    Actually it doesn't really matter for this if the lines are intersecting or not.

    Simply

    • get the four given start and end points of the lines
    • from these calculate min and max for X and Y axis
    • from these min and max permutations you get the four corners

    Something like e.g.

    // The given line points
    Vector2 startA;
    Vector2 endA;
    Vector2 startB;
    Vector2 endB;
    
    // calculate min/max for each axis
    var minX = Mathf.Min(startA.x, endA.x, startB.x, endB.x);
    var maxX = Mathf.Max(startA.x, endA.x, startB.x, endB.x);
    var minY = Mathf.Min(startA.y, endA.y, startB.y, endB.y);
    var maxY = Mathf.Max(startA.y, endA.y, startB.y, endB.y);
    
    // permutations of these give you the corners
    var topRight = new Vector2(maxX, maxY);
    var bottomRight = new Vector2(maxX, minY);
    var bottomLeft = new Vector2 (minX, minY);
    var topLeft = new Vector2 (minX, maxY);
    

    If you also need the Z axis (in order to actually get a box) it is just four permutations more for minZ and maxZ accordingly.

    // The given line points
    Vector3 startA;
    Vector3 endA;
    Vector3 startB;
    Vector3 endB;
    
    // calculate min/max for each axis
    var minX = Mathf.Min(startA.x, endA.x, startB.x, endB.x);
    var maxX = Mathf.Max(startA.x, endA.x, startB.x, endB.x);
    var minY = Mathf.Min(startA.y, endA.y, startB.y, endB.y);
    var maxY = Mathf.Max(startA.y, endA.y, startB.y, endB.y);
    var minZ = Mathf.Min(startA.z, endA.z, startB.z, endB.z);
    var maxZ = Mathf.Max(startA.z, endA.z, startB.z, endB.z);
    
    // permutations of these give you the corners
    var topRightFront = new Vector3(maxX, maxY, minZ);
    var bottomRightFront = new Vector3(maxX, minY, minZ);
    var bottomLeftFront = new Vector3 (minX, minY, minZ);
    var topLeftFront = new Vector3 (minX, maxY, minZ);
    var topRightBack = new Vector3(maxX, maxY, maxZ);
    var bottomRightBack = new Vector3(maxX, minY, maxZ);
    var bottomLeftBack = new Vector3 (minX, minY, maxZ);
    var topLeftBack = new Vector3 (minX, maxY, maxZ);
    

    So the before mentioned code was assuming you want the rect/box to be world axis aligned.

    In case that is not the case you could use the following way

    • Have an empty GameObject as the reference for the rotated world (e.g. aligned via QR code tracking etc) - let's call it "WorldAnchor"
    • convert the line points into local space of that WorldAnchor
    • Do the same min/max calculation for all axis now in local space
    • Do the same permutation to obtain the corners
    • Finally convert the corners back to world space

    Something like

    // The given line points in WORLD Space
    Vector3 startA;
    Vector3 endA;
    Vector3 startB;
    Vector3 endB;
    
    // The given oriented world anchor
    Transform anchor;
    
    // The line points converted to LOCAL space
    var localStartA = anchor.InverseTransformPoint(startA);
    var localEndA = anchor.InverseTransformPoint(endA);
    var localStartB = anchor.InverseTransformPoint(startB);
    var localEndB = anchor.InverseTransformPoint(endB);
    
    // calculate min/max for each axis
    var localMinX = Mathf.Min(localStartA.x, localEndA.x, localStartB.x, localEndB.x);
    var localMaxX = Mathf.Max(localStartA.x, localEndA.x, localStartB.x, localEndB.x);
    var localMinY = Mathf.Min(localStartA.y, localEndA.y, localStartB.y, localEndB.y);
    var localMaxY = Mathf.Max(localStartA.y, localEndA.y, localStartB.y, localEndB.y);
    var localMinZ = Mathf.Min(localStartA.z, localEndA.z, localStartB.z, localEndB.z);
    var localMaxZ = Mathf.Max(localStartA.z, localEndA.z, localStartB.z, localEndB.z);
    
    // permutations of these give you the corners
    var localTopRightFront = new Vector3(localMaxX, localMaxY, localMinZ);
    var localBottomRightFront = new Vector3(localMaxX, localMinY, localMinZ);
    var localBottomLeftFront = new Vector3 (localMinX, localMinY, localMinZ);
    var localTopLeftFront = new Vector3 (localMinX, localMaxY, localMinZ);
    var localTopRightBack = new Vector3(localMaxX, localMaxY, localMaxZ);
    var localBottomRightBack = new Vector3(localMaxX, localMinY, localMaxZ);
    var localBottomLeftBack = new Vector3 (localMinX, localMinY, localMaxZ);
    var localTopLeftBack = new Vector3 (localMinX, localMaxY, localMaxZ);
    

    Now either simply place your corner visualizers at these positions but as children of the WorldAnchor object.

    Or convert them back to global world space using

    var topRightFront = anchor.TransformPoint(localTopRightFront);
    var bottomRightFront = anchor.TransformPoint(localBottomRightFront);
    var bottomLeftFront = anchor.TransformPoint(localBottomLeftFront);
    var topLeftFront = anchor.TransformPoint(localTopLeftFront);
    var topRightBack = anchor.TransformPoint(localTopRightBack);
    var bottomRightBack = anchor.TransformPoint(localBottomRightBack);
    var bottomLeftBack = anchor.TransformPoint(localBottomLeftBack);
    var topLeftBack = anchor.TransformPoint(localTopLeftBack);