Domanda

Ho le coordinate del punto in alto a sinistra di un rettangolo, nonché la sua larghezza, altezza e rotazione da 0 a 180 e da -0 a -180.

Sto cercando di ottenere le coordinate di delimitazione della casella effettiva attorno al rettangolo.

Che cos'è un modo semplice per calcolare le coordinate del rettangolo di selezione

  • Min y, max y, min x, max x?

Il punto A non è sempre sul limite minimo, può essere ovunque.

Posso usare matrix il trasformatore toolkit in as3 se necessario.

È stato utile?

Soluzione

  • Trasforma le coordinate di tutti e quattro gli angoli
  • Trova la più piccola di tutte e quattro le x come min_x
  • Trova la più grande di tutte e quattro le x e chiamala max_x
  • Idem con le y
  • Il rettangolo di selezione è (min_x, min_y), (min_x, max_y), (max_x, max_y), (max_x, min_y)

AFAIK, non esiste una strada reale che ti porterà molto più velocemente.

Se ti stai chiedendo come trasformare le coordinate, prova:

x2 = x0+(x-x0)*cos(theta)+(y-y0)*sin(theta)
y2 = y0-(x-x0)*sin(theta)+(y-y0)*cos(theta)

dove (x0, y0) è il centro attorno al quale si sta ruotando. Potrebbe essere necessario armeggiare con questo a seconda delle funzioni di innesco (si aspettano gradi o radianti) il senso / segno del sistema di coordinate rispetto al modo in cui si specificano gli angoli, ecc.

Altri suggerimenti

Mi rendo conto che stai chiedendo ActionScript ma, nel caso in cui qualcuno arrivi qui alla ricerca della risposta iOS o OS-X, è questo:

+ (CGRect) boundingRectAfterRotatingRect: (CGRect) rect toAngle: (float) radians
{
    CGAffineTransform xfrm = CGAffineTransformMakeRotation(radians);
    CGRect result = CGRectApplyAffineTransform (rect, xfrm);

    return result;
}

Se il tuo sistema operativo si offre di fare tutto il duro lavoro per te, fallo! :)

Swift:

func boundingRectAfterRotatingRect(rect: CGRect, toAngle radians: CGFloat) -> CGRect {
    let xfrm = CGAffineTransformMakeRotation(radians)
    return CGRectApplyAffineTransform (rect, xfrm)
}

Il metodo delineato da MarkusQ funziona perfettamente, ma tieni presente che non è necessario trasformare gli altri tre angoli se hai già il punto A.

Un metodo alternativo, che è più efficiente, è testare in quale quadrante si trova l'angolo di rotazione e quindi semplicemente calcolare direttamente la risposta. Questo è più efficiente in quanto hai solo il caso peggiore di due istruzioni if ??(controllando l'angolo) mentre l'altro approccio ha il caso peggiore di dodici (6 per ogni componente quando controlla gli altri tre angoli per vedere se sono maggiori della corrente massimo o inferiore all'attuale minimo) penso.

L'algoritmo di base, che non utilizza altro che una serie di applicazioni del teorema di Pitagora, è mostrato di seguito. Ho indicato l'angolo di rotazione di theta ed ho espresso il segno di spunta in gradi in quanto è pseudo-codice.

ct = cos( theta );
st = sin( theta );

hct = h * ct;
wct = w * ct;
hst = h * st;
wst = w * st;

if ( theta > 0 )
{
    if ( theta < 90 )
    {
        // 0 < theta < 90
        y_min = A_y;
        y_max = A_y + hct + wst;
        x_min = A_x - hst;
        x_max = A_x + wct;
    }
    else
    {
        // 90 <= theta <= 180
        y_min = A_y + hct;
        y_max = A_y + wst;
        x_min = A_x - hst + wct;
        x_max = A_x;
    }
}
else
{
    if ( theta > -90 )
    {
        // -90 < theta <= 0
        y_min = A_y + wst;
        y_max = A_y + hct;
        x_min = A_x;
        x_max = A_x + wct - hst;
    }
    else
    {
        // -180 <= theta <= -90
        y_min = A_y + wst + hct;
        y_max = A_y;
        x_min = A_x + wct;
        x_max = A_x - hst;
    }
}

