# Paths#

## Assigning absolute paths#

Absolute object paths are assigned at initialization or through the object properties.

import numpy as np
from scipy.spatial.transform import Rotation as R
import magpylib as magpy

ts = np.linspace(0, 10, 51)
pos = np.array([(t, 0, np.sin(t)) for t in ts])
ori = R.from_rotvec(np.array([(0, -np.cos(t)*0.785, 0) for t in ts]))

# set path at initialization
sensor = magpy.Sensor(position=pos, orientation=ori)

# set path through properties
cube = magpy.magnet.Cuboid(magnetization=(0,0,1), dimension=(.5,.5,.5))
cube.position = pos + np.array((0,0,3))
cube.orientation = ori

magpy.show(sensor, cube, style_path_frames=10)


## Move and rotate#

The attributes position and orientation can be either of “scalar” nature, i.e. a single position or a single rotation, or “vectors” when they are arrays of such scalars. The two attributes together define an object “path”.

The move and rotate methods obey the following rules:

• Scalar input is applied to the whole object path, starting with path index start. With the default start='auto' the index is set to start=0 and the functionality is moving objects around.

• Vector input of length $$n$$ applies the individual $$n$$ operations to $$n$$ object path entries, starting with path index start. Padding applies when the input exceeds the existing path. With the default start='auto' the index is set to start=len(object path) and the functionality is appending paths.

import magpylib as magpy

sensor = magpy.Sensor()

sensor.move((1,1,1))                                      # scalar input is by default applied
print(sensor.position)                                    # to the whole path
# out: [1. 1. 1.]

sensor.move([(1,1,1), (2,2,2)])                           # vector input is by default appended
print(sensor.position)                                    # to the existing path
# out: [[1. 1. 1.]  [2. 2. 2.]  [3. 3. 3.]]

sensor.move((1,1,1), start=1)                             # scalar input and start=1 is applied
print(sensor.position)                                    # to whole path starting at index 1
# out: [[1. 1. 1.]  [3. 3. 3.]  [4. 4. 4.]]

sensor.move([(0,0,10), (0,0,20)], start=1)                # vector input and start=1 merges
print(sensor.position)                                    # the input with the existing path
# out: [[ 1.  1.  1.]  [ 3.  3. 13.]  [ 4.  4. 24.]]      # starting at index 1.


## Relative paths#

move and rotate input is interpreted relative to the existing path. Vector input is by default appended:

import numpy as np
from magpylib.magnet import Sphere

x_path = np.linspace((0,0,0), (10,0,0), 10)[1:]
z_path = np.linspace((0,0,0), (0,0,10), 10)[1:]

sphere = Sphere(magnetization=(0,0,1), diameter=3)

for _ in range(3):
sphere.move(x_path).move(z_path)

sphere.show()


## Merging paths#

Complex paths can be created by merging multiple path operations. This is done with vector input for the move and rotate methods, and choosing values for start that will make the paths overlap. In the following example we combine a linear path with a rotation about self (anchor=None) until path index 30. Thereon, a second rotation about the origin is applied, creating a spiral motion.

import numpy as np
from magpylib.magnet import Cuboid

cube =  Cuboid(magnetization=(0,0,100), dimension=(2,2,2))
cube.position = np.linspace((0,0,0), (10,0,0), 60)
cube.rotate_from_rotvec(np.linspace((0,0,0), (0,0,360), 30), start=0)
cube.rotate_from_rotvec(np.linspace((0,0,0), (0,0,360), 30), anchor=0, start=30)

cube.show(backend='plotly', animation=True)