Changes in version 0.4.0 New features - aabb_polygon2d() creates an axis-aligned bounding box Polygon2D object covering the range of its input (#81). - cross_product2d() computes the 2D cross product (perp dot product) of two Coord2D vectors, returning a scalar. If R >= 4.4.0, crossprod() is also overloaded for Coord2D objects. - range() now has methods for Ellipse2D, Line2D, Plane3D, Point1D, and Segment2D objects (#82). Bug fixes and minor improvements - c() methods added for Ellipse2D and Segment2D objects. Changes in version 0.3.1 (2026-05-10) New features - as_ellipse2d() creates an Ellipse2D R6 object representing a 2D ellipse (or vector of ellipses) (#46). - as_polygon2d() creates a Polygon2D R6 object representing a 2D polygon (#46). - isotoxal_2ngon_polygon2d() creates an isotoxal 2n-gon [Polygon2D] object; star_polygon2d() is an alias (#78). - rectangle_polygon2d() creates a rectangle [Polygon2D] object (#78). - regular_ngon_polygon2d() creates a regular n-gon [Polygon2D] object (#78). - as_segment2d() creates a Segment2D R6 object representing a vector of 2D line segments (#75). - dot_product1d(), dot_product2d(), and dot_product3d() are new exported functions that compute the dot (inner) product of two coordinate vectors (#61). You may also (continue to) use the * and (if R >= 4.3) the %*% operators to compute the dot (inner) product. - has_overlap2d() tests whether two 2D objects (ellipses/circles or convex polygons) have a non-zero-area overlap (#46). - as_coord2d.Coord3D() now supports oblique projections onto arbitrary planes (not just the xy-plane) and gains a roll parameter to rotate the in-plane coordinate frame around the plane normal after the azimuth/inclination alignment. - intersection() now supports Line2D and Ellipse2D pairs, returning 0, 1, or 2 intersection points. - is_ellipse2d() tests whether an object is a Ellipse2D R6 class. - is_segment2d() tests whether an object is a Segment2D R6 class. - is_polygon2d() tests whether an object is a Polygon2D R6 class. - painter_depth() computes painter's algorithm depth values for Coord2D, Coord3D, Polygon2D, and Segment2D objects under parallel (orthographic or oblique) projections. - painter_order() wraps painter_depth() and order() to return the integer indices for painter's algorithm draw order (farthest first) for Coord2D, Coord3D, Segment2D, and Polygon2D objects. - sort.Coord2D() and sort.Coord3D() sort coordinate/segment vectors by painter's depth (farthest first by default), for use with the painter's algorithm. Bug fixes and minor improvements - permute3d() now correctly returns a transform3d object instead of a transform2d object. - rotate3d() now correctly returns a transform3d object instead of a plain matrix. - shear3d() now correctly returns a transform3d object instead of a transform2d object. - rgl::plot3d() method added for Plane3D objects (wraps rgl::planes3d()). Changes in version 0.2.1 (2026-01-28) - has_intersection() is a generic S3 method which tests whether two objects have an intersection. - intersection() is a generic S3 method which computes the intersection of two objects. - is_equivalent() is a generic S3 method which tests whether two objects are "equivalent". The is_equivalent() method for angle vectors tests whether two angles are congruent. The is_equivalent() method for Point1D, Line2D, Plane3D classes tests whether they are the same point/line/plane after standardization. - is_parallel() is a generic S3 method which tests whether two objects are "parallel" (e.g. Line2D and Plane3D objects). - isotoxal_2ngon_inner_radius() computes the inner radius of an isotoxal 2n-gon polygon (#66). star_inner_radius() is an alias. - If R >= 4.4.0 can now also use crossprod() (in addition to cross_product3d()) to compute the vector cross product of two Coord3D objects. - Can now use ceiling(), floor(), round(), signif(), and trunc() on Coord1D, Coord2D, and Coord3D objects (#63). Changes in version 0.1.3 (2024-12-02) - isocubeGrob() and grid.isocube() now make sure that the fill of gp_border is always "transparent" (#58). Changes in version 0.1.1 (2024-10-14) Initial features - affineGrob() and grid.affine() provide wrappers around grid::defineGrob() and grid::useGrob() - isocubeGrob() and grid.isocube() provides a convenience wrapper for the isometric cube case. - affine_settings() computes grid affine transformation feature viewports and transformation functions - Available as a "standalone" file that can be copied over into other R packages under the permissive Unlicense. - angle() creates angle vector S3 classes that allow users to use whichever angular unit is most convenient for them: - Supports "degrees", "radians", "half-turns" (aka "pi-radians"), (full) "turns", and "gradians" units. - is_angle() tests whether the input is an angle vector. - as_angle() casts objects to angle vectors. - degrees(), gradians(), pi_radians(), radians(), and turns() are convenience wrappers around as_angle() for those commonly used angular units. - is_congruent() is a generic S3 method which tests whether two R objects are "congruent". The is_congruent() method for angle vectors tests whether two angles are congruent. - angular_unit() can be used to get/set the angular unit of angle vectors. - The default angular unit can be adjusted locally/globally by setting the "affiner_angular_unit" option. e.g. options(affiner_angular_unit = "turns"). - sine(), cosine(), tangent(), secant(), cosecant(), cotangent(), arcsine(), arccosine(), arctangent(), arcsecant(), arccosecant(), and arccotangent() are angle vector aware trigonometric functions. - We implement methods for several base generics (plus as a numeric vector it inherits support for several more). Some notes: - If both objects in a mathematical operation (in particular + and -) or a c() combining operation are angle vectors then we coerce the second one to use the same angular unit as the first one. - as.numeric() takes a unit argument which can be used to convert angles into other angular units e.g. angle(x, "degrees") |> as.numeric("radians") to cast a numeric vector x from degrees to radians. - abs() will calculate the angle modulo full turns. - Coord1D, Coord2D, and Coord3D are (Cartesian) coordinate R6 classes - is_coord1d(), is_coord2d(), and is_coord3d() test whether objects are Coord1D, Coord2D, or Coord3D R6 classes - as_coord1d(), as_coord2d(), and as_coord3d() cast objects to Coord1D, Coord2D, or Coord3D R6 classes - Several mathematical operations are supported for Coord1D, Coord2D, or Coord3D R6 classes - * either applies a "dot" product (if multiplying another Coord1D, Coord2D, or Coord3D object) or a "scaling" transformation (if multiplying a numeric value) - / applies a "scaling" transformation - Unary - applies a "scaling" transformation whereas binary - and + apply a "translation" transformation - Additional S3 methods: - abs() computes Euclidean norm - convex_hull2d() computes convex hull (currently just for Coord2D vectors) - cross_product3d() computes a cross product between Coord3D vectors - distance1d(), distance2d(), and distance3d() computes Euclidean distances - mean() computes centroids of coordinates - normal2d() computes Coord2D normals - normal3d() computes Coord3D normals - plot() and points() plots Coord1D and Coord2D coordinates using base graphics. If the suggested {ggplot2} package is installed one may also use autolayer() to plot Coord1D and Coord2D points. If the suggested {rgl} package is installed one may also use plot3d() to plot Coord3D points (or straightforwardly use the primitive points3d()). - range() computes axis-aligned ranges - Point1D, Line2D, and Plane3D R6 classes - as_point1d() casts objects to Point1D R6 classes - as_line2d() casts objects to Line2D R6 classes - as_plane3d() casts objects to Plane3D R6 classes - is_point1d() tests whether objects are Point1D R6 classes - is_line2d() tests whether objects are Line2D R6 classes - is_plane3d() tests whether objects are Plane3D R6 classes - transform1d(), transform2d(), and transform3d() create 1D/2D/3D affine transformation matrix S3 classes - is_transform1d(),is_transform2d(), and is_transform3d() test iftransform1d(), transform2d(), or transform3d() objects. - as_transform1d(), as_transform2d(), and as_transform3d() cast objects to transform1d(), transform2d(), or transform3d() objects. - permute2d() and permute3d() transformation matrices permutes coordinate axes. - project1d(), project2d(), and project3d() create projection matrices. - reflect1d(), reflect2d() and reflect3d() create reflection affine transformation matrices. - rotate2d() and rotate3d() create rotation affine transformation matrices. rotate3d_to_AA() converts from 3D rotation matrix to axis-angle representation. - scale1d(), scale2d(), and scale3d() create scaling affine transformation matrices. - shear2d() and shear3d() create shearing affine transformation matrices. - translate1d(), translate2d(), and translate3d() create translation affine transformation matrices. - {affiner} supports the following options settable by base::options(): - affiner_angular_unit: The default for the unit argument used by angle() and as_angle(). The default for this option is "degrees". - affiner_grid_unit: The default for the unit argument used by affine_settings(). The default for this option is inches. - These options can be queried with the convenience function affiner_options().