Static build of Academy Software Foundation’s Imath
C++ library for R. Imath
is a basic, light-weight, and
efficient C++ representation of 2D and 3D vectors, matrices, and other
mathematical objects, functions, and data types common in computer
graphics applications, including the half
16-bit
floating-point type. It is not a generic linear algebra library (such as
Eigen), but rather one specialized for 2D and 3D transformations common
in computer graphics.
The installed package includes a static copy of the
C++ library (along with CMake config files) so you can use Imath
functionality in your package without requiring the user to separately
install Imath
as a system dependency. This package does not
provide an R API–rather, it simply makes the Imath
C++
library available to other R packages.
Imath
is maintained by the OpenEXR project, a part of
the Academy Software Foundation (ASWF).
The Imath
library provides:
For detailed information on the Imath
API, please refer
to the Imath
documentation.
# once released on CRAN
install.packages("tylermorganwall/libimath")
# development version
::install_github("tylermorganwall/libimath") remotes
No external libraries are required—the Imath
static
library is built and installed during the R package install.
The package installs:
lib/<R_ARCH>/libImath-3_2.a # static archive (version 3.2)
lib/<R_ARCH>/cmake/Imath/* # CMake config files
include/Imath/* # public headers
R_ARCH
can be obtained in R via
Sys.info()[["machine"]]
.
The version (3_2) is appended after the library name: add this to link the static library.
## configure
IMATH_DIR=$(Rscript -e 'cat(system.file("lib", Sys.info()[["machine"]], package = "libimath"))')
CPPFLAGS += -I$(IMATH_DIR)/../include
PKG_LIBS += -L$(IMATH_DIR) -lImath-3_2
Call this R code in your configure step to determine the location of the CMake config files:
= normalizePath(sprintf(
IMATH_LIB_ARCH "%s/%s",
system.file(
"lib",
package = "libimath",
mustWork = TRUE
),Sys.info()[["machine"]]
))
= file.path(IMATH_LIB_ARCH, "cmake", "Imath") IMATH_CMAKE_CONFIG
Below is a minimal example showing how to use this library with R.
#define R_NO_REMAP
#include <R.h>
#include <Rinternals.h>
#include <R_ext/Rdynload.h>
#include <R_ext/Print.h>
#include <Imath/ImathMatrix.h>
#include <Imath/ImathVec.h>
/**
* Rotates a 3D point using Imath's matrix operations
*
* @param point An R numeric vector with 3 elements (x, y, z)
* @param angles An R numeric vector with 3 elements (rotation angles in radians)
* @return The rotated point as an R numeric vector
*/
extern "C" SEXP imath_rotate_point(SEXP point, SEXP angles) {
// Validate inputs
if (TYPEOF(point) != REALSXP || LENGTH(point) != 3) {
("'point' must be a numeric vector of length 3");
Rf_error}
if (TYPEOF(angles) != REALSXP || LENGTH(angles) != 3) {
("'angles' must be a numeric vector of length 3");
Rf_error}
// Extract point coordinates
double *point_ptr = REAL(point);
::V3f p((float)point_ptr[0], (float)point_ptr[1], (float)point_ptr[2]);
Imath
// Extract rotation angles
double *angles_ptr = REAL(angles);
::V3f rot((float)angles_ptr[0], (float)angles_ptr[1], (float)angles_ptr[2]);
Imath
// Create identity matrix
::M44f M;
Imath.makeIdentity();
M
// Create rotation matrix
::M44f R;
Imath.makeIdentity();
R.rotate(rot);
R
// Apply rotation
= R * M;
M
// Transform the point
::V3f result;
Imath.multVecMatrix(p, result);
M
// Create and populate result vector
= PROTECT(Rf_allocVector(REALSXP, 3));
SEXP r_result (r_result)[0] = (double)result.x;
REAL(r_result)[1] = (double)result.y;
REAL(r_result)[2] = (double)result.z;
REAL
// Add names to result vector for R
= PROTECT(Rf_allocVector(STRSXP, 3));
SEXP names (names, 0, Rf_mkChar("x"));
SET_STRING_ELT(names, 1, Rf_mkChar("y"));
SET_STRING_ELT(names, 2, Rf_mkChar("z"));
SET_STRING_ELT(r_result, R_NamesSymbol, names);
Rf_setAttrib
(2);
UNPROTECTreturn r_result;
}
//=== registration ===========================================================
static const R_CallMethodDef CallEntries[] = {
{"imath_rotate_point", (DL_FUNC) &imath_rotate_point, 2},
{NULL, NULL, 0}
};
void R_init_libimathwrapper(DllInfo *dll) {
(dll, NULL, CallEntries, NULL, NULL);
R_registerRoutines(dll, FALSE);
R_useDynamicSymbols}
And the R code calling this function:
#' Rotate Point
#'
#' @param point A length-3 numeric vector (x, y, z)
#' @param angles A length-3 numeric vector (rotation angles in radians)
#' @return The rotated point as an R numeric vector
#' @export
#' @examples
#' # This rotates a point around an angle.
#' point = c(1.0, 0.0, 0.0)
#' angles = c(0.0, pi/4, 0.0)
#' imath_rotate_point(point, angles)
= function(point, angles) {
imath_rotate_point = .Call(
rotated "imath_rotate_point",
point,
angles,PACKAGE = "libimath"
)return(rotated)
}