Questo approccio presuppone che tu abbia ciò che dici di avere, cioè il punto A e un valore per theta compreso nell'intervallo [-180, 180]. Ho anche supposto che il theta aumenti in senso orario poiché questo è ciò che il rettangolo che è stato ruotato di 30 gradi nel diagramma sembra indicare che stai usando, non ero sicuro di ciò che la parte a destra stava cercando di indicare. Se questo è il modo sbagliato, basta scambiare le clausole simmetriche e anche il segno dei termini di st.

    fitRect: function( rw,rh,radians ){
            var x1 = -rw/2,
                x2 = rw/2,
                x3 = rw/2,
                x4 = -rw/2,
                y1 = rh/2,
                y2 = rh/2,
                y3 = -rh/2,
                y4 = -rh/2;

            var x11 = x1 * Math.cos(radians) + y1 * Math.sin(radians),
                y11 = -x1 * Math.sin(radians) + y1 * Math.cos(radians),
                x21 = x2 * Math.cos(radians) + y2 * Math.sin(radians),
                y21 = -x2 * Math.sin(radians) + y2 * Math.cos(radians), 
                x31 = x3 * Math.cos(radians) + y3 * Math.sin(radians),
                y31 = -x3 * Math.sin(radians) + y3 * Math.cos(radians),
                x41 = x4 * Math.cos(radians) + y4 * Math.sin(radians),
                y41 = -x4 * Math.sin(radians) + y4 * Math.cos(radians);

            var x_min = Math.min(x11,x21,x31,x41),
                x_max = Math.max(x11,x21,x31,x41);

            var y_min = Math.min(y11,y21,y31,y41);
                y_max = Math.max(y11,y21,y31,y41);

            return [x_max-x_min,y_max-y_min];
        }

se stai usando GDI +, puoi creare un nuovo GrpaphicsPath - > Aggiungi punti o forme ad esso - > Applica rotazione trasformazione - > usa GraphicsPath.GetBounds () e restituirà un rettangolo che delimita la tua forma ruotata.

(modifica) Esempio VB.Net

Public Shared Sub RotateImage(ByRef img As Bitmap, degrees As Integer)
' http://stackoverflow.com/questions/622140/calculate-bounding-box-coordinates-from-a-rotated-rectangle-picture-inside#680877
'
Using gp As New GraphicsPath
  gp.AddRectangle(New Rectangle(0, 0, img.Width, img.Height))

  Dim translateMatrix As New Matrix
  translateMatrix.RotateAt(degrees, New PointF(img.Width \ 2, img.Height \ 2))
  gp.Transform(translateMatrix)

  Dim gpb = gp.GetBounds

  Dim newwidth = CInt(gpb.Width)
  Dim newheight = CInt(gpb.Height)

  ' http://www.codeproject.com/Articles/58815/C-Image-PictureBox-Rotations
  '
  Dim rotatedBmp As New Bitmap(newwidth, newheight)

  rotatedBmp.SetResolution(img.HorizontalResolution, img.VerticalResolution)

  Using g As Graphics = Graphics.FromImage(rotatedBmp)
    g.Clear(Color.White)
    translateMatrix = New Matrix
    translateMatrix.Translate(newwidth \ 2, newheight \ 2)
    translateMatrix.Rotate(degrees)
    translateMatrix.Translate(-img.Width \ 2, -img.Height \ 2)
    g.Transform = translateMatrix
    g.DrawImage(img, New PointF(0, 0))
  End Using
  img.Dispose()
  img = rotatedBmp
End Using

End Sub

Sebbene Code Guru abbia dichiarato il metodo GetBounds (), ho notato che la domanda è taggata come3, flex, quindi ecco uno snippet che illustra l'idea.

var box:Shape = new Shape();
box.graphics.beginFill(0,.5);
box.graphics.drawRect(0,0,100,50);
box.graphics.endFill();
box.rotation = 20;
box.x = box.y = 100;
addChild(box);

var bounds:Rectangle = box.getBounds(this);

