|
7 | 7 |
|
8 | 8 | from numba import njit, prange
|
9 | 9 | from numba import types as numba_types
|
10 |
| -from numpy import arctan, array, concatenate, empty, nan, ones, pi, where |
| 10 | +from numpy import arctan, array, concatenate, empty, nan, ones, pi, where, zeros |
11 | 11 | from numpy.linalg import lstsq
|
12 | 12 | from Polygon import Polygon
|
13 | 13 |
|
| 14 | +from .generic import build_index |
| 15 | + |
14 | 16 |
|
15 | 17 | @njit(cache=True)
|
16 | 18 | def is_left(
|
@@ -788,3 +790,110 @@ def reduce_size(x, y):
|
788 | 790 | # In case of virtual obs all value could be fill with same value, to avoid empty array
|
789 | 791 | i = max(3, i)
|
790 | 792 | return x[:i], y[:i]
|
| 793 | + |
| 794 | + |
| 795 | +@njit(cache=True) |
| 796 | +def group_obs(x, y, step, nb_x): |
| 797 | + """Get index k_box for each box, and indexes to sort""" |
| 798 | + nb = x.size |
| 799 | + i = empty(nb, dtype=numba_types.uint32) |
| 800 | + for k in range(nb): |
| 801 | + i[k] = box_index(x[k], y[k], step, nb_x) |
| 802 | + return i, i.argsort() |
| 803 | + |
| 804 | + |
| 805 | +@njit(cache=True) |
| 806 | +def box_index(x, y, step, nb_x): |
| 807 | + """Return k_box index for each value""" |
| 808 | + return numba_types.uint32((x % 360) // step + nb_x * ((y + 90) // step)) |
| 809 | + |
| 810 | + |
| 811 | +@njit(cache=True) |
| 812 | +def box_indexes(x, y, step): |
| 813 | + """Return i_box,j_box index for each value""" |
| 814 | + return numba_types.uint32((x % 360) // step), numba_types.uint32((y + 90) // step) |
| 815 | + |
| 816 | + |
| 817 | +@njit(cache=True) |
| 818 | +def poly_indexs(x_p, y_p, x_c, y_c): |
| 819 | + """ |
| 820 | + Index of contour for each postion inside a contour, -1 in case of no contour |
| 821 | +
|
| 822 | + :param array x_p: longitude to test (must be define, no nan) |
| 823 | + :param array y_p: latitude to test (must be define, no nan) |
| 824 | + :param array x_c: longitude of contours |
| 825 | + :param array y_c: latitude of contours |
| 826 | + """ |
| 827 | + i, i_order = group_obs(x_p, y_p, 1, 360) |
| 828 | + nb_p = x_p.shape[0] |
| 829 | + nb_c = x_c.shape[0] |
| 830 | + indexs = -ones(nb_p, dtype=numba_types.int32) |
| 831 | + # Adress table to get particle bloc |
| 832 | + start_index, end_index, i_first = build_index(i[i_order]) |
| 833 | + nb_bloc = end_index.size |
| 834 | + for i_contour in range(nb_c): |
| 835 | + # Build vertice and box included contour |
| 836 | + x_, y_ = reduce_size(x_c[i_contour], y_c[i_contour]) |
| 837 | + x_c_min, y_c_min = x_.min(), y_.min() |
| 838 | + x_c_max, y_c_max = x_.max(), y_.max() |
| 839 | + v = create_vertice(x_, y_) |
| 840 | + i0, j0 = box_indexes(x_c_min, y_c_min, 1) |
| 841 | + i1, j1 = box_indexes(x_c_max, y_c_max, 1) |
| 842 | + # i0 could be greater than i1, (x_c is always continious) so you could have a contour over bound |
| 843 | + if i0 > i1: |
| 844 | + i1 += 360 |
| 845 | + for i_x in range(i0, i1 + 1): |
| 846 | + # we force i_x in 0 360 range |
| 847 | + i_x %= 360 |
| 848 | + for i_y in range(j0, j1 + 1): |
| 849 | + # Get box indices |
| 850 | + i_box = i_x + 360 * i_y - i_first |
| 851 | + # Indice must be in table range |
| 852 | + if i_box < 0 or i_box >= nb_bloc: |
| 853 | + continue |
| 854 | + for i_p_ordered in range(start_index[i_box], end_index[i_box]): |
| 855 | + i_p = i_order[i_p_ordered] |
| 856 | + if indexs[i_p] != -1: |
| 857 | + continue |
| 858 | + y = y_p[i_p] |
| 859 | + if y > y_c_max: |
| 860 | + continue |
| 861 | + if y < y_c_min: |
| 862 | + continue |
| 863 | + x = (x_p[i_p] - x_c_min + 180) % 360 + x_c_min - 180 |
| 864 | + if x > x_c_max: |
| 865 | + continue |
| 866 | + if x < x_c_min: |
| 867 | + continue |
| 868 | + if winding_number_poly(x, y, v) != 0: |
| 869 | + indexs[i_p] = i_contour |
| 870 | + return indexs |
| 871 | + |
| 872 | + |
| 873 | +@njit(cache=True) |
| 874 | +def insidepoly(x_p, y_p, x_c, y_c): |
| 875 | + """ |
| 876 | + True for each postion inside a contour |
| 877 | +
|
| 878 | + :param array x_p: longitude to test |
| 879 | + :param array y_p: latitude to test |
| 880 | + :param array x_c: longitude of contours |
| 881 | + :param array y_c: latitude of contours |
| 882 | + """ |
| 883 | + # TODO must be optimize like poly_index |
| 884 | + nb_p = x_p.shape[0] |
| 885 | + nb_c = x_c.shape[0] |
| 886 | + flag = zeros(nb_p, dtype=numba_types.bool_) |
| 887 | + for i in range(nb_c): |
| 888 | + x_, y_ = reduce_size(x_c[i], y_c[i]) |
| 889 | + x_c_min, y_c_min = x_.min(), y_.min() |
| 890 | + x_c_max, y_c_max = x_.max(), y_.max() |
| 891 | + v = create_vertice(x_, y_) |
| 892 | + for j in range(nb_p): |
| 893 | + if flag[j]: |
| 894 | + continue |
| 895 | + x, y = x_p[j], y_p[j] |
| 896 | + if x > x_c_min and x < x_c_max and y > y_c_min and y < y_c_max: |
| 897 | + if winding_number_poly(x, y, v) != 0: |
| 898 | + flag[j] = True |
| 899 | + return flag |
0 commit comments