diff --git a/upstream/404.html b/upstream/404.html index 875b1cc3..7d897d57 100644 --- a/upstream/404.html +++ b/upstream/404.html @@ -12,7 +12,7 @@ - + diff --git a/upstream/acknowledgements/index.html b/upstream/acknowledgements/index.html index 7848d0ea..e5389acb 100644 --- a/upstream/acknowledgements/index.html +++ b/upstream/acknowledgements/index.html @@ -14,7 +14,7 @@ - + diff --git a/upstream/cli/index.html b/upstream/cli/index.html index 51c40c71..eb6e59dd 100644 --- a/upstream/cli/index.html +++ b/upstream/cli/index.html @@ -16,7 +16,7 @@ - + diff --git a/upstream/fabrication/intro/index.html b/upstream/fabrication/intro/index.html index 77de991e..84f35185 100644 --- a/upstream/fabrication/intro/index.html +++ b/upstream/fabrication/intro/index.html @@ -16,7 +16,7 @@ - + diff --git a/upstream/fabrication/jlcpcb/index.html b/upstream/fabrication/jlcpcb/index.html index 6d4bd77b..7151904b 100644 --- a/upstream/fabrication/jlcpcb/index.html +++ b/upstream/fabrication/jlcpcb/index.html @@ -16,7 +16,7 @@ - + diff --git a/upstream/fabrication/neodenyy1/index.html b/upstream/fabrication/neodenyy1/index.html index cb0a27ff..9b622e21 100644 --- a/upstream/fabrication/neodenyy1/index.html +++ b/upstream/fabrication/neodenyy1/index.html @@ -12,7 +12,7 @@ - + diff --git a/upstream/fabrication/openpnp/index.html b/upstream/fabrication/openpnp/index.html index b69c5cf6..64bc2680 100644 --- a/upstream/fabrication/openpnp/index.html +++ b/upstream/fabrication/openpnp/index.html @@ -12,7 +12,7 @@ - + diff --git a/upstream/fabrication/oshpark/index.html b/upstream/fabrication/oshpark/index.html index 8dd7d20f..1cb6f8dc 100644 --- a/upstream/fabrication/oshpark/index.html +++ b/upstream/fabrication/oshpark/index.html @@ -16,7 +16,7 @@ - + diff --git a/upstream/fabrication/pcbway/index.html b/upstream/fabrication/pcbway/index.html index 6c436a43..1a8cf6ed 100644 --- a/upstream/fabrication/pcbway/index.html +++ b/upstream/fabrication/pcbway/index.html @@ -16,7 +16,7 @@ - + diff --git a/upstream/faq/index.html b/upstream/faq/index.html index 0396d189..31097d1f 100644 --- a/upstream/faq/index.html +++ b/upstream/faq/index.html @@ -16,7 +16,7 @@ - + diff --git a/upstream/index.html b/upstream/index.html index c2ce7540..eec9ef17 100644 --- a/upstream/index.html +++ b/upstream/index.html @@ -14,7 +14,7 @@ - + diff --git a/upstream/installation/choosing_kicad/index.html b/upstream/installation/choosing_kicad/index.html index ff6a2869..ba0e0092 100644 --- a/upstream/installation/choosing_kicad/index.html +++ b/upstream/installation/choosing_kicad/index.html @@ -16,7 +16,7 @@ - + diff --git a/upstream/installation/docker/index.html b/upstream/installation/docker/index.html index 9e4592b1..edaa4598 100644 --- a/upstream/installation/docker/index.html +++ b/upstream/installation/docker/index.html @@ -16,7 +16,7 @@ - + diff --git a/upstream/installation/gui_and_libs/index.html b/upstream/installation/gui_and_libs/index.html index bbf4a46c..961c8de1 100644 --- a/upstream/installation/gui_and_libs/index.html +++ b/upstream/installation/gui_and_libs/index.html @@ -16,7 +16,7 @@ - + diff --git a/upstream/installation/intro/index.html b/upstream/installation/intro/index.html index ee8a2041..67d5464a 100644 --- a/upstream/installation/intro/index.html +++ b/upstream/installation/intro/index.html @@ -16,7 +16,7 @@ - + diff --git a/upstream/installation/linux/index.html b/upstream/installation/linux/index.html index b8d76049..7e0e7809 100644 --- a/upstream/installation/linux/index.html +++ b/upstream/installation/linux/index.html @@ -16,7 +16,7 @@ - + diff --git a/upstream/installation/macos/index.html b/upstream/installation/macos/index.html index 3caa2a27..2d678a05 100644 --- a/upstream/installation/macos/index.html +++ b/upstream/installation/macos/index.html @@ -16,7 +16,7 @@ - + diff --git a/upstream/installation/upgrading/index.html b/upstream/installation/upgrading/index.html index de341bba..164af402 100644 --- a/upstream/installation/upgrading/index.html +++ b/upstream/installation/upgrading/index.html @@ -16,7 +16,7 @@ - + diff --git a/upstream/installation/windows/index.html b/upstream/installation/windows/index.html index 408b5525..fbd77196 100644 --- a/upstream/installation/windows/index.html +++ b/upstream/installation/windows/index.html @@ -16,7 +16,7 @@ - + diff --git a/upstream/multiboard/index.html b/upstream/multiboard/index.html index fc49ee9e..cd3eb55f 100644 --- a/upstream/multiboard/index.html +++ b/upstream/multiboard/index.html @@ -16,7 +16,7 @@ - + diff --git a/upstream/panelization/cli/index.html b/upstream/panelization/cli/index.html index 1e666b39..dcce0971 100644 --- a/upstream/panelization/cli/index.html +++ b/upstream/panelization/cli/index.html @@ -16,7 +16,7 @@ - + diff --git a/upstream/panelization/examples/index.html b/upstream/panelization/examples/index.html index 7517597d..c87a20fb 100644 --- a/upstream/panelization/examples/index.html +++ b/upstream/panelization/examples/index.html @@ -16,7 +16,7 @@ - + diff --git a/upstream/panelization/gui/index.html b/upstream/panelization/gui/index.html index 62dad181..119ed4f2 100644 --- a/upstream/panelization/gui/index.html +++ b/upstream/panelization/gui/index.html @@ -16,7 +16,7 @@ - + diff --git a/upstream/panelization/intro/index.html b/upstream/panelization/intro/index.html index 19a9c3aa..ddfd9f45 100644 --- a/upstream/panelization/intro/index.html +++ b/upstream/panelization/intro/index.html @@ -16,7 +16,7 @@ - + diff --git a/upstream/panelization/plugins/index.html b/upstream/panelization/plugins/index.html index ac6f6a71..e5391e75 100644 --- a/upstream/panelization/plugins/index.html +++ b/upstream/panelization/plugins/index.html @@ -16,7 +16,7 @@ - + diff --git a/upstream/panelization/python_api/index.html b/upstream/panelization/python_api/index.html index 81001da2..3ea9a7eb 100644 --- a/upstream/panelization/python_api/index.html +++ b/upstream/panelization/python_api/index.html @@ -16,7 +16,7 @@ - + diff --git a/upstream/panelization/scripting/index.html b/upstream/panelization/scripting/index.html index fff02183..b468179c 100644 --- a/upstream/panelization/scripting/index.html +++ b/upstream/panelization/scripting/index.html @@ -16,7 +16,7 @@ - + diff --git a/upstream/panelization/tabs/index.html b/upstream/panelization/tabs/index.html index b83c4bdb..0315059f 100644 --- a/upstream/panelization/tabs/index.html +++ b/upstream/panelization/tabs/index.html @@ -16,7 +16,7 @@ - + diff --git a/upstream/present/index.html b/upstream/present/index.html index 0f54258a..798c38d4 100644 --- a/upstream/present/index.html +++ b/upstream/present/index.html @@ -16,7 +16,7 @@ - + diff --git a/upstream/resources/jig.3mf b/upstream/resources/jig.3mf new file mode 100644 index 00000000..08b3a93a Binary files /dev/null and b/upstream/resources/jig.3mf differ diff --git a/upstream/resources/jig.f3d b/upstream/resources/jig.f3d new file mode 100644 index 00000000..d429578a Binary files /dev/null and b/upstream/resources/jig.f3d differ diff --git a/upstream/resources/jig.step b/upstream/resources/jig.step new file mode 100644 index 00000000..3ee808a0 --- /dev/null +++ b/upstream/resources/jig.step @@ -0,0 +1,3433 @@ +ISO-10303-21; +HEADER; +/* Generated by software containing ST-Developer + * from STEP Tools, Inc. (www.steptools.com) + */ + +FILE_DESCRIPTION( +/* description */ (''), +/* implementation_level */ '2;1'); + +FILE_NAME( +/* name */ 'jig v4.step', +/* time_stamp */ '2024-06-20T15:43:55+02:00', +/* author */ (''), +/* organization */ (''), +/* preprocessor_version */ 'ST-DEVELOPER v20', +/* originating_system */ 'Autodesk Translation Framework v12.20.1.177', + +/* authorisation */ ''); + +FILE_SCHEMA (('AUTOMOTIVE_DESIGN { 1 0 10303 214 3 1 1 }')); +ENDSEC; + +DATA; +#10=MECHANICAL_DESIGN_GEOMETRIC_PRESENTATION_REPRESENTATION('',(#43,#44, +#45),#3242); +#11=ITEM_DEFINED_TRANSFORMATION($,$,#1909,#2140); +#12=ITEM_DEFINED_TRANSFORMATION($,$,#2045,#2141); +#13=ITEM_DEFINED_TRANSFORMATION($,$,#2128,#2142); +#14=ITEM_DEFINED_TRANSFORMATION($,$,#2128,#2143); +#15=ITEM_DEFINED_TRANSFORMATION($,$,#2128,#2144); +#16=ITEM_DEFINED_TRANSFORMATION($,$,#2128,#2145); +#17=( +REPRESENTATION_RELATIONSHIP($,$,#3262,#3261) +REPRESENTATION_RELATIONSHIP_WITH_TRANSFORMATION(#11) +SHAPE_REPRESENTATION_RELATIONSHIP() +); +#18=( +REPRESENTATION_RELATIONSHIP($,$,#3263,#3261) +REPRESENTATION_RELATIONSHIP_WITH_TRANSFORMATION(#12) +SHAPE_REPRESENTATION_RELATIONSHIP() +); +#19=( +REPRESENTATION_RELATIONSHIP($,$,#3264,#3261) +REPRESENTATION_RELATIONSHIP_WITH_TRANSFORMATION(#13) +SHAPE_REPRESENTATION_RELATIONSHIP() +); +#20=( +REPRESENTATION_RELATIONSHIP($,$,#3264,#3261) +REPRESENTATION_RELATIONSHIP_WITH_TRANSFORMATION(#14) +SHAPE_REPRESENTATION_RELATIONSHIP() +); +#21=( +REPRESENTATION_RELATIONSHIP($,$,#3264,#3261) +REPRESENTATION_RELATIONSHIP_WITH_TRANSFORMATION(#15) +SHAPE_REPRESENTATION_RELATIONSHIP() +); +#22=( +REPRESENTATION_RELATIONSHIP($,$,#3264,#3261) +REPRESENTATION_RELATIONSHIP_WITH_TRANSFORMATION(#16) +SHAPE_REPRESENTATION_RELATIONSHIP() +); +#23=CONTEXT_DEPENDENT_SHAPE_REPRESENTATION(#17,#3255); +#24=CONTEXT_DEPENDENT_SHAPE_REPRESENTATION(#18,#3256); +#25=CONTEXT_DEPENDENT_SHAPE_REPRESENTATION(#19,#3257); +#26=CONTEXT_DEPENDENT_SHAPE_REPRESENTATION(#20,#3258); +#27=CONTEXT_DEPENDENT_SHAPE_REPRESENTATION(#21,#3259); +#28=CONTEXT_DEPENDENT_SHAPE_REPRESENTATION(#22,#3260); +#29=NEXT_ASSEMBLY_USAGE_OCCURRENCE('base:1','base:1','base:1',#3266,#3267, +'base:1'); +#30=NEXT_ASSEMBLY_USAGE_OCCURRENCE('stencilFrame:1','stencilFrame:1', +'stencilFrame:1',#3266,#3268,'stencilFrame:1'); +#31=NEXT_ASSEMBLY_USAGE_OCCURRENCE('aligmentPin:1','aligmentPin:1', +'aligmentPin:1',#3266,#3269,'aligmentPin:1'); +#32=NEXT_ASSEMBLY_USAGE_OCCURRENCE('aligmentPin:2','aligmentPin:2', +'aligmentPin:2',#3266,#3269,'aligmentPin:2'); +#33=NEXT_ASSEMBLY_USAGE_OCCURRENCE('aligmentPin:3','aligmentPin:3', +'aligmentPin:3',#3266,#3269,'aligmentPin:3'); +#34=NEXT_ASSEMBLY_USAGE_OCCURRENCE('aligmentPin:4','aligmentPin:4', +'aligmentPin:4',#3266,#3269,'aligmentPin:4'); +#35=TOROIDAL_SURFACE('',#2136,0.749999999999996,0.25); +#36=CONICAL_SURFACE('',#2129,0.899999999999999,0.244978663126859); +#37=SHAPE_REPRESENTATION_RELATIONSHIP('SRR','None',#3262,#40); +#38=SHAPE_REPRESENTATION_RELATIONSHIP('SRR','None',#3263,#41); +#39=SHAPE_REPRESENTATION_RELATIONSHIP('SRR','None',#3264,#42); +#40=ADVANCED_BREP_SHAPE_REPRESENTATION('',(#46),#3239); +#41=ADVANCED_BREP_SHAPE_REPRESENTATION('',(#47),#3240); +#42=ADVANCED_BREP_SHAPE_REPRESENTATION('',(#48),#3241); +#43=STYLED_ITEM('',(#3286),#46); +#44=STYLED_ITEM('',(#3286),#47); +#45=STYLED_ITEM('',(#3285),#48); +#46=MANIFOLD_SOLID_BREP('Body1',#1871); +#47=MANIFOLD_SOLID_BREP('Body1',#1872); +#48=MANIFOLD_SOLID_BREP('Body1',#1873); +#49=FACE_BOUND('',#270,.T.); +#50=FACE_BOUND('',#271,.T.); +#51=FACE_BOUND('',#272,.T.); +#52=FACE_BOUND('',#273,.T.); +#53=FACE_BOUND('',#274,.T.); +#54=FACE_BOUND('',#275,.T.); +#55=FACE_BOUND('',#276,.T.); +#56=FACE_BOUND('',#277,.T.); +#57=FACE_BOUND('',#278,.T.); +#58=FACE_BOUND('',#279,.T.); +#59=FACE_BOUND('',#280,.T.); +#60=FACE_BOUND('',#281,.T.); +#61=FACE_BOUND('',#282,.T.); +#62=FACE_BOUND('',#283,.T.); +#63=FACE_BOUND('',#284,.T.); +#64=FACE_BOUND('',#285,.T.); +#65=FACE_BOUND('',#286,.T.); +#66=FACE_BOUND('',#287,.T.); +#67=FACE_BOUND('',#288,.T.); +#68=FACE_BOUND('',#289,.T.); +#69=FACE_BOUND('',#290,.T.); +#70=FACE_BOUND('',#291,.T.); +#71=FACE_BOUND('',#292,.T.); +#72=FACE_BOUND('',#293,.T.); +#73=FACE_BOUND('',#294,.T.); +#74=FACE_BOUND('',#295,.T.); +#75=FACE_BOUND('',#296,.T.); +#76=FACE_BOUND('',#297,.T.); +#77=FACE_BOUND('',#298,.T.); +#78=FACE_BOUND('',#299,.T.); +#79=FACE_BOUND('',#300,.T.); +#80=FACE_BOUND('',#301,.T.); +#81=FACE_BOUND('',#302,.T.); +#82=FACE_BOUND('',#303,.T.); +#83=FACE_BOUND('',#304,.T.); +#84=FACE_BOUND('',#305,.T.); +#85=FACE_BOUND('',#306,.T.); +#86=FACE_BOUND('',#307,.T.); +#87=FACE_BOUND('',#308,.T.); +#88=FACE_BOUND('',#355,.T.); +#89=FACE_BOUND('',#356,.T.); +#90=FACE_BOUND('',#357,.T.); +#91=FACE_BOUND('',#358,.T.); +#92=FACE_BOUND('',#359,.T.); +#93=FACE_BOUND('',#360,.T.); +#94=FACE_BOUND('',#361,.T.); +#95=FACE_BOUND('',#362,.T.); +#96=FACE_BOUND('',#363,.T.); +#97=FACE_BOUND('',#364,.T.); +#98=FACE_BOUND('',#365,.T.); +#99=FACE_BOUND('',#366,.T.); +#100=FACE_BOUND('',#367,.T.); +#101=FACE_BOUND('',#368,.T.); +#102=FACE_BOUND('',#369,.T.); +#103=FACE_BOUND('',#370,.T.); +#104=FACE_BOUND('',#371,.T.); +#105=FACE_BOUND('',#372,.T.); +#106=FACE_BOUND('',#373,.T.); +#107=FACE_BOUND('',#374,.T.); +#108=FACE_BOUND('',#375,.T.); +#109=FACE_BOUND('',#376,.T.); +#110=FACE_BOUND('',#377,.T.); +#111=FACE_BOUND('',#378,.T.); +#112=FACE_BOUND('',#379,.T.); +#113=FACE_BOUND('',#380,.T.); +#114=FACE_BOUND('',#381,.T.); +#115=FACE_BOUND('',#382,.T.); +#116=FACE_BOUND('',#383,.T.); +#117=FACE_BOUND('',#384,.T.); +#118=FACE_BOUND('',#385,.T.); +#119=FACE_BOUND('',#386,.T.); +#120=FACE_BOUND('',#387,.T.); +#121=FACE_BOUND('',#388,.T.); +#122=FACE_BOUND('',#389,.T.); +#123=FACE_BOUND('',#390,.T.); +#124=FACE_BOUND('',#391,.T.); +#125=FACE_BOUND('',#392,.T.); +#126=FACE_BOUND('',#393,.T.); +#127=FACE_BOUND('',#397,.T.); +#128=FACE_BOUND('',#398,.T.); +#129=FACE_BOUND('',#399,.T.); +#130=FACE_BOUND('',#400,.T.); +#131=FACE_BOUND('',#401,.T.); +#132=FACE_BOUND('',#402,.T.); +#133=FACE_BOUND('',#403,.T.); +#134=FACE_BOUND('',#404,.T.); +#135=FACE_BOUND('',#405,.T.); +#136=FACE_BOUND('',#406,.T.); +#137=FACE_BOUND('',#407,.T.); +#138=FACE_BOUND('',#408,.T.); +#139=FACE_BOUND('',#409,.T.); +#140=FACE_BOUND('',#410,.T.); +#141=FACE_BOUND('',#411,.T.); +#142=FACE_BOUND('',#412,.T.); +#143=FACE_BOUND('',#413,.T.); +#144=FACE_BOUND('',#445,.T.); +#145=FACE_BOUND('',#446,.T.); +#146=FACE_BOUND('',#447,.T.); +#147=FACE_BOUND('',#448,.T.); +#148=FACE_BOUND('',#449,.T.); +#149=FACE_BOUND('',#450,.T.); +#150=FACE_BOUND('',#451,.T.); +#151=FACE_BOUND('',#452,.T.); +#152=FACE_BOUND('',#453,.T.); +#153=FACE_BOUND('',#454,.T.); +#154=FACE_BOUND('',#455,.T.); +#155=FACE_BOUND('',#456,.T.); +#156=FACE_BOUND('',#457,.T.); +#157=FACE_BOUND('',#458,.T.); +#158=FACE_BOUND('',#459,.T.); +#159=FACE_BOUND('',#460,.T.); +#160=FACE_BOUND('',#461,.T.); +#161=PLANE('',#1913); +#162=PLANE('',#1914); +#163=PLANE('',#1959); +#164=PLANE('',#2042); +#165=PLANE('',#2043); +#166=PLANE('',#2044); +#167=PLANE('',#2049); +#168=PLANE('',#2050); +#169=PLANE('',#2076); +#170=PLANE('',#2083); +#171=PLANE('',#2086); +#172=PLANE('',#2089); +#173=PLANE('',#2092); +#174=PLANE('',#2125); +#175=PLANE('',#2126); +#176=PLANE('',#2127); +#177=PLANE('',#2135); +#178=PLANE('',#2139); +#179=FACE_OUTER_BOUND('',#267,.T.); +#180=FACE_OUTER_BOUND('',#268,.T.); +#181=FACE_OUTER_BOUND('',#269,.T.); +#182=FACE_OUTER_BOUND('',#309,.T.); +#183=FACE_OUTER_BOUND('',#310,.T.); +#184=FACE_OUTER_BOUND('',#311,.T.); +#185=FACE_OUTER_BOUND('',#312,.T.); +#186=FACE_OUTER_BOUND('',#313,.T.); +#187=FACE_OUTER_BOUND('',#314,.T.); +#188=FACE_OUTER_BOUND('',#315,.T.); +#189=FACE_OUTER_BOUND('',#316,.T.); +#190=FACE_OUTER_BOUND('',#317,.T.); +#191=FACE_OUTER_BOUND('',#318,.T.); +#192=FACE_OUTER_BOUND('',#319,.T.); +#193=FACE_OUTER_BOUND('',#320,.T.); +#194=FACE_OUTER_BOUND('',#321,.T.); +#195=FACE_OUTER_BOUND('',#322,.T.); +#196=FACE_OUTER_BOUND('',#323,.T.); +#197=FACE_OUTER_BOUND('',#324,.T.); +#198=FACE_OUTER_BOUND('',#325,.T.); +#199=FACE_OUTER_BOUND('',#326,.T.); +#200=FACE_OUTER_BOUND('',#327,.T.); +#201=FACE_OUTER_BOUND('',#328,.T.); +#202=FACE_OUTER_BOUND('',#329,.T.); +#203=FACE_OUTER_BOUND('',#330,.T.); +#204=FACE_OUTER_BOUND('',#331,.T.); +#205=FACE_OUTER_BOUND('',#332,.T.); +#206=FACE_OUTER_BOUND('',#333,.T.); +#207=FACE_OUTER_BOUND('',#334,.T.); +#208=FACE_OUTER_BOUND('',#335,.T.); +#209=FACE_OUTER_BOUND('',#336,.T.); +#210=FACE_OUTER_BOUND('',#337,.T.); +#211=FACE_OUTER_BOUND('',#338,.T.); +#212=FACE_OUTER_BOUND('',#339,.T.); +#213=FACE_OUTER_BOUND('',#340,.T.); +#214=FACE_OUTER_BOUND('',#341,.T.); +#215=FACE_OUTER_BOUND('',#342,.T.); +#216=FACE_OUTER_BOUND('',#343,.T.); +#217=FACE_OUTER_BOUND('',#344,.T.); +#218=FACE_OUTER_BOUND('',#345,.T.); +#219=FACE_OUTER_BOUND('',#346,.T.); +#220=FACE_OUTER_BOUND('',#347,.T.); +#221=FACE_OUTER_BOUND('',#348,.T.); +#222=FACE_OUTER_BOUND('',#349,.T.); +#223=FACE_OUTER_BOUND('',#350,.T.); +#224=FACE_OUTER_BOUND('',#351,.T.); +#225=FACE_OUTER_BOUND('',#352,.T.); +#226=FACE_OUTER_BOUND('',#353,.T.); +#227=FACE_OUTER_BOUND('',#354,.T.); +#228=FACE_OUTER_BOUND('',#394,.T.); +#229=FACE_OUTER_BOUND('',#395,.T.); +#230=FACE_OUTER_BOUND('',#396,.T.); +#231=FACE_OUTER_BOUND('',#414,.T.); +#232=FACE_OUTER_BOUND('',#415,.T.); +#233=FACE_OUTER_BOUND('',#416,.T.); +#234=FACE_OUTER_BOUND('',#417,.T.); +#235=FACE_OUTER_BOUND('',#418,.T.); +#236=FACE_OUTER_BOUND('',#419,.T.); +#237=FACE_OUTER_BOUND('',#420,.T.); +#238=FACE_OUTER_BOUND('',#421,.T.); +#239=FACE_OUTER_BOUND('',#422,.T.); +#240=FACE_OUTER_BOUND('',#423,.T.); +#241=FACE_OUTER_BOUND('',#424,.T.); +#242=FACE_OUTER_BOUND('',#425,.T.); +#243=FACE_OUTER_BOUND('',#426,.T.); +#244=FACE_OUTER_BOUND('',#427,.T.); +#245=FACE_OUTER_BOUND('',#428,.T.); +#246=FACE_OUTER_BOUND('',#429,.T.); +#247=FACE_OUTER_BOUND('',#430,.T.); +#248=FACE_OUTER_BOUND('',#431,.T.); +#249=FACE_OUTER_BOUND('',#432,.T.); +#250=FACE_OUTER_BOUND('',#433,.T.); +#251=FACE_OUTER_BOUND('',#434,.T.); +#252=FACE_OUTER_BOUND('',#435,.T.); +#253=FACE_OUTER_BOUND('',#436,.T.); +#254=FACE_OUTER_BOUND('',#437,.T.); +#255=FACE_OUTER_BOUND('',#438,.T.); +#256=FACE_OUTER_BOUND('',#439,.T.); +#257=FACE_OUTER_BOUND('',#440,.T.); +#258=FACE_OUTER_BOUND('',#441,.T.); +#259=FACE_OUTER_BOUND('',#442,.T.); +#260=FACE_OUTER_BOUND('',#443,.T.); +#261=FACE_OUTER_BOUND('',#444,.T.); +#262=FACE_OUTER_BOUND('',#462,.T.); +#263=FACE_OUTER_BOUND('',#463,.T.); +#264=FACE_OUTER_BOUND('',#464,.T.); +#265=FACE_OUTER_BOUND('',#465,.T.); +#266=FACE_OUTER_BOUND('',#466,.T.); +#267=EDGE_LOOP('',(#1225,#1226,#1227,#1228)); +#268=EDGE_LOOP('',(#1229,#1230,#1231,#1232)); +#269=EDGE_LOOP('',(#1233,#1234,#1235,#1236,#1237,#1238,#1239,#1240)); +#270=EDGE_LOOP('',(#1241)); +#271=EDGE_LOOP('',(#1242)); +#272=EDGE_LOOP('',(#1243)); +#273=EDGE_LOOP('',(#1244)); +#274=EDGE_LOOP('',(#1245)); +#275=EDGE_LOOP('',(#1246)); +#276=EDGE_LOOP('',(#1247)); +#277=EDGE_LOOP('',(#1248)); +#278=EDGE_LOOP('',(#1249)); +#279=EDGE_LOOP('',(#1250)); +#280=EDGE_LOOP('',(#1251)); +#281=EDGE_LOOP('',(#1252)); +#282=EDGE_LOOP('',(#1253)); +#283=EDGE_LOOP('',(#1254)); +#284=EDGE_LOOP('',(#1255)); +#285=EDGE_LOOP('',(#1256)); +#286=EDGE_LOOP('',(#1257)); +#287=EDGE_LOOP('',(#1258)); +#288=EDGE_LOOP('',(#1259)); +#289=EDGE_LOOP('',(#1260)); +#290=EDGE_LOOP('',(#1261)); +#291=EDGE_LOOP('',(#1262)); +#292=EDGE_LOOP('',(#1263)); +#293=EDGE_LOOP('',(#1264)); +#294=EDGE_LOOP('',(#1265)); +#295=EDGE_LOOP('',(#1266)); +#296=EDGE_LOOP('',(#1267)); +#297=EDGE_LOOP('',(#1268)); +#298=EDGE_LOOP('',(#1269)); +#299=EDGE_LOOP('',(#1270)); +#300=EDGE_LOOP('',(#1271)); +#301=EDGE_LOOP('',(#1272)); +#302=EDGE_LOOP('',(#1273)); +#303=EDGE_LOOP('',(#1274)); +#304=EDGE_LOOP('',(#1275)); +#305=EDGE_LOOP('',(#1276)); +#306=EDGE_LOOP('',(#1277)); +#307=EDGE_LOOP('',(#1278)); +#308=EDGE_LOOP('',(#1279)); +#309=EDGE_LOOP('',(#1280,#1281,#1282,#1283)); +#310=EDGE_LOOP('',(#1284,#1285,#1286,#1287)); +#311=EDGE_LOOP('',(#1288,#1289,#1290,#1291)); +#312=EDGE_LOOP('',(#1292,#1293,#1294,#1295)); +#313=EDGE_LOOP('',(#1296,#1297,#1298,#1299)); +#314=EDGE_LOOP('',(#1300,#1301,#1302,#1303)); +#315=EDGE_LOOP('',(#1304,#1305,#1306,#1307)); +#316=EDGE_LOOP('',(#1308,#1309,#1310,#1311)); +#317=EDGE_LOOP('',(#1312,#1313,#1314,#1315)); +#318=EDGE_LOOP('',(#1316,#1317,#1318,#1319)); +#319=EDGE_LOOP('',(#1320,#1321,#1322,#1323)); +#320=EDGE_LOOP('',(#1324,#1325,#1326,#1327)); +#321=EDGE_LOOP('',(#1328,#1329,#1330,#1331)); +#322=EDGE_LOOP('',(#1332,#1333,#1334,#1335)); +#323=EDGE_LOOP('',(#1336,#1337,#1338,#1339)); +#324=EDGE_LOOP('',(#1340,#1341,#1342,#1343)); +#325=EDGE_LOOP('',(#1344,#1345,#1346,#1347)); +#326=EDGE_LOOP('',(#1348,#1349,#1350,#1351)); +#327=EDGE_LOOP('',(#1352,#1353,#1354,#1355)); +#328=EDGE_LOOP('',(#1356,#1357,#1358,#1359)); +#329=EDGE_LOOP('',(#1360,#1361,#1362,#1363)); +#330=EDGE_LOOP('',(#1364,#1365,#1366,#1367)); +#331=EDGE_LOOP('',(#1368,#1369,#1370,#1371)); +#332=EDGE_LOOP('',(#1372,#1373,#1374,#1375)); +#333=EDGE_LOOP('',(#1376,#1377,#1378,#1379)); +#334=EDGE_LOOP('',(#1380,#1381,#1382,#1383)); +#335=EDGE_LOOP('',(#1384,#1385,#1386,#1387)); +#336=EDGE_LOOP('',(#1388,#1389,#1390,#1391)); +#337=EDGE_LOOP('',(#1392,#1393,#1394,#1395)); +#338=EDGE_LOOP('',(#1396,#1397,#1398,#1399)); +#339=EDGE_LOOP('',(#1400,#1401,#1402,#1403)); +#340=EDGE_LOOP('',(#1404,#1405,#1406,#1407)); +#341=EDGE_LOOP('',(#1408,#1409,#1410,#1411)); +#342=EDGE_LOOP('',(#1412,#1413,#1414,#1415)); +#343=EDGE_LOOP('',(#1416,#1417,#1418,#1419)); +#344=EDGE_LOOP('',(#1420,#1421,#1422,#1423)); +#345=EDGE_LOOP('',(#1424,#1425,#1426,#1427)); +#346=EDGE_LOOP('',(#1428,#1429,#1430,#1431)); +#347=EDGE_LOOP('',(#1432,#1433,#1434,#1435)); +#348=EDGE_LOOP('',(#1436,#1437,#1438,#1439)); +#349=EDGE_LOOP('',(#1440,#1441,#1442,#1443)); +#350=EDGE_LOOP('',(#1444,#1445,#1446,#1447)); +#351=EDGE_LOOP('',(#1448,#1449,#1450,#1451)); +#352=EDGE_LOOP('',(#1452,#1453,#1454,#1455)); +#353=EDGE_LOOP('',(#1456,#1457,#1458,#1459)); +#354=EDGE_LOOP('',(#1460,#1461,#1462,#1463,#1464,#1465,#1466,#1467)); +#355=EDGE_LOOP('',(#1468)); +#356=EDGE_LOOP('',(#1469)); +#357=EDGE_LOOP('',(#1470)); +#358=EDGE_LOOP('',(#1471)); +#359=EDGE_LOOP('',(#1472)); +#360=EDGE_LOOP('',(#1473)); +#361=EDGE_LOOP('',(#1474)); +#362=EDGE_LOOP('',(#1475)); +#363=EDGE_LOOP('',(#1476)); +#364=EDGE_LOOP('',(#1477)); +#365=EDGE_LOOP('',(#1478)); +#366=EDGE_LOOP('',(#1479)); +#367=EDGE_LOOP('',(#1480)); +#368=EDGE_LOOP('',(#1481)); +#369=EDGE_LOOP('',(#1482)); +#370=EDGE_LOOP('',(#1483)); +#371=EDGE_LOOP('',(#1484)); +#372=EDGE_LOOP('',(#1485)); +#373=EDGE_LOOP('',(#1486)); +#374=EDGE_LOOP('',(#1487)); +#375=EDGE_LOOP('',(#1488)); +#376=EDGE_LOOP('',(#1489)); +#377=EDGE_LOOP('',(#1490)); +#378=EDGE_LOOP('',(#1491)); +#379=EDGE_LOOP('',(#1492)); +#380=EDGE_LOOP('',(#1493)); +#381=EDGE_LOOP('',(#1494)); +#382=EDGE_LOOP('',(#1495)); +#383=EDGE_LOOP('',(#1496)); +#384=EDGE_LOOP('',(#1497)); +#385=EDGE_LOOP('',(#1498)); +#386=EDGE_LOOP('',(#1499)); +#387=EDGE_LOOP('',(#1500)); +#388=EDGE_LOOP('',(#1501)); +#389=EDGE_LOOP('',(#1502)); +#390=EDGE_LOOP('',(#1503)); +#391=EDGE_LOOP('',(#1504)); +#392=EDGE_LOOP('',(#1505)); +#393=EDGE_LOOP('',(#1506)); +#394=EDGE_LOOP('',(#1507,#1508,#1509,#1510)); +#395=EDGE_LOOP('',(#1511,#1512,#1513,#1514)); +#396=EDGE_LOOP('',(#1515,#1516,#1517,#1518,#1519,#1520,#1521,#1522)); +#397=EDGE_LOOP('',(#1523)); +#398=EDGE_LOOP('',(#1524)); +#399=EDGE_LOOP('',(#1525)); +#400=EDGE_LOOP('',(#1526)); +#401=EDGE_LOOP('',(#1527)); +#402=EDGE_LOOP('',(#1528)); +#403=EDGE_LOOP('',(#1529)); +#404=EDGE_LOOP('',(#1530)); +#405=EDGE_LOOP('',(#1531)); +#406=EDGE_LOOP('',(#1532)); +#407=EDGE_LOOP('',(#1533)); +#408=EDGE_LOOP('',(#1534)); +#409=EDGE_LOOP('',(#1535)); +#410=EDGE_LOOP('',(#1536)); +#411=EDGE_LOOP('',(#1537)); +#412=EDGE_LOOP('',(#1538)); +#413=EDGE_LOOP('',(#1539,#1540,#1541,#1542,#1543,#1544,#1545,#1546)); +#414=EDGE_LOOP('',(#1547,#1548,#1549,#1550)); +#415=EDGE_LOOP('',(#1551,#1552,#1553,#1554)); +#416=EDGE_LOOP('',(#1555,#1556,#1557,#1558)); +#417=EDGE_LOOP('',(#1559,#1560,#1561,#1562)); +#418=EDGE_LOOP('',(#1563,#1564,#1565,#1566)); +#419=EDGE_LOOP('',(#1567,#1568,#1569,#1570)); +#420=EDGE_LOOP('',(#1571,#1572,#1573,#1574)); +#421=EDGE_LOOP('',(#1575,#1576,#1577,#1578)); +#422=EDGE_LOOP('',(#1579,#1580,#1581,#1582)); +#423=EDGE_LOOP('',(#1583,#1584,#1585,#1586)); +#424=EDGE_LOOP('',(#1587,#1588,#1589,#1590)); +#425=EDGE_LOOP('',(#1591,#1592,#1593,#1594)); +#426=EDGE_LOOP('',(#1595,#1596,#1597,#1598)); +#427=EDGE_LOOP('',(#1599,#1600,#1601,#1602)); +#428=EDGE_LOOP('',(#1603,#1604,#1605,#1606)); +#429=EDGE_LOOP('',(#1607,#1608,#1609,#1610)); +#430=EDGE_LOOP('',(#1611,#1612,#1613,#1614)); +#431=EDGE_LOOP('',(#1615,#1616,#1617,#1618)); +#432=EDGE_LOOP('',(#1619,#1620,#1621,#1622)); +#433=EDGE_LOOP('',(#1623,#1624,#1625,#1626)); +#434=EDGE_LOOP('',(#1627,#1628,#1629,#1630)); +#435=EDGE_LOOP('',(#1631,#1632,#1633,#1634)); +#436=EDGE_LOOP('',(#1635,#1636,#1637,#1638)); +#437=EDGE_LOOP('',(#1639,#1640,#1641,#1642)); +#438=EDGE_LOOP('',(#1643,#1644,#1645,#1646)); +#439=EDGE_LOOP('',(#1647,#1648,#1649,#1650)); +#440=EDGE_LOOP('',(#1651,#1652,#1653,#1654)); +#441=EDGE_LOOP('',(#1655,#1656,#1657,#1658)); +#442=EDGE_LOOP('',(#1659,#1660,#1661,#1662)); +#443=EDGE_LOOP('',(#1663,#1664,#1665,#1666)); +#444=EDGE_LOOP('',(#1667,#1668,#1669,#1670,#1671,#1672,#1673,#1674)); +#445=EDGE_LOOP('',(#1675)); +#446=EDGE_LOOP('',(#1676)); +#447=EDGE_LOOP('',(#1677)); +#448=EDGE_LOOP('',(#1678)); +#449=EDGE_LOOP('',(#1679)); +#450=EDGE_LOOP('',(#1680)); +#451=EDGE_LOOP('',(#1681)); +#452=EDGE_LOOP('',(#1682)); +#453=EDGE_LOOP('',(#1683)); +#454=EDGE_LOOP('',(#1684)); +#455=EDGE_LOOP('',(#1685)); +#456=EDGE_LOOP('',(#1686)); +#457=EDGE_LOOP('',(#1687)); +#458=EDGE_LOOP('',(#1688)); +#459=EDGE_LOOP('',(#1689)); +#460=EDGE_LOOP('',(#1690)); +#461=EDGE_LOOP('',(#1691,#1692,#1693,#1694,#1695,#1696,#1697,#1698)); +#462=EDGE_LOOP('',(#1699,#1700,#1701,#1702)); +#463=EDGE_LOOP('',(#1703,#1704,#1705,#1706,#1707)); +#464=EDGE_LOOP('',(#1708)); +#465=EDGE_LOOP('',(#1709,#1710,#1711,#1712,#1713)); +#466=EDGE_LOOP('',(#1714)); +#467=LINE('',#2734,#572); +#468=LINE('',#2737,#573); +#469=LINE('',#2740,#574); +#470=LINE('',#2742,#575); +#471=LINE('',#2743,#576); +#472=LINE('',#2746,#577); +#473=LINE('',#2750,#578); +#474=LINE('',#2754,#579); +#475=LINE('',#2838,#580); +#476=LINE('',#2839,#581); +#477=LINE('',#2842,#582); +#478=LINE('',#2843,#583); +#479=LINE('',#2847,#584); +#480=LINE('',#2851,#585); +#481=LINE('',#2855,#586); +#482=LINE('',#2859,#587); +#483=LINE('',#2863,#588); +#484=LINE('',#2867,#589); +#485=LINE('',#2871,#590); +#486=LINE('',#2875,#591); +#487=LINE('',#2879,#592); +#488=LINE('',#2883,#593); +#489=LINE('',#2887,#594); +#490=LINE('',#2891,#595); +#491=LINE('',#2895,#596); +#492=LINE('',#2899,#597); +#493=LINE('',#2903,#598); +#494=LINE('',#2907,#599); +#495=LINE('',#2911,#600); +#496=LINE('',#2915,#601); +#497=LINE('',#2919,#602); +#498=LINE('',#2923,#603); +#499=LINE('',#2927,#604); +#500=LINE('',#2931,#605); +#501=LINE('',#2935,#606); +#502=LINE('',#2939,#607); +#503=LINE('',#2943,#608); +#504=LINE('',#2947,#609); +#505=LINE('',#2951,#610); +#506=LINE('',#2955,#611); +#507=LINE('',#2959,#612); +#508=LINE('',#2963,#613); +#509=LINE('',#2967,#614); +#510=LINE('',#2971,#615); +#511=LINE('',#2975,#616); +#512=LINE('',#2979,#617); +#513=LINE('',#2983,#618); +#514=LINE('',#2987,#619); +#515=LINE('',#2991,#620); +#516=LINE('',#2995,#621); +#517=LINE('',#2999,#622); +#518=LINE('',#3003,#623); +#519=LINE('',#3007,#624); +#520=LINE('',#3009,#625); +#521=LINE('',#3011,#626); +#522=LINE('',#3019,#627); +#523=LINE('',#3022,#628); +#524=LINE('',#3025,#629); +#525=LINE('',#3027,#630); +#526=LINE('',#3028,#631); +#527=LINE('',#3031,#632); +#528=LINE('',#3035,#633); +#529=LINE('',#3039,#634); +#530=LINE('',#3077,#635); +#531=LINE('',#3081,#636); +#532=LINE('',#3085,#637); +#533=LINE('',#3088,#638); +#534=LINE('',#3093,#639); +#535=LINE('',#3094,#640); +#536=LINE('',#3097,#641); +#537=LINE('',#3098,#642); +#538=LINE('',#3102,#643); +#539=LINE('',#3106,#644); +#540=LINE('',#3109,#645); +#541=LINE('',#3112,#646); +#542=LINE('',#3115,#647); +#543=LINE('',#3116,#648); +#544=LINE('',#3119,#649); +#545=LINE('',#3123,#650); +#546=LINE('',#3124,#651); +#547=LINE('',#3127,#652); +#548=LINE('',#3131,#653); +#549=LINE('',#3132,#654); +#550=LINE('',#3135,#655); +#551=LINE('',#3138,#656); +#552=LINE('',#3142,#657); +#553=LINE('',#3146,#658); +#554=LINE('',#3150,#659); +#555=LINE('',#3154,#660); +#556=LINE('',#3158,#661); +#557=LINE('',#3162,#662); +#558=LINE('',#3166,#663); +#559=LINE('',#3170,#664); +#560=LINE('',#3174,#665); +#561=LINE('',#3178,#666); +#562=LINE('',#3182,#667); +#563=LINE('',#3186,#668); +#564=LINE('',#3190,#669); +#565=LINE('',#3194,#670); +#566=LINE('',#3198,#671); +#567=LINE('',#3202,#672); +#568=LINE('',#3204,#673); +#569=LINE('',#3206,#674); +#570=LINE('',#3213,#675); +#571=LINE('',#3217,#676); +#572=VECTOR('',#2154,10.); +#573=VECTOR('',#2157,10.); +#574=VECTOR('',#2160,10.); +#575=VECTOR('',#2161,10.); +#576=VECTOR('',#2162,10.); +#577=VECTOR('',#2165,10.); +#578=VECTOR('',#2168,10.); +#579=VECTOR('',#2171,10.); +#580=VECTOR('',#2256,10.); +#581=VECTOR('',#2257,10.); +#582=VECTOR('',#2260,10.); +#583=VECTOR('',#2261,10.); +#584=VECTOR('',#2266,10.); +#585=VECTOR('',#2271,10.); +#586=VECTOR('',#2276,1.75); +#587=VECTOR('',#2281,1.75); +#588=VECTOR('',#2286,1.); +#589=VECTOR('',#2291,1.); +#590=VECTOR('',#2296,1.); +#591=VECTOR('',#2301,1.); +#592=VECTOR('',#2306,0.8115); +#593=VECTOR('',#2311,0.8115); +#594=VECTOR('',#2316,0.8115); +#595=VECTOR('',#2321,0.8115); +#596=VECTOR('',#2326,0.8115); +#597=VECTOR('',#2331,0.8115); +#598=VECTOR('',#2336,0.8115); +#599=VECTOR('',#2341,0.8115); +#600=VECTOR('',#2346,0.8115); +#601=VECTOR('',#2351,0.8115); +#602=VECTOR('',#2356,0.8115); +#603=VECTOR('',#2361,0.8115); +#604=VECTOR('',#2366,0.8115); +#605=VECTOR('',#2371,0.8115); +#606=VECTOR('',#2376,0.8115); +#607=VECTOR('',#2381,0.8115); +#608=VECTOR('',#2386,0.8115); +#609=VECTOR('',#2391,0.8115); +#610=VECTOR('',#2396,0.8115); +#611=VECTOR('',#2401,0.8115); +#612=VECTOR('',#2406,0.8115); +#613=VECTOR('',#2411,0.8115); +#614=VECTOR('',#2416,0.8115); +#615=VECTOR('',#2421,0.8115); +#616=VECTOR('',#2426,0.8115); +#617=VECTOR('',#2431,0.8115); +#618=VECTOR('',#2436,0.8115); +#619=VECTOR('',#2441,0.8115); +#620=VECTOR('',#2446,0.8115); +#621=VECTOR('',#2451,0.8115); +#622=VECTOR('',#2456,0.8115); +#623=VECTOR('',#2461,0.8115); +#624=VECTOR('',#2466,0.8115); +#625=VECTOR('',#2469,10.); +#626=VECTOR('',#2472,10.); +#627=VECTOR('',#2481,10.); +#628=VECTOR('',#2484,10.); +#629=VECTOR('',#2487,10.); +#630=VECTOR('',#2488,10.); +#631=VECTOR('',#2489,10.); +#632=VECTOR('',#2492,10.); +#633=VECTOR('',#2495,10.); +#634=VECTOR('',#2498,10.); +#635=VECTOR('',#2535,10.); +#636=VECTOR('',#2538,10.); +#637=VECTOR('',#2541,10.); +#638=VECTOR('',#2544,10.); +#639=VECTOR('',#2549,10.); +#640=VECTOR('',#2550,10.); +#641=VECTOR('',#2553,10.); +#642=VECTOR('',#2554,10.); +#643=VECTOR('',#2559,10.); +#644=VECTOR('',#2564,10.); +#645=VECTOR('',#2567,10.); +#646=VECTOR('',#2570,10.); +#647=VECTOR('',#2573,10.); +#648=VECTOR('',#2574,10.); +#649=VECTOR('',#2577,10.); +#650=VECTOR('',#2582,10.); +#651=VECTOR('',#2583,10.); +#652=VECTOR('',#2586,10.); +#653=VECTOR('',#2591,10.); +#654=VECTOR('',#2592,10.); +#655=VECTOR('',#2595,10.); +#656=VECTOR('',#2600,10.); +#657=VECTOR('',#2605,1.); +#658=VECTOR('',#2610,1.); +#659=VECTOR('',#2615,1.); +#660=VECTOR('',#2620,1.); +#661=VECTOR('',#2625,0.8115); +#662=VECTOR('',#2630,0.8115); +#663=VECTOR('',#2635,0.8115); +#664=VECTOR('',#2640,0.8115); +#665=VECTOR('',#2645,0.8115); +#666=VECTOR('',#2650,0.8115); +#667=VECTOR('',#2655,0.8115); +#668=VECTOR('',#2660,0.8115); +#669=VECTOR('',#2665,0.8115); +#670=VECTOR('',#2670,0.8115); +#671=VECTOR('',#2675,0.8115); +#672=VECTOR('',#2680,0.8115); +#673=VECTOR('',#2683,10.); +#674=VECTOR('',#2686,10.); +#675=VECTOR('',#2695,0.899999999999999); +#676=VECTOR('',#2700,0.999999999999996); +#677=CIRCLE('',#1911,6.); +#678=CIRCLE('',#1912,6.); +#679=CIRCLE('',#1915,6.); +#680=CIRCLE('',#1916,6.); +#681=CIRCLE('',#1917,6.); +#682=CIRCLE('',#1918,1.75); +#683=CIRCLE('',#1919,1.75); +#684=CIRCLE('',#1920,1.); +#685=CIRCLE('',#1921,1.); +#686=CIRCLE('',#1922,1.); +#687=CIRCLE('',#1923,1.); +#688=CIRCLE('',#1924,0.8115); +#689=CIRCLE('',#1925,0.8115); +#690=CIRCLE('',#1926,0.8115); +#691=CIRCLE('',#1927,0.8115); +#692=CIRCLE('',#1928,0.8115); +#693=CIRCLE('',#1929,0.8115); +#694=CIRCLE('',#1930,0.8115); +#695=CIRCLE('',#1931,0.8115); +#696=CIRCLE('',#1932,0.8115); +#697=CIRCLE('',#1933,0.8115); +#698=CIRCLE('',#1934,0.8115); +#699=CIRCLE('',#1935,0.8115); +#700=CIRCLE('',#1936,0.8115); +#701=CIRCLE('',#1937,0.8115); +#702=CIRCLE('',#1938,0.8115); +#703=CIRCLE('',#1939,0.8115); +#704=CIRCLE('',#1940,0.8115); +#705=CIRCLE('',#1941,0.8115); +#706=CIRCLE('',#1942,0.8115); +#707=CIRCLE('',#1943,0.8115); +#708=CIRCLE('',#1944,0.8115); +#709=CIRCLE('',#1945,0.8115); +#710=CIRCLE('',#1946,0.8115); +#711=CIRCLE('',#1947,0.8115); +#712=CIRCLE('',#1948,0.8115); +#713=CIRCLE('',#1949,0.8115); +#714=CIRCLE('',#1950,0.8115); +#715=CIRCLE('',#1951,0.8115); +#716=CIRCLE('',#1952,0.8115); +#717=CIRCLE('',#1953,0.8115); +#718=CIRCLE('',#1954,0.8115); +#719=CIRCLE('',#1955,0.8115); +#720=CIRCLE('',#1956,0.8115); +#721=CIRCLE('',#1958,6.); +#722=CIRCLE('',#1961,6.); +#723=CIRCLE('',#1963,6.); +#724=CIRCLE('',#1965,1.75); +#725=CIRCLE('',#1967,1.75); +#726=CIRCLE('',#1969,1.); +#727=CIRCLE('',#1971,1.); +#728=CIRCLE('',#1973,1.); +#729=CIRCLE('',#1975,1.); +#730=CIRCLE('',#1977,0.8115); +#731=CIRCLE('',#1979,0.8115); +#732=CIRCLE('',#1981,0.8115); +#733=CIRCLE('',#1983,0.8115); +#734=CIRCLE('',#1985,0.8115); +#735=CIRCLE('',#1987,0.8115); +#736=CIRCLE('',#1989,0.8115); +#737=CIRCLE('',#1991,0.8115); +#738=CIRCLE('',#1993,0.8115); +#739=CIRCLE('',#1995,0.8115); +#740=CIRCLE('',#1997,0.8115); +#741=CIRCLE('',#1999,0.8115); +#742=CIRCLE('',#2001,0.8115); +#743=CIRCLE('',#2003,0.8115); +#744=CIRCLE('',#2005,0.8115); +#745=CIRCLE('',#2007,0.8115); +#746=CIRCLE('',#2009,0.8115); +#747=CIRCLE('',#2011,0.8115); +#748=CIRCLE('',#2013,0.8115); +#749=CIRCLE('',#2015,0.8115); +#750=CIRCLE('',#2017,0.8115); +#751=CIRCLE('',#2019,0.8115); +#752=CIRCLE('',#2021,0.8115); +#753=CIRCLE('',#2023,0.8115); +#754=CIRCLE('',#2025,0.8115); +#755=CIRCLE('',#2027,0.8115); +#756=CIRCLE('',#2029,0.8115); +#757=CIRCLE('',#2031,0.8115); +#758=CIRCLE('',#2033,0.8115); +#759=CIRCLE('',#2035,0.8115); +#760=CIRCLE('',#2037,0.8115); +#761=CIRCLE('',#2039,0.8115); +#762=CIRCLE('',#2041,0.8115); +#763=CIRCLE('',#2047,3.); +#764=CIRCLE('',#2048,3.); +#765=CIRCLE('',#2051,3.); +#766=CIRCLE('',#2052,3.); +#767=CIRCLE('',#2053,3.); +#768=CIRCLE('',#2054,1.); +#769=CIRCLE('',#2055,1.); +#770=CIRCLE('',#2056,1.); +#771=CIRCLE('',#2057,1.); +#772=CIRCLE('',#2058,0.8115); +#773=CIRCLE('',#2059,0.8115); +#774=CIRCLE('',#2060,0.8115); +#775=CIRCLE('',#2061,0.8115); +#776=CIRCLE('',#2062,0.8115); +#777=CIRCLE('',#2063,0.8115); +#778=CIRCLE('',#2064,0.8115); +#779=CIRCLE('',#2065,0.8115); +#780=CIRCLE('',#2066,0.8115); +#781=CIRCLE('',#2067,0.8115); +#782=CIRCLE('',#2068,0.8115); +#783=CIRCLE('',#2069,0.8115); +#784=CIRCLE('',#2070,1.); +#785=CIRCLE('',#2071,1.); +#786=CIRCLE('',#2072,1.); +#787=CIRCLE('',#2073,1.); +#788=CIRCLE('',#2075,3.); +#789=CIRCLE('',#2078,3.); +#790=CIRCLE('',#2080,3.); +#791=CIRCLE('',#2082,1.); +#792=CIRCLE('',#2085,1.); +#793=CIRCLE('',#2088,1.); +#794=CIRCLE('',#2091,1.); +#795=CIRCLE('',#2094,1.); +#796=CIRCLE('',#2096,1.); +#797=CIRCLE('',#2098,1.); +#798=CIRCLE('',#2100,1.); +#799=CIRCLE('',#2102,0.8115); +#800=CIRCLE('',#2104,0.8115); +#801=CIRCLE('',#2106,0.8115); +#802=CIRCLE('',#2108,0.8115); +#803=CIRCLE('',#2110,0.8115); +#804=CIRCLE('',#2112,0.8115); +#805=CIRCLE('',#2114,0.8115); +#806=CIRCLE('',#2116,0.8115); +#807=CIRCLE('',#2118,0.8115); +#808=CIRCLE('',#2120,0.8115); +#809=CIRCLE('',#2122,0.8115); +#810=CIRCLE('',#2124,0.8115); +#811=CIRCLE('',#2130,0.800000000000001); +#812=CIRCLE('',#2131,0.999999999999996); +#813=CIRCLE('',#2133,0.999999999999996); +#814=CIRCLE('',#2134,0.999999999999996); +#815=CIRCLE('',#2137,0.749999999999996); +#816=CIRCLE('',#2138,0.25); +#817=VERTEX_POINT('',#2730); +#818=VERTEX_POINT('',#2731); +#819=VERTEX_POINT('',#2733); +#820=VERTEX_POINT('',#2735); +#821=VERTEX_POINT('',#2739); +#822=VERTEX_POINT('',#2741); +#823=VERTEX_POINT('',#2745); +#824=VERTEX_POINT('',#2747); +#825=VERTEX_POINT('',#2749); +#826=VERTEX_POINT('',#2751); +#827=VERTEX_POINT('',#2753); +#828=VERTEX_POINT('',#2756); +#829=VERTEX_POINT('',#2758); +#830=VERTEX_POINT('',#2760); +#831=VERTEX_POINT('',#2762); +#832=VERTEX_POINT('',#2764); +#833=VERTEX_POINT('',#2766); +#834=VERTEX_POINT('',#2768); +#835=VERTEX_POINT('',#2770); +#836=VERTEX_POINT('',#2772); +#837=VERTEX_POINT('',#2774); +#838=VERTEX_POINT('',#2776); +#839=VERTEX_POINT('',#2778); +#840=VERTEX_POINT('',#2780); +#841=VERTEX_POINT('',#2782); +#842=VERTEX_POINT('',#2784); +#843=VERTEX_POINT('',#2786); +#844=VERTEX_POINT('',#2788); +#845=VERTEX_POINT('',#2790); +#846=VERTEX_POINT('',#2792); +#847=VERTEX_POINT('',#2794); +#848=VERTEX_POINT('',#2796); +#849=VERTEX_POINT('',#2798); +#850=VERTEX_POINT('',#2800); +#851=VERTEX_POINT('',#2802); +#852=VERTEX_POINT('',#2804); +#853=VERTEX_POINT('',#2806); +#854=VERTEX_POINT('',#2808); +#855=VERTEX_POINT('',#2810); +#856=VERTEX_POINT('',#2812); +#857=VERTEX_POINT('',#2814); +#858=VERTEX_POINT('',#2816); +#859=VERTEX_POINT('',#2818); +#860=VERTEX_POINT('',#2820); +#861=VERTEX_POINT('',#2822); +#862=VERTEX_POINT('',#2824); +#863=VERTEX_POINT('',#2826); +#864=VERTEX_POINT('',#2828); +#865=VERTEX_POINT('',#2830); +#866=VERTEX_POINT('',#2832); +#867=VERTEX_POINT('',#2835); +#868=VERTEX_POINT('',#2836); +#869=VERTEX_POINT('',#2841); +#870=VERTEX_POINT('',#2845); +#871=VERTEX_POINT('',#2849); +#872=VERTEX_POINT('',#2853); +#873=VERTEX_POINT('',#2857); +#874=VERTEX_POINT('',#2861); +#875=VERTEX_POINT('',#2865); +#876=VERTEX_POINT('',#2869); +#877=VERTEX_POINT('',#2873); +#878=VERTEX_POINT('',#2877); +#879=VERTEX_POINT('',#2881); +#880=VERTEX_POINT('',#2885); +#881=VERTEX_POINT('',#2889); +#882=VERTEX_POINT('',#2893); +#883=VERTEX_POINT('',#2897); +#884=VERTEX_POINT('',#2901); +#885=VERTEX_POINT('',#2905); +#886=VERTEX_POINT('',#2909); +#887=VERTEX_POINT('',#2913); +#888=VERTEX_POINT('',#2917); +#889=VERTEX_POINT('',#2921); +#890=VERTEX_POINT('',#2925); +#891=VERTEX_POINT('',#2929); +#892=VERTEX_POINT('',#2933); +#893=VERTEX_POINT('',#2937); +#894=VERTEX_POINT('',#2941); +#895=VERTEX_POINT('',#2945); +#896=VERTEX_POINT('',#2949); +#897=VERTEX_POINT('',#2953); +#898=VERTEX_POINT('',#2957); +#899=VERTEX_POINT('',#2961); +#900=VERTEX_POINT('',#2965); +#901=VERTEX_POINT('',#2969); +#902=VERTEX_POINT('',#2973); +#903=VERTEX_POINT('',#2977); +#904=VERTEX_POINT('',#2981); +#905=VERTEX_POINT('',#2985); +#906=VERTEX_POINT('',#2989); +#907=VERTEX_POINT('',#2993); +#908=VERTEX_POINT('',#2997); +#909=VERTEX_POINT('',#3001); +#910=VERTEX_POINT('',#3005); +#911=VERTEX_POINT('',#3015); +#912=VERTEX_POINT('',#3016); +#913=VERTEX_POINT('',#3018); +#914=VERTEX_POINT('',#3020); +#915=VERTEX_POINT('',#3024); +#916=VERTEX_POINT('',#3026); +#917=VERTEX_POINT('',#3030); +#918=VERTEX_POINT('',#3032); +#919=VERTEX_POINT('',#3034); +#920=VERTEX_POINT('',#3036); +#921=VERTEX_POINT('',#3038); +#922=VERTEX_POINT('',#3041); +#923=VERTEX_POINT('',#3043); +#924=VERTEX_POINT('',#3045); +#925=VERTEX_POINT('',#3047); +#926=VERTEX_POINT('',#3049); +#927=VERTEX_POINT('',#3051); +#928=VERTEX_POINT('',#3053); +#929=VERTEX_POINT('',#3055); +#930=VERTEX_POINT('',#3057); +#931=VERTEX_POINT('',#3059); +#932=VERTEX_POINT('',#3061); +#933=VERTEX_POINT('',#3063); +#934=VERTEX_POINT('',#3065); +#935=VERTEX_POINT('',#3067); +#936=VERTEX_POINT('',#3069); +#937=VERTEX_POINT('',#3071); +#938=VERTEX_POINT('',#3073); +#939=VERTEX_POINT('',#3074); +#940=VERTEX_POINT('',#3076); +#941=VERTEX_POINT('',#3078); +#942=VERTEX_POINT('',#3080); +#943=VERTEX_POINT('',#3082); +#944=VERTEX_POINT('',#3084); +#945=VERTEX_POINT('',#3086); +#946=VERTEX_POINT('',#3090); +#947=VERTEX_POINT('',#3091); +#948=VERTEX_POINT('',#3096); +#949=VERTEX_POINT('',#3100); +#950=VERTEX_POINT('',#3104); +#951=VERTEX_POINT('',#3108); +#952=VERTEX_POINT('',#3110); +#953=VERTEX_POINT('',#3114); +#954=VERTEX_POINT('',#3118); +#955=VERTEX_POINT('',#3122); +#956=VERTEX_POINT('',#3126); +#957=VERTEX_POINT('',#3130); +#958=VERTEX_POINT('',#3134); +#959=VERTEX_POINT('',#3140); +#960=VERTEX_POINT('',#3144); +#961=VERTEX_POINT('',#3148); +#962=VERTEX_POINT('',#3152); +#963=VERTEX_POINT('',#3156); +#964=VERTEX_POINT('',#3160); +#965=VERTEX_POINT('',#3164); +#966=VERTEX_POINT('',#3168); +#967=VERTEX_POINT('',#3172); +#968=VERTEX_POINT('',#3176); +#969=VERTEX_POINT('',#3180); +#970=VERTEX_POINT('',#3184); +#971=VERTEX_POINT('',#3188); +#972=VERTEX_POINT('',#3192); +#973=VERTEX_POINT('',#3196); +#974=VERTEX_POINT('',#3200); +#975=VERTEX_POINT('',#3210); +#976=VERTEX_POINT('',#3212); +#977=VERTEX_POINT('',#3216); +#978=VERTEX_POINT('',#3218); +#979=VERTEX_POINT('',#3223); +#980=EDGE_CURVE('',#817,#818,#677,.T.); +#981=EDGE_CURVE('',#818,#819,#467,.T.); +#982=EDGE_CURVE('',#819,#820,#678,.T.); +#983=EDGE_CURVE('',#820,#817,#468,.T.); +#984=EDGE_CURVE('',#820,#821,#469,.F.); +#985=EDGE_CURVE('',#822,#821,#470,.T.); +#986=EDGE_CURVE('',#817,#822,#471,.F.); +#987=EDGE_CURVE('',#823,#819,#472,.T.); +#988=EDGE_CURVE('',#824,#823,#679,.T.); +#989=EDGE_CURVE('',#825,#824,#473,.F.); +#990=EDGE_CURVE('',#826,#825,#680,.T.); +#991=EDGE_CURVE('',#827,#826,#474,.T.); +#992=EDGE_CURVE('',#821,#827,#681,.T.); +#993=EDGE_CURVE('',#828,#828,#682,.T.); +#994=EDGE_CURVE('',#829,#829,#683,.T.); +#995=EDGE_CURVE('',#830,#830,#684,.T.); +#996=EDGE_CURVE('',#831,#831,#685,.T.); +#997=EDGE_CURVE('',#832,#832,#686,.T.); +#998=EDGE_CURVE('',#833,#833,#687,.T.); +#999=EDGE_CURVE('',#834,#834,#688,.T.); +#1000=EDGE_CURVE('',#835,#835,#689,.T.); +#1001=EDGE_CURVE('',#836,#836,#690,.T.); +#1002=EDGE_CURVE('',#837,#837,#691,.T.); +#1003=EDGE_CURVE('',#838,#838,#692,.T.); +#1004=EDGE_CURVE('',#839,#839,#693,.T.); +#1005=EDGE_CURVE('',#840,#840,#694,.T.); +#1006=EDGE_CURVE('',#841,#841,#695,.T.); +#1007=EDGE_CURVE('',#842,#842,#696,.T.); +#1008=EDGE_CURVE('',#843,#843,#697,.T.); +#1009=EDGE_CURVE('',#844,#844,#698,.T.); +#1010=EDGE_CURVE('',#845,#845,#699,.T.); +#1011=EDGE_CURVE('',#846,#846,#700,.T.); +#1012=EDGE_CURVE('',#847,#847,#701,.T.); +#1013=EDGE_CURVE('',#848,#848,#702,.T.); +#1014=EDGE_CURVE('',#849,#849,#703,.T.); +#1015=EDGE_CURVE('',#850,#850,#704,.T.); +#1016=EDGE_CURVE('',#851,#851,#705,.T.); +#1017=EDGE_CURVE('',#852,#852,#706,.T.); +#1018=EDGE_CURVE('',#853,#853,#707,.T.); +#1019=EDGE_CURVE('',#854,#854,#708,.T.); +#1020=EDGE_CURVE('',#855,#855,#709,.T.); +#1021=EDGE_CURVE('',#856,#856,#710,.T.); +#1022=EDGE_CURVE('',#857,#857,#711,.T.); +#1023=EDGE_CURVE('',#858,#858,#712,.T.); +#1024=EDGE_CURVE('',#859,#859,#713,.T.); +#1025=EDGE_CURVE('',#860,#860,#714,.T.); +#1026=EDGE_CURVE('',#861,#861,#715,.T.); +#1027=EDGE_CURVE('',#862,#862,#716,.T.); +#1028=EDGE_CURVE('',#863,#863,#717,.T.); +#1029=EDGE_CURVE('',#864,#864,#718,.T.); +#1030=EDGE_CURVE('',#865,#865,#719,.T.); +#1031=EDGE_CURVE('',#866,#866,#720,.T.); +#1032=EDGE_CURVE('',#867,#868,#721,.T.); +#1033=EDGE_CURVE('',#868,#824,#475,.T.); +#1034=EDGE_CURVE('',#823,#867,#476,.T.); +#1035=EDGE_CURVE('',#869,#868,#477,.F.); +#1036=EDGE_CURVE('',#825,#869,#478,.T.); +#1037=EDGE_CURVE('',#869,#870,#722,.T.); +#1038=EDGE_CURVE('',#870,#826,#479,.T.); +#1039=EDGE_CURVE('',#871,#822,#723,.T.); +#1040=EDGE_CURVE('',#827,#871,#480,.T.); +#1041=EDGE_CURVE('',#872,#872,#724,.T.); +#1042=EDGE_CURVE('',#872,#828,#481,.T.); +#1043=EDGE_CURVE('',#873,#873,#725,.T.); +#1044=EDGE_CURVE('',#873,#829,#482,.T.); +#1045=EDGE_CURVE('',#874,#874,#726,.T.); +#1046=EDGE_CURVE('',#874,#830,#483,.T.); +#1047=EDGE_CURVE('',#875,#875,#727,.T.); +#1048=EDGE_CURVE('',#875,#831,#484,.T.); +#1049=EDGE_CURVE('',#876,#876,#728,.T.); +#1050=EDGE_CURVE('',#876,#832,#485,.T.); +#1051=EDGE_CURVE('',#877,#877,#729,.T.); +#1052=EDGE_CURVE('',#877,#833,#486,.T.); +#1053=EDGE_CURVE('',#878,#878,#730,.T.); +#1054=EDGE_CURVE('',#878,#834,#487,.T.); +#1055=EDGE_CURVE('',#879,#879,#731,.T.); +#1056=EDGE_CURVE('',#879,#835,#488,.T.); +#1057=EDGE_CURVE('',#880,#880,#732,.T.); +#1058=EDGE_CURVE('',#880,#836,#489,.T.); +#1059=EDGE_CURVE('',#881,#881,#733,.T.); +#1060=EDGE_CURVE('',#881,#837,#490,.T.); +#1061=EDGE_CURVE('',#882,#882,#734,.T.); +#1062=EDGE_CURVE('',#882,#838,#491,.T.); +#1063=EDGE_CURVE('',#883,#883,#735,.T.); +#1064=EDGE_CURVE('',#883,#839,#492,.T.); +#1065=EDGE_CURVE('',#884,#884,#736,.T.); +#1066=EDGE_CURVE('',#884,#840,#493,.T.); +#1067=EDGE_CURVE('',#885,#885,#737,.T.); +#1068=EDGE_CURVE('',#885,#841,#494,.T.); +#1069=EDGE_CURVE('',#886,#886,#738,.T.); +#1070=EDGE_CURVE('',#886,#842,#495,.T.); +#1071=EDGE_CURVE('',#887,#887,#739,.T.); +#1072=EDGE_CURVE('',#887,#843,#496,.T.); +#1073=EDGE_CURVE('',#888,#888,#740,.T.); +#1074=EDGE_CURVE('',#888,#844,#497,.T.); +#1075=EDGE_CURVE('',#889,#889,#741,.T.); +#1076=EDGE_CURVE('',#889,#845,#498,.T.); +#1077=EDGE_CURVE('',#890,#890,#742,.T.); +#1078=EDGE_CURVE('',#890,#846,#499,.T.); +#1079=EDGE_CURVE('',#891,#891,#743,.T.); +#1080=EDGE_CURVE('',#891,#847,#500,.T.); +#1081=EDGE_CURVE('',#892,#892,#744,.T.); +#1082=EDGE_CURVE('',#892,#848,#501,.T.); +#1083=EDGE_CURVE('',#893,#893,#745,.T.); +#1084=EDGE_CURVE('',#893,#849,#502,.T.); +#1085=EDGE_CURVE('',#894,#894,#746,.T.); +#1086=EDGE_CURVE('',#894,#850,#503,.T.); +#1087=EDGE_CURVE('',#895,#895,#747,.T.); +#1088=EDGE_CURVE('',#895,#851,#504,.T.); +#1089=EDGE_CURVE('',#896,#896,#748,.T.); +#1090=EDGE_CURVE('',#896,#852,#505,.T.); +#1091=EDGE_CURVE('',#897,#897,#749,.T.); +#1092=EDGE_CURVE('',#897,#853,#506,.T.); +#1093=EDGE_CURVE('',#898,#898,#750,.T.); +#1094=EDGE_CURVE('',#898,#854,#507,.T.); +#1095=EDGE_CURVE('',#899,#899,#751,.T.); +#1096=EDGE_CURVE('',#899,#855,#508,.T.); +#1097=EDGE_CURVE('',#900,#900,#752,.T.); +#1098=EDGE_CURVE('',#900,#856,#509,.T.); +#1099=EDGE_CURVE('',#901,#901,#753,.T.); +#1100=EDGE_CURVE('',#901,#857,#510,.T.); +#1101=EDGE_CURVE('',#902,#902,#754,.T.); +#1102=EDGE_CURVE('',#902,#858,#511,.T.); +#1103=EDGE_CURVE('',#903,#903,#755,.T.); +#1104=EDGE_CURVE('',#903,#859,#512,.T.); +#1105=EDGE_CURVE('',#904,#904,#756,.T.); +#1106=EDGE_CURVE('',#904,#860,#513,.T.); +#1107=EDGE_CURVE('',#905,#905,#757,.T.); +#1108=EDGE_CURVE('',#905,#861,#514,.T.); +#1109=EDGE_CURVE('',#906,#906,#758,.T.); +#1110=EDGE_CURVE('',#906,#862,#515,.T.); +#1111=EDGE_CURVE('',#907,#907,#759,.T.); +#1112=EDGE_CURVE('',#907,#863,#516,.T.); +#1113=EDGE_CURVE('',#908,#908,#760,.T.); +#1114=EDGE_CURVE('',#908,#864,#517,.T.); +#1115=EDGE_CURVE('',#909,#909,#761,.T.); +#1116=EDGE_CURVE('',#909,#865,#518,.T.); +#1117=EDGE_CURVE('',#910,#910,#762,.T.); +#1118=EDGE_CURVE('',#910,#866,#519,.T.); +#1119=EDGE_CURVE('',#871,#870,#520,.T.); +#1120=EDGE_CURVE('',#867,#818,#521,.T.); +#1121=EDGE_CURVE('',#911,#912,#763,.T.); +#1122=EDGE_CURVE('',#912,#913,#522,.T.); +#1123=EDGE_CURVE('',#913,#914,#764,.T.); +#1124=EDGE_CURVE('',#914,#911,#523,.T.); +#1125=EDGE_CURVE('',#914,#915,#524,.T.); +#1126=EDGE_CURVE('',#916,#915,#525,.T.); +#1127=EDGE_CURVE('',#911,#916,#526,.T.); +#1128=EDGE_CURVE('',#917,#913,#527,.T.); +#1129=EDGE_CURVE('',#918,#917,#765,.T.); +#1130=EDGE_CURVE('',#919,#918,#528,.T.); +#1131=EDGE_CURVE('',#920,#919,#766,.T.); +#1132=EDGE_CURVE('',#921,#920,#529,.T.); +#1133=EDGE_CURVE('',#915,#921,#767,.T.); +#1134=EDGE_CURVE('',#922,#922,#768,.T.); +#1135=EDGE_CURVE('',#923,#923,#769,.T.); +#1136=EDGE_CURVE('',#924,#924,#770,.T.); +#1137=EDGE_CURVE('',#925,#925,#771,.T.); +#1138=EDGE_CURVE('',#926,#926,#772,.T.); +#1139=EDGE_CURVE('',#927,#927,#773,.T.); +#1140=EDGE_CURVE('',#928,#928,#774,.T.); +#1141=EDGE_CURVE('',#929,#929,#775,.T.); +#1142=EDGE_CURVE('',#930,#930,#776,.T.); +#1143=EDGE_CURVE('',#931,#931,#777,.T.); +#1144=EDGE_CURVE('',#932,#932,#778,.T.); +#1145=EDGE_CURVE('',#933,#933,#779,.T.); +#1146=EDGE_CURVE('',#934,#934,#780,.T.); +#1147=EDGE_CURVE('',#935,#935,#781,.T.); +#1148=EDGE_CURVE('',#936,#936,#782,.T.); +#1149=EDGE_CURVE('',#937,#937,#783,.T.); +#1150=EDGE_CURVE('',#938,#939,#784,.T.); +#1151=EDGE_CURVE('',#940,#938,#530,.T.); +#1152=EDGE_CURVE('',#941,#940,#785,.T.); +#1153=EDGE_CURVE('',#942,#941,#531,.T.); +#1154=EDGE_CURVE('',#943,#942,#786,.T.); +#1155=EDGE_CURVE('',#944,#943,#532,.T.); +#1156=EDGE_CURVE('',#945,#944,#787,.T.); +#1157=EDGE_CURVE('',#939,#945,#533,.T.); +#1158=EDGE_CURVE('',#946,#947,#788,.T.); +#1159=EDGE_CURVE('',#947,#918,#534,.T.); +#1160=EDGE_CURVE('',#917,#946,#535,.T.); +#1161=EDGE_CURVE('',#948,#947,#536,.T.); +#1162=EDGE_CURVE('',#919,#948,#537,.T.); +#1163=EDGE_CURVE('',#948,#949,#789,.T.); +#1164=EDGE_CURVE('',#949,#920,#538,.T.); +#1165=EDGE_CURVE('',#950,#916,#790,.T.); +#1166=EDGE_CURVE('',#921,#950,#539,.T.); +#1167=EDGE_CURVE('',#942,#951,#540,.T.); +#1168=EDGE_CURVE('',#951,#952,#791,.T.); +#1169=EDGE_CURVE('',#952,#943,#541,.T.); +#1170=EDGE_CURVE('',#953,#941,#542,.T.); +#1171=EDGE_CURVE('',#951,#953,#543,.T.); +#1172=EDGE_CURVE('',#940,#954,#544,.T.); +#1173=EDGE_CURVE('',#954,#953,#792,.T.); +#1174=EDGE_CURVE('',#955,#938,#545,.T.); +#1175=EDGE_CURVE('',#954,#955,#546,.T.); +#1176=EDGE_CURVE('',#939,#956,#547,.T.); +#1177=EDGE_CURVE('',#956,#955,#793,.T.); +#1178=EDGE_CURVE('',#957,#945,#548,.T.); +#1179=EDGE_CURVE('',#956,#957,#549,.T.); +#1180=EDGE_CURVE('',#944,#958,#550,.T.); +#1181=EDGE_CURVE('',#958,#957,#794,.T.); +#1182=EDGE_CURVE('',#958,#952,#551,.T.); +#1183=EDGE_CURVE('',#959,#959,#795,.T.); +#1184=EDGE_CURVE('',#959,#922,#552,.T.); +#1185=EDGE_CURVE('',#960,#960,#796,.T.); +#1186=EDGE_CURVE('',#960,#923,#553,.T.); +#1187=EDGE_CURVE('',#961,#961,#797,.T.); +#1188=EDGE_CURVE('',#961,#924,#554,.T.); +#1189=EDGE_CURVE('',#962,#962,#798,.T.); +#1190=EDGE_CURVE('',#962,#925,#555,.T.); +#1191=EDGE_CURVE('',#963,#963,#799,.T.); +#1192=EDGE_CURVE('',#963,#926,#556,.T.); +#1193=EDGE_CURVE('',#964,#964,#800,.T.); +#1194=EDGE_CURVE('',#964,#927,#557,.T.); +#1195=EDGE_CURVE('',#965,#965,#801,.T.); +#1196=EDGE_CURVE('',#965,#928,#558,.T.); +#1197=EDGE_CURVE('',#966,#966,#802,.T.); +#1198=EDGE_CURVE('',#966,#929,#559,.T.); +#1199=EDGE_CURVE('',#967,#967,#803,.T.); +#1200=EDGE_CURVE('',#967,#930,#560,.T.); +#1201=EDGE_CURVE('',#968,#968,#804,.T.); +#1202=EDGE_CURVE('',#968,#931,#561,.T.); +#1203=EDGE_CURVE('',#969,#969,#805,.T.); +#1204=EDGE_CURVE('',#969,#932,#562,.T.); +#1205=EDGE_CURVE('',#970,#970,#806,.T.); +#1206=EDGE_CURVE('',#970,#933,#563,.T.); +#1207=EDGE_CURVE('',#971,#971,#807,.T.); +#1208=EDGE_CURVE('',#971,#934,#564,.T.); +#1209=EDGE_CURVE('',#972,#972,#808,.T.); +#1210=EDGE_CURVE('',#972,#935,#565,.T.); +#1211=EDGE_CURVE('',#973,#973,#809,.T.); +#1212=EDGE_CURVE('',#973,#936,#566,.T.); +#1213=EDGE_CURVE('',#974,#974,#810,.T.); +#1214=EDGE_CURVE('',#974,#937,#567,.T.); +#1215=EDGE_CURVE('',#950,#949,#568,.T.); +#1216=EDGE_CURVE('',#946,#912,#569,.T.); +#1217=EDGE_CURVE('',#975,#975,#811,.T.); +#1218=EDGE_CURVE('',#975,#976,#570,.T.); +#1219=EDGE_CURVE('',#976,#976,#812,.T.); +#1220=EDGE_CURVE('',#976,#977,#571,.T.); +#1221=EDGE_CURVE('',#978,#977,#813,.T.); +#1222=EDGE_CURVE('',#977,#978,#814,.T.); +#1223=EDGE_CURVE('',#979,#979,#815,.T.); +#1224=EDGE_CURVE('',#979,#978,#816,.T.); +#1225=ORIENTED_EDGE('',*,*,#980,.T.); +#1226=ORIENTED_EDGE('',*,*,#981,.T.); +#1227=ORIENTED_EDGE('',*,*,#982,.T.); +#1228=ORIENTED_EDGE('',*,*,#983,.T.); +#1229=ORIENTED_EDGE('',*,*,#983,.F.); +#1230=ORIENTED_EDGE('',*,*,#984,.T.); +#1231=ORIENTED_EDGE('',*,*,#985,.F.); +#1232=ORIENTED_EDGE('',*,*,#986,.F.); +#1233=ORIENTED_EDGE('',*,*,#982,.F.); +#1234=ORIENTED_EDGE('',*,*,#987,.F.); +#1235=ORIENTED_EDGE('',*,*,#988,.F.); +#1236=ORIENTED_EDGE('',*,*,#989,.F.); +#1237=ORIENTED_EDGE('',*,*,#990,.F.); +#1238=ORIENTED_EDGE('',*,*,#991,.F.); +#1239=ORIENTED_EDGE('',*,*,#992,.F.); +#1240=ORIENTED_EDGE('',*,*,#984,.F.); +#1241=ORIENTED_EDGE('',*,*,#993,.T.); +#1242=ORIENTED_EDGE('',*,*,#994,.T.); +#1243=ORIENTED_EDGE('',*,*,#995,.T.); +#1244=ORIENTED_EDGE('',*,*,#996,.T.); +#1245=ORIENTED_EDGE('',*,*,#997,.T.); +#1246=ORIENTED_EDGE('',*,*,#998,.T.); +#1247=ORIENTED_EDGE('',*,*,#999,.T.); +#1248=ORIENTED_EDGE('',*,*,#1000,.T.); +#1249=ORIENTED_EDGE('',*,*,#1001,.T.); +#1250=ORIENTED_EDGE('',*,*,#1002,.T.); +#1251=ORIENTED_EDGE('',*,*,#1003,.T.); +#1252=ORIENTED_EDGE('',*,*,#1004,.T.); +#1253=ORIENTED_EDGE('',*,*,#1005,.T.); +#1254=ORIENTED_EDGE('',*,*,#1006,.T.); +#1255=ORIENTED_EDGE('',*,*,#1007,.T.); +#1256=ORIENTED_EDGE('',*,*,#1008,.T.); +#1257=ORIENTED_EDGE('',*,*,#1009,.T.); +#1258=ORIENTED_EDGE('',*,*,#1010,.T.); +#1259=ORIENTED_EDGE('',*,*,#1011,.T.); +#1260=ORIENTED_EDGE('',*,*,#1012,.T.); +#1261=ORIENTED_EDGE('',*,*,#1013,.T.); +#1262=ORIENTED_EDGE('',*,*,#1014,.T.); +#1263=ORIENTED_EDGE('',*,*,#1015,.T.); +#1264=ORIENTED_EDGE('',*,*,#1016,.T.); +#1265=ORIENTED_EDGE('',*,*,#1017,.T.); +#1266=ORIENTED_EDGE('',*,*,#1018,.T.); +#1267=ORIENTED_EDGE('',*,*,#1019,.T.); +#1268=ORIENTED_EDGE('',*,*,#1020,.T.); +#1269=ORIENTED_EDGE('',*,*,#1021,.T.); +#1270=ORIENTED_EDGE('',*,*,#1022,.T.); +#1271=ORIENTED_EDGE('',*,*,#1023,.T.); +#1272=ORIENTED_EDGE('',*,*,#1024,.T.); +#1273=ORIENTED_EDGE('',*,*,#1025,.T.); +#1274=ORIENTED_EDGE('',*,*,#1026,.T.); +#1275=ORIENTED_EDGE('',*,*,#1027,.T.); +#1276=ORIENTED_EDGE('',*,*,#1028,.T.); +#1277=ORIENTED_EDGE('',*,*,#1029,.T.); +#1278=ORIENTED_EDGE('',*,*,#1030,.T.); +#1279=ORIENTED_EDGE('',*,*,#1031,.T.); +#1280=ORIENTED_EDGE('',*,*,#1032,.T.); +#1281=ORIENTED_EDGE('',*,*,#1033,.T.); +#1282=ORIENTED_EDGE('',*,*,#988,.T.); +#1283=ORIENTED_EDGE('',*,*,#1034,.T.); +#1284=ORIENTED_EDGE('',*,*,#1033,.F.); +#1285=ORIENTED_EDGE('',*,*,#1035,.F.); +#1286=ORIENTED_EDGE('',*,*,#1036,.F.); +#1287=ORIENTED_EDGE('',*,*,#989,.T.); +#1288=ORIENTED_EDGE('',*,*,#1037,.T.); +#1289=ORIENTED_EDGE('',*,*,#1038,.T.); +#1290=ORIENTED_EDGE('',*,*,#990,.T.); +#1291=ORIENTED_EDGE('',*,*,#1036,.T.); +#1292=ORIENTED_EDGE('',*,*,#1039,.T.); +#1293=ORIENTED_EDGE('',*,*,#985,.T.); +#1294=ORIENTED_EDGE('',*,*,#992,.T.); +#1295=ORIENTED_EDGE('',*,*,#1040,.T.); +#1296=ORIENTED_EDGE('',*,*,#1041,.F.); +#1297=ORIENTED_EDGE('',*,*,#1042,.T.); +#1298=ORIENTED_EDGE('',*,*,#993,.F.); +#1299=ORIENTED_EDGE('',*,*,#1042,.F.); +#1300=ORIENTED_EDGE('',*,*,#1043,.F.); +#1301=ORIENTED_EDGE('',*,*,#1044,.T.); +#1302=ORIENTED_EDGE('',*,*,#994,.F.); +#1303=ORIENTED_EDGE('',*,*,#1044,.F.); +#1304=ORIENTED_EDGE('',*,*,#1045,.F.); +#1305=ORIENTED_EDGE('',*,*,#1046,.T.); +#1306=ORIENTED_EDGE('',*,*,#995,.F.); +#1307=ORIENTED_EDGE('',*,*,#1046,.F.); +#1308=ORIENTED_EDGE('',*,*,#1047,.F.); +#1309=ORIENTED_EDGE('',*,*,#1048,.T.); +#1310=ORIENTED_EDGE('',*,*,#996,.F.); +#1311=ORIENTED_EDGE('',*,*,#1048,.F.); +#1312=ORIENTED_EDGE('',*,*,#1049,.F.); +#1313=ORIENTED_EDGE('',*,*,#1050,.T.); +#1314=ORIENTED_EDGE('',*,*,#997,.F.); +#1315=ORIENTED_EDGE('',*,*,#1050,.F.); +#1316=ORIENTED_EDGE('',*,*,#1051,.F.); +#1317=ORIENTED_EDGE('',*,*,#1052,.T.); +#1318=ORIENTED_EDGE('',*,*,#998,.F.); +#1319=ORIENTED_EDGE('',*,*,#1052,.F.); +#1320=ORIENTED_EDGE('',*,*,#1053,.F.); +#1321=ORIENTED_EDGE('',*,*,#1054,.T.); +#1322=ORIENTED_EDGE('',*,*,#999,.F.); +#1323=ORIENTED_EDGE('',*,*,#1054,.F.); +#1324=ORIENTED_EDGE('',*,*,#1055,.F.); +#1325=ORIENTED_EDGE('',*,*,#1056,.T.); +#1326=ORIENTED_EDGE('',*,*,#1000,.F.); +#1327=ORIENTED_EDGE('',*,*,#1056,.F.); +#1328=ORIENTED_EDGE('',*,*,#1057,.F.); +#1329=ORIENTED_EDGE('',*,*,#1058,.T.); +#1330=ORIENTED_EDGE('',*,*,#1001,.F.); +#1331=ORIENTED_EDGE('',*,*,#1058,.F.); +#1332=ORIENTED_EDGE('',*,*,#1059,.F.); +#1333=ORIENTED_EDGE('',*,*,#1060,.T.); +#1334=ORIENTED_EDGE('',*,*,#1002,.F.); +#1335=ORIENTED_EDGE('',*,*,#1060,.F.); +#1336=ORIENTED_EDGE('',*,*,#1061,.F.); +#1337=ORIENTED_EDGE('',*,*,#1062,.T.); +#1338=ORIENTED_EDGE('',*,*,#1003,.F.); +#1339=ORIENTED_EDGE('',*,*,#1062,.F.); +#1340=ORIENTED_EDGE('',*,*,#1063,.F.); +#1341=ORIENTED_EDGE('',*,*,#1064,.T.); +#1342=ORIENTED_EDGE('',*,*,#1004,.F.); +#1343=ORIENTED_EDGE('',*,*,#1064,.F.); +#1344=ORIENTED_EDGE('',*,*,#1065,.F.); +#1345=ORIENTED_EDGE('',*,*,#1066,.T.); +#1346=ORIENTED_EDGE('',*,*,#1005,.F.); +#1347=ORIENTED_EDGE('',*,*,#1066,.F.); +#1348=ORIENTED_EDGE('',*,*,#1067,.F.); +#1349=ORIENTED_EDGE('',*,*,#1068,.T.); +#1350=ORIENTED_EDGE('',*,*,#1006,.F.); +#1351=ORIENTED_EDGE('',*,*,#1068,.F.); +#1352=ORIENTED_EDGE('',*,*,#1069,.F.); +#1353=ORIENTED_EDGE('',*,*,#1070,.T.); +#1354=ORIENTED_EDGE('',*,*,#1007,.F.); +#1355=ORIENTED_EDGE('',*,*,#1070,.F.); +#1356=ORIENTED_EDGE('',*,*,#1071,.F.); +#1357=ORIENTED_EDGE('',*,*,#1072,.T.); +#1358=ORIENTED_EDGE('',*,*,#1008,.F.); +#1359=ORIENTED_EDGE('',*,*,#1072,.F.); +#1360=ORIENTED_EDGE('',*,*,#1073,.F.); +#1361=ORIENTED_EDGE('',*,*,#1074,.T.); +#1362=ORIENTED_EDGE('',*,*,#1009,.F.); +#1363=ORIENTED_EDGE('',*,*,#1074,.F.); +#1364=ORIENTED_EDGE('',*,*,#1075,.F.); +#1365=ORIENTED_EDGE('',*,*,#1076,.T.); +#1366=ORIENTED_EDGE('',*,*,#1010,.F.); +#1367=ORIENTED_EDGE('',*,*,#1076,.F.); +#1368=ORIENTED_EDGE('',*,*,#1077,.F.); +#1369=ORIENTED_EDGE('',*,*,#1078,.T.); +#1370=ORIENTED_EDGE('',*,*,#1011,.F.); +#1371=ORIENTED_EDGE('',*,*,#1078,.F.); +#1372=ORIENTED_EDGE('',*,*,#1079,.F.); +#1373=ORIENTED_EDGE('',*,*,#1080,.T.); +#1374=ORIENTED_EDGE('',*,*,#1012,.F.); +#1375=ORIENTED_EDGE('',*,*,#1080,.F.); +#1376=ORIENTED_EDGE('',*,*,#1081,.F.); +#1377=ORIENTED_EDGE('',*,*,#1082,.T.); +#1378=ORIENTED_EDGE('',*,*,#1013,.F.); +#1379=ORIENTED_EDGE('',*,*,#1082,.F.); +#1380=ORIENTED_EDGE('',*,*,#1083,.F.); +#1381=ORIENTED_EDGE('',*,*,#1084,.T.); +#1382=ORIENTED_EDGE('',*,*,#1014,.F.); +#1383=ORIENTED_EDGE('',*,*,#1084,.F.); +#1384=ORIENTED_EDGE('',*,*,#1085,.F.); +#1385=ORIENTED_EDGE('',*,*,#1086,.T.); +#1386=ORIENTED_EDGE('',*,*,#1015,.F.); +#1387=ORIENTED_EDGE('',*,*,#1086,.F.); +#1388=ORIENTED_EDGE('',*,*,#1087,.F.); +#1389=ORIENTED_EDGE('',*,*,#1088,.T.); +#1390=ORIENTED_EDGE('',*,*,#1016,.F.); +#1391=ORIENTED_EDGE('',*,*,#1088,.F.); +#1392=ORIENTED_EDGE('',*,*,#1089,.F.); +#1393=ORIENTED_EDGE('',*,*,#1090,.T.); +#1394=ORIENTED_EDGE('',*,*,#1017,.F.); +#1395=ORIENTED_EDGE('',*,*,#1090,.F.); +#1396=ORIENTED_EDGE('',*,*,#1091,.F.); +#1397=ORIENTED_EDGE('',*,*,#1092,.T.); +#1398=ORIENTED_EDGE('',*,*,#1018,.F.); +#1399=ORIENTED_EDGE('',*,*,#1092,.F.); +#1400=ORIENTED_EDGE('',*,*,#1093,.F.); +#1401=ORIENTED_EDGE('',*,*,#1094,.T.); +#1402=ORIENTED_EDGE('',*,*,#1019,.F.); +#1403=ORIENTED_EDGE('',*,*,#1094,.F.); +#1404=ORIENTED_EDGE('',*,*,#1095,.F.); +#1405=ORIENTED_EDGE('',*,*,#1096,.T.); +#1406=ORIENTED_EDGE('',*,*,#1020,.F.); +#1407=ORIENTED_EDGE('',*,*,#1096,.F.); +#1408=ORIENTED_EDGE('',*,*,#1097,.F.); +#1409=ORIENTED_EDGE('',*,*,#1098,.T.); +#1410=ORIENTED_EDGE('',*,*,#1021,.F.); +#1411=ORIENTED_EDGE('',*,*,#1098,.F.); +#1412=ORIENTED_EDGE('',*,*,#1099,.F.); +#1413=ORIENTED_EDGE('',*,*,#1100,.T.); +#1414=ORIENTED_EDGE('',*,*,#1022,.F.); +#1415=ORIENTED_EDGE('',*,*,#1100,.F.); +#1416=ORIENTED_EDGE('',*,*,#1101,.F.); +#1417=ORIENTED_EDGE('',*,*,#1102,.T.); +#1418=ORIENTED_EDGE('',*,*,#1023,.F.); +#1419=ORIENTED_EDGE('',*,*,#1102,.F.); +#1420=ORIENTED_EDGE('',*,*,#1103,.F.); +#1421=ORIENTED_EDGE('',*,*,#1104,.T.); +#1422=ORIENTED_EDGE('',*,*,#1024,.F.); +#1423=ORIENTED_EDGE('',*,*,#1104,.F.); +#1424=ORIENTED_EDGE('',*,*,#1105,.F.); +#1425=ORIENTED_EDGE('',*,*,#1106,.T.); +#1426=ORIENTED_EDGE('',*,*,#1025,.F.); +#1427=ORIENTED_EDGE('',*,*,#1106,.F.); +#1428=ORIENTED_EDGE('',*,*,#1107,.F.); +#1429=ORIENTED_EDGE('',*,*,#1108,.T.); +#1430=ORIENTED_EDGE('',*,*,#1026,.F.); +#1431=ORIENTED_EDGE('',*,*,#1108,.F.); +#1432=ORIENTED_EDGE('',*,*,#1109,.F.); +#1433=ORIENTED_EDGE('',*,*,#1110,.T.); +#1434=ORIENTED_EDGE('',*,*,#1027,.F.); +#1435=ORIENTED_EDGE('',*,*,#1110,.F.); +#1436=ORIENTED_EDGE('',*,*,#1111,.F.); +#1437=ORIENTED_EDGE('',*,*,#1112,.T.); +#1438=ORIENTED_EDGE('',*,*,#1028,.F.); +#1439=ORIENTED_EDGE('',*,*,#1112,.F.); +#1440=ORIENTED_EDGE('',*,*,#1113,.F.); +#1441=ORIENTED_EDGE('',*,*,#1114,.T.); +#1442=ORIENTED_EDGE('',*,*,#1029,.F.); +#1443=ORIENTED_EDGE('',*,*,#1114,.F.); +#1444=ORIENTED_EDGE('',*,*,#1115,.F.); +#1445=ORIENTED_EDGE('',*,*,#1116,.T.); +#1446=ORIENTED_EDGE('',*,*,#1030,.F.); +#1447=ORIENTED_EDGE('',*,*,#1116,.F.); +#1448=ORIENTED_EDGE('',*,*,#1117,.F.); +#1449=ORIENTED_EDGE('',*,*,#1118,.T.); +#1450=ORIENTED_EDGE('',*,*,#1031,.F.); +#1451=ORIENTED_EDGE('',*,*,#1118,.F.); +#1452=ORIENTED_EDGE('',*,*,#1038,.F.); +#1453=ORIENTED_EDGE('',*,*,#1119,.F.); +#1454=ORIENTED_EDGE('',*,*,#1040,.F.); +#1455=ORIENTED_EDGE('',*,*,#991,.T.); +#1456=ORIENTED_EDGE('',*,*,#981,.F.); +#1457=ORIENTED_EDGE('',*,*,#1120,.F.); +#1458=ORIENTED_EDGE('',*,*,#1034,.F.); +#1459=ORIENTED_EDGE('',*,*,#987,.T.); +#1460=ORIENTED_EDGE('',*,*,#980,.F.); +#1461=ORIENTED_EDGE('',*,*,#986,.T.); +#1462=ORIENTED_EDGE('',*,*,#1039,.F.); +#1463=ORIENTED_EDGE('',*,*,#1119,.T.); +#1464=ORIENTED_EDGE('',*,*,#1037,.F.); +#1465=ORIENTED_EDGE('',*,*,#1035,.T.); +#1466=ORIENTED_EDGE('',*,*,#1032,.F.); +#1467=ORIENTED_EDGE('',*,*,#1120,.T.); +#1468=ORIENTED_EDGE('',*,*,#1041,.T.); +#1469=ORIENTED_EDGE('',*,*,#1043,.T.); +#1470=ORIENTED_EDGE('',*,*,#1045,.T.); +#1471=ORIENTED_EDGE('',*,*,#1047,.T.); +#1472=ORIENTED_EDGE('',*,*,#1049,.T.); +#1473=ORIENTED_EDGE('',*,*,#1051,.T.); +#1474=ORIENTED_EDGE('',*,*,#1053,.T.); +#1475=ORIENTED_EDGE('',*,*,#1055,.T.); +#1476=ORIENTED_EDGE('',*,*,#1057,.T.); +#1477=ORIENTED_EDGE('',*,*,#1059,.T.); +#1478=ORIENTED_EDGE('',*,*,#1061,.T.); +#1479=ORIENTED_EDGE('',*,*,#1063,.T.); +#1480=ORIENTED_EDGE('',*,*,#1065,.T.); +#1481=ORIENTED_EDGE('',*,*,#1067,.T.); +#1482=ORIENTED_EDGE('',*,*,#1069,.T.); +#1483=ORIENTED_EDGE('',*,*,#1071,.T.); +#1484=ORIENTED_EDGE('',*,*,#1073,.T.); +#1485=ORIENTED_EDGE('',*,*,#1075,.T.); +#1486=ORIENTED_EDGE('',*,*,#1077,.T.); +#1487=ORIENTED_EDGE('',*,*,#1079,.T.); +#1488=ORIENTED_EDGE('',*,*,#1081,.T.); +#1489=ORIENTED_EDGE('',*,*,#1083,.T.); +#1490=ORIENTED_EDGE('',*,*,#1085,.T.); +#1491=ORIENTED_EDGE('',*,*,#1087,.T.); +#1492=ORIENTED_EDGE('',*,*,#1089,.T.); +#1493=ORIENTED_EDGE('',*,*,#1091,.T.); +#1494=ORIENTED_EDGE('',*,*,#1093,.T.); +#1495=ORIENTED_EDGE('',*,*,#1095,.T.); +#1496=ORIENTED_EDGE('',*,*,#1097,.T.); +#1497=ORIENTED_EDGE('',*,*,#1099,.T.); +#1498=ORIENTED_EDGE('',*,*,#1101,.T.); +#1499=ORIENTED_EDGE('',*,*,#1103,.T.); +#1500=ORIENTED_EDGE('',*,*,#1105,.T.); +#1501=ORIENTED_EDGE('',*,*,#1107,.T.); +#1502=ORIENTED_EDGE('',*,*,#1109,.T.); +#1503=ORIENTED_EDGE('',*,*,#1111,.T.); +#1504=ORIENTED_EDGE('',*,*,#1113,.T.); +#1505=ORIENTED_EDGE('',*,*,#1115,.T.); +#1506=ORIENTED_EDGE('',*,*,#1117,.T.); +#1507=ORIENTED_EDGE('',*,*,#1121,.T.); +#1508=ORIENTED_EDGE('',*,*,#1122,.T.); +#1509=ORIENTED_EDGE('',*,*,#1123,.T.); +#1510=ORIENTED_EDGE('',*,*,#1124,.T.); +#1511=ORIENTED_EDGE('',*,*,#1124,.F.); +#1512=ORIENTED_EDGE('',*,*,#1125,.T.); +#1513=ORIENTED_EDGE('',*,*,#1126,.F.); +#1514=ORIENTED_EDGE('',*,*,#1127,.F.); +#1515=ORIENTED_EDGE('',*,*,#1123,.F.); +#1516=ORIENTED_EDGE('',*,*,#1128,.F.); +#1517=ORIENTED_EDGE('',*,*,#1129,.F.); +#1518=ORIENTED_EDGE('',*,*,#1130,.F.); +#1519=ORIENTED_EDGE('',*,*,#1131,.F.); +#1520=ORIENTED_EDGE('',*,*,#1132,.F.); +#1521=ORIENTED_EDGE('',*,*,#1133,.F.); +#1522=ORIENTED_EDGE('',*,*,#1125,.F.); +#1523=ORIENTED_EDGE('',*,*,#1134,.T.); +#1524=ORIENTED_EDGE('',*,*,#1135,.T.); +#1525=ORIENTED_EDGE('',*,*,#1136,.T.); +#1526=ORIENTED_EDGE('',*,*,#1137,.T.); +#1527=ORIENTED_EDGE('',*,*,#1138,.T.); +#1528=ORIENTED_EDGE('',*,*,#1139,.T.); +#1529=ORIENTED_EDGE('',*,*,#1140,.T.); +#1530=ORIENTED_EDGE('',*,*,#1141,.T.); +#1531=ORIENTED_EDGE('',*,*,#1142,.T.); +#1532=ORIENTED_EDGE('',*,*,#1143,.T.); +#1533=ORIENTED_EDGE('',*,*,#1144,.T.); +#1534=ORIENTED_EDGE('',*,*,#1145,.T.); +#1535=ORIENTED_EDGE('',*,*,#1146,.T.); +#1536=ORIENTED_EDGE('',*,*,#1147,.T.); +#1537=ORIENTED_EDGE('',*,*,#1148,.T.); +#1538=ORIENTED_EDGE('',*,*,#1149,.T.); +#1539=ORIENTED_EDGE('',*,*,#1150,.F.); +#1540=ORIENTED_EDGE('',*,*,#1151,.F.); +#1541=ORIENTED_EDGE('',*,*,#1152,.F.); +#1542=ORIENTED_EDGE('',*,*,#1153,.F.); +#1543=ORIENTED_EDGE('',*,*,#1154,.F.); +#1544=ORIENTED_EDGE('',*,*,#1155,.F.); +#1545=ORIENTED_EDGE('',*,*,#1156,.F.); +#1546=ORIENTED_EDGE('',*,*,#1157,.F.); +#1547=ORIENTED_EDGE('',*,*,#1158,.T.); +#1548=ORIENTED_EDGE('',*,*,#1159,.T.); +#1549=ORIENTED_EDGE('',*,*,#1129,.T.); +#1550=ORIENTED_EDGE('',*,*,#1160,.T.); +#1551=ORIENTED_EDGE('',*,*,#1159,.F.); +#1552=ORIENTED_EDGE('',*,*,#1161,.F.); +#1553=ORIENTED_EDGE('',*,*,#1162,.F.); +#1554=ORIENTED_EDGE('',*,*,#1130,.T.); +#1555=ORIENTED_EDGE('',*,*,#1163,.T.); +#1556=ORIENTED_EDGE('',*,*,#1164,.T.); +#1557=ORIENTED_EDGE('',*,*,#1131,.T.); +#1558=ORIENTED_EDGE('',*,*,#1162,.T.); +#1559=ORIENTED_EDGE('',*,*,#1165,.T.); +#1560=ORIENTED_EDGE('',*,*,#1126,.T.); +#1561=ORIENTED_EDGE('',*,*,#1133,.T.); +#1562=ORIENTED_EDGE('',*,*,#1166,.T.); +#1563=ORIENTED_EDGE('',*,*,#1154,.T.); +#1564=ORIENTED_EDGE('',*,*,#1167,.T.); +#1565=ORIENTED_EDGE('',*,*,#1168,.T.); +#1566=ORIENTED_EDGE('',*,*,#1169,.T.); +#1567=ORIENTED_EDGE('',*,*,#1167,.F.); +#1568=ORIENTED_EDGE('',*,*,#1153,.T.); +#1569=ORIENTED_EDGE('',*,*,#1170,.F.); +#1570=ORIENTED_EDGE('',*,*,#1171,.F.); +#1571=ORIENTED_EDGE('',*,*,#1152,.T.); +#1572=ORIENTED_EDGE('',*,*,#1172,.T.); +#1573=ORIENTED_EDGE('',*,*,#1173,.T.); +#1574=ORIENTED_EDGE('',*,*,#1170,.T.); +#1575=ORIENTED_EDGE('',*,*,#1172,.F.); +#1576=ORIENTED_EDGE('',*,*,#1151,.T.); +#1577=ORIENTED_EDGE('',*,*,#1174,.F.); +#1578=ORIENTED_EDGE('',*,*,#1175,.F.); +#1579=ORIENTED_EDGE('',*,*,#1150,.T.); +#1580=ORIENTED_EDGE('',*,*,#1176,.T.); +#1581=ORIENTED_EDGE('',*,*,#1177,.T.); +#1582=ORIENTED_EDGE('',*,*,#1174,.T.); +#1583=ORIENTED_EDGE('',*,*,#1176,.F.); +#1584=ORIENTED_EDGE('',*,*,#1157,.T.); +#1585=ORIENTED_EDGE('',*,*,#1178,.F.); +#1586=ORIENTED_EDGE('',*,*,#1179,.F.); +#1587=ORIENTED_EDGE('',*,*,#1156,.T.); +#1588=ORIENTED_EDGE('',*,*,#1180,.T.); +#1589=ORIENTED_EDGE('',*,*,#1181,.T.); +#1590=ORIENTED_EDGE('',*,*,#1178,.T.); +#1591=ORIENTED_EDGE('',*,*,#1169,.F.); +#1592=ORIENTED_EDGE('',*,*,#1182,.F.); +#1593=ORIENTED_EDGE('',*,*,#1180,.F.); +#1594=ORIENTED_EDGE('',*,*,#1155,.T.); +#1595=ORIENTED_EDGE('',*,*,#1183,.F.); +#1596=ORIENTED_EDGE('',*,*,#1184,.T.); +#1597=ORIENTED_EDGE('',*,*,#1134,.F.); +#1598=ORIENTED_EDGE('',*,*,#1184,.F.); +#1599=ORIENTED_EDGE('',*,*,#1185,.F.); +#1600=ORIENTED_EDGE('',*,*,#1186,.T.); +#1601=ORIENTED_EDGE('',*,*,#1135,.F.); +#1602=ORIENTED_EDGE('',*,*,#1186,.F.); +#1603=ORIENTED_EDGE('',*,*,#1187,.F.); +#1604=ORIENTED_EDGE('',*,*,#1188,.T.); +#1605=ORIENTED_EDGE('',*,*,#1136,.F.); +#1606=ORIENTED_EDGE('',*,*,#1188,.F.); +#1607=ORIENTED_EDGE('',*,*,#1189,.F.); +#1608=ORIENTED_EDGE('',*,*,#1190,.T.); +#1609=ORIENTED_EDGE('',*,*,#1137,.F.); +#1610=ORIENTED_EDGE('',*,*,#1190,.F.); +#1611=ORIENTED_EDGE('',*,*,#1191,.F.); +#1612=ORIENTED_EDGE('',*,*,#1192,.T.); +#1613=ORIENTED_EDGE('',*,*,#1138,.F.); +#1614=ORIENTED_EDGE('',*,*,#1192,.F.); +#1615=ORIENTED_EDGE('',*,*,#1193,.F.); +#1616=ORIENTED_EDGE('',*,*,#1194,.T.); +#1617=ORIENTED_EDGE('',*,*,#1139,.F.); +#1618=ORIENTED_EDGE('',*,*,#1194,.F.); +#1619=ORIENTED_EDGE('',*,*,#1195,.F.); +#1620=ORIENTED_EDGE('',*,*,#1196,.T.); +#1621=ORIENTED_EDGE('',*,*,#1140,.F.); +#1622=ORIENTED_EDGE('',*,*,#1196,.F.); +#1623=ORIENTED_EDGE('',*,*,#1197,.F.); +#1624=ORIENTED_EDGE('',*,*,#1198,.T.); +#1625=ORIENTED_EDGE('',*,*,#1141,.F.); +#1626=ORIENTED_EDGE('',*,*,#1198,.F.); +#1627=ORIENTED_EDGE('',*,*,#1199,.F.); +#1628=ORIENTED_EDGE('',*,*,#1200,.T.); +#1629=ORIENTED_EDGE('',*,*,#1142,.F.); +#1630=ORIENTED_EDGE('',*,*,#1200,.F.); +#1631=ORIENTED_EDGE('',*,*,#1201,.F.); +#1632=ORIENTED_EDGE('',*,*,#1202,.T.); +#1633=ORIENTED_EDGE('',*,*,#1143,.F.); +#1634=ORIENTED_EDGE('',*,*,#1202,.F.); +#1635=ORIENTED_EDGE('',*,*,#1203,.F.); +#1636=ORIENTED_EDGE('',*,*,#1204,.T.); +#1637=ORIENTED_EDGE('',*,*,#1144,.F.); +#1638=ORIENTED_EDGE('',*,*,#1204,.F.); +#1639=ORIENTED_EDGE('',*,*,#1205,.F.); +#1640=ORIENTED_EDGE('',*,*,#1206,.T.); +#1641=ORIENTED_EDGE('',*,*,#1145,.F.); +#1642=ORIENTED_EDGE('',*,*,#1206,.F.); +#1643=ORIENTED_EDGE('',*,*,#1207,.F.); +#1644=ORIENTED_EDGE('',*,*,#1208,.T.); +#1645=ORIENTED_EDGE('',*,*,#1146,.F.); +#1646=ORIENTED_EDGE('',*,*,#1208,.F.); +#1647=ORIENTED_EDGE('',*,*,#1209,.F.); +#1648=ORIENTED_EDGE('',*,*,#1210,.T.); +#1649=ORIENTED_EDGE('',*,*,#1147,.F.); +#1650=ORIENTED_EDGE('',*,*,#1210,.F.); +#1651=ORIENTED_EDGE('',*,*,#1211,.F.); +#1652=ORIENTED_EDGE('',*,*,#1212,.T.); +#1653=ORIENTED_EDGE('',*,*,#1148,.F.); +#1654=ORIENTED_EDGE('',*,*,#1212,.F.); +#1655=ORIENTED_EDGE('',*,*,#1213,.F.); +#1656=ORIENTED_EDGE('',*,*,#1214,.T.); +#1657=ORIENTED_EDGE('',*,*,#1149,.F.); +#1658=ORIENTED_EDGE('',*,*,#1214,.F.); +#1659=ORIENTED_EDGE('',*,*,#1164,.F.); +#1660=ORIENTED_EDGE('',*,*,#1215,.F.); +#1661=ORIENTED_EDGE('',*,*,#1166,.F.); +#1662=ORIENTED_EDGE('',*,*,#1132,.T.); +#1663=ORIENTED_EDGE('',*,*,#1122,.F.); +#1664=ORIENTED_EDGE('',*,*,#1216,.F.); +#1665=ORIENTED_EDGE('',*,*,#1160,.F.); +#1666=ORIENTED_EDGE('',*,*,#1128,.T.); +#1667=ORIENTED_EDGE('',*,*,#1121,.F.); +#1668=ORIENTED_EDGE('',*,*,#1127,.T.); +#1669=ORIENTED_EDGE('',*,*,#1165,.F.); +#1670=ORIENTED_EDGE('',*,*,#1215,.T.); +#1671=ORIENTED_EDGE('',*,*,#1163,.F.); +#1672=ORIENTED_EDGE('',*,*,#1161,.T.); +#1673=ORIENTED_EDGE('',*,*,#1158,.F.); +#1674=ORIENTED_EDGE('',*,*,#1216,.T.); +#1675=ORIENTED_EDGE('',*,*,#1183,.T.); +#1676=ORIENTED_EDGE('',*,*,#1185,.T.); +#1677=ORIENTED_EDGE('',*,*,#1187,.T.); +#1678=ORIENTED_EDGE('',*,*,#1189,.T.); +#1679=ORIENTED_EDGE('',*,*,#1191,.T.); +#1680=ORIENTED_EDGE('',*,*,#1193,.T.); +#1681=ORIENTED_EDGE('',*,*,#1195,.T.); +#1682=ORIENTED_EDGE('',*,*,#1197,.T.); +#1683=ORIENTED_EDGE('',*,*,#1199,.T.); +#1684=ORIENTED_EDGE('',*,*,#1201,.T.); +#1685=ORIENTED_EDGE('',*,*,#1203,.T.); +#1686=ORIENTED_EDGE('',*,*,#1205,.T.); +#1687=ORIENTED_EDGE('',*,*,#1207,.T.); +#1688=ORIENTED_EDGE('',*,*,#1209,.T.); +#1689=ORIENTED_EDGE('',*,*,#1211,.T.); +#1690=ORIENTED_EDGE('',*,*,#1213,.T.); +#1691=ORIENTED_EDGE('',*,*,#1179,.T.); +#1692=ORIENTED_EDGE('',*,*,#1181,.F.); +#1693=ORIENTED_EDGE('',*,*,#1182,.T.); +#1694=ORIENTED_EDGE('',*,*,#1168,.F.); +#1695=ORIENTED_EDGE('',*,*,#1171,.T.); +#1696=ORIENTED_EDGE('',*,*,#1173,.F.); +#1697=ORIENTED_EDGE('',*,*,#1175,.T.); +#1698=ORIENTED_EDGE('',*,*,#1177,.F.); +#1699=ORIENTED_EDGE('',*,*,#1217,.T.); +#1700=ORIENTED_EDGE('',*,*,#1218,.T.); +#1701=ORIENTED_EDGE('',*,*,#1219,.T.); +#1702=ORIENTED_EDGE('',*,*,#1218,.F.); +#1703=ORIENTED_EDGE('',*,*,#1219,.F.); +#1704=ORIENTED_EDGE('',*,*,#1220,.T.); +#1705=ORIENTED_EDGE('',*,*,#1221,.F.); +#1706=ORIENTED_EDGE('',*,*,#1222,.F.); +#1707=ORIENTED_EDGE('',*,*,#1220,.F.); +#1708=ORIENTED_EDGE('',*,*,#1217,.F.); +#1709=ORIENTED_EDGE('',*,*,#1223,.T.); +#1710=ORIENTED_EDGE('',*,*,#1224,.T.); +#1711=ORIENTED_EDGE('',*,*,#1221,.T.); +#1712=ORIENTED_EDGE('',*,*,#1222,.T.); +#1713=ORIENTED_EDGE('',*,*,#1224,.F.); +#1714=ORIENTED_EDGE('',*,*,#1223,.F.); +#1715=CYLINDRICAL_SURFACE('',#1910,6.); +#1716=CYLINDRICAL_SURFACE('',#1957,6.); +#1717=CYLINDRICAL_SURFACE('',#1960,6.); +#1718=CYLINDRICAL_SURFACE('',#1962,6.); +#1719=CYLINDRICAL_SURFACE('',#1964,1.75); +#1720=CYLINDRICAL_SURFACE('',#1966,1.75); +#1721=CYLINDRICAL_SURFACE('',#1968,1.); +#1722=CYLINDRICAL_SURFACE('',#1970,1.); +#1723=CYLINDRICAL_SURFACE('',#1972,1.); +#1724=CYLINDRICAL_SURFACE('',#1974,1.); +#1725=CYLINDRICAL_SURFACE('',#1976,0.8115); +#1726=CYLINDRICAL_SURFACE('',#1978,0.8115); +#1727=CYLINDRICAL_SURFACE('',#1980,0.8115); +#1728=CYLINDRICAL_SURFACE('',#1982,0.8115); +#1729=CYLINDRICAL_SURFACE('',#1984,0.8115); +#1730=CYLINDRICAL_SURFACE('',#1986,0.8115); +#1731=CYLINDRICAL_SURFACE('',#1988,0.8115); +#1732=CYLINDRICAL_SURFACE('',#1990,0.8115); +#1733=CYLINDRICAL_SURFACE('',#1992,0.8115); +#1734=CYLINDRICAL_SURFACE('',#1994,0.8115); +#1735=CYLINDRICAL_SURFACE('',#1996,0.8115); +#1736=CYLINDRICAL_SURFACE('',#1998,0.8115); +#1737=CYLINDRICAL_SURFACE('',#2000,0.8115); +#1738=CYLINDRICAL_SURFACE('',#2002,0.8115); +#1739=CYLINDRICAL_SURFACE('',#2004,0.8115); +#1740=CYLINDRICAL_SURFACE('',#2006,0.8115); +#1741=CYLINDRICAL_SURFACE('',#2008,0.8115); +#1742=CYLINDRICAL_SURFACE('',#2010,0.8115); +#1743=CYLINDRICAL_SURFACE('',#2012,0.8115); +#1744=CYLINDRICAL_SURFACE('',#2014,0.8115); +#1745=CYLINDRICAL_SURFACE('',#2016,0.8115); +#1746=CYLINDRICAL_SURFACE('',#2018,0.8115); +#1747=CYLINDRICAL_SURFACE('',#2020,0.8115); +#1748=CYLINDRICAL_SURFACE('',#2022,0.8115); +#1749=CYLINDRICAL_SURFACE('',#2024,0.8115); +#1750=CYLINDRICAL_SURFACE('',#2026,0.8115); +#1751=CYLINDRICAL_SURFACE('',#2028,0.8115); +#1752=CYLINDRICAL_SURFACE('',#2030,0.8115); +#1753=CYLINDRICAL_SURFACE('',#2032,0.8115); +#1754=CYLINDRICAL_SURFACE('',#2034,0.8115); +#1755=CYLINDRICAL_SURFACE('',#2036,0.8115); +#1756=CYLINDRICAL_SURFACE('',#2038,0.8115); +#1757=CYLINDRICAL_SURFACE('',#2040,0.8115); +#1758=CYLINDRICAL_SURFACE('',#2046,3.); +#1759=CYLINDRICAL_SURFACE('',#2074,3.); +#1760=CYLINDRICAL_SURFACE('',#2077,3.); +#1761=CYLINDRICAL_SURFACE('',#2079,3.); +#1762=CYLINDRICAL_SURFACE('',#2081,1.); +#1763=CYLINDRICAL_SURFACE('',#2084,1.); +#1764=CYLINDRICAL_SURFACE('',#2087,1.); +#1765=CYLINDRICAL_SURFACE('',#2090,1.); +#1766=CYLINDRICAL_SURFACE('',#2093,1.); +#1767=CYLINDRICAL_SURFACE('',#2095,1.); +#1768=CYLINDRICAL_SURFACE('',#2097,1.); +#1769=CYLINDRICAL_SURFACE('',#2099,1.); +#1770=CYLINDRICAL_SURFACE('',#2101,0.8115); +#1771=CYLINDRICAL_SURFACE('',#2103,0.8115); +#1772=CYLINDRICAL_SURFACE('',#2105,0.8115); +#1773=CYLINDRICAL_SURFACE('',#2107,0.8115); +#1774=CYLINDRICAL_SURFACE('',#2109,0.8115); +#1775=CYLINDRICAL_SURFACE('',#2111,0.8115); +#1776=CYLINDRICAL_SURFACE('',#2113,0.8115); +#1777=CYLINDRICAL_SURFACE('',#2115,0.8115); +#1778=CYLINDRICAL_SURFACE('',#2117,0.8115); +#1779=CYLINDRICAL_SURFACE('',#2119,0.8115); +#1780=CYLINDRICAL_SURFACE('',#2121,0.8115); +#1781=CYLINDRICAL_SURFACE('',#2123,0.8115); +#1782=CYLINDRICAL_SURFACE('',#2132,0.999999999999996); +#1783=ADVANCED_FACE('',(#179),#1715,.T.); +#1784=ADVANCED_FACE('',(#180),#161,.T.); +#1785=ADVANCED_FACE('',(#181,#49,#50,#51,#52,#53,#54,#55,#56,#57,#58,#59, +#60,#61,#62,#63,#64,#65,#66,#67,#68,#69,#70,#71,#72,#73,#74,#75,#76,#77, +#78,#79,#80,#81,#82,#83,#84,#85,#86,#87),#162,.F.); +#1786=ADVANCED_FACE('',(#182),#1716,.T.); +#1787=ADVANCED_FACE('',(#183),#163,.T.); +#1788=ADVANCED_FACE('',(#184),#1717,.T.); +#1789=ADVANCED_FACE('',(#185),#1718,.T.); +#1790=ADVANCED_FACE('',(#186),#1719,.F.); +#1791=ADVANCED_FACE('',(#187),#1720,.F.); +#1792=ADVANCED_FACE('',(#188),#1721,.F.); +#1793=ADVANCED_FACE('',(#189),#1722,.F.); +#1794=ADVANCED_FACE('',(#190),#1723,.F.); +#1795=ADVANCED_FACE('',(#191),#1724,.F.); +#1796=ADVANCED_FACE('',(#192),#1725,.F.); +#1797=ADVANCED_FACE('',(#193),#1726,.F.); +#1798=ADVANCED_FACE('',(#194),#1727,.F.); +#1799=ADVANCED_FACE('',(#195),#1728,.F.); +#1800=ADVANCED_FACE('',(#196),#1729,.F.); +#1801=ADVANCED_FACE('',(#197),#1730,.F.); +#1802=ADVANCED_FACE('',(#198),#1731,.F.); +#1803=ADVANCED_FACE('',(#199),#1732,.F.); +#1804=ADVANCED_FACE('',(#200),#1733,.F.); +#1805=ADVANCED_FACE('',(#201),#1734,.F.); +#1806=ADVANCED_FACE('',(#202),#1735,.F.); +#1807=ADVANCED_FACE('',(#203),#1736,.F.); +#1808=ADVANCED_FACE('',(#204),#1737,.F.); +#1809=ADVANCED_FACE('',(#205),#1738,.F.); +#1810=ADVANCED_FACE('',(#206),#1739,.F.); +#1811=ADVANCED_FACE('',(#207),#1740,.F.); +#1812=ADVANCED_FACE('',(#208),#1741,.F.); +#1813=ADVANCED_FACE('',(#209),#1742,.F.); +#1814=ADVANCED_FACE('',(#210),#1743,.F.); +#1815=ADVANCED_FACE('',(#211),#1744,.F.); +#1816=ADVANCED_FACE('',(#212),#1745,.F.); +#1817=ADVANCED_FACE('',(#213),#1746,.F.); +#1818=ADVANCED_FACE('',(#214),#1747,.F.); +#1819=ADVANCED_FACE('',(#215),#1748,.F.); +#1820=ADVANCED_FACE('',(#216),#1749,.F.); +#1821=ADVANCED_FACE('',(#217),#1750,.F.); +#1822=ADVANCED_FACE('',(#218),#1751,.F.); +#1823=ADVANCED_FACE('',(#219),#1752,.F.); +#1824=ADVANCED_FACE('',(#220),#1753,.F.); +#1825=ADVANCED_FACE('',(#221),#1754,.F.); +#1826=ADVANCED_FACE('',(#222),#1755,.F.); +#1827=ADVANCED_FACE('',(#223),#1756,.F.); +#1828=ADVANCED_FACE('',(#224),#1757,.F.); +#1829=ADVANCED_FACE('',(#225),#164,.T.); +#1830=ADVANCED_FACE('',(#226),#165,.T.); +#1831=ADVANCED_FACE('',(#227,#88,#89,#90,#91,#92,#93,#94,#95,#96,#97,#98, +#99,#100,#101,#102,#103,#104,#105,#106,#107,#108,#109,#110,#111,#112,#113, +#114,#115,#116,#117,#118,#119,#120,#121,#122,#123,#124,#125,#126),#166, + .T.); +#1832=ADVANCED_FACE('',(#228),#1758,.T.); +#1833=ADVANCED_FACE('',(#229),#167,.T.); +#1834=ADVANCED_FACE('',(#230,#127,#128,#129,#130,#131,#132,#133,#134,#135, +#136,#137,#138,#139,#140,#141,#142,#143),#168,.F.); +#1835=ADVANCED_FACE('',(#231),#1759,.T.); +#1836=ADVANCED_FACE('',(#232),#169,.T.); +#1837=ADVANCED_FACE('',(#233),#1760,.T.); +#1838=ADVANCED_FACE('',(#234),#1761,.T.); +#1839=ADVANCED_FACE('',(#235),#1762,.F.); +#1840=ADVANCED_FACE('',(#236),#170,.T.); +#1841=ADVANCED_FACE('',(#237),#1763,.F.); +#1842=ADVANCED_FACE('',(#238),#171,.T.); +#1843=ADVANCED_FACE('',(#239),#1764,.F.); +#1844=ADVANCED_FACE('',(#240),#172,.T.); +#1845=ADVANCED_FACE('',(#241),#1765,.F.); +#1846=ADVANCED_FACE('',(#242),#173,.T.); +#1847=ADVANCED_FACE('',(#243),#1766,.F.); +#1848=ADVANCED_FACE('',(#244),#1767,.F.); +#1849=ADVANCED_FACE('',(#245),#1768,.F.); +#1850=ADVANCED_FACE('',(#246),#1769,.F.); +#1851=ADVANCED_FACE('',(#247),#1770,.F.); +#1852=ADVANCED_FACE('',(#248),#1771,.F.); +#1853=ADVANCED_FACE('',(#249),#1772,.F.); +#1854=ADVANCED_FACE('',(#250),#1773,.F.); +#1855=ADVANCED_FACE('',(#251),#1774,.F.); +#1856=ADVANCED_FACE('',(#252),#1775,.F.); +#1857=ADVANCED_FACE('',(#253),#1776,.F.); +#1858=ADVANCED_FACE('',(#254),#1777,.F.); +#1859=ADVANCED_FACE('',(#255),#1778,.F.); +#1860=ADVANCED_FACE('',(#256),#1779,.F.); +#1861=ADVANCED_FACE('',(#257),#1780,.F.); +#1862=ADVANCED_FACE('',(#258),#1781,.F.); +#1863=ADVANCED_FACE('',(#259),#174,.T.); +#1864=ADVANCED_FACE('',(#260),#175,.T.); +#1865=ADVANCED_FACE('',(#261,#144,#145,#146,#147,#148,#149,#150,#151,#152, +#153,#154,#155,#156,#157,#158,#159,#160),#176,.T.); +#1866=ADVANCED_FACE('',(#262),#36,.T.); +#1867=ADVANCED_FACE('',(#263),#1782,.T.); +#1868=ADVANCED_FACE('',(#264),#177,.F.); +#1869=ADVANCED_FACE('',(#265),#35,.T.); +#1870=ADVANCED_FACE('',(#266),#178,.T.); +#1871=CLOSED_SHELL('',(#1783,#1784,#1785,#1786,#1787,#1788,#1789,#1790, +#1791,#1792,#1793,#1794,#1795,#1796,#1797,#1798,#1799,#1800,#1801,#1802, +#1803,#1804,#1805,#1806,#1807,#1808,#1809,#1810,#1811,#1812,#1813,#1814, +#1815,#1816,#1817,#1818,#1819,#1820,#1821,#1822,#1823,#1824,#1825,#1826, +#1827,#1828,#1829,#1830,#1831)); +#1872=CLOSED_SHELL('',(#1832,#1833,#1834,#1835,#1836,#1837,#1838,#1839, +#1840,#1841,#1842,#1843,#1844,#1845,#1846,#1847,#1848,#1849,#1850,#1851, +#1852,#1853,#1854,#1855,#1856,#1857,#1858,#1859,#1860,#1861,#1862,#1863, +#1864,#1865)); +#1873=CLOSED_SHELL('',(#1866,#1867,#1868,#1869,#1870)); +#1874=DERIVED_UNIT_ELEMENT(#1880,1.); +#1875=DERIVED_UNIT_ELEMENT(#3244,-3.); +#1876=DERIVED_UNIT_ELEMENT(#1880,1.); +#1877=DERIVED_UNIT_ELEMENT(#3244,-3.); +#1878=DERIVED_UNIT_ELEMENT(#1880,1.); +#1879=DERIVED_UNIT_ELEMENT(#3244,-3.); +#1880=( +MASS_UNIT() +NAMED_UNIT(*) +SI_UNIT(.KILO.,.GRAM.) +); +#1881=DERIVED_UNIT((#1874,#1875)); +#1882=DERIVED_UNIT((#1876,#1877)); +#1883=DERIVED_UNIT((#1878,#1879)); +#1884=MEASURE_REPRESENTATION_ITEM('density measure', +POSITIVE_RATIO_MEASURE(7850.),#1881); +#1885=MEASURE_REPRESENTATION_ITEM('density measure', +POSITIVE_RATIO_MEASURE(7850.),#1882); +#1886=MEASURE_REPRESENTATION_ITEM('density measure', +POSITIVE_RATIO_MEASURE(7850.),#1883); +#1887=PROPERTY_DEFINITION_REPRESENTATION(#1902,#1893); +#1888=PROPERTY_DEFINITION_REPRESENTATION(#1903,#1894); +#1889=PROPERTY_DEFINITION_REPRESENTATION(#1904,#1895); +#1890=PROPERTY_DEFINITION_REPRESENTATION(#1905,#1896); +#1891=PROPERTY_DEFINITION_REPRESENTATION(#1906,#1897); +#1892=PROPERTY_DEFINITION_REPRESENTATION(#1907,#1898); +#1893=REPRESENTATION('material name',(#1899),#3239); +#1894=REPRESENTATION('density',(#1884),#3239); +#1895=REPRESENTATION('material name',(#1900),#3240); +#1896=REPRESENTATION('density',(#1885),#3240); +#1897=REPRESENTATION('material name',(#1901),#3241); +#1898=REPRESENTATION('density',(#1886),#3241); +#1899=DESCRIPTIVE_REPRESENTATION_ITEM('Steel','Steel'); +#1900=DESCRIPTIVE_REPRESENTATION_ITEM('Steel','Steel'); +#1901=DESCRIPTIVE_REPRESENTATION_ITEM('Steel','Steel'); +#1902=PROPERTY_DEFINITION('material property','material name',#3267); +#1903=PROPERTY_DEFINITION('material property','density of part',#3267); +#1904=PROPERTY_DEFINITION('material property','material name',#3268); +#1905=PROPERTY_DEFINITION('material property','density of part',#3268); +#1906=PROPERTY_DEFINITION('material property','material name',#3269); +#1907=PROPERTY_DEFINITION('material property','density of part',#3269); +#1908=AXIS2_PLACEMENT_3D('',#2727,#2146,#2147); +#1909=AXIS2_PLACEMENT_3D('',#2728,#2148,#2149); +#1910=AXIS2_PLACEMENT_3D('',#2729,#2150,#2151); +#1911=AXIS2_PLACEMENT_3D('',#2732,#2152,#2153); +#1912=AXIS2_PLACEMENT_3D('',#2736,#2155,#2156); +#1913=AXIS2_PLACEMENT_3D('',#2738,#2158,#2159); +#1914=AXIS2_PLACEMENT_3D('',#2744,#2163,#2164); +#1915=AXIS2_PLACEMENT_3D('',#2748,#2166,#2167); +#1916=AXIS2_PLACEMENT_3D('',#2752,#2169,#2170); +#1917=AXIS2_PLACEMENT_3D('',#2755,#2172,#2173); +#1918=AXIS2_PLACEMENT_3D('',#2757,#2174,#2175); +#1919=AXIS2_PLACEMENT_3D('',#2759,#2176,#2177); +#1920=AXIS2_PLACEMENT_3D('',#2761,#2178,#2179); +#1921=AXIS2_PLACEMENT_3D('',#2763,#2180,#2181); +#1922=AXIS2_PLACEMENT_3D('',#2765,#2182,#2183); +#1923=AXIS2_PLACEMENT_3D('',#2767,#2184,#2185); +#1924=AXIS2_PLACEMENT_3D('',#2769,#2186,#2187); +#1925=AXIS2_PLACEMENT_3D('',#2771,#2188,#2189); +#1926=AXIS2_PLACEMENT_3D('',#2773,#2190,#2191); +#1927=AXIS2_PLACEMENT_3D('',#2775,#2192,#2193); +#1928=AXIS2_PLACEMENT_3D('',#2777,#2194,#2195); +#1929=AXIS2_PLACEMENT_3D('',#2779,#2196,#2197); +#1930=AXIS2_PLACEMENT_3D('',#2781,#2198,#2199); +#1931=AXIS2_PLACEMENT_3D('',#2783,#2200,#2201); +#1932=AXIS2_PLACEMENT_3D('',#2785,#2202,#2203); +#1933=AXIS2_PLACEMENT_3D('',#2787,#2204,#2205); +#1934=AXIS2_PLACEMENT_3D('',#2789,#2206,#2207); +#1935=AXIS2_PLACEMENT_3D('',#2791,#2208,#2209); +#1936=AXIS2_PLACEMENT_3D('',#2793,#2210,#2211); +#1937=AXIS2_PLACEMENT_3D('',#2795,#2212,#2213); +#1938=AXIS2_PLACEMENT_3D('',#2797,#2214,#2215); +#1939=AXIS2_PLACEMENT_3D('',#2799,#2216,#2217); +#1940=AXIS2_PLACEMENT_3D('',#2801,#2218,#2219); +#1941=AXIS2_PLACEMENT_3D('',#2803,#2220,#2221); +#1942=AXIS2_PLACEMENT_3D('',#2805,#2222,#2223); +#1943=AXIS2_PLACEMENT_3D('',#2807,#2224,#2225); +#1944=AXIS2_PLACEMENT_3D('',#2809,#2226,#2227); +#1945=AXIS2_PLACEMENT_3D('',#2811,#2228,#2229); +#1946=AXIS2_PLACEMENT_3D('',#2813,#2230,#2231); +#1947=AXIS2_PLACEMENT_3D('',#2815,#2232,#2233); +#1948=AXIS2_PLACEMENT_3D('',#2817,#2234,#2235); +#1949=AXIS2_PLACEMENT_3D('',#2819,#2236,#2237); +#1950=AXIS2_PLACEMENT_3D('',#2821,#2238,#2239); +#1951=AXIS2_PLACEMENT_3D('',#2823,#2240,#2241); +#1952=AXIS2_PLACEMENT_3D('',#2825,#2242,#2243); +#1953=AXIS2_PLACEMENT_3D('',#2827,#2244,#2245); +#1954=AXIS2_PLACEMENT_3D('',#2829,#2246,#2247); +#1955=AXIS2_PLACEMENT_3D('',#2831,#2248,#2249); +#1956=AXIS2_PLACEMENT_3D('',#2833,#2250,#2251); +#1957=AXIS2_PLACEMENT_3D('',#2834,#2252,#2253); +#1958=AXIS2_PLACEMENT_3D('',#2837,#2254,#2255); +#1959=AXIS2_PLACEMENT_3D('',#2840,#2258,#2259); +#1960=AXIS2_PLACEMENT_3D('',#2844,#2262,#2263); +#1961=AXIS2_PLACEMENT_3D('',#2846,#2264,#2265); +#1962=AXIS2_PLACEMENT_3D('',#2848,#2267,#2268); +#1963=AXIS2_PLACEMENT_3D('',#2850,#2269,#2270); +#1964=AXIS2_PLACEMENT_3D('',#2852,#2272,#2273); +#1965=AXIS2_PLACEMENT_3D('',#2854,#2274,#2275); +#1966=AXIS2_PLACEMENT_3D('',#2856,#2277,#2278); +#1967=AXIS2_PLACEMENT_3D('',#2858,#2279,#2280); +#1968=AXIS2_PLACEMENT_3D('',#2860,#2282,#2283); +#1969=AXIS2_PLACEMENT_3D('',#2862,#2284,#2285); +#1970=AXIS2_PLACEMENT_3D('',#2864,#2287,#2288); +#1971=AXIS2_PLACEMENT_3D('',#2866,#2289,#2290); +#1972=AXIS2_PLACEMENT_3D('',#2868,#2292,#2293); +#1973=AXIS2_PLACEMENT_3D('',#2870,#2294,#2295); +#1974=AXIS2_PLACEMENT_3D('',#2872,#2297,#2298); +#1975=AXIS2_PLACEMENT_3D('',#2874,#2299,#2300); +#1976=AXIS2_PLACEMENT_3D('',#2876,#2302,#2303); +#1977=AXIS2_PLACEMENT_3D('',#2878,#2304,#2305); +#1978=AXIS2_PLACEMENT_3D('',#2880,#2307,#2308); +#1979=AXIS2_PLACEMENT_3D('',#2882,#2309,#2310); +#1980=AXIS2_PLACEMENT_3D('',#2884,#2312,#2313); +#1981=AXIS2_PLACEMENT_3D('',#2886,#2314,#2315); +#1982=AXIS2_PLACEMENT_3D('',#2888,#2317,#2318); +#1983=AXIS2_PLACEMENT_3D('',#2890,#2319,#2320); +#1984=AXIS2_PLACEMENT_3D('',#2892,#2322,#2323); +#1985=AXIS2_PLACEMENT_3D('',#2894,#2324,#2325); +#1986=AXIS2_PLACEMENT_3D('',#2896,#2327,#2328); +#1987=AXIS2_PLACEMENT_3D('',#2898,#2329,#2330); +#1988=AXIS2_PLACEMENT_3D('',#2900,#2332,#2333); +#1989=AXIS2_PLACEMENT_3D('',#2902,#2334,#2335); +#1990=AXIS2_PLACEMENT_3D('',#2904,#2337,#2338); +#1991=AXIS2_PLACEMENT_3D('',#2906,#2339,#2340); +#1992=AXIS2_PLACEMENT_3D('',#2908,#2342,#2343); +#1993=AXIS2_PLACEMENT_3D('',#2910,#2344,#2345); +#1994=AXIS2_PLACEMENT_3D('',#2912,#2347,#2348); +#1995=AXIS2_PLACEMENT_3D('',#2914,#2349,#2350); +#1996=AXIS2_PLACEMENT_3D('',#2916,#2352,#2353); +#1997=AXIS2_PLACEMENT_3D('',#2918,#2354,#2355); +#1998=AXIS2_PLACEMENT_3D('',#2920,#2357,#2358); +#1999=AXIS2_PLACEMENT_3D('',#2922,#2359,#2360); +#2000=AXIS2_PLACEMENT_3D('',#2924,#2362,#2363); +#2001=AXIS2_PLACEMENT_3D('',#2926,#2364,#2365); +#2002=AXIS2_PLACEMENT_3D('',#2928,#2367,#2368); +#2003=AXIS2_PLACEMENT_3D('',#2930,#2369,#2370); +#2004=AXIS2_PLACEMENT_3D('',#2932,#2372,#2373); +#2005=AXIS2_PLACEMENT_3D('',#2934,#2374,#2375); +#2006=AXIS2_PLACEMENT_3D('',#2936,#2377,#2378); +#2007=AXIS2_PLACEMENT_3D('',#2938,#2379,#2380); +#2008=AXIS2_PLACEMENT_3D('',#2940,#2382,#2383); +#2009=AXIS2_PLACEMENT_3D('',#2942,#2384,#2385); +#2010=AXIS2_PLACEMENT_3D('',#2944,#2387,#2388); +#2011=AXIS2_PLACEMENT_3D('',#2946,#2389,#2390); +#2012=AXIS2_PLACEMENT_3D('',#2948,#2392,#2393); +#2013=AXIS2_PLACEMENT_3D('',#2950,#2394,#2395); +#2014=AXIS2_PLACEMENT_3D('',#2952,#2397,#2398); +#2015=AXIS2_PLACEMENT_3D('',#2954,#2399,#2400); +#2016=AXIS2_PLACEMENT_3D('',#2956,#2402,#2403); +#2017=AXIS2_PLACEMENT_3D('',#2958,#2404,#2405); +#2018=AXIS2_PLACEMENT_3D('',#2960,#2407,#2408); +#2019=AXIS2_PLACEMENT_3D('',#2962,#2409,#2410); +#2020=AXIS2_PLACEMENT_3D('',#2964,#2412,#2413); +#2021=AXIS2_PLACEMENT_3D('',#2966,#2414,#2415); +#2022=AXIS2_PLACEMENT_3D('',#2968,#2417,#2418); +#2023=AXIS2_PLACEMENT_3D('',#2970,#2419,#2420); +#2024=AXIS2_PLACEMENT_3D('',#2972,#2422,#2423); +#2025=AXIS2_PLACEMENT_3D('',#2974,#2424,#2425); +#2026=AXIS2_PLACEMENT_3D('',#2976,#2427,#2428); +#2027=AXIS2_PLACEMENT_3D('',#2978,#2429,#2430); +#2028=AXIS2_PLACEMENT_3D('',#2980,#2432,#2433); +#2029=AXIS2_PLACEMENT_3D('',#2982,#2434,#2435); +#2030=AXIS2_PLACEMENT_3D('',#2984,#2437,#2438); +#2031=AXIS2_PLACEMENT_3D('',#2986,#2439,#2440); +#2032=AXIS2_PLACEMENT_3D('',#2988,#2442,#2443); +#2033=AXIS2_PLACEMENT_3D('',#2990,#2444,#2445); +#2034=AXIS2_PLACEMENT_3D('',#2992,#2447,#2448); +#2035=AXIS2_PLACEMENT_3D('',#2994,#2449,#2450); +#2036=AXIS2_PLACEMENT_3D('',#2996,#2452,#2453); +#2037=AXIS2_PLACEMENT_3D('',#2998,#2454,#2455); +#2038=AXIS2_PLACEMENT_3D('',#3000,#2457,#2458); +#2039=AXIS2_PLACEMENT_3D('',#3002,#2459,#2460); +#2040=AXIS2_PLACEMENT_3D('',#3004,#2462,#2463); +#2041=AXIS2_PLACEMENT_3D('',#3006,#2464,#2465); +#2042=AXIS2_PLACEMENT_3D('',#3008,#2467,#2468); +#2043=AXIS2_PLACEMENT_3D('',#3010,#2470,#2471); +#2044=AXIS2_PLACEMENT_3D('',#3012,#2473,#2474); +#2045=AXIS2_PLACEMENT_3D('',#3013,#2475,#2476); +#2046=AXIS2_PLACEMENT_3D('',#3014,#2477,#2478); +#2047=AXIS2_PLACEMENT_3D('',#3017,#2479,#2480); +#2048=AXIS2_PLACEMENT_3D('',#3021,#2482,#2483); +#2049=AXIS2_PLACEMENT_3D('',#3023,#2485,#2486); +#2050=AXIS2_PLACEMENT_3D('',#3029,#2490,#2491); +#2051=AXIS2_PLACEMENT_3D('',#3033,#2493,#2494); +#2052=AXIS2_PLACEMENT_3D('',#3037,#2496,#2497); +#2053=AXIS2_PLACEMENT_3D('',#3040,#2499,#2500); +#2054=AXIS2_PLACEMENT_3D('',#3042,#2501,#2502); +#2055=AXIS2_PLACEMENT_3D('',#3044,#2503,#2504); +#2056=AXIS2_PLACEMENT_3D('',#3046,#2505,#2506); +#2057=AXIS2_PLACEMENT_3D('',#3048,#2507,#2508); +#2058=AXIS2_PLACEMENT_3D('',#3050,#2509,#2510); +#2059=AXIS2_PLACEMENT_3D('',#3052,#2511,#2512); +#2060=AXIS2_PLACEMENT_3D('',#3054,#2513,#2514); +#2061=AXIS2_PLACEMENT_3D('',#3056,#2515,#2516); +#2062=AXIS2_PLACEMENT_3D('',#3058,#2517,#2518); +#2063=AXIS2_PLACEMENT_3D('',#3060,#2519,#2520); +#2064=AXIS2_PLACEMENT_3D('',#3062,#2521,#2522); +#2065=AXIS2_PLACEMENT_3D('',#3064,#2523,#2524); +#2066=AXIS2_PLACEMENT_3D('',#3066,#2525,#2526); +#2067=AXIS2_PLACEMENT_3D('',#3068,#2527,#2528); +#2068=AXIS2_PLACEMENT_3D('',#3070,#2529,#2530); +#2069=AXIS2_PLACEMENT_3D('',#3072,#2531,#2532); +#2070=AXIS2_PLACEMENT_3D('',#3075,#2533,#2534); +#2071=AXIS2_PLACEMENT_3D('',#3079,#2536,#2537); +#2072=AXIS2_PLACEMENT_3D('',#3083,#2539,#2540); +#2073=AXIS2_PLACEMENT_3D('',#3087,#2542,#2543); +#2074=AXIS2_PLACEMENT_3D('',#3089,#2545,#2546); +#2075=AXIS2_PLACEMENT_3D('',#3092,#2547,#2548); +#2076=AXIS2_PLACEMENT_3D('',#3095,#2551,#2552); +#2077=AXIS2_PLACEMENT_3D('',#3099,#2555,#2556); +#2078=AXIS2_PLACEMENT_3D('',#3101,#2557,#2558); +#2079=AXIS2_PLACEMENT_3D('',#3103,#2560,#2561); +#2080=AXIS2_PLACEMENT_3D('',#3105,#2562,#2563); +#2081=AXIS2_PLACEMENT_3D('',#3107,#2565,#2566); +#2082=AXIS2_PLACEMENT_3D('',#3111,#2568,#2569); +#2083=AXIS2_PLACEMENT_3D('',#3113,#2571,#2572); +#2084=AXIS2_PLACEMENT_3D('',#3117,#2575,#2576); +#2085=AXIS2_PLACEMENT_3D('',#3120,#2578,#2579); +#2086=AXIS2_PLACEMENT_3D('',#3121,#2580,#2581); +#2087=AXIS2_PLACEMENT_3D('',#3125,#2584,#2585); +#2088=AXIS2_PLACEMENT_3D('',#3128,#2587,#2588); +#2089=AXIS2_PLACEMENT_3D('',#3129,#2589,#2590); +#2090=AXIS2_PLACEMENT_3D('',#3133,#2593,#2594); +#2091=AXIS2_PLACEMENT_3D('',#3136,#2596,#2597); +#2092=AXIS2_PLACEMENT_3D('',#3137,#2598,#2599); +#2093=AXIS2_PLACEMENT_3D('',#3139,#2601,#2602); +#2094=AXIS2_PLACEMENT_3D('',#3141,#2603,#2604); +#2095=AXIS2_PLACEMENT_3D('',#3143,#2606,#2607); +#2096=AXIS2_PLACEMENT_3D('',#3145,#2608,#2609); +#2097=AXIS2_PLACEMENT_3D('',#3147,#2611,#2612); +#2098=AXIS2_PLACEMENT_3D('',#3149,#2613,#2614); +#2099=AXIS2_PLACEMENT_3D('',#3151,#2616,#2617); +#2100=AXIS2_PLACEMENT_3D('',#3153,#2618,#2619); +#2101=AXIS2_PLACEMENT_3D('',#3155,#2621,#2622); +#2102=AXIS2_PLACEMENT_3D('',#3157,#2623,#2624); +#2103=AXIS2_PLACEMENT_3D('',#3159,#2626,#2627); +#2104=AXIS2_PLACEMENT_3D('',#3161,#2628,#2629); +#2105=AXIS2_PLACEMENT_3D('',#3163,#2631,#2632); +#2106=AXIS2_PLACEMENT_3D('',#3165,#2633,#2634); +#2107=AXIS2_PLACEMENT_3D('',#3167,#2636,#2637); +#2108=AXIS2_PLACEMENT_3D('',#3169,#2638,#2639); +#2109=AXIS2_PLACEMENT_3D('',#3171,#2641,#2642); +#2110=AXIS2_PLACEMENT_3D('',#3173,#2643,#2644); +#2111=AXIS2_PLACEMENT_3D('',#3175,#2646,#2647); +#2112=AXIS2_PLACEMENT_3D('',#3177,#2648,#2649); +#2113=AXIS2_PLACEMENT_3D('',#3179,#2651,#2652); +#2114=AXIS2_PLACEMENT_3D('',#3181,#2653,#2654); +#2115=AXIS2_PLACEMENT_3D('',#3183,#2656,#2657); +#2116=AXIS2_PLACEMENT_3D('',#3185,#2658,#2659); +#2117=AXIS2_PLACEMENT_3D('',#3187,#2661,#2662); +#2118=AXIS2_PLACEMENT_3D('',#3189,#2663,#2664); +#2119=AXIS2_PLACEMENT_3D('',#3191,#2666,#2667); +#2120=AXIS2_PLACEMENT_3D('',#3193,#2668,#2669); +#2121=AXIS2_PLACEMENT_3D('',#3195,#2671,#2672); +#2122=AXIS2_PLACEMENT_3D('',#3197,#2673,#2674); +#2123=AXIS2_PLACEMENT_3D('',#3199,#2676,#2677); +#2124=AXIS2_PLACEMENT_3D('',#3201,#2678,#2679); +#2125=AXIS2_PLACEMENT_3D('',#3203,#2681,#2682); +#2126=AXIS2_PLACEMENT_3D('',#3205,#2684,#2685); +#2127=AXIS2_PLACEMENT_3D('',#3207,#2687,#2688); +#2128=AXIS2_PLACEMENT_3D('',#3208,#2689,#2690); +#2129=AXIS2_PLACEMENT_3D('',#3209,#2691,#2692); +#2130=AXIS2_PLACEMENT_3D('',#3211,#2693,#2694); +#2131=AXIS2_PLACEMENT_3D('',#3214,#2696,#2697); +#2132=AXIS2_PLACEMENT_3D('',#3215,#2698,#2699); +#2133=AXIS2_PLACEMENT_3D('',#3219,#2701,#2702); +#2134=AXIS2_PLACEMENT_3D('',#3220,#2703,#2704); +#2135=AXIS2_PLACEMENT_3D('',#3221,#2705,#2706); +#2136=AXIS2_PLACEMENT_3D('',#3222,#2707,#2708); +#2137=AXIS2_PLACEMENT_3D('',#3224,#2709,#2710); +#2138=AXIS2_PLACEMENT_3D('',#3225,#2711,#2712); +#2139=AXIS2_PLACEMENT_3D('',#3226,#2713,#2714); +#2140=AXIS2_PLACEMENT_3D('',#3227,#2715,#2716); +#2141=AXIS2_PLACEMENT_3D('',#3228,#2717,#2718); +#2142=AXIS2_PLACEMENT_3D('',#3229,#2719,#2720); +#2143=AXIS2_PLACEMENT_3D('',#3230,#2721,#2722); +#2144=AXIS2_PLACEMENT_3D('',#3231,#2723,#2724); +#2145=AXIS2_PLACEMENT_3D('',#3232,#2725,#2726); +#2146=DIRECTION('axis',(0.,0.,1.)); +#2147=DIRECTION('refdir',(1.,0.,0.)); +#2148=DIRECTION('axis',(0.,0.,1.)); +#2149=DIRECTION('refdir',(1.,0.,0.)); +#2150=DIRECTION('center_axis',(0.,0.,1.)); +#2151=DIRECTION('ref_axis',(-0.707106781186548,0.707106781186548,0.)); +#2152=DIRECTION('center_axis',(0.,0.,-1.)); +#2153=DIRECTION('ref_axis',(-0.707106781186548,0.707106781186548,0.)); +#2154=DIRECTION('',(0.,0.,-1.)); +#2155=DIRECTION('center_axis',(0.,0.,1.)); +#2156=DIRECTION('ref_axis',(-0.707106781186548,0.707106781186548,0.)); +#2157=DIRECTION('',(0.,0.,1.)); +#2158=DIRECTION('center_axis',(-1.,8.5265128291212E-16,0.)); +#2159=DIRECTION('ref_axis',(-8.5265128291212E-16,-1.,0.)); +#2160=DIRECTION('',(8.5265128291212E-16,1.,0.)); +#2161=DIRECTION('',(0.,0.,-1.)); +#2162=DIRECTION('',(8.5265128291212E-16,1.,0.)); +#2163=DIRECTION('center_axis',(0.,0.,1.)); +#2164=DIRECTION('ref_axis',(1.,0.,0.)); +#2165=DIRECTION('',(-1.,0.,0.)); +#2166=DIRECTION('center_axis',(0.,0.,1.)); +#2167=DIRECTION('ref_axis',(0.707106781186549,0.707106781186546,0.)); +#2168=DIRECTION('',(0.,-1.,0.)); +#2169=DIRECTION('center_axis',(0.,0.,1.)); +#2170=DIRECTION('ref_axis',(0.707106781186549,-0.707106781186546,0.)); +#2171=DIRECTION('',(1.,0.,0.)); +#2172=DIRECTION('center_axis',(0.,0.,1.)); +#2173=DIRECTION('ref_axis',(-0.707106781186548,-0.707106781186547,0.)); +#2174=DIRECTION('center_axis',(0.,0.,1.)); +#2175=DIRECTION('ref_axis',(1.,0.,0.)); +#2176=DIRECTION('center_axis',(0.,0.,1.)); +#2177=DIRECTION('ref_axis',(1.,0.,0.)); +#2178=DIRECTION('center_axis',(0.,0.,1.)); +#2179=DIRECTION('ref_axis',(1.,0.,0.)); +#2180=DIRECTION('center_axis',(0.,0.,1.)); +#2181=DIRECTION('ref_axis',(1.,0.,0.)); +#2182=DIRECTION('center_axis',(0.,0.,1.)); +#2183=DIRECTION('ref_axis',(1.,0.,0.)); +#2184=DIRECTION('center_axis',(0.,0.,1.)); +#2185=DIRECTION('ref_axis',(1.,0.,0.)); +#2186=DIRECTION('center_axis',(0.,0.,1.)); +#2187=DIRECTION('ref_axis',(1.,0.,0.)); +#2188=DIRECTION('center_axis',(0.,0.,1.)); +#2189=DIRECTION('ref_axis',(1.,0.,0.)); +#2190=DIRECTION('center_axis',(0.,0.,1.)); +#2191=DIRECTION('ref_axis',(1.,0.,0.)); +#2192=DIRECTION('center_axis',(0.,0.,1.)); +#2193=DIRECTION('ref_axis',(1.,0.,0.)); +#2194=DIRECTION('center_axis',(0.,0.,1.)); +#2195=DIRECTION('ref_axis',(1.,0.,0.)); +#2196=DIRECTION('center_axis',(0.,0.,1.)); +#2197=DIRECTION('ref_axis',(1.,0.,0.)); +#2198=DIRECTION('center_axis',(0.,0.,1.)); +#2199=DIRECTION('ref_axis',(1.,0.,0.)); +#2200=DIRECTION('center_axis',(0.,0.,1.)); +#2201=DIRECTION('ref_axis',(1.,0.,0.)); +#2202=DIRECTION('center_axis',(0.,0.,1.)); +#2203=DIRECTION('ref_axis',(1.,0.,0.)); +#2204=DIRECTION('center_axis',(0.,0.,1.)); +#2205=DIRECTION('ref_axis',(1.,0.,0.)); +#2206=DIRECTION('center_axis',(0.,0.,1.)); +#2207=DIRECTION('ref_axis',(1.,0.,0.)); +#2208=DIRECTION('center_axis',(0.,0.,1.)); +#2209=DIRECTION('ref_axis',(1.,0.,0.)); +#2210=DIRECTION('center_axis',(0.,0.,1.)); +#2211=DIRECTION('ref_axis',(1.,0.,0.)); +#2212=DIRECTION('center_axis',(0.,0.,1.)); +#2213=DIRECTION('ref_axis',(1.,0.,0.)); +#2214=DIRECTION('center_axis',(0.,0.,1.)); +#2215=DIRECTION('ref_axis',(1.,0.,0.)); +#2216=DIRECTION('center_axis',(0.,0.,1.)); +#2217=DIRECTION('ref_axis',(1.,0.,0.)); +#2218=DIRECTION('center_axis',(0.,0.,1.)); +#2219=DIRECTION('ref_axis',(1.,0.,0.)); +#2220=DIRECTION('center_axis',(0.,0.,1.)); +#2221=DIRECTION('ref_axis',(1.,0.,0.)); +#2222=DIRECTION('center_axis',(0.,0.,1.)); +#2223=DIRECTION('ref_axis',(1.,0.,0.)); +#2224=DIRECTION('center_axis',(0.,0.,1.)); +#2225=DIRECTION('ref_axis',(1.,0.,0.)); +#2226=DIRECTION('center_axis',(0.,0.,1.)); +#2227=DIRECTION('ref_axis',(1.,0.,0.)); +#2228=DIRECTION('center_axis',(0.,0.,1.)); +#2229=DIRECTION('ref_axis',(1.,0.,0.)); +#2230=DIRECTION('center_axis',(0.,0.,1.)); +#2231=DIRECTION('ref_axis',(1.,0.,0.)); +#2232=DIRECTION('center_axis',(0.,0.,1.)); +#2233=DIRECTION('ref_axis',(1.,0.,0.)); +#2234=DIRECTION('center_axis',(0.,0.,1.)); +#2235=DIRECTION('ref_axis',(1.,0.,0.)); +#2236=DIRECTION('center_axis',(0.,0.,1.)); +#2237=DIRECTION('ref_axis',(1.,0.,0.)); +#2238=DIRECTION('center_axis',(0.,0.,1.)); +#2239=DIRECTION('ref_axis',(1.,0.,0.)); +#2240=DIRECTION('center_axis',(0.,0.,1.)); +#2241=DIRECTION('ref_axis',(1.,0.,0.)); +#2242=DIRECTION('center_axis',(0.,0.,1.)); +#2243=DIRECTION('ref_axis',(1.,0.,0.)); +#2244=DIRECTION('center_axis',(0.,0.,1.)); +#2245=DIRECTION('ref_axis',(1.,0.,0.)); +#2246=DIRECTION('center_axis',(0.,0.,1.)); +#2247=DIRECTION('ref_axis',(1.,0.,0.)); +#2248=DIRECTION('center_axis',(0.,0.,1.)); +#2249=DIRECTION('ref_axis',(1.,0.,0.)); +#2250=DIRECTION('center_axis',(0.,0.,1.)); +#2251=DIRECTION('ref_axis',(1.,0.,0.)); +#2252=DIRECTION('center_axis',(0.,0.,1.)); +#2253=DIRECTION('ref_axis',(0.707106781186549,0.707106781186546,0.)); +#2254=DIRECTION('center_axis',(0.,0.,-1.)); +#2255=DIRECTION('ref_axis',(0.707106781186549,0.707106781186546,0.)); +#2256=DIRECTION('',(0.,0.,-1.)); +#2257=DIRECTION('',(0.,0.,1.)); +#2258=DIRECTION('center_axis',(1.,0.,0.)); +#2259=DIRECTION('ref_axis',(0.,1.,0.)); +#2260=DIRECTION('',(0.,-1.,0.)); +#2261=DIRECTION('',(0.,0.,1.)); +#2262=DIRECTION('center_axis',(0.,0.,1.)); +#2263=DIRECTION('ref_axis',(0.707106781186549,-0.707106781186546,0.)); +#2264=DIRECTION('center_axis',(0.,0.,-1.)); +#2265=DIRECTION('ref_axis',(0.707106781186549,-0.707106781186546,0.)); +#2266=DIRECTION('',(0.,0.,-1.)); +#2267=DIRECTION('center_axis',(0.,0.,1.)); +#2268=DIRECTION('ref_axis',(-0.707106781186548,-0.707106781186547,0.)); +#2269=DIRECTION('center_axis',(0.,0.,-1.)); +#2270=DIRECTION('ref_axis',(-0.707106781186548,-0.707106781186547,0.)); +#2271=DIRECTION('',(0.,0.,1.)); +#2272=DIRECTION('center_axis',(0.,0.,-1.)); +#2273=DIRECTION('ref_axis',(1.,0.,0.)); +#2274=DIRECTION('center_axis',(0.,0.,-1.)); +#2275=DIRECTION('ref_axis',(1.,0.,0.)); +#2276=DIRECTION('',(0.,0.,-1.)); +#2277=DIRECTION('center_axis',(0.,0.,-1.)); +#2278=DIRECTION('ref_axis',(1.,0.,0.)); +#2279=DIRECTION('center_axis',(0.,0.,-1.)); +#2280=DIRECTION('ref_axis',(1.,0.,0.)); +#2281=DIRECTION('',(0.,0.,-1.)); +#2282=DIRECTION('center_axis',(0.,0.,-1.)); +#2283=DIRECTION('ref_axis',(1.,0.,0.)); +#2284=DIRECTION('center_axis',(0.,0.,-1.)); +#2285=DIRECTION('ref_axis',(1.,0.,0.)); +#2286=DIRECTION('',(0.,0.,-1.)); +#2287=DIRECTION('center_axis',(0.,0.,-1.)); +#2288=DIRECTION('ref_axis',(1.,0.,0.)); +#2289=DIRECTION('center_axis',(0.,0.,-1.)); +#2290=DIRECTION('ref_axis',(1.,0.,0.)); +#2291=DIRECTION('',(0.,0.,-1.)); +#2292=DIRECTION('center_axis',(0.,0.,-1.)); +#2293=DIRECTION('ref_axis',(1.,0.,0.)); +#2294=DIRECTION('center_axis',(0.,0.,-1.)); +#2295=DIRECTION('ref_axis',(1.,0.,0.)); +#2296=DIRECTION('',(0.,0.,-1.)); +#2297=DIRECTION('center_axis',(0.,0.,-1.)); +#2298=DIRECTION('ref_axis',(1.,0.,0.)); +#2299=DIRECTION('center_axis',(0.,0.,-1.)); +#2300=DIRECTION('ref_axis',(1.,0.,0.)); +#2301=DIRECTION('',(0.,0.,-1.)); +#2302=DIRECTION('center_axis',(0.,0.,-1.)); +#2303=DIRECTION('ref_axis',(1.,0.,0.)); +#2304=DIRECTION('center_axis',(0.,0.,-1.)); +#2305=DIRECTION('ref_axis',(1.,0.,0.)); +#2306=DIRECTION('',(0.,0.,-1.)); +#2307=DIRECTION('center_axis',(0.,0.,-1.)); +#2308=DIRECTION('ref_axis',(1.,0.,0.)); +#2309=DIRECTION('center_axis',(0.,0.,-1.)); +#2310=DIRECTION('ref_axis',(1.,0.,0.)); +#2311=DIRECTION('',(0.,0.,-1.)); +#2312=DIRECTION('center_axis',(0.,0.,-1.)); +#2313=DIRECTION('ref_axis',(1.,0.,0.)); +#2314=DIRECTION('center_axis',(0.,0.,-1.)); +#2315=DIRECTION('ref_axis',(1.,0.,0.)); +#2316=DIRECTION('',(0.,0.,-1.)); +#2317=DIRECTION('center_axis',(0.,0.,-1.)); +#2318=DIRECTION('ref_axis',(1.,0.,0.)); +#2319=DIRECTION('center_axis',(0.,0.,-1.)); +#2320=DIRECTION('ref_axis',(1.,0.,0.)); +#2321=DIRECTION('',(0.,0.,-1.)); +#2322=DIRECTION('center_axis',(0.,0.,-1.)); +#2323=DIRECTION('ref_axis',(1.,0.,0.)); +#2324=DIRECTION('center_axis',(0.,0.,-1.)); +#2325=DIRECTION('ref_axis',(1.,0.,0.)); +#2326=DIRECTION('',(0.,0.,-1.)); +#2327=DIRECTION('center_axis',(0.,0.,-1.)); +#2328=DIRECTION('ref_axis',(1.,0.,0.)); +#2329=DIRECTION('center_axis',(0.,0.,-1.)); +#2330=DIRECTION('ref_axis',(1.,0.,0.)); +#2331=DIRECTION('',(0.,0.,-1.)); +#2332=DIRECTION('center_axis',(0.,0.,-1.)); +#2333=DIRECTION('ref_axis',(1.,0.,0.)); +#2334=DIRECTION('center_axis',(0.,0.,-1.)); +#2335=DIRECTION('ref_axis',(1.,0.,0.)); +#2336=DIRECTION('',(0.,0.,-1.)); +#2337=DIRECTION('center_axis',(0.,0.,-1.)); +#2338=DIRECTION('ref_axis',(1.,0.,0.)); +#2339=DIRECTION('center_axis',(0.,0.,-1.)); +#2340=DIRECTION('ref_axis',(1.,0.,0.)); +#2341=DIRECTION('',(0.,0.,-1.)); +#2342=DIRECTION('center_axis',(0.,0.,-1.)); +#2343=DIRECTION('ref_axis',(1.,0.,0.)); +#2344=DIRECTION('center_axis',(0.,0.,-1.)); +#2345=DIRECTION('ref_axis',(1.,0.,0.)); +#2346=DIRECTION('',(0.,0.,-1.)); +#2347=DIRECTION('center_axis',(0.,0.,-1.)); +#2348=DIRECTION('ref_axis',(1.,0.,0.)); +#2349=DIRECTION('center_axis',(0.,0.,-1.)); +#2350=DIRECTION('ref_axis',(1.,0.,0.)); +#2351=DIRECTION('',(0.,0.,-1.)); +#2352=DIRECTION('center_axis',(0.,0.,-1.)); +#2353=DIRECTION('ref_axis',(1.,0.,0.)); +#2354=DIRECTION('center_axis',(0.,0.,-1.)); +#2355=DIRECTION('ref_axis',(1.,0.,0.)); +#2356=DIRECTION('',(0.,0.,-1.)); +#2357=DIRECTION('center_axis',(0.,0.,-1.)); +#2358=DIRECTION('ref_axis',(1.,0.,0.)); +#2359=DIRECTION('center_axis',(0.,0.,-1.)); +#2360=DIRECTION('ref_axis',(1.,0.,0.)); +#2361=DIRECTION('',(0.,0.,-1.)); +#2362=DIRECTION('center_axis',(0.,0.,-1.)); +#2363=DIRECTION('ref_axis',(1.,0.,0.)); +#2364=DIRECTION('center_axis',(0.,0.,-1.)); +#2365=DIRECTION('ref_axis',(1.,0.,0.)); +#2366=DIRECTION('',(0.,0.,-1.)); +#2367=DIRECTION('center_axis',(0.,0.,-1.)); +#2368=DIRECTION('ref_axis',(1.,0.,0.)); +#2369=DIRECTION('center_axis',(0.,0.,-1.)); +#2370=DIRECTION('ref_axis',(1.,0.,0.)); +#2371=DIRECTION('',(0.,0.,-1.)); +#2372=DIRECTION('center_axis',(0.,0.,-1.)); +#2373=DIRECTION('ref_axis',(1.,0.,0.)); +#2374=DIRECTION('center_axis',(0.,0.,-1.)); +#2375=DIRECTION('ref_axis',(1.,0.,0.)); +#2376=DIRECTION('',(0.,0.,-1.)); +#2377=DIRECTION('center_axis',(0.,0.,-1.)); +#2378=DIRECTION('ref_axis',(1.,0.,0.)); +#2379=DIRECTION('center_axis',(0.,0.,-1.)); +#2380=DIRECTION('ref_axis',(1.,0.,0.)); +#2381=DIRECTION('',(0.,0.,-1.)); +#2382=DIRECTION('center_axis',(0.,0.,-1.)); +#2383=DIRECTION('ref_axis',(1.,0.,0.)); +#2384=DIRECTION('center_axis',(0.,0.,-1.)); +#2385=DIRECTION('ref_axis',(1.,0.,0.)); +#2386=DIRECTION('',(0.,0.,-1.)); +#2387=DIRECTION('center_axis',(0.,0.,-1.)); +#2388=DIRECTION('ref_axis',(1.,0.,0.)); +#2389=DIRECTION('center_axis',(0.,0.,-1.)); +#2390=DIRECTION('ref_axis',(1.,0.,0.)); +#2391=DIRECTION('',(0.,0.,-1.)); +#2392=DIRECTION('center_axis',(0.,0.,-1.)); +#2393=DIRECTION('ref_axis',(1.,0.,0.)); +#2394=DIRECTION('center_axis',(0.,0.,-1.)); +#2395=DIRECTION('ref_axis',(1.,0.,0.)); +#2396=DIRECTION('',(0.,0.,-1.)); +#2397=DIRECTION('center_axis',(0.,0.,-1.)); +#2398=DIRECTION('ref_axis',(1.,0.,0.)); +#2399=DIRECTION('center_axis',(0.,0.,-1.)); +#2400=DIRECTION('ref_axis',(1.,0.,0.)); +#2401=DIRECTION('',(0.,0.,-1.)); +#2402=DIRECTION('center_axis',(0.,0.,-1.)); +#2403=DIRECTION('ref_axis',(1.,0.,0.)); +#2404=DIRECTION('center_axis',(0.,0.,-1.)); +#2405=DIRECTION('ref_axis',(1.,0.,0.)); +#2406=DIRECTION('',(0.,0.,-1.)); +#2407=DIRECTION('center_axis',(0.,0.,-1.)); +#2408=DIRECTION('ref_axis',(1.,0.,0.)); +#2409=DIRECTION('center_axis',(0.,0.,-1.)); +#2410=DIRECTION('ref_axis',(1.,0.,0.)); +#2411=DIRECTION('',(0.,0.,-1.)); +#2412=DIRECTION('center_axis',(0.,0.,-1.)); +#2413=DIRECTION('ref_axis',(1.,0.,0.)); +#2414=DIRECTION('center_axis',(0.,0.,-1.)); +#2415=DIRECTION('ref_axis',(1.,0.,0.)); +#2416=DIRECTION('',(0.,0.,-1.)); +#2417=DIRECTION('center_axis',(0.,0.,-1.)); +#2418=DIRECTION('ref_axis',(1.,0.,0.)); +#2419=DIRECTION('center_axis',(0.,0.,-1.)); +#2420=DIRECTION('ref_axis',(1.,0.,0.)); +#2421=DIRECTION('',(0.,0.,-1.)); +#2422=DIRECTION('center_axis',(0.,0.,-1.)); +#2423=DIRECTION('ref_axis',(1.,0.,0.)); +#2424=DIRECTION('center_axis',(0.,0.,-1.)); +#2425=DIRECTION('ref_axis',(1.,0.,0.)); +#2426=DIRECTION('',(0.,0.,-1.)); +#2427=DIRECTION('center_axis',(0.,0.,-1.)); +#2428=DIRECTION('ref_axis',(1.,0.,0.)); +#2429=DIRECTION('center_axis',(0.,0.,-1.)); +#2430=DIRECTION('ref_axis',(1.,0.,0.)); +#2431=DIRECTION('',(0.,0.,-1.)); +#2432=DIRECTION('center_axis',(0.,0.,-1.)); +#2433=DIRECTION('ref_axis',(1.,0.,0.)); +#2434=DIRECTION('center_axis',(0.,0.,-1.)); +#2435=DIRECTION('ref_axis',(1.,0.,0.)); +#2436=DIRECTION('',(0.,0.,-1.)); +#2437=DIRECTION('center_axis',(0.,0.,-1.)); +#2438=DIRECTION('ref_axis',(1.,0.,0.)); +#2439=DIRECTION('center_axis',(0.,0.,-1.)); +#2440=DIRECTION('ref_axis',(1.,0.,0.)); +#2441=DIRECTION('',(0.,0.,-1.)); +#2442=DIRECTION('center_axis',(0.,0.,-1.)); +#2443=DIRECTION('ref_axis',(1.,0.,0.)); +#2444=DIRECTION('center_axis',(0.,0.,-1.)); +#2445=DIRECTION('ref_axis',(1.,0.,0.)); +#2446=DIRECTION('',(0.,0.,-1.)); +#2447=DIRECTION('center_axis',(0.,0.,-1.)); +#2448=DIRECTION('ref_axis',(1.,0.,0.)); +#2449=DIRECTION('center_axis',(0.,0.,-1.)); +#2450=DIRECTION('ref_axis',(1.,0.,0.)); +#2451=DIRECTION('',(0.,0.,-1.)); +#2452=DIRECTION('center_axis',(0.,0.,-1.)); +#2453=DIRECTION('ref_axis',(1.,0.,0.)); +#2454=DIRECTION('center_axis',(0.,0.,-1.)); +#2455=DIRECTION('ref_axis',(1.,0.,0.)); +#2456=DIRECTION('',(0.,0.,-1.)); +#2457=DIRECTION('center_axis',(0.,0.,-1.)); +#2458=DIRECTION('ref_axis',(1.,0.,0.)); +#2459=DIRECTION('center_axis',(0.,0.,-1.)); +#2460=DIRECTION('ref_axis',(1.,0.,0.)); +#2461=DIRECTION('',(0.,0.,-1.)); +#2462=DIRECTION('center_axis',(0.,0.,-1.)); +#2463=DIRECTION('ref_axis',(1.,0.,0.)); +#2464=DIRECTION('center_axis',(0.,0.,-1.)); +#2465=DIRECTION('ref_axis',(1.,0.,0.)); +#2466=DIRECTION('',(0.,0.,-1.)); +#2467=DIRECTION('center_axis',(0.,-1.,0.)); +#2468=DIRECTION('ref_axis',(1.,0.,0.)); +#2469=DIRECTION('',(1.,0.,0.)); +#2470=DIRECTION('center_axis',(0.,1.,0.)); +#2471=DIRECTION('ref_axis',(-1.,0.,0.)); +#2472=DIRECTION('',(-1.,0.,0.)); +#2473=DIRECTION('center_axis',(0.,0.,1.)); +#2474=DIRECTION('ref_axis',(1.,0.,0.)); +#2475=DIRECTION('axis',(0.,0.,1.)); +#2476=DIRECTION('refdir',(1.,0.,0.)); +#2477=DIRECTION('center_axis',(0.,0.,1.)); +#2478=DIRECTION('ref_axis',(0.707106781186548,0.707106781186548,0.)); +#2479=DIRECTION('center_axis',(0.,0.,-1.)); +#2480=DIRECTION('ref_axis',(0.707106781186548,0.707106781186548,0.)); +#2481=DIRECTION('',(0.,0.,-1.)); +#2482=DIRECTION('center_axis',(0.,0.,1.)); +#2483=DIRECTION('ref_axis',(0.707106781186548,0.707106781186548,0.)); +#2484=DIRECTION('',(0.,0.,1.)); +#2485=DIRECTION('center_axis',(0.,1.,0.)); +#2486=DIRECTION('ref_axis',(-1.,0.,0.)); +#2487=DIRECTION('',(-1.,0.,0.)); +#2488=DIRECTION('',(0.,0.,-1.)); +#2489=DIRECTION('',(-1.,0.,0.)); +#2490=DIRECTION('center_axis',(0.,0.,1.)); +#2491=DIRECTION('ref_axis',(-1.,0.,0.)); +#2492=DIRECTION('',(0.,1.,0.)); +#2493=DIRECTION('center_axis',(0.,0.,1.)); +#2494=DIRECTION('ref_axis',(0.707106781186548,-0.707106781186548,0.)); +#2495=DIRECTION('',(1.,0.,0.)); +#2496=DIRECTION('center_axis',(0.,0.,1.)); +#2497=DIRECTION('ref_axis',(-0.70710678118655,-0.707106781186545,0.)); +#2498=DIRECTION('',(-8.5265128291212E-16,-1.,0.)); +#2499=DIRECTION('center_axis',(0.,0.,1.)); +#2500=DIRECTION('ref_axis',(-0.707106781186548,0.707106781186548,0.)); +#2501=DIRECTION('center_axis',(0.,0.,1.)); +#2502=DIRECTION('ref_axis',(1.,0.,0.)); +#2503=DIRECTION('center_axis',(0.,0.,1.)); +#2504=DIRECTION('ref_axis',(1.,0.,0.)); +#2505=DIRECTION('center_axis',(0.,0.,1.)); +#2506=DIRECTION('ref_axis',(1.,0.,0.)); +#2507=DIRECTION('center_axis',(0.,0.,1.)); +#2508=DIRECTION('ref_axis',(1.,0.,0.)); +#2509=DIRECTION('center_axis',(0.,0.,1.)); +#2510=DIRECTION('ref_axis',(1.,0.,0.)); +#2511=DIRECTION('center_axis',(0.,0.,1.)); +#2512=DIRECTION('ref_axis',(1.,0.,0.)); +#2513=DIRECTION('center_axis',(0.,0.,1.)); +#2514=DIRECTION('ref_axis',(1.,0.,0.)); +#2515=DIRECTION('center_axis',(0.,0.,1.)); +#2516=DIRECTION('ref_axis',(1.,0.,0.)); +#2517=DIRECTION('center_axis',(0.,0.,1.)); +#2518=DIRECTION('ref_axis',(1.,0.,0.)); +#2519=DIRECTION('center_axis',(0.,0.,1.)); +#2520=DIRECTION('ref_axis',(1.,0.,0.)); +#2521=DIRECTION('center_axis',(0.,0.,1.)); +#2522=DIRECTION('ref_axis',(1.,0.,0.)); +#2523=DIRECTION('center_axis',(0.,0.,1.)); +#2524=DIRECTION('ref_axis',(1.,0.,0.)); +#2525=DIRECTION('center_axis',(0.,0.,1.)); +#2526=DIRECTION('ref_axis',(1.,0.,0.)); +#2527=DIRECTION('center_axis',(0.,0.,1.)); +#2528=DIRECTION('ref_axis',(1.,0.,0.)); +#2529=DIRECTION('center_axis',(0.,0.,1.)); +#2530=DIRECTION('ref_axis',(1.,0.,0.)); +#2531=DIRECTION('center_axis',(0.,0.,1.)); +#2532=DIRECTION('ref_axis',(1.,0.,0.)); +#2533=DIRECTION('center_axis',(0.,0.,-1.)); +#2534=DIRECTION('ref_axis',(0.707106781186554,0.707106781186541,0.)); +#2535=DIRECTION('',(1.,0.,0.)); +#2536=DIRECTION('center_axis',(0.,0.,-1.)); +#2537=DIRECTION('ref_axis',(-0.707106781186548,0.707106781186548,0.)); +#2538=DIRECTION('',(0.,1.,0.)); +#2539=DIRECTION('center_axis',(0.,0.,-1.)); +#2540=DIRECTION('ref_axis',(-0.707106781186548,-0.707106781186548,0.)); +#2541=DIRECTION('',(-1.,0.,0.)); +#2542=DIRECTION('center_axis',(0.,0.,-1.)); +#2543=DIRECTION('ref_axis',(0.707106781186548,-0.707106781186548,0.)); +#2544=DIRECTION('',(0.,-1.,0.)); +#2545=DIRECTION('center_axis',(0.,0.,1.)); +#2546=DIRECTION('ref_axis',(0.707106781186548,-0.707106781186548,0.)); +#2547=DIRECTION('center_axis',(0.,0.,-1.)); +#2548=DIRECTION('ref_axis',(0.707106781186548,-0.707106781186548,0.)); +#2549=DIRECTION('',(0.,0.,-1.)); +#2550=DIRECTION('',(0.,0.,1.)); +#2551=DIRECTION('center_axis',(0.,-1.,0.)); +#2552=DIRECTION('ref_axis',(1.,0.,0.)); +#2553=DIRECTION('',(1.,0.,0.)); +#2554=DIRECTION('',(0.,0.,1.)); +#2555=DIRECTION('center_axis',(0.,0.,1.)); +#2556=DIRECTION('ref_axis',(-0.70710678118655,-0.707106781186545,0.)); +#2557=DIRECTION('center_axis',(0.,0.,-1.)); +#2558=DIRECTION('ref_axis',(-0.70710678118655,-0.707106781186545,0.)); +#2559=DIRECTION('',(0.,0.,-1.)); +#2560=DIRECTION('center_axis',(0.,0.,1.)); +#2561=DIRECTION('ref_axis',(-0.707106781186548,0.707106781186548,0.)); +#2562=DIRECTION('center_axis',(0.,0.,-1.)); +#2563=DIRECTION('ref_axis',(-0.707106781186548,0.707106781186548,0.)); +#2564=DIRECTION('',(0.,0.,1.)); +#2565=DIRECTION('center_axis',(0.,0.,1.)); +#2566=DIRECTION('ref_axis',(-0.707106781186548,-0.707106781186548,0.)); +#2567=DIRECTION('',(0.,0.,1.)); +#2568=DIRECTION('center_axis',(0.,0.,1.)); +#2569=DIRECTION('ref_axis',(-0.707106781186548,-0.707106781186548,0.)); +#2570=DIRECTION('',(0.,0.,-1.)); +#2571=DIRECTION('center_axis',(1.,0.,0.)); +#2572=DIRECTION('ref_axis',(0.,1.,0.)); +#2573=DIRECTION('',(0.,0.,-1.)); +#2574=DIRECTION('',(0.,1.,0.)); +#2575=DIRECTION('center_axis',(0.,0.,1.)); +#2576=DIRECTION('ref_axis',(-0.707106781186548,0.707106781186548,0.)); +#2577=DIRECTION('',(0.,0.,1.)); +#2578=DIRECTION('center_axis',(0.,0.,1.)); +#2579=DIRECTION('ref_axis',(-0.707106781186548,0.707106781186548,0.)); +#2580=DIRECTION('center_axis',(0.,-1.,0.)); +#2581=DIRECTION('ref_axis',(1.,0.,0.)); +#2582=DIRECTION('',(0.,0.,-1.)); +#2583=DIRECTION('',(1.,0.,0.)); +#2584=DIRECTION('center_axis',(0.,0.,1.)); +#2585=DIRECTION('ref_axis',(0.707106781186554,0.707106781186541,0.)); +#2586=DIRECTION('',(0.,0.,1.)); +#2587=DIRECTION('center_axis',(0.,0.,1.)); +#2588=DIRECTION('ref_axis',(0.707106781186554,0.707106781186541,0.)); +#2589=DIRECTION('center_axis',(-1.,0.,0.)); +#2590=DIRECTION('ref_axis',(0.,-1.,0.)); +#2591=DIRECTION('',(0.,0.,-1.)); +#2592=DIRECTION('',(0.,-1.,0.)); +#2593=DIRECTION('center_axis',(0.,0.,1.)); +#2594=DIRECTION('ref_axis',(0.707106781186548,-0.707106781186548,0.)); +#2595=DIRECTION('',(0.,0.,1.)); +#2596=DIRECTION('center_axis',(0.,0.,1.)); +#2597=DIRECTION('ref_axis',(0.707106781186548,-0.707106781186548,0.)); +#2598=DIRECTION('center_axis',(0.,1.,0.)); +#2599=DIRECTION('ref_axis',(-1.,0.,0.)); +#2600=DIRECTION('',(-1.,0.,0.)); +#2601=DIRECTION('center_axis',(0.,0.,-1.)); +#2602=DIRECTION('ref_axis',(1.,0.,0.)); +#2603=DIRECTION('center_axis',(0.,0.,-1.)); +#2604=DIRECTION('ref_axis',(1.,0.,0.)); +#2605=DIRECTION('',(0.,0.,-1.)); +#2606=DIRECTION('center_axis',(0.,0.,-1.)); +#2607=DIRECTION('ref_axis',(1.,0.,0.)); +#2608=DIRECTION('center_axis',(0.,0.,-1.)); +#2609=DIRECTION('ref_axis',(1.,0.,0.)); +#2610=DIRECTION('',(0.,0.,-1.)); +#2611=DIRECTION('center_axis',(0.,0.,-1.)); +#2612=DIRECTION('ref_axis',(1.,0.,0.)); +#2613=DIRECTION('center_axis',(0.,0.,-1.)); +#2614=DIRECTION('ref_axis',(1.,0.,0.)); +#2615=DIRECTION('',(0.,0.,-1.)); +#2616=DIRECTION('center_axis',(0.,0.,-1.)); +#2617=DIRECTION('ref_axis',(1.,0.,0.)); +#2618=DIRECTION('center_axis',(0.,0.,-1.)); +#2619=DIRECTION('ref_axis',(1.,0.,0.)); +#2620=DIRECTION('',(0.,0.,-1.)); +#2621=DIRECTION('center_axis',(0.,0.,-1.)); +#2622=DIRECTION('ref_axis',(1.,0.,0.)); +#2623=DIRECTION('center_axis',(0.,0.,-1.)); +#2624=DIRECTION('ref_axis',(1.,0.,0.)); +#2625=DIRECTION('',(0.,0.,-1.)); +#2626=DIRECTION('center_axis',(0.,0.,-1.)); +#2627=DIRECTION('ref_axis',(1.,0.,0.)); +#2628=DIRECTION('center_axis',(0.,0.,-1.)); +#2629=DIRECTION('ref_axis',(1.,0.,0.)); +#2630=DIRECTION('',(0.,0.,-1.)); +#2631=DIRECTION('center_axis',(0.,0.,-1.)); +#2632=DIRECTION('ref_axis',(1.,0.,0.)); +#2633=DIRECTION('center_axis',(0.,0.,-1.)); +#2634=DIRECTION('ref_axis',(1.,0.,0.)); +#2635=DIRECTION('',(0.,0.,-1.)); +#2636=DIRECTION('center_axis',(0.,0.,-1.)); +#2637=DIRECTION('ref_axis',(1.,0.,0.)); +#2638=DIRECTION('center_axis',(0.,0.,-1.)); +#2639=DIRECTION('ref_axis',(1.,0.,0.)); +#2640=DIRECTION('',(0.,0.,-1.)); +#2641=DIRECTION('center_axis',(0.,0.,-1.)); +#2642=DIRECTION('ref_axis',(1.,0.,0.)); +#2643=DIRECTION('center_axis',(0.,0.,-1.)); +#2644=DIRECTION('ref_axis',(1.,0.,0.)); +#2645=DIRECTION('',(0.,0.,-1.)); +#2646=DIRECTION('center_axis',(0.,0.,-1.)); +#2647=DIRECTION('ref_axis',(1.,0.,0.)); +#2648=DIRECTION('center_axis',(0.,0.,-1.)); +#2649=DIRECTION('ref_axis',(1.,0.,0.)); +#2650=DIRECTION('',(0.,0.,-1.)); +#2651=DIRECTION('center_axis',(0.,0.,-1.)); +#2652=DIRECTION('ref_axis',(1.,0.,0.)); +#2653=DIRECTION('center_axis',(0.,0.,-1.)); +#2654=DIRECTION('ref_axis',(1.,0.,0.)); +#2655=DIRECTION('',(0.,0.,-1.)); +#2656=DIRECTION('center_axis',(0.,0.,-1.)); +#2657=DIRECTION('ref_axis',(1.,0.,0.)); +#2658=DIRECTION('center_axis',(0.,0.,-1.)); +#2659=DIRECTION('ref_axis',(1.,0.,0.)); +#2660=DIRECTION('',(0.,0.,-1.)); +#2661=DIRECTION('center_axis',(0.,0.,-1.)); +#2662=DIRECTION('ref_axis',(1.,0.,0.)); +#2663=DIRECTION('center_axis',(0.,0.,-1.)); +#2664=DIRECTION('ref_axis',(1.,0.,0.)); +#2665=DIRECTION('',(0.,0.,-1.)); +#2666=DIRECTION('center_axis',(0.,0.,-1.)); +#2667=DIRECTION('ref_axis',(1.,0.,0.)); +#2668=DIRECTION('center_axis',(0.,0.,-1.)); +#2669=DIRECTION('ref_axis',(1.,0.,0.)); +#2670=DIRECTION('',(0.,0.,-1.)); +#2671=DIRECTION('center_axis',(0.,0.,-1.)); +#2672=DIRECTION('ref_axis',(1.,0.,0.)); +#2673=DIRECTION('center_axis',(0.,0.,-1.)); +#2674=DIRECTION('ref_axis',(1.,0.,0.)); +#2675=DIRECTION('',(0.,0.,-1.)); +#2676=DIRECTION('center_axis',(0.,0.,-1.)); +#2677=DIRECTION('ref_axis',(1.,0.,0.)); +#2678=DIRECTION('center_axis',(0.,0.,-1.)); +#2679=DIRECTION('ref_axis',(1.,0.,0.)); +#2680=DIRECTION('',(0.,0.,-1.)); +#2681=DIRECTION('center_axis',(-1.,8.5265128291212E-16,0.)); +#2682=DIRECTION('ref_axis',(-8.5265128291212E-16,-1.,0.)); +#2683=DIRECTION('',(-8.5265128291212E-16,-1.,0.)); +#2684=DIRECTION('center_axis',(1.,0.,0.)); +#2685=DIRECTION('ref_axis',(0.,1.,0.)); +#2686=DIRECTION('',(0.,1.,0.)); +#2687=DIRECTION('center_axis',(0.,0.,1.)); +#2688=DIRECTION('ref_axis',(1.,0.,0.)); +#2689=DIRECTION('axis',(0.,0.,1.)); +#2690=DIRECTION('refdir',(1.,0.,0.)); +#2691=DIRECTION('center_axis',(0.,0.,-1.)); +#2692=DIRECTION('ref_axis',(1.,0.,0.)); +#2693=DIRECTION('center_axis',(0.,0.,-1.)); +#2694=DIRECTION('ref_axis',(1.,0.,0.)); +#2695=DIRECTION('',(-0.242535625036328,-2.97020476879942E-17,-0.970142500145333)); +#2696=DIRECTION('center_axis',(0.,0.,1.)); +#2697=DIRECTION('ref_axis',(1.,0.,0.)); +#2698=DIRECTION('center_axis',(0.,0.,1.)); +#2699=DIRECTION('ref_axis',(1.,0.,0.)); +#2700=DIRECTION('',(0.,0.,-1.)); +#2701=DIRECTION('center_axis',(0.,0.,-1.)); +#2702=DIRECTION('ref_axis',(1.,0.,0.)); +#2703=DIRECTION('center_axis',(0.,0.,-1.)); +#2704=DIRECTION('ref_axis',(1.,0.,0.)); +#2705=DIRECTION('center_axis',(0.,0.,-1.)); +#2706=DIRECTION('ref_axis',(1.,0.,0.)); +#2707=DIRECTION('center_axis',(0.,0.,-1.)); +#2708=DIRECTION('ref_axis',(-1.,0.,0.)); +#2709=DIRECTION('center_axis',(0.,0.,1.)); +#2710=DIRECTION('ref_axis',(1.,0.,0.)); +#2711=DIRECTION('center_axis',(0.,-1.,0.)); +#2712=DIRECTION('ref_axis',(1.,0.,0.)); +#2713=DIRECTION('center_axis',(0.,0.,-1.)); +#2714=DIRECTION('ref_axis',(1.,0.,0.)); +#2715=DIRECTION('',(0.,0.,1.)); +#2716=DIRECTION('',(1.,0.,0.)); +#2717=DIRECTION('',(0.,0.,1.)); +#2718=DIRECTION('',(1.,0.,0.)); +#2719=DIRECTION('',(0.,0.,1.)); +#2720=DIRECTION('',(1.,0.,0.)); +#2721=DIRECTION('',(0.,0.,1.)); +#2722=DIRECTION('',(1.,0.,0.)); +#2723=DIRECTION('',(0.,0.,1.)); +#2724=DIRECTION('',(1.,0.,0.)); +#2725=DIRECTION('',(0.,0.,1.)); +#2726=DIRECTION('',(1.,0.,0.)); +#2727=CARTESIAN_POINT('',(0.,0.,0.)); +#2728=CARTESIAN_POINT('',(0.,0.,0.)); +#2729=CARTESIAN_POINT('Origin',(-66.5,56.5,0.)); +#2730=CARTESIAN_POINT('',(-72.5,56.5,3.)); +#2731=CARTESIAN_POINT('',(-66.5,62.5,3.)); +#2732=CARTESIAN_POINT('Origin',(-66.5,56.5,3.)); +#2733=CARTESIAN_POINT('',(-66.5,62.5,0.)); +#2734=CARTESIAN_POINT('',(-66.5,62.5,0.)); +#2735=CARTESIAN_POINT('',(-72.5,56.5,0.)); +#2736=CARTESIAN_POINT('Origin',(-66.5,56.5,0.)); +#2737=CARTESIAN_POINT('',(-72.5,56.5,0.)); +#2738=CARTESIAN_POINT('Origin',(-72.5,62.5,0.)); +#2739=CARTESIAN_POINT('',(-72.5000000000001,-56.5,0.)); +#2740=CARTESIAN_POINT('',(-72.5,31.25,0.)); +#2741=CARTESIAN_POINT('',(-72.5000000000001,-56.5,3.)); +#2742=CARTESIAN_POINT('',(-72.5000000000001,-56.5,0.)); +#2743=CARTESIAN_POINT('',(-72.5,31.25,3.)); +#2744=CARTESIAN_POINT('Origin',(-2.66453525910038E-14,-3.5527136788005E-14, +0.)); +#2745=CARTESIAN_POINT('',(66.5,62.5,0.)); +#2746=CARTESIAN_POINT('',(62.5,62.5,0.)); +#2747=CARTESIAN_POINT('',(72.5,56.5,0.)); +#2748=CARTESIAN_POINT('Origin',(66.5,56.5,0.)); +#2749=CARTESIAN_POINT('',(72.5,-56.5,0.)); +#2750=CARTESIAN_POINT('',(72.5,-31.25,0.)); +#2751=CARTESIAN_POINT('',(66.5,-62.5,0.)); +#2752=CARTESIAN_POINT('Origin',(66.5,-56.5,0.)); +#2753=CARTESIAN_POINT('',(-66.5000000000001,-62.5,0.)); +#2754=CARTESIAN_POINT('',(-62.5000000000001,-62.5,0.)); +#2755=CARTESIAN_POINT('Origin',(-66.5000000000001,-56.5,0.)); +#2756=CARTESIAN_POINT('',(-69.25,-1.5757435534603E-14,0.)); +#2757=CARTESIAN_POINT('Origin',(-67.5,-1.55431223447522E-14,0.)); +#2758=CARTESIAN_POINT('',(65.75,-2.01983276331036E-14,0.)); +#2759=CARTESIAN_POINT('Origin',(67.5,-1.99840144432528E-14,0.)); +#2760=CARTESIAN_POINT('',(57.75,-58.75,0.)); +#2761=CARTESIAN_POINT('Origin',(58.75,-58.75,0.)); +#2762=CARTESIAN_POINT('',(-59.75,58.75,0.)); +#2763=CARTESIAN_POINT('Origin',(-58.75,58.75,0.)); +#2764=CARTESIAN_POINT('',(57.75,58.75,0.)); +#2765=CARTESIAN_POINT('Origin',(58.75,58.75,0.)); +#2766=CARTESIAN_POINT('',(-59.75,-58.75,0.)); +#2767=CARTESIAN_POINT('Origin',(-58.7500000000001,-58.75,0.)); +#2768=CARTESIAN_POINT('',(-0.811500000000044,-52.5,0.)); +#2769=CARTESIAN_POINT('Origin',(-4.44089209850063E-14,-52.5,0.)); +#2770=CARTESIAN_POINT('',(-0.811500000000027,52.5,0.)); +#2771=CARTESIAN_POINT('Origin',(-2.66453525910038E-14,52.5,0.)); +#2772=CARTESIAN_POINT('',(51.6885,-52.5,0.)); +#2773=CARTESIAN_POINT('Origin',(52.5,-52.5,0.)); +#2774=CARTESIAN_POINT('',(-53.3115000000001,52.5,0.)); +#2775=CARTESIAN_POINT('Origin',(-52.5000000000001,52.5,0.)); +#2776=CARTESIAN_POINT('',(51.6885,52.5,0.)); +#2777=CARTESIAN_POINT('Origin',(52.5,52.5,0.)); +#2778=CARTESIAN_POINT('',(-53.3115000000001,-52.5,0.)); +#2779=CARTESIAN_POINT('Origin',(-52.5000000000001,-52.5,0.)); +#2780=CARTESIAN_POINT('',(51.6885,1.76641883062517E-14,0.)); +#2781=CARTESIAN_POINT('Origin',(52.5,1.77635683940025E-14,0.)); +#2782=CARTESIAN_POINT('',(-53.3115000000001,8.78240410925044E-15,0.)); +#2783=CARTESIAN_POINT('Origin',(-52.5000000000001,8.88178419700125E-15, +0.)); +#2784=CARTESIAN_POINT('',(39.1885,40.,0.)); +#2785=CARTESIAN_POINT('Origin',(40.,40.,0.)); +#2786=CARTESIAN_POINT('',(19.1885,40.,0.)); +#2787=CARTESIAN_POINT('Origin',(20.,40.,0.)); +#2788=CARTESIAN_POINT('',(-0.8115,40.,0.)); +#2789=CARTESIAN_POINT('Origin',(0.,40.,0.)); +#2790=CARTESIAN_POINT('',(-20.8115,40.,0.)); +#2791=CARTESIAN_POINT('Origin',(-20.,40.,0.)); +#2792=CARTESIAN_POINT('',(-40.8115,40.,0.)); +#2793=CARTESIAN_POINT('Origin',(-40.,40.,0.)); +#2794=CARTESIAN_POINT('',(39.1885,20.,0.)); +#2795=CARTESIAN_POINT('Origin',(40.,20.,0.)); +#2796=CARTESIAN_POINT('',(19.1885,20.,0.)); +#2797=CARTESIAN_POINT('Origin',(20.,20.,0.)); +#2798=CARTESIAN_POINT('',(-0.8115,20.,0.)); +#2799=CARTESIAN_POINT('Origin',(0.,20.,0.)); +#2800=CARTESIAN_POINT('',(-20.8115,20.,0.)); +#2801=CARTESIAN_POINT('Origin',(-20.,20.,0.)); +#2802=CARTESIAN_POINT('',(-40.8115,20.,0.)); +#2803=CARTESIAN_POINT('Origin',(-40.,20.,0.)); +#2804=CARTESIAN_POINT('',(39.1885,-9.93800877508077E-17,0.)); +#2805=CARTESIAN_POINT('Origin',(40.,0.,0.)); +#2806=CARTESIAN_POINT('',(19.1885,-9.93800877508077E-17,0.)); +#2807=CARTESIAN_POINT('Origin',(20.,0.,0.)); +#2808=CARTESIAN_POINT('',(-20.8115,-9.93800877508077E-17,0.)); +#2809=CARTESIAN_POINT('Origin',(-20.,0.,0.)); +#2810=CARTESIAN_POINT('',(-40.8115,-9.93800877508077E-17,0.)); +#2811=CARTESIAN_POINT('Origin',(-40.,0.,0.)); +#2812=CARTESIAN_POINT('',(39.1885,-20.,0.)); +#2813=CARTESIAN_POINT('Origin',(40.,-20.,0.)); +#2814=CARTESIAN_POINT('',(19.1885,-20.,0.)); +#2815=CARTESIAN_POINT('Origin',(20.,-20.,0.)); +#2816=CARTESIAN_POINT('',(-0.8115,-20.,0.)); +#2817=CARTESIAN_POINT('Origin',(0.,-20.,0.)); +#2818=CARTESIAN_POINT('',(-20.8115,-20.,0.)); +#2819=CARTESIAN_POINT('Origin',(-20.,-20.,0.)); +#2820=CARTESIAN_POINT('',(-40.8115,-20.,0.)); +#2821=CARTESIAN_POINT('Origin',(-40.,-20.,0.)); +#2822=CARTESIAN_POINT('',(39.1885,-40.,0.)); +#2823=CARTESIAN_POINT('Origin',(40.,-40.,0.)); +#2824=CARTESIAN_POINT('',(19.1885,-40.,0.)); +#2825=CARTESIAN_POINT('Origin',(20.,-40.,0.)); +#2826=CARTESIAN_POINT('',(-0.8115,-40.,0.)); +#2827=CARTESIAN_POINT('Origin',(0.,-40.,0.)); +#2828=CARTESIAN_POINT('',(-20.8115,-40.,0.)); +#2829=CARTESIAN_POINT('Origin',(-20.,-40.,0.)); +#2830=CARTESIAN_POINT('',(-40.8115,-40.,0.)); +#2831=CARTESIAN_POINT('Origin',(-40.,-40.,0.)); +#2832=CARTESIAN_POINT('',(-0.8115,-9.93800877508077E-17,0.)); +#2833=CARTESIAN_POINT('Origin',(0.,0.,0.)); +#2834=CARTESIAN_POINT('Origin',(66.5,56.5,0.)); +#2835=CARTESIAN_POINT('',(66.5,62.5,3.)); +#2836=CARTESIAN_POINT('',(72.5,56.5,3.)); +#2837=CARTESIAN_POINT('Origin',(66.5,56.5,3.)); +#2838=CARTESIAN_POINT('',(72.5,56.5,0.)); +#2839=CARTESIAN_POINT('',(66.5,62.5,0.)); +#2840=CARTESIAN_POINT('Origin',(72.5,-62.5,0.)); +#2841=CARTESIAN_POINT('',(72.5,-56.5,3.)); +#2842=CARTESIAN_POINT('',(72.5,-31.25,3.)); +#2843=CARTESIAN_POINT('',(72.5,-56.5,0.)); +#2844=CARTESIAN_POINT('Origin',(66.5,-56.5,0.)); +#2845=CARTESIAN_POINT('',(66.5,-62.5,3.)); +#2846=CARTESIAN_POINT('Origin',(66.5,-56.5,3.)); +#2847=CARTESIAN_POINT('',(66.5,-62.5,0.)); +#2848=CARTESIAN_POINT('Origin',(-66.5000000000001,-56.5,0.)); +#2849=CARTESIAN_POINT('',(-66.5000000000001,-62.5,3.)); +#2850=CARTESIAN_POINT('Origin',(-66.5000000000001,-56.5,3.)); +#2851=CARTESIAN_POINT('',(-66.5000000000001,-62.5,0.)); +#2852=CARTESIAN_POINT('Origin',(-67.5,-1.55431223447522E-14,-17.)); +#2853=CARTESIAN_POINT('',(-69.25,-1.53288091549014E-14,3.)); +#2854=CARTESIAN_POINT('Origin',(-67.5,-1.55431223447522E-14,3.)); +#2855=CARTESIAN_POINT('',(-69.25,-1.53288091549014E-14,-17.)); +#2856=CARTESIAN_POINT('Origin',(67.5,-1.99840144432528E-14,-17.)); +#2857=CARTESIAN_POINT('',(65.75,-1.9769701253402E-14,3.)); +#2858=CARTESIAN_POINT('Origin',(67.5,-1.99840144432528E-14,3.)); +#2859=CARTESIAN_POINT('',(65.75,-1.9769701253402E-14,-17.)); +#2860=CARTESIAN_POINT('Origin',(58.75,-58.75,-14.)); +#2861=CARTESIAN_POINT('',(57.75,-58.75,3.)); +#2862=CARTESIAN_POINT('Origin',(58.75,-58.75,3.)); +#2863=CARTESIAN_POINT('',(57.75,-58.75,-14.)); +#2864=CARTESIAN_POINT('Origin',(-58.75,58.75,-14.)); +#2865=CARTESIAN_POINT('',(-59.75,58.75,3.)); +#2866=CARTESIAN_POINT('Origin',(-58.75,58.75,3.)); +#2867=CARTESIAN_POINT('',(-59.75,58.75,-14.)); +#2868=CARTESIAN_POINT('Origin',(58.75,58.75,-14.)); +#2869=CARTESIAN_POINT('',(57.75,58.75,3.)); +#2870=CARTESIAN_POINT('Origin',(58.75,58.75,3.)); +#2871=CARTESIAN_POINT('',(57.75,58.75,-14.)); +#2872=CARTESIAN_POINT('Origin',(-58.7500000000001,-58.75,-14.)); +#2873=CARTESIAN_POINT('',(-59.75,-58.75,3.)); +#2874=CARTESIAN_POINT('Origin',(-58.7500000000001,-58.75,3.)); +#2875=CARTESIAN_POINT('',(-59.75,-58.75,-14.)); +#2876=CARTESIAN_POINT('Origin',(-4.44089209850063E-14,-52.5,-17.)); +#2877=CARTESIAN_POINT('',(-0.811500000000044,-52.5,3.)); +#2878=CARTESIAN_POINT('Origin',(-4.44089209850063E-14,-52.5,3.)); +#2879=CARTESIAN_POINT('',(-0.811500000000044,-52.5,-17.)); +#2880=CARTESIAN_POINT('Origin',(-2.66453525910038E-14,52.5,-17.)); +#2881=CARTESIAN_POINT('',(-0.811500000000027,52.5,3.)); +#2882=CARTESIAN_POINT('Origin',(-2.66453525910038E-14,52.5,3.)); +#2883=CARTESIAN_POINT('',(-0.811500000000027,52.5,-17.)); +#2884=CARTESIAN_POINT('Origin',(52.5,-52.5,-17.)); +#2885=CARTESIAN_POINT('',(51.6885,-52.5,3.)); +#2886=CARTESIAN_POINT('Origin',(52.5,-52.5,3.)); +#2887=CARTESIAN_POINT('',(51.6885,-52.5,-17.)); +#2888=CARTESIAN_POINT('Origin',(-52.5000000000001,52.5,-17.)); +#2889=CARTESIAN_POINT('',(-53.3115000000001,52.5,3.)); +#2890=CARTESIAN_POINT('Origin',(-52.5000000000001,52.5,3.)); +#2891=CARTESIAN_POINT('',(-53.3115000000001,52.5,-17.)); +#2892=CARTESIAN_POINT('Origin',(52.5,52.5,-17.)); +#2893=CARTESIAN_POINT('',(51.6885,52.5,3.)); +#2894=CARTESIAN_POINT('Origin',(52.5,52.5,3.)); +#2895=CARTESIAN_POINT('',(51.6885,52.5,-17.)); +#2896=CARTESIAN_POINT('Origin',(-52.5000000000001,-52.5,-17.)); +#2897=CARTESIAN_POINT('',(-53.3115000000001,-52.5,3.)); +#2898=CARTESIAN_POINT('Origin',(-52.5000000000001,-52.5,3.)); +#2899=CARTESIAN_POINT('',(-53.3115000000001,-52.5,-17.)); +#2900=CARTESIAN_POINT('Origin',(52.5,1.77635683940025E-14,-17.)); +#2901=CARTESIAN_POINT('',(51.6885,1.78629484817533E-14,3.)); +#2902=CARTESIAN_POINT('Origin',(52.5,1.77635683940025E-14,3.)); +#2903=CARTESIAN_POINT('',(51.6885,1.78629484817533E-14,-17.)); +#2904=CARTESIAN_POINT('Origin',(-52.5000000000001,8.88178419700125E-15, +-17.)); +#2905=CARTESIAN_POINT('',(-53.3115000000001,8.98116428475206E-15,3.)); +#2906=CARTESIAN_POINT('Origin',(-52.5000000000001,8.88178419700125E-15, +3.)); +#2907=CARTESIAN_POINT('',(-53.3115000000001,8.98116428475206E-15,-17.)); +#2908=CARTESIAN_POINT('Origin',(40.,40.,-17.)); +#2909=CARTESIAN_POINT('',(39.1885,40.,3.)); +#2910=CARTESIAN_POINT('Origin',(40.,40.,3.)); +#2911=CARTESIAN_POINT('',(39.1885,40.,-17.)); +#2912=CARTESIAN_POINT('Origin',(20.,40.,-17.)); +#2913=CARTESIAN_POINT('',(19.1885,40.,3.)); +#2914=CARTESIAN_POINT('Origin',(20.,40.,3.)); +#2915=CARTESIAN_POINT('',(19.1885,40.,-17.)); +#2916=CARTESIAN_POINT('Origin',(0.,40.,-17.)); +#2917=CARTESIAN_POINT('',(-0.8115,40.,3.)); +#2918=CARTESIAN_POINT('Origin',(0.,40.,3.)); +#2919=CARTESIAN_POINT('',(-0.8115,40.,-17.)); +#2920=CARTESIAN_POINT('Origin',(-20.,40.,-17.)); +#2921=CARTESIAN_POINT('',(-20.8115,40.,3.)); +#2922=CARTESIAN_POINT('Origin',(-20.,40.,3.)); +#2923=CARTESIAN_POINT('',(-20.8115,40.,-17.)); +#2924=CARTESIAN_POINT('Origin',(-40.,40.,-17.)); +#2925=CARTESIAN_POINT('',(-40.8115,40.,3.)); +#2926=CARTESIAN_POINT('Origin',(-40.,40.,3.)); +#2927=CARTESIAN_POINT('',(-40.8115,40.,-17.)); +#2928=CARTESIAN_POINT('Origin',(40.,20.,-17.)); +#2929=CARTESIAN_POINT('',(39.1885,20.,3.)); +#2930=CARTESIAN_POINT('Origin',(40.,20.,3.)); +#2931=CARTESIAN_POINT('',(39.1885,20.,-17.)); +#2932=CARTESIAN_POINT('Origin',(20.,20.,-17.)); +#2933=CARTESIAN_POINT('',(19.1885,20.,3.)); +#2934=CARTESIAN_POINT('Origin',(20.,20.,3.)); +#2935=CARTESIAN_POINT('',(19.1885,20.,-17.)); +#2936=CARTESIAN_POINT('Origin',(0.,20.,-17.)); +#2937=CARTESIAN_POINT('',(-0.8115,20.,3.)); +#2938=CARTESIAN_POINT('Origin',(0.,20.,3.)); +#2939=CARTESIAN_POINT('',(-0.8115,20.,-17.)); +#2940=CARTESIAN_POINT('Origin',(-20.,20.,-17.)); +#2941=CARTESIAN_POINT('',(-20.8115,20.,3.)); +#2942=CARTESIAN_POINT('Origin',(-20.,20.,3.)); +#2943=CARTESIAN_POINT('',(-20.8115,20.,-17.)); +#2944=CARTESIAN_POINT('Origin',(-40.,20.,-17.)); +#2945=CARTESIAN_POINT('',(-40.8115,20.,3.)); +#2946=CARTESIAN_POINT('Origin',(-40.,20.,3.)); +#2947=CARTESIAN_POINT('',(-40.8115,20.,-17.)); +#2948=CARTESIAN_POINT('Origin',(40.,0.,-17.)); +#2949=CARTESIAN_POINT('',(39.1885,9.93800877508077E-17,3.)); +#2950=CARTESIAN_POINT('Origin',(40.,0.,3.)); +#2951=CARTESIAN_POINT('',(39.1885,9.93800877508077E-17,-17.)); +#2952=CARTESIAN_POINT('Origin',(20.,0.,-17.)); +#2953=CARTESIAN_POINT('',(19.1885,9.93800877508077E-17,3.)); +#2954=CARTESIAN_POINT('Origin',(20.,0.,3.)); +#2955=CARTESIAN_POINT('',(19.1885,9.93800877508077E-17,-17.)); +#2956=CARTESIAN_POINT('Origin',(-20.,0.,-17.)); +#2957=CARTESIAN_POINT('',(-20.8115,9.93800877508077E-17,3.)); +#2958=CARTESIAN_POINT('Origin',(-20.,0.,3.)); +#2959=CARTESIAN_POINT('',(-20.8115,9.93800877508077E-17,-17.)); +#2960=CARTESIAN_POINT('Origin',(-40.,0.,-17.)); +#2961=CARTESIAN_POINT('',(-40.8115,9.93800877508077E-17,3.)); +#2962=CARTESIAN_POINT('Origin',(-40.,0.,3.)); +#2963=CARTESIAN_POINT('',(-40.8115,9.93800877508077E-17,-17.)); +#2964=CARTESIAN_POINT('Origin',(40.,-20.,-17.)); +#2965=CARTESIAN_POINT('',(39.1885,-20.,3.)); +#2966=CARTESIAN_POINT('Origin',(40.,-20.,3.)); +#2967=CARTESIAN_POINT('',(39.1885,-20.,-17.)); +#2968=CARTESIAN_POINT('Origin',(20.,-20.,-17.)); +#2969=CARTESIAN_POINT('',(19.1885,-20.,3.)); +#2970=CARTESIAN_POINT('Origin',(20.,-20.,3.)); +#2971=CARTESIAN_POINT('',(19.1885,-20.,-17.)); +#2972=CARTESIAN_POINT('Origin',(0.,-20.,-17.)); +#2973=CARTESIAN_POINT('',(-0.8115,-20.,3.)); +#2974=CARTESIAN_POINT('Origin',(0.,-20.,3.)); +#2975=CARTESIAN_POINT('',(-0.8115,-20.,-17.)); +#2976=CARTESIAN_POINT('Origin',(-20.,-20.,-17.)); +#2977=CARTESIAN_POINT('',(-20.8115,-20.,3.)); +#2978=CARTESIAN_POINT('Origin',(-20.,-20.,3.)); +#2979=CARTESIAN_POINT('',(-20.8115,-20.,-17.)); +#2980=CARTESIAN_POINT('Origin',(-40.,-20.,-17.)); +#2981=CARTESIAN_POINT('',(-40.8115,-20.,3.)); +#2982=CARTESIAN_POINT('Origin',(-40.,-20.,3.)); +#2983=CARTESIAN_POINT('',(-40.8115,-20.,-17.)); +#2984=CARTESIAN_POINT('Origin',(40.,-40.,-17.)); +#2985=CARTESIAN_POINT('',(39.1885,-40.,3.)); +#2986=CARTESIAN_POINT('Origin',(40.,-40.,3.)); +#2987=CARTESIAN_POINT('',(39.1885,-40.,-17.)); +#2988=CARTESIAN_POINT('Origin',(20.,-40.,-17.)); +#2989=CARTESIAN_POINT('',(19.1885,-40.,3.)); +#2990=CARTESIAN_POINT('Origin',(20.,-40.,3.)); +#2991=CARTESIAN_POINT('',(19.1885,-40.,-17.)); +#2992=CARTESIAN_POINT('Origin',(0.,-40.,-17.)); +#2993=CARTESIAN_POINT('',(-0.8115,-40.,3.)); +#2994=CARTESIAN_POINT('Origin',(0.,-40.,3.)); +#2995=CARTESIAN_POINT('',(-0.8115,-40.,-17.)); +#2996=CARTESIAN_POINT('Origin',(-20.,-40.,-17.)); +#2997=CARTESIAN_POINT('',(-20.8115,-40.,3.)); +#2998=CARTESIAN_POINT('Origin',(-20.,-40.,3.)); +#2999=CARTESIAN_POINT('',(-20.8115,-40.,-17.)); +#3000=CARTESIAN_POINT('Origin',(-40.,-40.,-17.)); +#3001=CARTESIAN_POINT('',(-40.8115,-40.,3.)); +#3002=CARTESIAN_POINT('Origin',(-40.,-40.,3.)); +#3003=CARTESIAN_POINT('',(-40.8115,-40.,-17.)); +#3004=CARTESIAN_POINT('Origin',(0.,0.,-17.)); +#3005=CARTESIAN_POINT('',(-0.8115,9.93800877508077E-17,3.)); +#3006=CARTESIAN_POINT('Origin',(0.,0.,3.)); +#3007=CARTESIAN_POINT('',(-0.8115,9.93800877508077E-17,-17.)); +#3008=CARTESIAN_POINT('Origin',(-62.5000000000001,-62.5,0.)); +#3009=CARTESIAN_POINT('',(-62.5000000000001,-62.5,3.)); +#3010=CARTESIAN_POINT('Origin',(62.5,62.5,0.)); +#3011=CARTESIAN_POINT('',(62.5,62.5,3.)); +#3012=CARTESIAN_POINT('Origin',(-2.66453525910038E-14,-3.5527136788005E-14, +3.)); +#3013=CARTESIAN_POINT('',(0.,0.,0.)); +#3014=CARTESIAN_POINT('Origin',(59.5,59.5,3.)); +#3015=CARTESIAN_POINT('',(59.5,62.5,6.)); +#3016=CARTESIAN_POINT('',(62.5,59.5,6.)); +#3017=CARTESIAN_POINT('Origin',(59.5,59.5,6.)); +#3018=CARTESIAN_POINT('',(62.5,59.5,3.)); +#3019=CARTESIAN_POINT('',(62.5,59.5,3.)); +#3020=CARTESIAN_POINT('',(59.5,62.5,3.)); +#3021=CARTESIAN_POINT('Origin',(59.5,59.5,3.)); +#3022=CARTESIAN_POINT('',(59.5,62.5,3.)); +#3023=CARTESIAN_POINT('Origin',(62.5,62.5,3.)); +#3024=CARTESIAN_POINT('',(-59.5,62.5,3.)); +#3025=CARTESIAN_POINT('',(62.5,62.5,3.)); +#3026=CARTESIAN_POINT('',(-59.5,62.5,6.)); +#3027=CARTESIAN_POINT('',(-59.5,62.5,3.)); +#3028=CARTESIAN_POINT('',(62.5,62.5,6.)); +#3029=CARTESIAN_POINT('Origin',(-2.66453525910038E-14,-3.5527136788005E-14, +3.)); +#3030=CARTESIAN_POINT('',(62.5,-59.5,3.)); +#3031=CARTESIAN_POINT('',(62.5,-62.5,3.)); +#3032=CARTESIAN_POINT('',(59.5,-62.5,3.)); +#3033=CARTESIAN_POINT('Origin',(59.5,-59.5,3.)); +#3034=CARTESIAN_POINT('',(-59.5000000000001,-62.5,3.)); +#3035=CARTESIAN_POINT('',(-62.5000000000001,-62.5,3.)); +#3036=CARTESIAN_POINT('',(-62.5000000000001,-59.5,3.)); +#3037=CARTESIAN_POINT('Origin',(-59.5000000000001,-59.5,3.)); +#3038=CARTESIAN_POINT('',(-62.5,59.5,3.)); +#3039=CARTESIAN_POINT('',(-62.5,62.5,3.)); +#3040=CARTESIAN_POINT('Origin',(-59.5,59.5,3.)); +#3041=CARTESIAN_POINT('',(57.75,-58.75,3.)); +#3042=CARTESIAN_POINT('Origin',(58.75,-58.75,3.)); +#3043=CARTESIAN_POINT('',(-59.75,58.75,3.)); +#3044=CARTESIAN_POINT('Origin',(-58.75,58.75,3.)); +#3045=CARTESIAN_POINT('',(57.75,58.75,3.)); +#3046=CARTESIAN_POINT('Origin',(58.75,58.75,3.)); +#3047=CARTESIAN_POINT('',(-59.75,-58.75,3.)); +#3048=CARTESIAN_POINT('Origin',(-58.7500000000001,-58.75,3.)); +#3049=CARTESIAN_POINT('',(-59.5615,-1.12016103340024E-14,3.)); +#3050=CARTESIAN_POINT('Origin',(-58.75,-1.11022302462516E-14,3.)); +#3051=CARTESIAN_POINT('',(-30.1865,-58.75,3.)); +#3052=CARTESIAN_POINT('Origin',(-29.375,-58.75,3.)); +#3053=CARTESIAN_POINT('',(28.5635,-58.75,3.)); +#3054=CARTESIAN_POINT('Origin',(29.375,-58.75,3.)); +#3055=CARTESIAN_POINT('',(57.9385,-1.34220563832527E-14,3.)); +#3056=CARTESIAN_POINT('Origin',(58.75,-1.33226762955019E-14,3.)); +#3057=CARTESIAN_POINT('',(28.5635,58.75,3.)); +#3058=CARTESIAN_POINT('Origin',(29.375,58.75,3.)); +#3059=CARTESIAN_POINT('',(-30.1865,58.75,3.)); +#3060=CARTESIAN_POINT('Origin',(-29.375,58.75,3.)); +#3061=CARTESIAN_POINT('',(-0.811499999999987,58.75,3.)); +#3062=CARTESIAN_POINT('Origin',(1.33226762955019E-14,58.75,3.)); +#3063=CARTESIAN_POINT('',(57.9385,29.375,3.)); +#3064=CARTESIAN_POINT('Origin',(58.75,29.375,3.)); +#3065=CARTESIAN_POINT('',(57.9385,-29.375,3.)); +#3066=CARTESIAN_POINT('Origin',(58.75,-29.375,3.)); +#3067=CARTESIAN_POINT('',(-0.811500000000027,-58.75,3.)); +#3068=CARTESIAN_POINT('Origin',(-2.66453525910038E-14,-58.75,3.)); +#3069=CARTESIAN_POINT('',(-59.5615,-29.375,3.)); +#3070=CARTESIAN_POINT('Origin',(-58.75,-29.375,3.)); +#3071=CARTESIAN_POINT('',(-59.5615,29.375,3.)); +#3072=CARTESIAN_POINT('Origin',(-58.75,29.375,3.)); +#3073=CARTESIAN_POINT('',(54.,55.,3.)); +#3074=CARTESIAN_POINT('',(55.,54.,3.)); +#3075=CARTESIAN_POINT('Origin',(54.,54.,3.)); +#3076=CARTESIAN_POINT('',(-54.,55.,3.)); +#3077=CARTESIAN_POINT('',(55.,55.,3.)); +#3078=CARTESIAN_POINT('',(-55.,54.,3.)); +#3079=CARTESIAN_POINT('Origin',(-54.,54.,3.)); +#3080=CARTESIAN_POINT('',(-55.,-54.,3.)); +#3081=CARTESIAN_POINT('',(-55.,55.,3.)); +#3082=CARTESIAN_POINT('',(-54.,-55.,3.)); +#3083=CARTESIAN_POINT('Origin',(-54.,-54.,3.)); +#3084=CARTESIAN_POINT('',(54.,-55.,3.)); +#3085=CARTESIAN_POINT('',(-55.,-55.,3.)); +#3086=CARTESIAN_POINT('',(55.,-54.,3.)); +#3087=CARTESIAN_POINT('Origin',(54.,-54.,3.)); +#3088=CARTESIAN_POINT('',(55.,-55.,3.)); +#3089=CARTESIAN_POINT('Origin',(59.5,-59.5,3.)); +#3090=CARTESIAN_POINT('',(62.5,-59.5,6.)); +#3091=CARTESIAN_POINT('',(59.5,-62.5,6.)); +#3092=CARTESIAN_POINT('Origin',(59.5,-59.5,6.)); +#3093=CARTESIAN_POINT('',(59.5,-62.5,3.)); +#3094=CARTESIAN_POINT('',(62.5,-59.5,3.)); +#3095=CARTESIAN_POINT('Origin',(-62.5000000000001,-62.5,3.)); +#3096=CARTESIAN_POINT('',(-59.5000000000001,-62.5,6.)); +#3097=CARTESIAN_POINT('',(-62.5000000000001,-62.5,6.)); +#3098=CARTESIAN_POINT('',(-59.5000000000001,-62.5,3.)); +#3099=CARTESIAN_POINT('Origin',(-59.5000000000001,-59.5,3.)); +#3100=CARTESIAN_POINT('',(-62.5000000000001,-59.5,6.)); +#3101=CARTESIAN_POINT('Origin',(-59.5000000000001,-59.5,6.)); +#3102=CARTESIAN_POINT('',(-62.5000000000001,-59.5,3.)); +#3103=CARTESIAN_POINT('Origin',(-59.5,59.5,3.)); +#3104=CARTESIAN_POINT('',(-62.5,59.5,6.)); +#3105=CARTESIAN_POINT('Origin',(-59.5,59.5,6.)); +#3106=CARTESIAN_POINT('',(-62.5,59.5,3.)); +#3107=CARTESIAN_POINT('Origin',(-54.,-54.,3.)); +#3108=CARTESIAN_POINT('',(-55.,-54.,6.)); +#3109=CARTESIAN_POINT('',(-55.,-54.,3.)); +#3110=CARTESIAN_POINT('',(-54.,-55.,6.)); +#3111=CARTESIAN_POINT('Origin',(-54.,-54.,6.)); +#3112=CARTESIAN_POINT('',(-54.,-55.,3.)); +#3113=CARTESIAN_POINT('Origin',(-55.,-55.,3.)); +#3114=CARTESIAN_POINT('',(-55.,54.,6.)); +#3115=CARTESIAN_POINT('',(-55.,54.,3.)); +#3116=CARTESIAN_POINT('',(-55.,55.,6.)); +#3117=CARTESIAN_POINT('Origin',(-54.,54.,3.)); +#3118=CARTESIAN_POINT('',(-54.,55.,6.)); +#3119=CARTESIAN_POINT('',(-54.,55.,3.)); +#3120=CARTESIAN_POINT('Origin',(-54.,54.,6.)); +#3121=CARTESIAN_POINT('Origin',(-55.,55.,3.)); +#3122=CARTESIAN_POINT('',(54.,55.,6.)); +#3123=CARTESIAN_POINT('',(54.,55.,3.)); +#3124=CARTESIAN_POINT('',(55.,55.,6.)); +#3125=CARTESIAN_POINT('Origin',(54.,54.,3.)); +#3126=CARTESIAN_POINT('',(55.,54.,6.)); +#3127=CARTESIAN_POINT('',(55.,54.,3.)); +#3128=CARTESIAN_POINT('Origin',(54.,54.,6.)); +#3129=CARTESIAN_POINT('Origin',(55.,55.,3.)); +#3130=CARTESIAN_POINT('',(55.,-54.,6.)); +#3131=CARTESIAN_POINT('',(55.,-54.,3.)); +#3132=CARTESIAN_POINT('',(55.,-55.,6.)); +#3133=CARTESIAN_POINT('Origin',(54.,-54.,3.)); +#3134=CARTESIAN_POINT('',(54.,-55.,6.)); +#3135=CARTESIAN_POINT('',(54.,-55.,3.)); +#3136=CARTESIAN_POINT('Origin',(54.,-54.,6.)); +#3137=CARTESIAN_POINT('Origin',(55.,-55.,3.)); +#3138=CARTESIAN_POINT('',(-55.,-55.,6.)); +#3139=CARTESIAN_POINT('Origin',(58.75,-58.75,-14.)); +#3140=CARTESIAN_POINT('',(57.75,-58.75,6.)); +#3141=CARTESIAN_POINT('Origin',(58.75,-58.75,6.)); +#3142=CARTESIAN_POINT('',(57.75,-58.75,-14.)); +#3143=CARTESIAN_POINT('Origin',(-58.75,58.75,-14.)); +#3144=CARTESIAN_POINT('',(-59.75,58.75,6.)); +#3145=CARTESIAN_POINT('Origin',(-58.75,58.75,6.)); +#3146=CARTESIAN_POINT('',(-59.75,58.75,-14.)); +#3147=CARTESIAN_POINT('Origin',(58.75,58.75,-14.)); +#3148=CARTESIAN_POINT('',(57.75,58.75,6.)); +#3149=CARTESIAN_POINT('Origin',(58.75,58.75,6.)); +#3150=CARTESIAN_POINT('',(57.75,58.75,-14.)); +#3151=CARTESIAN_POINT('Origin',(-58.7500000000001,-58.75,-14.)); +#3152=CARTESIAN_POINT('',(-59.75,-58.75,6.)); +#3153=CARTESIAN_POINT('Origin',(-58.7500000000001,-58.75,6.)); +#3154=CARTESIAN_POINT('',(-59.75,-58.75,-14.)); +#3155=CARTESIAN_POINT('Origin',(-58.75,-1.11022302462516E-14,-14.)); +#3156=CARTESIAN_POINT('',(-59.5615,-1.10028501585008E-14,6.)); +#3157=CARTESIAN_POINT('Origin',(-58.75,-1.11022302462516E-14,6.)); +#3158=CARTESIAN_POINT('',(-59.5615,-1.10028501585008E-14,-14.)); +#3159=CARTESIAN_POINT('Origin',(-29.375,-58.75,-14.)); +#3160=CARTESIAN_POINT('',(-30.1865,-58.75,6.)); +#3161=CARTESIAN_POINT('Origin',(-29.375,-58.75,6.)); +#3162=CARTESIAN_POINT('',(-30.1865,-58.75,-14.)); +#3163=CARTESIAN_POINT('Origin',(29.375,-58.75,-14.)); +#3164=CARTESIAN_POINT('',(28.5635,-58.75,6.)); +#3165=CARTESIAN_POINT('Origin',(29.375,-58.75,6.)); +#3166=CARTESIAN_POINT('',(28.5635,-58.75,-14.)); +#3167=CARTESIAN_POINT('Origin',(58.75,-1.33226762955019E-14,-14.)); +#3168=CARTESIAN_POINT('',(57.9385,-1.32232962077511E-14,6.)); +#3169=CARTESIAN_POINT('Origin',(58.75,-1.33226762955019E-14,6.)); +#3170=CARTESIAN_POINT('',(57.9385,-1.32232962077511E-14,-14.)); +#3171=CARTESIAN_POINT('Origin',(29.375,58.75,-14.)); +#3172=CARTESIAN_POINT('',(28.5635,58.75,6.)); +#3173=CARTESIAN_POINT('Origin',(29.375,58.75,6.)); +#3174=CARTESIAN_POINT('',(28.5635,58.75,-14.)); +#3175=CARTESIAN_POINT('Origin',(-29.375,58.75,-14.)); +#3176=CARTESIAN_POINT('',(-30.1865,58.75,6.)); +#3177=CARTESIAN_POINT('Origin',(-29.375,58.75,6.)); +#3178=CARTESIAN_POINT('',(-30.1865,58.75,-14.)); +#3179=CARTESIAN_POINT('Origin',(1.33226762955019E-14,58.75,-14.)); +#3180=CARTESIAN_POINT('',(-0.811499999999987,58.75,6.)); +#3181=CARTESIAN_POINT('Origin',(1.33226762955019E-14,58.75,6.)); +#3182=CARTESIAN_POINT('',(-0.811499999999987,58.75,-14.)); +#3183=CARTESIAN_POINT('Origin',(58.75,29.375,-14.)); +#3184=CARTESIAN_POINT('',(57.9385,29.375,6.)); +#3185=CARTESIAN_POINT('Origin',(58.75,29.375,6.)); +#3186=CARTESIAN_POINT('',(57.9385,29.375,-14.)); +#3187=CARTESIAN_POINT('Origin',(58.75,-29.375,-14.)); +#3188=CARTESIAN_POINT('',(57.9385,-29.375,6.)); +#3189=CARTESIAN_POINT('Origin',(58.75,-29.375,6.)); +#3190=CARTESIAN_POINT('',(57.9385,-29.375,-14.)); +#3191=CARTESIAN_POINT('Origin',(-2.66453525910038E-14,-58.75,-14.)); +#3192=CARTESIAN_POINT('',(-0.811500000000027,-58.75,6.)); +#3193=CARTESIAN_POINT('Origin',(-2.66453525910038E-14,-58.75,6.)); +#3194=CARTESIAN_POINT('',(-0.811500000000027,-58.75,-14.)); +#3195=CARTESIAN_POINT('Origin',(-58.75,-29.375,-14.)); +#3196=CARTESIAN_POINT('',(-59.5615,-29.375,6.)); +#3197=CARTESIAN_POINT('Origin',(-58.75,-29.375,6.)); +#3198=CARTESIAN_POINT('',(-59.5615,-29.375,-14.)); +#3199=CARTESIAN_POINT('Origin',(-58.75,29.375,-14.)); +#3200=CARTESIAN_POINT('',(-59.5615,29.375,6.)); +#3201=CARTESIAN_POINT('Origin',(-58.75,29.375,6.)); +#3202=CARTESIAN_POINT('',(-59.5615,29.375,-14.)); +#3203=CARTESIAN_POINT('Origin',(-62.5,62.5,3.)); +#3204=CARTESIAN_POINT('',(-62.5,62.5,6.)); +#3205=CARTESIAN_POINT('Origin',(62.5,-62.5,3.)); +#3206=CARTESIAN_POINT('',(62.5,-62.5,6.)); +#3207=CARTESIAN_POINT('Origin',(-2.66453525910038E-14,-3.5527136788005E-14, +6.)); +#3208=CARTESIAN_POINT('',(0.,0.,0.)); +#3209=CARTESIAN_POINT('Origin',(58.75,-58.75,5.6)); +#3210=CARTESIAN_POINT('',(57.95,-58.75,6.)); +#3211=CARTESIAN_POINT('Origin',(58.75,-58.75,6.)); +#3212=CARTESIAN_POINT('',(57.75,-58.75,5.2)); +#3213=CARTESIAN_POINT('',(57.85,-58.75,5.6)); +#3214=CARTESIAN_POINT('Origin',(58.75,-58.75,5.2)); +#3215=CARTESIAN_POINT('Origin',(58.75,-58.75,0.)); +#3216=CARTESIAN_POINT('',(57.75,-58.75,0.25)); +#3217=CARTESIAN_POINT('',(57.75,-58.75,0.)); +#3218=CARTESIAN_POINT('',(59.75,-58.75,0.25)); +#3219=CARTESIAN_POINT('Origin',(58.75,-58.75,0.25)); +#3220=CARTESIAN_POINT('Origin',(58.75,-58.75,0.25)); +#3221=CARTESIAN_POINT('Origin',(58.75,-58.75,6.)); +#3222=CARTESIAN_POINT('Origin',(58.75,-58.75,0.25)); +#3223=CARTESIAN_POINT('',(59.5,-58.75,0.)); +#3224=CARTESIAN_POINT('Origin',(58.75,-58.75,0.)); +#3225=CARTESIAN_POINT('Origin',(59.5,-58.75,0.25)); +#3226=CARTESIAN_POINT('Origin',(58.75,-58.75,0.)); +#3227=CARTESIAN_POINT('',(0.,0.,0.)); +#3228=CARTESIAN_POINT('',(0.,0.,0.)); +#3229=CARTESIAN_POINT('',(0.,0.,0.)); +#3230=CARTESIAN_POINT('',(0.,117.5,0.)); +#3231=CARTESIAN_POINT('',(-117.5,0.,0.)); +#3232=CARTESIAN_POINT('',(-117.5,117.5,0.)); +#3233=UNCERTAINTY_MEASURE_WITH_UNIT(LENGTH_MEASURE(0.01),#3243, +'DISTANCE_ACCURACY_VALUE', +'Maximum model space distance between geometric entities at asserted c +onnectivities'); +#3234=UNCERTAINTY_MEASURE_WITH_UNIT(LENGTH_MEASURE(0.01),#3243, +'DISTANCE_ACCURACY_VALUE', +'Maximum model space distance between geometric entities at asserted c +onnectivities'); +#3235=UNCERTAINTY_MEASURE_WITH_UNIT(LENGTH_MEASURE(0.01),#3243, +'DISTANCE_ACCURACY_VALUE', +'Maximum model space distance between geometric entities at asserted c +onnectivities'); +#3236=UNCERTAINTY_MEASURE_WITH_UNIT(LENGTH_MEASURE(0.01),#3243, +'DISTANCE_ACCURACY_VALUE', +'Maximum model space distance between geometric entities at asserted c +onnectivities'); +#3237=UNCERTAINTY_MEASURE_WITH_UNIT(LENGTH_MEASURE(0.01),#3243, +'DISTANCE_ACCURACY_VALUE', +'Maximum model space distance between geometric entities at asserted c +onnectivities'); +#3238=( +GEOMETRIC_REPRESENTATION_CONTEXT(3) +GLOBAL_UNCERTAINTY_ASSIGNED_CONTEXT((#3233)) +GLOBAL_UNIT_ASSIGNED_CONTEXT((#3243,#3245,#3246)) +REPRESENTATION_CONTEXT('','3D') +); +#3239=( +GEOMETRIC_REPRESENTATION_CONTEXT(3) +GLOBAL_UNCERTAINTY_ASSIGNED_CONTEXT((#3234)) +GLOBAL_UNIT_ASSIGNED_CONTEXT((#3243,#3245,#3246)) +REPRESENTATION_CONTEXT('','3D') +); +#3240=( +GEOMETRIC_REPRESENTATION_CONTEXT(3) +GLOBAL_UNCERTAINTY_ASSIGNED_CONTEXT((#3235)) +GLOBAL_UNIT_ASSIGNED_CONTEXT((#3243,#3245,#3246)) +REPRESENTATION_CONTEXT('','3D') +); +#3241=( +GEOMETRIC_REPRESENTATION_CONTEXT(3) +GLOBAL_UNCERTAINTY_ASSIGNED_CONTEXT((#3236)) +GLOBAL_UNIT_ASSIGNED_CONTEXT((#3243,#3245,#3246)) +REPRESENTATION_CONTEXT('','3D') +); +#3242=( +GEOMETRIC_REPRESENTATION_CONTEXT(3) +GLOBAL_UNCERTAINTY_ASSIGNED_CONTEXT((#3237)) +GLOBAL_UNIT_ASSIGNED_CONTEXT((#3243,#3245,#3246)) +REPRESENTATION_CONTEXT('','3D') +); +#3243=( +LENGTH_UNIT() +NAMED_UNIT(*) +SI_UNIT(.MILLI.,.METRE.) +); +#3244=( +LENGTH_UNIT() +NAMED_UNIT(*) +SI_UNIT($,.METRE.) +); +#3245=( +NAMED_UNIT(*) +PLANE_ANGLE_UNIT() +SI_UNIT($,.RADIAN.) +); +#3246=( +NAMED_UNIT(*) +SI_UNIT($,.STERADIAN.) +SOLID_ANGLE_UNIT() +); +#3247=SHAPE_DEFINITION_REPRESENTATION(#3251,#3261); +#3248=SHAPE_DEFINITION_REPRESENTATION(#3252,#3262); +#3249=SHAPE_DEFINITION_REPRESENTATION(#3253,#3263); +#3250=SHAPE_DEFINITION_REPRESENTATION(#3254,#3264); +#3251=PRODUCT_DEFINITION_SHAPE('',$,#3266); +#3252=PRODUCT_DEFINITION_SHAPE('',$,#3267); +#3253=PRODUCT_DEFINITION_SHAPE('',$,#3268); +#3254=PRODUCT_DEFINITION_SHAPE('',$,#3269); +#3255=PRODUCT_DEFINITION_SHAPE($,$,#29); +#3256=PRODUCT_DEFINITION_SHAPE($,$,#30); +#3257=PRODUCT_DEFINITION_SHAPE($,$,#31); +#3258=PRODUCT_DEFINITION_SHAPE($,$,#32); +#3259=PRODUCT_DEFINITION_SHAPE($,$,#33); +#3260=PRODUCT_DEFINITION_SHAPE($,$,#34); +#3261=SHAPE_REPRESENTATION('',(#1908,#2140,#2141,#2142,#2143,#2144,#2145), +#3238); +#3262=SHAPE_REPRESENTATION('',(#1909),#3239); +#3263=SHAPE_REPRESENTATION('',(#2045),#3240); +#3264=SHAPE_REPRESENTATION('',(#2128),#3241); +#3265=PRODUCT_DEFINITION_CONTEXT('part definition',#3279,'design'); +#3266=PRODUCT_DEFINITION('jig','jig v4',#3270,#3265); +#3267=PRODUCT_DEFINITION('base','base',#3271,#3265); +#3268=PRODUCT_DEFINITION('stencilFrame','stencilFrame',#3272,#3265); +#3269=PRODUCT_DEFINITION('aligmentPin','aligmentPin',#3273,#3265); +#3270=PRODUCT_DEFINITION_FORMATION('',$,#3281); +#3271=PRODUCT_DEFINITION_FORMATION('',$,#3282); +#3272=PRODUCT_DEFINITION_FORMATION('',$,#3283); +#3273=PRODUCT_DEFINITION_FORMATION('',$,#3284); +#3274=PRODUCT_RELATED_PRODUCT_CATEGORY('jig v4','jig v4',(#3281)); +#3275=PRODUCT_RELATED_PRODUCT_CATEGORY('base','base',(#3282)); +#3276=PRODUCT_RELATED_PRODUCT_CATEGORY('stencilFrame','stencilFrame',(#3283)); +#3277=PRODUCT_RELATED_PRODUCT_CATEGORY('aligmentPin','aligmentPin',(#3284)); +#3278=APPLICATION_PROTOCOL_DEFINITION('international standard', +'automotive_design',2009,#3279); +#3279=APPLICATION_CONTEXT( +'Core Data for Automotive Mechanical Design Process'); +#3280=PRODUCT_CONTEXT('part definition',#3279,'mechanical'); +#3281=PRODUCT('jig','jig v4',$,(#3280)); +#3282=PRODUCT('base','base',$,(#3280)); +#3283=PRODUCT('stencilFrame','stencilFrame',$,(#3280)); +#3284=PRODUCT('aligmentPin','aligmentPin',$,(#3280)); +#3285=PRESENTATION_STYLE_ASSIGNMENT((#3287)); +#3286=PRESENTATION_STYLE_ASSIGNMENT((#3288)); +#3287=SURFACE_STYLE_USAGE(.BOTH.,#3289); +#3288=SURFACE_STYLE_USAGE(.BOTH.,#3290); +#3289=SURFACE_SIDE_STYLE('',(#3291)); +#3290=SURFACE_SIDE_STYLE('',(#3292)); +#3291=SURFACE_STYLE_FILL_AREA(#3293); +#3292=SURFACE_STYLE_FILL_AREA(#3294); +#3293=FILL_AREA_STYLE('Steel - Satin',(#3295)); +#3294=FILL_AREA_STYLE('ABS (White)',(#3296)); +#3295=FILL_AREA_STYLE_COLOUR('Steel - Satin',#3297); +#3296=FILL_AREA_STYLE_COLOUR('ABS (White)',#3298); +#3297=COLOUR_RGB('Steel - Satin',0.627450980392157,0.627450980392157,0.627450980392157); +#3298=COLOUR_RGB('ABS (White)',0.964705882352941,0.964705882352941,0.952941176470588); +ENDSEC; +END-ISO-10303-21; diff --git a/upstream/search/search_index.json b/upstream/search/search_index.json index b27eb9e3..81e01be3 100644 --- a/upstream/search/search_index.json +++ b/upstream/search/search_index.json @@ -1 +1 @@ -{"config":{"lang":["en"],"separator":"[\\s\\-]+","pipeline":["stopWordFilter"]},"docs":[{"location":"","title":"KiKit \u2013 Automation for KiCAD","text":"
KiKit is a Python library, KiCAD plugin and a CLI tool to automate several tasks in a standard KiCAD workflow like:
Then definitely consider:
Your support will allow me to allocate time to properly maintain my projects like this.
PS: Be sure to check out my other KiCAD & PCB related projects:
Everything KiKit does, can also be done via Pcbnew in KiCAD. However, you have to do it manually. One of the common scenarios is the creation of panels. Most of the tutorials on the internet guide you to use the \"append board\" functionality of Pcbnew. However, this approach is labour-intensive, error-prone and whenever, you change the board, you have to do it again.
With KiKit you just call a CLI command if you have a simple layout (e.g., a grid) or write few Python instructions like \"place board here\", \"add bridge here\", \"separate boards via mouse bites/v-cuts\" and you are done. The process is repeatable and actually much simpler than hand-drawing the panels. KiKit also allows you to easily export all the Gerbers in a single step.
You can then write a Makefile and simply call make
to get all your manufacturing data and board presentation pages.
Read the CLI documentation and the panelize documentation. Also don't miss the examples. There is also a quick not on how to use panelization action plugin. If you are interested in generating solder paste stencils, see Stencil documentation
"},{"location":"#acknowledgements","title":"Acknowledgements","text":"The project is supported by:
Please, first check FAQ. If you have not found answer for your problem there, feel free to open an issue on GitHub.
If you would like to have a feature in KiKit that is currently not on a roadmap, or if you need to prepare custom panelization script (e.g., multi-design panels, panels with specific arrangement), you can consider hiring me to do the job. Just reach out to me via e-mail and we can discuss further details.
"},{"location":"acknowledgements/","title":"Acknowledgements","text":"The project is supported by:
Thank you all!
"},{"location":"cli/","title":"KiKit CLI interface","text":"KiKit offers a simple CLI interface to perform common tasks easily. You can obtain help of the interface by calling kikit --help
.
The interface is structured into nested commands. On the top level, there are the following commands available:
kikit export gerber <boardFile> [<outputDir>]
- export gerber files of boardFile
to outputDir
. If no dir is specified, a new one <boardFile>-gerbers
is created.kikit export dxf <boardFile> [<outputDir>]
- export board outline and paste layers to DXF. The main use case for this command is making 3D printed solder paste stencils.Read more in a separate documentation section or see a walkthrough.
"},{"location":"cli/#separate-commands","title":"Separate commands","text":"Read more in a separate documentation section.
"},{"location":"cli/#stencil-commands","title":"Stencil commands","text":"Read more in a separate documentation section.
"},{"location":"cli/#present-commands","title":"Present commands","text":"kikit present boardpage --name <pagename> -d <descriptionFile> -b <name comment boadfile> -r <resource> --template <template> --repository <url> <outputdir>
- generate single webpage providing board preview and a possibility to download board files (gerbers and sources). See an example of such page.-r
or --resource
. Resources are files which will be copied to the output directory. Useful for images referred from description-b
or --board
default
). See template documentation for more information about templates.kikit modify references --show/--hide --pattern <pattern> <board>
hide or show all references on the board matching a regular pattern.
kikit modify values --show/--hide --pattern <pattern> <board>
is the same as above, just with footprint values.
KiKit respects the KiCAD component selection criteria. When you specify an input rectangle, only the components that fully fit inside the input rectangle are selected. This however take in account both name and value labels.
When you do not specify the source are explicitly, KiKit takes the board outline bounding box as the source area. Therefore, by default, components outside the board substrate are not copied to panel.
Since version 1.1 this behavior, however, changes for footprints. KiKit decides whether to keep a footprint or not based on whether its origin fits inside the source area or not. For graphical items, the behavior remains the same. The reason for this change is that often footprints reach out beyond the board edge (e.g., connectors) and the users don't want to remove them. On the other hand, graphical items (e.g., texts or arrows towards the board) are purely for documentation purposes and thus, they shouldn't be included in the panelized design.
Note that this is intended behavior; for once it is consistent with KiCAD behavior of user selection and also it allows to easily ignore surrounding comments and drawings in the board sheet (it makes no sense to have 12 same copies of the notes around the board).
How to include the components? - specify the source area explicitly to include all your components - specify tolerance: 20mm
for source
(i.e., --source 'tolerance: 20mm'
) to enlarge the board outline bounding box. The default value is 1 mm.
KiKit's millradius
parameter from the postprocess
section simulates the board outline milling by a tool with given radius. That means that it will round all inner corners. It is not a command to round just your tabs. That means if you specify a tool which diameter is larger than your slot, KiKit will remove the slot as such slot cannot be created with the tool.
This is an intended behavior. The options is designed for you to check if your board can be manufactured with all the features you have in your board outline. There aren't many fabrication houses that support sharp inner corners as they cannot be milled but have to be e.g., broached, which is much more complicated and expensive setup.
If you want to preserve your narrow internal slots: - don't specify millradius
at all in the postprocess
- specify smaller millradius
but make sure that your fabrication house supports such small tools.
KiKit's mouse bites offset specifies how much should be the mouse bites put inside the board. The recommended value is 0.25 mm (read about it in this blog post). Why is it so? When you break the tab, there will be rough edges. By putting the mouse bites inside the board, these rough edges won't be sticking outside the designed board outline. When you want to fit your board in a tight enclosure, you don't have to perform manual deburing. Since it is considered a good practice, KiKit makes this the positive direction so you don't have to put minus everywhere.
If you don't want to put mouse bites inside your board, just specify zero or negative offset.
"},{"location":"faq/#i-have-board-with-no-spacing-but-some-v-cuts-are-missing","title":"I have board with no spacing, but some V-cuts are missing.","text":"The default style of tabs (spacing
) does not generate in such a case any tabs, and, therefore, not cuts. Please use tab style full
.
ModuleNotFoundError: No module named 'pcbnew'
","text":"You probably installed KiKit via Windows command prompt, not KiCAD Command Prompt.
"},{"location":"faq/#i-would-like-to-make-a-panel-out-of-different-designs-but-there-is-no-such-option-in-help","title":"I would like to make a panel out of different designs, but there is no such option in help","text":"KiKit supports such feature. But it is not available from CLI. You have to write a simple Python script describing the panel and use KiKit as a library. Also, please refer to the panelization documentation.
If you wonder why is it in such way: there are infinitely many ways to panel your design. A single CLI/UI will not fit them all and also even for the simple cases, it would be enormous and painful to use. Much better idea is to use a language to specify the panel. But why reinvent the wheel and design a custom language when we can use Python? It integrates well with other tools and many people already know it.
"},{"location":"faq/#there-are-no-plugins-in-kicad","title":"There are no plugins in KiCAD!","text":"You have to install them via KiCAD PCM. See the installation guide.
"},{"location":"faq/#how-do-i-run-kikit-with-kicad-nightly","title":"How do I run KiKit with KiCAD nightly?","text":"See section \"Choosing KiCAD version\" in the installation guide. However, at the moment KiKit is incompatible with KiCAD 6.99.
"},{"location":"multiboard/","title":"Multiboard workflow","text":""},{"location":"multiboard/#multi-board-workflow-with-kikit","title":"Multi-board workflow with KiKit","text":"KiCAD does not support multiple board per project, nor boards with shared schematics. However, with the following workflow, you can easily draw multiple boards with shared schematics and, e.g., easily ensure that tha board connectors match.
The workflow is the following:
First, draw a separate schematics sheet for each of your boards and propagate the pins on the inter-board connectors. E.g., in one of my project it looks like this:
I also place the corresponding connectors next to each other to illustrate that they connect. Then draw your board schematics as usual - with one exception. Do not use global power symbols nor global labels, use only local labels. This ensures that the power lines are separate for each board and DRC won't complain, that you have not connected the power between two board.
Then, draw all your boards into a single board file side-by-side. See file resources/multiboard.kicad_pcb for a dead simple illustration. You can also draw lines that will help you align your boards' connectors.
Before manufacturing, use KiKit to extract the boards into a separate board files via the extract
command.
This can be done in two ways:
We will show how to use it on resources/multiboard.kicad_pcb which looks like this:
"},{"location":"multiboard/#bounding-box-selection","title":"Bounding box selection","text":"Simply specify the top left and bottom right corner. Everything that fits fully inside it, will be included in the board. The command for separation of board A into a separate board file is:
kikit separate --source 'rectangle; tlx: 89mm; tly: 89mm; brx: 111mm; bry: 111mm' \\\n multiboard.kicad_pcb board_a.kicad_pcb\n
After that, board_a.kicad_pcb
will contain only a board A. Note that the \\
is there for shell as we split our command into two lines.
As you can see, the source file contains an annotation in the form of virtual footprints kikit:Board
. You can place them into your document so that the arrow points to the board edge. Than you can use the reference of the annotation symbol for separation of the board. To separate board A simply invoke:
kikit separate --source 'annotation; ref: B1' \\\n multiboard.kicad_pcb board_a.kicad_pcb\n
After that, board_a.kicad_pcb
will contain only a board A. Note that the \\
is there for shell as we split our command into two lines.
Note that if panelize your boards, you don't have to separate your boards first; just use the --source
with the panelization command.
When you use the separate command, KiKit preserves all annotations within the source bounding box. If you would like to strip the annotations, you can specify --stripAnnotation
and KiKit will remove all annotations from the resulting board.
Present is a collection of functions providing various ways to present KiCAD boards. The main one is a simple page generator which can be used in continuous integration to build pages where your users and collagues can download the automatically generated panels.
"},{"location":"present/#requirements","title":"Requirements","text":"In order to include PCB drawings in presentations you will need to install PcbDraw.
"},{"location":"present/#template-namepath-resolution","title":"Template name/path resolution","text":"The template argument is either a name of a built-it template or a path to a directory with a user-defined template. During the name resolution the first test is for the user-defined template; i.e., check if the name provided by the user is a directory path and the directory contains the file template.json
. If not, try to resolve the name as the name of the built-in template.
A template is a directory containing template files. There is a single mandatory file common to all template types template.json
. An example of such file follows:
{\n \"type\": \"HtmlTemplate\",\n \"resources\": [\"css/*.css\"]\n}\n
The key type
specifies what kind of template it is. Currently, only HtmlTemplate
is supported (see more info about them below). Then there is the list of resources
which are glob patterns for resource files which are copied to the output directory when rendering the template.
Expects an index.html
file in the root of the template. This is Handlerbars template which receives the following dictionary on render:
\"repo\": self.repository,\n\"gitRev\": gitRev,\n\"gitRevShort\": gitRev[:7] if gitRev else None,\n\"datetime\": self.currentDateTime(),\n\"name\": self.name,\n\"boards\": self.boards,\n\"description\": self.description\n
boards
is a list of a dictionary with following keys:
front
path to render of the front sideback
path to render of the back sidegerbers
path to archive with gerbersfile
path to kicad_pcb
fileSee the default template in kikit/resources/present/templates/default
for a starting point for custom templates.
If you populate your boards using a reflow oven, you often need solder paste stencils. One of the inconveniences with stencils is that you have to align them manually. It is not hard, but it takes some time and a little bit of practice & tricks (e.g. to use other PCBs for stencil alignment).
KiKit provides two ways to generate stencils:
KiKit allows you to ignore components from the stencil by specifying --ignore
followed by a comma separated list of components' references to exclude. Pads of these components will not appear in the stencil. This is useful, when you do not want to populate all components.
The second common option is --cutout
followed by a comma separated lists of components' references. For these components, the stencil will contain a cutout based on the component courtyard. This is useful when you have already pre-populated board and you want to populate more components -- e.g., when your assembly house does not have a special IC and you populate it yourself and also, when you do a board repair.
I wrote a blog post about the 3D printed self-registering stencils on my blog. These stencils are quick solution when you urgently need a stencil but probably they don't last long and might come with imperfections.
To generate such stencil, just call:
kikit stencil createprinted [parameters] <boardFile> <outputDirectory>\n
where parameters is one of the following: --pcbthickness FLOAT PCB thickness in mm\n--thickness FLOAT Stencil thickness in mm. Defines amount of paste\n dispensed\n--framewidth FLOAT Register frame width\n--ignore TEXT Comma separated list of components references to\n exclude from the stencil\n--frameclearance FLOAT Clearance for the stencil register in milimeters\n--enlargeholes FLOAT Enlarge pad holes by x mm\n
KiKit will output two STL files representing bottom and top register to the specified directory. You can directly print these files. In theory, if you don't have small pads spacing, you could print them even on FDM machine, but I haven't tested it.
"},{"location":"stencil/#steel-stencils","title":"Steel Stencils","text":"Many fabhouses offer you to create a custom stencil. However, it is pain to align them. Therefore, KiKit offers a functionality to automatically generate stencils which fit a simple 3D printed or lasercut alignment jig.
You can find Fusion 360 model of the alignment jig here: https://a360.co/3iiFXKp. It it designed to be cut from 3mm thick acrylic. You need 4 2mm pins, 8 M2 screws and that's it. The frame can be customized - there two parameters of the model, frameWidth
and frameHeight
which define the largest PCB it can accept. I usually use 100x100mm and 60x60mm.
Then you issue the following command within KiKit:
kikit stencil create --jigsize 60 60 <boardFile> <outputDir>\n
Note that there are more options for this command, see output of kikit stencil create --help
. KiKit will produce 2 STL files for aligning the PCB and a zip file with gerbers for the manufacturer. When you order your stencil, let them make both top and bottom side on the same stencil. One tip for JLC PCB: set custom size of the stencil when you order it - then it fits into your package with your PCB and you don't have to pay for extra shipping.
The stencil you receive should look like on the following picture. It has mouse bites so you can easily break it off to precise size. It also has mounting holes.
Once you break the stencils off, you mount them in the jig frame:
Then you print alignment parts for your board and mount in onto the jig using M2 screws:
Then you just use 2mm pins to align the frame and you can apply the paste!
The acrylic jig is reusable - you just have to mount new alignment pieces and change the stencil.
"},{"location":"fabrication/intro/","title":"Fabrication","text":"KiKit offers fully automatic export of all data required for fabrication of your designs. Since every fabrication house has different requirements on the design files (e.g., special names of gerber files, different requirements for assembly files) there is no \"universal exporter\" in KiKit. Instead, KiKit offers special command for each supported fabrication house.
"},{"location":"fabrication/intro/#common-options","title":"Common Options","text":"All fab subcommands has a common invocation structure:
kikit fab <fabhouse> <options> <sourceDir> <outputDir>\n
All commands also support the following options:
--drc\\--no-drc
(default --drc
). Check for DRC violations before exporting the files. With this options, you won't send a board that fails DRC to your manufacturer.--nametemplate <str>
: If you want to name your files differently, specify this option. This option takes a string that should contain {}
. This string will be replaced by gerber
, pos
or bom
in the out file names. The extension is appended automatically. Variables in text are also supported eg: {boardTitle}_rev{boardRevision}_{date}_{}
. The project variables are available with the user-
prefix; e.g., `MFR: {user-mfr}```Each of the fab command also take additional, manufacturer specific, options. See documentation for the individual manufacturer below:
"},{"location":"fabrication/intro/#currently-supported","title":"Currently Supported:","text":"Note: click on the name of the manufacturer to see corresponding documentation:
To add a new fabrication command you have to extend KiKit's source code. A rather basic knowledge of python is required to do so.
Create a new file kikit/fab/fabhousename.py
and implement a new command with the same name as the file. Then add the command to kikit/fab/__init__.py
. The common functionality for all fabrication houses should be located in kikit/fab/common.py
. You can use kikit/fab/jlcpcb.py
for inspiration.
Once you implement a support for new fabrication house, open a pull request on KiKit's GitHub page.
"},{"location":"fabrication/jlcpcb/","title":"Fabrication: JLC PCB","text":"The basic usage of this exporter is:
kikit fab jlcpcb [OPTIONS] BOARD OUTPUTDIR\n
When you run this command, you will find file gerbers.zip
in OUTPUTDIR
. This file can be directly uploaded to JLC PCB site. KiKit automatically detects the number of layers.
If you want to name your files differently, you can specify --nametemplate
. This option takes a string that should contain {}
. This string will be replaced by gerber
, pos
or bom
in the out file names. The extension is appended automatically.
If you would also like to use the SMD assembly service, you have to specify --assembly
option and also provide the board --schematic <schematics_file>
. KiKit will generate two extra files: bom.csv
(bill of materials) and pos.csv
(component placement). Use these two files when ordering the PCB assembly.
The files above will include all components on the board. You can override the default field name with option --field
. This option accepts a comma separated list of names. The first found field is used. This can be used, e.g., for configuration of the board via resistors. You can put field \"LCSC\" for all components, then add fields \"CFG1_LCSC\" and \"CFG2_LCSC\" for some components. Then invoke KiKit with option --field CFG1_LCSC,LCSC
for configuration 1 or --field CFG2_LCSC,LCSC
for configuration 2.
You can exclude some of the components by specifying --ignore <comma separated list of references>
. You can also specify component field with name JLCPCB_IGNORE
(the value of the field does not matter) to exclude the component from assembly. Also, if a component misses the order code field, KiKit will show warning. When you pass option --missingError
, KiKit will fail when there is a component with missing order code. This might be useful in case when you run KiKit in CI and you want to fail the build.
Note that when you order SMD assembly for a panel, you should specify panelized board and the original schematics of a single board.
"},{"location":"fabrication/jlcpcb/#correction-of-the-footprint-position","title":"Correction of the Footprint Position","text":"It is possible that orientation footprints in your SMD does not match the orientation of the components in the SMD assembly service. There are two solutions:
The first option is not always feasible - e.g., when you use KiCAD's built-in libraries or you are preparing a board for multiple fabrication houses and each of them uses a different orientation.
KiKit allows you to specify the origin and orientation correction of the position. The correction is specified by JLCPCB_CORRECTION
field. The field value is a semicolon separated tuple: <X>; <Y>; <Rotation>
with values in millimeters and degrees. You can read the XY corrections by hovering cursor over the intended origin in footprint editor and mark the coordinates. Note that first the rotation correction is applied, then the translation. Usually, you will need only the rotation correction.
If your board features solder jumpers you can use the corrections to specify their default value. The solder jumper should be designed such it can fit a zero Ohm resistor in suitable size. Then specify an order code of the zero Ohm resistor for the jumper and adjust correction so it fits the default position.
Note that you can specify multiple correction fields by --corrections <comma separated list of correction filed names>
. The first found correction field is used. This allows you to keep several configuration of the solder jumpers in your design e.g., in fields JLCPCB_CORRECTION_CFG_1
and JLCPCB_CORRECTION_CFG_2
. Then you can simply change the board configuration by calling kikit with --corrections JLCPCB_CORRECTION_CFG_1,JLCPCB_CORRECTION
or --corrections JLCPCB_CORRECTION_CFG_2,JLCPCB_CORRECTION
.
The basic usage of this exporter is:
kikit fab neodenyy1 [OPTIONS] BOARD OUTPUTDIR\n
When you run this command, you will find file top_pos.csv
and bottom_pos.csv
in OUTPUTDIR
. This file can be used in Neoden YY1. KiKit automatically detects the number of layers.
If you want to name your files differently, you can specify --nametemplate
. This option takes a string that should contain {}
. This string will be replaced by gerber
, pos
or bom
in the out file names. The extension is appended automatically.
For Neoden YY1 you must specify --assembly
option and provide the board --schematic <schematics_file>
. KiKit will generate files: top_pos.csv
(top layer component placement) and bottom_pos.csv
(bottom layer component placement). Use these two files to assembly PCB on machine.
On Neoden YY1, the position origin must use the bottom left corner of the board edge.
"},{"location":"fabrication/neodenyy1/#correction-of-the-footprint-position","title":"Correction of the Footprint Position","text":"It is possible that orientation footprints in your SMD does not match the orientation of the components in the SMD assembly service. There are two solutions:
The first option is not always feasible - e.g., when you use KiCAD's built-in libraries or you are preparing a board for multiple fabrication houses and each of them uses a different orientation.
KiKit allows you to specify the origin and orientation correction of the position. The correction is specified by YY1_CORRECTION
field. The field value is a semicolon separated tuple: <X>; <Y>; <Rotation>
with values in millimeters and degrees. You can read the XY corrections by hovering cursor over the intended origin in footprint editor and mark the coordinates. Note that first the rotation correction is applied, then the translation. Usually, you will need only the rotation correction.
The basic usage of this exporter is:
kikit fab openpn [OPTIONS] BOARD OUTPUTDIR\n
This exporter creates a single file components.pos
that mimics KiCAD native .pos
output. However, unlike KiCAD, it adds a unique identifier to component references to ensure they are unique (in the case of panels).
The basic usage of this exporter is:
kikit fab oshpark [OPTIONS] BOARD OUTPUTDIR\n
When you run this command, you will find gerbers.zip
in OUTPUTDIR
. This file can be directly uploaded to the OSH Park site. KiKit automatically detects the number of layers.
If you want to name your files differently, you can specify --nametemplate
. The extension is appended automatically.
The basic usage of this exporter is:
kikit fab pcbway [OPTIONS] BOARD OUTPUTDIR\n
When you run this command, you will find file gerbers.zip
in OUTPUTDIR
. This file can be directly uploaded to the PCBWay site. KiKit automatically detects the number of layers.
If you want to name your files differently, you can specify --nametemplate
. For detailed description of this option, see JLC PCB documentation.
If you would also like to use the SMD assembly service, you have to specify --assembly
option and also provide the board --schematic <schematics_file>
. KiKit will generate two extra files: bom.csv
(bill of materials) and pos.csv
(component placement). Use these two files when ordering the PCB assembly.
The files above will include all components on the board by default, except footprints having the attribute virtual set. You should provide the \"Manufacturer\" and \"PartNumber\" Fields for each component, where PartNumber refers to the manufacturers part number (and can safely contain non-digit characters). If the \"Description\" field is present, this value will be inserted in the \"Value/Description\" column in the BOM, otherwise the value of the component. It is recommended to provide no description for capacitors, resistors, and inductors, so that the value is inserted into the BOM for them. PCBWay also requires the soldering type (SMD, thru-hole, ...) to be specified. Any footprint only having SMD pads will be considered as \"SMD\", everything else as \"thru-hole\". You can manually overwrite the type by adding a \"Type\" field to the component. For the footprint column of the BOM the KiCad footprint name is used by default. Add a \"FootprintPCBWay\" field to overwrite this in the BOM list for a more human readable footprint name, if you want. Finally, notes or assembly instructions can be added using the \"Notes\" field.
You can exclude some of the components by specifying --ignore <comma separated list of references>
. When you pass option --missingError
, KiKit will fail when there is a component with missing manufacturer and/or part number. This might be useful in case when you run KiKit in CI and you want to fail the build.
Note that when you order assembly for a panel, you should specify panelized board and the original schematics of a single board. Use the --nBoards
parameter to specify the number of boards in the panel. The quantity column is generated by multiplying this number with the number of references in each row.
It is possible that orientation footprints in your SMD does not match the orientation of the components in the SMD assembly service. There are two solutions:
The first option is not always feasible - e.g., when you use KiCAD's built-in libraries or you are preparing a board for multiple fabrication houses and each of them uses a different orientation.
KiKit allows you to specify the origin and orientation correction of the position. The correction is specified by PCBWAY_CORRECTION
field. The field value is a semicolon separated tuple: <X>; <Y>; <Rotation>
with values in millimeters and degrees. You can read the XY corrections by hovering cursor over the intended origin in footprint editor and mark the coordinates. Note that first the rotation correction is applied, then the translation. Usually, you will need only the rotation correction.
If your board features solder jumpers you can use the corrections to specify their default value. The solder jumper should be designed such it can fit a zero Ohm resistor in suitable size. Then specify an order code of the zero Ohm resistor for the jumper and adjust correction so it fits the default position.
Note that you can specify multiple correction fields by --corrections <comma separated list of correction filed names>
. The first found correction field is used. This allows you to keep several configuration of the solder jumpers in your design e.g., in fields PCBWAY_CORRECTION_CFG_1
and PCBWAY_CORRECTION_CFG_2
. Then you can simply change the board configuration by calling kikit with --corrections PCBWAY_CORRECTION_CFG_1,PCBWAY_CORRECTION
or --corrections PCBWAY_CORRECTION_CFG_2,PCBWAY_CORRECTION
.
When you have multiple versions of KiCAD installed, it might be desirable to run KiKit with one or another (e.g., to not convert your designs into new format).
KiKit loads the Python API directly via a module, so which module is loaded (which KiCAD version is used) follows standard Python conventions. Therefore, to choose a particular KiCAD version, just specify the environmental variable PYTHONPATH
. The path have to point to a folder containing the module (pcbnew.py
file).
The most common on linux are:
stable: /usr/lib/python3/dist-packages/pcbn\nnightly: /usr/lib/kicad-nightly/lib/python3/dist-packages/\n
E.g., to run KiKit with nightly, run:
PYTHONPATH=/usr/lib/kicad-nightly/lib/python3/dist-packages/ kikit\n
To run KiKit with a KiCAD you compiled (and not installed):
PYTHONPATH=path-to-sources/build/pcbnew kikit\n
This also works when you invoke make
as environmental variables are propagated:
PYTHONPATH=/usr/lib/kicad-nightly/lib/python3/dist-packages/ make\n
"},{"location":"installation/docker/","title":"Running KiKit via Docker","text":"This method is applicable to Windows, Linux and MacOS. It provides access to all of the CLI commands in a known-working container, but doesn't allow your local install of KiCad to access KiKit via the KiKit plugin.
First, install Docker. The installation procedure varies by the platform, so Google up a recent guide for your platform.
With Docker you can skip all of the install steps and instead run KiKit via (on Linux or Mac):
docker run -v $(pwd):/kikit yaqwsx/kikit --help\n
(replacing the call to display the --help
with whatever command you want to run. Try --version
or panelize
) or on Windows:
docker run -v %cd%:/kikit yaqwsx/kikit --help\n
Note that on Windows you might have to explicitly allow for mounting directories outside your user account (see the following topic).
"},{"location":"installation/docker/#creating-an-alias-to-kikit-in-docker-to-save-some-typing","title":"Creating an alias to KiKit in Docker to save some typing","text":"If you're on Linux or Mac and are going to run commands repeatedly within the same directory you can create an alias within the current terminal session via:
alias kikit=\"docker run -v $(pwd):/kikit yaqwsx/kikit\"\n
Note that alias
is a Linux/ Unix command so won't work on Windows, you'll need to call docker run -v %cd%:/kikit yaqwsx/kikit
each time. Also note that you must update the alias (by running the same alias command again) if you move to a different directory. The current working directory for the alias is \"frozen\" at the directory you create the alias in. From then on, until you close that terminal, you'll be able to just run kikit
followed by the relevant paramenters (e.g. kikit --version
or kikit panelize
).
If you would like to run a particular version of KiKit, simply append a tag to the image name (e.g., yaqwsx/kikit:nightly
), and Docker will pull that version down and run that for you instead:
docker run -v $(pwd):/kikit yaqwsx/kikit:nightly --version\n
We provide the following containers:
A full list is available on Dockerhub.
"},{"location":"installation/docker/#mac-m1-containers","title":"Mac M1 containers","text":"There are also nightly containers of Mac M1 available with tag nightly-m1
.
If you want to use Makefile for your projects, the preferable way is to invoke make
inside the container. The Docker image contains several often used tools and you can even run KiCAD from it (if you supply it with X-server). To call make
within the container, override the container's entrypoint:
docker run -it -v $(pwd):/kikit --entrypoint '/usr/bin/make' --help\n
(replacing --help
with your make command, such as build
or test
)."},{"location":"installation/gui_and_libs/","title":"GUI and libs installation","text":""},{"location":"installation/gui_and_libs/#kikit-symbol-and-footprint-libraries","title":"KiKit Symbol and Footprint Libraries","text":"From v6 onwards KiCad comes with a \"Plugin and Content Manager\" (PCM) which can be used to add the KiKit symbol and footprint libraries used in multi-board workflows. The PCM is new functionality for KiCad though, and only does part of the installation in v6. To install the libraries using the PCM:
Tools
menu and select Plugin and Content Manager
Libraries
tab and scroll down to KiKit Library
Install
and then Apply Changes
The following steps are only required in KiCad 6, they are automated in KiCad 7:
Preferences
menu and select Manage Symbol Libraries
Global Libraries
tab, and click the +
icon towards the bottom of the window then enter kikit
(all lowercase) as the nickname, and ${KICAD6_3RD_PARTY}/symbols/com_github_yaqwsx_kikit-library/kikit.kicad_sym
as the Library Path.OK
Preferences
menu and select Manage Footprint Libraries
Global Libraries
tab, with a nickname kikit
(all lowercase again), and this time enter ${KICAD6_3RD_PARTY}/footprints/com_github_yaqwsx_kikit-library/kikit.pretty
for the Library Path.OK
kikit
alongside all the others.KiKit consists of three parts:
Unfortunately, it is not possible to install all three parts automatically in a single step due to technical limitations of KiCAD's PCM at the moment, so you have to install them separately.
"},{"location":"installation/intro/#backend-installation","title":"Backend installation","text":"The backend installation differs slightly based on the platform:
GUI plugins and libraries are available via KiCAD PCM. See details about their installation.
"},{"location":"installation/intro/#optional-dependencies","title":"Optional dependencies","text":"Some KiKit features rely on external dependencies:
We also distribute a Docker container for running KiKit in CI or on platform where it is hard to meet all dependencies. This mode doesn't support GUI. Learn more about the docker images.
"},{"location":"installation/linux/","title":"Installation on Linux","text":"KiKit is distributed as PyPi package.
"},{"location":"installation/linux/#instalation-for-kicad-installed-via-system-package-manager","title":"Instalation for KiCAD installed via system package manager","text":"The installation consists of a single command you have to enter into the terminal. If you installed KiCAD via package manager (apt, yum, etc.) you can use a regular terminal and enter pip3 install kikit
. Now you are ready to use KiKit.
However, if you installed KiCAD via Flatpak, you have to open a special terminal as Flatpak sandboxes the applications. Open terminal and invoke flatpak run --command=sh org.kicad.KiCad
, this will open a terminal session inside the KiCAD\u2019s sandbox. Now you can install pip via python3 -m ensurepip
and then, inside the same terminal you can install KiKit: python3 -m pip install kikit
. If you would like to use CLI interface, all commands have to be invoked inside the shell flatpak run --command=sh org.kicad.KiCad
, and, instead of kikit something
you have to use python -m kikit.ui something
.
Now you can test that it works:
> kikit --help\n
You should get something like this:
Usage: kikit [OPTIONS] COMMAND [ARGS]...\n\nOptions:\n --version Show the version and exit.\n --help Show this message and exit.\n\nCommands:\n drc Validate design rules of the board\n export Export KiCAD boards\n fab Export complete manufacturing data for given fabrication houses\n modify Modify board items\n panelize Panelize boards\n present Prepare board presentation\n separate Separate a single board out of a multi-board design.\n stencil Create solder paste stencils\n
Now you are done with the basic installation. If you plan to use graphical interface, install GUI frontend and libraries via PCM.
"},{"location":"installation/macos/","title":"KiKit Installation on MacOS","text":"Installation on MacOS is a little more involved as MacOS enforces that all external programs are signed. KiCAD installed via homebrew is signed, however, once plugins with binary dependencies are installed, the signature gets invalidated. This prevents KiKit from running.
The current solution is to re-sign KiCAD after KiKit installation. Therefore, KiKit's installation on MacOS is twofold: - create a self-signed certificate - install KiKit and sign KiCAD
"},{"location":"installation/macos/#create-a-codesigning-certificate","title":"Create a codesigning certificate","text":"Open Keychain a select \"Create a Certificate\":
Then, enter name \"kikit\", select \"Self-Signed Root\" and type \"Code Signing\":
Confirm and the certificate is ready.
"},{"location":"installation/macos/#install-kikit-related-wrappers","title":"Install KiKit & related wrappers","text":"We provide a script for KiKit installation's, KiCAD signing and creating a wrapper script for KiKit. You can find the script here. You can download and run it. Open a terminal and enter:
$ curl -O https://raw.githubusercontent.com/yaqwsx/KiKit/master/scripts/installMacOS.bash\n$ sudo bash installMacOS.bash\n
The script will ask you for a password several times. Once it finishes, you can test it:
$ kikit --help\nUsage: python3 -m kikit.ui [OPTIONS] COMMAND [ARGS]...\n\nOptions:\n --version Show the version and exit.\n --help Show this message and exit.\n\nCommands:\n drc Validate design rules of the board\n export Export KiCAD boards\n fab Export complete manufacturing data for given fabrication houses\n modify Modify board items\n panelize Panelize boards\n present Prepare board presentation\n separate Separate a single board out of a multi-board design.\n stencil Create solder paste stencils\n
Once you install the PCM plugin, KiKit will be available via GUI in Pcbnew.
"},{"location":"installation/upgrading/","title":"Upgrading KiKit and installing special versions","text":""},{"location":"installation/upgrading/#upgrading-kikit","title":"Upgrading KiKit","text":"If you want to upgrade KiKit, you have to perform two steps:
pip install -U kikit
in the command line (depending on the platform, see the installation instructions for individual platform).If you would like to install a specific version of KiKit (e.g., the upstream version), you can install it directly from git. The command for that is:
# The master branch (also called the upstream version) - the most up-to-date KiKit there is (but might me unstable)\npip install git+https://github.com/yaqwsx/KiKit@master\n# A concrete branch, e.g., from a pull request\npip3 install git+https://github.com/yaqwsx/KiKit@someBranchName\n
"},{"location":"installation/windows/","title":"Windows","text":""},{"location":"installation/windows/#installation-on-windows","title":"Installation on Windows","text":"To install KiKit on Windows, you have to open \"KiCAD Command Prompt\". You can find it in the start menu:
Once you have it open like this:
you can put command in there and confirm them by pressing enter. This is also the prompt from which you will invoke all KiKit's CLI commands. They, unfortunately, does not work in an ordinary Command prompt due to the way KiCAD is packaged on Windows.
Then you have to enter the following command to install it:
pip install kikit\n
Now you can test that it works:
kikit --help\n
You should get something like this:
Usage: kikit [OPTIONS] COMMAND [ARGS]...\n\nOptions:\n --version Show the version and exit.\n --help Show this message and exit.\n\nCommands:\n drc Validate design rules of the board\n export Export KiCAD boards\n fab Export complete manufacturing data for given fabrication houses\n modify Modify board items\n panelize Panelize boards\n present Prepare board presentation\n separate Separate a single board out of a multi-board design.\n stencil Create solder paste stencils\n
Now you are done with the basic installation. Don't forget to get the GUI frontend and libraries via PCM.
"},{"location":"panelization/cli/","title":"Panelization CLI","text":"The whole panelization process of KiKit's CLI is driven by a configuration structure. The configuration contains several categories (e.g., layout
, tabs
, framing
). Each of the categories have number of named parameters (e.g., tabsCount
). All categories and their parameters are described further below.
Note that you can use the pcbnew action plugin to interactively construct the panelization configuration structure.
"},{"location":"panelization/cli/#configurations","title":"Configurations","text":"The configuration can be supplied to KiKit via a JSON file with comments and from the command line. The example of a configuration in a JSON file is the following
{\n // There can be C-like comments\n \"layout\": {\n \"type\": \"grid\",\n \"rows\": 1,\n \"cols\": 1,\n \"hspace\": \"0mm\",\n \"vspace\": \"0mm\",\n \"rotation\": \"0deg\",\n \"alternation\": \"none\",\n \"renamenet\": \"Board_{n}-{orig}\",\n \"renameref\": \"{orig}\"\n },\n \"source\": {\n \"type\": \"auto\",\n \"tolerance\": \"1mm\"\n },\n \"tabs\": {\n \"type\": \"normal\",\n \"source\": \"none\"\n },\n \"cuts\": {\n \"type\": \"none\"\n },\n \"framing\": {\n \"type\": \"none\",\n \"thickness\": \"0mm\",\n },\n \"post\": {\n \"type\": \"auto\",\n \"millradius\": \"0mm\",\n \"copperfill\": false\n }\n}\n
KiKit accepts -p <configurationFile>
option to specify one or more configurations. When multiple configurations are specified, they are composed into a single configuration. The later specified configurations overwrite parameters of the former specified configurations. This allows us to start with a basic configuration and have a number of small configurations specifying details.
To give and example, consider the two following configurations:
// A\n{\n \"tabs\": {\n \"type\": \"normal\",\n \"width\": \"3mm\"\n },\n \"framing\": {\n \"type\": \"frame\"\n }\n}\n\n// B\n{\n \"framing\": {\n \"type\": \"rails\"\n \"width\": \"5mm\"\n }\n}\n
When we merge B
into A
, we get:
{\n \"tabs\": {\n \"type\": \"normal\",\n \"width\": \"3mm\"\n },\n \"framing\": {\n \"type\": \"rails\"\n \"width\": \"5mm\"\n }\n}\n
You can also override every parameter from CLI. There is an option for each category, which accepts a semicolon-separated list of key-value pairs; e.g.:
--layout 'rows: 3; cols: 4'\n
The options from CLI have the highest priority - they override values from specified from the files. If you need to specify the character ;
, you can escape it via \\
.
Therefore, a full invocation of KiKit for panelization can look like this:
kikit panelize -p myDefault.json -p useVcuts.json -p myFrame.json\n --layout 'rows: 3; cols: 4'\n board.kicad_pcb panel.kicad_pcb.\n
Note the single quotes -- without them your shell will eat the spaces and the command will be interpreted badly. The command will use our default configuration, then it will override some options to use V-cuts and then it adds a frame specified by myFrame.json
. Last we specify the panel size from CLI.
Note that KiKit always start with a default configuration (specified in the file default.json). There are also some configuration files shipped with KiKit. You can find them in the directory kikit/resources/panelizePresets
. When you want to use them via option -p
, just prefix their name with :
and drop the suffix. E.g., for vcuts.json
use -p :vcuts
.
If you would like to inspect which configuration was used by KiKit, you can dump it into a file with the -d <filename>
option.
You can specify units in the configuration files and CLI. Always specify them as string, e.g., \"2mm\" or \"0.5 inch\" (do not forget the quotes in the JSON files).
Supported length units: mm, cm, dm, m, mil, inch, in.
Supported angle units: deg, \u00b0, rad.
"},{"location":"panelization/cli/#configuration-categories","title":"Configuration categories","text":"There are the following categories: layout, source, tabs, cuts, framing, and tooling.
Each category has a mandatory parameter type
which dictates the style of that feature. Note that you can specify the type parameter in a simplified manner in the CLI by specifying it first and omitting the type
word; e.g., --cuts 'mousebites, someParameter: 10cm'
.
Types: grid, plugin
Common options:
hspace
, vspace
, space
: Specify the gap between the boards. You can specify separately vertical and horizontal spacing or you can specify space
to make them the same (it has higher priority).rotation
: Rotate the boards before placing them in the panelrenamenet
, renameref
: A pattern by which to rename the nets and references. You can use {n}
and {orig}
to get the board number and original name. Default values are Board_{n}-{orig}
for nets and {orig}
for references.baketext
: A flag that indicates if text variables should be substituted or not.The boars are placed in a grid pattern connected by tabs. There are no special options.
rows
, cols
: Specify the number of boards in the grid patternalternation
: Specify alternations of board rotation.none
: Do not alternaterows
: Rotate boards by 180\u00b0 on every next rowcols
: Rotate boards by 180\u00b0 on every next columnrowsCols
: Rotate boards by 180\u00b0 based on a chessboard patternvbackbone
, hbackbone
: The width of vertical and horizontal backbone (0 means no backbone). The backbone does not increase the spacing of the boards.vboneskip
, hboneskip
: Skip every n backbones. I.e., 1 means place only every other backbone.vbonefirst
, hbonefirst
: Specify first backbone to render. Allows to specify the offset when skipping backbones. The offset is indexed from 1.vbonecut
, hbonecut
: true/false. If there are both backbones specified, specifies if there should be a vertical or horizontal cut (or both) where the backbones cross.Implements a custom layout based on a plugin.
code
: the plugin specification. See (plugin documentation)[plugin.md] for more detailsarg
: text argument for the user pluginThis option allows you to specify the source area, e.g., when multiple boards are present. You can read more about multi-board project here.
Types: auto, rectangle, annotation
Common options:
stack
: specify the number of layers of the panel. Valid options are 2layer
, 4layer
, 6layer
or inehrit
(default). The use case for this option is when you design a multiple boards in a single desing and you separate them, however, one boards is e.g., 4 layer and one 2 layer. Then you design both of them as 4 layer and you specify stack: 2layer
for the 2 layer one when panelizing or separating.Find all board edges and use them to construct source rectangle. Suitable for most cases when there is only a single board in the design. Note that might want to increase tolerance
or specify the source area explicitly via rectangle
if you have components sticking out of your design.
tolerance
: KiKit extracts only board items that fit fully into the source area (including all drawings on all layers). Tolerance enlarges the source area by given amount, to e.g., not omit KiKit annotations for tabs or connectors sticking out of the board.Specify the source rectangle explicitly.
tlx, tly, brx, bry
: specify the coordinates (via length units) of the rectangle via top-left and bottom-right corner.KiKit offers you to place an annotation footprint kikit:Board
into your design file to name the board. The area is determined by a bounding box of the lines in the Edge.Cuts
layer that the arrows point to. Note that the tip of the arrow must lie on the PCB edge or slightly outside of it.
ref
: specify the annotation symbol referencetolerance
: see aboveTypes: fixed, spacing, full, annotation, plugin
Place tabs. To make some of the options clear, please see the explanation of tab placement process.
"},{"location":"panelization/cli/#fixed","title":"Fixed","text":"Place given number of tabs on the PCB edge. The tabs are spaced uniformly. If you need a custom tab placement (e.g., to avoid critical feature), see type annotation.
vwidth
, hwidth
, width
: The width of tabs in the vertical and horizontal direction. width
overrides both.vcount
, hcount
: Number of tabs in a given direction.mindistance
: Minimal spacing between the tabs. If there are too many tabs, their count is reduced.Place tabs on the PCB edges based on spacing.
vwidth
, hwidth
, width
: The width of tabs in the vertical and horizontal direction. width
overrides both.spacing
: The maximum spacing of the tabs.Create tabs that are full width of the PCB. Suitable for PCBs separated by V-Cuts. This mode does not make much sense for mousebites in practice. Note that in this mode the cuts do not faithfully copy the PCB outline and, instead, they cut the bounding box of the PCB. There are no other options.
cutout
: When your design features open pockets on the side, this parameter specifies extra cutout depth in order to ensure that a sharp corner of the pocket can be milled. The default is 1\u00a0mm.patchcorners
: The full tabs are appended to the nearest flat face of the PCB. If the PCB has sharp corners, you want to add patches of substrate to these corners. However, if the PCB has fillet or miter, you don't want to apply the patches.Create tabs in the corners of the PCB.
width
: The width of tabsAdd tabs based on PCB annotations. Place a footprint kikit:Tab
at the edges of your PCB. You can edit the text field prefixed with KIKIT:
to adjust the tab parameters. If you want to specify a custom tab symbol (e.g., with predefined) width, you can specify tabfootprints
as a list of footprints separated by comma. For example: myLib:Tab2mm, myLib:Tab3mm
.
The individual tabs can have the following properties specified in the text field of the component as KIKIT:<propertyname>
:
width
: width of the tab.Tabs based on a plugin.
code
: the plugin specification. See (plugin documentation)[plugin.md] for more detailsarg
: text argument for the user pluginSpecify how to perform the cuts on the tabs separating the board.
Types: none, mousebites, vcuts, layer, plugin
"},{"location":"panelization/cli/#none","title":"None","text":"Do not perform any cuts
"},{"location":"panelization/cli/#mousebites","title":"Mousebites","text":"Use mousebites to
drill
- specify drill size for the bitesspacing
- specify the spacing of the holesoffset
- specify the offset, positive offset puts the cuts into the board, negative puts the cuts into the tabsprolong
- distance for tangential prolongation of the cuts (to cut through the internal corner fillets caused by milling)clearance
- specify clearance for copper around V-cutscutcurves
- true/false - specify if curves should be approximated by straight cuts (e.g., for cutting tabs on circular boards)offset
- specify the offset, positive offset puts the cuts into the board, negative puts the cuts into the tabslayer
- specify the layer to render V-cuts on.linewidth
- specify linewidthendprolongation
- prolongation of the cut line from the board line on the side without text.textprolongation
- the same as above, just on the text sidetextoffset
- offset of the text from the cut linetemplate
- a string template for text to render. Can contain variables listed below, e.g., V-CUT {pos_mm}
.pos_mm
, pos_inch
\u2013 position of the V-cut from the panel originpos_inv_mm
, pos_inv_inch
\u2013 inverted position of the V-cut from the panel originWhen KiKit reports it cannot perform cuts, you can render the cuts into a layer with this option to understand what's going on. Shouldn't be used for the final design.
layer
- specify the layer to render the cuts on.prolong
- distance for tangential prolongation of the cuts. It has the same meaning as mousebites.linewidth
- width of line to renderCuts based on a plugin.
code
: the plugin specification. See (plugin documentation)[plugin.md] for more detailsarg
: text argument for the user pluginKiKit allows you to frame the panel with a full frame, or bottom/top or left/right rails.
Types: none, railstb, railslr, frame, tightframe, plugin Common options:
hspace
, vspace
, space
- specify the space between PCB and the frame/rail. space
overrides hspace and vspace
.width
- specify with of the rails or framefillet
, chamfer
- fillet/chamfer frame corners. Specify radius or chamfer size. You can also separately specify chamferwidth
and chamferheight
to create a non 45\u00b0 chamfer.mintotalheight
, mintotalwidth
\u2013 if needed, add extra material to the rail or frame to meet the minimal requested size. Useful for services that require minimal panel size.Add rail (either on top and bottom or on left and right) to the panel.
"},{"location":"panelization/cli/#frame","title":"Frame","text":"Add a frame around the board.
cuts
- one of none
, both
, v
, h
- specify whether to add cuts to the corners of the frame for easy removal. Default both
.Add a frame around the board which fills the whole area of the panel - the boards have just a milled slot around their perimeter.
slotwidth
- width of the milled slot.Frame based on a plugin.
code
: the plugin specification. See (plugin documentation)[plugin.md] for more detailsarg
: text argument for the user pluginAdd tooling holes to the (rail/frame of) the panel. The holes are positioned by
Types: none, 3hole, 4hole, plugin
Common options:
hoffset
, voffset
- specify the offset from from panel edgessize
- diameter of the holespaste
- if true, the holes are included in the paste layer (therefore they appear on the stencil).solderMaskMargin
- diameter of solder mask (optional)Tooling based on a plugin.
code
: the plugin specification. See (plugin documentation)[plugin.md] for more detailsarg
: text argument for the user pluginAdd fiducial to the (rail/frame of) the panel.
Types: none, 3fid, 4fid, plugin
Common options:
hoffset
, voffset
- specify the offset from from panel edgescoppersize
, opening
- diameter of the copper spot and solder mask openingpaste
- if true, the fiducials are included in the paste layer (therefore they appear on the stencil).Fiducials based on a plugin.
code
: the plugin specification. See (plugin documentation)[plugin.md] for more detailsarg
: text argument for the user pluginAdd text to the panel. Allows you to put a single block of text on panel. You can use variables enclosed in {}
. E.g. {boardTitle} | {boardDate}
. The list of all available variables in listed bellow. You can also use the variables specified in the project. They are prefixed with user-
. That is, to include your variable revision
in KiKit text, use formatting string Rev: {user-revision}
. In the case you need more independent texts on the panel, you can use sections names text2
, text3
and text3
to add at most 4 text. All these sections behave the same and accept the same options.
If you need more texts or more sophisticated placing options, see script
option from postprocess
.
Types: none, simple
Common options:
text
- The text to be displayed. Note that you can escape ;
via \\
anchor
- Origin of the text. Can be one of tl
, tr
, bl
, br
(corners), mt
, mb
, ml
, mr
(middle of sides), c
(center). The anchors refer to the panel outline. Default mt
hoffset
, voffset
- specify the offset from anchor. Respects KiCAD coordinate system. Default 0mm
.orientation
- specify the orientation (angle). Default 0deg
width
, height
- width and height of the characters (the same parameters as KiCAD uses). Default 1.5mm
.hjustify
- justification of the text. One of left
, right
, center
. Default center
.vjustify
- justification of the text. One of top
, bottom
, center
. Default center
thickness
- stroke thickness. Default 0.3mm
.layer
- specify text layerplugin
- specify the plugin that provides extra variables for the textdate
- formats current date as <year>-<month>-<day>
time24
- formats current time in 24-hour formatyear
, month
, day
, hour
, minute
, second
- individual variables for any date formatboardTitle
- the title from the source boardboardDate
- the date from the source boardboardRevision
- the revision from the source boardboardCompany
- the company from the source boardboardComment1
-boardComment9
- comments from the source boardYou can get extra variables by providing custom text plugin via the plugin
field.
Sets page size on the resulting panel and position the panel in the page. The type of style dictates paper size. The default inherit
option inherits paper size from the source board. This feature is not supported on KiCAD 5
Types: inherit
, custom
, A0
, A1
, A2
, A3
, A4
, A5
, A
, B
, C
, D
, E
, USLetter
, USLegal
, USLedger
, A0-portrait
, A1-portrait
, A2-portrait
, A3-portrait
, A4-portrait
, A5-portrait
, A-portrait
, B-portrait
, C-portrait
, D-portrait
, E-portrait
, USLetter-portrait
, USLegal-portrait
, USLedger-portrait
Common options:
anchor
- Point of the panel to be placed at given position. Can be one of tl
, tr
, bl
, br
(corners), mt
, mb
, ml
, mr
(middle of sides), c
(center). The anchors refer to the panel outline. Default mt
posx
, posy
- the position of the panel on the page. Default 50%
for posx
and 20mm
for posy
.Instead of the pre-defined paper size you can also specify a custom paper size via width
and height
.
Fill non-board areas of the panel with copper.
Types: none, solid, hatched, hex
Common options:
clearance
- optional extra clearance from the board perimeters. Suitable for, e.g., not filling the tabs with copper.edgeclearance
- specifies clearance between the fill and panel perimeter.layers
- comma-separated list of layer to fill. Default top and bottom. You can specify a shortcut all
to fill all layers.Fill with solid copper.
"},{"location":"panelization/cli/#hatched","title":"Hatched","text":"Use hatch pattern for the fill.
width
- the width of the strokesspacing
- the space between the strokesorientation
- the orientation of the strokesUse hexagon pattern for the fill.
diameter
\u2013 diameter of the hexagonsspacing
\u2013 space between the hexagonsthreshold
\u2013 a percentage value that will discard fragments smaller than given thresholdFinishing touches to the panel.
Types: auto
Common options:
copperfill
- fill tabs and frame with copper (e.g., to save etchant or to increase rigidity of flex-PCB panels)millradius
- simulate the milling operation (add fillets to the internal corners). Specify mill radius (usually 1 mm). 0 radius disables the functionality.millradiusouter
\u00ad\u2013 same as the previous one, modifies only board outer counter. No internal features of the board are affected.reconstructarcs
- the panelization process works on top of a polygonal representation of the board. This options allows to reconstruct the arcs in the design before saving the panel.refillzones
\u2013 refill the user zones after the panel is build. This is only necessary when you want your zones to avoid cuts in panel.script
- a path to custom Python file. The file should contain a function kikitPostprocess(panel, args)
that receives the prepared panel as the kikit.panelize.Panel
object and the user-supplied arguments as a string - see scriptarg
. The function can make arbitrary changes to the panel - you can append text, footprints, alter labels, etc. The function is invoked after the whole panel is constructed (including all other postprocessing). If you try to add a functionality for a common fabrication houses via scripting, consider submitting PR for KiKit.scriptarg
: An arbitrary string passed to the user post-processing script specified in script
origin
- specify if the auxilary origin an grid origin should be placed. Can be one of tl
, tr
, bl
, br
(corners), mt
, mb
, ml
, mr
(middle of sides), c
(center). Empty string does not changes the origin.dimensions
- true
or false
. Draw dimensions with the panel size.edgewidth
\u00ad\u2013 width of the line for panel edges (that is the lines in the Edge.Cuts
layer).This document will show you several examples of KiKit CLI for panelization. Note that this is not an exhaustive description of everything that KiKit can do, nor proper documentation. For further details, please refer to:
We will show everything on a single board located in docs/resources/conn.kicad_pcb
. The board looks like this when rendered via PcbDraw:
Let's start with our first panel.
Panelization command
Linux/macOSWindowskikit panelize \\\n --layout 'grid; rows: 2; cols: 2;' \\\n --tabs full \\\n --cuts vcuts \\\n docs/resources/conn.kicad_pcb panel.kicad_pcb\n
kikit panelize ^\n --layout \"grid; rows: 2; cols: 2;\" ^\n --tabs full ^\n --cuts vcuts ^\n docs/resources/conn.kicad_pcb panel.kicad_pcb\n
We specified that we want 2x2 panel, no space between board and separate them by V-cuts. We also specified that we want to build full tabs (although no tabs are visible in this example). This is ,however, essential \u2013 if we omitted tabs, no cuts between the boards would be performed. Note, that due to the rounded corners, this panel cannot be manufactured. We will fix it later.
Note that the \\
in the input is there to make shell happy, so we can break our command into multiple lines. Also note that there are single quotes around the key-value pair \u2013 again, to make shell happy and to interpret a string with spaces as a single option.
Note that on Windows you have the enter the commands into KiCAD Command Prompt instead of the regular Command Prompt. You can find it under the Start menu.
Also note that KiKit accepts all options in categories (e.g., layout
, tabs
, cuts
, ...). You can specify the parameters as a semicolon-separated key-value list. To learn about the precise syntax of the CLI and about all options, please refer to \u2013 documentation.
One side note \u2013 if you try it with your own board some components might be gone. KiKit respects the KiCAD component selection criteria. When you specify an input rectangle, only the components that fully fit inside the input rectangle are selected. This however take in account both name and value labels (even when they are hidden).
When you do not specify the source are explicitly, KiKit takes the board outline bounding box as the source area. Therefore, by default, components outside the board substrate are not copied to panel.
Note that this is intended behavior; for once it is consistent with KiCAD behavior of user selection and also it allows to easily ignore surrounding comments and drawings in the board sheet (it makes no sense to have 12 same copies of the notes around the board).
How to include the missing components? - specify the source area explicitly to include all your components - specify --source 'tolerance: 10mm'
to enlarge the board outline bounding box by e.g. 10 mm. The default value is 1 mm.
I told you that the panel above is not suitable for manufacturing. Let's see why:
Panelization command
Linux/macOSWindowskikit panelize \\\n --layout 'grid; rows: 2; cols: 2;' \\\n --tabs full \\\n --cuts vcuts \\\n --post 'millradius: 1mm' \\\n docs/resources/conn.kicad_pcb panel.kicad_pcb\n
kikit panelize ^\n --layout \"grid; rows: 2; cols: 2;\" ^\n --tabs full ^\n --cuts vcuts ^\n --post \"millradius: 1mm\" ^\n docs/resources/conn.kicad_pcb panel.kicad_pcb\n
We specified a milling simulation post-processing. This simulates the milling operation in the fab house. As you can see, the sharp internal corners cannot be manufactured. I recommend you to use milling postprocessing always \u2013 you can easily see if your cuts are off or you have too narrow slots in your design.
Usually, one would use full tabs only for rectangular boards. Usually, when you have rounded corners, you will use short tabs instead and add some space between the boards. So let's fix it:
Panelization command
Linux/macOSWindowskikit panelize \\\n --layout 'grid; rows: 2; cols: 2; space: 2mm' \\\n --tabs 'fixed; hwidth: 10mm; vwidth: 15mm' \\\n --cuts vcuts \\\n --post 'millradius: 1mm' \\\n docs/resources/conn.kicad_pcb panel.kicad_pcb\n
kikit panelize ^\n --layout \"grid; rows: 2; cols: 2; space: 2mm\" ^\n --tabs \"fixed; hwidth: 10mm; vwidth: 15mm\" ^\n --cuts vcuts ^\n --post \"millradius: 1mm\" ^\n docs/resources/conn.kicad_pcb panel.kicad_pcb\n
In that way, the rounded corners can be machined. Lets' see the same example with mousebites instead:
Panelization command
Linux/macOSWindowskikit panelize \\\n --layout 'grid; rows: 2; cols: 2; space: 2mm' \\\n --tabs 'fixed; width: 5mm' \\\n --cuts 'mousebites; drill: 0.5mm; spacing: 1mm; offset: 0.2mm' \\\n docs/resources/conn.kicad_pcb panel.kicad_pcb\n
kikit panelize ^\n --layout \"grid; rows: 2; cols: 2; space: 2mm\" ^\n --tabs \"fixed; width: 5mm\" ^\n --cuts \"mousebites; drill: 0.5mm; spacing: 1mm; offset: 0.2mm\" ^\n docs/resources/conn.kicad_pcb panel.kicad_pcb\n
We changed cut type to mousebites and we specified that they should be performed by 0.5mm holes with a spacing of 1 mm. You could also use inches if you want \u2013 just specify `in. Since we use mousebites, we used narrower tabs. We also specified that the cuts should be inset 0.25 mm into the board outline. This is suitable when your board should fit into a cover \u2013 when you break away the tabs, all burs will be inside the intended board outline.
What happens, when we simulate the milling operation?
Panelization command
Linux/macOSWindowskikit panelize \\\n --layout 'grid; rows: 2; cols: 2; space: 2mm' \\\n --tabs 'fixed; width: 5mm' \\\n --cuts 'mousebites; drill: 0.5mm; spacing: 1mm; offset: 0.2mm' \\\n --post 'millradius: 1mm' \\\n docs/resources/conn.kicad_pcb panel.kicad_pcb\n
kikit panelize ^\n --layout \"grid; rows: 2; cols: 2; space: 2mm\" ^\n --tabs \"fixed; width: 5mm\" ^\n --cuts \"mousebites; drill: 0.5mm; spacing: 1mm; offset: 0.2mm\" ^\n --post \"millradius: 1mm\" ^\n docs/resources/conn.kicad_pcb panel.kicad_pcb\n
See? The cuts are somewhat short. This is due to the internal corners that cannot be milled. KiKit can fix that for you \u2013 just specify you want to prolong your cuts tangentially by a small amount:
Panelization command
Linux/macOSWindowskikit panelize \\\n --layout 'grid; rows: 2; cols: 2; space: 2mm' \\\n --tabs 'fixed; width: 3mm' \\\n --cuts 'mousebites; drill: 0.5mm; spacing: 1mm; offset: 0.2mm; prolong: 0.5mm' \\\n --post 'millradius: 1mm' \\\n docs/resources/conn.kicad_pcb panel.kicad_pcb\n
kikit panelize ^\n --layout \"grid; rows: 2; cols: 2; space: 2mm\" ^\n --tabs \"fixed; width: 3mm\" ^\n --cuts \"mousebites; drill: 0.5mm; spacing: 1mm; offset: 0.2mm; prolong: 0.5mm\" ^\n --post \"millradius: 1mm\" ^\n docs/resources/conn.kicad_pcb panel.kicad_pcb\n
If you want, you can also specify a number of tabs to generate. KiKit will place them evenly:
Panelization command
Linux/macOSWindowskikit panelize \\\n --layout 'grid; rows: 2; cols: 2; space: 2mm' \\\n --tabs 'fixed; width: 3mm; vcount: 2' \\\n --cuts 'mousebites; drill: 0.5mm; spacing: 1mm; offset: 0.2mm; prolong: 0.5mm' \\\n --post 'millradius: 1mm' \\\n docs/resources/conn.kicad_pcb panel.kicad_pcb\n
kikit panelize ^\n --layout \"grid; rows: 2; cols: 2; space: 2mm\" ^\n --tabs \"fixed; width: 3mm; vcount: 2\" ^\n --cuts \"mousebites; drill: 0.5mm; spacing: 1mm; offset: 0.2mm; prolong: 0.5mm\" ^\n --post \"millradius: 1mm\" ^\n docs/resources/conn.kicad_pcb panel.kicad_pcb\n
You can also append frame or rails to the panel. Frames and rail are useful in the following situations:
Let's start with rails:
Panelization command
Linux/macOSWindowskikit panelize \\\n --layout 'grid; rows: 2; cols: 2; space: 2mm' \\\n --tabs 'fixed; width: 3mm; vcount: 2' \\\n --cuts 'mousebites; drill: 0.5mm; spacing: 1mm; offset: 0.2mm; prolong: 0.5mm' \\\n --framing 'railstb; width: 5mm; space: 3mm;' \\\n --post 'millradius: 1mm' \\\n docs/resources/conn.kicad_pcb panel.kicad_pcb\n
kikit panelize ^\n --layout \"grid; rows: 2; cols: 2; space: 2mm\" ^\n --tabs \"fixed; width: 3mm; vcount: 2\" ^\n --cuts \"mousebites; drill: 0.5mm; spacing: 1mm; offset: 0.2mm; prolong: 0.5mm\" ^\n --framing \"railstb; width: 5mm; space: 3mm;\" ^\n --post \"millradius: 1mm\" ^\n docs/resources/conn.kicad_pcb panel.kicad_pcb\n
Similarly, you can add left and right rail via the railslr
type. If you want a full frame, use the type frame
. When you place a full frame, it might make sense to include cuts in the corner of the frame, so you can break it apart easily. Let's see an example:
Panelization command
Linux/macOSWindowskikit panelize \\\n --layout 'grid; rows: 2; cols: 2; space: 2mm' \\\n --tabs 'fixed; width: 3mm; vcount: 2' \\\n --cuts 'mousebites; drill: 0.5mm; spacing: 1mm; offset: 0.2mm; prolong: 0.5mm' \\\n --framing 'frame; width: 5mm; space: 3mm; cuts: both' \\\n --post 'millradius: 1mm' \\\n docs/resources/conn.kicad_pcb panel.kicad_pcb\n
kikit panelize ^\n --layout \"grid; rows: 2; cols: 2; space: 2mm\" ^\n --tabs \"fixed; width: 3mm; vcount: 2\" ^\n --cuts \"mousebites; drill: 0.5mm; spacing: 1mm; offset: 0.2mm; prolong: 0.5mm\" ^\n --framing \"frame; width: 5mm; space: 3mm; cuts: both\" ^\n --post \"millradius: 1mm\" ^\n docs/resources/conn.kicad_pcb panel.kicad_pcb\n
Note that you can also use just only a vertical or horizontal frame cuts:
Panelization command
Linux/macOSWindowskikit panelize \\\n --layout 'grid; rows: 2; cols: 2; space: 2mm' \\\n --tabs 'fixed; width: 3mm; vcount: 2' \\\n --cuts 'mousebites; drill: 0.5mm; spacing: 1mm; offset: 0.2mm; prolong: 0.5mm' \\\n --framing 'frame; width: 5mm; space: 3mm; cuts: h' \\\n --post 'millradius: 1mm' \\\n docs/resources/conn.kicad_pcb panel.kicad_pcb\n
kikit panelize ^\n --layout \"grid; rows: 2; cols: 2; space: 2mm\" ^\n --tabs \"fixed; width: 3mm; vcount: 2\" ^\n --cuts \"mousebites; drill: 0.5mm; spacing: 1mm; offset: 0.2mm; prolong: 0.5mm\" ^\n --framing \"frame; width: 5mm; space: 3mm; cuts: h\" ^\n --post \"millradius: 1mm\" ^\n docs/resources/conn.kicad_pcb panel.kicad_pcb\n
When you use V-cuts it might make sense to not remove all material, but only mill a slot around the board of the board. This yields a stronger panel \u2013 and some manufacturers require such style for assembly with V-Cuts. This is achieved via framing type tightframe
. Note that it does not make much sense with mousebites.
Panelization command
Linux/macOSWindowskikit panelize \\\n --layout 'grid; rows: 2; cols: 2; space: 6mm' \\\n --tabs 'fixed; width: 3mm; vcount: 2' \\\n --cuts vcuts \\\n --framing 'tightframe; width: 5mm; space: 3mm; ' \\\n --post 'millradius: 1mm' \\\n docs/resources/conn.kicad_pcb panel.kicad_pcb\n
kikit panelize ^\n --layout \"grid; rows: 2; cols: 2; space: 6mm\" ^\n --tabs \"fixed; width: 3mm; vcount: 2\" ^\n --cuts vcuts ^\n --framing \"tightframe; width: 5mm; space: 3mm; \" ^\n --post \"millradius: 1mm\" ^\n docs/resources/conn.kicad_pcb panel.kicad_pcb\n
Once we have a frame, we can append a tooling holes, fiducials and some text to it:
Panelization command
Linux/macOSWindowskikit panelize \\\n --layout 'grid; rows: 2; cols: 2; space: 2mm' \\\n --tabs 'fixed; width: 3mm; vcount: 2' \\\n --cuts 'mousebites; drill: 0.5mm; spacing: 1mm; offset: 0.2mm; prolong: 0.5mm' \\\n --framing 'railstb; width: 5mm; space: 3mm;' \\\n --tooling '3hole; hoffset: 2.5mm; voffset: 2.5mm; size: 1.5mm' \\\n --fiducials '3fid; hoffset: 5mm; voffset: 2.5mm; coppersize: 2mm; opening: 1mm;' \\\n --text 'simple; text: yaqwsx's panel; anchor: mt; voffset: 2.5mm; hjustify: center; vjustify: center;' \\\n --post 'millradius: 1mm' \\\n docs/resources/conn.kicad_pcb panel.kicad_pcb\n
kikit panelize ^\n --layout \"grid; rows: 2; cols: 2; space: 2mm\" ^\n --tabs \"fixed; width: 3mm; vcount: 2\" ^\n --cuts \"mousebites; drill: 0.5mm; spacing: 1mm; offset: 0.2mm; prolong: 0.5mm\" ^\n --framing \"railstb; width: 5mm; space: 3mm;\" ^\n --tooling \"3hole; hoffset: 2.5mm; voffset: 2.5mm; size: 1.5mm\" ^\n --fiducials \"3fid; hoffset: 5mm; voffset: 2.5mm; coppersize: 2mm; opening: 1mm;\" ^\n --text \"simple; text: yaqwsx's panel; anchor: mt; voffset: 2.5mm; hjustify: center; vjustify: center;\" ^\n --post \"millradius: 1mm\" ^\n docs/resources/conn.kicad_pcb panel.kicad_pcb\n
If you want to add text to both rails, you can use section --text2
to add a second text. You can also use variables enclosed in curly brackets ({}
). The list of supported variables is listed in the documentation. Also, plugins can introduce new variables.
Panelization command
Linux/macOSWindowskikit panelize \\\n --layout 'grid; rows: 2; cols: 2; space: 2mm' \\\n --tabs 'fixed; width: 3mm; vcount: 2' \\\n --cuts 'mousebites; drill: 0.5mm; spacing: 1mm; offset: 0.2mm; prolong: 0.5mm' \\\n --framing 'railstb; width: 5mm; space: 3mm;' \\\n --tooling '3hole; hoffset: 2.5mm; voffset: 2.5mm; size: 1.5mm' \\\n --fiducials '3fid; hoffset: 5mm; voffset: 2.5mm; coppersize: 2mm; opening: 1mm;' \\\n --text 'simple; text: yaqwsx's panel; anchor: mt; voffset: 2.5mm; hjustify: center; vjustify: center;' \\\n --text2 'simple; text: Created on {date}; anchor: mb; voffset: -2.5mm; hjustify: center; vjustify: center;' \\\n --post 'millradius: 1mm' \\\n docs/resources/conn.kicad_pcb panel.kicad_pcb\n
kikit panelize ^\n --layout \"grid; rows: 2; cols: 2; space: 2mm\" ^\n --tabs \"fixed; width: 3mm; vcount: 2\" ^\n --cuts \"mousebites; drill: 0.5mm; spacing: 1mm; offset: 0.2mm; prolong: 0.5mm\" ^\n --framing \"railstb; width: 5mm; space: 3mm;\" ^\n --tooling \"3hole; hoffset: 2.5mm; voffset: 2.5mm; size: 1.5mm\" ^\n --fiducials \"3fid; hoffset: 5mm; voffset: 2.5mm; coppersize: 2mm; opening: 1mm;\" ^\n --text \"simple; text: yaqwsx's panel; anchor: mt; voffset: 2.5mm; hjustify: center; vjustify: center;\" ^\n --text2 \"simple; text: Created on {date}; anchor: mb; voffset: -2.5mm; hjustify: center; vjustify: center;\" ^\n --post \"millradius: 1mm\" ^\n docs/resources/conn.kicad_pcb panel.kicad_pcb\n
There are many options for text and fiducials. Be sure to read the full documentation.
If you have an automatic feeder in your PNP machine or you just dislike sharp corners, you can add a chamfer or a fillet to the panel frame/rails:
Panelization command
Linux/macOSWindowskikit panelize \\\n --layout 'grid; rows: 2; cols: 2; space: 2mm' \\\n --tabs 'fixed; width: 3mm; vcount: 2' \\\n --cuts 'mousebites; drill: 0.5mm; spacing: 1mm; offset: 0.2mm; prolong: 0.5mm' \\\n --framing 'railstb; width: 5mm; space: 3mm; fillet: 1mm' \\\n --tooling '3hole; hoffset: 2.5mm; voffset: 2.5mm; size: 1.5mm' \\\n --fiducials '3fid; hoffset: 5mm; voffset: 2.5mm; coppersize: 2mm; opening: 1mm;' \\\n --post 'millradius: 1mm' \\\n docs/resources/conn.kicad_pcb panel.kicad_pcb\n
kikit panelize ^\n --layout \"grid; rows: 2; cols: 2; space: 2mm\" ^\n --tabs \"fixed; width: 3mm; vcount: 2\" ^\n --cuts \"mousebites; drill: 0.5mm; spacing: 1mm; offset: 0.2mm; prolong: 0.5mm\" ^\n --framing \"railstb; width: 5mm; space: 3mm; fillet: 1mm\" ^\n --tooling \"3hole; hoffset: 2.5mm; voffset: 2.5mm; size: 1.5mm\" ^\n --fiducials \"3fid; hoffset: 5mm; voffset: 2.5mm; coppersize: 2mm; opening: 1mm;\" ^\n --post \"millradius: 1mm\" ^\n docs/resources/conn.kicad_pcb panel.kicad_pcb\n
Panelization command
Linux/macOSWindowskikit panelize \\\n --layout 'grid; rows: 2; cols: 2; space: 2mm' \\\n --tabs 'fixed; width: 3mm; vcount: 2' \\\n --cuts 'mousebites; drill: 0.5mm; spacing: 1mm; offset: 0.2mm; prolong: 0.5mm' \\\n --framing 'railstb; width: 5mm; space: 3mm; chamfer: 1mm' \\\n --tooling '3hole; hoffset: 2.5mm; voffset: 2.5mm; size: 1.5mm' \\\n --fiducials '3fid; hoffset: 5mm; voffset: 2.5mm; coppersize: 2mm; opening: 1mm;' \\\n --post 'millradius: 1mm' \\\n docs/resources/conn.kicad_pcb panel.kicad_pcb\n
kikit panelize ^\n --layout \"grid; rows: 2; cols: 2; space: 2mm\" ^\n --tabs \"fixed; width: 3mm; vcount: 2\" ^\n --cuts \"mousebites; drill: 0.5mm; spacing: 1mm; offset: 0.2mm; prolong: 0.5mm\" ^\n --framing \"railstb; width: 5mm; space: 3mm; chamfer: 1mm\" ^\n --tooling \"3hole; hoffset: 2.5mm; voffset: 2.5mm; size: 1.5mm\" ^\n --fiducials \"3fid; hoffset: 5mm; voffset: 2.5mm; coppersize: 2mm; opening: 1mm;\" ^\n --post \"millradius: 1mm\" ^\n docs/resources/conn.kicad_pcb panel.kicad_pcb\n
Some services, e.g., JLC PCB require a minimal panel size. If you want to ensure that your panel meets the criteria, you can specify minimal total width/height of the panel. Let's see an example:
Panelization command
Linux/macOSWindowskikit panelize \\\n --layout 'grid; rows: 2; cols: 2; space: 2mm' \\\n --tabs 'fixed; width: 3mm; vcount: 2' \\\n --cuts 'mousebites; drill: 0.5mm; spacing: 1mm; offset: 0.2mm; prolong: 0.5mm' \\\n --framing 'frame; width: 5mm; space: 3mm; mintotalheight: 100mm; mintotalwidth: 100mm' \\\n --tooling '3hole; hoffset: 2.5mm; voffset: 2.5mm; size: 1.5mm' \\\n --fiducials '3fid; hoffset: 5mm; voffset: 2.5mm; coppersize: 2mm; opening: 1mm;' \\\n --text 'simple; text: yaqwsx's panel with minimal dimensions; anchor: mt; voffset: 2.5mm; hjustify: center; vjustify: center;' \\\n --post 'millradius: 1mm' \\\n docs/resources/conn.kicad_pcb panel.kicad_pcb\n
kikit panelize ^\n --layout \"grid; rows: 2; cols: 2; space: 2mm\" ^\n --tabs \"fixed; width: 3mm; vcount: 2\" ^\n --cuts \"mousebites; drill: 0.5mm; spacing: 1mm; offset: 0.2mm; prolong: 0.5mm\" ^\n --framing \"frame; width: 5mm; space: 3mm; mintotalheight: 100mm; mintotalwidth: 100mm\" ^\n --tooling \"3hole; hoffset: 2.5mm; voffset: 2.5mm; size: 1.5mm\" ^\n --fiducials \"3fid; hoffset: 5mm; voffset: 2.5mm; coppersize: 2mm; opening: 1mm;\" ^\n --text \"simple; text: yaqwsx's panel with minimal dimensions; anchor: mt; voffset: 2.5mm; hjustify: center; vjustify: center;\" ^\n --post \"millradius: 1mm\" ^\n docs/resources/conn.kicad_pcb panel.kicad_pcb\n
"},{"location":"panelization/examples/#advanced-features-layouts","title":"Advanced features & layouts","text":"It is possible that you have some critical features you want to avoid with tabs. KiKit has several features that can help you. Let's start with the simple ones.
First, you can rotate the boards in your layout. This might make not much sense for rectanglar boards, but it might save you when you have circular or oddly shaped boards:
Panelization command
Linux/macOSWindowskikit panelize \\\n --layout 'grid; rows: 2; cols: 2; space: 0mm; rotation: 45deg;' \\\n --tabs 'fixed; width: 3mm;' \\\n --cuts 'mousebites; drill: 0.5mm; spacing: 1mm; offset: 0.2mm; prolong: 0.75mm' \\\n --framing 'frame; width: 5mm; space: 3mm; cuts: both' \\\n --post 'millradius: 1mm' \\\n docs/resources/conn.kicad_pcb panel.kicad_pcb\n
kikit panelize ^\n --layout \"grid; rows: 2; cols: 2; space: 0mm; rotation: 45deg;\" ^\n --tabs \"fixed; width: 3mm;\" ^\n --cuts \"mousebites; drill: 0.5mm; spacing: 1mm; offset: 0.2mm; prolong: 0.75mm\" ^\n --framing \"frame; width: 5mm; space: 3mm; cuts: both\" ^\n --post \"millradius: 1mm\" ^\n docs/resources/conn.kicad_pcb panel.kicad_pcb\n
When your board has a connector sticking one one side of the board, it makes sense to rotate the boards every other column, row or combination of both. KiKit supports this via layout option alternation
. You should be careful about component references when rotating boards \u2013 KiCAD's references have a property \"Stay upright\" which makes them always face up (even when placed on a panel). So be sure to turn it off before panelizing. Here's an example:
Panelization command
Linux/macOSWindowskikit panelize \\\n --layout 'grid; rows: 2; cols: 2; space: 3mm; alternation: cols;' \\\n --tabs 'fixed; width: 3mm; vcount: 2' \\\n --cuts 'mousebites; drill: 0.5mm; spacing: 1mm; offset: 0.2mm; prolong: 0.5mm' \\\n --framing 'frame; width: 5mm; space: 3mm; cuts: both' \\\n --post 'millradius: 1mm' \\\n docs/resources/conn.kicad_pcb panel.kicad_pcb\n
kikit panelize ^\n --layout \"grid; rows: 2; cols: 2; space: 3mm; alternation: cols;\" ^\n --tabs \"fixed; width: 3mm; vcount: 2\" ^\n --cuts \"mousebites; drill: 0.5mm; spacing: 1mm; offset: 0.2mm; prolong: 0.5mm\" ^\n --framing \"frame; width: 5mm; space: 3mm; cuts: both\" ^\n --post \"millradius: 1mm\" ^\n docs/resources/conn.kicad_pcb panel.kicad_pcb\n
Another solution might be to not put tabs on, e.g., vertical edges of the PCB. However, in that case your panel might be weak for further assembly. You can make it more stiff by including backbones \u2013 a full piece of substrate between the panels. You can add either vertical, horizontal or both backbones. Also, similarly with frames, you can put cuts on your backbone to make depanelization of your boards easier. Enough theory, let's see an example
Panelization command
Linux/macOSWindowskikit panelize \\\n --layout 'grid; rows: 2; cols: 2; space: 2mm; hbackbone: 5mm; hbonecut: true' \\\n --tabs 'fixed; width: 3mm; vcount: 2; hcount: 0' \\\n --cuts 'mousebites; drill: 0.5mm; spacing: 1mm; offset: 0.2mm; prolong: 0.5mm' \\\n --framing 'railstb; width: 5mm; space: 3mm;' \\\n --post 'millradius: 1mm' \\\n docs/resources/conn.kicad_pcb panel.kicad_pcb\n
kikit panelize ^\n --layout \"grid; rows: 2; cols: 2; space: 2mm; hbackbone: 5mm; hbonecut: true\" ^\n --tabs \"fixed; width: 3mm; vcount: 2; hcount: 0\" ^\n --cuts \"mousebites; drill: 0.5mm; spacing: 1mm; offset: 0.2mm; prolong: 0.5mm\" ^\n --framing \"railstb; width: 5mm; space: 3mm;\" ^\n --post \"millradius: 1mm\" ^\n docs/resources/conn.kicad_pcb panel.kicad_pcb\n
Often, not all backbones are needed. Especially for larger panels. Therefore, if you want, you can skip some of them. Consider the following 4\u00d74 panel with only ever other backbone:
Panelization command
Linux/macOSWindowskikit panelize \\\n --layout 'grid; rows: 4; cols: 4; space: 2mm; hbackbone: 5mm; vbackbone: 5mm; hboneskip: 1; vboneskip: 1' \\\n --tabs 'fixed; width: 3mm; vcount: 2; hcount: 0' \\\n --cuts 'mousebites; drill: 0.5mm; spacing: 1mm; offset: 0.2mm; prolong: 0.5mm' \\\n --framing 'railstb; width: 5mm; space: 3mm;' \\\n --post 'millradius: 1mm' \\\n docs/resources/conn.kicad_pcb panel.kicad_pcb\n
kikit panelize ^\n --layout \"grid; rows: 4; cols: 4; space: 2mm; hbackbone: 5mm; vbackbone: 5mm; hboneskip: 1; vboneskip: 1\" ^\n --tabs \"fixed; width: 3mm; vcount: 2; hcount: 0\" ^\n --cuts \"mousebites; drill: 0.5mm; spacing: 1mm; offset: 0.2mm; prolong: 0.5mm\" ^\n --framing \"railstb; width: 5mm; space: 3mm;\" ^\n --post \"millradius: 1mm\" ^\n docs/resources/conn.kicad_pcb panel.kicad_pcb\n
The most powerful feature of KiKit regarding tab placement are tabs via annotation. Remember our test board? When you open it in Pcbnew, you can see that there are some special footprints \u2013 KiKit's annotations:
They specify where to place tabs. You can even specify individual tab width via text property of the symbol. How to use it? Just specify tab type to annotation
. We also have to increase the source area tolerance, so it can capture the annotations.
Panelization command
Linux/macOSWindowskikit panelize \\\n --layout 'grid; rows: 2; cols: 2; space: 5mm;' \\\n --tabs annotation \\\n --source 'tolerance: 15mm' \\\n --cuts 'mousebites; drill: 0.5mm; spacing: 1mm; offset: 0.2mm; prolong: 0.5mm' \\\n --framing 'railstb; width: 5mm; space: 3mm;' \\\n --post 'millradius: 1mm' \\\n docs/resources/conn.kicad_pcb panel.kicad_pcb\n
kikit panelize ^\n --layout \"grid; rows: 2; cols: 2; space: 5mm;\" ^\n --tabs annotation ^\n --source \"tolerance: 15mm\" ^\n --cuts \"mousebites; drill: 0.5mm; spacing: 1mm; offset: 0.2mm; prolong: 0.5mm\" ^\n --framing \"railstb; width: 5mm; space: 3mm;\" ^\n --post \"millradius: 1mm\" ^\n docs/resources/conn.kicad_pcb panel.kicad_pcb\n
Well, the panel looks strange \u2013 right? That's because KiKit always constructs a half-bridges. When you specify the tabs location, you have to either ensure they match or put a piece of substrate they can reach \u2013 e.g., a backbone or a tightframe. If you are interested in the details, read more about tabs in section Understanding tabs. Let's fix it:
Panelization command
Linux/macOSWindowskikit panelize \\\n --layout 'grid; rows: 2; cols: 2; space: 2mm; hbackbone: 3mm; vbackbone: 3mm' \\\n --tabs annotation \\\n --source 'tolerance: 15mm' \\\n --cuts 'mousebites; drill: 0.5mm; spacing: 1mm; offset: 0.2mm; prolong: 0.5mm' \\\n --framing 'railstb; width: 5mm; space: 3mm;' \\\n --post 'millradius: 1mm' \\\n docs/resources/conn.kicad_pcb panel.kicad_pcb\n
kikit panelize ^\n --layout \"grid; rows: 2; cols: 2; space: 2mm; hbackbone: 3mm; vbackbone: 3mm\" ^\n --tabs annotation ^\n --source \"tolerance: 15mm\" ^\n --cuts \"mousebites; drill: 0.5mm; spacing: 1mm; offset: 0.2mm; prolong: 0.5mm\" ^\n --framing \"railstb; width: 5mm; space: 3mm;\" ^\n --post \"millradius: 1mm\" ^\n docs/resources/conn.kicad_pcb panel.kicad_pcb\n
Note that the annotation can have an arbitrary orientation. The arrow just must be outside board edge and points towards it. KiKit will also place only those tabs, that have a neighboring substrate. For precise algorithm, see section understanding tabs.
When you make flex PCBs or you want to save etchant, it make sense to pour copper on all non-functional parts of the panel. It will make the PCB rigid. You can do so via copperfill
section:
Panelization command
Linux/macOSWindowskikit panelize \\\n --layout 'grid; rows: 2; cols: 2; space: 2mm' \\\n --tabs 'fixed; width: 3mm;' \\\n --cuts 'mousebites; drill: 0.5mm; spacing: 1mm; offset: 0.2mm; prolong: 0.5mm' \\\n --framing 'railstb; width: 5mm; space: 3mm;' \\\n --copperfill solid \\\n --post 'millradius: 1mm;' \\\n docs/resources/conn.kicad_pcb panel.kicad_pcb\n
kikit panelize ^\n --layout \"grid; rows: 2; cols: 2; space: 2mm\" ^\n --tabs \"fixed; width: 3mm;\" ^\n --cuts \"mousebites; drill: 0.5mm; spacing: 1mm; offset: 0.2mm; prolong: 0.5mm\" ^\n --framing \"railstb; width: 5mm; space: 3mm;\" ^\n --copperfill solid ^\n --post \"millradius: 1mm;\" ^\n docs/resources/conn.kicad_pcb panel.kicad_pcb\n
When you use V-cuts with copperfill
you (or your fab house) might want to include a clearance around the V-cuts:
Panelization command
Linux/macOSWindowskikit panelize \\\n --layout 'grid; rows: 2; cols: 2; space: 2mm' \\\n --tabs 'fixed; hwidth: 10mm; vwidth: 15mm' \\\n --cuts 'vcuts; clearance: 1.5mm' \\\n --framing 'railstb; width: 5mm; space: 3mm;' \\\n --copperfill solid \\\n --post 'millradius: 1mm;' \\\n docs/resources/conn.kicad_pcb panel.kicad_pcb\n
kikit panelize ^\n --layout \"grid; rows: 2; cols: 2; space: 2mm\" ^\n --tabs \"fixed; hwidth: 10mm; vwidth: 15mm\" ^\n --cuts \"vcuts; clearance: 1.5mm\" ^\n --framing \"railstb; width: 5mm; space: 3mm;\" ^\n --copperfill solid ^\n --post \"millradius: 1mm;\" ^\n docs/resources/conn.kicad_pcb panel.kicad_pcb\n
If you, for example do not wish to cover the tabs with copper, you can also specify clearance. Also, some manufacturers don't like when you have large solid copper areas. In that case, you can use a hatch pattern to fill the area:
Panelization command
Linux/macOSWindowskikit panelize \\\n --layout 'grid; rows: 2; cols: 2; space: 2mm' \\\n --tabs 'fixed; width: 3mm;' \\\n --cuts 'mousebites; drill: 0.5mm; spacing: 1mm; offset: 0.2mm; prolong: 0.5mm' \\\n --framing 'railstb; width: 5mm; space: 3mm;' \\\n --copperfill 'hatched; clearance: 2mm; spacing: 0.5mm; width: 0.5mm' \\\n --post 'millradius: 1mm;' \\\n docs/resources/conn.kicad_pcb panel.kicad_pcb\n
kikit panelize ^\n --layout \"grid; rows: 2; cols: 2; space: 2mm\" ^\n --tabs \"fixed; width: 3mm;\" ^\n --cuts \"mousebites; drill: 0.5mm; spacing: 1mm; offset: 0.2mm; prolong: 0.5mm\" ^\n --framing \"railstb; width: 5mm; space: 3mm;\" ^\n --copperfill \"hatched; clearance: 2mm; spacing: 0.5mm; width: 0.5mm\" ^\n --post \"millradius: 1mm;\" ^\n docs/resources/conn.kicad_pcb panel.kicad_pcb\n
Note one last facts about V-cuts. V-cuts can only be straight and horizontal/vertical. But you can use them with circular boards if you want by cutting a little inside them. The option cutcurves
, that will approximate the cut by staring and ending point.
If you need something special; e.g., custom placement of tooling holes, multiple texts, etc. KiKit has you covered.
The CLI interface allows you to run a custom script over the final panel. The script can use KiKit Python interface to modify it. For the sake of simplicity, let's add a hole in the middle of the frame. Therefore, we write the following script:
from kikit.units import mm\nfrom kikit.common import toKiCADPoint\n\ndef kikitPostprocess(panel, arg):\n minx, miny, maxx, maxy = panel.panelBBox()\n position = toKiCADPoint(((minx + maxx) // 2, miny + 2 * mm))\n panel.addNPTHole(position, 3 * mm)\n
Then run KiKit:
Panelization command
Linux/macOSWindowskikit panelize \\\n --layout 'grid; rows: 2; cols: 2; space: 2mm' \\\n --tabs 'fixed; width: 3mm; vcount: 2' \\\n --cuts 'mousebites; drill: 0.5mm; spacing: 1mm; offset: 0.2mm; prolong: 0.5mm' \\\n --framing 'railstb; width: 5mm; space: 3mm;' \\\n --post 'millradius: 1mm; script: docs/resources/examplePost.py' \\\n docs/resources/conn.kicad_pcb panel.kicad_pcb\n
kikit panelize ^\n --layout \"grid; rows: 2; cols: 2; space: 2mm\" ^\n --tabs \"fixed; width: 3mm; vcount: 2\" ^\n --cuts \"mousebites; drill: 0.5mm; spacing: 1mm; offset: 0.2mm; prolong: 0.5mm\" ^\n --framing \"railstb; width: 5mm; space: 3mm;\" ^\n --post \"millradius: 1mm; script: docs/resources/examplePost.py\" ^\n docs/resources/conn.kicad_pcb panel.kicad_pcb\n
You can learn more about available functions from the comment in the source code or in the Python API reference. The basic concepts are summarized in the scripting guide.
If you implement a feature that your fab house requires (e.g., new tooling hole type), consider submitting a pull request for KiKit instead. I believe the others will benefit from it.
"},{"location":"panelization/examples/#managing-presets","title":"Managing presets","text":"The last section of this document is dedicated to management of presets. You can read the specification in the documentation for CLI. Here I would like to focus on practical examples.
As you should know from the documentation, the panelization preset is divided into sections; e. g., layout
, tabs
, etc. The key-value parameters in these sections can be specified via JSON files. In KiKit, you can specify these files via -p
option:
kikit panelize -p myPreset.json -p :<builtInPreset> <other parameters>
The parameters in the later specified presets override the parameters in the previously specified presets. This allows you to define a named piece-wise presets. Therefore, you can prepare various presets for mousebites \u2013 e.g., fineMousebites.json
and coarseMousebites.json
:
// fineMousebites.json\n{\n \"cuts\": {\n \"type\": \"mousebites\", \"drill\": \"0.5mm\", \"spacing\": \"0.9mm\", \"offset\":\n \"0.25mm\"\n }\n}\n\n// coarseMousebites.json\n{\n \"cuts\": {\n \"type\": \"mousebites\", \"drill\": \"0.3mm\", \"spacing\": \"0.2mm\", \"offset\":\n \"0.15mm\"\n }\n}\n
Then you can specify your panelization commands easily via:
kikit panelize -p fineMousebites.json <otheroptions>
Therefore, you can build a custom library of commonly used-options; e.g., per fabrication house. KiKit offers some built-in presets \u2013 see panelizePresets
. Note that the built-in preset default.json
is always used as a base and it specifies conservative default values so you can only override the options relevant for you.
To give you an example \u2013 with KiKit, you will no longer have to remember what diameter of tooling holes JLC PCB requires, just use:
kikit panelize -p :jlcTooling <otheroptions>
The panelization feature of KiKit is also available via GUI in the KiCAD's PCB editor (Pcbnew). The main use-case for the GUI is to quickly construct the desired KiKit command and fine-tune the panel. It also serves as a quick help in case you are not sure about parameter naming.
The GUI is designed to be run in a standalone instance of Pcbnew (not executed from a project) as the generated panel replaces the currently open board.
You can invoke the GUI via clicking on the panelization icon:
Then the following window will open:
There are three parts of the window:
Note that both, the command and JSON preset, does not include a parameter if it is the same with the default, built-in, preset.
Once you are happy with the parameters, you can click the \"Panelize\" button and the panel will appear in the Pcbnew work area. You can then edit the parameters and regenerate the panel. The panel you see in the Pcbnew window is only a preview. The panel is automatically saved to the specified location upon creation.
"},{"location":"panelization/intro/","title":"Automatic panelization with KiKit","text":"KiKit panelization module is designed to:
There are two ways of specifying a panel:
To tweak the KiKit UI process it is possible to use plugins. Plugins are pieces of Python code that provide some functionality. They can save you from writing a custom panelization script from scratch when you only need a custom one of the steps during panelization.
"},{"location":"panelization/plugins/#specifying-plugins","title":"Specifying plugins","text":"Some of the CLI options allow you to specify plugin. In such a case, one of the following formats is expected:
<packagename>.<pluginname>
, e.g., ExternalPackage.CircleLayout
<filename>.<pluginname>
, e.g., localFile.py.CircleLayout
All plugins, except text plugins, accept optional user text argument.
The plugins can be implemented and published as Python packages.
"},{"location":"panelization/plugins/#writing-custom-plugins","title":"Writing custom plugins","text":"The plugins should be implemented by overriding one of the plugin types specified in ../kikit/plugin.py
. Currently, the following plugin types are supported:
HookPlugin
- this is a plugin that features a number of callback that are invoked during various stages of building the panel. You can tweak the panels in these callbacks.LayoutPlugin
- this plugin implements a new layout of the boards in the panel.FramingPlugin
- this plugin implements a new style of framing.TabsPlugin
- this plugin implements a new style of tab placement.CutsPlugin
- this plugin implements a new style of cut rendering.ToolingPlugin
- this plugin implements a new style of tolling decoration.FiducialsPlugin
- this plugin implements a new style of fiducials decoration.TextVariablePlugin
- this plugins provides new variables for the text placement.All plugins except TextVariablePlugin
have attributes self.preset
containing the whole preset and self.userArg
containing the string provided by the user.
When you want to panelize a board, you are expected to load the kikit.panelize
module and create an instance of the Panel
class.
All units are in the internal KiCAD units (1 nm). You can use predefined constants to convert from/to them:
from kikit.units import *\n\nl = 1 * mm # 1 mm\nl = 42 * inch # 42 inches\nl = 15 * cm # 15 cm\na = 90 * deg # 90\u00b0\na = 1 * rad # 1 radian\n
You can also use functions fromMm(mm)
and toMm(kiUnits)
to convert to/from them if you like them more. You are also encouraged to use the functions and objects the native KiCAD Python API offers, e.g.: VECTOR2I(args),
BOX2I(args).
The kikit.panelize.Panel
class holds a panel under construction. Basically it is pcbnew.BOARD
without outlines. The outlines are held separately as shapely.MultiPolygon
so we can easily merge pieces of a substrate, add cuts and export it back to pcbnew.BOARD
. This is all handled by the class kikit.substrate.Substrate
.
There are two ways to create tabs: generate a piece of a substrate by hand, or use tab generator.
To generate a piece of a substrate, create a shapely.Polygon. Then add the piece of substrate via panelize.Panel.appendSubstrate
. This method also accepts a BOX2I
for convenience.
The tab generator is available via panelize.Panel.boardSubstrate.tab
. This method takes an origin point, direction, and tab width. It tries to build a tab by extruding a tab with the given width in the given direction and stops when it reaches an existing substrate. It returns a tuple - the tab substrate and a piece of the outline of the original board, which was removed by the tab. Then add the piece of a substrate via panelize.Panel.appendSubstrate
. This design choice was made as batch adding of substrates is more efficient. Therefore, you are advised to first generate all the tabs and then append them to the board.
You read more about the algorithms for generating tabs in a separate document understanding tabs.
"},{"location":"panelization/python_api/#cuts","title":"Cuts","text":"All methods constructing panels do not create cuts directly, instead, they return them. This allows the users to decided how to perform the cuts - e.g., mouse bites, V-Cuts, silk-screen...
The cuts are represented by shapely.LineString
. The string is oriented - a positive side of the string should face the inner side of the board. This is important when, e.g., offsetting mouse bites.
To perform the cuts, see methods of the panelize.Panel
class below.
When placing a board, you might specify source area -- a rectangle from which the components are extracted. If no source area is specified, the smallest bounding box of all Edge.Cuts is taken.
Only components that fully fit inside source area are copied to the panel. To include components sticking out of the board outline, you can specify tolerance -- a distance by which the source area is expanded when copying components.
"},{"location":"panelization/python_api/#appendboard","title":"appendBoard
","text":"appendBoard(self, filename, destination, sourceArea=None, origin=Origin.Center, \n rotationAngle=<pcbnew.EDA_ANGLE; proxy of <Swig Object of type 'EDA_ANGLE *' at 0x7f4b833f3120> >, \n shrink=False, tolerance=0, bufferOutline=1000, netRenamer=None, \n refRenamer=None, inheritDrc=True, interpretAnnotations=True, \n bakeText=False)\n
"},{"location":"panelization/python_api/#panel-class","title":"Panel class","text":"This class has the following relevant members: - board
- pcbnew.BOARD
of the panel. Does not contain any edges. - substrates
- kikit.substrate.Substrate
- individual substrates appended via None
. You can use them to get the original outline (and e.g., generate tabs accroding to it). - boardSubstrate
- kikit.substrate.Substrate
of the whole panel. - backboneLines
- a list of lines representing backbone candidates. Read more about it in understanding tabs.
addCornerChamfers
","text":"addCornerChamfers(self, horizontalSize, verticalSize=None)\n
Add chamfers to the panel frame. The chamfer is specified as size in horizontal and vertical direction. If you specify only the horizontal one, the chamfering will be 45\u00b0."},{"location":"panelization/python_api/#addcornerfiducials","title":"addCornerFiducials
","text":"addCornerFiducials(self, fidCount, horizontalOffset, verticalOffset, \n copperDiameter, openingDiameter, paste=False)\n
Add up to 4 fiducials to the top-left, top-right, bottom-left and bottom-right corner of the board (in this order). This function expects there is enough space on the board/frame/rail to place the feature. The offsets are measured from the outer edges of the substrate.
"},{"location":"panelization/python_api/#addcornerfillets","title":"addCornerFillets
","text":"addCornerFillets(self, radius)\n
None"},{"location":"panelization/python_api/#addcornertooling","title":"addCornerTooling
","text":"addCornerTooling(self, holeCount, horizontalOffset, verticalOffset, diameter, \n paste=False, solderMaskMargin=None)\n
Add up to 4 tooling holes to the top-left, top-right, bottom-left and bottom-right corner of the board (in this order). This function expects there is enough space on the board/frame/rail to place the feature. The offsets are measured from the outer edges of the substrate.
Optionally, a solder mask margin (diameter) can also be specified.
"},{"location":"panelization/python_api/#addfiducial","title":"addFiducial
","text":"addFiducial(self, position, copperDiameter, openingDiameter, bottom=False, \n paste=False, ref=None)\n
Add fiducial, i.e round copper pad with solder mask opening to the position (VECTOR2I
), with given copperDiameter and openingDiameter. By setting bottom to True, the fiducial is placed on bottom side. The fiducial can also have an opening on the stencil. This is enabled by paste = True."},{"location":"panelization/python_api/#addkeepout","title":"addKeepout
","text":"addKeepout(self, area, noTracks=True, noVias=True, noCopper=True)\n
Add a keepout area to all copper layers. Area is a shapely polygon. Return the keepout area."},{"location":"panelization/python_api/#addline","title":"addLine
","text":"addLine(self, start, end, thickness, layer)\n
Add a line to the panel based on starting and ending point"},{"location":"panelization/python_api/#addmillfillets","title":"addMillFillets
","text":"addMillFillets(self, millRadius)\n
Add fillets to inner conernes which will be produced a by mill with given radius. This operation simulares milling."},{"location":"panelization/python_api/#addnpthole","title":"addNPTHole
","text":"addNPTHole(self, position, diameter, paste=False, ref=None, \n excludedFromPos=False)\n
Add a drilled non-plated hole to the position (VECTOR2I
) with given diameter. The paste option allows to place the hole on the paste layers."},{"location":"panelization/python_api/#addpaneldimensions","title":"addPanelDimensions
","text":"addPanelDimensions(self, layer, offset)\n
Add vertial and horizontal dimensions to the panel"},{"location":"panelization/python_api/#addtabmillfillets","title":"addTabMillFillets
","text":"addTabMillFillets(self, millRadius)\n
Add fillets to inner conernes which will be produced a by mill with given radius. Simulates milling only on the outside of the board; internal features of the board are not affected."},{"location":"panelization/python_api/#addtext","title":"addText
","text":"addText(self, text, position, \n orientation=<pcbnew.EDA_ANGLE; proxy of <Swig Object of type 'EDA_ANGLE *' at 0x7f4b833f37b0> >, \n width=1500000, height=1500000, thickness=300000, \n hJustify=EDA_TEXT_HJUSTIFY_T.GR_TEXT_HJUSTIFY_CENTER, \n vJustify=EDA_TEXT_VJUSTIFY_T.GR_TEXT_VJUSTIFY_CENTER, \n layer=Layer.F_SilkS)\n
Add text at given position to the panel. If appending to the bottom side, text is automatically mirrored."},{"location":"panelization/python_api/#addvcuth","title":"addVCutH
","text":"addVCutH(self, pos)\n
Adds a horizontal V-CUT at pos (integer in KiCAD units)."},{"location":"panelization/python_api/#addvcutv","title":"addVCutV
","text":"addVCutV(self, pos)\n
Adds a horizontal V-CUT at pos (integer in KiCAD units)."},{"location":"panelization/python_api/#appendboard_1","title":"appendBoard
","text":"appendBoard(self, filename, destination, sourceArea=None, origin=Origin.Center, \n rotationAngle=<pcbnew.EDA_ANGLE; proxy of <Swig Object of type 'EDA_ANGLE *' at 0x7f4b833f3120> >, \n shrink=False, tolerance=0, bufferOutline=1000, netRenamer=None, \n refRenamer=None, inheritDrc=True, interpretAnnotations=True, \n bakeText=False)\n
Appends a board to the panel. The sourceArea (BOX2I) of the board specified by filename is extracted and placed at destination (VECTOR2I). The source area (BOX2I) can be auto detected if it is not provided. Only board items which fit entirely into the source area are selected. You can also specify rotation. Both translation and rotation origin are specified by origin. Origin specifies which point of the sourceArea is used for translation and rotation (origin it is placed to destination). It is possible to specify coarse source area and automatically shrink it if shrink is True. Tolerance enlarges (even shrinked) source area - useful for inclusion of filled zones which can reach out of the board edges or footprints that extend outside the board outline, like connectors.
You can also specify functions which will rename the net and ref names. By default, nets are renamed to \"Board_{n}-{orig}\", refs are unchanged. The renamers are given board seq number and original name.
You can also decide whether you would like to inherit design rules from this boards or not.
Similarly, you can substitute variables in the text via bakeText.
Returns bounding box (BOX2I) of the extracted area placed at the destination and the extracted substrate of the board.
"},{"location":"panelization/python_api/#appendsubstrate","title":"appendSubstrate
","text":"appendSubstrate(self, substrate)\n
Append a piece of substrate or a list of pieces to the panel. Substrate can be either BOX2I or Shapely polygon. Newly appended corners can be rounded by specifying non-zero filletRadius."},{"location":"panelization/python_api/#apply","title":"apply
","text":"apply(self, feature)\n
Apply given feature to the panel"},{"location":"panelization/python_api/#boardsbbox","title":"boardsBBox
","text":"boardsBBox(self)\n
Return common bounding box for all boards in the design (ignores the individual pieces of substrate) as a shapely box."},{"location":"panelization/python_api/#buildfulltabs","title":"buildFullTabs
","text":"buildFullTabs(self, cutoutDepth, patchCorners=True)\n
Make full tabs. This strategy basically cuts the bounding boxes of the PCBs. Not suitable for mousebites or PCB that doesn't have a rectangular outline. Expects there is a valid partition line. Return a list of cuts.
"},{"location":"panelization/python_api/#buildpartitionlinefrombb","title":"buildPartitionLineFromBB
","text":"buildPartitionLineFromBB(self, boundarySubstrates=[], safeMargin=0)\n
Builds partition & backbone line from bounding boxes of the substrates. You can optionally pass extra substrates (e.g., for frame). Without these extra substrates no partition line would be generated on the side where the boundary is, therefore, there won't be any tabs."},{"location":"panelization/python_api/#buildtabannotationscorners","title":"buildTabAnnotationsCorners
","text":"buildTabAnnotationsCorners(self, width)\n
Add tab annotations to the corners of the individual substrates."},{"location":"panelization/python_api/#buildtabannotationsfixed","title":"buildTabAnnotationsFixed
","text":"buildTabAnnotationsFixed(self, hcount, vcount, hwidth, vwidth, minDistance, \n ghostSubstrates)\n
Add tab annotations for the individual substrates based on number of tabs in horizontal and vertical direction. You can specify individual width in each direction. If the edge is short for the specified number of tabs with given minimal spacing, the count is reduced.
You can also specify ghost substrates (for the future framing).
"},{"location":"panelization/python_api/#buildtabannotationsspacing","title":"buildTabAnnotationsSpacing
","text":"buildTabAnnotationsSpacing(self, spacing, hwidth, vwidth, ghostSubstrates)\n
Add tab annotations for the individual substrates based on their spacing. You can also specify ghost substrates (for the future framing).
"},{"location":"panelization/python_api/#buildtabsfromannotations","title":"buildTabsFromAnnotations
","text":"buildTabsFromAnnotations(self, fillet)\n
Given annotations for the individual substrates, create tabs for them. Tabs are appended to the panel, cuts are returned. Expects that a valid partition line is assigned to the the panel.
"},{"location":"panelization/python_api/#cleartabsannotations","title":"clearTabsAnnotations
","text":"clearTabsAnnotations(self)\n
Remove all existing tab annotations from the panel."},{"location":"panelization/python_api/#copperfillnonboardareas","title":"copperFillNonBoardAreas
","text":"copperFillNonBoardAreas(self, clearance=1000000, \n layers=[<Layer.F_Cu: 0>, <Layer.B_Cu: 31>], \n hatched=False, strokeWidth=1000000, \n strokeSpacing=1000000, \n orientation=<pcbnew.EDA_ANGLE; proxy of <Swig Object of type 'EDA_ANGLE *' at 0x7f4b833f3510> >)\n
This function is deprecated, please, use panel features instead. Fill given layers with copper on unused areas of the panel (frame, rails and tabs). You can specify the clearance, if it should be hatched (default is solid) or shape the strokes of hatched pattern.
By default, fills top and bottom layer, but you can specify any other copper layer that is enabled.
"},{"location":"panelization/python_api/#debugrenderbackbonelines","title":"debugRenderBackboneLines
","text":"debugRenderBackboneLines(self)\n
Render partition line to the panel to be easily able to inspect them via Pcbnew."},{"location":"panelization/python_api/#debugrenderboundingboxes","title":"debugRenderBoundingBoxes
","text":"debugRenderBoundingBoxes(self)\n
None"},{"location":"panelization/python_api/#debugrenderpartitionlines","title":"debugRenderPartitionLines
","text":"debugRenderPartitionLines(self)\n
Render partition line to the panel to be easily able to inspect them via Pcbnew."},{"location":"panelization/python_api/#getauxiliaryorigin","title":"getAuxiliaryOrigin
","text":"getAuxiliaryOrigin(self)\n
None"},{"location":"panelization/python_api/#getdrufilepath","title":"getDruFilepath
","text":"getDruFilepath(self, path=None)\n
None"},{"location":"panelization/python_api/#getgridorigin","title":"getGridOrigin
","text":"getGridOrigin(self)\n
None"},{"location":"panelization/python_api/#getpagedimensions","title":"getPageDimensions
","text":"getPageDimensions(self)\n
Get page size in KiCAD units for the current panel"},{"location":"panelization/python_api/#getprlfilepath","title":"getPrlFilepath
","text":"getPrlFilepath(self, path=None)\n
None"},{"location":"panelization/python_api/#getprofilepath","title":"getProFilepath
","text":"getProFilepath(self, path=None)\n
None"},{"location":"panelization/python_api/#inheritcopperlayers","title":"inheritCopperLayers
","text":"inheritCopperLayers(self, board)\n
Update the panel's layer count to match the design being panelized. Raise an error if this is attempted twice with inconsistent layer count boards."},{"location":"panelization/python_api/#inheritdesignsettings","title":"inheritDesignSettings
","text":"inheritDesignSettings(self, board)\n
Inherit design settings from the given board specified by a filename or a board"},{"location":"panelization/python_api/#inheritpagesize","title":"inheritPageSize
","text":"inheritPageSize(self, board)\n
Inherit page size from a board specified by a filename or a board"},{"location":"panelization/python_api/#inheritproperties","title":"inheritProperties
","text":"inheritProperties(self, board)\n
Inherit text properties from a board specified by a filename or a board"},{"location":"panelization/python_api/#inherittitleblock","title":"inheritTitleBlock
","text":"inheritTitleBlock(self, board)\n
Inherit title block from a board specified by a filename or a board"},{"location":"panelization/python_api/#locateboard","title":"locateBoard
","text":"locateBoard(inputFilename, expandDist=None)\n
Given a board filename, find its source area and optionally expand it by the given distance. Parameters:
inputFilename - the path to the board file
expandDist - the distance by which to expand the board outline in each direction to ensure elements that are outside the board are included
"},{"location":"panelization/python_api/#makecutstolayer","title":"makeCutsToLayer
","text":"makeCutsToLayer(self, cuts, layer=Layer.Cmts_User, prolongation=0)\n
Take a list of cuts and render them as lines on given layer. The cuts can be prolonged just like with mousebites. The purpose of this is to aid debugging when KiKit refuses to perform cuts. Rendering them into lines can give the user better understanding of where is the problem.
"},{"location":"panelization/python_api/#makeframe","title":"makeFrame
","text":"makeFrame(self, width, hspace, vspace, minWidth=0, minHeight=0, maxWidth=None, \n maxHeight=None)\n
Build a frame around the boards. Specify width and spacing between the boards substrates and the frame. Return a tuple of vertical and horizontal cuts. Parameters:
width - width of substrate around board outlines
slotwidth - width of milled-out perimeter around board outline
hspace - horizontal space between board outline and substrate
vspace - vertical space between board outline and substrate
minWidth - if the panel doesn't meet this width, it is extended
minHeight - if the panel doesn't meet this height, it is extended
maxWidth - if the panel doesn't meet this width, TooLargeError is raised
maxHeight - if the panel doesn't meet this height, TooLargeHeight is raised
"},{"location":"panelization/python_api/#makeframecutsh","title":"makeFrameCutsH
","text":"makeFrameCutsH(self, innerArea, frameInnerArea, outerArea)\n
Generate horizontal cuts for the frame corners and return them"},{"location":"panelization/python_api/#makeframecutsv","title":"makeFrameCutsV
","text":"makeFrameCutsV(self, innerArea, frameInnerArea, outerArea)\n
Generate vertical cuts for the frame corners and return them"},{"location":"panelization/python_api/#makegrid","title":"makeGrid
","text":"makeGrid(self, boardfile, sourceArea, rows, cols, destination, placer, \n rotation=<pcbnew.EDA_ANGLE; proxy of <Swig Object of type 'EDA_ANGLE *' at 0x7f4b833f3f00> >, \n netRenamePattern=Board_{n}-{orig}, refRenamePattern=Board_{n}-{orig}, \n tolerance=0, bakeText=False)\n
Place the given board in a grid pattern with given spacing. The board position of the gride is guided via placer. The nets and references are renamed according to the patterns. Parameters:
boardfile - the path to the filename of the board to be added
sourceArea - the region within the file specified to be selected (see also tolerance, below) set to None to automatically calculate the board area from the board file with the given tolerance
rows - the number of boards to place in the vertical direction
cols - the number of boards to place in the horizontal direction
destination - the center coordinates of the first board in the grid (for example, VECTOR2I(100 * mm, 50 * mm))
rotation - the rotation angle to be applied to the source board before placing it
placer - the placement rules for boards. The builtin classes are: BasicGridPosition - places each board in its original orientation OddEvenColumnPosition - every second column has the boards rotated by 180 degrees OddEvenRowPosition - every second row has the boards rotated by 180 degrees OddEvenRowsColumnsPosition - every second row and column has the boards rotated by 180 degrees
netRenamePattern - the pattern according to which the net names are transformed The default pattern is \"Board_{n}-{orig}\" which gives each board its own instance of its nets, i.e. GND becomes Board_0-GND for the first board , and Board_1-GND for the second board etc
refRenamePattern - the pattern according to which the reference designators are transformed The default pattern is \"Board_{n}-{orig}\" which gives each board its own instance of its reference designators, so R1 becomes Board_0-R1 for the first board, Board_1-R1 for the second board etc. To keep references the same as in the original, set this to \"{orig}\"
tolerance - if no sourceArea is specified, the distance by which the selection area for the board should extend outside the board edge. If you have any objects that are on or outside the board edge, make sure this is big enough to include them. Such objects often include zone outlines and connectors.
bakeText - substitute variables in text elements
Returns a list of the placed substrates. You can use these to generate tabs, frames, backbones, etc.
"},{"location":"panelization/python_api/#makelayersvisible","title":"makeLayersVisible
","text":"makeLayersVisible(self)\n
Modify corresponding *.prl files so all the layers are visible by default"},{"location":"panelization/python_api/#makemousebites","title":"makeMouseBites
","text":"makeMouseBites(self, cuts, diameter, spacing, offset=250000, prolongation=500000)\n
Take a list of cuts and perform mouse bites. The cuts can be prolonged to"},{"location":"panelization/python_api/#makerailslr","title":"makeRailsLr
","text":"makeRailsLr(self, thickness, minWidth=0, maxWidth=None)\n
Adds a rail to left and right. You can specify minimal width the panel has to feature."},{"location":"panelization/python_api/#makerailstb","title":"makeRailsTb
","text":"makeRailsTb(self, thickness, minHeight=0, maxHeight=None)\n
Adds a rail to top and bottom. You can specify minimal height the panel has to feature. You can also specify maximal height of the panel. If the height would be exceeded, TooLargeError is raised."},{"location":"panelization/python_api/#maketightframe","title":"makeTightFrame
","text":"makeTightFrame(self, width, slotwidth, hspace, vspace, minWidth=0, minHeight=0, \n maxWidth=None, maxHeight=None)\n
Build a full frame with board perimeter milled out. Add your boards to the panel first using appendBoard or makeGrid. Parameters:
width - width of substrate around board outlines
slotwidth - width of milled-out perimeter around board outline
hspace - horizontal space between board outline and substrate
vspace - vertical space between board outline and substrate
minWidth - if the panel doesn't meet this width, it is extended
minHeight - if the panel doesn't meet this height, it is extended
maxWidth - if the panel doesn't meet this width, TooLargeError is raised
maxHeight - if the panel doesn't meet this height, TooLargeHeight is raised
"},{"location":"panelization/python_api/#makevcuts","title":"makeVCuts
","text":"makeVCuts(self, cuts, boundCurves=False, offset=0)\n
Take a list of lines to cut and performs V-CUTS. When boundCurves is set, approximate curved cuts by a line from the first and last point. Otherwise, raise an exception."},{"location":"panelization/python_api/#panelbbox","title":"panelBBox
","text":"panelBBox(self)\n
Return bounding box of the panel as a shapely box."},{"location":"panelization/python_api/#panelcorners","title":"panelCorners
","text":"panelCorners(self, horizontalOffset=0, verticalOffset=0)\n
Return the list of top-left, top-right, bottom-left and bottom-right corners of the panel. You can specify offsets."},{"location":"panelization/python_api/#renderbackbone","title":"renderBackbone
","text":"renderBackbone(self, vthickness, hthickness, vcut, hcut, vskip=0, hskip=0, \n vfirst=0, hfirst=0)\n
Render horizontal and vertical backbone lines. If zero thickness is specified, no backbone is rendered. vcut, hcut specifies if vertical or horizontal backbones should be cut.
vskip and hskip specify how many backbones should be skipped before rendering one (i.e., skip 1 meand that every other backbone will be rendered)
vfirst and hfirst are indices of the first backbone to render. They are 1-indexed.
Return a list of cuts
"},{"location":"panelization/python_api/#save","title":"save
","text":"save(self, reconstructArcs=False, refillAllZones=False)\n
Saves the panel to a file and makes the requested changes to the prl and pro files."},{"location":"panelization/python_api/#setauxiliaryorigin","title":"setAuxiliaryOrigin
","text":"setAuxiliaryOrigin(self, point)\n
Set the auxiliary origin used e.g., for drill files"},{"location":"panelization/python_api/#setcopperlayers","title":"setCopperLayers
","text":"setCopperLayers(self, count)\n
Sets the copper layer count of the panel"},{"location":"panelization/python_api/#setdesignsettings","title":"setDesignSettings
","text":"setDesignSettings(self, designSettings)\n
Set design settings"},{"location":"panelization/python_api/#setgridorigin","title":"setGridOrigin
","text":"setGridOrigin(self, point)\n
Set grid origin"},{"location":"panelization/python_api/#setpagesize","title":"setPageSize
","text":"setPageSize(self, size)\n
Set page size - either a string name (e.g., A4) or size in KiCAD units"},{"location":"panelization/python_api/#setproperties","title":"setProperties
","text":"setProperties(self, properties)\n
Set text properties cached in the board"},{"location":"panelization/python_api/#settitleblock","title":"setTitleBlock
","text":"setTitleBlock(self, titleBlock)\n
Set panel title block"},{"location":"panelization/python_api/#setvcutclearance","title":"setVCutClearance
","text":"setVCutClearance(self, clearance)\n
Set V-cut clearance"},{"location":"panelization/python_api/#setvcutlayer","title":"setVCutLayer
","text":"setVCutLayer(self, layer)\n
Set layer on which the V-Cuts will be rendered"},{"location":"panelization/python_api/#transferprojectsettings","title":"transferProjectSettings
","text":"transferProjectSettings(self)\n
Examine DRC rules of the source boards, merge them into a single set of rules and store them in *.kicad_pro file. Also stores board DRC exclusions. Also, transfers the list of net classes from the internal representation into the project file.
"},{"location":"panelization/python_api/#translate","title":"translate
","text":"translate(self, vec)\n
Translates the whole panel by vec. Such a feature can be useful to specify the panel placement in the sheet. When we translate panel as the last operation, none of the operations have to be placement-aware."},{"location":"panelization/python_api/#writecustomdrcrules","title":"writeCustomDrcRules
","text":"writeCustomDrcRules(self)\n
None"},{"location":"panelization/python_api/#substrate-class","title":"Substrate class","text":"This class represents a pice of substrate (with no components). Basically it is just a relatively thin wrapper around shapely polygons. On top of that, it keeps a partition line for the substrate. Read more about partition lines in understanding tabs.
"},{"location":"panelization/python_api/#backtosource","title":"backToSource
","text":"backToSource(self, point)\n
Return a point in the source form (if a reverse transformation was set)"},{"location":"panelization/python_api/#boundary","title":"boundary
","text":"boundary(self)\n
Return shapely geometry representing the outer ring"},{"location":"panelization/python_api/#boundingbox","title":"boundingBox
","text":"boundingBox(self)\n
Return bounding box as BOX2I"},{"location":"panelization/python_api/#bounds","title":"bounds
","text":"bounds(self)\n
Return shapely bounds of substrates"},{"location":"panelization/python_api/#cut","title":"cut
","text":"cut(self, piece)\n
Remove a piece of substrate given a shapely polygon."},{"location":"panelization/python_api/#exterior","title":"exterior
","text":"exterior(self)\n
Return a geometry representing the substrate with no holes"},{"location":"panelization/python_api/#exteriorring","title":"exteriorRing
","text":"exteriorRing(self)\n
None"},{"location":"panelization/python_api/#interiors","title":"interiors
","text":"interiors(self)\n
Return shapely interiors of the substrate"},{"location":"panelization/python_api/#issinglepiece","title":"isSinglePiece
","text":"isSinglePiece(self)\n
Decide whether the substrate consists of a single piece"},{"location":"panelization/python_api/#midpoint","title":"midpoint
","text":"midpoint(self)\n
Return a mid point of the bounding box"},{"location":"panelization/python_api/#millfillets","title":"millFillets
","text":"millFillets(self, millRadius)\n
Add fillets to inner corners which will be produced by a mill with given radius."},{"location":"panelization/python_api/#orient","title":"orient
","text":"orient(self)\n
Ensures that the substrate is oriented in a correct way."},{"location":"panelization/python_api/#removeislands","title":"removeIslands
","text":"removeIslands(self)\n
Removes all islands - pieces of substrate fully contained within the outline of another board"},{"location":"panelization/python_api/#serialize","title":"serialize
","text":"serialize(self, reconstructArcs=False)\n
Produces a list of PCB_SHAPE on the Edge.Cuts layer"},{"location":"panelization/python_api/#tab","title":"tab
","text":"tab(self, origin, direction, width, partitionLine=None, maxHeight=50000000, \n fillet=0)\n
Create a tab for the substrate. The tab starts at the specified origin (2D point) and tries to penetrate existing substrate in direction (a 2D vector). The tab is constructed with given width. If the substrate is not penetrated within maxHeight, exception is raised. When partitionLine is specified, the tab is extended to the opposite side - limited by the partition line. Note that if tab cannot span towards the partition line, then the tab is not created - it returns a tuple (None, None).
If a fillet is specified, it allows you to add fillet to the tab of specified radius.
Returns a pair tab and cut outline. Add the tab it via union - batch adding of geometry is more efficient.
"},{"location":"panelization/python_api/#translate_1","title":"translate
","text":"translate(self, vec)\n
Translate substrate by vec"},{"location":"panelization/python_api/#union","title":"union
","text":"union(self, other)\n
Appends a substrate, polygon or list of polygons. If there is a common intersection, with existing substrate, it will be merged into a single substrate."},{"location":"panelization/scripting/","title":"Introduction to scripting with KiKit","text":"This document will show you how to use KiKit as a library for panelization. The full reference for the available API is located in the next section.
"},{"location":"panelization/scripting/#basic-concepts","title":"Basic concepts","text":"Let's start with an overview of the foundational concepts in KiKit.
"},{"location":"panelization/scripting/#units","title":"Units","text":"All units are in the internal KiCAD units (1 nm). You can use predefined constants to convert from/to them:
from kikit.units import *\n\nl = 1 * mm # 1 mm\nl = 42 * inch # 42 inches\nl = 15 * cm # 15 cm\na = 90 * deg # 90\u00b0\na = 1 * rad # 1 radian\n
You can also use functions fromMm(mm)
and toMm(kiUnits)
to convert to/from them if you like them more. You are also encouraged to use the functions and objects that the native KiCAD Python API offers, e.g.: pcbnew.wxPoint(args)
, pcbnew.wxPointMM(mmx, mmy)
, pcbnew.wxRect(args)
, pcbnew.wxRectMM(x, y, wx, wy)
.
When KiKit loads a KiCAD board, it takes the Edge.Cuts layer and tries to interpret it as a set of 2D polygons. If it cannot interpret them (i.e, there is a discontinuous outline), it raises an exception.
These polygons has a notion of what is inside and what is outside. We can also perform boolean operation on them (i.e., merge two polygons, subtract one from the other, etc.). When we save the panel, the polygons are converted back to outlines. All internal operations in KiKit that changes the board shape operate on top of the polygonal representation, not the outline themselves.
The polygonal representation of board shape is called PCB substrate and it is represented by the class kikit.substrate.Substrate
. Internally, KiKit uses the library Shapely to represent the polygon. We advise you to get at least briefly familiar with it as whenever you need to create a new piece of substrate (e.g., for a tab) you will do so using the operations Shapely provides.
The Substrate
class encapsulates the functionality regarding converting an outline into a polygon and vice-versa and modification of the substrate (add/subtract from it/construct a tab for it). For convenience, it also holds the partition lines associated with the substrate. For more details about partition lines, please refer to section Tabs below.
The panel construction is handled via kikit.panelize.Panel
class. This class represents a panel under construction as pcbnew.Board
without outlines. The outlines are represented via a substrate and it is converted into outline only on saving the panel to file.
The panel class provides you with a number of methods to construct the panel; e.g., append a board at given coordinates, create a grid of boards, add piece of substrate to it, add framing, create a cut, etc.
A typical workflow with the Panel
class is the following:
appendBoard
or makeAGrid
),buildPartitionLineFromBB
or manually set. Without a partition line the automatic tab building nor backbone do not work.During the whole process you can directly access panel.board
of the type pcbnew.Board
and use the KiCAD API to add or remove the features on the boards.
Every tab consists of two features: a piece of substrate that connects the individual board on the panel and a cut that will be broken when you depanelize the board.
In KiKit, the substrate is represented as a Substrate
, more precisely as shapely.geometry.Polygon
. This substrate is appended to the resulting panel substrate. The cut is represented as a polyline of the type shapely.geometry.LineString
. KiKit accepts the polyline and it can either convert it into mouse bites or V-cuts.
You can build the tab substrate and cuts manually. In that case, just build the tab shape as Polygon
and append it to the board via Panel.appendSubstrate
. You also construct the cuts manually as LineString
and you turn it
Panel.makeMouseBites
, orPanel.makeVCuts
. You can also use Panel.addVCutV
or Panel.addVCutH
in this case and avoid creating the LineString
.You will use this approach in the simple cases or cases when you need a specially shaped tabs.
The second approach is to let KiKit generate the tabs and cuts automatically based on annotations. Annotation is just a marking on the board outline that specifies \"here should be a tab of this width\". You can read the annotations from source board (there are special footprints for that), generate it manually or use some of the strategies to place the annotations (e.g., place tabs in a spacing or in given number along edges). Note that the strategies often need a properly build partition line. Once you are finished, you can render the tabs using Panel.buildTabsFromAnnotations
. This function will merge the tab bodies and returns a list of cuts. With the list of cuts, you can further decide whether to ignore them or render them via mousebites or V-cuts. For more details on the automated process of building tabs from annotations, see understanding tabs.
The document understanding tabs also explains what is a partition line and how it is used. Let us add that partition line is represented as shapely collection of line strings. The partition line is not a single one for the whole panel, but it is stored separately for each appended board as the annotations are rendered independently for each appended board.
Also note that you can use the partition line as guide when placing features (e.g., adding a holes on backbone, etc.).
"},{"location":"panelization/scripting/#appending-boards","title":"Appending Boards","text":"The simples approach to adding boards to a panel is using Panel.appendBoard
. This places a board in the panel and also, it renames the nets such that they are panel-wise unique. This is necessary to pass DRC. You can specify the renaming pattern if you want. The substrate of the board is added the panel substrate, but it is also stored separately in Panel.substrates
as the shape of the original board can be used to generate the automatic tabs and also it is used to copper-fill the non-board areas of the panel. You can also use these substrates to build your custom features.
If you make single-board panels, you can use the function Panel.makeGrid
to quickly place the boards in a grid. The function returns the list of individual substrates. You can use the substrates e.g., to build custom tabs or other features.
When you place multiple PCB into the panel, KiKit expects you to generate a so-called partition line for each individual PCB. Partition line is an oriented (poly)line that partitions the free space between the PCBs. It gives you the information \"this part of the free space belongs to this PCB substrate and this PCB is responsible for placing tabs in that space\". So for a regular input the partition line can look like this:
For more complicated input, it can look like this:
Note several facts: - partition line is used for backbone generator - partition line is not generated automatically, it is up to the user to generate it. KiKit offers Panel.buildPartitionLineFromBB
that builds the partition line based on bounding boxes. If you need possibly a more complicated lines, you have to implement them by yourself. - partition line is used for deciding if an annotation yields a tab or not - if the tab does not hit the partition line, it is not created. - when we create partition line from bounding boxes, we include \"ghost substrates\" representing the framing, that will be added in the future.
When KiKit generates a tab, it generates it based on tab origin, direction and optionally the partition line. When a tab is successfully generated, it consists out of two components - a piece of a substrate (which will be later appended to the panel) and a cut-line.
So assume we have the following PCB outline (the PCB is below the line, there is a free space above the line):
Then you specify your tab origin and its direction:
This is your input (e.g., via an annotation). Now KiKit does its job; it shoots two rays tabWidth
apart and looks for the intersection with existing substrates. Note that if the ray starts within the PCB, no intersection will be found.
Once we have the intersections, we can easily generate the tab substrate and the cut:
Note that if we specify a partition line, than we shoot new rays in the opposite direction and try to hit the line. If we manage to do so, we get a tab. Otherwise, no tab is generated.
This is the basic algorithm for generating tabs. Well, we might also call them \"half tabs\". KiKit usually generates the half tabs around the board bounding box and then expects that two half tabs in the middle of the panel will merge into a single one. Also, KiKit first generates all the tabs and then merges them in one step to the board substrate. The cut is just a polyline which is in later steps either rendered as a V-cut or via mousebites.
"}]} \ No newline at end of file +{"config":{"lang":["en"],"separator":"[\\s\\-]+","pipeline":["stopWordFilter"]},"docs":[{"location":"","title":"KiKit \u2013 Automation for KiCAD","text":"KiKit is a Python library, KiCAD plugin and a CLI tool to automate several tasks in a standard KiCAD workflow like:
Then definitely consider:
Your support will allow me to allocate time to properly maintain my projects like this.
PS: Be sure to check out my other KiCAD & PCB related projects:
Everything KiKit does, can also be done via Pcbnew in KiCAD. However, you have to do it manually. One of the common scenarios is the creation of panels. Most of the tutorials on the internet guide you to use the \"append board\" functionality of Pcbnew. However, this approach is labour-intensive, error-prone and whenever, you change the board, you have to do it again.
With KiKit you just call a CLI command if you have a simple layout (e.g., a grid) or write few Python instructions like \"place board here\", \"add bridge here\", \"separate boards via mouse bites/v-cuts\" and you are done. The process is repeatable and actually much simpler than hand-drawing the panels. KiKit also allows you to easily export all the Gerbers in a single step.
You can then write a Makefile and simply call make
to get all your manufacturing data and board presentation pages.
Read the CLI documentation and the panelize documentation. Also don't miss the examples. There is also a quick not on how to use panelization action plugin. If you are interested in generating solder paste stencils, see Stencil documentation
"},{"location":"#acknowledgements","title":"Acknowledgements","text":"The project is supported by:
Please, first check FAQ. If you have not found answer for your problem there, feel free to open an issue on GitHub.
If you would like to have a feature in KiKit that is currently not on a roadmap, or if you need to prepare custom panelization script (e.g., multi-design panels, panels with specific arrangement), you can consider hiring me to do the job. Just reach out to me via e-mail and we can discuss further details.
"},{"location":"acknowledgements/","title":"Acknowledgements","text":"The project is supported by:
Thank you all!
"},{"location":"cli/","title":"KiKit CLI interface","text":"KiKit offers a simple CLI interface to perform common tasks easily. You can obtain help of the interface by calling kikit --help
.
The interface is structured into nested commands. On the top level, there are the following commands available:
kikit export gerber <boardFile> [<outputDir>]
- export gerber files of boardFile
to outputDir
. If no dir is specified, a new one <boardFile>-gerbers
is created.kikit export dxf <boardFile> [<outputDir>]
- export board outline and paste layers to DXF. The main use case for this command is making 3D printed solder paste stencils.Read more in a separate documentation section or see a walkthrough.
"},{"location":"cli/#separate-commands","title":"Separate commands","text":"Read more in a separate documentation section.
"},{"location":"cli/#stencil-commands","title":"Stencil commands","text":"Read more in a separate documentation section.
"},{"location":"cli/#present-commands","title":"Present commands","text":"kikit present boardpage --name <pagename> -d <descriptionFile> -b <name comment boadfile> -r <resource> --template <template> --repository <url> <outputdir>
- generate single webpage providing board preview and a possibility to download board files (gerbers and sources). See an example of such page.-r
or --resource
. Resources are files which will be copied to the output directory. Useful for images referred from description-b
or --board
default
). See template documentation for more information about templates.kikit modify references --show/--hide --pattern <pattern> <board>
hide or show all references on the board matching a regular pattern.
kikit modify values --show/--hide --pattern <pattern> <board>
is the same as above, just with footprint values.
KiKit respects the KiCAD component selection criteria. When you specify an input rectangle, only the components that fully fit inside the input rectangle are selected. This however take in account both name and value labels.
When you do not specify the source are explicitly, KiKit takes the board outline bounding box as the source area. Therefore, by default, components outside the board substrate are not copied to panel.
Since version 1.1 this behavior, however, changes for footprints. KiKit decides whether to keep a footprint or not based on whether its origin fits inside the source area or not. For graphical items, the behavior remains the same. The reason for this change is that often footprints reach out beyond the board edge (e.g., connectors) and the users don't want to remove them. On the other hand, graphical items (e.g., texts or arrows towards the board) are purely for documentation purposes and thus, they shouldn't be included in the panelized design.
Note that this is intended behavior; for once it is consistent with KiCAD behavior of user selection and also it allows to easily ignore surrounding comments and drawings in the board sheet (it makes no sense to have 12 same copies of the notes around the board).
How to include the components? - specify the source area explicitly to include all your components - specify tolerance: 20mm
for source
(i.e., --source 'tolerance: 20mm'
) to enlarge the board outline bounding box. The default value is 1 mm.
KiKit's millradius
parameter from the postprocess
section simulates the board outline milling by a tool with given radius. That means that it will round all inner corners. It is not a command to round just your tabs. That means if you specify a tool which diameter is larger than your slot, KiKit will remove the slot as such slot cannot be created with the tool.
This is an intended behavior. The options is designed for you to check if your board can be manufactured with all the features you have in your board outline. There aren't many fabrication houses that support sharp inner corners as they cannot be milled but have to be e.g., broached, which is much more complicated and expensive setup.
If you want to preserve your narrow internal slots: - don't specify millradius
at all in the postprocess
- specify smaller millradius
but make sure that your fabrication house supports such small tools.
KiKit's mouse bites offset specifies how much should be the mouse bites put inside the board. The recommended value is 0.25 mm (read about it in this blog post). Why is it so? When you break the tab, there will be rough edges. By putting the mouse bites inside the board, these rough edges won't be sticking outside the designed board outline. When you want to fit your board in a tight enclosure, you don't have to perform manual deburing. Since it is considered a good practice, KiKit makes this the positive direction so you don't have to put minus everywhere.
If you don't want to put mouse bites inside your board, just specify zero or negative offset.
"},{"location":"faq/#i-have-board-with-no-spacing-but-some-v-cuts-are-missing","title":"I have board with no spacing, but some V-cuts are missing.","text":"The default style of tabs (spacing
) does not generate in such a case any tabs, and, therefore, not cuts. Please use tab style full
.
ModuleNotFoundError: No module named 'pcbnew'
","text":"You probably installed KiKit via Windows command prompt, not KiCAD Command Prompt.
"},{"location":"faq/#i-would-like-to-make-a-panel-out-of-different-designs-but-there-is-no-such-option-in-help","title":"I would like to make a panel out of different designs, but there is no such option in help","text":"KiKit supports such feature. But it is not available from CLI. You have to write a simple Python script describing the panel and use KiKit as a library. Also, please refer to the panelization documentation.
If you wonder why is it in such way: there are infinitely many ways to panel your design. A single CLI/UI will not fit them all and also even for the simple cases, it would be enormous and painful to use. Much better idea is to use a language to specify the panel. But why reinvent the wheel and design a custom language when we can use Python? It integrates well with other tools and many people already know it.
"},{"location":"faq/#there-are-no-plugins-in-kicad","title":"There are no plugins in KiCAD!","text":"You have to install them via KiCAD PCM. See the installation guide.
"},{"location":"faq/#how-do-i-run-kikit-with-kicad-nightly","title":"How do I run KiKit with KiCAD nightly?","text":"See section \"Choosing KiCAD version\" in the installation guide. However, at the moment KiKit is incompatible with KiCAD 6.99.
"},{"location":"multiboard/","title":"Multiboard workflow","text":""},{"location":"multiboard/#multi-board-workflow-with-kikit","title":"Multi-board workflow with KiKit","text":"KiCAD does not support multiple board per project, nor boards with shared schematics. However, with the following workflow, you can easily draw multiple boards with shared schematics and, e.g., easily ensure that tha board connectors match.
The workflow is the following:
First, draw a separate schematics sheet for each of your boards and propagate the pins on the inter-board connectors. E.g., in one of my project it looks like this:
I also place the corresponding connectors next to each other to illustrate that they connect. Then draw your board schematics as usual - with one exception. Do not use global power symbols nor global labels, use only local labels. This ensures that the power lines are separate for each board and DRC won't complain, that you have not connected the power between two board.
Then, draw all your boards into a single board file side-by-side. See file resources/multiboard.kicad_pcb for a dead simple illustration. You can also draw lines that will help you align your boards' connectors.
Before manufacturing, use KiKit to extract the boards into a separate board files via the extract
command.
This can be done in two ways:
We will show how to use it on resources/multiboard.kicad_pcb which looks like this:
"},{"location":"multiboard/#bounding-box-selection","title":"Bounding box selection","text":"Simply specify the top left and bottom right corner. Everything that fits fully inside it, will be included in the board. The command for separation of board A into a separate board file is:
kikit separate --source 'rectangle; tlx: 89mm; tly: 89mm; brx: 111mm; bry: 111mm' \\\n multiboard.kicad_pcb board_a.kicad_pcb\n
After that, board_a.kicad_pcb
will contain only a board A. Note that the \\
is there for shell as we split our command into two lines.
As you can see, the source file contains an annotation in the form of virtual footprints kikit:Board
. You can place them into your document so that the arrow points to the board edge. Than you can use the reference of the annotation symbol for separation of the board. To separate board A simply invoke:
kikit separate --source 'annotation; ref: B1' \\\n multiboard.kicad_pcb board_a.kicad_pcb\n
After that, board_a.kicad_pcb
will contain only a board A. Note that the \\
is there for shell as we split our command into two lines.
Note that if panelize your boards, you don't have to separate your boards first; just use the --source
with the panelization command.
When you use the separate command, KiKit preserves all annotations within the source bounding box. If you would like to strip the annotations, you can specify --stripAnnotation
and KiKit will remove all annotations from the resulting board.
Present is a collection of functions providing various ways to present KiCAD boards. The main one is a simple page generator which can be used in continuous integration to build pages where your users and collagues can download the automatically generated panels.
"},{"location":"present/#requirements","title":"Requirements","text":"In order to include PCB drawings in presentations you will need to install PcbDraw.
"},{"location":"present/#template-namepath-resolution","title":"Template name/path resolution","text":"The template argument is either a name of a built-it template or a path to a directory with a user-defined template. During the name resolution the first test is for the user-defined template; i.e., check if the name provided by the user is a directory path and the directory contains the file template.json
. If not, try to resolve the name as the name of the built-in template.
A template is a directory containing template files. There is a single mandatory file common to all template types template.json
. An example of such file follows:
{\n \"type\": \"HtmlTemplate\",\n \"resources\": [\"css/*.css\"]\n}\n
The key type
specifies what kind of template it is. Currently, only HtmlTemplate
is supported (see more info about them below). Then there is the list of resources
which are glob patterns for resource files which are copied to the output directory when rendering the template.
Expects an index.html
file in the root of the template. This is Handlerbars template which receives the following dictionary on render:
\"repo\": self.repository,\n\"gitRev\": gitRev,\n\"gitRevShort\": gitRev[:7] if gitRev else None,\n\"datetime\": self.currentDateTime(),\n\"name\": self.name,\n\"boards\": self.boards,\n\"description\": self.description\n
boards
is a list of a dictionary with following keys:
front
path to render of the front sideback
path to render of the back sidegerbers
path to archive with gerbersfile
path to kicad_pcb
fileSee the default template in kikit/resources/present/templates/default
for a starting point for custom templates.
If you populate your boards using a reflow oven, you often need solder paste stencils. One of the inconveniences with stencils is that you have to align them manually. It is not hard, but it takes some time and a little bit of practice & tricks (e.g. to use other PCBs for stencil alignment).
KiKit provides two ways to generate stencils:
KiKit allows you to ignore components from the stencil by specifying --ignore
followed by a comma separated list of components' references to exclude. Pads of these components will not appear in the stencil. This is useful, when you do not want to populate all components.
The second common option is --cutout
followed by a comma separated lists of components' references. For these components, the stencil will contain a cutout based on the component courtyard. This is useful when you have already pre-populated board and you want to populate more components -- e.g., when your assembly house does not have a special IC and you populate it yourself and also, when you do a board repair.
I wrote a blog post about the 3D printed self-registering stencils on my blog. These stencils are quick solution when you urgently need a stencil but probably they don't last long and might come with imperfections.
To generate such stencil, just call:
kikit stencil createprinted [parameters] <boardFile> <outputDirectory>\n
where parameters is one of the following: --pcbthickness FLOAT PCB thickness in mm\n--thickness FLOAT Stencil thickness in mm. Defines amount of paste\n dispensed\n--framewidth FLOAT Register frame width\n--ignore TEXT Comma separated list of components references to\n exclude from the stencil\n--frameclearance FLOAT Clearance for the stencil register in milimeters\n--enlargeholes FLOAT Enlarge pad holes by x mm\n
KiKit will output two STL files representing bottom and top register to the specified directory. You can directly print these files. In theory, if you don't have small pads spacing, you could print them even on FDM machine, but I haven't tested it.
"},{"location":"stencil/#steel-stencils","title":"Steel Stencils","text":"Many fabhouses offer you to create a custom stencil. However, it is pain to align them. Therefore, KiKit offers a functionality to automatically generate stencils which fit a simple 3D printed or lasercut alignment jig.
The jig is available as Fusion 360 model, STEP or 3MF.It it designed to be cut from 3mm thick acrylic but you can also print it. You need 4 2mm pins, 8 M2 screws and that's it. The frame can be customized - there two parameters of the model, frameWidth
and frameHeight
which define the largest PCB it can accept. I usually use 100x100mm and 60x60mm.
Then you issue the following command within KiKit:
kikit stencil create --jigsize 60 60 <boardFile> <outputDir>\n
Note that there are more options for this command, see output of kikit stencil create --help
. KiKit will produce 2 STL files for aligning the PCB and a zip file with gerbers for the manufacturer. When you order your stencil, let them make both top and bottom side on the same stencil. One tip for JLC PCB: set custom size of the stencil when you order it - then it fits into your package with your PCB and you don't have to pay for extra shipping.
The stencil you receive should look like on the following picture. It has mouse bites so you can easily break it off to precise size. It also has mounting holes.
Once you break the stencils off, you mount them in the jig frame:
Then you print alignment parts for your board and mount in onto the jig using M2 screws:
Then you just use 2mm pins to align the frame and you can apply the paste!
The acrylic jig is reusable - you just have to mount new alignment pieces and change the stencil.
"},{"location":"fabrication/intro/","title":"Fabrication","text":"KiKit offers fully automatic export of all data required for fabrication of your designs. Since every fabrication house has different requirements on the design files (e.g., special names of gerber files, different requirements for assembly files) there is no \"universal exporter\" in KiKit. Instead, KiKit offers special command for each supported fabrication house.
"},{"location":"fabrication/intro/#common-options","title":"Common Options","text":"All fab subcommands has a common invocation structure:
kikit fab <fabhouse> <options> <sourceDir> <outputDir>\n
All commands also support the following options:
--drc\\--no-drc
(default --drc
). Check for DRC violations before exporting the files. With this options, you won't send a board that fails DRC to your manufacturer.--nametemplate <str>
: If you want to name your files differently, specify this option. This option takes a string that should contain {}
. This string will be replaced by gerber
, pos
or bom
in the out file names. The extension is appended automatically. Variables in text are also supported eg: {boardTitle}_rev{boardRevision}_{date}_{}
. The project variables are available with the user-
prefix; e.g., `MFR: {user-mfr}```Each of the fab command also take additional, manufacturer specific, options. See documentation for the individual manufacturer below:
"},{"location":"fabrication/intro/#currently-supported","title":"Currently Supported:","text":"Note: click on the name of the manufacturer to see corresponding documentation:
To add a new fabrication command you have to extend KiKit's source code. A rather basic knowledge of python is required to do so.
Create a new file kikit/fab/fabhousename.py
and implement a new command with the same name as the file. Then add the command to kikit/fab/__init__.py
. The common functionality for all fabrication houses should be located in kikit/fab/common.py
. You can use kikit/fab/jlcpcb.py
for inspiration.
Once you implement a support for new fabrication house, open a pull request on KiKit's GitHub page.
"},{"location":"fabrication/jlcpcb/","title":"Fabrication: JLC PCB","text":"The basic usage of this exporter is:
kikit fab jlcpcb [OPTIONS] BOARD OUTPUTDIR\n
When you run this command, you will find file gerbers.zip
in OUTPUTDIR
. This file can be directly uploaded to JLC PCB site. KiKit automatically detects the number of layers.
If you want to name your files differently, you can specify --nametemplate
. This option takes a string that should contain {}
. This string will be replaced by gerber
, pos
or bom
in the out file names. The extension is appended automatically.
If you would also like to use the SMD assembly service, you have to specify --assembly
option and also provide the board --schematic <schematics_file>
. KiKit will generate two extra files: bom.csv
(bill of materials) and pos.csv
(component placement). Use these two files when ordering the PCB assembly.
The files above will include all components on the board. You can override the default field name with option --field
. This option accepts a comma separated list of names. The first found field is used. This can be used, e.g., for configuration of the board via resistors. You can put field \"LCSC\" for all components, then add fields \"CFG1_LCSC\" and \"CFG2_LCSC\" for some components. Then invoke KiKit with option --field CFG1_LCSC,LCSC
for configuration 1 or --field CFG2_LCSC,LCSC
for configuration 2.
You can exclude some of the components by specifying --ignore <comma separated list of references>
. You can also specify component field with name JLCPCB_IGNORE
(the value of the field does not matter) to exclude the component from assembly. Also, if a component misses the order code field, KiKit will show warning. When you pass option --missingError
, KiKit will fail when there is a component with missing order code. This might be useful in case when you run KiKit in CI and you want to fail the build.
Note that when you order SMD assembly for a panel, you should specify panelized board and the original schematics of a single board.
"},{"location":"fabrication/jlcpcb/#correction-of-the-footprint-position","title":"Correction of the Footprint Position","text":"It is possible that orientation footprints in your SMD does not match the orientation of the components in the SMD assembly service. There are two solutions:
The first option is not always feasible - e.g., when you use KiCAD's built-in libraries or you are preparing a board for multiple fabrication houses and each of them uses a different orientation.
KiKit allows you to specify the origin and orientation correction of the position. The correction is specified by JLCPCB_CORRECTION
field. The field value is a semicolon separated tuple: <X>; <Y>; <Rotation>
with values in millimeters and degrees. You can read the XY corrections by hovering cursor over the intended origin in footprint editor and mark the coordinates. Note that first the rotation correction is applied, then the translation. Usually, you will need only the rotation correction.
If your board features solder jumpers you can use the corrections to specify their default value. The solder jumper should be designed such it can fit a zero Ohm resistor in suitable size. Then specify an order code of the zero Ohm resistor for the jumper and adjust correction so it fits the default position.
Note that you can specify multiple correction fields by --corrections <comma separated list of correction filed names>
. The first found correction field is used. This allows you to keep several configuration of the solder jumpers in your design e.g., in fields JLCPCB_CORRECTION_CFG_1
and JLCPCB_CORRECTION_CFG_2
. Then you can simply change the board configuration by calling kikit with --corrections JLCPCB_CORRECTION_CFG_1,JLCPCB_CORRECTION
or --corrections JLCPCB_CORRECTION_CFG_2,JLCPCB_CORRECTION
.
The basic usage of this exporter is:
kikit fab neodenyy1 [OPTIONS] BOARD OUTPUTDIR\n
When you run this command, you will find file top_pos.csv
and bottom_pos.csv
in OUTPUTDIR
. This file can be used in Neoden YY1. KiKit automatically detects the number of layers.
If you want to name your files differently, you can specify --nametemplate
. This option takes a string that should contain {}
. This string will be replaced by gerber
, pos
or bom
in the out file names. The extension is appended automatically.
For Neoden YY1 you must specify --assembly
option and provide the board --schematic <schematics_file>
. KiKit will generate files: top_pos.csv
(top layer component placement) and bottom_pos.csv
(bottom layer component placement). Use these two files to assembly PCB on machine.
On Neoden YY1, the position origin must use the bottom left corner of the board edge.
"},{"location":"fabrication/neodenyy1/#correction-of-the-footprint-position","title":"Correction of the Footprint Position","text":"It is possible that orientation footprints in your SMD does not match the orientation of the components in the SMD assembly service. There are two solutions:
The first option is not always feasible - e.g., when you use KiCAD's built-in libraries or you are preparing a board for multiple fabrication houses and each of them uses a different orientation.
KiKit allows you to specify the origin and orientation correction of the position. The correction is specified by YY1_CORRECTION
field. The field value is a semicolon separated tuple: <X>; <Y>; <Rotation>
with values in millimeters and degrees. You can read the XY corrections by hovering cursor over the intended origin in footprint editor and mark the coordinates. Note that first the rotation correction is applied, then the translation. Usually, you will need only the rotation correction.
The basic usage of this exporter is:
kikit fab openpn [OPTIONS] BOARD OUTPUTDIR\n
This exporter creates a single file components.pos
that mimics KiCAD native .pos
output. However, unlike KiCAD, it adds a unique identifier to component references to ensure they are unique (in the case of panels).
The basic usage of this exporter is:
kikit fab oshpark [OPTIONS] BOARD OUTPUTDIR\n
When you run this command, you will find gerbers.zip
in OUTPUTDIR
. This file can be directly uploaded to the OSH Park site. KiKit automatically detects the number of layers.
If you want to name your files differently, you can specify --nametemplate
. The extension is appended automatically.
The basic usage of this exporter is:
kikit fab pcbway [OPTIONS] BOARD OUTPUTDIR\n
When you run this command, you will find file gerbers.zip
in OUTPUTDIR
. This file can be directly uploaded to the PCBWay site. KiKit automatically detects the number of layers.
If you want to name your files differently, you can specify --nametemplate
. For detailed description of this option, see JLC PCB documentation.
If you would also like to use the SMD assembly service, you have to specify --assembly
option and also provide the board --schematic <schematics_file>
. KiKit will generate two extra files: bom.csv
(bill of materials) and pos.csv
(component placement). Use these two files when ordering the PCB assembly.
The files above will include all components on the board by default, except footprints having the attribute virtual set. You should provide the \"Manufacturer\" and \"PartNumber\" Fields for each component, where PartNumber refers to the manufacturers part number (and can safely contain non-digit characters). If the \"Description\" field is present, this value will be inserted in the \"Value/Description\" column in the BOM, otherwise the value of the component. It is recommended to provide no description for capacitors, resistors, and inductors, so that the value is inserted into the BOM for them. PCBWay also requires the soldering type (SMD, thru-hole, ...) to be specified. Any footprint only having SMD pads will be considered as \"SMD\", everything else as \"thru-hole\". You can manually overwrite the type by adding a \"Type\" field to the component. For the footprint column of the BOM the KiCad footprint name is used by default. Add a \"FootprintPCBWay\" field to overwrite this in the BOM list for a more human readable footprint name, if you want. Finally, notes or assembly instructions can be added using the \"Notes\" field.
You can exclude some of the components by specifying --ignore <comma separated list of references>
. When you pass option --missingError
, KiKit will fail when there is a component with missing manufacturer and/or part number. This might be useful in case when you run KiKit in CI and you want to fail the build.
Note that when you order assembly for a panel, you should specify panelized board and the original schematics of a single board. Use the --nBoards
parameter to specify the number of boards in the panel. The quantity column is generated by multiplying this number with the number of references in each row.
It is possible that orientation footprints in your SMD does not match the orientation of the components in the SMD assembly service. There are two solutions:
The first option is not always feasible - e.g., when you use KiCAD's built-in libraries or you are preparing a board for multiple fabrication houses and each of them uses a different orientation.
KiKit allows you to specify the origin and orientation correction of the position. The correction is specified by PCBWAY_CORRECTION
field. The field value is a semicolon separated tuple: <X>; <Y>; <Rotation>
with values in millimeters and degrees. You can read the XY corrections by hovering cursor over the intended origin in footprint editor and mark the coordinates. Note that first the rotation correction is applied, then the translation. Usually, you will need only the rotation correction.
If your board features solder jumpers you can use the corrections to specify their default value. The solder jumper should be designed such it can fit a zero Ohm resistor in suitable size. Then specify an order code of the zero Ohm resistor for the jumper and adjust correction so it fits the default position.
Note that you can specify multiple correction fields by --corrections <comma separated list of correction filed names>
. The first found correction field is used. This allows you to keep several configuration of the solder jumpers in your design e.g., in fields PCBWAY_CORRECTION_CFG_1
and PCBWAY_CORRECTION_CFG_2
. Then you can simply change the board configuration by calling kikit with --corrections PCBWAY_CORRECTION_CFG_1,PCBWAY_CORRECTION
or --corrections PCBWAY_CORRECTION_CFG_2,PCBWAY_CORRECTION
.
When you have multiple versions of KiCAD installed, it might be desirable to run KiKit with one or another (e.g., to not convert your designs into new format).
KiKit loads the Python API directly via a module, so which module is loaded (which KiCAD version is used) follows standard Python conventions. Therefore, to choose a particular KiCAD version, just specify the environmental variable PYTHONPATH
. The path have to point to a folder containing the module (pcbnew.py
file).
The most common on linux are:
stable: /usr/lib/python3/dist-packages/pcbn\nnightly: /usr/lib/kicad-nightly/lib/python3/dist-packages/\n
E.g., to run KiKit with nightly, run:
PYTHONPATH=/usr/lib/kicad-nightly/lib/python3/dist-packages/ kikit\n
To run KiKit with a KiCAD you compiled (and not installed):
PYTHONPATH=path-to-sources/build/pcbnew kikit\n
This also works when you invoke make
as environmental variables are propagated:
PYTHONPATH=/usr/lib/kicad-nightly/lib/python3/dist-packages/ make\n
"},{"location":"installation/docker/","title":"Running KiKit via Docker","text":"This method is applicable to Windows, Linux and MacOS. It provides access to all of the CLI commands in a known-working container, but doesn't allow your local install of KiCad to access KiKit via the KiKit plugin.
First, install Docker. The installation procedure varies by the platform, so Google up a recent guide for your platform.
With Docker you can skip all of the install steps and instead run KiKit via (on Linux or Mac):
docker run -v $(pwd):/kikit yaqwsx/kikit --help\n
(replacing the call to display the --help
with whatever command you want to run. Try --version
or panelize
) or on Windows:
docker run -v %cd%:/kikit yaqwsx/kikit --help\n
Note that on Windows you might have to explicitly allow for mounting directories outside your user account (see the following topic).
"},{"location":"installation/docker/#creating-an-alias-to-kikit-in-docker-to-save-some-typing","title":"Creating an alias to KiKit in Docker to save some typing","text":"If you're on Linux or Mac and are going to run commands repeatedly within the same directory you can create an alias within the current terminal session via:
alias kikit=\"docker run -v $(pwd):/kikit yaqwsx/kikit\"\n
Note that alias
is a Linux/ Unix command so won't work on Windows, you'll need to call docker run -v %cd%:/kikit yaqwsx/kikit
each time. Also note that you must update the alias (by running the same alias command again) if you move to a different directory. The current working directory for the alias is \"frozen\" at the directory you create the alias in. From then on, until you close that terminal, you'll be able to just run kikit
followed by the relevant paramenters (e.g. kikit --version
or kikit panelize
).
If you would like to run a particular version of KiKit, simply append a tag to the image name (e.g., yaqwsx/kikit:nightly
), and Docker will pull that version down and run that for you instead:
docker run -v $(pwd):/kikit yaqwsx/kikit:nightly --version\n
We provide the following containers:
A full list is available on Dockerhub.
"},{"location":"installation/docker/#mac-m1-containers","title":"Mac M1 containers","text":"There are also nightly containers of Mac M1 available with tag nightly-m1
.
If you want to use Makefile for your projects, the preferable way is to invoke make
inside the container. The Docker image contains several often used tools and you can even run KiCAD from it (if you supply it with X-server). To call make
within the container, override the container's entrypoint:
docker run -it -v $(pwd):/kikit --entrypoint '/usr/bin/make' --help\n
(replacing --help
with your make command, such as build
or test
)."},{"location":"installation/gui_and_libs/","title":"GUI and libs installation","text":""},{"location":"installation/gui_and_libs/#kikit-symbol-and-footprint-libraries","title":"KiKit Symbol and Footprint Libraries","text":"From v6 onwards KiCad comes with a \"Plugin and Content Manager\" (PCM) which can be used to add the KiKit symbol and footprint libraries used in multi-board workflows. The PCM is new functionality for KiCad though, and only does part of the installation in v6. To install the libraries using the PCM:
Tools
menu and select Plugin and Content Manager
Libraries
tab and scroll down to KiKit Library
Install
and then Apply Changes
The following steps are only required in KiCad 6, they are automated in KiCad 7:
Preferences
menu and select Manage Symbol Libraries
Global Libraries
tab, and click the +
icon towards the bottom of the window then enter kikit
(all lowercase) as the nickname, and ${KICAD6_3RD_PARTY}/symbols/com_github_yaqwsx_kikit-library/kikit.kicad_sym
as the Library Path.OK
Preferences
menu and select Manage Footprint Libraries
Global Libraries
tab, with a nickname kikit
(all lowercase again), and this time enter ${KICAD6_3RD_PARTY}/footprints/com_github_yaqwsx_kikit-library/kikit.pretty
for the Library Path.OK
kikit
alongside all the others.KiKit consists of three parts:
Unfortunately, it is not possible to install all three parts automatically in a single step due to technical limitations of KiCAD's PCM at the moment, so you have to install them separately.
"},{"location":"installation/intro/#backend-installation","title":"Backend installation","text":"The backend installation differs slightly based on the platform:
GUI plugins and libraries are available via KiCAD PCM. See details about their installation.
"},{"location":"installation/intro/#optional-dependencies","title":"Optional dependencies","text":"Some KiKit features rely on external dependencies:
We also distribute a Docker container for running KiKit in CI or on platform where it is hard to meet all dependencies. This mode doesn't support GUI. Learn more about the docker images.
"},{"location":"installation/linux/","title":"Installation on Linux","text":"KiKit is distributed as PyPi package.
"},{"location":"installation/linux/#instalation-for-kicad-installed-via-system-package-manager","title":"Instalation for KiCAD installed via system package manager","text":"The installation consists of a single command you have to enter into the terminal. If you installed KiCAD via package manager (apt, yum, etc.) you can use a regular terminal and enter pip3 install kikit
. Now you are ready to use KiKit.
However, if you installed KiCAD via Flatpak, you have to open a special terminal as Flatpak sandboxes the applications. Open terminal and invoke flatpak run --command=sh org.kicad.KiCad
, this will open a terminal session inside the KiCAD\u2019s sandbox. Now you can install pip via python3 -m ensurepip
and then, inside the same terminal you can install KiKit: python3 -m pip install kikit
. If you would like to use CLI interface, all commands have to be invoked inside the shell flatpak run --command=sh org.kicad.KiCad
, and, instead of kikit something
you have to use python -m kikit.ui something
.
Now you can test that it works:
> kikit --help\n
You should get something like this:
Usage: kikit [OPTIONS] COMMAND [ARGS]...\n\nOptions:\n --version Show the version and exit.\n --help Show this message and exit.\n\nCommands:\n drc Validate design rules of the board\n export Export KiCAD boards\n fab Export complete manufacturing data for given fabrication houses\n modify Modify board items\n panelize Panelize boards\n present Prepare board presentation\n separate Separate a single board out of a multi-board design.\n stencil Create solder paste stencils\n
Now you are done with the basic installation. If you plan to use graphical interface, install GUI frontend and libraries via PCM.
"},{"location":"installation/macos/","title":"KiKit Installation on MacOS","text":"Installation on MacOS is a little more involved as MacOS enforces that all external programs are signed. KiCAD installed via homebrew is signed, however, once plugins with binary dependencies are installed, the signature gets invalidated. This prevents KiKit from running.
The current solution is to re-sign KiCAD after KiKit installation. Therefore, KiKit's installation on MacOS is twofold: - create a self-signed certificate - install KiKit and sign KiCAD
"},{"location":"installation/macos/#create-a-codesigning-certificate","title":"Create a codesigning certificate","text":"Open Keychain a select \"Create a Certificate\":
Then, enter name \"kikit\", select \"Self-Signed Root\" and type \"Code Signing\":
Confirm and the certificate is ready.
"},{"location":"installation/macos/#install-kikit-related-wrappers","title":"Install KiKit & related wrappers","text":"We provide a script for KiKit installation's, KiCAD signing and creating a wrapper script for KiKit. You can find the script here. You can download and run it. Open a terminal and enter:
$ curl -O https://raw.githubusercontent.com/yaqwsx/KiKit/master/scripts/installMacOS.bash\n$ sudo bash installMacOS.bash\n
The script will ask you for a password several times. Once it finishes, you can test it:
$ kikit --help\nUsage: python3 -m kikit.ui [OPTIONS] COMMAND [ARGS]...\n\nOptions:\n --version Show the version and exit.\n --help Show this message and exit.\n\nCommands:\n drc Validate design rules of the board\n export Export KiCAD boards\n fab Export complete manufacturing data for given fabrication houses\n modify Modify board items\n panelize Panelize boards\n present Prepare board presentation\n separate Separate a single board out of a multi-board design.\n stencil Create solder paste stencils\n
Once you install the PCM plugin, KiKit will be available via GUI in Pcbnew.
"},{"location":"installation/upgrading/","title":"Upgrading KiKit and installing special versions","text":""},{"location":"installation/upgrading/#upgrading-kikit","title":"Upgrading KiKit","text":"If you want to upgrade KiKit, you have to perform two steps:
pip install -U kikit
in the command line (depending on the platform, see the installation instructions for individual platform).If you would like to install a specific version of KiKit (e.g., the upstream version), you can install it directly from git. The command for that is:
# The master branch (also called the upstream version) - the most up-to-date KiKit there is (but might me unstable)\npip install git+https://github.com/yaqwsx/KiKit@master\n# A concrete branch, e.g., from a pull request\npip3 install git+https://github.com/yaqwsx/KiKit@someBranchName\n
"},{"location":"installation/windows/","title":"Windows","text":""},{"location":"installation/windows/#installation-on-windows","title":"Installation on Windows","text":"To install KiKit on Windows, you have to open \"KiCAD Command Prompt\". You can find it in the start menu:
Once you have it open like this:
you can put command in there and confirm them by pressing enter. This is also the prompt from which you will invoke all KiKit's CLI commands. They, unfortunately, does not work in an ordinary Command prompt due to the way KiCAD is packaged on Windows.
Then you have to enter the following command to install it:
pip install kikit\n
Now you can test that it works:
kikit --help\n
You should get something like this:
Usage: kikit [OPTIONS] COMMAND [ARGS]...\n\nOptions:\n --version Show the version and exit.\n --help Show this message and exit.\n\nCommands:\n drc Validate design rules of the board\n export Export KiCAD boards\n fab Export complete manufacturing data for given fabrication houses\n modify Modify board items\n panelize Panelize boards\n present Prepare board presentation\n separate Separate a single board out of a multi-board design.\n stencil Create solder paste stencils\n
Now you are done with the basic installation. Don't forget to get the GUI frontend and libraries via PCM.
"},{"location":"panelization/cli/","title":"Panelization CLI","text":"The whole panelization process of KiKit's CLI is driven by a configuration structure. The configuration contains several categories (e.g., layout
, tabs
, framing
). Each of the categories have number of named parameters (e.g., tabsCount
). All categories and their parameters are described further below.
Note that you can use the pcbnew action plugin to interactively construct the panelization configuration structure.
"},{"location":"panelization/cli/#configurations","title":"Configurations","text":"The configuration can be supplied to KiKit via a JSON file with comments and from the command line. The example of a configuration in a JSON file is the following
{\n // There can be C-like comments\n \"layout\": {\n \"type\": \"grid\",\n \"rows\": 1,\n \"cols\": 1,\n \"hspace\": \"0mm\",\n \"vspace\": \"0mm\",\n \"rotation\": \"0deg\",\n \"alternation\": \"none\",\n \"renamenet\": \"Board_{n}-{orig}\",\n \"renameref\": \"{orig}\"\n },\n \"source\": {\n \"type\": \"auto\",\n \"tolerance\": \"1mm\"\n },\n \"tabs\": {\n \"type\": \"normal\",\n \"source\": \"none\"\n },\n \"cuts\": {\n \"type\": \"none\"\n },\n \"framing\": {\n \"type\": \"none\",\n \"thickness\": \"0mm\",\n },\n \"post\": {\n \"type\": \"auto\",\n \"millradius\": \"0mm\",\n \"copperfill\": false\n }\n}\n
KiKit accepts -p <configurationFile>
option to specify one or more configurations. When multiple configurations are specified, they are composed into a single configuration. The later specified configurations overwrite parameters of the former specified configurations. This allows us to start with a basic configuration and have a number of small configurations specifying details.
To give and example, consider the two following configurations:
// A\n{\n \"tabs\": {\n \"type\": \"normal\",\n \"width\": \"3mm\"\n },\n \"framing\": {\n \"type\": \"frame\"\n }\n}\n\n// B\n{\n \"framing\": {\n \"type\": \"rails\"\n \"width\": \"5mm\"\n }\n}\n
When we merge B
into A
, we get:
{\n \"tabs\": {\n \"type\": \"normal\",\n \"width\": \"3mm\"\n },\n \"framing\": {\n \"type\": \"rails\"\n \"width\": \"5mm\"\n }\n}\n
You can also override every parameter from CLI. There is an option for each category, which accepts a semicolon-separated list of key-value pairs; e.g.:
--layout 'rows: 3; cols: 4'\n
The options from CLI have the highest priority - they override values from specified from the files. If you need to specify the character ;
, you can escape it via \\
.
Therefore, a full invocation of KiKit for panelization can look like this:
kikit panelize -p myDefault.json -p useVcuts.json -p myFrame.json\n --layout 'rows: 3; cols: 4'\n board.kicad_pcb panel.kicad_pcb.\n
Note the single quotes -- without them your shell will eat the spaces and the command will be interpreted badly. The command will use our default configuration, then it will override some options to use V-cuts and then it adds a frame specified by myFrame.json
. Last we specify the panel size from CLI.
Note that KiKit always start with a default configuration (specified in the file default.json). There are also some configuration files shipped with KiKit. You can find them in the directory kikit/resources/panelizePresets
. When you want to use them via option -p
, just prefix their name with :
and drop the suffix. E.g., for vcuts.json
use -p :vcuts
.
If you would like to inspect which configuration was used by KiKit, you can dump it into a file with the -d <filename>
option.
You can specify units in the configuration files and CLI. Always specify them as string, e.g., \"2mm\" or \"0.5 inch\" (do not forget the quotes in the JSON files).
Supported length units: mm, cm, dm, m, mil, inch, in.
Supported angle units: deg, \u00b0, rad.
"},{"location":"panelization/cli/#configuration-categories","title":"Configuration categories","text":"There are the following categories: layout, source, tabs, cuts, framing, and tooling.
Each category has a mandatory parameter type
which dictates the style of that feature. Note that you can specify the type parameter in a simplified manner in the CLI by specifying it first and omitting the type
word; e.g., --cuts 'mousebites, someParameter: 10cm'
.
Types: grid, plugin
Common options:
hspace
, vspace
, space
: Specify the gap between the boards. You can specify separately vertical and horizontal spacing or you can specify space
to make them the same (it has higher priority).rotation
: Rotate the boards before placing them in the panelrenamenet
, renameref
: A pattern by which to rename the nets and references. You can use {n}
and {orig}
to get the board number and original name. Default values are Board_{n}-{orig}
for nets and {orig}
for references.baketext
: A flag that indicates if text variables should be substituted or not.The boars are placed in a grid pattern connected by tabs. There are no special options.
rows
, cols
: Specify the number of boards in the grid patternalternation
: Specify alternations of board rotation.none
: Do not alternaterows
: Rotate boards by 180\u00b0 on every next rowcols
: Rotate boards by 180\u00b0 on every next columnrowsCols
: Rotate boards by 180\u00b0 based on a chessboard patternvbackbone
, hbackbone
: The width of vertical and horizontal backbone (0 means no backbone). The backbone does not increase the spacing of the boards.vboneskip
, hboneskip
: Skip every n backbones. I.e., 1 means place only every other backbone.vbonefirst
, hbonefirst
: Specify first backbone to render. Allows to specify the offset when skipping backbones. The offset is indexed from 1.vbonecut
, hbonecut
: true/false. If there are both backbones specified, specifies if there should be a vertical or horizontal cut (or both) where the backbones cross.Implements a custom layout based on a plugin.
code
: the plugin specification. See (plugin documentation)[plugin.md] for more detailsarg
: text argument for the user pluginThis option allows you to specify the source area, e.g., when multiple boards are present. You can read more about multi-board project here.
Types: auto, rectangle, annotation
Common options:
stack
: specify the number of layers of the panel. Valid options are 2layer
, 4layer
, 6layer
or inehrit
(default). The use case for this option is when you design a multiple boards in a single desing and you separate them, however, one boards is e.g., 4 layer and one 2 layer. Then you design both of them as 4 layer and you specify stack: 2layer
for the 2 layer one when panelizing or separating.Find all board edges and use them to construct source rectangle. Suitable for most cases when there is only a single board in the design. Note that might want to increase tolerance
or specify the source area explicitly via rectangle
if you have components sticking out of your design.
tolerance
: KiKit extracts only board items that fit fully into the source area (including all drawings on all layers). Tolerance enlarges the source area by given amount, to e.g., not omit KiKit annotations for tabs or connectors sticking out of the board.Specify the source rectangle explicitly.
tlx, tly, brx, bry
: specify the coordinates (via length units) of the rectangle via top-left and bottom-right corner.KiKit offers you to place an annotation footprint kikit:Board
into your design file to name the board. The area is determined by a bounding box of the lines in the Edge.Cuts
layer that the arrows point to. Note that the tip of the arrow must lie on the PCB edge or slightly outside of it.
ref
: specify the annotation symbol referencetolerance
: see aboveTypes: fixed, spacing, full, annotation, plugin
Place tabs. To make some of the options clear, please see the explanation of tab placement process.
"},{"location":"panelization/cli/#fixed","title":"Fixed","text":"Place given number of tabs on the PCB edge. The tabs are spaced uniformly. If you need a custom tab placement (e.g., to avoid critical feature), see type annotation.
vwidth
, hwidth
, width
: The width of tabs in the vertical and horizontal direction. width
overrides both.vcount
, hcount
: Number of tabs in a given direction.mindistance
: Minimal spacing between the tabs. If there are too many tabs, their count is reduced.Place tabs on the PCB edges based on spacing.
vwidth
, hwidth
, width
: The width of tabs in the vertical and horizontal direction. width
overrides both.spacing
: The maximum spacing of the tabs.Create tabs that are full width of the PCB. Suitable for PCBs separated by V-Cuts. This mode does not make much sense for mousebites in practice. Note that in this mode the cuts do not faithfully copy the PCB outline and, instead, they cut the bounding box of the PCB. There are no other options.
cutout
: When your design features open pockets on the side, this parameter specifies extra cutout depth in order to ensure that a sharp corner of the pocket can be milled. The default is 1\u00a0mm.patchcorners
: The full tabs are appended to the nearest flat face of the PCB. If the PCB has sharp corners, you want to add patches of substrate to these corners. However, if the PCB has fillet or miter, you don't want to apply the patches.Create tabs in the corners of the PCB.
width
: The width of tabsAdd tabs based on PCB annotations. Place a footprint kikit:Tab
at the edges of your PCB. You can edit the text field prefixed with KIKIT:
to adjust the tab parameters. If you want to specify a custom tab symbol (e.g., with predefined) width, you can specify tabfootprints
as a list of footprints separated by comma. For example: myLib:Tab2mm, myLib:Tab3mm
.
The individual tabs can have the following properties specified in the text field of the component as KIKIT:<propertyname>
:
width
: width of the tab.Tabs based on a plugin.
code
: the plugin specification. See (plugin documentation)[plugin.md] for more detailsarg
: text argument for the user pluginSpecify how to perform the cuts on the tabs separating the board.
Types: none, mousebites, vcuts, layer, plugin
"},{"location":"panelization/cli/#none","title":"None","text":"Do not perform any cuts
"},{"location":"panelization/cli/#mousebites","title":"Mousebites","text":"Use mousebites to
drill
- specify drill size for the bitesspacing
- specify the spacing of the holesoffset
- specify the offset, positive offset puts the cuts into the board, negative puts the cuts into the tabsprolong
- distance for tangential prolongation of the cuts (to cut through the internal corner fillets caused by milling)clearance
- specify clearance for copper around V-cutscutcurves
- true/false - specify if curves should be approximated by straight cuts (e.g., for cutting tabs on circular boards)offset
- specify the offset, positive offset puts the cuts into the board, negative puts the cuts into the tabslayer
- specify the layer to render V-cuts on.linewidth
- specify linewidthendprolongation
- prolongation of the cut line from the board line on the side without text.textprolongation
- the same as above, just on the text sidetextoffset
- offset of the text from the cut linetemplate
- a string template for text to render. Can contain variables listed below, e.g., V-CUT {pos_mm}
.pos_mm
, pos_inch
\u2013 position of the V-cut from the panel originpos_inv_mm
, pos_inv_inch
\u2013 inverted position of the V-cut from the panel originWhen KiKit reports it cannot perform cuts, you can render the cuts into a layer with this option to understand what's going on. Shouldn't be used for the final design.
layer
- specify the layer to render the cuts on.prolong
- distance for tangential prolongation of the cuts. It has the same meaning as mousebites.linewidth
- width of line to renderCuts based on a plugin.
code
: the plugin specification. See (plugin documentation)[plugin.md] for more detailsarg
: text argument for the user pluginKiKit allows you to frame the panel with a full frame, or bottom/top or left/right rails.
Types: none, railstb, railslr, frame, tightframe, plugin Common options:
hspace
, vspace
, space
- specify the space between PCB and the frame/rail. space
overrides hspace and vspace
.width
- specify with of the rails or framefillet
, chamfer
- fillet/chamfer frame corners. Specify radius or chamfer size. You can also separately specify chamferwidth
and chamferheight
to create a non 45\u00b0 chamfer.mintotalheight
, mintotalwidth
\u2013 if needed, add extra material to the rail or frame to meet the minimal requested size. Useful for services that require minimal panel size.Add rail (either on top and bottom or on left and right) to the panel.
"},{"location":"panelization/cli/#frame","title":"Frame","text":"Add a frame around the board.
cuts
- one of none
, both
, v
, h
- specify whether to add cuts to the corners of the frame for easy removal. Default both
.Add a frame around the board which fills the whole area of the panel - the boards have just a milled slot around their perimeter.
slotwidth
- width of the milled slot.Frame based on a plugin.
code
: the plugin specification. See (plugin documentation)[plugin.md] for more detailsarg
: text argument for the user pluginAdd tooling holes to the (rail/frame of) the panel. The holes are positioned by
Types: none, 3hole, 4hole, plugin
Common options:
hoffset
, voffset
- specify the offset from from panel edgessize
- diameter of the holespaste
- if true, the holes are included in the paste layer (therefore they appear on the stencil).solderMaskMargin
- diameter of solder mask (optional)Tooling based on a plugin.
code
: the plugin specification. See (plugin documentation)[plugin.md] for more detailsarg
: text argument for the user pluginAdd fiducial to the (rail/frame of) the panel.
Types: none, 3fid, 4fid, plugin
Common options:
hoffset
, voffset
- specify the offset from from panel edgescoppersize
, opening
- diameter of the copper spot and solder mask openingpaste
- if true, the fiducials are included in the paste layer (therefore they appear on the stencil).Fiducials based on a plugin.
code
: the plugin specification. See (plugin documentation)[plugin.md] for more detailsarg
: text argument for the user pluginAdd text to the panel. Allows you to put a single block of text on panel. You can use variables enclosed in {}
. E.g. {boardTitle} | {boardDate}
. The list of all available variables in listed bellow. You can also use the variables specified in the project. They are prefixed with user-
. That is, to include your variable revision
in KiKit text, use formatting string Rev: {user-revision}
. In the case you need more independent texts on the panel, you can use sections names text2
, text3
and text3
to add at most 4 text. All these sections behave the same and accept the same options.
If you need more texts or more sophisticated placing options, see script
option from postprocess
.
Types: none, simple
Common options:
text
- The text to be displayed. Note that you can escape ;
via \\
anchor
- Origin of the text. Can be one of tl
, tr
, bl
, br
(corners), mt
, mb
, ml
, mr
(middle of sides), c
(center). The anchors refer to the panel outline. Default mt
hoffset
, voffset
- specify the offset from anchor. Respects KiCAD coordinate system. Default 0mm
.orientation
- specify the orientation (angle). Default 0deg
width
, height
- width and height of the characters (the same parameters as KiCAD uses). Default 1.5mm
.hjustify
- justification of the text. One of left
, right
, center
. Default center
.vjustify
- justification of the text. One of top
, bottom
, center
. Default center
thickness
- stroke thickness. Default 0.3mm
.layer
- specify text layerplugin
- specify the plugin that provides extra variables for the textdate
- formats current date as <year>-<month>-<day>
time24
- formats current time in 24-hour formatyear
, month
, day
, hour
, minute
, second
- individual variables for any date formatboardTitle
- the title from the source boardboardDate
- the date from the source boardboardRevision
- the revision from the source boardboardCompany
- the company from the source boardboardComment1
-boardComment9
- comments from the source boardYou can get extra variables by providing custom text plugin via the plugin
field.
Sets page size on the resulting panel and position the panel in the page. The type of style dictates paper size. The default inherit
option inherits paper size from the source board. This feature is not supported on KiCAD 5
Types: inherit
, custom
, A0
, A1
, A2
, A3
, A4
, A5
, A
, B
, C
, D
, E
, USLetter
, USLegal
, USLedger
, A0-portrait
, A1-portrait
, A2-portrait
, A3-portrait
, A4-portrait
, A5-portrait
, A-portrait
, B-portrait
, C-portrait
, D-portrait
, E-portrait
, USLetter-portrait
, USLegal-portrait
, USLedger-portrait
Common options:
anchor
- Point of the panel to be placed at given position. Can be one of tl
, tr
, bl
, br
(corners), mt
, mb
, ml
, mr
(middle of sides), c
(center). The anchors refer to the panel outline. Default mt
posx
, posy
- the position of the panel on the page. Default 50%
for posx
and 20mm
for posy
.Instead of the pre-defined paper size you can also specify a custom paper size via width
and height
.
Fill non-board areas of the panel with copper.
Types: none, solid, hatched, hex
Common options:
clearance
- optional extra clearance from the board perimeters. Suitable for, e.g., not filling the tabs with copper.edgeclearance
- specifies clearance between the fill and panel perimeter.layers
- comma-separated list of layer to fill. Default top and bottom. You can specify a shortcut all
to fill all layers.Fill with solid copper.
"},{"location":"panelization/cli/#hatched","title":"Hatched","text":"Use hatch pattern for the fill.
width
- the width of the strokesspacing
- the space between the strokesorientation
- the orientation of the strokesUse hexagon pattern for the fill.
diameter
\u2013 diameter of the hexagonsspacing
\u2013 space between the hexagonsthreshold
\u2013 a percentage value that will discard fragments smaller than given thresholdFinishing touches to the panel.
Types: auto
Common options:
copperfill
- fill tabs and frame with copper (e.g., to save etchant or to increase rigidity of flex-PCB panels)millradius
- simulate the milling operation (add fillets to the internal corners). Specify mill radius (usually 1 mm). 0 radius disables the functionality.millradiusouter
\u00ad\u2013 same as the previous one, modifies only board outer counter. No internal features of the board are affected.reconstructarcs
- the panelization process works on top of a polygonal representation of the board. This options allows to reconstruct the arcs in the design before saving the panel.refillzones
\u2013 refill the user zones after the panel is build. This is only necessary when you want your zones to avoid cuts in panel.script
- a path to custom Python file. The file should contain a function kikitPostprocess(panel, args)
that receives the prepared panel as the kikit.panelize.Panel
object and the user-supplied arguments as a string - see scriptarg
. The function can make arbitrary changes to the panel - you can append text, footprints, alter labels, etc. The function is invoked after the whole panel is constructed (including all other postprocessing). If you try to add a functionality for a common fabrication houses via scripting, consider submitting PR for KiKit.scriptarg
: An arbitrary string passed to the user post-processing script specified in script
origin
- specify if the auxilary origin an grid origin should be placed. Can be one of tl
, tr
, bl
, br
(corners), mt
, mb
, ml
, mr
(middle of sides), c
(center). Empty string does not changes the origin.dimensions
- true
or false
. Draw dimensions with the panel size.edgewidth
\u00ad\u2013 width of the line for panel edges (that is the lines in the Edge.Cuts
layer).This document will show you several examples of KiKit CLI for panelization. Note that this is not an exhaustive description of everything that KiKit can do, nor proper documentation. For further details, please refer to:
We will show everything on a single board located in docs/resources/conn.kicad_pcb
. The board looks like this when rendered via PcbDraw:
Let's start with our first panel.
Panelization command
Linux/macOSWindowskikit panelize \\\n --layout 'grid; rows: 2; cols: 2;' \\\n --tabs full \\\n --cuts vcuts \\\n docs/resources/conn.kicad_pcb panel.kicad_pcb\n
kikit panelize ^\n --layout \"grid; rows: 2; cols: 2;\" ^\n --tabs full ^\n --cuts vcuts ^\n docs/resources/conn.kicad_pcb panel.kicad_pcb\n
We specified that we want 2x2 panel, no space between board and separate them by V-cuts. We also specified that we want to build full tabs (although no tabs are visible in this example). This is ,however, essential \u2013 if we omitted tabs, no cuts between the boards would be performed. Note, that due to the rounded corners, this panel cannot be manufactured. We will fix it later.
Note that the \\
in the input is there to make shell happy, so we can break our command into multiple lines. Also note that there are single quotes around the key-value pair \u2013 again, to make shell happy and to interpret a string with spaces as a single option.
Note that on Windows you have the enter the commands into KiCAD Command Prompt instead of the regular Command Prompt. You can find it under the Start menu.
Also note that KiKit accepts all options in categories (e.g., layout
, tabs
, cuts
, ...). You can specify the parameters as a semicolon-separated key-value list. To learn about the precise syntax of the CLI and about all options, please refer to \u2013 documentation.
One side note \u2013 if you try it with your own board some components might be gone. KiKit respects the KiCAD component selection criteria. When you specify an input rectangle, only the components that fully fit inside the input rectangle are selected. This however take in account both name and value labels (even when they are hidden).
When you do not specify the source are explicitly, KiKit takes the board outline bounding box as the source area. Therefore, by default, components outside the board substrate are not copied to panel.
Note that this is intended behavior; for once it is consistent with KiCAD behavior of user selection and also it allows to easily ignore surrounding comments and drawings in the board sheet (it makes no sense to have 12 same copies of the notes around the board).
How to include the missing components? - specify the source area explicitly to include all your components - specify --source 'tolerance: 10mm'
to enlarge the board outline bounding box by e.g. 10 mm. The default value is 1 mm.
I told you that the panel above is not suitable for manufacturing. Let's see why:
Panelization command
Linux/macOSWindowskikit panelize \\\n --layout 'grid; rows: 2; cols: 2;' \\\n --tabs full \\\n --cuts vcuts \\\n --post 'millradius: 1mm' \\\n docs/resources/conn.kicad_pcb panel.kicad_pcb\n
kikit panelize ^\n --layout \"grid; rows: 2; cols: 2;\" ^\n --tabs full ^\n --cuts vcuts ^\n --post \"millradius: 1mm\" ^\n docs/resources/conn.kicad_pcb panel.kicad_pcb\n
We specified a milling simulation post-processing. This simulates the milling operation in the fab house. As you can see, the sharp internal corners cannot be manufactured. I recommend you to use milling postprocessing always \u2013 you can easily see if your cuts are off or you have too narrow slots in your design.
Usually, one would use full tabs only for rectangular boards. Usually, when you have rounded corners, you will use short tabs instead and add some space between the boards. So let's fix it:
Panelization command
Linux/macOSWindowskikit panelize \\\n --layout 'grid; rows: 2; cols: 2; space: 2mm' \\\n --tabs 'fixed; hwidth: 10mm; vwidth: 15mm' \\\n --cuts vcuts \\\n --post 'millradius: 1mm' \\\n docs/resources/conn.kicad_pcb panel.kicad_pcb\n
kikit panelize ^\n --layout \"grid; rows: 2; cols: 2; space: 2mm\" ^\n --tabs \"fixed; hwidth: 10mm; vwidth: 15mm\" ^\n --cuts vcuts ^\n --post \"millradius: 1mm\" ^\n docs/resources/conn.kicad_pcb panel.kicad_pcb\n
In that way, the rounded corners can be machined. Lets' see the same example with mousebites instead:
Panelization command
Linux/macOSWindowskikit panelize \\\n --layout 'grid; rows: 2; cols: 2; space: 2mm' \\\n --tabs 'fixed; width: 5mm' \\\n --cuts 'mousebites; drill: 0.5mm; spacing: 1mm; offset: 0.2mm' \\\n docs/resources/conn.kicad_pcb panel.kicad_pcb\n
kikit panelize ^\n --layout \"grid; rows: 2; cols: 2; space: 2mm\" ^\n --tabs \"fixed; width: 5mm\" ^\n --cuts \"mousebites; drill: 0.5mm; spacing: 1mm; offset: 0.2mm\" ^\n docs/resources/conn.kicad_pcb panel.kicad_pcb\n
We changed cut type to mousebites and we specified that they should be performed by 0.5mm holes with a spacing of 1 mm. You could also use inches if you want \u2013 just specify `in. Since we use mousebites, we used narrower tabs. We also specified that the cuts should be inset 0.25 mm into the board outline. This is suitable when your board should fit into a cover \u2013 when you break away the tabs, all burs will be inside the intended board outline.
What happens, when we simulate the milling operation?
Panelization command
Linux/macOSWindowskikit panelize \\\n --layout 'grid; rows: 2; cols: 2; space: 2mm' \\\n --tabs 'fixed; width: 5mm' \\\n --cuts 'mousebites; drill: 0.5mm; spacing: 1mm; offset: 0.2mm' \\\n --post 'millradius: 1mm' \\\n docs/resources/conn.kicad_pcb panel.kicad_pcb\n
kikit panelize ^\n --layout \"grid; rows: 2; cols: 2; space: 2mm\" ^\n --tabs \"fixed; width: 5mm\" ^\n --cuts \"mousebites; drill: 0.5mm; spacing: 1mm; offset: 0.2mm\" ^\n --post \"millradius: 1mm\" ^\n docs/resources/conn.kicad_pcb panel.kicad_pcb\n
See? The cuts are somewhat short. This is due to the internal corners that cannot be milled. KiKit can fix that for you \u2013 just specify you want to prolong your cuts tangentially by a small amount:
Panelization command
Linux/macOSWindowskikit panelize \\\n --layout 'grid; rows: 2; cols: 2; space: 2mm' \\\n --tabs 'fixed; width: 3mm' \\\n --cuts 'mousebites; drill: 0.5mm; spacing: 1mm; offset: 0.2mm; prolong: 0.5mm' \\\n --post 'millradius: 1mm' \\\n docs/resources/conn.kicad_pcb panel.kicad_pcb\n
kikit panelize ^\n --layout \"grid; rows: 2; cols: 2; space: 2mm\" ^\n --tabs \"fixed; width: 3mm\" ^\n --cuts \"mousebites; drill: 0.5mm; spacing: 1mm; offset: 0.2mm; prolong: 0.5mm\" ^\n --post \"millradius: 1mm\" ^\n docs/resources/conn.kicad_pcb panel.kicad_pcb\n
If you want, you can also specify a number of tabs to generate. KiKit will place them evenly:
Panelization command
Linux/macOSWindowskikit panelize \\\n --layout 'grid; rows: 2; cols: 2; space: 2mm' \\\n --tabs 'fixed; width: 3mm; vcount: 2' \\\n --cuts 'mousebites; drill: 0.5mm; spacing: 1mm; offset: 0.2mm; prolong: 0.5mm' \\\n --post 'millradius: 1mm' \\\n docs/resources/conn.kicad_pcb panel.kicad_pcb\n
kikit panelize ^\n --layout \"grid; rows: 2; cols: 2; space: 2mm\" ^\n --tabs \"fixed; width: 3mm; vcount: 2\" ^\n --cuts \"mousebites; drill: 0.5mm; spacing: 1mm; offset: 0.2mm; prolong: 0.5mm\" ^\n --post \"millradius: 1mm\" ^\n docs/resources/conn.kicad_pcb panel.kicad_pcb\n
You can also append frame or rails to the panel. Frames and rail are useful in the following situations:
Let's start with rails:
Panelization command
Linux/macOSWindowskikit panelize \\\n --layout 'grid; rows: 2; cols: 2; space: 2mm' \\\n --tabs 'fixed; width: 3mm; vcount: 2' \\\n --cuts 'mousebites; drill: 0.5mm; spacing: 1mm; offset: 0.2mm; prolong: 0.5mm' \\\n --framing 'railstb; width: 5mm; space: 3mm;' \\\n --post 'millradius: 1mm' \\\n docs/resources/conn.kicad_pcb panel.kicad_pcb\n
kikit panelize ^\n --layout \"grid; rows: 2; cols: 2; space: 2mm\" ^\n --tabs \"fixed; width: 3mm; vcount: 2\" ^\n --cuts \"mousebites; drill: 0.5mm; spacing: 1mm; offset: 0.2mm; prolong: 0.5mm\" ^\n --framing \"railstb; width: 5mm; space: 3mm;\" ^\n --post \"millradius: 1mm\" ^\n docs/resources/conn.kicad_pcb panel.kicad_pcb\n
Similarly, you can add left and right rail via the railslr
type. If you want a full frame, use the type frame
. When you place a full frame, it might make sense to include cuts in the corner of the frame, so you can break it apart easily. Let's see an example:
Panelization command
Linux/macOSWindowskikit panelize \\\n --layout 'grid; rows: 2; cols: 2; space: 2mm' \\\n --tabs 'fixed; width: 3mm; vcount: 2' \\\n --cuts 'mousebites; drill: 0.5mm; spacing: 1mm; offset: 0.2mm; prolong: 0.5mm' \\\n --framing 'frame; width: 5mm; space: 3mm; cuts: both' \\\n --post 'millradius: 1mm' \\\n docs/resources/conn.kicad_pcb panel.kicad_pcb\n
kikit panelize ^\n --layout \"grid; rows: 2; cols: 2; space: 2mm\" ^\n --tabs \"fixed; width: 3mm; vcount: 2\" ^\n --cuts \"mousebites; drill: 0.5mm; spacing: 1mm; offset: 0.2mm; prolong: 0.5mm\" ^\n --framing \"frame; width: 5mm; space: 3mm; cuts: both\" ^\n --post \"millradius: 1mm\" ^\n docs/resources/conn.kicad_pcb panel.kicad_pcb\n
Note that you can also use just only a vertical or horizontal frame cuts:
Panelization command
Linux/macOSWindowskikit panelize \\\n --layout 'grid; rows: 2; cols: 2; space: 2mm' \\\n --tabs 'fixed; width: 3mm; vcount: 2' \\\n --cuts 'mousebites; drill: 0.5mm; spacing: 1mm; offset: 0.2mm; prolong: 0.5mm' \\\n --framing 'frame; width: 5mm; space: 3mm; cuts: h' \\\n --post 'millradius: 1mm' \\\n docs/resources/conn.kicad_pcb panel.kicad_pcb\n
kikit panelize ^\n --layout \"grid; rows: 2; cols: 2; space: 2mm\" ^\n --tabs \"fixed; width: 3mm; vcount: 2\" ^\n --cuts \"mousebites; drill: 0.5mm; spacing: 1mm; offset: 0.2mm; prolong: 0.5mm\" ^\n --framing \"frame; width: 5mm; space: 3mm; cuts: h\" ^\n --post \"millradius: 1mm\" ^\n docs/resources/conn.kicad_pcb panel.kicad_pcb\n
When you use V-cuts it might make sense to not remove all material, but only mill a slot around the board of the board. This yields a stronger panel \u2013 and some manufacturers require such style for assembly with V-Cuts. This is achieved via framing type tightframe
. Note that it does not make much sense with mousebites.
Panelization command
Linux/macOSWindowskikit panelize \\\n --layout 'grid; rows: 2; cols: 2; space: 6mm' \\\n --tabs 'fixed; width: 3mm; vcount: 2' \\\n --cuts vcuts \\\n --framing 'tightframe; width: 5mm; space: 3mm; ' \\\n --post 'millradius: 1mm' \\\n docs/resources/conn.kicad_pcb panel.kicad_pcb\n
kikit panelize ^\n --layout \"grid; rows: 2; cols: 2; space: 6mm\" ^\n --tabs \"fixed; width: 3mm; vcount: 2\" ^\n --cuts vcuts ^\n --framing \"tightframe; width: 5mm; space: 3mm; \" ^\n --post \"millradius: 1mm\" ^\n docs/resources/conn.kicad_pcb panel.kicad_pcb\n
Once we have a frame, we can append a tooling holes, fiducials and some text to it:
Panelization command
Linux/macOSWindowskikit panelize \\\n --layout 'grid; rows: 2; cols: 2; space: 2mm' \\\n --tabs 'fixed; width: 3mm; vcount: 2' \\\n --cuts 'mousebites; drill: 0.5mm; spacing: 1mm; offset: 0.2mm; prolong: 0.5mm' \\\n --framing 'railstb; width: 5mm; space: 3mm;' \\\n --tooling '3hole; hoffset: 2.5mm; voffset: 2.5mm; size: 1.5mm' \\\n --fiducials '3fid; hoffset: 5mm; voffset: 2.5mm; coppersize: 2mm; opening: 1mm;' \\\n --text 'simple; text: yaqwsx's panel; anchor: mt; voffset: 2.5mm; hjustify: center; vjustify: center;' \\\n --post 'millradius: 1mm' \\\n docs/resources/conn.kicad_pcb panel.kicad_pcb\n
kikit panelize ^\n --layout \"grid; rows: 2; cols: 2; space: 2mm\" ^\n --tabs \"fixed; width: 3mm; vcount: 2\" ^\n --cuts \"mousebites; drill: 0.5mm; spacing: 1mm; offset: 0.2mm; prolong: 0.5mm\" ^\n --framing \"railstb; width: 5mm; space: 3mm;\" ^\n --tooling \"3hole; hoffset: 2.5mm; voffset: 2.5mm; size: 1.5mm\" ^\n --fiducials \"3fid; hoffset: 5mm; voffset: 2.5mm; coppersize: 2mm; opening: 1mm;\" ^\n --text \"simple; text: yaqwsx's panel; anchor: mt; voffset: 2.5mm; hjustify: center; vjustify: center;\" ^\n --post \"millradius: 1mm\" ^\n docs/resources/conn.kicad_pcb panel.kicad_pcb\n
If you want to add text to both rails, you can use section --text2
to add a second text. You can also use variables enclosed in curly brackets ({}
). The list of supported variables is listed in the documentation. Also, plugins can introduce new variables.
Panelization command
Linux/macOSWindowskikit panelize \\\n --layout 'grid; rows: 2; cols: 2; space: 2mm' \\\n --tabs 'fixed; width: 3mm; vcount: 2' \\\n --cuts 'mousebites; drill: 0.5mm; spacing: 1mm; offset: 0.2mm; prolong: 0.5mm' \\\n --framing 'railstb; width: 5mm; space: 3mm;' \\\n --tooling '3hole; hoffset: 2.5mm; voffset: 2.5mm; size: 1.5mm' \\\n --fiducials '3fid; hoffset: 5mm; voffset: 2.5mm; coppersize: 2mm; opening: 1mm;' \\\n --text 'simple; text: yaqwsx's panel; anchor: mt; voffset: 2.5mm; hjustify: center; vjustify: center;' \\\n --text2 'simple; text: Created on {date}; anchor: mb; voffset: -2.5mm; hjustify: center; vjustify: center;' \\\n --post 'millradius: 1mm' \\\n docs/resources/conn.kicad_pcb panel.kicad_pcb\n
kikit panelize ^\n --layout \"grid; rows: 2; cols: 2; space: 2mm\" ^\n --tabs \"fixed; width: 3mm; vcount: 2\" ^\n --cuts \"mousebites; drill: 0.5mm; spacing: 1mm; offset: 0.2mm; prolong: 0.5mm\" ^\n --framing \"railstb; width: 5mm; space: 3mm;\" ^\n --tooling \"3hole; hoffset: 2.5mm; voffset: 2.5mm; size: 1.5mm\" ^\n --fiducials \"3fid; hoffset: 5mm; voffset: 2.5mm; coppersize: 2mm; opening: 1mm;\" ^\n --text \"simple; text: yaqwsx's panel; anchor: mt; voffset: 2.5mm; hjustify: center; vjustify: center;\" ^\n --text2 \"simple; text: Created on {date}; anchor: mb; voffset: -2.5mm; hjustify: center; vjustify: center;\" ^\n --post \"millradius: 1mm\" ^\n docs/resources/conn.kicad_pcb panel.kicad_pcb\n
There are many options for text and fiducials. Be sure to read the full documentation.
If you have an automatic feeder in your PNP machine or you just dislike sharp corners, you can add a chamfer or a fillet to the panel frame/rails:
Panelization command
Linux/macOSWindowskikit panelize \\\n --layout 'grid; rows: 2; cols: 2; space: 2mm' \\\n --tabs 'fixed; width: 3mm; vcount: 2' \\\n --cuts 'mousebites; drill: 0.5mm; spacing: 1mm; offset: 0.2mm; prolong: 0.5mm' \\\n --framing 'railstb; width: 5mm; space: 3mm; fillet: 1mm' \\\n --tooling '3hole; hoffset: 2.5mm; voffset: 2.5mm; size: 1.5mm' \\\n --fiducials '3fid; hoffset: 5mm; voffset: 2.5mm; coppersize: 2mm; opening: 1mm;' \\\n --post 'millradius: 1mm' \\\n docs/resources/conn.kicad_pcb panel.kicad_pcb\n
kikit panelize ^\n --layout \"grid; rows: 2; cols: 2; space: 2mm\" ^\n --tabs \"fixed; width: 3mm; vcount: 2\" ^\n --cuts \"mousebites; drill: 0.5mm; spacing: 1mm; offset: 0.2mm; prolong: 0.5mm\" ^\n --framing \"railstb; width: 5mm; space: 3mm; fillet: 1mm\" ^\n --tooling \"3hole; hoffset: 2.5mm; voffset: 2.5mm; size: 1.5mm\" ^\n --fiducials \"3fid; hoffset: 5mm; voffset: 2.5mm; coppersize: 2mm; opening: 1mm;\" ^\n --post \"millradius: 1mm\" ^\n docs/resources/conn.kicad_pcb panel.kicad_pcb\n
Panelization command
Linux/macOSWindowskikit panelize \\\n --layout 'grid; rows: 2; cols: 2; space: 2mm' \\\n --tabs 'fixed; width: 3mm; vcount: 2' \\\n --cuts 'mousebites; drill: 0.5mm; spacing: 1mm; offset: 0.2mm; prolong: 0.5mm' \\\n --framing 'railstb; width: 5mm; space: 3mm; chamfer: 1mm' \\\n --tooling '3hole; hoffset: 2.5mm; voffset: 2.5mm; size: 1.5mm' \\\n --fiducials '3fid; hoffset: 5mm; voffset: 2.5mm; coppersize: 2mm; opening: 1mm;' \\\n --post 'millradius: 1mm' \\\n docs/resources/conn.kicad_pcb panel.kicad_pcb\n
kikit panelize ^\n --layout \"grid; rows: 2; cols: 2; space: 2mm\" ^\n --tabs \"fixed; width: 3mm; vcount: 2\" ^\n --cuts \"mousebites; drill: 0.5mm; spacing: 1mm; offset: 0.2mm; prolong: 0.5mm\" ^\n --framing \"railstb; width: 5mm; space: 3mm; chamfer: 1mm\" ^\n --tooling \"3hole; hoffset: 2.5mm; voffset: 2.5mm; size: 1.5mm\" ^\n --fiducials \"3fid; hoffset: 5mm; voffset: 2.5mm; coppersize: 2mm; opening: 1mm;\" ^\n --post \"millradius: 1mm\" ^\n docs/resources/conn.kicad_pcb panel.kicad_pcb\n
Some services, e.g., JLC PCB require a minimal panel size. If you want to ensure that your panel meets the criteria, you can specify minimal total width/height of the panel. Let's see an example:
Panelization command
Linux/macOSWindowskikit panelize \\\n --layout 'grid; rows: 2; cols: 2; space: 2mm' \\\n --tabs 'fixed; width: 3mm; vcount: 2' \\\n --cuts 'mousebites; drill: 0.5mm; spacing: 1mm; offset: 0.2mm; prolong: 0.5mm' \\\n --framing 'frame; width: 5mm; space: 3mm; mintotalheight: 100mm; mintotalwidth: 100mm' \\\n --tooling '3hole; hoffset: 2.5mm; voffset: 2.5mm; size: 1.5mm' \\\n --fiducials '3fid; hoffset: 5mm; voffset: 2.5mm; coppersize: 2mm; opening: 1mm;' \\\n --text 'simple; text: yaqwsx's panel with minimal dimensions; anchor: mt; voffset: 2.5mm; hjustify: center; vjustify: center;' \\\n --post 'millradius: 1mm' \\\n docs/resources/conn.kicad_pcb panel.kicad_pcb\n
kikit panelize ^\n --layout \"grid; rows: 2; cols: 2; space: 2mm\" ^\n --tabs \"fixed; width: 3mm; vcount: 2\" ^\n --cuts \"mousebites; drill: 0.5mm; spacing: 1mm; offset: 0.2mm; prolong: 0.5mm\" ^\n --framing \"frame; width: 5mm; space: 3mm; mintotalheight: 100mm; mintotalwidth: 100mm\" ^\n --tooling \"3hole; hoffset: 2.5mm; voffset: 2.5mm; size: 1.5mm\" ^\n --fiducials \"3fid; hoffset: 5mm; voffset: 2.5mm; coppersize: 2mm; opening: 1mm;\" ^\n --text \"simple; text: yaqwsx's panel with minimal dimensions; anchor: mt; voffset: 2.5mm; hjustify: center; vjustify: center;\" ^\n --post \"millradius: 1mm\" ^\n docs/resources/conn.kicad_pcb panel.kicad_pcb\n
"},{"location":"panelization/examples/#advanced-features-layouts","title":"Advanced features & layouts","text":"It is possible that you have some critical features you want to avoid with tabs. KiKit has several features that can help you. Let's start with the simple ones.
First, you can rotate the boards in your layout. This might make not much sense for rectanglar boards, but it might save you when you have circular or oddly shaped boards:
Panelization command
Linux/macOSWindowskikit panelize \\\n --layout 'grid; rows: 2; cols: 2; space: 0mm; rotation: 45deg;' \\\n --tabs 'fixed; width: 3mm;' \\\n --cuts 'mousebites; drill: 0.5mm; spacing: 1mm; offset: 0.2mm; prolong: 0.75mm' \\\n --framing 'frame; width: 5mm; space: 3mm; cuts: both' \\\n --post 'millradius: 1mm' \\\n docs/resources/conn.kicad_pcb panel.kicad_pcb\n
kikit panelize ^\n --layout \"grid; rows: 2; cols: 2; space: 0mm; rotation: 45deg;\" ^\n --tabs \"fixed; width: 3mm;\" ^\n --cuts \"mousebites; drill: 0.5mm; spacing: 1mm; offset: 0.2mm; prolong: 0.75mm\" ^\n --framing \"frame; width: 5mm; space: 3mm; cuts: both\" ^\n --post \"millradius: 1mm\" ^\n docs/resources/conn.kicad_pcb panel.kicad_pcb\n
When your board has a connector sticking one one side of the board, it makes sense to rotate the boards every other column, row or combination of both. KiKit supports this via layout option alternation
. You should be careful about component references when rotating boards \u2013 KiCAD's references have a property \"Stay upright\" which makes them always face up (even when placed on a panel). So be sure to turn it off before panelizing. Here's an example:
Panelization command
Linux/macOSWindowskikit panelize \\\n --layout 'grid; rows: 2; cols: 2; space: 3mm; alternation: cols;' \\\n --tabs 'fixed; width: 3mm; vcount: 2' \\\n --cuts 'mousebites; drill: 0.5mm; spacing: 1mm; offset: 0.2mm; prolong: 0.5mm' \\\n --framing 'frame; width: 5mm; space: 3mm; cuts: both' \\\n --post 'millradius: 1mm' \\\n docs/resources/conn.kicad_pcb panel.kicad_pcb\n
kikit panelize ^\n --layout \"grid; rows: 2; cols: 2; space: 3mm; alternation: cols;\" ^\n --tabs \"fixed; width: 3mm; vcount: 2\" ^\n --cuts \"mousebites; drill: 0.5mm; spacing: 1mm; offset: 0.2mm; prolong: 0.5mm\" ^\n --framing \"frame; width: 5mm; space: 3mm; cuts: both\" ^\n --post \"millradius: 1mm\" ^\n docs/resources/conn.kicad_pcb panel.kicad_pcb\n
Another solution might be to not put tabs on, e.g., vertical edges of the PCB. However, in that case your panel might be weak for further assembly. You can make it more stiff by including backbones \u2013 a full piece of substrate between the panels. You can add either vertical, horizontal or both backbones. Also, similarly with frames, you can put cuts on your backbone to make depanelization of your boards easier. Enough theory, let's see an example
Panelization command
Linux/macOSWindowskikit panelize \\\n --layout 'grid; rows: 2; cols: 2; space: 2mm; hbackbone: 5mm; hbonecut: true' \\\n --tabs 'fixed; width: 3mm; vcount: 2; hcount: 0' \\\n --cuts 'mousebites; drill: 0.5mm; spacing: 1mm; offset: 0.2mm; prolong: 0.5mm' \\\n --framing 'railstb; width: 5mm; space: 3mm;' \\\n --post 'millradius: 1mm' \\\n docs/resources/conn.kicad_pcb panel.kicad_pcb\n
kikit panelize ^\n --layout \"grid; rows: 2; cols: 2; space: 2mm; hbackbone: 5mm; hbonecut: true\" ^\n --tabs \"fixed; width: 3mm; vcount: 2; hcount: 0\" ^\n --cuts \"mousebites; drill: 0.5mm; spacing: 1mm; offset: 0.2mm; prolong: 0.5mm\" ^\n --framing \"railstb; width: 5mm; space: 3mm;\" ^\n --post \"millradius: 1mm\" ^\n docs/resources/conn.kicad_pcb panel.kicad_pcb\n
Often, not all backbones are needed. Especially for larger panels. Therefore, if you want, you can skip some of them. Consider the following 4\u00d74 panel with only ever other backbone:
Panelization command
Linux/macOSWindowskikit panelize \\\n --layout 'grid; rows: 4; cols: 4; space: 2mm; hbackbone: 5mm; vbackbone: 5mm; hboneskip: 1; vboneskip: 1' \\\n --tabs 'fixed; width: 3mm; vcount: 2; hcount: 0' \\\n --cuts 'mousebites; drill: 0.5mm; spacing: 1mm; offset: 0.2mm; prolong: 0.5mm' \\\n --framing 'railstb; width: 5mm; space: 3mm;' \\\n --post 'millradius: 1mm' \\\n docs/resources/conn.kicad_pcb panel.kicad_pcb\n
kikit panelize ^\n --layout \"grid; rows: 4; cols: 4; space: 2mm; hbackbone: 5mm; vbackbone: 5mm; hboneskip: 1; vboneskip: 1\" ^\n --tabs \"fixed; width: 3mm; vcount: 2; hcount: 0\" ^\n --cuts \"mousebites; drill: 0.5mm; spacing: 1mm; offset: 0.2mm; prolong: 0.5mm\" ^\n --framing \"railstb; width: 5mm; space: 3mm;\" ^\n --post \"millradius: 1mm\" ^\n docs/resources/conn.kicad_pcb panel.kicad_pcb\n
The most powerful feature of KiKit regarding tab placement are tabs via annotation. Remember our test board? When you open it in Pcbnew, you can see that there are some special footprints \u2013 KiKit's annotations:
They specify where to place tabs. You can even specify individual tab width via text property of the symbol. How to use it? Just specify tab type to annotation
. We also have to increase the source area tolerance, so it can capture the annotations.
Panelization command
Linux/macOSWindowskikit panelize \\\n --layout 'grid; rows: 2; cols: 2; space: 5mm;' \\\n --tabs annotation \\\n --source 'tolerance: 15mm' \\\n --cuts 'mousebites; drill: 0.5mm; spacing: 1mm; offset: 0.2mm; prolong: 0.5mm' \\\n --framing 'railstb; width: 5mm; space: 3mm;' \\\n --post 'millradius: 1mm' \\\n docs/resources/conn.kicad_pcb panel.kicad_pcb\n
kikit panelize ^\n --layout \"grid; rows: 2; cols: 2; space: 5mm;\" ^\n --tabs annotation ^\n --source \"tolerance: 15mm\" ^\n --cuts \"mousebites; drill: 0.5mm; spacing: 1mm; offset: 0.2mm; prolong: 0.5mm\" ^\n --framing \"railstb; width: 5mm; space: 3mm;\" ^\n --post \"millradius: 1mm\" ^\n docs/resources/conn.kicad_pcb panel.kicad_pcb\n
Well, the panel looks strange \u2013 right? That's because KiKit always constructs a half-bridges. When you specify the tabs location, you have to either ensure they match or put a piece of substrate they can reach \u2013 e.g., a backbone or a tightframe. If you are interested in the details, read more about tabs in section Understanding tabs. Let's fix it:
Panelization command
Linux/macOSWindowskikit panelize \\\n --layout 'grid; rows: 2; cols: 2; space: 2mm; hbackbone: 3mm; vbackbone: 3mm' \\\n --tabs annotation \\\n --source 'tolerance: 15mm' \\\n --cuts 'mousebites; drill: 0.5mm; spacing: 1mm; offset: 0.2mm; prolong: 0.5mm' \\\n --framing 'railstb; width: 5mm; space: 3mm;' \\\n --post 'millradius: 1mm' \\\n docs/resources/conn.kicad_pcb panel.kicad_pcb\n
kikit panelize ^\n --layout \"grid; rows: 2; cols: 2; space: 2mm; hbackbone: 3mm; vbackbone: 3mm\" ^\n --tabs annotation ^\n --source \"tolerance: 15mm\" ^\n --cuts \"mousebites; drill: 0.5mm; spacing: 1mm; offset: 0.2mm; prolong: 0.5mm\" ^\n --framing \"railstb; width: 5mm; space: 3mm;\" ^\n --post \"millradius: 1mm\" ^\n docs/resources/conn.kicad_pcb panel.kicad_pcb\n
Note that the annotation can have an arbitrary orientation. The arrow just must be outside board edge and points towards it. KiKit will also place only those tabs, that have a neighboring substrate. For precise algorithm, see section understanding tabs.
When you make flex PCBs or you want to save etchant, it make sense to pour copper on all non-functional parts of the panel. It will make the PCB rigid. You can do so via copperfill
section:
Panelization command
Linux/macOSWindowskikit panelize \\\n --layout 'grid; rows: 2; cols: 2; space: 2mm' \\\n --tabs 'fixed; width: 3mm;' \\\n --cuts 'mousebites; drill: 0.5mm; spacing: 1mm; offset: 0.2mm; prolong: 0.5mm' \\\n --framing 'railstb; width: 5mm; space: 3mm;' \\\n --copperfill solid \\\n --post 'millradius: 1mm;' \\\n docs/resources/conn.kicad_pcb panel.kicad_pcb\n
kikit panelize ^\n --layout \"grid; rows: 2; cols: 2; space: 2mm\" ^\n --tabs \"fixed; width: 3mm;\" ^\n --cuts \"mousebites; drill: 0.5mm; spacing: 1mm; offset: 0.2mm; prolong: 0.5mm\" ^\n --framing \"railstb; width: 5mm; space: 3mm;\" ^\n --copperfill solid ^\n --post \"millradius: 1mm;\" ^\n docs/resources/conn.kicad_pcb panel.kicad_pcb\n
When you use V-cuts with copperfill
you (or your fab house) might want to include a clearance around the V-cuts:
Panelization command
Linux/macOSWindowskikit panelize \\\n --layout 'grid; rows: 2; cols: 2; space: 2mm' \\\n --tabs 'fixed; hwidth: 10mm; vwidth: 15mm' \\\n --cuts 'vcuts; clearance: 1.5mm' \\\n --framing 'railstb; width: 5mm; space: 3mm;' \\\n --copperfill solid \\\n --post 'millradius: 1mm;' \\\n docs/resources/conn.kicad_pcb panel.kicad_pcb\n
kikit panelize ^\n --layout \"grid; rows: 2; cols: 2; space: 2mm\" ^\n --tabs \"fixed; hwidth: 10mm; vwidth: 15mm\" ^\n --cuts \"vcuts; clearance: 1.5mm\" ^\n --framing \"railstb; width: 5mm; space: 3mm;\" ^\n --copperfill solid ^\n --post \"millradius: 1mm;\" ^\n docs/resources/conn.kicad_pcb panel.kicad_pcb\n
If you, for example do not wish to cover the tabs with copper, you can also specify clearance. Also, some manufacturers don't like when you have large solid copper areas. In that case, you can use a hatch pattern to fill the area:
Panelization command
Linux/macOSWindowskikit panelize \\\n --layout 'grid; rows: 2; cols: 2; space: 2mm' \\\n --tabs 'fixed; width: 3mm;' \\\n --cuts 'mousebites; drill: 0.5mm; spacing: 1mm; offset: 0.2mm; prolong: 0.5mm' \\\n --framing 'railstb; width: 5mm; space: 3mm;' \\\n --copperfill 'hatched; clearance: 2mm; spacing: 0.5mm; width: 0.5mm' \\\n --post 'millradius: 1mm;' \\\n docs/resources/conn.kicad_pcb panel.kicad_pcb\n
kikit panelize ^\n --layout \"grid; rows: 2; cols: 2; space: 2mm\" ^\n --tabs \"fixed; width: 3mm;\" ^\n --cuts \"mousebites; drill: 0.5mm; spacing: 1mm; offset: 0.2mm; prolong: 0.5mm\" ^\n --framing \"railstb; width: 5mm; space: 3mm;\" ^\n --copperfill \"hatched; clearance: 2mm; spacing: 0.5mm; width: 0.5mm\" ^\n --post \"millradius: 1mm;\" ^\n docs/resources/conn.kicad_pcb panel.kicad_pcb\n
Note one last facts about V-cuts. V-cuts can only be straight and horizontal/vertical. But you can use them with circular boards if you want by cutting a little inside them. The option cutcurves
, that will approximate the cut by staring and ending point.
If you need something special; e.g., custom placement of tooling holes, multiple texts, etc. KiKit has you covered.
The CLI interface allows you to run a custom script over the final panel. The script can use KiKit Python interface to modify it. For the sake of simplicity, let's add a hole in the middle of the frame. Therefore, we write the following script:
from kikit.units import mm\nfrom kikit.common import toKiCADPoint\n\ndef kikitPostprocess(panel, arg):\n minx, miny, maxx, maxy = panel.panelBBox()\n position = toKiCADPoint(((minx + maxx) // 2, miny + 2 * mm))\n panel.addNPTHole(position, 3 * mm)\n
Then run KiKit:
Panelization command
Linux/macOSWindowskikit panelize \\\n --layout 'grid; rows: 2; cols: 2; space: 2mm' \\\n --tabs 'fixed; width: 3mm; vcount: 2' \\\n --cuts 'mousebites; drill: 0.5mm; spacing: 1mm; offset: 0.2mm; prolong: 0.5mm' \\\n --framing 'railstb; width: 5mm; space: 3mm;' \\\n --post 'millradius: 1mm; script: docs/resources/examplePost.py' \\\n docs/resources/conn.kicad_pcb panel.kicad_pcb\n
kikit panelize ^\n --layout \"grid; rows: 2; cols: 2; space: 2mm\" ^\n --tabs \"fixed; width: 3mm; vcount: 2\" ^\n --cuts \"mousebites; drill: 0.5mm; spacing: 1mm; offset: 0.2mm; prolong: 0.5mm\" ^\n --framing \"railstb; width: 5mm; space: 3mm;\" ^\n --post \"millradius: 1mm; script: docs/resources/examplePost.py\" ^\n docs/resources/conn.kicad_pcb panel.kicad_pcb\n
You can learn more about available functions from the comment in the source code or in the Python API reference. The basic concepts are summarized in the scripting guide.
If you implement a feature that your fab house requires (e.g., new tooling hole type), consider submitting a pull request for KiKit instead. I believe the others will benefit from it.
"},{"location":"panelization/examples/#managing-presets","title":"Managing presets","text":"The last section of this document is dedicated to management of presets. You can read the specification in the documentation for CLI. Here I would like to focus on practical examples.
As you should know from the documentation, the panelization preset is divided into sections; e. g., layout
, tabs
, etc. The key-value parameters in these sections can be specified via JSON files. In KiKit, you can specify these files via -p
option:
kikit panelize -p myPreset.json -p :<builtInPreset> <other parameters>
The parameters in the later specified presets override the parameters in the previously specified presets. This allows you to define a named piece-wise presets. Therefore, you can prepare various presets for mousebites \u2013 e.g., fineMousebites.json
and coarseMousebites.json
:
// fineMousebites.json\n{\n \"cuts\": {\n \"type\": \"mousebites\", \"drill\": \"0.5mm\", \"spacing\": \"0.9mm\", \"offset\":\n \"0.25mm\"\n }\n}\n\n// coarseMousebites.json\n{\n \"cuts\": {\n \"type\": \"mousebites\", \"drill\": \"0.3mm\", \"spacing\": \"0.2mm\", \"offset\":\n \"0.15mm\"\n }\n}\n
Then you can specify your panelization commands easily via:
kikit panelize -p fineMousebites.json <otheroptions>
Therefore, you can build a custom library of commonly used-options; e.g., per fabrication house. KiKit offers some built-in presets \u2013 see panelizePresets
. Note that the built-in preset default.json
is always used as a base and it specifies conservative default values so you can only override the options relevant for you.
To give you an example \u2013 with KiKit, you will no longer have to remember what diameter of tooling holes JLC PCB requires, just use:
kikit panelize -p :jlcTooling <otheroptions>
The panelization feature of KiKit is also available via GUI in the KiCAD's PCB editor (Pcbnew). The main use-case for the GUI is to quickly construct the desired KiKit command and fine-tune the panel. It also serves as a quick help in case you are not sure about parameter naming.
The GUI is designed to be run in a standalone instance of Pcbnew (not executed from a project) as the generated panel replaces the currently open board.
You can invoke the GUI via clicking on the panelization icon:
Then the following window will open:
There are three parts of the window:
Note that both, the command and JSON preset, does not include a parameter if it is the same with the default, built-in, preset.
Once you are happy with the parameters, you can click the \"Panelize\" button and the panel will appear in the Pcbnew work area. You can then edit the parameters and regenerate the panel. The panel you see in the Pcbnew window is only a preview. The panel is automatically saved to the specified location upon creation.
"},{"location":"panelization/intro/","title":"Automatic panelization with KiKit","text":"KiKit panelization module is designed to:
There are two ways of specifying a panel:
To tweak the KiKit UI process it is possible to use plugins. Plugins are pieces of Python code that provide some functionality. They can save you from writing a custom panelization script from scratch when you only need a custom one of the steps during panelization.
"},{"location":"panelization/plugins/#specifying-plugins","title":"Specifying plugins","text":"Some of the CLI options allow you to specify plugin. In such a case, one of the following formats is expected:
<packagename>.<pluginname>
, e.g., ExternalPackage.CircleLayout
<filename>.<pluginname>
, e.g., localFile.py.CircleLayout
All plugins, except text plugins, accept optional user text argument.
The plugins can be implemented and published as Python packages.
"},{"location":"panelization/plugins/#writing-custom-plugins","title":"Writing custom plugins","text":"The plugins should be implemented by overriding one of the plugin types specified in ../kikit/plugin.py
. Currently, the following plugin types are supported:
HookPlugin
- this is a plugin that features a number of callback that are invoked during various stages of building the panel. You can tweak the panels in these callbacks.LayoutPlugin
- this plugin implements a new layout of the boards in the panel.FramingPlugin
- this plugin implements a new style of framing.TabsPlugin
- this plugin implements a new style of tab placement.CutsPlugin
- this plugin implements a new style of cut rendering.ToolingPlugin
- this plugin implements a new style of tolling decoration.FiducialsPlugin
- this plugin implements a new style of fiducials decoration.TextVariablePlugin
- this plugins provides new variables for the text placement.All plugins except TextVariablePlugin
have attributes self.preset
containing the whole preset and self.userArg
containing the string provided by the user.
When you want to panelize a board, you are expected to load the kikit.panelize
module and create an instance of the Panel
class.
All units are in the internal KiCAD units (1 nm). You can use predefined constants to convert from/to them:
from kikit.units import *\n\nl = 1 * mm # 1 mm\nl = 42 * inch # 42 inches\nl = 15 * cm # 15 cm\na = 90 * deg # 90\u00b0\na = 1 * rad # 1 radian\n
You can also use functions fromMm(mm)
and toMm(kiUnits)
to convert to/from them if you like them more. You are also encouraged to use the functions and objects the native KiCAD Python API offers, e.g.: VECTOR2I(args),
BOX2I(args).
The kikit.panelize.Panel
class holds a panel under construction. Basically it is pcbnew.BOARD
without outlines. The outlines are held separately as shapely.MultiPolygon
so we can easily merge pieces of a substrate, add cuts and export it back to pcbnew.BOARD
. This is all handled by the class kikit.substrate.Substrate
.
There are two ways to create tabs: generate a piece of a substrate by hand, or use tab generator.
To generate a piece of a substrate, create a shapely.Polygon. Then add the piece of substrate via panelize.Panel.appendSubstrate
. This method also accepts a BOX2I
for convenience.
The tab generator is available via panelize.Panel.boardSubstrate.tab
. This method takes an origin point, direction, and tab width. It tries to build a tab by extruding a tab with the given width in the given direction and stops when it reaches an existing substrate. It returns a tuple - the tab substrate and a piece of the outline of the original board, which was removed by the tab. Then add the piece of a substrate via panelize.Panel.appendSubstrate
. This design choice was made as batch adding of substrates is more efficient. Therefore, you are advised to first generate all the tabs and then append them to the board.
You read more about the algorithms for generating tabs in a separate document understanding tabs.
"},{"location":"panelization/python_api/#cuts","title":"Cuts","text":"All methods constructing panels do not create cuts directly, instead, they return them. This allows the users to decided how to perform the cuts - e.g., mouse bites, V-Cuts, silk-screen...
The cuts are represented by shapely.LineString
. The string is oriented - a positive side of the string should face the inner side of the board. This is important when, e.g., offsetting mouse bites.
To perform the cuts, see methods of the panelize.Panel
class below.
When placing a board, you might specify source area -- a rectangle from which the components are extracted. If no source area is specified, the smallest bounding box of all Edge.Cuts is taken.
Only components that fully fit inside source area are copied to the panel. To include components sticking out of the board outline, you can specify tolerance -- a distance by which the source area is expanded when copying components.
"},{"location":"panelization/python_api/#appendboard","title":"appendBoard
","text":"appendBoard(self, filename, destination, sourceArea=None, origin=Origin.Center, \n rotationAngle=<pcbnew.EDA_ANGLE; proxy of <Swig Object of type 'EDA_ANGLE *' at 0x7f4b833f3120> >, \n shrink=False, tolerance=0, bufferOutline=1000, netRenamer=None, \n refRenamer=None, inheritDrc=True, interpretAnnotations=True, \n bakeText=False)\n
"},{"location":"panelization/python_api/#panel-class","title":"Panel class","text":"This class has the following relevant members: - board
- pcbnew.BOARD
of the panel. Does not contain any edges. - substrates
- kikit.substrate.Substrate
- individual substrates appended via None
. You can use them to get the original outline (and e.g., generate tabs accroding to it). - boardSubstrate
- kikit.substrate.Substrate
of the whole panel. - backboneLines
- a list of lines representing backbone candidates. Read more about it in understanding tabs.
addCornerChamfers
","text":"addCornerChamfers(self, horizontalSize, verticalSize=None)\n
Add chamfers to the panel frame. The chamfer is specified as size in horizontal and vertical direction. If you specify only the horizontal one, the chamfering will be 45\u00b0."},{"location":"panelization/python_api/#addcornerfiducials","title":"addCornerFiducials
","text":"addCornerFiducials(self, fidCount, horizontalOffset, verticalOffset, \n copperDiameter, openingDiameter, paste=False)\n
Add up to 4 fiducials to the top-left, top-right, bottom-left and bottom-right corner of the board (in this order). This function expects there is enough space on the board/frame/rail to place the feature. The offsets are measured from the outer edges of the substrate.
"},{"location":"panelization/python_api/#addcornerfillets","title":"addCornerFillets
","text":"addCornerFillets(self, radius)\n
None"},{"location":"panelization/python_api/#addcornertooling","title":"addCornerTooling
","text":"addCornerTooling(self, holeCount, horizontalOffset, verticalOffset, diameter, \n paste=False, solderMaskMargin=None)\n
Add up to 4 tooling holes to the top-left, top-right, bottom-left and bottom-right corner of the board (in this order). This function expects there is enough space on the board/frame/rail to place the feature. The offsets are measured from the outer edges of the substrate.
Optionally, a solder mask margin (diameter) can also be specified.
"},{"location":"panelization/python_api/#addfiducial","title":"addFiducial
","text":"addFiducial(self, position, copperDiameter, openingDiameter, bottom=False, \n paste=False, ref=None)\n
Add fiducial, i.e round copper pad with solder mask opening to the position (VECTOR2I
), with given copperDiameter and openingDiameter. By setting bottom to True, the fiducial is placed on bottom side. The fiducial can also have an opening on the stencil. This is enabled by paste = True."},{"location":"panelization/python_api/#addkeepout","title":"addKeepout
","text":"addKeepout(self, area, noTracks=True, noVias=True, noCopper=True)\n
Add a keepout area to all copper layers. Area is a shapely polygon. Return the keepout area."},{"location":"panelization/python_api/#addline","title":"addLine
","text":"addLine(self, start, end, thickness, layer)\n
Add a line to the panel based on starting and ending point"},{"location":"panelization/python_api/#addmillfillets","title":"addMillFillets
","text":"addMillFillets(self, millRadius)\n
Add fillets to inner conernes which will be produced a by mill with given radius. This operation simulares milling."},{"location":"panelization/python_api/#addnpthole","title":"addNPTHole
","text":"addNPTHole(self, position, diameter, paste=False, ref=None, \n excludedFromPos=False)\n
Add a drilled non-plated hole to the position (VECTOR2I
) with given diameter. The paste option allows to place the hole on the paste layers."},{"location":"panelization/python_api/#addpaneldimensions","title":"addPanelDimensions
","text":"addPanelDimensions(self, layer, offset)\n
Add vertial and horizontal dimensions to the panel"},{"location":"panelization/python_api/#addtabmillfillets","title":"addTabMillFillets
","text":"addTabMillFillets(self, millRadius)\n
Add fillets to inner conernes which will be produced a by mill with given radius. Simulates milling only on the outside of the board; internal features of the board are not affected."},{"location":"panelization/python_api/#addtext","title":"addText
","text":"addText(self, text, position, \n orientation=<pcbnew.EDA_ANGLE; proxy of <Swig Object of type 'EDA_ANGLE *' at 0x7f4b833f37b0> >, \n width=1500000, height=1500000, thickness=300000, \n hJustify=EDA_TEXT_HJUSTIFY_T.GR_TEXT_HJUSTIFY_CENTER, \n vJustify=EDA_TEXT_VJUSTIFY_T.GR_TEXT_VJUSTIFY_CENTER, \n layer=Layer.F_SilkS)\n
Add text at given position to the panel. If appending to the bottom side, text is automatically mirrored."},{"location":"panelization/python_api/#addvcuth","title":"addVCutH
","text":"addVCutH(self, pos)\n
Adds a horizontal V-CUT at pos (integer in KiCAD units)."},{"location":"panelization/python_api/#addvcutv","title":"addVCutV
","text":"addVCutV(self, pos)\n
Adds a horizontal V-CUT at pos (integer in KiCAD units)."},{"location":"panelization/python_api/#appendboard_1","title":"appendBoard
","text":"appendBoard(self, filename, destination, sourceArea=None, origin=Origin.Center, \n rotationAngle=<pcbnew.EDA_ANGLE; proxy of <Swig Object of type 'EDA_ANGLE *' at 0x7f4b833f3120> >, \n shrink=False, tolerance=0, bufferOutline=1000, netRenamer=None, \n refRenamer=None, inheritDrc=True, interpretAnnotations=True, \n bakeText=False)\n
Appends a board to the panel. The sourceArea (BOX2I) of the board specified by filename is extracted and placed at destination (VECTOR2I). The source area (BOX2I) can be auto detected if it is not provided. Only board items which fit entirely into the source area are selected. You can also specify rotation. Both translation and rotation origin are specified by origin. Origin specifies which point of the sourceArea is used for translation and rotation (origin it is placed to destination). It is possible to specify coarse source area and automatically shrink it if shrink is True. Tolerance enlarges (even shrinked) source area - useful for inclusion of filled zones which can reach out of the board edges or footprints that extend outside the board outline, like connectors.
You can also specify functions which will rename the net and ref names. By default, nets are renamed to \"Board_{n}-{orig}\", refs are unchanged. The renamers are given board seq number and original name.
You can also decide whether you would like to inherit design rules from this boards or not.
Similarly, you can substitute variables in the text via bakeText.
Returns bounding box (BOX2I) of the extracted area placed at the destination and the extracted substrate of the board.
"},{"location":"panelization/python_api/#appendsubstrate","title":"appendSubstrate
","text":"appendSubstrate(self, substrate)\n
Append a piece of substrate or a list of pieces to the panel. Substrate can be either BOX2I or Shapely polygon. Newly appended corners can be rounded by specifying non-zero filletRadius."},{"location":"panelization/python_api/#apply","title":"apply
","text":"apply(self, feature)\n
Apply given feature to the panel"},{"location":"panelization/python_api/#boardsbbox","title":"boardsBBox
","text":"boardsBBox(self)\n
Return common bounding box for all boards in the design (ignores the individual pieces of substrate) as a shapely box."},{"location":"panelization/python_api/#buildfulltabs","title":"buildFullTabs
","text":"buildFullTabs(self, cutoutDepth, patchCorners=True)\n
Make full tabs. This strategy basically cuts the bounding boxes of the PCBs. Not suitable for mousebites or PCB that doesn't have a rectangular outline. Expects there is a valid partition line. Return a list of cuts.
"},{"location":"panelization/python_api/#buildpartitionlinefrombb","title":"buildPartitionLineFromBB
","text":"buildPartitionLineFromBB(self, boundarySubstrates=[], safeMargin=0)\n
Builds partition & backbone line from bounding boxes of the substrates. You can optionally pass extra substrates (e.g., for frame). Without these extra substrates no partition line would be generated on the side where the boundary is, therefore, there won't be any tabs."},{"location":"panelization/python_api/#buildtabannotationscorners","title":"buildTabAnnotationsCorners
","text":"buildTabAnnotationsCorners(self, width)\n
Add tab annotations to the corners of the individual substrates."},{"location":"panelization/python_api/#buildtabannotationsfixed","title":"buildTabAnnotationsFixed
","text":"buildTabAnnotationsFixed(self, hcount, vcount, hwidth, vwidth, minDistance, \n ghostSubstrates)\n
Add tab annotations for the individual substrates based on number of tabs in horizontal and vertical direction. You can specify individual width in each direction. If the edge is short for the specified number of tabs with given minimal spacing, the count is reduced.
You can also specify ghost substrates (for the future framing).
"},{"location":"panelization/python_api/#buildtabannotationsspacing","title":"buildTabAnnotationsSpacing
","text":"buildTabAnnotationsSpacing(self, spacing, hwidth, vwidth, ghostSubstrates)\n
Add tab annotations for the individual substrates based on their spacing. You can also specify ghost substrates (for the future framing).
"},{"location":"panelization/python_api/#buildtabsfromannotations","title":"buildTabsFromAnnotations
","text":"buildTabsFromAnnotations(self, fillet)\n
Given annotations for the individual substrates, create tabs for them. Tabs are appended to the panel, cuts are returned. Expects that a valid partition line is assigned to the the panel.
"},{"location":"panelization/python_api/#cleartabsannotations","title":"clearTabsAnnotations
","text":"clearTabsAnnotations(self)\n
Remove all existing tab annotations from the panel."},{"location":"panelization/python_api/#copperfillnonboardareas","title":"copperFillNonBoardAreas
","text":"copperFillNonBoardAreas(self, clearance=1000000, \n layers=[<Layer.F_Cu: 0>, <Layer.B_Cu: 31>], \n hatched=False, strokeWidth=1000000, \n strokeSpacing=1000000, \n orientation=<pcbnew.EDA_ANGLE; proxy of <Swig Object of type 'EDA_ANGLE *' at 0x7f4b833f3510> >)\n
This function is deprecated, please, use panel features instead. Fill given layers with copper on unused areas of the panel (frame, rails and tabs). You can specify the clearance, if it should be hatched (default is solid) or shape the strokes of hatched pattern.
By default, fills top and bottom layer, but you can specify any other copper layer that is enabled.
"},{"location":"panelization/python_api/#debugrenderbackbonelines","title":"debugRenderBackboneLines
","text":"debugRenderBackboneLines(self)\n
Render partition line to the panel to be easily able to inspect them via Pcbnew."},{"location":"panelization/python_api/#debugrenderboundingboxes","title":"debugRenderBoundingBoxes
","text":"debugRenderBoundingBoxes(self)\n
None"},{"location":"panelization/python_api/#debugrenderpartitionlines","title":"debugRenderPartitionLines
","text":"debugRenderPartitionLines(self)\n
Render partition line to the panel to be easily able to inspect them via Pcbnew."},{"location":"panelization/python_api/#getauxiliaryorigin","title":"getAuxiliaryOrigin
","text":"getAuxiliaryOrigin(self)\n
None"},{"location":"panelization/python_api/#getdrufilepath","title":"getDruFilepath
","text":"getDruFilepath(self, path=None)\n
None"},{"location":"panelization/python_api/#getgridorigin","title":"getGridOrigin
","text":"getGridOrigin(self)\n
None"},{"location":"panelization/python_api/#getpagedimensions","title":"getPageDimensions
","text":"getPageDimensions(self)\n
Get page size in KiCAD units for the current panel"},{"location":"panelization/python_api/#getprlfilepath","title":"getPrlFilepath
","text":"getPrlFilepath(self, path=None)\n
None"},{"location":"panelization/python_api/#getprofilepath","title":"getProFilepath
","text":"getProFilepath(self, path=None)\n
None"},{"location":"panelization/python_api/#inheritcopperlayers","title":"inheritCopperLayers
","text":"inheritCopperLayers(self, board)\n
Update the panel's layer count to match the design being panelized. Raise an error if this is attempted twice with inconsistent layer count boards."},{"location":"panelization/python_api/#inheritdesignsettings","title":"inheritDesignSettings
","text":"inheritDesignSettings(self, board)\n
Inherit design settings from the given board specified by a filename or a board"},{"location":"panelization/python_api/#inheritpagesize","title":"inheritPageSize
","text":"inheritPageSize(self, board)\n
Inherit page size from a board specified by a filename or a board"},{"location":"panelization/python_api/#inheritproperties","title":"inheritProperties
","text":"inheritProperties(self, board)\n
Inherit text properties from a board specified by a filename or a board"},{"location":"panelization/python_api/#inherittitleblock","title":"inheritTitleBlock
","text":"inheritTitleBlock(self, board)\n
Inherit title block from a board specified by a filename or a board"},{"location":"panelization/python_api/#locateboard","title":"locateBoard
","text":"locateBoard(inputFilename, expandDist=None)\n
Given a board filename, find its source area and optionally expand it by the given distance. Parameters:
inputFilename - the path to the board file
expandDist - the distance by which to expand the board outline in each direction to ensure elements that are outside the board are included
"},{"location":"panelization/python_api/#makecutstolayer","title":"makeCutsToLayer
","text":"makeCutsToLayer(self, cuts, layer=Layer.Cmts_User, prolongation=0)\n
Take a list of cuts and render them as lines on given layer. The cuts can be prolonged just like with mousebites. The purpose of this is to aid debugging when KiKit refuses to perform cuts. Rendering them into lines can give the user better understanding of where is the problem.
"},{"location":"panelization/python_api/#makeframe","title":"makeFrame
","text":"makeFrame(self, width, hspace, vspace, minWidth=0, minHeight=0, maxWidth=None, \n maxHeight=None)\n
Build a frame around the boards. Specify width and spacing between the boards substrates and the frame. Return a tuple of vertical and horizontal cuts. Parameters:
width - width of substrate around board outlines
slotwidth - width of milled-out perimeter around board outline
hspace - horizontal space between board outline and substrate
vspace - vertical space between board outline and substrate
minWidth - if the panel doesn't meet this width, it is extended
minHeight - if the panel doesn't meet this height, it is extended
maxWidth - if the panel doesn't meet this width, TooLargeError is raised
maxHeight - if the panel doesn't meet this height, TooLargeHeight is raised
"},{"location":"panelization/python_api/#makeframecutsh","title":"makeFrameCutsH
","text":"makeFrameCutsH(self, innerArea, frameInnerArea, outerArea)\n
Generate horizontal cuts for the frame corners and return them"},{"location":"panelization/python_api/#makeframecutsv","title":"makeFrameCutsV
","text":"makeFrameCutsV(self, innerArea, frameInnerArea, outerArea)\n
Generate vertical cuts for the frame corners and return them"},{"location":"panelization/python_api/#makegrid","title":"makeGrid
","text":"makeGrid(self, boardfile, sourceArea, rows, cols, destination, placer, \n rotation=<pcbnew.EDA_ANGLE; proxy of <Swig Object of type 'EDA_ANGLE *' at 0x7f4b833f3f00> >, \n netRenamePattern=Board_{n}-{orig}, refRenamePattern=Board_{n}-{orig}, \n tolerance=0, bakeText=False)\n
Place the given board in a grid pattern with given spacing. The board position of the gride is guided via placer. The nets and references are renamed according to the patterns. Parameters:
boardfile - the path to the filename of the board to be added
sourceArea - the region within the file specified to be selected (see also tolerance, below) set to None to automatically calculate the board area from the board file with the given tolerance
rows - the number of boards to place in the vertical direction
cols - the number of boards to place in the horizontal direction
destination - the center coordinates of the first board in the grid (for example, VECTOR2I(100 * mm, 50 * mm))
rotation - the rotation angle to be applied to the source board before placing it
placer - the placement rules for boards. The builtin classes are: BasicGridPosition - places each board in its original orientation OddEvenColumnPosition - every second column has the boards rotated by 180 degrees OddEvenRowPosition - every second row has the boards rotated by 180 degrees OddEvenRowsColumnsPosition - every second row and column has the boards rotated by 180 degrees
netRenamePattern - the pattern according to which the net names are transformed The default pattern is \"Board_{n}-{orig}\" which gives each board its own instance of its nets, i.e. GND becomes Board_0-GND for the first board , and Board_1-GND for the second board etc
refRenamePattern - the pattern according to which the reference designators are transformed The default pattern is \"Board_{n}-{orig}\" which gives each board its own instance of its reference designators, so R1 becomes Board_0-R1 for the first board, Board_1-R1 for the second board etc. To keep references the same as in the original, set this to \"{orig}\"
tolerance - if no sourceArea is specified, the distance by which the selection area for the board should extend outside the board edge. If you have any objects that are on or outside the board edge, make sure this is big enough to include them. Such objects often include zone outlines and connectors.
bakeText - substitute variables in text elements
Returns a list of the placed substrates. You can use these to generate tabs, frames, backbones, etc.
"},{"location":"panelization/python_api/#makelayersvisible","title":"makeLayersVisible
","text":"makeLayersVisible(self)\n
Modify corresponding *.prl files so all the layers are visible by default"},{"location":"panelization/python_api/#makemousebites","title":"makeMouseBites
","text":"makeMouseBites(self, cuts, diameter, spacing, offset=250000, prolongation=500000)\n
Take a list of cuts and perform mouse bites. The cuts can be prolonged to"},{"location":"panelization/python_api/#makerailslr","title":"makeRailsLr
","text":"makeRailsLr(self, thickness, minWidth=0, maxWidth=None)\n
Adds a rail to left and right. You can specify minimal width the panel has to feature."},{"location":"panelization/python_api/#makerailstb","title":"makeRailsTb
","text":"makeRailsTb(self, thickness, minHeight=0, maxHeight=None)\n
Adds a rail to top and bottom. You can specify minimal height the panel has to feature. You can also specify maximal height of the panel. If the height would be exceeded, TooLargeError is raised."},{"location":"panelization/python_api/#maketightframe","title":"makeTightFrame
","text":"makeTightFrame(self, width, slotwidth, hspace, vspace, minWidth=0, minHeight=0, \n maxWidth=None, maxHeight=None)\n
Build a full frame with board perimeter milled out. Add your boards to the panel first using appendBoard or makeGrid. Parameters:
width - width of substrate around board outlines
slotwidth - width of milled-out perimeter around board outline
hspace - horizontal space between board outline and substrate
vspace - vertical space between board outline and substrate
minWidth - if the panel doesn't meet this width, it is extended
minHeight - if the panel doesn't meet this height, it is extended
maxWidth - if the panel doesn't meet this width, TooLargeError is raised
maxHeight - if the panel doesn't meet this height, TooLargeHeight is raised
"},{"location":"panelization/python_api/#makevcuts","title":"makeVCuts
","text":"makeVCuts(self, cuts, boundCurves=False, offset=0)\n
Take a list of lines to cut and performs V-CUTS. When boundCurves is set, approximate curved cuts by a line from the first and last point. Otherwise, raise an exception."},{"location":"panelization/python_api/#panelbbox","title":"panelBBox
","text":"panelBBox(self)\n
Return bounding box of the panel as a shapely box."},{"location":"panelization/python_api/#panelcorners","title":"panelCorners
","text":"panelCorners(self, horizontalOffset=0, verticalOffset=0)\n
Return the list of top-left, top-right, bottom-left and bottom-right corners of the panel. You can specify offsets."},{"location":"panelization/python_api/#renderbackbone","title":"renderBackbone
","text":"renderBackbone(self, vthickness, hthickness, vcut, hcut, vskip=0, hskip=0, \n vfirst=0, hfirst=0)\n
Render horizontal and vertical backbone lines. If zero thickness is specified, no backbone is rendered. vcut, hcut specifies if vertical or horizontal backbones should be cut.
vskip and hskip specify how many backbones should be skipped before rendering one (i.e., skip 1 meand that every other backbone will be rendered)
vfirst and hfirst are indices of the first backbone to render. They are 1-indexed.
Return a list of cuts
"},{"location":"panelization/python_api/#save","title":"save
","text":"save(self, reconstructArcs=False, refillAllZones=False)\n
Saves the panel to a file and makes the requested changes to the prl and pro files."},{"location":"panelization/python_api/#setauxiliaryorigin","title":"setAuxiliaryOrigin
","text":"setAuxiliaryOrigin(self, point)\n
Set the auxiliary origin used e.g., for drill files"},{"location":"panelization/python_api/#setcopperlayers","title":"setCopperLayers
","text":"setCopperLayers(self, count)\n
Sets the copper layer count of the panel"},{"location":"panelization/python_api/#setdesignsettings","title":"setDesignSettings
","text":"setDesignSettings(self, designSettings)\n
Set design settings"},{"location":"panelization/python_api/#setgridorigin","title":"setGridOrigin
","text":"setGridOrigin(self, point)\n
Set grid origin"},{"location":"panelization/python_api/#setpagesize","title":"setPageSize
","text":"setPageSize(self, size)\n
Set page size - either a string name (e.g., A4) or size in KiCAD units"},{"location":"panelization/python_api/#setproperties","title":"setProperties
","text":"setProperties(self, properties)\n
Set text properties cached in the board"},{"location":"panelization/python_api/#settitleblock","title":"setTitleBlock
","text":"setTitleBlock(self, titleBlock)\n
Set panel title block"},{"location":"panelization/python_api/#setvcutclearance","title":"setVCutClearance
","text":"setVCutClearance(self, clearance)\n
Set V-cut clearance"},{"location":"panelization/python_api/#setvcutlayer","title":"setVCutLayer
","text":"setVCutLayer(self, layer)\n
Set layer on which the V-Cuts will be rendered"},{"location":"panelization/python_api/#transferprojectsettings","title":"transferProjectSettings
","text":"transferProjectSettings(self)\n
Examine DRC rules of the source boards, merge them into a single set of rules and store them in *.kicad_pro file. Also stores board DRC exclusions. Also, transfers the list of net classes from the internal representation into the project file.
"},{"location":"panelization/python_api/#translate","title":"translate
","text":"translate(self, vec)\n
Translates the whole panel by vec. Such a feature can be useful to specify the panel placement in the sheet. When we translate panel as the last operation, none of the operations have to be placement-aware."},{"location":"panelization/python_api/#writecustomdrcrules","title":"writeCustomDrcRules
","text":"writeCustomDrcRules(self)\n
None"},{"location":"panelization/python_api/#substrate-class","title":"Substrate class","text":"This class represents a pice of substrate (with no components). Basically it is just a relatively thin wrapper around shapely polygons. On top of that, it keeps a partition line for the substrate. Read more about partition lines in understanding tabs.
"},{"location":"panelization/python_api/#backtosource","title":"backToSource
","text":"backToSource(self, point)\n
Return a point in the source form (if a reverse transformation was set)"},{"location":"panelization/python_api/#boundary","title":"boundary
","text":"boundary(self)\n
Return shapely geometry representing the outer ring"},{"location":"panelization/python_api/#boundingbox","title":"boundingBox
","text":"boundingBox(self)\n
Return bounding box as BOX2I"},{"location":"panelization/python_api/#bounds","title":"bounds
","text":"bounds(self)\n
Return shapely bounds of substrates"},{"location":"panelization/python_api/#cut","title":"cut
","text":"cut(self, piece)\n
Remove a piece of substrate given a shapely polygon."},{"location":"panelization/python_api/#exterior","title":"exterior
","text":"exterior(self)\n
Return a geometry representing the substrate with no holes"},{"location":"panelization/python_api/#exteriorring","title":"exteriorRing
","text":"exteriorRing(self)\n
None"},{"location":"panelization/python_api/#interiors","title":"interiors
","text":"interiors(self)\n
Return shapely interiors of the substrate"},{"location":"panelization/python_api/#issinglepiece","title":"isSinglePiece
","text":"isSinglePiece(self)\n
Decide whether the substrate consists of a single piece"},{"location":"panelization/python_api/#midpoint","title":"midpoint
","text":"midpoint(self)\n
Return a mid point of the bounding box"},{"location":"panelization/python_api/#millfillets","title":"millFillets
","text":"millFillets(self, millRadius)\n
Add fillets to inner corners which will be produced by a mill with given radius."},{"location":"panelization/python_api/#orient","title":"orient
","text":"orient(self)\n
Ensures that the substrate is oriented in a correct way."},{"location":"panelization/python_api/#removeislands","title":"removeIslands
","text":"removeIslands(self)\n
Removes all islands - pieces of substrate fully contained within the outline of another board"},{"location":"panelization/python_api/#serialize","title":"serialize
","text":"serialize(self, reconstructArcs=False)\n
Produces a list of PCB_SHAPE on the Edge.Cuts layer"},{"location":"panelization/python_api/#tab","title":"tab
","text":"tab(self, origin, direction, width, partitionLine=None, maxHeight=50000000, \n fillet=0)\n
Create a tab for the substrate. The tab starts at the specified origin (2D point) and tries to penetrate existing substrate in direction (a 2D vector). The tab is constructed with given width. If the substrate is not penetrated within maxHeight, exception is raised. When partitionLine is specified, the tab is extended to the opposite side - limited by the partition line. Note that if tab cannot span towards the partition line, then the tab is not created - it returns a tuple (None, None).
If a fillet is specified, it allows you to add fillet to the tab of specified radius.
Returns a pair tab and cut outline. Add the tab it via union - batch adding of geometry is more efficient.
"},{"location":"panelization/python_api/#translate_1","title":"translate
","text":"translate(self, vec)\n
Translate substrate by vec"},{"location":"panelization/python_api/#union","title":"union
","text":"union(self, other)\n
Appends a substrate, polygon or list of polygons. If there is a common intersection, with existing substrate, it will be merged into a single substrate."},{"location":"panelization/scripting/","title":"Introduction to scripting with KiKit","text":"This document will show you how to use KiKit as a library for panelization. The full reference for the available API is located in the next section.
"},{"location":"panelization/scripting/#basic-concepts","title":"Basic concepts","text":"Let's start with an overview of the foundational concepts in KiKit.
"},{"location":"panelization/scripting/#units","title":"Units","text":"All units are in the internal KiCAD units (1 nm). You can use predefined constants to convert from/to them:
from kikit.units import *\n\nl = 1 * mm # 1 mm\nl = 42 * inch # 42 inches\nl = 15 * cm # 15 cm\na = 90 * deg # 90\u00b0\na = 1 * rad # 1 radian\n
You can also use functions fromMm(mm)
and toMm(kiUnits)
to convert to/from them if you like them more. You are also encouraged to use the functions and objects that the native KiCAD Python API offers, e.g.: pcbnew.wxPoint(args)
, pcbnew.wxPointMM(mmx, mmy)
, pcbnew.wxRect(args)
, pcbnew.wxRectMM(x, y, wx, wy)
.
When KiKit loads a KiCAD board, it takes the Edge.Cuts layer and tries to interpret it as a set of 2D polygons. If it cannot interpret them (i.e, there is a discontinuous outline), it raises an exception.
These polygons has a notion of what is inside and what is outside. We can also perform boolean operation on them (i.e., merge two polygons, subtract one from the other, etc.). When we save the panel, the polygons are converted back to outlines. All internal operations in KiKit that changes the board shape operate on top of the polygonal representation, not the outline themselves.
The polygonal representation of board shape is called PCB substrate and it is represented by the class kikit.substrate.Substrate
. Internally, KiKit uses the library Shapely to represent the polygon. We advise you to get at least briefly familiar with it as whenever you need to create a new piece of substrate (e.g., for a tab) you will do so using the operations Shapely provides.
The Substrate
class encapsulates the functionality regarding converting an outline into a polygon and vice-versa and modification of the substrate (add/subtract from it/construct a tab for it). For convenience, it also holds the partition lines associated with the substrate. For more details about partition lines, please refer to section Tabs below.
The panel construction is handled via kikit.panelize.Panel
class. This class represents a panel under construction as pcbnew.Board
without outlines. The outlines are represented via a substrate and it is converted into outline only on saving the panel to file.
The panel class provides you with a number of methods to construct the panel; e.g., append a board at given coordinates, create a grid of boards, add piece of substrate to it, add framing, create a cut, etc.
A typical workflow with the Panel
class is the following:
appendBoard
or makeAGrid
),buildPartitionLineFromBB
or manually set. Without a partition line the automatic tab building nor backbone do not work.During the whole process you can directly access panel.board
of the type pcbnew.Board
and use the KiCAD API to add or remove the features on the boards.
Every tab consists of two features: a piece of substrate that connects the individual board on the panel and a cut that will be broken when you depanelize the board.
In KiKit, the substrate is represented as a Substrate
, more precisely as shapely.geometry.Polygon
. This substrate is appended to the resulting panel substrate. The cut is represented as a polyline of the type shapely.geometry.LineString
. KiKit accepts the polyline and it can either convert it into mouse bites or V-cuts.
You can build the tab substrate and cuts manually. In that case, just build the tab shape as Polygon
and append it to the board via Panel.appendSubstrate
. You also construct the cuts manually as LineString
and you turn it
Panel.makeMouseBites
, orPanel.makeVCuts
. You can also use Panel.addVCutV
or Panel.addVCutH
in this case and avoid creating the LineString
.You will use this approach in the simple cases or cases when you need a specially shaped tabs.
The second approach is to let KiKit generate the tabs and cuts automatically based on annotations. Annotation is just a marking on the board outline that specifies \"here should be a tab of this width\". You can read the annotations from source board (there are special footprints for that), generate it manually or use some of the strategies to place the annotations (e.g., place tabs in a spacing or in given number along edges). Note that the strategies often need a properly build partition line. Once you are finished, you can render the tabs using Panel.buildTabsFromAnnotations
. This function will merge the tab bodies and returns a list of cuts. With the list of cuts, you can further decide whether to ignore them or render them via mousebites or V-cuts. For more details on the automated process of building tabs from annotations, see understanding tabs.
The document understanding tabs also explains what is a partition line and how it is used. Let us add that partition line is represented as shapely collection of line strings. The partition line is not a single one for the whole panel, but it is stored separately for each appended board as the annotations are rendered independently for each appended board.
Also note that you can use the partition line as guide when placing features (e.g., adding a holes on backbone, etc.).
"},{"location":"panelization/scripting/#appending-boards","title":"Appending Boards","text":"The simples approach to adding boards to a panel is using Panel.appendBoard
. This places a board in the panel and also, it renames the nets such that they are panel-wise unique. This is necessary to pass DRC. You can specify the renaming pattern if you want. The substrate of the board is added the panel substrate, but it is also stored separately in Panel.substrates
as the shape of the original board can be used to generate the automatic tabs and also it is used to copper-fill the non-board areas of the panel. You can also use these substrates to build your custom features.
If you make single-board panels, you can use the function Panel.makeGrid
to quickly place the boards in a grid. The function returns the list of individual substrates. You can use the substrates e.g., to build custom tabs or other features.
When you place multiple PCB into the panel, KiKit expects you to generate a so-called partition line for each individual PCB. Partition line is an oriented (poly)line that partitions the free space between the PCBs. It gives you the information \"this part of the free space belongs to this PCB substrate and this PCB is responsible for placing tabs in that space\". So for a regular input the partition line can look like this:
For more complicated input, it can look like this:
Note several facts: - partition line is used for backbone generator - partition line is not generated automatically, it is up to the user to generate it. KiKit offers Panel.buildPartitionLineFromBB
that builds the partition line based on bounding boxes. If you need possibly a more complicated lines, you have to implement them by yourself. - partition line is used for deciding if an annotation yields a tab or not - if the tab does not hit the partition line, it is not created. - when we create partition line from bounding boxes, we include \"ghost substrates\" representing the framing, that will be added in the future.
When KiKit generates a tab, it generates it based on tab origin, direction and optionally the partition line. When a tab is successfully generated, it consists out of two components - a piece of a substrate (which will be later appended to the panel) and a cut-line.
So assume we have the following PCB outline (the PCB is below the line, there is a free space above the line):
Then you specify your tab origin and its direction:
This is your input (e.g., via an annotation). Now KiKit does its job; it shoots two rays tabWidth
apart and looks for the intersection with existing substrates. Note that if the ray starts within the PCB, no intersection will be found.
Once we have the intersections, we can easily generate the tab substrate and the cut:
Note that if we specify a partition line, than we shoot new rays in the opposite direction and try to hit the line. If we manage to do so, we get a tab. Otherwise, no tab is generated.
This is the basic algorithm for generating tabs. Well, we might also call them \"half tabs\". KiKit usually generates the half tabs around the board bounding box and then expects that two half tabs in the middle of the panel will merge into a single one. Also, KiKit first generates all the tabs and then merges them in one step to the board substrate. The cut is just a polyline which is in later steps either rendered as a V-cut or via mousebites.
"}]} \ No newline at end of file diff --git a/upstream/sitemap.xml.gz b/upstream/sitemap.xml.gz index 829b953f..050adcc3 100644 Binary files a/upstream/sitemap.xml.gz and b/upstream/sitemap.xml.gz differ diff --git a/upstream/stencil/index.html b/upstream/stencil/index.html index 0d898b6b..135812e1 100644 --- a/upstream/stencil/index.html +++ b/upstream/stencil/index.html @@ -16,7 +16,7 @@ - + @@ -1449,12 +1449,12 @@Many fabhouses offer you to create a custom stencil. However, it is pain to align them. Therefore, KiKit offers a functionality to automatically generate stencils which fit a simple 3D printed or lasercut alignment jig.
-You can find Fusion 360 model of the alignment jig here:
-https://a360.co/3iiFXKp. It it designed to be cut
-from 3mm thick acrylic. You need 4 2mm pins, 8 M2 screws and that's it. The
-frame can be customized - there two parameters of the model, frameWidth
and
-frameHeight
which define the largest PCB it can accept. I usually use
-100x100mm and 60x60mm.
The jig is available as Fusion 360 model,
+STEP or 3MF.It it designed to be cut
+from 3mm thick acrylic but you can also print it. You need 4 2mm pins, 8 M2
+screws and that's it. The frame can be customized - there two parameters of the
+model, frameWidth
and frameHeight
which define the largest PCB it can
+accept. I usually use 100x100mm and 60x60mm.
Then you issue the following command within KiKit: