puntos funcion entre distancia coordenadas calcular python math graphics geometry

funcion - distancia entre dos puntos python 3



Encontrar puntos en un rectángulo en un ángulo dado (6)

Estoy tratando de dibujar un degradado en un objeto rectángulo, con un ángulo dado (Theta), donde los extremos del degradado tocan el perímetro del rectángulo.

Pensé que usar la tangente funcionaría, pero estoy teniendo problemas para solucionar los problemas. ¿Hay un algoritmo fácil que me estoy perdiendo?

Resultado final

Entonces, esto va a ser una función de (ángulo, RectX1, RectX2, RectY1, RectY2). Quiero que se devuelva en la forma de [x1, x2, y1, y2], para que el degradado se dibuje a través del cuadrado. En mi problema, si el origen es 0, entonces x2 = -x1 e y2 = -y1. Pero no siempre va a estar en el origen.


Hay una buena respuesta (más programática iOS / Objective-C) a esta pregunta en Encontrar el CGPoint en un rectángulo UIView intersecado por una línea recta en un ángulo dado desde el punto central que involucra los siguientes pasos:

  1. Supongamos que el ángulo es mayor o igual a 0 y menor que 2 * π, yendo en sentido contrario a las agujas del reloj desde 0 (Este).
  2. Obtenga la coordenada y de la intersección con el borde derecho del rectángulo [tan (ángulo) * ancho / 2].
  3. Compruebe si esta coordenada y está en el marco del rectángulo (valor absoluto menor o igual a la mitad de la altura).
  4. Si la intersección y está en el rectángulo, entonces si el ángulo es menor que π / 2 o mayor que 3π / 2, elija el borde derecho (ancho / 2, -y coordenada). De lo contrario, elija el borde izquierdo (-width / 2, y coord).
  5. Si la coordenada y de la intersección del borde derecho estaba fuera de los límites, calcule la coordenada x de la intersección con el borde inferior [la mitad de la altura / tan (ángulo)].
  6. A continuación, determine si desea el borde superior o el borde inferior. Si el ángulo es menor que π, queremos el borde inferior (x, mitad de la altura). De lo contrario, queremos el borde superior (-x coord, la mitad de la altura).
  7. Luego (si el centro del cuadro no es 0,0), desplace el punto con el centro real del cuadro.

Llamemos a yb a los lados de su rectángulo, y (x0, y0) las coordenadas de su centro del rectángulo.

Tienes que considerar cuatro regiones:

Region from to Where ==================================================================== 1 -arctan(b/a) +arctan(b/a) Right green triangle 2 +arctan(b/a) π-arctan(b/a) Upper yellow triangle 3 π-arctan(b/a) π+arctan(b/a) Left green triangle 4 π+arctan(b/a) -arctan(b/a) Lower yellow triangle

Con un poco de trigonometría-fu, podemos obtener las coordenadas para su intersección deseada en cada región.

Entonces Z0 es la expresión para el punto de intersección para las regiones 1 y 3
Y Z1 es la expresión del punto de intersección para las regiones 2 y 4

Las líneas deseadas pasan de (X0, Y0) a Z0 o Z1 según la región. Así que recordando que Tan (φ) = Sin (φ) / Cos (φ)

