File Coverage

blib/lib/CircuitLayout.pm
Criterion Covered Total %
statement 1 3 33.3
branch n/a
condition n/a
subroutine 1 1 100.0
pod n/a
total 2 4 50.0


line stmt bran cond sub pod time code
1             require 5.006;
2             our $VERSION = '0.07';
3             ## Note: '@ ( # )' used by the what command E.g. what CircuitLayout.pm
4             our $revision = '@(#) $RCSfile: CircuitLayout.pm,v $ $Revision: 1.30 $ $Date: 2003-08-01 00:19:14-05 $';
5             #use Math::Trig;
6             #use Tk;
7 1     1   2324 use Tk::WorldCanvas;
  0            
  0            
8             use strict;
9              
10             our $G_epsilon = 0.00000001;
11             my $pp = 4;
12              
13             # POD documentation is sprinkled throughout the file in an
14             # attempt at Literate Programming style (which Perl partly supports ...
15             # see http://www.literateprogramming.com/ )
16             # Search for the strings '=head' or run perldoc on this file.
17              
18             # You can run this file through either pod2man or pod2html to produce
19             # documentation in manual or html file format
20              
21             =pod
22             =head1 COPYRIGHT
23              
24             Author: Ken Schumack (c) 2001-2004. All rights reserved.
25             This module is free software. It may be used, redistributed
26             and/or modified under the terms of the Perl Artistic License.
27             (see http://www.perl.com/pub/a/language/misc/Artistic.html)
28             I do ask that you please let me know if you find bugs or have
29             idea for improvements. You can reach me at Schumack@cpan.org
30             Have fun, Ken
31              
32              
33             =head1 NAME
34              
35             CircuitLayout - circuit layout module
36              
37             =head1 DESCRIPTION
38              
39             This is CircuitLayout, a module for working with circuit layout items
40             like boundaries, texts, rectangles, and srefs.
41              
42             Send feedback/suggestions to Schumack@cpan.org
43              
44             =cut
45              
46             package CircuitLayout;
47             {
48              
49             =head1 CircuitLayout::pitches
50              
51             returns string of pitches given a ref to an array of CircuitLayout::Boundary items
52              
53             =cut
54              
55             ####### CircuitLayout::Text
56             sub pitches
57             {
58             my(%arg) = @_;
59             my $direction = $arg{'-direction'};
60             if (! defined $direction)
61             {
62             print "WARNING: missing -direction arg to pitches, using 'y'\n";
63             $direction = 'y';
64             }
65             $direction = lc $direction;
66             my $boundaryRefs = $arg{'-boundaries'};
67             if (defined($boundaryRefs))
68             {
69             my $firstItem = $$boundaryRefs[0];
70             if (ref($firstItem) ne 'CircuitLayout::Boundary')
71             {
72             die "-boundaries expects ref to CircuitLayout::Boundary items array. $!";
73             }
74             }
75             my $giveTransitionPoints = $arg{'-giveTransitionPoints'};
76             $giveTransitionPoints = 0 if (! defined $giveTransitionPoints);
77              
78             my %locations=();
79             foreach my $polygon (@$boundaryRefs)
80             {
81             my $x = $polygon -> extent -> center -> x;
82             my $y = $polygon -> extent -> center -> y;
83             if ($direction eq 'x')
84             {
85             $locations{$y} .= "$x " if ((! defined $locations{$y}) || ($locations{$y} !~ m/\b$x /));
86             }
87             else
88             {
89             $locations{$x} .= "$y " if ((! defined $locations{$x}) || ($locations{$x} !~ m/\b$y /));
90             }
91             }
92             my $pitches = '';
93             my @transitionPointsArray = ();
94             foreach my $location (sort {$a <=> $b} keys %locations)
95             {
96             my @centers = split(' ',$locations{$location});
97             my $lastCenter = '';
98             foreach my $center (sort {$a <=> $b} @centers)
99             {
100             if ($lastCenter ne '')
101             {
102             my $pitch = sprintf("%0.${pp}f",$center - $lastCenter);
103             if ($pitches !~ m/\b$pitch /)
104             {
105             $pitches .= "$pitch ";
106             push @transitionPointsArray, $lastCenter;
107             }
108             }
109             $lastCenter = $center;
110             }
111             }
112             $pitches =~ s/ $//;
113             if (($pitches =~ m/ /) && $giveTransitionPoints)
114             {
115             shift @transitionPointsArray; ## 1st one is not wanted
116             my $transitionPoints = join(' ;',@transitionPointsArray);
117             $pitches .= ";$transitionPoints";
118             }
119             $pitches =~ s/ $//;
120             $pitches;
121             }
122             1;
123             }
124              
125             package CircuitLayout::Text;
126             {
127             # This is the default class for the CircuitLayout::Text object to use when all else fails.
128             $CircuitLayout::Text::DefaultClass = 'CircuitLayout::Text' unless defined $CircuitLayout::Text::DefaultClass;
129              
130             =head1 CircuitLayout::Text::new
131              
132             =head2 Usage:
133              
134             ## Coord object for CircuitLayout::Text origin coordinate...
135             my $text = new CircuitLayout::Text(-origin=>$coord,
136             -string=>$string);
137             -or-
138              
139             my @point = (0,0);
140             ## anonymous array or array ref
141             my $edge = new CircuitLayout::Edge(-origin=>\@point,
142             -string=>"VDD");
143              
144             =cut
145              
146             #### Method: new CircuitLayout::Text
147             sub new
148             {
149             my($class,%arg) = @_;
150             my $self = {};
151             bless $self,$class || ref $class || $CircuitLayout::Text::DefaultClass;
152             my $origin = $arg{'-origin'};
153             if (! defined($origin))
154             {
155             die "new CircuitLayout::Text expects origin Coord. Missing -origin => Coord $!";
156             }
157             else
158             {
159             if (ref($origin) ne 'CircuitLayout::Coord')
160             {
161             if (ref($origin) eq 'ARRAY') ## anonymous array...
162             {
163             $origin = new CircuitLayout::Coord(-x=>@$origin[0],-y=>@$origin[1]);
164             }
165             die "CircuitLayout::Text::new did not receive or could not create a coord. $!" if (ref($origin) ne 'CircuitLayout::Coord');
166             }
167             }
168             my $string = $arg{'-string'};
169             if (! defined $string)
170             {
171             $string = '';
172             }
173              
174             my $layer = $arg{'-layer'};
175             if (! defined $layer)
176             {
177             $layer = 0;
178             }
179              
180             $self -> {'PrintPrecision'} = 4; #init
181             $self -> {'Origin'} = $origin;
182             $self -> {'Layer'} = $layer;
183             $self -> {'String'} = $string;
184             $self;
185             }
186             ################################################################
187              
188             =head1 CircuitLayout::Text::display
189              
190             draws on a worldCanvas
191              
192             =cut
193              
194             ####### CircuitLayout::Text
195             sub display
196             {
197             my($self,%arg) = @_;
198             my $canvas = $arg{'-worldCanvas'};
199             if (! defined $canvas)
200             {
201             print "ERROR: missing -canvas arg to CircuitLayout::Boundary::display\n";
202             exit 2;
203             }
204            
205             my $fill = $arg{'-fill'}; ## fill color
206             my $fillColor = '';
207             if (! defined $fill)
208             {
209             $fill = undef;
210             }
211             else
212             {
213             $fillColor = $fill;
214             }
215              
216             my $showOrigin = $arg{'-showOrigin'}; ##
217             if (! defined $showOrigin)
218             {
219             $showOrigin = 0;
220             }
221              
222             my $layer = $self -> {'Layer'};
223             my $name = $arg{'-name'};
224             if (! defined $name)
225             {
226             $name = "layer $layer";
227             }
228              
229             my $visible = $arg{'-visible'};
230             if (! defined $visible)
231             {
232             $visible = 'true';
233             }
234              
235             my $type = 'text';
236             my $string = $self -> {'String'};
237              
238             my @points = ();
239             push @points,$self -> origin -> x;
240             push @points,$self -> origin -> y;
241             $canvas -> createText(
242             @points,
243             -fill => $fill,
244             -tags => [
245             "fill=$fillColor",
246             "layer=$layer",
247             'layout=true',
248             "name=$name",
249             'selected=false',
250             "type=$type",
251             "visible=$visible",
252             ],
253             -text => "$string",
254             );
255              
256             if ($showOrigin)
257             {
258             my @textOriginPoints = (); ## make a diamond
259             my ($x,$y) = @points;
260             my $halfSize = 0.01;
261             push @textOriginPoints,$x - $halfSize; push @textOriginPoints,$y;
262             push @textOriginPoints,$x ; push @textOriginPoints,$y + $halfSize;
263             push @textOriginPoints,$x + $halfSize; push @textOriginPoints,$y;
264             push @textOriginPoints,$x ; push @textOriginPoints,$y - $halfSize;
265             push @textOriginPoints,$x - $halfSize; push @textOriginPoints,$y;
266             my $fillTagColor = '';
267             $fillTagColor = $fill if (defined $fill);
268             $canvas -> createLine(
269             @textOriginPoints,
270             -fill => $fill,
271             -width => 0,
272             -capstyle => 'butt',
273             -stipple => '',
274             -tags => [
275             "fill=$fillTagColor",
276             'layout=false',
277             'type=textorigin',
278             'selected=false',
279             "visible=$visible",
280             ],
281             );
282             }
283             }
284             ################################################################
285              
286             =head1 CircuitLayout::Text::directionExtent
287              
288             =cut
289              
290             ####### CircuitLayout::Text
291             sub directionExtent
292             {
293             my ($self,%arg) = @_;
294             my $side = $arg{'-direction'}; # 'N' 'S' 'E' or 'W' ...
295             $side =~ s|^(.).*|\U$1|;
296             my ($x1,$x2,$y1,$y2);
297             my $num;
298              
299             if (($side eq 'N') || ($side eq 'S'))
300             {
301             $num = $self -> origin -> y;
302             }
303             else
304             {
305             $num = $self -> origin -> x;
306             }
307             }
308             ################################################################
309              
310             =head1 CircuitLayout::Text::printPrecision
311              
312             returns precision (integer)
313              
314             =cut
315              
316             ####### CircuitLayout::Text
317             sub printPrecision
318             {
319             my($self,%arg) = @_;
320             my $value = $arg{'-value'};
321             if (defined $value)
322             {
323             $self -> {'PrintPrecision'} = $value if ($value =~ m/^\d+$/);
324             }
325             $self -> {'PrintPrecision'};
326             }
327             ################################################################
328              
329             =head1 CircuitLayout::Text::string
330              
331             =cut
332              
333             ####### CircuitLayout::Text
334             sub string
335             {
336             my($self,%arg) = @_;
337             my $value = $arg{'-value'};
338             if (defined $value)
339             {
340             $self -> {'String'} = $value;
341             }
342             $self -> {'String'};
343             }
344             ################################################################
345              
346             =head1 CircuitLayout::Text::layer
347              
348             =cut
349              
350             ####### CircuitLayout::Text
351             sub layer
352             {
353             my($self,%arg) = @_;
354             my $value = $arg{'-value'};
355             if (defined $value)
356             {
357             $self -> {'Layer'} = $value;
358             }
359             $self -> {'Layer'};
360             }
361             ################################################################
362              
363             =head1 CircuitLayout::Text::origin
364              
365             returns origin as Coord object
366             use -value to change and pass in Coord or x,y array
367              
368             =cut
369              
370             ####### CircuitLayout::Text
371             sub origin
372             {
373             my($self,%arg) = @_;
374             my $origin = $arg{'-value'};
375             if (defined($origin))
376             {
377             if (ref($origin) ne 'CircuitLayout::Coord')
378             {
379             if (ref($origin) eq 'ARRAY') ## anonymous array...
380             {
381             $origin = new CircuitLayout::Coord(-x=>@$origin[0],-y=>@$origin[1]);
382             }
383             die "CircuitLayout::Text::origin did not receive or could not create a coord. $!" if (ref($origin) ne 'CircuitLayout::Coord');
384             }
385             $self -> {'Origin'} = $origin;
386             }
387             $self -> {'Origin'};
388             }
389             ################################################################
390              
391             ## end package CircuitLayout::Text
392             1;
393             }
394              
395             package CircuitLayout::Coord;
396             {
397             # This is the default class for the CircuitLayout::Coord object to use when all else fails.
398             $CircuitLayout::Coord::DefaultClass = 'CircuitLayout::Coord' unless defined $CircuitLayout::Coord::DefaultClass;
399              
400             use overload '==' => \&equals,
401             'bool' => sub {defined $_[0] ? 1 : 0},
402             'fallback' => 1,
403             'nomethod' => sub {die "Operator $_[3] makes no sense for CircuitLayout::Coord" };
404              
405             =head1 CircuitLayout::Coord::new
406              
407             =cut
408              
409             #### Method: new CircuitLayout::Coord
410             sub new
411             {
412             my($class,%arg) = @_;
413             my $self = {};
414             bless $self,$class || ref $class || $CircuitLayout::Coord::DefaultClass;
415             my $resolution = $arg{'-resolution'};
416             if (! defined $resolution)
417             {
418             $resolution = 0.001;
419             }
420             die "new CircuitLayout::Coord expects a positive real resolution. Missing -resolution => #.# $!" if (("$resolution" !~ m|^\d*\.?\d+|)||($resolution<=0));
421             my $x = $arg{'-x'};
422             my $y = $arg{'-y'};
423             if (! ((defined $x)&&(defined $y)))
424             {
425             die "new CircuitLayout::Coord expects x and y value. Missing -x => #.# and or -y => #.# $!";
426             }
427             $self -> {'Resolution'} = $resolution;
428             $self -> {'PrintPrecision'} = 4; #init
429             my $pp1 = $self -> printPrecision + 1;
430             $x = sprintf("%0.${pp1}f",$x);
431             $y = sprintf("%0.${pp1}f",$y);
432             $self -> {'X'} = $x;
433             $self -> {'Y'} = $y;
434             $self;
435             }
436             ################################################################
437              
438             sub directionExtent
439             {
440             my ($self,%arg) = @_;
441             CircuitLayout::Edge::directionExtent($self,%arg);
442             }
443              
444             =head1 CircuitLayout::Coord::printPrecision
445              
446             returns precision (integer)
447              
448             =cut
449              
450             ####### CircuitLayout::Coord
451             sub printPrecision
452             {
453             my($self,%arg) = @_;
454             my $value = $arg{'-value'};
455             if (defined $value)
456             {
457             $self -> {'PrintPrecision'} = $value if ($value =~ m/^\d+$/);
458             }
459             $self -> {'PrintPrecision'};
460             }
461             ################################################################
462              
463             =head1 CircuitLayout::Coord::coordSubtract
464              
465             =cut
466              
467             ####### CircuitLayout::Coord
468             sub coordSubtract($$$)
469             {
470             my $self = shift;
471             my $coordA = shift;
472             my $coordB = shift;
473             my $x = $coordA -> x;
474             my $y = $coordA -> y;
475             $x -= $coordB -> x;
476             $y -= $coordB -> y;
477             my $result = new CircuitLayout::Coord(-x=>$x,-y=>$y);
478             $result;
479             }
480             ################################################################
481              
482             =head1 CircuitLayout::Coord::onGrid
483              
484             =cut
485              
486             ####### CircuitLayout::Coord
487             sub isOnGrid
488             {
489             my ($self,%arg) = @_;
490             my $xOffset = $arg{'-xOffset'};
491             my $yOffset = $arg{'-yOffset'};
492             my $xGrid = $arg{'-xGrid'};
493             my $yGrid = $arg{'-yGrid'};
494             if (! ((defined $xOffset) &&
495             (defined $yOffset) &&
496             (defined $xGrid) &&
497             (defined $yGrid) )
498             )
499             {
500             die "CircuitLayout::Coord isOnGrid expects -xOffset -yOffset -xGrid and -yGrid args $!";
501             return 0;
502             }
503             if ($xGrid == 0.0 || $yGrid == 0.0)
504             {
505             die "CircuitLayout::Coord isOnGrid was passed in 0.0 for an a or y grid $!";
506             return 0;
507             }
508             my $pp1 = ($self -> printPrecision) + 1;
509             my $offsetSelfX = sprintf("%0.${pp1}f",(abs($self -> x) - $xOffset));
510             my $offsetSelfY = sprintf("%0.${pp1}f",(abs($self -> y) - $yOffset));
511             if (
512             (sprintf("%0.${pp1}f",($offsetSelfX / $xGrid)) != int(($offsetSelfX / $xGrid) + $G_epsilon)) ||
513             (sprintf("%0.${pp1}f",($offsetSelfY / $yGrid)) != int(($offsetSelfY / $yGrid) + $G_epsilon))
514             )
515             {
516             return 0;
517             }
518             1;
519             }
520             ################################################################
521              
522             =head1 CircuitLayout::Coord::resolution
523              
524             =cut
525              
526             ####### CircuitLayout::Coord
527             sub resolution
528             {
529             my $self = shift;
530             $self -> {'Resolution'};
531             }
532             ################################################################
533              
534             =head1 CircuitLayout::Coord::x
535              
536             =cut
537              
538             ####### CircuitLayout::Coord
539             sub x
540             {
541             my $self = shift;
542             $self -> {'X'};
543             }
544             ################################################################
545              
546             =head1 CircuitLayout::Coord::y
547              
548             =cut
549              
550             ####### CircuitLayout::Coord
551             sub y
552             {
553             my $self = shift;
554             $self -> {'Y'};
555             }
556             ################################################################
557              
558             =head1 CircuitLayout::Coord::scale
559              
560             =cut
561              
562             ####### CircuitLayout::Coord
563             sub scale
564             {
565             my ($self,%arg) = @_;
566             my $factor = $arg{'-factor'};
567             if (! defined $factor)
568             {
569             $factor=1;
570             }
571             if ($factor <= 0)
572             {
573             die "CircuitLayout::Coord scale expects a positive factor -factor => #.# $!";
574             }
575            
576             my $snap = $arg{'-snap'};
577             if (! defined $snap)
578             {
579             $snap=0;
580             }
581             if ($snap < 0)
582             {
583             die "CircuitLayout::Coord scale expects a positive snap -snap => #.# $!";
584             }
585            
586             my $resolution=$self -> resolution;
587             ### written this way to make a separate x/y snap/factor easy to do....later :->
588             my $x = $self -> x;
589             my $y = $self -> y;
590             $x *= $factor;
591             $y *= $factor;
592            
593             if ($snap)
594             {
595             $x = snapNum($x,$snap,$resolution);
596             $y = snapNum($y,$snap,$resolution);
597             }
598             $self -> {'X'} = $x;
599             $self -> {'Y'} = $y;
600             $self;
601             }
602             ################################################################
603              
604             =head1 CircuitLayout::Coord::snapNum
605              
606             =cut
607              
608             ####### CircuitLayout::Coord
609             sub snapNum($$$)
610             {
611             my $num=shift;
612             my $snap=shift;
613             my $resolution=shift;
614             $snap =~ s|0+$||;
615             my $snapLength = length("$snap");
616             my $lean=1; ##init
617             $lean = -1 if($num < 0);
618             $num = int(($num*(1/$resolution))+0.5);
619             ## snap to grid..
620             my $littlePart=substr($num,-$snapLength,$snapLength);
621             if($num<0)
622             {
623             $littlePart = -$littlePart;
624             }
625             $littlePart = int(($littlePart/$snap)+(0.5*$lean))*$snap;
626             my $bigPart=substr($num,0,-$snapLength);
627             if ($bigPart =~ m|^[-]?$|)
628             {
629             $bigPart=0;
630             }
631             else
632             {
633             $bigPart *= 10**$snapLength;
634             }
635             $num = ($bigPart + $littlePart) * $resolution;
636             }
637             ################################################################
638            
639             =head1 CircuitLayout::Coord::printableCoords
640              
641             returns string in "x1,y1"
642             where x and y print precision is controlled by objects printPrecision
643              
644             Note: returns just one coordinate but method name
645             is plural none the less to be consistant with other methods.
646              
647             =cut
648              
649             ####### Coord
650             sub printableCoords
651             {
652             my $self = shift;
653             my $pp = $self -> printPrecision;
654             sprintf("%0.${pp}f",$self -> x).','.sprintf("%0.${pp}f",$self -> y);
655             }
656             ################################################################
657              
658             =head1 CircuitLayout::Coord::equals
659              
660             =cut
661              
662              
663             ####### CircuitLayout::Coord::equals
664             sub equals
665             {
666             my($self,$ref) = @_;
667             my ($x1,$x2,$y1,$y2);
668             my $result = 0;
669             if (ref $ref eq 'CircuitLayout::Coord')
670             {
671             $x2 = $ref -> x;
672             $y2 = $ref -> y;
673             }
674             elsif (ref $ref eq 'ARRAY') ## anonymous array...
675             {
676             $x2 = @$ref[0];
677             $y2 = @$ref[1];
678              
679             }
680             else
681             {
682             die "Coord::equals did not receive a CircuitLayout::Coord or anonymous/reference array. $!";
683             }
684             $x1 = $self -> x;
685             $y1 = $self -> y;
686              
687             ## use sprintf to handle binary representation errors
688             my $pp1 = $self -> printPrecision + 1;
689            
690             my $x1String = sprintf("%0.${pp1}f",$x1);
691             my $y1String = sprintf("%0.${pp1}f",$y1);
692             my $x2String = sprintf("%0.${pp1}f",$x2);
693             my $y2String = sprintf("%0.${pp1}f",$y2);
694              
695             $result = 1 if (($x1String eq $x2String) && ($y1String eq $y2String));
696             $result;
697             }
698             ################################################################
699              
700             ## end package CircuitLayout::Coord
701             1;
702             }
703              
704             package CircuitLayout::Edge;
705             {
706             # This is the default class for the CircuitLayout::Edge object to use when all else fails.
707             $CircuitLayout::Edge::DefaultClass = 'CircuitLayout::Edge' unless defined $CircuitLayout::Edge::DefaultClass;
708              
709             =head1 CircuitLayout::Edge::new
710              
711             =head2 Usage:
712              
713             ## CircuitLayout::Coord object for Lower Left Coordinate...
714             my $edge = new CircuitLayout::Edge(-startCoord=>$coord1,
715             -endCoord=>$coord2);
716             -or-
717              
718             my @startPoint = (0,0);
719             ## anonymous array or array ref
720             my $edge = new CircuitLayout::Edge(-startCoord=>\@startPoint,
721             -endCoord=>[2.3,4.5]);
722              
723             =cut
724              
725             #### Method: new CircuitLayout::Edge
726             sub new
727             {
728             my($class,%arg) = @_;
729             my $self = {};
730             bless $self,$class || ref $class || $CircuitLayout::Edge::DefaultClass;
731             my $startCoord = $arg{'-startCoord'};
732             my $endCoord = $arg{'-endCoord'};
733             my @coords;
734             if (! ((defined $startCoord)&&(defined $endCoord)))
735             {
736             die "new CircuitLayout::Edge expects start and end Coords. Missing -startCoord => CircuitLayout::Coord and or -endCoord => CircuitLayout::Coord $!";
737             }
738             if (ref($startCoord) ne 'CircuitLayout::Coord')
739             {
740             if (ref($startCoord) eq 'ARRAY') ## anonymous array...
741             {
742             $startCoord = new CircuitLayout::Coord(-x=>@$startCoord[0],-y=>@$startCoord[1]);
743             }
744             die "CircuitLayout::Edge::new did not receive or could not create a coord. $!" if (ref($startCoord) ne 'CircuitLayout::Coord');
745             }
746             if (ref($endCoord) ne 'CircuitLayout::Coord')
747             {
748             if (ref($endCoord) eq 'ARRAY') ## anonymous array...
749             {
750             $endCoord = new CircuitLayout::Coord(-x=>@$endCoord[0],-y=>@$endCoord[1]);
751             }
752             die "CircuitLayout::Edge::new did not receive or could not create a coord. $!" if (ref($endCoord) ne 'CircuitLayout::Coord');
753             }
754             $self -> {'PrintPrecision'} = 4;
755             $self -> {'StartCoord'} = $startCoord;
756             $self -> {'EndCoord'} = $endCoord;
757             push @coords,$startCoord;
758             push @coords,$endCoord;
759             $self -> {'Coords'} = \@coords;
760             $self;
761             }
762             ################################################################
763              
764             =head1 CircuitLayout::Edge::coords
765              
766             =cut
767              
768             ####### CircuitLayout::Edge
769             sub coords
770             {
771             my $self = shift;
772             my $coords=$self -> {'Coords'};
773             my @coords=@$coords;
774             @coords;
775             }
776             ################################################################
777              
778             =head1 CircuitLayout::Edge::printPrecision
779              
780             returns precision (integer)
781              
782             =cut
783              
784             ####### CircuitLayout::Edge
785             sub printPrecision
786             {
787             my($self,%arg) = @_;
788             my $value = $arg{'-value'};
789             if (defined $value)
790             {
791             $self -> {'PrintPrecision'} = $value if ($value =~ m/^\d+$/);
792             }
793             $self -> {'PrintPrecision'};
794             }
795             ################################################################
796              
797             =head1 CircuitLayout::Edge::isLeft
798              
799             =head2 Usage:
800              
801             my $isLeft = $edge -> isLeft(-coord=>$coord);
802              
803             =head2 Synopsis:
804              
805             =cut
806              
807             ####### CircuitLayout::Edge
808             sub isLeft
809             {
810             my ($self,%arg) = @_;
811             my $coordRef = $arg{'-coord'};
812             my ($x1,$x2,$y1,$y2,$x3,$y3);
813             $x1 = $self -> startCoord -> x;
814             $x2 = $self -> endCoord -> x;
815             $y1 = $self -> startCoord -> y;
816             $y2 = $self -> endCoord -> y;
817             if (defined $coordRef)
818             {
819             if (ref $coordRef ne 'CircuitLayout::Coord') ## anonymous array...
820             {
821             $coordRef = new CircuitLayout::Coord(-x=>@$coordRef[0],-y=>@$coordRef[1]);
822             }
823             }
824             $x3 = $coordRef -> x;
825             $y3 = $coordRef -> y;
826             my $result=( ($x2 - $x1) * ($y3 - $y1) - ($x3 - $x1) * ($y2 - $y1) );
827             return 1 if ($result > $G_epsilon);
828             return -1 if ($result < (0 - $G_epsilon));
829             return 0;
830             }
831              
832             ################################################################
833              
834              
835             =head1 CircuitLayout::Edge::direction
836              
837             =head2 Usage:
838              
839             my $edgeDirection = $edge -> direction;
840              
841             =head2 Synopsis:
842              
843             Returns one of 8 compass directions: 'N','NE','E','SE','S','SW','W','NW'
844              
845             S[0,0],-endCoord=E[5,5]);>
846              
847             S direction; >## prints 'NE';
848              
849             =cut
850              
851             ####### CircuitLayout::Edge
852             sub direction
853             {
854             my $self = shift;
855             my ($x1,$x2,$y1,$y2);
856             $x1 = $self -> startCoord -> x;
857             $x2 = $self -> endCoord -> x;
858             $y1 = $self -> startCoord -> y;
859             $y2 = $self -> endCoord -> y;
860             my $compass='';
861             if ($y2 > $y1) #NW N NE
862             {
863             $compass = 'N' if ($x2 == $x1);
864             $compass = 'NW' if ($x2 < $x1);
865             $compass = 'NE' if ($x2 > $x1);
866             }
867             elsif ($y2 < $y1) # SW S SE
868             {
869             $compass = 'S' if ($x2 == $x1);
870             $compass = 'SW' if ($x2 < $x1);
871             $compass = 'SE' if ($x2 > $x1);
872             }
873             else # W E
874             {
875             $compass = 'W' if ($x2 < $x1);
876             $compass = 'E' if ($x2 > $x1);
877             }
878             $compass;
879             }
880             ################################################################
881              
882             =head1 CircuitLayout::Edge::is45multiple
883              
884             =head2 Usage:
885              
886             my $test = $edge -> is45multiple;
887              
888             =head2 Synopsis:
889              
890             Returns true or false ( 1 or 0 ) depending on whether edge is a
891             45 degree multiple
892              
893             S[0,0],-endCoord=E[5,5]);>
894              
895             S is45multiple; >## prints 1;
896              
897             =cut
898              
899             ####### CircuitLayout::Edge
900             sub is45multiple
901             {
902             my $self = shift;
903             my ($x1,$x2,$y1,$y2);
904             $x1 = $self -> startCoord -> x;
905             $x2 = $self -> endCoord -> x;
906             $y1 = $self -> startCoord -> y;
907             $y2 = $self -> endCoord -> y;
908             return 1 if ($x1 == $x2);
909             return 1 if ($y1 == $y2);
910             my $pp1 = $self -> printPrecision + 1;
911             my $ax = sprintf("%0.${pp1}f",abs($x1 - $x2));
912             my $ay = sprintf("%0.${pp1}f",abs($y1 - $y2));
913             return 1 if ($ax == $ay);
914              
915             return 0;
916             }
917             ################################################################
918              
919             =head1 CircuitLayout::Edge::xIntersection
920              
921             Returns x value where CircuitLayout::Edge actually crosses x axis
922             or would cross if it was extended.
923              
924             =cut
925              
926             ####### CircuitLayout::Edge
927             sub xIntersection
928             {
929             my $self = shift;
930             my $x1 = $self -> startCoord -> x;
931             my $x2 = $self -> endCoord -> x;
932             my $y1 = $self -> startCoord -> y;
933             my $y2 = $self -> endCoord -> y;
934             return undef() if ($y2 == $y1);
935             (($x1 * $y2) - ($x2 * $y1)) / ($y2 - $y1);
936             }
937             ################################################################
938              
939             =head1 CircuitLayout::Edge::straddleTouchXray
940              
941             Returns 0 or 1 depending on whether CircuitLayout::Edge straddles or touches horizontal X ray.
942             Default X ray is X axis (y value==0)
943              
944             $edge -> straddleTouchXray;
945             -or-
946             $edge -> straddleTouchXray(-yValue=>4.3);
947              
948              
949             =cut
950              
951             ####### CircuitLayout::Edge
952             sub straddleTouchXray
953             {
954             my ($self,%arg) = @_;
955             my $yValue = $arg{'-yValue'};
956             if (! defined $yValue)
957             {
958             $yValue = 0.0;
959             }
960             my $y1 = $self -> startCoord -> y;
961             my $y2 = $self -> endCoord -> y;
962             my $result=0;
963             $result = 1 if ((($y1 > $yValue) && ($y2 <= $yValue)) ||
964             (($y2 > $yValue) && ($y1 <= $yValue)));
965             $result;
966             }
967             ################################################################
968              
969             =head1 CircuitLayout::Edge::printableCoords
970              
971             Returns CircuitLayout::Edge as 'x1,y1;x2,y2' string.
972              
973             print $edge -> printableCoords;
974              
975             =cut
976              
977             ####### CircuitLayout::Edge
978             sub printableCoords
979             {
980             my $self = shift;
981             $self -> {'StartCoord'} -> {'X'}.','.$self -> {'StartCoord'} -> {'Y'}.';'.$self -> {'EndCoord'} -> {'X'}.','.$self -> {'EndCoord'} -> {'Y'};
982             }
983             ################################################################
984              
985             =head1 CircuitLayout::Edge::startCoord
986              
987             Returns 1st edge coordinate as a Coord.
988              
989             =cut
990              
991             ####### CircuitLayout::Edge
992             sub startCoord
993             {
994             my $self = shift;
995             $self -> {'StartCoord'};
996             }
997             ################################################################
998              
999             =head1 CircuitLayout::Edge::endCoord
1000              
1001             Returns last edge coordinate as a Coord.
1002              
1003             =cut
1004              
1005             ####### CircuitLayout::Edge
1006             sub endCoord
1007             {
1008             my $self = shift;
1009             $self -> {'EndCoord'};
1010             }
1011             ################################################################
1012              
1013             =head1 CircuitLayout::Coord::directionExtent CircuitLayout::Edge::directionExtent CircuitLayout::Boundary::directionExtent
1014              
1015             =head2 Usage:
1016              
1017             my $edgeExtent = $edge -> directionExtent;
1018              
1019             =head2 Synopsis:
1020              
1021             Returns position (real number) of edge in one of 4 magor compass directions: 'N','E','S','W'
1022              
1023             S[0,0],-endCoord=E[0,5]);>
1024              
1025             S directionExtent(-direction=E'N'); >## prints 5;
1026              
1027             =cut
1028              
1029             ####### CircuitLayout::Edge Coord Boundary
1030             sub directionExtent
1031             {
1032             my ($self,%arg) = @_;
1033             my $side = $arg{'-direction'}; # 'N' 'S' 'E' or 'W' ...
1034             $side =~ s|^(.).*|\U$1|;
1035             my ($x1,$x2,$y1,$y2);
1036             my $num;
1037              
1038             if (ref($self) eq 'CircuitLayout::Coord')
1039             {
1040             if (($side eq 'N') || ($side eq 'S'))
1041             {
1042             $num = $self -> y;
1043             }
1044             else
1045             {
1046             $num = $self -> x;
1047             }
1048             }
1049             else
1050             {
1051             my @edges = ($self); ## default;
1052             @edges = $self -> edges if ((ref($self) eq 'CircuitLayout::Boundary') || (ref($self) eq 'CircuitLayout::Rectangle'));
1053              
1054             foreach my $edge (@edges)
1055             {
1056             my $edgeNum;
1057             $x1 = $edge -> startCoord -> x;
1058             $y1 = $edge -> startCoord -> y;
1059             $x2 = $edge -> endCoord -> x;
1060             $y2 = $edge -> endCoord -> y;
1061             if ($side eq 'N')
1062             {
1063             $edgeNum = $y1 > $y2 ? $y1 : $y2;
1064             $num = $edgeNum if (! defined $num);
1065             $num = $edgeNum if ($edgeNum > $num);
1066             }
1067             elsif ($side eq 'S')
1068             {
1069             $edgeNum = $y1 < $y2 ? $y1 : $y2;
1070             $num = $edgeNum if (! defined $num);
1071             $num = $edgeNum if ($edgeNum < $num);
1072             }
1073             elsif ($side eq 'E')
1074             {
1075             $edgeNum = $x1 > $x2 ? $x1 : $x2;
1076             $num = $edgeNum if (! defined $num);
1077             $num = $edgeNum if ($edgeNum > $num);
1078             }
1079             elsif ($side eq 'W')
1080             {
1081             $edgeNum = $x1 < $x2 ? $x1 : $x2;
1082             $num = $edgeNum if (! defined $num);
1083             $num = $edgeNum if ($edgeNum < $num);
1084             }
1085             }
1086             }
1087             $num;
1088             }
1089             ################################################################
1090              
1091             sub triangleArea($$$$$$)
1092             {
1093             my ($x0,$y0,$x1,$y1,$x2,$y2) = @_;
1094              
1095             ( ($x1 - $x0) * ($y2 - $y0) -
1096             ($x2 - $x0) * ($y1 - $y0)
1097             ) / 2.0;
1098             }
1099             ################################################################
1100              
1101             sub area
1102             {
1103             my ($self,%arg) = @_;
1104             my @coords = $self -> coords;
1105             my $area = 0;
1106             my $numCoords = $#coords;
1107             for (my $i=1; $i<($numCoords - 1); $i++)
1108             {
1109             $area += triangleArea($coords[0]->x, $coords[0]->y,
1110             $coords[$i]->x, $coords[$i]->y,
1111             $coords[$i+1]->x, $coords[$i+1]->y);
1112             }
1113             abs($area);
1114             }
1115             ################################################################
1116              
1117             =head1 CircuitLayout::Edge::length CircuitLayout::Boundary::length
1118              
1119             =head2 Usage:
1120              
1121             my $edgeLength = $edge -> length;
1122              
1123             =head2 Synopsis:
1124              
1125             Returns length of edge
1126              
1127             S[0,1],-endCoord=E[0,5]);>
1128              
1129             S length(); >## prints 4;
1130              
1131             =cut
1132              
1133             ####### CircuitLayout::Edge
1134             sub length
1135             {
1136             my ($self,%arg) = @_;
1137            
1138             my @edges = ($self); ## default;
1139             @edges = $self -> edges if ((ref($self) eq 'CircuitLayout::Boundary') || (ref($self) eq 'CircuitLayout::Rectangle'));
1140              
1141             my $edgeLength = 0.0;
1142             foreach my $edge (@edges)
1143             {
1144             my $x1 = $edge -> startCoord -> x;
1145             my $y1 = $edge -> startCoord -> y;
1146             my $x2 = $edge -> endCoord -> x;
1147             my $y2 = $edge -> endCoord -> y;
1148             $edgeLength += CircuitLayout::distance($x1, $y1, $x2, $y2);
1149             }
1150              
1151             $edgeLength;
1152             }
1153             ################################################################
1154              
1155             =head1 CircuitLayout::Edge::lengthAtExtent CircuitLayout::Boundary::lengthAtExtent
1156              
1157             =head2 Usage:
1158              
1159             my $edgeExtentLength = $edge -> lengthAtExtent;
1160              
1161             =head2 Synopsis:
1162              
1163             Returns position (real number) of edge length at maximum point in one of 4 magor compass directions: 'N','E','S','W'
1164              
1165             S[0,1],-endCoord=E[0,5]);>
1166              
1167             S lengthAtExtent(-direction=E'N'); >## prints 4;
1168              
1169             =cut
1170              
1171             ####### CircuitLayout::Edge
1172             sub lengthAtExtent
1173             {
1174             my ($self,%arg) = @_;
1175             my $side = $arg{'-direction'}; # 'N' 'S' 'E' or 'W' ...
1176             $side =~ s|^(.).*|\U$1|;
1177             my ($x1,$x2,$y1,$y2);
1178             my $num;
1179             my $position2Find = $self -> directionExtent(-direction=>$side);
1180             my @edges = ($self); ## default;
1181             @edges = $self -> edges if ((ref($self) eq 'CircuitLayout::Boundary') || (ref($self) eq 'CircuitLayout::Rectangle'));
1182              
1183             my $length = 0.0;
1184             my $edgeLength = 0.0;
1185             foreach my $edge (@edges)
1186             {
1187             my $edgeNum;
1188             $x1 = $edge -> startCoord -> x;
1189             $y1 = $edge -> startCoord -> y;
1190             $x2 = $edge -> endCoord -> x;
1191             $y2 = $edge -> endCoord -> y;
1192             if ($side eq 'N')
1193             {
1194             $edgeNum = $y1 > $y2 ? $y1 : $y2;
1195             $num = $edgeNum if (! defined $num);
1196             $num = $edgeNum if ($edgeNum > $num);
1197             $edgeLength = abs($x1 - $x2) if ($num == $position2Find);
1198             }
1199             elsif ($side eq 'S')
1200             {
1201             $edgeNum = $y1 < $y2 ? $y1 : $y2;
1202             $num = $edgeNum if (! defined $num);
1203             $num = $edgeNum if ($edgeNum < $num);
1204             $edgeLength = abs($x1 - $x2) if ($num == $position2Find);
1205             }
1206             elsif ($side eq 'E')
1207             {
1208             $edgeNum = $x1 > $x2 ? $x1 : $x2;
1209             $num = $edgeNum if (! defined $num);
1210             $num = $edgeNum if ($edgeNum > $num);
1211             $edgeLength = abs($y1 - $y2) if ($num == $position2Find);
1212             }
1213             elsif ($side eq 'W')
1214             {
1215             $edgeNum = $x1 < $x2 ? $x1 : $x2;
1216             $num = $edgeNum if (! defined $num);
1217             $num = $edgeNum if ($edgeNum < $num);
1218             $edgeLength = abs($y1 - $y2) if ($num == $position2Find);
1219             }
1220              
1221             $length = $edgeLength if ($edgeLength > $length);
1222             }
1223             my $pp1 = $self -> printPrecision + 1;
1224             sprintf("%0.${pp1}f",$length);
1225             }
1226             ################################################################
1227              
1228             =head1 CircuitLayout::Edge::inside
1229              
1230             =head2 Usage:
1231              
1232             print 'inside == true' if ($edge -> inside(-coord => $coord);
1233              
1234             =head2 Synopsis:
1235              
1236             Returns 0 | 1 depending on whether coord is inside of edge
1237              
1238             =cut
1239              
1240             ####### CircuitLayout::Edge
1241             sub inside
1242             {
1243             my ($self,%arg) = @_;
1244             my $coordRef = $arg{'-coord'};
1245             if (defined $coordRef)
1246             {
1247             if (ref $coordRef ne 'CircuitLayout::Coord') ## anonymous array...
1248             {
1249             $coordRef = new CircuitLayout::Coord(-x=>@$coordRef[0],-y=>@$coordRef[1]);
1250             }
1251             }
1252             my ($cx,$cy,$x1,$x2,$y1,$y2);
1253             $cx = $coordRef -> x;
1254             $cy = $coordRef -> y;
1255             $x1 = $self -> startCoord -> x;
1256             $x2 = $self -> endCoord -> x;
1257             $y1 = $self -> startCoord -> y;
1258             $y2 = $self -> endCoord -> y;
1259             if (
1260             ($cx < $x1 && $cx < $x2) ||
1261             ($cx > $x1 && $cx > $x2) ||
1262             ($cy < $y1 && $cy < $y2) ||
1263             ($cy > $y1 && $cy > $y2)
1264             )
1265             {
1266             return 0;
1267             }
1268             #( abs(atan2($y1,$x1)) != abs(atan2($cy,$cx)) )
1269             ## TODO handle cx,cy = 0,0 and edge passes through it....
1270             return 1; ## made it...
1271             }
1272             ################################################################
1273              
1274             ## end package CircuitLayout::Edge
1275             1;
1276             }
1277              
1278             package CircuitLayout::Path;
1279             {
1280             use base ('CircuitLayout::Edge'); ## inherit some stuff
1281              
1282             # This is the default class for the Path object to use when all else fails.
1283             $CircuitLayout::Path::DefaultClass = 'CircuitLayout::Path' unless defined $CircuitLayout::Path::DefaultClass;
1284              
1285             use overload '==' => \&equals,
1286             'fallback' => 1,
1287             'nomethod' => sub {die "Operator $_[3] makes no sense for CircuitLayout::Path" };
1288              
1289             =head1 CircuitLayout::Path::new
1290              
1291             =head2 Usage:
1292              
1293             ## CircuitLayout::Coord object for Lower Left Coordinate...
1294             my $path = new CircuitLayout::Path(
1295              
1296             =cut
1297              
1298             #### Method: new CircuitLayout::Path
1299             sub new
1300             {
1301             my($class,%arg) = @_;
1302             my $self = {};
1303             bless $self,$class || ref $class || $CircuitLayout::DefaultClass;
1304             my $numCoords=0;
1305             my @coords;
1306             my @edges;
1307             my @revXy;
1308             my $x;
1309             my $y;
1310             my $coordA;
1311             my $coordB;
1312             my $edge;
1313             my @xy;
1314             my $coordRef = $arg{'-coords'};
1315             if (defined $coordRef)
1316             {
1317             foreach my $coord (@$coordRef)
1318             {
1319             push @xy,$coord->x;
1320             push @xy,$coord->y;
1321             }
1322             }
1323             else
1324             {
1325             @xy = $arg{'-xy'};
1326             }
1327             my $xy = '';
1328             my $numValues = 0;
1329             if ((defined $xy[0])&&($xy[0] ne ''))
1330             {
1331             $xy = $xy[0];
1332             $numValues = @$xy;
1333             if ($numValues) ## passed in anonymous array
1334             {
1335             @xy = @$xy; ## deref
1336             }
1337             else
1338             {
1339             $numValues = @xy;
1340             }
1341             }
1342             else
1343             {
1344             die "new expects xy array or CircuitLayout::Coord reference. Missing -xy => \\\@array $!";
1345             }
1346             die "new expects an even sized array to -xy => \\\@array $!" if ($numValues % 2);
1347              
1348             my $width = $arg{'-width'};
1349             if (! defined $width)
1350             {
1351             $width = 0;
1352             }
1353              
1354             my $layer = $arg{'-layer'};
1355             if (! defined $layer)
1356             {
1357             $layer = 0;
1358             }
1359              
1360             my $dataType = $arg{'-dataType'};
1361             if (! defined $dataType)
1362             {
1363             $dataType = 0;
1364             }
1365              
1366             my $pathType = $arg{'-pathType'};
1367             if (! defined $pathType)
1368             {
1369             $pathType = 0; ## 0, 1, 2, 4
1370             }
1371              
1372             my $group = $arg{'-group'};
1373             if (! defined $group)
1374             {
1375             $group = '';
1376             }
1377              
1378             my $net = $arg{'-net'};
1379             if (! defined $net)
1380             {
1381             $net = $arg{'-node'}; ## OLD code may use this ## TODO
1382             }
1383             if (! defined $net)
1384             {
1385             $net = '';
1386             }
1387              
1388             my $property = $arg{'-property'};
1389             if (! defined $property)
1390             {
1391             $property = '';
1392             }
1393              
1394             @revXy = reverse @xy;
1395             $numCoords = ($#revXy + 1)/2;
1396             my $coordCnt=0;
1397             my $firstCoord;
1398             my $lastCoord;
1399             while ($#revXy>=0)
1400             {
1401             $x=pop @revXy;
1402             $y=pop @revXy;
1403             if (! ($coordCnt % 2))
1404             {
1405             $coordA = new CircuitLayout::Coord(-x=>$x,-y=>$y);
1406             push @coords,$coordA;
1407             if (! $coordCnt)
1408             {
1409             $firstCoord = $coordA;
1410             }
1411             else
1412             {
1413             $edge = new CircuitLayout::Edge(-startCoord=>$coordB,-endCoord=>$coordA);
1414             push @edges,$edge;
1415             }
1416             $lastCoord = $coordA;
1417             }
1418             else
1419             {
1420             $coordB = new CircuitLayout::Coord(-x=>$x,-y=>$y);
1421             push @coords,$coordB;
1422             $edge = new CircuitLayout::Edge(-startCoord=>$coordA,-endCoord=>$coordB);
1423             push @edges,$edge;
1424             $lastCoord = $coordB;
1425             }
1426             $coordCnt++;
1427             }
1428             $self -> {'PrintPrecision'} = 4;
1429             $self -> {'cPtr'} = 0; ## for coords
1430             $self -> {'ePtr'} = 0; ## for edges
1431             $self -> {'NumCoords'} = $numCoords;
1432             $self -> {'XYs'} = \@xy;
1433             $self -> {'Coords'} = \@coords;
1434             $self -> {'Width'} = $width;
1435             $self -> {'Edges'} = \@edges;
1436             $self -> {'Layer'} = $layer;
1437             $self -> {'DataType'} = $dataType;
1438             $self -> {'PathType'} = $pathType;
1439             $self -> {'Net'} = $net;
1440             $self -> {'Group'} = $group;
1441             $self -> {'Property'} = $property;
1442             $self -> {'bgnExt'} = 0; ## TODO
1443             $self -> {'endExt'} = 0; ## TODO GDS2 path type 4
1444            
1445             $self -> {'Extent'} = ''; ## set when needed
1446              
1447             $self;
1448             }
1449              
1450             =head1 CircuitLayout::Path::display
1451              
1452             draws on a worldCanvas
1453              
1454             =cut
1455              
1456             ####### CircuitLayout::Path
1457             sub display
1458             {
1459             my($self,%arg) = @_;
1460             my $canvas = $arg{'-worldCanvas'};
1461             if (! defined $canvas)
1462             {
1463             print "ERROR: missing -canvas arg to CircuitLayout::Boundary::display\n";
1464             exit 2;
1465             }
1466            
1467             my $stippleFile = $arg{'-stippleFile'};
1468             if ((defined $stippleFile) && (-f $stippleFile)) ## xbitmap file
1469             {
1470             $stippleFile = "\@$stippleFile";
1471             }
1472             else
1473             {
1474             $stippleFile = '';
1475             }
1476              
1477             my $fill = $arg{'-fill'}; ## fill color
1478             my $fillColor = '';
1479             if (! defined $fill)
1480             {
1481             $fill = undef;
1482             }
1483             else
1484             {
1485             $fillColor = $fill;
1486             }
1487              
1488             my $layer = $self -> {'Layer'};
1489              
1490             my $name = $arg{'-name'};
1491             if (! defined $name)
1492             {
1493             $name = "layer $layer";
1494             }
1495              
1496             my $visible = $arg{'-visible'};
1497             if (! defined $visible)
1498             {
1499             $visible = 'true';
1500             }
1501              
1502             my $width = $self -> {'Width'};
1503             my $type = 'path';
1504              
1505             my @points = @{$self -> {'XYs'}};
1506            
1507             my $capstyle = 'butt'; ## TODO
1508             $canvas -> createLine(
1509             @points,
1510             -fill => $fillColor,
1511             -width => $width,
1512             -capstyle => $capstyle,
1513             -stipple => "$stippleFile",
1514             -tags => [
1515             "fill=$fill",
1516             "layer=$layer",
1517             'layout=true',
1518             "name=$name",
1519             'selected=false',
1520             "stipple=$stippleFile",
1521             "type=$type",
1522             "visible=$visible",
1523             ],
1524             );
1525             }
1526             ################################################################
1527              
1528             ## end package CircuitLayout::Path
1529             1;
1530             }
1531              
1532              
1533             package CircuitLayout::Rectangle;
1534             {
1535             use base ('CircuitLayout::Edge'); ## inherit some stuff
1536              
1537             # This is the default class for the Rectangle object to use when all else fails.
1538             $CircuitLayout::Rectangle::DefaultClass = 'CircuitLayout::Rectangle' unless defined $CircuitLayout::Rectangle::DefaultClass;
1539              
1540             use overload '==' => \&equals,
1541             'fallback' => 1,
1542             'nomethod' => sub {die "Operator $_[3] makes no sense for CircuitLayout::Rectangle" };
1543              
1544             =head1 CircuitLayout::Rectangle::new
1545              
1546             =head2 Usage:
1547              
1548             ## CircuitLayout::Coord object for Lower Left Coordinate...
1549             my $rect = new CircuitLayout::Rectangle(-llCoord=>$coord1,
1550             -urCoord=>$coord2);
1551             -or-
1552              
1553             my @llPoint = (0,0);
1554             ## anonymous array or array ref
1555             my $rect = new CircuitLayout::Rectangle(-llCoord=>\@llPoint,
1556             -urCoord=>[2.3,4.5]);
1557              
1558             =cut
1559              
1560             #### Method: new CircuitLayout::Rectangle
1561             sub new
1562             {
1563             my($class,%arg) = @_;
1564             my $self = {};
1565             bless $self,$class || ref $class || $CircuitLayout::Rectangle::DefaultClass;
1566             my $layer = $arg{'-layer'};
1567             my $llCoord = $arg{'-llCoord'};
1568             my $urCoord = $arg{'-urCoord'};
1569             if (! ((defined $llCoord) && (defined $urCoord)))
1570             {
1571             die "new CircuitLayout::Rectangle expects lower left and upper right Coords. Missing -llCoord => Coord and or -urCoord => Coord $!";
1572             }
1573             if (! defined $layer) { $layer = 0; };
1574             if (ref($llCoord) ne 'CircuitLayout::Coord')
1575             {
1576             if (ref($llCoord) eq 'ARRAY') ## anonymous array...
1577             {
1578             $llCoord = new CircuitLayout::Coord(-x=>@$llCoord[0],-y=>@$llCoord[1]);
1579             }
1580             die "Rectangle::new did not receive or could not create a coord. $!" if (ref($llCoord) ne 'CircuitLayout::Coord');
1581             }
1582             if (ref($urCoord) ne 'CircuitLayout::Coord')
1583             {
1584             if (ref($urCoord) eq 'ARRAY') ## anonymous array...
1585             {
1586             $urCoord = new CircuitLayout::Coord(-x=>@$urCoord[0],-y=>@$urCoord[1]);
1587             }
1588             die "Rectangle::new did not receive or could not create a coord. $!" if (ref($urCoord) ne 'CircuitLayout::Coord');
1589             }
1590             my @edges;
1591             my $edge;
1592             $edge = new CircuitLayout::Edge(-startCoord=>[$llCoord->x,$llCoord->y], -endCoord=>[$llCoord->x,$urCoord->y]);
1593             push @edges,$edge;
1594             $edge = new CircuitLayout::Edge(-startCoord=>[$llCoord->x,$urCoord->y], -endCoord=>[$urCoord->x,$urCoord->y]);
1595             push @edges,$edge;
1596             $edge = new CircuitLayout::Edge(-startCoord=>[$urCoord->x,$urCoord->y], -endCoord=>[$urCoord->x,$llCoord->y]);
1597             push @edges,$edge;
1598             $edge = new CircuitLayout::Edge(-startCoord=>[$urCoord->x,$llCoord->y], -endCoord=>[$llCoord->x,$llCoord->y]);
1599             push @edges,$edge;
1600             $self -> {'PrintPrecision'} = 4;
1601             $self -> {'UR'} = $urCoord;
1602             $self -> {'LL'} = $llCoord;
1603             $self -> {'Layer'} = $layer;
1604             $self -> {'Edges'} = \@edges;
1605             $self;
1606             }
1607             ################################################################
1608              
1609             =head1 CircuitLayout::Rectangle::center
1610              
1611             =cut
1612              
1613             ####### CircuitLayout::Rectangle
1614             sub center
1615             {
1616             my $self = shift;
1617             my $x1 = $self -> ll -> x;
1618             my $x2 = $self -> ur -> x;
1619             my $y1 = $self -> ll -> y;
1620             my $y2 = $self -> ur -> y;
1621             my $xdiff = ($x2 - $x1)/2;
1622             my $ydiff = ($y2 - $y1)/2;
1623             my $x = $x1 + $xdiff;
1624             my $y = $y1 + $ydiff;
1625             my $result = new CircuitLayout::Coord(-x=>$x,-y=>$y);
1626             $result;
1627             }
1628             ################################################################
1629              
1630             =head1 CircuitLayout::Rectangle::edges
1631              
1632             =cut
1633              
1634             ####### CircuitLayout::Rectangle
1635             sub edges
1636             {
1637             my $self = shift;
1638             my $edges=$self -> {'Edges'};
1639             my @edges=@$edges;
1640             @edges;
1641             }
1642             ################################################################
1643              
1644             =head1 CircuitLayout::Rectangle::printPrecision
1645              
1646             returns precision (integer)
1647              
1648             =cut
1649              
1650             ####### CircuitLayout::Rectangle
1651             sub printPrecision
1652             {
1653             my($self,%arg) = @_;
1654             my $value = $arg{'-value'};
1655             if (defined $value)
1656             {
1657             $self -> {'PrintPrecision'} = $value if ($value =~ m/^\d+$/);
1658             }
1659             $self -> {'PrintPrecision'};
1660             }
1661             ################################################################
1662              
1663             =head1 CircuitLayout::Rectangle::printableCoords
1664              
1665             returns string in "x1,y1;x2,y2"
1666             where x and y print precision is controlled by objects printPrecision
1667              
1668             Note: x1,y1 is lower left
1669              
1670             =cut
1671              
1672             ####### CircuitLayout::Rectangle
1673             sub printableCoords
1674             {
1675             my $self = shift;
1676             my $pp = $self -> printPrecision;
1677             my $string = sprintf("%0.${pp}f",$self -> ll -> x).','.
1678             sprintf("%0.${pp}f",$self -> ll -> y).';'.
1679             sprintf("%0.${pp}f",$self -> ur -> x).','.
1680             sprintf("%0.${pp}f",$self -> ur -> y);
1681             $string;
1682             }
1683             ################################################################
1684              
1685             =head1 CircuitLayout::Rectangle::add
1686              
1687             =cut
1688              
1689             ####### CircuitLayout::Rectangle
1690             sub add
1691             {
1692             my($self,%arg) = @_;
1693             my $llCoord = $arg{'-llCoord'};
1694             my $urCoord = $arg{'-urCoord'};
1695             if (! ((defined $llCoord) && (defined $urCoord)))
1696             {
1697             die "CircuitLayout::Rectangle::add expects lower left and upper right Coords. Missing -llCoord => Coord and or -urCoord => Coord $!";
1698             }
1699             if (ref($llCoord) ne 'CircuitLayout::Coord')
1700             {
1701             if (ref($llCoord) eq 'ARRAY') ## anonymous array...
1702             {
1703             $llCoord = new CircuitLayout::Coord(-x=>@$llCoord[0],-y=>@$llCoord[1]);
1704             }
1705             die "Rectangle::add did not receive or could not create a coord. $!" if (ref($llCoord) ne 'CircuitLayout::Coord');
1706             }
1707             if (ref($urCoord) ne 'CircuitLayout::Coord')
1708             {
1709             if (ref($urCoord) eq 'ARRAY') ## anonymous array...
1710             {
1711             $urCoord = new CircuitLayout::Coord(-x=>@$urCoord[0],-y=>@$urCoord[1]);
1712             }
1713             die "Rectangle::add did not receive or could not create a coord. $!" if (ref($urCoord) ne 'CircuitLayout::Coord');
1714             }
1715              
1716             my $llX = $self -> ll -> x;
1717             my $llY = $self -> ll -> y;
1718             my $urX = $self -> ur -> x;
1719             my $urY = $self -> ur -> y;
1720             my $llX2 = $llCoord -> x;
1721             my $llY2 = $llCoord -> y;
1722             my $urX2 = $urCoord -> x;
1723             my $urY2 = $urCoord -> y;
1724              
1725             $llX = $llX2 if ($llX2 < $llX);
1726             $llY = $llY2 if ($llY2 < $llY);
1727             $urX = $urX2 if ($urX2 > $urX);
1728             $urY = $urY2 if ($urY2 > $urY);
1729             my $rectangle = new CircuitLayout::Rectangle(-llCoord=>[$llX,$llY],-urCoord=>[$urX,$urY],-layer=>$self -> layer);
1730             $rectangle;
1731             }
1732             ################################################################
1733              
1734             =head1 CircuitLayout::Rectangle::extent
1735              
1736             =cut
1737              
1738             ####### CircuitLayout::Rectangle
1739             sub extent
1740             {
1741             my($self,%arg) = @_;
1742             ### already a rectangle !!!
1743             $self;
1744             }
1745             ################################################################
1746              
1747             =head1 CircuitLayout::Rectangle::inside
1748              
1749             usage:
1750             my $rect = new CircuitLayout::Rectangle(...);
1751              
1752             print "is (4,6) inside ? ... ",$rect -> inside(-coord=>[4,6]);
1753              
1754             =cut
1755              
1756             sub inside
1757             {
1758             my($self,%arg) = @_;
1759             my $coordRef = $arg{'-coord'};
1760             my $numPoints=0;
1761             if (defined $coordRef)
1762             {
1763             if (ref $coordRef ne 'CircuitLayout::Coord') ## anonymous array...
1764             {
1765             $coordRef = new CircuitLayout::Coord(-x=>@$coordRef[0],-y=>@$coordRef[1]);
1766             }
1767             $numPoints++;
1768             }
1769             my ($cx,$cy,$x1,$x2,$y1,$y2);
1770             $cx = $coordRef -> x;
1771             $cy = $coordRef -> y;
1772             $x1 = $self -> ll -> x;
1773             $x2 = $self -> ur -> x;
1774             $y1 = $self -> ll -> y;
1775             $y2 = $self -> ur -> y;
1776             if (
1777             ($cx < $x1 && $cx < $x2) ||
1778             ($cx > $x1 && $cx > $x2) ||
1779             ($cy < $y1 && $cy < $y2) ||
1780             ($cy > $y1 && $cy > $y2)
1781             )
1782             {
1783             return 0;
1784             }
1785             return 1; ## made it...
1786             }
1787             ################################################################
1788              
1789             =head1 CircuitLayout::Rectangle::interiorTo
1790              
1791             usage:
1792             my $rect = new CircuitLayout::Rectangle(...);
1793              
1794             print "is (4,6) interiorTo ? ... ",$rect -> interiorTo(-coord=>[4,6]);
1795              
1796             =cut
1797              
1798             sub interiorTo
1799             {
1800             my($self,%arg) = @_;
1801             my $coordRef = $arg{'-coord'};
1802             my $numPoints=0;
1803             if (defined $coordRef)
1804             {
1805             if (ref $coordRef ne 'CircuitLayout::Coord') ## anonymous array...
1806             {
1807             $coordRef = new CircuitLayout::Coord(-x=>@$coordRef[0],-y=>@$coordRef[1]);
1808             }
1809             $numPoints++;
1810             }
1811             my ($cx,$cy,$x1,$x2,$y1,$y2);
1812             $cx = $coordRef -> x;
1813             $cy = $coordRef -> y;
1814             $x1 = $self -> ll -> x;
1815             $x2 = $self -> ur -> x;
1816             $y1 = $self -> ll -> y;
1817             $y2 = $self -> ur -> y;
1818             if (
1819             ($cx <= $x1 && $cx <= $x2) ||
1820             ($cx >= $x1 && $cx >= $x2) ||
1821             ($cy <= $y1 && $cy <= $y2) ||
1822             ($cy >= $y1 && $cy >= $y2)
1823             )
1824             {
1825             return 0;
1826             }
1827             return 1; ## made it...
1828             }
1829             ################################################################
1830              
1831             ## more package CircuitLayout::Rectangle later
1832             1;
1833             }
1834              
1835             package CircuitLayout::Boundary;
1836             {
1837             use base ('CircuitLayout::Coord','CircuitLayout::Edge','CircuitLayout::Rectangle','CircuitLayout::Text'); ## inherit some stuff
1838             # This is the default class for the CircuitLayout::Boundary object to use when all else fails.
1839             $CircuitLayout::Boundary::DefaultClass = 'CircuitLayout::Boundary' unless defined $CircuitLayout::Boundary::DefaultClass;
1840             use overload '+' => \&append,
1841             '+=' => \&append,
1842             'fallback' => 1,
1843             'nomethod' => sub {die "Operator $_[3] makes no sense" };
1844              
1845             =head1 CircuitLayout::new - create new CircuitLayout::Boundary
1846              
1847             usage:
1848             my $boundary = new CircuitLayout::Boundary(-xy=>\@xyArray) -or-
1849             my $boundary = new CircuitLayout::Boundary(-coords=>\$coords)
1850              
1851             =cut
1852              
1853             #### Method: new CircuitLayout::Boundary
1854             sub new
1855             {
1856             my($class,%arg) = @_;
1857             my $self = {};
1858             bless $self,$class || ref $class || $CircuitLayout::DefaultClass;
1859             my $numCoords=0;
1860             my @coords;
1861             my @edges;
1862             my @revXy;
1863             my $x;
1864             my $y;
1865             my $coordA;
1866             my $coordB;
1867             my $edge;
1868             my @xy;
1869             my $coordRef = $arg{'-coords'};
1870             if (defined $coordRef)
1871             {
1872             foreach my $coord (@$coordRef)
1873             {
1874             push @xy,$coord->x;
1875             push @xy,$coord->y;
1876             }
1877             }
1878             else
1879             {
1880             @xy = $arg{'-xy'};
1881             }
1882             my $xy = '';
1883             my $numValues = 0;
1884             if ((defined $xy[0])&&($xy[0] ne ''))
1885             {
1886             $xy = $xy[0];
1887             $numValues = @$xy;
1888             if ($numValues) ## passed in anonymous array
1889             {
1890             @xy = @$xy; ## deref
1891             }
1892             else
1893             {
1894             $numValues = @xy;
1895             }
1896             }
1897             else
1898             {
1899             die "new expects xy array or CircuitLayout::Coord reference. Missing -xy => \\\@array $!";
1900             }
1901             die "new expects an even sized array to -xy => \\\@array $!" if ($numValues % 2);
1902             my $layer = $arg{'-layer'};
1903             if (! defined $layer)
1904             {
1905             $layer = 0;
1906             }
1907              
1908             my $dataType = $arg{'-dataType'};
1909             if (! defined $dataType)
1910             {
1911             $dataType = 0;
1912             }
1913              
1914             my $group = $arg{'-group'};
1915             if (! defined $group)
1916             {
1917             $group = '';
1918             }
1919              
1920             my $net = $arg{'-net'};
1921             if (! defined $net)
1922             {
1923             $net = $arg{'-node'}; ## OLD code may use this ## TODO
1924             }
1925             if (! defined $net)
1926             {
1927             $net = '';
1928             }
1929              
1930             my $property = $arg{'-property'};
1931             if (! defined $property)
1932             {
1933             $property = '';
1934             }
1935              
1936             @revXy = reverse @xy;
1937             $numCoords = ($#revXy + 1)/2;
1938             my $coordCnt=0;
1939             my $firstCoord;
1940             my $lastCoord;
1941             while ($#revXy>=0)
1942             {
1943             $x=pop @revXy;
1944             $y=pop @revXy;
1945             if (! ($coordCnt % 2))
1946             {
1947             $coordA = new CircuitLayout::Coord(-x=>$x,-y=>$y);
1948             push @coords,$coordA;
1949             if (! $coordCnt)
1950             {
1951             $firstCoord = $coordA;
1952             }
1953             else
1954             {
1955             $edge = new CircuitLayout::Edge(-startCoord=>$coordB,-endCoord=>$coordA);
1956             push @edges,$edge;
1957             }
1958             $lastCoord = $coordA;
1959             }
1960             else
1961             {
1962             $coordB = new CircuitLayout::Coord(-x=>$x,-y=>$y);
1963             push @coords,$coordB;
1964             $edge = new CircuitLayout::Edge(-startCoord=>$coordA,-endCoord=>$coordB);
1965             push @edges,$edge;
1966             $lastCoord = $coordB;
1967             }
1968             $coordCnt++;
1969             }
1970             $edge = new CircuitLayout::Edge(-startCoord=>$lastCoord,-endCoord=>$firstCoord);
1971             push @edges,$edge; ## closure
1972             $self -> {'PrintPrecision'} = 4;
1973             $self -> {'cPtr'} = 0; ## for coords
1974             $self -> {'ePtr'} = 0; ## for edges
1975             $self -> {'NumCoords'} = $numCoords;
1976             $self -> {'XYs'} = \@xy;
1977             $self -> {'Coords'} = \@coords;
1978             $self -> {'Edges'} = \@edges;
1979             $self -> {'Layer'} = $layer;
1980             $self -> {'DataType'} = $dataType;
1981             $self -> {'Net'} = $net;
1982             $self -> {'Group'} = $group;
1983             $self -> {'Property'} = $property;
1984            
1985             $self -> {'IsRectangle'} = ''; ## set when needed
1986             $self -> {'Extent'} = ''; ## set when needed
1987              
1988             $self;
1989             }
1990             ################################################################
1991              
1992             =head1 CircuitLayout::Boundary::display
1993              
1994             draws on a worldCanvas
1995              
1996             =cut
1997              
1998             ####### CircuitLayout::Boundary
1999             sub display
2000             {
2001             my($self,%arg) = @_;
2002             my $canvas = $arg{'-worldCanvas'};
2003             if (! defined $canvas)
2004             {
2005             print "ERROR: missing -canvas arg to CircuitLayout::Boundary::display\n";
2006             exit 2;
2007             }
2008            
2009             my $stippleFile = $arg{'-stippleFile'};
2010              
2011             if ((defined $stippleFile) && (-f $stippleFile)) ## xbitmap file
2012             {
2013             $stippleFile = "\@$stippleFile";
2014             }
2015             else
2016             {
2017             $stippleFile = '';
2018             }
2019              
2020             my $fill = $arg{'-fill'}; ## fill color
2021             my $fillColor = '';
2022             if (! defined $fill)
2023             {
2024             $fill = undef;
2025             }
2026             else
2027             {
2028             $fillColor = $fill;
2029             }
2030              
2031             my $outline = $arg{'-outline'}; ## outline color
2032             my $outlineColor = '';
2033             if (! defined $outline)
2034             {
2035             $outline = undef;
2036             }
2037             else
2038             {
2039             $outlineColor = $outline;
2040             }
2041              
2042             my $layer = $self -> {'Layer'};
2043             my $name = $arg{'-name'};
2044             if (! defined $name)
2045             {
2046             $name = "layer $layer";
2047             }
2048              
2049             my $visible = $arg{'-visible'};
2050             if (! defined $visible)
2051             {
2052             $visible = 'true';
2053             }
2054              
2055             my $type = 'boundary';
2056             my @points = @{$self -> {'XYs'}};
2057             $canvas -> createPolygon(
2058             @points,
2059             -fill => $fill,
2060             -outline => $outline,
2061             -stipple => "$stippleFile",
2062             -tags => [
2063             "fill=$fillColor",
2064             "layer=$layer",
2065             'layout=true',
2066             "name=$name",
2067             "outline=$outlineColor",
2068             'selected=false',
2069             "stipple=$stippleFile",
2070             "type=$type",
2071             "visible=$visible",
2072             ],
2073             );
2074             }
2075             ################################################################
2076              
2077             =head1 CircuitLayout::Boundary::printPrecision
2078              
2079             returns precision (integer)
2080              
2081             =cut
2082              
2083             ####### CircuitLayout::Boundary
2084             sub printPrecision
2085             {
2086             my($self,%arg) = @_;
2087             my $value = $arg{'-value'};
2088             if (defined $value)
2089             {
2090             $self -> {'PrintPrecision'} = $value if ($value =~ m/^\d+$/);
2091             }
2092             $self -> {'PrintPrecision'};
2093             }
2094             ################################################################
2095              
2096             =head1 CircuitLayout::Boundary::isRectangle
2097              
2098             =cut
2099              
2100             ####### CircuitLayout::Boundary
2101             sub isRectangle
2102             {
2103             my $self = shift;
2104             if ($self -> {'IsRectangle'} eq '')
2105             {
2106             my $junk = $self -> extent; ## will find Extent and set IsRectangle
2107             }
2108             $self -> {'IsRectangle'};
2109             }
2110             ################################################################
2111              
2112             =head1 CircuitLayout::Boundary::extent
2113              
2114             =cut
2115              
2116             ####### CircuitLayout::Boundary
2117             sub extent
2118             {
2119             my($self,%arg) = @_;
2120             if ($self -> {'Extent'} eq '') ## then need to find extent
2121             {
2122             my $layer = $self -> layer;
2123             my @rectangle;
2124             my $numCoords = $self -> numCoords;
2125             my @coords = $self -> coords;
2126             $self -> {'IsRectangle'} = 0; ## init this way for now...
2127             if ($numCoords == 4)
2128             {
2129             my $llCoord = $coords[0];
2130             my $urCoord = $coords[0];
2131             my @last3Coords = ($coords[1],$coords[2],$coords[3]);
2132             foreach my $testCoord (@last3Coords)
2133             {
2134             if (($testCoord->x < $llCoord->x) || ($testCoord->y < $llCoord->y) )
2135             {
2136             $llCoord = $testCoord;
2137             }
2138             elsif (($testCoord->x > $urCoord->x) || ($testCoord->y > $urCoord->y) )
2139             {
2140             $urCoord = $testCoord;
2141             }
2142             }
2143             my $rectangle = new CircuitLayout::Rectangle(-llCoord=>$llCoord,-urCoord=>$urCoord,-layer=>$layer);
2144             push @rectangle,$rectangle;
2145             my $llXcnt=0;
2146             my $llYcnt=0;
2147             my $urXcnt=0;
2148             my $urYcnt=0;
2149             foreach my $testCoord (@coords)
2150             {
2151             $llXcnt++ if ($testCoord->x == $llCoord->x);
2152             $llYcnt++ if ($testCoord->y == $llCoord->y);
2153             $urXcnt++ if ($testCoord->x == $urCoord->x);
2154             $urYcnt++ if ($testCoord->y == $urCoord->y);
2155             }
2156             $self -> {'IsRectangle'} = 1 if ($llXcnt==2 && $llYcnt==2 && $urXcnt==2 && $urYcnt==2);
2157             }
2158             else ## not a rectangle - just rectangular extent...
2159             {
2160             my $llX = $coords[0] -> x;
2161             my $llY = $coords[0] -> y;
2162             my $urX = $llX;
2163             my $urY = $llY;
2164             foreach my $testCoord (@coords)
2165             {
2166             $llX = $testCoord->x if ($testCoord->x < $llX);
2167             $llY = $testCoord->y if ($testCoord->y < $llY);
2168             $urX = $testCoord->x if ($testCoord->x > $urX);
2169             $urY = $testCoord->y if ($testCoord->y > $urY);
2170             }
2171             my $rectangle = new CircuitLayout::Rectangle(-llCoord=>[$llX,$llY],-urCoord=>[$urX,$urY],-layer=>$layer);
2172             push @rectangle,$rectangle;
2173             }
2174             $self -> {'Extent'} = \@rectangle;
2175             }
2176              
2177             $self -> {'Extent'}[0];
2178             }
2179             ################################################################
2180              
2181             =head1 CircuitLayout::Boundary::layer
2182              
2183             =cut
2184              
2185             ####### CircuitLayout::Boundary
2186             sub layer
2187             {
2188             my($self,%arg) = @_;
2189             my $value = $arg{'-value'};
2190             if (defined $value)
2191             {
2192             $self -> {'Layer'} = $value;
2193             }
2194             $self -> {'Layer'};
2195             }
2196             ################################################################
2197              
2198              
2199             =head1 CircuitLayout::Boundary::dataType
2200              
2201             =cut
2202              
2203             ####### CircuitLayout::Boundary
2204             sub dataType
2205             {
2206             my($self,%arg) = @_;
2207             my $value = $arg{'-value'};
2208             if (defined $value)
2209             {
2210             $self -> {'DataType'} = $value;
2211             }
2212             $self -> {'DataType'};
2213             }
2214             ################################################################
2215              
2216             =head1 CircuitLayout::Boundary::property
2217              
2218             =cut
2219              
2220             ####### CircuitLayout::Boundary
2221             sub property
2222             {
2223             my($self,%arg) = @_;
2224             my $value = $arg{'-value'};
2225             if (defined $value)
2226             {
2227             $self -> {'Property'} = $value;
2228             }
2229             $self -> {'Property'};
2230             }
2231             ################################################################
2232              
2233             =head1 CircuitLayout::Boundary::node
2234              
2235             =cut
2236              
2237             ####### CircuitLayout::Boundary
2238             sub node
2239             {
2240             my($self,%arg) = @_;
2241             my $value = $arg{'-value'};
2242             if (defined $value)
2243             {
2244             $self -> {'Net'} = $value;
2245             }
2246             $self -> {'Net'};
2247             }
2248             ################################################################
2249              
2250             =head1 CircuitLayout::Boundary::net
2251              
2252             =cut
2253              
2254             ####### CircuitLayout::Boundary
2255             sub net
2256             {
2257             my($self,%arg) = @_;
2258             my $value = $arg{'-value'};
2259             if (defined $value)
2260             {
2261             $self -> {'Net'} = $value;
2262             }
2263             $self -> {'Net'};
2264             }
2265             ################################################################
2266              
2267             =head1 CircuitLayout::Boundary::group
2268              
2269             =cut
2270              
2271             ####### CircuitLayout::Boundary
2272             sub group
2273             {
2274             my($self,%arg) = @_;
2275             my $value = $arg{'-value'};
2276             if (defined $value)
2277             {
2278             $self -> {'Group'} = $value;
2279             }
2280             $self -> {'Group'};
2281             }
2282             ################################################################
2283              
2284             =head1 CircuitLayout::Boundary::nextCoord
2285              
2286             =cut
2287              
2288             ####### CircuitLayout::Boundary
2289             sub nextCoord
2290             {
2291             my $self = shift;
2292             my $ptr = $self -> {'cPtr'}++;
2293             if ($ptr < $self -> numCoords)
2294             {
2295             $self -> {'cPtr'} = $ptr + 1; ## Coord "pointer"
2296             return $self -> {'Coords'}[$ptr];
2297             }
2298             else
2299             {
2300             $self -> {'cPtr'} = 0;
2301             return undef();
2302             }
2303             }
2304             ################################################################
2305              
2306             =head1 CircuitLayout::Boundary::printableCoords
2307              
2308             returns string in "x1,y1;x2,y2;x...."
2309             where x and y print precision is controlled by objects printPrecision
2310              
2311             =cut
2312              
2313             ####### CircuitLayout::Boundary
2314             sub printableCoords
2315             {
2316             my $self = shift;
2317             my $string='';
2318             my $pp = $self -> printPrecision;
2319             my $savePtr = $self -> {'cPtr'};
2320             $self -> {'cPtr'} = 0;
2321             while (my $c = $self -> nextCoord)
2322             {
2323             $string .= sprintf("%0.${pp}f",$c -> x).','.sprintf("%0.${pp}f",$c -> y).';';
2324             }
2325             $self -> {'cPtr'} = $savePtr;
2326             $string =~ s|;$||;
2327             $string;
2328             }
2329             ################################################################
2330              
2331             =head1 CircuitLayout::Boundary::nextEdge
2332              
2333             =cut
2334              
2335             ####### CircuitLayout::Boundary
2336             sub nextEdge
2337             {
2338             my $self = shift;
2339             my $ptr = $self -> {'ePtr'}++;
2340             if ($ptr < $self -> numCoords)
2341             {
2342             $self -> {'ePtr'} = $ptr + 1; ## edge "pointer"
2343             return $self -> {'Edges'}[$ptr];
2344             }
2345             else
2346             {
2347             $self -> {'ePtr'} = 0;
2348             return undef();
2349             }
2350             }
2351             ################################################################
2352              
2353             =head1 CircuitLayout::Boundary::append
2354              
2355             =cut
2356              
2357             ####### CircuitLayout::Boundary
2358             sub append
2359             {
2360             my($self,$ref) = @_;
2361             if (ref $ref ne 'CircuitLayout::Coord')
2362             {
2363             if (ref $ref eq 'ARRAY') ## anonymous array...
2364             {
2365             $ref = new CircuitLayout::Coord(-x=>@$ref[0],-y=>@$ref[1]);
2366             }
2367             die "append did not receive or could not create a coord. $!" if (ref $ref ne 'CircuitLayout::Coord');
2368             }
2369             my @coords = $self -> coords;
2370             push @coords,$ref;
2371             $self -> {'NumCoords'}++;
2372             $self -> {'Coords'} = \@coords;
2373             bless $self,'CircuitLayout::Boundary';
2374             $self;
2375             }
2376             ################################################################
2377              
2378             =head1 CircuitLayout::Boundary::numCoords
2379              
2380             =cut
2381              
2382             ####### CircuitLayout::Boundary
2383             sub numCoords
2384             {
2385             my $self = shift;
2386             $self -> {'NumCoords'};
2387             }
2388             ################################################################
2389              
2390             =head1 CircuitLayout::Boundary::xys
2391              
2392             =cut
2393              
2394             ####### CircuitLayout::Boundary
2395             sub xys
2396             {
2397             my $self = shift;
2398             my $xys=$self -> {'XYs'};
2399             my @xys=@$xys;
2400             @xys;
2401             }
2402             ################################################################
2403              
2404             =head1 CircuitLayout::Boundary::coords
2405              
2406             =cut
2407              
2408             ####### CircuitLayout::Boundary
2409             sub coords
2410             {
2411             my $self = shift;
2412             my $coords=$self -> {'Coords'};
2413             my @coords=@$coords;
2414             @coords;
2415             }
2416             ################################################################
2417              
2418             =head1 CircuitLayout::Boundary::edges
2419              
2420             =cut
2421              
2422             ####### CircuitLayout::Boundary
2423             sub edges
2424             {
2425             my $self = shift;
2426             my $edges=$self -> {'Edges'};
2427             my @edges=@$edges;
2428             @edges;
2429             }
2430             ################################################################
2431              
2432             =head1 CircuitLayout::Boundary::boundaryOutline
2433              
2434             returns self (already a Boundary)
2435              
2436             =cut
2437              
2438             ####### CircuitLayout::Boundary
2439             sub boundaryOutline
2440             {
2441             my $self = shift;
2442             ## already a Boundary
2443             $self;
2444             }
2445             ################################################################
2446              
2447             =head1 CircuitLayout::Boundary::inside
2448              
2449             usage:
2450             my @xys=(0,0, 10,0, 10,10, 0,10);
2451              
2452             my $boundary = new CircuitLayout::Boundary(-xy=>\@xys);
2453              
2454             print "is (4,6) inside ? ... ",$boundary -> inside(-coord=>[4,6]);
2455              
2456             =cut
2457              
2458             sub inside_old
2459             {
2460             my($self,%arg) = @_;
2461             my $coordRef = $arg{'-coord'};
2462             my $numPoints=0;
2463             if (defined $coordRef)
2464             {
2465             if (ref $coordRef ne 'CircuitLayout::Coord') ## anonymous array...
2466             {
2467             $coordRef = new CircuitLayout::Coord(-x=>@$coordRef[0],-y=>@$coordRef[1]);
2468             }
2469             $numPoints++;
2470             }
2471             ## copy CircuitLayout::Boundary coords and shift so that coord to test is at the origin.
2472             my $crossings=0;
2473             my $savePtr = $self -> {'ePtr'};
2474             $self -> {'ePtr'} = 0;
2475             my $e;
2476             ## For each edge=(i-1,i), see if it crosses x ray.
2477             while ($e = $self -> nextEdge)
2478             {
2479             if (
2480             (defined ($e -> xIntersection)) &&
2481             ($e->straddleTouchXray(-yValue => $coordRef->y))
2482             )
2483             {
2484             $crossings++ if ($e->xIntersection > $coordRef->x);
2485             }
2486             if ($e -> inside(-coord => $coordRef) ) ## then on edge
2487             {
2488             $self -> {'ePtr'} = $savePtr;
2489             return 1;
2490             }
2491             }
2492             $self -> {'ePtr'} = $savePtr;
2493             # inside if (an odd number of crossings.)
2494             $crossings % 2;
2495             }
2496             ################################################################
2497              
2498             =head1 CircuitLayout::Boundary::inside
2499              
2500             usage:
2501             my @xys=(0,0, 10,0, 10,10, 0,10);
2502              
2503             my $boundary = new CircuitLayout::Boundary(-xy=>\@xys);
2504              
2505             print "is (4,6) inside ? ... ",$boundary -> inside(-coord=>[4,6]);
2506              
2507             =cut
2508              
2509             sub inside
2510             {
2511             my($self,%arg) = @_;
2512             my $coordRef = $arg{'-coord'};
2513             if (defined $coordRef)
2514             {
2515             if (ref $coordRef ne 'CircuitLayout::Coord') ## anonymous array...
2516             {
2517             $coordRef = new CircuitLayout::Coord(-x=>@$coordRef[0],-y=>@$coordRef[1]);
2518             }
2519             }
2520             #### 1st check if coord in extent rectangle.. if not return 0
2521             my $extent = $self -> extent;
2522             return 0 if (! $extent -> inside(-coord => $coordRef)); ## not even in extent
2523              
2524             my $savePtr = $self -> {'ePtr'}; ## save state
2525             $self -> {'ePtr'} = 0;
2526             my $e;
2527              
2528             ## winding number code modified from source posted on http://geometryalgorithms.com
2529             ##// Copyright 2000, softSurfer (www.softsurfer.com)
2530             ##// This code may be freely used and modified for any purpose
2531             ##// providing that this copyright notice is included with it.
2532             my $wn = 0; ## the winding number counter
2533             my $isLeft;
2534             while ($e = $self -> nextEdge)
2535             {
2536             $isLeft = $e -> isLeft(-coord => $coordRef);
2537             return 1 if (($isLeft == 0) && ($e -> inside(-coord=>$coordRef))); ## on an edge
2538              
2539             if (($e -> startCoord -> y) <= ($coordRef -> y))
2540             {
2541             ++$wn if (($isLeft == 1) && ($e -> endCoord -> y) > ($coordRef -> y));
2542             }
2543             else
2544             {
2545             --$wn if (($isLeft == -1) && ($e -> endCoord -> y) <= ($coordRef -> y));
2546             }
2547             }
2548              
2549             $self -> {'ePtr'} = $savePtr;
2550             return 1 if ($wn);
2551             $wn;
2552             }
2553             ################################################################
2554              
2555             =head1 CircuitLayout::Boundary::interiorTo
2556              
2557             usage:
2558             my @xys=(0,0, 10,0, 10,10, 0,10);
2559              
2560             my $boundary = new CircuitLayout::Boundary(-xy=>\@xys);
2561              
2562             print "is (4,6) interiorTo ? ... ",$boundary -> interiorTo(-coord=>[4,6]);
2563              
2564             =cut
2565              
2566             sub interiorTo
2567             {
2568             my($self,%arg) = @_;
2569             my $coordRef = $arg{'-coord'};
2570             my $numPoints=0;
2571             if (defined $coordRef)
2572             {
2573             if (ref $coordRef ne 'CircuitLayout::Coord') ## anonymous array...
2574             {
2575             $coordRef = new CircuitLayout::Coord(-x=>@$coordRef[0],-y=>@$coordRef[1]);
2576             }
2577             $numPoints++;
2578             }
2579             ## copy CircuitLayout::Boundary coords and shift so that coord to test is at the origin.
2580             my $crossings=0;
2581             my $savePtr = $self -> {'ePtr'};
2582             $self -> {'ePtr'} = 0;
2583             my $e;
2584             ## For each edge=(i-1,i), see if it crosses x ray.
2585             while ($e = $self -> nextEdge)
2586             {
2587             if (
2588             (defined ($e -> xIntersection)) &&
2589             ($e->straddleTouchXray(-yValue => $coordRef->y))
2590             )
2591             {
2592             $crossings++ if ($e->xIntersection > $coordRef->x);
2593             }
2594             if ($e -> inside(-coord => $coordRef) ) ## then not strictly interior
2595             {
2596             $self -> {'ePtr'} = $savePtr;
2597             return 0;
2598             }
2599             }
2600             $self -> {'ePtr'} = $savePtr;
2601             # interiorTo if (an odd number of crossings.)
2602             $crossings % 2;
2603             }
2604             ################################################################
2605              
2606             1;
2607             ## end package CircuitLayout::Boundary
2608             }
2609              
2610             package CircuitLayout::Rectangle;
2611             {
2612             =head1 CircuitLayout::Rectangle::ll
2613              
2614             =cut
2615              
2616             ####### CircuitLayout::Rectangle
2617             sub ll
2618             {
2619             my $self = shift;
2620             $self -> {'LL'};
2621             }
2622             ################################################################
2623              
2624             =head1 CircuitLayout::Rectangle::ur
2625              
2626             =cut
2627              
2628             ####### CircuitLayout::Rectangle
2629             sub ur
2630             {
2631             my $self = shift;
2632             $self -> {'UR'};
2633             }
2634             ################################################################
2635              
2636             =head1 CircuitLayout::Rectangle::layer
2637              
2638             =cut
2639              
2640             ####### CircuitLayout::Rectangle
2641             sub layer
2642             {
2643             my $self = shift;
2644             $self -> {'Layer'};
2645             }
2646             ################################################################
2647              
2648             =head1 CircuitLayout::Rectangle::boundaryOutline
2649              
2650             returns Boundary representation of 2 point rectangle
2651              
2652             =cut
2653              
2654             ####### CircuitLayout::Rectangle
2655             sub boundaryOutline
2656             {
2657             my $self = shift;
2658             my @pointArray = ($self -> ll -> x, $self -> ll -> y,
2659             $self -> ll -> x, $self -> ur -> y,
2660             $self -> ur -> x, $self -> ur -> y,
2661             $self -> ur -> x, $self -> ll -> y,
2662             );
2663             my $rectBoundary = new CircuitLayout::Boundary(-xy => \@pointArray);
2664             $rectBoundary;
2665             }
2666             ################################################################
2667              
2668             =head1 CircuitLayout::Rectangle::equals
2669              
2670             =cut
2671              
2672             ####### CircuitLayout::Rectangle::equals
2673             sub equals
2674             {
2675             my($self,$ref) = @_;
2676             my ($ll1,$ll2,$ur1,$ur2);
2677             my $result = 0;
2678             if (ref $ref eq 'CircuitLayout::Rectangle')
2679             {
2680             $ll2 = $ref -> ll;
2681             $ur2 = $ref -> ur;
2682             }
2683             else
2684             {
2685             die "Rectangle::equals did not receive a CircuitLayout::Rectangle. $!";
2686             }
2687             $ll1 = $self -> ll;
2688             $ur1 = $self -> ur;
2689             $result = 1 if (($ll1==$ll2) && ($ur1==$ur2));
2690             $result;
2691             }
2692             ################################################################
2693             ###########################################################
2694             ## end package CircuitLayout::Rectangle
2695             1;
2696             }
2697              
2698             package CircuitLayout::Sref;
2699             {
2700             use base ('CircuitLayout::Coord','CircuitLayout::Edge','CircuitLayout::Boundary','CircuitLayout::Rectangle','CircuitLayout::Text'); ## inherit some stuff
2701             # This is the default class for the CircuitLayout::Sref object to use when all else fails.
2702             $CircuitLayout::Sref::DefaultClass = 'CircuitLayout::Sref' unless defined $CircuitLayout::Sref::DefaultClass;
2703              
2704             =head1 CircuitLayout::new - create new CircuitLayout::Sref
2705              
2706             usage:
2707             my $sref = new CircuitLayout::Sref(-xy=>\@xyArray) -or-
2708             my $sref = new CircuitLayout::Sref(-coords=>\$coords)
2709              
2710             =cut
2711              
2712             #### Method: new CircuitLayout::Sref
2713             sub new
2714             {
2715             my($class,%arg) = @_;
2716             my $self = {};
2717             bless $self,$class || ref $class || $CircuitLayout::Sref::DefaultClass;
2718             my $origin = $arg{'-origin'};
2719             if (! defined($origin))
2720             {
2721             die "new CircuitLayout::Sref expects origin Coord. Missing -origin => Coord $!";
2722             }
2723             else
2724             {
2725             if (ref($origin) ne 'CircuitLayout::Coord')
2726             {
2727             if (ref($origin) eq 'ARRAY') ## anonymous array...
2728             {
2729             $origin = new CircuitLayout::Coord(-x=>@$origin[0],-y=>@$origin[1]);
2730             }
2731             die "CircuitLayout::Sref::new did not receive or could not create a coord. $!" if (ref($origin) ne 'CircuitLayout::Coord');
2732             }
2733             }
2734             my $name = $arg{'-name'};
2735             if (! defined $name)
2736             {
2737             $name = '';
2738             }
2739              
2740             my $reflection = $arg{'-reflection'};
2741             if (! defined $reflection)
2742             {
2743             $reflection = 0; ## false
2744             }
2745              
2746             my $angle = $arg{'-angle'};
2747             if (! defined $angle)
2748             {
2749             $angle = 0.0;
2750             }
2751              
2752             $self -> {'PrintPrecision'} = 4;
2753             $self -> {'Origin'} = $origin;
2754             $self -> {'Name'} = $name;
2755             $self -> {'Reflection'} = $reflection;
2756             $self -> {'Angle'} = $angle;
2757             $self;
2758             }
2759             ################################################################
2760              
2761             =head1 CircuitLayout::Sref::name
2762              
2763             returns name as "string"
2764             use -value to change and pass in string
2765              
2766             =cut
2767              
2768             ####### CircuitLayout::Sref
2769             sub name
2770             {
2771             my($self,%arg) = @_;
2772             my $name = $arg{'-value'};
2773             if (defined($name))
2774             {
2775             $self -> {'Name'} = $name;
2776             }
2777             $self -> {'Name'};
2778             }
2779             ################################################################
2780              
2781             =head1 CircuitLayout::Sref::origin
2782              
2783             returns origin as Coord object
2784             use -value to change and pass in Coord or x,y array
2785              
2786             =cut
2787              
2788             ####### CircuitLayout::Sref
2789             sub origin
2790             {
2791             my($self,%arg) = @_;
2792             my $origin = $arg{'-value'};
2793             if (defined($origin))
2794             {
2795             if (ref($origin) ne 'CircuitLayout::Coord')
2796             {
2797             if (ref($origin) eq 'ARRAY') ## anonymous array...
2798             {
2799             $origin = new CircuitLayout::Coord(-x=>@$origin[0],-y=>@$origin[1]);
2800             }
2801             die "CircuitLayout::Sref::origin did not receive or could not create a coord. $!" if (ref($origin) ne 'CircuitLayout::Coord');
2802             }
2803             $self -> {'Origin'} = $origin;
2804             }
2805             $self -> {'Origin'};
2806             }
2807             ################################################################
2808              
2809             =head1 CircuitLayout::printPrecision
2810              
2811             returns precision (integer)
2812              
2813             =cut
2814              
2815             ####### CircuitLayout::Sref
2816             sub printPrecision
2817             {
2818             my($self,%arg) = @_;
2819             my $value = $arg{'-value'};
2820             if (defined $value)
2821             {
2822             $self -> {'PrintPrecision'} = $value if ($value =~ m/^\d+$/);
2823             }
2824             $self -> {'PrintPrecision'};
2825             }
2826             ################################################################
2827              
2828              
2829             =head1 CircuitLayout::Sref::printableCoords
2830              
2831             returns string in "x1,y1"
2832             where x and y print precision is controlled by objects printPrecision
2833              
2834             Note: returns origin (which is just one coordinate) but method name
2835             is plural none the less to be consistant with other methods.
2836              
2837             =cut
2838              
2839             ####### CircuitLayout::Sref
2840             sub printableCoords
2841             {
2842             my $self = shift;
2843             $self -> origin -> printableCoords;
2844             }
2845             ################################################################
2846              
2847             1;
2848             ## end package CircuitLayout::Sref
2849             }
2850              
2851             package CircuitLayout;
2852             {
2853             use base ('CircuitLayout::Coord','CircuitLayout::Edge','CircuitLayout::Rectangle','CircuitLayout::Text'); ## inherit some stuff
2854             # This is the default class for the CircuitLayout object to use when all else fails.
2855             $CircuitLayout::DefaultClass = 'CircuitLayout' unless defined $CircuitLayout::DefaultClass;
2856              
2857             =head1 CircuitLayout::version
2858              
2859             =cut
2860              
2861             sub version()
2862             {
2863             return $VERSION;
2864             }
2865             ################################################################################
2866              
2867             =head1 CircuitLayout::revision
2868              
2869             =cut
2870              
2871             sub revision()
2872             {
2873             return $revision;
2874             }
2875             ################################################################################
2876              
2877             sub distance
2878             {
2879             my ($x1,$y1,$x2,$y2) = @_;
2880             sqrt( (($x2 - $x1)**2) + (($y2 - $y1)**2) );
2881             }
2882             ################################################################################
2883              
2884             1;
2885             ## end package CircuitLayout
2886             }
2887              
2888             __END__