sub Normaliza { say "Normalizar polígonos" if DEBUG; # Recorremos todos los polígonos y le restamos un polígono cero # El resultado se almacenará como nuevos polígonos my %NewContornos; my $Ancho = 400; my $Alto = 200; my $c; my $d; foreach my $base ( sort { $a <=> $b } keys %Contornos ) { # Para todos los contornos de ese valor foreach my $i ( 0..$#{$Contornos{$base}} ) { $c++; # Creamos objeto polígono base my $gpc_base = Math::Geometry::Planar::GPC::Polygon->new(); $gpc_base->add_polygon(\@{$Contornos{$base}[$i][0]}, 0); # Idem para el polígono a restart my $gpc_sup = Math::Geometry::Planar::GPC::Polygon->new(); $gpc_sup->add_polygon( [ [ $Ancho+0, $Alto+0 ], [ $Ancho+1, $Alto+0 ], [ $Ancho+1, $Alto+1 ], [ $Ancho+0, $Alto+1 ], ], 0); # Calcular diferencias my $gpc_res = $gpc_base->clip_to($gpc_sup, 'DIFFERENCE'); # Almacenar resultado, todos los polígonos encontrados my @p = $gpc_res->get_polygons; foreach my $poly ( 0..$#p ) { push @{ $NewContornos{$base} }, [ [ @{ clone(\@{$p[$poly]}) } ] ]; $d++; } } } say "\t$c -> $d" if DEBUG; %Contornos = %{ clone(\%NewContornos) }; } #### sub Diferencias { # Cálculo de las diferencias entre dos polígonos my ($base,$i,$sup,$j) = @_; # Creamos objeto polígono base my $gpc_base = Math::Geometry::Planar::GPC::Polygon->new(); # Añadir primero el contorno principal $gpc_base->add_polygon(\@{$Contornos{$base}[$i][0]}, 0); # Añadir luego los agujeros que tenga my $num_pol = @{$Contornos{$base}[$i]}; foreach my $agujero ( 1 .. $num_pol-1 ) { $gpc_base->add_polygon(\@{$Contornos{$base}[$i][$agujero]}, 1); } # Idem para el polígono a restart my $gpc_sup = Math::Geometry::Planar::GPC::Polygon->new(); $gpc_sup->add_polygon(\@{$Contornos{$sup}[$j][0]}, 0); # Calcular diferencias my $gpc_res = $gpc_base->clip_to($gpc_sup, 'DIFFERENCE'); undef $gpc_base; undef $gpc_sup; my $res = $gpc_res->as_string(); # Si no hay diferencias, salir inmediatamente # If the result of operation is null, the two polygons aren't coincidences. return if $res eq ''; # Almacenar resultado my @p = $gpc_res->get_polygons; @{$Contornos{$base}[$i]} = (); # A new definition of this contour foreach my $poly ( 0..$#p ) { # HERE ARE THE TRICK: # WE READ THE @p LIST OF POLYGONS RESULT OF DIFFERENCE OPERATION ->and<- # HOPE THIS N-1 ->FIRST<- POLYGONS ARE THE HOLES OF THE BIGGER POLYGON, THAT # THESE POINTS ARE IN THE ->LAST<- POLYGON OF @p LIST. # SO, WE READ THE LIST IN ->REVERSE<- ($#p-$poly) TO READ FIRST THE BIG POLYGON (the convex hull) # AND NEXT, THE HOLES. # We need to use the clone method of Clone module to make a copy of all struct return by gpc, because # are freed afterwards. # Here, I'm storing the points in a 4D struct: # $base is the value (altitude) of the contour base we are subtracting $sup contour # $i is the number of contour into $base value contours # $j is the number of contour into $sup value contours # %Contornos is a hash of arrays to arrays to arrays. # Every key of %Contornos is a altitude value (or the physic value you set to the contours) # Every altitude value is an array of contours of the same physic value ($base). # Every $i-contour of $base value is an array of polygons ($poly). # -> THE FIRST POLYGON IS THE 'BIG' POLYGON AND NEXT ARE THE HOLES OF THIS POLYGON <- # And every polygon is an array of points (the parent @{}): @{ $Contornos{$base}[$i][$poly] } = @{ clone(\@{$p[$#p - $poly]}) }; # # (These lines work the same the one above) # my $k = $#p - $poly; # foreach my $j ( @{$p[$k]} ) # { # $Contornos{$base}[$i][$poly][$j][0] = $p[$k][$j][0]; # $Contornos{$base}[$i][$poly][$j][1] = $p[$k][$j][1]; # } } # important: free memory undef $gpc_res; } #### sub Agujerear($) { say "\t\tAgujerear" if DEBUG; my $valor = shift; # Recorrer todos los polígonos y contruir el hash %Contornos #---------------------------------------------------------------------------- # Para cada polígono BORDE de la capa $valor # Creamos contorno a partir de ese polígono # Para cada polígono AGUJERO de la capa $valor # Si el agujero está dentro, asociarlo # Para todos los puntos del agujero # Si un sólo vértice está dentro del polígono, es un agujero suyo # Lo asociamos guardándolo en su contorno #---------------------------------------------------------------------------- foreach my $poligono ( @{ $Poligonos{$valor}[BORDE] } ) { my $contorno = Math::Geometry::Planar->new; $contorno->polygons( [ $poligono->points ] ); foreach my $agujero ( @{ $Poligonos{$valor}[AGUJERO] } ) { my $vertices = @{ $agujero->points }; foreach my $vertice ( @{ $agujero->points } ) { next unless $poligono->isinside($vertice); $vertices--; } $contorno->add_polygons( $agujero->points ) if $vertices < 2; } push @{ $Contornos{$valor} }, $contorno; } say if DEBUG; }