Lines in regions Start End ====================================================================== 1 and 3 (X0,Y0) (X0 + a/2 , (a/2 * Tan(φ))+ Y0 2 and 4 (X0,Y0) (X0 + b/(2* Tan(φ)) , b/2 + Y0)

Solo tenga en cuenta los signos de Tan (φ) en cada cuadrante, y que el ángulo siempre se mide desde EL POSITIVO x eje ANTICALIZADO.

HTH!


Ok whew , Finalmente tengo este

NOTA: Basé esto en la asombrosa respuesta de belisario. Si te gusta esto, por favor hazlo también. Todo lo que hice fue convertir lo que decía en código.

Esto es lo que parece en Objective-C. Debe ser lo suficientemente simple como para convertirlo a cualquiera que sea su idioma favorito.

+ (CGPoint) edgeOfView: (UIView*) view atAngle: (float) theta { // Move theta to range -M_PI .. M_PI const double twoPI = M_PI * 2.; while (theta < -M_PI) { theta += twoPI; } while (theta > M_PI) { theta -= twoPI; } // find edge ofview // Ref: http://.com/questions/4061576/finding-points-on-a-rectangle-at-a-given-angle float aa = view.bounds.size.width; // "a" in the diagram float bb = view.bounds.size.height; // "b" // Find our region (diagram) float rectAtan = atan2f(bb, aa); float tanTheta = tan(theta); int region; if ((theta > -rectAtan) && (theta <= rectAtan) ) { region = 1; } else if ((theta > rectAtan) && (theta <= (M_PI - rectAtan)) ) { region = 2; } else if ((theta > (M_PI - rectAtan)) || (theta <= -(M_PI - rectAtan)) ) { region = 3; } else { region = 4; } CGPoint edgePoint = view.center; float xFactor = 1; float yFactor = 1; switch (region) { case 1: yFactor = -1; break; case 2: yFactor = -1; break; case 3: xFactor = -1; break; case 4: xFactor = -1; break; } if ((region == 1) || (region == 3) ) { edgePoint.x += xFactor * (aa / 2.); // "Z0" edgePoint.y += yFactor * (aa / 2.) * tanTheta; } else // region 2 or 4 { edgePoint.x += xFactor * (bb / (2. * tanTheta)); // "Z1" edgePoint.y += yFactor * (bb / 2.); } return edgePoint; }

Además, aquí hay una pequeña vista de prueba que creé para verificar que funciona. Crea esta vista y colócala en algún lugar, hará que otra pequeña vista se desplace alrededor del borde.

@interface DebugEdgeView() { int degrees; UIView *dotView; NSTimer *timer; } @end @implementation DebugEdgeView - (void) dealloc { [timer invalidate]; } - (id) initWithFrame: (CGRect) frame { self = [super initWithFrame: frame]; if (self) { self.backgroundColor = [[UIColor magentaColor] colorWithAlphaComponent: 0.25]; degrees = 0; self.clipsToBounds = NO; // create subview dot CGRect dotRect = CGRectMake(frame.size.width / 2., frame.size.height / 2., 20, 20); dotView = [[DotView alloc] initWithFrame: dotRect]; dotView.backgroundColor = [UIColor magentaColor]; [self addSubview: dotView]; // move it around our edges timer = [NSTimer scheduledTimerWithTimeInterval: (5. / 360.) target: self selector: @selector(timerFired:) userInfo: nil repeats: YES]; } return self; } - (void) timerFired: (NSTimer*) timer { float radians = ++degrees * M_PI / 180.; if (degrees > 360) { degrees -= 360; } dispatch_async(dispatch_get_main_queue(), ^{ CGPoint edgePoint = [MFUtils edgeOfView: self atAngle: radians]; edgePoint.x += (self.bounds.size.width / 2.) - self.center.x; edgePoint.y += (self.bounds.size.height / 2.) - self.center.y; dotView.center = edgePoint; }); } @end


Para Java, LibGDX. He dejado que el ángulo sea un doble para aumentar la precisión.

public static Vector2 projectToRectEdge(double angle, float width, float height, Vector2 out) { return projectToRectEdgeRad(Math.toRadians(angle), width, height, out); } public static Vector2 projectToRectEdgeRad(double angle, float width, float height, Vector2 out) { float theta = negMod((float)angle + MathUtils.PI, MathUtils.PI2) - MathUtils.PI; float diag = MathUtils.atan2(height, width); float tangent = (float)Math.tan(angle); if (theta > -diag && theta <= diag) { out.x = width / 2f; out.y = width / 2f * tangent; } else if(theta > diag && theta <= MathUtils.PI - diag) { out.x = height / 2f / tangent; out.y = height / 2f; } else if(theta > MathUtils.PI - diag && theta <= MathUtils.PI + diag) { out.x = -width / 2f; out.y = -width / 2f * tangent; } else { out.x = -height / 2f / tangent; out.y = -height / 2f; } return out; }


Siguiendo tu foto, asumiré que el rectángulo está centrado en (0,0) y que la esquina superior derecha es (w, h). Luego, la línea que conecta (0,0) a (w, h) forma un ángulo φ con el eje X, donde tan (φ) = h / w.

Suponiendo que θ> φ, estamos buscando el punto (x, y) donde la línea que ha dibujado se interseca con el borde superior del rectángulo. Entonces y / x = tan (θ). Sabemos que y = h, resolviendo para x, obtenemos x = h / tan (θ).

Si θ <φ, la línea se interseca con el borde derecho del rectángulo en (x, y). Esta vez, sabemos que x = w, entonces y = tan (θ) * w.


Versión de Javascript:

function edgeOfView(rect, deg) { var twoPI = Math.PI*2; var theta = deg * Math.PI / 180; while (theta < -Math.PI) { theta += twoPI; } while (theta > Math.PI) { theta -= twoPI; } var rectAtan = Math.atan2(rect.height, rect.width); var tanTheta = Math.tan(theta); var region; if ((theta > -rectAtan) && (theta <= rectAtan)) { region = 1; } else if ((theta > rectAtan) && (theta <= (Math.PI - rectAtan))) { region = 2; } else if ((theta > (Math.PI - rectAtan)) || (theta <= -(Math.PI - rectAtan))) { region = 3; } else { region = 4; } var edgePoint = {x: rect.width/2, y: rect.height/2}; var xFactor = 1; var yFactor = 1; switch (region) { case 1: yFactor = -1; break; case 2: yFactor = -1; break; case 3: xFactor = -1; break; case 4: xFactor = -1; break; } if ((region === 1) || (region === 3)) { edgePoint.x += xFactor * (rect.width / 2.); // "Z0" edgePoint.y += yFactor * (rect.width / 2.) * tanTheta; } else { edgePoint.x += xFactor * (rect.height / (2. * tanTheta)); // "Z1" edgePoint.y += yFactor * (rect.height / 2.); } return edgePoint; };