Top Level Commands

To use these functions, import the package jitx/commands and the package jitx where the enums are defined.

  import jitx
  import jitx/commmands

defn get-merged-physical-design-module  () -> Instantiable

Obtain the physical-design-transformed "main" module of the current design.

Syntax

val new-module = get-merged-physical-design-module()

Description

Returns a new module which incorporates all of the physical design information incorporated into the "main" module of the current design.


defn print-def  (def:JITXDef)

Print the ESIR definition as ASCII. Not very human readable. Use Design Explorer to see this data structured for human consumption.

Syntax

pcb-module my-module :
  ...

print-def(my-module)

print-def will print out the fully expanded definition. JITX definitions include pcb-board, pcb-module, pcb-rules, pcb-stackup, pcb-component, pcb-pad, pcb-landpattern, etc.


defn get-def-string  (def:JITXDef) -> String

Get the string representation of the ESIR definition as ASCII. Returns the same string that print-def prints.

Syntax

pcb-module my-module :
  ...

val my-module-str = get-def-string(my-module)

get-def-string will return the fully expanded definition string. JITX definitions include pcb-board, pcb-module, pcb-rules, pcb-stackup, pcb-component, pcb-pad, pcb-landpattern, etc.


defn transform-component  (body:() -> ?, module:Instantiable) -> Instantiable

Applies body on component to return a newly transformed Instantiable.

Example

pcb-component my-component :
  ; ...

val my-modified-component = within transform-component(my-component) :
  inside pcb-component :
    override landpattern = my-new-landpattern
    override symbol = my-new-symbol
    property(self.transformed) = true

This example returns a modified component which has the same name, descriptions, pins, and so on, of the original component, but now has a different landpattern and symbol, and a new property. Note the use of the override keyword to allow setting the landpattern and symbol after they have already been set.

Because override is not yet implemented for many component attributes which can only be set once, such as name, description, mpn, manufacturer, etc., these will only be able to be set if the original component definition did not set them. override is also not yet implemented for symbols (setting multiple symbol units on one component).

transform-component is mainly intended to be used with modify-components.


defn assign-landpattern  (package:LandPattern) -> Null

Map a landpattern to a component using pin properties.

Syntax

public pcb-component component :
  manufacturer = "Texas Instruments"
  mpn          = "FDC2214QRGH"

  pin-properties :
    [pin:Ref | pads:Int ... | side:Dir ]
    [i2c.scl | 1            | Left     ]
    [i2c.sda | 2            | Left     ]
    [CLKIN   | 3            | Left     ]
    [ADDR    | 4            | Left     ]
    [INTB    | 5            | Left     ]
    [SD      | 6            | Left     ]
    [VDD     | 7            | Left     ]
    [GND     | 8            | Left     ]
    [IN0A    | 9            | Right    ]
    [IN0B    | 10           | Right    ]
    [IN1A    | 11           | Right    ]
    [IN1B    | 12           | Right    ]
    [IN2A    | 13           | Right    ]
    [IN2B    | 14           | Right    ]
    [IN3A    | 15           | Right    ]
    [IN3B    | 16           | Right    ]

val lp = qfn-landpattern(0.5, 3.8, 16, 0.25, 0.4, [2.6 2.6])
assign-landpattern(lp)

Description

The assign-landpattern convenience function is a helper for mapping a landpattern to a pcb-component using the pin-properties table. The table must contain a pads column whose type is | pads: Int ...|, | pads: Ref ...| or |pads: Int|Ref ...|. Multiple entries in the pads column can be used to assign a component pin to multiple pads.


defn assign-symbol  (symbol:SchematicSymbol) -> Null

Assign a symbol to a pcb-component

Syntax

public pcb-component component :
  name = "142-0761-881"
  manufacturer = "Johnson / Cinch Connectivity Solutions"
  mpn = "142-0761-881"
  reference-prefix = "J"

  pin-properties :
    [pin:Ref  |pads:Int ...   | side:Dir]
    [sig      | 1             | Left    ]
    [gnd      | 2 3           | Down    ]

  assign-symbol(coax-sym)
  assign-landpattern(johnson-142-0761-881-pkg)

Description

The assign-symbol function uses the pin column in a pin-properties table to map the pins of a component to the pins of a schematic symbol. The symbol pin names must match the component pin names


defn clear-dbquery-cache  () -> Null

