@@ -4,18 +4,17 @@ Released under Apache 2.0 license as described in the file LICENSE.
44Authors: Joseph Myers
55-/
66import Mathlib.Geometry.Euclidean.Projection
7- import Mathlib.LinearAlgebra.AffineSpace.ContinuousAffineEquiv
8- import Mathlib.LinearAlgebra.AffineSpace.FiniteDimensional
9- import Mathlib.Topology.Algebra.AffineSubspace
107
118/-!
129# Signed distance to an affine subspace in a Euclidean space.
1310
14- This file defines the signed distance between an affine subspace and a point, in the direction
15- of a given reference point.
11+ This file defines the signed distance between two points, in the direction of a given a vector, and
12+ the signed distance between an affine subspace and a point, in the direction of a given
13+ reference point.
1614
1715## Main definitions
1816
17+ * `signedDist` is the signed distance between two points
1918* `AffineSubspace.signedInfDist` is the signed distance between an affine subspace and a point.
2019* `Affine.Simplex.signedInfDist` is the signed distance between a face of a simplex and a point.
2120 In the case of a triangle, these distances are trilinear coordinates.
@@ -33,48 +32,222 @@ open scoped RealInnerProductSpace
3332variable {V P : Type *} [NormedAddCommGroup V] [InnerProductSpace ℝ V] [MetricSpace P]
3433variable [NormedAddTorsor V P]
3534
35+ section signedDist
36+
37+ /-- Auxiliary definition for `signedDist`. It is the underlying linear map of `signedDist`. -/
38+ private noncomputable def signedDistLinear (v : V) : V →ₗ[ℝ] P →ᴬ[ℝ] ℝ where
39+ toFun w := .const ℝ P ⟪-(‖v‖⁻¹ • v), w⟫
40+ map_add' x y := by ext; simp [inner_add_right]
41+ map_smul' r x := by ext; simp [inner_smul_right]
42+
43+ private lemma signedDistLinear_apply (v w : V) :
44+ signedDistLinear v w = .const ℝ P ⟪-(‖v‖⁻¹ • v), w⟫ := rfl
45+
46+ /--
47+ The signed distance between two points `p` and `q`, in the direction of a reference vector `v`.
48+ It is the size of `q - p` in the direction of `v`.
49+ In the degenerate case `v = 0`, it returns `0`.
50+
51+ TODO: once we have a topology on `P →ᴬ[ℝ] ℝ`, the type should be `P →ᴬ[ℝ] P →ᴬ[ℝ] ℝ`.
52+ -/
53+ noncomputable def signedDist (v : V) : P →ᵃ[ℝ] P →ᴬ[ℝ] ℝ where
54+ toFun p := (innerSL ℝ (‖v‖⁻¹ • v)).toContinuousAffineMap.comp
55+ (ContinuousAffineMap.id ℝ P -ᵥ .const ℝ P p)
56+ linear := signedDistLinear v
57+ map_vadd' p v' := by
58+ ext q
59+ rw [signedDistLinear_apply]
60+ generalize ‖v‖⁻¹ • v = x
61+ simp [vsub_vadd_eq_vsub_sub, inner_sub_right, ← sub_eq_neg_add]
62+
63+ variable (v w : V) (p q r : P)
64+
65+ -- Lemmas about the definition of `signedDist`
66+
67+ lemma signedDist_apply : signedDist v p = (innerSL ℝ (‖v‖⁻¹ • v)).toContinuousAffineMap.comp
68+ (ContinuousAffineMap.id ℝ P -ᵥ .const ℝ P p) :=
69+ rfl
70+
71+ lemma signedDist_apply_apply : signedDist v p q = ⟪‖v‖⁻¹ • v, q -ᵥ p⟫ :=
72+ rfl
73+
74+ lemma signedDist_apply_linear : (signedDist v p).linear = innerₗ V (‖v‖⁻¹ • v) := by
75+ change (innerₗ V (‖v‖⁻¹ • v)).comp (LinearMap.id - 0 ) = _
76+ simp
77+
78+ lemma signedDist_apply_linear_apply : (signedDist v p).linear w = ⟪‖v‖⁻¹ • v, w⟫ := by
79+ simp [signedDist_apply_linear, real_inner_smul_left]
80+
81+ lemma signedDist_linear_apply : (signedDist v).linear w = .const ℝ P ⟪-(‖v‖⁻¹ • v), w⟫ :=
82+ rfl
83+
84+ lemma signedDist_linear_apply_apply : (signedDist v).linear w p = ⟪-(‖v‖⁻¹ • v), w⟫ :=
85+ rfl
86+
87+ -- Lemmas about the vector argument of `signedDist`
88+
89+ lemma signedDist_smul (r : ℝ) : signedDist (r • v) p q = SignType.sign r * signedDist v p q := by
90+ simp only [signedDist_apply_apply]
91+ rw [norm_smul, mul_inv_rev, smul_smul, mul_rotate, ← smul_smul, real_inner_smul_left]
92+ congr
93+ by_cases h : r = 0
94+ · simp [h]
95+ · rw [inv_mul_eq_iff_eq_mul₀ (by positivity)]
96+ simp only [Real.norm_eq_abs, abs_mul_sign]
97+
98+ @[simp] lemma signedDist_zero : signedDist 0 p q = 0 := by
99+ simpa using signedDist_smul 0 p q 0
100+
101+ @[simp] lemma signedDist_neg : signedDist (-v) p q = -signedDist v p q := by
102+ simpa using signedDist_smul v p q (-1 )
103+
104+ lemma signedDist_congr (h : ∃ r > (0 : ℝ), r • v = w) : signedDist (P := P) v = signedDist w := by
105+ obtain ⟨r, _, _⟩ := h
106+ ext p q
107+ simpa [*] using (signedDist_smul v p q r).symm
108+
109+ -- Lemmas about permuting the point arguments of `signedDist`, analogous to lemmas about `dist`
110+
111+ @[simp] lemma signedDist_self : signedDist v p p = 0 := by
112+ simp [signedDist_apply_apply]
113+
114+ @[simp] lemma signedDist_anticomm : -signedDist v p q = signedDist v q p := by
115+ simp [signedDist_apply_apply, ← inner_neg_right]
116+
117+ @[simp]
118+ lemma signedDist_triangle : signedDist v p q + signedDist v q r = signedDist v p r := by
119+ simp only [signedDist_apply_apply]
120+ rw [add_comm, ← inner_add_right, vsub_add_vsub_cancel]
121+
122+ @[simp]
123+ lemma signedDist_triangle_left : signedDist v p q - signedDist v p r = signedDist v r q := by
124+ rw [sub_eq_iff_eq_add', signedDist_triangle]
125+
126+ @[simp]
127+ lemma signedDist_triangle_right : signedDist v p r - signedDist v q r = signedDist v p q := by
128+ rw [sub_eq_iff_eq_add, signedDist_triangle]
129+
130+ -- Lemmas about offsetting the point arguments of `signedDist` (with `+ᵥ` or `-ᵥ`)
131+
132+ lemma signedDist_vadd_left : signedDist v (w +ᵥ p) q = -⟪‖v‖⁻¹ • v, w⟫ + signedDist v p q := by
133+ simp [signedDist_linear_apply_apply]
134+
135+ lemma signedDist_vadd_right : signedDist v p (w +ᵥ q) = ⟪‖v‖⁻¹ • v, w⟫ + signedDist v p q := by
136+ simp [signedDist_apply_linear_apply]
137+
138+ -- TODO: find a better name for these 2 lemmas
139+ lemma signedDist_vadd_left_swap : signedDist v (w +ᵥ p) q = signedDist v p (-w +ᵥ q) := by
140+ rw [signedDist_vadd_left, signedDist_vadd_right, inner_neg_right]
141+
142+ lemma signedDist_vadd_right_swap : signedDist v p (w +ᵥ q) = signedDist v (-w +ᵥ p) q := by
143+ rw [signedDist_vadd_left_swap, neg_neg]
144+
145+ lemma signedDist_vadd_vadd : signedDist v (w +ᵥ p) (w +ᵥ q) = signedDist v p q := by
146+ rw [signedDist_vadd_left_swap, neg_vadd_vadd]
147+
148+ variable {v p q} in
149+ lemma signedDist_left_congr (h : ⟪v, p -ᵥ q⟫ = 0 ) : signedDist v p = signedDist v q := by
150+ ext r
151+ simpa [real_inner_smul_left, h] using signedDist_vadd_left v (p -ᵥ q) q r
152+
153+ variable {v q r} in
154+ lemma signedDist_right_congr (h : ⟪v, q -ᵥ r⟫ = 0 ) : signedDist v p q = signedDist v p r := by
155+ simpa [real_inner_smul_left, h] using signedDist_vadd_right v (q -ᵥ r) p r
156+
157+ variable {v p q} in
158+ lemma signedDist_eq_zero_of_orthogonal (h : ⟪v, q -ᵥ p⟫ = 0 ) : signedDist v p q = 0 := by
159+ simpa using signedDist_right_congr p h
160+
161+ -- Lemmas relating `signedDist` to `dist`
162+
163+ lemma abs_signedDist_le_dist : |signedDist v p q| ≤ dist p q := by
164+ rw [signedDist_apply_apply]
165+ by_cases h : v = 0
166+ · simp [h]
167+ · convert abs_real_inner_le_norm (‖v‖⁻¹ • v) (q -ᵥ p)
168+ simp [norm_smul, dist_eq_norm_vsub']
169+ field_simp
170+
171+ lemma signedDist_le_dist : signedDist v p q ≤ dist p q :=
172+ le_trans (le_abs_self _) (abs_signedDist_le_dist _ _ _)
173+
174+ lemma abs_signedDist_eq_dist_iff_vsub_mem_span :
175+ |signedDist v p q| = dist p q ↔ q -ᵥ p ∈ ℝ ∙ v := by
176+ rw [Submodule.mem_span_singleton]
177+ rw [signedDist_apply_apply, dist_eq_norm_vsub', real_inner_smul_left, abs_mul, abs_inv, abs_norm]
178+ by_cases h : v = 0
179+ · simp [h, eq_comm (a := (0 : ℝ)), eq_comm (a := (0 : V))]
180+ rw [inv_mul_eq_iff_eq_mul₀ (by positivity)]
181+ rw [← Real.norm_eq_abs, ((norm_inner_eq_norm_tfae ℝ v (q -ᵥ p)).out 0 2 :)]
182+ simp [h, eq_comm]
183+
184+ open NNReal in
185+ lemma signedDist_eq_dist_iff_vsub_mem_span : signedDist v p q = dist p q ↔ q -ᵥ p ∈ ℝ≥0 ∙ v := by
186+ rw [Submodule.mem_span_singleton]
187+ rw [signedDist_apply_apply, dist_eq_norm_vsub', real_inner_smul_left]
188+ by_cases h : v = 0
189+ · simp [h, eq_comm (a := (0 : ℝ)), eq_comm (a := (0 : V))]
190+ rw [inv_mul_eq_iff_eq_mul₀ (by positivity)]
191+ rw [inner_eq_norm_mul_iff_real]
192+ simp only [smul_def]
193+ refine ⟨fun h => ?_, fun ⟨c, h⟩ => ?_⟩
194+ · simp only [NNReal.exists, coe_mk, exists_prop]
195+ use ‖v‖⁻¹ * ‖q -ᵥ p‖
196+ constructor
197+ · positivity
198+ · rw [← smul_smul, h, smul_smul, inv_mul_cancel₀ (by positivity), one_smul]
199+ · rw [← h, norm_smul, smul_smul, mul_comm]
200+ simp
201+
202+ @[simp] lemma signedDist_vsub_self : signedDist (q -ᵥ p) p q = dist p q := by
203+ rw [signedDist_eq_dist_iff_vsub_mem_span]
204+ apply Submodule.mem_span_singleton_self
205+
206+ @[simp] lemma signedDist_vsub_self_rev : signedDist (p -ᵥ q) p q = -dist p q := by
207+ rw [← neg_eq_iff_eq_neg, ← signedDist_neg, neg_vsub_eq_vsub_rev]
208+ apply signedDist_vsub_self
209+
210+ end signedDist
211+
36212namespace AffineSubspace
37213
38- variable (s : AffineSubspace ℝ P) [Nonempty s] [s.direction.HasOrthogonalProjection] (p : P)
214+ variable (s : AffineSubspace ℝ P) [Nonempty s] [s.direction.HasOrthogonalProjection] (p q : P)
39215
40216/-- The signed distance between `s` and a point, in the direction of the reference point `p`.
41217This is expected to be used when `p` does not lie in `s` (in the degenerate case where `p` lies
42218in `s`, this yields 0) and when the point at which the distance is evaluated lies in the affine
43219span of `s` and `p` (any component of the distance orthogonal to that span is disregarded). -/
44220noncomputable def signedInfDist : P →ᴬ[ℝ] ℝ :=
45- (innerSL ℝ (‖p -ᵥ orthogonalProjection s p‖⁻¹ •
46- (p -ᵥ orthogonalProjection s p))).toContinuousAffineMap.comp
47- ((ContinuousAffineEquiv.refl ℝ P).toContinuousAffineMap -ᵥ
48- s.subtypeA.comp (orthogonalProjection s))
49-
50- lemma signedInfDist_apply (x : P) :
51- s.signedInfDist p x = ⟪‖p -ᵥ orthogonalProjection s p‖⁻¹ • (p -ᵥ orthogonalProjection s p),
52- x -ᵥ orthogonalProjection s x⟫ :=
53- rfl
221+ signedDist (p -ᵥ orthogonalProjection s p) (Classical.ofNonempty : s)
54222
55- lemma signedInfDist_linear : (s.signedInfDist p).linear =
56- (innerₗ V (‖p -ᵥ orthogonalProjection s p‖⁻¹ • (p -ᵥ orthogonalProjection s p))).comp
57- (LinearMap.id (R := ℝ) (M := V) -
58- s.direction.subtype.comp s.direction.orthogonalProjection.toLinearMap) :=
223+ lemma signedInfDist_def :
224+ s.signedInfDist p = signedDist (p -ᵥ orthogonalProjection s p) ↑(Classical.ofNonempty : s) :=
59225 rfl
60226
61- lemma signedInfDist_linear_apply (v : V) : (s.signedInfDist p).linear v =
62- ⟪‖p -ᵥ orthogonalProjection s p‖⁻¹ • (p -ᵥ orthogonalProjection s p),
63- v - s.direction.orthogonalProjection v⟫ :=
64- rfl
227+ variable {s p q} in
228+ lemma signedInfDist_eq_signedDist_of_mem (h : q ∈ s) :
229+ s.signedInfDist p = signedDist (p -ᵥ orthogonalProjection s p) q := by
230+ apply signedDist_left_congr
231+ apply s.direction.inner_left_of_mem_orthogonal
232+ · exact vsub_mem_direction (SetLike.coe_mem _) h
233+ · exact vsub_orthogonalProjection_mem_direction_orthogonal s p
234+
235+ lemma signedInfDist_eq_signedDist_orthogonalProjection {x : P} : s.signedInfDist p x =
236+ signedDist (p -ᵥ orthogonalProjection s p) ↑(orthogonalProjection s x) x := by
237+ rw [signedInfDist_eq_signedDist_of_mem (orthogonalProjection_mem x)]
65238
66239@[simp] lemma signedInfDist_apply_self : s.signedInfDist p p = ‖p -ᵥ orthogonalProjection s p‖ := by
67- simp [signedInfDist_apply, inner_smul_left, real_inner_self_eq_norm_sq, pow_two, ← mul_assoc ]
240+ rw [signedInfDist_eq_signedDist_orthogonalProjection, signedDist_vsub_self, dist_eq_norm_vsub' ]
68241
69242variable {s} in
70243@[simp] lemma signedInfDist_apply_of_mem {x : P} (hx : x ∈ s) : s.signedInfDist p x = 0 := by
71- simp [signedInfDist_apply , orthogonalProjection_eq_self_iff.2 hx]
244+ simp [signedInfDist_eq_signedDist_orthogonalProjection , orthogonalProjection_eq_self_iff.2 hx]
72245
73246variable {s p} in
74247@[simp] lemma signedInfDist_eq_const_of_mem (h : p ∈ s) :
75248 s.signedInfDist p = AffineMap.const ℝ P (0 : ℝ) := by
76249 ext x
77- simp [signedInfDist_apply , orthogonalProjection_eq_self_iff.2 h]
250+ simp [signedInfDist_def , orthogonalProjection_eq_self_iff.2 h]
78251
79252variable {s p} in
80253lemma abs_signedInfDist_eq_dist_of_mem_affineSpan_insert {x : P}
@@ -85,6 +258,10 @@ lemma abs_signedInfDist_eq_dist_of_mem_affineSpan_insert {x : P}
85258 simp [hp₀, dist_eq_norm_vsub, orthogonalProjection_eq_self_iff.2 hp₀,
86259 orthogonalProjection_vsub_orthogonalProjection, norm_smul, abs_mul]
87260
261+ lemma signedInfDist_singleton :
262+ (affineSpan ℝ ({q} : Set P)).signedInfDist p = signedDist (p -ᵥ q) q := by
263+ simpa using signedInfDist_eq_signedDist_of_mem (mem_affineSpan ℝ (Set.mem_singleton q))
264+
88265end AffineSubspace
89266
90267namespace Affine
0 commit comments