4 # slopecalc =HEIGHT|SLOPE%|+DIST|@ABSDIST ...
7 # args represent details of control points
9 # an arg starts a new control point if it specifies
10 # a property (height, slope or location) which has
11 # already been determined for the current control
14 # when a new point is started all the properties of the previous
15 # point must be determinable - although unless otherwise specified
16 # the slope will remain unchanged from the point before, and if
17 # the slope _has_ changed a default distance is supplied
19 # the first use of @... to specify an absolute location
20 # acts only to fix the zero point of the absolute position scale;
21 # the (relative to start) location of the current point must already be known
23 use strict qw(vars refs);
25 our $halfreverselen= 80; # mm to change from going flat to going up/down
26 our $printinterval= 10;
27 our $totallinesout= 139;
29 our @cp= ({ L => 0 });
31 # $cp[]{L} absolute dist
35 our $numre= '(?:\\d{1,6}(?:\\.\\d*)?|\\.\\d+)';
44 print STDERR "$progname: $m\n";
54 # always called in this order: $this->{S} $this->{L} $this->{H}
55 # compute_fixed_S($last,$this) undef - -
56 # compute_fixed_L($last,$this) - undef -
57 # compute_fixed_H($last,$this) - - undef
58 # compute_default_S($last,$this) undef - -
59 # compute_default_L($last,$this) defined undef -
60 # compute_default_H($last,$this) defined defined undef
61 # $last->{S}, $last->{H}, $last->{L} are always defined on entry
63 sub compute_fixed_S ($$) { }
64 sub compute_default_S ($$) {
65 my ($last,$this) = @_;
66 $this->{S}= $last->{S};
68 sub compute_fixed_L ($$) {
69 my ($last,$this) = @_;
70 if (defined $this->{S}
71 and defined $this->{H}
72 and $last->{S} == $this->{S}) {
73 $this->{L}= $last->{L} + ($this->{H} - $last->{H})/$last->{S};
77 sub compute_default_L ($$) {
78 my ($last,$this) = @_;
79 if (defined $this->{S}
80 and !defined $this->{H}
81 and $last->{S} != $this->{S}) {
82 $this->{L}= $last->{L} +
83 $halfreverselen * ($last->{S} * $this->{S} < 0 ? 2 : 1);
87 sub compute_fixed_H ($$) {
88 my ($last,$this) = @_;
89 if (defined $this->{S}
90 and defined $this->{L}) {
91 my $meanslope= 0.5 * ($last->{S} + $this->{S});
92 $this->{H}= $last->{H} + $meanslope * ($this->{L} - $last->{L});
96 sub compute_default_H ($$) { }
98 sub complete_current_point ($) {
103 my $last= @cp > 1 ? $cp[$#cp-1] : undef;
104 foreach my $k2 (qw(S L H)) {
107 defined $this->{$k2} or &{"compute_fixed_$k2"}($last, $this);
108 defined $this->{$k2} or &{"compute_default_$k2"}($last, $this);
110 if (!defined $this->{$k2}) {
111 arg_error("point \#$#cp: property $k2 unspecified");
117 print STDERR "$progname: ($why)\n"
124 my $last = $cp[$#cp];
126 if (!defined $last->{$k}) {
130 complete_current_point("new point started because of change to $k");
131 my $this = { $k => $v };
132 foreach my $k2 (qw(S L H)) {
134 defined $this->{$k2} or &{"compute_fixed_$k"}($last, $this);
143 #print STDERR ">$_<\n", Dumper(\@cp);
144 if (m/^\=([-+]?$numre)$/o) {
146 } elsif (m/^([-+]?$numre)\%$/o) {
147 arg_item(S, $1 * 0.01);
148 } elsif (m/^([-+]?1)\:($numre)$/o) {
149 arg_item(S, $1 / $2);
150 } elsif (m/^\@([-+]?$numre)$/o) {
151 if (defined $absoffset) {
152 arg_item(L, $1 + $absoffset);
156 } elsif (defined $cp[$#cp]{L}) {
157 $absoffset= $cp[$#cp]{L} - $1;
159 arg_error("point \#$#cp location still unknown at \`$_'");
162 } elsif (m/^\+($numre)$/o) {
163 complete_current_point("new point started because of +...");
164 arg_item(L, $cp[$#cp]{L} + $1);
166 arg_error("bad argument `$_'");
168 push @{ $cp[$#cp]{Args} }, $_;
170 complete_current_point("completing as it is the final point");
171 die "$progname: errors in argument(s)\n" if $arg_errors;
174 sub lprint_interp ($$$$) {
175 my ($l_more,$l,$y,$cc) = @_;
176 lprintf(" %4s %7d %8.2f %s",
177 "+$l_more", $l - $absoffset, $y, $cc);
180 sub dump_schedule ($) {
181 my ($interpolate) = @_;
182 $absoffset=0 unless defined $absoffset;
187 for ($i=0; $i<@cp; $i++) {
189 lprintf("%4s %7s %7s =%6.2f %s %5.02f%% %s %s",
191 '+'.($this->{L} - $last_l),
192 '@'.($this->{L} - $absoffset),
194 ($this->{S} < 0 ? '/' :
195 $this->{S} > 0 ? '\\' :
199 sprintf "=%+6.2f", $this->{H} - $last_h :
201 "@{ $this->{Args} }");
203 if ($interpolate and defined $next) {
205 my $dist_l = $next->{L} - $this->{L};
207 my $base_hdiff = $next->{H} - $this->{H};
208 my $base_slope = $base_hdiff / $dist_l;
209 my $next_hoop = -($next->{S} * $dist_l - $base_hdiff);
210 my $this_hoop = $this->{S} * $dist_l - $base_hdiff;
212 ($next->{S} < $this->{S} ? '>' :
213 $next->{S} > $this->{S} ? '<' :
214 $next->{H} < $this->{H} ? '/' :
215 $next->{H} > $this->{H} ? '\\' :
218 $more_l += $printinterval;
219 my $gamma= $more_l / $dist_l;
220 my $l = $this->{L} + $more_l;
221 last unless $l < $next->{L};
222 my $zeta= 1 - $gamma;
223 my $y = $this->{H} + $gamma * $base_hdiff;
224 my $hoop= $gamma * $zeta;
225 $y += $hoop * ($gamma * $next_hoop +
227 lprint_interp($more_l,$l,$y,$char_char);
237 while ($lines+2 < $totallinesout) {
238 lprint_interp($more_l,
239 $last->{L} + $more_l,
240 $last->{H} + $last->{S} * $more_l,
242 $more_l += $printinterval;
257 foreach my $oi (0..2) {
259 join(($oi==1 ? '|' : ' '),
264 $xpos += 1 + length($_[0]);
265 if ($xpos >= $lmax) {
266 foreach my $oi (0..2) {
268 ($oi==1 && $_[$oi] =~ m/^\-/ ? '-' : '');
273 $xpos= length($_[0]);
275 foreach my $oi (0..2) {
276 push @{ $out[$oi] }, $_[$oi];
280 foreach (my $i=0; $i<@cp; $i++) {
282 my @iargs= @{ $cp->{Args} };
284 if (@iargs && $iargs[0] =~ m/^\+$numre$/) {
285 my $relmove= shift @iargs;
287 '-'x length $relmove,
288 ' 'x length $relmove);
296 my $lipoint= length $ipoint;
299 my $l= $lipoint > length($iargs) ? $lipoint : length($iargs);
301 my $pad= int(($l-$lipoint)/2);
303 $push->((sprintf "%-*s", $l, $iargs),
305 (' 'x $pad). $ipoint. (' ' x ($l-$lipoint-$pad)));
313 lprintf("control points:");
316 lprintf("table of heights:");
319 my $dir= $0; $dir =~ s,/.*?$,,;
320 my $gitid= `$dir/../.git-revid`; $? and die $?; chomp $gitid;