3
from liblas import file as lasfile
4
from liblas import header
5
from liblas import point
14
import cx_Oracle as oci
16
# big-endian DOUBLE, DOUBLE, DOUBLE, LONG, LONG
18
ptsize = struct.calcsize(format)
21
class Translator(object):
23
def construct_parser(self):
24
from optparse import OptionParser, OptionGroup
25
usage = "usage: %prog [options] arg"
26
parser = OptionParser(usage)
27
g = OptionGroup(parser, "Base options", "Basic Translation Options")
28
g.add_option("-c", "--connection", dest="connection",
29
help="OCI connection string", metavar="CONNECTION")
30
g.add_option("-o", "--output", dest='output',
31
help="LAS file to write", metavar="OUTPUT")
32
g.add_option("-s", "--sql", dest='sql',
33
help="SQL to select the point cloud ", metavar="SQL")
34
g.add_option("-l", "--column", dest='column',
35
help="Column name containing the point cloud object ", metavar="COLUMN")
37
g.add_option("-p", "--precision", dest='precision',
38
help="Numeric precision (# of digits) to maintain for the output file ", metavar="PRECISION")
40
g.add_option("-r", "--srs", dest='srs',
41
help="Coordinate system override", metavar="SRS")
43
g.add_option("-w", "--overwrite",
44
action="store_true", dest="overwrite",
45
help="overwrite the existing file")
47
g.add_option("-m", "--min-offset",
48
action="store_true", dest="offset", default=False,
49
help="Use the minimum values as base for offset")
51
g.add_option("-q", "--quiet",
52
action="store_false", dest="verbose", default=False,
53
help="Don't say what we're doing on stdout")
55
g.add_option("--compressed", action="store_true", dest="compressed",
58
parser.add_option_group(g)
61
g = OptionGroup(parser, "Special Options", "Special options")
64
parser.add_option_group(g)
66
parser.set_defaults(verbose=True, precision = 6)
70
def __init__(self, arguments, options=None):
71
self.connection = None
76
self.construct_parser()
77
self.options, self.args = self.parser.parse_args(args=arguments)
80
self.options.connection = self.args[0]
82
if not self.options.output:
84
self.options.output = self.args[1]
86
self.options.output = 'output.las'
88
if not self.options.sql:
90
self.options.sql = self.args[2]
92
raise self.parser.error("No SQL was provided to select the point cloud!")
94
if self.options.output:
95
self.options.output = os.path.abspath(self.options.output)
96
if os.path.isdir(self.options.output):
97
raise self.parser.error("Output '%s' is a directory, not a file " % self.options.output)
99
if os.path.exists(self.options.output):
100
if not self.options.overwrite:
101
raise self.parser.error("Output file '%s' exists, but you have not selected the --overwrite option" % self.options.output)
103
raise self.parser.error("No output was specified")
106
self.options.precision = int(self.options.precision)
107
if not self.options.precision:
108
raise self.parser.error("Precision cannot be 0")
110
raise self.parser.error("Precision was not an number")
119
self.first_point = True
120
self.cloud_column = True
126
self.srs.set_userinput(self.options.srs)
127
print 'setting srs to %s' %self.srs.proj4
131
def print_options(self):
135
self.con = oci.Connection(self.options.connection)
137
def is_block_table(self, cursor_description):
139
names = [ 'OBJ_ID','BLK_ID','BLK_EXTENT','BLK_DOMAIN',
140
'PCBLK_MIN_RES','PCBLK_MAX_RES','NUM_POINTS',
141
'NUM_UNSORTED_POINTS','PT_SORT_DIM','POINTS']
142
for name in cursor_description:
143
if name.upper() not in names:
147
def write_points(self, num_points, blob):
148
# print 'writing block...', num_points
151
for i in xrange(num_points):
153
p.header = self.header
154
self.points.append(p)
155
if (num_points > len(self.points)):
156
for i in xrange(num_points-len(self.points)):
158
p.header = self.header
159
self.points.append(p)
161
for i in xrange(num_points):
162
rng = ptsize*i,ptsize*(i+1)
163
d = struct.unpack(format,blob[ptsize*i:ptsize*(i+1)])
164
x, y, z, time, classification, blk_id, pt_id = d
166
p.x = x; p.y = y; p.z = z
167
p.classification = int(classification)
177
self.first_point = False
179
# cumulate min/max for the header
180
self.minx = min(self.minx, p.x)
181
self.maxx = max(self.maxx, p.x)
183
self.miny = min(self.miny, p.y)
184
self.maxy = max(self.maxy, p.y)
186
self.minz = min(self.minz, p.z)
187
self.maxz = max(self.maxz, p.z)
193
def summarize_files(self):
196
def open_output(self):
197
self.header = header.Header()
199
prec = 10**-(self.options.precision-1)
200
self.header.scale = [prec, prec, prec]
202
if self.options.offset:
203
h.offset = [self.minx, self.miny, self.minz]
204
if self.options.verbose:
205
print 'using minimum offsets', h.offset
207
self.header.compressed = self.options.compressed
210
self.header.srs = self.srs
212
self.header.data_format_id = 1
213
output = lasfile.File(self.options.output,mode='w',header=self.header)
217
def rewrite_header(self):
219
self.output = lasfile.File(self.options.output)
220
h = self.output.header
222
h.min = [self.minx, self.miny, self.minz]
223
h.max = [self.maxx, self.maxy, self.maxz]
225
rc = h.point_return_count
227
h.point_return_count = rc
229
self.output = lasfile.File(self.options.output, mode='w+', header=h)
232
def get_srid(self, srid):
233
cur = self.con.cursor()
234
if not srid: return ''
235
cur.execute('SELECT WKTEXT,WKTEXT3D from MDSYS.CS_SRS where srid=%d'%(int(srid)))
251
self.cur = self.con.cursor()
252
# self.cur.execute(self.options.sql)
255
# res = self.cur.fetchall()
260
# column.BASE_TABLE_COL
261
# clouds.append(column)
262
# except AttributeError:
263
# # This column isn't a cloud
268
# write an actual cloud column
269
# for cloud in clouds:
270
# cur2 = self.con.cursor()
272
# cur2.execute('SELECT NUM_POINTS, POINTS, BLK_EXTENT FROM %s'% cloud.BLK_TABLE)
275
# for num_points, blob, extent in cur2:
276
# # set the SRS from the first geometry
278
# self.srs = self.get_srid(extent.SDO_SRID)
281
# points.append(self.get_points(num_points,b))
283
# num_pts_index, blob_index = self.get_block_indexes(self.cur)
285
# if we don't have a cloud object, we'll assume that NUM_POINTS and
286
# the POINTS blob exist in our already queried cursor
289
print 'have srs?: %s' % bool(self.srs)
291
self.output = self.open_output()
294
cur = self.cur.execute(self.options.sql)
295
num_pts_index, blob_index = self.get_block_indexes(cur)
297
num_points = row[num_pts_index]
298
blob = row[blob_index].read()
299
self.write_points(num_points, blob)
305
self.srs = self.get_srid(col.SDO_SRID)
307
except AttributeError:
310
# if we still haven't been able to set an SRS, don't try
316
self.rewrite_header()
318
def get_block_indexes(self, cursor):
323
for name in cursor.description:
325
if name.upper() == 'POINTS':
327
if name.upper() == 'NUM_POINTS':
330
return (num_pts_index, blob_index)
336
# o = optparse.make_option("-r", "--remainder", dest="remainder",
337
# type="choice",default='end',
338
# help="""what to do with the remainder -- place it at the beginning,
339
# place it at the end, or evenly distribute it across the segment""",
340
# choices=['end','begin','uniform'])
343
d = Translator(sys.argv[1:], options=options)
346
if __name__=='__main__':