Ejemplo n.º 1
0
    class WayIndex:
        def __init__(self, ways):
            self.max_way_id = 0
            self.way_idx_mapping = {}
            self.idx = Rtree()
            for way in ways:
                self.add(way)

        def add(self, way):
            self.idx.add(id=self.max_way_id, coordinates=way.get_bbox(), 
                         obj=way.id)
            self.way_idx_mapping[way.id] = self.max_way_id
            self.max_way_id += 1

        def delete(self, way):
            self.idx.delete(id=self.way_idx_mapping[way.id],
                            coordinates=way.get_bbox())
            way_ids = map(lambda way: way.object, 
                          wayidx.idx.intersection(way.get_bbox(), 
                                                  objects=True))
Ejemplo n.º 2
0
class SpatialIndex(Persistent):

    def __init__(self, *args):
        self.rtree_args = args
        self.rtree = Rtree(*args)
        self.backward = IOBTree()

    def index_doc(self, docid, value):
        if docid in self.backward:
            self.unindex_doc(docid)
        self.backward[docid] = value
        self.rtree.add(docid, value, obj=docid)

    def unindex_doc(self, docid):
        value = self.backward.get(docid)
        if value is None:
            return
        self.rtree.delete(docid, value)
        del self.backward[docid]

    def apply(self, value):
        return [x.object for x in self.rtree.intersection(value, objects=True)]

    def clear(self):
        self.backward.clear()
        props = self.rtree.properties
        if props.storage == RT_Disk:
            self.rtree.close()
            fname = props.filename
            try:
                os.unlink('%s.%s' % (fname, props.dat_extension))
            except OSError:
                pass
            try:
                os.unlink('%s.%s' % (fname, props.idx_extension))
            except OSError:
                pass
        self.rtree = Rtree(*self.rtree_args)

    def count(self, value):
        return self.rtree.count(value)
Ejemplo n.º 3
0
class GraphicScene(object):

    ITEM_SELECTION_RADIUS = 2 # px

    _logger = _module_logger.getChild('GraphicScene')

    ##############################################

    def __init__(self):

        self._items = OrderedDict()
        self._rtree = Rtree()
        self._selected_items = OrderedDict()

    ##############################################

    def add_item(self, item):

        item_id = item._id
        self._items[item_id] = item
        self._rtree.add(item_id, item.bounding_box)
        item._scene = self

    ##############################################

    def remove_item(self, item):

        if item in self._selected_items:
            item.deselect()
        
        item_id = item._id
        del self._items[item_id]
        self._rtree.delete(item_id, item.bounding_box)
        item._scene = None

    ##############################################

    def add_items(self, items):

        for item in items:
            self.add_item(item)

    ##############################################

    def remove_items(self, items):

        for item in items:
            self.remove_item(item)

    ##############################################

    def items_in(self, interval):

        items = [self._items[x] for x in self._rtree.intersection(interval.bounding_box())]
        items.sort() # accordind to z value

        return items

    ##############################################

    def items_at(self, x, y):

        # Fixme: vector or x, y
        return self.items_in(point_interval(x, y))

    ##############################################

    def items_around(self, x, y, radius):

        return self.items_in(centred_interval(x, y, radius))

    ##############################################

    def __iter__(self):

        return iter(self._items.values())

    ##############################################

    def _select_item(self, item):

        self._selected_items[item._id] = self

    ##############################################

    def _deselect_item(self, item):

        del self._selected_items[item._id]

    ##############################################

    def iter_on_selected_items(self):

        return self._selected_items.values()

    ##############################################

    def erase(self, position, radius):

        removed_items = []
        new_items = []
        for item in self:
        # for path in self.items_around(position.x, position.y, radius):
            # erase return None, the item or an iterable of new items
            items = item.erase(position, radius)
            if items is not item:
                self._logger.info("Erase item {}".format(item.id))
                removed_items.append(item)
                if items is not None:
                    new_items.extend(items)
        self.remove_items(removed_items)
        self.add_items(new_items)
        
        return removed_items, new_items
