Angle objects
In affiner angles are represented by the angle() class:
-
Supports the following angular units (note we ignore any punctuation and space characters as well as any trailing s’s e.g. “half turns” will be treated as equivalent to “halfturn”):
- “deg” or “degree”
- “half-revolution”, “half-turn”, or “pi-radian”
- “gon”, “grad”, “grade”, or “gradian”
- “rad” or “radian”
- “rev”, “revolution”, “tr”, or “turn”
degrees(),gradians(),pi_radians(),radians(),turns()are convenience wrappers aroundas_angle.()that specifies the angular unit.One can use the
affiner_angular_unitglobal option to set the default angular unit used by this package from “degrees” to “gradians”, (multiples of) “pi-radians”, “radians”, or “turns”.Use
is_congruent()to check if two angles are congruent modulo full turns.
## <angle<degrees>[1]>
## [1] 450°
is_congruent(degrees(180), radians(pi))## [1] TRUE
as.numeric(turns(1/3), "radians")## [1] 2.094395
Trigonometry
affiner provides several angle() class aware trigonometric functions:
-
sine(),cosine(),tangent(),secant(),cosecant(),cotangent(), -
arcsine(),arccosine(),arctangent(),arcsecant(),arccosecant(), andarccotangent().arcsine()andarccosine()also feature atolerancevalue so that values that exceed the1/-1cutoffs by a small tolerance are rounded to those values. - One can also use the base S3 methods
sin(),cos(), andtan()onangle()objects.
## [1] -2.449294e-16
## [1] 0
arctangent(x = 0, y = 1)## <angle<degrees>[1]>
## [1] 90°
2D Coordinates
In affiner 2D Coordinates are represented by a Coord2D R6 class:
Create
Coord2Dobjects withas_coord2d()-
Coord2DR6 objects supports several affine transformation methods that can be chained:permute()project()reflect()rotate()scale()shear()translate()transform()- R6 method chained affine transformation matrices are auto-multiplied so you don’t need to manually multiply them for efficiency reasons.
- affiner affine transformations are post-multiplied so affine transformations can be applied in an intuitive order.
-
abs()computes Euclidean norm anddistance2d()computes Euclidean distances -
convex_hull2d()computes the convex hull. -
range()computes the axis-aligned bounding box ranges.
# Cartesian coordinates
library("affiner")
p <- as_coord2d(x = 1:10, y = 1:10)
print(p)## <Coord2D[10]>
## x y w
## [1,] 1 1 1
## [2,] 2 2 1
## [3,] 3 3 1
## [4,] 4 4 1
## [5,] 5 5 1
## [6,] 6 6 1
## [7,] 7 7 1
## [8,] 8 8 1
## [9,] 9 9 1
## [10,] 10 10 1
p2 <- p$
clone()$
scale(x = 0.5)$
rotate(degrees(90))$
reflect(as_line2d("y-axis"))$
translate(as_coord2d(x = 0.5, y = 0.5))$
print()## <Coord2D[10]>
## x y w
## [1,] 1.0 1.0 1
## [2,] 1.5 1.5 1
## [3,] 2.0 2.0 1
## [4,] 2.5 2.5 1
## [5,] 3.0 3.0 1
## [6,] 3.5 3.5 1
## [7,] 4.0 4.0 1
## [8,] 4.5 4.5 1
## [9,] 5.0 5.0 1
## [10,] 5.5 5.5 1
# Polar coordinates
theta <- degrees(seq(0, 300, by = 60))
radius <- 1
p <- as_coord2d(theta, radius = radius)
is_congruent(as_angle(p), theta) |> all()## [1] TRUE
is_congruent(abs(p), radius) |> all()## [1] TRUE
3D Coordinates
In affiner 3D Coordinates are represented by a Coord3D R6 class:
Create
Coord3Dobjects withas_coord3d()-
Coord3DR6 objects supports several affine transformation methods that can be chained:permute()project()reflect()rotate()scale()shear()translate()transform()- R6 method chained affine transformation matrices are auto-multiplied so you don’t need to manually pre-multiply them for efficiency reasons.
- affiner affine transformations are post-multiplied so affine transformations can be applied in an intuitive order.
-
abs()computes Euclidean norm anddistance3d()computes Euclidean distances -
range()computes the axis-aligned bounding box ranges. -
cross_product3d()computes cross products (*computes inner products).
# Cartesian coordinates
library("affiner")
p <- as_coord3d(x = 1:10, y = 1:10, z = 1:10)
print(p)## <Coord3D[10]>
## x y z w
## [1,] 1 1 1 1
## [2,] 2 2 2 1
## [3,] 3 3 3 1
## [4,] 4 4 4 1
## [5,] 5 5 5 1
## [6,] 6 6 6 1
## [7,] 7 7 7 1
## [8,] 8 8 8 1
## [9,] 9 9 9 1
## [10,] 10 10 10 1
p2 <- p$
clone()$
scale(z = 0.5)$
rotate(axis = as_coord3d("z-axis"), theta = degrees(90))$
reflect(as_plane3d("yz-plane"))$
shear(xy_shear = 0.5)$
translate(as_coord3d(x = 0.5, y = 0.5, z = 0.5))$
print()## <Coord3D[10]>
## x y z w
## [1,] 2.0 1.5 1.0 1
## [2,] 3.5 2.5 1.5 1
## [3,] 5.0 3.5 2.0 1
## [4,] 6.5 4.5 2.5 1
## [5,] 8.0 5.5 3.0 1
## [6,] 9.5 6.5 3.5 1
## [7,] 11.0 7.5 4.0 1
## [8,] 12.5 8.5 4.5 1
## [9,] 14.0 9.5 5.0 1
## [10,] 15.5 10.5 5.5 1
# Spherical coordinates
inclination <- as_angle(p, type = "inclination")
azimuth <- as_angle(p, type = "azimuth")
radius <- abs(p)
ps <- as_coord3d(azimuth, radius = radius, inclination = inclination)
all.equal(p, ps)## [1] TRUE
# Cylindrical coordinates
radius <- as_coord2d(p, plane = "xy-plane") |> abs()
pc <- as_coord3d(azimuth, radius = radius, z = p$z)
all.equal(p, pc)## [1] TRUE
Orthographic/Axonometric and Oblique Projections
affiner can project Coord3D objects to Coord2D objects using orthographic/axonometric and oblique projections:
For a multiview/primary orthographic projection onto the xy-plane use
as_coord2d(x)For a multiview/primary orthographic projection onto the xz-plane use
as_coord2d(x, permutation = "xzy")For a “cabinet” oblique projection onto the xy-plane use
as_coord2d(x, scale = 0.5)For a “cabinet” oblique projection onto the xz-plane use
as_coord2d(x, permutation = "xzy", scale = 0.5)For other oblique projections manipulate the
scaleparameter (usually from 0.5 to 1.0) and thealphaangle parameter (usually from 30° to 45°).-
For one “isometric” axonometric projection one can use
x$ clone()$ translate(-mean(x)$ rotate("z-axis", degrees(45))$ rotate("x-axis", degrees(-90 + 35.264)) |> as_coord2d() Other axonometric projections can be achieved with the right 3D rotations
See
vignette("affiner", package = "affiner")for some visual examplesRecall one can use “scale” affine transformation to flip signs of x/y/z axes and “permute” affine transformation to switch order of x/y/z coordinates
