-
Notifications
You must be signed in to change notification settings - Fork 278
add polygon_chord #2969
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
add polygon_chord #2969
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -39,6 +39,98 @@ | |
| SQRT2 = np.sqrt(2) | ||
|
|
||
|
|
||
| def polygon_chord(mu_x, mu_y, phi, ri_x, ri_y, vi_x, vi_y): | ||
| """ | ||
| Compute the chord length of a ray intersecting a polygon. | ||
|
|
||
| This function calculates the length of the segment formed by the intersection | ||
| of a ray (defined by an origin and direction) with a polygon defined by its | ||
| edges. The polygon is represented parametrically using starting points and | ||
| direction vectors for each edge. | ||
|
|
||
| Parameters | ||
| ---------- | ||
| mu_x : float | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. These should be quantities, as we discussed offline, the best would be to use telescope coordinate system lat/lon.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Also, perhaps tuples of (x,y) or arrays of them would be more straightforward to define points (arrays of points) |
||
| X-coordinate of the ray origin, which is the muon's impact point (x). | ||
| mu_y : float | ||
| Y-coordinate of the ray origin, which is the muon's impact point (y). | ||
| phi : float | ||
| Angle defining the direction of the ray. | ||
| ri_x : ndarray of shape (N,) | ||
| X-coordinates of the starting points of the polygon edges. | ||
| ri_y : ndarray of shape (N,) | ||
| Y-coordinates of the starting points of the polygon edges. | ||
| vi_x : ndarray of shape (N,) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think we should deduce these (if needed) from the vertices. You can write a helper for this.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, I'd also prefer the vertices as input. But maybe the function as it is here is fine and that transformation is made once outside of this function. |
||
| X-components of the edge direction vectors. | ||
| vi_y : ndarray of shape (N,) | ||
| Y-components of the edge direction vectors. | ||
|
|
||
| Returns | ||
| ------- | ||
| float | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should be also a unit of length (or angular, equivalent in the telescope frame) |
||
| Length of the chord formed by the intersection of the ray with the polygon: | ||
| - 0.0 if there is no intersection, | ||
| - distance from the ray origin to the intersection point if only one intersection, | ||
| - distance between two intersection points if exactly two intersections, | ||
| - accumulated segment length for multiple intersections (handles complex polygons). | ||
|
|
||
| Notes | ||
| ----- | ||
| - The ray is defined parametrically as: | ||
| (x, y) = (mu_x, mu_y) + s * (cos(phi), sin(phi)), with s >= 0 | ||
| - Each polygon edge is defined as: | ||
| (x, y) = (ri_x, ri_y) + t * (vi_x, vi_y), with 0 <= t < 1 | ||
| - The function computes intersections by solving a 2D linear system. | ||
| - A small epsilon_d (`1e-20`) is added to the denominator to avoid division by zero. | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. why not using
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Just remember that catching an exception is quite a bit slower than adding an epsilon, so if you need this to be fast, the epsilon method might be better. Also if you want to use numba to speed things up
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. And doesn't vectorize |
||
| - For multiple intersections, distances are sorted and combined with alternating | ||
| signs to compute the total chord length (useful for non-convex polygons). | ||
|
|
||
| Examples | ||
| -------- | ||
| >>> length = polygon_chord(mu_x=0, mu_y=0, phi=np.pi/4, | ||
| ... ri_x=..., ri_y=..., vi_x=..., vi_y=...) | ||
| >>> print(length) | ||
|
|
||
| """ | ||
|
|
||
| # Effective speed of the ray, with unit norm. | ||
| vmu_x = np.cos(phi) | ||
| vmu_y = np.sin(phi) | ||
|
|
||
| epsilon_d = 1.0e-20 | ||
|
|
||
| c1 = mu_x - ri_x | ||
| c2 = mu_y - ri_y | ||
| determinant = vi_x * vmu_y - vi_y * vmu_x + epsilon_d | ||
|
|
||
| t = ( c1 * vmu_y - c2 * vmu_x ) / determinant | ||
| s = ( vi_y * c1 - vi_x * c2 ) / determinant | ||
|
|
||
| status = np.column_stack((vi_x, ri_x, vi_y, ri_y, t, s)) | ||
| mask = (status[:,4] >= 0) & (status[:,4] < 1) & (status[:,5] >= 0) | ||
|
|
||
| x_int = status[mask][:,0]*status[mask][:,4] + status[mask][:,1] | ||
| y_int = status[mask][:,2]*status[mask][:,4] + status[mask][:,3] | ||
|
|
||
| if x_int.shape[0] == 0 : | ||
| return 0.0 | ||
| elif x_int.shape[0] == 1: | ||
| return np.squeeze(np.sqrt((x_int - mu_x) ** 2 + (y_int - mu_y) ** 2)) | ||
| elif x_int.shape[0] == 2: | ||
| return np.squeeze(np.sqrt((x_int[0] - x_int[1]) ** 2 + (y_int[0] - y_int[1]) ** 2)) | ||
| else: | ||
| dist = np.sort( | ||
| np.squeeze(np.sqrt((x_int - mu_x) ** 2 + (y_int - mu_y) ** 2)) | ||
| ) | ||
| sign_arr = np.ones(x_int.shape[0]) | ||
| if x_int.shape[0] % 2 == 0: | ||
| sign_arr[0::2] = -1 | ||
| return np.sum(dist * sign_arr) | ||
|
|
||
| sign_arr[1::2] = -1 | ||
| return np.sum(dist * sign_arr) | ||
|
|
||
|
|
||
| def chord_length(radius, rho, phi, phi0=0): | ||
| """ | ||
| Function for integrating the length of a chord across a circle (effective chord length). | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This function should be
njit, as it will be called. If possible, it would also be good if it could be vectorized over multiple tiles.