Data-SpatialHash-Shared
view release on metacpan or search on metacpan
"new_memfd" creates a Linux memfd (anonymous but transferable via
"memfd" file descriptor). "new_from_fd" reopens an existing memfd in
another process.
Mutators
my $h = $s->insert(x, y, value); # 2D insert -- returns handle or undef
my $h = $s->insert(x, y, z, value); # 3D insert
my $h = $s->insert(x, y, z, value, r); # 3D insert with an interaction radius
$s->set_radius($h, $r); # set/replace an entry's radius
$s->move($h, x, y); # relocate entry (2D)
$s->move($h, x, y, z); # relocate entry (3D)
$s->remove($h); # free entry slot
$s->set_value($h, $v); # update stored value
$s->clear; # remove all entries
my @ids = $s->insert_many([ [x,y,value], [x,y,value,r], ... ]); # bulk insert
my $n = $s->move_many([ [handle,x,y], [handle,x,y,z], ... ]); # bulk move
"insert" returns a handle (opaque integer) on success, or "undef" if
"max_entries" is exhausted. "move" and "remove" return true on success,
or false if the handle is invalid or already removed. "set_value"
instead croaks on an invalid or freed handle; it and "clear" return
eg/moving_entities.pl view on Meta::CPAN
my (%h, %pos, @vel); # id => handle / [x,y] / [vx,vy]
for my $id (1 .. $N) {
my @p = (rand()*$WORLD, rand()*$WORLD);
$h{$id} = $s->insert(@p, $id);
$pos{$id} = [@p];
$vel[$id] = [ (rand()*2-1)*2, (rand()*2-1)*2 ];
}
for my $tick (1 .. 5) {
for my $id (keys %h) { # advance + relocate, bouncing off walls
my $p = $pos{$id};
for my $a (0, 1) {
$p->[$a] += $vel[$id][$a];
if ($p->[$a] < 0) { $p->[$a] = -$p->[$a]; $vel[$id][$a] *= -1 }
elsif ($p->[$a] > $WORLD) { $p->[$a] = 2*$WORLD - $p->[$a]; $vel[$id][$a] *= -1 }
}
$s->move($h{$id}, @$p);
}
my (%seen, $pairs); # broad-phase collision candidates
for my $id (keys %h) {
lib/Data/SpatialHash/Shared.pm view on Meta::CPAN
C<new_memfd> creates a Linux memfd (anonymous but transferable via C<memfd>
file descriptor). C<new_from_fd> reopens an existing memfd in another
process.
=head2 Mutators
my $h = $s->insert(x, y, value); # 2D insert -- returns handle or undef
my $h = $s->insert(x, y, z, value); # 3D insert
my $h = $s->insert(x, y, z, value, r); # 3D insert with an interaction radius
$s->set_radius($h, $r); # set/replace an entry's radius
$s->move($h, x, y); # relocate entry (2D)
$s->move($h, x, y, z); # relocate entry (3D)
$s->remove($h); # free entry slot
$s->set_value($h, $v); # update stored value
$s->clear; # remove all entries
my @ids = $s->insert_many([ [x,y,value], [x,y,value,r], ... ]); # bulk insert
my $n = $s->move_many([ [handle,x,y], [handle,x,y,z], ... ]); # bulk move
C<insert> returns a handle (opaque integer) on success, or C<undef> if
C<max_entries> is exhausted. C<move> and C<remove> return true on success,
or false if the handle is invalid or already removed. C<set_value> instead
croaks on an invalid or freed handle; it and C<clear> return nothing.
t/17-bulk.t view on Meta::CPAN
use strict; use warnings; use Test::More;
use Data::SpatialHash::Shared;
# --- move_many ---
{
my $s = Data::SpatialHash::Shared->new(undef, 100, 0, 1.0);
my @h = map { $s->insert($_, 0, $_) } 1..5;
my $moved = $s->move_many([ map { [ $h[$_-1], $_+10, $_+10 ] } 1..5 ]);
is $moved, 5, 'move_many reports 5 moved';
is_deeply [$s->position($h[0])], [11, 11, 0], 'move_many relocated entry (2D row)';
$s->move_many([[ $h[1], 1, 2, 3 ]]); # 3D row
is_deeply [$s->position($h[1])], [1, 2, 3], 'move_many 3D row';
$s->remove($h[2]);
my $m2 = $s->move_many([[ $h[2], 5, 5 ], [ $h[3], 6, 6 ]]); # dead handle skipped
is $m2, 1, 'move_many skips a freed handle, counts the live one';
is_deeply [$s->position($h[3])], [6, 6, 0], 'live handle in mixed batch moved';
is $s->move_many([]), 0, 'move_many([]) moves nothing';
}
# --- insert_many ---
ok abs($pp[2] - 500) < 1e-3, 'north pole altitude round-trips';
# +-pi meridian: longitude magnitude round-trips to ~pi
my @pm = $s->position_geo($s->insert_geo(0.3, $PI, 0, -2));
ok abs(abs($pm[1]) - $PI) < 1e-6, '+-pi meridian longitude magnitude round-trips';
# move_geo
my $hmv = $s->insert_geo(0.1, 0.1, 0, -3);
ok $s->move_geo($hmv, 0.2, 0.2, 1000), 'move_geo returns true';
my @mp = $s->position_geo($hmv);
ok abs($mp[0] - 0.2) < 1e-9 && abs($mp[1] - 0.2) < 1e-9 && abs($mp[2] - 1000) < 1e-3, 'move_geo relocated entity';
my $freed = $s->insert_geo(0.1, 0.1, 0, -4);
$s->remove($freed);
ok !$s->move_geo($freed, 0.2, 0.2, 0), 'move_geo returns false for a freed handle';
eval { $s->position_geo($freed) }; like $@, qr/invalid|freed/, 'position_geo croaks on a freed handle';
# ---- query_geo_radius vs brute-force 3D oracle (clustered patch) ----
my $g = Data::SpatialHash::Shared->new(undef, 6000, 0, 50000, sphere => $R);
my @pts;
for my $i (1 .. 500) {
( run in 2.020 seconds using v1.01-cache-2.11-cpan-84de2e75c66 )