| Title: | Estimate 3D Orientations from 2D Landmarks |
|---|---|
| Description: | Estimates possible 3D orientations of directed objects from the 2D image coordinates of two landmarks and any additional information about the imaging geometry or object. Because a 2D image generally does not uniquely determine a 3D orientation, the package returns sets of compatible pitch, yaw, and view-elevation angles rather than a single unconstrained estimate. |
| Authors: | João C T Menezes [aut, cre, cph] (ORCID: <https://orcid.org/0000-0003-4156-2934>) |
| Maintainer: | João C T Menezes <[email protected]> |
| License: | GPL (>= 3) |
| Version: | 2.0.0.9000 |
| Built: | 2026-10-27 14:50:56 UTC |
| Source: | https://github.com/jocateme/araponga |
Quick visual reminders of the angle conventions used by araponga.
conventions(type = c("pitch", "yaw", "view_elevation"))conventions(type = c("pitch", "yaw", "view_elevation"))
type |
Character vector specifying which convention plot(s) to draw.
Choices are |
No return value.
conventions() conventions("yaw")conventions() conventions("yaw")
deg2rad() takes angles in degrees and returns them converted in radians.
rad2deg() takes angles in radians and returns them converted in degrees.
deg2rad(deg) rad2deg(rad)deg2rad(deg) rad2deg(rad)
deg |
Numeric vector of angles in degrees. |
rad |
Numeric vector of angles in radians. |
A numeric vector of angles, in radians or degrees. Length matches deg or rad.
deg2rad(c(0, 90, 180)) rad2deg(c(0, pi/2, pi))deg2rad(c(0, 90, 180)) rad2deg(c(0, pi/2, pi))
Evaluate combinations of candidate 3D pitch, yaw, and view elevation and return those whose predicted
2D projection is compatible with supplied observations. find.pitch() and find.yaw() are convenience
wrappers for finding compatible 3D pitch and yaw orientations, respectively.
find.3d( observed2d = NULL, find = "all", label_error = NULL, full_length = NULL, pitch2d = NULL, length2d = NULL, candidate_pitches = seq(-90, 90, default_step), candidate_yaws = seq(-180 + default_step, 180, default_step), candidate_view_elevations = seq(-90, 90, default_step), default_step = 1, max_combinations = 1e+08 ) find.yaw( observed2d = NULL, label_error = NULL, full_length = NULL, pitch2d = NULL, length2d = NULL, candidate_pitches = seq(-90, 90, default_step), candidate_yaws = seq(-180 + default_step, 180, default_step), candidate_view_elevations = seq(-90, 90, default_step), paired = FALSE, default_step = 1, max_combinations = 1e+08 ) find.pitch( observed2d = NULL, label_error = NULL, full_length = NULL, pitch2d = NULL, length2d = NULL, candidate_pitches = seq(-90, 90, default_step), candidate_yaws = seq(-180 + default_step, 180, default_step), candidate_view_elevations = seq(-90, 90, default_step), paired = FALSE, default_step = 1, max_combinations = 1e+08 )find.3d( observed2d = NULL, find = "all", label_error = NULL, full_length = NULL, pitch2d = NULL, length2d = NULL, candidate_pitches = seq(-90, 90, default_step), candidate_yaws = seq(-180 + default_step, 180, default_step), candidate_view_elevations = seq(-90, 90, default_step), default_step = 1, max_combinations = 1e+08 ) find.yaw( observed2d = NULL, label_error = NULL, full_length = NULL, pitch2d = NULL, length2d = NULL, candidate_pitches = seq(-90, 90, default_step), candidate_yaws = seq(-180 + default_step, 180, default_step), candidate_view_elevations = seq(-90, 90, default_step), paired = FALSE, default_step = 1, max_combinations = 1e+08 ) find.pitch( observed2d = NULL, label_error = NULL, full_length = NULL, pitch2d = NULL, length2d = NULL, candidate_pitches = seq(-90, 90, default_step), candidate_yaws = seq(-180 + default_step, 180, default_step), candidate_view_elevations = seq(-90, 90, default_step), paired = FALSE, default_step = 1, max_combinations = 1e+08 )
observed2d |
Optional one-row |
find |
Character vector specifying which 3D angle(s) to return. One or more of "pitch", "yaw", and "view_elevation", or "all" to return all three. Default is "all". |
label_error |
Non-negative numeric scalar specifying the maximum labeling error in each landmark
coordinate, in the same units as the coordinates in |
full_length |
Optional positive numeric vector giving the possible unprojected (no foreshortening)
length of the directed vector, in the same units as |
pitch2d |
Optional numeric vector of projected 2D pitch angles, in degrees in the interval (-180,
180]. The smallest continuous angular interval containing the supplied values is treated as the allowed
|
length2d |
Optional non-negative numeric vector of projected 2D lengths. Its minimum and maximum
define a continuous allowed range. Requires |
candidate_pitches |
Numeric vector of candidate 3D pitch angles, in degrees in the interval
(-180, 180]. Convention: |
candidate_yaws |
Numeric vector of candidate yaw angles, in degrees in the
interval (-180, 180]. Convention: |
candidate_view_elevations |
Numeric vector of candidate camera elevation angles relative to the
object, in degrees in the interval [-90, 90]. Convention: |
default_step |
Positive numeric scalar specifying the step size, in degrees, used to generate
default candidate-angle vectors. Must evenly divide 180 to ensure full coverage of default candidate
ranges. Default is |
max_combinations |
Positive numeric scalar specifying the maximum total number of candidate
pitch-yaw-view elevation combinations to evaluate, in order to prevent excessive memory use and
computation. Default is |
paired |
Logical scalar used by |
For each unique combination of candidate pitch, yaw, and view elevation, find.3d() and wrappers use
project2d.from.3d() to predict the corresponding 2D projection. Candidate orientations are retained
when that projection is compatible with all supplied observational constraints.
The function supports two main ways of specifying the observed 2D projection.
The preferred route is to supply observed2d together with label_error. If full_length is not known,
the landmarks constrain projected pitch only. If full_length is also supplied, both projected
pitch and length are used jointly, preserving the relationship between them under landmark labeling
uncertainty.
Alternatively, projected measurements may be supplied directly through pitch2d and/or length2d. This
is useful when landmark coordinates are unavailable or when the user already has suitable 2D constraints.
length2d requires full_length. When both pitch2d and length2d are supplied directly, they are
treated as independent constraints.
Candidate angles supplied explicitly are evaluated exactly and are not rounded. For candidate
vectors left at their defaults, default_step determines the resolution of the search.
The default pitch range is [-90, 90], which provides a conventional down-to-up representation. Explicit candidate pitches may extend over (-180, 180]. Such extended pitch values should be used intentionally because they necessarily have equivalent representations involving a different yaw (e.g., a pitch of 135° at a yaw of 10° is equivalent to a pitch of 45° at the opposite yaw of -170°).
A data.frame containing the requested subset of:
numeric: 3D pitch angles, in degrees.
numeric: yaw angles, in degrees.
numeric: view elevation angles, in degrees.
Each row represents a candidate 3D orientation compatible with all supplied observational constraints.
If no combinations are compatible, the returned data.frame has zero rows.
For find.pitch(..., paired = FALSE) and find.yaw(..., paired = FALSE), a numeric vector of unique
compatible pitch or yaw angles is returned.
project2d.from.3d(), project2d.from.xy(), pitch2d.w.error()
# construct a hypothetical observation from a known 3D orientation predicted <- project2d.from.3d( pitch = 30, yaw = 20, view_elevation = 10, full_length = 100 ) observed <- project2d.from.xy( x_tip = predicted$dx, y_tip = predicted$dy, x_base = 0, y_base = 0 ) # landmark route: constrain projected direction only find.3d( observed2d = observed, label_error = 1, candidate_pitches = 25:35, candidate_yaws = 15:25, candidate_view_elevations = 5:15 ) # landmark route with full-length information: constrain projected direction and length jointly find.3d( observed2d = observed, label_error = 1, full_length = c(98, 102), candidate_pitches = 25:35, candidate_yaws = 15:25, candidate_view_elevations = 5:15 ) # direct constraints find.3d( pitch2d = predicted$pitch2d + c(-1, 1), length2d = predicted$length2d + c(-2, 2), full_length = c(98, 102), candidate_pitches = 25:35, candidate_yaws = 15:25, candidate_view_elevations = 5:15 ) # convenience wrappers find.pitch( observed2d = observed, label_error = 1, candidate_yaws = 15:25, candidate_view_elevations = 5:15 ) find.yaw( observed2d = observed, label_error = 1, candidate_pitches = 25:35, candidate_view_elevations = 5:15 )# construct a hypothetical observation from a known 3D orientation predicted <- project2d.from.3d( pitch = 30, yaw = 20, view_elevation = 10, full_length = 100 ) observed <- project2d.from.xy( x_tip = predicted$dx, y_tip = predicted$dy, x_base = 0, y_base = 0 ) # landmark route: constrain projected direction only find.3d( observed2d = observed, label_error = 1, candidate_pitches = 25:35, candidate_yaws = 15:25, candidate_view_elevations = 5:15 ) # landmark route with full-length information: constrain projected direction and length jointly find.3d( observed2d = observed, label_error = 1, full_length = c(98, 102), candidate_pitches = 25:35, candidate_yaws = 15:25, candidate_view_elevations = 5:15 ) # direct constraints find.3d( pitch2d = predicted$pitch2d + c(-1, 1), length2d = predicted$length2d + c(-2, 2), full_length = c(98, 102), candidate_pitches = 25:35, candidate_yaws = 15:25, candidate_view_elevations = 5:15 ) # convenience wrappers find.pitch( observed2d = observed, label_error = 1, candidate_yaws = 15:25, candidate_view_elevations = 5:15 ) find.yaw( observed2d = observed, label_error = 1, candidate_pitches = 25:35, candidate_view_elevations = 5:15 )
Estimates the unforeshortened length of an object in image pixels from its physical length, distance from the camera, and camera parameters.
full_length.from.camera( length_physical, distance, image_width, focal_length = NULL, sensor_width = NULL, field_of_view = NULL )full_length.from.camera( length_physical, distance, image_width, focal_length = NULL, sensor_width = NULL, field_of_view = NULL )
length_physical |
Positive numeric vector specifying the physical length of the object. When
|
distance |
Positive numeric vector specifying the distance from the camera to the object, in the
same units as |
image_width |
Positive numeric vector specifying the image width, in pixels, corresponding to the
supplied camera parameters and image scale. When |
focal_length |
Positive numeric vector specifying camera focal length. Must be in the same units
as |
sensor_width |
Positive numeric vector specifying sensor width. Must be
in the same units as |
field_of_view |
Positive numeric vector specifying horizontal field of view, in degrees in
the interval (0, 180). When |
Camera geometry can be specified either by focal_length and sensor_width, or by
field_of_view. These alternatives are mutually exclusive.
Input vectors represent ranges of possible values rather than paired observations. The returned
interval contains the minimum and maximum full_length values compatible with all supplied
ranges, allowing inputs to vary independently within those ranges.
The calculation assumes scaled orthographic projection: image scale is determined at the supplied camera-to-object distance and treated as constant across the object.
Numeric vector of length 2 giving the minimum and maximum compatible full_length
values, in pixels.
# focal length and sensor width full_length.from.camera(length_physical = 10, distance = 1000, image_width = 2000, focal_length = 50, sensor_width = 20) # equivalent camera geometry specified by field of view full_length.from.camera(length_physical = 10, distance = 1000, image_width = 2000, field_of_view = rad2deg(2 * atan(20 / (2 * 50)))) # propagate uncertainty in physical length and distance full_length.from.camera(length_physical = c(9, 11), distance = c(900, 1100), image_width = 2000, focal_length = 50, sensor_width = 20)# focal length and sensor width full_length.from.camera(length_physical = 10, distance = 1000, image_width = 2000, focal_length = 50, sensor_width = 20) # equivalent camera geometry specified by field of view full_length.from.camera(length_physical = 10, distance = 1000, image_width = 2000, field_of_view = rad2deg(2 * atan(20 / (2 * 50)))) # propagate uncertainty in physical length and distance full_length.from.camera(length_physical = c(9, 11), distance = c(900, 1100), image_width = 2000, focal_length = 50, sensor_width = 20)
Estimates the unforeshortened length of a target object in image pixels from a reference segment of known physical length.
full_length.from.reference(length_physical, reference_physical, reference_px)full_length.from.reference(length_physical, reference_physical, reference_px)
length_physical |
Positive numeric vector specifying the physical length of the target object.
When |
reference_physical |
Positive numeric vector specifying the physical length of the reference segment,
in the same units as |
reference_px |
Positive numeric vector specifying the length of the reference segment in image
pixels. When |
Input vectors represent ranges of possible values rather than paired observations. The returned
interval contains the minimum and maximum full_length values compatible with all supplied
ranges, allowing inputs to vary independently within those ranges.
The reference segment should be approximately perpendicular to the camera's viewing axis and at
approximately the same distance from the camera as the target object. Foreshortening of the
reference segment or differences in camera distance can bias the estimated full_length.
Numeric vector of length 2 giving the minimum and maximum compatible full_length
values, in pixels.
full_length.from.reference(length_physical = 10, reference_physical = 20, reference_px = 100) # propagate uncertainty in target and reference measurements full_length.from.reference(length_physical = c(9, 11), reference_physical = c(18, 22), reference_px = c(90, 110))full_length.from.reference(length_physical = 10, reference_physical = 20, reference_px = 100) # propagate uncertainty in target and reference measurements full_length.from.reference(length_physical = c(9, 11), reference_physical = c(18, 22), reference_px = c(90, 110))
Calculate the range of projected 2D pitch angles compatible with uncertainty in the locations of two landmarks.
pitch2d.w.error(observed2d, label_error)pitch2d.w.error(observed2d, label_error)
observed2d |
One-row |
label_error |
Non-negative numeric scalar specifying the maximum labeling error in each landmark
coordinate, in the same units as the coordinates in |
label_error is applied independently to each landmark coordinate. The function returns the smallest
continuous interval of projected 2D pitch angles compatible with that uncertainty.
If the uncertainty is large enough that all projected directions are possible, the returned interval spans the full circle.
A named list describing the smallest continuous angular interval compatible with the specified labeling error, with components:
from: Starting angle of the interval, in degrees.
to: Ending angle of the interval, in degrees.
width: Width of the interval, in degrees.
wrap: Logical indicating whether the interval crosses the 180/-180 boundary.
all: An empty list, included for consistency with summarize.yaws().
If the landmark error region contains the origin in its interior, all 2D pitch angles are possible and
the returned interval has from = -180, to = 180, and width = 360.
project2d.from.xy(), summarize.yaws()
# Projected vector from hypothetical pixel coordinates observed <- project2d.from.xy( x_tip = 10, y_tip = 8, x_base = 11, y_base = 12 ) # Pitch interval compatible with ±1 pixel labeling uncertainty pitch2d.w.error(observed, label_error = 1) # Pitch interval compatible with ±5 pixel labeling uncertainty (full circle returned) pitch2d.w.error(observed, label_error = 5)# Projected vector from hypothetical pixel coordinates observed <- project2d.from.xy( x_tip = 10, y_tip = 8, x_base = 11, y_base = 12 ) # Pitch interval compatible with ±1 pixel labeling uncertainty pitch2d.w.error(observed, label_error = 1) # Pitch interval compatible with ±5 pixel labeling uncertainty (full circle returned) pitch2d.w.error(observed, label_error = 5)
Plotting helper for quick visual inspection of angles, in particular pitches, yaws, and view elevations.
## S3 method for class 'angles' plot( angles = NULL, type = NULL, facing = c("right", "left"), col = NULL, main = NULL, labels = TRUE, add = FALSE )## S3 method for class 'angles' plot( angles = NULL, type = NULL, facing = c("right", "left"), col = NULL, main = NULL, labels = TRUE, add = FALSE )
angles |
Set(s) of angles to be plotted, in degrees in the range (-180, 180]. If a numeric vector,
one plot is generated. If a |
type |
When |
facing |
Character choice between |
col |
Optional vector of colors to draw angle segments in each plot. Recycled to match
|
main |
Optional character vector: titles for each plot. Recycled to match |
labels |
Logical scalar (default |
add |
Logical scalar (default |
No return value.
# calls with a vector ## pitch between 60 and 70 plot.angles(60:70, "pitch") ## view_elevation between -30 and -40 plot.angles(-30:-40, "view_elevation") # call with named list list <- list(pitch = 10:30, yaw = -100:-45, view_elevation = -10:-15) plot.angles(list) # call with output from find.3d ## pitches and yaws that project to 10° (± 1° error) if seen from 15° below df <- find.3d( pitch2d = 9:11, find = c("pitch", "yaw"), candidate_view_elevations = -15 ) plot.angles(df)# calls with a vector ## pitch between 60 and 70 plot.angles(60:70, "pitch") ## view_elevation between -30 and -40 plot.angles(-30:-40, "view_elevation") # call with named list list <- list(pitch = 10:30, yaw = -100:-45, view_elevation = -10:-15) plot.angles(list) # call with output from find.3d ## pitches and yaws that project to 10° (± 1° error) if seen from 15° below df <- find.3d( pitch2d = 9:11, find = c("pitch", "yaw"), candidate_view_elevations = -15 ) plot.angles(df)
Calculate the projected 2D pitch and length (relative or absolute) produced by combinations of 3D pitch, yaw, and view elevation.
project2d.from.3d(pitch, yaw, view_elevation, full_length = NULL, plot = FALSE)project2d.from.3d(pitch, yaw, view_elevation, full_length = NULL, plot = FALSE)
pitch |
Numeric vector: vertical orientation of the object relative to the horizontal plane, in
degrees, in the interval \(-180, 180]. Convention: |
yaw |
Numeric vector: horizontal orientation around the vertical axis, in degrees in the
interval (-180, 180]. Convention: |
view_elevation |
Numeric vector: camera elevation relative to the object, in degrees in
the interval [-90, 90]. Convention: |
full_length |
Optional positive numeric vector giving the unprojected (no foreshortening) length of
the directed vector. Values may be expressed in any linear unit. The returned |
plot |
Logical scalar. |
For the rotation matrix
where , , and are respectively pitch, yaw, and view elevation in radians
(as in rotate3d()), the projected components of the directed vector are
and
These are returned as dx_factor and dy_factor, respectively. Projected 2D pitch is then
and projection factor is
If full_length is supplied, the projected components are
and
giving projected length
full_length therefore need not represent a physical length. For example, a pixel length measured from
the same object under a known orientation with projection_factor == 1 may be supplied as a reference
length, provided image scale is unchanged. In that case, length2d, dx, and dy are returned in pixels.
pitch, yaw, and view_elevation are evaluated elementwise and must have the same length.
A list containing:
pitch2d: projected 2D pitch angle(s), in degrees in the interval (-180, 180].
projection_factor: projected length relative to full_length, ranging from 0 to 1.
dx_factor, dy_factor: projected x and y components per unit full_length.
length2d: if full_length is supplied, projected length in the same units.
dx, dy: if full_length is supplied, projected x and y components in the same units.
When the vector is effectively parallel to the viewing axis, projection_factor is zero and 2D pitch
is undefined (NA).
rotate3d(), project2d.from.xy(), find.3d()
# projected 2D pitch of object pointed up 15º and 30º toward camera, seen from 20º below project2d.from.3d( pitch = 15, yaw = -30, view_elevation = -20, plot = TRUE ) # also predict projected length from a 100-pixel reference length project2d.from.3d( pitch = 15, yaw = -30, view_elevation = -20, full_length = 100, plot = TRUE ) # vectorized usage project2d.from.3d( pitch = c(15, 15, 15), yaw = c(0, -30, 0), view_elevation = c(0, 0, -30), full_length = 100 )# projected 2D pitch of object pointed up 15º and 30º toward camera, seen from 20º below project2d.from.3d( pitch = 15, yaw = -30, view_elevation = -20, plot = TRUE ) # also predict projected length from a 100-pixel reference length project2d.from.3d( pitch = 15, yaw = -30, view_elevation = -20, full_length = 100, plot = TRUE ) # vectorized usage project2d.from.3d( pitch = c(15, 15, 15), yaw = c(0, -30, 0), view_elevation = c(0, 0, -30), full_length = 100 )
Calculate the projected pitch and length of the 2D directed vector defined by a base landmark and a tip landmark.
project2d.from.xy(x_tip, y_tip, x_base, y_base, plot = FALSE)project2d.from.xy(x_tip, y_tip, x_base, y_base, plot = FALSE)
x_tip, x_base
|
Numeric vectors: image x-coordinate(s) of tip and base of object, with x increasing right. |
y_tip, y_base
|
Numeric vectors: image y-coordinate(s) of the tip and base of objects, with y increasing up. |
plot |
Logical scalar. |
The landmarks define the directed vector
with projected 2D pitch
and projected 2D length
length2d is expressed in the same units as the landmark coordinates. For image coordinates in pixels,
for example, length2d is returned in pixels.
Coordinate arguments may have length 1 or a common length greater than 1. Length-1 arguments are recycled.
A data.frame of class araponga2d, with one row per base-tip pair and the following columns:
x_tip, y_tip, x_base, y_base: supplied landmark coordinates.
pitch2d: projected 2D pitch angle(s), in degrees in the interval (-180, 180].
length2d: Euclidean distance(s) between base and tip, in the same units as the supplied coordinates.
When tip and base coincide, length2d is zero and pitch2d is undefined (NA).
The returned object can be supplied as observed2d to find.3d() and wrappers.
pitch2d.w.error(), project2d.from.3d()
# scalar examples (plots) project2d.from.xy(1, 0, 0, 0, plot = TRUE) # pointed right -> 0° project2d.from.xy(-1, 0, 0, 0, plot = TRUE) # pointed left -> 180° project2d.from.xy(0, 1, 0, 0, plot = TRUE) # pointed up -> 90° project2d.from.xy(0, -1, 0, 0, plot = TRUE) # pointed down -> -90° # vectorised usage (no plot) x_tips <- c(1, 0, -1) y_tips <- c(0, 1, 0) x_bases <- c(0, 0, 0) y_bases <- c(0, 0, 0) project2d.from.xy(x_tips, y_tips, x_bases, y_bases)# scalar examples (plots) project2d.from.xy(1, 0, 0, 0, plot = TRUE) # pointed right -> 0° project2d.from.xy(-1, 0, 0, 0, plot = TRUE) # pointed left -> 180° project2d.from.xy(0, 1, 0, 0, plot = TRUE) # pointed up -> 90° project2d.from.xy(0, -1, 0, 0, plot = TRUE) # pointed down -> -90° # vectorised usage (no plot) x_tips <- c(1, 0, -1) y_tips <- c(0, 1, 0) x_bases <- c(0, 0, 0) y_bases <- c(0, 0, 0) project2d.from.xy(x_tips, y_tips, x_bases, y_bases)
Create a 3×3 rotation matrix corresponding to sequential Euler rotations about Z, then Y, then X (i.e., ZYX or pitch–yaw–roll sequence).
rotate3d(pitch = 0, yaw = 0, roll = 0) Rz(pitch = 0) Ry(yaw = 0) Rx(roll = 0)rotate3d(pitch = 0, yaw = 0, roll = 0) Rz(pitch = 0) Ry(yaw = 0) Rx(roll = 0)
pitch |
Numeric scalar: angle of rotation about the Z axis, in degrees. Defaults to |
yaw |
Numeric scalar: angle of rotation about the Y axis, in degrees. Defaults to |
roll |
Numeric scalar: angle of rotation about the X axis, in degrees. Defaults to |
Rz(), Ry(), and Rx() construct elementary rotation matrices about
the Z, Y, and X axes, respectively. rotate3d() combines these as
where , , and are pitch, yaw, and roll. When the
resulting matrix is applied to a column vector, the rotations therefore
occur in the order pitch, then yaw, then roll.
Angles are not restricted to a particular interval because rotations are periodic; any finite value in degrees is accepted.
In project2d.from.3d(), the same X-axis rotation represented here by
roll is used to incorporate view elevation. This represents relative
viewing geometry and should not be confused with image-plane camera roll.
A numeric 3×3 matrix (class matrix).
# rotate 45 about z, then 30 about y, then -80 about x rotate3d(45, 30, -80) # rotate 30 degrees about x Rx(30)# rotate 45 about z, then 30 about y, then -80 about x rotate3d(45, 30, -80) # rotate 30 degrees about x Rx(30)
Given a set of yaw angles (or any set of angles that wrap around ± 180), summarize.yaws() returns
the endpoints and width of the smallest continuous angular interval that contains all supplied angles.
summarize.yaws(yaws, plot = FALSE, tie_action = c("all", "error"))summarize.yaws(yaws, plot = FALSE, tie_action = c("all", "error"))
yaws |
Numeric vector of yaw angles, in degrees, in the interval (-180, 180]. |
plot |
Logical scalar. |
tie_action |
Choice between |
A named list with components:
numeric scalar: interval start (clockwise-most endpoint), in degrees.
numeric scalar: interval end (counterclockwise-most endpoint), in degrees.
numeric scalar: angular width of the shortest enclosing arc, in degrees.
logical: TRUE if the interval crosses the ±180 boundary.
list containing the output (from, to, width, wrap) for all alternative intervals, if any
# simple non-wrapping interval summarize.yaws(-60:60, plot = TRUE) # a wrapping interval (points around ±180) summarize.yaws(c(-175:-170, 171:179), plot = TRUE) # singleton (no plotting) summarize.yaws(30) # more than one interval possible (returns warning) summarize.yaws(c(-90, 90)) # output from find.yaw() yaws <- find.yaw( pitch2d = 14:16, candidate_view_elevations = -45, candidate_pitches = 10:20 ) summarize.yaws(yaws, plot = TRUE)# simple non-wrapping interval summarize.yaws(-60:60, plot = TRUE) # a wrapping interval (points around ±180) summarize.yaws(c(-175:-170, 171:179), plot = TRUE) # singleton (no plotting) summarize.yaws(30) # more than one interval possible (returns warning) summarize.yaws(c(-90, 90)) # output from find.yaw() yaws <- find.yaw( pitch2d = 14:16, candidate_view_elevations = -45, candidate_pitches = 10:20 ) summarize.yaws(yaws, plot = TRUE)
Trim two candidate yaw sets to angles that have at least one compatible partner in the other set, given minimum and maximum directional separation constraints.
trim.yaws(ccw_yaws, cw_yaws, min_sep, max_sep, plot = FALSE)trim.yaws(ccw_yaws, cw_yaws, min_sep, max_sep, plot = FALSE)
ccw_yaws |
Numeric vector: candidate yaw angles known/expected to be
counterclockwise of |
cw_yaws |
Numeric vector: candidate yaw angles known/expected to be clockwise of
|
min_sep |
Numeric scalar: minimum directional angular separation in degrees, satisfying
|
max_sep |
Numeric scalar: maximum directional angular separation in degrees, satisfying
|
plot |
Logical scalar. |
Given two sets of candidate yaw angles, trim.yaws() retains angles that
have at least one compatible partner in the other set. Directional
separation is measured counterclockwise from cw_yaws to ccw_yaws
and is represented in the interval [0, 360).
For a pair of angles from ccw_yaws and from cw_yaws,
their directional separation is
A pair is compatible when this separation is greater than or equal to
min_sep and less than or equal to max_sep. Each returned angle
therefore has at least one compatible partner in the other returned set.
A list with elements:
numeric: subset of ccw_yaws that have at least one matching cw_yaws.
numeric: subset of cw_yaws that have at least one matching ccw_yaws.
# hypothetical candidate yaw sets: a <- 10:80 b <- 30:90 # we know `a` to be CCW of `b` by up to 180° trim.yaws(a, b, 0, 180, plot = TRUE) # we know `a` to be CCW of `b` by 30 to 45° trim.yaws(a, b, 30, 45, plot = TRUE) # if no mutual partners exist, both returned vectors become empty trim.yaws(ccw_yaws = c(-10), cw_yaws = c(130), min_sep = 0, max_sep = 180)# hypothetical candidate yaw sets: a <- 10:80 b <- 30:90 # we know `a` to be CCW of `b` by up to 180° trim.yaws(a, b, 0, 180, plot = TRUE) # we know `a` to be CCW of `b` by 30 to 45° trim.yaws(a, b, 30, 45, plot = TRUE) # if no mutual partners exist, both returned vectors become empty trim.yaws(ccw_yaws = c(-10), cw_yaws = c(130), min_sep = 0, max_sep = 180)