-
Notifications
You must be signed in to change notification settings - Fork 14
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #42 from eEcoLiDAR/branch_plywriter_30
Branch plywriter 30
- Loading branch information
Showing
5 changed files
with
223 additions
and
22 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,3 @@ | ||
point = 'vertex' | ||
point_cloud = 'pointcloud' | ||
provenance = 'log' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,80 @@ | ||
from laserchicken.keys import point | ||
from laserchicken.keys import * | ||
import numpy as np | ||
import datetime as dt | ||
|
||
|
||
def generate_test_point_cloud(): | ||
pc = {point: {'x': {'type': 'double', 'data': [1, 2, 3]}, 'y': {'type': 'double', 'data': [2, 3, 4]}, | ||
'z': {'type': 'double', 'data': [3, 4, 5]}}} | ||
return pc | ||
class SimpleTestData(object): | ||
""" Test data within this class should all be in sync (reflect the same data).""" | ||
@staticmethod | ||
def get_point_cloud(): | ||
# This simple_test_point cloud and the simple_test_header should be in sync. Some tests depend on it. | ||
pc = {point: {'x': {'type': 'float', 'data': np.array([1, 2, 3])}, | ||
'y': {'type': 'float', 'data': np.array([20, 30, 40])}, | ||
'z': {'type': 'float', 'data': np.array([300, 400, 500])}}} | ||
return pc | ||
|
||
@staticmethod | ||
def get_header(): | ||
# This simple_test_header cloud and the simple_test_point should be in sync. Some tests depend on it. | ||
header = """ply | ||
format ascii 1.0 | ||
element vertex 3 | ||
property float x | ||
property float y | ||
property float z | ||
""" | ||
return header | ||
|
||
@staticmethod | ||
def get_data(): | ||
data = """1 20 300 | ||
2 30 400 | ||
3 40 500 | ||
""" | ||
return data | ||
|
||
|
||
class ComplexTestData(object): | ||
""" Test data within this class should all be in sync (reflect the same data).""" | ||
@staticmethod | ||
def get_point_cloud(): | ||
# This complex_test_point cloud and the complex_test_header should be in sync. Some tests depend on it. | ||
pc = {point: {'x': {'type': 'float', 'data': np.array([1, 2, 3, 4, 5])}, | ||
'y': {'type': 'float', 'data': np.array([2, 3, 4, 5, 6])}, | ||
'z': {'type': 'float', 'data': np.array([3, 4, 5, 6, 7])}, | ||
'return': {'type': 'int', 'data': np.array([1, 1, 2, 2, 1])} | ||
}, | ||
point_cloud: {'offset': {'type': 'double', 'data': 12.1}}, | ||
provenance: [{'time': (dt.datetime(2018, 1, 18, 16, 1, 0)), 'module': 'filter'}] | ||
} | ||
return pc | ||
|
||
@staticmethod | ||
def get_header(): | ||
# This complex_test_header cloud and the complex_test_point should be in sync. Some tests depend on it. | ||
comment = {"time": dt.datetime(2018, 1, 18, 16, 1, 0), "module": "filter"} | ||
header = """ply | ||
format ascii 1.0 | ||
comment [ | ||
comment %s | ||
comment ] | ||
element vertex 5 | ||
property float x | ||
property float y | ||
property float z | ||
property int return | ||
element pointcloud 1 | ||
property double offset | ||
""" % str(comment) | ||
return header | ||
|
||
@staticmethod | ||
def get_data(): | ||
data = """1 2 3 1 | ||
2 3 4 1 | ||
3 4 5 2 | ||
4 5 6 2 | ||
5 6 7 1 | ||
12.1 | ||
""" | ||
return data |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,82 @@ | ||
import os | ||
import numpy as np | ||
|
||
from laserchicken import keys | ||
|
||
# Writes the pointcloud data structure to a ply-file | ||
def write(pc, path): | ||
pass | ||
if os.path.exists(path): | ||
# Raise most specific subclass of FileExistsError (3.6) and IOError (2.7). | ||
raise Exception('Cannot write because path {} already exists.'.format(path)) | ||
with open(path, 'w') as ply: | ||
write_header(pc,ply) | ||
write_data(pc,ply) | ||
|
||
# Writes the ply-header | ||
def write_header(pc,ply): | ||
ply.write("ply" + '\n') | ||
ply.write("format ascii 1.0" + '\n') | ||
write_comment(pc,ply) | ||
for elem_name in get_ordered_elems(pc.keys()): | ||
get_num_elems = (lambda d: len(d["x"].get("data",[]))) if elem_name == keys.point else None | ||
write_elements(pc,ply,elem_name,get_num_elems = get_num_elems) | ||
ply.write("end_header" + '\n') | ||
|
||
# Writes the ply-data | ||
def write_data(pc,ply): | ||
delim = ' ' | ||
for elem_name in get_ordered_elems(pc.keys()): | ||
props = get_ordered_props(elem_name,pc[elem_name].keys()) | ||
num_elems = len(pc[elem_name]["x"].get("data",[])) if elem_name == keys.point else 1 | ||
for i in range(num_elems): | ||
for prop in props: | ||
datavalues = pc[elem_name][prop]["data"] | ||
if(isinstance(datavalues,np.ndarray)): | ||
if(prop == props[-1]): | ||
ply.write(formatply(datavalues[i])) | ||
else: | ||
ply.write(formatply(datavalues[i]) + delim) | ||
else: | ||
if(i != 0): | ||
raise Exception("Scalar quantity does not have element at index %d" % i) | ||
ply.write(formatply(datavalues)) | ||
ply.write('\n') | ||
|
||
# Formatting helper function | ||
def formatply(obj): | ||
return str(obj) | ||
|
||
# Defines the element ordering | ||
def get_ordered_elems(elem_names): | ||
if(keys.point in elem_names): | ||
return [keys.point] + sorted([e for e in elem_names if e not in [keys.point,keys.provenance]]) | ||
else: | ||
return sorted([e for e in elem_names if e not in [keys.point,keys.provenance]]) | ||
|
||
# Defines the property ordering for a given element | ||
def get_ordered_props(elem_name,prop_list): | ||
if(elem_name == keys.point): | ||
return ['x','y','z'] + [k for k in sorted(prop_list) if k not in ['x','y','z']] | ||
else: | ||
return sorted(prop_list) | ||
|
||
# Writes the comment | ||
# TODO: Use json for this | ||
def write_comment(pc,ply): | ||
log = pc.get(keys.provenance,[]) | ||
if(any(log)): | ||
ply.write("comment [" + '\n') | ||
for msg in log: | ||
ply.write("comment " + str(msg) + '\n') | ||
ply.write("comment ]" + '\n') | ||
|
||
# Writes elements for the header | ||
def write_elements(pc,ply,elem_name,get_num_elems = None): | ||
if(elem_name in pc): | ||
num_elems = get_num_elems(pc[elem_name]) if get_num_elems else 1 | ||
ply.write("element %s %d\n" % (elem_name,num_elems)) | ||
keylist = get_ordered_props(elem_name,pc[elem_name].keys()) | ||
for key in keylist: | ||
property_type = pc[elem_name][key]["type"] | ||
property_tuple = ("property",property_type,key) | ||
ply.write(" ".join(property_tuple) + '\n') |