Coverage for algebra/coordinates/transformations.py: 58%

1"""

2 Coordinates System Transformations

3==================================

4

5 Provide transformations between different coordinate systems.

6

7 This module implements transformations between Cartesian coordinates and

8 various other coordinate systems commonly used in colour science and

9 computer graphics applications. The transformations preserve the spatial

10 relationships while expressing positions in different mathematical

11 representations.

12

13 The following transformations are available:

14

15- :func:`colour.algebra.cartesian_to_spherical`: Transform from Cartesian

16 to spherical coordinate system.

17- :func:`colour.algebra.spherical_to_cartesian`: Transform from spherical

18 to Cartesian coordinate system.

19- :func:`colour.algebra.cartesian_to_polar`: Transform from Cartesian to

20 polar coordinate system.

21- :func:`colour.algebra.polar_to_cartesian`: Transform from polar to

22 Cartesian coordinate system.

23- :func:`colour.algebra.cartesian_to_cylindrical`: Transform from

24 Cartesian to cylindrical coordinate system.

25- :func:`colour.algebra.cylindrical_to_cartesian`: Transform from

26 cylindrical to Cartesian coordinate system.

27

28 References

29----------

30- :cite:`Wikipedia2005a` : Wikipedia. (2005). ISO 31-11. Retrieved July 31,

31 2016, from https://en.wikipedia.org/wiki/ISO_31-11

32- :cite:`Wikipedia2006` : Wikipedia. (2006). List of common coordinate

33 transformations. Retrieved July 18, 2014, from

34 http://en.wikipedia.org/wiki/List_of_common_coordinate_transformations

35"""

36

37 from __future__ import annotations

38

39 import typing

40

41 import numpy as np

42

43 from colour.algebra import sdiv, sdiv_mode

44

45 if typing.TYPE_CHECKING:

46 from colour.hints import ArrayLike, NDArrayFloat

47

48 from colour.utilities import as_float_array, tsplit, tstack

49

50 __author__ = "Colour Developers"

51 __copyright__ = "Copyright 2013 Colour Developers"

52 __license__ = "BSD-3-Clause - https://opensource.org/licenses/BSD-3-Clause"

53 __maintainer__ = "Colour Developers"

54 __email__ = "colour-developers@colour-science.org"

55 __status__ = "Production"

56

57 __all__ = [

58 "cartesian_to_spherical",

59 "spherical_to_cartesian",

60 "cartesian_to_polar",

61 "polar_to_cartesian",

62 "cartesian_to_cylindrical",

63 "cylindrical_to_cartesian",

64]

65

66

67 def cartesian_to_spherical(a: ArrayLike) -> NDArrayFloat:

68 """

69 Transform specified cartesian coordinates array :math:`xyz` to spherical

70 coordinates array :math:`\\rho\\theta\\phi` (radial distance, inclination

71 or elevation and azimuth).

72

73 Parameters

74 ----------

75 a

76 Cartesian coordinates array :math:`xyz` to transform.

77

78 Returns

79 -------

80 :class:`numpy.ndarray`

81 Spherical coordinates array :math:`\\rho\\theta\\phi`, :math:`\\rho`

82 is in range [0, +inf], :math:`\\theta` is in range [0, pi] radians,

83 i.e., [0, 180] degrees, and :math:`\\phi` is in range [-pi, pi]

84 radians, i.e., [-180, 180] degrees.

85

86 References

87 ----------

88 :cite:`Wikipedia2006`, :cite:`Wikipedia2005a`

89

90 Examples

91 --------

92 >>> a = np.array([3, 1, 6])

93 >>> cartesian_to_spherical(a) # doctest: +ELLIPSIS

94 array([ 6.7823299..., 0.4850497..., 0.3217505...])

95 """

96

97 x, y, z = tsplit(a)

98

99 rho = np.linalg.norm(a, axis=-1)

100 with sdiv_mode():

101 theta = np.arccos(sdiv(z, rho))

102 phi = np.arctan2(y, x)

103

104 return tstack([rho, theta, phi])

105

106

107 def spherical_to_cartesian(a: ArrayLike) -> NDArrayFloat:

108 """

109 Transform specified spherical coordinates array :math:`\\rho\\theta\\phi`

110 (radial distance, inclination or elevation and azimuth) to cartesian

111 coordinates array :math:`xyz`.

112

113 Parameters

114 ----------

115 a

116 Spherical coordinates array :math:`\\rho\\theta\\phi` to transform,

117 :math:`\\rho` is in range [0, +inf], :math:`\\theta` is in range

118 [0, pi] radians, i.e., [0, 180] degrees, and :math:`\\phi` is in

119 range [-pi, pi] radians, i.e., [-180, 180] degrees.

120

121 Returns

122 -------

123 :class:`numpy.ndarray`

124 Cartesian coordinates array :math:`xyz`.

125

126 References

127 ----------

128 :cite:`Wikipedia2006`, :cite:`Wikipedia2005a`

129

130 Examples

131 --------

132 >>> a = np.array([6.78232998, 0.48504979, 0.32175055])

133 >>> spherical_to_cartesian(a) # doctest: +ELLIPSIS

134 array([ 3.0000000..., 0.9999999..., 5.9999999...])

135 """

136

