Salut,<br><br>Je viens de tester : <br><br>steven@nausicaa:~/Desktop/test$ python polyshp2osm.py bati.shp <br>An error occurred: <br>Extent does not look like degrees; are you sure it is? <br>(90237.0400028, 103885.840002, 90380.4899998, 104008.340002)<br>
<br><br>C'est peut être ma source qui n'est pas compatible... je la joins en copie si tu veux essayer.<br><br>Je suppose que la projection n'est pas bonne ici ?<br><br><br><br><div class="gmail_quote">2009/6/20 Emilie Laffray <span dir="ltr"><<a href="mailto:emilie.laffray@gmail.com">emilie.laffray@gmail.com</a>></span><br>
<blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">Bonjour,<br>
<br>
je suis en train de partiellement réécrire le fichier polyshp2osm.py<br>
afin d'ajouter de nouvelles fonctionnalités. Cette version s'appuie sur<br>
ma version tres legerement modifiee intialement. Je n'ai pas fini de<br>
coder certains elements qui sont mineurs, mais le plus important<br>
fonctionne maintenant. Puisque je m'en sers pour Corine, je pense donner<br>
un avant gout a la communaute francaise pour que les gens puissent<br>
experimenter un peu avec s'ils veulent.<br>
Les améliorations sont les suivantes:<br>
-   Support de OSM 0.6<br>
-   Meilleur support des advanced polygons: les ways trop longues sont<br>
maintenant coupées en différentes ways, et une relation est créée si<br>
besoin est<br>
-   Code partiellement factorisé et commenté<br>
<br>
Il reste a ajouter les choses suivantes:<br>
-   Factoriser le code car certaines parties sont redondantes<br>
-   Nettoyer le code et lui enlever les parties superflues (le nom du<br>
fichier sera change pour ne pas creer de confusion avec les<br>
fonctionnalités actuelles, qui me semblent d'ailleurs inutiles)<br>
-   Changer la boucle principale afin que chaque ways coupées aient ses<br>
nodes avant au lieu d'avoir tous les nodes avant la série des ways coupées<br>
-   Documenter le code encore plus<br>
<br>
Je pense finir demain le code. Celui-ci permettra une meilleure gestion<br>
de l'import Corine. Cela enlève une étape (la conversion en format de<br>
fichier 0.6 par Osmose). La prochaine version après celle ci ajoutera le<br>
support multi-polygone.<br>
<font color="#888888"><br>
Emilie Laffray<br>
</font><br>#!/usr/bin/python<br>
<br>
"""<br>
This script is designed to act as assistance in converting shapefiles<br>
to OpenStreetMap data. This file is optimized and tested with MassGIS<br>
shapefiles, converted to EPSG:4326 before being passed to the script.<br>
You can perform this conversion with<br>
<br>
   ogr2ogr -t_srs EPSG:4326 new_file.shp old_file.shp<br>
<br>
It is expected that you will modify the fixed_tags, tag_mapping, and<br>
boring_tags attributes of this script before running. You should read,<br>
or at least skim, the code up until it says:<br>
<br>
  DO NOT CHANGE AFTER THIS LINE.<br>
<br>
to accomodate your own data.<br>
"""<br>
<br>
__author__ = "Christopher Schmidt <<a href="mailto:crschmidt@crschmidt.net">crschmidt@crschmidt.net</a>>"<br>
__version__ = "$Id$"<br>
<br>
gdal_install = """<br>
Installing GDAL depends on your platform. Information is available at:<br>
<br>
   <a href="http://trac.osgeo.org/gdal/wiki/DownloadingGdalBinaries" target="_blank">http://trac.osgeo.org/gdal/wiki/DownloadingGdalBinaries</a><br>
<br>
For Debian-based systems:<br>
<br>
   apt-get install python-gdal<br>
<br>
will usually suffice.<br>
"""<br>
<br>
import time<br>
<br>
# These tags are attached to all exterior ways. You can put any key/value pairs<br>
# in this dictionary.<br>
<br>
fixed_tags = {}<br>
<br>
# Here are a number of functions: These functions define tag mappings. The API<br>
# For these functions is that they are passed the attributes from a feature,<br>
# and they return a list of two-tuples which match to key/value pairs.<br>
<br>
def access(data):<br>
    """Access restrictions."""<br>
    keys = {<br>
        'Y': 'yes',<br>
        'N': 'private',<br>
        'L': 'restricted'<br>
    }<br>
    if 'pub_access' in data:<br>
        if data['pub_access'] in keys:<br>
            return [('access', keys[data['pub_access']])]<br>
    return None<br>
