WaBis

walter.bislins.ch

Schnittfläche zweier Kreise (JavaScript)

Donnerstag, 4. Mai 2017 - 00:19 | Autor: wabis | Themen: Wissen, Geometrie, Mathematik, Programmierung, Interaktiv | Kommentare(8)
Hier leite ich die Formeln zur Berechnung der Schnittfläche zweier Kreise her. Ich zeige wie der Abstand der Kreise numerisch mit dem Newton-Verfahren berechnet werden kann, wenn die Schnittfläche gegeben ist. Im Rechenformular kann man sich Werte ausrechnen lassen. Am Ende wird der Code des Rechenformulars aufgelistet.

Schnittfläche berechnen

Schnittflächen zweier Kreise

Zum Rechenformular

Die Kreisabschnitte AA gelb und BA blau im Bild rechts können mit denselben Formeln separat berechnet werden. Dazu definieren wir einige Parameter wie im Bild unten beschriftet. Dies sind die Radien der beiden Kreise a und b, sowie deren Abstand d.

Im Bild unten sind zur besseren Übersicht jeweils nur die halben Flächen bezeichnet, in den Formeln wird aber mit den ganzen Flächen gerechnet. Die gesuchten Kreisabschnitte AA und BA berechnet man aus den Kreissektoren AS bzw. BS abzüglich der Dreiecke AD bzw. BD. Die gesuchte Schnittfläche S ist dann einfach die Summe der Kreisabschnitte.

Es müssen die drei folgenden Fälle unterschieden werden:

  • Der Abstand der beiden Kreise d ist gösser als die Summe der beiden Radien a und b → die Kreise überlappen sich nicht, deren Schnittfläche ist also S = 0
  • Der Abstand der Kreiszentren d ist kleiner als die Differenz der beiden Radien → der kleinere Kreis liegt vollständig innerhalb des grösseren Kreises, die Schnittfläche ist gleich der Fläche des kleineren Kreises
  • In allen anderen Fällen überlappen sich die beiden Kreise teilweise → Die Schnittfläche S wird nach den folgenden Formeln berechnet. Die Schnittfläche ist immer ein Wert zwischen 0 und der Fläche des kleineren Kreises.

Schema zweier überlappender Kreise mit Beschriftung der Parameter

Für die Berechnungen der Kreisabschnitte müssen eventuell zwei weitere Fälle unterschieden werden: links der Fall bei dem alle Winkel des Dreiecks a-b-d kleiner als 90° sind, rechts der Fall, bei dem einer der Winkel grösser als 90° ist.

Für die Berechnung der Flächen führen wir den Abschnitt x sowie die Dreieckshöhe h ein. Der Abschnitt y ist entspricht dem Abschnitt x für den Kreis B, es ist also y = dx. Für die Parameter gelten die folgenden Beziehungen nach Pythagoras:

(1)

Wir können h eliminieren, indem wir die beiden Gleichungen einander gleich setzen, und nach x auflösen:

(2)

Der Term x2 kommt auf beiden Seiten vor und kann daher auf beiden Seiten gestrichen werden. Dann können wir nach x auflösen, das nur noch mit der ersten Potenz vorkommt.

Im Folgenden werden die Formeln für die beiden Kreise einander gegenüber gestellt. Der Abschnitt x für den linken Kreis entspricht dem Abschnitt y für den rechten Kreis. Alle Flächen des linken Kreises sind mit A bezeichnet, jene des rechten Kreises mit B.

(3)
mit

(4)
mit

Beachte, dass die Werte x bzw. y negativ sein können. Dies müssen wir berücksichtigen, wenn wir die Fläche der Sektoren AS und BS berechnen.

Zur Berechnung der Sektorflächen AS und BS benötigen wir die Sektorwinkel. Diese können wir im Prinzip aus dem arcsin oder dem arccos erhalten. Der arcsin ist hier nicht geeignet, weil er für negative x und y nicht den gewünschten Winkel zwischen π/2 und π liefert. Daher verwenden wir die arccos Funktion:

(5)
ergibt

wobei'
' =' 'Fläche des Kreissektors des Kreises A
' =' 'Radius des Kreises A
' =' 'siehe (3)
(6)
ergibt

wobei'
' =' 'Fläche des Kreissektors des Kreises B
' =' 'Radius des Kreises B
' =' 'siehe (4)