Ejemplo n.º 4
0
class IntRtreeIndex(BaseIndex):
    """Avoids the slower Rtree query object=True interface
    """
    _v_nextuid = None
    family = BTrees.family32

    def clear(self):
        self.fwd = Rtree()
        self.bwd = self.family.OO.BTree()
        self.keys = self.family.IO.BTree()
        self.intids = self.family.OI.BTree()
        self.ids = self.family.OO.BTree()
    def __init__(self):
        self.clear()
    def key(self, item):
        try:
            return item['id'], tuple(self.bbox(item))
        except:
            return tuple(item.items())
    def fid(self, item):
        return item['id']
    def intid(self, item):
        # Get and track next available key using zope.intid algorithm
        # Item might be already registered
        uid = self.intids.get(self.key(item))
        if uid is not None:
            return uid
        # But if not registered
        nextuid = getattr(self, '_v_nextuid', None)
        while True:
            if nextuid is None:
                nextuid = random.randrange(0, self.family.maxint)
            uid = nextuid
            if uid not in self.keys:
                nextuid += 1
                if nextuid > self.family.maxint:
                    nextuid = None
                self._v_nextuid = nextuid
                return uid
            nextuid = None
    def intersection(self, bbox):
        """Return an iterator over Items that intersect with the bbox"""
        for hit in self.fwd.intersection(bbox, objects=False):
            yield self.bwd[int(hit)]
    def nearest(self, bbox, limit=1):
        """Return an iterator over the nearest N=limit Items to the bbox"""
        for hit in self.fwd.nearest(bbox, num_results=limit, objects=False):
            yield self.bwd[int(hit)]
    def item(self, fid, bbox):
        return self.bwd[self.intids[(fid, bbox)]]
    def items(self, fid):
        return [self.bwd[intid] for intid in self.ids[fid]]
    def index_item(self, itemid, bbox, item):
        """Add an Item to the index"""
        if itemid in self.bwd:
            self.unindex_item(itemid, bbox)
        # Store an id for the item if it has None
        try:
            item.update(id=item.get('id') or str(uuid.uuid4()))
            key = self.key(item)
            sid = self.fid(item)
            
            # Map keys <-> intids
            intid = self.intid(item)
            self.keys[intid] = key
            self.intids[key] = intid
            
            if sid not in self.ids:
                self.ids[sid] = IISet([])
            self.ids[sid].add(intid)

            self.bwd[intid] = item
            self.fwd.add(intid, bbox)
        except:
            import pdb; pdb.set_trace()
            raise
    def unindex_item(self, itemid, bbox):
        """Remove an Item from the index"""
        intid = int(itemid)
        key = self.keys.get(intid)
        if key is None:
            return
        self.ids[key[0]].remove(intid)
        del self.keys[intid]
        del self.intids[key]
        del self.bwd[intid]
        self.fwd.delete(intid, bbox)
    def batch(self, changeset):
        BaseIndex.batch(self, changeset)
    def commit(self):
        transaction.commit()
        rtree_storage = self.fwd.properties.filename
        self.fwd.close()
        self.fwd = Rtree(rtree_storage)
    def close(self):
        self.fwd.close()
