--- /dev/null
+#!/usr/bin/perl
+#
+# Reads the special comments in the subsegment encoding output from
+# layout, determines the segment graph, and outputs a description of
+# that graph.
+
+# Approach/algorithm:
+#
+# We read the segenco.ps and each time we find a `%L segmentpart'
+# comment we add it to an annotated graph we construct. Each node in
+# the annotated graph is a tuple consisting of a loc and range of
+# layer levels. Each edge is a segment part from a %L comment. Each
+# node has a `front' and a `back', and each edget attach either to
+# one or the other.
+#
+# Only segment parts with certain layer kinds are processed: by
+# default, only the empty layer kind.
+#
+# When a loc is found in the input, as one end of a segmentpart, it
+# is considered identical to a existing node (if its details are
+# sufficiently similar) or creates a new node (if its details are
+# sufficiently different). If the segmentpart's end is considered
+# identical to an existing node then the existing node's layer level
+# range is extended, but the existing node's X Y and A are not
+# modified.
+#
+# A loc and layer level are compared with a node as follows:
+#
+# The difference between each of the loc's details and the node's
+# details is computed. If any of the differences is at least the
+# min clearance, then the loc/layerb is a new node. Otherwise, all
+# of the differences must be within the max tolerance and the
+# loc/layer is the same as the node (coming out of the back if the
+# 180deg was added to make the angle difference). Otherwise it is
+# an error.
+#
+# The detail differences are:
+# Position difference: horizontal distance between loc and node
+# Angle difference: difference betwen loc's and node's A, or
+# difference minus 180deg between loc's and node's A, whichever
+# is the smaller (both reduced mod 360deg to value with
+# smallest magnitude).
+# Level difference: 0 if layer level is within node's range
+# or distance by which it is outside that range.
+
+$conf{MinClearLayer}= 6;
+$conf{MaxTolerLayer}= 4;
+$conf{MinClearDist}= 2.0;
+$conf{MaxTolerDist}= 0.2;
+$conf{MinClearAngle}= 5.0;
+$conf{MaxTolerAngle}= 0.5;
+$conf{LayerKinds}= ''; # comma-separated list
+
+our @nodes;
+# $nodes[$nodenum]{X}
+# $nodes[$nodenum]{Y}
+# $nodes[$nodenum]{A}
+# $nodes[$nodenum]{LayerMin}
+# $nodes[$nodenum]{LayerMax}
+
+sub find_node (@) {
+ my ($l,$x,$y,$a) = @_;
+ my ($any_outside_tol);
+ for ($ni=0; $ni<@nodes; $ni++) {
+ $node= $nodes[$ni];
+ $diff{Layer}= (($d = $l - $node->{LayerMin}) < 0 ? $d :
+ ($d = $l - $node->{LayerMax}) > 0 ? $d :
+ 0);
+ $diff{Dist}= sqrt(sqr($x - $node->{X}) +
+ sqr($y - $node->{Y}));
+ $diff{Angle}= $a - $node->{A}; # <-360,360>
+ if ($diff{Angle} < 0) { $diff{Angle} += 360; } # [0,360>
+ $back= $diff{Angle} >= 90 && $diff{Angle} < 270; # $back <=> [90,270>
+ if ($back) { $diff{Angle} -= 180; } # [0,90> or [270,360>
+ if ($diff{Angle} > 180) { $diff{Angle} -= 360; } # [-90,90>
+ $any_outside_clear= 0;
+ $any_outside_toler= 0;
+ foreach $k (keys %diff) {
+ if (abs($diff{$k}) >= $conf{"MinClear$k"}) {
+ $any_outside_clear=1; last;
+ } elsif (abs($diff{$k}) <= $conf{"MaxToler$k"}) {
+ } else {
+ $any_outside_toler=1;
+ }
+ }
+ if ($any_outside_clear) {
+ } else if ($any_outside_toler) {
+ die "$l,$x,$y,$a vs. $node->{LayerMin}..$node->{LayerMax}".
+ ",$node->{X},$node->{Y},$node->{A}";
+ } else {
+ if ($diff{Layer} < 0) { $node->{LayerMin}= $l }
+ if ($diff{Layer} > 0) { $node->{LayerMax}= $l }
+ return ($node,$back);
+ }
+ }
+ $node= { X => $x, Y => $y, A => $a,
+ LayerMin => $l, LayerMax => $l };
+ push @nodes, $node;
+ return ($node,0);
+}
+
+while (<>) {
+ next unless m/^\%L /;
+ die unless m/^\%L (\w+)\b/;
+ next unless $1 eq 'segmentpart';
+ die unless m/^\%L segmentpart ([A-Za-z_]*)(\d+) (\S+) ([-.eE0-9 ]+)$/;
+ ($layerkind, $level, $subsegspec, $numbers) = ($1,$2,$3,$4);
+ next unless grep { $layerkind eq $_ } split /\,/, $conf{LayerKinds};
+ @numbers = map { $_ + 0 } split / /, $numbers;
+ for ($pti=0; $pti<2; $pti++) {
+ ($node[$pti], $back[$pti])=
+ find_node($level, $numbers[($i*3)..($i*3+2)]);
+ }
+}
+
+ ($pts[0]{X}, $pts[0]{Y}, $pts[0]{A},
+ $pts[1]{X}, $pts[1]{Y}, $pts[1]{A}) =
+ $node[0]
+
+
+(\w+(?:(?:\/([A-Za-z]+)(\d+))?)?)