137 rho, theta, phi = tsplit(a)

138

139 x = rho * np.sin(theta) * np.cos(phi)

140 y = rho * np.sin(theta) * np.sin(phi)

141 z = rho * np.cos(theta)

142

143 return tstack([x, y, z])

144

145

146 def cartesian_to_polar(a: ArrayLike) -> NDArrayFloat:

147 """

148 Transform specified cartesian coordinates array :math:`xy` to polar

149 coordinates array :math:`\\rho\\phi` (radial coordinate, angular

150 coordinate).

151

152 Parameters

153 ----------

154 a

155 Cartesian coordinates array :math:`xy` to transform.

156

157 Returns

158 -------

159 :class:`numpy.ndarray`

160 Polar coordinates array :math:`\\rho\\phi`, :math:`\\rho` is in range

161 [0, +inf], :math:`\\phi` is in range [-pi, pi] radians, i.e., [-180,

162 180] degrees.

163

164 References

165 ----------

166 :cite:`Wikipedia2006`, :cite:`Wikipedia2005a`

167

168 Examples

169 --------

170 >>> a = np.array([3, 1])

171 >>> cartesian_to_polar(a) # doctest: +ELLIPSIS

172 array([ 3.1622776..., 0.3217505...])

173 """

174

175 x, y = tsplit(a)

176

177 rho = np.hypot(x, y)

178 phi = np.arctan2(y, x)

179

180 return tstack([rho, phi])

181

182

183 def polar_to_cartesian(a: ArrayLike) -> NDArrayFloat:

184 """

185 Transform specified polar coordinates array :math:`\\rho\\phi` (radial

186 coordinate, angular coordinate) to Cartesian coordinates array :math:`xy`.

187

188 Parameters

189 ----------

190 a

191 Polar coordinates array :math:`\\rho\\phi` to transform where

192 :math:`\\rho` is the radial coordinate in range [0, +inf] and

193 :math:`\\phi` is the angular coordinate in range [-pi, pi] radians

194 (i.e., [-180, 180] degrees).

195

196 Returns

197 -------

198 :class:`numpy.ndarray`

199 Cartesian coordinates array :math:`xy`.

200

201 References

202 ----------

203 :cite:`Wikipedia2006`, :cite:`Wikipedia2005a`

204

205 Examples

206 --------

207 >>> a = np.array([3.16227766, 0.32175055])

208 >>> polar_to_cartesian(a) # doctest: +ELLIPSIS

209 array([ 3. , 0.9999999...])

210 """

211

212 rho, phi = tsplit(a)

213

214 x = rho * np.cos(phi)

215 y = rho * np.sin(phi)

216

217 return tstack([x, y])

218

219

220 def cartesian_to_cylindrical(a: ArrayLike) -> NDArrayFloat:

221 """

222 Transform specified cartesian coordinates array :math:`xyz` to cylindrical

223 coordinates array :math:`\\rho\\phi z` (radial distance, azimuth and

224 height).

225

226 Parameters

227 ----------

228 a

229 Cartesian coordinates array :math:`xyz` to transform.

230

231 Returns

232 -------

233 :class:`numpy.ndarray`

234 Cylindrical coordinates array :math:`\\rho\\phi z`, :math:`\\rho` is

235 in range [0, +inf], :math:`\\phi` is in range [-pi, pi] radians

236 i.e., [-180, 180] degrees, :math:`z` is in range [0, +inf].

237

238 References

239 ----------

240 :cite:`Wikipedia2006`, :cite:`Wikipedia2005a`

241

242 Examples

243 --------

244 >>> a = np.array([3, 1, 6])

245 >>> cartesian_to_cylindrical(a) # doctest: +ELLIPSIS

246 array([ 3.1622776..., 0.3217505..., 6. ])

247 """

248

249 a = as_float_array(a)

250

251 rho, phi = tsplit(cartesian_to_polar(a[..., 0:2]))

252

253 return tstack([rho, phi, a[..., -1]])

254

255

256 def cylindrical_to_cartesian(a: ArrayLike) -> NDArrayFloat:

257 """

258 Transform specified cylindrical coordinates array :math:`\\rho\\phi z`

259 (radial distance, azimuth and height) to cartesian coordinates array

260 :math:`xyz`.

261

262 Parameters

263 ----------

264 a

265 Cylindrical coordinates array :math:`\\rho\\phi z` to transform,

266 where :math:`\\rho` is in range [0, +inf], :math:`\\phi` is in

267 range [-pi, pi] radians i.e., [-180, 180] degrees, and :math:`z`

268 is in range [0, +inf].

269

270 Returns

271 -------

272 :class:`numpy.ndarray`

273 Cartesian coordinates array :math:`xyz`.

274

275 References

276 ----------

277 :cite:`Wikipedia2006`, :cite:`Wikipedia2005a`

278

279 Examples

280 --------

281 >>> a = np.array([3.16227766, 0.32175055, 6.00000000])

282 >>> cylindrical_to_cartesian(a) # doctest: +ELLIPSIS

283 array([ 3. , 0.9999999..., 6. ])

284 """

285

286 a = as_float_array(a)

287

288 x, y = tsplit(polar_to_cartesian(a[..., 0:2]))

289

290 return tstack([x, y, a[..., -1]])