A triaxial ellipsoid with semi-axes radii (x, y, z) centered at the
origin, for an equirectangular texture in geodetic coordinates.
The vertex at geodetic latitude lat and longitude lon is the point
whose surface normal is n = (cos lat cos lon, cos lat sin lon, sin lat):
p = (a^2 nx, b^2 ny, c^2 nz) / sqrt(a^2 nx^2 + b^2 ny^2 + c^2 nz^2).
So the normals are exact and texture rows are at geodetic latitude.
(OpenFrames makes an ellipsoid by scaling a sphere, which skews the
normals and maps the texture by parametric latitude.)
Longitude 0 is on +x and the north pole on +z; texture u runs from longitude -180 (u = 0) to +180 (u = 1), v from the north pole (v = 0) to the south pole (v = 1). The seam column and pole rows are duplicated so the texture wraps; triangles are counter-clockwise seen from outside, and the degenerate triangles at the poles are left out. Indices are 0-based. Sizes are given by ellipsoid_size.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| real(kind=c_double), | intent(in), | dimension(3) | :: | radii |
semi-axes along x, y, z |
|
| integer, | intent(in) | :: | n_lon |
segments in longitude (>= 3) |
||
| integer, | intent(in) | :: | n_lat |
segments in latitude (>= 2) |
||
| real(kind=c_float), | intent(out), | dimension(:,:) | :: | xyz |
(3, n_vertices) |
|
| real(kind=c_float), | intent(out), | dimension(:,:) | :: | normals |
(3, n_vertices) |
|
| real(kind=c_float), | intent(out), | dimension(:,:) | :: | uv |
(2, n_vertices) |
|
| integer(kind=c_int32_t), | intent(out), | dimension(:) | :: | indices |
(n_indices) |
pure subroutine ellipsoid(radii, n_lon, n_lat, xyz, normals, uv, indices) real(c_double), dimension(3), intent(in) :: radii !! semi-axes along x, y, z integer, intent(in) :: n_lon !! segments in longitude (>= 3) integer, intent(in) :: n_lat !! segments in latitude (>= 2) real(c_float), dimension(:,:), intent(out) :: xyz !! (3, n_vertices) real(c_float), dimension(:,:), intent(out) :: normals !! (3, n_vertices) real(c_float), dimension(:,:), intent(out) :: uv !! (2, n_vertices) integer(c_int32_t), dimension(:), intent(out) :: indices !! (n_indices) real(c_double), parameter :: pi = acos(-1.0_c_double) real(c_double) :: lat, lon, n(3), r2(3), p(3) integer :: i, j, k, a, b, c, d r2 = radii**2 do j = 0, n_lat lat = -0.5_c_double * pi + pi * real(j, c_double) / real(n_lat, c_double) do i = 0, n_lon lon = -pi + 2.0_c_double * pi * real(i, c_double) / real(n_lon, c_double) k = j * (n_lon + 1) + i + 1 n = [cos(lat) * cos(lon), cos(lat) * sin(lon), sin(lat)] p = r2 * n xyz(:, k) = real(p / sqrt(dot_product(p, n)), c_float) normals(:, k) = real(n, c_float) uv(:, k) = real([real(i, c_double) / real(n_lon, c_double), & 1.0_c_double - real(j, c_double) / real(n_lat, c_double)], c_float) end do end do ! quad (i, j): a = (i, j), b = (i+1, j), c = (i+1, j+1), d = (i, j+1); ! triangles (a, b, c) and (a, c, d), except (a, b, c) on the south row ! and (a, c, d) on the north row, which are degenerate k = 0 do j = 0, n_lat - 1 do i = 0, n_lon - 1 a = j * (n_lon + 1) + i b = a + 1 d = a + n_lon + 1 c = d + 1 if (j > 0) then indices(k+1:k+3) = int([a, b, c], c_int32_t) k = k + 3 end if if (j < n_lat - 1) then indices(k+1:k+3) = int([a, c, d], c_int32_t) k = k + 3 end if end do end do end subroutine ellipsoid