[GRASS-SVN] r53350 - in grass/trunk/lib/python: . pygrass pygrass/docs pygrass/modules pygrass/raster pygrass/tests pygrass/vector
svn_grass at osgeo.org
svn_grass at osgeo.org
Wed Oct 10 05:24:32 PDT 2012
Author: zarch
Date: 2012-10-10 05:24:32 -0700 (Wed, 10 Oct 2012)
New Revision: 53350
Added:
grass/trunk/lib/python/pygrass/
grass/trunk/lib/python/pygrass/Makefile
grass/trunk/lib/python/pygrass/__init__.py
grass/trunk/lib/python/pygrass/docs/
grass/trunk/lib/python/pygrass/docs/Makefile
grass/trunk/lib/python/pygrass/docs/attributes.rst
grass/trunk/lib/python/pygrass/docs/conf.py
grass/trunk/lib/python/pygrass/docs/index.rst
grass/trunk/lib/python/pygrass/docs/intro.rst
grass/trunk/lib/python/pygrass/docs/make.bat
grass/trunk/lib/python/pygrass/docs/modules.rst
grass/trunk/lib/python/pygrass/docs/raster.rst
grass/trunk/lib/python/pygrass/docs/vector.rst
grass/trunk/lib/python/pygrass/env.py
grass/trunk/lib/python/pygrass/errors.py
grass/trunk/lib/python/pygrass/modules/
grass/trunk/lib/python/pygrass/modules/Makefile
grass/trunk/lib/python/pygrass/modules/__init__.py
grass/trunk/lib/python/pygrass/orderdict.py
grass/trunk/lib/python/pygrass/raster/
grass/trunk/lib/python/pygrass/raster/Makefile
grass/trunk/lib/python/pygrass/raster/__init__.py
grass/trunk/lib/python/pygrass/raster/abstract.py
grass/trunk/lib/python/pygrass/raster/buffer.py
grass/trunk/lib/python/pygrass/raster/category.py
grass/trunk/lib/python/pygrass/raster/history.py
grass/trunk/lib/python/pygrass/raster/raster_type.py
grass/trunk/lib/python/pygrass/raster/rowio.py
grass/trunk/lib/python/pygrass/raster/segment.py
grass/trunk/lib/python/pygrass/region.py
grass/trunk/lib/python/pygrass/tests/
grass/trunk/lib/python/pygrass/tests/Makefile
grass/trunk/lib/python/pygrass/tests/__init__.py
grass/trunk/lib/python/pygrass/tests/benchmark.py
grass/trunk/lib/python/pygrass/tests/set_mapset.py
grass/trunk/lib/python/pygrass/vector/
grass/trunk/lib/python/pygrass/vector/Makefile
grass/trunk/lib/python/pygrass/vector/__init__.py
grass/trunk/lib/python/pygrass/vector/abstract.py
grass/trunk/lib/python/pygrass/vector/basic.py
grass/trunk/lib/python/pygrass/vector/geometry.py
grass/trunk/lib/python/pygrass/vector/sql.py
grass/trunk/lib/python/pygrass/vector/table.py
grass/trunk/lib/python/pygrass/vector/vector_type.py
Modified:
grass/trunk/lib/python/Makefile
Log:
Add pygrass library into grass
Modified: grass/trunk/lib/python/Makefile
===================================================================
--- grass/trunk/lib/python/Makefile 2012-10-09 23:20:48 UTC (rev 53349)
+++ grass/trunk/lib/python/Makefile 2012-10-10 12:24:32 UTC (rev 53350)
@@ -13,12 +13,13 @@
PYFILES := $(patsubst %,$(DSTDIR)/%.py,$(MODULES) __init__)
PYCFILES := $(patsubst %,$(DSTDIR)/%.pyc,$(MODULES) __init__)
-CLEAN_SUBDIRS = ctypes temporal
+CLEAN_SUBDIRS = ctypes temporal pygrass
EXTRA_CLEAN_FILES = setup.py
default: $(PYFILES) $(PYCFILES) $(GDIR)/__init__.py $(GDIR)/__init__.pyc
-$(MAKE) -C ctypes || echo $(CURDIR)/ctypes >> $(ERRORLOG)
-$(MAKE) -C temporal || echo $(CURDIR)/temporal >> $(ERRORLOG)
+ -$(MAKE) -C pygrass || echo $(CURDIR)/pygrass >> $(ERRORLOG)
$(PYDIR):
$(MKDIR) $@
Copied: grass/trunk/lib/python/pygrass/Makefile (from rev 53343, grass/trunk/lib/python/Makefile)
===================================================================
--- grass/trunk/lib/python/pygrass/Makefile (rev 0)
+++ grass/trunk/lib/python/pygrass/Makefile 2012-10-10 12:24:32 UTC (rev 53350)
@@ -0,0 +1,37 @@
+MODULE_TOPDIR=../../..
+
+include $(MODULE_TOPDIR)/include/Make/Other.make
+include $(MODULE_TOPDIR)/include/Make/Python.make
+include $(MODULE_TOPDIR)/include/Make/Doxygen.make
+
+PYDIR = $(ETC)/python
+GDIR = $(PYDIR)/grass
+DSTDIR = $(GDIR)/pygrass
+
+MODULES = errors env orderdict region
+
+CLEAN_SUBDIRS = modules raster vector tests
+
+PYFILES := $(patsubst %,$(DSTDIR)/%.py,$(MODULES) __init__)
+PYCFILES := $(patsubst %,$(DSTDIR)/%.pyc,$(MODULES) __init__)
+
+default: $(PYFILES) $(PYCFILES) $(GDIR)/__init__.py $(GDIR)/__init__.pyc
+ -$(MAKE) -C modules || echo $(CURDIR)/modules >> $(ERRORLOG)
+ -$(MAKE) -C raster || echo $(CURDIR)/raster >> $(ERRORLOG)
+ -$(MAKE) -C vector || echo $(CURDIR)/vector >> $(ERRORLOG)
+ -$(MAKE) -C tests || echo $(CURDIR)/tests >> $(ERRORLOG)
+
+$(PYDIR):
+ $(MKDIR) $@
+
+$(GDIR): | $(PYDIR)
+ $(MKDIR) $@
+
+$(DSTDIR): | $(GDIR)
+ $(MKDIR) $@
+
+$(DSTDIR)/%: % | $(DSTDIR)
+ $(INSTALL_DATA) $< $@
+
+#doxygen:
+DOXNAME = pythonpygrass
Added: grass/trunk/lib/python/pygrass/__init__.py
===================================================================
--- grass/trunk/lib/python/pygrass/__init__.py (rev 0)
+++ grass/trunk/lib/python/pygrass/__init__.py 2012-10-10 12:24:32 UTC (rev 53350)
@@ -0,0 +1,21 @@
+# -*- coding: utf-8 -*-
+"""
+Created on Fri May 25 12:55:14 2012
+
+ at author: pietro
+"""
+import grass.lib.gis as _libgis
+_libgis.G_gisinit('')
+import os as _os
+import sys as _sys
+
+_pygrasspath = _os.path.dirname(_os.path.realpath( __file__ )).split(_os.sep)
+
+_sys.path.append(_os.path.join(_os.sep,*_pygrasspath[:-1]))
+
+import region
+import raster
+import vector
+import modules
+import errors
+import env
\ No newline at end of file
Added: grass/trunk/lib/python/pygrass/docs/Makefile
===================================================================
--- grass/trunk/lib/python/pygrass/docs/Makefile (rev 0)
+++ grass/trunk/lib/python/pygrass/docs/Makefile 2012-10-10 12:24:32 UTC (rev 53350)
@@ -0,0 +1,158 @@
+# Makefile for Sphinx documentation
+#
+
+# You can set these variables from the command line.
+SPHINXOPTS =
+ifneq (@(type sphinx-build2 > /dev/null),)
+SPHINXBUILD = sphinx-build2
+endif
+ifneq (@(type sphinx-build > /dev/null),)
+SPHINXBUILD = sphinx-build
+endif
+PAPER =
+BUILDDIR = _build
+
+# Internal variables.
+PAPEROPT_a4 = -D latex_paper_size=a4
+PAPEROPT_letter = -D latex_paper_size=letter
+ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
+# the i18n builder cannot share the environment and doctrees with the others
+I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
+
+.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext
+
+help:
+ @echo "Please use \`make <target>' where <target> is one of"
+ @echo " html to make standalone HTML files"
+ @echo " dirhtml to make HTML files named index.html in directories"
+ @echo " singlehtml to make a single large HTML file"
+ @echo " pickle to make pickle files"
+ @echo " json to make JSON files"
+ @echo " htmlhelp to make HTML files and a HTML help project"
+ @echo " qthelp to make HTML files and a qthelp project"
+ @echo " devhelp to make HTML files and a Devhelp project"
+ @echo " epub to make an epub"
+ @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
+ @echo " latexpdf to make LaTeX files and run them through pdflatex"
+ @echo " text to make text files"
+ @echo " man to make manual pages"
+ @echo " texinfo to make Texinfo files"
+ @echo " info to make Texinfo files and run them through makeinfo"
+ @echo " gettext to make PO message catalogs"
+ @echo " changes to make an overview of all changed/added/deprecated items"
+ @echo " linkcheck to check all external links for integrity"
+ @echo " doctest to run all doctests embedded in the documentation (if enabled)"
+
+clean:
+ -rm -rf $(BUILDDIR)/*
+
+html:
+ $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
+ @echo
+ @echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
+
+dirhtml:
+ $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
+ @echo
+ @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
+
+singlehtml:
+ $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
+ @echo
+ @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
+
+pickle:
+ $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
+ @echo
+ @echo "Build finished; now you can process the pickle files."
+
+json:
+ $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
+ @echo
+ @echo "Build finished; now you can process the JSON files."
+
+htmlhelp:
+ $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
+ @echo
+ @echo "Build finished; now you can run HTML Help Workshop with the" \
+ ".hhp project file in $(BUILDDIR)/htmlhelp."
+
+qthelp:
+ $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
+ @echo
+ @echo "Build finished; now you can run "qcollectiongenerator" with the" \
+ ".qhcp project file in $(BUILDDIR)/qthelp, like this:"
+ @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/PyGrass.qhcp"
+ @echo "To view the help file:"
+ @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/PyGrass.qhc"
+
+devhelp:
+ $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
+ @echo
+ @echo "Build finished."
+ @echo "To view the help file:"
+ @echo "# mkdir -p $$HOME/.local/share/devhelp/PyGrass"
+ @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/PyGrass"
+ @echo "# devhelp"
+
+epub:
+ $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
+ @echo
+ @echo "Build finished. The epub file is in $(BUILDDIR)/epub."
+
+latex:
+ $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
+ @echo
+ @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
+ @echo "Run \`make' in that directory to run these through (pdf)latex" \
+ "(use \`make latexpdf' here to do that automatically)."
+
+latexpdf:
+ $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
+ @echo "Running LaTeX files through pdflatex..."
+ $(MAKE) -C $(BUILDDIR)/latex all-pdf
+ @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
+
+text:
+ $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
+ @echo
+ @echo "Build finished. The text files are in $(BUILDDIR)/text."
+
+man:
+ $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
+ @echo
+ @echo "Build finished. The manual pages are in $(BUILDDIR)/man."
+
+texinfo:
+ $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
+ @echo
+ @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
+ @echo "Run \`make' in that directory to run these through makeinfo" \
+ "(use \`make info' here to do that automatically)."
+
+info:
+ $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
+ @echo "Running Texinfo files through makeinfo..."
+ make -C $(BUILDDIR)/texinfo info
+ @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
+
+gettext:
+ $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
+ @echo
+ @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
+
+changes:
+ $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
+ @echo
+ @echo "The overview file is in $(BUILDDIR)/changes."
+
+linkcheck:
+ $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
+ @echo
+ @echo "Link check complete; look for any errors in the above output " \
+ "or in $(BUILDDIR)/linkcheck/output.txt."
+
+doctest:
+ $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
+ @echo "Testing of doctests in the sources finished, look at the " \
+ "results in $(BUILDDIR)/doctest/output.txt."
Added: grass/trunk/lib/python/pygrass/docs/attributes.rst
===================================================================
--- grass/trunk/lib/python/pygrass/docs/attributes.rst (rev 0)
+++ grass/trunk/lib/python/pygrass/docs/attributes.rst 2012-10-10 12:24:32 UTC (rev 53350)
@@ -0,0 +1,138 @@
+Attributes
+===========
+
+It is possible to access to the vector attributes with: ::
+
+ >>> from pygrass.vector import Vector
+ >>> municip = Vector('boundary_municp_sqlite')
+ >>> municip.open()
+ >>> municip.dblinks
+ DBlinks([[Link(1, boundary_municp, sqlite)]])
+
+The vector map have a ``table`` attributes that contain a Table object, that
+have some useful attributes like: layer, name, driver, etc.
+
+ >>> link = municip.dblinks[1]
+ >>> link.number
+ 1
+ >>> link.name
+ 'boundary_municp'
+ >>> link.table_name
+ 'boundary_municp_sqlite'
+ >>> link.driver
+ 'sqlite'
+ >>> link.database # doctest: +ELLIPSIS
+ '.../sqlite.db'
+ >>> link.key
+ 'cat'
+
+It is possible to change values, like: ::
+
+ >>> link.name = 'boundary'
+ >>> link.driver = 'pg'
+ >>> link.database = 'host=localhost,dbname=grassdb'
+ >>> link.key = 'gid'
+
+Now change again to old values: ::
+
+ >>> link.name = 'boundary_municp_sqlite'
+ >>> link.driver = 'sqlite'
+ >>> link.database = '$GISDBASE/$LOCATION_NAME/$MAPSET/sqlite.db'
+ >>> link.key = 'cat'
+
+Link object have methods that return a
+:ref:`Connection object <python:library:sqlite3:connection-objects>`, and to
+return a Table object: ::
+
+ >>> conn = link.connection()
+ >>> cur = conn.cursor()
+ >>> import sql
+ >>> cur.execute(sql.SELECT.format(cols=', '.join(['cat', 'AREA']),
+ ... tname=link.name)) # doctest: +ELLIPSIS
+ <sqlite3.Cursor object at ...>
+ >>> cur.fetchone()
+ (1, 0.0)
+ >>> cur.close()
+ >>> conn.close()
+
+From the Link object we can instantiate a Table object that allow user to
+make simple query with the Filters object: ::
+
+ >>> table = link.table()
+ >>> table.filters.select('cat', 'COUNTY',
+ ... 'AREA','PERIMETER').order_by('AREA').limit(3)
+ Filters('SELECT cat, COUNTY, AREA, PERIMETER FROM boundary_municp_sqlite ORDER BY AREA LIMIT 3;')
+ >>> cur = table.execute()
+ >>> for row in cur.fetchall():
+ ... print repr(row)
+ ...
+ (1, u'SURRY', 0.0, 1415.331)
+ (2, u'SURRY', 0.0, 48286.011)
+ (3, u'CASWELL', 0.0, 5750.087)
+
+
+Then we can get table information about table columns, from the columns
+attribute that is an instantiation of a Columns class.
+
+
+ >>> table.columns # doctest: +ELLIPSIS
+ Columns([(u'cat', u'integer'), ..., (u'ACRES', u'double precision')])
+ >>> table.columns.names() # doctest: +ELLIPSIS
+ [u'cat', u'OBJECTID', u'AREA', u'PERIMETER', ..., u'ACRES']
+ >>> table.columns.types() # doctest: +ELLIPSIS
+ [u'integer', u'integer', u'double precision', ..., u'double precision']
+
+
+.. note ::
+ If the map use postgresql it is possible to: add/rename/cast/remove columns
+ the sqlite does not support these operations.
+
+
+For people that are used to the standardized Python SQL 2.0 interface:
+
+ * http://docs.python.org/library/sqlite3.html
+ * http://www.python.org/dev/peps/pep-0249/
+
+Therefore advanced user can just use, the connect attribute to build
+a new cursor object and interact with the database. ::
+
+ >>> cur = table.conn.cursor()
+ >>> cur.execute("SELECT * FROM %s" % table.name) # doctest: +ELLIPSIS
+ <sqlite3.Cursor object at ...>
+ >>> cur.fetchone()[:5] # doctest: +ELLIPSIS
+ (1, 1, 0.0, 1415.331, 2.0)
+ >>> # Close communication with the database
+ >>> cur.close()
+ >>> conn.close()
+
+
+
+Link
+-------
+
+.. autoclass:: pygrass.vector.table.Link
+ :members:
+
+DBlinks
+-------
+
+.. autoclass:: pygrass.vector.table.DBlinks
+ :members:
+
+Filters
+-------
+
+.. autoclass:: pygrass.vector.table.Filters
+ :members:
+
+Columns
+-------
+
+.. autoclass:: pygrass.vector.table.Columns
+ :members:
+
+Table
+-----
+
+.. autoclass:: pygrass.vector.table.Table
+ :members:
\ No newline at end of file
Added: grass/trunk/lib/python/pygrass/docs/conf.py
===================================================================
--- grass/trunk/lib/python/pygrass/docs/conf.py (rev 0)
+++ grass/trunk/lib/python/pygrass/docs/conf.py 2012-10-10 12:24:32 UTC (rev 53350)
@@ -0,0 +1,292 @@
+# -*- coding: utf-8 -*-
+#
+# PyGrass documentation build configuration file, created by
+# sphinx-quickstart2 on Sat Jun 16 18:53:32 2012.
+#
+# This file is execfile()d with the current directory set to its containing dir.
+#
+# Note that not all possible configuration values are present in this
+# autogenerated file.
+#
+# All configuration values have a default; values that are commented out
+# serve to show the default.
+
+import sys, os
+
+# If extensions (or modules to document with autodoc) are in another directory,
+# add these directories to sys.path here. If the directory is relative to the
+# documentation root, use os.path.abspath to make it absolute, like shown here.
+sys.path.insert(0, os.path.abspath('../src/'))
+
+# -- General configuration -----------------------------------------------------
+
+# If your documentation needs a minimal Sphinx version, state it here.
+#needs_sphinx = '1.0'
+
+# Add any Sphinx extension module names here, as strings. They can be extensions
+# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
+extensions = ['sphinx.ext.autodoc', 'sphinx.ext.doctest', 'sphinx.ext.todo', 'sphinx.ext.coverage', 'sphinx.ext.mathjax', 'sphinx.ext.ifconfig', 'sphinx.ext.viewcode']
+
+# Add any paths that contain templates here, relative to this directory.
+templates_path = ['_templates']
+
+# The suffix of source filenames.
+source_suffix = '.rst'
+
+# The encoding of source files.
+#source_encoding = 'utf-8-sig'
+
+# The master toctree document.
+master_doc = 'index'
+
+# General information about the project.
+project = u'PyGrass'
+copyright = u'2012, Pietro Zambelli'
+
+# The version info for the project you're documenting, acts as replacement for
+# |version| and |release|, also used in various other places throughout the
+# built documents.
+#
+# The short X.Y version.
+version = '0.1'
+# The full version, including alpha/beta/rc tags.
+release = 'alpha'
+
+# The language for content autogenerated by Sphinx. Refer to documentation
+# for a list of supported languages.
+language = 'python'
+
+# There are two options for replacing |today|: either, you set today to some
+# non-false value, then it is used:
+#today = ''
+# Else, today_fmt is used as the format for a strftime call.
+#today_fmt = '%B %d, %Y'
+
+# List of patterns, relative to source directory, that match files and
+# directories to ignore when looking for source files.
+exclude_patterns = ['_build']
+
+# The reST default role (used for this markup: `text`) to use for all documents.
+#default_role = None
+
+# If true, '()' will be appended to :func: etc. cross-reference text.
+#add_function_parentheses = True
+
+# If true, the current module name will be prepended to all description
+# unit titles (such as .. function::).
+#add_module_names = True
+
+# If true, sectionauthor and moduleauthor directives will be shown in the
+# output. They are ignored by default.
+#show_authors = False
+
+# The name of the Pygments (syntax highlighting) style to use.
+pygments_style = 'sphinx'
+
+# A list of ignored prefixes for module index sorting.
+#modindex_common_prefix = []
+
+# If true, doctest flags (comments looking like # doctest: FLAG, ...)
+# at the ends of lines and <BLANKLINE> markers are removed for all code blocks
+# showing interactive Python sessions (i.e. doctests). Default is true.
+trim_doctest_flags = True
+
+
+intersphinx_mapping = {'python': ('http://docs.python.org/2.7', None)}
+
+# -- Options for HTML output ---------------------------------------------------
+
+# The theme to use for HTML and HTML Help pages. See the documentation for
+# a list of builtin themes.
+html_theme = 'default'
+
+# Theme options are theme-specific and customize the look and feel of a theme
+# further. For a list of options available for each theme, see the
+# documentation.
+#html_theme_options = {}
+
+# Add any paths that contain custom themes here, relative to this directory.
+#html_theme_path = []
+
+# The name for this set of Sphinx documents. If None, it defaults to
+# "<project> v<release> documentation".
+#html_title = None
+
+# A shorter title for the navigation bar. Default is the same as html_title.
+#html_short_title = None
+
+# The name of an image file (relative to this directory) to place at the top
+# of the sidebar.
+#html_logo = None
+
+# The name of an image file (within the static path) to use as favicon of the
+# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
+# pixels large.
+#html_favicon = None
+
+# Add any paths that contain custom static files (such as style sheets) here,
+# relative to this directory. They are copied after the builtin static files,
+# so a file named "default.css" will overwrite the builtin "default.css".
+html_static_path = ['_static']
+
+# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
+# using the given strftime format.
+#html_last_updated_fmt = '%b %d, %Y'
+
+# If true, SmartyPants will be used to convert quotes and dashes to
+# typographically correct entities.
+#html_use_smartypants = True
+
+# Custom sidebar templates, maps document names to template names.
+#html_sidebars = {}
+
+# Additional templates that should be rendered to pages, maps page names to
+# template names.
+#html_additional_pages = {}
+
+# If false, no module index is generated.
+#html_domain_indices = True
+
+# If false, no index is generated.
+html_use_index = True
+
+# If true, the index is split into individual pages for each letter.
+#html_split_index = False
+
+# If true, links to the reST sources are added to the pages.
+html_show_sourcelink = True
+
+# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
+html_show_sphinx = True
+
+# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
+html_show_copyright = True
+
+# If true, an OpenSearch description file will be output, and all pages will
+# contain a <link> tag referring to it. The value of this option must be the
+# base URL from which the finished HTML is served.
+#html_use_opensearch = ''
+
+# This is the file name suffix for HTML files (e.g. ".xhtml").
+#html_file_suffix = None
+
+# Output file base name for HTML help builder.
+htmlhelp_basename = 'PyGrassdoc'
+
+
+# -- Options for LaTeX output --------------------------------------------------
+
+latex_elements = {
+# The paper size ('letterpaper' or 'a4paper').
+'papersize': 'a4paper',
+
+# The font size ('10pt', '11pt' or '12pt').
+'pointsize': '10pt',
+
+# Additional stuff for the LaTeX preamble.
+#'preamble': '',
+}
+
+# Grouping the document tree into LaTeX files. List of tuples
+# (source start file, target name, title, author, documentclass [howto/manual]).
+latex_documents = [
+ ('index', 'PyGrass.tex', u'PyGrass Documentation',
+ u'Pietro Zambelli', 'manual'),
+]
+
+# The name of an image file (relative to this directory) to place at the top of
+# the title page.
+#latex_logo = None
+
+# For "manual" documents, if this is true, then toplevel headings are parts,
+# not chapters.
+#latex_use_parts = False
+
+# If true, show page references after internal links.
+#latex_show_pagerefs = False
+
+# If true, show URL addresses after external links.
+#latex_show_urls = False
+
+# Documents to append as an appendix to all manuals.
+#latex_appendices = []
+
+# If false, no module index is generated.
+#latex_domain_indices = True
+
+
+# -- Options for manual page output --------------------------------------------
+
+# One entry per manual page. List of tuples
+# (source start file, name, description, authors, manual section).
+man_pages = [
+ ('index', 'pygrass', u'PyGrass Documentation',
+ [u'Pietro Zambelli'], 1)
+]
+
+# If true, show URL addresses after external links.
+#man_show_urls = False
+
+
+# -- Options for Texinfo output ------------------------------------------------
+
+# Grouping the document tree into Texinfo files. List of tuples
+# (source start file, target name, title, author,
+# dir menu entry, description, category)
+texinfo_documents = [
+ ('index', 'PyGrass', u'PyGrass Documentation',
+ u'Pietro Zambelli', 'PyGrass', 'One line description of project.',
+ 'Miscellaneous'),
+]
+
+# Documents to append as an appendix to all manuals.
+#texinfo_appendices = []
+
+# If false, no module index is generated.
+#texinfo_domain_indices = True
+
+# How to display URL addresses: 'footnote', 'no', or 'inline'.
+#texinfo_show_urls = 'footnote'
+
+
+# -- Options for Epub output ---------------------------------------------------
+
+# Bibliographic Dublin Core info.
+epub_title = u'PyGrass'
+epub_author = u'Pietro Zambelli'
+epub_publisher = u'Pietro Zambelli'
+epub_copyright = u'2012, Pietro Zambelli'
+
+# The language of the text. It defaults to the language option
+# or en if the language is not set.
+#epub_language = ''
+
+# The scheme of the identifier. Typical schemes are ISBN or URL.
+#epub_scheme = ''
+
+# The unique identifier of the text. This can be a ISBN number
+# or the project homepage.
+#epub_identifier = ''
+
+# A unique identification for the text.
+#epub_uid = ''
+
+# A tuple containing the cover image and cover page html template filenames.
+#epub_cover = ()
+
+# HTML files that should be inserted before the pages created by sphinx.
+# The format is a list of tuples containing the path and title.
+#epub_pre_files = []
+
+# HTML files shat should be inserted after the pages created by sphinx.
+# The format is a list of tuples containing the path and title.
+#epub_post_files = []
+
+# A list of files that should not be packed into the epub file.
+#epub_exclude_files = []
+
+# The depth of the table of contents in toc.ncx.
+#epub_tocdepth = 3
+
+# Allow duplicate toc entries.
+#epub_tocdup = True
Added: grass/trunk/lib/python/pygrass/docs/index.rst
===================================================================
--- grass/trunk/lib/python/pygrass/docs/index.rst (rev 0)
+++ grass/trunk/lib/python/pygrass/docs/index.rst 2012-10-10 12:24:32 UTC (rev 53350)
@@ -0,0 +1,40 @@
+.. PyGrass documentation master file, created by
+ sphinx-quickstart2 on Sat Jun 16 18:53:32 2012.
+ You can adapt this file completely to your liking, but it should at least
+ contain the root `toctree` directive.
+
+Welcome to PyGrass's documentation!
+===================================
+
+Since in the 2006 GRASS developers start to adopt python for the new GUI,
+python becoming more and more important and developers plan to convert all
+the bash scripts in to python for the next major release GRASS 7.
+
+``pygrass`` want to improve integration between GRASS and python, make the
+use of python under GRASS more consistent with the language itself and make
+the GRASS scripting and programming activity easier and more natural
+to the final users.
+
+This project has been funded with support from the google Summer of Code 2012.
+
+
+Contents:
+
+.. toctree::
+ :maxdepth: 2
+
+ intro
+ raster
+ vector
+ attributes
+ modules
+
+
+
+Indices and tables
+==================
+
+* :ref:`genindex`
+* :ref:`modindex`
+* :ref:`search`
+
Added: grass/trunk/lib/python/pygrass/docs/intro.rst
===================================================================
--- grass/trunk/lib/python/pygrass/docs/intro.rst (rev 0)
+++ grass/trunk/lib/python/pygrass/docs/intro.rst 2012-10-10 12:24:32 UTC (rev 53350)
@@ -0,0 +1,30 @@
+Introduction
+=============
+
+To work with ``pygrass`` you need a up-to-date version of GRASS 7.
+You can obtain a recent version following the information on the
+`main web site <http://grass.osgeo.org/download/software.php#g70x>`_
+of GRASS, and you can read more about compilation on the
+`GRASS wiki <http://grass.osgeo.org/wiki/Compile_and_Install>`_
+
+Now you can download the ``pygrass`` source using ``git``
+
+::
+
+ git clone https://lucadeluge@code.google.com/p/pygrass/
+
+If you have not ``git`` you can install it from the `git website <http://git-scm.com/downloads>`_
+or download the source code of ``pygrass`` from `<http://code.google.com/p/pygrass/downloads/list>`_
+
+At this point you have to install ``pygrass``, so enter in the right
+folder and launch with administration permission
+
+::
+
+ python setup.py install
+
+The last action before start to work with ``pygrass`` is to run
+GRASS 7 and from the console launch ``python`` or ``ipython``
+(the second one is the the suggested)
+
+Read more about how to work with :doc:`raster`, :doc:`vector`, :doc:`modules`.
\ No newline at end of file
Added: grass/trunk/lib/python/pygrass/docs/make.bat
===================================================================
--- grass/trunk/lib/python/pygrass/docs/make.bat (rev 0)
+++ grass/trunk/lib/python/pygrass/docs/make.bat 2012-10-10 12:24:32 UTC (rev 53350)
@@ -0,0 +1,190 @@
+ at ECHO OFF
+
+REM Command file for Sphinx documentation
+
+if "%SPHINXBUILD%" == "" (
+ set SPHINXBUILD=sphinx-build2
+)
+set BUILDDIR=_build
+set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% .
+set I18NSPHINXOPTS=%SPHINXOPTS% .
+if NOT "%PAPER%" == "" (
+ set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS%
+ set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS%
+)
+
+if "%1" == "" goto help
+
+if "%1" == "help" (
+ :help
+ echo.Please use `make ^<target^>` where ^<target^> is one of
+ echo. html to make standalone HTML files
+ echo. dirhtml to make HTML files named index.html in directories
+ echo. singlehtml to make a single large HTML file
+ echo. pickle to make pickle files
+ echo. json to make JSON files
+ echo. htmlhelp to make HTML files and a HTML help project
+ echo. qthelp to make HTML files and a qthelp project
+ echo. devhelp to make HTML files and a Devhelp project
+ echo. epub to make an epub
+ echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter
+ echo. text to make text files
+ echo. man to make manual pages
+ echo. texinfo to make Texinfo files
+ echo. gettext to make PO message catalogs
+ echo. changes to make an overview over all changed/added/deprecated items
+ echo. linkcheck to check all external links for integrity
+ echo. doctest to run all doctests embedded in the documentation if enabled
+ goto end
+)
+
+if "%1" == "clean" (
+ for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i
+ del /q /s %BUILDDIR%\*
+ goto end
+)
+
+if "%1" == "html" (
+ %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The HTML pages are in %BUILDDIR%/html.
+ goto end
+)
+
+if "%1" == "dirhtml" (
+ %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml.
+ goto end
+)
+
+if "%1" == "singlehtml" (
+ %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml.
+ goto end
+)
+
+if "%1" == "pickle" (
+ %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished; now you can process the pickle files.
+ goto end
+)
+
+if "%1" == "json" (
+ %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished; now you can process the JSON files.
+ goto end
+)
+
+if "%1" == "htmlhelp" (
+ %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished; now you can run HTML Help Workshop with the ^
+.hhp project file in %BUILDDIR%/htmlhelp.
+ goto end
+)
+
+if "%1" == "qthelp" (
+ %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished; now you can run "qcollectiongenerator" with the ^
+.qhcp project file in %BUILDDIR%/qthelp, like this:
+ echo.^> qcollectiongenerator %BUILDDIR%\qthelp\PyGrass.qhcp
+ echo.To view the help file:
+ echo.^> assistant -collectionFile %BUILDDIR%\qthelp\PyGrass.ghc
+ goto end
+)
+
+if "%1" == "devhelp" (
+ %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished.
+ goto end
+)
+
+if "%1" == "epub" (
+ %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The epub file is in %BUILDDIR%/epub.
+ goto end
+)
+
+if "%1" == "latex" (
+ %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished; the LaTeX files are in %BUILDDIR%/latex.
+ goto end
+)
+
+if "%1" == "text" (
+ %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The text files are in %BUILDDIR%/text.
+ goto end
+)
+
+if "%1" == "man" (
+ %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The manual pages are in %BUILDDIR%/man.
+ goto end
+)
+
+if "%1" == "texinfo" (
+ %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo.
+ goto end
+)
+
+if "%1" == "gettext" (
+ %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The message catalogs are in %BUILDDIR%/locale.
+ goto end
+)
+
+if "%1" == "changes" (
+ %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.The overview file is in %BUILDDIR%/changes.
+ goto end
+)
+
+if "%1" == "linkcheck" (
+ %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Link check complete; look for any errors in the above output ^
+or in %BUILDDIR%/linkcheck/output.txt.
+ goto end
+)
+
+if "%1" == "doctest" (
+ %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Testing of doctests in the sources finished, look at the ^
+results in %BUILDDIR%/doctest/output.txt.
+ goto end
+)
+
+:end
Added: grass/trunk/lib/python/pygrass/docs/modules.rst
===================================================================
--- grass/trunk/lib/python/pygrass/docs/modules.rst (rev 0)
+++ grass/trunk/lib/python/pygrass/docs/modules.rst 2012-10-10 12:24:32 UTC (rev 53350)
@@ -0,0 +1,204 @@
+Modules
+=======
+
+Grass modules are represented as objects. These objects are generated based
+on the XML module description that is used for GUI generation already. ::
+
+ >>> from pygrass.modules import Module
+ >>> slope_aspect = Module("r.slope.aspect", elevation='elevation',
+ ... slope='slp', aspect='asp',
+ ... format='percent', overwrite=True)
+
+
+It is possible to create a run-able module object and run later:
+
+ >>> slope_aspect = Module("r.slope.aspect", elevation='elevation',
+ ... slope='slp', aspect='asp',
+ ... format='percent', overwrite=True, run_=False)
+
+Then we can run the module with: ::
+
+ >>> slope_aspect()
+
+or using the run method: ::
+
+ >>> slope_aspect.run()
+
+
+It is possible to initialize a module, and give the parameters later: ::
+
+ >>> slope_aspect = Module("r.slope.aspect")
+ >>> slope_aspect(elevation='elevation', slope='slp', aspect='asp',
+ ... format='percent', overwrite=True)
+
+
+Create the module object input step by step and run later: ::
+
+ >>> slope_aspect = Module("r.slope.aspect")
+ >>> slope_aspect.inputs['elevation']
+ Parameter <elevation> (required:yes, type:raster, multiple:no)
+ >>> slope_aspect.inputs["elevation"].value = "elevation"
+ >>> slope_aspect.inputs["format"]
+ Parameter <format> (required:no, type:string, multiple:no)
+ >>> print slope_aspect.inputs["format"].__doc__
+ format: 'degrees', optional, string
+ Format for reporting the slope
+ Values: 'degrees', 'percent'
+ >>> slope_aspect.inputs["format"].value = 'percents'
+ Traceback (most recent call last):
+ ...
+ ValueError: The Parameter <format>, must be one of: ['degrees', 'percent']
+ >>> slope_aspect.inputs["format"].value = 'percent'
+ >>> slope_aspect.flags = "g"
+ Traceback (most recent call last):
+ ...
+ ValueError: Flag not valid, valid flag are: ['a']
+ >>> slope_aspect.flags = "a"
+ >>> slope_aspect.flags_dict['overwrite']
+ Flag <overwrite> (Allow output files to overwrite existing files)
+ >>> slope_aspect.flags_dict['overwrite'].value = True
+ >>> slope_aspect()
+
+
+
+It is possible to access to the module info, with:
+
+ >>> slope_aspect.name
+ 'r.slope.aspect'
+ >>> slope_aspect.description
+ 'Aspect is calculated counterclockwise from east.'
+ >>> slope_aspect.keywords
+ 'raster, terrain'
+ >>> slope_aspect.label
+ 'Generates raster maps of slope, aspect, curvatures and partial derivatives from a elevation raster map.'
+
+and get the module documentation with: ::
+
+ >>> print slope_aspect.__doc__
+ r.slope.aspect(elevation=elevation, slope=None, aspect=None
+ format=percent, prec=None, pcurv=None
+ tcurv=None, dx=None, dy=None
+ dxx=None, dyy=None, dxy=None
+ zfactor=None, min_slp_allowed=None)
+ <BLANKLINE>
+ Parameters
+ ----------
+ <BLANKLINE>
+ <BLANKLINE>
+ elevation: required, string
+ Name of input elevation raster map
+ slope: optional, string
+ Name for output slope raster map
+ aspect: optional, string
+ Name for output aspect raster map
+ format: 'degrees', optional, string
+ Format for reporting the slope
+ Values: 'degrees', 'percent'
+ prec: 'float', optional, string
+ Type of output aspect and slope maps
+ Values: 'default', 'double', 'float', 'int'
+ pcurv: optional, string
+ Name for output profile curvature raster map
+ tcurv: optional, string
+ Name for output tangential curvature raster map
+ dx: optional, string
+ Name for output first order partial derivative dx (E-W slope) raster map
+ dy: optional, string
+ Name for output first order partial derivative dy (N-S slope) raster map
+ dxx: optional, string
+ Name for output second order partial derivative dxx raster map
+ dyy: optional, string
+ Name for output second order partial derivative dyy raster map
+ dxy: optional, string
+ Name for output second order partial derivative dxy raster map
+ zfactor: 1.0, optional, float
+ Multiplicative factor to convert elevation units to meters
+ min_slp_allowed: optional, float
+ Minimum slope val. (in percent) for which aspect is computed
+ <BLANKLINE>
+ Flags
+ ------
+ <BLANKLINE>
+ a: None
+ Do not align the current region to the elevation layer
+ overwrite: None
+ Allow output files to overwrite existing files
+ verbose: None
+ Verbose module output
+ quiet: None
+ Quiet module output
+
+
+
+For each inputs and outputs parameters it is possible to get info, to see all
+the module inputs, just type: ::
+
+ >>> slope_aspect.inputs #doctest: +NORMALIZE_WHITESPACE
+ TypeDict([('elevation', Parameter <elevation> (required:yes, type:raster, multiple:no)), ('format', Parameter <format> (required:no, type:string, multiple:no)), ('prec', Parameter <prec> (required:no, type:string, multiple:no)), ('zfactor', Parameter <zfactor> (required:no, type:float, multiple:no)), ('min_slp_allowed', Parameter <min_slp_allowed> (required:no, type:float, multiple:no))])
+
+To get info for each parameter: ::
+
+ >>> slope_aspect.inputs["elevation"].description
+ 'Name of input elevation raster map'
+ >>> slope_aspect.inputs["elevation"].type
+ 'raster'
+ >>> slope_aspect.inputs["elevation"].typedesc
+ 'string'
+ >>> slope_aspect.inputs["elevation"].multiple
+ False
+ >>> slope_aspect.inputs["elevation"].required
+ True
+
+Or get a small documentation for each parameter with:
+
+ >>> print slope_aspect.inputs["elevation"].__doc__
+ elevation: required, string
+ Name of input elevation raster map
+
+
+User or developer can check which parameter are set, with: ::
+
+ if slope_aspect.outputs['aspect'].value == None:
+ print "Aspect is not computed"
+
+
+After we set the parameter and run the module, the execution of the module
+instantiate a popen attribute to the class. The `Popen`_ class allow user
+to kill/wait/ the process. ::
+
+ >>> slope_aspect = Module('r.slope.aspect')
+ >>> slope_aspect(elevation='elevation', slope='slp', aspect='asp', overwrite=True, finish_=False)
+ >>> slope_aspect.popen.wait() # *.kill(), *.terminate()
+ 0
+ >>> out, err = slope_aspect.popen.communicate()
+ >>> print err #doctest: +NORMALIZE_WHITESPACE
+ 100%
+ Aspect raster map <asp> complete
+ Slope raster map <slp> complete
+ <BLANKLINE>
+
+On the above example we use a new parameter `finish_`, if is set to True, the
+run method, automatically store the stdout and stderr to stdout and stderr
+attributes of the class: ::
+
+ >>> slope_aspect = Module('r.slope.aspect')
+ >>> slope_aspect(elevation='elevation', slope='slp', aspect='asp', overwrite=True, finish_=True)
+ >>> print slope_aspect.stderr #doctest: +NORMALIZE_WHITESPACE
+ 100%
+ Aspect raster map <asp> complete
+ Slope raster map <slp> complete
+ <BLANKLINE>
+
+Another example of use: ::
+
+ >>> info = Module("r.info", map="elevation", flags="r", finish_=True)
+ >>> from pygrass.modules import stdout2dict
+ >>> stdout2dict(info.stdout)
+ {'max': '156.3299', 'min': '55.57879'}
+ >>> info = Module("r.info", map="elevation", flags="r", finish_=False)
+ >>> category = Module("r.category", map="elevation",
+ ... stdin_=info.popen.stdout, finish_=True)
+
+
+
+.. _Popen: http://docs.python.org/library/subprocess.html#Popen
Added: grass/trunk/lib/python/pygrass/docs/raster.rst
===================================================================
--- grass/trunk/lib/python/pygrass/docs/raster.rst (rev 0)
+++ grass/trunk/lib/python/pygrass/docs/raster.rst 2012-10-10 12:24:32 UTC (rev 53350)
@@ -0,0 +1,399 @@
+.. _raster-label:
+
+Raster
+======
+
+PyGrass use 4 different Raster classes, that respect the 4 different approaches
+of C grass API.
+The read access is row wise for :ref:`RasterRow-label` and
+:ref:`RasterRowIO-label` and additionally
+cached in the RowIO class. Booth classes write sequentially.
+RowIO is row cached, :ref:`RasterSegment-label` and :ref:`RasterNumpy-label`
+are tile cached for reading and writing therefore a randomly access is possible.
+Hence RasterRow and RasterRowIO should be used in case for fast (cached)
+row read access and RasterRow for fast sequential writing.
+Segment and Numpy should be used for random access, but numpy only for files
+not larger than 2GB.
+
+
+========================== ======================= ======== ============
+Class Name C library Read Write
+========================== ======================= ======== ============
+:ref:`RasterRow-label` `Raster library`_ randomly sequentially
+:ref:`RasterRowIO-label` `RowIO library`_ cached no
+:ref:`RasterSegment-label` `Segmentation library`_ cached randomly
+:ref:`RasterNumpy-label` `numpy.memmap`_ cached randomly
+========================== ======================= ======== ============
+
+
+All these classes share common methods and attributes, necessary to address
+common tasks as rename, remove, open, close, exist, is_open.
+In the next examples we instantiate a RasterRow object. ::
+
+ >>> from pygrass import raster
+ >>> elev = raster.RasterRow('elevation')
+ >>> elev.name
+ 'elevation'
+ >>> print(elev)
+ elevation at PERMANENT
+ >>> elev.exist()
+ True
+ >>> elev.is_open()
+ False
+ >>> new = raster.RasterRow('new')
+ >>> new.exist()
+ False
+ >>> new.is_open()
+ False
+
+
+We can rename the map: ::
+
+ >>> # setting the attribute
+ >>> new.name = 'new_map'
+ >>> print(new)
+ new_map
+ >>> # or using the rename methods
+ >>> new.rename('new')
+ >>> print(new)
+ new
+
+
+
+
+.. _RasterCategory-label:
+
+Categories
+----------
+
+All the raster classes support raster categories and share commons methods
+to modify the raster category.
+It is possible to check if the map has or not the categories with the
+``has_cats`` method. ::
+
+ >>> elev.has_cats()
+ False
+
+Opening a map that has category, for example the "landcove_1m" raster map
+from the North Carolina mapset. The ``has_cats`` method return True. ::
+
+ >>> land = raster.RasterRow('landcover_1m')
+ >>> land.has_cats()
+ True
+
+Get and set the categories title, with: ::
+
+ >>> land.cats_title
+ 'Rural area: Landcover'
+ >>> land.cats_title = 'Rural area: Landcover2'
+ >>> land.cats_title
+ 'Rural area: Landcover2'
+ >>> land.cats_title = 'Rural area: Landcover'
+
+Get the number of categories of the map with: ::
+
+ >>> land.num_cats()
+ 11
+
+See all the categories with: ::
+
+ >>> land.cats
+ [('pond', 1, None),
+ ('forest', 2, None),
+ ('developed', 3, None),
+ ('bare', 4, None),
+ ('paved road', 5, None),
+ ('dirt road', 6, None),
+ ('vineyard', 7, None),
+ ('agriculture', 8, None),
+ ('wetland', 9, None),
+ ('bare ground path', 10, None),
+ ('grass', 11, None)]
+
+Access to single category, using Rast_get_ith_cat(), with: ::
+
+ >>> land.cats[0]
+ ('pond', 1, None)
+ >>> land.cats['pond']
+ ('pond', 1, None)
+ >>> land.get_cat(0)
+ ('pond', 1, None)
+ >>> land.get_cat('pond')
+ ('pond', 1, None)
+
+Add new or change existing categories: ::
+
+ >>> land.set_cat('label', 1)
+ >>> land.get_cat('label')
+ ('label', 1, None)
+ >>> land.set_cat('pond', 1, 1)
+
+
+Sort categories, with: ::
+
+ >>> land.sort_cats()
+
+
+Copy categories from another raster map with: ::
+
+ >>> land.copy_cats(elev)
+
+Read and Write: ::
+
+ >>> land.read_cats()
+ >>> #land.write_cats()
+
+Get a Category object or set from a Category object: ::
+
+ >>> cats = land.get_cats()
+ >>> land.set_cats(cats)
+
+Export and import from a file: ::
+
+ >>> land.write_cats_rules('land_rules.csv', ';')
+ >>> land.read_cats_rules('land_rules.csv', ';')
+
+
+.. _RasterRow-label:
+
+RastRow
+-------
+
+PyGrass allow user to open the maps, in read and write mode,
+row by row using the `Raster library`_, there is not support to read and write
+to the same map at the same time, for this functionality, please see the
+:ref:`RasterSegment-label` and :ref:`RasterNumpy-label` classes.
+The RasterRow class allow to read in a randomly order the row from a map, but
+it is only possible to write the map using only a sequence order, therefore every
+time you are writing a new map, the row is add to the file as the last row. ::
+
+ >>> raster = reload(raster)
+ >>> elev = raster.RasterRow('elevation')
+ >>> # the cols attribute is set from the current region only when the map is open
+ >>> elev.cols
+ >>> elev.open()
+ >>> elev.is_open()
+ True
+ >>> elev.cols
+ 1500
+ >>> # we can read the elevation map, row by row
+ >>> for row in elev[:5]: print(row[:3])
+ [ 141.99613953 141.27848816 141.37904358]
+ [ 142.90461731 142.39450073 142.68611145]
+ [ 143.81854248 143.54707336 143.83972168]
+ [ 144.56524658 144.58493042 144.86477661]
+ [ 144.99488831 145.22894287 145.57142639]
+ >>> # we can open a new map in write mode
+ >>> new = raster.RasterRow('new')
+ >>> new.open('w', 'CELL')
+ >>> # for each elev row we can perform computation, and write the result into
+ >>> # the new map
+ >>> for row in elev:
+ ... new.put_row(row < 144)
+ ...
+ >>> # close the maps
+ >>> new.close()
+ >>> elev.close()
+ >>> # check if the map exist
+ >>> new.exist()
+ True
+ >>> # we can open the map in read mode
+ >>> new.open('r')
+ >>> for row in new[:5]: print(row[:3])
+ [1 1 1]
+ [1 1 1]
+ [1 1 1]
+ [0 0 0]
+ [0 0 0]
+ >>> new.close()
+ >>> new.remove()
+ >>> new.exist()
+ False
+
+
+.. _RasterRowIO-label:
+
+RasterRowIO
+-----------
+
+The RasterRowIO class use the grass `RowIO library`_, and implement a row
+cache. The RasterRowIO class support only reading the raster, because the
+raster rows can only be written in sequential order, writing by row id is not
+supported by design. Hence, we should use the rowio lib only for caching rows
+for reading and use the default row write access as in the RasterRow class. ::
+
+ >>> raster = reload(raster)
+ >>> elev = raster.RasterRowIO('elevation')
+ >>> elev.open('r')
+ >>> for row in elev[:5]: print(row[:3])
+ [ 141.99613953 141.27848816 141.37904358]
+ [ 142.90461731 142.39450073 142.68611145]
+ [ 143.81854248 143.54707336 143.83972168]
+ [ 144.56524658 144.58493042 144.86477661]
+ [ 144.99488831 145.22894287 145.57142639]
+ >>> elev.close()
+
+
+
+.. _RasterSegment-label:
+
+RastSegment
+-----------
+
+The RasterSegment class use the grass `Segmentation library`_, it work dividing
+the raster map into small different files, that grass read load into the memory
+and write to the hardisk.
+The segment library allow to open a map in a read-write mode. ::
+
+ >>> raster = reload(raster)
+ >>> elev = raster.RasterSegment('elevation')
+ >>> elev.open()
+ >>> for row in elev[:5]: print(row[:3])
+ [ 141.99613953 141.27848816 141.37904358]
+ [ 142.90461731 142.39450073 142.68611145]
+ [ 143.81854248 143.54707336 143.83972168]
+ [ 144.56524658 144.58493042 144.86477661]
+ [ 144.99488831 145.22894287 145.57142639]
+ >>> new = raster.RasterSegment('new')
+ >>> new.open('w', 'CELL')
+ >>> for irow in xrange(elev.rows):
+ ... new[irow] = elev[irow] < 144
+ ...
+ >>> for row in new[:5]: print(row[:3])
+ [1 1 1]
+ [1 1 1]
+ [1 1 1]
+ [0 0 0]
+ [0 0 0]
+
+The RasterSegment class define two methods to read and write the map:
+
+ * ``get_row`` that return the buffer object with the row that call the
+ C function ``segment_get_row``. ::
+
+ >>> # call explicity the method
+ >>> elev_row0 = elev.get_row(0)
+ >>> # call implicity the method
+ >>> elev_row0 = elev[0]
+
+ * ``get`` that return the value of the call map that call the
+ C function ``segment_get``. ::
+
+ >>> # call explicity the method
+ >>> elev_val_0_0 = elev.get(0, 0)
+ >>> # call implicity the method
+ >>> elev_val_0_0 = elev[0, 0]
+
+Similarly to write the map, with ``put_row``, to write a row and with ``put``
+to write a single value to the map. ::
+
+ >>> # compare the cell value get using the ``get`` method, and take the first
+ >>> # value of the row with the ``get_row`` method
+ >>> elev[0, 0] == elev[0][0]
+ True
+ >>> # write a new value to a cell,
+ >>> new[0, 0] = 10
+ >>> new[0, 0]
+ 10
+ >>> new.close()
+ >>> new.exist()
+ True
+ >>> new.remove()
+ >>> elev.close()
+ >>> elev.remove()
+
+
+
+.. _RasterNumpy-label:
+
+RasterNumpy
+-----------
+
+The RasterNumpy class, is based on the `numpy.memmap`_ class If you open an
+existing map, the map will be copied on a binary format, and read to avoid
+to load all the map in memory. ::
+
+ >>> raster = reload(raster)
+ >>> elev = raster.RasterNumpy('elevation', 'PERMANENT')
+ >>> elev.open('r')
+ >>> # in this case RasterNumpy is an extention of the numpy class
+ >>> # therefore you may use all the fancy things of numpy.
+ >>> elev[:5, :3]
+ RasterNumpy([[ 141.99613953, 141.27848816, 141.37904358],
+ [ 142.90461731, 142.39450073, 142.68611145],
+ [ 143.81854248, 143.54707336, 143.83972168],
+ [ 144.56524658, 144.58493042, 144.86477661],
+ [ 144.99488831, 145.22894287, 145.57142639]], dtype=float32)
+ >>> el = elev < 144
+ >>> el[:5, :3]
+ RasterNumpy([[1, 1, 1],
+ [1, 1, 1],
+ [1, 1, 1],
+ [0, 0, 0],
+ [0, 0, 0]], dtype=int32)
+ >>> el.name == None
+ True
+ >>> # give a name to the new map
+ >>> el.name = 'new'
+ >>> el.exist()
+ False
+ >>> el.close()
+ >>> el.exist()
+ True
+ >>> el.remove()
+
+
+
+.. _Buffer-label:
+
+Buffer
+------
+
+The buffer class is used to interact with a memory buffer of a map like a
+raster row. The buffer class is based on the `numpy.ndarray`_ class. Therefore
+all the nice feature of the ndarray are allowed.
+
+.. autoclass:: pygrass.raster.buffer.Buffer
+ :members:
+
+.. _numpy.ndarray: http://docs.scipy.org/doc/numpy/reference/generated/numpy.ndarray.html
+
+
+.. _RowIO-label:
+
+RowIO
+------
+
+.. autoclass:: pygrass.raster.rowio.RowIO
+ :members:
+
+.. _Segment-label:
+
+Segment
+-------
+
+.. autoclass:: pygrass.raster.segment.Segment
+ :members:
+
+.. _History-label:
+
+History
+--------
+
+.. autoclass:: pygrass.raster.history.History
+ :members:
+
+
+.. _Category-label:
+
+Category
+--------
+
+.. autoclass:: pygrass.raster.category.Category
+ :members:
+
+.. _Raster library: http://grass.osgeo.org/programming7/rasterlib.html/
+.. _RowIO library: http://grass.osgeo.org/programming7/rowiolib.html
+.. _Segmentation library: http://grass.osgeo.org/programming7/segmentlib.html
+.. _numpy.memmap: http://docs.scipy.org/doc/numpy/reference/generated/numpy.memmap.html
+
Added: grass/trunk/lib/python/pygrass/docs/vector.rst
===================================================================
--- grass/trunk/lib/python/pygrass/docs/vector.rst (rev 0)
+++ grass/trunk/lib/python/pygrass/docs/vector.rst 2012-10-10 12:24:32 UTC (rev 53350)
@@ -0,0 +1,197 @@
+
+Vector
+========
+
+Instantiation and basic interaction. ::
+
+ >>> from pygrass.vector import VectTopo
+ >>> municip = VectTopo('boundary_municp_sqlite')
+ >>> municip.is_open()
+ False
+ >>> municip.mapset
+ ''
+ >>> municip.exist() # check if exist, and if True set mapset
+ True
+ >>> municip.mapset
+ 'user1'
+
+
+
+Open the map with topology: ::
+
+ >>> municip.open()
+
+ get the number of primitive:
+ >>> municip.num_primitive_of('line')
+ 0
+ >>> municip.num_primitive_of('centroid')
+ 3579
+ >>> municip.num_primitive_of('boundary')
+ 5128
+
+
+
+ask for other feature in the vector map: ::
+
+ >>> municip.number_of("areas")
+ 3579
+ >>> municip.number_of("islands")
+ 2629
+ >>> municip.number_of("holes")
+ 0
+ >>> municip.number_of("lines")
+ 8707
+ >>> municip.number_of("nodes")
+ 4178
+ >>> municip.number_of("pizza") # doctest: +ELLIPSIS +NORMALIZE_WHITESPACE
+ Traceback (most recent call last):
+ ...
+ ValueError: vtype not supported, use one of: 'areas', ..., 'volumes'
+
+
+Suppose that we want to select all and only the areas that have an
+area bigger than 10000m2: ::
+
+ >>> big = [area for area in municip.viter('areas')
+ ... if area.alive() and area.area >= 10000]
+
+it's pretty easy, isn't it?!? :-)
+
+the method "viter" return an iterator object of the vector features,
+in this way no memory is wasted... User can choose on which
+vector features want to iterate...
+
+
+then you can go on with python stuff like, sort by area dimension: ::
+
+ >>> from operator import methodcaller as method
+ >>> big.sort(key = method('area'), reverse = True) # sort the list
+ >>> for area in big[:3]:
+ ... print area, area.area()
+ Area(3102) 697521857.848
+ Area(2682) 320224369.66
+ Area(2552) 298356117.948
+
+
+or sort for the number of isles that are contained inside: ::
+
+ >>> big.sort(key = lambda x: x.isles.__len__(), reverse = True)
+ >>> for area in big[:3]:
+ ... print area, area.isles.__len__()
+ ...
+ Area(2682) 68
+ Area(2753) 45
+ Area(872) 42
+
+
+or you may have only the list of the areas that contain isles inside, with: ::
+
+ >>> area_with_isles = [area for area in big if area.isles]
+ >>> area_with_isles # doctest: +ELLIPSIS
+ [Area(...), ..., Area(...)]
+
+
+
+Of course is still possible work only with a specific area, with: ::
+
+ >>> from pygrass.vector.geometry import Area
+ >>> area = Area(v_id=1859, c_mapinfo=municip.c_mapinfo)
+ >>> area.area()
+ 39486.05401495844
+ >>> area.bbox() # north, south, east, west
+ Bbox(175711.718494, 175393.514494, 460344.093986, 460115.281986)
+ >>> area.isles
+ Isles([])
+
+
+Now, find an area with an island inside... ::
+
+ >>> area = Area(v_id=2972, c_mapinfo=municip.c_mapinfo)
+ >>> area.isles # doctest: +ELLIPSIS
+ Isles([Isle(1538), Isle(1542), Isle(1543), ..., Isle(2571)])
+ >>> isle = area.isles[0]
+ >>> isle.bbox()
+ Bbox(199947.296494, 199280.969494, 754920.623987, 754351.812986)
+
+
+VectorTopo
+----------
+
+.. autoclass:: pygrass.vector.VectorTopo
+ :members:
+
+Vector
+----------
+
+.. autoclass:: pygrass.vector.Vector
+ :members:
+
+
+Vector Features
+===============
+
+Point
+------
+
+.. autoclass:: pygrass.vector.geometry.Point
+ :members:
+
+
+Line
+-----
+
+.. autoclass:: pygrass.vector.geometry.Line
+ :members:
+
+Boundary
+--------
+
+.. autoclass:: pygrass.vector.geometry.Boundary
+ :members:
+
+Isle
+-----
+
+.. autoclass:: pygrass.vector.geometry.Isle
+ :members:
+
+
+Isles
+-----
+
+.. autoclass:: pygrass.vector.geometry.Isles
+ :members:
+
+Area
+--------
+
+.. autoclass:: pygrass.vector.geometry.Boundary
+ :members:
+
+Utils
+=====
+
+Bbox
+----
+
+.. autoclass:: pygrass.vector.basic.Bbox
+ :members:
+
+
+BoxList
+--------
+
+.. autoclass:: pygrass.vector.basic.BoxList
+ :members:
+
+Ilist
+-----
+
+.. autoclass:: pygrass.vector.basic.Ilist
+ :members:
+
+Cats
+-----
+
+.. autoclass:: pygrass.vector.basic.Cats
+ :members:
\ No newline at end of file
Added: grass/trunk/lib/python/pygrass/env.py
===================================================================
--- grass/trunk/lib/python/pygrass/env.py (rev 0)
+++ grass/trunk/lib/python/pygrass/env.py 2012-10-10 12:24:32 UTC (rev 53350)
@@ -0,0 +1,57 @@
+# -*- coding: utf-8 -*-
+"""
+Created on Tue Jun 26 12:38:48 2012
+
+ at author: pietro
+"""
+import grass.lib.gis as libgis
+import fnmatch
+from grass.script import core as grasscore
+
+
+def looking(filter_string, obj):
+ """
+ >>> import grass.lib.vector as libvect
+ >>> sorted(looking('*by_box*', libvect)) # doctest: +NORMALIZE_WHITESPACE
+ ['Vect_select_areas_by_box', 'Vect_select_isles_by_box',
+ 'Vect_select_lines_by_box', 'Vect_select_nodes_by_box']
+
+ """
+ word_list = [i for i in dir(obj)]
+ word_list.sort()
+ return fnmatch.filter(word_list, filter_string)
+
+
+def remove(**kargs):
+ grasscore.run_command('g.remove', **kargs)
+
+
+def rename(oldname, newname, maptype):
+ grasscore.run_command('g.rename',
+ **{maptype: '{old},{new}'.format(old=oldname,
+ new=newname), })
+
+
+def copy(existingmap, newmap, maptype):
+ grasscore.run_command('g.copy',
+ **{maptype: '{old},{new}'.format(old=existingmap,
+ new=newmap), })
+
+
+def get_mapset_raster(mapname, mapset=''):
+ return libgis.G_find_raster(mapname, '')
+
+
+def get_mapset_vector(mapname, mapset=''):
+ return libgis.G_find_vector(mapname, '')
+
+
+def exist(mapname, mapset=''):
+ mapset = get_mapset_raster(mapname, mapset)
+ if mapset != '':
+ return True
+ else:
+ mapset = get_mapset_vector(mapname, mapset)
+ if mapset:
+ return True
+ return False
\ No newline at end of file
Added: grass/trunk/lib/python/pygrass/errors.py
===================================================================
--- grass/trunk/lib/python/pygrass/errors.py (rev 0)
+++ grass/trunk/lib/python/pygrass/errors.py 2012-10-10 12:24:32 UTC (rev 53350)
@@ -0,0 +1,22 @@
+# -*- coding: utf-8 -*-
+"""
+Created on Wed Aug 15 17:33:27 2012
+
+ at author: pietro
+"""
+
+
+class GrassError(Exception):
+ def __init__(self, value):
+ self.value = value
+
+ def __str__(self):
+ return repr(self.value)
+
+
+class OpenError(Exception):
+ def __init__(self, value):
+ self.value = value
+
+ def __str__(self):
+ return repr(self.value)
\ No newline at end of file
Copied: grass/trunk/lib/python/pygrass/modules/Makefile (from rev 53343, grass/trunk/lib/python/Makefile)
===================================================================
--- grass/trunk/lib/python/pygrass/modules/Makefile (rev 0)
+++ grass/trunk/lib/python/pygrass/modules/Makefile 2012-10-10 12:24:32 UTC (rev 53350)
@@ -0,0 +1,31 @@
+MODULE_TOPDIR = ../../../..
+
+include $(MODULE_TOPDIR)/include/Make/Other.make
+include $(MODULE_TOPDIR)/include/Make/Python.make
+include $(MODULE_TOPDIR)/include/Make/Doxygen.make
+
+PYDIR = $(ETC)/python
+GDIR = $(PYDIR)/grass
+PGDIR = $(GDIR)/pygrass
+DSTDIR= $(PGDIR)/modules
+
+
+PYFILES := $(patsubst %,$(DSTDIR)/%.py,$(MODULES) __init__)
+PYCFILES := $(patsubst %,$(DSTDIR)/%.pyc,$(MODULES) __init__)
+
+default: $(PYFILES) $(PYCFILES) $(GDIR)/__init__.py $(GDIR)/__init__.pyc
+
+$(PYDIR):
+ $(MKDIR) $@
+
+$(GDIR): | $(PYDIR)
+ $(MKDIR) $@
+
+$(DSTDIR): | $(GDIR)
+ $(MKDIR) $@
+
+$(DSTDIR)/%: % | $(DSTDIR)
+ $(INSTALL_DATA) $< $@
+
+#doxygen:
+DOXNAME = pythonpygrass
\ No newline at end of file
Added: grass/trunk/lib/python/pygrass/modules/__init__.py
===================================================================
--- grass/trunk/lib/python/pygrass/modules/__init__.py (rev 0)
+++ grass/trunk/lib/python/pygrass/modules/__init__.py 2012-10-10 12:24:32 UTC (rev 53350)
@@ -0,0 +1,500 @@
+# -*- coding: utf-8 -*-
+"""
+Created on Thu Jul 12 10:23:15 2012
+
+ at author: pietro
+
+"""
+from __future__ import print_function
+import subprocess
+
+try:
+ from collections import OrderedDict
+except:
+ from pygrass.orderdict import OrderedDict
+
+from itertools import izip_longest
+from xml.etree.ElementTree import fromstring
+import numpy as np
+import grass
+
+
+#
+# this dictionary is used to extract the value of interest from the xml
+# the lambda experssion is used to define small simple functions,
+# is equivalent to: ::
+#
+# def f(p):
+# return p.text.strip()
+#
+# and then we call f(p)
+#
+_GETFROMTAG = {
+ 'description': lambda p: p.text.strip(),
+ 'keydesc': lambda p: p.text.strip(),
+ 'gisprompt': lambda p: dict(p.items()),
+ 'default': lambda p: p.text.strip(),
+ 'values': lambda p: [e.text.strip() for e in p.findall('value/name')],
+ 'value': lambda p: None,
+ 'guisection': lambda p: p.text.strip(),
+ 'label': lambda p: p.text.strip(),
+ 'suppress_required': lambda p: None,
+ 'keywords': lambda p: p.text.strip(),
+}
+
+_GETTYPE = {
+ 'string': str,
+ 'integer': np.int32,
+ 'float': np.float32,
+ 'double': np.float64,
+}
+
+
+def stdout2dict(stdout, sep='=', default=None, val_type=None, vsep=None):
+ """Return a dictionary where entries are separated
+ by newlines and the key and value are separated by `sep' (default: `=').
+ Use the grass.core.parse_key_val function
+
+ sep: key/value separator
+ default: default value to be used
+ val_type: value type (None for no cast)
+ vsep: vertical separator (default os.linesep)
+ """
+ return grass.script.core.parse_key_val(stdout, sep, default,
+ val_type, vsep)
+
+
+class ParameterError(Exception):
+ pass
+
+
+class FlagError(Exception):
+ pass
+
+
+def _element2dict(xparameter):
+ diz = dict(xparameter.items())
+ for p in xparameter:
+ if p.tag in _GETFROMTAG:
+ diz[p.tag] = _GETFROMTAG[p.tag](p)
+ else:
+ print('New tag: %s, ignored' % p.tag)
+ return diz
+
+# dictionary used to create docstring for the objects
+_DOC = {
+ #------------------------------------------------------------
+ # head
+ 'head': """{cmd_name}({cmd_params})
+
+Parameters
+----------
+
+""",
+ #------------------------------------------------------------
+ # param
+ 'param': """{name}: {default}{required}{multi}{ptype}
+ {description}{values}""",
+ #------------------------------------------------------------
+ # flag_head
+ 'flag_head': """
+Flags
+------
+""",
+ #------------------------------------------------------------
+ # flag
+ 'flag': """{name}: {default}
+ {description}""",
+ #------------------------------------------------------------
+ # foot
+ 'foot': """
+Special Parameters
+------------------
+
+The Module class have some optional parameters which are distinct using a final
+underscore.
+
+run_: True, optional
+ If True execute the module.
+finish_: True, optional
+ If True wait untill the end of the module execution, and store the module
+ outputs into stdout, stderr attributes of the class.
+stdin_: PIPE,
+ Set the standard input
+"""}
+
+
+class Parameter(object):
+
+ def __init__(self, xparameter=None, diz=None):
+ self._value = None
+ diz = _element2dict(xparameter) if xparameter is not None else diz
+ if diz is None:
+ raise TypeError('Xparameter or diz are required')
+ self.name = diz['name']
+ self.required = True if diz['required'] == 'yes' else False
+ self.multiple = True if diz['multiple'] == 'yes' else False
+ # check the type
+ if diz['type'] in _GETTYPE:
+ self.type = _GETTYPE[diz['type']]
+ self.typedesc = diz['type']
+ self._type = _GETTYPE[diz['type']]
+ else:
+ raise TypeError('New type: %s, ignored' % diz['type'])
+
+ self.description = diz['description']
+ self.keydesc = diz['keydesc'] if 'keydesc' in diz else None
+ self.values = [self._type(
+ i) for i in diz['values']] if 'values' in diz else None
+ self.default = self._type(
+ diz['default']) if 'default' in diz else None
+ self.guisection = diz['guisection'] if 'guisection' in diz else None
+ if 'gisprompt' in diz:
+ self.type = diz['gisprompt']['prompt']
+ self.input = False if diz['gisprompt']['age'] == 'new' else True
+ else:
+ self.input = True
+
+ def _get_value(self):
+ return self._value
+
+ def _set_value(self, value):
+ if isinstance(value, list) or isinstance(value, tuple):
+ if self.multiple:
+ # check each value
+ self._value = [
+ val for val in value if isinstance(value, self._type)]
+ else:
+ str_err = 'The Parameter <%s>, not support multiple inputs'
+ raise TypeError(str_err % self.name)
+ elif isinstance(value, self._type):
+ if self.values:
+ if value in self.values:
+ self._value = value
+ else:
+ raise ValueError('The Parameter <%s>, must be one of: %r' %
+ (self.name, self.values))
+ else:
+ self._value = value
+ else:
+ raise TypeError('The Parameter <%s>, require: %s' %
+ (self.name, self.typedesc))
+
+ # here the property function is used to transform value in an attribute
+ # in this case we define which function must be use to get/set the value
+ value = property(fget=_get_value, fset=_set_value)
+
+ def __str__(self):
+ if isinstance(self._value, list) or isinstance(self._value, tuple):
+ value = ','.join([str(v) for v in self._value])
+ else:
+ value = str(self._value)
+ return "%s=%s" % (self.name, value)
+
+ def __repr__(self):
+ str_repr = "Parameter <%s> (required:%s, type:%s, multiple:%s)"
+ return str_repr % (self.name,
+ "yes" if self.required else "no",
+ self.type if self.type in (
+ 'raster', 'vector') else self.typedesc,
+ "yes" if self.multiple else "no")
+
+ # here we use property with a decorator, in this way we mask a method as
+ # a class attribute
+ @property
+ def __doc__(self):
+ """Return the docstring of the parameter
+
+ {name}: {default}{required}{multi}{ptype}
+ {description}{values}"","""
+ return _DOC['param'].format(name=self.name,
+ default=repr(self.default) + ', ' if self.default else '',
+ required='required, ' if self.required else 'optional, ',
+ multi='multi' if self.multiple else '',
+ ptype=self.typedesc, description=self.description,
+ values='\n Values: {0}'.format(', '.join([repr(val)
+ for val in self.values]))
+ if self.values else '')
+
+
+class TypeDict(OrderedDict):
+ def __init__(self, dict_type, *args, **kargs):
+ self.type = dict_type
+ super(TypeDict, self).__init__(*args, **kargs)
+
+ def __setitem__(self, key, value):
+ if isinstance(value, self.type):
+ super(TypeDict, self).__setitem__(key, value)
+ else:
+ cl = repr(self.type).translate(None, "'<> ").split('.')
+ str_err = 'The value: %r is not a %s object'
+ raise TypeError(str_err % (value, cl[-1].title()))
+
+ @property
+ def __doc__(self):
+ return '\n'.join([self.__getitem__(obj).__doc__
+ for obj in self.__iter__()])
+
+ def __call__(self):
+ return [self.__getitem__(obj) for obj in self.__iter__()]
+
+
+class Flag(object):
+ def __init__(self, xflag=None, diz=None):
+ self.value = None
+ diz = _element2dict(xflag) if xflag is not None else diz
+ self.name = diz['name']
+ self.special = True if self.name in (
+ 'verbose', 'overwrite', 'quiet', 'run') else False
+ self.description = diz['description']
+ self.default = diz['default'] if 'default' in diz else None
+ self.guisection = diz['guisection'] if 'guisection' in diz else None
+
+ def __str__(self):
+ if self.value:
+ if self.special:
+ return '--%s' % self.name[0]
+ else:
+ return '-%s' % self.name
+ else:
+ return ''
+
+ def __repr__(self):
+ return "Flag <%s> (%s)" % (self.name, self.description)
+
+ @property
+ def __doc__(self):
+ """
+ {name}: {default}
+ {description}"""
+ return _DOC['flag'].format(name=self.name,
+ default=repr(self.default),
+ description=self.description)
+
+
+class Module(object):
+ """
+
+ Python allow developers to not specify all the arguments and
+ keyword arguments of a method or function.
+
+ ::
+
+ def f(*args):
+ for arg in args:
+ print arg
+
+ therefore if we call the function like: ::
+
+ >>> f('grass', 'gis', 'modules')
+ grass
+ gis
+ modules
+
+ or we can define a new list: ::
+
+ >>> words = ['grass', 'gis', 'modules']
+ >>> f(*words)
+ grass
+ gis
+ modules
+
+ we can do the same with keyword arguments, rewrite the above function: ::
+
+ def f(*args, **kargs):
+ for arg in args:
+ print arg
+ for key, value in kargs.items():
+ print "%s = %r" % (key, value)
+
+ now we can use the new function, with: ::
+
+ >>> f('grass', 'gis', 'modules', os = 'linux', language = 'python')
+ grass
+ gis
+ modules
+ os = 'linux'
+ language = 'python'
+
+ or, as before we can, define a dictionary and give the dictionary to
+ the function, like: ::
+
+ >>> keywords = {'os' : 'linux', 'language' : 'python'}
+ >>> f(*words, **keywords)
+ grass
+ gis
+ modules
+ os = 'linux'
+ language = 'python'
+
+ In the Module class we heavily use this language feature to pass arguments
+ and keyword arguments to the grass module.
+ """
+ def __init__(self, cmd, *args, **kargs):
+ self.name = cmd
+ # call the command with --interface-description
+ get_cmd_xml = subprocess.Popen([cmd, "--interface-description"],
+ stdout=subprocess.PIPE)
+ # get the xml of the module
+ self.xml = get_cmd_xml.communicate()[0]
+ # transform and parse the xml into an Element class:
+ # http://docs.python.org/library/xml.etree.elementtree.html
+ tree = fromstring(self.xml)
+
+ for e in tree:
+ if e.tag not in ('parameter', 'flag'):
+ self.__setattr__(e.tag, _GETFROMTAG[e.tag](e))
+
+ #
+ # extract parameters from the xml
+ #
+ self.params_list = [Parameter(p) for p in tree.findall("parameter")]
+ self.inputs = TypeDict(Parameter)
+ self.outputs = TypeDict(Parameter)
+ self.required = []
+ # Insert parameters into input/output and required
+ for par in self.params_list:
+ if par.input:
+ self.inputs[par.name] = par
+ else:
+ self.outputs[par.name] = par
+ if par.required:
+ self.required.append(par)
+
+ #
+ # extract flags from the xml
+ #
+ flags_list = [Flag(f) for f in tree.findall("flag")]
+ self.flags_dict = TypeDict(Flag)
+ for flag in flags_list:
+ self.flags_dict[flag.name] = flag
+
+ #
+ # Add new attributes to the class
+ #
+ self._flags = ''
+ self.run_ = True
+ self.finish_ = True
+ self.stdin_ = subprocess.PIPE
+ self.stdout = subprocess.PIPE
+ self.stderr = subprocess.PIPE
+ self.popen = None
+
+ if args or kargs:
+ self.__call__(*args, **kargs)
+
+ def _get_flags(self):
+ return self._flags
+
+ def _set_flags(self, value):
+ if isinstance(value, str):
+ flgs = [flg for flg in self.flags_dict
+ if not self.flags_dict[flg].special]
+ # we need to check if the flag is valid, special flags are not
+ # allow
+ if value in flgs:
+ self._flags = value
+ else:
+ raise ValueError('Flag not valid, valid flag are: %r' % flgs)
+ else:
+ raise TypeError('The flags attribute must be a string')
+
+ flags = property(fget=_get_flags, fset=_set_flags)
+
+ def __call__(self, *args, **kargs):
+ if not args and not kargs:
+ self.run()
+ return
+ #
+ # check for extra kargs, set attribute and remove from dictionary
+ #
+ if 'flags' in kargs:
+ self.flags = kargs['flags']
+ del(kargs['flags'])
+ if 'run_' in kargs:
+ self.run_ = kargs['run_']
+ del(kargs['run_'])
+ if 'stdin_' in kargs:
+ self.stdin_ = kargs['stdin_']
+ del(kargs['stdin_'])
+ if 'finish_' in kargs:
+ self.finish_ = kargs['finish_']
+ del(kargs['finish_'])
+
+ #
+ # check args
+ #
+ for param, arg in zip(self.params_list, args):
+ param.value = arg
+ for key, val in kargs.items():
+ if key in self.inputs:
+ self.inputs[key].value = val
+ elif key in self.outputs:
+ self.outputs[key].value = val
+ elif key in self.flags_dict:
+ # we need to add this, because some parameters (overwrite,
+ # verbose and quiet) work like parameters
+ self.flags_dict[key].value = val
+ else:
+ raise ParameterError('Parameter not found')
+
+ #
+ # check reqire parameters
+ #
+ for par in self.required:
+ if par.value is None:
+ raise ParameterError(
+ "Required parameter <%s> not set." % par.name)
+
+ #
+ # check flags parameters
+ #
+ if self.flags:
+ # check each character in flags
+ for flag in self.flags:
+ if flag in self.flags_dict:
+ self.flags_dict[flag].value = True
+ else:
+ raise FlagError('Flag "%s" not valid.')
+
+ #
+ # check if execute
+ #
+ if self.run_:
+ self.run()
+
+ @property
+ def __doc__(self):
+ """{cmd_name}({cmd_params})
+ """
+ head = _DOC['head'].format(cmd_name=self.name,
+ cmd_params=('\n' + # go to a new line
+ # give space under the function name
+ (' ' * (len(self.name) + 1))).join([', '.join(
+ # transform each parameter in string
+ [str(param) for param in line if param is not None])
+ # make a list of parameters with only 3 param per line
+ for line in izip_longest(*[iter(self.params_list)] * 3)]),)
+ params = '\n'.join([par.__doc__ for par in self.params_list])
+ flags = self.flags_dict.__doc__
+ return '\n'.join([head, params, _DOC['flag_head'], flags])
+
+ def make_cmd(self):
+ args = [self.name, ]
+ for par in self.params_list:
+ if par.value is not None:
+ args.append(str(par))
+ for flg in self.flags_dict:
+ if self.flags_dict[flg].value is not None:
+ args.append(str(self.flags_dict[flg]))
+ return args
+
+ def run(self, node=None):
+ cmd = self.make_cmd()
+ #print(repr(cmd))
+ self.popen = subprocess.Popen(cmd, stdin=self.stdin_,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE)
+ if self.finish_:
+ self.popen.wait()
+ self.stdout, self.stderr = self.popen.communicate()
\ No newline at end of file
Added: grass/trunk/lib/python/pygrass/orderdict.py
===================================================================
--- grass/trunk/lib/python/pygrass/orderdict.py (rev 0)
+++ grass/trunk/lib/python/pygrass/orderdict.py 2012-10-10 12:24:32 UTC (rev 53350)
@@ -0,0 +1,259 @@
+# Backport of OrderedDict() class that runs on Python 2.4, 2.5, 2.6, 2.7 and pypy.
+# Passes Python2.7's test suite and incorporates all the latest updates.
+# Created by Raymond Hettinger on Wed, 18 Mar 2009 (MIT License)
+
+try:
+ from thread import get_ident as _get_ident
+except ImportError:
+ from dummy_thread import get_ident as _get_ident
+
+try:
+ from _abcoll import KeysView, ValuesView, ItemsView
+except ImportError:
+ pass
+
+
+class OrderedDict(dict):
+ 'Dictionary that remembers insertion order'
+ # An inherited dict maps keys to values.
+ # The inherited dict provides __getitem__, __len__, __contains__, and get.
+ # The remaining methods are order-aware.
+ # Big-O running times for all methods are the same as for regular dictionaries.
+
+ # The internal self.__map dictionary maps keys to links in a doubly linked list.
+ # The circular doubly linked list starts and ends with a sentinel element.
+ # The sentinel element never gets deleted (this simplifies the algorithm).
+ # Each link is stored as a list of length three: [PREV, NEXT, KEY].
+
+ def __init__(self, *args, **kwds):
+ '''Initialize an ordered dictionary. Signature is the same as for
+ regular dictionaries, but keyword arguments are not recommended
+ because their insertion order is arbitrary.
+
+ '''
+ if len(args) > 1:
+ raise TypeError('expected at most 1 arguments, got %d' % len(args))
+ try:
+ self.__root
+ except AttributeError:
+ self.__root = root = [] # sentinel node
+ root[:] = [root, root, None]
+ self.__map = {}
+ self.__update(*args, **kwds)
+
+ def __setitem__(self, key, value, dict_setitem=dict.__setitem__):
+ 'od.__setitem__(i, y) <==> od[i]=y'
+ # Setting a new item creates a new link which goes at the end of the linked
+ # list, and the inherited dictionary is updated with the new key/value pair.
+ if key not in self:
+ root = self.__root
+ last = root[0]
+ last[1] = root[0] = self.__map[key] = [last, root, key]
+ dict_setitem(self, key, value)
+
+ def __delitem__(self, key, dict_delitem=dict.__delitem__):
+ 'od.__delitem__(y) <==> del od[y]'
+ # Deleting an existing item uses self.__map to find the link which is
+ # then removed by updating the links in the predecessor and successor nodes.
+ dict_delitem(self, key)
+ link_prev, link_next, key = self.__map.pop(key)
+ link_prev[1] = link_next
+ link_next[0] = link_prev
+
+ def __iter__(self):
+ 'od.__iter__() <==> iter(od)'
+ root = self.__root
+ curr = root[1]
+ while curr is not root:
+ yield curr[2]
+ curr = curr[1]
+
+ def __reversed__(self):
+ 'od.__reversed__() <==> reversed(od)'
+ root = self.__root
+ curr = root[0]
+ while curr is not root:
+ yield curr[2]
+ curr = curr[0]
+
+ def clear(self):
+ 'od.clear() -> None. Remove all items from od.'
+ try:
+ for node in self.__map.itervalues():
+ del node[:]
+ root = self.__root
+ root[:] = [root, root, None]
+ self.__map.clear()
+ except AttributeError:
+ pass
+ dict.clear(self)
+
+ def popitem(self, last=True):
+ '''od.popitem() -> (k, v), return and remove a (key, value) pair.
+ Pairs are returned in LIFO order if last is true or FIFO order if false.
+
+ '''
+ if not self:
+ raise KeyError('dictionary is empty')
+ root = self.__root
+ if last:
+ link = root[0]
+ link_prev = link[0]
+ link_prev[1] = root
+ root[0] = link_prev
+ else:
+ link = root[1]
+ link_next = link[1]
+ root[1] = link_next
+ link_next[0] = root
+ key = link[2]
+ del self.__map[key]
+ value = dict.pop(self, key)
+ return key, value
+
+ # -- the following methods do not depend on the internal structure --
+
+ def keys(self):
+ 'od.keys() -> list of keys in od'
+ return list(self)
+
+ def values(self):
+ 'od.values() -> list of values in od'
+ return [self[key] for key in self]
+
+ def items(self):
+ 'od.items() -> list of (key, value) pairs in od'
+ return [(key, self[key]) for key in self]
+
+ def iterkeys(self):
+ 'od.iterkeys() -> an iterator over the keys in od'
+ return iter(self)
+
+ def itervalues(self):
+ 'od.itervalues -> an iterator over the values in od'
+ for k in self:
+ yield self[k]
+
+ def iteritems(self):
+ 'od.iteritems -> an iterator over the (key, value) items in od'
+ for k in self:
+ yield (k, self[k])
+
+ def update(*args, **kwds):
+ '''od.update(E, **F) -> None. Update od from dict/iterable E and F.
+
+ If E is a dict instance, does: for k in E: od[k] = E[k]
+ If E has a .keys() method, does: for k in E.keys(): od[k] = E[k]
+ Or if E is an iterable of items, does: for k, v in E: od[k] = v
+ In either case, this is followed by: for k, v in F.items(): od[k] = v
+
+ '''
+ if len(args) > 2:
+ raise TypeError('update() takes at most 2 positional '
+ 'arguments (%d given)' % (len(args),))
+ elif not args:
+ raise TypeError('update() takes at least 1 argument (0 given)')
+ self = args[0]
+ # Make progressively weaker assumptions about "other"
+ other = ()
+ if len(args) == 2:
+ other = args[1]
+ if isinstance(other, dict):
+ for key in other:
+ self[key] = other[key]
+ elif hasattr(other, 'keys'):
+ for key in other.keys():
+ self[key] = other[key]
+ else:
+ for key, value in other:
+ self[key] = value
+ for key, value in kwds.items():
+ self[key] = value
+
+ __update = update # let subclasses override update without breaking __init__
+
+ __marker = object()
+
+ def pop(self, key, default=__marker):
+ '''od.pop(k[,d]) -> v, remove specified key and return the corresponding value.
+ If key is not found, d is returned if given, otherwise KeyError is raised.
+
+ '''
+ if key in self:
+ result = self[key]
+ del self[key]
+ return result
+ if default is self.__marker:
+ raise KeyError(key)
+ return default
+
+ def setdefault(self, key, default=None):
+ 'od.setdefault(k[,d]) -> od.get(k,d), also set od[k]=d if k not in od'
+ if key in self:
+ return self[key]
+ self[key] = default
+ return default
+
+ def __repr__(self, _repr_running={}):
+ 'od.__repr__() <==> repr(od)'
+ call_key = id(self), _get_ident()
+ if call_key in _repr_running:
+ return '...'
+ _repr_running[call_key] = 1
+ try:
+ if not self:
+ return '%s()' % (self.__class__.__name__,)
+ return '%s(%r)' % (self.__class__.__name__, self.items())
+ finally:
+ del _repr_running[call_key]
+
+ def __reduce__(self):
+ 'Return state information for pickling'
+ items = [[k, self[k]] for k in self]
+ inst_dict = vars(self).copy()
+ for k in vars(OrderedDict()):
+ inst_dict.pop(k, None)
+ if inst_dict:
+ return (self.__class__, (items,), inst_dict)
+ return self.__class__, (items,)
+
+ def copy(self):
+ 'od.copy() -> a shallow copy of od'
+ return self.__class__(self)
+
+ @classmethod
+ def fromkeys(cls, iterable, value=None):
+ '''OD.fromkeys(S[, v]) -> New ordered dictionary with keys from S
+ and values equal to v (which defaults to None).
+
+ '''
+ d = cls()
+ for key in iterable:
+ d[key] = value
+ return d
+
+ def __eq__(self, other):
+ '''od.__eq__(y) <==> od==y. Comparison to another OD is order-sensitive
+ while comparison to a regular mapping is order-insensitive.
+
+ '''
+ if isinstance(other, OrderedDict):
+ return len(self)==len(other) and self.items() == other.items()
+ return dict.__eq__(self, other)
+
+ def __ne__(self, other):
+ return not self == other
+
+ # -- the following methods are only used in Python 2.7 --
+
+ def viewkeys(self):
+ "od.viewkeys() -> a set-like object providing a view on od's keys"
+ return KeysView(self)
+
+ def viewvalues(self):
+ "od.viewvalues() -> an object providing a view on od's values"
+ return ValuesView(self)
+
+ def viewitems(self):
+ "od.viewitems() -> a set-like object providing a view on od's items"
+ return ItemsView(self)
\ No newline at end of file
Copied: grass/trunk/lib/python/pygrass/raster/Makefile (from rev 53343, grass/trunk/lib/python/Makefile)
===================================================================
--- grass/trunk/lib/python/pygrass/raster/Makefile (rev 0)
+++ grass/trunk/lib/python/pygrass/raster/Makefile 2012-10-10 12:24:32 UTC (rev 53350)
@@ -0,0 +1,32 @@
+MODULE_TOPDIR = ../../../..
+
+include $(MODULE_TOPDIR)/include/Make/Other.make
+include $(MODULE_TOPDIR)/include/Make/Python.make
+include $(MODULE_TOPDIR)/include/Make/Doxygen.make
+
+PYDIR = $(ETC)/python
+GDIR = $(PYDIR)/grass
+PGDIR = $(GDIR)/pygrass
+DSTDIR= $(PGDIR)/raster
+
+MODULES = abstract buffer category history raster_type rowio segment
+
+PYFILES := $(patsubst %,$(DSTDIR)/%.py,$(MODULES) __init__)
+PYCFILES := $(patsubst %,$(DSTDIR)/%.pyc,$(MODULES) __init__)
+
+default: $(PYFILES) $(PYCFILES) $(GDIR)/__init__.py $(GDIR)/__init__.pyc
+
+$(PYDIR):
+ $(MKDIR) $@
+
+$(GDIR): | $(PYDIR)
+ $(MKDIR) $@
+
+$(DSTDIR): | $(GDIR)
+ $(MKDIR) $@
+
+$(DSTDIR)/%: % | $(DSTDIR)
+ $(INSTALL_DATA) $< $@
+
+#doxygen:
+DOXNAME = pythonpygrass
\ No newline at end of file
Added: grass/trunk/lib/python/pygrass/raster/__init__.py
===================================================================
--- grass/trunk/lib/python/pygrass/raster/__init__.py (rev 0)
+++ grass/trunk/lib/python/pygrass/raster/__init__.py 2012-10-10 12:24:32 UTC (rev 53350)
@@ -0,0 +1,676 @@
+# -*- coding: utf-8 -*-
+"""
+Created on Fri May 25 12:56:33 2012
+
+ at author: pietro
+"""
+import ctypes
+import numpy as np
+
+#
+# import GRASS modules
+#
+from grass.script import fatal, warning
+from grass.script import core as grasscore
+#from grass.script import core
+#import grass.lib as grasslib
+import grass.lib.gis as libgis
+import grass.lib.raster as libraster
+import grass.lib.segment as libseg
+import grass.lib.rowio as librowio
+
+#
+# import pygrass modules
+#
+from pygrass.errors import OpenError
+from pygrass.region import Region
+
+#
+# import raster classes
+#
+from abstract import RasterAbstractBase
+from raster_type import TYPE as RTYPE, RTYPE_STR
+from buffer import Buffer
+from segment import Segment
+from rowio import RowIO
+from category import Category
+from history import History
+
+class RasterRow(RasterAbstractBase):
+ """Raster_row_access": Inherits: "Raster_abstract_base" and implements
+ the default row access of the Rast library.
+ * Implements row access using row id
+ * The get_row() method must accept a Row object as argument that will
+ be used for value storage, so no new buffer will be allocated
+ * Implements sequential writing of rows
+ * Implements indexed value read only access using the [row][col]
+ operator
+ * Implements the [row] read method that returns a new Row object
+ * Writing is limited using the put_row() method which accepts a
+ Row as argument
+ * No mathematical operation like __add__ and stuff for the Raster
+ object (only for rows), since r.mapcalc is more sophisticated and
+ faster
+
+ Examples
+ --------
+
+ ::
+ >>> elev = RasterRow('elevation')
+ >>> elev.exist()
+ True
+ >>> elev.is_open()
+ False
+ >>> elev.cols
+ >>> elev.open()
+ >>> elev.is_open()
+ True
+ >>> type(elev.cols)
+ <type 'int'>
+ >>> elev.has_cats()
+ False
+ >>> elev.mode
+ 'r'
+ >>> elev.mtype
+ 'FCELL'
+ >>> elev.num_cats()
+ 0
+ >>> elev.range
+ (55.578792572021484, 156.32986450195312)
+
+ Each Raster map have an attribute call ``cats`` that allow user
+ to interact with the raster categories. ::
+
+ >>> land = RasterRow('landcover_1m')
+ >>> land.open()
+ >>> land.cats
+ []
+ >>> land.read_cats()
+ >>> land.cats
+ [('pond', 1, None),
+ ('forest', 2, None),
+ ('developed', 3, None),
+ ('bare', 4, None),
+ ('paved road', 5, None),
+ ('dirt road', 6, None),
+ ('vineyard', 7, None),
+ ('agriculture', 8, None),
+ ('wetland', 9, None),
+ ('bare ground path', 10, None),
+ ('grass', 11, None)]
+
+
+ """
+ def __init__(self, name, *args, **kargs):
+ super(RasterRow, self).__init__(name, *args, **kargs)
+
+ # mode = "r", method = "row",
+ def get_row(self, row, row_buffer=None):
+ """Private method that return the row using the read mode
+ call the `Rast_get_row` C function.
+
+ >>> elev = RasterRow('elevation')
+ >>> elev.open()
+ >>> elev[0] # doctest: +ELLIPSIS +NORMALIZE_WHITESPACE
+ Buffer([ 141.99613953, 141.27848816, 141.37904358, ..., 58.40825272,
+ 58.30711365, 58.18310547], dtype=float32)
+ >>> elev.get_row(0) # doctest: +ELLIPSIS +NORMALIZE_WHITESPACE
+ Buffer([ 141.99613953, 141.27848816, 141.37904358, ..., 58.40825272,
+ 58.30711365, 58.18310547], dtype=float32)
+
+ """
+ if row_buffer is None:
+ row_buffer = Buffer((self._cols,), self.mtype)
+ libraster.Rast_get_row(self._fd, row_buffer.p, row, self._gtype)
+ return row_buffer
+
+ def put_row(self, row):
+ """Private method to write the row sequentially.
+ """
+ libraster.Rast_put_row(self._fd, row.p, self._gtype)
+
+ def open(self, mode='r', mtype='CELL', overwrite=False):
+ """Open the raster if exist or created a new one.
+
+ Parameters
+ ------------
+
+ mode: string
+ Specify if the map will be open with read or write mode ('r', 'w')
+ type: string
+ If a new map is open, specify the type of the map(`CELL`, `FCELL`,
+ `DCELL`)
+ overwrite: Boolean
+ Use this flag to set the overwrite mode of existing raster maps
+
+
+ if the map already exist, automatically check the type and set:
+ * self.mtype
+
+ Set all the privite, attributes:
+ * self._fd;
+ * self._gtype
+ * self._rows and self._cols
+ """
+ self.mode = mode
+ self.mtype = mtype
+ self.overwrite = overwrite
+
+ # check if exist and instantiate all the private attributes
+ if self.exist():
+ if self.mode == 'r':
+ # the map exist, read mode
+ self._fd = libraster.Rast_open_old(self.name, self.mapset)
+ self._gtype = libraster.Rast_get_map_type(self._fd)
+ self.mtype = RTYPE_STR[self._gtype]
+ elif self.overwrite:
+ if self._gtype is None:
+ raise OpenError(_("Raster type not defined"))
+ self._fd = libraster.Rast_open_new(self.name, self._gtype)
+ else:
+ str_err = _("Raster map <{0}> already exists")
+ raise OpenError(str_err.format(self))
+ else:
+ # Create a new map
+ if self.mode == 'r':
+ # check if we are in read mode
+ str_err = _("The map does not exist, I can't open in 'r' mode")
+ raise OpenError(str_err)
+ self._fd = libraster.Rast_open_new(self.name, self._gtype)
+ # read rows and cols from the active region
+ self._rows = libraster.Rast_window_rows()
+ self._cols = libraster.Rast_window_cols()
+
+
+class RasterRowIO(RasterRow):
+ """Raster_row_cache_access": The same as "Raster_row_access" but uses
+ the ROWIO library for cached row access
+ """
+ def __init__(self, name, *args, **kargs):
+ self.rowio = RowIO()
+ super(RasterRowIO, self).__init__(name, *args, **kargs)
+
+ def open(self, mode='r', mtype='CELL', overwrite=False):
+ super(RasterRowIO, self).open(mode, mtype, overwrite)
+ self.rowio.open(self._fd, self.rows, self.cols, self.mtype)
+
+ def close(self):
+ if self.is_open():
+ self.rowio.release()
+ libraster.Rast_close(self._fd)
+ # update rows and cols attributes
+ self._rows = None
+ self._cols = None
+ self._fd = None
+ else:
+ warning(_("The map is already close!"))
+
+ def get_row(self, row, row_buffer=None):
+ """Private method that return the row using:
+
+ * the read mode and
+ * `rowcache` method
+
+ not implemented yet!"""
+ if row_buffer is None:
+ row_buffer = Buffer((self._cols,), self.mtype)
+ rowio_buf = librowio.Rowio_get(ctypes.byref(self.rowio.crowio), row)
+ ctypes.memmove(row_buffer.p, rowio_buf, self.rowio.row_size)
+ return row_buffer
+
+
+class RasterSegment(RasterAbstractBase):
+ """Raster_segment_access": Inherits "Raster_abstract_base" and uses the
+ segment library for cached randomly reading and writing access.
+ * Implements the [row][col] operator for read and write access using
+ segement_get() and segment_put() functions internally
+ * Implements row read and write access with the [row] operator using
+ segment_get_row() segment_put_row() internally
+ * Implements the get_row() and put_row() method using
+ segment_get_row() segment_put_row() internally
+ * Implements the flush_segment() method
+ * Implements the copying of raster maps to segments and vice verse
+ * Overwrites the open and close methods
+ * No mathematical operation like __add__ and stuff for the Raster
+ object (only for rows), since r.mapcalc is more sophisticated and
+ faster
+ """
+ def __init__(self, name, srows=64, scols=64, maxmem=100,
+ *args, **kargs):
+ self.segment = Segment(srows, scols, maxmem)
+ super(RasterSegment, self).__init__(name, *args, **kargs)
+
+ def _get_mode(self):
+ return self._mode
+
+ def _set_mode(self, mode):
+ if mode.lower() not in ('r', 'w', 'rw'):
+ str_err = _("Mode type: {0} not supported ('r', 'w','rw')")
+ raise ValueError(str_err.format(mode))
+ self._mode = mode
+
+ mode = property(fget=_get_mode, fset=_set_mode)
+
+ def __setitem__(self, key, row):
+ """Return the row of Raster object, slice allowed."""
+ if isinstance(key, slice):
+ #Get the start, stop, and step from the slice
+ return [self.put_row(ii, row)
+ for ii in xrange(*key.indices(len(self)))]
+ elif isinstance(key, tuple):
+ x, y = key
+ return self.put(x, y, row)
+ elif isinstance(key, int):
+ if key < 0: # Handle negative indices
+ key += self._rows
+ if key >= self._rows:
+ raise IndexError(_("Index out of range: %r.") % key)
+ return self.put_row(key, row)
+ else:
+ raise TypeError("Invalid argument type.")
+
+ def map2segment(self):
+ """Transform an existing map to segment file.
+ """
+ if self.is_open():
+ row_buffer = Buffer((self._cols), self.mtype)
+ for row in xrange(self._rows):
+ libraster.Rast_get_row(
+ self._fd, row_buffer.p, row, self._gtype)
+ libseg.segment_put_row(ctypes.byref(self.segment.cseg),
+ row_buffer.p, row)
+
+ def segment2map(self):
+ """Transform the segment file to a map.
+ """
+ if self.is_open():
+ row_buffer = Buffer((self._cols), self.mtype)
+ for row in xrange(self._rows):
+ libseg.segment_get_row(ctypes.byref(self.segment.cseg),
+ row_buffer.p, row)
+ libraster.Rast_put_row(self._fd, row_buffer.p, self._gtype)
+
+ def get_row(self, row, row_buffer=None):
+ """Return the row using the `segment.get_row` method
+
+ Parameters
+ ------------
+
+ row: integer
+ Specify the row number;
+ row_buffer: Buffer object, optional
+ Specify the Buffer object that will be instantiate.
+ """
+ if row_buffer is None:
+ row_buffer = Buffer((self._cols), self.mtype)
+ libseg.segment_get_row(
+ ctypes.byref(self.segment.cseg), row_buffer.p, row)
+ return row_buffer
+
+ def put_row(self, row, row_buffer):
+ """Write the row using the `segment.put_row` method
+
+ Parameters
+ ------------
+
+ row: integer
+ Specify the row number;
+ row_buffer: Buffer object
+ Specify the Buffer object that will be write to the map.
+ """
+ libseg.segment_put_row(ctypes.byref(self.segment.cseg),
+ row_buffer.p, row)
+
+ def get(self, row, col):
+ """Return the map value using the `segment.get` method
+
+ Parameters
+ ------------
+
+ row: integer
+ Specify the row number;
+ col: integer
+ Specify the column number.
+ """
+ libseg.segment_get(ctypes.byref(self.segment.cseg),
+ ctypes.byref(self.segment.val), row, col)
+ return self.segment.val.value
+
+ def put(self, row, col, val):
+ """Write the value to the map using the `segment.put` method
+
+ Parameters
+ ------------
+
+ row: integer
+ Specify the row number;
+ col: integer
+ Specify the column number.
+ val: value
+ Specify the value that will be write to the map cell.
+ """
+ self.segment.val.value = val
+ libseg.segment_put(ctypes.byref(self.segment.cseg),
+ ctypes.byref(self.segment.val), row, col)
+
+ def open(self, mode='r', mtype='DCELL', overwrite=False):
+ """Open the map, if the map already exist: determine the map type
+ and copy the map to the segment files;
+ else, open a new segment map.
+
+ Parameters
+ ------------
+
+ mode: string, optional
+ Specify if the map will be open with read, write or read/write
+ mode ('r', 'w', 'rw')
+ mtype: string, optional
+ Specify the map type, valid only for new maps: CELL, FCELL, DCELL;
+ overwrite: Boolean, optional
+ Use this flag to set the overwrite mode of existing raster maps
+ """
+ # read rows and cols from the active region
+ self._rows = libraster.Rast_window_rows()
+ self._cols = libraster.Rast_window_cols()
+
+ self.overwrite = overwrite
+ self.mode = mode
+ self.mtype = mtype
+
+ if self.exist():
+ if ((self.mode == "w" or self.mode == "rw") and
+ self.overwrite is False):
+ str_err = _("Raster map <{0}> already exists. Use overwrite.")
+ fatal(str_err.format(self))
+
+ # We copy the raster map content into the segments
+ if self.mode == "rw" or self.mode == "r":
+ self._fd = libraster.Rast_open_old(self.name, self.mapset)
+ self._gtype = libraster.Rast_get_map_type(self._fd)
+ self.mtype = RTYPE_STR[self._gtype]
+ # initialize the segment, I need to determine the mtype of the
+ # map
+ # before to open the segment
+ self.segment.open(self)
+ self.map2segment()
+ self.segment.flush()
+
+ if self.mode == "rw":
+ warning(_(WARN_OVERWRITE.format(self)))
+ # Close the file descriptor and open it as new again
+ libraster.Rast_close(self._fd)
+ self._fd = libraster.Rast_open_new(
+ self.name, self._gtype)
+ # Here we simply overwrite the existing map without content copying
+ elif self.mode == "w":
+ #warning(_(WARN_OVERWRITE.format(self)))
+ self._gtype = RTYPE[self.mtype]['grass type']
+ self.segment.open(self)
+ self._fd = libraster.Rast_open_new(self.name, self._gtype)
+ else:
+ if self.mode == "r":
+ str_err = _("Raster map <{0}> does not exists")
+ raise OpenError(str_err.format(self.name))
+
+ self._gtype = RTYPE[self.mtype]['grass type']
+ self.segment.open(self)
+ self._fd = libraster.Rast_open_new(self.name, self._gtype)
+
+ def close(self, rm_temp_files=True):
+ """Close the map, copy the segment files to the map.
+
+ Parameters
+ ------------
+
+ rm_temp_files: bool
+ If True all the segments file will be removed.
+ """
+ if self.is_open():
+ if self.mode == "w" or self.mode == "rw":
+ self.segment.flush()
+ self.segment2map()
+ if rm_temp_files:
+ self.segment.close()
+ else:
+ self.segment.release()
+ libraster.Rast_close(self._fd)
+ # update rows and cols attributes
+ self._rows = None
+ self._cols = None
+ self._fd = None
+ else:
+ warning(_("The map is already close!"))
+
+
+FLAGS = {1: {'b': 'i', 'i': 'i', 'u': 'i'},
+ 2: {'b': 'i', 'i': 'i', 'u': 'i'},
+ 4: {'f': 'f', 'i': 'i', 'b': 'i', 'u': 'i'},
+ 8: {'f': 'd'}, }
+
+
+class RasterNumpy(np.memmap, RasterAbstractBase):
+ """Raster_cached_narray": Inherits "Raster_abstract_base" and
+ "numpy.memmap". Its purpose is to allow numpy narray like access to
+ raster maps without loading the map into the main memory.
+ * Behaves like a numpy array and supports all kind of mathematical
+ operations: __add__, ...
+ * Overrides the open and close methods
+ * Be aware of the 2Gig file size limit
+
+ >>> import pygrass
+ >>> elev = pygrass.raster.RasterNumpy('elevation')
+ >>> elev.open()
+ >>> elev[:5, :3]
+ RasterNumpy([[ 141.99613953, 141.27848816, 141.37904358],
+ [ 142.90461731, 142.39450073, 142.68611145],
+ [ 143.81854248, 143.54707336, 143.83972168],
+ [ 144.56524658, 144.58493042, 144.86477661],
+ [ 144.99488831, 145.22894287, 145.57142639]], dtype=float32)
+ >>> el = elev < 144
+ >>> el[:5, :3]
+ RasterNumpy([[ True, True, True],
+ [ True, True, True],
+ [ True, True, True],
+ [False, False, False],
+ [False, False, False]], dtype=bool)
+ >>> el._write()
+ 0
+
+ """
+ def __new__(cls, name, mapset="", mtype='CELL', mode='r+',
+ overwrite=False):
+ reg = Region()
+ shape = (reg.rows, reg.cols)
+ mapset = libgis.G_find_raster(name, mapset)
+ gtype = None
+ if mapset:
+ # map exist, set the map type
+ gtype = libraster.Rast_map_type(name, mapset)
+ mtype = RTYPE_STR[gtype]
+ filename = grasscore.tempfile()
+ obj = np.memmap.__new__(cls, filename=filename,
+ dtype=RTYPE[mtype]['numpy'],
+ mode=mode,
+ shape=shape)
+ obj.mtype = mtype.upper()
+ obj.gtype = gtype if gtype else RTYPE[mtype]['grass type']
+ obj._rows = reg.rows
+ obj._cols = reg.cols
+ obj.filename = filename
+ obj._name = name
+ obj.mapset = mapset
+ obj.reg = reg
+ obj.overwrite = overwrite
+ return obj
+
+ def __array_finalize__(self, obj):
+ if hasattr(obj, '_mmap'):
+ self._mmap = obj._mmap
+ self.filename = grasscore.tempfile()
+ self.offset = obj.offset
+ self.mode = obj.mode
+ self._rows = obj._rows
+ self._cols = obj._cols
+ self._name = None
+ self.mapset = ''
+ self.reg = obj.reg
+ self.overwrite = obj.overwrite
+ self.mtype = obj.mtype
+ self._fd = obj._fd
+ else:
+ self._mmap = None
+
+ def _get_mode(self):
+ return self._mode
+
+ def _set_mode(self, mode):
+ if mode.lower() not in ('r', 'w+', 'r+', 'c'):
+ raise ValueError(_("Mode type: {0} not supported.").format(mode))
+ self._mode = mode
+
+ mode = property(fget=_get_mode, fset=_set_mode)
+
+ def __array_wrap__(self, out_arr, context=None):
+ """See:
+ http://docs.scipy.org/doc/numpy/user/
+ basics.subclassing.html#array-wrap-for-ufuncs"""
+ if out_arr.dtype.kind in 'bui':
+ # there is not support for boolean maps, so convert into integer
+ out_arr = out_arr.astype(np.int32)
+ out_arr.mtype = 'CELL'
+ #out_arr.p = out_arr.ctypes.data_as(out_arr.pointer_type)
+ return np.ndarray.__array_wrap__(self, out_arr, context)
+
+ def __init__(self, name, *args, **kargs):
+ ## Private attribute `_fd` that return the file descriptor of the map
+ #self._fd = None
+ rows, cols = self.rows, self.cols
+ RasterAbstractBase.__init__(self, name)
+ self._rows, self._cols = rows, cols
+
+ def __unicode__(self):
+ return RasterAbstractBase.__unicode__(self)
+
+ def __str__(self):
+ return self.__unicode__()
+
+ def _get_flags(self, size, kind):
+ if size in FLAGS:
+ if kind in FLAGS[size]:
+ return size, FLAGS[size][kind]
+ else:
+ raise ValueError(_('Invalid type {0}'.forma(kind)))
+ else:
+ raise ValueError(_('Invalid size {0}'.format(size)))
+
+ def _read(self):
+ """!Read raster map into array
+
+ @return 0 on success
+ @return non-zero code on failure
+ """
+ self.null = None
+
+ size, kind = self._get_flags(self.dtype.itemsize, self.dtype.kind)
+ kind = 'f' if kind == 'd' else kind
+ ret = grasscore.run_command('r.out.bin', flags=kind,
+ input=self._name, output=self.filename,
+ bytes=size, null=self.null,
+ quiet=True)
+ return ret
+
+ def _write(self):
+ """
+ r.in.bin input=/home/pietro/docdat/phd/thesis/gis/north_carolina/user1/.tmp/eraclito/14325.0 output=new title='' bytes=1,anull='' --verbose --overwrite north=228500.0 south=215000.0 east=645000.0 west=630000.0 rows=1350 cols=1500
+
+ """
+ self.tofile(self.filename)
+ size, kind = self._get_flags(self.dtype.itemsize, self.dtype.kind)
+ #print size, kind
+ if kind == 'i':
+ kind = None
+ size = 4
+ size = None if kind == 'f' else size
+
+ # To be set in the future
+ self.title = None
+ self.null = None
+
+ #import pdb; pdb.set_trace()
+ if self.mode in ('w+', 'r+'):
+ if not self._name:
+ import os
+ self._name = "doctest_%i" % os.getpid()
+ ret = grasscore.run_command('r.in.bin', flags=kind,
+ input=self.filename, output=self._name,
+ title=self.title, bytes=size,
+ anull=self.null,
+ overwrite=self.overwrite,
+ verbose=True,
+ north=self.reg.north,
+ south=self.reg.south,
+ east=self.reg.east,
+ west=self.reg.west,
+ rows=self.reg.rows,
+ cols=self.reg.cols)
+ return ret
+
+ def open(self, mtype='', null=None, overwrite=None):
+ """Open the map, if the map already exist: determine the map type
+ and copy the map to the segment files;
+ else, open a new segment map.
+
+ Parameters
+ ------------
+
+ mtype: string, optional
+ Specify the map type, valid only for new maps: CELL, FCELL, DCELL;
+ """
+ if overwrite is not None:
+ self.overwrite = overwrite
+ self.null = null
+ # rows and cols already set in __new__
+ if self.exist():
+ self._read()
+ else:
+ if mtype:
+ self.mtype = mtype
+ self._gtype = RTYPE[self.mtype]['grass type']
+ # set _fd, because this attribute is used to check
+ # if the map is open or not
+ self._fd = 1
+
+ def close(self):
+ self._write()
+ np.memmap._close(self)
+ grasscore.try_remove(self.filename)
+ self._fd = None
+
+
+def random_map_only_columns(mapname, mtype, overwrite=True, factor=100):
+ region = Region()
+ random_map = RasterRow(mapname)
+ row_buf = Buffer((region.cols, ), mtype,
+ buffer=(np.random.random(region.cols,) * factor).data)
+ random_map.open('w', mtype, overwrite)
+ for _ in xrange(region.rows):
+ random_map.put_row(row_buf)
+ random_map.close()
+ return random_map
+
+
+def random_map(mapname, mtype, overwrite=True, factor=100):
+ region = Region()
+ random_map = RasterRow(mapname)
+ random_map.open('w', mtype, overwrite)
+ for _ in xrange(region.rows):
+ row_buf = Buffer((region.cols, ), mtype,
+ buffer=(np.random.random(region.cols,) * factor).data)
+ random_map.put_row(row_buf)
+ random_map.close()
+ return random_map
+
+
+if __name__ == "__main__":
+ import doctest
+ doctest.testmod()
\ No newline at end of file
Added: grass/trunk/lib/python/pygrass/raster/abstract.py
===================================================================
--- grass/trunk/lib/python/pygrass/raster/abstract.py (rev 0)
+++ grass/trunk/lib/python/pygrass/raster/abstract.py 2012-10-10 12:24:32 UTC (rev 53350)
@@ -0,0 +1,344 @@
+# -*- coding: utf-8 -*-
+"""
+Created on Fri Aug 17 16:05:25 2012
+
+ at author: pietro
+"""
+
+
+import ctypes
+
+#
+# import GRASS modules
+#
+from grass.script import fatal, warning, gisenv
+from grass.script import core as grasscore
+#from grass.script import core
+#import grass.lib as grasslib
+import grass.lib.gis as libgis
+import grass.lib.raster as libraster
+
+#
+# import pygrass modules
+#
+import pygrass.env as env
+from pygrass.region import Region
+
+#
+# import raster classes
+#
+from raster_type import TYPE as RTYPE
+from category import Category
+
+
+## Define global variables to not exceed the 80 columns
+WARN_OVERWRITE = "Raster map <{0}> already exists and will be overwritten"
+INDXOUTRANGE = "The index (%d) is out of range, have you open the map?."
+
+
+def clean_map_name(name):
+ name.strip()
+ for char in ' @#^?°,;%&/':
+ name = name.replace(char, '')
+ return name
+
+
+class RasterAbstractBase(object):
+ """Raster_abstract_base: The base class from which all sub-classes
+ inherit. It does not implement any row or map access methods:
+ * Implements raster metadata information access (Type, ...)
+ * Implements an open method that will be overwritten by the sub-classes
+ * Implements the close method that might be overwritten by sub-classes
+ (should work for simple row access)
+ * Implements get and set region methods
+ * Implements color, history and category handling
+ * Renaming, deletion, ...
+ """
+ def __init__(self, name, mapset=""):
+ """The constructor need at least the name of the map
+ *optional* field is the `mapset`. ::
+
+ >>> land = RasterAbstractBase('landcover_1m')
+ >>> land.name
+ 'landcover_1m'
+ >>> land.mapset
+ ''
+ >>> land.exist()
+ True
+ >>> land.mapset
+ 'PERMANENT'
+
+ ..
+ """
+ self.mapset = mapset
+ #self.region = Region()
+ self.cats = Category()
+
+ self._name = name
+ ## Private attribute `_fd` that return the file descriptor of the map
+ self._fd = None
+ ## Private attribute `_rows` that return the number of rows
+ # in active window, When the class is instanced is empty and it is set
+ # when you open the file, using Rast_window_rows()
+ self._rows = None
+ ## Private attribute `_cols` that return the number of rows
+ # in active window, When the class is instanced is empty and it is set
+ # when you open the file, using Rast_window_cols()
+ self._cols = None
+
+ def _get_mtype(self):
+ return self._mtype
+
+ def _set_mtype(self, mtype):
+ if mtype.upper() not in ('CELL', 'FCELL', 'DCELL'):
+ #fatal(_("Raser type: {0} not supported".format(mtype) ) )
+ str_err = "Raster type: {0} not supported ('CELL','FCELL','DCELL')"
+ raise ValueError(_(str_err).format(mtype))
+ self._mtype = mtype
+ self._gtype = RTYPE[self.mtype]['grass type']
+
+ mtype = property(fget=_get_mtype, fset=_set_mtype)
+
+ def _get_mode(self):
+ return self._mode
+
+ def _set_mode(self, mode):
+ if mode.upper() not in ('R', 'W'):
+ str_err = _("Mode type: {0} not supported ('r', 'w')")
+ raise ValueError(str_err.format(mode))
+ self._mode = mode
+
+ mode = property(fget=_get_mode, fset=_set_mode)
+
+ def _get_overwrite(self):
+ return self._overwrite
+
+ def _set_overwrite(self, overwrite):
+ if overwrite not in (True, False):
+ str_err = _("Overwrite type: {0} not supported (True/False)")
+ raise ValueError(str_err.format(overwrite))
+ self._overwrite = overwrite
+
+ overwrite = property(fget=_get_overwrite, fset=_set_overwrite)
+
+ def _get_name(self):
+ """Private method to return the Raster name"""
+ return self._name
+
+ def _set_name(self, newname):
+ """Private method to change the Raster name"""
+ #import pdb; pdb.set_trace()
+ cleanname = clean_map_name(newname)
+ if self.exist():
+ self.rename(cleanname)
+ self._name = cleanname
+
+ name = property(fget=_get_name, fset=_set_name)
+
+ def _get_rows(self):
+ """Private method to return the Raster name"""
+ return self._rows
+
+ def _set_unchangeable(self, new):
+ """Private method to change the Raster name"""
+ warning(_("Unchangeable attribute"))
+
+ rows = property(fget=_get_rows, fset=_set_unchangeable)
+
+ def _get_cols(self):
+ """Private method to return the Raster name"""
+ return self._cols
+
+ cols = property(fget=_get_cols, fset=_set_unchangeable)
+
+ def _get_range(self):
+ if self.mtype == 'CELL':
+ maprange = libraster.Range()
+ libraster.Rast_read_range(self.name, self.mapset,
+ ctypes.byref(maprange))
+ self._min = libgis.CELL()
+ self._max = libgis.CELL()
+ else:
+ maprange = libraster.FPRange()
+ libraster.Rast_read_fp_range(self.name, self.mapset,
+ ctypes.byref(maprange))
+ self._min = libgis.DCELL()
+ self._max = libgis.DCELL()
+ libraster.Rast_get_fp_range_min_max(ctypes.byref(maprange),
+ ctypes.byref(self._min),
+ ctypes.byref(self._max))
+ return self._min.value, self._max.value
+
+ range = property(fget=_get_range, fset=_set_unchangeable)
+
+ def _get_cats_title(self):
+ return self.cats.title
+
+ def _set_cats_title(self, newtitle):
+ self.cats.title = newtitle
+
+ cats_title = property(fget=_get_cats_title, fset=_set_cats_title)
+
+ def __unicode__(self):
+ return self.name_mapset()
+
+ def __str__(self):
+ """Return the string of the object"""
+ return self.__unicode__()
+
+ def __len__(self):
+ return self._rows
+
+ def __getitem__(self, key):
+ """Return the row of Raster object, slice allowed."""
+ if isinstance(key, slice):
+ #import pdb; pdb.set_trace()
+ #Get the start, stop, and step from the slice
+ return (self.get_row(ii) for ii in xrange(*key.indices(len(self))))
+ elif isinstance(key, tuple):
+ x, y = key
+ return self.get(x, y)
+ elif isinstance(key, int):
+ if key < 0: # Handle negative indices
+ key += self._rows
+ if key >= self._rows:
+ fatal(INDXOUTRANGE.format(key))
+ raise IndexError
+ return self.get_row(key)
+ else:
+ fatal("Invalid argument type.")
+
+ def __iter__(self):
+ """Return a constructor of the class"""
+ return (self.__getitem__(irow) for irow in xrange(self._rows))
+
+ def exist(self):
+ """Return True if the map already exist, and
+ set the mapset if were not set.
+
+ call the C function `G_find_raster`."""
+ if self.name:
+ self.mapset = env.get_mapset_raster(self.name, self.mapset)
+ else:
+ return False
+ if self.mapset:
+ return True
+ else:
+ return False
+
+ def is_open(self):
+ """Return True if the map is open False otherwise"""
+ return True if self._fd is not None and self._fd >= 0 else False
+
+ def close(self):
+ """Close the map"""
+ if self.is_open():
+ libraster.Rast_close(self._fd)
+ # update rows and cols attributes
+ self._rows = None
+ self._cols = None
+ self._fd = None
+ else:
+ warning(_("The map is already close!"))
+
+ def remove(self):
+ """Remove the map"""
+ if self.is_open():
+ self.close()
+ grasscore.run_command('g.remove', rast=self.name)
+
+ def name_mapset(self, name=None, mapset=None):
+ if name is None:
+ name = self.name
+ if mapset is None:
+ self.exist()
+ mapset = self.mapset
+
+ gis_env = gisenv()
+
+ if mapset and mapset != gis_env['MAPSET']:
+ return "{name}@{mapset}".format(name=name, mapset=mapset)
+ else:
+ return name
+
+ def rename(self, newname):
+ """Rename the map"""
+ if self.exist():
+ env.rename(self.name, newname, 'rast')
+ self._name = newname
+
+ def set_from_rast(self, rastname='', mapset=''):
+ """Set the region that will use from a map, if rastername and mapset
+ is not specify, use itself.
+
+ call C function `Rast_get_cellhd`"""
+ if self.is_open():
+ fatal("You cannot change the region if map is open")
+ raise
+ region = Region()
+ if rastname == '':
+ rastname = self.name
+ if mapset == '':
+ mapset = self.mapset
+
+ libraster.Rast_get_cellhd(rastname, mapset,
+ ctypes.byref(region._region))
+ # update rows and cols attributes
+ self._rows = libraster.Rast_window_rows()
+ self._cols = libraster.Rast_window_cols()
+
+ def has_cats(self):
+ """Return True if the raster map has categories"""
+ if self.exist():
+ self.open()
+ self.cats.read(self)
+ self.close()
+ if len(self.cats) != 0:
+ return True
+ return False
+
+ def num_cats(self):
+ """Return the number of categories"""
+ return len(self.cats)
+
+ def copy_cats(self, raster):
+ """Copy categories from another raster map object"""
+ self.cats.copy(raster.cats)
+
+ def sort_cats(self):
+ """Sort categories order by range"""
+ self.cats.sort()
+
+ def read_cats(self):
+ """Read category from the raster map file"""
+ self.cats.read(self)
+
+ def write_cats(self):
+ """Write category to the raster map file"""
+ self.cats.write(self)
+
+ def read_cats_rules(self, filename, sep=':'):
+ """Read category from the raster map file"""
+ self.cats.read_rules(filename, sep)
+
+ def write_cats_rules(self, filename, sep=':'):
+ """Write category to the raster map file"""
+ self.cats.write_rules(filename, sep)
+
+ def get_cats(self):
+ """Return a category object"""
+ cat = Category()
+ cat.read(self)
+ return cat
+
+ def set_cats(self, category):
+ """The internal categories are copied from this object."""
+ self.cats.copy(category)
+
+ def get_cat(self, label):
+ """Return a category given an index or a label"""
+ return self.cats[label]
+
+ def set_cat(self, label, min_cat, max_cat=None, index=None):
+ """Set or update a category"""
+ self.cats.set_cat(index, (label, min_cat, max_cat))
\ No newline at end of file
Added: grass/trunk/lib/python/pygrass/raster/buffer.py
===================================================================
--- grass/trunk/lib/python/pygrass/raster/buffer.py (rev 0)
+++ grass/trunk/lib/python/pygrass/raster/buffer.py 2012-10-10 12:24:32 UTC (rev 53350)
@@ -0,0 +1,42 @@
+# -*- coding: utf-8 -*-
+"""
+Created on Fri Jun 8 18:46:34 2012
+
+ at author: pietro
+"""
+from raster_type import TYPE as RTYPE
+import ctypes
+import numpy as np
+
+
+class Buffer(np.ndarray):
+ """shape, mtype='FCELL', buffer=None, offset=0,
+ strides=None, order=None
+ """
+
+ def __new__(cls, shape, mtype='FCELL', buffer=None, offset=0,
+ strides=None, order=None):
+ #import pdb; pdb.set_trace()
+ obj = np.ndarray.__new__(cls, shape, RTYPE[mtype]['numpy'],
+ buffer, offset, strides, order)
+ obj.pointer_type = ctypes.POINTER(RTYPE[mtype]['ctypes'])
+ obj.p = obj.ctypes.data_as(obj.pointer_type)
+ obj.mtype = mtype
+ return obj
+
+ def __array_finalize__(self, obj):
+ if obj is None:
+ return
+ self.mtype = getattr(obj, 'mtype', None)
+ self.pointer_type = getattr(obj, 'pointer_type', None)
+ self.p = getattr(obj, 'p', None)
+
+ def __array_wrap__(self, out_arr, context=None):
+ """See:
+ http://docs.scipy.org/doc/numpy/user/
+ basics.subclassing.html#array-wrap-for-ufuncs"""
+ if out_arr.dtype == np.bool:
+ # there is not support for boolean maps, so convert into integer
+ out_arr = out_arr.astype(np.int32)
+ out_arr.p = out_arr.ctypes.data_as(out_arr.pointer_type)
+ return np.ndarray.__array_wrap__(self, out_arr, context)
\ No newline at end of file
Added: grass/trunk/lib/python/pygrass/raster/category.py
===================================================================
--- grass/trunk/lib/python/pygrass/raster/category.py (rev 0)
+++ grass/trunk/lib/python/pygrass/raster/category.py 2012-10-10 12:24:32 UTC (rev 53350)
@@ -0,0 +1,348 @@
+# -*- coding: utf-8 -*-
+"""
+Created on Thu Jun 28 17:44:14 2012
+
+ at author: pietro
+"""
+import ctypes
+from operator import itemgetter
+
+import grass.lib.raster as libraster
+
+from pygrass.errors import GrassError
+
+from raster_type import TYPE as RTYPE
+
+
+class Category(list):
+ """
+ I would like to add the following functions:
+
+ Getting the umber of cats:
+ Rast_number_of_cats() <- Important for ith access
+
+ Getting and setting the title:
+ Rast_get_cats_title()
+ Rast_set_cats_title()
+
+ Do not use these functions for category access:
+ Rast_get_cat()
+ and the specialized types for CELL, FCELL and DCELL.
+ Since these functions are working on hidden static buffer.
+
+ Use the ith-get methods:
+ Rast_get_ith_c_cat()
+ Rast_get_ith_f_cat()
+ Rast_get_ith_d_cat()
+
+ This can be implemented using an iterator too. So that the category object
+ provides the [] access operator to the categories, returning a tuple
+ (label, min, max).
+ Using this, the category object must be aware of its raster map type.
+
+ Set categories using:
+ Rast_set_c_cat()
+ Rast_set_f_cat()
+ Rast_set_d_cat()
+
+ Misc:
+ Rast_sort_cats()
+ Rast_copy_cats() <- This should be wrapped so that categories from an
+ existing Python category class are copied.
+
+
+ >>> import grass.lib.raster as libraster
+ >>> import ctypes
+ >>> import pygrass
+ >>> land = pygrass.raster.RasterRow('landcover_1m')
+ >>> cats = pygrass.raster.Category()
+ >>> cats.read(land) # or with cats.read(land.name, land.mapset, land.mtype)
+ >>> cats.labels()
+ ['pond', 'forest', 'developed', 'bare', 'paved road', 'dirt road',
+ 'vineyard', 'agriculture', 'wetland', 'bare ground path', 'grass']
+ >>> min_cat = ctypes.c_void_p()
+ >>> max_cat = ctypes.c_void_p()
+ >>> libraster.Rast_get_ith_c_cat(ctypes.byref(cats.cats), 0,
+ ... min_cat, max_cat)
+ """
+ def __init__(self, mtype=None, *args, **kargs):
+ self._cats = libraster.Categories()
+ libraster.Rast_init_cats("", ctypes.byref(self._cats))
+ self._mtype = mtype
+ self._gtype = None if mtype is None else RTYPE[mtype]['grass type']
+ super(Category, self).__init__(*args, **kargs)
+
+ def _get_mtype(self):
+ return self._mtype
+
+ def _set_mtype(self, mtype):
+ if mtype.upper() not in ('CELL', 'FCELL', 'DCELL'):
+ #fatal(_("Raser type: {0} not supported".format(mtype) ) )
+ raise ValueError(_("Raser type: {0} not supported".format(mtype)))
+ self._mtype = mtype
+ self._gtype = RTYPE[self.mtype]['grass type']
+
+ mtype = property(fget=_get_mtype, fset=_set_mtype)
+
+ def _get_title(self):
+ return libraster.Rast_get_cats_title(ctypes.byref(self._cats))
+
+ def _set_title(self, newtitle):
+ return libraster.Rast_set_cats_title(newtitle,
+ ctypes.byref(self._cats))
+
+ title = property(fget=_get_title, fset=_set_title)
+
+ def __str__(self):
+ return self.__repr__()
+
+ def __list__(self):
+ cats = []
+ for cat in self.__iter__():
+ cats.append(cat)
+ return cats
+
+ def __dict__(self):
+ diz = dict()
+ for cat in self.__iter__():
+ label, min_cat, max_cat = cat
+ diz[(min_cat, max_cat)] = label
+ return diz
+
+ def __repr__(self):
+ cats = []
+ for cat in self.__iter__():
+ cats.append(repr(cat))
+ return "[{0}]".format(',\n '.join(cats))
+
+ def _chk_index(self, index):
+ if type(index) == str:
+ try:
+ index = self.labels().index(index)
+ except ValueError:
+ raise KeyError(index)
+ return index
+
+ def _chk_value(self, value):
+ if type(value) == tuple:
+ length = len(value)
+ if length == 2:
+ label, min_cat = value
+ value = (label, min_cat, None)
+ elif length < 2 or length > 3:
+ raise TypeError('Tuple with a length that is not supported.')
+ else:
+ raise TypeError('Only Tuple are supported.')
+ return value
+
+ def __getitem__(self, index):
+ return super(Category, self).__getitem__(self._chk_index(index))
+
+ def __setitem__(self, index, value):
+ return super(Category, self).__setitem__(self._chk_index(index),
+ self._chk_value(value))
+
+ def _get_c_cat(self, index):
+ """Returns i-th description and i-th data range from the list of
+ category descriptions with corresponding data ranges. end points of
+ data interval.
+
+ Rast_get_ith_cat(const struct Categories * pcats,
+ int i,
+ void * rast1,
+ void * rast2,
+ RASTER_MAP_TYPE data_type
+ )
+ """
+ min_cat = ctypes.pointer(RTYPE[self.mtype]['grass def']())
+ max_cat = ctypes.pointer(RTYPE[self.mtype]['grass def']())
+ lab = libraster.Rast_get_ith_cat(ctypes.byref(self._cats),
+ index,
+ ctypes.cast(min_cat, ctypes.c_void_p),
+ ctypes.cast(max_cat, ctypes.c_void_p),
+ self._gtype)
+ # Manage C function Errors
+ if lab == '':
+ raise GrassError(_("Error executing: Rast_get_ith_cat"))
+ if max_cat.contents.value == min_cat.contents.value:
+ max_cat = None
+ else:
+ max_cat = max_cat.contents.value
+ return lab, min_cat.contents.value, max_cat
+
+ def _set_c_cat(self, label, min_cat, max_cat=None):
+ """Adds the label for range min through max in category structure cats.
+
+ int Rast_set_cat(const void * rast1,
+ const void * rast2,
+ const char * label,
+ struct Categories * pcats,
+ RASTER_MAP_TYPE data_type
+ )
+ """
+ max_cat = min_cat if max_cat is None else max_cat
+ min_cat = ctypes.pointer(RTYPE[self.mtype]['grass def'](min_cat))
+ max_cat = ctypes.pointer(RTYPE[self.mtype]['grass def'](max_cat))
+ err = libraster.Rast_set_cat(ctypes.cast(min_cat, ctypes.c_void_p),
+ ctypes.cast(max_cat, ctypes.c_void_p),
+ label,
+ ctypes.byref(self._cats), self._gtype)
+ # Manage C function Errors
+ if err == 1:
+ return None
+ elif err == 0:
+ raise GrassError(_("Null value detected"))
+ elif err == -1:
+ raise GrassError(_("Error executing: Rast_set_cat"))
+
+ def __del__(self):
+ libraster.Rast_free_cats(ctypes.byref(self._cats))
+
+ def get_cat(self, index):
+ return self.__getitem__(index)
+
+ def set_cat(self, index, value):
+ if index is None:
+ self.append(value)
+ elif index < self.__len__():
+ self.__setitem__(index, value)
+ else:
+ raise TypeError("Index outside range.")
+
+ def reset(self):
+ for i in xrange(len(self) - 1, -1, -1):
+ del(self[i])
+ libraster.Rast_init_cats("", ctypes.byref(self._cats))
+
+ def _read_cats(self):
+ """Copy from the C struct to the list"""
+ for i in xrange(self._cats.ncats):
+ self.append(self._get_c_cat(i))
+
+ def _write_cats(self):
+ """Copy from the list data to the C struct"""
+ # reset only the C struct
+ libraster.Rast_init_cats("", ctypes.byref(self._cats))
+ # write to the c struct
+ for cat in self.__iter__():
+ label, min_cat, max_cat = cat
+ if max_cat is None:
+ max_cat = min_cat
+ self._set_c_cat(label, min_cat, max_cat)
+
+ def read(self, rast, mapset=None, mtype=None):
+ """Read categories from a raster map
+
+ The category file for raster map name in mapset is read into the
+ cats structure. If there is an error reading the category file,
+ a diagnostic message is printed.
+
+ int Rast_read_cats(const char * name,
+ const char * mapset,
+ struct Categories * pcats
+ )
+ """
+ if type(rast) == str:
+ mapname = rast
+ if mapset is None or mtype is None:
+ raise TypeError(_('Mapset and maptype must be specify'))
+ else:
+ mapname = rast.name
+ mapset = rast.mapset
+ mtype = rast.mtype
+
+ self.mtype = mtype
+ self.reset()
+ err = libraster.Rast_read_cats(mapname, mapset,
+ ctypes.byref(self._cats))
+ if err == -1:
+ raise GrassError("Can not read the categories.")
+ # copy from C struct to list
+ self._read_cats()
+
+ def write(self, map):
+ """Writes the category file for the raster map name in the current
+ mapset from the cats structure.
+
+ void Rast_write_cats(const char * name,
+ struct Categories * cats
+ )
+ """
+ if type(map) == str:
+ mapname = map
+ else:
+ mapname = map.name
+ # copy from list to C struct
+ self._write_cats()
+ # write to the map
+ libraster.Rast_write_cats(mapname, ctypes.byref(self._cats))
+
+ def copy(self, category):
+ """Copy from another Category class"""
+ libraster.Rast_copy_cats(ctypes.byref(self._cats), # to
+ ctypes.byref(category._cats)) # from
+ self._read_cats()
+
+ def ncats(self):
+ return self.__len__()
+
+ def set_cats_fmt(self, fmt, m1, a1, m2, a2):
+ """Not implemented yet.
+ void Rast_set_cats_fmt()
+ """
+ #TODO: add
+ pass
+
+ def read_rules(self, filename, sep=':'):
+ """Copy categories from a rules file, default separetor is ':', the
+ columns must be: min and/or max and label. ::
+
+ 1:forest
+ 2:road
+ 3:urban
+
+ 0.:0.5:forest
+ 0.5:1.0:road
+ 1.0:1.5:urban
+
+ .."""
+ self.reset()
+ with open(filename, 'r') as f:
+ for row in f.readlines():
+ cat = row.strip().split(sep)
+ if len(cat) == 2:
+ label, min_cat = cat
+ max_cat = None
+ elif len(cat) == 3:
+ label, min_cat, max_cat = cat
+ else:
+ raise TypeError("Row lenght is greater than 3")
+ #import pdb; pdb.set_trace()
+ self.append((label, min_cat, max_cat))
+
+ def write_rules(self, filename, sep=':'):
+ """Copy categories from a rules file, default separetor is ':', the
+ columns must be: min and/or max and label. ::
+
+ 1:forest
+ 2:road
+ 3:urban
+
+ 0.:0.5:forest
+ 0.5:1.0:road
+ 1.0:1.5:urban
+
+ .."""
+ with open(filename, 'w') as f:
+ cats = []
+ for cat in self.__iter__():
+ if cat[-1] is None:
+ cat = cat[:-1]
+ cats.append(sep.join([str(i) for i in cat]))
+ f.write('\n'.join(cats))
+
+ def sort(self):
+ libraster.Rast_sort_cats(ctypes.byref(self._cats))
+
+ def labels(self):
+ return map(itemgetter(0), self)
\ No newline at end of file
Added: grass/trunk/lib/python/pygrass/raster/history.py
===================================================================
--- grass/trunk/lib/python/pygrass/raster/history.py (rev 0)
+++ grass/trunk/lib/python/pygrass/raster/history.py 2012-10-10 12:24:32 UTC (rev 53350)
@@ -0,0 +1,236 @@
+# -*- coding: utf-8 -*-
+"""
+Created on Thu Jun 28 17:44:45 2012
+
+ at author: pietro
+"""
+import ctypes
+import grass.lib.raster as libraster
+import datetime
+
+
+class History(object):
+ """
+ *Examples*
+
+ ::
+
+ >>> import pygrass
+ >>> hist = pygrass.raster.History()
+ >>> hist.read('aspect')
+ >>> hist.creator
+ 'helena'
+ >>> hist.src1
+ 'raster elevation file elev_ned10m'
+ >>> hist.src2
+ ''
+ >>> hist.keyword
+ 'generated by r.slope.aspect'
+ >>> hist.date
+ datetime.datetime(2006, 11, 7, 1, 11, 23)
+ >>> hist.mapset
+ 'PERMANENT'
+ >>> hist.maptype
+ 'raster'
+ >>> hist.title
+ 'asp_ned10m'
+
+ ..
+ """
+ def __init__(self):
+ self.hist = libraster.History()
+ # 'Tue Nov 7 01:11:23 2006'
+ self.date_fmt = '%a %b %d %H:%M:%S %Y'
+
+ def __del__(self):
+ """Rast_free_history"""
+ pass
+
+ #----------------------------------------------------------------------
+ #libraster.HIST_CREATOR
+ def _get_creator(self):
+ return libraster.Rast_get_history(ctypes.byref(self.hist),
+ libraster.HIST_CREATOR)
+
+ def _set_creator(self, creator):
+ return libraster.Rast_set_history(ctypes.byref(self.hist),
+ libraster.HIST_CREATOR,
+ ctypes.c_char_p(creator))
+
+ creator = property(fget=_get_creator, fset=_set_creator)
+
+ #----------------------------------------------------------------------
+ #libraster.HIST_DATSRC_1
+ def _get_src1(self):
+ return libraster.Rast_get_history(ctypes.byref(self.hist),
+ libraster.HIST_DATSRC_1)
+
+ def _set_src1(self, src1):
+ return libraster.Rast_set_history(ctypes.byref(self.hist),
+ libraster.HIST_DATSRC_1,
+ ctypes.c_char_p(src1))
+
+ src1 = property(fget=_get_src1, fset=_set_src1)
+
+ #----------------------------------------------------------------------
+ #libraster.HIST_DATSRC_2
+ def _get_src2(self):
+ return libraster.Rast_get_history(ctypes.byref(self.hist),
+ libraster.HIST_DATSRC_2)
+
+ def _set_src2(self, src2):
+ return libraster.Rast_set_history(ctypes.byref(self.hist),
+ libraster.HIST_DATSRC_2,
+ ctypes.c_char_p(src2))
+
+ src2 = property(fget=_get_src2, fset=_set_src2)
+
+ #----------------------------------------------------------------------
+ #libraster.HIST_KEYWORD
+ def _get_keyword(self):
+ return libraster.Rast_get_history(ctypes.byref(self.hist),
+ libraster.HIST_KEYWRD)
+
+ def _set_keyword(self, keyword):
+ return libraster.Rast_set_history(ctypes.byref(self.hist),
+ libraster.HIST_KEYWRD,
+ ctypes.c_char_p(keyword))
+
+ keyword = property(fget=_get_keyword, fset=_set_keyword)
+
+ #----------------------------------------------------------------------
+ #libraster.HIST_MAPID
+ def _get_date(self):
+ date_str = libraster.Rast_get_history(ctypes.byref(self.hist),
+ libraster.HIST_MAPID)
+ return datetime.datetime.strptime(date_str, self.date_fmt)
+
+ def _set_date(self, datetimeobj):
+ date_str = datetimeobj.strftime(self.date_fmt)
+ return libraster.Rast_set_history(ctypes.byref(self.hist),
+ libraster.HIST_MAPID,
+ ctypes.c_char_p(date_str))
+
+ date = property(fget=_get_date, fset=_set_date)
+
+ #----------------------------------------------------------------------
+ #libraster.HIST_MAPSET
+ def _get_mapset(self):
+ return libraster.Rast_get_history(ctypes.byref(self.hist),
+ libraster.HIST_MAPSET)
+
+ def _set_mapset(self, mapset):
+ return libraster.Rast_set_history(ctypes.byref(self.hist),
+ libraster.HIST_MAPSET,
+ ctypes.c_char_p(mapset))
+
+ mapset = property(fget=_get_mapset, fset=_set_mapset)
+
+ #----------------------------------------------------------------------
+ #libraster.HIST_MAPTYPE
+ def _get_maptype(self):
+ return libraster.Rast_get_history(ctypes.byref(self.hist),
+ libraster.HIST_MAPTYPE)
+
+ def _set_maptype(self, maptype):
+ return libraster.Rast_set_history(ctypes.byref(self.hist),
+ libraster.HIST_MAPTYPE,
+ ctypes.c_char_p(maptype))
+
+ maptype = property(fget=_get_maptype, fset=_set_maptype)
+
+ #----------------------------------------------------------------------
+ #libraster.HIST_NUM_FIELDS
+ #
+ # Never used in any raster modules
+ #
+ # def _get_num_fields(self):
+ # return libraster.Rast_get_history(ctypes.byref(self.hist),
+ # libraster.HIST_NUM_FIELDS)
+ #
+ # def _set_num_fields(self, num_fields):
+ # return libraster.Rast_set_history(ctypes.byref(self.hist),
+ # libraster.HIST_NUM_FIELDS,
+ # ctypes.c_char_p(num_fields))
+ #
+ # num_fields = property(fget = _get_num_fields, fset = _set_num_fields)
+ #----------------------------------------------------------------------
+ #libraster.HIST_TITLE
+ def _get_title(self):
+ return libraster.Rast_get_history(ctypes.byref(self.hist),
+ libraster.HIST_TITLE)
+
+ def _set_title(self, title):
+ return libraster.Rast_set_history(ctypes.byref(self.hist),
+ libraster.HIST_TITLE,
+ ctypes.c_char_p(title))
+
+ title = property(fget=_get_title, fset=_set_title)
+
+ def append(self, obj):
+ """Rast_append_history"""
+ libraster.Rast_append_history(ctypes.byref(self.hist),
+ ctypes.c_char_p(str(obj)))
+
+ def appent_fmt(self, fmt, *args):
+ """Rast_append_format_history"""
+ libraster.Rast_append_format_history(ctypes.byref(self.hist),
+ ctypes.c_char_p(fmt),
+ *args)
+
+ def clear(self):
+ """Rast_clear_history"""
+ libraster.Rast_clear_history(ctypes.byref(self.hist))
+
+ def command(self):
+ """Rast_command_history"""
+ libraster.Rast_command_history(ctypes.byref(self.hist))
+
+ def format(self, field, fmt, *args):
+ """Rast_format_history"""
+ libraster.Rast_format_history(ctypes.byref(self.hist),
+ ctypes.c_int(field),
+ ctypes.c_char_p(fmt),
+ *args)
+
+ def length(self):
+ """Rast_history_length"""
+ libraster.Rast_history_length(ctypes.byref(self.hist))
+
+ def line(self, line):
+ """Rast_history_line"""
+ libraster.Rast_history_line(ctypes.byref(self.hist),
+ ctypes.c_int(line))
+
+ def read(self, name):
+ """Rast_read_history. ::
+
+ >>> import grass.lib.gis as libgis
+ >>> libgis.G_gisinit('')
+ >>> import ctypes
+ >>> import grass.lib.raster as libraster
+ >>> hist = libraster.History()
+ >>> libraster.Rast_read_history(ctypes.c_char_p('aspect'),
+ ... ctypes.c_char_p(''),
+ ... ctypes.byref(hist))
+ 0
+ >>> libraster.Rast_get_history(ctypes.byref(hist),
+ ... libraster.HIST_MAPID)
+ 'Tue Nov 7 01:11:23 2006'
+
+ ..
+ """
+ libraster.Rast_read_history(ctypes.c_char_p(name),
+ ctypes.c_char_p(''),
+ ctypes.byref(self.hist))
+
+ def write(self, name):
+ """Rast_write_history"""
+ libraster.Rast_write_history(ctypes.c_char_p(name),
+ ctypes.byref(self.hist))
+
+ def short(self, name, maptype,):
+ """Rast_short_history"""
+ libraster.Rast_short_history(ctypes.c_char_p(name),
+ ctypes.c_char_p(maptype),
+ ctypes.byref(self.hist))
\ No newline at end of file
Added: grass/trunk/lib/python/pygrass/raster/raster_type.py
===================================================================
--- grass/trunk/lib/python/pygrass/raster/raster_type.py (rev 0)
+++ grass/trunk/lib/python/pygrass/raster/raster_type.py 2012-10-10 12:24:32 UTC (rev 53350)
@@ -0,0 +1,28 @@
+# -*- coding: utf-8 -*-
+"""
+Created on Wed Jun 13 19:42:22 2012
+
+ at author: pietro
+"""
+import grass.lib.raster as libraster
+import ctypes
+import numpy as np
+
+## Private dictionary to convert RASTER_TYPE into type string.
+RTYPE_STR = {libraster.CELL_TYPE: 'CELL',
+ libraster.FCELL_TYPE: 'FCELL',
+ libraster.DCELL_TYPE: 'DCELL'}
+
+
+TYPE = {'CELL': {'grass type': libraster.CELL_TYPE,
+ 'grass def': libraster.CELL,
+ 'numpy': np.int32,
+ 'ctypes': ctypes.c_int},
+ 'FCELL': {'grass type': libraster.FCELL_TYPE,
+ 'grass def': libraster.FCELL,
+ 'numpy': np.float32,
+ 'ctypes': ctypes.c_float},
+ 'DCELL': {'grass type': libraster.DCELL_TYPE,
+ 'grass def': libraster.DCELL,
+ 'numpy': np.float64,
+ 'ctypes': ctypes.c_double}}
\ No newline at end of file
Added: grass/trunk/lib/python/pygrass/raster/rowio.py
===================================================================
--- grass/trunk/lib/python/pygrass/raster/rowio.py (rev 0)
+++ grass/trunk/lib/python/pygrass/raster/rowio.py 2012-10-10 12:24:32 UTC (rev 53350)
@@ -0,0 +1,78 @@
+# -*- coding: utf-8 -*-
+"""
+Created on Mon Jun 18 13:22:38 2012
+
+ at author: pietro
+"""
+import ctypes
+
+import grass.lib.rowio as librowio
+import grass.lib.raster as librast
+
+from pygrass.errors import GrassError
+from raster_type import TYPE as RTYPE
+
+
+CMPFUNC = ctypes.CFUNCTYPE(ctypes.c_int,
+ ctypes.c_int, ctypes.c_void_p,
+ ctypes.c_int, ctypes.c_int)
+
+
+def getmaprow_CELL(fd, buf, row, l):
+ librast.Rast_get_f_row(fd, ctypes.cast(buf, ctypes.POINTER(librast.CELL)),
+ row)
+ return 1
+
+
+def getmaprow_FCELL(fd, buf, row, l):
+ librast.Rast_get_f_row(fd, ctypes.cast(buf, ctypes.POINTER(librast.FCELL)),
+ row)
+ return 1
+
+
+def getmaprow_DCELL(fd, buf, row, l):
+ librast.Rast_get_f_row(fd, ctypes.cast(buf, ctypes.POINTER(librast.DCELL)),
+ row)
+ return 1
+
+get_row = {
+ 'CELL': CMPFUNC(getmaprow_CELL),
+ 'FCELL': CMPFUNC(getmaprow_FCELL),
+ 'DCELL': CMPFUNC(getmaprow_DCELL),
+}
+
+
+class RowIO(object):
+
+ def __init__(self):
+ self.crowio = librowio.ROWIO()
+ self.fd = None
+ self.rows = None
+ self.cols = None
+ self.mtype = None
+ self.row_size = None
+
+ def open(self, fd, rows, cols, mtype):
+ self.fd = fd
+ self.rows = rows
+ self.cols = cols
+ self.mtype = mtype
+ self.row_size = ctypes.sizeof(RTYPE[mtype]['grass def'] * cols)
+ if (librowio.Rowio_setup(ctypes.byref(self.crowio), self.fd,
+ self.rows,
+ self.row_size,
+ get_row[self.mtype],
+ get_row[self.mtype]) == -1):
+ raise GrassError('Fatal error, Rowio not setup correctly.')
+
+ def release(self):
+ librowio.Rowio_release(ctypes.byref(self.crowio))
+ self.fd = None
+ self.rows = None
+ self.cols = None
+ self.mtype = None
+
+ def get(self, row_index, buf):
+ rowio_buf = librowio.Rowio_get(ctypes.byref(self.crowio), row_index)
+ ctypes.memmove(buf.p, rowio_buf, self.row_size)
+ return buf
\ No newline at end of file
Added: grass/trunk/lib/python/pygrass/raster/segment.py
===================================================================
--- grass/trunk/lib/python/pygrass/raster/segment.py (rev 0)
+++ grass/trunk/lib/python/pygrass/raster/segment.py 2012-10-10 12:24:32 UTC (rev 53350)
@@ -0,0 +1,129 @@
+# -*- coding: utf-8 -*-
+"""
+Created on Mon Jun 11 18:02:27 2012
+
+ at author: pietro
+"""
+import ctypes
+import grass.lib.gis as libgis
+import grass.lib.raster as libraster
+import grass.lib.segment as libseg
+from raster_type import TYPE as RTYPE
+
+
+class Segment(object):
+ def __init__(self, srows=64, scols=64, maxmem=100):
+ self.srows = srows
+ self.scols = scols
+ self.maxmem = maxmem
+ self.cseg = libseg.SEGMENT()
+
+ def rows(self):
+ return libraster.Rast_window_rows()
+
+ def cols(self):
+ return libraster.Rast_window_cols()
+
+ def nseg(self):
+ rows = self.rows()
+ cols = self.cols()
+ return ((rows + self.srows - 1) / self.srows) * \
+ ((cols + self.scols - 1) / self.scols)
+
+ def segments_in_mem(self):
+ if self.maxmem > 0 and self.maxmem < 100:
+ seg_in_mem = (self.maxmem * self.nseg()) / 100
+ else:
+ seg_in_mem = 4 * (self.rows() / self.srows +
+ self.cols() / self.scols + 2)
+ if seg_in_mem == 0:
+ seg_in_mem = 1
+ return seg_in_mem
+
+ def open(self, mapobj):
+ """Open a segment it is necessary to pass a RasterSegment object.
+
+ """
+ self.val = RTYPE[mapobj.mtype]['grass def']()
+ size = ctypes.sizeof(RTYPE[mapobj.mtype]['ctypes'])
+ file_name = libgis.G_tempfile()
+ #import pdb; pdb.set_trace()
+ libseg.segment_open(ctypes.byref(self.cseg), file_name,
+ self.rows(), self.cols(),
+ self.srows, self.scols,
+ size,
+ self.nseg())
+ self.flush()
+
+ def format(self, mapobj, file_name='', fill=True):
+ """The segmentation routines require a disk file to be used for paging
+ segments in and out of memory. This routine formats the file open for
+ write on file descriptor fd for use as a segment file.
+ """
+ if file_name == '':
+ file_name = libgis.G_tempfile()
+ mapobj.temp_file = file(file_name, 'w')
+ size = ctypes.sizeof(RTYPE[mapobj.mtype]['ctypes'])
+ if fill:
+ libseg.segment_format(mapobj.temp_file.fileno(), self.rows(),
+ self.cols(), self.srows, self.scols, size)
+ else:
+ libseg.segment_format_nofill(mapobj.temp_file.fileno(),
+ self.rows(), self.cols(),
+ self.srows, self.scols, size)
+ # TODO: why should I close and then re-open it?
+ mapobj.temp_file.close()
+
+ def init(self, mapobj, file_name=''):
+ if file_name == '':
+ file_name = mapobj.temp_file.name
+ mapobj.temp_file = open(file_name, 'w')
+ libseg.segment_init(ctypes.byref(self.cseg), mapobj.temp_file.fileno(),
+ self.segments_in_mem)
+
+ def get_row(self, row_index, buf):
+ """Return the row using, the `segment` method"""
+ libseg.segment_get_row(ctypes.byref(self.cseg), buf.p, row_index)
+ return buf
+
+ def put_row(self, row_index, buf):
+ """Write the row using the `segment` method"""
+ libseg.segment_put_row(ctypes.byref(self.cseg), buf.p, row_index)
+
+ def get(self, row_index, col_index):
+ """Return the value of the map
+ """
+ libseg.segment_get(ctypes.byref(self.cseg),
+ ctypes.byref(self.val), row_index, col_index)
+ return self.val.value
+
+ def put(self, row_index, col_index):
+ """Write the value to the map
+ """
+ libseg.segment_put(ctypes.byref(self.cseg),
+ ctypes.byref(self.val), row_index, col_index)
+
+ def get_seg_number(self, row_index, col_index):
+ """Return the segment number
+ """
+ return row_index / self.srows * self.cols / self.scols + \
+ col_index / self.scols
+
+ def flush(self):
+ """Flush pending updates to disk.
+ Forces all pending updates generated by segment_put() to be written to
+ the segment file seg. Must be called after the final segment_put()
+ to force all pending updates to disk. Must also be called before the
+ first call to segment_get_row."""
+ libseg.segment_flush(ctypes.byref(self.cseg))
+
+ def close(self):
+ """Free memory allocated to segment and delete temp file. """
+ libseg.segment_close(ctypes.byref(self.cseg))
+
+ def release(self):
+ """Free memory allocated to segment.
+ Releases the allocated memory associated with the segment file seg.
+ Note: Does not close the file. Does not flush the data which may be
+ pending from previous segment_put() calls."""
+ libseg.segment_release(ctypes.byref(self.cseg))
\ No newline at end of file
Added: grass/trunk/lib/python/pygrass/region.py
===================================================================
--- grass/trunk/lib/python/pygrass/region.py (rev 0)
+++ grass/trunk/lib/python/pygrass/region.py 2012-10-10 12:24:32 UTC (rev 53350)
@@ -0,0 +1,207 @@
+# -*- coding: utf-8 -*-
+"""
+Created on Fri May 25 12:57:10 2012
+
+ at author: Pietro Zambelli
+"""
+import ctypes
+import grass.lib.gis as libgis
+import grass.script as grass
+
+from errors import GrassError
+
+
+class Region(object):
+ def __init__(self, default=False):
+ """::
+
+ >>> default = Region(default=True)
+ >>> current = Region()
+ >>> default == current
+ True
+ >>> current.cols
+ 1500
+ >>> current.ewres
+ 10.0
+ >>> current.cols = 3000
+ >>> current.ewres
+ 5.0
+ >>> current.ewres = 20.0
+ >>> current.cols
+ 750
+ >>> current.set_current()
+ >>> default == current
+ False
+ >>> current.set_default()
+ >>> default = Region(default=True)
+ >>> default == current
+ True
+ >>> default
+ Region(n=228500, s=215000, e=645000, w=630000, nsres=10, ewres=20)
+ >>> current
+ Region(n=228500, s=215000, e=645000, w=630000, nsres=10, ewres=20)
+ >>> default.ewres = 10.
+ >>> default.set_default()
+ """
+ self.c_region = ctypes.pointer(libgis.Cell_head())
+ if default:
+ self.get_default()
+ else:
+ self.get_current()
+
+ def _set_param(self, key, value):
+ grass.run_command('g.region', **{key: value})
+
+ #----------LIMITS----------
+ def _get_n(self):
+ return self.c_region.contents.north
+
+ def _set_n(self, value):
+ self.c_region.contents.north = value
+
+ north = property(fget=_get_n, fset=_set_n)
+
+ def _get_s(self):
+ return self.c_region.contents.south
+
+ def _set_s(self, value):
+ self.c_region.contents.south = value
+
+ south = property(fget=_get_s, fset=_set_s)
+
+ def _get_e(self):
+ return self.c_region.contents.east
+
+ def _set_e(self, value):
+ self.c_region.contents.east = value
+
+ east = property(fget=_get_e, fset=_set_e)
+
+ def _get_w(self):
+ return self.c_region.contents.west
+
+ def _set_w(self, value):
+ self.c_region.contents.west = value
+
+ west = property(fget=_get_w, fset=_set_w)
+
+ def _get_t(self):
+ return self.c_region.contents.top
+
+ def _set_t(self, value):
+ self.c_region.contents.top = value
+
+ top = property(fget=_get_t, fset=_set_t)
+
+ def _get_b(self):
+ return self.c_region.contents.bottom
+
+ def _set_b(self, value):
+ self.c_region.contents.bottom = value
+
+ bottom = property(fget=_get_b, fset=_set_b)
+
+ #----------RESOLUTION----------
+ def _get_rows(self):
+ return self.c_region.contents.rows
+
+ def _set_rows(self, value):
+ self.c_region.contents.rows = value
+ self.adjust(rows=True)
+
+ rows = property(fget=_get_rows, fset=_set_rows)
+
+ def _get_cols(self):
+ return self.c_region.contents.cols
+
+ def _set_cols(self, value):
+ self.c_region.contents.cols = value
+ self.adjust(cols=True)
+
+ cols = property(fget=_get_cols, fset=_set_cols)
+
+ def _get_nsres(self):
+ return self.c_region.contents.ns_res
+
+ def _set_nsres(self, value):
+ self.c_region.contents.ns_res = value
+ self.adjust()
+
+ nsres = property(fget=_get_nsres, fset=_set_nsres)
+
+ def _get_ewres(self):
+ return self.c_region.contents.ew_res
+
+ def _set_ewres(self, value):
+ self.c_region.contents.ew_res = value
+ self.adjust()
+
+ ewres = property(fget=_get_ewres, fset=_set_ewres)
+
+ def _get_tbres(self):
+ return self.c_region.contents.tb_res
+
+ def _set_tbres(self, value):
+ self.c_region.contents.tb_res = value
+ self.adjust()
+
+ tbres = property(fget=_get_tbres, fset=_set_tbres)
+
+ @property
+ def zone(self):
+ return self.c_region.contents.zone
+
+ @property
+ def proj(self):
+ return self.c_region.contents.proj
+
+ #----------MAGIC METHODS----------
+ def __repr__(self):
+ return 'Region(n=%g, s=%g, e=%g, w=%g, nsres=%g, ewres=%g)' % (
+ self.north, self.south, self.east, self.west,
+ self.nsres, self.ewres)
+
+ def __unicode__(self):
+ return grass.pipe_command("g.region", flags="p").communicate()[0]
+
+ def __str__(self):
+ return self.__unicode__()
+
+ def __eq__(self, reg):
+ attrs = ['north', 'south', 'west', 'east', 'top', 'bottom',
+ 'nsres', 'ewres', 'tbres']
+ for attr in attrs:
+ if getattr(self, attr) != getattr(reg, attr):
+ return False
+ return True
+
+
+ #----------METHODS----------
+ def zoom(self, raster_name):
+ """Shrink region until it meets non-NULL data from this raster map:"""
+ self._set_param('zoom', str(raster_name))
+
+ def align(self, raster_name):
+ """Adjust region cells to cleanly align with this raster map"""
+ self._set_param('align', str(raster_name))
+
+ def adjust(self, rows=False, cols=False):
+ """Adjust rows and cols number according with the nsres and ewres
+ resolutions. If rows or cols parameters are True, the adjust method
+ update nsres and ewres according with the rows and cols numbers.
+ """
+ libgis.G_adjust_Cell_head(self.c_region, bool(rows), bool(cols))
+
+ def get_current(self):
+ libgis.G_get_set_window(self.c_region)
+
+ def set_current(self):
+ libgis.G_set_window(self.c_region)
+
+ def get_default(self):
+ libgis.G_get_window(self.c_region)
+
+ def set_default(self):
+ self.adjust()
+ if libgis.G_put_window(self.c_region) < 0:
+ raise GrassError("Cannot change region (WIND file).")
\ No newline at end of file
Copied: grass/trunk/lib/python/pygrass/tests/Makefile (from rev 53343, grass/trunk/lib/python/Makefile)
===================================================================
--- grass/trunk/lib/python/pygrass/tests/Makefile (rev 0)
+++ grass/trunk/lib/python/pygrass/tests/Makefile 2012-10-10 12:24:32 UTC (rev 53350)
@@ -0,0 +1,32 @@
+MODULE_TOPDIR = ../../../..
+
+include $(MODULE_TOPDIR)/include/Make/Other.make
+include $(MODULE_TOPDIR)/include/Make/Python.make
+include $(MODULE_TOPDIR)/include/Make/Doxygen.make
+
+PYDIR = $(ETC)/python
+GDIR = $(PYDIR)/grass
+PGDIR = $(GDIR)/pygrass
+DSTDIR= $(PGDIR)/tests
+
+MODULES = benchmark set_mapset
+
+PYFILES := $(patsubst %,$(DSTDIR)/%.py,$(MODULES) __init__)
+PYCFILES := $(patsubst %,$(DSTDIR)/%.pyc,$(MODULES) __init__)
+
+default: $(PYFILES) $(PYCFILES) $(GDIR)/__init__.py $(GDIR)/__init__.pyc
+
+$(PYDIR):
+ $(MKDIR) $@
+
+$(GDIR): | $(PYDIR)
+ $(MKDIR) $@
+
+$(DSTDIR): | $(GDIR)
+ $(MKDIR) $@
+
+$(DSTDIR)/%: % | $(DSTDIR)
+ $(INSTALL_DATA) $< $@
+
+#doxygen:
+DOXNAME = pythonpygrass
\ No newline at end of file
Added: grass/trunk/lib/python/pygrass/tests/__init__.py
===================================================================
Added: grass/trunk/lib/python/pygrass/tests/benchmark.py
===================================================================
--- grass/trunk/lib/python/pygrass/tests/benchmark.py (rev 0)
+++ grass/trunk/lib/python/pygrass/tests/benchmark.py 2012-10-10 12:24:32 UTC (rev 53350)
@@ -0,0 +1,524 @@
+# -*- coding: utf-8 -*-
+"""
+Created on Sat Jun 16 20:24:56 2012
+
+ at author: soeren
+"""
+import optparse
+#import numpy as np
+import time
+import collections
+import copy
+import cProfile
+import sys, os
+from jinja2 import Template
+sys.path.append(os.getcwd())
+sys.path.append("%s/.."%(os.getcwd()))
+
+import grass.lib.gis as libgis
+import grass.lib.raster as libraster
+import grass.script as core
+import pygrass
+import ctypes
+
+def test__RasterNumpy_value_access__if():
+ test_a = pygrass.RasterNumpy(name="test_a", mtype="CELL", mode="r+")
+ test_a.open()
+
+ test_c = pygrass.RasterNumpy(name="test_c", mtype="CELL", mode="w+", overwrite=True)
+ test_c.open()
+
+ for row in xrange(test_a.rows):
+ for col in xrange(test_a.cols):
+ test_c[row, col] = test_a[row, col] > 50
+
+ test_a.close()
+ test_c.close()
+
+def test__RasterNumpy_value_access__add():
+ test_a = pygrass.RasterNumpy(name="test_a", mode="r+")
+ test_a.open()
+
+ test_b = pygrass.RasterNumpy(name="test_b", mode="r+")
+ test_b.open()
+
+ test_c = pygrass.RasterNumpy(name="test_c", mtype="DCELL", mode="w+", overwrite=True)
+ test_c.open()
+
+ for row in xrange(test_a.rows):
+ for col in xrange(test_a.cols):
+ test_c[row, col] = test_a[row, col] + test_b[row, col]
+
+ test_a.close()
+ test_b.close()
+ test_c.close()
+
+def test__RasterNumpy_row_access__if():
+ test_a = pygrass.RasterNumpy(name="test_a", mtype="CELL", mode="r+")
+ test_a.open()
+
+ test_c = pygrass.RasterNumpy(name="test_c", mtype="CELL", mode="w+", overwrite=True)
+ test_c.open()
+
+ for row in xrange(test_a.rows):
+ test_c[row] = test_a[row] > 50
+
+ test_a.close()
+ test_c.close()
+
+def test__RasterNumpy_row_access__add():
+ test_a = pygrass.RasterNumpy(name="test_a", mode="r+")
+ test_a.open()
+
+ test_b = pygrass.RasterNumpy(name="test_b", mode="r+")
+ test_b.open()
+
+ test_c = pygrass.RasterNumpy(name="test_c", mtype="DCELL", mode="w+", overwrite=True)
+ test_c.open()
+
+ for row in xrange(test_a.rows):
+ test_c[row] = test_a[row] + test_b[row]
+
+ test_a.close()
+ test_b.close()
+ test_c.close()
+
+def test__RasterNumpy_map_access__if():
+ test_a = pygrass.RasterNumpy(name="test_a", mtype="CELL", mode="r+")
+ test_a.open()
+
+ test_c = pygrass.RasterNumpy(name="test_c", mtype="CELL", mode="w+", overwrite=True)
+ test_c.open()
+
+ test_c = test_a > 50
+
+ test_a.close()
+ test_c.close()
+
+def test__RasterNumpy_map_access__add():
+ test_a = pygrass.RasterNumpy(name="test_a", mode="r+")
+ test_a.open()
+
+ test_b = pygrass.RasterNumpy(name="test_b", mode="r+")
+ test_b.open()
+
+ test_c = pygrass.RasterNumpy(name="test_c", mtype="DCELL", mode="w+", overwrite=True)
+ test_c.open()
+
+ test_c = test_a + test_b
+
+ test_a.close()
+ test_b.close()
+ test_c.close()
+
+def test__RasterSegment_value_access__if():
+ test_a = pygrass.RasterSegment(name="test_a")
+ test_a.open(mode="r")
+
+ test_c = pygrass.RasterSegment(name="test_c")
+ test_c.open(mode="w", mtype="CELL", overwrite=True)
+
+ buff_a = pygrass.Buffer(test_a.cols, test_a.mtype)
+
+ for row in xrange(test_a.rows):
+ test_a.get_row(row, buff_a)
+ for col in xrange(test_a.cols):
+ test_c.put(row, col, buff_a[col] > 50)
+
+ test_a.close()
+ test_c.close()
+
+def test__RasterSegment_value_access__add():
+ test_a = pygrass.RasterSegment(name="test_a")
+ test_a.open(mode="r")
+
+ test_b = pygrass.RasterSegment(name="test_b")
+ test_b.open(mode="r")
+
+ test_c = pygrass.RasterSegment(name="test_c")
+ test_c.open(mode="w", mtype="DCELL", overwrite=True)
+
+ buff_a = pygrass.Buffer(test_a.cols, test_a.mtype)
+ buff_b = pygrass.Buffer(test_b.cols, test_b.mtype)
+
+ for row in xrange(test_a.rows):
+ test_a.get_row(row, buff_a)
+ test_b.get_row(row,buff_b)
+ for col in xrange(test_a.cols):
+ test_c.put(row, col, buff_a[col] + buff_b[col])
+
+ test_a.close()
+ test_b.close()
+ test_c.close()
+
+def test__RasterSegment_row_access__if():
+ test_a = pygrass.RasterSegment(name="test_a")
+ test_a.open(mode="r")
+
+ test_c = pygrass.RasterSegment(name="test_c")
+ test_c.open(mode="w", mtype="CELL", overwrite=True)
+
+ buff_a = pygrass.Buffer(test_a.cols, test_a.mtype)
+
+ for row in xrange(test_a.rows):
+ test_a.get_row(row, buff_a)
+ test_c.put_row(row, buff_a > 50)
+
+ test_a.close()
+ test_c.close()
+
+def test__RasterSegment_row_access__add():
+ test_a = pygrass.RasterSegment(name="test_a")
+ test_a.open(mode="r")
+
+ test_b = pygrass.RasterSegment(name="test_b")
+ test_b.open(mode="r")
+
+ test_c = pygrass.RasterSegment(name="test_c")
+ test_c.open(mode="w", mtype="DCELL", overwrite=True)
+
+ buff_a = pygrass.Buffer(test_a.cols, test_a.mtype)
+ buff_b = pygrass.Buffer(test_b.cols, test_b.mtype)
+
+ for row in xrange(test_a.rows):
+ test_a.get_row(row, buff_a)
+ test_b.get_row(row,buff_b)
+ test_c.put_row(row, buff_a + buff_b)
+
+ test_a.close()
+ test_b.close()
+ test_c.close()
+
+def test__RasterRow_value_access__add():
+ test_a = pygrass.RasterRow(name="test_a")
+ test_a.open(mode="r")
+
+ test_b = pygrass.RasterRow(name="test_b")
+ test_b.open(mode="r")
+
+ test_c = pygrass.RasterRow(name="test_c")
+ test_c.open(mode="w", mtype="FCELL", overwrite=True)
+
+ buff_a = pygrass.Buffer(test_a.cols, test_a.mtype)
+ buff_b = pygrass.Buffer(test_b.cols, test_b.mtype)
+ buff_c = pygrass.Buffer(test_b.cols, test_b.mtype)
+
+ for row in xrange(test_a.rows):
+ test_a.get_row(row, buff_a)
+ test_b.get_row(row,buff_b)
+
+ for col in xrange(test_a.cols):
+ buff_c[col] = buff_a[col] + buff_b[col]
+
+ test_c.put_row(buff_c)
+
+ test_a.close()
+ test_b.close()
+ test_c.close()
+
+def test__RasterRow_value_access__if():
+ test_a = pygrass.RasterRow(name="test_a")
+ test_a.open(mode="r")
+
+ test_c = pygrass.RasterRow(name="test_c")
+ test_c.open(mode="w", mtype="CELL", overwrite=True)
+
+ buff_a = pygrass.Buffer(test_a.cols, test_a.mtype)
+ buff_c = pygrass.Buffer(test_a.cols, test_a.mtype)
+
+ for row in xrange(test_a.rows):
+ test_a.get_row(row, buff_a)
+
+ for col in xrange(test_a.cols):
+ buff_c[col] = buff_a[col] > 50
+
+ test_c.put_row(buff_c)
+
+ test_a.close()
+ test_c.close()
+
+def test__RasterRowIO_row_access__add():
+ test_a = pygrass.RasterRowIO(name="test_a")
+ test_a.open(mode="r")
+
+ test_b = pygrass.RasterRowIO(name="test_b")
+ test_b.open(mode="r")
+
+ test_c = pygrass.RasterRowIO(name="test_c")
+ test_c.open(mode="w", mtype="FCELL", overwrite=True)
+
+ buff_a = pygrass.Buffer(test_a.cols, test_a.mtype)
+ buff_b = pygrass.Buffer(test_b.cols, test_b.mtype)
+
+ for row in xrange(test_a.rows):
+ test_a.get_row(row, buff_a)
+ test_b.get_row(row,buff_b)
+ test_c.put_row(buff_a + buff_b)
+
+ test_a.close()
+ test_b.close()
+ test_c.close()
+
+def test__RasterRowIO_row_access__if():
+ test_a = pygrass.RasterRowIO(name="test_a")
+ test_a.open(mode="r")
+
+ test_c = pygrass.RasterRowIO(name="test_c")
+ test_c.open(mode="w", mtype="CELL", overwrite=True)
+
+ buff_a = pygrass.Buffer(test_a.cols, test_a.mtype)
+
+ for row in xrange(test_a.rows):
+ test_a.get_row(row, buff_a)
+ test_c.put_row(buff_a > 50)
+
+ test_a.close()
+ test_c.close()
+
+def test__RasterRow_row_access__add():
+ test_a = pygrass.RasterRow(name="test_a")
+ test_a.open(mode="r")
+
+ test_b = pygrass.RasterRow(name="test_b")
+ test_b.open(mode="r")
+
+ test_c = pygrass.RasterRow(name="test_c")
+ test_c.open(mode="w", mtype="FCELL", overwrite=True)
+
+ buff_a = pygrass.Buffer(test_a.cols, test_a.mtype)
+ buff_b = pygrass.Buffer(test_b.cols, test_b.mtype)
+
+ for row in xrange(test_a.rows):
+ test_a.get_row(row, buff_a)
+ test_b.get_row(row,buff_b)
+ test_c.put_row(buff_a + buff_b)
+
+ test_a.close()
+ test_b.close()
+ test_c.close()
+
+def test__RasterRow_row_access__if():
+ test_a = pygrass.RasterRow(name="test_a")
+ test_a.open(mode="r")
+
+ test_c = pygrass.RasterRow(name="test_c")
+ test_c.open(mode="w", mtype="CELL", overwrite=True)
+
+ buff_a = pygrass.Buffer(test_a.cols, test_a.mtype)
+
+ for row in xrange(test_a.rows):
+ test_a.get_row(row, buff_a)
+ test_c.put_row(buff_a > 50)
+
+ test_a.close()
+ test_c.close()
+
+def test__mapcalc__add():
+ core.mapcalc("test_c = test_a + test_b", quite=True, overwrite=True)
+
+def test__mapcalc__if():
+ core.mapcalc("test_c = if(test_a > 50, 1, 0)", quite=True, overwrite=True)
+
+def mytimer(func, runs=1):
+ times = []
+ t = 0.0
+ for _ in xrange(runs):
+ start = time.time()
+ func()
+ end = time.time()
+ times.append(end - start)
+ t = t + end - start
+
+ return t/runs, times
+
+
+
+def run_benchmark(resolution_list, runs, testdict, profile):
+ regions = []
+ for resolution in resolution_list:
+ core.use_temp_region()
+ core.run_command('g.region', e=50, w=-50, n=50, s=-50, res=resolution, flags='p')
+
+ # Adjust the computational region for this process
+ region = libgis.Cell_head()
+ libraster.Rast_get_window(ctypes.byref(region))
+ region.e = 50
+ region.w = -50
+ region.n = 50
+ region.s = -50
+ region.ew_res = resolution
+ region.ns_res = resolution
+
+ libgis.G_adjust_Cell_head(ctypes.byref(region), 0, 0)
+
+ libraster.Rast_set_window(ctypes.byref(region))
+ libgis.G_set_window(ctypes.byref(region))
+
+ # Create two raster maps with random numbers
+ core.mapcalc("test_a = rand(0, 100)", quite=True, overwrite=True)
+ core.mapcalc("test_b = rand(0.0, 1.0)", quite=True, overwrite=True)
+ result = collections.OrderedDict()
+ result['res'] = resolution
+ result['cols'] = region.cols
+ result['rows'] = region.rows
+ result['cells'] = region.rows * region.cols
+ result['results'] = copy.deepcopy(testdict)
+ for execmode, operation in result['results'].iteritems():
+ print(execmode)
+ for oper, operdict in operation.iteritems():
+ operdict['time'], operdict['times'] = mytimer(operdict['func'],runs)
+ if profile:
+ filename = '{}_{}_{}'.format(execmode, oper, profile)
+ cProfile.runctx(operdict['func'].__name__ + '()',
+ globals(), locals(), filename = filename)
+ print(' {0}: {1: 40.6f}s'.format(oper, operdict['time']))
+ del(operdict['func'])
+
+ regions.append(result)
+ core.del_temp_region()
+
+ return regions
+
+def get_testlist(loc):
+ testlist = [test for test in loc.keys() if 'test' in test[:5]]
+ testlist.sort()
+ return testlist
+
+def get_testdict(testlist):
+ testdict = collections.OrderedDict()
+ for testfunc in testlist:
+ #import pdb; pdb.set_trace()
+ dummy, execmode, operation = testfunc.split('__')
+ if execmode in testdict.keys():
+ testdict[execmode][operation] = collections.OrderedDict()
+ testdict[execmode][operation]['func'] = loc[testfunc]
+ else:
+ testdict[execmode] = collections.OrderedDict()
+ testdict[execmode][operation] = collections.OrderedDict()
+ testdict[execmode][operation]['func'] = loc[testfunc]
+ return testdict
+
+def print_test(testdict):
+ for execmode, operation in testdict.iteritems():
+ print execmode
+ for oper, operdict in operation.iteritems():
+ print ' ', oper
+ for key, value in operdict.iteritems():
+ print ' ', key
+
+TXT = u"""
+{% for region in regions %}
+{{ '#'*60 }}
+### Benchmark cols = {{ region.cols }} rows = {{ region.rows}} cells = {{ region.cells }}
+{{ '#'*60 }}
+
+ # equation: c = a + b
+ {% for execmode, operation in region.results.iteritems() %}
+ {{ "%-30s - %5s % 12.6fs"|format(execmode, 'add', operation.add.time) }}
+ {%- endfor %}
+
+ # equation: c = if a > 50 then 1 else 0
+ {% for execmode, operation in region.results.iteritems() %}
+ {{ "%-30s - %5s % 12.6fs"|format(execmode, 'if', operation.if.time) }}
+ {%- endfor %}
+{%- endfor %}
+"""
+
+
+CSV = """Class; Mode; Operation;
+
+"""
+
+RST = """
+"""
+#>>> txt = Template(TxT)
+#>>> txt.render(name='John Doe')
+
+
+def get_txt(results):
+ txt = Template(TXT)
+ return txt.render(regions = results)
+
+
+#classes for required options
+strREQUIRED = 'required'
+
+class OptionWithDefault(optparse.Option):
+ ATTRS = optparse.Option.ATTRS + [strREQUIRED]
+
+ def __init__(self, *opts, **attrs):
+ if attrs.get(strREQUIRED, False):
+ attrs['help'] = '(Required) ' + attrs.get('help', "")
+ optparse.Option.__init__(self, *opts, **attrs)
+
+class OptionParser(optparse.OptionParser):
+ def __init__(self, **kwargs):
+ kwargs['option_class'] = OptionWithDefault
+ optparse.OptionParser.__init__(self, **kwargs)
+
+ def check_values(self, values, args):
+ for option in self.option_list:
+ if hasattr(option, strREQUIRED) and option.required:
+ if not getattr(values, option.dest):
+ self.error("option %s is required".format(str(option)))
+ return optparse.OptionParser.check_values(self, values, args)
+
+
+def main(testdict):
+ """Main function"""
+ #usage
+ usage = "usage: %prog [options] raster_map"
+ parser = OptionParser(usage=usage)
+ # ntime
+ parser.add_option("-n", "--ntimes", dest="ntime",default=5, type="int",
+ help="Number of run for each test.")
+ # res
+ parser.add_option("-r", "--resolution", action="store", type="string",
+ dest="res", default = '1,0.25',
+ help="Resolution list separete by comma.")
+ # fmt
+ parser.add_option("-f", "--fmt", action="store", type="string",
+ dest="fmt", default = 'txt',
+ help="Choose the output format: 'txt', 'csv', 'rst'.")
+
+ # output
+ parser.add_option("-o", "--output", action="store", type="string",
+ dest="output", help="The output filename.")
+
+ # store
+ parser.add_option("-s", "--store", action="store", type="string",
+ dest="store", help="The filename of pickle obj.")
+
+ # profile
+ parser.add_option("-p", "--profile", action="store", type="string",
+ dest="profile", help="The filename of the profile results.")
+
+ #return options and argument
+ options, args = parser.parse_args()
+ res = [float(r) for r in options.res.split(',')]
+ #res = [1, 0.25, 0.1, 0.05]
+
+ results = run_benchmark(res, options.ntime, testdict, options.profile)
+
+ if options.store:
+ import pickle
+ output = open(options.store, 'wb')
+ pickle.dump(results, output)
+ output.close()
+ #import pdb; pdb.set_trace()
+ print get_txt(results)
+
+
+#add options
+if __name__ == "__main__":
+ #import pdb; pdb.set_trace()
+ loc = locals()
+ testlist = get_testlist(loc)
+ testdict = get_testdict(testlist)
+ #print_test(testdict)
+
+
+
+ #import pdb; pdb.set_trace()
+
+ main(testdict)
\ No newline at end of file
Added: grass/trunk/lib/python/pygrass/tests/set_mapset.py
===================================================================
--- grass/trunk/lib/python/pygrass/tests/set_mapset.py (rev 0)
+++ grass/trunk/lib/python/pygrass/tests/set_mapset.py 2012-10-10 12:24:32 UTC (rev 53350)
@@ -0,0 +1,81 @@
+# -*- coding: utf-8 -*-
+"""
+Created on Thu Aug 23 11:07:38 2012
+
+ at author: pietro
+
+"""
+import os
+import subprocess
+import optparse
+
+from grass.script import core as grasscore
+
+def read_gisrc(gisrcpath):
+ gisrc = open(gisrcpath, 'r')
+ diz = {}
+ for row in gisrc:
+ key, val = row.split(':')
+ diz[key.strip()] = val.strip()
+ return diz
+
+def main():
+ # default option
+ gisrc = read_gisrc(os.environ['GISRC'])
+ user = os.environ['USER']
+ # start optparse
+ usage = "usage: %prog [options]"
+ parser = optparse.OptionParser(usage=usage)
+ parser.add_option("-U", "--user", dest="user", default=user,
+ help="PostgreSQL user [default=%default]")
+ parser.add_option("-P", "--password", dest="passwd", default=None,
+ help="PostgreSQL password for user [default=%default]")
+ parser.add_option("-D", "--database", dest="db", default='pygrassdb_doctest',
+ help="PostgreSQL database name [default=%default]")
+
+ (opts, args) = parser.parse_args()
+ #
+ # Create DB
+ #
+ print("\n\nCreate a new DB: %s...\n" % opts.db)
+ createdb = ['createdb', '--encoding=UTF-8', '--owner=%s' % opts.user,
+ '--host=localhost', '--username=%s' % opts.user, opts.db]
+ if opts.passwd:
+ print opts.passwd
+ createdb.append("--password=%s" % opts.passwd)
+ else:
+ createdb.append("--no-password")
+ subprocess.Popen(createdb)
+
+ #
+ # set postgreSQL
+ #
+ print("\n\nSet Postgres connection...\n")
+ grasscore.run_command('db.connect', driver='pg',
+ database='host=localhost,dbname=%s' % opts.db)
+
+ grasscore.run_command('db.login', user=opts.user)
+ print("\n\nCopy the map from PERMANENT to user1...\n")
+ grasscore.run_command('g.copy',
+ vect="boundary_municp at PERMANENT,boundary_municp_pg",
+ overwrite=True)
+ print("\n\nBuild topology...\n")
+ grasscore.run_command('v.build', map='boundary_municp_pg', overwrite=True)
+
+
+ #
+ # set sqlite
+ #
+ db = [gisrc['GISDBASE'], gisrc['LOCATION_NAME'], gisrc['MAPSET'], 'sqlite.db']
+ print("\n\nSet Sqlite connection...\n")
+ grasscore.run_command('db.connect', driver='sqlite',
+ database=os.path.join(db))
+ print("\n\nCopy the map from PERMANENT to user1...\n")
+ grasscore.run_command('g.copy',
+ vect="boundary_municp at PERMANENT,boundary_municp_sqlite",
+ overwrite=True)
+ print("\n\nBuild topology...\n")
+ grasscore.run_command('v.build', map='boundary_municp_sqlite', overwrite=True)
+
+if __name__ == "__main__":
+ main()
\ No newline at end of file
Copied: grass/trunk/lib/python/pygrass/vector/Makefile (from rev 53343, grass/trunk/lib/python/Makefile)
===================================================================
--- grass/trunk/lib/python/pygrass/vector/Makefile (rev 0)
+++ grass/trunk/lib/python/pygrass/vector/Makefile 2012-10-10 12:24:32 UTC (rev 53350)
@@ -0,0 +1,32 @@
+MODULE_TOPDIR = ../../../..
+
+include $(MODULE_TOPDIR)/include/Make/Other.make
+include $(MODULE_TOPDIR)/include/Make/Python.make
+include $(MODULE_TOPDIR)/include/Make/Doxygen.make
+
+PYDIR = $(ETC)/python
+GDIR = $(PYDIR)/grass
+PGDIR = $(GDIR)/pygrass
+DSTDIR= $(PGDIR)/vector
+
+MODULES = abstract basic geometry sql table vector_type
+
+PYFILES := $(patsubst %,$(DSTDIR)/%.py,$(MODULES) __init__)
+PYCFILES := $(patsubst %,$(DSTDIR)/%.pyc,$(MODULES) __init__)
+
+default: $(PYFILES) $(PYCFILES) $(GDIR)/__init__.py $(GDIR)/__init__.pyc
+
+$(PYDIR):
+ $(MKDIR) $@
+
+$(GDIR): | $(PYDIR)
+ $(MKDIR) $@
+
+$(DSTDIR): | $(GDIR)
+ $(MKDIR) $@
+
+$(DSTDIR)/%: % | $(DSTDIR)
+ $(INSTALL_DATA) $< $@
+
+#doxygen:
+DOXNAME = pythonpygrass
\ No newline at end of file
Added: grass/trunk/lib/python/pygrass/vector/__init__.py
===================================================================
--- grass/trunk/lib/python/pygrass/vector/__init__.py (rev 0)
+++ grass/trunk/lib/python/pygrass/vector/__init__.py 2012-10-10 12:24:32 UTC (rev 53350)
@@ -0,0 +1,390 @@
+# -*- coding: utf-8 -*-
+"""
+Created on Tue Jul 17 08:51:53 2012
+
+ at author: pietro
+"""
+import ctypes
+
+import grass.lib.vector as libvect
+from vector_type import VTYPE, GV_TYPE
+
+#
+# import pygrass modules
+#
+from pygrass.errors import GrassError
+
+from basic import Bbox
+import geometry
+from abstract import Info
+
+import grass.script.core as core
+_GRASSENV = core.gisenv()
+
+_NUMOF = {"areas": libvect.Vect_get_num_areas,
+ "dblinks": libvect.Vect_get_num_dblinks,
+ "faces": libvect.Vect_get_num_faces,
+ "holes": libvect.Vect_get_num_holes,
+ "islands": libvect.Vect_get_num_islands,
+ "kernels": libvect.Vect_get_num_kernels,
+ "line_points": libvect.Vect_get_num_line_points,
+ "lines": libvect.Vect_get_num_lines,
+ "nodes": libvect.Vect_get_num_nodes,
+ "updated_lines": libvect.Vect_get_num_updated_lines,
+ "updated_nodes": libvect.Vect_get_num_updated_nodes,
+ "volumes": libvect.Vect_get_num_volumes}
+
+_GEOOBJ = {"areas": geometry.Area,
+ "dblinks": None,
+ "faces": None,
+ "holes": None,
+ "islands": geometry.Isle,
+ "kernels": None,
+ "line_points": None,
+ "lines": geometry.Boundary,
+ "nodes": geometry.Node,
+ "volumes": None}
+
+
+#=============================================
+# VECTOR
+#=============================================
+
+class Vector(Info):
+ """ ::
+
+ >>> from pygrass.vector import Vector
+ >>> municip = Vector('boundary_municp_sqlite')
+ >>> municip.is_open()
+ False
+ >>> municip.mapset
+ ''
+ >>> municip.exist()
+ True
+ >>> municip.mapset
+ '%s'
+ >>> municip.overwrite
+ False
+
+ ..
+ """ % _GRASSENV['MAPSET']
+ def __init__(self, name, mapset=''):
+ # Set map name and mapset
+ super(Vector, self).__init__(name, mapset)
+ self._topo_level = 1
+ self._class_name = 'Vector'
+ self.overwrite = False
+ self.dblinks = None
+
+ def __repr__(self):
+ if self.exist():
+ return "%s(%r, %r)" % (self._class_name, self.name, self.mapset)
+ else:
+ return "%s(%r)" % (self._class_name, self.name)
+
+ def __iter__(self):
+ """::
+
+ >>> mun = Vector('boundary_municp_sqlite')
+ >>> mun.open()
+ >>> features = [feature for feature in mun]
+ >>> features[:3]
+ [Boundary(v_id=None), Boundary(v_id=None), Boundary(v_id=None)]
+ >>> mun.close()
+
+ ..
+ """
+ #return (self.read(f_id) for f_id in xrange(self.num_of_features()))
+ return self
+
+ def next(self):
+ """::
+
+ >>> mun = Vector('boundary_municp_sqlite')
+ >>> mun.open()
+ >>> mun.next()
+ Boundary(v_id=None)
+ >>> mun.next()
+ Boundary(v_id=None)
+ >>> mun.close()
+
+ ..
+ """
+ v_id = self.c_mapinfo.contents.next_line
+ v_id = v_id if v_id != 0 else None
+ c_points = ctypes.pointer(libvect.line_pnts())
+ c_cats = ctypes.pointer(libvect.line_cats())
+ ftype = libvect.Vect_read_next_line(self.c_mapinfo, c_points, c_cats)
+ if ftype == -2:
+ raise StopIteration()
+ if ftype == -1:
+ raise
+ #if GV_TYPE[ftype]['obj'] is not None:
+ return GV_TYPE[ftype]['obj'](v_id=v_id,
+ c_mapinfo=self.c_mapinfo,
+ c_points=c_points,
+ c_cats=c_cats)
+
+ def bbox(self):
+ """Return the BBox of the vecor map
+ """
+ bbox = Bbox()
+ libvect.Vect_get_map_box(self.c_mapinfo, bbox.c_bbox)
+ return bbox
+
+ def write(self, geo_obj):
+ """::
+
+ >>> mun = Vector('boundary_municp_sqlite') #doctest: +SKIP
+ >>> mun.open(mode='rw') #doctest: +SKIP
+ >>> feature1 = mun.read(1) #doctest: +SKIP
+ >>> feature1 #doctest: +SKIP
+ Boundary(v_id=1)
+ >>> feature1[:3] #doctest: +SKIP +NORMALIZE_WHITESPACE
+ [Point(463718.874987, 310970.844494),
+ Point(463707.405987, 310989.499494),
+ Point(463714.593986, 311084.281494)]
+ >>> from geometry import Point #doctest: +SKIP
+ >>> feature1.insert(1, Point(463713.000000, 310980.000000))
+ ... #doctest: +SKIP
+ >>> feature1[:4] #doctest: +SKIP +NORMALIZE_WHITESPACE
+ [Point(463718.874987, 310970.844494),
+ Point(463713.000000, 310980.000000),
+ Point(463707.405987, 310989.499494),
+ Point(463714.593986, 311084.281494)]
+ >>> mun.write(feature1) #doctest: +SKIP
+ >>> feature1 #doctest: +SKIP
+ Boundary(v_id=8708)
+ >>> mun.close() #doctest: +SKIP
+
+ ..
+ """
+ result = libvect.Vect_write_line(self.c_mapinfo, geo_obj.gtype,
+ geo_obj.c_points, geo_obj.c_cats)
+ if result == -1:
+ raise GrassError("Not able to write the vector feature.")
+ if self._topo_level == 2:
+ # return new feature id (on level 2)
+ geo_obj.id = result
+ else:
+ # return offset into file where the feature starts (on level 1)
+ geo_obj.offset = result
+
+
+#=============================================
+# VECTOR WITH TOPOLOGY
+#=============================================
+
+class VectorTopo(Vector):
+ def __init__(self, name, mapset=''):
+ super(VectorTopo, self).__init__(name, mapset)
+ self._topo_level = 2
+ self._class_name = 'VectorTopo'
+
+ def __len__(self):
+ return libvect.Vect_get_num_lines(self.c_mapinfo)
+
+ def __getitem__(self, key):
+ """::
+
+ >>> mun = VectorTopo('boundary_municp_sqlite')
+ >>> mun.open()
+ >>> mun[:3]
+ [Boundary(v_id=1), Boundary(v_id=2), Boundary(v_id=3)]
+ >>> mun.close()
+
+ ..
+ """
+ if isinstance(key, slice):
+ #import pdb; pdb.set_trace()
+ #Get the start, stop, and step from the slice
+ return [self.read(indx + 1)
+ for indx in xrange(*key.indices(len(self)))]
+ elif isinstance(key, int):
+ self.read(key)
+ else:
+ raise ValueError("Invalid argument type: %r." % key)
+
+ def num_primitive_of(self, primitive):
+ """Primitive are:
+
+ * "boundary",
+ * "centroid",
+ * "face",
+ * "kernel",
+ * "line",
+ * "point"
+
+ ::
+
+ >>> municip = VectorTopo('boundary_municp_sqlite')
+ >>> municip.open()
+ >>> municip.num_primitive_of('point')
+ 0
+ >>> municip.num_primitive_of('line')
+ 0
+ >>> municip.num_primitive_of('centroid')
+ 3579
+ >>> municip.num_primitive_of('boundary')
+ 5128
+ >>> municip.close()
+
+ ..
+ """
+ return libvect.Vect_get_num_primitives(self.c_mapinfo,
+ VTYPE[primitive])
+
+ def number_of(self, vtype):
+ """
+ vtype in ["areas", "dblinks", "faces", "holes", "islands", "kernels",
+ "line_points", "lines", "nodes", "update_lines",
+ "update_nodes", "volumes"]
+
+ >>> municip = VectorTopo('boundary_municp_sqlite')
+ >>> municip.open()
+ >>> municip.number_of("areas")
+ 3579
+ >>> municip.number_of("islands")
+ 2629
+ >>> municip.number_of("holes")
+ 0
+ >>> municip.number_of("lines")
+ 8707
+ >>> municip.number_of("nodes")
+ 4178
+ >>> municip.number_of("pizza")
+ ... # doctest: +ELLIPSIS +NORMALIZE_WHITESPACE
+ Traceback (most recent call last):
+ ...
+ ValueError: vtype not supported, use one of:
+ 'areas', 'dblinks', 'faces', 'holes', 'islands', 'kernels',
+ 'line_points', 'lines', 'nodes', 'updated_lines', 'updated_nodes',
+ 'volumes'
+ >>> municip.close()
+
+
+ ..
+ """
+ if vtype in _NUMOF.keys():
+ return _NUMOF[vtype](self.c_mapinfo)
+ else:
+ keys = "', '".join(sorted(_NUMOF.keys()))
+ raise ValueError("vtype not supported, use one of: '%s'" % keys)
+
+ def viter(self, vtype):
+ """Return an iterator of vector features
+
+ ::
+ >>> municip = VectorTopo('boundary_municp_sqlite')
+ >>> municip.open()
+ >>> big = [area for area in municip.viter('areas')
+ ... if area.alive() and area.area >= 10000]
+ >>> big[:3]
+ [Area(1), Area(2), Area(3)]
+
+
+ to sort the result in a efficient way, use: ::
+
+ >>> from operator import methodcaller as method
+ >>> big.sort(key = method('area'), reverse = True) # sort the list
+ >>> for area in big[:3]:
+ ... print area, area.area()
+ Area(3102) 697521857.848
+ Area(2682) 320224369.66
+ Area(2552) 298356117.948
+ >>> municip.close()
+
+ ..
+ """
+ if vtype in _GEOOBJ.keys():
+ if _GEOOBJ[vtype] is not None:
+ return (_GEOOBJ[vtype](v_id=indx, c_mapinfo=self.c_mapinfo)
+ for indx in xrange(1, self.number_of(vtype) + 1))
+ else:
+ keys = "', '".join(sorted(_GEOOBJ.keys()))
+ raise ValueError("vtype not supported, use one of: '%s'" % keys)
+
+ def rewind(self):
+ """Rewind vector map to cause reads to start at beginning. ::
+
+ >>> mun = VectorTopo('boundary_municp_sqlite')
+ >>> mun.open()
+ >>> mun.next()
+ Boundary(v_id=1)
+ >>> mun.next()
+ Boundary(v_id=2)
+ >>> mun.next()
+ Boundary(v_id=3)
+ >>> mun.rewind()
+ >>> mun.next()
+ Boundary(v_id=1)
+ >>> mun.close()
+
+ ..
+ """
+ libvect.Vect_rewind(self.c_mapinfo)
+
+ def read(self, feature_id):
+ """Return a geometry object given the feature id. ::
+
+ >>> mun = VectorTopo('boundary_municp_sqlite')
+ >>> mun.open()
+ >>> feature1 = mun.read(0) #doctest: +ELLIPSIS
+ Traceback (most recent call last):
+ ...
+ ValueError: The index must be >0, 0 given.
+ >>> feature1 = mun.read(1)
+ >>> feature1
+ Boundary(v_id=1)
+ >>> feature1.length()
+ 1415.3348048582038
+ >>> mun.read(-1)
+ Centoid(649102.382010, 15945.714502)
+ >>> len(mun)
+ 8707
+ >>> mun.read(8707)
+ Centoid(649102.382010, 15945.714502)
+ >>> mun.read(8708) #doctest: +ELLIPSIS
+ Traceback (most recent call last):
+ ...
+ IndexError: Index out of range
+ >>> mun.close()
+
+ ..
+ """
+ if feature_id < 0: # Handle negative indices
+ feature_id += self.__len__() + 1
+ if feature_id >= (self.__len__() + 1):
+ raise IndexError('Index out of range')
+ if feature_id > 0:
+ c_points = ctypes.pointer(libvect.line_pnts())
+ c_cats = ctypes.pointer(libvect.line_cats())
+ ftype = libvect.Vect_read_line(self.c_mapinfo, c_points,
+ c_cats, feature_id)
+ if GV_TYPE[ftype]['obj'] is not None:
+ return GV_TYPE[ftype]['obj'](v_id=feature_id,
+ c_mapinfo=self.c_mapinfo,
+ c_points=c_points,
+ c_cats=c_cats)
+ else:
+ raise ValueError('The index must be >0, %r given.' % feature_id)
+
+ def rewrite(self, geo_obj):
+ result = libvect.Vect_rewrite_line(self.c_mapinfo,
+ geo_obj.id, geo_obj.gtype,
+ geo_obj.c_points,
+ geo_obj.c_cats)
+ # return offset into file where the feature starts
+ geo_obj.offset = result
+
+ def delete(self, feature_id):
+ if libvect.Vect_rewrite_line(self.c_mapinfo, feature_id) == -1:
+ raise GrassError("C funtion: Vect_rewrite_line.")
+
+ def restore(self, geo_obj):
+ if hasattr(geo_obj, 'offset'):
+ if libvect.Vect_restore_line(self.c_mapinfo, geo_obj.id,
+ geo_obj.offset) == -1:
+ raise GrassError("C funtion: Vect_restore_line.")
+ else:
+ raise ValueError("The value have not an offset attribute.")
\ No newline at end of file
Added: grass/trunk/lib/python/pygrass/vector/abstract.py
===================================================================
--- grass/trunk/lib/python/pygrass/vector/abstract.py (rev 0)
+++ grass/trunk/lib/python/pygrass/vector/abstract.py 2012-10-10 12:24:32 UTC (rev 53350)
@@ -0,0 +1,287 @@
+# -*- coding: utf-8 -*-
+"""
+Created on Fri Aug 17 17:24:03 2012
+
+ at author: pietro
+"""
+import ctypes
+import datetime
+import grass.lib.vector as libvect
+from vector_type import MAPTYPE
+
+import pygrass.env as env
+from pygrass.errors import GrassError, OpenError
+from table import DBlinks
+
+
+def must_be_open(method):
+ def wrapper(self):
+ if self.is_open():
+ return method(self)
+ else:
+ print "You must open the map."
+ return wrapper
+
+
+#=============================================
+# VECTOR ABSTRACT CLASS
+#=============================================
+
+class Info(object):
+ """Basic vector info.
+ To get access to the vector info the map must be opened. ::
+
+ >>> municip = Info('boundary_municp', 'PERMANENT')
+ >>> municip.full_name
+ You must open the map.
+
+ >>> municip.open()
+
+ Then it is possible to read and write the following map attributes: ::
+
+ >>> municip.organization
+ 'NC OneMap'
+ >>> municip.person
+ 'helena'
+ >>> municip.title
+ 'North Carolina municipality boundaries (polygon map)'
+ >>> municip.map_date
+ datetime.datetime(2006, 11, 7, 0, 1, 27)
+ >>> municip.date
+ ''
+ >>> municip.scale
+ 1
+ >>> municip.comment
+ ''
+ >>> municip.comment = "One useful comment!"
+ >>> municip.comment
+ 'One useful comment!'
+ >>> municip.zone
+ 0
+ >>> municip.proj
+ 99
+
+ There are some read only attributes: ::
+
+ >>> municip.full_name
+ 'boundary_municp at PERMANENT'
+ >>> municip.proj_name
+ 'Lambert Conformal Conic'
+ >>> municip.maptype
+ 'native'
+
+ And some basic methods: ::
+
+ >>> municip.is_3D()
+ False
+ >>> municip.exist()
+ True
+ >>> municip.is_open()
+ True
+ >>> municip.close()
+
+ """
+ def __init__(self, name, mapset=''):
+ # Set map name and mapset
+ self._name = name
+ self.mapset = mapset
+ self.c_mapinfo = ctypes.pointer(libvect.Map_info())
+ self._topo_level = 1
+ self._class_name = 'Vector'
+ self.overwrite = False
+ self.date_fmt = '%a %b %d %H:%M:%S %Y'
+
+ def _get_name(self):
+ if self.exist() and self.is_open():
+ return libvect.Vect_get_name(self.c_mapinfo)
+ else:
+ return self._name
+
+ def _set_name(self, newname):
+ self.rename(newname)
+
+ name = property(fget=_get_name, fset=_set_name)
+
+# @property
+# def mapset(self):
+# return libvect.Vect_get_mapset(self.c_mapinfo)
+
+ def _get_organization(self):
+ return libvect.Vect_get_organization(self.c_mapinfo)
+
+ def _set_organization(self, org):
+ libvect.Vect_get_organization(self.c_mapinfo, ctypes.c_char_p(org))
+
+ organization = property(fget=_get_organization, fset=_set_organization)
+
+ def _get_date(self):
+ return libvect.Vect_get_date(self.c_mapinfo)
+
+ def _set_date(self, date):
+ return libvect.Vect_set_date(self.c_mapinfo, ctypes.c_char_p(date))
+
+ date = property(fget=_get_date, fset=_set_date)
+
+ def _get_person(self):
+ return libvect.Vect_get_person(self.c_mapinfo)
+
+ def _set_person(self, person):
+ libvect.Vect_set_person(self.c_mapinfo, ctypes.c_char_p(person))
+
+ person = property(fget=_get_person, fset=_set_person)
+
+ def _get_title(self):
+ return libvect.Vect_get_map_name(self.c_mapinfo)
+
+ def _set_title(self, title):
+ libvect.Vect_set_map_name(self.c_mapinfo, ctypes.c_char_p(title))
+
+ title = property(fget=_get_title, fset=_set_title)
+
+ def _get_map_date(self):
+ date_str = libvect.Vect_get_map_date(self.c_mapinfo)
+ return datetime.datetime.strptime(date_str, self.date_fmt)
+
+ def _set_map_date(self, datetimeobj):
+ date_str = datetimeobj.strftime(self.date_fmt)
+ libvect.Vect_set_map_date(self.c_mapinfo, ctypes.c_char_p(date_str))
+
+ map_date = property(fget=_get_map_date, fset=_set_map_date)
+
+ def _get_scale(self):
+ return libvect.Vect_get_scale(self.c_mapinfo)
+
+ def _set_scale(self, scale):
+ return libvect.Vect_set_scale(self.c_mapinfo, ctypes.c_int(scale))
+
+ scale = property(fget=_get_scale, fset=_set_scale)
+
+ def _get_comment(self):
+ return libvect.Vect_get_comment(self.c_mapinfo)
+
+ def _set_comment(self, comm):
+ return libvect.Vect_set_comment(self.c_mapinfo, ctypes.c_char_p(comm))
+
+ comment = property(fget=_get_comment, fset=_set_comment)
+
+ def _get_zone(self):
+ return libvect.Vect_get_zone(self.c_mapinfo)
+
+ def _set_zone(self, zone):
+ return libvect.Vect_set_zone(self.c_mapinfo, ctypes.c_int(zone))
+
+ zone = property(fget=_get_zone, fset=_set_zone)
+
+ def _get_proj(self):
+ return libvect.Vect_get_proj(self.c_mapinfo)
+
+ def _set_proj(self, proj):
+ libvect.Vect_set_proj(self.c_mapinfo, ctypes.c_int(proj))
+
+ proj = property(fget=_get_proj, fset=_set_proj)
+
+ def _get_thresh(self):
+ return libvect.Vect_get_thresh(self.c_mapinfo)
+
+ def _set_thresh(self, thresh):
+ return libvect.Vect_set_thresh(self.c_mapinfo, ctypes.c_double(thresh))
+
+ thresh = property(fget=_get_thresh, fset=_set_thresh)
+
+ @property
+ @must_be_open
+ def full_name(self):
+ return libvect.Vect_get_full_name(self.c_mapinfo)
+
+ @property
+ @must_be_open
+ def maptype(self):
+ return MAPTYPE[libvect.Vect_maptype(self.c_mapinfo)]
+
+ @property
+ @must_be_open
+ def proj_name(self):
+ return libvect.Vect_get_proj_name(self.c_mapinfo)
+
+ def _write_header(self):
+ libvect.Vect_write_header(self.c_mapinfo)
+
+ def rename(self, newname):
+ """Rename the map"""
+ if self.exist():
+ env.rename(self.name, newname, 'vect')
+ self._name = newname
+
+ def is_3D(self):
+ return bool(libvect.Vect_is_3d(self.c_mapinfo))
+
+ def exist(self):
+ if self._name:
+ self.mapset = env.get_mapset_vector(self._name, self.mapset)
+ else:
+ return False
+ if self.mapset:
+ return True
+ else:
+ return False
+
+ def is_open(self):
+ return bool(self.c_mapinfo.contents.open)
+
+ def open(self, mode='r', layer='0', overwrite=None):
+ """::
+
+ >>> mun = Info('boundary_municp_sqlite')
+ >>> mun.open()
+ >>> mun.is_open()
+ True
+ >>> mun.close()
+
+ ..
+ """
+ print "Sto aprendo..."
+ # check if map exists or not
+ if not self.exist() and mode != 'w':
+ raise OpenError("Map <%s> not found." % self._name)
+ if libvect.Vect_set_open_level(self._topo_level) != 0:
+ raise OpenError("Invalid access level.")
+ # update the overwrite attribute
+ self.overwrite = overwrite if overwrite is not None else self.overwrite
+ # check if the mode is valid
+ if mode not in ('r', 'rw', 'w'):
+ raise ValueError("Mode not supported. Use one of: 'r', 'rw', 'w'.")
+ # check if the map exist
+ if self.exist() and mode == 'r':
+ openvect = libvect.Vect_open_old2(self.c_mapinfo, self.name,
+ self.mapset, layer)
+ # If it is opened in write mode
+ if mode == 'w':
+ #TODO: build topo if new
+ openvect = libvect.Vect_open_new(self.c_mapinfo, self.name,
+ libvect.WITHOUT_Z)
+ elif mode == 'rw':
+ openvect = libvect.Vect_open_update2(self.c_mapinfo, self.name,
+ self.mapset, layer)
+ # initialize the dblinks object
+ self.dblinks = DBlinks(self.c_mapinfo)
+ # check the C function result.
+ if openvect != self._topo_level:
+ str_err = "Not able to open the map, C function return %d."
+ raise OpenError(str_err % openvect)
+
+ def close(self):
+ if self.is_open():
+ if libvect.Vect_close(self.c_mapinfo) != 0:
+ str_err = 'Error when trying to close the map with Vect_close'
+ raise GrassError(str_err)
+
+ def remove(self):
+ """Remove vector map"""
+ if self.is_open():
+ self.close()
+ env.remove(vect=self.name)
+
+ def build(self):
+ """Build vector Topology"""
+ #TODO: Add function
+ pass
\ No newline at end of file
Added: grass/trunk/lib/python/pygrass/vector/basic.py
===================================================================
--- grass/trunk/lib/python/pygrass/vector/basic.py (rev 0)
+++ grass/trunk/lib/python/pygrass/vector/basic.py 2012-10-10 12:24:32 UTC (rev 53350)
@@ -0,0 +1,319 @@
+# -*- coding: utf-8 -*-
+"""
+Created on Tue Jul 31 13:06:20 2012
+
+ at author: pietro
+"""
+import ctypes
+import grass.lib.vector as libvect
+from collections import Iterable
+
+
+class Bbox(object):
+ """Instantiate a Bounding Box class that contain
+ a ctypes pointer to the C struct bound_box, that could be use
+ by C GRASS functions. ::
+
+ >>> bbox = Bbox()
+ >>> bbox
+ Bbox(0.0, 0.0, 0.0, 0.0)
+
+ The default parameters are 0. It is possible to set or change
+ the parameters later, with: ::
+
+ >>> bbox.north = 10
+ >>> bbox.south = -10
+ >>> bbox.east = -20
+ >>> bbox.west = 20
+ >>> bbox
+ Bbox(10.0, -10.0, -20.0, 20.0)
+
+ Or directly istantiate the class with the values, with: ::
+
+ >>> bbox = Bbox(north=100, south=0, east=0, west=100)
+ >>> bbox
+ Bbox(100.0, 0.0, 0.0, 100.0)
+
+ ..
+ """
+ def __init__(self, north=0, south=0, east=0, west=0, top=0, bottom=0):
+ self.c_bbox = ctypes.pointer(libvect.bound_box())
+ self.north = north
+ self.south = south
+ self.east = east
+ self.west = west
+ self.top = top
+ self.bottom = bottom
+
+ def _get_n(self):
+ return self.c_bbox.contents.N
+
+ def _set_n(self, value):
+ self.c_bbox.contents.N = value
+
+ north = property(fget=_get_n, fset=_set_n)
+
+ def _get_s(self):
+ return self.c_bbox.contents.S
+
+ def _set_s(self, value):
+ self.c_bbox.contents.S = value
+
+ south = property(fget=_get_s, fset=_set_s)
+
+ def _get_e(self):
+ return self.c_bbox.contents.E
+
+ def _set_e(self, value):
+ self.c_bbox.contents.E = value
+
+ east = property(fget=_get_e, fset=_set_e)
+
+ def _get_w(self):
+ return self.c_bbox.contents.W
+
+ def _set_w(self, value):
+ self.c_bbox.contents.W = value
+
+ west = property(fget=_get_w, fset=_set_w)
+
+ def _get_t(self):
+ return self.c_bbox.contents.T
+
+ def _set_t(self, value):
+ self.c_bbox.contents.T = value
+
+ top = property(fget=_get_t, fset=_set_t)
+
+ def _get_b(self):
+ return self.c_bbox.contents.B
+
+ def _set_b(self, value):
+ self.c_bbox.contents.B = value
+
+ bottom = property(fget=_get_b, fset=_set_b)
+
+ def __repr__(self):
+ return "Bbox({n}, {s}, {e}, {w})".format(n=self.north, s=self.south,
+ e=self.east, w=self.west)
+
+
+class BoxList(object):
+ def __init__(self, boxlist=None):
+ self.c_boxlist = ctypes.pointer(libvect.boxlist())
+ # if set to 0, the list will hold only ids and no boxes
+ self.c_boxlist.contents.have_boxes = 1
+ if boxlist is not None:
+ for box in boxlist:
+ self.append(box)
+
+ def __len__(self):
+ return self.c_boxlist.contents.n_values
+
+ def __repr__(self):
+ return "Boxlist([%s])" % ", ".join([repr(box)
+ for box in self.__iter__()])
+
+ def __getitem__(self, indx):
+ bbox = Bbox()
+ bbox.c_bbox = ctypes.pointer(self.c_boxlist.contents.box[indx])
+ return bbox
+
+ def __setitem__(self, indx, bbox):
+ self.c_boxlist.cotents.box[indx] = bbox
+
+ def __iter__(self):
+ return (self.__getitem__(box_id) for box_id in xrange(self.__len__()))
+
+ def __str__(self):
+ return self.__repr__()
+
+ def append(self, box):
+ """Append a Bbox object to a Boxlist object, using the
+ ``Vect_boxlist_append`` C fuction. ::
+
+ >>> box0 = Bbox()
+ >>> box1 = Bbox(1,2,3,4)
+ >>> box2 = Bbox(5,6,7,8)
+ >>> boxlist = BoxList([box0, box1])
+ >>> boxlist
+ Boxlist([Bbox(0.0, 0.0, 0.0, 0.0), Bbox(1.0, 2.0, 3.0, 4.0)])
+ >>> len(boxlist)
+ 2
+ >>> boxlist.append(box2)
+ >>> len(boxlist)
+ 3
+
+ ..
+ """
+ indx = self.__len__()
+ libvect.Vect_boxlist_append(self.c_boxlist, indx, box.c_bbox.contents)
+
+# def extend(self, boxlist):
+# """Extend a boxlist with another boxlist or using a list of Bbox, using
+# ``Vect_boxlist_append_boxlist`` c function. ::
+#
+# >>> box0 = Bbox()
+# >>> box1 = Bbox(1,2,3,4)
+# >>> box2 = Bbox(5,6,7,8)
+# >>> box3 = Bbox(9,8,7,6)
+# >>> boxlist0 = BoxList([box0, box1])
+# >>> boxlist0
+# Boxlist([Bbox(0.0, 0.0, 0.0, 0.0), Bbox(1.0, 2.0, 3.0, 4.0)])
+# >>> boxlist1 = BoxList([box2, box3])
+# >>> len(boxlist0)
+# 2
+# >>> boxlist0.extend(boxlist1)
+# >>> len(boxlist0)
+# 4
+# >>> boxlist1.extend([box0, box1])
+# >>> len(boxlist1)
+# 4
+#
+# ..
+# """
+# if hasattr(boxlist, 'c_boxlist'):
+# #import pdb; pdb.set_trace()
+# # FIXME: doesn't work
+# libvect.Vect_boxlist_append_boxlist(self.c_boxlist,
+# boxlist.c_boxlist)
+# else:
+# for box in boxlist:
+# self.append(box)
+
+ def remove(self, indx):
+ """Remove Bbox from the boxlist, given an integer or a list of integer
+ or a boxlist, using ``Vect_boxlist_delete`` C function or the
+ ``Vect_boxlist_delete_boxlist``. ::
+
+ >>> boxlist = BoxList([Bbox(),
+ ... Bbox(1, 0, 0, 1),
+ ... Bbox(1, -1, -1, 1)])
+ >>> boxlist.remove(0)
+ >>> boxlist
+ Boxlist([Bbox(1.0, 0.0, 0.0, 1.0), Bbox(1.0, -1.0, -1.0, 1.0)])
+
+ ..
+ """
+ if hasattr(indx, 'c_boxlist'):
+ libvect.Vect_boxlist_delete_boxlist(self.c_boxlist, indx.c_boxlist)
+ elif isinstance(indx, int):
+ libvect.Vect_boxlist_delete(self.c_boxlist, indx)
+ else:
+ for ind in indx:
+ libvect.Vect_boxlist_delete(self.c_boxlist, ind)
+
+ def reset(self):
+ """Reset the c_boxlist C struct, using the ``Vect_reset_boxlist`` C
+ function. ::
+
+ >>> boxlist = BoxList([Bbox(),
+ ... Bbox(1, 0, 0, 1),
+ ... Bbox(1, -1, -1, 1)])
+ >>> len(boxlist)
+ 3
+ >>> boxlist.reset()
+ >>> len(boxlist)
+ 0
+
+ ..
+ """
+ libvect.Vect_reset_boxlist(self.c_boxlist)
+
+
+class Ilist(object):
+ """Instantiate a list of integer using the C GRASS struct ``ilist``,
+ the class contains this struct as ``c_ilist`` attribute. """
+ def __init__(self, integer_list=None):
+ self.c_ilist = ctypes.pointer(libvect.struct_ilist())
+ if integer_list is not None:
+ self.extend(integer_list)
+
+ def __getitem__(self, key):
+ if isinstance(key, slice):
+ #import pdb; pdb.set_trace()
+ #Get the start, stop, and step from the slice
+ return [self.c_ilist.contents.value[indx]
+ for indx in xrange(*key.indices(len(self)))]
+ elif isinstance(key, int):
+ if key < 0: # Handle negative indices
+ key += self.c_ilist.contents.n_values
+ if key >= self.c_ilist.contents.n_values:
+ raise IndexError('Index out of range')
+ return self.c_ilist.contents.value[key]
+ else:
+ raise ValueError("Invalid argument type: %r." % key)
+
+ def __setitem__(self, key, value):
+ if self.contains(value):
+ raise ValueError('Integer already in the list')
+ self.c_ilist.contents.value[key] = int(value)
+
+ def __len__(self):
+ return self.c_ilist.contents.n_values
+
+ def __iter__(self):
+ return [self.c_ilist.contents.value[i] for i in xrange(self.__len__())]
+
+ def __repr__(self):
+ return "Ilist(%r)" % repr(self.__iter__())
+
+ def append(self, value):
+ """Append an integer to the list"""
+ if libvect.Vect_list_append(self.c_ilist, value):
+ raise # TODO
+
+ def reset(self):
+ """Reset the list"""
+ libvect.Vect_reset_list(self.c_ilist)
+
+ def extend(self, ilist):
+ """Extend the list with another Ilist object or
+ with a list of integers"""
+ if isinstance(ilist, Ilist):
+ libvect.Vect_list_append_list(self.c_ilist, ilist.ilist)
+ else:
+ for i in ilist:
+ self.append(i)
+
+ def remove(self, value):
+ """Remove a value from a list"""
+ if isinstance(value, int):
+ libvect.Vect_list_delete(self.c_ilist, value)
+ elif isinstance(value, Ilist):
+ libvect.Vect_list_delete_list(self.c_ilist, value.ilist)
+ elif isinstance(value, Iterable):
+ for i in value:
+ libvect.Vect_list_delete(self.c_ilist, int(i))
+ else:
+ raise ValueError('Value: %r, is not supported' % value)
+
+ def contains(self, value):
+ """Check if value is in the list"""
+ return bool(libvect.Vect_val_in_list(self.c_ilist, value))
+
+
+class Cats(object):
+ """Instantiate a Category class that contains a ctypes pointer
+ to the Map_info C struct, and a ctypes pointer to that C cats struct,
+ that could be used by C functions.
+ """
+
+ def __init__(self, c_mapinfo, v_id, c_cats=None):
+ self.c_mapinfo = c_mapinfo
+ self.id = v_id
+ if c_cats is not None:
+ self.c_cats = c_cats
+ else:
+ self.c_cats = ctypes.pointer(libvect.line_cats())
+ self.get_area_cats()
+
+ def get_area_cats(self):
+ """Get area categories, set the c_cats struct given an area, using the
+ ``Vect_get_area_cats`` function.
+ """
+ libvect.Vect_get_area_cats(self.c_mapinfo, self.id, self.c_cats)
+
+ def reset(self):
+ """Reset the C cats struct from previous values."""
+ libvect.Vect_reset_cats(self.c_cats)
\ No newline at end of file
Added: grass/trunk/lib/python/pygrass/vector/geometry.py
===================================================================
--- grass/trunk/lib/python/pygrass/vector/geometry.py (rev 0)
+++ grass/trunk/lib/python/pygrass/vector/geometry.py 2012-10-10 12:24:32 UTC (rev 53350)
@@ -0,0 +1,1146 @@
+# -*- coding: utf-8 -*-
+"""
+Created on Wed Jul 18 10:46:25 2012
+
+ at author: pietro
+
+"""
+import ctypes
+import numpy as np
+import re
+
+import grass.lib.gis as libgis
+import grass.lib.vector as libvect
+
+from basic import Ilist, Bbox, Cats
+
+
+WKT = {'POINT\((.*)\)': 'point', # 'POINT\(\s*([+-]*\d+\.*\d*)+\s*\)'
+ 'LINESTRING\((.*)\)': 'line'}
+
+
+def read_WKT(string):
+ """Read the string and return a geometry object
+
+ WKT:
+ POINT(0 0)
+ LINESTRING(0 0,1 1,1 2)
+ POLYGON((0 0,4 0,4 4,0 4,0 0),(1 1, 2 1, 2 2, 1 2,1 1))
+ MULTIPOINT(0 0,1 2)
+ MULTILINESTRING((0 0,1 1,1 2),(2 3,3 2,5 4))
+ MULTIPOLYGON(((0 0,4 0,4 4,0 4,0 0),(1 1,2 1,2 2,1 2,1 1)),
+ ((-1 -1,-1 -2,-2 -2,-2 -1,-1 -1)))
+ GEOMETRYCOLLECTION(POINT(2 3),LINESTRING(2 3,3 4))
+
+
+ EWKT:
+ POINT(0 0 0) -- XYZ
+ SRID=32632;POINT(0 0) -- XY with SRID
+ POINTM(0 0 0) -- XYM
+ POINT(0 0 0 0) -- XYZM
+ SRID=4326;MULTIPOINTM(0 0 0,1 2 1) -- XYM with SRID
+ MULTILINESTRING((0 0 0,1 1 0,1 2 1),(2 3 1,3 2 1,5 4 1))
+ POLYGON((0 0 0,4 0 0,4 4 0,0 4 0,0 0 0),(1 1 0,2 1 0,2 2 0,1 2 0,1 1 0))
+ MULTIPOLYGON(((0 0 0,4 0 0,4 4 0,0 4 0,0 0 0),
+ (1 1 0,2 1 0,2 2 0,1 2 0,1 1 0)),
+ ((-1 -1 0,-1 -2 0,-2 -2 0,-2 -1 0,-1 -1 0)))
+ GEOMETRYCOLLECTIONM( POINTM(2 3 9), LINESTRINGM(2 3 4, 3 4 5) )
+ MULTICURVE( (0 0, 5 5), CIRCULARSTRING(4 0, 4 4, 8 4) )
+ POLYHEDRALSURFACE( ((0 0 0, 0 0 1, 0 1 1, 0 1 0, 0 0 0)),
+ ((0 0 0, 0 1 0, 1 1 0, 1 0 0, 0 0 0)),
+ ((0 0 0, 1 0 0, 1 0 1, 0 0 1, 0 0 0)),
+ ((1 1 0, 1 1 1, 1 0 1, 1 0 0, 1 1 0)),
+ ((0 1 0, 0 1 1, 1 1 1, 1 1 0, 0 1 0)),
+ ((0 0 1, 1 0 1, 1 1 1, 0 1 1, 0 0 1)) )
+ TRIANGLE ((0 0, 0 9, 9 0, 0 0))
+ TIN( ((0 0 0, 0 0 1, 0 1 0, 0 0 0)), ((0 0 0, 0 1 0, 1 1 0, 0 0 0)) )
+
+ """
+ for regexp, obj in WKT.items():
+ if re.match(regexp, string):
+ geo = 10
+ return obj(geo)
+
+
+def read_WKB(buff):
+ """Read the binary buffer and return a geometry object"""
+ pass
+
+
+#=============================================
+# GEOMETRY
+#=============================================
+
+
+def get_xyz(pnt):
+ """Return a tuple with: x, y, z. ::
+
+ >>> pnt = Point(0, 0)
+ >>> get_xyz(pnt)
+ (0.0, 0.0, 0.0)
+ >>> get_xyz((1, 1))
+ (1, 1, 0.0)
+ >>> get_xyz((1, 1, 2))
+ (1, 1, 2)
+ >>> get_xyz((1, 1, 2, 2)) #doctest: +ELLIPSIS
+ Traceback (most recent call last):
+ ...
+ ValueError: The the format of the point is not supported: (1, 1, 2, 2)
+
+ ..
+ """
+ if isinstance(pnt, Point):
+ if pnt.is2D:
+ x, y = pnt.x, pnt.y
+ z = 0.
+ else:
+ x, y, z = pnt.x, pnt.y, pnt.z
+ else:
+ if len(pnt) == 2:
+ x, y = pnt
+ z = 0.
+ elif len(pnt) == 3:
+ x, y, z = pnt
+ else:
+ str_error = "The the format of the point is not supported: {0!r}"
+ raise ValueError(str_error.format(pnt))
+ return x, y, z
+
+
+class Geo(object):
+ """
+ >>> geo0 = Geo()
+ >>> points = ctypes.pointer(libvect.line_pnts())
+ >>> cats = ctypes.pointer(libvect.line_cats())
+ >>> geo1 = Geo(c_points=points, c_cats=cats)
+ """
+ def __init__(self, v_id=None, c_mapinfo=None, c_points=None, c_cats=None):
+ self.id = v_id # vector id
+ self.c_mapinfo = c_mapinfo
+
+ # set c_points
+ if c_points is None:
+ self.c_points = ctypes.pointer(libvect.line_pnts())
+ else:
+ self.c_points = c_points
+
+ # set c_cats
+ if c_cats is None:
+ self.c_cats = ctypes.pointer(libvect.line_cats())
+ else:
+ self.c_cats = c_cats
+
+ def is_with_topology(self):
+ if self.c_mapinfo is not None:
+ return self.c_mapinfo.contents.level == 2
+ else:
+ return False
+
+ def read(self):
+ """Read and set the coordinates of the centroid from the vector map,
+ using the centroid_id and calling the Vect_read_line C function"""
+ libvect.Vect_read_line(self.c_mapinfo, self.c_points,
+ self.c_cats, self.id)
+
+ def write(self):
+ """Write the centroid to the Map."""
+ libvect.Vect_write_line(self.c_mapinfo, libvect.GV_CENTROID,
+ self.c_points, self.c_cats)
+
+
+class Point(Geo):
+ """Instantiate a Point object that could be 2 or 3D, default
+ parameters are 0.
+
+ ::
+
+ >>> pnt = Point()
+ >>> pnt.x
+ 0.0
+ >>> pnt.y
+ 0.0
+ >>> pnt.z
+ >>> pnt.is2D
+ True
+ >>> pnt
+ Point(0.000000, 0.000000)
+ >>> pnt.z = 0
+ >>> pnt.is2D
+ False
+ >>> pnt
+ Point(0.000000, 0.000000, 0.000000)
+ >>> print pnt
+ POINT(0.000000, 0.000000, 0.000000)
+
+ ..
+ """
+ def __init__(self, x=0, y=0, z=None, **kargs):
+ super(Point, self).__init__(**kargs)
+ self.is2D = True if z is None else False
+ z = z if z is not None else 0
+ libvect.Vect_append_point(self.c_points, x, y, z)
+
+ # geometry type
+ self.gtype = libvect.GV_POINT
+
+ def _get_x(self):
+ return self.c_points.contents.x[0]
+
+ def _set_x(self, value):
+ self.c_points.contents.x[0] = value
+
+ x = property(fget=_get_x, fset=_set_x)
+
+ def _get_y(self):
+ return self.c_points.contents.y[0]
+
+ def _set_y(self, value):
+ self.c_points.contents.y[0] = value
+
+ y = property(fget=_get_y, fset=_set_y)
+
+ def _get_z(self):
+ if self.is2D:
+ return None
+ return self.c_points.contents.z[0]
+
+ def _set_z(self, value):
+ if value is None:
+ self.is2D = True
+ self.c_points.contents.z[0] = 0
+ else:
+ self.c_points.contents.z[0] = value
+ self.is2D = False
+
+ z = property(fget=_get_z, fset=_set_z)
+
+ def __str__(self):
+ return self.get_wkt()
+
+ def __repr__(self):
+ return "Point(%s)" % ', '.join(['%f' % coor for coor in self.coords()])
+
+ def __eq__(self, pnt):
+ if isinstance(pnt, Point):
+ return pnt.coords() == self.coords()
+
+ return Point(*pnt).coords() == self.coords()
+
+ def coords(self):
+ """Return a tuple with the point coordinates. ::
+
+ >>> pnt = Point(10, 100)
+ >>> pnt.coords()
+ (10.0, 100.0)
+
+ If the point is 2D return a x, y tuple. But if we change the ``z``
+ the Point object become a 3D point, therefore the method return a
+ x, y, z tuple. ::
+
+ >>> pnt.z = 1000.
+ >>> pnt.coords()
+ (10.0, 100.0, 1000.0)
+
+ ..
+ """
+ if self.is2D:
+ return self.x, self.y
+ else:
+ return self.x, self.y, self.z
+
+ def get_wkt(self):
+ """Return a "well know text" (WKT) geometry string. ::
+
+ >>> pnt = Point(10, 100)
+ >>> pnt.get_wkt()
+ 'POINT(10.000000, 100.000000)'
+
+ .. warning::
+
+ Only ``POINT`` (2/3D) are supported, ``POINTM`` and ``POINT`` with:
+ ``XYZM`` are not supported yet.
+ """
+ return "POINT(%s)" % ', '.join(['%f' % coord
+ for coord in self.coords()])
+
+ def get_wkb(self):
+ """Return a "well know binary" (WKB) geometry buffer
+
+ .. warning::
+
+ Not implemented yet.
+
+ """
+ pass
+
+ def distance(self, pnt):
+ """Calculate distance of 2 points, using the Vect_points_distance
+ C function, If one of the point have z == None, return the 2D distance.
+ ::
+
+ >>> pnt0 = Point(0, 0, 0)
+ >>> pnt1 = Point(1, 0)
+ >>> pnt0.distance(pnt1)
+ 1.0
+ >>> pnt1.z = 1
+ >>> pnt1
+ Point(1.000000, 0.000000, 1.000000)
+ >>> pnt0.distance(pnt1)
+ 1.4142135623730951
+
+ The distance method require a :class:Point or a tuple with
+ the coordinates.
+ """
+ if self.is2D or pnt.is2D:
+ return libvect.Vect_points_distance(self.x, self.y, 0,
+ pnt.x, pnt.y, 0, 0)
+ else:
+ return libvect.Vect_points_distance(self.x, self.y, self.z,
+ pnt.x, pnt.y, pnt.z, 1)
+
+ def buffer(self, dist=None, dist_x=None, dist_y=None, angle=0,
+ round_=True, tol=0.1):
+ """Return an Area object using the ``Vect_point_buffer2`` C function.
+ Creates buffer around the point (px, py).
+ """
+ print "Not implemented yet"
+ raise
+ if dist is not None:
+ dist_x = dist
+ dist_y = dist
+ area = Area()
+ libvect.Vect_point_buffer2(self.x, self.y,
+ dist_x, dist_y,
+ angle, int(round_), tol,
+ area.c_points)
+ return area
+
+
+class Line(Geo):
+ """Instantiate a new Line with a list of tuple, or with a list of Point. ::
+
+ >>> line = Line([(0, 0), (1, 1), (2, 0), (1, -1)])
+ >>> line #doctest: +NORMALIZE_WHITESPACE
+ Line([Point(0.000000, 0.000000),
+ Point(1.000000, 1.000000),
+ Point(2.000000, 0.000000),
+ Point(1.000000, -1.000000)])
+
+ ..
+ """
+ def __init__(self, points=None, is2D=True, **kargs):
+ super(Line, self).__init__(**kargs)
+ if points is not None:
+ for pnt in points:
+ self.append(pnt)
+
+ self.is2D = is2D
+ # geometry type
+ self.gtype = libvect.GV_LINE
+
+ def __getitem__(self, key):
+ """Get line point of given index, slice allowed. ::
+
+ >>> line = Line([(0, 0), (1, 1), (2, 2), (3, 3)])
+ >>> line[1]
+ Point(1.000000, 1.000000)
+ >>> line[-1]
+ Point(3.000000, 3.000000)
+ >>> line[:2]
+ [Point(0.000000, 0.000000), Point(1.000000, 1.000000)]
+
+ ..
+ """
+ #TODO:
+ # line[0].x = 10 is not working
+ #pnt.c_px = ctypes.pointer(self.c_points.contents.x[indx])
+ # pnt.c_px = ctypes.cast(id(self.c_points.contents.x[indx]),
+ # ctypes.POINTER(ctypes.c_double))
+ if isinstance(key, slice):
+ #import pdb; pdb.set_trace()
+ #Get the start, stop, and step from the slice
+ return [Point(self.c_points.contents.x[indx],
+ self.c_points.contents.y[indx],
+ None if self.is2D else self.c_points.contents.z[indx])
+ for indx in xrange(*key.indices(len(self)))]
+ elif isinstance(key, int):
+ if key < 0: # Handle negative indices
+ key += self.c_points.contents.n_points
+ if key >= self.c_points.contents.n_points:
+ raise IndexError('Index out of range')
+ return Point(self.c_points.contents.x[key],
+ self.c_points.contents.y[key],
+ None if self.is2D else self.c_points.contents.z[key])
+ else:
+ raise ValueError("Invalid argument type: %r." % key)
+
+ def __setitem__(self, indx, pnt):
+ """Change the coordinate of point. ::
+
+ >>> line = Line([(0, 0), (1, 1)])
+ >>> line[0] = (2, 2)
+ >>> line
+ Line([Point(2.000000, 2.000000), Point(1.000000, 1.000000)])
+
+ ..
+ """
+ x, y, z = get_xyz(pnt)
+ self.c_points.contents.x[indx] = x
+ self.c_points.contents.y[indx] = y
+ self.c_points.contents.z[indx] = z
+
+ def __iter__(self):
+ """Return a Point generator of the Line"""
+ return (self.__getitem__(i) for i in range(self.__len__()))
+
+ def __len__(self):
+ """Return the number of points of the line."""
+ return self.c_points.contents.n_points
+
+ def __str__(self):
+ return self.get_wkt()
+
+ def __repr__(self):
+ return "Line([%s])" % ', '.join([repr(pnt) for pnt in self.__iter__()])
+
+ def get_pnt(self, distance, angle=0, slope=0):
+ """Return a Point object on line in the specified distance, using the
+ `Vect_point_on_line` C function.
+ Raise a ValueError If the distance exceed the Line length. ::
+
+ >>> line = Line([(0, 0), (1, 1)])
+ >>> line.get_pnt(5) #doctest: +ELLIPSIS +NORMALIZE_WHITESPACE
+ Traceback (most recent call last):
+ ...
+ ValueError: The distance exceed the lenght of the line,
+ that is: 1.414214
+ >>> line.get_pnt(1)
+ Point(0.707107, 0.707107)
+
+ ..
+ """
+ # instantiate an empty Point object
+ maxdist = self.length()
+ if distance > maxdist:
+ str_err = "The distance exceed the lenght of the line, that is: %f"
+ raise ValueError(str_err % maxdist)
+ pnt = Point(0, 0, -9999)
+ libvect.Vect_point_on_line(self.c_points, distance,
+ pnt.c_points.contents.x,
+ pnt.c_points.contents.y,
+ pnt.c_points.contents.z,
+ angle, slope)
+ pnt.is2D = self.is2D
+ return pnt
+
+ def append(self, pnt):
+ """Appends one point to the end of a line, using the
+ ``Vect_append_point`` C function. ::
+
+ >>> line = Line()
+ >>> line.append((10, 100))
+ >>> line
+ Line([Point(10.000000, 100.000000)])
+ >>> line.append((20, 200))
+ >>> line
+ Line([Point(10.000000, 100.000000), Point(20.000000, 200.000000)])
+
+ Like python list.
+ """
+ x, y, z = get_xyz(pnt)
+ libvect.Vect_append_point(self.c_points, x, y, z)
+
+ def bbox(self):
+ """Return the bounding box of the line, using ``Vect_line_box``
+ C function. ::
+
+ >>> line = Line([(0, 0), (0, 1), (2, 1), (2, 0)])
+ >>> bbox = line.bbox()
+ >>> bbox
+ Bbox(1.0, 0.0, 2.0, 0.0)
+
+ ..
+ """
+ bbox = Bbox()
+ libvect.Vect_line_box(self.c_points, bbox.c_bbox)
+ return bbox
+
+ def extend(self, line, forward=True):
+ """Appends points to the end of a line.
+
+ It is possible to extend a line, give a list of points, or directly
+ with a line_pnts struct.
+
+ If forward is True the line is extend forward otherwise is extend
+ backward. The method use the `Vect_append_points` C function. ::
+
+ >>> line = Line([(0, 0), (1, 1)])
+ >>> line.extend( Line([(2, 2), (3, 3)]) )
+ >>> line #doctest: +NORMALIZE_WHITESPACE
+ Line([Point(0.000000, 0.000000),
+ Point(1.000000, 1.000000),
+ Point(2.000000, 2.000000),
+ Point(3.000000, 3.000000)])
+
+ Like python list, it is possible to extend a line, with another line
+ or with a list of points.
+ """
+ # set direction
+ if forward:
+ direction = libvect.GV_FORWARD
+ else:
+ direction = libvect.GV_BACKWARD
+ # check if is a Line object
+ if isinstance(line, Line):
+ c_points = line.c_points
+ else:
+ # instantiate a Line object
+ lin = Line()
+ for pnt in line:
+ # add the points to the line
+ lin.append(pnt)
+ c_points = lin.c_points
+
+ libvect.Vect_append_points(self.c_points, c_points, direction)
+
+ def insert(self, indx, pnt):
+ """Insert new point at index position and move all old points at
+ that position and above up, using ``Vect_line_insert_point``
+ C function. ::
+
+ >>> line = Line([(0, 0), (1, 1)])
+ >>> line.insert(0, Point(1.000000, -1.000000) )
+ >>> line #doctest: +NORMALIZE_WHITESPACE
+ Line([Point(1.000000, -1.000000),
+ Point(0.000000, 0.000000),
+ Point(1.000000, 1.000000)])
+
+ ..
+ """
+ if indx < 0: # Handle negative indices
+ indx += self.c_points.contents.n_points
+ if indx >= self.c_points.contents.n_points:
+ raise IndexError('Index out of range')
+ x, y, z = get_xyz(pnt)
+ libvect.Vect_line_insert_point(self.c_points, indx, x, y, z)
+
+ def length(self):
+ """Calculate line length, 3D-length in case of 3D vector line, using
+ `Vect_line_length` C function. ::
+
+ >>> line = Line([(0, 0), (1, 1), (0, 1)])
+ >>> line.length()
+ 2.414213562373095
+
+ ..
+ """
+ return libvect.Vect_line_length(self.c_points)
+
+ def length_geodesic(self):
+ """Calculate line length, usig `Vect_line_geodesic_length` C function.
+ ::
+
+ >>> line = Line([(0, 0), (1, 1), (0, 1)])
+ >>> line.length_geodesic()
+ 2.414213562373095
+
+ ..
+ """
+ return libvect.Vect_line_geodesic_length(self.c_points)
+
+ def distance(self, pnt):
+ """Return a tuple with:
+
+ * the closest point on the line,
+ * the distance between these two points,
+ * distance of point from segment beginning
+ * distance of point from line
+
+ The distance is compute using the ``Vect_line_distance`` C function.
+ """
+ # instantite outputs
+ cx = ctypes.c_double(0)
+ cy = ctypes.c_double(0)
+ cz = ctypes.c_double(0)
+ dist = ctypes.c_double(0)
+ sp_dist = ctypes.c_double(0)
+ lp_dist = ctypes.c_double(0)
+
+ libvect.Vect_line_distance(self.c_points,
+ pnt.x, pnt.y, pnt.z, 0 if self.is2D else 1,
+ ctypes.byref(cx), ctypes.byref(cy),
+ ctypes.byref(cz), ctypes.byref(dist),
+ ctypes.byref(sp_dist),
+ ctypes.byref(lp_dist))
+ # instantiate the Point class
+ point = Point(cx.value, cy.value, cz.value)
+ point.is2D = self.is2D
+ return point, dist, sp_dist, lp_dist
+
+ def get_first_cat(self):
+ """Fetches FIRST category number for given vector line and field, using
+ the ``Vect_get_line_cat`` C function.
+
+ .. warning::
+
+ Not implemented yet.
+ """
+ # TODO: add this method.
+ libvect.Vect_get_line_cat(self.map, self.id, self.field)
+ pass
+
+ def pop(self, indx):
+ """Return the point in the index position and remove from the Line. ::
+
+ >>> line = Line([(0, 0), (1, 1), (2, 2)])
+ >>> midle_pnt = line.pop(1)
+ >>> midle_pnt
+ Point(1.000000, 1.000000)
+ >>> line
+ Line([Point(0.000000, 0.000000), Point(2.000000, 2.000000)])
+
+ ..
+ """
+ if indx < 0: # Handle negative indices
+ indx += self.c_points.contents.n_points
+ if indx >= self.c_points.contents.n_points:
+ raise IndexError('Index out of range')
+ pnt = self.__getitem__(indx)
+ libvect.Vect_line_delete_point(self.c_points, indx)
+ return pnt
+
+ def delete(self, indx):
+ """Remove the point in the index position. ::
+
+ >>> line = Line([(0, 0), (1, 1), (2, 2)])
+ >>> line.delete(-1)
+ >>> line
+ Line([Point(0.000000, 0.000000), Point(1.000000, 1.000000)])
+
+ ..
+ """
+ if indx < 0: # Handle negative indices
+ indx += self.c_points.contents.n_points
+ if indx >= self.c_points.contents.n_points:
+ raise IndexError('Index out of range')
+ libvect.Vect_line_delete_point(self.c_points, indx)
+
+ def prune(self):
+ """Remove duplicate points, i.e. zero length segments, using
+ `Vect_line_prune` C function. ::
+
+ >>> line = Line([(0, 0), (1, 1), (1, 1), (2, 2)])
+ >>> line.prune()
+ >>> line #doctest: +NORMALIZE_WHITESPACE
+ Line([Point(0.000000, 0.000000),
+ Point(1.000000, 1.000000),
+ Point(2.000000, 2.000000)])
+
+ ..
+ """
+ libvect.Vect_line_prune(self.c_points)
+
+ def prune_thresh(self, threshold):
+ """Remove points in threshold, using the ``Vect_line_prune_thresh``
+ C funtion. ::
+
+ >>> line = Line([(0, 0), (1.0, 1.0), (1.2, 0.9), (2, 2)])
+ >>> line.prune_thresh(0.5)
+ >>> line #doctest: +SKIP +NORMALIZE_WHITESPACE
+ Line([Point(0.000000, 0.000000),
+ Point(1.000000, 1.000000),
+ Point(2.000000, 2.000000)])
+
+ .. warning ::
+
+ prune_thresh is not working yet.
+ """
+ libvect.Vect_line_prune(self.c_points, ctypes.c_double(threshold))
+
+ def remove(self, pnt):
+ """Delete point at given index and move all points above down, using
+ `Vect_line_delete_point` C function. ::
+
+ >>> line = Line([(0, 0), (1, 1), (2, 2)])
+ >>> line.remove((2, 2))
+ >>> line[-1]
+ Point(1.000000, 1.000000)
+
+ ..
+ """
+ for indx, point in enumerate(self.__iter__()):
+ if pnt == point:
+ libvect.Vect_line_delete_point(self.c_points, indx)
+ return
+ raise ValueError('list.remove(x): x not in list')
+
+ def reverse(self):
+ """Reverse the order of vertices, using `Vect_line_reverse`
+ C function. ::
+
+ >>> line = Line([(0, 0), (1, 1), (2, 2)])
+ >>> line.reverse()
+ >>> line #doctest: +NORMALIZE_WHITESPACE
+ Line([Point(2.000000, 2.000000),
+ Point(1.000000, 1.000000),
+ Point(0.000000, 0.000000)])
+
+ ..
+ """
+ libvect.Vect_line_reverse(self.c_points)
+
+ def segment(self, start, end):
+ """Create line segment. using the ``Vect_line_segment`` C function."""
+ line = Line()
+ libvect.Vect_line_segment(self.c_points, start, end, line.c_points)
+ return line
+
+ def tolist(self):
+ """Return a list of tuple. ::
+
+ >>> line = Line([(0, 0), (1, 1), (2, 0), (1, -1)])
+ >>> line.tolist()
+ [(0.0, 0.0), (1.0, 1.0), (2.0, 0.0), (1.0, -1.0)]
+
+ ..
+ """
+ return [pnt.coords() for pnt in self.__iter__()]
+
+ def toarray(self):
+ """Return an array of coordinates. ::
+
+ >>> line = Line([(0, 0), (1, 1), (2, 0), (1, -1)])
+ >>> line.toarray() #doctest: +NORMALIZE_WHITESPACE
+ array([[ 0., 0.],
+ [ 1., 1.],
+ [ 2., 0.],
+ [ 1., -1.]])
+
+ ..
+ """
+ return np.array(self.tolist())
+
+ def get_wkt(self):
+ """Return a Well Known Text string of the line. ::
+
+ >>> line = Line([(0, 0), (1, 1), (1, 2)])
+ >>> line.get_wkt() #doctest: +ELLIPSIS
+ 'LINESTRING(0.000000 0.000000, ..., 1.000000 2.000000)'
+
+ ..
+ """
+ return "LINESTRING(%s)" % ', '.join([
+ ' '.join(['%f' % coord for coord in pnt.coords()])
+ for pnt in self.__iter__()])
+
+ def from_wkt(self, wkt):
+ """Read a WKT string. ::
+
+ >>> line = Line()
+ >>> line.from_wkt("LINESTRING(0 0,1 1,1 2)")
+ >>> line #doctest: +NORMALIZE_WHITESPACE
+ Line([Point(0.000000, 0.000000),
+ Point(1.000000, 1.000000),
+ Point(1.000000, 2.000000)])
+
+ ..
+ """
+ match = re.match('LINESTRING\((.*)\)', wkt)
+ if match:
+ self.reset()
+ for coord in match.groups()[0].strip().split(','):
+ self.append(tuple([float(e) for e in coord.split(' ')]))
+ else:
+ return None
+
+ def get_wkb(self):
+ """Return a WKB buffer.
+
+ .. warning::
+
+ Not implemented yet.
+ """
+ pass
+
+ def buffer(self, dist=None, dist_x=None, dist_y=None,
+ angle=0, round_=True, tol=0.1):
+ """Return the buffer area around the line, using the
+ ``Vect_line_buffer2`` C function.
+
+ .. warning::
+
+ Not implemented yet.
+ """
+ if dist is not None:
+ dist_x = dist
+ dist_y = dist
+ area = Area()
+ libvect.Vect_line_buffer2(self.c_points,
+ dist_x, dist_y,
+ angle, int(round_), tol,
+ area.boundary.c_points,
+ area.isles.c_points,
+ area.num_isles)
+ return area
+
+ def reset(self):
+ """Reset line, using `Vect_reset_line` C function. ::
+
+ >>> line = Line([(0, 0), (1, 1), (2, 0), (1, -1)])
+ >>> len(line)
+ 4
+ >>> line.reset()
+ >>> len(line)
+ 0
+ >>> line
+ Line([])
+
+ ..
+ """
+ libvect.Vect_reset_line(self.c_points)
+
+
+class Node(object):
+ pass
+
+
+class Boundary(Line):
+ """
+ """
+ def __init__(self, area_id=None, lines=None, left=None, right=None,
+ **kargs):
+ super(Boundary, self).__init__(**kargs)
+ self.area_id = area_id
+ self.ilist = Ilist()
+ self.lines = lines
+ if lines:
+ if len(lines) != len(left) or len(lines) != len(right):
+ str_err = "Left and right must have the same length of lines"
+ raise ValueError(str_err)
+ self.left = Ilist()
+ self.right = Ilist()
+ # geometry type
+ self.gtype = libvect.GV_BOUNDARY
+
+ def __repr__(self):
+ return "Boundary(v_id=%r)" % self.id
+
+ def boundaries(self):
+ """Returna Ilist object with the line id"""
+ bounds = Ilist()
+ libvect.Vect_get_area_boundaries(self.c_mapinfo, self.area_id,
+ bounds.c_ilist)
+ return bounds
+
+ def get_left_right(self):
+ """Return left and right value"""
+ left = ctypes.poiter(ctypes.c_int())
+ right = ctypes.poiter(ctypes.c_int())
+ libvect.Vect_get_line_areas(self.c_mapinfo, self.id,
+ left, right)
+ return left.contents.value, right.contents.value
+
+
+class Centroid(Point):
+ """The Centroid class inherit from the Point class.
+ Centroid contains an attribute with the C Map_info struct, and attributes
+ with the id of the Area. ::
+
+ >>> centroid = Centroid(x=0, y=10)
+ >>> centroid
+ Centoid(0.000000, 10.000000)
+ >>> import pygrass
+ >>> mun = pygrass.vector.VectorTopo('boundary_municp_sqlite')
+ >>> mun.open()
+ >>> centroid = Centroid(v_id=5129, c_mapinfo=mun.c_mapinfo)
+ >>> centroid
+ Centoid(463784.493822, 311023.913274)
+
+ ..
+ """
+ def __init__(self, area_id=None, **kargs):
+ super(Centroid, self).__init__(**kargs)
+ self.area_id = area_id
+ if self.id and self.c_mapinfo and self.area_id is None:
+ self.area_id = self.get_area_id()
+ elif self.c_mapinfo and self.area_id and self.id is None:
+ self.id = self.get_centroid_id()
+ if self.area_id is not None:
+ self.cats = Cats(c_mapinfo=self.c_mapinfo, v_id=self.area_id)
+ #TODO: why not pass the self.id?
+ self.read()
+
+ # geometry type
+ self.gtype = libvect.GV_CENTROID
+ #self.c_pline = ctypes.pointer(libvect.P_line()) if topology else None
+
+ def __repr__(self):
+ return "Centoid(%s)" % ', '.join(['%f' % co for co in self.coords()])
+
+ def get_centroid_id(self):
+ """Return the centroid_id, using the c_mapinfo and an area_id
+ attributes of the class, and calling the Vect_get_area_centroid
+ C function, if no centroid_id were found return None"""
+ centroid_id = libvect.Vect_get_area_centroid(self.c_mapinfo,
+ self.area_id)
+ return centroid_id if centroid_id != 0 else None
+
+ def get_area_id(self):
+ """Return the area_id, using the c_mapinfo and an centroid_id
+ attributes of the class, and calling the Vect_get_centroid_area
+ C function, if no area_id were found return None"""
+ area_id = libvect.Vect_get_centroid_area(self.c_mapinfo,
+ self.id)
+ return area_id if area_id != 0 else None
+
+
+class Isle(Geo):
+ """An Isle is an area contained by another area.
+ """
+ def __init__(self, **kargs):
+ super(Isle, self).__init__(**kargs)
+ #self.area_id = area_id
+
+ def __repr__(self):
+ return "Isle(%d)" % (self.id)
+
+ def boundaries(self):
+ ilist = Ilist()
+ libvect.Vect_get_isle_boundaries(self.c_mapinfo, self.id,
+ ilist.c_ilist)
+ return ilist
+
+ def bbox(self):
+ bbox = Bbox()
+ libvect.Vect_get_isle_box(self.c_mapinfo, self.id, bbox.c_bbox)
+ return bbox
+
+ def points(self):
+ """Return a Line object with the outer ring points"""
+ line = Line()
+ libvect.Vect_get_isle_points(self.c_mapinfo, self.id, line.c_points)
+ return line
+
+ def points_geos(self):
+ """Return a Line object with the outer ring points
+ """
+ return libvect.Vect_get_isle_points_geos(self.c_mapinfo, self.id)
+
+ def area_id(self):
+ """Returns area id for isle."""
+ return libvect.Vect_get_isle_area(self.c_mapinfo, self.id)
+
+ def alive(self):
+ """Check if isle is alive or dead (topology required)"""
+ return bool(libvect.Vect_isle_alive(self.c_mapinfo, self.id))
+
+ def contain_pnt(self, pnt):
+ """Check if point is in area."""
+ bbox = self.bbox()
+ return bool(libvect.Vect_point_in_island(pnt.x, pnt.y,
+ self.c_mapinfo, self.id,
+ bbox.c_bbox.contents))
+
+ def area(self):
+ """Return the area value of an Isle"""
+ border = self.points()
+ return libgis.G_area_of_polygon(border.c_points.contents.x,
+ border.c_points.contents.y,
+ border.c_points.contents.n_points)
+
+ def perimeter(self):
+ """Return the perimeter value of an Isle.
+ ::
+ double Vect_area_perimeter()
+
+ """
+ border = self.points()
+ return libvect.Vect_area_perimeter(border.c_points)
+
+
+class Isles(object):
+ def __init__(self, c_mapinfo, area_id):
+ self.c_mapinfo = c_mapinfo
+ self.area_id = area_id
+ self._isles_id = self.get_isles_id()
+ self._isles = self.get_isles()
+
+ def __len__(self):
+ return libvect.Vect_get_area_num_isles(self.c_mapinfo, self.area_id)
+
+ def __repr__(self):
+ return "Isles(%r)" % self._isles
+
+ def __getitem__(self, key):
+ return self._isles[key]
+
+ def get_isles_id(self):
+ return [libvect.Vect_get_area_isle(self.c_mapinfo, self.area_id, i)
+ for i in range(self.__len__())]
+
+ def get_isles(self):
+ return [Isle(v_id=isle_id, c_mapinfo=self.c_mapinfo)
+ for isle_id in self._isles_id]
+
+ def select_by_bbox(self, bbox):
+ """Vect_select_isles_by_box"""
+ pass
+
+
+class Area(Geo):
+ """
+ 'Vect_build_line_area',
+ 'Vect_find_area',
+ 'Vect_get_area_box',
+ 'Vect_get_area_points_geos',
+ 'Vect_get_centroid_area',
+
+ 'Vect_get_isle_area',
+ 'Vect_get_line_areas',
+ 'Vect_get_num_areas',
+ 'Vect_get_point_in_area',
+ 'Vect_isle_find_area',
+ 'Vect_point_in_area',
+ 'Vect_point_in_area_outer_ring',
+
+ 'Vect_read_area_geos',
+ 'Vect_remove_small_areas',
+ 'Vect_select_areas_by_box',
+ 'Vect_select_areas_by_polygon']
+ """
+
+ def __init__(self, boundary=None, centroid=None, isles=[], **kargs):
+ super(Area, self).__init__(**kargs)
+ self.boundary = self.points()
+ self.centroid = self.centroid()
+ self.isles = self.get_isles()
+ # geometry type
+ self.gtype = libvect.GV_AREA
+
+ def __repr__(self):
+ return "Area(%d)" % self.id
+
+ def init_from_id(self, area_id=None):
+ """Return an Area object"""
+ if area_id is None and self.id is None:
+ raise ValueError("You need to give or set the area_id")
+ self.id = area_id if area_id is not None else self.id
+ # get boundary
+ self.get_boundary()
+ # get isles
+ self.get_isles()
+ pass
+
+ def points(self):
+ """Return a Line object with the outer ring"""
+ line = Line()
+ libvect.Vect_get_area_points(self.c_mapinfo, self.id, line.c_points)
+ return line
+
+ def centroid(self):
+ centroid_id = libvect.Vect_get_area_centroid(self.c_mapinfo, self.id)
+ #import pdb; pdb.set_trace()
+ return Centroid(v_id=centroid_id, c_mapinfo=self.c_mapinfo,
+ area_id=self.id)
+
+ def num_isles(self):
+ return libvect.Vect_get_area_num_isles(self.c_mapinfo, self.id)
+
+ def get_isles(self):
+ """Instantiate the boundary attribute reading area_id"""
+ return Isles(self.c_mapinfo, self.id)
+
+ def area(self):
+ """Returns area of area without areas of isles.
+ double Vect_get_area_area (const struct Map_info *Map, int area)
+
+ """
+ return libvect.Vect_get_area_area(self.c_mapinfo, self.id)
+
+ def alive(self):
+ """Check if area is alive or dead (topology required)
+ """
+ return bool(libvect.Vect_area_alive(self.c_mapinfo, self.id))
+
+ def bbox(self):
+ """
+ Vect_get_area_box
+ """
+ bbox = Bbox()
+ libvect.Vect_get_area_box(self.c_mapinfo, self.id, bbox.c_bbox)
+ return bbox
+
+ def buffer(self):
+ """Creates buffer around area.
+
+ Parameters:
+ Map vector map
+ area area id
+ da distance along major axis
+ db distance along minor axis
+ dalpha angle between 0x and major axis
+ round make corners round
+ caps add caps at line ends
+ tol maximum distance between theoretical arc and output segments
+ [out] oPoints output polygon outer border (ccw order)
+ [out] inner_count number of holes
+ [out] iPoints array of output polygon's holes (cw order)
+
+ void Vect_area_buffer2(const struct Map_info * Map,
+ int area,
+ double da,
+ double db,
+ double dalpha,
+ int round,
+ int caps,
+ double tol,
+ struct line_pnts ** oPoints,
+ struct line_pnts *** iPoints,
+ int * inner_count)
+ """
+ pass
+
+ def boundaries(self):
+ """Creates list of boundaries for given area.
+
+ int Vect_get_area_boundaries(const struct Map_info *Map,
+ int area, struct ilist *List)
+ """
+ ilist = Ilist()
+ libvect.Vect_get_area_boundaries(self.c_mapinfo, self.id,
+ ilist.c_ilist)
+ return ilist
+
+ def cats(self):
+ """Get area categories.
+ int Vect_get_area_cats (const struct Map_info *Map,
+ int area, struct line_cats *Cats)
+ """
+ return Cats(self.c_mapinfo, self.id)
+
+ def get_first_cat(self):
+ """Find FIRST category of given field and area.
+
+ int Vect_get_area_cat(const struct Map_info *Map, int area, int field)
+ """
+ pass
+
+ def contain_pnt(self, pnt):
+ """Check if point is in area.
+ int Vect_point_in_area(double x, double y,
+ const struct Map_info *Map,
+ int area, struct bound_box box)
+ """
+ bbox = self.bbox()
+ libvect.Vect_point_in_area(pnt.x, pnt.y, self.c_mapinfo, self.id,
+ bbox.c_bbox)
+ return bbox
+
+ def perimeter(self):
+ """Calculate area perimeter.
+
+ double Vect_area_perimeter (const struct line_pnts *Points)
+
+ """
+ border = self.points()
+ return libvect.Vect_area_perimeter(border.c_points)
\ No newline at end of file
Added: grass/trunk/lib/python/pygrass/vector/sql.py
===================================================================
--- grass/trunk/lib/python/pygrass/vector/sql.py (rev 0)
+++ grass/trunk/lib/python/pygrass/vector/sql.py 2012-10-10 12:24:32 UTC (rev 53350)
@@ -0,0 +1,47 @@
+# -*- coding: utf-8 -*-
+"""
+SQL
+===
+
+It is a collection of strings to avoid to repeat the code. ::
+
+ >>> SELECT.format(cols=', '.join(['cat', 'area']), tname='table')
+ 'SELECT cat, area FROM table;'
+ >>> SELECT_WHERE.format(cols=', '.join(['cat', 'area']),
+ ... tname='table', condition='area>10000')
+ 'SELECT cat, area FROM table WHERE area>10000;'
+
+
+"""
+
+#
+# SQL
+#
+
+#ALTER TABLE
+ADD_COL = "ALTER TABLE {tname} ADD COLUMN {cname} {ctype};"
+DROP_COL = "ALTER TABLE {tname} DROP COLUMN {cname};"
+DROP_COL_SQLITE = ';\n'.join([
+"CREATE TEMPORARY TABLE {tname}_backup({coldef})",
+"INSERT INTO {tname}_backup SELECT {colnames} FROM {tname}",
+"DROP TABLE {tname}",
+"CREATE TABLE {tname}({coldef})",
+"INSERT INTO {tname} SELECT {colnames} FROM {tname}_backup",
+"CREATE UNIQUE INDEX {tname}_cat ON {tname} ({keycol} )",
+"DROP TABLE {tname}_backup",
+])
+RENAME_COL = "ALTER TABLE {tname} RENAME COLUMN {old_name} TO {new_name};"
+CAST_COL = "ALTER TABLE {tname} ALTER COLUMN {col} SET DATA TYPE {ctype};"
+RENAME_TAB = "ALTER TABLE {old_name} RENAME TO {new_name};"
+
+#SELECT
+SELECT = "SELECT {cols} FROM {tname};"
+SELECT_WHERE = "SELECT {cols} FROM {tname} WHERE {condition};"
+SELECT_ORDERBY = "SELECT {cols} FROM {tname} ORDER BY {orderby};"
+
+#UPDATE
+UPDATE = "UPDATE {tname} SET {new_col} = {old_col};"
+UPDATE_WHERE = "UPDATE {tname} SET {new_col} = {old_col} WHERE {condition};"
+
+# GET INFO
+PRAGMA = "PRAGMA table_info({tname});"
\ No newline at end of file
Added: grass/trunk/lib/python/pygrass/vector/table.py
===================================================================
--- grass/trunk/lib/python/pygrass/vector/table.py (rev 0)
+++ grass/trunk/lib/python/pygrass/vector/table.py 2012-10-10 12:24:32 UTC (rev 53350)
@@ -0,0 +1,839 @@
+# -*- coding: utf-8 -*-
+"""
+Created on Wed Aug 8 15:29:21 2012
+
+ at author: pietro
+
+
+
+"""
+import ctypes
+
+try:
+ from collections import OrderedDict
+except:
+ from pygrass.orderdict import OrderedDict
+
+import grass.lib.vector as libvect
+import grass.script.core as core
+
+import sql
+
+
+DRIVERS = ('sqlite', 'pg')
+
+
+class DBError(Exception):
+ def __init__(self, value):
+ self.value = value
+
+ def __str__(self):
+ return repr(self.value)
+
+
+def get_path(path):
+ if "$" not in path:
+ return path
+ else:
+ grassenv = core.gisenv()
+ path = path.replace('$GISDBASE', grassenv['GISDBASE'])
+ path = path.replace('$LOCATION_NAME', grassenv['LOCATION_NAME'])
+ path = path.replace('$MAPSET', grassenv['MAPSET'])
+ return path
+
+
+class Filters(object):
+ """Help user to build a simple sql query. ::
+
+ >>> filter = Filters('table')
+ >>> filter.get_sql()
+ 'SELECT * FROM table;'
+ >>> filter.where("area<10000").get_sql()
+ 'SELECT * FROM table WHERE area<10000;'
+ >>> filter.select("cat", "area").get_sql()
+ 'SELECT cat, area FROM table WHERE area<10000;'
+ >>> filter.order_by("area").limit(10).get_sql()
+ 'SELECT cat, area FROM table WHERE area<10000 ORDER BY area LIMIT 10;'
+
+ ..
+ """
+ def __init__(self, tname):
+ self.tname = tname
+ self._select = None
+ self._where = None
+ self._orderby = None
+ self._limit = None
+
+ def __repr__(self):
+ return "Filters(%r)" % self.get_sql()
+
+ def select(self, *args):
+ cols = ', '.join(args) if args else '*'
+ select = sql.SELECT[:-1]
+ self._select = select.format(cols=cols, tname=self.tname)
+ return self
+
+ def where(self, condition):
+ self._where = 'WHERE {condition}'.format(condition=condition)
+ return self
+
+ def order_by(self, orderby):
+ if not isinstance(orderby, str):
+ orderby = ', '.join(orderby)
+ self._orderby = 'ORDER BY {orderby}'.format(orderby=orderby)
+ return self
+
+ def limit(self, number):
+ if not isinstance(number, int):
+ raise ValueError("Must be an integer.")
+ else:
+ self._limit = 'LIMIT {number}'.format(number=number)
+ return self
+
+ def get_sql(self):
+ sql_list = list()
+ if self._select is None:
+ self.select()
+ sql_list.append(self._select)
+
+ if self._where is not None:
+ sql_list.append(self._where)
+ if self._orderby is not None:
+ sql_list.append(self._orderby)
+ if self._limit is not None:
+ sql_list.append(self._limit)
+ return "%s;" % ' '.join(sql_list)
+
+ def reset(self):
+ self._select = None
+ self._where = None
+ self._orderby = None
+ self._limit = None
+
+
+class Columns(object):
+ """Object to work with columns table.
+
+ It is possible to instantiate a Columns object given the table name and
+ the database connection.
+
+ For a sqlite table: ::
+
+ >>> import sqlite3
+ >>> path = '$GISDBASE/$LOCATION_NAME/$MAPSET/sqlite.db'
+ >>> cols_sqlite = Columns('boundary_municp_sqlite',
+ ... sqlite3.connect(get_path(path)))
+ >>> cols_sqlite.tname
+ 'boundary_municp_sqlite'
+
+ For a postgreSQL table: ::
+
+ >>> import psycopg2 as pg
+ >>> cols_pg = Columns('boundary_municp_pg',
+ ... pg.connect('host=localhost dbname=grassdb'))
+ >>> cols_pg.tname
+ 'boundary_municp_pg'
+
+ ..
+ """
+ def __init__(self, tname, connection, key='cat'):
+ self.tname = tname
+ self.conn = connection
+ self.key = key
+ self.odict = None
+ self.update_odict()
+
+ def __contains__(self, item):
+ return item in self.names()
+
+ def __repr__(self):
+ return "Columns(%r)" % self.items()
+
+ def __getitem__(self, key):
+ return self.odict[key]
+
+ def __setitem__(self, name, new_type):
+ self.cast(name, new_type)
+ self.update_odict(self)
+
+ def __iter__(self):
+ return self.odict.__iter__()
+
+ def __len__(self):
+ return self.odict.__len__()
+
+ def __eq__(self, obj):
+ return obj.tname == self.tname and obj.odict == self.odict
+
+ def is_pg(self):
+ """Return True if is a psycopg connection. ::
+
+ >>> import sqlite3
+ >>> path = '$GISDBASE/$LOCATION_NAME/$MAPSET/sqlite.db'
+ >>> cols_sqlite = Columns('boundary_municp_sqlite',
+ ... sqlite3.connect(get_path(path)))
+ >>> cols_sqlite.is_pg()
+ False
+ >>> import psycopg2 as pg
+ >>> cols_pg = Columns('boundary_municp_pg',
+ ... pg.connect('host=localhost dbname=grassdb'))
+ >>> cols_pg.is_pg()
+ True
+
+ ..
+ """
+ return hasattr(self.conn, 'xid')
+
+ def update_odict(self):
+ """Read columns name and types from table and update the odict
+ attribute.
+ """
+ if self.is_pg():
+ # is a postgres connection
+ cur = self.conn.cursor()
+ cur.execute("SELECT oid,typname FROM pg_type")
+ diz = dict(cur.fetchall())
+ cur.execute(sql.SELECT.format(cols='*', tname=self.tname))
+ descr = cur.description
+ odict = OrderedDict()
+ for column in descr:
+ name, ctype = column[:2]
+ odict[name] = diz[ctype]
+ self.odict = odict
+ else:
+ # is a sqlite connection
+ cur = self.conn.cursor()
+ cur.execute(sql.PRAGMA.format(tname=self.tname))
+ descr = cur.fetchall()
+ odict = OrderedDict()
+ for column in descr:
+ name, ctype = column[1:3]
+ odict[name] = ctype
+ self.odict = odict
+
+ def sql_descr(self, remove=None):
+ """Return a string with description of columns.
+ Remove it is used to remove a columns.::
+
+ >>> import sqlite3
+ >>> path = '$GISDBASE/$LOCATION_NAME/$MAPSET/sqlite.db'
+ >>> cols_sqlite = Columns('boundary_municp_sqlite',
+ ... sqlite3.connect(get_path(path)))
+ >>> cols_sqlite.sql_descr() # doctest: +ELLIPSIS
+ u'cat integer, OBJECTID integer, AREA double precision, ...'
+ >>> import psycopg2 as pg
+ >>> cols_pg = Columns('boundary_municp_pg',
+ ... pg.connect('host=localhost dbname=grassdb'))
+ >>> cols_pg.sql_descr() # doctest: +ELLIPSIS
+ 'cat int4, objectid int4, area float8, perimeter float8, ...'
+ """
+ if remove:
+ return ', '.join(['%s %s' % (key, val) for key, val in self.items()
+ if key != remove])
+ else:
+ return ', '.join(['%s %s' % (key, val)
+ for key, val in self.items()])
+
+ def types(self):
+ """Return a list with the column types. ::
+
+ >>> import sqlite3
+ >>> path = '$GISDBASE/$LOCATION_NAME/$MAPSET/sqlite.db'
+ >>> cols_sqlite = Columns('boundary_municp_sqlite',
+ ... sqlite3.connect(get_path(path)))
+ >>> cols_sqlite.types() # doctest: +ELLIPSIS
+ [u'integer', u'integer', ...]
+ >>> import psycopg2 as pg
+ >>> cols_pg = Columns('boundary_municp_pg',
+ ... pg.connect('host=localhost dbname=grassdb'))
+ >>> cols_pg.types() # doctest: +ELLIPSIS
+ ['int4', 'int4', 'float8', 'float8', 'float8', ...]
+
+
+ ..
+ """
+ return self.odict.values()
+
+ def names(self, remove=None, unicod=True):
+ """Return a list with the column names.
+ Remove it is used to remove a columns.::
+
+ >>> import sqlite3
+ >>> path = '$GISDBASE/$LOCATION_NAME/$MAPSET/sqlite.db'
+ >>> cols_sqlite = Columns('boundary_municp_sqlite',
+ ... sqlite3.connect(get_path(path)))
+ >>> cols_sqlite.names() # doctest: +ELLIPSIS
+ [u'cat', u'OBJECTID', u'AREA', u'PERIMETER', ...]
+ >>> import psycopg2 as pg
+ >>> cols_pg = Columns('boundary_municp_pg',
+ ... pg.connect('host=localhost dbname=grassdb'))
+ >>> cols_pg.names() # doctest: +ELLIPSIS
+ ['cat', 'objectid', 'area', 'perimeter', ...]
+
+
+ ..
+ """
+ if remove:
+ nams = self.odict.keys()
+ nams.remove(remove)
+ else:
+ nams = self.odict.keys()
+ if unicod:
+ return nams
+ else:
+ return [str(name) for name in nams]
+
+ def items(self):
+ """Return a list of tuple with column name and column type. ::
+
+ >>> import sqlite3
+ >>> path = '$GISDBASE/$LOCATION_NAME/$MAPSET/sqlite.db'
+ >>> cols_sqlite = Columns('boundary_municp_sqlite',
+ ... sqlite3.connect(get_path(path)))
+ >>> cols_sqlite.items() # doctest: +ELLIPSIS
+ [(u'cat', u'integer'), ...]
+ >>> import psycopg2 as pg
+ >>> cols_pg = Columns('boundary_municp_pg',
+ ... pg.connect('host=localhost dbname=grassdb'))
+ >>> cols_pg.items() # doctest: +ELLIPSIS
+ [('cat', 'int4'), ('objectid', 'int4'), ('area', 'float8'), ...]
+
+ ..
+ """
+ return self.odict.items()
+
+ def add(self, col_name, col_type):
+ """Add a new column to the table. ::
+
+ >>> import sqlite3
+ >>> path = '$GISDBASE/$LOCATION_NAME/$MAPSET/sqlite.db'
+ >>> cols_sqlite = Columns('boundary_municp_sqlite',
+ ... sqlite3.connect(get_path(path)))
+ >>> cols_sqlite.add('n_pizza', 'int4')
+ >>> 'n_pizza' in cols_sqlite
+ True
+
+ >>> import psycopg2 as pg
+ >>> cols_pg = Columns('boundary_municp_pg',
+ ... pg.connect('host=localhost dbname=grassdb'))
+ >>> cols_pg.add('n_pizza', 'int4')
+ >>> 'n_pizza' in cols_pg
+ True
+
+ ..
+ """
+ cur = self.conn.cursor()
+ cur.execute(sql.ADD_COL.format(tname=self.tname,
+ cname=col_name,
+ ctype=col_type))
+ self.conn.commit()
+ cur.close()
+ self.update_odict()
+
+ def rename(self, old_name, new_name):
+ """Rename a column of the table. ::
+
+ >>> import sqlite3
+ >>> path = '$GISDBASE/$LOCATION_NAME/$MAPSET/sqlite.db'
+ >>> cols_sqlite = Columns('boundary_municp_sqlite',
+ ... sqlite3.connect(get_path(path)))
+ >>> cols_sqlite.rename('n_pizza', 'n_pizzas') # doctest: +ELLIPSIS
+ >>> 'n_pizza' in cols_sqlite
+ False
+ >>> 'n_pizzas' in cols_sqlite
+ True
+
+ >>> import psycopg2 as pg
+ >>> cols_pg = Columns('boundary_municp_pg',
+ ... pg.connect('host=localhost dbname=grassdb'))
+ >>> cols_pg.rename('n_pizza', 'n_pizzas')
+ >>> 'n_pizza' in cols_pg
+ False
+ >>> 'n_pizzas' in cols_pg
+ True
+
+ ..
+ """
+ cur = self.conn.cursor()
+ if self.is_pg():
+ cur.execute(sql.RENAME_COL.format(tname=self.tname,
+ old_name=old_name,
+ new_name=new_name))
+ self.conn.commit()
+ cur.close()
+ self.update_odict()
+ else:
+ cur.execute(sql.ADD_COL.format(tname=self.tname,
+ cname=new_name,
+ ctype=str(self.odict[old_name])))
+ cur.execute(sql.UPDATE.format(tname=self.tname,
+ new_col=new_name,
+ old_col=old_name))
+ self.conn.commit()
+ cur.close()
+ self.update_odict()
+ self.drop(old_name)
+
+ def cast(self, col_name, new_type):
+ """Change the column type. ::
+
+ >>> import sqlite3
+ >>> path = '$GISDBASE/$LOCATION_NAME/$MAPSET/sqlite.db'
+ >>> cols_sqlite = Columns('boundary_municp_sqlite',
+ ... sqlite3.connect(get_path(path)))
+ >>> cols_sqlite.cast('n_pizzas', 'float8') # doctest: +ELLIPSIS
+ Traceback (most recent call last):
+ ...
+ DBError: 'SQLite does not support to cast columns.'
+ >>> import psycopg2 as pg
+ >>> cols_pg = Columns('boundary_municp_pg',
+ ... pg.connect('host=localhost dbname=grassdb'))
+ >>> cols_pg.cast('n_pizzas', 'float8')
+ >>> cols_pg['n_pizzas']
+ 'float8'
+
+ .. warning ::
+
+ It is not possible to cast a column with sqlite
+ ..
+ """
+ if self.is_pg():
+ cur = self.conn.cursor()
+ cur.execute(sql.CAST_COL.format(tname=self.tname, col=col_name,
+ ctype=new_type))
+ self.conn.commit()
+ cur.close()
+ self.update_odict()
+ else:
+ # sqlite does not support rename columns:
+ raise DBError('SQLite does not support to cast columns.')
+
+ def drop(self, col_name):
+ """Drop a column from the table. ::
+
+ >>> import sqlite3
+ >>> path = '$GISDBASE/$LOCATION_NAME/$MAPSET/sqlite.db'
+ >>> cols_sqlite = Columns('boundary_municp_sqlite',
+ ... sqlite3.connect(get_path(path)))
+ >>> cols_sqlite.drop('n_pizzas') # doctest: +ELLIPSIS
+ >>> 'n_pizzas' in cols_sqlite
+ False
+
+ >>> import psycopg2 as pg
+ >>> cols_pg = Columns('boundary_municp_pg',
+ ... pg.connect('host=localhost dbname=grassdb'))
+ >>> cols_pg.drop('n_pizzas')
+ >>> 'n_pizzas' in cols_pg
+ False
+
+ ..
+ """
+ cur = self.conn.cursor()
+ if self.is_pg():
+ cur.execute(sql.DROP_COL.format(tname=self.tname,
+ cname=col_name))
+ else:
+ desc = str(self.sql_descr(remove=col_name))
+ names = ', '.join(self.names(remove=col_name, unicod=False))
+ queries = sql.DROP_COL_SQLITE.format(tname=self.tname,
+ keycol=self.key,
+ coldef=desc,
+ colnames=names).split('\n')
+ for query in queries:
+ cur.execute(query)
+ self.conn.commit()
+ cur.close()
+ self.update_odict()
+
+
+class Link(object):
+ """Define a Link between vector map and the attributes table.
+
+ It is possible to define a Link object or given all the information
+ (number, name, table name, key, database, driver): ::
+
+ >>> link = Link(1, 'link0', 'boundary_municp_sqlite', 'cat',
+ ... '$GISDBASE/$LOCATION_NAME/$MAPSET/sqlite.db', 'sqlite')
+ >>> link.number
+ 1
+ >>> link.name
+ 'link0'
+ >>> link.table_name
+ 'boundary_municp_sqlite'
+ >>> link.key
+ 'cat'
+ >>> link.database
+ '$GISDBASE/$LOCATION_NAME/$MAPSET/sqlite.db'
+ >>> link.driver
+ 'sqlite'
+ >>> link
+ Link(1, link0, sqlite)
+
+
+ It is possible to change parameters with: ::
+
+ >>> link.driver = 'pg'
+ >>> link.driver
+ 'pg'
+ >>> link.driver = 'postgres' # doctest: +ELLIPSIS
+ Traceback (most recent call last):
+ ...
+ TypeError: Driver not supported, use: sqlite, pg.
+ >>> link.driver
+ 'pg'
+ >>> link.number = 0 # doctest: +ELLIPSIS
+ Traceback (most recent call last):
+ ...
+ TypeError: Number must be positive and greater than 0.
+
+
+ Or given a c_fieldinfo object that is a ctypes pointer to the field_info C
+ struct. ::
+
+ >>> link = Link(c_fieldinfo = ctypes.pointer(libvect.field_info()))
+
+
+ ..
+ """
+ def _get_number(self):
+ return self.c_fieldinfo.contents.number
+
+ def _set_number(self, number):
+ if number <= 0:
+ raise TypeError("Number must be positive and greater than 0.")
+ self.c_fieldinfo.contents.number = number
+
+ number = property(fget=_get_number, fset=_set_number)
+
+ def _get_name(self):
+ return self.c_fieldinfo.contents.name
+
+ def _set_name(self, name):
+ self.c_fieldinfo.contents.name = name
+
+ name = property(fget=_get_name, fset=_set_name)
+
+ def _get_table(self):
+ return self.c_fieldinfo.contents.table
+
+ def _set_table(self, new_name):
+ self.c_fieldinfo.contents.table = new_name
+
+ table_name = property(fget=_get_table, fset=_set_table)
+
+ def _get_key(self):
+ return self.c_fieldinfo.contents.key
+
+ def _set_key(self, key):
+ self.c_fieldinfo.contents.key = key
+
+ key = property(fget=_get_key, fset=_set_key)
+
+ def _get_database(self):
+ return self.c_fieldinfo.contents.database
+
+ def _set_database(self, database):
+ self.c_fieldinfo.contents.database = database
+
+ database = property(fget=_get_database, fset=_set_database)
+
+ def _get_driver(self):
+ return self.c_fieldinfo.contents.driver
+
+ def _set_driver(self, driver):
+ if driver not in ('sqlite', 'pg'):
+ str_err = "Driver not supported, use: %s." % ", ".join(DRIVERS)
+ raise TypeError(str_err)
+ self.c_fieldinfo.contents.driver = driver
+
+ driver = property(fget=_get_driver, fset=_set_driver)
+
+ def __init__(self, number=None, name=None, table=None, key=None,
+ database=None, driver=None, c_fieldinfo=None):
+ if c_fieldinfo is not None:
+ self.c_fieldinfo = c_fieldinfo
+ else:
+ self.c_fieldinfo = ctypes.pointer(libvect.field_info())
+ self.number = number
+ self.name = name
+ self.table_name = table
+ self.key = key
+ self.database = database
+ self.driver = driver
+
+ def __repr__(self):
+ return "Link(%d, %s, %s)" % (self.number, self.name, self.driver)
+
+ def connection(self):
+ """Return a connection object. ::
+
+ >>> link = Link(1, 'link0', 'boundary_municp_sqlite', 'cat',
+ ... '$GISDBASE/$LOCATION_NAME/$MAPSET/sqlite.db',
+ ... 'sqlite')
+ >>> conn = link.connection()
+ >>> cur = conn.cursor()
+ >>> cur.execute("SELECT cat,COUNTY,PERIMETER FROM %s" %
+ ... link.table_name) # doctest: +ELLIPSIS
+ <sqlite3.Cursor object at ...>
+ >>> cur.fetchone()
+ (1, u'SURRY', 1415.331)
+ >>> cur.close()
+ >>> conn.close()
+
+ ...
+ """
+ if self.driver == 'sqlite':
+ import sqlite3
+ return sqlite3.connect(get_path(self.database))
+ elif self.driver == 'pg':
+ try:
+ import psycopg2
+ db = ' '.join(self.database.split(','))
+ return psycopg2.connect(db)
+ except ImportError:
+ er = "You need to install psycopg2 to connect with this table."
+ raise ImportError(er)
+ else:
+ str_err = "Driver is not supported yet, pleas use: sqlite or pg"
+ raise TypeError(str_err)
+
+ def table(self):
+ """Return a Table object. ::
+
+ >>> link = Link(1, 'link0', 'boundary_municp_sqlite', 'cat',
+ ... '$GISDBASE/$LOCATION_NAME/$MAPSET/sqlite.db',
+ ... 'sqlite')
+ >>> table = link.table()
+ >>> table.filters.select('cat', 'COUNTY', 'PERIMETER')
+ Filters('SELECT cat, COUNTY, PERIMETER FROM boundary_municp_sqlite;')
+ >>> cur = table.execute()
+ >>> cur.fetchone()
+ (1, u'SURRY', 1415.331)
+ >>> cur.close()
+
+ ..
+ """
+ return Table(self.table_name, self.connection(), self.key)
+
+ def info(self):
+ """Print information of the link. ::
+
+ >>> link = Link(1, 'link0', 'boundary_municp_sqlite', 'cat',
+ ... '$GISDBASE/$LOCATION_NAME/$MAPSET/sqlite.db',
+ ... 'sqlite')
+ >>> link.info()
+ number: 1
+ name: link0
+ table: boundary_municp_sqlite
+ key: cat
+ database: $GISDBASE/$LOCATION_NAME/$MAPSET/sqlite.db
+ driver: sqlite
+
+ ..
+ """
+ print "number: ", self.number
+ print "name: ", self.name
+ print "table: ", self.table_name
+ print "key: ", self.key
+ print "database: ", self.database
+ print "driver: ", self.driver
+
+
+class DBlinks(object):
+ """Interface containing link to the table DB. ::
+
+ >>> from pygrass.vector import VectorTopo
+ >>> municip = VectorTopo('boundary_municp_sqlite')
+ >>> municip.open()
+ >>> dblinks = DBlinks(municip.c_mapinfo)
+ >>> dblinks
+ DBlinks([Link(1, boundary_municp, sqlite)])
+ >>> dblinks[1]
+ Link(1, boundary_municp, sqlite)
+ >>> dblinks[0] # doctest: +ELLIPSIS
+ Traceback (most recent call last):
+ ...
+ TypeError: The index must be != 0.
+ >>> dblinks['boundary_municp']
+ Link(1, boundary_municp, sqlite)
+
+ ..
+ """
+ def __init__(self, c_mapinfo):
+ self.c_mapinfo = c_mapinfo
+
+ def __len__(self):
+ return self.num_dblinks()
+
+ def __iter__(self):
+ return (self.by_number(ilink)
+ for ilink in xrange(1, self.num_dblinks() + 1))
+
+ def __getitem__(self, key):
+ """
+
+ """
+ if isinstance(key, int):
+ if key != 0:
+ return self.by_number(key)
+ else:
+ raise TypeError("The index must be != 0.")
+ else:
+ return self.by_name(key)
+
+ def __repr__(self):
+ return "DBlinks(%r)" % [link for link in self.__iter__()]
+
+ def by_number(self, number):
+ c_fieldinfo = libvect.Vect_get_field(self.c_mapinfo, number)
+ return Link(c_fieldinfo=c_fieldinfo)
+
+ def by_name(self, name):
+ c_fieldinfo = libvect.Vect_get_field_by_name(self.c_mapinfo, name)
+ return Link(c_fieldinfo=c_fieldinfo)
+
+ def num_dblinks(self):
+ return libvect.Vect_get_num_dblinks(self.c_mapinfo)
+
+ def add(self, link):
+ """Add a new link. ::
+
+ >>> from pygrass.vector import VectorTopo
+ >>> municip = VectorTopo('boundary_municp_sqlite')
+ >>> municip.open()
+ >>> dblinks = DBlinks(municip.c_mapinfo)
+ >>> dblinks
+ DBlinks([Link(1, boundary_municp, sqlite)])
+ >>> link = Link(2, 'pg_link', 'boundary_municp_pg', 'cat',
+ ... 'host=localhost dbname=grassdb', 'pg')
+ >>> dblinks.add(link)
+ >>> dblinks # need to open vector map in write mode
+ DBlinks([Link(1, boundary_municp, sqlite)])
+
+ ..
+ """
+ #TODO: check if open in write mode or not.
+ libvect.Vect_map_add_dblink(self.c_mapinfo,
+ link.number, link.name, link.table_name,
+ link.key, link.database, link.driver)
+
+ def remove(self, key):
+ """Remove a link. ::
+
+ >>> from pygrass.vector import VectorTopo
+ >>> municip = VectorTopo('boundary_municp_sqlite')
+ >>> municip.open()
+ >>> dblinks = DBlinks(municip.c_mapinfo)
+ >>> dblinks
+ DBlinks([Link(1, boundary_municp, sqlite)])
+ >>> dblinks.remove('pg_link')
+ >>> dblinks # need to open vector map in write mode
+ DBlinks([Link(1, boundary_municp, sqlite)])
+
+ ..
+ """
+ if isinstance(key, str):
+ key = self.from_name_to_num(key)
+ libvect.Vect_map_del_dblink(self.c_mapinfo, key)
+
+ def from_name_to_num(self, name):
+ """
+ Vect_get_field_number
+ """
+ return libvect.Vect_get_field_number(self.c_mapinfo, name)
+
+
+class Table(object):
+ """::
+
+ >>> import sqlite3
+ >>> path = '$GISDBASE/$LOCATION_NAME/$MAPSET/sqlite.db'
+ >>> tab_sqlite = Table(name='boundary_municp_sqlite',
+ ... connection=sqlite3.connect(get_path(path)))
+ >>> tab_sqlite.name
+ 'boundary_municp_sqlite'
+ >>> import psycopg2
+ >>> tab_pg = Table('boundary_municp_pg',
+ ... psycopg2.connect('host=localhost dbname=grassdb',
+ ... 'pg'))
+ >>> tab_pg.columns # doctest: +ELLIPSIS
+ Columns([('cat', 'int4'), ...])
+
+ ..
+ """
+ def _get_name(self):
+ return self._name
+
+ def _set_name(self, new_name):
+ old_name = self._name
+ cur = self.conn.cursor()
+ cur.execute(sql.RENAME_TAB.format(old_name=old_name,
+ new_name=new_name))
+ cur.commit()
+ cur.close()
+
+ name = property(fget=_get_name, fset=_set_name)
+
+ def __init__(self, name, connection, key='cat'):
+ self._name = name
+ self.conn = connection
+ self.key = key
+ self.columns = Columns(self.name,
+ self.conn,
+ self.key)
+ self.filters = Filters(self.name)
+
+ def __repr__(self):
+ """::
+
+ >>> import sqlite3
+ >>> path = '$GISDBASE/$LOCATION_NAME/$MAPSET/sqlite.db'
+ >>> tab_sqlite = Table(name='boundary_municp_sqlite',
+ ... connection=sqlite3.connect(get_path(path)))
+ >>> tab_sqlite
+ Table('boundary_municp_sqlite')
+
+ ..
+ """
+ return "Table(%r)" % (self.name)
+
+ def __iter__(self):
+ cur = self.execute()
+ return (cur.fetchone() for _ in xrange(self.__len__()))
+
+ def __len__(self):
+ """Return the nuber of rows"""
+ return self.num_rows()
+
+ def num_rows(self):
+ cur = self.conn.cursor()
+ cur.execute(sql.SELECT.format(cols='Count(*)', tname=self.name))
+ number = cur.fetchone()[0]
+ cur.close()
+ return number
+
+ def execute(self, sql_code=None):
+ """Execute SQL code from a given string or build with filters and
+ return a cursor object. ::
+
+ >>> import sqlite3
+ >>> path = '$GISDBASE/$LOCATION_NAME/$MAPSET/sqlite.db'
+ >>> tab_sqlite = Table(name='boundary_municp_sqlite',
+ ... connection=sqlite3.connect(get_path(path)))
+ >>> tab_sqlite.filters.select('cat', 'COUNTY').order_by('AREA')
+ Filters('SELECT cat, COUNTY FROM boundary_municp_sqlite ORDER BY AREA;')
+ >>> cur = tab_sqlite.execute()
+ >>> cur.fetchone()
+ (1, u'SURRY')
+
+ ..
+ """
+ if sql_code is not None:
+ cur = self.conn.cursor()
+ return cur.execute(sql_code)
+
+ # get the sql from filters
+ sql_code = self.filters.get_sql()
+ if sql_code is not None:
+ cur = self.conn.cursor()
+ return cur.execute(sql_code)
\ No newline at end of file
Added: grass/trunk/lib/python/pygrass/vector/vector_type.py
===================================================================
--- grass/trunk/lib/python/pygrass/vector/vector_type.py (rev 0)
+++ grass/trunk/lib/python/pygrass/vector/vector_type.py 2012-10-10 12:24:32 UTC (rev 53350)
@@ -0,0 +1,32 @@
+# -*- coding: utf-8 -*-
+"""
+Created on Wed Jul 18 10:49:26 2012
+
+ at author: pietro
+"""
+
+import grass.lib.vector as libvect
+import geometry as geo
+
+MAPTYPE = {libvect.GV_FORMAT_NATIVE: "native",
+ libvect.GV_FORMAT_OGR: "OGR",
+ libvect.GV_FORMAT_OGR_DIRECT: "OGR",
+ libvect.GV_FORMAT_POSTGIS: "PostGIS"}
+
+VTYPE = {'point': libvect.GV_POINT, # 1
+ 'line': libvect.GV_LINE, # 2
+ 'boundary': libvect.GV_BOUNDARY, # 3
+ 'centroid': libvect.GV_CENTROID, # 4
+ 'face': libvect.GV_FACE, # 5
+ 'kernel': libvect.GV_KERNEL, # 6
+ 'area': libvect.GV_AREA, # 7
+ 'volume': libvect.GV_VOLUME} # 8
+
+GV_TYPE = {libvect.GV_POINT: {'label': 'point', 'obj': geo.Point},
+ libvect.GV_LINE: {'label': 'line', 'obj': geo.Line},
+ libvect.GV_BOUNDARY: {'label': 'boundary', 'obj': geo.Boundary},
+ libvect.GV_CENTROID: {'label': 'centroid', 'obj': geo.Centroid},
+ libvect.GV_FACE: {'label': 'face', 'obj': None},
+ libvect.GV_KERNEL: {'label': 'kernel', 'obj': None},
+ libvect.GV_AREA: {'label': 'area', 'obj': geo.Area},
+ libvect.GV_VOLUME: {'label': 'volume', 'obj': None}, }
\ No newline at end of file
More information about the grass-commit
mailing list