fit_circle: Fits 2D Circles on a Point Cloud

View source: R/fit_shapes.R

fit_circleR Documentation

Fits 2D Circles on a Point Cloud

Description

Fits a 2D horizontally-aligned circle to a set of 3D points. The method uses RANSAC-based fitting for robust estimation. The function returns a list with the circle parameters and additional data to help determine whether the points form a circular shape. While it is always possible to fit a circle to any dataset, the additional information assists in evaluating if the data genuinely represent a circular pattern. The root mean square error (RMSE) may not always be a reliable metric for assessing the quality of the fit due to non-circular elements (such as branches) that can arbitrarily increase the RMSE of an otherwise well-fitted circle, as shown in the example below. Therefore, the function also returns the angular range of the data, which indicates the spread of the inlier points: 360 degrees suggests a full circle, 180 degrees indicates a half-circle, or a smaller range may suggest a partial arc.

Usage

fit_circle(points, num_iterations = 100, inlier_threshold = 0.01)

Arguments

points

A LAS object representing a clustered slice, or an nx3 matrix of point coordinates.

num_iterations

The number of iterations for the RANSAC fitting algorithm.

inlier_threshold

A threshold value; points are considered inliers if their residuals are below this value.

Value

A list containing the circle parameters and additional information for determining whether the data fit a circular shape:

  • center_x, center_y, radius: parameters of the fitted circle.

  • z: average elevation of the circle.

  • rmse: root mean square error between the circle and all points.

  • angle_range: angular sector covered by inlier points.

  • inliers: IDs of the inlier points.

Examples

LASfile <- system.file("extdata", "dbh.laz", package="lidR")
las <- readTLS(LASfile, select = "xyz")
xyz = sf::st_coordinates(las)
circle = fit_circle(xyz)
plot(xyz, asp = 1, pch = 19, cex = 0.1)
symbols(circle$center_x, circle$center_y, circles = circle$radius,
  add = TRUE, fg = "red", inches = FALSE)

trunk = las[circle$inliers]

# Fitting a half-circle
half = xyz[xyz[,1] > 101.45,]
circle = fit_circle(half)
plot(half, asp = 1, pch = 19, cex = 0.1)
symbols(circle$center_x, circle$center_y, circles = circle$radius,
  add = TRUE, fg = "red", inches = FALSE)
circle$angle_range

Jean-Romain/lidR documentation built on Feb. 9, 2025, 9:08 a.m.