Ejemplo n.º 5
0
class GraphicScene(object):

    ITEM_SELECTION_RADIUS = 2 # px

    _logger = logging.getLogger(__name__)

    ##############################################

    def __init__(self, glortho2d):

        self._glortho2d = glortho2d # Fixme: used for window_to_scene_coordinate window_to_scene_distance
        self._items = {}
        self._rtree = Rtree()
        self._selected_item = None

    ##############################################

    def _window_to_scene_coordinate(self, event):

        location = np.array((event.x(), event.y()), dtype=np.float)
        return list(self._glortho2d.window_to_gl_coordinate(location))

    ##############################################

    def _window_to_scene_distance(self, x):

        return self._glortho2d.window_to_gl_distance(x)

    ##############################################

    def add_item(self, item):

        item_id = hash(item)
        self._items[item_id] = item
        self._rtree.add(item_id, item.bounding_box)

    ##############################################

    def remove_item(self, item):

        if self._selected_item is item:
            self.deselect_item(item)
        
        item_id = hash(item)
        del self._items[item_id]
        self._rtree.delete(item_id, item.bounding_box)

    ##############################################

    def select_item(self, item):

        item.is_selected = True
        self._selected_item = item

    ##############################################

    def deselect_item(self, item):

        item.is_selected = False
        self._selected_item = None

    ##############################################

    def items_in(self, interval):

        self._logger.debug(str( interval))
        items = [self._items[x] for x in self._rtree.intersection(interval.bounding_box())]
        items.sort() # accordind to z value

        return items

    ##############################################

    def items_at(self, x, y):

        return self.items_in(point_interval(x, y))

    ##############################################

    def items_around(self, x, y, radius):

        return self.items_in(centred_interval(x, y, radius))

    ##############################################

    def item_under_mouse(self, event):

        x, y = self._window_to_scene_coordinate(event)
        radius = self._window_to_scene_distance(GraphicScene.ITEM_SELECTION_RADIUS)

        items = self.items_around(x, y, radius)
        if items:
            # return the highest z value
            # Fixme: ok ?
            return items[-1]
        else:
            return None

    ##############################################

    def keyPressEvent(self, event):

        return False

    ##############################################

    def keyReleaseEvent(self, event):

        return False

    ##############################################

    def mousePressEvent(self, event):

        item = self.item_under_mouse(event)
        if item is not None:
            self.select_item(item)
            item.mousePressEvent(event)
            return True
        else:
            return False

    ##############################################

    def mouseReleaseEvent(self, event):

        if self._selected_item is not None:
            self._selected_item.mouseReleaseEvent(event)
            self.deselect_item(self._selected_item)
            return True
        else:
            return False

    ##############################################

    def mouseDoubleClickEvent(self, event):

        return False

    ##############################################

    def wheelEvent(self, event):

        return False

    ##############################################

    def mouseMoveEvent(self, event):

        if self._selected_item is not None:
            self._selected_item.mouseMoveEvent(event)
            return True
        else:
            return False
Ejemplo n.º 6
0
 def delete(self, id_, coords):
     with threading.RLock():
         Rtree.delete(self, id_, coords)            
