package MyUnion; use strict; use warnings; use FindBin; our $VERSION = 0.001; our @EXPORT_OK = qw/ wrap_ppunpo /; use Inline C => Config => LIBS => "-L$FindBin::Bin/lib -lgfortran -lpolypack"; use Inline C => <<'EOC'; extern void ppunpo_( float* xclip, float* yclip, int* nclip, float* xpoly, float* ypoly, int* npoly, float* rwork, void* iwork, int* nwork, void* cback, int* error ); AV* ary; // AoA; collect output here, array (i.e. one call // to call-back function, below) per sub-path static void urpp( float* xcra, float* ycra, int* ncra ) { int i; AV* pgone = newAV(); for ( i = 0; i < *ncra; i ++ ) { AV* point = newAV(); av_push( point, newSVnv( xcra[ i ])); av_push( point, newSVnv( ycra[ i ])); av_push( pgone, newRV_noinc( point )); } av_push( ary, newRV_noinc( pgone )); } SV* wrap_ppunpo( SV* ccp, SV* csp ) { AV* ccp_ary = SvRV( ccp ); AV* csp_ary = SvRV( csp ); int nccp = av_top_index( ccp_ary ) + 1; int ncsp = av_top_index( csp_ary ) + 1; int nwrk = 20 * ( nccp + ncsp ); float* xccp = malloc( nccp * sizeof( float )); float* yccp = malloc( nccp * sizeof( float )); float* xcsp = malloc( ncsp * sizeof( float )); float* ycsp = malloc( ncsp * sizeof( float )); float* work = malloc( nwrk * sizeof( float )); int i; AV* point; for ( i = 0; i < nccp; i ++ ) { point = SvRV( *av_fetch( ccp_ary, i, 0 )); xccp[ i ] = SvNV( *av_fetch( point, 0, 0 )); yccp[ i ] = SvNV( *av_fetch( point, 1, 0 )); } for ( i = 0; i < ncsp; i ++ ) { point = SvRV( *av_fetch( csp_ary, i, 0 )); xcsp[ i ] = SvNV( *av_fetch( point, 0, 0 )); ycsp[ i ] = SvNV( *av_fetch( point, 1, 0 )); } ary = newAV(); int ierr; ppunpo_( &xccp[0], &yccp[0], &nccp, &xcsp[0], &ycsp[0], &ncsp, &work[0], &work[0], &nwrk, &urpp, &ierr ); SV* ret; if ( ierr ) { av_undef( ary ); ret = newSV( 0 ); } else { ret = newRV_noinc( ary ); } free( xccp ); free( yccp ); free( xcsp ); free( ycsp ); free( work ); // Note, this also frees memory // used by data passed to call-back return( ret ); } EOC 1; #### use strict; use warnings; use feature 'say'; use FindBin; use Data::Dump 'dd'; use autodie; use Benchmark 'cmpthese'; use lib "$FindBin::Bin/lib"; use MyUnion 'wrap_ppunpo'; use Math::Geometry::Planar; { ###### Demo data output block my @sets = ( [[0,0],[0,2],[2,2],[2,0],[0,0]], [[0,0],[3,0],[3,1],[0,1],[0,0]], [[3,0],[3,2],[4,2],[4,0],[3,0]], [[0,2],[0,3],[1,3],[1,2],[0,2]], ); say "\n**** Demo output for GPC:\n"; my $clip_gpc_obj = Math::Geometry::Planar-> new; my $poly_gpc_obj = Math::Geometry::Planar-> new; $clip_gpc_obj-> points( $sets[ 0 ]); for ( 1.. 3 ) { $poly_gpc_obj-> points( $sets[ $_ ]); dd [ map @{ $_-> polygons }, Gpc2Polygons( GpcClip( 'UNION', $poly_gpc_obj-> convert2gpc, $clip_gpc_obj-> convert2gpc, ) ) ] } say "\n\n*** Demo output for POLYPACK:\n"; dd wrap_ppunpo( @sets[ 0, $_ ]) for 1 .. 3; } ####################### Benchmark my $clip_points = _get_data( 'c' ); # clipmask polygon points my $poly_points = _get_data( 's' ); # sample polygon points my $clip_gpc_obj = Math::Geometry::Planar-> new; my $poly_gpc_obj = Math::Geometry::Planar-> new; $clip_gpc_obj-> points( $clip_points ); $poly_gpc_obj-> points( $poly_points ); my $clip_gpc_struct = $clip_gpc_obj-> convert2gpc; my $poly_gpc_struct = $poly_gpc_obj-> convert2gpc; say "\n\n*** Benchmark (union of polygons with " . @$clip_points . ' and ' . @$poly_points . " points):\n"; cmpthese( -5, { GPC_lib => sub { my $union_gpc_struct = GpcClip( 'UNION', $poly_gpc_struct, $clip_gpc_struct, ); my ( $contour ) = Gpc2Polygons( $union_gpc_struct ); return $contour-> polygons; }, POLYPACK => sub { return wrap_ppunpo( $clip_points, $poly_points ); }, }); sub _get_data { # only simple wlr files expected! my $name = shift; open my $fh, '<', "sample/$name.wlr"; <$fh>; <$fh>; <$fh>; my @a; push @a, [ map { 0 + $_ } split ',', <$fh> ] until eof $fh; return \@a } __END__ #### **** Demo output for GPC: [[[2, 2], [0, 2], [0, 1], [0, 0], [3, 0], [3, 1], [2, 1]]] [ [[4, 2], [3, 2], [3, 0], [4, 0]], [[2, 2], [0, 2], [0, 0], [2, 0]], ] [[[1, 3], [0, 3], [0, 2], [0, 0], [2, 0], [2, 2], [1, 2]]] *** Demo output for POLYPACK: [ [[2, 2], [2, 1], [3, 1], [3, 0], [2, 0], [0, 0], [0, 2], [2, 2]], ] [ [[2, 2], [2, 0], [0, 0], [0, 2], [2, 2]], [[4, 2], [4, 0], [3, 0], [3, 2], [4, 2]], ] [ [[1, 3], [1, 2], [2, 2], [2, 0], [0, 0], [0, 2], [0, 3], [1, 3]], ] *** Benchmark (union of polygons with 31084 and 38755 points): s/iter GPC_lib POLYPACK GPC_lib 1.26 -- -98% POLYPACK 2.74e-002 4491% --