This documentation was generated with the assistance of AI. Please report any inaccuracies.
Point2D/Point3D, Line2D and Plane are the three simplest estimator hierarchies in
com.irurueta.geometry.estimators. Each one wraps a single closed-form linear-algebra construction — the
exact join/meet operations already derived on Points, Lines and Planes — in the same family of five
robust variants that Estimators explains once, generically, for all twelve hierarchies in the
library. This page does not re-derive either piece: it connects the two. For the join/meet cross products, the
signed point-to-line distance and the 4×4-determinant plane construction, see
Points, Lines and Planes; for why five robust variants exist at all and the RANSAC/LMedS/MSAC equations
behind them, see Estimators (particularly estimators.adoc#non-robust-vs-robust,
estimators.adoc#ransac, estimators.adoc#lmeds, estimators.adoc#msac and
estimators.adoc#prosac-promeds).
A structural quirk worth flagging up front: unlike Line2D and Plane, there is no non-robust
Point2DEstimator/Point3DEstimator class at all — Point2DRobustEstimator/Point3DRobustEstimator are
abstract classes with no non-robust sibling, only the five robust wrappers. The minimal-sample closed form
(line∩line, or plane∩plane∩plane) is inlined directly inside each concrete
RANSACXxx/LMedSXxx/… class instead of living in a standalone estimator, exactly as
estimators.adoc#non-robust-vs-robust describes for PlaneEstimator (which likewise does not exist as a
public class).
Point2D and Point3D: the point that best fits a pencil of lines or planes
Point2DRobustEstimator and Point3DRobustEstimator solve the dual problem to the other two hierarchies
below: instead of fitting a line/plane through points, they fit a point through lines/planes.
`Point2DRobustEstimator’s own class javadoc reads, verbatim: "This is an abstract class for algorithms to
robustly find the best 3D point that intersects in a collection of 2D lines."
That "3D point" is a real, verified copy-paste typo in the source (Point2DRobustEstimator.java:34-37) — the class is unambiguously about Point2D (its estimate() returns Point2D, its MINIMUM_SIZE counts
Line2D instances, and `Point3DRobustEstimator’s own javadoc immediately below it correctly says "3D point"
for the actual 3D case). It is mentioned here because it is genuinely in the shipped javadoc, not because it
changes anything about how the class behaves.
Point2DRobustEstimator
Point3DRobustEstimator
Fits
the best 2D point that intersects a collection of Line2D (Point2DRobustEstimator.java:34-38)
the best 3D point that intersects a collection of Plane (Point3DRobustEstimator.java:34-38)
The closed-form step is a direct call into the meet operation Points, Lines and Planes already covers
under Shared operations: incidence, join, meet:
RANSACPoint2DRobustEstimator’s
`estimatePreliminarSolutions draws 2 lines from the minimal sample and calls
line1.getIntersection(line2) (RANSACPoint2DRobustEstimator.java:254-264, with the actual intersection at
line 259); RANSACPoint3DRobustEstimator does the analogous 3-plane version,
plane1.getIntersection(plane2, plane3) (RANSACPoint3DRobustEstimator.java:254-265). Both are the same
SVD null-space computation used for Line2D.intersection/Plane.intersection — the numerical generalization
of the cross-product meet m = l1 × l2.
The residual each robust wrapper scores a candidate point against is not a point-to-point distance — it is
the point’s distance to each of the input lines/planes it was not built from, using exactly the signed distance
formula already derived on Points, Lines and Planes. Point2DRobustEstimator.residual(Point2D, Line2D)
(Point2DRobustEstimator.java:866-871) is:
i.e. — the same
Line2D.signedDistance formula Points, Lines and Planes derives from the PhD thesis’s
Proof 1.1.
Point3DRobustEstimator.residual(Point3D, Plane) (Point3DRobustEstimator.java:865-870) is the 3D analogue,
Math.abs(plane.signedDistance(p)), using Plane.signedDistance(Point3D) (Plane.java:515-525) — the same
"dot product of homogeneous coordinates, normalized by the coefficient norm" pattern one dimension up, applied
to instead of . So a candidate 2D point’s total cost
is effectively how far it sits, on average or under a threshold, from every sampled line, not just the two it
was built from — exactly the outlier-rejection role estimators.adoc#non-robust-vs-robust describes.
// find the 2D point best explained by a set of (possibly noisy) 2D lines
final var estimator = new RANSACPoint2DRobustEstimator(lines);
estimator.setThreshold(1.0); // 1 pixel, RANSACPoint2DRobustEstimator.DEFAULT_THRESHOLD
final var bestPoint = estimator.estimate();
// the 3D dual: best 3D point explained by a set of 3D planes
final var estimator3D = new RANSACPoint3DRobustEstimator(planes);
estimator3D.setThreshold(1.0); // 1 "voxel", RANSACPoint3DRobustEstimator.DEFAULT_THRESHOLD
final var bestPoint3D = estimator3D.estimate();
Line2D: the line that best fits a set of points
`Line2DRobustEstimator’s own javadoc is exactly the mirror image of the point case above — and correctly
worded, unlike `Point2DRobustEstimator’s: "This is an abstract class for algorithms to robustly find the
best 2D line that passes through a collection of 2D points."
MINIMUM_SIZE is 2 (Line2DRobustEstimator.java:36). The closed-form step is the join operation
Points, Lines and Planes derives as the point-line duality’s cross product,
: RANSACLine2DRobustEstimator.estimatePreliminarSolutions
(RANSACLine2DRobustEstimator.java:179-189) draws two points from the minimal sample and constructs
final var line = new Line2D(point1, point2, false);
(RANSACLine2DRobustEstimator.java:184). That three-argument constructor delegates to
setParametersFromPairOfPoints (Line2D.java:118-120 for the constructor, Line2D.java:330 for the
implementation), the same SVD null-space join Points, Lines and Planes describes under
Shared operations — the numerical,
arbitrary-precision form of l = m1 × m2 that the third noThrow boolean argument guards against
throwing a CoincidentPointsException when the two sampled points happen to coincide (the surrounding
try/catch at RANSACLine2DRobustEstimator.java:183-188 simply drops that sample and adds no candidate).
The residual is the same signed point-to-line distance used above, just with the roles of point and line
swapped: Line2DRobustEstimator.residual(Line2D, Point2D) (Line2DRobustEstimator.java:722-727) is
— literally Line2D.signedDistance(Point2D) (Line2D.java:460), the exact formula
Points, Lines and Planes derives via
Proof 1.1 of the PhD thesis (projecting onto
the
line’s director vector). This is the cleanest instance of the pattern in this whole page: the non-robust
algorithm (l = m1 × m2) and the residual are both operations
Points, Lines and Planes already fully derives — Line2DRobustEstimator and its five concrete
subclasses contribute nothing mathematically new, only the sampling/scoring loop from
estimators.adoc#shared-architecture.
// find the 2D line best explained by a noisy set of 2D points
final var estimator = new RANSACLine2DRobustEstimator(points);
estimator.setThreshold(1.0); // 1 pixel, RANSACLine2DRobustEstimator.DEFAULT_THRESHOLD
final var bestLine = estimator.estimate();
Plane: the plane that best fits a set of points
`PlaneRobustEstimator’s javadoc reads: "This is an abstract class for algorithms to robustly find the best
3D plane that passes through a collection of 3D points."
MINIMUM_SIZE is 3 (PlaneRobustEstimator.java:36). The closed form is the 3D join
Points, Lines and Planes derives from the 4×4-determinant/Laplace-expansion argument: any point
coplanar with three others makes a 4×4 coordinate matrix singular, and that matrix’s null-space is the
plane’s homogeneous coefficients. RANSACPlaneRobustEstimator.estimatePreliminarSolutions
(RANSACPlaneRobustEstimator.java:179-190) draws three points from the minimal sample and constructs
final var plane = new Plane(point1, point2, point3);
(RANSACPlaneRobustEstimator.java:185), catching ColinearPointsException when the three sampled points
happen to be collinear (no plane, so no candidate is added for that sample). This constructor is
Plane’s "join" analogue to `Line2D.setParametersFromPairOfPoints — the same SVD null-space technique,
one dimension up, that Points, Lines and Planes attributes to Plane.setParametersFromThreePoints
under Shared operations.
The residual is the point-to-plane signed distance: PlaneRobustEstimator.residual(Plane, Point3D)
(PlaneRobustEstimator.java:722-727) is
i.e. Plane.signedDistance(Point3D) (Plane.java:515-525), the 3D point-plane-duality analogue
() of the 2D signed distance Points, Lines and Planes derives in full for
the point-line case — the library does not re-derive a separate proof for the plane case in the PhD thesis, but
the formula (dot product of homogeneous coordinates over the coefficient vector’s norm) is structurally
identical.
// find the 3D plane best explained by a noisy set of 3D points
final var estimator = new RANSACPlaneRobustEstimator(points);
estimator.setThreshold(1.0); // 1 "voxel", RANSACPlaneRobustEstimator.DEFAULT_THRESHOLD
final var bestPlane = estimator.estimate();
Shared configuration and what the five variants buy you here
All four abstract classes above (Point2DRobustEstimator, Point3DRobustEstimator, Line2DRobustEstimator,
PlaneRobustEstimator) expose exactly the shared properties estimators.adoc#shared-architecture's table
describes generically — MINIMUM_SIZE, confidence (DEFAULT_CONFIDENCE = 0.99), maxIterations
(DEFAULT_MAX_ITERATIONS = 5000), progressDelta and a listener — and none of them implement any sampling or
scoring logic themselves: every concrete RANSACXxx/LMedSXxx/MSACXxx/PROSACXxx/PROMedSXxx class hands
its estimatePreliminarSolutions/computeResidual pair straight to
com.irurueta.numerical.robust’s generic `RANSACRobustEstimator<T>, LMedSRobustEstimator<T>, etc., exactly
as estimators.adoc#shared-architecture describes for all twelve hierarchies. Point2DRobustEstimator and
Point3DRobustEstimator additionally carry a refineResult/refinementCoordinatesType/keepCovariance trio
(defaulting to Levenberg-Marquardt refinement over the final inlier set, homogeneous or inhomogeneous) that
Line2DRobustEstimator and PlaneRobustEstimator do not expose — the latter two return their robust result
directly with no separate refinement step.
What differs between the five variants is exactly what Estimators describes in the abstract, and
it is worth making concrete for this specific line/point/plane fitting problem rather than repeating the
formulas again:
RANSAC/MSAC need a threshold (DEFAULT_THRESHOLD = 1.0 for every one of the ten concrete classes on
this page, documented as "1 pixel" for the 2D hierarchies and "1 voxel" for the 3D ones). Fitting a 2D line to
a real, noisy point cloud with, say, 1-pixel Gaussian localization error and a handful of gross mismatches,
a threshold around 1-2 pixels (estimators.adoc#ransac's for 1
degree of freedom) correctly separates inliers from outliers; setting it too tight starts rejecting genuine
inliers as noise pushes them just past the boundary, too loose lets outliers vote for a biased line.
LMedS needs no threshold at all — useful exactly when that per-image-source pixel/voxel noise level is
unknown — but only while under half the points are outliers; past that, the median residual is itself an
outlier’s residual and LMedSLine2DRobustEstimator/LMedSPlaneRobustEstimator degrade, whereas
RANSACLine2DRobustEstimator with a well-chosen threshold keeps working.
PROSAC/PROMedS need a double[] qualityScores, one entry per line/point/plane (e.g.
PROSACLine2DRobustEstimator(List<Point2D> points, double[] qualityScores)), and simply try
high-quality-first minimal samples before falling back to RANSAC’s/LMedS’s own scoring — for a line fit from
a feature tracker’s point correspondences, feeding the tracker’s own per-point confidence directly in as
qualityScores converges to the right line in far fewer of the maxIterations than uniform-random sampling
would need.
The number of samples needed for a given confidence still follows estimators.adoc#ransac's eq. 4.18
directly from MINIMUM_SIZE: at s = 2 (Line2D, Point2D) a 99%-confidence RANSAC run needs far fewer trials
for a given outlier ratio than the s = 3 case (Plane, Point3D) or the larger-sample hierarchies on
Conic and Quadric Estimators/Pinhole Camera Estimators — these three hierarchies are, sample
efficiency-wise, the cheapest robust fits in the whole library.
References
No new book or paper citation is introduced on this page. All of the mathematics is either already derived on
Points, Lines and Planes (the join/meet cross products behind line1.getIntersection(line2),
plane1.getIntersection(plane2, plane3), new Line2D(point1, point2, false), new Plane(point1, point2,
point3), and the signed point-to-line distance behind every residual() method above, including its 3D
point-to-plane analogue) or already derived on Estimators (the RANSAC/LMedS/MSAC/PROSAC/PROMedS
scoring rules and sample-count formula, Hartley & Zisserman chapter 4
and Irurueta’s PhD thesis§2.5). Everything specific to this page — MINIMUM_SIZE values, the exact estimatePreliminarSolutions/computeResidual code, the Point2DRobustEstimator
javadoc typo, DEFAULT_THRESHOLD values — is drawn directly from the library’s own source rather than from any
of the three source PDFs.
Key classes
The classes exercised by the code examples above, with links to their source and Javadoc:
Estimators — the general robust-estimation theory (non-robust vs. robust, RANSAC/LMedS/MSAC/
PROSAC/PROMedS equations, shared com.irurueta.numerical.robust architecture) this page builds on.
Points, Lines and Planes — the point/line/plane entities themselves, their homogeneous
representations, and the join/meet/signed-distance math these estimators wrap.