This documentation was generated with the assistance of AI. Please report any inaccuracies.
A transformation maps geometric entities (points, lines, planes, conics, quadrics, cameras) onto other
entities of the same kind. irurueta-geometry organizes transformations into a stratified hierarchy of
increasing generality — Euclidean, metric, affine and projective — each one a special case of the next. This
page explains that hierarchy, what each family preserves, and how the library actually implements it in
com.irurueta.geometry.Transformation2D / Transformation3D and their subclasses.
The hierarchy
Family
Adds on top of the previous family
DOF (2D / 3D)
Preserves / fixes at infinity
Euclidean (rigid)
rotation + translation
3 / 6
distances, angles, areas/volumes; trivially fixes , and and the absolute scale.
Metric (similarity)
+ uniform scale
4 / 7
angles, ratios of distances, shape; fixes the plane at infinity and the absolute conic / dual absolute quadric (up to scale) — but not the absolute scale itself.
Affine
+ independent axis scaling and skew (general linear map)
6 / 12
parallelism, ratios of lengths on parallel lines, ratios of areas/volumes; fixes the plane at infinity as a set (not pointwise), but not /.
Projective
+ a general homography, defined up to scale
8 / 15
incidence (collinearity/coplanarity), cross-ratio of 4 collinear points; fixes none of , or in general.
The DOF and invariants above match the standard 2D hierarchy in
Hartley & Zisserman table 2.4 (p.44) and the 3D hierarchy in their
table 3.2 (p.78), and are worked out from first principles in
Irurueta’s PhD thesistable 1.4 (p.42). The rest of this page is devoted to
why those particular quantities — the plane at infinity, the absolute conic and the dual absolute quadric — are exactly the ones that separate affine from metric from Euclidean.
Each family is strictly more general than the previous one: every Euclidean transformation is also a metric
transformation (with scale = 1), every metric transformation is also affine, and every affine transformation is
also projective. irurueta-geometry exposes this with one-directional "upgrade" converters rather than a shared
supertype:
classDiagram
class Transformation2D
class Transformation3D
class EuclideanTransformation2D
class MetricTransformation2D
class AffineTransformation2D
class ProjectiveTransformation2D
Transformation2D <|-- EuclideanTransformation2D
Transformation2D <|-- AffineTransformation2D
Transformation2D <|-- ProjectiveTransformation2D
EuclideanTransformation2D <|-- MetricTransformation2D
EuclideanTransformation2D ..> MetricTransformation2D : toMetric()
MetricTransformation2D ..> AffineTransformation2D : toAffine()
AffineTransformation2D ..> ProjectiveTransformation2D : toProjective()
The 3D classes (Transformation3D, EuclideanTransformation3D, MetricTransformation3D,
AffineTransformation3D, ProjectiveTransformation3D) mirror this exactly. Two details worth noting:
MetricTransformation2D/3DextendsEuclideanTransformation2D/3D, adding a single scale field — metric/similarity really is "Euclidean plus scale" in the implementation, not an independent class.
AffineTransformation2D/3D and ProjectiveTransformation2D/3D extend Transformation2D/3D directly
(they do not extend Metric*/Euclidean*). They only expose one-way upgrade methods (toAffine(),
toProjective()); there is no built-in "downgrade" that tries to recover a simpler transformation from a more
general one.
ProjectiveTransformation2D/3D makes the nesting explicit in its own javadoc: its internal matrix has an
extra "projective parameters" row that is [0, …, 0, 1] (up to scale) for every transformation that is really
just affine, metric, or Euclidean in disguise.
Internal representation
Class
Representation
EuclideanTransformation2D/3D
a Rotation2D/Rotation3D plus a translation vector; point maps to .
MetricTransformation2D/3D
the same rotation/translation, plus a scalar scale; point maps to .
AffineTransformation2D/3D
a general (non-orthonormal) linear map matrix A (2×2 / 3×3) plus a translation; point maps to
. Rotation and independent-scale/skew components are recovered on demand from A via
RQ decomposition (getRotation(), getParameters() / AffineParameters2D/3D).
ProjectiveTransformation2D/3D
a single homogeneous matrix T (3×3 / 4×4), defined up to scale; a homogeneous point maps to
directly, with no separate translation step.
How other geometric entities transform
Because points, lines/planes and conics/quadrics play different roles in projective duality, they don’t all
transform the same way. Given a transformation matrix T (2D: 3×3, 3D: 4×4) and its application to a
point p' = T·p, the library implements:
Entity
Transform rule
Point2D / Point3D
(direct forward map)
Line2D / Plane
(inverse-transpose — lines/planes are covectors)
Conic / Quadric
(inverse-transpose on both sides)
DualConic / DualQuadric
(forward on both sides — duals transform contragradiently to their primal)
PinholeCamera
camera matrix
Polygon / Triangle
vertices transformed individually (each vertex is just a point)
Line3D
derived by transforming the two planes that define it
The inverse-transpose rule for lines/planes/conics/quadrics is the standard projective-duality argument, and it
appears as an inline comment repeated across every subclass’s transform(Conic, …) /
transform(Line2D, …) method, e.g.:
// point' * conic * point = 0
// point' * T' * transformedConic * T * point = 0
// where: transformedPoint = T * point
// Hence: transformedConic = T^-1' * conic * T^-1
All of these transform methods normalize the input, invert T once, and re-normalize before multiplying — this is a numerical-stability pattern repeated identically across the Euclidean/Metric/Affine/Projective
implementations of every entity above.
Invariants: what fixes what
The table above says that affine transformations preserve parallelism while metric transformations preserve
angles. Both facts have a single, precise algebraic root: each stratum is exactly the subgroup of the
projective linear group that fixes one particular geometric object living at infinity. Affine transformations
are exactly the ones that fix the plane at infinity as a set; metric (similarity)
transformations are exactly the ones that, in addition, fix the absolute conic (or,
equivalently, the dual absolute quadric ); Euclidean transformations are metric
transformations with the remaining scale freedom pinned to 1. This section works through why, following
Irurueta’s PhD thesis§1.4 and
Hartley & Zisserman §3.5-3.7.
The plane at infinity fixes the affine stratum
In any projective frame of , the points with homogeneous last coordinate
form a plane, the plane at infinity. In a frame that is already
affine (or metric, or Euclidean) it takes the canonical form
(PHD eq. 1.118; HZ eq. 3.1-analogue for 3-space). This is
exactly the constant returned by
Plane.createCanonicalPlaneAtInfinity(). Under an arbitrary projective transformation, however,
moves like any other plane — the library’s own rule
applies to it too, and in an arbitrary projective frame it can be anywhere: 3 vanishing points fix 3 independent
directions, and the plane they span identifies where actually sits in that frame
(PHD fig. 1.9). This is exactly what plane-at-infinity.svg below illustrates: on the left, a cube seen through an
uncalibrated homography, where 3 vanishing points mark 3 points of ;
on the right, the same cube after upgrading to the affine stratum, where those vanishing points have moved back
out to infinity and the cube’s edges are visibly parallel again.
Claim (PHD eq. 1.121-1.123; HZ Result 3.7): a projective
transformation fixes as a set
if, and only if, it is an affinity. Write a general affine transformation in the library’s own block form
(the exact shape produced by AffineTransformation3D.toProjective(), see below):
Applying the plane-transform rule directly to the canonical
(PHD eq. 1.121):
so is a fixed point of , and hence (taking inverse-transposes,
PHD eq. 1.123) also of the library’s covector rule .
Notice this is set-invariance, not pointwise invariance: individual points within — i.e. individual directions/vanishing points — are free to move around, as long as they stay on the plane. The
converse (any projective H that fixes as a set must have a last row proportional to
, i.e. must be affine) is HZ Result 3.7, proved the same way the 2D analogue (Result 2.17)
is: fixing a hyperplane algebraically forces the homography’s action on the complementary coordinate to vanish.
This is also precisely how you find the affine upgrade once has been identified in an
arbitrary projective frame: any matrix of the form
(PHD eq. 1.125, with the first 3
coordinates of the identified ,
scaled so its last coordinate is 1 — PHD eq. 1.126) sends that
plane back to its canonical position, because its
last row is. Any with non-singular works equally well
(PHD eq. 1.127) — is simply the simplest choice.
The absolute conic and dual absolute quadric fix the metric stratum
Fixing buys parallelism but says nothing about angles: an affine map can still skew a
square into an arbitrary parallelogram. To pin down angles, both HZ and PHD start from the elementary fact that
two vectors are orthogonal iff their dot product vanishes,
(PHD eq.
1.143-1.144). Pushing that relation through an arbitrary homography gives
(PHD eq. 1.145-1.148):
and is symmetric, i.e. exactly the shape of a conic transformed by the
library’s own rule with in the metric
frame. Running the same argument in 3D with planes and their director vectors
(PHD eq. 1.154-1.158) shows that
the analogous quadric that certifies orthogonality of planes in a metric frame is degenerate — — because the extra row/column that would encode a translation-like
term must vanish for perpendicularity to be translation-independent.
These two constants are, respectively, the absolute conic and the dual absolute
quadric: the point conic that lies on (formed by
intersecting the absolute quadric ), and the degenerate quadric whose
tangent planes are exactly the planes tangent to
(PHD §1.4.3.1, fig. 1.12). In a
metric frame:
(PHD eq. 1.160/1.162/1.169; HZ eq. 3.21/3.24 — identical
constants). Algebraically
is a conic of purely imaginary points, i.e. a "circle" of imaginary radius
(PHD eq. 1.163,
fig. 1.14); is the limit of an
ever-more-squashed
sphere as
(PHD eq. 1.168, fig. 1.15; HZ calls this a
"rim quadric" — picture an ellipsoid squashed to a pancake, with as its rim). These
are exactly the shapes absolute-conic-quadric.svg below depicts.
Claim (PHD Proof 1.6,
eq. 1.170-1.178; HZ Result 3.9/3.10): a projective transformation
fixes
(equivalently , up to the overall scale any projective quantity
is defined up to) if, and only if, it is a similarity. Sufficiency is a direct computation: writing a
similarity in the library’s block form (matching `EuclideanTransformation3D.toMetric()’s output shape) and
applying the dual-quadric transform rule (the library’s own
forward-forward rule for duals) gives
using for any rotation
(PHD eq. 1.170-1.173) — i.e.
is reproduced up to the scalar , which is exactly the "up to scale"
sense in which any projective entity is defined. For necessity, take an arbitrary projective
and demand
:
Matching this against (up to the scalar discussed above)
forces
(PHD eq. 1.177). So — the projective row that
would otherwise move — must
vanish, and must be a scaled rotation (the condition
is exactly "orthogonal up to a positive scalar"). That leaves precisely
a similarity transformation (PHD eq. 1.178) — and since
sits in the top-left
minor of (PHD eq.
1.166), a transformation that fixes
fixes (and hence ) too. HZ Result 3.10 gives the equivalent block-matrix proof for
directly, and Result 3.9 proves the corresponding statement for
itself by first invoking Result 3.7 (any transformation fixing a conic on must first fix , hence be affine) and then showing the affine part
must be orthogonal up to scale.
Upgrading between strata
Because affine upgrade only needs while metric upgrade needs /
as well, the two upgrades compose. Combining (eq. 1.125) with the
affine→metric matrix that Cholesky-factors the recovered conic out of the affine-stratum
dual quadric (PHD eq. 1.179-1.184) gives a single
projective→metric matrix (PHD eq. 1.185-1.186):
Inverting it (PHD eq. 1.189-1.192, via blockwise matrix
inversion) and substituting into the dual-quadric
transform rule shows that in any projective frame
(PHD eq. 1.193-1.195):
i.e. the dual absolute quadric in an arbitrary projective frame packages both the dual image of the absolute
conic (the "DIAC" that reappears in camera calibration, see
Pinhole Camera) and the direction of the plane at infinity into a single
symmetric matrix. This is why, in self-calibration literature, recovering
is treated as the way to upgrade a projective reconstruction straight to metric in one
step, rather than recovering and separately.
irurueta-geometry does not ship such a self-calibration/stratified-upgrade estimator — there is no
toAffine()/toMetric() on ProjectiveTransformation2D/3D, and no class under
com.irurueta.geometry.estimators or com.irurueta.geometry.refiners computes or
from image data. What the library does give you is exactly the algebraic building blocks
above — the canonical values of , and ,
and the one-directional Euclidean→metric→affine→projective upgrade chain — so that, given a
Plane/Conic/DualQuadric identified by some other means (vanishing points, orthogonal-plane constraints,
Kruppa’s equations, etc.), an application can still build the matrices /
above by hand.
From theory to code
The canonical constants above are not just theory — they are literally the values the library’s factory
methods return:
And the one-way upgrade chain (Euclidean → metric → affine → projective) walks the strata
exactly in the direction the invariants above allow — each step adds a degree of freedom (scale, then general
linear skew, then the projective row) rather than removing one:
Rotation3D rotation = new AxisRotation3D(0.0, 0.0, 1.0, Math.PI / 6.0);
double[] translation = {1.0, 2.0, 3.0};
EuclideanTransformation3D euclidean = new EuclideanTransformation3D(rotation, translation);
// adds a uniform scale (MetricTransformation3D.DEFAULT_SCALE = 1.0 initially)
MetricTransformation3D metric = euclidean.toMetric();
// embeds scale * R as the general 3x3 linear part -- concretely "metric subset of affine"
AffineTransformation3D affine = metric.toAffine();
// appends the implicit last row [0 0 0 1] -- this IS T_A from PHD eq. 1.120 / HZ table 3.2,
// the exact matrix shape whose invariance of Pi_infinity was proved above
ProjectiveTransformation3D projective = affine.toProjective();
AffineTransformation3D.toProjective() (AffineTransformation3D.java:1018-1020) builds
new ProjectiveTransformation3D(a, translation), which is precisely the block form
used throughout the proofs above — seeing that constructor call is seeing
PHD eq. 1.120 typed out in Java. Similarly,
MetricTransformation3D.toAffine() (MetricTransformation3D.java:272-274) builds
new AffineTransformation3D(scale, getRotation(), getTranslation()), embedding as the
linear part — the exact matrix that appeared as in the necessity proof of
§Invariants above.
References
The core Transformation* classes carry no external bibliographic citations in their javadoc — the
Euclidean/metric/affine/projective stratification is standard projective-geometry material, but it has precise,
citable proofs in both sources used throughout this page (see the full
bibliography for full citations):
Hartley & Zisserman, Multiple View Geometry in Computer Vision, 2nd
ed. §2.4 (pp.37-44, table 2.4) for the 2D hierarchy of transformations and its invariants; §3.4-3.7
(pp.77-84, table 3.2) for the 3D hierarchy, the plane at infinity (Result 3.7, worked
Example 3.8), the absolute conic (Result 3.9), and the absolute dual quadric
(Result 3.10, with a full matrix proof). Also §3.2.1/§3.2.3 (pp.66-74) for the
point/plane transform rule and the (dual) quadric transform rules
/ implemented by this
library’s transform(Plane, …) / transform(Quadric, …) / transform(DualQuadric, …) methods.
Points, Lines and Planes — the point/line/plane entities being transformed, and the plane-at-infinity’s
role among them.
Conics and Quadrics — conics, dual conics, quadrics and dual quadrics in detail, including the
absolute conic and dual absolute quadric introduced above.
Pinhole Camera — how a transformation acts on a PinholeCamera, and how the dual absolute quadric
relates to camera self-calibration.
Rotations — the Rotation2D/Rotation3D classes used internally by Euclidean and metric
transformations.