<br>
def protection(data):<br>
    keys = {<br>
        'P': 'perpetuity',<br>
        'T': 'temporary',<br>
        'L': 'limited',<br>
    }<br>
    if 'lev_prot' in data:<br>
        if data['lev_prot'] in keys:<br>
            return [('protected', keys[data['lev_prot']])]<br>
    return None<br>
<br>
def owner_type(data):<br>
    """See wiki:Key:ownership"""<br>
    keys = {<br>
        'F': 'national',<br>
        'S': 'state',<br>
        'C': 'county',<br>
        'M': 'municipal',<br>
        'N': 'private_nonprofit',<br>
        'P': 'private',<br>
        'B': 'public_nonprofit',<br>
        'L': 'land_trust',<br>
        'G': 'conservation_rganization',<br>
        'I': 'inholding',<br>
    }<br>
    if 'owner_type' in data:<br>
        if data['owner_type'] in keys:<br>
            return [['ownership', keys[data['owner_type']]]]<br>
<br>
def purpose(data):<br>
    """Based on a discussion on IRC"""<br>
    keys = {<br>
        'R': [('leisure', 'recreation_ground')],<br>
        'C': [('leisure', 'nature_reserve'), ('landuse', 'conservation')],<br>
        'B': [('landuse','conservation'), ('leisure','recreation_ground')],<br>
        'H': [('historical', 'yes')],<br>
        'A': [('agricultural', 'yes'), ('landuse','farm')],<br>
        'W': [('landuse', 'resevoir')],<br>
        'S': [('scenic','yes')],<br>
        'F': [('landuse','land')],<br>
        'Q': [('landuse','conservation')],<br>
        'U': [('water','yes')]<br>
    }<br>
    if 'prim_purp' in data:<br>
        if data['prim_purp'] in keys:<br>
            return keys[data['prim_purp']]<br>
<br>
def name_tags(data):<br>
    """This function returns two things: a 'pretty' name to use, and<br>
       may return a landuse of either 'cemetery' or 'forest' if the name<br>
       contains those words; based on evaluation the dataset in question."""<br>
    tags = []<br>
    name = data.get('site_name', None)<br>
    if not name:<br>
        return<br>
    name = name.title()<br>
<br>
    if "cemetery" in name.lower():<br>
        tags.append(['landuse', 'cemetery'])<br>
    elif "forest" in name.lower():<br>
        tags.append(['landuse', 'forest'])<br>
<br>
    tags.append(['name', name])<br>
    return tags<br>
<br>
def cal_date(data):<br>
    """Return YYYY-MM-DD or YYYY formatted dates, based on<br>
       (m)m/(d)d/yyyy dates"""<br>
    date = data.get('cal_date_r', None)<br>
    if not date: return<br>
    try:<br>
        m, d, y = map(int, date.split("/"))<br>
        if m == 1 and d == 1:<br>
            return [['start_date', '%4i' % y]]<br>
        return [['start_date', '%04i-%02i-%02i' % (y, m, d)]]<br>
    except:<br>
        print "Invalid date: %s" % date<br>
        return None<br>
<br>
# The most important part of the code: define a set of key/value pairs<br>
# to iterate over to generate keys. This is a list of two-tuples: first<br>
# is a 'key', which is only used if the second value is a string. In<br>
# that case, it is a map of lowercased fielnames to OSM tag names: so<br>
# fee_owner maps to 'owner' in the OSM output.<br>
<br>
# if the latter is callable (has a __call__; is a function), then that<br>
# method is called, passing in a dict of feature attributes with<br>
# lowercased key names. Those functions can then return a list of<br>
# two-tuples to be used as tags, or nothin' to skip the tags.<br>
<br>
<br>
tag_mapping = [<br>
    ('fee_owner', 'owner'),<br>
    ('cal_date', cal_date),<br>
    ('pub_access', access),<br>
    ('lev_prot', protection),<br>
    ('owner_type', owner_type),<br>
    ('prim_purp', purpose),<br>
    ('site_name', name_tags),<br>
]<br>
<br>
# These tags are not exported, even with the source data; this should be<br>
# used for tags which are usually calculated in a GIS. AREA and LEN are<br>
# common.<br>
<br>
boring_tags = [ 'AREA', 'LEN', 'GIS_ACRES' ]<br>
<br>
# Namespace is used to prefix existing data attributes. If 'None', or<br>
# '--no-source' is set, then source attributes are not exported, only<br>
# attributes in tag_mapping.<br>
<br>
namespace = "massgis"<br>
#namespace = None<br>
<br>
# Uncomment the "DONT_RUN = False" line to get started.<br>
<br>
DONT_RUN = True<br>
DONT_RUN = False<br>
<br>
# =========== DO NOT CHANGE AFTER THIS LINE. ===========================<br>
# Below here is regular code, part of the file. This is not designed to<br>
# be modified by users.<br>
# ======================================================================<br>
<br>
import sys<br>
<br>
try:<br>
    try:<br>
        from osgeo import ogr<br>
    except ImportError:<br>
        import ogr<br>
