[leicht]Flächenberechnung von sich überlappenden/einschließenden Rechtecken

CDW

0
Mitarbeiter
Gut, der Titel ist nicht ganz so knackig, dafür aber aussagekräftig ;)
Eingereicht von Ook!

Es geht darum, die Fläche von Rechtecken, die sich überlappen oder ganz einschließen können, zu berechen.

Euer Programm soll die Koordinaten der Rechtecke entgegennehmen
und die berechnete Fläche ausgeben.

Optional:
Eine GUI, in der die Rechtecke mit der Maus gezeichnet werden können
und die Fläche immer aktualisiert in einem Label/Textfeld steht.
Ihr sollt also Koordinten für Rechtecke einlesen können und deren Fläche ausgeben. Hierbei soll die "tatsächliche" Fläche ermittelt werden (also alle überlapenden Bereiche nicht mehrfach gezählt ;) ).
Bsp:
Code:
   |
 8 |      +-------------------------+
   |      |                         |
   |      |                         |
   |      |   +-----------------+   |
   |      |   |                 |   |
   |      |   |     +------+    |   |
   |      |   |     |      |    |   |
   |      |   |     +------+    |   |
   |      |   |                 |   |
   |      |   |                 |   |
   |      |   +-----------------+   |
   |      |                         |
   |      |                         |
 2 |      +-------------------------+
   |
   |______2_________________________8_____________
hier sind zwar 3 Rechtecke, allerdings beträcht die Fläche 36 Quadrat(einheiten), da die Seiten des großen Rechtecks 6 Einheiten länge haben (oder zumindest nah dran, soll nur eine Skizze sein) und die anderen Rechtecke komplett in diesem großen drin liegen.
Das Beispiel soll übrigens keineswegs vorgeben, wie und in welchem Format ihr die Koordinaten einlesen müsst ;).
Zusätzlich könnt ihr natürlich auch andere Figuren implementieren - Kreise, Dreiecke usw.
 
Ich reiche mal als erster meine "Lösung" ein =D

Übrigens, hier das Kernstück:
Code:
function PointInRect(const Point: TPoint; const Rect: TRect): Boolean;
begin
  with Rect do
    Result :=
      ( Point.X < Rect.Left ) or ( Point.X > Rect.Right ) or
      ( Point.Y < Rect.Top ) or ( Point.Y > Rect.Bottom );
  Result := not Result;
end;

function RectOverlapsRect(const Rect1, Rect2: TRect): Boolean;
begin
  with Rect1 do
  begin
    Result := PointInRect( Point( Left, Top ), Rect2 );
    if Result then
      Exit;
    Result := PointInRect( Point( Right, Top ), Rect2 );
    if Result then
      Exit;
    Result := PointInRect( Point( Right, Bottom ), Rect2 );
    if Result then
      Exit;
    Result := PointInRect( Point( Left, Bottom ), Rect2 );
    if Result then
      Exit;
  end;
end;

procedure CalculateOverlappingRectArea(const Rect1, Rect2: TRect; var SideA, SideB, A: Integer);
var
  r1Width, r1Height,
  r2Width, r2Height: Integer;
  Left1, Left2,
  Top1, Top2: Integer;

  procedure CalculateRectSideLengths(const R: TRect; var X, Y: Integer);
  begin
    with R do
    begin
      X := Right - Left;
      Y := Bottom - Top;
    end;
  end;

  procedure Exchange(var X, Y: Integer);
  begin
    X := X + Y;
    Y := X - Y;
    X := X - Y;
  end;

begin
  SideA := 0;
  SideB := 0;
  A := 0;
  if RectOverlapsRect( Rect1, Rect2 ) then
  begin
    CalculateRectSideLengths( Rect1, r1Width, r1Height );
    CalculateRectSideLengths( Rect2, r2Width, r2Height );

    if Rect1.Left < Rect2.Left then
    begin
      Left1 := Rect1.Left;
      Left2 := Rect2.Left;
    end else
    begin
      Left1 := Rect2.Left;
      Left2 := Rect1.Left;
      Exchange( r1Width, r2Width );
    end;
    if Rect1.Top < Rect2.Top then
    begin
      Top1 := Rect1.Top;
      Top2 := Rect2.Top;
    end else
    begin
      Top1 := Rect2.Top;
      Top2 := Rect1.Top;
      Exchange( r1Height, r2Height );
    end;

    SideA := Abs( r1Width - (Left2-Left1) );
    SideB := Abs( r1Height - (Top2-Top1) );
    A := SideA*SideB;
  end;
