1

I've been mulling this problem over in my head for a while. Given an arbitrary closed 2d polygon, which is well defined, consisting of lines and curves (perhaps Bezier curves for consistency). Given a starting point and direction within the polygon. How would you go about efficiently calculating how a laser, starting at that start point, and pointing in that direction, would bounce around inside the shape?

To put this in concrete terms say you had an array which defined the shape.

  • The elements of the array are either lines (start and end point), or Bezier curves (list of n points defining the curve).
  • You can assume that the end of one segment will connect to the start of the next segment of the array, and that the end of the last segment will connect to the start of the first one.
  • You can also assume that none of the segments intersect with one another or themself.

Here's an example array:

[
Line from (0, 0) to (1, 2),
Line from (1, 2) to (3, 2),
Bezier curve from (3, 2) to (3, 0) passing through (4, 1),
Line from (3, 0) to (0,0)
]

And we can say the laser originates at (1, 0.5) and travels directly NE.

Here is an image: The shape in question

The challenge is to build an algorithm which would follow the path of the line, calculating a list of intersections and normal values for reflection as the laser bounces around. I'd like to find a general algorithm for solving this given any input array. If you have a solution or just a helpful tip/place to start looking it would be much appreciated.

Em Eldar
  • 686
  • 1
  • 8
  • 25
  • I have been playing around with this exact problem. Here is my GitHub repo for reference [WindowsRayBounceForm](https://github.com/ja72/WindowsRayBounceForm). With the exception of the curved members of polygons. But I do support ellipses and circles. – John Alexiou May 24 '22 at 04:44
  • Is this a programming question, or a [Mathematics.SE] question? – John Alexiou May 24 '22 at 05:01
  • @JohnAlexiou I suppose this is more of a Mathematics question, but it came from the context of a coding challenge I randomly came up with. Your implementation looks super cool and I'll definitely dig into your code a little. – Em Eldar May 24 '22 at 22:00

3 Answers3

1

To calculate reflection, it is worth to define ray with base point P0 and unit direction vector dir.

When ray meets a wall as line segment or Bezier curve, and unit normal to wall is n, you have new base point is point of reflection, and can calculate new direction vector:

dot = dir.x * n.x + dir.y * n.y 
//after reflection
newdir.x = dir.x - 2 * dot * n.x
newdir.y = dir.y - 2 * dot * n.y

You also need to calculate intersection points of ray and segments (points A-B) solving simple equation system for unknown parameters u and v and checking that u is positive, v is in range 0..1

p0.x + dir.x * u = a.x + v * (b.x - a.x)
p0.y + dir.y * u = a.y + v * (b.y - a.y)

and intersection with Bezier curve (more complex, but the same approach)

Normal to A-B segment is

n.x = (a.y-b.y) / len(AB)
n.y = (b.x-a.x) / len(AB)

Normal to Bezier curve might be calculated using tangent (derivative of curve equation) in intersection point with similar y/x exchange as above

MBo
  • 77,366
  • 5
  • 53
  • 86
1

This is a 2D ray-casting problem.

Given a starting point and a direction, you compute the implicit equation of the ray s(x, y):= ax + by + c = 0, which is a straight line, and you want to find the first intersection with the shape outline.

In the case of a polygonal shape, an edge can only intersect the line if its endpoints are on either side of the ray, which is characterized by a change of sign of s. When there is an intersection, you can compute the parameter t of the parametric equation of the the ray, P = P0 + t.D. Then the first intersection is given by the smallest positive t (as long as you are inside a closed shape, there will be one).

In case of a cubic Bezier arc, the above sign rule must be modified, because a Bezier arc can cross a line twice and its endpoints have the same signs. A possible cure is to decompose the Bezier in monotonic arcs, as follows:

  • rotate the line and the control points so that the line becomes horizontal;

  • compute the cubic polynomial Y(u) for the ordinates only (u is the parameter of the Bezier);

  • find the extrema of Y by solving the quadratic Y'(u)=0. This gives you from 0 to 2 values of u in the range [0,1];

  • use the corresponding points to split the Bezier, and you will get arcs guaranteed to cross the line at most once and restore the sign rule.

[This procedure finds the tangent to the Bezier that are parallel to the ray.]

Now for every cubic arc with a change of sign, you can't avoid solving the cubic, for instance using the Cardano formulas. Then again, keep the intersection with the smallest positive t.

When you have found the first intersection, compute the direction of the normal to the outline at the intersection point. Then you have new starting point and direction, to continue the trajectory.

enter image description here

Update: I messed a little with the parameters. The convention is: t along the ray, u along the Bezier.

It is important to realize that the sign rule brings a safety in the procedure. For correctness, every time you detect a change of sign, you must report exactly one intersection. In case of exact equality to zero, you can assume positive (provided you always assume positive).

0

First, you create a ray, with an origination point p and a direction vector d.

Then find the intersection point of the ray for an arbitrary shape.

Then you find the normal vector of the shape at the intersection point

Then you find the reflected direction r using the vector form of the reflection equation

r = d - 2(d · n) n

where n is the surface normal, and d the ray direction.

The most challenging part here is finding the (closest) intersection point of the ray for an arbitrary shape.

I have a subroutine on GitHib for a polygon to do the intersection check.

fig

You split the polygon to segments, and check each segment. Pick the segment with the nearest positive distance if possible. If the segment is behind the ray it should not hit.

John Alexiou
  • 28,472
  • 11
  • 77
  • 133
  • As the bouncing is a chaotic process, the reflected ray must be computed very accurately. So it is advisable to refine the intersection point to the true curve after the linear approximation is found, or at least estimate the normal direction from the true curve rather than from the flattened approximation. –  May 25 '22 at 08:28
  • @YvesDaoust - I don't use a flattened approximation. All my shapes are analytical and the actual hit point and normal are computer from the geometry. – John Alexiou May 25 '22 at 16:37
  • Sorry, I was misled by "split the polygon to segments" and the fact that you don't supply a solution for "arbitrary shapes". –  May 25 '22 at 16:40
  • @YvesDaoust I wrote the code before the _op_ asked about curved segments. I just figured out how to intersect a bezier curve by solving a cubic. – John Alexiou May 25 '22 at 20:16
  • Well, I don't read in the future. –  May 26 '22 at 07:58