A path is a pseudo object, representing a succession of points with orientation in space. pseudo object, since it is built using merely dummies and a customization script that describes its functionality and behaviour.

[Simple path containing 4 control points]

Path objects can be added to the scene with [Add > Path]. A path is composed by control points that define its curve in space. Control points can be shifted, copy/pasted or deleted. A path's basic properties are accessed and adjusted via its user parameters (implemented via a user config callback function), in the scene hierarchy:

[User parameter icon]

A path can also automatically generate extruded shapes; this functionality is enabled via its user parameters, and the shape profile, color and other details can be adjusted in its customization script, which uses the API function sim.generateShapefromPath:

--lua function path.shaping(path,pathIsClosed,upVector) -- following section generates a square extrusion shape: local section={0.02,-0.02,0.02,0.02,-0.02,0.02,-0.02,-0.02,0.02,-0.02} local color={0.7,0.9,0.9} local options=0 if pathIsClosed then options=options|4 end local shape=sim.generateShapeFromPath(path,section,options,upVector) sim.setShapeColor(shape,nil,sim.colorcomponent_ambient_diffuse,color) return shape end

[Simple path generating an extruded square shape]

To generate an extruded circular shape, use following code to create the section data:

--lua local section={} local radius=0.02 local sides=32 local da=math.pi*2/sides for i=0,sides-1,1 do section[2*i+1]=radius*math.cos(da*i) section[2*i+2]=radius*math.sin(da*i) end -- the section shoujld be closed (first and last points perfect overlap): section[#section+1]=section[1] section[#section+1]=section[2]

[Simple path generating an extruded circular shape]

Path data is stored inside of the path object, as custom object data. It can be accessed with:

#python # control point data (each one has x, y, z, qx, qy, qz, qw (position and quaternion)): ctrlPts = sim.unpackDoubleTable(sim.readCustomDataBlock(pathHandle, 'PATHCTRLPTS')) # path data (each one has x, y, z, qx, qy, qz, qw (position and quaternion)): pathData = sim.unpackDoubleTable(sim.readCustomDataBlock(pathHandle, 'PATH') --lua -- control point data (each one has x, y, z, qx, qy, qz, qw (position and quaternion)): local ctrlPts = sim.unpackDoubleTable(sim.readCustomDataBlock(pathHandle, 'PATHCTRLPTS')) -- path data (each one has x, y, z, qx, qy, qz, qw (position and quaternion)): local pathData = sim.unpackDoubleTable(sim.readCustomDataBlock(pathHandle, 'PATH')

Various API functions related to paths are available, e.g. in order to have an object follow a path in position and orientation, one could use following script:

#python import numpy as np def sysCall_init(): sim = require('sim') self.objectToFollowPath = sim.getObject('.') self.path = sim.getObject('/Path') pathData = sim.unpackDoubleTable(sim.readCustomDataBlock(self.path, 'PATH')) m = np.array(pathData).reshape(len(pathData) // 7, 7) self.pathPositions = m[:, :3].flatten().tolist() self.pathQuaternions = m[:, 3:].flatten().tolist() self.pathLengths, self.totalLength = sim.getPathLengths(self.pathPositions, 3) self.velocity = 0.04 # m/s self.posAlongPath = 0 self.previousSimulationTime = 0 sim.setStepping(True) def sysCall_thread(): while not sim.getSimulationStopping(): t = sim.getSimulationTime() self.posAlongPath += self.velocity * (t - self.previousSimulationTime) self.posAlongPath %= self.totalLength pos = sim.getPathInterpolatedConfig(self.pathPositions, self.pathLengths, self.posAlongPath) quat = sim.getPathInterpolatedConfig(self.pathQuaternions, self.pathLengths, self.posAlongPath, None, [2, 2, 2, 2]) sim.setObjectPosition(self.objectToFollowPath, pos, self.path) sim.setObjectQuaternion(self.objectToFollowPath, quat, self.path) self.previousSimulationTime = t sim.step() --lua function sysCall_init() sim = require('sim') objectToFollowPath = sim.getObject('.') path = sim.getObject('/Path') pathData = sim.unpackDoubleTable(sim.readCustomDataBlock(path, 'PATH')) local m = Matrix(#pathData // 7, 7, pathData) pathPositions = m:slice(1, 1, m:rows(), 3):data() pathQuaternions = m:slice(1, 4, m:rows(), 7):data() pathLengths, totalLength = sim.getPathLengths(pathPositions, 3) velocity = 0.04 -- m/s posAlongPath = 0 previousSimulationTime = 0 sim.setStepping(true) end function sysCall_thread() while not sim.getSimulationStopping() do local t = sim.getSimulationTime() posAlongPath = posAlongPath+velocity * (t - previousSimulationTime) posAlongPath = posAlongPath % totalLength local pos = sim.getPathInterpolatedConfig(pathPositions, pathLengths, posAlongPath) local quat = sim.getPathInterpolatedConfig(pathQuaternions, pathLengths, posAlongPath, nil, {2,2,2,2}) sim.setObjectPosition(objectToFollowPath, pos, path) sim.setObjectQuaternion(objectToFollowPath, quat, path) previousSimulationTime = t sim.step() end end