[ Trigonometrie ] - absolute Höhe und Breite einer rotierten Box berechnen

Tobias Menzel

Erfahrenes Mitglied
Hallo,

ich arbeite an einer Flashanwendung und komme nicht auf den richtigen Ansatz für folgendes Problem:

Ich habe ein Rechteck, das um einen beliebigen Winkel gedreht werden kann (die Maße des Rechtecks an sich sind bekannt). Dabei muss das rotierte Rechteck in einen definierten (ebenfalls rechteckigen) Bereich passen (Breite und Höhe müssen angepasst werden, damit die Grenzen des Rahmens nicht überschritten werden - dabei muss das Seitenverhältnis allerdings bestehen bleiben).

Es geht mir um die Formel, die ich zur Berechnung des Skalierungsfaktors verwenden kann, wenn Rotationswinkel, Originalmaße der rotierten Form und Maße des Rahmens bekannt sind. Im Anhang befindet sich eine kleine Grafik zur Verdeutlichung.

Eigentlich sollte das Problem mit einigen Winkelfunktionen leicht zu lösen sein, aber ich habe mich irgendwie "festgebissen". ;)

Grüße,

Tobi
 

Anhänge

  • rotation.jpg
    rotation.jpg
    14 KB · Aufrufe: 251
Zuletzt bearbeitet:

vop

Erfahrenes Mitglied
Hmm

meine ersten Versuche liefern bei Rotation um Winkel alpha im Uhrzeigersinn:

Neue Höhe = Breite * sin ( alpha ) + Höhe * sin (180-alpha)

Neue Breite = Breite * cos (alpha ) + Höhe * cos (180-alpha)


Check doch mal
Gruß Vop
 

Tobias Menzel

Erfahrenes Mitglied
Hi,

danke erstmal für die Antwort - Dein Ansatz zeigt allerdings (wenn ich ihn korrekt umgesetzt habe) bemerkenswerte Ergebnisse (siehe: http://www.menzel-webmedien.de/tutorials/trial1.html).

Ich denke auch, mann braucht eine Fallunterscheidung, da je nach Winkel und Seitenverhältnis die Maße der inneren Box von den vertikalen oder den horizontalen Kanten des Rahmens begrenzt werden.

Zudem brauche ich im Prinzip einen Skalierungsfaktor, den ich sowohl auf die Breite als auch auf Höhe anwende; zwei Werte, die nicht in einem konstanten Verhältnis stehen, nützen leider nichts.

Vielleicht bin ich aber auch einfach nur zu müde, um das offensichtliche zu sehen. :-(

Grüße,

Tobi
 

Thomas Darimont

Erfahrenes Mitglied
Hallo,

schau mal hier:
Java:
/**
 * 
 */
package de.tutorials;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

import javax.swing.JFrame;

/**
 * @author Tom
 */
public class BoundingBoxExample extends JFrame {

  Box box;
  Runnable renderLoop = new Runnable() {
    public void run() {

      int angleInDegrees = 0;

      while (true) {

        angleInDegrees = ( ++angleInDegrees % 360);

        Graphics2D g = (Graphics2D) getBufferStrategy().getDrawGraphics();
        g.clearRect(0, 0, 400, 300);
        Point center = box.getCenter();

        Box boundingBox = createBoundingBoxFor(box, angleInDegrees);
        g.setColor(Color.RED);
        boundingBox.paint(g);

        g.rotate(Math.toRadians(angleInDegrees), center.x, center.y);

        g.setColor(Color.BLACK);
        box.paint(g);

        g.dispose();
        getBufferStrategy().show();

        try {
          TimeUnit.MILLISECONDS.sleep(10);
        } catch (InterruptedException e) {
          e.printStackTrace();
        }
      }
    }
  };


  public BoundingBoxExample() {
    super("BoundingBoxExample");
    setDefaultCloseOperation(EXIT_ON_CLOSE);
    setSize(400, 300);
    box = new Box(150, 90, 50, 75);
    setVisible(true);
    createBufferStrategy(2);
    Executors.newSingleThreadExecutor().execute(renderLoop);
  }


  protected Box createBoundingBoxFor(Box theBox, int angleInDegrees) {
    Point center = theBox.getCenter();

    int newWidth = 0;
    int newHeight = 0;

    if (angleInDegrees == 0 || angleInDegrees == 180) {
      newWidth = theBox.width;
      newHeight = theBox.height;
      return new Box(center.x - newWidth / 2, center.y - newHeight / 2, newWidth, newHeight);
    } else if (angleInDegrees == 90 || angleInDegrees == 270) {
      newWidth = theBox.height;
      newHeight = theBox.width;
      return new Box(center.x - newWidth / 2, center.y - newHeight / 2, newWidth, newHeight);
    } else {
      double angleInRadians = Math.toRadians(angleInDegrees);
      double widthA = Math.abs(Math.cos(angleInRadians) * theBox.width);
      double widthB = Math.abs(Math.sin(angleInRadians) * theBox.width);
      double heightA = Math.abs(Math.cos(angleInRadians) * theBox.height);
      double heightB = Math.abs(Math.sin(angleInRadians) * theBox.height);
      newWidth = (int) (widthA + heightB);
      newHeight = (int) (widthB + heightA);
      return new Box(center.x - newWidth / 2, center.y - newHeight / 2, newWidth, newHeight);
    }
  }


  /**
   * @param args
   */
  public static void main(String[] args) {
    new BoundingBoxExample();
  }

  static class Box {

    int x;
    int y;

    int width;
    int height;


    public Box(int x, int y, int width, int height) {
      this.x = x;
      this.y = y;
      this.width = width;
      this.height = height;
    }


    public void paint(Graphics g) {
      g.fillRect(x, y, width, height);
    }


    public Point getCenter() {
      return new Point(x + width / 2, y + height / 2);
    }
  }
}

Gruß Tom
 

Anhänge

  • trigo.jpg
    trigo.jpg
    5,4 KB · Aufrufe: 237

Tobias Menzel

Erfahrenes Mitglied
Java:
double widthA = Math.abs(Math.cos(angleInRadians) * theBox.width);
double widthB = Math.abs(Math.sin(angleInRadians) * theBox.width);
double heightA = Math.abs(Math.cos(angleInRadians) * theBox.height);
double heightB = Math.abs(Math.sin(angleInRadians) * theBox.height);
newWidth = (int) (widthA + heightB);
newHeight = (int) (widthB + heightA);
Yeah! Das scheint's tatsächlich zu sein. :)

Ich habe ewig mit ähnlichen (aber nur ähnlichen) Setups herumprobiert, bin aber zu nichts gekommen (und ehrlich gesagt wusste ich auch nicht, unter welchen Stichpunkten ich hätte nachschlagen können). Danke Dir.

Grüße,

Tobi

NACHTRAG: Ich habe das Beispiel noch so angepasst, dass a) das Seitenverhältnis konstant bleibt und b) das ganze für Hoch- und Querformate läuft:
Code:
function reScale(rotationInDegrees, originalWidth, originalHeight, objectToScale) {
	var ratio = originalWidth / originalHeight;
	if (rotationInDegrees < 0) rotationInDegrees += 360;
	if (rotationInDegrees == 0 || rotationInDegrees == 180) {
		var nw = originalWidth;
		var nh = nw / ratio;
	} else if (rotationInDegrees == 90 || rotationInDegrees == 270) {
		if (ratio < 1) {
			var nh = originalWidth;
			var nw = nh * ratio;
		} else {
			var nw = originalHeight;
			var nh = nw / ratio;
		}
	} else {
		var ang = rotationInDegrees * Math.PI / 180;
		var w1 = Math.abs(Math.cos(ang) * originalWidth);
		var w2 = Math.abs(Math.sin(ang) * originalWidth);
		var h1 = Math.abs(Math.cos(ang) * originalHeight);
		var h2 = Math.abs(Math.sin(ang) * originalHeight);
		var nw = Math.round(w1 + h2);
		var nh = Math.round(w2 + h1);
		if (ratio < 1) {
			nw = Math.pow(originalWidth, 2) / nw;
			nh = nw / ratio;
		} else {
			nh = Math.pow(originalHeight, 2) / nh;
			nw = nh * ratio;
		}
	}
	objectToScale._width = nw;
	objectToScale._height = nh;
}
.
 

