Compare commits
2 Commits
1ec56ce169
...
ed1c4c4fd6
| Author | SHA1 | Date | |
|---|---|---|---|
| ed1c4c4fd6 | |||
| 0cac6e76b6 |
@@ -5942,6 +5942,396 @@
|
||||
(net 15)
|
||||
(uuid "e4f05a23-17c7-49d3-83b3-feda00e54574")
|
||||
)
|
||||
(zone
|
||||
(net 1)
|
||||
(net_name "GND")
|
||||
(layer "F.Cu")
|
||||
(uuid "2d17122f-408e-48d2-bc1c-935230b355ff")
|
||||
(hatch edge 0.5)
|
||||
(connect_pads
|
||||
(clearance 0.5)
|
||||
)
|
||||
(min_thickness 0.25)
|
||||
(filled_areas_thickness no)
|
||||
(fill yes
|
||||
(thermal_gap 0.5)
|
||||
(thermal_bridge_width 0.5)
|
||||
)
|
||||
(polygon
|
||||
(pts
|
||||
(xy 132.15 42) (xy 182.15 42) (xy 182.15 92) (xy 132.15 92)
|
||||
)
|
||||
)
|
||||
(filled_polygon
|
||||
(layer "F.Cu")
|
||||
(pts
|
||||
(xy 181.592539 42.520185) (xy 181.638294 42.572989) (xy 181.6495 42.6245) (xy 181.6495 91.3755)
|
||||
(xy 181.629815 91.442539) (xy 181.577011 91.488294) (xy 181.5255 91.4995) (xy 132.7745 91.4995)
|
||||
(xy 132.707461 91.479815) (xy 132.661706 91.427011) (xy 132.6505 91.3755) (xy 132.6505 88.874038)
|
||||
(xy 133.5495 88.874038) (xy 133.5495 89.125961) (xy 133.58891 89.374785) (xy 133.66676 89.614383)
|
||||
(xy 133.781132 89.838848) (xy 133.929201 90.042649) (xy 133.929205 90.042654) (xy 134.107345 90.220794)
|
||||
(xy 134.10735 90.220798) (xy 134.285117 90.349952) (xy 134.311155 90.36887) (xy 134.454184 90.441747)
|
||||
(xy 134.535616 90.483239) (xy 134.535618 90.483239) (xy 134.535621 90.483241) (xy 134.775215 90.56109)
|
||||
(xy 135.024038 90.6005) (xy 135.024039 90.6005) (xy 135.275961 90.6005) (xy 135.275962 90.6005)
|
||||
(xy 135.524785 90.56109) (xy 135.764379 90.483241) (xy 135.988845 90.36887) (xy 136.192656 90.220793)
|
||||
(xy 136.370793 90.042656) (xy 136.51887 89.838845) (xy 136.633241 89.614379) (xy 136.71109 89.374785)
|
||||
(xy 136.7505 89.125962) (xy 136.7505 88.874038) (xy 177.5495 88.874038) (xy 177.5495 89.125961)
|
||||
(xy 177.58891 89.374785) (xy 177.66676 89.614383) (xy 177.781132 89.838848) (xy 177.929201 90.042649)
|
||||
(xy 177.929205 90.042654) (xy 178.107345 90.220794) (xy 178.10735 90.220798) (xy 178.285117 90.349952)
|
||||
(xy 178.311155 90.36887) (xy 178.454184 90.441747) (xy 178.535616 90.483239) (xy 178.535618 90.483239)
|
||||
(xy 178.535621 90.483241) (xy 178.775215 90.56109) (xy 179.024038 90.6005) (xy 179.024039 90.6005)
|
||||
(xy 179.275961 90.6005) (xy 179.275962 90.6005) (xy 179.524785 90.56109) (xy 179.764379 90.483241)
|
||||
(xy 179.988845 90.36887) (xy 180.192656 90.220793) (xy 180.370793 90.042656) (xy 180.51887 89.838845)
|
||||
(xy 180.633241 89.614379) (xy 180.71109 89.374785) (xy 180.7505 89.125962) (xy 180.7505 88.874038)
|
||||
(xy 180.71109 88.625215) (xy 180.633241 88.385621) (xy 180.633239 88.385618) (xy 180.633239 88.385616)
|
||||
(xy 180.591747 88.304184) (xy 180.51887 88.161155) (xy 180.388031 87.98107) (xy 180.370798 87.95735)
|
||||
(xy 180.370794 87.957345) (xy 180.192654 87.779205) (xy 180.192649 87.779201) (xy 179.988848 87.631132)
|
||||
(xy 179.988847 87.631131) (xy 179.988845 87.63113) (xy 179.918747 87.595413) (xy 179.764383 87.51676)
|
||||
(xy 179.524785 87.43891) (xy 179.275962 87.3995) (xy 179.024038 87.3995) (xy 178.899626 87.419205)
|
||||
(xy 178.775214 87.43891) (xy 178.535616 87.51676) (xy 178.311151 87.631132) (xy 178.10735 87.779201)
|
||||
(xy 178.107345 87.779205) (xy 177.929205 87.957345) (xy 177.929201 87.95735) (xy 177.781132 88.161151)
|
||||
(xy 177.66676 88.385616) (xy 177.58891 88.625214) (xy 177.5495 88.874038) (xy 136.7505 88.874038)
|
||||
(xy 136.71109 88.625215) (xy 136.633241 88.385621) (xy 136.633239 88.385618) (xy 136.633239 88.385616)
|
||||
(xy 136.591747 88.304184) (xy 136.51887 88.161155) (xy 136.388031 87.98107) (xy 136.370798 87.95735)
|
||||
(xy 136.370794 87.957345) (xy 136.192654 87.779205) (xy 136.192649 87.779201) (xy 135.988848 87.631132)
|
||||
(xy 135.988847 87.631131) (xy 135.988845 87.63113) (xy 135.918747 87.595413) (xy 135.764383 87.51676)
|
||||
(xy 135.524785 87.43891) (xy 135.275962 87.3995) (xy 135.024038 87.3995) (xy 134.899626 87.419205)
|
||||
(xy 134.775214 87.43891) (xy 134.535616 87.51676) (xy 134.311151 87.631132) (xy 134.10735 87.779201)
|
||||
(xy 134.107345 87.779205) (xy 133.929205 87.957345) (xy 133.929201 87.95735) (xy 133.781132 88.161151)
|
||||
(xy 133.66676 88.385616) (xy 133.58891 88.625214) (xy 133.5495 88.874038) (xy 132.6505 88.874038)
|
||||
(xy 132.6505 86.743075) (xy 138.6985 86.743075) (xy 138.6985 86.951724) (xy 138.731137 87.157789)
|
||||
(xy 138.795612 87.35622) (xy 138.89033 87.542114) (xy 139.012965 87.710905) (xy 139.160495 87.858435)
|
||||
(xy 139.329286 87.98107) (xy 139.417116 88.025821) (xy 139.515179 88.075787) (xy 139.515181 88.075787)
|
||||
(xy 139.515184 88.075789) (xy 139.621545 88.110348) (xy 139.71361 88.140262) (xy 139.919676 88.1729)
|
||||
(xy 139.919681 88.1729) (xy 140.128324 88.1729) (xy 140.334389 88.140262) (xy 140.532816 88.075789)
|
||||
(xy 140.718714 87.98107) (xy 140.887505 87.858435) (xy 141.035035 87.710905) (xy 141.15767 87.542114)
|
||||
(xy 141.252389 87.356216) (xy 141.316862 87.157789) (xy 141.320885 87.132389) (xy 141.3495 86.951724)
|
||||
(xy 141.3495 86.743078) (xy 141.347778 86.732204) (xy 141.347778 86.732202) (xy 141.345477 86.717675)
|
||||
(xy 161.5585 86.717675) (xy 161.5585 86.926324) (xy 161.591137 87.132389) (xy 161.655612 87.33082)
|
||||
(xy 161.710687 87.43891) (xy 161.75033 87.516714) (xy 161.872965 87.685505) (xy 162.020495 87.833035)
|
||||
(xy 162.189286 87.95567) (xy 162.239135 87.981069) (xy 162.375179 88.050387) (xy 162.375181 88.050387)
|
||||
(xy 162.375184 88.050389) (xy 162.453351 88.075787) (xy 162.57361 88.114862) (xy 162.779676 88.1475)
|
||||
(xy 162.779681 88.1475) (xy 162.988324 88.1475) (xy 163.194389 88.114862) (xy 163.392816 88.050389)
|
||||
(xy 163.578714 87.95567) (xy 163.747505 87.833035) (xy 163.895035 87.685505) (xy 164.01767 87.516714)
|
||||
(xy 164.112389 87.330816) (xy 164.176862 87.132389) (xy 164.2095 86.926324) (xy 164.2095 86.717675)
|
||||
(xy 164.176862 86.51161) (xy 164.112387 86.313179) (xy 164.062421 86.215116) (xy 164.01767 86.127286)
|
||||
(xy 163.895035 85.958495) (xy 163.747505 85.810965) (xy 163.578714 85.68833) (xy 163.39282 85.593612)
|
||||
(xy 163.194389 85.529137) (xy 162.988324 85.4965) (xy 162.988319 85.4965) (xy 162.779681 85.4965)
|
||||
(xy 162.779676 85.4965) (xy 162.57361 85.529137) (xy 162.375179 85.593612) (xy 162.189285 85.68833)
|
||||
(xy 162.020493 85.810966) (xy 161.872966 85.958493) (xy 161.75033 86.127285) (xy 161.655612 86.313179)
|
||||
(xy 161.591137 86.51161) (xy 161.5585 86.717675) (xy 141.345477 86.717675) (xy 141.316862 86.53701)
|
||||
(xy 141.252387 86.338579) (xy 141.157669 86.152685) (xy 141.035035 85.983895) (xy 140.887505 85.836365)
|
||||
(xy 140.718714 85.71373) (xy 140.53282 85.619012) (xy 140.334389 85.554537) (xy 140.128324 85.5219)
|
||||
(xy 140.128319 85.5219) (xy 139.919681 85.5219) (xy 139.919676 85.5219) (xy 139.71361 85.554537)
|
||||
(xy 139.515179 85.619012) (xy 139.329285 85.71373) (xy 139.160493 85.836366) (xy 139.012966 85.983893)
|
||||
(xy 138.89033 86.152685) (xy 138.795612 86.338579) (xy 138.731137 86.53701) (xy 138.6985 86.743075)
|
||||
(xy 132.6505 86.743075) (xy 132.6505 79.817294) (xy 151.065483 79.817294) (xy 157.751569 79.817294)
|
||||
(xy 157.751569 76.975741) (xy 151.065483 76.975741) (xy 151.065483 79.817294) (xy 132.6505 79.817294)
|
||||
(xy 132.6505 58.013713) (xy 138.1655 58.013713) (xy 138.1655 58.226287) (xy 138.198754 58.436243)
|
||||
(xy 138.213145 58.480535) (xy 138.264444 58.638414) (xy 138.360951 58.82782) (xy 138.48589 58.999786)
|
||||
(xy 138.636213 59.150109) (xy 138.808182 59.27505) (xy 138.816946 59.279516) (xy 138.867742 59.327491)
|
||||
(xy 138.884536 59.395312) (xy 138.861998 59.461447) (xy 138.816946 59.500484) (xy 138.808182 59.504949)
|
||||
(xy 138.636213 59.62989) (xy 138.48589 59.780213) (xy 138.360951 59.952179) (xy 138.264444 60.141585)
|
||||
(xy 138.198753 60.34376) (xy 138.1655 60.553713) (xy 138.1655 60.766286) (xy 138.198753 60.976239)
|
||||
(xy 138.264444 61.178414) (xy 138.360951 61.36782) (xy 138.48589 61.539786) (xy 138.636213 61.690109)
|
||||
(xy 138.808182 61.81505) (xy 138.816946 61.819516) (xy 138.867742 61.867491) (xy 138.884536 61.935312)
|
||||
(xy 138.861998 62.001447) (xy 138.816946 62.040484) (xy 138.808182 62.044949) (xy 138.636213 62.16989)
|
||||
(xy 138.48589 62.320213) (xy 138.360951 62.492179) (xy 138.264444 62.681585) (xy 138.198753 62.88376)
|
||||
(xy 138.1655 63.093713) (xy 138.1655 63.306286) (xy 138.198753 63.516239) (xy 138.264444 63.718414)
|
||||
(xy 138.360951 63.90782) (xy 138.48589 64.079786) (xy 138.636213 64.230109) (xy 138.808182 64.35505)
|
||||
(xy 138.816946 64.359516) (xy 138.867742 64.407491) (xy 138.884536 64.475312) (xy 138.861998 64.541447)
|
||||
(xy 138.816946 64.580484) (xy 138.808182 64.584949) (xy 138.636213 64.70989) (xy 138.48589 64.860213)
|
||||
(xy 138.360951 65.032179) (xy 138.264444 65.221585) (xy 138.198753 65.42376) (xy 138.1655 65.633713)
|
||||
(xy 138.1655 65.846286) (xy 138.198753 66.056239) (xy 138.264444 66.258414) (xy 138.360951 66.44782)
|
||||
(xy 138.48589 66.619786) (xy 138.636213 66.770109) (xy 138.808182 66.89505) (xy 138.816946 66.899516)
|
||||
(xy 138.867742 66.947491) (xy 138.884536 67.015312) (xy 138.861998 67.081447) (xy 138.816946 67.120484)
|
||||
(xy 138.808182 67.124949) (xy 138.636213 67.24989) (xy 138.48589 67.400213) (xy 138.360951 67.572179)
|
||||
(xy 138.264444 67.761585) (xy 138.198753 67.96376) (xy 138.194162 67.992748) (xy 138.1655 68.173713)
|
||||
(xy 138.1655 68.386287) (xy 138.198754 68.596243) (xy 138.239042 68.720237) (xy 138.264444 68.798414)
|
||||
(xy 138.360951 68.98782) (xy 138.48589 69.159786) (xy 138.636213 69.310109) (xy 138.808182 69.43505)
|
||||
(xy 138.816946 69.439516) (xy 138.867742 69.487491) (xy 138.884536 69.555312) (xy 138.861998 69.621447)
|
||||
(xy 138.816946 69.660484) (xy 138.808182 69.664949) (xy 138.636213 69.78989) (xy 138.48589 69.940213)
|
||||
(xy 138.360951 70.112179) (xy 138.264444 70.301585) (xy 138.198753 70.50376) (xy 138.1655 70.713713)
|
||||
(xy 138.1655 70.926286) (xy 138.198753 71.136239) (xy 138.264444 71.338414) (xy 138.360951 71.52782)
|
||||
(xy 138.48589 71.699786) (xy 138.636213 71.850109) (xy 138.808182 71.97505) (xy 138.816946 71.979516)
|
||||
(xy 138.867742 72.027491) (xy 138.884536 72.095312) (xy 138.861998 72.161447) (xy 138.816946 72.200484)
|
||||
(xy 138.808182 72.204949) (xy 138.636213 72.32989) (xy 138.48589 72.480213) (xy 138.360951 72.652179)
|
||||
(xy 138.264444 72.841585) (xy 138.198753 73.04376) (xy 138.1655 73.253713) (xy 138.1655 73.466286)
|
||||
(xy 138.198753 73.676239) (xy 138.264444 73.878414) (xy 138.360951 74.06782) (xy 138.48589 74.239786)
|
||||
(xy 138.599818 74.353714) (xy 138.633303 74.415037) (xy 138.628319 74.484729) (xy 138.586447 74.540662)
|
||||
(xy 138.555471 74.557577) (xy 138.423912 74.606646) (xy 138.423906 74.606649) (xy 138.308812 74.692809)
|
||||
(xy 138.308809 74.692812) (xy 138.222649 74.807906) (xy 138.222645 74.807913) (xy 138.172403 74.94262)
|
||||
(xy 138.172401 74.942627) (xy 138.166 75.002155) (xy 138.166 75.65) (xy 139.082988 75.65) (xy 139.050075 75.707007)
|
||||
(xy 139.016 75.834174) (xy 139.016 75.965826) (xy 139.050075 76.092993) (xy 139.082988 76.15) (xy 138.166 76.15)
|
||||
(xy 138.166 76.797844) (xy 138.172401 76.857372) (xy 138.172403 76.857379) (xy 138.222645 76.992086)
|
||||
(xy 138.222649 76.992093) (xy 138.308809 77.107187) (xy 138.308812 77.10719) (xy 138.423906 77.19335)
|
||||
(xy 138.423913 77.193354) (xy 138.55862 77.243596) (xy 138.558627 77.243598) (xy 138.618155 77.249999)
|
||||
(xy 138.618172 77.25) (xy 139.266 77.25) (xy 139.266 76.333012) (xy 139.323007 76.365925) (xy 139.450174 76.4)
|
||||
(xy 139.581826 76.4) (xy 139.708993 76.365925) (xy 139.766 76.333012) (xy 139.766 77.25) (xy 140.413828 77.25)
|
||||
(xy 140.413844 77.249999) (xy 140.473372 77.243598) (xy 140.473379 77.243596) (xy 140.608086 77.193354)
|
||||
(xy 140.608093 77.19335) (xy 140.723187 77.10719) (xy 140.72319 77.107187) (xy 140.80935 76.992093)
|
||||
(xy 140.809354 76.992086) (xy 140.85077 76.881046) (xy 140.859596 76.85738) (xy 140.859598 76.857372)
|
||||
(xy 140.865999 76.797844) (xy 140.866 76.797827) (xy 140.866 76.15) (xy 139.949012 76.15) (xy 139.981925 76.092993)
|
||||
(xy 140.016 75.965826) (xy 140.016 75.834174) (xy 139.991761 75.743713) (xy 175.2745 75.743713)
|
||||
(xy 175.2745 75.956286) (xy 175.307753 76.166239) (xy 175.373444 76.368414) (xy 175.469951 76.55782)
|
||||
(xy 175.59489 76.729786) (xy 175.745209 76.880105) (xy 175.745214 76.880109) (xy 175.910218 76.999991)
|
||||
(xy 175.952884 77.05532) (xy 175.958863 77.124934) (xy 175.926258 77.186729) (xy 175.910218 77.200627)
|
||||
(xy 175.74554 77.320272) (xy 175.745535 77.320276) (xy 175.595276 77.470535) (xy 175.595272 77.47054)
|
||||
(xy 175.470379 77.642442) (xy 175.373904 77.831782) (xy 175.308242 78.03387) (xy 175.308242 78.033873)
|
||||
(xy 175.297769 78.1) (xy 176.345854 78.1) (xy 176.30737 78.166657) (xy 176.275 78.287465) (xy 176.275 78.412535)
|
||||
(xy 176.30737 78.533343) (xy 176.345854 78.6) (xy 175.297769 78.6) (xy 175.308242 78.666126) (xy 175.308242 78.666129)
|
||||
(xy 175.373904 78.868217) (xy 175.470379 79.057557) (xy 175.595272 79.229459) (xy 175.595276 79.229464)
|
||||
(xy 175.734143 79.368331) (xy 175.767628 79.429654) (xy 175.762644 79.499346) (xy 175.720772 79.555279)
|
||||
(xy 175.711559 79.561551) (xy 175.556342 79.657289) (xy 175.432289 79.781342) (xy 175.340187 79.930663)
|
||||
(xy 175.340186 79.930666) (xy 175.285001 80.097203) (xy 175.285001 80.097204) (xy 175.285 80.097204)
|
||||
(xy 175.2745 80.199983) (xy 175.2745 81.500001) (xy 175.274501 81.500018) (xy 175.285 81.602796)
|
||||
(xy 175.285001 81.602799) (xy 175.340185 81.769331) (xy 175.340186 81.769334) (xy 175.432288 81.918656)
|
||||
(xy 175.556344 82.042712) (xy 175.705666 82.134814) (xy 175.872203 82.189999) (xy 175.974991 82.2005)
|
||||
(xy 177.525008 82.200499) (xy 177.627797 82.189999) (xy 177.794334 82.134814) (xy 177.943656 82.042712)
|
||||
(xy 178.067712 81.918656) (xy 178.159814 81.769334) (xy 178.214999 81.602797) (xy 178.2255 81.500009)
|
||||
(xy 178.225499 80.199992) (xy 178.214999 80.097203) (xy 178.159814 79.930666) (xy 178.067712 79.781344)
|
||||
(xy 177.943656 79.657288) (xy 177.794334 79.565186) (xy 177.794332 79.565185) (xy 177.78844 79.561551)
|
||||
(xy 177.741716 79.509603) (xy 177.730493 79.440641) (xy 177.758337 79.376558) (xy 177.765856 79.36833)
|
||||
(xy 177.904728 79.229458) (xy 178.02962 79.057557) (xy 178.126095 78.868217) (xy 178.191757 78.666129)
|
||||
(xy 178.191757 78.666126) (xy 178.202231 78.6) (xy 177.154146 78.6) (xy 177.19263 78.533343) (xy 177.225 78.412535)
|
||||
(xy 177.225 78.287465) (xy 177.19263 78.166657) (xy 177.154146 78.1) (xy 178.202231 78.1) (xy 178.191757 78.033873)
|
||||
(xy 178.191757 78.03387) (xy 178.126095 77.831782) (xy 178.02962 77.642442) (xy 177.904727 77.47054)
|
||||
(xy 177.904723 77.470535) (xy 177.754464 77.320276) (xy 177.754459 77.320272) (xy 177.589781 77.200627)
|
||||
(xy 177.547115 77.145297) (xy 177.541136 77.075684) (xy 177.573741 77.013889) (xy 177.589776 76.999994)
|
||||
(xy 177.754792 76.880104) (xy 177.905104 76.729792) (xy 177.905106 76.729788) (xy 177.905109 76.729786)
|
||||
(xy 178.030048 76.55782) (xy 178.030047 76.55782) (xy 178.030051 76.557816) (xy 178.126557 76.368412)
|
||||
(xy 178.192246 76.166243) (xy 178.2255 75.956287) (xy 178.2255 75.743713) (xy 178.192246 75.533757)
|
||||
(xy 178.126557 75.331588) (xy 178.030051 75.142184) (xy 178.030049 75.142181) (xy 178.030048 75.142179)
|
||||
(xy 177.905109 74.970213) (xy 177.754786 74.81989) (xy 177.58282 74.694951) (xy 177.393414 74.598444)
|
||||
(xy 177.393413 74.598443) (xy 177.393412 74.598443) (xy 177.191243 74.532754) (xy 177.191241 74.532753)
|
||||
(xy 177.19124 74.532753) (xy 177.029957 74.507208) (xy 176.981287 74.4995) (xy 176.518713 74.4995)
|
||||
(xy 176.470042 74.507208) (xy 176.30876 74.532753) (xy 176.106585 74.598444) (xy 175.917179 74.694951)
|
||||
(xy 175.745213 74.81989) (xy 175.59489 74.970213) (xy 175.469951 75.142179) (xy 175.373444 75.331585)
|
||||
(xy 175.307753 75.53376) (xy 175.2745 75.743713) (xy 139.991761 75.743713) (xy 139.981925 75.707007)
|
||||
(xy 139.949012 75.65) (xy 140.866 75.65) (xy 140.866 75.002172) (xy 140.865999 75.002155) (xy 140.859598 74.942627)
|
||||
(xy 140.859596 74.94262) (xy 140.809354 74.807913) (xy 140.80935 74.807906) (xy 140.72319 74.692812)
|
||||
(xy 140.723187 74.692809) (xy 140.608093 74.606649) (xy 140.608088 74.606646) (xy 140.476528 74.557577)
|
||||
(xy 140.420595 74.515705) (xy 140.396178 74.450241) (xy 140.41103 74.381968) (xy 140.432175 74.35372)
|
||||
(xy 140.546104 74.239792) (xy 140.671051 74.067816) (xy 140.767557 73.878412) (xy 140.833246 73.676243)
|
||||
(xy 140.8665 73.466287) (xy 140.8665 73.253713) (xy 140.833246 73.043757) (xy 140.767557 72.841588)
|
||||
(xy 140.671051 72.652184) (xy 140.671049 72.652181) (xy 140.671048 72.652179) (xy 140.546109 72.480213)
|
||||
(xy 140.395786 72.32989) (xy 140.22382 72.204951) (xy 140.223115 72.204591) (xy 140.215054 72.200485)
|
||||
(xy 140.164259 72.152512) (xy 140.147463 72.084692) (xy 140.169999 72.018556) (xy 140.215054 71.979515)
|
||||
(xy 140.223816 71.975051) (xy 140.245789 71.959086) (xy 140.395786 71.850109) (xy 140.395788 71.850106)
|
||||
(xy 140.395792 71.850104) (xy 140.546104 71.699792) (xy 140.546106 71.699788) (xy 140.546109 71.699786)
|
||||
(xy 140.671048 71.52782) (xy 140.671047 71.52782) (xy 140.671051 71.527816) (xy 140.767557 71.338412)
|
||||
(xy 140.833246 71.136243) (xy 140.8665 70.926287) (xy 140.8665 70.713713) (xy 140.861379 70.681379)
|
||||
(xy 148.9745 70.681379) (xy 148.9745 70.86862) (xy 149.011025 71.052243) (xy 149.011027 71.052251)
|
||||
(xy 149.082676 71.225228) (xy 149.082681 71.225237) (xy 149.186697 71.380907) (xy 149.1867 71.380911)
|
||||
(xy 149.319088 71.513299) (xy 149.319092 71.513302) (xy 149.474762 71.617318) (xy 149.474768 71.617321)
|
||||
(xy 149.474769 71.617322) (xy 149.647749 71.688973) (xy 149.831379 71.725499) (xy 149.831383 71.7255)
|
||||
(xy 149.831384 71.7255) (xy 150.018617 71.7255) (xy 150.018618 71.725499) (xy 150.202251 71.688973)
|
||||
(xy 150.375231 71.617322) (xy 150.530908 71.513302) (xy 150.663302 71.380908) (xy 150.767322 71.225231)
|
||||
(xy 150.838973 71.052251) (xy 150.8755 70.868616) (xy 150.8755 70.681384) (xy 150.838973 70.497749)
|
||||
(xy 150.767322 70.324769) (xy 150.767321 70.324768) (xy 150.767318 70.324762) (xy 150.663302 70.169092)
|
||||
(xy 150.663299 70.169088) (xy 150.661819 70.167608) (xy 150.661291 70.166641) (xy 150.659437 70.164382)
|
||||
(xy 150.659865 70.16403) (xy 150.628334 70.106285) (xy 150.6255 70.079927) (xy 150.6255 68.970072)
|
||||
(xy 150.645185 68.903033) (xy 150.661823 68.882387) (xy 150.668301 68.875909) (xy 150.668302 68.875908)
|
||||
(xy 150.772322 68.720231) (xy 150.843973 68.547251) (xy 150.8805 68.363616) (xy 150.8805 68.176384)
|
||||
(xy 150.843973 67.992749) (xy 150.772322 67.819769) (xy 150.772321 67.819768) (xy 150.772318 67.819762)
|
||||
(xy 150.668302 67.664092) (xy 150.668299 67.664088) (xy 150.535911 67.5317) (xy 150.535907 67.531697)
|
||||
(xy 150.380237 67.427681) (xy 150.380228 67.427676) (xy 150.207251 67.356027) (xy 150.207243 67.356025)
|
||||
(xy 150.02362 67.3195) (xy 150.023616 67.3195) (xy 149.836384 67.3195) (xy 149.836379 67.3195) (xy 149.652756 67.356025)
|
||||
(xy 149.652748 67.356027) (xy 149.479771 67.427676) (xy 149.479762 67.427681) (xy 149.324092 67.531697)
|
||||
(xy 149.324088 67.5317) (xy 149.1917 67.664088) (xy 149.191697 67.664092) (xy 149.087681 67.819762)
|
||||
(xy 149.087676 67.819771) (xy 149.016027 67.992748) (xy 149.016025 67.992756) (xy 148.9795 68.176379)
|
||||
(xy 148.9795 68.36362) (xy 149.016025 68.547243) (xy 149.016027 68.547251) (xy 149.087676 68.720228)
|
||||
(xy 149.087681 68.720237) (xy 149.191697 68.875907) (xy 149.195563 68.880618) (xy 149.193556 68.882264)
|
||||
(xy 149.22165 68.933637) (xy 149.2245 68.960072) (xy 149.2245 70.079927) (xy 149.204815 70.146966)
|
||||
(xy 149.188181 70.167608) (xy 149.1867 70.169088) (xy 149.186697 70.169092) (xy 149.082681 70.324762)
|
||||
(xy 149.082676 70.324771) (xy 149.011027 70.497748) (xy 149.011025 70.497756) (xy 148.9745 70.681379)
|
||||
(xy 140.861379 70.681379) (xy 140.833246 70.503757) (xy 140.767557 70.301588) (xy 140.671051 70.112184)
|
||||
(xy 140.671049 70.112181) (xy 140.671048 70.112179) (xy 140.546109 69.940213) (xy 140.395786 69.78989)
|
||||
(xy 140.22382 69.664951) (xy 140.223115 69.664591) (xy 140.215054 69.660485) (xy 140.164259 69.612512)
|
||||
(xy 140.147463 69.544692) (xy 140.169999 69.478556) (xy 140.215054 69.439515) (xy 140.223816 69.435051)
|
||||
(xy 140.245789 69.419086) (xy 140.395786 69.310109) (xy 140.395788 69.310106) (xy 140.395792 69.310104)
|
||||
(xy 140.546104 69.159792) (xy 140.546106 69.159788) (xy 140.546109 69.159786) (xy 140.671048 68.98782)
|
||||
(xy 140.671047 68.98782) (xy 140.671051 68.987816) (xy 140.767557 68.798412) (xy 140.833246 68.596243)
|
||||
(xy 140.8665 68.386287) (xy 140.8665 68.173713) (xy 140.833246 67.963757) (xy 140.767557 67.761588)
|
||||
(xy 140.671051 67.572184) (xy 140.671049 67.572181) (xy 140.671048 67.572179) (xy 140.546109 67.400213)
|
||||
(xy 140.395786 67.24989) (xy 140.22382 67.124951) (xy 140.223115 67.124591) (xy 140.215054 67.120485)
|
||||
(xy 140.164259 67.072512) (xy 140.147463 67.004692) (xy 140.169999 66.938556) (xy 140.215054 66.899515)
|
||||
(xy 140.223816 66.895051) (xy 140.245789 66.879086) (xy 140.395786 66.770109) (xy 140.395788 66.770106)
|
||||
(xy 140.395792 66.770104) (xy 140.546104 66.619792) (xy 140.546106 66.619788) (xy 140.546109 66.619786)
|
||||
(xy 140.671048 66.44782) (xy 140.671047 66.44782) (xy 140.671051 66.447816) (xy 140.767557 66.258412)
|
||||
(xy 140.833246 66.056243) (xy 140.8665 65.846287) (xy 140.8665 65.633713) (xy 140.833246 65.423757)
|
||||
(xy 140.767557 65.221588) (xy 140.671051 65.032184) (xy 140.671049 65.032181) (xy 140.671048 65.032179)
|
||||
(xy 140.546109 64.860213) (xy 140.395786 64.70989) (xy 140.22382 64.584951) (xy 140.223115 64.584591)
|
||||
(xy 140.215054 64.580485) (xy 140.164259 64.532512) (xy 140.147463 64.464692) (xy 140.169999 64.398556)
|
||||
(xy 140.215054 64.359515) (xy 140.223816 64.355051) (xy 140.245789 64.339086) (xy 140.395786 64.230109)
|
||||
(xy 140.395788 64.230106) (xy 140.395792 64.230104) (xy 140.546104 64.079792) (xy 140.546106 64.079788)
|
||||
(xy 140.546109 64.079786) (xy 140.671048 63.90782) (xy 140.671047 63.90782) (xy 140.671051 63.907816)
|
||||
(xy 140.767557 63.718412) (xy 140.833246 63.516243) (xy 140.8665 63.306287) (xy 140.8665 63.093713)
|
||||
(xy 140.833246 62.883757) (xy 140.767557 62.681588) (xy 140.671051 62.492184) (xy 140.671049 62.492181)
|
||||
(xy 140.671048 62.492179) (xy 140.546109 62.320213) (xy 140.395786 62.16989) (xy 140.22382 62.044951)
|
||||
(xy 140.223115 62.044591) (xy 140.215054 62.040485) (xy 140.164259 61.992512) (xy 140.147463 61.924692)
|
||||
(xy 140.169999 61.858556) (xy 140.215054 61.819515) (xy 140.223816 61.815051) (xy 140.245789 61.799086)
|
||||
(xy 140.395786 61.690109) (xy 140.395788 61.690106) (xy 140.395792 61.690104) (xy 140.546104 61.539792)
|
||||
(xy 140.546106 61.539788) (xy 140.546109 61.539786) (xy 140.671048 61.36782) (xy 140.671047 61.36782)
|
||||
(xy 140.671051 61.367816) (xy 140.767557 61.178412) (xy 140.833246 60.976243) (xy 140.8665 60.766287)
|
||||
(xy 140.8665 60.553713) (xy 140.833246 60.343757) (xy 140.767557 60.141588) (xy 140.671051 59.952184)
|
||||
(xy 140.671049 59.952181) (xy 140.671048 59.952179) (xy 140.546109 59.780213) (xy 140.395786 59.62989)
|
||||
(xy 140.22382 59.504951) (xy 140.223115 59.504591) (xy 140.215054 59.500485) (xy 140.164259 59.452512)
|
||||
(xy 140.147463 59.384692) (xy 140.169999 59.318556) (xy 140.215054 59.279515) (xy 140.223816 59.275051)
|
||||
(xy 140.359245 59.176657) (xy 140.395786 59.150109) (xy 140.395788 59.150106) (xy 140.395792 59.150104)
|
||||
(xy 140.546104 58.999792) (xy 140.546106 58.999788) (xy 140.546109 58.999786) (xy 140.671048 58.82782)
|
||||
(xy 140.671047 58.82782) (xy 140.671051 58.827816) (xy 140.767557 58.638412) (xy 140.833246 58.436243)
|
||||
(xy 140.8665 58.226287) (xy 140.8665 58.013713) (xy 140.833246 57.803757) (xy 140.767557 57.601588)
|
||||
(xy 140.671051 57.412184) (xy 140.671049 57.412181) (xy 140.671048 57.412179) (xy 140.546109 57.240213)
|
||||
(xy 140.395786 57.08989) (xy 140.22382 56.964951) (xy 140.034412 56.868443) (xy 140.029269 56.866772)
|
||||
(xy 139.832243 56.802754) (xy 139.832241 56.802753) (xy 139.83224 56.802753) (xy 139.670957 56.777208)
|
||||
(xy 139.622287 56.7695) (xy 139.409713 56.7695) (xy 139.361042 56.777208) (xy 139.19976 56.802753)
|
||||
(xy 138.997585 56.868444) (xy 138.808179 56.964951) (xy 138.636213 57.08989) (xy 138.48589 57.240213)
|
||||
(xy 138.360951 57.412179) (xy 138.264444 57.601585) (xy 138.198753 57.80376) (xy 138.185077 57.890109)
|
||||
(xy 138.1655 58.013713) (xy 132.6505 58.013713) (xy 132.6505 56.753713) (xy 175.2645 56.753713)
|
||||
(xy 175.2645 56.966287) (xy 175.297754 57.176243) (xy 175.318539 57.240213) (xy 175.363444 57.378414)
|
||||
(xy 175.459951 57.56782) (xy 175.58489 57.739786) (xy 175.735209 57.890105) (xy 175.735214 57.890109)
|
||||
(xy 175.900218 58.009991) (xy 175.942884 58.06532) (xy 175.948863 58.134934) (xy 175.916258 58.196729)
|
||||
(xy 175.900218 58.210627) (xy 175.73554 58.330272) (xy 175.735535 58.330276) (xy 175.585276 58.480535)
|
||||
(xy 175.585272 58.48054) (xy 175.460379 58.652442) (xy 175.363904 58.841782) (xy 175.298242 59.04387)
|
||||
(xy 175.298242 59.043873) (xy 175.287769 59.11) (xy 176.335854 59.11) (xy 176.29737 59.176657) (xy 176.265 59.297465)
|
||||
(xy 176.265 59.422535) (xy 176.29737 59.543343) (xy 176.335854 59.61) (xy 175.287769 59.61) (xy 175.298242 59.676126)
|
||||
(xy 175.298242 59.676129) (xy 175.363904 59.878217) (xy 175.460379 60.067557) (xy 175.585272 60.239459)
|
||||
(xy 175.585276 60.239464) (xy 175.724143 60.378331) (xy 175.757628 60.439654) (xy 175.752644 60.509346)
|
||||
(xy 175.710772 60.565279) (xy 175.701559 60.571551) (xy 175.546342 60.667289) (xy 175.422289 60.791342)
|
||||
(xy 175.330187 60.940663) (xy 175.330186 60.940666) (xy 175.275001 61.107203) (xy 175.275001 61.107204)
|
||||
(xy 175.275 61.107204) (xy 175.2645 61.209983) (xy 175.2645 62.510001) (xy 175.264501 62.510018)
|
||||
(xy 175.275 62.612796) (xy 175.275001 62.612799) (xy 175.297795 62.681585) (xy 175.330186 62.779334)
|
||||
(xy 175.422288 62.928656) (xy 175.546344 63.052712) (xy 175.695666 63.144814) (xy 175.862203 63.199999)
|
||||
(xy 175.964991 63.2105) (xy 177.515008 63.210499) (xy 177.617797 63.199999) (xy 177.784334 63.144814)
|
||||
(xy 177.933656 63.052712) (xy 178.057712 62.928656) (xy 178.149814 62.779334) (xy 178.204999 62.612797)
|
||||
(xy 178.2155 62.510009) (xy 178.215499 61.209992) (xy 178.204999 61.107203) (xy 178.149814 60.940666)
|
||||
(xy 178.057712 60.791344) (xy 177.933656 60.667288) (xy 177.784334 60.575186) (xy 177.784332 60.575185)
|
||||
(xy 177.77844 60.571551) (xy 177.731716 60.519603) (xy 177.720493 60.450641) (xy 177.748337 60.386558)
|
||||
(xy 177.755856 60.37833) (xy 177.894728 60.239458) (xy 178.01962 60.067557) (xy 178.116095 59.878217)
|
||||
(xy 178.181757 59.676129) (xy 178.181757 59.676126) (xy 178.192231 59.61) (xy 177.144146 59.61)
|
||||
(xy 177.18263 59.543343) (xy 177.215 59.422535) (xy 177.215 59.297465) (xy 177.18263 59.176657)
|
||||
(xy 177.144146 59.11) (xy 178.192231 59.11) (xy 178.181757 59.043873) (xy 178.181757 59.04387) (xy 178.116095 58.841782)
|
||||
(xy 178.01962 58.652442) (xy 177.894727 58.48054) (xy 177.894723 58.480535) (xy 177.744464 58.330276)
|
||||
(xy 177.744459 58.330272) (xy 177.579781 58.210627) (xy 177.537115 58.155297) (xy 177.531136 58.085684)
|
||||
(xy 177.563741 58.023889) (xy 177.579776 58.009994) (xy 177.744792 57.890104) (xy 177.895104 57.739792)
|
||||
(xy 177.895106 57.739788) (xy 177.895109 57.739786) (xy 178.020048 57.56782) (xy 178.020047 57.56782)
|
||||
(xy 178.020051 57.567816) (xy 178.116557 57.378412) (xy 178.182246 57.176243) (xy 178.2155 56.966287)
|
||||
(xy 178.2155 56.753713) (xy 178.182246 56.543757) (xy 178.116557 56.341588) (xy 178.020051 56.152184)
|
||||
(xy 178.020049 56.152181) (xy 178.020048 56.152179) (xy 177.895109 55.980213) (xy 177.744786 55.82989)
|
||||
(xy 177.57282 55.704951) (xy 177.383414 55.608444) (xy 177.383413 55.608443) (xy 177.383412 55.608443)
|
||||
(xy 177.181243 55.542754) (xy 177.181241 55.542753) (xy 177.18124 55.542753) (xy 177.019957 55.517208)
|
||||
(xy 176.971287 55.5095) (xy 176.508713 55.5095) (xy 176.460042 55.517208) (xy 176.29876 55.542753)
|
||||
(xy 176.096585 55.608444) (xy 175.907179 55.704951) (xy 175.735213 55.82989) (xy 175.58489 55.980213)
|
||||
(xy 175.459951 56.152179) (xy 175.363444 56.341585) (xy 175.297753 56.54376) (xy 175.2645 56.753713)
|
||||
(xy 132.6505 56.753713) (xy 132.6505 47.074875) (xy 138.6223 47.074875) (xy 138.6223 47.283524)
|
||||
(xy 138.654937 47.489589) (xy 138.719412 47.68802) (xy 138.797825 47.841914) (xy 138.81413 47.873914)
|
||||
(xy 138.936765 48.042705) (xy 139.084295 48.190235) (xy 139.253086 48.31287) (xy 139.340916 48.357621)
|
||||
(xy 139.438979 48.407587) (xy 139.438981 48.407587) (xy 139.438984 48.407589) (xy 139.538925 48.440062)
|
||||
(xy 139.63741 48.472062) (xy 139.843476 48.5047) (xy 139.843481 48.5047) (xy 140.052124 48.5047)
|
||||
(xy 140.258189 48.472062) (xy 140.456616 48.407589) (xy 140.642514 48.31287) (xy 140.811305 48.190235)
|
||||
(xy 140.958835 48.042705) (xy 141.08147 47.873914) (xy 141.176189 47.688016) (xy 141.240662 47.489589)
|
||||
(xy 141.24573 47.457589) (xy 141.2733 47.283524) (xy 141.2733 47.074876) (xy 141.270533 47.057408)
|
||||
(xy 141.270533 47.057407) (xy 141.268231 47.042875) (xy 161.5077 47.042875) (xy 161.5077 47.251524)
|
||||
(xy 161.540337 47.457589) (xy 161.604812 47.65602) (xy 161.69953 47.841914) (xy 161.822165 48.010705)
|
||||
(xy 161.969695 48.158235) (xy 162.138486 48.28087) (xy 162.201288 48.312869) (xy 162.324379 48.375587)
|
||||
(xy 162.324381 48.375587) (xy 162.324384 48.375589) (xy 162.42287 48.407589) (xy 162.52281 48.440062)
|
||||
(xy 162.728876 48.4727) (xy 162.728881 48.4727) (xy 162.937524 48.4727) (xy 163.143589 48.440062)
|
||||
(xy 163.162015 48.434075) (xy 163.342016 48.375589) (xy 163.527914 48.28087) (xy 163.696705 48.158235)
|
||||
(xy 163.844235 48.010705) (xy 163.96687 47.841914) (xy 164.061589 47.656016) (xy 164.126062 47.457589)
|
||||
(xy 164.126895 47.452328) (xy 164.1587 47.251524) (xy 164.1587 47.042875) (xy 164.126062 46.83681)
|
||||
(xy 164.061587 46.638379) (xy 164.011621 46.540316) (xy 163.96687 46.452486) (xy 163.844235 46.283695)
|
||||
(xy 163.696705 46.136165) (xy 163.527914 46.01353) (xy 163.34202 45.918812) (xy 163.143589 45.854337)
|
||||
(xy 162.937524 45.8217) (xy 162.937519 45.8217) (xy 162.728881 45.8217) (xy 162.728876 45.8217)
|
||||
(xy 162.52281 45.854337) (xy 162.324379 45.918812) (xy 162.138485 46.01353) (xy 161.969693 46.136166)
|
||||
(xy 161.822166 46.283693) (xy 161.69953 46.452485) (xy 161.604812 46.638379) (xy 161.540337 46.83681)
|
||||
(xy 161.5077 47.042875) (xy 141.268231 47.042875) (xy 141.240662 46.86881) (xy 141.176187 46.670379)
|
||||
(xy 141.081469 46.484485) (xy 141.05822 46.452486) (xy 140.958835 46.315695) (xy 140.811305 46.168165)
|
||||
(xy 140.642514 46.04553) (xy 140.636873 46.042656) (xy 140.45662 45.950812) (xy 140.258189 45.886337)
|
||||
(xy 140.052124 45.8537) (xy 140.052119 45.8537) (xy 139.843481 45.8537) (xy 139.843476 45.8537)
|
||||
(xy 139.63741 45.886337) (xy 139.438979 45.950812) (xy 139.253085 46.04553) (xy 139.084293 46.168166)
|
||||
(xy 138.936766 46.315693) (xy 138.81413 46.484485) (xy 138.719412 46.670379) (xy 138.654937 46.86881)
|
||||
(xy 138.6223 47.074875) (xy 132.6505 47.074875) (xy 132.6505 44.874038) (xy 133.5495 44.874038)
|
||||
(xy 133.5495 45.125961) (xy 133.58891 45.374785) (xy 133.66676 45.614383) (xy 133.745413 45.768747)
|
||||
(xy 133.772394 45.8217) (xy 133.781132 45.838848) (xy 133.929201 46.042649) (xy 133.929205 46.042654)
|
||||
(xy 134.107345 46.220794) (xy 134.10735 46.220798) (xy 134.285117 46.349952) (xy 134.311155 46.36887)
|
||||
(xy 134.454184 46.441747) (xy 134.535616 46.483239) (xy 134.535618 46.483239) (xy 134.535621 46.483241)
|
||||
(xy 134.775215 46.56109) (xy 135.024038 46.6005) (xy 135.024039 46.6005) (xy 135.275961 46.6005)
|
||||
(xy 135.275962 46.6005) (xy 135.524785 46.56109) (xy 135.764379 46.483241) (xy 135.988845 46.36887)
|
||||
(xy 136.192656 46.220793) (xy 136.370793 46.042656) (xy 136.51887 45.838845) (xy 136.633241 45.614379)
|
||||
(xy 136.682708 45.462135) (xy 167.6895 45.462135) (xy 167.6895 47.25787) (xy 167.689501 47.257876)
|
||||
(xy 167.695908 47.317483) (xy 167.746202 47.452328) (xy 167.746206 47.452335) (xy 167.832452 47.567544)
|
||||
(xy 167.832455 47.567547) (xy 167.947664 47.653793) (xy 167.947671 47.653797) (xy 167.992618 47.670561)
|
||||
(xy 168.082517 47.704091) (xy 168.142127 47.7105) (xy 168.152685 47.710499) (xy 168.219723 47.730179)
|
||||
(xy 168.240372 47.746818) (xy 168.910591 48.417037) (xy 168.847007 48.434075) (xy 168.732993 48.499901)
|
||||
(xy 168.639901 48.592993) (xy 168.574075 48.707007) (xy 168.557037 48.770591) (xy 167.924728 48.138282)
|
||||
(xy 167.924727 48.138282) (xy 167.88538 48.192439) (xy 167.788904 48.381782) (xy 167.723242 48.583869)
|
||||
(xy 167.723242 48.583872) (xy 167.69 48.793753) (xy 167.69 49.006246) (xy 167.723242 49.216127)
|
||||
(xy 167.723242 49.21613) (xy 167.788904 49.418217) (xy 167.885375 49.60755) (xy 167.924728 49.661716)
|
||||
(xy 168.557037 49.029408) (xy 168.574075 49.092993) (xy 168.639901 49.207007) (xy 168.732993 49.300099)
|
||||
(xy 168.847007 49.365925) (xy 168.91059 49.382962) (xy 168.278282 50.015269) (xy 168.278282 50.01527)
|
||||
(xy 168.332452 50.054626) (xy 168.332451 50.054626) (xy 168.341495 50.059234) (xy 168.392292 50.107208)
|
||||
(xy 168.409087 50.175029) (xy 168.38655 50.241164) (xy 168.341499 50.280202) (xy 168.332182 50.284949)
|
||||
(xy 168.160213 50.40989) (xy 168.00989 50.560213) (xy 167.884951 50.732179) (xy 167.788444 50.921585)
|
||||
(xy 167.722753 51.12376) (xy 167.6895 51.333713) (xy 167.6895 51.546286) (xy 167.722753 51.756239)
|
||||
(xy 167.788444 51.958414) (xy 167.884951 52.14782) (xy 168.00989 52.319786) (xy 168.160213 52.470109)
|
||||
(xy 168.332179 52.595048) (xy 168.332181 52.595049) (xy 168.332184 52.595051) (xy 168.521588 52.691557)
|
||||
(xy 168.723757 52.757246) (xy 168.933713 52.7905) (xy 168.933714 52.7905) (xy 169.146286 52.7905)
|
||||
(xy 169.146287 52.7905) (xy 169.356243 52.757246) (xy 169.558412 52.691557) (xy 169.747816 52.595051)
|
||||
(xy 169.769789 52.579086) (xy 169.919786 52.470109) (xy 169.919788 52.470106) (xy 169.919792 52.470104)
|
||||
(xy 170.070104 52.319792) (xy 170.070106 52.319788) (xy 170.070109 52.319786) (xy 170.195048 52.14782)
|
||||
(xy 170.195047 52.14782) (xy 170.195051 52.147816) (xy 170.291557 51.958412) (xy 170.357246 51.756243)
|
||||
(xy 170.3905 51.546287) (xy 170.3905 51.333713) (xy 170.357246 51.123757) (xy 170.291557 50.921588)
|
||||
(xy 170.195051 50.732184) (xy 170.195049 50.732181) (xy 170.195048 50.732179) (xy 170.070109 50.560213)
|
||||
(xy 169.919786 50.40989) (xy 169.747817 50.284949) (xy 169.738504 50.280204) (xy 169.687707 50.23223)
|
||||
(xy 169.670912 50.164409) (xy 169.693449 50.098274) (xy 169.738507 50.059232) (xy 169.747555 50.054622)
|
||||
(xy 169.801716 50.01527) (xy 169.801717 50.01527) (xy 169.169408 49.382962) (xy 169.232993 49.365925)
|
||||
(xy 169.347007 49.300099) (xy 169.440099 49.207007) (xy 169.505925 49.092993) (xy 169.522962 49.029408)
|
||||
(xy 170.15527 49.661717) (xy 170.15527 49.661716) (xy 170.194622 49.607554) (xy 170.291095 49.418217)
|
||||
(xy 170.356757 49.21613) (xy 170.356757 49.216127) (xy 170.39 49.006246) (xy 170.39 48.793753) (xy 170.356757 48.583872)
|
||||
(xy 170.356757 48.583869) (xy 170.291095 48.381782) (xy 170.194624 48.192449) (xy 170.15527 48.138282)
|
||||
(xy 170.155269 48.138282) (xy 169.522962 48.77059) (xy 169.505925 48.707007) (xy 169.440099 48.592993)
|
||||
(xy 169.347007 48.499901) (xy 169.232993 48.434075) (xy 169.169409 48.417037) (xy 169.839627 47.746818)
|
||||
(xy 169.90095 47.713333) (xy 169.927307 47.710499) (xy 169.937872 47.710499) (xy 169.997483 47.704091)
|
||||
(xy 170.132331 47.653796) (xy 170.247546 47.567546) (xy 170.333796 47.452331) (xy 170.384091 47.317483)
|
||||
(xy 170.3905 47.257873) (xy 170.390499 45.462128) (xy 170.384091 45.402517) (xy 170.333796 45.267669)
|
||||
(xy 170.333795 45.267668) (xy 170.333793 45.267664) (xy 170.247547 45.152455) (xy 170.247544 45.152452)
|
||||
(xy 170.132335 45.066206) (xy 170.132328 45.066202) (xy 169.997482 45.015908) (xy 169.997483 45.015908)
|
||||
(xy 169.937883 45.009501) (xy 169.937881 45.0095) (xy 169.937873 45.0095) (xy 169.937864 45.0095)
|
||||
(xy 168.142129 45.0095) (xy 168.142123 45.009501) (xy 168.082516 45.015908) (xy 167.947671 45.066202)
|
||||
(xy 167.947664 45.066206) (xy 167.832455 45.152452) (xy 167.832452 45.152455) (xy 167.746206 45.267664)
|
||||
(xy 167.746202 45.267671) (xy 167.695908 45.402517) (xy 167.689501 45.462116) (xy 167.689501 45.462123)
|
||||
(xy 167.6895 45.462135) (xy 136.682708 45.462135) (xy 136.68271 45.462129) (xy 136.696241 45.420487)
|
||||
(xy 136.696241 45.420486) (xy 136.711089 45.374789) (xy 136.711089 45.374788) (xy 136.71109 45.374785)
|
||||
(xy 136.7505 45.125962) (xy 136.7505 44.874038) (xy 177.5495 44.874038) (xy 177.5495 45.125961)
|
||||
(xy 177.58891 45.374785) (xy 177.66676 45.614383) (xy 177.745413 45.768747) (xy 177.772394 45.8217)
|
||||
(xy 177.781132 45.838848) (xy 177.929201 46.042649) (xy 177.929205 46.042654) (xy 178.107345 46.220794)
|
||||
(xy 178.10735 46.220798) (xy 178.285117 46.349952) (xy 178.311155 46.36887) (xy 178.454184 46.441747)
|
||||
(xy 178.535616 46.483239) (xy 178.535618 46.483239) (xy 178.535621 46.483241) (xy 178.775215 46.56109)
|
||||
(xy 179.024038 46.6005) (xy 179.024039 46.6005) (xy 179.275961 46.6005) (xy 179.275962 46.6005)
|
||||
(xy 179.524785 46.56109) (xy 179.764379 46.483241) (xy 179.988845 46.36887) (xy 180.192656 46.220793)
|
||||
(xy 180.370793 46.042656) (xy 180.51887 45.838845) (xy 180.633241 45.614379) (xy 180.71109 45.374785)
|
||||
(xy 180.7505 45.125962) (xy 180.7505 44.874038) (xy 180.71109 44.625215) (xy 180.633241 44.385621)
|
||||
(xy 180.633239 44.385618) (xy 180.633239 44.385616) (xy 180.591747 44.304184) (xy 180.51887 44.161155)
|
||||
(xy 180.499952 44.135117) (xy 180.370798 43.95735) (xy 180.370794 43.957345) (xy 180.192654 43.779205)
|
||||
(xy 180.192649 43.779201) (xy 179.988848 43.631132) (xy 179.988847 43.631131) (xy 179.988845 43.63113)
|
||||
(xy 179.918747 43.595413) (xy 179.764383 43.51676) (xy 179.524785 43.43891) (xy 179.275962 43.3995)
|
||||
(xy 179.024038 43.3995) (xy 178.899626 43.419205) (xy 178.775214 43.43891) (xy 178.535616 43.51676)
|
||||
(xy 178.311151 43.631132) (xy 178.10735 43.779201) (xy 178.107345 43.779205) (xy 177.929205 43.957345)
|
||||
(xy 177.929201 43.95735) (xy 177.781132 44.161151) (xy 177.66676 44.385616) (xy 177.58891 44.625214)
|
||||
(xy 177.5495 44.874038) (xy 136.7505 44.874038) (xy 136.71109 44.625215) (xy 136.633241 44.385621)
|
||||
(xy 136.633239 44.385618) (xy 136.633239 44.385616) (xy 136.591747 44.304184) (xy 136.51887 44.161155)
|
||||
(xy 136.499952 44.135117) (xy 136.370798 43.95735) (xy 136.370794 43.957345) (xy 136.192654 43.779205)
|
||||
(xy 136.192649 43.779201) (xy 135.988848 43.631132) (xy 135.988847 43.631131) (xy 135.988845 43.63113)
|
||||
(xy 135.918747 43.595413) (xy 135.764383 43.51676) (xy 135.524785 43.43891) (xy 135.275962 43.3995)
|
||||
(xy 135.024038 43.3995) (xy 134.899626 43.419205) (xy 134.775214 43.43891) (xy 134.535616 43.51676)
|
||||
(xy 134.311151 43.631132) (xy 134.10735 43.779201) (xy 134.107345 43.779205) (xy 133.929205 43.957345)
|
||||
(xy 133.929201 43.95735) (xy 133.781132 44.161151) (xy 133.66676 44.385616) (xy 133.58891 44.625214)
|
||||
(xy 133.5495 44.874038) (xy 132.6505 44.874038) (xy 132.6505 42.6245) (xy 132.670185 42.557461)
|
||||
(xy 132.722989 42.511706) (xy 132.7745 42.5005) (xy 181.5255 42.5005)
|
||||
)
|
||||
)
|
||||
)
|
||||
(zone
|
||||
(net 1)
|
||||
(net_name "GND")
|
||||
|
||||
5
scripts/.gitignore
vendored
5
scripts/.gitignore
vendored
@@ -1,4 +1,5 @@
|
||||
__pycache__/
|
||||
panel/
|
||||
gerbers/
|
||||
gcode/
|
||||
output/
|
||||
gcode/
|
||||
.venv/
|
||||
BIN
scripts/Dummy.pm4n
Normal file
BIN
scripts/Dummy.pm4n
Normal file
Binary file not shown.
@@ -57,7 +57,11 @@ nano millproject
|
||||
Run the export by providing the `.kicad_pcb` file as a first argument:
|
||||
|
||||
```bash
|
||||
./export.sh panel/Flow_Controller_Panel.kicad_pcb
|
||||
# Input layers/filenames and all milling/drilling parameters are taken from the config file: 'millproject'.
|
||||
docker run --rm -i -t \
|
||||
-u "$(id -u):$(id -g)" \
|
||||
-v "$(pwd):/data" \
|
||||
ptodorov/pcb2gcode
|
||||
```
|
||||
The script will first generate gerber files in the `gerbers` directory and then generate gcode files in the `gcode` directory.
|
||||
|
||||
@@ -75,3 +79,174 @@ Set up the entire back side as one big GND pour. Then, increase the thermal spok
|
||||

|
||||
|
||||
|
||||
# MSLA PCB Exposure: KiCad → Photon Mono 4
|
||||
|
||||
Convert KiCad PCB layers to `.pm4n` files for direct UV exposure on an **Anycubic Photon Mono 4** (9024×5120 px, 17 µm/px).
|
||||
|
||||
---
|
||||
|
||||
## Files
|
||||
|
||||
| File | Purpose |
|
||||
|---|---|
|
||||
| `export.sh` | Main entry point — exports Gerbers from KiCad, converts to `.pm4n` |
|
||||
| `gerber_to_pm4n.py` | Python converter (Gerber → RLE → pm4n binary surgery) |
|
||||
| `Dummy.pm4n` | Template file for your specific printer. |
|
||||
|
||||
---
|
||||
|
||||
## Setup
|
||||
|
||||
### 1. Create the Dummy.pm4n
|
||||
|
||||
Open **CHITUBOX_Basic** slicer, select printer **Anycubic Photon Mono 4**, slice any tiny STL (a 1×1×0.05 mm box), and save as `Dummy.pm4n` in the same directory as `export.sh`.
|
||||
|
||||
This file is reused for every job — it carries the correct LCD resolution metadata.
|
||||
|
||||
### 2. Install dependencies
|
||||
|
||||
```bash
|
||||
python3 -m venv .venv
|
||||
source .venv/bin/activate
|
||||
pip install pygerber Pillow numpy
|
||||
```
|
||||
|
||||
Or activate the venv once and put `source .venv/bin/activate` in your shell profile.
|
||||
|
||||
---
|
||||
|
||||
## Usage
|
||||
|
||||
```
|
||||
./export.sh [OPTIONS] <path/to/board.kicad_pcb>
|
||||
```
|
||||
|
||||
### Options
|
||||
|
||||
| Option | Default | Description |
|
||||
|---|---|---|
|
||||
| `--layers L,L,...` | `Front,F.Mask` | KiCad layer names to process |
|
||||
| `--invert L,L,...` | *(none)* | Layers to invert the image for |
|
||||
| `--mirror L,L,...` | *(none)* | Layers to mirror X for |
|
||||
| `--exposure N` | `60` | Exposure time in seconds |
|
||||
| `--dummy FILE` | `./Dummy.pm4n` | Path to dummy template |
|
||||
| `--out DIR` | `./output` | Output directory |
|
||||
| `--dpmm N` | `58.824` | Render resolution (native = 17 µm/px) |
|
||||
| `--pos X,Y` | centred | Board position in mm from top-left |
|
||||
|
||||
---
|
||||
|
||||
## Examples
|
||||
|
||||
### Typical: top copper, positive-working resist (Bungard standard)
|
||||
|
||||
```bash
|
||||
./export.sh \
|
||||
--layers Front \
|
||||
--invert Front \
|
||||
--mirror Front \
|
||||
--exposure 60 \
|
||||
panel/Flow_Controller_Panel.kicad_pcb
|
||||
```
|
||||
|
||||
`--invert`: Bungard presensitized is positive-working — UV removes resist, so the background must be exposed (white) and traces must block UV (dark). The Gerber is positive (copper=white), so inversion is needed.
|
||||
|
||||
`--mirror`: the board sits copper-side-down on the FEP, so the image must be flipped so the pattern reads correctly through the board.
|
||||
|
||||
### Multiple layers (e.g. copper + soldermask)
|
||||
|
||||
```bash
|
||||
./export.sh \
|
||||
--layers Front,F.Mask \
|
||||
--invert Front,F.Mask \
|
||||
--mirror Front,F.Mask \
|
||||
--exposure 60 \
|
||||
panel/Flow_Controller_Panel.kicad_pcb
|
||||
```
|
||||
|
||||
### Quick test at lower resolution (faster render)
|
||||
|
||||
```bash
|
||||
./export.sh --dpmm 30 --layers Front --invert Front --mirror Front panel/Flow_Controller_Panel.kicad_pcb
|
||||
```
|
||||
|
||||
### Using gerber_to_pm4n.py directly
|
||||
|
||||
```bash
|
||||
python3 gerber_to_pm4n.py Dummy.pm4n output/gerbers/Flow_Controller_Panel-Front.gbr \
|
||||
--invert --mirror --exposure 60
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Output structure
|
||||
|
||||
```
|
||||
output/
|
||||
├── gerbers/
|
||||
│ ├── Flow_Controller_Panel-Front.gbr
|
||||
│ └── Flow_Controller_Panel-F_Mask.gbr
|
||||
└── pm4n/
|
||||
├── Flow_Controller_Panel-Front.pm4n ← copy to USB, print on Mono 4
|
||||
├── Flow_Controller_Panel-Front.preview.png ← visual check before printing
|
||||
├── Flow_Controller_Panel-F_Mask.pm4n
|
||||
└── Flow_Controller_Panel-F_Mask.preview.png
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Invert and mirror logic
|
||||
|
||||
| Setting | When to use |
|
||||
|---|---|
|
||||
| `--invert` | Positive-working resist (standard Bungard): UV removes resist → background must be white (exposed), traces black (masked) |
|
||||
| no `--invert` | Negative-working resist: UV hardens resist → traces must be white |
|
||||
| `--mirror` | Board placed **copper-side down** on FEP (normal for this workflow) |
|
||||
| no `--mirror` | Board placed copper-side up |
|
||||
|
||||
When in doubt: check the `.preview.png` before printing. Traces should appear **dark** on a white background for standard Bungard positive-working boards.
|
||||
|
||||
---
|
||||
|
||||
## Exposure calibration
|
||||
|
||||
Start at **60 s** and bracket in ±15 s steps. Typical range for Bungard presensitized at 405 nm is 30–120 s depending on board age and storage conditions.
|
||||
|
||||
A correctly exposed board after development will show:
|
||||
- Clear copper traces (resist intact, blue/green tint)
|
||||
- Bare copper in etched areas (resist removed, shiny copper)
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
**`kicad-cli: command not found`** — add KiCad to PATH:
|
||||
```bash
|
||||
export PATH="/usr/lib/kicad/bin:$PATH"
|
||||
```
|
||||
Or on Flatpak:
|
||||
```bash
|
||||
alias kicad-cli='flatpak run --command=kicad-cli org.kicad.KiCad'
|
||||
```
|
||||
|
||||
**Expected Gerber not found** — KiCad's layer→filename mapping:
|
||||
|
||||
| Layer | Filename stem |
|
||||
|---|---|
|
||||
| `F.Cu` | `Front` |
|
||||
| `B.Cu` | `Back` |
|
||||
| `F.Mask` | `F_Mask` |
|
||||
| `B.Mask` | `B_Mask` |
|
||||
| `F.SilkS` | `F_Silkscreen` |
|
||||
|
||||
**Image looks wrong in preview** — check invert/mirror flags. Open `.preview.png`: for positive-working resist, traces = dark, background = white.
|
||||
|
||||
**UVtools PCB Exposure freezes on per-item invert checkbox** — known v6 bug at 46 MP. Use the global invert checkbox at the bottom of the dialog instead, or use this script pipeline entirely.
|
||||
|
||||
---
|
||||
First print checklist
|
||||
|
||||
Open the `.pm4n` in Chitubox to visually verify before printing.
|
||||
Check the `.preview.png` — traces should appear black on white background (background = UV exposed = resist removed = etched away; traces = dark = resist kept = copper stays)
|
||||
Start with `--exposure 60` and bracket from there — Bungard presensitized at 405nm typically lands between 30–120s depending on board vintage and storage.
|
||||
|
||||
|
||||
62
scripts/diagnose_pm4n.py
Normal file
62
scripts/diagnose_pm4n.py
Normal file
@@ -0,0 +1,62 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Run this on your machine: python3 diagnose_pm4n.py Dummy.pm4n"""
|
||||
import struct, sys
|
||||
|
||||
path = sys.argv[1] if len(sys.argv) > 1 else 'Dummy.pm4n'
|
||||
data = open(path, 'rb').read()
|
||||
fsize = len(data)
|
||||
print(f"File: {path} ({fsize} bytes)")
|
||||
print()
|
||||
|
||||
# Parse ANYCUBIC header
|
||||
magic = data[0:8]
|
||||
version = struct.unpack_from('<I', data, 8)[0]
|
||||
n_sections = struct.unpack_from('<I', data, 12)[0]
|
||||
header_size = struct.unpack_from('<I', data, 16)[0]
|
||||
print(f"Magic: {magic}")
|
||||
print(f"Bytes 8-11: {data[8:12].hex()} (={version})")
|
||||
print(f"Section count: {n_sections}")
|
||||
print(f"Header size: {header_size} (0x{header_size:X})")
|
||||
print()
|
||||
|
||||
# Section table: n_sections entries of (offset:u32, length:u32) starting at byte 20
|
||||
print(f"Section table ({n_sections} entries from offset 20):")
|
||||
sections = []
|
||||
for i in range(n_sections):
|
||||
base = 20 + i * 8
|
||||
if base + 8 > fsize:
|
||||
break
|
||||
off = struct.unpack_from('<I', data, base)[0]
|
||||
ln = struct.unpack_from('<I', data, base+4)[0]
|
||||
sections.append((off, ln))
|
||||
|
||||
for idx, (off, ln) in enumerate(sections):
|
||||
tag = data[off:off+4] if off + 4 <= fsize else b'????'
|
||||
tag_str = tag.decode('ascii', errors='replace')
|
||||
print(f" [{idx:2d}] offset=0x{off:06X} ({off:7d}) length={ln:7d} tag@offset={tag_str!r}")
|
||||
|
||||
print()
|
||||
# Also peek at each section start for tag-like content
|
||||
print("Content at each section offset (first 32 bytes):")
|
||||
for idx, (off, ln) in enumerate(sections):
|
||||
if off + 16 <= fsize:
|
||||
chunk = data[off:off+32]
|
||||
# Try to find sub-tags
|
||||
for sub_off in range(0, min(32, len(chunk))-3):
|
||||
sub_tag = chunk[sub_off:sub_off+4]
|
||||
if all(32 <= b < 127 for b in sub_tag):
|
||||
sub_len = struct.unpack_from('<I', chunk, sub_off+4)[0] if sub_off+8 <= len(chunk) else 0
|
||||
print(f" section[{idx}]+0x{sub_off:02X} tag={sub_tag.decode()!r} next_u32={sub_len}")
|
||||
break
|
||||
else:
|
||||
print(f" section[{idx}] hex: {chunk[:16].hex()}")
|
||||
|
||||
print()
|
||||
# Look for exposure-like floats (1.0 to 600.0) across the whole file
|
||||
print("Float values in range [1.0 .. 600.0] across whole file:")
|
||||
for off in range(0, fsize - 3, 4):
|
||||
v = struct.unpack_from('<f', data, off)[0]
|
||||
if 1.0 <= v <= 600.0 and v == round(v, 1):
|
||||
# Show context
|
||||
section_hint = next((f"sec[{i}]+{off-s:d}" for i,(s,l) in enumerate(sections) if s <= off < s+l), "outside")
|
||||
print(f" 0x{off:06X} {v:.1f} ({section_hint})")
|
||||
@@ -1,35 +1,156 @@
|
||||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
# export.sh — KiCad Gerber export + pm4n generation for Anycubic Photon Mono 4
|
||||
#
|
||||
# Usage:
|
||||
# ./export.sh [OPTIONS] <path/to/board.kicad_pcb>
|
||||
#
|
||||
# Options:
|
||||
# --layers LAYER,LAYER,... KiCad layer names to export (default: F.Cu)
|
||||
# --invert LAYER,LAYER,... Layers to invert (comma-separated, e.g. F.Cu,B.Mask)
|
||||
# --mirror LAYER,LAYER,... Layers to mirror (comma-separated, e.g. F.Cu,F.Mask)
|
||||
# --exposure SECONDS Exposure time in seconds (default: 60)
|
||||
# --dummy FILE Dummy .pm4n template (default: Dummy.pm4n beside this script)
|
||||
# --out DIR Output directory (default: ./output)
|
||||
# --dpmm N Render resolution in dots/mm (default: native 58.824)
|
||||
# --pos X,Y Board position on LCD in mm (default: centred)
|
||||
# -h, --help Show this help
|
||||
#
|
||||
# Example:
|
||||
# ./export.sh --invert F.Cu,B.Mask --mirror F.Cu,F.Mask panel/Flow_Controller_Panel.kicad_pcb
|
||||
#
|
||||
# Layer name → Gerber filename mapping (KiCad default):
|
||||
# F.Cu → <board>-F_Cu.gbr
|
||||
# B.Cu → <board>-B_Cu.gbr
|
||||
# F.Mask → <board>-F_Mask.gbr
|
||||
# B.Mask → <board>-B_Mask.gbr
|
||||
# F.SilkS → <board>-F_Silkscreen.gbr
|
||||
# (etc.)
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
GERBERS_DIR="gerbers"
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PYTHON="${PYTHON:-python3}"
|
||||
CONVERTER="$SCRIPT_DIR/gerber_to_pm4n.py"
|
||||
|
||||
# ---- defaults ----
|
||||
LAYERS="F.Cu"
|
||||
INVERT_LAYERS=""
|
||||
MIRROR_LAYERS=""
|
||||
EXPOSURE="60"
|
||||
DUMMY="$SCRIPT_DIR/Dummy.pm4n"
|
||||
OUT_DIR="./output"
|
||||
DPMM=""
|
||||
POS=""
|
||||
|
||||
# ---- helpers ----
|
||||
usage() {
|
||||
echo "Usage: $0 <kicad_pcb_file>"
|
||||
exit 1
|
||||
sed -n '/^# Usage/,/^[^#]/{ /^#/{ s/^# \{0,1\}//; p } }' "$0"
|
||||
exit 0
|
||||
}
|
||||
|
||||
PCB_FILE="$1"
|
||||
contains() { # contains <list> <item> — comma-separated list membership
|
||||
local list="$1" item="$2"
|
||||
echo "$list" | tr ',' '\n' | grep -qx "$item"
|
||||
}
|
||||
|
||||
mkdir -p "$GERBERS_DIR"
|
||||
layer_to_filename() { # KiCad layer name → Gerber filename stem
|
||||
local layer="$1"
|
||||
echo "$layer" | sed 's/\./_/g'
|
||||
}
|
||||
|
||||
# Export drill, front and back layers as gerber files.
|
||||
echo "Exporting gerbers..."
|
||||
kicad-cli pcb export drill -o "$GERBERS_DIR" "$PCB_FILE"
|
||||
kicad-cli pcb export gerbers -o "$GERBERS_DIR" -l Front "$PCB_FILE"
|
||||
kicad-cli pcb export gerbers -o "$GERBERS_DIR" -l Back "$PCB_FILE"
|
||||
kicad-cli pcb export gerbers -o "$GERBERS_DIR" -l Edge.Cuts "$PCB_FILE"
|
||||
# ---- parse arguments ----
|
||||
PCB_FILE=""
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--layers) LAYERS="$2"; shift 2 ;;
|
||||
--invert) INVERT_LAYERS="$2"; shift 2 ;;
|
||||
--mirror) MIRROR_LAYERS="$2"; shift 2 ;;
|
||||
--exposure) EXPOSURE="$2"; shift 2 ;;
|
||||
--dummy) DUMMY="$2"; shift 2 ;;
|
||||
--out) OUT_DIR="$2"; shift 2 ;;
|
||||
--dpmm) DPMM="$2"; shift 2 ;;
|
||||
--pos) POS="$2"; shift 2 ;;
|
||||
-h|--help) usage ;;
|
||||
-*) echo "Unknown option: $1"; exit 1 ;;
|
||||
*) PCB_FILE="$1"; shift ;;
|
||||
esac
|
||||
done
|
||||
|
||||
# Export outlines of the penelized board i.e. use the layer 'User.Eco1'.
|
||||
echo "Exporting panelized outlines from layer 'User.Eco1'..."
|
||||
python3 export_panel_outlines_gerber.py \
|
||||
--layers User.Eco1 \
|
||||
if [[ -z "$PCB_FILE" ]]; then
|
||||
echo "ERROR: no .kicad_pcb file specified"
|
||||
echo "Usage: $0 [OPTIONS] <board.kicad_pcb>"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ ! -f "$PCB_FILE" ]]; then
|
||||
echo "ERROR: file not found: $PCB_FILE"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ ! -f "$DUMMY" ]]; then
|
||||
echo "ERROR: dummy .pm4n not found: $DUMMY"
|
||||
echo "Place Dummy.pm4n next to export.sh, or pass --dummy <path>"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# ---- derive names ----
|
||||
BOARD_NAME="$(basename "$PCB_FILE" .kicad_pcb)"
|
||||
GERBERS_DIR="$OUT_DIR/gerbers"
|
||||
PM4N_DIR="$OUT_DIR/pm4n"
|
||||
|
||||
mkdir -p "$GERBERS_DIR" "$PM4N_DIR"
|
||||
|
||||
# ---- Step 1: export Gerbers via kicad-cli ----
|
||||
echo "=== Exporting Gerbers from KiCad ==="
|
||||
echo " Board: $PCB_FILE"
|
||||
echo " Layers: $LAYERS"
|
||||
echo " Output: $GERBERS_DIR"
|
||||
echo ""
|
||||
|
||||
kicad-cli pcb export gerbers \
|
||||
--output "$GERBERS_DIR" \
|
||||
--layers "$LAYERS" \
|
||||
--no-protel-ext \
|
||||
--subtract-soldermask \
|
||||
"$PCB_FILE"
|
||||
|
||||
# Input layers/filenames and all milling/drilling parameters are taken from the config file: 'millproject'.
|
||||
echo "Exporting Gcode..."
|
||||
docker run --rm -i -t \
|
||||
-u "$(id -u):$(id -g)" \
|
||||
-v "$(pwd):/data" \
|
||||
ptodorov/pcb2gcode
|
||||
echo ""
|
||||
|
||||
# ---- Step 2: convert each layer to .pm4n ----
|
||||
echo "=== Converting Gerbers to .pm4n ==="
|
||||
|
||||
IFS=',' read -ra LAYER_LIST <<< "$LAYERS"
|
||||
for LAYER in "${LAYER_LIST[@]}"; do
|
||||
LAYER_STEM="$(layer_to_filename "$LAYER")"
|
||||
GBR_FILE="$GERBERS_DIR/${BOARD_NAME}-${LAYER_STEM}.gbr"
|
||||
|
||||
if [[ ! -f "$GBR_FILE" ]]; then
|
||||
echo " WARNING: expected Gerber not found: $GBR_FILE — skipping"
|
||||
continue
|
||||
fi
|
||||
|
||||
OUT_PM4N="$PM4N_DIR/${BOARD_NAME}-${LAYER_STEM}.pm4n"
|
||||
|
||||
# Build flags
|
||||
FLAGS=()
|
||||
if contains "$INVERT_LAYERS" "$LAYER"; then FLAGS+=(--invert); fi
|
||||
if contains "$MIRROR_LAYERS" "$LAYER"; then FLAGS+=(--mirror); fi
|
||||
[[ -n "$DPMM" ]] && FLAGS+=(--dpmm "$DPMM")
|
||||
[[ -n "$POS" ]] && FLAGS+=(--pos "$POS")
|
||||
|
||||
echo " Layer: $LAYER"
|
||||
echo " Gerber: $GBR_FILE"
|
||||
echo " pm4n: $OUT_PM4N"
|
||||
echo " Flags: ${FLAGS[*]:-<none>} exposure=${EXPOSURE}s"
|
||||
|
||||
"$PYTHON" "$CONVERTER" \
|
||||
"$DUMMY" \
|
||||
"$GBR_FILE" \
|
||||
--output "$OUT_PM4N" \
|
||||
--exposure "$EXPOSURE" \
|
||||
"${FLAGS[@]}"
|
||||
echo ""
|
||||
done
|
||||
|
||||
echo "=== Done ==="
|
||||
echo "pm4n files in: $PM4N_DIR"
|
||||
287
scripts/gerber_to_pm4n.py
Executable file
287
scripts/gerber_to_pm4n.py
Executable file
@@ -0,0 +1,287 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
gerber_to_pm4n.py - Anycubic Photon Mono 4 PCB exposure file generator
|
||||
|
||||
Usage:
|
||||
python3 gerber_to_pm4n.py <dummy.pm4n> <board.gbr> [options]
|
||||
|
||||
Options:
|
||||
-o OUTPUT Output file path [default: <board>.pm4n]
|
||||
--invert Invert the image (for positive-working resist like Bungard standard)
|
||||
--mirror Mirror X axis (for copper-side-down placement on FEP)
|
||||
--exposure SEC Layer exposure time in seconds [default: 60]
|
||||
--dpmm N Render resolution in dots/mm [default: 58.824, native 17µm/px]
|
||||
--pos X,Y Place board at X,Y mm from top-left (default: centred on LCD)
|
||||
--help Show this message
|
||||
|
||||
Photon Mono 4 specs: 9024 x 5120 px | 153.408 x 87.040 mm | 17.001 µm/px
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import struct
|
||||
import sys
|
||||
import io
|
||||
from pathlib import Path
|
||||
from PIL import Image, ImageOps
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Printer constants
|
||||
# ---------------------------------------------------------------------------
|
||||
LCD_W_PX = 9024
|
||||
LCD_H_PX = 5120
|
||||
LCD_W_MM = 153.408
|
||||
LCD_H_MM = 87.040
|
||||
NATIVE_DPMM = LCD_W_PX / LCD_W_MM # 58.824 dpmm (1 px ≈ 17.001 µm)
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Photon Workshop RLE (BW — 2 bytes per run)
|
||||
#
|
||||
# Byte0 [7:4] = colour nibble (0x0 = black, 0xF = white)
|
||||
# Byte0 [3:0] = high 4 bits of run length (bits 11:8)
|
||||
# Byte1 = low 8 bits of run length (bits 7:0)
|
||||
# Run length encodes (n-1): 0x000 = 1 pixel, 0xFFF = 4096 pixels
|
||||
# ---------------------------------------------------------------------------
|
||||
MAX_RUN = 4096
|
||||
|
||||
def encode_rle(pixels: bytes) -> bytes:
|
||||
"""Encode flat 0x00/0xFF bytes → Photon Workshop BW RLE."""
|
||||
out = bytearray()
|
||||
i = 0
|
||||
n = len(pixels)
|
||||
while i < n:
|
||||
colour = pixels[i]
|
||||
nibble = 0xF if colour >= 0x80 else 0x0
|
||||
j = i + 1
|
||||
while j < n and pixels[j] == colour and (j - i) < MAX_RUN:
|
||||
j += 1
|
||||
run = j - i
|
||||
encoded = run - 1
|
||||
out.append((nibble << 4) | ((encoded >> 8) & 0x0F))
|
||||
out.append(encoded & 0xFF)
|
||||
i = j
|
||||
return bytes(out)
|
||||
|
||||
|
||||
def decode_rle(data: bytes, expected_pixels: int) -> bytes:
|
||||
"""Decode PW RLE → raw pixel bytes (used for verification)."""
|
||||
out = bytearray()
|
||||
i = 0
|
||||
while i + 1 < len(data):
|
||||
b0, b1 = data[i], data[i + 1]
|
||||
nibble = (b0 >> 4) & 0x0F
|
||||
colour = 0xFF if nibble == 0xF else 0x00
|
||||
run = (((b0 & 0x0F) << 8) | b1) + 1
|
||||
out.extend([colour] * run)
|
||||
i += 2
|
||||
return bytes(out[:expected_pixels])
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# pm4n binary surgery
|
||||
#
|
||||
# Photon Workshop file = sequence of tagged sections:
|
||||
# tag:4 length:4 payload:length
|
||||
#
|
||||
# Sections we care about:
|
||||
# HEAD – contains exposure time as a float somewhere in a packed struct
|
||||
# LAYE – layer definition table: count:u32 then N × entry(28 bytes)
|
||||
# entry[0:4] = absolute file offset of RLE blob
|
||||
# entry[4:8] = RLE blob length in bytes
|
||||
# After the sections: raw RLE layer image blobs (referenced by LAYE offsets)
|
||||
# ---------------------------------------------------------------------------
|
||||
SECTION_HDR = 8 # 4-byte tag + 4-byte length
|
||||
|
||||
def read_sections(data: bytes) -> list:
|
||||
sections = []
|
||||
i = 0
|
||||
while i + SECTION_HDR <= len(data):
|
||||
tag = data[i:i+4]
|
||||
length = struct.unpack_from('<I', data, i+4)[0]
|
||||
sections.append((tag, i + SECTION_HDR, length))
|
||||
i += SECTION_HDR + length
|
||||
return sections
|
||||
|
||||
def find_section(data: bytes, tag: bytes) -> tuple:
|
||||
for t, off, ln in read_sections(data):
|
||||
if t == tag:
|
||||
return off, ln
|
||||
raise ValueError(f"Section {tag!r} not found in file")
|
||||
|
||||
def patch_u32(data: bytearray, offset: int, value: int):
|
||||
struct.pack_into('<I', data, offset, value)
|
||||
|
||||
def patch_f32(data: bytearray, offset: int, value: float):
|
||||
struct.pack_into('<f', data, offset, value)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Gerber → PIL Image
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
def render_gerber(gbr_path: Path, dpmm: float,
|
||||
invert: bool, mirror: bool,
|
||||
pos_mm: tuple | None) -> Image.Image:
|
||||
"""
|
||||
Render a Gerber file to a binary PIL image sized to the Photon Mono 4 LCD.
|
||||
copper = white on black background before any transforms.
|
||||
"""
|
||||
try:
|
||||
from pygerber.gerberx3.api.v2 import (
|
||||
GerberFile, ColorScheme, PixelFormatEnum, ImageFormatEnum
|
||||
)
|
||||
except ImportError:
|
||||
sys.exit(
|
||||
"ERROR: pygerber not found.\n"
|
||||
"Activate the venv first: source .venv/bin/activate\n"
|
||||
"Or install: pip install pygerber Pillow numpy"
|
||||
)
|
||||
|
||||
buf = io.BytesIO()
|
||||
(GerberFile
|
||||
.from_file(str(gbr_path))
|
||||
.parse()
|
||||
.render_raster(
|
||||
buf,
|
||||
dpmm=int(round(dpmm)),
|
||||
color_scheme=ColorScheme.DEFAULT_GRAYSCALE,
|
||||
pixel_format=PixelFormatEnum.RGB,
|
||||
image_format=ImageFormatEnum.PNG,
|
||||
)
|
||||
)
|
||||
buf.seek(0)
|
||||
layer_img = Image.open(buf).convert('L')
|
||||
|
||||
# Place onto full LCD canvas
|
||||
cw, ch = layer_img.size
|
||||
canvas = Image.new('L', (LCD_W_PX, LCD_H_PX), 0)
|
||||
|
||||
if pos_mm is not None:
|
||||
px = int(round(pos_mm[0] * dpmm))
|
||||
py = int(round(pos_mm[1] * dpmm))
|
||||
else:
|
||||
px = (LCD_W_PX - cw) // 2
|
||||
py = (LCD_H_PX - ch) // 2
|
||||
|
||||
canvas.paste(layer_img, (max(0, px), max(0, py)))
|
||||
|
||||
if mirror:
|
||||
canvas = ImageOps.mirror(canvas)
|
||||
if invert:
|
||||
canvas = ImageOps.invert(canvas)
|
||||
|
||||
# Hard-binarise: no antialiasing artefacts in the RLE stream
|
||||
canvas = canvas.point(lambda v: 255 if v >= 128 else 0)
|
||||
|
||||
return canvas
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# pm4n surgery
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
def patch_pm4n(dummy_path: Path, image: Image.Image,
|
||||
exposure_sec: float, output_path: Path):
|
||||
"""Replace layer RLE + exposure time in a dummy .pm4n, write output."""
|
||||
raw = bytearray(dummy_path.read_bytes())
|
||||
|
||||
# Encode new layer image
|
||||
pixels = image.convert('L').tobytes()
|
||||
new_rle = encode_rle(pixels)
|
||||
|
||||
# Patch exposure time: scan HEAD for any float in 0.5–600 s range
|
||||
hdr_off, hdr_len = find_section(raw, b'HEAD')
|
||||
for off in range(hdr_off, hdr_off + hdr_len - 3):
|
||||
val = struct.unpack_from('<f', raw, off)[0]
|
||||
if 0.5 <= val <= 600.0:
|
||||
patch_f32(raw, off, exposure_sec)
|
||||
|
||||
# Locate layer image via LAYERDEF
|
||||
ld_off, _ = find_section(raw, b'LAYE')
|
||||
layer_count = struct.unpack_from('<I', raw, ld_off)[0]
|
||||
if layer_count != 1:
|
||||
print(f"WARNING: dummy has {layer_count} layers; only layer 0 will be replaced.")
|
||||
entry_off = ld_off + 4
|
||||
img_offset = struct.unpack_from('<I', raw, entry_off)[0]
|
||||
img_len = struct.unpack_from('<I', raw, entry_off + 4)[0]
|
||||
|
||||
print(f" Dummy RLE: offset=0x{img_offset:08X} {img_len} bytes")
|
||||
print(f" New RLE: {len(new_rle)} bytes")
|
||||
|
||||
# Splice new RLE in place
|
||||
old_end = img_offset + img_len
|
||||
raw[img_offset:old_end] = new_rle
|
||||
|
||||
# Update LAYERDEF length field
|
||||
patch_u32(raw, entry_off + 4, len(new_rle))
|
||||
|
||||
# Update any enclosing section's length field
|
||||
for tag, sec_off, sec_len in read_sections(bytes(raw)):
|
||||
if tag not in (b'HEAD', b'LAYE', b'PREV') and sec_off <= img_offset < sec_off + sec_len:
|
||||
patch_u32(raw, sec_off - 4, sec_len + len(new_rle) - img_len)
|
||||
break
|
||||
|
||||
output_path.write_bytes(raw)
|
||||
print(f" Written: {output_path} ({len(raw):,} bytes)")
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# CLI
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
def parse_args():
|
||||
p = argparse.ArgumentParser(
|
||||
description='Convert Gerber → Anycubic Photon Mono 4 .pm4n PCB exposure file',
|
||||
formatter_class=argparse.RawDescriptionHelpFormatter,
|
||||
epilog=__doc__,
|
||||
)
|
||||
p.add_argument('dummy', help='Dummy .pm4n template (from Photon Workshop)')
|
||||
p.add_argument('gerber', help='Input Gerber file')
|
||||
p.add_argument('-o', '--output', default=None, help='Output .pm4n path')
|
||||
p.add_argument('--invert', action='store_true', help='Invert image (positive-working resist)')
|
||||
p.add_argument('--mirror', action='store_true', help='Mirror X axis (copper-side-down placement)')
|
||||
p.add_argument('--exposure', type=float, default=60.0, help='Exposure seconds (default: 60)')
|
||||
p.add_argument('--dpmm', type=float, default=NATIVE_DPMM, help=f'Dots/mm (default: {NATIVE_DPMM:.3f})')
|
||||
p.add_argument('--pos', default=None, help='Board position X,Y mm from top-left')
|
||||
return p.parse_args()
|
||||
|
||||
|
||||
def main():
|
||||
args = parse_args()
|
||||
dummy = Path(args.dummy)
|
||||
gbr = Path(args.gerber)
|
||||
|
||||
for p, label in [(dummy, 'dummy'), (gbr, 'gerber')]:
|
||||
if not p.exists():
|
||||
sys.exit(f"ERROR: {label} file not found: {p}")
|
||||
|
||||
out = Path(args.output) if args.output else gbr.with_suffix('.pm4n')
|
||||
pos_mm = None
|
||||
if args.pos:
|
||||
try:
|
||||
x, y = map(float, args.pos.split(','))
|
||||
pos_mm = (x, y)
|
||||
except Exception:
|
||||
sys.exit("ERROR: --pos must be X,Y e.g. --pos 10.5,8.0")
|
||||
|
||||
print(f"Gerber: {gbr}")
|
||||
print(f"Dummy: {dummy}")
|
||||
print(f"Output: {out}")
|
||||
print(f"Invert: {args.invert} Mirror: {args.mirror} Exposure: {args.exposure}s dpmm: {args.dpmm:.3f}")
|
||||
print()
|
||||
|
||||
print("Rendering Gerber...")
|
||||
img = render_gerber(gbr, dpmm=args.dpmm, invert=args.invert,
|
||||
mirror=args.mirror, pos_mm=pos_mm)
|
||||
print(f"Canvas: {img.size[0]}×{img.size[1]} px")
|
||||
|
||||
preview = out.with_suffix('.preview.png')
|
||||
img.resize((img.size[0] // 4, img.size[1] // 4), Image.NEAREST).save(preview)
|
||||
print(f"Preview: {preview}")
|
||||
|
||||
print("Patching .pm4n...")
|
||||
patch_pm4n(dummy, img, args.exposure, out)
|
||||
print("Done.")
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -1,10 +1,10 @@
|
||||
front=gerbers/Flow_Controller_Panel-Front.gtl
|
||||
back=gerbers/Flow_Controller_Panel-Back.gbl
|
||||
drill=gerbers/Flow_Controller_Panel.drl
|
||||
front=output/gerbers/Flow_Controller_Panel-Front.gtl
|
||||
back=output/gerbers/Flow_Controller_Panel-Back.gbl
|
||||
drill=output/gerbers/Flow_Controller_Panel.drl
|
||||
# Use the 'User-Eco1' layer instead as it contains panelized board's slot outlines only.
|
||||
outline=gerbers/Flow_Controller_Panel-User-Eco1.gbr
|
||||
outline=output/gerbers/Flow_Controller_Panel-User-Eco1.gbr
|
||||
# Do not use the 'Edge_Cuts' layer as it contains also the panel outline.
|
||||
#outline=gerbers/Flow_Controller_Panel-Edge_Cuts.gm1
|
||||
#outline=output/gerbers/Flow_Controller_Panel-Edge_Cuts.gm1
|
||||
|
||||
# Generic
|
||||
metric=true # use metric units for parameters
|
||||
|
||||
@@ -24,32 +24,26 @@
|
||||
"type": "tightframe",
|
||||
"copperFill": true,
|
||||
"slotwidth": "2.1mm",
|
||||
"mintotalheight": "100mm",
|
||||
"mintotalwidth": "160mm",
|
||||
"maxtotalheight": "100mm",
|
||||
"maxtotalwidth": "160mm"
|
||||
"mintotalheight": "87mm",
|
||||
"mintotalwidth": "153.4mm",
|
||||
"maxtotalheight": "87mm",
|
||||
"maxtotalwidth": "153.4mm"
|
||||
},
|
||||
"tooling": {
|
||||
"type": "plugin",
|
||||
"code": "tooling_plugin.py.CustomTooling",
|
||||
"arg": ""
|
||||
},
|
||||
"fiducials": {
|
||||
"type": "4fid",
|
||||
"type": "3hole",
|
||||
"layout": "3hole",
|
||||
"hoffset": "6mm",
|
||||
"voffset": "9.2mm",
|
||||
"coppersize": "2mm",
|
||||
"opening": "1mm",
|
||||
"voffset": "6mm",
|
||||
"size": "2mm",
|
||||
"paste": true,
|
||||
"code": "none",
|
||||
"arg": ""
|
||||
"soldermaskmargin": "0mm"
|
||||
},
|
||||
"text": {
|
||||
"type": "simple",
|
||||
"text": "Front",
|
||||
"anchor": "mt",
|
||||
"hoffset": "0mm",
|
||||
"voffset": "15mm",
|
||||
"voffset": "10mm",
|
||||
"orientation": "0deg",
|
||||
"width": "3.5mm",
|
||||
"height": "3.5mm",
|
||||
@@ -63,7 +57,7 @@
|
||||
"text": "Back",
|
||||
"anchor": "mt",
|
||||
"hoffset": "0mm",
|
||||
"voffset": "15mm",
|
||||
"voffset": "10mm",
|
||||
"orientation": "0deg",
|
||||
"width": "3.5mm",
|
||||
"height": "3.5mm",
|
||||
@@ -76,7 +70,7 @@
|
||||
"type": "solid",
|
||||
"clearance": "0.5mm",
|
||||
"edgeclearance": "0.5mm",
|
||||
"layers": "B.Cu"
|
||||
"layers": "F.Cu,B.Cu"
|
||||
},
|
||||
"post": {
|
||||
"type": "auto",
|
||||
|
||||
Reference in New Issue
Block a user