Clear the cache on disk used for part queries with dbquery so that the parts gets refreshed next time the queries are run.


defn transform-module  (body:() -> ?, module:Instantiable) -> Instantiable

Applies body on module to return a newly transformed Instantiable. This is how to run custom passes on your design module.

Syntax

pcb-module main-module :
  ; ...

defn generate-power () :
  inside pcb-module :
    ; ...

val module-with-power = transform-module(generate-power, main-module)

Description

The transform-module function takes two arguments, a function body and pcb-module module. The compiler will apply body to the module


defn modify-components  (modify-component:(Instantiable) -> Instantiable|False, module:Instantiable) -> Instantiable

Transforms module by modifying every component definition by calling the user-supplied function modify-component on them. Whenever modify-component returns a new Instantiable, the component definition will be swapped in place. However, this substitution only takes effect in the new module returned by modify-components. If modify-component instead returns false, the component will be left as is.

To make useful changes, modify-component can use the transform-component function to add statements to the given component definition.

Example

defn standardize-parts (module:Instantiable) -> Instantiable :
  within component = modify-components(module) :
    if name(component) == "my-resistor" :
      println("standardizing component %_" % [name(component)])
      within transform-component(component) :
        inside pcb-component :
          val [p1,p2] = pins(self) as [Pin Pin]
          val symb = my-preferred-resistor-symbol
          val [q1,q2] = pins(symb) as [Pin Pin]
          override symbol = symb(p1 => q1, p2 => q2)
    else :
      false ; don't change the component
val new-design = standardize-parts(original-design)
set-main-module(new-design)

This example overrides the symbol of every component named my-resistor to my-preferred-resistor-symbol, mapping the pins in the order they were given.


defn run-evals  (module:Instantiable) -> Instantiable

Runs all eval-when blocks nested within module to return a newly evaluated Instantiable.

Syntax

pcb-module main-module :
  eval-when has-property?(self.voltage) :
    println("Voltage assigned!")

defn assign-voltage () :
  inside pcb-module :
    property(self.voltage) = 3.3

val transformed-module = transform-module(assign-voltage, main-module)
val evaluated-module = run-evals(transformed-module)

Description

eval-when statements need to be driven by the design generator code. The run-evals command is used to control this.


defn run-checks  (filename:String) -> CheckSummary

Runs all checks statements, saves results in a file named filename, and returns a CheckSummary.

Syntax

pcb-check check-5V (a:JITXObject) :
  #CHECK(has-property?(a.voltage))
  #CHECK(property(a.voltage) is Double)
  #CHECK(property(a.voltage) == 5.0)

pcb-module mymodule :
  pin x
  property(x.voltage) = 5.0
  check check-5V(self)

set-main-module(mymodule)
run-checks("5V-check.txt")

Description

The run-checks command is used to run pcb-checks on a design. Checks are arbitrary DRC, ERC, or other static analsyses defined in code to validate a design programmatically.


defn apply-variants  (vs:Tuple<String>, module:Instantiable) -> Instantiable

Apply Variants to a design to obtain a new design

Or no Variant is used if the argument is empty

Syntax

pcb-module my-module :
  inst a : component-a

  variant "DNP" :
    do-not-populate(a)

val new-module = apply-variants(["DNP"] my-module)
set-main-module(new-module)

Description

The apply-variants command is used to transform a module into another module with the Variants applied.


defn freeze-reference-designators  () -> Instantiable

Freeze all the reference designators, so they will not be recomputed.

Syntax

val lowered-module = run-final-passes(module)
set-main-module(lowered-module)
set-main-module(freeze-reference-designators())

Description

The freeze-reference-designators command stops the JITX compiler from generating new reference designators for existing components in a design.


defn assign-pins  () -> Instantiable

Explicitly run pin assignment before automatic placement, visualization, or export.

Syntax

pcb-module my-module :
  pin x
  supports gpio :
    gpio.gpio => x
  require mygpio: gpio from self

set-main-module(my-module)
val my-module-assigned = assign-pins()

Description

JITX will automatically run pin assignment prior to board placement, export, and visualization. Pin assignment can be run manually using the assign-pins function, which can be useful when running checks or debugging.

Running assign-pins?() instead of assign-pins will return False if there is no valid pin assignment.


defn view-board  (view-mode:ViewMode) -> Null
defn view-board  () -> Null