Tobias Menzel

Erfahrenes Mitglied
Hi,

das Endergebnis kann ich (noch) nicht zeigen, da es sich um eine (kommerzielle) Auftragsarbeit handelt. Dass es klappt, kann man allerdings hier (klick) betrachten. :)

Dein Code macht im Original eigentlich genau das Gegenteil von dem, was mir vorschwebte (siehe hier (klick) ) ;) - er passt die Maße des Rahmens so an, dass die innere Box hineinpasst.

Was ich nun noch bräuchte, wäre eigentlich folgendes: Der äußere Rahmen bleibt konstant, wärend die innere Box rotiert wird, und dabei (unter Mißachtung des Seitenverhältnisses) die maximal verfügbare Fläche annimmt, ohne die Grenzen des Rahmens zu schneiden.

Ich bin allerdings zuversichtlich, dass ich das selbst hinbekomme - notfalls melde ich mich noch einmal.

Grüße,

Tobi
 

hujange07

Grünschnabel
[ Trigonometrie ] -

Also, ich brauche driiingends schnell eure hilfe

folgendes: wie kann man rechteck, parallelogramm und trapez in sin, cos und tan berechnen ? :confused: ich meine die winkel/seiten !!

bitte, gaaaanz schnell hab do sa !! :google:

lg :)

Edit Mod: Bitte beachte beim Verfassen von Beiträgen Punkt 15 unserer Netiquette. Das schließt korrekte Groß- und Kleinschreibung sowie Ortographie ein - von Text in Größe 7, der kursiv, fett und unterstrichen dargestellt wird, ist dort nicht die Rede. Danke!
 
Zuletzt bearbeitet von einem Moderator:
Rechteck, Parallelogramm, Trapez

Abgesehen davon können wir alle mit unseren Browsern recht gut umgehen. Wenn uns also ein Text zu klein ist, können wir den schon selber größer darstellen lassen. Du musst also nicht aus Rücksicht auf die sehschwachen Benutzer von tutorials.de in einer überdimensionierten Schriftgröße schreiben.

Grüße,
Matthias