Map representing different coordinate systems. Coordinate definitions: * axes-coordinates goes from 0 to 1 in the domain. * data-coordinates are specified by the input x-y coordinates. * grid-coordinates goes from 0 to N and 0 to M for an N x M grid, where N and M match the s
| 237 | # ======================== |
| 238 | |
| 239 | class DomainMap(object): |
| 240 | """Map representing different coordinate systems. |
| 241 | |
| 242 | Coordinate definitions: |
| 243 | |
| 244 | * axes-coordinates goes from 0 to 1 in the domain. |
| 245 | * data-coordinates are specified by the input x-y coordinates. |
| 246 | * grid-coordinates goes from 0 to N and 0 to M for an N x M grid, |
| 247 | where N and M match the shape of the input data. |
| 248 | * mask-coordinates goes from 0 to N and 0 to M for an N x M mask, |
| 249 | where N and M are user-specified to control the density of streamlines. |
| 250 | |
| 251 | This class also has methods for adding trajectories to the StreamMask. |
| 252 | Before adding a trajectory, run `start_trajectory` to keep track of regions |
| 253 | crossed by a given trajectory. Later, if you decide the trajectory is bad |
| 254 | (e.g., if the trajectory is very short) just call `undo_trajectory`. |
| 255 | """ |
| 256 | |
| 257 | def __init__(self, grid, mask): |
| 258 | self.grid = grid |
| 259 | self.mask = mask |
| 260 | # Constants for conversion between grid- and mask-coordinates |
| 261 | self.x_grid2mask = (mask.nx - 1) / grid.nx |
| 262 | self.y_grid2mask = (mask.ny - 1) / grid.ny |
| 263 | |
| 264 | self.x_mask2grid = 1. / self.x_grid2mask |
| 265 | self.y_mask2grid = 1. / self.y_grid2mask |
| 266 | |
| 267 | self.x_data2grid = 1. / grid.dx |
| 268 | self.y_data2grid = 1. / grid.dy |
| 269 | |
| 270 | def grid2mask(self, xi, yi): |
| 271 | """Return nearest space in mask-coords from given grid-coords.""" |
| 272 | return (int((xi * self.x_grid2mask) + 0.5), |
| 273 | int((yi * self.y_grid2mask) + 0.5)) |
| 274 | |
| 275 | def mask2grid(self, xm, ym): |
| 276 | return xm * self.x_mask2grid, ym * self.y_mask2grid |
| 277 | |
| 278 | def data2grid(self, xd, yd): |
| 279 | return xd * self.x_data2grid, yd * self.y_data2grid |
| 280 | |
| 281 | def grid2data(self, xg, yg): |
| 282 | return xg / self.x_data2grid, yg / self.y_data2grid |
| 283 | |
| 284 | def start_trajectory(self, xg, yg): |
| 285 | xm, ym = self.grid2mask(xg, yg) |
| 286 | self.mask._start_trajectory(xm, ym) |
| 287 | |
| 288 | def reset_start_point(self, xg, yg): |
| 289 | xm, ym = self.grid2mask(xg, yg) |
| 290 | self.mask._current_xy = (xm, ym) |
| 291 | |
| 292 | def update_trajectory(self, xg, yg): |
| 293 | if not self.grid.within_grid(xg, yg): |
| 294 | raise InvalidIndexError |
| 295 | xm, ym = self.grid2mask(xg, yg) |
| 296 | self.mask._update_trajectory(xm, ym) |