end;
 
Hi,

bin neu hier. Hab vor gut einem Monat mit Programmieren in C angefangen und bin seither ziemlich süchtig. :wink: Bei der Suche nach Aufgaben bin ich auf dieses Forum hier gestoßen. Echt super, dass ihr so etwas anbietet.

Ich fand die Aufgabe ehrlich gesagt überhaupt nicht so leicht. All die Möglichkeiten, wie sich die Rechtecke schneiden können oder wenn gleich mehrere Rechtecke an einer Stelle übereinander lappen. In meiner Lösung kann man auch nur eine festgelegte Menge Rechtecke eingeben, aber ich bin ja auch noch Anfänger.:)

Hier ist meine Lösung in C:
Code:
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>

struct koordinaten{

    double x;
    double y;
};
struct eckdaten{
    
    double xmin;
    double xmax;
    double ymin;
    double ymax;
};

const int RECHTECKE = 20;
const int MAXE = 10;

void sort(struct koordinaten *array);
double A (struct eckdaten r);
double flaeche_von_schnittmengen(struct eckdaten *r, int durchlaeufe);
struct eckdaten gib_schnittmenge_von(struct eckdaten r, struct eckdaten s);
    
int main()
{
    struct koordinaten ecke[4];
    struct eckdaten rechteck[RECHTECKE];
    int i, j;
    double flaeche, ergebnis, temp;
    char input[MAXE], c;

    flaeche = 0;    
    for (j = 0; j < MAXE; j++){
        printf ("\nGebe die Eckpunkte des %i.ten Rechtecks ein.\n", j + 1);  
        for (i = 0; i < 4; i++){
            printf ("x-Koordinate von Ecke %i: ", i+1);
            ecke[i].x = atoi (fgets (input, MAXE, stdin));
            printf ("y-Koordinate von Ecke %i: ", i+1);
            ecke[i].y = atoi (fgets (input, MAXE, stdin));    
        }
        sort(ecke);
        rechteck[j].xmax = ecke[0].x;
        rechteck[j].xmin = ecke[3].x;
        rechteck[j].ymax = ecke[0].y;
        rechteck[j].ymin = ecke[3].y;
        flaeche += A (rechteck[j]);
        ergebnis = flaeche;        
        ergebnis -= flaeche_von_schnittmengen(rechteck, j); 
        printf ("Die mit den Rechtecken bedeckte Flaeche betraegt: %f\n", ergebnis);        
        printf("Noch ein Rechteck?\n");
        while (1){
            printf("J fuer Ja oder N fuer Nein: ");
            c = (char)toupper(getchar());
            while (getchar() != '\n');
            if (c == 'J' || c == 'N')
                break;
        }
        if (c == 'N')
            j = MAXE;         
    }
        
    return 0;
}

void sort(struct koordinaten *array){
//soritert varaiblen vom Typ struct koordinaten vor für die Übergabe in Typ struct eckdaten.

    int i, j;
    struct koordinaten temp;
    
    for (i = 0; i < 4; i++){
        for (j = i + 1; j < 4; j++){
            if (array[i].x < array[j].x){
                temp = array[i];
                array[i] = array[j];
                array[j] = temp;
            }
        }
    }
    if (array[0].y < array[1].y)
        array[0] = array[1];
    if (array[2].y < array[3].y)
        array[3] = array[2];
}        
double A (struct eckdaten r){
// berechnet Flaechninhalt

    double breite, laenge, a;
    
    breite = r.ymax - r.ymin;
    laenge = r.xmax - r.xmin;
    a = breite * laenge;

    return a;    
}
double flaeche_von_schnittmengen(struct eckdaten *r, int durchlaeufe){    
// summiert Schnittmengen und subtrahiert mehrfache Schnittmengen

   	int i, j, k;	
	double a, m;
	struct eckdaten schnitt[MAXE];

	a = 0; m = 0; k = 0;	

	for (i = 0; i < durchlaeufe; i++){
		for (j = i + 1; j <= durchlaeufe; j++){
				schnitt[k] = gib_schnittmenge_von(r[i], r[j]);
				m = A (schnitt[k]);
				if (m == 0){
					schnitt[k] = gib_schnittmenge_von(r[j], r[i]);
					m = A (schnitt[k]);
				}
				if (m != 0)
					k++;
				a += m;
		}
	printf("\n");
		a -=  flaeche_von_schnittmengen(schnitt, (durchlaeufe - 1));
	}
	return a;
}

