123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655 |
- # --------------------------------------------------------------------
- #
- # canvas.itcl
- #
- # The classes in this file draw a CSDL cross section on
- # a canvas. They act as visitors to the CSDL structure.
- # All canvas drawing code is contained here, while the
- # CSDL structures themselves support the navigation through
- # the structure.
- #
- # Example:
- #
- # # assume that a valid CSDL cross section has already been
- # # created. Create a canvas visitor objects to draw the
- # # stackup.
- # grid [canvas .c]
- # canvasDraw cd
- # Stackup::accept cd .c
- #
- #
- # Bob Techentin
- # February 2, 2001
- #
- # Copyright 2001-2004 Mayo Foundation. All Rights Reserved
- # $Id: gui_canvas.itcl,v 1.8 2004/07/20 14:51:55 techenti Exp $
- #
- # --------------------------------------------------------------------
- # --------------------------------------------------------------------
- #
- # Notes to the developer
- #
- # Why is it that layers have both a name and a description?
- # Which should be displayed in the annotation? Who sets them?
- #
- # Isn't there a lot of common code between this visitor and others?
- # For example, shouldn't we compute the x0,x1,y0,y1 coordinates
- # for a trapezoid just once? Shouldn't there be a common
- # visitor, which supports computing the appropriate x/y values?
- # Or will that work, given that GPGE visitors must know about
- # both the drawing x,y coordinates and the actual x,y coordinates?
- #
- # --------------------------------------------------------------------
- package require Itcl
- package provide gui 2.0
- # --------------------------------------------------------------------
- #
- # itcl::class canvasDraw
- #
- # This class is a visitor to the CSDL structures. It draws
- # the cross section structure on a Tk canvas.
- #
- # --------------------------------------------------------------------
- itcl::class canvasDraw {
- # Perhaps someday soon ...
- #inherit CSDLvisitor
- public variable annotate 1
- # Parameters describing a layer stackup.
- variable xOffsetLayer 0.0
- variable totalWidth 0.0
- variable totalHeight 0.0
- variable minThickness 0.0
- variable xoff 0.0
- variable yoff 0.0
- # Drawing controls
- # For groups of conductors, we only want to annotate the
- # first one in the group, so set a couple of flags for
- # the low level shape drawing callbacks.
- variable hlcsdlGroup 0
- variable firstInGroup 0
- # These variables represent the canvasDraw's State,
- # which is set in higher level structures, and used in
- # lower level structures. The high level structure can
- # set the name, color, and tags, which get used when the
- # lower level routines actually draw the polygons.
- variable canvas
- variable color
- variable structName
- variable description
- variable tags
- variable tagToSelect ""
- # HLCSDL - Stackup Structures
- method visitStackup { stackup canvas }
- method visitGroundPlane { groundPlane x y }
- method visitDielectricLayer { dielectricLayer x y }
- method visitRectangleDielectric { rectangleDielectric x y }
- method visitRectangleConductors { rectangleConductors x y }
- method visitTrapezoidConductors { trapezoidConductors x y }
- method visitCircleConductors { circleConductors x y }
- # LLCSDL - low level structures
- method visitDielectric { dielectric x y }
- method visitConductor { conductivity x y }
- method visitGround { ground x y }
- method visitRectangle { rectangle x y }
- method visitTrapezoid { trapezoid x y }
- method visitCircle { circle x y }
- method visitLayer { layer x y }
- method getWidth {} { return [expr { $totalWidth * 0.5 }] }
- method getHeight {} { return $totalHeight }
- # annotate the pitch and offsets for a set of conductors
- method annotatePitchOffsets { x y width height pitch atags }
- # get the current color
- method getFillColor {}
- # set the tag of the object that needs to be drawn selected
- method setTagToSelect { tagPrefix } {
- set tagToSelect $tagPrefix
- }
- }
- # --------------------------------------------------------------------
- # --------------------------------------------------------------------
- # --------------------------------------------------------------------
- #
- # HLCSDL - Stackup Structures
- #
- # --------------------------------------------------------------------
- # --------------------------------------------------------------------
- #
- # canvasDraw::visitStackup
- #
- # The canvasDraw visits the layer stackup before any of the
- # high level or low level structures. This routine will
- # compute scale factors for canvasDraw drawing based on
- # total cross section height and width.
- #
- # --------------------------------------------------------------------
- itcl::body canvasDraw::visitStackup { stackup widget } {
- set canvas $widget
- set structureList $Stackup::structureList
- # Drawn cross section should be twice as wide as
- # the widest stackup structure. Note that this is
- # distinct from the rules defined for the EM simulators,
- # such as the 3x factor for MMTL models, which are
- # required for reliable simulation. This just looks pretty.
- set totalWidth 0.0
- set condWidth 0.0
- # Find thinnest structure in the stackup, so if there
- # are any zero-thickness structures, we can draw them
- # with some minimum thickness.
- set minHeight 1.0e10
- foreach struct $structureList {
- if { ([$struct height] > 0.0) && \
- ([$struct height] < $minHeight) } {
- set minHeight [$struct height]
- }
- if { [$struct width] > $totalWidth } {
- set totalWidth [$struct width]
- }
- if {! [$struct isa GroundPlane] && ! [$struct isa DielectricLayer]} {
- if { [$struct width] > $condWidth } {
- set condWidth [$struct width]
- }
- }
- }
- if { $minHeight == 1.0e10 } {
- set minHeight 10
- }
- set minThickness [expr {$minHeight * 0.75}]
- set y0 0
- foreach struct $structureList {
- if {[$struct isa GroundPlane] || [$struct isa DielectricLayer]} {
- if { [$struct height] > 0.0 } {
- set y0 [expr {$y0 + [$struct height]}]
- } else {
- set y0 [expr {$y0 + $minThickness}]
- }
- }
- }
- if { $y0 > $totalWidth } {
- set totalWidth $y0
- }
- ## set xOffsetLayer [expr {$totalWidth / 2.0}]
- set totalWidth [expr { $totalWidth * 2 }]
- set xOffsetLayer [expr { ($totalWidth - $condWidth) * 0.5}]
- set totalHeight $y0
- # Draw all the cross section elements. Increment "y0"
- # for ground and dielectric layers.
- set y0 0
- foreach struct $structureList {
- $struct accept $this 0 $y0
- if {[$struct isa GroundPlane] || [$struct isa DielectricLayer]} {
- if { [$struct height] > 0.0 } {
- set y0 [expr {$y0 + [$struct height]}]
- } else {
- set y0 [expr {$y0 + $minThickness}]
- }
- }
- }
- # Mark the origin of the drawing.
- set xyP [expr { $minHeight * 0.25 } ]
- set xyN [expr { $xyP * -1 } ]
- $canvas create line $xyN $xyN $xyP $xyP \
- -tag annotation
- $canvas create line $xyN $xyP $xyP $xyN \
- -tag annotation
- # Arrange the canvas items so that layers are on the bottom,
- # then rectangles (which might be dielectric rectangles),
- # then conductors, then annotations. Note that we've set
- # tags on the various drawn items just for this purpose.
- $canvas lower layer
- $canvas raise rectangle
- $canvas raise conductor
- $canvas raise annotation
- }
- # --------------------------------------------------------------------
- # Structures
- #
- # We don't actually draw most of the high level
- # structures. We defer drawing to the structure shapes
- # (Rectangles, Layers, etc.). The shapes have to get
- # drawn anyway, so we're not going to duplicate code here.
- # --------------------------------------------------------------------
- itcl::body canvasDraw::visitGroundPlane { groundPlane x y } {
- set structName [namespace tail $groundPlane]
- set tags $structName
- }
- itcl::body canvasDraw::visitDielectricLayer { dielectricLayer x y } {
- set structName [namespace tail $dielectricLayer]
- set tags $structName
- }
- # --------------------------------------------------------------------
- # There are special annotations for groups of dielectric blocks.
- # First, we have to set a couple of flags so that only the first
- # dielectric in the group gets dimension annotations. Then we
- # have to add an annotation for the pitch.
- # --------------------------------------------------------------------
- itcl::body canvasDraw::visitRectangleDielectric { rectangleDielectric x y } {
- set structName [namespace tail $rectangleDielectric]
- set tags $structName
- # Set the group and first flags so that low level routines
- # know can handle the first drawn conductor differently.
- set xoff [$rectangleDielectric cget -xOffset]
- set yoff [$rectangleDielectric cget -yOffset]
- set hlcsdlGroup 1
- set firstInGroup 1
- set number [$rectangleDielectric cget -number]
- if { $annotate && $number > 1 } {
- # Append "annotation" to the tags list
- set atags $tags
- lappend atags annotation
- # Get parameters from the dielectric
- set width [$rectangleDielectric cget -width]
- set height [$rectangleDielectric height]
- set pitch [$rectangleDielectric cget -pitch]
- if { $number < 2 } {
- return
- }
- # Figure out coordinates and draw annotation
- annotatePitchOffsets [expr { $x + $xoff }] [expr { $y + $yoff }] \
- $width $height $pitch $atags
- }
- }
- # --------------------------------------------------------------------
- # There are also special annotations for groups of conductors.
- # --------------------------------------------------------------------
- itcl::body canvasDraw::visitRectangleConductors { rectangleConductors x y } {
- set structName [namespace tail $rectangleConductors]
- set tags $structName
- # Set the group and first flags so that low level routines
- # know can handle the first drawn conductor differently.
- set xoff [$rectangleConductors cget -xOffset]
- set yoff [$rectangleConductors cget -yOffset]
- set hlcsdlGroup 1
- set firstInGroup 1
- set number [$rectangleConductors cget -number]
- if { $annotate && $number > 1 } {
- # Append "annotation" to the tags list
- set atags $tags
- lappend atags annotation
- # Get parameters from the conductors
- set width [$rectangleConductors cget -width]
- set height [$rectangleConductors height]
- set pitch [$rectangleConductors cget -pitch]
- if { $number < 2 } {
- return
- }
- # Figure out coordinates and draw annotation
- annotatePitchOffsets [expr { $x + $xoff }] [expr { $y + $yoff }] \
- $width $height $pitch $atags
- }
- }
- itcl::body canvasDraw::visitTrapezoidConductors { trapezoidConductors x y } {
- set structName [namespace tail $trapezoidConductors]
- set tags $structName
- # Set the group and first flags so that low level routines
- # know can handle the first drawn conductor differently.
- set xoff [$trapezoidConductors cget -xOffset]
- set yoff [$trapezoidConductors cget -yOffset]
- set hlcsdlGroup 1
- set firstInGroup 1
- set number [$trapezoidConductors cget -number]
- if { $annotate && $number > 1 } {
- # Append "annotation" to the tags list
- set atags $tags
- lappend atags annotation
- # Get parameters from the conductors
- set height [$trapezoidConductors height]
- set pitch [$trapezoidConductors cget -pitch]
- set number [$trapezoidConductors cget -number]
- set twidth [$trapezoidConductors cget -topWidth]
- set twidth [$trapezoidConductors cget -topWidth]
- set bwidth [$trapezoidConductors cget -bottomWidth]
- set width [expr { ($twidth + $bwidth) * 0.5 }]
- # Figure out coordinates and draw annotation
- annotatePitchOffsets [expr { $x + $xoff }] [expr { $y + $yoff }] \
- $width $height $pitch $atags
- }
- }
- itcl::body canvasDraw::visitCircleConductors { circleConductors x y } {
- set structName [namespace tail $circleConductors]
- set tags $structName
- # Set the group and first flags so that low level routines
- # know can handle the first drawn conductor differently.
- set xoff [$circleConductors cget -xOffset]
- set yoff [$circleConductors cget -yOffset]
- set hlcsdlGroup 1
- set firstInGroup 1
- set number [$circleConductors cget -number]
- if { $annotate && $number > 1 } {
- # Append "annotation" to the tags list
- set atags $tags
- lappend atags annotation
- # Get parameters from the conductors
- set height [$circleConductors height]
- set pitch [$circleConductors cget -pitch]
- set width [$circleConductors cget -diameter]
- # Figure out coordinates and draw annotation
- annotatePitchOffsets [expr { $x + $xoff }] [expr { $y + $yoff }] \
- $width $height $pitch $atags
- }
- }
- # --------------------------------------------------------------------
- # LLCSDL - low level structures
- #
- # We don't draw the structures either. The actual drawing
- # is done by the shapes. But we *do* capture important
- # information from the structures which gets used during
- # the shape drawing code.
- #
- # Set the color, append tags for structuture type
- # (e.g., "conductor") and structure name. Create
- # a description with some properties from the structure.
- # --------------------------------------------------------------------
- itcl::body canvasDraw::visitDielectric { dielectric x y } {
- set color #90ee90 ;# "lightgreen"
- lappend tags dielectric $dielectric
- set perm [$dielectric cget -permittivity]
- set ltan [$dielectric cget -lossTangent]
- set description "$structName: econst=$perm, lossTan=$ltan"
- }
- itcl::body canvasDraw::visitConductor { conductor x y } {
- set color #ffff00 ;# "yellow"
- lappend tags conductor $conductor
- set cond [$conductor cget -conductivity]
- set description "$structName cond=$cond"
- }
- itcl::body canvasDraw::visitGround { ground x y} {
- set color #add8e6 ;# "lightblue"
- lappend tags ground $ground
- set description "$structName"
- }
- # --------------------------------------------------------------------
- #
- # getFillColor
- #
- # If one of the current set of tags matches $tagToSelect,
- # then we have to return the select color. Otherwise,
- # we use the current fill color.
- #
- # --------------------------------------------------------------------
- itcl::body canvasDraw::getFillColor {} {
- if { [lsearch $tags $tagToSelect] < 0 } {
- return $color
- } else {
- return #ff0000 ;# "red"
- }
- }
- # --------------------------------------------------------------------
- #
- # annotatePitchOffsets
- #
- # Draw arrows and dimension text for offsets and pitch
- # between multiple objects.
- #
- # --------------------------------------------------------------------
- itcl::body canvasDraw::annotatePitchOffsets { x y width height pitch atags } {
- set x0 [expr {[length $x] + $width/2.0}]
- set x1 [expr {$x0 + [length $pitch]}]
- set ycenter [expr {[length $y] + [length $height]/2.0}]
- set xcenter [expr {0.5 * ($x0+$x1)}]
- $canvas create line $x0 $ycenter $x1 $ycenter \
- -arrow both -tag $atags
- $canvas create text $xcenter $ycenter \
- -anchor s -text $pitch -tag $atags
- if { $xoff > 0 } {
- set x1 [length $x]
- set x0 [expr { $x1 - $xoff }]
- set ycenter [expr { [length $y] - $yoff }]
- set xcenter [expr {0.5 * ($x0+$x1)}]
- $canvas create line $x0 $ycenter $x1 $ycenter \
- -arrow both -tag $atags
- $canvas create text $xcenter $ycenter \
- -anchor n -text $xoff -tag $atags
- }
- if { $yoff > 0 } {
- set xcenter [length $x]
- set y1 [length $y]
- set y0 [expr { $y1 - $yoff }]
- set ycenter [expr {0.5 * ($y0+$y1)}]
- $canvas create line $xcenter $y0 $xcenter $y1 \
- -arrow both -tag $atags
- $canvas create text $xcenter $ycenter \
- -anchor e -text $yoff -tag $atags
- }
- }
- # --------------------------------------------------------------------
- #
- # canvasDraw::visitRectangle
- #
- # --------------------------------------------------------------------
- itcl::body canvasDraw::visitRectangle { rectangle x y } {
- # (x0,y1) + ----------- + (x1,y1)
- # | |
- # (x0,y0) + ----------- + (x1,y0)
- set width [$rectangle width]
- set height [$rectangle height]
- set x0 [length $x]
- set y0 [length $y]
- set x1 [expr {$x0 + $width}]
- set y1 [expr {$y0 + $height}]
- set fillcolor [getFillColor]
- lappend tags rectangle
- $canvas create rectangle $x0 $y0 $x1 $y1 \
- -fill $fillcolor -outline black -tags [concat $tags shape]
- if { $annotate && ( ! $hlcsdlGroup || $firstInGroup ) } {
- # Append "annotation" to the tags list
- set atags $tags
- lappend atags annotation
- set xcenter [expr { ($x0 + $x1) * 0.5 }]
- set ycenter [expr { ($y0 + $y1) * 0.5 }]
- # Create the text and arrows. Note that we get the
- # string values directly from the shape, which
- # might include units.
- $canvas create line $x0 $y0 $x1 $y0 \
- -arrow both -tag $atags
- $canvas create text $xcenter $y0 \
- -anchor n -text "[$rectangle cget -width]" -tag $atags
- $canvas create line $x0 $y0 $x0 $y1 \
- -arrow both -tag $atags
- $canvas create text $x0 $ycenter \
- -anchor e -text "[$rectangle cget -height] " -tag $atags
- set firstInGroup 0
- }
- }
- # --------------------------------------------------------------------
- #
- # canvasDraw::visitTrapezoid
- #
- # --------------------------------------------------------------------
- itcl::body canvasDraw::visitTrapezoid { trapezoid x y } {
- # (x1,y1) + ----------- + (x2,y1)
- # / \
- # (x0,y0) + --------------- + (x3,y0)
- set x [length $x]
- set y [length $y]
- set topWidth [length [$trapezoid cget -topWidth]]
- set bottomWidth [length [$trapezoid cget -bottomWidth]]
- set width [$trapezoid width]
- set height [$trapezoid height]
- set x0 [expr {$x + ($width - $bottomWidth)/2}]
- set x1 [expr {$x + ($width - $topWidth)/2}]
- set x2 [expr {$x + ($width + $topWidth)/2}]
- set x3 [expr {$x + ($width + $bottomWidth)/2}]
- set y0 $y
- set y1 [expr {$y + $height}]
- set fillcolor [getFillColor]
- lappend tags trapezoid
- $canvas create polygon $x0 $y0 $x1 $y1 $x2 $y1 $x3 $y0 \
- -fill $fillcolor -outline black -tags [concat $tags shape]
- if { $annotate && ( ! $hlcsdlGroup || $firstInGroup ) } {
- # Append "annotation" to the tags list
- set atags $tags
- lappend atags annotation
- set xcenter [expr {($x0 + $x3)/2}]
- set ycenter [expr {($y0 + $y1)/2}]
- $canvas create line $x0 $y0 $x3 $y0 \
- -arrow both -tag $atags
- $canvas create text $xcenter $y0 \
- -anchor n -text $bottomWidth -tag $atags
- $canvas create line $x1 $y1 $x2 $y1 \
- -arrow both -tag annotation
- $canvas create text $xcenter $y1 \
- -anchor s -text $topWidth -tag $atags
- $canvas create line $x0 $y0 $x0 $y1 \
- -arrow both -tag $atags
- $canvas create text $x0 $ycenter \
- -anchor e -text "$height " -tag $atags
- set firstInGroup 0
- }
- }
- # --------------------------------------------------------------------
- #
- # canvasDraw::visitCircle
- #
- # --------------------------------------------------------------------
- itcl::body canvasDraw::visitCircle { circle x y } {
- # (x0,y1) + --- + (x1,y1)
- # | | (just imagine a circle in the box)
- # (x0,y0) + --- + (x1,y0)
- set diameter [length [$circle cget -diameter]]
- set x0 [length $x]
- set y0 [length $y]
- set x1 [expr {$x0 + $diameter}]
- set y1 [expr {$y0 + $diameter}]
- set fillcolor [getFillColor]
- lappend tags circle
- $canvas create oval $x0 $y0 $x1 $y1 \
- -fill $fillcolor -outline black -tags [concat $tags shape]
- if { $annotate && ( ! $hlcsdlGroup || $firstInGroup ) } {
- # Append "annotation" to the tags list
- set atags $tags
- lappend atags annotation
- set xcenter [expr {[length $x] + [length $diameter]/2}]
- $canvas create line $x0 $y0 $x1 $y0 \
- -arrow both -tag $atags
- $canvas create text $xcenter $y0 \
- -anchor n -text $diameter -tag $atags
- set firstInGroup 0
- }
- }
- # --------------------------------------------------------------------
- #
- # canvasDraw::visitLayer
- #
- # --------------------------------------------------------------------
- itcl::body canvasDraw::visitLayer { layer x y } {
- # The layer width is really $totalWidth. Subtract
- # the X offset from X0. (prim_coord will add it back in
- # to get us back to zero)
- set x0 [expr {[length $x]-$xOffsetLayer}]
- set x1 [expr {$x0 + $totalWidth}]
- # Figure out the layer thickness. If the thickness is
- # zero, then set the drawing thickness to the minimum.
- set y0 [length $y]
- set thickness [length [$layer cget -thickness]]
- if { $thickness > 0.0 } {
- set y1 [expr {$y0 + $thickness}]
- } else {
- set y1 [expr {$y0 + $minThickness}]
- set thickness $minThickness
- }
- set fillcolor [getFillColor]
- lappend tags layer
- $canvas create rectangle $x0 $y0 $x1 $y1 \
- -fill $fillcolor -outline black \
- -tags [concat $tags shape]
- if { $annotate } {
- # Append "annotation" to the tags list
- set atags $tags
- lappend atags annotation
- # Add the description`
- set xat [expr { $x1 - ( $x1 - $x0 ) * 0.1 }]
- set yat $y1
- set anchor ne
- $canvas create text $xat $yat -anchor $anchor \
- -text $description -tags $atags
- # Add a dimension line
- set x3 [expr {$x0 + 0.98*($x1-$x0)}]
- set x3a [expr {$x0 + 0.97*($x1-$x0)}]
- set y3 [expr {double($y0+$y1)/2}]
- $canvas create line $x3 $y0 $x3 $y1 \
- -arrow both -tag $atags
- $canvas create text $x3a $y3 \
- -anchor e -text $thickness -tag $atags
- }
- }
|