addons-contrib: objects.link/unlink syntax update
[blender-addons-contrib.git] / io_points_pcd / pcd_utils.py
1 # ##### BEGIN GPL LICENSE BLOCK #####
2 #
3 #  This program is free software; you can redistribute it and/or
4 #  modify it under the terms of the GNU General Public License
5 #  as published by the Free Software Foundation; either version 2
6 #  of the License, or (at your option) any later version.
7 #
8 #  This program is distributed in the hope that it will be useful,
9 #  but WITHOUT ANY WARRANTY; without even the implied warranty of
10 #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 #  GNU General Public License for more details.
12 #
13 #  You should have received a copy of the GNU General Public License
14 #  along with this program; if not, write to the Free Software Foundation,
15 #  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 #
17 # ##### END GPL LICENSE BLOCK #####
18
19 import bpy
20
21 import os
22 import subprocess
23 import tempfile
24
25 from . import pcdparser
26
27
28 def create_and_link_mesh(name, points):
29     """
30     Create a blender mesh and object called name from a list of
31     *points* and link it in the current scene.
32     """
33
34     mesh = bpy.data.meshes.new(name)
35     mesh.from_pydata(points, [], [])
36
37     # update mesh to allow proper display
38     mesh.validate()
39     mesh.update()
40
41     obj = bpy.data.objects.new(name, mesh)
42     bpy.context.collection.objects.link(obj)
43     obj.select_set(True)
44
45
46 def import_pcd(filepath, name="new_pointcloud"):
47     # check if the file is binary compressed
48     parser = pcdparser.PCDParser.factory(filepath, pcdparser.PointXYZ)
49     parser.onlyParseHeader()
50     is_binary_compressed = parser.datatype == 'BINARY_COMPRESSED'
51
52     # create a temp uncompressed pcd file
53     if (is_binary_compressed):
54         tmpdir = tempfile.TemporaryDirectory()
55         tmpfilepath = tmpdir.name + "blender_pcd_io_tmp.pcd"
56         try:
57             subprocess.call(["pcl_convert_pcd_ascii_binary", filepath, tmpfilepath, "1"])
58         except FileNotFoundError:
59             print("[ERROR] Can't read BINARY COMPRESSED PCD. No pcl_convert_pcd_ascii_binary found! Have you installed libPCL?")
60             return
61         filepath = tmpfilepath
62
63
64     # do actual parsing
65     parser = pcdparser.PCDParser.factory(filepath, pcdparser.PointXYZ)
66     parser.parseFile()
67     points = parser.getPoints()
68
69     blender_points = []
70     for point in points:
71         blender_points.append((point.x, point.y, point.z))
72
73     create_and_link_mesh(name, blender_points)
74
75
76 def export_pcd(filepath):
77     obj = bpy.context.active_object
78
79     # apply object transformation and modifiers
80     mesh = obj.to_mesh(bpy.context.scene, True, "PREVIEW")
81     objmat = obj.matrix_world
82
83     points = []
84     for vert in mesh.vertices:
85         co = objmat * vert.co
86         point = pcdparser.PointXYZ()
87         point.x = co.x
88         point.y = co.y
89         point.z = co.z
90         points.append(point)
91
92     writer = pcdparser.PCDWriter(points)
93     writer.write(filepath)