struct eckdaten gib_schnittmenge_von(struct eckdaten r, struct eckdaten s){
// ermittelt Art der Schnittmenge und gibt entsprechende Eckdaten zurueck
	int a;
	struct eckdaten schnitt; 

	a = 0;
	//Links-Unten drin
	if (r.xmin >= s.xmin && r.xmin < s.xmax){
		if (r.ymin >= s.ymin && r.ymin < s.ymax)
			a += 1;
	}
	//Rechts-Oben drin
	if (r.xmax <= s.xmax && r.xmax > s.xmin){
		if (r.ymax <= s.ymax && r.ymax > s.ymin)
			a += 10;
	}
	//Links-Oben drin
	if (r.xmin >= s.xmin && r.xmin < s.xmax){
		if (r.ymax <= s.ymax && r.ymax > s.ymin)
			a += 100;
	}
	//Rechts-Unten drin
	if (r.xmax <= s.xmax && r.xmax > s.xmin){
		if (r.ymin >= s.ymin && r.ymin < s.ymax)
			a += 1000;
	}  
	// schnitt ohne Ecken drin
	if (r.xmin >= s.xmin && r.xmin < s.xmax){
		if (r.xmax <= s.xmax && r.xmax > s.xmin)
			if (s.ymin >= r.ymin && s.ymin < r.ymax)	
				if (s.ymax <= r.ymax && s.ymax > r.ymin)
			a = 2;
	}
	printf("case %i", a);
	switch (a){
		case 1:
			schnitt.xmin = r.xmin; 
			schnitt.xmax = s.xmax;
			schnitt.ymin = r.ymin;
			schnitt.ymax = s.ymax;
			break;
		case 2:
			schnitt.xmin = r.xmin; 
			schnitt.xmax = r.xmax;
			schnitt.ymin = s.ymin;
			schnitt.ymax = s.ymax;
			break;
		case 10:
			schnitt.xmin = s.xmin; 
			schnitt.xmax = r.xmax;
			schnitt.ymin = s.ymin;
			schnitt.ymax = r.ymax;
			break;
		case 1111:		//11 == 111 == 1011 == 1111
		case 1100:
		case 1101:
			schnitt.xmin = r.xmin; 
			schnitt.xmax = r.xmax;
			schnitt.ymin = r.ymin;
			schnitt.ymax = r.ymax;
			break;
		case 100:
			schnitt.xmin = r.xmin; 
			schnitt.xmax = s.xmax;
			schnitt.ymin = s.ymin;
			schnitt.ymax = r.ymax;
			break;
		case 101:
			schnitt.xmin = r.xmin; 
			schnitt.xmax = s.xmax;
			schnitt.ymin = r.ymin;
			schnitt.ymax = r.ymax;
			break;
		case 110:
			schnitt.xmin = r.xmin; 
			schnitt.xmax = r.xmax;
			schnitt.ymin = s.ymin;
			schnitt.ymax = r.ymax;
			break;
		case 1000:
			schnitt.xmin = s.xmin; 
			schnitt.xmax = r.xmax;
			schnitt.ymin = r.ymin;
			schnitt.ymax = s.ymax;
			break;
		case 1001:
			schnitt.xmin = r.xmin; 
			schnitt.xmax = r.xmax;
			schnitt.ymin = r.ymin;
			schnitt.ymax = s.ymax;
			break;
		case 1010:
			schnitt.xmin = s.xmin; 
			schnitt.xmax = r.xmax;
			schnitt.ymin = r.ymin;
			schnitt.ymax = r.ymax;
			break;
		default:
			schnitt.xmin = 0; 
			schnitt.xmax = 0;
			schnitt.ymin = 0;
			schnitt.ymax = 0;
	}
	return schnitt;
}
 
Zuletzt bearbeitet:
Zurück
Oben