diff --git a/py/cspov/control/layer_list.py b/py/cspov/control/layer_list.py index a314f430b20cb11526d55982a4a0945031f95866..865e23d41252fe7d18eb5abef035e571af97d0cc 100644 --- a/py/cspov/control/layer_list.py +++ b/py/cspov/control/layer_list.py @@ -198,7 +198,7 @@ class LayerStackTableModel(QAbstractTableModel): elif role==Qt.DisplayRole: lao = self.doc.layer_animation_order(row) return '-' if lao==0 else str(lao) - return None + return '?' def _nameData(self, row, listing, role): if role==Qt.DisplayRole: diff --git a/py/cspov/model/shapes.py b/py/cspov/model/shapes.py new file mode 100644 index 0000000000000000000000000000000000000000..127921b6ce17a1c1b1f2e94d1f1ad8534c948425 --- /dev/null +++ b/py/cspov/model/shapes.py @@ -0,0 +1,161 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +""" +shapes.py +~~~~~~~~~ + +PURPOSE +Shape layers which can be represented in the workspace as data content masks + +REFERENCES + + +REQUIRES + + +:author: R.K.Garcia <rayg@ssec.wisc.edu> +:copyright: 2014 by University of Wisconsin Regents, see AUTHORS for more details +:license: GPLv3, see LICENSE for more details +""" +__author__ = 'rayg' +__docformat__ = 'reStructuredText' + +import os, sys +import logging, unittest, argparse +from functools import partial +import shapely.geometry.polygon as sgp, shapely.ops as sops, shapely.geometry as sgeo +# import shapefile as shf +import numpy as np +import pyproj as prj +from numba import jit + +LOG = logging.getLogger(__name__) + +def convert_shape_to_proj(to_proj:prj.Proj, shape:sgp.LinearRing, shape_proj:prj.Proj): + # ref http://toblerity.org/shapely/manual.html#shapely.ops.transform + # ref http://all-geo.org/volcan01010/2012/11/change-coordinates-with-pyproj/ + # inverse-project the ring + if to_proj is shape_proj: + return shape + project = partial( + prj.transform, + shape_proj, + to_proj) + newshape = sops.transform(project, shape) + return newshape + +@jit +def mask_inside_index_shape(xoff, yoff, width, height, shape): + """ + for an index shape, return a mask of coordinates inside the shape + :param xoff: x offset between mask and shape + :param yoff: y offset + :param xmax: maximum x index 0-(xmax-1) + :param ymax: max y index + :param shape: + :return: + """ + mask = np.zeros((height,width), dtype=np.bool_) + for y in range(height): + for x in range(width): + p = sgeo.Point(x+xoff,y+yoff) + if p.within(shape): + mask[y,x] = True + return mask + +def content_within_shape(content:np.ndarray, display_xform:prj.Proj, shape:sgp.LinearRing): + """ + + :param content: data being displayed on the screen + :param display_proj: transform between content array indices and screen coordinates + :param shape: LinearRing in screen coordinates (e.g. mercator meters) + :return: masked_content:masked_array, (y_index_offset:int, x_index_offset:int) containing minified masked content array + """ + # invert shape to content indices + invproject = partial( + display_xform, + inverse=True + ) + # FIXME: deal with dateline crossing + # convert shape from display coords to content array indices + index_shape = sops.transform(invproject, shape) + + # now convert bounding box to content coordinates + nx,ny,mx,my = shape.bounds # minx,miny,maxx,maxy + nx, ny = display_xform(nx,ny, inverse=True) + mx, my = display_xform(mx,my, inverse=True) + nx, ny = int(nx), int(ny) + mx, my = int(np.ceil(mx)), int(np.ceil(my)) + + # subset the content + w = (mx-nx)+1 + h = (my-ny)+1 + + # generate index arrays + mask = mask_inside_index_shape(nx, ny, w, h, index_shape) + + masked_content = np.ma.masked_array(content[ny:ny+h, nx:nx+w], mask=mask) + return masked_content + + +def original_data_within_shape(raw_data:np.ndarray, + content_proj:prj.Proj, + display_xform:prj.Proj, + shape:sgp.LinearRing): + """ + :param raw_data: ndarray, unprojected data (e.g. lat/lon instead of XY space) + :param content_proj: projection applied to raw_data to make projected content array + :param display_xform: transformation applied to content to make screen coordinates + :param shape: shape we're working with, in display coordinates + :return: + """ + # + # + raise NotImplementedError('incomplete implementation') + # convert shape to coordinate system of content + if shape_proj is not None: + shape = convert_shape_to_proj(content_proj, shape, shape_proj) + + # generate bounding box for the shape + nx,ny,mx,my = shape.bounds # minx,miny,maxx,maxy + + # reverse the bounding box corners projection to array indices as subbox iy,ix,w,h + nx,ny = content_proj(nx,ny, inverse=True) + mx,my = content_proj(mx,my, inverse=True) + + # generate "subbox" projected x,y coordinate arrays for that bounded area of the content + + + # test inside/outside the shape for all the coordinates inside the subbox + + + +def main(): + parser = argparse.ArgumentParser( + description="PURPOSE", + epilog="", + fromfile_prefix_chars='@') + parser.add_argument('-v', '--verbose', dest='verbosity', action="count", default=0, + help='each occurrence increases verbosity 1 level through ERROR-WARNING-INFO-DEBUG') + # http://docs.python.org/2.7/library/argparse.html#nargs + # parser.add_argument('--stuff', nargs='5', dest='my_stuff', + # help="one or more random things") + parser.add_argument('pos_args', nargs='*', + help="positional arguments don't have the '-' prefix") + args = parser.parse_args() + + levels = [logging.ERROR, logging.WARN, logging.INFO, logging.DEBUG] + logging.basicConfig(level=levels[min(3, args.verbosity)]) + + if not args.pos_args: + unittest.main() + return 0 + + for pn in args.pos_args: + pass + + return 0 + + +if __name__ == '__main__': + sys.exit(main()) diff --git a/py/cspov/view/SceneGraphManager.py b/py/cspov/view/SceneGraphManager.py index a54b1941fb420b8ffdc7cc5bc4cc2aae74a3726f..91dd4651be644a42398db09f7c7b25bfb2947bcc 100644 --- a/py/cspov/view/SceneGraphManager.py +++ b/py/cspov/view/SceneGraphManager.py @@ -29,7 +29,7 @@ from vispy import scene from vispy.util.event import Event from vispy.visuals.transforms import STTransform, MatrixTransform from cspov.common import WORLD_EXTENT_BOX, DEFAULT_ANIMATION_DELAY -from cspov.control.layer_list import LayerStackListViewModel +from cspov.control.layer_list import LayerStackTableModel from cspov.view.LayerRep import NEShapefileLines, TiledGeolocatedImage from cspov.view.MapWidget import CspovMainMapCanvas from cspov.queue import TASK_DOING, TASK_PROGRESS