#!BPY """ Name: 'PostGIS' Blender: 245 Group: 'Export' Tooltip: 'Export to PostGIS' """ __author__ = "kyk" __url__ = "http://luxla.net" __version__ = "1.0" import Blender, bpy, psycopg2, struct from Blender import * WKBNDR = '\x01' WKBPOINT = 1 WKBLINESTRING = 2 WKBPOLYGON = 3 WKBMULTIPOINT = 4 WKBMULTILINESTRING = 5 WKBMULTIPOLYGON = 6 WKBGEOMETRYCOLLECTION = 7 def writePointStream( verts, indices = None, dim = 2): if not indices: indices = range(len(verts)) if dim == 3: return ''.join( struct.pack('<3d', verts[i].co.x, verts[i].co.y, verts[i].co.z) for i in indices ) else: return ''.join( struct.pack('<2d', verts[i].co.x, verts[i].co.y) for i in indices ) def writeWkbPoint( mesh, dim = 2, vertexIndex = 0 ): print 'Write Point' return struct.pack('<1c1L', WKBNDR, WKBPOINT) + writePointStream( [mesh.verts[vertexIndex]], None, dim ) def writeWkbMultiPoint( mesh, dim = 2 ): print 'Write MultiPoint' result = struct.pack('<1c2L', WKBNDR, WKBMULTIPOINT, len(mesh.verts)) for index in range(mesh.verts): result += writeWkbPoint( mesh, dim, index ) return result def buildEdgeBuffer( mesh ): buf = {} for edge in mesh.edges: ed1, ed2 = edge.key if ed1 not in buf: buf[ed1] = ed2 elif ed2 not in buf: buf[ed2] = ed1 elif buf[ed1] == ed2: pass return buf def buildIndex( buf ): def internalBuildIndex( indices, cdict ): while len(cdict): if indices[-1] not in cdict: return indices, cdict indices.append( cdict.pop(indices[-1] )) return indices, cdict result = list(buf.popitem()) result, buf = internalBuildIndex( result, buf ) if len(buf): buf = dict( (val, key) for key, val in buf.iteritems() ) result, buf = internalBuildIndex( result, buf ) return result, buf def writeWkbLineString( mesh, dim = 2 ): print 'Write LineString' indices, buf = buildIndex( buildEdgeBuffer(mesh) ) result = struct.pack('<1c2L', WKBNDR, WKBLINESTRING, len(indices)) print indices result += writePointStream( mesh.verts, indices, dim ) return result def writeWkbMultiLineString( mesh, dim = 2 ): print 'Write MultiLineString' result, numlinestring = '', 0 buf = buildEdgeBuffer( mesh ) while len(buf): indices, buf = buildIndex(buf) resutl += struct.pack('<1c2L', WKBNDR, WKBLINESTRING, len(indices)) result += writePointStream( mesh.verts, indices, dim ) numlinestring += 1 return struct.pack('<1c2L', WKBNDR, WKBMULTILINESTRING, numlinestring) + result def inInnerBound( b1, b2 ): if b1[0] < b2[0] and b1[1] < b2[1] and b1[2] > b2[2] and b1[3] > b2[3]: return 1 if b1[0] == b2[0] and b1[1] == b2[1] and b1[2] == b2[2] and b1[3] == b2[3]: return 0 return -1 def buildBoundingBox( mesh, indices ): fv = mesh.verts[indices[0]] result =[ fv.co.x, fv.co.y, fv.co.x, fv.co.y ] for i in indices[1:]: co = mesh.verts[i].co result[0] = min(result[0], co.x) result[1] = min(result[1], co.y) result[2] = max(result[2], co.x) result[3] = max(result[3], co.y) return result def writeWkbPolygon( mesh, dim = 2 ): print 'Write Polygon' buf = buildEdgeBuffer( mesh ) rings = [] while len(buf): indices, buf = buildIndex(buf) rings.append(indices) bounds = [buildBoundingBox(mesh, id) + [i] for i, id in enumerate(rings)] bounds.sort(inInnerBound) result = struct.pack('<1c2L', WKBNDR, WKBPOLYGON, len(rings)) for bound in bounds: ring = rings[bound[-1]] result += struct.pack('<1L', len(ring)) + writePointStream( mesh.verts, ring, dim ) return result registed = Registry.GetKey("PostGISExport",1) or dict() inikeys = ["host","dbname","user","password","table", "geometry"] defaultValue = ['localhost', 'postgis', '', '', 1, 1] uiDict = dict( (k, Draw.Create(registed.setdefault( k,v))) for k, v in zip(inikeys,defaultValue) ) pgConnection = None geomTables = None GeometryWriter = { WKBPOINT : writeWkbPoint, WKBLINESTRING : writeWkbLineString, WKBPOLYGON : writeWkbPolygon, WKBMULTIPOINT : writeWkbMultiPoint, WKBMULTILINESTRING :writeWkbMultiLineString, WKBMULTIPOLYGON : None, WKBGEOMETRYCOLLECTION : None } def draw(): global pgConnection, uiDict, geomTables GeometryMap = { 'Point' : 1, 'LineString' : 2, 'Polygon' : 3, 'MultiPoint' : 4, 'MultiLineString' : 5, 'MultiPolygon' : 6 } if pgConnection == None: uiDict['host'] = Draw.String('Host: ', 0, 20, 200, 200, 30, uiDict['host'].val, 256) uiDict['dbname'] = Draw.String('Database: ', 0, 20, 160, 200, 30, uiDict['dbname'].val, 256) uiDict['user'] = Draw.String('User: ', 0, 20, 120, 200, 30, uiDict['user'].val, 256) uiDict['password'] = Draw.String('Password: ', 0, 20, 80, 200, 30, uiDict['password'].val, 256) Draw.PushButton('Connect', 1, 20, 40, 200, 30) else: if geomTables == None: geomTables = {} cursor = pgConnection.cursor() cursor.execute('SELECT f_table_name, f_geometry_column, coord_dimension, type FROM geometry_columns') geomcol = cursor.fetchone() while geomcol: geomTables[geomcol[0]] = geomcol geomcol = cursor.fetchone() cursor.close() menuOptions = 'Choose Table %t|' menuOptions += '|'.join( [tn + ' %x' + str(i+1) for i, tn in enumerate(geomTables.keys())] ) uiDict['table'] = Draw.Menu(menuOptions, 0, 20, 200, 200, 30, uiDict['table'].val) geomOptions = 'Choose GeometryType %t|' geomOptions += '|'.join( [gn + ' %x' + str(i) for gn, i in GeometryMap.iteritems()]) uiDict['geometry'] = Draw.Menu(geomOptions, 0, 20, 160, 200, 30, uiDict['geometry'].val) Draw.PushButton('Insert', 2, 20, 40, 200, 30) scn = bpy.data.scenes.active obj = scn.objects.active me = obj.getData( mesh = 1 ) if me and len(me.edges) and not len(me.faces): Draw.PushButton('Line Test', 10, 20, 250, 200, 30) def event(ev): global pgConnection, uiDict, geomTables, GeometryWriter if ev == 1: try: pgConnection = psycopg2.connect("dbname=%s host=%s user=%s password=%s" % ( uiDict['dbname'], uiDict['host'], uiDict['user'], uiDict['password'] )) except Exception, err: print err Draw.Redraw() elif ev == 2: scn = bpy.data.scenes.active obj = scn.objects.active me = obj.getData( mesh = 1 ) if not me or not len(me.verts) or len(me.faces):return geomType = uiDict['geometry'].val if not GeometryWriter[geomType] :return if geomType not in [1,4] and not len(me.edges):return the_geom = psycopg2.Binary(GeometryWriter[geomType](me)) geomcol = geomTables[geomTables.keys()[uiDict['table'].val-1]] cursor = pgConnection.cursor() query = 'INSERT INTO "%s" (%s) VALUES(GeomFromWKB(%s))' % (geomcol[0], geomcol[1], '%s') cursor.execute(query, (the_geom,)) pgConnection.commit() Draw.Redraw() elif ev == 10: scn = bpy.data.scenes.active obj = scn.objects.active me = obj.getData( mesh = 1 ) try: buf = buildEdgeBuffer( me ) numlinestring = 0 while len(buf): indices, buf = buildIndex(buf) me.verts[indices[0]].co.z = 10 me.verts[indices[-1]].co.z = 10 numlinestring += 1 print numlinestring except Exception, err: print err Draw.Register(draw, lambda e,v: e == Draw.ESCKEY and not v and Draw.Exit() , event)