var boundingBox:Shape = new Shape();
boundingBox.graphics.lineStyle(1);
boundingBox.graphics.drawRect(bounds.x,bounds.y,bounds.width,bounds.height);
addChild(boundingBox);

Ho notato che esistono due metodi che sembrano fare la stessa cosa: getBounds () e getRect ()

/**
     * Applies the given transformation matrix to the rectangle and returns
     * a new bounding box to the transformed rectangle.
     */
    public static function getBoundsAfterTransformation(bounds:Rectangle, m:Matrix):Rectangle {
        if (m == null) return bounds;

        var topLeft:Point = m.transformPoint(bounds.topLeft);
        var topRight:Point = m.transformPoint(new Point(bounds.right, bounds.top));
        var bottomRight:Point = m.transformPoint(bounds.bottomRight);
        var bottomLeft:Point = m.transformPoint(new Point(bounds.left, bounds.bottom));

        var left:Number = Math.min(topLeft.x, topRight.x, bottomRight.x, bottomLeft.x);
        var top:Number = Math.min(topLeft.y, topRight.y, bottomRight.y, bottomLeft.y);
        var right:Number = Math.max(topLeft.x, topRight.x, bottomRight.x, bottomLeft.x);
        var bottom:Number = Math.max(topLeft.y, topRight.y, bottomRight.y, bottomLeft.y);
        return new Rectangle(left, top, right - left, bottom - top);
    }

Applica la matrice di rotazione ai tuoi punti d'angolo. Quindi utilizzare il minimo / massimo rispettivamente delle coordinate x, y ottenute per definire il nuovo riquadro di delimitazione.

Ecco tre funzioni delle mie librerie open source. Le funzioni sono completamente testate in Java ma le formule possono essere facilmente tradotte in qualsiasi lingua.

Le firme sono:

float statico pubblico getAngleFromPoint (final Point centerPoint, final Point touchPoint)

float statico pubblico getTwoFingerDistance (float firstTouchX, float firstTouchY, float secondTouchX, float secondTouchY)

Point getPointFromAngle (doppio angolo finale, doppio raggio finale)

Questa soluzione presuppone che la densità dei pixel sia uniformemente distanziata. Prima di ruotare l'oggetto, procedi come segue:

  1. Usa getAngleFromPoint per calcolare l'angolo dal centro all'angolo in alto a destra (diciamo che questo restituisce 20 gradi), il che significa che l'angolo in alto a sinistra è di -20 gradi o 340 gradi.

  2. Utilizzare getTwoFingerDistance per restituire la distanza diagonale tra il punto centrale e l'angolo in alto a destra (questa distanza dovrebbe essere ovviamente uguale per tutti gli angoli, questa distanza verrà utilizzata nel prossimo calcolo).

  3. Ora diciamo che ruotiamo l'oggetto in senso orario di 30 gradi. Ora sappiamo che l'angolo in alto a destra deve essere a 50 gradi e l'angolo in alto a sinistra a 10 gradi.

  4. Ora dovresti essere in grado di usare la funzione getPointFromAngle nell'angolo in alto a sinistra e in alto a destra. utilizzando il raggio restituito dal passaggio 2. La posizione X moltiplicata per 2 dall'angolo in alto a destra dovrebbe darti la nuova larghezza e la posizione Y i tempi 2 dall'angolo in alto a sinistra dovrebbero dare la nuova altezza.

Questi sopra 4 passaggi dovrebbero essere messi in condizioni in base a quanto lontano hai ruotato il tuo oggetto in altro modo puoi restituire l'altezza come larghezza e la larghezza come altezza.

Ricorda che le funzioni angolari sono espresse in fattori 0-1 anziché 0-360 (basta moltiplicare o dividere per 360 se del caso):

// Ottiene un angolo da due punti espresso come fattore 0 -1 (0 è 0/360, 0,25 è 90 gradi ecc.)

public float getAngleFromPoint(final Point centerPoint, final Point touchPoint) {

    float returnVal = 0;

    //+0 - 0.5
    if(touchPoint.x > centerPoint.x) {

        returnVal = (float) (Math.atan2((touchPoint.x - centerPoint.x), (centerPoint.y - touchPoint.y)) * 0.5 / Math.PI);

    }
    //+0.5
    else if(touchPoint.x < centerPoint.x) {

        returnVal = (float) (1 - (Math.atan2((centerPoint.x - touchPoint.x), (centerPoint.y - touchPoint.y)) * 0.5 / Math.PI));

    }//End if(touchPoint.x > centerPoint.x)

    return returnVal;

}

