This (from the PDL::Dataflow doc, not yet updated to CPAN) is a complete, working example that demonstrates the use of enduring flowing relationships to model 3D entities, through a few transformations:
{package PDL::3Space; use PDL; sub new { my ($class, $parent) = @_; my $self = bless {basis_local=>identity(3), origin_local=>zeroes(3)} +, $class; if (defined $parent) { $self->{parent} = $parent; $self->{basis} = $self->{basis_local}->flowing x $parent->{basis}- +>flowing; $self->{origin} = ($self->{origin_local}->flowing x $self->{basis} +->flowing)->flowing + $parent->{origin}->flowing; } else { $self->{basis} = $self->{basis_local}; $self->{origin} = $self->{origin_local}->flowing x $self->{basis}- +>flowing; } $self; } use overload '""' => sub {$_[0]{basis}->glue(1,$_[0]{origin}).''}; sub basis_update { $_[0]{basis_local} .= $_[1] x $_[0]{basis_local} } sub origin_move { $_[0]{origin_local} += $_[1] } sub local { my $local = PDL::3Space->new; $local->{$_} .= $_[0]{$_} fo +r qw(basis_local origin_local); $local} }
This is the class, heavily inspired by Math::3Space, and following discussions on interoperation between that and PDL (see https://github.com/nrdvana/perl-Math-3Space/pull/8). The basis and origin members are "subscribed" to both their own local basis and origin, and their parent's if any. The basis_update and origin_move methods only update the local members, both in terms of previous values.

The demonstrating code has a boat, and a bird within its frame of reference. Note that the "local" origin still gets affected by its local basis.

The basis and origin are always in global coordinates, and thanks to dataflow, are only recalculated on demand.

$rot_90_about_z = PDL->pdl([0,1,0], [-1,0,0], [0,0,1]); $boat = PDL::3Space->new; print "boat=$boat"; $bird = PDL::3Space->new($boat); print "bird=$bird"; # boat= # [ # [1 0 0] # [0 1 0] # [0 0 1] # [0 0 0] # ] # bird= # [ # [1 0 0] # [0 1 0] # [0 0 1] # [0 0 0] # ] $boat->basis_update($rot_90_about_z); print "after boat rot:\nboat=$boat"; print "bird=$bird"; # after boat rot: # boat= # [ # [ 0 1 0] # [-1 0 0] # [ 0 0 1] # [ 0 0 0] # ] # bird= # [ # [ 0 1 0] # [-1 0 0] # [ 0 0 1] # [ 0 0 0] # ] $boat->origin_move(PDL->pdl(1,0,0)); print "after boat move:\nboat=$boat"; print "bird=$bird"; print "bird local=".$bird->local; # after boat move: # boat= # [ # [ 0 1 0] # [-1 0 0] # [ 0 0 1] # [ 0 1 0] # ] # bird= # [ # [ 0 1 0] # [-1 0 0] # [ 0 0 1] # [ 0 1 0] # ] # bird local= # [ # [1 0 0] # [0 1 0] # [0 0 1] # [0 0 0] # ] $bird->basis_update($rot_90_about_z); $bird->origin_move(PDL->pdl(1,0,1)); print "after bird rot and move:\nbird=$bird"; print "bird local=".$bird->local; # after bird rot and move: # bird= # [ # [-1 0 0] # [ 0 -1 0] # [ 0 0 1] # [-1 1 1] # ] # bird local= # [ # [ 0 1 0] # [-1 0 0] # [ 0 0 1] # [ 0 1 1] # ] $boat->basis_update(PDL::MatrixOps::identity(3) * 2); print "after boat expand:\nboat=$boat"; print "bird=$bird"; # after boat expand: # boat= # [ # [ 0 2 0] # [-2 0 0] # [ 0 0 2] # [ 0 2 0] # ] # bird= # [ # [-2 0 0] # [ 0 -2 0] # [ 0 0 2] # [-2 2 2] # ]

Replies are listed 'Best First'.
Re: Example of PDL dataflow to implement 3D space calculations
by NERDVANA (Priest) on Jul 08, 2024 at 08:12 UTC
    Thanks for sharing! It's neat to see other ways of approaching this problem.

    I'm not entirely sure whether this solves my use cases better or worse than Math::3Space because I haven't gotten around to writing my use cases yet :-) I did a bit of cart-before-the-horse here, mostly prompted by the earlier discussion rather than by having time to write a video game or CAD software.

      In terms of raw performance for small computing tasks, your solution is much better. I believe that for larger computing tasks, which is arguably more realistic for games or CAD, the PDL solution is competitive in both computing performance, and especially ease of programming and maintenance.

      Probably the greatest utility in the above example is just showing how to approach this class of problems with PDL, and doing so prompted me to add a couple of arguably missing features to PDL.