except ImportError:<br>
    __doc__ += gdal_install<br>
    if DONT_RUN:<br>
        print __doc__<br>
        sys.exit(2)<br>
    print "OGR Python Bindings not installed.\n%s" % gdal_install<br>
    sys.exit(1)<br>
<br>
def close_file():<br>
    """ Internal. Close an open file."""<br>
    global open_file<br>
    if not open_file.closed:<br>
        open_file.write("</osm>")<br>
        open_file.close()<br>
<br>
def start_new_file():<br>
    """ Internal. Open a new file, closing existing file if neccesary."""<br>
    global open_file, file_counter<br>
    file_counter += 1<br>
    if open_file:<br>
        close_file()<br>
    open_file = open("%s.%s.osm" % (file_name, file_counter), "w")<br>
    print >>open_file, "<?xml version='1.0' encoding='UTF-8'?>"<br>
    print >>open_file, "<osm version='0.6' generator=\"polyshp2osm\">"<br>
<br>
def clean_attr(val):<br>
    """Internal. Hacky way to make attribute XML safe."""<br>
    val = str(val)<br>
    val = val.replace("&", "&amp;").replace("'", "&quot;").replace("<", "&lt;").replace(">", "&gt;").strip()<br>

    return val<br>
<br>
def add_ring_nodes(ring):<br>
    """Internal. Write the first ring nodes."""<br>
    global open_file, id_counter<br>
    ids = []<br>
    if range(ring.GetPointCount() - 1) == 0 or ring.GetPointCount() == 0:<br>
        print >>sys.stderr, "Degenerate ring."<br>
        return<br>
    for count in range(ring.GetPointCount()-1):<br>
        ids.append(id_counter)<br>
        print >>open_file, "<node id='-%s' version=\"1\" timestamp=\"%s\" lon='%s' lat='%s' />" % (id_counter, timestamp, ring.GetX(count), ring.GetY(count)) #print count<br>

        id_counter += 1<br>
    return ids<br>
<br>
def add_ring_way(ring):<br>
        """Internal. write out the 'holes' in a polygon."""<br>
        global open_file, id_counter<br>
<br>
        ids = []<br>
        for count in range(ring.GetPointCount()-1):<br>
                ids.append(id_counter)<br>
                print >>open_file, "<node id='-%s' version=\"1\" timestamp=\"%s\" lon='%s' lat='%s' />" % (id_counter, timestamp, ring.GetX(count), ring.GetY(count)) #print count<br>

                id_counter += 1<br>
        if len(ids) == 0:<br>
                return None<br>
<br>
        # We are now writing the way<br>
        print >>open_file, "<way id='-%s' version=\"1\" timestamp=\"%s\">" % (id_counter, timestamp)<br>
        way_id = id_counter<br>
        id_counter += 1<br>
<br>
        nodeCounter = 0<br>
        for i in ids:<br>
                print >>open_file, "<nd ref='-%s' />" % i<br>
<br>
                # This code will break long ways into multiple ways<br>
                if (nodeCounter > 0) and ((nodeCounter % 2000) == 0):<br>
                        # We are closing the current way<br>
                        print >>open_file, "</way>"<br>
<br>
                        # We are now opening the new way<br>
                        print >>open_file, "<way id='-%s' version=\"1\" timestamp=\"%s\">" % (id_counter, timestamp)<br>
                        ways.append(id_counter)<br>
                        id_counter += 1<br>
<br>
                        # We are readding the same node to make sure it is jointive<br>
                        print >>open_file, "<nd ref='-%s' />" % i<br>
<br>
                nodeCounter += 1<br>
<br>
        print >>open_file, "<nd ref='-%s' />" % ids[0]<br>
        print >>open_file, "</way>"<br>
<br>
        return way_id<br>
<br>
def add_tags(f):<br>
        """Internal. Write the tags"""<br>
        global open_file, id_counter,namespace<br>
<br>
        # We are now reading the fields<br>
        field_count = f.GetFieldCount()<br>
        fields  = {}<br>
        for field in range(field_count):<br>
                value = f.GetFieldAsString(field)<br>
                name = f.GetFieldDefnRef(field).GetName()<br>
                if name and value and name not in boring_tags:<br>
                        print >>open_file, "<tag k='%s' v='%s' />" % (name, clean_attr(value))<br>
                fields[name.lower()] = value<br>
