anispace (development version)
Removed
-
calculate_angular_difference()anddiff_angle()move to anicore, ascirc_difference()andcirc_successive_difference()(animovement/anicore#147). Both are general-purpose circular primitives rather than spatial transforms — the shortest signed distance between two angles, and that distance applied along a vector — andcalculate_angular_difference()was already a one-line wrapper overanicore::wrap_angle(). anicore owns the angle utilities, and keeping the circular family together means it can be split out on its own later without unpicking anispace.The new names follow anicore’s convention:
circ_*()computes with the wraparound,*_angle()manipulates how an angle is written. Callanicore::circ_difference()andanicore::circ_successive_difference()instead; both are attached bylibrary(animovement), so a script using the metapackage needs no change.
anispace 0.3.0 (2026-08-28)
Changed
The transforms read the frame’s declaration instead of naming its columns (#20).
translate_coords(),rotate_coords()andtransform_to_egocentric()tookindividual,keypoint,time,x,yandzliterally, so a frame declaring anything else failed outright. They now resolve identity throughvariables_what, the index throughget_index()and the coordinates throughget_axes().The reference point is a member of any identity level, not a keypoint (#20).
to_keypointbecomesto,alignment_pointsbecomesalign, and a newlevelsays which identity variable they name members of — so a group centre can be taken onindividualas readily as onkeypoint.leveldefaults to the frame’s only identity variable; a frame declaring several has to be told, sincevariables_whatorder is not something to rely on (animovement/anicore#140, animovement/anicore#141).translate_coords()takesby, a named offset per axis role, in place ofto_x/to_y/to_z.rotate_coords()takesabout, the centre of rotation — a member to turn around, or a fixed point. It defaults to the coordinate origin, which is what the previous behaviour was, unstated.transform_to_egocentric()’salignis optional. Omitted, the frame is re-centred without being reoriented.A quarter turn follows the frame’s declared sense of rotation (#29, in part).
align_perpendicularturned one way regardless; on a frame whose axes say its angles run clockwise it now turns the other. Themap_to_*()half of that issue is still open.wrap_angle()andunwrap_angle()move toanicore, which already helddeg_to_rad()andrad_to_deg()(animovement/aniframe#128). They are angle arithmetic rather than coordinate transformation. Useanicore::wrap_angle().The minimum
anicoreis 0.8.0, which is the first version published under that name — the dependency was renamed without a version constraint, so nothing recorded that a pre-renameaniframewill not do.The core data structures come from
anicore, which is what theaniframepackage was renamed to in its 0.8.0 (animovement/anicore#84). Theaniframeclass keeps its name; only the package providing it changed.
Fixed
-
map_to_polar(),map_to_cylindrical()andmap_to_spherical()declare the system they mapped to (#27). They returned frames whose metadata still described the system they came from —variables_wherenamingxandyon a frame that no longer had them, andcoordinate_systemstillcartesian_2d, whichvalidate_aniframe()rejects outright.It went unnoticed because
ensure_is_polar()matched column names, sorhoandphibeing present satisfied it whatever the metadata said. Those predicates now readcoordinate_systemand fail correctly. The trailingas_aniframe()would have re-derived the declaration, but it runs after the check, so the check had never validated the object being returned. Rotating a frame with more than one temporal group no longer multiplies its rows (#20).
rotate_coords()joined the rotation angles by the index alone, so every trial’s angle matched every trial’s rows: two trials turned 12 rows into 48, of which 36 were duplicates. It returned plausible-looking data rather than an error. The standing# TODO: Will likely break with multiple trialsis resolved.Rotating three-dimensional coordinates works (#4). It aborted with “not yet supported”. Two alignment points give the minimal rotation onto the target axis, leaving the roll about it as it was; a third fixes the orientation outright. Two dimensions are the same code with the rotation axis fixed to
z.translate_coords_keypoint()looped with1:length(), which runs twice on empty input (#15). The loops are gone entirely, replaced by grouped operations.-
map_to_spherical()returns the radial distance from the origin asrho, rather than the cylindrical radius (#19).thetaalready used the full radius, so the triple was inconsistent with the name; ISO 80000-2 uses the radial distance. This was lossy as well as non-standard — a point on the z-axis has a cylindrical radius of zero, so(0, 0, 5)round-tripped throughmap_to_cartesian()to the origin, and now returns(0, 0, 5).spherical_to_z(rho, theta)is nowrho * cos(theta)where it wasrho / tan(theta). Code readingrhofrom a spherical frame, or callingspherical_to_z()directly, needs updating.map_to_cylindrical()is unchanged:rhothere is the distance from the z-axis, which is correct for a cylindrical frame.
anispace 0.2.0 (2026-08-18)
First tagged release. anispace had been usable for a while but was never tagged, so this marks the current state rather than a change in it.
Added
- Coordinate-system conversion:
map_to_cartesian(),map_to_polar(),map_to_cylindrical()andmap_to_spherical(), with the element-wise helpers behind them —cartesian_to_rho(),cartesian_to_phi(),cartesian_to_theta(),polar_to_x(),polar_to_y()andspherical_to_z(). - Angular arithmetic:
wrap_angle(),unwrap_angle(),diff_angle()andcirc_difference(). - Rigid transformations:
rotate_coords(),translate_coords()andtransform_to_egocentric().