From 40e097ae1f049f4a7a28380da77d06aa8f741af0 Mon Sep 17 00:00:00 2001 From: ivankokan Date: Wed, 6 May 2020 02:45:55 +0200 Subject: [PATCH 01/23] Change prototype of inversion inversion(circle c1, circle c2, real sgn = 1) --- base/geometry.asy | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/base/geometry.asy b/base/geometry.asy index 1c8a95063..accf7e319 100644 --- a/base/geometry.asy +++ b/base/geometry.asy @@ -6358,9 +6358,9 @@ inversion inversion(point C, real k) return inversion(k, C); } -/**/ -inversion inversion(circle c1, circle c2, real sgn = 1) -{/*Return the inversion which transforms 'c1' to +/**/ +inversion[] inversion(circle c1, circle c2, real sgn = 1) +{/*Return the inversions which transform 'c1' to . 'c2' and positive inversion radius if 'sgn > 0'; . 'c2' and negative inversion radius if 'sgn < 0'; . 'c1' and 'c2' to 'c2' if 'sgn = 0'.*/ From 635e25ab00ed36f846b14c6ae87fb56ce3310ccf Mon Sep 17 00:00:00 2001 From: ivankokan Date: Wed, 6 May 2020 02:48:49 +0200 Subject: [PATCH 02/23] Minor edit: inversion(circle c1, circle c2, circle c3) transforms --- base/geometry.asy | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/base/geometry.asy b/base/geometry.asy index accf7e319..bd4534580 100644 --- a/base/geometry.asy +++ b/base/geometry.asy @@ -6379,7 +6379,7 @@ inversion[] inversion(circle c1, circle c2, real sgn = 1) /**/ inversion inversion(circle c1, circle c2, circle c3) -{/*Return the inversion which transform 'c1' to 'c1', 'c2' to 'c2' and 'c3' to 'c3'.*/ +{/*Return the inversion which transforms 'c1' to 'c1', 'c2' to 'c2' and 'c3' to 'c3'.*/ point Rc = radicalcenter(c1, c2, c3); return inversion(Rc, Rc^c1); } From 0c6f9d03db7daa8abeb811788b24ba29b1dd59a3 Mon Sep 17 00:00:00 2001 From: ivankokan Date: Wed, 6 May 2020 03:00:12 +0200 Subject: [PATCH 03/23] Add missing optional real argument to signature --- base/geometry.asy | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/base/geometry.asy b/base/geometry.asy index bd4534580..4efdb7b40 100644 --- a/base/geometry.asy +++ b/base/geometry.asy @@ -6358,7 +6358,7 @@ inversion inversion(point C, real k) return inversion(k, C); } -/**/ +/**/ inversion[] inversion(circle c1, circle c2, real sgn = 1) {/*Return the inversions which transform 'c1' to . 'c2' and positive inversion radius if 'sgn > 0'; From b07288910c4a1aae640a70b4ba022f2b492904ee Mon Sep 17 00:00:00 2001 From: ivankokan Date: Wed, 6 May 2020 03:46:44 +0200 Subject: [PATCH 04/23] Abort radicalcenter(circle,circle) for concentric circles (so as in radicalline(circle,circle)) --- base/geometry.asy | 1 + 1 file changed, 1 insertion(+) diff --git a/base/geometry.asy b/base/geometry.asy index 4efdb7b40..6ef40b7c3 100644 --- a/base/geometry.asy +++ b/base/geometry.asy @@ -6313,6 +6313,7 @@ point inverse(real k, point A, point M) /**/ point radicalcenter(circle c1, circle c2) {/**/ + if (c1.C == c2.C) abort("radicalcenter: the centers must be distinct"); point[] P = standardizecoordsys(c1.C, c2.C); real k = c1.r^2 - c2.r^2; pair C1 = locate(c1.C); From ce7947f5cd98c5237039a769fe5110b6d5cc7d17 Mon Sep 17 00:00:00 2001 From: ivankokan Date: Wed, 6 May 2020 04:06:13 +0200 Subject: [PATCH 05/23] Remove invalid check within radicalcenter(circle,circle) --- base/geometry.asy | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/base/geometry.asy b/base/geometry.asy index 6ef40b7c3..78fbf9a05 100644 --- a/base/geometry.asy +++ b/base/geometry.asy @@ -6319,9 +6319,7 @@ point radicalcenter(circle c1, circle c2) pair C1 = locate(c1.C); pair C2 = locate(c2.C); pair oop = C2 - C1; - pair K = (abs(oop) == 0) ? - (infinity, infinity) : - midpoint(C1--C2) + 0.5 * k * oop/dot(oop, oop); + pair K = midpoint(C1--C2) + 0.5 * k * oop/dot(oop, oop); return point(P[0].coordsys, K/P[0].coordsys); } From 3f8006dcd5743e1c0f0ed6114fb55e34008db132 Mon Sep 17 00:00:00 2001 From: ivankokan Date: Wed, 6 May 2020 04:39:30 +0200 Subject: [PATCH 06/23] Prettify radicalcenter(circle,circle) --- base/geometry.asy | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/base/geometry.asy b/base/geometry.asy index 78fbf9a05..07b0b235d 100644 --- a/base/geometry.asy +++ b/base/geometry.asy @@ -6315,12 +6315,13 @@ point radicalcenter(circle c1, circle c2) {/**/ if (c1.C == c2.C) abort("radicalcenter: the centers must be distinct"); point[] P = standardizecoordsys(c1.C, c2.C); - real k = c1.r^2 - c2.r^2; + coordsys R = P[0].coordsys; pair C1 = locate(c1.C); pair C2 = locate(c2.C); + real k = c1.r^2 - c2.r^2; pair oop = C2 - C1; - pair K = midpoint(C1--C2) + 0.5 * k * oop/dot(oop, oop); - return point(P[0].coordsys, K/P[0].coordsys); + pair K = (C1 + C2)/2 + k/2 * oop/dot(oop, oop); + return point(R, K/R); } /**/ From e7907c3de4e647b7cb2bc4d517867a54e719f289 Mon Sep 17 00:00:00 2001 From: ivankokan Date: Fri, 8 May 2020 01:41:19 +0200 Subject: [PATCH 07/23] Revisit and refactor all inverse functions and corresponding operators --- base/geometry.asy | 68 ++++++++++++++++++++++++----------------------- 1 file changed, 35 insertions(+), 33 deletions(-) diff --git a/base/geometry.asy b/base/geometry.asy index 07b0b235d..6cc58ab21 100644 --- a/base/geometry.asy +++ b/base/geometry.asy @@ -6304,10 +6304,10 @@ void dot(picture pic = currentpicture, triangle t, pen p = currentpen) // *=======================================================* // *.......................INVERSIONS......................* -/**/ -point inverse(real k, point A, point M) -{/*Return the inverse point of 'M' with respect to point A and inversion radius 'k'.*/ - return A + k/conj(M - A); +/**/ +point inverse(real k, point C, point P) +{/*Return the inverse point of 'P' with respect to point 'C' and inversion power 'k'.*/ + return C + k/conj(P - C); } /**/ @@ -6401,7 +6401,7 @@ inversion inversion(circle c) return c; } -/**/ +/**/ point operator *(inversion i, point P) {/*Provide inversion * point.*/ return inverse(i.k, i.C, P); @@ -6415,43 +6415,45 @@ The returned circle has an infinite radius, circle.l has been set."); /**/ -circle inverse(real k, point A, line l) +circle inverse(real k, point C, line l) {/*Return the inverse circle of 'l' with - respect to point 'A' and inversion radius 'k'.*/ - if(A @ l) { + respect to point 'C' and inversion power 'k'.*/ + if(C @ l) { lineinversion(); - circle C = circle(A, infinity); - C.l = l; - return C; + circle c = circle(C, infinity); + c.l = l; + return c; } - point Ap = inverse(k, A, l.A), Bp = inverse(k, A, l.B); - return circle(A, Ap, Bp); + point A = inverse(k, C, l.A); + point B = inverse(k, C, l.B); + return circle(C, A, B); } -/**/ +/**/ circle operator *(inversion i, line l) {/*Provide inversion * line for lines that don't pass through the inversion center.*/ return inverse(i.k, i.C, l); } /**/ -circle inverse(real k, point A, circle c) +circle inverse(real k, point C, circle c) {/*Return the inverse circle of 'c' with - respect to point A and inversion radius 'k'.*/ - if(degenerate(c)) return inverse(k, A, c.l); - if(A @ c) { + respect to point 'C' and inversion power 'k'.*/ + if(degenerate(c)) return inverse(k, C, c.l); + if(C @ c) { lineinversion(); - point M = rotate(180, c.C) * A, Mp = rotate(90, c.C) * A; - circle oc = circle(A, infinity); - oc.l = line(inverse(k, A, M), inverse(k, A, Mp)); + circle oc = circle(C, infinity); + point A = rotate(+90, c.C) * C; + point B = rotate(-90, c.C) * C; + oc.l = line(inverse(k, C, A), inverse(k, C, B)); return oc; } - point[] P = standardizecoordsys(A, c.C); + point[] P = standardizecoordsys(C, c.C); real s = k/((P[1].x - P[0].x)^2 + (P[1].y - P[0].y)^2 - c.r^2); - return circle(P[0] + s * (P[1]-P[0]), abs(s) * c.r); + return circle(P[0] + s * (P[1] - P[0]), abs(s) * c.r); } -/**/ +/**/ circle operator *(inversion i, circle c) {/*Provide inversion * circle.*/ return inverse(i.k, i.C, c); @@ -7102,18 +7104,18 @@ arc arc(explicit arc a, point M, point N) } /**/ -arc inverse(real k, point A, segment s) -{/*Return the inverse arc circle of 's' - with respect to point A and inversion radius 'k'.*/ - point Ap = inverse(k, A, s.A), Bp = inverse(k, A, s.B), - M = inverse(k, A, midpoint(s)); - return arccircle(Ap, M, Bp); +arc inverse(real k, point C, segment s) +{/*Return the inverse arc circle of 's' with + respect to point 'C' and inversion power 'k'.*/ + point A = inverse(k, C, s.A); + point B = inverse(k, C, s.B); + point M = inverse(k, C, midpoint(s)); + return arccircle(A, M, B); } -/**/ +/**/ arc operator *(inversion i, segment s) -{/*Provide - inversion * segment.*/ +{/*Provide inversion * segment.*/ return inverse(i.k, i.C, s); } From ba13a5b5a161449f4f19bb0ee5704d78349a2d33 Mon Sep 17 00:00:00 2001 From: ivankokan Date: Fri, 8 May 2020 02:01:45 +0200 Subject: [PATCH 08/23] Align with inversion(circle,circle,real) and avoid redundant inversion call --- base/geometry.asy | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/base/geometry.asy b/base/geometry.asy index 6cc58ab21..49c2afc7c 100644 --- a/base/geometry.asy +++ b/base/geometry.asy @@ -6380,8 +6380,8 @@ inversion[] inversion(circle c1, circle c2, real sgn = 1) /**/ inversion inversion(circle c1, circle c2, circle c3) {/*Return the inversion which transforms 'c1' to 'c1', 'c2' to 'c2' and 'c3' to 'c3'.*/ - point Rc = radicalcenter(c1, c2, c3); - return inversion(Rc, Rc^c1); + point O = radicalcenter(c1, c2, c3); + return inversion(O^c1, O); } circle operator cast(inversion i){return circle(i.C, sgn(i.k) * sqrt(abs(i.k)));} From 7c3fef1777e439f111e5816a9339477f0cb536c0 Mon Sep 17 00:00:00 2001 From: ivankokan Date: Fri, 8 May 2020 02:22:55 +0200 Subject: [PATCH 09/23] Revisit struct inversion --- base/geometry.asy | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/base/geometry.asy b/base/geometry.asy index 49c2afc7c..cbadf64be 100644 --- a/base/geometry.asy +++ b/base/geometry.asy @@ -6339,22 +6339,23 @@ point radicalcenter(circle c1, circle c2, circle c3) /**/ struct inversion -{/*http://mathworld.wolfram.com/Inversion.html*/ - point C; +{/**/ real k; + point C; }/**/ /**/ inversion inversion(real k, point C) -{/*Return the inversion with respect to 'C' having inversion radius 'k'.*/ +{/*Return the inversion with respect to 'C' having inversion power 'k'.*/ inversion oi; oi.k = k; oi.C = C; return oi; } -/**/ + +/**/ inversion inversion(point C, real k) -{/*Return the inversion with respect to 'C' having inversion radius 'k'.*/ +{/*Return the inversion with respect to 'C' having inversion power 'k'.*/ return inversion(k, C); } From aed6e166342661cc697af169aabd8fe109194ed7 Mon Sep 17 00:00:00 2001 From: ivankokan Date: Fri, 8 May 2020 03:10:48 +0200 Subject: [PATCH 10/23] Change prototype of lineinversion function and consolidate its usage --- base/geometry.asy | 25 ++++++++----------------- 1 file changed, 8 insertions(+), 17 deletions(-) diff --git a/base/geometry.asy b/base/geometry.asy index cbadf64be..470906aa2 100644 --- a/base/geometry.asy +++ b/base/geometry.asy @@ -6408,23 +6408,21 @@ point operator *(inversion i, point P) return inverse(i.k, i.C, P); } -void lineinversion() +/**/ +circle lineinversion(point C, line l) { - warning("lineinversion", "the inversion of the line is not a circle. + circle oc = circle(C, infinity); + oc.l = l; + warning("lineinversion", "The inversion of the line is not a circle. The returned circle has an infinite radius, circle.l has been set."); + return oc; } - /**/ circle inverse(real k, point C, line l) {/*Return the inverse circle of 'l' with respect to point 'C' and inversion power 'k'.*/ - if(C @ l) { - lineinversion(); - circle c = circle(C, infinity); - c.l = l; - return c; - } + if(C @ l) return lineinversion(C, l); point A = inverse(k, C, l.A); point B = inverse(k, C, l.B); return circle(C, A, B); @@ -6441,14 +6439,7 @@ circle inverse(real k, point C, circle c) {/*Return the inverse circle of 'c' with respect to point 'C' and inversion power 'k'.*/ if(degenerate(c)) return inverse(k, C, c.l); - if(C @ c) { - lineinversion(); - circle oc = circle(C, infinity); - point A = rotate(+90, c.C) * C; - point B = rotate(-90, c.C) * C; - oc.l = line(inverse(k, C, A), inverse(k, C, B)); - return oc; - } + if(C @ c) return lineinversion(C, line(inverse(k, C, rotate(+90, c.C) * C), inverse(k, C, rotate(-90, c.C) * C))); point[] P = standardizecoordsys(C, c.C); real s = k/((P[1].x - P[0].x)^2 + (P[1].y - P[0].y)^2 - c.r^2); return circle(P[0] + s * (P[1] - P[0]), abs(s) * c.r); From 8f0b8898e5a1fe6e340fea5e0156e579a96205e9 Mon Sep 17 00:00:00 2001 From: ivankokan Date: Fri, 8 May 2020 03:33:26 +0200 Subject: [PATCH 11/23] Simplify power of a point operator ^(point,explicit circle) --- base/geometry.asy | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/base/geometry.asy b/base/geometry.asy index 470906aa2..bcb85e93b 100644 --- a/base/geometry.asy +++ b/base/geometry.asy @@ -3269,10 +3269,10 @@ circle operator -(explicit circle c, vector m) {/*Translation of 'c'.*/ return circle(c.C - m, c.r); } -/**/ +/**/ real operator ^(point M, explicit circle c) -{/*The power of 'M' with respect to the circle 'c'*/ - return xpart((abs(locate(M) - locate(c.C)), c.r)^2); +{/*The power of 'M' with respect to the circle 'c'.*/ + return abs(locate(M) - locate(c.C))^2 - c.r^2; } /**/ bool operator @(point M, explicit circle c) From 7a82751af20b0cf54e97fbc301ba4f5ecdd56a92 Mon Sep 17 00:00:00 2001 From: ivankokan Date: Fri, 8 May 2020 03:51:46 +0200 Subject: [PATCH 12/23] Edit: inversion radius -> inversion power --- base/geometry.asy | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/base/geometry.asy b/base/geometry.asy index bcb85e93b..fc8f2a2bf 100644 --- a/base/geometry.asy +++ b/base/geometry.asy @@ -6362,8 +6362,8 @@ inversion inversion(point C, real k) /**/ inversion[] inversion(circle c1, circle c2, real sgn = 1) {/*Return the inversions which transform 'c1' to - . 'c2' and positive inversion radius if 'sgn > 0'; - . 'c2' and negative inversion radius if 'sgn < 0'; + . 'c2' and positive inversion power if 'sgn > 0'; + . 'c2' and negative inversion power if 'sgn < 0'; . 'c1' and 'c2' to 'c2' if 'sgn = 0'.*/ if(sgn == 0) { point O = radicalcenter(c1, c2); From b22478ca7c91f38fc7efded382d255d60db4a943 Mon Sep 17 00:00:00 2001 From: ivankokan Date: Sat, 9 May 2020 23:19:13 +0200 Subject: [PATCH 13/23] Remove unused variable --- base/geometry.asy | 1 - 1 file changed, 1 deletion(-) diff --git a/base/geometry.asy b/base/geometry.asy index fc8f2a2bf..31b6c2a10 100644 --- a/base/geometry.asy +++ b/base/geometry.asy @@ -3164,7 +3164,6 @@ circle circle(explicit point C, real r) /**/ circle circle(point A, point B) {/*Return the circle of diameter AB.*/ - real r; circle oc; real a = abs(A), b = abs(B); if(finite(a) && finite(b)) { From b77998e47d37743af89c8d9b76090521df79236b Mon Sep 17 00:00:00 2001 From: ivankokan Date: Sat, 9 May 2020 23:59:52 +0200 Subject: [PATCH 14/23] TODO remarks on radical* functions for degenerate circle(s) --- base/geometry.asy | 3 +++ 1 file changed, 3 insertions(+) diff --git a/base/geometry.asy b/base/geometry.asy index 31b6c2a10..8b1101c47 100644 --- a/base/geometry.asy +++ b/base/geometry.asy @@ -6312,6 +6312,7 @@ point inverse(real k, point C, point P) /**/ point radicalcenter(circle c1, circle c2) {/**/ + // TODO Consider degenerate circle(s) if (c1.C == c2.C) abort("radicalcenter: the centers must be distinct"); point[] P = standardizecoordsys(c1.C, c2.C); coordsys R = P[0].coordsys; @@ -6326,6 +6327,7 @@ point radicalcenter(circle c1, circle c2) /**/ line radicalline(circle c1, circle c2) {/**/ + // TODO Consider degenerate circle(s) if (c1.C == c2.C) abort("radicalline: the centers must be distinct"); return perpendicular(radicalcenter(c1, c2), line(c1.C, c2.C)); } @@ -6333,6 +6335,7 @@ line radicalline(circle c1, circle c2) /**/ point radicalcenter(circle c1, circle c2, circle c3) {/**/ + // TODO Consider degenerate circle(s) return intersectionpoint(radicalline(c1, c2), radicalline(c1, c3)); } From 6b5d52b58dda3ef83d4836da43df50b8d733dd7f Mon Sep 17 00:00:00 2001 From: ivankokan Date: Sun, 10 May 2020 01:25:16 +0200 Subject: [PATCH 15/23] Enhance radicalcenter(circle,circle) preserving the current behavior --- base/geometry.asy | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/base/geometry.asy b/base/geometry.asy index 8b1101c47..879b22325 100644 --- a/base/geometry.asy +++ b/base/geometry.asy @@ -6309,11 +6309,22 @@ point inverse(real k, point C, point P) return C + k/conj(P - C); } -/**/ -point radicalcenter(circle c1, circle c2) -{/**/ +/**/ +point radicalcenter(circle c1, circle c2, bool abort=true) +{/* + If 'abort' is 'true' and the circles are concentric, execution will be aborted. + If 'abort' is 'false' and the circles are both concentric and congruent, a warning is sent + but the common center is returned (as the most convenient point among infinitely many points in the plane + having the same power of a point with respect to both circles).*/ // TODO Consider degenerate circle(s) - if (c1.C == c2.C) abort("radicalcenter: the centers must be distinct"); + if (c1.C == c2.C) { + if (c1.r == c2.r && !abort) { + warning("radicalcenter", "The common center is returned as the most convenient point +for two circles which are both concentric and congruent."); + return c1.C; + } + abort("radicalcenter: circles are concentric" + ((c1.r == c2.r) ? " and congruent" : "")); + } point[] P = standardizecoordsys(c1.C, c2.C); coordsys R = P[0].coordsys; pair C1 = locate(c1.C); From bc4a348eeca19e8a35f9d9745843dd0c984f63c0 Mon Sep 17 00:00:00 2001 From: ivankokan Date: Sun, 10 May 2020 01:48:09 +0200 Subject: [PATCH 16/23] Use abs (negative radii are allowed) --- base/geometry.asy | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/base/geometry.asy b/base/geometry.asy index 879b22325..5c3ae1954 100644 --- a/base/geometry.asy +++ b/base/geometry.asy @@ -6318,12 +6318,12 @@ point radicalcenter(circle c1, circle c2, bool abort=true) having the same power of a point with respect to both circles).*/ // TODO Consider degenerate circle(s) if (c1.C == c2.C) { - if (c1.r == c2.r && !abort) { + if (abs(c1.r) == abs(c2.r) && !abort) { warning("radicalcenter", "The common center is returned as the most convenient point for two circles which are both concentric and congruent."); return c1.C; } - abort("radicalcenter: circles are concentric" + ((c1.r == c2.r) ? " and congruent" : "")); + abort("radicalcenter: circles are concentric" + ((abs(c1.r) == abs(c2.r)) ? " and congruent" : "")); } point[] P = standardizecoordsys(c1.C, c2.C); coordsys R = P[0].coordsys; From cc58f7949f05c9e1111355bae885f14544b547b6 Mon Sep 17 00:00:00 2001 From: ivankokan Date: Sun, 10 May 2020 15:00:07 +0200 Subject: [PATCH 17/23] Inversion docs --- base/geometry.asy | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/base/geometry.asy b/base/geometry.asy index 5c3ae1954..0f1c6b5f9 100644 --- a/base/geometry.asy +++ b/base/geometry.asy @@ -6353,8 +6353,10 @@ point radicalcenter(circle c1, circle c2, circle c3) /**/ struct inversion {/**/ - real k; - point C; + /**/ + real k;/*Inversion power*/ + /**/ + point C;/*Inversion center*/ }/**/ /**/ From 6d57c5135da55e1173160f5d7d79be801c3a0319 Mon Sep 17 00:00:00 2001 From: ivankokan Date: Sun, 10 May 2020 16:52:55 +0200 Subject: [PATCH 18/23] Replace regular inversion functions with implicit constructors --- base/geometry.asy | 31 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/base/geometry.asy b/base/geometry.asy index 0f1c6b5f9..086ac697b 100644 --- a/base/geometry.asy +++ b/base/geometry.asy @@ -6354,25 +6354,24 @@ point radicalcenter(circle c1, circle c2, circle c3) struct inversion {/**/ /**/ - real k;/*Inversion power*/ + restricted real k;/*Inversion power*/ /**/ - point C;/*Inversion center*/ -}/**/ + restricted point C;/*Inversion center*/ -/**/ -inversion inversion(real k, point C) -{/*Return the inversion with respect to 'C' having inversion power 'k'.*/ - inversion oi; - oi.k = k; - oi.C = C; - return oi; -} + /**/ + void operator init(real k, point C) + {/*Initialize the inversion with respect to 'C' having inversion power 'k'.*/ + this.k = k; + this.C = C; + } -/**/ -inversion inversion(point C, real k) -{/*Return the inversion with respect to 'C' having inversion power 'k'.*/ - return inversion(k, C); -} + /**/ + void operator init(point C, real k) + {/*Initialize the inversion with respect to 'C' having inversion power 'k'.*/ + this.k = k; + this.C = C; + } +}/**/ /**/ inversion[] inversion(circle c1, circle c2, real sgn = 1) From 86ccd0671b490326a0686bc8cd0c4f6e9bcb589b Mon Sep 17 00:00:00 2001 From: ivankokan Date: Sun, 10 May 2020 17:55:30 +0200 Subject: [PATCH 19/23] Disallow ambiguous inversions --- base/geometry.asy | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/base/geometry.asy b/base/geometry.asy index 086ac697b..a045db127 100644 --- a/base/geometry.asy +++ b/base/geometry.asy @@ -6306,6 +6306,8 @@ void dot(picture pic = currentpicture, triangle t, pen p = currentpen) /**/ point inverse(real k, point C, point P) {/*Return the inverse point of 'P' with respect to point 'C' and inversion power 'k'.*/ + if (k == 0 || !finite(k)) abort("inverse: inversion power must be non-zero and finite"); + if (!finite(C)) abort("inverse: inversion center must be finite"); return C + k/conj(P - C); } @@ -6354,13 +6356,15 @@ point radicalcenter(circle c1, circle c2, circle c3) struct inversion {/**/ /**/ - restricted real k;/*Inversion power*/ + restricted real k = 1;/*Inversion power*/ /**/ restricted point C;/*Inversion center*/ /**/ void operator init(real k, point C) {/*Initialize the inversion with respect to 'C' having inversion power 'k'.*/ + if (k == 0 || !finite(k)) abort("inversion: inversion power must be non-zero and finite"); + if (!finite(C)) abort("inversion: inversion center must be finite"); this.k = k; this.C = C; } @@ -6368,6 +6372,8 @@ struct inversion /**/ void operator init(point C, real k) {/*Initialize the inversion with respect to 'C' having inversion power 'k'.*/ + if (k == 0 || !finite(k)) abort("inversion: inversion power must be non-zero and finite"); + if (!finite(C)) abort("inversion: inversion center must be finite"); this.k = k; this.C = C; } From f35e0ef9f42bea71bb22a4a2ad1e607146c73c87 Mon Sep 17 00:00:00 2001 From: ivankokan Date: Sun, 10 May 2020 18:55:26 +0200 Subject: [PATCH 20/23] Make inversion an involution --- base/geometry.asy | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/base/geometry.asy b/base/geometry.asy index a045db127..b8415d8f3 100644 --- a/base/geometry.asy +++ b/base/geometry.asy @@ -6308,6 +6308,10 @@ point inverse(real k, point C, point P) {/*Return the inverse point of 'P' with respect to point 'C' and inversion power 'k'.*/ if (k == 0 || !finite(k)) abort("inverse: inversion power must be non-zero and finite"); if (!finite(C)) abort("inverse: inversion center must be finite"); + point[] p = standardizecoordsys(C, P); + coordsys R = p[0].coordsys; + if (p[1] == p[0]) return point(R, (infinity, infinity)); + if (!finite(p[1])) return C; return C + k/conj(P - C); } From 77237f751e06d0ce05719ed0d806594a61fd04fe Mon Sep 17 00:00:00 2001 From: ivankokan Date: Sun, 10 May 2020 20:38:35 +0200 Subject: [PATCH 21/23] Enhance radicalline(circle,circle) preserving the current behavior --- base/geometry.asy | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/base/geometry.asy b/base/geometry.asy index b8415d8f3..e71bc16d7 100644 --- a/base/geometry.asy +++ b/base/geometry.asy @@ -6341,11 +6341,22 @@ for two circles which are both concentric and congruent."); return point(R, K/R); } -/**/ -line radicalline(circle c1, circle c2) -{/**/ +/**/ +line radicalline(circle c1, circle c2, bool abort=true) +{/* + If 'abort' is 'true' and the circles are concentric, execution will be aborted. + If 'abort' is 'false' and the circles are both concentric and congruent, a warning is sent + but the line through the common center in direction '(1, 0)' is returned (as the most convenient one + among infinitely many).*/ // TODO Consider degenerate circle(s) - if (c1.C == c2.C) abort("radicalline: the centers must be distinct"); + if (c1.C == c2.C) { + if (abs(c1.r) == abs(c2.r) && !abort) { + warning("radicalline", "The line through the common center in direction '(1, 0)' is returned as the most convenient line +for two circles which are both concentric and congruent."); + return line(c1.C, c1.C + vector(c1.C.coordsys, (1, 0))); + } + abort("radicalline: circles are concentric" + ((abs(c1.r) == abs(c2.r)) ? " and congruent" : "")); + } return perpendicular(radicalcenter(c1, c2), line(c1.C, c2.C)); } From 7f89f0c8d611bd91d643cf3a67d30eca85fb9448 Mon Sep 17 00:00:00 2001 From: ivankokan Date: Sun, 10 May 2020 20:51:01 +0200 Subject: [PATCH 22/23] Remove redundant comparisons in radicalcenter and radicalline functions --- base/geometry.asy | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/base/geometry.asy b/base/geometry.asy index e71bc16d7..183d7c7d8 100644 --- a/base/geometry.asy +++ b/base/geometry.asy @@ -6324,12 +6324,13 @@ point radicalcenter(circle c1, circle c2, bool abort=true) having the same power of a point with respect to both circles).*/ // TODO Consider degenerate circle(s) if (c1.C == c2.C) { - if (abs(c1.r) == abs(c2.r) && !abort) { + bool congruent = abs(c1.r) == abs(c2.r); + if (congruent && !abort) { warning("radicalcenter", "The common center is returned as the most convenient point for two circles which are both concentric and congruent."); return c1.C; } - abort("radicalcenter: circles are concentric" + ((abs(c1.r) == abs(c2.r)) ? " and congruent" : "")); + abort("radicalcenter: circles are concentric" + (congruent ? " and congruent" : "")); } point[] P = standardizecoordsys(c1.C, c2.C); coordsys R = P[0].coordsys; @@ -6350,12 +6351,13 @@ line radicalline(circle c1, circle c2, bool abort=true) among infinitely many).*/ // TODO Consider degenerate circle(s) if (c1.C == c2.C) { - if (abs(c1.r) == abs(c2.r) && !abort) { + bool congruent = abs(c1.r) == abs(c2.r); + if (congruent && !abort) { warning("radicalline", "The line through the common center in direction '(1, 0)' is returned as the most convenient line for two circles which are both concentric and congruent."); return line(c1.C, c1.C + vector(c1.C.coordsys, (1, 0))); } - abort("radicalline: circles are concentric" + ((abs(c1.r) == abs(c2.r)) ? " and congruent" : "")); + abort("radicalline: circles are concentric" + (congruent ? " and congruent" : "")); } return perpendicular(radicalcenter(c1, c2), line(c1.C, c2.C)); } From 6e60b803ab72a6f09ea9f3422539995f894a5ba6 Mon Sep 17 00:00:00 2001 From: ivankokan Date: Mon, 11 May 2020 02:41:14 +0200 Subject: [PATCH 23/23] Pseudocode for radicalcenter(circle,circle,circle) --- base/geometry.asy | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/base/geometry.asy b/base/geometry.asy index 183d7c7d8..e723b42dc 100644 --- a/base/geometry.asy +++ b/base/geometry.asy @@ -6366,6 +6366,30 @@ for two circles which are both concentric and congruent."); point radicalcenter(circle c1, circle c2, circle c3) {/**/ // TODO Consider degenerate circle(s) + + /* Pseudocode: + - Introduce optional argument bool abort=true + - Remove duplicate circles from the set { c1, c2, c3 } considering two circles ci and cj to be equal + if ci.C == cj.C and abs(ci.r) == abs(cj.r) + - If there is only one unique circle c1', there are infinitely many points in the plane having + the same power of a point with respect to all circles: + if !abort: warn and return the common center as the most convenient point + otherwise: abort (there is no unique point) + (It seems that calling radicalcenter(c1', c1', abort) will do.) + - If there are two unique circles c1' and c2': + if concentric (hence non-congruent): abort (there is no point at all) + otherwise: there are infinitely many points in the plane having the same power of a point with respect to all circles + if !abort: warn and return radicalcenter(c1', c2') as the most convenient point (the value of the optional argument is not relevant here) + otherwise: abort (there is no unique point) + - If all circles are pairwise distinct: + if any two concentric (hence non-congruent): abort (there is no point at all) + otherwise: + if centers are collinear: (there is either none or infinitely many points) + check if radicalcenter(ci, cj) for all three pairs returns one unique point (the value of the optional argument is not relevant here) + if yes and !abort: warn and return that point as the most convenient point + otherwise: abort (there is no point at all) + otherwise: return intersectionpoint(radicalline(c1, c2), radicalline(c1, c3)) + */ return intersectionpoint(radicalline(c1, c2), radicalline(c1, c3)); }