Skip to content

Commit 3ff2af2

Browse files
committed
new version of from_scan with reverse raytrace
1 parent bde27d0 commit 3ff2af2

File tree

2 files changed

+84
-10
lines changed

2 files changed

+84
-10
lines changed

CMap2D.pyx

Lines changed: 83 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -138,15 +138,15 @@ cdef class CMap2D:
138138
# self._thresh_occupied # TODO
139139
# self.thresh_free
140140

141-
def from_scan(self, scan, resolution=0.05, limits=None, inscribed_radius=None):
141+
def from_scan(self, scan, resolution=0.05, limits=None, inscribed_radius=None, legacy=True):
142142
""" Creating a map from a scan places the x y origin in the center of the grid,
143143
and generates the occupancy field from the laser data.
144144
limits are in lidar frame (meters) [[xmin, xmax], [ymin, ymax]]
145145
"""
146146
angles = np.arange(scan.angle_min,
147147
scan.angle_max + scan.angle_increment,
148-
scan.angle_increment)[:len(scan.ranges)]
149-
ranges = np.array(scan.ranges)
148+
scan.angle_increment, dtype=np.float32)[:len(scan.ranges)]
149+
ranges = np.array(scan.ranges, dtype=np.float32)
150150
if inscribed_radius is not None:
151151
ranges[ranges < inscribed_radius] = np.inf
152152
xy_hits = (ranges * np.array([np.cos(angles), np.sin(angles)])).T
@@ -165,12 +165,18 @@ cdef class CMap2D:
165165
self.resolution_ = resolution
166166
self._thresh_occupied = 0.9
167167
self.thresh_free = 0.1
168-
ij_hits = self.xy_to_ij(xy_hits, clip_if_outside=False)
169-
is_inside = self.is_inside_ij(ij_hits.astype(np.float32))
170-
ij_hits = ij_hits[np.where(is_inside)]
171-
occupancy = 0.05 * np.ones((width, height), dtype=np.float32)
172-
occupancy[tuple(ij_hits.T)] = 0.95
173-
self._occupancy = occupancy
168+
if legacy:
169+
ij_hits = self.xy_to_ij(xy_hits, clip_if_outside=False)
170+
is_inside = self.is_inside_ij(ij_hits.astype(np.float32))
171+
ij_hits = ij_hits[np.where(is_inside)]
172+
occupancy = 0.05 * np.ones((width, height), dtype=np.float32)
173+
occupancy[tuple(ij_hits.T)] = 0.95
174+
self._occupancy = occupancy
175+
else:
176+
observer_ij = self.xy_to_ij(np.array([[0, 0]]))[0]
177+
occupancy = np.ones((width, height), dtype=np.float32) * 0.5
178+
self.creverse_raytrace_lidar(np.array(observer_ij).astype(np.int64), angles, ranges, occupancy)
179+
self._occupancy = occupancy
174180
# ij_laser_orig = (-self.origin / self.resolution_).astype(int)
175181
# compiled_reverse_raytrace(ij_hits, ij_laser_orig, self.occupancy_) # TODO
176182

@@ -1564,6 +1570,74 @@ cdef class CMap2D:
15641570
if r > max_r:
15651571
break
15661572

1573+
@cython.boundscheck(False)
1574+
@cython.wraparound(False)
1575+
@cython.nonecheck(False)
1576+
@cython.cdivision(True)
1577+
cdef creverse_raytrace_lidar(self, np.int64_t[::1] observer_ij,
1578+
np.float32_t[::1] angles, np.float32_t[::1] ranges,
1579+
np.float32_t[:, ::1] result):
1580+
cdef np.int64_t o_i = observer_ij[0]
1581+
cdef np.int64_t o_j = observer_ij[1]
1582+
cdef np.float32_t threshold = self._thresh_occupied
1583+
cdef np.int64_t shape0 = self.occupancy_shape0
1584+
cdef np.int64_t shape1 = self.occupancy_shape1
1585+
cdef np.float32_t i_inc_unit
1586+
cdef np.float32_t j_inc_unit
1587+
cdef np.float32_t i_abs_inc
1588+
cdef np.float32_t j_abs_inc
1589+
cdef np.float32_t raystretch
1590+
cdef np.int64_t max_inc
1591+
cdef np.int64_t max_i_inc
1592+
cdef np.int64_t max_j_inc
1593+
cdef np.float32_t i_inc
1594+
cdef np.float32_t j_inc
1595+
cdef np.float32_t n_i
1596+
cdef np.float32_t n_j
1597+
cdef np.int64_t in_i
1598+
cdef np.int64_t in_j
1599+
cdef np.float32_t occ
1600+
cdef np.int64_t di
1601+
cdef np.int64_t dj
1602+
cdef np.float32_t r
1603+
cdef np.float32_t max_r
1604+
cdef np.uint8_t is_hit
1605+
for i in range(len(angles)):
1606+
angle = angles[i]
1607+
max_r = ranges[i] / self.resolution_
1608+
i_inc_unit = ccos(angle)
1609+
j_inc_unit = csin(angle)
1610+
# Stretch the ray so that every 1 unit in the ray direction lands on a cell in i or
1611+
i_abs_inc = abs(i_inc_unit)
1612+
j_abs_inc = abs(j_inc_unit)
1613+
raystretch = 1. / i_abs_inc if i_abs_inc >= j_abs_inc else 1. / j_abs_inc
1614+
i_inc = i_inc_unit * raystretch
1615+
j_inc = j_inc_unit * raystretch
1616+
# max amount of increments before crossing the grid border
1617+
if i_inc == 0:
1618+
max_inc = <np.int64_t>((shape1 - 1 - o_j) / j_inc) if j_inc >= 0 else <np.int64_t>(o_j / -j_inc)
1619+
elif j_inc == 0:
1620+
max_inc = <np.int64_t>((shape0 - 1 - o_i) / i_inc) if i_inc >= 0 else <np.int64_t>(o_i / -i_inc)
1621+
else:
1622+
max_i_inc = <np.int64_t>((shape1 - 1 - o_j) / j_inc) if j_inc >= 0 else <np.int64_t>(o_j / -j_inc)
1623+
max_j_inc = <np.int64_t>((shape0 - 1 - o_i) / i_inc) if i_inc >= 0 else <np.int64_t>(o_i / -i_inc)
1624+
max_inc = max_i_inc if max_i_inc <= max_j_inc else max_j_inc
1625+
# Trace a ray
1626+
n_i = o_i + 0
1627+
n_j = o_j + 0
1628+
for n in range(1, max_inc-1):
1629+
n_i += i_inc
1630+
n_j += j_inc
1631+
in_i = <np.int64_t>n_i
1632+
in_j = <np.int64_t>n_j
1633+
di = ( in_i - o_i )
1634+
dj = ( in_j - o_j )
1635+
r = sqrt(di*di + dj*dj)
1636+
result[in_i, in_j] = 0.
1637+
if r >= max_r:
1638+
result[in_i, in_j] = 1.
1639+
break
1640+
15671641
cdef craymarch(self, np.int64_t[::1] observer_ij, np.int64_t[::1] angles, np.float32_t[::1] ranges):
15681642
cdef np.int64_t o_i = observer_ij[0]
15691643
cdef np.int64_t o_j = observer_ij[1]

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
long_description=long_description,
1313
long_description_content_type='text/markdown',
1414
url="https://github.com/danieldugas/pymap2d",
15-
version='0.1.14',
15+
version='0.1.15',
1616
py_modules=['map2d', 'pose2d', 'circular_index', 'map2d_ros_tools'],
1717
ext_modules=cythonize("CMap2D.pyx", annotate=True),
1818
install_requires=['pyyaml', 'numpy'],

0 commit comments

Comments
 (0)