7 use Math::GSL::Matrix qw/:all/;
9 use Math::GSL::CBLAS qw/:all/;
10 use Math::GSL::Machine qw/:all/;
14 BEGIN { unshift @INC, qw(.); }
17 require 'misc-data.pl';
22 our %vxname2pos; # $vxname2pos{VXNAME} = Math::GSL::Vector
24 sub TAU { M_PI * 2.0; }
25 sub MM2PT { 72.0 / 25.4; }
27 # ----- region names from plag, incl. reverse mapping -----
31 sub prep_region_rmap () {
32 foreach my $rn (keys %region) {
33 my $prs = plag_prs($rn);
34 die if $prs2region{$prs};
35 $prs2region{$prs} = $rn;
38 # bodgery for the sea and land
39 $prs2region{'NZ | L'} = 'NZ';
40 $prs2region{'L | NZ'} = 'NZ';
43 our $sre = qr{(?:(\")|(?=\w))(.*)\1$}; # 2 captures, $2 is the name
45 sub prs2r ($) { $prs2region{$_[0]} // confess "@_ ?" }
46 sub prs2rr ($) { $region{prs2r($_[0])} }
48 #----- file reader for plag output -----
52 # $region{NAME}{Adj}[]{Ends}[]{VxName}
53 # $region{NAME}{Adj}[]{Ends}[]{Pos}
54 # $region{NAME}{Polygon}{Pos}
55 # $region{NAME}{Special}
58 # $region{NAME}{Adj}[]{Ends}[]{Adjoins}
59 # $region{NAME}{Polygon}{Adjoins}
60 # which should be ignored
62 open P, "<", $facesf or die $!;
63 while (<P>) { last if m/^\&faces$/; }
66 my $process_rr = sub {
68 if ($rr->{Name} eq 'NZ') {
69 # We combined L and NZ; now we must split them again
70 # in fact, we just throw away L entirely.
71 # Here, when processing NZ, we keep only vertices that
74 my $evxname = $_->{VxName};
75 my @eregions = split / \| ?/, $evxname;
76 grep { $_ eq 'NZ' } @eregions
79 $rr->{Polygon} = [ @edges ];
80 if ($rr->{Name} ne 'NZ') {
81 for my $ei (0..$#edges) {
82 my $ej = $ei % @edges;
83 if (!defined $last_ai) {
85 for my $ai (0..$#{ $rr->{Adj} }) {
86 next unless $rr->{Adj}[$ai]{Name} eq $edges[$ei]{Adjoins};
89 confess $edges[$ei]{Adjoins}.' ?' unless defined $last_ai;
91 my $ai = ($last_ai-1+@edges) % @edges;
93 my $adj = $rr->{Adj}[$ai];
94 confess Dumper($rr, \@edges, $ei, $ej, $adj, $last_ai, $ai)." ?"
95 unless $adj->{Name} eq $edges[$ei]{Adjoins};
98 $adj->{Ends}[$endi] = $edges[ ($ei + $endi) % @edges ];
107 $!=0; $_=<P> // confess $!;
111 $process_rr->() if $rr;
112 $rr= prs2rr($new_face);
113 } elsif (m/^\s+$sre$/) {
116 push @edges, { VxName => $vxname };
117 } elsif (m/^\s+\^adjoins\s+$sre$/) {
118 $edges[-1]{Adjoins} = prs2r($2);
119 } elsif (m/^\s+\^\@([-e.0-9]+)\,([-e.0-9]+)$/) {
120 my $pos = Math::GSL::Vector->new([$1,$2]);
121 confess unless defined $vxname;
122 $edges[-1]{Pos} = $pos;
123 $vxname2pos{$vxname} = $pos;
128 $region{$_}{Special} = 1 foreach qw(NZ L);
131 #----- geometry mangling -----
133 sub calculate_centres () {
135 # $region{NAME}{Centre}
136 foreach my $rr (values %region) {
137 next if $rr->{Special};
138 my $poly = $rr->{Polygon};
139 my $sum = Math::GSL::Vector->new(2);
140 $sum += $_->{Pos} foreach @$poly;
141 $rr->{Centre} = $sum * (1.0 / @$poly);
145 sub for_each_pos ($) {
147 foreach my $rr (values %region) {
148 $f->( \ $rr->{Centre} );
149 foreach my $vertex (@{ $rr->{Polygon} }) {
150 $f->( \ $vertex->{Pos} );
155 sub transform_coordinates () {
156 # Adjusts coordinates in graph to be [0,0] .. top right (scaled)
157 # until it's all in PostScript points
158 my @or = map { $region{$_}{Centre} } $c{OrientRegions};
159 my $dir = $or[1] - $or[0];
160 my $theta = atan2 $dir->[1], $dir->[0];
161 my $rotateby = (90 - $c{OrientBearing}) * TAU - $theta;
164 my $s = sin($rotateby);
165 my $c = cos($rotateby);
166 my $transform = Math::GSL::Matrix->new([[ $c, $s ],
169 foreach my $topend (qw(0 1)) {
170 my $v = $topend ? $GSL_DBL_MAX : $GSL_DBL_MIN;
171 push @lims, Math::GSL::new([$v,$v]);
175 my $y = Math::GSL::Vector->new(2);
176 gsl_blas_dgemv($CblasNoTrans, 1.0, $transform, $$pr, 0., $y) or confess;
177 gsl_blas_dcopy($$pr, $y) or confess;
178 foreach my $topend (qw(0 1)) {
179 foreach my $xy (qw(0 1)) {
180 my $now = $y->get($xy);
181 my $lim = $lims[$topend]->get($xy);
182 next if $topend ? ($now <= $lim) : ($now >= $lim);
183 $lims[$topend]->set($xy, $now);
187 my $translate = -$lims[0];
188 print STDERR "translate $translate\n";
189 my $scale = $c{GraphScale} * MM2PT;
192 gsl_vector_add($$pr, $translate) or confess;
193 gsl_vector_scale($$pr, $scale) or confess;
197 #----- main program -----
199 ($facesf, @ARGV) = @ARGV or die;
204 transform_coordinates();
206 print Dumper(\%region);
209 # cperl-indent-level: 2