Last active
October 16, 2022 20:09
-
-
Save jaggzh/f34385f3e9f964014ed75fcfcb5da6a7 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/perl | |
| use warnings; | |
| use 5.24.0; | |
| use Text::Table; | |
| use Getopt::Lucid qw( :all ); | |
| # Colours! | |
| my $a_match="\033[33;1m"; | |
| my $a_close="\033[36;1m"; | |
| my $a_rst="\033[;m"; | |
| # Defaults | |
| my $def_maxi = 5; | |
| my $def_maxm = $def_maxi * 25.4; | |
| my $def_range = 2; | |
| sub imp2d { | |
| my $s = shift; | |
| # say ""; | |
| # say " S: {$s}"; | |
| return int($s) if $s !~ /-/; | |
| my ($whole, $f1, $f2) = ($s =~ m|^(.*)-(\d+)/(\d+)|); | |
| my $frac = (int($f1)/int($f2)); | |
| my $res = int($whole)+$frac; | |
| # say "Whole: $whole"; | |
| # say " f1: $f1"; | |
| # say " f2: $f2"; | |
| # say " Frac: $frac"; | |
| # say " Res: $res"; | |
| return $res; | |
| } | |
| sub gcd { | |
| my ($a, $b) = @_; | |
| ($a,$b) = ($b,$a) if $a > $b; | |
| while ($a) { | |
| ($a, $b) = ($b % $a, $a); | |
| } | |
| return $b; | |
| } | |
| sub is_float_or_int { $_[0] =~ /^(\d+(?:\.\d+)?)|\.\d+$/ } | |
| sub is_int { $_[0] =~ /^\d+$/ } | |
| sub def { defined shift } | |
| sub main { | |
| my @specs = ( | |
| Counter("verbose|v"), | |
| Switch("2")->doc("1/2 increments"), | |
| Switch("4")->doc("1/4 increments"), | |
| Switch("8")->doc("1/8 increments (default)"), | |
| Switch("16")->doc("1/16 increments"), | |
| Switch("32|3")->doc("1/32 increments"), | |
| Switch("64|6")->doc("1/64 increments"), | |
| Param("range|r")->default($def_range)-> | |
| doc("Range of items around selected value to display (ex: --max=$def_range)")-> | |
| valid(\&is_int), | |
| Param("maxi|max")->default($def_maxi)-> | |
| doc("Maximum (imperial) unit (ex: --max=3) (def: $def_maxi)")-> | |
| valid(\&is_float_or_int), | |
| Param("maxm")->default($def_maxm)-> | |
| doc("Maximum (metric) unit (ex: --maxm=26) (def: $def_maxm) (not implemented)")-> | |
| valid(qr/(\d+(?:\.\d+)?)/), | |
| #Param("config|C"), | |
| #List("lib|l|I"), | |
| #Keypair("define"), | |
| Switch("help|h") | |
| ); | |
| my $opt = Getopt::Lucid->getopt( \@specs )->validate; | |
| if ($opt->get_help) { | |
| say "Metric imperial table(s)"; | |
| print $opt->usage; | |
| exit 0; | |
| } | |
| my $user_num; | |
| if ($#ARGV+1 > 0) { # User gave an argument (or more?) | |
| $user_num = shift @ARGV; | |
| die "Provided target number ($user_num) is not a number" | |
| if !is_float_or_int($user_num) | |
| } | |
| my $default_denom = 8; | |
| my $st = 0; | |
| my $en = $opt->get_maxi; | |
| my $denom = | |
| $opt->get_2 ? 2 : | |
| $opt->get_4 ? 4 : | |
| $opt->get_8 ? 8 : | |
| $opt->get_16 ? 16 : | |
| $opt->get_32 ? 32 : | |
| $opt->get_64 ? 64 : $default_denom; # default | |
| my $tb = Text::Table->new( | |
| ("Idx", "Metric(mm)", "Imperial", "Imperial(Dec)")); | |
| die "No range to process (start = $st, end = $en)" | |
| if $st > $en; | |
| my @items; | |
| my ($found_itemi_i, $found_itemi_exact_i); | |
| my ($found_itemm_i, $found_itemm_exact_i); | |
| # Main loop through inches. You're welcome. | |
| for (my $in=$st; $in < $en; $in++) { | |
| # Looping through incremental denominators | |
| for my $num (1 .. $denom) { | |
| my $div = gcd($num, $denom); # greatest common divisor | |
| my $frac = $num/$denom; | |
| my $mm = ($in + $frac)*25.4; | |
| # say("$num / $denom (div: $div) ==> " . $num/$div . " / " . $denom/$div); | |
| # say("In: $in"); | |
| my $cnum = $num/$div; | |
| my $cdenom = $denom/$div; | |
| my $imp_str; | |
| if ($cnum == $cdenom) { | |
| $imp_str = sprintf("%d", $in+1); # Reached, eg. 8/8 (so 0+8/8) | |
| } else { | |
| $imp_str = $in == 0 ? | |
| sprintf("%d/%d", $cnum, $cdenom) : | |
| sprintf("%d-%d/%d", $in, $cnum, $cdenom); | |
| } | |
| # my $imp_dec = sprintf("%f", $in + $num/$denom); | |
| my $imp_dec = $in + $num/$denom; | |
| # Early termination: Loop doesn't handle calculating the decimal | |
| # so we'll just do it here. | |
| last if $imp_dec > $opt->get_maxi; | |
| # Keep values | |
| push(@items, {mm=>$mm, imp=>$imp_str, dec=>$imp_dec}); | |
| if (defined $user_num) { | |
| if (!defined $found_itemi_i) { | |
| if ($user_num == $imp_dec) { # exact imperial match | |
| $found_itemi_i = $#items; | |
| $found_itemi_exact_i = $#items-1; | |
| } elsif ($imp_dec > $user_num) { | |
| $found_itemi_i = $#items; | |
| $found_itemi_exact_i = $#items-1; | |
| } | |
| } | |
| if (!defined $found_itemi_i) { | |
| if ($user_num == $mm) { # exact metric match | |
| $found_itemm_i = $#items; | |
| $found_itemm_exact_i = $#items-1; | |
| } elsif ($user_num < $mm && !defined $found_itemm_i) { | |
| $found_itemm_i = $#items; | |
| } | |
| } | |
| } | |
| } | |
| } | |
| # Add values to table | |
| if ( defined $user_num ) { | |
| say "Found item imperial: " . ($found_itemi_i // '?'); | |
| say "Found item metric : " . ($found_itemm_i // '?'); | |
| if (!defined $found_itemi_i && !defined $found_itemm_i) { | |
| die "Nothing found near the number you wanted. This is a bug, not your fault."; | |
| } | |
| } | |
| for my $i (0 .. $#items) { | |
| my $item = $items[$i]; | |
| my ($mm, $imp, $dec) = ($$item{mm}, $$item{imp}, $$item{dec}); | |
| my $addflag = 0; | |
| if ( defined $user_num ) { # Results limited to user selection | |
| if (defined $found_itemi_i) { | |
| if ($item->{dec} == $user_num) { | |
| $imp = "[$a_match$$item{imp}$a_rst]"; | |
| $dec = "[$a_match$$item{dec}$a_rst]"; | |
| $addflag = 1; | |
| } elsif ($i >= $found_itemi_i - $opt->get_range && | |
| $i <= $found_itemi_i + $opt->get_range) { | |
| $imp = "*$a_close$$item{imp}$a_rst"; | |
| $dec = "*$a_close$$item{dec}$a_rst"; | |
| $addflag = 1; | |
| } | |
| } | |
| if (defined $found_itemm_i) { | |
| if ($item->{mm} == $user_num) { | |
| $mm = "[$a_match$$item{mm}$a_rst]"; | |
| $addflag = 1; | |
| } elsif ($i >= $found_itemm_i - $opt->get_range && | |
| $i <= $found_itemm_i + $opt->get_range) { | |
| $mm = "*$a_close$$item{mm}$a_rst"; | |
| $addflag = 1; | |
| } | |
| } | |
| } else { | |
| $addflag = 1; | |
| } | |
| if ($addflag) { | |
| $tb->add($i, $mm, $imp, $dec); | |
| } | |
| } | |
| # Print table | |
| if (! -t *STDOUT) { print $tb; } | |
| else { open my $pipe, "|-", "less -R"; $|=1; print $pipe $tb; } | |
| } | |
| main(); | |
| exit; | |
| # my $tb = Text::Table->new(qw/Metric Imperial Imperial(Dec)/); | |
| # for my $i (0 .. $#lines) { | |
| # $tb->add($met[$i], $imp[$i]->{imp}, $imp[$i]->{dec}); | |
| # } | |
| # open my $pipe, "|-", "less"; $|=1; print $pipe $tb; | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment