Skip to content

Commit 52925e4

Browse files
arkosestepjam
authored andcommitted
Octree support (#91)
* Octree function wrappers in sim.py * Wrote the Octree frontend. * Some changes suggested by stepjam. For pyrep/objects/octree.py: Parameter Type Annotations Added. RuntimeError -> ValueError. camelCase -> snake_case. Did not add type annotations to the pyrep/backend/sim.py octree functions as none of the other backend functions have them. * Added tests for octrees. * Added clear_voxels() method to octrees.
1 parent 40e598e commit 52925e4

File tree

4 files changed

+222
-0
lines changed

4 files changed

+222
-0
lines changed

pyrep/backend/sim.py

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1151,3 +1151,63 @@ def simGetUserParameter(objectHandle, parameterName):
11511151
val = ffi.string((parameterValue[0][:parameterLength[0]])).decode('utf-8')
11521152
simReleaseBuffer(ffi.cast('char *', parameterValue))
11531153
return val
1154+
1155+
def simCreateOctree(voxelSize, options, pointSize):
1156+
ret = lib.simCreateOctree(voxelSize, options, pointSize, ffi.NULL)
1157+
_check_return(ret)
1158+
return ret
1159+
1160+
def simInsertVoxelsIntoOctree(octreeHandle, options, points, color, tag):
1161+
if color is None:
1162+
color = ffi.NULL
1163+
if tag is None:
1164+
tag = ffi.NULL
1165+
ret = lib.simInsertVoxelsIntoOctree(octreeHandle, options, points,
1166+
len(points)//3, color, tag, ffi.NULL)
1167+
_check_return(ret)
1168+
return ret
1169+
1170+
def simRemoveVoxelsFromOctree(octreeHandle, options, points):
1171+
if points is None:
1172+
points = ffi.NULL
1173+
if points is ffi.NULL:
1174+
pointCount = 0
1175+
else:
1176+
pointCount = len(points)//3
1177+
ret = lib.simRemoveVoxelsFromOctree(octreeHandle, options, points,
1178+
pointCount, ffi.NULL)
1179+
_check_return(ret)
1180+
return ret
1181+
1182+
def simGetOctreeVoxels(octreeHandle):
1183+
pointCountPointer = ffi.new('int *')
1184+
ret = lib.simGetOctreeVoxels(octreeHandle, pointCountPointer, ffi.NULL)
1185+
if ret == ffi.NULL:
1186+
return []
1187+
pointCount = pointCountPointer[0]
1188+
return list(ret[0:pointCount*3])
1189+
1190+
def simInsertObjectIntoOctree(octreeHandle, objectHandle, options,
1191+
color, tag):
1192+
if color is None:
1193+
color = ffi.NULL
1194+
ret = lib.simInsertObjectIntoOctree(octreeHandle, objectHandle, options,
1195+
color, tag, ffi.NULL)
1196+
_check_return(ret)
1197+
return ret
1198+
1199+
def simSubtractObjectFromOctree(octreeHandle, objectHandle, options):
1200+
ret = lib.simSubtractObjectFromOctree(octreeHandle, objectHandle, options,
1201+
ffi.NULL)
1202+
_check_return(ret)
1203+
return ret
1204+
1205+
def simCheckOctreePointOccupancy(octreeHandle, options, points):
1206+
ret = lib.simCheckOctreePointOccupancy(octreeHandle, options, points,
1207+
len(points)//3, ffi.NULL, ffi.NULL,
1208+
ffi.NULL)
1209+
_check_return(ret)
1210+
if ret == 1:
1211+
return True
1212+
else:
1213+
return False

pyrep/objects/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,4 @@
66
# from pyrep.objects.proximity_sensor import ProximitySensor
77
# from pyrep.objects.shape import Shape
88
# from pyrep.objects.vision_sensor import VisionSensor
9+
# from pyrep.objects.octree import Octree

pyrep/objects/octree.py

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
from pyrep.objects.object import Object
2+
from pyrep.const import ObjectType
3+
from pyrep.backend import sim
4+
from typing import List, Optional
5+
6+
class Octree(Object):
7+
"""An octree object."""
8+
9+
@staticmethod
10+
def create(voxel_size: float, point_size: Optional[float] = None,
11+
options: int = 0) -> 'Octree':
12+
"""Creates an octree object and inserts in the scene.
13+
14+
:param voxelSize: The resolution of octree voxels.
15+
:param options: Octree options.
16+
:param pointSize: Point representation size of voxels.
17+
:return: The newly created Octree.
18+
"""
19+
if point_size is None:
20+
point_size = voxel_size
21+
handle = sim.simCreateOctree(voxel_size, options, point_size)
22+
return Octree(handle)
23+
24+
def _get_requested_type(self) -> ObjectType:
25+
return ObjectType.OCTREE
26+
27+
def insert_voxels(self, points: List[float], color: Optional[float] = None,
28+
options: int = 0) -> None:
29+
"""Inserts voxels into the octree.
30+
31+
:param points: A list of x,y,z numbers.
32+
:param color: A list containing RGB data, or None.
33+
:param options: Voxel insertion options.
34+
"""
35+
if not isinstance(points, list):
36+
raise ValueError(
37+
'Octree.insert_voxels: points parameter is not a list.')
38+
if len(points) % 3 is not 0:
39+
raise ValueError(
40+
'Octree.insert_voxels: points parameter length '
41+
'not a multiple of 3.')
42+
if color is not None:
43+
if not isinstance(color, list):
44+
raise ValueError(
45+
'Octree.insert_voxels: color parameter not a list.')
46+
elif len(color) is not 3:
47+
raise ValueError(
48+
'Octree.insert_voxels: color parameter not an RGB list.')
49+
sim.simInsertVoxelsIntoOctree(self._handle, options, points, color,None)
50+
return
51+
52+
def remove_voxels(self, points : Optional[List[float]],
53+
options: int = 0) -> None:
54+
"""Remove voxels from the octree.
55+
56+
:param points: A list of x,y,z numbers, or None to clear the octree.
57+
:param options: Voxel removal options.
58+
"""
59+
if points is not None:
60+
if not isinstance(points, list):
61+
raise ValueError(
62+
'Octree.insert_voxels: points parameter is not a list.')
63+
if len(points) % 3 is not 0:
64+
raise ValueError(
65+
'Octree.insert_voxels: points parameter length '
66+
'not a multiple of 3.')
67+
sim.simRemoveVoxelsFromOctree(self._handle, options, points)
68+
69+
def get_voxels(self) -> list:
70+
"""Returns voxels from the octree.
71+
72+
:return: List of voxel x,y,z coordinates.
73+
"""
74+
return sim.simGetOctreeVoxels(self._handle)
75+
76+
def insert_object(self, obj: Object, color: Optional[float] = None,
77+
options: int = 0) -> None:
78+
"""Inserts object into the octree.
79+
80+
:param obj: Object to insert.
81+
:param color: A list containing RGB data, or None.
82+
:param options: Object insertion options.
83+
"""
84+
if color is not None:
85+
if not isinstance(color, list):
86+
raise ValueError(
87+
'Octree.insert_object: color parameter not a list.')
88+
elif len(color) is not 3:
89+
raise ValueError(
90+
'Octree.insert_object: color parameter not an RGB list.')
91+
sim.simInsertObjectIntoOctree(self._handle, obj.get_handle(), options,
92+
color, 0)
93+
return
94+
95+
def subtract_object(self, obj: Object, options: int = 0) -> None:
96+
"""Subtract object from the octree.
97+
98+
:param obj: Object to subtract.
99+
:param options: Object subtraction options.
100+
"""
101+
sim.simSubtractObjectFromOctree(self._handle, obj.get_handle(), options)
102+
return
103+
104+
def check_point_occupancy(self, points: List[float],
105+
options: int = 0) -> bool:
106+
if not isinstance(points, list):
107+
raise ValueError(
108+
'Octree.check_point_occupancy: points parameter is not a list.')
109+
if len(points) % 3 is not 0:
110+
raise ValueError(
111+
'Octree._check_point_occupancy: points parameter length '
112+
'not a multiple of 3.')
113+
return sim.simCheckOctreePointOccupancy(self._handle, options, points)
114+
115+
def clear_voxels(self) -> None:
116+
"""Clears all voxels from the octree.
117+
"""
118+
sim.simRemoveVoxelsFromOctree(self._handle, 0, None)

tests/test_octrees.py

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import unittest
2+
3+
from pyrep.const import ObjectType
4+
5+
from tests.core import TestCore
6+
from pyrep.objects.object import Object
7+
from pyrep.objects.shape import Shape
8+
from pyrep.objects.octree import Octree
9+
10+
class TestOctrees(TestCore):
11+
12+
def setUp(self):
13+
super().setUp()
14+
self.octree = Octree.create(0.025)
15+
self.shape = Shape('Panda_link0_visual')
16+
17+
def test_octree_insert_and_remove_voxels(self):
18+
point = [0.0, 0.0, 0.0]
19+
self.octree.insert_voxels(point)
20+
voxels = self.octree.get_voxels()
21+
# As many as 8 voxels may be added from a single point insertion.
22+
self.assertTrue(1 <= len(voxels)//3 and len(voxels)/3 <= 8)
23+
self.assertTrue(self.octree.check_point_occupancy(point))
24+
self.octree.remove_voxels(point)
25+
voxels = self.octree.get_voxels()
26+
self.assertTrue(len(voxels)//3 is 0)
27+
self.assertFalse(self.octree.check_point_occupancy(point))
28+
29+
def test_octree_insert_and_subtract_object(self):
30+
self.octree.insert_object(self.shape)
31+
voxels = self.octree.get_voxels()
32+
self.assertTrue(1 <= len(voxels)//3)
33+
self.octree.subtract_object(self.shape)
34+
voxels = self.octree.get_voxels()
35+
self.assertTrue(len(voxels)//3 is 0)
36+
37+
def test_octree_insert_and_clear(self):
38+
self.octree.insert_object(self.shape)
39+
voxels = self.octree.get_voxels()
40+
self.assertTrue(1 <= len(voxels)//3)
41+
self.octree.clear_voxels()
42+
voxels = self.octree.get_voxels()
43+
self.assertTrue(len(voxels)//3 is 0)

0 commit comments

Comments
 (0)