nhueffme: thuban/Extensions/ogr ogrdialog.py, 1.2, 1.3 ogrshapes.py, 1.5, 1.6 ogrstart.py, 1.4, 1.5
cvs@intevation.de
cvs at intevation.de
Fri Mar 4 16:08:01 CET 2005
Author: nhueffme
Update of /thubanrepository/thuban/Extensions/ogr
In directory doto:/tmp/cvs-serv30928/Extensions/ogr
Modified Files:
ogrdialog.py ogrshapes.py ogrstart.py
Log Message:
Latest changes on OGR extension.
Added another menu item to open OGR datasource, handling of geometry collections
possible.
Index: ogrdialog.py
===================================================================
RCS file: /thubanrepository/thuban/Extensions/ogr/ogrdialog.py,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -d -r1.2 -r1.3
--- ogrdialog.py 8 Feb 2005 09:52:56 -0000 1.2
+++ ogrdialog.py 4 Mar 2005 15:07:59 -0000 1.3
@@ -16,18 +16,12 @@
try:
import ogr
except ImportError:
- psycopg = None
+ ogr = None
from Thuban import _
-from Thuban.UI.dialogs import NonModalDialog
from Thuban.Model.table import FIELDTYPE_INT
from Extensions.ogr import ogrshapes
-from Thuban.Model.messages import DBCONN_ADDED, DBCONN_REMOVED
-from Thuban.UI.messages import SESSION_REPLACED
-
-ID_DB_ADD = 9101
-ID_DB_REMOVE = 9102
ID_DBCHOOSE_RETRIEVE = 9201
ID_DBCHOOSE_OK = 9202
@@ -36,8 +30,11 @@
class ChooseFileFormat(wxDialog):
-
+ """This dialog lists all available drivers.
+ """
def __init__(self, parent, session):
+ """Initialize the dialog.
+ """
wxDialog.__init__(self, parent, -1, _("Choose file format"),
style = wxDIALOG_MODAL|wxCAPTION)
self.session = session
@@ -50,12 +47,12 @@
# Sizer for the entire dialog
top = wxFlexGridSizer(2, 1, 0, 0)
- # Sizer for the main part with the list boxes
+ # Sizer for the main part with the list box
main_sizer = wxBoxSizer(wxHORIZONTAL)
top.Add(main_sizer, 1, wxEXPAND, 0)
# The list box with the drivers
- static_box = wxStaticBoxSizer(wxStaticBox(self, -1, _("File formats")),
+ static_box = wxStaticBoxSizer(wxStaticBox(self, -1, "File formats"),
wxHORIZONTAL)
self.lb_drivers = wxListBox(self, -1)
static_box.Add(self.lb_drivers, 0, wxEXPAND, 0)
@@ -66,41 +63,6 @@
if self.lb_drivers.GetCount() > 0:
self.lb_drivers.SetSelection(0, True)
- # The button box between the connections list box and the table
- # list box
- buttons = wxFlexGridSizer(3, 1, 0, 0)
- buttons.Add(20, 80, 0, wxEXPAND, 0)
- retrieve_button = wxButton(self, ID_DBCHOOSE_RETRIEVE, _("Retrieve"))
- EVT_BUTTON(self, ID_DBCHOOSE_RETRIEVE, self.OnRetrieve)
- buttons.Add(retrieve_button, 0, wxALL
- |wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 4)
- buttons.Add(20, 80, 0, wxEXPAND, 0)
- main_sizer.Add(buttons, 0, wxEXPAND, 0)
-
- # The list box with the tables
- static_box = wxStaticBoxSizer(wxStaticBox(self, -1, _("Tables")),
- wxHORIZONTAL)
- self.lb_tables = wxListBox(self, ID_LB_DCLICK)
- EVT_LISTBOX(self, ID_LB_DCLICK, self.OnTableSelect)
- EVT_LISTBOX_DCLICK(self, ID_LB_DCLICK, self.OnLBDClick)
- static_box.Add(self.lb_tables, 0, wxEXPAND, 0)
- main_sizer.Add(static_box, 1, wxEXPAND, 0)
-
- # id column and geometry column selection
- box = wxBoxSizer(wxVERTICAL)
- box.Add(wxStaticText(self, -1, _("ID Column")), 0,
- wxALL|wxALIGN_CENTER_VERTICAL, 4)
- self.text_id_column = wxComboBox(self, -1, "")
- box.Add(self.text_id_column, 0,
- wxALL|wxALIGN_CENTER_VERTICAL|wxEXPAND, 4)
-
- box.Add(wxStaticText(self, -1, _("Geometry Column")), 0,
- wxALL|wxALIGN_CENTER_VERTICAL, 4)
- self.text_geo_column = wxComboBox(self, -1, "")
- box.Add(self.text_geo_column, 0,
- wxALL|wxALIGN_CENTER_VERTICAL|wxEXPAND, 4)
- main_sizer.Add(box, 1, wxEXPAND, 0)
-
# The standard button box at the bottom of the dialog
buttons = wxFlexGridSizer(1, 2, 0, 0)
ok_button = wxButton(self, ID_DBCHOOSE_OK, _("OK"))
@@ -120,48 +82,39 @@
def GetTable(self):
- i = self.lb_tables.GetSelection()
- if i >= 0:
- return (self.selected_conn, self.tables[i],
- self.text_id_column.GetValue(),
- self.text_geo_column.GetValue())
+ """no functionality
+ """
return None
- def OnRetrieve(self, event):
- i = self.lb_driver.GetSelection()
- if i >= 0:
- self.selected_conn = self.dbconns[i]
- self.tables = self.selected_conn.GeometryTables()
- self.lb_tables.Set(self.tables)
-
- def OnTableSelect(self, event):
- i = self.lb_tables.GetSelection()
- self.text_id_column.Clear()
- self.text_geo_column.Clear()
- if i >= 0:
- for name, typ in self.selected_conn.table_columns(self.tables[i]):
- if typ == "geometry":
- self.text_geo_column.Append(name)
- elif typ == FIELDTYPE_INT:
- self.text_id_column.Append(name)
-
def OnLBDClick(self, event):
+ """Close dialog.
+ """
if self.lb_tables.GetSelection() >= 0:
self.EndModal(wxID_OK)
self.Show(False)
def OnOK(self, event):
+ """Close dialog.
+ """
self.EndModal(wxID_OK)
self.Show(False)
def OnCancel(self, event):
+ """Close dialog.
+ """
self.EndModal(wxID_CANCEL)
self.Show(False)
class ChooseLayer(wxDialog):
+ """This dialog lists all the layers contained in the given datasource.
+
+ One layer can be chosen, which is then opened.
+ """
def __init__(self, parent, filename):
+ """Initialize the dialog.
+ """
wxDialog.__init__(self, parent, -1, _("Choose layer"),
style = wxDIALOG_MODAL|wxCAPTION)
self.tables = []
@@ -210,6 +163,9 @@
self.Layout()
def end_dialog(self, result):
+ """If the dialog is closed with OK, set chosen layer as layer
+ to be opened.
+ """
self.result = result
if result is not None:
self.EndModal(wxID_OK)
@@ -218,18 +174,31 @@
self.Show(False)
def OnOK(self, event):
+ """Dialog closed with OK button.
+ """
self.end_dialog(self.lb_drivers.GetSelection())
def OnCancel(self, event):
+ """Dialog closed with Cancel.
+ """
self.end_dialog(None)
def GetLayer(self):
+ """Return the selected layer."""
return self.layer[self.lb_drivers.GetSelection()].GetName()
class ChooseOGRDBTableDialog(wxDialog):
+ """This dialog opens a datasource from an existing database connection.
+
+ A list of all available database connections is offered. If one connection
+ is selected and the button "Retrieve" is clicked, all layers are listed.
+ One of these layers can be chosen to be opened.
+ An ID column can be chosen, too."""
def __init__(self, parent, session):
+ """Initialize the dialog.
+ """
wxDialog.__init__(self, parent, -1, _("Choose layer from database"),
style = wxDIALOG_MODAL|wxCAPTION)
self.session = session
@@ -279,6 +248,15 @@
static_box.Add(self.lb_tables, 0, wxEXPAND, 0)
main_sizer.Add(static_box, 1, wxEXPAND, 0)
+ # id column and geometry column selection
+ box = wxBoxSizer(wxVERTICAL)
+ box.Add(wxStaticText(self, -1, _("ID Column")), 0,
+ wxALL|wxALIGN_CENTER_VERTICAL, 4)
+ self.text_id_column = wxComboBox(self, -1, "")
+ box.Add(self.text_id_column, 0,
+ wxALL|wxALIGN_CENTER_VERTICAL|wxEXPAND, 4)
+ main_sizer.Add(box, 1, wxEXPAND, 0)
+
# The standard button box at the bottom of the dialog
buttons = wxFlexGridSizer(1, 2, 0, 0)
ok_button = wxButton(self, ID_DBCHOOSE_OK, _("OK"))
@@ -298,46 +276,141 @@
def GetTable(self):
+ """Return the chosen DB connection, the table to be opened,
+ the connection string for ogr and the ID column.
+ """
i = self.lb_tables.GetSelection()
if i >= 0:
- return (self.selected_conn, self.tables[i])
+ return (self.selected_conn, self.connString, self.tables[i],
+ self.text_id_column.GetValue())
return None
def OnRetrieve(self, event):
+ """Provide a list of all available layers in the selected datasource.
+ """
i = self.lb_connections.GetSelection()
if i >= 0:
self.selected_conn = self.dbconns[i]
- connString = ("PG: host=%s dbname=%s user=%s port=%s"
- %(self.selected_conn.host, self.selected_conn.dbname,
- self.selected_conn.user, self.selected_conn.port))
- ds = ogr.Open(connString)
+ self.connString = "PG: dbname=%s" %self.selected_conn.dbname
+ if self.selected_conn.host is not "":
+ self.connString = (self.connString + " host=%s"
+ %self.selected_conn.host)
+ if self.selected_conn.user is not "":
+ self.connString = (self.connString + " user=%s"
+ %self.selected_conn.user)
+ if self.selected_conn.password is not "":
+ self.connString = (self.connString + " password=%s"
+ %self.selected_conn.password)
+ if self.selected_conn.port is not "":
+ self.connString = (self.connString + " port= %s"
+ %self.selected_conn.port)
+ ds = ogr.Open(self.connString)
if ds:
for i in range(ds.GetLayerCount()):
self.tables.append(ds.GetLayer(i).GetName())
self.lb_tables.Set(self.tables)
def OnTableSelect(self, event):
+ """If a table is selected, list all possible ID columns.
+ """
i = self.lb_tables.GetSelection()
- # self.text_id_column.Clear()
- # self.text_geo_column.Clear()
- # if i >= 0:
- # for name, typ in self.selected_conn.table_columns(self.tables[i]):
- # if typ == "geometry":
- # self.text_geo_column.Append(name)
- # elif typ == FIELDTYPE_INT:
- # self.text_id_column.Append(name)
+ self.text_id_column.Clear()
+ if i >= 0:
+ for name, typ in self.selected_conn.table_columns(self.tables[i]):
+ if typ == FIELDTYPE_INT:
+ self.text_id_column.Append(name)
def OnLBDClick(self, event):
+ """Close dialog.
+ """
if self.lb_tables.GetSelection() >= 0:
self.EndModal(wxID_OK)
self.Show(False)
def OnOK(self, event):
+ """Dialog closed with OK button.
+ """
self.EndModal(wxID_OK)
self.Show(False)
def OnCancel(self, event):
+ """Dialog closed with Cancel.
+ """
self.EndModal(wxID_CANCEL)
self.Show(False)
+
+class OGRConnectionDialog(wxDialog):
+ """A string can be enteres, which is directly passed to ogr to open a
+ datasource.
+ """
+ def __init__(self, parent, session):
+ """Initialize the dialog.
+ """
+ wxDialog.__init__(self, parent, -1, "Enter string for OGRConnection",
+ style = wxDIALOG_MODAL|wxCAPTION)
+ self.session = session
+
+ # Sizer for the entire dialog
+ top = wxBoxSizer(wxVERTICAL)
+
+ # The list box with the drivers
+ box = wxBoxSizer(wxHORIZONTAL)#wxBox(self, -1, _("OGRConnection")),
+ # wxHORIZONTAL)
+ box.Add(wxStaticText(self, -1, _("URL:")), 0,
+ wxALL|wxALIGN_CENTER_VERTICAL, 4)
+ self.text_string = wxTextCtrl(self, -1, "")
+ box.Add(self.text_string, 0, wxEXPAND, 0)
+ top.Add(box, 0, wxEXPAND)
+
+ # The standard button box at the bottom of the dialog
+ buttons = wxFlexGridSizer(1, 2, 0, 0)
+ ok_button = wxButton(self, ID_DBCHOOSE_OK, _("OK"))
+ EVT_BUTTON(self, ID_DBCHOOSE_OK, self.OnOK)
+ buttons.Add(ok_button, 0, wxALL|wxALIGN_RIGHT, 4)
+ cancel_button = wxButton(self, ID_DBCHOOSE_CANCEL, _("Cancel"))
+ EVT_BUTTON(self, ID_DBCHOOSE_CANCEL, self.OnCancel)
+ buttons.Add(cancel_button, 0, wxALL, 4)
+ top.Add(buttons, 1, wxALL|wxALIGN_CENTER_HORIZONTAL, 4)
+
+ # Autosizing
+ self.SetAutoLayout(1)
+ self.SetSizer(top)
+ top.Fit(self)
+ top.SetSizeHints(self)
+ self.Layout()
+
+ def RunDialog(self):
+ """Run dialog
+ """
+ self.ShowModal()
+ self.Destroy()
+ return self.result
+
+ def end_dialog(self, result):
+ """Close dialog
+ """
+ self.result = result
+ if result is not None:
+ self.EndModal(wxID_OK)
+ else:
+ self.EndModal(wxID_CANCEL)
+ self.Show(False)
+
+ def OnOK(self, event):
+ """Dialog closed with OK
+ """
+ result = {}
+ result["string"] = getattr(self, "text_string").GetValue()
+ self.end_dialog(result)
+
+ def OnCancel(self, event):
+ """Dialog closed with Cancel.
+ """
+ self.end_dialog(None)
+
+ def GetDatasourceName(self):
+ """Return the string to be used for opening the database
+ """
+ return self.result["string"]
Index: ogrshapes.py
===================================================================
RCS file: /thubanrepository/thuban/Extensions/ogr/ogrshapes.py,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -d -r1.5 -r1.6
--- ogrshapes.py 8 Feb 2005 09:52:56 -0000 1.5
+++ ogrshapes.py 4 Mar 2005 15:07:59 -0000 1.6
@@ -17,17 +17,15 @@
ogr = None
import os
-import weakref
-from math import ceil, log
from Thuban import _
from Thuban.Model import table
+from Thuban.Model import transientdb
+from Thuban.Model.transientdb import TransientDatabase
from Thuban.Model.data import SHAPETYPE_POLYGON, SHAPETYPE_ARC, SHAPETYPE_POINT
from Thuban.Model.data import RAW_PYTHON, RAW_SHAPEFILE, RAW_WKT
-SHAPETYPE_UNKNOWN = ogr.wkbUnknown
-
def has_ogr_support():
"""Return whether this Thuban instance supports ogr file formats
@@ -37,53 +35,102 @@
return ogr is not None
if ogr is not None:
- # mapping from ogr-lib shapetype and table constants to our constants
+ SHAPETYPE_UNKNOWN = ogr.wkbUnknown
+ SHAPETYPE_GEOMCOLL = ogr.wkbGeometryCollection
+ SHAPETYPE_NONE = ogr.wkbNone
+
+ # mapping from ogr-lib shapetypes and table constants to our constants
ogrlib_shapetypes = {ogr.wkbPolygon: SHAPETYPE_POLYGON,
ogr.wkbLineString: SHAPETYPE_ARC,
ogr.wkbPoint: SHAPETYPE_POINT,
- ogr.wkbUnknown: SHAPETYPE_UNKNOWN}
+ ogr.wkbUnknown: SHAPETYPE_UNKNOWN,
+ ogr.wkbNone: SHAPETYPE_NONE,
+ ogr.wkbGeometryCollection: SHAPETYPE_GEOMCOLL}
fieldtype_map = {ogr.OFTString: table.FIELDTYPE_STRING,
ogr.OFTInteger: table.FIELDTYPE_INT,
ogr.OFTReal: table.FIELDTYPE_DOUBLE}
+else:
+ ogrlib_shapetypes = {}
+ fieldtype_map = {}
+ SHAPETYPE_UNKNOWN = 0
+ SHAPETYPE_GEOMCOLL = 7
+ SHAPETYPE_NONE = 100
+
class OGRShape:
+ """Represent one shape of an OGRShapeStore
+ """
- """Represent one shape of an OGRShapeStore"""
+ def __init__(self, shapestore, shape):
+ """Initialize the shape object.
- def __init__(self, ogrlayer, shapeid):
- self.ogrlayer = ogrlayer
- self.feature = self.ogrlayer.GetFeature(shapeid)
- self.shapeid = shapeid
+ shapestore should be an instance of OGRShapeStore,
+ shape should be an instance of an OGRFeature.
+ """
+ self.ogrlayer = shapestore.ogrlayer
+ id_column = shapestore.Id_column()
+ self.feature = shape
+ if id_column is None:
+ self.shapeid = self.feature.GetFID()
+ else:
+ self.shapeid = self.feature.GetField(id_column)
self.geom = self.feature.GetGeometryRef()
- self.shapetype = self.geom.GetGeometryType()
+ if self.geom:
+ self.shapetype = self.geom.GetGeometryType()
+ self.bbox = self._compute_bbox()
+ self.points = self._points()
+ else:
+ self.shapetype = ogr.wkbNone
+ self.bbox = None
+ self.points = [[]]
+ try:
+ self.shapetype = ogrlib_shapetypes[self.shapetype]
+ except:
+ self.shapetype = ogrlib_shapetypes[ogr.wkbUnknown]
- def compute_bbox(self):
+ self.geoms = self._geoms()
+
+ def _geoms(self):
+ """Return a list of geometry objects.
+
+ If the shape is a geometry collection, all contained geometry
+ objects are stored to the list as OGRGeometry objects.
"""
- Return the bounding box of the shape as a tuple (minx,miny,maxx,maxy)
+ geoms = []
+ if self.shapetype == SHAPETYPE_GEOMCOLL:
+ for i in range(self.geom.GetGeometryCount()):
+ geoms.append(OGRGeometry(self, self.geom, i))
+ return geoms
+
+ def _compute_bbox(self):
+ """
+ Compute the bounding box of the shape as a tuple (minx,miny,maxx,maxy)
"""
minx, maxx, miny, maxy = self.geom.GetEnvelope()
return (minx, miny, maxx, maxy)
+ def compute_bbox(self):
+ """
+ Return the bounding box of the shape as a tuple (minx,miny,maxx,maxy)
+ """
+ return self.bbox
+
def ShapeID(self):
+ """Return the feature id of this shape.
+ """
return self.shapeid
def Points(self):
- """Return the coordinates of the shape as a list of lists of pairs"""
- shape = []
- #spatialFilter = self.ogrlayer.GetSpatialFilter()
-
- #if spatialFilter is not None:
- #self.ogrlayer.SetSpatialFilter(None)
- #feature = self.ogrlayer.GetFeature(self.shapeid)
- #self.ogrlayer.SetSpatialFilter(spatialFilter)
- #else:
- #feature = self.ogrlayer.GetFeature(self.shapeid)
+ """Return the coordinates of the shape as a list of lists of pairs
+ """
+ return self.points
- #if feature is None:
- # return shape.append([])
- #geom = feature.GetGeometryRef()
+ def _points(self):
+ """Get the coordinates of the shape as a list of lists of pairs
+ """
+ shape = []
if self.geom is None:
return shape.append([])
@@ -107,7 +154,7 @@
y = geometry.GetY(point)
points.append((x, y))
shape.append(points)
- # if geometry object is of type multipolygon
+ # if geometry object is of type multipolygon or geometry collection
else:
for j in range(geometry.GetGeometryCount()):
points = []
@@ -120,46 +167,99 @@
return shape
def RawData(self):
- """Return the shape id to use with the shapestore"""
+ """Return the shape id to use with the shapestore
+ """
return self.shapeid
def OGRLayer(self):
- """Return the ogrlayer object"""
+ """Return the ogrlayer object
+ """
return self.ogrlayer
def ShapeType(self):
+ """Return the shapetype of this shape (may differ from the layer's
+ shapetype)
+ """
return self.shapetype
+ def GetGeoms(self):
+ """Return the list of geometries of this feature.
-class OGRShapeStore:
+ If this feature is a geometry collection, all contained geometries
+ are given. Else the returned list is empty.
+ """
+ return self.geoms
- """Corresponds to an OGRLayer object, containing features/shapes and
- providing all methods Thuban needs.
+ def GetGeom(self, index):
+ """Return the OGRGeometry object at the specified index.
+
+ This is not none only if the shape is a geometry collection.
+ """
+ if index < len(self.geoms):
+ return self.geoms[index]
+ else:
+ return None
+
+
+class OGRGeometry:
+ """This class represents a geometry belonging to a specified feature.
"""
- def __init__(self, filename, layername, id_column = None):
- # Make the filename absolute. The filename will be
- # interpreted relative to that anyway, but when saving a
- # session we need to compare absolute paths and it's usually
- # safer to always work with absolute paths.
+ def __init__(self, shape, geom, index):
+ """Initialize the geometry object.
- self.filename = filename
+ shape should be an OGRShape, which this geometry belongs to.
+ geom is the base geometry, index is the ReferenceID.
+ """
+ self.shape = shape
+ self.index = index
+
+ self.geom = geom.GetGeometryRef(index)
+ try:
+ self.shapetype = ogrlib_shapetypes[self.geom.GetGeometryType()]
+ except:
+ self.shapetype = ogrlib_shapetypes[ogr.wkbUnknown]
+
+
+ def ShapeType(self):
+ """Return the shapetype of this geometry object."""
+ return self.shapetype
+
+
+class OGRShapeStore:
+ """Corresponds to an OGRLayer object, containing features/shapes and
+ providing the same methods like ShapefileStore.
+ """
+
+ def __init__(self, session, filename, layername, id_column = None):
+ """Initialize the shapestore.
+
+ All required information is loaded from the datasource.
+ """
+ # if id_column is None, data is loaded from file, so we need path
+ # if id_column is not None, data is loaded from database
+ if id_column is None:
+ self.filename = os.path.abspath(filename)
+ else:
+ self.filename = filename
self.layername = layername
self.ogrdatasource = ogr.Open(filename)
self.ogrlayer = (self.ogrdatasource).GetLayerByName(layername)
- driver = self.ogrdatasource.GetDriver().GetName()
- if driver == 'PostgreSQL':
- self.id_column = 'gid'
+ if id_column is not None:
+ self.id_column = id_column
else:
- self.id_column = 'fid'
+ self.id_column = None
- self.table = OGRTable(self.ogrdatasource, self.ogrlayer, self.id_column)
+ self.table = OGRTable(session, self.ogrdatasource, self.ogrlayer,
+ self.id_column)
self._open_ogrlayer(layername)
def _open_ogrlayer(self, layername):
+ """Get all required information from the datasource.
+ """
self.numshapes = self.ogrlayer.GetFeatureCount()
self.shapetype = self.ogrlayer.GetLayerDefn().GetGeomType()
@@ -169,38 +269,73 @@
else:
self.bbox = None
- if self.shapetype is not ogr.wkbUnknown:
+ try:
self.shapetype = ogrlib_shapetypes[self.shapetype]
- #else:
- # this should be ogr.wkbUnknown, but Thuban does not know how
- # to handle an unknown shapetype (e.g. Session Tree)
- #self.shapetype = ogrlib_shapetypes[ogr.wkbPoint]
+ except:
+ # if shapetype is not contained in ogrlib_shapetypes
+ # treat it like SHAPETYPE_UNKNOWN
+ self.shapetype = ogrlib_shapetypes[ogr.wkbUnknown]
+
+ self.shapes = self.shapes()
+
+ def shapes(self):
+ """Return a collection of all features as OGRShape objects.
+ """
+ shapes = {}
+ self.ogrlayer.ResetReading()
+ if self.id_column is None:
+ nextFeature = self.ogrlayer.GetNextFeature()
+ while nextFeature is not None:
+ fid = nextFeature.GetFID()
+ shape = OGRShape(self, nextFeature)
+ shapes[shape.ShapeID()] = shape
+ nextFeature = self.ogrlayer.GetNextFeature()
+ else:
+ lay = self.ogrdatasource.ExecuteSQL("SELECT %s, * from %s"
+ % (self.id_column, self.layername))
+ if lay is not None:
+ lay.ResetReading()
+ nextFeature = lay.GetNextFeature()
+ while nextFeature is not None:
+ fid = nextFeature.GetField(0)
+ shape = OGRShape(self, nextFeature)
+ shapes[shape.ShapeID()] = shape
+ nextFeature = lay.GetNextFeature()
+ self.ogrdatasource.ReleaseResultSet(lay)
+ return shapes
def OGRLayer(self):
- """Return the OGRLayer object"""
+ """Return the OGRLayer object
+ """
return self.ogrlayer
def FileName(self):
- """Return the filename used to open the file"""
+ """Return the filename used to open the file
+ """
return self.filename
def FileType(self):
- """Return the filetype. This is always the string 'ogr-file'"""
- return "ogr-file"
+ """Return the filetype. This is depending on the driver used to open
+ the file.
+ """
+ return self.ogrdatasource.GetDriver().GetName()
def ShapeType(self):
"""Return the type of the shapes in the shapestore.
- This is either SHAPETYPE_POINT, SHAPETYPE_ARC or SHAPETYPE_POLYGON.
+ This is either SHAPETYPE_POINT, SHAPETYPE_ARC, SHAPETYPE_POLYGON,
+ SHAEPTYPE_GEOMCOLL, SHAPETYPE_NONE or SHAPETYPE_UNKNOWN.
"""
return self.shapetype
def RawShapeFormat(self):
- """Return the raw data format of the shape data, i.e. RAW_PYTHON"""
+ """Return the raw data format of the shape data, i.e. RAW_PYTHON
+ """
return RAW_PYTHON
def NumShapes(self):
- """Return the number of shapes in the shape store"""
+ """Return the number of shapes in the shape store
+ """
return self.numshapes
def BoundingBox(self):
@@ -214,53 +349,61 @@
The bbox parameter should be the bounding box as a tuple in the
form (minx, miny, maxx, maxy) in the coordinate system of the
shape store.
-
- The method GetFID() returns feature IDs starting from 0.
"""
- # Bind a few globals to locals to make it a bit faster
- cls = OGRShape
- ogrlayer = self.ogrlayer
-
left, bottom, right, top = bbox
+
# create a geometry which can be passed to the layer as spatial filter
bboxpolygon = ogr.CreateGeometryFromWkt(
('Polygon((%s %s, %s %s, %s %s,%s %s, %s %s))'
- %(left, bottom, left, top, right, top,
+ %(left, bottom, left, top, right, top,
right, bottom, left, bottom)))
- if ogrlayer.GetSpatialRef():
- bboxpolygon.AssignSpatialReference(ogrlayer.GetSpatialRef())
+ if self.ogrlayer.GetSpatialRef():
+ bboxpolygon.AssignSpatialReference(self.ogrlayer.GetSpatialRef())
- ogrlayer.ResetReading()
+ self.ogrlayer.ResetReading()
#ogrlayer.SetSpatialFilterRect(left, bottom, right, top)
- ogrlayer.SetSpatialFilter(bboxpolygon)
+ self.ogrlayer.SetSpatialFilter(bboxpolygon)
- numFeatures = ogrlayer.GetFeatureCount()
+ numFeatures = self.ogrlayer.GetFeatureCount()
+ # if no features are in bbox, return all features as shapesInRegion
+ # (PostGIS sometimes returns no features even if they are within
+ # the bounding box)
+ if numFeatures == 0:
+ self.ogrlayer.SetSpatialFilter(None)
+ numFeatures = self.ogrlayer.GetFeatureCount()
for feature in range(numFeatures):
- nextFeature = ogrlayer.GetNextFeature()
- yield cls(ogrlayer, nextFeature.GetFID())
+ nextFeature = self.ogrlayer.GetNextFeature()
+ if self.id_column is None:
+ yield self.shapes[nextFeature.GetFID()]
+ else:
+ yield self.shapes[nextFeature.GetField(self.id_column)]
- ogrlayer.SetSpatialFilter(None)
+ self.ogrlayer.SetSpatialFilter(None)
bboxpolygon.Destroy()
def AllShapes(self):
- """Return an iterable over the shapes in the shape store."""
- self.ogrlayer.ResetReading()
- nextFeature = self.ogrlayer.GetNextFeature()
- while nextFeature is not None:
- yield OGRShape(self.ogrlayer, nextFeature.GetFID())
- nextFeature = self.ogrlayer.GetNextFeature()
+ """Return an iterable over the shapes in the shape store.
+ """
+ for id in range(len(self.shapes)):
+ yield self.shapes[id]
- def Shape(self, index):
- """Return the shape with index index"""
- return OGRShape(self.ogrlayer, index)
+ def Shape(self, fid):
+ """Return the shape with fid = fid
+ """
+ if fid in self.table.ids.keys():
+ return self.shapes[fid]
+ else:
+ return None
def Table(self):
- """Return the table containing the attribute data"""
+ """Return the table containing the attribute data
+ """
return self.table
def Dependencies(self):
- """Return the empty tuple."""
+ """Return the empty tuple.
+ """
return ()
def OrigShapeStore(self):
@@ -268,24 +411,25 @@
return None
def Id_column(self):
- """Return the id_column."""
+ """Return the id_column.
+ """
return self.id_column
-class OGRTable:
-
- """A Table for an ogr file
+class OGRTable(transientdb.AutoTransientTable):
+ """A Table for an ogr datasource.
"""
- def __init__(self, ds, layer, id_column):
+ def __init__(self, session, ds, layer, id_column):
"""Initialize the OGRTable.
- ds should be an instance of OGRDatasource.
- layer should be an instance of OGRLayer.
+ session - should be the current session.
+ ds - should be an instance of OGRDatasource.
+ layer - should be an instance of OGRLayer.
+ id_column - should be the name of the column used as ID column
"""
-
self.datasource = ds
self.layer = layer
- self.tablename = layer.GetName()
+ self.tablename = self.layer.GetName()
self.id_column = id_column
# Map column names and indices to column objects.
@@ -295,12 +439,20 @@
self._map_ords_and_ids()
self._fetch_table_information()
+ self._fetch_table_content()
+
+ transientdb.AutoTransientTable.__init__(self, session.TransientDB(),
+ self)
def _fetch_table_information(self):
- """Internal: Update information about the table"""
+ """Internal: Update information about the table
+ """
self.columns = []
layerdefn = self.layer.GetLayerDefn()
+ # if FID column is of interest
+ #col = OGRColumn("FID", table.FIELDTYPE_INT, layerdefn.GetFieldCount())
+ #self.columns.append(col)
for i in range(layerdefn.GetFieldCount()):
fielddef = layerdefn.GetFieldDefn(i)
fieldname = fielddef.GetName()
@@ -314,86 +466,108 @@
self.column_map[col.name] = col
self.column_map[col.index] = col
+ def _fetch_table_content(self):
+ """Internal: Update information contained in the table
+ """
+ self.content = []
+ layerdefn = self.layer.GetLayerDefn()
+
+ self.layer.ResetReading()
+ for i in range(self.layer.GetFeatureCount()):
+ nextFeature = self.layer.GetNextFeature()
+ row = []
+ for j in range(layerdefn.GetFieldCount()):
+ row.append(nextFeature.GetField(j))
+ # if FID should be listed in the table
+ #if self.id_column is None:
+ # row.append(nextFeature.GetFID())
+ #else:
+ # row.append(nextFeature.GetField(self.id_column))
+ self.content.append(row)
+
def _map_ords_and_ids(self):
+ """Create collections which map ordinals to ids and verse visa.
+ """
self.ordinals = {}
self.ids = {}
- lay = self.datasource.ExecuteSQL(
- "SELECT %s from %s"
- %(self.id_column, self.tablename))
- lay.ResetReading()
- nextFeature = lay.GetNextFeature()
+ if self.id_column is not None:
+ lay = self.datasource.ExecuteSQL("SELECT %s from %s"
+ %(self.id_column, self.tablename))
+ lay.ResetReading()
+ nextFeature = lay.GetNextFeature()
+ else:
+ self.layer.ResetReading()
+ nextFeature = self.layer.GetNextFeature()
+
ord = 0
while nextFeature is not None:
- id = nextFeature.GetFID()
+ if self.id_column is not None:
+ id = nextFeature.GetField(self.id_column)
+ nextFeature = lay.GetNextFeature()
+ else:
+ id = nextFeature.GetFID()
+ nextFeature = self.layer.GetNextFeature()
self.ordinals[ord] = id
self.ids[id] = ord
- nextFeature = lay.GetNextFeature()
ord = ord + 1
- self.datasource.ReleaseResultSet(lay)
+ if self.id_column is not None:
+ self.datasource.ReleaseResultSet(lay)
def TableName(self):
- """Return the name of the table, which is the name of the layer"""
+ """Return the name of the table, which is the name of the layer
+ """
return self.tablename
def Title(self):
"""Return the title of the table.
-
- The title is currently
"""
return self.tablename
def Dependencies(self):
- """Return an empty tuple."""
+ """Return an empty tuple.
+ """
return ()
def NumColumns(self):
- """Return the number of columns."""
+ """Return the number of columns.
+ """
return len(self.columns)
def Columns(self):
- """Return all columns."""
+ """Return all columns.
+ """
return self.columns
def Column(self, col):
- """Return the column col. col can be either a string or an integer."""
+ """Return the column col. col can be either a string or an integer.
+ """
return self.column_map[col]
def HasColumn(self, col):
- """Return if column col exists. col can be either a string or an
+ """Return if column col exists. col can be either a string or an
integer.
"""
return self.column_map.has_key(col)
def NumRows(self):
- """Return the number of rows in the table, which equals the number of
+ """Return the number of rows in the table, which equals the number of
features in the layer.
"""
- return self.layer.GetFeatureCount()
+ return len(self.ids)
def RowIdToOrdinal(self, gid):
- """Return the row ordinal given its id"""
+ """Return the row ordinal given its id
+ """
if gid < 0:
return gid
else:
ord = self.ids[gid]
return ord
-# lay = self.datasource.ExecuteSQL(
- # "SELECT COUNT(%s) From %s where FID < %s"
- # %(self.id_column, self.tablename, gid))
- # ord = lay.GetFeature(0).GetField(0)
- # self.datasource.ReleaseResultSet(lay)
- # return ord
def RowOrdinalToId(self, num):
- """Return the rowid for given its ordinal"""
-# lay = self.datasource.ExecuteSQL(
- # "SELECT FID From %s"
- # %(self.tablename))
- # for i in range(num):
- # lay.GetNextFeature()
- # id = lay.GetNextFeature().GetField(0)
- # self.datasource.ReleaseResultSet(lay)
+ """Return the rowid for given its ordinal
+ """
if num >= 0:
id = self.ordinals[num]
return id
@@ -401,32 +575,31 @@
return num
def ReadRowAsDict(self, row, row_is_ordinal = 0):
- """Return a dictionary which contains all the fields."""
- if row_is_ordinal == 1:
- rowId = self.RowOrdinalToId(row)
+ """Return a dictionary which contains all the fields.
+ """
+ if row_is_ordinal == 0:
+ rowId = self.RowIdToOrdinal(row)
else:
rowId = row
- layerdef = self.layer.GetLayerDefn()
- feature = self.layer.GetFeature(rowId)
result = {}
- for i in range(len(self.columns)):
- fielddef = layerdef.GetFieldDefn(i)
- if feature is not None:
- result[self.columns[i].name] = feature.GetField(i)
- else:
- result[fielddef.GetName()] = None
+ for i in range(self.NumColumns()):
+ result[self.Column(i).name] = self.content[rowId][i]
return result
def ReadValue(self, row, col, row_is_ordinal = 0):
- """Return the requested value."""
- if col is None:
- return None
+ """Return the requested value.
+ """
+ if row_is_ordinal == 0:
+ rowId = self.RowIdToOrdinal(row)
else:
- feature = self.layer.GetFeature(row)
- return feature.GetField(col)
+ rowId = row
+ colIndex = self.column_map[col].index
+ return self.content[rowId][colIndex]
def ValueRange(self, col):
- """Return the value range of the given column (given as string)."""
+ """Return the value range of the given column (given as string).
+ """
+
result = self.datasource.ExecuteSQL("SELECT min(%s), max(%s) FROM %s"
%(col, col, self.layer.GetName()))
result.ResetReading()
@@ -456,7 +629,9 @@
return values
def SimpleQuery(self, left, comparison, right):
- """Return the FIDs resulting from the given query."""
+ """Return the FIDs resulting from the given query.
+ """
+
if comparison not in ("==", "!=", "<", "<=", ">=", ">"):
raise ValueError("Comparison operator %r not allowed" %comparison)
@@ -468,9 +643,13 @@
else:
right_template = right
- query = ("SELECT %s FROM %s WHERE '%s' %s %s ORDER BY FID"
- % (self.id_column, self.tablename,left.name, comparison,
- right_template))
+ if self.id_column is None:
+ id = "FID"
+ else:
+ id = self.id_column
+ query = ("SELECT %s FROM %s WHERE %s %s %s ORDER BY %s"
+ % (id, self.tablename,left.name, comparison,
+ right_template, id))
lay = self.datasource.ExecuteSQL(query)
result = []
@@ -484,12 +663,12 @@
return result
def Id_column(self):
- """Return the id_column."""
+ """Return the id_column.
+ """
return self.id_column
class OGRColumn:
-
"""Column description for a table for an ogr file
"""
Index: ogrstart.py
===================================================================
RCS file: /thubanrepository/thuban/Extensions/ogr/ogrstart.py,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -d -r1.4 -r1.5
--- ogrstart.py 8 Feb 2005 09:52:56 -0000 1.4
+++ ogrstart.py 4 Mar 2005 15:07:59 -0000 1.5
@@ -10,9 +10,7 @@
# $Id$
# Needed wx-toolkit classes
-#from wxPython.wx import *
-from wxPython.wx import wxFileDialog, wxOPEN, wxMULTIPLE, wxID_OK, \
- wxOK, wxICON_HAND
+from wxPython.wx import wxFileDialog, wxOPEN, wxMULTIPLE, wxID_OK
# We need os.path
import os
@@ -21,13 +19,13 @@
from Thuban import _
from Thuban.Model.layer import Layer
-from Thuban.UI.dbdialog import DBDialog
# Import ogr related classes
from Extensions.ogr import ogrshapes, ogrdialog
from Extensions.ogr.ogrdialog import ChooseOGRDBTableDialog
from Thuban.UI.menu import Menu
+from Thuban.UI.mainwindow import _has_dbconnections, _has_gdal_support
def open_with_ogr(context):
'''Open a file supported by ogr.
@@ -37,9 +35,13 @@
# Get the file to be opened
dlg = wxFileDialog(canvas, _("Select a data file"),
- ".", "",
- _("Shape/GML files (*.shp/*.gml)") + "|*.shp;*.gml|" +
- _("All Files (*.*)") + "|*.*",
+ context.application.Path("data"), "",
+ _("Shapefiles (*.shp)") + "|*.shp|" +
+ _("GML files (*.gml)") + "|*.gml|" +
+ _("MapInfo files (*.tab)") + "|*.tab|" +
+ _("DGN files (*.dgn)") + "|*.dgn|" +
+ _("CSV files (*.csv)") + "|*.csv|" +
+ _("All Files (*.*)") + "|*.*|",
wxOPEN | wxMULTIPLE)
if dlg.ShowModal() == wxID_OK:
@@ -50,22 +52,23 @@
layerDlg = ogrdialog.ChooseLayer(canvas, filename)
if layerDlg.ShowModal() == wxID_OK:
layername = layerDlg.GetLayer()
- try:
- session = context.application.Session()
- store = ogrshapes.OGRShapeStore(filename, layername)
- session.AddShapeStore(store)
- except:
- # the layer couldn't be opened
- context.mainwindow.RunMessageBox(("Add Layer"),
+ try:
+ session = context.application.Session()
+ store = OpenFileShapestore(session, filename, layername)
+ session.AddShapeStore(store)
+ except:
+ # the layer couldn't be opened
+ context.mainwindow.RunMessageBox(("Add Layer"),
("Can't open the file '%s'.")%filename)
- else:
- layer = Layer(title, store)
- map.AddLayer(layer)
- if not has_layers:
- # if we're adding a layer to an empty map, fit the
- # new map to the window
- canvas.FitMapToWindow()
- context.application.SetPath("data",filename)
+ else:
+ if store is not None:
+ layer = Layer(title, store)
+ map.AddLayer(layer)
+ if not has_layers:
+ # if we're adding a layer to an empty map, fit the
+ # new map to the window
+ canvas.FitMapToWindow()
+ context.application.SetPath("data",filename)
dlg.Destroy()
def select_file_format(context):
@@ -81,7 +84,7 @@
dlg = ogrdialog.ChooseFileFormat(canvas, session)
if dlg.ShowModal() == wxID_OK:
- context.mainwindow.RunMessageBox("dialog auf", "dialog auf")
+ pass
dlg.Destroy()
def open_db(context):
@@ -91,17 +94,14 @@
canvas = context.mainwindow.canvas
map = canvas.Map()
- session = context.application.Session()
+ session = context.application.Session()
dlg = ChooseOGRDBTableDialog(canvas, session)
if dlg.ShowModal() == wxID_OK:
- dbconn, dbtable = dlg.GetTable()
+ dbconn, connString, dbtable, id_column = dlg.GetTable()
try:
- # Choose the correct Interface for the database type
- filename = ('PG: host=%s user=%s dbname=%s port=%s'
- %(dbconn.host, dbconn.user, dbconn.dbname, dbconn.port))
-
- store = ogrshapes.OGRShapeStore(filename, dbtable)
+ store = OpenDBShapestore(session, dbconn, dbtable, id_column,
+ None)
session.AddShapeStore(store)
layer = Layer(dbtable, store)
@@ -117,7 +117,77 @@
% dbtable)
dlg.Destroy()
+def open_OGRConnection(context):
+ """Open a datasource with an OGRConnection string."""
+ canvas = context.mainwindow.canvas
+ map = canvas.Map()
+ session = context.application.Session()
+ dlg = ogrdialog.OGRConnectionDialog(canvas, session)
+
+ if dlg.ShowModal() == wxID_OK:
+ dsname = dlg.GetDatasourceName()
+
+ layerDlg = ogrdialog.ChooseLayer(canvas, dsname)
+ if layerDlg.ShowModal() == wxID_OK:
+ layername = layerDlg.GetLayer()
+ try:
+ store = ogrshapes.OGRShapeStore(session, dsname, layername)
+ session.AddShapeStore(store)
+ except:
+ # the layer couldn't be opened
+ context.mainwindow.RunMessageBox(("Add Layer"),
+ ("Can't open the file '%s'.") % dsname)
+ else:
+ layer = Layer(dsname, store)
+ has_layers = map.HasLayers()
+ map.AddLayer(layer)
+ if not has_layers:
+ # if we're adding a layer to an empty map, fit the
+ # new map to the window
+ canvas.FitMapToWindow()
+ dlg.Destroy()
+
+def OpenFileShapestore(session, filename, layername):
+ """Open a datasource and add the required layer.
+ """
+ try:
+ store = ogrshapes.OGRShapeStore(session, filename, layername)
+ return store
+ except:
+ # Some error occured while initializing the layer
+ context.mainwindow.RunMessageBox(_("Open datasource"),
+ _("Can't open the datasource '%s'")
+ % filename)
+ else:
+ return null
+
+def OpenDBShapestore(session, dbconn, layername, id_column, geo_column):
+ """Open a datasource and add the required layer.
+
+ dbconn - shold be a DBConnection
+ layername - the name of the table which should opened as layer
+ id_column - the column name which should be used as ID column
+ geo_column - always None for ogr
+ """
+ try:
+ filename = "PG: dbname=%s" %dbconn.dbname
+ if dbconn.host is not "":
+ filename = filename + " host=%s" % dbconn.host
+ if dbconn.user is not "":
+ filename = filename + " user=%s" % dbconn.user
+ if dbconn.password is not "":
+ filename = filename + " password=%s" % dbconn.password
+ if dbconn.port is not "":
+ filename = filename + " port=%s" % dbconn.port
+ store = ogrshapes.OGRShapeStore(session, filename, layername,
+ id_column = id_column)
+ return store
+ except:
+ # Some error occured while initializing the layer
+ context.mainwindow.RunMessageBox(_("Open datasource"),
+ _("Can't open the datasource '%s'")
+ % filename)
# Thuban has named commands which can be registered in the central
# instance registry.
@@ -128,28 +198,37 @@
from Thuban.UI.mainwindow import main_menu
-# find the map menu (create it a new if not found)
+# find the map menu (create a new if not found)
map_menu = main_menu.FindOrInsertMenu('map', _('Map'))
ogr_menu = Menu("ogr", _("Open layer via OGR"),[])
+ogrsupport = ogrshapes.has_ogr_support()
# create new commands and register them
registry.Add(Command('open_ogr_files', 'Open an ogr-file', open_with_ogr,
+ sensitive = _has_gdal_support,
helptext = 'Open a file supported from ogr'))
-registry.Add(Command('select_file_format', 'Select a file format',
- select_file_format,
- helptext = "Select a file format supported from ogr"))
+#registry.Add(Command('select_file_format', 'Select a file format',
+# select_file_format,
+# helptext = "Select a file format supported from ogr"))
registry.Add(Command('open_db', 'Open a layer from a database',
open_db,
+ sensitive = _has_dbconnections,
helptext = "Open a layer from a database, e.g. PostGIS"))
+registry.Add(Command('open_OGRConnection',
+ ("Open a datasource with an OGRConnection string"),
+ open_OGRConnection,
+ sensitive = _has_gdal_support, helptext =
+ "Open a datasource with an OGRConnection string"))
+
# finally bind the new command with an entry in the extensions menu
ogr_menu.InsertItem("open_ogr_files")
-ogr_menu.InsertItem('select_file_format')
+#ogr_menu.InsertItem('select_file_format')
ogr_menu.InsertItem('open_db')
+ogr_menu.InsertItem('open_OGRConnection')
# Add ogr menu to map menu
map_menu.InsertItem(ogr_menu, after = "rasterlayer_add")
-
More information about the Thuban-devel
mailing list
This site is hosted by Intevation GmbH (Datenschutzerklärung und Impressum | Privacy Policy and Imprint)