Ich schreibe gerade eine Funktion, um den Schnittpunkt eines Rechtecks mit einer Superellipse zu testen. Das Rechteck wird immer achsversetzt sein, während die Superellipse mit einem Drehwinkel alpha ausgerichtet sein kann.Algorithmus zum Erkennen von Überschneidungen zwischen einem achsenausgerichteten Rechteck und einer orientierten Superellipse
Im Falle eines achsausgerichteten Rechtecks, das eine achsenbündige Superellipse schneidet, habe ich diese zwei kurzen Funktionen geschrieben, die wunderbar funktionieren. Der Code ist prägnant, klar und effizient. Wenn möglich, möchte ich eine ähnliche Struktur für die neue allgemeinere Funktion beibehalten. Hier
ist, was ich habe zu erkennen, ob eine Achse ausgerichtetes Rechteck eine Achse ausgerichtete Superellipse schneidet:
double fclamp(double x, double min, double max)
{
if (x <= min) return min;
if (x >= max) return max;
return x;
}
bool rect_intersects_superellipse(const t_rect *rect, double cx, double cy, double rx, double ry, double exponent)
{
t_pt closest;
closest.x = fclamp(cx, rect->x, rect->x + rect->width);
closest.y = fclamp(cy, rect->y, rect->y + rect->height);
return point_inside_superellipse(&closest, cx, cy, rx, ry, exponent);
}
bool point_inside_superellipse(const t_pt *pt, double cx, double cy, double rx, double ry, double exponent)
{
double dx = fabs(pt->x - cx);
double dy = fabs(pt->y - cy);
double dxp = pow(dx, exponent);
double dyp = pow(dy, exponent);
double rxp = pow(rx, exponent);
double ryp = pow(ry, exponent);
return (dxp * ryp + dyp * rxp) <= (rxp * ryp);
}
Dies funktioniert korrekt, aber - wie gesagt - nur für eine Achse ausgerichtet Superellipse.
Jetzt möchte ich es zu einer orientierten Superellipse verallgemeinern, wobei ich die Algorithmusstruktur so nahe wie möglich an das obige halte. Die offensichtliche Erweiterung der bisherigen zwei Funktionen dann so etwas wie werden würde:
bool rect_intersects_oriented_superellipse(const t_rect *rect, double cx, double cy, double rx, double ry, double exponent, double radians)
{
t_pt closest;
closest.x = fclamp(cx, rect->x, rect->x + rect->width);
closest.y = fclamp(cy, rect->y, rect->y + rect->height);
return point_inside_oriented_superellipse(&closest, cx, cy, rx, ry, exponent, radians);
}
bool point_inside_oriented_superellipse(const t_pt *pt, double cx, double cy, double rx, double ry, double exponent, double radians)
{
double dx = pt->x - cx;
double dy = pt->y - cy;
if (radians) {
double c = cos(radians);
double s = sin(radians);
double new_x = dx * c - dy * s;
double new_y = dx * s + dy * c;
dx = new_x;
dy = new_y;
}
double dxp = pow(fabs(dx), exponent);
double dyp = pow(fabs(dy), exponent);
double rxp = pow(rx, exponent);
double ryp = pow(ry, exponent);
return (dxp * ryp + dyp * rxp) < (rxp * ryp);
}
Für eine orientierte Superellipse, wird die oben nicht korrekt funktionieren, obwohl point_inside_oriented_superellipse()
von selbst wie erwartet funktioniert. Ich kann die obigen Funktionen nicht verwenden, um auf einen Schnittpunkt mit einem achsausgerichteten Rechteck zu testen. Ich habe seit ungefähr einer Woche online geforscht und ich habe einige Lösungen gefunden, die eine inverse Matrixtransformation erfordern, um die Superellipsenachsen auszugleichen und ihren Ursprung bei (0, 0) zu bringen. Der Nachteil ist, dass jetzt mein Rechteck kein Rechteck mehr ist und sicher nicht achsversetzt. Ich möchte es vermeiden, diesen Weg zu gehen. Meine Frage ist zu zeigen, wie man den obigen Algorithmus arbeiten lässt und seine Struktur mehr oder weniger unverändert behält. Wenn es nicht möglich ist, dieselbe algorithmische Struktur beizubehalten, zeigen Sie bitte den einfachsten und effizientesten Algorithmus, um den Schnittpunkt zwischen einem achsausgerichteten Rechteck und einer orientierten Superellipse zu testen. Ich muss nur wissen, ob der Schnittpunkt aufgetreten ist oder nicht (boolesches Ergebnis). Der Bereich des Exponentenparameters kann von 0,25 bis 100,0 variieren.
Vielen Dank für Ihre Hilfe.
Sind Sie sicher, dass Ihre Methode funktioniert? Sie testen nur die Eckpunkte des Rechtecks, ja? Aber selbst für einen Kreis könnten Sie den Kreis und das Rechteck schneiden, ohne dass sich die Ecken im Kreis befinden. – dmuir
Für eine achsenbündige Superellipse - ja - ich bin mir sicher, dass meine Methode so funktioniert, wie sie sollte. Ich habe es gründlich getestet und benutze es die ganze Zeit. Nein, ich teste nicht nur die Rechteckscheitelpunkte. Der Code ist dort, bitte versuchen Sie es selbst und sehen Sie ... –