Ejemplo n.º 7
0
class GisCanvas:
    """
    Top-level drawing class that contains a list of all the objects to draw.
    """
    def __init__(self):
        """Initialise the class by creating an instance of each object."""
        self._ratio_index = (0.05, 0.1, 0.2, 0.5, 1, 2, 4, 8, 16, 32, 64) # pagal sita dydi turi kisti tasko atstumas nuo zoominimo centro
        self._zoom_level = self._ratio_index.index(4) # 0-dirbame su realiomis koordinatemis - kitur koordinates yra gaunamos atliekant dalyba... todel nera labai tikslios
        
        self._device_area = None # gtk.gdk.Rectangle()
        
        self._shapes = [] # shapes data
        self._index_rtree = Rtree() # shapes indexes in self._shapes
        
        self._offset = Point(0, 0) #- naudojamas ctx.translate() #device koordinates
  
        self._prj = GisProjection()
        self._styler = Styler(self)
        self._painter = Painter(self._styler)
        
        self._drag_to_center = True # jeigu norime kad resize metu (bus iskviestas set_device_area) butu iskvietsas center()

        
    def load(self, name):
        self._styler.load_css_file("%s.css" % name)
        self.load_fcad_file("%s.fcad" % name)

        
    def save(self, file_name):
        #self.create_fcad_file("%s.fcad" % file_name)
        ShapeFile.create_fcad_file("%s.fcad" % file_name, self._shapes)
        StyleFile.create_css_file("%s.css" % file_name, self._styler.get_shapes_style(), self._styler.get_symbols_style(), prettyprint=True)
        
        #self._styler.create_css_file("%s.css" % file_name, prettyprint=True)
        
        
        
    def clear(self):
        print "clear canvas!"
        self._zoom_level = self._ratio_index.index(1)
        self._offset = Point(0, 0)
       
        self._shapes = []
        #self._cairo_paths = {}
        self._index_rtree = Rtree()
        self._styler.load_default_style()

       
    def load_pickle(self, file_path):
        timer.start("loading shapes.p")
        if os.path.exists(file_path):
            self._shapes = pickle.load(open(file_path, "rb"))
            
            if len(self._shapes):
                def generator_function(points):
                    for i, obj in enumerate(points):
                        if obj == None: continue
                        yield (i, self._styler.get_bbox(fshape.Shape.decompress(obj)), obj)
                self._index_rtree = Rtree(generator_function(self._shapes))
        timer.end("loading shapes.p")

        
    def save_pickle(self, file_path):
        pickle.dump(self._shapes, open(file_path, "wb"))

        
    def load_fcad_file(self, file_path):
        timer.start("loading shapes.fcad")
        self._shapes = ShapeFile.read_fcad_file(file_path)
    
        if len(self._shapes):
            def generator_function(points):
                for i, obj in enumerate(points):
                    if obj == None: continue
                    yield (i, self._styler.get_bbox(fshape.Shape.decompress(obj)), obj)
            self._index_rtree = Rtree(generator_function(self._shapes))
        timer.end("loading shapes.fcad")
     
     
    def set_device_area(self, area): # atnaujina screen.resize()
        self._device_area = area
        
        if self._drag_to_center:
            self.center()
            self._drag_to_center = False


    def get_shape_by_id(self, id):
        compressed_shape = self._shapes[id]
        if compressed_shape == None: return None
        return fshape.Shape.decompress(compressed_shape)

        
    def get_object_by_id(self, id):
        return self._shapes[id]

        
    def draw_100(self, ctx, area):
        """100% draw for printing, no scale, area in user coordinates"""
        page_area = Area(0, 0, area.width, area.height)
        #ctx.rectangle(0, 0, area.width, area.height) 
        #ctx.clip() # tam kad nepaisytu uzh sito staciakampio ribu (tada gaunasi dubliuotos linijos)
        #self.background(ctx, page_area) # paint white background
        
        self._painter.background(ctx, page_area, color=(1,1,1), clip=True) # paint white background
        self._painter.setup(ctx, transform={"translate":(-area.x, -area.y)})

        radius = 0 #self.pixel_radius + self.line_width # ne cia reikia prideti radiusa, o ten kur dedame i cavas'a shape'us
        
        elements = self._index_rtree.intersection((area.x-radius, area.y-radius, area.x+area.width+radius, area.y+area.height+radius))
        elements_zindex = self._styler.create_zindex(elements) # jis yra pilnas visu galimu zindex'u sarasas - pradzioje dalis ju gali buti ir tusti []
        
        timer.start("draw100")
        for zindex in sorted(elements_zindex.keys()):
            for element in elements_zindex[zindex]:
                self._painter.draw(element, update=elements_zindex) # kazka visada nupaiso - bet dar papildomai gali iterpti elementu su didesniu zindex'u
                # tie elementai bus nupaisomi veliau.
            
        timer.end("draw100")
            
            
    
    
    def draw_object(self, ctx, id, fill_or_stroke=True):
        #self.apply_transforms(ctx) # drag and scale
        self._painter.setup(ctx, transform={"translate":self.get_offset(), "scale": self.get_ratio()})
        
        elements_zindex = self._styler.create_zindex([id])
        
        timer.start("draw single object")
        for zindex in sorted(elements_zindex.keys()):
            for element in elements_zindex[zindex]:
                self._painter.draw(element, update=elements_zindex, fill_or_stroke=fill_or_stroke) # kazka visada nupaiso - bet dar papildomai gali iterpti elementu su didesniu zindex'u
            
        timer.end("draw single object")
    

    def draw(self, ctx, area, fill_or_stroke=True):
        """Draw the complete drawing by drawing each object in turn."""
        
        self._painter.background(ctx, area, color=(1,1,1), clip=True) # paint white background
        self._painter.setup(ctx, transform={"translate":self.get_offset(), "scale": self.get_ratio()})
        
        # paishysime tik tuos tashkus kurie pakliuna i vartotojo langa
        # reikia device_area konvertuoti i user koordinates
        x, y = self.device_to_user(Point(area.x, area.y))
        x2, y2 = self.device_to_user(Point(area.x + area.width, area.y + area.height))
        
        radius = 0 #self.pixel_radius + self.line_width # ne cia reikia prideti radiusa, o ten kur dedame i cavas'a shape'us
        # geriau cia, nes paprasciau yra iskviesti nupaisyti didesni gabala nei paskaiciuoti tikslu pvz linijo simboliu dydi...
        
        elements = self._index_rtree.intersection((x-radius, y-radius, x2+radius, y2+radius))
        elements_zindex = self._styler.create_zindex(elements) # jis yra pilnas visu galimu zindex'u sarasas - pradzioje dalis ju gali buti ir tusti []
        
        timer.start("draw")
        for zindex in sorted(elements_zindex.keys()):
            for element in elements_zindex[zindex]:
                #print "element: ", element[0][0]
                self._painter.draw(element, update=elements_zindex, fill_or_stroke=fill_or_stroke) # kazka visada nupaiso - bet dar papildomai gali iterpti elementu su didesniu zindex'u
                # tie elementai bus nupaisomi veliau.
            
        timer.end("draw")
        
        
        
    def get_ratio(self, level=None):
        if level == None: level = self._zoom_level 
        return self._ratio_index[level]

    
    def drag2(self, drag_offset):
        self._offset = Point(self._offset.x + drag_offset.x, self._offset.y + drag_offset.y)
    
        
    def get_offset(self):
        return self._offset


    def find_objects_at_position(self, point):
        #ctx = self.get_context(transform=False) # naujas kontekstas kur paisysime, transformuoti nereikia - nes tai padarys .draw()
        ctx = cairo.Context(cairo.ImageSurface(cairo.FORMAT_ARGB32, 0,  0)) # naujas kontekstas kur paisysime, transformuoti nereikia - nes tai padarys .draw()
      
        area = Area(point.x, point.y, 1, 1)

        listener = ContextObjectsListener(point)
        listener_id = self._painter.addContextListener(listener)

        try:
            self.draw(ctx, area, fill_or_stroke=False) # nepaisysime tik sukursime path'us context'e ir su jais kazka atliks ContextListeneris
        finally:
            self._painter.removeContextListener(listener_id)
        
        return listener.get_objects() # rastu elementu indeksai

        
    def get_shape_redraw_area(self, id):
        #ctx = self.get_context(transform=False)
        ctx = cairo.Context(cairo.ImageSurface(cairo.FORMAT_ARGB32, 0,  0))
        
        shape = self.get_object_by_id(id)
        if shape == None: return None
        
        listener = ContextBoundsListener()
        listener_id = self._painter.addContextListener(listener)
        
        try:
            self.draw_object(ctx, id, fill_or_stroke=False)
        finally:
            self._painter.removeContextListener(listener_id)
            
        area = listener.get_area()
        #print "Area: ", area
        return area
        
        
    def device_to_user(self, point):
        #x, y = self.ctx.device_to_user(point.x, point.y)
        #x, y = self.get_context().device_to_user(point.x, point.y)
        
        ratio = self.get_ratio()
        offset = self.get_offset()
        x, y = (point.x - offset.x)/ratio, (point.y - offset.y)/ratio
        
        return Point(x, y)

        
    def user_to_device(self, point, offset=(0, 0)):
        #x, y = self.ctx.user_to_device(point.x, point.y)
        #x, y = self.get_context().user_to_device(point.x, point.y)
        
        ratio = self.get_ratio()
        drag_offset = self.get_offset()
        x, y = (point.x  * ratio) + drag_offset.x, (point.y  * ratio) + drag_offset.y
        
        return Point(x + offset[0], y + offset[1])

    
    def add(self, shape):
        id = len(self._shapes) # top element index
        self._shapes.append(shape.compress())
        self._index_rtree.add(id, self._styler.get_bbox(shape))
        return id

        
    def remove(self, id):
        shape = self.get_shape_by_id(id)
        self._index_rtree.delete(id, shape.bbox()) # po sito as jau niekada tokio id negausiu (nes viskas eina per rtree)
        self._shapes[id] = None

        
    def replace(self, id, shape):
        old = self.get_shape_by_id(id)
        #print "before :", list(self._index_rtree.intersection(old.bbox())) 
        if old != None:
            self._index_rtree.delete(id, old.bbox())
        #print "after :", list(self._index_rtree.intersection(old.bbox()))
        self._shapes[id] = shape.compress()
        self._index_rtree.add(id, self._styler.get_bbox(shape))
    
        
    def zoom(self, direction, center=None):
        """center cia yra device koordinatemis - jeigu butu paspausta su zoom irankiu peles pagalba"""
        new_zoom_level = self._zoom_level+direction
        if new_zoom_level in range(0, len(self._ratio_index)):
            #esamas centro taskas atlikus zooma turi islikti toje pacioje vietoje
            center = center or Point(self._device_area.width/2, self._device_area.height/2) # vartotojo parinktas tashkas arba tiesiog centras
            center_user = self.device_to_user(center)
            
            # gauname priesh tai buvusio centro koordinates naujame zoom lygyje
            new_ratio = self.get_ratio(new_zoom_level)
            new_center = Point(center_user.x * new_ratio, center_user.y * new_ratio)
                
            # gauname centro poslinki (per tiek reikia perstumti visa vaizdeli)
            self._offset = Point(center.x - new_center.x, center.y - new_center.y) # naujas poslinkis
            #print "zoom: ", self._offset
            self._zoom_level = new_zoom_level
            return True
        return False


    def center(self, point=None):
        """center to user point"""
        if not point:
            bounds = self._index_rtree.bounds
            point = Point((bounds[0]+bounds[2])/2.0, (bounds[1]+bounds[3])/2.0)
        
        hand = self.user_to_device(point)
        to = Point(self._device_area.width/2, self._device_area.height/2)
        self.drag2(Point(to.x-hand.x, to.y-hand.y))

        
    def get_projection(self):
        return self._prj
        
    def get_styler(self):
        return self._styler

        
    def load_ocad_file(self, file_path, generator=True):
        #import ocadfile
        #self.add(Shape(1, Point(0, 0), symbol="graphics")) # koordinaciu centras

        self._prj = GisProjection()
        self._zoom_level = self._ratio_index.index(4)
        
        of = OcadFile(file_path, self._prj)
        #self._styler.load_ocad_symbols(of, prj)

        timer.start("Adding ocad symbols")
        self._styler.set_symbols_style(of.get_symbols_style())
        timer.end("Adding ocad symbols")
        
        
        timer.start("Adding ocad elements")
        shapes = of.get_shapes()
        print "Shapes: ", len(shapes)
        for shape in shapes:
            self.add(shape)
        timer.end("Adding ocad elements")
        
        self.center()

        
    def load_shape_file(self, file_path, generator=True):
        import shapefile
        from random import randint

        sf = shapefile.Reader(file_path)
        print "Number of shapes: ", sf.numRecords
        
        self.add(fshape.Shape(1, Point(0, 0), style={"z-index":99})) # koordinaciu centras
        
        if self.prj.scale == 1: # pirmas kartas
            prj = GisProjection(self, sf.bbox)
            #po sito ciklo jau turesime zemelapio ribas
            center = prj.map_to_user(prj.get_center())
            self.center(center)
            self.prj = prj
                    
        timer.start("Adding shapes")
        symbol = sf.shapeName.split("/")[-1]
        self._styler.set_symbol_style(symbol, {"color": (randint(0,255),randint(0,255),randint(0,255))})
        
        for shape in sf.ogis_shapes(self.prj):
            self.add(fshape.Shape(shape.shapeType, shape.points, symbol=symbol))
        timer.end("Adding shapes")
                    
        

    def add_random_points(self, number, area, generator=True):
        """Kai generator=False - sunaudoja maziau atminties ikrovimo metu, bet trunka gerokai leciau
        """
        self._shapes = []
        timer.start("Adding random data")

        from random import randint
        for x in range(0, number):
            color = 65536 * randint(0,255) + 256 * randint(0,255) + randint(0,255) # RGBint
            x, y = randint(2, area.width), randint(2, area.height)

            if not generator: # darysime rtree.add kiekvienam taskui atskirai
                self.add(fshape.Shape(1, Point(x, y), color=color))
            else:
                self._shapes.append((1, color, x, y))
        
        if generator:
            def generator_function(points):
                for i, obj in enumerate(points):
                    yield (i, (obj[2], obj[3], obj[2], obj[3]), obj)
            self._index_rtree = Rtree(generator_function(self._shapes))
        
        timer.end("Adding random data")