or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

advanced-math.mdbasic-operations.mdconstruction.mdindex.mdinterpolation.mdrotation.md

rotation.mddocs/

0

# 3D Rotation

1

2

Apply quaternion rotations to 3D vectors and convert between different rotation representations including rotation matrices, Euler angles, and axis-angle pairs.

3

4

## Capabilities

5

6

### Vector Rotation

7

8

Rotate 3D vectors using quaternion rotations.

9

10

```python { .api }

11

def rotate(self, vector):

12

"""

13

Rotate a 3D vector by the rotation stored in the quaternion.

14

15

Parameters:

16

vector: 3-element sequence (list, tuple, numpy array) or Quaternion

17

For sequences: [x, y, z] coordinates

18

For Quaternion: uses vector part as 3D vector

19

20

Returns:

21

Same type as input: Rotated vector

22

- list input → list output

23

- tuple input → tuple output

24

- numpy array → numpy array

25

- Quaternion → Quaternion (rotated vector part)

26

27

Raises:

28

TypeError: If vector elements cannot be converted to real numbers

29

ValueError: If vector cannot be interpreted as 3-vector

30

"""

31

```

32

33

**Usage Examples:**

34

35

```python

36

from pyquaternion import Quaternion

37

import numpy as np

38

39

# 90-degree rotation about Y-axis

40

q = Quaternion(axis=[0, 1, 0], degrees=90)

41

42

# Rotate different vector types

43

vector_list = [1, 0, 0]

44

rotated_list = q.rotate(vector_list) # [0.0, 0.0, -1.0]

45

46

vector_tuple = (1, 0, 0)

47

rotated_tuple = q.rotate(vector_tuple) # (0.0, 0.0, -1.0)

48

49

vector_array = np.array([1, 0, 0])

50

rotated_array = q.rotate(vector_array) # array([0., 0., -1.])

51

52

# Rotate quaternion's vector part

53

q_vector = Quaternion(vector=[1, 0, 0])

54

rotated_q = q.rotate(q_vector) # Quaternion with rotated vector

55

```

56

57

### Axis Extraction

58

59

Get the rotation axis with handling for edge cases.

60

61

```python { .api }

62

def get_axis(self, undefined=np.zeros(3)):

63

"""

64

Get the rotation axis with fallback for undefined cases.

65

66

For unit quaternions representing rotations, returns the axis of rotation.

67

For edge cases (identity quaternion, pure real quaternions), returns

68

the provided fallback value.

69

70

Parameters:

71

undefined: array-like, default [0, 0, 0]

72

Fallback value when axis is undefined

73

74

Returns:

75

numpy.ndarray: Unit vector representing rotation axis,

76

or undefined value for edge cases

77

78

Note:

79

The axis property may return [0, 0, 0] for identity rotations,

80

while this method allows custom handling of such cases.

81

"""

82

```

83

84

**Usage Examples:**

85

86

```python

87

from pyquaternion import Quaternion

88

import numpy as np

89

90

# Regular rotation - has well-defined axis

91

q = Quaternion(axis=[1, 1, 0], degrees=45)

92

axis = q.get_axis()

93

print(f"Rotation axis: {axis}") # Normalized [1, 1, 0]

94

95

# Identity quaternion - no rotation, undefined axis

96

q_identity = Quaternion()

97

axis_default = q_identity.get_axis() # [0, 0, 0]

98

axis_custom = q_identity.get_axis(undefined=[0, 0, 1]) # [0, 0, 1]

99

100

print(f"Identity axis (default): {axis_default}")

101

print(f"Identity axis (custom): {axis_custom}")

102

```

103

104

### Matrix Representations

105

106

Convert quaternions to rotation and transformation matrices.

107

108

```python { .api }

109

@property

110

def rotation_matrix(self):

111

"""

112

Get 3x3 rotation matrix equivalent of the quaternion rotation.

113

114

The quaternion is automatically normalized to unit length.

115

116

Returns:

117

numpy.ndarray: 3x3 orthogonal rotation matrix

118

119

Note:

120

Only meaningful for unit quaternions. Non-unit quaternions

121

are automatically normalized before conversion.

122

"""

123

124

@property

125

def transformation_matrix(self):

126

"""

127

Get 4x4 homogeneous transformation matrix.

128

129

Creates a 4x4 matrix with the rotation in the upper-left 3x3 block,

130

zero translation, and [0, 0, 0, 1] in the bottom row.

131

132

Returns:

133

numpy.ndarray: 4x4 homogeneous transformation matrix

134

"""

135

```

136

137

**Usage Examples:**

138

139

```python

140

# Create rotation quaternion

141

q = Quaternion(axis=[0, 0, 1], degrees=45) # 45° about Z-axis

142

143

# Get rotation matrix

144

rot_matrix = q.rotation_matrix

145

print(f"Rotation matrix shape: {rot_matrix.shape}") # (3, 3)

146

print(f"Determinant: {np.linalg.det(rot_matrix)}") # ~1.0 (orthogonal)

147

148

# Get transformation matrix

149

transform_matrix = q.transformation_matrix

150

print(f"Transform matrix shape: {transform_matrix.shape}") # (4, 4)

151

152

# Apply to multiple points

153

points = np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1]]).T # 3x3

154

rotated_points = rot_matrix @ points

155

```

156

157

### Euler Angles

158

159

Convert quaternions to Euler angle representations.

160

161

```python { .api }

162

@property

163

def yaw_pitch_roll(self):

164

"""

165

Get equivalent yaw-pitch-roll angles (intrinsic Tait-Bryan z-y'-x'').

166

167

The quaternion is automatically normalized to unit length.

168

169

Returns:

170

tuple: (yaw, pitch, roll) angles in radians

171

yaw: rotation about z-axis, range [-π, π]

172

pitch: rotation about y'-axis, range [-π/2, π/2]

173

roll: rotation about x''-axis, range [-π, π]

174

175

Note:

176

Rotation matrix equivalent: R = R_x(roll) * R_y(pitch) * R_z(yaw)

177

"""

178

```