Beachte, dass die hier berechnete Fläche AS das doppelte der gelb gezeichneten Fläche im obigen Bild ist, da die Segmentfläche eines Kreises A = (α/2π) · r2 · π = α/2 · r2 ist. Dies gilt auch für die folgenden Berechnungen.

Um die Kreisabschnitte (Kreissegmente) AA und BA zu berechnen, benötigen wir die Flächen der Dreiecke AD und BD. Die Kreisabschnitte erhält man, indem man von den Kreissektoren die Flächen der Dreiecke abzieht, siehe (9) und (10).

Bei negativen x bzw. y wird der entsprechende Sektorwinkel grösser als π und wir müssen die Dreiecksflächen zu den Sektorflächen hinzufügen. In den folgenden Formeln erhalten wir negative Dreiecksflächen für Sektorwinkel grösser als π, sodass diese Fälle in (9) und (10) automatisch korrekt behandelt werden. Wir brauchen also keine extra Fallunterscheidung dafür zu machen.

(7)
mit

ergibt

wobei'
' =' 'Dreicksfläche des Kreissektors von Kreis A
' =' 'siehe (3)
' =' 'Radius des Kreises A
(8)
mit

ergibt

wobei'
' =' 'Dreicksfläche des Kreissektors von Kreis B
' =' 'siehe (4)
' =' 'Radius des Kreises B

Die Kreisabschnitts-Flächen sind:

(9)
wobei'
' =' 'Kreisabschnitt-Fläche
' =' 'Kreissektor-Fläche (5)
' =' 'Dreiecks-Fläche des Kreissektors (7)
(10)
wobei'
' =' 'Kreisabschnitt-Fläche
' =' 'Kreissektor-Fläche (6)
' =' 'Dreiecks-Fläche des Kreissektors (8)

Und schliesslich erhalten wir die Schnittfläche S der zwei Kreise:

(11)
wobei'
' =' 'Schnittfläche der Kreise
' =' 'Kreisabschnittfläche von Kreis A, siehe (9)
' =' 'Kreisabschnittfläche von Kreis B, siehe (10)

Abstand berechnen

Wenn wir die Schnittfläche der zwei Kreise kennen, können wir den Abstand der Kreise berechnen. Im Prinzip müsste man dazu einfach die Formel (11) nach Einsetzen aller Zwischenformeln nach d auflösen. Da aber d sowohl im arccos, unter der Wurzel und separat steht, kann die Formel nicht analytisch nach d aufgelöst werden. Wir müssen ein numerisches Verfahren wie das Newton-Verfahren anwenden.

Beim Newton-Verfahren muss man einen sinnvollen Startwert vorgeben. Zudem sollte man die Funktion, deren Nullstelle man sucht, grafisch aufzeichnen, um zu sehen, ob es eine eindeutige Lösung gibt und wo ein geeigneter Startwert angesetzt werden muss, damit das Verfahren immer eine Lösung findet.

Ich generiere deshalb eine Grafik für verschiedene Radien und Abstände, um das Verhalten der Funktion zu analysieren:

In der Grafik ist die Schnittfläche S als Funktion des Abstandes der Kreise d für verschiedene Kombinationen von Kreisradien a und b aufgezeichnet. Wenn man nun zum Beispiel den Abstand d wissen will, bei dem die Schnittfläche 1 ist (rote Linie), so sucht man jene blaue Linie, die den beiden Radien der Kreise entspricht und sucht deren Schnittpunkt mit der roten Linie. Unterhalb des Schnittpunktes kann man den Abstand d ablesen.

Für das Newton-Verfahren ist wichtig, dass die blauen Kurven erstens die rote Linie überhaupt schneiden. Dies gilt nicht für alle Radien, aber die entsprechenden Fälle kann man aussortieren. Zweitens kann man sehen, dass es für jede blaue Linie nur genau einen Schnittpunkt mit der roten Linie gibt. D.h. es gibt immer eine eindeutige Lösung.

Die blauen Linien schneiden die rote Linie meist in einem steilen Winkel und die blauen Linien sind in einem grossen Bereich praktisch gerade. Das sind ideale Voraussetzungen für das Newton-Verfahren. Problematisch werden die Grenzfälle, wo die blauen Linien horizontal in die Horizontale über gehen. In diesen Fällen ist das Newton-Verfahren überfordert, da es bei horizontalen Lininen nicht gut oder überhaupt nicht konvergiert. Dies kann ich korrigieren, indem ich an die Enden je eine Parabel anhänge, welche die Funktion so erweitert, dass sie kontinuierlich abfallend wird. Damit kann das Verfahren zwar Werte ein wenig ausserhalb des Wertebereiches liefern, aber diese können in den Wertebereich zurück gespiegelt werden.

