确定从切线到椭圆的反射矢量

Determining reflection vector from tangent to ellipse

我在椭圆内部发射了一条光线,它需要反射出椭圆并继续在椭圆内部飞行。我发现最简单的方法可能是找到撞击点的切线向量,然后从那里计算反射角。

虽然我不确定如何在代码中实现它。

这是我目前所拥有的,我有以下函数绘制椭圆及其半长轴 (a) 和半短轴 (b)。 t 在更新函数中递增。

void drawEllipse(float t) {
  float x = a * cos(t);
  float y = b * sin(t);
  
  PVector ellipseDotPosition = new PVector(x, y).add(ellipseCenter);
  circle(ellipseDotPosition.x, ellipseDotPosition.y, 2);
}

我用这个函数判断光线是否发生碰撞:

boolean hasCollided(PVector pointToCheck) {
  return pow((pointToCheck.x - ellipseCenter.x) / a, 2) + 
         pow((pointToCheck.y - ellipseCenter.y) / b, 2) > 1;
}

这是我尝试计算反射矢量的方法。

PVector getReflectionVector(PVector pointOfImpact) {
  // Differentiate to get tangent to the collision point.
  
  // PVector tangent = new PVector(-a / b * pointOfImpact.y, b / a * pointOfImpact.x);
  // PVector tangent = new PVector(-(a * pointOfImpact.y / b), (b * pointOfImpact.x / a));
  // circle(tangent.x, tangent.y, 10);
  
  // Treat the tangent as the surface to be reflected off.
  
  // Determine angle of reflection off the surface.
  
  // Return reflection vector.
  
  return new PVector();
}

我数学不好吗?是的。请帮助:)

根据 wikipedia 所说:

Analytically, the equation of a standard ellipse centered at the origin with width 2a and height 2b is:

其中,如果我们对其求导(即 returns 其在该点的切线)结果为:

导数只适用于以 (0, 0) 为中心的椭圆。

另请注意,如果 y = 0,您将获得异常。这是因为它会给出无穷大,因为切线是完全垂直的。

要将切线视为曲面,我们将执行代码中解释的以下步骤:

  // OriginalRay will be the direction of the colliding ray.
  // You may also define the origin as the last collision point.
  PVector getReflectionVector(PVector pointOfImpact, PVector originalRay){
    // Differentiate to get tangent to the collision point.
    // atan() to get angle of tangent line from 0X
    
    float tangentAngle;
  
    if(pointOfImpact.y != 0){
      float tangent = -1*pointOfImpact.x*sq(b)/(pointOfImpact.y*sq(a));
      tangentAngle = atan(tangent);
    }else{
      tangentAngle = PI/2;
    }
    
    // Treat the tangent as the surface to be reflected off.
    // Determine angle of reflection off the surface.
    float rayAngle = atan2(originalRay.y, originalRay.x);
    // We now transform the case as it had collided on an horizontal surfface to simplify.
    //float tempRayAngle = rayAngle - tangentAngle;
    // Calc the reflectionAngle 
    //float tempReflectionAngle = PI - tempRayAngle;
    // And undo the transformation
    //float newRayAngle = rayAngle - tempReflectionAngle;
    float newRayAngle = 2*rayAngle - tangentAngle - PI; //End result
    
    // Return reflection vector. (The direction vector with abs() = 1)
    PVector reflectedRay = new PVector(cos(newRayAngle), sin(newRayAngle));
    
    return reflectedRay;
  }