179

180

**Usage Example:**

181

182

```python

183

# Create quaternion from Euler angles equivalent

184

q = Quaternion(axis=[0, 0, 1], degrees=30) # Yaw rotation

185

186

# Extract Euler angles

187

yaw, pitch, roll = q.yaw_pitch_roll

188

print(f"Yaw: {np.degrees(yaw):.1f}°") # ~30.0°

189

print(f"Pitch: {np.degrees(pitch):.1f}°") # ~0.0°

190

print(f"Roll: {np.degrees(roll):.1f}°") # ~0.0°

191

```

192

193

### Axis-Angle Representation

194

195

Extract rotation axis and angle from quaternions.

196

197

```python { .api }

198

@property

199

def axis(self):

200

"""

201

Get the unit vector axis of rotation.

202

203

Returns:

204

numpy.ndarray: 3-element unit vector [x, y, z]

205

Returns [0, 0, 0] for null rotations

206

"""

207

208

def get_axis(self, undefined=np.zeros(3)):

209

"""

210

Get rotation axis with custom fallback for null rotations.

211

212

Parameters:

213

undefined: 3-element sequence to return for null rotations

214

Default: [0, 0, 0]

215

216

Returns:

217

numpy.ndarray: 3-element unit vector or undefined value

218

"""

219

220

@property

221

def angle(self):

222

"""

223

Get rotation angle in radians.

224

225

Returns:

226

float: Angle in range (-π, π), sign indicates direction

227

Magnitude represents rotation amount

228

229

Note:

230

For 180° rotations, the axis/angle representation may

231

jump discontinuously between equivalent representations.

232

"""

233

234

@property

235

def degrees(self):

236

"""

237

Get rotation angle in degrees.

238

239

Returns:

240

float: Angle in degrees, converted from radians

241

"""

242

243

@property

244

def radians(self):

245

"""Alias for angle property."""

246

```

247

248

**Usage Examples:**

249

250

```python

251

# Create quaternion with known axis and angle

252

original_axis = [1, 1, 0] # Will be normalized

253

original_angle = 60 # degrees

254

q = Quaternion(axis=original_axis, degrees=original_angle)

255

256

# Extract axis and angle

257

extracted_axis = q.axis

258

extracted_angle_deg = q.degrees

259

extracted_angle_rad = q.radians

260

261

print(f"Original axis: {np.array(original_axis) / np.linalg.norm(original_axis)}")

262

print(f"Extracted axis: {extracted_axis}")

263

print(f"Original angle: {original_angle}°")

264

print(f"Extracted angle: {extracted_angle_deg:.1f}°")

265

266

# Handle null rotation case

267

identity_q = Quaternion() # Identity quaternion

268

null_axis = identity_q.axis # [0, 0, 0]

269

null_angle = identity_q.degrees # 0.0

270

271

# Custom undefined axis for null rotations

272

custom_axis = identity_q.get_axis(undefined=[1, 0, 0])

273

```

274

275

### Polar Decomposition

276

277

Advanced decomposition of quaternions into unit vector and angle components.

278

279

```python { .api }

280

@property

281

def polar_unit_vector(self):

282

"""

283

Get the unit vector component of polar decomposition.

284

285

Returns:

286

numpy.ndarray: Unit vector direction [x, y, z]

287

288

Raises:

289

ZeroDivisionError: If quaternion is pure real (no unique unit vector)

290

"""

291

292

@property

293

def polar_angle(self):

294

"""

295

Get the angle component of polar decomposition.

296

297

Returns:

298

float: Polar angle in radians

299

"""

300

301

@property

302

def polar_decomposition(self):

303

"""

304

Get complete polar decomposition.

305

306

Decomposes quaternion as: q = |q| * exp(unit_vector * angle)

307

308

Returns:

309

tuple: (unit_vector, angle)

310

unit_vector: numpy array [x, y, z]

311

angle: float in radians

312

313

Raises:

314

ZeroDivisionError: For pure real quaternions

315

"""

316

```

317

318

**Usage Example:**

319

320

```python

321

# Create non-trivial quaternion

322

q = Quaternion(axis=[1, 1, 1], degrees=120)

323

324

try:

325

# Get polar decomposition

326

unit_vec, polar_angle = q.polar_decomposition

327

print(f"Unit vector: {unit_vec}")

328

print(f"Polar angle: {np.degrees(polar_angle):.1f}°")

329

330

# Reconstruct quaternion (approximately)

331

reconstructed = q.norm * Quaternion.exp(

332

Quaternion(vector=unit_vec * polar_angle)

333

)

334

print(f"Original: {q}")

335

print(f"Reconstructed: {reconstructed}")

336

337

except ZeroDivisionError:

338

print("Cannot decompose pure real quaternion")

339

```

340

341

### Internal Rotation Methods

342

343

Internal methods used by the rotation system.

344

345

```python { .api }

346

def _rotate_quaternion(self, q):

347

"""

348

Rotate a quaternion vector using stored rotation.

349

350

Parameters:

351

q: Quaternion with vector part to rotate (scalar part ignored)

352

353

Returns:

354

Quaternion: Rotated quaternion using formula: self * q * self.conjugate

355

"""

356

357

def _wrap_angle(self, theta):

358

"""

359

Wrap angle to range (-π, π].

360

361

Parameters:

362

theta: Angle in radians

363

364

Returns:

365

float: Wrapped angle, with odd multiples of π mapped to +π

366

"""

367

```