Visualize the generated board.

Syntax

; Default: update the view
view-board()
; Visualize, panning to the center of the view and zooming to fit
view-board(NewView)
; Visualize, but maintain the same pan/zoom state.
view-board(UpdateView)

Description

The view-board command is used to visualize the generated circuit board.


defn view-schematic  (view-mode:ViewMode) -> Null
defn view-schematic  () -> Null

Visualize the generated schematic.

Syntax

; Default: update the view
view-schematic()
; Visualize, panning to the center of the view and zooming to fit
view-schematic(NewView)
; Visualize, but maintain the same pan/zoom state.
view-schematic(UpdateView)

Description

The view-schematic command is used to visualize the generated circuit board.


defn view-sub-schematic  (objects:Tuple<JITXObject>, schematic-group?:True|False) -> Null
defn view-sub-schematic  (object:JITXObject, schematic-group?:True|False) -> Null
defn view-sub-schematic  (object:JITXObject) -> Null
defn view-sub-schematic  (objects:Tuple<JITXObject>) -> Null

Visualize the generated sub-schematic for a list of nets and instances.

Nets can be single nets, net arrays or bundle nets.

Instances can be component or module instances. They can be single instances or instance arrays.

Syntax

; Objects given to view-sub-schematic need to reference the design main module.
set-main-module(main-module)

; Visualize a list of nets and instances. Default: no schematic groups.
view-sub-schematic([main-module.gnd, main-module.P3V3])
; Visualize a list of nets and instances with schematic groups.
view-sub-schematic([main-module.gnd, main-module.P3V3], true)
; Visualize a single net or instance. Default: no schematic groups.
view-sub-schematic(main-module.sensors)
; Visualize a single net or instance with schematic groups.
view-sub-schematic(main-module.sensors, true)

Description

The view-sub-schematic command is used to visualize a subset of the schematic of the generated board.


defn view  (def:LandPattern, view-mode:ViewMode) -> Null
defn view  (def:SchematicSymbol, view-mode:ViewMode) -> Null
defn view  (def:Instantiable, view-mode:ViewMode) -> Null
defn view  (def:LandPattern) -> Null
defn view  (def:SchematicSymbol) -> Null
defn view  (def:Instantiable) -> Null

View a landpattern, schematic symbol, or pcb-component.

Syntax

; Default: update the view
view(ocdb/utils/symbols/resistor-sym)
; Visualize, panning to the center of the view and zooming to fit
view(ocdb/utils/symbols/resistor-sym, NewView)
; Visualize, but maintain the same pan/zoom state.
view(ocdb/utils/symbols/resistor-sym, UpdateView)

Description

The view command is used to visualize generated landpatterns, schematic symbols, or components. It will fail if passed a pcb-module or array of instantiables.


defn view-design-explorer  () -> Null
defn view-design-explorer  (def:Instantiable -- default-3d:True|False = ?) -> Null

Visualize the design as a hierarchical tree.

Syntax

; Visualize the design as a tree
view-design-explorer()

Description

The view-design-explorer command is used to visualize the design in the VSCode UI.


defn set-current-design  (name:String) -> Null

Set the directory "./designs/" that JITX will use to store design data.

Syntax

set-current-design("jitx-design")

Description

The set-current-design command will clear design state and create a new design directory to store data JITX uses. This directory will contain export data, 3D model files, and cached data used by the design.


defn export-cad  (field-mapping:False|Tuple<KeyValue<String, String>>) -> Null
defn export-cad  ()

Export the JITX design to CAD.

Syntax

set-current-design("jitx-design")
set-export-backend(`altium)

; ... run design ...

export-cad()
; Cad files written to <project-root>/designs/jitx-design/altium

Or

val mappings = [
  "rated-temperature" => "Rated-temperature"
  "datasheet" => "Datasheet"
]
export-cad(mappings)
; Cad files exported with the field/property names converted.

Description

The export-cad command will take the generated board and schematic and convert it to a set of files in the design directory that can be used in CAD software.

The output directory will be <design-directory-name>/<export-backend>.

An optional field-mappings can be supplied as an argument. Name, Description, Manufacturer, MPN, Reference-prefix will always be exported, even if there is no field-mappings. Their exported names can be changed by using the field-mapping.

Component properties can also be exported if an entry exists in field-mappings. For example, if there is a property(U1.datasheet) = "http://www.somewhere.com/my-datasheet.pdf", using "datasheet" => "Datasheet" in the field-mappings (as above), a field "Datasheet" with value "https://www.somewhere.com/my-datasheet.pdf" will appear as a property of the component in CAD software.

A property will not be exported if...

  • there is no corresponding entry in field-mappings; OR
  • it does not exist; OR
  • its value cannot be converted to a string.

To export a property without name change, put the same name in both ends of the mapping. For example, "rated-voltage" => "rated-voltage".


defn set-export-backend  (backend:Symbol) -> Null

Set the CAD exporter backend to use.

Syntax

set-current-design("jitx-design")
set-export-backend(`altium)