// Misura la distanza diagonale tra due punti

public float getTwoFingerDistance(final float firstTouchX, final float firstTouchY, final float secondTouchX, final float secondTouchY) {

    float pinchDistanceX = 0;
    float pinchDistanceY = 0;

    if(firstTouchX > secondTouchX) {

        pinchDistanceX = Math.abs(secondTouchX - firstTouchX);

    }
    else if(firstTouchX < secondTouchX) {

        pinchDistanceX = Math.abs(firstTouchX - secondTouchX);

    }//End if(firstTouchX > secondTouchX)

    if(firstTouchY > secondTouchY) {

        pinchDistanceY = Math.abs(secondTouchY - firstTouchY);

    }
    else if(firstTouchY < secondTouchY) {

        pinchDistanceY = Math.abs(firstTouchY - secondTouchY);

    }//End if(firstTouchY > secondTouchY)

    if(pinchDistanceX == 0 && pinchDistanceY == 0) {

        return 0;

    }
    else {

        pinchDistanceX = (pinchDistanceX * pinchDistanceX);
        pinchDistanceY = (pinchDistanceY * pinchDistanceY);
        return (float) Math.abs(Math.sqrt(pinchDistanceX + pinchDistanceY));

    }//End if(pinchDistanceX == 0 && pinchDistanceY == 0)

}

// Ottieni coordinate XY da un angolo dato un raggio (l'angolo è espresso in un fattore 0-1 0 che è 0/360 gradi e 0,75 che è 270 ecc.)

public Point getPointFromAngle(final double angle, final double radius) {

    final Point coords = new Point();
    coords.x = (int) (radius * Math.sin((angle) * 2 * Math.PI));
    coords.y = (int) -(radius * Math.cos((angle) * 2 * Math.PI));

    return coords;

}

Questi frammenti di codice provengono dalle mie librerie open source: https://bitbucket.org/warwick/hgdialrepo e https://bitbucket.org/warwick/hacergestov2 . Uno è una libreria di gesti per Android e l'altro è un controllo di composizione per Android. Esiste anche un'implementazione OpenGLES 2.0 del controllo dial su: https://bitbucket.org/warwick/hggldial

Non sono sicuro di aver capito, ma una matrice di trasformazione composta ti fornirà le nuove coordinate per tutti i punti in questione. Se ritieni che il rettangolo possa fuoriuscire dall'area immaginabile dopo la trasformazione, applica un tracciato di ritaglio.

Nel caso in cui non si abbia familiarità con la definizione esatta delle matrici, consultare qui .

Ho usato Regione per prima cosa ruotando il rettangolo e poi ho usato quella regione ruotata per rilevare quel rettangolo

        r = new Rectangle(new Point(100, 200), new Size(200, 200));         
        Color BorderColor = Color.WhiteSmoke;
        Color FillColor = Color.FromArgb(66, 85, 67);
        int angle = 13;
        Point pt = new Point(r.X, r.Y);
        PointF rectPt = new PointF(r.Left + (r.Width / 2),
                               r.Top + (r.Height / 2));
       //declare myRegion globally 
        myRegion = new Region(r);

        // Create a transform matrix and set it to have a 13 degree

        // rotation.
        Matrix transformMatrix = new Matrix();
        transformMatrix.RotateAt(angle, pt);

        // Apply the transform to the region.
        myRegion.Transform(transformMatrix);
        g.FillRegion(Brushes.Green, myRegion);
        g.ResetTransform();

ora per rilevare quel rettangolo

        private void panel_MouseMove(object sender, MouseEventArgs e)
    {


        Point point = e.Location;
        if (myRegion.IsVisible(point, _graphics))
        {
            // The point is in the region. Use an opaque brush.
            this.Cursor = Cursors.Hand;
        }
        else {
            this.Cursor = Cursors.Cross;
        }

    }
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top