Als Startwert für das Newton-Verfahren kann d = (a+b)/2 gesetzt werden.

Rechenformular

Um die Schnittfläche der beiden Kreise zu berechnen, gib a, b und den Abstand d ein. Die resultierende Schnittfläche wird im Feld S angezeigt.

Um den benötigten Abstand der beiden Kreise für eine vorgegebene Schnittfläche zu berechnen, gib in das Feld S die Schnittfläche ein. Der zugehörige Abstand wird im Feld d angezeigt.

Code

#INCLUDE JsGraph.inc
#INCLUDE ControlPanel.inc
#INCLUDE NewtonSolver.inc

{{col|50}}

<jscript>

function Area( a, b, d ) {
  // Schnittfläche berechnen
  var x = (a*a - b*b + d*d) / (2*d);
  var As = a*a * Math.acos( x / a );
  var Ad = x * Math.sqrt( a*a - x*x );
  var Aa = As - Ad;
  var y = (b*b - a*a + d*d) / (2*d);
  var Bs = b*b * Math.acos( y / b );
  var Bd = y * Math.sqrt( b*b - y*y );
  var Ba = Bs - Bd;
  return Aa + Ba;
}

function S( a, b, d ) {
  // Test ob d ausserhalb des Bereiches liegt
  if (d >= a + b) return 0;
  if (d <= Math.abs(a-b)) {
    var r = (a > b) ? b : a;
    return r*r * Math.PI;
  }
  return Area( a, b, d );
}

function Sx( a, b, d ) {
  // Funktion an den Enden des Wertebereiches d für das Newton-Verfahren erweitern mit Parabeln
  var dmax = a + b;
  if (d >= dmax) return -Math.pow(d-dmax, 2);
  var dmin = Math.abs(a-b);
  if (d <= dmin) {
    var r = (a > b) ? b : a;
    var Smin = r*r * Math.PI;
    return Math.pow(d-dmin,2) + Smin;
  }
  return Area( a, b, d );
}

var Model = {
  a: 1,
  b: 1,
  d: 1.5,
  S: 0,
  S_field: 0,

  Update: function() {
    // ungültige Eingaben korrigieren
    if (isNaN(this.a)) this.a = 1;
    if (isNaN(this.b)) this.b = 1;
    if (isNaN(this.d)) this.d = 1.5;
    if (isNaN(this.S_field)) this.S_field = this.S;
    this.a = Math.abs(this.a);
    this.b = Math.abs(this.b);
    this.d = Math.abs(this.d);
    // test, ob S verändert wurde
    if (this.S != this.S_field) {
      this.S = Math.abs(this.S_field);
      this.d = this.ComputeD();
    } else {
      this.S = S( this.a, this.b, this.d );
    }
    this.S_field = this.S;
  },

  ComputeD: function() {
    // wenn S ausserhalb des Wertebereiches liegt...
    if (this.S <= 0) return this.a + this.b;
    var r = (this.a > this.b) ? this.b : this.a;
    var smax = Math.PI * r * r;
    if (this.S >= smax) {
      this.S = smax;
      return 0;
    }
    // Abstand d mit Newton-Verfahren berechnen
    var me = this;
    var d = SolveWithNewton( 
      function(x){ 
        return Sx( me.a, me.b, x ); 
      }, 
      this.S, (this.a+this.b)/2, 1e-6
    );
    // wenn d ausserhalb des Wertebereiches 0..a+b liegt, dann 
    // d in den Wertebereich zurück spiegeln
    if (d < 0) d = -d;
    if (d > this.a+this.b) d = 2 * (this.a+this.b) - d;
    return d;
  }
}

var ModelGraph = NewGraph2D( {
  Id: 'ModelGraph',
  Width: '100%',
  Height: '75%',
  DrawFunc: DrawModelGraph,
  AutoReset: true,
  AutoClear: true,
  AutoScalePix: true
} );