; ... run design ...

export-cad()
; Cad files written to <project-root>/designs/jitx-design/altium

Description

The set-export-backend command will control which CAD backend that export-cad will use. The backend will also define some contraints on internals like placement and visualization.


defn set-export-board?  (b:True|False) -> Null

Set whether export-cad should generate board files.

Syntax

set-export-board?(true) ; or false

Description

By default, the export command will generate a board. Use set-export-board? to control whether it is generated or not.


defn set-export-schematic?  (b:True|False) -> Null

Set whether export-cad should generate schematic files.

Syntax

set-export-schematic?(true) ; or false

Description

By default, the export command will generate a schematic. Use set-export-schematic? to control whether it is generated or not.


defn export-bom  () -> Null

Export the bill of materials (BOM) to the design directory.

Syntax

set-bom-vendors([
  "JLCPCB",
  "Arrow",
  "Avnet",
  "DigiKey",
  "Future",
  "Mouser",
  "Newark"
])

set-bom-design-quantity(100)

;write the BOM files to disk
export-bom()

Description

The export-bom command will create the following files in the design directory :

<design-directory>/bom/<design>.tsv
<design-directory>/bom/<design>.select

The .tsv file is a tab separated value that can be imported by spreadsheet software to order parts. The formatting is not defined and subject to change. Parts are autoselected, unless overridden by the .select file.


defn view-bom  (view:BOMViewMode = ?)

View the bill of materials (BOM).

Syntax

view-bom(view:BOMViewMode = BOM-LAST)

Description

BOMViewMode is either BOM-STD: evaluate based on the criteria and display the result BOM-DIFF: evaluate based on the criteria and display the difference since the last version BOM-LAST: do not evaluate, just display the last version if no parameter is given, view-bom(BOM-LAST) is the default.


defn set-bom-columns  (cols:Tuple<BOMColumn>|False)

set-bom-columns(cols: Tuple)

set the columns of the bill of materials (BOM).

Syntax

set-bom-columns([
  BOMColumn(BOMFieldStatus, "Status", 10.0)
  BOMColumn(BOMFieldInsts, "References", 10.0)
  BOMColumn(BOMFieldMPN, "MPN", 10.0)
  BOMColumn(BOMFieldDescription, "Description", 20.0)
  BOMColumn(BOMFieldVendor, "Supplier", 10.0)
  BOMColumn(BOMFieldQuantity, "Qty", 5.0)
  BOMColumn(BOMFieldSubtotal, "Total", 5.0)
  BOMColumn(BOMFieldPreferred, "Preferred", 5.0)
])

Description

Set the columns to display in BOM Visualizer and to export. If none is set, JITX default columns are used.


defn set-bom-metrics  (metrics:Tuple<BOMMetric>|False)

set-bom-metrics(metrics: Tuple)

set the metrics of the bill of materials (BOM).

Syntax

set-bom-metrics([
  BOMMetric(BOMMetricLineItems, "Line Items"),
  BOMMetric(BOMMetricComponentCount, "Components"),
  BOMMetric(BOMMetricTotalCost, "Cost")
])

Description

Set the metrics and their display names in the BOM visualizer.

If not set, the above metrics are used by default.


defn set-bom-design-quantity  (quantity:Int) -> Null

Set the quantity of boards to manufacturer when generating a BOM.

Syntax

set-bom-vendors([
  "JLCPCB",
  "LCSC",
  "DigiKey",
  "Future",
  "Mouser",
  "Arrow",
  "Avnet"
  "Newwark"
])

set-bom-design-quantity(100)

;write the BOM files to disk
export-bom()

Description

