def project_extrema(self, detector, scan_angle): coords = self.extrema_at_scan_angle(scan_angle) shadow_boundary = [] for p_id, p in enumerate(detector): # project coordinates onto panel plane a = p.get_D_matrix() * coords x, y, z = a.parts() valid = z > 0 x.set_selected(valid, x.select(valid) / z.select(valid)) y.set_selected(valid, y.select(valid) / z.select(valid)) if valid.count(True) < 3: # no shadow projected onto this panel shadow_boundary.append(flex.vec2_double()) continue # Compute convex hull of shadow points points = flex.vec2_double(x.select(valid), y.select(valid)) shadow = flex.vec2_double(_convex_hull(points)) shadow *= 1 / p.get_pixel_size()[0] shadow_orig = shadow.deep_copy() for i in (0, p.get_image_size()[0]): points = flex.vec2_double( flex.double(p.get_image_size()[1], i), flex.double_range(0, p.get_image_size()[1]), ) inside = is_inside_polygon(shadow_orig, points) # only add those points needed to define vertices of shadow inside_isel = inside.iselection() outside_isel = (~inside).iselection() while inside_isel.size(): j = inside_isel[0] shadow.append(points[j]) outside_isel = outside_isel.select(outside_isel > j) if outside_isel.size() == 0: shadow.append(points[inside_isel[-1]]) break sel = inside_isel >= outside_isel[0] if sel.count(True) == 0: shadow.append(points[inside_isel[-1]]) break inside_isel = inside_isel.select(sel) for i in (0, p.get_image_size()[1]): points = flex.vec2_double( flex.double_range(0, p.get_image_size()[0]), flex.double(p.get_image_size()[0], i), ) inside = is_inside_polygon(shadow_orig, points) # only add those points needed to define vertices of shadow inside_isel = inside.iselection() outside_isel = (~inside).iselection() while inside_isel.size(): j = inside_isel[0] shadow.append(points[j]) outside_isel = outside_isel.select(outside_isel > j) if outside_isel.size() == 0: shadow.append(points[inside_isel[-1]]) break sel = inside_isel >= outside_isel[0] if sel.count(True) == 0: shadow.append(points[inside_isel[-1]]) break inside_isel = inside_isel.select(sel) # Select only those vertices that are within the panel dimensions n_px = p.get_image_size() x, y = shadow.parts() valid = (x >= 0) & (x <= n_px[0]) & (y >= 0) & (y <= n_px[1]) shadow = shadow.select(valid) # sort vertices clockwise from centre of mass com = principal_axes_of_inertia_2d(shadow).center_of_mass() sx, sy = shadow.parts() shadow = shadow.select( flex.sort_permutation(flex.atan2(sy - com[1], sx - com[0])) ) shadow_boundary.append(shadow) return shadow_boundary
def project_extrema(self, detector, scan_angle): from dials.util import is_inside_polygon coords = self.extrema_at_scan_angle(scan_angle) shadow_boundary = [] for p_id, p in enumerate(detector): # project coordinates onto panel plane a = p.get_D_matrix() * coords x, y, z = a.parts() valid = z > 0 x.set_selected(valid, x.select(valid)/z.select(valid)) y.set_selected(valid, y.select(valid)/z.select(valid)) if valid.count(True) < 3: # no shadow projected onto this panel shadow_boundary.append(flex.vec2_double()) continue # Compute convex hull of shadow points points = flex.vec2_double(x.select(valid), y.select(valid)) shadow = flex.vec2_double(convex_hull(points)) shadow *= 1/p.get_pixel_size()[0] shadow_orig = shadow.deep_copy() for i in (0, p.get_image_size()[0]): points = flex.vec2_double(flex.double(p.get_image_size()[1], i), flex.double_range(0, p.get_image_size()[1])) inside = is_inside_polygon(shadow_orig, points) # only add those points needed to define vertices of shadow inside_isel = inside.iselection() outside_isel = (~inside).iselection() while inside_isel.size(): j = inside_isel[0] shadow.append(points[j]) outside_isel = outside_isel.select(outside_isel > j) if outside_isel.size() == 0: shadow.append(points[inside_isel[-1]]) break sel = inside_isel >= outside_isel[0] if sel.count(True) == 0: shadow.append(points[inside_isel[-1]]) break inside_isel = inside_isel.select(sel) for i in (0, p.get_image_size()[1]): points = flex.vec2_double(flex.double_range(0, p.get_image_size()[0]), flex.double(p.get_image_size()[0], i)) inside = is_inside_polygon(shadow_orig, points) # only add those points needed to define vertices of shadow inside_isel = inside.iselection() outside_isel = (~inside).iselection() while inside_isel.size(): j = inside_isel[0] shadow.append(points[j]) outside_isel = outside_isel.select(outside_isel > j) if outside_isel.size() == 0: shadow.append(points[inside_isel[-1]]) break sel = inside_isel >= outside_isel[0] if sel.count(True) == 0: shadow.append(points[inside_isel[-1]]) break inside_isel = inside_isel.select(sel) # Select only those vertices that are within the panel dimensions n_px = p.get_image_size() x, y = shadow.parts() valid = (x >= 0) & (x <= n_px[0]) & (y >= 0) & (y <= n_px[1]) shadow = shadow.select(valid) # sort vertices clockwise from centre of mass from scitbx.math import principal_axes_of_inertia_2d com = principal_axes_of_inertia_2d(shadow).center_of_mass() sx, sy = shadow.parts() shadow = shadow.select( flex.sort_permutation(flex.atan2(sy-com[1],sx-com[0]))) shadow_boundary.append(shadow) return shadow_boundary