Frage

Die Suche nach einem guten Weg, dies zu tun, hat mich schon seit einiger Zeit ratlos gemacht:Angenommen, ich habe ein Auswahlfeld mit einer Reihe von Punkten darin.Durch Ziehen der Ecken können Sie den (Abstand zwischen) Punkten im Feld skalieren.Bei einer achsenausgerichteten Box ist dies nun einfach.Nehmen Sie eine Ecke als Ankerpunkt (subtrahieren Sie diese Ecke von jedem Punkt, skalieren Sie sie und addieren Sie sie dann wieder zum Punkt) und multiplizieren Sie jeden Punkt x und y mit dem Faktor, mit dem die Box größer geworden ist.

Aber nun nehmen Sie eine Box, die nicht an der x- und y-Achse ausgerichtet ist.Wie skalieren Sie die Punkte innerhalb dieses Felds, wenn Sie an den Ecken ziehen?

War es hilfreich?

Lösung

Sie wählen eine Ecke des Rechtecks ​​als Ursprung.Die beiden damit verbundenen Kanten bilden die Basis (u Und v, die senkrecht zueinander stehen sollten).Sie müssten sie zuerst normalisieren.

Subtrahieren Sie den Ursprung von den Koordinaten und berechnen Sie das Skalarprodukt mit dem Skalierungsvektor (u) und mit dem anderen Vektor (v).Das würde Ihnen sagen, wie viel u Und v trägt zur Koordinate bei.

Anschließend skalieren Sie die gewünschte Komponente.Um die endgültige Koordinate zu erhalten, multiplizieren Sie einfach die (jetzt skalierten) Komponenten mit ihrem jeweiligen Vektor und addieren sie.

Zum Beispiel:

Points: p1 = (3,5) and p2 = (6,4)

Selection corners: (0,2),(8,0),(9,4),(1,6)
selected origin = (8,0)

u = ((0,2)-(8,0))/|(0,2)-(8,0)| = <-0.970, 0.242>
v = <-0.242, -0.970>

(v Ist u, aber mit umgekehrten Koordinaten und einer davon negiert)

p1´ = p1 - origin = (-5, 5)
p2´ = p2 - origin = (-2, 4)

p1_u = p1´ . u = -0.970 * (-5) + 0.242 * 5 = 6.063
p1_v = p1´ . v = -0.242 * (-5) - 0.970 * 5 = -3.638

Scale p1_u by 0.5: 3.038

p1_u * u + p1_v * v + origin = <5.941, 4.265>

Same for p2: <7.412, 3.647>

Wie Sie vielleicht sehen können, haben sie sich auf die Linie zubewegt (8,0)-(9,4), da wir um 0,5 skaliert haben, mit (0,8) als Ursprung.

Bearbeiten: Es stellte sich heraus, dass es etwas schwieriger zu erklären war, als ich erwartet hatte.

Im Python-Code könnte es etwa so aussehen:

def scale(points, origin, u, scale):
    # normalize
    len_u = (u[0]**2 + u[1]**2) ** 0.5
    u = (u[0]/len_u, u[1]/len_u)
    # create v
    v = (-u[1],u[0])
    ret = []
    for x,y in points:
        # subtract origin
        x, y = x - origin[0], y - origin[1]
        # calculate dot product
        pu = x * u[0] + y * u[1]
        pv = x * v[0] + y * v[1]
        # scale
        pu = pu * scale
        # transform back to normal space
        x = pu * u[0] + pv * v[0] + origin[0]
        y = pu * u[1] + pv * v[1] + origin[1]
        ret.append((x,y))
    return ret

>>> scale([(3,5),(6,4)],(8,0),(-8,2),0.5)
[(5.9411764705882355, 4.2647058823529411), (7.4117647058823533, 3.6470588235294117)]

Andere Tipps

Jede Box ist in einem Kreis enthalten sind.
Sie finden den Kreis, der die Box bindet, finden die Mitte und tun genau das gleiche wie Sie mit einer Achse ausgerichtet Feld tun.

Lassen Sie uns sagen, dass die Box als ein Satz von vier Punkten definiert ist (P1, P2, P3 und P4). Aus Gründen der Einfachheit, sagen wir Ihnen P1 schleppen, und dass P3 ist die gegenüberliegende Ecke (die Sie als Anker verwenden).

Lassen Sie uns die Mausposition als M beschriften, und die neuen Punkte, die Sie wollen, wie N1, N2 und N4 berechnen. P3 wird natürlich gleich bleiben.

kann Ihr Skalierungsfaktor einfach mit Vektor-Subtraktion und das Vektorpunktprodukt berechnet werden:

scale = ((M - P3) dot (P1 - P3)) / ((P1 - P3) dot (P1 - P3))

Und die drei neuen Punkte können unter Verwendung von skalaren Multiplikation und Vektoraddition zu finden:

N1 = scale*P1 + (1 - scale)*P3
N2 = scale*P2 + (1 - scale)*P3
N4 = scale*P4 + (1 - scale)*P3

bearbeiten: Ich sehe, dass MizardX die Frage bereits beantwortet hat, so meine Antwort hier mit dieser schwierigen Erklärung zu helfen. Ich hoffe, es hilft!

Bearbeiten: hier ist der Algorithmus für nicht-proportionale Skalierung. In diesem Fall N1 gleich M (der Punkt folgt die Maus gezogen wird), so dass die einzigen Punkte von Interesse sind, N2 und N4:

N2 = ((M - P3) dot (P2 - P3)) / ((P2 - P3) dot (P2 - P3)) * (P2 - P3) + P3
N4 = ((M - P3) dot (P4 - P3)) / ((P4 - P3) dot (P4 - P3)) * (P4 - P3) + P3

wobei * Skalarmultiplikation repräsentiert

bearbeiten: Hier sind einige C ++ Code, der die Frage beantwortet. Ich bin sicher, diese Frage ist schon lange tot jetzt, aber es war ein interessantes Problem, und ich hatte etwas Spaß, den Code zu schreiben.

#include <vector>

class Point
{
    public:
        float x;
        float y;
        Point() { x = y = 0; }
        Point(float nx, float ny) { x = nx; y = ny; }
};

Point& operator-(Point& A, Point& B) { return Point(A.x-B.x, A.y-B.y); }
Point& operator+(Point& A, Point& B) { return Point(A.x+B.x, A.y+B.y); }
Point& operator*(float sc, Point& P) { return Point(sc*P.x, sc*P.y); }

float dot_product(Point A, Point B) { return A.x*B.x + A.y*B.y; }

struct Rect { Point point[4]; };

void scale_points(Rect box, int anchor, Point mouse, vector<Point> points)
{
    Point& P3 = box.point[anchor];
    Point& P2 = box.point[(anchor + 1)%4];
    Point& P1 = box.point[(anchor + 2)%4];
    Point& P4 = box.point[(anchor + 3)%4];

    Point A = P4 - P3;
    Point aFactor = dot_product(mouse - P3, A) / dot_product(A, A) * A;

    Point B = P2 - P3;
    Point bFactor = dot_product(mouse - P3, B) / dot_product(B, B) * B;

    for (int i = 0; i < points.size(); i++)
    {
        Point P = points[i] - P3;
        points[i] = P3 + dot_product(P, aFactor) + dot_product(P, bFactor);
    }
}
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top