function DrawModelGraph( g ) {

  // compute window size
  var abd = Model.a + Model.b + Model.d;
  if (Model.a + Model.d < Model.b) abd = 2 * Model.b;
  if (Model.b + Model.d < Model.a) abd = 2 * Model.a;
  var wModel = 1.05 * abd;
  var hModel = (Model.a > Model.b) ? Model.a : Model.b;
  hModel *= 2.1;
  if (wModel == 0 || hModel == 0) return;
  var vpRatio = g.VpInnerWidth / g.VpInnerHeight;
  var modelRatio = wModel / hModel;
  var WinWidth = wModel;
  var WinHeight = hModel;
  if (modelRatio > vpRatio) {
    WinHeight = wModel / vpRatio;
  } else {
    WinWidth = hModel * vpRatio;
  }
  var l = Model.a;
  if (Model.b - Model.d > Model.a) l = Model.b - Model.d;
  var WinXmin = -(WinWidth/2 - abd/2 + l);
  var WinYmin = -0.5 * WinHeight;

  g.SetWindowWH( WinXmin, WinYmin, WinWidth, WinHeight );

  // draw circles
  g.SetAlpha( 0.5 );
  g.SetAreaAttr( '#f88', 'black', 2 );
  g.Circle( 0, 0, Model.a, 3 );
  g.SetAreaAttr( '#88f', 'black', 2 );
  g.Circle( Model.d, 0, Model.b, 3 );

  g.SetAlpha( 1 );
  g.Circle( 0, 0, Model.a, 1 );
  g.Circle( Model.d, 0, Model.b, 1 );

  // draw circle centers
  g.SetMarkerAttr( 'Plus', 12, 'black', 'black', 1 );
  g.Marker( 0, 0 );
  g.Marker( Model.d, 0 );

  // draw a, b, d
  var rx = Math.sin(Math.PI/4);
  var ry = Math.cos(Math.PI/4);
  g.SetMarkerAttr( 'Arrow1', 10 );
  g.SetAreaAttr( 'red', 'red', 2 );
  g.Arrow( 0, 0, -Model.a*rx, Model.a*ry );
  g.SetTextSize( 24 );
  g.SetTextColor( 'red' );
  g.SetTextAlign( 'left', 'bottom' );
  g.SetTextPadding( 5 );
  g.Text( 'a', -Model.a*rx/2, Model.a*ry/2 );

  g.SetAreaAttr( 'blue', 'blue', 2 );
  g.Arrow( Model.d, 0, Model.b*rx+Model.d, Model.b*ry );
  g.SetTextColor( 'blue' );
  g.SetTextAlign( 'right', 'bottom' );
  g.Text( 'b', Model.d+Model.b*rx/2, Model.b*ry/2 );

  g.SetLineAttr( 'black', 2 );
  g.Line( 0, 0, Model.d, 0 );
  g.SetTextAlign( 'center', 'bottom' );
  g.SetTextColor( 'black' );
  g.Text( 'd', Model.d/2, 0 );
}

</jscript>

{{col}}

<jscript>

ControlPanels.NewPanel( {
    ModelRef: 'Model',
    NCols: 2,
    PanelFormat: 'InputMaxWidth',
    OnModelChange: UpdateAll,
    Format: 'std',
    Digits: 6,
  }

).AddHeader( { 
    ColSpan: 4,
    Text: ControlPanels.ResetButtonR(),
  }

).AddTextField( {
    Name: 'a'
  }

).AddTextField( {
    Name: 'b'
  }

).AddTextField( {
    Name: 'd',
  }

).AddTextField( {
    Name: 'S',
    ValueRef: 'S_field'
  }

).Render();


function UpdateAll() {
  Model.Update();
  ControlPanels.Update();
  ModelGraph.Redraw();
}

function Reset() {
  ControlPanels.Reset();
  Model.S = Model.S_field;
  UpdateAll();
}

xOnLoad( UpdateAll );

</jscript>


Kommentare

1Wolfgang Schmidt 30.08.2018 | 09:55

Sehr gute detaillierte Herleitung,

schade, dass die Berechnung in C erfolgt. VBA in Excel wäre mir lieber.

LG
ws

2Lothar Ternes 28.04.2021 | 19:38

Tippfehler
Am Ende des Satzes muss stehen "rechten" und nicht "rechnten"

Satz: Im Folgenden werden die Formeln für die beiden Kreise einander gegenüber gestellt. Der Abschnitt x für den linken Kreis entspricht dem Abschnitt y für den rechnten Kreis.

3wabiswalter@bislins.ch (Walter Bislin, Autor dieser Seite) 30.04.2021 | 02:42

