static inline void transform_pos()

in Transform_V1/vf_transform_v1.c [202:527]


static inline void transform_pos(
        TransformContext *ctx,
        float x, float y,
        float *outX, float *outY,
        int *has_mapping,
        float input_pixel_w
        )
{
    int is_right = 0;

    *has_mapping = 1;
    if (ctx->input_stereo_format != STEREO_FORMAT_MONO) {
        if (y > Y_HALF) {
            y = (y - Y_HALF) / Y_HALF;
            if (ctx->vflip) {
                y = 1.0f - y;
            }
            is_right = 1;
        } else {
            y = y / Y_HALF;
        }
    }

    if (ctx->output_layout == LAYOUT_PLANE_POLES) {
        if (x >= ctx->main_plane_ratio) {
            float dx = (x * 2 - 1 - ctx->main_plane_ratio) / (1 - ctx->main_plane_ratio);
            if (y < Y_HALF) {
                // Bottom
                float dy = (y - YC_BOTTOM) / PH;
                *outX = (atan2f(dy, dx)) / (M_PI * 2.0f) + 0.75f;
                *outY = sqrtf(dy * dy + dx * dx) * 0.25f;
            } else {
                // Top
                float dy = (y - YC_TOP) / PH;
                *outX = (atan2f(dy, dx)) / (M_PI * 2.0f) + 0.75f;
                *outY = 1.0f - sqrtf(dy * dy + dx * dx) * 0.25f;
            }
            if (*outX > 1.0f) {
                *outX -= 1.0f;
            }
        } else {
            // Main
            *outX = x / ctx->main_plane_ratio;
            *outY = y * 0.5f + 0.25f;
        }
    } else if (ctx->output_layout == LAYOUT_PLANE_POLES_6) {
        int face = (int) (x * 6);
        if (face < 4) {
            // Main
            *outX = x * 6.0f / 4.0f;
            *outY = y * 0.5f + 0.25f;
        } else {
            float dx, dy;
            x = x * 6.0f - face;
            dx = x * 2 - 1;
            dy = y * 2 - 1;
            if (face == 4) {
                // Top
                *outX = (atan2f(dy, dx)) / (M_PI * 2.0f) + 0.75f;
                *outY = 1.0f - sqrtf(dy * dy + dx * dx) * 0.25f;
            } else {
                // Bottom
                *outX = (atan2f(dy, dx)) / (M_PI * 2.0f) + 0.75f;
                *outY = sqrtf(dy * dy + dx * dx) * 0.25f;
            }
            if (*outX > 1.0f) {
                *outX -= 1.0f;
            }
        }
    } else if (ctx->output_layout == LAYOUT_FLAT_FIXED) {
        // Per the Metadata RFC for orienting the equirectangular coords:
        //                           Heading
        //         -180           0           180
        //       90 +-------------+-------------+   0.0
        //          |             |             |
        //    P     |             |      o      |
        //    i     |             ^             |
        //    t   0 +-------------X-------------+   0.5
        //    c     |             |             |
        //    h     |             |             |
        //          |             |             |
        //      -90 +-------------+-------------+   1.0
        //          0.0          0.5          1.0
        //    X  - the default camera center
        //    ^  - the default up vector
        //    o  - the image center for a pitch of 45 and a heading of 90
        //    Coords on left and top sides are degrees
        //    Coords on right and bottom axes are our X/Y in range [0..1)
        //  Note: Negative field of view can be supplied to flip the image.
        *outX = ((x - 0.5f) * ctx->fixed_hfov + ctx->fixed_yaw)   / 360.0f
            + 0.5f;
        *outY = ((y - 0.5f) * ctx->fixed_vfov - ctx->fixed_pitch) / 180.0f
            + 0.5f;

        normalize_equirectangular(*outX, *outY, outX, outY);
    } else if (ctx->output_layout == LAYOUT_CUBEMAP ||
            ctx->output_layout == LAYOUT_PLANE_POLES_CUBEMAP ||
            ctx->output_layout == LAYOUT_CUBEMAP_32 ||
            ctx->output_layout == LAYOUT_CUBEMAP_180 ||
            ctx->output_layout == LAYOUT_PLANE_CUBEMAP_32 ||
            ctx->output_layout == LAYOUT_PLANE_CUBEMAP ||
            ctx->output_layout == LAYOUT_BARREL ||
            ctx->output_layout == LAYOUT_TB_ONLY ||
            ctx->output_layout == LAYOUT_TB_BARREL_ONLY) {
        float qx, qy, qz;
        float cos_y, cos_p, sin_y, sin_p;
        float tx, ty, tz;
        float yaw, pitch;
        float d;
        y = 1.0f - y;

        const float *vx, *vy, *p;
        int face = 0;
        if (ctx->output_layout == LAYOUT_CUBEMAP) {
            face = (int) (x * 6);
            x = x * 6.0f - face;
        } else if (ctx->output_layout == LAYOUT_CUBEMAP_32) {
            int vface = (int) (y * 2);
            int hface = (int) (x * 3);
            x = x * 3.0f - hface;
            y = y * 2.0f - vface;
            face = hface + (1 - vface) * 3;
        } else if (ctx->output_layout == LAYOUT_CUBEMAP_180) {
            // LAYOUT_CUBEMAP_180: layout for spatial resolution downsampling with 180 degree viewport size
            //
            // - Given a view (yaw,pitch) we can create a customized cube mapping to make the view center at the front cube face.
            // - A 180 degree viewport cut the cube into 2 equal-sized halves: front half and back half.
            // - The front half contains these faces of the cube: front, half of right, half of left, half of top, half of bottom.
            //   The back half contains these faces of the cube: back, half of right, half of left, half of top, half of bottom.
            //   Illutrasion on LAYOUT_CUBEMAP_32 (mono):
            //
            //   +---+---+---+---+---+---+
            //   |   |   |   |   |   5   |
            //   + 1 | 2 + 3 | 4 +-------+     Area 1, 4, 6, 7, 9 are in the front half
            //   |   |   |   |   |   6   |
            //   +---+---+---+---+---+---+     Area 2, 3, 5, 8, 0 are in the back half
            //   |   7   |       |       |
            //   +-------+   9   +   0   +
            //   |   8   |       |       |
            //   +---+---+---+---+---+---+
            //
            // - LAYOUT_CUBEMAP_180 reduces the spatial resolution of the back half to 25% (1/2 height, 1/2 width makes 1/4 size)
            //   and then re-pack the cube map like this:
            //
            //   +---+---+---+---+---+      Front half   Back half (1/4 size)
            //   |       |   |   c   |      ----------   --------------------
            //   +   a   + b +---+----      Area a = 9   Area f = 0
            //   |       |   | f |   |      Area b = 4   Area g = 3
            //   +---+---+---+---+ d +      Area c = 6   Area h = 2
            //   |g|h|-i-|   e   |   |      Area d = 1   Area i1(top) = 5
            //   +---+---+---+---+---+      Area e = 7   Area i2(bottom) = 8
            //
            if (0.0f <= y && y < 1.0f/3 && 0.0f <= x && x < 0.8f) { // Area g, h, i1, i2, e
                if (0.0f <= x && x < 0.1f) { // g
                    face = LEFT;
                    x = x/0.2f;
                    y = y/(1.0f/3);
                }
                else if (0.1f <= x && x < 0.2f) { // h
                    face = RIGHT;
                    x = (x-0.1f)/0.2f + 0.5f;
                    y = y/(1.0f/3);
                }
                else if (0.2f <= x && x < 0.4f) {
                    if (y >= 1.0f/6){ //i1
                        face = TOP;
                        x = (x-0.2f)/0.2f;
                        y  =(y-1.0f/6)/(1.0f/3) + 0.5f;
                    }
                    else { // i2
                        face = BOTTOM;
                        x = (x-0.2f)/0.2f;
                        y = y/(1.0f/3);
                    }
                }
                else if (0.4f <= x && x < 0.8f){ // e
                    face = BOTTOM;
                    x = (x-0.4f)/0.4f;
                    y = y/(2.0f/3) + 0.5f;
                }
            }
            else if (2.0f/3 <= y && y < 1.0f && 0.6f <= x && x < 1.0f) { // Area c
                face = TOP;
                x = (x-0.6f)/0.4f;
                y = (y-2.0f/3)/(2.0f/3);
            }
            else { // Area a, b, f, d
                if (0.0f <= x && x < 0.4f) { // a
                    face = FRONT;
                    x = x/0.4f;
                    y = (y-1.0/3)/(2.0f/3);
                }
                else if (0.4f <= x && x < 0.6f) { // b
                    face = LEFT;
                    x = (x-0.4f)/0.4f + 0.5f;
                    y = (y-1.0f/3)/(2.0f/3);
                }
                else if (0.6f <= x && x < 0.8f) { // f
                    face = BACK;
                    x = (x-0.6f)/0.2f;
                    y = (y-1.0f/3)/(1.0f/3);
                }
                else if (0.8f <= x && x < 1.0f) { // d
                    face = RIGHT;
                    x = (x-0.8f)/0.4f;
                    y = y/(2.0f/3);
                }
            }
        } else if (ctx->output_layout == LAYOUT_PLANE_CUBEMAP_32) {
            int vface = (int) (y * 2);
            int hface = (int) (x * 3);
            x = x * 3.0f - hface;
            y = y * 2.0f - vface;
            face = hface + (1 - vface) * 3;
            face = PLANE_CUBEMAP_32_FACE_MAP[face];
        } else if (ctx->output_layout == LAYOUT_PLANE_POLES_CUBEMAP) {
            face = (int) (x * 4.5f);
            x = x * 4.5f - face;
            if (face == 4) {
                x *= 2.0f;
                y *= 2.0f;
                if (y >= 1.0f) {
                    y -= 1.0f;
                } else {
                    face = 5; // bottom
                }
            }
            face = PLANE_POLES_FACE_MAP[face];
        } else if (ctx->output_layout == LAYOUT_PLANE_CUBEMAP) {
            face = (int) (x * 6);
            x = x * 6.0f - face;
            face = PLANE_CUBEMAP_FACE_MAP[face];
        } else if (ctx->output_layout == LAYOUT_BARREL) {
          if (x <= 0.8f) {
            yaw = (2.5f * x - 1.0f) * ctx->expand_coef * M_PI;
            pitch = (y * 0.5f  - 0.25f) * ctx->expand_coef * M_PI;
            face = -1;
          } else {
            int vFace = (int) (y * 2);
            face = (vFace == 1) ? TOP : BOTTOM;
            x = x * 5.0f - 4.0f;
            y = y * 2.0f - vFace;
          }
        } else if (ctx->output_layout == LAYOUT_TB_ONLY ||
                ctx->output_layout == LAYOUT_TB_BARREL_ONLY) {
          int vFace = (int) (y * 2);
          face = (vFace == 1) ? TOP : BOTTOM;
          y = y * 2.0f - vFace;
        } else {
            av_assert0(0);
        }

        if (ctx->output_layout == LAYOUT_BARREL && face < 0) {
          float sin_yaw = sin(yaw);
          float sin_pitch = sin(pitch);
          float cos_yaw = cos(yaw);
          float cos_pitch = cos(pitch);
          qx = sin_yaw * cos_pitch;
          qy = sin_pitch;
          qz = cos_yaw * cos_pitch;
        } else {
          av_assert1(x >= 0 && x <= 1);
          av_assert1(y >= 0 && y <= 1);
          av_assert1(face >= 0 && face < 6);

          if (ctx->output_layout == LAYOUT_BARREL ||
            ctx->output_layout == LAYOUT_TB_BARREL_ONLY) {
            float radius = (x - 0.5f) * (x - 0.5f) + (y - 0.5f) * (y - 0.5f);
            if (radius > 0.25f * ctx->expand_coef * ctx->expand_coef) {
              *has_mapping = 0;
              return;
            }
          }

          x = (x - 0.5f) * ctx->expand_coef + 0.5f;
          y = (y - 0.5f) * ctx->expand_coef + 0.5f;

          switch (face) {
              case RIGHT:   p = P5; vx = NZ; vy = PY; break;
              case LEFT:    p = P0; vx = PZ; vy = PY; break;
              case TOP:     p = P6; vx = PX; vy = NZ; break;
              case BOTTOM:  p = P0; vx = PX; vy = PZ; break;
              case FRONT:   p = P4; vx = PX; vy = PY; break;
              case BACK:    p = P1; vx = NX; vy = PY; break;
          }
          qx = p [0] + vx [0] * x + vy [0] * y;
          qy = p [1] + vx [1] * x + vy [1] * y;
          qz = p [2] + vx [2] * x + vy [2] * y;
        }

        // rotation
        sin_y = sin(ctx->fixed_yaw*M_PI/180.0f);
        sin_p = sin(ctx->fixed_pitch*M_PI/180.0f);
        cos_y = cos(ctx->fixed_yaw*M_PI/180.0f);
        cos_p = cos(ctx->fixed_pitch*M_PI/180.0f);
        tx = qx * cos_y   - qy * sin_y*sin_p  + qz * sin_y*cos_p;
        ty =                qy * cos_p        + qz * sin_p;
        tz = qx* (-sin_y) - qy * cos_y*sin_p  + qz * cos_y*cos_p;

        d = sqrtf(tx * tx + ty * ty + tz * tz);
        *outX = -atan2f (-tx / d, tz / d) / (M_PI * 2.0f) + 0.5f;
        if (ctx->output_layout == LAYOUT_BARREL) {
          *outX = FFMIN(*outX, 1.0f - input_pixel_w * 0.5f);
          *outX = FFMAX(*outX, input_pixel_w * 0.5f);
        }
        *outY = asinf (-ty / d) / M_PI + 0.5f;
    }

    if (ctx->input_stereo_format == STEREO_FORMAT_TB) {
        if (is_right) {
            *outY = *outY * Y_HALF + Y_HALF;
        } else {
            *outY = *outY * Y_HALF;
        }
    } else if (ctx->input_stereo_format == STEREO_FORMAT_LR) {
        if (is_right) {
            *outX = *outX * X_HALF + X_HALF;
        } else {
            *outX = *outX * X_HALF;
        }
    } else {
        // mono no steps needed.
    }
    av_assert1(*outX >= 0 && *outX <= 1);
    av_assert1(*outY >= 0 && *outY <= 1);
}