Realizing a polygonal Jordan curve as a ClosedPolygon #
The blueprint's "simple closed polygonal curve" is set-theoretic: an IsJordanCurve that is
also IsPolygonal, with no condition on vertices at all. The development works instead with
Schoenflies.ClosedPolygon, a cyclic vertex list carrying a corner field — no three
consecutive vertices collinear. That field is a presentation condition, strictly stronger than
the blueprint's notion, and until now nothing said that a set-level polygonal Jordan curve
admits such a presentation. This module proves it.
How the vertex list is found #
The curve is not read off the vertex list IsPolygonal hands over: that list may retrace
itself, cross itself, and repeat segments, and it carries no order along the curve. Two
structures are laid over the point set instead and then matched.
- From the plane side, the overlay of
Schoenflies/OverlayGraph.lean, with the graph discarded:Schoenflies.IsCleanis a finite list of nondegenerate segments occupying the curve, with pairwise disjoint interiors and no end interior to any of them. Around an interior point of a piece the curve is that piece (IsClean.exists_ball_subset_seg), so the piece interiors are separated by honest open sets of the plane (Schoenflies.nearPiece) and a connected subset of the curve away from the ends lies inside a single piece. - From the curve side, the loop's parameters at which it reaches an end of a piece. They
form a finite subset of
[0, 1)containing0—0because the loop's start is put on the cut list, so that the last gap is the one that closes the curve — and, listed in increasing order, they cut[0, 1)into gaps.
The two match: a gap image is connected and misses the ends, so it lies in one piece interior;
and the interior is connected and covered by the closed gap images, so it lies in that one
gap. Gaps and pieces therefore correspond one to one, the ends of a gap are the ends of its
piece, and the ends listed in the loop's order are a cyclic vertex list whose edges are the
pieces. That list satisfies vertex_inj and edges_meet but not corner, which is what
Schoenflies.PrePolygon is for; corner is then arranged by deleting redundant vertices.
Blueprint #
Schoenflies.PrePolygon— aClosedPolygonless thecornerfield: the blueprint's simple closed polygonal curve presented by a vertex list, redundant vertices allowed.Schoenflies.PrePolygon.deleteLast,Schoenflies.PrePolygon.exists_closedPolygon_of_prePolygon— the blueprint's opening move in Lemma 1.8, "delete redundant vertices at which two consecutive edges are collinear", as an operation rather than an invariant.Schoenflies.IsClean,Schoenflies.exists_isClean— Lemma 3.7 (polygonal overlay) with the combinatorics dropped: what the overlay says about the point set alone.Schoenflies.par,Schoenflies.parNext,Schoenflies.exists_mem_gap— the parameters in increasing order, and that their gaps tile[0, 1).Schoenflies.exists_prePolygon_of_isJordanCurve,Schoenflies.exists_closedPolygon— §1: every simple closed polygonal curve, in the blueprint's set-level sense, is the carrier of aClosedPolygon.Schoenflies.IsStraightAt,Schoenflies.IsCornerAt,Schoenflies.ClosedPolygon.exists_vertex_eq_of_isCornerAt,Schoenflies.ClosedPolygon.isCornerAt_vertex— the vertex set of a realization is exactly the set of points at which the curve does not run straight. So a named point can be required to be a vertex precisely when it is a corner, and no realization has any choice about it.Schoenflies.ClosedPolygon.rotate,…isArcBetween_arc,…arc_inter— the two arcs of a splitting, as arcs between the two cut vertices meeting exactly there.Schoenflies.two_arcs_unique— two points cut a Jordan curve into two arcs in only one way.Schoenflies.exists_closedPolygon_corners,Schoenflies.exists_closedPolygon_split,Schoenflies.exists_closedPolygon_arcs,Schoenflies.exists_closedPolygon_arcs_ordered— the realization with named corners, with the splitting indices, and with the two arcs identified. The last is the shapeGraph.IsHexRealizationasks for.
The corner hypothesis is not an artefact #
exists_closedPolygon_arcs requires the two cut points to be corners.
ClosedPolygon.isCornerAt_vertex shows that this cannot be dropped: every vertex of every
realization is a corner, so a cut point at which the curve runs straight is a vertex of no
realization, and no ClosedPolygon with that carrier has an arc ending there. A consumer that
needs to cut at a straight point has to change the curve — bend it there — which is a different
theorem, and is exactly the freedom Graph.IsK33Config.not_isDrawing reserves for itself.
Polygons before normalization #
PrePolygon is ClosedPolygon with the corner field removed. Everything the curve bridge of
Schoenflies/PolygonBridge.lean proves about a ClosedPolygon — that its carrier is a Jordan
curve, that it is polygonal — uses only vertex_inj and edges_meet, so it is already true
here; what corner buys is the germ argument of the strip lemma, and nothing else.
A simple closed polygonal curve presented by its cyclic vertex list, with redundant
vertices allowed: ClosedPolygon less its corner field.
The vertices, in cyclic order.
- vertex_inj : Function.Injective self.vertex
The vertices are distinct.
- edges_meet (i j : ZMod (m + 3)) : i ≠ j → segment ℝ (self.vertex i) (self.vertex (i + 1)) ∩ segment ℝ (self.vertex j) (self.vertex (j + 1)) ⊆ {self.vertex i, self.vertex (i + 1)}
Simplicity: an edge meets any other edge only at one of its own endpoints.
Instances For
A ClosedPolygon read as a PrePolygon: forget the corner field.
Instances For
Small facts about the cyclic index #
ZMod (m + 3) has at least three elements; 0, 1 and 2 are distinct, which is what makes
a vertex, its successor and its predecessor three different vertices.
Rotation #
Reading the same cyclic list from a different starting vertex. It is used once, to bring the vertex that is about to be deleted to the end of the list.
The same closed polygon, read from vertex a onwards.
Equations
Instances For
Rotating does not move the curve: the edges are the same, listed from elsewhere.
Deleting the last vertex #
The blueprint's opening move in the strip lemma. The vertex to be deleted is brought to the end
of the list by rotate, so only that one case has to be treated. emb is the inclusion of the
shortened index set into the old one: the same numeral, one modulus smaller.
The vertex list with its last entry dropped.
Equations
- P.dropVertex j = P.vertex (Schoenflies.PrePolygon.emb j)
Instances For
Away from the deleted vertex the edges are unchanged.
The final edge of the shortened list is the union of the two edges at the deleted vertex — which is a segment precisely because the deleted vertex is interior to it.
The deleted vertex lies on no edge but its own two: edges_meet puts a meeting point at an
end of the other edge, and the deleted vertex is an end only of the two edges at it.
Simplicity survives the deletion. The only new edge is the merged one, and the point that has to be kept out of it — the deleted vertex — lies on no other edge at all.
The polygon with a redundant vertex deleted.
Equations
- P.deleteLast hcol = { vertex := P.dropVertex, vertex_inj := ⋯, edges_meet := ⋯ }
Instances For
Deleting a redundant vertex does not move the curve.
Recognising a redundant vertex #
The corner field is det ≠ 0 at every vertex. Where it fails the vertex is interior to the
segment joining its two neighbours, never an endpoint of it. That is the geometric content of
edges_meet: two edges leaving a vertex in the same direction would overlap in a
nondegenerate segment, and edges_meet would then put a whole segment inside a two-point
set.
Three collinear points meeting only at the shared one are in the order that makes the
middle one interior. The alternative — the two segments running the same way out of b —
makes them overlap in a nondegenerate segment, which the meeting hypothesis forbids.
Normalization #
Delete redundant vertices until none is left. Each deletion shortens the list by one, and the
list can never shrink below three vertices: a triangle with a redundant vertex would have one
edge inside another, which edges_meet forbids.
A three-vertex polygon has no redundant vertex: were the last one interior to the segment joining the other two, the edge before it would lie inside the edge opposite it.
Every PrePolygon normalizes to a ClosedPolygon with the same carrier. This is the
blueprint's "delete redundant vertices at which two consecutive edges are collinear", run to
completion; the induction is on the number of vertices, which each deletion lowers by one.
Assembling a cyclic vertex family into a PrePolygon. The index type is ZMod n for an
n known only to be at least three, which is what PrePolygon asks for after n is written
m + 3.
Clean pieces #
The overlay of Schoenflies/OverlayGraph.lean, stripped of the graph. All that is wanted from
it is a finite list of segments occupying the curve whose interiors are pairwise disjoint and
none of whose ends is interior to any of them — the geometric content of lem:polygonal-overlay
with the combinatorics left out.
A finite list of segments presenting a polygonal set as a plane graph would: occupying it, nondegenerate, with pairwise disjoint interiors, and with no end interior to any piece.
The pieces occupy the set.
No piece is a point.
No end of any piece is interior to any piece.
Distinct pieces have disjoint interiors.
Instances For
Every polygonal set with two points in it has a clean presentation, and any finite list
of points of it may be required to be among the ends. Lengthening the cut list is free: both
EndsAreCut and MeetsAreCut only ask that certain points occur in it.
The open set that isolates one piece from the others: the union of the balls in which the curve is that piece alone.
Equations
- Schoenflies.nearPiece C R = {y : Schoenflies.Plane | ∃ x ∈ R.interior, ∃ r > 0, y ∈ Metric.ball x r ∧ Metric.ball x r ∩ C ⊆ R.seg}
Instances For
Near an interior point the curve is that piece alone. The other pieces are finitely many closed sets missing the point: interior points are not shared, and an end of another piece cannot be interior to this one.
A connected piece of the curve away from the ends lies inside a single piece. The
nearPiece sets are honest open sets of the plane that trace out the pieces on the curve, so
IsPreconnected can be applied to them directly.
The gaps between the parameters #
The loop's parameters at which it visits an end of a piece form a finite subset of [0, 1)
containing 0. Listed in increasing order they cut [0, 1) into gaps, one per piece; the last
gap runs to 1, where the loop closes. This section is pure order theory on ℝ.
The i-th parameter, in increasing order.
Equations
- Schoenflies.par T hcard i = (T.orderEmbOfFin hcard) i
Instances For
From a clean presentation to a cyclic vertex list #
The loop reaches an end of a piece at finitely many parameters. Between two consecutive ones it
runs through one whole piece interior — the gap image is connected and misses the ends, so it
lies in one interior; and the interior, being connected and covered by the closed gap images,
lies in that one gap. So the ends, listed in the order the loop reaches them, are the cyclic
vertex list of a PrePolygon whose edges are the pieces.
A connected set in a finite relatively closed partition lies in the member it meets. This is shared by the arc and closed-curve realization arguments.
A polygonal Jordan curve is the carrier of a cyclic vertex list.
The realization theorem #
Every simple closed polygonal curve is the carrier of a ClosedPolygon. This is the
blueprint's set-level notion — IsJordanCurve together with IsPolygonal, no condition on
vertices — matched with the presentation the development works with.
Corners #
A realization cannot put a vertex wherever it likes: corner forbids a vertex at which the
curve runs straight through. The points that must be vertices are exactly the ones at which
it does not, and this is what a consumer needing a named point to be a vertex has to check.
C runs straight through p when, near p, it lies inside a segment having p in its
interior.
Equations
- Schoenflies.IsStraightAt C p = ∃ (a : Schoenflies.Plane) (b : Schoenflies.Plane), p ∈ openSegment ℝ a b ∧ ∃ r > 0, Metric.ball p r ∩ C ⊆ segment ℝ a b
Instances For
A corner of C: a point of it at which it does not run straight.
Equations
- Schoenflies.IsCornerAt C p = (p ∈ C ∧ ¬Schoenflies.IsStraightAt C p)
Instances For
Every corner is a vertex. A point interior to an edge lies on no other edge, so a small ball meets the curve only in that edge — and then the curve runs straight through it.
Every vertex is a corner. With ClosedPolygon.exists_vertex_eq_of_isCornerAt this says
that the vertex set of a realization is exactly the corner set of the curve — so any two
realizations of one curve have the same vertices, and a point can be required to be a vertex
precisely when it is a corner.
The realization theorem, with named corners. Any finite list of corners of the curve can
be required to be among the vertices — and by ClosedPolygon.exists_vertex_eq_of_isCornerAt,
being a corner is exactly what a point must be for that to be possible.
The realization theorem, tracking a splitting. Two distinct corners of the curve become
two vertices a and a + k of the realization, which is what names the two arcs
P.arc a k and P.arc (a + k) (m + 3 - k) that they cut it into.
The corner hypothesis is not an artefact: ClosedPolygon.corner forbids a vertex where the
curve runs straight through, so a splitting point that is not a corner cannot be a vertex of
any realization.
The two arcs of a splitting #
ClosedPolygon.arc a k and ClosedPolygon.arc (a + k) (m + 3 - k) are what a consumer tracking
a decomposition of the curve has to be handed. This section says what they are: two arcs between
the two cut vertices, covering the curve and meeting exactly there.
The same closed polygon, read from vertex a onwards.
Equations
Instances For
An arc of a splitting is an arc between the two cut vertices.
The two arcs of a splitting meet exactly at the two cut vertices. A point on both lies
on an edge of each; edges_meet, read in both directions, puts it at a vertex shared by the two
edges, and the only shared vertices are the two ends of the split.
The two-arc decomposition is unique #
Two points cut a Jordan curve into two arcs, and only into those two: the interior of any arc of the curve between them is connected and misses both, so it lies on one side of any other such splitting. Without this a realization could name two arcs and still not be known to name the two arcs a consumer started from.
The interior of an arc — the arc less its two endpoints — is connected and nonempty. The
paired form the uniqueness argument below destructures; both halves are in
Schoenflies/Subarc.lean, which is where the shared set identity A ∖ {p, q} = f '' Ioo 0 1
lives.
The two arcs a pair of points cuts a curve into are determined.
The realization theorem, tracking a splitting. A polygonal Jordan curve decomposed into
two arcs meeting at two of its corners is the carrier of a ClosedPolygon whose two arcs at the
corresponding vertices are those two arcs.
This is the form the plane-graph layer wants — compare Graph.IsHexRealization. The corner
hypothesis on the two cut points is not an artefact of the proof:
ClosedPolygon.isCornerAt_vertex says every vertex of a realization is a corner, so a cut point
that is not one cannot be a vertex of any realization at all.
The realization theorem, with the two arcs in the order they were given. The same as
Schoenflies.exists_closedPolygon_arcs with the disjunction moved off the arcs and onto the two
cut vertices: reading the polygon from the other cut point exchanges the two arcs, so exactly
one of the two starting vertices makes P.arc a k the first arc. This is the shape
Graph.IsHexRealization asks for.