@Lothar, vielen Dank für die Aufmerksamkeit. Fehler ist korrigiert.

4Dieter Renz 09.08.2022 | 17:53

Hallo Walter,

ich bin auf deine Seite gestoßen, weil ich mich intensiv mit diesem Problem beschäftige, nämlich aus der vorgegebenen, beliebigen Schnittflächengröße (> 0% - < 100% der Kreisfläche) von zwei sich überlappenden Kreisen mit gleichem Radius, den Abstand d von M1 und M2 zu berechnen. Dein beeindruckender Lösungsweg ist, wenn ich es richtig sehe, ein iteratives Näherungsverfahren (Newton), also kein rein analytisches Berechnungsverfahrem. Mein Lösungsweg ist ein analytisches Berechnungsverfahren (Integralmethode) und wenn du Interesse hast, würde ich dir gerne meinen Lösungsweg per Email zukommen lassen.

Viele Grüße, Dieter

5Dieter Renz 09.08.2022 | 18:12

Ergänzung zu meiner Mail am 9.08.22:

für a = 1, b = 1, S = 1,5708 (pi/2)
d = 0,807943 (dein Rechnerergebnis)
d = 0,807946 (meine Berechnung nach der Integralmethode)

6Andreas 03.03.2023 | 10:36

Hallo, gegeben ist ein Vierpass, also vier Kreise gleichen Radius’. Diese vier Kreise berühren sich am Schnittpunkt von x und y Achse. Von zwei Kreisen liegt der Mittelpunkt auf der x~Achse, sie tangieren die y-Achse, aber schneiden sie nicht. Von zwei Kreisen liegt der Mittelpunkt auf der y~Achse, sie tangieren die x-Achse, aber schneiden sie nicht.
Das ergibt vier gleich große Schnittflächen. Ich möchte gerne die Gesamtfläche des Vierpass errechnen. Dazu brauche ich ja eigentlich nur den Kreisinhalt zu multiplizieren und die Schnittflächen davon zu substrahieren. Die vier Kreismittelpunkte sind zueinander als Quadrat angeordnet, eine Seitenlänge entspricht also dem Abstand .... ah... es geht mir ein Licht auf. d (also der Abstand zweier sich schneidender Kreise) kann errechnet werden, wenn man die Diagonale des Quadrats als Hypothenuse heranzieht. Oder eben d als Hypothenuse definiert und Quadratdiagonale/2 als a bzw. b (Satz des Pythagoras). Und die Diagonale des Quadrats entsprich 2*r. Danke, hilft manchmal schon, wenn man irgendwo ein Problem schildern kann. Sorry, wenn die Terminologie nicht stimmt, Abi ist mehr als zwei Jahrzehnte her und in Mathe war ich nie gut.

7Andrej 26.03.2024 | 22:15

Hallo Walter,
sorry, ich habe kein Kommentar, sondern eine relevante Frage. Mich interessieren die Schnittflächen der Kreise, weil Hana, meine Frau, als Bildhauerin Lentoide als modulare Körper in ihren geometrischen Kunstwerken zusammenstellt: www.hana-hasilik.de
Ich fand keinen Trivialnamen der Schnittfläche von Kreisscheiben. Leider habe ich nur 1962-Bratislava-Abi-Kenntnisse von Geometrie. Daher meine Frage: Gibt es eine Benennung im Deutsch oder in anderen Sprachen? Für einen Hinweis wäre ich sehr dankbar.
Beste Grüße aus Marburg
Andrej

8wabiswalter@bislins.ch (Walter Bislin, Autor dieser Seite) 03.04.2024 | 02:27

Laut ChatGPT: Die Schnittfläche zweier Kreise wird als Kreissegment oder genauer als gemeinsames Kreissegment bezeichnet.

Dein Kommentar zu diesem Artikel
Name
Email optional; wird nicht angezeigt
Kommentar
  • Name wird bei deinem Kommentar angezeigt.
  • Email ist nur für den Administrator, sie wird nicht angezeigt.
  • Du kannst deine Kommentare eine Zeit lang editieren oder löschen.
  • Du kannst Formatierungen im Kommentar verwenden, z.B: Code, Formeln, usw.
  • Externen Links und Bilder werden nicht angezeigt, bis sie der Admin freischaltet.
More Page Infos / Sitemap
Created Donnerstag, 4. Mai 2017
Scroll to Top of Page
Changed Donnerstag, 24. März 2022