Hackerboard WikiHaboBlog

[HaBo]

 
Programmieraufgaben Hier wird regelmäßig eine neue Programmieraufgabe gestellt, die dann gelöst werden soll und in Zusammenarbeit mit den Moderatoren auch besprochen werden kann.

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

Diskussion: [leicht]Flächenberechnung von sich überlappenden/einschließenden Rechtecken im Forum Programmieraufgaben, in der Kategorie Code Kitchen; Gut, der Titel ist nicht ganz so knackig, dafür aber aussagekräftig Eingereicht von Ook! Zitat: Es geht darum, die Fläche ...

Antwort
Alt 08.08.10, 00:34   #1 (permalink)
CDW
Moderator
 
Benutzerbild von CDW
 
Registriert seit: 20.07.05
CDW Leistung: OpteronCDW Leistung: OpteronCDW Leistung: OpteronCDW Leistung: OpteronCDW Leistung: Opteron
Likes: 156
Standard [leicht]Flächenberechnung von sich überlappenden/einschließenden Rechtecken


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

Zitat:
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.
__________________
Noch mal, für alle Pseudo-Geeks: 1+1=0. -> 10 wäre Überlauf!
Selig, wer nichts zu sagen hat und trotzdem schweigt.
CDW ist offline   Mit Zitat antworten
Alt 08.08.10, 18:40   #2 (permalink)
 
Registriert seit: 12.01.09
lone.wolf Leistung: Z3
lone.wolf eine Nachricht über AIM schicken
Likes: 1
Standard

Ich reiche mal als erster meine "Lösung" ein =D

Übrigens, hier das Kernstück:
Delphi-Code   

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;
Angehängte Dateien
Dateityp: zip Rect.zip (211,0 KB, 3x aufgerufen)
lone.wolf ist offline   Mit Zitat antworten
   
HaBOT
 

Werbung ist gerade online    
Alt 16.03.11, 16:16   #3 (permalink)
 
Registriert seit: 16.03.11
Tofuzius Leistung: Facit NTK
Likes: 0
Standard

Hi,

bin neu hier. Hab vor gut einem Monat mit Programmieren in C angefangen und bin seither ziemlich süchtig. 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;
}

Geändert von Tofuzius (17.03.11 um 07:35 Uhr) Grund: Hab noch Fehler in den Funktionen flaeche_von_schnittmengen und gib_schnittmenge_von gefunden und behoben.
Tofuzius ist offline   Mit Zitat antworten
Antwort
   

Werbung ist gerade online    

[HaBo] » Software Home » Code Kitchen » Programmieraufgaben » [leicht]Flächenberechnung von sich überlappenden/einschließenden Rechtecken
Themen-Optionen
Ansicht

Forumregeln
Es ist Ihnen nicht erlaubt, neue Themen zu verfassen.
Es ist Ihnen nicht erlaubt, auf Beiträge zu antworten.
Es ist Ihnen nicht erlaubt, Anhänge hochzuladen.
Es ist Ihnen nicht erlaubt, Ihre Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks sind aus
Pingbacks sind aus
Refbacks sind aus



1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61