#!/usr/bin/perl # Copyright : http://www.fsf.org/copyleft/gpl.html # Author : Dan Jacobson -- http://jidanni.org/geo/taipower/ # Created On : Thu Mar 16 17:37:29 2006 # Last Modified On: Sat Mar 7 01:50:23 2020 # Update Count : 488 =encoding utf8 =head1 DESCRIPTION 轉換台灣電力公司設備座標 < = > 公尺座標。 Taipowergrid converts Taiwan Power Company coordinates to and from X and Y meters coordinates. =head1 USAGE $ taipowergrid 輸入 with standard input of #A comment 329999 2449999 W9999 HE9999 354999 2663999 119 輸出 gives output: ##A comment #1 329999 2449999 W9999 HE9999 #2 W9999 HE9999 329999 2449999 #3 354999 2663999 119 X9999 HE9999 加註 119 為澎湖,無則台、金、馬。 The 119 specifies the Penghu meridian, else Taiwan, Jinmen, or Mazu is assumed. W9999HE9999 無空格輸入亦可。 No-space input also OK. =cut use strict; use warnings FATAL => 'all'; use constant II => "輸入錯誤 invalid input"; use constant D_EW => 80000; #Dimension east-west use constant D_NS => 50000; #Dimension north-south use constant TAIWAN_LEFT => 90000; use constant TAIWAN_TOP => 2800000; use constant PENGHU_LEFT => 275000; use constant PENGHU_BOTTOM => 2564000; use constant JINMEN_LEFT => 10000; #552700; use constant JINMEN_BOTTOM => 2675800; use constant MAZU_LEFT => 10000; #790400 use constant MAZU_BOTTOM => 2894000; my %baselines = ( S => [ MAZU_LEFT, MAZU_BOTTOM ], Y => [ PENGHU_LEFT, PENGHU_BOTTOM ], X => [ PENGHU_LEFT, PENGHU_BOTTOM + D_NS ], Z => [ JINMEN_LEFT, JINMEN_BOTTOM ] ); use constant TAIWAN_MAP => ' _ABC _DEF _GH_ JKL_ MNO_ PQR_ _TU_ _VW'; my $taiwan_bottom = ( undef, TAIWAN_TOP + D_NS ); for ( split /\n/, TAIWAN_MAP ) { my $left_edge = 10000; $taiwan_bottom -= D_NS; for ( split // ) { $left_edge += D_EW; $baselines{$_} = [ $left_edge, $taiwan_bottom ] if /[[:upper:]]/; } } my $conversion; while (<>) { if (/^(#|$)/) { print "#$_"; next } #comments print "#", ++$conversion, " ", $_; chomp; if (/^\d/) { print join( " ", xy_to_electric($_) ), "\n" } else { print join( " ", electric_to_xy($_) ), "\n" } } sub electric_to_xy { die II unless my ( $area_letter, @electric ) = /^([A-HJ-Z])(\d\d)(\d\d)\s*([A-H])([A-E])(\d)(\d)(?:(\d)(\d))?$/; $electric[0] = 50 + ( $electric[0] + 50 ) % 100 if $area_letter eq 'Z'; my @xy = electric80000x50000_to_xy(@electric); $xy[$_] += $baselines{$area_letter}[$_] for 0 .. 1; push @xy, 119 if $area_letter =~ /[XY]/; return @xy; } sub electric80000x50000_to_xy { my @xy = ( 800 * shift, 500 * shift ); $_ += ( ord(shift) - ord 'A' ) * 100 for @xy; $_ += 10 * shift for @xy; $_ += shift // 0 for @xy; return @xy; } sub xy_to_electric { die II unless my @xy = /^(\d+)\s+(\d+)(\s+\d+)?$/; my $area_letter = area_letter_of(@xy); $xy[$_] -= $baselines{$area_letter}[$_] for 0 .. 1; $xy[0] %= D_EW if $area_letter eq 'Z'; return $area_letter . xy_to_electric80000x50000(@xy); } sub area_letter_of { if ( defined $_[2] ) { die "澎湖加註 119. 其餘自動偵測。 Append 119 for Penghu, other areas automatically detected" unless $_[2] == 119; die II if $_[0] < PENGHU_LEFT; die II if $_[0] >= PENGHU_LEFT + D_EW; die II if $_[1] < PENGHU_BOTTOM; my $i; for ( 'Y', 'X' ) { return $_ if $_[1] < PENGHU_BOTTOM + D_NS * ++$i; } die II; } if ( $_[1] >= MAZU_BOTTOM ) { die II unless $_[1] < MAZU_BOTTOM + D_NS; die II unless $_[0] >= MAZU_LEFT; die II unless $_[0] < MAZU_LEFT + D_EW; return 'S'; } if ( $_[0] < JINMEN_LEFT + D_EW * 3 / 2 ) { die II unless $_[0] >= JINMEN_LEFT; die II unless $_[1] >= JINMEN_BOTTOM; die II unless $_[1] < JINMEN_BOTTOM + D_NS; return 'Z'; } die II if $_[1] >= TAIWAN_TOP; die II if $_[1] < $taiwan_bottom; my $char_position = int( ( TAIWAN_TOP - $_[1] - 1 ) / D_NS ) * 5 + int( ( $_[0] - TAIWAN_LEFT ) / D_EW ) + 1; die II if $char_position > length TAIWAN_MAP; die II if ( my $char = substr TAIWAN_MAP, $char_position, 1 ) !~ /[A-W]/; return $char; } sub xy_to_electric80000x50000 { return sprintf "%02d%02d %s%s%d%d%d%d", map( int, $_[0] / 800, $_[1] / 500 ), chr( ord('A') + int( $_[0] % 800 / 100 ) ), chr( ord('A') + int( $_[1] % 500 / 100 ) ), map( int, $_[0] % 100 / 10, $_[1] % 100 / 10 ), $_[0] % 10, $_[1] % 10; }