<br>
        tags={}<br>
        for tag_name, map_value in tag_mapping:<br>
                if hasattr(map_value, '__call__'):<br>
                        tag_values = map_value(fields)<br>
                        if tag_values:<br>
                                for tag in tag_values:<br>
                                        tags[tag[0]] = tag[1]<br>
                else:<br>
                        if tag_name in fields:<br>
                                tags[map_value] = fields[tag_name].title()<br>
<br>
        for key, value in tags.items():<br>
                if key and value:<br>
                        print >>open_file, "<tag k='%s' v='%s' />" % (key, clean_attr(value))<br>
<br>
        for name, value in fixed_tags.items():<br>
                print >>open_file, "<tag k='%s' v='%s' />" % (name, clean_attr(value))<br>
<br>
# We are initializing the variables that we need<br>
open_file = None<br>
file_name = None<br>
id_counter = 1<br>
file_counter = 0<br>
counter = 0<br>
<br>
# We are creating a timestamp value<br>
timestamp = time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime())<br>
<br>
class AppError(Exception): pass<br>
<br>
def run(filename, slice_count=1, obj_count=50000, output_location=None, no_source=False):<br>
        """Run the converter. Requires open_file, file_name, id_counter,<br>
        file_counter, counter to be defined in global space; not really a very good<br>
        singleton."""<br>
        global id_counter, file_counter, counter, file_name, open_file, namespace<br>
<br>
        if no_source:<br>
                namespace=None<br>
<br>
        if output_location:<br>
                file_name = output_location<br>
<br>
        ds = ogr.Open(filename)<br>
        if not ds:<br>
                raise AppError("OGR Could not open the file %s" % filename)<br>
        l = ds.GetLayer(0)<br>
<br>
        max_objs_per_file = obj_count<br>
<br>
        extent = l.GetExtent()<br>
        if extent[0] < -180 or extent[0] > 180 or extent[2] < -90 or extent[2] > 90:<br>
                raise AppError("Extent does not look like degrees; are you sure it is? \n(%s, %s, %s, %s)" % (extent[0], extent[2], extent[1], extent[3]))<br>
        slice_width = (extent[1] - extent[0]) / slice_count<br>
<br>
        seen = {}<br>
<br>
        print "Running %s slices with %s base filename against shapefile %s" % (slice_count, file_name, filename)<br>
<br>
        for i in range(slice_count):<br>
<br>
                l.ResetReading()<br>
                l.SetSpatialFilterRect(extent[0] + slice_width * i, extent[2], extent[0] + (slice_width * (i + 1)), extent[3])<br>
<br>
                start_new_file()<br>
                f = l.GetNextFeature()<br>
<br>
                obj_counter = 0<br>
                last_obj_split = 0<br>
<br>
                while f:<br>
                        start_id_counter = id_counter<br>
                        if f.GetFID() in seen:<br>
                                f = l.GetNextFeature()<br>
                                continue<br>
<br>
                        seen[f.GetFID()] = True<br>
<br>
                        if (obj_counter - last_obj_split) > max_objs_per_file:<br>
                                print "Splitting file with %s objs" % (obj_counter - last_obj_split)<br>
                                start_new_file()<br>
                                last_obj_split = obj_counter<br>
<br>
                        ways = []<br>
<br>
                        geom = f.GetGeometryRef()<br>
                        numberGeometry = geom.GetGeometryCount()<br>
                        ring = geom.GetGeometryRef(0)<br>
                        numberOuter = 1<br>
<br>
                        # We are writing the nodes to the file<br>
                        ids = add_ring_nodes(ring)<br>
<br>
                        # If we have no nodes in the geometry, we just get the next structure<br>
                        if not ids or len(ids) == 0:<br>
                                f = l.GetNextFeature()<br>
                                continue<br>
<br>
                        # We are creating the way now<br>
                        print >>open_file, "<way id='-%s' version=\"1\" timestamp=\"%s\">" % (id_counter, timestamp)<br>
                        ways.append(id_counter)<br>
                        id_counter += 1<br>
<br>
                        # We are now writing the nodes of the way<br>
                        nodeCounter = 0<br>
                        for i in ids:<br>
                                print >>open_file, "<nd ref='-%s' />" % i<br>
<br>
                                # This code will break long ways into multiple ways<br>
                                if (nodeCounter > 0) and ((nodeCounter % 2000) == 0):<br>
                                        # We are closing the current way<br>
                                        print >>open_file, "</way>"<br>
<br>
                                        # We are now opening the new way<br>
                                        print >>open_file, "<way id='-%s' version=\"1\" timestamp=\"%s\">" % (id_counter, timestamp)<br>
                                        ways.append(id_counter)<br>
                                        id_counter += 1<br>
<br>
                                        # We are readding the same node to make sure it is jointive<br>
                                        print >>open_file, "<nd ref='-%s' />" % i<br>
<br>
                                        # We are indicating we have an extra inner<br>
                                        # and that we have a geometry that requires a relation<br>
                                        numberOuter += 1<br>
                                        numberGeometry += 1<br>
<br>
                                nodeCounter += 1<br>
<br>
                        # To make sure that we are closing properly the polygon we are adding the first point<br>
                        print >>open_file, "<nd ref='-%s' />" % ids[0]<br>
<br>
                        # We are writing the tags if we have only a simple structure<br>
                        if numberGeometry == 1:<br>
                                add_tags(f)<br>
<br>
                        # We close the way<br>
                        print >>open_file, "</way>"<br>
<br>
                        # We are now writing the relations if we have a complex polygon<br>
                        if numberGeometry > 1:<br>
                                # We are writing first the inner ways<br>
                                for i in range(1, geom.GetGeometryCount()):<br>
                                        ways.append(add_ring_way(geom.GetGeometryRef(i)))<br>
<br>
                                # We are now writing the relation<br>
                                print >>open_file, "<relation id='-%s' version=\"1\" timestamp=\"%s\">" % (id_counter, timestamp)<br>
                                id_counter += 1<br>
<br>
                                # We are now printing the inner ways<br>
                                for wayPosition in range(numberOuter):<br>
                                        print >>open_file, '<member type="way" ref="-%s" role="outer" />' % ways[wayPosition]<br>
<br>
                                # We are now printing the outer ways<br>
                                for way in ways[numberOuter:]:<br>
                                    print >>open_file, '<member type="way" ref="-%s" role="inner" />' % way<br>
<br>
                                # We are adding the tags on the relation<br>
                                add_tags(f)<br>
                                print >>open_file, "<tag k='type' v='multipolygon' />"<br>
                                print >>open_file, "</relation>"<br>
<br>
                        counter += 1<br>
                        f = l.GetNextFeature()<br>
                        obj_counter += (id_counter - start_id_counter)<br>
<br>
        close_file()<br>
<br>
if __name__ == "__main__":<br>
    if DONT_RUN:<br>
        print __doc__<br>
        sys.exit(2)<br>
<br>
    from optparse import OptionParser<br>
<br>
    parse = OptionParser(usage="%prog [args] filename.shp", version=__version__)<br>
    parse.add_option("-s", "--slice-count", dest="slice_count",<br>
                     help="Number of horizontal slices of data", default=1,<br>
                     action="store", type="int")<br>
    parse.add_option("-o", "--obj-count",<br>
                     dest="obj_count",<br>
                     help="Target Maximum number of objects in a single .osm file",<br>
                     default=50000, type="int")<br>
    parse.add_option("-n", "--no-source", dest="no_source",<br>
                     help="Do not store source attributes as tags.",<br>
                     action="store_true", default=False)<br>
    parse.add_option("-l", "--output-location",<br>
                        dest="output_location", help="base filepath for output files.",<br>
                        default="poly_output")<br>
    (options, args) = parse.parse_args()<br>
<br>
    if not len(args):<br>
        print "No shapefile name given!"<br>
        parse.print_help()<br>
        sys.exit(3)<br>
<br>
    kw = {}<br>
    for key in  ('slice_count', 'obj_count', 'output_location', 'no_source'):<br>
        kw[key] = getattr(options, key)<br>
<br>
    try:<br>
        run(args[0], **kw)<br>
    except AppError, E:<br>
        print "An error occurred: \n%s" % E<br>
<br>_______________________________________________<br>
Talk-fr mailing list<br>
<a href="mailto:Talk-fr@openstreetmap.org">Talk-fr@openstreetmap.org</a><br>
<a href="http://lists.openstreetmap.org/listinfo/talk-fr" target="_blank">http://lists.openstreetmap.org/listinfo/talk-fr</a><br>
<br></blockquote></div><br><br clear="all"><br>-- <br>Steven Le Roux<br>Jabber-ID : <a href="mailto:Steven@jabber.fr">Steven@jabber.fr</a><br>0x39494CCB <<a href="mailto:steven@le-roux.info">steven@le-roux.info</a>><br>
2FF7 226B 552E 4709 03F0  6281 72D7 A010 3949 4CCB<br>