The set-bom-design-quantity is used to define the number of boards to manufacturer. It is combined with the vendors list to automatically find parts from the vendors lists in the appropriate quantity to assemble the generated board design.


defn set-paper  (paper:Paper) -> Null

Set the paper size used in schematic export

Syntax

set-paper(ANSI-A4)

Description

The set-paper command is used to define the paper size in the exported schematic files.

Valid values are :

public defenum Paper :
  ANSI-A0
  ANSI-A1
  ANSI-A2
  ANSI-A3
  ANSI-A4
  ANSI-A5
  ANSI-A
  ANSI-B
  ANSI-C
  ANSI-D
  ANSI-E

defn set-value-format-options  (format-options:Tuple<String>) -> Null

Set the formats of the value strings during export operation.

Syntax

set-current-design("jitx-design")
set-export-backend(`kicad)
val format-options = ["keep-decimal" "LC-units-always-present"]
set-value-format-options(format-options)

; ... run design ...

export-cad()
; Cad files written to <project-root>/designs/jitx-design/altium

Description

The set-value-format-options command will set the preferences to generate component values. It is optional. export-cad will work even if this command is not present. By default, without this command the output will look like these: By way of examples: | |Value |Output| |----------|------------------|------| |Resistor |3300 Ohm |3K3 | | |100 Ohm |100R | |----------|------------------|------| |Capacitor |0.0000047 Farad |4.7u | | |0.000000010 Farad |10n | |----------|------------------|------| |Inductor |0.010 Henry |10m |

If a string is present in the format-options, the value will be different: "use-small-k" => 3300-ohm Resistor Value will be: 3k3 "use-greek-mu" => 0.0000047-farad Capacitor Value will be: 4.7μ "use-greek-ohm" => 100-ohm Resistor Value will be: 100Ω "R-unit-always-present" => 3300-ohm Resistor Value will be: 3K3R or 3K3Ω "LC-units-always-present" => 0.0000047-farad Capacitor Value will be: 4.7uF "R-not-replace-decimal-by-quantifier" => 3300-ohm Resistor Value will be: 3.3K "LC-replace-decimal-by-quantifier" => 0.0000047-farad Capacitor Value will be: 4u7 "keep-decimal" => 100-ohm Resistor Value will be: 100.0R "C-replace-n-by-K" => 0.000000010-farad Capacitor Value will be: 10K or 10k (if "use-small-k" is also present) "add-tolerance" => 0.010-henry Inductor Value will be: 10m ± 20% (depends on actual tolerance value)


defn set-use-layout-sketch  () -> Null

Configure the placer to run in sketch mode.

Syntax

set-use-layout-sketch()

Description

When running in sketch mode, the placer will not take Layout Groups into account (faster).


defn set-use-layout-groups  () -> Null

Configure the placer to run in groups mode.

Syntax

set-use-layout-groups()

Description

When running in groups mode, the placer will take Layout Groups into account (slower).


defn enable-debug-plugin-serializer  () -> Null

Enable debugging printout from the plugin object serializer.

Syntax

enable-debug-serializer()

defn enable-spy  () -> Null

Dump the generated internal representation during compilation

Syntax

enable-spy()
evaluate(my-design)

Description

The enable-spy command is a debugging tool to dump the compiler's internal representation(s) into a human readable text form. It is generally only useful for analyzing internal compiler errors.


defn disable-spy  () -> Null

Disable dumping the generated internal representation during compilation

Syntax

disable-spy()

Description

The disable-spy command disables the dumping of the compiler's internal representation(s) after a call to enable-spy.


defn enable-import-dump-ir  (b:True|False) -> Null

Dump the generated internal representation during import

Syntax

enable-import-dump-ir(true)
import-cad(...)

Description

The enable-import-dump-ir command is a debugging tool to dump the importer's internal representation(s) into a human readable text form. It is generally only useful for analyzing importer errors. The command can be called with false as the input to re-disable dumping after enabling.


defn optimized-mode?  () -> True|False

Checks whether the algorithmic core has been compiled with optimizations enabled.

Syntax

optimized-mode?()

Description

The optimized-mode? command returns true if the algorithmic core has been compiled with optimizations enabled, or false otherwise.


defn import-cad  (input-dir:String, output-dir:String, cad:CadSoftware) -> ImportCadResult
defn import-cad  (input-dir:String, output-dir:String, cad:CadSoftware, field-mapping:False|Tuple<KeyValue<String, String>>) -> ImportCadResult

Import CAD projects from KiCAD or Altium.

Syntax

defpackage import-script :
  import core
  import jitx
  import jitx/commands

import-cad("input-directory", "output-directory", Altium)

Optional field-mapping can be used to change property field names, used only in KiCad. Possible target Fields are "Name", "Manufacturer", "MPN", "Description", case-sensitive. For example, you can map "Field1" to "Manfacturer" and "Part Desc" to "Description" by

val mapping = [ "Field1" => "Manufacturer" "Part Desc" => "Description" ]
import-cad("input-design", "output-directory", Altium, field-mapping)

Description

The import-cad command is used to read KiCAD or Altium files from input-directory and generate JITX code in output-directory. The currently supported CadSoftware values are :

public defenum CadSoftware :
  Kicad ; Experimental v6 support
  Altium

Requirements

  • The input directory must exist.
  • input may not be a symbolic link.
  • The output directory must not exist or be an empty directory
  • When importing a board, schematic, and netlist:
    • Reference designators in the project files must be consistent.
    • Nets on the board, in the schematic, and netlist must be consistent.
    • "Consisent" means components may not be present on the board or schematic that aren't in the other, nets on the board/schematic/netlist must be the same, etc.
  • Altium constraints :
    • Only files generated with the JITX Altium Extension will be imported. These are files with the following extensions :
      • (SCHLIB).JSON
      • (SCHDOC).JSON
      • (PRJPCB).JSON
      • (PCBLIB).JSON
      • (PCBDOC).JSON
  • Kicad constraints :
    • Only files of the following file extension will be imported :
      • kicad_mod
      • kicad_sym
      • kicad_pcb
      • kicad_sch
      • net
      • kicad_pro
      • fp-lib-table
    • Only Kicad 6 is supported.
    • A netlist (.net) file must be provided.
    • Only one .kicad_pcb, .kicad_pro, and .net file may exist in the input directory.
  • 3D Model Files:
    • only .step, .stp, and .wrl files will be copied to imported code.
  • BOM Files:
    • BOM files must be named jitx-import-bom.tsv and be of the correct schema

defn min-space  (s:Seqable<Shape>) -> Double

Compute the minimum space in a sequence of shapes.

Syntax

val shapes = [
  loc(1.0, 1.0) * Circle(0.001)
  loc(2.0, -1.0) * Circle(0.01)
]

println(min-space(shapes))

Description

The minimum space in a set of shapes is defined as the smallest distance between non overlapping sides of the shapes. This command is useful when writing DRC checks.


defn min-width  (s:Seqable<Shape>) -> Double

Compute the minimum width in a sequence of shapes.

Syntax

val r1 = loc(-0.5, 0.0) * Rectangle(2.0, 1.0)
val r2 = loc( 0.5, 0.0) * Rectangle(2.0, 1.0)
val mw = min-width([r1, r2])
println(mw)

Description

The minimum width is defined as the minimum length of a line you can draw inside the shape between two segments (on the boundary) with opposite directions and overlapping.


defn offset  (s:Shape, amount:Double) -> Shape

Compute a shape that is "offset" from another by a fixed distance.

Syntax

val rect = Rectangle(10.0, 10.0)
val offset-rect = offset(rect, 1.0)
println(offset-rect) ; Rectangle(11.0, 11.0)

Description

The offset command derives a new shape from an existing one using a factor to expand the dimensions in x/y directions. This is useful when creating new shapes that are a fixed size larger than some root shape.


defn dims  (s:Shape) -> Dims

Compute the x/y dimensions of a shape.

Syntax

val shape = Union([
  Rectangle(10.0, 10.0)
  loc(2.0, 0.0 * Circle(10.0, 10.0)
])

println(dims(shape))

Description

The dims command takes a shape as an argument and computes the x/y dimensions (bounding box) of the complete shape. This is useful for simple collision detection and size computation.


defn expand  (s:Shape, amount:Double) -> Shape

Expand a shape by a fixed distance.

Syntax

val shape = Rectangle(10.0, 10.0)
val expanded = expand(shape, 1.0)
println(expanded)

Description

The expand command computes an "expanded" shape, which is a shape that is exactly amount distance away from the perimeter of s.